diff options
Diffstat (limited to 'chapter21')
47 files changed, 832 insertions, 599 deletions
diff --git a/chapter21/README.md b/chapter21/README.md index 80304c1a..a3ae6cb8 100644 --- a/chapter21/README.md +++ b/chapter21/README.md @@ -17,6 +17,18 @@ in the linear revision history and Here is the [complete language grammar](docs/21-grammar.md) for this chapter. +Two phases extend the pipeline: `Encoding` turns allocated nodes into bytes, +and `Export` resolves relocations in memory or writes an ELF object. For example: + +```java +code.driver(CodeGen.Phase.Encoding, "x86_64_v2", "SystemV"); +code.exportELF("program.o"); +``` + +The CLI uses the same driver. `--dump-after-iter`, the other phase dump options, +and `--dump-time` expose the stages without duplicating their ordering in the +command-line frontend. + ## From machine nodes to bytes Instruction selection chooses the operation and register constraints. Register diff --git a/chapter21/src/main/java/com/seaofnodes/simple/codegen/CodeGen.java b/chapter21/src/main/java/com/seaofnodes/simple/codegen/CodeGen.java index 2c44cb05..95e30d12 100644 --- a/chapter21/src/main/java/com/seaofnodes/simple/codegen/CodeGen.java +++ b/chapter21/src/main/java/com/seaofnodes/simple/codegen/CodeGen.java @@ -9,7 +9,6 @@ import com.seaofnodes.simple.type.*; import java.io.IOException; import java.util.BitSet; import java.util.HashMap; -import java.util.IdentityHashMap; @SuppressWarnings("unchecked") public class CodeGen { @@ -20,19 +19,61 @@ 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 - InstSelect, // 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 + TypeCheck, // Check the surviving ideal graph + LoopTree, // Discover loops and connect nonreturning paths + InstSelect, // 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.TypeCheck, this::typeCheck, dump); + step(target, Phase.LoopTree, this::loopTree, dump); + step(target, Phase.InstSelect, () -> 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; @@ -53,21 +94,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(); - if( _phase.ordinal() < phase.ordinal() ) opto(); - if( _phase.ordinal() < phase.ordinal() ) typeCheck(); - if( _phase.ordinal() < phase.ordinal() ) loopTree(); - if( _phase.ordinal() < phase.ordinal() && cpu != null ) instSelect(cpu,callingConv); - if( _phase.ordinal() < phase.ordinal() ) GCM(); - if( _phase.ordinal() < phase.ordinal() ) localSched(); - if( _phase.ordinal() < phase.ordinal() ) regAlloc(); - if( _phase.ordinal() < phase.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); @@ -143,16 +169,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(); + }); } @@ -167,61 +187,23 @@ 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); - _tOpto = (int)(System.currentTimeMillis() - t0); - - // TODO: - // Optimistic - // TODO: - // loop unroll, peel, RCE, etc - if( _obs != null ) _obs.phase("Opto"); - return this; - } + // Pessimistic peepholes reach a fixed point after parsing. + public CodeGen iter() { return phase(Phase.Iter, _phase==Phase.Parse, () -> _iter.iterate(this)); } public <N extends Node> N add( N n ) { return (N)_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.Iter, () -> 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(_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(_stop); + }); } // --------------------------- @@ -243,138 +225,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.InstSelect; - - _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 ); - _start = (StartNode)map.get(_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) ); - // 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 - - // Updates forward edges only. - n._outputs.clear(); - 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.InstSelect, _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.InstSelect.ordinal(); - _phase = Phase.Schedule; - long t0 = System.currentTimeMillis(); - - GlobalCodeMotion.buildCFG(this); - _tGCM = (int)(System.currentTimeMillis() - t0); + return phase(Phase.Schedule, (_phase==Phase.LoopTree || _phase==Phase.InstSelect), () -> { + GlobalCodeMotion.buildCFG(this); - 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 @@ -390,27 +275,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/chapter21/src/main/java/com/seaofnodes/simple/codegen/GlobalCodeMotion.java b/chapter21/src/main/java/com/seaofnodes/simple/codegen/GlobalCodeMotion.java index 447a6df1..d4db558a 100644 --- a/chapter21/src/main/java/com/seaofnodes/simple/codegen/GlobalCodeMotion.java +++ b/chapter21/src/main/java/com/seaofnodes/simple/codegen/GlobalCodeMotion.java @@ -274,10 +274,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: @@ -294,7 +295,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/chapter21/src/main/java/com/seaofnodes/simple/codegen/InstSelect.java b/chapter21/src/main/java/com/seaofnodes/simple/codegen/InstSelect.java new file mode 100644 index 00000000..4d67be4b --- /dev/null +++ b/chapter21/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 ); + _code._start = (StartNode)map.get(_code._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) ); + // 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 + + // Updates forward edges only. + n._outputs.clear(); + 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/chapter21/src/main/java/com/seaofnodes/simple/codegen/LRG.java b/chapter21/src/main/java/com/seaofnodes/simple/codegen/LRG.java index ec254a2e..6ece27a2 100644 --- a/chapter21/src/main/java/com/seaofnodes/simple/codegen/LRG.java +++ b/chapter21/src/main/java/com/seaofnodes/simple/codegen/LRG.java @@ -59,6 +59,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/chapter21/src/main/java/com/seaofnodes/simple/codegen/RegAlloc.java b/chapter21/src/main/java/com/seaofnodes/simple/codegen/RegAlloc.java index dd3d2acb..85b3d283 100644 --- a/chapter21/src/main/java/com/seaofnodes/simple/codegen/RegAlloc.java +++ b/chapter21/src/main/java/com/seaofnodes/simple/codegen/RegAlloc.java @@ -361,7 +361,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 ) continue; // Ignoring splits; since spilling need to split in a deeper loop + if( n instanceof SplitNode split && !split.isNonStackSplit() ) continue; // Ordinary splits already reach stack storage. if( n.isDead() ) continue; // Some Clonable 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. @@ -414,8 +414,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/chapter21/src/main/java/com/seaofnodes/simple/codegen/TypeCheck.java b/chapter21/src/main/java/com/seaofnodes/simple/codegen/TypeCheck.java new file mode 100644 index 00000000..0997fd2f --- /dev/null +++ b/chapter21/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/chapter21/src/main/java/com/seaofnodes/simple/node/SplitNode.java b/chapter21/src/main/java/com/seaofnodes/simple/node/SplitNode.java index ff18b292..437a700a 100644 --- a/chapter21/src/main/java/com/seaofnodes/simple/node/SplitNode.java +++ b/chapter21/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/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/SplitFlagsARM.java b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/SplitFlagsARM.java new file mode 100644 index 00000000..3e045a6f --- /dev/null +++ b/chapter21/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/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/SplitGPRARM.java b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/SplitGPRARM.java new file mode 100644 index 00000000..46eff4ca --- /dev/null +++ b/chapter21/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/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/arm.java b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/arm.java index 66a59fde..9910795d 100644 --- a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/arm.java +++ b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/arm.java @@ -267,7 +267,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/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/SplitFlagsX86.java b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/SplitFlagsX86.java new file mode 100644 index 00000000..4650b535 --- /dev/null +++ b/chapter21/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/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/SplitX86.java b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/SplitX86.java index 5cf668d1..3c4dde17 100644 --- a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/SplitX86.java +++ b/chapter21/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/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/x86_64_v2.java b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/x86_64_v2.java index 1b7cf775..1dc47188 100644 --- a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/x86_64_v2.java +++ b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/x86_64_v2.java @@ -45,7 +45,7 @@ public class x86_64_v2 extends Machine { static RegMask RPC_MASK = new RegMask(RPC); 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); @@ -235,7 +235,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/chapter21/src/main/java/com/seaofnodes/simple/print/SimpleGraphObserver.java b/chapter21/src/main/java/com/seaofnodes/simple/print/SimpleGraphObserver.java index d8d0e216..99b3d190 100644 --- a/chapter21/src/main/java/com/seaofnodes/simple/print/SimpleGraphObserver.java +++ b/chapter21/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/chapter21/src/test/java/com/seaofnodes/simple/BrainFuckTest.java b/chapter21/src/test/java/com/seaofnodes/simple/BrainFuckTest.java index aa6fada0..97d33b70 100644 --- a/chapter21/src/test/java/com/seaofnodes/simple/BrainFuckTest.java +++ b/chapter21/src/test/java/com/seaofnodes/simple/BrainFuckTest.java @@ -20,7 +20,7 @@ public class BrainFuckTest { String brain_fuck = "Hello World!\n"; TestC.run("brain_fuck", brain_fuck, 40); - EvalRisc5 R5 = TestRisc5.build("brain_fuck", 0, 146, false); + EvalRisc5 R5 = TestRisc5.build("brain_fuck", 0, 42, false); int trap = R5.step(100000); assertEquals(0,trap); int ptr = (int)R5.regs[riscv.A0]; diff --git a/chapter21/src/test/java/com/seaofnodes/simple/Chapter05Test.java b/chapter21/src/test/java/com/seaofnodes/simple/Chapter05Test.java index 6ff4ac95..c809f72f 100644 --- a/chapter21/src/test/java/com/seaofnodes/simple/Chapter05Test.java +++ b/chapter21/src/test/java/com/seaofnodes/simple/Chapter05Test.java @@ -20,7 +20,7 @@ else { } return a; """); - code.parse().opto(); + code.parse().iter(); 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(); 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(); 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(); 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(); 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(); 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(); assertEquals("return (arg==Phi(Region,3,2));", code.print()); } @@ -145,7 +145,7 @@ else a=3; return a; """); - code.parse().opto(); + code.parse().iter(); assertEquals("return 3;", code.print()); } diff --git a/chapter21/src/test/java/com/seaofnodes/simple/Chapter06Test.java b/chapter21/src/test/java/com/seaofnodes/simple/Chapter06Test.java index b6bc2bf3..2c97b9c2 100644 --- a/chapter21/src/test/java/com/seaofnodes/simple/Chapter06Test.java +++ b/chapter21/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(); 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(); assertEquals("return 1;", code.print()); } @@ -44,7 +44,7 @@ else a=3; return a; """); - code.parse().opto(); + code.parse().iter(); 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(); 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(); 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).parse().opto(); +""", TypeInteger.constant(2), 123L).parse().iter(); assertEquals("return 5;", code.print()); } @@ -124,7 +124,7 @@ else if( arg==3 ) else a=5; return a; -""", TypeInteger.constant(1), 123L).parse().opto(); +""", TypeInteger.constant(1), 123L).parse().iter(); assertEquals("return 3;", code.print()); } @@ -144,7 +144,7 @@ else a=5; return a; """); - code.parse().opto(); + code.parse().iter(); assertEquals("return Phi(Region,3,5,4);", code.print()); } @@ -165,7 +165,7 @@ else a=5; return a; """, TypeInteger.constant(1), 123L); - code.parse().opto(); + code.parse().iter(); assertEquals("return 3;", code.print()); } @@ -186,7 +186,7 @@ else a=5; return a; """, TypeInteger.constant(3), 123L); - code.parse().opto(); + code.parse().iter(); assertEquals("return 4;", code.print()); } @@ -202,7 +202,7 @@ if( arg ) { } return a+b; """); - code.parse().opto(); + code.parse().iter(); assertEquals("return Phi(Region,4,1);", code.print()); } @@ -221,7 +221,7 @@ if( arg ) { } return a+b; """, TypeInteger.constant(1), 123L); - code.parse().opto(); + code.parse().iter(); assertEquals("return 4;", code.print()); } @@ -239,7 +239,7 @@ if( arg ) { } return a+b; """, TypeInteger.constant(0), 123L); - code.parse().opto(); + code.parse().iter(); assertEquals("return 1;", code.print()); } @@ -257,7 +257,7 @@ if( arg ) { } return a+b+c; """); - code.parse().opto(); + code.parse().iter(); assertEquals("return Phi(Region,6,1,5);", code.print()); } @@ -278,7 +278,7 @@ if( arg ) { } return a+b+c; """, TypeInteger.constant(1), 123L); - code.parse().opto(); + code.parse().iter(); assertEquals("return 6;", code.print()); } @@ -298,7 +298,7 @@ if( arg ) { } return a+b+c; """, TypeInteger.constant(2), 123L); - code.parse().opto(); + code.parse().iter(); assertEquals("return 5;", code.print()); } diff --git a/chapter21/src/test/java/com/seaofnodes/simple/Chapter07Test.java b/chapter21/src/test/java/com/seaofnodes/simple/Chapter07Test.java index 88554323..b0526eb1 100644 --- a/chapter21/src/test/java/com/seaofnodes/simple/Chapter07Test.java +++ b/chapter21/src/test/java/com/seaofnodes/simple/Chapter07Test.java @@ -34,7 +34,7 @@ if(arg){}else{ } return a; """); - code.parse().opto(); + code.parse().iter(); 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(); 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(); 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(); 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(); 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(); 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(); assertEquals("return Phi(Loop,1,(Phi_a+3));", code.print()); assertTrue(code.ctrl() instanceof CProjNode); } diff --git a/chapter21/src/test/java/com/seaofnodes/simple/Chapter08Test.java b/chapter21/src/test/java/com/seaofnodes/simple/Chapter08Test.java index 09669cc7..487a2c7b 100644 --- a/chapter21/src/test/java/com/seaofnodes/simple/Chapter08Test.java +++ b/chapter21/src/test/java/com/seaofnodes/simple/Chapter08Test.java @@ -22,7 +22,7 @@ while(arg < 10) { } return arg; """); - code.parse().opto(); + code.parse().iter(); 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(); 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(); 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(); 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(); 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(); 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(); 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(); assertEquals("return 0;", code.print()); } @@ -167,7 +167,7 @@ while(arg < 10) { } return arg; """); - code.parse().opto(); + code.parse().iter(); assertEquals("return arg;", code.print()); } @@ -184,7 +184,7 @@ while(arg < 10) { } return a; """); - code.parse().opto(); + code.parse().iter(); 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(); assertEquals("return (Phi(Loop,1,Add)+1);", code.print()); assertTrue(code.ctrl() instanceof CProjNode prj && prj._idx==1 ); } diff --git a/chapter21/src/test/java/com/seaofnodes/simple/Chapter09Test.java b/chapter21/src/test/java/com/seaofnodes/simple/Chapter09Test.java index 401f346f..0a3049e6 100644 --- a/chapter21/src/test/java/com/seaofnodes/simple/Chapter09Test.java +++ b/chapter21/src/test/java/com/seaofnodes/simple/Chapter09Test.java @@ -24,7 +24,7 @@ while(v0) { } return 0; """); - code.parse().opto(); + code.parse().iter(); } @Test @@ -40,7 +40,7 @@ else { } return x; """); - code.parse().opto(); + code.parse().iter(); 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(); 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(); 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(); 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(); assertEquals("return 0;", code.print()); } @@ -127,14 +127,14 @@ while(v1+arg) { v1=v2; } """); - code.parse().opto(); + code.parse().iter(); assertEquals("return 0;", code.print()); } @Test public void testWhile0() { CodeGen code = new CodeGen("while(0) continue; if(0) arg=0;"); - code.parse().opto(); + code.parse().iter(); assertEquals("return 0;", code.print()); } @@ -146,7 +146,7 @@ if(0) while(0) { while(0) {} } """); - code.parse().opto(); + code.parse().iter(); assertEquals("return 0;", code.print()); } @@ -154,14 +154,14 @@ if(0) while(0) { @Test public void testPrecedence() { CodeGen code = new CodeGen("return 3-1+2;"); - code.parse().opto(); + code.parse().iter(); assertEquals("return 4;", code.print()); } @Test public void testSwap2() { CodeGen code = new CodeGen("return 1+(1+1);"); - code.parse().opto(); + code.parse().iter(); assertEquals("return 3;", code.print()); } @@ -179,7 +179,7 @@ while(arg) { } return a; """); - code.parse().opto(); + code.parse().iter(); assertEquals("return Phi(Loop,0,(-(Phi_a+3)));", code.print()); } @@ -193,7 +193,7 @@ arg=0; int v0=0!=0<-0; return -0+0+0; """); - code.parse().opto(); + code.parse().iter(); assertEquals("return Top;", code.print()); } @@ -201,14 +201,14 @@ return -0+0+0; @Test public void testFuzz2() { CodeGen code = new CodeGen("return 0+-0;"); - code.parse().opto(); + code.parse().iter(); assertEquals("return 0;", code.print()); } @Test public void testFuzz3() { CodeGen code = new CodeGen("int v0=0; while(0==69) while(v0) return 0;"); - code.parse().opto(); + code.parse().iter(); assertEquals("return 0;", code.print()); } @@ -220,7 +220,7 @@ while(1) { if(1<0) while(arg==-0) arg=arg-arg; } """); - code.parse().opto(); + code.parse().iter(); assertEquals("return Top;", code.print()); } @@ -242,7 +242,7 @@ while(1) { } return 0!=0; """); - code.parse().opto(); + code.parse().iter(); assertEquals("return Top;", code.print()); } @@ -254,7 +254,7 @@ int v0=0; while(0==1) while(v0) v0=1+v0; """); - code.parse().opto(); + code.parse().iter(); assertEquals("return 0;", code.print()); } @@ -270,14 +270,14 @@ while(1) v1=1; return v1+v0; """); - code.parse().opto(); + code.parse().iter(); 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(); assertEquals("return 0;", code.print()); } diff --git a/chapter21/src/test/java/com/seaofnodes/simple/Chapter10Test.java b/chapter21/src/test/java/com/seaofnodes/simple/Chapter10Test.java index 91505f41..8af1c71d 100644 --- a/chapter21/src/test/java/com/seaofnodes/simple/Chapter10Test.java +++ b/chapter21/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).parse().iter().typeCheck(); org.junit.Assert.assertTrue(body, code.expr()._type instanceof com.seaofnodes.simple.type.TypeMemPtr); } @@ -39,7 +39,7 @@ public class Chapter10Test { "if (!!!p) return -1; return p.x;", "int b = !!p; if (b) return p.x + b - 1; return -1;" } ) { - CodeGen code = new CodeGen(NULLABLE_POINT_SOURCE+body).parse().opto().typeCheck(); + CodeGen code = new CodeGen(NULLABLE_POINT_SOURCE+body).parse().iter().typeCheck(); assertEquals(body,"-1",Eval2.eval(code,0)); assertEquals(body,"42",Eval2.eval(code,1)); } @@ -54,7 +54,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).parse().iter().typeCheck(); fail(body); } catch( RuntimeException e ) { // Known null is rejected during parsing in these chapters. @@ -86,7 +86,7 @@ if( (arg/13)==0 ) { int r = g+h; return p-r; """); - code.parse().opto(); + code.parse().iter(); assertEquals("return 0;", code.print()); } @@ -106,7 +106,7 @@ bar.a = 1; bar.a = 2; return bar.a; """); - code.parse().opto(); + code.parse().iter(); assertEquals("return 2;", code.print()); } @@ -122,7 +122,7 @@ else v.y = 3; return v; """); - code.parse().opto(); + code.parse().iter(); assertEquals("return Vector2D;", code.print()); } @@ -160,7 +160,7 @@ while (arg) { } return bar.a; """); - code.parse().opto(); + code.parse().iter(); assertEquals("return Phi(Loop,0,(Phi_a+2));", code.print()); } @@ -173,7 +173,7 @@ if (arg) bar = null; bar.a = 1; return bar.a; """); - try { code.parse().opto(); fail(); } + try { code.parse().iter(); fail(); } catch( Exception e ) { assertEquals("Type null is not of declared type *Bar",e.getMessage()); } } @@ -186,7 +186,7 @@ if (arg) bar = new Bar; bar.a = 1; return bar.a; """); - try { code.parse().opto().typeCheck(); fail(); } + try { code.parse().iter().typeCheck(); fail(); } catch( Exception e ) { assertEquals("Might be null accessing 'a'",e.getMessage()); } } @@ -212,7 +212,7 @@ if (arg) bar = null; if( bar ) bar.a = 1; return bar; """); - code.parse().opto(); + code.parse().iter(); assertEquals("return Phi(Region,null,Bar);", code.print()); } @@ -228,7 +228,7 @@ if( !bar ) rez=4; else bar.a = 1; return rez; """); - code.parse().opto(); + code.parse().iter(); assertEquals("return Phi(Region,4,3);", code.print()); } @@ -245,7 +245,7 @@ while(arg) { } return ret; """); - try { code.parse().opto().typeCheck(); fail(); } + try { code.parse().iter().typeCheck(); fail(); } catch( Exception e ) { assertEquals("Might be null accessing 'v0'", e.getMessage()); } } @@ -282,7 +282,7 @@ while( i.x < i.len ) { } return sum; """); - code.parse().opto(); + code.parse().iter(); assertEquals("return Phi(Loop,0,(Phi(Loop,0,(Phi_x+1))+Phi_sum));", code.print()); } @@ -301,7 +301,7 @@ while(arg) { } return ret; """); - code.parse().opto(); + code.parse().iter(); assertEquals("return Phi(Loop,s0,Phi(Region,s0,Phi_ret));", code.print()); } @@ -319,7 +319,7 @@ while(arg) { } return ret; """); - code.parse().opto(); + code.parse().iter(); assertEquals("return Phi(Loop,s0,Phi(Region,s0,Phi_ret));", code.print()); } @@ -336,7 +336,7 @@ while(arg < 10) { } return ret; """); - code.parse().opto(); + code.parse().iter(); assertEquals("return Phi(Loop,s0,Phi(Region,s0,Phi_ret));", code.print()); } @@ -363,7 +363,7 @@ if(0) { } } """); - code.parse().opto(); + code.parse().iter(); assertEquals("return 0;", code.print()); } @@ -377,7 +377,7 @@ if(0) return 0; else return new s0; if(new s0.f0) return 0; """); - code.parse().opto(); + code.parse().iter(); assertEquals("return s0;", code.print()); } @@ -393,7 +393,7 @@ while(0<arg) { } return 0; """); - code.parse().opto(); + code.parse().iter(); } @Test @@ -405,7 +405,7 @@ while(v0.f0) {} s0 v1 = v0; return v1; """); - code.parse().opto(); + code.parse().iter(); assertEquals("return (const)s0;", code.print()); } @@ -437,7 +437,7 @@ while(0) {} } } } """); - code.parse().opto(); + code.parse().iter(); assertEquals("return 0;", code.print()); } @@ -448,7 +448,7 @@ int v0=arg==0; while(v0) continue; return 0; """); - code.parse().opto(); + code.parse().iter(); assertEquals("return 0;", code.print()); } @@ -462,7 +462,7 @@ return 0; a.y = 55; b.y = 66; a.x = 33; b.x = 44; return before*100 + p.x; - """).parse().opto(); + """).parse().iter(); StopNode stop = code._stop; assertEquals("1133",Eval2.eval(code,0)); assertEquals("2244",Eval2.eval(code,1)); @@ -488,7 +488,7 @@ return 0; """; @Test public void testMemoryAcrossNestedLoops() { - var code = new CodeGen(NESTED_MEMORY).parse().opto(); + var code = new CodeGen(NESTED_MEMORY).parse().iter(); 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))+ @@ -504,7 +504,7 @@ return 0; if (arg) { s.x = 11; s.z = 13; return s; } s.y = 17; return s; - """).parse().opto(); + """).parse().iter(); 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)); @@ -521,7 +521,7 @@ return 0; int v; if (arg>1) v=p.x; else v=q.x; return v; - """).parse().opto(); + """).parse().iter(); StopNode stop = code._stop; // The one-step safety check stops at the memory aggregate. assertEquals(2,countMemoryNodes(stop,LoadNode.class,new BitSet())); @@ -536,7 +536,7 @@ return 0; !S !s = new S; if (arg) s.x=arg+1; else s.x=arg+2; return s; - """).parse().opto(); + """).parse().iter(); StopNode stop = code._stop; assertEquals(1,countMemoryNodes(stop,StoreNode.class,new BitSet())); assertEquals("S{x=2}",Eval2.eval(code,0)); @@ -554,7 +554,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(); StopNode stop = code._stop; assertEquals(2,countMemoryNodes(stop,LoadNode.class,new BitSet())); assertEquals("-1",Eval2.eval(code,-1)); diff --git a/chapter21/src/test/java/com/seaofnodes/simple/Chapter11Test.java b/chapter21/src/test/java/com/seaofnodes/simple/Chapter11Test.java index 439333ca..a74f8540 100644 --- a/chapter21/src/test/java/com/seaofnodes/simple/Chapter11Test.java +++ b/chapter21/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(); 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(); 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).parse(); - code.opto(); + code.iter(); assertEquals("S{x=9,y=25,z=17}",Eval2.eval(code,4)); } } diff --git a/chapter21/src/test/java/com/seaofnodes/simple/Chapter12Test.java b/chapter21/src/test/java/com/seaofnodes/simple/Chapter12Test.java index 0b4ad8ec..324b2a12 100644 --- a/chapter21/src/test/java/com/seaofnodes/simple/Chapter12Test.java +++ b/chapter21/src/test/java/com/seaofnodes/simple/Chapter12Test.java @@ -14,7 +14,7 @@ public class Chapter12Test { """ return 3.14; """); - code.parse().opto(); + code.parse().iter(); 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.parse().iter().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.i; """); - code.parse().opto(); + code.parse().iter(); assertEquals("return Phi(Region,0,1,.i);", 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(); 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(); 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(); 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(); fail(); } + try { code.parse().iter(); 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(); + code.parse().iter(); assertEquals("3",Eval2.eval(code,0)); } @Test public void testNullRef4() { CodeGen code = new CodeGen("-null-5/null-5;"); - try { code.parse().opto().typeCheck(); fail(); } + try { code.parse().iter().typeCheck(); fail(); } catch( Exception e ) { assertEquals("Cannot 'Add' null",e.getMessage()); } } @Test public void testNullRef5() { CodeGen code = new CodeGen("return null+42;"); - try { code.parse().opto().typeCheck(); fail(); } + try { code.parse().iter().typeCheck(); fail(); } catch( Exception e ) { assertEquals("Cannot 'Add' null",e.getMessage()); } } @@ -149,7 +149,7 @@ return n.i; """ struct S{}; """); - code.parse().opto(); + code.parse().iter(); assertEquals("return 0;", code.print()); assertEquals("0", Eval2.eval(code, 0)); } @@ -161,7 +161,7 @@ struct S{}; struct S1 { !S2? !s; }; return new S2; """); - try { code.parse().opto(); fail(); } + try { code.parse().iter(); fail(); } catch( Exception e ) { assertEquals("Unknown struct type 'S2'",e.getMessage()); } } @@ -173,7 +173,7 @@ struct S1 { !S2? !s; }; struct S2 { int x; }; return new S1.s=new S2; """); - code.parse().opto(); + code.parse().iter(); assertEquals("return S2;", code.print()); } @@ -190,7 +190,7 @@ p2.pi.i = 2; if (arg) p1 = new P; return p1.pi.i + 1; """); - try { code.parse().opto().typeCheck(); fail(); } + try { code.parse().iter().typeCheck(); fail(); } catch( Exception e ) { assertEquals("Might be null accessing 'i'",e.getMessage()); } } @@ -255,7 +255,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{a=Y{a=J{a=U{a=F{a=Q{a=B{a=M{a=X{a=I{a=T{a=E{a=P{a=A{a=L{a=W{a=H{a=S{a=D{a=O{a=Z{a=K{a=V{a=G{a=$cyclic,b=$cyclic,c=$cyclic},b=$cyclic,c=$cyclic},b=$cyclic,c=$cyclic},b=$cyclic,c=$cyclic},b=$cyclic,c=$cyclic},b=$cyclic,c=$cyclic},b=$cyclic,c=$cyclic},b=$cyclic,c=$cyclic},b=$cyclic,c=$cyclic},b=$cyclic,c=$cyclic},b=$cyclic,c=$cyclic},b=$cyclic,c=$cyclic},b=$cyclic,c=$cyclic},b=$cyclic,c=$cyclic},b=$cyclic,c=$cyclic},b=$cyclic,c=$cyclic},b=$cyclic,c=$cyclic},b=$cyclic,c=$cyclic},b=$cyclic,c=$cyclic},b=$cyclic,c=$cyclic},b=$cyclic,c=$cyclic},b=$cyclic,c=$cyclic},b=$cyclic,c=$cyclic},b=$cyclic,c=$cyclic},b=$cyclic,c=$cyclic},b=$cyclic,c=$cyclic}", Eval2.eval(code, 0)); } diff --git a/chapter21/src/test/java/com/seaofnodes/simple/Chapter13Test.java b/chapter21/src/test/java/com/seaofnodes/simple/Chapter13Test.java index 66e12e42..4e56b9de 100644 --- a/chapter21/src/test/java/com/seaofnodes/simple/Chapter13Test.java +++ b/chapter21/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(); 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(); 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(); assertEquals("return Phi(Region,.f,0);", code.print()); } @@ -386,7 +389,7 @@ if (v1) { } return v0; """); - code.parse().opto(); + code.parse().iter(); 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(); assertEquals("return arg;", code.print()); } @@ -421,7 +424,7 @@ while(1) { } return v; """); - code.parse().opto(); + code.parse().iter(); assertEquals("return S;", code.print()); } @@ -436,7 +439,7 @@ while( -arg ) while(1) arg = arg+ptr.v; """); - code.parse().opto(); + code.parse().iter(); assertEquals("return Top;", code.print()); } @@ -454,7 +457,7 @@ while (arg) { } return i; """); - code.parse().opto(); + code.parse().iter(); assertEquals("return 0;", code.print()); } @@ -474,7 +477,7 @@ while(arg) { } return arg; """); - code.parse().opto(); + code.parse().iter(); assertEquals("return 0;", code.print()); } @@ -492,7 +495,7 @@ if (arg) { } return v; """); - code.parse().opto(); + code.parse().iter(); assertEquals("return S;", code.print()); } @@ -511,7 +514,7 @@ while (arg > 0) { } return v; """); - code.parse().opto(); + code.parse().iter(); //assertEquals("return new S;", code.print()); } @@ -528,7 +531,7 @@ while(0>=0) { } return 0; """); - code.parse().opto(); + code.parse().iter(); assertEquals("return Top;", code.print()); } @@ -546,7 +549,7 @@ u32 v0=0; return v1; } """); - code.parse().opto(); + code.parse().iter(); assertEquals("return 0;", code.print()); } diff --git a/chapter21/src/test/java/com/seaofnodes/simple/Chapter14FloatTest.java b/chapter21/src/test/java/com/seaofnodes/simple/Chapter14FloatTest.java index 6377bc14..cf7d3481 100644 --- a/chapter21/src/test/java/com/seaofnodes/simple/Chapter14FloatTest.java +++ b/chapter21/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]).parse().iter().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;").parse().iter().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).parse().iter().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(); 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(); 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(); 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(); assertEquals("return ((flt)arg==(ToFloat+1.0f));", code.print()); assertEquals("0", Eval2.eval(code, 1)); } diff --git a/chapter21/src/test/java/com/seaofnodes/simple/Chapter14Test.java b/chapter21/src/test/java/com/seaofnodes/simple/Chapter14Test.java index f0fe7dcd..ebc94d21 100644 --- a/chapter21/src/test/java/com/seaofnodes/simple/Chapter14Test.java +++ b/chapter21/src/test/java/com/seaofnodes/simple/Chapter14Test.java @@ -16,7 +16,7 @@ public class Chapter14Test { """ return 3.14; """); - code.parse().opto(); + code.parse().iter(); 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(); 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(); 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(); 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(); 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(); 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(); 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(); 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(); 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(); 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(); 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.parse().iter().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(); assertEquals("return (Phi(Loop,((1<<arg)&1),0)&Phi(Loop,Shl,4294967295));", code.print()); assertEquals("1", Eval2.eval(code, 0)); } @@ -194,7 +194,7 @@ if(0&0>>>0) { } return v0; """); - code.parse().opto(); + code.parse().iter(); 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(); assertEquals("return 0;", code.print()); assertEquals("0", Eval2.eval(code, 0)); } diff --git a/chapter21/src/test/java/com/seaofnodes/simple/Chapter15Test.java b/chapter21/src/test/java/com/seaofnodes/simple/Chapter15Test.java index cb92277f..fbbb6c9d 100644 --- a/chapter21/src/test/java/com/seaofnodes/simple/Chapter15Test.java +++ b/chapter21/src/test/java/com/seaofnodes/simple/Chapter15Test.java @@ -17,7 +17,7 @@ public class Chapter15Test { """ return 3.14; """); - code.parse().opto(); + code.parse().iter(); 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(); 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(); 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(); 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(); 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(); 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(); assertEquals("return [*A?];", code.print()); assertEquals("*A {int !i; }?[ null,null]", Eval2.eval(code, 0)); } @@ -131,7 +131,7 @@ else { } return rez; """); - code.parse().opto(); + code.parse().iter(); 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.parse().iter().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(); assertEquals("return Tree;", code.print()); assertEquals("Tree{_kids=*Tree?[ 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(); 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(); 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(); 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(); 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(); fail(); } catch( Exception e ) { assertEquals("Cannot allocate a flt",e.getMessage()); } } @@ -257,7 +257,7 @@ return new flt; """ int is = new int[2]; """); - try { code.parse().opto(); fail(); } + try { code.parse().iter(); fail(); } catch( Exception e ) { assertEquals("Type *[int] is not of declared type int",e.getMessage()); } } @@ -268,7 +268,7 @@ int is = new int[2]; int[] is = new int[3.14]; return is[1]; """); - try { code.parse().opto(); fail(); } + try { code.parse().iter(); fail(); } catch( Exception e ) { assertEquals("Cannot allocate an array with length 3.14",e.getMessage()); } } @@ -278,7 +278,7 @@ return is[1]; int[] is = new int[arg]; return is[1]; """); - code.parse().opto(); + code.parse().iter(); assertEquals("return 0;", code.print()); assertEquals("0", Eval2.eval(code, 4)); try { Eval2.eval(code,-1); fail(); } @@ -311,7 +311,7 @@ while(v5+(0&0)) { } return v1; """); - code.parse().opto(); + code.parse().iter(); assertEquals("return 0;", code.print()); assertEquals("0", Eval2.eval(code, 0)); } @@ -326,7 +326,7 @@ u32 v7=0; int v8=0; while(0<--1>>>---(v7*0==v8)) {} """); - code.parse().opto(); + code.parse().iter(); assertEquals("return 0;", code.print()); } @@ -350,7 +350,7 @@ else { } } """); - code.parse().opto(); + code.parse().iter(); assertEquals("return 0;", code.print()); } } diff --git a/chapter21/src/test/java/com/seaofnodes/simple/Chapter16Test.java b/chapter21/src/test/java/com/seaofnodes/simple/Chapter16Test.java index 362388d6..78e468cd 100644 --- a/chapter21/src/test/java/com/seaofnodes/simple/Chapter16Test.java +++ b/chapter21/src/test/java/com/seaofnodes/simple/Chapter16Test.java @@ -17,7 +17,7 @@ public class Chapter16Test { """ return 3.14; """); - code.parse().opto(); + code.parse().iter(); assertEquals("return 3.14;", code.print()); assertEquals("3.14", Eval2.eval(code, 0)); } @@ -30,7 +30,7 @@ return 3.14; int x, y; return x+y; """); - code.parse().opto(); + code.parse().iter(); assertEquals("return 0;", code.print()); assertEquals("0", Eval2.eval(code, 0)); } @@ -41,7 +41,7 @@ return x+y; int x=2, y=x+1; return x+y; """); - code.parse().opto(); + code.parse().iter(); assertEquals("return 5;", code.print()); assertEquals("5", Eval2.eval(code, 0)); } @@ -54,7 +54,7 @@ struct X { int x=3; }; X z = new X; return z.x; """); - code.parse().opto(); + code.parse().iter(); assertEquals("return 3;", code.print()); assertEquals("3", Eval2.eval(code, 0)); } @@ -66,7 +66,7 @@ struct X { int x=3; }; X z = new X { x = 4; }; return z.x; """); - code.parse().opto(); + code.parse().iter(); assertEquals("return 4;", code.print()); assertEquals("4", Eval2.eval(code, 0)); } @@ -87,7 +87,7 @@ LLI? next = head.next; if( !next ) return 1; return next.i; """); - code.parse().opto(); + code.parse().iter(); assertEquals("return Phi(Region,0,1,.i);", code.print()); assertEquals("0", Eval2.eval(code, 0)); assertEquals("1", Eval2.eval(code, 1)); @@ -118,7 +118,7 @@ LLI? next = head.next; if( !next ) return 1; return next.i; """); - code.parse().opto(); + code.parse().iter(); assertEquals("return Phi(Region,0,1,.i);", code.print()); assertEquals("0", Eval2.eval(code, 0)); assertEquals("1", Eval2.eval(code, 1)); @@ -143,7 +143,7 @@ struct Square { }; return new Square; """); - code.parse().opto(); + code.parse().iter(); 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)); @@ -167,7 +167,7 @@ return new Square; """; @Test public void testConstructorMemory() { - var code = new CodeGen(CONSTRUCTOR_MEMORY).parse().opto(); + var code = new CodeGen(CONSTRUCTOR_MEMORY).parse().iter(); assertEquals("111249",Eval2.eval(code,0)); assertEquals("222352",Eval2.eval(code,1)); } diff --git a/chapter21/src/test/java/com/seaofnodes/simple/Chapter17aTest.java b/chapter21/src/test/java/com/seaofnodes/simple/Chapter17aTest.java index 16ffe967..4a69c33d 100644 --- a/chapter21/src/test/java/com/seaofnodes/simple/Chapter17aTest.java +++ b/chapter21/src/test/java/com/seaofnodes/simple/Chapter17aTest.java @@ -17,7 +17,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(); assertEquals("return Phi(Region,9,3);", code.print()); assertEquals("3", Eval2.eval(code, 0)); assertEquals("9", Eval2.eval(code, 1)); @@ -30,7 +30,7 @@ struct X { int ~x; }; X z = new X { x=3; }; return z.x; """); - code.parse().opto(); + code.parse().iter(); assertEquals("return 3;", code.print()); assertEquals("3", Eval2.eval(code, 0)); } @@ -42,7 +42,7 @@ struct Point { int ~x, ~y; }; Point p = new Point { x=3; y=4; }; return p; """); - code.parse().opto(); + code.parse().iter(); assertEquals("return (const)Point;", code.print()); assertEquals("Point{x=3,y=4}", Eval2.eval(code, 0)); } @@ -55,7 +55,7 @@ Point p = new Point { x=5; y=6; }; p.x++; return p; """); - try { code.parse().opto().typeCheck(); fail(); } + try { code.parse().iter().typeCheck(); fail(); } catch( Exception e ) { assertEquals("Cannot modify final field 'x'",e.getMessage()); } } @@ -67,7 +67,7 @@ Point p = new Point; p.x++; return p; """); - try { code.parse().opto().typeCheck(); fail(); } + try { code.parse().iter().typeCheck(); fail(); } catch( Exception e ) { assertEquals("Cannot modify final field 'x'",e.getMessage()); } } @@ -75,7 +75,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(); fail(fields); } catch( Exception e ) { assertEquals("'Point' is not fully initialized, field 'x' needs to be set in a constructor",e.getMessage()); } } } @@ -88,7 +88,7 @@ Point p = new Point; p.x++; return p; """); - try { code.parse().opto(); fail(); } + try { code.parse().iter(); fail(); } catch( Exception e ) { assertEquals("Cannot reassign final 'x'",e.getMessage()); } } @@ -100,7 +100,7 @@ struct Point { var x=3; var y=4; }; p.x++; return p; """); - code.parse().opto(); + code.parse().iter(); assertEquals("return Point;", code.print()); assertEquals("Point{x=4,y=4}", Eval2.eval(code, 0)); } diff --git a/chapter21/src/test/java/com/seaofnodes/simple/Chapter17bTest.java b/chapter21/src/test/java/com/seaofnodes/simple/Chapter17bTest.java index e8f6e0bd..8ea72c21 100644 --- a/chapter21/src/test/java/com/seaofnodes/simple/Chapter17bTest.java +++ b/chapter21/src/test/java/com/seaofnodes/simple/Chapter17bTest.java @@ -15,7 +15,7 @@ public class Chapter17bTest { """ return 1; """); - code.parse().opto().typeCheck(); + code.parse().iter().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(); 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(); 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(); 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(); 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(); 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(); 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(); 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(); 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(); 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(); 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(); + code.parse().iter(); 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(); 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(); 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(); 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(); 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(); 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(); 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.parse().iter().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.parse().iter().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(); 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(); 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.parse().iter().typeCheck(); fail(); } catch( Exception e ) { assertEquals("Cannot modify final field 'x'",e.getMessage()); } } @@ -217,7 +217,7 @@ foo.bar.x++; // Ok foo and foo.bar and foo.bar.x are all mutable ~Foo xfoo = foo; // Throw away mutability xfoo.bar.x++; // Error, cannot mutate through xfoo """); - try { code.parse().opto().typeCheck(); fail(); } + try { code.parse().iter().typeCheck(); fail(); } catch( Exception e ) { assertEquals("Cannot modify final field 'x'",e.getMessage()); } } @@ -238,7 +238,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(); assertEquals("return 45;", code.print()); assertEquals("45", Eval2.eval(code, 0)); } @@ -248,7 +248,7 @@ return x4*10+x5; CodeGen code = new CodeGen(""" int i,i++; """); - try { code.parse().opto().typeCheck(); fail(); } + try { code.parse().iter().typeCheck(); fail(); } catch( Exception e ) { assertEquals("Redefining name 'i'",e.getMessage()); } } @@ -263,7 +263,7 @@ A x = new A { b = new B; }; """); - try { code.parse().opto(); fail(); } + try { code.parse().iter(); fail(); } catch( Exception e ) { assertEquals("Cannot read uninitialized field 'b'",e.getMessage()); } } @@ -276,7 +276,7 @@ return new A { if (arg) b = new B; // Constructor ends with partial init of b }.b; """); - try { code.parse().opto(); fail(); } + try { code.parse().iter(); fail(); } catch( Exception e ) { assertEquals("'A' is not fully initialized, field 'b' needs to be set in a constructor",e.getMessage()); } } @@ -290,7 +290,7 @@ val s = new S{x = 2;}; return x; """ ); - try { code.parse().opto().typeCheck(); fail(); } + try { code.parse().iter().typeCheck(); fail(); } catch( Exception e ) { assertEquals("Cannot reassign final 'x'",e.getMessage()); } } @@ -309,7 +309,7 @@ focus(me); return me; """ ); - try { code.parse().opto().typeCheck(); fail(); } + try { code.parse().iter().typeCheck(); fail(); } catch( Exception e ) { assertEquals("Syntax error, expected =expression: ;",e.getMessage()); } } @@ -319,7 +319,7 @@ return me; CodeGen code = new CodeGen(""" return arg ? 1 : 2; """); - code.parse().opto(); + code.parse().iter(); assertEquals("return Phi(Region,1,2);", code.print()); assertEquals("2", Eval2.eval(code, 0)); assertEquals("1", Eval2.eval(code, 1)); @@ -330,7 +330,7 @@ return arg ? 1 : 2; CodeGen code = new CodeGen(""" return arg ? 0 : arg; """); - code.parse().opto(); + code.parse().iter(); assertEquals("return 0;", code.print()); assertEquals("0", Eval2.eval(code, 0)); } @@ -342,7 +342,7 @@ struct Bar { int x; }; var b = arg ? new Bar : null; return b ? b.x++ + b.x++ : -1; """); - code.parse().opto(); + code.parse().iter(); assertEquals("return Phi(Region,((.x<<1)+1),-1);", code.print()); assertEquals("-1", Eval2.eval(code, 0)); assertEquals("1", Eval2.eval(code, 1)); @@ -355,7 +355,7 @@ struct Bar { int x; }; var b = arg ? new Bar; return b ? b.x++ + b.x++ : -1; """); - code.parse().opto(); + code.parse().iter(); assertEquals("return Phi(Region,((.x<<1)+1),-1);", code.print()); assertEquals("-1", Eval2.eval(code, 0)); assertEquals("1", Eval2.eval(code, 1)); @@ -369,7 +369,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(); assertEquals("return Phi(Region,.x,0,.x);", code.print()); assertEquals("0", Eval2.eval(code, 0)); assertEquals("1", Eval2.eval(code, 1)); @@ -382,7 +382,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(); assertEquals("return Phi(Region,1.0f,1.2);", code.print()); assertEquals("1.2", Eval2.eval(code, 0)); } @@ -394,7 +394,7 @@ return f; // missing widening struct S{}; return arg ? 7 : new S; """); - try { code.parse().opto().typeCheck(); fail(); } + try { code.parse().iter().typeCheck(); fail(); } catch( Exception e ) { assertEquals("No common type amongst int and reference",e.getMessage()); } } @@ -407,7 +407,7 @@ for( int i=0; i<arg; i++ ) sum += i; return sum; """); - code.parse().opto(); + code.parse().iter(); 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)); @@ -420,7 +420,7 @@ for( ; i<arg; i++ ) sum += i; return sum; """); - code.parse().opto(); + code.parse().iter(); 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)); @@ -435,7 +435,7 @@ for( int i=0; ; i++ ) { } return sum; """); - code.parse().opto(); + code.parse().iter(); 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)); @@ -448,7 +448,7 @@ for( int i=0; i<arg; ) sum += i++; return sum; """); - code.parse().opto(); + code.parse().iter(); 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)); @@ -461,7 +461,7 @@ for( int i=0; i<arg; i++ ) sum += i; return i; """); - try { code.parse().opto(); fail(); } + try { code.parse().iter(); fail(); } catch( Exception e ) { assertEquals("Undefined name 'i'",e.getMessage()); } } @Test @@ -469,7 +469,7 @@ return i; CodeGen code = new CodeGen(""" for(;;arg++;) {} """); - try { code.parse().opto(); fail(); } + try { code.parse().iter(); fail(); } catch( Exception e ) { assertEquals("Syntax error, expected Unexpected code after expression: ;",e.getMessage()); } } @@ -485,7 +485,7 @@ struct A{ }; return new A; """); - code.parse().opto(); + code.parse().iter(); assertEquals("return A;", code.print()); assertEquals("A{f1=null,f2=null}", Eval2.eval(code,0)); } @@ -499,7 +499,7 @@ struct A{ }; return new A.not_array_of_b; """); - code.parse().opto(); + code.parse().iter(); assertEquals("return [*B?];", code.print()); assertEquals("*B?[]", Eval2.eval(code,0)); } @@ -518,7 +518,7 @@ for( ; ptr; ptr = ptr.next ) sum += ptr.i; return sum; """); - code.parse().opto(); + code.parse().iter(); assertEquals("return Phi(Loop,0,(Phi_sum+.i));", code.print()); assertEquals("45", Eval2.eval(code, 10)); } @@ -549,7 +549,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 [int];", code.print()); assertEquals("int[ 2,3,5,7,11,13,17,19]",Eval2.eval(code, 20)); } diff --git a/chapter21/src/test/java/com/seaofnodes/simple/Chapter18Test.java b/chapter21/src/test/java/com/seaofnodes/simple/Chapter18Test.java index 7c0af028..6282f26c 100644 --- a/chapter21/src/test/java/com/seaofnodes/simple/Chapter18Test.java +++ b/chapter21/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]).parse().iter().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().GCM(); + code.driver(CodeGen.Phase.Schedule); 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(); 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(); assertEquals("return (Parm_x(sq,int)*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(); 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(); 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(); assertEquals("Stop[ return #2; return (Parm_x($fun1,int,3)*x); return (Parm_x($fun2,int,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.parse().iter().typeCheck(); assertEquals("Stop[ return #2; return Phi(Region,1,(Parm_x(fact,int,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(); fail(); } catch( Exception e ) { assertEquals("No active loop for a break or continue",e.getMessage()); } } @@ -357,7 +357,7 @@ for(;;) { i2i = null; } """); - try { code.parse().opto().typeCheck(); fail(); } + try { code.parse().iter().typeCheck(); fail(); } catch( Exception e ) { assertEquals("Might be null calling { int -> int #1}?",e.getMessage()); } } @@ -369,7 +369,7 @@ for(;;) { val f = { int i, int j -> return i+j; }; return f(); """); - try { code.parse().opto().typeCheck(); fail(); } + try { code.parse().iter().typeCheck(); fail(); } catch( Exception e ) { assertEquals("Expecting 2 arguments, but found 0",e.getMessage()); } } @@ -387,7 +387,7 @@ for(;;) { if (s) return s.x; } """); - try { code.parse().opto().typeCheck(); fail(); } + try { code.parse().iter().typeCheck(); fail(); } catch( Exception e ) { assertEquals("Accessing unknown field 'x' from '*S'",e.getMessage()); } } @@ -400,7 +400,7 @@ val g = { -> }; return 0; """); - try { code.parse().opto().typeCheck(); fail(); } + try { code.parse().iter().typeCheck(); fail(); } catch( Exception e ) { assertEquals("No defined return type",e.getMessage()); } } @@ -414,7 +414,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(); 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)); @@ -436,7 +436,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)); } @@ -488,7 +488,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(); 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. @@ -517,7 +517,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(); for(int n=0; n<7; n++) assertEquals(Long.toString((10L*(n+1)+n*(n+1)/2)*100+10+n),Eval2.eval(code,n)); } @@ -535,7 +535,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(); 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/chapter21/src/test/java/com/seaofnodes/simple/Chapter19Test.java b/chapter21/src/test/java/com/seaofnodes/simple/Chapter19Test.java index c53a8e11..2027dbd6 100644 --- a/chapter21/src/test/java/com/seaofnodes/simple/Chapter19Test.java +++ b/chapter21/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.parse().iter().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,._hashCode,Phi(Region,123456789,Phi(Loop,0,(.[]+((Phi_hash<<5)-Phi_hash))))); return Phi(Region,1,0,0,1); ]", code._stop.toString()); //assertEquals("-4898613127354160978", Eval2.eval(code, 2)); } @@ -357,11 +357,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).parse().iter().typeCheck(); var aliases = memoryPhis(code._stop); - code.loopTree().instSelect(cpu,"SystemV"); + code.loopTree().driver(CodeGen.Phase.InstSelect,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); @@ -413,7 +413,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/chapter21/src/test/java/com/seaofnodes/simple/Chapter20Test.java b/chapter21/src/test/java/com/seaofnodes/simple/Chapter20Test.java index e63fb32e..93d8caae 100644 --- a/chapter21/src/test/java/com/seaofnodes/simple/Chapter20Test.java +++ b/chapter21/src/test/java/com/seaofnodes/simple/Chapter20Test.java @@ -9,6 +9,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() { @@ -69,7 +73,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).parse().opto().typeCheck(); + CodeGen code = new CodeGen(src,com.seaofnodes.simple.type.TypeInteger.BOT,seed).parse().iter().typeCheck(); assertEquals("seed "+seed, "123", Eval2.eval(code,0)); } } @@ -93,7 +97,7 @@ return f(s); @Test public void testJig() { CodeGen code = new CodeGen("return 0;"); - code.parse().opto().typeCheck(); + code.parse().iter().typeCheck(); assertEquals("return 0;", code._stop.toString()); assertEquals("0", Eval2.eval(code, 2)); } @@ -339,7 +343,7 @@ for( int pc = 0; pc < program#; pc++ ) { return output; """; testTarget(src,"x86_64_v2", "SystemV",40,null); - testTarget(src,"riscv" , "SystemV",146,null); + testTarget(src,"riscv" , "SystemV",42,null); testTarget(src,"arm" , "SystemV",34,null); //assertEquals("Hello World!\n", Eval2.eval(code, 0, 10000)); } @@ -407,8 +411,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/chapter21/src/test/java/com/seaofnodes/simple/Chapter21Test.java b/chapter21/src/test/java/com/seaofnodes/simple/Chapter21Test.java index a51ae3bc..b19d1bb5 100644 --- a/chapter21/src/test/java/com/seaofnodes/simple/Chapter21Test.java +++ b/chapter21/src/test/java/com/seaofnodes/simple/Chapter21Test.java @@ -27,7 +27,7 @@ public class Chapter21Test { else if(i==4) b.x=40; } return sum; - """).parse().opto(); + """).parse().iter(); // 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/chapter21/src/test/java/com/seaofnodes/simple/Compile.java b/chapter21/src/test/java/com/seaofnodes/simple/Compile.java index 088055f9..f3ca1905 100644 --- a/chapter21/src/test/java/com/seaofnodes/simple/Compile.java +++ b/chapter21/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/chapter21/src/test/java/com/seaofnodes/simple/CompoundAssignmentTest.java b/chapter21/src/test/java/com/seaofnodes/simple/CompoundAssignmentTest.java index 48f739cf..8131c95f 100644 --- a/chapter21/src/test/java/com/seaofnodes/simple/CompoundAssignmentTest.java +++ b/chapter21/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).parse().iter().typeCheck(); assertEquals(src, Long.toString(expected), Eval2.eval(code, arg)); } } diff --git a/chapter21/src/test/java/com/seaofnodes/simple/Eval2.java b/chapter21/src/test/java/com/seaofnodes/simple/Eval2.java index a855350e..f39750c2 100644 --- a/chapter21/src/test/java/com/seaofnodes/simple/Eval2.java +++ b/chapter21/src/test/java/com/seaofnodes/simple/Eval2.java @@ -116,10 +116,7 @@ public abstract class Eval2 { public static String eval( CodeGen code, long arg, int timeout ) { SB trace = null; // new SB(); // TRACE, set to null for off, new SB() for on // Force local scheduling phase - if( code._phase.ordinal() < CodeGen.Phase.TypeCheck .ordinal() ) code.typeCheck(); - if( code._phase.ordinal() < CodeGen.Phase.LoopTree .ordinal() ) code.loopTree(); - if( code._phase.ordinal() < CodeGen.Phase.Schedule .ordinal() ) code.GCM(); - if( code._phase.ordinal() < CodeGen.Phase.LocalSched.ordinal() ) code.localSched(); + code.driver(CodeGen.Phase.LocalSched); // Set global, so don't have to pass everywhere CODE = code; diff --git a/chapter21/src/test/java/com/seaofnodes/simple/Main.java b/chapter21/src/test/java/com/seaofnodes/simple/Main.java index 589c043b..ca1d0b5b 100644 --- a/chapter21/src/test/java/com/seaofnodes/simple/Main.java +++ b/chapter21/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/chapter21/src/test/java/com/seaofnodes/simple/MemoryEncodingTest.java b/chapter21/src/test/java/com/seaofnodes/simple/MemoryEncodingTest.java index 1ce2cd34..7cdf217b 100644 --- a/chapter21/src/test/java/com/seaofnodes/simple/MemoryEncodingTest.java +++ b/chapter21/src/test/java/com/seaofnodes/simple/MemoryEncodingTest.java @@ -65,7 +65,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(); if( p==0 ) assertNull(code._stop.walk(n -> n instanceof LoadNode ld && ld.ptr() instanceof ProjNode ptr && ptr.in(0) instanceof NewNode nn && @@ -158,7 +158,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/chapter21/src/test/java/com/seaofnodes/simple/MutabilityTest.java b/chapter21/src/test/java/com/seaofnodes/simple/MutabilityTest.java index 7ae80314..baf4e252 100644 --- a/chapter21/src/test/java/com/seaofnodes/simple/MutabilityTest.java +++ b/chapter21/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).parse().iter().typeCheck(); assertEquals(result,Eval2.eval(code,0)); } private static void bad(String src) { try { - new CodeGen(src).parse().opto().typeCheck(); + new CodeGen(src).parse().iter().typeCheck(); } catch( RuntimeException expected ) { String msg = expected.getMessage(); assertTrue("Expected a permission error, got: "+expected, diff --git a/chapter21/src/test/java/com/seaofnodes/simple/PhaseTest.java b/chapter21/src/test/java/com/seaofnodes/simple/PhaseTest.java new file mode 100644 index 00000000..d890a537 --- /dev/null +++ b/chapter21/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 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.InstSelect,"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/chapter21/src/test/java/com/seaofnodes/simple/SchedulerTest.java b/chapter21/src/test/java/com/seaofnodes/simple/SchedulerTest.java index 3b19857a..a388d8c3 100644 --- a/chapter21/src/test/java/com/seaofnodes/simple/SchedulerTest.java +++ b/chapter21/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(); 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(); 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(); var eval = new Evaluator(code._stop); assertEquals(2L, eval.evaluate(0, 10)); assertEquals(2L, eval.evaluate(1, 10)); diff --git a/chapter21/src/test/java/com/seaofnodes/simple/Simple.java b/chapter21/src/test/java/com/seaofnodes/simple/Simple.java index 705b086a..c496ea90 100644 --- a/chapter21/src/test/java/com/seaofnodes/simple/Simple.java +++ b/chapter21/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 java.nio.file.Files; @@ -13,20 +14,20 @@ 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_INSTR_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_TYPE_CHECK = 1<<Phase.TypeCheck.ordinal(); + static final int DUMP_AFTER_LOOP_TREE = 1<<Phase.LoopTree.ordinal(); + static final int DUMP_AFTER_INSTR_SELECT = 1<<Phase.InstSelect.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; @@ -39,15 +40,16 @@ public class Simple { simple <input-file> [options] [--eval|--run ...] 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-instr-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-type-check - dump intermediate representation after type checking + --dump-after-loop-tree - dump intermediate representation after loop-tree construction + --dump-after-instr-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 @@ -80,50 +82,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_INSTR_SELECT -> "After Instruction 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 Instruction 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.println(String.format("Parsing Time: %.3f sec", t)); - total += t = code._tOpto / 1e3; - System.out.println(String.format("Optimization Time: %.3f sec", t)); - total += t = code._tTypeCheck / 1e3; - System.out.println(String.format("Type Checking Time: %.3f sec", t)); - total += t = code._tLoopTree / 1e3; - System.out.println(String.format("Loop Tree Time: %.3f sec", t)); - total += t = code._tInsSel / 1e3; - System.out.println(String.format("Instruction Selection Time: %.3f sec", t)); - total += t = code._tGCM / 1e3; - System.out.println(String.format("GCM Time: %.3f sec", t)); - total += t = code._tLocal / 1e3; - System.out.println(String.format("Local Scheduling Time: %.3f sec", t)); - total += t = code._tRegAlloc / 1e3; - System.out.println(String.format("Register Allocation Time: %.3f sec", t)); - total += t = code._tEncode / 1e3; - System.out.println(String.format("Instruction Encoding Time: %.3f sec", t)); - System.out.println(String.format("TOTAL COMPILATION TIME: %.3f sec", 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 { @@ -157,16 +128,16 @@ loop: for (int i = 0; i < args.length; i++) { switch (arg) { case "-": use_stdin = true; 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-instr-select": dump |= DUMP_AFTER_INSTR_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-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-instr-select": dump |= DUMP_AFTER_INSTR_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; first_arg = i + 1; break loop; case "--run": do_run = true; first_arg = i + 1; break loop; @@ -221,36 +192,8 @@ loop: for (int i = 0; i < args.length; i++) { // 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(PORTS, cpu, abi); - dump(code, dump, DUMP_AFTER_INSTR_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.driver(do_codegen ? Phase.Encoding : Phase.LocalSched, + do_codegen ? cpu : null, abi, dump); dump(code, dump, DUMP_FINAL); diff --git a/chapter21/src/test/java/com/seaofnodes/simple/codegen/FlagSpillTestSupport.java b/chapter21/src/test/java/com/seaofnodes/simple/codegen/FlagSpillTestSupport.java new file mode 100644 index 00000000..7054ade4 --- /dev/null +++ b/chapter21/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,(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/chapter21/src/test/java/com/seaofnodes/simple/codegen/RegAllocTestSupport.java b/chapter21/src/test/java/com/seaofnodes/simple/codegen/RegAllocTestSupport.java index 739eba3b..06ed40d9 100644 --- a/chapter21/src/test/java/com/seaofnodes/simple/codegen/RegAllocTestSupport.java +++ b/chapter21/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); @@ -168,11 +173,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); @@ -186,7 +191,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)); } @@ -199,7 +204,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); @@ -222,7 +227,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/chapter21/src/test/java/com/seaofnodes/simple/fuzzer/Fuzzer.java b/chapter21/src/test/java/com/seaofnodes/simple/fuzzer/Fuzzer.java index 586924b2..7e8bdbf1 100644 --- a/chapter21/src/test/java/com/seaofnodes/simple/fuzzer/Fuzzer.java +++ b/chapter21/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(); int iter_peeps= code._iter_cnt; int iter_nops = code._iter_nop_cnt; double iter_nop_ratio = (double)iter_nops/iter_peeps; |
