Skip to content

Commit 6c0f39b

Browse files
authored
[opt] Allow more inlining of class methods (#366)
1 parent ce68ae4 commit 6c0f39b

20 files changed

+175
-14
lines changed

aeneas/src/ir/Facts.v3

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ enum Fact {
1111
M_EQUALS, // method is an equality comparator
1212
M_OVERRIDDEN, // method has been overridden in a subclass
1313
M_OVERRIDE, // method overrides a superclass method
14-
M_OPERATOR, // method wraps an operator
14+
M_ENUM_INIT, // method represents a enum init initializer
1515
M_NEW, // the method is a constructor
1616
M_ABSTRACT, // the method is abstract
1717
M_INLINE, // method should be inlined whenever possible

aeneas/src/ir/IrOpMethodBuilder.v3

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ class IrOpMethodBuilder(prog: Program) {
1919
def receiver = createGlobalIrClass();
2020
var context = SsaContext.new(compiler, prog);
2121
var meth = createIrMethod(receiver, typeArgs, op.sig);
22-
meth.setFact(Fact.M_INLINE | Fact.M_OPERATOR);
22+
meth.setFact(Fact.M_INLINE);
2323
context.enterMethod(meth);
2424
var block = createSsa(context, receiver, meth);
2525
// build block

aeneas/src/ir/Normalization.v3

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ def defaultGetBitWidth(compiler: Compiler, prog: Program, t: Type) -> byte {
4040
}
4141

4242
// Normalizes a program based on the results of reachability analysis.
43-
def TRANSFERRABLE_FACTS = (Fact.M_ABSTRACT | Fact.M_INLINE | Fact.M_OPERATOR | Fact.M_NEW | Fact.M_EMPTY | Fact.M_EQUALS);
43+
def TRANSFERRABLE_FACTS = (Fact.M_ABSTRACT | Fact.M_INLINE | Fact.M_ENUM_INIT | Fact.M_NEW | Fact.M_EMPTY | Fact.M_EQUALS);
4444
class ReachabilityNormalizer(config: NormalizerConfig, ra: ReachabilityAnalyzer) {
4545
def liveClasses = Vector<RaClass>.new();
4646
def context = SsaContext.new(ra.compiler, ra.prog);
@@ -177,7 +177,10 @@ class ReachabilityNormalizer(config: NormalizerConfig, ra: ReachabilityAnalyzer)
177177
}
178178

179179
def norm(t: Type) -> TypeNorm {
180-
if (t.open()) return V3.fail1("is open %q", t.render);
180+
if (t.open()) {
181+
context.fail1("is open %q", t.render);
182+
return null;
183+
}
181184
var tn = typeMap[t];
182185
if (tn != null) return tn;
183186
// not in the hashmap, build appropriately

aeneas/src/main/Compiler.v3

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -308,7 +308,7 @@ class Compilation(compiler: Compiler, prog: Program) {
308308
var graph = gen.generate();
309309
context.verify();
310310
meth.ssa = graph;
311-
if (gen.directCallBlocks != null) {
311+
if (gen.directCallBlocks != null && !meth.facts.M_ENUM_INIT) { // don't early-inline into enum inits
312312
// Perform inlining.
313313
// TODO: -inline=foo also enables heuristic-based early inlining
314314
SsaEarlyInliner.new(context, this, gen).inline(depth);

aeneas/src/main/Version.v3

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,6 @@
33

44
// Updated by VCS scripts. DO NOT EDIT.
55
component Version {
6-
def version: string = "III-9.1806";
6+
def version: string = "III-9.1807";
77
var buildData: string;
88
}

aeneas/src/ssa/SsaBuilder.v3

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -715,7 +715,12 @@ class SsaBuilder {
715715
def opCallVirtual(m: IrSpec, x: Array<SsaInstr>) -> SsaInstr {
716716
var facts = m.member.facts & Fact.O_PURE;
717717
if(x[0].facts.V_NON_ZERO) facts |= Fact.O_NO_NULL_CHECK;
718-
return add(V3Op.bestCallVirtual(m), x, facts); // XXX: devirtualize based on x's type as well
718+
var op = V3Op.bestCallVirtual(m);
719+
match (op.opcode) {
720+
CallClassMethod(m) => recordDirectCall(V3Op.extractIrSpec(op, m));
721+
_ => ;
722+
}
723+
return add(op, x, facts); // XXX: devirtualize based on x's type as well
719724
}
720725
// CallClosure(args)
721726
def opCallClosure(ftype: Type, x: Array<SsaInstr>) -> SsaInstr {

aeneas/src/ssa/SsaOptimizer.v3

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -818,8 +818,10 @@ class SsaInstrReducer(context: SsaContext) extends SsaInstrMatcher {
818818
if (field.isConst()) {
819819
if (SsaConst.?(receiver)) {
820820
// ClassGetField(#K) => #K
821-
return graph.valConst(getFieldType(i.op, field),
822-
asRecord(receiver).values[field.index]);
821+
var record = asRecord(receiver);
822+
var ftype = field.fieldType;
823+
if (ftype.open()) ftype = IrSpec.new(record.rtype, TypeUtil.NO_TYPES, field).getFieldType();
824+
return graph.valConst(ftype, record.values[field.index]);
823825
}
824826
i.setFactIf(Fact.O_NO_NULL_CHECK, Fact.O_PURE);
825827
i.facts |= Fact.F_VALUE;
@@ -868,10 +870,9 @@ class SsaInstrReducer(context: SsaContext) extends SsaInstrMatcher {
868870
if (SsaConst.?(receiver)) {
869871
// VariantGetField(#K) => #K
870872
var record = asRecord(receiver);
871-
var val = if(record != null, record.values[field.index]);
872-
//TODO: variants should not have null records, but this can currently happen in folding during normalization
873-
//TODO if (record == null) context.fail1("VariantGetField @%d has null input record", i.uid);
874-
return graph.valConst(getFieldType(i.op, field), val);
873+
var ftype = field.fieldType;
874+
if (ftype.open()) ftype = IrSpec.new(record.rtype, TypeUtil.NO_TYPES, field).getFieldType();
875+
return graph.valConst(ftype, if(record != null, record.values[field.index]));
875876
}
876877
if (!i.facts.F_POINTED_AT) i.facts |= Fact.F_VALUE;
877878
if (optimize_loads) return state.load(receiver, field, i);

aeneas/src/ssa/VstSsaGen.v3

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,10 @@ class VstSsaGen extends VstVisitor<VstSsaEnv, SsaInstr> {
9292
return graph;
9393
}
9494
def addConstructorCode(decl: VstNew, env: VstSsaEnv) {
95-
if (decl.receiver.isEnum()) return addEnumParamInitCode(env);
95+
if (decl.receiver.isEnum()) {
96+
context.method.facts |= Fact.M_ENUM_INIT;
97+
return addEnumParamInitCode(env);
98+
}
9699
appendImplicitFieldInits(decl.params.list, env);
97100
appendFieldInits(decl.memberinits, env);
98101
appendSuperClause(decl.superclause, env);

test/core/inline_cm00.v3

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
//@execute 0=0; 111=111
2+
class C {
3+
def m() -> int { return 0; }
4+
}
5+
6+
def c = C.new();
7+
8+
def main(a: int) -> int {
9+
return a + c.m();
10+
}

test/core/inline_cm01.v3

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
//@execute 0=100; 11=111
2+
class C {
3+
def m() -> int { return 100; }
4+
}
5+
6+
def c = C.new();
7+
8+
def main(a: int) -> int {
9+
return a + c.m();
10+
}

test/core/inline_cm02.v3

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
//@execute 0=200; 11=211
2+
class C {
3+
def m() -> int { return 200; }
4+
}
5+
6+
class D extends C {
7+
}
8+
9+
def c = C.new();
10+
11+
def main(a: int) -> int {
12+
return a + c.m();
13+
}

test/core/inline_cm03.v3

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
//@execute 0=200; 11=211
2+
class C {
3+
def m() -> int { return 200; }
4+
}
5+
6+
class D extends C {
7+
def m() -> int { return 300; }
8+
}
9+
10+
def c = C.new();
11+
12+
def main(a: int) -> int {
13+
return a + c.m();
14+
}

test/core/inline_cm04.v3

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
//@execute 0=200; 11=211
2+
class C {
3+
def m() -> int { return 200; }
4+
}
5+
6+
class D extends C {
7+
}
8+
9+
def c: C = D.new();
10+
11+
def main(a: int) -> int {
12+
return a + c.m();
13+
}

test/core/inline_cm05.v3

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
//@execute 0=200; 11=211
2+
class C {
3+
def m() -> int { return 200; }
4+
}
5+
6+
class D extends C {
7+
}
8+
9+
def d: D = D.new();
10+
11+
def main(a: int) -> int {
12+
return a + d.m();
13+
}

test/core/inline_cm06.v3

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
//@execute = false
2+
class C {
3+
def m() -> bool { return D.?(this); }
4+
}
5+
class D extends C {
6+
}
7+
8+
def c = C.new();
9+
10+
def main() -> bool {
11+
return c.m();
12+
}

test/core/inline_cm07.v3

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
//@execute = true
2+
class C {
3+
def m() -> bool { return D.?(this); }
4+
}
5+
class D extends C {
6+
}
7+
8+
def d = D.new();
9+
10+
def main() -> bool {
11+
return d.m();
12+
}

test/core/inline_cm08.v3

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
//@execute 0=false; 1=true
2+
class C {
3+
def m() -> bool { return D.?(this); }
4+
}
5+
class D extends C {
6+
}
7+
8+
def a = [C.new(), D.new()];
9+
10+
def main(x: int) -> bool {
11+
return a[x].m();
12+
}

test/core/inline_cm09.v3

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
//@execute = true
2+
class C {
3+
def m() -> bool { return D.?(this); }
4+
}
5+
class D extends C {
6+
def m() -> bool { return D.?(this); }
7+
}
8+
9+
def d = D.new();
10+
11+
def main() -> bool {
12+
return d.m();
13+
}

test/core/inline_poly00.v3

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
//@execute = true
2+
class C<T> {
3+
def x: T;
4+
def m() -> C<T> {
5+
return C<T>.new();
6+
}
7+
}
8+
9+
def main() -> bool {
10+
var c = C<int>.new();
11+
var d = c.m();
12+
return c.x == d.x;
13+
}

test/enums/param08.v3

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
//@execute = 33
2+
def sum = E.A.x + E.B.x;
3+
4+
def f() {
5+
}
6+
7+
enum E(x: int, v: void) {
8+
A(11, f()),
9+
B(22, f())
10+
}
11+
12+
def main() -> int {
13+
return sum;
14+
}

0 commit comments

Comments
 (0)