summaryrefslogtreecommitdiff
path: root/chapter22/src
diff options
context:
space:
mode:
Diffstat (limited to 'chapter22/src')
-rw-r--r--chapter22/src/main/java/com/seaofnodes/simple/Parser.java3
-rw-r--r--chapter22/src/main/java/com/seaofnodes/simple/codegen/BuildLRG.java2
-rw-r--r--chapter22/src/main/java/com/seaofnodes/simple/codegen/CodeGen.java18
-rw-r--r--chapter22/src/main/java/com/seaofnodes/simple/codegen/Encoding.java2
-rw-r--r--chapter22/src/main/java/com/seaofnodes/simple/codegen/GlobalCodeMotion.java44
-rw-r--r--chapter22/src/main/java/com/seaofnodes/simple/codegen/IFG.java8
-rw-r--r--chapter22/src/main/java/com/seaofnodes/simple/codegen/Machine.java8
-rw-r--r--chapter22/src/main/java/com/seaofnodes/simple/codegen/RegAlloc.java25
-rw-r--r--chapter22/src/main/java/com/seaofnodes/simple/codegen/RegMask.java6
-rw-r--r--chapter22/src/main/java/com/seaofnodes/simple/node/CFGNode.java5
-rw-r--r--chapter22/src/main/java/com/seaofnodes/simple/node/CallEndNode.java6
-rw-r--r--chapter22/src/main/java/com/seaofnodes/simple/node/FunNode.java7
-rw-r--r--chapter22/src/main/java/com/seaofnodes/simple/node/LoopNode.java4
-rw-r--r--chapter22/src/main/java/com/seaofnodes/simple/node/NewNode.java4
-rw-r--r--chapter22/src/main/java/com/seaofnodes/simple/node/RegionNode.java7
-rw-r--r--chapter22/src/main/java/com/seaofnodes/simple/node/StartNode.java2
-rw-r--r--chapter22/src/main/java/com/seaofnodes/simple/node/StoreNode.java8
-rw-r--r--chapter22/src/main/java/com/seaofnodes/simple/node/cpus/arm/CallARM.java2
-rw-r--r--chapter22/src/main/java/com/seaofnodes/simple/node/cpus/arm/CallRRARM.java2
-rw-r--r--chapter22/src/main/java/com/seaofnodes/simple/node/cpus/arm/ParmARM.java2
-rw-r--r--chapter22/src/main/java/com/seaofnodes/simple/node/cpus/arm/arm.java8
-rw-r--r--chapter22/src/main/java/com/seaofnodes/simple/node/cpus/riscv/CallRISC.java2
-rw-r--r--chapter22/src/main/java/com/seaofnodes/simple/node/cpus/riscv/CallRRISC.java2
-rw-r--r--chapter22/src/main/java/com/seaofnodes/simple/node/cpus/riscv/ParmRISC.java2
-rw-r--r--chapter22/src/main/java/com/seaofnodes/simple/node/cpus/riscv/StoreRISC.java2
-rw-r--r--chapter22/src/main/java/com/seaofnodes/simple/node/cpus/riscv/riscv.java5
-rw-r--r--chapter22/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/CallRX86.java2
-rw-r--r--chapter22/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/CallX86.java2
-rw-r--r--chapter22/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/ParmX86.java2
-rw-r--r--chapter22/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/SplitX86.java11
-rw-r--r--chapter22/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/StoreX86.java2
-rw-r--r--chapter22/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/x86_64_v2.java18
-rw-r--r--chapter22/src/test/java/com/seaofnodes/simple/Chapter21Test.java3
-rw-r--r--chapter22/src/test/java/com/seaofnodes/simple/Chapter22Test.java2
34 files changed, 156 insertions, 72 deletions
diff --git a/chapter22/src/main/java/com/seaofnodes/simple/Parser.java b/chapter22/src/main/java/com/seaofnodes/simple/Parser.java
index 21d6c359..07fbdd5b 100644
--- a/chapter22/src/main/java/com/seaofnodes/simple/Parser.java
+++ b/chapter22/src/main/java/com/seaofnodes/simple/Parser.java
@@ -653,7 +653,8 @@ public class Parser {
// Make finals deep; widen ints to floats; narrow wide int types.
// Early error if types do not match variable.
private Node liftExpr( Node expr, Type t, boolean xfinal ) {
- assert !(expr._type instanceof TypeMemPtr tmp) || !tmp.isFRef();
+ if( expr._type instanceof TypeMemPtr tmp && tmp.isFRef() )
+ throw error("Must define forward ref "+tmp._obj._name);
// Final is deep on ptrs
if( xfinal && t instanceof TypeMemPtr tmp ) {
t = tmp.makeRO();
diff --git a/chapter22/src/main/java/com/seaofnodes/simple/codegen/BuildLRG.java b/chapter22/src/main/java/com/seaofnodes/simple/codegen/BuildLRG.java
index a2bb21ed..e9b5eb2e 100644
--- a/chapter22/src/main/java/com/seaofnodes/simple/codegen/BuildLRG.java
+++ b/chapter22/src/main/java/com/seaofnodes/simple/codegen/BuildLRG.java
@@ -63,7 +63,7 @@ abstract public class BuildLRG {
}
// MultiNodes have projections which set registers
- if( n instanceof MultiNode )
+ if( n instanceof MultiNode && !(n instanceof CFGNode) )
for( Node proj : n.outs() )
if( proj instanceof MachNode )
defLRG(alloc,proj);
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 74fa1f71..874f850b 100644
--- a/chapter22/src/main/java/com/seaofnodes/simple/codegen/CodeGen.java
+++ b/chapter22/src/main/java/com/seaofnodes/simple/codegen/CodeGen.java
@@ -89,6 +89,24 @@ public class CodeGen {
public int getALIAS() { return _alias++; }
+ // idepths are cached and valid until *inserting* CFG edges (deleting is
+ // OK). This happens with inlining, which bumps the version to bulk
+ // invalidate the idepth caches.
+ private int _iDepthVersion = 0;
+ public void invalidateIDepthCaches() { _iDepthVersion++; }
+ public boolean validIDepth(int idepth) {
+ if( idepth==0 ) return false;
+ if( _iDepthVersion==0 ) return true;
+ return (idepth%100)==_iDepthVersion;
+ }
+ public int iDepthAt(int idepth) {
+ return 100*idepth+_iDepthVersion;
+ }
+ public int iDepthFrom(int idepth) {
+ assert idepth==0 || validIDepth(idepth);
+ return idepth+100;
+ }
+
// Popular visit bitset, declared here, so it gets reused all over
public final BitSet _visit = new BitSet();
public BitSet visit() { assert _visit.isEmpty(); return _visit; }
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 f4b2ab69..7a43f099 100644
--- a/chapter22/src/main/java/com/seaofnodes/simple/codegen/Encoding.java
+++ b/chapter22/src/main/java/com/seaofnodes/simple/codegen/Encoding.java
@@ -322,7 +322,6 @@ public class Encoding {
if( !(bb instanceof MachNode mach0) )
_opStart[bb._nid] = _bits.size();
else if( bb instanceof FunNode fun ) {
- padN(16,_bits);
_fun = fun; // Currently encoding function
_opStart[bb._nid] = _bits.size();
mach0.encoding( this );
@@ -336,7 +335,6 @@ public class Encoding {
}
}
}
- padN(16,_bits);
}
// --------------------------------------------------
diff --git a/chapter22/src/main/java/com/seaofnodes/simple/codegen/GlobalCodeMotion.java b/chapter22/src/main/java/com/seaofnodes/simple/codegen/GlobalCodeMotion.java
index f76b35ef..3de66626 100644
--- a/chapter22/src/main/java/com/seaofnodes/simple/codegen/GlobalCodeMotion.java
+++ b/chapter22/src/main/java/com/seaofnodes/simple/codegen/GlobalCodeMotion.java
@@ -166,10 +166,10 @@ public abstract class GlobalCodeMotion {
!(memuse instanceof NewNode) &&
// Load-use directly defines memory
(memuse._type instanceof TypeMem ||
+ // Load-use directly defines memory
+ memuse instanceof CallNode ||
// Load-use indirectly defines memory
- (memuse._type instanceof TypeTuple tt && tt._types[ld._alias] instanceof TypeMem) ||
- // Load-use use/defs memory
- memuse instanceof CallNode) )
+ (memuse._type instanceof TypeTuple tt && tt._types[ld._alias] instanceof TypeMem)) )
continue outer;
// All uses done, schedule
@@ -201,6 +201,33 @@ public abstract class GlobalCodeMotion {
if( n instanceof MemOpNode load && load._isLoad )
lca = find_anti_dep(lca,load,early,late);
+
+ // Nodes setting a single register and getting killed will stay close
+ // to the uses, since they will be forced to spill anyway. The kill
+ // check is very weak, and some may be hoisted only to spill in the RA.
+ if( n instanceof MachNode mach ) {
+ RegMask out = mach.outregmap();
+ if( out!=null && out.size1() ) {
+ int reg = mach.outregmap().firstReg();
+ // Look for kills
+ outer:
+ for( CFGNode lca2=lca; lca2 != early; lca2 = lca2.idom() ) {
+ if( lca2 instanceof MachNode mach2 ) {
+ for( int i=1; i<lca2.nIns(); i++ ) {
+ RegMask mask = mach2.regmap(i);
+ if( mask!=null && mask.test(reg) ) {
+ early = lca2 instanceof IfNode ? lca2.idom() : lca2;
+ break outer;
+ }
+ }
+ RegMask kill = mach2.killmap();
+ if( kill != null )
+ throw Utils.TODO();
+ }
+ }
+ }
+ }
+
// Walk up from the LCA to the early, looking for best place. This is
// the lowest execution frequency, approximated by least loop depth and
// deepest control flow.
@@ -232,8 +259,9 @@ public abstract class GlobalCodeMotion {
// Least loop depth first, then largest idepth
private static boolean better( CFGNode lca, CFGNode best ) {
return lca.loopDepth() < best.loopDepth() ||
- lca instanceof NeverNode ||
- (lca.idepth() > best.idepth() || best instanceof IfNode);
+ lca instanceof NeverNode ||
+ lca.idepth() > best.idepth() ||
+ best instanceof IfNode;
}
private static CFGNode find_anti_dep(CFGNode lca, MemOpNode load, CFGNode early, CFGNode[] late) {
@@ -250,9 +278,9 @@ public abstract class GlobalCodeMotion {
lca = anti_dep( load, late[mem._nid], mem.cfg0(), lca, st );
}
break; // Loads do not cause anti-deps on other loads
- case CallNode st:
- assert late[st._nid]!=null;
- lca = anti_dep(load,late[st._nid],st.cfg0(),lca,st);
+ case CallNode call:
+ assert late[call._nid]!=null;
+ lca = anti_dep(load,late[call._nid],call.cfg0(),lca,call);
break;
case PhiNode phi:
// Repeat anti-dep for matching Phi inputs.
diff --git a/chapter22/src/main/java/com/seaofnodes/simple/codegen/IFG.java b/chapter22/src/main/java/com/seaofnodes/simple/codegen/IFG.java
index 81955779..fdd4e2f9 100644
--- a/chapter22/src/main/java/com/seaofnodes/simple/codegen/IFG.java
+++ b/chapter22/src/main/java/com/seaofnodes/simple/codegen/IFG.java
@@ -242,14 +242,12 @@ abstract public class IFG {
private static void mergeLiveOut( RegAlloc alloc, CFGNode priorbb, int i ) {
CFGNode bb = priorbb.cfg(i);
if( bb == null ) return; // Start has no prior
- if( !bb.blockHead() ) bb = bb.cfg0();
- //if( i==0 && !(bb instanceof StartNode) ) bb = bb.cfg0();
- assert bb.blockHead();
+ while( !bb.blockHead() ) bb = bb.cfg0();
// Lazy get live-out set for bb
- IdentityHashMap<LRG, Node> lrgs = BBOUTS.computeIfAbsent( bb, k -> new IdentityHashMap<>() );
+ IdentityHashMap<LRG, Node> lrgs = BBOUTS.computeIfAbsent( bb, k -> new IdentityHashMap<>() );
- for( LRG lrg : TMP.keySet() ) {
+ for( LRG lrg : TMP.keySet() ) {
Node def = TMP.get(lrg);
// Effective def comes from phi input from prior block
if( def instanceof PhiNode phi && phi.cfg0()==priorbb ) {
diff --git a/chapter22/src/main/java/com/seaofnodes/simple/codegen/Machine.java b/chapter22/src/main/java/com/seaofnodes/simple/codegen/Machine.java
index 1c12bfcb..2766414f 100644
--- a/chapter22/src/main/java/com/seaofnodes/simple/codegen/Machine.java
+++ b/chapter22/src/main/java/com/seaofnodes/simple/codegen/Machine.java
@@ -16,8 +16,12 @@ abstract public class Machine {
public abstract long callerSave();
// List of never-save registers, e.g. RSP or a ZERO register if you have one
public abstract long neverSave();
- // Call Argument Mask
- public abstract RegMask callArgMask(TypeFunPtr tfp, int arg);
+ // Call Argument Mask. Passed in the function signature and argument
+ // number (2-based; 0 is for control and 1 for memory). Also passed in a 0
+ // for the function itself, or for *outgoing* calls, the maximum stack slot
+ // given to the incoming function arguments (stack slots reserved for
+ // incoming arguments).
+ public abstract RegMask callArgMask(TypeFunPtr tfp, int arg, int maxArgSlot);
// Return register mask, based on signature (GPR vs FPR)
public abstract RegMask retMask(TypeFunPtr tfp);
// Return PC register
diff --git a/chapter22/src/main/java/com/seaofnodes/simple/codegen/RegAlloc.java b/chapter22/src/main/java/com/seaofnodes/simple/codegen/RegAlloc.java
index e4a48750..f68caf91 100644
--- a/chapter22/src/main/java/com/seaofnodes/simple/codegen/RegAlloc.java
+++ b/chapter22/src/main/java/com/seaofnodes/simple/codegen/RegAlloc.java
@@ -262,7 +262,7 @@ public class RegAlloc {
}
// Single-def live range with an empty mask. There are many single-reg
- // uses. Theory is there's many repeats if the same reg amongst the uses.
+ // uses. Theory is there's many repeats of the same reg amongst the uses.
// In of splitting once per use, start by splitting into groups based on
// required input register.
boolean splitEmptyMaskByUse( byte round, LRG lrg ) {
@@ -271,20 +271,27 @@ public class RegAlloc {
// Look at each use, and break into non-overlapping register classes.
Ary<RegMask> rclass = new Ary<>(RegMask.class);
boolean done=false;
+ int ncalls=0;
while( !done ) {
done = true;
for( Node use : def._outputs )
- if( use instanceof MachNode mach )
+ if( use instanceof MachNode mach ) {
+ if( mach instanceof CallNode ) ncalls++;
for( int i=1; i<use.nIns(); i++ )
if( use.in(i)==def )
done = putIntoRegClass( rclass, mach.regmap(i) );
+ }
}
- // See how many register classes we split into
- if( rclass._len <= 1 ) return false;
+ // See how many register classes we split into. Generally not
+ // productive to split like this across calls, which are going to kill
+ // all registers anyways.
+ if( rclass._len <= 1 || ncalls > 1 ) return false;
// Split by class
+ Ary<Node> ns = new Ary<>(Node.class);
for( RegMask rmask : rclass ) {
+ ns.addAll(def._outputs);
Node split = makeSplit(def,"popular",round,lrg,rmask);
split.insertAfter( def );
if( split.nIns()>1 ) split.setDef(1,def);
@@ -295,11 +302,15 @@ public class RegAlloc {
// Check all use inputs for n, in case there's several
for( int i = 1; i < use.nIns(); i++ )
// Find a def input, and check register class
- if( use.in( i ) == def && mach.regmap( i ).overlap( rmask ) )
- // Modify use to use the split version specialized to this rclass
- { use.setDef( i, split ); j--; break; }
+ if( use.in( i ) == def && mach.regmap( i ).overlap( rmask ) ) {
+ RegMask m = mach.regmap( i );
+ if( m!=null && mach.regmap( i ).overlap( rmask ) )
+ // Modify use to use the split version specialized to this rclass
+ { use.setDefOrdered( i, split ); j--; break; }
+ }
}
}
+ ns.clear();
}
return true;
}
diff --git a/chapter22/src/main/java/com/seaofnodes/simple/codegen/RegMask.java b/chapter22/src/main/java/com/seaofnodes/simple/codegen/RegMask.java
index 79de3fbf..ec0c4e30 100644
--- a/chapter22/src/main/java/com/seaofnodes/simple/codegen/RegMask.java
+++ b/chapter22/src/main/java/com/seaofnodes/simple/codegen/RegMask.java
@@ -4,11 +4,11 @@ import com.seaofnodes.simple.Utils;
import com.seaofnodes.simple.SB;
/** RegMask
- * A "register mask" - 1 bit set for each allowed register. In addition
+ * A "register mask" - 1 bit set for each allowed register. In addition,
* "stack slot" registers may be allowed, effectively making the set infinite.
* <p>
* For smaller and simpler machines it suffices to make such masks an i64 or
- * i128 (64 or 128 bit integers), and this presentation is by far the better
+ * i128 (64- or 128-bit integers), and this presentation is by far the better
* way to go... if all register allocations can fit in this bit limitation.
* The allocator will need bits for stack-based parameters and for splits
* which cannot get a register. For a 32-register machine like the X86, add 1
@@ -28,7 +28,7 @@ public class RegMask {
public RegMask(int bit) {
if( bit < 64 ) _bits0 = 1L<<bit;
- else _bits1 = 1L<<(bit=64);
+ else _bits1 = 1L<<(bit-64);
}
public RegMask(long bits ) { _bits0 = bits; }
public RegMask(long bits0, long bits1 ) { _bits0 = bits0; _bits1 = bits1; }
diff --git a/chapter22/src/main/java/com/seaofnodes/simple/node/CFGNode.java b/chapter22/src/main/java/com/seaofnodes/simple/node/CFGNode.java
index 96597648..1dddc171 100644
--- a/chapter22/src/main/java/com/seaofnodes/simple/node/CFGNode.java
+++ b/chapter22/src/main/java/com/seaofnodes/simple/node/CFGNode.java
@@ -3,6 +3,7 @@ package com.seaofnodes.simple.node;
import com.seaofnodes.simple.Ary;
import com.seaofnodes.simple.Parser;
import com.seaofnodes.simple.Utils;
+import com.seaofnodes.simple.codegen.CodeGen;
import com.seaofnodes.simple.type.*;
import java.util.BitSet;
import java.util.HashMap;
@@ -72,7 +73,9 @@ public abstract class CFGNode extends Node {
* See {@link <a href="https://en.wikipedia.org/wiki/Dominator_(graph_theory)">...</a>}
*/
public int _idepth;
- public int idepth() { return _idepth==0 ? (_idepth=idom().idepth()+1) : _idepth; }
+ public int idepth() {
+ return CodeGen.CODE.validIDepth(_idepth) ? _idepth : (_idepth=CodeGen.CODE.iDepthFrom(idom().idepth()));
+ }
// Return the immediate dominator of this Node and compute dom tree depth.
public CFGNode idom(Node dep) { return cfg(0); }
diff --git a/chapter22/src/main/java/com/seaofnodes/simple/node/CallEndNode.java b/chapter22/src/main/java/com/seaofnodes/simple/node/CallEndNode.java
index e1d8aee5..7a331deb 100644
--- a/chapter22/src/main/java/com/seaofnodes/simple/node/CallEndNode.java
+++ b/chapter22/src/main/java/com/seaofnodes/simple/node/CallEndNode.java
@@ -69,8 +69,9 @@ public class CallEndNode extends CFGNode implements MultiNode {
assert fun.in(1) instanceof StartNode && fun.in(2)==call;
// Disallow self-recursive inlining (loop unrolling by another name)
CFGNode idom = call;
- while( !(idom instanceof FunNode fun2) )
+ while( !(idom instanceof FunNode) )
idom = idom.idom();
+ // Inline?
if( idom != fun ) {
// Trivial inline: rewrite
_folding = true;
@@ -80,6 +81,9 @@ public class CallEndNode extends CFGNode implements MultiNode {
fun.setDef(2,call.ctrl()); // Bypass the Call;
fun.ret().setDef(3,null); // Return is folding also
CodeGen.CODE.addAll(fun._outputs);
+ // Inlining immediately blows all cache idepth fields past the inline point.
+ // Bump the global version number invalidating them en-masse.
+ CodeGen.CODE.invalidateIDepthCaches();
return this;
}
} else {
diff --git a/chapter22/src/main/java/com/seaofnodes/simple/node/FunNode.java b/chapter22/src/main/java/com/seaofnodes/simple/node/FunNode.java
index c469fc96..f19e1cd6 100644
--- a/chapter22/src/main/java/com/seaofnodes/simple/node/FunNode.java
+++ b/chapter22/src/main/java/com/seaofnodes/simple/node/FunNode.java
@@ -119,8 +119,11 @@ public class FunNode extends RegionNode {
return null;
}
- // Bypass Region idom, always assume depth == 1, one more than Start
- @Override public int idepth() { return (_idepth=1); }
+ // Bypass Region idom, always assume depth == 1, one more than Start,
+ // unless folding then just a ID on input#1
+ @Override public int idepth() {
+ return _folding ? super.idepth() : CodeGen.CODE.iDepthAt(1);
+ }
// Bypass Region idom, always assume idom is Start
@Override public CFGNode idom(Node dep) { return cfg(1); }
diff --git a/chapter22/src/main/java/com/seaofnodes/simple/node/LoopNode.java b/chapter22/src/main/java/com/seaofnodes/simple/node/LoopNode.java
index cacf9c99..ec9055dc 100644
--- a/chapter22/src/main/java/com/seaofnodes/simple/node/LoopNode.java
+++ b/chapter22/src/main/java/com/seaofnodes/simple/node/LoopNode.java
@@ -26,7 +26,9 @@ public class LoopNode extends RegionNode {
}
// Bypass Region idom, same as the default idom() using use in(1) instead of in(0)
- @Override public int idepth() { return _idepth==0 ? (_idepth=idom().idepth()+1) : _idepth; }
+ @Override public int idepth() {
+ return CodeGen.CODE.validIDepth(_idepth) ? _idepth : (_idepth=CodeGen.CODE.iDepthFrom(idom().idepth()));
+ }
// Bypass Region idom, same as the default idom() using use in(1) instead of in(0)
@Override public CFGNode idom(Node dep) { return entry(); }
diff --git a/chapter22/src/main/java/com/seaofnodes/simple/node/NewNode.java b/chapter22/src/main/java/com/seaofnodes/simple/node/NewNode.java
index 3d4bad5e..5a8c1b6b 100644
--- a/chapter22/src/main/java/com/seaofnodes/simple/node/NewNode.java
+++ b/chapter22/src/main/java/com/seaofnodes/simple/node/NewNode.java
@@ -90,8 +90,8 @@ public class NewNode extends Node implements MultiNode {
private RegMask _retMask;
private RegMask _kills;
public void cacheRegs(CodeGen code) {
- _arg2Reg = code._mach.callArgMask(TypeFunPtr.CALLOC,2).firstReg();
- _arg3Mask = code._mach.callArgMask(TypeFunPtr.CALLOC,3);
+ _arg2Reg = code._mach.callArgMask(TypeFunPtr.CALLOC,2,0).firstReg();
+ _arg3Mask = code._mach.callArgMask(TypeFunPtr.CALLOC,3,0);
// Return mask depends on TFP (either GPR or FPR)
_retMask = code._mach.retMask(TypeFunPtr.CALLOC);
// Kill mask is all caller-saves, and any mirror stack slots for args
diff --git a/chapter22/src/main/java/com/seaofnodes/simple/node/RegionNode.java b/chapter22/src/main/java/com/seaofnodes/simple/node/RegionNode.java
index 8c56feff..8f65d0e5 100644
--- a/chapter22/src/main/java/com/seaofnodes/simple/node/RegionNode.java
+++ b/chapter22/src/main/java/com/seaofnodes/simple/node/RegionNode.java
@@ -141,12 +141,13 @@ public class RegionNode extends CFGNode {
// Immediate dominator of Region is a little more complicated.
@Override public int idepth() {
- if( _idepth!=0 ) return _idepth;
+ if( CodeGen.CODE.validIDepth(_idepth) )
+ return _idepth;
int d=0;
for( Node n : _inputs )
if( n!=null )
- d = Math.max(d,((CFGNode)n).idepth()+1);
- return _idepth=d;
+ d = Math.max(d,CodeGen.CODE.iDepthFrom(((CFGNode)n).idepth()));
+ return _idepth = d;
}
@Override public CFGNode idom(Node dep) {
diff --git a/chapter22/src/main/java/com/seaofnodes/simple/node/StartNode.java b/chapter22/src/main/java/com/seaofnodes/simple/node/StartNode.java
index 4bd76f50..f40203b4 100644
--- a/chapter22/src/main/java/com/seaofnodes/simple/node/StartNode.java
+++ b/chapter22/src/main/java/com/seaofnodes/simple/node/StartNode.java
@@ -51,7 +51,7 @@ public class StartNode extends LoopNode implements MultiNode {
@Override public Node idealize() { return null; }
// No immediate dominator, and idepth==0
- @Override public int idepth() { return 0; }
+ @Override public int idepth() { return CodeGen.CODE.iDepthAt(0); }
@Override public CFGNode idom(Node dep) { return null; }
}
diff --git a/chapter22/src/main/java/com/seaofnodes/simple/node/StoreNode.java b/chapter22/src/main/java/com/seaofnodes/simple/node/StoreNode.java
index 0beef65c..4b73ac1b 100644
--- a/chapter22/src/main/java/com/seaofnodes/simple/node/StoreNode.java
+++ b/chapter22/src/main/java/com/seaofnodes/simple/node/StoreNode.java
@@ -84,6 +84,12 @@ public class StoreNode extends MemOpNode {
}
}
+ // Store of zero after alloc
+ if( mem() instanceof ProjNode prj && prj.in(0) instanceof NewNode &&
+ prj.in(0)==ptr().in(0) && // Same NewNode memory & pointer
+ (val()._type==TypeInteger.ZERO || val()._type==Type.NIL ) )
+ return mem();
+
// TODO: Needs more love: the shift amount depends on the store size
//if( val() instanceof SarNode shr &&
// shr.in(1) instanceof ShlNode shl &&
@@ -114,8 +120,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/chapter22/src/main/java/com/seaofnodes/simple/node/cpus/arm/CallARM.java b/chapter22/src/main/java/com/seaofnodes/simple/node/cpus/arm/CallARM.java
index d5e12b7f..989bd366 100644
--- a/chapter22/src/main/java/com/seaofnodes/simple/node/cpus/arm/CallARM.java
+++ b/chapter22/src/main/java/com/seaofnodes/simple/node/cpus/arm/CallARM.java
@@ -21,7 +21,7 @@ public class CallARM extends CallNode implements MachNode, RIPRelSize {
@Override public String label() { return op(); }
@Override public String name() { return _name; }
@Override public TypeFunPtr tfp() { return _tfp; }
- @Override public RegMask regmap(int i) { return arm.callInMask(_tfp,i); }
+ @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
diff --git a/chapter22/src/main/java/com/seaofnodes/simple/node/cpus/arm/CallRRARM.java b/chapter22/src/main/java/com/seaofnodes/simple/node/cpus/arm/CallRRARM.java
index b3f55659..87dde38c 100644
--- a/chapter22/src/main/java/com/seaofnodes/simple/node/cpus/arm/CallRRARM.java
+++ b/chapter22/src/main/java/com/seaofnodes/simple/node/cpus/arm/CallRRARM.java
@@ -11,7 +11,7 @@ public class CallRRARM extends CallNode implements MachNode {
@Override public RegMask regmap(int i) {
return i==_inputs._len
? arm.RMASK // Function call target
- : arm.callInMask(tfp(),i); // Normal argument
+ : arm.callInMask(tfp(),i,fun()._maxArgSlot); // Normal argument
}
@Override public RegMask outregmap() { return null; }
diff --git a/chapter22/src/main/java/com/seaofnodes/simple/node/cpus/arm/ParmARM.java b/chapter22/src/main/java/com/seaofnodes/simple/node/cpus/arm/ParmARM.java
index 4d0f95ab..b419fe0a 100644
--- a/chapter22/src/main/java/com/seaofnodes/simple/node/cpus/arm/ParmARM.java
+++ b/chapter22/src/main/java/com/seaofnodes/simple/node/cpus/arm/ParmARM.java
@@ -9,7 +9,7 @@ public class ParmARM extends ParmNode implements MachNode {
final RegMask _rmask;
ParmARM(ParmNode parm) {
super(parm);
- _rmask = arm.callInMask(fun().sig(),_idx);
+ _rmask = arm.callInMask(fun().sig(),_idx,0);
}
@Override public RegMask regmap(int i) { return null; }
@Override public RegMask outregmap() { return _rmask; }
diff --git a/chapter22/src/main/java/com/seaofnodes/simple/node/cpus/arm/arm.java b/chapter22/src/main/java/com/seaofnodes/simple/node/cpus/arm/arm.java
index 88a2e8c5..e6f64158 100644
--- a/chapter22/src/main/java/com/seaofnodes/simple/node/cpus/arm/arm.java
+++ b/chapter22/src/main/java/com/seaofnodes/simple/node/cpus/arm/arm.java
@@ -563,10 +563,11 @@ public class arm extends Machine {
return (opcode << 26) | delta;
}
- @Override public RegMask callArgMask(TypeFunPtr tfp, int idx ) { return callInMask(tfp,idx); }
- static RegMask callInMask(TypeFunPtr tfp, int idx ) {
+ @Override public RegMask callArgMask(TypeFunPtr tfp, int idx, int maxArgSlot ) { return callInMask(tfp,idx,maxArgSlot); }
+ static RegMask callInMask(TypeFunPtr tfp, int idx, int maxArgSlot ) {
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;
@@ -789,8 +790,7 @@ public class arm extends Machine {
private static int off;
private static Node idx;
private Node st(StoreNode st) {
- Node xval = st.val() instanceof ConstantNode con && con._con == TypeInteger.ZERO ? null : st.val();
- return new StoreARM(address(st),st.ptr(),idx,off,xval);
+ return new StoreARM(address(st),st.ptr(),idx,off,st.val());
}
// Gather addressing mode bits prior to constructing. This is a builder
diff --git a/chapter22/src/main/java/com/seaofnodes/simple/node/cpus/riscv/CallRISC.java b/chapter22/src/main/java/com/seaofnodes/simple/node/cpus/riscv/CallRISC.java
index daef60f2..89b2c865 100644
--- a/chapter22/src/main/java/com/seaofnodes/simple/node/cpus/riscv/CallRISC.java
+++ b/chapter22/src/main/java/com/seaofnodes/simple/node/cpus/riscv/CallRISC.java
@@ -21,7 +21,7 @@ public class CallRISC extends CallNode implements MachNode, RIPRelSize {
@Override public String label() { return op(); }
@Override public String name() { return _name; }
@Override public TypeFunPtr tfp() { return _tfp; }
- @Override public RegMask regmap(int i) { return riscv.callInMask(_tfp,i); }
+ @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
diff --git a/chapter22/src/main/java/com/seaofnodes/simple/node/cpus/riscv/CallRRISC.java b/chapter22/src/main/java/com/seaofnodes/simple/node/cpus/riscv/CallRRISC.java
index 2afbbfa9..dcc53cbf 100644
--- a/chapter22/src/main/java/com/seaofnodes/simple/node/cpus/riscv/CallRRISC.java
+++ b/chapter22/src/main/java/com/seaofnodes/simple/node/cpus/riscv/CallRRISC.java
@@ -11,7 +11,7 @@ public class CallRRISC extends CallNode implements MachNode {
@Override public RegMask regmap(int i) {
return i==_inputs._len-1
? riscv.RMASK // Function call target
- : riscv.callInMask(tfp(),i); // Normal argument
+ : riscv.callInMask(tfp(),i,fun()._maxArgSlot); // Normal argument
}
@Override public RegMask outregmap() { return null; }
diff --git a/chapter22/src/main/java/com/seaofnodes/simple/node/cpus/riscv/ParmRISC.java b/chapter22/src/main/java/com/seaofnodes/simple/node/cpus/riscv/ParmRISC.java
index 02d53560..0f8db4e5 100644
--- a/chapter22/src/main/java/com/seaofnodes/simple/node/cpus/riscv/ParmRISC.java
+++ b/chapter22/src/main/java/com/seaofnodes/simple/node/cpus/riscv/ParmRISC.java
@@ -9,7 +9,7 @@ public class ParmRISC extends ParmNode implements MachNode {
final RegMask _rmask;
ParmRISC(ParmNode parm) {
super(parm);
- _rmask = riscv.callInMask(fun().sig(),_idx);
+ _rmask = riscv.callInMask(fun().sig(),_idx,0);
}
@Override public RegMask regmap(int i) { return null; }
@Override public RegMask outregmap() { return _rmask; }
diff --git a/chapter22/src/main/java/com/seaofnodes/simple/node/cpus/riscv/StoreRISC.java b/chapter22/src/main/java/com/seaofnodes/simple/node/cpus/riscv/StoreRISC.java
index d34d94fc..7305c4d9 100644
--- a/chapter22/src/main/java/com/seaofnodes/simple/node/cpus/riscv/StoreRISC.java
+++ b/chapter22/src/main/java/com/seaofnodes/simple/node/cpus/riscv/StoreRISC.java
@@ -36,7 +36,7 @@ public class StoreRISC extends MemOpRISC {
short ptr = enc.reg(ptr());
int op = val >= riscv.F_OFFSET ? riscv.OP_STOREFP : riscv.OP_STORE;
if( val >= riscv.F_OFFSET ) val -= riscv.F_OFFSET;
- enc.add4(riscv.s_type(op, func3()&7, ptr, val, _off));
+ enc.add4(riscv.s_type(op, func3()&7, ptr, val == -1 ? riscv.ZERO : val, _off));
}
@Override public void asm(CodeGen code, SB sb) {
diff --git a/chapter22/src/main/java/com/seaofnodes/simple/node/cpus/riscv/riscv.java b/chapter22/src/main/java/com/seaofnodes/simple/node/cpus/riscv/riscv.java
index c1ad1647..8e722563 100644
--- a/chapter22/src/main/java/com/seaofnodes/simple/node/cpus/riscv/riscv.java
+++ b/chapter22/src/main/java/com/seaofnodes/simple/node/cpus/riscv/riscv.java
@@ -252,8 +252,8 @@ public class riscv extends Machine {
};
}
- @Override public RegMask callArgMask( TypeFunPtr tfp, int idx ) { return callInMask(tfp,idx); }
- static RegMask callInMask( TypeFunPtr tfp, int idx ) {
+ @Override public RegMask callArgMask( TypeFunPtr tfp, int idx, int maxArgSlot ) { return callInMask(tfp,idx,maxArgSlot); }
+ 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
@@ -272,6 +272,7 @@ public class riscv extends Machine {
return cargs[idx-2-fcnt];
}
// Pass on stack slot(8 and higher)
+ if( maxArgSlot>0 ) throw Utils.TODO();
return new RegMask(MAX_REG + 1 + (idx - 2));
}
diff --git a/chapter22/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/CallRX86.java b/chapter22/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/CallRX86.java
index b9d4fa8d..1a74f817 100644
--- a/chapter22/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/CallRX86.java
+++ b/chapter22/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/CallRX86.java
@@ -12,7 +12,7 @@ public class CallRX86 extends CallNode implements MachNode {
@Override public RegMask regmap(int i) {
return i==_inputs._len
? x86_64_v2.WMASK // Function call target
- : x86_64_v2.callInMask(tfp(),i); // Normal argument
+ : x86_64_v2.callInMask(tfp(),i,fun()._maxArgSlot); // Normal argument
}
@Override public RegMask outregmap() { return null; }
@Override public void encoding( Encoding enc ) {
diff --git a/chapter22/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/CallX86.java b/chapter22/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/CallX86.java
index 3110dbb4..4696c859 100644
--- a/chapter22/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/CallX86.java
+++ b/chapter22/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/CallX86.java
@@ -20,7 +20,7 @@ public class CallX86 extends CallNode implements MachNode, RIPRelSize {
@Override public String label() { return op(); }
@Override public String name() { return _name; }
@Override public TypeFunPtr tfp() { return _tfp; }
- @Override public RegMask regmap(int i) { return x86_64_v2.callInMask(_tfp,i); }
+ @Override public RegMask regmap(int i) { return x86_64_v2.callInMask(_tfp,i,fun()._maxArgSlot); }
@Override public RegMask outregmap() { return null; }
@Override public int nargs() { return nIns()-2; } // Minus control, memory, fptr
diff --git a/chapter22/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/ParmX86.java b/chapter22/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/ParmX86.java
index 7a6dbb13..5cfdd804 100644
--- a/chapter22/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/ParmX86.java
+++ b/chapter22/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/ParmX86.java
@@ -9,7 +9,7 @@ public class ParmX86 extends ParmNode implements MachNode {
final RegMask _rmask;
ParmX86( ParmNode parm ) {
super(parm);
- _rmask = x86_64_v2.callInMask(fun().sig(),_idx);
+ _rmask = x86_64_v2.callInMask(fun().sig(),_idx,1/*RPC*/);
}
@Override public RegMask regmap(int i) { return null; }
@Override public RegMask outregmap() { return _rmask; }
diff --git a/chapter22/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/SplitX86.java b/chapter22/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/SplitX86.java
index f965157b..960ea6f8 100644
--- a/chapter22/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/SplitX86.java
+++ b/chapter22/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/SplitX86.java
@@ -49,9 +49,16 @@ public class SplitX86 extends SplitNode {
// Stack spills
if( dst >= x86_64_v2.MAX_REG ) {
- if( src >= x86_64_v2.MAX_REG )
- throw Utils.TODO(); // Very rare stack-stack move
int off = enc._fun.computeStackOffset(enc._code,dst);
+ if( src >= x86_64_v2.MAX_REG ) {
+ // Rare stack-stack move. push [RSP+soff]; pop [RSP+doff]
+ int soff = enc._fun.computeStackOffset(enc._code,src);
+ enc.add1(0xFF);
+ x86_64_v2.indirectAdr(0, (short)-1/*index*/, (short)x86_64_v2.RSP, soff, 6, enc);
+ enc.add1(0x8F);
+ x86_64_v2.indirectAdr(0, (short)-1/*index*/, (short)x86_64_v2.RSP, off, 0, enc);
+ return;
+ }
StoreX86.encVal(enc, srcX ? TypeFloat.F64 : TypeInteger.BOT, (short)x86_64_v2.RSP, (short)-1/*index*/, src, off, 0);
return;
}
diff --git a/chapter22/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/StoreX86.java b/chapter22/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/StoreX86.java
index c906c3f2..76fb4e8d 100644
--- a/chapter22/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/StoreX86.java
+++ b/chapter22/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/StoreX86.java
@@ -44,7 +44,7 @@ public class StoreX86 extends MemOpX86 {
case 0: enc.add1(_imm); break;
case 1: enc.add2(_imm); break;
case 2: enc.add4(_imm); break;
- case 3: enc.add8(_imm); break;
+ case 3: enc.add4(_imm); break; // Limit of a 4 byte immediate
}
} else {
encVal(enc,_declaredType,ptr,idx,src,_off,_scale);
diff --git a/chapter22/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/x86_64_v2.java b/chapter22/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/x86_64_v2.java
index 35541346..60e10d79 100644
--- a/chapter22/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/x86_64_v2.java
+++ b/chapter22/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/x86_64_v2.java
@@ -185,14 +185,14 @@ public class x86_64_v2 extends Machine {
// Map from function signature and argument index to register.
// Used to set input registers to CallNodes, and ParmNode outputs.
- @Override public RegMask callArgMask( TypeFunPtr tfp, int idx ) { return callInMask(tfp,idx); }
- static RegMask callInMask( TypeFunPtr tfp, int idx ) {
+ @Override public RegMask callArgMask( TypeFunPtr tfp, int idx, int maxArgSlot ) { return callInMask(tfp,idx,maxArgSlot); }
+ 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
return switch( CodeGen.CODE._callingConv ) {
- case "SystemV" -> callSys5 (tfp,idx);
- case "Win64" -> callWin64(tfp,idx);
+ case "SystemV" -> callSys5 (tfp,idx,maxArgSlot);
+ case "Win64" -> callWin64(tfp,idx,maxArgSlot);
default -> throw Utils.TODO();
};
}
@@ -231,11 +231,11 @@ public class x86_64_v2 extends Machine {
R09_MASK,
};
- static RegMask callWin64(TypeFunPtr tfp, int idx ) {
+ static RegMask callWin64(TypeFunPtr tfp, int idx, int maxArgSlot ) {
// idx 2,3,4,5 passed in registers, with stack slot mirrors.
// idx >= 6 passed on stack, starting at slot#1 (#0 reserved for RPC).
if( idx >= 6 )
- return new RegMask(MAX_REG+1/*RPC*/+(idx-2));
+ return new RegMask(MAX_REG+maxArgSlot+(idx-2));
return tfp.arg(idx-2) instanceof TypeFloat
? XMMS8 [idx-2]
: WIN64_CALL[idx-2];
@@ -272,7 +272,7 @@ public class x86_64_v2 extends Machine {
R09_MASK,
};
- static RegMask callSys5(TypeFunPtr tfp, int idx ) {
+ static RegMask callSys5(TypeFunPtr tfp, int idx, int maxArgSlot ) {
// First 6 integers passed in registers: rdi,rsi,rdx,rcx,r08,r09
// First 8 floats passed in registers: xmm0-xmm7
int icnt=0, fcnt=0; // Count of ints, floats
@@ -282,8 +282,8 @@ public class x86_64_v2 extends Machine {
}
int nstk = Math.max(icnt-6,0)+Math.max(fcnt-8,0);
return tfp.arg(idx-2) instanceof TypeFloat
- ? fcnt<8 ? XMMS8 [fcnt] : new RegMask(MAX_REG+1/*RPC*/+nstk)
- : icnt<6 ? SYS5_CALL[icnt] : new RegMask(MAX_REG+1/*RPC*/+nstk);
+ ? fcnt<8 ? XMMS8 [fcnt] : new RegMask(MAX_REG+maxArgSlot+nstk)
+ : icnt<6 ? SYS5_CALL[icnt] : new RegMask(MAX_REG+maxArgSlot+nstk);
}
static short maxArgSlotSys5(TypeFunPtr tfp) {
int icnt=0, fcnt=0; // Count of ints, floats
diff --git a/chapter22/src/test/java/com/seaofnodes/simple/Chapter21Test.java b/chapter22/src/test/java/com/seaofnodes/simple/Chapter21Test.java
index 96e6c5ff..e589d5a4 100644
--- a/chapter22/src/test/java/com/seaofnodes/simple/Chapter21Test.java
+++ b/chapter22/src/test/java/com/seaofnodes/simple/Chapter21Test.java
@@ -6,12 +6,13 @@ import com.seaofnodes.simple.node.cpus.riscv.riscv;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
+import org.junit.Ignore;
import org.junit.Test;
import static org.junit.Assert.*;
public class Chapter21Test {
- @Test
+ @Test @Ignore
public void testJig() throws IOException {
String src = Files.readString(Path.of("src/test/java/com/seaofnodes/simple/progs/jig.smp"));
testCPU(src,"x86_64_v2", "Win64" ,-1,null);
diff --git a/chapter22/src/test/java/com/seaofnodes/simple/Chapter22Test.java b/chapter22/src/test/java/com/seaofnodes/simple/Chapter22Test.java
index baca507c..4b15124c 100644
--- a/chapter22/src/test/java/com/seaofnodes/simple/Chapter22Test.java
+++ b/chapter22/src/test/java/com/seaofnodes/simple/Chapter22Test.java
@@ -13,7 +13,7 @@ import static org.junit.Assert.*;
public class Chapter22Test {
- @Test
+ @Test @Ignore
public void testJig() throws IOException {
String src = Files.readString(Path.of("src/test/java/com/seaofnodes/simple/progs/jig.smp"));
testCPU(src,"x86_64_v2", "Win64" ,-1,null);