From 018379b0cf4e286ceacb1e39f34dd80f770e381e Mon Sep 17 00:00:00 2001 From: Cliff Click Date: Mon, 21 Apr 2025 14:18:23 -0700 Subject: Chapter 22: A Hello, World! MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: godalming123 <68993177+godalming123@users.noreply.github.com> Co-authored-by: Tamás Hadházy <85063808+Hels15@users.noreply.github.com> --- .../java/com/seaofnodes/simple/node/AddNode.java | 47 +++-------- .../java/com/seaofnodes/simple/node/AndNode.java | 29 ++----- .../java/com/seaofnodes/simple/node/ArithNode.java | 98 ++++++++++++++++++++++ .../java/com/seaofnodes/simple/node/BoolNode.java | 21 ++++- .../java/com/seaofnodes/simple/node/CFGNode.java | 14 +++- .../com/seaofnodes/simple/node/CallEndMach.java | 36 ++++++++ .../com/seaofnodes/simple/node/CallEndNode.java | 35 ++------ .../java/com/seaofnodes/simple/node/CallNode.java | 10 ++- .../java/com/seaofnodes/simple/node/CastMach.java | 19 +++++ .../java/com/seaofnodes/simple/node/CastNode.java | 5 ++ .../java/com/seaofnodes/simple/node/DivNode.java | 28 ++----- .../com/seaofnodes/simple/node/ExternNode.java | 23 +++++ .../java/com/seaofnodes/simple/node/FunNode.java | 15 +++- .../java/com/seaofnodes/simple/node/LoadNode.java | 6 ++ .../com/seaofnodes/simple/node/LogicalNode.java | 29 ------- .../java/com/seaofnodes/simple/node/LoopNode.java | 2 +- .../com/seaofnodes/simple/node/MemMergeNode.java | 41 ++++++--- .../java/com/seaofnodes/simple/node/MemOpNode.java | 3 +- .../java/com/seaofnodes/simple/node/MinusNode.java | 2 +- .../java/com/seaofnodes/simple/node/MulNode.java | 34 ++------ src/main/java/com/seaofnodes/simple/node/Node.java | 12 ++- .../java/com/seaofnodes/simple/node/OrNode.java | 20 ++--- .../java/com/seaofnodes/simple/node/ParmNode.java | 4 + .../java/com/seaofnodes/simple/node/PhiNode.java | 9 +- .../com/seaofnodes/simple/node/ReadOnlyMach.java | 19 +++++ .../com/seaofnodes/simple/node/ReadOnlyNode.java | 2 +- .../com/seaofnodes/simple/node/ReturnNode.java | 1 - .../java/com/seaofnodes/simple/node/SarNode.java | 26 ++---- .../java/com/seaofnodes/simple/node/ScopeNode.java | 44 +++++----- .../java/com/seaofnodes/simple/node/ShlNode.java | 27 +++--- .../java/com/seaofnodes/simple/node/ShrNode.java | 22 ++--- .../java/com/seaofnodes/simple/node/StopNode.java | 20 +++-- .../java/com/seaofnodes/simple/node/StoreNode.java | 29 +++++-- .../java/com/seaofnodes/simple/node/SubNode.java | 36 +++----- .../java/com/seaofnodes/simple/node/XorNode.java | 18 +--- .../seaofnodes/simple/node/cpus/arm/CallARM.java | 9 +- .../simple/node/cpus/arm/CallEndARM.java | 8 -- .../seaofnodes/simple/node/cpus/arm/CastARM.java | 18 ---- .../seaofnodes/simple/node/cpus/arm/FloatARM.java | 2 - .../seaofnodes/simple/node/cpus/arm/TFPARM.java | 14 ++-- .../seaofnodes/simple/node/cpus/arm/TMPARM.java | 53 ++++++++++++ .../com/seaofnodes/simple/node/cpus/arm/arm.java | 90 ++++++++++---------- .../simple/node/cpus/riscv/CallEndRISC.java | 8 -- .../simple/node/cpus/riscv/CallRISC.java | 20 +++-- .../simple/node/cpus/riscv/CastRISC.java | 18 ---- .../seaofnodes/simple/node/cpus/riscv/FltRISC.java | 3 +- .../seaofnodes/simple/node/cpus/riscv/ImmRISC.java | 3 +- .../simple/node/cpus/riscv/Int8RISC.java | 47 +++++++++++ .../com/seaofnodes/simple/node/cpus/riscv/LUI.java | 2 +- .../simple/node/cpus/riscv/MemOpRISC.java | 12 +-- .../simple/node/cpus/riscv/SraIRISC.java | 4 +- .../seaofnodes/simple/node/cpus/riscv/TFPRISC.java | 11 ++- .../seaofnodes/simple/node/cpus/riscv/TMPRISC.java | 41 +++++++++ .../simple/node/cpus/riscv/XorIRISC.java | 1 + .../seaofnodes/simple/node/cpus/riscv/riscv.java | 16 ++-- .../simple/node/cpus/x86_64_v2/AddIX86.java | 11 +++ .../simple/node/cpus/x86_64_v2/CallEndX86.java | 8 -- .../simple/node/cpus/x86_64_v2/CallX86.java | 11 ++- .../simple/node/cpus/x86_64_v2/CastX86.java | 16 ---- .../simple/node/cpus/x86_64_v2/CmpMemX86.java | 2 +- .../simple/node/cpus/x86_64_v2/CmpX86.java | 6 ++ .../simple/node/cpus/x86_64_v2/DivX86.java | 2 +- .../simple/node/cpus/x86_64_v2/ImmX86.java | 3 +- .../simple/node/cpus/x86_64_v2/MemAddX86.java | 5 +- .../simple/node/cpus/x86_64_v2/MulIX86.java | 33 ++++++-- .../simple/node/cpus/x86_64_v2/RegX86.java | 1 + .../simple/node/cpus/x86_64_v2/SetX86.java | 4 +- .../simple/node/cpus/x86_64_v2/TFPX86.java | 1 + .../simple/node/cpus/x86_64_v2/TMPX86.java | 35 ++++++++ .../simple/node/cpus/x86_64_v2/x86_64_v2.java | 28 ++++--- 70 files changed, 799 insertions(+), 533 deletions(-) create mode 100644 src/main/java/com/seaofnodes/simple/node/ArithNode.java create mode 100644 src/main/java/com/seaofnodes/simple/node/CallEndMach.java create mode 100644 src/main/java/com/seaofnodes/simple/node/CastMach.java create mode 100644 src/main/java/com/seaofnodes/simple/node/ExternNode.java delete mode 100644 src/main/java/com/seaofnodes/simple/node/LogicalNode.java create mode 100644 src/main/java/com/seaofnodes/simple/node/ReadOnlyMach.java delete mode 100644 src/main/java/com/seaofnodes/simple/node/cpus/arm/CallEndARM.java delete mode 100644 src/main/java/com/seaofnodes/simple/node/cpus/arm/CastARM.java create mode 100644 src/main/java/com/seaofnodes/simple/node/cpus/arm/TMPARM.java delete mode 100644 src/main/java/com/seaofnodes/simple/node/cpus/riscv/CallEndRISC.java delete mode 100644 src/main/java/com/seaofnodes/simple/node/cpus/riscv/CastRISC.java create mode 100644 src/main/java/com/seaofnodes/simple/node/cpus/riscv/Int8RISC.java create mode 100644 src/main/java/com/seaofnodes/simple/node/cpus/riscv/TMPRISC.java delete mode 100644 src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/CallEndX86.java delete mode 100644 src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/CastX86.java create mode 100644 src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/TMPX86.java (limited to 'src/main/java/com/seaofnodes/simple/node') diff --git a/src/main/java/com/seaofnodes/simple/node/AddNode.java b/src/main/java/com/seaofnodes/simple/node/AddNode.java index dd128e76..0f472829 100644 --- a/src/main/java/com/seaofnodes/simple/node/AddNode.java +++ b/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/src/main/java/com/seaofnodes/simple/node/AndNode.java b/src/main/java/com/seaofnodes/simple/node/AndNode.java index 3cfcbda3..70b57d6d 100644 --- a/src/main/java/com/seaofnodes/simple/node/AndNode.java +++ b/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/src/main/java/com/seaofnodes/simple/node/ArithNode.java b/src/main/java/com/seaofnodes/simple/node/ArithNode.java new file mode 100644 index 00000000..3e376418 --- /dev/null +++ b/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=nIns() || in(i)==null ) + setDefX(i,mem.in(i)); + } + } + setDef(1,mem.in(1)); + return this; + } + + return progress ? this : null; } public Node in( Var v ) { return in(v._idx); } public Node alias( int alias ) { - return in(alias _outputs; + public Ary _outputs; /** @@ -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); @@ -239,7 +239,7 @@ public abstract class Node implements Cloneable { // Shortcut for "popping" until n nodes. A "pop" is basically a // setDef(last,null) followed by lowering the nIns() count. - void popUntil(int n) { + public void popUntil(int n) { unlock(); while( nIns() > n ) { Node old_def = _inputs.pop(); @@ -255,9 +255,9 @@ public abstract class Node implements Cloneable { * code elimination. */ public void kill( ) { + assert isUnused(); // Has no uses, so it is dead unlock(); moveDepsToWorklist(); - assert isUnused(); // Has no uses, so it is dead _type=null; // Flag as dead while( nIns()>0 ) { // Set all inputs to null, recursively killing unused Nodes Node old_def = _inputs.removeLast(); @@ -295,6 +295,10 @@ public abstract class Node implements Cloneable { if( unkeep().isUnused() ) kill(); } + public void isKill() { + if( isUnused() ) + kill(); + } // Replace self with nnn in the graph, making 'this' go dead diff --git a/src/main/java/com/seaofnodes/simple/node/OrNode.java b/src/main/java/com/seaofnodes/simple/node/OrNode.java index 9b03dc5d..ac0d8454 100644 --- a/src/main/java/com/seaofnodes/simple/node/OrNode.java +++ b/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/src/main/java/com/seaofnodes/simple/node/ParmNode.java b/src/main/java/com/seaofnodes/simple/node/ParmNode.java index 9e11a129..32e41f54 100644 --- a/src/main/java/com/seaofnodes/simple/node/ParmNode.java +++ b/src/main/java/com/seaofnodes/simple/node/ParmNode.java @@ -45,4 +45,8 @@ public class ParmNode extends PhiNode { // Always in-progress until we run out of unknown callers @Override public boolean inProgress() { return fun().inProgress(); } + + @Override public boolean eq( Node n ) { + return ((ParmNode)n)._idx==_idx && super.eq(n); + } } diff --git a/src/main/java/com/seaofnodes/simple/node/PhiNode.java b/src/main/java/com/seaofnodes/simple/node/PhiNode.java index 0579ecd0..971b52ae 100644 --- a/src/main/java/com/seaofnodes/simple/node/PhiNode.java +++ b/src/main/java/com/seaofnodes/simple/node/PhiNode.java @@ -54,7 +54,7 @@ public class PhiNode extends Node { // During parsing Phis have to be computed type pessimistically. if( r.inProgress() ) return _declaredType; // Set type to local top of the starting type - Type t = _declaredType.glb().dual();//Type.TOP; + Type t = _declaredType.glb(false).dual();//Type.TOP; for (int i = 1; i < nIns(); i++) // If the region's control input is live, add this as a dependency // to the control because we can be peeped should it become dead. @@ -121,12 +121,17 @@ public class PhiNode extends Node { Node op = in(i); if( in(1).getClass() != op.getClass() || op.in(0)!=null || in(1).nIns() != op.nIns() ) return false; // Wrong class or CFG bound or mismatched inputs + if( in(1) instanceof MemOpNode mem && mem._alias != ((MemOpNode)op)._alias ) + return false; if( op.nOuts() > 1 ) { // Too many users, but addDep in case lose users for( Node out : op._outputs ) if( out!=null && out!=this ) addDep(out); return false; } + for( int j=1; j>"; } - @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/src/main/java/com/seaofnodes/simple/node/ScopeNode.java b/src/main/java/com/seaofnodes/simple/node/ScopeNode.java index 38a5d968..3127e491 100644 --- a/src/main/java/com/seaofnodes/simple/node/ScopeNode.java +++ b/src/main/java/com/seaofnodes/simple/node/ScopeNode.java @@ -25,7 +25,10 @@ public class ScopeNode extends MemMergeNode { // Size of each nested lexical scope public final Ary _lexSize; - // Lexical scope is one of normal Block, constructor or function + // Lexical scope is typed: + // - Block scope - basic block scoping + // - Constructor - struct type is defined, and here we give values to all fields + // - Function - out-of-scope lookups restricted to final constants public enum Kind { Block, Constructor, Function }; public final Ary _kinds; @@ -49,7 +52,7 @@ public class ScopeNode extends MemMergeNode { int j=1; for( int i=0; i N ctrl(N n) { return setDef(0,n); } public Node mem(Node n) { return setDef(1,n); } - public void push(Kind kind) { + public void push( Kind kind ) { assert _lexSize._len==_kinds._len; _lexSize.push(_vars.size()); _kinds .push(kind); @@ -94,11 +98,11 @@ public class ScopeNode extends MemMergeNode { // Pop a lexical scope public void pop() { assert _lexSize._len==_kinds._len; - promote(); + promote(); // Promote forward references to the next outer scope int n = _lexSize.pop(); _kinds.pop(); - popUntil(n); - _vars.setLen(n); + popUntil(n); // Pop off inputs going out of scope + _vars.setLen(n); // Pop off variables going out of scope } @@ -107,7 +111,7 @@ public class ScopeNode extends MemMergeNode { public void promote() { int n = _lexSize.last(); for( int i=n; i=0; i-- ) - if( _vars.at(i)._name.equals(name) ) + if( var(i)._name.equals(name) ) return i; return -1; } @@ -148,7 +152,7 @@ public class ScopeNode extends MemMergeNode { assert _lexSize.isEmpty() || name.charAt(0)!='$' ; // Later scopes do not define memory if( _lexSize._len > 0 ) for( int i=_vars.size()-1; i>=_lexSize.last(); i-- ) { - Var n = _vars.at(i); + Var n = var(i); if( n._name.equals(name) ) { if( !n.isFRef() ) return false; // Double define FRefNode fref = (FRefNode)in(n._idx); // Get forward ref @@ -181,11 +185,11 @@ public class ScopeNode extends MemMergeNode { public Var lookup( String name ) { int idx = find(name); // -1 is missed in all scopes, not found - return idx == -1 ? null : update(_vars.at(idx),null); + return idx == -1 ? null : update(var(idx),null); } /** - * If the name is present in any scope, then redefine else null + * Redefine an existing name * * @param name Name being redefined * @param n The node to bind to the name @@ -193,7 +197,7 @@ public class ScopeNode extends MemMergeNode { public void update( String name, Node n ) { int idx = find(name); assert idx>=0; - update(_vars.at(idx),n); + update(var(idx),n); } public Var update( Var v, Node st ) { @@ -207,7 +211,7 @@ public class ScopeNode extends MemMergeNode { // Set real Phi in the loop head // The phi takes its one input (no backedge yet) from a recursive // lookup, which might have insert a Phi in every loop nest. - : loop.setDef(v._idx,new PhiNode(v._name, v.lazyGLB(), loop.ctrl(), loop.in(loop.update(v,null)._idx),null).peephole()); + : loop.setDef(v._idx,new PhiNode(v._name, v.type(), loop.ctrl(), loop.in(loop.update(v,null)._idx),null).peephole()); setDef(v._idx,old); } assert !v._final || st==null; @@ -260,7 +264,7 @@ public class ScopeNode extends MemMergeNode { for( int i=2; i>shf) != x._min || + ((x._max<>shf) != x._max ) ) + return TypeInteger.make(x._min< 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/src/main/java/com/seaofnodes/simple/node/ShrNode.java b/src/main/java/com/seaofnodes/simple/node/ShrNode.java index 789fb8a8..269f6b7f 100644 --- a/src/main/java/com/seaofnodes/simple/node/ShrNode.java +++ b/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/src/main/java/com/seaofnodes/simple/node/StopNode.java b/src/main/java/com/seaofnodes/simple/node/StopNode.java index 9be08ad9..b65535f1 100644 --- a/src/main/java/com/seaofnodes/simple/node/StopNode.java +++ b/src/main/java/com/seaofnodes/simple/node/StopNode.java @@ -23,11 +23,15 @@ public class StopNode extends CFGNode { @Override public StringBuilder _print1(StringBuilder sb, BitSet visited) { // For the sake of many old tests, and single value prints as "return val" - if( ret()!=null ) return ret()._print0(sb,visited); + ReturnNode ret1 = ret(); + if( ret1!=null ) return ret1._print0(sb,visited); sb.append("Stop[ "); for( Node ret : _inputs ) - if( ret!=null ) - ret._print0(sb, visited).append(" "); + if( ret!=null ) { + String name = ((ReturnNode)ret).fun()._name; + if( name== null || !name.startsWith("sys.") ) + ret._print0(sb, visited).append(" "); + } return sb.append("]"); } @@ -37,7 +41,13 @@ public class StopNode extends CFGNode { // If a single Return, return it. // Otherwise, null because ambiguous. public ReturnNode ret() { - return nIns()==1 && in(0) instanceof ReturnNode ret ? ret : null; + Node ret1 = this; + for( Node ret : _inputs ) { + String name = ((ReturnNode)ret).fun()._name; + if( name==null || !name.startsWith("sys.") ) + ret1 = ret1==this ? ((ReturnNode)ret) : null; + } + return ret1==this ? null : (ReturnNode)ret1; } @Override @@ -49,7 +59,7 @@ public class StopNode extends CFGNode { public Node idealize() { int len = nIns(); for( int i=0; i= store_size && not_affected_bits >= store_size) { + setDef(4, shl.in(1)); + return this; + } + } return null; } @@ -111,8 +128,6 @@ public class StoreNode extends MemOpNode { TypeMemPtr tmp = (TypeMemPtr)ptr()._type; if( tmp._obj.field(_name)._final && !_init ) return Parser.error("Cannot modify final field '"+_name+"'",_loc); - //Type t = val()._type; - //return _init || t.isa(_declaredType) ? null : Parser.error("Cannot store "+t+" into field "+_declaredType+" "+_name,_loc); return null; } } diff --git a/src/main/java/com/seaofnodes/simple/node/SubNode.java b/src/main/java/com/seaofnodes/simple/node/SubNode.java index 4290ff9b..8e4f6f79 100644 --- a/src/main/java/com/seaofnodes/simple/node/SubNode.java +++ b/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/src/main/java/com/seaofnodes/simple/node/XorNode.java b/src/main/java/com/seaofnodes/simple/node/XorNode.java index 37d7147d..fdb4863e 100644 --- a/src/main/java/com/seaofnodes/simple/node/XorNode.java +++ b/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/src/main/java/com/seaofnodes/simple/node/cpus/arm/CallARM.java b/src/main/java/com/seaofnodes/simple/node/cpus/arm/CallARM.java index 7f6fe93c..989bd366 100644 --- a/src/main/java/com/seaofnodes/simple/node/cpus/arm/CallARM.java +++ b/src/main/java/com/seaofnodes/simple/node/cpus/arm/CallARM.java @@ -8,13 +8,13 @@ import com.seaofnodes.simple.type.TypeFunPtr; public class CallARM extends CallNode implements MachNode, RIPRelSize { final TypeFunPtr _tfp; final String _name; - CallARM(CallNode call, TypeFunPtr tfp) { super(call); _inputs.pop(); // Pop constant target assert tfp.isConstant(); _tfp = tfp; - _name = CodeGen.CODE.link(tfp)._name; + FunNode fun = CodeGen.CODE.link(tfp); + _name = fun==null ? ((ExternNode)call.fptr())._extern : fun._name; // Can be null for extern calls } @Override public String op() { return "call"; } @@ -23,9 +23,12 @@ public class CallARM extends CallNode implements MachNode, RIPRelSize { @Override public TypeFunPtr tfp() { return _tfp; } @Override public RegMask regmap(int i) { return arm.callInMask(_tfp,i,fun()._maxArgSlot); } @Override public RegMask outregmap() { return null; } + @Override public int nargs() { return nIns()-2; } // Minus control, memory, fptr @Override public void encoding( Encoding enc ) { - enc.relo(this); + FunNode fun = CodeGen.CODE.link(_tfp); + if( fun==null ) enc.external(this,_name); + else enc.relo(this); // BL enc.add4(arm.b(arm.OP_CALL,0)); // Target patched at link time } diff --git a/src/main/java/com/seaofnodes/simple/node/cpus/arm/CallEndARM.java b/src/main/java/com/seaofnodes/simple/node/cpus/arm/CallEndARM.java deleted file mode 100644 index b3c2f6c2..00000000 --- a/src/main/java/com/seaofnodes/simple/node/cpus/arm/CallEndARM.java +++ /dev/null @@ -1,8 +0,0 @@ -package com.seaofnodes.simple.node.cpus.arm; - -import com.seaofnodes.simple.node.CallEndNode; -import com.seaofnodes.simple.node.MachNode; - -public class CallEndARM extends CallEndNode implements MachNode { - CallEndARM( CallEndNode cend ) { super(cend); } -} diff --git a/src/main/java/com/seaofnodes/simple/node/cpus/arm/CastARM.java b/src/main/java/com/seaofnodes/simple/node/cpus/arm/CastARM.java deleted file mode 100644 index a5a4e112..00000000 --- a/src/main/java/com/seaofnodes/simple/node/cpus/arm/CastARM.java +++ /dev/null @@ -1,18 +0,0 @@ -package com.seaofnodes.simple.node.cpus.arm; - -import com.seaofnodes.simple.SB; -import com.seaofnodes.simple.codegen.CodeGen; -import com.seaofnodes.simple.codegen.Encoding; -import com.seaofnodes.simple.codegen.RegMask; -import com.seaofnodes.simple.node.CastNode; -import com.seaofnodes.simple.node.MachNode; - -public class CastARM extends CastNode implements MachNode { - public CastARM( CastNode cast ) { super(cast); } - @Override public String op() { return label(); } - @Override public RegMask regmap(int i) { assert i==1; return RegMask.FULL; } - @Override public RegMask outregmap() { return RegMask.FULL; } - @Override public int twoAddress( ) { return 1; } - @Override public void encoding( Encoding enc ) { } - @Override public void asm(CodeGen code, SB sb) { _t.print(sb.p(code.reg(in(1))).p(" isa ")); } -} diff --git a/src/main/java/com/seaofnodes/simple/node/cpus/arm/FloatARM.java b/src/main/java/com/seaofnodes/simple/node/cpus/arm/FloatARM.java index 6de65b03..63c57770 100644 --- a/src/main/java/com/seaofnodes/simple/node/cpus/arm/FloatARM.java +++ b/src/main/java/com/seaofnodes/simple/node/cpus/arm/FloatARM.java @@ -20,8 +20,6 @@ public class FloatARM extends ConstantNode implements MachNode, RIPRelSize { @Override public void encoding( Encoding enc ) { enc.largeConstant(this,_con,0,-1/*TODO: ARM-style ELF patching*/); short dst = (short)(enc.reg(this) - arm.D_OFFSET); - double d = ((TypeFloat)_con).value(); - long x = Double.doubleToRawLongBits(d); enc.add4(arm.load_pc(arm.OPF_ARM, 0, dst)); } diff --git a/src/main/java/com/seaofnodes/simple/node/cpus/arm/TFPARM.java b/src/main/java/com/seaofnodes/simple/node/cpus/arm/TFPARM.java index 16b56553..606b03f0 100644 --- a/src/main/java/com/seaofnodes/simple/node/cpus/arm/TFPARM.java +++ b/src/main/java/com/seaofnodes/simple/node/cpus/arm/TFPARM.java @@ -4,7 +4,7 @@ import com.seaofnodes.simple.*; import com.seaofnodes.simple.codegen.*; import com.seaofnodes.simple.node.ConstantNode; import com.seaofnodes.simple.node.MachNode; -import com.seaofnodes.simple.node.cpus.riscv.riscv; +import com.seaofnodes.simple.node.Node; import com.seaofnodes.simple.type.TypeFunPtr; public class TFPARM extends ConstantNode implements MachNode, RIPRelSize { @@ -25,21 +25,22 @@ public class TFPARM extends ConstantNode implements MachNode, RIPRelSize { } @Override public byte encSize(int delta) { - if( -(1L<<12) <= delta && delta < (1L<<12) ) return 4; - throw Utils.TODO(); + return 8; } // Delta is from opcode start @Override public void patch( Encoding enc, int opStart, int opLen, int delta ) { short rpc = enc.reg(this); if(opLen == 8 ) { - // opstart of add - int next = opStart + opLen; + // ARM encoding delta is from PC & 0xFFF + int target = opStart+delta; + int base = opStart & ~0xFFF; + delta = target-base; int adrp_delta = delta >> 12; // patch upper 20 bits via adrp enc.patch4(opStart, arm.adrp(1, adrp_delta & 0b11, 0b10000, adrp_delta >> 2, rpc)); // low 12 bits via add - enc.patch4(next, arm.imm_inst_l(arm.OPI_ADD, delta & 0xfff, rpc)); + enc.patch4(opStart+4, arm.imm_inst_l(arm.OPI_ADD, delta & 0xfff, rpc)); } else { // should not happen as one instruction is 4 byte, and TFP arm encodes 2. throw Utils.TODO(); @@ -50,4 +51,5 @@ public class TFPARM extends ConstantNode implements MachNode, RIPRelSize { String reg = code.reg(this); _con.print(sb.p(reg).p(" #")); } + @Override public boolean eq(Node n) { return this==n; } } diff --git a/src/main/java/com/seaofnodes/simple/node/cpus/arm/TMPARM.java b/src/main/java/com/seaofnodes/simple/node/cpus/arm/TMPARM.java new file mode 100644 index 00000000..68e32c78 --- /dev/null +++ b/src/main/java/com/seaofnodes/simple/node/cpus/arm/TMPARM.java @@ -0,0 +1,53 @@ +package com.seaofnodes.simple.node.cpus.arm; + +import com.seaofnodes.simple.*; +import com.seaofnodes.simple.codegen.*; +import com.seaofnodes.simple.node.ConstantNode; +import com.seaofnodes.simple.node.MachNode; +import com.seaofnodes.simple.node.Node; +import com.seaofnodes.simple.type.TypeMemPtr; + +public class TMPARM extends ConstantNode implements MachNode, RIPRelSize { + TMPARM( ConstantNode con ) { super(con); } + @Override public String op() { return "ldp"; } + @Override public RegMask regmap(int i) { return null; } + @Override public RegMask outregmap() { return arm.WMASK; } + @Override public boolean isClone() { return true; } + @Override public TMPARM copy() { return new TMPARM(this); } + @Override public void encoding( Encoding enc ) { + enc.largeConstant(this,((TypeMemPtr)_con)._obj,0,-1); + short dst = enc.reg(this); + // adrp x0, 0 + enc.add4(arm.adrp(1,0, arm.OP_ADRP, 0,dst)); + // add x0, x0, 0 + arm.imm_inst(enc,arm.OPI_ADD,0, dst); + } + + @Override public byte encSize(int delta) { + return 8; + } + + // Delta is from opcode start + @Override public void patch( Encoding enc, int opStart, int opLen, int delta ) { + short dst = enc.reg(this); + if(opLen == 8 ) { + // ARM encoding delta is from PC & 0xFFF + int target = opStart+delta; + int base = opStart & ~0xFFF; + delta = target-base; + int adrp_delta = delta >> 12; + // patch upper 20 bits via adrp + enc.patch4(opStart, arm.adrp(1, adrp_delta & 0b11, 0b10000, adrp_delta >> 2, dst)); + // low 12 bits via add + enc.patch4(opStart+4, arm.imm_inst_l(arm.OPI_ADD, delta & 0xfff, dst)); + } else { + throw Utils.TODO(); + } + } + + @Override public void asm(CodeGen code, SB sb) { + String reg = code.reg(this); + _con.print(sb.p(reg).p(" #")); + } + @Override public boolean eq(Node n) { return this==n; } +} diff --git a/src/main/java/com/seaofnodes/simple/node/cpus/arm/arm.java b/src/main/java/com/seaofnodes/simple/node/cpus/arm/arm.java index 3e39adc0..e6f64158 100644 --- a/src/main/java/com/seaofnodes/simple/node/cpus/arm/arm.java +++ b/src/main/java/com/seaofnodes/simple/node/cpus/arm/arm.java @@ -568,6 +568,8 @@ public class arm extends Machine { if( idx==0 ) return CodeGen.CODE._rpcMask; if( idx==1 ) return null; // Count floats in signature up to index + if( idx-2 >= tfp.nargs() ) return null; // Anti-dependence + // Count floats in signature up to index int fcnt=0; for( int i=2; i new AddFARM(addf); - case AddNode add -> add(add); - case AndNode and -> and(and); - case BoolNode bool -> cmp(bool); - case CallNode call -> call(call); - case CastNode cast -> new CastARM(cast); - case CallEndNode cend -> new CallEndARM(cend); - case CProjNode c -> new CProjNode(c); - case ConstantNode con -> con(con); - case DivFNode divf -> new DivFARM(divf); - case DivNode div -> new DivARM(div); - case FunNode fun -> new FunARM(fun); - case IfNode iff -> jmp(iff); - case LoadNode ld -> ld(ld); - case MemMergeNode mem -> new MemMergeNode(mem); - case MinusNode neg -> new NegARM(neg); - case MulFNode mulf -> new MulFARM(mulf); - case MulNode mul -> new MulARM(mul); - case NewNode nnn -> new NewARM(nnn); - case NotNode not -> new NotARM(not); - case OrNode or -> or(or); - case ParmNode parm -> new ParmARM(parm); - case PhiNode phi -> new PhiNode(phi); - case ProjNode prj -> new ProjARM(prj); - case ReadOnlyNode read -> new ReadOnlyNode(read); - case ReturnNode ret -> new RetARM(ret,ret.fun()); - case SarNode sar -> asr(sar); - case ShlNode shl -> lsl(shl); - case ShrNode shr -> lsr(shr); + case AddFNode addf -> new AddFARM(addf); + case AddNode add -> add(add); + case AndNode and -> and(and); + case BoolNode bool -> cmp(bool); + case CallNode call -> call(call); + case CastNode cast -> new CastMach(cast); + case CallEndNode cend-> new CallEndMach(cend); + case CProjNode c -> new CProjNode(c); + case ConstantNode con-> con(con); + case DivFNode divf -> new DivFARM(divf); + case DivNode div -> new DivARM(div); + case FunNode fun -> new FunARM(fun); + case IfNode iff -> jmp(iff); + case LoadNode ld -> ld(ld); + case MemMergeNode mem-> new MemMergeNode(mem); + case MinusNode neg -> new NegARM(neg); + case MulFNode mulf -> new MulFARM(mulf); + case MulNode mul -> new MulARM(mul); + case NewNode nnn -> new NewARM(nnn); + case NotNode not -> new NotARM(not); + case OrNode or -> or(or); + case ParmNode parm -> new ParmARM(parm); + case PhiNode phi -> new PhiNode(phi); + case ProjNode prj -> new ProjARM(prj); + case ReadOnlyNode read -> new ReadOnlyMach(read); + case ReturnNode ret -> new RetARM(ret,ret.fun()); + case SarNode sar -> asr(sar); + case ShlNode shl -> lsl(shl); + case ShrNode shr -> lsr(shr); case StartNode start -> new StartNode(start); - case StopNode stop -> new StopNode(stop); - case StoreNode st -> st(st); - case SubFNode subf -> new SubFARM(subf); - case SubNode sub -> sub(sub); - case ToFloatNode tfn-> new I2F8ARM(tfn); - case XorNode xor -> xor(xor); - - case LoopNode loop -> new LoopNode(loop); + case StopNode stop -> new StopNode(stop); + case StoreNode st -> st(st); + case SubFNode subf -> new SubFARM(subf); + case SubNode sub -> sub(sub); + case ToFloatNode tfn -> new I2F8ARM(tfn); + case XorNode xor -> xor(xor); + + case LoopNode loop -> new LoopNode(loop); case RegionNode region-> new RegionNode(region); default -> throw Utils.TODO(); }; @@ -729,13 +731,13 @@ public class arm extends Machine { private Node con( ConstantNode con ) { if( !con._con.isConstant() ) return new ConstantNode( con ); // Default unknown caller inputs return switch( con._con ) { - case TypeInteger ti -> new IntARM(con); - case TypeFloat tf -> new FloatARM(con); - case TypeFunPtr tfp -> new TFPARM(con); - case TypeMemPtr tmp -> new ConstantNode(con); - case TypeNil tn -> throw Utils.TODO(); - // TOP, BOTTOM, XCtrl, Ctrl, etc. Never any executable code. - case Type t -> t==Type.NIL ? new IntARM(con) : new ConstantNode(con); + case TypeInteger ti -> new IntARM(con); + case TypeFloat tf -> new FloatARM(con); + case TypeFunPtr tfp -> new TFPARM(con); + case TypeMemPtr tmp -> new TMPARM(con); + case TypeNil tn -> throw Utils.TODO(); + // TOP, BOTTOM, XCtrl, Ctrl, etc. Never any executable code. + case Type t -> t==Type.NIL ? new IntARM(con) : new ConstantNode(con); }; } diff --git a/src/main/java/com/seaofnodes/simple/node/cpus/riscv/CallEndRISC.java b/src/main/java/com/seaofnodes/simple/node/cpus/riscv/CallEndRISC.java deleted file mode 100644 index 7df68e77..00000000 --- a/src/main/java/com/seaofnodes/simple/node/cpus/riscv/CallEndRISC.java +++ /dev/null @@ -1,8 +0,0 @@ -package com.seaofnodes.simple.node.cpus.riscv; - -import com.seaofnodes.simple.node.CallEndNode; -import com.seaofnodes.simple.node.MachNode; - -public class CallEndRISC extends CallEndNode implements MachNode { - CallEndRISC( CallEndNode cend ) { super(cend); } -} diff --git a/src/main/java/com/seaofnodes/simple/node/cpus/riscv/CallRISC.java b/src/main/java/com/seaofnodes/simple/node/cpus/riscv/CallRISC.java index 7a0f3313..89b2c865 100644 --- a/src/main/java/com/seaofnodes/simple/node/cpus/riscv/CallRISC.java +++ b/src/main/java/com/seaofnodes/simple/node/cpus/riscv/CallRISC.java @@ -13,23 +13,26 @@ public class CallRISC extends CallNode implements MachNode, RIPRelSize { assert tfp.isConstant(); _inputs.pop(); // Pop constant target _tfp = tfp; - _name = CodeGen.CODE.link(tfp)._name; + FunNode fun = CodeGen.CODE.link(tfp); + _name = fun==null ? ((ExternNode)call.fptr())._extern : fun._name; // Can be null for extern calls } @Override public String op() { return "call"; } @Override public String label() { return op(); } - @Override public RegMask regmap(int i) { - return riscv.callInMask(_tfp,i,fun()._maxArgSlot); - } - @Override public RegMask outregmap() { return riscv.RPC_MASK; } @Override public String name() { return _name; } @Override public TypeFunPtr tfp() { return _tfp; } + @Override public RegMask regmap(int i) { return riscv.callInMask(_tfp,i,fun()._maxArgSlot); } + @Override public RegMask outregmap() { return riscv.RPC_MASK; } + @Override public int nargs() { return nIns()-2; } // Minus control, memory, fptr @Override public void encoding( Encoding enc ) { // Short form +/-4K: beq r0,r0,imm12 // Long form: auipc rX,imm20/32; jal r0,[rX+imm12/32] - enc.relo(this); - enc.add4(riscv.j_type(riscv.OP_JAL, riscv.RPC, 0)); + FunNode fun = CodeGen.CODE.link(_tfp); + if( fun==null ) enc.external(this,_name); + else enc.relo(this); + short rpc = enc.reg(this); + enc.add4(riscv.j_type(riscv.OP_JAL, rpc, 0)); } // Delta is from opcode start @@ -41,8 +44,9 @@ public class CallRISC extends CallNode implements MachNode, RIPRelSize { // Delta is from opcode start @Override public void patch( Encoding enc, int opStart, int opLen, int delta ) { + short rpc = enc.reg(this); if( opLen==4 ) { - enc.patch4(opStart,riscv.j_type(riscv.OP_JAL, riscv.RPC, delta)); + enc.patch4(opStart,riscv.j_type(riscv.OP_JAL, rpc, delta)); } else { throw Utils.TODO(); } diff --git a/src/main/java/com/seaofnodes/simple/node/cpus/riscv/CastRISC.java b/src/main/java/com/seaofnodes/simple/node/cpus/riscv/CastRISC.java deleted file mode 100644 index c404aaa5..00000000 --- a/src/main/java/com/seaofnodes/simple/node/cpus/riscv/CastRISC.java +++ /dev/null @@ -1,18 +0,0 @@ -package com.seaofnodes.simple.node.cpus.riscv; - -import com.seaofnodes.simple.SB; -import com.seaofnodes.simple.codegen.CodeGen; -import com.seaofnodes.simple.codegen.Encoding; -import com.seaofnodes.simple.codegen.RegMask; -import com.seaofnodes.simple.node.CastNode; -import com.seaofnodes.simple.node.MachNode; - -public class CastRISC extends CastNode implements MachNode { - public CastRISC( CastNode cast ) { super(cast); } - @Override public String op() { return label(); } - @Override public RegMask regmap(int i) { assert i==1; return RegMask.FULL; } - @Override public RegMask outregmap() { return RegMask.FULL; } - @Override public int twoAddress( ) { return 1; } - @Override public void encoding( Encoding enc ) { } - @Override public void asm(CodeGen code, SB sb) { _t.print(sb.p(code.reg(in(1))).p(" isa ")); } -} diff --git a/src/main/java/com/seaofnodes/simple/node/cpus/riscv/FltRISC.java b/src/main/java/com/seaofnodes/simple/node/cpus/riscv/FltRISC.java index 35de7e04..be699280 100644 --- a/src/main/java/com/seaofnodes/simple/node/cpus/riscv/FltRISC.java +++ b/src/main/java/com/seaofnodes/simple/node/cpus/riscv/FltRISC.java @@ -16,7 +16,7 @@ public class FltRISC extends ConstantNode implements MachNode, RIPRelSize { @Override public FltRISC copy() { return new FltRISC(this); } @Override public void encoding( Encoding enc ) { - enc.largeConstant(this,_con, 0, -1/*TODO: RISC5 style patching*/); + enc.largeConstant(this,_con, 0, -1); short dst = (short)(enc.reg(this) - riscv.F_OFFSET); short tmp = (short)riscv.T6; // AUIPC dst,#hi20_constant_pool @@ -27,7 +27,6 @@ public class FltRISC extends ConstantNode implements MachNode, RIPRelSize { @Override public RegMask killmap() { return new RegMask(riscv.T6); } // Delta is from opcode start. - // TODO: always size 8? @Override public byte encSize(int delta) { return 8; } // Delta is from opcode start diff --git a/src/main/java/com/seaofnodes/simple/node/cpus/riscv/ImmRISC.java b/src/main/java/com/seaofnodes/simple/node/cpus/riscv/ImmRISC.java index 9303e566..9e7f456a 100644 --- a/src/main/java/com/seaofnodes/simple/node/cpus/riscv/ImmRISC.java +++ b/src/main/java/com/seaofnodes/simple/node/cpus/riscv/ImmRISC.java @@ -40,8 +40,7 @@ abstract public class ImmRISC extends MachConcreteNode implements MachNode { @Override public void encoding( Encoding enc ) { short dst = enc.reg(this ); short src = enc.reg(in(1)); - int body = riscv.i_type(opcode(), dst, func3(), src, _imm12 & 0xFFF); - enc.add4(body); + enc.add4(riscv.i_type(opcode(), dst, func3(), src, _imm12 & 0xFFF)); } // General form: "addi rd = rs1 + imm" diff --git a/src/main/java/com/seaofnodes/simple/node/cpus/riscv/Int8RISC.java b/src/main/java/com/seaofnodes/simple/node/cpus/riscv/Int8RISC.java new file mode 100644 index 00000000..f9b7daee --- /dev/null +++ b/src/main/java/com/seaofnodes/simple/node/cpus/riscv/Int8RISC.java @@ -0,0 +1,47 @@ +package com.seaofnodes.simple.node.cpus.riscv; + +import com.seaofnodes.simple.node.ConstantNode; + +import com.seaofnodes.simple.*; +import com.seaofnodes.simple.codegen.*; +import com.seaofnodes.simple.node.MachNode; + +// Special instruction for loading 8 byte constants from the constant pool. + +public class Int8RISC extends ConstantNode implements MachNode, RIPRelSize { + public Int8RISC(ConstantNode con) { super(con); } + + @Override public String op() { return "ld8"; } + @Override public RegMask regmap(int i) { return null; } + @Override public RegMask outregmap() { return riscv.WMASK; } + @Override public boolean isClone() { return true; } + @Override public Int8RISC copy() { return new Int8RISC(this); } + + @Override public byte encSize(int delta) { return 8; } + + @Override public void encoding( Encoding enc ) { + short dst = enc.reg(this); + short tmp = (short)riscv.T6; + enc.largeConstant(this,_con, 0, -1); + // AUIPC dst,#hi20_constant_pool + enc.add4(riscv.u_type(riscv.OP_AUIPC, tmp, 0)); + // Load dst,[dst+#low12_constant_pool] + enc.add4(riscv.i_type(riscv.OP_LOAD, dst, 0b11, tmp, 0)); + } + @Override public RegMask killmap() { return new RegMask(riscv.T6); } + + // Delta is from opcode start + @Override public void patch( Encoding enc, int opStart, int opLen, int delta ) { + short dst = enc.reg(this); + short tmp = (short)riscv.T6; + // AUIPC dst,#hi20_constant_pool + enc.patch4(opStart , riscv.u_type(riscv.OP_AUIPC, tmp, delta>>12)); + // Load dst,[dst+#low12_constant_pool] + enc.patch4(opStart+4, riscv.i_type(riscv.OP_LOAD, dst, 0b11, tmp, delta & 0xFFF)); + } + + @Override public void asm(CodeGen code, SB sb) { + _con.print(sb.p(code.reg(this)).p(" = #")); + } + +} diff --git a/src/main/java/com/seaofnodes/simple/node/cpus/riscv/LUI.java b/src/main/java/com/seaofnodes/simple/node/cpus/riscv/LUI.java index 75ad6496..b65afc79 100644 --- a/src/main/java/com/seaofnodes/simple/node/cpus/riscv/LUI.java +++ b/src/main/java/com/seaofnodes/simple/node/cpus/riscv/LUI.java @@ -10,7 +10,7 @@ import com.seaofnodes.simple.type.TypeInteger; public class LUI extends ConstantNode implements MachNode { public LUI( int imm20 ) { super(TypeInteger.constant(imm20)); - assert riscv.imm20Exact((TypeInteger)_con); + assert (imm20 & 0xFFF)==0; } @Override public RegMask regmap(int i) { return null; } @Override public RegMask outregmap() { return riscv.WMASK; } diff --git a/src/main/java/com/seaofnodes/simple/node/cpus/riscv/MemOpRISC.java b/src/main/java/com/seaofnodes/simple/node/cpus/riscv/MemOpRISC.java index b8eb7644..8b84a2b9 100644 --- a/src/main/java/com/seaofnodes/simple/node/cpus/riscv/MemOpRISC.java +++ b/src/main/java/com/seaofnodes/simple/node/cpus/riscv/MemOpRISC.java @@ -35,8 +35,9 @@ public abstract class MemOpRISC extends MemOpNode implements MachNode { if(this instanceof StoreRISC) { if( _declaredType == TypeInteger. I8 || _declaredType == TypeInteger.U8 || _declaredType == TypeInteger.BOOL) func3=0; // SB if( _declaredType == TypeInteger.I16 || _declaredType == TypeInteger.U16 ) func3=1; // SH - if( _declaredType == TypeInteger.I32 || _declaredType == TypeInteger.U32 || _declaredType instanceof TypeMemPtr) func3=2; // SW - if( _declaredType == TypeInteger.BOT ) func3=3; // SD + if( _declaredType == TypeInteger.I32 || _declaredType == TypeInteger.U32 ) func3=2; // SW + if( _declaredType instanceof TypeMemPtr) func3=3; // SD + if( _declaredType == TypeInteger.BOT ) func3=3; // SD if( func3 == -1 ) throw Utils.TODO(); return func3; } @@ -50,9 +51,10 @@ public abstract class MemOpRISC extends MemOpNode implements MachNode { if( _declaredType == TypeInteger.U32 ) func3=6; // LWU // float - if(_declaredType == TypeFloat.F32) func3 = 2; // fLW fSW - if(_declaredType == TypeFloat.F64) func3 = 3; // fLD fSD - if( _declaredType instanceof TypeMemPtr ) func3=3; // 8 byte pointers + if( _declaredType == TypeFloat.F32) func3 = 2; // fLW fSW + if( _declaredType == TypeFloat.F64) func3 = 3; // fLD fSD + + if( _declaredType instanceof TypeMemPtr) func3 = 3; // 8 byte pointers (pick ld) if( func3 == -1 ) throw Utils.TODO(); return func3; } diff --git a/src/main/java/com/seaofnodes/simple/node/cpus/riscv/SraIRISC.java b/src/main/java/com/seaofnodes/simple/node/cpus/riscv/SraIRISC.java index 26404e95..1533003c 100644 --- a/src/main/java/com/seaofnodes/simple/node/cpus/riscv/SraIRISC.java +++ b/src/main/java/com/seaofnodes/simple/node/cpus/riscv/SraIRISC.java @@ -4,7 +4,9 @@ import com.seaofnodes.simple.Utils; import com.seaofnodes.simple.node.Node; public class SraIRISC extends ImmRISC { - public SraIRISC( Node and, int imm) { super(and,imm); } + public SraIRISC( Node and, int imm) { + super(and,imm | (0x20 << 5)); + } @Override int opcode() { return riscv.OP_IMM; } @Override int func3() { return 5;} @Override public String glabel() { return ">>"; } diff --git a/src/main/java/com/seaofnodes/simple/node/cpus/riscv/TFPRISC.java b/src/main/java/com/seaofnodes/simple/node/cpus/riscv/TFPRISC.java index 17613009..15be82bc 100644 --- a/src/main/java/com/seaofnodes/simple/node/cpus/riscv/TFPRISC.java +++ b/src/main/java/com/seaofnodes/simple/node/cpus/riscv/TFPRISC.java @@ -4,6 +4,7 @@ import com.seaofnodes.simple.*; import com.seaofnodes.simple.codegen.*; import com.seaofnodes.simple.node.ConstantNode; import com.seaofnodes.simple.node.MachNode; +import com.seaofnodes.simple.node.Node; import com.seaofnodes.simple.type.TypeFunPtr; public class TFPRISC extends ConstantNode implements MachNode, RIPRelSize { @@ -19,11 +20,9 @@ public class TFPRISC extends ConstantNode implements MachNode, RIPRelSize { short dst = enc.reg(this); TypeFunPtr tfp = (TypeFunPtr)_con; // auipc t0,0 - int auipc = riscv.u_type(riscv.OP_AUIPC, dst, 0); + enc.add4(riscv.u_type(riscv.OP_AUIPC, dst, 0)); // addi t1,t0 + #0 - int addi = riscv.i_type(riscv.OP_IMM, dst, 0, dst, 0); - enc.add4(auipc); - enc.add4(addi); + enc.add4(riscv.i_type(riscv.OP_IMM, dst, 0, dst, 0)); } @Override public byte encSize(int delta) { @@ -38,7 +37,7 @@ public class TFPRISC extends ConstantNode implements MachNode, RIPRelSize { // AUIPC (upper 20 bits) // opstart of add int next = opStart + opLen; - enc.patch4(opStart,riscv.u_type(riscv.OP_AUIPC, rpc, delta)); + enc.patch4(opStart,riscv.u_type(riscv.OP_AUIPC, rpc, delta>>12)); // addi(low 12 bits) enc.patch4(next,riscv.i_type(riscv.OP_IMM, rpc, 0, rpc, delta & 0xFFF)); // addi @@ -51,5 +50,5 @@ public class TFPRISC extends ConstantNode implements MachNode, RIPRelSize { @Override public void asm(CodeGen code, SB sb) { _con.print(sb.p(code.reg(this)).p(" #")); } - + @Override public boolean eq(Node n) { return this==n; } } diff --git a/src/main/java/com/seaofnodes/simple/node/cpus/riscv/TMPRISC.java b/src/main/java/com/seaofnodes/simple/node/cpus/riscv/TMPRISC.java new file mode 100644 index 00000000..860e5eaf --- /dev/null +++ b/src/main/java/com/seaofnodes/simple/node/cpus/riscv/TMPRISC.java @@ -0,0 +1,41 @@ +package com.seaofnodes.simple.node.cpus.riscv; + +import com.seaofnodes.simple.*; +import com.seaofnodes.simple.codegen.*; +import com.seaofnodes.simple.node.ConstantNode; +import com.seaofnodes.simple.node.MachNode; +import com.seaofnodes.simple.node.Node; +import com.seaofnodes.simple.type.TypeMemPtr; + +public class TMPRISC extends ConstantNode implements MachNode, RIPRelSize { + TMPRISC(ConstantNode con) { super(con); } + @Override public String op() { return "ldp"; } + @Override public RegMask regmap(int i) { return null; } + @Override public RegMask outregmap() { return riscv.WMASK; } + @Override public boolean isClone() { return true; } + @Override public TMPRISC copy() { return new TMPRISC(this); } + @Override public void encoding( Encoding enc ) { + enc.largeConstant(this,((TypeMemPtr)_con)._obj,0,-1); + short dst = enc.reg(this); + // AUIPC dst,#hi20_constant_pool + enc.add4(riscv.u_type(riscv.OP_AUIPC, dst, 0)); + // addi dst,[dst+#low12_constant_pool] + enc.add4(riscv.i_type(riscv.OP_IMM, dst, 0, dst, 0)); + } + + @Override public byte encSize(int delta) { return 8; } + + // Delta is from opcode start + @Override public void patch( Encoding enc, int opStart, int opLen, int delta ) { + short dst = enc.reg(this); + // AUIPC dst,#hi20_constant_pool + enc.patch4(opStart , riscv.u_type(riscv.OP_AUIPC, dst, delta>>12)); + // Load dst,[dst+#low12_constant_pool] + enc.patch4(opStart+4, riscv.i_type(riscv.OP_IMM, dst, 0, dst, delta & 0xFFF)); + } + + @Override public void asm(CodeGen code, SB sb) { + _con.print(sb.p(code.reg(this)).p(" #")); + } + @Override public boolean eq(Node n) { return this==n; } +} diff --git a/src/main/java/com/seaofnodes/simple/node/cpus/riscv/XorIRISC.java b/src/main/java/com/seaofnodes/simple/node/cpus/riscv/XorIRISC.java index 61f25be2..27098033 100644 --- a/src/main/java/com/seaofnodes/simple/node/cpus/riscv/XorIRISC.java +++ b/src/main/java/com/seaofnodes/simple/node/cpus/riscv/XorIRISC.java @@ -5,6 +5,7 @@ import com.seaofnodes.simple.node.Node; public class XorIRISC extends ImmRISC { public XorIRISC( Node and, int imm) { super(and,imm); } + public XorIRISC( Node and, int imm, boolean pop) { super(and,imm,pop); } @Override int opcode() { return riscv.OP_IMM; } @Override int func3() { return 4; } @Override public String glabel() { return "^"; } diff --git a/src/main/java/com/seaofnodes/simple/node/cpus/riscv/riscv.java b/src/main/java/com/seaofnodes/simple/node/cpus/riscv/riscv.java index 54c6b828..9c5bfa10 100644 --- a/src/main/java/com/seaofnodes/simple/node/cpus/riscv/riscv.java +++ b/src/main/java/com/seaofnodes/simple/node/cpus/riscv/riscv.java @@ -188,7 +188,6 @@ public class riscv extends Machine { return (imm12 << 20) | (rs1 << 15) | (func3 << 12) | (rd << 7) | opcode; } - // S-type instructions(store) public static int s_type(int opcode, int func3, int rs1, int rs2, int imm12) { assert 0 <= rs1 && rs1 < 32; @@ -257,6 +256,7 @@ public class riscv extends Machine { static RegMask callInMask( TypeFunPtr tfp, int idx, int maxArgSlot ) { if( idx==0 ) return RPC_MASK; if( idx==1 ) return null; + if( idx-2 >= tfp.nargs() ) return null; // Anti-dependence // Count floats in signature up to index int fcnt=0; for( int i=2; i>>44)<<12) == ti.value(); + return ti.isConstant() && (((ti.value()<<32)>>44)<<12) == ti.value(); } @Override public Node instSelect( Node n ) { @@ -328,8 +328,8 @@ public class riscv extends Machine { case AndNode and -> and(and); case BoolNode bool -> cmp(bool); case CallNode call -> call(call); - case CastNode cast -> new CastRISC(cast); - case CallEndNode cend -> new CallEndRISC(cend); + case CastNode cast -> new CastMach(cast); + case CallEndNode cend -> new CallEndMach(cend); case CProjNode c -> new CProjNode(c); case ConstantNode con -> con(con); case DivFNode divf -> new DivFRISC(divf); @@ -347,7 +347,7 @@ public class riscv extends Machine { case ParmNode parm -> new ParmRISC(parm); case PhiNode phi -> new PhiNode(phi); case ProjNode prj -> prj(prj); - case ReadOnlyNode read-> new ReadOnlyNode(read); + case ReadOnlyNode read-> new ReadOnlyMach(read); case ReturnNode ret -> new RetRISC(ret, ret.fun()); case SarNode sar -> sra(sar); case ShlNode shl -> sll(shl); @@ -420,7 +420,7 @@ public class riscv extends Machine { ? new SetIRISC(bool, (int)ti.value(),false) : new SetRISC(bool, false); // x <= y - flip and negate; !(y < x); `slt tmp=y,x; xori dst=tmp,#1` - case "<=" -> new XorIRISC(new SetRISC(bool.swap12(), false),1); + case "<=" -> new XorIRISC(new SetRISC(bool.swap12(), false),1,false); // x == y - sub and vs0 == `sub tmp=x-y; sltu dst=tmp,#1` case "==" -> new SetIRISC(new SubRISC(bool),1,true); default -> throw Utils.TODO(); @@ -443,12 +443,12 @@ public class riscv extends Machine { } // Need more complex sequence for larger constants... or a load // from a constant pool, which does not need an extra register - throw Utils.TODO(); + yield new Int8RISC(con); } // Load from constant pool case TypeFloat tf -> new FltRISC(con); case TypeFunPtr tfp -> new TFPRISC(con); - case TypeMemPtr tmp -> throw Utils.TODO(); + case TypeMemPtr tmp -> new TMPRISC(con); case TypeNil tn -> throw Utils.TODO(); // TOP, BOTTOM, XCtrl, Ctrl, etc. Never any executable code. case Type t -> t==Type.NIL ? new IntRISC(con) : new ConstantNode(con); diff --git a/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/AddIX86.java b/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/AddIX86.java index 569be754..050451f1 100644 --- a/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/AddIX86.java +++ b/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/AddIX86.java @@ -1,5 +1,8 @@ package com.seaofnodes.simple.node.cpus.x86_64_v2; +import com.seaofnodes.simple.SB; +import com.seaofnodes.simple.Utils; +import com.seaofnodes.simple.codegen.Encoding; import com.seaofnodes.simple.node.Node; public class AddIX86 extends ImmX86 { @@ -10,4 +13,12 @@ public class AddIX86 extends ImmX86 { @Override public String glabel() { return "+"; } @Override int opcode() { return 0x81; } @Override int mod() { return 0; } + @Override public final void encoding( Encoding enc ) { + if( _imm== 1 || _imm== -1 ) { + short dst = enc.reg(this); // Also src1 + enc.add1( x86_64_v2.rex(0,dst,0)); + enc.add1(0xFF); + enc.add1( x86_64_v2.modrm(x86_64_v2.MOD.DIRECT, _imm==1 ? 0 : 1, dst) ); + } else super.encoding(enc); + } } diff --git a/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/CallEndX86.java b/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/CallEndX86.java deleted file mode 100644 index ce8b993f..00000000 --- a/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/CallEndX86.java +++ /dev/null @@ -1,8 +0,0 @@ -package com.seaofnodes.simple.node.cpus.x86_64_v2; - -import com.seaofnodes.simple.node.CallEndNode; -import com.seaofnodes.simple.node.MachNode; - -public class CallEndX86 extends CallEndNode implements MachNode { - CallEndX86( CallEndNode cend ) { super(cend); } -} diff --git a/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/CallX86.java b/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/CallX86.java index c97037e2..4696c859 100644 --- a/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/CallX86.java +++ b/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/CallX86.java @@ -2,8 +2,7 @@ package com.seaofnodes.simple.node.cpus.x86_64_v2; import com.seaofnodes.simple.SB; import com.seaofnodes.simple.codegen.*; -import com.seaofnodes.simple.node.CallNode; -import com.seaofnodes.simple.node.MachNode; +import com.seaofnodes.simple.node.*; import com.seaofnodes.simple.type.TypeFunPtr; public class CallX86 extends CallNode implements MachNode, RIPRelSize { @@ -14,7 +13,8 @@ public class CallX86 extends CallNode implements MachNode, RIPRelSize { _inputs.pop(); // Pop constant target assert tfp.isConstant(); _tfp = tfp; - _name = CodeGen.CODE.link(tfp)._name; + FunNode fun = CodeGen.CODE.link(tfp); + _name = fun==null ? ((ExternNode)call.fptr())._extern : fun._name; // Can be null for extern calls } @Override public String op() { return "call"; } @Override public String label() { return op(); } @@ -25,7 +25,10 @@ public class CallX86 extends CallNode implements MachNode, RIPRelSize { @Override public int nargs() { return nIns()-2; } // Minus control, memory, fptr @Override public void encoding( Encoding enc ) { - enc.relo(this).add1(0xe8).add4(0); + FunNode fun = CodeGen.CODE.link(_tfp); + if( fun==null ) enc.external(this,_name); + else enc.relo(this); + enc.add1(0xe8).add4(0); } // Delta is from opcode start, but X86 measures from the end of the 5-byte encoding diff --git a/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/CastX86.java b/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/CastX86.java deleted file mode 100644 index 9537cfb3..00000000 --- a/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/CastX86.java +++ /dev/null @@ -1,16 +0,0 @@ -package com.seaofnodes.simple.node.cpus.x86_64_v2; - -import com.seaofnodes.simple.SB; -import com.seaofnodes.simple.codegen.*; -import com.seaofnodes.simple.node.CastNode; -import com.seaofnodes.simple.node.MachNode; - -public class CastX86 extends CastNode implements MachNode { - CastX86( CastNode cast ) { super(cast); } - @Override public String op() { return label(); } - @Override public RegMask regmap(int i) { assert i==1; return RegMask.FULL; } - @Override public RegMask outregmap() { return RegMask.FULL; } - @Override public int twoAddress( ) { return 1; } - @Override public void encoding( Encoding enc ) { } - @Override public void asm(CodeGen code, SB sb) { _t.print(sb.p(code.reg(in(1))).p(" isa ")); } -} diff --git a/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/CmpMemX86.java b/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/CmpMemX86.java index 489853eb..a1845363 100644 --- a/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/CmpMemX86.java +++ b/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/CmpMemX86.java @@ -11,7 +11,7 @@ public class CmpMemX86 extends MemOpX86 { CmpMemX86( BoolNode bool, LoadNode ld, Node base, Node idx, int off, int scale, int imm, Node val, boolean swap ) { super(bool,ld, base, idx, off, scale, imm, val ); _swap = swap; - assert !_swap || val() == null || bool.op()=="==" || bool.op()=="!="; // Cannot swap with immediate + assert !_swap || val() != null || bool.op()=="==" || bool.op()=="!="; // Cannot swap with immediate } @Override public String op() { return ((val()==null && _imm==0) ? "test" : "cmp") + _sz; } @Override public RegMask outregmap() { return x86_64_v2.FLAGS_MASK; } diff --git a/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/CmpX86.java b/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/CmpX86.java index 06a36d99..3e4200c0 100644 --- a/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/CmpX86.java +++ b/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/CmpX86.java @@ -9,6 +9,12 @@ public class CmpX86 extends MachConcreteNode implements MachNode { @Override public String op() { return "cmp"; } @Override public RegMask regmap(int i) { return x86_64_v2.RMASK; } @Override public RegMask outregmap() { return x86_64_v2.FLAGS_MASK; } + // This one is marginal: cloning a Cmp[reg,reg] means stretching the + // lifetimes of 2 normal registers in exchange for shortening a flags + // register lifetime. Spilling flags is (probably) relatively expensive + // compared to some normal registers - and those normal registers might not + // be spilling! + @Override public boolean isClone() { return true; } @Override public void encoding( Encoding enc ) { short dst = enc.reg(in(1)); diff --git a/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/DivX86.java b/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/DivX86.java index 87b8b0c3..06f001b0 100644 --- a/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/DivX86.java +++ b/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/DivX86.java @@ -8,7 +8,7 @@ public class DivX86 extends MachConcreteNode implements MachNode { DivX86( Node div ) { super(div); } @Override public String op() { return "div"; } @Override public RegMask regmap(int i) { - return (i==1) ? x86_64_v2.RAX_MASK : x86_64_v2.RMASK; + return (i==1) ? x86_64_v2.RAX_MASK : x86_64_v2.DIV_MASK; } @Override public RegMask outregmap() { return x86_64_v2.RAX_MASK; } @Override public RegMask killmap() { return x86_64_v2.RDX_MASK; } diff --git a/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/ImmX86.java b/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/ImmX86.java index 760d6805..95f617e7 100644 --- a/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/ImmX86.java +++ b/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/ImmX86.java @@ -15,11 +15,12 @@ public abstract class ImmX86 extends MachConcreteNode implements MachNode { @Override public RegMask regmap(int i) { return x86_64_v2.RMASK; } @Override public RegMask outregmap() { return x86_64_v2.WMASK; } @Override public int twoAddress() { return 1; } + @Override public RegMask killmap() { return x86_64_v2.FLAGS_MASK; } abstract int opcode(); abstract int mod(); - @Override public final void encoding( Encoding enc ) { + @Override public void encoding( Encoding enc ) { short dst = enc.reg(this); // Also src1 enc.add1(x86_64_v2.rex(0, dst, 0)); // opcode; 0x81 or 0x83; 0x69 or 0x6B diff --git a/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/MemAddX86.java b/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/MemAddX86.java index a97f3d9f..f0d01b3d 100644 --- a/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/MemAddX86.java +++ b/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/MemAddX86.java @@ -13,6 +13,7 @@ public class MemAddX86 extends MemOpX86 { } // Register mask allowed as a result. 0 for no register. @Override public RegMask outregmap() { return null; } + @Override public RegMask killmap() { return x86_64_v2.FLAGS_MASK; } @Override public void encoding( Encoding enc ) { // add something to memory // REX.W + 01 /r | REX.W + 81 /0 id @@ -23,11 +24,11 @@ public class MemAddX86 extends MemOpX86 { enc.add1(x86_64_v2.rex(src, ptr, idx)); // opcode - enc.add1( src == -1 ? 0x81: 0x01); + enc.add1( src == -1 ? (_imm==1 ? 0xFF : 0x81): 0x01); // includes modrm x86_64_v2.indirectAdr(_scale, idx, ptr, _off, src == -1 ? 0 : src, enc); - if( src == -1 ) enc.add4(_imm); + if( src == -1 && _imm!=1 ) enc.add4(_imm); } // General form: "add [base + idx<<2 + 12] += src" @Override public void asm(CodeGen code, SB sb) { diff --git a/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/MulIX86.java b/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/MulIX86.java index a9a83fb7..0dc16ab1 100644 --- a/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/MulIX86.java +++ b/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/MulIX86.java @@ -1,11 +1,34 @@ package com.seaofnodes.simple.node.cpus.x86_64_v2; -import com.seaofnodes.simple.node.Node; +import com.seaofnodes.simple.SB; +import com.seaofnodes.simple.node.*; +import com.seaofnodes.simple.codegen.*; -public class MulIX86 extends ImmX86 { - MulIX86( Node add, int imm ) { super(add,imm); } +public class MulIX86 extends MachConcreteNode implements MachNode { + final int _imm; + MulIX86( Node add, int imm ) { + super(add); + _inputs.pop(); // Pop the constant input + _imm = imm; // Record the constant + } @Override public String op() { return "muli"; } @Override public String glabel() { return "*"; } - @Override int opcode() { return 0x69; } - @Override int mod() { return 0; } + @Override public RegMask regmap(int i) { return x86_64_v2.RMASK; } + @Override public RegMask outregmap() { return x86_64_v2.WMASK; } + // Rare 3-address form + @Override public final void encoding( Encoding enc ) { + short dst = enc.reg(this ); // Also src1 + short src = enc.reg(in(1)); + enc.add1(x86_64_v2.rex(src, dst, 0)); + // opcode; 0x69 or 0x6B + enc.add1( 0x69 + (x86_64_v2.imm8(_imm) ? 2 : 0) ); + enc.add1( x86_64_v2.modrm(x86_64_v2.MOD.DIRECT, dst, src) ); + // immediate(4 bytes) 32 bits or (1 byte)8 bits + if( x86_64_v2.imm8(_imm) ) enc.add1(_imm); + else enc.add4(_imm); + } + // General form: "addi dst += #imm" + @Override public void asm(CodeGen code, SB sb) { + sb.p(code.reg(this)).p(" = ").p(code.reg(in(1))).p(" * #").p(_imm); + } } diff --git a/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/RegX86.java b/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/RegX86.java index 0997644d..a4a6a814 100644 --- a/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/RegX86.java +++ b/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/RegX86.java @@ -8,6 +8,7 @@ public abstract class RegX86 extends MachConcreteNode { RegX86( Node add ) { super(add); } @Override public RegMask regmap(int i) { return x86_64_v2.RMASK; } @Override public RegMask outregmap() { return x86_64_v2.WMASK; } + @Override public RegMask killmap() { return x86_64_v2.FLAGS_MASK; } @Override public int twoAddress() { return 1; } abstract int opcode(); @Override public void encoding( Encoding enc ) { diff --git a/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/SetX86.java b/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/SetX86.java index b2902086..775ea8eb 100644 --- a/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/SetX86.java +++ b/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/SetX86.java @@ -27,7 +27,7 @@ public class SetX86 extends MachConcreteNode implements MachNode { short dst = enc.reg(this ); // Optional rex, for dst - if( dst >= 8 ) enc.add1(x86_64_v2.rex(0, dst, 0)); + if( dst >= 4 ) enc.add1(x86_64_v2.rex(0, dst, 0, false)); enc.add1(0x0F); // opcode enc.add1(switch (_bop) { case "==" -> 0x94; // SETE @@ -39,7 +39,7 @@ public class SetX86 extends MachConcreteNode implements MachNode { enc.add1(x86_64_v2.modrm(x86_64_v2.MOD.DIRECT, 0, dst)); // low 8 bites are set, now zero extend for next instruction - if( dst >= 8 ) enc.add1(x86_64_v2.rex(0, dst, 0)); + if( dst >= 4 ) enc.add1(x86_64_v2.rex(dst, dst, 0, false)); enc.add1(0x0F); // opcode enc.add1(0xB6); // opcode enc.add1(x86_64_v2.modrm(x86_64_v2.MOD.DIRECT, dst, dst)); diff --git a/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/TFPX86.java b/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/TFPX86.java index be4d1a83..d7566f9e 100644 --- a/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/TFPX86.java +++ b/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/TFPX86.java @@ -63,4 +63,5 @@ public class TFPX86 extends ConstantNode implements MachNode, RIPRelSize { else _con.print(sb.p(reg).p(" = #")); } + @Override public boolean eq(Node n) { return this==n; } } diff --git a/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/TMPX86.java b/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/TMPX86.java new file mode 100644 index 00000000..c44cf2f9 --- /dev/null +++ b/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/TMPX86.java @@ -0,0 +1,35 @@ +package com.seaofnodes.simple.node.cpus.x86_64_v2; + +import com.seaofnodes.simple.SB; +import com.seaofnodes.simple.codegen.*; +import com.seaofnodes.simple.node.*; +import com.seaofnodes.simple.type.TypeMemPtr; + +public class TMPX86 extends ConstantNode implements MachNode, RIPRelSize{ + TMPX86(ConstantNode con ) { super(con); } + @Override public String op() { return "ldp"; } + @Override public RegMask regmap(int i) { return null; } + @Override public RegMask outregmap() { return x86_64_v2.WMASK; } + @Override public boolean isClone() { return true; } + @Override public Node copy() { return new TMPX86(this); } + + @Override public void encoding( Encoding enc ) { + short dst = enc.reg(this); + x86_64_v2.rexF(dst, 0, 0, true, enc); + enc.add1(0x8D).add1(x86_64_v2.modrm(x86_64_v2.MOD.INDIRECT, dst, 0b101)).add4(0); + enc.largeConstant(this,((TypeMemPtr)_con)._obj,7-4,2/*ELF encoding PC32*/); + } + + // Delta is from opcode start + @Override public byte encSize(int delta) { return (byte)7; } + + // Delta is from opcode start + @Override public void patch( Encoding enc, int opStart, int opLen, int delta ) { + enc.patch4(opStart+opLen-4,delta-opLen); + } + + @Override public void asm(CodeGen code, SB sb) { + _con.print(sb.p(code.reg(this)).p(" = #")); + } + @Override public boolean eq(Node n) { return this==n; } +} diff --git a/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/x86_64_v2.java b/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/x86_64_v2.java index 2b7fddb1..6706635f 100644 --- a/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/x86_64_v2.java +++ b/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/x86_64_v2.java @@ -43,6 +43,8 @@ public class x86_64_v2 extends Machine { static RegMask XMASK = new RegMask(FP_BITS); static RegMask FLAGS_MASK = new RegMask(FLAGS); static RegMask RPC_MASK = new RegMask(RPC); + // Divide mask: exclude RDX:RAX + static RegMask DIV_MASK = new RegMask(RD_BITS & ~(1L<= tfp.nargs() ) return null; // Anti-dependence return switch( CodeGen.CODE._callingConv ) { case "SystemV" -> callSys5 (tfp,idx,maxArgSlot); case "Win64" -> callWin64(tfp,idx,maxArgSlot); @@ -343,9 +346,9 @@ public class x86_64_v2 extends Machine { case AndNode and -> and(and); case BoolNode bool -> cmp(bool); case CProjNode c -> new CProjNode(c); - case CallEndNode cend -> new CallEndX86(cend); + case CallEndNode cend -> new CallEndMach(cend); case CallNode call -> call(call); - case CastNode cast -> new CastX86(cast); + case CastNode cast -> new CastMach(cast); case ConstantNode con -> con(con); case DivFNode divf -> new DivFX86(divf); case DivNode div -> new DivX86(div); @@ -362,7 +365,7 @@ public class x86_64_v2 extends Machine { case ParmNode parm -> new ParmX86(parm); case PhiNode phi -> new PhiNode(phi); case ProjNode prj -> prj(prj); - case ReadOnlyNode read-> new ReadOnlyNode(read); + case ReadOnlyNode read-> new ReadOnlyMach(read); case ReturnNode ret -> new RetX86(ret, ret.fun()); case SarNode sar -> sar(sar); case ShlNode shl -> shl(shl); @@ -499,15 +502,16 @@ public class x86_64_v2 extends Machine { } private Node con( ConstantNode con ) { - if(!con._con.isConstant()) return new ConstantNode(con); // Default unknown caller inputs + if( !con._con.isConstant() ) + return new ConstantNode(con); // Default unknown caller inputs return switch (con._con) { - case TypeInteger ti -> new IntX86(con); - case TypeFloat tf -> new FltX86(con); - case TypeFunPtr tfp -> new TFPX86(con); - case TypeMemPtr tmp -> throw Utils.TODO(); - case TypeNil tn -> throw Utils.TODO(); - // TOP, BOTTOM, XCtrl, Ctrl, etc. Never any executable code. - case Type t -> t == Type.NIL ? new IntX86(con) : new ConstantNode(con); + case TypeInteger ti -> new IntX86(con); + case TypeFloat tf -> new FltX86(con); + case TypeFunPtr tfp -> new TFPX86(con); + case TypeMemPtr tmp -> new TMPX86(con); + case TypeNil tn -> throw Utils.TODO(); + // TOP, BOTTOM, XCtrl, Ctrl, etc. Never any executable code. + case Type t -> t == Type.NIL ? new IntX86(con) : new ConstantNode(con); }; } -- cgit v1.2.3