summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--chapter28b/src/main/java/com/seaofnodes/simple/codegen/CodeGen.java54
-rw-r--r--chapter28b/src/main/java/com/seaofnodes/simple/node/CFGNode.java10
-rw-r--r--chapter28b/src/test/java/com/seaofnodes/simple/Eval2.java5
-rw-r--r--chapter28b/src/test/java/com/seaofnodes/simple/PhaseTest.java4
-rw-r--r--chapter28b/src/test/java/com/seaofnodes/simple/SeparateCompilationTest.java3
5 files changed, 24 insertions, 52 deletions
diff --git a/chapter28b/src/main/java/com/seaofnodes/simple/codegen/CodeGen.java b/chapter28b/src/main/java/com/seaofnodes/simple/codegen/CodeGen.java
index e56068e7..2852e23d 100644
--- a/chapter28b/src/main/java/com/seaofnodes/simple/codegen/CodeGen.java
+++ b/chapter28b/src/main/java/com/seaofnodes/simple/codegen/CodeGen.java
@@ -261,17 +261,16 @@ public class CodeGen {
step(target, Phase.FinalizeIR, this::finalizeIR, dump);
// Final error check - bad programs fail here
step(target, Phase.TypeCheck, this::typeCheck, dump);
- if( cpu==null && target.ordinal()>=Phase.Lower.ordinal() && _phase.ordinal()<Phase.Lower.ordinal() )
- loadAllIR(); // Ideal evaluation needs code for calls left out of line.
// Save reloadable ideal IR for a later seperate compilation
step(target, Phase.Serialize, () -> Serialize.forTarget(this,target,inMemory), dump);
- // Replace "fat" nodes with their exploded explicit IR; this can
- // introduce CFG diamonds
- step(target, Phase.Lower, this::lower, dump);
+ // Eval2 executes ideal operations, including CLInit, directly. Only
+ // machine compilation expands them before scheduling.
+ step(target, Phase.Lower, () -> { if( cpu!=null ) lower(); }, dump);
// Compute the loop-tree, used for approximating exec frequencies for
// scheduling and register allocation
step(target, Phase.LoopTree, this::loopTree, dump);
- // Drop imports for machine selection, retain them for ideal evaluation.
+ // Detach call-graph edges; ideal execution retains unloaded summaries
+ // as dispatch targets and schedules their bodies on first use.
step(target, Phase.Unlink, () -> unlink(cpu!=null), dump);
// Instruction selection
step(target, Phase.Select, () -> instSelect(cpu,callingConv), dump);
@@ -494,34 +493,6 @@ public class CodeGen {
ParseAll.loadCompUnit(this,cu);
}
- // Evaluation needs implementations even for calls left out of line. E.g.,
- // this code is being run by the evaluator, and so doesn't get a link step.
- // If, instead, the code was going to run natively, it would first go
- // through a link step which would resolve all these call sites to code
- // generated in other object files. Since no link step, we need acess to
- // that other code right now.
- public void loadAllIR() {
- boolean loaded = false;
- for( CompUnit cu : _compunits.values() ) {
- if( cu._src!=null || cu._obj==null ) continue;
- ElfReader elf = getElf(cu._obj);
- if( elf._nodes!=null ) continue;
- ParseAll.loadCompUnit(this,cu);
- loaded=true;
- }
- if( !loaded ) return;
- if( _phase.ordinal()<Phase.FinalizeIR.ordinal() ) return;
- Phase prior = _phase;
- try {
- _phase=Phase.IterPostOpto;
- _iter.iterate(this);
- _phase=Phase.FinalizeIR;
- FinalizeIR.run(this);
- _phase=Phase.TypeCheck;
- TypeCheck.run(this);
- } finally { _phase=prior; }
- }
-
// TypeCheck saves its successful analysis for Serialize. Loading bodies
// or entering another graph-changing phase discards it.
ClassInitDependencies _classInitDependencies;
@@ -613,7 +584,8 @@ public class CodeGen {
// ---------------------------
// Build the loop tree; break never-exit loops
public CodeGen loopTree() {
- return phase(Phase.LoopTree, _phase==Phase.Lower, () -> _start.buildLoopTree(_linker,_stop));
+ return phase(Phase.LoopTree, (_phase==Phase.Lower || _phase==Phase.TypeCheck || _phase==Phase.Serialize),
+ () -> _start.buildLoopTree(_linker,_stop));
}
// ---------------------------
@@ -654,7 +626,10 @@ public class CodeGen {
unlink(true);
}
private void unlink(boolean removeImports) {
- phase(Phase.Unlink, _phase==Phase.LoopTree, () -> Unlink.run(this,removeImports));
+ phase(Phase.Unlink, _phase==Phase.LoopTree, () -> {
+ if( removeImports ) Unlink.run(this,true);
+ else Unlink.forEval(this,_start,_stop);
+ });
}
// ---------------------------
@@ -666,13 +641,6 @@ public class CodeGen {
return phase(Phase.Schedule, (_phase==Phase.Unlink || _phase==Phase.Select), () -> GlobalCodeMotion.buildCFG(this));
}
- // Evaluation branches from checked ideal IR directly to scheduling.
- // CLInit remains an executable ideal operation; no Lower or Select pass.
- public CodeGen scheduleForEval() {
- return phase(Phase.Schedule, (_phase==Phase.TypeCheck || _phase==Phase.Serialize),
- () -> _cfg=GlobalCodeMotion.forEval(this,_start,_stop));
- }
-
// ---------------------------
// Local (basic block) scheduler phase, a classic list scheduler
public CodeGen localSched() { return phase(Phase.LocalSched, _phase==Phase.Schedule, () -> ListScheduler.sched(this)); }
diff --git a/chapter28b/src/main/java/com/seaofnodes/simple/node/CFGNode.java b/chapter28b/src/main/java/com/seaofnodes/simple/node/CFGNode.java
index 7740df79..2e8c3ff9 100644
--- a/chapter28b/src/main/java/com/seaofnodes/simple/node/CFGNode.java
+++ b/chapter28b/src/main/java/com/seaofnodes/simple/node/CFGNode.java
@@ -207,7 +207,9 @@ public abstract class CFGNode extends Node {
int pre = 1;
_pre = pre++;
for( FunNode fun : funs ) {
- if( fun!=null && !fun.isDead() && !fun._type.isHigh() ) {
+ // Summaries have no executable CFG. Their loop trees are built
+ // only if Eval2 later loads the corresponding bodies.
+ if( fun!=null && !fun.isDead() && !fun._type.isHigh() && fun.summary()==null ) {
work.push(fun);
if(fun.in(1) instanceof StartCUNode start && start._pre==0 ) {
start._pre = pre++;
@@ -237,7 +239,7 @@ public abstract class CFGNode extends Node {
for( Node use : _outputs )
if( use instanceof CFGNode usecfg ) {
if( skip( usecfg ) ) {
- if( usecfg._pre==0 && usecfg instanceof FunNode fun2 ) work.add( fun2 );
+ if( usecfg._pre==0 && usecfg instanceof FunNode fun2 && fun2.summary()==null ) work.add( fun2 );
} else
pre = usecfg._bltWalk( pre, use instanceof FunNode fuse ? fuse : fun, stop, post, work );
}
@@ -285,9 +287,11 @@ public abstract class CFGNode extends Node {
public boolean skip(CFGNode usecfg) {
// Only walk control users that are alive.
- // Do not walk from a Call to linked Fun's.
+ // Do not follow interprocedural edges. CLInit's call projection is
+ // only an analysis edge, not a branch in the caller's loop tree.
return usecfg instanceof XCtrlNode ||
(this instanceof CallNode && usecfg instanceof FunNode) ||
+ (this instanceof CLInitNode && usecfg instanceof CProjNode proj && proj._idx==3) ||
(this instanceof CProjNode proj && proj._idx==3 && proj.in(0) instanceof CLInitNode && usecfg instanceof FunNode) ||
(this instanceof ReturnNode && usecfg instanceof CallEndNode);
}
diff --git a/chapter28b/src/test/java/com/seaofnodes/simple/Eval2.java b/chapter28b/src/test/java/com/seaofnodes/simple/Eval2.java
index fc87c13a..eea5b023 100644
--- a/chapter28b/src/test/java/com/seaofnodes/simple/Eval2.java
+++ b/chapter28b/src/test/java/com/seaofnodes/simple/Eval2.java
@@ -118,9 +118,8 @@ public abstract class Eval2 {
SB trace = null; // new SB(); // TRACE, set to null for off, new SB() for on
// Set global, so don't have to pass everywhere
CODE = code;
- // Eval uses checked ideal IR, including CLInit, and does not run Lower.
- // Objects loaded later are scheduled independently of this graph.
- if( code._phase.ordinal()<CodeGen.Phase.Schedule.ordinal() ) code.scheduleForEval();
+ // The normal driver schedules ideal IR without Lower or instruction
+ // selection. Objects loaded later are scheduled independently.
code.driver(CodeGen.Phase.LocalSched);
CLASSES.clear();
diff --git a/chapter28b/src/test/java/com/seaofnodes/simple/PhaseTest.java b/chapter28b/src/test/java/com/seaofnodes/simple/PhaseTest.java
index 7252378a..ee262d6c 100644
--- a/chapter28b/src/test/java/com/seaofnodes/simple/PhaseTest.java
+++ b/chapter28b/src/test/java/com/seaofnodes/simple/PhaseTest.java
@@ -21,12 +21,12 @@ public class PhaseTest {
};
code.driver(Phase.TypeCheck);
code.driver(Phase.TypeCheck); // A repeated request does not rerun anything.
+ assertEquals("45",Eval2.eval(code,10));
code.driver(Phase.LocalSched);
- assertEquals("Parse Iter Opto IterPostOpto FinalizeIR TypeCheck Lower LoopTree Unlink Schedule LocalSched",
+ assertEquals("Parse Iter Opto IterPostOpto FinalizeIR TypeCheck LoopTree Unlink Schedule LocalSched",
String.join(" ",phases));
assertNull(code._serial);
assertNull(code._mach);
- assertEquals("45",Eval2.eval(code,10));
}
@Test public void testEncodingWithoutSerialization() {
diff --git a/chapter28b/src/test/java/com/seaofnodes/simple/SeparateCompilationTest.java b/chapter28b/src/test/java/com/seaofnodes/simple/SeparateCompilationTest.java
index 4e8a0417..cfc0b7e0 100644
--- a/chapter28b/src/test/java/com/seaofnodes/simple/SeparateCompilationTest.java
+++ b/chapter28b/src/test/java/com/seaofnodes/simple/SeparateCompilationTest.java
@@ -30,7 +30,8 @@ public class SeparateCompilationTest {
CodeGen code=new CodeGen(null,null,new Ary<>(new String[]{lib.toString()}),
"Client","return Callbacks.run(arg);",123,true,TypeInteger.BOT)
.driver(CodeGen.Phase.Opto);
- code.loadAllIR(); // This assertion inspects a body, not just its saved summary.
+ // This assertion inspects a body, not just its saved summary.
+ ParseAll.loadCompUnit(code,code._compunits.get("Callbacks"));
assertNull(code._compunits.get("Callbacks")._src);
ParmNode base=code._start.walk(n -> n instanceof ParmNode p && p._label.equals("base") ? p : null);
assertNotNull(base);