Skip to content

Commit 94bf890

Browse files
2 parents a707fba + 188b9ef commit 94bf890

File tree

2 files changed

+161
-0
lines changed

2 files changed

+161
-0
lines changed

optvm/src/main/java/com/compilerprogramming/ezlang/compiler/EnterSSA.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ public class EnterSSA {
3535

3636
public EnterSSA(CompiledFunction bytecodeFunction, EnumSet<Options> options) {
3737
this.function = bytecodeFunction;
38+
if (function.isSSA) throw new CompilerException("Supplied function is already in SSA form");
3839
setupGlobals();
3940
computeDomTreeAndDominanceFrontiers();
4041
if (options.contains(Options.DUMP_PRE_SSA_DOMTREE)) {

optvm/src/test/java/com/compilerprogramming/ezlang/compiler/TestLiveness.java

Lines changed: 160 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@
66
import org.junit.Assert;
77
import org.junit.Test;
88

9+
import java.util.Arrays;
10+
911
public class TestLiveness {
1012

1113
TypeDictionary compileSrc(String src) {
@@ -564,4 +566,162 @@ func foo()->Int
564566
#LIVEOUT = {1}
565567
""", result.toString());
566568
}
569+
570+
// From discussion
571+
// https://www.reddit.com/r/Compilers/comments/1qhfbqh/liveness_analysis_correctness/
572+
static CompiledFunction buildTestReddit() {
573+
TypeDictionary typeDictionary = new TypeDictionary();
574+
EZType.EZTypeFunction functionType = new EZType.EZTypeFunction("foo");
575+
functionType.setReturnType(typeDictionary.INT);
576+
CompiledFunction function = new CompiledFunction(functionType, typeDictionary);
577+
RegisterPool regPool = function.registerPool;
578+
Register v0_0 = regPool.newReg("v0_0", typeDictionary.INT);
579+
Register v0_1 = regPool.newReg("v0_1", typeDictionary.INT);
580+
Register v0_2 = regPool.newReg("v0_2", typeDictionary.INT);
581+
Register v1_0 = regPool.newReg("v1_0", typeDictionary.INT);
582+
Register v1_1 = regPool.newReg("v1_1", typeDictionary.INT);
583+
Register v1_2 = regPool.newReg("v1_2", typeDictionary.INT);
584+
Register v2_0 = regPool.newReg("v2_0", typeDictionary.INT);
585+
Register v2_1 = regPool.newReg("v2_1", typeDictionary.INT);
586+
Register v2_2 = regPool.newReg("v2_2", typeDictionary.INT);
587+
Register v3_0 = regPool.newReg("v3_0", typeDictionary.INT);
588+
Register v4_0 = regPool.newReg("v4_0", typeDictionary.INT);
589+
function.code(new Instruction.Move(
590+
new Operand.ConstantOperand(47, typeDictionary.INT),
591+
new Operand.RegisterOperand(v0_0)));
592+
function.code(new Instruction.Move(
593+
new Operand.ConstantOperand(42, typeDictionary.INT),
594+
new Operand.RegisterOperand(v1_0)));
595+
function.code(new Instruction.Move(
596+
new Operand.ConstantOperand(1, typeDictionary.INT),
597+
new Operand.RegisterOperand(v3_0)));
598+
BasicBlock b1 = function.createBlock();
599+
BasicBlock b2 = function.createBlock();
600+
BasicBlock b3 = function.createBlock();
601+
BasicBlock b4 = function.createBlock();
602+
function.code(new Instruction.ConditionalBranch(
603+
function.currentBlock,
604+
new Operand.RegisterOperand(v3_0),
605+
b1, b2));
606+
function.currentBlock.addSuccessor(b1);
607+
function.currentBlock.addSuccessor(b2);
608+
function.startBlock(b1);
609+
function.code(new Instruction.Move(
610+
new Operand.ConstantOperand(1, typeDictionary.INT),
611+
new Operand.RegisterOperand(v1_1)));
612+
function.code(new Instruction.Move(
613+
new Operand.ConstantOperand(5, typeDictionary.INT),
614+
new Operand.RegisterOperand(v2_0)));
615+
function.jumpTo(b3);
616+
617+
function.startBlock(b2);
618+
function.code(new Instruction.Move(
619+
new Operand.ConstantOperand(2, typeDictionary.INT),
620+
new Operand.RegisterOperand(v0_2)));
621+
function.code(new Instruction.Move(
622+
new Operand.ConstantOperand(10, typeDictionary.INT),
623+
new Operand.RegisterOperand(v2_2)));
624+
function.jumpTo(b3);
625+
626+
function.startBlock(b3);
627+
function.code(new Instruction.Phi(v2_1, Arrays.asList(v2_0, v2_2)));
628+
function.code(new Instruction.Phi(v1_2, Arrays.asList(v1_1, v1_0)));
629+
function.code(new Instruction.Phi(v0_1, Arrays.asList(v0_0, v0_2)));
630+
function.code(new Instruction.Binary(
631+
"-",
632+
new Operand.RegisterOperand(v4_0),
633+
new Operand.RegisterOperand(v0_1),
634+
new Operand.RegisterOperand(v2_1)));
635+
636+
function.jumpTo(b4);
637+
function.startBlock(b4);
638+
function.code(new Instruction.Ret(new Operand.RegisterOperand(v4_0)));
639+
function.startBlock(function.exit);
640+
function.isSSA = true;
641+
642+
System.out.println(function.toStr(new StringBuilder(), true));
643+
644+
return function;
645+
}
646+
647+
@Test
648+
public void testReddit() {
649+
CompiledFunction function = buildTestReddit();
650+
function.livenessAnalysis();
651+
String actual = function.toStr(new StringBuilder(), true).toString();
652+
Assert.assertEquals("""
653+
func foo()->Int
654+
Reg #0 v0_0 0
655+
Reg #1 v0_1 1
656+
Reg #2 v0_2 2
657+
Reg #3 v1_0 3
658+
Reg #4 v1_1 4
659+
Reg #5 v1_2 5
660+
Reg #6 v2_0 6
661+
Reg #7 v2_1 7
662+
Reg #8 v2_2 8
663+
Reg #9 v3_0 9
664+
Reg #10 v4_0 10
665+
L0:
666+
v0_0 = 47
667+
v1_0 = 42
668+
v3_0 = 1
669+
if v3_0 goto L2 else goto L3
670+
#PHIDEFS = {}
671+
#PHIUSES = {}
672+
#UEVAR = {}
673+
#VARKILL = {0, 3, 9}
674+
#LIVEIN = {}
675+
#LIVEOUT = {0, 3}
676+
L2:
677+
v1_1 = 1
678+
v2_0 = 5
679+
goto L4
680+
#PHIDEFS = {}
681+
#PHIUSES = {0, 4, 6}
682+
#UEVAR = {}
683+
#VARKILL = {4, 6}
684+
#LIVEIN = {0}
685+
#LIVEOUT = {0, 4, 6}
686+
L4:
687+
v2_1 = phi(v2_0, v2_2)
688+
v1_2 = phi(v1_1, v1_0)
689+
v0_1 = phi(v0_0, v0_2)
690+
v4_0 = v0_1-v2_1
691+
goto L5
692+
#PHIDEFS = {1, 5, 7}
693+
#PHIUSES = {}
694+
#UEVAR = {1, 7}
695+
#VARKILL = {10}
696+
#LIVEIN = {1, 5, 7}
697+
#LIVEOUT = {10}
698+
L5:
699+
ret v4_0
700+
goto L1
701+
#PHIDEFS = {}
702+
#PHIUSES = {}
703+
#UEVAR = {10}
704+
#VARKILL = {}
705+
#LIVEIN = {10}
706+
#LIVEOUT = {}
707+
L1:
708+
#PHIDEFS = {}
709+
#PHIUSES = {}
710+
#UEVAR = {}
711+
#VARKILL = {}
712+
#LIVEIN = {}
713+
#LIVEOUT = {}
714+
L3:
715+
v0_2 = 2
716+
v2_2 = 10
717+
goto L4
718+
#PHIDEFS = {}
719+
#PHIUSES = {2, 3, 8}
720+
#UEVAR = {}
721+
#VARKILL = {2, 8}
722+
#LIVEIN = {3}
723+
#LIVEOUT = {2, 3, 8}
724+
""", actual);
725+
}
726+
567727
}

0 commit comments

Comments
 (0)