summaryrefslogtreecommitdiff
path: root/chapter23
diff options
context:
space:
mode:
Diffstat (limited to 'chapter23')
-rw-r--r--chapter23/README.md8
-rw-r--r--chapter23/src/main/java/com/seaofnodes/simple/codegen/CodeGen.java330
-rw-r--r--chapter23/src/main/java/com/seaofnodes/simple/codegen/FinalizeIR.java48
-rw-r--r--chapter23/src/main/java/com/seaofnodes/simple/codegen/GlobalCodeMotion.java11
-rw-r--r--chapter23/src/main/java/com/seaofnodes/simple/codegen/InstSelect.java90
-rw-r--r--chapter23/src/main/java/com/seaofnodes/simple/codegen/LRG.java2
-rw-r--r--chapter23/src/main/java/com/seaofnodes/simple/codegen/RegAlloc.java6
-rw-r--r--chapter23/src/main/java/com/seaofnodes/simple/codegen/TypeCheck.java15
-rw-r--r--chapter23/src/main/java/com/seaofnodes/simple/node/SplitNode.java2
-rw-r--r--chapter23/src/main/java/com/seaofnodes/simple/node/cpus/arm/SplitFlagsARM.java21
-rw-r--r--chapter23/src/main/java/com/seaofnodes/simple/node/cpus/arm/SplitGPRARM.java11
-rw-r--r--chapter23/src/main/java/com/seaofnodes/simple/node/cpus/arm/arm.java11
-rw-r--r--chapter23/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/SplitFlagsX86.java25
-rw-r--r--chapter23/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/SplitX86.java6
-rw-r--r--chapter23/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/x86_64_v2.java6
-rw-r--r--chapter23/src/main/java/com/seaofnodes/simple/print/SimpleGraphObserver.java2
-rw-r--r--chapter23/src/main/java/com/seaofnodes/simple/type/TypeStruct.java2
-rw-r--r--chapter23/src/test/java/com/seaofnodes/simple/Chapter05Test.java16
-rw-r--r--chapter23/src/test/java/com/seaofnodes/simple/Chapter06Test.java32
-rw-r--r--chapter23/src/test/java/com/seaofnodes/simple/Chapter07Test.java14
-rw-r--r--chapter23/src/test/java/com/seaofnodes/simple/Chapter08Test.java22
-rw-r--r--chapter23/src/test/java/com/seaofnodes/simple/Chapter09Test.java40
-rw-r--r--chapter23/src/test/java/com/seaofnodes/simple/Chapter10Test.java58
-rw-r--r--chapter23/src/test/java/com/seaofnodes/simple/Chapter11Test.java6
-rw-r--r--chapter23/src/test/java/com/seaofnodes/simple/Chapter12Test.java32
-rw-r--r--chapter23/src/test/java/com/seaofnodes/simple/Chapter13Test.java31
-rw-r--r--chapter23/src/test/java/com/seaofnodes/simple/Chapter14FloatTest.java14
-rw-r--r--chapter23/src/test/java/com/seaofnodes/simple/Chapter14Test.java30
-rw-r--r--chapter23/src/test/java/com/seaofnodes/simple/Chapter15Test.java42
-rw-r--r--chapter23/src/test/java/com/seaofnodes/simple/Chapter16Test.java18
-rw-r--r--chapter23/src/test/java/com/seaofnodes/simple/Chapter17aTest.java16
-rw-r--r--chapter23/src/test/java/com/seaofnodes/simple/Chapter17bTest.java90
-rw-r--r--chapter23/src/test/java/com/seaofnodes/simple/Chapter18Test.java40
-rw-r--r--chapter23/src/test/java/com/seaofnodes/simple/Chapter19Test.java12
-rw-r--r--chapter23/src/test/java/com/seaofnodes/simple/Chapter20Test.java11
-rw-r--r--chapter23/src/test/java/com/seaofnodes/simple/Chapter21Test.java2
-rw-r--r--chapter23/src/test/java/com/seaofnodes/simple/Chapter22Test.java8
-rw-r--r--chapter23/src/test/java/com/seaofnodes/simple/Chapter23Test.java8
-rw-r--r--chapter23/src/test/java/com/seaofnodes/simple/Compile.java2
-rw-r--r--chapter23/src/test/java/com/seaofnodes/simple/CompoundAssignmentTest.java2
-rw-r--r--chapter23/src/test/java/com/seaofnodes/simple/LiteralTest.java4
-rw-r--r--chapter23/src/test/java/com/seaofnodes/simple/Main.java2
-rw-r--r--chapter23/src/test/java/com/seaofnodes/simple/MemoryEncodingTest.java4
-rw-r--r--chapter23/src/test/java/com/seaofnodes/simple/MutabilityTest.java4
-rw-r--r--chapter23/src/test/java/com/seaofnodes/simple/PhaseTest.java42
-rw-r--r--chapter23/src/test/java/com/seaofnodes/simple/SchedulerTest.java26
-rw-r--r--chapter23/src/test/java/com/seaofnodes/simple/Simple.java149
-rw-r--r--chapter23/src/test/java/com/seaofnodes/simple/codegen/FlagSpillTestSupport.java145
-rw-r--r--chapter23/src/test/java/com/seaofnodes/simple/codegen/RegAllocTestSupport.java15
-rw-r--r--chapter23/src/test/java/com/seaofnodes/simple/fuzzer/Fuzzer.java2
50 files changed, 891 insertions, 644 deletions
diff --git a/chapter23/README.md b/chapter23/README.md
index 85a5b201..c99d2441 100644
--- a/chapter23/README.md
+++ b/chapter23/README.md
@@ -376,6 +376,14 @@ will be cycle-equals (all other things being equals).
+## Finalizing field layouts
+
+`FinalizeIR` now also settles field sizes and layouts, replaces symbolic field
+offsets by constants, and runs peepholes exposed by those constants. Recursive
+type construction must finish before layout is queried. The phase follows
+`Iter` and precedes `TypeCheck`; the driver includes it when compiling through
+any later stage.
+
## Methods and Final Fields and Classes
Methods are simply function values (final fields) declared inside a struct that
diff --git a/chapter23/src/main/java/com/seaofnodes/simple/codegen/CodeGen.java b/chapter23/src/main/java/com/seaofnodes/simple/codegen/CodeGen.java
index 9bf1aa61..e332146f 100644
--- a/chapter23/src/main/java/com/seaofnodes/simple/codegen/CodeGen.java
+++ b/chapter23/src/main/java/com/seaofnodes/simple/codegen/CodeGen.java
@@ -21,19 +21,63 @@ public class CodeGen {
public static CodeGen CODE;
public enum Phase {
- Parse, // Parse ASCII text into Sea-of-Nodes IR
- Opto, // Run ideal optimizations
- TypeCheck, // Last check for bad programs
- LoopTree, // Build a loop tree; break infinite loops
- Select, // Convert to target hardware nodes
- Schedule, // Global schedule (code motion) nodes
- LocalSched, // Local schedule
- RegAlloc, // Register allocation
- Encoding, // Encoding
- Export, // Export
+ Parse, // Build ideal IR from source
+ Iter, // Pessimistic peepholes
+ FinalizeIR, // Finish function cleanup and layouts
+ TypeCheck, // Check the surviving ideal graph
+ LoopTree, // Discover loops and connect nonreturning paths
+ Select, // Select machine instructions
+ Schedule, // Global code motion
+ LocalSched, // Order instructions within blocks
+ RegAlloc, // Assign registers and stack slots
+ Encoding, // Encode instructions
+ Export; // Link in memory or write ELF
+
}
public Phase _phase;
+ // Run through target, skipping phases already completed.
+ public CodeGen driver(Phase target) { return driver(target,null,null); }
+ public CodeGen driver(Phase target, String cpu, String callingConv) { return driver(target,cpu,callingConv,0); }
+ public CodeGen driver(Phase target, String cpu, String callingConv, int dump) {
+ if( target.ordinal()>=Phase.RegAlloc.ordinal() && cpu==null && _mach==null )
+ throw new IllegalArgumentException("Machine code requires a CPU target");
+ if( target==Phase.Export ) throw new IllegalArgumentException("Use exportELF with an output file or null for memory linking");
+ step(target, Phase.Parse, this::parse, dump);
+ step(target, Phase.Iter, this::iter, dump);
+ step(target, Phase.FinalizeIR, this::finalizeIR, dump);
+ step(target, Phase.TypeCheck, this::typeCheck, dump);
+ step(target, Phase.LoopTree, this::loopTree, dump);
+ step(target, Phase.Select, () -> instSelect(cpu,callingConv), dump);
+ step(target, Phase.Schedule, this::GCM, dump);
+ step(target, Phase.LocalSched, this::localSched, dump);
+ step(target, Phase.RegAlloc, this::regAlloc, dump);
+ step(target, Phase.Encoding, this::encode, dump);
+ return this;
+ }
+
+ private void step(Phase target, Phase next, Runnable work, int dump) {
+ if( next.ordinal()>target.ordinal() || (_phase!=null && _phase.ordinal()>=next.ordinal()) ) return;
+ Phase prior = _phase;
+ work.run();
+ if( _phase!=prior && (dump & (1<<_phase.ordinal()))!=0 ) {
+ if( (dump & (1<<30))!=0 ) System.err.println("After "+_phase+":");
+ System.err.println(this);
+ }
+ }
+
+ public final long[] _times = new long[Phase.values().length];
+ private CodeGen phase(Phase next, boolean ordered, Runnable work) {
+ assert ordered : "Cannot run "+next+" after "+_phase;
+ _phase = next;
+ long t0 = System.currentTimeMillis();
+ try { work.run(); }
+ finally { _times[next.ordinal()] = System.currentTimeMillis()-t0; }
+ if( _obs!=null ) _obs.phase(next.name());
+ return this;
+ }
+
+
// ---------------------------
// Compilation source code
public final String _src;
@@ -59,22 +103,6 @@ public class CodeGen {
}
- // All passes up to Phase, except ELF
- public CodeGen driver( Phase phase ) { return driver(phase,null,null); }
- public CodeGen driver( Phase phase, String cpu, String callingConv ) {
- if( _phase==null ) parse();
- int p1 = phase.ordinal();
- if( _phase.ordinal() < p1 && _phase.ordinal() < Phase.Opto .ordinal() ) opto();
- if( _phase.ordinal() < p1 && _phase.ordinal() < Phase.TypeCheck .ordinal() ) typeCheck();
- if( _phase.ordinal() < p1 && _phase.ordinal() < Phase.LoopTree .ordinal() ) loopTree();
- if( _phase.ordinal() < p1 && _phase.ordinal() < Phase.Select .ordinal() && cpu != null ) instSelect(cpu,callingConv);
- if( _phase.ordinal() < p1 && _phase.ordinal() < Phase.Schedule .ordinal() ) GCM();
- if( _phase.ordinal() < p1 && _phase.ordinal() < Phase.LocalSched.ordinal() ) localSched();
- if( _phase.ordinal() < p1 && _phase.ordinal() < Phase.RegAlloc .ordinal() ) regAlloc();
- if( _phase.ordinal() < p1 && _phase.ordinal() < Phase.Encoding .ordinal() ) encode();
- return this;
- }
-
// Run all the phases through final ELF emission
public CodeGen driver( String cpu, String callingConv, String obj ) throws IOException {
return driver(Phase.Encoding,cpu,callingConv).exportELF(obj);
@@ -147,16 +175,10 @@ public class CodeGen {
public final Parser P;
// Parse ASCII text into Sea-of-Nodes IR
- public int _tParse;
public CodeGen parse() {
- assert _phase == null;
- _phase = Phase.Parse;
- long t0 = System.currentTimeMillis();
-
- P.parse();
- _tParse = (int)(System.currentTimeMillis() - t0);
- if( _obs != null ) _obs.phase("Parse");
- return this;
+ return phase(Phase.Parse, _phase==null, () -> {
+ P.parse();
+ });
}
@@ -171,100 +193,25 @@ public class CodeGen {
public void iterCnt() { if( !_midAssert ) _iter_cnt++; }
public void iterNop() { if( !_midAssert ) _iter_nop_cnt++; }
- // Run ideal optimizations
- public int _tOpto;
- public CodeGen opto() {
- assert _phase == Phase.Parse;
- _phase = Phase.Opto;
- long t0 = System.currentTimeMillis();
-
- // Pessimistic peephole optimization on a worklist
- _iter.iterate(this);
-
- // OPTIMISTIC PASS GOES HERE
-
- // Not really a true optimistic pass, but look for unlinked functions.
- // This can be removed, which may trigger another round of pessimistic.
- // This is the point where we flip from a virtual Call Graph (any call
- // can call any function) to having a correct (but conservative) CG.
- int progress = 0;
- while( progress != _start.nOuts() ) {
- progress = _start.nOuts();
- FunNode main = link(_main);
- for( int i=0; i<_start.nOuts(); i++ ) {
- Node use = _start.out(i);
- if( use instanceof FunNode fun &&
- fun.nIns()==2 && fun.in(1)==_start && fun != main && !fun.hasPtr() &&
- (fun._name==null || fun._name.startsWith("sys.")) ) {
- add(fun).setDef(1,Parser.XCTRL);
- addAll(fun._outputs);
- i--;
- }
- }
- _iter.iterate(this);
- }
-
- // Freeze field sizes; do struct layouts; convert field offsets into
- // constants.
- for( int i=0; i<_start.nOuts(); i++ ) {
- Node use = _start.out(i);
- if( use instanceof ConFldOffNode off ) {
- TypeMemPtr tmp = (TypeMemPtr) Parser.TYPES.get(off._name);
- off.subsume( off.asOffset(tmp._obj) );
- i--;
- }
- }
- _iter.iterate(this);
-
- // To help with testing, sort StopNode returns by NID
- Arrays.sort(_stop._inputs._es,0,_stop.nIns(),(x,y) -> x._nid - y._nid );
-
- _tOpto = (int)(System.currentTimeMillis() - t0);
+ // Pessimistic peepholes reach a fixed point after parsing.
+ public CodeGen iter() { return phase(Phase.Iter, _phase==Phase.Parse, () -> _iter.iterate(this)); }
- // TODO:
- // Optimistic
- // TODO:
- // loop unroll, peel, RCE, etc
- if( _obs != null ) _obs.phase("Opto");
- return this;
- }
+ public CodeGen finalizeIR() { return phase(Phase.FinalizeIR, _phase==Phase.Iter, () -> FinalizeIR.run(this)); }
public <N extends Node> N add( N n ) { return _iter.add(n); }
public void addAll( Ary<Node> ary ) { _iter.addAll(ary); }
// ---------------------------
// Last check for bad programs
- public int _tTypeCheck;
- public CodeGen typeCheck() {
- // Demand phase Opto for cleaning up dead control flow at least,
- // required for the following GCM.
- assert _phase.ordinal() <= Phase.Opto.ordinal();
- _phase = Phase.TypeCheck;
- long t0 = System.currentTimeMillis();
-
- Parser.ParseException err = _stop.walk(n -> {
- Parser.ParseException msg = n.err();
- if( msg != null && _obs != null ) _obs.error(n, msg.getMessage());
- return msg;
- });
- _tTypeCheck = (int)(System.currentTimeMillis() - t0);
- if( err != null )
- throw err;
- if( _obs != null ) _obs.phase("TypeCheck");
- return this;
- }
+ public CodeGen typeCheck() { return phase(Phase.TypeCheck, _phase==Phase.FinalizeIR, () -> TypeCheck.run(this)); }
// ---------------------------
// Build the loop tree; break never-exit loops
- public int _tLoopTree;
public CodeGen loopTree() {
- assert _phase.ordinal() <= Phase.TypeCheck.ordinal();
- _phase = Phase.LoopTree;
- long t0 = System.currentTimeMillis();
- // Build the loop tree, fix never-exit loops
- _start.buildLoopTree(_start,_stop);
- _tLoopTree = (int)(System.currentTimeMillis() - t0);
- return this;
+ return phase(Phase.LoopTree, _phase==Phase.TypeCheck, () -> {
+ // Build the loop tree, fix never-exit loops
+ _start.buildLoopTree(_start,_stop);
+ });
}
// ---------------------------
@@ -286,138 +233,41 @@ public class CodeGen {
public RegMask _rpcMask;
// Convert to target hardware nodes
- public int _tInsSel;
public CodeGen instSelect( String cpu, String callingConv ) { return instSelect(cpu,callingConv,PORTS); }
public CodeGen instSelect( String cpu, String callingConv, String base ) {
- assert _phase.ordinal() == Phase.LoopTree.ordinal();
- _phase = Phase.Select;
-
- _callingConv = callingConv;
-
- // Not timing the class load...
- // Look for CPU in fixed named place:
- // com.seaofnodes.simple.node.cpus."cpu"."cpu.class"
- String clzFile = base+"."+cpu+"."+cpu;
- try { _mach = ((Class<Machine>) Class.forName( clzFile )).getDeclaredConstructor(new Class[]{CodeGen.class}).newInstance(this); }
- catch( Exception e ) { throw new RuntimeException(e); }
-
- // Build global copies of common register masks.
- long callerSave = _mach.callerSave();
- long neverSave = _mach. neverSave();
- int maxReg = Math.min(64,_mach.regs().length);
- assert maxReg>=64 || (-1L << maxReg & callerSave)==0; // No stack slots in callerSave
- _callerSave = new RegMask(callerSave);
-
- // Build a Return RegMask array. All returns have the following inputs:
- // 0 - ctrl
- // 1 - memory
- // 2 - varies with returning GPR,FPR
- // 3 - RPC
- // 4+- Caller save registers
- _retMasks = new RegMask[(maxReg-_callerSave.size()-Long.bitCount( neverSave ))+4];
- for( int reg=0, i=4; reg<maxReg; reg++ )
- if( !_callerSave.test(reg) && ((1L<<reg)&neverSave)==0 )
- _retMasks[i++] = new RegMask(reg);
- _rpcMask = new RegMask(_mach.rpc());
- _retMasks[3] = _rpcMask;
-
- // Convert to machine ops
- long t0 = System.currentTimeMillis();
- _uid = 1; // All new machine nodes reset numbering
- var map = new IdentityHashMap<Node,Node>();
- _instSelect( _stop, map );
- _stop = ( StopNode)map.get(_stop );
- StartNode start = (StartNode)map.get(_start);
- _start = start==null ? new StartNode(_start) : start;
- _instOuts(_stop,visit());
- _visit.clear();
- _tInsSel = (int)(System.currentTimeMillis() - t0);
- return this;
- }
-
- // Walk all ideal nodes, recursively mapping ideal to machine nodes, then
- // make a machine node for "this".
- private Node _instSelect( Node n, IdentityHashMap<Node,Node> map ) {
- if( n==null ) return null;
- Node x = map.get(n);
- if( x !=null ) return x; // Been there, done that
-
- // If n is a MachNode already, then its part of a multi-node expansion.
- // It does not need instruction selection (already selected!)
- // but it does need its inputs walked.
- if( n instanceof MachNode ) {
- for( int i=0; i < n.nIns(); i++ )
- n._inputs.set(i, _instSelect(n.in(i),map) );
- return n;
- }
-
- // Produce a machine node from n; map it to flag as done so stops cycles.
- map.put(n, x=_mach.instSelect(n) );
- // Stop retains the callable body. Its lifetime edge is not a machine operand.
- if( n instanceof FunPtrNode ) x._inputs.pop();
- // Walk machine op and replace inputs with mapped inputs
- for( int i=0; i < x.nIns(); i++ )
- x._inputs.set(i, _instSelect(x.in(i),map) );
- if( x instanceof MachNode mach )
- mach.postSelect(this); // Post selection action
-
- return x;
- }
-
- // Walk all machine Nodes, and set their output edges
- private void _instOuts( Node n, BitSet visit ) {
- if( visit.get(n._nid) ) return;
- visit.set(n._nid);
- for( Node in : n._inputs )
- if( in!=null ) {
- in._outputs.push(n);
- _instOuts(in,visit);
- }
+ if( cpu==null ) return this;
+ return phase(Phase.Select, _phase==Phase.LoopTree,
+ () -> new InstSelect(this).run(cpu,callingConv,base));
}
// ---------------------------
// Control Flow Graph in Reverse Post Order.
- public int _tGCM;
public Ary<CFGNode> _cfg = new Ary<>(CFGNode.class);
// Global schedule (code motion) nodes
public CodeGen GCM() {
- assert _phase.ordinal() <= Phase.Select.ordinal();
- _phase = Phase.Schedule;
- long t0 = System.currentTimeMillis();
+ return phase(Phase.Schedule, (_phase==Phase.LoopTree || _phase==Phase.Select), () -> {
+ GlobalCodeMotion.buildCFG(this);
- GlobalCodeMotion.buildCFG(this);
- _tGCM = (int)(System.currentTimeMillis() - t0);
-
- return this;
+ });
}
// ---------------------------
// Local (basic block) scheduler phase, a classic list scheduler
- public int _tLocal;
public CodeGen localSched() {
- assert _phase == Phase.Schedule;
- _phase = Phase.LocalSched;
- long t0 = System.currentTimeMillis();
- ListScheduler.sched(this);
- _tLocal = (int)(System.currentTimeMillis() - t0);
- return this;
- }
+ return phase(Phase.LocalSched, _phase==Phase.Schedule, () -> ListScheduler.sched(this));
+ }
// ---------------------------
// Register Allocation
- public int _tRegAlloc;
public RegAlloc _regAlloc;
public CodeGen regAlloc() {
- assert _phase == Phase.LocalSched;
- _phase = Phase.RegAlloc;
- long t0 = System.currentTimeMillis();
- _regAlloc = new RegAlloc(this);
- _regAlloc.regAlloc();
- _tRegAlloc = (int)(System.currentTimeMillis() - t0);
- return this;
+ return phase(Phase.RegAlloc, _phase==Phase.LocalSched, () -> {
+ _regAlloc = new RegAlloc(this);
+ _regAlloc.regAlloc();
+ });
}
// Human readable register name
@@ -433,27 +283,27 @@ public class CodeGen {
// ---------------------------
// Encoding
- public int _tEncode;
public Encoding _encoding; // Encoding object
public void preEncode() { } // overridden by alternative ports
public CodeGen encode() {
- assert _phase == Phase.RegAlloc;
- _phase = Phase.Encoding;
- long t0 = System.currentTimeMillis();
- _encoding = new Encoding(this);
- preEncode();
- _encoding.encode();
- _tEncode = (int)(System.currentTimeMillis() - t0);
- return this;
+ return phase(Phase.Encoding, _phase==Phase.RegAlloc, () -> {
+ _encoding = new Encoding(this);
+ preEncode();
+ _encoding.encode();
+ });
}
// ---------------------------
// Exporting to external formats
public CodeGen exportELF(String fname) throws IOException {
- assert _phase == Phase.Encoding;
- _phase = Phase.Export;
- if( fname == null ) new LinkMem(this).link(); // In memory patching
- else new ElfFile(this).export(fname); // External ELF file
+ assert _phase==Phase.Encoding;
+ _phase=Phase.Export;
+ long t0=System.currentTimeMillis();
+ try {
+ if( fname == null ) new LinkMem(this).link(); // In memory patching
+ else new ElfFile(this).export(fname); // External ELF file
+ } finally { _times[Phase.Export.ordinal()]=System.currentTimeMillis()-t0; }
+ if( _obs!=null ) _obs.phase(Phase.Export.name());
return this;
}
diff --git a/chapter23/src/main/java/com/seaofnodes/simple/codegen/FinalizeIR.java b/chapter23/src/main/java/com/seaofnodes/simple/codegen/FinalizeIR.java
new file mode 100644
index 00000000..55553393
--- /dev/null
+++ b/chapter23/src/main/java/com/seaofnodes/simple/codegen/FinalizeIR.java
@@ -0,0 +1,48 @@
+package com.seaofnodes.simple.codegen;
+
+import com.seaofnodes.simple.Parser;
+import com.seaofnodes.simple.node.*;
+import com.seaofnodes.simple.type.*;
+import java.util.Arrays;
+
+// Finish the ideal graph before type checking and scheduling.
+abstract class FinalizeIR {
+ static void run(CodeGen code) {
+ // Not really a true optimistic pass, but look for unlinked functions.
+ // This can be removed, which may trigger another round of pessimistic.
+ // This is the point where we flip from a virtual Call Graph (any call
+ // can call any function) to having a correct (but conservative) CG.
+ int progress = 0;
+ while( progress != code._start.nOuts() ) {
+ progress = code._start.nOuts();
+ FunNode main = code.link(code._main);
+ for( int i=0; i<code._start.nOuts(); i++ ) {
+ Node use = code._start.out(i);
+ if( use instanceof FunNode fun &&
+ fun.nIns()==2 && fun.in(1)==code._start && fun != main && !fun.hasPtr() &&
+ (fun._name==null || fun._name.startsWith("sys.")) ) {
+ code.add(fun).setDef(1,Parser.XCTRL);
+ code.addAll(fun._outputs);
+ i--;
+ }
+ }
+ code._iter.iterate(code);
+ }
+
+ // Freeze field sizes; do struct layouts; convert field offsets into
+ // constants.
+ for( int i=0; i<code._start.nOuts(); i++ ) {
+ Node use = code._start.out(i);
+ if( use instanceof ConFldOffNode off ) {
+ TypeMemPtr tmp = (TypeMemPtr) Parser.TYPES.get(off._name);
+ off.subsume( off.asOffset(tmp._obj) );
+ i--;
+ }
+ }
+ code._iter.iterate(code);
+
+ // To help with testing, sort StopNode returns by NID
+ Arrays.sort(code._stop._inputs._es,0,code._stop.nIns(),(x,y) -> x._nid - y._nid );
+
+ }
+}
diff --git a/chapter23/src/main/java/com/seaofnodes/simple/codegen/GlobalCodeMotion.java b/chapter23/src/main/java/com/seaofnodes/simple/codegen/GlobalCodeMotion.java
index 80d5d9bb..da45db4f 100644
--- a/chapter23/src/main/java/com/seaofnodes/simple/codegen/GlobalCodeMotion.java
+++ b/chapter23/src/main/java/com/seaofnodes/simple/codegen/GlobalCodeMotion.java
@@ -273,10 +273,11 @@ public abstract class GlobalCodeMotion {
lca = anti_dep(load,late[st._nid],st.cfg0(),lca,st,anti);
break;
case PhiNode phi:
- // Repeat anti-dep for matching Phi inputs.
- // No anti-dep edges but may raise the LCA.
+ // Inputs carrying different memory might overwrite this alias.
+ // Raise the LCA for those paths; unchanged memory does not
+ // clobber the load. No scheduling edge to the Phi.
for( int i=1; i<phi.nIns(); i++ )
- if( phi.in(i)==load.mem() )
+ if( phi.in(i)!=load.mem() )
lca = anti_dep(load,phi.region().cfg(i),load.mem().cfg0(),lca,null,anti);
break;
case NewNode st:
@@ -293,7 +294,9 @@ public abstract class GlobalCodeMotion {
private static CFGNode anti_dep( MemOpNode load, CFGNode stblk, CFGNode defblk, CFGNode lca, Node st, int[] anti ) {
// A conditional writer can precede the load without dominating its late block.
// Walk back to the first overlap with the load's placement range.
- for( ; stblk != defblk.idom(); stblk = stblk.idom() ) {
+ // Another Phi input need not be dominated by this memory definition.
+ // Include its depth, and retain the sentinel for an entry's null idom.
+ for( ; stblk != defblk.idom() && stblk.idepth() >= defblk.idepth(); stblk = stblk.idom() ) {
// Store and Load overlap, need anti-dependence
if( anti[stblk._nid]==load._nid ) {
lca = stblk.domLCA(lca,null); // Raise Loads LCA
diff --git a/chapter23/src/main/java/com/seaofnodes/simple/codegen/InstSelect.java b/chapter23/src/main/java/com/seaofnodes/simple/codegen/InstSelect.java
new file mode 100644
index 00000000..e8e87785
--- /dev/null
+++ b/chapter23/src/main/java/com/seaofnodes/simple/codegen/InstSelect.java
@@ -0,0 +1,90 @@
+package com.seaofnodes.simple.codegen;
+
+import com.seaofnodes.simple.node.*;
+import java.util.BitSet;
+import java.util.IdentityHashMap;
+
+// Replace ideal nodes with machine nodes, then rebuild the copied graph's uses.
+class InstSelect {
+ private final CodeGen _code;
+ InstSelect(CodeGen code) { _code=code; }
+
+ @SuppressWarnings("unchecked")
+ void run(String cpu, String callingConv, String base) {
+ _code._callingConv = callingConv;
+
+ // Look for CPU in fixed named place:
+ // com.seaofnodes.simple.node.cpus."cpu"."cpu.class"
+ String clzFile = base+"."+cpu+"."+cpu;
+ try { _code._mach = ((Class<Machine>) Class.forName( clzFile )).getDeclaredConstructor(new Class[]{CodeGen.class}).newInstance(_code); }
+ catch( Exception e ) { throw new RuntimeException(e); }
+
+ // Build global copies of common register masks.
+ long callerSave = _code._mach.callerSave();
+ long neverSave = _code._mach. neverSave();
+ int maxReg = Math.min(64,_code._mach.regs().length);
+ assert maxReg>=64 || (-1L << maxReg & callerSave)==0; // No stack slots in callerSave
+ _code._callerSave = new RegMask(callerSave);
+
+ // Build a Return RegMask array. All returns have the following inputs:
+ // 0 - ctrl
+ // 1 - memory
+ // 2 - varies with returning GPR,FPR
+ // 3 - RPC
+ // 4+- Caller save registers
+ _code._retMasks = new RegMask[(maxReg-_code._callerSave.size()-Long.bitCount( neverSave ))+4];
+ for( int reg=0, i=4; reg<maxReg; reg++ )
+ if( !_code._callerSave.test(reg) && ((1L<<reg)&neverSave)==0 )
+ _code._retMasks[i++] = new RegMask(reg);
+ _code._rpcMask = new RegMask(_code._mach.rpc());
+ _code._retMasks[3] = _code._rpcMask;
+
+ // Convert to machine ops
+ _code._uid = 1; // All new machine nodes reset numbering
+ var map = new IdentityHashMap<Node,Node>();
+ _instSelect( _code._stop, map );
+ _code._stop = ( StopNode)map.get(_code._stop );
+ StartNode start = (StartNode)map.get(_code._start);
+ _code._start = start==null ? new StartNode(_code._start) : start;
+ _instOuts(_code._stop,_code.visit());
+ _code._visit.clear();
+ }
+
+ private Node _instSelect( Node n, IdentityHashMap<Node,Node> map ) {
+ if( n==null ) return null;
+ Node x = map.get(n);
+ if( x !=null ) return x; // Been there, done that
+
+ // If n is a MachNode already, then its part of a multi-node expansion.
+ // It does not need instruction selection (already selected!)
+ // but it does need its inputs walked.
+ if( n instanceof MachNode ) {
+ for( int i=0; i < n.nIns(); i++ )
+ n._inputs.set(i, _instSelect(n.in(i),map) );
+ return n;
+ }
+
+ // Produce a machine node from n; map it to flag as done so stops cycles.
+ map.put(n, x=_code._mach.instSelect(n) );
+ // Stop retains the callable body. Its lifetime edge is not a machine operand.
+ if( n instanceof FunPtrNode ) x._inputs.pop();
+ // Walk machine op and replace inputs with mapped inputs
+ for( int i=0; i < x.nIns(); i++ )
+ x._inputs.set(i, _instSelect(x.in(i),map) );
+ if( x instanceof MachNode mach )
+ mach.postSelect(_code); // Post selection action
+
+ return x;
+ }
+
+ private void _instOuts( Node n, BitSet visit ) {
+ if( visit.get(n._nid) ) return;
+ visit.set(n._nid);
+ for( Node in : n._inputs )
+ if( in!=null ) {
+ in._outputs.push(n);
+ _instOuts(in,visit);
+ }
+ }
+
+}
diff --git a/chapter23/src/main/java/com/seaofnodes/simple/codegen/LRG.java b/chapter23/src/main/java/com/seaofnodes/simple/codegen/LRG.java
index 009ddcdb..0c36ae2b 100644
--- a/chapter23/src/main/java/com/seaofnodes/simple/codegen/LRG.java
+++ b/chapter23/src/main/java/com/seaofnodes/simple/codegen/LRG.java
@@ -58,6 +58,8 @@ public class LRG {
public int nadj() { return _adj==null ? 0 : _adj._len; }
+ public RegMask useMask() { return _machUse==null ? null : _machUse.regmap(_uidx); }
+
void addNeighbor(LRG lrg) {
if( _adj==null ) _adj = new Ary<>(LRG.class);
_adj.push(lrg);
diff --git a/chapter23/src/main/java/com/seaofnodes/simple/codegen/RegAlloc.java b/chapter23/src/main/java/com/seaofnodes/simple/codegen/RegAlloc.java
index 6518f3b3..51ca3a1a 100644
--- a/chapter23/src/main/java/com/seaofnodes/simple/codegen/RegAlloc.java
+++ b/chapter23/src/main/java/com/seaofnodes/simple/codegen/RegAlloc.java
@@ -416,7 +416,7 @@ public class RegAlloc {
// If the minLoopDepth is less than the maxLoopDepth: for-all defs and
// uses, if at minLoopDepth or lower, split after def and before use.
for( Node n : _ns ) {
- if( n instanceof SplitNode && min!=max ) continue; // Ignoring splits; since spilling need to split in a deeper loop
+ if( n instanceof SplitNode split && !split.isNonStackSplit() && min!=max ) continue; // Ordinary splits already reach stack storage.
if( n.isDead() ) continue; // Some Cloneable went dead by other spill changes
// If this is a 2-address commutable op (e.g. AddX86, MulX86) and the rhs has only a single user,
// commute the inputs... which chops the LHS live ranges' upper bound to just the RHS.
@@ -469,8 +469,8 @@ public class RegAlloc {
}
private static long ldepth( long ld, Node n, CFGNode cfg ) {
- // Do not count splits
- if( n instanceof SplitNode ) return ld;
+ // Ordinary splits already reach stack storage; register-only transfers do not.
+ if( n instanceof SplitNode split && !split.isNonStackSplit() ) return ld;
// Collect min/max loop depth
int min = (int)ld;
int max = (int)(ld>>32);
diff --git a/chapter23/src/main/java/com/seaofnodes/simple/codegen/TypeCheck.java b/chapter23/src/main/java/com/seaofnodes/simple/codegen/TypeCheck.java
new file mode 100644
index 00000000..0997fd2f
--- /dev/null
+++ b/chapter23/src/main/java/com/seaofnodes/simple/codegen/TypeCheck.java
@@ -0,0 +1,15 @@
+package com.seaofnodes.simple.codegen;
+
+import com.seaofnodes.simple.Parser;
+
+abstract class TypeCheck {
+ static void run(CodeGen code) {
+ Parser.ParseException err = code._stop.walk(n -> {
+ Parser.ParseException msg = n.err();
+ if( msg != null && code._obs != null ) code._obs.error(n, msg.getMessage());
+ return msg;
+ });
+ if( err != null )
+ throw err;
+ }
+}
diff --git a/chapter23/src/main/java/com/seaofnodes/simple/node/SplitNode.java b/chapter23/src/main/java/com/seaofnodes/simple/node/SplitNode.java
index 211489fb..a7fe6c5f 100644
--- a/chapter23/src/main/java/com/seaofnodes/simple/node/SplitNode.java
+++ b/chapter23/src/main/java/com/seaofnodes/simple/node/SplitNode.java
@@ -10,6 +10,8 @@ public abstract class SplitNode extends MachConcreteNode {
public final String _kind; // Kind of split
public final byte _round;
public SplitNode(String kind, byte round, Node[] nodes) { super(nodes); _kind = kind; _round = round; }
+ // A register-only transfer may need another split to reach stack storage.
+ public boolean isNonStackSplit() { return false; }
@Override public String op() { return "mov"; }
@Override protected ExprPrinter<Node> _print1(ExprPrinter<Node> p) {
p.p("mov(");
diff --git a/chapter23/src/main/java/com/seaofnodes/simple/node/cpus/arm/SplitFlagsARM.java b/chapter23/src/main/java/com/seaofnodes/simple/node/cpus/arm/SplitFlagsARM.java
new file mode 100644
index 00000000..3e045a6f
--- /dev/null
+++ b/chapter23/src/main/java/com/seaofnodes/simple/node/cpus/arm/SplitFlagsARM.java
@@ -0,0 +1,21 @@
+package com.seaofnodes.simple.node.cpus.arm;
+
+import com.seaofnodes.isa.Arm64;
+import com.seaofnodes.simple.codegen.*;
+
+// NZCV transfers require a GPR. Further splits can spill that GPR to the stack.
+public class SplitFlagsARM extends SplitARM {
+ private static final RegMask MASK = new RegMask(arm.WR_BITS,1L);
+ SplitFlagsARM(String kind,byte round) { super(kind,round); }
+ @Override public boolean isNonStackSplit() { return true; }
+ @Override public RegMask regmap(int i) { return MASK; }
+ @Override public RegMask outregmap() { return MASK; }
+
+ @Override public void encoding(Encoding enc) {
+ short dst=enc.reg(this), src=enc.reg(in(1));
+ if( dst==src ) return;
+ if( src==arm.FLAGS ) enc.add4(Arm64.flags(dst,false));
+ else if( dst==arm.FLAGS ) enc.add4(Arm64.flags(src,true));
+ else super.encoding(enc);
+ }
+}
diff --git a/chapter23/src/main/java/com/seaofnodes/simple/node/cpus/arm/SplitGPRARM.java b/chapter23/src/main/java/com/seaofnodes/simple/node/cpus/arm/SplitGPRARM.java
new file mode 100644
index 00000000..46eff4ca
--- /dev/null
+++ b/chapter23/src/main/java/com/seaofnodes/simple/node/cpus/arm/SplitGPRARM.java
@@ -0,0 +1,11 @@
+package com.seaofnodes.simple.node.cpus.arm;
+
+import com.seaofnodes.simple.codegen.*;
+
+// Keep a saved NZCV value in GPRs and stack slots through subsequent spills.
+public class SplitGPRARM extends SplitARM {
+ private static final RegMask MASK = new RegMask(arm.WR_BITS,-2L);
+ SplitGPRARM(String kind,byte round) { super(kind,round); }
+ @Override public RegMask regmap(int i) { return MASK; }
+ @Override public RegMask outregmap() { return MASK; }
+}
diff --git a/chapter23/src/main/java/com/seaofnodes/simple/node/cpus/arm/arm.java b/chapter23/src/main/java/com/seaofnodes/simple/node/cpus/arm/arm.java
index 9faf1d40..b4609419 100644
--- a/chapter23/src/main/java/com/seaofnodes/simple/node/cpus/arm/arm.java
+++ b/chapter23/src/main/java/com/seaofnodes/simple/node/cpus/arm/arm.java
@@ -269,7 +269,16 @@ public class arm extends Machine {
@Override public int rpc() { return X30; }
// Create a split op; any register to any register, including stack slots
- @Override public SplitNode split(String kind, byte round, LRG lrg) { return new SplitARM(kind,round); }
+ @Override public SplitNode split(String kind, byte round, LRG lrg) {
+ RegMask def = lrg._machDef==null ? null : lrg._machDef.outregmap(), use = lrg.useMask();
+ if( (def!=null && def.size1() && def.test(FLAGS)) ||
+ (use!=null && use.size1() && use.test(FLAGS)) )
+ return new SplitFlagsARM(kind,round);
+ // Spilling the saved flags requires a GPR between NZCV and the stack.
+ if( lrg._machDef instanceof SplitFlagsARM || lrg._machDef instanceof SplitGPRARM )
+ return new SplitGPRARM(kind,round);
+ return new SplitARM(kind,round);
+ }
// Return a MachNode unconditional branch
@Override public CFGNode jump() {
diff --git a/chapter23/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/SplitFlagsX86.java b/chapter23/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/SplitFlagsX86.java
new file mode 100644
index 00000000..4650b535
--- /dev/null
+++ b/chapter23/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/SplitFlagsX86.java
@@ -0,0 +1,25 @@
+package com.seaofnodes.simple.node.cpus.x86_64_v2;
+
+import com.seaofnodes.isa.X86;
+import com.seaofnodes.simple.codegen.*;
+
+// Flag snapshots can use GPRs or stack slots, but never XMM registers.
+public class SplitFlagsX86 extends SplitX86 {
+ private static final RegMask MASK = new RegMask(x86_64_v2.WR_BITS | (1L<<x86_64_v2.FLAGS) | x86_64_v2.SPILLS,-1L);
+ SplitFlagsX86(String kind,byte round) { super(kind,round); }
+ @Override public RegMask regmap(int i) { return MASK; }
+ @Override public RegMask outregmap() { return MASK; }
+
+ @Override public void encoding(Encoding enc) {
+ short dst=enc.reg(this), src=enc.reg(in(1));
+ if( dst==src ) return;
+ if( dst==x86_64_v2.FLAGS || src==x86_64_v2.FLAGS ) {
+ boolean toFlags = dst==x86_64_v2.FLAGS;
+ int reg = toFlags ? src : dst;
+ if( reg>=x86_64_v2.MAX_REG )
+ X86.flagsStack(enc,enc._fun.computeStackOffset(enc._code,reg),toFlags);
+ else
+ X86.flags(enc,reg,toFlags);
+ } else super.encoding(enc);
+ }
+}
diff --git a/chapter23/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/SplitX86.java b/chapter23/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/SplitX86.java
index e8281975..4e9eda7d 100644
--- a/chapter23/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/SplitX86.java
+++ b/chapter23/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/SplitX86.java
@@ -17,12 +17,10 @@ public class SplitX86 extends SplitNode {
@Override public RegMask regmap(int i) { return x86_64_v2.SPLIT_MASK; }
@Override public RegMask outregmap() { return x86_64_v2.SPLIT_MASK; }
- // Need to handle 8 cases: . reg->reg, reg->xmm, reg->flags, xmm->reg, xmm->xmm, xmm->flags, flags->reg, flags->xmm,
- // flags->flags.
+ // Ordinary GPR, XMM, and stack moves. Flags use SplitFlagsX86.
@Override public void encoding( Encoding enc ) {
short dst=enc.reg(this), src=enc.reg(in(1));
- if( dst==x86_64_v2.FLAGS ) { X86.flags(enc,src,true); return; }
- if( src==x86_64_v2.FLAGS ) { X86.flags(enc,dst,false); return; }
+ assert dst!=x86_64_v2.FLAGS && src!=x86_64_v2.FLAGS;
boolean dstX=dst>=x86_64_v2.XMM_OFFSET, srcX=src>=x86_64_v2.XMM_OFFSET;
// Stack spills
if( dst >= x86_64_v2.MAX_REG ) {
diff --git a/chapter23/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/x86_64_v2.java b/chapter23/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/x86_64_v2.java
index e283bc8f..fcae17f8 100644
--- a/chapter23/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/x86_64_v2.java
+++ b/chapter23/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/x86_64_v2.java
@@ -47,7 +47,7 @@ public class x86_64_v2 extends Machine {
static RegMask DIV_MASK = new RegMask(RD_BITS & ~(1L<<RAX) & ~(1L<<RDX));
static final long SPILLS = -(1L << MAX_REG);
- static final RegMask SPLIT_MASK = new RegMask(WR_BITS | FP_BITS /* | (1L<<FLAGS)*/ | SPILLS, -1L );
+ static final RegMask SPLIT_MASK = new RegMask(WR_BITS | FP_BITS | SPILLS, -1L );
// Load/store mask; both GPR and FPR
static RegMask MEM_MASK = new RegMask(WR_BITS | FP_BITS);
@@ -238,7 +238,9 @@ public class x86_64_v2 extends Machine {
// Create a split op; any register to any register, including stack slots
@Override public SplitNode split(String kind, byte round, LRG lrg) {
- return new SplitX86(kind, round);
+ return lrg._machDef!=null && lrg._machDef.outregmap().test(FLAGS)
+ ? new SplitFlagsX86(kind,round)
+ : new SplitX86(kind,round);
}
// Return a MachNode unconditional branch
diff --git a/chapter23/src/main/java/com/seaofnodes/simple/print/SimpleGraphObserver.java b/chapter23/src/main/java/com/seaofnodes/simple/print/SimpleGraphObserver.java
index 8877b310..fb87ec75 100644
--- a/chapter23/src/main/java/com/seaofnodes/simple/print/SimpleGraphObserver.java
+++ b/chapter23/src/main/java/com/seaofnodes/simple/print/SimpleGraphObserver.java
@@ -17,7 +17,7 @@ public class SimpleGraphObserver extends GraphCapture<Node> {
@Override protected void compile(String src) {
_code = new CodeGen(src);
_code._obs = this;
- _code.parse().opto().typeCheck();
+ _code.driver(CodeGen.Phase.TypeCheck);
}
@Override protected String phase() { return _code._phase.name(); }
@Override protected int pos() { return _code._phase == CodeGen.Phase.Parse ? _code.P.pos() : -1; }
diff --git a/chapter23/src/main/java/com/seaofnodes/simple/type/TypeStruct.java b/chapter23/src/main/java/com/seaofnodes/simple/type/TypeStruct.java
index f065126a..0077ee31 100644
--- a/chapter23/src/main/java/com/seaofnodes/simple/type/TypeStruct.java
+++ b/chapter23/src/main/java/com/seaofnodes/simple/type/TypeStruct.java
@@ -429,7 +429,7 @@ public class TypeStruct extends Type {
return _offs[idx];
}
private int[] offsets() { // Field byte offsets
- assert CodeGen.CODE._phase.ordinal() >= CodeGen.Phase.Opto.ordinal();
+ assert CodeGen.CODE._phase.ordinal() >= CodeGen.Phase.FinalizeIR.ordinal();
// Compute a layout for a collection of fields
assert _fields != null; // No forward refs
diff --git a/chapter23/src/test/java/com/seaofnodes/simple/Chapter05Test.java b/chapter23/src/test/java/com/seaofnodes/simple/Chapter05Test.java
index 6ff4ac95..8168594a 100644
--- a/chapter23/src/test/java/com/seaofnodes/simple/Chapter05Test.java
+++ b/chapter23/src/test/java/com/seaofnodes/simple/Chapter05Test.java
@@ -20,7 +20,7 @@ else {
}
return a;
""");
- code.parse().opto();
+ code.parse().iter().finalizeIR();
assertEquals("return Phi(Region,(arg+2),(arg-3));", code.print());
}
@@ -36,7 +36,7 @@ if (arg == 1) {
}
return c;
""");
- code.parse().opto();
+ code.parse().iter().finalizeIR();
assertEquals("return Phi(Region,4,3);", code.print());
}
@@ -64,7 +64,7 @@ if( arg==1 )
else
b=a+1;
return a+b;""");
- code.parse().opto();
+ code.parse().iter().finalizeIR();
assertEquals("return ((arg<<1)+Phi(Region,2,3));", code.print());
}
@@ -79,7 +79,7 @@ if( arg==1 )
else
a=b+1;
return a+b;""");
- code.parse().opto();
+ code.parse().iter().finalizeIR();
assertEquals("return ((Phi(Region,(arg<<1),arg)+arg)+Phi(Region,4,5));", code.print());
}
@@ -99,7 +99,7 @@ else
a=5;
return a;
""");
- code.parse().opto();
+ code.parse().iter().finalizeIR();
assertEquals("return Phi(Region,3,5,2,4);", code.print());
}
@@ -115,7 +115,7 @@ if( arg==0 )
b=2;
return arg+a+b;
""");
- code.parse().opto();
+ code.parse().iter().finalizeIR();
assertEquals("return ((arg+Phi(Region,1,0))+Phi(Region,2,0));", code.print());
}
@@ -130,7 +130,7 @@ if( arg==1 )
}
return a;
""");
- code.parse().opto();
+ code.parse().iter().finalizeIR();
assertEquals("return (arg==Phi(Region,3,2));", code.print());
}
@@ -145,7 +145,7 @@ else
a=3;
return a;
""");
- code.parse().opto();
+ code.parse().iter().finalizeIR();
assertEquals("return 3;", code.print());
}
diff --git a/chapter23/src/test/java/com/seaofnodes/simple/Chapter06Test.java b/chapter23/src/test/java/com/seaofnodes/simple/Chapter06Test.java
index 1ff875b4..d817a015 100644
--- a/chapter23/src/test/java/com/seaofnodes/simple/Chapter06Test.java
+++ b/chapter23/src/test/java/com/seaofnodes/simple/Chapter06Test.java
@@ -15,7 +15,7 @@ public class Chapter06Test {
if( true ) return 2;
return 1;
""");
- code.parse().opto();
+ code.parse().iter().finalizeIR();
assertEquals("return 2;", code.print());
assertTrue(code.ctrl() instanceof FunNode);
}
@@ -29,7 +29,7 @@ if (arg)
a = 2;
return (arg < a) < 3; // Because (arg < a) is a bool/uint1/[0-1], its always less than 3
""");
- code.parse().opto();
+ code.parse().iter().finalizeIR();
assertEquals("return 1;", code.print());
}
@@ -44,7 +44,7 @@ else
a=3;
return a;
""");
- code.parse().opto();
+ code.parse().iter().finalizeIR();
assertEquals("return 2;", code.print());
assertTrue(code.ctrl() instanceof FunNode);
}
@@ -65,7 +65,7 @@ else
b=5;
return b;
""");
- code.parse().opto();
+ code.parse().iter().finalizeIR();
assertEquals("return Phi(Region,42,5);", code.print());
}
@@ -84,7 +84,7 @@ if( arg==2 )
else
b=5;
return b;""");
- code.parse().opto();
+ code.parse().iter().finalizeIR();
assertEquals("return Phi(Region,2,5);", code.print());
}
@@ -104,7 +104,7 @@ else if( arg==3 )
else
a=5;
return a;
-""", TypeInteger.constant(2), 123L, true).parse().opto();
+""", TypeInteger.constant(2), 123L, true).parse().iter().finalizeIR();
assertEquals("return 5;", code.print());
}
@@ -124,7 +124,7 @@ else if( arg==3 )
else
a=5;
return a;
-""", TypeInteger.constant(1), 123L, true).parse().opto();
+""", TypeInteger.constant(1), 123L, true).parse().iter().finalizeIR();
assertEquals("return 3;", code.print());
}
@@ -144,7 +144,7 @@ else
a=5;
return a;
""");
- code.parse().opto();
+ code.parse().iter().finalizeIR();
assertEquals("return Phi(Region,3,5,4);", code.print());
}
@@ -165,7 +165,7 @@ else
a=5;
return a;
""", TypeInteger.constant(1), 123L, true);
- code.parse().opto();
+ code.parse().iter().finalizeIR();
assertEquals("return 3;", code.print());
}
@@ -186,7 +186,7 @@ else
a=5;
return a;
""", TypeInteger.constant(3), 123L, true);
- code.parse().opto();
+ code.parse().iter().finalizeIR();
assertEquals("return 4;", code.print());
}
@@ -202,7 +202,7 @@ if( arg ) {
}
return a+b;
""");
- code.parse().opto();
+ code.parse().iter().finalizeIR();
assertEquals("return Phi(Region,4,1);", code.print());
}
@@ -221,7 +221,7 @@ if( arg ) {
}
return a+b;
""", TypeInteger.constant(1), 123L, true);
- code.parse().opto();
+ code.parse().iter().finalizeIR();
assertEquals("return 4;", code.print());
}
@@ -239,7 +239,7 @@ if( arg ) {
}
return a+b;
""", TypeInteger.constant(0), 123L, true);
- code.parse().opto();
+ code.parse().iter().finalizeIR();
assertEquals("return 1;", code.print());
}
@@ -257,7 +257,7 @@ if( arg ) {
}
return a+b+c;
""");
- code.parse().opto();
+ code.parse().iter().finalizeIR();
assertEquals("return Phi(Region,6,1,5);", code.print());
}
@@ -278,7 +278,7 @@ if( arg ) {
}
return a+b+c;
""", TypeInteger.constant(1), 123L, true);
- code.parse().opto();
+ code.parse().iter().finalizeIR();
assertEquals("return 6;", code.print());
}
@@ -298,7 +298,7 @@ if( arg ) {
}
return a+b+c;
""", TypeInteger.constant(2), 123L, true);
- code.parse().opto();
+ code.parse().iter().finalizeIR();
assertEquals("return 5;", code.print());
}
diff --git a/chapter23/src/test/java/com/seaofnodes/simple/Chapter07Test.java b/chapter23/src/test/java/com/seaofnodes/simple/Chapter07Test.java
index 88554323..0ebc427c 100644
--- a/chapter23/src/test/java/com/seaofnodes/simple/Chapter07Test.java
+++ b/chapter23/src/test/java/com/seaofnodes/simple/Chapter07Test.java
@@ -34,7 +34,7 @@ if(arg){}else{
}
return a;
""");
- code.parse().opto();
+ code.parse().iter().finalizeIR();
assertEquals("return Phi(Region,1,Phi(Loop,1,(Phi_a+1)));", code.print());
}
@@ -54,7 +54,7 @@ while(i < arg) {
}
return sum;
""");
- code.parse().opto();
+ code.parse().iter().finalizeIR();
assertEquals("return Phi(Loop,0,Phi(Loop,Phi_sum,(Phi_sum+Phi(Loop,0,(Phi_j+1)))));", code.print());
}
@@ -89,7 +89,7 @@ while(a < 10) {
}
return b;
""");
- code.parse().opto();
+ code.parse().iter().finalizeIR();
assertEquals("return Phi(Loop,2,(Phi(Region,Phi_b,4)+1));", code.print());
assertTrue(code.ctrl() instanceof CProjNode);
}
@@ -122,7 +122,7 @@ while(a < 10) {
}
return a;
""");
- code.parse().opto();
+ code.parse().iter().finalizeIR();
assertEquals("return Phi(Loop,1,(Phi_a+3));", code.print());
assertTrue(code.ctrl() instanceof CProjNode);
}
@@ -148,7 +148,7 @@ int a = 1;
while(arg) a = 2;
return a;
""");
- code.parse().opto();
+ code.parse().iter().finalizeIR();
assertEquals("return Phi(Loop,1,2);", code.print());
assertTrue(code.ctrl() instanceof CProjNode);
}
@@ -180,7 +180,7 @@ while(a < 10) {
}
return a;
""");
- code.parse().opto();
+ code.parse().iter().finalizeIR();
assertEquals("return Phi(Loop,1,(Phi_a+3));", code.print());
assertTrue(code.ctrl() instanceof CProjNode);
}
@@ -214,7 +214,7 @@ while(a < 10) {
}
return a;
""");
- code.parse().opto();
+ code.parse().iter().finalizeIR();
assertEquals("return Phi(Loop,1,(Phi_a+3));", code.print());
assertTrue(code.ctrl() instanceof CProjNode);
}
diff --git a/chapter23/src/test/java/com/seaofnodes/simple/Chapter08Test.java b/chapter23/src/test/java/com/seaofnodes/simple/Chapter08Test.java
index 09669cc7..543b91d1 100644
--- a/chapter23/src/test/java/com/seaofnodes/simple/Chapter08Test.java
+++ b/chapter23/src/test/java/com/seaofnodes/simple/Chapter08Test.java
@@ -22,7 +22,7 @@ while(arg < 10) {
}
return arg;
""");
- code.parse().opto();
+ code.parse().iter().finalizeIR();
assertEquals("return Phi(Region,(Phi(Loop,arg,Add)+1),Add,Phi_arg);", code.print());
assertTrue(code.ctrl() instanceof RegionNode);
Assert.assertEquals( "5", Eval2.eval(code, 1));
@@ -45,7 +45,7 @@ while(arg < 10) {
}
return a;
""");
- code.parse().opto();
+ code.parse().iter().finalizeIR();
assertEquals("return Phi(Loop,1,Phi(Region,Phi_a,(Phi_a+1),Phi_a));", code.print());
assertTrue(code.ctrl() instanceof CProjNode);
}
@@ -64,7 +64,7 @@ while(arg < 10) {
}
return arg;
""");
- code.parse().opto();
+ code.parse().iter().finalizeIR();
assertEquals("return Phi(Region,Phi(Loop,arg,(Phi_arg+1)),Add);", code.print());
assertTrue(code.ctrl() instanceof RegionNode);
}
@@ -80,7 +80,7 @@ while(arg < 10) {
}
return arg;
""");
- code.parse().opto();
+ code.parse().iter().finalizeIR();
assertEquals("return Phi(Region,Phi(Loop,arg,(Phi_arg+1)),Add);", code.print());
assertTrue(code.ctrl() instanceof RegionNode);
}
@@ -99,7 +99,7 @@ while(arg < 10) {
}
return arg;
""");
- code.parse().opto();
+ code.parse().iter().finalizeIR();
assertEquals("return Phi(Loop,arg,(Phi_arg+1));", code.print());
assertTrue(code.ctrl() instanceof CProjNode);
}
@@ -116,7 +116,7 @@ while(arg < 10) {
}
return arg;
""");
- code.parse().opto();
+ code.parse().iter().finalizeIR();
assertEquals("return Phi(Loop,arg,(Phi_arg+1));", code.print());
assertTrue(code.ctrl() instanceof CProjNode);
}
@@ -132,14 +132,14 @@ while( arg < 10 ) {
}
return arg;
""");
- code.parse().opto();
+ code.parse().iter().finalizeIR();
assertEquals("return arg;", code.print());
}
@Test
public void testRegress2() {
CodeGen code = new CodeGen("if(1) return 0; else while(arg>- -arg) arg=arg+1; return 0;");
- code.parse().opto();
+ code.parse().iter().finalizeIR();
assertEquals("return 0;", code.print());
}
@@ -167,7 +167,7 @@ while(arg < 10) {
}
return arg;
""");
- code.parse().opto();
+ code.parse().iter().finalizeIR();
assertEquals("return arg;", code.print());
}
@@ -184,7 +184,7 @@ while(arg < 10) {
}
return a;
""");
- code.parse().opto();
+ code.parse().iter().finalizeIR();
assertEquals("return Phi(Region,Phi(Loop,1,(Phi_a+1)),Add);", code.print());
assertTrue(code.ctrl() instanceof RegionNode);
}
@@ -200,7 +200,7 @@ while(1) {
}
return a;
""");
- code.parse().opto();
+ code.parse().iter().finalizeIR();
assertEquals("return (Phi(Loop,1,Add)+1);", code.print());
assertTrue(code.ctrl() instanceof CProjNode prj && prj._idx==1 );
}
diff --git a/chapter23/src/test/java/com/seaofnodes/simple/Chapter09Test.java b/chapter23/src/test/java/com/seaofnodes/simple/Chapter09Test.java
index 54a14a25..3a4415d9 100644
--- a/chapter23/src/test/java/com/seaofnodes/simple/Chapter09Test.java
+++ b/chapter23/src/test/java/com/seaofnodes/simple/Chapter09Test.java
@@ -24,7 +24,7 @@ while(v0) {
}
return 0;
""");
- code.parse().opto();
+ code.parse().iter().finalizeIR();
}
@Test
@@ -40,7 +40,7 @@ else {
}
return x;
""");
- code.parse().opto();
+ code.parse().iter().finalizeIR();
assertEquals("return Phi(Region,(arg<<1),(Shl+1));", code.print());
Assert.assertEquals( "2", Eval2.eval(code, 1));
Assert.assertEquals("23", Eval2.eval(code, 11));
@@ -49,7 +49,7 @@ return x;
@Test
public void testGVN2() {
CodeGen code = new CodeGen("return arg*arg-arg*arg;");
- code.parse().opto();
+ code.parse().iter().finalizeIR();
assertEquals("return 0;", code.print());
Assert.assertEquals("0", Eval2.eval(code, 1, 1));
}
@@ -63,7 +63,7 @@ while (arg < 10) {
}
return arg;
""");
- code.parse().opto();
+ code.parse().iter().finalizeIR();
assertEquals("return Phi(Loop,arg,(Phi_arg+2));", code.print());
Assert.assertEquals("11", Eval2.eval(code, 1));
}
@@ -80,7 +80,7 @@ while (arg < 10) {
}
return arg;
""");
- code.parse().opto();
+ code.parse().iter().finalizeIR();
assertEquals("return Phi(Loop,arg,(Phi_arg+4));", code.print());
Assert.assertEquals("13", Eval2.eval(code, 1));
}
@@ -109,7 +109,7 @@ while (arg) {
}
return arg;
""");
- code.parse().opto();
+ code.parse().iter().finalizeIR();
assertEquals("return 0;", code.print());
}
@@ -128,14 +128,14 @@ while(v1+arg) {
}
return 0;
""");
- code.parse().opto();
+ code.parse().iter().finalizeIR();
assertEquals("return 0;", code.print());
}
@Test
public void testWhile0() {
CodeGen code = new CodeGen("while(0) continue; if(0) arg=0; return arg;");
- code.parse().opto();
+ code.parse().iter().finalizeIR();
assertEquals("return arg;", code.print());
}
@@ -148,7 +148,7 @@ if(0) while(0) {
}
return 0;
""");
- code.parse().opto();
+ code.parse().iter().finalizeIR();
assertEquals("return 0;", code.print());
}
@@ -156,14 +156,14 @@ return 0;
@Test
public void testPrecedence() {
CodeGen code = new CodeGen("return 3-1+2;");
- code.parse().opto();
+ code.parse().iter().finalizeIR();
assertEquals("return 4;", code.print());
}
@Test
public void testSwap2() {
CodeGen code = new CodeGen("return 1+(1+1);");
- code.parse().opto();
+ code.parse().iter().finalizeIR();
assertEquals("return 3;", code.print());
}
@@ -181,7 +181,7 @@ while(arg) {
}
return a;
""");
- code.parse().opto();
+ code.parse().iter().finalizeIR();
assertEquals("return Phi(Loop,0,(-(Phi_a+3)));", code.print());
}
@@ -195,7 +195,7 @@ arg=0;
int v0=0!=0<-0;
return -0+0+0;
""");
- code.parse().opto();
+ code.parse().iter().finalizeIR();
assertEquals("return Top;", code.print());
}
@@ -203,14 +203,14 @@ return -0+0+0;
@Test
public void testFuzz2() {
CodeGen code = new CodeGen("return 0+-0;");
- code.parse().opto();
+ code.parse().iter().finalizeIR();
assertEquals("return 0;", code.print());
}
@Test
public void testFuzz3() {
CodeGen code = new CodeGen("int v0=0; while(0==69) while(v0) return 0; return 0;");
- code.parse().opto();
+ code.parse().iter().finalizeIR();
assertEquals("return 0;", code.print());
}
@@ -222,7 +222,7 @@ while(1) {
if(1<0) while(arg==-0) arg=arg-arg;
}
""");
- code.parse().opto();
+ code.parse().iter().finalizeIR();
assertEquals("return Top;", code.print());
}
@@ -244,7 +244,7 @@ while(1) {
}
return 0!=0;
""");
- code.parse().opto();
+ code.parse().iter().finalizeIR();
assertEquals("return Top;", code.print());
}
@@ -257,7 +257,7 @@ while(0==1) while(v0)
v0=1+v0;
return 0;
""");
- code.parse().opto();
+ code.parse().iter().finalizeIR();
assertEquals("return 0;", code.print());
}
@@ -273,14 +273,14 @@ while(1)
v1=1;
return v1+v0;
""");
- code.parse().opto();
+ code.parse().iter().finalizeIR();
assertEquals("return Top;", code.print());
}
@Test
public void testFuzz8() {
CodeGen code = new CodeGen("while(arg) arg = arg - 1; return arg;");
- code.parse().opto();
+ code.parse().iter().finalizeIR();
assertEquals("return 0;", code.print());
}
diff --git a/chapter23/src/test/java/com/seaofnodes/simple/Chapter10Test.java b/chapter23/src/test/java/com/seaofnodes/simple/Chapter10Test.java
index 0f4ca169..78265bb2 100644
--- a/chapter23/src/test/java/com/seaofnodes/simple/Chapter10Test.java
+++ b/chapter23/src/test/java/com/seaofnodes/simple/Chapter10Test.java
@@ -14,7 +14,7 @@ public class Chapter10Test {
"if(1) return new S; else return 0;"
} ) {
String src = "struct S { int x; }; " + body;
- var code = new CodeGen(src).parse().opto().typeCheck();
+ var code = new CodeGen(src).driver(CodeGen.Phase.TypeCheck);
org.junit.Assert.assertTrue(body,
code.expr()._type instanceof com.seaofnodes.simple.type.TypeMemPtr);
}
@@ -40,7 +40,7 @@ public class Chapter10Test {
"int b = !!p; if (b) return p.x + b - 1; return -1;",
"if (!(p == null || arg == 0)) return p.x; return -1;"
} ) {
- CodeGen code = new CodeGen(NULLABLE_POINT_SOURCE+body).parse().opto().typeCheck();
+ CodeGen code = new CodeGen(NULLABLE_POINT_SOURCE+body).driver(CodeGen.Phase.TypeCheck);
assertEquals(body,"-1",Eval2.eval(code,0));
assertEquals(body,"42",Eval2.eval(code,1));
}
@@ -70,7 +70,7 @@ public class Chapter10Test {
"if (!!p) { int x = p.x; } return p.x;"
} ) {
try {
- new CodeGen(NULLABLE_POINT_SOURCE+body).parse().opto().typeCheck();
+ new CodeGen(NULLABLE_POINT_SOURCE+body).driver(CodeGen.Phase.TypeCheck);
fail(body);
} catch( RuntimeException e ) {
// Known null is rejected during parsing in these chapters.
@@ -102,7 +102,7 @@ if( (arg/13)==0 ) {
int r = g+h;
return p-r;
""");
- code.parse().opto();
+ code.parse().iter().finalizeIR();
assertEquals("return 0;", code.print());
}
@@ -122,7 +122,7 @@ bar.a = 1;
bar.a = 2;
return bar.a;
""");
- code.parse().opto();
+ code.parse().iter().finalizeIR();
assertEquals("return 2;", code.print());
}
@@ -138,7 +138,7 @@ else
v.y = 3;
return v;
""");
- code.parse().opto();
+ code.parse().iter().finalizeIR();
assertEquals("return Vector2D;", code.print());
}
@@ -176,7 +176,7 @@ while (arg) {
}
return bar.a;
""");
- code.parse().opto();
+ code.parse().iter().finalizeIR();
assertEquals("return Phi(Loop,0,(Phi_a+2));", code.print());
}
@@ -189,7 +189,7 @@ if (arg) bar = null;
bar.a = 1;
return bar.a;
""");
- try { code.parse().opto().typeCheck(); fail(); }
+ try { code.driver(CodeGen.Phase.TypeCheck); fail(); }
catch( Exception e ) { assertEquals("Type null is not of declared type *Bar",e.getMessage()); }
}
@@ -202,7 +202,7 @@ if (arg) bar = new Bar;
bar.a = 1;
return bar.a;
""");
- try { code.parse().opto().typeCheck(); fail(); }
+ try { code.driver(CodeGen.Phase.TypeCheck); fail(); }
catch( Exception e ) { assertEquals("Might be null accessing 'a'",e.getMessage()); }
}
@@ -215,7 +215,7 @@ if (arg) bar = null;
bar.a = 1;
return bar.a;
""");
- try { code.parse().opto().typeCheck(); fail(); }
+ try { code.driver(CodeGen.Phase.TypeCheck); fail(); }
catch( Exception e ) { assertEquals("Type null is not of declared type *Bar", e.getMessage()); }
}
@@ -228,7 +228,7 @@ if (arg) bar = null;
if( bar ) bar.a = 1;
return bar;
""");
- code.parse().opto();
+ code.parse().iter().finalizeIR();
assertEquals("return Phi(Region,null,Bar);", code.print());
}
@@ -244,7 +244,7 @@ if( !bar ) rez=4;
else bar.a = 1;
return rez;
""");
- code.parse().opto();
+ code.parse().iter().finalizeIR();
assertEquals("return Phi(Region,4,3);", code.print());
}
@@ -261,7 +261,7 @@ while(arg) {
}
return ret;
""");
- try { code.parse().opto().typeCheck(); fail(); }
+ try { code.driver(CodeGen.Phase.TypeCheck); fail(); }
catch( Exception e ) {
assertEquals("Might be null accessing 'v0'", e.getMessage()); }
}
@@ -298,7 +298,7 @@ while( i.x < i.len ) {
}
return sum;
""");
- code.parse().opto();
+ code.parse().iter().finalizeIR();
assertEquals("return Phi(Loop,0,(Phi(Loop,0,(Phi_x+1))+Phi_sum));", code.print());
}
@@ -317,7 +317,7 @@ while(arg) {
}
return ret;
""");
- code.parse().opto();
+ code.parse().iter().finalizeIR();
assertEquals("return Phi(Loop,s0,Phi(Region,s0,Phi_ret));", code.print());
}
@@ -335,7 +335,7 @@ while(arg) {
}
return ret;
""");
- code.parse().opto();
+ code.parse().iter().finalizeIR();
assertEquals("return Phi(Loop,s0,Phi(Region,s0,Phi_ret));", code.print());
}
@@ -352,7 +352,7 @@ while(arg < 10) {
}
return ret;
""");
- code.parse().opto();
+ code.parse().iter().finalizeIR();
assertEquals("return Phi(Loop,s0,Phi(Region,s0,Phi_ret));", code.print());
}
@@ -380,7 +380,7 @@ if(0) {
}
return 0;
""");
- code.parse().opto();
+ code.parse().iter().finalizeIR();
assertEquals("return 0;", code.print());
}
@@ -394,7 +394,7 @@ if(0) return 0;
else return new s0;
if(new s0.f0) return 0;
""");
- code.parse().opto();
+ code.parse().iter().finalizeIR();
assertEquals("return s0;", code.print());
}
@@ -410,7 +410,7 @@ while(0<arg) {
}
return 0;
""");
- code.parse().opto();
+ code.parse().iter().finalizeIR();
}
@Test
@@ -422,7 +422,7 @@ while(v0.f0) {}
s0 v1 = v0;
return v1;
""");
- code.parse().opto();
+ code.parse().iter().finalizeIR();
assertEquals("return (const)s0;", code.print());
}
@@ -455,7 +455,7 @@ while(0) {}
}
return 0;
""");
- code.parse().opto();
+ code.parse().iter().finalizeIR();
assertEquals("return 0;", code.print());
}
@@ -466,7 +466,7 @@ int v0=arg==0;
while(v0) continue;
return 0;
""");
- code.parse().opto();
+ code.parse().iter().finalizeIR();
assertEquals("return 0;", code.print());
}
@@ -480,7 +480,7 @@ return 0;
a.y = 55; b.y = 66;
a.x = 33; b.x = 44;
return before*100 + p.x;
- """).parse().opto();
+ """).parse().iter().finalizeIR();
StopNode stop = code._stop;
assertEquals("1133",Eval2.eval(code,0));
assertEquals("2244",Eval2.eval(code,1));
@@ -506,7 +506,7 @@ return 0;
""";
@Test public void testMemoryAcrossNestedLoops() {
- var code = new CodeGen(NESTED_MEMORY).parse().opto();
+ var code = new CodeGen(NESTED_MEMORY).parse().iter().finalizeIR();
StopNode stop = code._stop;
for (int arg=0; arg<7; arg++) {
assertEquals("S{x="+(5L+arg)+",y="+(7L+arg*(arg+1)-(arg>=2 ? 2 : 0))+
@@ -522,7 +522,7 @@ return 0;
if (arg) { s.x = 11; s.z = 13; return s; }
s.y = 17;
return s;
- """).parse().opto();
+ """).parse().iter().finalizeIR();
StopNode stop = code._stop;
for (int arg=0; arg<2; arg++) {
assertEquals(arg==0 ? "S{x=3,y=17,z=7}" : "S{x=11,y=5,z=13}",Eval2.eval(code,arg));
@@ -539,7 +539,7 @@ return 0;
int v;
if (arg>1) v=p.x; else v=q.x;
return v;
- """).parse().opto();
+ """).parse().iter().finalizeIR();
StopNode stop = code._stop;
// The one-step safety check stops at the memory aggregate.
assertEquals(2,countMemoryNodes(stop,LoadNode.class,new BitSet()));
@@ -554,7 +554,7 @@ return 0;
!S !s = new S;
if (arg) s.x=arg+1; else s.x=arg+2;
return s;
- """).parse().opto();
+ """).parse().iter().finalizeIR();
StopNode stop = code._stop;
assertEquals(1,countMemoryNodes(stop,StoreNode.class,new BitSet()));
assertEquals("S{x=2}",Eval2.eval(code,0));
@@ -572,7 +572,7 @@ return 0;
if (arg>1) { v=p.x; p.x=41; p.y=5; }
else { v=q.x; q.x=42; }
return v;
- """).parse().opto();
+ """).parse().iter().finalizeIR();
StopNode stop = code._stop;
assertEquals(2,countMemoryNodes(stop,LoadNode.class,new BitSet()));
assertEquals("-1",Eval2.eval(code,-1));
diff --git a/chapter23/src/test/java/com/seaofnodes/simple/Chapter11Test.java b/chapter23/src/test/java/com/seaofnodes/simple/Chapter11Test.java
index 3d5d2686..43a780ec 100644
--- a/chapter23/src/test/java/com/seaofnodes/simple/Chapter11Test.java
+++ b/chapter23/src/test/java/com/seaofnodes/simple/Chapter11Test.java
@@ -13,7 +13,7 @@ public class Chapter11Test {
s.x = 42;
while (arg > 0) { s.y = s.y + arg; arg = arg - 1; }
return s.x;
- """).parse().opto();
+ """).parse().iter().finalizeIR();
var stop = code._stop;
assertEquals("return 42;",stop.toString());
assertEquals("42",Eval2.eval(code,5));
@@ -32,7 +32,7 @@ public class Chapter11Test {
arg = arg - 1;
}
return a;
- """).parse().opto();
+ """).parse().iter().finalizeIR();
var stop = code._stop;
int[] phis = {0};
stop.walk(n -> {
@@ -54,7 +54,7 @@ public class Chapter11Test {
// it. Keep both the worklist assertion and the final heap check.
for (int seed : new int[]{0,97,123,456}) {
var code = new CodeGen(Chapter10Test.NESTED_MEMORY,com.seaofnodes.simple.type.TypeInteger.BOT,seed,false).parse();
- code.opto();
+ code.iter().finalizeIR();
assertEquals("S{x=9,y=25,z=17}",Eval2.eval(code,4));
}
}
diff --git a/chapter23/src/test/java/com/seaofnodes/simple/Chapter12Test.java b/chapter23/src/test/java/com/seaofnodes/simple/Chapter12Test.java
index ac3b81ec..4026ea8b 100644
--- a/chapter23/src/test/java/com/seaofnodes/simple/Chapter12Test.java
+++ b/chapter23/src/test/java/com/seaofnodes/simple/Chapter12Test.java
@@ -14,7 +14,7 @@ public class Chapter12Test {
"""
return 3.14;
""");
- code.parse().opto();
+ code.parse().iter().finalizeIR();
assertEquals("return 3.14;", code.print());
assertEquals("3.14", Eval2.eval(code, 0));
}
@@ -34,7 +34,7 @@ while( arg ) {
}
return head.next.i;
""");
- try { code.parse().opto().typeCheck(); fail(); }
+ try { code.driver(CodeGen.Phase.TypeCheck); fail(); }
catch( Exception e ) { assertEquals("Might be null accessing 'next'",e.getMessage()); }
}
@@ -56,7 +56,7 @@ LLI? next = head.next;
if( next==null ) return 1;
return next.q;
""");
- code.parse().opto().typeCheck();
+ code.driver(CodeGen.Phase.TypeCheck);
assertEquals("return Phi(Region,0,1,.q);", code.print());
assertEquals("2", Eval2.eval(code, 3));
}
@@ -75,7 +75,7 @@ i0.f = f0;
f0.i = i0;
return f0.i.f.i.i;
""");
- code.parse().opto();
+ code.parse().iter().finalizeIR();
assertEquals("return 17;", code.print());
}
@@ -87,7 +87,7 @@ struct N { !N? !next; int i; };
N n = new N;
return n.next;
""");
- code.parse().opto();
+ code.parse().iter().finalizeIR();
assertEquals("return null;", code.print());
}
@@ -100,7 +100,7 @@ struct N { !M !next; int i; };
N n = new N { next = new M; };
return n.next;
""");
- code.parse().opto();
+ code.parse().iter().finalizeIR();
assertEquals("return (const)M;", code.print());
}
@@ -113,7 +113,7 @@ struct N { !M !next; int i; };
N n = new N { next = null; };
return n.next;
""");
- try { code.parse().opto().typeCheck(); fail(); }
+ try { code.driver(CodeGen.Phase.TypeCheck); fail(); }
catch( Exception e ) { assertEquals("Type null is not of declared type *M",e.getMessage()); }
}
@@ -126,20 +126,20 @@ struct N { !N? !next; int i; };
n.i = 3.14;
return n.i;
""");
- code.parse().opto().typeCheck();
+ code.driver(CodeGen.Phase.TypeCheck);
assertEquals("3",Eval2.eval(code,0));
}
@Test
public void testNullRef4() {
CodeGen code = new CodeGen("return -null-5/null-5;");
- try { code.parse().opto().typeCheck(); fail(); }
+ try { code.driver(CodeGen.Phase.TypeCheck); fail(); }
catch( Exception e ) { assertEquals("Cannot '//' null",e.getMessage()); }
}
@Test public void testNullRef5() {
CodeGen code = new CodeGen("return null+42;");
- try { code.parse().opto().typeCheck(); fail(); }
+ try { code.driver(CodeGen.Phase.TypeCheck); fail(); }
catch( Exception e ) { assertEquals("Cannot '+' null",e.getMessage()); }
}
@@ -150,7 +150,7 @@ return n.i;
struct S{};
return 0;
""");
- code.parse().opto();
+ code.parse().iter().finalizeIR();
assertEquals("return 0;", code.print());
assertEquals("0", Eval2.eval(code, 0));
}
@@ -162,7 +162,7 @@ return 0;
struct S1 { !S2? !s; };
return new S2;
""");
- try { code.parse().opto(); fail(); }
+ try { code.parse().iter().finalizeIR(); fail(); }
catch( Exception e ) { assertEquals("Unknown struct type 'S2'",e.getMessage()); }
}
@@ -174,7 +174,7 @@ struct S1 { !S2? !s; };
struct S2 { int x; };
return new S1.s=new S2;
""");
- code.parse().opto();
+ code.parse().iter().finalizeIR();
assertEquals("return S2;", code.print());
}
@@ -191,7 +191,7 @@ p2.pi.i = 2;
if (arg) p1 = new P;
return p1.pi.i + 1;
""");
- try { code.parse().opto().typeCheck(); fail(); }
+ try { code.driver(CodeGen.Phase.TypeCheck); fail(); }
catch( Exception e ) { assertEquals("Might be null accessing 'i'",e.getMessage()); }
}
@@ -210,7 +210,7 @@ c.f0=a; c.f1=b;
return a.f0.f1.f0.f1.f0;
""");
- code.parse().opto().typeCheck().GCM().localSched();
+ code.driver(CodeGen.Phase.LocalSched);
assertEquals("return B;", code._stop.toString());
assertEquals("B{f0=C},f1=A{f0=$cyclic,f1=$cyclic}}", Eval2.eval(code, 0));
}
@@ -276,7 +276,7 @@ z.a=k; z.b=s; z.c=e;
return a.b.c.a.b.c.a.b.c.a.b.c.a.b.c.a.b.c;
""");
- code.parse().opto().typeCheck().GCM().localSched();
+ code.driver(CodeGen.Phase.LocalSched);
assertEquals("return R;", code._stop.toString());
assertEquals("R{a=C{a=N},b=V},c=H}},b=K{a=$cyclic,b=D{a=O},b=W},c=I}},c=P}},c=$cyclic}", Eval2.eval(code, 0));
}
diff --git a/chapter23/src/test/java/com/seaofnodes/simple/Chapter13Test.java b/chapter23/src/test/java/com/seaofnodes/simple/Chapter13Test.java
index 63f1d12c..6451ad1d 100644
--- a/chapter23/src/test/java/com/seaofnodes/simple/Chapter13Test.java
+++ b/chapter23/src/test/java/com/seaofnodes/simple/Chapter13Test.java
@@ -290,8 +290,11 @@ else {
}
}
""");
- code.parse().opto().typeCheck().GCM();
+ code.driver(CodeGen.Phase.TypeCheck);
assertEquals("return 9;", code.print());
+ code.driver(CodeGen.Phase.Schedule);
+ // LoopTree connects the nonreturning paths using synthetic Never exits.
+ assertEquals("return Phi(Region,9,Top,Top,Top,Top);", code.print());
}
@@ -322,7 +325,7 @@ while( prime <= arg ) {
}
return primeCount;
""");
- code.parse().opto();
+ code.parse().iter().finalizeIR();
assertEquals("return Phi(Region,0,Phi(Loop,1,Phi(Region,Phi_primeCount,Phi_primeCount,(Phi_primeCount+1))));", code.print());
assertEquals("0", Eval2.eval(code, 1)); // No primes 1 or below
assertEquals("1", Eval2.eval(code, 2)); // 2
@@ -344,7 +347,7 @@ i=v.f;
if (arg) v.f=1;
return i;
""");
- code.parse().opto();
+ code.parse().iter().finalizeIR();
assertEquals("return 2;", code.print());
assertEquals("2", Eval2.eval(code, 0));
assertEquals("2", Eval2.eval(code, 1));
@@ -367,7 +370,7 @@ if (arg) {
}
return i;
""");
- code.parse().opto();
+ code.parse().iter().finalizeIR();
assertEquals("return Phi(Region,.f,0);", code.print());
}
@@ -386,7 +389,7 @@ if (v1) {
}
return v0;
""");
- code.parse().opto();
+ code.parse().iter().finalizeIR();
assertEquals("return S;", code.print());
}
@@ -404,7 +407,7 @@ if (arg+1) arg= 0;
while (arg) v.f = 2;
return i;
""");
- code.parse().opto();
+ code.parse().iter().finalizeIR();
assertEquals("return arg;", code.print());
}
@@ -421,7 +424,7 @@ while(1) {
}
return v;
""");
- code.parse().opto();
+ code.parse().iter().finalizeIR();
assertEquals("return S;", code.print());
}
@@ -436,7 +439,7 @@ while( -arg )
while(1)
arg = arg+ptr.v;
""");
- code.parse().opto();
+ code.parse().iter().finalizeIR();
assertEquals("return Top;", code.print());
}
@@ -454,7 +457,7 @@ while (arg) {
}
return i;
""");
- code.parse().opto();
+ code.parse().iter().finalizeIR();
assertEquals("return 0;", code.print());
}
@@ -474,7 +477,7 @@ while(arg) {
}
return arg;
""");
- code.parse().opto();
+ code.parse().iter().finalizeIR();
assertEquals("return 0;", code.print());
}
@@ -492,7 +495,7 @@ if (arg) {
}
return v;
""");
- code.parse().opto();
+ code.parse().iter().finalizeIR();
assertEquals("return S;", code.print());
}
@@ -511,7 +514,7 @@ while (arg > 0) {
}
return v;
""");
- code.parse().opto();
+ code.parse().iter().finalizeIR();
//assertEquals("return new S;", code.print());
}
@@ -528,7 +531,7 @@ while(0>=0) {
}
return 0;
""");
- code.parse().opto();
+ code.parse().iter().finalizeIR();
assertEquals("return Top;", code.print());
}
@@ -546,7 +549,7 @@ u32 v0=0;
return v1;
}
""");
- code.parse().opto();
+ code.parse().iter().finalizeIR();
assertEquals("return 0;", code.print());
}
diff --git a/chapter23/src/test/java/com/seaofnodes/simple/Chapter14FloatTest.java b/chapter23/src/test/java/com/seaofnodes/simple/Chapter14FloatTest.java
index 6377bc14..51397e77 100644
--- a/chapter23/src/test/java/com/seaofnodes/simple/Chapter14FloatTest.java
+++ b/chapter23/src/test/java/com/seaofnodes/simple/Chapter14FloatTest.java
@@ -20,7 +20,7 @@ public class Chapter14FloatTest {
{"f32 rounded=arg+16777216.0; return rounded;", "1.6777232E7", "1.6777199E7"}
};
for( String[] test : tests ) {
- var code = new CodeGen(test[0]).parse().opto().typeCheck();
+ var code = new CodeGen(test[0]).driver(CodeGen.Phase.TypeCheck);
assertEquals(test[0],test[1],Eval2.eval(code,17));
assertEquals(test[0],test[2],Eval2.eval(code,-17));
}
@@ -28,7 +28,7 @@ public class Chapter14FloatTest {
@Test public void testSubZeroFloat() {
- var code = new CodeGen("flt x = arg; return 0-x;").parse().opto().typeCheck();
+ var code = new CodeGen("flt x = arg; return 0-x;").driver(CodeGen.Phase.TypeCheck);
// Compare strings so +0.0 and -0.0 remain distinct.
assertEquals("0.0", Eval2.eval(code,0));
assertEquals("-1.0", Eval2.eval(code,1));
@@ -42,7 +42,7 @@ public class Chapter14FloatTest {
{"return 2.5; return 7;", "2.5"}
} ) {
String src = test[0];
- var code = new CodeGen(src).parse().opto().typeCheck();
+ var code = new CodeGen(src).driver(CodeGen.Phase.TypeCheck);
assertEquals(src,test[1],Eval2.eval(code,0));
}
}
@@ -55,7 +55,7 @@ public class Chapter14FloatTest {
"""
return 3.14;
""");
- code.parse().opto();
+ code.parse().iter().finalizeIR();
assertEquals("return 3.14;", code.print());
assertEquals("3.14", Eval2.eval(code, 0));
}
@@ -66,7 +66,7 @@ return 3.14;
"""
return 3.14;
""");
- code.parse().opto();
+ code.parse().iter().finalizeIR();
assertEquals("return 3.14;", code.print());
assertEquals("3.14", Eval2.eval(code, 0));
}
@@ -83,7 +83,7 @@ while( 1 ) {
}
return guess;
""");
- code.parse().opto();
+ code.parse().iter().finalizeIR();
assertEquals("return Phi(Loop,(flt)arg,(((ToFloat/Phi_guess)+Phi_guess)*0.5f));", code.print());
assertEquals("3.0", Eval2.eval(code, 9));
assertEquals("1.414213562373095", Eval2.eval(code, 2));
@@ -96,7 +96,7 @@ return guess;
flt x = arg;
return x+1==x;
""");
- code.parse().opto();
+ code.parse().iter().finalizeIR();
assertEquals("return ((flt)arg==(ToFloat+1.0f));", code.print());
assertEquals("0", Eval2.eval(code, 1));
}
diff --git a/chapter23/src/test/java/com/seaofnodes/simple/Chapter14Test.java b/chapter23/src/test/java/com/seaofnodes/simple/Chapter14Test.java
index c342eeed..95a5ee81 100644
--- a/chapter23/src/test/java/com/seaofnodes/simple/Chapter14Test.java
+++ b/chapter23/src/test/java/com/seaofnodes/simple/Chapter14Test.java
@@ -16,7 +16,7 @@ public class Chapter14Test {
"""
return 3.14;
""");
- code.parse().opto();
+ code.parse().iter().finalizeIR();
assertEquals("return 3.14;", code.print());
assertEquals("3.14", Eval2.eval(code, 0));
}
@@ -32,7 +32,7 @@ if( b < 0 ) c = -1;
if( b > 2 ) c = 1;
return c;
""");
- code.parse().opto();
+ code.parse().iter().finalizeIR();
assertEquals("return 99;", code.print());
assertEquals("99", Eval2.eval(code, 0));
}
@@ -45,7 +45,7 @@ u8 b = 123;
b = b + 456;// Truncate
return b;
""");
- code.parse().opto();
+ code.parse().iter().finalizeIR();
assertEquals("return 67;", code.print());
assertEquals("67", Eval2.eval(code, 0));
}
@@ -59,7 +59,7 @@ u8 b = 123;
while( b ) b = b + 456;// Truncate
return b;
""");
- code.parse().opto();
+ code.parse().iter().finalizeIR();
assertEquals("return 0;", code.print());
}
@@ -72,7 +72,7 @@ b = b + 456;// Truncate
u1 c = b; // No more truncate needed
return c;
""");
- code.parse().opto();
+ code.parse().iter().finalizeIR();
assertEquals("return 1;", code.print());
assertEquals("1", Eval2.eval(code, 0));
}
@@ -85,7 +85,7 @@ int b = 123;
b = b+456 & 31; // Precedence
return b;
""");
- code.parse().opto();
+ code.parse().iter().finalizeIR();
assertEquals("return 3;", code.print());
assertEquals("3", Eval2.eval(code, 0));
}
@@ -99,7 +99,7 @@ struct Foo { u1 b; };
f.b = 123;
return f.b;
""");
- code.parse().opto();
+ code.parse().iter().finalizeIR();
assertEquals("return 1;", code.print());
assertEquals("1", Eval2.eval(code, 0));
}
@@ -111,7 +111,7 @@ return f.b;
i8 b = 255; // Chopped
return b; // Sign extend
""");
- code.parse().opto();
+ code.parse().iter().finalizeIR();
assertEquals("return -1;", code.print());
assertEquals("-1", Eval2.eval(code, 0));
}
@@ -124,7 +124,7 @@ i8 b = arg;
b = b + 1;// Truncate
return b;
""");
- code.parse().opto();
+ code.parse().iter().finalizeIR();
assertEquals("return (((((arg<<56)>>56)+1)<<56)>>56);", code.print());
assertEquals("1", Eval2.eval(code, 0));
assertEquals("-128", Eval2.eval(code, 127));
@@ -138,7 +138,7 @@ u16 mask = (1<<16)-1; // AND mask
int c = 123456789 & mask;
return c; //
""");
- code.parse().opto();
+ code.parse().iter().finalizeIR();
assertEquals("return 52501;", code.print());
assertEquals("52501", Eval2.eval(code, 0));
}
@@ -149,7 +149,7 @@ return c; //
"""
return (arg | 123 ^ 456) >>> 1;
""");
- code.parse().opto();
+ code.parse().iter().finalizeIR();
assertEquals("return (((arg|123)^456)>>>1);", code.print());
assertEquals("217", Eval2.eval(code, 0));
}
@@ -162,7 +162,7 @@ flt f = arg;
arg = f & 1;
return arg;
""");
- try { code.parse().opto().typeCheck(); fail(); }
+ try { code.driver(CodeGen.Phase.TypeCheck); fail(); }
catch( Exception e ) { assertEquals("Cannot '&' flt",e.getMessage()); }
}
@@ -175,7 +175,7 @@ while(arg) v1=-v0;
while(v1) break;
return v1;
""");
- code.parse().opto();
+ code.parse().iter().finalizeIR();
assertEquals("return Phi(Loop,(((1<<arg)&1)&Shl),0);", code.print());
assertEquals("1", Eval2.eval(code, 0));
}
@@ -194,7 +194,7 @@ if(0&0>>>0) {
}
return v0;
""");
- code.parse().opto();
+ code.parse().iter().finalizeIR();
assertEquals("return 0;", code.print());
assertEquals("0", Eval2.eval(code, 0));
}
@@ -220,7 +220,7 @@ f32 ff32 = 3.141592653589793; if( ff32 != 3.1415927410125732) return 5;
return 0;
""");
- code.parse().opto();
+ code.parse().iter().finalizeIR();
assertEquals("return 0;", code.print());
assertEquals("0", Eval2.eval(code, 0));
}
diff --git a/chapter23/src/test/java/com/seaofnodes/simple/Chapter15Test.java b/chapter23/src/test/java/com/seaofnodes/simple/Chapter15Test.java
index d0a42ccf..5331809f 100644
--- a/chapter23/src/test/java/com/seaofnodes/simple/Chapter15Test.java
+++ b/chapter23/src/test/java/com/seaofnodes/simple/Chapter15Test.java
@@ -17,7 +17,7 @@ public class Chapter15Test {
"""
return 3.14;
""");
- code.parse().opto();
+ code.parse().iter().finalizeIR();
assertEquals("return 3.14;", code.print());
assertEquals("3.14", Eval2.eval(code, 0));
}
@@ -31,7 +31,7 @@ struct C { !C? !l; };
c.l = c;
return c;
""");
- code.parse().opto();
+ code.parse().iter().finalizeIR();
assertEquals("return C;", code.print());
assertEquals("C{l=$cyclic}", Eval2.eval(code, 0));
}
@@ -50,7 +50,7 @@ while (i < old#) {
output[i] = 1;
return output;
""");
- code.parse().opto();
+ code.parse().iter().finalizeIR();
assertEquals("return []u8;", code.print());
assertEquals("\u0001", Eval2.eval(code, 0));
}
@@ -62,7 +62,7 @@ return output;
int[] is = new int[2];
return is[1];
""");
- code.parse().opto();
+ code.parse().iter().finalizeIR();
assertEquals("return 0;", code.print());
assertEquals("0", Eval2.eval(code, 0));
}
@@ -75,7 +75,7 @@ int[] is = new int[2];
int[] is2 = new int[2];
return is[1];
""");
- code.parse().opto();
+ code.parse().iter().finalizeIR();
assertEquals("return 0;", code.print());
assertEquals("0", Eval2.eval(code, 0));
}
@@ -89,7 +89,7 @@ a[0] = 1;
a[1] = 2;
return a[0];
""");
- code.parse().opto();
+ code.parse().iter().finalizeIR();
assertEquals("return 1;", code.print());
assertEquals("1", Eval2.eval(code, 0));
}
@@ -102,7 +102,7 @@ struct A { int i; };
!A?[] !a = new !A?[2];
return a;
""");
- code.parse().opto();
+ code.parse().iter().finalizeIR();
assertEquals("return []*A?;", code.print());
assertEquals("*A {i64 !i; }?[ null,null]", Eval2.eval(code, 0));
}
@@ -131,7 +131,7 @@ else {
}
return rez;
""");
- code.parse().opto();
+ code.parse().iter().finalizeIR();
assertEquals("return Phi(Region,1.2,.y,2.3);", code.print());
assertEquals("3.14", Eval2.eval(code, 0));
assertEquals("1.2", Eval2.eval(code, 1));
@@ -156,7 +156,7 @@ if( iss[arg] )
if( iss[arg][2] )
rez = iss[arg][2].y;
return rez;""");
- code.parse().opto().typeCheck();
+ code.driver(CodeGen.Phase.TypeCheck);
assertEquals("return Phi(Region,1.2,1.2,.y);", code.print());
assertEquals("3.14", Eval2.eval(code, 0));
try { Eval2.eval(code, 10); fail(); } // Fails AIOOBE in Eval2, no range checks
@@ -174,7 +174,7 @@ root._kids = new !Tree?[2]; // NO BANG SO ARRAY IS OF IMMUTABLE TREES????
root._kids[0] = new Tree;
return root;
""");
- code.parse().opto();
+ code.parse().iter().finalizeIR();
assertEquals("return Tree;", code.print());
assertEquals("Tree{_kids=*Tree {*[]*Tree?? !_kids; }?[ Tree{_kids=null},null]}", Eval2.eval(code, 0));
}
@@ -186,7 +186,7 @@ return root;
struct S { int a; int[] !b; };
return 0;
""");
- code.parse().opto();
+ code.parse().iter().finalizeIR();
assertEquals("return 0;", code.print());
}
@@ -209,7 +209,7 @@ while( i < ary# - 1 ) {
}
return ary[1] * 1000 + ary[3]; // 1 * 1000 + 6
""");
- code.parse().opto();
+ code.parse().iter().finalizeIR();
assertEquals("return (.[]+(.[]*1000));", code.print());
assertEquals("1006", Eval2.eval(code, 4));
}
@@ -218,7 +218,7 @@ return ary[1] * 1000 + ary[3]; // 1 * 1000 + 6
public void sieveOEratosthenes() throws IOException {
String src = Files.readString(Path.of("src/test/java/com/seaofnodes/simple/progs/sieve.smp"));
CodeGen code = new CodeGen(src+"return sieve(arg);");
- code.parse().opto();
+ code.parse().iter().finalizeIR();
assertEquals("return []u32;", code.print());
assertEquals("u32[ 2,3,5,7,11,13,17,19]",Eval2.eval(code, 20));
}
@@ -235,7 +235,7 @@ s2.f = 2.0;
if (arg) s1 = new S;
return s1.i + s1.f;
""");
- code.parse().opto();
+ code.parse().iter().finalizeIR();
assertEquals("return ((flt).i+.f);", code.print());
assertEquals("0.0", Eval2.eval(code, 0));
}
@@ -247,7 +247,7 @@ return s1.i + s1.f;
"""
return new flt;
""");
- try { code.parse().opto(); fail(); }
+ try { code.parse().iter().finalizeIR(); fail(); }
catch( Exception e ) { assertEquals("Cannot allocate a flt",e.getMessage()); }
}
@@ -258,7 +258,7 @@ return new flt;
flt is = new int[2];
return is;
""");
- try { code.parse().opto().typeCheck(); fail(); }
+ try { code.driver(CodeGen.Phase.TypeCheck); fail(); }
catch( Exception e ) { assertEquals("Type *[]i64 is not of declared type flt",e.getMessage()); }
}
@@ -269,7 +269,7 @@ return is;
int[] is = new int[3.14];
return is[1];
""");
- try { code.parse().opto(); fail(); }
+ try { code.parse().iter().finalizeIR(); fail(); }
catch( Exception e ) { assertEquals("Cannot allocate an array with length 3.14",e.getMessage()); }
}
@@ -279,7 +279,7 @@ return is[1];
int[] is = new int[arg];
return is[1];
""");
- code.parse().opto();
+ code.parse().iter().finalizeIR();
assertEquals("return 0;", code.print());
assertEquals("0", Eval2.eval(code, 4));
try { Eval2.eval(code,-1); fail(); }
@@ -312,7 +312,7 @@ while(v5+(0&0)) {
}
return v1;
""");
- code.parse().opto();
+ code.parse().iter().finalizeIR();
assertEquals("return 0;", code.print());
assertEquals("0", Eval2.eval(code, 0));
}
@@ -328,7 +328,7 @@ int v8=0;
while(0<--1>>>---(v7*0==v8)) {}
return 0;
""");
- code.parse().opto();
+ code.parse().iter().finalizeIR();
assertEquals("return 0;", code.print());
}
@@ -353,7 +353,7 @@ else {
}
return 0;
""");
- code.parse().opto();
+ code.parse().iter().finalizeIR();
assertEquals("return 0;", code.print());
}
}
diff --git a/chapter23/src/test/java/com/seaofnodes/simple/Chapter16Test.java b/chapter23/src/test/java/com/seaofnodes/simple/Chapter16Test.java
index f73cbf57..67962acd 100644
--- a/chapter23/src/test/java/com/seaofnodes/simple/Chapter16Test.java
+++ b/chapter23/src/test/java/com/seaofnodes/simple/Chapter16Test.java
@@ -15,7 +15,7 @@ public class Chapter16Test {
"""
return 3.14;
""");
- code.parse().opto();
+ code.parse().iter().finalizeIR();
assertEquals("return 3.14;", code.print());
assertEquals("3.14", Eval2.eval(code, 0));
}
@@ -28,7 +28,7 @@ return 3.14;
int x, y;
return x+y;
""");
- code.parse().opto();
+ code.parse().iter().finalizeIR();
assertEquals("return 0;", code.print());
assertEquals("0", Eval2.eval(code, 0));
}
@@ -39,7 +39,7 @@ return x+y;
int x=2, y=x+1;
return x+y;
""");
- code.parse().opto();
+ code.parse().iter().finalizeIR();
assertEquals("return 5;", code.print());
assertEquals("5", Eval2.eval(code, 0));
}
@@ -52,7 +52,7 @@ struct X { int x=3; };
X z = new X;
return z.x;
""");
- code.parse().opto();
+ code.parse().iter().finalizeIR();
assertEquals("return 3;", code.print());
assertEquals("3", Eval2.eval(code, 0));
}
@@ -64,7 +64,7 @@ struct X { int x=3; };
X z = new X { x = 4; };
return z.x;
""");
- code.parse().opto();
+ code.parse().iter().finalizeIR();
assertEquals("return 4;", code.print());
assertEquals("4", Eval2.eval(code, 0));
}
@@ -85,7 +85,7 @@ LLI? next = head.next;
if( !next ) return 1;
return next.i;
""");
- code.parse().opto();
+ code.parse().iter().finalizeIR();
assertEquals("return Phi(Region,0,1,.i);", code.print());
assertEquals("0", Eval2.eval(code, 0));
assertEquals("1", Eval2.eval(code, 1));
@@ -116,7 +116,7 @@ LLI? next = head.next;
if( !next ) return 1;
return next.i;
""");
- code.parse().opto();
+ code.parse().iter().finalizeIR();
assertEquals("return Phi(Region,0,1,.i);", code.print());
assertEquals("0", Eval2.eval(code, 0));
assertEquals("1", Eval2.eval(code, 1));
@@ -141,7 +141,7 @@ struct Square {
};
return new Square;
""");
- code.parse().opto();
+ code.parse().iter().finalizeIR();
assertEquals("return Square;", code.print());
assertEquals("Square{side=3.0,diag=1.7320508075688772}", Eval2.eval(code, 3));
assertEquals("Square{side=4.0,diag=2.0}", Eval2.eval(code, 4));
@@ -165,7 +165,7 @@ return new Square;
""";
@Test public void testConstructorMemory() {
- var code = new CodeGen(CONSTRUCTOR_MEMORY).parse().opto();
+ var code = new CodeGen(CONSTRUCTOR_MEMORY).parse().iter().finalizeIR();
assertEquals("111249",Eval2.eval(code,0));
assertEquals("222352",Eval2.eval(code,1));
}
diff --git a/chapter23/src/test/java/com/seaofnodes/simple/Chapter17aTest.java b/chapter23/src/test/java/com/seaofnodes/simple/Chapter17aTest.java
index 8597b799..ba5bb985 100644
--- a/chapter23/src/test/java/com/seaofnodes/simple/Chapter17aTest.java
+++ b/chapter23/src/test/java/com/seaofnodes/simple/Chapter17aTest.java
@@ -15,7 +15,7 @@ int x=2, y=3;
if( arg ) { int x = y; x = x*x; y=x; } // Shadow final x
return y;
""");
- code.parse().opto();
+ code.parse().iter().finalizeIR();
assertEquals("return Phi(Region,9,3);", code.print());
assertEquals("3", Eval2.eval(code, 0));
assertEquals("9", Eval2.eval(code, 1));
@@ -28,7 +28,7 @@ struct X { int ~x; };
X z = new X { x=3; };
return z.x;
""");
- code.parse().opto();
+ code.parse().iter().finalizeIR();
assertEquals("return 3;", code.print());
assertEquals("3", Eval2.eval(code, 0));
}
@@ -40,7 +40,7 @@ struct Point { int ~x, ~y; };
Point p = new Point { x=3; y=4; };
return p;
""");
- code.parse().opto();
+ code.parse().iter().finalizeIR();
assertEquals("return (const)Point;", code.print());
assertEquals("Point{x=3,y=4}", Eval2.eval(code, 0));
}
@@ -53,7 +53,7 @@ struct Point { int x=3, y=4; };
p.x++;
return p;
""");
- try { code.parse().opto().typeCheck(); fail(); }
+ try { code.driver(CodeGen.Phase.TypeCheck); fail(); }
catch( Exception e ) { assertEquals("Cannot modify final field 'x'",e.getMessage()); }
}
@@ -65,7 +65,7 @@ struct Point { int x=3, y=4; };
p.x++;
return p;
""");
- try { code.parse().opto().typeCheck(); fail(); }
+ try { code.driver(CodeGen.Phase.TypeCheck); fail(); }
catch( Exception e ) { assertEquals("Cannot modify final field 'x'",e.getMessage()); }
}
@@ -73,7 +73,7 @@ return p;
public void testStructFinal3() {
for( String fields : new String[] { "var x; var y;", "int[] !x;", "int[] !x;" } ) {
String src = "struct Point { "+fields+" }; Point p = new Point; p.x++; return p;";
- try { new CodeGen(src).parse().opto(); fail(fields); }
+ try { new CodeGen(src).parse().iter().finalizeIR(); fail(fields); }
catch( Exception e ) { assertEquals("'Point' is not fully initialized, field 'x' needs to be set in a constructor",e.getMessage()); }
}
}
@@ -86,7 +86,7 @@ Point p = new Point;
p.x++;
return p;
""");
- try { code.parse().opto().typeCheck(); fail(); }
+ try { code.driver(CodeGen.Phase.TypeCheck); fail(); }
catch( Exception e ) { assertEquals("Cannot modify final field 'x'",e.getMessage()); }
}
@@ -98,7 +98,7 @@ struct Point { var x=3; var y=4; };
p.x++;
return p;
""");
- code.parse().opto();
+ code.parse().iter().finalizeIR();
assertEquals("return Point;", code.print());
assertEquals("Point{x=4,y=4}", Eval2.eval(code, 0));
}
diff --git a/chapter23/src/test/java/com/seaofnodes/simple/Chapter17bTest.java b/chapter23/src/test/java/com/seaofnodes/simple/Chapter17bTest.java
index 24dc0229..28a10b05 100644
--- a/chapter23/src/test/java/com/seaofnodes/simple/Chapter17bTest.java
+++ b/chapter23/src/test/java/com/seaofnodes/simple/Chapter17bTest.java
@@ -15,7 +15,7 @@ public class Chapter17bTest {
"""
return 1;
""");
- code.parse().opto().typeCheck();
+ code.driver(CodeGen.Phase.TypeCheck);
assertEquals("return 1;", code.print());
assertEquals("1", Eval2.eval(code, 0));
}
@@ -27,7 +27,7 @@ return 1;
CodeGen code = new CodeGen("""
return arg++;
""");
- code.parse().opto();
+ code.parse().iter().finalizeIR();
assertEquals("return arg;", code.print());
assertEquals("0", Eval2.eval(code, 0));
}
@@ -37,7 +37,7 @@ return arg++;
CodeGen code = new CodeGen("""
return arg+++arg++;
""");
- code.parse().opto();
+ code.parse().iter().finalizeIR();
assertEquals("return ((arg<<1)+1);", code.print());
assertEquals("1", Eval2.eval(code, 0));
}
@@ -48,7 +48,7 @@ return arg+++arg++;
// -(arg--)-(arg--)
return -arg---arg--;
""");
- code.parse().opto();
+ code.parse().iter().finalizeIR();
assertEquals("return (-((arg<<1)+-1));", code.print());
assertEquals("1", Eval2.eval(code, 0));
}
@@ -61,7 +61,7 @@ xs[0]++;
xs[1]++;
return xs[0];
""");
- code.parse().opto();
+ code.parse().iter().finalizeIR();
assertEquals("return 1;", code.print());
assertEquals("1", Eval2.eval(code, 2));
}
@@ -73,7 +73,7 @@ u8[] !xs = new u8[1];
xs[0]--;
return xs[0];
""");
- code.parse().opto();
+ code.parse().iter().finalizeIR();
assertEquals("return 255;", code.print());
assertEquals("255", Eval2.eval(code, 2));
}
@@ -86,7 +86,7 @@ struct S { u16 x; };
s.x--;
return s.x;
""");
- code.parse().opto();
+ code.parse().iter().finalizeIR();
assertEquals("return 65535;", code.print());
assertEquals("65535", Eval2.eval(code, 2));
}
@@ -94,7 +94,7 @@ return s.x;
@Test
public void testInc6() {
CodeGen code = new CodeGen("return --arg;");
- code.parse().opto();
+ code.parse().iter().finalizeIR();
assertEquals("return (arg+-1);", code.print());
assertEquals("-1", Eval2.eval(code, 0));
}
@@ -102,7 +102,7 @@ return s.x;
@Test
public void testInc7() {
CodeGen code = new CodeGen("u8 x=0; return --x;");
- code.parse().opto();
+ code.parse().iter().finalizeIR();
assertEquals("return 255;", code.print());
assertEquals("255", Eval2.eval(code, 0));
}
@@ -110,7 +110,7 @@ return s.x;
@Test
public void testInc8() {
CodeGen code = new CodeGen("int x; x+=2; return x+=3;");
- code.parse().opto();
+ code.parse().iter().finalizeIR();
assertEquals("return 5;", code.print());
assertEquals("5", Eval2.eval(code, 0));
}
@@ -118,14 +118,14 @@ return s.x;
@Test
public void testInc9() {
CodeGen code = new CodeGen("flt x = 1.5; x++; return x;");
- code.parse().opto();
+ code.parse().iter().finalizeIR();
assertEquals("return 2.5f;", code.print());
assertEquals("2.5", Eval2.eval(code, 0));
}
@Test public void testInt10() {
CodeGen code = new CodeGen("flt x = 1.5; x++; int i = x; return i;");
- code.parse().opto().typeCheck();
+ code.driver(CodeGen.Phase.TypeCheck);
assertEquals("2",Eval2.eval(code,0));
}
@@ -133,73 +133,73 @@ return s.x;
// ---------------------------------------------------------------
@Test public void testVar0() {
CodeGen code = new CodeGen("var d; return d;");
- try { code.parse().opto(); fail(); }
+ try { code.parse().iter().finalizeIR(); fail(); }
catch( Exception e ) { assertEquals("Syntax error, expected =expression: ;",e.getMessage()); }
}
@Test public void testVar1() {
CodeGen code = new CodeGen("val d; return d;");
- try { code.parse().opto(); fail(); }
+ try { code.parse().iter().finalizeIR(); fail(); }
catch( Exception e ) { assertEquals("Syntax error, expected =expression: ;",e.getMessage()); }
}
@Test public void testVar2() {
CodeGen code = new CodeGen("int x; x=3; x++; return x; // Ok, no initializer so x is mutable ");
- code.parse().opto();
+ code.parse().iter().finalizeIR();
assertEquals("return 4;", code.print());
assertEquals("4", Eval2.eval(code, 0));
}
@Test public void testVar3() {
CodeGen code = new CodeGen("int x=3; x++; return x; // Ok, primitive so x is mutable despite initializer ");
- code.parse().opto();
+ code.parse().iter().finalizeIR();
assertEquals("return 4;", code.print());
assertEquals("4", Eval2.eval(code, 0));
}
@Test public void testVar4() {
CodeGen code = new CodeGen("struct S{int x;}; !S? !s; s=new S; s.x++; return s.x; // Ok, no initializer so x is mutable ");
- code.parse().opto();
+ code.parse().iter().finalizeIR();
assertEquals("return 1;", code.print());
assertEquals("1", Eval2.eval(code, 0));
}
@Test public void testVar5() {
CodeGen code = new CodeGen("struct S{int x;}; !S? !s; s=new S{x=3;}; s.x++; return s.x; // Ok, no initializer so x is mutable ");
- code.parse().opto();
+ code.parse().iter().finalizeIR();
assertEquals("return 4;", code.print());
assertEquals("4", Eval2.eval(code, 0));
}
@Test public void testVar6() {
CodeGen code = new CodeGen("struct S{int x;}; ~S s = new S; s.x++; return s.x; // Error initializer so x is immutable ");
- try { code.parse().opto().typeCheck(); fail(); }
+ try { code.driver(CodeGen.Phase.TypeCheck); fail(); }
catch( Exception e ) { assertEquals("Cannot modify final field 'x'",e.getMessage()); }
}
@Test public void testVar7() {
CodeGen code = new CodeGen("struct S{int x;}; ~S s = new S{x=3;}; s.x++; return s.x; // Error initializer so x is immutable ");
- try { code.parse().opto().typeCheck(); fail(); }
+ try { code.driver(CodeGen.Phase.TypeCheck); fail(); }
catch( Exception e ) { assertEquals("Cannot modify final field 'x'",e.getMessage()); }
}
@Test public void testVar8() {
CodeGen code = new CodeGen("struct S{int x;}; !S !s=new S; s.x++; return s.x; // Ok, has '!' so s.x is mutable ");
- code.parse().opto();
+ code.parse().iter().finalizeIR();
assertEquals("return 1;", code.print());
assertEquals("1", Eval2.eval(code, 0));
}
@Test public void testVar9() {
CodeGen code = new CodeGen("struct S{int x;}; var s=new S; s.x++; return s.x; // Ok, has var so s.x is mutable ");
- code.parse().opto();
+ code.parse().iter().finalizeIR();
assertEquals("return 1;", code.print());
assertEquals("1", Eval2.eval(code, 0));
}
@Test public void testVar10() {
CodeGen code = new CodeGen("struct S{int x;}; ~S s=new S; s.x++; return s.x; // Error, has val so x is immutable ");
- try { code.parse().opto().typeCheck(); fail(); }
+ try { code.driver(CodeGen.Phase.TypeCheck); fail(); }
catch( Exception e ) { assertEquals("Cannot modify final field 'x'",e.getMessage()); }
}
@@ -218,7 +218,7 @@ foo.bar.x++; // Ok foo and foo.bar and foo.bar.x are all mutable
xfoo.bar.x++; // Error, cannot mutate through xfoo
return xfoo.bar.x;
""");
- try { code.parse().opto().typeCheck(); fail(); }
+ try { code.driver(CodeGen.Phase.TypeCheck); fail(); }
catch( Exception e ) { assertEquals("Cannot modify final field 'x'",e.getMessage()); }
}
@@ -239,7 +239,7 @@ foo.bar.x++; // Bumps to 5
int x5 = xfoo.bar.x; // Ok to read through xfoo, gets 5
return x4*10+x5;
""");
- code.parse().opto();
+ code.parse().iter().finalizeIR();
assertEquals("return 45;", code.print());
assertEquals("45", Eval2.eval(code, 0));
}
@@ -249,7 +249,7 @@ return x4*10+x5;
CodeGen code = new CodeGen("""
int i,i++;
""");
- try { code.parse().opto().typeCheck(); fail(); }
+ try { code.driver(CodeGen.Phase.TypeCheck); fail(); }
catch( Exception e ) { assertEquals("Redefining name 'i'",e.getMessage()); }
}
@@ -264,7 +264,7 @@ A x = new A {
b = new B;
};
""");
- try { code.parse().opto(); fail(); }
+ try { code.parse().iter().finalizeIR(); fail(); }
catch( Exception e ) { assertEquals("Cannot read uninitialized field 'b'",e.getMessage()); }
}
@@ -291,7 +291,7 @@ val x = 1;
return x;
"""
);
- try { code.parse().opto().typeCheck(); fail(); }
+ try { code.driver(CodeGen.Phase.TypeCheck); fail(); }
catch( Exception e ) { assertEquals("Cannot reassign final 'x'",e.getMessage()); }
}
@@ -320,7 +320,7 @@ return me;
CodeGen code = new CodeGen("""
return arg ? 1 : 2;
""");
- code.parse().opto();
+ code.parse().iter().finalizeIR();
assertEquals("return Phi(Region,1,2);", code.print());
assertEquals("2", Eval2.eval(code, 0));
assertEquals("1", Eval2.eval(code, 1));
@@ -331,7 +331,7 @@ return arg ? 1 : 2;
CodeGen code = new CodeGen("""
return arg ? 0 : arg;
""");
- code.parse().opto();
+ code.parse().iter().finalizeIR();
assertEquals("return 0;", code.print());
assertEquals("0", Eval2.eval(code, 0));
}
@@ -343,7 +343,7 @@ struct Bar { int x; };
var b = arg ? new Bar : null;
return b ? b.x++ + b.x++ : -1;
""");
- code.parse().opto();
+ code.parse().iter().finalizeIR();
assertEquals("return Phi(Region,((.x<<1)+1),-1);", code.print());
assertEquals("-1", Eval2.eval(code, 0));
assertEquals("1", Eval2.eval(code, 1));
@@ -356,7 +356,7 @@ struct Bar { int x; };
var b = arg ? new Bar;
return b ? b.x++ + b.x++ : -1;
""");
- code.parse().opto();
+ code.parse().iter().finalizeIR();
assertEquals("return Phi(Region,((.x<<1)+1),-1);", code.print());
assertEquals("-1", Eval2.eval(code, 0));
assertEquals("1", Eval2.eval(code, 1));
@@ -370,7 +370,7 @@ struct Bar { !Bar? !next; int x; };
var b = arg ? new Bar { next = (arg==2) ? new Bar{x=2;}; x=1; };
return b ? b.next ? b.next.x : b.x; // parses "b ? (b.next ? b.next.x : b.x) : 0"
""");
- code.parse().opto();
+ code.parse().iter().finalizeIR();
assertEquals("return Phi(Region,.x,0,.x);", code.print());
assertEquals("0", Eval2.eval(code, 0));
assertEquals("1", Eval2.eval(code, 1));
@@ -383,7 +383,7 @@ return b ? b.next ? b.next.x : b.x; // parses "b ? (b.next ? b.next.x : b.x) : 0
flt f=arg?1:1.2;
return f; // missing widening
""");
- code.parse().opto();
+ code.parse().iter().finalizeIR();
assertEquals("return Phi(Region,1.0f,1.2);", code.print());
assertEquals("1.2", Eval2.eval(code, 0));
}
@@ -395,7 +395,7 @@ return f; // missing widening
struct S{};
return arg ? 7 : new S;
""");
- try { code.parse().opto().typeCheck(); fail(); }
+ try { code.driver(CodeGen.Phase.TypeCheck); fail(); }
catch( Exception e ) { assertEquals("No common type amongst int and reference",e.getMessage()); }
}
@@ -408,7 +408,7 @@ for( int i=0; i<arg; i++ )
sum += i;
return sum;
""");
- code.parse().opto();
+ code.parse().iter().finalizeIR();
assertEquals("return Phi(Loop,0,(Phi_sum+Phi(Loop,0,(Phi_i+1))));", code.print());
assertEquals("3", Eval2.eval(code, 3));
assertEquals("45", Eval2.eval(code, 10));
@@ -421,7 +421,7 @@ for( ; i<arg; i++ )
sum += i;
return sum;
""");
- code.parse().opto();
+ code.parse().iter().finalizeIR();
assertEquals("return Phi(Loop,0,(Phi_sum+Phi(Loop,0,(Phi_i+1))));", code.print());
assertEquals("3", Eval2.eval(code, 3));
assertEquals("45", Eval2.eval(code, 10));
@@ -436,7 +436,7 @@ for( int i=0; ; i++ ) {
}
return sum;
""");
- code.parse().opto();
+ code.parse().iter().finalizeIR();
assertEquals("return Phi(Loop,0,(Phi_sum+Phi(Loop,0,(Phi_i+1))));", code.print());
assertEquals("3", Eval2.eval(code, 3));
assertEquals("45", Eval2.eval(code, 10));
@@ -449,7 +449,7 @@ for( int i=0; i<arg; )
sum += i++;
return sum;
""");
- code.parse().opto();
+ code.parse().iter().finalizeIR();
assertEquals("return Phi(Loop,0,(Phi_sum+Phi(Loop,0,(Phi_i+1))));", code.print());
assertEquals("3", Eval2.eval(code, 3));
assertEquals("45", Eval2.eval(code, 10));
@@ -462,7 +462,7 @@ for( int i=0; i<arg; i++ )
sum += i;
return i;
""");
- try { code.parse().opto(); fail(); }
+ try { code.parse().iter().finalizeIR(); fail(); }
catch( Exception e ) { assertEquals("Undefined name 'i'",e.getMessage()); }
}
@Test
@@ -470,7 +470,7 @@ return i;
CodeGen code = new CodeGen("""
for(;;arg++;) {}
""");
- try { code.parse().opto(); fail(); }
+ try { code.parse().iter().finalizeIR(); fail(); }
catch( Exception e ) { assertEquals("Syntax error, expected Unexpected code after expression: ;",e.getMessage()); }
}
@@ -486,7 +486,7 @@ struct A{
};
return new A;
""");
- code.parse().opto();
+ code.parse().iter().finalizeIR();
assertEquals("return A;", code.print());
assertEquals("A{f1=null,f2=null}", Eval2.eval(code,0));
}
@@ -500,7 +500,7 @@ struct A {
};
return new A{array_of_b = new !B?[0]; }.array_of_b;
""");
- code.parse().opto();
+ code.parse().iter().finalizeIR();
assertEquals("return []*B?;", code.print());
assertEquals("*B {... }?[]", Eval2.eval(code,0));
}
@@ -519,7 +519,7 @@ for( ; ptr; ptr = ptr.next )
sum += ptr.i;
return sum;
""");
- code.parse().opto();
+ code.parse().iter().finalizeIR();
assertEquals("return Phi(Loop,0,(Phi_sum+.i));", code.print());
assertEquals("45", Eval2.eval(code, 10));
}
@@ -550,7 +550,7 @@ for( int j=0; j<nprimes; j++ )
rez[j] = primes[j];
return rez;
""");
- code.parse().opto().typeCheck().GCM();
+ code.driver(CodeGen.Phase.Schedule);
assertEquals("return []i64;", code.print());
assertEquals("i64[ 2,3,5,7,11,13,17,19]",Eval2.eval(code, 20));
}
diff --git a/chapter23/src/test/java/com/seaofnodes/simple/Chapter18Test.java b/chapter23/src/test/java/com/seaofnodes/simple/Chapter18Test.java
index 902344ed..11bdfb9a 100644
--- a/chapter23/src/test/java/com/seaofnodes/simple/Chapter18Test.java
+++ b/chapter23/src/test/java/com/seaofnodes/simple/Chapter18Test.java
@@ -91,7 +91,7 @@ public class Chapter18Test {
"No common type amongst int and reference"}
} ) {
try {
- new CodeGen(test[0]).parse().opto().typeCheck();
+ new CodeGen(test[0]).driver(CodeGen.Phase.TypeCheck);
fail("Expected incompatible return types: " + test[0]);
} catch( Parser.ParseException e ) {
assertEquals(test[1],e.getMessage());
@@ -140,7 +140,7 @@ while(arg--) {
}
return a;
""");
- code.parse().opto().typeCheck();
+ code.driver(CodeGen.Phase.TypeCheck);
assertEquals("return Phi(Loop,1,Phi(Loop,2,Phi_a));", code._stop.toString());
assertEquals("1", Eval2.eval(code, 0));
assertEquals("2", Eval2.eval(code, 1));
@@ -157,7 +157,7 @@ return a;
{int -> int}? x2 = null; // null function ptr
return x2;
""");
- code.parse().opto();
+ code.parse().iter().finalizeIR();
assertEquals("return null;", code._stop.toString());
assertEquals("null", Eval2.eval(code, 0 ) );
}
@@ -170,7 +170,7 @@ return x2;
x*x;
};
""");
- code.parse().opto();
+ code.parse().iter().finalizeIR();
assertEquals("return (Parm_x(sq,i64)*x);", code._stop.toString());
//assertEquals("{ int -> int #1}", Eval2.eval(code, 3));
}
@@ -197,7 +197,7 @@ return sq(arg)+sq(3);
int cnt=1;
return { -> cnt; };
""");
- try { code.parse().opto(); fail(); }
+ try { code.parse().iter().finalizeIR(); fail(); }
catch( Exception e ) { assertEquals("Variable 'cnt' is out of function scope and must be a final constant",e.getMessage()); }
}
@@ -209,7 +209,7 @@ return { -> cnt; };
val cnt=2;
return { -> cnt; }();
""");
- code.parse().opto();
+ code.parse().iter().finalizeIR();
assertEquals("return 2;", code._stop.toString());
assertEquals("2", Eval2.eval(code, 0));
}
@@ -222,7 +222,7 @@ return { -> cnt; }();
var fcn = arg ? { int x -> x*x; } : { int x -> x+x; };
return fcn(3);
""");
- code.parse().opto();
+ code.parse().iter().finalizeIR();
assertEquals("Stop[ return #2; return (Parm_x($fun21,i64,3)*x); return (Parm_x($fun22,i64,3)<<1); ]", code._stop.toString());
assertEquals("6", Eval2.eval(code, 0));
assertEquals("9", Eval2.eval(code, 1));
@@ -232,7 +232,7 @@ return fcn(3);
@Test
public void testFcn5() {
CodeGen code = new CodeGen("val fact = { int x -> x <= 1 ? 1 : x*fact(x-1); }; return fact(arg);");
- code.parse().opto().typeCheck();
+ code.driver(CodeGen.Phase.TypeCheck);
assertEquals("Stop[ return #2; return Phi(Region,1,(Parm_x(fact,i64,arg,(x-1))*#2)); ]", code._stop.toString());
assertEquals( "1", Eval2.eval(code, 0));
assertEquals( "1", Eval2.eval(code, 1));
@@ -249,7 +249,7 @@ struct S { int i; };
val newS = { int x -> return new S { i=x; }; };
return newS(1).i;
""");
- code.parse().opto().typeCheck().GCM();
+ code.driver(CodeGen.Phase.Schedule);
assertEquals("return 1;", code._stop.toString());
assertEquals("1", Eval2.eval(code, 0));
}
@@ -264,7 +264,7 @@ val f = {->1;};
val g = {->2;};
return 2;
""");
- code.parse().opto().typeCheck().GCM();
+ code.driver(CodeGen.Phase.Schedule);
assertEquals("Stop[ return 1; return 1; return 2; ]", code._stop.toString());
assertEquals("1", Eval2.eval(code, 0));
}
@@ -342,7 +342,7 @@ for(;;) {
}
return 1;
""");
- try { code.parse().opto(); fail(); }
+ try { code.parse().iter().finalizeIR(); fail(); }
catch( Exception e ) { assertEquals("No active loop for a break or continue",e.getMessage()); }
}
@@ -358,7 +358,7 @@ for(;;) {
}
return 0;
""");
- try { code.parse().opto().typeCheck(); fail(); }
+ try { code.driver(CodeGen.Phase.TypeCheck); fail(); }
catch( Exception e ) { assertEquals("Might be null calling { i64 -> i64 #21}?",e.getMessage()); }
}
@@ -370,7 +370,7 @@ return 0;
val f = { int i, int j -> return i+j; };
return f();
""");
- try { code.parse().opto().typeCheck(); fail(); }
+ try { code.driver(CodeGen.Phase.TypeCheck); fail(); }
catch( Exception e ) { assertEquals("Expecting 2 arguments, but found 0",e.getMessage()); }
}
@@ -388,7 +388,7 @@ for(;;) {
if (s) return s.x;
}
""");
- try { code.parse().opto().typeCheck(); fail(); }
+ try { code.driver(CodeGen.Phase.TypeCheck); fail(); }
catch( Exception e ) { assertEquals("Accessing unknown field 'x' from '*S'",e.getMessage()); }
}
@@ -401,7 +401,7 @@ val g = { ->
};
return 0;
""");
- try { code.parse().opto().typeCheck(); fail(); }
+ try { code.driver(CodeGen.Phase.TypeCheck); fail(); }
catch( Exception e ) { assertEquals("No defined return type",e.getMessage()); }
}
@@ -415,7 +415,7 @@ val is_even = { int x -> x ? is_odd (x-1) : true ; };
val is_odd = { int x -> x ? is_even(x-1) : false; };
return is_even(arg);
""");
- code.parse().opto();
+ code.parse().iter().finalizeIR();
assertEquals("Stop[ return is_even( arg); return Phi(Region,Phi(Region,is_even( ((Parm_x(is_even,int,arg,Sub)-1)-1)),0),1); ]", code._stop.toString());
assertEquals("1", Eval2.eval(code, 0));
assertEquals("0", Eval2.eval(code, 1));
@@ -437,7 +437,7 @@ for(;;) {
if (s) return s.f;
}
""");
- code.parse().opto().typeCheck().GCM();
+ code.driver(CodeGen.Phase.Schedule);
assertEquals("return 0;", code._stop.toString());
assertEquals("0", Eval2.eval(code, 0));
}
@@ -489,7 +489,7 @@ return p.coffee_count;
""";
@Test public void testCallMemory() {
- var code = new CodeGen(CALL_MEMORY).parse().opto();
+ var code = new CodeGen(CALL_MEMORY).parse().iter().finalizeIR();
int[] calls={0};
code._stop.walk(n -> { if(n instanceof CallNode) calls[0]++; return null; });
assertEquals(2,calls[0]); // Keep real calls so this checks scheduling across them.
@@ -518,7 +518,7 @@ return p.coffee_count;
""";
@Test public void testRecursiveMemory() {
- var code = new CodeGen(RECURSIVE_MEMORY).parse().opto();
+ var code = new CodeGen(RECURSIVE_MEMORY).parse().iter().finalizeIR();
for(int n=0; n<7; n++)
assertEquals(Long.toString((10L*(n+1)+n*(n+1)/2)*100+10+n),Eval2.eval(code,n));
}
@@ -536,7 +536,7 @@ return p.coffee_count;
""";
@Test public void testInlineAllocationMemory() {
- var code = new CodeGen(INLINE_MEMORY).parse().opto();
+ var code = new CodeGen(INLINE_MEMORY).parse().iter().finalizeIR();
assertNull(code._stop.walk(n -> n instanceof CallNode ? n : null));
assertEquals("400944",Eval2.eval(code,0));
assertEquals("420946",Eval2.eval(code,2));
diff --git a/chapter23/src/test/java/com/seaofnodes/simple/Chapter19Test.java b/chapter23/src/test/java/com/seaofnodes/simple/Chapter19Test.java
index 23b45e46..70fd3ade 100644
--- a/chapter23/src/test/java/com/seaofnodes/simple/Chapter19Test.java
+++ b/chapter23/src/test/java/com/seaofnodes/simple/Chapter19Test.java
@@ -39,7 +39,7 @@ public class Chapter19Test {
CodeGen code = new CodeGen("""
return 0;
""");
- code.parse().opto().typeCheck();
+ code.driver(CodeGen.Phase.TypeCheck);
assertEquals("return 0;", code._stop.toString());
assertEquals("0", Eval2.eval(code, 2));
}
@@ -48,7 +48,7 @@ return 0;
@Test
public void testString() throws IOException {
String src = Files.readString(Path.of("src/test/java/com/seaofnodes/simple/progs/stringHash.smp"));
- CodeGen code = new CodeGen(src).parse().opto().typeCheck().GCM().localSched();
+ CodeGen code = new CodeGen(src).driver(CodeGen.Phase.LocalSched);
assertEquals("Stop[ return Phi(Region,1,0,0,1); return Phi(Region,._hashCode,Phi(Region,123456789,Phi(Loop,0,(.[]+((Phi_hash<<5)-Phi_hash))))); ]", code._stop.toString());
//assertEquals("-4898613127354160978", Eval2.eval(code, 2));
}
@@ -358,11 +358,11 @@ return sq(arg) + sq(3);
for( String cpu : new String[]{"x86_64_v2","riscv","arm"} )
for( String src : new String[]{Chapter10Test.NESTED_MEMORY,Chapter16Test.CONSTRUCTOR_MEMORY,
Chapter18Test.CALL_MEMORY,Chapter18Test.RECURSIVE_MEMORY} ) {
- var code = new CodeGen(src).parse().opto().typeCheck();
+ var code = new CodeGen(src).driver(CodeGen.Phase.TypeCheck);
var aliases = memoryPhis(code._stop);
- code.loopTree().instSelect(cpu,"SystemV");
+ code.loopTree().driver(CodeGen.Phase.Select,cpu,"SystemV");
assertEquals(aliases,memoryPhis(code._stop));
- code.GCM().localSched();
+ code.driver(CodeGen.Phase.Schedule).localSched();
code._stop.walk(n -> {
if( !(n instanceof CFGNode) && !(n instanceof ProjNode) )
assertTrue(n.in(0) instanceof CFGNode);
@@ -414,7 +414,7 @@ return sq(arg) + sq(3);
int before = p.x + arg;
a.x=33; b.x=44;
return before;
- """).parse().opto().typeCheck().loopTree().instSelect("x86_64_v2","SystemV").GCM().localSched();
+ """).driver(CodeGen.Phase.LocalSched,"x86_64_v2","SystemV");
var read = (MemOpNode)code._stop.walk(n ->
n instanceof com.seaofnodes.simple.node.cpus.x86_64_v2.AddMemX86 ? n : null);
assertNotNull(read);
diff --git a/chapter23/src/test/java/com/seaofnodes/simple/Chapter20Test.java b/chapter23/src/test/java/com/seaofnodes/simple/Chapter20Test.java
index 08a23ef0..cf2b175d 100644
--- a/chapter23/src/test/java/com/seaofnodes/simple/Chapter20Test.java
+++ b/chapter23/src/test/java/com/seaofnodes/simple/Chapter20Test.java
@@ -11,6 +11,10 @@ import org.junit.Test;
import static org.junit.Assert.*;
public class Chapter20Test {
+ @Test public void testFlagSpills() throws Exception {
+ com.seaofnodes.simple.codegen.FlagSpillTestSupport.run();
+ }
+
@Test public void testAllocatorTopPhi() { com.seaofnodes.simple.codegen.RegAllocTestSupport.topPhi(); }
@Test public void testNeverReturnAllocation() {
@@ -71,7 +75,7 @@ return f(s);
// The entry of g can disappear before its Return is folded into f.
// Exercise both worklist orders; deleting the entry does not kill 123.
for( int seed=0; seed<64; seed++ ) {
- CodeGen code = new CodeGen(src,com.seaofnodes.simple.type.TypeInteger.BOT,seed,true).parse().opto().typeCheck();
+ CodeGen code = new CodeGen(src,com.seaofnodes.simple.type.TypeInteger.BOT,seed,true).driver(CodeGen.Phase.TypeCheck);
assertEquals("seed "+seed, "123", Eval2.eval(code,0));
}
}
@@ -96,7 +100,7 @@ return f(s);
@Test
public void testJig() {
CodeGen code = new CodeGen("return 0;");
- code.parse().opto().typeCheck();
+ code.driver(CodeGen.Phase.TypeCheck);
assertEquals("return 0;", code._stop.toString());
assertEquals("0", Eval2.eval(code, 2));
}
@@ -409,8 +413,7 @@ return a;
for( String src : new String[]{Chapter10Test.NESTED_MEMORY,Chapter16Test.CONSTRUCTOR_MEMORY,
Chapter18Test.CALL_MEMORY,Chapter18Test.RECURSIVE_MEMORY,
"int[] !a = new int[3]; a[arg]=arg; return a[0]+1;"} ) {
- var code = new CodeGen(src).parse().opto().typeCheck().loopTree()
- .instSelect(cpu,"SystemV").GCM().localSched().regAlloc();
+ var code = new CodeGen(src).driver(CodeGen.Phase.RegAlloc,cpu,"SystemV");
com.seaofnodes.simple.codegen.RegAllocTestSupport.checkRegisters(code);
code._stop.walk(n -> {
// Whole memory, precise Phis, and memory projections need no register.
diff --git a/chapter23/src/test/java/com/seaofnodes/simple/Chapter21Test.java b/chapter23/src/test/java/com/seaofnodes/simple/Chapter21Test.java
index 30d22fc9..f25a881a 100644
--- a/chapter23/src/test/java/com/seaofnodes/simple/Chapter21Test.java
+++ b/chapter23/src/test/java/com/seaofnodes/simple/Chapter21Test.java
@@ -29,7 +29,7 @@ public class Chapter21Test {
else if(i==4) b.x=40;
}
return sum;
- """).parse().opto();
+ """).parse().iter().finalizeIR();
// The i==2 read still sees 10: three reads of 10, then three of 30.
assertEquals("120",Eval2.eval(code,0));
assertEquals("60",Eval2.eval(code,1));
diff --git a/chapter23/src/test/java/com/seaofnodes/simple/Chapter22Test.java b/chapter23/src/test/java/com/seaofnodes/simple/Chapter22Test.java
index ea210e3f..351fd571 100644
--- a/chapter23/src/test/java/com/seaofnodes/simple/Chapter22Test.java
+++ b/chapter23/src/test/java/com/seaofnodes/simple/Chapter22Test.java
@@ -126,7 +126,7 @@ public class Chapter22Test {
else assertEquals(42,cpu.regs[0]);
}
}
- CodeGen unused = new CodeGen("({->42;}); return 0;").parse().opto();
+ CodeGen unused = new CodeGen("({->42;}); return 0;").parse().iter().finalizeIR();
assertEquals(1,unused._stop.nIns());
}
@@ -172,7 +172,7 @@ public class Chapter22Test {
@Test public void testSubZeroTypeError() {
try {
- new CodeGen("return null-0;").parse().opto().typeCheck();
+ new CodeGen("return null-0;").driver(CodeGen.Phase.TypeCheck);
fail("Subtraction must reject null even when the other operand is zero");
} catch( Parser.ParseException e ) {
assertEquals("Cannot '-' null",e.getMessage());
@@ -344,7 +344,7 @@ bb.c = cc;
val x = 5; // aa.az; // Error to self-define forward ref
return cc.cz;
""";
- CodeGen code = new CodeGen(src).parse().opto().typeCheck();
+ CodeGen code = new CodeGen(src).driver(CodeGen.Phase.TypeCheck);
assertEquals("return 25;", code._stop.toString());
assertEquals("25", Eval2.eval(code, 0));
}
@@ -384,7 +384,7 @@ val sum = { i32[~] is -> // final array
};
return sum(is);
""";
- CodeGen code = new CodeGen(src).parse().opto().typeCheck();
+ CodeGen code = new CodeGen(src).driver(CodeGen.Phase.TypeCheck);
assertEquals("return Phi(Loop,0,(Phi_sum+.[]));", code._stop.toString());
assertEquals("14", Eval2.eval(code, 0));
}
diff --git a/chapter23/src/test/java/com/seaofnodes/simple/Chapter23Test.java b/chapter23/src/test/java/com/seaofnodes/simple/Chapter23Test.java
index 0feaa5de..e27434c2 100644
--- a/chapter23/src/test/java/com/seaofnodes/simple/Chapter23Test.java
+++ b/chapter23/src/test/java/com/seaofnodes/simple/Chapter23Test.java
@@ -154,7 +154,7 @@ struct S { !S? !fld; };
val ptr = arg == 1 ? null : new S{fld = arg==1 ? null : new S{fld = null;};};
return ptr && ptr.fld ? "true" : "false";
""";
- CodeGen code = new CodeGen(src).parse().opto().typeCheck();
+ CodeGen code = new CodeGen(src).driver(CodeGen.Phase.TypeCheck);
assertEquals("[97-117][ 116,114,117,101]", Eval2.eval(code, 0));
// Evaluate on RISC5 emulator
@@ -257,7 +257,7 @@ struct Scan {
return Scan.peek(s,'q');
""";
- CodeGen code = new CodeGen(src).parse().opto().typeCheck();
+ CodeGen code = new CodeGen(src).driver(CodeGen.Phase.TypeCheck);
assertEquals("return Phi(Region,0,1);", code._stop.toString());
assertEquals("1", Eval2.eval(code, 0));
testCPU(src,"x86_64_v2", "Win64" ,23,null);
@@ -282,7 +282,7 @@ struct Scan {
return s.skip().x;
""";
- try { new CodeGen(src).parse().opto().typeCheck(); fail(); }
+ try { new CodeGen(src).driver(CodeGen.Phase.TypeCheck); fail(); }
catch( Exception e ) { org.junit.Assert.assertTrue(e.getMessage().startsWith("Argument #0 isa")); }
};
@@ -309,7 +309,7 @@ struct Scan {
return s.require('[');
""";
- CodeGen code = new CodeGen(src).parse().opto().typeCheck();
+ CodeGen code = new CodeGen(src).driver(CodeGen.Phase.TypeCheck);
assertEquals("return (.[]==91);", code._stop.toString());
assertEquals("1", Eval2.eval(code, 0));
testCPU(src,"x86_64_v2", "Win64" ,4,null);
diff --git a/chapter23/src/test/java/com/seaofnodes/simple/Compile.java b/chapter23/src/test/java/com/seaofnodes/simple/Compile.java
index 088055f9..f3ca1905 100644
--- a/chapter23/src/test/java/com/seaofnodes/simple/Compile.java
+++ b/chapter23/src/test/java/com/seaofnodes/simple/Compile.java
@@ -16,7 +16,7 @@ public class Compile {
private static Process run(String simple, String c) throws IOException, InterruptedException {
boolean USE_WSL = System.getProperty("os.name").startsWith("Windows");
CodeGen code = new CodeGen(simple);
- code.parse().opto().typeCheck().instSelect("x86_64_v2", "SystemV").GCM().localSched().regAlloc().encode();
+ code.driver(CodeGen.Phase.Encoding,"x86_64_v2","SystemV");
if (c != null) for (var n:code._start._outputs) if (n instanceof FunNode f && f._name.equals("main")) f._name = "simple_main";
code.exportELF("test.o");
var params = new ArrayList<String>();
diff --git a/chapter23/src/test/java/com/seaofnodes/simple/CompoundAssignmentTest.java b/chapter23/src/test/java/com/seaofnodes/simple/CompoundAssignmentTest.java
index 48f739cf..e2d822d0 100644
--- a/chapter23/src/test/java/com/seaofnodes/simple/CompoundAssignmentTest.java
+++ b/chapter23/src/test/java/com/seaofnodes/simple/CompoundAssignmentTest.java
@@ -88,7 +88,7 @@ public class CompoundAssignmentTest {
}
private static void check(String src, long arg, long expected) {
- var code = new CodeGen(src).parse().opto().typeCheck();
+ var code = new CodeGen(src).driver(CodeGen.Phase.TypeCheck);
assertEquals(src, Long.toString(expected), Eval2.eval(code, arg));
}
}
diff --git a/chapter23/src/test/java/com/seaofnodes/simple/LiteralTest.java b/chapter23/src/test/java/com/seaofnodes/simple/LiteralTest.java
index 09ee30f5..447ef46e 100644
--- a/chapter23/src/test/java/com/seaofnodes/simple/LiteralTest.java
+++ b/chapter23/src/test/java/com/seaofnodes/simple/LiteralTest.java
@@ -20,7 +20,7 @@ public class LiteralTest {
}
private static void assertString(String text, byte[] expected) {
- var code = new CodeGen("return \"" + text + "\";").parse().opto().typeCheck();
+ var code = new CodeGen("return \"" + text + "\";").driver(CodeGen.Phase.TypeCheck);
TypeMemPtr ptr = (TypeMemPtr)code.expr()._type;
TypeConAryB bytes = (TypeConAryB)ptr._obj.field("[]")._t;
assertArrayEquals(text, expected, bytes._ary);
@@ -33,7 +33,7 @@ public class LiteralTest {
}
private static void assertCharacter(String text, int expected) {
- var code = new CodeGen("return '" + text + "';").parse().opto().typeCheck();
+ var code = new CodeGen("return '" + text + "';").driver(CodeGen.Phase.TypeCheck);
assertEquals(text, expected, ((TypeInteger)code.expr()._type).value());
}
diff --git a/chapter23/src/test/java/com/seaofnodes/simple/Main.java b/chapter23/src/test/java/com/seaofnodes/simple/Main.java
index 589c043b..ca1d0b5b 100644
--- a/chapter23/src/test/java/com/seaofnodes/simple/Main.java
+++ b/chapter23/src/test/java/com/seaofnodes/simple/Main.java
@@ -11,7 +11,7 @@ public class Main {
String src = Files.readString(Path.of(args[0]));
int arg = Integer.valueOf(args[1]);
CodeGen code = new CodeGen(src);
- code.parse().opto().typeCheck().GCM().localSched();
+ code.driver(CodeGen.Phase.LocalSched);
System.out.println(code._stop);
System.out.println(Eval2.eval(code,arg,100000));
}
diff --git a/chapter23/src/test/java/com/seaofnodes/simple/MemoryEncodingTest.java b/chapter23/src/test/java/com/seaofnodes/simple/MemoryEncodingTest.java
index 52c0a573..3397a850 100644
--- a/chapter23/src/test/java/com/seaofnodes/simple/MemoryEncodingTest.java
+++ b/chapter23/src/test/java/com/seaofnodes/simple/MemoryEncodingTest.java
@@ -66,7 +66,7 @@ public class MemoryEncodingTest {
"""
};
for( int p=0; p<sources.length; p++ ) {
- CodeGen code=new CodeGen(sources[p]).parse().opto();
+ CodeGen code=new CodeGen(sources[p]).parse().iter().finalizeIR();
if( p==0 ) assertNull(code._stop.walk(n ->
n instanceof LoadNode ld && ld.ptr() instanceof ProjNode ptr &&
ptr.in(0) instanceof NewNode nn &&
@@ -160,7 +160,7 @@ public class MemoryEncodingTest {
}
return null;
}));
- code.instSelect(target,"SystemV").GCM().localSched().regAlloc();
+ code.driver(CodeGen.Phase.RegAlloc,target,"SystemV");
RegAllocTestSupport.checkRegisters(code);
code.encode();
}
diff --git a/chapter23/src/test/java/com/seaofnodes/simple/MutabilityTest.java b/chapter23/src/test/java/com/seaofnodes/simple/MutabilityTest.java
index 7ae80314..51e31a17 100644
--- a/chapter23/src/test/java/com/seaofnodes/simple/MutabilityTest.java
+++ b/chapter23/src/test/java/com/seaofnodes/simple/MutabilityTest.java
@@ -6,12 +6,12 @@ import com.seaofnodes.simple.codegen.CodeGen;
public class MutabilityTest {
private static void ok(String src, String result) {
- var code = new CodeGen(src).parse().opto().typeCheck();
+ var code = new CodeGen(src).driver(CodeGen.Phase.TypeCheck);
assertEquals(result,Eval2.eval(code,0));
}
private static void bad(String src) {
try {
- new CodeGen(src).parse().opto().typeCheck();
+ new CodeGen(src).driver(CodeGen.Phase.TypeCheck);
} catch( RuntimeException expected ) {
String msg = expected.getMessage();
assertTrue("Expected a permission error, got: "+expected,
diff --git a/chapter23/src/test/java/com/seaofnodes/simple/PhaseTest.java b/chapter23/src/test/java/com/seaofnodes/simple/PhaseTest.java
new file mode 100644
index 00000000..885889a8
--- /dev/null
+++ b/chapter23/src/test/java/com/seaofnodes/simple/PhaseTest.java
@@ -0,0 +1,42 @@
+package com.seaofnodes.simple;
+
+import com.seaofnodes.graph.GraphObserver;
+import com.seaofnodes.simple.codegen.CodeGen;
+import com.seaofnodes.simple.codegen.CodeGen.Phase;
+import com.seaofnodes.simple.node.Node;
+import java.util.ArrayList;
+import org.junit.Test;
+import static org.junit.Assert.*;
+
+public class PhaseTest {
+ private static final String SRC = "int sum=0; for(int i=0; i<arg; i++) sum+=i; return sum;";
+
+ @Test public void testStopAndResume() {
+ ArrayList<String> phases = new ArrayList<>();
+ CodeGen code = new CodeGen(SRC);
+ code._obs = new GraphObserver<Node>() {
+ @Override public void before(Node n) {}
+ @Override public void after(Node n, Node repl, boolean applied) {}
+ @Override public void phase(String phase) { phases.add(phase); }
+ };
+ code.driver(Phase.Iter);
+ assertEquals(Phase.Iter,code._phase);
+ assertEquals("Parse Iter",String.join(" ",phases));
+ code.driver(Phase.TypeCheck);
+ code.driver(Phase.TypeCheck); // Repeated requests do not rerun phases.
+ code.driver(Phase.LoopTree);
+ assertEquals(Phase.LoopTree,code._phase);
+ code.driver(Phase.LocalSched);
+ assertEquals("Parse Iter FinalizeIR TypeCheck LoopTree Schedule LocalSched",String.join(" ",phases));
+ assertEquals("45",Eval2.eval(code,10));
+ }
+
+ @Test public void testResumeMachineCompilation() {
+ CodeGen staged = new CodeGen(SRC).driver(Phase.TypeCheck);
+ staged.driver(Phase.Select,"x86_64_v2","SystemV");
+ staged.driver(Phase.Encoding,"x86_64_v2","SystemV");
+ byte[] bits = staged._encoding._bits.toByteArray();
+ CodeGen direct = new CodeGen(SRC).driver(Phase.Encoding,"x86_64_v2","SystemV");
+ assertArrayEquals(bits,direct._encoding._bits.toByteArray());
+ }
+}
diff --git a/chapter23/src/test/java/com/seaofnodes/simple/SchedulerTest.java b/chapter23/src/test/java/com/seaofnodes/simple/SchedulerTest.java
index 3b19857a..ca211c60 100644
--- a/chapter23/src/test/java/com/seaofnodes/simple/SchedulerTest.java
+++ b/chapter23/src/test/java/com/seaofnodes/simple/SchedulerTest.java
@@ -11,6 +11,26 @@ import static org.junit.Assert.assertEquals;
public class SchedulerTest {
+ @Test public void testMemoryPhiAcrossSiblingBranch() {
+ // The inner memory Phi defines the load's memory. The outer Phi's
+ // other input comes from a branch not dominated by that definition.
+ String src = """
+ struct S { int x; }; !S !a=new S; !S !b=new S;
+ a.x=10; b.x=20; !S !p=a; if(arg>3) p=b;
+ int result=0;
+ if(arg>0) {
+ if(arg>2) p.x=30; else p.x=40;
+ result=a.x;
+ }
+ return result;
+ """;
+ var code = new CodeGen(src).driver(CodeGen.Phase.LocalSched);
+ long[] expected = {0,40,40,30,10,10};
+ for( int arg=0; arg<expected.length; arg++ )
+ assertEquals(Long.toString(expected[arg]),Eval2.eval(code,arg));
+ }
+
+
private static void assertObj(Object obj, String name, Object... fields) {
assertEquals(Evaluator.Obj.class, obj.getClass());
var o = (Evaluator.Obj)obj;
@@ -31,7 +51,7 @@ int i=v.f;
if (arg) v.f=1;
return i;
""");
- code.parse();//.opto();
+ code.parse();//.iter().finalizeIR();
var eval = new Evaluator(code._stop);
assertEquals(2L, eval.evaluate(1, 10));
}
@@ -46,7 +66,7 @@ struct S {
if(arg) v0.f=1;
return v0;
""");
- code.parse().opto();
+ code.parse().iter().finalizeIR();
var eval = new Evaluator(code._stop);
assertObj(eval.evaluate(0, 10), "S", 0L);
assertObj(eval.evaluate(1, 10), "S", 1L);
@@ -65,7 +85,7 @@ i=v.f;
if (arg) v.f=1;
return i;
""");
- code.parse().opto();
+ code.parse().iter().finalizeIR();
var eval = new Evaluator(code._stop);
assertEquals(2L, eval.evaluate(0, 10));
assertEquals(2L, eval.evaluate(1, 10));
diff --git a/chapter23/src/test/java/com/seaofnodes/simple/Simple.java b/chapter23/src/test/java/com/seaofnodes/simple/Simple.java
index aef810d1..9da0d71b 100644
--- a/chapter23/src/test/java/com/seaofnodes/simple/Simple.java
+++ b/chapter23/src/test/java/com/seaofnodes/simple/Simple.java
@@ -1,6 +1,7 @@
package com.seaofnodes.simple;
import com.seaofnodes.simple.codegen.CodeGen;
+import com.seaofnodes.simple.codegen.CodeGen.Phase;
import com.seaofnodes.simple.print.*;
import com.seaofnodes.simple.util.Utils;
import java.io.BufferedReader;
@@ -13,20 +14,21 @@ import java.util.stream.Collectors;
public class Simple {
public static final String PORTS = "com.seaofnodes.simple.node.cpus";
- static final int DUMP_AFTER_PARSE = 1<<0;
- static final int DUMP_AFTER_OPTO = 1<<1;
- static final int DUMP_AFTER_TYPE_CHECK = 1<<2;
- static final int DUMP_AFTER_LOOP_TREE = 1<<3;
- static final int DUMP_AFTER_SELECT = 1<<4;
- static final int DUMP_AFTER_GCM = 1<<5;
- static final int DUMP_AFTER_LOCAL_SCHED = 1<<6;
- static final int DUMP_AFTER_REG_ALLOC = 1<<7;
- static final int DUMP_AFTER_ENCODE = 1<<8;
+ static final int DUMP_AFTER_PARSE = 1<<Phase.Parse.ordinal();
+ static final int DUMP_AFTER_ITER = 1<<Phase.Iter.ordinal();
+ static final int DUMP_AFTER_FINALIZE_IR = 1<<Phase.FinalizeIR.ordinal();
+ static final int DUMP_AFTER_TYPE_CHECK = 1<<Phase.TypeCheck.ordinal();
+ static final int DUMP_AFTER_LOOP_TREE = 1<<Phase.LoopTree.ordinal();
+ static final int DUMP_AFTER_SELECT = 1<<Phase.Select.ordinal();
+ static final int DUMP_AFTER_GCM = 1<<Phase.Schedule.ordinal();
+ static final int DUMP_AFTER_LOCAL_SCHED = 1<<Phase.LocalSched.ordinal();
+ static final int DUMP_AFTER_REG_ALLOC = 1<<Phase.RegAlloc.ordinal();
+ static final int DUMP_AFTER_ENCODE = 1<<Phase.Encoding.ordinal();
static final int DUMP_FINAL = 1<<16;
static final int DUMP_PASS_NAME = 1<<30;
- static final int DUMP_AFTER_ALL = 0xff | DUMP_PASS_NAME;
+ static final int DUMP_AFTER_ALL = ((1<<Phase.values().length)-1) | DUMP_PASS_NAME;
static final int DUMP_DISASSEMBLE = 1<<31;
@@ -36,15 +38,17 @@ public class Simple {
simple [options] <input-file> ...args...
Options:
--dump - dump final intermediate representation
- --dump-after-parse - dump intermediate representation after parse
- --dump-after-opto - dump intermediate representation after opto pass
- --dump-after-type-check - dump intermediate representation after type check pass
- --dump-after-select - dump intermediate representation after instrution selection pass
- --dump-after-gcm - dump intermediate representation after GCM pass
- --dump-after-local-sched - dump intermediate representation after local scheduling pass
- --dump-after-reg-alloc - dump intermediate representation after register allocation pass
- --dump-after-encode - dump intermediate representation after encoding pass
- --dump-after-all - dump intermediate representation after all passes
+ --dump-after-parse - dump intermediate representation after parsing
+ --dump-after-iter - dump intermediate representation after Iter
+ --dump-after-finalize-ir - dump intermediate representation after FinalizeIR
+ --dump-after-type-check - dump intermediate representation after type checking
+ --dump-after-loop-tree - dump intermediate representation after loop-tree construction
+ --dump-after-select - dump intermediate representation after instruction selection
+ --dump-after-gcm - dump intermediate representation after GCM
+ --dump-after-local-sched - dump intermediate representation after local scheduling
+ --dump-after-reg-alloc - dump intermediate representation after register allocation
+ --dump-after-encode - dump intermediate representation after encoding
+ --dump-after-all - dump intermediate representation after all passes
-S - dump generated assembler code
--eval - evaluate the compiled code in emulator
--run - run the compiled code natively; this is the default
@@ -74,50 +78,19 @@ Options:
}
static void dump(CodeGen code, int dump, int pass) {
- if ((dump & pass) != 0) {
- if ((dump & DUMP_PASS_NAME) != 0) {
- System.err.println(switch (pass) {
- case DUMP_AFTER_PARSE -> "After Parse:";
- case DUMP_AFTER_OPTO -> "After OPTO:";
- case DUMP_AFTER_TYPE_CHECK -> "After Type Check:";
- case DUMP_AFTER_LOOP_TREE -> "After Loop Tree:";
- case DUMP_AFTER_SELECT -> "After Code Selection:";
- case DUMP_AFTER_GCM -> "After GCM:";
- case DUMP_AFTER_LOCAL_SCHED -> "After Local Scheduling:";
- case DUMP_AFTER_REG_ALLOC -> "After Register Allocation:";
- case DUMP_AFTER_ENCODE -> "After Encoding:";
- case DUMP_FINAL -> "Final:";
- default -> throw Utils.TODO();
- });
- }
-
- System.err.println(IRPrinter.prettyPrint(code._stop, 9999));
-
- }
+ if( (dump & pass)==0 ) return;
+ if( (dump & DUMP_PASS_NAME)!=0 ) System.err.println("Final:");
+ System.err.println(code);
}
static void print_compilation_times(CodeGen code) {
- double t, total = 0;
-
- total += t = code._tParse / 1e3;
- System.out.printf( "Parsing Time: %.3f sec%n", t);
- total += t = code._tOpto / 1e3;
- System.out.printf( "Optimization Time: %.3f sec%n", t);
- total += t = code._tTypeCheck / 1e3;
- System.out.printf( "Type Checking Time: %.3f sec%n", t);
- total += t = code._tLoopTree / 1e3;
- System.out.printf( "Loop Tree Time: %.3f sec%n", t);
- total += t = code._tInsSel / 1e3;
- System.out.printf( "Code Selection Time: %.3f sec%n", t);
- total += t = code._tGCM / 1e3;
- System.out.printf( "GCM Time: %.3f sec%n", t);
- total += t = code._tLocal / 1e3;
- System.out.printf( "Local Scheduling Time: %.3f sec%n", t);
- total += t = code._tRegAlloc / 1e3;
- System.out.printf( "Register Allocation Time: %.3f sec%n", t);
- total += t = code._tEncode / 1e3;
- System.out.printf( "Encoding Time: %.3f sec%n", t);
- System.out.printf( "TOTAL COMPILATION TIME: %.3f sec%n", total);
+ long total=0;
+ for( Phase phase : Phase.values() ) {
+ long time=code._times[phase.ordinal()];
+ total+=time;
+ System.out.printf("%-24s %.3f sec%n",phase+" Time:",time/1e3);
+ }
+ System.out.printf("TOTAL COMPILATION TIME: %.3f sec%n",total/1e3);
}
static String getInput() throws IOException {
@@ -150,16 +123,17 @@ Options:
switch (arg) {
case "-": input_filename=""; break;
case "--dump": dump |= DUMP_FINAL; break;
- case "--dump-after-parse": dump |= DUMP_AFTER_PARSE; break;
- case "--dump-after-opto": dump |= DUMP_AFTER_OPTO; break;
- case "--dump-after-type-check": dump |= DUMP_AFTER_TYPE_CHECK; break;
- case "--dump-after-loop-tree": dump |= DUMP_AFTER_LOOP_TREE; break;
- case "--dump-after-select": dump |= DUMP_AFTER_SELECT; break;
- case "--dump-after-gcm": dump |= DUMP_AFTER_GCM; break;
- case "--dump-after-local-sched": dump |= DUMP_AFTER_LOCAL_SCHED; break;
- case "--dump-after-reg-alloc": dump |= DUMP_AFTER_REG_ALLOC; break;
- case "--dump-after-encode": dump |= DUMP_AFTER_ENCODE; break;
- case "--dump-after-all": dump |= DUMP_AFTER_ALL; break;
+ case "--dump-after-parse": dump |= DUMP_AFTER_PARSE; break;
+ case "--dump-after-finalize-ir": dump |= DUMP_AFTER_FINALIZE_IR; break;
+ case "--dump-after-iter": dump |= DUMP_AFTER_ITER; break;
+ case "--dump-after-type-check": dump |= DUMP_AFTER_TYPE_CHECK; break;
+ case "--dump-after-loop-tree": dump |= DUMP_AFTER_LOOP_TREE; break;
+ case "--dump-after-select": dump |= DUMP_AFTER_SELECT; break;
+ case "--dump-after-gcm": dump |= DUMP_AFTER_GCM; break;
+ case "--dump-after-local-sched": dump |= DUMP_AFTER_LOCAL_SCHED; break;
+ case "--dump-after-reg-alloc": dump |= DUMP_AFTER_REG_ALLOC; break;
+ case "--dump-after-encode": dump |= DUMP_AFTER_ENCODE; break;
+ case "--dump-after-all": dump |= DUMP_AFTER_ALL; break;
case "-S": dump |= DUMP_DISASSEMBLE; break;
case "--eval": do_eval = true ; do_run = false; break;
case "--run": do_run = true ; break;
@@ -198,38 +172,9 @@ Options:
// Compilation pipeline
CodeGen code = new CodeGen(src);
- code.parse();
- dump(code, dump, DUMP_AFTER_PARSE);
-
- code.opto();
- dump(code, dump, DUMP_AFTER_OPTO);
-
- code.typeCheck();
- dump(code, dump, DUMP_AFTER_TYPE_CHECK);
-
- code.loopTree();
- dump(code, dump, DUMP_AFTER_LOOP_TREE);
-
- if (do_codegen) {
- code.instSelect(cpu, abi, PORTS);
- dump(code, dump, DUMP_AFTER_SELECT);
- }
-
- code.GCM();
- dump(code, dump, DUMP_AFTER_GCM);
-
- code.localSched();
- dump(code, dump, DUMP_AFTER_LOCAL_SCHED);
-
- if (do_codegen) {
- code.regAlloc();
- dump(code, dump, DUMP_AFTER_REG_ALLOC);
-
- code.encode();
- dump(code, dump, DUMP_AFTER_ENCODE);
-
- code.exportELF(base+".o");
- }
+ code.driver(do_codegen ? Phase.Encoding : Phase.LocalSched,
+ do_codegen ? cpu : null, abi, dump);
+ if( do_codegen ) code.exportELF(base+".o");
dump(code, dump, DUMP_FINAL);
diff --git a/chapter23/src/test/java/com/seaofnodes/simple/codegen/FlagSpillTestSupport.java b/chapter23/src/test/java/com/seaofnodes/simple/codegen/FlagSpillTestSupport.java
new file mode 100644
index 00000000..00d86c63
--- /dev/null
+++ b/chapter23/src/test/java/com/seaofnodes/simple/codegen/FlagSpillTestSupport.java
@@ -0,0 +1,145 @@
+package com.seaofnodes.simple.codegen;
+
+import com.seaofnodes.isa.X86;
+import com.seaofnodes.isa.eval.EvalArm64;
+import com.seaofnodes.simple.TestC;
+import com.seaofnodes.simple.node.*;
+import com.seaofnodes.simple.node.cpus.arm.arm;
+import com.seaofnodes.simple.node.cpus.x86_64_v2.x86_64_v2;
+import com.seaofnodes.simple.type.TypeInteger;
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import static org.junit.Assert.*;
+
+// Force overlapping flags, then force every GPR unavailable across the gap.
+public class FlagSpillTestSupport {
+ private static class Op extends MachConcreteNode {
+ final RegMask _def, _use, _kill;
+ Op(RegMask def,RegMask use,RegMask kill,Node... ins) {
+ super(ins); _def=def; _use=use; _kill=kill; _type=TypeInteger.BOT;
+ }
+ @Override public String op() { return "flagsProbe"; }
+ @Override public RegMask outregmap() { return _def; }
+ @Override public RegMask regmap(int i) { return _use; }
+ @Override public RegMask killmap() { return _kill; }
+ @Override public void encoding(Encoding enc) { throw new AssertionError(); }
+ }
+
+ public static void run() throws Exception {
+ StringBuilder asm = new StringBuilder(".text\n");
+ for( boolean isArm : new boolean[]{false,true} )
+ for( boolean stack : new boolean[]{false,true} ) {
+ CodeGen code = new CodeGen("");
+ code._callingConv="SystemV";
+ code._mach=isArm ? new arm(code) : new x86_64_v2(code);
+ RegionNode block = new RegionNode(null,code._start,code._start);
+ code._cfg.add(block);
+ int flagsReg=isArm ? 64 : 32, firstStack=flagsReg+1;
+ RegMask flags = new RegMask(flagsReg);
+ Op def = new Op(flags,null,null,block);
+ RegMask killMask = stack ? (isArm ? new RegMask(0x7fffffffL,1L) : new RegMask(0x1ffffffefL)) : flags;
+ Op kill = new Op(null,null,killMask,block);
+ new Op(null,flags,null,block,def);
+ RegAlloc alloc = new RegAlloc(code);
+ alloc.regAlloc();
+
+ int splits=0, slots=0;
+ for( Node n : block._outputs ) if( n instanceof SplitNode split ) {
+ int dst=alloc.regnum(n), src=alloc.regnum(n.in(1));
+ assertTrue(split.outregmap().test(dst));
+ assertTrue(split.regmap(1).test(src));
+ for( int fp=isArm ? 32 : 16; fp<flagsReg; fp++ ) {
+ assertFalse("FP output allowed",split.outregmap().test(fp));
+ assertFalse("FP input allowed",split.regmap(1).test(fp));
+ }
+ if( dst>=firstStack || src>=firstStack ) slots++;
+ splits++;
+ }
+ assertTrue(splits>=2);
+ assertEquals(stack,slots!=0);
+
+ code._regAlloc=alloc;
+ FunNode frame = new FunNode(null,null,"flags",(Node)null);
+ Encoding save = new Encoding(code), restore = new Encoding(code);
+ save._fun=restore._fun=frame;
+ Encoding enc = save;
+ for( Node n : block._outputs ) {
+ if( n==kill ) enc=restore;
+ if( n instanceof SplitNode split ) split.encoding(enc);
+ }
+ if( isArm ) {
+ for( int bits=0; bits<16; bits++ ) {
+ EvalArm64 cpu = new EvalArm64(new byte[1024],512);
+ System.arraycopy(save._bits.buf(),0,cpu._buf,0,save._bits.size());
+ System.arraycopy(restore._bits.buf(),0,cpu._buf,save._bits.size(),restore._bits.size());
+ cpu.N=(bits&8)!=0; cpu.Z=(bits&4)!=0; cpu.C=(bits&2)!=0; cpu.V=(bits&1)!=0;
+ assertEquals(0,cpu.step(save._bits.size()/4));
+ cpu.N=cpu.Z=cpu.C=cpu.V=false;
+ if( stack ) for( int r=0; r<31; r++ ) cpu.regs[r]=0;
+ assertEquals(0,cpu.step(restore._bits.size()/4));
+ assertEquals((bits&8)!=0,cpu.N); assertEquals((bits&4)!=0,cpu.Z);
+ assertEquals((bits&2)!=0,cpu.C); assertEquals((bits&1)!=0,cpu.V);
+ assertEquals(512,cpu.regs[31]);
+ }
+ } else {
+ Encoding body = new Encoding(code);
+ int[] preserved={3,5,6,7,12,13,14,15};
+ for( int r : preserved ) pushPop(body,r,false);
+ X86.imm(body,0x81,5,4,16); // Reserve spill storage.
+ X86.flags(body,TestC.OS.startsWith("Windows") ? 1 : 7,true);
+ bytes(body,save);
+ if( stack ) {
+ for( int r=0; r<16; r++ ) if( r!=4 ) X86.constant(body,r,0);
+ } else X86.reg(body,0x39,0,0); // CMP rax,rax clobbers only flags.
+ bytes(body,restore);
+ X86.flags(body,0,false); // Return the restored flags.
+ X86.imm(body,0x81,0,4,16);
+ for( int i=preserved.length-1; i>=0; i-- ) pushPop(body,preserved[i],true);
+ X86.ret(body);
+ String name=stack ? "flags_stack" : "flags_reg";
+ asm.append(".globl ").append(name).append('\n').append(name).append(":\n.byte ");
+ for( int i=0; i<body._bits.size(); i++ ) {
+ if( i!=0 ) asm.append(',');
+ asm.append(body._bits.buf()[i]&255);
+ }
+ asm.append('\n');
+ }
+ }
+ Path dir=Files.createTempDirectory(Path.of("build/objs"),"flag_spills_");
+ Files.writeString(dir.resolve("flags.s"),asm);
+ Files.writeString(dir.resolve("flags.c"),"""
+ typedef unsigned long long u64;
+ u64 __attribute__((CALL_CONV)) flags_reg(u64);
+ u64 __attribute__((CALL_CONV)) flags_stack(u64);
+ int main(void) {
+ const int positions[]={0,2,4,6,7,11};
+ for(int bits=0; bits<64; bits++) {
+ u64 flags=0x202;
+ for(int i=0;i<6;i++) if(bits&(1<<i)) flags|=1ULL<<positions[i];
+ if((flags_reg(flags)&0x8d5)!=(flags&0x8d5)) return 1;
+ if((flags_stack(flags)&0x8d5)!=(flags&0x8d5)) return 2;
+ }
+ return 0;
+ }
+ """);
+ String exe=dir.resolve(TestC.OS.startsWith("Windows") ? "flags.exe" : "flags").toString();
+ exec("gcc","-DCALL_CONV="+(TestC.OS.startsWith("Windows") ? "ms_abi" : "sysv_abi"),
+ "-o",exe,dir.resolve("flags.c").toString(),dir.resolve("flags.s").toString());
+ exec(exe);
+ }
+
+ private static void exec(String... command) throws Exception {
+ Process process = new ProcessBuilder(command).redirectErrorStream(true).start();
+ String output = new String(process.getInputStream().readAllBytes(),java.nio.charset.StandardCharsets.UTF_8);
+ assertEquals(String.join(" ",command)+"\n"+output,0,process.waitFor());
+ }
+
+ private static void bytes(Encoding dst,Encoding src) {
+ for( int i=0; i<src._bits.size(); i++ ) dst.add1(src._bits.buf()[i]&255);
+ }
+ private static void pushPop(Encoding enc,int reg,boolean pop) {
+ if( reg>=8 ) enc.add1(0x41);
+ enc.add1((pop ? 0x58 : 0x50)+(reg&7));
+ }
+}
diff --git a/chapter23/src/test/java/com/seaofnodes/simple/codegen/RegAllocTestSupport.java b/chapter23/src/test/java/com/seaofnodes/simple/codegen/RegAllocTestSupport.java
index ad898be3..b60adce7 100644
--- a/chapter23/src/test/java/com/seaofnodes/simple/codegen/RegAllocTestSupport.java
+++ b/chapter23/src/test/java/com/seaofnodes/simple/codegen/RegAllocTestSupport.java
@@ -22,6 +22,11 @@ public class RegAllocTestSupport {
@Override public Node copy() { return new Op(_def,_use,_kill,_clone,(Node)null); }
@Override public void encoding(Encoding enc) { throw new AssertionError(); }
}
+ private static SplitNode testSplit(CodeGen code, MachNode def) {
+ LRG lrg = new LRG((short)0);
+ lrg._machDef = def;
+ return code._mach.split("test",(byte)0,lrg);
+ }
private static CodeGen graph() {
CodeGen code = new CodeGen("");
code._mach = new x86_64_v2(code);
@@ -221,11 +226,11 @@ public class RegAllocTestSupport {
RegAlloc alloc = new RegAlloc(code);
Op def = new Op(A,null,null,false,code._start);
alloc.newLRG(def)._reg=0;
- SplitNode hi = code._mach.split("test",(byte)0,null);
+ SplitNode hi = testSplit(code,def);
hi.setDef(0,code._start); hi.setDef(1,def);
alloc.newLRG(hi)._reg=1;
new Op(null,null,killed ? A : null,false,code._start);
- SplitNode lo = code._mach.split("test",(byte)0,null);
+ SplitNode lo = testSplit(code,hi);
lo.setDef(0,code._start); lo.setDef(1,hi);
alloc.newLRG(lo)._reg=0;
Op use = new Op(null,A,null,false,code._start,lo);
@@ -239,7 +244,7 @@ public class RegAllocTestSupport {
uncolored.newLRG(def0)._mask=A;
Op fixed = new Op(A,null,null,false,pre._start);
uncolored.newLRG(fixed)._mask=A;
- SplitNode copy = pre._mach.split("test",(byte)0,null);
+ SplitNode copy = testSplit(pre,def0);
copy.setDef(0,pre._start); copy.setDef(1,def0);
assertFalse("A fixed definition clobbers even before coloring",uncolored.sameBlockNoClobber(copy));
}
@@ -252,7 +257,7 @@ public class RegAllocTestSupport {
RegAlloc alloc = new RegAlloc(code);
Op def = new Op(A,null,null,false,code._start);
alloc.newLRG(def)._reg=0;
- SplitNode copy = code._mach.split("test",(byte)0,null);
+ SplitNode copy = testSplit(code,def);
copy.setDef(0,code._start); copy.setDef(1,def);
alloc.newLRG(copy)._reg=1;
if( kind==3 ) new Op(null,null,A,false,code._start);
@@ -275,7 +280,7 @@ public class RegAllocTestSupport {
CodeGen code = graph();
RegAlloc alloc = new RegAlloc(code);
Op def = new Op(new RegMask(3L),null,null,false,code._start);
- SplitNode copy = code._mach.split("test",(byte)0,null);
+ SplitNode copy = testSplit(code,def);
copy.setDef(0,code._start); copy.setDef(1,def);
Op use = new Op(null,new RegMask(3L),null,false,code._start,copy);
LRG from = alloc.newLRG(def), to = alloc.newLRG(copy);
diff --git a/chapter23/src/test/java/com/seaofnodes/simple/fuzzer/Fuzzer.java b/chapter23/src/test/java/com/seaofnodes/simple/fuzzer/Fuzzer.java
index b29eb2c3..a3112d55 100644
--- a/chapter23/src/test/java/com/seaofnodes/simple/fuzzer/Fuzzer.java
+++ b/chapter23/src/test/java/com/seaofnodes/simple/fuzzer/Fuzzer.java
@@ -133,7 +133,7 @@ public class Fuzzer {
double parse_nop_ratio = (double)parse_nops/parse_peeps;
double parse_peeps_per_node = (double)parse_peeps/nids;
- code.opto();
+ code.iter().finalizeIR();
int iter_peeps= code._iter_cnt;
int iter_nops = code._iter_nop_cnt;
double iter_nop_ratio = (double)iter_nops/iter_peeps;