diff options
| author | Cliff Click <cliffc@acm.org> | 2026-09-22 11:25:05 -0700 |
|---|---|---|
| committer | Cliff Click <cliffc@acm.org> | 2026-09-22 11:25:05 -0700 |
| commit | 29fb671e69f90ad3b04c6fa8d746caf857f89e77 (patch) | |
| tree | 2f39d082f8a6de6a2b60b66406f8c9f0190d25c2 /chapter06 | |
| parent | 1d961838cff168a101069d08a8ab6594f49f0911 (diff) | |
| download | Simple-29fb671e69f90ad3b04c6fa8d746caf857f89e77.tar.gz Simple-29fb671e69f90ad3b04c6fa8d746caf857f89e77.zip | |
Add shared graph viewer to all chapters
Diffstat (limited to 'chapter06')
18 files changed, 150 insertions, 295 deletions
diff --git a/chapter06/Makefile b/chapter06/Makefile index cb362b42..8c2d5797 100644 --- a/chapter06/Makefile +++ b/chapter06/Makefile @@ -36,6 +36,7 @@ CLZDIR:= build/classes main_javas := $(wildcard $(SRC)/$(SIMPLE)/*java $(SRC)/$(SIMPLE)/*/*java) test_javas := $(wildcard $(TST)/$(SIMPLE)/*java $(TST)/$(SIMPLE)/*/*java) main_classes := $(patsubst $(SRC)/%java,$(CLZDIR)/main/%class,$(main_javas)) +include $(firstword $(wildcard ../graph/graph.mk graph/graph.mk)) test_classes := $(patsubst $(TST)/%java,$(CLZDIR)/test/%class,$(test_javas)) test_cp := $(patsubst $(TST)/$(SIMPLE)/%.java,com.seaofnodes.simple.%,$(test_javas)) classes = $(main_classes) $(test_classes) @@ -53,7 +54,7 @@ endif default: $(default_targets) # Compile just the out-of-date files -$(main_classes): build/classes/main/%class: $(SRC)/%java +$(main_classes): build/classes/main/%class: $(SRC)/%java $(graph_javas) @echo "compiling " $@ " because " $? @[ -d $(CLZDIR)/main ] || mkdir -p $(CLZDIR)/main @javac $(JAVAC_ARGS) -cp "$(CLZDIR)/main$(SEP)$(jars)" -sourcepath $(SRC) -d $(CLZDIR)/main $(main_javas) @@ -92,4 +93,7 @@ tags: $(main_javas) $(test_javas) @rm -f TAGS @$(CTAGS) -e --recurse=yes --extra=+q --fields=+fksaiS $(SRC) $(TST) -include ../build-support/chapter-release.mk +include $(firstword $(wildcard ../build-support/chapter-release.mk build-support/chapter-release.mk)) + +.PHONY: build +build: $(main_classes) diff --git a/chapter06/docs/06-grammar.md b/chapter06/docs/06-grammar.md index 4cf1cac6..9ed7b160 100644 --- a/chapter06/docs/06-grammar.md +++ b/chapter06/docs/06-grammar.md @@ -13,16 +13,12 @@ statement | blockStatment | expressionStatement | ifStatement - | metaStatement ; ifStatement : 'if' '(' expression ')' statement ('else' statement)? ; -metaStatement - : '#showGraph' ';' - ; expressionStatement : IDENTIFIER '=' expression ';' diff --git a/chapter06/pom.xml b/chapter06/pom.xml index fb852b3d..fa76937e 100644 --- a/chapter06/pom.xml +++ b/chapter06/pom.xml @@ -11,4 +11,7 @@ <artifactId>chapter06</artifactId> <packaging>jar</packaging> <name>Chapter 6</name> + <properties> + <simple.graph.directory>${project.basedir}/../graph</simple.graph.directory> + </properties> </project> diff --git a/chapter06/src/main/java/com/seaofnodes/simple/GraphVisualizer.java b/chapter06/src/main/java/com/seaofnodes/simple/GraphVisualizer.java deleted file mode 100644 index b30dd450..00000000 --- a/chapter06/src/main/java/com/seaofnodes/simple/GraphVisualizer.java +++ /dev/null @@ -1,230 +0,0 @@ -package com.seaofnodes.simple; - -import com.seaofnodes.simple.node.*; - -import java.util.*; - -/** - * Simple visualizer that outputs GraphViz dot format. - * The dot output must be saved to a file and run manually via dot to generate the SVG output. - * Currently, this is done manually. - */ -public class GraphVisualizer { - - public String generateDotOutput(Parser parser) { - - // Since the graph has cycles, we need to create a flat list of all the - // nodes in the graph. - Collection<Node> all = findAll(parser); - StringBuilder sb = new StringBuilder(); - sb.append("digraph chapter06 {\n"); - sb.append("/*\n"); - sb.append(parser.src()); - sb.append("\n*/\n"); - - // To keep the Scopes below the graph and pointing up into the graph we - // need to group the Nodes in a subgraph cluster, and the scopes into a - // different subgraph cluster. THEN we can draw edges between the - // scopes and nodes. If we try to cross subgraph cluster borders while - // still making the subgraphs DOT gets confused. - sb.append("\trankdir=BT;\n"); // Force Nodes before Scopes - - // Preserve node input order - sb.append("\tordering=\"in\";\n"); - - // Merge multiple edges hitting the same node. Makes common shared - // nodes much prettier to look at. - sb.append("\tconcentrate=\"true\";\n"); - - // Just the Nodes first, in a cluster no edges - nodes(sb, all); - - // Now the scopes, in a cluster no edges - for (ScopeNode sn: parser._xScopes) - scopes(sb, sn); - - // Walk the Node edges - nodeEdges(sb, all); - - // Walk the Scope edges - for (ScopeNode sn: parser._xScopes) - scopeEdges(sb, sn); - - sb.append("}\n"); - return sb.toString(); - } - - - private void nodes(StringBuilder sb, Collection<Node> all) { - // Just the Nodes first, in a cluster no edges - sb.append("\tsubgraph cluster_Nodes {\n"); // Magic "cluster_" in the subgraph name - for( Node n : all ) { - if( n instanceof ProjNode || n instanceof ScopeNode ) - continue; // Do not emit, rolled into MultiNode or Scope cluster already - sb.append("\t\t").append(n.uniqueName()).append(" [ "); - String lab = n.glabel(); - if( n instanceof MultiNode ) { - // Make a box with the MultiNode on top, and all the projections on the bottom - sb.append("shape=plaintext label=<\n"); - sb.append("\t\t\t<TABLE BORDER=\"0\" CELLBORDER=\"1\" CELLSPACING=\"0\" CELLPADDING=\"4\">\n"); - sb.append("\t\t\t<TR><TD BGCOLOR=\"yellow\">").append(lab).append("</TD></TR>\n"); - sb.append("\t\t\t<TR>"); - boolean doProjTable = false; - for( Node use : n._outputs ) { - if( use instanceof ProjNode proj ) { - if (!doProjTable) { - doProjTable = true; - sb.append("<TD>").append("\n"); - sb.append("\t\t\t\t<TABLE BORDER=\"0\" CELLBORDER=\"1\" CELLSPACING=\"0\">").append("\n"); - sb.append("\t\t\t\t<TR>"); - } - sb.append("<TD PORT=\"p").append(proj._idx).append("\""); - if( proj.isCFG() ) sb.append(" BGCOLOR=\"yellow\""); - sb.append(">").append(proj.glabel()).append("</TD>"); - } - } - if (doProjTable) { - sb.append("</TR>").append("\n"); - sb.append("\t\t\t\t</TABLE>").append("\n"); - sb.append("\t\t\t</TD>"); - } - sb.append("</TR>\n"); - sb.append("\t\t\t</TABLE>>\n\t\t"); - - } else { - // control nodes have box shape - // other nodes are ellipses, i.e. default shape - if( n.isCFG() ) - sb.append("shape=box style=filled fillcolor=yellow "); - if( n instanceof PhiNode ) - sb.append("style=filled fillcolor=lightyellow "); - sb.append("label=\"").append(lab).append("\" "); - } - sb.append("];\n"); - } - - // Force Region & Phis to line up - for( Node n : all ) { - if( n instanceof RegionNode region ) { - sb.append("\t\t{ rank=same; "); - sb.append(region).append(";") ; - for( Node phi : region._outputs ) - if( phi instanceof PhiNode ) - sb.append(phi.uniqueName()).append(";"); - sb.append("}\n"); - } - } - - sb.append("\t}\n"); // End Node cluster - } - - private void scopes( StringBuilder sb, ScopeNode scopenode) { - sb.append("\tnode [shape=plaintext];\n"); - int level=0; - for( HashMap<String,Integer> scope : scopenode._scopes ) { - String scopeName = makeScopeName(scopenode, level); - sb.append("\tsubgraph cluster_").append(scopeName).append(" {\n"); // Magic "cluster_" in the subgraph name - sb.append("\t\t").append(scopeName).append(" [label=<\n"); - sb.append("\t\t\t<TABLE BORDER=\"0\" CELLBORDER=\"1\" CELLSPACING=\"0\">\n"); - // Add the scope level - sb.append("\t\t\t<TR><TD BGCOLOR=\"cyan\">").append(level).append("</TD>"); - for( String name : scope.keySet() ) - sb.append("<TD PORT=\"").append(makePortName(scopeName, name)).append("\">").append(name).append("</TD>"); - sb.append("</TR>\n"); - sb.append("\t\t\t</TABLE>>];\n"); - level++; - } - // Scope clusters nest, so the graphics shows the nested scopes, so - // they are not closed as they are printed; so they just keep nesting. - // We close them all at once here. - sb.append( "\t}\n".repeat( level ) ); // End all Scope clusters - } - - private String makeScopeName(ScopeNode sn, int level) { return sn.uniqueName() + "_" + level; } - private String makePortName(String scopeName, String varName) { return scopeName + "_" + varName; } - - // Walk the node edges - private void nodeEdges(StringBuilder sb, Collection<Node> all) { - // All them edge labels - sb.append("\tedge [ fontname=Helvetica, fontsize=8 ];\n"); - for( Node n : all ) { - // Do not display the Constant->Start edge; - // ProjNodes handled by Multi; - // ScopeNodes are done separately - if( n instanceof ConstantNode || n instanceof ProjNode || n instanceof ScopeNode ) - continue; - int i=0; - for( Node def : n._inputs ) { - if( n instanceof PhiNode && def instanceof RegionNode ) { - // Draw a dotted use->def edge from Phi to Region. - sb.append('\t').append(n.uniqueName()); - sb.append(" -> "); - sb.append(def.uniqueName()); - sb.append(" [style=dotted taillabel=").append(i).append("];\n"); - } else if( def != null ) { - // Most edges land here use->def - sb.append('\t').append(n.uniqueName()).append(" -> "); - if( def instanceof ProjNode proj ) { - String mname = proj.ctrl().uniqueName(); - sb.append(mname).append(":p").append(proj._idx); - } else sb.append(def.uniqueName()); - // Number edges, so we can see how they track - sb.append("[taillabel=").append(i); - // control edges are colored red - if( def.isCFG() ) - sb.append(" color=red"); - sb.append("];\n"); - } - i++; - } - } - } - - // Walk the scope edges - private void scopeEdges( StringBuilder sb, ScopeNode scopenode ) { - sb.append("\tedge [style=dashed color=cornflowerblue];\n"); - int level=0; - for( HashMap<String,Integer> scope : scopenode._scopes ) { - String scopeName = makeScopeName(scopenode, level); - for( String name : scope.keySet() ) { - Node def = scopenode.in(scope.get(name)); - if( def==null ) continue; - sb.append("\t") - .append(scopeName).append(":") - .append('"').append(makePortName(scopeName, name)).append('"') // wrap port name with quotes because $ctrl is not valid unquoted - .append(" -> "); - if( def instanceof ProjNode proj ) { - String mname = proj.ctrl().uniqueName(); - sb.append(mname).append(":p").append(proj._idx); - } else sb.append(def.uniqueName()); - sb.append(";\n"); - } - level++; - } - } - - /** - * Finds all nodes in the graph. - */ - private Collection<Node> findAll(Parser parser) { - final HashMap<Integer, Node> all = new HashMap<>(); - for( Node n : Parser.START._outputs ) - walk(all, n); - for( Node n : parser._scope._inputs ) - walk(all, n); - return all.values(); - } - - /** - * Walk a subgraph and populate distinct nodes in the all list. - */ - private void walk(HashMap<Integer,Node> all, Node n) { - if(n == null ) return; - if (all.get(n._nid) != null) return; // Been there, done that - all.put(n._nid, n); - for (Node c : n._inputs) - walk(all, c); - for( Node c : n._outputs ) - walk(all, c); - } -} diff --git a/chapter06/src/main/java/com/seaofnodes/simple/Parser.java b/chapter06/src/main/java/com/seaofnodes/simple/Parser.java index 1a15efa3..9b79c195 100644 --- a/chapter06/src/main/java/com/seaofnodes/simple/Parser.java +++ b/chapter06/src/main/java/com/seaofnodes/simple/Parser.java @@ -1,5 +1,7 @@ package com.seaofnodes.simple; +import com.seaofnodes.graph.GraphObserver; + import com.seaofnodes.simple.node.*; import com.seaofnodes.simple.type.*; @@ -14,6 +16,12 @@ import java.util.*; */ public class Parser { + // Current compilation context; the observer belongs to the parser. + public static Parser PARSER; + public GraphObserver<Node> _obs; + public int pos() { return _lexer._position; } + + /** * A Global Static, unique to each compilation. This is a public, so we * can make constants everywhere without having to thread the StartNode @@ -62,6 +70,7 @@ public class Parser { public final Stack<ScopeNode> _xScopes = new Stack<>(); public Parser(String source, TypeInteger arg) { + PARSER = this; Node.reset(); _lexer = new Lexer(source); _scope = new ScopeNode(); @@ -85,8 +94,7 @@ public class Parser { private Node ctrl(Node n) { return _scope.ctrl(n); } - public StopNode parse() { return parse(false); } - public StopNode parse(boolean show) { + public StopNode parse() { _xScopes.push(_scope); // Enter a new scope for the initial control and arguments _scope.push(); @@ -97,7 +105,6 @@ public class Parser { _xScopes.pop(); if (!_lexer.isEOF()) throw error("Syntax error, unexpected " + _lexer.getAnyNextToken()); STOP.peephole(); - if( show ) showGraph(); return STOP; } @@ -134,7 +141,6 @@ public class Parser { else if (matchx("int")) return parseDecl(); else if (match ("{" )) return require(parseBlock(),"}"); else if (matchx("if" )) return parseIf(); - else if (matchx("#showGraph")) return require(showGraph(),";"); else if (matchx(";")) return null; // Empty statement else return parseExpressionStatement(); } @@ -203,14 +209,7 @@ public class Parser { return ret; } - /** - * Dumps out the node graph - * @return {@code null} - */ - private Node showGraph() { - System.out.println(new GraphVisualizer().generateDotOutput(this)); - return null; - } + /** * Parses an expression statement diff --git a/chapter06/src/main/java/com/seaofnodes/simple/node/AddNode.java b/chapter06/src/main/java/com/seaofnodes/simple/node/AddNode.java index af2a41b3..1cc20608 100644 --- a/chapter06/src/main/java/com/seaofnodes/simple/node/AddNode.java +++ b/chapter06/src/main/java/com/seaofnodes/simple/node/AddNode.java @@ -7,8 +7,6 @@ public class AddNode extends Node { @Override public String label() { return "Add"; } - @Override public String glabel() { return "+"; } - @Override StringBuilder _print1(StringBuilder sb) { in(1)._print0(sb.append("(")); diff --git a/chapter06/src/main/java/com/seaofnodes/simple/node/BoolNode.java b/chapter06/src/main/java/com/seaofnodes/simple/node/BoolNode.java index 79c65c60..24bca613 100644 --- a/chapter06/src/main/java/com/seaofnodes/simple/node/BoolNode.java +++ b/chapter06/src/main/java/com/seaofnodes/simple/node/BoolNode.java @@ -15,9 +15,6 @@ abstract public class BoolNode extends Node { public String label() { return getClass().getSimpleName(); } @Override - public String glabel() { return op(); } - - @Override StringBuilder _print1(StringBuilder sb) { in(1)._print0(sb.append("(")); in(2)._print0(sb.append(op())); diff --git a/chapter06/src/main/java/com/seaofnodes/simple/node/DivNode.java b/chapter06/src/main/java/com/seaofnodes/simple/node/DivNode.java index 519a8c8a..1bb04be7 100644 --- a/chapter06/src/main/java/com/seaofnodes/simple/node/DivNode.java +++ b/chapter06/src/main/java/com/seaofnodes/simple/node/DivNode.java @@ -8,8 +8,6 @@ public class DivNode extends Node { @Override public String label() { return "Div"; } - @Override public String glabel() { return "//"; } - @Override StringBuilder _print1(StringBuilder sb) { in(1)._print0(sb.append("(")); diff --git a/chapter06/src/main/java/com/seaofnodes/simple/node/MinusNode.java b/chapter06/src/main/java/com/seaofnodes/simple/node/MinusNode.java index 0d59ef25..b83c41a5 100644 --- a/chapter06/src/main/java/com/seaofnodes/simple/node/MinusNode.java +++ b/chapter06/src/main/java/com/seaofnodes/simple/node/MinusNode.java @@ -8,8 +8,6 @@ public class MinusNode extends Node { @Override public String label() { return "Minus"; } - @Override public String glabel() { return "-"; } - @Override StringBuilder _print1(StringBuilder sb) { in(1)._print0(sb.append("(-")); diff --git a/chapter06/src/main/java/com/seaofnodes/simple/node/MulNode.java b/chapter06/src/main/java/com/seaofnodes/simple/node/MulNode.java index 0380c079..20ec7d87 100644 --- a/chapter06/src/main/java/com/seaofnodes/simple/node/MulNode.java +++ b/chapter06/src/main/java/com/seaofnodes/simple/node/MulNode.java @@ -8,8 +8,6 @@ public class MulNode extends Node { @Override public String label() { return "Mul"; } - @Override public String glabel() { return "*"; } - @Override StringBuilder _print1(StringBuilder sb) { in(1)._print0(sb.append("(")); diff --git a/chapter06/src/main/java/com/seaofnodes/simple/node/Node.java b/chapter06/src/main/java/com/seaofnodes/simple/node/Node.java index 44e8dfd2..b533ae34 100644 --- a/chapter06/src/main/java/com/seaofnodes/simple/node/Node.java +++ b/chapter06/src/main/java/com/seaofnodes/simple/node/Node.java @@ -1,5 +1,7 @@ package com.seaofnodes.simple.node; +import com.seaofnodes.simple.Parser; + import com.seaofnodes.simple.Utils; import com.seaofnodes.simple.type.Type; @@ -76,13 +78,9 @@ public abstract class Node { // Easy reading label for debugger, e.g. "Add" or "Region" or "EQ" public abstract String label(); - // Unique label for graph visualization, e.g. "Add12" or "Region30" or "EQ99" + // Unique label for debugging, e.g. "Add12" or "Region30" or "EQ99" public String uniqueName() { return label() + _nid; } - // Graphical label, e.g. "+" or "Region" or "==" - public String glabel() { return label(); } - - // ------------------------------------------------------------------------ // Debugger Printing. @@ -223,7 +221,7 @@ public abstract class Node { } // Mostly used for asserts and printing. - boolean isDead() { return isUnused() && nIns()==0 && _type==null; } + public boolean isDead() { return isUnused() && nIns()==0 && _type==null; } // Shortcuts to stop DCE mid-parse // Add bogus null use to keep node alive @@ -254,12 +252,22 @@ public abstract class Node { * code. </li> * </ul> */ - public final Node peephole( ) { + public final Node peephole() { + var obs = Parser.PARSER == null ? null : Parser.PARSER._obs; + if( obs != null ) obs.before(this); + Type old = _type; + Node n = peepholeOpt(); + Node rez = n == null ? this : n; + if( obs != null ) obs.after(this, n == null && old == _type ? null : rez, false); + return rez; + } + + private Node peepholeOpt() { // Compute initial or improved Type Type type = _type = compute(); if (_disablePeephole) - return this; // Peephole optimizations turned off + return null; // Peephole optimizations turned off // Replace constant computations from non-constants with a constant node if (!(this instanceof ConstantNode) && type.isConstant()) @@ -273,8 +281,8 @@ public abstract class Node { // Recursively optimize return deadCodeElim(n.peephole()); - return this; // No progress - } + return null; // No progress + } // m is the new Node, self is the old. // Return 'm', which may have zero uses but is alive nonetheless. diff --git a/chapter06/src/main/java/com/seaofnodes/simple/node/NotNode.java b/chapter06/src/main/java/com/seaofnodes/simple/node/NotNode.java index e3683646..83c63244 100644 --- a/chapter06/src/main/java/com/seaofnodes/simple/node/NotNode.java +++ b/chapter06/src/main/java/com/seaofnodes/simple/node/NotNode.java @@ -8,8 +8,6 @@ public class NotNode extends Node { @Override public String label() { return "Not"; } - @Override public String glabel() { return "!"; } - @Override StringBuilder _print1(StringBuilder sb) { in(1)._print0(sb.append("(!")); diff --git a/chapter06/src/main/java/com/seaofnodes/simple/node/PhiNode.java b/chapter06/src/main/java/com/seaofnodes/simple/node/PhiNode.java index 15088e08..f7cf917e 100644 --- a/chapter06/src/main/java/com/seaofnodes/simple/node/PhiNode.java +++ b/chapter06/src/main/java/com/seaofnodes/simple/node/PhiNode.java @@ -10,8 +10,6 @@ public class PhiNode extends Node { @Override public String label() { return "Phi_"+_label; } - @Override public String glabel() { return "φ_"+_label; } - @Override StringBuilder _print1(StringBuilder sb) { sb.append("Phi("); diff --git a/chapter06/src/main/java/com/seaofnodes/simple/node/SubNode.java b/chapter06/src/main/java/com/seaofnodes/simple/node/SubNode.java index 475b3790..2e170273 100644 --- a/chapter06/src/main/java/com/seaofnodes/simple/node/SubNode.java +++ b/chapter06/src/main/java/com/seaofnodes/simple/node/SubNode.java @@ -8,8 +8,6 @@ public class SubNode extends Node { @Override public String label() { return "Sub"; } - @Override public String glabel() { return "-"; } - @Override StringBuilder _print1(StringBuilder sb) { in(1)._print0(sb.append("(")); diff --git a/chapter06/src/main/java/com/seaofnodes/simple/print/SimpleGraphAdapter.java b/chapter06/src/main/java/com/seaofnodes/simple/print/SimpleGraphAdapter.java new file mode 100644 index 00000000..cee75f6a --- /dev/null +++ b/chapter06/src/main/java/com/seaofnodes/simple/print/SimpleGraphAdapter.java @@ -0,0 +1,52 @@ +package com.seaofnodes.simple.print; + +import com.seaofnodes.graph.GraphAdapter; +import com.seaofnodes.graph.GraphSnapshot; +import com.seaofnodes.graph.GraphSnapshot.*; +import com.seaofnodes.simple.node.*; +import com.seaofnodes.simple.node.Node; +import java.util.ArrayList; + +/** Chapter 6's view of the IR; browser, transport and layout are shared. */ +public class SimpleGraphAdapter extends GraphAdapter<Node> { + @Override protected boolean dead(Node n) { return n.isDead(); } + @Override protected int id(Node n) { return n._nid; } + @Override protected int nIns(Node n) { return n.nIns(); } + @Override protected Node in(Node n, int idx) { return n.in(idx); } + @Override protected int nOuts(Node n) { return n.nOuts(); } + @Override protected Node out(Node n, int idx) { return n.out(idx); } + + private ArrayList<Edge> edges(Node n) { + var edges = new ArrayList<Edge>(); + String[] names = n instanceof ScopeNode scope && n.nIns() != 0 ? scope.reverseNames() : null; + for( int i = 0; i < n.nIns(); i++ ) { + String name = names == null || i >= names.length ? null : names[i]; + edges.add(new Edge(i, ref(n.in(i)), role(n, i), name)); + } + return edges; + } + + @Override protected GraphSnapshot.Node desc(Node n) { + Projection proj = n instanceof ProjNode p ? new Projection(ref(n.in(0)), p._idx) : null; + String label = n.label(); + return new GraphSnapshot.Node(n._nid, label == null ? n.getClass().getSimpleName() : label, + n._type == null ? null : n._type.toString(), kind(n), edges(n), proj); + } + + private Kind kind(Node n) { + if( n instanceof ScopeNode ) return Kind.SCOPE; + if( n instanceof StartNode ) return Kind.CTRL; + if( n instanceof RegionNode ) return Kind.REGION; + if( n instanceof PhiNode ) return Kind.PHI; + return n.isCFG() ? Kind.CTRL : Kind.DATA; + } + + private Role role(Node n, int i) { + if( n instanceof ScopeNode || n instanceof ConstantNode ) return Role.ASSOC; + if( n instanceof PhiNode ) return i == 0 ? Role.ASSOC : Role.DATA; + if( n instanceof ProjNode ) return n.isCFG() ? Role.CTRL : Role.DATA; + if( n instanceof RegionNode && i == 0 ) return Role.ASSOC; + if( i == 0 || n instanceof RegionNode || n instanceof StopNode ) return Role.CTRL; + return Role.DATA; + } +} diff --git a/chapter06/src/main/java/com/seaofnodes/simple/print/SimpleGraphObserver.java b/chapter06/src/main/java/com/seaofnodes/simple/print/SimpleGraphObserver.java new file mode 100644 index 00000000..122c7267 --- /dev/null +++ b/chapter06/src/main/java/com/seaofnodes/simple/print/SimpleGraphObserver.java @@ -0,0 +1,40 @@ +package com.seaofnodes.simple.print; + +import com.seaofnodes.graph.GraphCapture; +import com.seaofnodes.graph.GraphViewer; +import com.seaofnodes.simple.Parser; +import com.seaofnodes.simple.node.Node; +import java.util.ArrayList; +import java.io.IOException; + +/** Chapter 6's compilation context; capture and event bookkeeping are shared. */ +public class SimpleGraphObserver extends GraphCapture<Node> { + private Parser _parser; + private Node _ret; + private String _phase; + public SimpleGraphObserver() { super(new SimpleGraphAdapter()); } + public static void main(String[] args) throws IOException { + GraphViewer.run(new SimpleGraphObserver()); + } + @Override protected void compile(String src) { + _parser = new Parser(src); + _parser._obs = this; + _phase = "Parse"; + _ret = _parser.parse(); + phase(_phase); + } + @Override protected String phase() { return _phase; } + @Override protected int pos() { return "Parse".equals(_phase) ? _parser.pos() : -1; } + @Override protected void detach() { + if( _parser != null ) _parser._obs = null; + _parser = null; + _ret = null; + } + @Override protected void roots(ArrayList<Node> roots) { + roots.add(Parser.START); + roots.add(_parser.STOP); + roots.add(_parser._scope); + roots.addAll(_parser._xScopes); + roots.add(_ret); + } +} diff --git a/chapter06/src/test/java/com/seaofnodes/simple/Chapter05Test.java b/chapter06/src/test/java/com/seaofnodes/simple/Chapter05Test.java index 134a8be2..31ca56a0 100644 --- a/chapter06/src/test/java/com/seaofnodes/simple/Chapter05Test.java +++ b/chapter06/src/test/java/com/seaofnodes/simple/Chapter05Test.java @@ -19,7 +19,7 @@ else { a = arg-3; } return a;"""); - StopNode ret = parser.parse(false); + StopNode ret = parser.parse(); assertEquals("return Phi(Region17,(arg+2),(arg-3));", ret.toString()); } @@ -34,7 +34,7 @@ if (arg == 1) { c = 4; } return c;""", TypeInteger.BOT); - StopNode ret = parser.parse(false); + StopNode ret = parser.parse(); assertEquals("return Phi(Region16,4,3);", ret.toString()); } @@ -62,7 +62,7 @@ if( arg==1 ) else b=a+1; return a+b;"""); - StopNode ret = parser.parse(false); + StopNode ret = parser.parse(); assertEquals("return ((arg*2)+Phi(Region20,2,3));", ret.toString()); } @@ -77,7 +77,7 @@ if( arg==1 ) else a=b+1; return a+b;"""); - StopNode ret = parser.parse(false); + StopNode ret = parser.parse(); assertEquals("return ((Phi(Region31,(arg*2),arg)+arg)+Phi(Region31,4,5));", ret.toString()); } @@ -127,7 +127,7 @@ if( arg==1 ) a=arg==3; } return a;"""); - StopNode ret = parser.parse(false); + StopNode ret = parser.parse(); assertEquals("return (arg==Phi(Region16,3,2));", ret.toString()); } diff --git a/chapter06/src/test/java/com/seaofnodes/simple/Chapter06Test.java b/chapter06/src/test/java/com/seaofnodes/simple/Chapter06Test.java index 44b49d73..cb58f2bb 100644 --- a/chapter06/src/test/java/com/seaofnodes/simple/Chapter06Test.java +++ b/chapter06/src/test/java/com/seaofnodes/simple/Chapter06Test.java @@ -15,7 +15,7 @@ public class Chapter06Test { if( true ) return 2; return 1; """); - StopNode stop = parser.parse(false); + StopNode stop = parser.parse(); assertEquals("return 2;", stop.toString()); assertTrue(stop.ret().ctrl() instanceof ProjNode); } @@ -29,7 +29,7 @@ if (arg) a = 2; return (arg < a) < 3; """); - StopNode stop = parser.parse(false); + StopNode stop = parser.parse(); assertEquals("return ((arg<Phi(Region12,2,1))<3);", stop.toString()); } @@ -44,7 +44,7 @@ else a=3; return a; """); - StopNode stop = parser.parse(false); + StopNode stop = parser.parse(); assertEquals("return 2;", stop.toString()); assertTrue(stop.ret().ctrl() instanceof ProjNode); } @@ -64,7 +64,7 @@ if( a==2 ) else b=5; return b;""", TypeInteger.BOT); - StopNode stop = parser.parse(false); + StopNode stop = parser.parse(); assertEquals("return Phi(Region32,42,5);", stop.toString()); } @@ -83,7 +83,7 @@ if( arg==2 ) else b=5; return b;""", TypeInteger.BOT); - StopNode stop = parser.parse(false); + StopNode stop = parser.parse(); assertEquals("return Phi(Region28,2,5);", stop.toString()); } @@ -123,7 +123,7 @@ else a=5; return a; """, TypeInteger.constant(1)); - StopNode stop = parser.parse(false); + StopNode stop = parser.parse(); assertEquals("return 3;", stop.toString()); } @@ -143,7 +143,7 @@ else a=5; return a; """, TypeInteger.BOT); - StopNode stop = parser.parse(false); + StopNode stop = parser.parse(); assertEquals("return Phi(Region36,3,Phi(Region34,4,5));", stop.toString()); } @@ -163,7 +163,7 @@ else a=5; return a; """, TypeInteger.constant(1)); - StopNode stop = parser.parse(false); + StopNode stop = parser.parse(); assertEquals("return 3;", stop.toString()); } @@ -183,7 +183,7 @@ else a=5; return a; """, TypeInteger.constant(3)); - StopNode stop = parser.parse(false); + StopNode stop = parser.parse(); assertEquals("return 4;", stop.toString()); } @@ -199,7 +199,7 @@ if( arg ) { } return a+b; """); - StopNode ret = parser.parse(false); + StopNode ret = parser.parse(); assertEquals("return Phi(Region22,4,1);", ret.toString()); } @@ -216,7 +216,7 @@ if( arg ) { } return a+b; """, TypeInteger.constant(1)); - StopNode ret = parser.parse(false); + StopNode ret = parser.parse(); assertEquals("return 4;", ret.toString()); } @@ -232,7 +232,7 @@ if( arg ) { } return a+b; """, TypeInteger.constant(0)); - StopNode ret = parser.parse(false); + StopNode ret = parser.parse(); assertEquals("return 1;", ret.toString()); } @@ -250,7 +250,7 @@ if( arg ) { } return a+b+c; """); - StopNode ret = parser.parse(false); + StopNode ret = parser.parse(); assertEquals("return (Phi(Region33,Phi(Region22,2,3),0)+Phi(Region33,3,1));", ret.toString()); } @@ -269,7 +269,7 @@ if( arg ) { } return a+b+c; """, TypeInteger.constant(1)); - StopNode ret = parser.parse(false); + StopNode ret = parser.parse(); assertEquals("return 6;", ret.toString()); } @@ -287,7 +287,7 @@ if( arg ) { } return a+b+c; """, TypeInteger.constant(2)); - StopNode ret = parser.parse(false); + StopNode ret = parser.parse(); assertEquals("return 5;", ret.toString()); } |
