summaryrefslogtreecommitdiff
path: root/chapter25/src/main/java
diff options
context:
space:
mode:
Diffstat (limited to 'chapter25/src/main/java')
-rw-r--r--chapter25/src/main/java/com/seaofnodes/simple/codegen/IFG.java7
-rw-r--r--chapter25/src/main/java/com/seaofnodes/simple/node/CallEndNode.java43
-rw-r--r--chapter25/src/main/java/com/seaofnodes/simple/node/FunNode.java7
3 files changed, 52 insertions, 5 deletions
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; i<len; i++ ) {
+ Node n = TINYBODY[i];
+ addDep(n);
+ if( n==ret ) continue;
+ if( n instanceof ParmNode parm && parm.region()!=fun ) return false;
+ if( n!=fun && !(n instanceof ParmNode) &&
+ !(n instanceof StoreNode) && !(n instanceof MemMergeNode) )
+ return false; // Something unexpected
+ if( n.nOuts()>TINYBODY.length ) return false; // Too big
+ for( Node use : n._outputs ) {
+ if( use==null ) continue;
+ int j=0;
+ while( j<len && TINYBODY[j]!=use ) j++;
+ if( j<len ) continue; // Already in TINYBODY
+ if( len==TINYBODY.length ) { addDep(use); return false; } // Too big
+ TINYBODY[len++] = use; // Add to worklist
+ }
+ }
+ return true;
+ }
+
public void doInline() {
assert _inline > 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(".<init>"); }
+ // Allocation factories and instance initializers carry extra memory boilerplate.
+ public int inlineLimit() {
+ return isInstance() || (_name!=null && _name.endsWith(".<new>")) ? 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<Node,Node> map = new IdentityHashMap<>();
BitSet visit = CodeGen.CODE.visit();