From a956288e19bf2e6ddc7eca04f1c2bffea815ed26 Mon Sep 17 00:00:00 2001 From: dibyendumajumdar Date: Wed, 1 Jan 2025 20:52:49 +0000 Subject: [PATCH 1/2] Dot output --- .../ezlang/compiler/BasicBlock.java | 22 ++++++++++++++++ .../ezlang/compiler/CompiledFunction.java | 25 +++++++++++++++---- 2 files changed, 42 insertions(+), 5 deletions(-) diff --git a/optvm/src/main/java/com/compilerprogramming/ezlang/compiler/BasicBlock.java b/optvm/src/main/java/com/compilerprogramming/ezlang/compiler/BasicBlock.java index 5401c04..845b2f6 100644 --- a/optvm/src/main/java/com/compilerprogramming/ezlang/compiler/BasicBlock.java +++ b/optvm/src/main/java/com/compilerprogramming/ezlang/compiler/BasicBlock.java @@ -164,6 +164,28 @@ public static StringBuilder toStr(StringBuilder sb, BasicBlock bb, BitSet visite } return sb; } + private String escapeHtmlChars(String s) { + if (s.contains(">")) + s = s.replaceAll(">", " > "); + if (s.contains(">=")) + s = s.replaceAll(">=", " ≥ "); + if (s.contains("<")) + s = s.replaceAll("<", " < "); + if (s.contains("<=")) + s = s.replaceAll("<=", " ≤ "); + return s; + } + public StringBuilder toDot(StringBuilder sb, boolean verbose) { + sb.append("\n"); + sb.append("\n"); + for (Instruction i: instructions) { + sb.append("\n"); + } + sb.append("
L").append(bid).append("
"); + sb.append(escapeHtmlChars(i.toStr(new StringBuilder()).toString())); + sb.append("
"); + return sb; + } @Override public boolean equals(Object o) { if (this == o) return true; 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 ff005bc..8cd4c23 100644 --- a/optvm/src/main/java/com/compilerprogramming/ezlang/compiler/CompiledFunction.java +++ b/optvm/src/main/java/com/compilerprogramming/ezlang/compiler/CompiledFunction.java @@ -14,7 +14,7 @@ public class CompiledFunction { public BasicBlock entry; public BasicBlock exit; - private int bid = 0; + private int BID = 0; public BasicBlock currentBlock; private BasicBlock currentBreakTarget; private BasicBlock currentContinueTarget; @@ -41,7 +41,7 @@ public CompiledFunction(Symbol.FunctionTypeSymbol functionSymbol) { this.functionType = (Type.TypeFunction) functionSymbol.type; this.registerPool = new RegisterPool(); setVirtualRegisters(funcDecl.scope); - this.bid = 0; + this.BID = 0; this.entry = this.currentBlock = createBlock(); this.exit = createBlock(); this.currentBreakTarget = null; @@ -55,7 +55,7 @@ public CompiledFunction(Symbol.FunctionTypeSymbol functionSymbol) { public CompiledFunction(Type.TypeFunction functionType) { this.functionType = (Type.TypeFunction) functionType; this.registerPool = new RegisterPool(); - this.bid = 0; + this.BID = 0; this.entry = this.currentBlock = createBlock(); this.exit = createBlock(); this.currentBreakTarget = null; @@ -99,11 +99,11 @@ private void setVirtualRegisters(Scope scope) { } public BasicBlock createBlock() { - return new BasicBlock(bid++); + return new BasicBlock(BID++); } private BasicBlock createLoopHead() { - return new BasicBlock(bid++, true); + return new BasicBlock(BID++, true); } private void compileBlock(AST.BlockStmt block) { @@ -574,4 +574,19 @@ public void livenessAnalysis() { public List getBlocks() { return BBHelper.findAllBlocks(entry); } + + public StringBuilder toDot(StringBuilder sb, boolean verbose) { + sb.append("digraph CompiledFunction {\n"); + List blocks = getBlocks(); + for (BasicBlock block: blocks) { + sb.append("L").append(block.bid).append(" [shape=none, margin=0, label=<"); + block.toDot(sb, verbose); + sb.append(">];\n"); + for (BasicBlock s: block.successors) { + sb.append("L").append(block.bid).append(" -> ").append("L").append(s.bid).append("\n"); + } + } + sb.append("}\n"); + return sb; + } } From bfba0002fb269007169623ecc70a3ceed4091312 Mon Sep 17 00:00:00 2001 From: dibyendumajumdar Date: Wed, 1 Jan 2025 20:57:24 +0000 Subject: [PATCH 2/2] SCCP: don't visit instruction that's not in a visited block because block might not be executable Test case added --- .../SparseConditionalConstantPropagation.java | 40 +++++---- .../ezlang/compiler/TestSCCP.java | 85 +++++++++++++++++++ 2 files changed, 108 insertions(+), 17 deletions(-) diff --git a/optvm/src/main/java/com/compilerprogramming/ezlang/compiler/SparseConditionalConstantPropagation.java b/optvm/src/main/java/com/compilerprogramming/ezlang/compiler/SparseConditionalConstantPropagation.java index 47a838b..08c558a 100644 --- a/optvm/src/main/java/com/compilerprogramming/ezlang/compiler/SparseConditionalConstantPropagation.java +++ b/optvm/src/main/java/com/compilerprogramming/ezlang/compiler/SparseConditionalConstantPropagation.java @@ -65,22 +65,6 @@ public SparseConditionalConstantPropagation constantPropagation(CompiledFunction return this; } - @Override - public String toString() { - StringBuilder sb = new StringBuilder(); - sb.append("Flow edges:\n"); - for (var edge : flowEdges.keySet()) { - if (flowEdges.get(edge)) { - sb.append(edge).append("=Executable").append("\n"); - } - } - sb.append("Lattices:\n"); - for (var register: valueLattice.getRegisters()) { - sb.append(register.name()).append("=").append(valueLattice.get(register)).append("\n"); - } - return sb.toString(); - } - private void visitBlock(BasicBlock b) { for (var phi : b.phis()) { visitInstruction(phi); @@ -109,7 +93,10 @@ private void visitInstruction(Instruction instruction) { SSAEdges.SSADef ssaDef = ssaEdges.get(def); if (ssaDef != null) { for (Instruction use : ssaDef.useList) { - instructionWorkList.push(use); + if (visited.get(use.block.bid)) + // Don't visit the instruction if block hasn't been + // visited + instructionWorkList.push(use); } } } @@ -457,6 +444,25 @@ private static boolean evalArith(LatticeElement cell, LatticeElement left, Latti return changed; } + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("Flow edges:\n"); + for (var edge : flowEdges.keySet()) { + if (flowEdges.get(edge)) { + sb.append(edge).append("=Executable").append("\n"); + } + else { + sb.append(edge).append("=NOT Executable").append("\n"); + } + } + sb.append("Lattices:\n"); + for (var register: valueLattice.getRegisters()) { + sb.append(register.name()).append("=").append(valueLattice.get(register)).append("\n"); + } + return sb.toString(); + } + /** * Maintains a Lattice for each SSA variable - i.e register * Initial value of lattice is TOP/Undefined diff --git a/optvm/src/test/java/com/compilerprogramming/ezlang/compiler/TestSCCP.java b/optvm/src/test/java/com/compilerprogramming/ezlang/compiler/TestSCCP.java index ec9ec15..c0d4cae 100644 --- a/optvm/src/test/java/com/compilerprogramming/ezlang/compiler/TestSCCP.java +++ b/optvm/src/test/java/com/compilerprogramming/ezlang/compiler/TestSCCP.java @@ -17,6 +17,7 @@ String compileSrc(String src) { var functionBuilder = (CompiledFunction) f.code(); new EnterSSA(functionBuilder); BasicBlock.toStr(sb, functionBuilder.entry, new BitSet(), false); + //functionBuilder.toDot(sb, false); sb.append(new SparseConditionalConstantPropagation().constantPropagation(functionBuilder).toString()); } } @@ -53,14 +54,98 @@ func foo()->Int { i_1 = 3 goto L4 Flow edges: +L0->L2=NOT Executable L0->L3=Executable L4->L1=Executable +L2->L4=NOT Executable L3->L4=Executable Lattices: i_0=1 %t1_0=0 i_1=3 i_3=3 +"""; + Assert.assertEquals(expected, actual); + } + + // 19.4 in MCIC Appel + // Expected results are based on fig 19.13 page 456 + @Test + public void test2() { + String src = """ +func foo()->Int { + var i = 1 + var j = 1 + var k = 0 + while (k < 100) { + if (j < 20) { + j = i + k = k + 1 + } + else { + j = k + k = k + 2 + } + } + return j +} +"""; + String actual = compileSrc(src); + String expected = """ +L0: + i_0 = 1 + j_0 = 1 + k_0 = 0 + goto L2 +L2: + k_1 = phi(k_0, k_4) + j_1 = phi(j_0, j_4) + %t3_0 = k_1<100 + if %t3_0 goto L3 else goto L4 +L3: + %t4_0 = j_1<20 + if %t4_0 goto L5 else goto L6 +L5: + j_3 = i_0 + %t5_0 = k_1+1 + k_3 = %t5_0 + goto L7 +L7: + k_4 = phi(k_3, k_2) + j_4 = phi(j_3, j_2) + goto L2 +L6: + j_2 = k_1 + %t6_0 = k_1+2 + k_2 = %t6_0 + goto L7 +L4: + ret j_1 + goto L1 +L1: +Flow edges: +L0->L2=Executable +L4->L1=Executable +L2->L3=Executable +L2->L4=Executable +L3->L5=Executable +L7->L2=Executable +L3->L6=NOT Executable +L5->L7=Executable +L6->L7=NOT Executable +Lattices: +j_3=1 +%t5_0=varying +k_3=varying +k_4=varying +j_4=1 +i_0=1 +j_0=1 +k_0=0 +k_1=varying +j_1=1 +%t3_0=varying +%t4_0=1 """; Assert.assertEquals(expected, actual); }