summaryrefslogtreecommitdiff
path: root/chapter-sccp/src/main/java/com/seaofnodes/simple/print
diff options
context:
space:
mode:
Diffstat (limited to 'chapter-sccp/src/main/java/com/seaofnodes/simple/print')
-rw-r--r--chapter-sccp/src/main/java/com/seaofnodes/simple/print/ASMPrinter.java85
-rw-r--r--chapter-sccp/src/main/java/com/seaofnodes/simple/print/IRPrinter.java61
-rw-r--r--chapter-sccp/src/main/java/com/seaofnodes/simple/print/SimpleGraphAdapter.java57
-rw-r--r--chapter-sccp/src/main/java/com/seaofnodes/simple/print/SimpleGraphObserver.java35
4 files changed, 238 insertions, 0 deletions
diff --git a/chapter-sccp/src/main/java/com/seaofnodes/simple/print/ASMPrinter.java b/chapter-sccp/src/main/java/com/seaofnodes/simple/print/ASMPrinter.java
new file mode 100644
index 00000000..48296ce7
--- /dev/null
+++ b/chapter-sccp/src/main/java/com/seaofnodes/simple/print/ASMPrinter.java
@@ -0,0 +1,85 @@
+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;
+
+/** Machine-specific facts; traversal, columns and byte display live in print/. */
+public final class ASMPrinter extends AssemblyAdapter<Node> {
+ 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<Node> blocks() {
+ var blocks=new ArrayList<Node>();
+ var cfg=_code._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;
+ return n.getClass()==ConstantNode.class;
+ }
+ @Override public boolean postAlloc() { return _code._phase.ordinal()>CodeGen.Phase.RegAlloc.ordinal(); }
+ @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!=null && n._nid<_enc._opStart.length ? _enc._opStart[n._nid] : -1;
+ }
+ @Override public int size(Node n) {
+ return encoded() && _enc._opLen!=null && n._nid<_enc._opLen.length ? _enc._opLen[n._nid]&255 : 0;
+ }
+ private static ArrayList<Data> entries(Iterable<Encoding.Relo> relos) {
+ var data=new ArrayList<Data>();
+ for( Encoding.Relo r : relos ) {
+ int align=1<<r._align;
+ int size=r._t instanceof TypeStruct ? (r._structSize+align-1)&-align : align;
+ if( r._t instanceof TypeTuple t ) size=align*t._types.length;
+ data.add(new Data(r._t,r._t.str(),r._align,size));
+ }
+ return data;
+ }
+ @Override public ArrayList<Pool> pools(int codeEnd) {
+ var pools=new ArrayList<Pool>();
+ if( !encoded() ) return pools;
+ int base=(codeEnd+15)&-16;
+ if( !_enc._bigCons.isEmpty() && base<_enc._bits.size() )
+ pools.add(new Pool("Constant Pool",_enc._bits.buf(),base,base,entries(_enc._bigCons.values())));
+ return pools;
+ }
+}
diff --git a/chapter-sccp/src/main/java/com/seaofnodes/simple/print/IRPrinter.java b/chapter-sccp/src/main/java/com/seaofnodes/simple/print/IRPrinter.java
new file mode 100644
index 00000000..c912ab77
--- /dev/null
+++ b/chapter-sccp/src/main/java/com/seaofnodes/simple/print/IRPrinter.java
@@ -0,0 +1,61 @@
+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<Node> {
+ private static final com.seaofnodes.print.IRPrinter<Node> 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 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<com.seaofnodes.print.IRPrinter.Unit<Node>>();
+ var funs=new ArrayList<Node>();
+ for( Node n : code._start._outputs ) if( n instanceof FunNode ) funs.add(n);
+ units.add(new com.seaofnodes.print.IRPrinter.Unit<>(null,null,null,funs));
+ return PRINT.program(code._start,code._stop,units);
+ }
+ public static String _prettyPrint(CodeGen code) {
+ if( code._cfg==null ) return prettyPrint(code);
+ var blocks=new ArrayList<Node>();
+ for( Node n : code._cfg ) blocks.add(n);
+ return PRINT.scheduled(blocks);
+ }
+}
diff --git a/chapter-sccp/src/main/java/com/seaofnodes/simple/print/SimpleGraphAdapter.java b/chapter-sccp/src/main/java/com/seaofnodes/simple/print/SimpleGraphAdapter.java
new file mode 100644
index 00000000..8dc6ea47
--- /dev/null
+++ b/chapter-sccp/src/main/java/com/seaofnodes/simple/print/SimpleGraphAdapter.java
@@ -0,0 +1,57 @@
+package com.seaofnodes.simple.print;
+
+import com.seaofnodes.graph.GraphAdapter;
+import com.seaofnodes.graph.GraphSnapshot.*;
+import com.seaofnodes.simple.node.*;
+import com.seaofnodes.simple.node.Node;
+import com.seaofnodes.simple.type.TypeMem;
+
+/** Chapter 24's view of the IR; browser, transport and layout are shared. */
+public class SimpleGraphAdapter extends GraphAdapter<Node> {
+
+ @Override protected String edgeName(Node n, int i) {
+ return n instanceof ScopeNode scope && i < scope._vars.size()
+ ? scope._vars.get(i)._name : null;
+ }
+ @Override protected int edgeJump(Node n, int i) {
+ return n instanceof CallEndNode && i>0 && n.in(i) instanceof ReturnNode ret
+ ? ref(ret.fun()) : 0;
+ }
+ @Override protected int projectionIndex(Node n) { return n instanceof ProjNode p ? p._idx : n instanceof CProjNode 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<n.nOuts(); i++ )
+ if( n.out(i) instanceof CallEndNode cend && cend.folding() ) return true;
+ return false;
+ }
+
+ @Override protected Kind kind(Node n) {
+ if( n instanceof StopNode ) return Kind.STOP;
+ if( n instanceof ScopeNode ) return Kind.SCOPE;
+ if( n instanceof FunNode ) return Kind.FUN;
+ if( n instanceof StartNode ) return Kind.CTRL;
+ if( n instanceof LoopNode ) return Kind.LOOP;
+ if( n instanceof RegionNode ) return Kind.REGION;
+ if( n instanceof PhiNode ) return Kind.PHI;
+ return n instanceof CFGNode ? Kind.CTRL : isMem(n) ? Kind.MEM : Kind.DATA;
+ }
+
+ @Override protected Role role(Node n, int i) {
+ if( n instanceof ScopeNode || n instanceof ConstantNode || n instanceof CtrlNode || n instanceof XCtrlNode ) return Role.ASSOC;
+ if( n instanceof PhiNode ) return i == 0 ? Role.ASSOC : isMem(n) ? Role.MEM : Role.DATA;
+ if( n instanceof ProjNode || n instanceof CProjNode )
+ return n instanceof CFGNode ? Role.CTRL : isMem(n) ? Role.MEM : Role.DATA;
+ if( n instanceof RegionNode && i == 0 ) return Role.ASSOC;
+ if( i == 0 || n instanceof RegionNode || n instanceof StopNode ) return Role.CTRL;
+ if( n instanceof MemMergeNode || (i == 1 && (n instanceof MemOpNode || n instanceof ReturnNode || n instanceof CallNode || n instanceof NewNode)) ) return Role.MEM;
+ Node def = n.in(i);
+ if( def != null && isMem(def) ) return Role.MEM;
+ return Role.DATA;
+ }
+
+ private boolean isMem(Node n) { return n.isMem() || n._type instanceof TypeMem; }
+}
diff --git a/chapter-sccp/src/main/java/com/seaofnodes/simple/print/SimpleGraphObserver.java b/chapter-sccp/src/main/java/com/seaofnodes/simple/print/SimpleGraphObserver.java
new file mode 100644
index 00000000..b2c5492e
--- /dev/null
+++ b/chapter-sccp/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 24's compilation context; capture and event bookkeeping are shared. */
+public class SimpleGraphObserver extends GraphCapture<Node> {
+ 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<Node> roots) {
+ roots.add(_code._stop);
+ if( _code._phase == CodeGen.Phase.Parse ) {
+ roots.addAll(_code.P._xScopes);
+ }
+ }
+}