diff options
64 files changed, 1108 insertions, 64 deletions
diff --git a/chapter04/README.md b/chapter04/README.md index 2c7f7e9c..07085e80 100644 --- a/chapter04/README.md +++ b/chapter04/README.md @@ -305,6 +305,7 @@ Here is a list of peepholes introduced in this Chapter, more will be introduced | Before | After | Description | |-----------------------|-----------------------|------------------------------------------------| | (arg + 0 ) | arg | Add of zero identity | +| (arg - 0 ) | arg | Sub of zero identity | | (arg * 1 ) | arg | Multiple of one identity | | (con + arg) | (arg + con) | Move constants to right, to encourage folding | | (con * arg) | (arg * con) | Move constants to right, to encourage folding | @@ -312,6 +313,9 @@ Here is a list of peepholes introduced in this Chapter, more will be introduced | ((arg1 + con) + arg2) | ((arg1 + arg2) + con) | Move constants to right, to encourage folding | | (arg + arg) | (arg * 2) | Sum-of-products form | | (arg - arg) | 0 | Sub of same is 0 +| (0 - arg) | (-arg) | Sub from 0 is negation +| (arg1 - (-arg2)) | (arg1 + arg2) | Sub of negation is add +| ((-arg1) - arg2) | -(arg1 + arg2) | Sub from negation is negation of sum | (con / 1) | con | Division by one | (arg == arg) | 1 | Compare of same | (arg != arg) | 0 | Compare of same diff --git a/chapter04/src/main/java/com/seaofnodes/simple/node/SubNode.java b/chapter04/src/main/java/com/seaofnodes/simple/node/SubNode.java index f5ad663d..c831a798 100644 --- a/chapter04/src/main/java/com/seaofnodes/simple/node/SubNode.java +++ b/chapter04/src/main/java/com/seaofnodes/simple/node/SubNode.java @@ -32,6 +32,25 @@ public class SubNode extends Node { @Override public Node idealize() { + Node lhs = in(1); + Node rhs = in(2); + Type t1 = lhs._type; + Type t2 = rhs._type; + + // Keep invalid operands for type checking. + if( t1 instanceof TypeInteger x && t2 instanceof TypeInteger y ) { + if( y.isConstant() && y.value()==0 ) return lhs; + if( x.isConstant() && x.value()==0 ) return new MinusNode(rhs); + } + + // x - (-y) is x+y + if( rhs instanceof MinusNode minus ) + return new AddNode(lhs,minus.in(1)); + + // (-x) - y is -(x+y) + if( lhs instanceof MinusNode minus ) + return new MinusNode(new AddNode(minus.in(1),rhs).peephole()); + return null; } diff --git a/chapter04/src/test/java/com/seaofnodes/simple/Chapter04Test.java b/chapter04/src/test/java/com/seaofnodes/simple/Chapter04Test.java index 28912d5d..74682310 100644 --- a/chapter04/src/test/java/com/seaofnodes/simple/Chapter04Test.java +++ b/chapter04/src/test/java/com/seaofnodes/simple/Chapter04Test.java @@ -51,6 +51,34 @@ public class Chapter04Test { } @Test + public void testSub0() { + Parser parser = new Parser("return arg-0;"); + ReturnNode ret = parser.parse(); + assertEquals("return arg;", ret.print()); + } + + @Test + public void test0Sub() { + Parser parser = new Parser("return 0-arg;"); + ReturnNode ret = parser.parse(); + assertEquals("return (-arg);", ret.print()); + } + + @Test + public void testSubNeg() { + Parser parser = new Parser("return 3--arg;"); + ReturnNode ret = parser.parse(); + assertEquals("return (arg+3);", ret.print()); + } + + @Test + public void testNegSub() { + Parser parser = new Parser("return -arg-3;"); + ReturnNode ret = parser.parse(); + assertEquals("return (-(arg+3));", ret.print()); + } + + @Test public void testVarArg() { Parser parser = new Parser("return arg; ", TypeInteger.BOT); ReturnNode ret = parser.parse(); diff --git a/chapter05/src/main/java/com/seaofnodes/simple/node/SubNode.java b/chapter05/src/main/java/com/seaofnodes/simple/node/SubNode.java index d3fd1c7e..bd43bc6c 100644 --- a/chapter05/src/main/java/com/seaofnodes/simple/node/SubNode.java +++ b/chapter05/src/main/java/com/seaofnodes/simple/node/SubNode.java @@ -32,6 +32,25 @@ public class SubNode extends Node { @Override public Node idealize() { + Node lhs = in(1); + Node rhs = in(2); + Type t1 = lhs._type; + Type t2 = rhs._type; + + // Keep invalid operands for type checking. + if( t1 instanceof TypeInteger x && t2 instanceof TypeInteger y ) { + if( y.isConstant() && y.value()==0 ) return lhs; + if( x.isConstant() && x.value()==0 ) return new MinusNode(rhs); + } + + // x - (-y) is x+y + if( rhs instanceof MinusNode minus ) + return new AddNode(lhs,minus.in(1)); + + // (-x) - y is -(x+y) + if( lhs instanceof MinusNode minus ) + return new MinusNode(new AddNode(minus.in(1),rhs).peephole()); + return null; } diff --git a/chapter05/src/test/java/com/seaofnodes/simple/Chapter04Test.java b/chapter05/src/test/java/com/seaofnodes/simple/Chapter04Test.java index 2e2abb25..f1603cc4 100644 --- a/chapter05/src/test/java/com/seaofnodes/simple/Chapter04Test.java +++ b/chapter05/src/test/java/com/seaofnodes/simple/Chapter04Test.java @@ -51,6 +51,34 @@ public class Chapter04Test { } @Test + public void testSub0() { + Parser parser = new Parser("return arg-0;"); + StopNode ret = parser.parse(); + assertEquals("return arg;", ret.print()); + } + + @Test + public void test0Sub() { + Parser parser = new Parser("return 0-arg;"); + StopNode ret = parser.parse(); + assertEquals("return (-arg);", ret.print()); + } + + @Test + public void testSubNeg() { + Parser parser = new Parser("return 3--arg;"); + StopNode ret = parser.parse(); + assertEquals("return (arg+3);", ret.print()); + } + + @Test + public void testNegSub() { + Parser parser = new Parser("return -arg-3;"); + StopNode ret = parser.parse(); + assertEquals("return (-(arg+3));", ret.print()); + } + + @Test public void testVarArg() { Parser parser = new Parser("return arg; "); StopNode stop = parser.parse(); diff --git a/chapter06/src/main/java/com/seaofnodes/simple/node/SubNode.java b/chapter06/src/main/java/com/seaofnodes/simple/node/SubNode.java index d3fd1c7e..bd43bc6c 100644 --- a/chapter06/src/main/java/com/seaofnodes/simple/node/SubNode.java +++ b/chapter06/src/main/java/com/seaofnodes/simple/node/SubNode.java @@ -32,6 +32,25 @@ public class SubNode extends Node { @Override public Node idealize() { + Node lhs = in(1); + Node rhs = in(2); + Type t1 = lhs._type; + Type t2 = rhs._type; + + // Keep invalid operands for type checking. + if( t1 instanceof TypeInteger x && t2 instanceof TypeInteger y ) { + if( y.isConstant() && y.value()==0 ) return lhs; + if( x.isConstant() && x.value()==0 ) return new MinusNode(rhs); + } + + // x - (-y) is x+y + if( rhs instanceof MinusNode minus ) + return new AddNode(lhs,minus.in(1)); + + // (-x) - y is -(x+y) + if( lhs instanceof MinusNode minus ) + return new MinusNode(new AddNode(minus.in(1),rhs).peephole()); + return null; } diff --git a/chapter06/src/test/java/com/seaofnodes/simple/Chapter04Test.java b/chapter06/src/test/java/com/seaofnodes/simple/Chapter04Test.java index 98878ca6..e5840622 100644 --- a/chapter06/src/test/java/com/seaofnodes/simple/Chapter04Test.java +++ b/chapter06/src/test/java/com/seaofnodes/simple/Chapter04Test.java @@ -51,6 +51,34 @@ public class Chapter04Test { } @Test + public void testSub0() { + Parser parser = new Parser("return arg-0;"); + StopNode ret = parser.parse(); + assertEquals("return arg;", ret.print()); + } + + @Test + public void test0Sub() { + Parser parser = new Parser("return 0-arg;"); + StopNode ret = parser.parse(); + assertEquals("return (-arg);", ret.print()); + } + + @Test + public void testSubNeg() { + Parser parser = new Parser("return 3--arg;"); + StopNode ret = parser.parse(); + assertEquals("return (arg+3);", ret.print()); + } + + @Test + public void testNegSub() { + Parser parser = new Parser("return -arg-3;"); + StopNode ret = parser.parse(); + assertEquals("return (-(arg+3));", ret.print()); + } + + @Test public void testVarArg() { Parser parser = new Parser("return arg;"); StopNode stop = parser.parse(); diff --git a/chapter07/src/main/java/com/seaofnodes/simple/node/SubNode.java b/chapter07/src/main/java/com/seaofnodes/simple/node/SubNode.java index 1ab17b04..421e659b 100644 --- a/chapter07/src/main/java/com/seaofnodes/simple/node/SubNode.java +++ b/chapter07/src/main/java/com/seaofnodes/simple/node/SubNode.java @@ -34,6 +34,25 @@ public class SubNode extends Node { @Override public Node idealize() { + Node lhs = in(1); + Node rhs = in(2); + Type t1 = lhs._type; + Type t2 = rhs._type; + + // Keep invalid operands for type checking. + if( t1 instanceof TypeInteger x && t2 instanceof TypeInteger y ) { + if( y.isConstant() && y.value()==0 ) return lhs; + if( x.isConstant() && x.value()==0 ) return new MinusNode(rhs); + } + + // x - (-y) is x+y + if( rhs instanceof MinusNode minus ) + return new AddNode(lhs,minus.in(1)); + + // (-x) - y is -(x+y) + if( lhs instanceof MinusNode minus ) + return new MinusNode(new AddNode(minus.in(1),rhs).peephole()); + return null; } diff --git a/chapter07/src/test/java/com/seaofnodes/simple/Chapter04Test.java b/chapter07/src/test/java/com/seaofnodes/simple/Chapter04Test.java index 98878ca6..e5840622 100644 --- a/chapter07/src/test/java/com/seaofnodes/simple/Chapter04Test.java +++ b/chapter07/src/test/java/com/seaofnodes/simple/Chapter04Test.java @@ -51,6 +51,34 @@ public class Chapter04Test { } @Test + public void testSub0() { + Parser parser = new Parser("return arg-0;"); + StopNode ret = parser.parse(); + assertEquals("return arg;", ret.print()); + } + + @Test + public void test0Sub() { + Parser parser = new Parser("return 0-arg;"); + StopNode ret = parser.parse(); + assertEquals("return (-arg);", ret.print()); + } + + @Test + public void testSubNeg() { + Parser parser = new Parser("return 3--arg;"); + StopNode ret = parser.parse(); + assertEquals("return (arg+3);", ret.print()); + } + + @Test + public void testNegSub() { + Parser parser = new Parser("return -arg-3;"); + StopNode ret = parser.parse(); + assertEquals("return (-(arg+3));", ret.print()); + } + + @Test public void testVarArg() { Parser parser = new Parser("return arg;"); StopNode stop = parser.parse(); diff --git a/chapter08/src/main/java/com/seaofnodes/simple/node/SubNode.java b/chapter08/src/main/java/com/seaofnodes/simple/node/SubNode.java index 1ab17b04..421e659b 100644 --- a/chapter08/src/main/java/com/seaofnodes/simple/node/SubNode.java +++ b/chapter08/src/main/java/com/seaofnodes/simple/node/SubNode.java @@ -34,6 +34,25 @@ public class SubNode extends Node { @Override public Node idealize() { + Node lhs = in(1); + Node rhs = in(2); + Type t1 = lhs._type; + Type t2 = rhs._type; + + // Keep invalid operands for type checking. + if( t1 instanceof TypeInteger x && t2 instanceof TypeInteger y ) { + if( y.isConstant() && y.value()==0 ) return lhs; + if( x.isConstant() && x.value()==0 ) return new MinusNode(rhs); + } + + // x - (-y) is x+y + if( rhs instanceof MinusNode minus ) + return new AddNode(lhs,minus.in(1)); + + // (-x) - y is -(x+y) + if( lhs instanceof MinusNode minus ) + return new MinusNode(new AddNode(minus.in(1),rhs).peephole()); + return null; } diff --git a/chapter08/src/test/java/com/seaofnodes/simple/Chapter04Test.java b/chapter08/src/test/java/com/seaofnodes/simple/Chapter04Test.java index 2e2abb25..f1603cc4 100644 --- a/chapter08/src/test/java/com/seaofnodes/simple/Chapter04Test.java +++ b/chapter08/src/test/java/com/seaofnodes/simple/Chapter04Test.java @@ -51,6 +51,34 @@ public class Chapter04Test { } @Test + public void testSub0() { + Parser parser = new Parser("return arg-0;"); + StopNode ret = parser.parse(); + assertEquals("return arg;", ret.print()); + } + + @Test + public void test0Sub() { + Parser parser = new Parser("return 0-arg;"); + StopNode ret = parser.parse(); + assertEquals("return (-arg);", ret.print()); + } + + @Test + public void testSubNeg() { + Parser parser = new Parser("return 3--arg;"); + StopNode ret = parser.parse(); + assertEquals("return (arg+3);", ret.print()); + } + + @Test + public void testNegSub() { + Parser parser = new Parser("return -arg-3;"); + StopNode ret = parser.parse(); + assertEquals("return (-(arg+3));", ret.print()); + } + + @Test public void testVarArg() { Parser parser = new Parser("return arg; "); StopNode stop = parser.parse(); diff --git a/chapter09/src/main/java/com/seaofnodes/simple/node/SubNode.java b/chapter09/src/main/java/com/seaofnodes/simple/node/SubNode.java index 59cd31f0..eeec5e1d 100644 --- a/chapter09/src/main/java/com/seaofnodes/simple/node/SubNode.java +++ b/chapter09/src/main/java/com/seaofnodes/simple/node/SubNode.java @@ -37,6 +37,25 @@ public class SubNode extends Node { @Override public Node idealize() { + Node lhs = in(1); + Node rhs = in(2); + Type t1 = lhs._type; + Type t2 = rhs._type; + + // Keep invalid operands for type checking. + if( t1 instanceof TypeInteger x && t2 instanceof TypeInteger y ) { + if( y.isConstant() && y.value()==0 ) return lhs; + if( x.isConstant() && x.value()==0 ) return new MinusNode(rhs); + } + + // x - (-y) is x+y + if( rhs instanceof MinusNode minus ) + return new AddNode(lhs,minus.in(1)); + + // (-x) - y is -(x+y) + if( lhs instanceof MinusNode minus ) + return new MinusNode(new AddNode(minus.in(1),rhs).peephole()); + return null; } diff --git a/chapter09/src/test/java/com/seaofnodes/simple/Chapter04Test.java b/chapter09/src/test/java/com/seaofnodes/simple/Chapter04Test.java index 2e2abb25..f1603cc4 100644 --- a/chapter09/src/test/java/com/seaofnodes/simple/Chapter04Test.java +++ b/chapter09/src/test/java/com/seaofnodes/simple/Chapter04Test.java @@ -51,6 +51,34 @@ public class Chapter04Test { } @Test + public void testSub0() { + Parser parser = new Parser("return arg-0;"); + StopNode ret = parser.parse(); + assertEquals("return arg;", ret.print()); + } + + @Test + public void test0Sub() { + Parser parser = new Parser("return 0-arg;"); + StopNode ret = parser.parse(); + assertEquals("return (-arg);", ret.print()); + } + + @Test + public void testSubNeg() { + Parser parser = new Parser("return 3--arg;"); + StopNode ret = parser.parse(); + assertEquals("return (arg+3);", ret.print()); + } + + @Test + public void testNegSub() { + Parser parser = new Parser("return -arg-3;"); + StopNode ret = parser.parse(); + assertEquals("return (-(arg+3));", ret.print()); + } + + @Test public void testVarArg() { Parser parser = new Parser("return arg; "); StopNode stop = parser.parse(); diff --git a/chapter10/src/main/java/com/seaofnodes/simple/node/SubNode.java b/chapter10/src/main/java/com/seaofnodes/simple/node/SubNode.java index dfb4744d..eeec5e1d 100644 --- a/chapter10/src/main/java/com/seaofnodes/simple/node/SubNode.java +++ b/chapter10/src/main/java/com/seaofnodes/simple/node/SubNode.java @@ -37,13 +37,24 @@ public class SubNode extends Node { @Override public Node idealize() { + Node lhs = in(1); + Node rhs = in(2); + Type t1 = lhs._type; + Type t2 = rhs._type; + + // Keep invalid operands for type checking. + if( t1 instanceof TypeInteger x && t2 instanceof TypeInteger y ) { + if( y.isConstant() && y.value()==0 ) return lhs; + if( x.isConstant() && x.value()==0 ) return new MinusNode(rhs); + } + // x - (-y) is x+y - if( in(2) instanceof MinusNode minus ) - return new AddNode(in(1),minus.in(1)); + if( rhs instanceof MinusNode minus ) + return new AddNode(lhs,minus.in(1)); // (-x) - y is -(x+y) - if( in(1) instanceof MinusNode minus ) - return new MinusNode(new AddNode(minus.in(1),in(2)).peephole()); + if( lhs instanceof MinusNode minus ) + return new MinusNode(new AddNode(minus.in(1),rhs).peephole()); return null; } diff --git a/chapter10/src/test/java/com/seaofnodes/simple/Chapter04Test.java b/chapter10/src/test/java/com/seaofnodes/simple/Chapter04Test.java index 2e2abb25..f1603cc4 100644 --- a/chapter10/src/test/java/com/seaofnodes/simple/Chapter04Test.java +++ b/chapter10/src/test/java/com/seaofnodes/simple/Chapter04Test.java @@ -51,6 +51,34 @@ public class Chapter04Test { } @Test + public void testSub0() { + Parser parser = new Parser("return arg-0;"); + StopNode ret = parser.parse(); + assertEquals("return arg;", ret.print()); + } + + @Test + public void test0Sub() { + Parser parser = new Parser("return 0-arg;"); + StopNode ret = parser.parse(); + assertEquals("return (-arg);", ret.print()); + } + + @Test + public void testSubNeg() { + Parser parser = new Parser("return 3--arg;"); + StopNode ret = parser.parse(); + assertEquals("return (arg+3);", ret.print()); + } + + @Test + public void testNegSub() { + Parser parser = new Parser("return -arg-3;"); + StopNode ret = parser.parse(); + assertEquals("return (-(arg+3));", ret.print()); + } + + @Test public void testVarArg() { Parser parser = new Parser("return arg; "); StopNode stop = parser.parse(); diff --git a/chapter11/src/main/java/com/seaofnodes/simple/node/SubNode.java b/chapter11/src/main/java/com/seaofnodes/simple/node/SubNode.java index 76a34e31..2c5bafca 100644 --- a/chapter11/src/main/java/com/seaofnodes/simple/node/SubNode.java +++ b/chapter11/src/main/java/com/seaofnodes/simple/node/SubNode.java @@ -38,13 +38,24 @@ public class SubNode extends Node { @Override public Node idealize() { + Node lhs = in(1); + Node rhs = in(2); + Type t1 = lhs._type; + Type t2 = rhs._type; + + // Keep invalid operands for type checking. + if( t1 instanceof TypeInteger x && t2 instanceof TypeInteger y ) { + if( y.isConstant() && y.value()==0 ) return lhs; + if( x.isConstant() && x.value()==0 ) return new MinusNode(rhs); + } + // x - (-y) is x+y - if( in(2) instanceof MinusNode minus ) - return new AddNode(in(1),minus.in(1)); + if( rhs instanceof MinusNode minus ) + return new AddNode(lhs,minus.in(1)); // (-x) - y is -(x+y) - if( in(1) instanceof MinusNode minus ) - return new MinusNode(new AddNode(minus.in(1),in(2)).peephole()); + if( lhs instanceof MinusNode minus ) + return new MinusNode(new AddNode(minus.in(1),rhs).peephole()); return null; } diff --git a/chapter11/src/test/java/com/seaofnodes/simple/Chapter04Test.java b/chapter11/src/test/java/com/seaofnodes/simple/Chapter04Test.java index 80cdb3f2..a3109ff7 100644 --- a/chapter11/src/test/java/com/seaofnodes/simple/Chapter04Test.java +++ b/chapter11/src/test/java/com/seaofnodes/simple/Chapter04Test.java @@ -51,6 +51,34 @@ public class Chapter04Test { } @Test + public void testSub0() { + Parser parser = new Parser("return arg-0;"); + StopNode ret = parser.parse(); + assertEquals("return arg;", ret.print()); + } + + @Test + public void test0Sub() { + Parser parser = new Parser("return 0-arg;"); + StopNode ret = parser.parse(); + assertEquals("return (-arg);", ret.print()); + } + + @Test + public void testSubNeg() { + Parser parser = new Parser("return 3--arg;"); + StopNode ret = parser.parse(); + assertEquals("return (arg+3);", ret.print()); + } + + @Test + public void testNegSub() { + Parser parser = new Parser("return -arg-3;"); + StopNode ret = parser.parse(); + assertEquals("return (-(arg+3));", ret.print()); + } + + @Test public void testVarArg() { Parser parser = new Parser("return arg; "); StopNode stop = parser.parse(); diff --git a/chapter12/src/main/java/com/seaofnodes/simple/node/SubNode.java b/chapter12/src/main/java/com/seaofnodes/simple/node/SubNode.java index d8538277..4ae302f0 100644 --- a/chapter12/src/main/java/com/seaofnodes/simple/node/SubNode.java +++ b/chapter12/src/main/java/com/seaofnodes/simple/node/SubNode.java @@ -39,13 +39,24 @@ public class SubNode extends Node { @Override public Node idealize() { + Node lhs = in(1); + Node rhs = in(2); + Type t1 = lhs._type; + Type t2 = rhs._type; + + // Keep invalid operands for type checking. + if( t1 instanceof TypeInteger x && t2 instanceof TypeInteger y ) { + if( y.isConstant() && y.value()==0 ) return lhs; + if( x.isConstant() && x.value()==0 ) return new MinusNode(rhs); + } + // x - (-y) is x+y - if( in(2) instanceof MinusNode minus ) - return new AddNode(in(1),minus.in(1)); + if( rhs instanceof MinusNode minus ) + return new AddNode(lhs,minus.in(1)); // (-x) - y is -(x+y) - if( in(1) instanceof MinusNode minus ) - return new MinusNode(new AddNode(minus.in(1),in(2)).peephole()); + if( lhs instanceof MinusNode minus ) + return new MinusNode(new AddNode(minus.in(1),rhs).peephole()); return null; } diff --git a/chapter12/src/test/java/com/seaofnodes/simple/Chapter04Test.java b/chapter12/src/test/java/com/seaofnodes/simple/Chapter04Test.java index 80cdb3f2..a3109ff7 100644 --- a/chapter12/src/test/java/com/seaofnodes/simple/Chapter04Test.java +++ b/chapter12/src/test/java/com/seaofnodes/simple/Chapter04Test.java @@ -51,6 +51,34 @@ public class Chapter04Test { } @Test + public void testSub0() { + Parser parser = new Parser("return arg-0;"); + StopNode ret = parser.parse(); + assertEquals("return arg;", ret.print()); + } + + @Test + public void test0Sub() { + Parser parser = new Parser("return 0-arg;"); + StopNode ret = parser.parse(); + assertEquals("return (-arg);", ret.print()); + } + + @Test + public void testSubNeg() { + Parser parser = new Parser("return 3--arg;"); + StopNode ret = parser.parse(); + assertEquals("return (arg+3);", ret.print()); + } + + @Test + public void testNegSub() { + Parser parser = new Parser("return -arg-3;"); + StopNode ret = parser.parse(); + assertEquals("return (-(arg+3));", ret.print()); + } + + @Test public void testVarArg() { Parser parser = new Parser("return arg; "); StopNode stop = parser.parse(); diff --git a/chapter12/src/test/java/com/seaofnodes/simple/Chapter12Test.java b/chapter12/src/test/java/com/seaofnodes/simple/Chapter12Test.java index d862df95..9da4a4b8 100644 --- a/chapter12/src/test/java/com/seaofnodes/simple/Chapter12Test.java +++ b/chapter12/src/test/java/com/seaofnodes/simple/Chapter12Test.java @@ -9,6 +9,13 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.fail; public class Chapter12Test { + @Test public void testSubZeroFloat() { + var stop = new Parser("flt x = arg; return 0-x;").parse().iterate(); + // Compare strings so +0.0 and -0.0 remain distinct. + assertEquals("0.0", Evaluator.evaluate(stop,0).toString()); + assertEquals("-1.0", Evaluator.evaluate(stop,1).toString()); + } + @Test public void testDeadNumericReturns() { for( String[] test : new String[][] { {"if(1) return 7; else return 2.5;", "7"}, diff --git a/chapter13/src/main/java/com/seaofnodes/simple/node/SubNode.java b/chapter13/src/main/java/com/seaofnodes/simple/node/SubNode.java index 4b860c37..4ae302f0 100644 --- a/chapter13/src/main/java/com/seaofnodes/simple/node/SubNode.java +++ b/chapter13/src/main/java/com/seaofnodes/simple/node/SubNode.java @@ -39,14 +39,24 @@ public class SubNode extends Node { @Override public Node idealize() { + Node lhs = in(1); + Node rhs = in(2); + Type t1 = lhs._type; + Type t2 = rhs._type; + + // Keep invalid operands for type checking. + if( t1 instanceof TypeInteger x && t2 instanceof TypeInteger y ) { + if( y.isConstant() && y.value()==0 ) return lhs; + if( x.isConstant() && x.value()==0 ) return new MinusNode(rhs); + } // x - (-y) is x+y - if( in(2) instanceof MinusNode minus ) - return new AddNode(in(1),minus.in(1)); + if( rhs instanceof MinusNode minus ) + return new AddNode(lhs,minus.in(1)); // (-x) - y is -(x+y) - if( in(1) instanceof MinusNode minus ) - return new MinusNode(new AddNode(minus.in(1),in(2)).peephole()); + if( lhs instanceof MinusNode minus ) + return new MinusNode(new AddNode(minus.in(1),rhs).peephole()); return null; } diff --git a/chapter13/src/test/java/com/seaofnodes/simple/Chapter04Test.java b/chapter13/src/test/java/com/seaofnodes/simple/Chapter04Test.java index 80cdb3f2..a3109ff7 100644 --- a/chapter13/src/test/java/com/seaofnodes/simple/Chapter04Test.java +++ b/chapter13/src/test/java/com/seaofnodes/simple/Chapter04Test.java @@ -51,6 +51,34 @@ public class Chapter04Test { } @Test + public void testSub0() { + Parser parser = new Parser("return arg-0;"); + StopNode ret = parser.parse(); + assertEquals("return arg;", ret.print()); + } + + @Test + public void test0Sub() { + Parser parser = new Parser("return 0-arg;"); + StopNode ret = parser.parse(); + assertEquals("return (-arg);", ret.print()); + } + + @Test + public void testSubNeg() { + Parser parser = new Parser("return 3--arg;"); + StopNode ret = parser.parse(); + assertEquals("return (arg+3);", ret.print()); + } + + @Test + public void testNegSub() { + Parser parser = new Parser("return -arg-3;"); + StopNode ret = parser.parse(); + assertEquals("return (-(arg+3));", ret.print()); + } + + @Test public void testVarArg() { Parser parser = new Parser("return arg; "); StopNode stop = parser.parse(); diff --git a/chapter13/src/test/java/com/seaofnodes/simple/Chapter12Test.java b/chapter13/src/test/java/com/seaofnodes/simple/Chapter12Test.java index 57455510..a1c7a92a 100644 --- a/chapter13/src/test/java/com/seaofnodes/simple/Chapter12Test.java +++ b/chapter13/src/test/java/com/seaofnodes/simple/Chapter12Test.java @@ -8,6 +8,13 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.fail; public class Chapter12Test { + @Test public void testSubZeroFloat() { + var stop = new Parser("flt x = arg; return 0-x;").parse().iterate(); + // Compare strings so +0.0 and -0.0 remain distinct. + assertEquals("0.0", Evaluator.evaluate(stop,0).toString()); + assertEquals("-1.0", Evaluator.evaluate(stop,1).toString()); + } + @Test public void testDeadNumericReturns() { for( String[] test : new String[][] { {"if(1) return 7; else return 2.5;", "7"}, diff --git a/chapter14/src/main/java/com/seaofnodes/simple/node/SubNode.java b/chapter14/src/main/java/com/seaofnodes/simple/node/SubNode.java index 45c4817c..1bae995b 100644 --- a/chapter14/src/main/java/com/seaofnodes/simple/node/SubNode.java +++ b/chapter14/src/main/java/com/seaofnodes/simple/node/SubNode.java @@ -38,13 +38,24 @@ public class SubNode extends Node { @Override public Node idealize() { + Node lhs = in(1); + Node rhs = in(2); + Type t1 = lhs._type; + Type t2 = rhs._type; + + // Keep invalid operands for type checking. + if( t1 instanceof TypeInteger x && t2 instanceof TypeInteger y ) { + if( y.isConstant() && y.value()==0 ) return lhs; + if( x.isConstant() && x.value()==0 ) return new MinusNode(rhs); + } + // x - (-y) is x+y - if( in(2) instanceof MinusNode minus ) - return new AddNode(in(1),minus.in(1)); + if( rhs instanceof MinusNode minus ) + return new AddNode(lhs,minus.in(1)); // (-x) - y is -(x+y) - if( in(1) instanceof MinusNode minus ) - return new MinusNode(new AddNode(minus.in(1),in(2)).peephole()); + if( lhs instanceof MinusNode minus ) + return new MinusNode(new AddNode(minus.in(1),rhs).peephole()); return null; } diff --git a/chapter14/src/test/java/com/seaofnodes/simple/Chapter04Test.java b/chapter14/src/test/java/com/seaofnodes/simple/Chapter04Test.java index 80cdb3f2..a3109ff7 100644 --- a/chapter14/src/test/java/com/seaofnodes/simple/Chapter04Test.java +++ b/chapter14/src/test/java/com/seaofnodes/simple/Chapter04Test.java @@ -51,6 +51,34 @@ public class Chapter04Test { } @Test + public void testSub0() { + Parser parser = new Parser("return arg-0;"); + StopNode ret = parser.parse(); + assertEquals("return arg;", ret.print()); + } + + @Test + public void test0Sub() { + Parser parser = new Parser("return 0-arg;"); + StopNode ret = parser.parse(); + assertEquals("return (-arg);", ret.print()); + } + + @Test + public void testSubNeg() { + Parser parser = new Parser("return 3--arg;"); + StopNode ret = parser.parse(); + assertEquals("return (arg+3);", ret.print()); + } + + @Test + public void testNegSub() { + Parser parser = new Parser("return -arg-3;"); + StopNode ret = parser.parse(); + assertEquals("return (-(arg+3));", ret.print()); + } + + @Test public void testVarArg() { Parser parser = new Parser("return arg; "); StopNode stop = parser.parse(); diff --git a/chapter14/src/test/java/com/seaofnodes/simple/Chapter12Test.java b/chapter14/src/test/java/com/seaofnodes/simple/Chapter12Test.java index c8802f4c..4eaf81df 100644 --- a/chapter14/src/test/java/com/seaofnodes/simple/Chapter12Test.java +++ b/chapter14/src/test/java/com/seaofnodes/simple/Chapter12Test.java @@ -8,6 +8,13 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.fail; public class Chapter12Test { + @Test public void testSubZeroFloat() { + var stop = new Parser("flt x = arg; return 0-x;").parse().iterate(); + // Compare strings so +0.0 and -0.0 remain distinct. + assertEquals("0.0", Evaluator.evaluate(stop,0).toString()); + assertEquals("-1.0", Evaluator.evaluate(stop,1).toString()); + } + @Test public void testDeadNumericReturns() { for( String[] test : new String[][] { {"if(1) return 7; else return 2.5;", "7"}, diff --git a/chapter15/src/main/java/com/seaofnodes/simple/node/SubNode.java b/chapter15/src/main/java/com/seaofnodes/simple/node/SubNode.java index 9eb30089..237e40ed 100644 --- a/chapter15/src/main/java/com/seaofnodes/simple/node/SubNode.java +++ b/chapter15/src/main/java/com/seaofnodes/simple/node/SubNode.java @@ -37,13 +37,24 @@ public class SubNode extends Node { @Override public Node idealize() { + Node lhs = in(1); + Node rhs = in(2); + Type t1 = lhs._type; + Type t2 = rhs._type; + + // Keep invalid operands for type checking. + if( t1 instanceof TypeInteger x && t2 instanceof TypeInteger y ) { + if( y.isConstant() && y.value()==0 ) return lhs; + if( x.isConstant() && x.value()==0 ) return new MinusNode(rhs); + } + // x - (-y) is x+y - if( in(2) instanceof MinusNode minus ) - return new AddNode(in(1),minus.in(1)); + if( rhs instanceof MinusNode minus ) + return new AddNode(lhs,minus.in(1)); // (-x) - y is -(x+y) - if( in(1) instanceof MinusNode minus ) - return new MinusNode(new AddNode(minus.in(1),in(2)).peephole()); + if( lhs instanceof MinusNode minus ) + return new MinusNode(new AddNode(minus.in(1),rhs).peephole()); return null; } diff --git a/chapter15/src/test/java/com/seaofnodes/simple/Chapter04Test.java b/chapter15/src/test/java/com/seaofnodes/simple/Chapter04Test.java index 80cdb3f2..a3109ff7 100644 --- a/chapter15/src/test/java/com/seaofnodes/simple/Chapter04Test.java +++ b/chapter15/src/test/java/com/seaofnodes/simple/Chapter04Test.java @@ -51,6 +51,34 @@ public class Chapter04Test { } @Test + public void testSub0() { + Parser parser = new Parser("return arg-0;"); + StopNode ret = parser.parse(); + assertEquals("return arg;", ret.print()); + } + + @Test + public void test0Sub() { + Parser parser = new Parser("return 0-arg;"); + StopNode ret = parser.parse(); + assertEquals("return (-arg);", ret.print()); + } + + @Test + public void testSubNeg() { + Parser parser = new Parser("return 3--arg;"); + StopNode ret = parser.parse(); + assertEquals("return (arg+3);", ret.print()); + } + + @Test + public void testNegSub() { + Parser parser = new Parser("return -arg-3;"); + StopNode ret = parser.parse(); + assertEquals("return (-(arg+3));", ret.print()); + } + + @Test public void testVarArg() { Parser parser = new Parser("return arg; "); StopNode stop = parser.parse(); diff --git a/chapter15/src/test/java/com/seaofnodes/simple/Chapter12Test.java b/chapter15/src/test/java/com/seaofnodes/simple/Chapter12Test.java index c8802f4c..4eaf81df 100644 --- a/chapter15/src/test/java/com/seaofnodes/simple/Chapter12Test.java +++ b/chapter15/src/test/java/com/seaofnodes/simple/Chapter12Test.java @@ -8,6 +8,13 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.fail; public class Chapter12Test { + @Test public void testSubZeroFloat() { + var stop = new Parser("flt x = arg; return 0-x;").parse().iterate(); + // Compare strings so +0.0 and -0.0 remain distinct. + assertEquals("0.0", Evaluator.evaluate(stop,0).toString()); + assertEquals("-1.0", Evaluator.evaluate(stop,1).toString()); + } + @Test public void testDeadNumericReturns() { for( String[] test : new String[][] { {"if(1) return 7; else return 2.5;", "7"}, diff --git a/chapter16/src/main/java/com/seaofnodes/simple/node/SubNode.java b/chapter16/src/main/java/com/seaofnodes/simple/node/SubNode.java index 9eb30089..237e40ed 100644 --- a/chapter16/src/main/java/com/seaofnodes/simple/node/SubNode.java +++ b/chapter16/src/main/java/com/seaofnodes/simple/node/SubNode.java @@ -37,13 +37,24 @@ public class SubNode extends Node { @Override public Node idealize() { + Node lhs = in(1); + Node rhs = in(2); + Type t1 = lhs._type; + Type t2 = rhs._type; + + // Keep invalid operands for type checking. + if( t1 instanceof TypeInteger x && t2 instanceof TypeInteger y ) { + if( y.isConstant() && y.value()==0 ) return lhs; + if( x.isConstant() && x.value()==0 ) return new MinusNode(rhs); + } + // x - (-y) is x+y - if( in(2) instanceof MinusNode minus ) - return new AddNode(in(1),minus.in(1)); + if( rhs instanceof MinusNode minus ) + return new AddNode(lhs,minus.in(1)); // (-x) - y is -(x+y) - if( in(1) instanceof MinusNode minus ) - return new MinusNode(new AddNode(minus.in(1),in(2)).peephole()); + if( lhs instanceof MinusNode minus ) + return new MinusNode(new AddNode(minus.in(1),rhs).peephole()); return null; } diff --git a/chapter16/src/test/java/com/seaofnodes/simple/Chapter04Test.java b/chapter16/src/test/java/com/seaofnodes/simple/Chapter04Test.java index 80cdb3f2..a3109ff7 100644 --- a/chapter16/src/test/java/com/seaofnodes/simple/Chapter04Test.java +++ b/chapter16/src/test/java/com/seaofnodes/simple/Chapter04Test.java @@ -51,6 +51,34 @@ public class Chapter04Test { } @Test + public void testSub0() { + Parser parser = new Parser("return arg-0;"); + StopNode ret = parser.parse(); + assertEquals("return arg;", ret.print()); + } + + @Test + public void test0Sub() { + Parser parser = new Parser("return 0-arg;"); + StopNode ret = parser.parse(); + assertEquals("return (-arg);", ret.print()); + } + + @Test + public void testSubNeg() { + Parser parser = new Parser("return 3--arg;"); + StopNode ret = parser.parse(); + assertEquals("return (arg+3);", ret.print()); + } + + @Test + public void testNegSub() { + Parser parser = new Parser("return -arg-3;"); + StopNode ret = parser.parse(); + assertEquals("return (-(arg+3));", ret.print()); + } + + @Test public void testVarArg() { Parser parser = new Parser("return arg; "); StopNode stop = parser.parse(); diff --git a/chapter16/src/test/java/com/seaofnodes/simple/Chapter12Test.java b/chapter16/src/test/java/com/seaofnodes/simple/Chapter12Test.java index 4db27407..c93f905d 100644 --- a/chapter16/src/test/java/com/seaofnodes/simple/Chapter12Test.java +++ b/chapter16/src/test/java/com/seaofnodes/simple/Chapter12Test.java @@ -8,6 +8,13 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.fail; public class Chapter12Test { + @Test public void testSubZeroFloat() { + var stop = new Parser("flt x = arg; return 0-x;").parse().iterate(); + // Compare strings so +0.0 and -0.0 remain distinct. + assertEquals("0.0", Evaluator.evaluate(stop,0).toString()); + assertEquals("-1.0", Evaluator.evaluate(stop,1).toString()); + } + @Test public void testDeadNumericReturns() { for( String[] test : new String[][] { {"if(1) return 7; else return 2.5;", "7"}, diff --git a/chapter17/src/main/java/com/seaofnodes/simple/node/SubNode.java b/chapter17/src/main/java/com/seaofnodes/simple/node/SubNode.java index 24499cbc..2f2a7a05 100644 --- a/chapter17/src/main/java/com/seaofnodes/simple/node/SubNode.java +++ b/chapter17/src/main/java/com/seaofnodes/simple/node/SubNode.java @@ -42,13 +42,24 @@ public class SubNode extends Node { @Override public Node idealize() { + Node lhs = in(1); + Node rhs = in(2); + Type t1 = lhs._type; + Type t2 = rhs._type; + + // Keep invalid operands for type checking. + if( t1 instanceof TypeInteger x && t2 instanceof TypeInteger y ) { + if( y.isConstant() && y.value()==0 ) return lhs; + if( x.isConstant() && x.value()==0 ) return new MinusNode(rhs); + } + // x - (-y) is x+y - if( in(2) instanceof MinusNode minus ) - return new AddNode(in(1),minus.in(1)); + if( rhs instanceof MinusNode minus ) + return new AddNode(lhs,minus.in(1)); // (-x) - y is -(x+y) - if( in(1) instanceof MinusNode minus ) - return new MinusNode(new AddNode(minus.in(1),in(2)).peephole()); + if( lhs instanceof MinusNode minus ) + return new MinusNode(new AddNode(minus.in(1),rhs).peephole()); return null; } diff --git a/chapter17/src/test/java/com/seaofnodes/simple/Chapter04Test.java b/chapter17/src/test/java/com/seaofnodes/simple/Chapter04Test.java index 0db3afde..dfd3569f 100644 --- a/chapter17/src/test/java/com/seaofnodes/simple/Chapter04Test.java +++ b/chapter17/src/test/java/com/seaofnodes/simple/Chapter04Test.java @@ -51,6 +51,34 @@ public class Chapter04Test { } @Test + public void testSub0() { + Parser parser = new Parser("return arg-0;"); + StopNode ret = parser.parse(); + assertEquals("return arg;", ret.print()); + } + + @Test + public void test0Sub() { + Parser parser = new Parser("return 0-arg;"); + StopNode ret = parser.parse(); + assertEquals("return (-arg);", ret.print()); + } + + @Test + public void testSubNeg() { + Parser parser = new Parser("return 3--arg;"); + StopNode ret = parser.parse(); + assertEquals("return (arg+3);", ret.print()); + } + + @Test + public void testNegSub() { + Parser parser = new Parser("return -arg-3;"); + StopNode ret = parser.parse(); + assertEquals("return (-(arg+3));", ret.print()); + } + + @Test public void testVarArg() { Parser parser = new Parser("return arg; "); StopNode stop = parser.parse(); diff --git a/chapter17/src/test/java/com/seaofnodes/simple/Chapter12Test.java b/chapter17/src/test/java/com/seaofnodes/simple/Chapter12Test.java index e81f9845..f7efde96 100644 --- a/chapter17/src/test/java/com/seaofnodes/simple/Chapter12Test.java +++ b/chapter17/src/test/java/com/seaofnodes/simple/Chapter12Test.java @@ -8,6 +8,13 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.fail; public class Chapter12Test { + @Test public void testSubZeroFloat() { + var stop = new Parser("flt x = arg; return 0-x;").parse().iterate(); + // Compare strings so +0.0 and -0.0 remain distinct. + assertEquals("0.0", Evaluator.evaluate(stop,0).toString()); + assertEquals("-1.0", Evaluator.evaluate(stop,1).toString()); + } + @Test public void testDeadNumericReturns() { for( String[] test : new String[][] { {"if(1) return 7; else return 2.5;", "7"}, diff --git a/chapter18/src/main/java/com/seaofnodes/simple/node/SubNode.java b/chapter18/src/main/java/com/seaofnodes/simple/node/SubNode.java index 357bbc3b..034f2fb1 100644 --- a/chapter18/src/main/java/com/seaofnodes/simple/node/SubNode.java +++ b/chapter18/src/main/java/com/seaofnodes/simple/node/SubNode.java @@ -41,13 +41,24 @@ public class SubNode extends Node { @Override public Node idealize() { + Node lhs = in(1); + Node rhs = in(2); + Type t1 = lhs._type; + Type t2 = rhs._type; + + // Keep invalid operands for type checking. + if( t1 instanceof TypeInteger x && t2 instanceof TypeInteger y ) { + if( y.isConstant() && y.value()==0 ) return lhs; + if( x.isConstant() && x.value()==0 ) return new MinusNode(rhs); + } + // x - (-y) is x+y - if( in(2) instanceof MinusNode minus ) - return new AddNode(in(1),minus.in(1)); + if( rhs instanceof MinusNode minus ) + return new AddNode(lhs,minus.in(1)); // (-x) - y is -(x+y) - if( in(1) instanceof MinusNode minus ) - return new MinusNode(new AddNode(minus.in(1),in(2)).peephole()); + if( lhs instanceof MinusNode minus ) + return new MinusNode(new AddNode(minus.in(1),rhs).peephole()); return null; } diff --git a/chapter18/src/test/java/com/seaofnodes/simple/Chapter04Test.java b/chapter18/src/test/java/com/seaofnodes/simple/Chapter04Test.java index afed67d1..d2260e1f 100644 --- a/chapter18/src/test/java/com/seaofnodes/simple/Chapter04Test.java +++ b/chapter18/src/test/java/com/seaofnodes/simple/Chapter04Test.java @@ -52,6 +52,34 @@ public class Chapter04Test { } @Test + public void testSub0() { + CodeGen code = new CodeGen("return arg-0;"); + code.parse(); + assertEquals("return arg;", code.print()); + } + + @Test + public void test0Sub() { + CodeGen code = new CodeGen("return 0-arg;"); + code.parse(); + assertEquals("return (-arg);", code.print()); + } + + @Test + public void testSubNeg() { + CodeGen code = new CodeGen("return 3--arg;"); + code.parse(); + assertEquals("return (arg+3);", code.print()); + } + + @Test + public void testNegSub() { + CodeGen code = new CodeGen("return -arg-3;"); + code.parse(); + assertEquals("return (-(arg+3));", code.print()); + } + + @Test public void testVarArg() { CodeGen code = new CodeGen("return arg; "); code.parse(); diff --git a/chapter18/src/test/java/com/seaofnodes/simple/Chapter12Test.java b/chapter18/src/test/java/com/seaofnodes/simple/Chapter12Test.java index 43345809..1e7bfc6b 100644 --- a/chapter18/src/test/java/com/seaofnodes/simple/Chapter12Test.java +++ b/chapter18/src/test/java/com/seaofnodes/simple/Chapter12Test.java @@ -8,6 +8,13 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.fail; public class Chapter12Test { + @Test public void testSubZeroFloat() { + var code = new CodeGen("flt x = arg; return 0-x;").parse().opto().typeCheck(); + // Compare strings so +0.0 and -0.0 remain distinct. + assertEquals("0.0", Eval2.eval(code,0)); + assertEquals("-1.0", Eval2.eval(code,1)); + } + @Test public void testDeadNumericReturns() { for( String[] test : new String[][] { {"if(1) return 7; else return 2.5;", "7"}, diff --git a/chapter19/src/main/java/com/seaofnodes/simple/node/SubNode.java b/chapter19/src/main/java/com/seaofnodes/simple/node/SubNode.java index 357bbc3b..034f2fb1 100644 --- a/chapter19/src/main/java/com/seaofnodes/simple/node/SubNode.java +++ b/chapter19/src/main/java/com/seaofnodes/simple/node/SubNode.java @@ -41,13 +41,24 @@ public class SubNode extends Node { @Override public Node idealize() { + Node lhs = in(1); + Node rhs = in(2); + Type t1 = lhs._type; + Type t2 = rhs._type; + + // Keep invalid operands for type checking. + if( t1 instanceof TypeInteger x && t2 instanceof TypeInteger y ) { + if( y.isConstant() && y.value()==0 ) return lhs; + if( x.isConstant() && x.value()==0 ) return new MinusNode(rhs); + } + // x - (-y) is x+y - if( in(2) instanceof MinusNode minus ) - return new AddNode(in(1),minus.in(1)); + if( rhs instanceof MinusNode minus ) + return new AddNode(lhs,minus.in(1)); // (-x) - y is -(x+y) - if( in(1) instanceof MinusNode minus ) - return new MinusNode(new AddNode(minus.in(1),in(2)).peephole()); + if( lhs instanceof MinusNode minus ) + return new MinusNode(new AddNode(minus.in(1),rhs).peephole()); return null; } diff --git a/chapter19/src/test/java/com/seaofnodes/simple/Chapter04Test.java b/chapter19/src/test/java/com/seaofnodes/simple/Chapter04Test.java index d09b1748..934e794f 100644 --- a/chapter19/src/test/java/com/seaofnodes/simple/Chapter04Test.java +++ b/chapter19/src/test/java/com/seaofnodes/simple/Chapter04Test.java @@ -52,6 +52,34 @@ public class Chapter04Test { } @Test + public void testSub0() { + CodeGen code = new CodeGen("return arg-0;"); + code.parse(); + assertEquals("return arg;", code.print()); + } + + @Test + public void test0Sub() { + CodeGen code = new CodeGen("return 0-arg;"); + code.parse(); + assertEquals("return (-arg);", code.print()); + } + + @Test + public void testSubNeg() { + CodeGen code = new CodeGen("return 3--arg;"); + code.parse(); + assertEquals("return (arg+3);", code.print()); + } + + @Test + public void testNegSub() { + CodeGen code = new CodeGen("return -arg-3;"); + code.parse(); + assertEquals("return (-(arg+3));", code.print()); + } + + @Test public void testVarArg() { CodeGen code = new CodeGen("return arg; "); code.parse(); diff --git a/chapter19/src/test/java/com/seaofnodes/simple/Chapter12Test.java b/chapter19/src/test/java/com/seaofnodes/simple/Chapter12Test.java index 43345809..1e7bfc6b 100644 --- a/chapter19/src/test/java/com/seaofnodes/simple/Chapter12Test.java +++ b/chapter19/src/test/java/com/seaofnodes/simple/Chapter12Test.java @@ -8,6 +8,13 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.fail; public class Chapter12Test { + @Test public void testSubZeroFloat() { + var code = new CodeGen("flt x = arg; return 0-x;").parse().opto().typeCheck(); + // Compare strings so +0.0 and -0.0 remain distinct. + assertEquals("0.0", Eval2.eval(code,0)); + assertEquals("-1.0", Eval2.eval(code,1)); + } + @Test public void testDeadNumericReturns() { for( String[] test : new String[][] { {"if(1) return 7; else return 2.5;", "7"}, diff --git a/chapter20/src/main/java/com/seaofnodes/simple/node/SubNode.java b/chapter20/src/main/java/com/seaofnodes/simple/node/SubNode.java index 357bbc3b..034f2fb1 100644 --- a/chapter20/src/main/java/com/seaofnodes/simple/node/SubNode.java +++ b/chapter20/src/main/java/com/seaofnodes/simple/node/SubNode.java @@ -41,13 +41,24 @@ public class SubNode extends Node { @Override public Node idealize() { + Node lhs = in(1); + Node rhs = in(2); + Type t1 = lhs._type; + Type t2 = rhs._type; + + // Keep invalid operands for type checking. + if( t1 instanceof TypeInteger x && t2 instanceof TypeInteger y ) { + if( y.isConstant() && y.value()==0 ) return lhs; + if( x.isConstant() && x.value()==0 ) return new MinusNode(rhs); + } + // x - (-y) is x+y - if( in(2) instanceof MinusNode minus ) - return new AddNode(in(1),minus.in(1)); + if( rhs instanceof MinusNode minus ) + return new AddNode(lhs,minus.in(1)); // (-x) - y is -(x+y) - if( in(1) instanceof MinusNode minus ) - return new MinusNode(new AddNode(minus.in(1),in(2)).peephole()); + if( lhs instanceof MinusNode minus ) + return new MinusNode(new AddNode(minus.in(1),rhs).peephole()); return null; } diff --git a/chapter20/src/test/java/com/seaofnodes/simple/Chapter04Test.java b/chapter20/src/test/java/com/seaofnodes/simple/Chapter04Test.java index c6199193..e5a16680 100644 --- a/chapter20/src/test/java/com/seaofnodes/simple/Chapter04Test.java +++ b/chapter20/src/test/java/com/seaofnodes/simple/Chapter04Test.java @@ -53,6 +53,34 @@ public class Chapter04Test { } @Test + public void testSub0() { + CodeGen code = new CodeGen("return arg-0;"); + code.parse(); + assertEquals("return arg;", code.print()); + } + + @Test + public void test0Sub() { + CodeGen code = new CodeGen("return 0-arg;"); + code.parse(); + assertEquals("return (-arg);", code.print()); + } + + @Test + public void testSubNeg() { + CodeGen code = new CodeGen("return 3--arg;"); + code.parse(); + assertEquals("return (arg+3);", code.print()); + } + + @Test + public void testNegSub() { + CodeGen code = new CodeGen("return -arg-3;"); + code.parse(); + assertEquals("return (-(arg+3));", code.print()); + } + + @Test public void testVarArg() { CodeGen code = new CodeGen("return arg; "); code.parse(); diff --git a/chapter20/src/test/java/com/seaofnodes/simple/Chapter12Test.java b/chapter20/src/test/java/com/seaofnodes/simple/Chapter12Test.java index 21759b78..c50be559 100644 --- a/chapter20/src/test/java/com/seaofnodes/simple/Chapter12Test.java +++ b/chapter20/src/test/java/com/seaofnodes/simple/Chapter12Test.java @@ -7,6 +7,13 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.fail; public class Chapter12Test { + @Test public void testSubZeroFloat() { + var code = new CodeGen("flt x = arg; return 0-x;").parse().opto().typeCheck(); + // Compare strings so +0.0 and -0.0 remain distinct. + assertEquals("0.0", Eval2.eval(code,0)); + assertEquals("-1.0", Eval2.eval(code,1)); + } + @Test public void testDeadNumericReturns() { for( String[] test : new String[][] { {"if(1) return 7; else return 2.5;", "7"}, diff --git a/chapter21/src/main/java/com/seaofnodes/simple/node/SubNode.java b/chapter21/src/main/java/com/seaofnodes/simple/node/SubNode.java index 51164dcc..3b3a6321 100644 --- a/chapter21/src/main/java/com/seaofnodes/simple/node/SubNode.java +++ b/chapter21/src/main/java/com/seaofnodes/simple/node/SubNode.java @@ -41,13 +41,24 @@ public class SubNode extends Node { @Override public Node idealize() { + Node lhs = in(1); + Node rhs = in(2); + Type t1 = lhs._type; + Type t2 = rhs._type; + + // Keep invalid operands for type checking. + if( t1 instanceof TypeInteger x && t2 instanceof TypeInteger y ) { + if( y.isConstant() && y.value()==0 ) return lhs; + if( x.isConstant() && x.value()==0 ) return new MinusNode(rhs); + } + // x - (-y) is x+y - if( in(2) instanceof MinusNode minus ) - return new AddNode(in(1),minus.in(1)); + if( rhs instanceof MinusNode minus ) + return new AddNode(lhs,minus.in(1)); // (-x) - y is -(x+y) - if( in(1) instanceof MinusNode minus ) - return new MinusNode(new AddNode(minus.in(1),in(2)).peephole()); + if( lhs instanceof MinusNode minus ) + return new MinusNode(new AddNode(minus.in(1),rhs).peephole()); return null; } diff --git a/chapter21/src/test/java/com/seaofnodes/simple/Chapter04Test.java b/chapter21/src/test/java/com/seaofnodes/simple/Chapter04Test.java index c6199193..e5a16680 100644 --- a/chapter21/src/test/java/com/seaofnodes/simple/Chapter04Test.java +++ b/chapter21/src/test/java/com/seaofnodes/simple/Chapter04Test.java @@ -53,6 +53,34 @@ public class Chapter04Test { } @Test + public void testSub0() { + CodeGen code = new CodeGen("return arg-0;"); + code.parse(); + assertEquals("return arg;", code.print()); + } + + @Test + public void test0Sub() { + CodeGen code = new CodeGen("return 0-arg;"); + code.parse(); + assertEquals("return (-arg);", code.print()); + } + + @Test + public void testSubNeg() { + CodeGen code = new CodeGen("return 3--arg;"); + code.parse(); + assertEquals("return (arg+3);", code.print()); + } + + @Test + public void testNegSub() { + CodeGen code = new CodeGen("return -arg-3;"); + code.parse(); + assertEquals("return (-(arg+3));", code.print()); + } + + @Test public void testVarArg() { CodeGen code = new CodeGen("return arg; "); code.parse(); diff --git a/chapter21/src/test/java/com/seaofnodes/simple/Chapter12Test.java b/chapter21/src/test/java/com/seaofnodes/simple/Chapter12Test.java index 21759b78..c50be559 100644 --- a/chapter21/src/test/java/com/seaofnodes/simple/Chapter12Test.java +++ b/chapter21/src/test/java/com/seaofnodes/simple/Chapter12Test.java @@ -7,6 +7,13 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.fail; public class Chapter12Test { + @Test public void testSubZeroFloat() { + var code = new CodeGen("flt x = arg; return 0-x;").parse().opto().typeCheck(); + // Compare strings so +0.0 and -0.0 remain distinct. + assertEquals("0.0", Eval2.eval(code,0)); + assertEquals("-1.0", Eval2.eval(code,1)); + } + @Test public void testDeadNumericReturns() { for( String[] test : new String[][] { {"if(1) return 7; else return 2.5;", "7"}, diff --git a/chapter22/src/main/java/com/seaofnodes/simple/node/SubNode.java b/chapter22/src/main/java/com/seaofnodes/simple/node/SubNode.java index 8e4f6f79..2c4fed39 100644 --- a/chapter22/src/main/java/com/seaofnodes/simple/node/SubNode.java +++ b/chapter22/src/main/java/com/seaofnodes/simple/node/SubNode.java @@ -27,13 +27,24 @@ public class SubNode extends ArithNode { @Override public Node idealize() { + Node lhs = in(1); + Node rhs = in(2); + Type t1 = lhs._type; + Type t2 = rhs._type; + + // Keep invalid operands for type checking. + if( t1 instanceof TypeInteger x && t2 instanceof TypeInteger y ) { + if( y.isConstant() && y.value()==0 ) return lhs; + if( x.isConstant() && x.value()==0 ) return new MinusNode(rhs); + } + // x - (-y) is x+y - if( in(2) instanceof MinusNode minus ) - return new AddNode(in(1),minus.in(1)); + if( rhs instanceof MinusNode minus ) + return new AddNode(lhs,minus.in(1)); // (-x) - y is -(x+y) - if( in(1) instanceof MinusNode minus ) - return new MinusNode(new AddNode(minus.in(1),in(2)).peephole()); + if( lhs instanceof MinusNode minus ) + return new MinusNode(new AddNode(minus.in(1),rhs).peephole()); return super.idealize(); } diff --git a/chapter22/src/test/java/com/seaofnodes/simple/Chapter04Test.java b/chapter22/src/test/java/com/seaofnodes/simple/Chapter04Test.java index c6199193..e5a16680 100644 --- a/chapter22/src/test/java/com/seaofnodes/simple/Chapter04Test.java +++ b/chapter22/src/test/java/com/seaofnodes/simple/Chapter04Test.java @@ -53,6 +53,34 @@ public class Chapter04Test { } @Test + public void testSub0() { + CodeGen code = new CodeGen("return arg-0;"); + code.parse(); + assertEquals("return arg;", code.print()); + } + + @Test + public void test0Sub() { + CodeGen code = new CodeGen("return 0-arg;"); + code.parse(); + assertEquals("return (-arg);", code.print()); + } + + @Test + public void testSubNeg() { + CodeGen code = new CodeGen("return 3--arg;"); + code.parse(); + assertEquals("return (arg+3);", code.print()); + } + + @Test + public void testNegSub() { + CodeGen code = new CodeGen("return -arg-3;"); + code.parse(); + assertEquals("return (-(arg+3));", code.print()); + } + + @Test public void testVarArg() { CodeGen code = new CodeGen("return arg; "); code.parse(); diff --git a/chapter22/src/test/java/com/seaofnodes/simple/Chapter12Test.java b/chapter22/src/test/java/com/seaofnodes/simple/Chapter12Test.java index 21759b78..c50be559 100644 --- a/chapter22/src/test/java/com/seaofnodes/simple/Chapter12Test.java +++ b/chapter22/src/test/java/com/seaofnodes/simple/Chapter12Test.java @@ -7,6 +7,13 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.fail; public class Chapter12Test { + @Test public void testSubZeroFloat() { + var code = new CodeGen("flt x = arg; return 0-x;").parse().opto().typeCheck(); + // Compare strings so +0.0 and -0.0 remain distinct. + assertEquals("0.0", Eval2.eval(code,0)); + assertEquals("-1.0", Eval2.eval(code,1)); + } + @Test public void testDeadNumericReturns() { for( String[] test : new String[][] { {"if(1) return 7; else return 2.5;", "7"}, diff --git a/chapter22/src/test/java/com/seaofnodes/simple/Chapter22Test.java b/chapter22/src/test/java/com/seaofnodes/simple/Chapter22Test.java index 369e365e..8d0f4c65 100644 --- a/chapter22/src/test/java/com/seaofnodes/simple/Chapter22Test.java +++ b/chapter22/src/test/java/com/seaofnodes/simple/Chapter22Test.java @@ -13,6 +13,15 @@ import org.junit.Test; import static org.junit.Assert.*; public class Chapter22Test { + @Test public void testSubZeroTypeError() { + try { + new CodeGen("return null-0;").parse().opto().typeCheck(); + fail("Subtraction must reject null even when the other operand is zero"); + } catch( Parser.ParseException e ) { + assertEquals("Cannot '-' null",e.getMessage()); + } + } + @Test public void testInfiniteReturn() { 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;"); diff --git a/chapter23/src/main/java/com/seaofnodes/simple/node/SubNode.java b/chapter23/src/main/java/com/seaofnodes/simple/node/SubNode.java index 8e4f6f79..2c4fed39 100644 --- a/chapter23/src/main/java/com/seaofnodes/simple/node/SubNode.java +++ b/chapter23/src/main/java/com/seaofnodes/simple/node/SubNode.java @@ -27,13 +27,24 @@ public class SubNode extends ArithNode { @Override public Node idealize() { + Node lhs = in(1); + Node rhs = in(2); + Type t1 = lhs._type; + Type t2 = rhs._type; + + // Keep invalid operands for type checking. + if( t1 instanceof TypeInteger x && t2 instanceof TypeInteger y ) { + if( y.isConstant() && y.value()==0 ) return lhs; + if( x.isConstant() && x.value()==0 ) return new MinusNode(rhs); + } + // x - (-y) is x+y - if( in(2) instanceof MinusNode minus ) - return new AddNode(in(1),minus.in(1)); + if( rhs instanceof MinusNode minus ) + return new AddNode(lhs,minus.in(1)); // (-x) - y is -(x+y) - if( in(1) instanceof MinusNode minus ) - return new MinusNode(new AddNode(minus.in(1),in(2)).peephole()); + if( lhs instanceof MinusNode minus ) + return new MinusNode(new AddNode(minus.in(1),rhs).peephole()); return super.idealize(); } diff --git a/chapter23/src/test/java/com/seaofnodes/simple/Chapter04Test.java b/chapter23/src/test/java/com/seaofnodes/simple/Chapter04Test.java index 1361d8b6..ce808084 100644 --- a/chapter23/src/test/java/com/seaofnodes/simple/Chapter04Test.java +++ b/chapter23/src/test/java/com/seaofnodes/simple/Chapter04Test.java @@ -53,6 +53,34 @@ public class Chapter04Test { } @Test + public void testSub0() { + CodeGen code = new CodeGen("return arg-0;"); + code.parse(); + assertEquals("return arg;", code.print()); + } + + @Test + public void test0Sub() { + CodeGen code = new CodeGen("return 0-arg;"); + code.parse(); + assertEquals("return (-arg);", code.print()); + } + + @Test + public void testSubNeg() { + CodeGen code = new CodeGen("return 3--arg;"); + code.parse(); + assertEquals("return (arg+3);", code.print()); + } + + @Test + public void testNegSub() { + CodeGen code = new CodeGen("return -arg-3;"); + code.parse(); + assertEquals("return (-(arg+3));", code.print()); + } + + @Test public void testVarArg() { CodeGen code = new CodeGen("return arg; "); code.parse(); diff --git a/chapter23/src/test/java/com/seaofnodes/simple/Chapter12Test.java b/chapter23/src/test/java/com/seaofnodes/simple/Chapter12Test.java index 21759b78..c50be559 100644 --- a/chapter23/src/test/java/com/seaofnodes/simple/Chapter12Test.java +++ b/chapter23/src/test/java/com/seaofnodes/simple/Chapter12Test.java @@ -7,6 +7,13 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.fail; public class Chapter12Test { + @Test public void testSubZeroFloat() { + var code = new CodeGen("flt x = arg; return 0-x;").parse().opto().typeCheck(); + // Compare strings so +0.0 and -0.0 remain distinct. + assertEquals("0.0", Eval2.eval(code,0)); + assertEquals("-1.0", Eval2.eval(code,1)); + } + @Test public void testDeadNumericReturns() { for( String[] test : new String[][] { {"if(1) return 7; else return 2.5;", "7"}, diff --git a/chapter23/src/test/java/com/seaofnodes/simple/Chapter22Test.java b/chapter23/src/test/java/com/seaofnodes/simple/Chapter22Test.java index a3e9a016..bca06f0c 100644 --- a/chapter23/src/test/java/com/seaofnodes/simple/Chapter22Test.java +++ b/chapter23/src/test/java/com/seaofnodes/simple/Chapter22Test.java @@ -13,6 +13,15 @@ import org.junit.Test; import static org.junit.Assert.*; public class Chapter22Test { + @Test public void testSubZeroTypeError() { + try { + new CodeGen("return null-0;").parse().opto().typeCheck(); + fail("Subtraction must reject null even when the other operand is zero"); + } catch( Parser.ParseException e ) { + assertEquals("Cannot '-' null",e.getMessage()); + } + } + @Test public void testInfiniteReturn() { 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;"); diff --git a/chapter24/src/main/java/com/seaofnodes/simple/node/SubNode.java b/chapter24/src/main/java/com/seaofnodes/simple/node/SubNode.java index 8e4f6f79..2c4fed39 100644 --- a/chapter24/src/main/java/com/seaofnodes/simple/node/SubNode.java +++ b/chapter24/src/main/java/com/seaofnodes/simple/node/SubNode.java @@ -27,13 +27,24 @@ public class SubNode extends ArithNode { @Override public Node idealize() { + Node lhs = in(1); + Node rhs = in(2); + Type t1 = lhs._type; + Type t2 = rhs._type; + + // Keep invalid operands for type checking. + if( t1 instanceof TypeInteger x && t2 instanceof TypeInteger y ) { + if( y.isConstant() && y.value()==0 ) return lhs; + if( x.isConstant() && x.value()==0 ) return new MinusNode(rhs); + } + // x - (-y) is x+y - if( in(2) instanceof MinusNode minus ) - return new AddNode(in(1),minus.in(1)); + if( rhs instanceof MinusNode minus ) + return new AddNode(lhs,minus.in(1)); // (-x) - y is -(x+y) - if( in(1) instanceof MinusNode minus ) - return new MinusNode(new AddNode(minus.in(1),in(2)).peephole()); + if( lhs instanceof MinusNode minus ) + return new MinusNode(new AddNode(minus.in(1),rhs).peephole()); return super.idealize(); } diff --git a/chapter24/src/test/java/com/seaofnodes/simple/Chapter04Test.java b/chapter24/src/test/java/com/seaofnodes/simple/Chapter04Test.java index 1361d8b6..ce808084 100644 --- a/chapter24/src/test/java/com/seaofnodes/simple/Chapter04Test.java +++ b/chapter24/src/test/java/com/seaofnodes/simple/Chapter04Test.java @@ -53,6 +53,34 @@ public class Chapter04Test { } @Test + public void testSub0() { + CodeGen code = new CodeGen("return arg-0;"); + code.parse(); + assertEquals("return arg;", code.print()); + } + + @Test + public void test0Sub() { + CodeGen code = new CodeGen("return 0-arg;"); + code.parse(); + assertEquals("return (-arg);", code.print()); + } + + @Test + public void testSubNeg() { + CodeGen code = new CodeGen("return 3--arg;"); + code.parse(); + assertEquals("return (arg+3);", code.print()); + } + + @Test + public void testNegSub() { + CodeGen code = new CodeGen("return -arg-3;"); + code.parse(); + assertEquals("return (-(arg+3));", code.print()); + } + + @Test public void testVarArg() { CodeGen code = new CodeGen("return arg; "); code.parse(); diff --git a/chapter24/src/test/java/com/seaofnodes/simple/Chapter12Test.java b/chapter24/src/test/java/com/seaofnodes/simple/Chapter12Test.java index 21759b78..c50be559 100644 --- a/chapter24/src/test/java/com/seaofnodes/simple/Chapter12Test.java +++ b/chapter24/src/test/java/com/seaofnodes/simple/Chapter12Test.java @@ -7,6 +7,13 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.fail; public class Chapter12Test { + @Test public void testSubZeroFloat() { + var code = new CodeGen("flt x = arg; return 0-x;").parse().opto().typeCheck(); + // Compare strings so +0.0 and -0.0 remain distinct. + assertEquals("0.0", Eval2.eval(code,0)); + assertEquals("-1.0", Eval2.eval(code,1)); + } + @Test public void testDeadNumericReturns() { for( String[] test : new String[][] { {"if(1) return 7; else return 2.5;", "7"}, diff --git a/chapter24/src/test/java/com/seaofnodes/simple/Chapter22Test.java b/chapter24/src/test/java/com/seaofnodes/simple/Chapter22Test.java index 7c2f4f69..e4eb03c0 100644 --- a/chapter24/src/test/java/com/seaofnodes/simple/Chapter22Test.java +++ b/chapter24/src/test/java/com/seaofnodes/simple/Chapter22Test.java @@ -13,6 +13,15 @@ import org.junit.Test; import static org.junit.Assert.*; public class Chapter22Test { + @Test public void testSubZeroTypeError() { + try { + new CodeGen("return null-0;").parse().opto().typeCheck(); + fail("Subtraction must reject null even when the other operand is zero"); + } catch( Parser.ParseException e ) { + assertEquals("Cannot '-' null",e.getMessage()); + } + } + @Test public void testInfiniteReturn() { 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;"); diff --git a/chapter25/src/main/java/com/seaofnodes/simple/node/SubNode.java b/chapter25/src/main/java/com/seaofnodes/simple/node/SubNode.java index aba1df90..8eb1f4cc 100644 --- a/chapter25/src/main/java/com/seaofnodes/simple/node/SubNode.java +++ b/chapter25/src/main/java/com/seaofnodes/simple/node/SubNode.java @@ -30,13 +30,24 @@ public class SubNode extends ArithNode { @Override public Node idealize() { + Node lhs = in(1); + Node rhs = in(2); + Type t1 = lhs._type; + Type t2 = rhs._type; + + // Keep invalid operands and unresolved numeric modes for type checking. + if( _mode==1 && t1 instanceof TypeInteger x && t2 instanceof TypeInteger y ) { + if( y.isConstant() && y.value()==0 ) return lhs; + if( x.isConstant() && x.value()==0 ) return new MinusNode(rhs); + } + // x - (-y) is x+y - if( in(2) instanceof MinusNode minus ) - return new AddNode(in(1),minus.in(1)); + if( rhs instanceof MinusNode minus ) + return new AddNode(lhs,minus.in(1)); // (-x) - y is -(x+y) - if( in(1) instanceof MinusNode minus ) - return new MinusNode(new AddNode(minus.in(1),in(2)).peephole()); + if( lhs instanceof MinusNode minus ) + return new MinusNode(new AddNode(minus.in(1),rhs).peephole()); return super.idealize(); } diff --git a/chapter25/src/test/java/com/seaofnodes/simple/Chapter04Test.java b/chapter25/src/test/java/com/seaofnodes/simple/Chapter04Test.java index eaa959cb..1132375e 100644 --- a/chapter25/src/test/java/com/seaofnodes/simple/Chapter04Test.java +++ b/chapter25/src/test/java/com/seaofnodes/simple/Chapter04Test.java @@ -53,6 +53,34 @@ public class Chapter04Test { } @Test + public void testSub0() { + CodeGen code = new CodeGen("return arg-0;"); + code.parse(); + assertEquals("return arg;", code.print()); + } + + @Test + public void test0Sub() { + CodeGen code = new CodeGen("return 0-arg;"); + code.parse(); + assertEquals("return (-arg);", code.print()); + } + + @Test + public void testSubNeg() { + CodeGen code = new CodeGen("return 3--arg;"); + code.parse(); + assertEquals("return (arg+3);", code.print()); + } + + @Test + public void testNegSub() { + CodeGen code = new CodeGen("return -arg-3;"); + code.parse(); + assertEquals("return (-(arg+3));", code.print()); + } + + @Test public void testVarArg() { CodeGen code = new CodeGen("return arg; "); code.parse(); diff --git a/chapter25/src/test/java/com/seaofnodes/simple/Chapter12Test.java b/chapter25/src/test/java/com/seaofnodes/simple/Chapter12Test.java index 4b2d48d8..0f4bb0b4 100644 --- a/chapter25/src/test/java/com/seaofnodes/simple/Chapter12Test.java +++ b/chapter25/src/test/java/com/seaofnodes/simple/Chapter12Test.java @@ -5,6 +5,13 @@ import org.junit.Test; import static org.junit.Assert.assertEquals; public class Chapter12Test { + @Test public void testSubZeroFloat() { + var code = new CodeGen("flt x = arg; return 0-x;").parse().opto().typeCheck(); + // Compare strings so +0.0 and -0.0 remain distinct. + assertEquals("0.0", Eval2.eval(code,0)); + assertEquals("-1.0", Eval2.eval(code,1)); + } + @Test public void testDeadNumericReturns() { for( String[] test : new String[][] { {"if(1) return 7; else return 2.5;", "7"}, diff --git a/chapter25/src/test/java/com/seaofnodes/simple/Chapter22Test.java b/chapter25/src/test/java/com/seaofnodes/simple/Chapter22Test.java index fde523cf..4b036e62 100644 --- a/chapter25/src/test/java/com/seaofnodes/simple/Chapter22Test.java +++ b/chapter25/src/test/java/com/seaofnodes/simple/Chapter22Test.java @@ -11,6 +11,15 @@ import org.junit.Test; import static org.junit.Assert.*; public class Chapter22Test { + @Test public void testSubZeroTypeError() { + try { + new CodeGen("return null-0;").parse().opto().typeCheck(); + fail("Subtraction must reject null even when the other operand is zero"); + } catch( Parser.ParseException e ) { + assertEquals("Cannot null - 0",e.getMessage()); + } + } + @Test public void testJig() throws IOException { diff --git a/docs/chapter-backports.md b/docs/chapter-backports.md index 0f20d0b3..3cbd93c1 100644 --- a/docs/chapter-backports.md +++ b/docs/chapter-backports.md @@ -218,6 +218,7 @@ Unresolved reproductions have been promoted to the pending queue above. | Completed work | Scope and evidence retained | |---|---| +| #254 subtraction zero identities | Require integer operands in 4-25 and resolved integer mode in 25. Preserve floating-point signed zero and subtraction diagnostics. `Chapter12Test.testSubZeroFloat` runs in 12-25; `Chapter22Test.testSubZeroTypeError` runs in 22-25. Against the original PR, the signed-zero test fails in 25 and the diagnostic test fails in 22-25. Full Make suites passed in every chapter 4-25 on 2026-09-25, including fresh `sys.o` compilation in 25. | | Short type extrema | Memory, struct and memory-pointer BOT/TOP names from 10; function-pointer names from 18. Exact types use shortcuts in ordinary, nested and HTML prints; precise types retain their details. Full Make suites in 10-20 and type/frontend suites in 21-25 passed; canonical/nested print checks passed in 10-25. | | Integer result types | Integer-op fallbacks in 4-13 and remaining unary cases through 17 retain integer types; 5's Phis meet their data-input types. Full Make suites in 4-17 passed, plus a chapter 5 snapshot check of Phi/Add types. Integer BOT starts in 4; later arithmetic already has typed fallbacks, with unresolved bimorphic modes preserved in 25. | | B14 cyclic leaf-kind equality | 23-24 backport; 25 already correct. Cyclic equality starts in 23. `TypeTest.testCyclicLeafKinds` fails before the fix; earlier interned-child equality already checks kinds. Full affected suites passed. | |
