summaryrefslogtreecommitdiff
path: root/chapter25/src/main/java/com/seaofnodes
diff options
context:
space:
mode:
Diffstat (limited to 'chapter25/src/main/java/com/seaofnodes')
-rw-r--r--chapter25/src/main/java/com/seaofnodes/simple/node/ArithNode.java10
-rw-r--r--chapter25/src/main/java/com/seaofnodes/simple/node/BoolNode.java10
-rw-r--r--chapter25/src/main/java/com/seaofnodes/simple/node/CProjNode.java5
-rw-r--r--chapter25/src/main/java/com/seaofnodes/simple/node/CallEndNode.java14
-rw-r--r--chapter25/src/main/java/com/seaofnodes/simple/node/CallNode.java16
-rw-r--r--chapter25/src/main/java/com/seaofnodes/simple/node/ConFldOffNode.java9
-rw-r--r--chapter25/src/main/java/com/seaofnodes/simple/node/ConstantNode.java16
-rw-r--r--chapter25/src/main/java/com/seaofnodes/simple/node/ConvertNode.java7
-rw-r--r--chapter25/src/main/java/com/seaofnodes/simple/node/CtrlNode.java5
-rw-r--r--chapter25/src/main/java/com/seaofnodes/simple/node/EscapeNode.java17
-rw-r--r--chapter25/src/main/java/com/seaofnodes/simple/node/ExternNode.java1
-rw-r--r--chapter25/src/main/java/com/seaofnodes/simple/node/FRefNode.java8
-rw-r--r--chapter25/src/main/java/com/seaofnodes/simple/node/FldOffNode.java9
-rw-r--r--chapter25/src/main/java/com/seaofnodes/simple/node/FunPtrNode.java10
-rw-r--r--chapter25/src/main/java/com/seaofnodes/simple/node/GuardNode.java8
-rw-r--r--chapter25/src/main/java/com/seaofnodes/simple/node/IfNode.java13
-rw-r--r--chapter25/src/main/java/com/seaofnodes/simple/node/LoadNode.java4
-rw-r--r--chapter25/src/main/java/com/seaofnodes/simple/node/MachConcreteNode.java12
-rw-r--r--chapter25/src/main/java/com/seaofnodes/simple/node/MemMergeNode.java19
-rw-r--r--chapter25/src/main/java/com/seaofnodes/simple/node/MemOpNode.java6
-rw-r--r--chapter25/src/main/java/com/seaofnodes/simple/node/MinusNode.java8
-rw-r--r--chapter25/src/main/java/com/seaofnodes/simple/node/NeverNode.java5
-rw-r--r--chapter25/src/main/java/com/seaofnodes/simple/node/NewNode.java8
-rw-r--r--chapter25/src/main/java/com/seaofnodes/simple/node/Node.java70
-rw-r--r--chapter25/src/main/java/com/seaofnodes/simple/node/NotNode.java8
-rw-r--r--chapter25/src/main/java/com/seaofnodes/simple/node/ParmNode.java19
-rw-r--r--chapter25/src/main/java/com/seaofnodes/simple/node/PhiNode.java19
-rw-r--r--chapter25/src/main/java/com/seaofnodes/simple/node/ProjNode.java11
-rw-r--r--chapter25/src/main/java/com/seaofnodes/simple/node/PtrToIntNode.java6
-rw-r--r--chapter25/src/main/java/com/seaofnodes/simple/node/ReadOnlyNode.java7
-rw-r--r--chapter25/src/main/java/com/seaofnodes/simple/node/RegionNode.java7
-rw-r--r--chapter25/src/main/java/com/seaofnodes/simple/node/ReturnNode.java13
-rw-r--r--chapter25/src/main/java/com/seaofnodes/simple/node/RoundF32Node.java7
-rw-r--r--chapter25/src/main/java/com/seaofnodes/simple/node/ScopeNode.java28
-rw-r--r--chapter25/src/main/java/com/seaofnodes/simple/node/SplitNode.java13
-rw-r--r--chapter25/src/main/java/com/seaofnodes/simple/node/StartNode.java8
-rw-r--r--chapter25/src/main/java/com/seaofnodes/simple/node/StopNode.java13
-rw-r--r--chapter25/src/main/java/com/seaofnodes/simple/node/StoreNode.java7
-rw-r--r--chapter25/src/main/java/com/seaofnodes/simple/node/ToFloatNode.java7
-rw-r--r--chapter25/src/main/java/com/seaofnodes/simple/node/XCtrlNode.java5
-rw-r--r--chapter25/src/main/java/com/seaofnodes/simple/node/cpus/arm/MemOpARM.java5
-rw-r--r--chapter25/src/main/java/com/seaofnodes/simple/node/cpus/arm/UJmpARM.java6
-rw-r--r--chapter25/src/main/java/com/seaofnodes/simple/node/cpus/riscv/BranchRISC.java19
-rw-r--r--chapter25/src/main/java/com/seaofnodes/simple/node/cpus/riscv/ImmRISC.java9
-rw-r--r--chapter25/src/main/java/com/seaofnodes/simple/node/cpus/riscv/MemOpRISC.java5
-rw-r--r--chapter25/src/main/java/com/seaofnodes/simple/node/cpus/riscv/UJmpRISC.java5
-rw-r--r--chapter25/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/MemOpX86.java7
-rw-r--r--chapter25/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/StoreX86.java13
-rw-r--r--chapter25/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/UJmpX86.java6
-rw-r--r--chapter25/src/main/java/com/seaofnodes/simple/print/ASMPrinter.java367
-rw-r--r--chapter25/src/main/java/com/seaofnodes/simple/print/IRPrinter.java329
-rw-r--r--chapter25/src/main/java/com/seaofnodes/simple/print/SimpleGraphAdapter.java42
52 files changed, 376 insertions, 905 deletions
diff --git a/chapter25/src/main/java/com/seaofnodes/simple/node/ArithNode.java b/chapter25/src/main/java/com/seaofnodes/simple/node/ArithNode.java
index bb370a56..bc47ebfc 100644
--- a/chapter25/src/main/java/com/seaofnodes/simple/node/ArithNode.java
+++ b/chapter25/src/main/java/com/seaofnodes/simple/node/ArithNode.java
@@ -1,12 +1,13 @@
package com.seaofnodes.simple.node;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.Parser;
import com.seaofnodes.simple.codegen.CodeGen;
import com.seaofnodes.simple.type.*;
import com.seaofnodes.simple.util.BAOS;
import com.seaofnodes.simple.util.Utils;
-import java.util.BitSet;
import java.util.HashMap;
import java.util.IdentityHashMap;
@@ -23,11 +24,8 @@ public abstract class ArithNode extends Node implements ModeNode {
}
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/chapter25/src/main/java/com/seaofnodes/simple/node/BoolNode.java b/chapter25/src/main/java/com/seaofnodes/simple/node/BoolNode.java
index f720d02d..73e786e3 100644
--- a/chapter25/src/main/java/com/seaofnodes/simple/node/BoolNode.java
+++ b/chapter25/src/main/java/com/seaofnodes/simple/node/BoolNode.java
@@ -1,11 +1,12 @@
package com.seaofnodes.simple.node;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.Parser;
import com.seaofnodes.simple.codegen.CodeGen;
import com.seaofnodes.simple.type.*;
import com.seaofnodes.simple.util.BAOS;
import com.seaofnodes.simple.util.Utils;
-import java.util.BitSet;
import java.util.HashMap;
import java.util.IdentityHashMap;
import static com.seaofnodes.simple.type.TypeInteger.*;
@@ -23,11 +24,8 @@ abstract public class BoolNode extends Node implements ModeNode {
abstract public String op(); // String opcode name
- @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/chapter25/src/main/java/com/seaofnodes/simple/node/CProjNode.java b/chapter25/src/main/java/com/seaofnodes/simple/node/CProjNode.java
index b74619a3..12fde6c0 100644
--- a/chapter25/src/main/java/com/seaofnodes/simple/node/CProjNode.java
+++ b/chapter25/src/main/java/com/seaofnodes/simple/node/CProjNode.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.codegen.Serialize;
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeTuple;
import com.seaofnodes.simple.util.BAOS;
-import java.util.BitSet;
import java.util.HashMap;
import java.util.IdentityHashMap;
@@ -35,7 +36,7 @@ public class CProjNode extends CFGNode implements Proj {
@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/chapter25/src/main/java/com/seaofnodes/simple/node/CallEndNode.java b/chapter25/src/main/java/com/seaofnodes/simple/node/CallEndNode.java
index d2286c09..2e921301 100644
--- a/chapter25/src/main/java/com/seaofnodes/simple/node/CallEndNode.java
+++ b/chapter25/src/main/java/com/seaofnodes/simple/node/CallEndNode.java
@@ -1,11 +1,12 @@
package com.seaofnodes.simple.node;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.Parser;
import com.seaofnodes.simple.codegen.*;
import com.seaofnodes.simple.type.*;
import com.seaofnodes.simple.util.BAOS;
-import java.util.BitSet;
import java.util.HashMap;
import java.util.IdentityHashMap;
@@ -64,13 +65,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/chapter25/src/main/java/com/seaofnodes/simple/node/CallNode.java b/chapter25/src/main/java/com/seaofnodes/simple/node/CallNode.java
index c053f377..84f1e705 100644
--- a/chapter25/src/main/java/com/seaofnodes/simple/node/CallNode.java
+++ b/chapter25/src/main/java/com/seaofnodes/simple/node/CallNode.java
@@ -1,5 +1,7 @@
package com.seaofnodes.simple.node;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.Parser;
import com.seaofnodes.simple.codegen.CodeGen;
import com.seaofnodes.simple.type.Type;
@@ -9,7 +11,6 @@ import com.seaofnodes.simple.type.TypeRPC;
import com.seaofnodes.simple.type.XInt;
import com.seaofnodes.simple.util.BAOS;
import com.seaofnodes.simple.util.Utils;
-import java.util.BitSet;
import java.util.HashMap;
import java.util.IdentityHashMap;
@@ -27,15 +28,14 @@ public class CallNode extends CFGNode {
public void packed( BAOS baos, HashMap<String,Integer> strs, HashMap<Type,Integer> types, IdentityHashMap<Node, Integer> anodes ) { baos.packed1(nIns()); }
static Node make( BAOS bais ) { return new CallNode(null,new Node[bais.packed1()]); }
- @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/chapter25/src/main/java/com/seaofnodes/simple/node/ConFldOffNode.java b/chapter25/src/main/java/com/seaofnodes/simple/node/ConFldOffNode.java
index 468721a4..f94fa484 100644
--- a/chapter25/src/main/java/com/seaofnodes/simple/node/ConFldOffNode.java
+++ b/chapter25/src/main/java/com/seaofnodes/simple/node/ConFldOffNode.java
@@ -1,5 +1,7 @@
package com.seaofnodes.simple.node;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.Parser;
import com.seaofnodes.simple.codegen.CodeGen;
import com.seaofnodes.simple.type.Type;
@@ -7,7 +9,6 @@ import com.seaofnodes.simple.type.TypeInteger;
import com.seaofnodes.simple.type.TypeStruct;
import com.seaofnodes.simple.util.SB;
import com.seaofnodes.simple.util.Utils;
-import java.util.BitSet;
import java.util.HashMap;
/**
@@ -25,11 +26,9 @@ public class ConFldOffNode extends ConstantNode {
@Override public String label() {
return _fname == " len" ? "sizeof("+_ts._name+")" : "#"+_fname;
}
- @Override public String uniqueName() { return "Off_" + _nid; }
- @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 Node idealize() {
diff --git a/chapter25/src/main/java/com/seaofnodes/simple/node/ConstantNode.java b/chapter25/src/main/java/com/seaofnodes/simple/node/ConstantNode.java
index 1dc369d3..47a7bbf6 100644
--- a/chapter25/src/main/java/com/seaofnodes/simple/node/ConstantNode.java
+++ b/chapter25/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.type.Type;
import com.seaofnodes.simple.type.TypeFunPtr;
import com.seaofnodes.simple.util.BAOS;
-import java.util.BitSet;
import java.util.HashMap;
import java.util.IdentityHashMap;
@@ -66,19 +67,22 @@ public class ConstantNode extends TypeNode {
// own the constructor function; the class FunPtr does.
public static ConstantNode seed( Type type ) { return new ConstantNode(type,true); }
- @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 Node copy() { return raw(this); }
@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.toString());
+ return p.p(_con==null ? "---" : _con.toString());
}
@Override public boolean isConst() { return true; }
diff --git a/chapter25/src/main/java/com/seaofnodes/simple/node/ConvertNode.java b/chapter25/src/main/java/com/seaofnodes/simple/node/ConvertNode.java
index 4e8e93ce..4ee5521a 100644
--- a/chapter25/src/main/java/com/seaofnodes/simple/node/ConvertNode.java
+++ b/chapter25/src/main/java/com/seaofnodes/simple/node/ConvertNode.java
@@ -1,10 +1,11 @@
package com.seaofnodes.simple.node;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.Parser;
import com.seaofnodes.simple.codegen.CodeGen;
import com.seaofnodes.simple.type.*;
-import java.util.BitSet;
import java.util.HashMap;
// Convert a value to an authoritative destination type. The destination is
@@ -24,8 +25,8 @@ public class ConvertNode extends Node {
public Node val() { return in(1); }
@Override public String label() { return "Convert_"+_dst.str(); }
- @Override public StringBuilder _print1(StringBuilder sb, BitSet visited) {
- return val()._print0(sb.append(label()).append("("),visited).append(")");
+ @Override protected ExprPrinter<Node> _print1(ExprPrinter<Node> p) {
+ return p.p(label()).open().n(val()).close();
}
// The declaration fixes the result family during pessimistic parsing.
diff --git a/chapter25/src/main/java/com/seaofnodes/simple/node/CtrlNode.java b/chapter25/src/main/java/com/seaofnodes/simple/node/CtrlNode.java
index 39c95aa4..62140873 100644
--- a/chapter25/src/main/java/com/seaofnodes/simple/node/CtrlNode.java
+++ b/chapter25/src/main/java/com/seaofnodes/simple/node/CtrlNode.java
@@ -1,15 +1,16 @@
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 Tag serialTag() { throw com.seaofnodes.simple.util.Utils.TODO(); }
@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/chapter25/src/main/java/com/seaofnodes/simple/node/EscapeNode.java b/chapter25/src/main/java/com/seaofnodes/simple/node/EscapeNode.java
index 5be4d3e8..3e95fffb 100644
--- a/chapter25/src/main/java/com/seaofnodes/simple/node/EscapeNode.java
+++ b/chapter25/src/main/java/com/seaofnodes/simple/node/EscapeNode.java
@@ -1,8 +1,9 @@
package com.seaofnodes.simple.node;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.type.*;
import com.seaofnodes.simple.util.*;
-import java.util.BitSet;
import java.util.HashMap;
import java.util.IdentityHashMap;
@@ -43,13 +44,13 @@ public class EscapeNode extends TypeNode {
}
@Override
- public StringBuilder _print1(StringBuilder sb, BitSet visited) {
- sb.append("Esc#").append(fld()._alias).append(" {");
- if( self()==null ) sb.append("---");
- else self()._print0(sb,visited).append(",");
- priv()._print0(sb,visited).append("}, ");
- pub ()._print0(sb,visited);
- return sb;
+ protected ExprPrinter<Node> _print1(ExprPrinter<Node> p) {
+ p.p("Esc#").p(fld()._alias).p(" {");
+ if( self()==null ) p.p("---");
+ else p.n(self()).p(",");
+ p.n(priv()).p("}, ");
+ p.n(pub ());
+ return p;
}
@Override
diff --git a/chapter25/src/main/java/com/seaofnodes/simple/node/ExternNode.java b/chapter25/src/main/java/com/seaofnodes/simple/node/ExternNode.java
index 58d96745..978298fc 100644
--- a/chapter25/src/main/java/com/seaofnodes/simple/node/ExternNode.java
+++ b/chapter25/src/main/java/com/seaofnodes/simple/node/ExternNode.java
@@ -29,7 +29,6 @@ public class ExternNode extends ConstantNode {
}
@Override public String label() { return "#"+_con+":"+_extern; }
- @Override public String uniqueName() { return "Extern_" + _nid; }
@Override public boolean eq(Node n) { return this==n; }
@Override public void gather( HashMap<String,Integer> strs ) {
diff --git a/chapter25/src/main/java/com/seaofnodes/simple/node/FRefNode.java b/chapter25/src/main/java/com/seaofnodes/simple/node/FRefNode.java
index 698ba755..644f1434 100644
--- a/chapter25/src/main/java/com/seaofnodes/simple/node/FRefNode.java
+++ b/chapter25/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
@@ -32,10 +33,9 @@ public class FRefNode extends ConstantNode {
@Override public String label() { return "FRef"+_name; }
- @Override public String uniqueName() { return "FRef_" + _nid; }
- @Override public StringBuilder _print1(StringBuilder sb, BitSet visited) {
- return sb.append("FRef_").append(_name);
+ @Override protected ExprPrinter<Node> _print1(ExprPrinter<Node> p) {
+ return p.p("FRef_").p(_name);
}
@Override public Node idealize() {
diff --git a/chapter25/src/main/java/com/seaofnodes/simple/node/FldOffNode.java b/chapter25/src/main/java/com/seaofnodes/simple/node/FldOffNode.java
index e34799c9..ef894929 100644
--- a/chapter25/src/main/java/com/seaofnodes/simple/node/FldOffNode.java
+++ b/chapter25/src/main/java/com/seaofnodes/simple/node/FldOffNode.java
@@ -1,11 +1,12 @@
package com.seaofnodes.simple.node;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.Parser;
import com.seaofnodes.simple.codegen.CodeGen;
import com.seaofnodes.simple.type.*;
import com.seaofnodes.simple.util.SB;
import com.seaofnodes.simple.util.Utils;
-import java.util.BitSet;
import java.util.HashMap;
/**
@@ -23,11 +24,9 @@ public class FldOffNode extends TypeNode {
@Override public String label() {
return _fname == " len" ? "sizeof()" : "#"+_fname;
}
- @Override public String uniqueName() { return "Off_" + _nid; }
- @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 Type compute() {
diff --git a/chapter25/src/main/java/com/seaofnodes/simple/node/FunPtrNode.java b/chapter25/src/main/java/com/seaofnodes/simple/node/FunPtrNode.java
index 141fc357..82053fd8 100644
--- a/chapter25/src/main/java/com/seaofnodes/simple/node/FunPtrNode.java
+++ b/chapter25/src/main/java/com/seaofnodes/simple/node/FunPtrNode.java
@@ -1,10 +1,11 @@
package com.seaofnodes.simple.node;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.codegen.CodeGen;
import com.seaofnodes.simple.type.*;
import com.seaofnodes.simple.util.BAOS;
-import java.util.BitSet;
import java.util.HashMap;
import java.util.IdentityHashMap;
@@ -25,7 +26,6 @@ public class FunPtrNode extends TypeNode {
public FunNode fun() { return ret().fun(); }
@Override public String label() { return "#"+_con; }
- @Override public String uniqueName() { return "FunPtr_" + _nid; }
@Override public Node copy() {
FunPtrNode fptr = new FunPtrNode((TypeFunPtr)_con,null,null);
fptr._type = _type;
@@ -33,11 +33,11 @@ public class FunPtrNode extends TypeNode {
}
@Override
- public StringBuilder _print1(StringBuilder sb, BitSet visited) {
+ protected ExprPrinter<Node> _print1(ExprPrinter<Node> p) {
FunNode fun = CodeGen.CODE._link(((TypeFunPtr)_con).fidx());
return fun!=null && fun._name!=null
- ? sb.append("{ ").append(fun._name).append("}")
- : sb.append(_con);
+ ? p.p("{ ").p(fun._name).p("}")
+ : p.p(_con);
}
@Override public boolean isConst() { return true; }
diff --git a/chapter25/src/main/java/com/seaofnodes/simple/node/GuardNode.java b/chapter25/src/main/java/com/seaofnodes/simple/node/GuardNode.java
index 076a8388..0ce504d9 100644
--- a/chapter25/src/main/java/com/seaofnodes/simple/node/GuardNode.java
+++ b/chapter25/src/main/java/com/seaofnodes/simple/node/GuardNode.java
@@ -1,11 +1,12 @@
package com.seaofnodes.simple.node;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeScalar;
import com.seaofnodes.simple.util.BAOS;
import com.seaofnodes.simple.util.Utils;
-import java.util.BitSet;
import java.util.HashMap;
import java.util.IdentityHashMap;
@@ -31,10 +32,9 @@ public class GuardNode extends Node {
static Node make(BAOS bais) { return new GuardNode(bais.read()!=0,null,null); }
@Override public String label() { return _nonZero ? "(!=0)" : "(==0)"; }
- @Override public String uniqueName() { return "Guard_"+_nid; }
- @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 public Type compute() {
diff --git a/chapter25/src/main/java/com/seaofnodes/simple/node/IfNode.java b/chapter25/src/main/java/com/seaofnodes/simple/node/IfNode.java
index d8d72411..c83c81d0 100644
--- a/chapter25/src/main/java/com/seaofnodes/simple/node/IfNode.java
+++ b/chapter25/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.codegen.CodeGen;
import com.seaofnodes.simple.type.*;
import com.seaofnodes.simple.util.Utils;
-import java.util.BitSet;
public class IfNode extends CFGNode implements MultiNode {
@@ -15,11 +16,11 @@ public class IfNode extends CFGNode implements MultiNode {
@Override public Tag serialTag() { return Tag.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/chapter25/src/main/java/com/seaofnodes/simple/node/LoadNode.java b/chapter25/src/main/java/com/seaofnodes/simple/node/LoadNode.java
index 85ca42cd..a2345d92 100644
--- a/chapter25/src/main/java/com/seaofnodes/simple/node/LoadNode.java
+++ b/chapter25/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.Parser;
import com.seaofnodes.simple.codegen.CodeGen;
import com.seaofnodes.simple.codegen.GlobalBits;
@@ -53,7 +55,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/chapter25/src/main/java/com/seaofnodes/simple/node/MachConcreteNode.java b/chapter25/src/main/java/com/seaofnodes/simple/node/MachConcreteNode.java
index c2dcae0b..b25fcaaf 100644
--- a/chapter25/src/main/java/com/seaofnodes/simple/node/MachConcreteNode.java
+++ b/chapter25/src/main/java/com/seaofnodes/simple/node/MachConcreteNode.java
@@ -1,8 +1,9 @@
package com.seaofnodes.simple.node;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.type.Type;
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.
@@ -15,12 +16,11 @@ public abstract class MachConcreteNode extends Node implements MachNode {
@Override public Type compute () { throw new AssertionError("Do not call compute on "+getClass().getSimpleName()); }
@Override public Node idealize() { throw new AssertionError("Do not call idealize on "+getClass().getSimpleName()); }
- @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/chapter25/src/main/java/com/seaofnodes/simple/node/MemMergeNode.java b/chapter25/src/main/java/com/seaofnodes/simple/node/MemMergeNode.java
index e16eee9e..3e618472 100644
--- a/chapter25/src/main/java/com/seaofnodes/simple/node/MemMergeNode.java
+++ b/chapter25/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.util.BAOS;
@@ -24,21 +26,20 @@ public class MemMergeNode extends Node {
@Override public boolean isMem() { return true; }
@Override
- public StringBuilder _print1(StringBuilder sb, BitSet visited) {
- sb.append("MEM[ ");
+ protected ExprPrinter<Node> _print1(ExprPrinter<Node> p) {
+ p.p("MEM[ ");
for( int j=2; j<nIns(); j++ ) {
- sb.append(j);
- sb.append(":");
+ p.p(j);
+ p.p(":");
Node n = in(j);
while( n instanceof ScopeNode loop ) {
- sb.append("Lazy_");
+ p.p("Lazy_");
n = loop.mem();
}
- if( n==null ) sb.append("___ ");
- else n._print0(sb, visited).append(" ");
+ if( n==null ) p.p("___ ");
+ else p.n(n).p(" ");
}
- sb.setLength(sb.length()-1);
- return sb.append("]");
+ return p.unchar(' ').p("]");
}
diff --git a/chapter25/src/main/java/com/seaofnodes/simple/node/MemOpNode.java b/chapter25/src/main/java/com/seaofnodes/simple/node/MemOpNode.java
index de7adede..365157d2 100644
--- a/chapter25/src/main/java/com/seaofnodes/simple/node/MemOpNode.java
+++ b/chapter25/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.codegen.CodeGen;
import com.seaofnodes.simple.codegen.GlobalBits;
@@ -98,8 +100,8 @@ public abstract class MemOpNode extends TypeNode {
return fld == null || fld._t == null ? Type.BOTTOM : fld._t;
}
- @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(); }
// Extra conditions for factoring matching memory operations through a Phi.
diff --git a/chapter25/src/main/java/com/seaofnodes/simple/node/MinusNode.java b/chapter25/src/main/java/com/seaofnodes/simple/node/MinusNode.java
index 7c3d49f2..023deba2 100644
--- a/chapter25/src/main/java/com/seaofnodes/simple/node/MinusNode.java
+++ b/chapter25/src/main/java/com/seaofnodes/simple/node/MinusNode.java
@@ -1,11 +1,11 @@
package com.seaofnodes.simple.node;
+
import com.seaofnodes.simple.Parser;
import com.seaofnodes.simple.codegen.CodeGen;
import com.seaofnodes.simple.type.*;
import com.seaofnodes.simple.util.BAOS;
import com.seaofnodes.simple.util.Utils;
-import java.util.BitSet;
import java.util.HashMap;
import java.util.IdentityHashMap;
@@ -28,11 +28,7 @@ public class MinusNode extends Node implements ModeNode {
return this;
}
- @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/chapter25/src/main/java/com/seaofnodes/simple/node/NeverNode.java b/chapter25/src/main/java/com/seaofnodes/simple/node/NeverNode.java
index e2c279d2..ba1dab8c 100644
--- a/chapter25/src/main/java/com/seaofnodes/simple/node/NeverNode.java
+++ b/chapter25/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 {
@@ -15,7 +16,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/chapter25/src/main/java/com/seaofnodes/simple/node/NewNode.java b/chapter25/src/main/java/com/seaofnodes/simple/node/NewNode.java
index 3e1d78dc..5eedd0cd 100644
--- a/chapter25/src/main/java/com/seaofnodes/simple/node/NewNode.java
+++ b/chapter25/src/main/java/com/seaofnodes/simple/node/NewNode.java
@@ -1,11 +1,12 @@
package com.seaofnodes.simple.node;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.codegen.*;
import com.seaofnodes.simple.type.*;
import com.seaofnodes.simple.util.BAOS;
import com.seaofnodes.simple.util.SB;
-import java.util.BitSet;
import java.util.HashMap;
import java.util.IdentityHashMap;
@@ -34,9 +35,8 @@ public class NewNode extends Node implements MultiNode {
@Override public String label() { return "new_"+(_ts.isAry() ? "ary_"+_ts._fields[1]._t.str() : _ts.str()); }
- @Override public StringBuilder _print1(StringBuilder sb, BitSet visited) {
- sb.append("new ");
- return sb.append(_ts.str());
+ @Override protected ExprPrinter<Node> _print1(ExprPrinter<Node> p) {
+ return p.p("new ").p(_ts.str());
}
@Override public TypeTuple compute() {
diff --git a/chapter25/src/main/java/com/seaofnodes/simple/node/Node.java b/chapter25/src/main/java/com/seaofnodes/simple/node/Node.java
index 8842db78..9f5e107a 100644
--- a/chapter25/src/main/java/com/seaofnodes/simple/node/Node.java
+++ b/chapter25/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.IterPeeps;
import com.seaofnodes.simple.Parser;
import com.seaofnodes.simple.codegen.CodeGen;
@@ -16,14 +18,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.
@@ -45,16 +40,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);
@@ -66,8 +59,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;
@@ -152,48 +145,6 @@ public abstract class Node implements Cloneable {
// Easy reading label for debugger, e.g. "Add" or "Region" or "EQ"
public String label() { return serialTag().toString(); }
- // 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; }
@@ -201,6 +152,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
@@ -279,7 +232,6 @@ public abstract class Node implements Cloneable {
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.
@@ -358,7 +310,6 @@ public abstract class Node implements Cloneable {
kill();
}
-
// Mostly used for asserts and printing.
public boolean isDead() { return isUnused() && nIns()==0 && _type==null; }
@@ -382,7 +333,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;
@@ -622,7 +572,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
@@ -669,7 +618,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 ) {
@@ -687,7 +635,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
@@ -703,7 +650,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;
@@ -723,7 +669,6 @@ public abstract class Node implements Cloneable {
/** Is this Node Memory related */
public boolean isMem() { return false; }
-
// ------------------------------------------------------------------------
// Peephole utilities
@@ -750,7 +695,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/chapter25/src/main/java/com/seaofnodes/simple/node/NotNode.java b/chapter25/src/main/java/com/seaofnodes/simple/node/NotNode.java
index ed6091fe..2328c287 100644
--- a/chapter25/src/main/java/com/seaofnodes/simple/node/NotNode.java
+++ b/chapter25/src/main/java/com/seaofnodes/simple/node/NotNode.java
@@ -1,18 +1,14 @@
package com.seaofnodes.simple.node;
+
import com.seaofnodes.simple.type.*;
import com.seaofnodes.simple.util.Utils;
-import java.util.BitSet;
public class NotNode extends Node {
public NotNode(Node in) { super(null, in); }
@Override public Tag serialTag() { return Tag.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/chapter25/src/main/java/com/seaofnodes/simple/node/ParmNode.java b/chapter25/src/main/java/com/seaofnodes/simple/node/ParmNode.java
index be36e8d9..899d7639 100644
--- a/chapter25/src/main/java/com/seaofnodes/simple/node/ParmNode.java
+++ b/chapter25/src/main/java/com/seaofnodes/simple/node/ParmNode.java
@@ -1,9 +1,10 @@
package com.seaofnodes.simple.node;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.type.*;
import com.seaofnodes.simple.util.BAOS;
-import java.util.BitSet;
import java.util.HashMap;
import java.util.IdentityHashMap;
@@ -47,18 +48,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( fun()._name!=null && fun()._name.endsWith("<clinit>") && _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/chapter25/src/main/java/com/seaofnodes/simple/node/PhiNode.java b/chapter25/src/main/java/com/seaofnodes/simple/node/PhiNode.java
index 9d8adb15..0097c773 100644
--- a/chapter25/src/main/java/com/seaofnodes/simple/node/PhiNode.java
+++ b/chapter25/src/main/java/com/seaofnodes/simple/node/PhiNode.java
@@ -1,10 +1,11 @@
package com.seaofnodes.simple.node;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.*;
import com.seaofnodes.simple.codegen.Serialize;
import com.seaofnodes.simple.type.*;
import com.seaofnodes.simple.util.*;
-import java.util.BitSet;
import java.util.HashMap;
import java.util.IdentityHashMap;
@@ -48,18 +49,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/chapter25/src/main/java/com/seaofnodes/simple/node/ProjNode.java b/chapter25/src/main/java/com/seaofnodes/simple/node/ProjNode.java
index 5e3c7080..4b29cc3c 100644
--- a/chapter25/src/main/java/com/seaofnodes/simple/node/ProjNode.java
+++ b/chapter25/src/main/java/com/seaofnodes/simple/node/ProjNode.java
@@ -1,11 +1,12 @@
package com.seaofnodes.simple.node;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.codegen.Serialize;
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeMem;
import com.seaofnodes.simple.type.TypeTuple;
import com.seaofnodes.simple.util.BAOS;
-import java.util.BitSet;
import java.util.HashMap;
import java.util.IdentityHashMap;
@@ -35,11 +36,11 @@ public class ProjNode extends Node implements Proj {
@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/chapter25/src/main/java/com/seaofnodes/simple/node/PtrToIntNode.java b/chapter25/src/main/java/com/seaofnodes/simple/node/PtrToIntNode.java
index f0e7ae95..d3d38060 100644
--- a/chapter25/src/main/java/com/seaofnodes/simple/node/PtrToIntNode.java
+++ b/chapter25/src/main/java/com/seaofnodes/simple/node/PtrToIntNode.java
@@ -1,11 +1,11 @@
package com.seaofnodes.simple.node;
+
import com.seaofnodes.simple.Parser;
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeInteger;
import com.seaofnodes.simple.type.TypeMemPtr;
-import java.util.BitSet;
/**
* Reinterpret a non-null managed pointer as its raw integer address.
@@ -19,9 +19,7 @@ public class PtrToIntNode extends Node {
public PtrToIntNode(PtrToIntNode ptr) { super(ptr); }
@Override public Tag serialTag() { return Tag.PtrToInt; }
- @Override public StringBuilder _print1(StringBuilder sb, BitSet visited) {
- return in(1)._print0(sb.append("(i64*)"),visited);
- }
+ @Override protected String format() { return "(i64*)%1"; }
@Override public Type compute() {
return in(1)._type.isHigh() ? TypeInteger.TOP : TypeInteger.BOT;
diff --git a/chapter25/src/main/java/com/seaofnodes/simple/node/ReadOnlyNode.java b/chapter25/src/main/java/com/seaofnodes/simple/node/ReadOnlyNode.java
index c36be85a..0a720d5b 100644
--- a/chapter25/src/main/java/com/seaofnodes/simple/node/ReadOnlyNode.java
+++ b/chapter25/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 Tag serialTag() { return Tag.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/chapter25/src/main/java/com/seaofnodes/simple/node/RegionNode.java b/chapter25/src/main/java/com/seaofnodes/simple/node/RegionNode.java
index a886183e..8883ba8e 100644
--- a/chapter25/src/main/java/com/seaofnodes/simple/node/RegionNode.java
+++ b/chapter25/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.Parser;
import com.seaofnodes.simple.codegen.CodeGen;
import com.seaofnodes.simple.type.Type;
@@ -17,9 +19,8 @@ public class RegionNode extends CFGNode {
public void packed( BAOS baos, HashMap<String,Integer> strs, HashMap<Type,Integer> types, IdentityHashMap<Node, Integer> anodes ) { baos.packed1(nIns()); }
static Node make( BAOS bais ) { return new RegionNode(null,new Node[bais.packed1()]); }
- @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/chapter25/src/main/java/com/seaofnodes/simple/node/ReturnNode.java b/chapter25/src/main/java/com/seaofnodes/simple/node/ReturnNode.java
index 0dc14fd2..0431f7d5 100644
--- a/chapter25/src/main/java/com/seaofnodes/simple/node/ReturnNode.java
+++ b/chapter25/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.codegen.CodeGen;
import com.seaofnodes.simple.codegen.Encoding;
@@ -7,7 +9,6 @@ import com.seaofnodes.simple.codegen.RegMask;
import com.seaofnodes.simple.type.*;
import com.seaofnodes.simple.util.SB;
import com.seaofnodes.simple.util.Utils;
-import java.util.BitSet;
/**
* The Return node has two inputs. The first input is a control node and the
@@ -36,11 +37,11 @@ public class ReturnNode extends CFGNode {
@Override public FunNode fun() { return _fun; }
@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/chapter25/src/main/java/com/seaofnodes/simple/node/RoundF32Node.java b/chapter25/src/main/java/com/seaofnodes/simple/node/RoundF32Node.java
index 61809fe3..1a3592dc 100644
--- a/chapter25/src/main/java/com/seaofnodes/simple/node/RoundF32Node.java
+++ b/chapter25/src/main/java/com/seaofnodes/simple/node/RoundF32Node.java
@@ -1,18 +1,15 @@
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 Tag serialTag() { return Tag.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/chapter25/src/main/java/com/seaofnodes/simple/node/ScopeNode.java b/chapter25/src/main/java/com/seaofnodes/simple/node/ScopeNode.java
index 527d3395..92cad745 100644
--- a/chapter25/src/main/java/com/seaofnodes/simple/node/ScopeNode.java
+++ b/chapter25/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.Parser;
import com.seaofnodes.simple.Var;
import com.seaofnodes.simple.codegen.CodeGen;
@@ -61,28 +63,26 @@ public class ScopeNode extends MemMergeNode {
@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 < depth() && i == _kinds.at(j)._lexSize ) { sb.append("| "); j++; }
+ if( j < depth() && i == _kinds.at(j)._lexSize ) { p.p("| "); j++; }
Var v = var(i);
- sb.append(v._type());
- sb.append(" ");
- if( v._final ) sb.append("!");
- sb.append(v._name);
- sb.append("=");
+ p.p(v._type());
+ 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/chapter25/src/main/java/com/seaofnodes/simple/node/SplitNode.java b/chapter25/src/main/java/com/seaofnodes/simple/node/SplitNode.java
index 4b58187f..0e104c15 100644
--- a/chapter25/src/main/java/com/seaofnodes/simple/node/SplitNode.java
+++ b/chapter25/src/main/java/com/seaofnodes/simple/node/SplitNode.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.codegen.Encoding;
import com.seaofnodes.simple.codegen.LRG;
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.util.SB;
-import java.util.BitSet;
public abstract class SplitNode extends MachConcreteNode {
public final LRG _lrg; // Live range for split
@@ -13,11 +14,11 @@ public abstract class SplitNode extends MachConcreteNode {
public final byte _round; // Debugging info for which RegAlloc round
public SplitNode(LRG lrg,String kind, byte round, Node[] nodes) { super(nodes); _lrg=lrg; _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();
}
public FunNode fun(Encoding enc) { return enc._code._regAlloc.lrg(this)._fun; }
@Override public Type compute() { return in(0)._type; }
diff --git a/chapter25/src/main/java/com/seaofnodes/simple/node/StartNode.java b/chapter25/src/main/java/com/seaofnodes/simple/node/StartNode.java
index dc21e5eb..84c8a3a7 100644
--- a/chapter25/src/main/java/com/seaofnodes/simple/node/StartNode.java
+++ b/chapter25/src/main/java/com/seaofnodes/simple/node/StartNode.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.type.*;
import com.seaofnodes.simple.util.Utils;
import java.util.Arrays;
-import java.util.BitSet;
import java.util.HashSet;
/**
@@ -31,9 +32,8 @@ public class StartNode extends LoopNode implements MultiNode {
@Override public Tag serialTag() { return Tag.Start; }
public Type arg() { return _arg; }
- @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 CFGNode cfg0() { return null; }
diff --git a/chapter25/src/main/java/com/seaofnodes/simple/node/StopNode.java b/chapter25/src/main/java/com/seaofnodes/simple/node/StopNode.java
index b0bf8343..e52a49a2 100644
--- a/chapter25/src/main/java/com/seaofnodes/simple/node/StopNode.java
+++ b/chapter25/src/main/java/com/seaofnodes/simple/node/StopNode.java
@@ -1,10 +1,11 @@
package com.seaofnodes.simple.node;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.codegen.CodeGen;
import com.seaofnodes.simple.type.*;
import com.seaofnodes.simple.util.BAOS;
-import java.util.BitSet;
import java.util.HashMap;
import java.util.IdentityHashMap;
@@ -25,7 +26,7 @@ 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 = null;
for( Node n : _inputs ) {
@@ -34,16 +35,16 @@ public class StopNode extends CFGNode {
ret1 = ret;
}
}
- if( ret1!=null ) return ret1._print0(sb,visited);
+ if( ret1!=null ) return p.n(ret1);
- sb.append("Stop[ ");
+ p.p("Stop[ ");
for( Node n : _inputs )
if( n instanceof ReturnNode ret ) {
String name = 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/chapter25/src/main/java/com/seaofnodes/simple/node/StoreNode.java b/chapter25/src/main/java/com/seaofnodes/simple/node/StoreNode.java
index fe379c80..7e2963f2 100644
--- a/chapter25/src/main/java/com/seaofnodes/simple/node/StoreNode.java
+++ b/chapter25/src/main/java/com/seaofnodes/simple/node/StoreNode.java
@@ -1,12 +1,13 @@
package com.seaofnodes.simple.node;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.*;
import com.seaofnodes.simple.codegen.CodeGen;
import com.seaofnodes.simple.codegen.GlobalBits;
import com.seaofnodes.simple.type.*;
import com.seaofnodes.simple.util.BAOS;
import com.seaofnodes.simple.util.Utils;
-import java.util.BitSet;
import java.util.HashMap;
import java.util.IdentityHashMap;
@@ -67,8 +68,8 @@ public class StoreNode extends MemOpNode {
public int log_size() { return Integer.numberOfTrailingZeros(storeSize()); };
@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/chapter25/src/main/java/com/seaofnodes/simple/node/ToFloatNode.java b/chapter25/src/main/java/com/seaofnodes/simple/node/ToFloatNode.java
index 15350afb..151a326e 100644
--- a/chapter25/src/main/java/com/seaofnodes/simple/node/ToFloatNode.java
+++ b/chapter25/src/main/java/com/seaofnodes/simple/node/ToFloatNode.java
@@ -1,19 +1,16 @@
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 Tag serialTag() { return Tag.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/chapter25/src/main/java/com/seaofnodes/simple/node/XCtrlNode.java b/chapter25/src/main/java/com/seaofnodes/simple/node/XCtrlNode.java
index a8c06b37..32e1deb9 100644
--- a/chapter25/src/main/java/com/seaofnodes/simple/node/XCtrlNode.java
+++ b/chapter25/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 Tag serialTag() { return Tag.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/chapter25/src/main/java/com/seaofnodes/simple/node/cpus/arm/MemOpARM.java b/chapter25/src/main/java/com/seaofnodes/simple/node/cpus/arm/MemOpARM.java
index 53a0f8cf..a26f385a 100644
--- a/chapter25/src/main/java/com/seaofnodes/simple/node/cpus/arm/MemOpARM.java
+++ b/chapter25/src/main/java/com/seaofnodes/simple/node/cpus/arm/MemOpARM.java
@@ -1,11 +1,12 @@
package com.seaofnodes.simple.node.cpus.arm;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.codegen.*;
import com.seaofnodes.simple.node.*;
import com.seaofnodes.simple.type.*;
import com.seaofnodes.simple.util.SB;
import java.lang.StringBuilder;
-import java.util.BitSet;
public abstract class MemOpARM extends MemOpNode implements MachNode {
final int _off; // Limit 9 bits sized, or (13 bits<<logsize) unsigned
@@ -33,7 +34,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 new AssertionError("Do not call compute on "+getClass().getSimpleName()); }
@Override public Node idealize() { throw new AssertionError("Do not call idealize on "+getClass().getSimpleName()); }
diff --git a/chapter25/src/main/java/com/seaofnodes/simple/node/cpus/arm/UJmpARM.java b/chapter25/src/main/java/com/seaofnodes/simple/node/cpus/arm/UJmpARM.java
index 2dd5fd6b..ce4f523c 100644
--- a/chapter25/src/main/java/com/seaofnodes/simple/node/cpus/arm/UJmpARM.java
+++ b/chapter25/src/main/java/com/seaofnodes/simple/node/cpus/arm/UJmpARM.java
@@ -1,20 +1,18 @@
package com.seaofnodes.simple.node.cpus.arm;
+
import com.seaofnodes.simple.codegen.*;
import com.seaofnodes.simple.node.*;
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.util.SB;
import com.seaofnodes.simple.util.Utils;
-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/chapter25/src/main/java/com/seaofnodes/simple/node/cpus/riscv/BranchRISC.java b/chapter25/src/main/java/com/seaofnodes/simple/node/cpus/riscv/BranchRISC.java
index b7284265..b8664679 100644
--- a/chapter25/src/main/java/com/seaofnodes/simple/node/cpus/riscv/BranchRISC.java
+++ b/chapter25/src/main/java/com/seaofnodes/simple/node/cpus/riscv/BranchRISC.java
@@ -1,10 +1,11 @@
package com.seaofnodes.simple.node.cpus.riscv;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.codegen.*;
import com.seaofnodes.simple.node.*;
import com.seaofnodes.simple.util.SB;
import com.seaofnodes.simple.util.Utils;
-import java.util.BitSet;
// Conditional branch such as: BEQ
public class BranchRISC extends IfNode implements MachNode, RIPRelSize {
@@ -31,14 +32,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/chapter25/src/main/java/com/seaofnodes/simple/node/cpus/riscv/ImmRISC.java b/chapter25/src/main/java/com/seaofnodes/simple/node/cpus/riscv/ImmRISC.java
index f2beb25c..b4c87872 100644
--- a/chapter25/src/main/java/com/seaofnodes/simple/node/cpus/riscv/ImmRISC.java
+++ b/chapter25/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.codegen.*;
import com.seaofnodes.simple.node.*;
import com.seaofnodes.simple.type.TypeInteger;
import com.seaofnodes.simple.util.SB;
-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/chapter25/src/main/java/com/seaofnodes/simple/node/cpus/riscv/MemOpRISC.java b/chapter25/src/main/java/com/seaofnodes/simple/node/cpus/riscv/MemOpRISC.java
index 5fcba6f8..e0bbc219 100644
--- a/chapter25/src/main/java/com/seaofnodes/simple/node/cpus/riscv/MemOpRISC.java
+++ b/chapter25/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.util.SB;
import com.seaofnodes.simple.util.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
@@ -25,7 +26,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 new AssertionError("Do not call compute on "+getClass().getSimpleName()); }
@Override public Node idealize() { throw new AssertionError("Do not call idealize on "+getClass().getSimpleName()); }
diff --git a/chapter25/src/main/java/com/seaofnodes/simple/node/cpus/riscv/UJmpRISC.java b/chapter25/src/main/java/com/seaofnodes/simple/node/cpus/riscv/UJmpRISC.java
index c4d5d8af..160895df 100644
--- a/chapter25/src/main/java/com/seaofnodes/simple/node/cpus/riscv/UJmpRISC.java
+++ b/chapter25/src/main/java/com/seaofnodes/simple/node/cpus/riscv/UJmpRISC.java
@@ -1,17 +1,18 @@
package com.seaofnodes.simple.node.cpus.riscv;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.codegen.*;
import com.seaofnodes.simple.node.*;
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.util.SB;
import com.seaofnodes.simple.util.Utils;
-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/chapter25/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/MemOpX86.java b/chapter25/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/MemOpX86.java
index 87cc6e35..fcca7f8f 100644
--- a/chapter25/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/MemOpX86.java
+++ b/chapter25/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/MemOpX86.java
@@ -1,11 +1,12 @@
package com.seaofnodes.simple.node.cpus.x86_64_v2;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.codegen.*;
import com.seaofnodes.simple.node.*;
import com.seaofnodes.simple.type.*;
import com.seaofnodes.simple.util.SB;
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/chapter25/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/StoreX86.java b/chapter25/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/StoreX86.java
index faedeb8b..7133e824 100644
--- a/chapter25/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/StoreX86.java
+++ b/chapter25/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.codegen.*;
import com.seaofnodes.simple.node.ConstantNode;
import com.seaofnodes.simple.node.Node;
@@ -7,19 +9,18 @@ import com.seaofnodes.simple.node.StoreNode;
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeFloat;
import com.seaofnodes.simple.util.SB;
-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/chapter25/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/UJmpX86.java b/chapter25/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/UJmpX86.java
index 92d2a87d..6f538d27 100644
--- a/chapter25/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/UJmpX86.java
+++ b/chapter25/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/UJmpX86.java
@@ -1,20 +1,18 @@
package com.seaofnodes.simple.node.cpus.x86_64_v2;
+
import com.seaofnodes.simple.codegen.*;
import com.seaofnodes.simple.node.*;
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.util.SB;
import com.seaofnodes.simple.util.Utils;
-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/chapter25/src/main/java/com/seaofnodes/simple/print/ASMPrinter.java b/chapter25/src/main/java/com/seaofnodes/simple/print/ASMPrinter.java
index ff3eada2..994065d8 100644
--- a/chapter25/src/main/java/com/seaofnodes/simple/print/ASMPrinter.java
+++ b/chapter25/src/main/java/com/seaofnodes/simple/print/ASMPrinter.java
@@ -1,309 +1,94 @@
package com.seaofnodes.simple.print;
-import com.seaofnodes.simple.codegen.CompUnit;
+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.Relo;
-import com.seaofnodes.simple.codegen.Encoding;
+import com.seaofnodes.simple.util.SB;
import com.seaofnodes.simple.node.*;
import com.seaofnodes.simple.type.*;
-import com.seaofnodes.simple.util.*;
+import java.util.ArrayList;
+import com.seaofnodes.simple.codegen.Encoding;
+import com.seaofnodes.simple.util.BAOS;
import java.util.HashMap;
-import java.util.Collections;
-import java.util.IdentityHashMap;
-import java.util.Set;
-
-public abstract class ASMPrinter {
-
- public static SB print(SB sb, CodeGen code ) {
- Encoding enc = code._encoding;
- Ary<CFGNode> cfg = enc == null ? code._cfg : enc._cfg;
- if( cfg == null || cfg._len == 0 ) return sb.p("No scheduled code for ").p(code._srcName);
- // instruction address
- int iadr = 0;
- // Print all functions in order
- for( int i=0; i<cfg._len; i++ )
- if( cfg.at(i) instanceof FunNode fun )
- iadr = print(iadr,sb,code,enc,cfg,fun,i);
-
- // constant pools
- if( enc != null ) {
- iadr = (iadr+15)&-16; // pad to 16
- if( enc._cpool.size()>0 )
- iadr = printConstantPool(iadr, sb, enc._cpool,enc._bigCons,true ,"Constant Pool");
-
- iadr = (iadr+15)&-16; // pad to 16
- if( enc._sdata.size()>0 )
- iadr = printConstantPool(iadr, sb,enc._sdata,enc._bigCons,false, "Static Data" );
- }
-
- return sb;
+/** 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;
}
-
-
- static int printConstantPool( int iadr, SB sb, BAOS bits, HashMap<Node,Relo> bigCons, boolean ro, String msg ) {
- sb.p("--- ").p(msg).p(" ------").nl();
- // radix sort the big constants by alignment
- Ary<Relo>[] raligns = new Ary[5];
- for( Relo relo : bigCons.values() ) {
- if( relo.readOnly() != ro )
- continue;
- 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<>());
-
- // By alignment
- int dadr=0;
- 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+dadr).p(" ");
- if( relo._t instanceof 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(bits.read1(dadr++));
- } else {
- // Simple primitive (e.g. larger int, float)
- pN(bits,sb,dadr,align).fix(9-(1<<align),"");
- dadr += (1<<align);
- }
- relo._t.print(sb.p('\t')).nl();
- }
- }
- return iadr+dadr;
+ public static SB print(SB sb, CodeGen code) {
+ return sb.p(new com.seaofnodes.print.ASMPrinter<>(new ASMPrinter(code)).print());
}
-
-
- private static SB pN( BAOS bits, SB sb, int dadr, int log ) {
- switch( log ) {
- case 0: sb.hex1(bits.read1(dadr)); break;
- case 1: sb.hex2(bits.read2(dadr)); break;
- case 2: sb.hex4(bits.read4(dadr)); break;
- case 3: sb.hex8(bits.read8(dadr)); break;
+ @Override public ArrayList<Node> blocks() {
+ var blocks=new ArrayList<Node>();
+ var cfg=_enc==null ? _code._cfg : _enc._cfg;
+ if( cfg!=null ) for( Node n : cfg ) blocks.add(n);
+ return blocks;
+ }
+ @Override public String op(Node n) { return n instanceof MachNode m ? m.op() : n.label(); }
+ @Override public String register(Node n) { return _code.reg(n); }
+ @Override public String comment(Node n) { return n.comment(); }
+ @Override public String phiName(Node n) { return ((PhiNode)n)._label; }
+ @Override public String operands(Node n) {
+ SB sb=new SB();
+ if( n instanceof MachNode m ) m.asm(_code,sb);
+ else if( !(n._type instanceof TypeMem) ) {
+ sb.p(n._nid).p(": ");
+ for( Node def : n._inputs ) sb.p(def==null ? "___" : Integer.toString(def._nid)).p(' ');
}
- return sb;
+ return sb.toString();
}
-
-
- private static int print(int iadr, SB sb, CodeGen code, Encoding enc, Ary<CFGNode> cfg, FunNode fun, int cfgidx) {
- // 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,enc, cfgidx,fun,true,enc!=null);
- while( !(cfg.at(cfgidx) instanceof ReturnNode) )
- iadr = doBlock(iadr,sb,code,enc,cfg,fun,cfgidx++);
-
- // Function separator
- sb.p("---");
- fun.sig().print(sb);
- sb.p("---------------------------").nl();
- 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 private final int opWidth = 5;
- static private final int argWidth = 30;
- static int doBlock(int iadr, SB sb, CodeGen code, Encoding enc, Ary<CFGNode> cfg, FunNode fun, int cfgidx) {
- final int encWidth = code._mach==null ? 2 : code._mach.defaultOpSize()*2;
- CFGNode bb = 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 postEncode= code._phase.ordinal() >=CodeGen.Phase.Encoding.ordinal();
- final boolean postAlloc = code._phase.ordinal() > CodeGen.Phase.RegAlloc.ordinal() ||
- (code._phase.ordinal() == CodeGen.Phase.RegAlloc.ordinal() && code._regAlloc.done());
-
- 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)).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));
- 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, enc, cfgidx, bb.out(i),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;
+ if( n instanceof EscapeNode ) return true;
+ return n.getClass()==ConstantNode.class;
}
-
- static int doInst( int iadr, SB sb, CodeGen code, Encoding enc, 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 instanceof EscapeNode ) 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
- Ary<CFGNode> blocks = enc == null ? code._cfg : enc._cfg;
- while( cfgidx < blocks._len-1 ) {
- CFGNode next = blocks.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;
+ @Override public boolean postAlloc() { return _code._phase.ordinal()>CodeGen.Phase.RegAlloc.ordinal() ||
+ (_code._phase==CodeGen.Phase.RegAlloc && _code._regAlloc!=null && _code._regAlloc.done()); }
+ @Override public boolean encoded() { return _enc!=null && _code._phase.ordinal()>=CodeGen.Phase.Encoding.ordinal(); }
+ @Override public int defaultSize() { return _code._mach==null ? 2 : _code._mach.defaultOpSize(); }
+ @Override public boolean littleEndian() { return _code._asmLittle; }
+ @Override public boolean prologue(Node n) { return ((FunNode)n)._frameAdjust!=0; }
+ @Override public byte[] bytes() { return encoded() ? _enc._bits.buf() : null; }
+ @Override public int offset(Node n) { return encoded() ? _enc.opStart(n) : -1; }
+ @Override public int size(Node n) { return encoded() ? _enc.opLen(n)&255 : 0; }
+ private static ArrayList<Data> entries(Iterable<Encoding.Relo> relos, boolean ro) {
+ var data=new ArrayList<Data>();
+ for( Encoding.Relo r : relos ) {
+ if( r.readOnly()!=ro ) continue;
+ int align=1<<r._align;
+ int size=r._t instanceof TypeStruct ? (r._structSize+align-1)&-align : align;
+ data.add(new Data(r._t,r._t.str(),r._align,size));
}
-
- // 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,code.reg(n)).p(" // ");
- if( proj._label != null ) sb.p(proj._label);
- sb.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( enc != null ) {
- int size = enc.opLen(n);
- if( code._asmLittle )
- for( int i=0; i<Math.min(size,dopz); i++ )
- sb.hex1(enc._bits.buf()[iadr++]);
- else {
- iadr += Math.min(size,dopz);
- for( int i=0; i<Math.min(size,dopz); i++ )
- sb.hex1(enc._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 && enc != null ) {
- // Multiple ops, template style, no RA, no scheduling. Print out
- // one-line-per-newline, with encoding bits up front.
- int size = enc != null ? enc.opLen(n) : 0;
- 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(enc._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( isMultiOp != null ) {
- sb.p(isMultiOp).nl();
-
- } 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(enc._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,enc, cfgidx, proj,postAlloc,postEncode);
- }
- }
-
- return iadr;
+ return data;
}
-
- private static String label( CFGNode bb ) {
- return (bb instanceof LoopNode ? "LOOP" : "L")+bb._nid;
+ @Override public ArrayList<Pool> pools(int codeEnd) {
+ var pools=new ArrayList<Pool>();
+ if( !encoded() ) return pools;
+ int base=(codeEnd+15)&-16;
+ if( _enc._cpool.size()>0 )
+ pools.add(new Pool("Constant Pool",_enc._cpool.buf(),0,base,entries(_enc._bigCons.values(),true)));
+ base=(base+_enc._cpool.size()+15)&-16;
+ if( _enc._sdata.size()>0 )
+ pools.add(new Pool("Static Data",_enc._sdata.buf(),0,base,entries(_enc._bigCons.values(),false)));
+ return pools;
}
-
- private static String isMultiOp(SB sb, int old, int len) {
- if( old==len || sb.at(old)!='\n' ) return null;
- String rest = sb.subString(old+1,len);
- sb.setLen(old);
- return rest;
+ // Retain this diagnostic entry point for checking that pool printing never lays out types.
+ static int printConstantPool(int address, SB sb, BAOS bits, HashMap<Node,Encoding.Relo> relos,
+ boolean ro, String name) {
+ sb.p(com.seaofnodes.print.ASMPrinter.pool(new Pool(name,bits.buf(),0,address,entries(relos.values(),ro))));
+ return address+bits.size();
}
-
}
diff --git a/chapter25/src/main/java/com/seaofnodes/simple/print/IRPrinter.java b/chapter25/src/main/java/com/seaofnodes/simple/print/IRPrinter.java
index f278be70..531a549a 100644
--- a/chapter25/src/main/java/com/seaofnodes/simple/print/IRPrinter.java
+++ b/chapter25/src/main/java/com/seaofnodes/simple/print/IRPrinter.java
@@ -1,287 +1,60 @@
package com.seaofnodes.simple.print;
-import com.seaofnodes.simple.codegen.CodeGen;
-import com.seaofnodes.simple.codegen.CompUnit;
+import com.seaofnodes.print.IRAdapter;
import com.seaofnodes.simple.node.*;
-import com.seaofnodes.simple.util.Ary;
+import java.util.ArrayList;
import com.seaofnodes.simple.util.SB;
+import com.seaofnodes.simple.codegen.CodeGen;
-import java.util.*;
-
-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");
- }
-
- // Bulk whole program pretty print
- public static String prettyPrint( CodeGen code ) {
- SB sb = new SB();
- printLine(code._start,sb);
-
- // Constants are shared program-wide. Print only actual Start children
- // here; derived values belong to the functions which use them.
- ArrayList<Node> globals = new ArrayList<>();
- for( Node n : code._start._outputs )
- if( n instanceof ConstantNode ) globals.add(n);
- globals.sort(Comparator.comparingInt(n -> n._nid));
- for( Node n : globals ) printLine(n,sb);
-
- ArrayList<CompUnit> cus = new ArrayList<>(code._compunits.values());
- cus.sort(Comparator.comparing(cu -> cu._cname==null ? "" : cu._cname));
- for( CompUnit cu : cus ) {
- if( cu._start==null || cu._start.isDead() ) continue;
- sb.nl().p("=== ").p(cu._cname==null ? "" : cu._cname).p(" ===\n");
- printLine(cu._start,sb);
- ArrayList<Node> projs = projections(cu._start);
- for( Node proj : projs ) printLine(proj,sb);
-
- ArrayList<FunNode> funs = new ArrayList<>();
+/** 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 StartCUNode ) return Kind.UNIT;
+ if( n instanceof StopCUNode ) return Kind.UNIT;
+ if( n instanceof StartNode ) return Kind.START;
+ if( n instanceof StopNode ) return Kind.STOP;
+ if( n instanceof FunNode ) return Kind.FUN;
+ if( n instanceof LoopNode ) return Kind.LOOP;
+ if( n instanceof RegionNode ) return Kind.REGION;
+ if( n instanceof ParmNode ) return Kind.PARM;
+ if( n instanceof PhiNode ) return Kind.PHI;
+ if( n instanceof CallEndNode ) return Kind.CALL_END;
+ if( n instanceof CallNode ) return Kind.CALL;
+ if( n instanceof ReturnNode ) return Kind.RETURN;
+ if( n instanceof ConstantNode ) return Kind.CONSTANT;
+ if( n instanceof CProjNode ) return Kind.CPROJ;
+ if( n instanceof ProjNode ) return n instanceof CFGNode ? Kind.CPROJ : Kind.PROJ;
+ if( n instanceof CFGNode ) return Kind.CTRL;
+ if( n instanceof MultiNode ) return Kind.MULTI;
+ return Kind.DATA;
+ }
+ @Override public int index(Node n) {
+ if( n instanceof ProjNode p ) return p._idx;
+ if( n instanceof CProjNode p ) return p._idx;
+ return n._nid;
+ }
+ @Override public String functionName(Node n) { return ((FunNode)n)._name==null ? "" : ((FunNode)n)._name; }
+ @Override public String signature(Node n) {
+ FunNode fun=(FunNode)n;
+ return (fun._name==null ? "" : fun._name)+" "+fun.sig().str();
+ }
+
+ public static String prettyPrint(Node n, int depth) { return PRINT.prettyPrint(n,depth); }
+ public static SB printLine(Node n, SB sb) { return sb.p(PRINT.line(n)); }
+
+ public static String prettyPrint(CodeGen code) {
+ var units=new ArrayList<com.seaofnodes.print.IRPrinter.Unit<Node>>();
+ for( var cu : code._compunits.values() ) {
+ var funs=new ArrayList<Node>();
for( FunNode fun : code._linker )
- if( fun!=null && !fun.isDead() && fun._compunit==cu )
- funs.add(fun);
- funs.sort(Comparator.comparingInt(n -> n._nid));
- for( FunNode fun : funs ) printFunction(fun,sb);
-
- printLine(cu._stop,sb);
- }
- printLine(code._stop,sb);
- return sb.toString();
- }
-
- /** Print one function without ever traversing a call-graph linkage. */
- private static void printFunction(FunNode fun, SB sb) {
- sb.nl().p("--- ");
- fun.sig().print(sb.p(fun._name==null ? "" : fun._name).p(" "));
- sb.p("----------------------\n");
-
- ArrayList<Node> post = new ArrayList<>();
- IdentityHashMap<Node,Boolean> visit = new IdentityHashMap<>();
- functionPost(fun,fun,visit,post);
- Collections.reverse(post);
-
- Node prior = null;
- IdentityHashMap<Node,Boolean> emitted = new IdentityHashMap<>();
- for( Node n : post ) {
- if( emitted.containsKey(n) ) continue;
- if( n instanceof RegionNode || n instanceof MultiNode || n instanceof CallNode ||
- (isMultiChild(prior) && !isMultiChild(n)) )
- sb.nl();
- // A Region/Loop and its Phis are one block header. In particular,
- // do not pull loop-carried Phi inputs up between the header and
- // the Phi; those values belong down in the loop body/backedge.
- if( !isMultiChild(n) )
- emitLocalDefs(n,visit,emitted,sb);
- printLine(n,sb);
- emitted.put(n,Boolean.TRUE);
- prior = n;
+ if( fun!=null && fun._compunit==cu ) funs.add(fun);
+ units.add(new com.seaofnodes.print.IRPrinter.Unit<>(cu._cname,cu._start,cu._stop,funs));
}
- sb.p("--- ").p(fun._name==null ? "" : fun._name).p(" ----------------------\n");
- }
-
- private static void emitLocalDefs(Node n,
- IdentityHashMap<Node,Boolean> owned,
- IdentityHashMap<Node,Boolean> emitted,
- SB sb) {
- if( n.isDead() ) return;
- for( Node def : n._inputs ) {
- if( def==null || def instanceof CFGNode || def instanceof ConstantNode ||
- def instanceof PhiNode || isMultiChild(def) ||
- !owned.containsKey(def) || emitted.containsKey(def) )
- continue;
- emitLocalDefs(def,owned,emitted,sb);
- printLine(def,sb);
- emitted.put(def,Boolean.TRUE);
- }
- }
-
- // Printer-private RPO. This deliberately uses raw edge arrays and local
- // identity state: no Node visit bits, cached idoms, or loop-tree metadata.
- private static void functionPost(Node n, FunNode owner,
- IdentityHashMap<Node,Boolean> visit,
- ArrayList<Node> post) {
- if( n==null || n.isDead() || visit.put(n,Boolean.TRUE)!=null ) return;
- if( n instanceof FunNode fun && fun!=owner ) return; // Linked callee
- if( n instanceof ParmNode &&
- input0(n)!=owner ) return; // Callee parameter
- if( n instanceof StopCUNode || n instanceof StopNode || n instanceof StartCUNode ) return;
- if( n instanceof CallEndNode && input0(n) instanceof CallNode call &&
- !visit.containsKey(call) ) return; // Foreign caller
-
- ArrayList<Node> uses = new ArrayList<>();
- // A Return is terminal inside its function. All of its graph users
- // are ownership/linkage hooks (StopCU, CallEnds, FunPtrs), never CFG
- // continuation in the function being printed.
- if( !(n instanceof ReturnNode) ) for( Node use : n._outputs ) {
- if( use==null || use.isDead() ) continue;
- if( n instanceof CallNode && use instanceof FunNode ) continue;
- if( use instanceof FunNode fun && fun!=owner ) continue;
- if( use instanceof ParmNode &&
- input0(use)!=owner ) continue;
- uses.add(use);
- }
- // CFG first produces an RPO-like block order. Stable nid ordering
- // keeps malformed/multiply-connected graphs deterministic.
- uses.sort(Comparator
- .comparingInt((Node use) -> use instanceof CFGNode ? 0 : 1)
- .thenComparingInt(use -> use._nid));
- for( Node use : uses ) functionPost(use,owner,visit,post);
-
- // Keep a multi-head and its projections contiguous.
- if( isMultiChild(n) ) return;
- if( isMultiHead(n) ) {
- ArrayList<Node> ps = projections(n);
- for( Node p : ps ) visit.put(p,Boolean.TRUE);
- for( int i=ps.size()-1; i>=0; i-- ) post.add(ps.get(i));
- }
- post.add(n);
- }
-
- private static ArrayList<Node> projections(Node multi) {
- ArrayList<Node> ps = new ArrayList<>();
- for( Node use : multi._outputs )
- if( use!=null && !use.isDead() && isMultiChild(use) ) ps.add(use);
- ps.sort(Comparator.comparingInt(IRPrinter::sortOrder));
- return ps;
+ return PRINT.program(code._start,code._stop,units);
}
-
- private static boolean isMultiHead(Node n) {
- return n instanceof RegionNode || n instanceof MultiNode;
- }
-
- private static boolean isMultiChild(Node n) {
- Node head = input0(n);
- // Regions group their Phis, and tuple-producing MultiNodes group their
- // projections. Merely being controlled by a Region/Loop does not
- // make an ordinary CFG node a grouped child.
- return (n instanceof PhiNode && head instanceof RegionNode) ||
- (n instanceof Proj && head instanceof MultiNode);
- }
-
- // Raw, bounds-safe graph inspection for the debugger. In particular do
- // not call an accessor which might assert, sharpen, cache, or lazily kill.
- private static Node input0(Node n) {
- return n==null || n._inputs.isEmpty()
- ? null : n._inputs.at(0);
- }
-
-
- // ----------------------------------------
- // Another bulk pretty-printer. Makes more effort at basic-block grouping.
- public static String prettyPrint(Node node, int depth) {
- // Convert just that set to a post-order
- Ary<Node> post = new Ary<>(Node.class);
- Ary<Node> rets = new Ary<>(Node.class);
- var visit = new IdentityHashMap<Node,Integer>();
- assert depth < 5000;
- postOrd( node, 0, depth, visit, post, rets);
- // Function calls all print independent
- while( rets.size()>0 )
- postOrd( rets.pop(), 0, depth, visit, post, rets );
-
-
- // Reverse the post-order walk
- SB sb = new SB();
- for( int i=0; i<post._len; i++ ) {
- Node n = post.at(i);
- // Split ahead of a Region/MultiNode
- if( n instanceof RegionNode || n instanceof MultiNode ||
- (i>0 && isMultiChild(post.at(i-1)) && !isMultiChild(n)) )
- sb.nl();
- if( n instanceof FunNode fun )
- fun.sig().print(sb.p("--- ").p(fun._name==null ? "" : fun._name).p(" ")).p("----------------------\n");
- printLine( n, sb ); // Print head
- if( n instanceof ReturnNode ret ) {
- FunNode fun = ret.fun();
- sb.p("--- ").p(fun==null ? "" : fun._name).p("----------------------\n");
- }
- }
- return sb.toString();
- }
-
-
- // keep the largest PO depth?; probably want *shortest*
- private static void postOrd( Node n, int d, int cutoff, IdentityHashMap<Node,Integer> visit, Ary<Node> post, Ary<Node> rets ) {
- if( n==null ) return;
- if( d >= cutoff ) return; // Too deep
- Integer depth = visit.get(n);
- if( depth!=null ) return; // Been there, done that
-
- // Not a multi-child (Phi of a Region or Proj of a MultiNode)
- if( !isMultiHead(n) && !isMultiChild(n) ) {
- visit.put(n,d); // Visit node N and depth D
- for( Node def : n._inputs ) // Children before visit
- postOrd(def, d+1, cutoff, visit, post, rets);
- post.add(n); // Post-order add
- return;
- }
-
- // Multi-child; print the parent and all children together
- Node multi = isMultiHead(n) ? n : n.in(0);
- // Multi + children are visited all at once
- visit.put(multi,d+1);
- for( Node out : multi.outs() )
- visit.put(out,d);
-
- // Order to visit all the children
- Node[] outs = multi.outs().asAry();
- Arrays.sort(outs, Comparator.comparingInt( IRPrinter::sortOrder ) );
-
- // Do not walk out of Functions, this makes functions stand-alone
- // but otherwise unordered
- if( !(multi instanceof FunNode fun && fun._folding) ) {
- // Visit all children inputs all at once
- for( Node out : outs ) {
- // A FunNode is both a multi-head AND a multi-child from Start
- if( !isMultiHead(out) && out != null ) {
- for( Node def : out._inputs ) {
- postOrd(def, d+1, cutoff, visit, post, rets);
- }
- }
- }
- // Visit multi inputs
- for( Node def : multi._inputs ) {
- if( multi instanceof CallEndNode && def instanceof ReturnNode ret && !ret._fun._folding ) {
- rets.add(ret); // But save the Return for a separate function print
- } else {
- postOrd(def, d+2, cutoff, visit, post, rets);
- }
- }
- }
-
- // Post visit the multi and all children
- post.add(multi);
- for( Node out : outs )
- if( !isMultiHead(out) )
- post.add(out);
- }
-
- static int sortOrder( Node n ) {
- if( n instanceof Proj proj ) return proj.idx();
- if( n instanceof PhiNode phi ) return phi._nid;
- if( n == null ) return 0;
- return n._nid+1000000;
- }
-
}
diff --git a/chapter25/src/main/java/com/seaofnodes/simple/print/SimpleGraphAdapter.java b/chapter25/src/main/java/com/seaofnodes/simple/print/SimpleGraphAdapter.java
index 6c4e7e31..9ca0ec51 100644
--- a/chapter25/src/main/java/com/seaofnodes/simple/print/SimpleGraphAdapter.java
+++ b/chapter25/src/main/java/com/seaofnodes/simple/print/SimpleGraphAdapter.java
@@ -1,24 +1,14 @@
package com.seaofnodes.simple.print;
import com.seaofnodes.graph.GraphAdapter;
-import com.seaofnodes.graph.GraphSnapshot;
import com.seaofnodes.graph.GraphSnapshot.*;
import com.seaofnodes.simple.codegen.CodeGen;
import com.seaofnodes.simple.node.*;
import com.seaofnodes.simple.node.Node;
import com.seaofnodes.simple.type.TypeMem;
-import java.util.ArrayList;
/** Chapter 25's view of the IR, including partially constructed parse-time graphs. */
public class SimpleGraphAdapter extends GraphAdapter<Node> {
- @Override protected boolean dead(Node n) { return n.isDead(); }
- @Override protected int nDeps(Node n) { return n.nDeps(); }
- @Override protected Node dep(Node n, int idx) { return n.dep(idx); }
- @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 boolean show(Node n) {
if( n != CodeGen.CODE.ZERO && n != CodeGen.CODE.XCTRL ) return true;
@@ -27,27 +17,17 @@ public class SimpleGraphAdapter extends GraphAdapter<Node> {
return false; // The parser's keep is not a graph use.
}
- 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.var(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 Proj p
- ? new Projection(n.nIns() == 0 ? 0 : 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 Proj 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();
@@ -57,7 +37,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 StartCUNode ) return Kind.UNIT;
@@ -71,7 +51,7 @@ public class SimpleGraphAdapter extends GraphAdapter<Node> {
return 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 FunPtrNode ||
n instanceof CtrlNode || n instanceof XCtrlNode )
return Role.ASSOC;
@@ -85,8 +65,8 @@ public class SimpleGraphAdapter extends GraphAdapter<Node> {
// Preserve known slot roles even when an input is not attached/typed yet.
if( i == 0 || n instanceof RegionNode || n instanceof StopNode ) return Role.CTRL;
if( n instanceof MemMergeNode ||
- i == 1 && (n instanceof MemOpNode || n instanceof ReturnNode || n instanceof CallNode) ||
- n instanceof EscapeNode && i >= 2 ) return Role.MEM;
+ (i == 1 && (n instanceof MemOpNode || n instanceof ReturnNode || n instanceof CallNode)) ||
+ (n instanceof EscapeNode && i >= 2) ) return Role.MEM;
Node def = n.in(i);
if( def instanceof CFGNode ) return Role.CTRL;
if( def != null && isMem(def) ) return Role.MEM;