diff options
Diffstat (limited to 'src/test/java/com/seaofnodes/simple/Chapter21Test.java')
| -rw-r--r-- | src/test/java/com/seaofnodes/simple/Chapter21Test.java | 240 |
1 files changed, 114 insertions, 126 deletions
diff --git a/src/test/java/com/seaofnodes/simple/Chapter21Test.java b/src/test/java/com/seaofnodes/simple/Chapter21Test.java index 5b2c3a54..0cfdb577 100644 --- a/src/test/java/com/seaofnodes/simple/Chapter21Test.java +++ b/src/test/java/com/seaofnodes/simple/Chapter21Test.java @@ -10,14 +10,33 @@ import com.seaofnodes.simple.node.cpus.arm.arm; import com.seaofnodes.simple.node.cpus.riscv.riscv; import com.seaofnodes.simple.util.SB; import java.io.IOException; -import java.nio.file.Files; -import java.nio.file.Path; import org.junit.Ignore; import org.junit.Test; import static org.junit.Assert.*; public class Chapter21Test { + @Test public void testFloatToInteger() throws IOException { + String src = "val float_to_int={ flt x -> int i=x; return i; };"+ + "val float_to_u8={ flt x -> u8 i=x; return i; };"; + TestC.runC(src,"floatToInteger","",-1); + for( double x : new double[]{0.0,-0.0,6.92,-6.92,255.75,-257.75, + 0x1p63,Math.nextDown(0x1p63),-0x1p63,Math.nextDown(-0x1p63), + Double.POSITIVE_INFINITY,Double.NEGATIVE_INFINITY,Double.NaN} ) { + for( String name : new String[]{"float_to_int","float_to_u8"} ) { + long expected = name.equals("float_to_u8") ? ((long)x)&255 : (long)x; + EvalRisc5 r = TestRisc5.build(src,name,0,-1,false); + r.fregs[riscv.FA0-riscv.F_OFFSET]=x; + assertEquals(0,r.step(1000)); + assertEquals(name+"("+x+")",expected,r.regs[riscv.A0]); + EvalArm64 a = TestArm64.build(name,src,0,-1,false); + a.fregs[arm.D0-arm.D_OFFSET]=x; + assertEquals(0,a.step(1000)); + assertEquals(name+"("+x+")",expected,a.regs[arm.X0]); + } + } + } + @Test public void testReadBeforeConditionalStore() { var code = new CodeGen(""" struct S { int x; }; !S !a=new S; !S !b=new S; @@ -52,35 +71,10 @@ public class Chapter21Test { } - @Test public void testReturnedFunctionEncoding() throws IOException { - String src = "if(arg) return {->42;}; return {->43;};"; - CodeGen code = new CodeGen(src).driver("riscv","SystemV",null); - for( int arg : new int[]{0,1} ) { - byte[] image = new byte[1<<16]; - byte[] bits = code._encoding.bits(); - System.arraycopy(bits,0,image,0,bits.length); - EvalRisc5 cpu = new EvalRisc5(image,1<<15); - cpu._pc = code._encoding._opStart[code.link(code._main)._nid]; - cpu.regs[riscv.A0] = arg; - assertEquals(0,cpu.step(100)); - assertEquals(0,cpu._pc); - cpu._pc = (int)cpu.regs[riscv.A0]; - assertEquals(0,cpu.step(100)); - assertEquals(0,cpu._pc); - assertEquals(arg==0 ? 43 : 42,cpu.regs[riscv.A0]); - } - // Anonymous bodies need code, but no exported ELF name. - new CodeGen(src).driver(TestC.CPU_PORT,TestC.CALL_CONVENTION,"build/objs/anonymous.o"); - } - @Test public void testArmFloatMemory() throws IOException { for( String type : new String[]{"f32","f64"} ) { String src = type+"[] !a=new "+type+"[3]; a[arg]=1.25; return a[1];"; - CodeGen code = new CodeGen(src).driver("arm","SystemV",null); - byte[] image = new byte[1<<20]; - byte[] bits = code._encoding.bits(); - System.arraycopy(bits,0,image,0,bits.length); - EvalArm64 cpu = new EvalArm64(image,1<<16); + EvalArm64 cpu = TestArm64.build("probe","val probe={ int arg -> "+src+" };",1,-1,false); cpu.regs[arm.X0]=1; assertEquals(0,cpu.step(1000)); assertEquals(1.25,cpu.fregs[0],0); @@ -156,6 +150,7 @@ public class Chapter21Test { struct _Vec { u32 !len; int[] !buf; + new _Vec = { int[] initial -> buf=initial; }; val grow = { int sz -> var buf2 = new int[sz]; for( int i=0; i<len; i++ ) buf2[i]=buf[i]; @@ -168,7 +163,7 @@ public class Chapter21Test { }; }; val run = { int arg -> - val v = new _Vec{buf=new int[4];}.add(2).add(3).add(5).add(7).add(11); + val v = new _Vec(new int[4]).add(2).add(3).add(5).add(7).add(11); return v.len*100+v.buf[arg]; }; """; @@ -176,7 +171,7 @@ public class Chapter21Test { } private static int checkArmCalls(String src, String entryName, int arg, int result) throws IOException { - CodeGen code = new CodeGen(src).driver("arm","SystemV",null); + CodeGen code = new CodeGen(src).driver("arm","SystemV",true,false); byte[] image = new byte[1<<20]; System.arraycopy(code._encoding.bits(),0,image,0,code._encoding.bits().length); EvalArm64 cpu = new EvalArm64(image,1<<16); @@ -184,7 +179,7 @@ public class Chapter21Test { int frames=0, calls=0; for( var bb : code._cfg ) { if( bb instanceof com.seaofnodes.simple.node.FunNode fun ) { - int off = code._encoding._opStart[fun._nid]; + int off = code._encoding.opStart(fun); if( entryName.equals(fun._name) ) { cpu._pc=off; entry=true; } int frame=fun._frameAdjust; assertEquals(0,frame&15); @@ -194,7 +189,7 @@ public class Chapter21Test { } } if( bb instanceof com.seaofnodes.simple.node.ReturnNode ret ) { - int off=code._encoding._opStart[ret._nid]; + int off=code._encoding.opStart(ret); int frame=ret.fun()._frameAdjust; if( frame>0 ) { assertEquals(0x910003FF | (frame<<10),cpu.ld4s(off)); // ADD SP,SP,#bytes @@ -220,52 +215,6 @@ public class Chapter21Test { @Test public void testCoalescing() { com.seaofnodes.simple.codegen.RegAllocTestSupport.coalescing(); } @Test public void testCopyForward() throws Exception { com.seaofnodes.simple.codegen.RegAllocTestSupport.copyForward(); } - @Test public void testNarrowStores() throws IOException { - for( String type : new String[]{"i8","u8","i16","u16"} ) { - String src = "struct S { "+type+" x; }; !S !s = new S; s.x = arg; return 0;"; - CodeGen code = new CodeGen(src).driver("riscv","SystemV",null); - int stores=0; - for( var bb : code._cfg ) - for( var node : bb.outs() ) - if( node instanceof com.seaofnodes.simple.node.cpus.riscv.StoreRISC st ) { - stores++; - assertEquals("Byte/short stores have no FP encoding",-1,st.regmap(4).nextReg((short)31)); - } - assertEquals(1,stores); - byte[] image = new byte[1<<20]; - byte[] bits = code._encoding.bits(); - System.arraycopy(bits,0,image,0,bits.length); - EvalRisc5 cpu = new EvalRisc5(image,1<<16); - cpu.regs[riscv.A0] = 0x8765; - assertEquals(0,cpu.step(100)); - assertEquals(type.endsWith("8") ? 0x65 : 0x8765, - type.endsWith("8") ? cpu.ld1z(1<<16) : cpu.ld2z(1<<16)); - code = new CodeGen(src).driver(CodeGen.Phase.Encoding,"x86_64_v2",TestC.CALL_CONVENTION); - stores=0; - for( var bb : code._cfg ) - for( var node : bb.outs() ) - if( node instanceof com.seaofnodes.simple.node.cpus.x86_64_v2.StoreX86 st ) { - stores++; - assertEquals("Byte/short stores have no XMM encoding",-1,st.regmap(4).nextReg((short)15)); - } - assertEquals(1,stores); - } - } - - @Test public void testNativeExitStatus() throws IOException { - Path source = Path.of("build/objs/nativeExit.c"); - Files.createDirectories(source.getParent()); - Files.writeString(source,"int main() { return 7; }\n"); - try { - TestC.gcc(source.toString(),null,null,false, - "build/objs/nativeExit"+(TestC.OS.startsWith("Windows") ? ".exe" : "")); - } catch( AssertionError error ) { - assertTrue(error.getMessage(),error.getMessage().contains("Program exit status")); - return; - } - fail("A failing native program must fail the test, even with empty stdout"); - } - @Test public void testArmSubtractRegisters() { EvalArm64 cpu = new EvalArm64(new byte[16],16); cpu.st4(0,0xCB020020); // SUB X0,X1,X2, no shift or flag update. @@ -309,21 +258,41 @@ public class Chapter21Test { } - // Frozen Jig runs in Chapter23AllocTest; the revised input is in Chapter24AllocTest. - @Test @Ignore + @Ignore + @Test public void testJig() throws IOException { - String src = Files.readString(Path.of("src/test/java/com/seaofnodes/simple/progs/jig.smp")); - testCPU(src,"x86_64_v2", "Win64" ,-1,null); + String src = +""" +struct _s0 { + bool v1; + i16 v2; + int v3; + i8 v4; + byte v5; +}; +while(new _s0.v3) + while(new _s0.v5<<new _s0.v4) {} +if(0) { + if(0) { + flt !P5ZUD4=new _s0.v2; + } + while(0) {} +} +return new _s0.v1; +"""; + testCPU(src,"x86_64_v2", "win64" ,-1,null); testCPU(src,"riscv" , "SystemV",-1,null); testCPU(src,"arm" , "SystemV",-1,null); } static void testCPU( String src, String cpu, String os, int spills, String stop ) { CodeGen code = new CheckedCodeGen(src).driver(CodeGen.Phase.Encoding,cpu,os); - SpillStats.record(code,"Chapter21",cpu,os); - SpillStats.checkSpills(spills,code._regAlloc._spillScaled); + 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._stop.toString()); + assertEquals(stop, code.print()); } @@ -335,14 +304,14 @@ public class Chapter21Test { } @Test public void testInfinite() { - String src = "struct S { int i; }; !S !s = new S; while(1) s.i++;"; + String src = "struct _S { int i; }; !_S !s = new _S; while(1) s.i++; return s.i;"; testCPU(src,"x86_64_v2", "SystemV",0,"return Top;"); testCPU(src,"riscv" , "SystemV",0,"return Top;"); testCPU(src,"arm" , "SystemV",0,"return Top;"); } @Test - public void testArray1() throws IOException { + public void testArray1() { String src = """ int[] !ary = new int[arg]; @@ -354,19 +323,19 @@ for( int i=0; i<ary#-1; i++ ) ary[i+1] += ary[i]; return ary[1] * 1000 + ary[3]; // 1 * 1000 + 6 """; - testCPU(src,"x86_64_v2", "SystemV",-1,"return .[];"); - testCPU(src,"riscv" , "SystemV", 7,"return (add,.[],(mul,.[],1000));"); + testCPU(src,"x86_64_v2", "SystemV",-1,"return mov(.[]);"); + testCPU(src,"riscv" , "SystemV", 9,"return (add,.[],(mul,.[],1000));"); testCPU(src,"arm" , "SystemV", 5,"return (add,.[],(mul,.[],1000));"); } @Test - public void testAntiDeps1() throws IOException { + public void testAntiDeps1() { String src = """ -struct S { int f; }; -var v0 = new S; -!S? !v1; -if (arg) v1 = new S; +struct _S { int f; }; +var v0 = new _S; +!_S? !v1; +if (arg) v1 = new _S; if (v1) { v0.f = v1.f; } else { @@ -374,18 +343,19 @@ if (v1) { } return v0; """; - testCPU(src,"x86_64_v2", "SystemV", 7,"return mov(mov(S));"); - testCPU(src,"riscv" , "SystemV",10,"return mov(mov(S));"); - testCPU(src,"arm" , "SystemV",10,"return mov(mov(S));"); + testCPU(src,"x86_64_v2", "SystemV", 9,"return mov(mov(Test._S));"); + testCPU(src,"riscv" , "SystemV",10,"return mov(mov(Test._S));"); + testCPU(src,"arm" , "SystemV",11,"return mov(mov(Test._S));"); } @Test - public void testString() throws IOException { + public void testString() { String src = """ struct String { u8[] !cs; int _hashCode; + new String = { u8[] data -> cs=data; }; }; // Compare two Strings @@ -413,9 +383,9 @@ val _hashCodeString = { !String self -> return hash; }; """; - testCPU(src,"x86_64_v2", "SystemV", 9,null); - testCPU(src,"riscv" , "SystemV", 3,null); - testCPU(src,"arm" , "SystemV", 1,null); + testCPU(src,"x86_64_v2", "SystemV",21,null); + testCPU(src,"riscv" , "SystemV",8,null); + testCPU(src,"arm" , "SystemV",8,null); } @Test public void testStringExport() throws IOException { @@ -424,6 +394,7 @@ val _hashCodeString = { !String self -> struct String { u8[] !cs; int _hashCode; + new String = { u8[] data -> cs=data; }; }; // Compare two Strings @@ -451,10 +422,10 @@ val _hashCodeString = { !String self -> return hash; }; """; - TestC.run(src, "stringHash",null, "", 9); + TestC.runC(src, "stringHash", "",21); } - @Test public void testLoop2() throws IOException { + @Test public void testLoop2() { String src = """ int i = 0; @@ -467,9 +438,9 @@ while(true) { } return i; """; - testCPU(src,"x86_64_v2", "Win64" ,0,"return (inc,Phi(Loop,0,inc));"); - testCPU(src,"riscv" , "SystemV",0,"return ( Phi(Loop,0,addi) + #1 );"); - testCPU(src,"arm" , "SystemV",0,"return (inc,Phi(Loop,0,inc));"); + testCPU(src,"x86_64_v2", "win64" ,0,"return (!=0)(inc,Phi(Loop,0,Phi(Region,(!=0),(!=0),0)));"); + testCPU(src,"riscv" , "SystemV",0,"return (!=0)( Phi(Loop,0,Phi(Region,(!=0),(!=0),0)) + #1 );"); + testCPU(src,"arm" , "SystemV",0,"return (!=0)(inc,Phi(Loop,0,Phi(Region,(!=0),(!=0),0)));"); } @Test public void testNewtonExport() throws IOException { @@ -498,9 +469,9 @@ val test_sqrt = { flt x -> } }; """; - TestC.run(src, "newtonFloat", null, result, 34); + TestC.runC(src, "newtonFloat", result, TestC.CALL_CONVENTION.equals("win64") ? 42 : 34); - EvalRisc5 R5 = TestRisc5.build("newtonFloat",src, 0, 10, false); + EvalRisc5 R5 = TestRisc5.build( src, "test_sqrt", 0, 10, false); R5.fregs[riscv.FA0 - riscv.F_OFFSET] = 3.0; int trap_r5 = R5.step(1000); assertEquals(0,trap_r5); @@ -508,7 +479,7 @@ val test_sqrt = { flt x -> assertEquals(1.732051,R5.fregs[riscv.FA0 - riscv.F_OFFSET], 0.00001); // arm - EvalArm64 A5 = TestArm64.build("newtonFloat", src,0, 10, false); + EvalArm64 A5 = TestArm64.build("test_sqrt", src,0, 10, false); A5.fregs[arm.D0 - arm.D_OFFSET] = 3.0; int trap_arm = A5.step(1000); assertEquals(0,trap_arm); @@ -558,11 +529,11 @@ val sieve = { int N -> String sprimes = sb.p("]").toString(); // Compile, link against native C; expect the above string of primes to be printed out by C - TestC.run(src, "sieve", null, sprimes, 186); + TestC.runC(src, "sieve", sprimes, 186); // Evaluate on RISC5 emulator; expect return of an array of primes in // the simulated heap. - EvalRisc5 R5 = TestRisc5.build("sieve", src, 100, 92, false); + EvalRisc5 R5 = TestRisc5.build( src, "sieve", 100, 90, false); int trap = R5.step(10000); assertEquals(0,trap); // Return register A0 holds sieve(100) @@ -574,7 +545,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, 94, 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]; @@ -587,7 +558,7 @@ val sieve = { int N -> @Test public void testFibExport() throws IOException { String src = """ -val fib = {int n -> +val fib = { int n -> int f1=1; int f2=1; while( n-- > 1 ){ @@ -599,9 +570,9 @@ val fib = {int n -> }; """; String fib = "[1, 1, 2, 3, 5, 8, 13, 21, 34, 55]"; - TestC.run(src, "fib", null, fib, 24); + TestC.runC(src, "fib", fib, 24); - EvalRisc5 R5 = TestRisc5.build("fib", src, 9, 17, false); + EvalRisc5 R5 = TestRisc5.build( src, "fib", 9, 17, false); int trap = R5.step(100); assertEquals(0,trap); // Return register A0 holds fib(8)==55 @@ -616,8 +587,19 @@ val fib = {int n -> } @Test public void testPerson() throws IOException { + String src = + """ + struct Person { + i32 age; + }; + + val fcn = { !Person?[] !ps, int x -> + if( ps[x] ) + ps[x].age++; + }; + """; String person = "6\n"; - TestC.run("person21", person, 0); + TestC.run(src, "person1", null, TestC.CALL_CONVENTION, "", TestC.C_DRIVERS_DIR+"person.c", person, 2); // Memory layout starting at PS: int ps = 1<<16; // Person array pointer starts at heap start @@ -628,7 +610,7 @@ val fib = {int n -> int p1 = ps+4*8+1*8; // P2 = { age } // sizeof=8 int p2 = ps+4*8+2*8; - EvalRisc5 R5 = TestRisc5.build("person21", ps, 0, false); + EvalRisc5 R5 = TestRisc5.build( src, "fcn", ps, 2, false); R5.regs[riscv.A1] = 1; // Index 1 R5.st8(ps,3); // Length R5.st8(ps+1*8,p0); @@ -644,7 +626,7 @@ val fib = {int n -> assertEquals(17+1,R5.ld8(p1)); assertEquals(60+0,R5.ld8(p2)); - EvalArm64 A5 = TestArm64.build("person21", ps, 0, false); + EvalArm64 A5 = TestArm64.build("fcn", src, ps, 2, false); A5.regs[arm.X1] = 1; // Index 1 A5.st8(ps, 3); A5.st8(ps+1*8,p0); @@ -662,14 +644,21 @@ val fib = {int n -> } @Test public void testArgCount() throws IOException { - // Test passes more args than registers in Sys5, which is far far more - // than what Win64 allows - so Win64 gets a lot more spills here. + // Test passes more args than registers in Sys5, which is far, far more + // than what win64 allows - so win64 gets a lot more spills here. + String src = +""" +val addAll = { int i0, flt f1, int i2, flt f3, int i4, flt f5, int i6, flt f7, int x8, flt f9, int i10, flt f11, int i12, flt f13, int i14, flt f15, int x16, flt f17 int x18, flt f19 -> + return + i0 + f1+ i2+ f3+ i4+ f5+ i6+ f7+ x8 +f9 + + i10+f11+i12+f13+i14+f15+x16+f17+x18+f19 ; +}; +"""; String arg_count = "191.000000\n"; - TestC.run("arg_count", arg_count, - TestC.CALL_CONVENTION.equals("Win64") ? 32 : 9); + TestC.runC(src, "arg_count", arg_count, TestC.CALL_CONVENTION.equals("win64") ? 35 : 9); - EvalRisc5 R5 = TestRisc5.build("no_stack_arg_count", 0, 0, false); + EvalRisc5 R5 = TestRisc5.build( src, "addAll", 0, 4, false); // Todo: handle stack(imaginary stack in emulator) // pass in float arguments @@ -682,14 +671,13 @@ val fib = {int n -> R5.fregs[riscv.FA6 - riscv.F_OFFSET] = 1.1; R5.fregs[riscv.FA7 - riscv.F_OFFSET] = 1.1; - // a0 is passed in arg + R5.regs[riscv.A0] = 2; R5.regs[riscv.A1] = 2; R5.regs[riscv.A2] = 2; R5.regs[riscv.A3] = 2; R5.regs[riscv.A4] = 2; R5.regs[riscv.A5] = 2; R5.regs[riscv.A6] = 2; - R5.regs[riscv.A7] = 2; int trap = R5.step(100); assertEquals(0,trap); @@ -699,7 +687,7 @@ val fib = {int n -> assertEquals(22.8, result, 0.00001); // arm - EvalArm64 A5 = TestArm64.build("no_stack_arg_count", 0, 0, false); + EvalArm64 A5 = TestArm64.build("addAll", src, 0, 4, false); A5.fregs[arm.D0 - arm.D_OFFSET] = 1.1; A5.fregs[arm.D1 - arm.D_OFFSET] = 1.1; |
