Skip to content

Commit 8e4fb47

Browse files
Merge pull request #24 from CompilerProgramming/sccp
A parser bugfix and additional test cases for SSA
2 parents 3a9e584 + 9aa77e1 commit 8e4fb47

File tree

3 files changed

+298
-2
lines changed

3 files changed

+298
-2
lines changed

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

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,9 @@
77
* Implementation is based on description in
88
* 'Practical Improvements to the Construction and Destruction
99
* of Static Single Assignment Form' by Preston Briggs.
10+
*
11+
* The JikesRVM LeaveSSA implements a version of the
12+
* same algorithm.
1013
*/
1114
public class ExitSSA {
1215

@@ -70,8 +73,11 @@ private void replaceUses(Instruction i) {
7073
}
7174

7275
static class CopyItem {
76+
/** Phi input can be a register or a constant so we record the operand */
7377
final Operand src;
78+
/** The phi destination */
7479
final Register dest;
80+
/** The basic block where the phi was present */
7581
final BasicBlock destBlock;
7682
boolean removed;
7783

@@ -130,11 +136,19 @@ private void scheduleCopies(BasicBlock block, List<Integer> pushed) {
130136
a copy target that is live, we must preserve the live
131137
value in a temporary name and rewrite subsequent uses to
132138
refer to the temporary name.
139+
140+
This captures the cases when the result of a phi
141+
in a control successor is live on exit of the current block.
142+
This means that it is incorrect to simply insert a copy
143+
of the destination in the current block. So we rename
144+
the destination to a new temporary, and record the renaming
145+
so that the dominator blocks get the new name. Comment adapted
146+
from JikesRVM LeaveSSA
133147
*/
134148
if (block.liveOut.get(dest.id)) {
135149
/* Insert a copy from dest to a new temp t at phi node defining dest */
136150
final Register t = addMoveToTempAfterPhi(destBlock, dest);
137-
stacks[dest.id].push(t);
151+
stacks[dest.id].push(t); // record the temp name
138152
pushed.add(dest.id);
139153
}
140154
/* Insert a copy operation from map[src] to dest at end of BB */
@@ -158,6 +172,13 @@ else if (src instanceof Operand.ConstantOperand srcConstantOperand) {
158172
cycle of references, it must insert a copy to a temporary
159173
that breaks the cycle. Then we can schedule the copies to
160174
respect the dependencies implied by the phi functions.
175+
176+
An empty work list with work remaining in the copy set
177+
implies a cycle in the dependencies amongst copies. To break
178+
the cycle copy the destination of an arbitrary member of the
179+
copy set to a temporary. This destination has therefore been
180+
saved and can be safely overwritten. So then add the copy to the
181+
work list. Comment adapted from JikesRVM LeaveSSA.
161182
*/
162183
if (!copySet.isEmpty()) {
163184
CopyItem copyItem = copySet.remove(0);
@@ -220,6 +241,7 @@ private void addMoveAtBBEnd(BasicBlock block, Register src, Register dest) {
220241
var inst = new Instruction.Move(new Operand.RegisterOperand(src), new Operand.RegisterOperand(dest));
221242
insertAtEnd(block, inst);
222243
}
244+
/* Insert a copy from constant src to dst at end of BB */
223245
private void addMoveAtBBEnd(BasicBlock block, Operand.ConstantOperand src, Register dest) {
224246
var inst = new Instruction.Move(src, new Operand.RegisterOperand(dest));
225247
insertAtEnd(block, inst);

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

Lines changed: 275 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1045,5 +1045,280 @@ func foo() {
10451045

10461046
}
10471047

1048+
@Test
1049+
public void testParallelAssign() {
1050+
String src = """
1051+
func foo(n: Int)->Int {
1052+
var a = 1
1053+
var b = 2
1054+
1055+
while (n > 0) {
1056+
var t = a
1057+
a = b
1058+
b = t
1059+
n = n - 1
1060+
}
1061+
return a
1062+
}
1063+
""";
1064+
String result = compileSrc(src);
1065+
System.out.println(result);
1066+
}
1067+
1068+
@Test
1069+
public void testSSA1() {
1070+
String src = """
1071+
func foo()->Int {
1072+
var a = 5
1073+
var b = 10
1074+
var c = a + b
1075+
return c
1076+
}
1077+
""";
1078+
String result = compileSrc(src);
1079+
System.out.println(result);
1080+
}
1081+
1082+
@Test
1083+
public void testSSA2() {
1084+
String src = """
1085+
func foo()->Int {
1086+
var a = 5
1087+
a = a + 1;
1088+
return a
1089+
}
1090+
""";
1091+
String result = compileSrc(src);
1092+
System.out.println(result);
1093+
}
1094+
1095+
@Test
1096+
public void testSSA3() {
1097+
String src = """
1098+
func foo()->Int {
1099+
var a = 5
1100+
if (a > 3) {
1101+
a = 10
1102+
} else {
1103+
a = 20
1104+
}
1105+
return a
1106+
}
1107+
""";
1108+
String result = compileSrc(src);
1109+
System.out.println(result);
1110+
}
1111+
1112+
@Test
1113+
public void testSSA4() {
1114+
String src = """
1115+
func foo()->Int {
1116+
var a = 0
1117+
while (a < 5) {
1118+
a = a + 1;
1119+
}
1120+
return a
1121+
}
1122+
""";
1123+
String result = compileSrc(src);
1124+
System.out.println(result);
1125+
}
1126+
1127+
@Test
1128+
public void testSSA5() {
1129+
String src = """
1130+
func foo()->Int {
1131+
var a = 0
1132+
var b = 10
1133+
if (b > 5) {
1134+
if (a < 5) {
1135+
a = 5
1136+
} else {
1137+
a = 15
1138+
}
1139+
} else {
1140+
a = 20
1141+
}
1142+
return a
1143+
}
1144+
""";
1145+
String result = compileSrc(src);
1146+
System.out.println(result);
1147+
}
1148+
1149+
@Test
1150+
public void testSSA6() {
1151+
String src = """
1152+
func foo()->Int {
1153+
var arr = new [Int] {1, 2};
1154+
arr[0] = 10
1155+
var x = arr[0]
1156+
return x
1157+
}
1158+
""";
1159+
String result = compileSrc(src);
1160+
System.out.println(result);
1161+
}
1162+
1163+
@Test
1164+
public void testSSA7() {
1165+
String src = """
1166+
func add(x: Int, y : Int)->Int {
1167+
return x + y
1168+
}
1169+
func main()->Int {
1170+
var a = 5
1171+
var b = 10
1172+
var c = add(a, b)
1173+
return c
1174+
}
1175+
""";
1176+
String result = compileSrc(src);
1177+
System.out.println(result);
1178+
}
1179+
1180+
@Test
1181+
public void testSSA8() {
1182+
String src = """
1183+
func main()->Int {
1184+
var a = 0
1185+
var b = 1
1186+
while (a < 10) {
1187+
a = a + 2
1188+
}
1189+
while (b < 20) {
1190+
b = b + 3
1191+
}
1192+
return a + b
1193+
}
1194+
""";
1195+
String result = compileSrc(src);
1196+
System.out.println(result);
1197+
}
1198+
1199+
@Test
1200+
public void testSSA9() {
1201+
String src = """
1202+
func main()->Int {
1203+
var a = 0
1204+
var b = 0
1205+
var i = 0
1206+
var j = 0
1207+
while (i < 3) {
1208+
j = 0
1209+
while (j < 2) {
1210+
a = a + 1
1211+
i = j + 1
1212+
}
1213+
b = b + 1;
1214+
i = i + 1
1215+
}
1216+
return a + b
1217+
}
1218+
""";
1219+
String result = compileSrc(src);
1220+
System.out.println(result);
1221+
}
1222+
1223+
@Test
1224+
public void testSSA10() {
1225+
String src = """
1226+
func main()->Int {
1227+
var sum = 0
1228+
var i = 0
1229+
var j = 0
1230+
while (i < 5) {
1231+
j = 0
1232+
while (j < 5) {
1233+
if (j % 2 == 0)
1234+
sum = sum + j
1235+
j = j + 1
1236+
}
1237+
i = i + 1
1238+
}
1239+
return sum
1240+
}
1241+
""";
1242+
String result = compileSrc(src);
1243+
System.out.println(result);
1244+
}
1245+
1246+
@Test
1247+
public void testSSA11() {
1248+
String src = """
1249+
func main()->Int {
1250+
var a = 0
1251+
var i = 0
1252+
var j = 0
1253+
while (i < 3) {
1254+
j = 0
1255+
while (j < 3) {
1256+
if (i == j)
1257+
a = a + i + j
1258+
else if (i > j)
1259+
a = a - 1
1260+
j = j + 1
1261+
}
1262+
i = i + 1
1263+
}
1264+
return a
1265+
}
1266+
""";
1267+
String result = compileSrc(src);
1268+
System.out.println(result);
1269+
}
1270+
1271+
@Test
1272+
public void testSSA12() {
1273+
String src = """
1274+
func main()->Int {
1275+
var count = 0
1276+
var i = 0
1277+
var j = 0
1278+
while (i < 5) {
1279+
j = 0
1280+
while (j < 5) {
1281+
if (i + j > 5)
1282+
break
1283+
if (i == j) {
1284+
j = j + 1
1285+
continue
1286+
}
1287+
count = count + 1
1288+
j = j + 1
1289+
}
1290+
i = i + 1
1291+
}
1292+
return count
1293+
}
1294+
""";
1295+
String result = compileSrc(src);
1296+
System.out.println(result);
1297+
}
1298+
1299+
@Test
1300+
public void testSSA13() {
1301+
String src = """
1302+
func main()->Int {
1303+
var outerSum = 0
1304+
var innerSum = 0
1305+
var i = 0
1306+
var j = 0
1307+
while (i < 4) {
1308+
j = 0
1309+
while (j < 4) {
1310+
if ((i + j) % 2 == 0)
1311+
innerSum = innerSum + j
1312+
j = j + 1
1313+
}
1314+
outerSum = outerSum + innerSum
1315+
i = i + 1
1316+
}
1317+
return outerSum
1318+
}
1319+
""";
1320+
String result = compileSrc(src);
1321+
System.out.println(result);
1322+
}
10481323

10491324
}

parser/src/main/java/com/compilerprogramming/ezlang/parser/Parser.java

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -348,7 +348,6 @@ private AST.Expr parsePrimary(Lexer lexer) {
348348
case PUNCT -> {
349349
/* Nested expression */
350350
matchPunctuation(lexer, "(");
351-
nextToken(lexer);
352351
var x = parseBool(lexer);
353352
matchPunctuation(lexer, ")");
354353
return x;

0 commit comments

Comments
 (0)