Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 7 additions & 2 deletions aeneas/src/ir/SsaNormalizer.v3
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,12 @@ class SsaRaNormalizer extends SsaRebuilder {
def norm: ReachabilityNormalizer;
var specSet: SpecSet;

new(context: SsaContext, norm) super(context) { }
new(context: SsaContext, norm) super(context) {
if (context.compiler.NormBuildOpt) {
opt = SsaOptimizer.new(context);
opt.remove_pure_ops = false; // instructions have no uses yet when added
}
}

def build(newMethod: IrMethod, empty: bool) {
newMethod.ssa = genGraph(empty);
Expand All @@ -18,7 +23,7 @@ class SsaRaNormalizer extends SsaRebuilder {
if (context.compiler.NormOptimize &&
context.compiler.optEnabled("(ra)", newMethod, null, null)) {
var opt = SsaOptimizer.new(context);
opt.iopt.optimize_loads = context.compiler.LoadOptimize &&
opt.optimize_loads = context.compiler.LoadOptimize &&
context.compiler.optEnabled("(ra loads)", newMethod, null, null);
opt.optGraph();
context.printSsa("Norm Optimized");
Expand Down
6 changes: 5 additions & 1 deletion aeneas/src/mach/MachDataWriter.v3
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ enum PatchKind {
ABS_32,
ABS_64,
ABS_SLEB32,
ABS_ULEB32,
ARM64_REL_IMM19,
ARM64_ABS_IMM16,
ARM64_REL_IMM26,
Expand Down Expand Up @@ -68,14 +69,17 @@ class MachDataWriter extends DataWriter {
put_b32(if(wrap, int.view(disp), int.!(disp)));
}
ABS_32 => {
put_b32(if(wrap, int.view(u32.!(absAddr)), int.!(absAddr)));
put_b32(if(wrap, int.view(absAddr), int.!(absAddr)));
}
ABS_64 => {
put_b64(absAddr);
}
ABS_SLEB32 => {
overwrite_sleb32(int.!(absAddr));
}
ABS_ULEB32 => {
overwrite_uleb32(int.view(absAddr));
}
ARM64_REL_IMM19 => {
var offset = int.!((absAddr - posAddr) / 4);
var old = int.view(data[pos]) | (int.view(data[pos + 1]) << 8) |
Expand Down
25 changes: 17 additions & 8 deletions aeneas/src/mach/MachLowering.v3
Original file line number Diff line number Diff line change
Expand Up @@ -73,9 +73,9 @@ class MachLoweringConfig {
class SsaGraphNormalizer(context: SsaContext) extends SsaInstrVisitor {
def buffer = Vector<SsaInstr>.new(); // reusable input buffer
def replacements = Vector<Array<SsaInstr>>.new();
var cfopt: SsaCfOptimizer;
var singleMark: int;
var ssa: SsaBuilder;
var opt: SsaOptimizer; // if non-null, optimizes instructions as they are added
var phis: List<SsaPhi>;

// Map {i_old} to multiple instructions in {i_new}.
Expand Down Expand Up @@ -133,6 +133,7 @@ class SsaGraphNormalizer(context: SsaContext) extends SsaInstrVisitor {
replacements.clear();
buffer.clear();
ssa = SsaBuilder.new(context, graph, null);
ssa.opt = opt;
}
// Get the replacements for a given instruction, if it is not a 1-1 mapping.
// Returns {null} if there is a 1-1 mapping.
Expand Down Expand Up @@ -280,7 +281,12 @@ class SsaGraphNormalizer(context: SsaContext) extends SsaInstrVisitor {
// with loads and stores. Introduces truncations and wrapping for integer operations
// according to the {config}.
class MachLowering(mach: MachProgram, compiler: Compiler, config: MachLoweringConfig) extends SsaGraphNormalizer {
new() super(SsaContext.new(compiler, mach.prog)) { }
new() super(SsaContext.new(compiler, mach.prog)) {
if (compiler.MachBuildOpt) {
opt = SsaOptimizer.new(context);
opt.remove_pure_ops = false; // instructions have no uses yet when added
}
}
var maybeDead: List<SsaInstr>;
def doMethod(method: IrMethod) {
context.enterMethod(method);
Expand Down Expand Up @@ -893,6 +899,7 @@ class MachLowering(mach: MachProgram, compiler: Compiler, config: MachLoweringCo
def visitPtrAtObject(opcode: Opcode.PtrAtObject, t: Type) { mapOrId(app, normRef1(app.inputs[0])); }
def visitPtrAtArrayElem(opcode: Opcode.PtrAtArrayElem, at: ArrayType, it: IntType) {
genBoundsCheck(app, Fact.O_NO_NULL_CHECK); // XXX: propagate nullity
if (ssa.end()) return;
var i_array = normRef1(app.inputs[0]);
var i_index = normRef1(app.inputs[1]);
var hsize = mach.getArrayElemOffset(at, 0), scale = mach.getArrayElemScale(at);
Expand Down Expand Up @@ -1152,8 +1159,9 @@ class MachLowering(mach: MachProgram, compiler: Compiler, config: MachLoweringCo

var tv: SsaInstr, zero = context.graph.nullConst(tt);
if (Opcode.IntDiv.?(i_old.op.opcode)) {
var apply = ssa.add(tt.opSub(), [zero, x], Facts.NONE);
tv = genTruncateInPlace(apply, tt); // XXX: weird to apply this to new instructions.
var neg = ssa.add(tt.opSub(), [zero, x], Facts.NONE);
// XXX: weird to apply this to new instructions.
tv = if(SsaApplyOp.?(neg), genTruncateInPlace(SsaApplyOp.!(neg), tt), neg);
} else {
tv = zero; // x % -1 == #0
}
Expand Down Expand Up @@ -1943,6 +1951,7 @@ class MachLowering(mach: MachProgram, compiler: Compiler, config: MachLoweringCo
var oarr = i_old.inputs[0];
// XXX: CSE the array length if possible
var len = refLoad(nullity, Int.TYPE, i_old, oarr, narr, mach.getArrayLengthOffset(i_old.op.typeArgs[0]));
if (ssa.end()) return (len, nullity | Fact.O_NO_NULL_CHECK); // the load threw, killing {i_old}
var index = normRef1(i_old.inputs[1]);
var throwOp = V3Op.newConditionalThrow(V3Exception.BoundsCheck);
var op = Int.getType(false, 32).opLtEq();
Expand All @@ -1967,12 +1976,14 @@ class MachLowering(mach: MachProgram, compiler: Compiler, config: MachLoweringCo
}
def genCallClassSelector(i_old: SsaApplyOp, selector: IrSelector) {
var func = genClassGetSelector(i_old, selector);
if (ssa.end()) return;
var methodRef = V3Op.extractIrSpec(i_old.op, selector);
var args = Arrays.prepend(func, normRefs(i_old.inputs));
call(i_old, mach.funcRep(methodRef), args);
}
def genCallVariantSelector(i_old: SsaApplyOp, selector: IrSelector) {
var func = genVariantGetSelector(i_old, selector);
if (ssa.end()) return;
var methodRef = V3Op.extractIrSpec(i_old.op, selector);
var args = Arrays.prepend(func, normRefs(i_old.inputs));
call(i_old, mach.funcRep(methodRef), args);
Expand Down Expand Up @@ -2225,10 +2236,8 @@ class MachLowering(mach: MachProgram, compiler: Compiler, config: MachLoweringCo
}
def addThrow(exception: string) -> SsaInstr {
if (ssa.end()) return null;
if (cfopt == null) cfopt = SsaCfOptimizer.new(context);
var r = cfopt.insertThrow(ssa.prev.next, ssa.source, exception, null);
ssa.setPrev(null);
return r;
ssa.addThrow(ssa.source, exception);
return context.graph.nop();
}

def genAllocMethod(size: IntType) -> IrMethod {
Expand Down
11 changes: 9 additions & 2 deletions aeneas/src/main/Compiler.v3
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,9 @@ class Compiler(target: Target) {
var LocalRegAlloc = flags.get("LocalRegAlloc", level >= 1) && !CLOptions.DWARF.get();
var NormOptimize = flags.get("NormOptimize", level >= 2);
var MachOptimize = flags.get("MachOptimize", level >= 2);
var VstBuildOpt = flags.get("VstBuildOpt", false);
var NormBuildOpt = flags.get("NormBuildOpt", false);
var MachBuildOpt = flags.get("MachBuildOpt", false);
var LoopInvariantCodeMotion = flags.get("LoopInvariantCodeMotion", CLOptions.LICM.val);
var IrAlloc = CLOptions.IR_ALLOC.get();
var firstEnabled = CLOptions.FIRST_ENABLED.get();
Expand Down Expand Up @@ -400,6 +403,10 @@ class Compilation(compiler: Compiler, prog: Program) {
if (meth.ssa == null) {
var context = SsaContext.new(compiler, prog).enterSpec(memberRef);
var gen = VstSsaGen.new(context, prog.opBuilder);
if (compiler.VstBuildOpt) {
var opt = gen.opt = SsaOptimizer.new(context);
opt.remove_pure_ops = false; // instructions have no uses yet when added
}
gen.recordDirectCalls = compiler.InlineEarly || CLOptions.INLINE.val != VstMatcher.None;
var graph = gen.generate();
context.verify();
Expand All @@ -411,14 +418,14 @@ class Compilation(compiler: Compiler, prog: Program) {
}
if (compiler.VstControlOpt && graph.isMultiBlock()) {
// Perform control flow optimizations.
SsaCfOptimizer.new(context).optimize();
SsaOptimizer.new(context).optControlFlow();
context.printSsa("Control Optimized");
}
if (compiler.PostpassOptimize &&
compiler.optEnabled("(gen)", meth, null, null)) {
// Run the post-pass optimizer.
var opt = SsaOptimizer.new(context);
opt.iopt.optimize_loads = compiler.LoadOptimize &&
opt.optimize_loads = compiler.LoadOptimize &&
compiler.optEnabled("(gen loads)", meth, null, null);
opt.optGraph();
context.printSsa("Postpass Optimized");
Expand Down
2 changes: 1 addition & 1 deletion aeneas/src/main/Version.v3
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,6 @@
// Updated by VCS scripts. DO NOT EDIT.
component Version {
def UNSTABLE = true;
def version: string = "III-13.2003";
def version: string = "III-13.2004";
var buildData: string;
}
38 changes: 38 additions & 0 deletions aeneas/src/ssa/Ssa.v3
Original file line number Diff line number Diff line change
Expand Up @@ -500,6 +500,44 @@ component Ssa {
next = nn;
}
}
// Recursively kills {block}, its instructions, and any successors that become unreachable.
def killBlock(block: SsaBlock) {
if (block.facts.O_KILLED) return;
// Recursively kill this block and its successor blocks
block.facts |= Fact.O_KILLED;
var succs = block.succs();
var i = block.next;
while (i != null) {
// Kill all instructions in the block
var n = i.next;
i.next = null;
i.prev = null;
if (SsaInstr.?(i)) {
var j = SsaInstr.!(i);
j.kill();
j.facts |= Fact.O_KILLED;
}
i = n;
}
killSuccs(succs);
}
// Removes {edges} and kills any successor blocks that become unreachable.
def killSuccs(edges: Array<SsaCfEdge>) {
// kill the outgoing control flow edges
var succs = Vector<SsaBlock>.new();
for (s in edges) {
var d = s.dest;
if (d != null) {
Ssa.removeEdge(s, true);
succs.put(d);
}
}
// kill any dead successor blocks.
for (i < succs.length) {
var d = succs[i];
if (!d.hasPred()) killBlock(d);
}
}
def killInstr(i: SsaInstr) -> SsaInstr {
i.remove();
i.kill();
Expand Down
48 changes: 35 additions & 13 deletions aeneas/src/ssa/SsaBuilder.v3
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ class SsaBuilder {
var block: SsaBlock;
def var prev: SsaLink; // new instructions are inserted after this; {null} if ended or unreachable
var source: Source;
var opt: SsaOptimizer; // if non-null, optimizes each apply instruction as it is added

new(context, graph, block: SsaBlock) {
set(block);
Expand All @@ -40,8 +41,7 @@ class SsaBuilder {
}
var i = SsaApplyOp.new(source, op, args);
i.setFact(Opcodes.facts(op.opcode));
append(i);
return i;
return appendApply(i);
}
def addApplyF(op: Operator, args: Array<SsaInstr>, facts: Fact.set) -> SsaInstr {
if (Debug.PARANOID) { checkNoTypeVarsInOp(op); checkInputs(args); }
Expand All @@ -52,8 +52,7 @@ class SsaBuilder {
}
var i = SsaApplyOp.new(source, op, args);
i.setFact(Opcodes.facts(op.opcode) | facts);
append(i);
return i;
return appendApply(i);
}
def addApplyVst(source: Source, op: Operator, vst: VstOperator, args: Array<SsaInstr>) -> SsaInstr {
var pt = op.sig.paramTypes;
Expand Down Expand Up @@ -371,6 +370,7 @@ class SsaBuilder {
def split() -> SsaBuilder {
var mergeBuilder = SsaBuilder.new(context, graph, SsaBlock.new());
mergeBuilder.source = this.source;
mergeBuilder.opt = this.opt;
splitInto(mergeBuilder.block);
return mergeBuilder;
}
Expand All @@ -395,12 +395,31 @@ class SsaBuilder {
// use it.
return SsaIfCascade.new(this, t, merge.block, merge.prev);
}
// Ends the block with a throw at the insertion point, killing any instructions after it.
def addThrow(source: Source, ex: string) -> SsaInstr {
if (end()) return block.end();
var t = SsaThrow.new(source, ex);
appendEnd(t);
killAfter(t);
return t;
}
// Kills the instructions after the new end {t}, including any previous end of the block.
// The optimizer, if any, kills the previous end's successors.
private def killAfter(t: SsaEnd) {
for (p = t.next; !SsaBlock.?(p); ()) {
var n = p.next;
p.remove();
if (SsaEnd.?(p)) {
var end = SsaEnd.!(p);
if (opt != null) opt.killSuccs(end.succs);
else Ssa.killSuccs(end.succs);
Ssa.killInstr(end);
break;
}
if (SsaInstr.?(p)) Ssa.killInstr(SsaInstr.!(p));
p = n;
}
}
def addGoto(target: SsaBlock) {
if (end()) return;
appendEnd(SsaGoto.new(target));
Expand Down Expand Up @@ -466,6 +485,12 @@ class SsaBuilder {
if (!t.open()) return graph.valConst(t, context.prog.getDefaultValue(t));
return add(V3Op.newDefaultValue(t), Ssa.NO_INSTRS, Fact.O_PURE);
}
// Appends the apply {i} and then, if this builder has an optimizer, optimizes it.
// Returns the instruction that computes the value of {i}.
def appendApply(i: SsaApplyOp) -> SsaInstr {
append(i);
return if(opt == null, i, opt.optAppended(this, i));
}
// Inserts {i} after {prev} and advances {prev} to {i}.
def append(i: SsaInstr) {
insert(i);
Expand Down Expand Up @@ -784,7 +809,7 @@ class SsaBuilder {
private def tryElimBoundsCheck(x: SsaInstr, y: SsaInstr) -> Fact.set {
if (SsaConst.?(y)) {
var yk = SsaConst.!(y).val;
if (SsaConst.?(x)) {
if (SsaConst.?(x) && Record.?(SsaConst.!(x).val)) {
var r = Record.!(SsaConst.!(x).val);
if (r != null && (yk == null || Box<int>.?(yk))) {
var i = V3.unboxI32(yk);
Expand Down Expand Up @@ -939,14 +964,13 @@ class SsaBuilder {
}
return val;
}
def pure(op: Operator, args: Array<SsaInstr>) -> SsaApplyOp {
def pure(op: Operator, args: Array<SsaInstr>) -> SsaInstr {
return add(op, args, Fact.O_PURE);
}
def add(op: Operator, args: Array<SsaInstr>, facts: Fact.set) -> SsaApplyOp {
def add(op: Operator, args: Array<SsaInstr>, facts: Fact.set) -> SsaInstr {
if (Opcode.VstSugar.?(op.opcode)) return V3.fail("unexpected sugar");
var i = SsaApplyOp.new(source, op, args).setFact(facts | Opcodes.facts(op.opcode));
if (!end()) append(i);
return i;
return if(end(), i, appendApply(i));
}
// add() specialized to 1 input.
def add1(op: Operator, x: SsaInstr, facts: Fact.set) -> SsaInstr {
Expand All @@ -956,8 +980,7 @@ class SsaBuilder {
// if (r.0) return r.1;
// }
var i = SsaApplyOp.new(source, op, [x]).setFact(facts);
if (!end()) append(i);
return i;
return if(end(), i, appendApply(i));
}
def pure1(op: Operator, x: SsaInstr) -> SsaInstr {
return add1(op, x, Fact.O_PURE); // XXX: can skip an operator fact lookup for tryEval
Expand All @@ -970,8 +993,7 @@ class SsaBuilder {
// if (r.0) return r.1;
// }
var i = SsaApplyOp.new(source, op, [x, y]).setFact(facts);
if (!end()) append(i);
return i;
return if(end(), i, appendApply(i));
}
def pure2(op: Operator, x: SsaInstr, y: SsaInstr) -> SsaInstr {
return add2(op, x, y, Fact.O_PURE); // XXX: can skip an operator fact lookup for tryEval
Expand Down
2 changes: 1 addition & 1 deletion aeneas/src/ssa/SsaInliner.v3
Original file line number Diff line number Diff line change
Expand Up @@ -169,7 +169,7 @@ class SsaInliner extends SsaRebuilder {
for (i = contInstrs; i != null; i = i.next) {
if (SsaInstr.?(i)) SsaInstr.!(i).kill();
}
SsaCfOptimizer.new(context).killSuccs(contEnd.succs);
Ssa.killSuccs(contEnd.succs);
contBlock = null;
}
def visitApplyOp(oi: SsaApplyOp) {
Expand Down
Loading
Loading