From 56d346ce2cb7c5ee4ab59e3d403d52d030670eca Mon Sep 17 00:00:00 2001 From: Cliff Click Date: Mon, 6 Jan 2025 09:53:05 -0800 Subject: JSView for functions Constants use glabel in JSView. TypeFunPtr gprint uses "→" instead of "->" --- chapter18/docs/lattice.gv | 2 +- .../main/java/com/seaofnodes/simple/CodeGen.java | 1 + .../main/java/com/seaofnodes/simple/JSViewer.java | 90 ++++++++++++++-------- .../main/java/com/seaofnodes/simple/Parser.java | 9 +-- .../com/seaofnodes/simple/node/ConstantNode.java | 4 +- .../java/com/seaofnodes/simple/node/FunNode.java | 2 +- .../java/com/seaofnodes/simple/node/ScopeNode.java | 2 +- .../com/seaofnodes/simple/type/TypeFunPtr.java | 2 +- 8 files changed, 67 insertions(+), 45 deletions(-) (limited to 'chapter18') diff --git a/chapter18/docs/lattice.gv b/chapter18/docs/lattice.gv index f8af5718..8661082d 100644 --- a/chapter18/docs/lattice.gv +++ b/chapter18/docs/lattice.gv @@ -47,7 +47,7 @@ digraph Lattice { INT_CON0 -> INT_CON1 -> INT_CON [style=invis]; // ---------------------- - // Integers + // Floats FLT_TOP [label=<⊤:flt>, fillcolor=aqua, shape=oval]; FLT_BOT [label=<⊥:flt>, fillcolor=aqua, shape=oval]; diff --git a/chapter18/src/main/java/com/seaofnodes/simple/CodeGen.java b/chapter18/src/main/java/com/seaofnodes/simple/CodeGen.java index bd56110c..47616b51 100644 --- a/chapter18/src/main/java/com/seaofnodes/simple/CodeGen.java +++ b/chapter18/src/main/java/com/seaofnodes/simple/CodeGen.java @@ -42,6 +42,7 @@ public class CodeGen { Node._disablePeephole = disable; _stop = P.parse(); _start = Parser.START; // Capture global start + JSViewer.show(); P = null; // No longer parsing return this; } diff --git a/chapter18/src/main/java/com/seaofnodes/simple/JSViewer.java b/chapter18/src/main/java/com/seaofnodes/simple/JSViewer.java index adbe9f30..7422767a 100644 --- a/chapter18/src/main/java/com/seaofnodes/simple/JSViewer.java +++ b/chapter18/src/main/java/com/seaofnodes/simple/JSViewer.java @@ -24,7 +24,7 @@ public class JSViewer implements AutoCloseable { static CodeGen CODE; // JSViewer() throws Exception { - // Launch server; hand shake + // Launch server; handshake SERVER = new SimpleWebSocket(Paths.get("docs/index.html").toUri(),12345) ; } @@ -35,7 +35,7 @@ public class JSViewer implements AutoCloseable { switch( src ) { case null: return; case "null": return; - case "+": break; // Client requests more frames, but we send them all anyways + case "+": break; // Client requests more frames, but we send them all anyway default: System.out.println(src); try { @@ -69,6 +69,9 @@ public class JSViewer implements AutoCloseable { public static void show() { if( SERVER!=null && SHOW ) _show(); } private static void _show() { boolean midParse = CODE.P!=null; + // Skip util we at least get the Parse object made + if( !midParse && (CODE._phase==null || CODE._phase == CodeGen.Phase.Parse) ) + return; Stack xScopes = midParse ? CODE.P._xScopes : null; Collection all = GraphVisualizer.findAll(xScopes, CODE._stop, midParse ? CODE.P._scope: null); @@ -130,11 +133,11 @@ public class JSViewer implements AutoCloseable { private static void nodes(SB sb, Collection all) { // Just the Nodes first, in a cluster no edges sb.i().p("subgraph cluster_Nodes {\n").ii(); // Magic "cluster_" in the subgraph name - for (Node n : all) { - if( n instanceof ProjNode || n instanceof CProjNode || n instanceof MemMergeNode || n==Parser.XCTRL ) + for( Node n : all ) { + if( n instanceof ProjNode || n instanceof CProjNode || n instanceof MemMergeNode ) continue; // Do not emit, rolled into MultiNode or Scope cluster already sb.i().p(n.uniqueName()).p(" [ "); - if( n instanceof MultiNode ) { + if( n instanceof MultiNode && !(n instanceof StartNode) ) { // Make a box with the MultiNode on top, and all the projections on the bottom sb. p("shape=plaintext label=<\n").ii(); sb.i().p("\n"); @@ -184,14 +187,15 @@ public class JSViewer implements AutoCloseable { private static void scope( SB sb, ScopeNode scope ) { sb.i().p("node [shape=plaintext];\n"); int last = scope.nIns(); - int max = scope._lexSize.size(); + int max = scope._lexSize.size()+1; // One more than lexsize for( int i = 0; i < max; i++ ) { int level = max-i-1; String scopeName = makeScopeName(scope, level); sb.i().p("subgraph cluster_").p(scopeName).p(" {\n").ii(); // Magic "cluster_" in the subgraph name sb.i().p(scopeName).p(" [label=<\n").ii(); sb.i().p("
\n"); - int lexStart=scope._lexSize.at(level); + int lexStart = level==0 ? 0 : scope._lexSize.at(level-1); + // Special for memory ScopeMinNode MemMergeNode n = scope.nIns()>1 ? scope.mem() : null; if( level==0 && n!=null && n.nIns()>2 ) { @@ -200,10 +204,12 @@ public class JSViewer implements AutoCloseable { cell(sb,"#"+m,n.alias(m),"m"+m); sb.p("\n"); // End scope level } + // Scope variables, empty if none if( lexStart\n"); for( int j=lexStart; j"),text,n,dark).p(""); + return colorcell(sb.p(">"),text,n,dark(color)).p(""); } private static SB node(SB sb, String text, Node n) { - boolean dark=false; - if( n instanceof CFGNode ) sb.p("style=filled fillcolor=yellow shape=box "); - if( n instanceof PhiNode ) sb.p("style=filled fillcolor=lightyellow "); - if( n instanceof StructNode) sb.p("style=filled fillcolor=lightgreen "); - if( n.isMem() ) { sb.p("style=filled fillcolor=blue "); dark=true; } - if( n._type instanceof TypeMemPtr ) { sb.p("style=filled fillcolor=green "); dark=true; } - if( n._type instanceof TypeInteger ) sb.p("style=filled fillcolor=lightblue "); - return colorcell(sb.p("label=<"),text,n,dark).p(">"); + String color = color(n); + sb.p("style=filled fillcolor=").p(color).p(" "); + String shape = switch( n ) { + case FunNode fun -> "shape=box peripheries=2"; + case CFGNode cfg -> "shape=box"; + default -> ""; + }; + sb.p(shape).p(" "); + return colorcell(sb.p("label=<"),text,n,dark(color)).p(">"); } + + private static String color(Node n) { + return switch( n ) { + case CFGNode cfg -> "yellow"; + case NewNode nnn -> "lightgreen"; + case StructNode s -> "lightgreen"; + default -> typeColor(n._type); + }; + } + private static String typeColor(Type t) { + return t==null ? "white" : switch( t ) { + case TypeMem mem -> "blue"; + case TypeMemPtr tmp -> "green"; + case TypeFunPtr tfp -> "orange"; + case TypeRPC rpc -> "antiquewhite"; + case TypeInteger ti -> "lightblue"; + case TypeFloat tf -> "aqua"; + case Type tn -> tn==Type.NIL ? "lightgray" : "red"; + }; + } + private static final String[] DARKS = new String[]{"blue","green","black"}; + private static boolean dark(String color) { return Utils.find(DARKS,color) != -1; } + + + // Called with an open div private static SB colorcell(SB sb, String text, Node n, boolean dark) { if( dark ) sb.p(""); @@ -313,19 +340,14 @@ public class JSViewer implements AutoCloseable { if( (n.iskeep() || n.isUnused()) && scopeName != null ) { sb.i().p(scopeName).p(" -> ").p(n.uniqueName()).p(" [ style=dashed color=grey];\n"); } + // Force functions above return + if( n instanceof ReturnNode ret && ret.inProgress() && !ret.fun().isDead() ) + sb.i().p(ret.ctrl().uniqueName()).p(" -> ").p(ret.fun().uniqueName()).p("[style=invis]\n"); } } private static void nodeEdgeColor(SB sb, Type t) { - String color = switch( t ) { - case TypeMem mem -> "blue"; - case TypeMemPtr ptr -> "green"; - case TypeInteger ti -> "lightblue"; - // control edges are colored red - default -> (t==Type.CONTROL || t==Type.XCONTROL) ? "red" : null; - }; - if( color!=null ) - sb.p(" color=").p(color); + sb.p(" color=").p(typeColor(t)); } // Walk the scope edges @@ -333,14 +355,14 @@ public class JSViewer implements AutoCloseable { sb.i().p("edge [style=dashed color=cornflowerblue];\n"); int level=0; for( var v : scope._vars ) { - if( v._idx==1 ) continue; // Memory done seperately + if( v._idx==1 ) continue; // Memory done separately Node def = scope.in(v._idx); while( def instanceof ScopeNode lazy ) def = lazy.in(v._idx); if( def==null ) continue; while( level < scope._lexSize.size() && v._idx >= scope._lexSize.at(level) ) level++; - String scopeName = makeScopeName(scope, level-1); + String scopeName = makeScopeName(scope, level); sb.i() .p(scopeName).p(":") .p('"').p(makePortName(scopeName, v._name)).p('"') // wrap port name with quotes because $ctrl is not valid unquoted diff --git a/chapter18/src/main/java/com/seaofnodes/simple/Parser.java b/chapter18/src/main/java/com/seaofnodes/simple/Parser.java index e518d2a0..dc8f042a 100644 --- a/chapter18/src/main/java/com/seaofnodes/simple/Parser.java +++ b/chapter18/src/main/java/com/seaofnodes/simple/Parser.java @@ -170,7 +170,6 @@ public class Parser { init.unkeep().kill(); INITS.clear(); STOP.peephole(); - JSViewer.show(); if( show ) showGraph(); return STOP; } @@ -194,11 +193,11 @@ public class Parser { Node rpc = new ParmNode("$rpc",0,TypeRPC.BOT,fun,con(TypeRPC.BOT)).peephole(); // Build a multi-exit return point for all function returns - RegionNode r = new RegionNode((Node)null,null); + RegionNode r = new RegionNode((Node)null,null).init(); assert r.inProgress(); - PhiNode rmem = new PhiNode(ScopeNode.MEM0,TypeMem.BOT,r,null); - PhiNode rrez = new PhiNode(ScopeNode.ARG0,Type.BOTTOM,r,null); - ReturnNode ret = new ReturnNode(r, rmem, rrez, rpc, fun); + PhiNode rmem = new PhiNode(ScopeNode.MEM0,TypeMem.BOT,r,null).init(); + PhiNode rrez = new PhiNode(ScopeNode.ARG0,Type.BOTTOM,r,null).init(); + ReturnNode ret = new ReturnNode(r, rmem, rrez, rpc, fun).init(); fun.setRet(ret); assert ret.inProgress(); STOP.addDef(ret); diff --git a/chapter18/src/main/java/com/seaofnodes/simple/node/ConstantNode.java b/chapter18/src/main/java/com/seaofnodes/simple/node/ConstantNode.java index e54797a5..e03bfb0e 100644 --- a/chapter18/src/main/java/com/seaofnodes/simple/node/ConstantNode.java +++ b/chapter18/src/main/java/com/seaofnodes/simple/node/ConstantNode.java @@ -31,8 +31,8 @@ public class ConstantNode extends Node { return new ConstantNode(type); } - @Override - public String label() { return "#"+_con; } + @Override public String label() { return "#"+_con; } + @Override public String glabel() { return _con.gprint(new SB().p("#")).toString(); } @Override public String uniqueName() { return "Con_" + _nid; } diff --git a/chapter18/src/main/java/com/seaofnodes/simple/node/FunNode.java b/chapter18/src/main/java/com/seaofnodes/simple/node/FunNode.java index 2d01b4d4..3e426ebe 100644 --- a/chapter18/src/main/java/com/seaofnodes/simple/node/FunNode.java +++ b/chapter18/src/main/java/com/seaofnodes/simple/node/FunNode.java @@ -19,7 +19,7 @@ public class FunNode extends RegionNode { public FunNode( Parser.Lexer loc, StartNode start, TypeFunPtr sig ) { super(loc,null,start); _sig=sig; } @Override - public String label() { return _sig._name; } + public String label() { return _sig._name == null ? "$fun" : _sig._name; } // Find the one CFG user from Fun. It's not always the Return, but always // the Return *is* a CFG user of Fun. diff --git a/chapter18/src/main/java/com/seaofnodes/simple/node/ScopeNode.java b/chapter18/src/main/java/com/seaofnodes/simple/node/ScopeNode.java index 727f7bbf..408c8195 100644 --- a/chapter18/src/main/java/com/seaofnodes/simple/node/ScopeNode.java +++ b/chapter18/src/main/java/com/seaofnodes/simple/node/ScopeNode.java @@ -160,7 +160,7 @@ public class ScopeNode extends MemMergeNode { _vars.add(v); // Creating a forward reference if( init==Parser.XCTRL ) - init = new FRefNode(v).peephole(); + init = new FRefNode(v).init(); addDef(init); return true; } diff --git a/chapter18/src/main/java/com/seaofnodes/simple/type/TypeFunPtr.java b/chapter18/src/main/java/com/seaofnodes/simple/type/TypeFunPtr.java index f0dc36a7..9e2cec07 100644 --- a/chapter18/src/main/java/com/seaofnodes/simple/type/TypeFunPtr.java +++ b/chapter18/src/main/java/com/seaofnodes/simple/type/TypeFunPtr.java @@ -110,7 +110,7 @@ public class TypeFunPtr extends TypeNil { else { for( Type t : _sig._types ) _print(sb,g,t).p(" "); - _print(sb.p("-> "),g,_ret).p(" #"); + _print(sb.p(g ? "→ " : "-> "),g,_ret).p(" #"); long fidxs = isHigh() ? ~_fidxs : _fidxs; String fidx = fidxs==0 ? "" : Long.bitCount(fidxs) == 1 ? ""+Long.numberOfTrailingZeros(fidxs) -- cgit v1.2.3