diff --git a/optvm/src/main/java/com/compilerprogramming/ezlang/compiler/CompiledFunction.java b/optvm/src/main/java/com/compilerprogramming/ezlang/compiler/CompiledFunction.java index 0d577d2..4eb3bf3 100644 --- a/optvm/src/main/java/com/compilerprogramming/ezlang/compiler/CompiledFunction.java +++ b/optvm/src/main/java/com/compilerprogramming/ezlang/compiler/CompiledFunction.java @@ -41,6 +41,7 @@ public CompiledFunction(Symbol.FunctionTypeSymbol functionSymbol, TypeDictionary AST.FuncDecl funcDecl = (AST.FuncDecl) functionSymbol.functionDecl; this.functionType = (Type.TypeFunction) functionSymbol.type; this.registerPool = new RegisterPool(); + // Incremental SSA is an optional feature this.issa = (options != null && options.contains(Options.ISSA)) ? new IncrementalSSABraun(this) : new NoopIncrementalSSA(); setVirtualRegisters(funcDecl.scope); this.BID = 0; @@ -49,6 +50,7 @@ public CompiledFunction(Symbol.FunctionTypeSymbol functionSymbol, TypeDictionary this.currentBreakTarget = null; this.currentContinueTarget = null; this.typeDictionary = typeDictionary; + issa.sealBlock(entry); // Incremental SSA is an optional feature generateArgInstructions(funcDecl.scope); compileStatement(funcDecl.block); exitBlockIfNeeded(); @@ -135,7 +137,7 @@ else if (virtualStack.size() > 1) public void code(Instruction instruction) { currentBlock.add(instruction); - instruction.block = currentBlock; + assert instruction.block == currentBlock; } private void compileStatement(AST.Stmt statement) { @@ -225,12 +227,12 @@ private void compileWhile(AST.WhileStmt whileStmt) { codeIndexedLoad(); codeCBR(currentBlock, pop(), bodyBlock, exitBlock); assert vstackEmpty(); - startSealedBlock(bodyBlock); // ISSA If we seal this here fib test fails, wrong code generated, why? + startSealedBlock(bodyBlock); // ISSA Body is immediately sealed as no new predecessors possible compileStatement(whileStmt.stmt); if (!isBlockTerminated(currentBlock)) jumpTo(loopHead); issa.sealBlock(loopHead); - startSealedBlock(exitBlock); + startSealedBlock(exitBlock); // ISSA seal exit block (breaks already done) currentContinueTarget = savedContinueTarget; currentBreakTarget = savedBreakTarget; } @@ -450,7 +452,7 @@ private boolean codeBoolean(AST.BinaryExpr binaryExpr) { } startSealedBlock(l1); // ISSA seal immediately compileExpr(binaryExpr.expr2); - var temp = ensureTemp(); + var temp = ensureTemp(); // Normally temps are SSA but this temp gets two assignments, thus must be included during SSA conversion jumpTo(l3); startSealedBlock(l2); // ISSA seal immediately // Below we must write to the same temp @@ -464,7 +466,7 @@ private boolean codeBoolean(AST.BinaryExpr binaryExpr) { private boolean compileBinaryExpr(AST.BinaryExpr binaryExpr) { String opCode = binaryExpr.op.str; if (opCode.equals("&&") || - opCode.equals("||")) { + opCode.equals("||")) { return codeBoolean(binaryExpr); } boolean indexed = compileExpr(binaryExpr.expr1); @@ -476,7 +478,7 @@ private boolean compileBinaryExpr(AST.BinaryExpr binaryExpr) { Operand right = pop(); Operand left = pop(); if (left instanceof Operand.NullConstantOperand && - right instanceof Operand.NullConstantOperand) { + right instanceof Operand.NullConstantOperand) { long value = 0; switch (opCode) { case "==": value = 1; break; @@ -602,15 +604,17 @@ private Operand top() { return virtualStack.getLast(); } + private boolean vstackEmpty() { + return virtualStack.isEmpty(); + } + private Operand.TempRegisterOperand codeIndexedLoad() { Operand indexed = pop(); var temp = createTemp(indexed.type); - if (indexed instanceof Operand.LoadIndexedOperand loadIndexedOperand) { + if (indexed instanceof Operand.LoadIndexedOperand loadIndexedOperand) codeArrayLoad(loadIndexedOperand, temp); - } - else if (indexed instanceof Operand.LoadFieldOperand loadFieldOperand) { + else if (indexed instanceof Operand.LoadFieldOperand loadFieldOperand) codeGetField(loadFieldOperand, temp); - } else codeMove(indexed, temp); return temp; @@ -619,12 +623,10 @@ else if (indexed instanceof Operand.LoadFieldOperand loadFieldOperand) { private void codeIndexedStore() { Operand value = pop(); Operand indexed = pop(); - if (indexed instanceof Operand.LoadIndexedOperand loadIndexedOperand) { + if (indexed instanceof Operand.LoadIndexedOperand loadIndexedOperand) codeArrayStore(value, loadIndexedOperand); - } - else if (indexed instanceof Operand.LoadFieldOperand loadFieldOperand) { + else if (indexed instanceof Operand.LoadFieldOperand loadFieldOperand) codeSetField(value, loadFieldOperand); - } else codeMove(value, indexed); } @@ -638,6 +640,15 @@ else if (type instanceof Type.TypeStruct typeStruct) throw new CompilerException("Unexpected type: " + type); } + private void codeStoreAppend() { + var operand = issa.read(pop()); + Operand.RegisterOperand arrayOperand = (Operand.RegisterOperand) issa.read(top()); + var insn = new Instruction.AStoreAppend(arrayOperand, operand); + issa.recordUse(arrayOperand, insn); + issa.recordUse(operand, insn); + code(insn); + } + private void codeNewArray(Type.TypeArray typeArray) { var temp = createTemp(typeArray); var target = (Operand.RegisterOperand) issa.write(temp); @@ -654,15 +665,6 @@ private void codeNewStruct(Type.TypeStruct typeStruct) { code(insn); } - private void codeStoreAppend() { - var operand = issa.read(pop()); - Operand.RegisterOperand arrayOperand = (Operand.RegisterOperand) issa.read(top()); - var insn = new Instruction.AStoreAppend(arrayOperand, operand); - issa.recordUse(arrayOperand, insn); - issa.recordUse(operand, insn); - code(insn); - } - private void codeArg(Operand.LocalRegisterOperand target) { var newtarget = (Operand.RegisterOperand) issa.write(target); var insn = new Instruction.ArgInstruction(newtarget); @@ -774,10 +776,6 @@ private void codeSetField(Operand value, Operand.LoadFieldOperand loadFieldOpera code(insn); } - private boolean vstackEmpty() { - return virtualStack.isEmpty(); - } - public StringBuilder toStr(StringBuilder sb, boolean verbose) { if (verbose) { sb.append(this.functionType.describe()).append("\n"); diff --git a/optvm/src/main/java/com/compilerprogramming/ezlang/compiler/EnterSSA.java b/optvm/src/main/java/com/compilerprogramming/ezlang/compiler/EnterSSA.java index 13a8556..fc1d275 100644 --- a/optvm/src/main/java/com/compilerprogramming/ezlang/compiler/EnterSSA.java +++ b/optvm/src/main/java/com/compilerprogramming/ezlang/compiler/EnterSSA.java @@ -94,6 +94,8 @@ void insertPhis() { while (b != null) { visited.set(b.bid); for (BasicBlock d: b.dominationFrontier) { + if (d == function.exit) // The exit block does not need any phis as it has no instructions + continue; // insert phi for x in d d.insertPhiFor(x); if (!visited.get(d.bid)) diff --git a/optvm/src/main/java/com/compilerprogramming/ezlang/compiler/Options.java b/optvm/src/main/java/com/compilerprogramming/ezlang/compiler/Options.java index b49d9b5..e71988c 100644 --- a/optvm/src/main/java/com/compilerprogramming/ezlang/compiler/Options.java +++ b/optvm/src/main/java/com/compilerprogramming/ezlang/compiler/Options.java @@ -23,6 +23,7 @@ public enum Options { public static final EnumSet NONE = EnumSet.noneOf(Options.class); public static final EnumSet OPT = EnumSet.of(Options.OPTIMIZE,Options.SCCP,Options.CCP,Options.REGALLOC); + public static final EnumSet OPT_ISSA = EnumSet.of(Options.OPTIMIZE,Options.ISSA,Options.SCCP,Options.CCP,Options.REGALLOC); public static final EnumSet VERBOSE = EnumSet.range(DUMP_INITIAL_IR, DUMP_POST_CHAITIN_IR); public static final EnumSet OPT_VERBOSE = EnumSet.range(OPTIMIZE, DUMP_POST_CHAITIN_IR); } diff --git a/optvm/src/test/java/com/compilerprogramming/ezlang/compiler/TestIncrementalSSA.java b/optvm/src/test/java/com/compilerprogramming/ezlang/compiler/TestIncrementalSSA.java index 864cb42..546425d 100644 --- a/optvm/src/test/java/com/compilerprogramming/ezlang/compiler/TestIncrementalSSA.java +++ b/optvm/src/test/java/com/compilerprogramming/ezlang/compiler/TestIncrementalSSA.java @@ -1,5 +1,6 @@ package com.compilerprogramming.ezlang.compiler; +import org.junit.Assert; import org.junit.Test; import java.util.EnumSet; @@ -7,8 +8,8 @@ public class TestIncrementalSSA { String compileSrc(String src) { var compiler = new Compiler(); - var typeDict = compiler.compileSrc(src, EnumSet.of(Options.ISSA,Options.DUMP_SSA_IR)); - return compiler.dumpIR(typeDict,true); + var typeDict = compiler.compileSrc(src, EnumSet.of(Options.ISSA)); + return compiler.dumpIR(typeDict, true); } @Test @@ -23,7 +24,30 @@ func foo(d: Int) { } """; String result = compileSrc(src); - System.out.println(result); + Assert.assertEquals(""" + func foo(d: Int) + Reg #0 d 0 + Reg #1 a 1 + Reg #2 b 2 + Reg #3 c 3 + Reg #4 %t4 4 + Reg #5 %t5 5 + Reg #6 a_1 1 + Reg #7 %t7 7 + Reg #8 c_1 3 + L0: + arg d + a = 42 + b = a + %t4 = a+b + c = %t4 + %t5 = c+23 + a_1 = %t5 + %t7 = a_1+d + c_1 = %t7 + goto L1 + L1: + """, result); } @Test @@ -43,7 +67,33 @@ func foo(d: Int)->Int { } """; String result = compileSrc(src); - System.out.println(result); + Assert.assertEquals(""" + func foo(d: Int)->Int + Reg #0 d 0 + Reg #1 a 1 + Reg #2 %t2 2 + Reg #3 a_1 1 + Reg #4 %t4 4 + Reg #5 a_2 1 + Reg #6 a_3 1 + L0: + arg d + a = 42 + if d goto L2 else goto L3 + L2: + %t2 = a+1 + a_1 = %t2 + goto L4 + L4: + a_3 = phi(a_1, a_2) + ret a_3 + goto L1 + L1: + L3: + %t4 = a-1 + a_2 = %t4 + goto L4 + """, result); } @Test @@ -60,7 +110,37 @@ func factorial(num: Int)->Int { } """; String result = compileSrc(src); - System.out.println(result); + Assert.assertEquals(""" + func factorial(num: Int)->Int + Reg #0 num 0 + Reg #1 result 1 + Reg #2 %t2 2 + Reg #3 num_1 0 + Reg #4 %t4 4 + Reg #5 result_1 1 + Reg #6 result_2 1 + Reg #7 %t7 7 + Reg #8 num_2 0 + L0: + arg num + result = 1 + goto L2 + L2: + result_1 = phi(result, result_2) + num_1 = phi(num, num_2) + %t2 = num_1>1 + if %t2 goto L3 else goto L4 + L3: + %t4 = result_1*num_1 + result_2 = %t4 + %t7 = num_1-1 + num_2 = %t7 + goto L2 + L4: + ret result_1 + goto L1 + L1: + """, result); } @@ -102,7 +182,189 @@ func example14_66(p: Int, q: Int, r: Int, s: Int, t: Int) { } """; String result = compileSrc(src); - System.out.println(result); + Assert.assertEquals(""" + func print(a: Int,b: Int,c: Int,d: Int) + Reg #0 a 0 + Reg #1 b 1 + Reg #2 c 2 + Reg #3 d 3 + L0: + arg a + arg b + arg c + arg d + goto L1 + L1: + func example14_66(p: Int,q: Int,r: Int,s: Int,t: Int) + Reg #0 p 0 + Reg #1 q 1 + Reg #2 r 2 + Reg #3 s 3 + Reg #4 t 4 + Reg #5 i 5 + Reg #6 j 6 + Reg #7 k 7 + Reg #8 l 8 + Reg #9 p_1 0 + Reg #10 i_1 5 + Reg #11 j_1 6 + Reg #12 q_1 1 + Reg #13 l_1 8 + Reg #14 l_2 8 + Reg #15 %t15 15 + Reg #16 k_1 7 + Reg #17 k_2 7 + Reg #18 k_3 7 + Reg #19 %t19 19 + Reg #20 k_4 7 + Reg #21 %t21 21 + Reg #22 i_2 5 + Reg #23 i_3 5 + Reg #24 %t24 24 + Reg #25 j_2 6 + Reg #26 j_3 6 + Reg #27 j_4 6 + Reg #28 %t28 28 + Reg #29 k_5 7 + Reg #30 %t30 30 + Reg #31 l_3 8 + Reg #32 l_4 8 + Reg #33 l_5 8 + Reg #34 r_1 2 + Reg #35 %t35 35 + Reg #36 l_6 8 + Reg #37 l_7 8 + Reg #38 %t38 38 + Reg #39 s_1 3 + Reg #40 s_2 3 + Reg #41 r_2 2 + Reg #42 r_3 2 + Reg #43 r_4 2 + Reg #44 r_5 2 + Reg #45 s_3 3 + Reg #46 s_4 3 + Reg #47 s_5 3 + Reg #48 l_8 8 + Reg #49 %t49 49 + Reg #50 i_4 5 + Reg #51 i_5 5 + Reg #52 i_6 5 + Reg #53 i_7 5 + Reg #54 %t54 54 + Reg #55 t_1 4 + Reg #56 t_2 4 + Reg #57 t_3 4 + Reg #58 t_4 4 + Reg #59 t_5 4 + Reg #60 t_6 4 + Reg #61 p_2 0 + Reg #62 p_3 0 + Reg #63 p_4 0 + Reg #64 p_5 0 + Reg #65 p_6 0 + Reg #66 q_2 1 + Reg #67 q_3 1 + Reg #68 q_4 1 + Reg #69 q_5 1 + Reg #70 q_6 1 + Reg #71 r_6 2 + Reg #72 s_6 3 + Reg #73 j_5 6 + Reg #74 j_6 6 + Reg #75 j_7 6 + Reg #76 k_6 7 + Reg #77 k_7 7 + Reg #78 k_8 7 + Reg #79 l_9 8 + L0: + arg p + arg q + arg r + arg s + arg t + i = 1 + j = 1 + k = 1 + l = 1 + goto L2 + L2: + t_5 = phi(t, t_1) + s_5 = phi(s, s_2) + r_4 = phi(r, r_1) + l_5 = phi(l, l_9) + j_4 = phi(j, j_5) + k_2 = phi(k, k_6) + q_1 = phi(q, q_2) + i_1 = phi(i, i_7) + p_1 = phi(p, p_2) + if 1 goto L3 else goto L4 + L3: + if p_1 goto L5 else goto L6 + L5: + j_1 = i_1 + if q_1 goto L8 else goto L9 + L8: + l_1 = 2 + goto L10 + L10: + l_4 = phi(l_1, l_2) + %t15 = k_2+1 + k_3 = %t15 + goto L7 + L7: + l_3 = phi(l_4, l_5) + k_5 = phi(k_3, k_4) + j_2 = phi(j_1, j_4) + %t21 = i_1 + %t24 = j_2 + %t28 = k_5 + %t30 = l_3 + call print params %t21, %t24, %t28, %t30 + goto L11 + L11: + l_6 = phi(l_3, l_8) + if 1 goto L12 else goto L13 + L12: + if r_4 goto L14 else goto L15 + L14: + %t35 = l_6+4 + l_7 = %t35 + goto L15 + L15: + l_8 = phi(l_6, l_7) + %t38 = !s_5 + if %t38 goto L16 else goto L17 + L16: + goto L13 + L13: + l_9 = phi(l_6, l_8) + k_6 = phi(k_5, k_7) + j_5 = phi(j_2, j_6) + q_2 = phi(q_1, q_3) + p_2 = phi(p_1, p_3) + t_1 = phi(t_5, t_2) + i_4 = phi(i_1, i_5) + %t49 = i_4+6 + i_7 = %t49 + %t54 = !t_1 + if %t54 goto L18 else goto L19 + L18: + goto L4 + L4: + goto L1 + L1: + L19: + goto L2 + L17: + goto L11 + L9: + l_2 = 3 + goto L10 + L6: + %t19 = k_2+2 + k_4 = %t19 + goto L7 + """, result); } @Test @@ -127,6 +389,136 @@ func foo()->Int { } """; String result = compileSrc(src); + Assert.assertEquals(""" + func fib(n: Int)->Int + Reg #0 n 0 + Reg #1 i 1 + Reg #2 temp 2 + Reg #3 f1 3 + Reg #4 f2 4 + Reg #5 %t5 5 + Reg #6 i_1 1 + Reg #7 %t7 7 + Reg #8 f1_1 3 + Reg #9 f2_1 4 + Reg #10 f1_2 3 + Reg #11 f2_2 4 + Reg #12 %t12 12 + Reg #13 i_2 1 + L0: + arg n + f1 = 1 + f2 = 1 + i = n + goto L2 + L2: + f2_1 = phi(f2, f2_2) + f1_1 = phi(f1, f1_2) + i_1 = phi(i, i_2) + %t5 = i_1>1 + if %t5 goto L3 else goto L4 + L3: + %t7 = f1_1+f2_1 + temp = %t7 + f1_2 = f2_1 + f2_2 = temp + %t12 = i_1-1 + i_2 = %t12 + goto L2 + L4: + ret f2_1 + goto L1 + L1: + func foo()->Int + Reg #0 %t0 0 + Reg #1 %t1 1 + L0: + %t0 = 10 + %t1 = call fib params %t0 + ret %t1 + goto L1 + L1: + """, result); System.out.println(result); } + + // http://users.csc.calpoly.edu/~akeen/courses/csc431/handouts/references/ssa_example.pdf + @Test + public void testSSAExample() { + String src = """ + func foo(x: Int, y: Int)->Int { + var sum: Int + + if (x >= y) + return 0 + + sum = 0; + while (x < y) { + if (x / 2 * 2 == x) { + sum = sum + 1 + } + x = x + 1 + } + return sum + } + """; + String result = compileSrc(src); + Assert.assertEquals(""" +func foo(x: Int,y: Int)->Int +Reg #0 x 0 +Reg #1 y 1 +Reg #2 sum 2 +Reg #3 %t3 3 +Reg #4 %t4 4 +Reg #5 x_1 0 +Reg #6 y_1 1 +Reg #7 %t7 7 +Reg #8 %t8 8 +Reg #9 %t9 9 +Reg #10 %t10 10 +Reg #11 sum_1 2 +Reg #12 sum_2 2 +Reg #13 %t13 13 +Reg #14 x_2 0 +Reg #15 x_3 0 +Reg #16 y_2 1 +Reg #17 sum_3 2 +L0: + arg x + arg y + %t3 = x>=y + if %t3 goto L2 else goto L3 +L2: + ret 0 + goto L1 +L1: +L3: + sum = 0 + goto L4 +L4: + sum_1 = phi(sum, sum_3) + x_1 = phi(x, x_3) + %t4 = x_1Int { var sum: Int @@ -843,8 +842,117 @@ func foo(x: Int, y: Int)->Int { } """; String result = compileSrc(src); - System.out.println(result); - + Assert.assertEquals(""" +func foo +Before SSA +========== +L0: + arg x + arg y + %t3 = x>=y + if %t3 goto L2 else goto L3 +L2: + ret 0 + goto L1 +L1: +L3: + sum = 0 + goto L4 +L4: + %t4 = x=y_0 + if %t3_0 goto L2 else goto L3 +L2: + ret 0 + goto L1 +L1: +L3: + sum_0 = 0 + goto L4 +L4: + sum_1 = phi(sum_0, sum_3) + x_1 = phi(x_0, x_2) + %t4_0 = x_1=y_0 + if %t3_0 goto L2 else goto L3 +L2: + ret 0 + goto L1 +L1: +L3: + sum_0 = 0 + sum_1 = sum_0 + x_1 = x_0 + goto L4 +L4: + %t4_0 = x_1Int { } """; String result = compileSrc(src); - System.out.println(result); + Assert.assertEquals(""" +func foo +Before SSA +========== +L0: + arg n + a = 1 + b = 2 + goto L2 +L2: + %t4 = n>0 + if %t4 goto L3 else goto L4 +L3: + t = a + a = b + b = t + %t5 = n-1 + n = %t5 + goto L2 +L4: + ret a + goto L1 +L1: +After SSA +========= +L0: + arg n_0 + a_0 = 1 + b_0 = 2 + goto L2 +L2: + b_1 = phi(b_0, b_2) + a_1 = phi(a_0, a_2) + n_1 = phi(n_0, n_2) + %t4_0 = n_1>0 + if %t4_0 goto L3 else goto L4 +L3: + t_0 = a_1 + a_2 = b_1 + b_2 = t_0 + %t5_0 = n_1-1 + n_2 = %t5_0 + goto L2 +L4: + ret a_1 + goto L1 +L1: +After exiting SSA +================= +L0: + arg n_0 + a_0 = 1 + b_0 = 2 + b_1 = b_0 + a_1 = a_0 + n_1 = n_0 + goto L2 +L2: + %t4_0 = n_1>0 + if %t4_0 goto L3 else goto L4 +L3: + t_0 = a_1 + a_2 = b_1 + b_2 = t_0 + %t5_0 = n_1-1 + n_2 = %t5_0 + b_1 = b_2 + a_1 = a_2 + n_1 = n_2 + goto L2 +L4: + ret a_1 + goto L1 +L1: +""", result); } @Test diff --git a/optvm/src/test/java/com/compilerprogramming/ezlang/interpreter/TestInterpreter.java b/optvm/src/test/java/com/compilerprogramming/ezlang/interpreter/TestInterpreter.java index fcfe0f5..acb583c 100644 --- a/optvm/src/test/java/com/compilerprogramming/ezlang/interpreter/TestInterpreter.java +++ b/optvm/src/test/java/com/compilerprogramming/ezlang/interpreter/TestInterpreter.java @@ -4,15 +4,24 @@ import com.compilerprogramming.ezlang.compiler.Options; import org.junit.Assert; import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; +import java.util.ArrayList; +import java.util.Collection; import java.util.EnumSet; +import java.util.List; +@RunWith(Parameterized.class) public class TestInterpreter { + @Parameterized.Parameter + public EnumSet options; + Value compileAndRun(String src, String mainFunction) { - return compileAndRun(src, mainFunction, Options.NONE); + return compileAndRun(src, mainFunction, options); } - Value compileAndRun(String src, String mainFunction, EnumSet options) { + Value compileAndRun(String src, String mainFunction, EnumSet optionsIgnored) { //options.add(Options.ISSA); var compiler = new Compiler(); var typeDict = compiler.compileSrc(src, options); @@ -22,6 +31,16 @@ Value compileAndRun(String src, String mainFunction, EnumSet options) { return interpreter.run(mainFunction); } + @Parameterized.Parameters + public static Collection data() { + List parameters = new ArrayList<>(); + parameters.add(new Object[] { Options.NONE }); + parameters.add(new Object[] { Options.OPT }); + parameters.add(new Object[] { Options.OPT_ISSA }); + return parameters; + } + + @Test public void testFunction1() { String src = """ diff --git a/registervm/src/main/java/com/compilerprogramming/ezlang/compiler/CompiledFunction.java b/registervm/src/main/java/com/compilerprogramming/ezlang/compiler/CompiledFunction.java index 9cd5112..b0849e6 100644 --- a/registervm/src/main/java/com/compilerprogramming/ezlang/compiler/CompiledFunction.java +++ b/registervm/src/main/java/com/compilerprogramming/ezlang/compiler/CompiledFunction.java @@ -176,14 +176,14 @@ private void compileBreak(AST.BreakStmt breakStmt) { } private void compileWhile(AST.WhileStmt whileStmt) { - BasicBlock loopBlock = createLoopHead(); + BasicBlock loopHead = createLoopHead(); BasicBlock bodyBlock = createBlock(); BasicBlock exitBlock = createBlock(); BasicBlock savedBreakTarget = currentBreakTarget; BasicBlock savedContinueTarget = currentContinueTarget; currentBreakTarget = exitBlock; - currentContinueTarget = loopBlock; - startBlock(loopBlock); + currentContinueTarget = loopHead; + startBlock(loopHead); boolean indexed = compileExpr(whileStmt.condition); if (indexed) codeIndexedLoad(); @@ -192,7 +192,7 @@ private void compileWhile(AST.WhileStmt whileStmt) { startBlock(bodyBlock); compileStatement(whileStmt.stmt); if (!isBlockTerminated(currentBlock)) - jumpTo(loopBlock); + jumpTo(loopHead); startBlock(exitBlock); currentContinueTarget = savedContinueTarget; currentBreakTarget = savedBreakTarget; @@ -217,16 +217,16 @@ private void startBlock(BasicBlock block) { } private void compileIf(AST.IfElseStmt ifElseStmt) { - BasicBlock ifBlock = createBlock(); + BasicBlock thenBlock = createBlock(); boolean needElse = ifElseStmt.elseStmt != null; BasicBlock elseBlock = needElse ? createBlock() : null; BasicBlock exitBlock = createBlock(); boolean indexed = compileExpr(ifElseStmt.condition); if (indexed) codeIndexedLoad(); - code(new Instruction.ConditionalBranch(currentBlock, pop(), ifBlock, needElse ? elseBlock : exitBlock)); + code(new Instruction.ConditionalBranch(currentBlock, pop(), thenBlock, needElse ? elseBlock : exitBlock)); assert vstackEmpty(); - startBlock(ifBlock); + startBlock(thenBlock); compileStatement(ifElseStmt.ifStmt); if (!isBlockTerminated(currentBlock)) jumpTo(exitBlock); @@ -363,23 +363,6 @@ private boolean compileSetFieldExpr(AST.SetFieldExpr setFieldExpr) { return false; } - private void codeNew(Type type) { - var temp = createTemp(type); - if (type instanceof Type.TypeArray typeArray) { - code(new Instruction.NewArray(typeArray, temp)); - } - else if (type instanceof Type.TypeStruct typeStruct) { - code(new Instruction.NewStruct(typeStruct, temp)); - } - else - throw new CompilerException("Unexpected type: " + type); - } - - private void codeStoreAppend() { - var operand = pop(); - code(new Instruction.AStoreAppend((Operand.RegisterOperand) top(), operand)); - } - private boolean compileNewExpr(AST.NewExpr newExpr) { codeNew(newExpr.type); if (newExpr.initExprList != null && !newExpr.initExprList.isEmpty()) { @@ -437,7 +420,6 @@ private boolean codeBoolean(AST.BinaryExpr binaryExpr) { return false; } - private boolean compileBinaryExpr(AST.BinaryExpr binaryExpr) { String opCode = binaryExpr.op.str; if (opCode.equals("&&") || @@ -581,15 +563,17 @@ private Operand top() { return virtualStack.getLast(); } + private boolean vstackEmpty() { + return virtualStack.isEmpty(); + } + private Operand.TempRegisterOperand codeIndexedLoad() { Operand indexed = pop(); var temp = createTemp(indexed.type); - if (indexed instanceof Operand.LoadIndexedOperand loadIndexedOperand) { + if (indexed instanceof Operand.LoadIndexedOperand loadIndexedOperand) code(new Instruction.ArrayLoad(loadIndexedOperand, temp)); - } - else if (indexed instanceof Operand.LoadFieldOperand loadFieldOperand) { + else if (indexed instanceof Operand.LoadFieldOperand loadFieldOperand) code(new Instruction.GetField(loadFieldOperand, temp)); - } else code(new Instruction.Move(indexed, temp)); return temp; @@ -598,17 +582,28 @@ else if (indexed instanceof Operand.LoadFieldOperand loadFieldOperand) { private void codeIndexedStore() { Operand value = pop(); Operand indexed = pop(); - if (indexed instanceof Operand.LoadIndexedOperand loadIndexedOperand) { + if (indexed instanceof Operand.LoadIndexedOperand loadIndexedOperand) code(new Instruction.ArrayStore(value, loadIndexedOperand)); - } - else if (indexed instanceof Operand.LoadFieldOperand loadFieldOperand) { + else if (indexed instanceof Operand.LoadFieldOperand loadFieldOperand) code(new Instruction.SetField(value, loadFieldOperand)); - } else code(new Instruction.Move(value, indexed)); } - private boolean vstackEmpty() { - return virtualStack.isEmpty(); + private void codeNew(Type type) { + var temp = createTemp(type); + if (type instanceof Type.TypeArray typeArray) + code(new Instruction.NewArray(typeArray, temp)); + else if (type instanceof Type.TypeStruct typeStruct) + code(new Instruction.NewStruct(typeStruct, temp)); + else + throw new CompilerException("Unexpected type: " + type); } + + private void codeStoreAppend() { + var operand = pop(); + code(new Instruction.AStoreAppend((Operand.RegisterOperand) top(), operand)); + } + + }