summaryrefslogtreecommitdiff
path: root/chapter14/src
diff options
context:
space:
mode:
Diffstat (limited to 'chapter14/src')
-rw-r--r--chapter14/src/main/java/com/seaofnodes/simple/Parser.java4
-rw-r--r--chapter14/src/main/java/com/seaofnodes/simple/node/AndNode.java6
-rw-r--r--chapter14/src/main/java/com/seaofnodes/simple/node/OrNode.java62
-rw-r--r--chapter14/src/main/java/com/seaofnodes/simple/node/XorNode.java62
-rw-r--r--chapter14/src/test/java/com/seaofnodes/simple/Chapter14Test.java11
-rw-r--r--chapter14/src/test/java/com/seaofnodes/simple/evaluator/Evaluator.java2
6 files changed, 143 insertions, 4 deletions
diff --git a/chapter14/src/main/java/com/seaofnodes/simple/Parser.java b/chapter14/src/main/java/com/seaofnodes/simple/Parser.java
index b6ff4724..bea06a19 100644
--- a/chapter14/src/main/java/com/seaofnodes/simple/Parser.java
+++ b/chapter14/src/main/java/com/seaofnodes/simple/Parser.java
@@ -516,6 +516,8 @@ public class Parser {
while( true ) {
if( false ) ;
else if( match("&") ) lhs = new AndNode(lhs,null);
+ else if( match("|") ) lhs = new OrNode(lhs,null);
+ else if( match("^") ) lhs = new XorNode(lhs,null);
else break;
lhs.setDef(2,parseComparison());
lhs = lhs.peephole();
@@ -566,8 +568,8 @@ public class Parser {
while( true ) {
if( false ) ;
else if( match("<<") ) lhs = new ShlNode(lhs,null);
- else if( match(">>") ) lhs = new SarNode(lhs,null);
else if( match(">>>")) lhs = new ShrNode(lhs,null);
+ else if( match(">>") ) lhs = new SarNode(lhs,null);
else break;
lhs.setDef(2,parseAddition());
lhs = lhs.widen().peephole();
diff --git a/chapter14/src/main/java/com/seaofnodes/simple/node/AndNode.java b/chapter14/src/main/java/com/seaofnodes/simple/node/AndNode.java
index 06e02d9a..7e4b898b 100644
--- a/chapter14/src/main/java/com/seaofnodes/simple/node/AndNode.java
+++ b/chapter14/src/main/java/com/seaofnodes/simple/node/AndNode.java
@@ -39,10 +39,10 @@ public class AndNode extends Node {
Type t1 = lhs._type;
Type t2 = rhs._type;
- // And of -1. We do not check for (0&x) because this will already
- // canonicalize to (x&0)
+ // And of -1. We do not check for (-1&x) because this will already
+ // canonicalize to (x&-1)
if( t2.isConstant() && t2 instanceof TypeInteger i && i.value()==-1 )
- return rhs;
+ return lhs;
// Move constants to RHS: con*arg becomes arg*con
if ( t1.isConstant() && !t2.isConstant() )
diff --git a/chapter14/src/main/java/com/seaofnodes/simple/node/OrNode.java b/chapter14/src/main/java/com/seaofnodes/simple/node/OrNode.java
new file mode 100644
index 00000000..24577b16
--- /dev/null
+++ b/chapter14/src/main/java/com/seaofnodes/simple/node/OrNode.java
@@ -0,0 +1,62 @@
+package com.seaofnodes.simple.node;
+
+import com.seaofnodes.simple.type.Type;
+import com.seaofnodes.simple.type.TypeInteger;
+
+import java.util.BitSet;
+
+public class OrNode extends Node {
+ public OrNode(Node lhs, Node rhs) { super(null, lhs, rhs); }
+
+ @Override public String label() { return "Or"; }
+
+ @Override public String glabel() { return "|"; }
+
+ @Override
+ StringBuilder _print1(StringBuilder sb, BitSet visited) {
+ in(1)._print0(sb.append("("), visited);
+ in(2)._print0(sb.append("|"), visited);
+ return sb.append(")");
+ }
+
+ @Override
+ public Type compute() {
+ if( in(1)._type instanceof TypeInteger i0 &&
+ in(2)._type instanceof TypeInteger i1 ) {
+ if( i0.isConstant() && i1.isConstant() )
+ return TypeInteger.constant(i0.value()|i1.value());
+ }
+ return TypeInteger.BOT;
+ }
+
+ @Override
+ public Node idealize() {
+ Node lhs = in(1);
+ Node rhs = in(2);
+ Type t1 = lhs._type;
+ Type t2 = rhs._type;
+
+ // Or of 0. We do not check for (0&x) because this will already
+ // canonicalize to (x&0)
+ if( t2.isConstant() && t2 instanceof TypeInteger i && i.value()==0 )
+ return lhs;
+
+ // Move constants to RHS: con*arg becomes arg*con
+ if ( t1.isConstant() && !t2.isConstant() )
+ return swap12();
+
+ // Do we have ((x & (phi cons)) & con) ?
+ // Do we have ((x & (phi cons)) & (phi cons)) ?
+ // Push constant up through the phi: x & (phi con0&con0 con1&con1...)
+ Node phicon = AddNode.phiCon(this,true);
+ if( phicon!=null ) return phicon;
+
+ return null;
+ }
+ @Override Node copy(Node lhs, Node rhs) { return new OrNode(lhs,rhs); }
+ @Override String err() {
+ if( !(in(1)._type instanceof TypeInteger) ) return "Cannot '|' " + in(1)._type;
+ if( !(in(2)._type instanceof TypeInteger) ) return "Cannot '|' " + in(2)._type;
+ return null;
+ }
+}
diff --git a/chapter14/src/main/java/com/seaofnodes/simple/node/XorNode.java b/chapter14/src/main/java/com/seaofnodes/simple/node/XorNode.java
new file mode 100644
index 00000000..0e235eae
--- /dev/null
+++ b/chapter14/src/main/java/com/seaofnodes/simple/node/XorNode.java
@@ -0,0 +1,62 @@
+package com.seaofnodes.simple.node;
+
+import com.seaofnodes.simple.type.Type;
+import com.seaofnodes.simple.type.TypeInteger;
+
+import java.util.BitSet;
+
+public class XorNode extends Node {
+ public XorNode(Node lhs, Node rhs) { super(null, lhs, rhs); }
+
+ @Override public String label() { return "Xor"; }
+
+ @Override public String glabel() { return "^"; }
+
+ @Override
+ StringBuilder _print1(StringBuilder sb, BitSet visited) {
+ in(1)._print0(sb.append("("), visited);
+ in(2)._print0(sb.append("^"), visited);
+ return sb.append(")");
+ }
+
+ @Override
+ public Type compute() {
+ if( in(1)._type instanceof TypeInteger i0 &&
+ in(2)._type instanceof TypeInteger i1 ) {
+ if( i0.isConstant() && i1.isConstant() )
+ return TypeInteger.constant(i0.value()^i1.value());
+ }
+ return TypeInteger.BOT;
+ }
+
+ @Override
+ public Node idealize() {
+ Node lhs = in(1);
+ Node rhs = in(2);
+ Type t1 = lhs._type;
+ Type t2 = rhs._type;
+
+ // Xor of 0. We do not check for (0&x) because this will already
+ // canonicalize to (x&0)
+ if( t2.isConstant() && t2 instanceof TypeInteger i && i.value()==0 )
+ return lhs;
+
+ // Move constants to RHS: con*arg becomes arg*con
+ if ( t1.isConstant() && !t2.isConstant() )
+ return swap12();
+
+ // Do we have ((x & (phi cons)) & con) ?
+ // Do we have ((x & (phi cons)) & (phi cons)) ?
+ // Push constant up through the phi: x & (phi con0&con0 con1&con1...)
+ Node phicon = AddNode.phiCon(this,true);
+ if( phicon!=null ) return phicon;
+
+ return null;
+ }
+ @Override Node copy(Node lhs, Node rhs) { return new XorNode(lhs,rhs); }
+ @Override String err() {
+ if( !(in(1)._type instanceof TypeInteger) ) return "Cannot '^' " + in(1)._type;
+ if( !(in(2)._type instanceof TypeInteger) ) return "Cannot '^' " + in(2)._type;
+ return null;
+ }
+}
diff --git a/chapter14/src/test/java/com/seaofnodes/simple/Chapter14Test.java b/chapter14/src/test/java/com/seaofnodes/simple/Chapter14Test.java
index 962b8e4d..5f7cf954 100644
--- a/chapter14/src/test/java/com/seaofnodes/simple/Chapter14Test.java
+++ b/chapter14/src/test/java/com/seaofnodes/simple/Chapter14Test.java
@@ -142,6 +142,17 @@ return c; //
}
@Test
+ public void testOr() {
+ Parser parser = new Parser(
+"""
+return (arg | 123 ^ 456) >>> 1;
+""");
+ StopNode stop = parser.parse(false).iterate(false);
+ assertEquals("return (((arg|123)^456)>>>1);", stop.toString());
+ assertEquals(217L, Evaluator.evaluate(stop, 0));
+ }
+
+ @Test
public void testMaskFloat() {
Parser parser = new Parser(
"""
diff --git a/chapter14/src/test/java/com/seaofnodes/simple/evaluator/Evaluator.java b/chapter14/src/test/java/com/seaofnodes/simple/evaluator/Evaluator.java
index 67e9deac..31a14c05 100644
--- a/chapter14/src/test/java/com/seaofnodes/simple/evaluator/Evaluator.java
+++ b/chapter14/src/test/java/com/seaofnodes/simple/evaluator/Evaluator.java
@@ -154,6 +154,8 @@ public class Evaluator {
case ShrNode shr -> vall(shr.in(1)) >>> vall(shr.in(2));
case SarNode sar -> vall(sar.in(1)) >> vall(sar.in(2));
case AndNode and -> vall(and.in(1)) & vall(and.in(2));
+ case OrNode or -> vall(or .in(1)) | vall(or .in(2));
+ case XorNode xor -> vall(xor.in(1)) ^ vall(xor.in(2));
case CastNode cast -> val(cast.in(1));
case ToFloatNode cast -> (double)vall(cast.in(1));
case LoadNode load -> load(load);