diff options
| author | Cliff Click <cliffc@acm.org> | 2026-10-28 15:05:08 -0700 |
|---|---|---|
| committer | Cliff Click <cliffc@acm.org> | 2026-10-28 15:05:08 -0700 |
| commit | 50924bbe7cfeecfe7aec1885dae9bbda0013ac1b (patch) | |
| tree | 2d04316faa3c73e2a2586de8f95f9b9fb248425f /chapter28a/src/test/java/com/seaofnodes | |
| parent | 86ce5bc5d5018dcb62054d214b23f7a59b9c0d7d (diff) | |
| download | Simple-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/com/seaofnodes')
| -rw-r--r-- | chapter28a/src/test/java/com/seaofnodes/simple/ArithNodeTest.java | 96 | ||||
| -rw-r--r-- | chapter28a/src/test/java/com/seaofnodes/simple/ConvertNodeTest.java | 69 |
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]); + } + } + } +} |
