From f4bd723d929e53475f7990374dca7b7dfcbbdc42 Mon Sep 17 00:00:00 2001 From: Cliff Click Date: Sun, 1 Nov 2026 10:33:55 -0800 Subject: Add Chapter 29 for tech debt cleanup with the parser split Keep Chapter 28b intact and carry the grammar-oriented parser package, Var move, IterPeeps move, and parser regression tests into Chapter 29. Defer privacy and exclude its experimental tests and fixture changes. Register the chapter in the indexes, IntelliJ modules and run configurations, Maven reactor, roadmap, and linear-history publisher. Windows and Linux each pass 573 tests, release builds, 199 allocation replays, and 29 native checks. --- .../com/seaofnodes/simple/print/ASMPrinter.java | 101 +++++++++++++++++++++ .../com/seaofnodes/simple/print/IRPrinter.java | 60 ++++++++++++ .../simple/print/SimpleGraphAdapter.java | 80 ++++++++++++++++ .../simple/print/SimpleGraphObserver.java | 35 +++++++ 4 files changed, 276 insertions(+) create mode 100644 chapter29/src/main/java/com/seaofnodes/simple/print/ASMPrinter.java create mode 100644 chapter29/src/main/java/com/seaofnodes/simple/print/IRPrinter.java create mode 100644 chapter29/src/main/java/com/seaofnodes/simple/print/SimpleGraphAdapter.java create mode 100644 chapter29/src/main/java/com/seaofnodes/simple/print/SimpleGraphObserver.java (limited to 'chapter29/src/main/java/com/seaofnodes/simple/print') diff --git a/chapter29/src/main/java/com/seaofnodes/simple/print/ASMPrinter.java b/chapter29/src/main/java/com/seaofnodes/simple/print/ASMPrinter.java new file mode 100644 index 00000000..e8218afd --- /dev/null +++ b/chapter29/src/main/java/com/seaofnodes/simple/print/ASMPrinter.java @@ -0,0 +1,101 @@ +package com.seaofnodes.simple.print; + +import com.seaofnodes.print.AssemblyAdapter; +import com.seaofnodes.print.ASMPrinter.Data; +import com.seaofnodes.print.ASMPrinter.Pool; +import com.seaofnodes.simple.codegen.CodeGen; +import com.seaofnodes.simple.util.SB; +import com.seaofnodes.simple.node.*; +import com.seaofnodes.simple.type.*; +import java.util.ArrayList; +import com.seaofnodes.simple.codegen.Encoding; +import com.seaofnodes.simple.util.BAOS; +import java.util.HashMap; + +/** Machine-specific facts; traversal, columns and byte display live in print/. */ +public final class ASMPrinter extends AssemblyAdapter { + private final CodeGen _code; + private final Encoding _enc; + private ASMPrinter(CodeGen code) { + super(new IRPrinter()); + _code=code; + _enc=code._encoding; + } + public static SB print(SB sb, CodeGen code) { + return sb.p(new com.seaofnodes.print.ASMPrinter<>(new ASMPrinter(code)).print()); + } + @Override public ArrayList blocks() { + var blocks=new ArrayList(); + var cfg=_enc==null ? _code._cfg : _enc._cfg; + if( cfg!=null ) for( Node n : cfg ) blocks.add(n); + return blocks; + } + @Override public String op(Node n) { return n instanceof MachNode m ? m.op() : n.label(); } + @Override public String register(Node n) { return _code.reg(n); } + @Override public String comment(Node n) { return n.comment(); } + @Override public String phiName(Node n) { return ((PhiNode)n)._label; } + @Override public String operands(Node n) { + SB sb=new SB(); + if( n instanceof MachNode m ) m.asm(_code,sb); + else if( !(n._type instanceof TypeMem) ) { + sb.p(n._nid).p(": "); + for( Node def : n._inputs ) sb.p(def==null ? "___" : Integer.toString(def._nid)).p(' '); + } + return sb.toString(); + } + @Override public boolean labelBlock(Node n) { + return !(n instanceof FunNode) && !(n instanceof IfNode) && !(n instanceof CallNode) && + !(n instanceof CallEndNode) && !(n instanceof CProjNode && ir.input0(n) instanceof CallEndNode); + } + @Override public boolean hidden(Node n) { + if( n instanceof PhiNode || n instanceof ProjNode ) + if( n._type instanceof TypeMem || n._type instanceof TypeRPC ) return true; + if( postAlloc() && n instanceof CalleeSaveNode ) return true; + if( n instanceof MemMergeNode ) return true; + if( n instanceof EscapeNode ) return true; + return n.getClass()==ConstantNode.class; + } + @Override public boolean postAlloc() { return _code._phase.ordinal()>CodeGen.Phase.RegAlloc.ordinal() || + (_code._phase==CodeGen.Phase.RegAlloc && _code._regAlloc!=null && _code._regAlloc.done()); } + @Override public boolean encoded() { return _enc!=null && _code._phase.ordinal()>=CodeGen.Phase.Encoding.ordinal(); } + @Override public int defaultSize() { return _code._mach==null ? 2 : _code._mach.defaultOpSize(); } + @Override public boolean littleEndian() { return _code._asmLittle; } + @Override public boolean prologue(Node n) { return ((FunNode)n)._frameAdjust!=0; } + @Override public byte[] bytes() { return encoded() ? _enc._bits.buf() : null; } + @Override public int offset(Node n) { return encoded() ? _enc.opStart(n) : -1; } + @Override public int size(Node n) { return encoded() ? _enc.opLen(n)&255 : 0; } + private static ArrayList entries(Iterable relos, boolean ro) { + var data=new ArrayList(); + for( Encoding.Relo r : relos ) { + if( r.readOnly()!=ro ) continue; + int align=1< pools(int codeEnd) { + var pools=new ArrayList(); + if( !encoded() ) return pools; + int base=(codeEnd+15)&-16; + if( _enc._cpool.size()>0 ) + pools.add(new Pool("Constant Pool",_enc._cpool.buf(),0,base,objects(true))); + base=(base+_enc._cpool.size()+15)&-16; + if( _enc._sdata.size()>0 ) + pools.add(new Pool("Static Data",_enc._sdata.buf(),0,base,objects(false))); + return pools; + } + private ArrayList objects(boolean ro) { + var data=new ArrayList(); + for( var obj : _enc._data.entries() ) + if( !obj.external && obj.readOnly==ro ) + data.add(new Data(obj,obj.symbol+": "+obj.type.str(),obj.alignment,obj.size)); + return data; + } + // Retain this diagnostic entry point for checking that pool printing never lays out types. + static int printConstantPool(int address, SB sb, BAOS bits, HashMap relos, + boolean ro, String name) { + sb.p(com.seaofnodes.print.ASMPrinter.pool(new Pool(name,bits.buf(),0,address,entries(relos.values(),ro)))); + return address+bits.size(); + } +} diff --git a/chapter29/src/main/java/com/seaofnodes/simple/print/IRPrinter.java b/chapter29/src/main/java/com/seaofnodes/simple/print/IRPrinter.java new file mode 100644 index 00000000..531a549a --- /dev/null +++ b/chapter29/src/main/java/com/seaofnodes/simple/print/IRPrinter.java @@ -0,0 +1,60 @@ +package com.seaofnodes.simple.print; + +import com.seaofnodes.print.IRAdapter; +import com.seaofnodes.simple.node.*; +import java.util.ArrayList; +import com.seaofnodes.simple.util.SB; +import com.seaofnodes.simple.codegen.CodeGen; + +/** This chapter's read-only IR facts and the familiar debugger entry points. */ +public final class IRPrinter extends IRAdapter { + private static final com.seaofnodes.print.IRPrinter PRINT = + new com.seaofnodes.print.IRPrinter<>(new IRPrinter()); + @Override public boolean global(Node n) { return n.isConst(); } + @Override public String type(Node n) { return n._type==null ? "" : n._type.str(); } + @Override public String inputMark(Node n, Node def) { return n instanceof MemMergeNode && def instanceof MemMergeNode ? "^" : " "; } + @Override public Kind kind(Node n) { + if( n instanceof StartCUNode ) return Kind.UNIT; + if( n instanceof StopCUNode ) return Kind.UNIT; + if( n instanceof StartNode ) return Kind.START; + if( n instanceof StopNode ) return Kind.STOP; + if( n instanceof FunNode ) return Kind.FUN; + if( n instanceof LoopNode ) return Kind.LOOP; + if( n instanceof RegionNode ) return Kind.REGION; + if( n instanceof ParmNode ) return Kind.PARM; + if( n instanceof PhiNode ) return Kind.PHI; + if( n instanceof CallEndNode ) return Kind.CALL_END; + if( n instanceof CallNode ) return Kind.CALL; + if( n instanceof ReturnNode ) return Kind.RETURN; + if( n instanceof ConstantNode ) return Kind.CONSTANT; + if( n instanceof CProjNode ) return Kind.CPROJ; + if( n instanceof ProjNode ) return n instanceof CFGNode ? Kind.CPROJ : Kind.PROJ; + if( n instanceof CFGNode ) return Kind.CTRL; + if( n instanceof MultiNode ) return Kind.MULTI; + return Kind.DATA; + } + @Override public int index(Node n) { + if( n instanceof ProjNode p ) return p._idx; + if( n instanceof CProjNode p ) return p._idx; + return n._nid; + } + @Override public String functionName(Node n) { return ((FunNode)n)._name==null ? "" : ((FunNode)n)._name; } + @Override public String signature(Node n) { + FunNode fun=(FunNode)n; + return (fun._name==null ? "" : fun._name)+" "+fun.sig().str(); + } + + public static String prettyPrint(Node n, int depth) { return PRINT.prettyPrint(n,depth); } + public static SB printLine(Node n, SB sb) { return sb.p(PRINT.line(n)); } + + public static String prettyPrint(CodeGen code) { + var units=new ArrayList>(); + for( var cu : code._compunits.values() ) { + var funs=new ArrayList(); + for( FunNode fun : code._linker ) + if( fun!=null && fun._compunit==cu ) funs.add(fun); + units.add(new com.seaofnodes.print.IRPrinter.Unit<>(cu._cname,cu._start,cu._stop,funs)); + } + return PRINT.program(code._start,code._stop,units); + } +} diff --git a/chapter29/src/main/java/com/seaofnodes/simple/print/SimpleGraphAdapter.java b/chapter29/src/main/java/com/seaofnodes/simple/print/SimpleGraphAdapter.java new file mode 100644 index 00000000..9ca0ec51 --- /dev/null +++ b/chapter29/src/main/java/com/seaofnodes/simple/print/SimpleGraphAdapter.java @@ -0,0 +1,80 @@ +package com.seaofnodes.simple.print; + +import com.seaofnodes.graph.GraphAdapter; +import com.seaofnodes.graph.GraphSnapshot.*; +import com.seaofnodes.simple.codegen.CodeGen; +import com.seaofnodes.simple.node.*; +import com.seaofnodes.simple.node.Node; +import com.seaofnodes.simple.type.TypeMem; + +/** Chapter 25's view of the IR, including partially constructed parse-time graphs. */ +public class SimpleGraphAdapter extends GraphAdapter { + + @Override protected boolean show(Node n) { + if( n != CodeGen.CODE.ZERO && n != CodeGen.CODE.XCTRL ) return true; + for( int i=0; i0 && n.in(i) instanceof ReturnNode ret + ? ref(ret.fun()) : 0; + } + @Override protected int projectionIndex(Node n) { return n instanceof Proj p ? p.idx() : -1; } + + @Override protected boolean folding(Node n) { + if( n instanceof FunNode fun ) return fun.folding(); + if( n instanceof ReturnNode ret ) return ret.fun().folding(); + if( n instanceof CallEndNode cend ) return cend.folding(); + if( n instanceof CallNode ) + for( int i=0; i= 2) ) return Role.MEM; + Node def = n.in(i); + if( def instanceof CFGNode ) return Role.CTRL; + if( def != null && isMem(def) ) return Role.MEM; + return Role.DATA; + } + + private boolean isMem(Node n) { + // These Phi subclasses are memory even before their first type computation. + return n instanceof MemPhiNode || n instanceof BulkMemPhiNode || n.isMem() || n._type instanceof TypeMem; + } +} diff --git a/chapter29/src/main/java/com/seaofnodes/simple/print/SimpleGraphObserver.java b/chapter29/src/main/java/com/seaofnodes/simple/print/SimpleGraphObserver.java new file mode 100644 index 00000000..f2ed2f72 --- /dev/null +++ b/chapter29/src/main/java/com/seaofnodes/simple/print/SimpleGraphObserver.java @@ -0,0 +1,35 @@ +package com.seaofnodes.simple.print; + +import com.seaofnodes.graph.GraphCapture; +import com.seaofnodes.graph.GraphViewer; +import com.seaofnodes.simple.codegen.CodeGen; +import com.seaofnodes.simple.node.Node; +import java.util.ArrayList; +import java.io.IOException; + +/** Chapter 25's compilation context; capture and event bookkeeping are shared. */ +public class SimpleGraphObserver extends GraphCapture { + private CodeGen _code; + public SimpleGraphObserver() { super(new SimpleGraphAdapter()); } + public static void main(String[] args) throws IOException { + GraphViewer.run(new SimpleGraphObserver()); + } + @Override protected void compile(String src) { + _code = new CodeGen(src); + _code._obs = this; + _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; } + @Override protected void detach() { + if( _code != null ) _code._obs = null; + _code = null; + } + @Override protected Node scope() { return _code.P._scope; } + @Override protected void roots(ArrayList roots) { + roots.add(_code._stop); + if( _code._phase == CodeGen.Phase.Parse ) { + roots.addAll(_code.P._xScopes); + } + } +} -- cgit v1.2.3