summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--chapter04/README.md4
-rw-r--r--chapter04/src/main/java/com/seaofnodes/simple/node/SubNode.java19
-rw-r--r--chapter04/src/test/java/com/seaofnodes/simple/Chapter04Test.java28
-rw-r--r--chapter05/src/main/java/com/seaofnodes/simple/node/SubNode.java19
-rw-r--r--chapter05/src/test/java/com/seaofnodes/simple/Chapter04Test.java28
-rw-r--r--chapter06/src/main/java/com/seaofnodes/simple/node/SubNode.java19
-rw-r--r--chapter06/src/test/java/com/seaofnodes/simple/Chapter04Test.java28
-rw-r--r--chapter07/src/main/java/com/seaofnodes/simple/node/SubNode.java19
-rw-r--r--chapter07/src/test/java/com/seaofnodes/simple/Chapter04Test.java28
-rw-r--r--chapter08/src/main/java/com/seaofnodes/simple/node/SubNode.java19
-rw-r--r--chapter08/src/test/java/com/seaofnodes/simple/Chapter04Test.java28
-rw-r--r--chapter09/src/main/java/com/seaofnodes/simple/node/SubNode.java19
-rw-r--r--chapter09/src/test/java/com/seaofnodes/simple/Chapter04Test.java28
-rw-r--r--chapter10/src/main/java/com/seaofnodes/simple/node/SubNode.java19
-rw-r--r--chapter10/src/test/java/com/seaofnodes/simple/Chapter04Test.java28
-rw-r--r--chapter11/src/main/java/com/seaofnodes/simple/node/SubNode.java19
-rw-r--r--chapter11/src/test/java/com/seaofnodes/simple/Chapter04Test.java28
-rw-r--r--chapter12/src/main/java/com/seaofnodes/simple/node/SubNode.java19
-rw-r--r--chapter12/src/test/java/com/seaofnodes/simple/Chapter04Test.java28
-rw-r--r--chapter12/src/test/java/com/seaofnodes/simple/Chapter12Test.java7
-rw-r--r--chapter13/src/main/java/com/seaofnodes/simple/node/SubNode.java18
-rw-r--r--chapter13/src/test/java/com/seaofnodes/simple/Chapter04Test.java28
-rw-r--r--chapter13/src/test/java/com/seaofnodes/simple/Chapter12Test.java7
-rw-r--r--chapter14/src/main/java/com/seaofnodes/simple/node/SubNode.java19
-rw-r--r--chapter14/src/test/java/com/seaofnodes/simple/Chapter04Test.java28
-rw-r--r--chapter14/src/test/java/com/seaofnodes/simple/Chapter12Test.java7
-rw-r--r--chapter15/src/main/java/com/seaofnodes/simple/node/SubNode.java19
-rw-r--r--chapter15/src/test/java/com/seaofnodes/simple/Chapter04Test.java28
-rw-r--r--chapter15/src/test/java/com/seaofnodes/simple/Chapter12Test.java7
-rw-r--r--chapter16/src/main/java/com/seaofnodes/simple/node/SubNode.java19
-rw-r--r--chapter16/src/test/java/com/seaofnodes/simple/Chapter04Test.java28
-rw-r--r--chapter16/src/test/java/com/seaofnodes/simple/Chapter12Test.java7
-rw-r--r--chapter17/src/main/java/com/seaofnodes/simple/node/SubNode.java19
-rw-r--r--chapter17/src/test/java/com/seaofnodes/simple/Chapter04Test.java28
-rw-r--r--chapter17/src/test/java/com/seaofnodes/simple/Chapter12Test.java7
-rw-r--r--chapter18/src/main/java/com/seaofnodes/simple/node/SubNode.java19
-rw-r--r--chapter18/src/test/java/com/seaofnodes/simple/Chapter04Test.java28
-rw-r--r--chapter18/src/test/java/com/seaofnodes/simple/Chapter12Test.java7
-rw-r--r--chapter19/src/main/java/com/seaofnodes/simple/node/SubNode.java19
-rw-r--r--chapter19/src/test/java/com/seaofnodes/simple/Chapter04Test.java28
-rw-r--r--chapter19/src/test/java/com/seaofnodes/simple/Chapter12Test.java7
-rw-r--r--chapter20/src/main/java/com/seaofnodes/simple/node/SubNode.java19
-rw-r--r--chapter20/src/test/java/com/seaofnodes/simple/Chapter04Test.java28
-rw-r--r--chapter20/src/test/java/com/seaofnodes/simple/Chapter12Test.java7
-rw-r--r--chapter21/src/main/java/com/seaofnodes/simple/node/SubNode.java19
-rw-r--r--chapter21/src/test/java/com/seaofnodes/simple/Chapter04Test.java28
-rw-r--r--chapter21/src/test/java/com/seaofnodes/simple/Chapter12Test.java7
-rw-r--r--chapter22/src/main/java/com/seaofnodes/simple/node/SubNode.java19
-rw-r--r--chapter22/src/test/java/com/seaofnodes/simple/Chapter04Test.java28
-rw-r--r--chapter22/src/test/java/com/seaofnodes/simple/Chapter12Test.java7
-rw-r--r--chapter22/src/test/java/com/seaofnodes/simple/Chapter22Test.java9
-rw-r--r--chapter23/src/main/java/com/seaofnodes/simple/node/SubNode.java19
-rw-r--r--chapter23/src/test/java/com/seaofnodes/simple/Chapter04Test.java28
-rw-r--r--chapter23/src/test/java/com/seaofnodes/simple/Chapter12Test.java7
-rw-r--r--chapter23/src/test/java/com/seaofnodes/simple/Chapter22Test.java9
-rw-r--r--chapter24/src/main/java/com/seaofnodes/simple/node/SubNode.java19
-rw-r--r--chapter24/src/test/java/com/seaofnodes/simple/Chapter04Test.java28
-rw-r--r--chapter24/src/test/java/com/seaofnodes/simple/Chapter12Test.java7
-rw-r--r--chapter24/src/test/java/com/seaofnodes/simple/Chapter22Test.java9
-rw-r--r--chapter25/src/main/java/com/seaofnodes/simple/node/SubNode.java19
-rw-r--r--chapter25/src/test/java/com/seaofnodes/simple/Chapter04Test.java28
-rw-r--r--chapter25/src/test/java/com/seaofnodes/simple/Chapter12Test.java7
-rw-r--r--chapter25/src/test/java/com/seaofnodes/simple/Chapter22Test.java9
-rw-r--r--docs/chapter-backports.md1
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. |