summaryrefslogtreecommitdiff
path: root/chapter25/src/test/java
diff options
context:
space:
mode:
Diffstat (limited to 'chapter25/src/test/java')
-rw-r--r--chapter25/src/test/java/com/seaofnodes/simple/Chapter11Test.java2
-rw-r--r--chapter25/src/test/java/com/seaofnodes/simple/Chapter20Test.java2
-rw-r--r--chapter25/src/test/java/com/seaofnodes/simple/Chapter21Test.java4
-rw-r--r--chapter25/src/test/java/com/seaofnodes/simple/EvalArm64.java7
-rw-r--r--chapter25/src/test/java/com/seaofnodes/simple/MemoryEncodingTest.java104
5 files changed, 114 insertions, 5 deletions
diff --git a/chapter25/src/test/java/com/seaofnodes/simple/Chapter11Test.java b/chapter25/src/test/java/com/seaofnodes/simple/Chapter11Test.java
index 2e661901..d515df8d 100644
--- a/chapter25/src/test/java/com/seaofnodes/simple/Chapter11Test.java
+++ b/chapter25/src/test/java/com/seaofnodes/simple/Chapter11Test.java
@@ -152,6 +152,8 @@ return v.f;
""");
code.parse().opto();
assertEquals("return Phi(Loop,0,2);", code.print());
+ for( int arg : new int[]{-1,0,1,3,100} )
+ assertEquals("0",Eval2.eval(code,arg));
}
@Test
diff --git a/chapter25/src/test/java/com/seaofnodes/simple/Chapter20Test.java b/chapter25/src/test/java/com/seaofnodes/simple/Chapter20Test.java
index ce604cf1..e39c09e7 100644
--- a/chapter25/src/test/java/com/seaofnodes/simple/Chapter20Test.java
+++ b/chapter25/src/test/java/com/seaofnodes/simple/Chapter20Test.java
@@ -183,7 +183,7 @@ for( int i=0; i<ary#-1; i++ )
return ary[1] * 1000 + ary[3]; // 1 * 1000 + 6
""";
testCPU(src,"x86_64_v2", "SystemV",-1,"return mov(.[]);");
- testCPU(src,"riscv" , "SystemV", 7,"return (add,.[],(mul,.[],1000));");
+ testCPU(src,"riscv" , "SystemV", 9,"return (add,.[],(mul,.[],1000));");
testCPU(src,"arm" , "SystemV", 5,"return (add,.[],(mul,.[],1000));");
}
diff --git a/chapter25/src/test/java/com/seaofnodes/simple/Chapter21Test.java b/chapter25/src/test/java/com/seaofnodes/simple/Chapter21Test.java
index b88e8af9..08da0654 100644
--- a/chapter25/src/test/java/com/seaofnodes/simple/Chapter21Test.java
+++ b/chapter25/src/test/java/com/seaofnodes/simple/Chapter21Test.java
@@ -279,7 +279,7 @@ for( int i=0; i<ary#-1; i++ )
return ary[1] * 1000 + ary[3]; // 1 * 1000 + 6
""";
testCPU(src,"x86_64_v2", "SystemV",-1,"return mov(.[]);");
- testCPU(src,"riscv" , "SystemV", 7,"return (add,.[],(mul,.[],1000));");
+ testCPU(src,"riscv" , "SystemV", 9,"return (add,.[],(mul,.[],1000));");
testCPU(src,"arm" , "SystemV", 5,"return (add,.[],(mul,.[],1000));");
}
@@ -500,7 +500,7 @@ val sieve = { int N ->
// Evaluate on ARM5 emulator; expect return of an array of primes in
// the simulated heap.
- EvalArm64 A5 = TestArm64.build("sieve", src, 100, 105, false);
+ EvalArm64 A5 = TestArm64.build("sieve", src, 100, 88, false);
int trap_arm = A5.step(10000);
assertEquals(0, trap_arm);
int ary_arm = (int)A5.regs[arm.X0];
diff --git a/chapter25/src/test/java/com/seaofnodes/simple/EvalArm64.java b/chapter25/src/test/java/com/seaofnodes/simple/EvalArm64.java
index 86fcf96f..1503adb5 100644
--- a/chapter25/src/test/java/com/seaofnodes/simple/EvalArm64.java
+++ b/chapter25/src/test/java/com/seaofnodes/simple/EvalArm64.java
@@ -544,10 +544,13 @@ public class EvalArm64 {
break;
}
- case 0xD2: {
+ case 0xD2: // MOVZ
+ case 0xF2: { // MOVK preserves the other halfwords
// movz
// get immediate
- rval = (ir >> 5) & 0x7FFF;
+ int shift = ((ir >> 21) & 3)*16;
+ rval = ((ir >> 5) & 0xFFFFL) << shift;
+ if( opcode1==0xF2 ) rval |= regs[rdid] & ~(0xFFFFL << shift);
break;
}
diff --git a/chapter25/src/test/java/com/seaofnodes/simple/MemoryEncodingTest.java b/chapter25/src/test/java/com/seaofnodes/simple/MemoryEncodingTest.java
new file mode 100644
index 00000000..2786b403
--- /dev/null
+++ b/chapter25/src/test/java/com/seaofnodes/simple/MemoryEncodingTest.java
@@ -0,0 +1,104 @@
+package com.seaofnodes.simple;
+
+import com.seaofnodes.simple.codegen.CodeGen;
+import com.seaofnodes.simple.node.*;
+import java.util.BitSet;
+import org.junit.Test;
+import static org.junit.Assert.*;
+
+// Execution regressions are separate from the fixed spill-measurement cohorts.
+public class MemoryEncodingTest {
+ @Test public void testLoopLoadSearch() {
+ String[] sources = {
+ """
+ u8[] !program=new u8[106]; u8[] !out=new u8[0];
+ int sum=0;
+ for(int i=0; i<arg; i++) {
+ sum+=program#;
+ if(i==1) out=new u8[i+1];
+ else if(i==3) out=new u8[2];
+ }
+ return sum+out#;
+ """,
+ // One possibly aliasing arm must reject the unchanged-memory proof.
+ """
+ struct S { int x; }; S !a=new S; S !b=new S;
+ a.x=10; b.x=20; S !p=a; if(arg&1) p=b;
+ int sum=0;
+ for(int i=0; i<6; i++) {
+ if(i==2) p.x=30;
+ else if(i==4) b.x=40;
+ sum+=a.x;
+ }
+ return sum;
+ """,
+ // Unchanged memory does not imply an unchanged loop-carried pointer.
+ """
+ struct S { int x; }; S !a=new S; S !b=new S;
+ a.x=10; b.x=20; S !p=a; int sum=0;
+ for(int i=0; i<6; i++) {
+ if(i==2) a.x=30;
+ sum+=p.x;
+ p=b; if(i&1) p=a;
+ }
+ return sum;
+ """,
+ // All arms fold, but their values differ: build a value Phi.
+ """
+ struct S { int x; }; S !a=new S; a.x=1; int sum=0;
+ for(int i=0; i<6; i++) {
+ sum+=a.x;
+ if(i&1) a.x=2;
+ else if(i==2) a.x=3;
+ else a.x=4;
+ }
+ return sum;
+ """
+ };
+ // Exercise both unresolved Store aliases and nested value-Phi cleanup.
+ for( long seed : new long[]{0,9,126} )
+ for( int p=0; p<sources.length; p++ ) {
+ CodeGen code=new CodeGen(sources[p],seed,true).parse().opto();
+ if( p==0 ) assertNull(code._stop.walk(n ->
+ n instanceof LoadNode ld && ld.ptr() instanceof ProjNode ptr &&
+ ptr.in(0) instanceof NewNode nn &&
+ nn.size()._type==com.seaofnodes.simple.type.TypeInteger.constant(110) ? ld : null));
+ for( int arg=0; arg<7; arg++ ) {
+ long expected=switch(p) {
+ case 0 -> 106*arg+(arg>=2 ? 2 : 0);
+ case 1 -> (arg&1)==0 ? 140 : 60;
+ case 2 -> 130;
+ default -> 16;
+ };
+ assertEquals(Long.toString(expected),Eval2.eval(code,arg));
+ }
+ }
+ }
+
+ @Test public void testKeepReadsBeforeWrites() {
+ var code = new CodeGen("""
+ 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().opto();
+ StopNode stop = code._stop;
+ assertEquals(2,countMemoryNodes(stop,LoadNode.class,new BitSet()));
+ assertEquals("-1",Eval2.eval(code,-1));
+ assertEquals("1",Eval2.eval(code,0));
+ assertEquals("3",Eval2.eval(code,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;
+ }
+}