From 91a3631cf6739115f8f84ecbac742f9a6280e9b3 Mon Sep 17 00:00:00 2001 From: dibyendumajumdar Date: Mon, 24 Feb 2025 17:14:16 +0000 Subject: [PATCH] Improve tests Comments added Fix EnterSSA to not put phi nodes in exit block as exit block will never have any instructions Some code adjustments to make comparison easy between regvm and optvm compiler --- .../ezlang/compiler/CompiledFunction.java | 52 ++- .../ezlang/compiler/EnterSSA.java | 2 + .../ezlang/compiler/Options.java | 1 + .../ezlang/compiler/TestIncrementalSSA.java | 404 +++++++++++++++++- .../ezlang/compiler/TestSSATransform.java | 190 +++++++- .../ezlang/interpreter/TestInterpreter.java | 23 +- .../ezlang/compiler/CompiledFunction.java | 65 ++- 7 files changed, 663 insertions(+), 74 deletions(-) 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)); + } + + }