summaryrefslogtreecommitdiff
path: root/chapter29/src/test/java/com/seaofnodes/simple/Chapter24Test.java
diff options
context:
space:
mode:
Diffstat (limited to 'chapter29/src/test/java/com/seaofnodes/simple/Chapter24Test.java')
-rw-r--r--chapter29/src/test/java/com/seaofnodes/simple/Chapter24Test.java293
1 files changed, 293 insertions, 0 deletions
diff --git a/chapter29/src/test/java/com/seaofnodes/simple/Chapter24Test.java b/chapter29/src/test/java/com/seaofnodes/simple/Chapter24Test.java
new file mode 100644
index 00000000..2bc2ce7f
--- /dev/null
+++ b/chapter29/src/test/java/com/seaofnodes/simple/Chapter24Test.java
@@ -0,0 +1,293 @@
+package com.seaofnodes.simple;
+
+import com.seaofnodes.isa.eval.EvalRisc5;
+
+import com.seaofnodes.isa.eval.EvalArm64;
+
+import com.seaofnodes.simple.codegen.RegAllocTestSupport.CheckedCodeGen;
+import com.seaofnodes.simple.node.*;
+import com.seaofnodes.simple.type.*;
+
+
+import com.seaofnodes.simple.codegen.CodeGen;
+import com.seaofnodes.simple.node.cpus.riscv.riscv;
+import java.io.IOException;
+import org.junit.Ignore;
+import org.junit.Test;
+import static org.junit.Assert.*;
+
+public class Chapter24Test {
+ @Test public void testRecursiveWidening() {
+ String[] srcs = {
+ // Parm(x) must widen even though the recursive result is constant.
+ "val f = { int x, int limit -> x >= limit ? 0 : f(x+1,limit); }; return f(0,arg);",
+ // The growing result has its own cycle, which never crosses Parm(x).
+ "val f = { int x -> x <= 0 ? 0 : f(x-1)+1; }; return f(3);"
+ };
+ for( int i=0; i<srcs.length; i++ )
+ for( long seed : new long[]{0,42,126} ) {
+ var code = new CodeGen(srcs[i],seed,true).driver(CodeGen.Phase.LocalSched);
+ assertEquals(i==0 ? "0" : "3",Eval2.eval(code,3));
+ }
+ }
+
+ @Test public void testColdLoopSelfConflict() { com.seaofnodes.simple.codegen.RegAllocTestSupport.coldLoopSelfConflict(); }
+
+ @Test public void testPrintingDeadFunction() throws Exception {
+ var code = new CodeGen("return 0;").parse();
+ var tfp = TypeFunPtr.TEST;
+ var fun = new FunNode(null,tfp,"deadPrinterTarget",null);
+ org.junit.Assert.assertTrue(fun.isDead());
+ code.link(fun);
+ var con = ConstantNode.raw(tfp);
+ var call = new CallNode(null,con,con,con);
+ con.toString();
+ call.name();
+ code.funcName(tfp.fidx());
+ org.junit.Assert.assertSame(fun,code._link(tfp));
+ // Optimizer lookup still performs its usual lazy cleanup.
+ org.junit.Assert.assertNull(code.link(tfp));
+ org.junit.Assert.assertNull(code._link(tfp));
+ }
+
+
+ @Ignore
+ @Test
+ public void testJig() throws IOException {
+ String src = "int v0=0; v0 = arg && 0== 0 !=0;";
+ testCPU(src,"x86_64_v2", "win64" ,-1,null);
+ testCPU(src,"riscv" , "SystemV",-1,null);
+ testCPU(src,"arm" , "SystemV",-1,null);
+ }
+
+ static CodeGen testCPU( String src, String cpu, String os, int spills, String stop ) {
+ CodeGen code = new CheckedCodeGen(src).driver(CodeGen.Phase.Encoding,cpu,os);
+ int delta = spills>>3;
+ if( delta==0 ) delta = 1;
+ if( spills != -1 && !CodeGen.iterSeedOverridden() )
+ assertEquals("Expect spills:",spills,code._regAlloc._spillScaled,delta);
+ if( stop != null )
+ assertEquals(stop, code.print());
+ return code;
+ }
+
+ // test it with function calls
+ @Test
+ public void testStack1() throws IOException {
+ String src ="""
+int something_specific = 11;
+return (10 < something_specific < 20)
+ ? 0 // Expected
+ : 1; // Error
+""";
+ TestC.runSF( src, "stacked_r_1", "", 0);
+
+ // Evaluate on RISC5 emulator
+ EvalRisc5 R5 = TestRisc5.build( src, "stacked_r_1", 0, 0, false);
+ int trap = R5.step(100);
+ assertEquals(0,trap);
+ assertEquals(0,R5.regs[riscv.A0]);
+
+ // Evaluate on ARM emulator
+ EvalArm64 arm = TestArm64.build("stacked_r_1", src, 0, 0, false);
+ trap = arm.step(100);
+ assertEquals(0,trap);
+ assertEquals(0,arm.regs[0]);
+ }
+
+ @Test
+ public void testStack3() throws IOException {
+ String src ="""
+var sq_noInline = { int x ->
+ x*x;
+};
+int score = 4;
+return (sq_noInline(2) <= score < sq_noInline(3))
+ ? 0 // Expected
+ : 1; // Error
+""";
+ TestC.runSF( src, "stacked_r_3", "", 2);
+
+ // Evaluate on RISC5 emulator
+ EvalRisc5 R5 = TestRisc5.build( src, "stacked_r_3", 0, 2, false);
+ int trap = R5.step(100);
+ assertEquals(0,trap);
+ assertEquals(0,R5.regs[riscv.A0]);
+
+ // Evaluate on ARM emulator
+ EvalArm64 arm = TestArm64.build("stacked_r_3", src, 0, 3, false);
+ int trap_1 = arm.step(100);
+ assertEquals(0,trap_1);
+ assertEquals(0,arm.regs[0]);
+ }
+
+ @Test
+ public void testStack4() throws IOException {
+ String src ="""
+int something_specific = 9;
+return (10 < something_specific < 20)
+ ? 1 // Error
+ : 0; // Expected
+""";
+
+ TestC.runSF( src, "stacked_r_4", "", 0);
+
+ // Evaluate on RISC5 emulator
+ EvalRisc5 R5 = TestRisc5.build( src, "stacked_r_4", 0, 0, false);
+ int trap = R5.step(100);
+ assertEquals(0,trap);
+ assertEquals(0,R5.regs[riscv.A0]);
+
+ // Evaluate on ARM emulator
+ EvalArm64 arm = TestArm64.build("stacked_r_4", src, 0, 0, false);
+ trap = arm.step(100);
+ assertEquals(0,trap);
+ assertEquals(0,arm.regs[0]);
+ }
+
+ @Test
+ public void testStack6() {
+ try { new CodeGen("return 0 < arg > 1;" ).parse(); fail(); }
+ catch( RuntimeException e ) { assertEquals("Mixing relational directions in a chained relational test",e.getMessage()); }
+ }
+
+ @Test
+ public void testStack9() throws IOException {
+ String src = "var stack9 = { int x -> (x < 1) == 1; };";
+ String src2 = "return (0 < 1) == 1;";
+ TestC.runC(src, "stacked_r_9x", "1", 0);
+
+ // Evaluate on RISC5 emulator
+ EvalRisc5 R5 = TestRisc5.build( src2, "stacked_r_9", 0, 0, false);
+ int trap = R5.step(100);
+ assertEquals(0,trap);
+ assertEquals(1,R5.regs[riscv.A0]);
+
+ // Evaluate on ARM emulator
+ EvalArm64 arm = TestArm64.build("stacked_r_9", src2, 0, 0, false);
+ trap = arm.step(100);
+ assertEquals(0,trap);
+ assertEquals(1,arm.regs[0]);
+ }
+
+ @Test
+ public void testStack10() throws IOException {
+ String src ="var stack10 = { int x -> (x < 1) == (1>x);};";
+ String src2 ="return (0 < 1) == (1>0);";
+ TestC.runC(src, "stacked_r_10x", "1",0);
+
+ // Evaluate on RISC5 emulator
+ EvalRisc5 R5 = TestRisc5.build( src2, "stacked_r_10", 0, 0, false);
+ int trap = R5.step(100);
+ assertEquals(0,trap);
+ assertEquals(1,R5.regs[riscv.A0]);
+
+ // Evaluate on ARM emulator
+ EvalArm64 arm = TestArm64.build("stacked_r_10", src2,0, 0, false);
+ trap = arm.step(100);
+ assertEquals(0,trap);
+ assertEquals(1,arm.regs[0]);
+ }
+
+ @Test
+ public void testStack11() throws IOException {
+ String src = "var stack11 = { int x -> 0 < x < x+1 < 4;}; ";
+ String src2 = "return 0 < arg < arg+1 < 4;";
+ TestC.runC(src, "stacked_r_11x", "1", 2);
+
+ // Evaluate on RISC5 emulator
+ EvalRisc5 R5 = TestRisc5.build( src2, "stacked_r_11", 1, 0, false);
+ R5.regs[riscv.A1] = 1; // Arg in A1, Test.class in A0
+ int trap = R5.step(100);
+ assertEquals(0,trap);
+ assertEquals(1,R5.regs[riscv.A0]);
+
+ // Evaluate on ARM emulator
+ EvalArm64 arm = TestArm64.build("stacked_r_11", src2, 1, 0, false);
+ arm.regs[1] = 1; // Arg in r1, Test.class in r0
+ trap = arm.step(100);
+ assertEquals(0,trap);
+ assertEquals(1,arm.regs[0]);
+ }
+
+ // shows that it is parsed as
+ // ((0 != x) != 2)
+ @Test
+ public void testStack12() throws IOException {
+ String src = "var stack12 = { int x -> 0 != x != 2; };";
+ String src2 = "return 0 != arg != 2;";
+ TestC.runC(src, "stacked_r_12x", "1",0);
+
+ // Evaluate on RISC5 emulator
+ EvalRisc5 R5 = TestRisc5.build( src2, "stacked_r_12", 1, 0, false);
+ int trap = R5.step(100);
+ assertEquals(0,trap);
+ assertEquals(1,R5.regs[riscv.A0]);
+
+ // Evaluate on ARM emulator
+ EvalArm64 arm = TestArm64.build("stacked_r_12", src2, 1, 0, false);
+ trap = arm.step(100);
+ assertEquals(0,trap);
+ assertEquals(1,arm.regs[0]);
+ }
+
+
+ // shows that it is parsed as
+ // ((0 == x) == 1)
+ @Test
+ public void testStack13() throws IOException {
+ String src = "var stack13 = { int x -> 0 == x == 1; };";
+ String src2 = "return 0 == arg == 1;";
+ TestC.runC(src, "stacked_r_13x", "1",0);
+
+ // Compile once per target, then check false, true and negative inputs.
+ EvalRisc5 R5 = TestRisc5.build( src2, "stacked_r_13", 1, 0, false);
+ for( int arg : new int[]{-1,0,1} ) {
+ R5._pc = 0;
+ R5.regs[riscv.A1] = arg;
+ assertEquals(0,R5.step(100));
+ assertEquals(arg==0 ? 1 : 0,R5.regs[riscv.A0]);
+ }
+ EvalArm64 arm = TestArm64.build("stacked_r_13", src2, 1, 0, false);
+ for( int arg : new int[]{-1,0,1} ) {
+ arm._pc = 0;
+ arm.regs[1] = arg;
+ assertEquals(0,arm.step(100));
+ assertEquals(arg==0 ? 1 : 0,arm.regs[0]);
+ }
+ }
+
+ @Test
+ public void testSCCP0() {
+ String src =
+"""
+int x = 1;
+int cnt = 5;
+while (cnt) {
+ cnt -= 1;
+ if (x == 0) {
+ x += 1;
+ }
+}
+return x;
+""";
+ CodeGen code = new CodeGen(src).driver(CodeGen.Phase.TypeCheck);
+ assertEquals("return 1;", code.print());
+ }
+
+ @Test
+ public void testSCCP1() {
+ String src =
+"""
+int x = 1;
+int cnt = 5;
+while( cnt-- )
+ if( x == 1 )
+ x = 2-x;
+return x;
+""";
+ CodeGen code = new CodeGen(src).driver(CodeGen.Phase.TypeCheck);
+ assertEquals("return 1;", code.print());
+ }
+
+}