Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@
* Implementation is based on description in
* 'Practical Improvements to the Construction and Destruction
* of Static Single Assignment Form' by Preston Briggs.
*
* The JikesRVM LeaveSSA implements a version of the
* same algorithm.
*/
public class ExitSSA {

Expand Down Expand Up @@ -70,8 +73,11 @@ private void replaceUses(Instruction i) {
}

static class CopyItem {
/** Phi input can be a register or a constant so we record the operand */
final Operand src;
/** The phi destination */
final Register dest;
/** The basic block where the phi was present */
final BasicBlock destBlock;
boolean removed;

Expand Down Expand Up @@ -130,11 +136,19 @@ private void scheduleCopies(BasicBlock block, List<Integer> pushed) {
a copy target that is live, we must preserve the live
value in a temporary name and rewrite subsequent uses to
refer to the temporary name.

This captures the cases when the result of a phi
in a control successor is live on exit of the current block.
This means that it is incorrect to simply insert a copy
of the destination in the current block. So we rename
the destination to a new temporary, and record the renaming
so that the dominator blocks get the new name. Comment adapted
from JikesRVM LeaveSSA
*/
if (block.liveOut.get(dest.id)) {
/* Insert a copy from dest to a new temp t at phi node defining dest */
final Register t = addMoveToTempAfterPhi(destBlock, dest);
stacks[dest.id].push(t);
stacks[dest.id].push(t); // record the temp name
pushed.add(dest.id);
}
/* Insert a copy operation from map[src] to dest at end of BB */
Expand All @@ -158,6 +172,13 @@ else if (src instanceof Operand.ConstantOperand srcConstantOperand) {
cycle of references, it must insert a copy to a temporary
that breaks the cycle. Then we can schedule the copies to
respect the dependencies implied by the phi functions.

An empty work list with work remaining in the copy set
implies a cycle in the dependencies amongst copies. To break
the cycle copy the destination of an arbitrary member of the
copy set to a temporary. This destination has therefore been
saved and can be safely overwritten. So then add the copy to the
work list. Comment adapted from JikesRVM LeaveSSA.
*/
if (!copySet.isEmpty()) {
CopyItem copyItem = copySet.remove(0);
Expand Down Expand Up @@ -220,6 +241,7 @@ private void addMoveAtBBEnd(BasicBlock block, Register src, Register dest) {
var inst = new Instruction.Move(new Operand.RegisterOperand(src), new Operand.RegisterOperand(dest));
insertAtEnd(block, inst);
}
/* Insert a copy from constant src to dst at end of BB */
private void addMoveAtBBEnd(BasicBlock block, Operand.ConstantOperand src, Register dest) {
var inst = new Instruction.Move(src, new Operand.RegisterOperand(dest));
insertAtEnd(block, inst);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1045,5 +1045,280 @@ func foo() {

}

@Test
public void testParallelAssign() {
String src = """
func foo(n: Int)->Int {
var a = 1
var b = 2

while (n > 0) {
var t = a
a = b
b = t
n = n - 1
}
return a
}
""";
String result = compileSrc(src);
System.out.println(result);
}

@Test
public void testSSA1() {
String src = """
func foo()->Int {
var a = 5
var b = 10
var c = a + b
return c
}
""";
String result = compileSrc(src);
System.out.println(result);
}

@Test
public void testSSA2() {
String src = """
func foo()->Int {
var a = 5
a = a + 1;
return a
}
""";
String result = compileSrc(src);
System.out.println(result);
}

@Test
public void testSSA3() {
String src = """
func foo()->Int {
var a = 5
if (a > 3) {
a = 10
} else {
a = 20
}
return a
}
""";
String result = compileSrc(src);
System.out.println(result);
}

@Test
public void testSSA4() {
String src = """
func foo()->Int {
var a = 0
while (a < 5) {
a = a + 1;
}
return a
}
""";
String result = compileSrc(src);
System.out.println(result);
}

@Test
public void testSSA5() {
String src = """
func foo()->Int {
var a = 0
var b = 10
if (b > 5) {
if (a < 5) {
a = 5
} else {
a = 15
}
} else {
a = 20
}
return a
}
""";
String result = compileSrc(src);
System.out.println(result);
}

@Test
public void testSSA6() {
String src = """
func foo()->Int {
var arr = new [Int] {1, 2};
arr[0] = 10
var x = arr[0]
return x
}
""";
String result = compileSrc(src);
System.out.println(result);
}

@Test
public void testSSA7() {
String src = """
func add(x: Int, y : Int)->Int {
return x + y
}
func main()->Int {
var a = 5
var b = 10
var c = add(a, b)
return c
}
""";
String result = compileSrc(src);
System.out.println(result);
}

@Test
public void testSSA8() {
String src = """
func main()->Int {
var a = 0
var b = 1
while (a < 10) {
a = a + 2
}
while (b < 20) {
b = b + 3
}
return a + b
}
""";
String result = compileSrc(src);
System.out.println(result);
}

@Test
public void testSSA9() {
String src = """
func main()->Int {
var a = 0
var b = 0
var i = 0
var j = 0
while (i < 3) {
j = 0
while (j < 2) {
a = a + 1
i = j + 1
}
b = b + 1;
i = i + 1
}
return a + b
}
""";
String result = compileSrc(src);
System.out.println(result);
}

@Test
public void testSSA10() {
String src = """
func main()->Int {
var sum = 0
var i = 0
var j = 0
while (i < 5) {
j = 0
while (j < 5) {
if (j % 2 == 0)
sum = sum + j
j = j + 1
}
i = i + 1
}
return sum
}
""";
String result = compileSrc(src);
System.out.println(result);
}

@Test
public void testSSA11() {
String src = """
func main()->Int {
var a = 0
var i = 0
var j = 0
while (i < 3) {
j = 0
while (j < 3) {
if (i == j)
a = a + i + j
else if (i > j)
a = a - 1
j = j + 1
}
i = i + 1
}
return a
}
""";
String result = compileSrc(src);
System.out.println(result);
}

@Test
public void testSSA12() {
String src = """
func main()->Int {
var count = 0
var i = 0
var j = 0
while (i < 5) {
j = 0
while (j < 5) {
if (i + j > 5)
break
if (i == j) {
j = j + 1
continue
}
count = count + 1
j = j + 1
}
i = i + 1
}
return count
}
""";
String result = compileSrc(src);
System.out.println(result);
}

@Test
public void testSSA13() {
String src = """
func main()->Int {
var outerSum = 0
var innerSum = 0
var i = 0
var j = 0
while (i < 4) {
j = 0
while (j < 4) {
if ((i + j) % 2 == 0)
innerSum = innerSum + j
j = j + 1
}
outerSum = outerSum + innerSum
i = i + 1
}
return outerSum
}
""";
String result = compileSrc(src);
System.out.println(result);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -348,7 +348,6 @@ private AST.Expr parsePrimary(Lexer lexer) {
case PUNCT -> {
/* Nested expression */
matchPunctuation(lexer, "(");
nextToken(lexer);
var x = parseBool(lexer);
matchPunctuation(lexer, ")");
return x;
Expand Down
Loading