summaryrefslogtreecommitdiff
path: root/chapter16/src/test/java/com/seaofnodes
diff options
context:
space:
mode:
Diffstat (limited to 'chapter16/src/test/java/com/seaofnodes')
-rw-r--r--chapter16/src/test/java/com/seaofnodes/simple/Chapter04Test.java5
-rw-r--r--chapter16/src/test/java/com/seaofnodes/simple/Chapter05Test.java14
-rw-r--r--chapter16/src/test/java/com/seaofnodes/simple/Chapter06Test.java10
-rw-r--r--chapter16/src/test/java/com/seaofnodes/simple/Chapter07Test.java26
-rw-r--r--chapter16/src/test/java/com/seaofnodes/simple/Chapter08Test.java16
-rw-r--r--chapter16/src/test/java/com/seaofnodes/simple/Chapter09Test.java10
-rw-r--r--chapter16/src/test/java/com/seaofnodes/simple/Chapter10Test.java129
-rw-r--r--chapter16/src/test/java/com/seaofnodes/simple/Chapter10bTest.java64
-rw-r--r--chapter16/src/test/java/com/seaofnodes/simple/Chapter11Test.java6
-rw-r--r--chapter16/src/test/java/com/seaofnodes/simple/Chapter12Test.java2
-rw-r--r--chapter16/src/test/java/com/seaofnodes/simple/Chapter14Test.java4
-rw-r--r--chapter16/src/test/java/com/seaofnodes/simple/Chapter15Test.java3
-rw-r--r--chapter16/src/test/java/com/seaofnodes/simple/Chapter16Test.java25
-rw-r--r--chapter16/src/test/java/com/seaofnodes/simple/evaluator/Evaluator.java16
-rw-r--r--chapter16/src/test/java/com/seaofnodes/simple/evaluator/Scheduler.java33
15 files changed, 282 insertions, 81 deletions
diff --git a/chapter16/src/test/java/com/seaofnodes/simple/Chapter04Test.java b/chapter16/src/test/java/com/seaofnodes/simple/Chapter04Test.java
index a3109ff7..14d31245 100644
--- a/chapter16/src/test/java/com/seaofnodes/simple/Chapter04Test.java
+++ b/chapter16/src/test/java/com/seaofnodes/simple/Chapter04Test.java
@@ -84,7 +84,10 @@ public class Chapter04Test {
StopNode stop = parser.parse();
ReturnNode ret = stop.ret();
assertTrue(ret.in(0) instanceof CProjNode);
- assertTrue(ret.in(1) instanceof ProjNode);
+ assertTrue(ret.in(1) instanceof ProjNode);
+ assertEquals(1, ((ProjNode)ret.in(1))._idx);
+ assertTrue(ret.in(2) instanceof ProjNode);
+ assertEquals(2, ((ProjNode)ret.in(2))._idx);
}
@Test
diff --git a/chapter16/src/test/java/com/seaofnodes/simple/Chapter05Test.java b/chapter16/src/test/java/com/seaofnodes/simple/Chapter05Test.java
index b5920125..ca7bb482 100644
--- a/chapter16/src/test/java/com/seaofnodes/simple/Chapter05Test.java
+++ b/chapter16/src/test/java/com/seaofnodes/simple/Chapter05Test.java
@@ -22,7 +22,7 @@ else {
return a;""");
StopNode ret = parser.parse().iterate();
- assertEquals("return Phi(Region23,(arg+2),(arg-3));", ret.toString());
+ assertEquals("return Phi(Region21,(arg+2),(arg-3));", ret.toString());
}
@Test
@@ -37,7 +37,7 @@ if (arg == 1) {
}
return c;""", TypeInteger.BOT);
StopNode ret = parser.parse().iterate();
- assertEquals("return Phi(Region22,4,3);", ret.toString());
+ assertEquals("return Phi(Region20,4,3);", ret.toString());
}
@Test
@@ -65,7 +65,7 @@ else
b=a+1;
return a+b;""");
StopNode ret = parser.parse().iterate();
- assertEquals("return ((arg*2)+Phi(Region26,2,3));", ret.toString());
+ assertEquals("return ((arg*2)+Phi(Region24,2,3));", ret.toString());
}
@Test
@@ -80,7 +80,7 @@ else
a=b+1;
return a+b;""");
StopNode ret = parser.parse().iterate();
- assertEquals("return ((Phi(Region37,(arg*2),arg)+arg)+Phi(Region,4,5));", ret.toString());
+ assertEquals("return ((Phi(Region35,(arg*2),arg)+arg)+Phi(Region,4,5));", ret.toString());
}
@Test
@@ -100,7 +100,7 @@ else
return a;
""", TypeInteger.BOT);
StopNode stop = parser.parse().iterate();
- assertEquals("return Phi(Region43,Phi(Region28,2,3),Phi(Region41,4,5));", stop.toString());
+ assertEquals("return Phi(Region39,Phi(Region25,2,3),Phi(Region37,4,5));", stop.toString());
}
@Test
@@ -116,7 +116,7 @@ if( arg==0 )
return arg+a+b;
""", TypeInteger.BOT);
StopNode stop = parser.parse();
- assertEquals("return ((arg+Phi(Region20,1,0))+Phi(Region37,2,0));", stop.toString());
+ assertEquals("return ((arg+Phi(Region18,1,0))+Phi(Region34,2,0));", stop.toString());
}
@Test
@@ -130,7 +130,7 @@ if( arg==1 )
}
return a;""");
StopNode ret = parser.parse().iterate();
- assertEquals("return (arg==Phi(Region22,3,2));", ret.toString());
+ assertEquals("return (arg==Phi(Region20,3,2));", ret.toString());
}
@Test
diff --git a/chapter16/src/test/java/com/seaofnodes/simple/Chapter06Test.java b/chapter16/src/test/java/com/seaofnodes/simple/Chapter06Test.java
index ff1f3251..d2c46df5 100644
--- a/chapter16/src/test/java/com/seaofnodes/simple/Chapter06Test.java
+++ b/chapter16/src/test/java/com/seaofnodes/simple/Chapter06Test.java
@@ -65,7 +65,7 @@ else
b=5;
return b;""", TypeInteger.BOT);
StopNode stop = parser.parse().iterate();
- assertEquals("return Phi(Region43,42,5);", stop.toString());
+ assertEquals("return Phi(Region40,42,5);", stop.toString());
}
@Test
@@ -84,7 +84,7 @@ else
b=5;
return b;""", TypeInteger.BOT);
StopNode stop = parser.parse().iterate();
- assertEquals("return Phi(Region38,2,5);", stop.toString());
+ assertEquals("return Phi(Region33,2,5);", stop.toString());
}
@Test
@@ -144,7 +144,7 @@ else
return a;
""", TypeInteger.BOT);
StopNode stop = parser.parse().iterate();
- assertEquals("return Phi(Region48,3,Phi(Region46,4,5));", stop.toString());
+ assertEquals("return Phi(Region44,3,Phi(Region42,4,5));", stop.toString());
}
@Test
@@ -200,7 +200,7 @@ if( arg ) {
return a+b;
""");
StopNode ret = parser.parse().iterate();
- assertEquals("return Phi(Region35,4,1);", ret.toString());
+ assertEquals("return Phi(Region29,4,1);", ret.toString());
}
@@ -251,7 +251,7 @@ if( arg ) {
return a+b+c;
""");
StopNode ret = parser.parse().iterate();
- assertEquals("return (Phi(Region48,Phi(Region29,2,3),0)+Phi(Region,3,1));", ret.toString());
+ assertEquals("return (Phi(Region41,Phi(Region26,2,3),0)+Phi(Region,3,1));", ret.toString());
}
diff --git a/chapter16/src/test/java/com/seaofnodes/simple/Chapter07Test.java b/chapter16/src/test/java/com/seaofnodes/simple/Chapter07Test.java
index 390e1da5..443b0d17 100644
--- a/chapter16/src/test/java/com/seaofnodes/simple/Chapter07Test.java
+++ b/chapter16/src/test/java/com/seaofnodes/simple/Chapter07Test.java
@@ -17,7 +17,7 @@ public class Chapter07Test {
return arg;
""");
StopNode stop = parser.parse();
- assertEquals("return Phi(Loop10,arg,(Phi_arg+1));", stop.toString());
+ assertEquals("return Phi(Loop9,arg,(Phi_arg+1));", stop.toString());
assertTrue(stop.ret().ctrl() instanceof CProjNode);
}
@@ -34,7 +34,7 @@ if(arg){}else{
return a;
""");
StopNode stop = parser.parse().iterate();
- assertEquals("return Phi(Region31,1,Phi(Loop18,1,(Phi_a+1)));", stop.toString());
+ assertEquals("return Phi(Region27,1,Phi(Loop16,1,(Phi_a+1)));", stop.toString());
}
@Test
@@ -54,7 +54,7 @@ while(i < arg) {
return sum;
""");
StopNode stop = parser.parse().iterate();
- assertEquals("return Phi(Loop12,0,Phi(Loop26,Phi_sum,(Phi_sum+Phi(Loop,0,(Phi_j+1)))));", stop.toString());
+ assertEquals("return Phi(Loop11,0,Phi(Loop23,Phi_sum,(Phi_sum+Phi(Loop,0,(Phi_j+1)))));", stop.toString());
}
@Test
@@ -70,7 +70,7 @@ while(a < 10) {
return b;
""");
StopNode stop = parser.parse();
- assertEquals("return Phi(Loop12,2,Phi(Region34,Phi_b,4));", stop.toString());
+ assertEquals("return Phi(Loop11,2,Phi(Region30,Phi_b,4));", stop.toString());
assertTrue(stop.ret().ctrl() instanceof CProjNode);
}
@@ -89,7 +89,7 @@ while(a < 10) {
return b;
""");
StopNode stop = parser.parse().iterate();
- assertEquals("return Phi(Loop12,2,(Phi(Region34,Phi_b,4)+1));", stop.toString());
+ assertEquals("return Phi(Loop11,2,(Phi(Region30,Phi_b,4)+1));", stop.toString());
assertTrue(stop.ret().ctrl() instanceof CProjNode);
}
@@ -106,7 +106,7 @@ while(a < 10) {
return a;
""");
StopNode stop = parser.parse();
- assertEquals("return Phi(Loop11,1,(Phi_a+3));", stop.toString());
+ assertEquals("return Phi(Loop10,1,(Phi_a+3));", stop.toString());
assertTrue(stop.ret().ctrl() instanceof CProjNode);
}
@@ -122,7 +122,7 @@ while(a < 10) {
return a;
""");
StopNode stop = parser.parse().iterate();
- assertEquals("return Phi(Loop11,1,(Phi_a+3));", stop.toString());
+ assertEquals("return Phi(Loop10,1,(Phi_a+3));", stop.toString());
assertTrue(stop.ret().ctrl() instanceof CProjNode);
}
@@ -135,7 +135,7 @@ while(arg) a = 2;
return a;
""");
StopNode stop = parser.parse();
- assertEquals("return Phi(Loop11,1,2);", stop.toString());
+ assertEquals("return Phi(Loop10,1,2);", stop.toString());
assertTrue(stop.ret().ctrl() instanceof CProjNode);
}
@@ -148,7 +148,7 @@ while(arg) a = 2;
return a;
""");
StopNode stop = parser.parse().iterate();
- assertEquals("return Phi(Loop11,1,2);", stop.toString());
+ assertEquals("return Phi(Loop10,1,2);", stop.toString());
assertTrue(stop.ret().ctrl() instanceof CProjNode);
}
@@ -164,7 +164,7 @@ while(a < 10) {
return a;
""");
StopNode stop = parser.parse();
- assertEquals("return Phi(Loop11,1,(Phi_a+3));", stop.toString());
+ assertEquals("return Phi(Loop10,1,(Phi_a+3));", stop.toString());
assertTrue(stop.ret().ctrl() instanceof CProjNode);
}
@@ -180,7 +180,7 @@ while(a < 10) {
return a;
""");
StopNode stop = parser.parse().iterate();
- assertEquals("return Phi(Loop11,1,(Phi_a+3));", stop.toString());
+ assertEquals("return Phi(Loop10,1,(Phi_a+3));", stop.toString());
assertTrue(stop.ret().ctrl() instanceof CProjNode);
}
@@ -197,7 +197,7 @@ while(a < 10) {
return a;
""");
StopNode stop = parser.parse();
- assertEquals("return Phi(Loop12,1,(Phi_a+3));", stop.toString());
+ assertEquals("return Phi(Loop11,1,(Phi_a+3));", stop.toString());
assertTrue(stop.ret().ctrl() instanceof CProjNode);
}
@@ -214,7 +214,7 @@ while(a < 10) {
return a;
""");
StopNode stop = parser.parse().iterate();
- assertEquals("return Phi(Loop12,1,(Phi_a+3));", stop.toString());
+ assertEquals("return Phi(Loop11,1,(Phi_a+3));", stop.toString());
assertTrue(stop.ret().ctrl() instanceof CProjNode);
}
diff --git a/chapter16/src/test/java/com/seaofnodes/simple/Chapter08Test.java b/chapter16/src/test/java/com/seaofnodes/simple/Chapter08Test.java
index c199b78c..89ce8313 100644
--- a/chapter16/src/test/java/com/seaofnodes/simple/Chapter08Test.java
+++ b/chapter16/src/test/java/com/seaofnodes/simple/Chapter08Test.java
@@ -23,7 +23,7 @@ while(arg < 10) {
return arg;
""");
StopNode stop = parser.parse().iterate();
- assertEquals("return Phi(Region45,Phi(Region32,Phi(Loop10,arg,(Phi_arg+1)),Add),Add);", stop.toString());
+ assertEquals("return Phi(Region38,Phi(Region27,Phi(Loop9,arg,(Phi_arg+1)),Add),Add);", stop.toString());
assertTrue(stop.ret().ctrl() instanceof RegionNode);
Assert.assertEquals(5L, Evaluator.evaluate(stop, 1));
Assert.assertEquals(10L, Evaluator.evaluate(stop, 6));
@@ -46,7 +46,7 @@ while(arg < 10) {
return a;
""");
StopNode stop = parser.parse().iterate();
- assertEquals("return Phi(Loop11,1,Phi(Region52,Phi_a,(Phi_a+1)));", stop.toString());
+ assertEquals("return Phi(Loop10,1,Phi(Region44,Phi_a,(Phi_a+1)));", stop.toString());
assertTrue(stop.ret().ctrl() instanceof CProjNode);
}
@@ -65,7 +65,7 @@ while(arg < 10) {
return arg;
""");
StopNode stop = parser.parse().iterate();
- assertEquals("return Phi(Region43,Phi(Loop10,arg,(Phi_arg+1)),Add);", stop.toString());
+ assertEquals("return Phi(Region36,Phi(Loop9,arg,(Phi_arg+1)),Add);", stop.toString());
assertTrue(stop.ret().ctrl() instanceof RegionNode);
}
@@ -81,7 +81,7 @@ while(arg < 10) {
return arg;
""");
StopNode stop = parser.parse().iterate();
- assertEquals("return Phi(Region32,Phi(Loop10,arg,(Phi_arg+1)),Add);", stop.toString());
+ assertEquals("return Phi(Region27,Phi(Loop9,arg,(Phi_arg+1)),Add);", stop.toString());
assertTrue(stop.ret().ctrl() instanceof RegionNode);
}
@@ -100,7 +100,7 @@ while(arg < 10) {
return arg;
""");
StopNode stop = parser.parse().iterate();
- assertEquals("return Phi(Loop10,arg,(Phi_arg+1));", stop.toString());
+ assertEquals("return Phi(Loop9,arg,(Phi_arg+1));", stop.toString());
assertTrue(stop.ret().ctrl() instanceof CProjNode);
}
@@ -117,7 +117,7 @@ while(arg < 10) {
return arg;
""");
StopNode stop = parser.parse().iterate();
- assertEquals("return Phi(Loop10,arg,(Phi_arg+1));", stop.toString());
+ assertEquals("return Phi(Loop9,arg,(Phi_arg+1));", stop.toString());
assertTrue(stop.ret().ctrl() instanceof CProjNode);
}
@@ -185,7 +185,7 @@ while(arg < 10) {
return a;
""");
StopNode stop = parser.parse().iterate();
- assertEquals("return Phi(Region35,Phi(Loop11,1,(Phi_a+1)),Add);", stop.toString());
+ assertEquals("return Phi(Region30,Phi(Loop10,1,(Phi_a+1)),Add);", stop.toString());
assertTrue(stop.ret().ctrl() instanceof RegionNode);
}
@@ -201,7 +201,7 @@ while(1) {
return a;
""");
StopNode stop = parser.parse().iterate();
- assertEquals("return (Phi(Loop11,1,Add)+1);", stop.toString());
+ assertEquals("return (Phi(Loop10,1,Add)+1);", stop.toString());
assertTrue(stop.ret().ctrl() instanceof CProjNode prj && prj._idx==1 );
}
diff --git a/chapter16/src/test/java/com/seaofnodes/simple/Chapter09Test.java b/chapter16/src/test/java/com/seaofnodes/simple/Chapter09Test.java
index b1d9d6e5..49ee75a2 100644
--- a/chapter16/src/test/java/com/seaofnodes/simple/Chapter09Test.java
+++ b/chapter16/src/test/java/com/seaofnodes/simple/Chapter09Test.java
@@ -69,7 +69,7 @@ while (arg < 10) {
return arg;
""");
StopNode stop = parser.parse().iterate();
- assertEquals("return Phi(Loop11,arg,(Phi_arg+2));", stop.toString());
+ assertEquals("return Phi(Loop10,arg,(Phi_arg+2));", stop.toString());
Assert.assertEquals(11L, Evaluator.evaluate(stop, 1));
}
@@ -86,7 +86,7 @@ while (arg < 10) {
return arg;
""");
StopNode stop = parser.parse().iterate();
- assertEquals("return Phi(Loop12,arg,(Phi_arg+4));", stop.toString());
+ assertEquals("return Phi(Loop11,arg,(Phi_arg+4));", stop.toString());
Assert.assertEquals(13L, Evaluator.evaluate(stop, 1));
}
@@ -115,7 +115,7 @@ while (arg) {
return arg;
""");
StopNode stop = parser.parse().iterate();
- assertEquals("return Phi(Loop18,arg,(Phi_arg+1));", stop.toString());
+ assertEquals("return Phi(Loop17,arg,(Phi_arg+1));", stop.toString());
}
@Test
@@ -185,7 +185,7 @@ while(arg) {
return a;
""");
StopNode stop = parser.parse().iterate();
- assertEquals("return Phi(Loop13,0,(-(Phi_a+3)));", stop.toString());
+ assertEquals("return Phi(Loop12,0,(-(Phi_a+3)));", stop.toString());
}
@Test
@@ -283,7 +283,7 @@ return v1+v0;
public void testFuzz8() {
Parser parser = new Parser("while(arg) arg = arg - 1; return arg;");
StopNode stop = parser.parse().iterate();
- assertEquals("return Phi(Loop10,arg,(Phi_arg-1));", stop.toString());
+ assertEquals("return Phi(Loop9,arg,(Phi_arg-1));", stop.toString());
}
@Test
diff --git a/chapter16/src/test/java/com/seaofnodes/simple/Chapter10Test.java b/chapter16/src/test/java/com/seaofnodes/simple/Chapter10Test.java
index 408a4814..75119a75 100644
--- a/chapter16/src/test/java/com/seaofnodes/simple/Chapter10Test.java
+++ b/chapter16/src/test/java/com/seaofnodes/simple/Chapter10Test.java
@@ -1,7 +1,8 @@
package com.seaofnodes.simple;
import com.seaofnodes.simple.evaluator.Evaluator;
-import com.seaofnodes.simple.node.StopNode;
+import com.seaofnodes.simple.node.*;
+import java.util.BitSet;
import org.junit.Test;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.fail;
@@ -160,7 +161,7 @@ while (arg) {
return bar.a;
""");
StopNode stop = parser.parse().iterate();
- assertEquals("return Phi(Loop16,0,(Phi_a+2));", stop.toString());
+ assertEquals("return Phi(Loop17,0,(Phi_a+2));", stop.toString());
}
@Test
@@ -282,7 +283,7 @@ while( i.x < i.len ) {
return sum;
""");
StopNode stop = parser.parse().iterate();
- assertEquals("return Phi(Loop21,0,(Phi(Loop,0,(Phi_x+1))+Phi_sum));", stop.toString());
+ assertEquals("return Phi(Loop22,0,(Phi(Loop,0,(Phi_x+1))+Phi_sum));", stop.toString());
}
@@ -301,7 +302,7 @@ while(arg) {
return ret;
""");
StopNode stop = parser.parse().iterate();
- assertEquals("return Phi(Loop16,s0,Phi(Region43,s0,Phi_ret));", stop.toString());
+ assertEquals("return Phi(Loop17,s0,Phi(Region44,s0,Phi_ret));", stop.toString());
}
@Test
@@ -319,7 +320,7 @@ while(arg) {
return ret;
""");
StopNode stop = parser.parse().iterate();
- assertEquals("return Phi(Loop20,s0,Phi(Region44,s0,Phi_ret));", stop.toString());
+ assertEquals("return Phi(Loop23,s0,Phi(Region45,s0,Phi_ret));", stop.toString());
}
@@ -336,7 +337,7 @@ while(arg < 10) {
return ret;
""");
StopNode stop = parser.parse().iterate();
- assertEquals("return Phi(Loop16,s0,Phi(Region41,s0,Phi_ret));", stop.toString());
+ assertEquals("return Phi(Loop17,s0,Phi(Region41,s0,Phi_ret));", stop.toString());
}
@Test
@@ -452,4 +453,120 @@ return 0;
assertEquals("return 0;", stop.toString());
}
+ @Test public void testReadBeforeStores() {
+ var stop = new Parser("""
+ struct S { int x; int y; };
+ S a = new S; S b = new S;
+ a.x = 11; b.x = 22;
+ S p = a; if (arg) p = b;
+ int before = p.x;
+ a.y = 55; b.y = 66;
+ a.x = 33; b.x = 44;
+ return before*100 + p.x;
+ """).parse().iterate();
+ assertEquals(1133L, com.seaofnodes.simple.evaluator.Evaluator.evaluate(stop,0));
+ assertEquals(2244L, com.seaofnodes.simple.evaluator.Evaluator.evaluate(stop,1));
+ }
+
+ static final String NESTED_MEMORY = """
+ struct S { int x; int y; int z; };
+ S s = new S;
+ s.x = 5; s.y = 7; s.z = 11;
+ while (arg > 0) {
+ s.x = s.x + 1;
+ int j = 3;
+ while (j > 0) {
+ j = j - 1;
+ if (j == 1) continue;
+ s.y = s.y + arg;
+ if (arg == 2) break;
+ s.z = s.z + 1;
+ }
+ arg = arg - 1;
+ }
+ return s;
+ """;
+
+ @Test public void testMemoryAcrossNestedLoops() {
+ var stop = new Parser(NESTED_MEMORY).parse().iterate();
+ for (int arg=0; arg<7; arg++) {
+ var obj = (com.seaofnodes.simple.evaluator.Evaluator.Obj)
+ com.seaofnodes.simple.evaluator.Evaluator.evaluate(stop,arg);
+ org.junit.Assert.assertArrayEquals(new Object[] {
+ 5L+arg, 7L+arg*(arg+1)-(arg>=2 ? 2 : 0), 11L+2*arg-(arg>=2 ? 2 : 0)
+ }, obj.fields());
+ }
+ }
+
+ @Test public void testMemoryAtEarlyReturns() {
+ var stop = new Parser("""
+ struct S { int x; int y; int z; };
+ S s = new S;
+ s.x = 3; s.y = 5; s.z = 7;
+ if (arg) { s.x = 11; s.z = 13; return s; }
+ s.y = 17;
+ return s;
+ """).parse().iterate();
+ for (int arg=0; arg<2; arg++) {
+ var obj = (com.seaofnodes.simple.evaluator.Evaluator.Obj)
+ com.seaofnodes.simple.evaluator.Evaluator.evaluate(stop,arg);
+ org.junit.Assert.assertArrayEquals(arg==0 ? new Object[]{3L,17L,7L} : new Object[]{11L,5L,13L}, obj.fields());
+ }
+ }
+
+ @Test public void testKeepLoadsAtMerge() {
+ StopNode stop = new Parser("""
+ struct S { int x; };
+ S a = new S; S b = new S;
+ a.x = arg; b.x = arg+1;
+ S p = a; S q = b;
+ if (arg<0) { p=b; q=a; }
+ int v;
+ if (arg>1) v=p.x; else v=q.x;
+ return v;
+ """).parse().iterate();
+ // The one-step safety check stops at the memory aggregate.
+ assertEquals(2,countMemoryNodes(stop,LoadNode.class,new BitSet()));
+ assertEquals(-1L,Evaluator.evaluate(stop,-1));
+ assertEquals(1L,Evaluator.evaluate(stop,0));
+ assertEquals(3L,Evaluator.evaluate(stop,3));
+ }
+
+ @Test public void testDropStores() {
+ StopNode stop = new Parser("""
+ struct S { int x; };
+ S s = new S;
+ if (arg) s.x=arg+1; else s.x=arg+2;
+ return s;
+ """).parse().iterate();
+ assertEquals(1,countMemoryNodes(stop,StoreNode.class,new BitSet()));
+ assertEquals(2L,((Evaluator.Obj)Evaluator.evaluate(stop,0)).fields()[0]);
+ assertEquals(4L,((Evaluator.Obj)Evaluator.evaluate(stop,3)).fields()[0]);
+ }
+
+ @Test public void testKeepReadsBeforeWrites() {
+ StopNode stop = new Parser("""
+ struct S { int x; int y; };
+ S a = new S; S b = new S;
+ a.x=arg; b.x=arg+1;
+ S p=a; S q=b;
+ if (arg<0) { p=b; q=a; }
+ int v;
+ if (arg>1) { v=p.x; p.x=41; p.y=5; }
+ else { v=q.x; q.x=42; }
+ return v;
+ """).parse().iterate();
+ assertEquals(2,countMemoryNodes(stop,LoadNode.class,new BitSet()));
+ assertEquals(-1L,Evaluator.evaluate(stop,-1));
+ assertEquals(1L,Evaluator.evaluate(stop,0));
+ assertEquals(3L,Evaluator.evaluate(stop,3));
+ }
+
+ private static int countMemoryNodes(Node n, Class<?> kind, BitSet seen) {
+ if (n==null || seen.get(n._nid)) return 0;
+ seen.set(n._nid);
+ int cnt=kind.isInstance(n) ? 1 : 0;
+ for (Node def : n._inputs) cnt+=countMemoryNodes(def,kind,seen);
+ return cnt;
+ }
}
diff --git a/chapter16/src/test/java/com/seaofnodes/simple/Chapter10bTest.java b/chapter16/src/test/java/com/seaofnodes/simple/Chapter10bTest.java
new file mode 100644
index 00000000..4281f0a1
--- /dev/null
+++ b/chapter16/src/test/java/com/seaofnodes/simple/Chapter10bTest.java
@@ -0,0 +1,64 @@
+package com.seaofnodes.simple;
+
+import com.seaofnodes.simple.node.*;
+import com.seaofnodes.simple.evaluator.Evaluator;
+import org.junit.Test;
+import static org.junit.Assert.*;
+
+public class Chapter10bTest {
+ @Test public void testIndependentField() {
+ var stop = new Parser("""
+ struct S { int x; int y; };
+ S s = new S;
+ s.x = 42;
+ while (arg > 0) { s.y = s.y + arg; arg = arg - 1; }
+ return s.x;
+ """).parse().iterate();
+ assertEquals("return 42;",stop.toString());
+ assertEquals(42L,Evaluator.evaluate(stop,5));
+ assertNull(stop.walk(n -> n instanceof LoadNode ? n : null));
+ }
+
+ @Test public void testParallelMemoryPhis() {
+ var stop = new Parser("""
+ struct S { int x; int y; int z; };
+ S a = new S; S b = new S;
+ S p = a; if (arg) p = b;
+ while (arg > 0) {
+ a.x = p.x + arg;
+ a.y = p.y + 2;
+ a.z = p.z + 3;
+ arg = arg - 1;
+ }
+ return a;
+ """).parse().iterate();
+ int[] phis = {0};
+ stop.walk(n -> {
+ if (n instanceof MemPhiNode) phis[0]++;
+ if (n instanceof MemMergeNode m && m.in(1) instanceof BulkMemPhiNode b)
+ for(int a=b._aliases.nextSetBit(0); a>=0; a=b._aliases.nextSetBit(a+1))
+ assertTrue(a<m.nIns() && m.in(a)!=null);
+ assertFalse(n instanceof PhiNode && n.isMem() &&
+ !(n instanceof MemPhiNode) && !(n instanceof BulkMemPhiNode));
+ return null;
+ });
+ assertTrue(phis[0]>=3);
+ assertArrayEquals(new Object[]{1L,2L,3L},((Evaluator.Obj)Evaluator.evaluate(stop,4)).fields());
+ }
+
+ @Test public void testLateSliceWorklist() throws ReflectiveOperationException {
+ // Seed 97 exposed a store selecting a bulk predecessor without queuing
+ // it. Keep both the worklist assertion and the final heap check.
+ for (int seed : new int[]{0,97,123,456}) {
+ var parser = new Parser(Chapter10Test.NESTED_MEMORY);
+ var field = IterPeeps.class.getDeclaredField("WORK");
+ field.setAccessible(true);
+ Object work = field.get(null);
+ field = work.getClass().getDeclaredField("_R");
+ field.setAccessible(true);
+ ((java.util.Random)field.get(work)).setSeed(seed);
+ var stop = parser.parse().iterate();
+ assertArrayEquals(new Object[]{9L,25L,17L},((Evaluator.Obj)Evaluator.evaluate(stop,4)).fields());
+ }
+ }
+}
diff --git a/chapter16/src/test/java/com/seaofnodes/simple/Chapter11Test.java b/chapter16/src/test/java/com/seaofnodes/simple/Chapter11Test.java
index 30bcab1e..1183da5f 100644
--- a/chapter16/src/test/java/com/seaofnodes/simple/Chapter11Test.java
+++ b/chapter16/src/test/java/com/seaofnodes/simple/Chapter11Test.java
@@ -325,7 +325,7 @@ while( prime <= arg ) {
return primeCount;
""");
StopNode stop = parser.parse().iterate();
- assertEquals("Stop[ return 0; return Phi(Loop23,1,Phi(Region100,Phi_primeCount,Phi(Region93,(Phi_primeCount+1),Phi_primeCount))); ]", stop.toString());
+ assertEquals("Stop[ return 0; return Phi(Loop21,1,Phi(Region88,Phi_primeCount,Phi(Region82,(Phi_primeCount+1),Phi_primeCount))); ]", stop.toString());
assertEquals(0L, Evaluator.evaluate(stop, 1)); // No primes 1 or below
assertEquals(1L, Evaluator.evaluate(stop, 2)); // 2
assertEquals(2L, Evaluator.evaluate(stop, 3)); // 2, 3
@@ -370,7 +370,7 @@ if (arg) {
return i;
""");
StopNode stop = parser.parse().iterate();
- assertEquals("return Phi(Region45,.f,0);", stop.toString());
+ assertEquals("return Phi(Region48,.f,0);", stop.toString());
}
@Test
@@ -477,7 +477,7 @@ while(arg) {
return arg;
""");
StopNode stop = parser.parse().iterate();
- assertEquals("return Phi(Loop20,arg,Phi(Region48,.f,0));", stop.toString());
+ assertEquals("return Phi(Loop23,arg,Phi(Region50,.f,0));", stop.toString());
}
@Test
diff --git a/chapter16/src/test/java/com/seaofnodes/simple/Chapter12Test.java b/chapter16/src/test/java/com/seaofnodes/simple/Chapter12Test.java
index c93f905d..998053ec 100644
--- a/chapter16/src/test/java/com/seaofnodes/simple/Chapter12Test.java
+++ b/chapter16/src/test/java/com/seaofnodes/simple/Chapter12Test.java
@@ -64,7 +64,7 @@ while( 1 ) {
return guess;
""");
StopNode stop = parser.parse().iterate();
- assertEquals("return Phi(Loop11,(flt)arg,(((ToFloat/Phi_guess)+Phi_guess)/2.0));", stop.toString());
+ assertEquals("return Phi(Loop10,(flt)arg,(((ToFloat/Phi_guess)+Phi_guess)/2.0));", stop.toString());
assertEquals(3.0, Evaluator.evaluate(stop, 9));
assertEquals(1.414213562373095, Evaluator.evaluate(stop, 2));
}
diff --git a/chapter16/src/test/java/com/seaofnodes/simple/Chapter14Test.java b/chapter16/src/test/java/com/seaofnodes/simple/Chapter14Test.java
index 7d7bb25a..03a02795 100644
--- a/chapter16/src/test/java/com/seaofnodes/simple/Chapter14Test.java
+++ b/chapter16/src/test/java/com/seaofnodes/simple/Chapter14Test.java
@@ -59,7 +59,7 @@ while( b ) b = b + 456;// Truncate
return b;
""");
StopNode stop = parser.parse().iterate();
- assertEquals("return Phi(Loop11,123,((Phi_b+456)&255));", stop.toString());
+ assertEquals("return Phi(Loop10,123,((Phi_b+456)&255));", stop.toString());
}
@Test
@@ -175,7 +175,7 @@ while(v1) break;
return v1;
""");
StopNode stop = parser.parse().iterate();
- assertEquals("return (Phi(Loop18,((1<<arg)&1),0)&Phi(Loop,Shl,4294967295));", stop.toString());
+ assertEquals("return (Phi(Loop17,((1<<arg)&1),0)&Phi(Loop,Shl,4294967295));", stop.toString());
assertEquals(1L, Evaluator.evaluate(stop, 0));
}
diff --git a/chapter16/src/test/java/com/seaofnodes/simple/Chapter15Test.java b/chapter16/src/test/java/com/seaofnodes/simple/Chapter15Test.java
index 8161862f..643b45e7 100644
--- a/chapter16/src/test/java/com/seaofnodes/simple/Chapter15Test.java
+++ b/chapter16/src/test/java/com/seaofnodes/simple/Chapter15Test.java
@@ -130,7 +130,8 @@ else {
return rez;
""");
StopNode stop = parser.parse().iterate();
- assertEquals("return Phi(Region117,1.2,Phi(Region114,2.3,3.14));", stop.toString());
+ // Shared allocation memory prevents folding the field Store into New.
+ assertEquals("return Phi(Region121,1.2,Phi(Region118,2.3,.y));", stop.toString());
assertEquals(3.14, Evaluator.evaluate(stop, 0));
assertEquals(1.2 , Evaluator.evaluate(stop, 1));
}
diff --git a/chapter16/src/test/java/com/seaofnodes/simple/Chapter16Test.java b/chapter16/src/test/java/com/seaofnodes/simple/Chapter16Test.java
index 6fb41233..76fdb31e 100644
--- a/chapter16/src/test/java/com/seaofnodes/simple/Chapter16Test.java
+++ b/chapter16/src/test/java/com/seaofnodes/simple/Chapter16Test.java
@@ -73,7 +73,7 @@ if( arg ) { int x = y; x = x*x; y=x; } // Shadow final x
return y;
""");
StopNode stop = parser.parse().iterate();
- assertEquals("return Phi(Region21,9,3);", stop.toString());
+ assertEquals("return Phi(Region19,9,3);", stop.toString());
assertEquals(3L, Evaluator.evaluate(stop, 0));
assertEquals(9L, Evaluator.evaluate(stop, 1));
}
@@ -205,4 +205,27 @@ return new Square;
assertEquals("Obj<Square>{side=3.0,diag=1.7320508075688772}", Evaluator.evaluate(stop, 3).toString());
assertEquals("Obj<Square>{side=4.0,diag=2.0}", Evaluator.evaluate(stop, 4).toString());
}
+ static final String CONSTRUCTOR_MEMORY = """
+ struct S { int x; int y; };
+ struct T { int z=arg+40; };
+ T t = new T;
+ S a = new S { x=11; y=7; };
+ S b = new S { x=22; y=9; };
+ S p=a;
+ if (arg) p=b;
+ int before=p.x;
+ S c = new S {
+ x=p.x+1;
+ { int i=0; while (i<2) { p.y=p.y+1; i=i+1; } }
+ y=p.y;
+ };
+ p.x=33;
+ return before*10000+c.x*100+c.y+t.z;
+ """;
+
+ @Test public void testConstructorMemory() {
+ StopNode stop = new Parser(CONSTRUCTOR_MEMORY).parse().iterate();
+ assertEquals(111249L,Evaluator.evaluate(stop,0));
+ assertEquals(222352L,Evaluator.evaluate(stop,1));
+ }
}
diff --git a/chapter16/src/test/java/com/seaofnodes/simple/evaluator/Evaluator.java b/chapter16/src/test/java/com/seaofnodes/simple/evaluator/Evaluator.java
index c215de00..3eb406eb 100644
--- a/chapter16/src/test/java/com/seaofnodes/simple/evaluator/Evaluator.java
+++ b/chapter16/src/test/java/com/seaofnodes/simple/evaluator/Evaluator.java
@@ -187,7 +187,7 @@ public class Evaluator {
Object[] body=null;
int num;
if( type.isAry() ) {
- long sz = (Long)val(alloc.in(1));
+ long sz = (Long)val(alloc.size());
long n = offToIdx(sz, type);
if( n < 0 )
throw new NegativeArraySizeException(""+n);
@@ -201,17 +201,13 @@ public class Evaluator {
assert elem instanceof TypeMemPtr;
}
// Length value
- body[0] = vall(alloc.in(2+2));
+ body[0] = vall(alloc.in(3));
} else {
body = new Object[num = type._fields.length];
for (int i=0; i<num; i++)
- body[i] = val(alloc.in(2+i+num));
+ body[i] = val(alloc.in(3+i));
}
- Object[] mems = new Object[type._fields.length+2];
- // mems[0] is control
- mems[1] = new Obj(type,body); // the ref
- // mems[2+...] are memory aliases
- return mems;
+ return new Object[]{new Obj(type,body),MEMORY};
}
private Object load(LoadNode load) {
@@ -304,10 +300,10 @@ public class Evaluator {
case ToFloatNode cast -> (double)vall(cast.in(1));
case LoadNode load -> load(load);
case StoreNode store -> store(store);
+ case MemMergeNode merge -> MEMORY;
case NewNode alloc -> alloc(alloc);
case CProjNode cproj -> ((Object[])val(cproj.ctrl()))[cproj._idx];
case ProjNode proj -> ((Object[])val( proj.in(0) ))[ proj._idx];
- case ScopeMinNode mem -> null;
default -> throw new AssertionError("Unexpected node " + node);
};
}
@@ -330,7 +326,7 @@ public class Evaluator {
case null:
return Status.FALLTHROUGH;
case ReturnNode ret:
- return val(ret.in(1));
+ return val(ret.expr());
case IfNode ifn:
block = block.next()[isTrue(val(ifn.in(1))) ? 0 : 1];
if (block == null) return Status.FALLTHROUGH;
diff --git a/chapter16/src/test/java/com/seaofnodes/simple/evaluator/Scheduler.java b/chapter16/src/test/java/com/seaofnodes/simple/evaluator/Scheduler.java
index 06169e2c..afcc700f 100644
--- a/chapter16/src/test/java/com/seaofnodes/simple/evaluator/Scheduler.java
+++ b/chapter16/src/test/java/com/seaofnodes/simple/evaluator/Scheduler.java
@@ -31,6 +31,8 @@ import java.util.*;
*/
public class Scheduler {
+ private final HashMap<Node,ArrayList<NodeData>> readers = new HashMap<>();
+
/**
* A basic block with a schedule of the containing nodes.
*
@@ -252,7 +254,7 @@ public class Scheduler {
// but they did not refine the placement
// so do that now.
var mem = l.in(1);
- for(var out : mem._outputs) {
+ for(var out : l.antiDeps()) {
if (out instanceof PhiNode p) {
var r = p.in(0);
for (int i = 1; i < p.nIns(); i++) {
@@ -270,13 +272,9 @@ public class Scheduler {
for(var in:data.node._inputs) {
if (in!=null) update(d(in), data.block);
}
- if (data.node instanceof StoreNode s) {
- // Store nodes have anti-deps to load nodes.
- // So decrease the uses of these loads when the store is placed.
- for (var out: s.in(1)._outputs) {
- if (out instanceof LoadNode) od(out).ifPresent(this::decUsers);
- }
- }
+ var loads = readers.get(data.node);
+ if (loads != null)
+ for (var load : loads) decUsers(load);
}
// Now all nodes should be placed and have a block assigned
@@ -442,7 +440,6 @@ public class Scheduler {
private void doMarkAlive(Node node) {
var cfgQueue = new Stack<NodeData>();
var dataQueue = new Stack<NodeData>();
- var mem = new Stack<NodeData>();
markAlive(cfgQueue, node, true);
// Mark all CFG nodes.
while (!cfgQueue.isEmpty()) {
@@ -467,16 +464,16 @@ public class Scheduler {
} else {
for (var in : node._inputs) if (in != null && !(in instanceof CFGNode)) markAlive(dataQueue, in, false);
}
- if (node instanceof StoreNode) mem.push(data);
- }
- // Handle store nodes and increase load with an anti-dep to the store.
- while (!mem.isEmpty()) {
- var data = mem.pop();
- node = data.node;
- for(var out:node.in(1)._outputs) {
- if (out instanceof LoadNode) od(out).ifPresent(d->d.users++);
- }
}
+ // Writes, including New behind an aggregate, schedule before their
+ // anti-dependent reads in this reverse scheduling pass.
+ for (var load : data.values())
+ if (load.node instanceof LoadNode l)
+ for (var use : l.antiDeps())
+ if ((use instanceof StoreNode || use instanceof NewNode) && data.containsKey(use)) {
+ load.users++;
+ readers.computeIfAbsent(use,k->new ArrayList<>()).add(load);
+ }
}
/**