summaryrefslogtreecommitdiff
path: root/chapter28a/src/test/java
diff options
context:
space:
mode:
authorCliff Click <cliffc@acm.org>2026-10-28 15:05:08 -0700
committerCliff Click <cliffc@acm.org>2026-10-28 15:05:08 -0700
commit50924bbe7cfeecfe7aec1885dae9bbda0013ac1b (patch)
tree2d04316faa3c73e2a2586de8f95f9b9fb248425f /chapter28a/src/test/java
parent86ce5bc5d5018dcb62054d214b23f7a59b9c0d7d (diff)
downloadSimple-50924bbe7cfeecfe7aec1885dae9bbda0013ac1b.tar.gz
Simple-50924bbe7cfeecfe7aec1885dae9bbda0013ac1b.zip
Remove _phase checks from Arith & Compute
Fix some monotonicty bugs, rounding bugs, in float ops
Diffstat (limited to 'chapter28a/src/test/java')
-rw-r--r--chapter28a/src/test/java/com/seaofnodes/simple/ArithNodeTest.java96
-rw-r--r--chapter28a/src/test/java/com/seaofnodes/simple/ConvertNodeTest.java69
2 files changed, 165 insertions, 0 deletions
diff --git a/chapter28a/src/test/java/com/seaofnodes/simple/ArithNodeTest.java b/chapter28a/src/test/java/com/seaofnodes/simple/ArithNodeTest.java
new file mode 100644
index 00000000..e912f224
--- /dev/null
+++ b/chapter28a/src/test/java/com/seaofnodes/simple/ArithNodeTest.java
@@ -0,0 +1,96 @@
+package com.seaofnodes.simple;
+
+import com.seaofnodes.simple.codegen.CodeGen;
+import com.seaofnodes.simple.node.*;
+import com.seaofnodes.simple.type.*;
+import java.util.ArrayList;
+import java.util.Arrays;
+import org.junit.Test;
+import static org.junit.Assert.*;
+
+public class ArithNodeTest {
+ @Test public void testUnresolvedInput() {
+ new CodeGen("return 0;").driver(CodeGen.Phase.Opto);
+ Node lhs = ConstantNode.seed(TypeInteger.TRUE);
+ Node rhs = ConstantNode.seed(TypeInteger.TRUE);
+ ArithNode add = new AddNode(lhs,rhs);
+ assertSame(TypeInteger.constant(2),add.compute());
+ lhs._type = TypeScalar.BOT;
+ assertSame(Type.BOTTOM,add.compute());
+ add.setMode((byte)1);
+ assertSame(Type.BOTTOM,add.compute());
+ }
+
+ @Test public void testFloatPrecision() {
+ CodeGen code = new CodeGen("f32 x = arg; return x+1.0;").driver(CodeGen.Phase.TypeCheck);
+ assertEquals("1.6777217E7",Eval2.eval(code,16777216));
+ code = new CodeGen("f32 x = arg; f32 y = x+1.0; return y;").driver(CodeGen.Phase.TypeCheck);
+ assertEquals("1.6777216E7",Eval2.eval(code,16777216));
+ }
+
+ @Test public void testMonotoneCompute() {
+ CodeGen code = new CodeGen("return 0;");
+ ArrayList<Type> inputs = new ArrayList<>(Arrays.asList(
+ Type.BOTTOM,Type.CONTROL,Type.NIL,TypeScalar.BOT,TypeMem.BOT));
+ TypeInteger.gather(inputs);
+ TypeFloat.gather(inputs);
+ TypePtr.gather(inputs);
+ TypeMemPtr.gather(inputs);
+ TypeFunPtr.gather(inputs);
+ inputs.add(TypeConAryB.make(new byte[]{1,2,3}));
+ for( long value : new long[]{Long.MIN_VALUE,Long.MIN_VALUE+1,-1,1,Long.MAX_VALUE} )
+ inputs.add(TypeInteger.constant(value));
+ for( double value : new double[]{-0.0,0.0,-1.0,1.0,16777216.0,16777217.0,Double.NaN,Double.NEGATIVE_INFINITY,Double.POSITIVE_INFINITY} )
+ inputs.add(TypeFloat.constant(value));
+ int size = inputs.size();
+ for( int i = 0; i<size; i++ ) inputs.add(inputs.get(i).dual());
+ size = inputs.size();
+
+ // Isolated inputs let us vary types without peepholes settling modes.
+ Node lhs = ConstantNode.seed(Type.BOTTOM);
+ Node rhs = ConstantNode.seed(Type.BOTTOM);
+ lhs.setDef(0,null);
+ rhs.setDef(0,null);
+ ArrayList<ArithNode> ops = new ArrayList<>();
+ for( byte mode = 0; mode<3; mode++ ) {
+ ops.add(new AddNode(lhs,rhs,mode));
+ ops.add(new SubNode(lhs,rhs,mode));
+ ops.add(new MulNode(lhs,rhs,mode));
+ ops.add(new DivNode(lhs,rhs,mode));
+ }
+ ops.add(new AndNode(null,lhs,rhs));
+ ops.add(new OrNode(null,lhs,rhs));
+ ops.add(new XorNode(null,lhs,rhs));
+ ops.add(new ShlNode(null,lhs,rhs));
+ ops.add(new SarNode(null,lhs,rhs));
+ ops.add(new ShrNode(null,lhs,rhs));
+ Type[][][] expected = new Type[ops.size()][size][size];
+ for( CodeGen.Phase phase : new CodeGen.Phase[]{CodeGen.Phase.Parse,CodeGen.Phase.Iter,CodeGen.Phase.Opto,CodeGen.Phase.IterPostOpto} ) {
+ code.driver(phase);
+ for( int op = 0; op<ops.size(); op++ ) {
+ ArithNode arith = ops.get(op);
+ Type[][] results = new Type[size][size];
+ for( int i = 0; i<size; i++ )
+ for( int j = 0; j<size; j++ ) {
+ lhs._type = inputs.get(i);
+ rhs._type = inputs.get(j);
+ results[i][j] = arith.compute();
+ if( phase==CodeGen.Phase.Parse ) expected[op][i][j] = results[i][j];
+ else assertSame("Phase changed compute",expected[op][i][j],results[i][j]);
+ }
+ // Check the order relation in each argument independently.
+ // This covers both falling SCCP types and rising Iter types.
+ for( int i = 0; i<size; i++ )
+ for( int j = 0; j<size; j++ )
+ if( inputs.get(i).isa(inputs.get(j)) )
+ for( int k = 0; k<size; k++ ) {
+ if( !results[i][k].isa(results[j][k]) || !results[k][i].isa(results[k][j]) )
+ fail(arith.getClass().getSimpleName()+" mode="+arith.mode()+": "+
+ inputs.get(i)+" -> "+inputs.get(j)+", other="+inputs.get(k)+
+ "; lhs results "+results[i][k]+" -> "+results[j][k]+
+ "; rhs results "+results[k][i]+" -> "+results[k][j]);
+ }
+ }
+ }
+ }
+}
diff --git a/chapter28a/src/test/java/com/seaofnodes/simple/ConvertNodeTest.java b/chapter28a/src/test/java/com/seaofnodes/simple/ConvertNodeTest.java
new file mode 100644
index 00000000..96d73f26
--- /dev/null
+++ b/chapter28a/src/test/java/com/seaofnodes/simple/ConvertNodeTest.java
@@ -0,0 +1,69 @@
+package com.seaofnodes.simple;
+
+import com.seaofnodes.simple.codegen.CodeGen;
+import com.seaofnodes.simple.node.ConstantNode;
+import com.seaofnodes.simple.node.ConvertNode;
+import com.seaofnodes.simple.node.Node;
+import com.seaofnodes.simple.type.*;
+import java.util.ArrayList;
+import java.util.Arrays;
+import org.junit.Test;
+import static org.junit.Assert.*;
+
+public class ConvertNodeTest {
+ @Test public void testMonotoneCompute() {
+ CodeGen code = new CodeGen("return 0;");
+ ArrayList<Type> inputs = new ArrayList<>(Arrays.asList(
+ Type.BOTTOM,Type.CONTROL,Type.NIL,TypeScalar.BOT,TypeMem.BOT));
+ TypeInteger.gather(inputs);
+ TypeFloat.gather(inputs);
+ TypePtr.gather(inputs);
+ TypeMemPtr.gather(inputs);
+ TypeFunPtr.gather(inputs);
+ // Writable arrays require matching element access in both directions.
+ // Widening the element's access can make that check pass while keeping
+ // a known length; compute must not suddenly gain that length fact.
+ for( TypeInteger len : new TypeInteger[]{TypeInteger.U32,TypeInteger.TRUE} )
+ for( boolean elementRO : new boolean[]{false,true} )
+ for( boolean arrayRO : new boolean[]{false,true} )
+ inputs.add(TypeMemPtr.make(TypeStruct.makeAry("[]test",len,-1,
+ TypeMemPtr.TEST.withAccess(elementRO),-2,false)).withAccess(arrayRO));
+ inputs.add(TypeConAryB.make(new byte[]{1,2,3}));
+ for( long value : new long[]{Long.MIN_VALUE,-129,-128,-1,0,1,127,128,255,256,Long.MAX_VALUE} )
+ inputs.add(TypeInteger.constant(value));
+ for( double value : new double[]{-0.0,0.0,1.0,16777217.0,Double.NaN,Double.NEGATIVE_INFINITY,Double.POSITIVE_INFINITY} )
+ inputs.add(TypeFloat.constant(value));
+ int size = inputs.size();
+ for( int i = 0; i<size; i++ ) inputs.add(inputs.get(i).dual());
+
+ ArrayList<Type> destinations = new ArrayList<>();
+ for( Type t : inputs )
+ if( !t.isHigh() && (t instanceof TypeInteger || t instanceof TypeFloat || t instanceof TypeNil) )
+ destinations.add(t);
+
+ // Vary one isolated input without folding or lowering the conversion.
+ Node input = ConstantNode.seed(Type.BOTTOM);
+ input.setDef(0,null);
+ Type[][] expected = new Type[destinations.size()][inputs.size()];
+ for( CodeGen.Phase phase : new CodeGen.Phase[]{CodeGen.Phase.Parse,CodeGen.Phase.Iter,CodeGen.Phase.Opto,CodeGen.Phase.IterPostOpto} ) {
+ code.driver(phase);
+ for( int d = 0; d<destinations.size(); d++ ) {
+ Type dst = destinations.get(d);
+ ConvertNode convert = new ConvertNode(dst,input);
+ Type[] results = new Type[inputs.size()];
+ for( int i = 0; i<inputs.size(); i++ ) {
+ input._type = inputs.get(i);
+ results[i] = convert.compute();
+ if( phase==CodeGen.Phase.Parse ) expected[d][i] = results[i];
+ else assertSame("Phase changed compute for "+inputs.get(i)+" to "+dst,expected[d][i],results[i]);
+ }
+ // Check both rising Iter and falling SCCP with the same order.
+ for( int i = 0; i<inputs.size(); i++ )
+ for( int j = 0; j<inputs.size(); j++ )
+ if( inputs.get(i).isa(inputs.get(j)) && !results[i].isa(results[j]) )
+ fail("Convert to "+dst+": "+inputs.get(i)+" -> "+inputs.get(j)+
+ " gave "+results[i]+" -> "+results[j]);
+ }
+ }
+ }
+}