summaryrefslogtreecommitdiff
path: root/src/test/java/com/seaofnodes/simple/Chapter20Test.java
diff options
context:
space:
mode:
Diffstat (limited to 'src/test/java/com/seaofnodes/simple/Chapter20Test.java')
-rw-r--r--src/test/java/com/seaofnodes/simple/Chapter20Test.java302
1 files changed, 91 insertions, 211 deletions
diff --git a/src/test/java/com/seaofnodes/simple/Chapter20Test.java b/src/test/java/com/seaofnodes/simple/Chapter20Test.java
index 4ca1dbda..b46a54b2 100644
--- a/src/test/java/com/seaofnodes/simple/Chapter20Test.java
+++ b/src/test/java/com/seaofnodes/simple/Chapter20Test.java
@@ -4,8 +4,6 @@ import com.seaofnodes.simple.codegen.RegAllocTestSupport.CheckedCodeGen;
import com.seaofnodes.simple.codegen.CodeGen;
-import com.seaofnodes.simple.print.ASMPrinter;
-import org.junit.Assert;
import org.junit.Ignore;
import org.junit.Test;
import static org.junit.Assert.*;
@@ -52,11 +50,11 @@ public class Chapter20Test {
int 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 ) {
+ if( node instanceof com.seaofnodes.simple.node.cpus.x86_64_v2.StoreX86 st && st._name.equals("x") ) {
stores++;
assertEquals(-1,st.regmap(4).nextReg((short)15));
}
- assertEquals(1,stores);
+ assertTrue(stores>0);
}
}
@@ -71,14 +69,12 @@ return f(s);
// The entry of g can disappear before its Return is folded into f.
// Exercise both worklist orders; deleting the entry does not kill 123.
for( int seed=0; seed<64; seed++ ) {
- CodeGen code = new CodeGen(src,com.seaofnodes.simple.type.TypeInteger.BOT,seed,true).parse().opto().typeCheck();
+ CodeGen code = new CodeGen(src,seed,true).parse().opto().typeCheck();
assertEquals("seed "+seed, "123", Eval2.eval(code,0));
}
}
- @org.junit.Rule public final org.junit.rules.ErrorCollector _errors = new org.junit.rules.ErrorCollector();
-
@Test public void testAllocatorMasks() { com.seaofnodes.simple.codegen.RegAllocTestSupport.masks(); }
@Test public void testAllocatorUnion() { com.seaofnodes.simple.codegen.RegAllocTestSupport.union(); }
@Test public void testAllocatorCopyClobber() throws Exception { com.seaofnodes.simple.codegen.RegAllocTestSupport.copyClobber(); }
@@ -97,40 +93,38 @@ return f(s);
public void testJig() {
CodeGen code = new CodeGen("return 0;");
code.parse().opto().typeCheck();
- assertEquals("return 0;", code._stop.toString());
+ assertEquals("return 0;", code.print());
assertEquals("0", Eval2.eval(code, 2));
}
- // Collect differences so every target runs; JUnit still fails the test.
- private void testTarget(String src, String cpu, String os, int spills, String stop) {
- _errors.checkSucceeds(() -> { testCPU(src,cpu,os,spills,stop); return null; });
- }
-
- static void testCPU(String src, String cpu, String os, int spills, String stop) {
+ static void testCPU( String src, String cpu, String os, int spills, String stop ) {
CodeGen code = new CheckedCodeGen(src);
code.driver(CodeGen.Phase.RegAlloc,cpu,os);
- SpillStats.record(code,"Chapter20",cpu,os);
- SpillStats.checkSpills(spills,code._regAlloc._spillScaled);
- if( stop!=null ) assertEquals(stop,code._stop.toString());
+ 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());
}
- private void testAllCPUs( String src, int spills, String stop ) {
- testTarget(src,"x86_64_v2", "SystemV",spills,stop);
- testTarget(src,"riscv" , "SystemV",spills,stop);
- testTarget(src,"arm" , "SystemV",spills,stop);
+ private static void testAllCPUs( String src, int spills, String stop ) {
+ testCPU(src,"x86_64_v2", "SystemV",spills,stop);
+ testCPU(src,"riscv" , "SystemV",spills,stop);
+ testCPU(src,"arm" , "SystemV",spills,stop);
}
@Test public void testAlloc0() {
- testTarget("return new u8[arg];","x86_64_v2","SystemV",4,"return []u8;");
- testTarget("return new u8[arg];","riscv","SystemV",5,"return []u8;");
- testTarget("return new u8[arg];","arm","SystemV",5,"return []u8;");
+ testCPU("return new u8[arg];","x86_64_v2", "SystemV",3,"return []u8;");
+ testCPU("return new u8[arg];","riscv" , "SystemV",5,"return []u8;");
+ testCPU("return new u8[arg];","arm" , "SystemV",5,"return []u8;");
}
@Test public void testBasic1() {
String src = "return arg | 2;";
- testTarget(src,"x86_64_v2", "SystemV",1,"return (ori,mov(arg));");
- testTarget(src,"riscv" , "SystemV",0,"return ( arg | #2 );");
- testTarget(src,"arm" , "SystemV",0,"return (ori,arg);");
+ testCPU(src,"x86_64_v2", "SystemV",1,"return (ori,mov(arg));");
+ testCPU(src,"riscv" , "SystemV",0,"return ( arg | #2 );");
+ testCPU(src,"arm" , "SystemV",0,"return (ori,arg);");
}
@Test
@@ -138,50 +132,77 @@ return f(s);
String src =
"""
// Newtons approximation to the square root
-val sqrt = { int x ->
+val _sqrt = { int x ->
int guess = x;
while( 1 ) {
- int next = (x/guess + guess)/2;
+ int next = (x/guess + guess)>>1;
if( next == guess ) return guess;
guess = next;
}
};
-return sqrt(arg) + sqrt(arg+2);
+return _sqrt(arg) + _sqrt(arg+2);
""";
- testTarget(src,"x86_64_v2", "SystemV",40,null);
- testTarget(src,"riscv" , "SystemV",17,null);
- testTarget(src,"arm" , "SystemV",18,null);
+ testCPU(src,"x86_64_v2", "win64" ,38,null);
+ testCPU(src,"riscv" , "SystemV",19,null);
+ testCPU(src,"arm" , "SystemV",19,null);
}
@Test
public void testNewtonFloat() {
String src =
"""
-// Newtons approximation to the square root
-val sqrt = { flt x ->
+val _test_sqrt_noInline = { flt x ->
+ flt epsilon = 1e-15;
flt guess = x;
while( 1 ) {
flt next = (x/guess + guess)/2;
- if( next == guess ) return guess;
+ if( guess-epsilon <= next && next <= guess+epsilon )
+ return guess;
guess = next;
}
};
-flt farg = arg;
-return sqrt(farg) + sqrt(farg+2.0);
+flt farg = arg; return _test_sqrt_noInline(farg) + _test_sqrt_noInline(farg+2.0);
""";
- testTarget(src,"x86_64_v2", "SystemV",23,null);
- testTarget(src,"riscv" , "SystemV",18,null);
- testTarget(src,"arm" , "SystemV",18,null);
+ testCPU(src,"x86_64_v2", "SystemV",40,null);
+ testCPU(src,"riscv" , "SystemV",17,null);
+ testCPU(src,"arm" , "SystemV",18,null);
+ }
+
+ @Test
+ public void testIterPrettyPrintIsLocalAndReadOnly() {
+ CodeGen code = new CodeGen("""
+ val f_noInline = { flt x -> while(1) { if(x) return x; } };
+ flt y=arg;
+ return f_noInline(y)+f_noInline(y+2.0);
+ """).driver(CodeGen.Phase.Iter);
+ assertNull(code._start._ltree);
+ int pre = code._start._pre;
+
+ String p0 = code.toString();
+ String p1 = code.toString();
+ assertEquals(p0,p1);
+ assertNull(code._start._ltree);
+ assertEquals(pre,code._start._pre);
+
+ int main0 = p0.indexOf("--- class:Test.<clinit>");
+ int main1 = p0.indexOf("--- class:Test.<clinit> ----------------------",main0);
+ int fun0 = p0.indexOf("--- f_noInline ",main1);
+ int fun1 = p0.indexOf("--- f_noInline ----------------------",fun0);
+ assertTrue(main0 < main1 && main1 < fun0 && fun0 < fun1);
+ assertTrue(p0.indexOf("ToFloat",main0) < p0.indexOf("Call",main0));
+ assertTrue(p0.indexOf("CallEnd",fun0) == -1 || p0.indexOf("CallEnd",fun0) > fun1);
}
@Test
public void testAlloc2() {
String src = "int[] !xs = new int[3]; xs[arg]=1; return xs[arg&1];";
- testTarget(src,"x86_64_v2","SystemV",3,"return .[];");
- testTarget(src,"riscv","SystemV",6,"return .[];");
- testTarget(src,"arm","SystemV",6,"return .[];");
+ testCPU(src,"x86_64_v2", "SystemV",-1,"return .[];");
+ testCPU(src,"riscv" , "SystemV", 6,"return .[];");
+ testCPU(src,"arm" , "SystemV", 6,"return .[];");
}
+
+
@Test
public void testArray1() {
String src =
@@ -195,19 +216,23 @@ for( int i=0; i<ary#-1; i++ )
ary[i+1] += ary[i];
return ary[1] * 1000 + ary[3]; // 1 * 1000 + 6
""";
- testTarget(src,"x86_64_v2", "SystemV",5,"return .[];");
- testTarget(src,"riscv" , "SystemV",7,"return (add,.[],(mul,.[],1000));");
- testTarget(src,"arm" , "SystemV",5,"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 testString() {
- String src = """
+ String src =
+"""
struct String {
u8[] !cs;
int _hashCode;
+ new String = { u8[] data -> cs=data; };
};
+// Compare two Strings
val equals = { !String !self, !String s ->
if( self == s ) return true;
if( self.cs# != s.cs# ) return false;
@@ -217,6 +242,7 @@ val equals = { !String !self, !String s ->
return true;
};
+// Return the String hashCode (cached, and never 0)
val hashCode = { !String self ->
self._hashCode
? self._hashCode
@@ -225,30 +251,23 @@ val hashCode = { !String self ->
val _hashCodeString = { !String self ->
int hash=0;
- if( self.cs ) {
- for( int i=0; i< self.cs#; i++ )
- hash = hash*31 + self.cs[i];
- }
+ for( int i=0; i< self.cs#; i++ )
+ hash = hash*31 + self.cs[i];
if( !hash ) hash = 123456789;
return hash;
};
-
-!String !s = new String { cs = new u8[17]; };
-s.cs[0] = 67; // C
-s.cs[1] = 108; // l
-hashCode(s);
""";
- testTarget(src,"x86_64_v2", "SystemV",9,null);
- testTarget(src,"riscv" , "SystemV",3,null);
- testTarget(src,"arm" , "SystemV",0,null);
+ testCPU(src,"x86_64_v2", "SystemV",21,null);
+ testCPU(src,"riscv" , "SystemV",8,null);
+ testCPU(src,"arm" , "SystemV",8,null);
}
@Test
public void testCast() {
String src = "struct Bar { int x; }; var b = arg ? new Bar; return b ? b.x++ + b.x++ : -1;";
- testTarget(src,"x86_64_v2","SystemV",1,null);
- testTarget(src,"riscv","SystemV",2,null);
- testTarget(src,"arm","SystemV",2,null);
+ testCPU(src,"x86_64_v2", "SystemV",3,null);
+ testCPU(src,"riscv" , "SystemV",6,null);
+ testCPU(src,"arm" , "SystemV",6,null);
}
@Test
@@ -260,15 +279,15 @@ hashCode(s);
@Test
public void testFlags1() {
String src = """
-bool b1 = arg == 1;
+bool _b1 = arg == 1;
bool b2 = arg == 2;
-if (b2) if (b1) return 1;
-if (b1) return 2;
+if (b2) if (_b1) return 1;
+if (_b1) return 2;
return 0;
""";
- testTarget(src,"x86_64_v2", "SystemV",0,"return Phi(Region,1,2,0);");
- testTarget(src,"riscv" , "SystemV",0,"return Phi(Region,1,2,0);");
- testTarget(src,"arm" , "SystemV",0,"return Phi(Region,1,2,0);");
+ testCPU(src,"x86_64_v2", "SystemV",0,"return Phi(Region,2,0,1);");
+ testCPU(src,"riscv" , "SystemV",0,"return Phi(Region,2,0,1);");
+ testCPU(src,"arm" , "SystemV",0,"return Phi(Region,2,0,1);");
}
@Test
@@ -281,147 +300,8 @@ while (arg > 0) {
}
return arg;
""";
- testTarget(src,"x86_64_v2", "SystemV",3,null);
- testTarget(src,"riscv" , "SystemV",2,null);
- testTarget(src,"arm" , "SystemV",2,null);
- }
- // Original Chapter 20 allocation workload, kept fixed for cohort comparisons.
- @Test
- public void testBrainfuck() {
- var program = "++++++++[>++++[>++>+++>+++>+<<<<-]>+>+>->>+[<]<-]>>.>---.+++++++..+++.>>.<-.<.+++.------.--------.>>+.>++.".getBytes(java.nio.charset.StandardCharsets.UTF_8);
- var encoded = new StringBuilder("u8[] !program = new u8[").append(program.length).append("];");
- for (int i = 0; i < program.length; i++) {
- int value = program[i] & 0xFF;
- encoded.append("program[").append(i).append("] = ").append(value).append(";");
- }
-
- String src = encoded + """
-
-int d = 0;
-u8[] !output = new u8[0];
-u8[] !data = new u8[100];
-
-for( int pc = 0; pc < program#; pc++ ) {
- var command = program[pc];
- if (command == 62) {
- d++;
- } else if (command == 60) {
- d--;
- } else if (command == 43) {
- data[d]++;
- } else if (command == 45) {
- data[d]--;
- } else if (command == 46) {
- // Output a byte; increase the output array size
- var old = output;
- output = new u8[output# + 1];
- for( int i = 0; i < old#; i++ )
- output[i] = old[i];
- output[old#] = data[d]; // Add the extra byte on the end
- } else if (command == 44) {
- data[d] = 42;
- } else if (command == 91) {
- if (data[d] == 0) {
- for( int d = 1; d > 0; ) {
- command = program[++pc];
- if (command == 91) d++;
- if (command == 93) d--;
- }
- }
- } else if (command == 93) {
- if (data[d]) {
- for( int d = 1; d > 0; ) {
- command = program[--pc];
- if (command == 93) d++;
- if (command == 91) d--;
- }
- }
- }
-}
-return output;
-""";
- testTarget(src,"x86_64_v2", "SystemV",40,null);
- testTarget(src,"riscv" , "SystemV",28,null);
- testTarget(src,"arm" , "SystemV",28,null);
- //assertEquals("Hello World!\n", Eval2.eval(code, 0, 10000));
- }
- // Original Chapter 20 allocation workload, kept fixed for cohort comparisons.
- @Test
- public void testMergeSort() {
- String src =
-"""
-// based on the top-down version from https://en.wikipedia.org/wiki/Merge_sort
-
-val merge_sort = { int[] !a, int[] !b, int n ->
- copy_array(a, 0, n, b);
- split_merge(a, 0, n, b);
-};
-
-val split_merge = { int[] !b, int begin, int end, int[] a ->
- if (end - begin <= 1)
- return 0;
- int middle = (end + begin) / 2;
- split_merge(a, begin, middle, b);
- split_merge(a, middle, end, b);
- merge(b, begin, middle, end, a);
- return 0;
-};
-
-val merge = { int[] !b, int begin, int middle, int end, int[] a ->
- int i = begin, j = middle;
-
- for (int k = begin; k < end; k++) {
- // && and ||
- bool cond = false;
- if (i < middle) {
- if (j >= end) cond = true;
- else if (a[i] <= a[j]) cond = true;
- }
- if (cond) b[k] = a[i++];
- else b[k] = a[j++];
- }
-};
-
-val copy_array = { int[] !a, int begin, int end, int[] b ->
- for (int k = begin; k < end; k++)
- b[k] = a[k];
-};
-
-int[] !a = new int[arg];
-int[] !b = new int[a#];
-
-for (int i = 0; i < a#; i++)
- a[i] = a# - i;
-
-merge_sort(a, b, a#);
-
-return a;
-""";
- testTarget(src,"x86_64_v2", "SystemV",52,null);
- testTarget(src,"riscv" , "SystemV",44,null);
- testTarget(src,"arm" , "SystemV",41,null);
-//assertEquals("int[ 1,2,3,4,5,6,7,8,9,10,11]", Eval2.eval(code, 11));
- }
-
-
- @Test public void testMemoryAllocation() {
- for( String cpu : new String[]{"x86_64_v2","riscv","arm"} )
- for( String src : new String[]{Chapter10Test.NESTED_MEMORY,Chapter16Test.CONSTRUCTOR_MEMORY,
- Chapter18Test.CALL_MEMORY,Chapter18Test.RECURSIVE_MEMORY,
- "int[] !a = new int[3]; a[arg]=arg; return a[0]+1;"} ) {
- var code = new CodeGen(src).parse().opto().typeCheck().loopTree()
- .instSelect(cpu,"SystemV").GCM().localSched().regAlloc();
- com.seaofnodes.simple.codegen.RegAllocTestSupport.checkRegisters(code);
- code._stop.walk(n -> {
- // Whole memory, precise Phis, and memory projections need no register.
- if( n._type instanceof com.seaofnodes.simple.type.TypeMem )
- assertEquals(-1,code._regAlloc.regnum(n));
- if( n instanceof com.seaofnodes.simple.node.NewNode nn ) {
- assertTrue(code._regAlloc.regnum(nn.proj(0))>=0);
- assertEquals(-1,code._regAlloc.regnum(nn.proj(1)));
- }
- return null;
- });
- }
+ testCPU(src,"x86_64_v2", "SystemV",3,null);
+ testCPU(src,"riscv" , "SystemV",2,null);
+ testCPU(src,"arm" , "SystemV",2,null);
}
}