diff options
| author | Cliff Click <cliffc@acm.org> | 2024-09-07 09:22:29 -0700 |
|---|---|---|
| committer | Thalia Archibald <thalia@archibald.dev> | 2024-09-07 10:54:48 -0700 |
| commit | eccda096c2e8e30f76e4c4a21421243159cd9026 (patch) | |
| tree | d94f7ba3f46cd2c877e000d260406d084d27fb6f /chapter14 | |
| parent | 22a129078b27d5244fac5bddd44a1b50cbb79839 (diff) | |
| download | Simple-eccda096c2e8e30f76e4c4a21421243159cd9026.tar.gz Simple-eccda096c2e8e30f76e4c4a21421243159cd9026.zip | |
README includes more design decisions for type names.
Add Or,Xor for completeness.
Diffstat (limited to 'chapter14')
7 files changed, 157 insertions, 4 deletions
diff --git a/chapter14/README.md b/chapter14/README.md index a42c37e2..2ca7d977 100644 --- a/chapter14/README.md +++ b/chapter14/README.md @@ -44,6 +44,20 @@ zero-extended on a load yielding `52501 (0x0000 0000 0000 CD15)`. Similarly, floats can be limited to IEEE754 32-bit standard format and will be rounded when assigned, and inflated to 64-bits when loaded. +The complete list of primitive types is now: +```java +int, i64; // 64-bits, matching modern hardware +// u64 // NOT implemented, as it hints at some kind of >64 bit behavior +i32, u32 // 32 bits, sign or zero extended on load +i16, u16 // 16 bits, sign or zero extended on load + i8, u8 // 8 bits, sign or zero extended on load + i1, u1 // 1 bit , sign or zero extended on load +bool // Same as u1 +flt, f64 .// IEEE 754 64-bit float, sometimes called a "double" +f32 .// IEEE 754 32-bit float +``` + + ## Type Implementation 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); |
