diff options
| author | Cliff Click <cliffc@acm.org> | 2026-10-01 12:01:57 -0700 |
|---|---|---|
| committer | Cliff Click <cliffc@acm.org> | 2026-10-01 12:01:57 -0700 |
| commit | 5ea32e69433d0c850d02bbc1e6c4a260bc095fec (patch) | |
| tree | ba4917ded278097332ee8f9f33227be74d3ac104 /chapter22/src/main/java/com/seaofnodes | |
| parent | bf7f603dd4e8ec781fe578243cdc18180322420b (diff) | |
| download | Simple-5ea32e69433d0c850d02bbc1e6c4a260bc095fec.tar.gz Simple-5ea32e69433d0c850d02bbc1e6c4a260bc095fec.zip | |
Move debug printing into shared space
Same as the graph viewer, moves a lot of code out of all Nodes
Diffstat (limited to 'chapter22/src/main/java/com/seaofnodes')
54 files changed, 359 insertions, 985 deletions
diff --git a/chapter22/src/main/java/com/seaofnodes/simple/codegen/CodeGen.java b/chapter22/src/main/java/com/seaofnodes/simple/codegen/CodeGen.java index 7c884b49..8a3d6322 100644 --- a/chapter22/src/main/java/com/seaofnodes/simple/codegen/CodeGen.java +++ b/chapter22/src/main/java/com/seaofnodes/simple/codegen/CodeGen.java @@ -450,7 +450,7 @@ public class CodeGen { @Override public String toString() { return _phase.ordinal() > Phase.Schedule.ordinal() ? IRPrinter._prettyPrint( this ) - : _stop.p(9999); + : IRPrinter.prettyPrint(this); } // Debugging helper diff --git a/chapter22/src/main/java/com/seaofnodes/simple/node/AddFNode.java b/chapter22/src/main/java/com/seaofnodes/simple/node/AddFNode.java index ba5815da..fd713156 100644 --- a/chapter22/src/main/java/com/seaofnodes/simple/node/AddFNode.java +++ b/chapter22/src/main/java/com/seaofnodes/simple/node/AddFNode.java @@ -1,21 +1,16 @@ package com.seaofnodes.simple.node; + import com.seaofnodes.simple.type.Type; import com.seaofnodes.simple.type.TypeFloat; -import java.util.BitSet; public class AddFNode extends Node { public AddFNode(Node lhs, Node rhs) { super(null, lhs, rhs); } @Override public String label() { return "AddF"; } - @Override - public StringBuilder _print1(StringBuilder sb, BitSet visited) { - in(1)._print0(sb.append("("), visited); - in(2)._print0(sb.append("+"), visited); - return sb.append(")"); - } + @Override protected String format() { return "(%1+%2)"; } @Override public Type compute() { diff --git a/chapter22/src/main/java/com/seaofnodes/simple/node/ArithNode.java b/chapter22/src/main/java/com/seaofnodes/simple/node/ArithNode.java index f9fc2870..e94ccbc6 100644 --- a/chapter22/src/main/java/com/seaofnodes/simple/node/ArithNode.java +++ b/chapter22/src/main/java/com/seaofnodes/simple/node/ArithNode.java @@ -1,10 +1,11 @@ package com.seaofnodes.simple.node; +import com.seaofnodes.print.ExprPrinter; + import com.seaofnodes.simple.Parser; import com.seaofnodes.simple.Utils; import com.seaofnodes.simple.type.Type; import com.seaofnodes.simple.type.TypeInteger; -import java.util.BitSet; public abstract class ArithNode extends Node { // Source location for late reported errors @@ -13,11 +14,8 @@ public abstract class ArithNode extends Node { public ArithNode( Parser.Lexer loc, Node lhs, Node rhs) { super(null, lhs, rhs); _loc = loc; } abstract String op(); - @Override - public StringBuilder _print1(StringBuilder sb, BitSet visited) { - in(1)._print0(sb.append("("), visited); - in(2)._print0(sb.append(op()), visited); - return sb.append(")"); + @Override protected ExprPrinter<Node> _print1(ExprPrinter<Node> p) { + return p.open().n(in(1)).p(op()).n(in(2)).close(); } abstract long doOp(long x, long y); diff --git a/chapter22/src/main/java/com/seaofnodes/simple/node/BoolNode.java b/chapter22/src/main/java/com/seaofnodes/simple/node/BoolNode.java index 80e8cf46..21ac59d3 100644 --- a/chapter22/src/main/java/com/seaofnodes/simple/node/BoolNode.java +++ b/chapter22/src/main/java/com/seaofnodes/simple/node/BoolNode.java @@ -1,9 +1,10 @@ package com.seaofnodes.simple.node; +import com.seaofnodes.print.ExprPrinter; + import com.seaofnodes.simple.Parser; import com.seaofnodes.simple.Utils; import com.seaofnodes.simple.type.*; -import java.util.BitSet; import static com.seaofnodes.simple.type.TypeInteger.*; abstract public class BoolNode extends Node { @@ -17,11 +18,8 @@ abstract public class BoolNode extends Node { @Override public String label() { return getClass().getSimpleName(); } - @Override - public StringBuilder _print1(StringBuilder sb, BitSet visited) { - in(1)._print0(sb.append("("), visited); - in(2)._print0(sb.append(op()), visited); - return sb.append(")"); + @Override protected ExprPrinter<Node> _print1(ExprPrinter<Node> p) { + return p.open().n(in(1)).p(op()).n(in(2)).close(); } @Override diff --git a/chapter22/src/main/java/com/seaofnodes/simple/node/CProjNode.java b/chapter22/src/main/java/com/seaofnodes/simple/node/CProjNode.java index 94770f16..4d3d8d0d 100644 --- a/chapter22/src/main/java/com/seaofnodes/simple/node/CProjNode.java +++ b/chapter22/src/main/java/com/seaofnodes/simple/node/CProjNode.java @@ -1,11 +1,12 @@ package com.seaofnodes.simple.node; +import com.seaofnodes.print.ExprPrinter; + import com.seaofnodes.simple.Parser; import com.seaofnodes.simple.Utils; import com.seaofnodes.simple.type.Type; import com.seaofnodes.simple.type.TypeMem; import com.seaofnodes.simple.type.TypeTuple; -import java.util.BitSet; public class CProjNode extends CFGNode { @@ -24,7 +25,7 @@ public class CProjNode extends CFGNode { @Override public String label() { return _label; } - @Override public StringBuilder _print1(StringBuilder sb, BitSet visited) { return sb.append(_label); } + @Override protected ExprPrinter<Node> _print1(ExprPrinter<Node> p) { return p.p(_label); } @Override public boolean blockHead() { return true; } diff --git a/chapter22/src/main/java/com/seaofnodes/simple/node/CallEndNode.java b/chapter22/src/main/java/com/seaofnodes/simple/node/CallEndNode.java index f37da4f3..264a506e 100644 --- a/chapter22/src/main/java/com/seaofnodes/simple/node/CallEndNode.java +++ b/chapter22/src/main/java/com/seaofnodes/simple/node/CallEndNode.java @@ -1,9 +1,10 @@ package com.seaofnodes.simple.node; +import com.seaofnodes.print.ExprPrinter; + import com.seaofnodes.simple.*; import com.seaofnodes.simple.codegen.*; import com.seaofnodes.simple.type.*; -import java.util.BitSet; /** * CallEnd @@ -29,13 +30,12 @@ public class CallEndNode extends CFGNode implements MultiNode { } @Override - public StringBuilder _print1(StringBuilder sb, BitSet visited) { - sb.append("cend( "); - sb.append( in(0) instanceof CallNode ? "Call, " : "----, "); + protected ExprPrinter<Node> _print1(ExprPrinter<Node> p) { + p.p("cend( "); + p.p( in(0) instanceof CallNode ? "Call, " : "----, "); for( int i=1; i<nIns()-1; i++ ) - in(i)._print0(sb,visited).append(","); - sb.setLength(sb.length()-1); - return sb.append(")"); + p.n(in(i)).p(","); + return p.unchar(',').unchar(' ').close(); } @Override diff --git a/chapter22/src/main/java/com/seaofnodes/simple/node/CallNode.java b/chapter22/src/main/java/com/seaofnodes/simple/node/CallNode.java index 94935e7c..8871e6a7 100644 --- a/chapter22/src/main/java/com/seaofnodes/simple/node/CallNode.java +++ b/chapter22/src/main/java/com/seaofnodes/simple/node/CallNode.java @@ -1,12 +1,13 @@ package com.seaofnodes.simple.node; +import com.seaofnodes.print.ExprPrinter; + import com.seaofnodes.simple.codegen.CodeGen; import com.seaofnodes.simple.IterPeeps; import com.seaofnodes.simple.Parser; import com.seaofnodes.simple.Utils; import com.seaofnodes.simple.type.Type; import com.seaofnodes.simple.type.TypeFunPtr; -import java.util.BitSet; /** * Call @@ -21,15 +22,14 @@ public class CallNode extends CFGNode { @Override public String label() { return "Call"; } - @Override public StringBuilder _print1(StringBuilder sb, BitSet visited) { + @Override protected ExprPrinter<Node> _print1(ExprPrinter<Node> p) { String fname = name(); - if( fname == null ) fptr()._print0(sb,visited); - else sb.append(fname); - sb.append("( "); + if( fname == null ) p.n(fptr()); + else p.p(fname); + p.p("( "); for( int i=2; i<nIns()-1; i++ ) - in(i)._print0(sb,visited).append(","); - sb.setLength(sb.length()-1); - return sb.append(")"); + p.n(in(i)).p(","); + return p.unchar(',').unchar(' ').close(); } public String name() { if( fptr()._type instanceof TypeFunPtr tfp && tfp.isConstant() && tfp.notNull() ) { diff --git a/chapter22/src/main/java/com/seaofnodes/simple/node/CastNode.java b/chapter22/src/main/java/com/seaofnodes/simple/node/CastNode.java index beec825c..8ae7b327 100644 --- a/chapter22/src/main/java/com/seaofnodes/simple/node/CastNode.java +++ b/chapter22/src/main/java/com/seaofnodes/simple/node/CastNode.java @@ -1,12 +1,13 @@ package com.seaofnodes.simple.node; +import com.seaofnodes.print.ExprPrinter; + import com.seaofnodes.simple.Parser; import com.seaofnodes.simple.Utils; import com.seaofnodes.simple.type.Type; import com.seaofnodes.simple.type.TypeInteger; import com.seaofnodes.simple.type.TypeMemPtr; -import java.util.BitSet; // Upcast (join) the input to a t. Used after guard test to lift an input. // Can also be used to make a type-assertion if ctrl is null. @@ -26,14 +27,11 @@ public class CastNode extends Node { @Override public String label() { return "("+_t.str()+")"; } - @Override - public String uniqueName() { return "Cast_" + _nid; } @Override public boolean isConst() { return true; } - @Override - public StringBuilder _print1(StringBuilder sb, BitSet visited) { - return in(1)._print0(sb.append(label()), visited); + @Override protected ExprPrinter<Node> _print1(ExprPrinter<Node> p) { + return p.p(label()).n(in(1)); } @Override diff --git a/chapter22/src/main/java/com/seaofnodes/simple/node/ConstantNode.java b/chapter22/src/main/java/com/seaofnodes/simple/node/ConstantNode.java index 60aa40c4..d3ac24a7 100644 --- a/chapter22/src/main/java/com/seaofnodes/simple/node/ConstantNode.java +++ b/chapter22/src/main/java/com/seaofnodes/simple/node/ConstantNode.java @@ -1,11 +1,12 @@ package com.seaofnodes.simple.node; +import com.seaofnodes.print.ExprPrinter; + import com.seaofnodes.simple.codegen.CodeGen; import com.seaofnodes.simple.Parser; import com.seaofnodes.simple.SB; import com.seaofnodes.simple.type.Type; import com.seaofnodes.simple.type.TypeFunPtr; -import java.util.BitSet; /** * A Constant node represents a constant value. At present, the only constants @@ -39,18 +40,20 @@ public class ConstantNode extends Node { return new ConstantNode(type); } - @Override public String label() { return "#"+_con; } - @Override - public String uniqueName() { return "Con_" + _nid; } + @Override protected String repeatName() { + return _con==null || _con.toString().length()<=32 ? null : uniqueName(); + } + + @Override public String label() { return "Con"; } @Override - public StringBuilder _print1(StringBuilder sb, BitSet visited) { + protected ExprPrinter<Node> _print1(ExprPrinter<Node> p) { if( _con instanceof TypeFunPtr tfp && tfp.isConstant() && tfp.notNull() ) { FunNode fun = CodeGen.CODE.link(tfp); if( fun!=null && fun._name != null ) - return sb.append("{ ").append(fun._name).append("}"); + return p.p("{ ").p(fun._name).p("}"); } - return sb.append(_con==null ? "---" : _con.print(new SB())); + return p.p(_con==null ? "---" : _con.print(new SB())); } @Override public boolean isConst() { return true; } diff --git a/chapter22/src/main/java/com/seaofnodes/simple/node/CtrlNode.java b/chapter22/src/main/java/com/seaofnodes/simple/node/CtrlNode.java index eda7d684..cf630ad4 100644 --- a/chapter22/src/main/java/com/seaofnodes/simple/node/CtrlNode.java +++ b/chapter22/src/main/java/com/seaofnodes/simple/node/CtrlNode.java @@ -1,14 +1,15 @@ package com.seaofnodes.simple.node; +import com.seaofnodes.print.ExprPrinter; + import com.seaofnodes.simple.codegen.CodeGen; import com.seaofnodes.simple.Parser; import com.seaofnodes.simple.type.Type; -import java.util.BitSet; public class CtrlNode extends CFGNode { public CtrlNode() { super(CodeGen.CODE._start); } @Override public String label() { return "Ctrl"; } - @Override public StringBuilder _print1(StringBuilder sb, BitSet visited) { return sb.append("Cctrl"); } + @Override protected ExprPrinter<Node> _print1(ExprPrinter<Node> p) { return p.p("Cctrl"); } @Override public boolean isConst() { return true; } @Override public Type compute() { return Type.CONTROL; } @Override public Node idealize() { return null; } diff --git a/chapter22/src/main/java/com/seaofnodes/simple/node/DivFNode.java b/chapter22/src/main/java/com/seaofnodes/simple/node/DivFNode.java index 2180ab46..149499f9 100644 --- a/chapter22/src/main/java/com/seaofnodes/simple/node/DivFNode.java +++ b/chapter22/src/main/java/com/seaofnodes/simple/node/DivFNode.java @@ -1,21 +1,16 @@ package com.seaofnodes.simple.node; + import com.seaofnodes.simple.type.Type; import com.seaofnodes.simple.type.TypeFloat; -import java.util.BitSet; public class DivFNode extends Node { public DivFNode(Node lhs, Node rhs) { super(null, lhs, rhs); } @Override public String label() { return "DivF"; } - @Override - public StringBuilder _print1(StringBuilder sb, BitSet visited) { - in(1)._print0(sb.append("("), visited); - in(2)._print0(sb.append("/"), visited); - return sb.append(")"); - } + @Override protected String format() { return "(%1/%2)"; } @Override public Type compute() { diff --git a/chapter22/src/main/java/com/seaofnodes/simple/node/ExternNode.java b/chapter22/src/main/java/com/seaofnodes/simple/node/ExternNode.java index a993d9de..093cc2cb 100644 --- a/chapter22/src/main/java/com/seaofnodes/simple/node/ExternNode.java +++ b/chapter22/src/main/java/com/seaofnodes/simple/node/ExternNode.java @@ -16,7 +16,6 @@ public class ExternNode extends ConstantNode { public ExternNode(Type t, String ex) { super(t); _extern = ex; } @Override public String label() { return "#"+_con+":"+_extern; } - @Override public String uniqueName() { return "Extern_" + _nid; } @Override public boolean eq(Node n) { return this==n; } } diff --git a/chapter22/src/main/java/com/seaofnodes/simple/node/FRefNode.java b/chapter22/src/main/java/com/seaofnodes/simple/node/FRefNode.java index 6093b8a6..e7333c23 100644 --- a/chapter22/src/main/java/com/seaofnodes/simple/node/FRefNode.java +++ b/chapter22/src/main/java/com/seaofnodes/simple/node/FRefNode.java @@ -1,9 +1,10 @@ package com.seaofnodes.simple.node; +import com.seaofnodes.print.ExprPrinter; + import com.seaofnodes.simple.Parser; import com.seaofnodes.simple.Var; import com.seaofnodes.simple.type.Type; -import java.util.BitSet; /** * A Forward Reference. Its any final constant, including functions. When @@ -17,10 +18,9 @@ public class FRefNode extends ConstantNode { @Override public String label() { return "FRef"+_n; } - @Override public String uniqueName() { return "FRef_" + _nid; } - @Override public StringBuilder _print1(StringBuilder sb, BitSet visited) { - return sb.append("FRef_").append(_n); + @Override protected ExprPrinter<Node> _print1(ExprPrinter<Node> p) { + return p.p("FRef_").p(_n); } @Override public Node idealize() { diff --git a/chapter22/src/main/java/com/seaofnodes/simple/node/FunPtrNode.java b/chapter22/src/main/java/com/seaofnodes/simple/node/FunPtrNode.java index 7f32698e..43242c32 100644 --- a/chapter22/src/main/java/com/seaofnodes/simple/node/FunPtrNode.java +++ b/chapter22/src/main/java/com/seaofnodes/simple/node/FunPtrNode.java @@ -9,5 +9,4 @@ public class FunPtrNode extends ConstantNode { addDef(ret); } public ReturnNode ret() { return (ReturnNode)in(1); } - @Override public String uniqueName() { return "FunPtr_"+_nid; } } diff --git a/chapter22/src/main/java/com/seaofnodes/simple/node/IfNode.java b/chapter22/src/main/java/com/seaofnodes/simple/node/IfNode.java index 5d90449e..81fbe170 100644 --- a/chapter22/src/main/java/com/seaofnodes/simple/node/IfNode.java +++ b/chapter22/src/main/java/com/seaofnodes/simple/node/IfNode.java @@ -1,9 +1,10 @@ package com.seaofnodes.simple.node; +import com.seaofnodes.print.ExprPrinter; + import com.seaofnodes.simple.Utils; import com.seaofnodes.simple.codegen.CodeGen; import com.seaofnodes.simple.type.*; -import java.util.BitSet; public class IfNode extends CFGNode implements MultiNode { @@ -17,11 +18,11 @@ public class IfNode extends CFGNode implements MultiNode { public String label() { return "If"; } @Override - public StringBuilder _print1(StringBuilder sb, BitSet visited) { - sb.append("if( "); - if( in(1)==null ) sb.append("never"); - else in(1)._print0(sb, visited); - return sb.append(" )"); + protected ExprPrinter<Node> _print1(ExprPrinter<Node> p) { + p.p("if( "); + if( in(1)==null ) p.p("never"); + else p.n(in(1)); + return p.p(" )"); } public Node ctrl() { return in(0); } diff --git a/chapter22/src/main/java/com/seaofnodes/simple/node/LoadNode.java b/chapter22/src/main/java/com/seaofnodes/simple/node/LoadNode.java index 0432bcbc..f668d2c3 100644 --- a/chapter22/src/main/java/com/seaofnodes/simple/node/LoadNode.java +++ b/chapter22/src/main/java/com/seaofnodes/simple/node/LoadNode.java @@ -1,5 +1,7 @@ package com.seaofnodes.simple.node; +import com.seaofnodes.print.ExprPrinter; + import com.seaofnodes.simple.codegen.CodeGen; import com.seaofnodes.simple.Parser; import com.seaofnodes.simple.type.*; @@ -45,7 +47,7 @@ public class LoadNode extends MemOpNode { // Debugger label @Override public String label() { return "ld_"+mlabel(); } @Override - public StringBuilder _print1(StringBuilder sb, BitSet visited) { return sb.append(".").append(_name); } + protected ExprPrinter<Node> _print1(ExprPrinter<Node> p) { return p.p(".").p(_name); } @Override public Type compute() { diff --git a/chapter22/src/main/java/com/seaofnodes/simple/node/MachConcreteNode.java b/chapter22/src/main/java/com/seaofnodes/simple/node/MachConcreteNode.java index b01b3308..4f5d9151 100644 --- a/chapter22/src/main/java/com/seaofnodes/simple/node/MachConcreteNode.java +++ b/chapter22/src/main/java/com/seaofnodes/simple/node/MachConcreteNode.java @@ -1,9 +1,10 @@ package com.seaofnodes.simple.node; +import com.seaofnodes.print.ExprPrinter; + import com.seaofnodes.simple.type.Type; import com.seaofnodes.simple.Utils; import java.io.ByteArrayOutputStream; -import java.util.BitSet; // Generic machine-specific class, has a few Node implementations that have to // exist (abstract) but are not useful past the optimizer. @@ -16,12 +17,11 @@ public abstract class MachConcreteNode extends Node implements MachNode { @Override public Type compute () { throw Utils.TODO(); } @Override public Node idealize() { throw Utils.TODO(); } - @Override public StringBuilder _print1(StringBuilder sb, BitSet visited) { - sb.append("(").append(op()).append(","); + @Override protected ExprPrinter<Node> _print1(ExprPrinter<Node> p) { + p.open().p(op()).p(","); for( int i=1; i<nIns(); i++ ) - (in(i)==null ? sb.append(" ---") : in(i)._print0(sb, visited)).append(","); - sb.setLength(sb.length()-1); - return sb.append(")"); + (in(i)==null ? p.p(" ---") : p.n(in(i))).p(","); + return p.unchar(',').close(); } } diff --git a/chapter22/src/main/java/com/seaofnodes/simple/node/MemMergeNode.java b/chapter22/src/main/java/com/seaofnodes/simple/node/MemMergeNode.java index c1d11f88..421e4864 100644 --- a/chapter22/src/main/java/com/seaofnodes/simple/node/MemMergeNode.java +++ b/chapter22/src/main/java/com/seaofnodes/simple/node/MemMergeNode.java @@ -1,5 +1,7 @@ package com.seaofnodes.simple.node; +import com.seaofnodes.print.ExprPrinter; + import com.seaofnodes.simple.*; import com.seaofnodes.simple.codegen.CodeGen; import com.seaofnodes.simple.type.*; @@ -52,14 +54,14 @@ public class MemMergeNode extends Node { @Override public String label() { return "MemMerge"; } @Override public boolean isMem() { return true; } @Override public Type compute() { return TypeMem.BOT; } - @Override public StringBuilder _print1(StringBuilder sb, BitSet visited) { - sb.append("MEM["); + @Override protected ExprPrinter<Node> _print1(ExprPrinter<Node> p) { + p.p("MEM["); for( int i=1; i<nIns(); i++ ) if( in(i)!=null ) { - sb.append(i==1 ? "default:" : i+":"); - in(i)._print0(sb,visited).append(" "); + p.p(i==1 ? "default:" : i+":"); + p.n(in(i)).p(" "); } - return sb.append("]"); + return p.p("]"); } @Override public Node idealize() { diff --git a/chapter22/src/main/java/com/seaofnodes/simple/node/MemOpNode.java b/chapter22/src/main/java/com/seaofnodes/simple/node/MemOpNode.java index 3428b5a5..db667e6d 100644 --- a/chapter22/src/main/java/com/seaofnodes/simple/node/MemOpNode.java +++ b/chapter22/src/main/java/com/seaofnodes/simple/node/MemOpNode.java @@ -1,5 +1,7 @@ package com.seaofnodes.simple.node; +import com.seaofnodes.print.ExprPrinter; + import com.seaofnodes.simple.Parser; import com.seaofnodes.simple.Utils; import com.seaofnodes.simple.type.Type; @@ -85,8 +87,8 @@ public abstract class MemOpNode extends Node { public Node ptr() { return in(2); } public Node off() { return in(3); } - @Override public StringBuilder _print1( StringBuilder sb, BitSet visited ) { return _printMach(sb,visited); } - public StringBuilder _printMach( StringBuilder sb, BitSet visited ) { throw Utils.TODO(); } + @Override protected ExprPrinter<Node> _print1(ExprPrinter<Node> p) { return _printMach(p); } + protected ExprPrinter<Node> _printMach(ExprPrinter<Node> p) { throw Utils.TODO(); } public int log_size() { return _declaredType.log_size(); } // Extra conditions for factoring matching memory operations through a Phi. diff --git a/chapter22/src/main/java/com/seaofnodes/simple/node/MinusFNode.java b/chapter22/src/main/java/com/seaofnodes/simple/node/MinusFNode.java index bfdb41cc..852e646d 100644 --- a/chapter22/src/main/java/com/seaofnodes/simple/node/MinusFNode.java +++ b/chapter22/src/main/java/com/seaofnodes/simple/node/MinusFNode.java @@ -1,20 +1,16 @@ package com.seaofnodes.simple.node; + import com.seaofnodes.simple.type.Type; import com.seaofnodes.simple.type.TypeFloat; -import java.util.BitSet; public class MinusFNode extends Node { public MinusFNode(Node in) { super(null, in); } @Override public String label() { return "MinusF"; } - @Override - public StringBuilder _print1(StringBuilder sb, BitSet visited) { - in(1)._print0(sb.append("(-"), visited); - return sb.append(")"); - } + @Override protected String format() { return "(-%1)"; } @Override public Type compute() { diff --git a/chapter22/src/main/java/com/seaofnodes/simple/node/MinusNode.java b/chapter22/src/main/java/com/seaofnodes/simple/node/MinusNode.java index 3a9eb39d..89e65254 100644 --- a/chapter22/src/main/java/com/seaofnodes/simple/node/MinusNode.java +++ b/chapter22/src/main/java/com/seaofnodes/simple/node/MinusNode.java @@ -1,21 +1,17 @@ package com.seaofnodes.simple.node; + import com.seaofnodes.simple.type.Type; import com.seaofnodes.simple.type.TypeInteger; import com.seaofnodes.simple.Utils; -import java.util.BitSet; public class MinusNode extends Node { public MinusNode(Node in) { super(null, in); } @Override public String label() { return "Minus"; } - @Override - public StringBuilder _print1(StringBuilder sb, BitSet visited) { - in(1)._print0(sb.append("(-"), visited); - return sb.append(")"); - } + @Override protected String format() { return "(-%1)"; } @Override public Type compute() { diff --git a/chapter22/src/main/java/com/seaofnodes/simple/node/MulFNode.java b/chapter22/src/main/java/com/seaofnodes/simple/node/MulFNode.java index 0fc062cd..6a57f3c5 100644 --- a/chapter22/src/main/java/com/seaofnodes/simple/node/MulFNode.java +++ b/chapter22/src/main/java/com/seaofnodes/simple/node/MulFNode.java @@ -1,21 +1,16 @@ package com.seaofnodes.simple.node; + import com.seaofnodes.simple.type.Type; import com.seaofnodes.simple.type.TypeFloat; -import java.util.BitSet; public class MulFNode extends Node { public MulFNode(Node lhs, Node rhs) { super(null, lhs, rhs); } @Override public String label() { return "MulF"; } - @Override - public StringBuilder _print1(StringBuilder sb, BitSet visited) { - in(1)._print0(sb.append("("), visited); - in(2)._print0(sb.append("*"), visited); - return sb.append(")"); - } + @Override protected String format() { return "(%1*%2)"; } @Override public Type compute() { diff --git a/chapter22/src/main/java/com/seaofnodes/simple/node/NeverNode.java b/chapter22/src/main/java/com/seaofnodes/simple/node/NeverNode.java index 516f218b..66879b66 100644 --- a/chapter22/src/main/java/com/seaofnodes/simple/node/NeverNode.java +++ b/chapter22/src/main/java/com/seaofnodes/simple/node/NeverNode.java @@ -1,11 +1,12 @@ package com.seaofnodes.simple.node; +import com.seaofnodes.print.ExprPrinter; + import com.seaofnodes.simple.Parser; import com.seaofnodes.simple.type.TypeInteger; import com.seaofnodes.simple.type.Type; import com.seaofnodes.simple.type.TypeTuple; -import java.util.BitSet; // "Never true" for infinite loop exits public class NeverNode extends IfNode { @@ -14,7 +15,7 @@ public class NeverNode extends IfNode { @Override public String label() { return "Never"; } - @Override public StringBuilder _print1(StringBuilder sb, BitSet visited) { return sb.append("Never"); } + @Override protected ExprPrinter<Node> _print1(ExprPrinter<Node> p) { return p.p("Never"); } @Override public Type compute() { return TypeTuple.IF_BOTH; } diff --git a/chapter22/src/main/java/com/seaofnodes/simple/node/NewNode.java b/chapter22/src/main/java/com/seaofnodes/simple/node/NewNode.java index 57d351ef..4179821c 100644 --- a/chapter22/src/main/java/com/seaofnodes/simple/node/NewNode.java +++ b/chapter22/src/main/java/com/seaofnodes/simple/node/NewNode.java @@ -1,10 +1,11 @@ package com.seaofnodes.simple.node; +import com.seaofnodes.print.ExprPrinter; + import com.seaofnodes.simple.SB; import com.seaofnodes.simple.Utils; import com.seaofnodes.simple.codegen.*; import com.seaofnodes.simple.type.*; -import java.util.BitSet; /** Allocate a zeroed object. Inputs {ctrl, $mem, size}; * results {ptr, $mem}. @@ -37,10 +38,8 @@ public class NewNode extends Node implements MultiNode { @Override public String label() { return "new_"+(_ptr._obj.isAry() ? "ary_"+_ptr._obj._fields[1]._type.str() : _ptr._obj.str()); } - @Override - public StringBuilder _print1(StringBuilder sb, BitSet visited) { - sb.append("new "); - return sb.append(_ptr._obj.str()); + @Override protected ExprPrinter<Node> _print1(ExprPrinter<Node> p) { + return p.p("new ").p(_ptr._obj.str()); } diff --git a/chapter22/src/main/java/com/seaofnodes/simple/node/Node.java b/chapter22/src/main/java/com/seaofnodes/simple/node/Node.java index 339ef9af..fff1ab14 100644 --- a/chapter22/src/main/java/com/seaofnodes/simple/node/Node.java +++ b/chapter22/src/main/java/com/seaofnodes/simple/node/Node.java @@ -1,5 +1,7 @@ package com.seaofnodes.simple.node; +import com.seaofnodes.print.BaseNode; + import com.seaofnodes.simple.*; import com.seaofnodes.simple.codegen.CodeGen; import com.seaofnodes.simple.print.IRPrinter; @@ -15,14 +17,7 @@ import static com.seaofnodes.simple.codegen.CodeGen.CODE; * The Node class provides common functionality used by all subtypes. * Subtypes of Node specialize by overriding methods. */ -public abstract class Node implements Cloneable { - - /** - * Each node has a unique dense Node ID within a compilation context - * The ID is useful for debugging, for using as an offset in a bitvector, - * as well as for computing equality of nodes (to be implemented later). - */ - public int _nid; +public abstract class Node extends BaseNode<Node> implements Cloneable { /** * Inputs to the node. These are use-def references to Nodes. @@ -44,16 +39,14 @@ public abstract class Node implements Cloneable { */ public Ary<Node> _outputs; - /** * Current computed type for this Node. This value changes as the graph * changes and more knowledge is gained about the program. */ public Type _type; - Node(Node... inputs) { - _nid = CODE.getUID(); // allocate unique dense ID + super(CODE.getUID()); // allocate unique dense ID _inputs = new Ary<>(Node.class); Collections.addAll(_inputs,inputs); _outputs = new Ary<>(Node.class); @@ -65,8 +58,8 @@ public abstract class Node implements Cloneable { // Make a Node using the existing arrays of nodes. // Used by any pass rewriting all Node classes but not the edges. Node( Node n ) { + super(CODE.getUID()); // allocate unique dense ID assert CodeGen.CODE._phase.ordinal() >= CodeGen.Phase.Select.ordinal(); - _nid = CODE.getUID(); // allocate unique dense ID _inputs = new Ary<>(n==null ? new Node[0] : n._inputs.asAry()); _outputs = new Ary<>(Node.class); _type = n==null ? Type.BOTTOM : n._type; @@ -77,48 +70,6 @@ public abstract class Node implements Cloneable { // Easy reading label for debugger, e.g. "Add" or "Region" or "EQ" public abstract String label(); - // Unique label for debugging, e.g. "Add12" or "Region30" or "EQ99" - public String uniqueName() { - return label() + _nid; - } - - // Operator symbol used by assembly/debug printing. - public String glabel() { return label(); } - - // Extra fun stuff, for assembly printing. Jump labels, parser locations, - // variable types, etc. - public String comment() { return null; } - - // ------------------------------------------------------------------------ - - // Debugger Printing. - - // {@code toString} is what you get in the debugger. It has to print 1 - // line (because this is what a debugger typically displays by default) and - // has to be robust with broken graph/nodes. - @Override - public final String toString() { return print(); } - - // This is a *deep* print. We print with a mutually recursive tik-tok - // style; the common _print0 calls the per-Node _print1, which calls back - // to _print0; - public final String print() { - return _print0(new StringBuilder(), new BitSet()).toString(); - } - - // This is the common print: check for repeats, check for DEAD and print - // "DEAD" else call the per-Node print1. - public final StringBuilder _print0(StringBuilder sb, BitSet visited) { - if (visited.get(_nid) && !(this instanceof ConstantNode) ) - return sb.append(label()); - visited.set(_nid); - return isDead() - ? sb.append(uniqueName()).append(":DEAD") - : _print1(sb, visited); - } - // Every Node implements this; a partial-line recursive print - abstract public StringBuilder _print1(StringBuilder sb, BitSet visited); - public String p(int depth) { return IRPrinter.prettyPrint(this,depth); } public boolean isConst() { return false; } @@ -126,6 +77,8 @@ public abstract class Node implements Cloneable { // ------------------------------------------------------------------------ // Graph Node & Edge manipulation + @Override public String typeName() { return _type==null ? null : _type.toString(); } + /** * Gets the ith input node * @param i Offset of the input node @@ -204,7 +157,6 @@ public abstract class Node implements Cloneable { return setDef(idx,new_def); } - /** * Add a new def to an existing Node. Keep the edges correct by * adding the corresponding <em>def->use</em> edge. @@ -273,7 +225,6 @@ public abstract class Node implements Cloneable { kill(); } - // Mostly used for asserts and printing. public boolean isDead() { return isUnused() && nIns()==0 && _type==null; } @@ -295,7 +246,6 @@ public abstract class Node implements Cloneable { kill(); } - // Replace self with nnn in the graph, making 'this' go dead public void subsume( Node nnn ) { assert nnn!=this; @@ -536,7 +486,6 @@ public abstract class Node implements Cloneable { */ public abstract Node idealize(); - // Some of the peephole rules get complex, and search further afield than // just the nearest neighbor. These peepholes can fail the pattern match // on a node some distance away, and if that node ever changes we should @@ -577,7 +526,6 @@ public abstract class Node implements Cloneable { _deps.clear(); } - // Two nodes are equal if they have the same inputs and the same "opcode" // which means the same Java class, plus same internal parts. @Override public final boolean equals( Object o ) { @@ -595,7 +543,6 @@ public abstract class Node implements Cloneable { // and can assume "this!=n" and has the same Java class. public boolean eq( Node n ) { return true; } - // Cached hash. If zero, then not computed AND this Node is NOT in the GVN // table - and can have its edges hacked (which will change his hash // anyway). If Non-Zero then this Node is IN the GVN table, or is being @@ -611,7 +558,6 @@ public abstract class Node implements Cloneable { _hash=0; // Out of table now } - // Hash of opcode and inputs @Override public final int hashCode() { if( _hash != 0 ) return _hash; @@ -631,7 +577,6 @@ public abstract class Node implements Cloneable { /** Is this Node Memory related */ public boolean isMem() { return false; } - // Semantic change to the graph (so NOT a peephole), used by the Parser. // If any input is a float, flip to a float-flavored opcode and widen any // non-float input. @@ -652,7 +597,6 @@ public abstract class Node implements Cloneable { } Node copyF() { return null; } - // ------------------------------------------------------------------------ // Peephole utilities @@ -679,7 +623,6 @@ public abstract class Node implements Cloneable { return true; } - // Make a shallow copy (same class) of this Node, with given inputs and // empty outputs and a new Node ID. The original inputs are ignored. // Does not need to be implemented in isCFG() nodes. diff --git a/chapter22/src/main/java/com/seaofnodes/simple/node/NotNode.java b/chapter22/src/main/java/com/seaofnodes/simple/node/NotNode.java index 118ef5c8..57fa9301 100644 --- a/chapter22/src/main/java/com/seaofnodes/simple/node/NotNode.java +++ b/chapter22/src/main/java/com/seaofnodes/simple/node/NotNode.java @@ -1,19 +1,15 @@ package com.seaofnodes.simple.node; + import com.seaofnodes.simple.Utils; import com.seaofnodes.simple.type.*; -import java.util.BitSet; public class NotNode extends Node { public NotNode(Node in) { super(null, in); } @Override public String label() { return "Not"; } - @Override - public StringBuilder _print1(StringBuilder sb, BitSet visited) { - in(1)._print0(sb.append("(!"), visited); - return sb.append(")"); - } + @Override protected String format() { return "(!%1)"; } @Override public TypeInteger compute() { diff --git a/chapter22/src/main/java/com/seaofnodes/simple/node/ParmNode.java b/chapter22/src/main/java/com/seaofnodes/simple/node/ParmNode.java index f75e7c64..3e8e3711 100644 --- a/chapter22/src/main/java/com/seaofnodes/simple/node/ParmNode.java +++ b/chapter22/src/main/java/com/seaofnodes/simple/node/ParmNode.java @@ -1,8 +1,9 @@ package com.seaofnodes.simple.node; +import com.seaofnodes.print.ExprPrinter; + import com.seaofnodes.simple.Utils; import com.seaofnodes.simple.type.Type; -import java.util.BitSet; public class ParmNode extends PhiNode { @@ -20,18 +21,12 @@ public class ParmNode extends PhiNode { public FunNode fun() { return (FunNode)in(0); } @Override - public StringBuilder _print1(StringBuilder sb, BitSet visited) { + protected ExprPrinter<Node> _print1(ExprPrinter<Node> p) { if( "main".equals(fun()._name) && _label.equals("arg") ) - return sb.append("arg"); - sb.append("Parm_").append(_label).append("("); - for( Node in : _inputs ) { - if (in == null) sb.append("____"); - else in._print0(sb, visited); - sb.append(","); - } - sb.setLength(sb.length()-1); - sb.append(")"); - return sb; + return p.p("arg"); + p.p("Parm_").p(_label).open(); + for( Node in : _inputs ) p.n(in).p(","); + return p.unchar(',').close(); } diff --git a/chapter22/src/main/java/com/seaofnodes/simple/node/PhiNode.java b/chapter22/src/main/java/com/seaofnodes/simple/node/PhiNode.java index 5d0c842f..8aa123f7 100644 --- a/chapter22/src/main/java/com/seaofnodes/simple/node/PhiNode.java +++ b/chapter22/src/main/java/com/seaofnodes/simple/node/PhiNode.java @@ -1,8 +1,9 @@ package com.seaofnodes.simple.node; +import com.seaofnodes.print.ExprPrinter; + import com.seaofnodes.simple.*; import com.seaofnodes.simple.type.*; -import java.util.BitSet; public class PhiNode extends Node { @@ -31,18 +32,12 @@ public class PhiNode extends Node { @Override public String label() { return "Phi_"+MemOpNode.mlabel(_label); } @Override - public StringBuilder _print1(StringBuilder sb, BitSet visited) { + protected ExprPrinter<Node> _print1(ExprPrinter<Node> p) { if( !(region() instanceof RegionNode r) || r.inProgress() ) - sb.append("Z"); - sb.append("Phi("); - for( Node in : _inputs ) { - if (in == null) sb.append("____"); - else in._print0(sb, visited); - sb.append(","); - } - sb.setLength(sb.length()-1); - sb.append(")"); - return sb; + p.p("Z"); + p.p("Phi("); + for( Node in : _inputs ) p.n(in).p(","); + return p.unchar(',').close(); } public CFGNode region() { return (CFGNode)in(0); } diff --git a/chapter22/src/main/java/com/seaofnodes/simple/node/ProjNode.java b/chapter22/src/main/java/com/seaofnodes/simple/node/ProjNode.java index 48f92525..26b3a522 100644 --- a/chapter22/src/main/java/com/seaofnodes/simple/node/ProjNode.java +++ b/chapter22/src/main/java/com/seaofnodes/simple/node/ProjNode.java @@ -1,10 +1,11 @@ package com.seaofnodes.simple.node; +import com.seaofnodes.print.ExprPrinter; + import com.seaofnodes.simple.type.Type; import com.seaofnodes.simple.type.TypeMem; import com.seaofnodes.simple.type.TypeTuple; -import java.util.BitSet; public class ProjNode extends Node { @@ -24,11 +25,11 @@ public class ProjNode extends Node { @Override public String label() { return _label; } @Override - public StringBuilder _print1(StringBuilder sb, BitSet visited) { - if( _label != null ) return sb.append(_label); + protected ExprPrinter<Node> _print1(ExprPrinter<Node> p) { + if( _label != null ) return p.p(_label); if( in(0) instanceof CallEndNode cend && cend.call()!=null ) - return cend.call()._print0(sb,visited); - return sb.append("LONELY PROJ"); + return p.n(cend.call()); + return p.p("LONELY PROJ"); } @Override public CFGNode cfg0() { diff --git a/chapter22/src/main/java/com/seaofnodes/simple/node/ReadOnlyNode.java b/chapter22/src/main/java/com/seaofnodes/simple/node/ReadOnlyNode.java index d8fe6286..94c1b6f6 100644 --- a/chapter22/src/main/java/com/seaofnodes/simple/node/ReadOnlyNode.java +++ b/chapter22/src/main/java/com/seaofnodes/simple/node/ReadOnlyNode.java @@ -1,8 +1,8 @@ package com.seaofnodes.simple.node; + import com.seaofnodes.simple.type.Type; import com.seaofnodes.simple.type.TypeMemPtr; -import java.util.BitSet; /** * Cast a pointer to read-only @@ -12,10 +12,7 @@ public class ReadOnlyNode extends Node { public ReadOnlyNode( ReadOnlyNode n ) { super(n); } @Override public String label() { return "ReadOnly"; } - @Override - public StringBuilder _print1(StringBuilder sb, BitSet visited) { - return in(1)._print0(sb.append("(const)"),visited); - } + @Override protected String format() { return "(const)%1"; } @Override public Type compute() { Type t = in(1)._type; return t instanceof TypeMemPtr tmp ? tmp.makeRO() : t; diff --git a/chapter22/src/main/java/com/seaofnodes/simple/node/RegionNode.java b/chapter22/src/main/java/com/seaofnodes/simple/node/RegionNode.java index 84383845..79b7f53a 100644 --- a/chapter22/src/main/java/com/seaofnodes/simple/node/RegionNode.java +++ b/chapter22/src/main/java/com/seaofnodes/simple/node/RegionNode.java @@ -1,5 +1,7 @@ package com.seaofnodes.simple.node; +import com.seaofnodes.print.ExprPrinter; + import com.seaofnodes.simple.*; import com.seaofnodes.simple.Parser; import com.seaofnodes.simple.codegen.CodeGen; @@ -17,9 +19,8 @@ public class RegionNode extends CFGNode { @Override public String label() { return "Region"; } - @Override - public StringBuilder _print1(StringBuilder sb, BitSet visited) { - return sb.append(label()); + @Override protected ExprPrinter<Node> _print1(ExprPrinter<Node> p) { + return p.p(label()); } @Override public boolean blockHead() { return true; } diff --git a/chapter22/src/main/java/com/seaofnodes/simple/node/ReturnNode.java b/chapter22/src/main/java/com/seaofnodes/simple/node/ReturnNode.java index 05b19682..e0ab863a 100644 --- a/chapter22/src/main/java/com/seaofnodes/simple/node/ReturnNode.java +++ b/chapter22/src/main/java/com/seaofnodes/simple/node/ReturnNode.java @@ -1,5 +1,7 @@ package com.seaofnodes.simple.node; +import com.seaofnodes.print.ExprPrinter; + import com.seaofnodes.simple.Parser; import com.seaofnodes.simple.SB; import com.seaofnodes.simple.Utils; @@ -7,7 +9,6 @@ import com.seaofnodes.simple.codegen.CodeGen; import com.seaofnodes.simple.codegen.RegMask; import com.seaofnodes.simple.codegen.Encoding; import com.seaofnodes.simple.type.*; -import java.util.BitSet; /** Keeps all preceding memory effects and the return value alive: {ctrl, $mem, value, rpc}. */ public class ReturnNode extends CFGNode { @@ -30,11 +31,11 @@ public class ReturnNode extends CFGNode { public String label() { return "Return"; } @Override - public StringBuilder _print1(StringBuilder sb, BitSet visited) { - sb.append("return "); - if( expr()==null ) sb.append("----"); - else expr()._print0(sb, visited); - return sb.append(";"); + protected ExprPrinter<Node> _print1(ExprPrinter<Node> p) { + p.p("return "); + if( expr()==null ) p.p("----"); + else p.n(expr()); + return p.p(";"); } // No one unique control follows; can be many call end sites diff --git a/chapter22/src/main/java/com/seaofnodes/simple/node/RoundF32Node.java b/chapter22/src/main/java/com/seaofnodes/simple/node/RoundF32Node.java index 2ad034d6..78e7698c 100644 --- a/chapter22/src/main/java/com/seaofnodes/simple/node/RoundF32Node.java +++ b/chapter22/src/main/java/com/seaofnodes/simple/node/RoundF32Node.java @@ -1,19 +1,16 @@ package com.seaofnodes.simple.node; + import com.seaofnodes.simple.type.Type; import com.seaofnodes.simple.type.TypeFloat; -import java.util.BitSet; public class RoundF32Node extends Node { public RoundF32Node(Node lhs) { super(null, lhs); } @Override public String label() { return "RoundF32"; } - @Override - public StringBuilder _print1(StringBuilder sb, BitSet visited) { - return in(1)._print0(sb.append("((f32)"), visited).append(")"); - } + @Override protected String format() { return "((f32)%1)"; } @Override public Type compute() { diff --git a/chapter22/src/main/java/com/seaofnodes/simple/node/ScopeNode.java b/chapter22/src/main/java/com/seaofnodes/simple/node/ScopeNode.java index 0c9bb881..3f110cde 100644 --- a/chapter22/src/main/java/com/seaofnodes/simple/node/ScopeNode.java +++ b/chapter22/src/main/java/com/seaofnodes/simple/node/ScopeNode.java @@ -1,5 +1,7 @@ package com.seaofnodes.simple.node; +import com.seaofnodes.print.ExprPrinter; + import com.seaofnodes.simple.*; import com.seaofnodes.simple.codegen.CodeGen; import com.seaofnodes.simple.type.*; @@ -52,28 +54,26 @@ public class ScopeNode extends Node { @Override public String label() { return "Scope"; } @Override - public StringBuilder _print1(StringBuilder sb, BitSet visited) { - sb.append("Scope[ "); + protected ExprPrinter<Node> _print1(ExprPrinter<Node> p) { + p.p("Scope[ "); int j=1; for( int i=0; i<nIns(); i++ ) { - if( j < _lexSize._len && i == _lexSize.at(j) ) { sb.append("| "); j++; } + if( j < _lexSize._len && i == _lexSize.at(j) ) { p.p("| "); j++; } Var v = _vars.at(i); - sb.append(v._type().print(new SB())); - sb.append(" "); - if( v._final ) sb.append("!"); - sb.append(v._name); - sb.append("="); + p.p(v._type().print(new SB())); + p.p(" "); + if( v._final ) p.p("!"); + p.p(v._name); + p.p("="); Node n = in(i); while( n instanceof ScopeNode loop ) { - sb.append("Lazy_"); + p.p("Lazy_"); n = loop.in(i); } - if( n==null ) sb.append("___"); - else n._print0(sb, visited); - sb.append(", "); + p.n(n); + p.p(", "); } - sb.setLength(sb.length()-2); - return sb.append("]"); + return p.unchar(", ").p("]"); } diff --git a/chapter22/src/main/java/com/seaofnodes/simple/node/SplitNode.java b/chapter22/src/main/java/com/seaofnodes/simple/node/SplitNode.java index 3a1ed011..ff18b292 100644 --- a/chapter22/src/main/java/com/seaofnodes/simple/node/SplitNode.java +++ b/chapter22/src/main/java/com/seaofnodes/simple/node/SplitNode.java @@ -1,20 +1,21 @@ package com.seaofnodes.simple.node; +import com.seaofnodes.print.ExprPrinter; + import com.seaofnodes.simple.SB; import com.seaofnodes.simple.codegen.CodeGen; import com.seaofnodes.simple.type.Type; -import java.util.BitSet; 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; } @Override public String op() { return "mov"; } - @Override public StringBuilder _print1(StringBuilder sb, BitSet visited) { - sb.append("mov("); - if( in(1) == null ) sb.append("---"); - else in(1)._print0(sb,visited); - return sb.append(")"); + @Override protected ExprPrinter<Node> _print1(ExprPrinter<Node> p) { + p.p("mov("); + if( in(1) == null ) p.p("---"); + else p.n(in(1)); + return p.close(); } @Override public Type compute() { return in(0)._type; } @Override public Node idealize() { return null; } diff --git a/chapter22/src/main/java/com/seaofnodes/simple/node/StartNode.java b/chapter22/src/main/java/com/seaofnodes/simple/node/StartNode.java index 91bf85a1..cbaefa6a 100644 --- a/chapter22/src/main/java/com/seaofnodes/simple/node/StartNode.java +++ b/chapter22/src/main/java/com/seaofnodes/simple/node/StartNode.java @@ -1,9 +1,10 @@ package com.seaofnodes.simple.node; +import com.seaofnodes.print.ExprPrinter; + import com.seaofnodes.simple.codegen.CodeGen; import com.seaofnodes.simple.Parser; import com.seaofnodes.simple.type.*; -import java.util.BitSet; import java.util.HashSet; import static com.seaofnodes.simple.Utils.TODO; @@ -17,9 +18,8 @@ public class StartNode extends LoopNode implements MultiNode { @Override public String label() { return "Start"; } - @Override - public StringBuilder _print1(StringBuilder sb, BitSet visited) { - return sb.append(label()); + @Override protected ExprPrinter<Node> _print1(ExprPrinter<Node> p) { + return p.p(label()); } @Override public boolean blockHead() { return true; } diff --git a/chapter22/src/main/java/com/seaofnodes/simple/node/StopNode.java b/chapter22/src/main/java/com/seaofnodes/simple/node/StopNode.java index 2363db2c..298c24a9 100644 --- a/chapter22/src/main/java/com/seaofnodes/simple/node/StopNode.java +++ b/chapter22/src/main/java/com/seaofnodes/simple/node/StopNode.java @@ -1,8 +1,9 @@ package com.seaofnodes.simple.node; +import com.seaofnodes.print.ExprPrinter; + import com.seaofnodes.simple.Utils; import com.seaofnodes.simple.type.Type; -import java.util.BitSet; public class StopNode extends CFGNode { @@ -21,18 +22,18 @@ public class StopNode extends CFGNode { } @Override - public StringBuilder _print1(StringBuilder sb, BitSet visited) { + protected ExprPrinter<Node> _print1(ExprPrinter<Node> p) { // For the sake of many old tests, and single value prints as "return val" ReturnNode ret1 = ret(); - if( ret1!=null ) return ret1._print0(sb,visited); - sb.append("Stop[ "); + if( ret1!=null ) return p.n(ret1); + p.p("Stop[ "); for( Node ret : _inputs ) if( ret!=null ) { String name = ((ReturnNode)ret).fun()._name; if( name== null || !name.startsWith("sys.") ) - ret._print0(sb, visited).append(" "); + p.n(ret).p(" "); } - return sb.append("]"); + return p.p("]"); } @Override public boolean blockHead() { return true; } diff --git a/chapter22/src/main/java/com/seaofnodes/simple/node/StoreNode.java b/chapter22/src/main/java/com/seaofnodes/simple/node/StoreNode.java index 99adfdfc..5e8b77f4 100644 --- a/chapter22/src/main/java/com/seaofnodes/simple/node/StoreNode.java +++ b/chapter22/src/main/java/com/seaofnodes/simple/node/StoreNode.java @@ -1,9 +1,10 @@ package com.seaofnodes.simple.node; +import com.seaofnodes.print.ExprPrinter; + import com.seaofnodes.simple.codegen.*; import com.seaofnodes.simple.*; import com.seaofnodes.simple.type.*; -import java.util.BitSet; /** * Store represents setting a value to a memory based object, in chapter 10 @@ -36,8 +37,8 @@ public class StoreNode extends MemOpNode { public Node val() { return in(4); } @Override - public StringBuilder _print1(StringBuilder sb, BitSet visited) { - return sb.append(".").append(_name).append("=").append( val()).append(";"); + protected ExprPrinter<Node> _print1(ExprPrinter<Node> p) { + return p.p(".").p(_name).p("=").p( val()).p(";"); } @Override diff --git a/chapter22/src/main/java/com/seaofnodes/simple/node/StructNode.java b/chapter22/src/main/java/com/seaofnodes/simple/node/StructNode.java index 4efc0de9..3782d64a 100644 --- a/chapter22/src/main/java/com/seaofnodes/simple/node/StructNode.java +++ b/chapter22/src/main/java/com/seaofnodes/simple/node/StructNode.java @@ -1,8 +1,9 @@ package com.seaofnodes.simple.node; +import com.seaofnodes.print.ExprPrinter; + import com.seaofnodes.simple.SB; import com.seaofnodes.simple.type.*; -import java.util.BitSet; /** * Build a compound object @@ -14,16 +15,15 @@ public class StructNode extends Node { @Override public String label() { return _ts==null ? "STRUCT?" : _ts.str(); } @Override - public StringBuilder _print1(StringBuilder sb, BitSet visited) { - if( _ts==null ) return sb.append("STRUCT?"); - sb.append(_ts._name).append(" {"); + protected ExprPrinter<Node> _print1(ExprPrinter<Node> p) { + if( _ts==null ) return p.p("STRUCT?"); + p.p(_ts._name).p(" {"); for( int i=0; i<nIns(); i++ ) { - sb.append(_ts._fields[i]._fname).append(":"); - sb.append((in(i)==null ? Type.BOTTOM : in(i)._type).print(new SB())); - sb.append("; "); + p.p(_ts._fields[i]._fname).p(":"); + p.p((in(i)==null ? Type.BOTTOM : in(i)._type).print(new SB())); + p.p("; "); } - sb.setLength(sb.length()-2); - return sb.append("}"); + return p.unchar("; ").p("}"); } @Override diff --git a/chapter22/src/main/java/com/seaofnodes/simple/node/SubFNode.java b/chapter22/src/main/java/com/seaofnodes/simple/node/SubFNode.java index 73cf9de5..2d218a03 100644 --- a/chapter22/src/main/java/com/seaofnodes/simple/node/SubFNode.java +++ b/chapter22/src/main/java/com/seaofnodes/simple/node/SubFNode.java @@ -1,21 +1,16 @@ package com.seaofnodes.simple.node; + import com.seaofnodes.simple.type.Type; import com.seaofnodes.simple.type.TypeFloat; -import java.util.BitSet; public class SubFNode extends Node { public SubFNode(Node lhs, Node rhs) { super(null, lhs, rhs); } @Override public String label() { return "SubF"; } - @Override - public StringBuilder _print1(StringBuilder sb, BitSet visited) { - in(1)._print0(sb.append("("), visited); - in(2)._print0(sb.append("-"), visited); - return sb.append(")"); - } + @Override protected String format() { return "(%1-%2)"; } @Override public Type compute() { diff --git a/chapter22/src/main/java/com/seaofnodes/simple/node/ToFloatNode.java b/chapter22/src/main/java/com/seaofnodes/simple/node/ToFloatNode.java index 8ef5e40a..7b0122ce 100644 --- a/chapter22/src/main/java/com/seaofnodes/simple/node/ToFloatNode.java +++ b/chapter22/src/main/java/com/seaofnodes/simple/node/ToFloatNode.java @@ -1,20 +1,17 @@ package com.seaofnodes.simple.node; + import com.seaofnodes.simple.type.Type; import com.seaofnodes.simple.type.TypeFloat; import com.seaofnodes.simple.type.TypeInteger; -import java.util.BitSet; public class ToFloatNode extends Node { public ToFloatNode(Node lhs) { super(null, lhs); } @Override public String label() { return "ToFloat"; } - @Override - public StringBuilder _print1(StringBuilder sb, BitSet visited) { - return in(1)._print0(sb.append("(flt)"), visited); - } + @Override protected String format() { return "(flt)%1"; } @Override public Type compute() { diff --git a/chapter22/src/main/java/com/seaofnodes/simple/node/XCtrlNode.java b/chapter22/src/main/java/com/seaofnodes/simple/node/XCtrlNode.java index 8c620a04..477b9af8 100644 --- a/chapter22/src/main/java/com/seaofnodes/simple/node/XCtrlNode.java +++ b/chapter22/src/main/java/com/seaofnodes/simple/node/XCtrlNode.java @@ -1,14 +1,15 @@ package com.seaofnodes.simple.node; +import com.seaofnodes.print.ExprPrinter; + import com.seaofnodes.simple.codegen.CodeGen; import com.seaofnodes.simple.Parser; import com.seaofnodes.simple.type.Type; -import java.util.BitSet; public class XCtrlNode extends CFGNode { public XCtrlNode() { super(new Node[]{CodeGen.CODE._start}); } @Override public String label() { return "Xctrl"; } - @Override public StringBuilder _print1(StringBuilder sb, BitSet visited) { return sb.append("Xctrl"); } + @Override protected ExprPrinter<Node> _print1(ExprPrinter<Node> p) { return p.p("Xctrl"); } @Override public boolean isConst() { return true; } @Override public Type compute() { return Type.XCONTROL; } @Override public Node idealize() { return null; } diff --git a/chapter22/src/main/java/com/seaofnodes/simple/node/cpus/arm/MemOpARM.java b/chapter22/src/main/java/com/seaofnodes/simple/node/cpus/arm/MemOpARM.java index bec0acc5..afd8723e 100644 --- a/chapter22/src/main/java/com/seaofnodes/simple/node/cpus/arm/MemOpARM.java +++ b/chapter22/src/main/java/com/seaofnodes/simple/node/cpus/arm/MemOpARM.java @@ -1,12 +1,13 @@ package com.seaofnodes.simple.node.cpus.arm; +import com.seaofnodes.print.ExprPrinter; + import com.seaofnodes.simple.*; import com.seaofnodes.simple.codegen.*; import com.seaofnodes.simple.node.*; import com.seaofnodes.simple.type.*; import java.lang.StringBuilder; -import java.util.BitSet; public abstract class MemOpARM extends MemOpNode implements MachNode { @@ -32,7 +33,7 @@ public abstract class MemOpARM extends MemOpNode implements MachNode { @Override public String label() { return op();} Node val() { return in(4); } // Only for stores - @Override public StringBuilder _printMach(StringBuilder sb, BitSet visited) { return sb.append(".").append(_name); } + @Override protected ExprPrinter<Node> _printMach(ExprPrinter<Node> p) { return p.p(".").p(_name); } @Override public Type compute() { throw Utils.TODO(); } @Override public Node idealize() { throw Utils.TODO(); } diff --git a/chapter22/src/main/java/com/seaofnodes/simple/node/cpus/arm/UJmpARM.java b/chapter22/src/main/java/com/seaofnodes/simple/node/cpus/arm/UJmpARM.java index a69c3c7c..bf46a7b1 100644 --- a/chapter22/src/main/java/com/seaofnodes/simple/node/cpus/arm/UJmpARM.java +++ b/chapter22/src/main/java/com/seaofnodes/simple/node/cpus/arm/UJmpARM.java @@ -1,19 +1,17 @@ package com.seaofnodes.simple.node.cpus.arm; + import com.seaofnodes.simple.*; import com.seaofnodes.simple.codegen.*; import com.seaofnodes.simple.node.*; import com.seaofnodes.simple.type.Type; -import java.util.BitSet; // unconditional jump public class UJmpARM extends CFGNode implements MachNode, RIPRelSize { UJmpARM() { } @Override public String op() { return "jmp"; } @Override public String label() { return op(); } - @Override public StringBuilder _print1( StringBuilder sb, BitSet visited ) { - return sb.append("jmp "); - } + @Override protected String format() { return "jmp "; } @Override public RegMask regmap(int i) {return null; } @Override public RegMask outregmap() { return null; } @Override public Type compute() { throw Utils.TODO(); } diff --git a/chapter22/src/main/java/com/seaofnodes/simple/node/cpus/riscv/BranchRISC.java b/chapter22/src/main/java/com/seaofnodes/simple/node/cpus/riscv/BranchRISC.java index 44ff4e8b..f6dc5cf2 100644 --- a/chapter22/src/main/java/com/seaofnodes/simple/node/cpus/riscv/BranchRISC.java +++ b/chapter22/src/main/java/com/seaofnodes/simple/node/cpus/riscv/BranchRISC.java @@ -1,9 +1,10 @@ package com.seaofnodes.simple.node.cpus.riscv; +import com.seaofnodes.print.ExprPrinter; + import com.seaofnodes.simple.*; import com.seaofnodes.simple.codegen.*; import com.seaofnodes.simple.node.*; -import java.util.BitSet; // Conditional branch such as: BEQ public class BranchRISC extends IfNode implements MachNode, RIPRelSize { @@ -30,14 +31,14 @@ public class BranchRISC extends IfNode implements MachNode, RIPRelSize { } } - @Override public StringBuilder _print1(StringBuilder sb, BitSet visited) { - sb.append("if( "); - if( in(1)==null ) sb.append("0"); - else in(1)._print0(sb,visited); - sb.append(_bop); - if( in(2)==null ) sb.append("0"); - else in(2)._print0(sb,visited); - return sb.append(" )"); + @Override protected ExprPrinter<Node> _print1(ExprPrinter<Node> p) { + p.p("if( "); + if( in(1)==null ) p.p("0"); + else p.n(in(1)); + p.p(_bop); + if( in(2)==null ) p.p("0"); + else p.n(in(2)); + return p.p(" )"); } @Override public void encoding( Encoding enc ) { diff --git a/chapter22/src/main/java/com/seaofnodes/simple/node/cpus/riscv/ImmRISC.java b/chapter22/src/main/java/com/seaofnodes/simple/node/cpus/riscv/ImmRISC.java index 9e7f456a..8847d2b7 100644 --- a/chapter22/src/main/java/com/seaofnodes/simple/node/cpus/riscv/ImmRISC.java +++ b/chapter22/src/main/java/com/seaofnodes/simple/node/cpus/riscv/ImmRISC.java @@ -1,10 +1,11 @@ package com.seaofnodes.simple.node.cpus.riscv; +import com.seaofnodes.print.ExprPrinter; + import com.seaofnodes.simple.*; import com.seaofnodes.simple.codegen.*; import com.seaofnodes.simple.node.*; import com.seaofnodes.simple.type.TypeInteger; -import java.util.BitSet; abstract public class ImmRISC extends MachConcreteNode implements MachNode { public final int _imm12; @@ -28,10 +29,10 @@ abstract public class ImmRISC extends MachConcreteNode implements MachNode { return in(1) instanceof LUI || in(1) instanceof AUIPC; } - @Override public StringBuilder _print1(StringBuilder sb, BitSet visited) { + @Override protected ExprPrinter<Node> _print1(ExprPrinter<Node> p) { int imm12 = (_imm12<<20)>>20; // Sign extend 12 bits - in(1)._print0(sb.append("( "), visited); - return sb.append(String.format(" %s #%d )",glabel(),imm12)); + p.p("( ").n(in(1)); + return p.p(String.format(" %s #%d )",glabel(),imm12)); } abstract int opcode(); diff --git a/chapter22/src/main/java/com/seaofnodes/simple/node/cpus/riscv/MemOpRISC.java b/chapter22/src/main/java/com/seaofnodes/simple/node/cpus/riscv/MemOpRISC.java index 8b84a2b9..c2025a3d 100644 --- a/chapter22/src/main/java/com/seaofnodes/simple/node/cpus/riscv/MemOpRISC.java +++ b/chapter22/src/main/java/com/seaofnodes/simple/node/cpus/riscv/MemOpRISC.java @@ -1,11 +1,12 @@ package com.seaofnodes.simple.node.cpus.riscv; +import com.seaofnodes.print.ExprPrinter; + import com.seaofnodes.simple.SB; import com.seaofnodes.simple.Utils; import com.seaofnodes.simple.codegen.*; import com.seaofnodes.simple.node.*; import com.seaofnodes.simple.type.*; -import java.util.BitSet; public abstract class MemOpRISC extends MemOpNode implements MachNode { final int _off; // Limit 12 bits @@ -23,7 +24,7 @@ public abstract class MemOpRISC extends MemOpNode implements MachNode { @Override public String label() { return op(); } Node val() { return in(4); } // Only for stores - @Override public StringBuilder _printMach(StringBuilder sb, BitSet visited) { return sb.append(".").append(_name); } + @Override protected ExprPrinter<Node> _printMach(ExprPrinter<Node> p) { return p.p(".").p(_name); } @Override public Type compute() { throw Utils.TODO(); } @Override public Node idealize() { throw Utils.TODO(); } diff --git a/chapter22/src/main/java/com/seaofnodes/simple/node/cpus/riscv/UJmpRISC.java b/chapter22/src/main/java/com/seaofnodes/simple/node/cpus/riscv/UJmpRISC.java index 6473d81c..3868990d 100644 --- a/chapter22/src/main/java/com/seaofnodes/simple/node/cpus/riscv/UJmpRISC.java +++ b/chapter22/src/main/java/com/seaofnodes/simple/node/cpus/riscv/UJmpRISC.java @@ -1,16 +1,17 @@ package com.seaofnodes.simple.node.cpus.riscv; +import com.seaofnodes.print.ExprPrinter; + import com.seaofnodes.simple.*; import com.seaofnodes.simple.codegen.*; import com.seaofnodes.simple.node.*; import com.seaofnodes.simple.type.Type; -import java.util.BitSet; // unconditional jump public class UJmpRISC extends CFGNode implements MachNode, RIPRelSize { @Override public String op() { return "jmp"; } @Override public String label() { return op(); } - @Override public StringBuilder _print1( StringBuilder sb, BitSet visited ) { return sb.append("jmp "); } + @Override protected ExprPrinter<Node> _print1(ExprPrinter<Node> p) { return p.p("jmp "); } @Override public RegMask regmap(int i) {return null; } @Override public RegMask outregmap() { return null; } @Override public Type compute() { throw Utils.TODO(); } diff --git a/chapter22/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/MemOpX86.java b/chapter22/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/MemOpX86.java index 9f80b1f5..fa3cdd13 100644 --- a/chapter22/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/MemOpX86.java +++ b/chapter22/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/MemOpX86.java @@ -1,12 +1,13 @@ package com.seaofnodes.simple.node.cpus.x86_64_v2; +import com.seaofnodes.print.ExprPrinter; + import com.seaofnodes.simple.*; import com.seaofnodes.simple.codegen.*; import com.seaofnodes.simple.node.*; import com.seaofnodes.simple.type.*; import java.lang.StringBuilder; -import java.util.BitSet; // Generic X86 memory operand base. // inputs: @@ -53,8 +54,8 @@ public abstract class MemOpX86 extends MemOpNode implements MachNode { Node idx() { return in(3); } Node val() { return in(4); } // Only for stores, including op-to-memory - @Override public StringBuilder _printMach(StringBuilder sb, BitSet visited) { - return sb.append(".").append(_name); + @Override protected ExprPrinter<Node> _printMach(ExprPrinter<Node> p) { + return p.p(".").p(_name); } @Override public String label() { return op(); } diff --git a/chapter22/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/StoreX86.java b/chapter22/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/StoreX86.java index 76fb4e8d..22a0bd79 100644 --- a/chapter22/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/StoreX86.java +++ b/chapter22/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/StoreX86.java @@ -1,5 +1,7 @@ package com.seaofnodes.simple.node.cpus.x86_64_v2; +import com.seaofnodes.print.ExprPrinter; + import com.seaofnodes.simple.SB; import com.seaofnodes.simple.codegen.*; import com.seaofnodes.simple.node.ConstantNode; @@ -7,19 +9,18 @@ import com.seaofnodes.simple.node.Node; import com.seaofnodes.simple.node.StoreNode; import com.seaofnodes.simple.type.Type; import com.seaofnodes.simple.type.TypeFloat; -import java.util.BitSet; public class StoreX86 extends MemOpX86 { StoreX86( StoreNode st, Node base, Node idx, int off, int scale, int imm, Node val ) { super(st,st, base, idx, off, scale, imm, val); } @Override public String op() { return "st"+_sz; } - @Override public StringBuilder _printMach(StringBuilder sb, BitSet visited) { + @Override protected ExprPrinter<Node> _printMach(ExprPrinter<Node> p) { Node val = val(); - sb.append(".").append(_name).append("="); - if( val==null ) sb.append(_imm); - else val._print0(sb,visited); - return sb.append(";"); + p.p(".").p(_name).p("="); + if( val==null ) p.p(_imm); + else p.n(val); + return p.p(";"); } // Register mask allowed as a result. 0 for no register. @Override public RegMask outregmap() { return null; } diff --git a/chapter22/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/UJmpX86.java b/chapter22/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/UJmpX86.java index ec4eeb3b..5db9e75e 100644 --- a/chapter22/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/UJmpX86.java +++ b/chapter22/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/UJmpX86.java @@ -1,19 +1,17 @@ package com.seaofnodes.simple.node.cpus.x86_64_v2; + import com.seaofnodes.simple.*; import com.seaofnodes.simple.codegen.*; import com.seaofnodes.simple.node.*; import com.seaofnodes.simple.type.Type; -import java.util.BitSet; // unconditional jump public class UJmpX86 extends CFGNode implements MachNode, RIPRelSize { UJmpX86() { } @Override public String op() { return "jmp"; } @Override public String label() { return op(); } - @Override public StringBuilder _print1( StringBuilder sb, BitSet visited ) { - return sb.append("jmp "); - } + @Override protected String format() { return "jmp "; } @Override public RegMask regmap(int i) {return null; } @Override public RegMask outregmap() { return null; } @Override public Type compute() { throw Utils.TODO(); } diff --git a/chapter22/src/main/java/com/seaofnodes/simple/print/ASMPrinter.java b/chapter22/src/main/java/com/seaofnodes/simple/print/ASMPrinter.java index c8082841..1cc83813 100644 --- a/chapter22/src/main/java/com/seaofnodes/simple/print/ASMPrinter.java +++ b/chapter22/src/main/java/com/seaofnodes/simple/print/ASMPrinter.java @@ -1,306 +1,85 @@ package com.seaofnodes.simple.print; -import com.seaofnodes.simple.Ary; -import com.seaofnodes.simple.SB; -import com.seaofnodes.simple.Utils; +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.codegen.Encoding; -import com.seaofnodes.simple.codegen.Encoding.Relo; +import com.seaofnodes.simple.SB; import com.seaofnodes.simple.node.*; import com.seaofnodes.simple.type.*; -import java.util.Collections; -import java.util.IdentityHashMap; -import java.util.Set; - -public abstract class ASMPrinter { +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) { - if( code._cfg==null ) - return sb.p("Need _cfg set, run after GCM"); - - // instruction address - int iadr = 0; - for( int i=0; i<code._cfg._len; i++ ) - if( code._cfg.at(i) instanceof FunNode fun ) - iadr = print(iadr,sb,code,fun,i); - - // constant pool - iadr = (iadr+15)&-16; // pad to 16 - Encoding enc = code._encoding; - if( enc!=null && !enc._bigCons.isEmpty() && iadr < enc._bits.size() ) { - // radix sort the big constants by alignment - Ary<Relo>[] raligns = new Ary[5]; - for( Relo relo : enc._bigCons.values() ) { - int align = relo._align; - Ary<Relo> relos = raligns[align]==null ? (raligns[align]=new Ary<>( Relo.class)) : raligns[align]; - relos.add(relo); - } - - Set<Type> targets = Collections.newSetFromMap(new IdentityHashMap<>()); - sb.p("--- Constant Pool ------").nl(); - - // By alignment - for( int align = 4; align >= 0; align-- ) { - Ary<Relo> relos = raligns[align]; - if( relos == null ) continue; - for( Relo relo : relos ) { - if( targets.contains(relo._t) ) continue; - targets.add(relo._t); - sb.hex2(iadr).p(" "); - switch( relo._t ) { - case TypeTuple tt -> { - for( Type tx : tt._types ) { - pN(enc,sb,iadr,align).p(" "); - iadr += (1<<align); - } - } - - case TypeStruct ts -> { - int sz = relo._structSize; - int log = 1<<align; - sz = (sz + (log -1)) & -log; // Round up final padding - for( int i=0; i<sz; i++ ) - sb.hex1(enc.read1(iadr++)); - } - - // Simple primitive (e.g. larger int, float) - default -> { - pN(enc,sb,iadr,align).fix(9-(1<<align),""); - iadr += (1<<align); - } - } - relo._t.print(sb).nl(); - } - } - } - - return sb; + return sb.p(new com.seaofnodes.print.ASMPrinter<>(new ASMPrinter(code)).print()); } - - private static SB pN( Encoding enc, SB sb, int iadr, int log ) { - switch( log ) { - case 0: sb.hex1(enc.read1(iadr)); break; - case 1: sb.hex2(enc.read2(iadr)); break; - case 2: sb.hex4(enc.read4(iadr)); break; - case 3: sb.hex8(enc.read8(iadr)); break; - } - return sb; + @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; } - - - private static int print(int iadr, SB sb, CodeGen code, FunNode fun, int cfgidx) { - FunNode old=null; - if( code._encoding!=null ) { - old = code._encoding._fun; - code._encoding._fun = fun; // Useful printing after RA + @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(' '); } - // Function header - sb.nl().p("---"); - if( fun._name != null ) sb.p(fun._name).p(" "); - fun.sig().print(sb); - sb.p("---------------------------").nl(); - iadr = (iadr + 15)&-16; // All function entries padded to 16 align - - if( fun._frameAdjust != 0 ) - iadr = doInst(iadr,sb,code,fun,cfgidx,fun,true,true); - while( !(code._cfg.at(cfgidx) instanceof ReturnNode) ) - iadr = doBlock(iadr,sb,code,fun,cfgidx++); - - // Function separator - sb.p("---"); - fun.sig().print(sb); - sb.p("---------------------------").nl(); - if( code._encoding != null ) - code._encoding._fun = old; - return iadr; + return sb.toString(); } - - static private final int opWidth = 5; - static private final int argWidth = 30; - static int doBlock(int iadr, SB sb, CodeGen code, FunNode fun, int cfgidx) { - final int encWidth = code._mach==null ? 2 : code._mach.defaultOpSize()*2; - CFGNode bb = code._cfg.at(cfgidx); - if( bb != fun && !(bb instanceof IfNode) && !(bb instanceof CallEndNode) && !(bb instanceof CallNode) && !(bb instanceof CProjNode && bb.in(0) instanceof CallEndNode )) - sb.p(label(bb)).p(":").nl(); - if( bb instanceof CallNode ) return iadr; - final boolean postAlloc = code._phase.ordinal() > CodeGen.Phase.RegAlloc.ordinal(); - final boolean postEncode= code._phase.ordinal() >=CodeGen.Phase.Encoding.ordinal(); - - boolean once=false; - for( Node n : bb.outs() ) { - if( !(n instanceof PhiNode phi) ) continue; - if( phi._type instanceof TypeMem || phi._type instanceof TypeRPC ) continue; // Nothing for the hidden ones - // Post-RegAlloc phi prints all on one line - if( postAlloc ) { - if( !once ) { once=true; sb.fix(4," ").p(" ").fix(encWidth,"").p(" "); } - sb.p(phi._label).p(':').p(code.reg(phi,fun)).p(','); - } else { - // Pre-RegAlloc phi prints one line per - sb.fix(4," ").p(" ").fix(encWidth,"").p(" ").fix(opWidth,phi._label).p(" ").p(code.reg(phi,fun)); - if( phi.getClass() == PhiNode.class ) { - sb.p(" = phi( "); - for( int i=1; i<phi.nIns(); i++ ) - sb.p("N").p(phi.in(i)._nid).p(","); - sb.unchar().p(" )"); - } - sb.nl(); - } - } - if( once ) sb.unchar().nl(); - - // All the non-phis - for( int i=0; i<bb.nOuts(); i++ ) - if( !(bb.out(i) instanceof PhiNode) ) - iadr = doInst(iadr, sb,code, fun, cfgidx, bb.out(i),postAlloc, postEncode ); - - return iadr; + @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); } - - static int doInst( int iadr, SB sb, CodeGen code, FunNode fun, int cfgidx, Node n, boolean postAlloc, boolean postEncode ) { - if( n==null || n instanceof CProjNode ) return iadr; - if( postAlloc && n instanceof CalleeSaveNode ) return iadr; - if( postEncode && n instanceof ProjNode ) return iadr; - if( n instanceof MemMergeNode ) return iadr; - if( n.getClass() == ConstantNode.class ) return iadr; // Default placeholders - final int dopz = code._mach==null ? 2 : code._mach.defaultOpSize(); - final int encWidth = dopz*2; - - // All blocks ending in a Region will need to either fall into or jump - // to this block. Until the post-reg-alloc block layout cleanup, we - // need to assume a jump. There's no real hardware op here, yet. - if( n instanceof RegionNode cfg && !(n instanceof FunNode) ) { - if( postEncode ) return iadr; // All jumps inserted already - while( cfgidx < code._cfg._len-1 ) { - CFGNode next = code._cfg.at(++cfgidx); - if( next == n ) return iadr; // Fall-through, no branch - if( next.nOuts()>1 ) - break; // Has code in the block, need to jump around - // No code in the block, can fall through it - } - sb.hex2(iadr++).p(" ").fix(encWidth,"??").p(" ").fix(opWidth,"JMP").p(" ").fix(argWidth,label(cfg)).nl(); - return iadr; - } - - // ProjNodes following a multi (e.g. Call or New results), - // get indent slightly and just print their index & node# - if( n instanceof ProjNode proj ) { - if( proj._type instanceof TypeMem ) return iadr; // Nothing for the hidden ones - sb.fix(4," ").p(" ").fix(encWidth,"").p(" ").fix(opWidth,proj._label==null ? "---" : proj._label).p(" ").p(code.reg(n,fun)).nl(); - return iadr; - } - - // ADDR ENCODING Op--- dst = src op src // Comment - // 1234 abcdefgh ld4 RAX = [Rbase + off] // Comment - sb.hex2(iadr).p(" "); - - // Encoding - int fatEncoding = 0; - if( code._encoding != null && code._encoding._opLen!=null ) { - int size = code._encoding._opLen[n._nid]; - if( code._asmLittle ) - for( int i=0; i<Math.min(size,dopz); i++ ) - sb.hex1(code._encoding._bits.buf()[iadr++]); - else { - iadr += Math.min(size,dopz); - for( int i=0; i<Math.min(size,dopz); i++ ) - sb.hex1(code._encoding._bits.buf()[iadr-i-1]); - } - for( int i=size*2; i<encWidth; i++ ) - sb.p(" "); - fatEncoding = size - (encWidth>>1); // Not-printed parts of encoding - } else - sb.fix(encWidth,""); - sb.p(" "); - - // Op; generally "ld4" or "call" - sb.fix(opWidth, n instanceof MachNode mach ? mach.op() : n.label()).p(" "); - - // General asm args - String isMultiOp = null; - if( n instanceof MachNode mach ) { - int old = sb.len(); - mach.asm(code,sb); - int len = sb.len(); - isMultiOp = isMultiOp(sb,old,len); - sb.fix(argWidth-(len-old),""); // Pad out - - } else if( !(n._type instanceof TypeMem) ) { - // Room for some inputs - sb.fix(5, n._nid+":" ); - int off = 0; - for( int i=0; i<n.nIns(); i++ ) { - sb.fix(5, n.in(i) == null ? "___" : String.valueOf(n.in(i)._nid)); - off += 5; - if( off >= argWidth ) break; - } - if( off < argWidth ) sb.fix(argWidth-off,""); - } - sb.p(" "); - - // Comment - String comment = n.comment(); - if( comment!=null ) sb.p("// ").p(comment); - - sb.nl(); - - // Printing more op bits than fit - if( isMultiOp != null && code._encoding != null && code._encoding._opLen!=null ) { - // Multiple ops, template style, no RA, no scheduling. Print out - // one-line-per-newline, with encoding bits up front. - int size = code._encoding._opLen[n._nid]; - int off = Math.min(size,dopz); - while( isMultiOp!=null ) { - sb.hex2(iadr).p(" "); - int len = Math.min(size-off,dopz); - for( int i=0; i<len; i++ ) - sb.hex1(code._encoding._bits.buf()[iadr++]); - off += len; - for( int i=len; i<dopz; i++ ) sb.p(" "); - sb.p(" "); - int x = isMultiOp.indexOf('\n'); - if( x== -1 ) { // Last line - sb.p(isMultiOp).nl(); - isMultiOp = null; - } else { - sb.p(isMultiOp.substring(0,x+1)); // Includes the newline - isMultiOp = isMultiOp.substring(x+1); - } - - } - - } else if( fatEncoding > 0 ) { - // Extra bytes past the default encoding width, all put on a line by - // themselves. X86 special for super long encodings - sb.hex2(iadr).p(" "); - for( int i=0; i<fatEncoding; i++ ) - sb.hex1(code._encoding._bits.buf()[iadr++]); - sb.nl(); - } - - - // MultiNodes are immediately followed by projection(s) - if( !(n instanceof CFGNode) && n instanceof MultiNode ) { - for( Node proj : n._outputs ) { - if( proj instanceof ProjNode ) // it could also be an ante-dep - doInst(iadr,sb,code,fun, cfgidx, proj,postAlloc,postEncode); - } - } - - return iadr; + @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; } - - private static String label( CFGNode bb ) { - return (bb instanceof LoopNode ? "LOOP" : "L")+bb._nid; + @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; } - - private static String isMultiOp(SB sb, int old, int len) { - for( int i=old; i<len; i++ ) - if( sb.at(i)=='\n' ) { - String s = sb.subString(i+1,len); - sb.setLen(i); - return s; - } - return null; + @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/chapter22/src/main/java/com/seaofnodes/simple/print/IRPrinter.java b/chapter22/src/main/java/com/seaofnodes/simple/print/IRPrinter.java index ffa1d742..e4d719f4 100644 --- a/chapter22/src/main/java/com/seaofnodes/simple/print/IRPrinter.java +++ b/chapter22/src/main/java/com/seaofnodes/simple/print/IRPrinter.java @@ -1,352 +1,61 @@ package com.seaofnodes.simple.print; -import com.seaofnodes.simple.Ary; -import com.seaofnodes.simple.SB; -import com.seaofnodes.simple.Utils; -import com.seaofnodes.simple.codegen.CodeGen; +import com.seaofnodes.print.IRAdapter; import com.seaofnodes.simple.node.*; -import com.seaofnodes.simple.type.TypeFunPtr; import java.util.ArrayList; -import java.util.BitSet; -import java.util.HashMap; - -public abstract class IRPrinter { - - // Print a node on 1 line, columnar aligned, as: - // NNID NNAME DDEF DDEF [[ UUSE UUSE ]] TYPE - // 1234 sssss 1234 1234 1234 1234 1234 1234 tttttt - public static SB printLine( Node n, SB sb ) { - if( n==null ) return sb; - sb.p("%4d %-7.7s ".formatted(n._nid,n.label())); - if( n.isDead() ) - return sb.p("DEAD\n"); - for( Node def : n._inputs ) - sb.p(def==null ? "____" : "%4d".formatted(def._nid)) - // Lazy Phi indicator - .p(n instanceof MemMergeNode && def instanceof MemMergeNode ? "^" : " "); - for( int i = n._inputs.size(); i<4; i++ ) - sb.p(" "); - sb.p(" [[ "); - for( Node use : n._outputs ) - sb.p(use==null ? "____ " : "%4d ".formatted(use._nid)); - int lim = 6 - Math.max(n._inputs.size(),4); - for( int i = n._outputs.size(); i<lim; i++ ) - sb.p(" "); - sb.p(" ]] "); - if( n._type!= null ) sb.p(n._type.str()); - return sb.p("\n"); - } - - - public static String prettyPrint(Node node, int depth) { - return CodeGen.CODE._phase.ordinal() > CodeGen.Phase.Schedule.ordinal() - ? _prettyPrintScheduled( node, depth ) - : _prettyPrint( node, depth ); - } - - // Another bulk pretty-printer. Makes more effort at basic-block grouping. - private static String _prettyPrint( Node node, int depth ) { - // First, a Breadth First Search at a fixed depth. - BFS bfs = new BFS(node,depth); - // Convert just that set to a post-order - ArrayList<Node> rpos = new ArrayList<>(); - BitSet visit = new BitSet(); - for( int i=bfs._lim; i< bfs._bfs.size(); i++ ) - postOrd( bfs._bfs.get(i), null, rpos, visit, bfs._bs); - // Reverse the post-order walk - SB sb = new SB(); - boolean gap=false; - for( int i=rpos.size()-1; i>=0; i-- ) { - Node n = rpos.get(i); - if( n instanceof CFGNode || n instanceof MultiNode ) { - if( !gap ) sb.p("\n"); // Blank before multihead - if( n instanceof FunNode fun ) - fun.sig().print(sb.p("--- ").p(fun._name==null ? "" : fun._name).p(" "),false).p("----------------------\n"); - printLine( n, sb ); // Print head - while( --i >= 0 ) { - Node t = rpos.get(i); - if( !(t.in(0) instanceof MultiNode) ) { i++; break; } - printLine( t, sb ); - } - if( n instanceof ReturnNode ret ) { - FunNode fun = ret.fun(); - sb.p("--- "); - if( fun != null ) - fun.sig().print(sb.p(fun._name==null ? "" : fun._name).p(" "),false); - sb.p("----------------------\n"); - } - if( !(n instanceof CallNode) ) { - sb.p("\n"); // Blank after multitail - gap = true; - } - } else { - printLine( n, sb ); - gap = false; - } - } - return sb.toString(); - } - - private static void postOrd(Node n, Node prior, ArrayList<Node> rpos, BitSet visit, BitSet bfs) { - if( !bfs.get(n._nid) ) - return; // Not in the BFS visit - if( n instanceof FunNode && !(prior instanceof StartNode) ) - return; // Only visit Fun from Start - if( visit.get(n._nid) ) return; // Already post-order walked - visit.set(n._nid); - // First walk the CFG, then everything - if( n instanceof CFGNode ) { - for( Node use : n._outputs ) - // Follow CFG, not across call/function borders, and not around backedges - if( use instanceof CFGNode && !(n instanceof CallNode && use instanceof FunNode) && - use.nOuts() >= 1 && !(use._outputs.get(0) instanceof LoopNode) ) - postOrd(use, n, rpos,visit,bfs); - for( Node use : n._outputs ) - // Follow CFG, not across call/function borders - if( use instanceof CFGNode && !(n instanceof CallNode && use instanceof FunNode) ) - postOrd(use,n,rpos,visit,bfs); - } - // Follow all outputs - for( Node use : n._outputs ) - if( use != null && - !(n instanceof CallNode && use instanceof FunNode) && - (n instanceof FunNode || !(use instanceof ParmNode)) ) - postOrd(use, n, rpos,visit,bfs); - // Post-order - rpos.add(n); - } - - // Breadth-first search, broken out in a class to keep in more independent. - // Maintains a root-set of Nodes at the limit (or past by 1 if MultiHead). - public static class BFS { - // A breadth first search, plus MultiHeads for any MultiTails - public final ArrayList<Node> _bfs; - public final BitSet _bs; // Visited members by node id - public final int _depth; // Depth limit - public final int _lim; // From here to _bfs._len can be roots for a reverse search - public BFS( Node base, int d ) { - _depth = d; - _bfs = new ArrayList<>(); - _bs = new BitSet(); - - add(base); // Prime the pump - int idx=0, lim=1; // Limit is where depth counter changes - while( idx < _bfs.size() ) { // Ran out of nodes below depth - Node n = _bfs.get(idx++); - for( Node def : n._inputs ) - if( def!=null && !_bs.get(def._nid) ) - add(def); - if( idx==lim ) { // Depth counter changes at limit - if( --d < 0 ) - break; // Ran out of depth - lim = _bfs.size(); // New depth limit - } - } - // Toss things past the limit except multi-heads - while( idx < _bfs.size() ) { - Node n = _bfs.get(idx); - if( n instanceof MultiNode ) idx++; - else del(idx); - } - // Root set is any node with no inputs in the visited set - lim = _bfs.size(); - for( int i=_bfs.size()-1; i>=0; i-- ) - if( !any_visited(_bfs.get(i)) ) - swap( i,--lim); - _lim = lim; - } - void swap( int x, int y ) { - if( x==y ) return; - Node tx = _bfs.get(x); - Node ty = _bfs.get(y); - _bfs.set(x,ty); - _bfs.set(y,tx); - } - void add(Node n) { - _bfs.add(n); - _bs.set(n._nid); - } - void del(int idx) { - _bs.clear(_bfs.get(idx)._nid); - Utils.del(_bfs, idx); - } - boolean any_visited( Node n ) { - for( Node def : n._inputs ) - if( def!=null && _bs.get(def._nid) ) - return true; - return false; - } - } - - public static String _prettyPrint( CodeGen code ) { - SB sb = new SB(); - // Print the Start "block" - printLine(code._start,sb); - for( Node n : code._start._outputs ) - printLine(n,sb); - sb.nl(); - - // Skip start, stop - for( int i=1; i<code._cfg._len-1; i++ ) { - CFGNode blk = code._cfg.at(i); - if( blk.blockHead() && (!(blk instanceof CProjNode) || (blk.cfg0() instanceof IfNode )) ) { - if( blk instanceof FunNode fun ) - sb.p("--- ").p(fun.label()).p(" ---------------------------").nl(); - // Print block header - sb.p("%-13.13s".formatted(label(blk)+":")); - sb.p( " ".repeat(4) ).p(" [[ "); - if( blk instanceof RegionNode ) - for( int j=1; j<blk.nIns(); j++ ) - label(sb,blk.cfg(j)); - else - label(sb,blk.cfg(0)); - sb.p(" ]] \n"); - } - printLine(blk,sb); - if( blk instanceof ReturnNode ret ) - sb.p("--- ").p(ret.fun().label()).p(" ---------------------------").nl(); - - // Block contents - for( Node n : blk._outputs ) { - if( n instanceof CFGNode cfg ) continue; - printLine(n,sb); - if( !(n instanceof CFGNode) && n instanceof MultiNode ) - for( Node use : n._outputs ) - if( use instanceof ProjNode ) - printLine(use,sb); - } - } - - printLine(code._stop,sb); - return sb.toString(); - } - - // Diagnostic block ordering from raw control edges. Do not call idepth(): - // it fills compiler caches (and can walk lazy dominator accessors). - private static int _idepth(CFGNode cfg, HashMap<Integer,Integer> depths) { - if( cfg == null || cfg instanceof StartNode || cfg instanceof FunNode ) return cfg instanceof FunNode ? 1 : 0; - Integer old = depths.get(cfg._nid); - if( old != null ) return old; - depths.put(cfg._nid,0); // Break cycles in partially constructed graphs. - int d = 0; - if( cfg instanceof LoopNode ) { - d = _idepth((CFGNode)cfg.in(1),depths)+1; - } else if( cfg instanceof RegionNode || cfg instanceof StopNode ) { - for( Node n : cfg._inputs ) - if( n instanceof CFGNode pred ) d = Math.max(d,_idepth(pred,depths)+1); - } else if( cfg.in(0) instanceof CFGNode pred ) { - d = _idepth(pred,depths)+1; - } - depths.put(cfg._nid,d); - return d; - } - - // Bulk pretty printer, knowing scheduling information is available - private static String _prettyPrintScheduled( Node node, int depth ) { - // Backwards DFS walk to depth. - HashMap<Integer,Integer> ds = new HashMap<>(); - Ary<Node> ns = new Ary<>(Node.class); - _walk(ds,ns,node,depth); - // Remove data projections, these are force-printed behind their multinode head - for( int i=0; i<ns.size(); i++ ) { - if( ns.get(i) instanceof ProjNode proj && !(proj.in(0) instanceof CFGNode) ) { - ns.del(i--); - ds.remove(proj._nid); - } - } - // Print by block with least diagnostic depth - HashMap<Integer,Integer> depths = new HashMap<>(); - SB sb = new SB(); - Ary<Node> bns = new Ary<>(Node.class); - while( !ds.isEmpty() ) { - CFGNode blk = null; - for( Node n : ns ) { - CFGNode cfg = n instanceof CFGNode cfg0 && cfg0.blockHead() ? cfg0 : n.cfg0(); - if( blk==null || _idepth(cfg,depths) < _idepth(blk,depths) ) - blk = cfg; - } - Integer d = ds.remove(blk._nid); - ns.del(ns.find(blk)); - - // Print block header - sb.p("%-13.13s".formatted(label(blk)+":")); - sb.p( " ".repeat(4) ).p(" [[ "); - if( blk instanceof StartNode ) ; - else if( blk instanceof RegionNode || blk instanceof StopNode ) - for( int i=(blk instanceof StopNode ? 3 : 1); i<blk.nIns(); i++ ) - label(sb,blk.cfg(i)); - else - label(sb,blk.cfg(0)); - sb.p(" ]] \n"); - printLine(blk,sb); - - // Collect block contents that are in the depth limit - bns.clear(); - int xd = Integer.MAX_VALUE; - for( Node use : blk._outputs ) { - Integer i = ds.get(use._nid); - if( i!=null && !(use instanceof CFGNode cfg && cfg.blockHead()) ) { - if( bns.find(use)==-1 ) - bns.add(use); - xd = Math.min(xd,i); - } - } - // Print Phis up front, if any - for( int i=0; i<bns.size(); i++ ) - if( bns.get(i) instanceof PhiNode phi ) - printLine( phi, sb,bns,i--,ds,ns); - - // Print block contents in depth order, bumping depth until whole block printed - for( ; !bns.isEmpty(); xd++ ) - for( int i=0; i<bns.size(); i++ ) { - Node n = bns.get(i); - if( ds.get(n._nid)==xd ) { - printLine( n, sb, bns, i--, ds,ns ); - if( n instanceof MultiNode && !(n instanceof CFGNode) ) { - for( Node use : n._outputs ) { - if( use instanceof ProjNode ) - printLine(use,sb,bns,bns.indexOf(use),ds,ns); - } - } - } - } - sb.p("\n"); - } - return sb.toString(); - } - - private static void _walk( HashMap<Integer,Integer> ds, Ary<Node> ns, Node node, int d ) { - Integer nd = ds.get(node._nid); - if( nd!=null && d <= nd ) return; // Been there, done that - Integer old = ds.put(node._nid,d) ; - if( old == null ) - ns.add(node); - if( d == 0 ) return; // Depth cutoff - for( Node def : node._inputs ) - if( def != null && - !(node instanceof LoopNode loop && loop.back()==def) && - // Don't walk into or out of functions - !(node instanceof CallEndNode && def instanceof ReturnNode) && - !(node instanceof FunNode && def instanceof CallNode) && - !(node instanceof ParmNode && !(def instanceof FunNode)) - ) - _walk(ds,ns,def,d-1); - } +import com.seaofnodes.simple.SB; +import com.seaofnodes.simple.codegen.CodeGen; - static String label( CFGNode blk ) { - if( blk instanceof StartNode ) return "START"; - return (blk instanceof LoopNode ? "LOOP" : "L")+blk._nid; - } - static void label( SB sb, CFGNode blk ) { - if( !blk.blockHead() ) blk = blk.cfg(0); - sb.p( "%-9.9s ".formatted( label( blk ) ) ); +/** 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); } - static void printLine( Node n, SB sb, Ary<Node> bns, int i, HashMap<Integer,Integer> ds, Ary<Node> ns ) { - printLine( n, sb ); - if( i != -1 ) bns.del(i); - ds.remove(n._nid); - int idx = ns.find(n); - if( idx!=-1 ) ns.del(idx); - } - } diff --git a/chapter22/src/main/java/com/seaofnodes/simple/print/SimpleGraphAdapter.java b/chapter22/src/main/java/com/seaofnodes/simple/print/SimpleGraphAdapter.java index d3f22a6d..3d10a80c 100644 --- a/chapter22/src/main/java/com/seaofnodes/simple/print/SimpleGraphAdapter.java +++ b/chapter22/src/main/java/com/seaofnodes/simple/print/SimpleGraphAdapter.java @@ -1,45 +1,25 @@ 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 com.seaofnodes.simple.type.TypeMem; -import java.util.ArrayList; /** Chapter 22'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); } - @Override protected int nDeps(Node n) { return n.nDeps(); } - @Override protected Node dep(Node n, int idx) { return n.dep(idx); } - private ArrayList<Edge> edges(Node n) { - var edges = new ArrayList<Edge>(); - for( int i = 0; i < n.nIns(); i++ ) { - String name = n instanceof ScopeNode scope && i < scope._vars.size() + @Override protected String edgeName(Node n, int i) { + return n instanceof ScopeNode scope && i < scope._vars.size() ? scope._vars.get(i)._name : null; - int jump = n instanceof CallEndNode && i>0 && n.in(i) instanceof ReturnNode ret - ? ref(ret.fun()) : 0; - edges.add(new Edge(i, ref(n.in(i)), role(n, i), name, jump)); - } - return edges; } - - @Override protected GraphSnapshot.Node desc(Node n) { - Projection proj = n instanceof ProjNode p ? new Projection(ref(n.in(0)), p._idx) - : n instanceof CProjNode 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, folding(n)); + @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; } - private boolean folding(Node n) { + @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(); @@ -49,7 +29,7 @@ public class SimpleGraphAdapter extends GraphAdapter<Node> { return false; } - private Kind kind(Node n) { + @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; @@ -60,7 +40,7 @@ public class SimpleGraphAdapter extends GraphAdapter<Node> { return n instanceof CFGNode ? Kind.CTRL : isMem(n) ? Kind.MEM : Kind.DATA; } - private Role role(Node n, int i) { + @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 ) |
