From 2eba63966bdc3d9cfdf41ee085f35cbb6d529bbc Mon Sep 17 00:00:00 2001 From: Cliff Click Date: Wed, 7 Oct 2026 19:10:51 -0700 Subject: Towrds getting RA spill counts comparable Ignore JIGs. Get test suites more conical, so reg alloc spill counts are comparable --- .../java/com/seaofnodes/simple/codegen/IFG.java | 7 ++++ .../com/seaofnodes/simple/node/CallEndNode.java | 43 ++++++++++++++++++++-- .../java/com/seaofnodes/simple/node/FunNode.java | 7 +++- 3 files changed, 52 insertions(+), 5 deletions(-) (limited to 'chapter25/src/main') diff --git a/chapter25/src/main/java/com/seaofnodes/simple/codegen/IFG.java b/chapter25/src/main/java/com/seaofnodes/simple/codegen/IFG.java index 6145910c..bcdb14bf 100644 --- a/chapter25/src/main/java/com/seaofnodes/simple/codegen/IFG.java +++ b/chapter25/src/main/java/com/seaofnodes/simple/codegen/IFG.java @@ -457,6 +457,13 @@ abstract public class IFG { int area = cfg != use.cfg0() ? functionArea(lrg._fun,alloc) : cfg._outputs.find(use)-cfg._outputs.find(def)-1; + // A single-use function address can move next to its use without + // adding an instruction. Prefer that to saving a callee-save + // register just to hold the address. Stay in the same block and + // require a gap so the clone makes progress. + if( def instanceof FunPtrNode && !lrg._multiUse && + cfg == use.cfg0() && area > 0 ) + return 1000000; if( area > 0 ) return areaScore(area,loopCost(use)); } diff --git a/chapter25/src/main/java/com/seaofnodes/simple/node/CallEndNode.java b/chapter25/src/main/java/com/seaofnodes/simple/node/CallEndNode.java index 162f9c24..35180fea 100644 --- a/chapter25/src/main/java/com/seaofnodes/simple/node/CallEndNode.java +++ b/chapter25/src/main/java/com/seaofnodes/simple/node/CallEndNode.java @@ -179,10 +179,12 @@ public class CallEndNode extends CFGNode implements MultiNode { { addDep(fptr); return -1; } // Encouraged inlining because small size and constructor. - int maxSize = fun._name!=null && fun.isInit() && !fun.isClz() ? 200 : 100; - if( fun._approxUIDs >= maxSize ) - return -2; // Try later (if shrinking helps) - if( fun.body().cardinality() >= maxSize ) + int maxSize = fun.inlineLimit(); + // A large parse can leave only a tiny initializer. Recognize that + // without repeatedly walking the whole body while it shrinks. + if( fun._approxUIDs >= maxSize ) { + if( !smallBody(fun) ) return -1; + } else if( fun.body().cardinality() >= maxSize ) return -1; // Try later (if cleanup makes the real body small enough) // Can be cloned but not trivial @@ -192,6 +194,39 @@ public class CallEndNode extends CFGNode implements MultiNode { return 1; } + // Bounded, conservative recognition of straight-line initializer boilerplate. + // Walk uses from the entry and stop at Return, never following callers or + // constant inputs. This also avoids scanning sparse MemMerge input arrays. + // Watch only this small prefix, including an unsupported node that may fold. + private static final Node[] TINYBODY = new Node[15]; // Tiny worklist + private boolean smallBody(FunNode fun) { + ReturnNode ret = fun.ret(); + for( Node in : ret._inputs ) + if( in!=null ) addDep(in); + if( ret.ctrl()!=fun ) return false; + TINYBODY[0] = fun; + int len=1; + for( int i=0; iTINYBODY.length ) return false; // Too big + for( Node use : n._outputs ) { + if( use==null ) continue; + int j=0; + while( j 0; // Only called when possible to inline diff --git a/chapter25/src/main/java/com/seaofnodes/simple/node/FunNode.java b/chapter25/src/main/java/com/seaofnodes/simple/node/FunNode.java index 29e9900a..b74f9e6b 100644 --- a/chapter25/src/main/java/com/seaofnodes/simple/node/FunNode.java +++ b/chapter25/src/main/java/com/seaofnodes/simple/node/FunNode.java @@ -221,6 +221,11 @@ public class FunNode extends RegionNode { public static boolean isInit(String name ) { return name!=null && name.endsWith("init>"); } public static boolean isInstance(String name ) { return name!=null && name.endsWith("."); } + // Allocation factories and instance initializers carry extra memory boilerplate. + public int inlineLimit() { + return isInstance() || (_name!=null && _name.endsWith(".")) ? 200 : 100; + } + // Function is public (callable from Start directly). public boolean isPublic( ) { // Never true for anonymous functions @@ -316,7 +321,7 @@ public class FunNode extends RegionNode { FunNode copyBody() { // Build the function body BitSet BitSet body = body(); - assert body.cardinality() < 100; + assert body.cardinality() < inlineLimit(); // Walk the body, cloning IdentityHashMap map = new IdentityHashMap<>(); BitSet visit = CodeGen.CODE.visit(); -- cgit v1.2.3