diff options
| author | Cliff Click <cliffc@acm.org> | 2025-05-07 11:28:33 -0700 |
|---|---|---|
| committer | Cliff Click <cliffc@acm.org> | 2025-05-07 11:28:33 -0700 |
| commit | 518d5c60f714c7d5f58c3da484368cbf26e9bfd5 (patch) | |
| tree | 0884a45436707169b72df5f8e321c0962f97275a /chapter22/src/main | |
| parent | 6852981f48f55b245fae6229c2930c3d09d9e45e (diff) | |
| download | Simple-518d5c60f714c7d5f58c3da484368cbf26e9bfd5.tar.gz Simple-518d5c60f714c7d5f58c3da484368cbf26e9bfd5.zip | |
Fix missing up/down phi peep.
Slight shuffling of sys.smp triggers different worklist order, triggers missing peep.
The pull-down phi op needs a reverse peep when more constants appear.
CodeGen driver can be called repeatedly.
Rename LogicalNode to ArithNode; use it on Add,Sub,MulDiv also.
Bugfix jump in loop that both exits on one path and enters a deeper loop on other.
Diffstat (limited to 'chapter22/src/main')
18 files changed, 213 insertions, 270 deletions
diff --git a/chapter22/src/main/java/com/seaofnodes/simple/codegen/CodeGen.java b/chapter22/src/main/java/com/seaofnodes/simple/codegen/CodeGen.java index 8a28dacc..c3e211ea 100644 --- a/chapter22/src/main/java/com/seaofnodes/simple/codegen/CodeGen.java +++ b/chapter22/src/main/java/com/seaofnodes/simple/codegen/CodeGen.java @@ -21,7 +21,7 @@ public class CodeGen { Opto, // Run ideal optimizations TypeCheck, // Last check for bad programs LoopTree, // Build a loop tree; break infinite loops - InstSelect, // Convert to target hardware nodes + Select, // Convert to target hardware nodes Schedule, // Global schedule (code motion) nodes LocalSched, // Local schedule RegAlloc, // Register allocation @@ -55,14 +55,15 @@ public class CodeGen { public CodeGen driver( Phase phase ) { return driver(phase,null,null); } public CodeGen driver( Phase phase, String cpu, String callingConv ) { if( _phase==null ) parse(); - if( _phase.ordinal() < phase.ordinal() ) opto(); - if( _phase.ordinal() < phase.ordinal() ) typeCheck(); - if( _phase.ordinal() < phase.ordinal() ) loopTree(); - if( _phase.ordinal() < phase.ordinal() && cpu != null ) instSelect(cpu,callingConv); - if( _phase.ordinal() < phase.ordinal() ) GCM(); - if( _phase.ordinal() < phase.ordinal() ) localSched(); - if( _phase.ordinal() < phase.ordinal() ) regAlloc(); - if( _phase.ordinal() < phase.ordinal() ) encode(); + int p1 = phase.ordinal(); + if( _phase.ordinal() < p1 && _phase.ordinal() < Phase.Opto .ordinal() ) opto(); + if( _phase.ordinal() < p1 && _phase.ordinal() < Phase.TypeCheck .ordinal() ) typeCheck(); + if( _phase.ordinal() < p1 && _phase.ordinal() < Phase.LoopTree .ordinal() ) loopTree(); + if( _phase.ordinal() < p1 && _phase.ordinal() < Phase.Select .ordinal() && cpu != null ) instSelect(cpu,callingConv); + if( _phase.ordinal() < p1 && _phase.ordinal() < Phase.Schedule .ordinal() ) GCM(); + if( _phase.ordinal() < p1 && _phase.ordinal() < Phase.LocalSched.ordinal() ) localSched(); + if( _phase.ordinal() < p1 && _phase.ordinal() < Phase.RegAlloc .ordinal() ) regAlloc(); + if( _phase.ordinal() < p1 && _phase.ordinal() < Phase.Encoding .ordinal() ) encode(); return this; } @@ -247,7 +248,7 @@ public class CodeGen { public CodeGen instSelect( String cpu, String callingConv ) { return instSelect(cpu,callingConv,PORTS); } public CodeGen instSelect( String cpu, String callingConv, String base ) { assert _phase.ordinal() == Phase.LoopTree.ordinal(); - _phase = Phase.InstSelect; + _phase = Phase.Select; _callingConv = callingConv; @@ -339,7 +340,7 @@ public class CodeGen { // Global schedule (code motion) nodes public CodeGen GCM() { return GCM(false); } public CodeGen GCM( boolean show) { - assert _phase.ordinal() <= Phase.InstSelect.ordinal(); + assert _phase.ordinal() <= Phase.Select.ordinal(); _phase = Phase.Schedule; long t0 = System.currentTimeMillis(); diff --git a/chapter22/src/main/java/com/seaofnodes/simple/codegen/Encoding.java b/chapter22/src/main/java/com/seaofnodes/simple/codegen/Encoding.java index 6efb84dd..f4b2ab69 100644 --- a/chapter22/src/main/java/com/seaofnodes/simple/codegen/Encoding.java +++ b/chapter22/src/main/java/com/seaofnodes/simple/codegen/Encoding.java @@ -299,7 +299,7 @@ public class Encoding { private static boolean forwardsEmptyScan( CFGNode c, int bld ) { if( c.nOuts()!=1 || c.loopDepth()!=bld ) return false; return c.uctrl() instanceof RegionNode cfg && - (cfg instanceof LoopNode || forwardsEmptyScan(cfg,bld)); + ((cfg instanceof LoopNode && cfg._ltree==c._ltree) || forwardsEmptyScan(cfg,bld)); } // Is the CFG from "next" to the end empty? This means jumping to "next" diff --git a/chapter22/src/main/java/com/seaofnodes/simple/node/AddNode.java b/chapter22/src/main/java/com/seaofnodes/simple/node/AddNode.java index dd128e76..0f472829 100644 --- a/chapter22/src/main/java/com/seaofnodes/simple/node/AddNode.java +++ b/chapter22/src/main/java/com/seaofnodes/simple/node/AddNode.java @@ -7,42 +7,21 @@ import java.util.BitSet; import static com.seaofnodes.simple.Parser.con; -public class AddNode extends Node { +public class AddNode extends ArithNode { public AddNode(Node lhs, Node rhs) { super(null, lhs, rhs); } @Override public String label() { return "Add"; } - - @Override public String glabel() { return "+"; } - - @Override - public 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() { - Type t1 = in(1)._type, t2 = in(2)._type; - if( t1.isHigh() || t2.isHigh() ) - return TypeInteger.TOP; - if( t1 instanceof TypeInteger i1 && - t2 instanceof TypeInteger i2 ) { - if (i1.isConstant() && i2.isConstant()) - return TypeInteger.constant(i1.value()+i2.value()); - // Fold ranges like {0-1} + {2-3} into {2-4}. - if( !overflow(i1._min,i2._min) && - !overflow(i1._max,i2._max) ) - return TypeInteger.make(i1._min+i2._min,i1._max+i2._max); - } + @Override public String op() { return "+"; } + + @Override long doOp( long x, long y ) { return x + y; } + @Override TypeInteger doOp(TypeInteger x, TypeInteger y) { + // Fold ranges like {0-1} + {2-3} into {2-4}. + if( !overflow(x._min,y._min) && + !overflow(x._max,y._max) ) + return TypeInteger.make(x._min+y._min,x._max+y._max); return TypeInteger.BOT; } - static boolean overflow( long x, long y ) { - if( (x ^ y ) < 0 ) return false; // unequal signs, never overflow - return (x ^ (x + y)) < 0; // sum has unequal signs, so overflow - } @Override public Node idealize () { Node lhs = in(1); @@ -113,7 +92,7 @@ public class AddNode extends Node { if( spine_cmp(lhs.in(2),rhs,this) ) return new AddNode(new AddNode(lhs.in(1),rhs).peephole(),lhs.in(2)); - return null; + return super.idealize(); } // Rotation is only valid for associative ops, e.g. Add, Mul, And, Or, Xor. @@ -190,10 +169,4 @@ public class AddNode extends Node { @Override Node copy(Node lhs, Node rhs) { return new AddNode(lhs,rhs); } @Override Node copyF() { return new AddFNode(null,null); } - @Override public Parser.ParseException err() { - if( in(1)._type.isHigh() || in(2)._type.isHigh() ) return null; - if( !(in(1)._type instanceof TypeInteger) ) return Parser.error("Cannot '"+label()+"' " + in(1)._type,null); - if( !(in(2)._type instanceof TypeInteger) ) return Parser.error("Cannot '"+label()+"' " + in(2)._type,null); - return null; - } } diff --git a/chapter22/src/main/java/com/seaofnodes/simple/node/AndNode.java b/chapter22/src/main/java/com/seaofnodes/simple/node/AndNode.java index 3cfcbda3..70b57d6d 100644 --- a/chapter22/src/main/java/com/seaofnodes/simple/node/AndNode.java +++ b/chapter22/src/main/java/com/seaofnodes/simple/node/AndNode.java @@ -4,30 +4,18 @@ import com.seaofnodes.simple.Parser; import com.seaofnodes.simple.type.Type; import com.seaofnodes.simple.type.TypeInteger; -import java.util.BitSet; - -public class AndNode extends LogicalNode { +public class AndNode extends ArithNode { public AndNode(Parser.Lexer loc, Node lhs, Node rhs) { super(loc, lhs, rhs); } @Override public String label() { return "And"; } @Override public String op() { return "&"; } - @Override public String glabel() { return "&"; } - @Override - public Type compute() { - Type t1 = in(1)._type, t2 = in(2)._type; - if( t1.isHigh() || t2.isHigh() ) - return TypeInteger.TOP; - if( t1 instanceof TypeInteger i0 && - t2 instanceof TypeInteger i1 ) { - if( i0.isConstant() && i1.isConstant() ) - return TypeInteger.constant(i0.value()&i1.value()); - // Sharpen allowed bits if either value is narrowed - long mask = i0.mask() & i1.mask(); - return mask < 0 ? TypeInteger.BOT : TypeInteger.make(0,mask); - } - return TypeInteger.BOT; + @Override long doOp( long x, long y ) { return x & y; } + @Override TypeInteger doOp(TypeInteger x, TypeInteger y) { + // Sharpen allowed bits if either value is narrowed + long mask = x.mask() & y.mask(); + return mask < 0 ? TypeInteger.BOT : TypeInteger.make(0,mask); } @Override @@ -53,9 +41,10 @@ public class AndNode extends LogicalNode { // 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; + if( phicon!=null ) + return phicon; - return null; + return super.idealize(); } @Override Node copy(Node lhs, Node rhs) { return new AndNode(_loc,lhs,rhs); } } diff --git a/chapter22/src/main/java/com/seaofnodes/simple/node/ArithNode.java b/chapter22/src/main/java/com/seaofnodes/simple/node/ArithNode.java new file mode 100644 index 00000000..3e376418 --- /dev/null +++ b/chapter22/src/main/java/com/seaofnodes/simple/node/ArithNode.java @@ -0,0 +1,98 @@ +package com.seaofnodes.simple.node; + +import com.seaofnodes.simple.Parser; +import com.seaofnodes.simple.Utils; +import com.seaofnodes.simple.type.Type; +import com.seaofnodes.simple.type.TypeInteger; +import java.util.BitSet; + +public abstract class ArithNode extends Node { + // Source location for late reported errors + Parser.Lexer _loc; + + public ArithNode( Parser.Lexer loc, Node lhs, Node rhs) { super(null, lhs, rhs); _loc = loc; } + @Override public String glabel() { return op(); } + abstract String op(); + + @Override + public StringBuilder _print1(StringBuilder sb, BitSet visited) { + in(1)._print0(sb.append("("), visited); + in(2)._print0(sb.append(op()), visited); + return sb.append(")"); + } + + abstract long doOp(long x, long y); + abstract TypeInteger doOp(TypeInteger x, TypeInteger y); + + // Generic airthmetic op math: high returns high; low returns low; 2 + // constants fold; only 2 non-constants call specialized math. + @Override + public final TypeInteger compute() { + Type t1 = in(1)._type, t2 = in(2)._type; + if( t1.isHigh() || t2.isHigh() ) + return TypeInteger.TOP; + if( t1 instanceof TypeInteger x && + t2 instanceof TypeInteger y ) + return x.isConstant() && y.isConstant() + ? con(x,y) + : doOp(x,y); + return TypeInteger.BOT; + } + + private TypeInteger con( Type t1, Type t2 ) { + return TypeInteger.constant( doOp( ((TypeInteger)t1).value(), ((TypeInteger)t2).value()) ); + } + + // Check for "op(Phi(con,x),Phi(con,y))" and push-up through the Phi. + // Note that this is the exact reverse of Phi pulling a common op down + // to reduce total op-count. We don't get in an endless push-up + // push-down peephole cycle because the constants all fold first. + // Returns "Phi(op(con,con),op(x,y))". + + // This check is slightly different from the + + // Expected to be called after other ideal checks are done. + @Override public Node idealize() { + if( in(1) instanceof PhiNode lhs && + in(2) instanceof PhiNode rhs && + lhs.nIns() >= 2 && !lhs.inProgress() && + lhs.region()==rhs.region() ) { + // Profit check: only 1 instance of `this` will remain, all the + // others will fold to constants. + int cnt=0; + for( int i=1; i<lhs.nIns(); i++ ) + if( isCon(lhs,rhs,i) ) + cnt++; + if( lhs.nIns()-1 - cnt <= 1 ) { + // Profit! Push up-phi and fold + Node[] ns = new Node[lhs.nIns()]; + ns[0] = lhs.in(0); + for( int i=1; i<lhs.nIns(); i++ ) { + ns[i] = isCon(lhs,rhs,i) + ? new ConstantNode(con(lhs.in(i)._type, rhs.in(i)._type)).peephole() + : copy(lhs.in(i), rhs.in(i)).peephole(); + } + String label = lhs._label==rhs._label ? lhs._label : lhs._label + rhs._label; + return new PhiNode(label,lhs._declaredType,ns).peephole(); + } + } + return null; + } + + static boolean isCon( PhiNode lhs, PhiNode rhs, int i ) { + return lhs.in(i)._type.isConstant() && rhs.in(i)._type.isConstant(); + } + + + static boolean overflow( long x, long y ) { + if( (x ^ y ) < 0 ) return false; // unequal signs, never overflow + return (x ^ (x + y)) < 0; // sum has unequal signs, so overflow + } + + @Override public Parser.ParseException err() { + if( in(1)._type.isHigh() || in(2)._type.isHigh() ) return null; + if( !(in(1)._type instanceof TypeInteger) ) return Parser.error("Cannot '"+op()+"' " + in(1)._type,_loc); + if( !(in(2)._type instanceof TypeInteger) ) return Parser.error("Cannot '"+op()+"' " + in(2)._type,_loc); + return null; + } +} diff --git a/chapter22/src/main/java/com/seaofnodes/simple/node/DivNode.java b/chapter22/src/main/java/com/seaofnodes/simple/node/DivNode.java index 41518311..0de1c946 100644 --- a/chapter22/src/main/java/com/seaofnodes/simple/node/DivNode.java +++ b/chapter22/src/main/java/com/seaofnodes/simple/node/DivNode.java @@ -4,32 +4,14 @@ import com.seaofnodes.simple.type.Type; import com.seaofnodes.simple.type.TypeInteger; import java.util.BitSet; -public class DivNode extends Node { +public class DivNode extends ArithNode { public DivNode(Node lhs, Node rhs) { super(null, lhs, rhs); } @Override public String label() { return "Div"; } + @Override public String op() { return "//"; } - @Override public String glabel() { return "//"; } - - @Override - public 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() { - Type t1 = in(1)._type, t2 = in(2)._type; - if( t1.isHigh() || t2.isHigh() ) - return TypeInteger.TOP; - if( t1 instanceof TypeInteger i1 && - t2 instanceof TypeInteger i2 ) { - if (i1.isConstant() && i2.isConstant()) - return i2.value() == 0 - ? TypeInteger.ZERO - : TypeInteger.constant(i1.value()/i2.value()); - } + @Override long doOp( long x, long y ) { return y==0 ? 0 : x / y; } + @Override TypeInteger doOp(TypeInteger x, TypeInteger y) { return TypeInteger.BOT; } @@ -38,7 +20,7 @@ public class DivNode extends Node { // Div of 1. if( in(2)._type == TypeInteger.TRUE ) return in(1); - return null; + return super.idealize(); } @Override Node copy(Node lhs, Node rhs) { return new DivNode(lhs,rhs); } diff --git a/chapter22/src/main/java/com/seaofnodes/simple/node/LogicalNode.java b/chapter22/src/main/java/com/seaofnodes/simple/node/LogicalNode.java deleted file mode 100644 index e8552789..00000000 --- a/chapter22/src/main/java/com/seaofnodes/simple/node/LogicalNode.java +++ /dev/null @@ -1,29 +0,0 @@ -package com.seaofnodes.simple.node; - -import com.seaofnodes.simple.Parser; -import com.seaofnodes.simple.type.Type; -import com.seaofnodes.simple.type.TypeInteger; -import java.util.BitSet; - -public abstract class LogicalNode extends Node { - // Source location for late reported errors - Parser.Lexer _loc; - - public LogicalNode(Parser.Lexer loc, Node lhs, Node rhs) { super(null, lhs, rhs); _loc = loc; } - abstract String op(); - - @Override - public StringBuilder _print1(StringBuilder sb, BitSet visited) { - in(1)._print0(sb.append("("), visited); - in(2)._print0(sb.append(op()), visited); - return sb.append(")"); - } - - - @Override public Parser.ParseException err() { - if( in(1)._type.isHigh() || in(2)._type.isHigh() ) return null; - if( !(in(1)._type instanceof TypeInteger) ) return Parser.error("Cannot '"+op()+"' " + in(1)._type,_loc); - if( !(in(2)._type instanceof TypeInteger) ) return Parser.error("Cannot '"+op()+"' " + in(2)._type,_loc); - return null; - } -} diff --git a/chapter22/src/main/java/com/seaofnodes/simple/node/MinusNode.java b/chapter22/src/main/java/com/seaofnodes/simple/node/MinusNode.java index e06e0c69..059d0d00 100644 --- a/chapter22/src/main/java/com/seaofnodes/simple/node/MinusNode.java +++ b/chapter22/src/main/java/com/seaofnodes/simple/node/MinusNode.java @@ -23,7 +23,7 @@ public class MinusNode extends Node { public Type compute() { if( in(1)._type.isHigh() ) return TypeInteger.TOP; if( in(1)._type instanceof TypeInteger i0 && - !(i0==TypeInteger.BOT || i0._min == Long.MIN_VALUE || i0._max == Long.MIN_VALUE) ) + i0._min != Long.MIN_VALUE && i0._max != Long.MIN_VALUE ) return TypeInteger.make(-i0._max,-i0._min); return TypeInteger.BOT; } diff --git a/chapter22/src/main/java/com/seaofnodes/simple/node/MulNode.java b/chapter22/src/main/java/com/seaofnodes/simple/node/MulNode.java index c1a5a524..debc2c56 100644 --- a/chapter22/src/main/java/com/seaofnodes/simple/node/MulNode.java +++ b/chapter22/src/main/java/com/seaofnodes/simple/node/MulNode.java @@ -5,32 +5,14 @@ import com.seaofnodes.simple.type.Type; import com.seaofnodes.simple.type.TypeInteger; import java.util.BitSet; -public class MulNode extends Node { +public class MulNode extends ArithNode { public MulNode(Node lhs, Node rhs) { super(null, lhs, rhs); } @Override public String label() { return "Mul"; } + @Override public String op() { return "*"; } - @Override public String glabel() { return "*"; } - - @Override - public 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() { - Type t1 = in(1)._type, t2 = in(2)._type; - if( t1.isHigh() || t2.isHigh() ) - return TypeInteger.TOP; - if( t1 instanceof TypeInteger i1 && - t2 instanceof TypeInteger i2 ) { - if( i1==TypeInteger.ZERO || i2==TypeInteger.ZERO) - return TypeInteger.ZERO; - if (i1.isConstant() && i2.isConstant()) - return TypeInteger.constant(i1.value()*i2.value()); - } + @Override long doOp( long x, long y ) { return x * y; } + @Override TypeInteger doOp(TypeInteger x, TypeInteger y) { return TypeInteger.BOT; } @@ -74,14 +56,8 @@ public class MulNode extends Node { Node phicon = AddNode.phiCon(this,true); if( phicon!=null ) return phicon; - return null; + return super.idealize(); } @Override Node copy(Node lhs, Node rhs) { return new MulNode(lhs,rhs); } @Override Node copyF() { return new MulFNode(null,null); } - @Override public Parser.ParseException err() { - if( in(1)._type.isHigh() || in(2)._type.isHigh() ) return null; - if( !(in(1)._type instanceof TypeInteger) ) return Parser.error("Cannot '"+label()+"' " + in(1)._type.glb(false),null); - if( !(in(2)._type instanceof TypeInteger) ) return Parser.error("Cannot '"+label()+"' " + in(2)._type.glb(false),null); - return null; - } } diff --git a/chapter22/src/main/java/com/seaofnodes/simple/node/Node.java b/chapter22/src/main/java/com/seaofnodes/simple/node/Node.java index 39010f3d..eadb984a 100644 --- a/chapter22/src/main/java/com/seaofnodes/simple/node/Node.java +++ b/chapter22/src/main/java/com/seaofnodes/simple/node/Node.java @@ -66,7 +66,7 @@ public abstract class Node implements Cloneable { // Make a Node using the existing arrays of nodes. // Used by any pass rewriting all Node classes but not the edges. Node( Node n ) { - assert CodeGen.CODE._phase.ordinal() >= CodeGen.Phase.InstSelect.ordinal(); + assert CodeGen.CODE._phase.ordinal() >= CodeGen.Phase.Select.ordinal(); _nid = CODE.getUID(); // allocate unique dense ID _inputs = new Ary<>(n==null ? new Node[0] : n._inputs.asAry()); _outputs = new Ary<>(Node.class); diff --git a/chapter22/src/main/java/com/seaofnodes/simple/node/OrNode.java b/chapter22/src/main/java/com/seaofnodes/simple/node/OrNode.java index 9b03dc5d..ac0d8454 100644 --- a/chapter22/src/main/java/com/seaofnodes/simple/node/OrNode.java +++ b/chapter22/src/main/java/com/seaofnodes/simple/node/OrNode.java @@ -4,26 +4,16 @@ import com.seaofnodes.simple.Parser; import com.seaofnodes.simple.type.Type; import com.seaofnodes.simple.type.TypeInteger; -import java.util.BitSet; - -public class OrNode extends LogicalNode { +public class OrNode extends ArithNode { public OrNode(Parser.Lexer loc, Node lhs, Node rhs) { super(loc, lhs, rhs); } @Override public String label() { return "Or"; } @Override public String op() { return "|"; } - @Override public String glabel() { return "|"; } - @Override - public Type compute() { - Type t1 = in(1)._type, t2 = in(2)._type; - if( t1.isHigh() || t2.isHigh() ) - return TypeInteger.TOP; - if( t1 instanceof TypeInteger i0 && - t2 instanceof TypeInteger i1 ) { - if( i0.isConstant() && i1.isConstant() ) - return TypeInteger.constant(i0.value()|i1.value()); - } + + @Override long doOp( long x, long y ) { return x | y; } + @Override TypeInteger doOp(TypeInteger x, TypeInteger y) { return TypeInteger.BOT; } @@ -49,7 +39,7 @@ public class OrNode extends LogicalNode { Node phicon = AddNode.phiCon(this,true); if( phicon!=null ) return phicon; - return null; + return super.idealize(); } @Override Node copy(Node lhs, Node rhs) { return new OrNode(_loc,lhs,rhs); } } diff --git a/chapter22/src/main/java/com/seaofnodes/simple/node/SarNode.java b/chapter22/src/main/java/com/seaofnodes/simple/node/SarNode.java index 4a71ec06..ee15fa65 100644 --- a/chapter22/src/main/java/com/seaofnodes/simple/node/SarNode.java +++ b/chapter22/src/main/java/com/seaofnodes/simple/node/SarNode.java @@ -3,31 +3,19 @@ package com.seaofnodes.simple.node; import com.seaofnodes.simple.Parser; import com.seaofnodes.simple.type.Type; import com.seaofnodes.simple.type.TypeInteger; -import java.util.BitSet; -public class SarNode extends LogicalNode { +public class SarNode extends ArithNode { public SarNode(Parser.Lexer loc, Node lhs, Node rhs) { super(loc, lhs, rhs); } @Override public String label() { return "Sar"; } @Override public String op() { return ">>"; } - @Override public String glabel() { return ">>"; } - @Override - public Type compute() { - Type t1 = in(1)._type, t2 = in(2)._type; - if( t1.isHigh() || t2.isHigh() ) - return TypeInteger.TOP; - if (t1 instanceof TypeInteger i0 && - t2 instanceof TypeInteger i1) { - if( i0 == TypeInteger.ZERO ) - return TypeInteger.ZERO; - if( i0.isConstant() && i1.isConstant() ) - return TypeInteger.constant(i0.value()>>i1.value()); - if( i1.isConstant() ) { - int log = (int)i1.value(); - return TypeInteger.make(-1L<<(63-log),(1L<<(63-log))-1); - } + @Override long doOp( long x, long y ) { return x >> y; } + @Override TypeInteger doOp( TypeInteger x, TypeInteger y ) { + if( y.isConstant() ) { + int log = (int)y.value(); + return TypeInteger.make(-1L<<(63-log),(1L<<(63-log))-1); } return TypeInteger.BOT; } @@ -44,7 +32,7 @@ public class SarNode extends LogicalNode { // TODO: x >> 3 >> (y ? 1 : 2) ==> x >> (y ? 4 : 5) - return null; + return super.idealize(); } @Override Node copy(Node lhs, Node rhs) { return new SarNode(_loc,lhs,rhs); } } diff --git a/chapter22/src/main/java/com/seaofnodes/simple/node/ShlNode.java b/chapter22/src/main/java/com/seaofnodes/simple/node/ShlNode.java index 39a2698a..2557bf6b 100644 --- a/chapter22/src/main/java/com/seaofnodes/simple/node/ShlNode.java +++ b/chapter22/src/main/java/com/seaofnodes/simple/node/ShlNode.java @@ -3,34 +3,24 @@ package com.seaofnodes.simple.node; import com.seaofnodes.simple.Parser; import com.seaofnodes.simple.type.Type; import com.seaofnodes.simple.type.TypeInteger; -import java.util.BitSet; -public class ShlNode extends LogicalNode { +public class ShlNode extends ArithNode { public ShlNode(Parser.Lexer loc, Node lhs, Node rhs) { super(loc, lhs, rhs); } @Override public String label() { return "Shl"; } @Override public String op() { return "<<"; } - @Override public String glabel() { return "<<"; } - @Override - public Type compute() { - Type t1 = in(1)._type, t2 = in(2)._type; - if( t1.isHigh() || t2.isHigh() ) - return TypeInteger.TOP; - if (t1 instanceof TypeInteger i0 && - t2 instanceof TypeInteger i1 ) { - if( i0 == TypeInteger.ZERO ) - return TypeInteger.ZERO; - if( i1.isConstant() ) { - int shf = (int)i1.value(); - if( i0.isConstant() ) - return TypeInteger.constant(i0.value()<<shf); - // If no overflow, shift endpoints - if( !(((i0._min<<shf)>>shf) != i0._min || - ((i0._max<<shf)>>shf) != i0._max ) ) - return TypeInteger.make(i0._min<<shf,i0._max<<shf); - } + @Override long doOp( long x, long y ) { return x << y; } + @Override TypeInteger doOp( TypeInteger x, TypeInteger y ) { + if( x == TypeInteger.ZERO ) + return TypeInteger.ZERO; + if( y.isConstant() ) { + int shf = (int)y.value(); + // If no overflow, shift endpoints + if( !(((x._min<<shf)>>shf) != x._min || + ((x._max<<shf)>>shf) != x._max ) ) + return TypeInteger.make(x._min<<shf,x._max<<shf); } return TypeInteger.BOT; } @@ -54,7 +44,7 @@ public class ShlNode extends LogicalNode { // TODO: x << 3 << (y ? 1 : 2) ==> x << (y ? 4 : 5) - return null; + return super.idealize(); } @Override Node copy(Node lhs, Node rhs) { return new ShlNode(_loc,lhs,rhs); } } diff --git a/chapter22/src/main/java/com/seaofnodes/simple/node/ShrNode.java b/chapter22/src/main/java/com/seaofnodes/simple/node/ShrNode.java index 789fb8a8..269f6b7f 100644 --- a/chapter22/src/main/java/com/seaofnodes/simple/node/ShrNode.java +++ b/chapter22/src/main/java/com/seaofnodes/simple/node/ShrNode.java @@ -3,29 +3,17 @@ package com.seaofnodes.simple.node; import com.seaofnodes.simple.Parser; import com.seaofnodes.simple.type.Type; import com.seaofnodes.simple.type.TypeInteger; -import java.util.BitSet; -public class ShrNode extends LogicalNode { +public class ShrNode extends ArithNode { public ShrNode(Parser.Lexer loc, Node lhs, Node rhs) { super(loc, lhs, rhs); } @Override public String label() { return "Shr"; } @Override public String op() { return ">>>"; } - @Override public String glabel() { return ">>>"; } - @Override - public Type compute() { - Type t1 = in(1)._type, t2 = in(2)._type; - if( t1.isHigh() || t2.isHigh() ) - return TypeInteger.TOP; - if (t1 instanceof TypeInteger i0 && - t2 instanceof TypeInteger i1 ) { - if( i0 == TypeInteger.ZERO ) - return TypeInteger.ZERO; - if( i0.isConstant() && i1.isConstant() ) - return TypeInteger.constant(i0.value()>>>i1.value()); - } - return TypeInteger.BOT; + @Override long doOp( long x, long y ) { return x >>> y; } + @Override TypeInteger doOp( TypeInteger x, TypeInteger y ) { + return x == TypeInteger.ZERO ? x : TypeInteger.BOT; } @Override @@ -40,7 +28,7 @@ public class ShrNode extends LogicalNode { // TODO: x >>> 3 >>> (y ? 1 : 2) ==> x >>> (y ? 4 : 5) - return null; + return super.idealize(); } @Override Node copy(Node lhs, Node rhs) { return new ShrNode(_loc,lhs,rhs); } } 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 4290ff9b..8e4f6f79 100644 --- a/chapter22/src/main/java/com/seaofnodes/simple/node/SubNode.java +++ b/chapter22/src/main/java/com/seaofnodes/simple/node/SubNode.java @@ -5,38 +5,22 @@ import com.seaofnodes.simple.type.Type; import com.seaofnodes.simple.type.TypeInteger; import java.util.BitSet; -public class SubNode extends Node { +public class SubNode extends ArithNode { public SubNode(Node lhs, Node rhs) { super(null, lhs, rhs); } @Override public String label() { return "Sub"; } + @Override public String op() { return "-"; } - @Override public String glabel() { return "-"; } - - @Override - public 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() { - Type t1 = in(1)._type, t2 = in(2)._type; - if( t1.isHigh() || t2.isHigh() ) - return TypeInteger.TOP; + @Override long doOp( long x, long y ) { return x - y; } + @Override TypeInteger doOp(TypeInteger x, TypeInteger y) { // Sub of same is 0 if( in(1)==in(2) ) return TypeInteger.ZERO; - if( t1 instanceof TypeInteger i1 && - t2 instanceof TypeInteger i2 ) { - if (i1.isConstant() && i2.isConstant()) - return TypeInteger.constant(i1.value()-i2.value()); - // Fold ranges like {2-3} - {0-1} into {1-3}. - if( !AddNode.overflow(i1._min,-i2._max) && - !AddNode.overflow(i1._max,-i2._min) && - i2._min != Long.MIN_VALUE ) - return TypeInteger.make(i1._min-i2._max,i1._max-i2._min); - } + // Fold ranges like {2-3} - {0-1} into {1-3}. + if( !AddNode.overflow(x._min,-y._max) && + !AddNode.overflow(x._max,-y._min) && + y._min != Long.MIN_VALUE ) + return TypeInteger.make(x._min-y._max,x._max-y._min); return TypeInteger.BOT; } @@ -51,7 +35,7 @@ public class SubNode extends Node { if( in(1) instanceof MinusNode minus ) return new MinusNode(new AddNode(minus.in(1),in(2)).peephole()); - return null; + return super.idealize(); } @Override Node copy(Node lhs, Node rhs) { return new SubNode(lhs,rhs); } diff --git a/chapter22/src/main/java/com/seaofnodes/simple/node/XorNode.java b/chapter22/src/main/java/com/seaofnodes/simple/node/XorNode.java index 37d7147d..fdb4863e 100644 --- a/chapter22/src/main/java/com/seaofnodes/simple/node/XorNode.java +++ b/chapter22/src/main/java/com/seaofnodes/simple/node/XorNode.java @@ -3,26 +3,16 @@ package com.seaofnodes.simple.node; import com.seaofnodes.simple.Parser; import com.seaofnodes.simple.type.Type; import com.seaofnodes.simple.type.TypeInteger; -import java.util.BitSet; -public class XorNode extends LogicalNode { +public class XorNode extends ArithNode { public XorNode(Parser.Lexer loc, Node lhs, Node rhs) { super(loc, lhs, rhs); } @Override public String label() { return "Xor"; } @Override public String op() { return "^"; } - @Override public String glabel() { return "^"; } - @Override - public Type compute() { - Type t1 = in(1)._type, t2 = in(2)._type; - if( t1.isHigh() || t2.isHigh() ) - return TypeInteger.TOP; - if( t1 instanceof TypeInteger i0 && - t2 instanceof TypeInteger i1 ) { - if( i0.isConstant() && i1.isConstant() ) - return TypeInteger.constant(i0.value()^i1.value()); - } + @Override long doOp( long x, long y ) { return x ^ y; } + @Override TypeInteger doOp( TypeInteger x, TypeInteger y ) { return TypeInteger.BOT; } @@ -48,7 +38,7 @@ public class XorNode extends LogicalNode { Node phicon = AddNode.phiCon(this,true); if( phicon!=null ) return phicon; - return null; + return super.idealize(); } @Override Node copy(Node lhs, Node rhs) { return new XorNode(_loc,lhs,rhs); } } diff --git a/chapter22/src/main/java/com/seaofnodes/simple/print/ASMPrinter.java b/chapter22/src/main/java/com/seaofnodes/simple/print/ASMPrinter.java index 3b946cb5..45f71e40 100644 --- a/chapter22/src/main/java/com/seaofnodes/simple/print/ASMPrinter.java +++ b/chapter22/src/main/java/com/seaofnodes/simple/print/ASMPrinter.java @@ -198,7 +198,7 @@ public abstract class ASMPrinter { // Encoding int fatEncoding = 0; - if( code._encoding != null ) { + if( code._encoding != null && code._encoding._opLen!=null ) { int size = code._encoding._opLen[n._nid]; if( code._asmLittle ) for( int i=0; i<Math.min(size,dopz); i++ ) @@ -247,7 +247,7 @@ public abstract class ASMPrinter { sb.nl(); // Printing more op bits than fit - if( isMultiOp != null && code._encoding != null ) { + if( isMultiOp != null && code._encoding != null && code._encoding._opLen!=null ) { // Multiple ops, template style, no RA, no scheduling. Print out // one-line-per-newline, with encoding bits up front. int size = code._encoding._opLen[n._nid]; diff --git a/chapter22/src/main/java/com/seaofnodes/simple/sys/sys.smp b/chapter22/src/main/java/com/seaofnodes/simple/sys/sys.smp index 50d9166e..bc0492e8 100644 --- a/chapter22/src/main/java/com/seaofnodes/simple/sys/sys.smp +++ b/chapter22/src/main/java/com/seaofnodes/simple/sys/sys.smp @@ -5,8 +5,13 @@ struct sys { // libc bindings /** https://www.man7.org/linux/man-pages/man2/<libc call>.2.html */ struct libc { + i32 errno = "C"; // fd buf len -> len - { i32 i64 i32 -> i32 } write = "C"; + { i32 i64 u32 -> u32 } write = "C"; + // fd buf len -> len + { i32 i64 u32 -> u32 } read = "C"; + //// status + //{ i32 -> i32 } _exit = "C"; // addr len prot flags fd off -> void* { i64 i64 i32 i32 i32 i32 -> i64 } mmap = "C"; // mmap flags @@ -18,10 +23,28 @@ struct sys { i32 MAP_ANON = 32; }; struct io { + // Print string to stdout val p = { u8[~] str -> i64 ptr = str; // cast array base to i64 - i32 len = str#; // cast length to signed - return sys.libc.write(1,ptr,len); + return sys.libc.write(1,ptr,str#); }; + + //// Return stdin as a u8[] + //val stdin = { -> + // var buf = new u8[8*1024]; + // i64 ptr = buf; + // int len = 0; + // while( true ) { + // int rez = sys.libc.read(0,ptr,buf#); + // if( rez < 0 ) sys.libc._exit(sys.libc.errno); + // if( rez < buf# ) + // break; + // sys.libc._exit(-2); // Need to implement + // } + // // Compress + // var rez = new u8[len]; + // sys.ary.copy(buf,0,rez,0,len); + // return rez; + //}; }; }; |
