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("| L").append(bid).append(" |
\n");
+ for (Instruction i: instructions) {
+ sb.append("| ");
+ sb.append(escapeHtmlChars(i.toStr(new StringBuilder()).toString()));
+ sb.append(" |
\n");
+ }
+ 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;
+ }
}
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);
}