summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rwxr-xr-x.github/workflows/linearize.sh4
-rw-r--r--.gitignore1
-rw-r--r--Makefile5
-rw-r--r--README.md5
-rw-r--r--build-support/early-chapter.mk1
-rw-r--r--chapter01/pom.xml1
-rw-r--r--chapter01/src/main/java/com/seaofnodes/simple/node/ConstantNode.java4
-rw-r--r--chapter01/src/main/java/com/seaofnodes/simple/node/Node.java18
-rw-r--r--chapter01/src/main/java/com/seaofnodes/simple/print/SimpleGraphAdapter.java28
-rw-r--r--chapter02/pom.xml1
-rw-r--r--chapter02/src/main/java/com/seaofnodes/simple/node/AddNode.java8
-rw-r--r--chapter02/src/main/java/com/seaofnodes/simple/node/ConstantNode.java15
-rw-r--r--chapter02/src/main/java/com/seaofnodes/simple/node/DivNode.java8
-rw-r--r--chapter02/src/main/java/com/seaofnodes/simple/node/MinusNode.java7
-rw-r--r--chapter02/src/main/java/com/seaofnodes/simple/node/MulNode.java8
-rw-r--r--chapter02/src/main/java/com/seaofnodes/simple/node/Node.java56
-rw-r--r--chapter02/src/main/java/com/seaofnodes/simple/node/ReturnNode.java6
-rw-r--r--chapter02/src/main/java/com/seaofnodes/simple/node/StartNode.java7
-rw-r--r--chapter02/src/main/java/com/seaofnodes/simple/print/SimpleGraphAdapter.java28
-rw-r--r--chapter03/pom.xml1
-rw-r--r--chapter03/src/main/java/com/seaofnodes/simple/node/AddNode.java8
-rw-r--r--chapter03/src/main/java/com/seaofnodes/simple/node/ConstantNode.java15
-rw-r--r--chapter03/src/main/java/com/seaofnodes/simple/node/DivNode.java8
-rw-r--r--chapter03/src/main/java/com/seaofnodes/simple/node/MinusNode.java7
-rw-r--r--chapter03/src/main/java/com/seaofnodes/simple/node/MulNode.java8
-rw-r--r--chapter03/src/main/java/com/seaofnodes/simple/node/Node.java56
-rw-r--r--chapter03/src/main/java/com/seaofnodes/simple/node/ReturnNode.java6
-rw-r--r--chapter03/src/main/java/com/seaofnodes/simple/node/ScopeNode.java20
-rw-r--r--chapter03/src/main/java/com/seaofnodes/simple/node/StartNode.java7
-rw-r--r--chapter03/src/main/java/com/seaofnodes/simple/node/SubNode.java8
-rw-r--r--chapter03/src/main/java/com/seaofnodes/simple/print/SimpleGraphAdapter.java29
-rw-r--r--chapter04/Makefile3
-rw-r--r--chapter04/pom.xml1
-rw-r--r--chapter04/src/main/java/com/seaofnodes/simple/node/AddNode.java8
-rw-r--r--chapter04/src/main/java/com/seaofnodes/simple/node/BoolNode.java9
-rw-r--r--chapter04/src/main/java/com/seaofnodes/simple/node/ConstantNode.java15
-rw-r--r--chapter04/src/main/java/com/seaofnodes/simple/node/DivNode.java8
-rw-r--r--chapter04/src/main/java/com/seaofnodes/simple/node/MinusNode.java7
-rw-r--r--chapter04/src/main/java/com/seaofnodes/simple/node/MulNode.java8
-rw-r--r--chapter04/src/main/java/com/seaofnodes/simple/node/Node.java48
-rw-r--r--chapter04/src/main/java/com/seaofnodes/simple/node/NotNode.java7
-rw-r--r--chapter04/src/main/java/com/seaofnodes/simple/node/ProjNode.java4
-rw-r--r--chapter04/src/main/java/com/seaofnodes/simple/node/ReturnNode.java6
-rw-r--r--chapter04/src/main/java/com/seaofnodes/simple/node/ScopeNode.java20
-rw-r--r--chapter04/src/main/java/com/seaofnodes/simple/node/StartNode.java7
-rw-r--r--chapter04/src/main/java/com/seaofnodes/simple/node/SubNode.java8
-rw-r--r--chapter04/src/main/java/com/seaofnodes/simple/print/SimpleGraphAdapter.java33
-rw-r--r--chapter05/pom.xml1
-rw-r--r--chapter05/src/main/java/com/seaofnodes/simple/node/AddNode.java8
-rw-r--r--chapter05/src/main/java/com/seaofnodes/simple/node/BoolNode.java9
-rw-r--r--chapter05/src/main/java/com/seaofnodes/simple/node/ConstantNode.java15
-rw-r--r--chapter05/src/main/java/com/seaofnodes/simple/node/DivNode.java8
-rw-r--r--chapter05/src/main/java/com/seaofnodes/simple/node/IfNode.java7
-rw-r--r--chapter05/src/main/java/com/seaofnodes/simple/node/MinusNode.java7
-rw-r--r--chapter05/src/main/java/com/seaofnodes/simple/node/MulNode.java8
-rw-r--r--chapter05/src/main/java/com/seaofnodes/simple/node/Node.java48
-rw-r--r--chapter05/src/main/java/com/seaofnodes/simple/node/NotNode.java7
-rw-r--r--chapter05/src/main/java/com/seaofnodes/simple/node/PhiNode.java12
-rw-r--r--chapter05/src/main/java/com/seaofnodes/simple/node/ProjNode.java4
-rw-r--r--chapter05/src/main/java/com/seaofnodes/simple/node/RegionNode.java7
-rw-r--r--chapter05/src/main/java/com/seaofnodes/simple/node/ReturnNode.java6
-rw-r--r--chapter05/src/main/java/com/seaofnodes/simple/node/ScopeNode.java20
-rw-r--r--chapter05/src/main/java/com/seaofnodes/simple/node/StartNode.java7
-rw-r--r--chapter05/src/main/java/com/seaofnodes/simple/node/StopNode.java12
-rw-r--r--chapter05/src/main/java/com/seaofnodes/simple/node/SubNode.java8
-rw-r--r--chapter05/src/main/java/com/seaofnodes/simple/print/SimpleGraphAdapter.java30
-rw-r--r--chapter05/src/test/java/com/seaofnodes/simple/Chapter05Test.java2
-rw-r--r--chapter06/Makefile3
-rw-r--r--chapter06/pom.xml1
-rw-r--r--chapter06/src/main/java/com/seaofnodes/simple/node/AddNode.java8
-rw-r--r--chapter06/src/main/java/com/seaofnodes/simple/node/BoolNode.java9
-rw-r--r--chapter06/src/main/java/com/seaofnodes/simple/node/ConstantNode.java15
-rw-r--r--chapter06/src/main/java/com/seaofnodes/simple/node/DivNode.java8
-rw-r--r--chapter06/src/main/java/com/seaofnodes/simple/node/IfNode.java7
-rw-r--r--chapter06/src/main/java/com/seaofnodes/simple/node/MinusNode.java7
-rw-r--r--chapter06/src/main/java/com/seaofnodes/simple/node/MulNode.java8
-rw-r--r--chapter06/src/main/java/com/seaofnodes/simple/node/Node.java50
-rw-r--r--chapter06/src/main/java/com/seaofnodes/simple/node/NotNode.java7
-rw-r--r--chapter06/src/main/java/com/seaofnodes/simple/node/PhiNode.java12
-rw-r--r--chapter06/src/main/java/com/seaofnodes/simple/node/ProjNode.java4
-rw-r--r--chapter06/src/main/java/com/seaofnodes/simple/node/RegionNode.java7
-rw-r--r--chapter06/src/main/java/com/seaofnodes/simple/node/ReturnNode.java6
-rw-r--r--chapter06/src/main/java/com/seaofnodes/simple/node/ScopeNode.java20
-rw-r--r--chapter06/src/main/java/com/seaofnodes/simple/node/StartNode.java7
-rw-r--r--chapter06/src/main/java/com/seaofnodes/simple/node/StopNode.java12
-rw-r--r--chapter06/src/main/java/com/seaofnodes/simple/node/SubNode.java8
-rw-r--r--chapter06/src/main/java/com/seaofnodes/simple/print/SimpleGraphAdapter.java30
-rw-r--r--chapter06/src/test/java/com/seaofnodes/simple/Chapter05Test.java2
-rw-r--r--chapter06/src/test/java/com/seaofnodes/simple/Chapter06Test.java2
-rw-r--r--chapter07/Makefile3
-rw-r--r--chapter07/pom.xml1
-rw-r--r--chapter07/src/main/java/com/seaofnodes/simple/IRPrinter.java124
-rw-r--r--chapter07/src/main/java/com/seaofnodes/simple/node/AddNode.java9
-rw-r--r--chapter07/src/main/java/com/seaofnodes/simple/node/BoolNode.java10
-rw-r--r--chapter07/src/main/java/com/seaofnodes/simple/node/ConstantNode.java16
-rw-r--r--chapter07/src/main/java/com/seaofnodes/simple/node/DivNode.java9
-rw-r--r--chapter07/src/main/java/com/seaofnodes/simple/node/IfNode.java8
-rw-r--r--chapter07/src/main/java/com/seaofnodes/simple/node/MinusNode.java8
-rw-r--r--chapter07/src/main/java/com/seaofnodes/simple/node/MulNode.java9
-rw-r--r--chapter07/src/main/java/com/seaofnodes/simple/node/Node.java80
-rw-r--r--chapter07/src/main/java/com/seaofnodes/simple/node/NotNode.java8
-rw-r--r--chapter07/src/main/java/com/seaofnodes/simple/node/PhiNode.java19
-rw-r--r--chapter07/src/main/java/com/seaofnodes/simple/node/ProjNode.java5
-rw-r--r--chapter07/src/main/java/com/seaofnodes/simple/node/RegionNode.java8
-rw-r--r--chapter07/src/main/java/com/seaofnodes/simple/node/ReturnNode.java7
-rw-r--r--chapter07/src/main/java/com/seaofnodes/simple/node/ScopeNode.java13
-rw-r--r--chapter07/src/main/java/com/seaofnodes/simple/node/StartNode.java8
-rw-r--r--chapter07/src/main/java/com/seaofnodes/simple/node/StopNode.java13
-rw-r--r--chapter07/src/main/java/com/seaofnodes/simple/node/SubNode.java9
-rw-r--r--chapter07/src/main/java/com/seaofnodes/simple/print/SimpleGraphAdapter.java30
-rw-r--r--chapter08/Makefile3
-rw-r--r--chapter08/pom.xml1
-rw-r--r--chapter08/src/main/java/com/seaofnodes/simple/IRPrinter.java141
-rw-r--r--chapter08/src/main/java/com/seaofnodes/simple/node/AddNode.java9
-rw-r--r--chapter08/src/main/java/com/seaofnodes/simple/node/BoolNode.java10
-rw-r--r--chapter08/src/main/java/com/seaofnodes/simple/node/ConstantNode.java16
-rw-r--r--chapter08/src/main/java/com/seaofnodes/simple/node/DivNode.java9
-rw-r--r--chapter08/src/main/java/com/seaofnodes/simple/node/IfNode.java8
-rw-r--r--chapter08/src/main/java/com/seaofnodes/simple/node/MinusNode.java8
-rw-r--r--chapter08/src/main/java/com/seaofnodes/simple/node/MulNode.java9
-rw-r--r--chapter08/src/main/java/com/seaofnodes/simple/node/Node.java83
-rw-r--r--chapter08/src/main/java/com/seaofnodes/simple/node/NotNode.java8
-rw-r--r--chapter08/src/main/java/com/seaofnodes/simple/node/PhiNode.java19
-rw-r--r--chapter08/src/main/java/com/seaofnodes/simple/node/ProjNode.java5
-rw-r--r--chapter08/src/main/java/com/seaofnodes/simple/node/RegionNode.java8
-rw-r--r--chapter08/src/main/java/com/seaofnodes/simple/node/ReturnNode.java7
-rw-r--r--chapter08/src/main/java/com/seaofnodes/simple/node/ScopeNode.java15
-rw-r--r--chapter08/src/main/java/com/seaofnodes/simple/node/StartNode.java8
-rw-r--r--chapter08/src/main/java/com/seaofnodes/simple/node/StopNode.java13
-rw-r--r--chapter08/src/main/java/com/seaofnodes/simple/node/SubNode.java9
-rw-r--r--chapter08/src/main/java/com/seaofnodes/simple/print/SimpleGraphAdapter.java30
-rw-r--r--chapter09/Makefile3
-rw-r--r--chapter09/pom.xml1
-rw-r--r--chapter09/src/main/java/com/seaofnodes/simple/IRPrinter.java142
-rw-r--r--chapter09/src/main/java/com/seaofnodes/simple/node/AddNode.java9
-rw-r--r--chapter09/src/main/java/com/seaofnodes/simple/node/BoolNode.java10
-rw-r--r--chapter09/src/main/java/com/seaofnodes/simple/node/ConstantNode.java16
-rw-r--r--chapter09/src/main/java/com/seaofnodes/simple/node/DivNode.java9
-rw-r--r--chapter09/src/main/java/com/seaofnodes/simple/node/IfNode.java8
-rw-r--r--chapter09/src/main/java/com/seaofnodes/simple/node/MinusNode.java8
-rw-r--r--chapter09/src/main/java/com/seaofnodes/simple/node/MulNode.java9
-rw-r--r--chapter09/src/main/java/com/seaofnodes/simple/node/Node.java87
-rw-r--r--chapter09/src/main/java/com/seaofnodes/simple/node/NotNode.java8
-rw-r--r--chapter09/src/main/java/com/seaofnodes/simple/node/PhiNode.java19
-rw-r--r--chapter09/src/main/java/com/seaofnodes/simple/node/ProjNode.java5
-rw-r--r--chapter09/src/main/java/com/seaofnodes/simple/node/RegionNode.java8
-rw-r--r--chapter09/src/main/java/com/seaofnodes/simple/node/ReturnNode.java7
-rw-r--r--chapter09/src/main/java/com/seaofnodes/simple/node/ScopeNode.java15
-rw-r--r--chapter09/src/main/java/com/seaofnodes/simple/node/StartNode.java8
-rw-r--r--chapter09/src/main/java/com/seaofnodes/simple/node/StopNode.java13
-rw-r--r--chapter09/src/main/java/com/seaofnodes/simple/node/SubNode.java9
-rw-r--r--chapter09/src/main/java/com/seaofnodes/simple/print/SimpleGraphAdapter.java32
-rw-r--r--chapter10a/chapter10a.iml1
-rw-r--r--chapter10a/pom.xml1
-rw-r--r--chapter10a/src/main/java/com/seaofnodes/simple/IRPrinter.java213
-rw-r--r--chapter10a/src/main/java/com/seaofnodes/simple/node/AddNode.java9
-rw-r--r--chapter10a/src/main/java/com/seaofnodes/simple/node/BoolNode.java10
-rw-r--r--chapter10a/src/main/java/com/seaofnodes/simple/node/CastNode.java10
-rw-r--r--chapter10a/src/main/java/com/seaofnodes/simple/node/ConstantNode.java16
-rw-r--r--chapter10a/src/main/java/com/seaofnodes/simple/node/DivNode.java9
-rw-r--r--chapter10a/src/main/java/com/seaofnodes/simple/node/IfNode.java8
-rw-r--r--chapter10a/src/main/java/com/seaofnodes/simple/node/LoadNode.java5
-rw-r--r--chapter10a/src/main/java/com/seaofnodes/simple/node/MinusNode.java8
-rw-r--r--chapter10a/src/main/java/com/seaofnodes/simple/node/MulNode.java9
-rw-r--r--chapter10a/src/main/java/com/seaofnodes/simple/node/NewNode.java9
-rw-r--r--chapter10a/src/main/java/com/seaofnodes/simple/node/Node.java65
-rw-r--r--chapter10a/src/main/java/com/seaofnodes/simple/node/NotNode.java8
-rw-r--r--chapter10a/src/main/java/com/seaofnodes/simple/node/PhiNode.java19
-rw-r--r--chapter10a/src/main/java/com/seaofnodes/simple/node/ProjNode.java5
-rw-r--r--chapter10a/src/main/java/com/seaofnodes/simple/node/RegionNode.java8
-rw-r--r--chapter10a/src/main/java/com/seaofnodes/simple/node/ReturnNode.java11
-rw-r--r--chapter10a/src/main/java/com/seaofnodes/simple/node/ScopeNode.java15
-rw-r--r--chapter10a/src/main/java/com/seaofnodes/simple/node/StartNode.java8
-rw-r--r--chapter10a/src/main/java/com/seaofnodes/simple/node/StopNode.java13
-rw-r--r--chapter10a/src/main/java/com/seaofnodes/simple/node/StoreNode.java7
-rw-r--r--chapter10a/src/main/java/com/seaofnodes/simple/node/SubNode.java9
-rw-r--r--chapter10a/src/main/java/com/seaofnodes/simple/print/SimpleGraphAdapter.java32
-rw-r--r--chapter10b/chapter10b.iml1
-rw-r--r--chapter10b/pom.xml1
-rw-r--r--chapter10b/src/main/java/com/seaofnodes/simple/IRPrinter.java214
-rw-r--r--chapter10b/src/main/java/com/seaofnodes/simple/node/AddNode.java9
-rw-r--r--chapter10b/src/main/java/com/seaofnodes/simple/node/BoolNode.java10
-rw-r--r--chapter10b/src/main/java/com/seaofnodes/simple/node/CastNode.java10
-rw-r--r--chapter10b/src/main/java/com/seaofnodes/simple/node/ConstantNode.java16
-rw-r--r--chapter10b/src/main/java/com/seaofnodes/simple/node/DivNode.java9
-rw-r--r--chapter10b/src/main/java/com/seaofnodes/simple/node/IfNode.java8
-rw-r--r--chapter10b/src/main/java/com/seaofnodes/simple/node/LoadNode.java5
-rw-r--r--chapter10b/src/main/java/com/seaofnodes/simple/node/MemMergeNode.java13
-rw-r--r--chapter10b/src/main/java/com/seaofnodes/simple/node/MinusNode.java8
-rw-r--r--chapter10b/src/main/java/com/seaofnodes/simple/node/MulNode.java9
-rw-r--r--chapter10b/src/main/java/com/seaofnodes/simple/node/NewNode.java9
-rw-r--r--chapter10b/src/main/java/com/seaofnodes/simple/node/Node.java65
-rw-r--r--chapter10b/src/main/java/com/seaofnodes/simple/node/NotNode.java8
-rw-r--r--chapter10b/src/main/java/com/seaofnodes/simple/node/PhiNode.java19
-rw-r--r--chapter10b/src/main/java/com/seaofnodes/simple/node/ProjNode.java5
-rw-r--r--chapter10b/src/main/java/com/seaofnodes/simple/node/RegionNode.java8
-rw-r--r--chapter10b/src/main/java/com/seaofnodes/simple/node/ReturnNode.java11
-rw-r--r--chapter10b/src/main/java/com/seaofnodes/simple/node/ScopeNode.java15
-rw-r--r--chapter10b/src/main/java/com/seaofnodes/simple/node/StartNode.java8
-rw-r--r--chapter10b/src/main/java/com/seaofnodes/simple/node/StopNode.java13
-rw-r--r--chapter10b/src/main/java/com/seaofnodes/simple/node/StoreNode.java7
-rw-r--r--chapter10b/src/main/java/com/seaofnodes/simple/node/SubNode.java9
-rw-r--r--chapter10b/src/main/java/com/seaofnodes/simple/print/SimpleGraphAdapter.java32
-rw-r--r--chapter11/Makefile3
-rw-r--r--chapter11/pom.xml1
-rw-r--r--chapter11/src/main/java/com/seaofnodes/simple/IRPrinter.java311
-rw-r--r--chapter11/src/main/java/com/seaofnodes/simple/node/AddNode.java9
-rw-r--r--chapter11/src/main/java/com/seaofnodes/simple/node/BoolNode.java10
-rw-r--r--chapter11/src/main/java/com/seaofnodes/simple/node/CProjNode.java5
-rw-r--r--chapter11/src/main/java/com/seaofnodes/simple/node/CastNode.java10
-rw-r--r--chapter11/src/main/java/com/seaofnodes/simple/node/ConstantNode.java16
-rw-r--r--chapter11/src/main/java/com/seaofnodes/simple/node/DivNode.java9
-rw-r--r--chapter11/src/main/java/com/seaofnodes/simple/node/IfNode.java7
-rw-r--r--chapter11/src/main/java/com/seaofnodes/simple/node/LoadNode.java5
-rw-r--r--chapter11/src/main/java/com/seaofnodes/simple/node/MemMergeNode.java13
-rw-r--r--chapter11/src/main/java/com/seaofnodes/simple/node/MinusNode.java8
-rw-r--r--chapter11/src/main/java/com/seaofnodes/simple/node/MulNode.java9
-rw-r--r--chapter11/src/main/java/com/seaofnodes/simple/node/NeverNode.java5
-rw-r--r--chapter11/src/main/java/com/seaofnodes/simple/node/NewNode.java9
-rw-r--r--chapter11/src/main/java/com/seaofnodes/simple/node/Node.java63
-rw-r--r--chapter11/src/main/java/com/seaofnodes/simple/node/NotNode.java8
-rw-r--r--chapter11/src/main/java/com/seaofnodes/simple/node/PhiNode.java19
-rw-r--r--chapter11/src/main/java/com/seaofnodes/simple/node/ProjNode.java5
-rw-r--r--chapter11/src/main/java/com/seaofnodes/simple/node/RegionNode.java7
-rw-r--r--chapter11/src/main/java/com/seaofnodes/simple/node/ReturnNode.java11
-rw-r--r--chapter11/src/main/java/com/seaofnodes/simple/node/ScopeNode.java15
-rw-r--r--chapter11/src/main/java/com/seaofnodes/simple/node/StartNode.java7
-rw-r--r--chapter11/src/main/java/com/seaofnodes/simple/node/StopNode.java13
-rw-r--r--chapter11/src/main/java/com/seaofnodes/simple/node/StoreNode.java7
-rw-r--r--chapter11/src/main/java/com/seaofnodes/simple/node/SubNode.java9
-rw-r--r--chapter11/src/main/java/com/seaofnodes/simple/node/XCtrlNode.java5
-rw-r--r--chapter11/src/main/java/com/seaofnodes/simple/print/SimpleGraphAdapter.java33
-rw-r--r--chapter12/Makefile3
-rw-r--r--chapter12/pom.xml1
-rw-r--r--chapter12/src/main/java/com/seaofnodes/simple/IRPrinter.java311
-rw-r--r--chapter12/src/main/java/com/seaofnodes/simple/node/AddFNode.java9
-rw-r--r--chapter12/src/main/java/com/seaofnodes/simple/node/AddNode.java9
-rw-r--r--chapter12/src/main/java/com/seaofnodes/simple/node/BoolNode.java10
-rw-r--r--chapter12/src/main/java/com/seaofnodes/simple/node/CProjNode.java5
-rw-r--r--chapter12/src/main/java/com/seaofnodes/simple/node/CastNode.java10
-rw-r--r--chapter12/src/main/java/com/seaofnodes/simple/node/ConstantNode.java16
-rw-r--r--chapter12/src/main/java/com/seaofnodes/simple/node/DivFNode.java9
-rw-r--r--chapter12/src/main/java/com/seaofnodes/simple/node/DivNode.java9
-rw-r--r--chapter12/src/main/java/com/seaofnodes/simple/node/IfNode.java7
-rw-r--r--chapter12/src/main/java/com/seaofnodes/simple/node/LoadNode.java5
-rw-r--r--chapter12/src/main/java/com/seaofnodes/simple/node/MemMergeNode.java13
-rw-r--r--chapter12/src/main/java/com/seaofnodes/simple/node/MinusFNode.java8
-rw-r--r--chapter12/src/main/java/com/seaofnodes/simple/node/MinusNode.java8
-rw-r--r--chapter12/src/main/java/com/seaofnodes/simple/node/MulFNode.java9
-rw-r--r--chapter12/src/main/java/com/seaofnodes/simple/node/MulNode.java9
-rw-r--r--chapter12/src/main/java/com/seaofnodes/simple/node/NeverNode.java5
-rw-r--r--chapter12/src/main/java/com/seaofnodes/simple/node/NewNode.java9
-rw-r--r--chapter12/src/main/java/com/seaofnodes/simple/node/Node.java64
-rw-r--r--chapter12/src/main/java/com/seaofnodes/simple/node/NotNode.java8
-rw-r--r--chapter12/src/main/java/com/seaofnodes/simple/node/PhiNode.java19
-rw-r--r--chapter12/src/main/java/com/seaofnodes/simple/node/ProjNode.java5
-rw-r--r--chapter12/src/main/java/com/seaofnodes/simple/node/RegionNode.java7
-rw-r--r--chapter12/src/main/java/com/seaofnodes/simple/node/ReturnNode.java11
-rw-r--r--chapter12/src/main/java/com/seaofnodes/simple/node/ScopeNode.java15
-rw-r--r--chapter12/src/main/java/com/seaofnodes/simple/node/StartNode.java7
-rw-r--r--chapter12/src/main/java/com/seaofnodes/simple/node/StopNode.java13
-rw-r--r--chapter12/src/main/java/com/seaofnodes/simple/node/StoreNode.java7
-rw-r--r--chapter12/src/main/java/com/seaofnodes/simple/node/SubFNode.java9
-rw-r--r--chapter12/src/main/java/com/seaofnodes/simple/node/SubNode.java9
-rw-r--r--chapter12/src/main/java/com/seaofnodes/simple/node/ToFloatNode.java7
-rw-r--r--chapter12/src/main/java/com/seaofnodes/simple/node/XCtrlNode.java5
-rw-r--r--chapter12/src/main/java/com/seaofnodes/simple/print/SimpleGraphAdapter.java33
-rw-r--r--chapter13/Makefile3
-rw-r--r--chapter13/pom.xml1
-rw-r--r--chapter13/src/main/java/com/seaofnodes/simple/IRPrinter.java311
-rw-r--r--chapter13/src/main/java/com/seaofnodes/simple/node/AddFNode.java9
-rw-r--r--chapter13/src/main/java/com/seaofnodes/simple/node/AddNode.java9
-rw-r--r--chapter13/src/main/java/com/seaofnodes/simple/node/BoolNode.java10
-rw-r--r--chapter13/src/main/java/com/seaofnodes/simple/node/CProjNode.java5
-rw-r--r--chapter13/src/main/java/com/seaofnodes/simple/node/CastNode.java10
-rw-r--r--chapter13/src/main/java/com/seaofnodes/simple/node/ConstantNode.java16
-rw-r--r--chapter13/src/main/java/com/seaofnodes/simple/node/DivFNode.java9
-rw-r--r--chapter13/src/main/java/com/seaofnodes/simple/node/DivNode.java9
-rw-r--r--chapter13/src/main/java/com/seaofnodes/simple/node/IfNode.java7
-rw-r--r--chapter13/src/main/java/com/seaofnodes/simple/node/LoadNode.java5
-rw-r--r--chapter13/src/main/java/com/seaofnodes/simple/node/MemMergeNode.java13
-rw-r--r--chapter13/src/main/java/com/seaofnodes/simple/node/MinusFNode.java8
-rw-r--r--chapter13/src/main/java/com/seaofnodes/simple/node/MinusNode.java8
-rw-r--r--chapter13/src/main/java/com/seaofnodes/simple/node/MulFNode.java9
-rw-r--r--chapter13/src/main/java/com/seaofnodes/simple/node/MulNode.java9
-rw-r--r--chapter13/src/main/java/com/seaofnodes/simple/node/NeverNode.java5
-rw-r--r--chapter13/src/main/java/com/seaofnodes/simple/node/NewNode.java9
-rw-r--r--chapter13/src/main/java/com/seaofnodes/simple/node/Node.java64
-rw-r--r--chapter13/src/main/java/com/seaofnodes/simple/node/NotNode.java8
-rw-r--r--chapter13/src/main/java/com/seaofnodes/simple/node/PhiNode.java19
-rw-r--r--chapter13/src/main/java/com/seaofnodes/simple/node/ProjNode.java5
-rw-r--r--chapter13/src/main/java/com/seaofnodes/simple/node/RegionNode.java7
-rw-r--r--chapter13/src/main/java/com/seaofnodes/simple/node/ReturnNode.java11
-rw-r--r--chapter13/src/main/java/com/seaofnodes/simple/node/ScopeNode.java15
-rw-r--r--chapter13/src/main/java/com/seaofnodes/simple/node/StartNode.java7
-rw-r--r--chapter13/src/main/java/com/seaofnodes/simple/node/StopNode.java13
-rw-r--r--chapter13/src/main/java/com/seaofnodes/simple/node/StoreNode.java7
-rw-r--r--chapter13/src/main/java/com/seaofnodes/simple/node/SubFNode.java9
-rw-r--r--chapter13/src/main/java/com/seaofnodes/simple/node/SubNode.java9
-rw-r--r--chapter13/src/main/java/com/seaofnodes/simple/node/ToFloatNode.java7
-rw-r--r--chapter13/src/main/java/com/seaofnodes/simple/node/XCtrlNode.java5
-rw-r--r--chapter13/src/main/java/com/seaofnodes/simple/print/SimpleGraphAdapter.java33
-rw-r--r--chapter14/Makefile3
-rw-r--r--chapter14/pom.xml1
-rw-r--r--chapter14/src/main/java/com/seaofnodes/simple/IRPrinter.java311
-rw-r--r--chapter14/src/main/java/com/seaofnodes/simple/node/AddFNode.java9
-rw-r--r--chapter14/src/main/java/com/seaofnodes/simple/node/AddNode.java9
-rw-r--r--chapter14/src/main/java/com/seaofnodes/simple/node/AndNode.java9
-rw-r--r--chapter14/src/main/java/com/seaofnodes/simple/node/BoolNode.java10
-rw-r--r--chapter14/src/main/java/com/seaofnodes/simple/node/CProjNode.java5
-rw-r--r--chapter14/src/main/java/com/seaofnodes/simple/node/CastNode.java10
-rw-r--r--chapter14/src/main/java/com/seaofnodes/simple/node/ConstantNode.java16
-rw-r--r--chapter14/src/main/java/com/seaofnodes/simple/node/DivFNode.java9
-rw-r--r--chapter14/src/main/java/com/seaofnodes/simple/node/DivNode.java9
-rw-r--r--chapter14/src/main/java/com/seaofnodes/simple/node/IfNode.java7
-rw-r--r--chapter14/src/main/java/com/seaofnodes/simple/node/LoadNode.java5
-rw-r--r--chapter14/src/main/java/com/seaofnodes/simple/node/MemMergeNode.java13
-rw-r--r--chapter14/src/main/java/com/seaofnodes/simple/node/MinusFNode.java8
-rw-r--r--chapter14/src/main/java/com/seaofnodes/simple/node/MinusNode.java8
-rw-r--r--chapter14/src/main/java/com/seaofnodes/simple/node/MulFNode.java9
-rw-r--r--chapter14/src/main/java/com/seaofnodes/simple/node/MulNode.java9
-rw-r--r--chapter14/src/main/java/com/seaofnodes/simple/node/NeverNode.java5
-rw-r--r--chapter14/src/main/java/com/seaofnodes/simple/node/NewNode.java9
-rw-r--r--chapter14/src/main/java/com/seaofnodes/simple/node/Node.java62
-rw-r--r--chapter14/src/main/java/com/seaofnodes/simple/node/NotNode.java8
-rw-r--r--chapter14/src/main/java/com/seaofnodes/simple/node/OrNode.java9
-rw-r--r--chapter14/src/main/java/com/seaofnodes/simple/node/PhiNode.java19
-rw-r--r--chapter14/src/main/java/com/seaofnodes/simple/node/ProjNode.java5
-rw-r--r--chapter14/src/main/java/com/seaofnodes/simple/node/RegionNode.java7
-rw-r--r--chapter14/src/main/java/com/seaofnodes/simple/node/ReturnNode.java11
-rw-r--r--chapter14/src/main/java/com/seaofnodes/simple/node/RoundF32Node.java7
-rw-r--r--chapter14/src/main/java/com/seaofnodes/simple/node/SarNode.java9
-rw-r--r--chapter14/src/main/java/com/seaofnodes/simple/node/ScopeNode.java15
-rw-r--r--chapter14/src/main/java/com/seaofnodes/simple/node/ShlNode.java9
-rw-r--r--chapter14/src/main/java/com/seaofnodes/simple/node/ShrNode.java9
-rw-r--r--chapter14/src/main/java/com/seaofnodes/simple/node/StartNode.java7
-rw-r--r--chapter14/src/main/java/com/seaofnodes/simple/node/StopNode.java13
-rw-r--r--chapter14/src/main/java/com/seaofnodes/simple/node/StoreNode.java7
-rw-r--r--chapter14/src/main/java/com/seaofnodes/simple/node/SubFNode.java9
-rw-r--r--chapter14/src/main/java/com/seaofnodes/simple/node/SubNode.java9
-rw-r--r--chapter14/src/main/java/com/seaofnodes/simple/node/ToFloatNode.java7
-rw-r--r--chapter14/src/main/java/com/seaofnodes/simple/node/XCtrlNode.java5
-rw-r--r--chapter14/src/main/java/com/seaofnodes/simple/node/XorNode.java9
-rw-r--r--chapter14/src/main/java/com/seaofnodes/simple/print/SimpleGraphAdapter.java33
-rw-r--r--chapter15/Makefile3
-rw-r--r--chapter15/pom.xml1
-rw-r--r--chapter15/src/main/java/com/seaofnodes/simple/IRPrinter.java329
-rw-r--r--chapter15/src/main/java/com/seaofnodes/simple/node/AddFNode.java9
-rw-r--r--chapter15/src/main/java/com/seaofnodes/simple/node/AddNode.java9
-rw-r--r--chapter15/src/main/java/com/seaofnodes/simple/node/AndNode.java9
-rw-r--r--chapter15/src/main/java/com/seaofnodes/simple/node/BoolNode.java10
-rw-r--r--chapter15/src/main/java/com/seaofnodes/simple/node/CProjNode.java5
-rw-r--r--chapter15/src/main/java/com/seaofnodes/simple/node/CastNode.java10
-rw-r--r--chapter15/src/main/java/com/seaofnodes/simple/node/ConstantNode.java16
-rw-r--r--chapter15/src/main/java/com/seaofnodes/simple/node/DivFNode.java9
-rw-r--r--chapter15/src/main/java/com/seaofnodes/simple/node/DivNode.java9
-rw-r--r--chapter15/src/main/java/com/seaofnodes/simple/node/IfNode.java7
-rw-r--r--chapter15/src/main/java/com/seaofnodes/simple/node/LoadNode.java4
-rw-r--r--chapter15/src/main/java/com/seaofnodes/simple/node/MemMergeNode.java13
-rw-r--r--chapter15/src/main/java/com/seaofnodes/simple/node/MinusFNode.java8
-rw-r--r--chapter15/src/main/java/com/seaofnodes/simple/node/MinusNode.java8
-rw-r--r--chapter15/src/main/java/com/seaofnodes/simple/node/MulFNode.java9
-rw-r--r--chapter15/src/main/java/com/seaofnodes/simple/node/MulNode.java9
-rw-r--r--chapter15/src/main/java/com/seaofnodes/simple/node/NeverNode.java5
-rw-r--r--chapter15/src/main/java/com/seaofnodes/simple/node/NewNode.java9
-rw-r--r--chapter15/src/main/java/com/seaofnodes/simple/node/Node.java61
-rw-r--r--chapter15/src/main/java/com/seaofnodes/simple/node/NotNode.java8
-rw-r--r--chapter15/src/main/java/com/seaofnodes/simple/node/OrNode.java9
-rw-r--r--chapter15/src/main/java/com/seaofnodes/simple/node/PhiNode.java19
-rw-r--r--chapter15/src/main/java/com/seaofnodes/simple/node/ProjNode.java5
-rw-r--r--chapter15/src/main/java/com/seaofnodes/simple/node/RegionNode.java7
-rw-r--r--chapter15/src/main/java/com/seaofnodes/simple/node/ReturnNode.java11
-rw-r--r--chapter15/src/main/java/com/seaofnodes/simple/node/RoundF32Node.java7
-rw-r--r--chapter15/src/main/java/com/seaofnodes/simple/node/SarNode.java9
-rw-r--r--chapter15/src/main/java/com/seaofnodes/simple/node/ScopeNode.java15
-rw-r--r--chapter15/src/main/java/com/seaofnodes/simple/node/ShlNode.java9
-rw-r--r--chapter15/src/main/java/com/seaofnodes/simple/node/ShrNode.java9
-rw-r--r--chapter15/src/main/java/com/seaofnodes/simple/node/StartNode.java7
-rw-r--r--chapter15/src/main/java/com/seaofnodes/simple/node/StopNode.java13
-rw-r--r--chapter15/src/main/java/com/seaofnodes/simple/node/StoreNode.java7
-rw-r--r--chapter15/src/main/java/com/seaofnodes/simple/node/SubFNode.java9
-rw-r--r--chapter15/src/main/java/com/seaofnodes/simple/node/SubNode.java9
-rw-r--r--chapter15/src/main/java/com/seaofnodes/simple/node/ToFloatNode.java7
-rw-r--r--chapter15/src/main/java/com/seaofnodes/simple/node/XCtrlNode.java5
-rw-r--r--chapter15/src/main/java/com/seaofnodes/simple/node/XorNode.java9
-rw-r--r--chapter15/src/main/java/com/seaofnodes/simple/print/SimpleGraphAdapter.java33
-rw-r--r--chapter16/Makefile3
-rw-r--r--chapter16/pom.xml1
-rw-r--r--chapter16/src/main/java/com/seaofnodes/simple/IRPrinter.java329
-rw-r--r--chapter16/src/main/java/com/seaofnodes/simple/node/AddFNode.java9
-rw-r--r--chapter16/src/main/java/com/seaofnodes/simple/node/AddNode.java9
-rw-r--r--chapter16/src/main/java/com/seaofnodes/simple/node/AndNode.java9
-rw-r--r--chapter16/src/main/java/com/seaofnodes/simple/node/BoolNode.java10
-rw-r--r--chapter16/src/main/java/com/seaofnodes/simple/node/CProjNode.java5
-rw-r--r--chapter16/src/main/java/com/seaofnodes/simple/node/CastNode.java10
-rw-r--r--chapter16/src/main/java/com/seaofnodes/simple/node/ConstantNode.java16
-rw-r--r--chapter16/src/main/java/com/seaofnodes/simple/node/DivFNode.java9
-rw-r--r--chapter16/src/main/java/com/seaofnodes/simple/node/DivNode.java9
-rw-r--r--chapter16/src/main/java/com/seaofnodes/simple/node/IfNode.java7
-rw-r--r--chapter16/src/main/java/com/seaofnodes/simple/node/LoadNode.java4
-rw-r--r--chapter16/src/main/java/com/seaofnodes/simple/node/MemMergeNode.java13
-rw-r--r--chapter16/src/main/java/com/seaofnodes/simple/node/MinusFNode.java8
-rw-r--r--chapter16/src/main/java/com/seaofnodes/simple/node/MinusNode.java8
-rw-r--r--chapter16/src/main/java/com/seaofnodes/simple/node/MulFNode.java9
-rw-r--r--chapter16/src/main/java/com/seaofnodes/simple/node/MulNode.java9
-rw-r--r--chapter16/src/main/java/com/seaofnodes/simple/node/NeverNode.java5
-rw-r--r--chapter16/src/main/java/com/seaofnodes/simple/node/NewNode.java9
-rw-r--r--chapter16/src/main/java/com/seaofnodes/simple/node/Node.java62
-rw-r--r--chapter16/src/main/java/com/seaofnodes/simple/node/NotNode.java8
-rw-r--r--chapter16/src/main/java/com/seaofnodes/simple/node/OrNode.java9
-rw-r--r--chapter16/src/main/java/com/seaofnodes/simple/node/PhiNode.java19
-rw-r--r--chapter16/src/main/java/com/seaofnodes/simple/node/ProjNode.java5
-rw-r--r--chapter16/src/main/java/com/seaofnodes/simple/node/RegionNode.java7
-rw-r--r--chapter16/src/main/java/com/seaofnodes/simple/node/ReturnNode.java11
-rw-r--r--chapter16/src/main/java/com/seaofnodes/simple/node/RoundF32Node.java7
-rw-r--r--chapter16/src/main/java/com/seaofnodes/simple/node/SarNode.java9
-rw-r--r--chapter16/src/main/java/com/seaofnodes/simple/node/ScopeNode.java28
-rw-r--r--chapter16/src/main/java/com/seaofnodes/simple/node/ShlNode.java9
-rw-r--r--chapter16/src/main/java/com/seaofnodes/simple/node/ShrNode.java9
-rw-r--r--chapter16/src/main/java/com/seaofnodes/simple/node/StartNode.java7
-rw-r--r--chapter16/src/main/java/com/seaofnodes/simple/node/StopNode.java13
-rw-r--r--chapter16/src/main/java/com/seaofnodes/simple/node/StoreNode.java7
-rw-r--r--chapter16/src/main/java/com/seaofnodes/simple/node/StructNode.java18
-rw-r--r--chapter16/src/main/java/com/seaofnodes/simple/node/SubFNode.java9
-rw-r--r--chapter16/src/main/java/com/seaofnodes/simple/node/SubNode.java9
-rw-r--r--chapter16/src/main/java/com/seaofnodes/simple/node/ToFloatNode.java7
-rw-r--r--chapter16/src/main/java/com/seaofnodes/simple/node/XCtrlNode.java5
-rw-r--r--chapter16/src/main/java/com/seaofnodes/simple/node/XorNode.java9
-rw-r--r--chapter16/src/main/java/com/seaofnodes/simple/print/SimpleGraphAdapter.java32
-rw-r--r--chapter17/Makefile3
-rw-r--r--chapter17/pom.xml1
-rw-r--r--chapter17/src/main/java/com/seaofnodes/simple/IRPrinter.java330
-rw-r--r--chapter17/src/main/java/com/seaofnodes/simple/node/AddFNode.java9
-rw-r--r--chapter17/src/main/java/com/seaofnodes/simple/node/AddNode.java9
-rw-r--r--chapter17/src/main/java/com/seaofnodes/simple/node/AndNode.java9
-rw-r--r--chapter17/src/main/java/com/seaofnodes/simple/node/BoolNode.java10
-rw-r--r--chapter17/src/main/java/com/seaofnodes/simple/node/CProjNode.java5
-rw-r--r--chapter17/src/main/java/com/seaofnodes/simple/node/CastNode.java10
-rw-r--r--chapter17/src/main/java/com/seaofnodes/simple/node/ConstantNode.java16
-rw-r--r--chapter17/src/main/java/com/seaofnodes/simple/node/DivFNode.java9
-rw-r--r--chapter17/src/main/java/com/seaofnodes/simple/node/DivNode.java9
-rw-r--r--chapter17/src/main/java/com/seaofnodes/simple/node/IfNode.java8
-rw-r--r--chapter17/src/main/java/com/seaofnodes/simple/node/LoadNode.java4
-rw-r--r--chapter17/src/main/java/com/seaofnodes/simple/node/MemMergeNode.java13
-rw-r--r--chapter17/src/main/java/com/seaofnodes/simple/node/MinusFNode.java8
-rw-r--r--chapter17/src/main/java/com/seaofnodes/simple/node/MinusNode.java8
-rw-r--r--chapter17/src/main/java/com/seaofnodes/simple/node/MulFNode.java9
-rw-r--r--chapter17/src/main/java/com/seaofnodes/simple/node/MulNode.java9
-rw-r--r--chapter17/src/main/java/com/seaofnodes/simple/node/NeverNode.java5
-rw-r--r--chapter17/src/main/java/com/seaofnodes/simple/node/NewNode.java9
-rw-r--r--chapter17/src/main/java/com/seaofnodes/simple/node/Node.java62
-rw-r--r--chapter17/src/main/java/com/seaofnodes/simple/node/NotNode.java8
-rw-r--r--chapter17/src/main/java/com/seaofnodes/simple/node/OrNode.java9
-rw-r--r--chapter17/src/main/java/com/seaofnodes/simple/node/PhiNode.java19
-rw-r--r--chapter17/src/main/java/com/seaofnodes/simple/node/ProjNode.java5
-rw-r--r--chapter17/src/main/java/com/seaofnodes/simple/node/ReadOnlyNode.java7
-rw-r--r--chapter17/src/main/java/com/seaofnodes/simple/node/RegionNode.java8
-rw-r--r--chapter17/src/main/java/com/seaofnodes/simple/node/ReturnNode.java11
-rw-r--r--chapter17/src/main/java/com/seaofnodes/simple/node/RoundF32Node.java7
-rw-r--r--chapter17/src/main/java/com/seaofnodes/simple/node/SarNode.java9
-rw-r--r--chapter17/src/main/java/com/seaofnodes/simple/node/ScopeNode.java28
-rw-r--r--chapter17/src/main/java/com/seaofnodes/simple/node/ShlNode.java9
-rw-r--r--chapter17/src/main/java/com/seaofnodes/simple/node/ShrNode.java9
-rw-r--r--chapter17/src/main/java/com/seaofnodes/simple/node/StartNode.java8
-rw-r--r--chapter17/src/main/java/com/seaofnodes/simple/node/StopNode.java13
-rw-r--r--chapter17/src/main/java/com/seaofnodes/simple/node/StoreNode.java7
-rw-r--r--chapter17/src/main/java/com/seaofnodes/simple/node/StructNode.java18
-rw-r--r--chapter17/src/main/java/com/seaofnodes/simple/node/SubFNode.java9
-rw-r--r--chapter17/src/main/java/com/seaofnodes/simple/node/SubNode.java9
-rw-r--r--chapter17/src/main/java/com/seaofnodes/simple/node/ToFloatNode.java7
-rw-r--r--chapter17/src/main/java/com/seaofnodes/simple/node/XCtrlNode.java5
-rw-r--r--chapter17/src/main/java/com/seaofnodes/simple/node/XorNode.java9
-rw-r--r--chapter17/src/main/java/com/seaofnodes/simple/print/SimpleGraphAdapter.java32
-rw-r--r--chapter18/Makefile3
-rw-r--r--chapter18/pom.xml1
-rw-r--r--chapter18/src/main/java/com/seaofnodes/simple/CodeGen.java2
-rw-r--r--chapter18/src/main/java/com/seaofnodes/simple/IRPrinter.java343
-rw-r--r--chapter18/src/main/java/com/seaofnodes/simple/node/AddFNode.java9
-rw-r--r--chapter18/src/main/java/com/seaofnodes/simple/node/AddNode.java9
-rw-r--r--chapter18/src/main/java/com/seaofnodes/simple/node/BoolNode.java10
-rw-r--r--chapter18/src/main/java/com/seaofnodes/simple/node/CProjNode.java5
-rw-r--r--chapter18/src/main/java/com/seaofnodes/simple/node/CallEndNode.java14
-rw-r--r--chapter18/src/main/java/com/seaofnodes/simple/node/CallNode.java16
-rw-r--r--chapter18/src/main/java/com/seaofnodes/simple/node/CastNode.java10
-rw-r--r--chapter18/src/main/java/com/seaofnodes/simple/node/ConstantNode.java16
-rw-r--r--chapter18/src/main/java/com/seaofnodes/simple/node/CtrlNode.java5
-rw-r--r--chapter18/src/main/java/com/seaofnodes/simple/node/DivFNode.java9
-rw-r--r--chapter18/src/main/java/com/seaofnodes/simple/node/DivNode.java9
-rw-r--r--chapter18/src/main/java/com/seaofnodes/simple/node/FRefNode.java8
-rw-r--r--chapter18/src/main/java/com/seaofnodes/simple/node/IfNode.java8
-rw-r--r--chapter18/src/main/java/com/seaofnodes/simple/node/LoadNode.java4
-rw-r--r--chapter18/src/main/java/com/seaofnodes/simple/node/LogicalNode.java10
-rw-r--r--chapter18/src/main/java/com/seaofnodes/simple/node/MemMergeNode.java13
-rw-r--r--chapter18/src/main/java/com/seaofnodes/simple/node/MinusFNode.java8
-rw-r--r--chapter18/src/main/java/com/seaofnodes/simple/node/MinusNode.java8
-rw-r--r--chapter18/src/main/java/com/seaofnodes/simple/node/MulFNode.java9
-rw-r--r--chapter18/src/main/java/com/seaofnodes/simple/node/MulNode.java9
-rw-r--r--chapter18/src/main/java/com/seaofnodes/simple/node/NeverNode.java5
-rw-r--r--chapter18/src/main/java/com/seaofnodes/simple/node/NewNode.java9
-rw-r--r--chapter18/src/main/java/com/seaofnodes/simple/node/Node.java62
-rw-r--r--chapter18/src/main/java/com/seaofnodes/simple/node/NotNode.java8
-rw-r--r--chapter18/src/main/java/com/seaofnodes/simple/node/ParmNode.java19
-rw-r--r--chapter18/src/main/java/com/seaofnodes/simple/node/PhiNode.java19
-rw-r--r--chapter18/src/main/java/com/seaofnodes/simple/node/ProjNode.java11
-rw-r--r--chapter18/src/main/java/com/seaofnodes/simple/node/ReadOnlyNode.java7
-rw-r--r--chapter18/src/main/java/com/seaofnodes/simple/node/RegionNode.java8
-rw-r--r--chapter18/src/main/java/com/seaofnodes/simple/node/ReturnNode.java11
-rw-r--r--chapter18/src/main/java/com/seaofnodes/simple/node/RoundF32Node.java7
-rw-r--r--chapter18/src/main/java/com/seaofnodes/simple/node/ScopeNode.java28
-rw-r--r--chapter18/src/main/java/com/seaofnodes/simple/node/StartNode.java8
-rw-r--r--chapter18/src/main/java/com/seaofnodes/simple/node/StopNode.java13
-rw-r--r--chapter18/src/main/java/com/seaofnodes/simple/node/StoreNode.java7
-rw-r--r--chapter18/src/main/java/com/seaofnodes/simple/node/StructNode.java18
-rw-r--r--chapter18/src/main/java/com/seaofnodes/simple/node/SubFNode.java9
-rw-r--r--chapter18/src/main/java/com/seaofnodes/simple/node/SubNode.java9
-rw-r--r--chapter18/src/main/java/com/seaofnodes/simple/node/ToFloatNode.java7
-rw-r--r--chapter18/src/main/java/com/seaofnodes/simple/node/XCtrlNode.java5
-rw-r--r--chapter18/src/main/java/com/seaofnodes/simple/print/SimpleGraphAdapter.java38
-rw-r--r--chapter19/Makefile3
-rw-r--r--chapter19/pom.xml1
-rw-r--r--chapter19/src/main/java/com/seaofnodes/simple/ASMPrinter.java173
-rw-r--r--chapter19/src/main/java/com/seaofnodes/simple/CodeGen.java2
-rw-r--r--chapter19/src/main/java/com/seaofnodes/simple/IRPrinter.java342
-rw-r--r--chapter19/src/main/java/com/seaofnodes/simple/node/AddFNode.java9
-rw-r--r--chapter19/src/main/java/com/seaofnodes/simple/node/AddNode.java9
-rw-r--r--chapter19/src/main/java/com/seaofnodes/simple/node/BoolNode.java10
-rw-r--r--chapter19/src/main/java/com/seaofnodes/simple/node/CProjNode.java5
-rw-r--r--chapter19/src/main/java/com/seaofnodes/simple/node/CallEndNode.java14
-rw-r--r--chapter19/src/main/java/com/seaofnodes/simple/node/CallNode.java16
-rw-r--r--chapter19/src/main/java/com/seaofnodes/simple/node/CastNode.java10
-rw-r--r--chapter19/src/main/java/com/seaofnodes/simple/node/ConstantNode.java17
-rw-r--r--chapter19/src/main/java/com/seaofnodes/simple/node/CtrlNode.java5
-rw-r--r--chapter19/src/main/java/com/seaofnodes/simple/node/DivFNode.java9
-rw-r--r--chapter19/src/main/java/com/seaofnodes/simple/node/DivNode.java9
-rw-r--r--chapter19/src/main/java/com/seaofnodes/simple/node/FRefNode.java8
-rw-r--r--chapter19/src/main/java/com/seaofnodes/simple/node/IfNode.java8
-rw-r--r--chapter19/src/main/java/com/seaofnodes/simple/node/LoadNode.java5
-rw-r--r--chapter19/src/main/java/com/seaofnodes/simple/node/LogicalNode.java10
-rw-r--r--chapter19/src/main/java/com/seaofnodes/simple/node/MachConcreteNode.java12
-rw-r--r--chapter19/src/main/java/com/seaofnodes/simple/node/MemMergeNode.java13
-rw-r--r--chapter19/src/main/java/com/seaofnodes/simple/node/MemOpNode.java6
-rw-r--r--chapter19/src/main/java/com/seaofnodes/simple/node/MinusFNode.java8
-rw-r--r--chapter19/src/main/java/com/seaofnodes/simple/node/MinusNode.java8
-rw-r--r--chapter19/src/main/java/com/seaofnodes/simple/node/MulFNode.java9
-rw-r--r--chapter19/src/main/java/com/seaofnodes/simple/node/MulNode.java9
-rw-r--r--chapter19/src/main/java/com/seaofnodes/simple/node/NeverNode.java5
-rw-r--r--chapter19/src/main/java/com/seaofnodes/simple/node/NewNode.java9
-rw-r--r--chapter19/src/main/java/com/seaofnodes/simple/node/Node.java67
-rw-r--r--chapter19/src/main/java/com/seaofnodes/simple/node/NotNode.java8
-rw-r--r--chapter19/src/main/java/com/seaofnodes/simple/node/ParmNode.java19
-rw-r--r--chapter19/src/main/java/com/seaofnodes/simple/node/PhiNode.java19
-rw-r--r--chapter19/src/main/java/com/seaofnodes/simple/node/ProjNode.java11
-rw-r--r--chapter19/src/main/java/com/seaofnodes/simple/node/ReadOnlyNode.java7
-rw-r--r--chapter19/src/main/java/com/seaofnodes/simple/node/RegionNode.java7
-rw-r--r--chapter19/src/main/java/com/seaofnodes/simple/node/ReturnNode.java11
-rw-r--r--chapter19/src/main/java/com/seaofnodes/simple/node/RoundF32Node.java7
-rw-r--r--chapter19/src/main/java/com/seaofnodes/simple/node/ScopeNode.java28
-rw-r--r--chapter19/src/main/java/com/seaofnodes/simple/node/StartNode.java8
-rw-r--r--chapter19/src/main/java/com/seaofnodes/simple/node/StopNode.java13
-rw-r--r--chapter19/src/main/java/com/seaofnodes/simple/node/StoreNode.java7
-rw-r--r--chapter19/src/main/java/com/seaofnodes/simple/node/StructNode.java18
-rw-r--r--chapter19/src/main/java/com/seaofnodes/simple/node/SubFNode.java9
-rw-r--r--chapter19/src/main/java/com/seaofnodes/simple/node/SubNode.java9
-rw-r--r--chapter19/src/main/java/com/seaofnodes/simple/node/ToFloatNode.java7
-rw-r--r--chapter19/src/main/java/com/seaofnodes/simple/node/XCtrlNode.java5
-rw-r--r--chapter19/src/main/java/com/seaofnodes/simple/node/cpus/riscv/MemOpRISC.java5
-rw-r--r--chapter19/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/MemOpX86.java5
-rw-r--r--chapter19/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/StoreX86.java7
-rw-r--r--chapter19/src/main/java/com/seaofnodes/simple/print/SimpleGraphAdapter.java38
-rw-r--r--chapter20/Makefile3
-rw-r--r--chapter20/pom.xml1
-rw-r--r--chapter20/src/main/java/com/seaofnodes/simple/codegen/CodeGen.java2
-rw-r--r--chapter20/src/main/java/com/seaofnodes/simple/node/AddFNode.java9
-rw-r--r--chapter20/src/main/java/com/seaofnodes/simple/node/AddNode.java9
-rw-r--r--chapter20/src/main/java/com/seaofnodes/simple/node/BoolNode.java10
-rw-r--r--chapter20/src/main/java/com/seaofnodes/simple/node/CProjNode.java5
-rw-r--r--chapter20/src/main/java/com/seaofnodes/simple/node/CallEndNode.java14
-rw-r--r--chapter20/src/main/java/com/seaofnodes/simple/node/CallNode.java16
-rw-r--r--chapter20/src/main/java/com/seaofnodes/simple/node/CastNode.java10
-rw-r--r--chapter20/src/main/java/com/seaofnodes/simple/node/ConstantNode.java17
-rw-r--r--chapter20/src/main/java/com/seaofnodes/simple/node/CtrlNode.java5
-rw-r--r--chapter20/src/main/java/com/seaofnodes/simple/node/DivFNode.java9
-rw-r--r--chapter20/src/main/java/com/seaofnodes/simple/node/DivNode.java9
-rw-r--r--chapter20/src/main/java/com/seaofnodes/simple/node/FRefNode.java8
-rw-r--r--chapter20/src/main/java/com/seaofnodes/simple/node/IfNode.java8
-rw-r--r--chapter20/src/main/java/com/seaofnodes/simple/node/LoadNode.java5
-rw-r--r--chapter20/src/main/java/com/seaofnodes/simple/node/LogicalNode.java10
-rw-r--r--chapter20/src/main/java/com/seaofnodes/simple/node/MachConcreteNode.java12
-rw-r--r--chapter20/src/main/java/com/seaofnodes/simple/node/MemMergeNode.java12
-rw-r--r--chapter20/src/main/java/com/seaofnodes/simple/node/MemOpNode.java6
-rw-r--r--chapter20/src/main/java/com/seaofnodes/simple/node/MinusFNode.java8
-rw-r--r--chapter20/src/main/java/com/seaofnodes/simple/node/MinusNode.java8
-rw-r--r--chapter20/src/main/java/com/seaofnodes/simple/node/MulFNode.java9
-rw-r--r--chapter20/src/main/java/com/seaofnodes/simple/node/MulNode.java9
-rw-r--r--chapter20/src/main/java/com/seaofnodes/simple/node/NeverNode.java5
-rw-r--r--chapter20/src/main/java/com/seaofnodes/simple/node/NewNode.java9
-rw-r--r--chapter20/src/main/java/com/seaofnodes/simple/node/Node.java70
-rw-r--r--chapter20/src/main/java/com/seaofnodes/simple/node/NotNode.java8
-rw-r--r--chapter20/src/main/java/com/seaofnodes/simple/node/ParmNode.java19
-rw-r--r--chapter20/src/main/java/com/seaofnodes/simple/node/PhiNode.java19
-rw-r--r--chapter20/src/main/java/com/seaofnodes/simple/node/ProjNode.java11
-rw-r--r--chapter20/src/main/java/com/seaofnodes/simple/node/ReadOnlyNode.java7
-rw-r--r--chapter20/src/main/java/com/seaofnodes/simple/node/RegionNode.java7
-rw-r--r--chapter20/src/main/java/com/seaofnodes/simple/node/ReturnNode.java13
-rw-r--r--chapter20/src/main/java/com/seaofnodes/simple/node/RoundF32Node.java7
-rw-r--r--chapter20/src/main/java/com/seaofnodes/simple/node/ScopeNode.java28
-rw-r--r--chapter20/src/main/java/com/seaofnodes/simple/node/SplitNode.java13
-rw-r--r--chapter20/src/main/java/com/seaofnodes/simple/node/StartNode.java8
-rw-r--r--chapter20/src/main/java/com/seaofnodes/simple/node/StopNode.java13
-rw-r--r--chapter20/src/main/java/com/seaofnodes/simple/node/StoreNode.java7
-rw-r--r--chapter20/src/main/java/com/seaofnodes/simple/node/StructNode.java18
-rw-r--r--chapter20/src/main/java/com/seaofnodes/simple/node/SubFNode.java9
-rw-r--r--chapter20/src/main/java/com/seaofnodes/simple/node/SubNode.java9
-rw-r--r--chapter20/src/main/java/com/seaofnodes/simple/node/ToFloatNode.java7
-rw-r--r--chapter20/src/main/java/com/seaofnodes/simple/node/XCtrlNode.java5
-rw-r--r--chapter20/src/main/java/com/seaofnodes/simple/node/cpus/arm/CallARM.java2
-rw-r--r--chapter20/src/main/java/com/seaofnodes/simple/node/cpus/arm/MemOpARM.java5
-rw-r--r--chapter20/src/main/java/com/seaofnodes/simple/node/cpus/riscv/BranchRISC.java13
-rw-r--r--chapter20/src/main/java/com/seaofnodes/simple/node/cpus/riscv/ImmRISC.java8
-rw-r--r--chapter20/src/main/java/com/seaofnodes/simple/node/cpus/riscv/MemOpRISC.java5
-rw-r--r--chapter20/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/MemOpX86.java7
-rw-r--r--chapter20/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/StoreX86.java13
-rw-r--r--chapter20/src/main/java/com/seaofnodes/simple/print/ASMPrinter.java192
-rw-r--r--chapter20/src/main/java/com/seaofnodes/simple/print/IRPrinter.java396
-rw-r--r--chapter20/src/main/java/com/seaofnodes/simple/print/SimpleGraphAdapter.java38
-rw-r--r--chapter21/Makefile3
-rw-r--r--chapter21/pom.xml1
-rw-r--r--chapter21/src/main/java/com/seaofnodes/simple/node/AddFNode.java9
-rw-r--r--chapter21/src/main/java/com/seaofnodes/simple/node/AddNode.java9
-rw-r--r--chapter21/src/main/java/com/seaofnodes/simple/node/BoolNode.java10
-rw-r--r--chapter21/src/main/java/com/seaofnodes/simple/node/CProjNode.java5
-rw-r--r--chapter21/src/main/java/com/seaofnodes/simple/node/CallEndNode.java14
-rw-r--r--chapter21/src/main/java/com/seaofnodes/simple/node/CallNode.java16
-rw-r--r--chapter21/src/main/java/com/seaofnodes/simple/node/CastNode.java10
-rw-r--r--chapter21/src/main/java/com/seaofnodes/simple/node/ConstantNode.java17
-rw-r--r--chapter21/src/main/java/com/seaofnodes/simple/node/CtrlNode.java5
-rw-r--r--chapter21/src/main/java/com/seaofnodes/simple/node/DivFNode.java9
-rw-r--r--chapter21/src/main/java/com/seaofnodes/simple/node/DivNode.java9
-rw-r--r--chapter21/src/main/java/com/seaofnodes/simple/node/FRefNode.java8
-rw-r--r--chapter21/src/main/java/com/seaofnodes/simple/node/IfNode.java13
-rw-r--r--chapter21/src/main/java/com/seaofnodes/simple/node/LoadNode.java4
-rw-r--r--chapter21/src/main/java/com/seaofnodes/simple/node/LogicalNode.java10
-rw-r--r--chapter21/src/main/java/com/seaofnodes/simple/node/MachConcreteNode.java12
-rw-r--r--chapter21/src/main/java/com/seaofnodes/simple/node/MemMergeNode.java12
-rw-r--r--chapter21/src/main/java/com/seaofnodes/simple/node/MemOpNode.java6
-rw-r--r--chapter21/src/main/java/com/seaofnodes/simple/node/MinusFNode.java8
-rw-r--r--chapter21/src/main/java/com/seaofnodes/simple/node/MinusNode.java8
-rw-r--r--chapter21/src/main/java/com/seaofnodes/simple/node/MulFNode.java9
-rw-r--r--chapter21/src/main/java/com/seaofnodes/simple/node/MulNode.java9
-rw-r--r--chapter21/src/main/java/com/seaofnodes/simple/node/NeverNode.java5
-rw-r--r--chapter21/src/main/java/com/seaofnodes/simple/node/NewNode.java9
-rw-r--r--chapter21/src/main/java/com/seaofnodes/simple/node/Node.java71
-rw-r--r--chapter21/src/main/java/com/seaofnodes/simple/node/NotNode.java8
-rw-r--r--chapter21/src/main/java/com/seaofnodes/simple/node/ParmNode.java19
-rw-r--r--chapter21/src/main/java/com/seaofnodes/simple/node/PhiNode.java19
-rw-r--r--chapter21/src/main/java/com/seaofnodes/simple/node/ProjNode.java11
-rw-r--r--chapter21/src/main/java/com/seaofnodes/simple/node/ReadOnlyNode.java7
-rw-r--r--chapter21/src/main/java/com/seaofnodes/simple/node/RegionNode.java7
-rw-r--r--chapter21/src/main/java/com/seaofnodes/simple/node/ReturnNode.java13
-rw-r--r--chapter21/src/main/java/com/seaofnodes/simple/node/RoundF32Node.java7
-rw-r--r--chapter21/src/main/java/com/seaofnodes/simple/node/ScopeNode.java28
-rw-r--r--chapter21/src/main/java/com/seaofnodes/simple/node/SplitNode.java13
-rw-r--r--chapter21/src/main/java/com/seaofnodes/simple/node/StartNode.java8
-rw-r--r--chapter21/src/main/java/com/seaofnodes/simple/node/StopNode.java13
-rw-r--r--chapter21/src/main/java/com/seaofnodes/simple/node/StoreNode.java7
-rw-r--r--chapter21/src/main/java/com/seaofnodes/simple/node/StructNode.java18
-rw-r--r--chapter21/src/main/java/com/seaofnodes/simple/node/SubFNode.java9
-rw-r--r--chapter21/src/main/java/com/seaofnodes/simple/node/SubNode.java9
-rw-r--r--chapter21/src/main/java/com/seaofnodes/simple/node/ToFloatNode.java7
-rw-r--r--chapter21/src/main/java/com/seaofnodes/simple/node/XCtrlNode.java5
-rw-r--r--chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/CallARM.java2
-rw-r--r--chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/MemOpARM.java5
-rw-r--r--chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/UJmpARM.java6
-rw-r--r--chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/BranchRISC.java19
-rw-r--r--chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/ImmRISC.java9
-rw-r--r--chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/MemOpRISC.java5
-rw-r--r--chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/UJmpRISC.java5
-rw-r--r--chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/MemOpX86.java7
-rw-r--r--chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/StoreX86.java13
-rw-r--r--chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/UJmpX86.java6
-rw-r--r--chapter21/src/main/java/com/seaofnodes/simple/print/ASMPrinter.java342
-rw-r--r--chapter21/src/main/java/com/seaofnodes/simple/print/IRPrinter.java554
-rw-r--r--chapter21/src/main/java/com/seaofnodes/simple/print/SimpleGraphAdapter.java38
-rw-r--r--chapter22/Makefile1
-rw-r--r--chapter22/pom.xml1
-rw-r--r--chapter22/src/main/java/com/seaofnodes/simple/codegen/CodeGen.java2
-rw-r--r--chapter22/src/main/java/com/seaofnodes/simple/node/AddFNode.java9
-rw-r--r--chapter22/src/main/java/com/seaofnodes/simple/node/ArithNode.java10
-rw-r--r--chapter22/src/main/java/com/seaofnodes/simple/node/BoolNode.java10
-rw-r--r--chapter22/src/main/java/com/seaofnodes/simple/node/CProjNode.java5
-rw-r--r--chapter22/src/main/java/com/seaofnodes/simple/node/CallEndNode.java14
-rw-r--r--chapter22/src/main/java/com/seaofnodes/simple/node/CallNode.java16
-rw-r--r--chapter22/src/main/java/com/seaofnodes/simple/node/CastNode.java10
-rw-r--r--chapter22/src/main/java/com/seaofnodes/simple/node/ConstantNode.java17
-rw-r--r--chapter22/src/main/java/com/seaofnodes/simple/node/CtrlNode.java5
-rw-r--r--chapter22/src/main/java/com/seaofnodes/simple/node/DivFNode.java9
-rw-r--r--chapter22/src/main/java/com/seaofnodes/simple/node/ExternNode.java1
-rw-r--r--chapter22/src/main/java/com/seaofnodes/simple/node/FRefNode.java8
-rw-r--r--chapter22/src/main/java/com/seaofnodes/simple/node/FunPtrNode.java1
-rw-r--r--chapter22/src/main/java/com/seaofnodes/simple/node/IfNode.java13
-rw-r--r--chapter22/src/main/java/com/seaofnodes/simple/node/LoadNode.java4
-rw-r--r--chapter22/src/main/java/com/seaofnodes/simple/node/MachConcreteNode.java12
-rw-r--r--chapter22/src/main/java/com/seaofnodes/simple/node/MemMergeNode.java12
-rw-r--r--chapter22/src/main/java/com/seaofnodes/simple/node/MemOpNode.java6
-rw-r--r--chapter22/src/main/java/com/seaofnodes/simple/node/MinusFNode.java8
-rw-r--r--chapter22/src/main/java/com/seaofnodes/simple/node/MinusNode.java8
-rw-r--r--chapter22/src/main/java/com/seaofnodes/simple/node/MulFNode.java9
-rw-r--r--chapter22/src/main/java/com/seaofnodes/simple/node/NeverNode.java5
-rw-r--r--chapter22/src/main/java/com/seaofnodes/simple/node/NewNode.java9
-rw-r--r--chapter22/src/main/java/com/seaofnodes/simple/node/Node.java71
-rw-r--r--chapter22/src/main/java/com/seaofnodes/simple/node/NotNode.java8
-rw-r--r--chapter22/src/main/java/com/seaofnodes/simple/node/ParmNode.java19
-rw-r--r--chapter22/src/main/java/com/seaofnodes/simple/node/PhiNode.java19
-rw-r--r--chapter22/src/main/java/com/seaofnodes/simple/node/ProjNode.java11
-rw-r--r--chapter22/src/main/java/com/seaofnodes/simple/node/ReadOnlyNode.java7
-rw-r--r--chapter22/src/main/java/com/seaofnodes/simple/node/RegionNode.java7
-rw-r--r--chapter22/src/main/java/com/seaofnodes/simple/node/ReturnNode.java13
-rw-r--r--chapter22/src/main/java/com/seaofnodes/simple/node/RoundF32Node.java7
-rw-r--r--chapter22/src/main/java/com/seaofnodes/simple/node/ScopeNode.java28
-rw-r--r--chapter22/src/main/java/com/seaofnodes/simple/node/SplitNode.java13
-rw-r--r--chapter22/src/main/java/com/seaofnodes/simple/node/StartNode.java8
-rw-r--r--chapter22/src/main/java/com/seaofnodes/simple/node/StopNode.java13
-rw-r--r--chapter22/src/main/java/com/seaofnodes/simple/node/StoreNode.java7
-rw-r--r--chapter22/src/main/java/com/seaofnodes/simple/node/StructNode.java18
-rw-r--r--chapter22/src/main/java/com/seaofnodes/simple/node/SubFNode.java9
-rw-r--r--chapter22/src/main/java/com/seaofnodes/simple/node/ToFloatNode.java7
-rw-r--r--chapter22/src/main/java/com/seaofnodes/simple/node/XCtrlNode.java5
-rw-r--r--chapter22/src/main/java/com/seaofnodes/simple/node/cpus/arm/MemOpARM.java5
-rw-r--r--chapter22/src/main/java/com/seaofnodes/simple/node/cpus/arm/UJmpARM.java6
-rw-r--r--chapter22/src/main/java/com/seaofnodes/simple/node/cpus/riscv/BranchRISC.java19
-rw-r--r--chapter22/src/main/java/com/seaofnodes/simple/node/cpus/riscv/ImmRISC.java9
-rw-r--r--chapter22/src/main/java/com/seaofnodes/simple/node/cpus/riscv/MemOpRISC.java5
-rw-r--r--chapter22/src/main/java/com/seaofnodes/simple/node/cpus/riscv/UJmpRISC.java5
-rw-r--r--chapter22/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/MemOpX86.java7
-rw-r--r--chapter22/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/StoreX86.java13
-rw-r--r--chapter22/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/UJmpX86.java6
-rw-r--r--chapter22/src/main/java/com/seaofnodes/simple/print/ASMPrinter.java359
-rw-r--r--chapter22/src/main/java/com/seaofnodes/simple/print/IRPrinter.java399
-rw-r--r--chapter22/src/main/java/com/seaofnodes/simple/print/SimpleGraphAdapter.java38
-rw-r--r--chapter23/Makefile1
-rw-r--r--chapter23/pom.xml1
-rw-r--r--chapter23/src/main/java/com/seaofnodes/simple/codegen/CodeGen.java2
-rw-r--r--chapter23/src/main/java/com/seaofnodes/simple/node/AddFNode.java9
-rw-r--r--chapter23/src/main/java/com/seaofnodes/simple/node/ArithNode.java10
-rw-r--r--chapter23/src/main/java/com/seaofnodes/simple/node/BoolNode.java10
-rw-r--r--chapter23/src/main/java/com/seaofnodes/simple/node/CProjNode.java5
-rw-r--r--chapter23/src/main/java/com/seaofnodes/simple/node/CallEndNode.java14
-rw-r--r--chapter23/src/main/java/com/seaofnodes/simple/node/CallNode.java16
-rw-r--r--chapter23/src/main/java/com/seaofnodes/simple/node/CastNode.java10
-rw-r--r--chapter23/src/main/java/com/seaofnodes/simple/node/ConFldOffNode.java9
-rw-r--r--chapter23/src/main/java/com/seaofnodes/simple/node/ConstantNode.java16
-rw-r--r--chapter23/src/main/java/com/seaofnodes/simple/node/CtrlNode.java5
-rw-r--r--chapter23/src/main/java/com/seaofnodes/simple/node/DivFNode.java9
-rw-r--r--chapter23/src/main/java/com/seaofnodes/simple/node/ExternNode.java1
-rw-r--r--chapter23/src/main/java/com/seaofnodes/simple/node/FRefNode.java8
-rw-r--r--chapter23/src/main/java/com/seaofnodes/simple/node/FunPtrNode.java1
-rw-r--r--chapter23/src/main/java/com/seaofnodes/simple/node/IfNode.java13
-rw-r--r--chapter23/src/main/java/com/seaofnodes/simple/node/LoadNode.java4
-rw-r--r--chapter23/src/main/java/com/seaofnodes/simple/node/MachConcreteNode.java12
-rw-r--r--chapter23/src/main/java/com/seaofnodes/simple/node/MemMergeNode.java12
-rw-r--r--chapter23/src/main/java/com/seaofnodes/simple/node/MemOpNode.java6
-rw-r--r--chapter23/src/main/java/com/seaofnodes/simple/node/MinusFNode.java8
-rw-r--r--chapter23/src/main/java/com/seaofnodes/simple/node/MinusNode.java8
-rw-r--r--chapter23/src/main/java/com/seaofnodes/simple/node/MulFNode.java9
-rw-r--r--chapter23/src/main/java/com/seaofnodes/simple/node/NeverNode.java5
-rw-r--r--chapter23/src/main/java/com/seaofnodes/simple/node/NewNode.java9
-rw-r--r--chapter23/src/main/java/com/seaofnodes/simple/node/Node.java71
-rw-r--r--chapter23/src/main/java/com/seaofnodes/simple/node/NotNode.java8
-rw-r--r--chapter23/src/main/java/com/seaofnodes/simple/node/ParmNode.java19
-rw-r--r--chapter23/src/main/java/com/seaofnodes/simple/node/PhiNode.java19
-rw-r--r--chapter23/src/main/java/com/seaofnodes/simple/node/ProjNode.java11
-rw-r--r--chapter23/src/main/java/com/seaofnodes/simple/node/ReadOnlyNode.java7
-rw-r--r--chapter23/src/main/java/com/seaofnodes/simple/node/RegionNode.java7
-rw-r--r--chapter23/src/main/java/com/seaofnodes/simple/node/ReturnNode.java13
-rw-r--r--chapter23/src/main/java/com/seaofnodes/simple/node/RoundF32Node.java7
-rw-r--r--chapter23/src/main/java/com/seaofnodes/simple/node/ScopeNode.java28
-rw-r--r--chapter23/src/main/java/com/seaofnodes/simple/node/SplitNode.java13
-rw-r--r--chapter23/src/main/java/com/seaofnodes/simple/node/StartNode.java8
-rw-r--r--chapter23/src/main/java/com/seaofnodes/simple/node/StopNode.java13
-rw-r--r--chapter23/src/main/java/com/seaofnodes/simple/node/StoreNode.java7
-rw-r--r--chapter23/src/main/java/com/seaofnodes/simple/node/StructNode.java18
-rw-r--r--chapter23/src/main/java/com/seaofnodes/simple/node/SubFNode.java9
-rw-r--r--chapter23/src/main/java/com/seaofnodes/simple/node/ToFloatNode.java7
-rw-r--r--chapter23/src/main/java/com/seaofnodes/simple/node/XCtrlNode.java5
-rw-r--r--chapter23/src/main/java/com/seaofnodes/simple/node/cpus/arm/MemOpARM.java5
-rw-r--r--chapter23/src/main/java/com/seaofnodes/simple/node/cpus/arm/UJmpARM.java6
-rw-r--r--chapter23/src/main/java/com/seaofnodes/simple/node/cpus/riscv/BranchRISC.java19
-rw-r--r--chapter23/src/main/java/com/seaofnodes/simple/node/cpus/riscv/ImmRISC.java9
-rw-r--r--chapter23/src/main/java/com/seaofnodes/simple/node/cpus/riscv/MemOpRISC.java5
-rw-r--r--chapter23/src/main/java/com/seaofnodes/simple/node/cpus/riscv/UJmpRISC.java5
-rw-r--r--chapter23/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/MemOpX86.java7
-rw-r--r--chapter23/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/StoreX86.java13
-rw-r--r--chapter23/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/UJmpX86.java6
-rw-r--r--chapter23/src/main/java/com/seaofnodes/simple/print/ASMPrinter.java360
-rw-r--r--chapter23/src/main/java/com/seaofnodes/simple/print/IRPrinter.java399
-rw-r--r--chapter23/src/main/java/com/seaofnodes/simple/print/SimpleGraphAdapter.java38
-rw-r--r--chapter24/Makefile1
-rw-r--r--chapter24/pom.xml1
-rw-r--r--chapter24/src/main/java/com/seaofnodes/simple/codegen/CodeGen.java2
-rw-r--r--chapter24/src/main/java/com/seaofnodes/simple/node/ArithFNode.java10
-rw-r--r--chapter24/src/main/java/com/seaofnodes/simple/node/ArithNode.java10
-rw-r--r--chapter24/src/main/java/com/seaofnodes/simple/node/BoolNode.java10
-rw-r--r--chapter24/src/main/java/com/seaofnodes/simple/node/CProjNode.java5
-rw-r--r--chapter24/src/main/java/com/seaofnodes/simple/node/CallEndNode.java14
-rw-r--r--chapter24/src/main/java/com/seaofnodes/simple/node/CallNode.java16
-rw-r--r--chapter24/src/main/java/com/seaofnodes/simple/node/CastNode.java10
-rw-r--r--chapter24/src/main/java/com/seaofnodes/simple/node/ConFldOffNode.java9
-rw-r--r--chapter24/src/main/java/com/seaofnodes/simple/node/ConstantNode.java16
-rw-r--r--chapter24/src/main/java/com/seaofnodes/simple/node/CtrlNode.java5
-rw-r--r--chapter24/src/main/java/com/seaofnodes/simple/node/ExternNode.java1
-rw-r--r--chapter24/src/main/java/com/seaofnodes/simple/node/FRefNode.java8
-rw-r--r--chapter24/src/main/java/com/seaofnodes/simple/node/FunPtrNode.java1
-rw-r--r--chapter24/src/main/java/com/seaofnodes/simple/node/IfNode.java13
-rw-r--r--chapter24/src/main/java/com/seaofnodes/simple/node/LoadNode.java4
-rw-r--r--chapter24/src/main/java/com/seaofnodes/simple/node/MachConcreteNode.java12
-rw-r--r--chapter24/src/main/java/com/seaofnodes/simple/node/MemMergeNode.java12
-rw-r--r--chapter24/src/main/java/com/seaofnodes/simple/node/MemOpNode.java6
-rw-r--r--chapter24/src/main/java/com/seaofnodes/simple/node/MinusFNode.java8
-rw-r--r--chapter24/src/main/java/com/seaofnodes/simple/node/MinusNode.java8
-rw-r--r--chapter24/src/main/java/com/seaofnodes/simple/node/NeverNode.java5
-rw-r--r--chapter24/src/main/java/com/seaofnodes/simple/node/NewNode.java9
-rw-r--r--chapter24/src/main/java/com/seaofnodes/simple/node/Node.java70
-rw-r--r--chapter24/src/main/java/com/seaofnodes/simple/node/NotNode.java8
-rw-r--r--chapter24/src/main/java/com/seaofnodes/simple/node/ParmNode.java19
-rw-r--r--chapter24/src/main/java/com/seaofnodes/simple/node/PhiNode.java19
-rw-r--r--chapter24/src/main/java/com/seaofnodes/simple/node/ProjNode.java11
-rw-r--r--chapter24/src/main/java/com/seaofnodes/simple/node/ReadOnlyNode.java7
-rw-r--r--chapter24/src/main/java/com/seaofnodes/simple/node/RegionNode.java7
-rw-r--r--chapter24/src/main/java/com/seaofnodes/simple/node/ReturnNode.java13
-rw-r--r--chapter24/src/main/java/com/seaofnodes/simple/node/RoundF32Node.java7
-rw-r--r--chapter24/src/main/java/com/seaofnodes/simple/node/ScopeNode.java28
-rw-r--r--chapter24/src/main/java/com/seaofnodes/simple/node/SplitNode.java13
-rw-r--r--chapter24/src/main/java/com/seaofnodes/simple/node/StartNode.java8
-rw-r--r--chapter24/src/main/java/com/seaofnodes/simple/node/StopNode.java13
-rw-r--r--chapter24/src/main/java/com/seaofnodes/simple/node/StoreNode.java7
-rw-r--r--chapter24/src/main/java/com/seaofnodes/simple/node/StructNode.java18
-rw-r--r--chapter24/src/main/java/com/seaofnodes/simple/node/ToFloatNode.java7
-rw-r--r--chapter24/src/main/java/com/seaofnodes/simple/node/XCtrlNode.java5
-rw-r--r--chapter24/src/main/java/com/seaofnodes/simple/node/cpus/arm/MemOpARM.java5
-rw-r--r--chapter24/src/main/java/com/seaofnodes/simple/node/cpus/arm/UJmpARM.java6
-rw-r--r--chapter24/src/main/java/com/seaofnodes/simple/node/cpus/riscv/BranchRISC.java19
-rw-r--r--chapter24/src/main/java/com/seaofnodes/simple/node/cpus/riscv/ImmRISC.java9
-rw-r--r--chapter24/src/main/java/com/seaofnodes/simple/node/cpus/riscv/MemOpRISC.java5
-rw-r--r--chapter24/src/main/java/com/seaofnodes/simple/node/cpus/riscv/UJmpRISC.java5
-rw-r--r--chapter24/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/MemOpX86.java7
-rw-r--r--chapter24/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/StoreX86.java13
-rw-r--r--chapter24/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/UJmpX86.java6
-rw-r--r--chapter24/src/main/java/com/seaofnodes/simple/print/ASMPrinter.java360
-rw-r--r--chapter24/src/main/java/com/seaofnodes/simple/print/IRPrinter.java399
-rw-r--r--chapter24/src/main/java/com/seaofnodes/simple/print/SimpleGraphAdapter.java38
-rw-r--r--chapter25/Makefile1
-rw-r--r--chapter25/pom.xml1
-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
-rw-r--r--docs/chapter-backports.md75
-rw-r--r--graph/README.md23
-rw-r--r--graph/graph.iml1
-rw-r--r--graph/src/main/java/com/seaofnodes/graph/GraphAdapter.java46
-rw-r--r--graph/src/main/java/com/seaofnodes/graph/GraphCapture.java3
-rw-r--r--pom.xml6
-rw-r--r--print/Makefile14
-rw-r--r--print/README.md112
-rw-r--r--print/print.iml16
-rw-r--r--print/print.mk4
-rw-r--r--print/src/main/java/com/seaofnodes/print/ASMPrinter.java157
-rw-r--r--print/src/main/java/com/seaofnodes/print/AssemblyAdapter.java26
-rw-r--r--print/src/main/java/com/seaofnodes/print/BaseNode.java37
-rw-r--r--print/src/main/java/com/seaofnodes/print/ExprPrinter.java56
-rw-r--r--print/src/main/java/com/seaofnodes/print/IRAdapter.java34
-rw-r--r--print/src/main/java/com/seaofnodes/print/IRPrinter.java293
-rw-r--r--print/src/test/java/com/seaofnodes/print/PrinterTest.java153
-rw-r--r--skills/chapter25-codex-notes.md29
-rw-r--r--skills/graph-viewer-codex-notes.md8
923 files changed, 5724 insertions, 13691 deletions
diff --git a/.github/workflows/linearize.sh b/.github/workflows/linearize.sh
index e8785367..fb39b380 100755
--- a/.github/workflows/linearize.sh
+++ b/.github/workflows/linearize.sh
@@ -47,7 +47,7 @@ while read -r chapter; do
done <<< "$all_authors"
# Get the first and last dates this chapter was modified.
- root_files=(README.md LICENSE pom.xml .gitignore .dir-locals.el transpile-tests graph build-support)
+ root_files=(README.md LICENSE pom.xml .gitignore .dir-locals.el transpile-tests graph print build-support)
author_root_files=()
if [[ $chapter = chapter01 ]]; then
# Only include the commit date of the root files for chapter01.
@@ -71,7 +71,7 @@ while read -r chapter; do
git add .
# Add the shared files in the root, except for README.md and pom.xml.
- root_files=(LICENSE .gitignore .dir-locals.el transpile-tests graph build-support)
+ root_files=(LICENSE .gitignore .dir-locals.el transpile-tests graph print build-support)
cp -R "${root_files[@]/#/"$repo/"}" .
git add "${root_files[@]}"
diff --git a/.gitignore b/.gitignore
index e776c5be..ce26378a 100644
--- a/.gitignore
+++ b/.gitignore
@@ -28,3 +28,4 @@ TAGS
!chapter10a/chapter10a.iml
!chapter10b/chapter10b.iml
!graph/graph.iml
+!print/print.iml
diff --git a/Makefile b/Makefile
index 1e097bcf..32ab9973 100644
--- a/Makefile
+++ b/Makefile
@@ -14,3 +14,8 @@ $(foreach action,$(ACTIONS),$(eval $(action): $(addsuffix /$(action),$(CHAPTERS)
$(CHAPTER_TARGETS):
+$(MAKE) --no-print-directory -C $(dir $@) $(notdir $@)
+
+.PHONY: print/tests
+tests: print/tests
+print/tests:
+ +$(MAKE) --no-print-directory -C print tests
diff --git a/README.md b/README.md
index ef31f64e..09588e96 100644
--- a/README.md
+++ b/README.md
@@ -76,6 +76,11 @@ The Simple language is styled after a subset of C or Java.
The optional [interactive graph viewer](graph/README.md) is shared in `graph/`.
Chapters 10a, 10b, and 18–25 launch it with `make view` from the chapter directory.
+The [debug printers](print/README.md) are shared in `print/`; Chapter 2 needs only
+a one-line expression format. A shared `BaseNode` supplies identity and edge
+access to both printers and the viewer; chapter adapters add semantic details
+as the IR grows.
+
The top-level Makefile runs each chapter's `tests`, `tags` (also `tag`),
`release`, or `lib` target. Start with `make lib` on a fresh checkout, then
`make tests`.
diff --git a/build-support/early-chapter.mk b/build-support/early-chapter.mk
index 5f82b5b0..d0135b74 100644
--- a/build-support/early-chapter.mk
+++ b/build-support/early-chapter.mk
@@ -18,6 +18,7 @@ main_classes := $(CLZDIR)/main/.mtag
test_classes := $(CLZDIR)/test/.ttag
include $(firstword $(wildcard ../graph/graph.mk graph/graph.mk))
+include $(firstword $(wildcard ../print/print.mk print/print.mk))
.PHONY: build
build: $(main_classes)
diff --git a/chapter01/pom.xml b/chapter01/pom.xml
index 5151e8c4..567f221f 100644
--- a/chapter01/pom.xml
+++ b/chapter01/pom.xml
@@ -13,5 +13,6 @@
<name>Chapter 1</name>
<properties>
<simple.graph.directory>${project.basedir}/../graph</simple.graph.directory>
+ <simple.print.directory>${project.basedir}/../print</simple.print.directory>
</properties>
</project>
diff --git a/chapter01/src/main/java/com/seaofnodes/simple/node/ConstantNode.java b/chapter01/src/main/java/com/seaofnodes/simple/node/ConstantNode.java
index 21f65084..01d9cbe1 100644
--- a/chapter01/src/main/java/com/seaofnodes/simple/node/ConstantNode.java
+++ b/chapter01/src/main/java/com/seaofnodes/simple/node/ConstantNode.java
@@ -16,6 +16,10 @@ import com.seaofnodes.simple.Parser;
*/
public class ConstantNode extends Node {
+ @Override public String label() { return "Con"; }
+ @Override protected String format() { return Long.toString(_value); }
+ @Override protected String repeatName() { return null; }
+
public final long _value;
public ConstantNode(long value) {
diff --git a/chapter01/src/main/java/com/seaofnodes/simple/node/Node.java b/chapter01/src/main/java/com/seaofnodes/simple/node/Node.java
index 5d74e206..ed88e86e 100644
--- a/chapter01/src/main/java/com/seaofnodes/simple/node/Node.java
+++ b/chapter01/src/main/java/com/seaofnodes/simple/node/Node.java
@@ -1,5 +1,7 @@
package com.seaofnodes.simple.node;
+import com.seaofnodes.print.BaseNode;
+
import java.util.*;
/**
@@ -7,14 +9,7 @@ import java.util.*;
* The Node class provides common functionality used by all subtypes.
* Subtypes of Node specialize by overriding methods.
*/
-public abstract class Node {
-
- /**
- * 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 final int _nid;
+public abstract class Node extends BaseNode<Node> {
/**
* Inputs to the node. These are use-def references to Nodes.
@@ -44,7 +39,7 @@ public abstract class Node {
private static int UNIQUE_ID = 1;
protected Node(Node... inputs) {
- _nid = UNIQUE_ID++; // allocate unique dense ID
+ super(UNIQUE_ID++); // allocate unique dense ID
_inputs = new ArrayList<>();
Collections.addAll(_inputs,inputs);
_outputs = new ArrayList<>();
@@ -62,13 +57,12 @@ public abstract class Node {
public int nIns() { return _inputs.size(); }
+ public Node out(int i) { return _outputs.get(i); }
+
public int nOuts() { return _outputs.size(); }
public boolean isUnused() { return nOuts() == 0; }
- public boolean isCFG() { return false; }
-
-
/**
* Used to allow repeating tests in the same JVM. This just resets the
* Node unique id generator, and is done as part of making a new Parser.
diff --git a/chapter01/src/main/java/com/seaofnodes/simple/print/SimpleGraphAdapter.java b/chapter01/src/main/java/com/seaofnodes/simple/print/SimpleGraphAdapter.java
index 59275832..20ee6aed 100644
--- a/chapter01/src/main/java/com/seaofnodes/simple/print/SimpleGraphAdapter.java
+++ b/chapter01/src/main/java/com/seaofnodes/simple/print/SimpleGraphAdapter.java
@@ -1,43 +1,19 @@
package com.seaofnodes.simple.print;
import com.seaofnodes.graph.GraphAdapter;
-import com.seaofnodes.graph.GraphSnapshot;
import com.seaofnodes.graph.GraphSnapshot.*;
import com.seaofnodes.simple.node.*;
import com.seaofnodes.simple.node.Node;
-import java.util.ArrayList;
/** Chapter 1's view of the IR; browser, transport and layout are shared. */
public class SimpleGraphAdapter extends GraphAdapter<Node> {
- @Override protected boolean dead(Node n) { return false; }
- @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._outputs.get(idx); }
- private ArrayList<Edge> edges(Node n) {
- var edges = new ArrayList<Edge>();
- for( int i = 0; i < n.nIns(); i++ ) {
- String name = null;
- edges.add(new Edge(i, ref(n.in(i)), role(n, i), name));
- }
- return edges;
- }
-
- @Override protected GraphSnapshot.Node desc(Node n) {
- Projection proj = null;
- String label = n instanceof ConstantNode c ? Long.toString(c._value) : n.getClass().getSimpleName();
- return new GraphSnapshot.Node(n._nid, label == null ? n.getClass().getSimpleName() : label,
- null, kind(n), edges(n), proj);
- }
-
- private Kind kind(Node n) {
+ @Override protected Kind kind(Node n) {
if( n instanceof StartNode ) return Kind.CTRL;
return n.isCFG() ? Kind.CTRL : Kind.DATA;
}
- private Role role(Node n, int i) {
+ @Override protected Role role(Node n, int i) {
if( n instanceof ConstantNode ) return Role.ASSOC;
if( i == 0 ) return Role.CTRL;
return Role.DATA;
diff --git a/chapter02/pom.xml b/chapter02/pom.xml
index 6fc4f177..6200fe8d 100644
--- a/chapter02/pom.xml
+++ b/chapter02/pom.xml
@@ -13,5 +13,6 @@
<name>Chapter 2</name>
<properties>
<simple.graph.directory>${project.basedir}/../graph</simple.graph.directory>
+ <simple.print.directory>${project.basedir}/../print</simple.print.directory>
</properties>
</project>
diff --git a/chapter02/src/main/java/com/seaofnodes/simple/node/AddNode.java b/chapter02/src/main/java/com/seaofnodes/simple/node/AddNode.java
index 814b99b8..94aa4fbb 100644
--- a/chapter02/src/main/java/com/seaofnodes/simple/node/AddNode.java
+++ b/chapter02/src/main/java/com/seaofnodes/simple/node/AddNode.java
@@ -1,5 +1,6 @@
package com.seaofnodes.simple.node;
+
import com.seaofnodes.simple.type.*;
public class AddNode extends Node {
@@ -7,12 +8,7 @@ public class AddNode extends Node {
@Override public String label() { return "Add"; }
- @Override
- StringBuilder _print1(StringBuilder sb) {
- in(1)._print0(sb.append("("));
- in(2)._print0(sb.append("+"));
- return sb.append(")");
- }
+ @Override protected String format() { return "(%1+%2)"; }
@Override
diff --git a/chapter02/src/main/java/com/seaofnodes/simple/node/ConstantNode.java b/chapter02/src/main/java/com/seaofnodes/simple/node/ConstantNode.java
index 43a22426..cc1db452 100644
--- a/chapter02/src/main/java/com/seaofnodes/simple/node/ConstantNode.java
+++ b/chapter02/src/main/java/com/seaofnodes/simple/node/ConstantNode.java
@@ -1,5 +1,7 @@
package com.seaofnodes.simple.node;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.Parser;
import com.seaofnodes.simple.type.Type;
@@ -22,15 +24,16 @@ public class ConstantNode extends Node {
_con = type;
}
- @Override
- public String label() { return "#"+_con; }
+ @Override protected String repeatName() {
+ return _con==null || _con.toString().length()<=32 ? null : uniqueName();
+ }
@Override
- public String uniqueName() { return "Con_" + _nid; }
+ public String label() { return "Con"; }
- @Override
- StringBuilder _print1(StringBuilder sb) {
- return _con.print(sb);
+
+ @Override protected ExprPrinter<Node> _print1(ExprPrinter<Node> p) {
+ return p.p(_con);
}
@Override
diff --git a/chapter02/src/main/java/com/seaofnodes/simple/node/DivNode.java b/chapter02/src/main/java/com/seaofnodes/simple/node/DivNode.java
index fc893e27..d1a554bc 100644
--- a/chapter02/src/main/java/com/seaofnodes/simple/node/DivNode.java
+++ b/chapter02/src/main/java/com/seaofnodes/simple/node/DivNode.java
@@ -1,5 +1,6 @@
package com.seaofnodes.simple.node;
+
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeInteger;
@@ -8,12 +9,7 @@ public class DivNode extends Node {
@Override public String label() { return "Div"; }
- @Override
- StringBuilder _print1(StringBuilder sb) {
- in(1)._print0(sb.append("("));
- in(2)._print0(sb.append("/"));
- return sb.append(")");
- }
+ @Override protected String format() { return "(%1/%2)"; }
@Override
public Type compute() {
diff --git a/chapter02/src/main/java/com/seaofnodes/simple/node/MinusNode.java b/chapter02/src/main/java/com/seaofnodes/simple/node/MinusNode.java
index b83c41a5..11769935 100644
--- a/chapter02/src/main/java/com/seaofnodes/simple/node/MinusNode.java
+++ b/chapter02/src/main/java/com/seaofnodes/simple/node/MinusNode.java
@@ -1,5 +1,6 @@
package com.seaofnodes.simple.node;
+
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeInteger;
@@ -8,11 +9,7 @@ public class MinusNode extends Node {
@Override public String label() { return "Minus"; }
- @Override
- StringBuilder _print1(StringBuilder sb) {
- in(1)._print0(sb.append("(-"));
- return sb.append(")");
- }
+ @Override protected String format() { return "(-%1)"; }
@Override
public Type compute() {
diff --git a/chapter02/src/main/java/com/seaofnodes/simple/node/MulNode.java b/chapter02/src/main/java/com/seaofnodes/simple/node/MulNode.java
index b2b2f9c0..abae6925 100644
--- a/chapter02/src/main/java/com/seaofnodes/simple/node/MulNode.java
+++ b/chapter02/src/main/java/com/seaofnodes/simple/node/MulNode.java
@@ -1,5 +1,6 @@
package com.seaofnodes.simple.node;
+
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeInteger;
@@ -8,12 +9,7 @@ public class MulNode extends Node {
@Override public String label() { return "Mul"; }
- @Override
- StringBuilder _print1(StringBuilder sb) {
- in(1)._print0(sb.append("("));
- in(2)._print0(sb.append("*"));
- return sb.append(")");
- }
+ @Override protected String format() { return "(%1*%2)"; }
@Override
public Type compute() {
diff --git a/chapter02/src/main/java/com/seaofnodes/simple/node/Node.java b/chapter02/src/main/java/com/seaofnodes/simple/node/Node.java
index acf6b236..3c0c3905 100644
--- a/chapter02/src/main/java/com/seaofnodes/simple/node/Node.java
+++ b/chapter02/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.Parser;
import com.seaofnodes.simple.Utils;
@@ -12,14 +14,7 @@ import java.util.*;
* The Node class provides common functionality used by all subtypes.
* Subtypes of Node specialize by overriding methods.
*/
-public abstract class Node {
-
- /**
- * 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 final int _nid;
+public abstract class Node extends BaseNode<Node> {
/**
* Inputs to the node. These are use-def references to Nodes.
@@ -41,7 +36,6 @@ public abstract class Node {
*/
public final ArrayList<Node> _outputs;
-
/**
* Current computed type for this Node. This value changes as the graph
* changes and more knowledge is gained about the program.
@@ -56,7 +50,7 @@ public abstract class Node {
private static int UNIQUE_ID = 1;
protected Node(Node... inputs) {
- _nid = UNIQUE_ID++; // allocate unique dense ID
+ super(UNIQUE_ID++); // allocate unique dense ID
_inputs = new ArrayList<>();
Collections.addAll(_inputs,inputs);
_outputs = new ArrayList<>();
@@ -68,43 +62,7 @@ public abstract class Node {
// Easy reading label for debugger, e.g. "Add" or "Region" or "EQ"
public abstract String label();
- // Unique label for debugging, e.g. "Add12" or "Region30" or "EQ99"
- public String uniqueName() { return label() + _nid; }
-
- // ------------------------------------------------------------------------
-
- // 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() {
- // TODO: The print evolves in later chapters. For now, a simple
- // recursive print does well. Later with control flow and later still
- // with loops, we need some serious algorithm work to get a decent
- // print. So you should consider the "print" to always be a work-in-
- // progress as we march through the chapters.
- return print();
- }
-
- // This is a *deep* print. This version will fail on cycles, which we will
- // correct later when we can parse programs with loops. We print with a
- // tik-tok style; the common _print0 calls the per-Node _print1, which
- // calls back to _print0;
- public final String print() {
- return _print0(new StringBuilder()).toString();
- }
- // This is the common print: check for DEAD and print "DEAD" else call the
- // per-Node print1.
- final StringBuilder _print0(StringBuilder sb) {
- return isDead()
- ? sb.append(uniqueName()).append(":DEAD")
- : _print1(sb);
- }
- // Every Node implements this.
- abstract StringBuilder _print1(StringBuilder sb);
-
+ @Override public String typeName() { return _type==null ? null : _type.toString(); }
/**
* Gets the ith input node
@@ -121,9 +79,6 @@ public abstract class Node {
public boolean isUnused() { return nOuts() == 0; }
- public boolean isCFG() { return false; }
-
-
/**
* Change a <em>def</em> into a Node. Keeps the edges correct, by removing
* the corresponding <em>use->def</em> edge. This may make the original
@@ -217,7 +172,6 @@ public abstract class Node {
return null; // No progress
}
-
/**
* This function needs to be
* <a href="https://en.wikipedia.org/wiki/Monotonic_function">Monotonic</a>
diff --git a/chapter02/src/main/java/com/seaofnodes/simple/node/ReturnNode.java b/chapter02/src/main/java/com/seaofnodes/simple/node/ReturnNode.java
index 7fa470f8..b48682ca 100644
--- a/chapter02/src/main/java/com/seaofnodes/simple/node/ReturnNode.java
+++ b/chapter02/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.type.*;
/**
@@ -24,8 +26,8 @@ public class ReturnNode extends Node {
public String label() { return "Return"; }
@Override
- StringBuilder _print1(StringBuilder sb) {
- return expr()._print0(sb.append("return ")).append(";");
+ protected ExprPrinter<Node> _print1(ExprPrinter<Node> p) {
+ return p.p("return ").n(expr()).p(";");
}
@Override public boolean isCFG() { return true; }
diff --git a/chapter02/src/main/java/com/seaofnodes/simple/node/StartNode.java b/chapter02/src/main/java/com/seaofnodes/simple/node/StartNode.java
index 99e240ad..12f35736 100644
--- a/chapter02/src/main/java/com/seaofnodes/simple/node/StartNode.java
+++ b/chapter02/src/main/java/com/seaofnodes/simple/node/StartNode.java
@@ -1,5 +1,7 @@
package com.seaofnodes.simple.node;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.type.Type;
/**
@@ -18,9 +20,8 @@ public class StartNode extends Node {
@Override
public String label() { return "Start"; }
- @Override
- StringBuilder _print1(StringBuilder sb) {
- return sb.append(label());
+ @Override protected ExprPrinter<Node> _print1(ExprPrinter<Node> p) {
+ return p.p(label());
}
@Override public boolean isCFG() { return true; }
diff --git a/chapter02/src/main/java/com/seaofnodes/simple/print/SimpleGraphAdapter.java b/chapter02/src/main/java/com/seaofnodes/simple/print/SimpleGraphAdapter.java
index 502a2a8e..8f2f31ec 100644
--- a/chapter02/src/main/java/com/seaofnodes/simple/print/SimpleGraphAdapter.java
+++ b/chapter02/src/main/java/com/seaofnodes/simple/print/SimpleGraphAdapter.java
@@ -1,43 +1,19 @@
package com.seaofnodes.simple.print;
import com.seaofnodes.graph.GraphAdapter;
-import com.seaofnodes.graph.GraphSnapshot;
import com.seaofnodes.graph.GraphSnapshot.*;
import com.seaofnodes.simple.node.*;
import com.seaofnodes.simple.node.Node;
-import java.util.ArrayList;
/** Chapter 2's view of the IR; browser, transport and layout are shared. */
public class SimpleGraphAdapter extends GraphAdapter<Node> {
- @Override protected boolean dead(Node n) { return n.isDead(); }
- @Override protected int id(Node n) { return n._nid; }
- @Override protected int nIns(Node n) { return n.nIns(); }
- @Override protected Node in(Node n, int idx) { return n.in(idx); }
- @Override protected int nOuts(Node n) { return n.nOuts(); }
- @Override protected Node out(Node n, int idx) { return n.out(idx); }
- private ArrayList<Edge> edges(Node n) {
- var edges = new ArrayList<Edge>();
- for( int i = 0; i < n.nIns(); i++ ) {
- String name = null;
- edges.add(new Edge(i, ref(n.in(i)), role(n, i), name));
- }
- return edges;
- }
-
- @Override protected GraphSnapshot.Node desc(Node n) {
- Projection proj = null;
- String label = n.label();
- return new GraphSnapshot.Node(n._nid, label == null ? n.getClass().getSimpleName() : label,
- n._type == null ? null : n._type.toString(), kind(n), edges(n), proj);
- }
-
- private Kind kind(Node n) {
+ @Override protected Kind kind(Node n) {
if( n instanceof StartNode ) return Kind.CTRL;
return n.isCFG() ? Kind.CTRL : Kind.DATA;
}
- private Role role(Node n, int i) {
+ @Override protected Role role(Node n, int i) {
if( n instanceof ConstantNode ) return Role.ASSOC;
if( i == 0 ) return Role.CTRL;
return Role.DATA;
diff --git a/chapter03/pom.xml b/chapter03/pom.xml
index db9f8f88..5349e825 100644
--- a/chapter03/pom.xml
+++ b/chapter03/pom.xml
@@ -13,5 +13,6 @@
<name>Chapter 3</name>
<properties>
<simple.graph.directory>${project.basedir}/../graph</simple.graph.directory>
+ <simple.print.directory>${project.basedir}/../print</simple.print.directory>
</properties>
</project>
diff --git a/chapter03/src/main/java/com/seaofnodes/simple/node/AddNode.java b/chapter03/src/main/java/com/seaofnodes/simple/node/AddNode.java
index 814b99b8..94aa4fbb 100644
--- a/chapter03/src/main/java/com/seaofnodes/simple/node/AddNode.java
+++ b/chapter03/src/main/java/com/seaofnodes/simple/node/AddNode.java
@@ -1,5 +1,6 @@
package com.seaofnodes.simple.node;
+
import com.seaofnodes.simple.type.*;
public class AddNode extends Node {
@@ -7,12 +8,7 @@ public class AddNode extends Node {
@Override public String label() { return "Add"; }
- @Override
- StringBuilder _print1(StringBuilder sb) {
- in(1)._print0(sb.append("("));
- in(2)._print0(sb.append("+"));
- return sb.append(")");
- }
+ @Override protected String format() { return "(%1+%2)"; }
@Override
diff --git a/chapter03/src/main/java/com/seaofnodes/simple/node/ConstantNode.java b/chapter03/src/main/java/com/seaofnodes/simple/node/ConstantNode.java
index 43a22426..cc1db452 100644
--- a/chapter03/src/main/java/com/seaofnodes/simple/node/ConstantNode.java
+++ b/chapter03/src/main/java/com/seaofnodes/simple/node/ConstantNode.java
@@ -1,5 +1,7 @@
package com.seaofnodes.simple.node;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.Parser;
import com.seaofnodes.simple.type.Type;
@@ -22,15 +24,16 @@ public class ConstantNode extends Node {
_con = type;
}
- @Override
- public String label() { return "#"+_con; }
+ @Override protected String repeatName() {
+ return _con==null || _con.toString().length()<=32 ? null : uniqueName();
+ }
@Override
- public String uniqueName() { return "Con_" + _nid; }
+ public String label() { return "Con"; }
- @Override
- StringBuilder _print1(StringBuilder sb) {
- return _con.print(sb);
+
+ @Override protected ExprPrinter<Node> _print1(ExprPrinter<Node> p) {
+ return p.p(_con);
}
@Override
diff --git a/chapter03/src/main/java/com/seaofnodes/simple/node/DivNode.java b/chapter03/src/main/java/com/seaofnodes/simple/node/DivNode.java
index fc893e27..d1a554bc 100644
--- a/chapter03/src/main/java/com/seaofnodes/simple/node/DivNode.java
+++ b/chapter03/src/main/java/com/seaofnodes/simple/node/DivNode.java
@@ -1,5 +1,6 @@
package com.seaofnodes.simple.node;
+
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeInteger;
@@ -8,12 +9,7 @@ public class DivNode extends Node {
@Override public String label() { return "Div"; }
- @Override
- StringBuilder _print1(StringBuilder sb) {
- in(1)._print0(sb.append("("));
- in(2)._print0(sb.append("/"));
- return sb.append(")");
- }
+ @Override protected String format() { return "(%1/%2)"; }
@Override
public Type compute() {
diff --git a/chapter03/src/main/java/com/seaofnodes/simple/node/MinusNode.java b/chapter03/src/main/java/com/seaofnodes/simple/node/MinusNode.java
index b83c41a5..11769935 100644
--- a/chapter03/src/main/java/com/seaofnodes/simple/node/MinusNode.java
+++ b/chapter03/src/main/java/com/seaofnodes/simple/node/MinusNode.java
@@ -1,5 +1,6 @@
package com.seaofnodes.simple.node;
+
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeInteger;
@@ -8,11 +9,7 @@ public class MinusNode extends Node {
@Override public String label() { return "Minus"; }
- @Override
- StringBuilder _print1(StringBuilder sb) {
- in(1)._print0(sb.append("(-"));
- return sb.append(")");
- }
+ @Override protected String format() { return "(-%1)"; }
@Override
public Type compute() {
diff --git a/chapter03/src/main/java/com/seaofnodes/simple/node/MulNode.java b/chapter03/src/main/java/com/seaofnodes/simple/node/MulNode.java
index b2b2f9c0..abae6925 100644
--- a/chapter03/src/main/java/com/seaofnodes/simple/node/MulNode.java
+++ b/chapter03/src/main/java/com/seaofnodes/simple/node/MulNode.java
@@ -1,5 +1,6 @@
package com.seaofnodes.simple.node;
+
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeInteger;
@@ -8,12 +9,7 @@ public class MulNode extends Node {
@Override public String label() { return "Mul"; }
- @Override
- StringBuilder _print1(StringBuilder sb) {
- in(1)._print0(sb.append("("));
- in(2)._print0(sb.append("*"));
- return sb.append(")");
- }
+ @Override protected String format() { return "(%1*%2)"; }
@Override
public Type compute() {
diff --git a/chapter03/src/main/java/com/seaofnodes/simple/node/Node.java b/chapter03/src/main/java/com/seaofnodes/simple/node/Node.java
index 3fa0fd1e..54687b2e 100644
--- a/chapter03/src/main/java/com/seaofnodes/simple/node/Node.java
+++ b/chapter03/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.Parser;
import com.seaofnodes.simple.Utils;
@@ -12,14 +14,7 @@ import java.util.*;
* The Node class provides common functionality used by all subtypes.
* Subtypes of Node specialize by overriding methods.
*/
-public abstract class Node {
-
- /**
- * 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 final int _nid;
+public abstract class Node extends BaseNode<Node> {
/**
* Inputs to the node. These are use-def references to Nodes.
@@ -41,7 +36,6 @@ public abstract class Node {
*/
public final ArrayList<Node> _outputs;
-
/**
* Current computed type for this Node. This value changes as the graph
* changes and more knowledge is gained about the program.
@@ -56,7 +50,7 @@ public abstract class Node {
private static int UNIQUE_ID = 1;
protected Node(Node... inputs) {
- _nid = UNIQUE_ID++; // allocate unique dense ID
+ super(UNIQUE_ID++); // allocate unique dense ID
_inputs = new ArrayList<>();
Collections.addAll(_inputs,inputs);
_outputs = new ArrayList<>();
@@ -68,43 +62,7 @@ public abstract class Node {
// Easy reading label for debugger, e.g. "Add" or "Region" or "EQ"
public abstract String label();
- // Unique label for debugging, e.g. "Add12" or "Region30" or "EQ99"
- public String uniqueName() { return label() + _nid; }
-
- // ------------------------------------------------------------------------
-
- // 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() {
- // TODO: The print evolves in later chapters. For now, a simple
- // recursive print does well. Later with control flow and later still
- // with loops, we need some serious algorithm work to get a decent
- // print. So you should consider the "print" to always be a work-in-
- // progress as we march through the chapters.
- return print();
- }
-
- // This is a *deep* print. This version will fail on cycles, which we will
- // correct later when we can parse programs with loops. We print with a
- // tik-tok style; the common _print0 calls the per-Node _print1, which
- // calls back to _print0;
- public final String print() {
- return _print0(new StringBuilder()).toString();
- }
- // This is the common print: check for DEAD and print "DEAD" else call the
- // per-Node print1.
- final StringBuilder _print0(StringBuilder sb) {
- return isDead()
- ? sb.append(uniqueName()).append(":DEAD")
- : _print1(sb);
- }
- // Every Node implements this.
- abstract StringBuilder _print1(StringBuilder sb);
-
+ @Override public String typeName() { return _type==null ? null : _type.toString(); }
/**
* Gets the ith input node
@@ -121,10 +79,6 @@ public abstract class Node {
public boolean isUnused() { return nOuts() == 0; }
- public boolean isCFG() { return false; }
-
-
-
/**
* Change a <em>def</em> into a Node. Keeps the edges correct, by removing
* the corresponding <em>use->def</em> edge. This may make the original
diff --git a/chapter03/src/main/java/com/seaofnodes/simple/node/ReturnNode.java b/chapter03/src/main/java/com/seaofnodes/simple/node/ReturnNode.java
index 7fa470f8..b48682ca 100644
--- a/chapter03/src/main/java/com/seaofnodes/simple/node/ReturnNode.java
+++ b/chapter03/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.type.*;
/**
@@ -24,8 +26,8 @@ public class ReturnNode extends Node {
public String label() { return "Return"; }
@Override
- StringBuilder _print1(StringBuilder sb) {
- return expr()._print0(sb.append("return ")).append(";");
+ protected ExprPrinter<Node> _print1(ExprPrinter<Node> p) {
+ return p.p("return ").n(expr()).p(";");
}
@Override public boolean isCFG() { return true; }
diff --git a/chapter03/src/main/java/com/seaofnodes/simple/node/ScopeNode.java b/chapter03/src/main/java/com/seaofnodes/simple/node/ScopeNode.java
index 379ef033..95c25391 100644
--- a/chapter03/src/main/java/com/seaofnodes/simple/node/ScopeNode.java
+++ b/chapter03/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.type.Type;
import java.util.*;
@@ -27,22 +29,22 @@ public class ScopeNode extends Node {
@Override public String label() { return "Scope"; }
@Override
- StringBuilder _print1(StringBuilder sb) {
- sb.append(label());
+ protected ExprPrinter<Node> _print1(ExprPrinter<Node> p) {
+ p.p(label());
for( HashMap<String,Integer> scope : _scopes ) {
- sb.append("[");
+ p.p("[");
boolean first=true;
for( String name : scope.keySet() ) {
- if( !first ) sb.append(", ");
+ if( !first ) p.p(", ");
first=false;
- sb.append(name).append(":");
+ p.p(name).p(":");
Node n = in(scope.get(name));
- if( n==null ) sb.append("null");
- else n._print0(sb);
+ if( n==null ) p.p("null");
+ else p.n(n);
}
- sb.append("]");
+ p.p("]");
}
- return sb;
+ return p;
}
/**
diff --git a/chapter03/src/main/java/com/seaofnodes/simple/node/StartNode.java b/chapter03/src/main/java/com/seaofnodes/simple/node/StartNode.java
index 99e240ad..12f35736 100644
--- a/chapter03/src/main/java/com/seaofnodes/simple/node/StartNode.java
+++ b/chapter03/src/main/java/com/seaofnodes/simple/node/StartNode.java
@@ -1,5 +1,7 @@
package com.seaofnodes.simple.node;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.type.Type;
/**
@@ -18,9 +20,8 @@ public class StartNode extends Node {
@Override
public String label() { return "Start"; }
- @Override
- StringBuilder _print1(StringBuilder sb) {
- return sb.append(label());
+ @Override protected ExprPrinter<Node> _print1(ExprPrinter<Node> p) {
+ return p.p(label());
}
@Override public boolean isCFG() { return true; }
diff --git a/chapter03/src/main/java/com/seaofnodes/simple/node/SubNode.java b/chapter03/src/main/java/com/seaofnodes/simple/node/SubNode.java
index 1d2ddaa0..88106018 100644
--- a/chapter03/src/main/java/com/seaofnodes/simple/node/SubNode.java
+++ b/chapter03/src/main/java/com/seaofnodes/simple/node/SubNode.java
@@ -1,5 +1,6 @@
package com.seaofnodes.simple.node;
+
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeInteger;
@@ -8,12 +9,7 @@ public class SubNode extends Node {
@Override public String label() { return "Sub"; }
- @Override
- StringBuilder _print1(StringBuilder sb) {
- in(1)._print0(sb.append("("));
- in(2)._print0(sb.append("-"));
- return sb.append(")");
- }
+ @Override protected String format() { return "(%1-%2)"; }
@Override
public Type compute() {
diff --git a/chapter03/src/main/java/com/seaofnodes/simple/print/SimpleGraphAdapter.java b/chapter03/src/main/java/com/seaofnodes/simple/print/SimpleGraphAdapter.java
index a615741d..c97aaf55 100644
--- a/chapter03/src/main/java/com/seaofnodes/simple/print/SimpleGraphAdapter.java
+++ b/chapter03/src/main/java/com/seaofnodes/simple/print/SimpleGraphAdapter.java
@@ -1,45 +1,24 @@
package com.seaofnodes.simple.print;
import com.seaofnodes.graph.GraphAdapter;
-import com.seaofnodes.graph.GraphSnapshot;
import com.seaofnodes.graph.GraphSnapshot.*;
import com.seaofnodes.simple.node.*;
import com.seaofnodes.simple.node.Node;
-import java.util.ArrayList;
/** Chapter 3's view of the IR; browser, transport and layout are shared. */
public class SimpleGraphAdapter extends GraphAdapter<Node> {
- @Override protected boolean dead(Node n) { return n.isDead(); }
- @Override protected int id(Node n) { return n._nid; }
- @Override protected int nIns(Node n) { return n.nIns(); }
- @Override protected Node in(Node n, int idx) { return n.in(idx); }
- @Override protected int nOuts(Node n) { return n.nOuts(); }
- @Override protected Node out(Node n, int idx) { return n.out(idx); }
- private ArrayList<Edge> edges(Node n) {
- var edges = new ArrayList<Edge>();
- String[] names = n instanceof ScopeNode scope && n.nIns() != 0 ? scope.reverseNames() : null;
- for( int i = 0; i < n.nIns(); i++ ) {
- String name = names == null || i >= names.length ? null : names[i];
- edges.add(new Edge(i, ref(n.in(i)), role(n, i), name));
- }
- return edges;
+ @Override protected String[] edgeNames(Node n) {
+ return n instanceof ScopeNode scope && n.nIns()!=0 ? scope.reverseNames() : null;
}
- @Override protected GraphSnapshot.Node desc(Node n) {
- Projection proj = null;
- String label = n.label();
- return new GraphSnapshot.Node(n._nid, label == null ? n.getClass().getSimpleName() : label,
- n._type == null ? null : n._type.toString(), kind(n), edges(n), proj);
- }
-
- private Kind kind(Node n) {
+ @Override protected Kind kind(Node n) {
if( n instanceof ScopeNode ) return Kind.SCOPE;
if( n instanceof StartNode ) return Kind.CTRL;
return n.isCFG() ? Kind.CTRL : Kind.DATA;
}
- private Role role(Node n, int i) {
+ @Override protected Role role(Node n, int i) {
if( n instanceof ScopeNode || n instanceof ConstantNode ) return Role.ASSOC;
if( i == 0 ) return Role.CTRL;
return Role.DATA;
diff --git a/chapter04/Makefile b/chapter04/Makefile
index 060e0cfd..9648e939 100644
--- a/chapter04/Makefile
+++ b/chapter04/Makefile
@@ -37,6 +37,7 @@ main_javas := $(wildcard $(SRC)/$(SIMPLE)/*java $(SRC)/$(SIMPLE)/*/*java)
test_javas := $(wildcard $(TST)/$(SIMPLE)/*java $(TST)/$(SIMPLE)/*/*java)
main_classes := $(patsubst $(SRC)/%java,$(CLZDIR)/main/%class,$(main_javas))
include $(firstword $(wildcard ../graph/graph.mk graph/graph.mk))
+include $(firstword $(wildcard ../print/print.mk print/print.mk))
test_classes := $(patsubst $(TST)/%java,$(CLZDIR)/test/%class,$(test_javas))
test_cp := $(patsubst $(TST)/$(SIMPLE)/%.java,com.seaofnodes.simple.%,$(wildcard $(TST)/$(SIMPLE)/*Test.java))
classes = $(main_classes) $(test_classes)
@@ -57,7 +58,7 @@ default: $(default_targets)
build: $(main_classes)
# Compile just the out-of-date files
-$(main_classes): $(CLZDIR)/main/%class: $(SRC)/%java $(graph_javas)
+$(main_classes): $(CLZDIR)/main/%class: $(SRC)/%java $(graph_javas) $(print_javas)
@echo "compiling " $@ " because " $?
@[ -d $(CLZDIR)/main ] || mkdir -p $(CLZDIR)/main
@javac $(JAVAC_ARGS) -cp "$(CLZDIR)/main$(SEP)$(jars)" -sourcepath $(SRC) -d $(CLZDIR)/main $(main_javas)
diff --git a/chapter04/pom.xml b/chapter04/pom.xml
index 5b9c7c6e..a2f3b26a 100644
--- a/chapter04/pom.xml
+++ b/chapter04/pom.xml
@@ -13,5 +13,6 @@
<name>Chapter 4</name>
<properties>
<simple.graph.directory>${project.basedir}/../graph</simple.graph.directory>
+ <simple.print.directory>${project.basedir}/../print</simple.print.directory>
</properties>
</project>
diff --git a/chapter04/src/main/java/com/seaofnodes/simple/node/AddNode.java b/chapter04/src/main/java/com/seaofnodes/simple/node/AddNode.java
index 0291a900..2fa4514e 100644
--- a/chapter04/src/main/java/com/seaofnodes/simple/node/AddNode.java
+++ b/chapter04/src/main/java/com/seaofnodes/simple/node/AddNode.java
@@ -1,5 +1,6 @@
package com.seaofnodes.simple.node;
+
import com.seaofnodes.simple.type.*;
public class AddNode extends Node {
@@ -7,12 +8,7 @@ public class AddNode extends Node {
@Override public String label() { return "Add"; }
- @Override
- StringBuilder _print1(StringBuilder sb) {
- in(1)._print0(sb.append("("));
- in(2)._print0(sb.append("+"));
- return sb.append(")");
- }
+ @Override protected String format() { return "(%1+%2)"; }
@Override
diff --git a/chapter04/src/main/java/com/seaofnodes/simple/node/BoolNode.java b/chapter04/src/main/java/com/seaofnodes/simple/node/BoolNode.java
index 143a6fde..4c79fa0b 100644
--- a/chapter04/src/main/java/com/seaofnodes/simple/node/BoolNode.java
+++ b/chapter04/src/main/java/com/seaofnodes/simple/node/BoolNode.java
@@ -1,5 +1,7 @@
package com.seaofnodes.simple.node;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeInteger;
@@ -14,11 +16,8 @@ abstract public class BoolNode extends Node {
@Override
public String label() { return getClass().getSimpleName(); }
- @Override
- StringBuilder _print1(StringBuilder sb) {
- in(1)._print0(sb.append("("));
- in(2)._print0(sb.append(op()));
- 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/chapter04/src/main/java/com/seaofnodes/simple/node/ConstantNode.java b/chapter04/src/main/java/com/seaofnodes/simple/node/ConstantNode.java
index 85277d82..5efe29b7 100644
--- a/chapter04/src/main/java/com/seaofnodes/simple/node/ConstantNode.java
+++ b/chapter04/src/main/java/com/seaofnodes/simple/node/ConstantNode.java
@@ -1,5 +1,7 @@
package com.seaofnodes.simple.node;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.Parser;
import com.seaofnodes.simple.type.Type;
@@ -22,15 +24,16 @@ public class ConstantNode extends Node {
_con = type;
}
- @Override
- public String label() { return ""+_con; }
+ @Override protected String repeatName() {
+ return _con==null || _con.toString().length()<=32 ? null : uniqueName();
+ }
@Override
- public String uniqueName() { return "Con_" + _nid; }
+ public String label() { return "Con"; }
- @Override
- StringBuilder _print1(StringBuilder sb) {
- return _con.print(sb);
+
+ @Override protected ExprPrinter<Node> _print1(ExprPrinter<Node> p) {
+ return p.p(_con);
}
@Override
diff --git a/chapter04/src/main/java/com/seaofnodes/simple/node/DivNode.java b/chapter04/src/main/java/com/seaofnodes/simple/node/DivNode.java
index bffa4b44..08dea003 100644
--- a/chapter04/src/main/java/com/seaofnodes/simple/node/DivNode.java
+++ b/chapter04/src/main/java/com/seaofnodes/simple/node/DivNode.java
@@ -1,5 +1,6 @@
package com.seaofnodes.simple.node;
+
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeInteger;
@@ -8,12 +9,7 @@ public class DivNode extends Node {
@Override public String label() { return "Div"; }
- @Override
- StringBuilder _print1(StringBuilder sb) {
- in(1)._print0(sb.append("("));
- in(2)._print0(sb.append("/"));
- return sb.append(")");
- }
+ @Override protected String format() { return "(%1/%2)"; }
@Override
public Type compute() {
diff --git a/chapter04/src/main/java/com/seaofnodes/simple/node/MinusNode.java b/chapter04/src/main/java/com/seaofnodes/simple/node/MinusNode.java
index ad6e513a..bb5f155d 100644
--- a/chapter04/src/main/java/com/seaofnodes/simple/node/MinusNode.java
+++ b/chapter04/src/main/java/com/seaofnodes/simple/node/MinusNode.java
@@ -1,5 +1,6 @@
package com.seaofnodes.simple.node;
+
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeInteger;
@@ -8,11 +9,7 @@ public class MinusNode extends Node {
@Override public String label() { return "Minus"; }
- @Override
- StringBuilder _print1(StringBuilder sb) {
- in(1)._print0(sb.append("(-"));
- return sb.append(")");
- }
+ @Override protected String format() { return "(-%1)"; }
@Override
public Type compute() {
diff --git a/chapter04/src/main/java/com/seaofnodes/simple/node/MulNode.java b/chapter04/src/main/java/com/seaofnodes/simple/node/MulNode.java
index 60103b8b..e866cf24 100644
--- a/chapter04/src/main/java/com/seaofnodes/simple/node/MulNode.java
+++ b/chapter04/src/main/java/com/seaofnodes/simple/node/MulNode.java
@@ -1,5 +1,6 @@
package com.seaofnodes.simple.node;
+
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeInteger;
@@ -8,12 +9,7 @@ public class MulNode extends Node {
@Override public String label() { return "Mul"; }
- @Override
- StringBuilder _print1(StringBuilder sb) {
- in(1)._print0(sb.append("("));
- in(2)._print0(sb.append("*"));
- return sb.append(")");
- }
+ @Override protected String format() { return "(%1*%2)"; }
@Override
public Type compute() {
diff --git a/chapter04/src/main/java/com/seaofnodes/simple/node/Node.java b/chapter04/src/main/java/com/seaofnodes/simple/node/Node.java
index fdde869b..bd72c8e4 100644
--- a/chapter04/src/main/java/com/seaofnodes/simple/node/Node.java
+++ b/chapter04/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.Parser;
import com.seaofnodes.simple.Utils;
import com.seaofnodes.simple.type.Type;
@@ -10,14 +12,7 @@ import java.util.*;
* The Node class provides common functionality used by all subtypes.
* Subtypes of Node specialize by overriding methods.
*/
-public abstract class Node {
-
- /**
- * 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 final int _nid;
+public abstract class Node extends BaseNode<Node> {
/**
* Inputs to the node. These are use-def references to Nodes.
@@ -39,7 +34,6 @@ public abstract class Node {
*/
public final ArrayList<Node> _outputs;
-
/**
* Current computed type for this Node. This value changes as the graph
* changes and more knowledge is gained about the program.
@@ -54,7 +48,7 @@ public abstract class Node {
private static int UNIQUE_ID = 1;
protected Node(Node... inputs) {
- _nid = UNIQUE_ID++; // allocate unique dense ID
+ super(UNIQUE_ID++); // allocate unique dense ID
_inputs = new ArrayList<>();
Collections.addAll(_inputs,inputs);
_outputs = new ArrayList<>();
@@ -66,36 +60,7 @@ public abstract class Node {
// Easy reading label for debugger, e.g. "Add" or "Region" or "EQ"
public abstract String label();
- // Unique label for debugging, e.g. "Add12" or "Region30" or "EQ99"
- public String uniqueName() { return label() + _nid; }
-
- // ------------------------------------------------------------------------
-
- // 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. This version will fail on cycles, which we will
- // correct later when we can parse programs with loops. We print with a
- // tik-tok style; the common _print0 calls the per-Node _print1, which
- // calls back to _print0;
- public final String print() {
- return _print0(new StringBuilder()).toString();
- }
- // This is the common print: check for DEAD and print "DEAD" else call the
- // per-Node print1.
- final StringBuilder _print0(StringBuilder sb) {
- return isDead()
- ? sb.append(uniqueName()).append(":DEAD")
- : _print1(sb);
- }
- // Every Node implements this.
- abstract StringBuilder _print1(StringBuilder sb);
-
+ @Override public String typeName() { return _type==null ? null : _type.toString(); }
/**
* Gets the ith input node
@@ -112,8 +77,6 @@ public abstract class Node {
public boolean isUnused() { return nOuts() == 0; }
- public boolean isCFG() { return false; }
-
/**
* Change a <em>def</em> into a Node. Keeps the edges correct, by removing
* the corresponding <em>use->def</em> edge. This may make the original
@@ -334,7 +297,6 @@ public abstract class Node {
*/
public abstract Node idealize();
-
// ------------------------------------------------------------------------
// Peephole utilities
diff --git a/chapter04/src/main/java/com/seaofnodes/simple/node/NotNode.java b/chapter04/src/main/java/com/seaofnodes/simple/node/NotNode.java
index 6a56ff64..a9781ce1 100644
--- a/chapter04/src/main/java/com/seaofnodes/simple/node/NotNode.java
+++ b/chapter04/src/main/java/com/seaofnodes/simple/node/NotNode.java
@@ -1,5 +1,6 @@
package com.seaofnodes.simple.node;
+
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeInteger;
@@ -8,11 +9,7 @@ public class NotNode extends Node {
@Override public String label() { return "Not"; }
- @Override
- StringBuilder _print1(StringBuilder sb) {
- in(1)._print0(sb.append("(!"));
- return sb.append(")");
- }
+ @Override protected String format() { return "(!%1)"; }
@Override
public Type compute() {
diff --git a/chapter04/src/main/java/com/seaofnodes/simple/node/ProjNode.java b/chapter04/src/main/java/com/seaofnodes/simple/node/ProjNode.java
index 2f49fe91..063f9edc 100644
--- a/chapter04/src/main/java/com/seaofnodes/simple/node/ProjNode.java
+++ b/chapter04/src/main/java/com/seaofnodes/simple/node/ProjNode.java
@@ -1,5 +1,7 @@
package com.seaofnodes.simple.node;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeTuple;
@@ -21,7 +23,7 @@ public class ProjNode extends Node {
public String label() { return _label; }
@Override
- StringBuilder _print1(StringBuilder sb) { return sb.append(_label); }
+ protected ExprPrinter<Node> _print1(ExprPrinter<Node> p) { return p.p(_label); }
@Override public boolean isCFG() { return _idx==0; }
diff --git a/chapter04/src/main/java/com/seaofnodes/simple/node/ReturnNode.java b/chapter04/src/main/java/com/seaofnodes/simple/node/ReturnNode.java
index c9d6c9c8..c5dc532d 100644
--- a/chapter04/src/main/java/com/seaofnodes/simple/node/ReturnNode.java
+++ b/chapter04/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.type.*;
/**
@@ -24,8 +26,8 @@ public class ReturnNode extends Node {
public String label() { return "Return"; }
@Override
- StringBuilder _print1(StringBuilder sb) {
- return expr()._print0(sb.append("return ")).append(";");
+ protected ExprPrinter<Node> _print1(ExprPrinter<Node> p) {
+ return p.p("return ").n(expr()).p(";");
}
@Override public boolean isCFG() { return true; }
diff --git a/chapter04/src/main/java/com/seaofnodes/simple/node/ScopeNode.java b/chapter04/src/main/java/com/seaofnodes/simple/node/ScopeNode.java
index 8ffeac64..6ffa8939 100644
--- a/chapter04/src/main/java/com/seaofnodes/simple/node/ScopeNode.java
+++ b/chapter04/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.type.Type;
import java.util.*;
@@ -33,22 +35,22 @@ public class ScopeNode extends Node {
@Override public String label() { return "Scope"; }
@Override
- StringBuilder _print1(StringBuilder sb) {
- sb.append(label());
+ protected ExprPrinter<Node> _print1(ExprPrinter<Node> p) {
+ p.p(label());
for( HashMap<String,Integer> scope : _scopes ) {
- sb.append("[");
+ p.p("[");
boolean first=true;
for( String name : scope.keySet() ) {
- if( !first ) sb.append(", ");
+ if( !first ) p.p(", ");
first=false;
- sb.append(name).append(":");
+ p.p(name).p(":");
Node n = in(scope.get(name));
- if( n==null ) sb.append("null");
- else n._print0(sb);
+ if( n==null ) p.p("null");
+ else p.n(n);
}
- sb.append("]");
+ p.p("]");
}
- return sb;
+ return p;
}
/**
diff --git a/chapter04/src/main/java/com/seaofnodes/simple/node/StartNode.java b/chapter04/src/main/java/com/seaofnodes/simple/node/StartNode.java
index 022e276d..c9f53abd 100644
--- a/chapter04/src/main/java/com/seaofnodes/simple/node/StartNode.java
+++ b/chapter04/src/main/java/com/seaofnodes/simple/node/StartNode.java
@@ -1,5 +1,7 @@
package com.seaofnodes.simple.node;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeTuple;
@@ -23,9 +25,8 @@ public class StartNode extends MultiNode {
@Override
public String label() { return "Start"; }
- @Override
- StringBuilder _print1(StringBuilder sb) {
- return sb.append(label());
+ @Override protected ExprPrinter<Node> _print1(ExprPrinter<Node> p) {
+ return p.p(label());
}
@Override public boolean isCFG() { return true; }
diff --git a/chapter04/src/main/java/com/seaofnodes/simple/node/SubNode.java b/chapter04/src/main/java/com/seaofnodes/simple/node/SubNode.java
index c831a798..43e684a1 100644
--- a/chapter04/src/main/java/com/seaofnodes/simple/node/SubNode.java
+++ b/chapter04/src/main/java/com/seaofnodes/simple/node/SubNode.java
@@ -1,5 +1,6 @@
package com.seaofnodes.simple.node;
+
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeInteger;
@@ -8,12 +9,7 @@ public class SubNode extends Node {
@Override public String label() { return "Sub"; }
- @Override
- StringBuilder _print1(StringBuilder sb) {
- in(1)._print0(sb.append("("));
- in(2)._print0(sb.append("-"));
- return sb.append(")");
- }
+ @Override protected String format() { return "(%1-%2)"; }
@Override
public Type compute() {
diff --git a/chapter04/src/main/java/com/seaofnodes/simple/print/SimpleGraphAdapter.java b/chapter04/src/main/java/com/seaofnodes/simple/print/SimpleGraphAdapter.java
index a0ad7be0..b68012dc 100644
--- a/chapter04/src/main/java/com/seaofnodes/simple/print/SimpleGraphAdapter.java
+++ b/chapter04/src/main/java/com/seaofnodes/simple/print/SimpleGraphAdapter.java
@@ -1,39 +1,22 @@
package com.seaofnodes.simple.print;
import com.seaofnodes.graph.GraphAdapter;
-import com.seaofnodes.graph.GraphSnapshot;
import com.seaofnodes.graph.GraphSnapshot.*;
import com.seaofnodes.simple.node.*;
import com.seaofnodes.simple.node.Node;
-import java.util.ArrayList;
/** Chapter 4's view of the IR; no knowledge of browser, transport or layout. */
public class SimpleGraphAdapter extends GraphAdapter<Node> {
- @Override protected boolean dead(Node n) { return n.isDead(); }
- @Override protected int id(Node n) { return n._nid; }
- @Override protected int nIns(Node n) { return n.nIns(); }
- @Override protected Node in(Node n, int idx) { return n.in(idx); }
- @Override protected int nOuts(Node n) { return n.nOuts(); }
- @Override protected Node out(Node n, int idx) { return n.out(idx); }
- private ArrayList<Edge> edges(Node n) {
- String[] names = n instanceof ScopeNode scope && n.nIns() != 0 ? scope.reverseNames() : null;
- var edges = new ArrayList<Edge>();
- for( int i = 0; i < n.nIns(); i++ ) {
- Role role = n instanceof ScopeNode || n instanceof ConstantNode ? Role.ASSOC
- : n instanceof ProjNode ? (n.isCFG() ? Role.CTRL : Role.DATA)
- : i == 0 ? Role.CTRL : Role.DATA;
- edges.add(new Edge(i, ref(n.in(i)), role, names == null ? null : names[i]));
- }
- return edges;
+ @Override protected String[] edgeNames(Node n) {
+ return n instanceof ScopeNode scope && n.nIns()!=0 ? scope.reverseNames() : null;
}
+ @Override protected int projectionIndex(Node n) { return n instanceof ProjNode p ? p._idx : -1; }
- @Override protected GraphSnapshot.Node desc(Node n) {
- Projection proj = n instanceof ProjNode p
- ? new Projection(n.nIns() == 0 ? 0 : ref(n.in(0)), p._idx) : null;
- Kind kind = n instanceof ScopeNode ? Kind.SCOPE : n.isCFG() ? Kind.CTRL : Kind.DATA;
- String label = n.label();
- return new GraphSnapshot.Node(n._nid, label == null ? n.getClass().getSimpleName() : label,
- n._type == null ? null : n._type.toString(), kind, edges(n), proj);
+ @Override protected Kind kind(Node n) { return n instanceof ScopeNode ? Kind.SCOPE : n.isCFG() ? Kind.CTRL : Kind.DATA; }
+ @Override protected Role role(Node n, int i) {
+ return n instanceof ScopeNode || n instanceof ConstantNode ? Role.ASSOC
+ : n instanceof ProjNode ? (n.isCFG() ? Role.CTRL : Role.DATA)
+ : i==0 ? Role.CTRL : Role.DATA;
}
}
diff --git a/chapter05/pom.xml b/chapter05/pom.xml
index d952e5ca..75f352a3 100644
--- a/chapter05/pom.xml
+++ b/chapter05/pom.xml
@@ -13,5 +13,6 @@
<name>Chapter 5</name>
<properties>
<simple.graph.directory>${project.basedir}/../graph</simple.graph.directory>
+ <simple.print.directory>${project.basedir}/../print</simple.print.directory>
</properties>
</project>
diff --git a/chapter05/src/main/java/com/seaofnodes/simple/node/AddNode.java b/chapter05/src/main/java/com/seaofnodes/simple/node/AddNode.java
index 2772c4c5..367cb2c0 100644
--- a/chapter05/src/main/java/com/seaofnodes/simple/node/AddNode.java
+++ b/chapter05/src/main/java/com/seaofnodes/simple/node/AddNode.java
@@ -1,5 +1,6 @@
package com.seaofnodes.simple.node;
+
import com.seaofnodes.simple.type.*;
public class AddNode extends Node {
@@ -7,12 +8,7 @@ public class AddNode extends Node {
@Override public String label() { return "Add"; }
- @Override
- StringBuilder _print1(StringBuilder sb) {
- in(1)._print0(sb.append("("));
- in(2)._print0(sb.append("+"));
- return sb.append(")");
- }
+ @Override protected String format() { return "(%1+%2)"; }
@Override
diff --git a/chapter05/src/main/java/com/seaofnodes/simple/node/BoolNode.java b/chapter05/src/main/java/com/seaofnodes/simple/node/BoolNode.java
index 87acc6cc..aaf261d5 100644
--- a/chapter05/src/main/java/com/seaofnodes/simple/node/BoolNode.java
+++ b/chapter05/src/main/java/com/seaofnodes/simple/node/BoolNode.java
@@ -1,5 +1,7 @@
package com.seaofnodes.simple.node;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeInteger;
@@ -14,11 +16,8 @@ abstract public class BoolNode extends Node {
@Override
public String label() { return getClass().getSimpleName(); }
- @Override
- StringBuilder _print1(StringBuilder sb) {
- in(1)._print0(sb.append("("));
- in(2)._print0(sb.append(op()));
- 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/chapter05/src/main/java/com/seaofnodes/simple/node/ConstantNode.java b/chapter05/src/main/java/com/seaofnodes/simple/node/ConstantNode.java
index 85277d82..5efe29b7 100644
--- a/chapter05/src/main/java/com/seaofnodes/simple/node/ConstantNode.java
+++ b/chapter05/src/main/java/com/seaofnodes/simple/node/ConstantNode.java
@@ -1,5 +1,7 @@
package com.seaofnodes.simple.node;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.Parser;
import com.seaofnodes.simple.type.Type;
@@ -22,15 +24,16 @@ public class ConstantNode extends Node {
_con = type;
}
- @Override
- public String label() { return ""+_con; }
+ @Override protected String repeatName() {
+ return _con==null || _con.toString().length()<=32 ? null : uniqueName();
+ }
@Override
- public String uniqueName() { return "Con_" + _nid; }
+ public String label() { return "Con"; }
- @Override
- StringBuilder _print1(StringBuilder sb) {
- return _con.print(sb);
+
+ @Override protected ExprPrinter<Node> _print1(ExprPrinter<Node> p) {
+ return p.p(_con);
}
@Override
diff --git a/chapter05/src/main/java/com/seaofnodes/simple/node/DivNode.java b/chapter05/src/main/java/com/seaofnodes/simple/node/DivNode.java
index f80f092d..f6b4e03e 100644
--- a/chapter05/src/main/java/com/seaofnodes/simple/node/DivNode.java
+++ b/chapter05/src/main/java/com/seaofnodes/simple/node/DivNode.java
@@ -1,5 +1,6 @@
package com.seaofnodes.simple.node;
+
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeInteger;
@@ -8,12 +9,7 @@ public class DivNode extends Node {
@Override public String label() { return "Div"; }
- @Override
- StringBuilder _print1(StringBuilder sb) {
- in(1)._print0(sb.append("("));
- in(2)._print0(sb.append("/"));
- return sb.append(")");
- }
+ @Override protected String format() { return "(%1/%2)"; }
@Override
public Type compute() {
diff --git a/chapter05/src/main/java/com/seaofnodes/simple/node/IfNode.java b/chapter05/src/main/java/com/seaofnodes/simple/node/IfNode.java
index 6124b893..3b644bec 100644
--- a/chapter05/src/main/java/com/seaofnodes/simple/node/IfNode.java
+++ b/chapter05/src/main/java/com/seaofnodes/simple/node/IfNode.java
@@ -1,5 +1,6 @@
package com.seaofnodes.simple.node;
+
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeInteger;
import com.seaofnodes.simple.type.TypeTuple;
@@ -13,11 +14,7 @@ public class IfNode extends MultiNode {
@Override
public String label() { return "If"; }
- @Override
- StringBuilder _print1(StringBuilder sb) {
- sb.append("if( ");
- return in(1)._print0(sb).append(" )");
- }
+ @Override protected String format() { return "if( %1 )"; }
@Override public boolean isCFG() { return true; }
diff --git a/chapter05/src/main/java/com/seaofnodes/simple/node/MinusNode.java b/chapter05/src/main/java/com/seaofnodes/simple/node/MinusNode.java
index ad6e513a..bb5f155d 100644
--- a/chapter05/src/main/java/com/seaofnodes/simple/node/MinusNode.java
+++ b/chapter05/src/main/java/com/seaofnodes/simple/node/MinusNode.java
@@ -1,5 +1,6 @@
package com.seaofnodes.simple.node;
+
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeInteger;
@@ -8,11 +9,7 @@ public class MinusNode extends Node {
@Override public String label() { return "Minus"; }
- @Override
- StringBuilder _print1(StringBuilder sb) {
- in(1)._print0(sb.append("(-"));
- return sb.append(")");
- }
+ @Override protected String format() { return "(-%1)"; }
@Override
public Type compute() {
diff --git a/chapter05/src/main/java/com/seaofnodes/simple/node/MulNode.java b/chapter05/src/main/java/com/seaofnodes/simple/node/MulNode.java
index b1d9e44a..a881bd96 100644
--- a/chapter05/src/main/java/com/seaofnodes/simple/node/MulNode.java
+++ b/chapter05/src/main/java/com/seaofnodes/simple/node/MulNode.java
@@ -1,5 +1,6 @@
package com.seaofnodes.simple.node;
+
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeInteger;
@@ -8,12 +9,7 @@ public class MulNode extends Node {
@Override public String label() { return "Mul"; }
- @Override
- StringBuilder _print1(StringBuilder sb) {
- in(1)._print0(sb.append("("));
- in(2)._print0(sb.append("*"));
- return sb.append(")");
- }
+ @Override protected String format() { return "(%1*%2)"; }
@Override
public Type compute() {
diff --git a/chapter05/src/main/java/com/seaofnodes/simple/node/Node.java b/chapter05/src/main/java/com/seaofnodes/simple/node/Node.java
index e17d7b9a..72469ad2 100644
--- a/chapter05/src/main/java/com/seaofnodes/simple/node/Node.java
+++ b/chapter05/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.Parser;
import com.seaofnodes.simple.Utils;
import com.seaofnodes.simple.type.Type;
@@ -10,14 +12,7 @@ import java.util.*;
* The Node class provides common functionality used by all subtypes.
* Subtypes of Node specialize by overriding methods.
*/
-public abstract class Node {
-
- /**
- * 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 final int _nid;
+public abstract class Node extends BaseNode<Node> {
/**
* Inputs to the node. These are use-def references to Nodes.
@@ -39,7 +34,6 @@ public abstract class Node {
*/
public final ArrayList<Node> _outputs;
-
/**
* Current computed type for this Node. This value changes as the graph
* changes and more knowledge is gained about the program.
@@ -54,7 +48,7 @@ public abstract class Node {
private static int UNIQUE_ID = 1;
protected Node(Node... inputs) {
- _nid = UNIQUE_ID++; // allocate unique dense ID
+ super(UNIQUE_ID++); // allocate unique dense ID
_inputs = new ArrayList<>();
Collections.addAll(_inputs,inputs);
_outputs = new ArrayList<>();
@@ -66,36 +60,7 @@ public abstract class Node {
// Easy reading label for debugger, e.g. "Add" or "Region" or "EQ"
public abstract String label();
- // Unique label for debugging, e.g. "Add12" or "Region30" or "EQ99"
- public String uniqueName() { return label() + _nid; }
-
- // ------------------------------------------------------------------------
-
- // 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. This version will fail on cycles, which we will
- // correct later when we can parse programs with loops. We print with a
- // tik-tok style; the common _print0 calls the per-Node _print1, which
- // calls back to _print0;
- public final String print() {
- return _print0(new StringBuilder()).toString();
- }
- // This is the common print: check for DEAD and print "DEAD" else call the
- // per-Node print1.
- final StringBuilder _print0(StringBuilder sb) {
- return isDead()
- ? sb.append(uniqueName()).append(":DEAD")
- : _print1(sb);
- }
- // Every Node implements this.
- abstract StringBuilder _print1(StringBuilder sb);
-
+ @Override public String typeName() { return _type==null ? null : _type.toString(); }
/**
* Gets the ith input node
@@ -112,8 +77,6 @@ public abstract class Node {
public boolean isUnused() { return nOuts() == 0; }
- public boolean isCFG() { return false; }
-
/**
* Change a <em>def</em> into a Node. Keeps the edges correct, by removing
* the corresponding <em>use->def</em> edge. This may make the original
@@ -334,7 +297,6 @@ public abstract class Node {
*/
public abstract Node idealize();
-
// ------------------------------------------------------------------------
// Peephole utilities
diff --git a/chapter05/src/main/java/com/seaofnodes/simple/node/NotNode.java b/chapter05/src/main/java/com/seaofnodes/simple/node/NotNode.java
index 6a56ff64..a9781ce1 100644
--- a/chapter05/src/main/java/com/seaofnodes/simple/node/NotNode.java
+++ b/chapter05/src/main/java/com/seaofnodes/simple/node/NotNode.java
@@ -1,5 +1,6 @@
package com.seaofnodes.simple.node;
+
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeInteger;
@@ -8,11 +9,7 @@ public class NotNode extends Node {
@Override public String label() { return "Not"; }
- @Override
- StringBuilder _print1(StringBuilder sb) {
- in(1)._print0(sb.append("(!"));
- return sb.append(")");
- }
+ @Override protected String format() { return "(!%1)"; }
@Override
public Type compute() {
diff --git a/chapter05/src/main/java/com/seaofnodes/simple/node/PhiNode.java b/chapter05/src/main/java/com/seaofnodes/simple/node/PhiNode.java
index b3b5462d..da3917c7 100644
--- a/chapter05/src/main/java/com/seaofnodes/simple/node/PhiNode.java
+++ b/chapter05/src/main/java/com/seaofnodes/simple/node/PhiNode.java
@@ -1,5 +1,7 @@
package com.seaofnodes.simple.node;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.type.Type;
public class PhiNode extends Node {
@@ -11,13 +13,11 @@ public class PhiNode extends Node {
@Override public String label() { return "Phi_"+_label; }
@Override
- StringBuilder _print1(StringBuilder sb) {
- sb.append("Phi(");
+ protected ExprPrinter<Node> _print1(ExprPrinter<Node> p) {
+ p.p("Phi(");
for( Node in : _inputs )
- in._print0(sb).append(",");
- sb.setLength(sb.length()-1);
- sb.append(")");
- return sb;
+ p.n(in).p(",");
+ return p.unchar(',').close();
}
Node region() { return in(0); }
diff --git a/chapter05/src/main/java/com/seaofnodes/simple/node/ProjNode.java b/chapter05/src/main/java/com/seaofnodes/simple/node/ProjNode.java
index 2826d192..8917fbd4 100644
--- a/chapter05/src/main/java/com/seaofnodes/simple/node/ProjNode.java
+++ b/chapter05/src/main/java/com/seaofnodes/simple/node/ProjNode.java
@@ -1,5 +1,7 @@
package com.seaofnodes.simple.node;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeTuple;
@@ -21,7 +23,7 @@ public class ProjNode extends Node {
public String label() { return _label; }
@Override
- StringBuilder _print1(StringBuilder sb) { return sb.append(_label); }
+ protected ExprPrinter<Node> _print1(ExprPrinter<Node> p) { return p.p(_label); }
@Override public boolean isCFG() { return _idx==0 || ctrl() instanceof IfNode; }
diff --git a/chapter05/src/main/java/com/seaofnodes/simple/node/RegionNode.java b/chapter05/src/main/java/com/seaofnodes/simple/node/RegionNode.java
index 5d520d65..e29254ad 100644
--- a/chapter05/src/main/java/com/seaofnodes/simple/node/RegionNode.java
+++ b/chapter05/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.type.Type;
public class RegionNode extends Node {
@@ -8,9 +10,8 @@ public class RegionNode extends Node {
@Override
public String label() { return "Region"; }
- @Override
- StringBuilder _print1(StringBuilder sb) {
- return sb.append(label()).append(_nid);
+ @Override protected ExprPrinter<Node> _print1(ExprPrinter<Node> p) {
+ return p.p(label()).p(_nid);
}
@Override public boolean isCFG() { return true; }
diff --git a/chapter05/src/main/java/com/seaofnodes/simple/node/ReturnNode.java b/chapter05/src/main/java/com/seaofnodes/simple/node/ReturnNode.java
index c9d6c9c8..c5dc532d 100644
--- a/chapter05/src/main/java/com/seaofnodes/simple/node/ReturnNode.java
+++ b/chapter05/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.type.*;
/**
@@ -24,8 +26,8 @@ public class ReturnNode extends Node {
public String label() { return "Return"; }
@Override
- StringBuilder _print1(StringBuilder sb) {
- return expr()._print0(sb.append("return ")).append(";");
+ protected ExprPrinter<Node> _print1(ExprPrinter<Node> p) {
+ return p.p("return ").n(expr()).p(";");
}
@Override public boolean isCFG() { return true; }
diff --git a/chapter05/src/main/java/com/seaofnodes/simple/node/ScopeNode.java b/chapter05/src/main/java/com/seaofnodes/simple/node/ScopeNode.java
index 32045fbc..90b97bae 100644
--- a/chapter05/src/main/java/com/seaofnodes/simple/node/ScopeNode.java
+++ b/chapter05/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.type.Type;
import java.util.*;
@@ -33,22 +35,22 @@ public class ScopeNode extends Node {
@Override public String label() { return "Scope"; }
@Override
- StringBuilder _print1(StringBuilder sb) {
- sb.append(label());
+ protected ExprPrinter<Node> _print1(ExprPrinter<Node> p) {
+ p.p(label());
for( HashMap<String,Integer> scope : _scopes ) {
- sb.append("[");
+ p.p("[");
boolean first=true;
for( String name : scope.keySet() ) {
- if( !first ) sb.append(", ");
+ if( !first ) p.p(", ");
first=false;
- sb.append(name).append(":");
+ p.p(name).p(":");
Node n = in(scope.get(name));
- if( n==null ) sb.append("null");
- else n._print0(sb);
+ if( n==null ) p.p("null");
+ else p.n(n);
}
- sb.append("]");
+ p.p("]");
}
- return sb;
+ return p;
}
/**
diff --git a/chapter05/src/main/java/com/seaofnodes/simple/node/StartNode.java b/chapter05/src/main/java/com/seaofnodes/simple/node/StartNode.java
index 022e276d..c9f53abd 100644
--- a/chapter05/src/main/java/com/seaofnodes/simple/node/StartNode.java
+++ b/chapter05/src/main/java/com/seaofnodes/simple/node/StartNode.java
@@ -1,5 +1,7 @@
package com.seaofnodes.simple.node;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeTuple;
@@ -23,9 +25,8 @@ public class StartNode extends MultiNode {
@Override
public String label() { return "Start"; }
- @Override
- StringBuilder _print1(StringBuilder sb) {
- return sb.append(label());
+ @Override protected ExprPrinter<Node> _print1(ExprPrinter<Node> p) {
+ return p.p(label());
}
@Override public boolean isCFG() { return true; }
diff --git a/chapter05/src/main/java/com/seaofnodes/simple/node/StopNode.java b/chapter05/src/main/java/com/seaofnodes/simple/node/StopNode.java
index a30256f9..9ae0acb4 100644
--- a/chapter05/src/main/java/com/seaofnodes/simple/node/StopNode.java
+++ b/chapter05/src/main/java/com/seaofnodes/simple/node/StopNode.java
@@ -1,5 +1,7 @@
package com.seaofnodes.simple.node;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.type.Type;
public class StopNode extends Node {
@@ -13,12 +15,12 @@ public class StopNode extends Node {
}
@Override
- StringBuilder _print1(StringBuilder sb) {
- if( ret()!=null ) return ret()._print0(sb);
- sb.append("Stop[ ");
+ protected ExprPrinter<Node> _print1(ExprPrinter<Node> p) {
+ if( ret()!=null ) return p.n(ret());
+ p.p("Stop[ ");
for( Node ret : _inputs )
- ret._print0(sb).append(" ");
- return sb.append("]");
+ p.n(ret).p(" ");
+ return p.p("]");
}
@Override public boolean isCFG() { return true; }
diff --git a/chapter05/src/main/java/com/seaofnodes/simple/node/SubNode.java b/chapter05/src/main/java/com/seaofnodes/simple/node/SubNode.java
index bd43bc6c..7a6e1a4b 100644
--- a/chapter05/src/main/java/com/seaofnodes/simple/node/SubNode.java
+++ b/chapter05/src/main/java/com/seaofnodes/simple/node/SubNode.java
@@ -1,5 +1,6 @@
package com.seaofnodes.simple.node;
+
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeInteger;
@@ -8,12 +9,7 @@ public class SubNode extends Node {
@Override public String label() { return "Sub"; }
- @Override
- StringBuilder _print1(StringBuilder sb) {
- in(1)._print0(sb.append("("));
- in(2)._print0(sb.append("-"));
- return sb.append(")");
- }
+ @Override protected String format() { return "(%1-%2)"; }
@Override
public Type compute() {
diff --git a/chapter05/src/main/java/com/seaofnodes/simple/print/SimpleGraphAdapter.java b/chapter05/src/main/java/com/seaofnodes/simple/print/SimpleGraphAdapter.java
index 0c2ac4b0..930d5376 100644
--- a/chapter05/src/main/java/com/seaofnodes/simple/print/SimpleGraphAdapter.java
+++ b/chapter05/src/main/java/com/seaofnodes/simple/print/SimpleGraphAdapter.java
@@ -1,39 +1,19 @@
package com.seaofnodes.simple.print;
import com.seaofnodes.graph.GraphAdapter;
-import com.seaofnodes.graph.GraphSnapshot;
import com.seaofnodes.graph.GraphSnapshot.*;
import com.seaofnodes.simple.node.*;
import com.seaofnodes.simple.node.Node;
-import java.util.ArrayList;
/** Chapter 5's view of the IR; browser, transport and layout are shared. */
public class SimpleGraphAdapter extends GraphAdapter<Node> {
- @Override protected boolean dead(Node n) { return n.isDead(); }
- @Override protected int id(Node n) { return n._nid; }
- @Override protected int nIns(Node n) { return n.nIns(); }
- @Override protected Node in(Node n, int idx) { return n.in(idx); }
- @Override protected int nOuts(Node n) { return n.nOuts(); }
- @Override protected Node out(Node n, int idx) { return n.out(idx); }
- private ArrayList<Edge> edges(Node n) {
- var edges = new ArrayList<Edge>();
- String[] names = n instanceof ScopeNode scope && n.nIns() != 0 ? scope.reverseNames() : null;
- for( int i = 0; i < n.nIns(); i++ ) {
- String name = names == null || i >= names.length ? null : names[i];
- edges.add(new Edge(i, ref(n.in(i)), role(n, i), name));
- }
- return edges;
+ @Override protected String[] edgeNames(Node n) {
+ return n instanceof ScopeNode scope && n.nIns()!=0 ? scope.reverseNames() : null;
}
+ @Override protected int projectionIndex(Node n) { return n instanceof ProjNode p ? p._idx : -1; }
- @Override protected GraphSnapshot.Node desc(Node n) {
- Projection proj = n instanceof ProjNode p ? new Projection(ref(n.in(0)), p._idx) : null;
- String label = n.label();
- return new GraphSnapshot.Node(n._nid, label == null ? n.getClass().getSimpleName() : label,
- n._type == null ? null : n._type.toString(), kind(n), edges(n), proj);
- }
-
- private Kind kind(Node n) {
+ @Override protected Kind kind(Node n) {
if( n instanceof StopNode ) return Kind.STOP;
if( n instanceof ScopeNode ) return Kind.SCOPE;
if( n instanceof StartNode ) return Kind.CTRL;
@@ -42,7 +22,7 @@ public class SimpleGraphAdapter extends GraphAdapter<Node> {
return n.isCFG() ? Kind.CTRL : Kind.DATA;
}
- private Role role(Node n, int i) {
+ @Override protected Role role(Node n, int i) {
if( n instanceof ScopeNode || n instanceof ConstantNode ) return Role.ASSOC;
if( n instanceof PhiNode ) return i == 0 ? Role.ASSOC : Role.DATA;
if( n instanceof ProjNode ) return n.isCFG() ? Role.CTRL : Role.DATA;
diff --git a/chapter05/src/test/java/com/seaofnodes/simple/Chapter05Test.java b/chapter05/src/test/java/com/seaofnodes/simple/Chapter05Test.java
index 674e2ba9..d6c91a4a 100644
--- a/chapter05/src/test/java/com/seaofnodes/simple/Chapter05Test.java
+++ b/chapter05/src/test/java/com/seaofnodes/simple/Chapter05Test.java
@@ -78,7 +78,7 @@ else
a=b+1;
return a+b;""");
StopNode ret = parser.parse();
- assertEquals("return ((Phi(Region31,(arg*2),arg)+arg)+Phi(Region31,4,5));", ret.toString());
+ assertEquals("return ((Phi(Region31,(arg*2),arg)+arg)+Phi(Region,4,5));", ret.toString());
}
@Test
diff --git a/chapter06/Makefile b/chapter06/Makefile
index 8c2d5797..9afabcaf 100644
--- a/chapter06/Makefile
+++ b/chapter06/Makefile
@@ -37,6 +37,7 @@ main_javas := $(wildcard $(SRC)/$(SIMPLE)/*java $(SRC)/$(SIMPLE)/*/*java)
test_javas := $(wildcard $(TST)/$(SIMPLE)/*java $(TST)/$(SIMPLE)/*/*java)
main_classes := $(patsubst $(SRC)/%java,$(CLZDIR)/main/%class,$(main_javas))
include $(firstword $(wildcard ../graph/graph.mk graph/graph.mk))
+include $(firstword $(wildcard ../print/print.mk print/print.mk))
test_classes := $(patsubst $(TST)/%java,$(CLZDIR)/test/%class,$(test_javas))
test_cp := $(patsubst $(TST)/$(SIMPLE)/%.java,com.seaofnodes.simple.%,$(test_javas))
classes = $(main_classes) $(test_classes)
@@ -54,7 +55,7 @@ endif
default: $(default_targets)
# Compile just the out-of-date files
-$(main_classes): build/classes/main/%class: $(SRC)/%java $(graph_javas)
+$(main_classes): build/classes/main/%class: $(SRC)/%java $(graph_javas) $(print_javas)
@echo "compiling " $@ " because " $?
@[ -d $(CLZDIR)/main ] || mkdir -p $(CLZDIR)/main
@javac $(JAVAC_ARGS) -cp "$(CLZDIR)/main$(SEP)$(jars)" -sourcepath $(SRC) -d $(CLZDIR)/main $(main_javas)
diff --git a/chapter06/pom.xml b/chapter06/pom.xml
index fa76937e..b0013006 100644
--- a/chapter06/pom.xml
+++ b/chapter06/pom.xml
@@ -13,5 +13,6 @@
<name>Chapter 6</name>
<properties>
<simple.graph.directory>${project.basedir}/../graph</simple.graph.directory>
+ <simple.print.directory>${project.basedir}/../print</simple.print.directory>
</properties>
</project>
diff --git a/chapter06/src/main/java/com/seaofnodes/simple/node/AddNode.java b/chapter06/src/main/java/com/seaofnodes/simple/node/AddNode.java
index 72dc0ffd..22c36746 100644
--- a/chapter06/src/main/java/com/seaofnodes/simple/node/AddNode.java
+++ b/chapter06/src/main/java/com/seaofnodes/simple/node/AddNode.java
@@ -1,5 +1,6 @@
package com.seaofnodes.simple.node;
+
import com.seaofnodes.simple.type.*;
public class AddNode extends Node {
@@ -7,12 +8,7 @@ public class AddNode extends Node {
@Override public String label() { return "Add"; }
- @Override
- StringBuilder _print1(StringBuilder sb) {
- in(1)._print0(sb.append("("));
- in(2)._print0(sb.append("+"));
- return sb.append(")");
- }
+ @Override protected String format() { return "(%1+%2)"; }
@Override
diff --git a/chapter06/src/main/java/com/seaofnodes/simple/node/BoolNode.java b/chapter06/src/main/java/com/seaofnodes/simple/node/BoolNode.java
index ab1b474c..3a5e1a8f 100644
--- a/chapter06/src/main/java/com/seaofnodes/simple/node/BoolNode.java
+++ b/chapter06/src/main/java/com/seaofnodes/simple/node/BoolNode.java
@@ -1,5 +1,7 @@
package com.seaofnodes.simple.node;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeInteger;
@@ -14,11 +16,8 @@ abstract public class BoolNode extends Node {
@Override
public String label() { return getClass().getSimpleName(); }
- @Override
- StringBuilder _print1(StringBuilder sb) {
- in(1)._print0(sb.append("("));
- in(2)._print0(sb.append(op()));
- 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/chapter06/src/main/java/com/seaofnodes/simple/node/ConstantNode.java b/chapter06/src/main/java/com/seaofnodes/simple/node/ConstantNode.java
index 85277d82..5efe29b7 100644
--- a/chapter06/src/main/java/com/seaofnodes/simple/node/ConstantNode.java
+++ b/chapter06/src/main/java/com/seaofnodes/simple/node/ConstantNode.java
@@ -1,5 +1,7 @@
package com.seaofnodes.simple.node;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.Parser;
import com.seaofnodes.simple.type.Type;
@@ -22,15 +24,16 @@ public class ConstantNode extends Node {
_con = type;
}
- @Override
- public String label() { return ""+_con; }
+ @Override protected String repeatName() {
+ return _con==null || _con.toString().length()<=32 ? null : uniqueName();
+ }
@Override
- public String uniqueName() { return "Con_" + _nid; }
+ public String label() { return "Con"; }
- @Override
- StringBuilder _print1(StringBuilder sb) {
- return _con.print(sb);
+
+ @Override protected ExprPrinter<Node> _print1(ExprPrinter<Node> p) {
+ return p.p(_con);
}
@Override
diff --git a/chapter06/src/main/java/com/seaofnodes/simple/node/DivNode.java b/chapter06/src/main/java/com/seaofnodes/simple/node/DivNode.java
index f80f092d..f6b4e03e 100644
--- a/chapter06/src/main/java/com/seaofnodes/simple/node/DivNode.java
+++ b/chapter06/src/main/java/com/seaofnodes/simple/node/DivNode.java
@@ -1,5 +1,6 @@
package com.seaofnodes.simple.node;
+
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeInteger;
@@ -8,12 +9,7 @@ public class DivNode extends Node {
@Override public String label() { return "Div"; }
- @Override
- StringBuilder _print1(StringBuilder sb) {
- in(1)._print0(sb.append("("));
- in(2)._print0(sb.append("/"));
- return sb.append(")");
- }
+ @Override protected String format() { return "(%1/%2)"; }
@Override
public Type compute() {
diff --git a/chapter06/src/main/java/com/seaofnodes/simple/node/IfNode.java b/chapter06/src/main/java/com/seaofnodes/simple/node/IfNode.java
index 34846e99..05c1c844 100644
--- a/chapter06/src/main/java/com/seaofnodes/simple/node/IfNode.java
+++ b/chapter06/src/main/java/com/seaofnodes/simple/node/IfNode.java
@@ -1,5 +1,6 @@
package com.seaofnodes.simple.node;
+
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeInteger;
import com.seaofnodes.simple.type.TypeTuple;
@@ -13,11 +14,7 @@ public class IfNode extends MultiNode {
@Override
public String label() { return "If"; }
- @Override
- StringBuilder _print1(StringBuilder sb) {
- sb.append("if( ");
- return in(1)._print0(sb).append(" )");
- }
+ @Override protected String format() { return "if( %1 )"; }
@Override public boolean isCFG() { return true; }
diff --git a/chapter06/src/main/java/com/seaofnodes/simple/node/MinusNode.java b/chapter06/src/main/java/com/seaofnodes/simple/node/MinusNode.java
index ad6e513a..bb5f155d 100644
--- a/chapter06/src/main/java/com/seaofnodes/simple/node/MinusNode.java
+++ b/chapter06/src/main/java/com/seaofnodes/simple/node/MinusNode.java
@@ -1,5 +1,6 @@
package com.seaofnodes.simple.node;
+
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeInteger;
@@ -8,11 +9,7 @@ public class MinusNode extends Node {
@Override public String label() { return "Minus"; }
- @Override
- StringBuilder _print1(StringBuilder sb) {
- in(1)._print0(sb.append("(-"));
- return sb.append(")");
- }
+ @Override protected String format() { return "(-%1)"; }
@Override
public Type compute() {
diff --git a/chapter06/src/main/java/com/seaofnodes/simple/node/MulNode.java b/chapter06/src/main/java/com/seaofnodes/simple/node/MulNode.java
index 380cb042..d7c65b26 100644
--- a/chapter06/src/main/java/com/seaofnodes/simple/node/MulNode.java
+++ b/chapter06/src/main/java/com/seaofnodes/simple/node/MulNode.java
@@ -1,5 +1,6 @@
package com.seaofnodes.simple.node;
+
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeInteger;
@@ -8,12 +9,7 @@ public class MulNode extends Node {
@Override public String label() { return "Mul"; }
- @Override
- StringBuilder _print1(StringBuilder sb) {
- in(1)._print0(sb.append("("));
- in(2)._print0(sb.append("*"));
- return sb.append(")");
- }
+ @Override protected String format() { return "(%1*%2)"; }
@Override
public Type compute() {
diff --git a/chapter06/src/main/java/com/seaofnodes/simple/node/Node.java b/chapter06/src/main/java/com/seaofnodes/simple/node/Node.java
index 6f9ee258..23f15ebe 100644
--- a/chapter06/src/main/java/com/seaofnodes/simple/node/Node.java
+++ b/chapter06/src/main/java/com/seaofnodes/simple/node/Node.java
@@ -1,5 +1,7 @@
package com.seaofnodes.simple.node;
+import com.seaofnodes.print.BaseNode;
+
import com.seaofnodes.simple.Parser;
import com.seaofnodes.simple.Utils;
@@ -12,14 +14,7 @@ import java.util.*;
* The Node class provides common functionality used by all subtypes.
* Subtypes of Node specialize by overriding methods.
*/
-public abstract class Node {
-
- /**
- * 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 final int _nid;
+public abstract class Node extends BaseNode<Node> {
/**
* Inputs to the node. These are use-def references to Nodes.
@@ -41,14 +36,12 @@ public abstract class Node {
*/
public final ArrayList<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;
-
/**
* Immediate dominator tree depth, used to approximate a real IDOM during
* parsing where we do not have the whole program, and also peepholes
@@ -66,7 +59,7 @@ public abstract class Node {
private static int UNIQUE_ID = 1;
protected Node(Node... inputs) {
- _nid = UNIQUE_ID++; // allocate unique dense ID
+ super(UNIQUE_ID++); // allocate unique dense ID
_inputs = new ArrayList<>();
Collections.addAll(_inputs,inputs);
_outputs = new ArrayList<>();
@@ -78,36 +71,7 @@ public abstract class Node {
// Easy reading label for debugger, e.g. "Add" or "Region" or "EQ"
public abstract String label();
- // Unique label for debugging, e.g. "Add12" or "Region30" or "EQ99"
- public String uniqueName() { return label() + _nid; }
-
- // ------------------------------------------------------------------------
-
- // 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. This version will fail on cycles, which we will
- // correct later when we can parse programs with loops. We print with a
- // tik-tok style; the common _print0 calls the per-Node _print1, which
- // calls back to _print0;
- public final String print() {
- return _print0(new StringBuilder()).toString();
- }
- // This is the common print: check for DEAD and print "DEAD" else call the
- // per-Node print1.
- final StringBuilder _print0(StringBuilder sb) {
- return isDead()
- ? sb.append(uniqueName()).append(":DEAD")
- : _print1(sb);
- }
- // Every Node implements this.
- abstract StringBuilder _print1(StringBuilder sb);
-
+ @Override public String typeName() { return _type==null ? null : _type.toString(); }
/**
* Gets the ith input node
@@ -124,8 +88,6 @@ public abstract class Node {
public boolean isUnused() { return nOuts() == 0; }
- public boolean isCFG() { return false; }
-
/**
* Change a <em>def</em> into a Node. Keeps the edges correct, by removing
* the corresponding <em>use->def</em> edge. This may make the original
@@ -357,7 +319,6 @@ public abstract class Node {
*/
public abstract Node idealize();
-
// ------------------------------------------------------------------------
// Peephole utilities
@@ -401,7 +362,6 @@ public abstract class Node {
return _idepth = (char)depth;
}
-
// 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/chapter06/src/main/java/com/seaofnodes/simple/node/NotNode.java b/chapter06/src/main/java/com/seaofnodes/simple/node/NotNode.java
index 6a56ff64..a9781ce1 100644
--- a/chapter06/src/main/java/com/seaofnodes/simple/node/NotNode.java
+++ b/chapter06/src/main/java/com/seaofnodes/simple/node/NotNode.java
@@ -1,5 +1,6 @@
package com.seaofnodes.simple.node;
+
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeInteger;
@@ -8,11 +9,7 @@ public class NotNode extends Node {
@Override public String label() { return "Not"; }
- @Override
- StringBuilder _print1(StringBuilder sb) {
- in(1)._print0(sb.append("(!"));
- return sb.append(")");
- }
+ @Override protected String format() { return "(!%1)"; }
@Override
public Type compute() {
diff --git a/chapter06/src/main/java/com/seaofnodes/simple/node/PhiNode.java b/chapter06/src/main/java/com/seaofnodes/simple/node/PhiNode.java
index f7cf917e..6acb5535 100644
--- a/chapter06/src/main/java/com/seaofnodes/simple/node/PhiNode.java
+++ b/chapter06/src/main/java/com/seaofnodes/simple/node/PhiNode.java
@@ -1,5 +1,7 @@
package com.seaofnodes.simple.node;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.type.Type;
public class PhiNode extends Node {
@@ -11,13 +13,11 @@ public class PhiNode extends Node {
@Override public String label() { return "Phi_"+_label; }
@Override
- StringBuilder _print1(StringBuilder sb) {
- sb.append("Phi(");
+ protected ExprPrinter<Node> _print1(ExprPrinter<Node> p) {
+ p.p("Phi(");
for( Node in : _inputs )
- in._print0(sb).append(",");
- sb.setLength(sb.length()-1);
- sb.append(")");
- return sb;
+ p.n(in).p(",");
+ return p.unchar(',').close();
}
Node region() { return in(0); }
diff --git a/chapter06/src/main/java/com/seaofnodes/simple/node/ProjNode.java b/chapter06/src/main/java/com/seaofnodes/simple/node/ProjNode.java
index 85f28037..e313d31b 100644
--- a/chapter06/src/main/java/com/seaofnodes/simple/node/ProjNode.java
+++ b/chapter06/src/main/java/com/seaofnodes/simple/node/ProjNode.java
@@ -1,5 +1,7 @@
package com.seaofnodes.simple.node;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeTuple;
@@ -21,7 +23,7 @@ public class ProjNode extends Node {
public String label() { return _label; }
@Override
- StringBuilder _print1(StringBuilder sb) { return sb.append(_label); }
+ protected ExprPrinter<Node> _print1(ExprPrinter<Node> p) { return p.p(_label); }
@Override public boolean isCFG() { return _idx==0 || ctrl() instanceof IfNode; }
diff --git a/chapter06/src/main/java/com/seaofnodes/simple/node/RegionNode.java b/chapter06/src/main/java/com/seaofnodes/simple/node/RegionNode.java
index 9b51a277..cbd51743 100644
--- a/chapter06/src/main/java/com/seaofnodes/simple/node/RegionNode.java
+++ b/chapter06/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.Utils;
import com.seaofnodes.simple.type.Type;
@@ -9,9 +11,8 @@ public class RegionNode extends Node {
@Override
public String label() { return "Region"; }
- @Override
- StringBuilder _print1(StringBuilder sb) {
- return sb.append(label()).append(_nid);
+ @Override protected ExprPrinter<Node> _print1(ExprPrinter<Node> p) {
+ return p.p(label()).p(_nid);
}
@Override public boolean isCFG() { return true; }
diff --git a/chapter06/src/main/java/com/seaofnodes/simple/node/ReturnNode.java b/chapter06/src/main/java/com/seaofnodes/simple/node/ReturnNode.java
index 6130d050..b8bc8859 100644
--- a/chapter06/src/main/java/com/seaofnodes/simple/node/ReturnNode.java
+++ b/chapter06/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.type.*;
/**
@@ -24,8 +26,8 @@ public class ReturnNode extends Node {
public String label() { return "Return"; }
@Override
- StringBuilder _print1(StringBuilder sb) {
- return expr()._print0(sb.append("return ")).append(";");
+ protected ExprPrinter<Node> _print1(ExprPrinter<Node> p) {
+ return p.p("return ").n(expr()).p(";");
}
@Override public boolean isCFG() { return true; }
diff --git a/chapter06/src/main/java/com/seaofnodes/simple/node/ScopeNode.java b/chapter06/src/main/java/com/seaofnodes/simple/node/ScopeNode.java
index a7a04a42..86f4778e 100644
--- a/chapter06/src/main/java/com/seaofnodes/simple/node/ScopeNode.java
+++ b/chapter06/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.type.Type;
import java.util.*;
@@ -33,22 +35,22 @@ public class ScopeNode extends Node {
@Override public String label() { return "Scope"; }
@Override
- StringBuilder _print1(StringBuilder sb) {
- sb.append(label());
+ protected ExprPrinter<Node> _print1(ExprPrinter<Node> p) {
+ p.p(label());
for( HashMap<String,Integer> scope : _scopes ) {
- sb.append("[");
+ p.p("[");
boolean first=true;
for( String name : scope.keySet() ) {
- if( !first ) sb.append(", ");
+ if( !first ) p.p(", ");
first=false;
- sb.append(name).append(":");
+ p.p(name).p(":");
Node n = in(scope.get(name));
- if( n==null ) sb.append("null");
- else n._print0(sb);
+ if( n==null ) p.p("null");
+ else p.n(n);
}
- sb.append("]");
+ p.p("]");
}
- return sb;
+ return p;
}
/**
diff --git a/chapter06/src/main/java/com/seaofnodes/simple/node/StartNode.java b/chapter06/src/main/java/com/seaofnodes/simple/node/StartNode.java
index 6b98aed7..199845fe 100644
--- a/chapter06/src/main/java/com/seaofnodes/simple/node/StartNode.java
+++ b/chapter06/src/main/java/com/seaofnodes/simple/node/StartNode.java
@@ -1,5 +1,7 @@
package com.seaofnodes.simple.node;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeTuple;
@@ -23,9 +25,8 @@ public class StartNode extends MultiNode {
@Override
public String label() { return "Start"; }
- @Override
- StringBuilder _print1(StringBuilder sb) {
- return sb.append(label());
+ @Override protected ExprPrinter<Node> _print1(ExprPrinter<Node> p) {
+ return p.p(label());
}
@Override public boolean isCFG() { return true; }
diff --git a/chapter06/src/main/java/com/seaofnodes/simple/node/StopNode.java b/chapter06/src/main/java/com/seaofnodes/simple/node/StopNode.java
index 01574dc7..fe10b1ce 100644
--- a/chapter06/src/main/java/com/seaofnodes/simple/node/StopNode.java
+++ b/chapter06/src/main/java/com/seaofnodes/simple/node/StopNode.java
@@ -1,5 +1,7 @@
package com.seaofnodes.simple.node;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.type.Type;
public class StopNode extends Node {
@@ -13,12 +15,12 @@ public class StopNode extends Node {
}
@Override
- StringBuilder _print1(StringBuilder sb) {
- if( ret()!=null ) return ret()._print0(sb);
- sb.append("Stop[ ");
+ protected ExprPrinter<Node> _print1(ExprPrinter<Node> p) {
+ if( ret()!=null ) return p.n(ret());
+ p.p("Stop[ ");
for( Node ret : _inputs )
- ret._print0(sb).append(" ");
- return sb.append("]");
+ p.n(ret).p(" ");
+ return p.p("]");
}
@Override public boolean isCFG() { return true; }
diff --git a/chapter06/src/main/java/com/seaofnodes/simple/node/SubNode.java b/chapter06/src/main/java/com/seaofnodes/simple/node/SubNode.java
index bd43bc6c..7a6e1a4b 100644
--- a/chapter06/src/main/java/com/seaofnodes/simple/node/SubNode.java
+++ b/chapter06/src/main/java/com/seaofnodes/simple/node/SubNode.java
@@ -1,5 +1,6 @@
package com.seaofnodes.simple.node;
+
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeInteger;
@@ -8,12 +9,7 @@ public class SubNode extends Node {
@Override public String label() { return "Sub"; }
- @Override
- StringBuilder _print1(StringBuilder sb) {
- in(1)._print0(sb.append("("));
- in(2)._print0(sb.append("-"));
- return sb.append(")");
- }
+ @Override protected String format() { return "(%1-%2)"; }
@Override
public Type compute() {
diff --git a/chapter06/src/main/java/com/seaofnodes/simple/print/SimpleGraphAdapter.java b/chapter06/src/main/java/com/seaofnodes/simple/print/SimpleGraphAdapter.java
index 84ef99f2..24614ad4 100644
--- a/chapter06/src/main/java/com/seaofnodes/simple/print/SimpleGraphAdapter.java
+++ b/chapter06/src/main/java/com/seaofnodes/simple/print/SimpleGraphAdapter.java
@@ -1,39 +1,19 @@
package com.seaofnodes.simple.print;
import com.seaofnodes.graph.GraphAdapter;
-import com.seaofnodes.graph.GraphSnapshot;
import com.seaofnodes.graph.GraphSnapshot.*;
import com.seaofnodes.simple.node.*;
import com.seaofnodes.simple.node.Node;
-import java.util.ArrayList;
/** Chapter 6's view of the IR; browser, transport and layout are shared. */
public class SimpleGraphAdapter extends GraphAdapter<Node> {
- @Override protected boolean dead(Node n) { return n.isDead(); }
- @Override protected int id(Node n) { return n._nid; }
- @Override protected int nIns(Node n) { return n.nIns(); }
- @Override protected Node in(Node n, int idx) { return n.in(idx); }
- @Override protected int nOuts(Node n) { return n.nOuts(); }
- @Override protected Node out(Node n, int idx) { return n.out(idx); }
- private ArrayList<Edge> edges(Node n) {
- var edges = new ArrayList<Edge>();
- String[] names = n instanceof ScopeNode scope && n.nIns() != 0 ? scope.reverseNames() : null;
- for( int i = 0; i < n.nIns(); i++ ) {
- String name = names == null || i >= names.length ? null : names[i];
- edges.add(new Edge(i, ref(n.in(i)), role(n, i), name));
- }
- return edges;
+ @Override protected String[] edgeNames(Node n) {
+ return n instanceof ScopeNode scope && n.nIns()!=0 ? scope.reverseNames() : null;
}
+ @Override protected int projectionIndex(Node n) { return n instanceof ProjNode p ? p._idx : -1; }
- @Override protected GraphSnapshot.Node desc(Node n) {
- Projection proj = n instanceof ProjNode p ? new Projection(ref(n.in(0)), p._idx) : null;
- String label = n.label();
- return new GraphSnapshot.Node(n._nid, label == null ? n.getClass().getSimpleName() : label,
- n._type == null ? null : n._type.toString(), kind(n), edges(n), proj);
- }
-
- private Kind kind(Node n) {
+ @Override protected Kind kind(Node n) {
if( n instanceof StopNode ) return Kind.STOP;
if( n instanceof ScopeNode ) return Kind.SCOPE;
if( n instanceof StartNode ) return Kind.CTRL;
@@ -42,7 +22,7 @@ public class SimpleGraphAdapter extends GraphAdapter<Node> {
return n.isCFG() ? Kind.CTRL : Kind.DATA;
}
- private Role role(Node n, int i) {
+ @Override protected Role role(Node n, int i) {
if( n instanceof ScopeNode || n instanceof ConstantNode ) return Role.ASSOC;
if( n instanceof PhiNode ) return i == 0 ? Role.ASSOC : Role.DATA;
if( n instanceof ProjNode ) return n.isCFG() ? Role.CTRL : Role.DATA;
diff --git a/chapter06/src/test/java/com/seaofnodes/simple/Chapter05Test.java b/chapter06/src/test/java/com/seaofnodes/simple/Chapter05Test.java
index 674e2ba9..d6c91a4a 100644
--- a/chapter06/src/test/java/com/seaofnodes/simple/Chapter05Test.java
+++ b/chapter06/src/test/java/com/seaofnodes/simple/Chapter05Test.java
@@ -78,7 +78,7 @@ else
a=b+1;
return a+b;""");
StopNode ret = parser.parse();
- assertEquals("return ((Phi(Region31,(arg*2),arg)+arg)+Phi(Region31,4,5));", ret.toString());
+ assertEquals("return ((Phi(Region31,(arg*2),arg)+arg)+Phi(Region,4,5));", ret.toString());
}
@Test
diff --git a/chapter06/src/test/java/com/seaofnodes/simple/Chapter06Test.java b/chapter06/src/test/java/com/seaofnodes/simple/Chapter06Test.java
index cb58f2bb..00d725bc 100644
--- a/chapter06/src/test/java/com/seaofnodes/simple/Chapter06Test.java
+++ b/chapter06/src/test/java/com/seaofnodes/simple/Chapter06Test.java
@@ -251,7 +251,7 @@ if( arg ) {
return a+b+c;
""");
StopNode ret = parser.parse();
- assertEquals("return (Phi(Region33,Phi(Region22,2,3),0)+Phi(Region33,3,1));", ret.toString());
+ assertEquals("return (Phi(Region33,Phi(Region22,2,3),0)+Phi(Region,3,1));", ret.toString());
}
diff --git a/chapter07/Makefile b/chapter07/Makefile
index 8c2d5797..9afabcaf 100644
--- a/chapter07/Makefile
+++ b/chapter07/Makefile
@@ -37,6 +37,7 @@ main_javas := $(wildcard $(SRC)/$(SIMPLE)/*java $(SRC)/$(SIMPLE)/*/*java)
test_javas := $(wildcard $(TST)/$(SIMPLE)/*java $(TST)/$(SIMPLE)/*/*java)
main_classes := $(patsubst $(SRC)/%java,$(CLZDIR)/main/%class,$(main_javas))
include $(firstword $(wildcard ../graph/graph.mk graph/graph.mk))
+include $(firstword $(wildcard ../print/print.mk print/print.mk))
test_classes := $(patsubst $(TST)/%java,$(CLZDIR)/test/%class,$(test_javas))
test_cp := $(patsubst $(TST)/$(SIMPLE)/%.java,com.seaofnodes.simple.%,$(test_javas))
classes = $(main_classes) $(test_classes)
@@ -54,7 +55,7 @@ endif
default: $(default_targets)
# Compile just the out-of-date files
-$(main_classes): build/classes/main/%class: $(SRC)/%java $(graph_javas)
+$(main_classes): build/classes/main/%class: $(SRC)/%java $(graph_javas) $(print_javas)
@echo "compiling " $@ " because " $?
@[ -d $(CLZDIR)/main ] || mkdir -p $(CLZDIR)/main
@javac $(JAVAC_ARGS) -cp "$(CLZDIR)/main$(SEP)$(jars)" -sourcepath $(SRC) -d $(CLZDIR)/main $(main_javas)
diff --git a/chapter07/pom.xml b/chapter07/pom.xml
index 947fdf4b..c60357d5 100644
--- a/chapter07/pom.xml
+++ b/chapter07/pom.xml
@@ -13,5 +13,6 @@
<name>Chapter 7</name>
<properties>
<simple.graph.directory>${project.basedir}/../graph</simple.graph.directory>
+ <simple.print.directory>${project.basedir}/../print</simple.print.directory>
</properties>
</project>
diff --git a/chapter07/src/main/java/com/seaofnodes/simple/IRPrinter.java b/chapter07/src/main/java/com/seaofnodes/simple/IRPrinter.java
deleted file mode 100644
index 2a6dbefd..00000000
--- a/chapter07/src/main/java/com/seaofnodes/simple/IRPrinter.java
+++ /dev/null
@@ -1,124 +0,0 @@
-package com.seaofnodes.simple;
-
-import com.seaofnodes.simple.node.LoopNode;
-import com.seaofnodes.simple.node.Node;
-
-import java.util.ArrayList;
-import java.util.BitSet;
-
-public class IRPrinter {
-
- // Another bulk pretty-printer. Makes more effort at basic-block grouping.
- public static String prettyPrint(Node node, int depth) {
- // First, a Breadth First Search at a fixed depth.
- BFS bfs = new BFS(node,depth);
- // Convert just that set to a post-order
- ArrayList<Node> rpos = new ArrayList<>();
- BitSet visit = new BitSet();
- for( int i=bfs._lim; i< bfs._bfs.size(); i++ )
- postOrd( bfs._bfs.get(i), rpos, visit, bfs._bs);
- // Reverse the post-order walk
- StringBuilder sb = new StringBuilder();
- boolean gap=false;
- for( int i=rpos.size()-1; i>=0; i-- ) {
- Node n = rpos.get(i);
- if( n.isCFG() || n.isMultiHead() ) {
- if( !gap ) sb.append("\n"); // Blank before multihead
- n._printLine(sb); // Print head
- while( --i >= 0 ) {
- Node t = rpos.get(i);
- if( !t.isMultiTail() ) { i++; break; }
- t._printLine(sb);
- }
- sb.append("\n"); // Blank after multitail
- gap = true;
- } else {
- n._printLine( sb );
- gap = false;
- }
- }
- return sb.toString();
- }
-
- private static void postOrd(Node n, ArrayList<Node> rpos, BitSet visit, BitSet bfs) {
- if( !bfs.get(n._nid) )
- return; // Not in the BFS visit
- if( visit.get(n._nid) ) return; // Already post-order walked
- visit.set(n._nid);
- // First walk the CFG, then everything
- if( n.isCFG() ) {
- for( Node use : n._outputs )
- if( use.isCFG() && use.nOuts()>=1 && !(use._outputs.get(0) instanceof LoopNode) )
- postOrd(use, rpos,visit,bfs);
- for( Node use : n._outputs )
- if( use.isCFG() )
- postOrd(use,rpos,visit,bfs);
- }
- for( Node use : n._outputs )
- postOrd(use, rpos,visit,bfs);
- // Post-order
- rpos.add(n);
- }
-
- // Breadth-first search, broken out in a class to keep in more independent.
- // Maintains a root-set of Nodes at the limit (or past by 1 if MultiHead).
- public static class BFS {
- // A breadth first search, plus MultiHeads for any MultiTails
- public final ArrayList<Node> _bfs;
- public final BitSet _bs; // Visited members by node id
- public final int _depth; // Depth limit
- public final int _lim; // From here to _bfs._len can be roots for a reverse search
- public BFS( Node base, int d ) {
- _depth = d;
- _bfs = new ArrayList<>();
- _bs = new BitSet();
-
- add(base); // Prime the pump
- int idx=0, lim=1; // Limit is where depth counter changes
- while( idx < _bfs.size() ) { // Ran out of nodes below depth
- Node n = _bfs.get(idx++);
- for( Node def : n._inputs )
- if( def!=null && !_bs.get(def._nid) )
- add(def);
- if( idx==lim ) { // Depth counter changes at limit
- if( --d < 0 )
- break; // Ran out of depth
- lim = _bfs.size(); // New depth limit
- }
- }
- // Toss things past the limit except multi-heads
- while( idx < _bfs.size() ) {
- Node n = _bfs.get(idx);
- if( n.isMultiHead() ) idx++;
- else del(idx);
- }
- // Root set is any node with no inputs in the visited set
- lim = _bfs.size();
- for( int i=_bfs.size()-1; i>=0; i-- )
- if( !any_visited(_bfs.get(i)) )
- swap( i,--lim);
- _lim = lim;
- }
- void swap( int x, int y ) {
- if( x==y ) return;
- Node tx = _bfs.get(x);
- Node ty = _bfs.get(y);
- _bfs.set(x,ty);
- _bfs.set(y,tx);
- }
- void add(Node n) {
- _bfs.add(n);
- _bs.set(n._nid);
- }
- void del(int idx) {
- Node n = Utils.del(_bfs, idx);
- _bs.clear(n._nid);
- }
- boolean any_visited( Node n ) {
- for( Node def : n._inputs )
- if( def!=null && _bs.get(def._nid) )
- return true;
- return false;
- }
- }
-}
diff --git a/chapter07/src/main/java/com/seaofnodes/simple/node/AddNode.java b/chapter07/src/main/java/com/seaofnodes/simple/node/AddNode.java
index 84367cc7..5ee742f7 100644
--- a/chapter07/src/main/java/com/seaofnodes/simple/node/AddNode.java
+++ b/chapter07/src/main/java/com/seaofnodes/simple/node/AddNode.java
@@ -1,20 +1,15 @@
package com.seaofnodes.simple.node;
+
import com.seaofnodes.simple.type.*;
-import java.util.BitSet;
public class AddNode extends Node {
public AddNode(Node lhs, Node rhs) { super(null, lhs, rhs); }
@Override public String label() { return "Add"; }
- @Override
- StringBuilder _print1(StringBuilder sb, BitSet visited) {
- in(1)._print0(sb.append("("), visited);
- in(2)._print0(sb.append("+"), visited);
- return sb.append(")");
- }
+ @Override protected String format() { return "(%1+%2)"; }
@Override
diff --git a/chapter07/src/main/java/com/seaofnodes/simple/node/BoolNode.java b/chapter07/src/main/java/com/seaofnodes/simple/node/BoolNode.java
index f5bbc9ad..e363bf75 100644
--- a/chapter07/src/main/java/com/seaofnodes/simple/node/BoolNode.java
+++ b/chapter07/src/main/java/com/seaofnodes/simple/node/BoolNode.java
@@ -1,9 +1,10 @@
package com.seaofnodes.simple.node;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeInteger;
-import java.util.BitSet;
abstract public class BoolNode extends Node {
@@ -16,11 +17,8 @@ abstract public class BoolNode extends Node {
@Override
public String label() { return getClass().getSimpleName(); }
- @Override
- 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/chapter07/src/main/java/com/seaofnodes/simple/node/ConstantNode.java b/chapter07/src/main/java/com/seaofnodes/simple/node/ConstantNode.java
index b7ec8292..19166ec6 100644
--- a/chapter07/src/main/java/com/seaofnodes/simple/node/ConstantNode.java
+++ b/chapter07/src/main/java/com/seaofnodes/simple/node/ConstantNode.java
@@ -1,9 +1,10 @@
package com.seaofnodes.simple.node;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.Parser;
import com.seaofnodes.simple.type.Type;
-import java.util.BitSet;
/**
* A Constant node represents a constant value. At present, the only constants
@@ -24,15 +25,16 @@ public class ConstantNode extends Node {
_con = type;
}
- @Override
- public String label() { return ""+_con; }
+ @Override protected String repeatName() {
+ return _con==null || _con.toString().length()<=32 ? null : uniqueName();
+ }
@Override
- public String uniqueName() { return "Con_" + _nid; }
+ public String label() { return "Con"; }
- @Override
- StringBuilder _print1(StringBuilder sb, BitSet visited) {
- return _con.print(sb);
+
+ @Override protected ExprPrinter<Node> _print1(ExprPrinter<Node> p) {
+ return p.p(_con);
}
@Override public boolean isMultiTail() { return true; }
diff --git a/chapter07/src/main/java/com/seaofnodes/simple/node/DivNode.java b/chapter07/src/main/java/com/seaofnodes/simple/node/DivNode.java
index f71a32db..4c3c2feb 100644
--- a/chapter07/src/main/java/com/seaofnodes/simple/node/DivNode.java
+++ b/chapter07/src/main/java/com/seaofnodes/simple/node/DivNode.java
@@ -1,21 +1,16 @@
package com.seaofnodes.simple.node;
+
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeInteger;
-import java.util.BitSet;
public class DivNode extends Node {
public DivNode(Node lhs, Node rhs) { super(null, lhs, rhs); }
@Override public String label() { return "Div"; }
- @Override
- StringBuilder _print1(StringBuilder sb, BitSet visited) {
- in(1)._print0(sb.append("("), visited);
- in(2)._print0(sb.append("/"), visited);
- return sb.append(")");
- }
+ @Override protected String format() { return "(%1/%2)"; }
@Override
public Type compute() {
diff --git a/chapter07/src/main/java/com/seaofnodes/simple/node/IfNode.java b/chapter07/src/main/java/com/seaofnodes/simple/node/IfNode.java
index 0f414c08..52d7e31e 100644
--- a/chapter07/src/main/java/com/seaofnodes/simple/node/IfNode.java
+++ b/chapter07/src/main/java/com/seaofnodes/simple/node/IfNode.java
@@ -1,10 +1,10 @@
package com.seaofnodes.simple.node;
+
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeInteger;
import com.seaofnodes.simple.type.TypeTuple;
-import java.util.BitSet;
public class IfNode extends MultiNode {
@@ -15,11 +15,7 @@ public class IfNode extends MultiNode {
@Override
public String label() { return "If"; }
- @Override
- StringBuilder _print1(StringBuilder sb, BitSet visited) {
- sb.append("if( ");
- return in(1)._print0(sb, visited).append(" )");
- }
+ @Override protected String format() { return "if( %1 )"; }
@Override public boolean isCFG() { return true; }
@Override public boolean isMultiHead() { return true; }
diff --git a/chapter07/src/main/java/com/seaofnodes/simple/node/MinusNode.java b/chapter07/src/main/java/com/seaofnodes/simple/node/MinusNode.java
index 9d3d3f5d..fb51777e 100644
--- a/chapter07/src/main/java/com/seaofnodes/simple/node/MinusNode.java
+++ b/chapter07/src/main/java/com/seaofnodes/simple/node/MinusNode.java
@@ -1,20 +1,16 @@
package com.seaofnodes.simple.node;
+
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeInteger;
-import java.util.BitSet;
public class MinusNode extends Node {
public MinusNode(Node in) { super(null, in); }
@Override public String label() { return "Minus"; }
- @Override
- 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/chapter07/src/main/java/com/seaofnodes/simple/node/MulNode.java b/chapter07/src/main/java/com/seaofnodes/simple/node/MulNode.java
index 4884ee18..2d0fa95b 100644
--- a/chapter07/src/main/java/com/seaofnodes/simple/node/MulNode.java
+++ b/chapter07/src/main/java/com/seaofnodes/simple/node/MulNode.java
@@ -1,21 +1,16 @@
package com.seaofnodes.simple.node;
+
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeInteger;
-import java.util.BitSet;
public class MulNode extends Node {
public MulNode(Node lhs, Node rhs) { super(null, lhs, rhs); }
@Override public String label() { return "Mul"; }
- @Override
- StringBuilder _print1(StringBuilder sb, BitSet visited) {
- in(1)._print0(sb.append("("), visited);
- in(2)._print0(sb.append("*"), visited);
- return sb.append(")");
- }
+ @Override protected String format() { return "(%1*%2)"; }
@Override
public Type compute() {
diff --git a/chapter07/src/main/java/com/seaofnodes/simple/node/Node.java b/chapter07/src/main/java/com/seaofnodes/simple/node/Node.java
index 921292cb..1430cdac 100644
--- a/chapter07/src/main/java/com/seaofnodes/simple/node/Node.java
+++ b/chapter07/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.Parser;
import com.seaofnodes.simple.Utils;
@@ -12,14 +14,7 @@ import java.util.*;
* The Node class provides common functionality used by all subtypes.
* Subtypes of Node specialize by overriding methods.
*/
-public abstract class Node {
-
- /**
- * 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 final int _nid;
+public abstract class Node extends BaseNode<Node> {
/**
* Inputs to the node. These are use-def references to Nodes.
@@ -41,14 +36,12 @@ public abstract class Node {
*/
public final ArrayList<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;
-
/**
* Immediate dominator tree depth, used to approximate a real IDOM during
* parsing where we do not have the whole program, and also peepholes
@@ -66,7 +59,7 @@ public abstract class Node {
private static int UNIQUE_ID = 1;
protected Node(Node... inputs) {
- _nid = UNIQUE_ID++; // allocate unique dense ID
+ super(UNIQUE_ID++); // allocate unique dense ID
_inputs = new ArrayList<>();
Collections.addAll(_inputs,inputs);
_outputs = new ArrayList<>();
@@ -78,70 +71,14 @@ public abstract class Node {
// Easy reading label for debugger, e.g. "Add" or "Region" or "EQ"
public abstract String label();
- // Unique label for debugging, e.g. "Add12" or "Region30" or "EQ99"
- public String uniqueName() { return label() + _nid; }
-
- // ------------------------------------------------------------------------
-
- // 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. This version will fail on cycles, which we will
- // correct later when we can parse programs with loops. We print with a
- // 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.
- final StringBuilder _print0(StringBuilder sb, BitSet visited) {
- if (visited.get(_nid))
- 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 StringBuilder _print1(StringBuilder sb, BitSet visited);
-
-
- // 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 void _printLine(StringBuilder sb ) {
- sb.append("%4d %-7.7s ".formatted(_nid,label()));
- if( isDead() ) {
- sb.append("DEAD\n");
- return;
- }
- for( Node def : _inputs )
- sb.append(def==null ? "____ " : "%4d ".formatted(def._nid));
- for( int i = _inputs.size(); i<3; i++ )
- sb.append(" ");
- sb.append(" [[ ");
- for( Node use : _outputs )
- sb.append("%4d ".formatted(use._nid));
- int lim = 5 - Math.max(_inputs.size(),3);
- for( int i = _outputs.size(); i<lim; i++ )
- sb.append(" ");
- sb.append(" ]] ");
- if( _type!= null ) _type.print(sb);
- sb.append("\n");
- }
-
public boolean isMultiHead() { return false; }
public boolean isMultiTail() { return false; }
// ------------------------------------------------------------------------
// 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
@@ -157,8 +94,6 @@ public abstract class Node {
public boolean isUnused() { return nOuts() == 0; }
- public boolean isCFG() { return false; }
-
/**
* Change a <em>def</em> into a Node. Keeps the edges correct, by removing
* the corresponding <em>use->def</em> edge. This may make the original
@@ -262,7 +197,6 @@ public abstract class Node {
// Remove bogus null.
public <N extends Node> N unkeep() { delUse(null); return (N)this; }
-
// Replace self with nnn in the graph, making 'this' go dead
void subsume( Node nnn ) {
assert nnn!=this;
@@ -404,7 +338,6 @@ public abstract class Node {
*/
public abstract Node idealize();
-
// ------------------------------------------------------------------------
// Peephole utilities
@@ -448,7 +381,6 @@ public abstract class Node {
return _idepth = (char)depth;
}
-
// 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/chapter07/src/main/java/com/seaofnodes/simple/node/NotNode.java b/chapter07/src/main/java/com/seaofnodes/simple/node/NotNode.java
index 4c0be167..538016bd 100644
--- a/chapter07/src/main/java/com/seaofnodes/simple/node/NotNode.java
+++ b/chapter07/src/main/java/com/seaofnodes/simple/node/NotNode.java
@@ -1,20 +1,16 @@
package com.seaofnodes.simple.node;
+
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeInteger;
-import java.util.BitSet;
public class NotNode extends Node {
public NotNode(Node in) { super(null, in); }
@Override public String label() { return "Not"; }
- @Override
- 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/chapter07/src/main/java/com/seaofnodes/simple/node/PhiNode.java b/chapter07/src/main/java/com/seaofnodes/simple/node/PhiNode.java
index 46646773..64cd3dd7 100644
--- a/chapter07/src/main/java/com/seaofnodes/simple/node/PhiNode.java
+++ b/chapter07/src/main/java/com/seaofnodes/simple/node/PhiNode.java
@@ -1,8 +1,9 @@
package com.seaofnodes.simple.node;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.type.Type;
-import java.util.BitSet;
public class PhiNode extends Node {
@@ -13,18 +14,12 @@ public class PhiNode extends Node {
@Override public String label() { return "Phi_"+_label; }
@Override
- StringBuilder _print1(StringBuilder sb, BitSet visited) {
+ protected ExprPrinter<Node> _print1(ExprPrinter<Node> p) {
if( region().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();
}
RegionNode region() { return (RegionNode)in(0); }
diff --git a/chapter07/src/main/java/com/seaofnodes/simple/node/ProjNode.java b/chapter07/src/main/java/com/seaofnodes/simple/node/ProjNode.java
index 3c3f73b8..605c73bd 100644
--- a/chapter07/src/main/java/com/seaofnodes/simple/node/ProjNode.java
+++ b/chapter07/src/main/java/com/seaofnodes/simple/node/ProjNode.java
@@ -1,9 +1,10 @@
package com.seaofnodes.simple.node;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeTuple;
-import java.util.BitSet;
public class ProjNode extends Node {
@@ -23,7 +24,7 @@ public class ProjNode extends Node {
public String label() { return _label; }
@Override
- StringBuilder _print1(StringBuilder sb, BitSet visited) { return sb.append(_label); }
+ protected ExprPrinter<Node> _print1(ExprPrinter<Node> p) { return p.p(_label); }
@Override public boolean isCFG() { return _idx==0 || ctrl() instanceof IfNode; }
@Override public boolean isMultiTail() { return in(0).isMultiHead(); }
diff --git a/chapter07/src/main/java/com/seaofnodes/simple/node/RegionNode.java b/chapter07/src/main/java/com/seaofnodes/simple/node/RegionNode.java
index e357796b..e0dd45d7 100644
--- a/chapter07/src/main/java/com/seaofnodes/simple/node/RegionNode.java
+++ b/chapter07/src/main/java/com/seaofnodes/simple/node/RegionNode.java
@@ -1,9 +1,10 @@
package com.seaofnodes.simple.node;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.Utils;
import com.seaofnodes.simple.type.Type;
-import java.util.BitSet;
public class RegionNode extends Node {
@@ -12,9 +13,8 @@ public class RegionNode extends Node {
@Override
public String label() { return "Region"; }
- @Override
- StringBuilder _print1(StringBuilder sb, BitSet visited) {
- return sb.append(label()).append(_nid);
+ @Override protected ExprPrinter<Node> _print1(ExprPrinter<Node> p) {
+ return p.p(label()).p(_nid);
}
@Override public boolean isCFG() { return true; }
diff --git a/chapter07/src/main/java/com/seaofnodes/simple/node/ReturnNode.java b/chapter07/src/main/java/com/seaofnodes/simple/node/ReturnNode.java
index 312058b9..9f4cad7a 100644
--- a/chapter07/src/main/java/com/seaofnodes/simple/node/ReturnNode.java
+++ b/chapter07/src/main/java/com/seaofnodes/simple/node/ReturnNode.java
@@ -1,8 +1,9 @@
package com.seaofnodes.simple.node;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.type.*;
-import java.util.BitSet;
/**
* The Return node has two inputs. The first input is a control node and the
@@ -26,8 +27,8 @@ public class ReturnNode extends Node {
public String label() { return "Return"; }
@Override
- StringBuilder _print1(StringBuilder sb, BitSet visited) {
- return expr()._print0(sb.append("return "), visited).append(";");
+ protected ExprPrinter<Node> _print1(ExprPrinter<Node> p) {
+ return p.p("return ").n(expr()).p(";");
}
@Override public boolean isCFG() { return true; }
diff --git a/chapter07/src/main/java/com/seaofnodes/simple/node/ScopeNode.java b/chapter07/src/main/java/com/seaofnodes/simple/node/ScopeNode.java
index a4fcbe65..bd6b0d8c 100644
--- a/chapter07/src/main/java/com/seaofnodes/simple/node/ScopeNode.java
+++ b/chapter07/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.type.Type;
import java.util.*;
@@ -33,16 +35,15 @@ public class ScopeNode extends Node {
@Override public String label() { return "Scope"; }
@Override
- StringBuilder _print1(StringBuilder sb, BitSet visited) {
- sb.append("Scope[ ");
+ protected ExprPrinter<Node> _print1(ExprPrinter<Node> p) {
+ p.p("Scope[ ");
String[] names = reverseNames();
for( int j=0; j<nIns(); j++ ) {
- sb.append(names[j]).append(":");
+ p.p(names[j]).p(":");
Node n = in(j);
- n._print0(sb, visited).append(" ");
+ p.n(n).p(" ");
}
- sb.setLength(sb.length()-1);
- return sb.append("]");
+ return p.unchar(' ').p("]");
}
/**
diff --git a/chapter07/src/main/java/com/seaofnodes/simple/node/StartNode.java b/chapter07/src/main/java/com/seaofnodes/simple/node/StartNode.java
index bab0f18c..56689503 100644
--- a/chapter07/src/main/java/com/seaofnodes/simple/node/StartNode.java
+++ b/chapter07/src/main/java/com/seaofnodes/simple/node/StartNode.java
@@ -1,9 +1,10 @@
package com.seaofnodes.simple.node;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeTuple;
-import java.util.BitSet;
/**
* The Start node represents the start of the function. For now, we do not
@@ -25,9 +26,8 @@ public class StartNode extends MultiNode {
@Override
public String label() { return "Start"; }
- @Override
- 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 isCFG() { return true; }
diff --git a/chapter07/src/main/java/com/seaofnodes/simple/node/StopNode.java b/chapter07/src/main/java/com/seaofnodes/simple/node/StopNode.java
index 417790d9..aa655f63 100644
--- a/chapter07/src/main/java/com/seaofnodes/simple/node/StopNode.java
+++ b/chapter07/src/main/java/com/seaofnodes/simple/node/StopNode.java
@@ -1,8 +1,9 @@
package com.seaofnodes.simple.node;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.type.Type;
-import java.util.BitSet;
public class StopNode extends Node {
public StopNode(Node... inputs) {
@@ -15,12 +16,12 @@ public class StopNode extends Node {
}
@Override
- StringBuilder _print1(StringBuilder sb, BitSet visited) {
- if( ret()!=null ) return ret()._print0(sb, visited);
- sb.append("Stop[ ");
+ protected ExprPrinter<Node> _print1(ExprPrinter<Node> p) {
+ if( ret()!=null ) return p.n(ret());
+ p.p("Stop[ ");
for( Node ret : _inputs )
- ret._print0(sb, visited).append(" ");
- return sb.append("]");
+ p.n(ret).p(" ");
+ return p.p("]");
}
@Override public boolean isCFG() { return true; }
diff --git a/chapter07/src/main/java/com/seaofnodes/simple/node/SubNode.java b/chapter07/src/main/java/com/seaofnodes/simple/node/SubNode.java
index 421e659b..bf938504 100644
--- a/chapter07/src/main/java/com/seaofnodes/simple/node/SubNode.java
+++ b/chapter07/src/main/java/com/seaofnodes/simple/node/SubNode.java
@@ -1,21 +1,16 @@
package com.seaofnodes.simple.node;
+
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeInteger;
-import java.util.BitSet;
public class SubNode extends Node {
public SubNode(Node lhs, Node rhs) { super(null, lhs, rhs); }
@Override public String label() { return "Sub"; }
- @Override
- StringBuilder _print1(StringBuilder sb, BitSet visited) {
- in(1)._print0(sb.append("("), visited);
- in(2)._print0(sb.append("-"), visited);
- return sb.append(")");
- }
+ @Override protected String format() { return "(%1-%2)"; }
@Override
public Type compute() {
diff --git a/chapter07/src/main/java/com/seaofnodes/simple/print/SimpleGraphAdapter.java b/chapter07/src/main/java/com/seaofnodes/simple/print/SimpleGraphAdapter.java
index 9f33520e..c5ab1c60 100644
--- a/chapter07/src/main/java/com/seaofnodes/simple/print/SimpleGraphAdapter.java
+++ b/chapter07/src/main/java/com/seaofnodes/simple/print/SimpleGraphAdapter.java
@@ -1,39 +1,19 @@
package com.seaofnodes.simple.print;
import com.seaofnodes.graph.GraphAdapter;
-import com.seaofnodes.graph.GraphSnapshot;
import com.seaofnodes.graph.GraphSnapshot.*;
import com.seaofnodes.simple.node.*;
import com.seaofnodes.simple.node.Node;
-import java.util.ArrayList;
/** Chapter 7's view of the IR; browser, transport and layout are shared. */
public class SimpleGraphAdapter extends GraphAdapter<Node> {
- @Override protected boolean dead(Node n) { return n.isDead(); }
- @Override protected int id(Node n) { return n._nid; }
- @Override protected int nIns(Node n) { return n.nIns(); }
- @Override protected Node in(Node n, int idx) { return n.in(idx); }
- @Override protected int nOuts(Node n) { return n.nOuts(); }
- @Override protected Node out(Node n, int idx) { return n.out(idx); }
- private ArrayList<Edge> edges(Node n) {
- var edges = new ArrayList<Edge>();
- String[] names = n instanceof ScopeNode scope && n.nIns() != 0 ? scope.reverseNames() : null;
- for( int i = 0; i < n.nIns(); i++ ) {
- String name = names == null || i >= names.length ? null : names[i];
- edges.add(new Edge(i, ref(n.in(i)), role(n, i), name));
- }
- return edges;
+ @Override protected String[] edgeNames(Node n) {
+ return n instanceof ScopeNode scope && n.nIns()!=0 ? scope.reverseNames() : null;
}
+ @Override protected int projectionIndex(Node n) { return n instanceof ProjNode p ? p._idx : -1; }
- @Override protected GraphSnapshot.Node desc(Node n) {
- Projection proj = n instanceof ProjNode p ? new Projection(ref(n.in(0)), p._idx) : null;
- String label = n.label();
- return new GraphSnapshot.Node(n._nid, label == null ? n.getClass().getSimpleName() : label,
- n._type == null ? null : n._type.toString(), kind(n), edges(n), proj);
- }
-
- private Kind kind(Node n) {
+ @Override protected Kind kind(Node n) {
if( n instanceof StopNode ) return Kind.STOP;
if( n instanceof ScopeNode ) return Kind.SCOPE;
if( n instanceof StartNode ) return Kind.CTRL;
@@ -43,7 +23,7 @@ public class SimpleGraphAdapter extends GraphAdapter<Node> {
return n.isCFG() ? Kind.CTRL : Kind.DATA;
}
- private Role role(Node n, int i) {
+ @Override protected Role role(Node n, int i) {
if( n instanceof ScopeNode || n instanceof ConstantNode ) return Role.ASSOC;
if( n instanceof PhiNode ) return i == 0 ? Role.ASSOC : Role.DATA;
if( n instanceof ProjNode ) return n.isCFG() ? Role.CTRL : Role.DATA;
diff --git a/chapter08/Makefile b/chapter08/Makefile
index fcecddfa..5ededbc3 100644
--- a/chapter08/Makefile
+++ b/chapter08/Makefile
@@ -37,6 +37,7 @@ main_javas := $(wildcard $(SRC)/$(SIMPLE)/*java $(SRC)/$(SIMPLE)/*/*java)
test_javas := $(wildcard $(TST)/$(SIMPLE)/*java $(TST)/$(SIMPLE)/*/*java)
main_classes := $(patsubst $(SRC)/%java,$(CLZDIR)/main/%class,$(main_javas))
include $(firstword $(wildcard ../graph/graph.mk graph/graph.mk))
+include $(firstword $(wildcard ../print/print.mk print/print.mk))
test_classes := $(patsubst $(TST)/%java,$(CLZDIR)/test/%class,$(test_javas))
test_cp := $(patsubst $(TST)/$(SIMPLE)/%.java,com.seaofnodes.simple.%,$(wildcard $(TST)/$(SIMPLE)/*Test.java))
classes = $(main_classes) $(test_classes)
@@ -54,7 +55,7 @@ endif
default: $(default_targets)
# Compile just the out-of-date files
-$(main_classes): build/classes/main/%class: $(SRC)/%java $(graph_javas)
+$(main_classes): build/classes/main/%class: $(SRC)/%java $(graph_javas) $(print_javas)
@echo "compiling " $@ " because " $?
@[ -d $(CLZDIR)/main ] || mkdir -p $(CLZDIR)/main
@javac $(JAVAC_ARGS) -cp "$(CLZDIR)/main$(SEP)$(jars)" -sourcepath $(SRC) -d $(CLZDIR)/main $(main_javas)
diff --git a/chapter08/pom.xml b/chapter08/pom.xml
index 40fd6883..b87fa7bc 100644
--- a/chapter08/pom.xml
+++ b/chapter08/pom.xml
@@ -13,5 +13,6 @@
<name>Chapter 8</name>
<properties>
<simple.graph.directory>${project.basedir}/../graph</simple.graph.directory>
+ <simple.print.directory>${project.basedir}/../print</simple.print.directory>
</properties>
</project>
diff --git a/chapter08/src/main/java/com/seaofnodes/simple/IRPrinter.java b/chapter08/src/main/java/com/seaofnodes/simple/IRPrinter.java
index 2a6dbefd..2e40ff74 100644
--- a/chapter08/src/main/java/com/seaofnodes/simple/IRPrinter.java
+++ b/chapter08/src/main/java/com/seaofnodes/simple/IRPrinter.java
@@ -1,124 +1,31 @@
package com.seaofnodes.simple;
-import com.seaofnodes.simple.node.LoopNode;
-import com.seaofnodes.simple.node.Node;
+import com.seaofnodes.print.IRAdapter;
+import com.seaofnodes.simple.node.*;
-import java.util.ArrayList;
-import java.util.BitSet;
-
-public class IRPrinter {
-
- // Another bulk pretty-printer. Makes more effort at basic-block grouping.
- public static String prettyPrint(Node node, int depth) {
- // First, a Breadth First Search at a fixed depth.
- BFS bfs = new BFS(node,depth);
- // Convert just that set to a post-order
- ArrayList<Node> rpos = new ArrayList<>();
- BitSet visit = new BitSet();
- for( int i=bfs._lim; i< bfs._bfs.size(); i++ )
- postOrd( bfs._bfs.get(i), rpos, visit, bfs._bs);
- // Reverse the post-order walk
- StringBuilder sb = new StringBuilder();
- boolean gap=false;
- for( int i=rpos.size()-1; i>=0; i-- ) {
- Node n = rpos.get(i);
- if( n.isCFG() || n.isMultiHead() ) {
- if( !gap ) sb.append("\n"); // Blank before multihead
- n._printLine(sb); // Print head
- while( --i >= 0 ) {
- Node t = rpos.get(i);
- if( !t.isMultiTail() ) { i++; break; }
- t._printLine(sb);
- }
- sb.append("\n"); // Blank after multitail
- gap = true;
- } else {
- n._printLine( sb );
- gap = false;
- }
- }
- return sb.toString();
+/** 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 String type(Node n) { return n._type==null ? "" : n._type.toString(); }
+ @Override public int inputColumns() { return 3; }
+ @Override public Kind kind(Node n) {
+ if( n instanceof StartNode ) return Kind.START;
+ if( n instanceof StopNode ) return Kind.STOP;
+ if( n instanceof LoopNode ) return Kind.LOOP;
+ if( n instanceof RegionNode ) return Kind.REGION;
+ if( n instanceof PhiNode ) return Kind.PHI;
+ if( n instanceof ReturnNode ) return Kind.RETURN;
+ if( n instanceof ConstantNode ) return Kind.CONSTANT;
+ if( n instanceof ProjNode ) return n.isCFG() ? Kind.CPROJ : Kind.PROJ;
+ if( n.isCFG() ) return Kind.CTRL;
+ if( n instanceof MultiNode ) return Kind.MULTI;
+ return Kind.DATA;
}
-
- private static void postOrd(Node n, ArrayList<Node> rpos, BitSet visit, BitSet bfs) {
- if( !bfs.get(n._nid) )
- return; // Not in the BFS visit
- if( visit.get(n._nid) ) return; // Already post-order walked
- visit.set(n._nid);
- // First walk the CFG, then everything
- if( n.isCFG() ) {
- for( Node use : n._outputs )
- if( use.isCFG() && use.nOuts()>=1 && !(use._outputs.get(0) instanceof LoopNode) )
- postOrd(use, rpos,visit,bfs);
- for( Node use : n._outputs )
- if( use.isCFG() )
- postOrd(use,rpos,visit,bfs);
- }
- for( Node use : n._outputs )
- postOrd(use, rpos,visit,bfs);
- // Post-order
- rpos.add(n);
+ @Override public int index(Node n) {
+ if( n instanceof ProjNode p ) return p._idx;
+ return n._nid;
}
- // Breadth-first search, broken out in a class to keep in more independent.
- // Maintains a root-set of Nodes at the limit (or past by 1 if MultiHead).
- public static class BFS {
- // A breadth first search, plus MultiHeads for any MultiTails
- public final ArrayList<Node> _bfs;
- public final BitSet _bs; // Visited members by node id
- public final int _depth; // Depth limit
- public final int _lim; // From here to _bfs._len can be roots for a reverse search
- public BFS( Node base, int d ) {
- _depth = d;
- _bfs = new ArrayList<>();
- _bs = new BitSet();
-
- add(base); // Prime the pump
- int idx=0, lim=1; // Limit is where depth counter changes
- while( idx < _bfs.size() ) { // Ran out of nodes below depth
- Node n = _bfs.get(idx++);
- for( Node def : n._inputs )
- if( def!=null && !_bs.get(def._nid) )
- add(def);
- if( idx==lim ) { // Depth counter changes at limit
- if( --d < 0 )
- break; // Ran out of depth
- lim = _bfs.size(); // New depth limit
- }
- }
- // Toss things past the limit except multi-heads
- while( idx < _bfs.size() ) {
- Node n = _bfs.get(idx);
- if( n.isMultiHead() ) idx++;
- else del(idx);
- }
- // Root set is any node with no inputs in the visited set
- lim = _bfs.size();
- for( int i=_bfs.size()-1; i>=0; i-- )
- if( !any_visited(_bfs.get(i)) )
- swap( i,--lim);
- _lim = lim;
- }
- void swap( int x, int y ) {
- if( x==y ) return;
- Node tx = _bfs.get(x);
- Node ty = _bfs.get(y);
- _bfs.set(x,ty);
- _bfs.set(y,tx);
- }
- void add(Node n) {
- _bfs.add(n);
- _bs.set(n._nid);
- }
- void del(int idx) {
- Node n = Utils.del(_bfs, idx);
- _bs.clear(n._nid);
- }
- boolean any_visited( Node n ) {
- for( Node def : n._inputs )
- if( def!=null && _bs.get(def._nid) )
- return true;
- return false;
- }
- }
+ public static String prettyPrint(Node n, int depth) { return PRINT.prettyPrint(n,depth); }
}
diff --git a/chapter08/src/main/java/com/seaofnodes/simple/node/AddNode.java b/chapter08/src/main/java/com/seaofnodes/simple/node/AddNode.java
index fa3a6169..4a587953 100644
--- a/chapter08/src/main/java/com/seaofnodes/simple/node/AddNode.java
+++ b/chapter08/src/main/java/com/seaofnodes/simple/node/AddNode.java
@@ -1,20 +1,15 @@
package com.seaofnodes.simple.node;
+
import com.seaofnodes.simple.type.*;
-import java.util.BitSet;
public class AddNode extends Node {
public AddNode(Node lhs, Node rhs) { super(null, lhs, rhs); }
@Override public String label() { return "Add"; }
- @Override
- StringBuilder _print1(StringBuilder sb, BitSet visited) {
- in(1)._print0(sb.append("("), visited);
- in(2)._print0(sb.append("+"), visited);
- return sb.append(")");
- }
+ @Override protected String format() { return "(%1+%2)"; }
@Override
diff --git a/chapter08/src/main/java/com/seaofnodes/simple/node/BoolNode.java b/chapter08/src/main/java/com/seaofnodes/simple/node/BoolNode.java
index f5bbc9ad..e363bf75 100644
--- a/chapter08/src/main/java/com/seaofnodes/simple/node/BoolNode.java
+++ b/chapter08/src/main/java/com/seaofnodes/simple/node/BoolNode.java
@@ -1,9 +1,10 @@
package com.seaofnodes.simple.node;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeInteger;
-import java.util.BitSet;
abstract public class BoolNode extends Node {
@@ -16,11 +17,8 @@ abstract public class BoolNode extends Node {
@Override
public String label() { return getClass().getSimpleName(); }
- @Override
- 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/chapter08/src/main/java/com/seaofnodes/simple/node/ConstantNode.java b/chapter08/src/main/java/com/seaofnodes/simple/node/ConstantNode.java
index b7ec8292..19166ec6 100644
--- a/chapter08/src/main/java/com/seaofnodes/simple/node/ConstantNode.java
+++ b/chapter08/src/main/java/com/seaofnodes/simple/node/ConstantNode.java
@@ -1,9 +1,10 @@
package com.seaofnodes.simple.node;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.Parser;
import com.seaofnodes.simple.type.Type;
-import java.util.BitSet;
/**
* A Constant node represents a constant value. At present, the only constants
@@ -24,15 +25,16 @@ public class ConstantNode extends Node {
_con = type;
}
- @Override
- public String label() { return ""+_con; }
+ @Override protected String repeatName() {
+ return _con==null || _con.toString().length()<=32 ? null : uniqueName();
+ }
@Override
- public String uniqueName() { return "Con_" + _nid; }
+ public String label() { return "Con"; }
- @Override
- StringBuilder _print1(StringBuilder sb, BitSet visited) {
- return _con.print(sb);
+
+ @Override protected ExprPrinter<Node> _print1(ExprPrinter<Node> p) {
+ return p.p(_con);
}
@Override public boolean isMultiTail() { return true; }
diff --git a/chapter08/src/main/java/com/seaofnodes/simple/node/DivNode.java b/chapter08/src/main/java/com/seaofnodes/simple/node/DivNode.java
index f71a32db..4c3c2feb 100644
--- a/chapter08/src/main/java/com/seaofnodes/simple/node/DivNode.java
+++ b/chapter08/src/main/java/com/seaofnodes/simple/node/DivNode.java
@@ -1,21 +1,16 @@
package com.seaofnodes.simple.node;
+
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeInteger;
-import java.util.BitSet;
public class DivNode extends Node {
public DivNode(Node lhs, Node rhs) { super(null, lhs, rhs); }
@Override public String label() { return "Div"; }
- @Override
- StringBuilder _print1(StringBuilder sb, BitSet visited) {
- in(1)._print0(sb.append("("), visited);
- in(2)._print0(sb.append("/"), visited);
- return sb.append(")");
- }
+ @Override protected String format() { return "(%1/%2)"; }
@Override
public Type compute() {
diff --git a/chapter08/src/main/java/com/seaofnodes/simple/node/IfNode.java b/chapter08/src/main/java/com/seaofnodes/simple/node/IfNode.java
index 23a8fafc..41b5ffd7 100644
--- a/chapter08/src/main/java/com/seaofnodes/simple/node/IfNode.java
+++ b/chapter08/src/main/java/com/seaofnodes/simple/node/IfNode.java
@@ -1,10 +1,10 @@
package com.seaofnodes.simple.node;
+
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeInteger;
import com.seaofnodes.simple.type.TypeTuple;
-import java.util.BitSet;
public class IfNode extends MultiNode {
@@ -15,11 +15,7 @@ public class IfNode extends MultiNode {
@Override
public String label() { return "If"; }
- @Override
- StringBuilder _print1(StringBuilder sb, BitSet visited) {
- sb.append("if( ");
- return in(1)._print0(sb, visited).append(" )");
- }
+ @Override protected String format() { return "if( %1 )"; }
@Override public boolean isCFG() { return true; }
@Override public boolean isMultiHead() { return true; }
diff --git a/chapter08/src/main/java/com/seaofnodes/simple/node/MinusNode.java b/chapter08/src/main/java/com/seaofnodes/simple/node/MinusNode.java
index 9d3d3f5d..fb51777e 100644
--- a/chapter08/src/main/java/com/seaofnodes/simple/node/MinusNode.java
+++ b/chapter08/src/main/java/com/seaofnodes/simple/node/MinusNode.java
@@ -1,20 +1,16 @@
package com.seaofnodes.simple.node;
+
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeInteger;
-import java.util.BitSet;
public class MinusNode extends Node {
public MinusNode(Node in) { super(null, in); }
@Override public String label() { return "Minus"; }
- @Override
- 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/chapter08/src/main/java/com/seaofnodes/simple/node/MulNode.java b/chapter08/src/main/java/com/seaofnodes/simple/node/MulNode.java
index 4884ee18..2d0fa95b 100644
--- a/chapter08/src/main/java/com/seaofnodes/simple/node/MulNode.java
+++ b/chapter08/src/main/java/com/seaofnodes/simple/node/MulNode.java
@@ -1,21 +1,16 @@
package com.seaofnodes.simple.node;
+
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeInteger;
-import java.util.BitSet;
public class MulNode extends Node {
public MulNode(Node lhs, Node rhs) { super(null, lhs, rhs); }
@Override public String label() { return "Mul"; }
- @Override
- StringBuilder _print1(StringBuilder sb, BitSet visited) {
- in(1)._print0(sb.append("("), visited);
- in(2)._print0(sb.append("*"), visited);
- return sb.append(")");
- }
+ @Override protected String format() { return "(%1*%2)"; }
@Override
public Type compute() {
diff --git a/chapter08/src/main/java/com/seaofnodes/simple/node/Node.java b/chapter08/src/main/java/com/seaofnodes/simple/node/Node.java
index ffb868cb..46d5b843 100644
--- a/chapter08/src/main/java/com/seaofnodes/simple/node/Node.java
+++ b/chapter08/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.Parser;
import com.seaofnodes.simple.IRPrinter;
@@ -13,14 +15,7 @@ import java.util.*;
* The Node class provides common functionality used by all subtypes.
* Subtypes of Node specialize by overriding methods.
*/
-public abstract class Node {
-
- /**
- * 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 final int _nid;
+public abstract class Node extends BaseNode<Node> {
/**
* Inputs to the node. These are use-def references to Nodes.
@@ -42,14 +37,12 @@ public abstract class Node {
*/
public final ArrayList<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;
-
/**
* Immediate dominator tree depth, used to approximate a real IDOM during
* parsing where we do not have the whole program, and also peepholes
@@ -67,7 +60,7 @@ public abstract class Node {
private static int UNIQUE_ID = 1;
protected Node(Node... inputs) {
- _nid = UNIQUE_ID++; // allocate unique dense ID
+ super(UNIQUE_ID++); // allocate unique dense ID
_inputs = new ArrayList<>();
Collections.addAll(_inputs,inputs);
_outputs = new ArrayList<>();
@@ -79,65 +72,6 @@ public abstract class Node {
// Easy reading label for debugger, e.g. "Add" or "Region" or "EQ"
public abstract String label();
- // Unique label for debugging, e.g. "Add12" or "Region30" or "EQ99"
- public String uniqueName() { return label() + _nid; }
-
- // ------------------------------------------------------------------------
-
- // 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. This version will fail on cycles, which we will
- // correct later when we can parse programs with loops. We print with a
- // 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.
- final StringBuilder _print0(StringBuilder sb, BitSet visited) {
- if (visited.get(_nid))
- 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 StringBuilder _print1(StringBuilder sb, BitSet visited);
-
-
- // 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 void _printLine(StringBuilder sb ) {
- sb.append("%4d %-7.7s ".formatted(_nid,label()));
- if( isDead() ) {
- sb.append("DEAD\n");
- return;
- }
- for( Node def : _inputs )
- sb.append(def==null ? "____ " : "%4d ".formatted(def._nid));
- for( int i = _inputs.size(); i<3; i++ )
- sb.append(" ");
- sb.append(" [[ ");
- for( Node use : _outputs )
- sb.append("%4d ".formatted(use._nid));
- int lim = 5 - Math.max(_inputs.size(),3);
- for( int i = _outputs.size(); i<lim; i++ )
- sb.append(" ");
- sb.append(" ]] ");
- if( _type!= null ) _type.print(sb);
- sb.append("\n");
- }
-
public String p(int depth) { return IRPrinter.prettyPrint(this,depth); }
public boolean isMultiHead() { return false; }
@@ -146,6 +80,8 @@ public abstract class Node {
// ------------------------------------------------------------------------
// 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
@@ -155,12 +91,12 @@ public abstract class Node {
public int nIns() { return _inputs.size(); }
+ public Node out(int i) { return _outputs.get(i); }
+
public int nOuts() { return _outputs.size(); }
public boolean isUnused() { return nOuts() == 0; }
- public boolean isCFG() { return false; }
-
/**
* Change a <em>def</em> into a Node. Keeps the edges correct, by removing
* the corresponding <em>use->def</em> edge. This may make the original
@@ -264,7 +200,6 @@ public abstract class Node {
// Remove bogus null.
public <N extends Node> N unkeep() { delUse(null); return (N)this; }
-
// Replace self with nnn in the graph, making 'this' go dead
void subsume( Node nnn ) {
assert nnn!=this;
@@ -406,7 +341,6 @@ public abstract class Node {
*/
public abstract Node idealize();
-
// ------------------------------------------------------------------------
// Peephole utilities
@@ -450,7 +384,6 @@ public abstract class Node {
return _idepth = (char)depth;
}
-
// 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/chapter08/src/main/java/com/seaofnodes/simple/node/NotNode.java b/chapter08/src/main/java/com/seaofnodes/simple/node/NotNode.java
index 4c0be167..538016bd 100644
--- a/chapter08/src/main/java/com/seaofnodes/simple/node/NotNode.java
+++ b/chapter08/src/main/java/com/seaofnodes/simple/node/NotNode.java
@@ -1,20 +1,16 @@
package com.seaofnodes.simple.node;
+
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeInteger;
-import java.util.BitSet;
public class NotNode extends Node {
public NotNode(Node in) { super(null, in); }
@Override public String label() { return "Not"; }
- @Override
- 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/chapter08/src/main/java/com/seaofnodes/simple/node/PhiNode.java b/chapter08/src/main/java/com/seaofnodes/simple/node/PhiNode.java
index 7eeed394..14622140 100644
--- a/chapter08/src/main/java/com/seaofnodes/simple/node/PhiNode.java
+++ b/chapter08/src/main/java/com/seaofnodes/simple/node/PhiNode.java
@@ -1,8 +1,9 @@
package com.seaofnodes.simple.node;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.type.Type;
-import java.util.BitSet;
public class PhiNode extends Node {
@@ -13,18 +14,12 @@ public class PhiNode extends Node {
@Override public String label() { return "Phi_"+_label; }
@Override
- StringBuilder _print1(StringBuilder sb, BitSet visited) {
+ protected ExprPrinter<Node> _print1(ExprPrinter<Node> p) {
if( region().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();
}
RegionNode region() { return (RegionNode)in(0); }
diff --git a/chapter08/src/main/java/com/seaofnodes/simple/node/ProjNode.java b/chapter08/src/main/java/com/seaofnodes/simple/node/ProjNode.java
index 3c3f73b8..605c73bd 100644
--- a/chapter08/src/main/java/com/seaofnodes/simple/node/ProjNode.java
+++ b/chapter08/src/main/java/com/seaofnodes/simple/node/ProjNode.java
@@ -1,9 +1,10 @@
package com.seaofnodes.simple.node;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeTuple;
-import java.util.BitSet;
public class ProjNode extends Node {
@@ -23,7 +24,7 @@ public class ProjNode extends Node {
public String label() { return _label; }
@Override
- StringBuilder _print1(StringBuilder sb, BitSet visited) { return sb.append(_label); }
+ protected ExprPrinter<Node> _print1(ExprPrinter<Node> p) { return p.p(_label); }
@Override public boolean isCFG() { return _idx==0 || ctrl() instanceof IfNode; }
@Override public boolean isMultiTail() { return in(0).isMultiHead(); }
diff --git a/chapter08/src/main/java/com/seaofnodes/simple/node/RegionNode.java b/chapter08/src/main/java/com/seaofnodes/simple/node/RegionNode.java
index 756b4e24..b4dc3f58 100644
--- a/chapter08/src/main/java/com/seaofnodes/simple/node/RegionNode.java
+++ b/chapter08/src/main/java/com/seaofnodes/simple/node/RegionNode.java
@@ -1,10 +1,11 @@
package com.seaofnodes.simple.node;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.Utils;
import com.seaofnodes.simple.type.Type;
import java.util.Collection;
-import java.util.BitSet;
public class RegionNode extends Node {
@@ -13,9 +14,8 @@ public class RegionNode extends Node {
@Override
public String label() { return "Region"; }
- @Override
- StringBuilder _print1(StringBuilder sb, BitSet visited) {
- return sb.append(label()).append(_nid);
+ @Override protected ExprPrinter<Node> _print1(ExprPrinter<Node> p) {
+ return p.p(label()).p(_nid);
}
@Override public boolean isCFG() { return true; }
diff --git a/chapter08/src/main/java/com/seaofnodes/simple/node/ReturnNode.java b/chapter08/src/main/java/com/seaofnodes/simple/node/ReturnNode.java
index 312058b9..9f4cad7a 100644
--- a/chapter08/src/main/java/com/seaofnodes/simple/node/ReturnNode.java
+++ b/chapter08/src/main/java/com/seaofnodes/simple/node/ReturnNode.java
@@ -1,8 +1,9 @@
package com.seaofnodes.simple.node;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.type.*;
-import java.util.BitSet;
/**
* The Return node has two inputs. The first input is a control node and the
@@ -26,8 +27,8 @@ public class ReturnNode extends Node {
public String label() { return "Return"; }
@Override
- StringBuilder _print1(StringBuilder sb, BitSet visited) {
- return expr()._print0(sb.append("return "), visited).append(";");
+ protected ExprPrinter<Node> _print1(ExprPrinter<Node> p) {
+ return p.p("return ").n(expr()).p(";");
}
@Override public boolean isCFG() { return true; }
diff --git a/chapter08/src/main/java/com/seaofnodes/simple/node/ScopeNode.java b/chapter08/src/main/java/com/seaofnodes/simple/node/ScopeNode.java
index e5d03d93..31585ef4 100644
--- a/chapter08/src/main/java/com/seaofnodes/simple/node/ScopeNode.java
+++ b/chapter08/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.type.Type;
import java.util.*;
@@ -33,20 +35,19 @@ public class ScopeNode extends Node {
@Override public String label() { return "Scope"; }
@Override
- StringBuilder _print1(StringBuilder sb, BitSet visited) {
- sb.append("Scope[ ");
+ protected ExprPrinter<Node> _print1(ExprPrinter<Node> p) {
+ p.p("Scope[ ");
String[] names = reverseNames();
for( int j=0; j<nIns(); j++ ) {
- sb.append(names[j]).append(":");
+ p.p(names[j]).p(":");
Node n = in(j);
while( n instanceof ScopeNode loop ) {
- sb.append("Lazy_");
+ p.p("Lazy_");
n = loop.in(j);
}
- n._print0(sb, visited).append(" ");
+ p.n(n).p(" ");
}
- sb.setLength(sb.length()-1);
- return sb.append("]");
+ return p.unchar(' ').p("]");
}
/**
diff --git a/chapter08/src/main/java/com/seaofnodes/simple/node/StartNode.java b/chapter08/src/main/java/com/seaofnodes/simple/node/StartNode.java
index bab0f18c..56689503 100644
--- a/chapter08/src/main/java/com/seaofnodes/simple/node/StartNode.java
+++ b/chapter08/src/main/java/com/seaofnodes/simple/node/StartNode.java
@@ -1,9 +1,10 @@
package com.seaofnodes.simple.node;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeTuple;
-import java.util.BitSet;
/**
* The Start node represents the start of the function. For now, we do not
@@ -25,9 +26,8 @@ public class StartNode extends MultiNode {
@Override
public String label() { return "Start"; }
- @Override
- 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 isCFG() { return true; }
diff --git a/chapter08/src/main/java/com/seaofnodes/simple/node/StopNode.java b/chapter08/src/main/java/com/seaofnodes/simple/node/StopNode.java
index 417790d9..aa655f63 100644
--- a/chapter08/src/main/java/com/seaofnodes/simple/node/StopNode.java
+++ b/chapter08/src/main/java/com/seaofnodes/simple/node/StopNode.java
@@ -1,8 +1,9 @@
package com.seaofnodes.simple.node;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.type.Type;
-import java.util.BitSet;
public class StopNode extends Node {
public StopNode(Node... inputs) {
@@ -15,12 +16,12 @@ public class StopNode extends Node {
}
@Override
- StringBuilder _print1(StringBuilder sb, BitSet visited) {
- if( ret()!=null ) return ret()._print0(sb, visited);
- sb.append("Stop[ ");
+ protected ExprPrinter<Node> _print1(ExprPrinter<Node> p) {
+ if( ret()!=null ) return p.n(ret());
+ p.p("Stop[ ");
for( Node ret : _inputs )
- ret._print0(sb, visited).append(" ");
- return sb.append("]");
+ p.n(ret).p(" ");
+ return p.p("]");
}
@Override public boolean isCFG() { return true; }
diff --git a/chapter08/src/main/java/com/seaofnodes/simple/node/SubNode.java b/chapter08/src/main/java/com/seaofnodes/simple/node/SubNode.java
index 421e659b..bf938504 100644
--- a/chapter08/src/main/java/com/seaofnodes/simple/node/SubNode.java
+++ b/chapter08/src/main/java/com/seaofnodes/simple/node/SubNode.java
@@ -1,21 +1,16 @@
package com.seaofnodes.simple.node;
+
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeInteger;
-import java.util.BitSet;
public class SubNode extends Node {
public SubNode(Node lhs, Node rhs) { super(null, lhs, rhs); }
@Override public String label() { return "Sub"; }
- @Override
- StringBuilder _print1(StringBuilder sb, BitSet visited) {
- in(1)._print0(sb.append("("), visited);
- in(2)._print0(sb.append("-"), visited);
- return sb.append(")");
- }
+ @Override protected String format() { return "(%1-%2)"; }
@Override
public Type compute() {
diff --git a/chapter08/src/main/java/com/seaofnodes/simple/print/SimpleGraphAdapter.java b/chapter08/src/main/java/com/seaofnodes/simple/print/SimpleGraphAdapter.java
index 3c4dd7dd..a9acba10 100644
--- a/chapter08/src/main/java/com/seaofnodes/simple/print/SimpleGraphAdapter.java
+++ b/chapter08/src/main/java/com/seaofnodes/simple/print/SimpleGraphAdapter.java
@@ -1,39 +1,19 @@
package com.seaofnodes.simple.print;
import com.seaofnodes.graph.GraphAdapter;
-import com.seaofnodes.graph.GraphSnapshot;
import com.seaofnodes.graph.GraphSnapshot.*;
import com.seaofnodes.simple.node.*;
import com.seaofnodes.simple.node.Node;
-import java.util.ArrayList;
/** Chapter 8's view of the IR; browser, transport and layout are shared. */
public class SimpleGraphAdapter extends GraphAdapter<Node> {
- @Override protected boolean dead(Node n) { return n.isDead(); }
- @Override protected int id(Node n) { return n._nid; }
- @Override protected int nIns(Node n) { return n.nIns(); }
- @Override protected Node in(Node n, int idx) { return n.in(idx); }
- @Override protected int nOuts(Node n) { return n.nOuts(); }
- @Override protected Node out(Node n, int idx) { return n._outputs.get(idx); }
- private ArrayList<Edge> edges(Node n) {
- var edges = new ArrayList<Edge>();
- String[] names = n instanceof ScopeNode scope && n.nIns() != 0 ? scope.reverseNames() : null;
- for( int i = 0; i < n.nIns(); i++ ) {
- String name = names == null || i >= names.length ? null : names[i];
- edges.add(new Edge(i, ref(n.in(i)), role(n, i), name));
- }
- return edges;
+ @Override protected String[] edgeNames(Node n) {
+ return n instanceof ScopeNode scope && n.nIns()!=0 ? scope.reverseNames() : null;
}
+ @Override protected int projectionIndex(Node n) { return n instanceof ProjNode p ? p._idx : -1; }
- @Override protected GraphSnapshot.Node desc(Node n) {
- Projection proj = n instanceof ProjNode p ? new Projection(ref(n.in(0)), p._idx) : null;
- String label = n.label();
- return new GraphSnapshot.Node(n._nid, label == null ? n.getClass().getSimpleName() : label,
- n._type == null ? null : n._type.toString(), kind(n), edges(n), proj);
- }
-
- private Kind kind(Node n) {
+ @Override protected Kind kind(Node n) {
if( n instanceof StopNode ) return Kind.STOP;
if( n instanceof ScopeNode ) return Kind.SCOPE;
if( n instanceof StartNode ) return Kind.CTRL;
@@ -43,7 +23,7 @@ public class SimpleGraphAdapter extends GraphAdapter<Node> {
return n.isCFG() ? Kind.CTRL : Kind.DATA;
}
- private Role role(Node n, int i) {
+ @Override protected Role role(Node n, int i) {
if( n instanceof ScopeNode || n instanceof ConstantNode ) return Role.ASSOC;
if( n instanceof PhiNode ) return i == 0 ? Role.ASSOC : Role.DATA;
if( n instanceof ProjNode ) return n.isCFG() ? Role.CTRL : Role.DATA;
diff --git a/chapter09/Makefile b/chapter09/Makefile
index 2ec07dfe..1874a5b5 100644
--- a/chapter09/Makefile
+++ b/chapter09/Makefile
@@ -37,6 +37,7 @@ main_javas := $(wildcard $(SRC)/$(SIMPLE)/*java $(SRC)/$(SIMPLE)/*/*java)
test_javas := $(wildcard $(TST)/$(SIMPLE)/*java $(TST)/$(SIMPLE)/*/*java)
main_classes := $(patsubst $(SRC)/%java,$(CLZDIR)/main/%class,$(main_javas))
include $(firstword $(wildcard ../graph/graph.mk graph/graph.mk))
+include $(firstword $(wildcard ../print/print.mk print/print.mk))
test_classes := $(patsubst $(TST)/%java,$(CLZDIR)/test/%class,$(test_javas))
test_cp := $(patsubst $(TST)/$(SIMPLE)/%.java,com.seaofnodes.simple.%,$(wildcard $(TST)/$(SIMPLE)/*Test.java))
classes = $(main_classes) $(test_classes)
@@ -54,7 +55,7 @@ endif
default: $(default_targets)
# Compile just the out-of-date files
-$(main_classes): build/classes/main/%class: $(SRC)/%java $(graph_javas)
+$(main_classes): build/classes/main/%class: $(SRC)/%java $(graph_javas) $(print_javas)
@echo "compiling " $@ " because " $?
@[ -d $(CLZDIR)/main ] || mkdir -p $(CLZDIR)/main
@javac $(JAVAC_ARGS) -cp "$(CLZDIR)/main$(SEP)$(jars)" -sourcepath $(SRC) -d $(CLZDIR)/main $(main_javas)
diff --git a/chapter09/pom.xml b/chapter09/pom.xml
index 5c1a762b..96d4cd32 100644
--- a/chapter09/pom.xml
+++ b/chapter09/pom.xml
@@ -13,5 +13,6 @@
<name>Chapter 9</name>
<properties>
<simple.graph.directory>${project.basedir}/../graph</simple.graph.directory>
+ <simple.print.directory>${project.basedir}/../print</simple.print.directory>
</properties>
</project>
diff --git a/chapter09/src/main/java/com/seaofnodes/simple/IRPrinter.java b/chapter09/src/main/java/com/seaofnodes/simple/IRPrinter.java
index c06ac9d0..2e40ff74 100644
--- a/chapter09/src/main/java/com/seaofnodes/simple/IRPrinter.java
+++ b/chapter09/src/main/java/com/seaofnodes/simple/IRPrinter.java
@@ -1,125 +1,31 @@
package com.seaofnodes.simple;
-import com.seaofnodes.simple.node.LoopNode;
-import com.seaofnodes.simple.node.Node;
+import com.seaofnodes.print.IRAdapter;
+import com.seaofnodes.simple.node.*;
-import java.util.ArrayList;
-import java.util.BitSet;
-
-public class IRPrinter {
-
- // Another bulk pretty-printer. Makes more effort at basic-block grouping.
- public static String prettyPrint(Node node, int depth) {
- // First, a Breadth First Search at a fixed depth.
- BFS bfs = new BFS(node,depth);
- // Convert just that set to a post-order
- ArrayList<Node> rpos = new ArrayList<>();
- BitSet visit = new BitSet();
- for( int i=bfs._lim; i< bfs._bfs.size(); i++ )
- postOrd( bfs._bfs.get(i), rpos, visit, bfs._bs);
- // Reverse the post-order walk
- StringBuilder sb = new StringBuilder();
- boolean gap=false;
- for( int i=rpos.size()-1; i>=0; i-- ) {
- Node n = rpos.get(i);
- if( n.isCFG() || n.isMultiHead() ) {
- if( !gap ) sb.append("\n"); // Blank before multihead
- n._printLine(sb); // Print head
- while( --i >= 0 ) {
- Node t = rpos.get(i);
- if( !t.isMultiTail() ) { i++; break; }
- t._printLine(sb);
- }
- sb.append("\n"); // Blank after multitail
- gap = true;
- } else {
- n._printLine( sb );
- gap = false;
- }
- }
- return sb.toString();
+/** 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 String type(Node n) { return n._type==null ? "" : n._type.toString(); }
+ @Override public int inputColumns() { return 3; }
+ @Override public Kind kind(Node n) {
+ if( n instanceof StartNode ) return Kind.START;
+ if( n instanceof StopNode ) return Kind.STOP;
+ if( n instanceof LoopNode ) return Kind.LOOP;
+ if( n instanceof RegionNode ) return Kind.REGION;
+ if( n instanceof PhiNode ) return Kind.PHI;
+ if( n instanceof ReturnNode ) return Kind.RETURN;
+ if( n instanceof ConstantNode ) return Kind.CONSTANT;
+ if( n instanceof ProjNode ) return n.isCFG() ? Kind.CPROJ : Kind.PROJ;
+ if( n.isCFG() ) return Kind.CTRL;
+ if( n instanceof MultiNode ) return Kind.MULTI;
+ return Kind.DATA;
}
-
- private static void postOrd(Node n, ArrayList<Node> rpos, BitSet visit, BitSet bfs) {
- if( !bfs.get(n._nid) )
- return; // Not in the BFS visit
- if( visit.get(n._nid) ) return; // Already post-order walked
- visit.set(n._nid);
- // First walk the CFG, then everything
- if( n.isCFG() ) {
- for( Node use : n._outputs )
- if( use!=null && use.isCFG() && use.nOuts()>=1 && !(use._outputs.get(0) instanceof LoopNode) )
- postOrd(use, rpos,visit,bfs);
- for( Node use : n._outputs )
- if( use!=null && use.isCFG() )
- postOrd(use,rpos,visit,bfs);
- }
- for( Node use : n._outputs )
- if( use != null )
- postOrd(use, rpos,visit,bfs);
- // Post-order
- rpos.add(n);
+ @Override public int index(Node n) {
+ if( n instanceof ProjNode p ) return p._idx;
+ return n._nid;
}
- // Breadth-first search, broken out in a class to keep in more independent.
- // Maintains a root-set of Nodes at the limit (or past by 1 if MultiHead).
- public static class BFS {
- // A breadth first search, plus MultiHeads for any MultiTails
- public final ArrayList<Node> _bfs;
- public final BitSet _bs; // Visited members by node id
- public final int _depth; // Depth limit
- public final int _lim; // From here to _bfs._len can be roots for a reverse search
- public BFS( Node base, int d ) {
- _depth = d;
- _bfs = new ArrayList<>();
- _bs = new BitSet();
-
- add(base); // Prime the pump
- int idx=0, lim=1; // Limit is where depth counter changes
- while( idx < _bfs.size() ) { // Ran out of nodes below depth
- Node n = _bfs.get(idx++);
- for( Node def : n._inputs )
- if( def!=null && !_bs.get(def._nid) )
- add(def);
- if( idx==lim ) { // Depth counter changes at limit
- if( --d < 0 )
- break; // Ran out of depth
- lim = _bfs.size(); // New depth limit
- }
- }
- // Toss things past the limit except multi-heads
- while( idx < _bfs.size() ) {
- Node n = _bfs.get(idx);
- if( n.isMultiHead() ) idx++;
- else del(idx);
- }
- // Root set is any node with no inputs in the visited set
- lim = _bfs.size();
- for( int i=_bfs.size()-1; i>=0; i-- )
- if( !any_visited(_bfs.get(i)) )
- swap( i,--lim);
- _lim = lim;
- }
- void swap( int x, int y ) {
- if( x==y ) return;
- Node tx = _bfs.get(x);
- Node ty = _bfs.get(y);
- _bfs.set(x,ty);
- _bfs.set(y,tx);
- }
- void add(Node n) {
- _bfs.add(n);
- _bs.set(n._nid);
- }
- void del(int idx) {
- Node n = Utils.del(_bfs, idx);
- _bs.clear(n._nid);
- }
- boolean any_visited( Node n ) {
- for( Node def : n._inputs )
- if( def!=null && _bs.get(def._nid) )
- return true;
- return false;
- }
- }
+ public static String prettyPrint(Node n, int depth) { return PRINT.prettyPrint(n,depth); }
}
diff --git a/chapter09/src/main/java/com/seaofnodes/simple/node/AddNode.java b/chapter09/src/main/java/com/seaofnodes/simple/node/AddNode.java
index b57b305f..c299e805 100644
--- a/chapter09/src/main/java/com/seaofnodes/simple/node/AddNode.java
+++ b/chapter09/src/main/java/com/seaofnodes/simple/node/AddNode.java
@@ -1,20 +1,15 @@
package com.seaofnodes.simple.node;
+
import com.seaofnodes.simple.type.*;
-import java.util.BitSet;
public class AddNode extends Node {
public AddNode(Node lhs, Node rhs) { super(null, lhs, rhs); }
@Override public String label() { return "Add"; }
- @Override
- StringBuilder _print1(StringBuilder sb, BitSet visited) {
- in(1)._print0(sb.append("("), visited);
- in(2)._print0(sb.append("+"), visited);
- return sb.append(")");
- }
+ @Override protected String format() { return "(%1+%2)"; }
@Override
diff --git a/chapter09/src/main/java/com/seaofnodes/simple/node/BoolNode.java b/chapter09/src/main/java/com/seaofnodes/simple/node/BoolNode.java
index 08ff3789..a6b8bfc7 100644
--- a/chapter09/src/main/java/com/seaofnodes/simple/node/BoolNode.java
+++ b/chapter09/src/main/java/com/seaofnodes/simple/node/BoolNode.java
@@ -1,9 +1,10 @@
package com.seaofnodes.simple.node;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeInteger;
-import java.util.BitSet;
abstract public class BoolNode extends Node {
@@ -16,11 +17,8 @@ abstract public class BoolNode extends Node {
@Override
public String label() { return getClass().getSimpleName(); }
- @Override
- 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/chapter09/src/main/java/com/seaofnodes/simple/node/ConstantNode.java b/chapter09/src/main/java/com/seaofnodes/simple/node/ConstantNode.java
index 8fd955e9..cf2465e3 100644
--- a/chapter09/src/main/java/com/seaofnodes/simple/node/ConstantNode.java
+++ b/chapter09/src/main/java/com/seaofnodes/simple/node/ConstantNode.java
@@ -1,9 +1,10 @@
package com.seaofnodes.simple.node;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.Parser;
import com.seaofnodes.simple.type.Type;
-import java.util.BitSet;
/**
* A Constant node represents a constant value. At present, the only constants
@@ -24,15 +25,16 @@ public class ConstantNode extends Node {
_con = type;
}
- @Override
- public String label() { return "#"+_con; }
+ @Override protected String repeatName() {
+ return _con==null || _con.toString().length()<=32 ? null : uniqueName();
+ }
@Override
- public String uniqueName() { return "Con_" + _nid; }
+ public String label() { return "Con"; }
- @Override
- StringBuilder _print1(StringBuilder sb, BitSet visited) {
- return _con.print(sb);
+
+ @Override protected ExprPrinter<Node> _print1(ExprPrinter<Node> p) {
+ return p.p(_con);
}
@Override public boolean isMultiTail() { return true; }
diff --git a/chapter09/src/main/java/com/seaofnodes/simple/node/DivNode.java b/chapter09/src/main/java/com/seaofnodes/simple/node/DivNode.java
index 6cee90ad..d7244ace 100644
--- a/chapter09/src/main/java/com/seaofnodes/simple/node/DivNode.java
+++ b/chapter09/src/main/java/com/seaofnodes/simple/node/DivNode.java
@@ -1,21 +1,16 @@
package com.seaofnodes.simple.node;
+
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeInteger;
-import java.util.BitSet;
public class DivNode extends Node {
public DivNode(Node lhs, Node rhs) { super(null, lhs, rhs); }
@Override public String label() { return "Div"; }
- @Override
- StringBuilder _print1(StringBuilder sb, BitSet visited) {
- in(1)._print0(sb.append("("), visited);
- in(2)._print0(sb.append("/"), visited);
- return sb.append(")");
- }
+ @Override protected String format() { return "(%1/%2)"; }
@Override
public Type compute() {
diff --git a/chapter09/src/main/java/com/seaofnodes/simple/node/IfNode.java b/chapter09/src/main/java/com/seaofnodes/simple/node/IfNode.java
index 460dce51..1c3d2c85 100644
--- a/chapter09/src/main/java/com/seaofnodes/simple/node/IfNode.java
+++ b/chapter09/src/main/java/com/seaofnodes/simple/node/IfNode.java
@@ -1,10 +1,10 @@
package com.seaofnodes.simple.node;
+
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeInteger;
import com.seaofnodes.simple.type.TypeTuple;
-import java.util.BitSet;
public class IfNode extends MultiNode {
@@ -15,11 +15,7 @@ public class IfNode extends MultiNode {
@Override
public String label() { return "If"; }
- @Override
- StringBuilder _print1(StringBuilder sb, BitSet visited) {
- sb.append("if( ");
- return in(1)._print0(sb, visited).append(" )");
- }
+ @Override protected String format() { return "if( %1 )"; }
@Override public boolean isCFG() { return true; }
@Override public boolean isMultiHead() { return true; }
diff --git a/chapter09/src/main/java/com/seaofnodes/simple/node/MinusNode.java b/chapter09/src/main/java/com/seaofnodes/simple/node/MinusNode.java
index 5b055089..0934c37f 100644
--- a/chapter09/src/main/java/com/seaofnodes/simple/node/MinusNode.java
+++ b/chapter09/src/main/java/com/seaofnodes/simple/node/MinusNode.java
@@ -1,20 +1,16 @@
package com.seaofnodes.simple.node;
+
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeInteger;
-import java.util.BitSet;
public class MinusNode extends Node {
public MinusNode(Node in) { super(null, in); }
@Override public String label() { return "Minus"; }
- @Override
- 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/chapter09/src/main/java/com/seaofnodes/simple/node/MulNode.java b/chapter09/src/main/java/com/seaofnodes/simple/node/MulNode.java
index 97721ce3..5592c52d 100644
--- a/chapter09/src/main/java/com/seaofnodes/simple/node/MulNode.java
+++ b/chapter09/src/main/java/com/seaofnodes/simple/node/MulNode.java
@@ -1,21 +1,16 @@
package com.seaofnodes.simple.node;
+
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeInteger;
-import java.util.BitSet;
public class MulNode extends Node {
public MulNode(Node lhs, Node rhs) { super(null, lhs, rhs); }
@Override public String label() { return "Mul"; }
- @Override
- StringBuilder _print1(StringBuilder sb, BitSet visited) {
- in(1)._print0(sb.append("("), visited);
- in(2)._print0(sb.append("*"), visited);
- return sb.append(")");
- }
+ @Override protected String format() { return "(%1*%2)"; }
@Override
public Type compute() {
diff --git a/chapter09/src/main/java/com/seaofnodes/simple/node/Node.java b/chapter09/src/main/java/com/seaofnodes/simple/node/Node.java
index a0ec0289..3c1ed0ab 100644
--- a/chapter09/src/main/java/com/seaofnodes/simple/node/Node.java
+++ b/chapter09/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.Parser;
import com.seaofnodes.simple.IRPrinter;
@@ -15,14 +17,7 @@ import java.util.function.Function;
* The Node class provides common functionality used by all subtypes.
* Subtypes of Node specialize by overriding methods.
*/
-public abstract class Node {
-
- /**
- * 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 final int _nid;
+public abstract class Node extends BaseNode<Node> {
/**
* Inputs to the node. These are use-def references to Nodes.
@@ -44,14 +39,12 @@ public abstract class Node {
*/
public final ArrayList<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;
-
/**
* Immediate dominator tree depth, used to approximate a real IDOM during
* parsing where we do not have the whole program, and also peepholes
@@ -70,7 +63,7 @@ public abstract class Node {
public static int UID() { return UNIQUE_ID; }
protected Node(Node... inputs) {
- _nid = UNIQUE_ID++; // allocate unique dense ID
+ super(UNIQUE_ID++); // allocate unique dense ID
_inputs = new ArrayList<>();
Collections.addAll(_inputs,inputs);
_outputs = new ArrayList<>();
@@ -82,65 +75,6 @@ public abstract class Node {
// Easy reading label for debugger, e.g. "Add" or "Region" or "EQ"
public abstract String label();
- // Unique label for debugging, e.g. "Add12" or "Region30" or "EQ99"
- public String uniqueName() { return label() + _nid; }
-
- // ------------------------------------------------------------------------
-
- // 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. This version will fail on cycles, which we will
- // correct later when we can parse programs with loops. We print with a
- // 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.
- 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 StringBuilder _print1(StringBuilder sb, BitSet visited);
-
-
- // 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 void _printLine(StringBuilder sb ) {
- sb.append("%4d %-7.7s ".formatted(_nid,label()));
- if( isDead() ) {
- sb.append("DEAD\n");
- return;
- }
- for( Node def : _inputs )
- sb.append(def==null ? "____ " : "%4d ".formatted(def._nid));
- for( int i = _inputs.size(); i<3; i++ )
- sb.append(" ");
- sb.append(" [[ ");
- for( Node use : _outputs )
- sb.append(use==null ? "____ " : "%4d ".formatted(use._nid));
- int lim = 5 - Math.max(_inputs.size(),3);
- for( int i = _outputs.size(); i<lim; i++ )
- sb.append(" ");
- sb.append(" ]] ");
- if( _type!= null ) _type.print(sb);
- sb.append("\n");
- }
-
public String p(int depth) { return IRPrinter.prettyPrint(this,depth); }
public boolean isMultiHead() { return false; }
@@ -149,6 +83,8 @@ public abstract class Node {
// ------------------------------------------------------------------------
// 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
@@ -163,8 +99,6 @@ public abstract class Node {
public boolean isUnused() { return nOuts() == 0; }
- public boolean isCFG() { return false; }
-
/**
* Change a <em>def</em> into a Node. Keeps the edges correct, by removing
* the corresponding <em>use->def</em> edge. This may make the original
@@ -283,7 +217,6 @@ public abstract class Node {
// Remove bogus null.
public <N extends Node> N unkeep() { delUse(null); return (N)this; }
-
// Replace self with nnn in the graph, making 'this' go dead
public void subsume( Node nnn ) {
assert nnn!=this;
@@ -413,7 +346,6 @@ public abstract class Node {
return old;
}
-
/**
* This function rewrites the current Node into a more "idealized" form.
* This is the bulk of our peephole rewrite rules, and we use this to
@@ -461,7 +393,6 @@ public abstract class Node {
*/
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
@@ -497,7 +428,6 @@ public abstract class Node {
_deps.clear();
}
-
// Global Value Numbering. Hash over opcode and inputs; hits in this table
// are structurally equal.
public static final HashMap<Node,Node> GVN = new HashMap<>();
@@ -519,7 +449,6 @@ public abstract class Node {
// and can assume "this!=n" and has the same Java class.
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
@@ -535,7 +464,6 @@ public abstract class Node {
_hash=0; // Out of table now
}
-
// Hash of opcode and inputs
@Override public final int hashCode() {
if( _hash != 0 ) return _hash;
@@ -549,7 +477,6 @@ public abstract class Node {
// Subclasses add extra hash info (such as ConstantNodes constant)
int hash() { return 0; }
-
// ------------------------------------------------------------------------
// Peephole utilities
@@ -604,7 +531,6 @@ public abstract class Node {
return _idepth = (char)depth;
}
-
// 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.
@@ -620,7 +546,6 @@ public abstract class Node {
ITER_CNT = ITER_NOP_CNT = 0;
}
-
// Utility to walk the entire graph applying a function; return the first
// not-null result.
private static final BitSet WVISIT = new BitSet();
diff --git a/chapter09/src/main/java/com/seaofnodes/simple/node/NotNode.java b/chapter09/src/main/java/com/seaofnodes/simple/node/NotNode.java
index a9a69c59..8077f108 100644
--- a/chapter09/src/main/java/com/seaofnodes/simple/node/NotNode.java
+++ b/chapter09/src/main/java/com/seaofnodes/simple/node/NotNode.java
@@ -1,20 +1,16 @@
package com.seaofnodes.simple.node;
+
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeInteger;
-import java.util.BitSet;
public class NotNode extends Node {
public NotNode(Node in) { super(null, in); }
@Override public String label() { return "Not"; }
- @Override
- 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/chapter09/src/main/java/com/seaofnodes/simple/node/PhiNode.java b/chapter09/src/main/java/com/seaofnodes/simple/node/PhiNode.java
index 13c9423d..fe6231fa 100644
--- a/chapter09/src/main/java/com/seaofnodes/simple/node/PhiNode.java
+++ b/chapter09/src/main/java/com/seaofnodes/simple/node/PhiNode.java
@@ -1,8 +1,9 @@
package com.seaofnodes.simple.node;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.type.Type;
-import java.util.BitSet;
public class PhiNode extends Node {
@@ -13,18 +14,12 @@ public class PhiNode extends Node {
@Override public String label() { return "Phi_"+_label; }
@Override
- 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();
}
Node region() { return in(0); }
diff --git a/chapter09/src/main/java/com/seaofnodes/simple/node/ProjNode.java b/chapter09/src/main/java/com/seaofnodes/simple/node/ProjNode.java
index 0ed9441d..a794dfcc 100644
--- a/chapter09/src/main/java/com/seaofnodes/simple/node/ProjNode.java
+++ b/chapter09/src/main/java/com/seaofnodes/simple/node/ProjNode.java
@@ -1,9 +1,10 @@
package com.seaofnodes.simple.node;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeTuple;
-import java.util.BitSet;
public class ProjNode extends Node {
@@ -23,7 +24,7 @@ public class ProjNode extends Node {
public String label() { return _label; }
@Override
- StringBuilder _print1(StringBuilder sb, BitSet visited) { return sb.append(_label); }
+ protected ExprPrinter<Node> _print1(ExprPrinter<Node> p) { return p.p(_label); }
@Override public boolean isCFG() { return _idx==0 || ctrl() instanceof IfNode; }
@Override public boolean isMultiTail() { return in(0).isMultiHead(); }
diff --git a/chapter09/src/main/java/com/seaofnodes/simple/node/RegionNode.java b/chapter09/src/main/java/com/seaofnodes/simple/node/RegionNode.java
index 71bef275..315fcf0e 100644
--- a/chapter09/src/main/java/com/seaofnodes/simple/node/RegionNode.java
+++ b/chapter09/src/main/java/com/seaofnodes/simple/node/RegionNode.java
@@ -1,12 +1,13 @@
package com.seaofnodes.simple.node;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.IterPeeps;
import com.seaofnodes.simple.Utils;
import com.seaofnodes.simple.type.Type;
import java.util.ArrayList;
import java.util.Arrays;
-import java.util.BitSet;
public class RegionNode extends Node {
@@ -15,9 +16,8 @@ public class RegionNode extends Node {
@Override
public String label() { return "Region"; }
- @Override
- StringBuilder _print1(StringBuilder sb, BitSet visited) {
- return sb.append(label()).append(_nid);
+ @Override protected ExprPrinter<Node> _print1(ExprPrinter<Node> p) {
+ return p.p(label()).p(_nid);
}
@Override public boolean isCFG() { return true; }
diff --git a/chapter09/src/main/java/com/seaofnodes/simple/node/ReturnNode.java b/chapter09/src/main/java/com/seaofnodes/simple/node/ReturnNode.java
index 922a3649..bc09c623 100644
--- a/chapter09/src/main/java/com/seaofnodes/simple/node/ReturnNode.java
+++ b/chapter09/src/main/java/com/seaofnodes/simple/node/ReturnNode.java
@@ -1,8 +1,9 @@
package com.seaofnodes.simple.node;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.type.*;
-import java.util.BitSet;
/**
* The Return node has two inputs. The first input is a control node and the
@@ -26,8 +27,8 @@ public class ReturnNode extends Node {
public String label() { return "Return"; }
@Override
- StringBuilder _print1(StringBuilder sb, BitSet visited) {
- return expr()._print0(sb.append("return "), visited).append(";");
+ protected ExprPrinter<Node> _print1(ExprPrinter<Node> p) {
+ return p.p("return ").n(expr()).p(";");
}
@Override public boolean isCFG() { return true; }
diff --git a/chapter09/src/main/java/com/seaofnodes/simple/node/ScopeNode.java b/chapter09/src/main/java/com/seaofnodes/simple/node/ScopeNode.java
index 3abea54d..f34d78e1 100644
--- a/chapter09/src/main/java/com/seaofnodes/simple/node/ScopeNode.java
+++ b/chapter09/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.IterPeeps;
import com.seaofnodes.simple.type.Type;
@@ -34,20 +36,19 @@ public class ScopeNode extends Node {
@Override public String label() { return "Scope"; }
@Override
- StringBuilder _print1(StringBuilder sb, BitSet visited) {
- sb.append("Scope[ ");
+ protected ExprPrinter<Node> _print1(ExprPrinter<Node> p) {
+ p.p("Scope[ ");
String[] names = reverseNames();
for( int j=0; j<nIns(); j++ ) {
- sb.append(names[j]).append(":");
+ p.p(names[j]).p(":");
Node n = in(j);
while( n instanceof ScopeNode loop ) {
- sb.append("Lazy_");
+ p.p("Lazy_");
n = loop.in(j);
}
- n._print0(sb, visited).append(" ");
+ p.n(n).p(" ");
}
- sb.setLength(sb.length()-1);
- return sb.append("]");
+ return p.unchar(' ').p("]");
}
/**
diff --git a/chapter09/src/main/java/com/seaofnodes/simple/node/StartNode.java b/chapter09/src/main/java/com/seaofnodes/simple/node/StartNode.java
index 1e3559ce..c2fcaba5 100644
--- a/chapter09/src/main/java/com/seaofnodes/simple/node/StartNode.java
+++ b/chapter09/src/main/java/com/seaofnodes/simple/node/StartNode.java
@@ -1,9 +1,10 @@
package com.seaofnodes.simple.node;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeTuple;
-import java.util.BitSet;
/**
* The Start node represents the start of the function. For now, we do not
@@ -25,9 +26,8 @@ public class StartNode extends MultiNode {
@Override
public String label() { return "Start"; }
- @Override
- 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 isCFG() { return true; }
diff --git a/chapter09/src/main/java/com/seaofnodes/simple/node/StopNode.java b/chapter09/src/main/java/com/seaofnodes/simple/node/StopNode.java
index 6ed80df4..d79194d8 100644
--- a/chapter09/src/main/java/com/seaofnodes/simple/node/StopNode.java
+++ b/chapter09/src/main/java/com/seaofnodes/simple/node/StopNode.java
@@ -1,9 +1,10 @@
package com.seaofnodes.simple.node;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.IterPeeps;
-import java.util.BitSet;
public class StopNode extends Node {
@@ -20,12 +21,12 @@ public class StopNode extends Node {
}
@Override
- StringBuilder _print1(StringBuilder sb, BitSet visited) {
- if( ret()!=null ) return ret()._print0(sb, visited);
- sb.append("Stop[ ");
+ protected ExprPrinter<Node> _print1(ExprPrinter<Node> p) {
+ if( ret()!=null ) return p.n(ret());
+ p.p("Stop[ ");
for( Node ret : _inputs )
- ret._print0(sb, visited).append(" ");
- return sb.append("]");
+ p.n(ret).p(" ");
+ return p.p("]");
}
@Override public boolean isCFG() { return true; }
diff --git a/chapter09/src/main/java/com/seaofnodes/simple/node/SubNode.java b/chapter09/src/main/java/com/seaofnodes/simple/node/SubNode.java
index eeec5e1d..6fa87a07 100644
--- a/chapter09/src/main/java/com/seaofnodes/simple/node/SubNode.java
+++ b/chapter09/src/main/java/com/seaofnodes/simple/node/SubNode.java
@@ -1,21 +1,16 @@
package com.seaofnodes.simple.node;
+
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeInteger;
-import java.util.BitSet;
public class SubNode extends Node {
public SubNode(Node lhs, Node rhs) { super(null, lhs, rhs); }
@Override public String label() { return "Sub"; }
- @Override
- StringBuilder _print1(StringBuilder sb, BitSet visited) {
- in(1)._print0(sb.append("("), visited);
- in(2)._print0(sb.append("-"), visited);
- return sb.append(")");
- }
+ @Override protected String format() { return "(%1-%2)"; }
@Override
public Type compute() {
diff --git a/chapter09/src/main/java/com/seaofnodes/simple/print/SimpleGraphAdapter.java b/chapter09/src/main/java/com/seaofnodes/simple/print/SimpleGraphAdapter.java
index df46cc6b..64b78766 100644
--- a/chapter09/src/main/java/com/seaofnodes/simple/print/SimpleGraphAdapter.java
+++ b/chapter09/src/main/java/com/seaofnodes/simple/print/SimpleGraphAdapter.java
@@ -1,41 +1,19 @@
package com.seaofnodes.simple.print;
import com.seaofnodes.graph.GraphAdapter;
-import com.seaofnodes.graph.GraphSnapshot;
import com.seaofnodes.graph.GraphSnapshot.*;
import com.seaofnodes.simple.node.*;
import com.seaofnodes.simple.node.Node;
-import java.util.ArrayList;
/** Chapter 9's view of the IR; browser, transport and layout are shared. */
public class SimpleGraphAdapter extends GraphAdapter<Node> {
- @Override protected boolean dead(Node n) { return n.isDead(); }
- @Override protected int id(Node n) { return n._nid; }
- @Override protected int nIns(Node n) { return n.nIns(); }
- @Override protected Node in(Node n, int idx) { return n.in(idx); }
- @Override protected int nOuts(Node n) { return n.nOuts(); }
- @Override protected Node out(Node n, int idx) { return n.out(idx); }
- @Override protected int nDeps(Node n) { return n.nDeps(); }
- @Override protected Node dep(Node n, int idx) { return n.dep(idx); }
- private ArrayList<Edge> edges(Node n) {
- var edges = new ArrayList<Edge>();
- String[] names = n instanceof ScopeNode scope && n.nIns() != 0 ? scope.reverseNames() : null;
- for( int i = 0; i < n.nIns(); i++ ) {
- String name = names == null || i >= names.length ? null : names[i];
- edges.add(new Edge(i, ref(n.in(i)), role(n, i), name));
- }
- return edges;
+ @Override protected String[] edgeNames(Node n) {
+ return n instanceof ScopeNode scope && n.nIns()!=0 ? scope.reverseNames() : null;
}
+ @Override protected int projectionIndex(Node n) { return n instanceof ProjNode p ? p._idx : -1; }
- @Override protected GraphSnapshot.Node desc(Node n) {
- Projection proj = n instanceof ProjNode p ? new Projection(ref(n.in(0)), p._idx) : null;
- String label = n.label();
- return new GraphSnapshot.Node(n._nid, label == null ? n.getClass().getSimpleName() : label,
- n._type == null ? null : n._type.toString(), kind(n), edges(n), proj);
- }
-
- private Kind kind(Node n) {
+ @Override protected Kind kind(Node n) {
if( n instanceof StopNode ) return Kind.STOP;
if( n instanceof ScopeNode ) return Kind.SCOPE;
if( n instanceof StartNode ) return Kind.CTRL;
@@ -45,7 +23,7 @@ public class SimpleGraphAdapter extends GraphAdapter<Node> {
return n.isCFG() ? Kind.CTRL : Kind.DATA;
}
- private Role role(Node n, int i) {
+ @Override protected Role role(Node n, int i) {
if( n instanceof ScopeNode || n instanceof ConstantNode ) return Role.ASSOC;
if( n instanceof PhiNode ) return i == 0 ? Role.ASSOC : Role.DATA;
if( n instanceof ProjNode ) return n.isCFG() ? Role.CTRL : Role.DATA;
diff --git a/chapter10a/chapter10a.iml b/chapter10a/chapter10a.iml
index 3f930463..a58e898f 100644
--- a/chapter10a/chapter10a.iml
+++ b/chapter10a/chapter10a.iml
@@ -13,6 +13,7 @@
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
<orderEntry type="module" module-name="graph" />
+ <orderEntry type="module" module-name="print" />
<orderEntry type="module-library" scope="TEST">
<library name="JUnit4">
<CLASSES>
diff --git a/chapter10a/pom.xml b/chapter10a/pom.xml
index 141ff7d6..d0f1faae 100644
--- a/chapter10a/pom.xml
+++ b/chapter10a/pom.xml
@@ -13,5 +13,6 @@
<name>Chapter 10a</name>
<properties>
<simple.graph.directory>${project.basedir}/../graph</simple.graph.directory>
+ <simple.print.directory>${project.basedir}/../print</simple.print.directory>
</properties>
</project>
diff --git a/chapter10a/src/main/java/com/seaofnodes/simple/IRPrinter.java b/chapter10a/src/main/java/com/seaofnodes/simple/IRPrinter.java
index 1ac32b1a..621bc2d6 100644
--- a/chapter10a/src/main/java/com/seaofnodes/simple/IRPrinter.java
+++ b/chapter10a/src/main/java/com/seaofnodes/simple/IRPrinter.java
@@ -1,188 +1,31 @@
package com.seaofnodes.simple;
-import com.seaofnodes.simple.node.LoopNode;
-import com.seaofnodes.simple.node.Node;
-import com.seaofnodes.simple.node.ProjNode;
-
-import java.util.ArrayList;
-import java.util.BitSet;
-
-public 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 void _printLine( Node n, StringBuilder sb ) {
- sb.append("%4d %-7.7s ".formatted(n._nid,n.label()));
- if( n.isDead() ) {
- sb.append("DEAD\n");
- return;
- }
- for( Node def : n._inputs )
- sb.append(def==null ? "____ " : "%4d ".formatted(def._nid));
- for( int i = n._inputs.size(); i<3; i++ )
- sb.append(" ");
- sb.append(" [[ ");
- for( Node use : n._outputs )
- sb.append(use==null ? "____ " : "%4d ".formatted(use._nid));
- int lim = 5 - Math.max(n._inputs.size(),3);
- for( int i = n._outputs.size(); i<lim; i++ )
- sb.append(" ");
- sb.append(" ]] ");
- if( n._type!= null ) sb.append(n._type.str());
- sb.append("\n");
- }
-
- private static StringBuilder nodeId(StringBuilder sb, Node n) {
- sb.append("%%%d".formatted(n._nid));
- if (n instanceof ProjNode proj) {
- sb.append(".").append(proj._idx);
- }
- return sb;
- }
-
- // Print a node on 1 line, format is inspired by LLVM
- // %id: TYPE = NODE(inputs ....)
- // Nodes as referred to as %id
- public static void _printLineLlvmFormat( Node n, StringBuilder sb ) {
- nodeId(sb, n).append(": ");
- if( n.isDead() ) {
- sb.append("DEAD\n");
- return;
- }
- if( n._type!= null ) n._type.typeName(sb);
- sb.append(" = ").append( n.label() ).append( "(" );
- for( int i = 0; i < n._inputs.size(); i++ ) {
- Node def = n.in(i);
- if (i > 0)
- sb.append(", ");
- if (def == null) sb.append("_");
- else nodeId(sb, def);
- }
- sb.append(")").append("\n");
- }
-
- public static void printLine( Node n, StringBuilder sb, boolean llvmFormat ) {
- if (llvmFormat) _printLineLlvmFormat( n, sb );
- else _printLine ( n, sb );
- }
-
- public static String prettyPrint(Node node, int depth) {
- return prettyPrint( node, depth, false );
- }
-
- // Another bulk pretty-printer. Makes more effort at basic-block grouping.
- public static String prettyPrint( Node node, int depth, boolean llvmFormat ) {
- // First, a Breadth First Search at a fixed depth.
- BFS bfs = new BFS(node,depth);
- // Convert just that set to a post-order
- ArrayList<Node> rpos = new ArrayList<>();
- BitSet visit = new BitSet();
- for( int i=bfs._lim; i< bfs._bfs.size(); i++ )
- postOrd( bfs._bfs.get(i), rpos, visit, bfs._bs);
- // Reverse the post-order walk
- StringBuilder sb = new StringBuilder();
- boolean gap=false;
- for( int i=rpos.size()-1; i>=0; i-- ) {
- Node n = rpos.get(i);
- if( n.isCFG() || n.isMultiHead() ) {
- if( !gap ) sb.append("\n"); // Blank before multihead
- printLine( n, sb, llvmFormat ); // Print head
- while( --i >= 0 ) {
- Node t = rpos.get(i);
- if( !t.isMultiTail() ) { i++; break; }
- printLine( t, sb, llvmFormat );
- }
- sb.append("\n"); // Blank after multitail
- gap = true;
- } else {
- printLine( n, sb, llvmFormat );
- gap = false;
- }
- }
- return sb.toString();
- }
-
- private static void postOrd(Node n, ArrayList<Node> rpos, BitSet visit, BitSet bfs) {
- if( !bfs.get(n._nid) )
- return; // Not in the BFS visit
- if( visit.get(n._nid) ) return; // Already post-order walked
- visit.set(n._nid);
- // First walk the CFG, then everything
- if( n.isCFG() ) {
- for( Node use : n._outputs )
- if( use!=null && use.isCFG() && use.nOuts()>=1 && !(use._outputs.get(0) instanceof LoopNode) )
- postOrd(use, rpos,visit,bfs);
- for( Node use : n._outputs )
- if( use!=null && use.isCFG() )
- postOrd(use,rpos,visit,bfs);
- }
- for( Node use : n._outputs )
- if( use != null )
- postOrd(use, rpos,visit,bfs);
- // Post-order
- rpos.add(n);
- }
-
- // Breadth-first search, broken out in a class to keep in more independent.
- // Maintains a root-set of Nodes at the limit (or past by 1 if MultiHead).
- public static class BFS {
- // A breadth first search, plus MultiHeads for any MultiTails
- public final ArrayList<Node> _bfs;
- public final BitSet _bs; // Visited members by node id
- public final int _depth; // Depth limit
- public final int _lim; // From here to _bfs._len can be roots for a reverse search
- public BFS( Node base, int d ) {
- _depth = d;
- _bfs = new ArrayList<>();
- _bs = new BitSet();
-
- add(base); // Prime the pump
- int idx=0, lim=1; // Limit is where depth counter changes
- while( idx < _bfs.size() ) { // Ran out of nodes below depth
- Node n = _bfs.get(idx++);
- for( Node def : n._inputs )
- if( def!=null && !_bs.get(def._nid) )
- add(def);
- if( idx==lim ) { // Depth counter changes at limit
- if( --d < 0 )
- break; // Ran out of depth
- lim = _bfs.size(); // New depth limit
- }
- }
- // Toss things past the limit except multi-heads
- while( idx < _bfs.size() ) {
- Node n = _bfs.get(idx);
- if( n.isMultiHead() ) idx++;
- else del(idx);
- }
- // Root set is any node with no inputs in the visited set
- lim = _bfs.size();
- for( int i=_bfs.size()-1; i>=0; i-- )
- if( !any_visited(_bfs.get(i)) )
- swap( i,--lim);
- _lim = lim;
- }
- void swap( int x, int y ) {
- if( x==y ) return;
- Node tx = _bfs.get(x);
- Node ty = _bfs.get(y);
- _bfs.set(x,ty);
- _bfs.set(y,tx);
- }
- void add(Node n) {
- _bfs.add(n);
- _bs.set(n._nid);
- }
- void del(int idx) {
- Node n = Utils.del(_bfs, idx);
- _bs.clear(n._nid);
- }
- boolean any_visited( Node n ) {
- for( Node def : n._inputs )
- if( def!=null && _bs.get(def._nid) )
- return true;
- return false;
- }
- }
+import com.seaofnodes.print.IRAdapter;
+import com.seaofnodes.simple.node.*;
+
+/** 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 String type(Node n) { return n._type==null ? "" : n._type.str(); }
+ @Override public int inputColumns() { return 3; }
+ @Override public Kind kind(Node n) {
+ if( n instanceof StartNode ) return Kind.START;
+ if( n instanceof StopNode ) return Kind.STOP;
+ if( n instanceof LoopNode ) return Kind.LOOP;
+ if( n instanceof RegionNode ) return Kind.REGION;
+ if( n instanceof PhiNode ) return Kind.PHI;
+ if( n instanceof ReturnNode ) return Kind.RETURN;
+ if( n instanceof ConstantNode ) return Kind.CONSTANT;
+ if( n instanceof ProjNode ) return n.isCFG() ? Kind.CPROJ : Kind.PROJ;
+ if( n.isCFG() ) 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;
+ return n._nid;
+ }
+
+ public static String prettyPrint(Node n, int depth) { return PRINT.prettyPrint(n,depth); }
}
diff --git a/chapter10a/src/main/java/com/seaofnodes/simple/node/AddNode.java b/chapter10a/src/main/java/com/seaofnodes/simple/node/AddNode.java
index de5044d7..e235d288 100644
--- a/chapter10a/src/main/java/com/seaofnodes/simple/node/AddNode.java
+++ b/chapter10a/src/main/java/com/seaofnodes/simple/node/AddNode.java
@@ -1,20 +1,15 @@
package com.seaofnodes.simple.node;
+
import com.seaofnodes.simple.type.*;
-import java.util.BitSet;
public class AddNode extends Node {
public AddNode(Node lhs, Node rhs) { super(null, lhs, rhs); }
@Override public String label() { return "Add"; }
- @Override
- StringBuilder _print1(StringBuilder sb, BitSet visited) {
- in(1)._print0(sb.append("("), visited);
- in(2)._print0(sb.append("+"), visited);
- return sb.append(")");
- }
+ @Override protected String format() { return "(%1+%2)"; }
@Override
diff --git a/chapter10a/src/main/java/com/seaofnodes/simple/node/BoolNode.java b/chapter10a/src/main/java/com/seaofnodes/simple/node/BoolNode.java
index bf0d3a84..63452dba 100644
--- a/chapter10a/src/main/java/com/seaofnodes/simple/node/BoolNode.java
+++ b/chapter10a/src/main/java/com/seaofnodes/simple/node/BoolNode.java
@@ -1,10 +1,11 @@
package com.seaofnodes.simple.node;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeInteger;
import com.seaofnodes.simple.type.TypeMemPtr;
-import java.util.BitSet;
abstract public class BoolNode extends Node {
@@ -17,11 +18,8 @@ abstract public class BoolNode extends Node {
@Override
public String label() { return getClass().getSimpleName(); }
- @Override
- 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/chapter10a/src/main/java/com/seaofnodes/simple/node/CastNode.java b/chapter10a/src/main/java/com/seaofnodes/simple/node/CastNode.java
index fec540f7..c1faf210 100644
--- a/chapter10a/src/main/java/com/seaofnodes/simple/node/CastNode.java
+++ b/chapter10a/src/main/java/com/seaofnodes/simple/node/CastNode.java
@@ -1,10 +1,11 @@
package com.seaofnodes.simple.node;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeInteger;
import com.seaofnodes.simple.IterPeeps;
-import java.util.BitSet;
// Upcast (join) the input to a t. Used after guard test to lift an input.
// Can also be used to make a type-assertion if ctrl is null.
@@ -18,12 +19,9 @@ public class CastNode extends Node {
@Override public String label() { return "("+_t.str()+")"; }
- @Override
- public String uniqueName() { return "Cast_" + _nid; }
- @Override
- StringBuilder _print1(StringBuilder sb, BitSet visited) {
- return in(1)._print0(sb.append(label()), visited);
+ @Override protected ExprPrinter<Node> _print1(ExprPrinter<Node> p) {
+ return p.p(label()).n(in(1));
}
@Override
diff --git a/chapter10a/src/main/java/com/seaofnodes/simple/node/ConstantNode.java b/chapter10a/src/main/java/com/seaofnodes/simple/node/ConstantNode.java
index d760c0df..426736ed 100644
--- a/chapter10a/src/main/java/com/seaofnodes/simple/node/ConstantNode.java
+++ b/chapter10a/src/main/java/com/seaofnodes/simple/node/ConstantNode.java
@@ -1,9 +1,10 @@
package com.seaofnodes.simple.node;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.Parser;
import com.seaofnodes.simple.type.Type;
-import java.util.BitSet;
/**
* A Constant node represents a constant value. At present, the only constants
@@ -24,15 +25,16 @@ public class ConstantNode extends Node {
_con = type;
}
- @Override
- public String label() { return "#"+_con; }
+ @Override protected String repeatName() {
+ return _con==null || _con.toString().length()<=32 ? null : uniqueName();
+ }
@Override
- public String uniqueName() { return "Con_" + _nid; }
+ public String label() { return "Con"; }
- @Override
- StringBuilder _print1(StringBuilder sb, BitSet visited) {
- return _con.print(sb);
+
+ @Override protected ExprPrinter<Node> _print1(ExprPrinter<Node> p) {
+ return p.p(_con);
}
@Override public boolean isMultiTail() { return true; }
diff --git a/chapter10a/src/main/java/com/seaofnodes/simple/node/DivNode.java b/chapter10a/src/main/java/com/seaofnodes/simple/node/DivNode.java
index 6cee90ad..d7244ace 100644
--- a/chapter10a/src/main/java/com/seaofnodes/simple/node/DivNode.java
+++ b/chapter10a/src/main/java/com/seaofnodes/simple/node/DivNode.java
@@ -1,21 +1,16 @@
package com.seaofnodes.simple.node;
+
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeInteger;
-import java.util.BitSet;
public class DivNode extends Node {
public DivNode(Node lhs, Node rhs) { super(null, lhs, rhs); }
@Override public String label() { return "Div"; }
- @Override
- StringBuilder _print1(StringBuilder sb, BitSet visited) {
- in(1)._print0(sb.append("("), visited);
- in(2)._print0(sb.append("/"), visited);
- return sb.append(")");
- }
+ @Override protected String format() { return "(%1/%2)"; }
@Override
public Type compute() {
diff --git a/chapter10a/src/main/java/com/seaofnodes/simple/node/IfNode.java b/chapter10a/src/main/java/com/seaofnodes/simple/node/IfNode.java
index 1cf4ddaf..45f695a5 100644
--- a/chapter10a/src/main/java/com/seaofnodes/simple/node/IfNode.java
+++ b/chapter10a/src/main/java/com/seaofnodes/simple/node/IfNode.java
@@ -1,10 +1,10 @@
package com.seaofnodes.simple.node;
+
import com.seaofnodes.simple.IterPeeps;
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeInteger;
import com.seaofnodes.simple.type.TypeTuple;
-import java.util.BitSet;
public class IfNode extends MultiNode {
@@ -16,11 +16,7 @@ public class IfNode extends MultiNode {
@Override
public String label() { return "If"; }
- @Override
- StringBuilder _print1(StringBuilder sb, BitSet visited) {
- sb.append("if( ");
- return in(1)._print0(sb, visited).append(" )");
- }
+ @Override protected String format() { return "if( %1 )"; }
@Override public boolean isCFG() { return true; }
@Override public boolean isMultiHead() { return true; }
diff --git a/chapter10a/src/main/java/com/seaofnodes/simple/node/LoadNode.java b/chapter10a/src/main/java/com/seaofnodes/simple/node/LoadNode.java
index 001f4bf6..31c7699c 100644
--- a/chapter10a/src/main/java/com/seaofnodes/simple/node/LoadNode.java
+++ b/chapter10a/src/main/java/com/seaofnodes/simple/node/LoadNode.java
@@ -1,8 +1,9 @@
package com.seaofnodes.simple.node;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.type.Type;
-import java.util.BitSet;
/**
* Load represents extracting a value from inside a memory object,
@@ -44,7 +45,7 @@ public class LoadNode extends MemOpNode {
public String label() { return "Load"; }
@Override
- 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/chapter10a/src/main/java/com/seaofnodes/simple/node/MinusNode.java b/chapter10a/src/main/java/com/seaofnodes/simple/node/MinusNode.java
index 8b1b73bf..5b65b3fb 100644
--- a/chapter10a/src/main/java/com/seaofnodes/simple/node/MinusNode.java
+++ b/chapter10a/src/main/java/com/seaofnodes/simple/node/MinusNode.java
@@ -1,20 +1,16 @@
package com.seaofnodes.simple.node;
+
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeInteger;
-import java.util.BitSet;
public class MinusNode extends Node {
public MinusNode(Node in) { super(null, in); }
@Override public String label() { return "Minus"; }
- @Override
- 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/chapter10a/src/main/java/com/seaofnodes/simple/node/MulNode.java b/chapter10a/src/main/java/com/seaofnodes/simple/node/MulNode.java
index 97721ce3..5592c52d 100644
--- a/chapter10a/src/main/java/com/seaofnodes/simple/node/MulNode.java
+++ b/chapter10a/src/main/java/com/seaofnodes/simple/node/MulNode.java
@@ -1,21 +1,16 @@
package com.seaofnodes.simple.node;
+
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeInteger;
-import java.util.BitSet;
public class MulNode extends Node {
public MulNode(Node lhs, Node rhs) { super(null, lhs, rhs); }
@Override public String label() { return "Mul"; }
- @Override
- StringBuilder _print1(StringBuilder sb, BitSet visited) {
- in(1)._print0(sb.append("("), visited);
- in(2)._print0(sb.append("*"), visited);
- return sb.append(")");
- }
+ @Override protected String format() { return "(%1*%2)"; }
@Override
public Type compute() {
diff --git a/chapter10a/src/main/java/com/seaofnodes/simple/node/NewNode.java b/chapter10a/src/main/java/com/seaofnodes/simple/node/NewNode.java
index b13462f5..857920bc 100644
--- a/chapter10a/src/main/java/com/seaofnodes/simple/node/NewNode.java
+++ b/chapter10a/src/main/java/com/seaofnodes/simple/node/NewNode.java
@@ -1,9 +1,10 @@
package com.seaofnodes.simple.node;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeMemPtr;
-import java.util.BitSet;
public class NewNode extends Node {
@@ -17,10 +18,8 @@ public class NewNode extends Node {
@Override
public String label() { return "new"; }
- @Override
- StringBuilder _print1(StringBuilder sb, BitSet visited) {
- sb.append("new ");
- return sb.append(_ptr._obj.str());
+ @Override protected ExprPrinter<Node> _print1(ExprPrinter<Node> p) {
+ return p.p("new ").p(_ptr._obj.str());
}
@Override
diff --git a/chapter10a/src/main/java/com/seaofnodes/simple/node/Node.java b/chapter10a/src/main/java/com/seaofnodes/simple/node/Node.java
index 0a64a7b9..d0752af1 100644
--- a/chapter10a/src/main/java/com/seaofnodes/simple/node/Node.java
+++ b/chapter10a/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.Parser;
import com.seaofnodes.simple.IRPrinter;
@@ -15,14 +17,7 @@ import java.util.function.Function;
* The Node class provides common functionality used by all subtypes.
* Subtypes of Node specialize by overriding methods.
*/
-public abstract class Node implements Cloneable {
-
- /**
- * Each node has a unique dense Node ID within a compilation context
- * The ID is useful for debugging, for using as an offset in a bitvector,
- * as well as for computing equality of nodes (to be implemented later).
- */
- public int _nid;
+public abstract class Node extends BaseNode<Node> implements Cloneable {
/**
* Inputs to the node. These are use-def references to Nodes.
@@ -44,14 +39,12 @@ public abstract class Node implements Cloneable {
*/
public ArrayList<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;
-
/**
* A private Global Static mutable counter, for unique node id generation.
* To make the compiler multithreaded, this field will have to move into a TLS.
@@ -61,7 +54,7 @@ public abstract class Node implements Cloneable {
public static int UID() { return UNIQUE_ID; }
protected Node(Node... inputs) {
- _nid = UNIQUE_ID++; // allocate unique dense ID
+ super(UNIQUE_ID++); // allocate unique dense ID
_inputs = new ArrayList<>();
Collections.addAll(_inputs,inputs);
_outputs = new ArrayList<>();
@@ -73,42 +66,6 @@ public abstract class Node implements Cloneable {
// Easy reading label for debugger, e.g. "Add" or "Region" or "EQ"
public abstract String label();
- // Unique label for debugging, e.g. "Add12" or "Region30" or "EQ99"
- public String uniqueName() {
- return label() + _nid;
- }
-
- // ------------------------------------------------------------------------
-
- // 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. This version will fail on cycles, which we will
- // correct later when we can parse programs with loops. We print with a
- // 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.
- 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 StringBuilder _print1(StringBuilder sb, BitSet visited);
-
public String p(int depth) { return IRPrinter.prettyPrint(this,depth); }
public boolean isMultiHead() { return false; }
@@ -117,6 +74,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
@@ -131,8 +90,6 @@ public abstract class Node implements Cloneable {
public boolean isUnused() { return nOuts() == 0; }
- public boolean isCFG() { return false; }
-
public boolean isMem() { return false; }
/**
@@ -257,7 +214,6 @@ public abstract class Node implements Cloneable {
// Test "keep" status
public boolean iskeep() { return Utils.find(_outputs,null) != -1; }
-
// Replace self with nnn in the graph, making 'this' go dead
public void subsume( Node nnn ) {
assert nnn!=this;
@@ -388,7 +344,6 @@ public abstract class Node implements Cloneable {
return old;
}
-
/**
* This function rewrites the current Node into a more "idealized" form.
* This is the bulk of our peephole rewrite rules, and we use this to
@@ -436,7 +391,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
@@ -474,7 +428,6 @@ public abstract class Node implements Cloneable {
_deps.clear();
}
-
// Global Value Numbering. Hash over opcode and inputs; hits in this table
// are structurally equal.
public static final HashMap<Node,Node> GVN = new HashMap<>();
@@ -496,7 +449,6 @@ public abstract class Node implements Cloneable {
// and can assume "this!=n" and has the same Java class.
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
@@ -512,7 +464,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;
@@ -526,7 +477,6 @@ public abstract class Node implements Cloneable {
// Subclasses add extra hash info (such as ConstantNodes constant)
int hash() { return 0; }
-
// ------------------------------------------------------------------------
// Peephole utilities
@@ -555,7 +505,6 @@ public abstract class Node implements Cloneable {
return true;
}
-
/**
* Immediate dominator tree depth, used to approximate a real IDOM depth
* during parsing where we do not have the whole program, and also
@@ -585,7 +534,6 @@ public abstract class Node implements Cloneable {
return _idepth = (char)depth;
}
-
// Return the immediate dominator of this Node.
Node idom() { return in(0); }
@@ -621,7 +569,6 @@ public abstract class Node implements Cloneable {
ITER_CNT = ITER_NOP_CNT = 0;
}
-
// Utility to walk the entire graph applying a function; return the first
// not-null result.
private static final BitSet WVISIT = new BitSet();
diff --git a/chapter10a/src/main/java/com/seaofnodes/simple/node/NotNode.java b/chapter10a/src/main/java/com/seaofnodes/simple/node/NotNode.java
index 83141836..5e556390 100644
--- a/chapter10a/src/main/java/com/seaofnodes/simple/node/NotNode.java
+++ b/chapter10a/src/main/java/com/seaofnodes/simple/node/NotNode.java
@@ -1,19 +1,15 @@
package com.seaofnodes.simple.node;
+
import com.seaofnodes.simple.Utils;
import com.seaofnodes.simple.type.*;
-import java.util.BitSet;
public class NotNode extends Node {
public NotNode(Node in) { super(null, in); }
@Override public String label() { return "Not"; }
- @Override
- 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/chapter10a/src/main/java/com/seaofnodes/simple/node/PhiNode.java b/chapter10a/src/main/java/com/seaofnodes/simple/node/PhiNode.java
index c52fad49..24a72aa4 100644
--- a/chapter10a/src/main/java/com/seaofnodes/simple/node/PhiNode.java
+++ b/chapter10a/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.type.Type;
import com.seaofnodes.simple.type.TypeMem;
import com.seaofnodes.simple.Utils;
-import java.util.BitSet;
public class PhiNode extends Node {
@@ -19,18 +20,12 @@ public class PhiNode extends Node {
@Override public String label() { return "Phi_"+_label; }
@Override
- 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();
}
Node region() { return in(0); }
diff --git a/chapter10a/src/main/java/com/seaofnodes/simple/node/ProjNode.java b/chapter10a/src/main/java/com/seaofnodes/simple/node/ProjNode.java
index 735fcdf3..a2632110 100644
--- a/chapter10a/src/main/java/com/seaofnodes/simple/node/ProjNode.java
+++ b/chapter10a/src/main/java/com/seaofnodes/simple/node/ProjNode.java
@@ -1,10 +1,11 @@
package com.seaofnodes.simple.node;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeMem;
import com.seaofnodes.simple.type.TypeTuple;
-import java.util.BitSet;
public class ProjNode extends Node {
@@ -24,7 +25,7 @@ public class ProjNode extends Node {
public String label() { return _label; }
@Override
- StringBuilder _print1(StringBuilder sb, BitSet visited) { return sb.append(_label); }
+ protected ExprPrinter<Node> _print1(ExprPrinter<Node> p) { return p.p(_label); }
@Override public boolean isCFG() { return _idx==0 || ctrl() instanceof IfNode; }
@Override public boolean isMultiTail() { return in(0).isMultiHead(); }
diff --git a/chapter10a/src/main/java/com/seaofnodes/simple/node/RegionNode.java b/chapter10a/src/main/java/com/seaofnodes/simple/node/RegionNode.java
index a6b8d834..8b52494a 100644
--- a/chapter10a/src/main/java/com/seaofnodes/simple/node/RegionNode.java
+++ b/chapter10a/src/main/java/com/seaofnodes/simple/node/RegionNode.java
@@ -1,12 +1,13 @@
package com.seaofnodes.simple.node;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.IterPeeps;
import com.seaofnodes.simple.Utils;
import com.seaofnodes.simple.type.Type;
import java.util.ArrayList;
import java.util.Arrays;
-import java.util.BitSet;
public class RegionNode extends Node {
@@ -15,9 +16,8 @@ public class RegionNode extends Node {
@Override
public String label() { return "Region"; }
- @Override
- StringBuilder _print1(StringBuilder sb, BitSet visited) {
- return sb.append(label()).append(_nid);
+ @Override protected ExprPrinter<Node> _print1(ExprPrinter<Node> p) {
+ return p.p(label()).p(_nid);
}
@Override public boolean isCFG() { return true; }
diff --git a/chapter10a/src/main/java/com/seaofnodes/simple/node/ReturnNode.java b/chapter10a/src/main/java/com/seaofnodes/simple/node/ReturnNode.java
index 96d58599..ef4ddb3a 100644
--- a/chapter10a/src/main/java/com/seaofnodes/simple/node/ReturnNode.java
+++ b/chapter10a/src/main/java/com/seaofnodes/simple/node/ReturnNode.java
@@ -1,8 +1,9 @@
package com.seaofnodes.simple.node;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.type.*;
-import java.util.BitSet;
/** Keeps all preceding memory effects and the return value alive: {ctrl, $mem, value}. */
public class ReturnNode extends Node {
@@ -19,10 +20,10 @@ public class ReturnNode extends Node {
public String label() { return "Return"; }
@Override
- StringBuilder _print1(StringBuilder sb, BitSet visited) {
- sb.append("return ");
- expr()._print0(sb, visited);
- return sb.append(";");
+ protected ExprPrinter<Node> _print1(ExprPrinter<Node> p) {
+ p.p("return ");
+ p.n(expr());
+ return p.p(";");
}
@Override public boolean isCFG() { return true; }
diff --git a/chapter10a/src/main/java/com/seaofnodes/simple/node/ScopeNode.java b/chapter10a/src/main/java/com/seaofnodes/simple/node/ScopeNode.java
index 455f4b3a..d567feb5 100644
--- a/chapter10a/src/main/java/com/seaofnodes/simple/node/ScopeNode.java
+++ b/chapter10a/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.IterPeeps;
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.Utils;
@@ -42,20 +44,19 @@ public class ScopeNode extends Node {
@Override public String label() { return "Scope"; }
@Override
- StringBuilder _print1(StringBuilder sb, BitSet visited) {
- sb.append("Scope[ ");
+ protected ExprPrinter<Node> _print1(ExprPrinter<Node> p) {
+ p.p("Scope[ ");
String[] names = reverseNames();
for( int j=0; j<nIns(); j++ ) {
- sb.append(names[j]).append(":");
+ p.p(names[j]).p(":");
Node n = in(j);
while( n instanceof ScopeNode loop ) {
- sb.append("Lazy_");
+ p.p("Lazy_");
n = loop.in(j);
}
- n._print0(sb, visited).append(" ");
+ p.n(n).p(" ");
}
- sb.setLength(sb.length()-1);
- return sb.append("]");
+ return p.unchar(' ').p("]");
}
/**
diff --git a/chapter10a/src/main/java/com/seaofnodes/simple/node/StartNode.java b/chapter10a/src/main/java/com/seaofnodes/simple/node/StartNode.java
index 1ca52af0..3404f111 100644
--- a/chapter10a/src/main/java/com/seaofnodes/simple/node/StartNode.java
+++ b/chapter10a/src/main/java/com/seaofnodes/simple/node/StartNode.java
@@ -1,7 +1,8 @@
package com.seaofnodes.simple.node;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.type.*;
-import java.util.BitSet;
/** The entry tuple: control, initial whole-memory state, and argument. */
public class StartNode extends MultiNode {
@@ -15,9 +16,8 @@ public class StartNode extends MultiNode {
@Override
public String label() { return "Start"; }
- @Override
- 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 isCFG() { return true; }
diff --git a/chapter10a/src/main/java/com/seaofnodes/simple/node/StopNode.java b/chapter10a/src/main/java/com/seaofnodes/simple/node/StopNode.java
index cb4126f5..4b4e9615 100644
--- a/chapter10a/src/main/java/com/seaofnodes/simple/node/StopNode.java
+++ b/chapter10a/src/main/java/com/seaofnodes/simple/node/StopNode.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.Type;
import com.seaofnodes.simple.IterPeeps;
-import java.util.BitSet;
public class StopNode extends Node {
@@ -22,12 +23,12 @@ public class StopNode extends Node {
}
@Override
- StringBuilder _print1(StringBuilder sb, BitSet visited) {
- if( ret()!=null ) return ret()._print0(sb, visited);
- sb.append("Stop[ ");
+ protected ExprPrinter<Node> _print1(ExprPrinter<Node> p) {
+ if( ret()!=null ) return p.n(ret());
+ p.p("Stop[ ");
for( Node ret : _inputs )
- ret._print0(sb, visited).append(" ");
- return sb.append("]");
+ p.n(ret).p(" ");
+ return p.p("]");
}
@Override public boolean isCFG() { return true; }
diff --git a/chapter10a/src/main/java/com/seaofnodes/simple/node/StoreNode.java b/chapter10a/src/main/java/com/seaofnodes/simple/node/StoreNode.java
index 4bc67c3c..71eb0842 100644
--- a/chapter10a/src/main/java/com/seaofnodes/simple/node/StoreNode.java
+++ b/chapter10a/src/main/java/com/seaofnodes/simple/node/StoreNode.java
@@ -1,8 +1,9 @@
package com.seaofnodes.simple.node;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.type.*;
-import java.util.BitSet;
/**
* Store represents setting a value to a memory based object, in chapter 10
@@ -27,8 +28,8 @@ public class StoreNode extends MemOpNode {
public Node val() { return in(3); }
@Override
- 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/chapter10a/src/main/java/com/seaofnodes/simple/node/SubNode.java b/chapter10a/src/main/java/com/seaofnodes/simple/node/SubNode.java
index eeec5e1d..6fa87a07 100644
--- a/chapter10a/src/main/java/com/seaofnodes/simple/node/SubNode.java
+++ b/chapter10a/src/main/java/com/seaofnodes/simple/node/SubNode.java
@@ -1,21 +1,16 @@
package com.seaofnodes.simple.node;
+
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeInteger;
-import java.util.BitSet;
public class SubNode extends Node {
public SubNode(Node lhs, Node rhs) { super(null, lhs, rhs); }
@Override public String label() { return "Sub"; }
- @Override
- StringBuilder _print1(StringBuilder sb, BitSet visited) {
- in(1)._print0(sb.append("("), visited);
- in(2)._print0(sb.append("-"), visited);
- return sb.append(")");
- }
+ @Override protected String format() { return "(%1-%2)"; }
@Override
public Type compute() {
diff --git a/chapter10a/src/main/java/com/seaofnodes/simple/print/SimpleGraphAdapter.java b/chapter10a/src/main/java/com/seaofnodes/simple/print/SimpleGraphAdapter.java
index 600e9c73..92d970d8 100644
--- a/chapter10a/src/main/java/com/seaofnodes/simple/print/SimpleGraphAdapter.java
+++ b/chapter10a/src/main/java/com/seaofnodes/simple/print/SimpleGraphAdapter.java
@@ -1,42 +1,20 @@
package com.seaofnodes.simple.print;
import com.seaofnodes.graph.GraphAdapter;
-import com.seaofnodes.graph.GraphSnapshot;
import com.seaofnodes.graph.GraphSnapshot.*;
import com.seaofnodes.simple.node.*;
import com.seaofnodes.simple.node.Node;
import com.seaofnodes.simple.type.TypeMem;
-import java.util.ArrayList;
/** Chapter 10's view of the IR; browser, transport and layout are shared. */
public class SimpleGraphAdapter extends GraphAdapter<Node> {
- @Override protected boolean dead(Node n) { return n.isDead(); }
- @Override protected int id(Node n) { return n._nid; }
- @Override protected int nIns(Node n) { return n.nIns(); }
- @Override protected Node in(Node n, int idx) { return n.in(idx); }
- @Override protected int nOuts(Node n) { return n.nOuts(); }
- @Override protected Node out(Node n, int idx) { return n.out(idx); }
- @Override protected int nDeps(Node n) { return n.nDeps(); }
- @Override protected Node dep(Node n, int idx) { return n.dep(idx); }
- private ArrayList<Edge> edges(Node n) {
- var edges = new ArrayList<Edge>();
- String[] names = n instanceof ScopeNode scope && n.nIns() != 0 ? scope.reverseNames() : null;
- for( int i = 0; i < n.nIns(); i++ ) {
- String name = names == null || i >= names.length ? null : names[i];
- edges.add(new Edge(i, ref(n.in(i)), role(n, i), name));
- }
- return edges;
+ @Override protected String[] edgeNames(Node n) {
+ return n instanceof ScopeNode scope && n.nIns()!=0 ? scope.reverseNames() : null;
}
+ @Override protected int projectionIndex(Node n) { return n instanceof ProjNode p ? p._idx : -1; }
- @Override protected GraphSnapshot.Node desc(Node n) {
- Projection proj = n instanceof ProjNode p ? new Projection(ref(n.in(0)), p._idx) : null;
- String label = n.label();
- return new GraphSnapshot.Node(n._nid, label == null ? n.getClass().getSimpleName() : label,
- n._type == null ? null : n._type.toString(), kind(n), edges(n), proj);
- }
-
- private Kind kind(Node n) {
+ @Override protected Kind kind(Node n) {
if( n instanceof StopNode ) return Kind.STOP;
if( n instanceof ScopeNode ) return Kind.SCOPE;
if( n instanceof StartNode ) return Kind.CTRL;
@@ -46,7 +24,7 @@ public class SimpleGraphAdapter extends GraphAdapter<Node> {
return n.isCFG() ? Kind.CTRL : isMem(n) ? Kind.MEM : Kind.DATA;
}
- private Role role(Node n, int i) {
+ @Override protected Role role(Node n, int i) {
if( n instanceof ScopeNode || n instanceof ConstantNode ) return Role.ASSOC;
if( n instanceof PhiNode ) return i == 0 ? Role.ASSOC : isMem(n) ? Role.MEM : Role.DATA;
if( n instanceof ProjNode ) return n.isCFG() ? Role.CTRL : isMem(n) ? Role.MEM : Role.DATA;
diff --git a/chapter10b/chapter10b.iml b/chapter10b/chapter10b.iml
index 9d1eeeb2..74da25d0 100644
--- a/chapter10b/chapter10b.iml
+++ b/chapter10b/chapter10b.iml
@@ -13,6 +13,7 @@
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
<orderEntry type="module" module-name="graph" />
+ <orderEntry type="module" module-name="print" />
<orderEntry type="module-library" scope="TEST">
<library name="JUnit4">
<CLASSES>
diff --git a/chapter10b/pom.xml b/chapter10b/pom.xml
index fb7c947f..5378c5eb 100644
--- a/chapter10b/pom.xml
+++ b/chapter10b/pom.xml
@@ -13,5 +13,6 @@
<name>Chapter 10b</name>
<properties>
<simple.graph.directory>${project.basedir}/../graph</simple.graph.directory>
+ <simple.print.directory>${project.basedir}/../print</simple.print.directory>
</properties>
</project>
diff --git a/chapter10b/src/main/java/com/seaofnodes/simple/IRPrinter.java b/chapter10b/src/main/java/com/seaofnodes/simple/IRPrinter.java
index 1ac32b1a..d5ab15fe 100644
--- a/chapter10b/src/main/java/com/seaofnodes/simple/IRPrinter.java
+++ b/chapter10b/src/main/java/com/seaofnodes/simple/IRPrinter.java
@@ -1,188 +1,32 @@
package com.seaofnodes.simple;
-import com.seaofnodes.simple.node.LoopNode;
-import com.seaofnodes.simple.node.Node;
-import com.seaofnodes.simple.node.ProjNode;
-
-import java.util.ArrayList;
-import java.util.BitSet;
-
-public 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 void _printLine( Node n, StringBuilder sb ) {
- sb.append("%4d %-7.7s ".formatted(n._nid,n.label()));
- if( n.isDead() ) {
- sb.append("DEAD\n");
- return;
- }
- for( Node def : n._inputs )
- sb.append(def==null ? "____ " : "%4d ".formatted(def._nid));
- for( int i = n._inputs.size(); i<3; i++ )
- sb.append(" ");
- sb.append(" [[ ");
- for( Node use : n._outputs )
- sb.append(use==null ? "____ " : "%4d ".formatted(use._nid));
- int lim = 5 - Math.max(n._inputs.size(),3);
- for( int i = n._outputs.size(); i<lim; i++ )
- sb.append(" ");
- sb.append(" ]] ");
- if( n._type!= null ) sb.append(n._type.str());
- sb.append("\n");
- }
-
- private static StringBuilder nodeId(StringBuilder sb, Node n) {
- sb.append("%%%d".formatted(n._nid));
- if (n instanceof ProjNode proj) {
- sb.append(".").append(proj._idx);
- }
- return sb;
- }
-
- // Print a node on 1 line, format is inspired by LLVM
- // %id: TYPE = NODE(inputs ....)
- // Nodes as referred to as %id
- public static void _printLineLlvmFormat( Node n, StringBuilder sb ) {
- nodeId(sb, n).append(": ");
- if( n.isDead() ) {
- sb.append("DEAD\n");
- return;
- }
- if( n._type!= null ) n._type.typeName(sb);
- sb.append(" = ").append( n.label() ).append( "(" );
- for( int i = 0; i < n._inputs.size(); i++ ) {
- Node def = n.in(i);
- if (i > 0)
- sb.append(", ");
- if (def == null) sb.append("_");
- else nodeId(sb, def);
- }
- sb.append(")").append("\n");
- }
-
- public static void printLine( Node n, StringBuilder sb, boolean llvmFormat ) {
- if (llvmFormat) _printLineLlvmFormat( n, sb );
- else _printLine ( n, sb );
- }
-
- public static String prettyPrint(Node node, int depth) {
- return prettyPrint( node, depth, false );
- }
-
- // Another bulk pretty-printer. Makes more effort at basic-block grouping.
- public static String prettyPrint( Node node, int depth, boolean llvmFormat ) {
- // First, a Breadth First Search at a fixed depth.
- BFS bfs = new BFS(node,depth);
- // Convert just that set to a post-order
- ArrayList<Node> rpos = new ArrayList<>();
- BitSet visit = new BitSet();
- for( int i=bfs._lim; i< bfs._bfs.size(); i++ )
- postOrd( bfs._bfs.get(i), rpos, visit, bfs._bs);
- // Reverse the post-order walk
- StringBuilder sb = new StringBuilder();
- boolean gap=false;
- for( int i=rpos.size()-1; i>=0; i-- ) {
- Node n = rpos.get(i);
- if( n.isCFG() || n.isMultiHead() ) {
- if( !gap ) sb.append("\n"); // Blank before multihead
- printLine( n, sb, llvmFormat ); // Print head
- while( --i >= 0 ) {
- Node t = rpos.get(i);
- if( !t.isMultiTail() ) { i++; break; }
- printLine( t, sb, llvmFormat );
- }
- sb.append("\n"); // Blank after multitail
- gap = true;
- } else {
- printLine( n, sb, llvmFormat );
- gap = false;
- }
- }
- return sb.toString();
- }
-
- private static void postOrd(Node n, ArrayList<Node> rpos, BitSet visit, BitSet bfs) {
- if( !bfs.get(n._nid) )
- return; // Not in the BFS visit
- if( visit.get(n._nid) ) return; // Already post-order walked
- visit.set(n._nid);
- // First walk the CFG, then everything
- if( n.isCFG() ) {
- for( Node use : n._outputs )
- if( use!=null && use.isCFG() && use.nOuts()>=1 && !(use._outputs.get(0) instanceof LoopNode) )
- postOrd(use, rpos,visit,bfs);
- for( Node use : n._outputs )
- if( use!=null && use.isCFG() )
- postOrd(use,rpos,visit,bfs);
- }
- for( Node use : n._outputs )
- if( use != null )
- postOrd(use, rpos,visit,bfs);
- // Post-order
- rpos.add(n);
- }
-
- // Breadth-first search, broken out in a class to keep in more independent.
- // Maintains a root-set of Nodes at the limit (or past by 1 if MultiHead).
- public static class BFS {
- // A breadth first search, plus MultiHeads for any MultiTails
- public final ArrayList<Node> _bfs;
- public final BitSet _bs; // Visited members by node id
- public final int _depth; // Depth limit
- public final int _lim; // From here to _bfs._len can be roots for a reverse search
- public BFS( Node base, int d ) {
- _depth = d;
- _bfs = new ArrayList<>();
- _bs = new BitSet();
-
- add(base); // Prime the pump
- int idx=0, lim=1; // Limit is where depth counter changes
- while( idx < _bfs.size() ) { // Ran out of nodes below depth
- Node n = _bfs.get(idx++);
- for( Node def : n._inputs )
- if( def!=null && !_bs.get(def._nid) )
- add(def);
- if( idx==lim ) { // Depth counter changes at limit
- if( --d < 0 )
- break; // Ran out of depth
- lim = _bfs.size(); // New depth limit
- }
- }
- // Toss things past the limit except multi-heads
- while( idx < _bfs.size() ) {
- Node n = _bfs.get(idx);
- if( n.isMultiHead() ) idx++;
- else del(idx);
- }
- // Root set is any node with no inputs in the visited set
- lim = _bfs.size();
- for( int i=_bfs.size()-1; i>=0; i-- )
- if( !any_visited(_bfs.get(i)) )
- swap( i,--lim);
- _lim = lim;
- }
- void swap( int x, int y ) {
- if( x==y ) return;
- Node tx = _bfs.get(x);
- Node ty = _bfs.get(y);
- _bfs.set(x,ty);
- _bfs.set(y,tx);
- }
- void add(Node n) {
- _bfs.add(n);
- _bs.set(n._nid);
- }
- void del(int idx) {
- Node n = Utils.del(_bfs, idx);
- _bs.clear(n._nid);
- }
- boolean any_visited( Node n ) {
- for( Node def : n._inputs )
- if( def!=null && _bs.get(def._nid) )
- return true;
- return false;
- }
- }
+import com.seaofnodes.print.IRAdapter;
+import com.seaofnodes.simple.node.*;
+
+/** 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 String type(Node n) { return n._type==null ? "" : n._type.str(); }
+ @Override public int inputColumns() { return 3; }
+ @Override public String inputMark(Node n, Node def) { return n instanceof MemMergeNode && def instanceof MemMergeNode ? "^" : " "; }
+ @Override public Kind kind(Node n) {
+ if( n instanceof StartNode ) return Kind.START;
+ if( n instanceof StopNode ) return Kind.STOP;
+ if( n instanceof LoopNode ) return Kind.LOOP;
+ if( n instanceof RegionNode ) return Kind.REGION;
+ if( n instanceof PhiNode ) return Kind.PHI;
+ if( n instanceof ReturnNode ) return Kind.RETURN;
+ if( n instanceof ConstantNode ) return Kind.CONSTANT;
+ if( n instanceof ProjNode ) return n.isCFG() ? Kind.CPROJ : Kind.PROJ;
+ if( n.isCFG() ) 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;
+ return n._nid;
+ }
+
+ public static String prettyPrint(Node n, int depth) { return PRINT.prettyPrint(n,depth); }
}
diff --git a/chapter10b/src/main/java/com/seaofnodes/simple/node/AddNode.java b/chapter10b/src/main/java/com/seaofnodes/simple/node/AddNode.java
index de5044d7..e235d288 100644
--- a/chapter10b/src/main/java/com/seaofnodes/simple/node/AddNode.java
+++ b/chapter10b/src/main/java/com/seaofnodes/simple/node/AddNode.java
@@ -1,20 +1,15 @@
package com.seaofnodes.simple.node;
+
import com.seaofnodes.simple.type.*;
-import java.util.BitSet;
public class AddNode extends Node {
public AddNode(Node lhs, Node rhs) { super(null, lhs, rhs); }
@Override public String label() { return "Add"; }
- @Override
- StringBuilder _print1(StringBuilder sb, BitSet visited) {
- in(1)._print0(sb.append("("), visited);
- in(2)._print0(sb.append("+"), visited);
- return sb.append(")");
- }
+ @Override protected String format() { return "(%1+%2)"; }
@Override
diff --git a/chapter10b/src/main/java/com/seaofnodes/simple/node/BoolNode.java b/chapter10b/src/main/java/com/seaofnodes/simple/node/BoolNode.java
index bf0d3a84..63452dba 100644
--- a/chapter10b/src/main/java/com/seaofnodes/simple/node/BoolNode.java
+++ b/chapter10b/src/main/java/com/seaofnodes/simple/node/BoolNode.java
@@ -1,10 +1,11 @@
package com.seaofnodes.simple.node;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeInteger;
import com.seaofnodes.simple.type.TypeMemPtr;
-import java.util.BitSet;
abstract public class BoolNode extends Node {
@@ -17,11 +18,8 @@ abstract public class BoolNode extends Node {
@Override
public String label() { return getClass().getSimpleName(); }
- @Override
- 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/chapter10b/src/main/java/com/seaofnodes/simple/node/CastNode.java b/chapter10b/src/main/java/com/seaofnodes/simple/node/CastNode.java
index fec540f7..c1faf210 100644
--- a/chapter10b/src/main/java/com/seaofnodes/simple/node/CastNode.java
+++ b/chapter10b/src/main/java/com/seaofnodes/simple/node/CastNode.java
@@ -1,10 +1,11 @@
package com.seaofnodes.simple.node;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeInteger;
import com.seaofnodes.simple.IterPeeps;
-import java.util.BitSet;
// Upcast (join) the input to a t. Used after guard test to lift an input.
// Can also be used to make a type-assertion if ctrl is null.
@@ -18,12 +19,9 @@ public class CastNode extends Node {
@Override public String label() { return "("+_t.str()+")"; }
- @Override
- public String uniqueName() { return "Cast_" + _nid; }
- @Override
- StringBuilder _print1(StringBuilder sb, BitSet visited) {
- return in(1)._print0(sb.append(label()), visited);
+ @Override protected ExprPrinter<Node> _print1(ExprPrinter<Node> p) {
+ return p.p(label()).n(in(1));
}
@Override
diff --git a/chapter10b/src/main/java/com/seaofnodes/simple/node/ConstantNode.java b/chapter10b/src/main/java/com/seaofnodes/simple/node/ConstantNode.java
index d760c0df..426736ed 100644
--- a/chapter10b/src/main/java/com/seaofnodes/simple/node/ConstantNode.java
+++ b/chapter10b/src/main/java/com/seaofnodes/simple/node/ConstantNode.java
@@ -1,9 +1,10 @@
package com.seaofnodes.simple.node;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.Parser;
import com.seaofnodes.simple.type.Type;
-import java.util.BitSet;
/**
* A Constant node represents a constant value. At present, the only constants
@@ -24,15 +25,16 @@ public class ConstantNode extends Node {
_con = type;
}
- @Override
- public String label() { return "#"+_con; }
+ @Override protected String repeatName() {
+ return _con==null || _con.toString().length()<=32 ? null : uniqueName();
+ }
@Override
- public String uniqueName() { return "Con_" + _nid; }
+ public String label() { return "Con"; }
- @Override
- StringBuilder _print1(StringBuilder sb, BitSet visited) {
- return _con.print(sb);
+
+ @Override protected ExprPrinter<Node> _print1(ExprPrinter<Node> p) {
+ return p.p(_con);
}
@Override public boolean isMultiTail() { return true; }
diff --git a/chapter10b/src/main/java/com/seaofnodes/simple/node/DivNode.java b/chapter10b/src/main/java/com/seaofnodes/simple/node/DivNode.java
index 6cee90ad..d7244ace 100644
--- a/chapter10b/src/main/java/com/seaofnodes/simple/node/DivNode.java
+++ b/chapter10b/src/main/java/com/seaofnodes/simple/node/DivNode.java
@@ -1,21 +1,16 @@
package com.seaofnodes.simple.node;
+
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeInteger;
-import java.util.BitSet;
public class DivNode extends Node {
public DivNode(Node lhs, Node rhs) { super(null, lhs, rhs); }
@Override public String label() { return "Div"; }
- @Override
- StringBuilder _print1(StringBuilder sb, BitSet visited) {
- in(1)._print0(sb.append("("), visited);
- in(2)._print0(sb.append("/"), visited);
- return sb.append(")");
- }
+ @Override protected String format() { return "(%1/%2)"; }
@Override
public Type compute() {
diff --git a/chapter10b/src/main/java/com/seaofnodes/simple/node/IfNode.java b/chapter10b/src/main/java/com/seaofnodes/simple/node/IfNode.java
index 1cf4ddaf..45f695a5 100644
--- a/chapter10b/src/main/java/com/seaofnodes/simple/node/IfNode.java
+++ b/chapter10b/src/main/java/com/seaofnodes/simple/node/IfNode.java
@@ -1,10 +1,10 @@
package com.seaofnodes.simple.node;
+
import com.seaofnodes.simple.IterPeeps;
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeInteger;
import com.seaofnodes.simple.type.TypeTuple;
-import java.util.BitSet;
public class IfNode extends MultiNode {
@@ -16,11 +16,7 @@ public class IfNode extends MultiNode {
@Override
public String label() { return "If"; }
- @Override
- StringBuilder _print1(StringBuilder sb, BitSet visited) {
- sb.append("if( ");
- return in(1)._print0(sb, visited).append(" )");
- }
+ @Override protected String format() { return "if( %1 )"; }
@Override public boolean isCFG() { return true; }
@Override public boolean isMultiHead() { return true; }
diff --git a/chapter10b/src/main/java/com/seaofnodes/simple/node/LoadNode.java b/chapter10b/src/main/java/com/seaofnodes/simple/node/LoadNode.java
index 5f096ef7..9bf36459 100644
--- a/chapter10b/src/main/java/com/seaofnodes/simple/node/LoadNode.java
+++ b/chapter10b/src/main/java/com/seaofnodes/simple/node/LoadNode.java
@@ -1,11 +1,12 @@
package com.seaofnodes.simple.node;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.Utils;
import com.seaofnodes.simple.IterPeeps;
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.Field;
-import java.util.BitSet;
/**
* Load represents extracting a value from inside a memory object,
@@ -48,7 +49,7 @@ public class LoadNode extends MemOpNode {
public String label() { return "Load"; }
@Override
- 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/chapter10b/src/main/java/com/seaofnodes/simple/node/MemMergeNode.java b/chapter10b/src/main/java/com/seaofnodes/simple/node/MemMergeNode.java
index d7fed402..f3d5b01e 100644
--- a/chapter10b/src/main/java/com/seaofnodes/simple/node/MemMergeNode.java
+++ b/chapter10b/src/main/java/com/seaofnodes/simple/node/MemMergeNode.java
@@ -1,9 +1,10 @@
package com.seaofnodes.simple.node;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.IterPeeps;
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeMem;
-import java.util.BitSet;
/** All memory: a default slice and explicit overrides for individual aliases. */
public class MemMergeNode extends Node {
@@ -28,14 +29,14 @@ public class MemMergeNode extends Node {
@Override public String label() { return "MemMerge"; }
@Override public boolean isMem() { return true; }
@Override public Type compute() { return TypeMem.BOT; }
- @Override StringBuilder _print1(StringBuilder sb, BitSet visited) {
- sb.append("MEM[");
+ @Override protected ExprPrinter<Node> _print1(ExprPrinter<Node> p) {
+ p.p("MEM[");
for( int i=1; i<nIns(); i++ )
if( in(i)!=null ) {
- sb.append(i==1 ? "default:" : i+":");
- in(i)._print0(sb,visited).append(" ");
+ p.p(i==1 ? "default:" : i+":");
+ p.n(in(i)).p(" ");
}
- return sb.append("]");
+ return p.p("]");
}
@Override public Node idealize() {
diff --git a/chapter10b/src/main/java/com/seaofnodes/simple/node/MinusNode.java b/chapter10b/src/main/java/com/seaofnodes/simple/node/MinusNode.java
index 8b1b73bf..5b65b3fb 100644
--- a/chapter10b/src/main/java/com/seaofnodes/simple/node/MinusNode.java
+++ b/chapter10b/src/main/java/com/seaofnodes/simple/node/MinusNode.java
@@ -1,20 +1,16 @@
package com.seaofnodes.simple.node;
+
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeInteger;
-import java.util.BitSet;
public class MinusNode extends Node {
public MinusNode(Node in) { super(null, in); }
@Override public String label() { return "Minus"; }
- @Override
- 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/chapter10b/src/main/java/com/seaofnodes/simple/node/MulNode.java b/chapter10b/src/main/java/com/seaofnodes/simple/node/MulNode.java
index 97721ce3..5592c52d 100644
--- a/chapter10b/src/main/java/com/seaofnodes/simple/node/MulNode.java
+++ b/chapter10b/src/main/java/com/seaofnodes/simple/node/MulNode.java
@@ -1,21 +1,16 @@
package com.seaofnodes.simple.node;
+
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeInteger;
-import java.util.BitSet;
public class MulNode extends Node {
public MulNode(Node lhs, Node rhs) { super(null, lhs, rhs); }
@Override public String label() { return "Mul"; }
- @Override
- StringBuilder _print1(StringBuilder sb, BitSet visited) {
- in(1)._print0(sb.append("("), visited);
- in(2)._print0(sb.append("*"), visited);
- return sb.append(")");
- }
+ @Override protected String format() { return "(%1*%2)"; }
@Override
public Type compute() {
diff --git a/chapter10b/src/main/java/com/seaofnodes/simple/node/NewNode.java b/chapter10b/src/main/java/com/seaofnodes/simple/node/NewNode.java
index b13462f5..857920bc 100644
--- a/chapter10b/src/main/java/com/seaofnodes/simple/node/NewNode.java
+++ b/chapter10b/src/main/java/com/seaofnodes/simple/node/NewNode.java
@@ -1,9 +1,10 @@
package com.seaofnodes.simple.node;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeMemPtr;
-import java.util.BitSet;
public class NewNode extends Node {
@@ -17,10 +18,8 @@ public class NewNode extends Node {
@Override
public String label() { return "new"; }
- @Override
- StringBuilder _print1(StringBuilder sb, BitSet visited) {
- sb.append("new ");
- return sb.append(_ptr._obj.str());
+ @Override protected ExprPrinter<Node> _print1(ExprPrinter<Node> p) {
+ return p.p("new ").p(_ptr._obj.str());
}
@Override
diff --git a/chapter10b/src/main/java/com/seaofnodes/simple/node/Node.java b/chapter10b/src/main/java/com/seaofnodes/simple/node/Node.java
index 9a48c515..1d8e23f8 100644
--- a/chapter10b/src/main/java/com/seaofnodes/simple/node/Node.java
+++ b/chapter10b/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.Parser;
import com.seaofnodes.simple.IRPrinter;
@@ -15,14 +17,7 @@ import java.util.function.Function;
* The Node class provides common functionality used by all subtypes.
* Subtypes of Node specialize by overriding methods.
*/
-public abstract class Node implements Cloneable {
-
- /**
- * Each node has a unique dense Node ID within a compilation context
- * The ID is useful for debugging, for using as an offset in a bitvector,
- * as well as for computing equality of nodes (to be implemented later).
- */
- public int _nid;
+public abstract class Node extends BaseNode<Node> implements Cloneable {
/**
* Inputs to the node. These are use-def references to Nodes.
@@ -44,14 +39,12 @@ public abstract class Node implements Cloneable {
*/
public ArrayList<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;
-
/**
* A private Global Static mutable counter, for unique node id generation.
* To make the compiler multithreaded, this field will have to move into a TLS.
@@ -61,7 +54,7 @@ public abstract class Node implements Cloneable {
public static int UID() { return UNIQUE_ID; }
protected Node(Node... inputs) {
- _nid = UNIQUE_ID++; // allocate unique dense ID
+ super(UNIQUE_ID++); // allocate unique dense ID
_inputs = new ArrayList<>();
Collections.addAll(_inputs,inputs);
_outputs = new ArrayList<>();
@@ -73,42 +66,6 @@ public abstract class Node implements Cloneable {
// Easy reading label for debugger, e.g. "Add" or "Region" or "EQ"
public abstract String label();
- // Unique label for debugging, e.g. "Add12" or "Region30" or "EQ99"
- public String uniqueName() {
- return label() + _nid;
- }
-
- // ------------------------------------------------------------------------
-
- // 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. This version will fail on cycles, which we will
- // correct later when we can parse programs with loops. We print with a
- // 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.
- 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 StringBuilder _print1(StringBuilder sb, BitSet visited);
-
public String p(int depth) { return IRPrinter.prettyPrint(this,depth); }
public boolean isMultiHead() { return false; }
@@ -117,6 +74,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
@@ -131,8 +90,6 @@ public abstract class Node implements Cloneable {
public boolean isUnused() { return nOuts() == 0; }
- public boolean isCFG() { return false; }
-
public boolean isMem() { return false; }
/**
@@ -257,7 +214,6 @@ public abstract class Node implements Cloneable {
// Test "keep" status
public boolean iskeep() { return Utils.find(_outputs,null) != -1; }
-
// Replace self with nnn in the graph, making 'this' go dead
public void subsume( Node nnn ) {
assert nnn!=this;
@@ -388,7 +344,6 @@ public abstract class Node implements Cloneable {
return old;
}
-
/**
* This function rewrites the current Node into a more "idealized" form.
* This is the bulk of our peephole rewrite rules, and we use this to
@@ -436,7 +391,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
@@ -480,7 +434,6 @@ public abstract class Node implements Cloneable {
_deps.clear();
}
-
// Global Value Numbering. Hash over opcode and inputs; hits in this table
// are structurally equal.
public static final HashMap<Node,Node> GVN = new HashMap<>();
@@ -502,7 +455,6 @@ public abstract class Node implements Cloneable {
// and can assume "this!=n" and has the same Java class.
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
@@ -518,7 +470,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;
@@ -532,7 +483,6 @@ public abstract class Node implements Cloneable {
// Subclasses add extra hash info (such as ConstantNodes constant)
int hash() { return 0; }
-
// ------------------------------------------------------------------------
// Peephole utilities
@@ -561,7 +511,6 @@ public abstract class Node implements Cloneable {
return true;
}
-
/**
* Immediate dominator tree depth, used to approximate a real IDOM depth
* during parsing where we do not have the whole program, and also
@@ -591,7 +540,6 @@ public abstract class Node implements Cloneable {
return _idepth = (char)depth;
}
-
// Return the immediate dominator of this Node.
Node idom() { return in(0); }
@@ -627,7 +575,6 @@ public abstract class Node implements Cloneable {
ITER_CNT = ITER_NOP_CNT = 0;
}
-
// Utility to walk the entire graph applying a function; return the first
// not-null result.
private static final BitSet WVISIT = new BitSet();
diff --git a/chapter10b/src/main/java/com/seaofnodes/simple/node/NotNode.java b/chapter10b/src/main/java/com/seaofnodes/simple/node/NotNode.java
index 83141836..5e556390 100644
--- a/chapter10b/src/main/java/com/seaofnodes/simple/node/NotNode.java
+++ b/chapter10b/src/main/java/com/seaofnodes/simple/node/NotNode.java
@@ -1,19 +1,15 @@
package com.seaofnodes.simple.node;
+
import com.seaofnodes.simple.Utils;
import com.seaofnodes.simple.type.*;
-import java.util.BitSet;
public class NotNode extends Node {
public NotNode(Node in) { super(null, in); }
@Override public String label() { return "Not"; }
- @Override
- 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/chapter10b/src/main/java/com/seaofnodes/simple/node/PhiNode.java b/chapter10b/src/main/java/com/seaofnodes/simple/node/PhiNode.java
index cdb4b7cc..6995cc2f 100644
--- a/chapter10b/src/main/java/com/seaofnodes/simple/node/PhiNode.java
+++ b/chapter10b/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.type.Type;
import com.seaofnodes.simple.type.TypeMem;
import com.seaofnodes.simple.Utils;
-import java.util.BitSet;
public class PhiNode extends Node {
@@ -23,18 +24,12 @@ public class PhiNode extends Node {
@Override public String label() { return "Phi_"+_label; }
@Override
- 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();
}
Node region() { return in(0); }
diff --git a/chapter10b/src/main/java/com/seaofnodes/simple/node/ProjNode.java b/chapter10b/src/main/java/com/seaofnodes/simple/node/ProjNode.java
index 735fcdf3..a2632110 100644
--- a/chapter10b/src/main/java/com/seaofnodes/simple/node/ProjNode.java
+++ b/chapter10b/src/main/java/com/seaofnodes/simple/node/ProjNode.java
@@ -1,10 +1,11 @@
package com.seaofnodes.simple.node;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeMem;
import com.seaofnodes.simple.type.TypeTuple;
-import java.util.BitSet;
public class ProjNode extends Node {
@@ -24,7 +25,7 @@ public class ProjNode extends Node {
public String label() { return _label; }
@Override
- StringBuilder _print1(StringBuilder sb, BitSet visited) { return sb.append(_label); }
+ protected ExprPrinter<Node> _print1(ExprPrinter<Node> p) { return p.p(_label); }
@Override public boolean isCFG() { return _idx==0 || ctrl() instanceof IfNode; }
@Override public boolean isMultiTail() { return in(0).isMultiHead(); }
diff --git a/chapter10b/src/main/java/com/seaofnodes/simple/node/RegionNode.java b/chapter10b/src/main/java/com/seaofnodes/simple/node/RegionNode.java
index a6b8d834..8b52494a 100644
--- a/chapter10b/src/main/java/com/seaofnodes/simple/node/RegionNode.java
+++ b/chapter10b/src/main/java/com/seaofnodes/simple/node/RegionNode.java
@@ -1,12 +1,13 @@
package com.seaofnodes.simple.node;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.IterPeeps;
import com.seaofnodes.simple.Utils;
import com.seaofnodes.simple.type.Type;
import java.util.ArrayList;
import java.util.Arrays;
-import java.util.BitSet;
public class RegionNode extends Node {
@@ -15,9 +16,8 @@ public class RegionNode extends Node {
@Override
public String label() { return "Region"; }
- @Override
- StringBuilder _print1(StringBuilder sb, BitSet visited) {
- return sb.append(label()).append(_nid);
+ @Override protected ExprPrinter<Node> _print1(ExprPrinter<Node> p) {
+ return p.p(label()).p(_nid);
}
@Override public boolean isCFG() { return true; }
diff --git a/chapter10b/src/main/java/com/seaofnodes/simple/node/ReturnNode.java b/chapter10b/src/main/java/com/seaofnodes/simple/node/ReturnNode.java
index 96d58599..ef4ddb3a 100644
--- a/chapter10b/src/main/java/com/seaofnodes/simple/node/ReturnNode.java
+++ b/chapter10b/src/main/java/com/seaofnodes/simple/node/ReturnNode.java
@@ -1,8 +1,9 @@
package com.seaofnodes.simple.node;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.type.*;
-import java.util.BitSet;
/** Keeps all preceding memory effects and the return value alive: {ctrl, $mem, value}. */
public class ReturnNode extends Node {
@@ -19,10 +20,10 @@ public class ReturnNode extends Node {
public String label() { return "Return"; }
@Override
- StringBuilder _print1(StringBuilder sb, BitSet visited) {
- sb.append("return ");
- expr()._print0(sb, visited);
- return sb.append(";");
+ protected ExprPrinter<Node> _print1(ExprPrinter<Node> p) {
+ p.p("return ");
+ p.n(expr());
+ return p.p(";");
}
@Override public boolean isCFG() { return true; }
diff --git a/chapter10b/src/main/java/com/seaofnodes/simple/node/ScopeNode.java b/chapter10b/src/main/java/com/seaofnodes/simple/node/ScopeNode.java
index b931e862..b408eb2f 100644
--- a/chapter10b/src/main/java/com/seaofnodes/simple/node/ScopeNode.java
+++ b/chapter10b/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.IterPeeps;
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.Utils;
@@ -42,20 +44,19 @@ public class ScopeNode extends Node {
@Override public String label() { return "Scope"; }
@Override
- StringBuilder _print1(StringBuilder sb, BitSet visited) {
- sb.append("Scope[ ");
+ protected ExprPrinter<Node> _print1(ExprPrinter<Node> p) {
+ p.p("Scope[ ");
String[] names = reverseNames();
for( int j=0; j<nIns(); j++ ) {
- sb.append(names[j]).append(":");
+ p.p(names[j]).p(":");
Node n = in(j);
while( n instanceof ScopeNode loop ) {
- sb.append("Lazy_");
+ p.p("Lazy_");
n = loop.in(j);
}
- n._print0(sb, visited).append(" ");
+ p.n(n).p(" ");
}
- sb.setLength(sb.length()-1);
- return sb.append("]");
+ return p.unchar(' ').p("]");
}
/**
diff --git a/chapter10b/src/main/java/com/seaofnodes/simple/node/StartNode.java b/chapter10b/src/main/java/com/seaofnodes/simple/node/StartNode.java
index 1ca52af0..3404f111 100644
--- a/chapter10b/src/main/java/com/seaofnodes/simple/node/StartNode.java
+++ b/chapter10b/src/main/java/com/seaofnodes/simple/node/StartNode.java
@@ -1,7 +1,8 @@
package com.seaofnodes.simple.node;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.type.*;
-import java.util.BitSet;
/** The entry tuple: control, initial whole-memory state, and argument. */
public class StartNode extends MultiNode {
@@ -15,9 +16,8 @@ public class StartNode extends MultiNode {
@Override
public String label() { return "Start"; }
- @Override
- 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 isCFG() { return true; }
diff --git a/chapter10b/src/main/java/com/seaofnodes/simple/node/StopNode.java b/chapter10b/src/main/java/com/seaofnodes/simple/node/StopNode.java
index cb4126f5..4b4e9615 100644
--- a/chapter10b/src/main/java/com/seaofnodes/simple/node/StopNode.java
+++ b/chapter10b/src/main/java/com/seaofnodes/simple/node/StopNode.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.Type;
import com.seaofnodes.simple.IterPeeps;
-import java.util.BitSet;
public class StopNode extends Node {
@@ -22,12 +23,12 @@ public class StopNode extends Node {
}
@Override
- StringBuilder _print1(StringBuilder sb, BitSet visited) {
- if( ret()!=null ) return ret()._print0(sb, visited);
- sb.append("Stop[ ");
+ protected ExprPrinter<Node> _print1(ExprPrinter<Node> p) {
+ if( ret()!=null ) return p.n(ret());
+ p.p("Stop[ ");
for( Node ret : _inputs )
- ret._print0(sb, visited).append(" ");
- return sb.append("]");
+ p.n(ret).p(" ");
+ return p.p("]");
}
@Override public boolean isCFG() { return true; }
diff --git a/chapter10b/src/main/java/com/seaofnodes/simple/node/StoreNode.java b/chapter10b/src/main/java/com/seaofnodes/simple/node/StoreNode.java
index b752aad5..026d5c50 100644
--- a/chapter10b/src/main/java/com/seaofnodes/simple/node/StoreNode.java
+++ b/chapter10b/src/main/java/com/seaofnodes/simple/node/StoreNode.java
@@ -1,10 +1,11 @@
package com.seaofnodes.simple.node;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.Utils;
import com.seaofnodes.simple.IterPeeps;
import com.seaofnodes.simple.type.*;
-import java.util.BitSet;
/**
* Store represents setting a value to a memory based object, in chapter 10
@@ -29,8 +30,8 @@ public class StoreNode extends MemOpNode {
public Node val() { return in(3); }
@Override
- 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/chapter10b/src/main/java/com/seaofnodes/simple/node/SubNode.java b/chapter10b/src/main/java/com/seaofnodes/simple/node/SubNode.java
index eeec5e1d..6fa87a07 100644
--- a/chapter10b/src/main/java/com/seaofnodes/simple/node/SubNode.java
+++ b/chapter10b/src/main/java/com/seaofnodes/simple/node/SubNode.java
@@ -1,21 +1,16 @@
package com.seaofnodes.simple.node;
+
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeInteger;
-import java.util.BitSet;
public class SubNode extends Node {
public SubNode(Node lhs, Node rhs) { super(null, lhs, rhs); }
@Override public String label() { return "Sub"; }
- @Override
- StringBuilder _print1(StringBuilder sb, BitSet visited) {
- in(1)._print0(sb.append("("), visited);
- in(2)._print0(sb.append("-"), visited);
- return sb.append(")");
- }
+ @Override protected String format() { return "(%1-%2)"; }
@Override
public Type compute() {
diff --git a/chapter10b/src/main/java/com/seaofnodes/simple/print/SimpleGraphAdapter.java b/chapter10b/src/main/java/com/seaofnodes/simple/print/SimpleGraphAdapter.java
index 600e9c73..92d970d8 100644
--- a/chapter10b/src/main/java/com/seaofnodes/simple/print/SimpleGraphAdapter.java
+++ b/chapter10b/src/main/java/com/seaofnodes/simple/print/SimpleGraphAdapter.java
@@ -1,42 +1,20 @@
package com.seaofnodes.simple.print;
import com.seaofnodes.graph.GraphAdapter;
-import com.seaofnodes.graph.GraphSnapshot;
import com.seaofnodes.graph.GraphSnapshot.*;
import com.seaofnodes.simple.node.*;
import com.seaofnodes.simple.node.Node;
import com.seaofnodes.simple.type.TypeMem;
-import java.util.ArrayList;
/** Chapter 10's view of the IR; browser, transport and layout are shared. */
public class SimpleGraphAdapter extends GraphAdapter<Node> {
- @Override protected boolean dead(Node n) { return n.isDead(); }
- @Override protected int id(Node n) { return n._nid; }
- @Override protected int nIns(Node n) { return n.nIns(); }
- @Override protected Node in(Node n, int idx) { return n.in(idx); }
- @Override protected int nOuts(Node n) { return n.nOuts(); }
- @Override protected Node out(Node n, int idx) { return n.out(idx); }
- @Override protected int nDeps(Node n) { return n.nDeps(); }
- @Override protected Node dep(Node n, int idx) { return n.dep(idx); }
- private ArrayList<Edge> edges(Node n) {
- var edges = new ArrayList<Edge>();
- String[] names = n instanceof ScopeNode scope && n.nIns() != 0 ? scope.reverseNames() : null;
- for( int i = 0; i < n.nIns(); i++ ) {
- String name = names == null || i >= names.length ? null : names[i];
- edges.add(new Edge(i, ref(n.in(i)), role(n, i), name));
- }
- return edges;
+ @Override protected String[] edgeNames(Node n) {
+ return n instanceof ScopeNode scope && n.nIns()!=0 ? scope.reverseNames() : null;
}
+ @Override protected int projectionIndex(Node n) { return n instanceof ProjNode p ? p._idx : -1; }
- @Override protected GraphSnapshot.Node desc(Node n) {
- Projection proj = n instanceof ProjNode p ? new Projection(ref(n.in(0)), p._idx) : null;
- String label = n.label();
- return new GraphSnapshot.Node(n._nid, label == null ? n.getClass().getSimpleName() : label,
- n._type == null ? null : n._type.toString(), kind(n), edges(n), proj);
- }
-
- private Kind kind(Node n) {
+ @Override protected Kind kind(Node n) {
if( n instanceof StopNode ) return Kind.STOP;
if( n instanceof ScopeNode ) return Kind.SCOPE;
if( n instanceof StartNode ) return Kind.CTRL;
@@ -46,7 +24,7 @@ public class SimpleGraphAdapter extends GraphAdapter<Node> {
return n.isCFG() ? Kind.CTRL : isMem(n) ? Kind.MEM : Kind.DATA;
}
- private Role role(Node n, int i) {
+ @Override protected Role role(Node n, int i) {
if( n instanceof ScopeNode || n instanceof ConstantNode ) return Role.ASSOC;
if( n instanceof PhiNode ) return i == 0 ? Role.ASSOC : isMem(n) ? Role.MEM : Role.DATA;
if( n instanceof ProjNode ) return n.isCFG() ? Role.CTRL : isMem(n) ? Role.MEM : Role.DATA;
diff --git a/chapter11/Makefile b/chapter11/Makefile
index 77df7182..3f1e53ff 100644
--- a/chapter11/Makefile
+++ b/chapter11/Makefile
@@ -37,6 +37,7 @@ main_javas := $(wildcard $(SRC)/$(SIMPLE)/*java $(SRC)/$(SIMPLE)/*/*java)
test_javas := $(wildcard $(TST)/$(SIMPLE)/*java $(TST)/$(SIMPLE)/*/*java)
main_classes := $(patsubst $(SRC)/%java,$(CLZDIR)/main/%class,$(main_javas))
include $(firstword $(wildcard ../graph/graph.mk graph/graph.mk))
+include $(firstword $(wildcard ../print/print.mk print/print.mk))
test_classes := $(patsubst $(TST)/%java,$(CLZDIR)/test/%class,$(test_javas))
test_cp := $(patsubst $(TST)/$(SIMPLE)/%.java,com.seaofnodes.simple.%,$(wildcard $(TST)/$(SIMPLE)/*Test.java))
classes = $(main_classes) $(test_classes)
@@ -54,7 +55,7 @@ endif
default: $(default_targets)
# Compile just the out-of-date files
-$(main_classes): build/classes/main/%class: $(SRC)/%java $(graph_javas)
+$(main_classes): build/classes/main/%class: $(SRC)/%java $(graph_javas) $(print_javas)
@echo "compiling " $@ " because " $?
@[ -d $(CLZDIR)/main ] || mkdir -p $(CLZDIR)/main
@javac $(JAVAC_ARGS) -cp "$(CLZDIR)/main$(SEP)$(jars)" -sourcepath $(SRC) -d $(CLZDIR)/main $(main_javas)
diff --git a/chapter11/pom.xml b/chapter11/pom.xml
index 16536ba3..673b4364 100644
--- a/chapter11/pom.xml
+++ b/chapter11/pom.xml
@@ -13,5 +13,6 @@
<name>Chapter 11</name>
<properties>
<simple.graph.directory>${project.basedir}/../graph</simple.graph.directory>
+ <simple.print.directory>${project.basedir}/../print</simple.print.directory>
</properties>
</project>
diff --git a/chapter11/src/main/java/com/seaofnodes/simple/IRPrinter.java b/chapter11/src/main/java/com/seaofnodes/simple/IRPrinter.java
index 3410ab64..7e93e9da 100644
--- a/chapter11/src/main/java/com/seaofnodes/simple/IRPrinter.java
+++ b/chapter11/src/main/java/com/seaofnodes/simple/IRPrinter.java
@@ -1,288 +1,33 @@
package com.seaofnodes.simple;
+import com.seaofnodes.print.IRAdapter;
import com.seaofnodes.simple.node.*;
-import java.lang.StringBuilder;
-import java.util.ArrayList;
-import java.util.BitSet;
-import java.util.HashMap;
-import java.util.IdentityHashMap;
-
-public 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 void _printLine( Node n, StringBuilder sb ) {
- sb.append("%4d %-7.7s ".formatted(n._nid,n.label()));
- if( n.isDead() ) {
- sb.append("DEAD\n");
- return;
- }
- for( Node def : n._inputs )
- sb.append(def==null ? "____ " : "%4d ".formatted(def._nid));
- for( int i = n._inputs.size(); i<4; i++ )
- sb.append(" ");
- sb.append(" [[ ");
- for( Node use : n._outputs )
- sb.append(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.append(" ");
- sb.append(" ]] ");
- if( n._type!= null ) sb.append(n._type.str());
- sb.append("\n");
- }
-
- private static StringBuilder nodeId(StringBuilder sb, Node n) {
- sb.append("%%%d".formatted(n._nid));
- if (n instanceof ProjNode proj) {
- sb.append(".").append(proj._idx);
- }
- return sb;
- }
-
- // Print a node on 1 line, format is inspired by LLVM
- // %id: TYPE = NODE(inputs ....)
- // Nodes as referred to as %id
- public static void _printLineLlvmFormat( Node n, StringBuilder sb ) {
- nodeId(sb, n).append(": ");
- if( n.isDead() ) {
- sb.append("DEAD\n");
- return;
- }
- if( n._type!= null ) n._type.typeName(sb);
- sb.append(" = ").append( n.label() ).append( "(" );
- for( int i = 0; i < n._inputs.size(); i++ ) {
- Node def = n.in(i);
- if (i > 0)
- sb.append(", ");
- if (def == null) sb.append("_");
- else nodeId(sb, def);
- }
- sb.append(")").append("\n");
- }
-
- public static void printLine( Node n, StringBuilder sb, boolean llvmFormat ) {
- if (llvmFormat) _printLineLlvmFormat( n, sb );
- else _printLine ( n, sb );
- }
-
- public static String prettyPrint(Node node, int depth) {
- return Parser.SCHEDULED
- ? prettyPrintScheduled( node, depth, false )
- : prettyPrint( node, depth, false );
- }
-
- // Another bulk pretty-printer. Makes more effort at basic-block grouping.
- public static String prettyPrint( Node node, int depth, boolean llvmFormat ) {
- // First, a Breadth First Search at a fixed depth.
- BFS bfs = new BFS(node,depth);
- // Convert just that set to a post-order
- ArrayList<Node> rpos = new ArrayList<>();
- BitSet visit = new BitSet();
- for( int i=bfs._lim; i< bfs._bfs.size(); i++ )
- postOrd( bfs._bfs.get(i), rpos, visit, bfs._bs);
- // Reverse the post-order walk
- StringBuilder sb = new StringBuilder();
- boolean gap=false;
- for( int i=rpos.size()-1; i>=0; i-- ) {
- Node n = rpos.get(i);
- if( n.isCFG() || n.isMultiHead() ) {
- if( !gap ) sb.append("\n"); // Blank before multihead
- printLine( n, sb, llvmFormat ); // Print head
- while( --i >= 0 ) {
- Node t = rpos.get(i);
- if( !t.isMultiTail() ) { i++; break; }
- printLine( t, sb, llvmFormat );
- }
- sb.append("\n"); // Blank after multitail
- gap = true;
- } else {
- printLine( n, sb, llvmFormat );
- gap = false;
- }
- }
- return sb.toString();
- }
-
- private static void postOrd(Node n, ArrayList<Node> rpos, BitSet visit, BitSet bfs) {
- if( !bfs.get(n._nid) )
- return; // Not in the BFS visit
- if( visit.get(n._nid) ) return; // Already post-order walked
- visit.set(n._nid);
- // First walk the CFG, then everything
- if( n.isCFG() ) {
- for( Node use : n._outputs )
- if( use!=null && use.isCFG() && use.nOuts()>=1 && !(use._outputs.get(0) instanceof LoopNode) )
- postOrd(use, rpos,visit,bfs);
- for( Node use : n._outputs )
- if( use!=null && use.isCFG() )
- postOrd(use,rpos,visit,bfs);
- }
- for( Node use : n._outputs )
- if( use != null )
- postOrd(use, rpos,visit,bfs);
- // Post-order
- rpos.add(n);
- }
-
- // Breadth-first search, broken out in a class to keep in more independent.
- // Maintains a root-set of Nodes at the limit (or past by 1 if MultiHead).
- public static class BFS {
- // A breadth first search, plus MultiHeads for any MultiTails
- public final ArrayList<Node> _bfs;
- public final BitSet _bs; // Visited members by node id
- public final int _depth; // Depth limit
- public final int _lim; // From here to _bfs._len can be roots for a reverse search
- public BFS( Node base, int d ) {
- _depth = d;
- _bfs = new ArrayList<>();
- _bs = new BitSet();
-
- add(base); // Prime the pump
- int idx=0, lim=1; // Limit is where depth counter changes
- while( idx < _bfs.size() ) { // Ran out of nodes below depth
- Node n = _bfs.get(idx++);
- for( Node def : n._inputs )
- if( def!=null && !_bs.get(def._nid) )
- add(def);
- if( idx==lim ) { // Depth counter changes at limit
- if( --d < 0 )
- break; // Ran out of depth
- lim = _bfs.size(); // New depth limit
- }
- }
- // Toss things past the limit except multi-heads
- while( idx < _bfs.size() ) {
- Node n = _bfs.get(idx);
- if( n.isMultiHead() ) idx++;
- else del(idx);
- }
- // Root set is any node with no inputs in the visited set
- lim = _bfs.size();
- for( int i=_bfs.size()-1; i>=0; i-- )
- if( !any_visited(_bfs.get(i)) )
- swap( i,--lim);
- _lim = lim;
- }
- void swap( int x, int y ) {
- if( x==y ) return;
- Node tx = _bfs.get(x);
- Node ty = _bfs.get(y);
- _bfs.set(x,ty);
- _bfs.set(y,tx);
- }
- void add(Node n) {
- _bfs.add(n);
- _bs.set(n._nid);
- }
- void del(int idx) {
- Node n = Utils.del(_bfs, idx);
- _bs.clear(n._nid);
- }
- boolean any_visited( Node n ) {
- for( Node def : n._inputs )
- if( def!=null && _bs.get(def._nid) )
- return true;
- return false;
- }
- }
-
- // Diagnostic block ordering from raw control edges. Do not call idepth():
- // it fills compiler caches (and can walk lazy dominator accessors).
- private static int _idepth(CFGNode cfg, HashMap<Integer,Integer> depths) {
- if( cfg == null || cfg instanceof StartNode ) return 0;
- Integer old = depths.get(cfg._nid);
- if( old != null ) return old;
- depths.put(cfg._nid,0); // Break cycles in partially constructed graphs.
- int d = 0;
- if( cfg instanceof LoopNode ) {
- d = _idepth((CFGNode)cfg.in(1),depths)+1;
- } else if( cfg instanceof RegionNode || cfg instanceof StopNode ) {
- for( Node n : cfg._inputs )
- if( n instanceof CFGNode pred ) d = Math.max(d,_idepth(pred,depths)+1);
- } else if( cfg.in(0) instanceof CFGNode pred ) {
- d = _idepth(pred,depths)+1;
- }
- depths.put(cfg._nid,d);
- return d;
- }
-
- // Bulk pretty printer, knowing scheduling information is available
- public static String prettyPrintScheduled( Node node, int depth, boolean llvmFormat ) {
- // Backwards DFS walk to depth.
- IdentityHashMap<Node,Integer> ds = new IdentityHashMap<>();
- _walk(ds,node,depth);
- // Print by block with least diagnostic depth
- HashMap<Integer,Integer> depths = new HashMap<>();
- StringBuilder sb = new StringBuilder();
- ArrayList<Node> bns = new ArrayList<>();
- while( !ds.isEmpty() ) {
- CFGNode blk = null;
- for( Node n : ds.keySet() ) {
- CFGNode cfg = n instanceof CFGNode cfg0 && cfg0.blockHead() ? cfg0 : (CFGNode)n.in(0);
- if( blk==null || _idepth(cfg,depths) < _idepth(blk,depths) )
- blk = cfg;
- }
- ds.remove(blk);
-
- // Print block header
- sb.append("%-13.13s".formatted(label(blk)+":"));
- sb.append( " ".repeat(4) ).append(" [[ ");
- if( blk instanceof RegionNode || blk instanceof StopNode )
- for( int i=(blk instanceof StopNode ? 0 : 1); i<blk.nIns(); i++ )
- label(sb,blk.cfg(i));
- else if( !(blk instanceof StartNode) )
- label(sb,blk.cfg(0));
- sb.append(" ]] \n");
-
- // Collect block contents that are in the depth limit
- bns.clear();
- int xd = Integer.MAX_VALUE;
- for( Node use : blk._outputs ) {
- Integer i = ds.get(use);
- if( i!=null && !(use instanceof CFGNode cfg && cfg.blockHead()) ) {
- bns.add(use);
- xd = Math.min(xd,i);
- }
- }
- // Print Phis up front, if any
- for( int i=0; i<bns.size(); i++ )
- if( bns.get(i) instanceof PhiNode phi )
- printLine( phi, sb, llvmFormat,bns,i--,ds);
-
- // Print block contents in depth order, bumping depth until whole block printed
- for( ; !bns.isEmpty(); xd++ )
- for( int i=0; i<bns.size(); i++ )
- if( ds.get(bns.get(i))==xd )
- printLine( bns.get(i), sb, llvmFormat, bns, i--, ds );
- sb.append("\n");
- }
- return sb.toString();
- }
-
- private static void _walk( IdentityHashMap<Node,Integer> ds, Node node, int d ) {
- Integer nd = ds.get(node);
- if( nd!=null && d <= nd ) return; // Been there, done that
- ds.put(node,d);
- if( d == 0 ) return; // Depth cutoff
- for( Node def : node._inputs )
- if( def != null )
- _walk(ds,def,d-1);
- }
-
- static String label( CFGNode blk ) {
- if( blk instanceof StartNode ) return "START";
- return (blk instanceof LoopNode ? "LOOP" : "L")+blk._nid;
- }
- static void label( StringBuilder sb, CFGNode blk ) {
- if( !blk.blockHead() ) blk = blk.cfg(0);
- sb.append( "%-9.9s ".formatted( label( blk ) ) );
- }
- static void printLine( Node n, StringBuilder sb, boolean llvmFormat, ArrayList<Node> bns, int i, IdentityHashMap<Node,Integer> ds ) {
- printLine( n, sb, llvmFormat );
- Utils.del(bns,i);
- ds.remove(n);
- }
+/** 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 String type(Node n) { return n._type==null ? "" : n._type.str(); }
+ @Override public String inputMark(Node n, Node def) { return n instanceof MemMergeNode && def instanceof MemMergeNode ? "^" : " "; }
+ @Override public Kind kind(Node n) {
+ if( n instanceof StartNode ) return Kind.START;
+ if( n instanceof StopNode ) return Kind.STOP;
+ if( n instanceof LoopNode ) return Kind.LOOP;
+ if( n instanceof RegionNode ) return Kind.REGION;
+ if( n instanceof PhiNode ) return Kind.PHI;
+ 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;
+ }
+
+ public static String prettyPrint(Node n, int depth) { return PRINT.prettyPrint(n,depth); }
}
diff --git a/chapter11/src/main/java/com/seaofnodes/simple/node/AddNode.java b/chapter11/src/main/java/com/seaofnodes/simple/node/AddNode.java
index de5044d7..e235d288 100644
--- a/chapter11/src/main/java/com/seaofnodes/simple/node/AddNode.java
+++ b/chapter11/src/main/java/com/seaofnodes/simple/node/AddNode.java
@@ -1,20 +1,15 @@
package com.seaofnodes.simple.node;
+
import com.seaofnodes.simple.type.*;
-import java.util.BitSet;
public class AddNode extends Node {
public AddNode(Node lhs, Node rhs) { super(null, lhs, rhs); }
@Override public String label() { return "Add"; }
- @Override
- StringBuilder _print1(StringBuilder sb, BitSet visited) {
- in(1)._print0(sb.append("("), visited);
- in(2)._print0(sb.append("+"), visited);
- return sb.append(")");
- }
+ @Override protected String format() { return "(%1+%2)"; }
@Override
diff --git a/chapter11/src/main/java/com/seaofnodes/simple/node/BoolNode.java b/chapter11/src/main/java/com/seaofnodes/simple/node/BoolNode.java
index bf0d3a84..63452dba 100644
--- a/chapter11/src/main/java/com/seaofnodes/simple/node/BoolNode.java
+++ b/chapter11/src/main/java/com/seaofnodes/simple/node/BoolNode.java
@@ -1,10 +1,11 @@
package com.seaofnodes.simple.node;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeInteger;
import com.seaofnodes.simple.type.TypeMemPtr;
-import java.util.BitSet;
abstract public class BoolNode extends Node {
@@ -17,11 +18,8 @@ abstract public class BoolNode extends Node {
@Override
public String label() { return getClass().getSimpleName(); }
- @Override
- 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/chapter11/src/main/java/com/seaofnodes/simple/node/CProjNode.java b/chapter11/src/main/java/com/seaofnodes/simple/node/CProjNode.java
index fb0ff879..ff5d1a76 100644
--- a/chapter11/src/main/java/com/seaofnodes/simple/node/CProjNode.java
+++ b/chapter11/src/main/java/com/seaofnodes/simple/node/CProjNode.java
@@ -1,10 +1,11 @@
package com.seaofnodes.simple.node;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.Parser;
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeMem;
import com.seaofnodes.simple.type.TypeTuple;
-import java.util.BitSet;
public class CProjNode extends CFGNode {
@@ -22,7 +23,7 @@ public class CProjNode extends CFGNode {
@Override public String label() { return _label; }
- @Override 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 isMultiTail() { return in(0).isMultiHead(); }
@Override public boolean blockHead() { return true; }
diff --git a/chapter11/src/main/java/com/seaofnodes/simple/node/CastNode.java b/chapter11/src/main/java/com/seaofnodes/simple/node/CastNode.java
index fec540f7..c1faf210 100644
--- a/chapter11/src/main/java/com/seaofnodes/simple/node/CastNode.java
+++ b/chapter11/src/main/java/com/seaofnodes/simple/node/CastNode.java
@@ -1,10 +1,11 @@
package com.seaofnodes.simple.node;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeInteger;
import com.seaofnodes.simple.IterPeeps;
-import java.util.BitSet;
// Upcast (join) the input to a t. Used after guard test to lift an input.
// Can also be used to make a type-assertion if ctrl is null.
@@ -18,12 +19,9 @@ public class CastNode extends Node {
@Override public String label() { return "("+_t.str()+")"; }
- @Override
- public String uniqueName() { return "Cast_" + _nid; }
- @Override
- StringBuilder _print1(StringBuilder sb, BitSet visited) {
- return in(1)._print0(sb.append(label()), visited);
+ @Override protected ExprPrinter<Node> _print1(ExprPrinter<Node> p) {
+ return p.p(label()).n(in(1));
}
@Override
diff --git a/chapter11/src/main/java/com/seaofnodes/simple/node/ConstantNode.java b/chapter11/src/main/java/com/seaofnodes/simple/node/ConstantNode.java
index 37a529d1..9ecd1152 100644
--- a/chapter11/src/main/java/com/seaofnodes/simple/node/ConstantNode.java
+++ b/chapter11/src/main/java/com/seaofnodes/simple/node/ConstantNode.java
@@ -1,9 +1,10 @@
package com.seaofnodes.simple.node;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.Parser;
import com.seaofnodes.simple.type.Type;
-import java.util.BitSet;
/**
* A Constant node represents a constant value. At present, the only constants
@@ -24,15 +25,16 @@ public class ConstantNode extends Node {
_con = type;
}
- @Override
- public String label() { return "#"+_con; }
+ @Override protected String repeatName() {
+ return _con==null || _con.toString().length()<=32 ? null : uniqueName();
+ }
@Override
- public String uniqueName() { return "Con_" + _nid; }
+ public String label() { return "Con"; }
- @Override
- StringBuilder _print1(StringBuilder sb, BitSet visited) {
- return _con.print(sb);
+
+ @Override protected ExprPrinter<Node> _print1(ExprPrinter<Node> p) {
+ return p.p(_con);
}
@Override public boolean isMultiTail() { return true; }
diff --git a/chapter11/src/main/java/com/seaofnodes/simple/node/DivNode.java b/chapter11/src/main/java/com/seaofnodes/simple/node/DivNode.java
index 6cee90ad..d7244ace 100644
--- a/chapter11/src/main/java/com/seaofnodes/simple/node/DivNode.java
+++ b/chapter11/src/main/java/com/seaofnodes/simple/node/DivNode.java
@@ -1,21 +1,16 @@
package com.seaofnodes.simple.node;
+
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeInteger;
-import java.util.BitSet;
public class DivNode extends Node {
public DivNode(Node lhs, Node rhs) { super(null, lhs, rhs); }
@Override public String label() { return "Div"; }
- @Override
- StringBuilder _print1(StringBuilder sb, BitSet visited) {
- in(1)._print0(sb.append("("), visited);
- in(2)._print0(sb.append("/"), visited);
- return sb.append(")");
- }
+ @Override protected String format() { return "(%1/%2)"; }
@Override
public Type compute() {
diff --git a/chapter11/src/main/java/com/seaofnodes/simple/node/IfNode.java b/chapter11/src/main/java/com/seaofnodes/simple/node/IfNode.java
index 5457ac6e..70340f7f 100644
--- a/chapter11/src/main/java/com/seaofnodes/simple/node/IfNode.java
+++ b/chapter11/src/main/java/com/seaofnodes/simple/node/IfNode.java
@@ -1,5 +1,6 @@
package com.seaofnodes.simple.node;
+
import com.seaofnodes.simple.IterPeeps;
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeInteger;
@@ -17,11 +18,7 @@ public class IfNode extends CFGNode implements MultiNode {
@Override
public String label() { return "If"; }
- @Override
- StringBuilder _print1(StringBuilder sb, BitSet visited) {
- sb.append("if( ");
- return in(1)._print0(sb, visited).append(" )");
- }
+ @Override protected String format() { return "if( %1 )"; }
@Override public boolean isMultiHead() { return true; }
diff --git a/chapter11/src/main/java/com/seaofnodes/simple/node/LoadNode.java b/chapter11/src/main/java/com/seaofnodes/simple/node/LoadNode.java
index 6d44c84a..386009b4 100644
--- a/chapter11/src/main/java/com/seaofnodes/simple/node/LoadNode.java
+++ b/chapter11/src/main/java/com/seaofnodes/simple/node/LoadNode.java
@@ -1,11 +1,12 @@
package com.seaofnodes.simple.node;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.Utils;
import com.seaofnodes.simple.IterPeeps;
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.Field;
-import java.util.BitSet;
/**
* Load represents extracting a value from inside a memory object,
@@ -48,7 +49,7 @@ public class LoadNode extends MemOpNode {
public String label() { return "Load"; }
@Override
- 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/chapter11/src/main/java/com/seaofnodes/simple/node/MemMergeNode.java b/chapter11/src/main/java/com/seaofnodes/simple/node/MemMergeNode.java
index d7fed402..f3d5b01e 100644
--- a/chapter11/src/main/java/com/seaofnodes/simple/node/MemMergeNode.java
+++ b/chapter11/src/main/java/com/seaofnodes/simple/node/MemMergeNode.java
@@ -1,9 +1,10 @@
package com.seaofnodes.simple.node;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.IterPeeps;
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeMem;
-import java.util.BitSet;
/** All memory: a default slice and explicit overrides for individual aliases. */
public class MemMergeNode extends Node {
@@ -28,14 +29,14 @@ public class MemMergeNode extends Node {
@Override public String label() { return "MemMerge"; }
@Override public boolean isMem() { return true; }
@Override public Type compute() { return TypeMem.BOT; }
- @Override StringBuilder _print1(StringBuilder sb, BitSet visited) {
- sb.append("MEM[");
+ @Override protected ExprPrinter<Node> _print1(ExprPrinter<Node> p) {
+ p.p("MEM[");
for( int i=1; i<nIns(); i++ )
if( in(i)!=null ) {
- sb.append(i==1 ? "default:" : i+":");
- in(i)._print0(sb,visited).append(" ");
+ p.p(i==1 ? "default:" : i+":");
+ p.n(in(i)).p(" ");
}
- return sb.append("]");
+ return p.p("]");
}
@Override public Node idealize() {
diff --git a/chapter11/src/main/java/com/seaofnodes/simple/node/MinusNode.java b/chapter11/src/main/java/com/seaofnodes/simple/node/MinusNode.java
index 8b1b73bf..5b65b3fb 100644
--- a/chapter11/src/main/java/com/seaofnodes/simple/node/MinusNode.java
+++ b/chapter11/src/main/java/com/seaofnodes/simple/node/MinusNode.java
@@ -1,20 +1,16 @@
package com.seaofnodes.simple.node;
+
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeInteger;
-import java.util.BitSet;
public class MinusNode extends Node {
public MinusNode(Node in) { super(null, in); }
@Override public String label() { return "Minus"; }
- @Override
- 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/chapter11/src/main/java/com/seaofnodes/simple/node/MulNode.java b/chapter11/src/main/java/com/seaofnodes/simple/node/MulNode.java
index 97721ce3..5592c52d 100644
--- a/chapter11/src/main/java/com/seaofnodes/simple/node/MulNode.java
+++ b/chapter11/src/main/java/com/seaofnodes/simple/node/MulNode.java
@@ -1,21 +1,16 @@
package com.seaofnodes.simple.node;
+
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeInteger;
-import java.util.BitSet;
public class MulNode extends Node {
public MulNode(Node lhs, Node rhs) { super(null, lhs, rhs); }
@Override public String label() { return "Mul"; }
- @Override
- StringBuilder _print1(StringBuilder sb, BitSet visited) {
- in(1)._print0(sb.append("("), visited);
- in(2)._print0(sb.append("*"), visited);
- return sb.append(")");
- }
+ @Override protected String format() { return "(%1*%2)"; }
@Override
public Type compute() {
diff --git a/chapter11/src/main/java/com/seaofnodes/simple/node/NeverNode.java b/chapter11/src/main/java/com/seaofnodes/simple/node/NeverNode.java
index f50d3503..6eb7fe63 100644
--- a/chapter11/src/main/java/com/seaofnodes/simple/node/NeverNode.java
+++ b/chapter11/src/main/java/com/seaofnodes/simple/node/NeverNode.java
@@ -1,9 +1,10 @@
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 java.util.BitSet;
// "Never true" for infinite loop exits
public class NeverNode extends IfNode {
@@ -11,7 +12,7 @@ public class NeverNode extends IfNode {
@Override public String label() { return "Never"; }
- @Override 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 TypeInteger.BOT; }
diff --git a/chapter11/src/main/java/com/seaofnodes/simple/node/NewNode.java b/chapter11/src/main/java/com/seaofnodes/simple/node/NewNode.java
index 1c82d5f5..74ba5184 100644
--- a/chapter11/src/main/java/com/seaofnodes/simple/node/NewNode.java
+++ b/chapter11/src/main/java/com/seaofnodes/simple/node/NewNode.java
@@ -1,9 +1,10 @@
package com.seaofnodes.simple.node;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeMemPtr;
-import java.util.BitSet;
public class NewNode extends Node {
@@ -17,10 +18,8 @@ public class NewNode extends Node {
@Override
public String label() { return "new"; }
- @Override
- StringBuilder _print1(StringBuilder sb, BitSet visited) {
- sb.append("new ");
- return sb.append(_ptr._obj.str());
+ @Override protected ExprPrinter<Node> _print1(ExprPrinter<Node> p) {
+ return p.p("new ").p(_ptr._obj.str());
}
diff --git a/chapter11/src/main/java/com/seaofnodes/simple/node/Node.java b/chapter11/src/main/java/com/seaofnodes/simple/node/Node.java
index 2d09db40..568c23cc 100644
--- a/chapter11/src/main/java/com/seaofnodes/simple/node/Node.java
+++ b/chapter11/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.IRPrinter;
import com.seaofnodes.simple.Parser;
import com.seaofnodes.simple.IterPeeps;
@@ -14,14 +16,7 @@ import java.util.function.Function;
* The Node class provides common functionality used by all subtypes.
* Subtypes of Node specialize by overriding methods.
*/
-public abstract class Node implements OutNode, 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 OutNode, Cloneable {
/**
* Inputs to the node. These are use-def references to Nodes.
@@ -43,14 +38,12 @@ public abstract class Node implements OutNode, Cloneable {
*/
public ArrayList<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;
-
/**
* A private Global Static mutable counter, for unique node id generation.
* To make the compiler multithreaded, this field will have to move into a TLS.
@@ -60,7 +53,7 @@ public abstract class Node implements OutNode, Cloneable {
public static int UID() { return UNIQUE_ID; }
protected Node(Node... inputs) {
- _nid = UNIQUE_ID++; // allocate unique dense ID
+ super(UNIQUE_ID++); // allocate unique dense ID
_inputs = new ArrayList<>();
Collections.addAll(_inputs,inputs);
_outputs = new ArrayList<>();
@@ -72,42 +65,6 @@ public abstract class Node implements OutNode, Cloneable {
// Easy reading label for debugger, e.g. "Add" or "Region" or "EQ"
public abstract String label();
- // Unique label for debugging, e.g. "Add12" or "Region30" or "EQ99"
- public String uniqueName() {
- return label() + _nid;
- }
-
- // ------------------------------------------------------------------------
-
- // 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. This version will fail on cycles, which we will
- // correct later when we can parse programs with loops. We print with a
- // 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.
- 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 StringBuilder _print1(StringBuilder sb, BitSet visited);
-
public String p(int depth) { return IRPrinter.prettyPrint(this,depth); }
public boolean isMultiHead() { return false; }
@@ -116,6 +73,8 @@ public abstract class Node implements OutNode, 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
@@ -255,7 +214,6 @@ public abstract class Node implements OutNode, Cloneable {
// Test "keep" status
public boolean iskeep() { return Utils.find(_outputs,null) != -1; }
-
// Replace self with nnn in the graph, making 'this' go dead
public void subsume( Node nnn ) {
assert nnn!=this;
@@ -386,7 +344,6 @@ public abstract class Node implements OutNode, Cloneable {
return old;
}
-
/**
* This function rewrites the current Node into a more "idealized" form.
* This is the bulk of our peephole rewrite rules, and we use this to
@@ -434,7 +391,6 @@ public abstract class Node implements OutNode, 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
@@ -478,7 +434,6 @@ public abstract class Node implements OutNode, Cloneable {
_deps.clear();
}
-
// Global Value Numbering. Hash over opcode and inputs; hits in this table
// are structurally equal.
public static final HashMap<Node,Node> GVN = new HashMap<>();
@@ -500,7 +455,6 @@ public abstract class Node implements OutNode, Cloneable {
// and can assume "this!=n" and has the same Java class.
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
@@ -516,7 +470,6 @@ public abstract class Node implements OutNode, Cloneable {
_hash=0; // Out of table now
}
-
// Hash of opcode and inputs
@Override public final int hashCode() {
if( _hash != 0 ) return _hash;
@@ -534,7 +487,6 @@ public abstract class Node implements OutNode, Cloneable {
//
/** Is this Node control-flow-graph related */
- public boolean isCFG() { return false; }
/** Is this Node Memory related */
public boolean isMem() { return false; }
@@ -542,7 +494,6 @@ public abstract class Node implements OutNode, Cloneable {
/** Return block start from a isCFG() */
public Node getBlockStart() { return null; }
-
// ------------------------------------------------------------------------
// Peephole utilities
@@ -571,7 +522,6 @@ public abstract class Node implements OutNode, 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.
@@ -604,7 +554,6 @@ public abstract class Node implements OutNode, Cloneable {
ITER_CNT = ITER_NOP_CNT = 0;
}
-
// Utility to walk the entire graph applying a function; return the first
// not-null result.
private static final BitSet WVISIT = new BitSet();
diff --git a/chapter11/src/main/java/com/seaofnodes/simple/node/NotNode.java b/chapter11/src/main/java/com/seaofnodes/simple/node/NotNode.java
index 83141836..5e556390 100644
--- a/chapter11/src/main/java/com/seaofnodes/simple/node/NotNode.java
+++ b/chapter11/src/main/java/com/seaofnodes/simple/node/NotNode.java
@@ -1,19 +1,15 @@
package com.seaofnodes.simple.node;
+
import com.seaofnodes.simple.Utils;
import com.seaofnodes.simple.type.*;
-import java.util.BitSet;
public class NotNode extends Node {
public NotNode(Node in) { super(null, in); }
@Override public String label() { return "Not"; }
- @Override
- 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/chapter11/src/main/java/com/seaofnodes/simple/node/PhiNode.java b/chapter11/src/main/java/com/seaofnodes/simple/node/PhiNode.java
index 886ef092..8f3cda9e 100644
--- a/chapter11/src/main/java/com/seaofnodes/simple/node/PhiNode.java
+++ b/chapter11/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.type.Type;
import com.seaofnodes.simple.type.TypeMem;
import com.seaofnodes.simple.Utils;
-import java.util.BitSet;
public class PhiNode extends Node {
@@ -23,18 +24,12 @@ public class PhiNode extends Node {
@Override public String label() { return "Phi_"+_label; }
@Override
- 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/chapter11/src/main/java/com/seaofnodes/simple/node/ProjNode.java b/chapter11/src/main/java/com/seaofnodes/simple/node/ProjNode.java
index 93239a61..e82c69b3 100644
--- a/chapter11/src/main/java/com/seaofnodes/simple/node/ProjNode.java
+++ b/chapter11/src/main/java/com/seaofnodes/simple/node/ProjNode.java
@@ -1,10 +1,11 @@
package com.seaofnodes.simple.node;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeMem;
import com.seaofnodes.simple.type.TypeTuple;
-import java.util.BitSet;
public class ProjNode extends Node {
@@ -24,7 +25,7 @@ public class ProjNode extends Node {
public String label() { return _label; }
@Override
- StringBuilder _print1(StringBuilder sb, BitSet visited) { return sb.append(_label); }
+ protected ExprPrinter<Node> _print1(ExprPrinter<Node> p) { return p.p(_label); }
@Override public boolean isMultiTail() { return in(0).isMultiHead(); }
@Override public boolean isMem() { return _type instanceof TypeMem; }
diff --git a/chapter11/src/main/java/com/seaofnodes/simple/node/RegionNode.java b/chapter11/src/main/java/com/seaofnodes/simple/node/RegionNode.java
index 8933ea74..f0808410 100644
--- a/chapter11/src/main/java/com/seaofnodes/simple/node/RegionNode.java
+++ b/chapter11/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.IterPeeps;
import com.seaofnodes.simple.Parser;
import com.seaofnodes.simple.Utils;
@@ -16,9 +18,8 @@ public class RegionNode extends CFGNode {
@Override
public String label() { return "Region"; }
- @Override
- StringBuilder _print1(StringBuilder sb, BitSet visited) {
- return sb.append(label()).append(_nid);
+ @Override protected ExprPrinter<Node> _print1(ExprPrinter<Node> p) {
+ return p.p(label()).p(_nid);
}
@Override public boolean isMultiHead() { return true; }
diff --git a/chapter11/src/main/java/com/seaofnodes/simple/node/ReturnNode.java b/chapter11/src/main/java/com/seaofnodes/simple/node/ReturnNode.java
index 725c704f..161cc7d6 100644
--- a/chapter11/src/main/java/com/seaofnodes/simple/node/ReturnNode.java
+++ b/chapter11/src/main/java/com/seaofnodes/simple/node/ReturnNode.java
@@ -1,8 +1,9 @@
package com.seaofnodes.simple.node;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.type.*;
-import java.util.BitSet;
/** Keeps all preceding memory effects and the return value alive: {ctrl, $mem, value}. */
public class ReturnNode extends CFGNode {
@@ -20,10 +21,10 @@ public class ReturnNode extends CFGNode {
public String label() { return "Return"; }
@Override
- StringBuilder _print1(StringBuilder sb, BitSet visited) {
- sb.append("return ");
- expr()._print0(sb, visited);
- return sb.append(";");
+ protected ExprPrinter<Node> _print1(ExprPrinter<Node> p) {
+ p.p("return ");
+ p.n(expr());
+ return p.p(";");
}
@Override
diff --git a/chapter11/src/main/java/com/seaofnodes/simple/node/ScopeNode.java b/chapter11/src/main/java/com/seaofnodes/simple/node/ScopeNode.java
index b931e862..b408eb2f 100644
--- a/chapter11/src/main/java/com/seaofnodes/simple/node/ScopeNode.java
+++ b/chapter11/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.IterPeeps;
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.Utils;
@@ -42,20 +44,19 @@ public class ScopeNode extends Node {
@Override public String label() { return "Scope"; }
@Override
- StringBuilder _print1(StringBuilder sb, BitSet visited) {
- sb.append("Scope[ ");
+ protected ExprPrinter<Node> _print1(ExprPrinter<Node> p) {
+ p.p("Scope[ ");
String[] names = reverseNames();
for( int j=0; j<nIns(); j++ ) {
- sb.append(names[j]).append(":");
+ p.p(names[j]).p(":");
Node n = in(j);
while( n instanceof ScopeNode loop ) {
- sb.append("Lazy_");
+ p.p("Lazy_");
n = loop.in(j);
}
- n._print0(sb, visited).append(" ");
+ p.n(n).p(" ");
}
- sb.setLength(sb.length()-1);
- return sb.append("]");
+ return p.unchar(' ').p("]");
}
/**
diff --git a/chapter11/src/main/java/com/seaofnodes/simple/node/StartNode.java b/chapter11/src/main/java/com/seaofnodes/simple/node/StartNode.java
index b4fa549b..c1b57915 100644
--- a/chapter11/src/main/java/com/seaofnodes/simple/node/StartNode.java
+++ b/chapter11/src/main/java/com/seaofnodes/simple/node/StartNode.java
@@ -1,5 +1,7 @@
package com.seaofnodes.simple.node;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.type.*;
import java.util.BitSet;
import java.util.HashSet;
@@ -17,9 +19,8 @@ public class StartNode extends CFGNode implements MultiNode {
@Override
public String label() { return "Start"; }
- @Override
- 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 isMultiHead() { return true; }
diff --git a/chapter11/src/main/java/com/seaofnodes/simple/node/StopNode.java b/chapter11/src/main/java/com/seaofnodes/simple/node/StopNode.java
index fcd6d4ab..46cf51da 100644
--- a/chapter11/src/main/java/com/seaofnodes/simple/node/StopNode.java
+++ b/chapter11/src/main/java/com/seaofnodes/simple/node/StopNode.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.Type;
import com.seaofnodes.simple.IterPeeps;
-import java.util.BitSet;
public class StopNode extends CFGNode {
@@ -22,12 +23,12 @@ public class StopNode extends CFGNode {
}
@Override
- StringBuilder _print1(StringBuilder sb, BitSet visited) {
- if( ret()!=null ) return ret()._print0(sb, visited);
- sb.append("Stop[ ");
+ protected ExprPrinter<Node> _print1(ExprPrinter<Node> p) {
+ if( ret()!=null ) return p.n(ret());
+ p.p("Stop[ ");
for( Node ret : _inputs )
- ret._print0(sb, visited).append(" ");
- return sb.append("]");
+ p.n(ret).p(" ");
+ return p.p("]");
}
@Override public boolean blockHead() { return true; }
diff --git a/chapter11/src/main/java/com/seaofnodes/simple/node/StoreNode.java b/chapter11/src/main/java/com/seaofnodes/simple/node/StoreNode.java
index b816762b..f61afe78 100644
--- a/chapter11/src/main/java/com/seaofnodes/simple/node/StoreNode.java
+++ b/chapter11/src/main/java/com/seaofnodes/simple/node/StoreNode.java
@@ -1,10 +1,11 @@
package com.seaofnodes.simple.node;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.Utils;
import com.seaofnodes.simple.IterPeeps;
import com.seaofnodes.simple.type.*;
-import java.util.BitSet;
/**
* Store represents setting a value to a memory based object, in chapter 10
@@ -29,8 +30,8 @@ public class StoreNode extends MemOpNode {
public Node val() { return in(3); }
@Override
- 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/chapter11/src/main/java/com/seaofnodes/simple/node/SubNode.java b/chapter11/src/main/java/com/seaofnodes/simple/node/SubNode.java
index 2c5bafca..7b4cff0b 100644
--- a/chapter11/src/main/java/com/seaofnodes/simple/node/SubNode.java
+++ b/chapter11/src/main/java/com/seaofnodes/simple/node/SubNode.java
@@ -1,22 +1,17 @@
package com.seaofnodes.simple.node;
+
import com.seaofnodes.simple.Parser;
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeInteger;
-import java.util.BitSet;
public class SubNode extends Node {
public SubNode(Node lhs, Node rhs) { super(null, lhs, rhs); }
@Override public String label() { return "Sub"; }
- @Override
- StringBuilder _print1(StringBuilder sb, BitSet visited) {
- in(1)._print0(sb.append("("), visited);
- in(2)._print0(sb.append("-"), visited);
- return sb.append(")");
- }
+ @Override protected String format() { return "(%1-%2)"; }
@Override
public Type compute() {
diff --git a/chapter11/src/main/java/com/seaofnodes/simple/node/XCtrlNode.java b/chapter11/src/main/java/com/seaofnodes/simple/node/XCtrlNode.java
index 83779dd2..056dfba1 100644
--- a/chapter11/src/main/java/com/seaofnodes/simple/node/XCtrlNode.java
+++ b/chapter11/src/main/java/com/seaofnodes/simple/node/XCtrlNode.java
@@ -1,13 +1,14 @@
package com.seaofnodes.simple.node;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.Parser;
import com.seaofnodes.simple.type.Type;
-import java.util.BitSet;
public class XCtrlNode extends CFGNode {
public XCtrlNode( ) { super(Parser.START); }
@Override public String label() { return "Xctrl"; }
- @Override StringBuilder _print1(StringBuilder sb, BitSet visited) { return sb.append("Xctrl"); }
+ @Override protected ExprPrinter<Node> _print1(ExprPrinter<Node> p) { return p.p("Xctrl"); }
@Override public Type compute() { return Type.XCONTROL; }
@Override public Node idealize() { return null; }
}
diff --git a/chapter11/src/main/java/com/seaofnodes/simple/print/SimpleGraphAdapter.java b/chapter11/src/main/java/com/seaofnodes/simple/print/SimpleGraphAdapter.java
index 9ddf0de6..89ef99bd 100644
--- a/chapter11/src/main/java/com/seaofnodes/simple/print/SimpleGraphAdapter.java
+++ b/chapter11/src/main/java/com/seaofnodes/simple/print/SimpleGraphAdapter.java
@@ -1,43 +1,20 @@
package com.seaofnodes.simple.print;
import com.seaofnodes.graph.GraphAdapter;
-import com.seaofnodes.graph.GraphSnapshot;
import com.seaofnodes.graph.GraphSnapshot.*;
import com.seaofnodes.simple.node.*;
import com.seaofnodes.simple.node.Node;
import com.seaofnodes.simple.type.TypeMem;
-import java.util.ArrayList;
/** Chapter 11's view of the IR; browser, transport and layout are shared. */
public class SimpleGraphAdapter extends GraphAdapter<Node> {
- @Override protected boolean dead(Node n) { return n.isDead(); }
- @Override protected int id(Node n) { return n._nid; }
- @Override protected int nIns(Node n) { return n.nIns(); }
- @Override protected Node in(Node n, int idx) { return n.in(idx); }
- @Override protected int nOuts(Node n) { return n.nOuts(); }
- @Override protected Node out(Node n, int idx) { return n.out(idx); }
- @Override protected int nDeps(Node n) { return n.nDeps(); }
- @Override protected Node dep(Node n, int idx) { return n.dep(idx); }
- private ArrayList<Edge> edges(Node n) {
- var edges = new ArrayList<Edge>();
- String[] names = n instanceof ScopeNode scope && n.nIns() != 0 ? scope.reverseNames() : null;
- for( int i = 0; i < n.nIns(); i++ ) {
- String name = names == null || i >= names.length ? null : names[i];
- edges.add(new Edge(i, ref(n.in(i)), role(n, i), name));
- }
- return edges;
+ @Override protected String[] edgeNames(Node n) {
+ return n instanceof ScopeNode scope && n.nIns()!=0 ? scope.reverseNames() : null;
}
+ @Override protected int projectionIndex(Node n) { return n instanceof ProjNode p ? p._idx : n instanceof CProjNode p ? p._idx : -1; }
- @Override protected GraphSnapshot.Node desc(Node n) {
- Projection proj = n instanceof ProjNode p ? new Projection(ref(n.in(0)), p._idx)
- : n instanceof CProjNode p ? new Projection(ref(n.in(0)), p._idx) : null;
- String label = n.label();
- return new GraphSnapshot.Node(n._nid, label == null ? n.getClass().getSimpleName() : label,
- n._type == null ? null : n._type.toString(), kind(n), edges(n), proj);
- }
-
- 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 StartNode ) return Kind.CTRL;
@@ -47,7 +24,7 @@ public class SimpleGraphAdapter extends GraphAdapter<Node> {
return n.isCFG() ? Kind.CTRL : isMem(n) ? Kind.MEM : Kind.DATA;
}
- private Role role(Node n, int i) {
+ @Override protected Role role(Node n, int i) {
if( n instanceof ScopeNode || n instanceof ConstantNode || n instanceof XCtrlNode ) return Role.ASSOC;
if( n instanceof PhiNode ) return i == 0 ? Role.ASSOC : isMem(n) ? Role.MEM : Role.DATA;
if( n instanceof ProjNode || n instanceof CProjNode ) return n.isCFG() ? Role.CTRL : isMem(n) ? Role.MEM : Role.DATA;
diff --git a/chapter12/Makefile b/chapter12/Makefile
index 77df7182..3f1e53ff 100644
--- a/chapter12/Makefile
+++ b/chapter12/Makefile
@@ -37,6 +37,7 @@ main_javas := $(wildcard $(SRC)/$(SIMPLE)/*java $(SRC)/$(SIMPLE)/*/*java)
test_javas := $(wildcard $(TST)/$(SIMPLE)/*java $(TST)/$(SIMPLE)/*/*java)
main_classes := $(patsubst $(SRC)/%java,$(CLZDIR)/main/%class,$(main_javas))
include $(firstword $(wildcard ../graph/graph.mk graph/graph.mk))
+include $(firstword $(wildcard ../print/print.mk print/print.mk))
test_classes := $(patsubst $(TST)/%java,$(CLZDIR)/test/%class,$(test_javas))
test_cp := $(patsubst $(TST)/$(SIMPLE)/%.java,com.seaofnodes.simple.%,$(wildcard $(TST)/$(SIMPLE)/*Test.java))
classes = $(main_classes) $(test_classes)
@@ -54,7 +55,7 @@ endif
default: $(default_targets)
# Compile just the out-of-date files
-$(main_classes): build/classes/main/%class: $(SRC)/%java $(graph_javas)
+$(main_classes): build/classes/main/%class: $(SRC)/%java $(graph_javas) $(print_javas)
@echo "compiling " $@ " because " $?
@[ -d $(CLZDIR)/main ] || mkdir -p $(CLZDIR)/main
@javac $(JAVAC_ARGS) -cp "$(CLZDIR)/main$(SEP)$(jars)" -sourcepath $(SRC) -d $(CLZDIR)/main $(main_javas)
diff --git a/chapter12/pom.xml b/chapter12/pom.xml
index f70175a8..e63ae3a2 100644
--- a/chapter12/pom.xml
+++ b/chapter12/pom.xml
@@ -13,5 +13,6 @@
<name>Chapter 12</name>
<properties>
<simple.graph.directory>${project.basedir}/../graph</simple.graph.directory>
+ <simple.print.directory>${project.basedir}/../print</simple.print.directory>
</properties>
</project>
diff --git a/chapter12/src/main/java/com/seaofnodes/simple/IRPrinter.java b/chapter12/src/main/java/com/seaofnodes/simple/IRPrinter.java
index 3410ab64..7e93e9da 100644
--- a/chapter12/src/main/java/com/seaofnodes/simple/IRPrinter.java
+++ b/chapter12/src/main/java/com/seaofnodes/simple/IRPrinter.java
@@ -1,288 +1,33 @@
package com.seaofnodes.simple;
+import com.seaofnodes.print.IRAdapter;
import com.seaofnodes.simple.node.*;
-import java.lang.StringBuilder;
-import java.util.ArrayList;
-import java.util.BitSet;
-import java.util.HashMap;
-import java.util.IdentityHashMap;
-
-public 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 void _printLine( Node n, StringBuilder sb ) {
- sb.append("%4d %-7.7s ".formatted(n._nid,n.label()));
- if( n.isDead() ) {
- sb.append("DEAD\n");
- return;
- }
- for( Node def : n._inputs )
- sb.append(def==null ? "____ " : "%4d ".formatted(def._nid));
- for( int i = n._inputs.size(); i<4; i++ )
- sb.append(" ");
- sb.append(" [[ ");
- for( Node use : n._outputs )
- sb.append(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.append(" ");
- sb.append(" ]] ");
- if( n._type!= null ) sb.append(n._type.str());
- sb.append("\n");
- }
-
- private static StringBuilder nodeId(StringBuilder sb, Node n) {
- sb.append("%%%d".formatted(n._nid));
- if (n instanceof ProjNode proj) {
- sb.append(".").append(proj._idx);
- }
- return sb;
- }
-
- // Print a node on 1 line, format is inspired by LLVM
- // %id: TYPE = NODE(inputs ....)
- // Nodes as referred to as %id
- public static void _printLineLlvmFormat( Node n, StringBuilder sb ) {
- nodeId(sb, n).append(": ");
- if( n.isDead() ) {
- sb.append("DEAD\n");
- return;
- }
- if( n._type!= null ) n._type.typeName(sb);
- sb.append(" = ").append( n.label() ).append( "(" );
- for( int i = 0; i < n._inputs.size(); i++ ) {
- Node def = n.in(i);
- if (i > 0)
- sb.append(", ");
- if (def == null) sb.append("_");
- else nodeId(sb, def);
- }
- sb.append(")").append("\n");
- }
-
- public static void printLine( Node n, StringBuilder sb, boolean llvmFormat ) {
- if (llvmFormat) _printLineLlvmFormat( n, sb );
- else _printLine ( n, sb );
- }
-
- public static String prettyPrint(Node node, int depth) {
- return Parser.SCHEDULED
- ? prettyPrintScheduled( node, depth, false )
- : prettyPrint( node, depth, false );
- }
-
- // Another bulk pretty-printer. Makes more effort at basic-block grouping.
- public static String prettyPrint( Node node, int depth, boolean llvmFormat ) {
- // First, a Breadth First Search at a fixed depth.
- BFS bfs = new BFS(node,depth);
- // Convert just that set to a post-order
- ArrayList<Node> rpos = new ArrayList<>();
- BitSet visit = new BitSet();
- for( int i=bfs._lim; i< bfs._bfs.size(); i++ )
- postOrd( bfs._bfs.get(i), rpos, visit, bfs._bs);
- // Reverse the post-order walk
- StringBuilder sb = new StringBuilder();
- boolean gap=false;
- for( int i=rpos.size()-1; i>=0; i-- ) {
- Node n = rpos.get(i);
- if( n.isCFG() || n.isMultiHead() ) {
- if( !gap ) sb.append("\n"); // Blank before multihead
- printLine( n, sb, llvmFormat ); // Print head
- while( --i >= 0 ) {
- Node t = rpos.get(i);
- if( !t.isMultiTail() ) { i++; break; }
- printLine( t, sb, llvmFormat );
- }
- sb.append("\n"); // Blank after multitail
- gap = true;
- } else {
- printLine( n, sb, llvmFormat );
- gap = false;
- }
- }
- return sb.toString();
- }
-
- private static void postOrd(Node n, ArrayList<Node> rpos, BitSet visit, BitSet bfs) {
- if( !bfs.get(n._nid) )
- return; // Not in the BFS visit
- if( visit.get(n._nid) ) return; // Already post-order walked
- visit.set(n._nid);
- // First walk the CFG, then everything
- if( n.isCFG() ) {
- for( Node use : n._outputs )
- if( use!=null && use.isCFG() && use.nOuts()>=1 && !(use._outputs.get(0) instanceof LoopNode) )
- postOrd(use, rpos,visit,bfs);
- for( Node use : n._outputs )
- if( use!=null && use.isCFG() )
- postOrd(use,rpos,visit,bfs);
- }
- for( Node use : n._outputs )
- if( use != null )
- postOrd(use, rpos,visit,bfs);
- // Post-order
- rpos.add(n);
- }
-
- // Breadth-first search, broken out in a class to keep in more independent.
- // Maintains a root-set of Nodes at the limit (or past by 1 if MultiHead).
- public static class BFS {
- // A breadth first search, plus MultiHeads for any MultiTails
- public final ArrayList<Node> _bfs;
- public final BitSet _bs; // Visited members by node id
- public final int _depth; // Depth limit
- public final int _lim; // From here to _bfs._len can be roots for a reverse search
- public BFS( Node base, int d ) {
- _depth = d;
- _bfs = new ArrayList<>();
- _bs = new BitSet();
-
- add(base); // Prime the pump
- int idx=0, lim=1; // Limit is where depth counter changes
- while( idx < _bfs.size() ) { // Ran out of nodes below depth
- Node n = _bfs.get(idx++);
- for( Node def : n._inputs )
- if( def!=null && !_bs.get(def._nid) )
- add(def);
- if( idx==lim ) { // Depth counter changes at limit
- if( --d < 0 )
- break; // Ran out of depth
- lim = _bfs.size(); // New depth limit
- }
- }
- // Toss things past the limit except multi-heads
- while( idx < _bfs.size() ) {
- Node n = _bfs.get(idx);
- if( n.isMultiHead() ) idx++;
- else del(idx);
- }
- // Root set is any node with no inputs in the visited set
- lim = _bfs.size();
- for( int i=_bfs.size()-1; i>=0; i-- )
- if( !any_visited(_bfs.get(i)) )
- swap( i,--lim);
- _lim = lim;
- }
- void swap( int x, int y ) {
- if( x==y ) return;
- Node tx = _bfs.get(x);
- Node ty = _bfs.get(y);
- _bfs.set(x,ty);
- _bfs.set(y,tx);
- }
- void add(Node n) {
- _bfs.add(n);
- _bs.set(n._nid);
- }
- void del(int idx) {
- Node n = Utils.del(_bfs, idx);
- _bs.clear(n._nid);
- }
- boolean any_visited( Node n ) {
- for( Node def : n._inputs )
- if( def!=null && _bs.get(def._nid) )
- return true;
- return false;
- }
- }
-
- // Diagnostic block ordering from raw control edges. Do not call idepth():
- // it fills compiler caches (and can walk lazy dominator accessors).
- private static int _idepth(CFGNode cfg, HashMap<Integer,Integer> depths) {
- if( cfg == null || cfg instanceof StartNode ) return 0;
- Integer old = depths.get(cfg._nid);
- if( old != null ) return old;
- depths.put(cfg._nid,0); // Break cycles in partially constructed graphs.
- int d = 0;
- if( cfg instanceof LoopNode ) {
- d = _idepth((CFGNode)cfg.in(1),depths)+1;
- } else if( cfg instanceof RegionNode || cfg instanceof StopNode ) {
- for( Node n : cfg._inputs )
- if( n instanceof CFGNode pred ) d = Math.max(d,_idepth(pred,depths)+1);
- } else if( cfg.in(0) instanceof CFGNode pred ) {
- d = _idepth(pred,depths)+1;
- }
- depths.put(cfg._nid,d);
- return d;
- }
-
- // Bulk pretty printer, knowing scheduling information is available
- public static String prettyPrintScheduled( Node node, int depth, boolean llvmFormat ) {
- // Backwards DFS walk to depth.
- IdentityHashMap<Node,Integer> ds = new IdentityHashMap<>();
- _walk(ds,node,depth);
- // Print by block with least diagnostic depth
- HashMap<Integer,Integer> depths = new HashMap<>();
- StringBuilder sb = new StringBuilder();
- ArrayList<Node> bns = new ArrayList<>();
- while( !ds.isEmpty() ) {
- CFGNode blk = null;
- for( Node n : ds.keySet() ) {
- CFGNode cfg = n instanceof CFGNode cfg0 && cfg0.blockHead() ? cfg0 : (CFGNode)n.in(0);
- if( blk==null || _idepth(cfg,depths) < _idepth(blk,depths) )
- blk = cfg;
- }
- ds.remove(blk);
-
- // Print block header
- sb.append("%-13.13s".formatted(label(blk)+":"));
- sb.append( " ".repeat(4) ).append(" [[ ");
- if( blk instanceof RegionNode || blk instanceof StopNode )
- for( int i=(blk instanceof StopNode ? 0 : 1); i<blk.nIns(); i++ )
- label(sb,blk.cfg(i));
- else if( !(blk instanceof StartNode) )
- label(sb,blk.cfg(0));
- sb.append(" ]] \n");
-
- // Collect block contents that are in the depth limit
- bns.clear();
- int xd = Integer.MAX_VALUE;
- for( Node use : blk._outputs ) {
- Integer i = ds.get(use);
- if( i!=null && !(use instanceof CFGNode cfg && cfg.blockHead()) ) {
- bns.add(use);
- xd = Math.min(xd,i);
- }
- }
- // Print Phis up front, if any
- for( int i=0; i<bns.size(); i++ )
- if( bns.get(i) instanceof PhiNode phi )
- printLine( phi, sb, llvmFormat,bns,i--,ds);
-
- // Print block contents in depth order, bumping depth until whole block printed
- for( ; !bns.isEmpty(); xd++ )
- for( int i=0; i<bns.size(); i++ )
- if( ds.get(bns.get(i))==xd )
- printLine( bns.get(i), sb, llvmFormat, bns, i--, ds );
- sb.append("\n");
- }
- return sb.toString();
- }
-
- private static void _walk( IdentityHashMap<Node,Integer> ds, Node node, int d ) {
- Integer nd = ds.get(node);
- if( nd!=null && d <= nd ) return; // Been there, done that
- ds.put(node,d);
- if( d == 0 ) return; // Depth cutoff
- for( Node def : node._inputs )
- if( def != null )
- _walk(ds,def,d-1);
- }
-
- static String label( CFGNode blk ) {
- if( blk instanceof StartNode ) return "START";
- return (blk instanceof LoopNode ? "LOOP" : "L")+blk._nid;
- }
- static void label( StringBuilder sb, CFGNode blk ) {
- if( !blk.blockHead() ) blk = blk.cfg(0);
- sb.append( "%-9.9s ".formatted( label( blk ) ) );
- }
- static void printLine( Node n, StringBuilder sb, boolean llvmFormat, ArrayList<Node> bns, int i, IdentityHashMap<Node,Integer> ds ) {
- printLine( n, sb, llvmFormat );
- Utils.del(bns,i);
- ds.remove(n);
- }
+/** 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 String type(Node n) { return n._type==null ? "" : n._type.str(); }
+ @Override public String inputMark(Node n, Node def) { return n instanceof MemMergeNode && def instanceof MemMergeNode ? "^" : " "; }
+ @Override public Kind kind(Node n) {
+ if( n instanceof StartNode ) return Kind.START;
+ if( n instanceof StopNode ) return Kind.STOP;
+ if( n instanceof LoopNode ) return Kind.LOOP;
+ if( n instanceof RegionNode ) return Kind.REGION;
+ if( n instanceof PhiNode ) return Kind.PHI;
+ 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;
+ }
+
+ public static String prettyPrint(Node n, int depth) { return PRINT.prettyPrint(n,depth); }
}
diff --git a/chapter12/src/main/java/com/seaofnodes/simple/node/AddFNode.java b/chapter12/src/main/java/com/seaofnodes/simple/node/AddFNode.java
index 5d0a473a..fd713156 100644
--- a/chapter12/src/main/java/com/seaofnodes/simple/node/AddFNode.java
+++ b/chapter12/src/main/java/com/seaofnodes/simple/node/AddFNode.java
@@ -1,21 +1,16 @@
package com.seaofnodes.simple.node;
+
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeFloat;
-import java.util.BitSet;
public class AddFNode extends Node {
public AddFNode(Node lhs, Node rhs) { super(null, lhs, rhs); }
@Override public String label() { return "AddF"; }
- @Override
- StringBuilder _print1(StringBuilder sb, BitSet visited) {
- in(1)._print0(sb.append("("), visited);
- in(2)._print0(sb.append("+"), visited);
- return sb.append(")");
- }
+ @Override protected String format() { return "(%1+%2)"; }
@Override
public Type compute() {
diff --git a/chapter12/src/main/java/com/seaofnodes/simple/node/AddNode.java b/chapter12/src/main/java/com/seaofnodes/simple/node/AddNode.java
index 188c50a8..01aa209f 100644
--- a/chapter12/src/main/java/com/seaofnodes/simple/node/AddNode.java
+++ b/chapter12/src/main/java/com/seaofnodes/simple/node/AddNode.java
@@ -1,20 +1,15 @@
package com.seaofnodes.simple.node;
+
import com.seaofnodes.simple.type.*;
-import java.util.BitSet;
public class AddNode extends Node {
public AddNode(Node lhs, Node rhs) { super(null, lhs, rhs); }
@Override public String label() { return "Add"; }
- @Override
- StringBuilder _print1(StringBuilder sb, BitSet visited) {
- in(1)._print0(sb.append("("), visited);
- in(2)._print0(sb.append("+"), visited);
- return sb.append(")");
- }
+ @Override protected String format() { return "(%1+%2)"; }
@Override
diff --git a/chapter12/src/main/java/com/seaofnodes/simple/node/BoolNode.java b/chapter12/src/main/java/com/seaofnodes/simple/node/BoolNode.java
index 2055ea6f..e515a5f1 100644
--- a/chapter12/src/main/java/com/seaofnodes/simple/node/BoolNode.java
+++ b/chapter12/src/main/java/com/seaofnodes/simple/node/BoolNode.java
@@ -1,5 +1,7 @@
package com.seaofnodes.simple.node;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.Parser;
import com.seaofnodes.simple.Utils;
import com.seaofnodes.simple.type.Type;
@@ -7,7 +9,6 @@ import com.seaofnodes.simple.type.TypeInteger;
import com.seaofnodes.simple.type.TypeFloat;
import com.seaofnodes.simple.type.TypeMemPtr;
-import java.util.BitSet;
abstract public class BoolNode extends Node {
@@ -20,11 +21,8 @@ abstract public class BoolNode extends Node {
@Override
public String label() { return getClass().getSimpleName(); }
- @Override
- 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/chapter12/src/main/java/com/seaofnodes/simple/node/CProjNode.java b/chapter12/src/main/java/com/seaofnodes/simple/node/CProjNode.java
index fb0ff879..ff5d1a76 100644
--- a/chapter12/src/main/java/com/seaofnodes/simple/node/CProjNode.java
+++ b/chapter12/src/main/java/com/seaofnodes/simple/node/CProjNode.java
@@ -1,10 +1,11 @@
package com.seaofnodes.simple.node;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.Parser;
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeMem;
import com.seaofnodes.simple.type.TypeTuple;
-import java.util.BitSet;
public class CProjNode extends CFGNode {
@@ -22,7 +23,7 @@ public class CProjNode extends CFGNode {
@Override public String label() { return _label; }
- @Override 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 isMultiTail() { return in(0).isMultiHead(); }
@Override public boolean blockHead() { return true; }
diff --git a/chapter12/src/main/java/com/seaofnodes/simple/node/CastNode.java b/chapter12/src/main/java/com/seaofnodes/simple/node/CastNode.java
index fec540f7..c1faf210 100644
--- a/chapter12/src/main/java/com/seaofnodes/simple/node/CastNode.java
+++ b/chapter12/src/main/java/com/seaofnodes/simple/node/CastNode.java
@@ -1,10 +1,11 @@
package com.seaofnodes.simple.node;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeInteger;
import com.seaofnodes.simple.IterPeeps;
-import java.util.BitSet;
// Upcast (join) the input to a t. Used after guard test to lift an input.
// Can also be used to make a type-assertion if ctrl is null.
@@ -18,12 +19,9 @@ public class CastNode extends Node {
@Override public String label() { return "("+_t.str()+")"; }
- @Override
- public String uniqueName() { return "Cast_" + _nid; }
- @Override
- StringBuilder _print1(StringBuilder sb, BitSet visited) {
- return in(1)._print0(sb.append(label()), visited);
+ @Override protected ExprPrinter<Node> _print1(ExprPrinter<Node> p) {
+ return p.p(label()).n(in(1));
}
@Override
diff --git a/chapter12/src/main/java/com/seaofnodes/simple/node/ConstantNode.java b/chapter12/src/main/java/com/seaofnodes/simple/node/ConstantNode.java
index 37a529d1..9ecd1152 100644
--- a/chapter12/src/main/java/com/seaofnodes/simple/node/ConstantNode.java
+++ b/chapter12/src/main/java/com/seaofnodes/simple/node/ConstantNode.java
@@ -1,9 +1,10 @@
package com.seaofnodes.simple.node;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.Parser;
import com.seaofnodes.simple.type.Type;
-import java.util.BitSet;
/**
* A Constant node represents a constant value. At present, the only constants
@@ -24,15 +25,16 @@ public class ConstantNode extends Node {
_con = type;
}
- @Override
- public String label() { return "#"+_con; }
+ @Override protected String repeatName() {
+ return _con==null || _con.toString().length()<=32 ? null : uniqueName();
+ }
@Override
- public String uniqueName() { return "Con_" + _nid; }
+ public String label() { return "Con"; }
- @Override
- StringBuilder _print1(StringBuilder sb, BitSet visited) {
- return _con.print(sb);
+
+ @Override protected ExprPrinter<Node> _print1(ExprPrinter<Node> p) {
+ return p.p(_con);
}
@Override public boolean isMultiTail() { return true; }
diff --git a/chapter12/src/main/java/com/seaofnodes/simple/node/DivFNode.java b/chapter12/src/main/java/com/seaofnodes/simple/node/DivFNode.java
index 6c0c2eb3..a3f4318d 100644
--- a/chapter12/src/main/java/com/seaofnodes/simple/node/DivFNode.java
+++ b/chapter12/src/main/java/com/seaofnodes/simple/node/DivFNode.java
@@ -1,21 +1,16 @@
package com.seaofnodes.simple.node;
+
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeFloat;
-import java.util.BitSet;
public class DivFNode extends Node {
public DivFNode(Node lhs, Node rhs) { super(null, lhs, rhs); }
@Override public String label() { return "DivF"; }
- @Override
- StringBuilder _print1(StringBuilder sb, BitSet visited) {
- in(1)._print0(sb.append("("), visited);
- in(2)._print0(sb.append("/"), visited);
- return sb.append(")");
- }
+ @Override protected String format() { return "(%1/%2)"; }
@Override
public Type compute() {
diff --git a/chapter12/src/main/java/com/seaofnodes/simple/node/DivNode.java b/chapter12/src/main/java/com/seaofnodes/simple/node/DivNode.java
index bc9ff7d9..cd52d117 100644
--- a/chapter12/src/main/java/com/seaofnodes/simple/node/DivNode.java
+++ b/chapter12/src/main/java/com/seaofnodes/simple/node/DivNode.java
@@ -1,21 +1,16 @@
package com.seaofnodes.simple.node;
+
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeInteger;
-import java.util.BitSet;
public class DivNode extends Node {
public DivNode(Node lhs, Node rhs) { super(null, lhs, rhs); }
@Override public String label() { return "Div"; }
- @Override
- StringBuilder _print1(StringBuilder sb, BitSet visited) {
- in(1)._print0(sb.append("("), visited);
- in(2)._print0(sb.append("/"), visited);
- return sb.append(")");
- }
+ @Override protected String format() { return "(%1/%2)"; }
@Override
public Type compute() {
diff --git a/chapter12/src/main/java/com/seaofnodes/simple/node/IfNode.java b/chapter12/src/main/java/com/seaofnodes/simple/node/IfNode.java
index 5457ac6e..70340f7f 100644
--- a/chapter12/src/main/java/com/seaofnodes/simple/node/IfNode.java
+++ b/chapter12/src/main/java/com/seaofnodes/simple/node/IfNode.java
@@ -1,5 +1,6 @@
package com.seaofnodes.simple.node;
+
import com.seaofnodes.simple.IterPeeps;
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeInteger;
@@ -17,11 +18,7 @@ public class IfNode extends CFGNode implements MultiNode {
@Override
public String label() { return "If"; }
- @Override
- StringBuilder _print1(StringBuilder sb, BitSet visited) {
- sb.append("if( ");
- return in(1)._print0(sb, visited).append(" )");
- }
+ @Override protected String format() { return "if( %1 )"; }
@Override public boolean isMultiHead() { return true; }
diff --git a/chapter12/src/main/java/com/seaofnodes/simple/node/LoadNode.java b/chapter12/src/main/java/com/seaofnodes/simple/node/LoadNode.java
index 72af8101..01a82a79 100644
--- a/chapter12/src/main/java/com/seaofnodes/simple/node/LoadNode.java
+++ b/chapter12/src/main/java/com/seaofnodes/simple/node/LoadNode.java
@@ -1,11 +1,12 @@
package com.seaofnodes.simple.node;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.Utils;
import com.seaofnodes.simple.IterPeeps;
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.Field;
-import java.util.BitSet;
/**
* Load represents extracting a value from inside a memory object,
@@ -48,7 +49,7 @@ public class LoadNode extends MemOpNode {
public String label() { return "Load"; }
@Override
- 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/chapter12/src/main/java/com/seaofnodes/simple/node/MemMergeNode.java b/chapter12/src/main/java/com/seaofnodes/simple/node/MemMergeNode.java
index d7fed402..f3d5b01e 100644
--- a/chapter12/src/main/java/com/seaofnodes/simple/node/MemMergeNode.java
+++ b/chapter12/src/main/java/com/seaofnodes/simple/node/MemMergeNode.java
@@ -1,9 +1,10 @@
package com.seaofnodes.simple.node;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.IterPeeps;
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeMem;
-import java.util.BitSet;
/** All memory: a default slice and explicit overrides for individual aliases. */
public class MemMergeNode extends Node {
@@ -28,14 +29,14 @@ public class MemMergeNode extends Node {
@Override public String label() { return "MemMerge"; }
@Override public boolean isMem() { return true; }
@Override public Type compute() { return TypeMem.BOT; }
- @Override StringBuilder _print1(StringBuilder sb, BitSet visited) {
- sb.append("MEM[");
+ @Override protected ExprPrinter<Node> _print1(ExprPrinter<Node> p) {
+ p.p("MEM[");
for( int i=1; i<nIns(); i++ )
if( in(i)!=null ) {
- sb.append(i==1 ? "default:" : i+":");
- in(i)._print0(sb,visited).append(" ");
+ p.p(i==1 ? "default:" : i+":");
+ p.n(in(i)).p(" ");
}
- return sb.append("]");
+ return p.p("]");
}
@Override public Node idealize() {
diff --git a/chapter12/src/main/java/com/seaofnodes/simple/node/MinusFNode.java b/chapter12/src/main/java/com/seaofnodes/simple/node/MinusFNode.java
index 7cacf2c9..1b45c7c5 100644
--- a/chapter12/src/main/java/com/seaofnodes/simple/node/MinusFNode.java
+++ b/chapter12/src/main/java/com/seaofnodes/simple/node/MinusFNode.java
@@ -1,20 +1,16 @@
package com.seaofnodes.simple.node;
+
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeFloat;
-import java.util.BitSet;
public class MinusFNode extends Node {
public MinusFNode(Node in) { super(null, in); }
@Override public String label() { return "MinusF"; }
- @Override
- 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/chapter12/src/main/java/com/seaofnodes/simple/node/MinusNode.java b/chapter12/src/main/java/com/seaofnodes/simple/node/MinusNode.java
index c3be733c..ae450b22 100644
--- a/chapter12/src/main/java/com/seaofnodes/simple/node/MinusNode.java
+++ b/chapter12/src/main/java/com/seaofnodes/simple/node/MinusNode.java
@@ -1,20 +1,16 @@
package com.seaofnodes.simple.node;
+
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeInteger;
-import java.util.BitSet;
public class MinusNode extends Node {
public MinusNode(Node in) { super(null, in); }
@Override public String label() { return "Minus"; }
- @Override
- 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/chapter12/src/main/java/com/seaofnodes/simple/node/MulFNode.java b/chapter12/src/main/java/com/seaofnodes/simple/node/MulFNode.java
index 4b753ba7..6a57f3c5 100644
--- a/chapter12/src/main/java/com/seaofnodes/simple/node/MulFNode.java
+++ b/chapter12/src/main/java/com/seaofnodes/simple/node/MulFNode.java
@@ -1,21 +1,16 @@
package com.seaofnodes.simple.node;
+
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeFloat;
-import java.util.BitSet;
public class MulFNode extends Node {
public MulFNode(Node lhs, Node rhs) { super(null, lhs, rhs); }
@Override public String label() { return "MulF"; }
- @Override
- StringBuilder _print1(StringBuilder sb, BitSet visited) {
- in(1)._print0(sb.append("("), visited);
- in(2)._print0(sb.append("*"), visited);
- return sb.append(")");
- }
+ @Override protected String format() { return "(%1*%2)"; }
@Override
public Type compute() {
diff --git a/chapter12/src/main/java/com/seaofnodes/simple/node/MulNode.java b/chapter12/src/main/java/com/seaofnodes/simple/node/MulNode.java
index 9891cd45..2c13fd0f 100644
--- a/chapter12/src/main/java/com/seaofnodes/simple/node/MulNode.java
+++ b/chapter12/src/main/java/com/seaofnodes/simple/node/MulNode.java
@@ -1,21 +1,16 @@
package com.seaofnodes.simple.node;
+
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeInteger;
-import java.util.BitSet;
public class MulNode extends Node {
public MulNode(Node lhs, Node rhs) { super(null, lhs, rhs); }
@Override public String label() { return "Mul"; }
- @Override
- StringBuilder _print1(StringBuilder sb, BitSet visited) {
- in(1)._print0(sb.append("("), visited);
- in(2)._print0(sb.append("*"), visited);
- return sb.append(")");
- }
+ @Override protected String format() { return "(%1*%2)"; }
@Override
public Type compute() {
diff --git a/chapter12/src/main/java/com/seaofnodes/simple/node/NeverNode.java b/chapter12/src/main/java/com/seaofnodes/simple/node/NeverNode.java
index e77ed653..7e42ccf9 100644
--- a/chapter12/src/main/java/com/seaofnodes/simple/node/NeverNode.java
+++ b/chapter12/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 {
@@ -13,7 +14,7 @@ public class NeverNode extends IfNode {
@Override public String label() { return "Never"; }
- @Override 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/chapter12/src/main/java/com/seaofnodes/simple/node/NewNode.java b/chapter12/src/main/java/com/seaofnodes/simple/node/NewNode.java
index 1c82d5f5..74ba5184 100644
--- a/chapter12/src/main/java/com/seaofnodes/simple/node/NewNode.java
+++ b/chapter12/src/main/java/com/seaofnodes/simple/node/NewNode.java
@@ -1,9 +1,10 @@
package com.seaofnodes.simple.node;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeMemPtr;
-import java.util.BitSet;
public class NewNode extends Node {
@@ -17,10 +18,8 @@ public class NewNode extends Node {
@Override
public String label() { return "new"; }
- @Override
- StringBuilder _print1(StringBuilder sb, BitSet visited) {
- sb.append("new ");
- return sb.append(_ptr._obj.str());
+ @Override protected ExprPrinter<Node> _print1(ExprPrinter<Node> p) {
+ return p.p("new ").p(_ptr._obj.str());
}
diff --git a/chapter12/src/main/java/com/seaofnodes/simple/node/Node.java b/chapter12/src/main/java/com/seaofnodes/simple/node/Node.java
index ff8415c5..e3503a7c 100644
--- a/chapter12/src/main/java/com/seaofnodes/simple/node/Node.java
+++ b/chapter12/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.Parser;
import com.seaofnodes.simple.IRPrinter;
@@ -16,14 +18,7 @@ import java.util.function.Function;
* The Node class provides common functionality used by all subtypes.
* Subtypes of Node specialize by overriding methods.
*/
-public abstract class Node implements OutNode, 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 OutNode, Cloneable {
/**
* Inputs to the node. These are use-def references to Nodes.
@@ -45,14 +40,12 @@ public abstract class Node implements OutNode, Cloneable {
*/
public ArrayList<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;
-
/**
* A private Global Static mutable counter, for unique node id generation.
* To make the compiler multithreaded, this field will have to move into a TLS.
@@ -62,7 +55,7 @@ public abstract class Node implements OutNode, Cloneable {
public static int UID() { return UNIQUE_ID; }
protected Node(Node... inputs) {
- _nid = UNIQUE_ID++; // allocate unique dense ID
+ super(UNIQUE_ID++); // allocate unique dense ID
_inputs = new ArrayList<>();
Collections.addAll(_inputs,inputs);
_outputs = new ArrayList<>();
@@ -74,42 +67,6 @@ public abstract class Node implements OutNode, Cloneable {
// Easy reading label for debugger, e.g. "Add" or "Region" or "EQ"
public abstract String label();
- // Unique label for debugging, e.g. "Add12" or "Region30" or "EQ99"
- public String uniqueName() {
- return label() + _nid;
- }
-
- // ------------------------------------------------------------------------
-
- // 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. This version will fail on cycles, which we will
- // correct later when we can parse programs with loops. We print with a
- // 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.
- 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 StringBuilder _print1(StringBuilder sb, BitSet visited);
-
public String p(int depth) { return IRPrinter.prettyPrint(this,depth); }
public boolean isMultiHead() { return false; }
@@ -118,6 +75,8 @@ public abstract class Node implements OutNode, 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
@@ -258,7 +217,6 @@ public abstract class Node implements OutNode, Cloneable {
// Test "keep" status
public boolean iskeep() { return Utils.find(_outputs,null) != -1; }
-
// Replace self with nnn in the graph, making 'this' go dead
public void subsume( Node nnn ) {
assert nnn!=this;
@@ -389,7 +347,6 @@ public abstract class Node implements OutNode, Cloneable {
return old;
}
-
/**
* This function rewrites the current Node into a more "idealized" form.
* This is the bulk of our peephole rewrite rules, and we use this to
@@ -437,7 +394,6 @@ public abstract class Node implements OutNode, 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
@@ -481,7 +437,6 @@ public abstract class Node implements OutNode, Cloneable {
_deps.clear();
}
-
// Global Value Numbering. Hash over opcode and inputs; hits in this table
// are structurally equal.
public static final HashMap<Node,Node> GVN = new HashMap<>();
@@ -503,7 +458,6 @@ public abstract class Node implements OutNode, Cloneable {
// and can assume "this!=n" and has the same Java class.
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
@@ -519,7 +473,6 @@ public abstract class Node implements OutNode, Cloneable {
_hash=0; // Out of table now
}
-
// Hash of opcode and inputs
@Override public final int hashCode() {
if( _hash != 0 ) return _hash;
@@ -537,7 +490,6 @@ public abstract class Node implements OutNode, Cloneable {
//
/** Is this Node control-flow-graph related */
- public boolean isCFG() { return false; }
/** Is this Node Memory related */
public boolean isMem() { return false; }
@@ -545,7 +497,6 @@ public abstract class Node implements OutNode, Cloneable {
/** Return block start from a isCFG() */
public Node getBlockStart() { return null; }
-
// Semantic change to the graph (so NOT a peephole), used by the Parser.
// If any input is a float, flip to a float-flavored opcode and widen any
// non-float input.
@@ -566,7 +517,6 @@ public abstract class Node implements OutNode, Cloneable {
}
Node copyF() { return null; }
-
// ------------------------------------------------------------------------
// Peephole utilities
@@ -595,7 +545,6 @@ public abstract class Node implements OutNode, 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.
@@ -628,7 +577,6 @@ public abstract class Node implements OutNode, Cloneable {
ITER_CNT = ITER_NOP_CNT = 0;
}
-
// Utility to walk the entire graph applying a function; return the first
// not-null result.
private static final BitSet WVISIT = new BitSet();
diff --git a/chapter12/src/main/java/com/seaofnodes/simple/node/NotNode.java b/chapter12/src/main/java/com/seaofnodes/simple/node/NotNode.java
index bb7e9265..4539f982 100644
--- a/chapter12/src/main/java/com/seaofnodes/simple/node/NotNode.java
+++ b/chapter12/src/main/java/com/seaofnodes/simple/node/NotNode.java
@@ -1,19 +1,15 @@
package com.seaofnodes.simple.node;
+
import com.seaofnodes.simple.Utils;
import com.seaofnodes.simple.type.*;
-import java.util.BitSet;
public class NotNode extends Node {
public NotNode(Node in) { super(null, in); }
@Override public String label() { return "Not"; }
- @Override
- 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/chapter12/src/main/java/com/seaofnodes/simple/node/PhiNode.java b/chapter12/src/main/java/com/seaofnodes/simple/node/PhiNode.java
index 277c16d1..8dfa04cf 100644
--- a/chapter12/src/main/java/com/seaofnodes/simple/node/PhiNode.java
+++ b/chapter12/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.type.Type;
import com.seaofnodes.simple.type.TypeMem;
import com.seaofnodes.simple.Utils;
-import java.util.BitSet;
public class PhiNode extends Node {
@@ -23,18 +24,12 @@ public class PhiNode extends Node {
@Override public String label() { return "Phi_"+_label; }
@Override
- 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/chapter12/src/main/java/com/seaofnodes/simple/node/ProjNode.java b/chapter12/src/main/java/com/seaofnodes/simple/node/ProjNode.java
index 93239a61..e82c69b3 100644
--- a/chapter12/src/main/java/com/seaofnodes/simple/node/ProjNode.java
+++ b/chapter12/src/main/java/com/seaofnodes/simple/node/ProjNode.java
@@ -1,10 +1,11 @@
package com.seaofnodes.simple.node;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeMem;
import com.seaofnodes.simple.type.TypeTuple;
-import java.util.BitSet;
public class ProjNode extends Node {
@@ -24,7 +25,7 @@ public class ProjNode extends Node {
public String label() { return _label; }
@Override
- StringBuilder _print1(StringBuilder sb, BitSet visited) { return sb.append(_label); }
+ protected ExprPrinter<Node> _print1(ExprPrinter<Node> p) { return p.p(_label); }
@Override public boolean isMultiTail() { return in(0).isMultiHead(); }
@Override public boolean isMem() { return _type instanceof TypeMem; }
diff --git a/chapter12/src/main/java/com/seaofnodes/simple/node/RegionNode.java b/chapter12/src/main/java/com/seaofnodes/simple/node/RegionNode.java
index d7e934d7..cdfd10ad 100644
--- a/chapter12/src/main/java/com/seaofnodes/simple/node/RegionNode.java
+++ b/chapter12/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.IterPeeps;
import com.seaofnodes.simple.Parser;
import com.seaofnodes.simple.Utils;
@@ -16,9 +18,8 @@ public class RegionNode extends CFGNode {
@Override
public String label() { return "Region"; }
- @Override
- StringBuilder _print1(StringBuilder sb, BitSet visited) {
- return sb.append(label()).append(_nid);
+ @Override protected ExprPrinter<Node> _print1(ExprPrinter<Node> p) {
+ return p.p(label()).p(_nid);
}
@Override public boolean isMultiHead() { return true; }
diff --git a/chapter12/src/main/java/com/seaofnodes/simple/node/ReturnNode.java b/chapter12/src/main/java/com/seaofnodes/simple/node/ReturnNode.java
index 725c704f..161cc7d6 100644
--- a/chapter12/src/main/java/com/seaofnodes/simple/node/ReturnNode.java
+++ b/chapter12/src/main/java/com/seaofnodes/simple/node/ReturnNode.java
@@ -1,8 +1,9 @@
package com.seaofnodes.simple.node;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.type.*;
-import java.util.BitSet;
/** Keeps all preceding memory effects and the return value alive: {ctrl, $mem, value}. */
public class ReturnNode extends CFGNode {
@@ -20,10 +21,10 @@ public class ReturnNode extends CFGNode {
public String label() { return "Return"; }
@Override
- StringBuilder _print1(StringBuilder sb, BitSet visited) {
- sb.append("return ");
- expr()._print0(sb, visited);
- return sb.append(";");
+ protected ExprPrinter<Node> _print1(ExprPrinter<Node> p) {
+ p.p("return ");
+ p.n(expr());
+ return p.p(";");
}
@Override
diff --git a/chapter12/src/main/java/com/seaofnodes/simple/node/ScopeNode.java b/chapter12/src/main/java/com/seaofnodes/simple/node/ScopeNode.java
index b931e862..b408eb2f 100644
--- a/chapter12/src/main/java/com/seaofnodes/simple/node/ScopeNode.java
+++ b/chapter12/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.IterPeeps;
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.Utils;
@@ -42,20 +44,19 @@ public class ScopeNode extends Node {
@Override public String label() { return "Scope"; }
@Override
- StringBuilder _print1(StringBuilder sb, BitSet visited) {
- sb.append("Scope[ ");
+ protected ExprPrinter<Node> _print1(ExprPrinter<Node> p) {
+ p.p("Scope[ ");
String[] names = reverseNames();
for( int j=0; j<nIns(); j++ ) {
- sb.append(names[j]).append(":");
+ p.p(names[j]).p(":");
Node n = in(j);
while( n instanceof ScopeNode loop ) {
- sb.append("Lazy_");
+ p.p("Lazy_");
n = loop.in(j);
}
- n._print0(sb, visited).append(" ");
+ p.n(n).p(" ");
}
- sb.setLength(sb.length()-1);
- return sb.append("]");
+ return p.unchar(' ').p("]");
}
/**
diff --git a/chapter12/src/main/java/com/seaofnodes/simple/node/StartNode.java b/chapter12/src/main/java/com/seaofnodes/simple/node/StartNode.java
index 2cedf0f6..a5d4923f 100644
--- a/chapter12/src/main/java/com/seaofnodes/simple/node/StartNode.java
+++ b/chapter12/src/main/java/com/seaofnodes/simple/node/StartNode.java
@@ -1,5 +1,7 @@
package com.seaofnodes.simple.node;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.type.*;
import java.util.BitSet;
import java.util.HashSet;
@@ -17,9 +19,8 @@ public class StartNode extends CFGNode implements MultiNode {
@Override
public String label() { return "Start"; }
- @Override
- 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 isMultiHead() { return true; }
diff --git a/chapter12/src/main/java/com/seaofnodes/simple/node/StopNode.java b/chapter12/src/main/java/com/seaofnodes/simple/node/StopNode.java
index 3ef2e4a6..b5d2d716 100644
--- a/chapter12/src/main/java/com/seaofnodes/simple/node/StopNode.java
+++ b/chapter12/src/main/java/com/seaofnodes/simple/node/StopNode.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.Type;
import com.seaofnodes.simple.IterPeeps;
-import java.util.BitSet;
public class StopNode extends CFGNode {
@@ -22,12 +23,12 @@ public class StopNode extends CFGNode {
}
@Override
- StringBuilder _print1(StringBuilder sb, BitSet visited) {
- if( ret()!=null ) return ret()._print0(sb, visited);
- sb.append("Stop[ ");
+ protected ExprPrinter<Node> _print1(ExprPrinter<Node> p) {
+ if( ret()!=null ) return p.n(ret());
+ p.p("Stop[ ");
for( Node ret : _inputs )
- ret._print0(sb, visited).append(" ");
- return sb.append("]");
+ p.n(ret).p(" ");
+ return p.p("]");
}
@Override public boolean blockHead() { return true; }
diff --git a/chapter12/src/main/java/com/seaofnodes/simple/node/StoreNode.java b/chapter12/src/main/java/com/seaofnodes/simple/node/StoreNode.java
index b816762b..f61afe78 100644
--- a/chapter12/src/main/java/com/seaofnodes/simple/node/StoreNode.java
+++ b/chapter12/src/main/java/com/seaofnodes/simple/node/StoreNode.java
@@ -1,10 +1,11 @@
package com.seaofnodes.simple.node;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.Utils;
import com.seaofnodes.simple.IterPeeps;
import com.seaofnodes.simple.type.*;
-import java.util.BitSet;
/**
* Store represents setting a value to a memory based object, in chapter 10
@@ -29,8 +30,8 @@ public class StoreNode extends MemOpNode {
public Node val() { return in(3); }
@Override
- 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/chapter12/src/main/java/com/seaofnodes/simple/node/SubFNode.java b/chapter12/src/main/java/com/seaofnodes/simple/node/SubFNode.java
index 27bbda8d..2d218a03 100644
--- a/chapter12/src/main/java/com/seaofnodes/simple/node/SubFNode.java
+++ b/chapter12/src/main/java/com/seaofnodes/simple/node/SubFNode.java
@@ -1,21 +1,16 @@
package com.seaofnodes.simple.node;
+
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeFloat;
-import java.util.BitSet;
public class SubFNode extends Node {
public SubFNode(Node lhs, Node rhs) { super(null, lhs, rhs); }
@Override public String label() { return "SubF"; }
- @Override
- StringBuilder _print1(StringBuilder sb, BitSet visited) {
- in(1)._print0(sb.append("("), visited);
- in(2)._print0(sb.append("-"), visited);
- return sb.append(")");
- }
+ @Override protected String format() { return "(%1-%2)"; }
@Override
public Type compute() {
diff --git a/chapter12/src/main/java/com/seaofnodes/simple/node/SubNode.java b/chapter12/src/main/java/com/seaofnodes/simple/node/SubNode.java
index 4ae302f0..f36f2af5 100644
--- a/chapter12/src/main/java/com/seaofnodes/simple/node/SubNode.java
+++ b/chapter12/src/main/java/com/seaofnodes/simple/node/SubNode.java
@@ -1,22 +1,17 @@
package com.seaofnodes.simple.node;
+
import com.seaofnodes.simple.Parser;
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeInteger;
-import java.util.BitSet;
public class SubNode extends Node {
public SubNode(Node lhs, Node rhs) { super(null, lhs, rhs); }
@Override public String label() { return "Sub"; }
- @Override
- StringBuilder _print1(StringBuilder sb, BitSet visited) {
- in(1)._print0(sb.append("("), visited);
- in(2)._print0(sb.append("-"), visited);
- return sb.append(")");
- }
+ @Override protected String format() { return "(%1-%2)"; }
@Override
public Type compute() {
diff --git a/chapter12/src/main/java/com/seaofnodes/simple/node/ToFloatNode.java b/chapter12/src/main/java/com/seaofnodes/simple/node/ToFloatNode.java
index fde483d6..26cf50e1 100644
--- a/chapter12/src/main/java/com/seaofnodes/simple/node/ToFloatNode.java
+++ b/chapter12/src/main/java/com/seaofnodes/simple/node/ToFloatNode.java
@@ -1,20 +1,17 @@
package com.seaofnodes.simple.node;
+
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeFloat;
import com.seaofnodes.simple.type.TypeInteger;
-import java.util.BitSet;
public class ToFloatNode extends Node {
public ToFloatNode(Node lhs) { super(null, lhs); }
@Override public String label() { return "ToFloat"; }
- @Override
- 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/chapter12/src/main/java/com/seaofnodes/simple/node/XCtrlNode.java b/chapter12/src/main/java/com/seaofnodes/simple/node/XCtrlNode.java
index 83779dd2..056dfba1 100644
--- a/chapter12/src/main/java/com/seaofnodes/simple/node/XCtrlNode.java
+++ b/chapter12/src/main/java/com/seaofnodes/simple/node/XCtrlNode.java
@@ -1,13 +1,14 @@
package com.seaofnodes.simple.node;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.Parser;
import com.seaofnodes.simple.type.Type;
-import java.util.BitSet;
public class XCtrlNode extends CFGNode {
public XCtrlNode( ) { super(Parser.START); }
@Override public String label() { return "Xctrl"; }
- @Override StringBuilder _print1(StringBuilder sb, BitSet visited) { return sb.append("Xctrl"); }
+ @Override protected ExprPrinter<Node> _print1(ExprPrinter<Node> p) { return p.p("Xctrl"); }
@Override public Type compute() { return Type.XCONTROL; }
@Override public Node idealize() { return null; }
}
diff --git a/chapter12/src/main/java/com/seaofnodes/simple/print/SimpleGraphAdapter.java b/chapter12/src/main/java/com/seaofnodes/simple/print/SimpleGraphAdapter.java
index 8af87a2b..e65963db 100644
--- a/chapter12/src/main/java/com/seaofnodes/simple/print/SimpleGraphAdapter.java
+++ b/chapter12/src/main/java/com/seaofnodes/simple/print/SimpleGraphAdapter.java
@@ -1,43 +1,20 @@
package com.seaofnodes.simple.print;
import com.seaofnodes.graph.GraphAdapter;
-import com.seaofnodes.graph.GraphSnapshot;
import com.seaofnodes.graph.GraphSnapshot.*;
import com.seaofnodes.simple.node.*;
import com.seaofnodes.simple.node.Node;
import com.seaofnodes.simple.type.TypeMem;
-import java.util.ArrayList;
/** Chapter 12's view of the IR; browser, transport and layout are shared. */
public class SimpleGraphAdapter extends GraphAdapter<Node> {
- @Override protected boolean dead(Node n) { return n.isDead(); }
- @Override protected int id(Node n) { return n._nid; }
- @Override protected int nIns(Node n) { return n.nIns(); }
- @Override protected Node in(Node n, int idx) { return n.in(idx); }
- @Override protected int nOuts(Node n) { return n.nOuts(); }
- @Override protected Node out(Node n, int idx) { return n.out(idx); }
- @Override protected int nDeps(Node n) { return n.nDeps(); }
- @Override protected Node dep(Node n, int idx) { return n.dep(idx); }
- private ArrayList<Edge> edges(Node n) {
- var edges = new ArrayList<Edge>();
- String[] names = n instanceof ScopeNode scope && n.nIns() != 0 ? scope.reverseNames() : null;
- for( int i = 0; i < n.nIns(); i++ ) {
- String name = names == null || i >= names.length ? null : names[i];
- edges.add(new Edge(i, ref(n.in(i)), role(n, i), name));
- }
- return edges;
+ @Override protected String[] edgeNames(Node n) {
+ return n instanceof ScopeNode scope && n.nIns()!=0 ? scope.reverseNames() : null;
}
+ @Override protected int projectionIndex(Node n) { return n instanceof ProjNode p ? p._idx : n instanceof CProjNode p ? p._idx : -1; }
- @Override protected GraphSnapshot.Node desc(Node n) {
- Projection proj = n instanceof ProjNode p ? new Projection(ref(n.in(0)), p._idx)
- : n instanceof CProjNode p ? new Projection(ref(n.in(0)), p._idx) : null;
- String label = n.label();
- return new GraphSnapshot.Node(n._nid, label == null ? n.getClass().getSimpleName() : label,
- n._type == null ? null : n._type.toString(), kind(n), edges(n), proj);
- }
-
- 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 StartNode ) return Kind.CTRL;
@@ -47,7 +24,7 @@ public class SimpleGraphAdapter extends GraphAdapter<Node> {
return n.isCFG() ? Kind.CTRL : isMem(n) ? Kind.MEM : Kind.DATA;
}
- private Role role(Node n, int i) {
+ @Override protected Role role(Node n, int i) {
if( n instanceof ScopeNode || n instanceof ConstantNode || n instanceof XCtrlNode ) return Role.ASSOC;
if( n instanceof PhiNode ) return i == 0 ? Role.ASSOC : isMem(n) ? Role.MEM : Role.DATA;
if( n instanceof ProjNode || n instanceof CProjNode ) return n.isCFG() ? Role.CTRL : isMem(n) ? Role.MEM : Role.DATA;
diff --git a/chapter13/Makefile b/chapter13/Makefile
index 77df7182..3f1e53ff 100644
--- a/chapter13/Makefile
+++ b/chapter13/Makefile
@@ -37,6 +37,7 @@ main_javas := $(wildcard $(SRC)/$(SIMPLE)/*java $(SRC)/$(SIMPLE)/*/*java)
test_javas := $(wildcard $(TST)/$(SIMPLE)/*java $(TST)/$(SIMPLE)/*/*java)
main_classes := $(patsubst $(SRC)/%java,$(CLZDIR)/main/%class,$(main_javas))
include $(firstword $(wildcard ../graph/graph.mk graph/graph.mk))
+include $(firstword $(wildcard ../print/print.mk print/print.mk))
test_classes := $(patsubst $(TST)/%java,$(CLZDIR)/test/%class,$(test_javas))
test_cp := $(patsubst $(TST)/$(SIMPLE)/%.java,com.seaofnodes.simple.%,$(wildcard $(TST)/$(SIMPLE)/*Test.java))
classes = $(main_classes) $(test_classes)
@@ -54,7 +55,7 @@ endif
default: $(default_targets)
# Compile just the out-of-date files
-$(main_classes): build/classes/main/%class: $(SRC)/%java $(graph_javas)
+$(main_classes): build/classes/main/%class: $(SRC)/%java $(graph_javas) $(print_javas)
@echo "compiling " $@ " because " $?
@[ -d $(CLZDIR)/main ] || mkdir -p $(CLZDIR)/main
@javac $(JAVAC_ARGS) -cp "$(CLZDIR)/main$(SEP)$(jars)" -sourcepath $(SRC) -d $(CLZDIR)/main $(main_javas)
diff --git a/chapter13/pom.xml b/chapter13/pom.xml
index 138c3d2e..f8369496 100644
--- a/chapter13/pom.xml
+++ b/chapter13/pom.xml
@@ -13,5 +13,6 @@
<name>Chapter 13</name>
<properties>
<simple.graph.directory>${project.basedir}/../graph</simple.graph.directory>
+ <simple.print.directory>${project.basedir}/../print</simple.print.directory>
</properties>
</project>
diff --git a/chapter13/src/main/java/com/seaofnodes/simple/IRPrinter.java b/chapter13/src/main/java/com/seaofnodes/simple/IRPrinter.java
index 3410ab64..7e93e9da 100644
--- a/chapter13/src/main/java/com/seaofnodes/simple/IRPrinter.java
+++ b/chapter13/src/main/java/com/seaofnodes/simple/IRPrinter.java
@@ -1,288 +1,33 @@
package com.seaofnodes.simple;
+import com.seaofnodes.print.IRAdapter;
import com.seaofnodes.simple.node.*;
-import java.lang.StringBuilder;
-import java.util.ArrayList;
-import java.util.BitSet;
-import java.util.HashMap;
-import java.util.IdentityHashMap;
-
-public 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 void _printLine( Node n, StringBuilder sb ) {
- sb.append("%4d %-7.7s ".formatted(n._nid,n.label()));
- if( n.isDead() ) {
- sb.append("DEAD\n");
- return;
- }
- for( Node def : n._inputs )
- sb.append(def==null ? "____ " : "%4d ".formatted(def._nid));
- for( int i = n._inputs.size(); i<4; i++ )
- sb.append(" ");
- sb.append(" [[ ");
- for( Node use : n._outputs )
- sb.append(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.append(" ");
- sb.append(" ]] ");
- if( n._type!= null ) sb.append(n._type.str());
- sb.append("\n");
- }
-
- private static StringBuilder nodeId(StringBuilder sb, Node n) {
- sb.append("%%%d".formatted(n._nid));
- if (n instanceof ProjNode proj) {
- sb.append(".").append(proj._idx);
- }
- return sb;
- }
-
- // Print a node on 1 line, format is inspired by LLVM
- // %id: TYPE = NODE(inputs ....)
- // Nodes as referred to as %id
- public static void _printLineLlvmFormat( Node n, StringBuilder sb ) {
- nodeId(sb, n).append(": ");
- if( n.isDead() ) {
- sb.append("DEAD\n");
- return;
- }
- if( n._type!= null ) n._type.typeName(sb);
- sb.append(" = ").append( n.label() ).append( "(" );
- for( int i = 0; i < n._inputs.size(); i++ ) {
- Node def = n.in(i);
- if (i > 0)
- sb.append(", ");
- if (def == null) sb.append("_");
- else nodeId(sb, def);
- }
- sb.append(")").append("\n");
- }
-
- public static void printLine( Node n, StringBuilder sb, boolean llvmFormat ) {
- if (llvmFormat) _printLineLlvmFormat( n, sb );
- else _printLine ( n, sb );
- }
-
- public static String prettyPrint(Node node, int depth) {
- return Parser.SCHEDULED
- ? prettyPrintScheduled( node, depth, false )
- : prettyPrint( node, depth, false );
- }
-
- // Another bulk pretty-printer. Makes more effort at basic-block grouping.
- public static String prettyPrint( Node node, int depth, boolean llvmFormat ) {
- // First, a Breadth First Search at a fixed depth.
- BFS bfs = new BFS(node,depth);
- // Convert just that set to a post-order
- ArrayList<Node> rpos = new ArrayList<>();
- BitSet visit = new BitSet();
- for( int i=bfs._lim; i< bfs._bfs.size(); i++ )
- postOrd( bfs._bfs.get(i), rpos, visit, bfs._bs);
- // Reverse the post-order walk
- StringBuilder sb = new StringBuilder();
- boolean gap=false;
- for( int i=rpos.size()-1; i>=0; i-- ) {
- Node n = rpos.get(i);
- if( n.isCFG() || n.isMultiHead() ) {
- if( !gap ) sb.append("\n"); // Blank before multihead
- printLine( n, sb, llvmFormat ); // Print head
- while( --i >= 0 ) {
- Node t = rpos.get(i);
- if( !t.isMultiTail() ) { i++; break; }
- printLine( t, sb, llvmFormat );
- }
- sb.append("\n"); // Blank after multitail
- gap = true;
- } else {
- printLine( n, sb, llvmFormat );
- gap = false;
- }
- }
- return sb.toString();
- }
-
- private static void postOrd(Node n, ArrayList<Node> rpos, BitSet visit, BitSet bfs) {
- if( !bfs.get(n._nid) )
- return; // Not in the BFS visit
- if( visit.get(n._nid) ) return; // Already post-order walked
- visit.set(n._nid);
- // First walk the CFG, then everything
- if( n.isCFG() ) {
- for( Node use : n._outputs )
- if( use!=null && use.isCFG() && use.nOuts()>=1 && !(use._outputs.get(0) instanceof LoopNode) )
- postOrd(use, rpos,visit,bfs);
- for( Node use : n._outputs )
- if( use!=null && use.isCFG() )
- postOrd(use,rpos,visit,bfs);
- }
- for( Node use : n._outputs )
- if( use != null )
- postOrd(use, rpos,visit,bfs);
- // Post-order
- rpos.add(n);
- }
-
- // Breadth-first search, broken out in a class to keep in more independent.
- // Maintains a root-set of Nodes at the limit (or past by 1 if MultiHead).
- public static class BFS {
- // A breadth first search, plus MultiHeads for any MultiTails
- public final ArrayList<Node> _bfs;
- public final BitSet _bs; // Visited members by node id
- public final int _depth; // Depth limit
- public final int _lim; // From here to _bfs._len can be roots for a reverse search
- public BFS( Node base, int d ) {
- _depth = d;
- _bfs = new ArrayList<>();
- _bs = new BitSet();
-
- add(base); // Prime the pump
- int idx=0, lim=1; // Limit is where depth counter changes
- while( idx < _bfs.size() ) { // Ran out of nodes below depth
- Node n = _bfs.get(idx++);
- for( Node def : n._inputs )
- if( def!=null && !_bs.get(def._nid) )
- add(def);
- if( idx==lim ) { // Depth counter changes at limit
- if( --d < 0 )
- break; // Ran out of depth
- lim = _bfs.size(); // New depth limit
- }
- }
- // Toss things past the limit except multi-heads
- while( idx < _bfs.size() ) {
- Node n = _bfs.get(idx);
- if( n.isMultiHead() ) idx++;
- else del(idx);
- }
- // Root set is any node with no inputs in the visited set
- lim = _bfs.size();
- for( int i=_bfs.size()-1; i>=0; i-- )
- if( !any_visited(_bfs.get(i)) )
- swap( i,--lim);
- _lim = lim;
- }
- void swap( int x, int y ) {
- if( x==y ) return;
- Node tx = _bfs.get(x);
- Node ty = _bfs.get(y);
- _bfs.set(x,ty);
- _bfs.set(y,tx);
- }
- void add(Node n) {
- _bfs.add(n);
- _bs.set(n._nid);
- }
- void del(int idx) {
- Node n = Utils.del(_bfs, idx);
- _bs.clear(n._nid);
- }
- boolean any_visited( Node n ) {
- for( Node def : n._inputs )
- if( def!=null && _bs.get(def._nid) )
- return true;
- return false;
- }
- }
-
- // Diagnostic block ordering from raw control edges. Do not call idepth():
- // it fills compiler caches (and can walk lazy dominator accessors).
- private static int _idepth(CFGNode cfg, HashMap<Integer,Integer> depths) {
- if( cfg == null || cfg instanceof StartNode ) return 0;
- Integer old = depths.get(cfg._nid);
- if( old != null ) return old;
- depths.put(cfg._nid,0); // Break cycles in partially constructed graphs.
- int d = 0;
- if( cfg instanceof LoopNode ) {
- d = _idepth((CFGNode)cfg.in(1),depths)+1;
- } else if( cfg instanceof RegionNode || cfg instanceof StopNode ) {
- for( Node n : cfg._inputs )
- if( n instanceof CFGNode pred ) d = Math.max(d,_idepth(pred,depths)+1);
- } else if( cfg.in(0) instanceof CFGNode pred ) {
- d = _idepth(pred,depths)+1;
- }
- depths.put(cfg._nid,d);
- return d;
- }
-
- // Bulk pretty printer, knowing scheduling information is available
- public static String prettyPrintScheduled( Node node, int depth, boolean llvmFormat ) {
- // Backwards DFS walk to depth.
- IdentityHashMap<Node,Integer> ds = new IdentityHashMap<>();
- _walk(ds,node,depth);
- // Print by block with least diagnostic depth
- HashMap<Integer,Integer> depths = new HashMap<>();
- StringBuilder sb = new StringBuilder();
- ArrayList<Node> bns = new ArrayList<>();
- while( !ds.isEmpty() ) {
- CFGNode blk = null;
- for( Node n : ds.keySet() ) {
- CFGNode cfg = n instanceof CFGNode cfg0 && cfg0.blockHead() ? cfg0 : (CFGNode)n.in(0);
- if( blk==null || _idepth(cfg,depths) < _idepth(blk,depths) )
- blk = cfg;
- }
- ds.remove(blk);
-
- // Print block header
- sb.append("%-13.13s".formatted(label(blk)+":"));
- sb.append( " ".repeat(4) ).append(" [[ ");
- if( blk instanceof RegionNode || blk instanceof StopNode )
- for( int i=(blk instanceof StopNode ? 0 : 1); i<blk.nIns(); i++ )
- label(sb,blk.cfg(i));
- else if( !(blk instanceof StartNode) )
- label(sb,blk.cfg(0));
- sb.append(" ]] \n");
-
- // Collect block contents that are in the depth limit
- bns.clear();
- int xd = Integer.MAX_VALUE;
- for( Node use : blk._outputs ) {
- Integer i = ds.get(use);
- if( i!=null && !(use instanceof CFGNode cfg && cfg.blockHead()) ) {
- bns.add(use);
- xd = Math.min(xd,i);
- }
- }
- // Print Phis up front, if any
- for( int i=0; i<bns.size(); i++ )
- if( bns.get(i) instanceof PhiNode phi )
- printLine( phi, sb, llvmFormat,bns,i--,ds);
-
- // Print block contents in depth order, bumping depth until whole block printed
- for( ; !bns.isEmpty(); xd++ )
- for( int i=0; i<bns.size(); i++ )
- if( ds.get(bns.get(i))==xd )
- printLine( bns.get(i), sb, llvmFormat, bns, i--, ds );
- sb.append("\n");
- }
- return sb.toString();
- }
-
- private static void _walk( IdentityHashMap<Node,Integer> ds, Node node, int d ) {
- Integer nd = ds.get(node);
- if( nd!=null && d <= nd ) return; // Been there, done that
- ds.put(node,d);
- if( d == 0 ) return; // Depth cutoff
- for( Node def : node._inputs )
- if( def != null )
- _walk(ds,def,d-1);
- }
-
- static String label( CFGNode blk ) {
- if( blk instanceof StartNode ) return "START";
- return (blk instanceof LoopNode ? "LOOP" : "L")+blk._nid;
- }
- static void label( StringBuilder sb, CFGNode blk ) {
- if( !blk.blockHead() ) blk = blk.cfg(0);
- sb.append( "%-9.9s ".formatted( label( blk ) ) );
- }
- static void printLine( Node n, StringBuilder sb, boolean llvmFormat, ArrayList<Node> bns, int i, IdentityHashMap<Node,Integer> ds ) {
- printLine( n, sb, llvmFormat );
- Utils.del(bns,i);
- ds.remove(n);
- }
+/** 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 String type(Node n) { return n._type==null ? "" : n._type.str(); }
+ @Override public String inputMark(Node n, Node def) { return n instanceof MemMergeNode && def instanceof MemMergeNode ? "^" : " "; }
+ @Override public Kind kind(Node n) {
+ if( n instanceof StartNode ) return Kind.START;
+ if( n instanceof StopNode ) return Kind.STOP;
+ if( n instanceof LoopNode ) return Kind.LOOP;
+ if( n instanceof RegionNode ) return Kind.REGION;
+ if( n instanceof PhiNode ) return Kind.PHI;
+ 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;
+ }
+
+ public static String prettyPrint(Node n, int depth) { return PRINT.prettyPrint(n,depth); }
}
diff --git a/chapter13/src/main/java/com/seaofnodes/simple/node/AddFNode.java b/chapter13/src/main/java/com/seaofnodes/simple/node/AddFNode.java
index 5d0a473a..fd713156 100644
--- a/chapter13/src/main/java/com/seaofnodes/simple/node/AddFNode.java
+++ b/chapter13/src/main/java/com/seaofnodes/simple/node/AddFNode.java
@@ -1,21 +1,16 @@
package com.seaofnodes.simple.node;
+
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeFloat;
-import java.util.BitSet;
public class AddFNode extends Node {
public AddFNode(Node lhs, Node rhs) { super(null, lhs, rhs); }
@Override public String label() { return "AddF"; }
- @Override
- StringBuilder _print1(StringBuilder sb, BitSet visited) {
- in(1)._print0(sb.append("("), visited);
- in(2)._print0(sb.append("+"), visited);
- return sb.append(")");
- }
+ @Override protected String format() { return "(%1+%2)"; }
@Override
public Type compute() {
diff --git a/chapter13/src/main/java/com/seaofnodes/simple/node/AddNode.java b/chapter13/src/main/java/com/seaofnodes/simple/node/AddNode.java
index eb1bd073..94fee330 100644
--- a/chapter13/src/main/java/com/seaofnodes/simple/node/AddNode.java
+++ b/chapter13/src/main/java/com/seaofnodes/simple/node/AddNode.java
@@ -1,20 +1,15 @@
package com.seaofnodes.simple.node;
+
import com.seaofnodes.simple.type.*;
-import java.util.BitSet;
public class AddNode extends Node {
public AddNode(Node lhs, Node rhs) { super(null, lhs, rhs); }
@Override public String label() { return "Add"; }
- @Override
- StringBuilder _print1(StringBuilder sb, BitSet visited) {
- in(1)._print0(sb.append("("), visited);
- in(2)._print0(sb.append("+"), visited);
- return sb.append(")");
- }
+ @Override protected String format() { return "(%1+%2)"; }
@Override
diff --git a/chapter13/src/main/java/com/seaofnodes/simple/node/BoolNode.java b/chapter13/src/main/java/com/seaofnodes/simple/node/BoolNode.java
index 2055ea6f..e515a5f1 100644
--- a/chapter13/src/main/java/com/seaofnodes/simple/node/BoolNode.java
+++ b/chapter13/src/main/java/com/seaofnodes/simple/node/BoolNode.java
@@ -1,5 +1,7 @@
package com.seaofnodes.simple.node;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.Parser;
import com.seaofnodes.simple.Utils;
import com.seaofnodes.simple.type.Type;
@@ -7,7 +9,6 @@ import com.seaofnodes.simple.type.TypeInteger;
import com.seaofnodes.simple.type.TypeFloat;
import com.seaofnodes.simple.type.TypeMemPtr;
-import java.util.BitSet;
abstract public class BoolNode extends Node {
@@ -20,11 +21,8 @@ abstract public class BoolNode extends Node {
@Override
public String label() { return getClass().getSimpleName(); }
- @Override
- 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/chapter13/src/main/java/com/seaofnodes/simple/node/CProjNode.java b/chapter13/src/main/java/com/seaofnodes/simple/node/CProjNode.java
index fb0ff879..ff5d1a76 100644
--- a/chapter13/src/main/java/com/seaofnodes/simple/node/CProjNode.java
+++ b/chapter13/src/main/java/com/seaofnodes/simple/node/CProjNode.java
@@ -1,10 +1,11 @@
package com.seaofnodes.simple.node;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.Parser;
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeMem;
import com.seaofnodes.simple.type.TypeTuple;
-import java.util.BitSet;
public class CProjNode extends CFGNode {
@@ -22,7 +23,7 @@ public class CProjNode extends CFGNode {
@Override public String label() { return _label; }
- @Override 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 isMultiTail() { return in(0).isMultiHead(); }
@Override public boolean blockHead() { return true; }
diff --git a/chapter13/src/main/java/com/seaofnodes/simple/node/CastNode.java b/chapter13/src/main/java/com/seaofnodes/simple/node/CastNode.java
index 38d6a126..9ade5a50 100644
--- a/chapter13/src/main/java/com/seaofnodes/simple/node/CastNode.java
+++ b/chapter13/src/main/java/com/seaofnodes/simple/node/CastNode.java
@@ -1,10 +1,11 @@
package com.seaofnodes.simple.node;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeInteger;
import com.seaofnodes.simple.IterPeeps;
-import java.util.BitSet;
// Upcast (join) the input to a t. Used after guard test to lift an input.
// Can also be used to make a type-assertion if ctrl is null.
@@ -18,13 +19,10 @@ public class CastNode extends Node {
@Override public String label() { return "("+_t.str()+")"; }
- @Override
- public String uniqueName() { return "Cast_" + _nid; }
- @Override
- StringBuilder _print1(StringBuilder sb, BitSet visited) {
- return in(1)._print0(sb.append(label()), visited);
+ @Override protected ExprPrinter<Node> _print1(ExprPrinter<Node> p) {
+ return p.p(label()).n(in(1));
}
@Override
diff --git a/chapter13/src/main/java/com/seaofnodes/simple/node/ConstantNode.java b/chapter13/src/main/java/com/seaofnodes/simple/node/ConstantNode.java
index 37a529d1..9ecd1152 100644
--- a/chapter13/src/main/java/com/seaofnodes/simple/node/ConstantNode.java
+++ b/chapter13/src/main/java/com/seaofnodes/simple/node/ConstantNode.java
@@ -1,9 +1,10 @@
package com.seaofnodes.simple.node;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.Parser;
import com.seaofnodes.simple.type.Type;
-import java.util.BitSet;
/**
* A Constant node represents a constant value. At present, the only constants
@@ -24,15 +25,16 @@ public class ConstantNode extends Node {
_con = type;
}
- @Override
- public String label() { return "#"+_con; }
+ @Override protected String repeatName() {
+ return _con==null || _con.toString().length()<=32 ? null : uniqueName();
+ }
@Override
- public String uniqueName() { return "Con_" + _nid; }
+ public String label() { return "Con"; }
- @Override
- StringBuilder _print1(StringBuilder sb, BitSet visited) {
- return _con.print(sb);
+
+ @Override protected ExprPrinter<Node> _print1(ExprPrinter<Node> p) {
+ return p.p(_con);
}
@Override public boolean isMultiTail() { return true; }
diff --git a/chapter13/src/main/java/com/seaofnodes/simple/node/DivFNode.java b/chapter13/src/main/java/com/seaofnodes/simple/node/DivFNode.java
index 6c0c2eb3..a3f4318d 100644
--- a/chapter13/src/main/java/com/seaofnodes/simple/node/DivFNode.java
+++ b/chapter13/src/main/java/com/seaofnodes/simple/node/DivFNode.java
@@ -1,21 +1,16 @@
package com.seaofnodes.simple.node;
+
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeFloat;
-import java.util.BitSet;
public class DivFNode extends Node {
public DivFNode(Node lhs, Node rhs) { super(null, lhs, rhs); }
@Override public String label() { return "DivF"; }
- @Override
- StringBuilder _print1(StringBuilder sb, BitSet visited) {
- in(1)._print0(sb.append("("), visited);
- in(2)._print0(sb.append("/"), visited);
- return sb.append(")");
- }
+ @Override protected String format() { return "(%1/%2)"; }
@Override
public Type compute() {
diff --git a/chapter13/src/main/java/com/seaofnodes/simple/node/DivNode.java b/chapter13/src/main/java/com/seaofnodes/simple/node/DivNode.java
index bc9ff7d9..cd52d117 100644
--- a/chapter13/src/main/java/com/seaofnodes/simple/node/DivNode.java
+++ b/chapter13/src/main/java/com/seaofnodes/simple/node/DivNode.java
@@ -1,21 +1,16 @@
package com.seaofnodes.simple.node;
+
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeInteger;
-import java.util.BitSet;
public class DivNode extends Node {
public DivNode(Node lhs, Node rhs) { super(null, lhs, rhs); }
@Override public String label() { return "Div"; }
- @Override
- StringBuilder _print1(StringBuilder sb, BitSet visited) {
- in(1)._print0(sb.append("("), visited);
- in(2)._print0(sb.append("/"), visited);
- return sb.append(")");
- }
+ @Override protected String format() { return "(%1/%2)"; }
@Override
public Type compute() {
diff --git a/chapter13/src/main/java/com/seaofnodes/simple/node/IfNode.java b/chapter13/src/main/java/com/seaofnodes/simple/node/IfNode.java
index 5457ac6e..70340f7f 100644
--- a/chapter13/src/main/java/com/seaofnodes/simple/node/IfNode.java
+++ b/chapter13/src/main/java/com/seaofnodes/simple/node/IfNode.java
@@ -1,5 +1,6 @@
package com.seaofnodes.simple.node;
+
import com.seaofnodes.simple.IterPeeps;
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeInteger;
@@ -17,11 +18,7 @@ public class IfNode extends CFGNode implements MultiNode {
@Override
public String label() { return "If"; }
- @Override
- StringBuilder _print1(StringBuilder sb, BitSet visited) {
- sb.append("if( ");
- return in(1)._print0(sb, visited).append(" )");
- }
+ @Override protected String format() { return "if( %1 )"; }
@Override public boolean isMultiHead() { return true; }
diff --git a/chapter13/src/main/java/com/seaofnodes/simple/node/LoadNode.java b/chapter13/src/main/java/com/seaofnodes/simple/node/LoadNode.java
index f1d4884a..277644f5 100644
--- a/chapter13/src/main/java/com/seaofnodes/simple/node/LoadNode.java
+++ b/chapter13/src/main/java/com/seaofnodes/simple/node/LoadNode.java
@@ -1,10 +1,11 @@
package com.seaofnodes.simple.node;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.Utils;
import com.seaofnodes.simple.IterPeeps;
import com.seaofnodes.simple.type.Type;
-import java.util.BitSet;
/**
* Load represents extracting a value from inside a memory object,
@@ -43,7 +44,7 @@ public class LoadNode extends MemOpNode {
@Override public String label() { return _name; }
@Override
- 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/chapter13/src/main/java/com/seaofnodes/simple/node/MemMergeNode.java b/chapter13/src/main/java/com/seaofnodes/simple/node/MemMergeNode.java
index d7fed402..f3d5b01e 100644
--- a/chapter13/src/main/java/com/seaofnodes/simple/node/MemMergeNode.java
+++ b/chapter13/src/main/java/com/seaofnodes/simple/node/MemMergeNode.java
@@ -1,9 +1,10 @@
package com.seaofnodes.simple.node;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.IterPeeps;
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeMem;
-import java.util.BitSet;
/** All memory: a default slice and explicit overrides for individual aliases. */
public class MemMergeNode extends Node {
@@ -28,14 +29,14 @@ public class MemMergeNode extends Node {
@Override public String label() { return "MemMerge"; }
@Override public boolean isMem() { return true; }
@Override public Type compute() { return TypeMem.BOT; }
- @Override StringBuilder _print1(StringBuilder sb, BitSet visited) {
- sb.append("MEM[");
+ @Override protected ExprPrinter<Node> _print1(ExprPrinter<Node> p) {
+ p.p("MEM[");
for( int i=1; i<nIns(); i++ )
if( in(i)!=null ) {
- sb.append(i==1 ? "default:" : i+":");
- in(i)._print0(sb,visited).append(" ");
+ p.p(i==1 ? "default:" : i+":");
+ p.n(in(i)).p(" ");
}
- return sb.append("]");
+ return p.p("]");
}
@Override public Node idealize() {
diff --git a/chapter13/src/main/java/com/seaofnodes/simple/node/MinusFNode.java b/chapter13/src/main/java/com/seaofnodes/simple/node/MinusFNode.java
index 7cacf2c9..1b45c7c5 100644
--- a/chapter13/src/main/java/com/seaofnodes/simple/node/MinusFNode.java
+++ b/chapter13/src/main/java/com/seaofnodes/simple/node/MinusFNode.java
@@ -1,20 +1,16 @@
package com.seaofnodes.simple.node;
+
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeFloat;
-import java.util.BitSet;
public class MinusFNode extends Node {
public MinusFNode(Node in) { super(null, in); }
@Override public String label() { return "MinusF"; }
- @Override
- 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/chapter13/src/main/java/com/seaofnodes/simple/node/MinusNode.java b/chapter13/src/main/java/com/seaofnodes/simple/node/MinusNode.java
index c3be733c..ae450b22 100644
--- a/chapter13/src/main/java/com/seaofnodes/simple/node/MinusNode.java
+++ b/chapter13/src/main/java/com/seaofnodes/simple/node/MinusNode.java
@@ -1,20 +1,16 @@
package com.seaofnodes.simple.node;
+
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeInteger;
-import java.util.BitSet;
public class MinusNode extends Node {
public MinusNode(Node in) { super(null, in); }
@Override public String label() { return "Minus"; }
- @Override
- 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/chapter13/src/main/java/com/seaofnodes/simple/node/MulFNode.java b/chapter13/src/main/java/com/seaofnodes/simple/node/MulFNode.java
index 4b753ba7..6a57f3c5 100644
--- a/chapter13/src/main/java/com/seaofnodes/simple/node/MulFNode.java
+++ b/chapter13/src/main/java/com/seaofnodes/simple/node/MulFNode.java
@@ -1,21 +1,16 @@
package com.seaofnodes.simple.node;
+
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeFloat;
-import java.util.BitSet;
public class MulFNode extends Node {
public MulFNode(Node lhs, Node rhs) { super(null, lhs, rhs); }
@Override public String label() { return "MulF"; }
- @Override
- StringBuilder _print1(StringBuilder sb, BitSet visited) {
- in(1)._print0(sb.append("("), visited);
- in(2)._print0(sb.append("*"), visited);
- return sb.append(")");
- }
+ @Override protected String format() { return "(%1*%2)"; }
@Override
public Type compute() {
diff --git a/chapter13/src/main/java/com/seaofnodes/simple/node/MulNode.java b/chapter13/src/main/java/com/seaofnodes/simple/node/MulNode.java
index 4cd075e4..7fd52399 100644
--- a/chapter13/src/main/java/com/seaofnodes/simple/node/MulNode.java
+++ b/chapter13/src/main/java/com/seaofnodes/simple/node/MulNode.java
@@ -1,21 +1,16 @@
package com.seaofnodes.simple.node;
+
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeInteger;
-import java.util.BitSet;
public class MulNode extends Node {
public MulNode(Node lhs, Node rhs) { super(null, lhs, rhs); }
@Override public String label() { return "Mul"; }
- @Override
- StringBuilder _print1(StringBuilder sb, BitSet visited) {
- in(1)._print0(sb.append("("), visited);
- in(2)._print0(sb.append("*"), visited);
- return sb.append(")");
- }
+ @Override protected String format() { return "(%1*%2)"; }
@Override
public Type compute() {
diff --git a/chapter13/src/main/java/com/seaofnodes/simple/node/NeverNode.java b/chapter13/src/main/java/com/seaofnodes/simple/node/NeverNode.java
index e77ed653..7e42ccf9 100644
--- a/chapter13/src/main/java/com/seaofnodes/simple/node/NeverNode.java
+++ b/chapter13/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 {
@@ -13,7 +14,7 @@ public class NeverNode extends IfNode {
@Override public String label() { return "Never"; }
- @Override 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/chapter13/src/main/java/com/seaofnodes/simple/node/NewNode.java b/chapter13/src/main/java/com/seaofnodes/simple/node/NewNode.java
index 1c82d5f5..74ba5184 100644
--- a/chapter13/src/main/java/com/seaofnodes/simple/node/NewNode.java
+++ b/chapter13/src/main/java/com/seaofnodes/simple/node/NewNode.java
@@ -1,9 +1,10 @@
package com.seaofnodes.simple.node;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeMemPtr;
-import java.util.BitSet;
public class NewNode extends Node {
@@ -17,10 +18,8 @@ public class NewNode extends Node {
@Override
public String label() { return "new"; }
- @Override
- StringBuilder _print1(StringBuilder sb, BitSet visited) {
- sb.append("new ");
- return sb.append(_ptr._obj.str());
+ @Override protected ExprPrinter<Node> _print1(ExprPrinter<Node> p) {
+ return p.p("new ").p(_ptr._obj.str());
}
diff --git a/chapter13/src/main/java/com/seaofnodes/simple/node/Node.java b/chapter13/src/main/java/com/seaofnodes/simple/node/Node.java
index 2082168a..7448e05e 100644
--- a/chapter13/src/main/java/com/seaofnodes/simple/node/Node.java
+++ b/chapter13/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.Parser;
import com.seaofnodes.simple.IRPrinter;
@@ -16,14 +18,7 @@ import java.util.function.Function;
* The Node class provides common functionality used by all subtypes.
* Subtypes of Node specialize by overriding methods.
*/
-public abstract class Node implements OutNode, 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 OutNode, Cloneable {
/**
* Inputs to the node. These are use-def references to Nodes.
@@ -45,14 +40,12 @@ public abstract class Node implements OutNode, Cloneable {
*/
public ArrayList<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;
-
/**
* A private Global Static mutable counter, for unique node id generation.
* To make the compiler multithreaded, this field will have to move into a TLS.
@@ -62,7 +55,7 @@ public abstract class Node implements OutNode, Cloneable {
public static int UID() { return UNIQUE_ID; }
protected Node(Node... inputs) {
- _nid = UNIQUE_ID++; // allocate unique dense ID
+ super(UNIQUE_ID++); // allocate unique dense ID
_inputs = new ArrayList<>();
Collections.addAll(_inputs,inputs);
_outputs = new ArrayList<>();
@@ -74,42 +67,6 @@ public abstract class Node implements OutNode, Cloneable {
// Easy reading label for debugger, e.g. "Add" or "Region" or "EQ"
public abstract String label();
- // Unique label for debugging, e.g. "Add12" or "Region30" or "EQ99"
- public String uniqueName() {
- return label() + _nid;
- }
-
- // ------------------------------------------------------------------------
-
- // 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. This version will fail on cycles, which we will
- // correct later when we can parse programs with loops. We print with a
- // 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.
- 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 StringBuilder _print1(StringBuilder sb, BitSet visited);
-
public String p(int depth) { return IRPrinter.prettyPrint(this,depth); }
public boolean isMultiHead() { return false; }
@@ -118,6 +75,8 @@ public abstract class Node implements OutNode, 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
@@ -258,7 +217,6 @@ public abstract class Node implements OutNode, Cloneable {
// Test "keep" status
public boolean iskeep() { return Utils.find(_outputs,null) != -1; }
-
// Replace self with nnn in the graph, making 'this' go dead
public void subsume( Node nnn ) {
assert nnn!=this;
@@ -389,7 +347,6 @@ public abstract class Node implements OutNode, Cloneable {
return old;
}
-
/**
* This function rewrites the current Node into a more "idealized" form.
* This is the bulk of our peephole rewrite rules, and we use this to
@@ -437,7 +394,6 @@ public abstract class Node implements OutNode, 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
@@ -481,7 +437,6 @@ public abstract class Node implements OutNode, Cloneable {
_deps.clear();
}
-
// Global Value Numbering. Hash over opcode and inputs; hits in this table
// are structurally equal.
public static final HashMap<Node,Node> GVN = new HashMap<>();
@@ -503,7 +458,6 @@ public abstract class Node implements OutNode, Cloneable {
// and can assume "this!=n" and has the same Java class.
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
@@ -519,7 +473,6 @@ public abstract class Node implements OutNode, Cloneable {
_hash=0; // Out of table now
}
-
// Hash of opcode and inputs
@Override public final int hashCode() {
if( _hash != 0 ) return _hash;
@@ -537,7 +490,6 @@ public abstract class Node implements OutNode, Cloneable {
//
/** Is this Node control-flow-graph related */
- public boolean isCFG() { return false; }
/** Is this Node Memory related */
public boolean isMem() { return false; }
@@ -545,7 +497,6 @@ public abstract class Node implements OutNode, Cloneable {
/** Return block start from a isCFG() */
public Node getBlockStart() { return null; }
-
// Semantic change to the graph (so NOT a peephole), used by the Parser.
// If any input is a float, flip to a float-flavored opcode and widen any
// non-float input.
@@ -566,7 +517,6 @@ public abstract class Node implements OutNode, Cloneable {
}
Node copyF() { return null; }
-
// ------------------------------------------------------------------------
// Peephole utilities
@@ -595,7 +545,6 @@ public abstract class Node implements OutNode, 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.
@@ -628,7 +577,6 @@ public abstract class Node implements OutNode, Cloneable {
ITER_CNT = ITER_NOP_CNT = 0;
}
-
// Utility to walk the entire graph applying a function; return the first
// not-null result.
private static final BitSet WVISIT = new BitSet();
diff --git a/chapter13/src/main/java/com/seaofnodes/simple/node/NotNode.java b/chapter13/src/main/java/com/seaofnodes/simple/node/NotNode.java
index bb7e9265..4539f982 100644
--- a/chapter13/src/main/java/com/seaofnodes/simple/node/NotNode.java
+++ b/chapter13/src/main/java/com/seaofnodes/simple/node/NotNode.java
@@ -1,19 +1,15 @@
package com.seaofnodes.simple.node;
+
import com.seaofnodes.simple.Utils;
import com.seaofnodes.simple.type.*;
-import java.util.BitSet;
public class NotNode extends Node {
public NotNode(Node in) { super(null, in); }
@Override public String label() { return "Not"; }
- @Override
- 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/chapter13/src/main/java/com/seaofnodes/simple/node/PhiNode.java b/chapter13/src/main/java/com/seaofnodes/simple/node/PhiNode.java
index 277c16d1..8dfa04cf 100644
--- a/chapter13/src/main/java/com/seaofnodes/simple/node/PhiNode.java
+++ b/chapter13/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.type.Type;
import com.seaofnodes.simple.type.TypeMem;
import com.seaofnodes.simple.Utils;
-import java.util.BitSet;
public class PhiNode extends Node {
@@ -23,18 +24,12 @@ public class PhiNode extends Node {
@Override public String label() { return "Phi_"+_label; }
@Override
- 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/chapter13/src/main/java/com/seaofnodes/simple/node/ProjNode.java b/chapter13/src/main/java/com/seaofnodes/simple/node/ProjNode.java
index 93239a61..e82c69b3 100644
--- a/chapter13/src/main/java/com/seaofnodes/simple/node/ProjNode.java
+++ b/chapter13/src/main/java/com/seaofnodes/simple/node/ProjNode.java
@@ -1,10 +1,11 @@
package com.seaofnodes.simple.node;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeMem;
import com.seaofnodes.simple.type.TypeTuple;
-import java.util.BitSet;
public class ProjNode extends Node {
@@ -24,7 +25,7 @@ public class ProjNode extends Node {
public String label() { return _label; }
@Override
- StringBuilder _print1(StringBuilder sb, BitSet visited) { return sb.append(_label); }
+ protected ExprPrinter<Node> _print1(ExprPrinter<Node> p) { return p.p(_label); }
@Override public boolean isMultiTail() { return in(0).isMultiHead(); }
@Override public boolean isMem() { return _type instanceof TypeMem; }
diff --git a/chapter13/src/main/java/com/seaofnodes/simple/node/RegionNode.java b/chapter13/src/main/java/com/seaofnodes/simple/node/RegionNode.java
index d7e934d7..cdfd10ad 100644
--- a/chapter13/src/main/java/com/seaofnodes/simple/node/RegionNode.java
+++ b/chapter13/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.IterPeeps;
import com.seaofnodes.simple.Parser;
import com.seaofnodes.simple.Utils;
@@ -16,9 +18,8 @@ public class RegionNode extends CFGNode {
@Override
public String label() { return "Region"; }
- @Override
- StringBuilder _print1(StringBuilder sb, BitSet visited) {
- return sb.append(label()).append(_nid);
+ @Override protected ExprPrinter<Node> _print1(ExprPrinter<Node> p) {
+ return p.p(label()).p(_nid);
}
@Override public boolean isMultiHead() { return true; }
diff --git a/chapter13/src/main/java/com/seaofnodes/simple/node/ReturnNode.java b/chapter13/src/main/java/com/seaofnodes/simple/node/ReturnNode.java
index 725c704f..161cc7d6 100644
--- a/chapter13/src/main/java/com/seaofnodes/simple/node/ReturnNode.java
+++ b/chapter13/src/main/java/com/seaofnodes/simple/node/ReturnNode.java
@@ -1,8 +1,9 @@
package com.seaofnodes.simple.node;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.type.*;
-import java.util.BitSet;
/** Keeps all preceding memory effects and the return value alive: {ctrl, $mem, value}. */
public class ReturnNode extends CFGNode {
@@ -20,10 +21,10 @@ public class ReturnNode extends CFGNode {
public String label() { return "Return"; }
@Override
- StringBuilder _print1(StringBuilder sb, BitSet visited) {
- sb.append("return ");
- expr()._print0(sb, visited);
- return sb.append(";");
+ protected ExprPrinter<Node> _print1(ExprPrinter<Node> p) {
+ p.p("return ");
+ p.n(expr());
+ return p.p(";");
}
@Override
diff --git a/chapter13/src/main/java/com/seaofnodes/simple/node/ScopeNode.java b/chapter13/src/main/java/com/seaofnodes/simple/node/ScopeNode.java
index b931e862..b408eb2f 100644
--- a/chapter13/src/main/java/com/seaofnodes/simple/node/ScopeNode.java
+++ b/chapter13/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.IterPeeps;
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.Utils;
@@ -42,20 +44,19 @@ public class ScopeNode extends Node {
@Override public String label() { return "Scope"; }
@Override
- StringBuilder _print1(StringBuilder sb, BitSet visited) {
- sb.append("Scope[ ");
+ protected ExprPrinter<Node> _print1(ExprPrinter<Node> p) {
+ p.p("Scope[ ");
String[] names = reverseNames();
for( int j=0; j<nIns(); j++ ) {
- sb.append(names[j]).append(":");
+ p.p(names[j]).p(":");
Node n = in(j);
while( n instanceof ScopeNode loop ) {
- sb.append("Lazy_");
+ p.p("Lazy_");
n = loop.in(j);
}
- n._print0(sb, visited).append(" ");
+ p.n(n).p(" ");
}
- sb.setLength(sb.length()-1);
- return sb.append("]");
+ return p.unchar(' ').p("]");
}
/**
diff --git a/chapter13/src/main/java/com/seaofnodes/simple/node/StartNode.java b/chapter13/src/main/java/com/seaofnodes/simple/node/StartNode.java
index 2cedf0f6..a5d4923f 100644
--- a/chapter13/src/main/java/com/seaofnodes/simple/node/StartNode.java
+++ b/chapter13/src/main/java/com/seaofnodes/simple/node/StartNode.java
@@ -1,5 +1,7 @@
package com.seaofnodes.simple.node;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.type.*;
import java.util.BitSet;
import java.util.HashSet;
@@ -17,9 +19,8 @@ public class StartNode extends CFGNode implements MultiNode {
@Override
public String label() { return "Start"; }
- @Override
- 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 isMultiHead() { return true; }
diff --git a/chapter13/src/main/java/com/seaofnodes/simple/node/StopNode.java b/chapter13/src/main/java/com/seaofnodes/simple/node/StopNode.java
index af3a9de6..202afbd2 100644
--- a/chapter13/src/main/java/com/seaofnodes/simple/node/StopNode.java
+++ b/chapter13/src/main/java/com/seaofnodes/simple/node/StopNode.java
@@ -1,12 +1,13 @@
package com.seaofnodes.simple.node;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.Parser;
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.IterPeeps;
import com.seaofnodes.simple.GlobalCodeMotion;
-import java.util.BitSet;
public class StopNode extends CFGNode {
@@ -23,12 +24,12 @@ public class StopNode extends CFGNode {
}
@Override
- StringBuilder _print1(StringBuilder sb, BitSet visited) {
- if( ret()!=null ) return ret()._print0(sb, visited);
- sb.append("Stop[ ");
+ protected ExprPrinter<Node> _print1(ExprPrinter<Node> p) {
+ if( ret()!=null ) return p.n(ret());
+ p.p("Stop[ ");
for( Node ret : _inputs )
- ret._print0(sb, visited).append(" ");
- return sb.append("]");
+ p.n(ret).p(" ");
+ return p.p("]");
}
@Override public boolean blockHead() { return true; }
diff --git a/chapter13/src/main/java/com/seaofnodes/simple/node/StoreNode.java b/chapter13/src/main/java/com/seaofnodes/simple/node/StoreNode.java
index 031240ce..e9eaaf2e 100644
--- a/chapter13/src/main/java/com/seaofnodes/simple/node/StoreNode.java
+++ b/chapter13/src/main/java/com/seaofnodes/simple/node/StoreNode.java
@@ -1,10 +1,11 @@
package com.seaofnodes.simple.node;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.Utils;
import com.seaofnodes.simple.IterPeeps;
import com.seaofnodes.simple.type.*;
-import java.util.BitSet;
/**
* Store represents setting a value to a memory based object, in chapter 10
@@ -35,8 +36,8 @@ public class StoreNode extends MemOpNode {
public Node val() { return in(3); }
@Override
- 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/chapter13/src/main/java/com/seaofnodes/simple/node/SubFNode.java b/chapter13/src/main/java/com/seaofnodes/simple/node/SubFNode.java
index d911ce7e..7c1a5dde 100644
--- a/chapter13/src/main/java/com/seaofnodes/simple/node/SubFNode.java
+++ b/chapter13/src/main/java/com/seaofnodes/simple/node/SubFNode.java
@@ -1,21 +1,16 @@
package com.seaofnodes.simple.node;
+
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeFloat;
-import java.util.BitSet;
public class SubFNode extends Node {
public SubFNode(Node lhs, Node rhs) { super(null, lhs, rhs); }
@Override public String label() { return "SubF"; }
- @Override
- StringBuilder _print1(StringBuilder sb, BitSet visited) {
- in(1)._print0(sb.append("("), visited);
- in(2)._print0(sb.append("-"), visited);
- return sb.append(")");
- }
+ @Override protected String format() { return "(%1-%2)"; }
@Override
public Type compute() {
diff --git a/chapter13/src/main/java/com/seaofnodes/simple/node/SubNode.java b/chapter13/src/main/java/com/seaofnodes/simple/node/SubNode.java
index 4ae302f0..f36f2af5 100644
--- a/chapter13/src/main/java/com/seaofnodes/simple/node/SubNode.java
+++ b/chapter13/src/main/java/com/seaofnodes/simple/node/SubNode.java
@@ -1,22 +1,17 @@
package com.seaofnodes.simple.node;
+
import com.seaofnodes.simple.Parser;
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeInteger;
-import java.util.BitSet;
public class SubNode extends Node {
public SubNode(Node lhs, Node rhs) { super(null, lhs, rhs); }
@Override public String label() { return "Sub"; }
- @Override
- StringBuilder _print1(StringBuilder sb, BitSet visited) {
- in(1)._print0(sb.append("("), visited);
- in(2)._print0(sb.append("-"), visited);
- return sb.append(")");
- }
+ @Override protected String format() { return "(%1-%2)"; }
@Override
public Type compute() {
diff --git a/chapter13/src/main/java/com/seaofnodes/simple/node/ToFloatNode.java b/chapter13/src/main/java/com/seaofnodes/simple/node/ToFloatNode.java
index fde483d6..26cf50e1 100644
--- a/chapter13/src/main/java/com/seaofnodes/simple/node/ToFloatNode.java
+++ b/chapter13/src/main/java/com/seaofnodes/simple/node/ToFloatNode.java
@@ -1,20 +1,17 @@
package com.seaofnodes.simple.node;
+
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeFloat;
import com.seaofnodes.simple.type.TypeInteger;
-import java.util.BitSet;
public class ToFloatNode extends Node {
public ToFloatNode(Node lhs) { super(null, lhs); }
@Override public String label() { return "ToFloat"; }
- @Override
- 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/chapter13/src/main/java/com/seaofnodes/simple/node/XCtrlNode.java b/chapter13/src/main/java/com/seaofnodes/simple/node/XCtrlNode.java
index 83779dd2..056dfba1 100644
--- a/chapter13/src/main/java/com/seaofnodes/simple/node/XCtrlNode.java
+++ b/chapter13/src/main/java/com/seaofnodes/simple/node/XCtrlNode.java
@@ -1,13 +1,14 @@
package com.seaofnodes.simple.node;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.Parser;
import com.seaofnodes.simple.type.Type;
-import java.util.BitSet;
public class XCtrlNode extends CFGNode {
public XCtrlNode( ) { super(Parser.START); }
@Override public String label() { return "Xctrl"; }
- @Override StringBuilder _print1(StringBuilder sb, BitSet visited) { return sb.append("Xctrl"); }
+ @Override protected ExprPrinter<Node> _print1(ExprPrinter<Node> p) { return p.p("Xctrl"); }
@Override public Type compute() { return Type.XCONTROL; }
@Override public Node idealize() { return null; }
}
diff --git a/chapter13/src/main/java/com/seaofnodes/simple/print/SimpleGraphAdapter.java b/chapter13/src/main/java/com/seaofnodes/simple/print/SimpleGraphAdapter.java
index 3778a6d9..9d996c03 100644
--- a/chapter13/src/main/java/com/seaofnodes/simple/print/SimpleGraphAdapter.java
+++ b/chapter13/src/main/java/com/seaofnodes/simple/print/SimpleGraphAdapter.java
@@ -1,43 +1,20 @@
package com.seaofnodes.simple.print;
import com.seaofnodes.graph.GraphAdapter;
-import com.seaofnodes.graph.GraphSnapshot;
import com.seaofnodes.graph.GraphSnapshot.*;
import com.seaofnodes.simple.node.*;
import com.seaofnodes.simple.node.Node;
import com.seaofnodes.simple.type.TypeMem;
-import java.util.ArrayList;
/** Chapter 13's view of the IR; browser, transport and layout are shared. */
public class SimpleGraphAdapter extends GraphAdapter<Node> {
- @Override protected boolean dead(Node n) { return n.isDead(); }
- @Override protected int id(Node n) { return n._nid; }
- @Override protected int nIns(Node n) { return n.nIns(); }
- @Override protected Node in(Node n, int idx) { return n.in(idx); }
- @Override protected int nOuts(Node n) { return n.nOuts(); }
- @Override protected Node out(Node n, int idx) { return n.out(idx); }
- @Override protected int nDeps(Node n) { return n.nDeps(); }
- @Override protected Node dep(Node n, int idx) { return n.dep(idx); }
- private ArrayList<Edge> edges(Node n) {
- var edges = new ArrayList<Edge>();
- String[] names = n instanceof ScopeNode scope && n.nIns() != 0 ? scope.reverseNames() : null;
- for( int i = 0; i < n.nIns(); i++ ) {
- String name = names == null || i >= names.length ? null : names[i];
- edges.add(new Edge(i, ref(n.in(i)), role(n, i), name));
- }
- return edges;
+ @Override protected String[] edgeNames(Node n) {
+ return n instanceof ScopeNode scope && n.nIns()!=0 ? scope.reverseNames() : null;
}
+ @Override protected int projectionIndex(Node n) { return n instanceof ProjNode p ? p._idx : n instanceof CProjNode p ? p._idx : -1; }
- @Override protected GraphSnapshot.Node desc(Node n) {
- Projection proj = n instanceof ProjNode p ? new Projection(ref(n.in(0)), p._idx)
- : n instanceof CProjNode p ? new Projection(ref(n.in(0)), p._idx) : null;
- String label = n.label();
- return new GraphSnapshot.Node(n._nid, label == null ? n.getClass().getSimpleName() : label,
- n._type == null ? null : n._type.toString(), kind(n), edges(n), proj);
- }
-
- 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 StartNode ) return Kind.CTRL;
@@ -47,7 +24,7 @@ public class SimpleGraphAdapter extends GraphAdapter<Node> {
return n.isCFG() ? Kind.CTRL : isMem(n) ? Kind.MEM : Kind.DATA;
}
- private Role role(Node n, int i) {
+ @Override protected Role role(Node n, int i) {
if( n instanceof ScopeNode || n instanceof ConstantNode || n instanceof XCtrlNode ) return Role.ASSOC;
if( n instanceof PhiNode ) return i == 0 ? Role.ASSOC : isMem(n) ? Role.MEM : Role.DATA;
if( n instanceof ProjNode || n instanceof CProjNode ) return n.isCFG() ? Role.CTRL : isMem(n) ? Role.MEM : Role.DATA;
diff --git a/chapter14/Makefile b/chapter14/Makefile
index 77df7182..3f1e53ff 100644
--- a/chapter14/Makefile
+++ b/chapter14/Makefile
@@ -37,6 +37,7 @@ main_javas := $(wildcard $(SRC)/$(SIMPLE)/*java $(SRC)/$(SIMPLE)/*/*java)
test_javas := $(wildcard $(TST)/$(SIMPLE)/*java $(TST)/$(SIMPLE)/*/*java)
main_classes := $(patsubst $(SRC)/%java,$(CLZDIR)/main/%class,$(main_javas))
include $(firstword $(wildcard ../graph/graph.mk graph/graph.mk))
+include $(firstword $(wildcard ../print/print.mk print/print.mk))
test_classes := $(patsubst $(TST)/%java,$(CLZDIR)/test/%class,$(test_javas))
test_cp := $(patsubst $(TST)/$(SIMPLE)/%.java,com.seaofnodes.simple.%,$(wildcard $(TST)/$(SIMPLE)/*Test.java))
classes = $(main_classes) $(test_classes)
@@ -54,7 +55,7 @@ endif
default: $(default_targets)
# Compile just the out-of-date files
-$(main_classes): build/classes/main/%class: $(SRC)/%java $(graph_javas)
+$(main_classes): build/classes/main/%class: $(SRC)/%java $(graph_javas) $(print_javas)
@echo "compiling " $@ " because " $?
@[ -d $(CLZDIR)/main ] || mkdir -p $(CLZDIR)/main
@javac $(JAVAC_ARGS) -cp "$(CLZDIR)/main$(SEP)$(jars)" -sourcepath $(SRC) -d $(CLZDIR)/main $(main_javas)
diff --git a/chapter14/pom.xml b/chapter14/pom.xml
index 3aaa2d40..b8a8cb32 100644
--- a/chapter14/pom.xml
+++ b/chapter14/pom.xml
@@ -13,5 +13,6 @@
<name>Chapter 14</name>
<properties>
<simple.graph.directory>${project.basedir}/../graph</simple.graph.directory>
+ <simple.print.directory>${project.basedir}/../print</simple.print.directory>
</properties>
</project>
diff --git a/chapter14/src/main/java/com/seaofnodes/simple/IRPrinter.java b/chapter14/src/main/java/com/seaofnodes/simple/IRPrinter.java
index 3410ab64..7e93e9da 100644
--- a/chapter14/src/main/java/com/seaofnodes/simple/IRPrinter.java
+++ b/chapter14/src/main/java/com/seaofnodes/simple/IRPrinter.java
@@ -1,288 +1,33 @@
package com.seaofnodes.simple;
+import com.seaofnodes.print.IRAdapter;
import com.seaofnodes.simple.node.*;
-import java.lang.StringBuilder;
-import java.util.ArrayList;
-import java.util.BitSet;
-import java.util.HashMap;
-import java.util.IdentityHashMap;
-
-public 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 void _printLine( Node n, StringBuilder sb ) {
- sb.append("%4d %-7.7s ".formatted(n._nid,n.label()));
- if( n.isDead() ) {
- sb.append("DEAD\n");
- return;
- }
- for( Node def : n._inputs )
- sb.append(def==null ? "____ " : "%4d ".formatted(def._nid));
- for( int i = n._inputs.size(); i<4; i++ )
- sb.append(" ");
- sb.append(" [[ ");
- for( Node use : n._outputs )
- sb.append(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.append(" ");
- sb.append(" ]] ");
- if( n._type!= null ) sb.append(n._type.str());
- sb.append("\n");
- }
-
- private static StringBuilder nodeId(StringBuilder sb, Node n) {
- sb.append("%%%d".formatted(n._nid));
- if (n instanceof ProjNode proj) {
- sb.append(".").append(proj._idx);
- }
- return sb;
- }
-
- // Print a node on 1 line, format is inspired by LLVM
- // %id: TYPE = NODE(inputs ....)
- // Nodes as referred to as %id
- public static void _printLineLlvmFormat( Node n, StringBuilder sb ) {
- nodeId(sb, n).append(": ");
- if( n.isDead() ) {
- sb.append("DEAD\n");
- return;
- }
- if( n._type!= null ) n._type.typeName(sb);
- sb.append(" = ").append( n.label() ).append( "(" );
- for( int i = 0; i < n._inputs.size(); i++ ) {
- Node def = n.in(i);
- if (i > 0)
- sb.append(", ");
- if (def == null) sb.append("_");
- else nodeId(sb, def);
- }
- sb.append(")").append("\n");
- }
-
- public static void printLine( Node n, StringBuilder sb, boolean llvmFormat ) {
- if (llvmFormat) _printLineLlvmFormat( n, sb );
- else _printLine ( n, sb );
- }
-
- public static String prettyPrint(Node node, int depth) {
- return Parser.SCHEDULED
- ? prettyPrintScheduled( node, depth, false )
- : prettyPrint( node, depth, false );
- }
-
- // Another bulk pretty-printer. Makes more effort at basic-block grouping.
- public static String prettyPrint( Node node, int depth, boolean llvmFormat ) {
- // First, a Breadth First Search at a fixed depth.
- BFS bfs = new BFS(node,depth);
- // Convert just that set to a post-order
- ArrayList<Node> rpos = new ArrayList<>();
- BitSet visit = new BitSet();
- for( int i=bfs._lim; i< bfs._bfs.size(); i++ )
- postOrd( bfs._bfs.get(i), rpos, visit, bfs._bs);
- // Reverse the post-order walk
- StringBuilder sb = new StringBuilder();
- boolean gap=false;
- for( int i=rpos.size()-1; i>=0; i-- ) {
- Node n = rpos.get(i);
- if( n.isCFG() || n.isMultiHead() ) {
- if( !gap ) sb.append("\n"); // Blank before multihead
- printLine( n, sb, llvmFormat ); // Print head
- while( --i >= 0 ) {
- Node t = rpos.get(i);
- if( !t.isMultiTail() ) { i++; break; }
- printLine( t, sb, llvmFormat );
- }
- sb.append("\n"); // Blank after multitail
- gap = true;
- } else {
- printLine( n, sb, llvmFormat );
- gap = false;
- }
- }
- return sb.toString();
- }
-
- private static void postOrd(Node n, ArrayList<Node> rpos, BitSet visit, BitSet bfs) {
- if( !bfs.get(n._nid) )
- return; // Not in the BFS visit
- if( visit.get(n._nid) ) return; // Already post-order walked
- visit.set(n._nid);
- // First walk the CFG, then everything
- if( n.isCFG() ) {
- for( Node use : n._outputs )
- if( use!=null && use.isCFG() && use.nOuts()>=1 && !(use._outputs.get(0) instanceof LoopNode) )
- postOrd(use, rpos,visit,bfs);
- for( Node use : n._outputs )
- if( use!=null && use.isCFG() )
- postOrd(use,rpos,visit,bfs);
- }
- for( Node use : n._outputs )
- if( use != null )
- postOrd(use, rpos,visit,bfs);
- // Post-order
- rpos.add(n);
- }
-
- // Breadth-first search, broken out in a class to keep in more independent.
- // Maintains a root-set of Nodes at the limit (or past by 1 if MultiHead).
- public static class BFS {
- // A breadth first search, plus MultiHeads for any MultiTails
- public final ArrayList<Node> _bfs;
- public final BitSet _bs; // Visited members by node id
- public final int _depth; // Depth limit
- public final int _lim; // From here to _bfs._len can be roots for a reverse search
- public BFS( Node base, int d ) {
- _depth = d;
- _bfs = new ArrayList<>();
- _bs = new BitSet();
-
- add(base); // Prime the pump
- int idx=0, lim=1; // Limit is where depth counter changes
- while( idx < _bfs.size() ) { // Ran out of nodes below depth
- Node n = _bfs.get(idx++);
- for( Node def : n._inputs )
- if( def!=null && !_bs.get(def._nid) )
- add(def);
- if( idx==lim ) { // Depth counter changes at limit
- if( --d < 0 )
- break; // Ran out of depth
- lim = _bfs.size(); // New depth limit
- }
- }
- // Toss things past the limit except multi-heads
- while( idx < _bfs.size() ) {
- Node n = _bfs.get(idx);
- if( n.isMultiHead() ) idx++;
- else del(idx);
- }
- // Root set is any node with no inputs in the visited set
- lim = _bfs.size();
- for( int i=_bfs.size()-1; i>=0; i-- )
- if( !any_visited(_bfs.get(i)) )
- swap( i,--lim);
- _lim = lim;
- }
- void swap( int x, int y ) {
- if( x==y ) return;
- Node tx = _bfs.get(x);
- Node ty = _bfs.get(y);
- _bfs.set(x,ty);
- _bfs.set(y,tx);
- }
- void add(Node n) {
- _bfs.add(n);
- _bs.set(n._nid);
- }
- void del(int idx) {
- Node n = Utils.del(_bfs, idx);
- _bs.clear(n._nid);
- }
- boolean any_visited( Node n ) {
- for( Node def : n._inputs )
- if( def!=null && _bs.get(def._nid) )
- return true;
- return false;
- }
- }
-
- // Diagnostic block ordering from raw control edges. Do not call idepth():
- // it fills compiler caches (and can walk lazy dominator accessors).
- private static int _idepth(CFGNode cfg, HashMap<Integer,Integer> depths) {
- if( cfg == null || cfg instanceof StartNode ) return 0;
- Integer old = depths.get(cfg._nid);
- if( old != null ) return old;
- depths.put(cfg._nid,0); // Break cycles in partially constructed graphs.
- int d = 0;
- if( cfg instanceof LoopNode ) {
- d = _idepth((CFGNode)cfg.in(1),depths)+1;
- } else if( cfg instanceof RegionNode || cfg instanceof StopNode ) {
- for( Node n : cfg._inputs )
- if( n instanceof CFGNode pred ) d = Math.max(d,_idepth(pred,depths)+1);
- } else if( cfg.in(0) instanceof CFGNode pred ) {
- d = _idepth(pred,depths)+1;
- }
- depths.put(cfg._nid,d);
- return d;
- }
-
- // Bulk pretty printer, knowing scheduling information is available
- public static String prettyPrintScheduled( Node node, int depth, boolean llvmFormat ) {
- // Backwards DFS walk to depth.
- IdentityHashMap<Node,Integer> ds = new IdentityHashMap<>();
- _walk(ds,node,depth);
- // Print by block with least diagnostic depth
- HashMap<Integer,Integer> depths = new HashMap<>();
- StringBuilder sb = new StringBuilder();
- ArrayList<Node> bns = new ArrayList<>();
- while( !ds.isEmpty() ) {
- CFGNode blk = null;
- for( Node n : ds.keySet() ) {
- CFGNode cfg = n instanceof CFGNode cfg0 && cfg0.blockHead() ? cfg0 : (CFGNode)n.in(0);
- if( blk==null || _idepth(cfg,depths) < _idepth(blk,depths) )
- blk = cfg;
- }
- ds.remove(blk);
-
- // Print block header
- sb.append("%-13.13s".formatted(label(blk)+":"));
- sb.append( " ".repeat(4) ).append(" [[ ");
- if( blk instanceof RegionNode || blk instanceof StopNode )
- for( int i=(blk instanceof StopNode ? 0 : 1); i<blk.nIns(); i++ )
- label(sb,blk.cfg(i));
- else if( !(blk instanceof StartNode) )
- label(sb,blk.cfg(0));
- sb.append(" ]] \n");
-
- // Collect block contents that are in the depth limit
- bns.clear();
- int xd = Integer.MAX_VALUE;
- for( Node use : blk._outputs ) {
- Integer i = ds.get(use);
- if( i!=null && !(use instanceof CFGNode cfg && cfg.blockHead()) ) {
- bns.add(use);
- xd = Math.min(xd,i);
- }
- }
- // Print Phis up front, if any
- for( int i=0; i<bns.size(); i++ )
- if( bns.get(i) instanceof PhiNode phi )
- printLine( phi, sb, llvmFormat,bns,i--,ds);
-
- // Print block contents in depth order, bumping depth until whole block printed
- for( ; !bns.isEmpty(); xd++ )
- for( int i=0; i<bns.size(); i++ )
- if( ds.get(bns.get(i))==xd )
- printLine( bns.get(i), sb, llvmFormat, bns, i--, ds );
- sb.append("\n");
- }
- return sb.toString();
- }
-
- private static void _walk( IdentityHashMap<Node,Integer> ds, Node node, int d ) {
- Integer nd = ds.get(node);
- if( nd!=null && d <= nd ) return; // Been there, done that
- ds.put(node,d);
- if( d == 0 ) return; // Depth cutoff
- for( Node def : node._inputs )
- if( def != null )
- _walk(ds,def,d-1);
- }
-
- static String label( CFGNode blk ) {
- if( blk instanceof StartNode ) return "START";
- return (blk instanceof LoopNode ? "LOOP" : "L")+blk._nid;
- }
- static void label( StringBuilder sb, CFGNode blk ) {
- if( !blk.blockHead() ) blk = blk.cfg(0);
- sb.append( "%-9.9s ".formatted( label( blk ) ) );
- }
- static void printLine( Node n, StringBuilder sb, boolean llvmFormat, ArrayList<Node> bns, int i, IdentityHashMap<Node,Integer> ds ) {
- printLine( n, sb, llvmFormat );
- Utils.del(bns,i);
- ds.remove(n);
- }
+/** 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 String type(Node n) { return n._type==null ? "" : n._type.str(); }
+ @Override public String inputMark(Node n, Node def) { return n instanceof MemMergeNode && def instanceof MemMergeNode ? "^" : " "; }
+ @Override public Kind kind(Node n) {
+ if( n instanceof StartNode ) return Kind.START;
+ if( n instanceof StopNode ) return Kind.STOP;
+ if( n instanceof LoopNode ) return Kind.LOOP;
+ if( n instanceof RegionNode ) return Kind.REGION;
+ if( n instanceof PhiNode ) return Kind.PHI;
+ 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;
+ }
+
+ public static String prettyPrint(Node n, int depth) { return PRINT.prettyPrint(n,depth); }
}
diff --git a/chapter14/src/main/java/com/seaofnodes/simple/node/AddFNode.java b/chapter14/src/main/java/com/seaofnodes/simple/node/AddFNode.java
index 5d0a473a..fd713156 100644
--- a/chapter14/src/main/java/com/seaofnodes/simple/node/AddFNode.java
+++ b/chapter14/src/main/java/com/seaofnodes/simple/node/AddFNode.java
@@ -1,21 +1,16 @@
package com.seaofnodes.simple.node;
+
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeFloat;
-import java.util.BitSet;
public class AddFNode extends Node {
public AddFNode(Node lhs, Node rhs) { super(null, lhs, rhs); }
@Override public String label() { return "AddF"; }
- @Override
- StringBuilder _print1(StringBuilder sb, BitSet visited) {
- in(1)._print0(sb.append("("), visited);
- in(2)._print0(sb.append("+"), visited);
- return sb.append(")");
- }
+ @Override protected String format() { return "(%1+%2)"; }
@Override
public Type compute() {
diff --git a/chapter14/src/main/java/com/seaofnodes/simple/node/AddNode.java b/chapter14/src/main/java/com/seaofnodes/simple/node/AddNode.java
index 31332722..5e54100d 100644
--- a/chapter14/src/main/java/com/seaofnodes/simple/node/AddNode.java
+++ b/chapter14/src/main/java/com/seaofnodes/simple/node/AddNode.java
@@ -1,20 +1,15 @@
package com.seaofnodes.simple.node;
+
import com.seaofnodes.simple.type.*;
-import java.util.BitSet;
public class AddNode extends Node {
public AddNode(Node lhs, Node rhs) { super(null, lhs, rhs); }
@Override public String label() { return "Add"; }
- @Override
- StringBuilder _print1(StringBuilder sb, BitSet visited) {
- in(1)._print0(sb.append("("), visited);
- in(2)._print0(sb.append("+"), visited);
- return sb.append(")");
- }
+ @Override protected String format() { return "(%1+%2)"; }
@Override
diff --git a/chapter14/src/main/java/com/seaofnodes/simple/node/AndNode.java b/chapter14/src/main/java/com/seaofnodes/simple/node/AndNode.java
index 8afb14b1..5e51e248 100644
--- a/chapter14/src/main/java/com/seaofnodes/simple/node/AndNode.java
+++ b/chapter14/src/main/java/com/seaofnodes/simple/node/AndNode.java
@@ -1,21 +1,16 @@
package com.seaofnodes.simple.node;
+
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeInteger;
-import java.util.BitSet;
public class AndNode extends Node {
public AndNode(Node lhs, Node rhs) { super(null, lhs, rhs); }
@Override public String label() { return "And"; }
- @Override
- StringBuilder _print1(StringBuilder sb, BitSet visited) {
- in(1)._print0(sb.append("("), visited);
- in(2)._print0(sb.append("&"), visited);
- return sb.append(")");
- }
+ @Override protected String format() { return "(%1&%2)"; }
@Override
public Type compute() {
diff --git a/chapter14/src/main/java/com/seaofnodes/simple/node/BoolNode.java b/chapter14/src/main/java/com/seaofnodes/simple/node/BoolNode.java
index b504712f..8a25e8d9 100644
--- a/chapter14/src/main/java/com/seaofnodes/simple/node/BoolNode.java
+++ b/chapter14/src/main/java/com/seaofnodes/simple/node/BoolNode.java
@@ -1,5 +1,7 @@
package com.seaofnodes.simple.node;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.Parser;
import com.seaofnodes.simple.Utils;
import com.seaofnodes.simple.type.Type;
@@ -7,7 +9,6 @@ import com.seaofnodes.simple.type.TypeInteger;
import com.seaofnodes.simple.type.TypeFloat;
import com.seaofnodes.simple.type.TypeMemPtr;
-import java.util.BitSet;
import static com.seaofnodes.simple.type.TypeInteger.*;
abstract public class BoolNode extends Node {
@@ -21,11 +22,8 @@ abstract public class BoolNode extends Node {
@Override
public String label() { return getClass().getSimpleName(); }
- @Override
- 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/chapter14/src/main/java/com/seaofnodes/simple/node/CProjNode.java b/chapter14/src/main/java/com/seaofnodes/simple/node/CProjNode.java
index fb0ff879..ff5d1a76 100644
--- a/chapter14/src/main/java/com/seaofnodes/simple/node/CProjNode.java
+++ b/chapter14/src/main/java/com/seaofnodes/simple/node/CProjNode.java
@@ -1,10 +1,11 @@
package com.seaofnodes.simple.node;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.Parser;
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeMem;
import com.seaofnodes.simple.type.TypeTuple;
-import java.util.BitSet;
public class CProjNode extends CFGNode {
@@ -22,7 +23,7 @@ public class CProjNode extends CFGNode {
@Override public String label() { return _label; }
- @Override 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 isMultiTail() { return in(0).isMultiHead(); }
@Override public boolean blockHead() { return true; }
diff --git a/chapter14/src/main/java/com/seaofnodes/simple/node/CastNode.java b/chapter14/src/main/java/com/seaofnodes/simple/node/CastNode.java
index 38d6a126..9ade5a50 100644
--- a/chapter14/src/main/java/com/seaofnodes/simple/node/CastNode.java
+++ b/chapter14/src/main/java/com/seaofnodes/simple/node/CastNode.java
@@ -1,10 +1,11 @@
package com.seaofnodes.simple.node;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeInteger;
import com.seaofnodes.simple.IterPeeps;
-import java.util.BitSet;
// Upcast (join) the input to a t. Used after guard test to lift an input.
// Can also be used to make a type-assertion if ctrl is null.
@@ -18,13 +19,10 @@ public class CastNode extends Node {
@Override public String label() { return "("+_t.str()+")"; }
- @Override
- public String uniqueName() { return "Cast_" + _nid; }
- @Override
- StringBuilder _print1(StringBuilder sb, BitSet visited) {
- return in(1)._print0(sb.append(label()), visited);
+ @Override protected ExprPrinter<Node> _print1(ExprPrinter<Node> p) {
+ return p.p(label()).n(in(1));
}
@Override
diff --git a/chapter14/src/main/java/com/seaofnodes/simple/node/ConstantNode.java b/chapter14/src/main/java/com/seaofnodes/simple/node/ConstantNode.java
index 37a529d1..9ecd1152 100644
--- a/chapter14/src/main/java/com/seaofnodes/simple/node/ConstantNode.java
+++ b/chapter14/src/main/java/com/seaofnodes/simple/node/ConstantNode.java
@@ -1,9 +1,10 @@
package com.seaofnodes.simple.node;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.Parser;
import com.seaofnodes.simple.type.Type;
-import java.util.BitSet;
/**
* A Constant node represents a constant value. At present, the only constants
@@ -24,15 +25,16 @@ public class ConstantNode extends Node {
_con = type;
}
- @Override
- public String label() { return "#"+_con; }
+ @Override protected String repeatName() {
+ return _con==null || _con.toString().length()<=32 ? null : uniqueName();
+ }
@Override
- public String uniqueName() { return "Con_" + _nid; }
+ public String label() { return "Con"; }
- @Override
- StringBuilder _print1(StringBuilder sb, BitSet visited) {
- return _con.print(sb);
+
+ @Override protected ExprPrinter<Node> _print1(ExprPrinter<Node> p) {
+ return p.p(_con);
}
@Override public boolean isMultiTail() { return true; }
diff --git a/chapter14/src/main/java/com/seaofnodes/simple/node/DivFNode.java b/chapter14/src/main/java/com/seaofnodes/simple/node/DivFNode.java
index 6c0c2eb3..a3f4318d 100644
--- a/chapter14/src/main/java/com/seaofnodes/simple/node/DivFNode.java
+++ b/chapter14/src/main/java/com/seaofnodes/simple/node/DivFNode.java
@@ -1,21 +1,16 @@
package com.seaofnodes.simple.node;
+
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeFloat;
-import java.util.BitSet;
public class DivFNode extends Node {
public DivFNode(Node lhs, Node rhs) { super(null, lhs, rhs); }
@Override public String label() { return "DivF"; }
- @Override
- StringBuilder _print1(StringBuilder sb, BitSet visited) {
- in(1)._print0(sb.append("("), visited);
- in(2)._print0(sb.append("/"), visited);
- return sb.append(")");
- }
+ @Override protected String format() { return "(%1/%2)"; }
@Override
public Type compute() {
diff --git a/chapter14/src/main/java/com/seaofnodes/simple/node/DivNode.java b/chapter14/src/main/java/com/seaofnodes/simple/node/DivNode.java
index fd5fd1ed..5c7ba42c 100644
--- a/chapter14/src/main/java/com/seaofnodes/simple/node/DivNode.java
+++ b/chapter14/src/main/java/com/seaofnodes/simple/node/DivNode.java
@@ -1,21 +1,16 @@
package com.seaofnodes.simple.node;
+
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeInteger;
-import java.util.BitSet;
public class DivNode extends Node {
public DivNode(Node lhs, Node rhs) { super(null, lhs, rhs); }
@Override public String label() { return "Div"; }
- @Override
- StringBuilder _print1(StringBuilder sb, BitSet visited) {
- in(1)._print0(sb.append("("), visited);
- in(2)._print0(sb.append("/"), visited);
- return sb.append(")");
- }
+ @Override protected String format() { return "(%1/%2)"; }
@Override
public Type compute() {
diff --git a/chapter14/src/main/java/com/seaofnodes/simple/node/IfNode.java b/chapter14/src/main/java/com/seaofnodes/simple/node/IfNode.java
index 5457ac6e..70340f7f 100644
--- a/chapter14/src/main/java/com/seaofnodes/simple/node/IfNode.java
+++ b/chapter14/src/main/java/com/seaofnodes/simple/node/IfNode.java
@@ -1,5 +1,6 @@
package com.seaofnodes.simple.node;
+
import com.seaofnodes.simple.IterPeeps;
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeInteger;
@@ -17,11 +18,7 @@ public class IfNode extends CFGNode implements MultiNode {
@Override
public String label() { return "If"; }
- @Override
- StringBuilder _print1(StringBuilder sb, BitSet visited) {
- sb.append("if( ");
- return in(1)._print0(sb, visited).append(" )");
- }
+ @Override protected String format() { return "if( %1 )"; }
@Override public boolean isMultiHead() { return true; }
diff --git a/chapter14/src/main/java/com/seaofnodes/simple/node/LoadNode.java b/chapter14/src/main/java/com/seaofnodes/simple/node/LoadNode.java
index 5cd39a33..3191061c 100644
--- a/chapter14/src/main/java/com/seaofnodes/simple/node/LoadNode.java
+++ b/chapter14/src/main/java/com/seaofnodes/simple/node/LoadNode.java
@@ -1,10 +1,11 @@
package com.seaofnodes.simple.node;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.Utils;
import com.seaofnodes.simple.IterPeeps;
import com.seaofnodes.simple.type.Type;
-import java.util.BitSet;
/**
* Load represents extracting a value from inside a memory object,
@@ -43,7 +44,7 @@ public class LoadNode extends MemOpNode {
@Override public String label() { return _name; }
@Override
- 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/chapter14/src/main/java/com/seaofnodes/simple/node/MemMergeNode.java b/chapter14/src/main/java/com/seaofnodes/simple/node/MemMergeNode.java
index d7fed402..f3d5b01e 100644
--- a/chapter14/src/main/java/com/seaofnodes/simple/node/MemMergeNode.java
+++ b/chapter14/src/main/java/com/seaofnodes/simple/node/MemMergeNode.java
@@ -1,9 +1,10 @@
package com.seaofnodes.simple.node;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.IterPeeps;
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeMem;
-import java.util.BitSet;
/** All memory: a default slice and explicit overrides for individual aliases. */
public class MemMergeNode extends Node {
@@ -28,14 +29,14 @@ public class MemMergeNode extends Node {
@Override public String label() { return "MemMerge"; }
@Override public boolean isMem() { return true; }
@Override public Type compute() { return TypeMem.BOT; }
- @Override StringBuilder _print1(StringBuilder sb, BitSet visited) {
- sb.append("MEM[");
+ @Override protected ExprPrinter<Node> _print1(ExprPrinter<Node> p) {
+ p.p("MEM[");
for( int i=1; i<nIns(); i++ )
if( in(i)!=null ) {
- sb.append(i==1 ? "default:" : i+":");
- in(i)._print0(sb,visited).append(" ");
+ p.p(i==1 ? "default:" : i+":");
+ p.n(in(i)).p(" ");
}
- return sb.append("]");
+ return p.p("]");
}
@Override public Node idealize() {
diff --git a/chapter14/src/main/java/com/seaofnodes/simple/node/MinusFNode.java b/chapter14/src/main/java/com/seaofnodes/simple/node/MinusFNode.java
index 7cacf2c9..1b45c7c5 100644
--- a/chapter14/src/main/java/com/seaofnodes/simple/node/MinusFNode.java
+++ b/chapter14/src/main/java/com/seaofnodes/simple/node/MinusFNode.java
@@ -1,20 +1,16 @@
package com.seaofnodes.simple.node;
+
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeFloat;
-import java.util.BitSet;
public class MinusFNode extends Node {
public MinusFNode(Node in) { super(null, in); }
@Override public String label() { return "MinusF"; }
- @Override
- 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/chapter14/src/main/java/com/seaofnodes/simple/node/MinusNode.java b/chapter14/src/main/java/com/seaofnodes/simple/node/MinusNode.java
index 176d2a3d..f56c423e 100644
--- a/chapter14/src/main/java/com/seaofnodes/simple/node/MinusNode.java
+++ b/chapter14/src/main/java/com/seaofnodes/simple/node/MinusNode.java
@@ -1,20 +1,16 @@
package com.seaofnodes.simple.node;
+
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeInteger;
-import java.util.BitSet;
public class MinusNode extends Node {
public MinusNode(Node in) { super(null, in); }
@Override public String label() { return "Minus"; }
- @Override
- 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/chapter14/src/main/java/com/seaofnodes/simple/node/MulFNode.java b/chapter14/src/main/java/com/seaofnodes/simple/node/MulFNode.java
index 4b753ba7..6a57f3c5 100644
--- a/chapter14/src/main/java/com/seaofnodes/simple/node/MulFNode.java
+++ b/chapter14/src/main/java/com/seaofnodes/simple/node/MulFNode.java
@@ -1,21 +1,16 @@
package com.seaofnodes.simple.node;
+
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeFloat;
-import java.util.BitSet;
public class MulFNode extends Node {
public MulFNode(Node lhs, Node rhs) { super(null, lhs, rhs); }
@Override public String label() { return "MulF"; }
- @Override
- StringBuilder _print1(StringBuilder sb, BitSet visited) {
- in(1)._print0(sb.append("("), visited);
- in(2)._print0(sb.append("*"), visited);
- return sb.append(")");
- }
+ @Override protected String format() { return "(%1*%2)"; }
@Override
public Type compute() {
diff --git a/chapter14/src/main/java/com/seaofnodes/simple/node/MulNode.java b/chapter14/src/main/java/com/seaofnodes/simple/node/MulNode.java
index f521f2ce..b403c2bf 100644
--- a/chapter14/src/main/java/com/seaofnodes/simple/node/MulNode.java
+++ b/chapter14/src/main/java/com/seaofnodes/simple/node/MulNode.java
@@ -1,21 +1,16 @@
package com.seaofnodes.simple.node;
+
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeInteger;
-import java.util.BitSet;
public class MulNode extends Node {
public MulNode(Node lhs, Node rhs) { super(null, lhs, rhs); }
@Override public String label() { return "Mul"; }
- @Override
- StringBuilder _print1(StringBuilder sb, BitSet visited) {
- in(1)._print0(sb.append("("), visited);
- in(2)._print0(sb.append("*"), visited);
- return sb.append(")");
- }
+ @Override protected String format() { return "(%1*%2)"; }
@Override
public Type compute() {
diff --git a/chapter14/src/main/java/com/seaofnodes/simple/node/NeverNode.java b/chapter14/src/main/java/com/seaofnodes/simple/node/NeverNode.java
index e77ed653..7e42ccf9 100644
--- a/chapter14/src/main/java/com/seaofnodes/simple/node/NeverNode.java
+++ b/chapter14/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 {
@@ -13,7 +14,7 @@ public class NeverNode extends IfNode {
@Override public String label() { return "Never"; }
- @Override 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/chapter14/src/main/java/com/seaofnodes/simple/node/NewNode.java b/chapter14/src/main/java/com/seaofnodes/simple/node/NewNode.java
index 1c82d5f5..74ba5184 100644
--- a/chapter14/src/main/java/com/seaofnodes/simple/node/NewNode.java
+++ b/chapter14/src/main/java/com/seaofnodes/simple/node/NewNode.java
@@ -1,9 +1,10 @@
package com.seaofnodes.simple.node;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeMemPtr;
-import java.util.BitSet;
public class NewNode extends Node {
@@ -17,10 +18,8 @@ public class NewNode extends Node {
@Override
public String label() { return "new"; }
- @Override
- StringBuilder _print1(StringBuilder sb, BitSet visited) {
- sb.append("new ");
- return sb.append(_ptr._obj.str());
+ @Override protected ExprPrinter<Node> _print1(ExprPrinter<Node> p) {
+ return p.p("new ").p(_ptr._obj.str());
}
diff --git a/chapter14/src/main/java/com/seaofnodes/simple/node/Node.java b/chapter14/src/main/java/com/seaofnodes/simple/node/Node.java
index 61679fa4..4ee82187 100644
--- a/chapter14/src/main/java/com/seaofnodes/simple/node/Node.java
+++ b/chapter14/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.Parser;
import com.seaofnodes.simple.IRPrinter;
@@ -16,14 +18,7 @@ import java.util.function.Function;
* The Node class provides common functionality used by all subtypes.
* Subtypes of Node specialize by overriding methods.
*/
-public abstract class Node implements OutNode, 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 OutNode, Cloneable {
/**
* Inputs to the node. These are use-def references to Nodes.
@@ -45,14 +40,12 @@ public abstract class Node implements OutNode, Cloneable {
*/
public ArrayList<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;
-
/**
* A private Global Static mutable counter, for unique node id generation.
* To make the compiler multithreaded, this field will have to move into a TLS.
@@ -62,7 +55,7 @@ public abstract class Node implements OutNode, Cloneable {
public static int UID() { return UNIQUE_ID; }
protected Node(Node... inputs) {
- _nid = UNIQUE_ID++; // allocate unique dense ID
+ super(UNIQUE_ID++); // allocate unique dense ID
_inputs = new ArrayList<>();
Collections.addAll(_inputs,inputs);
_outputs = new ArrayList<>();
@@ -74,40 +67,6 @@ public abstract class Node implements OutNode, Cloneable {
// Easy reading label for debugger, e.g. "Add" or "Region" or "EQ"
public abstract String label();
- // Unique label for debugging, e.g. "Add12" or "Region30" or "EQ99"
- public String uniqueName() {
- return label() + _nid;
- }
-
- // ------------------------------------------------------------------------
-
- // 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 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.
- 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 StringBuilder _print1(StringBuilder sb, BitSet visited);
-
public String p(int depth) { return IRPrinter.prettyPrint(this,depth); }
public boolean isMultiHead() { return false; }
@@ -116,6 +75,8 @@ public abstract class Node implements OutNode, 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
@@ -256,7 +217,6 @@ public abstract class Node implements OutNode, Cloneable {
// Test "keep" status
public boolean iskeep() { return Utils.find(_outputs,null) != -1; }
-
// Replace self with nnn in the graph, making 'this' go dead
public void subsume( Node nnn ) {
assert nnn!=this;
@@ -387,7 +347,6 @@ public abstract class Node implements OutNode, Cloneable {
return old;
}
-
/**
* This function rewrites the current Node into a more "idealized" form.
* This is the bulk of our peephole rewrite rules, and we use this to
@@ -435,7 +394,6 @@ public abstract class Node implements OutNode, 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
@@ -479,7 +437,6 @@ public abstract class Node implements OutNode, Cloneable {
_deps.clear();
}
-
// Global Value Numbering. Hash over opcode and inputs; hits in this table
// are structurally equal.
public static final HashMap<Node,Node> GVN = new HashMap<>();
@@ -501,7 +458,6 @@ public abstract class Node implements OutNode, Cloneable {
// and can assume "this!=n" and has the same Java class.
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
@@ -517,7 +473,6 @@ public abstract class Node implements OutNode, Cloneable {
_hash=0; // Out of table now
}
-
// Hash of opcode and inputs
@Override public final int hashCode() {
if( _hash != 0 ) return _hash;
@@ -535,7 +490,6 @@ public abstract class Node implements OutNode, Cloneable {
//
/** Is this Node control-flow-graph related */
- public boolean isCFG() { return false; }
/** Is this Node Memory related */
public boolean isMem() { return false; }
@@ -543,7 +497,6 @@ public abstract class Node implements OutNode, Cloneable {
/** Return block start from a isCFG() */
public Node getBlockStart() { return null; }
-
// Semantic change to the graph (so NOT a peephole), used by the Parser.
// If any input is a float, flip to a float-flavored opcode and widen any
// non-float input.
@@ -564,7 +517,6 @@ public abstract class Node implements OutNode, Cloneable {
}
Node copyF() { return null; }
-
// ------------------------------------------------------------------------
// Peephole utilities
@@ -593,7 +545,6 @@ public abstract class Node implements OutNode, 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.
@@ -626,7 +577,6 @@ public abstract class Node implements OutNode, Cloneable {
ITER_CNT = ITER_NOP_CNT = 0;
}
-
// Utility to walk the entire graph applying a function; return the first
// not-null result.
private static final BitSet WVISIT = new BitSet();
diff --git a/chapter14/src/main/java/com/seaofnodes/simple/node/NotNode.java b/chapter14/src/main/java/com/seaofnodes/simple/node/NotNode.java
index 17b6e46e..2e89f013 100644
--- a/chapter14/src/main/java/com/seaofnodes/simple/node/NotNode.java
+++ b/chapter14/src/main/java/com/seaofnodes/simple/node/NotNode.java
@@ -1,19 +1,15 @@
package com.seaofnodes.simple.node;
+
import com.seaofnodes.simple.Utils;
import com.seaofnodes.simple.type.*;
-import java.util.BitSet;
public class NotNode extends Node {
public NotNode(Node in) { super(null, in); }
@Override public String label() { return "Not"; }
- @Override
- 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/chapter14/src/main/java/com/seaofnodes/simple/node/OrNode.java b/chapter14/src/main/java/com/seaofnodes/simple/node/OrNode.java
index fd5be78e..4088fde6 100644
--- a/chapter14/src/main/java/com/seaofnodes/simple/node/OrNode.java
+++ b/chapter14/src/main/java/com/seaofnodes/simple/node/OrNode.java
@@ -1,21 +1,16 @@
package com.seaofnodes.simple.node;
+
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeInteger;
-import java.util.BitSet;
public class OrNode extends Node {
public OrNode(Node lhs, Node rhs) { super(null, lhs, rhs); }
@Override public String label() { return "Or"; }
- @Override
- StringBuilder _print1(StringBuilder sb, BitSet visited) {
- in(1)._print0(sb.append("("), visited);
- in(2)._print0(sb.append("|"), visited);
- return sb.append(")");
- }
+ @Override protected String format() { return "(%1|%2)"; }
@Override
public Type compute() {
diff --git a/chapter14/src/main/java/com/seaofnodes/simple/node/PhiNode.java b/chapter14/src/main/java/com/seaofnodes/simple/node/PhiNode.java
index 0f8b06f5..309cd8b5 100644
--- a/chapter14/src/main/java/com/seaofnodes/simple/node/PhiNode.java
+++ b/chapter14/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.type.Type;
import com.seaofnodes.simple.type.TypeMem;
import com.seaofnodes.simple.Utils;
-import java.util.BitSet;
public class PhiNode extends Node {
@@ -23,18 +24,12 @@ public class PhiNode extends Node {
@Override public String label() { return "Phi_"+_label; }
@Override
- 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/chapter14/src/main/java/com/seaofnodes/simple/node/ProjNode.java b/chapter14/src/main/java/com/seaofnodes/simple/node/ProjNode.java
index 93239a61..e82c69b3 100644
--- a/chapter14/src/main/java/com/seaofnodes/simple/node/ProjNode.java
+++ b/chapter14/src/main/java/com/seaofnodes/simple/node/ProjNode.java
@@ -1,10 +1,11 @@
package com.seaofnodes.simple.node;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeMem;
import com.seaofnodes.simple.type.TypeTuple;
-import java.util.BitSet;
public class ProjNode extends Node {
@@ -24,7 +25,7 @@ public class ProjNode extends Node {
public String label() { return _label; }
@Override
- StringBuilder _print1(StringBuilder sb, BitSet visited) { return sb.append(_label); }
+ protected ExprPrinter<Node> _print1(ExprPrinter<Node> p) { return p.p(_label); }
@Override public boolean isMultiTail() { return in(0).isMultiHead(); }
@Override public boolean isMem() { return _type instanceof TypeMem; }
diff --git a/chapter14/src/main/java/com/seaofnodes/simple/node/RegionNode.java b/chapter14/src/main/java/com/seaofnodes/simple/node/RegionNode.java
index d7e934d7..cdfd10ad 100644
--- a/chapter14/src/main/java/com/seaofnodes/simple/node/RegionNode.java
+++ b/chapter14/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.IterPeeps;
import com.seaofnodes.simple.Parser;
import com.seaofnodes.simple.Utils;
@@ -16,9 +18,8 @@ public class RegionNode extends CFGNode {
@Override
public String label() { return "Region"; }
- @Override
- StringBuilder _print1(StringBuilder sb, BitSet visited) {
- return sb.append(label()).append(_nid);
+ @Override protected ExprPrinter<Node> _print1(ExprPrinter<Node> p) {
+ return p.p(label()).p(_nid);
}
@Override public boolean isMultiHead() { return true; }
diff --git a/chapter14/src/main/java/com/seaofnodes/simple/node/ReturnNode.java b/chapter14/src/main/java/com/seaofnodes/simple/node/ReturnNode.java
index 725c704f..161cc7d6 100644
--- a/chapter14/src/main/java/com/seaofnodes/simple/node/ReturnNode.java
+++ b/chapter14/src/main/java/com/seaofnodes/simple/node/ReturnNode.java
@@ -1,8 +1,9 @@
package com.seaofnodes.simple.node;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.type.*;
-import java.util.BitSet;
/** Keeps all preceding memory effects and the return value alive: {ctrl, $mem, value}. */
public class ReturnNode extends CFGNode {
@@ -20,10 +21,10 @@ public class ReturnNode extends CFGNode {
public String label() { return "Return"; }
@Override
- StringBuilder _print1(StringBuilder sb, BitSet visited) {
- sb.append("return ");
- expr()._print0(sb, visited);
- return sb.append(";");
+ protected ExprPrinter<Node> _print1(ExprPrinter<Node> p) {
+ p.p("return ");
+ p.n(expr());
+ return p.p(";");
}
@Override
diff --git a/chapter14/src/main/java/com/seaofnodes/simple/node/RoundF32Node.java b/chapter14/src/main/java/com/seaofnodes/simple/node/RoundF32Node.java
index 3dd7cbf0..78e7698c 100644
--- a/chapter14/src/main/java/com/seaofnodes/simple/node/RoundF32Node.java
+++ b/chapter14/src/main/java/com/seaofnodes/simple/node/RoundF32Node.java
@@ -1,19 +1,16 @@
package com.seaofnodes.simple.node;
+
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeFloat;
-import java.util.BitSet;
public class RoundF32Node extends Node {
public RoundF32Node(Node lhs) { super(null, lhs); }
@Override public String label() { return "RoundF32"; }
- @Override
- 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/chapter14/src/main/java/com/seaofnodes/simple/node/SarNode.java b/chapter14/src/main/java/com/seaofnodes/simple/node/SarNode.java
index 6436cd64..31d96ada 100644
--- a/chapter14/src/main/java/com/seaofnodes/simple/node/SarNode.java
+++ b/chapter14/src/main/java/com/seaofnodes/simple/node/SarNode.java
@@ -1,21 +1,16 @@
package com.seaofnodes.simple.node;
+
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeInteger;
-import java.util.BitSet;
public class SarNode extends Node {
public SarNode(Node lhs, Node rhs) { super(null, lhs, rhs); }
@Override public String label() { return "Sar"; }
- @Override
- StringBuilder _print1(StringBuilder sb, BitSet visited) {
- in(1)._print0(sb.append("("), visited);
- in(2)._print0(sb.append(">>"), visited);
- return sb.append(")");
- }
+ @Override protected String format() { return "(%1>>%2)"; }
@Override
public Type compute() {
diff --git a/chapter14/src/main/java/com/seaofnodes/simple/node/ScopeNode.java b/chapter14/src/main/java/com/seaofnodes/simple/node/ScopeNode.java
index b931e862..b408eb2f 100644
--- a/chapter14/src/main/java/com/seaofnodes/simple/node/ScopeNode.java
+++ b/chapter14/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.IterPeeps;
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.Utils;
@@ -42,20 +44,19 @@ public class ScopeNode extends Node {
@Override public String label() { return "Scope"; }
@Override
- StringBuilder _print1(StringBuilder sb, BitSet visited) {
- sb.append("Scope[ ");
+ protected ExprPrinter<Node> _print1(ExprPrinter<Node> p) {
+ p.p("Scope[ ");
String[] names = reverseNames();
for( int j=0; j<nIns(); j++ ) {
- sb.append(names[j]).append(":");
+ p.p(names[j]).p(":");
Node n = in(j);
while( n instanceof ScopeNode loop ) {
- sb.append("Lazy_");
+ p.p("Lazy_");
n = loop.in(j);
}
- n._print0(sb, visited).append(" ");
+ p.n(n).p(" ");
}
- sb.setLength(sb.length()-1);
- return sb.append("]");
+ return p.unchar(' ').p("]");
}
/**
diff --git a/chapter14/src/main/java/com/seaofnodes/simple/node/ShlNode.java b/chapter14/src/main/java/com/seaofnodes/simple/node/ShlNode.java
index 1bed5264..98331d08 100644
--- a/chapter14/src/main/java/com/seaofnodes/simple/node/ShlNode.java
+++ b/chapter14/src/main/java/com/seaofnodes/simple/node/ShlNode.java
@@ -1,21 +1,16 @@
package com.seaofnodes.simple.node;
+
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeInteger;
-import java.util.BitSet;
public class ShlNode extends Node {
public ShlNode(Node lhs, Node rhs) { super(null, lhs, rhs); }
@Override public String label() { return "Shl"; }
- @Override
- StringBuilder _print1(StringBuilder sb, BitSet visited) {
- in(1)._print0(sb.append("("), visited);
- in(2)._print0(sb.append("<<"), visited);
- return sb.append(")");
- }
+ @Override protected String format() { return "(%1<<%2)"; }
@Override
public Type compute() {
diff --git a/chapter14/src/main/java/com/seaofnodes/simple/node/ShrNode.java b/chapter14/src/main/java/com/seaofnodes/simple/node/ShrNode.java
index 26442c29..97ffc7cd 100644
--- a/chapter14/src/main/java/com/seaofnodes/simple/node/ShrNode.java
+++ b/chapter14/src/main/java/com/seaofnodes/simple/node/ShrNode.java
@@ -1,21 +1,16 @@
package com.seaofnodes.simple.node;
+
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeInteger;
-import java.util.BitSet;
public class ShrNode extends Node {
public ShrNode(Node lhs, Node rhs) { super(null, lhs, rhs); }
@Override public String label() { return "Shr"; }
- @Override
- StringBuilder _print1(StringBuilder sb, BitSet visited) {
- in(1)._print0(sb.append("("), visited);
- in(2)._print0(sb.append(">>>"), visited);
- return sb.append(")");
- }
+ @Override protected String format() { return "(%1>>>%2)"; }
@Override
public Type compute() {
diff --git a/chapter14/src/main/java/com/seaofnodes/simple/node/StartNode.java b/chapter14/src/main/java/com/seaofnodes/simple/node/StartNode.java
index 2cedf0f6..a5d4923f 100644
--- a/chapter14/src/main/java/com/seaofnodes/simple/node/StartNode.java
+++ b/chapter14/src/main/java/com/seaofnodes/simple/node/StartNode.java
@@ -1,5 +1,7 @@
package com.seaofnodes.simple.node;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.type.*;
import java.util.BitSet;
import java.util.HashSet;
@@ -17,9 +19,8 @@ public class StartNode extends CFGNode implements MultiNode {
@Override
public String label() { return "Start"; }
- @Override
- 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 isMultiHead() { return true; }
diff --git a/chapter14/src/main/java/com/seaofnodes/simple/node/StopNode.java b/chapter14/src/main/java/com/seaofnodes/simple/node/StopNode.java
index af3a9de6..202afbd2 100644
--- a/chapter14/src/main/java/com/seaofnodes/simple/node/StopNode.java
+++ b/chapter14/src/main/java/com/seaofnodes/simple/node/StopNode.java
@@ -1,12 +1,13 @@
package com.seaofnodes.simple.node;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.Parser;
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.IterPeeps;
import com.seaofnodes.simple.GlobalCodeMotion;
-import java.util.BitSet;
public class StopNode extends CFGNode {
@@ -23,12 +24,12 @@ public class StopNode extends CFGNode {
}
@Override
- StringBuilder _print1(StringBuilder sb, BitSet visited) {
- if( ret()!=null ) return ret()._print0(sb, visited);
- sb.append("Stop[ ");
+ protected ExprPrinter<Node> _print1(ExprPrinter<Node> p) {
+ if( ret()!=null ) return p.n(ret());
+ p.p("Stop[ ");
for( Node ret : _inputs )
- ret._print0(sb, visited).append(" ");
- return sb.append("]");
+ p.n(ret).p(" ");
+ return p.p("]");
}
@Override public boolean blockHead() { return true; }
diff --git a/chapter14/src/main/java/com/seaofnodes/simple/node/StoreNode.java b/chapter14/src/main/java/com/seaofnodes/simple/node/StoreNode.java
index 031240ce..e9eaaf2e 100644
--- a/chapter14/src/main/java/com/seaofnodes/simple/node/StoreNode.java
+++ b/chapter14/src/main/java/com/seaofnodes/simple/node/StoreNode.java
@@ -1,10 +1,11 @@
package com.seaofnodes.simple.node;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.Utils;
import com.seaofnodes.simple.IterPeeps;
import com.seaofnodes.simple.type.*;
-import java.util.BitSet;
/**
* Store represents setting a value to a memory based object, in chapter 10
@@ -35,8 +36,8 @@ public class StoreNode extends MemOpNode {
public Node val() { return in(3); }
@Override
- 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/chapter14/src/main/java/com/seaofnodes/simple/node/SubFNode.java b/chapter14/src/main/java/com/seaofnodes/simple/node/SubFNode.java
index 27bbda8d..2d218a03 100644
--- a/chapter14/src/main/java/com/seaofnodes/simple/node/SubFNode.java
+++ b/chapter14/src/main/java/com/seaofnodes/simple/node/SubFNode.java
@@ -1,21 +1,16 @@
package com.seaofnodes.simple.node;
+
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeFloat;
-import java.util.BitSet;
public class SubFNode extends Node {
public SubFNode(Node lhs, Node rhs) { super(null, lhs, rhs); }
@Override public String label() { return "SubF"; }
- @Override
- StringBuilder _print1(StringBuilder sb, BitSet visited) {
- in(1)._print0(sb.append("("), visited);
- in(2)._print0(sb.append("-"), visited);
- return sb.append(")");
- }
+ @Override protected String format() { return "(%1-%2)"; }
@Override
public Type compute() {
diff --git a/chapter14/src/main/java/com/seaofnodes/simple/node/SubNode.java b/chapter14/src/main/java/com/seaofnodes/simple/node/SubNode.java
index 1bae995b..d5e54e73 100644
--- a/chapter14/src/main/java/com/seaofnodes/simple/node/SubNode.java
+++ b/chapter14/src/main/java/com/seaofnodes/simple/node/SubNode.java
@@ -1,22 +1,17 @@
package com.seaofnodes.simple.node;
+
import com.seaofnodes.simple.Parser;
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeInteger;
-import java.util.BitSet;
public class SubNode extends Node {
public SubNode(Node lhs, Node rhs) { super(null, lhs, rhs); }
@Override public String label() { return "Sub"; }
- @Override
- StringBuilder _print1(StringBuilder sb, BitSet visited) {
- in(1)._print0(sb.append("("), visited);
- in(2)._print0(sb.append("-"), visited);
- return sb.append(")");
- }
+ @Override protected String format() { return "(%1-%2)"; }
@Override
public Type compute() {
diff --git a/chapter14/src/main/java/com/seaofnodes/simple/node/ToFloatNode.java b/chapter14/src/main/java/com/seaofnodes/simple/node/ToFloatNode.java
index fde483d6..26cf50e1 100644
--- a/chapter14/src/main/java/com/seaofnodes/simple/node/ToFloatNode.java
+++ b/chapter14/src/main/java/com/seaofnodes/simple/node/ToFloatNode.java
@@ -1,20 +1,17 @@
package com.seaofnodes.simple.node;
+
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeFloat;
import com.seaofnodes.simple.type.TypeInteger;
-import java.util.BitSet;
public class ToFloatNode extends Node {
public ToFloatNode(Node lhs) { super(null, lhs); }
@Override public String label() { return "ToFloat"; }
- @Override
- 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/chapter14/src/main/java/com/seaofnodes/simple/node/XCtrlNode.java b/chapter14/src/main/java/com/seaofnodes/simple/node/XCtrlNode.java
index 83779dd2..056dfba1 100644
--- a/chapter14/src/main/java/com/seaofnodes/simple/node/XCtrlNode.java
+++ b/chapter14/src/main/java/com/seaofnodes/simple/node/XCtrlNode.java
@@ -1,13 +1,14 @@
package com.seaofnodes.simple.node;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.Parser;
import com.seaofnodes.simple.type.Type;
-import java.util.BitSet;
public class XCtrlNode extends CFGNode {
public XCtrlNode( ) { super(Parser.START); }
@Override public String label() { return "Xctrl"; }
- @Override StringBuilder _print1(StringBuilder sb, BitSet visited) { return sb.append("Xctrl"); }
+ @Override protected ExprPrinter<Node> _print1(ExprPrinter<Node> p) { return p.p("Xctrl"); }
@Override public Type compute() { return Type.XCONTROL; }
@Override public Node idealize() { return null; }
}
diff --git a/chapter14/src/main/java/com/seaofnodes/simple/node/XorNode.java b/chapter14/src/main/java/com/seaofnodes/simple/node/XorNode.java
index 6b3bbec5..7490032c 100644
--- a/chapter14/src/main/java/com/seaofnodes/simple/node/XorNode.java
+++ b/chapter14/src/main/java/com/seaofnodes/simple/node/XorNode.java
@@ -1,21 +1,16 @@
package com.seaofnodes.simple.node;
+
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeInteger;
-import java.util.BitSet;
public class XorNode extends Node {
public XorNode(Node lhs, Node rhs) { super(null, lhs, rhs); }
@Override public String label() { return "Xor"; }
- @Override
- StringBuilder _print1(StringBuilder sb, BitSet visited) {
- in(1)._print0(sb.append("("), visited);
- in(2)._print0(sb.append("^"), visited);
- return sb.append(")");
- }
+ @Override protected String format() { return "(%1^%2)"; }
@Override
public Type compute() {
diff --git a/chapter14/src/main/java/com/seaofnodes/simple/print/SimpleGraphAdapter.java b/chapter14/src/main/java/com/seaofnodes/simple/print/SimpleGraphAdapter.java
index 4b1cc065..26897a7c 100644
--- a/chapter14/src/main/java/com/seaofnodes/simple/print/SimpleGraphAdapter.java
+++ b/chapter14/src/main/java/com/seaofnodes/simple/print/SimpleGraphAdapter.java
@@ -1,43 +1,20 @@
package com.seaofnodes.simple.print;
import com.seaofnodes.graph.GraphAdapter;
-import com.seaofnodes.graph.GraphSnapshot;
import com.seaofnodes.graph.GraphSnapshot.*;
import com.seaofnodes.simple.node.*;
import com.seaofnodes.simple.node.Node;
import com.seaofnodes.simple.type.TypeMem;
-import java.util.ArrayList;
/** Chapter 14's view of the IR; browser, transport and layout are shared. */
public class SimpleGraphAdapter extends GraphAdapter<Node> {
- @Override protected boolean dead(Node n) { return n.isDead(); }
- @Override protected int id(Node n) { return n._nid; }
- @Override protected int nIns(Node n) { return n.nIns(); }
- @Override protected Node in(Node n, int idx) { return n.in(idx); }
- @Override protected int nOuts(Node n) { return n.nOuts(); }
- @Override protected Node out(Node n, int idx) { return n.out(idx); }
- @Override protected int nDeps(Node n) { return n.nDeps(); }
- @Override protected Node dep(Node n, int idx) { return n.dep(idx); }
- private ArrayList<Edge> edges(Node n) {
- var edges = new ArrayList<Edge>();
- String[] names = n instanceof ScopeNode scope && n.nIns() != 0 ? scope.reverseNames() : null;
- for( int i = 0; i < n.nIns(); i++ ) {
- String name = names == null || i >= names.length ? null : names[i];
- edges.add(new Edge(i, ref(n.in(i)), role(n, i), name));
- }
- return edges;
+ @Override protected String[] edgeNames(Node n) {
+ return n instanceof ScopeNode scope && n.nIns()!=0 ? scope.reverseNames() : null;
}
+ @Override protected int projectionIndex(Node n) { return n instanceof ProjNode p ? p._idx : n instanceof CProjNode p ? p._idx : -1; }
- @Override protected GraphSnapshot.Node desc(Node n) {
- Projection proj = n instanceof ProjNode p ? new Projection(ref(n.in(0)), p._idx)
- : n instanceof CProjNode p ? new Projection(ref(n.in(0)), p._idx) : null;
- String label = n.label();
- return new GraphSnapshot.Node(n._nid, label == null ? n.getClass().getSimpleName() : label,
- n._type == null ? null : n._type.toString(), kind(n), edges(n), proj);
- }
-
- 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 StartNode ) return Kind.CTRL;
@@ -47,7 +24,7 @@ public class SimpleGraphAdapter extends GraphAdapter<Node> {
return n.isCFG() ? Kind.CTRL : isMem(n) ? Kind.MEM : Kind.DATA;
}
- private Role role(Node n, int i) {
+ @Override protected Role role(Node n, int i) {
if( n instanceof ScopeNode || n instanceof ConstantNode || n instanceof XCtrlNode ) return Role.ASSOC;
if( n instanceof PhiNode ) return i == 0 ? Role.ASSOC : isMem(n) ? Role.MEM : Role.DATA;
if( n instanceof ProjNode || n instanceof CProjNode ) return n.isCFG() ? Role.CTRL : isMem(n) ? Role.MEM : Role.DATA;
diff --git a/chapter15/Makefile b/chapter15/Makefile
index 77df7182..3f1e53ff 100644
--- a/chapter15/Makefile
+++ b/chapter15/Makefile
@@ -37,6 +37,7 @@ main_javas := $(wildcard $(SRC)/$(SIMPLE)/*java $(SRC)/$(SIMPLE)/*/*java)
test_javas := $(wildcard $(TST)/$(SIMPLE)/*java $(TST)/$(SIMPLE)/*/*java)
main_classes := $(patsubst $(SRC)/%java,$(CLZDIR)/main/%class,$(main_javas))
include $(firstword $(wildcard ../graph/graph.mk graph/graph.mk))
+include $(firstword $(wildcard ../print/print.mk print/print.mk))
test_classes := $(patsubst $(TST)/%java,$(CLZDIR)/test/%class,$(test_javas))
test_cp := $(patsubst $(TST)/$(SIMPLE)/%.java,com.seaofnodes.simple.%,$(wildcard $(TST)/$(SIMPLE)/*Test.java))
classes = $(main_classes) $(test_classes)
@@ -54,7 +55,7 @@ endif
default: $(default_targets)
# Compile just the out-of-date files
-$(main_classes): build/classes/main/%class: $(SRC)/%java $(graph_javas)
+$(main_classes): build/classes/main/%class: $(SRC)/%java $(graph_javas) $(print_javas)
@echo "compiling " $@ " because " $?
@[ -d $(CLZDIR)/main ] || mkdir -p $(CLZDIR)/main
@javac $(JAVAC_ARGS) -cp "$(CLZDIR)/main$(SEP)$(jars)" -sourcepath $(SRC) -d $(CLZDIR)/main $(main_javas)
diff --git a/chapter15/pom.xml b/chapter15/pom.xml
index 6e81a91e..8c63b55a 100644
--- a/chapter15/pom.xml
+++ b/chapter15/pom.xml
@@ -13,5 +13,6 @@
<name>Chapter 15</name>
<properties>
<simple.graph.directory>${project.basedir}/../graph</simple.graph.directory>
+ <simple.print.directory>${project.basedir}/../print</simple.print.directory>
</properties>
</project>
diff --git a/chapter15/src/main/java/com/seaofnodes/simple/IRPrinter.java b/chapter15/src/main/java/com/seaofnodes/simple/IRPrinter.java
index bc1e2741..7e93e9da 100644
--- a/chapter15/src/main/java/com/seaofnodes/simple/IRPrinter.java
+++ b/chapter15/src/main/java/com/seaofnodes/simple/IRPrinter.java
@@ -1,306 +1,33 @@
package com.seaofnodes.simple;
+import com.seaofnodes.print.IRAdapter;
import com.seaofnodes.simple.node.*;
-import java.lang.StringBuilder;
-import java.util.ArrayList;
-import java.util.BitSet;
-import java.util.HashMap;
-
-public 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 void _printLine( Node n, StringBuilder sb ) {
- sb.append("%4d %-7.7s ".formatted(n._nid,n.label()));
- if( n.isDead() ) {
- sb.append("DEAD\n");
- return;
- }
- for( Node def : n._inputs )
- sb.append(def==null ? "____ " : "%4d ".formatted(def._nid));
- for( int i = n._inputs.size(); i<4; i++ )
- sb.append(" ");
- sb.append(" [[ ");
- for( Node use : n._outputs )
- sb.append(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.append(" ");
- sb.append(" ]] ");
- if( n._type!= null ) sb.append(n._type.str());
- sb.append("\n");
- }
-
- private static StringBuilder nodeId(StringBuilder sb, Node n) {
- sb.append("%%%d".formatted(n._nid));
- if (n instanceof ProjNode proj) {
- sb.append(".").append(proj._idx);
- }
- return sb;
- }
-
- // Print a node on 1 line, format is inspired by LLVM
- // %id: TYPE = NODE(inputs ....)
- // Nodes as referred to as %id
- public static void _printLineLlvmFormat( Node n, StringBuilder sb ) {
- nodeId(sb, n).append(": ");
- if( n.isDead() ) {
- sb.append("DEAD\n");
- return;
- }
- if( n._type!= null ) n._type.typeName(sb);
- sb.append(" = ").append( n.label() ).append( "(" );
- for( int i = 0; i < n._inputs.size(); i++ ) {
- Node def = n.in(i);
- if (i > 0)
- sb.append(", ");
- if (def == null) sb.append("_");
- else nodeId(sb, def);
- }
- sb.append(")").append("\n");
- }
-
- public static void printLine( Node n, StringBuilder sb, boolean llvmFormat ) {
- if (llvmFormat) _printLineLlvmFormat( n, sb );
- else _printLine ( n, sb );
- }
-
- public static String prettyPrint(Node node, int depth) {
- return Parser.SCHEDULED
- ? prettyPrintScheduled( node, depth, false )
- : prettyPrint( node, depth, false );
- }
-
- // Another bulk pretty-printer. Makes more effort at basic-block grouping.
- public static String prettyPrint( Node node, int depth, boolean llvmFormat ) {
- // First, a Breadth First Search at a fixed depth.
- BFS bfs = new BFS(node,depth);
- // Convert just that set to a post-order
- ArrayList<Node> rpos = new ArrayList<>();
- BitSet visit = new BitSet();
- for( int i=bfs._lim; i< bfs._bfs.size(); i++ )
- postOrd( bfs._bfs.get(i), rpos, visit, bfs._bs);
- // Reverse the post-order walk
- StringBuilder sb = new StringBuilder();
- boolean gap=false;
- for( int i=rpos.size()-1; i>=0; i-- ) {
- Node n = rpos.get(i);
- if( n instanceof CFGNode || n.isMultiHead() ) {
- if( !gap ) sb.append("\n"); // Blank before multihead
- printLine( n, sb, llvmFormat ); // Print head
- while( --i >= 0 ) {
- Node t = rpos.get(i);
- if( !t.isMultiTail() ) { i++; break; }
- printLine( t, sb, llvmFormat );
- }
- sb.append("\n"); // Blank after multitail
- gap = true;
- } else {
- printLine( n, sb, llvmFormat );
- gap = false;
- }
- }
- return sb.toString();
- }
-
- private static void postOrd(Node n, ArrayList<Node> rpos, BitSet visit, BitSet bfs) {
- if( !bfs.get(n._nid) )
- return; // Not in the BFS visit
- if( visit.get(n._nid) ) return; // Already post-order walked
- visit.set(n._nid);
- // First walk the CFG, then everything
- if( n instanceof CFGNode ) {
- for( Node use : n._outputs )
- if( use instanceof CFGNode && use.nOuts() >= 1 && !(use._outputs.get( 0 ) instanceof LoopNode) )
- postOrd(use, rpos,visit,bfs);
- for( Node use : n._outputs )
- if( use instanceof CFGNode )
- postOrd(use,rpos,visit,bfs);
- }
- for( Node use : n._outputs )
- if( use != null )
- postOrd(use, rpos,visit,bfs);
- // Post-order
- rpos.add(n);
- }
-
- // Breadth-first search, broken out in a class to keep in more independent.
- // Maintains a root-set of Nodes at the limit (or past by 1 if MultiHead).
- public static class BFS {
- // A breadth first search, plus MultiHeads for any MultiTails
- public final ArrayList<Node> _bfs;
- public final BitSet _bs; // Visited members by node id
- public final int _depth; // Depth limit
- public final int _lim; // From here to _bfs._len can be roots for a reverse search
- public BFS( Node base, int d ) {
- _depth = d;
- _bfs = new ArrayList<>();
- _bs = new BitSet();
-
- add(base); // Prime the pump
- int idx=0, lim=1; // Limit is where depth counter changes
- while( idx < _bfs.size() ) { // Ran out of nodes below depth
- Node n = _bfs.get(idx++);
- for( Node def : n._inputs )
- if( def!=null && !_bs.get(def._nid) )
- add(def);
- if( idx==lim ) { // Depth counter changes at limit
- if( --d < 0 )
- break; // Ran out of depth
- lim = _bfs.size(); // New depth limit
- }
- }
- // Toss things past the limit except multi-heads
- while( idx < _bfs.size() ) {
- Node n = _bfs.get(idx);
- if( n.isMultiHead() ) idx++;
- else del(idx);
- }
- // Root set is any node with no inputs in the visited set
- lim = _bfs.size();
- for( int i=_bfs.size()-1; i>=0; i-- )
- if( !any_visited(_bfs.get(i)) )
- swap( i,--lim);
- _lim = lim;
- }
- void swap( int x, int y ) {
- if( x==y ) return;
- Node tx = _bfs.get(x);
- Node ty = _bfs.get(y);
- _bfs.set(x,ty);
- _bfs.set(y,tx);
- }
- void add(Node n) {
- _bfs.add(n);
- _bs.set(n._nid);
- }
- void del(int idx) {
- _bs.clear(_bfs.get(idx)._nid);
- Utils.del(_bfs, idx);
- }
- boolean any_visited( Node n ) {
- for( Node def : n._inputs )
- if( def!=null && _bs.get(def._nid) )
- return true;
- return false;
- }
- }
-
- // Diagnostic block ordering from raw control edges. Do not call idepth():
- // it fills compiler caches (and can walk lazy dominator accessors).
- private static int _idepth(CFGNode cfg, HashMap<Integer,Integer> depths) {
- if( cfg == null || cfg instanceof StartNode ) return 0;
- Integer old = depths.get(cfg._nid);
- if( old != null ) return old;
- depths.put(cfg._nid,0); // Break cycles in partially constructed graphs.
- int d = 0;
- if( cfg instanceof LoopNode ) {
- d = _idepth((CFGNode)cfg.in(1),depths)+1;
- } else if( cfg instanceof RegionNode || cfg instanceof StopNode ) {
- for( Node n : cfg._inputs )
- if( n instanceof CFGNode pred ) d = Math.max(d,_idepth(pred,depths)+1);
- } else if( cfg.in(0) instanceof CFGNode pred ) {
- d = _idepth(pred,depths)+1;
- }
- depths.put(cfg._nid,d);
- return d;
- }
-
- // Bulk pretty printer, knowing scheduling information is available
- public static String prettyPrintScheduled( Node node, int depth, boolean llvmFormat ) {
- // Backwards DFS walk to depth.
- HashMap<Integer,Integer> ds = new HashMap<>();
- ArrayList<Node> ns = new ArrayList<>();
- _walk(ds,ns,node,depth);
- // Remove data projections, these are force-printed behind their multinode head
- for( int i=0; i<ns.size(); i++ ) {
- if( ns.get(i) instanceof ProjNode proj && !(proj.in(0) instanceof CFGNode) ) {
- Utils.del(ns,i--);
- ds.remove(proj._nid);
- }
- }
- // Print by block with least diagnostic depth
- HashMap<Integer,Integer> depths = new HashMap<>();
- StringBuilder sb = new StringBuilder();
- ArrayList<Node> bns = new ArrayList<>();
- while( !ds.isEmpty() ) {
- CFGNode blk = null;
- for( Node n : ns ) {
- CFGNode cfg = n instanceof CFGNode cfg0 && cfg0.blockHead() ? cfg0 : n.cfg0();
- if( blk==null || _idepth(cfg,depths) < _idepth(blk,depths) )
- blk = cfg;
- }
- ds.remove(blk._nid);
- ns.remove(blk);
-
- // Print block header
- sb.append("%-13.13s".formatted(label(blk)+":"));
- sb.append( " ".repeat(4) ).append(" [[ ");
- if( blk instanceof RegionNode || blk instanceof StopNode )
- for( int i=(blk instanceof StopNode ? 0 : 1); i<blk.nIns(); i++ )
- label(sb,blk.cfg(i));
- else if( !(blk instanceof StartNode) )
- label(sb,blk.cfg(0));
- sb.append(" ]] \n");
-
- // Collect block contents that are in the depth limit
- bns.clear();
- int xd = Integer.MAX_VALUE;
- for( Node use : blk._outputs ) {
- Integer i = ds.get(use._nid);
- if( i!=null && !(use instanceof CFGNode cfg && cfg.blockHead()) ) {
- bns.add(use);
- xd = Math.min(xd,i);
- }
- }
- // Print Phis up front, if any
- for( int i=0; i<bns.size(); i++ )
- if( bns.get(i) instanceof PhiNode phi )
- printLine( phi, sb, llvmFormat,bns,i--,ds,ns);
-
- // Print block contents in depth order, bumping depth until whole block printed
- for( ; !bns.isEmpty(); xd++ )
- for( int i=0; i<bns.size(); i++ ) {
- Node n = bns.get(i);
- if( ds.get(n._nid)==xd ) {
- printLine( n, sb, llvmFormat, bns, i--, ds,ns );
- if( n instanceof MultiNode && !(n instanceof CFGNode) ) {
- for( Node use : n._outputs ) {
- printLine(use,sb,llvmFormat,bns,bns.indexOf(use),ds,ns);
- }
- }
- }
- }
- sb.append("\n");
- }
- return sb.toString();
- }
-
- private static void _walk( HashMap<Integer,Integer> ds, ArrayList<Node> ns, Node node, int d ) {
- Integer nd = ds.get(node._nid);
- if( nd!=null && d <= nd ) return; // Been there, done that
- if( ds.put(node._nid,d) == null )
- ns.add(node);
- if( d == 0 ) return; // Depth cutoff
- for( Node def : node._inputs )
- if( def != null )
- _walk(ds,ns,def,d-1);
- }
-
- static String label( CFGNode blk ) {
- if( blk instanceof StartNode ) return "START";
- return (blk instanceof LoopNode ? "LOOP" : "L")+blk._nid;
- }
- static void label( StringBuilder sb, CFGNode blk ) {
- if( !blk.blockHead() ) blk = blk.cfg(0);
- sb.append( "%-9.9s ".formatted( label( blk ) ) );
- }
- static void printLine( Node n, StringBuilder sb, boolean llvmFormat, ArrayList<Node> bns, int i, HashMap<Integer,Integer> ds, ArrayList<Node> ns ) {
- printLine( n, sb, llvmFormat );
- if( i != -1 ) Utils.del(bns,i);
- ds.remove(n._nid);
- ns.remove(n);
- }
+/** 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 String type(Node n) { return n._type==null ? "" : n._type.str(); }
+ @Override public String inputMark(Node n, Node def) { return n instanceof MemMergeNode && def instanceof MemMergeNode ? "^" : " "; }
+ @Override public Kind kind(Node n) {
+ if( n instanceof StartNode ) return Kind.START;
+ if( n instanceof StopNode ) return Kind.STOP;
+ if( n instanceof LoopNode ) return Kind.LOOP;
+ if( n instanceof RegionNode ) return Kind.REGION;
+ if( n instanceof PhiNode ) return Kind.PHI;
+ 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;
+ }
+
+ public static String prettyPrint(Node n, int depth) { return PRINT.prettyPrint(n,depth); }
}
diff --git a/chapter15/src/main/java/com/seaofnodes/simple/node/AddFNode.java b/chapter15/src/main/java/com/seaofnodes/simple/node/AddFNode.java
index 5d0a473a..fd713156 100644
--- a/chapter15/src/main/java/com/seaofnodes/simple/node/AddFNode.java
+++ b/chapter15/src/main/java/com/seaofnodes/simple/node/AddFNode.java
@@ -1,21 +1,16 @@
package com.seaofnodes.simple.node;
+
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeFloat;
-import java.util.BitSet;
public class AddFNode extends Node {
public AddFNode(Node lhs, Node rhs) { super(null, lhs, rhs); }
@Override public String label() { return "AddF"; }
- @Override
- StringBuilder _print1(StringBuilder sb, BitSet visited) {
- in(1)._print0(sb.append("("), visited);
- in(2)._print0(sb.append("+"), visited);
- return sb.append(")");
- }
+ @Override protected String format() { return "(%1+%2)"; }
@Override
public Type compute() {
diff --git a/chapter15/src/main/java/com/seaofnodes/simple/node/AddNode.java b/chapter15/src/main/java/com/seaofnodes/simple/node/AddNode.java
index e0d3d204..b08f749a 100644
--- a/chapter15/src/main/java/com/seaofnodes/simple/node/AddNode.java
+++ b/chapter15/src/main/java/com/seaofnodes/simple/node/AddNode.java
@@ -1,20 +1,15 @@
package com.seaofnodes.simple.node;
+
import com.seaofnodes.simple.type.*;
-import java.util.BitSet;
public class AddNode extends Node {
public AddNode(Node lhs, Node rhs) { super(null, lhs, rhs); }
@Override public String label() { return "Add"; }
- @Override
- StringBuilder _print1(StringBuilder sb, BitSet visited) {
- in(1)._print0(sb.append("("), visited);
- in(2)._print0(sb.append("+"), visited);
- return sb.append(")");
- }
+ @Override protected String format() { return "(%1+%2)"; }
@Override
diff --git a/chapter15/src/main/java/com/seaofnodes/simple/node/AndNode.java b/chapter15/src/main/java/com/seaofnodes/simple/node/AndNode.java
index d431c13e..1f223bcb 100644
--- a/chapter15/src/main/java/com/seaofnodes/simple/node/AndNode.java
+++ b/chapter15/src/main/java/com/seaofnodes/simple/node/AndNode.java
@@ -1,21 +1,16 @@
package com.seaofnodes.simple.node;
+
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeInteger;
-import java.util.BitSet;
public class AndNode extends Node {
public AndNode(Node lhs, Node rhs) { super(null, lhs, rhs); }
@Override public String label() { return "And"; }
- @Override
- StringBuilder _print1(StringBuilder sb, BitSet visited) {
- in(1)._print0(sb.append("("), visited);
- in(2)._print0(sb.append("&"), visited);
- return sb.append(")");
- }
+ @Override protected String format() { return "(%1&%2)"; }
@Override
public Type compute() {
diff --git a/chapter15/src/main/java/com/seaofnodes/simple/node/BoolNode.java b/chapter15/src/main/java/com/seaofnodes/simple/node/BoolNode.java
index 5d2212b0..6efde623 100644
--- a/chapter15/src/main/java/com/seaofnodes/simple/node/BoolNode.java
+++ b/chapter15/src/main/java/com/seaofnodes/simple/node/BoolNode.java
@@ -1,5 +1,7 @@
package com.seaofnodes.simple.node;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.Parser;
import com.seaofnodes.simple.Utils;
import com.seaofnodes.simple.type.Type;
@@ -7,7 +9,6 @@ import com.seaofnodes.simple.type.TypeInteger;
import com.seaofnodes.simple.type.TypeFloat;
import com.seaofnodes.simple.type.TypeMemPtr;
-import java.util.BitSet;
import static com.seaofnodes.simple.type.TypeInteger.*;
abstract public class BoolNode extends Node {
@@ -21,11 +22,8 @@ abstract public class BoolNode extends Node {
@Override
public String label() { return getClass().getSimpleName(); }
- @Override
- 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/chapter15/src/main/java/com/seaofnodes/simple/node/CProjNode.java b/chapter15/src/main/java/com/seaofnodes/simple/node/CProjNode.java
index 3d6fd1fa..cba63db8 100644
--- a/chapter15/src/main/java/com/seaofnodes/simple/node/CProjNode.java
+++ b/chapter15/src/main/java/com/seaofnodes/simple/node/CProjNode.java
@@ -1,10 +1,11 @@
package com.seaofnodes.simple.node;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.Parser;
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeMem;
import com.seaofnodes.simple.type.TypeTuple;
-import java.util.BitSet;
public class CProjNode extends CFGNode {
@@ -22,7 +23,7 @@ public class CProjNode extends CFGNode {
@Override public String label() { return _label; }
- @Override 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 isMultiTail() { return in(0).isMultiHead(); }
@Override public boolean blockHead() { return true; }
diff --git a/chapter15/src/main/java/com/seaofnodes/simple/node/CastNode.java b/chapter15/src/main/java/com/seaofnodes/simple/node/CastNode.java
index 38d6a126..9ade5a50 100644
--- a/chapter15/src/main/java/com/seaofnodes/simple/node/CastNode.java
+++ b/chapter15/src/main/java/com/seaofnodes/simple/node/CastNode.java
@@ -1,10 +1,11 @@
package com.seaofnodes.simple.node;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeInteger;
import com.seaofnodes.simple.IterPeeps;
-import java.util.BitSet;
// Upcast (join) the input to a t. Used after guard test to lift an input.
// Can also be used to make a type-assertion if ctrl is null.
@@ -18,13 +19,10 @@ public class CastNode extends Node {
@Override public String label() { return "("+_t.str()+")"; }
- @Override
- public String uniqueName() { return "Cast_" + _nid; }
- @Override
- StringBuilder _print1(StringBuilder sb, BitSet visited) {
- return in(1)._print0(sb.append(label()), visited);
+ @Override protected ExprPrinter<Node> _print1(ExprPrinter<Node> p) {
+ return p.p(label()).n(in(1));
}
@Override
diff --git a/chapter15/src/main/java/com/seaofnodes/simple/node/ConstantNode.java b/chapter15/src/main/java/com/seaofnodes/simple/node/ConstantNode.java
index d760c0df..426736ed 100644
--- a/chapter15/src/main/java/com/seaofnodes/simple/node/ConstantNode.java
+++ b/chapter15/src/main/java/com/seaofnodes/simple/node/ConstantNode.java
@@ -1,9 +1,10 @@
package com.seaofnodes.simple.node;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.Parser;
import com.seaofnodes.simple.type.Type;
-import java.util.BitSet;
/**
* A Constant node represents a constant value. At present, the only constants
@@ -24,15 +25,16 @@ public class ConstantNode extends Node {
_con = type;
}
- @Override
- public String label() { return "#"+_con; }
+ @Override protected String repeatName() {
+ return _con==null || _con.toString().length()<=32 ? null : uniqueName();
+ }
@Override
- public String uniqueName() { return "Con_" + _nid; }
+ public String label() { return "Con"; }
- @Override
- StringBuilder _print1(StringBuilder sb, BitSet visited) {
- return _con.print(sb);
+
+ @Override protected ExprPrinter<Node> _print1(ExprPrinter<Node> p) {
+ return p.p(_con);
}
@Override public boolean isMultiTail() { return true; }
diff --git a/chapter15/src/main/java/com/seaofnodes/simple/node/DivFNode.java b/chapter15/src/main/java/com/seaofnodes/simple/node/DivFNode.java
index 6c0c2eb3..a3f4318d 100644
--- a/chapter15/src/main/java/com/seaofnodes/simple/node/DivFNode.java
+++ b/chapter15/src/main/java/com/seaofnodes/simple/node/DivFNode.java
@@ -1,21 +1,16 @@
package com.seaofnodes.simple.node;
+
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeFloat;
-import java.util.BitSet;
public class DivFNode extends Node {
public DivFNode(Node lhs, Node rhs) { super(null, lhs, rhs); }
@Override public String label() { return "DivF"; }
- @Override
- StringBuilder _print1(StringBuilder sb, BitSet visited) {
- in(1)._print0(sb.append("("), visited);
- in(2)._print0(sb.append("/"), visited);
- return sb.append(")");
- }
+ @Override protected String format() { return "(%1/%2)"; }
@Override
public Type compute() {
diff --git a/chapter15/src/main/java/com/seaofnodes/simple/node/DivNode.java b/chapter15/src/main/java/com/seaofnodes/simple/node/DivNode.java
index d13dcacf..cd749a03 100644
--- a/chapter15/src/main/java/com/seaofnodes/simple/node/DivNode.java
+++ b/chapter15/src/main/java/com/seaofnodes/simple/node/DivNode.java
@@ -1,21 +1,16 @@
package com.seaofnodes.simple.node;
+
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeInteger;
-import java.util.BitSet;
public class DivNode extends Node {
public DivNode(Node lhs, Node rhs) { super(null, lhs, rhs); }
@Override public String label() { return "Div"; }
- @Override
- StringBuilder _print1(StringBuilder sb, BitSet visited) {
- in(1)._print0(sb.append("("), visited);
- in(2)._print0(sb.append("/"), visited);
- return sb.append(")");
- }
+ @Override protected String format() { return "(%1/%2)"; }
@Override
public Type compute() {
diff --git a/chapter15/src/main/java/com/seaofnodes/simple/node/IfNode.java b/chapter15/src/main/java/com/seaofnodes/simple/node/IfNode.java
index 5457ac6e..70340f7f 100644
--- a/chapter15/src/main/java/com/seaofnodes/simple/node/IfNode.java
+++ b/chapter15/src/main/java/com/seaofnodes/simple/node/IfNode.java
@@ -1,5 +1,6 @@
package com.seaofnodes.simple.node;
+
import com.seaofnodes.simple.IterPeeps;
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeInteger;
@@ -17,11 +18,7 @@ public class IfNode extends CFGNode implements MultiNode {
@Override
public String label() { return "If"; }
- @Override
- StringBuilder _print1(StringBuilder sb, BitSet visited) {
- sb.append("if( ");
- return in(1)._print0(sb, visited).append(" )");
- }
+ @Override protected String format() { return "if( %1 )"; }
@Override public boolean isMultiHead() { return true; }
diff --git a/chapter15/src/main/java/com/seaofnodes/simple/node/LoadNode.java b/chapter15/src/main/java/com/seaofnodes/simple/node/LoadNode.java
index 4c2013b9..b0517a4c 100644
--- a/chapter15/src/main/java/com/seaofnodes/simple/node/LoadNode.java
+++ b/chapter15/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.IterPeeps;
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeMem;
@@ -46,7 +48,7 @@ public class LoadNode extends MemOpNode {
// Debugger label
@Override public String label() { return "ld_"+mlabel(); }
@Override
- 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/chapter15/src/main/java/com/seaofnodes/simple/node/MemMergeNode.java b/chapter15/src/main/java/com/seaofnodes/simple/node/MemMergeNode.java
index 22d97dae..a4b105c9 100644
--- a/chapter15/src/main/java/com/seaofnodes/simple/node/MemMergeNode.java
+++ b/chapter15/src/main/java/com/seaofnodes/simple/node/MemMergeNode.java
@@ -1,9 +1,10 @@
package com.seaofnodes.simple.node;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.IterPeeps;
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeMem;
-import java.util.BitSet;
/** A default slice and explicit alias overrides. A null default means partial
* memory: absent aliases are not covered, rather than having unknown contents.
@@ -52,14 +53,14 @@ public class MemMergeNode extends Node {
@Override public String label() { return "MemMerge"; }
@Override public boolean isMem() { return true; }
@Override public Type compute() { return TypeMem.BOT; }
- @Override StringBuilder _print1(StringBuilder sb, BitSet visited) {
- sb.append("MEM[");
+ @Override protected ExprPrinter<Node> _print1(ExprPrinter<Node> p) {
+ p.p("MEM[");
for( int i=1; i<nIns(); i++ )
if( in(i)!=null ) {
- sb.append(i==1 ? "default:" : i+":");
- in(i)._print0(sb,visited).append(" ");
+ p.p(i==1 ? "default:" : i+":");
+ p.n(in(i)).p(" ");
}
- return sb.append("]");
+ return p.p("]");
}
@Override public Node idealize() {
diff --git a/chapter15/src/main/java/com/seaofnodes/simple/node/MinusFNode.java b/chapter15/src/main/java/com/seaofnodes/simple/node/MinusFNode.java
index 7cacf2c9..1b45c7c5 100644
--- a/chapter15/src/main/java/com/seaofnodes/simple/node/MinusFNode.java
+++ b/chapter15/src/main/java/com/seaofnodes/simple/node/MinusFNode.java
@@ -1,20 +1,16 @@
package com.seaofnodes.simple.node;
+
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeFloat;
-import java.util.BitSet;
public class MinusFNode extends Node {
public MinusFNode(Node in) { super(null, in); }
@Override public String label() { return "MinusF"; }
- @Override
- 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/chapter15/src/main/java/com/seaofnodes/simple/node/MinusNode.java b/chapter15/src/main/java/com/seaofnodes/simple/node/MinusNode.java
index 63cfd110..bd8f71ad 100644
--- a/chapter15/src/main/java/com/seaofnodes/simple/node/MinusNode.java
+++ b/chapter15/src/main/java/com/seaofnodes/simple/node/MinusNode.java
@@ -1,20 +1,16 @@
package com.seaofnodes.simple.node;
+
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeInteger;
-import java.util.BitSet;
public class MinusNode extends Node {
public MinusNode(Node in) { super(null, in); }
@Override public String label() { return "Minus"; }
- @Override
- 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/chapter15/src/main/java/com/seaofnodes/simple/node/MulFNode.java b/chapter15/src/main/java/com/seaofnodes/simple/node/MulFNode.java
index 4b753ba7..6a57f3c5 100644
--- a/chapter15/src/main/java/com/seaofnodes/simple/node/MulFNode.java
+++ b/chapter15/src/main/java/com/seaofnodes/simple/node/MulFNode.java
@@ -1,21 +1,16 @@
package com.seaofnodes.simple.node;
+
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeFloat;
-import java.util.BitSet;
public class MulFNode extends Node {
public MulFNode(Node lhs, Node rhs) { super(null, lhs, rhs); }
@Override public String label() { return "MulF"; }
- @Override
- StringBuilder _print1(StringBuilder sb, BitSet visited) {
- in(1)._print0(sb.append("("), visited);
- in(2)._print0(sb.append("*"), visited);
- return sb.append(")");
- }
+ @Override protected String format() { return "(%1*%2)"; }
@Override
public Type compute() {
diff --git a/chapter15/src/main/java/com/seaofnodes/simple/node/MulNode.java b/chapter15/src/main/java/com/seaofnodes/simple/node/MulNode.java
index f521f2ce..b403c2bf 100644
--- a/chapter15/src/main/java/com/seaofnodes/simple/node/MulNode.java
+++ b/chapter15/src/main/java/com/seaofnodes/simple/node/MulNode.java
@@ -1,21 +1,16 @@
package com.seaofnodes.simple.node;
+
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeInteger;
-import java.util.BitSet;
public class MulNode extends Node {
public MulNode(Node lhs, Node rhs) { super(null, lhs, rhs); }
@Override public String label() { return "Mul"; }
- @Override
- StringBuilder _print1(StringBuilder sb, BitSet visited) {
- in(1)._print0(sb.append("("), visited);
- in(2)._print0(sb.append("*"), visited);
- return sb.append(")");
- }
+ @Override protected String format() { return "(%1*%2)"; }
@Override
public Type compute() {
diff --git a/chapter15/src/main/java/com/seaofnodes/simple/node/NeverNode.java b/chapter15/src/main/java/com/seaofnodes/simple/node/NeverNode.java
index e77ed653..7e42ccf9 100644
--- a/chapter15/src/main/java/com/seaofnodes/simple/node/NeverNode.java
+++ b/chapter15/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 {
@@ -13,7 +14,7 @@ public class NeverNode extends IfNode {
@Override public String label() { return "Never"; }
- @Override 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/chapter15/src/main/java/com/seaofnodes/simple/node/NewNode.java b/chapter15/src/main/java/com/seaofnodes/simple/node/NewNode.java
index d5154d90..f92d3cdf 100644
--- a/chapter15/src/main/java/com/seaofnodes/simple/node/NewNode.java
+++ b/chapter15/src/main/java/com/seaofnodes/simple/node/NewNode.java
@@ -1,7 +1,8 @@
package com.seaofnodes.simple.node;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.type.*;
-import java.util.BitSet;
/** Allocate and zero an object. Inputs {ctrl, $mem, size}; results {ptr, $mem}.
* The memory input and result cover only the aliases in the allocated struct.
@@ -31,10 +32,8 @@ public class NewNode extends Node implements MultiNode {
return "new_" + (_ptr._obj.isAry() ? "ary_"+_ptr._obj._fields[1]._type.str() : _ptr._obj.str());
}
- @Override
- StringBuilder _print1(StringBuilder sb, BitSet visited) {
- sb.append("new ");
- return sb.append(_ptr._obj.str());
+ @Override protected ExprPrinter<Node> _print1(ExprPrinter<Node> p) {
+ return p.p("new ").p(_ptr._obj.str());
}
@Override
diff --git a/chapter15/src/main/java/com/seaofnodes/simple/node/Node.java b/chapter15/src/main/java/com/seaofnodes/simple/node/Node.java
index 54fbc68f..541c8eb1 100644
--- a/chapter15/src/main/java/com/seaofnodes/simple/node/Node.java
+++ b/chapter15/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.Parser;
import com.seaofnodes.simple.IRPrinter;
@@ -16,14 +18,7 @@ import java.util.function.Function;
* The Node class provides common functionality used by all subtypes.
* Subtypes of Node specialize by overriding methods.
*/
-public abstract class Node implements OutNode, 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 OutNode, Cloneable {
/**
* Inputs to the node. These are use-def references to Nodes.
@@ -45,14 +40,12 @@ public abstract class Node implements OutNode, Cloneable {
*/
public ArrayList<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;
-
/**
* A private Global Static mutable counter, for unique node id generation.
* To make the compiler multithreaded, this field will have to move into a TLS.
@@ -62,7 +55,7 @@ public abstract class Node implements OutNode, Cloneable {
public static int UID() { return UNIQUE_ID; }
protected Node(Node... inputs) {
- _nid = UNIQUE_ID++; // allocate unique dense ID
+ super(UNIQUE_ID++); // allocate unique dense ID
_inputs = new ArrayList<>();
Collections.addAll(_inputs,inputs);
_outputs = new ArrayList<>();
@@ -74,40 +67,6 @@ public abstract class Node implements OutNode, Cloneable {
// Easy reading label for debugger, e.g. "Add" or "Region" or "EQ"
public abstract String label();
- // Unique label for debugging, e.g. "Add12" or "Region30" or "EQ99"
- public String uniqueName() {
- return label() + _nid;
- }
-
- // ------------------------------------------------------------------------
-
- // 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 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.
- 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 StringBuilder _print1(StringBuilder sb, BitSet visited);
-
public String p(int depth) { return IRPrinter.prettyPrint(this,depth); }
public boolean isMultiHead() { return false; }
@@ -116,6 +75,8 @@ public abstract class Node implements OutNode, 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
@@ -255,7 +216,6 @@ public abstract class Node implements OutNode, Cloneable {
// Test "keep" status
public boolean iskeep() { return Utils.find(_outputs,null) != -1; }
-
// Replace self with nnn in the graph, making 'this' go dead
public void subsume( Node nnn ) {
assert nnn!=this;
@@ -386,7 +346,6 @@ public abstract class Node implements OutNode, Cloneable {
return old;
}
-
/**
* This function rewrites the current Node into a more "idealized" form.
* This is the bulk of our peephole rewrite rules, and we use this to
@@ -434,7 +393,6 @@ public abstract class Node implements OutNode, 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
@@ -478,7 +436,6 @@ public abstract class Node implements OutNode, Cloneable {
_deps.clear();
}
-
// Global Value Numbering. Hash over opcode and inputs; hits in this table
// are structurally equal.
public static final HashMap<Node,Node> GVN = new HashMap<>();
@@ -500,7 +457,6 @@ public abstract class Node implements OutNode, Cloneable {
// and can assume "this!=n" and has the same Java class.
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
@@ -516,7 +472,6 @@ public abstract class Node implements OutNode, Cloneable {
_hash=0; // Out of table now
}
-
// Hash of opcode and inputs
@Override public final int hashCode() {
if( _hash != 0 ) return _hash;
@@ -539,7 +494,6 @@ public abstract class Node implements OutNode, Cloneable {
/** Return block start from a isCFG() */
public Node getBlockStart() { return null; }
-
// Semantic change to the graph (so NOT a peephole), used by the Parser.
// If any input is a float, flip to a float-flavored opcode and widen any
// non-float input.
@@ -560,7 +514,6 @@ public abstract class Node implements OutNode, Cloneable {
}
Node copyF() { return null; }
-
// ------------------------------------------------------------------------
// Peephole utilities
@@ -589,7 +542,6 @@ public abstract class Node implements OutNode, 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.
@@ -622,7 +574,6 @@ public abstract class Node implements OutNode, Cloneable {
ITER_CNT = ITER_NOP_CNT = 0;
}
-
// Utility to walk the entire graph applying a function; return the first
// not-null result.
private static final BitSet WVISIT = new BitSet();
diff --git a/chapter15/src/main/java/com/seaofnodes/simple/node/NotNode.java b/chapter15/src/main/java/com/seaofnodes/simple/node/NotNode.java
index 17b6e46e..2e89f013 100644
--- a/chapter15/src/main/java/com/seaofnodes/simple/node/NotNode.java
+++ b/chapter15/src/main/java/com/seaofnodes/simple/node/NotNode.java
@@ -1,19 +1,15 @@
package com.seaofnodes.simple.node;
+
import com.seaofnodes.simple.Utils;
import com.seaofnodes.simple.type.*;
-import java.util.BitSet;
public class NotNode extends Node {
public NotNode(Node in) { super(null, in); }
@Override public String label() { return "Not"; }
- @Override
- 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/chapter15/src/main/java/com/seaofnodes/simple/node/OrNode.java b/chapter15/src/main/java/com/seaofnodes/simple/node/OrNode.java
index 24f59f20..5badd015 100644
--- a/chapter15/src/main/java/com/seaofnodes/simple/node/OrNode.java
+++ b/chapter15/src/main/java/com/seaofnodes/simple/node/OrNode.java
@@ -1,21 +1,16 @@
package com.seaofnodes.simple.node;
+
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeInteger;
-import java.util.BitSet;
public class OrNode extends Node {
public OrNode(Node lhs, Node rhs) { super(null, lhs, rhs); }
@Override public String label() { return "Or"; }
- @Override
- StringBuilder _print1(StringBuilder sb, BitSet visited) {
- in(1)._print0(sb.append("("), visited);
- in(2)._print0(sb.append("|"), visited);
- return sb.append(")");
- }
+ @Override protected String format() { return "(%1|%2)"; }
@Override
public Type compute() {
diff --git a/chapter15/src/main/java/com/seaofnodes/simple/node/PhiNode.java b/chapter15/src/main/java/com/seaofnodes/simple/node/PhiNode.java
index f92458f1..ea5eeb89 100644
--- a/chapter15/src/main/java/com/seaofnodes/simple/node/PhiNode.java
+++ b/chapter15/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.type.Type;
import com.seaofnodes.simple.type.TypeMem;
import com.seaofnodes.simple.Utils;
-import java.util.BitSet;
public class PhiNode extends Node {
@@ -23,18 +24,12 @@ public class PhiNode extends Node {
@Override public String label() { return "Phi_"+MemOpNode.mlabel(_label); }
@Override
- 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/chapter15/src/main/java/com/seaofnodes/simple/node/ProjNode.java b/chapter15/src/main/java/com/seaofnodes/simple/node/ProjNode.java
index cd57b85c..668e20ad 100644
--- a/chapter15/src/main/java/com/seaofnodes/simple/node/ProjNode.java
+++ b/chapter15/src/main/java/com/seaofnodes/simple/node/ProjNode.java
@@ -1,10 +1,11 @@
package com.seaofnodes.simple.node;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeMem;
import com.seaofnodes.simple.type.TypeTuple;
-import java.util.BitSet;
public class ProjNode extends Node {
@@ -23,7 +24,7 @@ public class ProjNode extends Node {
@Override public String label() { return _label; }
@Override
- StringBuilder _print1(StringBuilder sb, BitSet visited) { return sb.append(_label); }
+ protected ExprPrinter<Node> _print1(ExprPrinter<Node> p) { return p.p(_label); }
@Override public CFGNode cfg0() { return in(0).cfg0(); }
diff --git a/chapter15/src/main/java/com/seaofnodes/simple/node/RegionNode.java b/chapter15/src/main/java/com/seaofnodes/simple/node/RegionNode.java
index e0bee5f4..d4f73ddf 100644
--- a/chapter15/src/main/java/com/seaofnodes/simple/node/RegionNode.java
+++ b/chapter15/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.IterPeeps;
import com.seaofnodes.simple.Parser;
import com.seaofnodes.simple.Utils;
@@ -16,9 +18,8 @@ public class RegionNode extends CFGNode {
@Override
public String label() { return "Region"; }
- @Override
- StringBuilder _print1(StringBuilder sb, BitSet visited) {
- return sb.append(label()).append(_nid);
+ @Override protected ExprPrinter<Node> _print1(ExprPrinter<Node> p) {
+ return p.p(label()).p(_nid);
}
@Override public boolean isMultiHead() { return true; }
diff --git a/chapter15/src/main/java/com/seaofnodes/simple/node/ReturnNode.java b/chapter15/src/main/java/com/seaofnodes/simple/node/ReturnNode.java
index 725c704f..161cc7d6 100644
--- a/chapter15/src/main/java/com/seaofnodes/simple/node/ReturnNode.java
+++ b/chapter15/src/main/java/com/seaofnodes/simple/node/ReturnNode.java
@@ -1,8 +1,9 @@
package com.seaofnodes.simple.node;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.type.*;
-import java.util.BitSet;
/** Keeps all preceding memory effects and the return value alive: {ctrl, $mem, value}. */
public class ReturnNode extends CFGNode {
@@ -20,10 +21,10 @@ public class ReturnNode extends CFGNode {
public String label() { return "Return"; }
@Override
- StringBuilder _print1(StringBuilder sb, BitSet visited) {
- sb.append("return ");
- expr()._print0(sb, visited);
- return sb.append(";");
+ protected ExprPrinter<Node> _print1(ExprPrinter<Node> p) {
+ p.p("return ");
+ p.n(expr());
+ return p.p(";");
}
@Override
diff --git a/chapter15/src/main/java/com/seaofnodes/simple/node/RoundF32Node.java b/chapter15/src/main/java/com/seaofnodes/simple/node/RoundF32Node.java
index 3dd7cbf0..78e7698c 100644
--- a/chapter15/src/main/java/com/seaofnodes/simple/node/RoundF32Node.java
+++ b/chapter15/src/main/java/com/seaofnodes/simple/node/RoundF32Node.java
@@ -1,19 +1,16 @@
package com.seaofnodes.simple.node;
+
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeFloat;
-import java.util.BitSet;
public class RoundF32Node extends Node {
public RoundF32Node(Node lhs) { super(null, lhs); }
@Override public String label() { return "RoundF32"; }
- @Override
- 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/chapter15/src/main/java/com/seaofnodes/simple/node/SarNode.java b/chapter15/src/main/java/com/seaofnodes/simple/node/SarNode.java
index 3143d417..65151598 100644
--- a/chapter15/src/main/java/com/seaofnodes/simple/node/SarNode.java
+++ b/chapter15/src/main/java/com/seaofnodes/simple/node/SarNode.java
@@ -1,21 +1,16 @@
package com.seaofnodes.simple.node;
+
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeInteger;
-import java.util.BitSet;
public class SarNode extends Node {
public SarNode(Node lhs, Node rhs) { super(null, lhs, rhs); }
@Override public String label() { return "Sar"; }
- @Override
- StringBuilder _print1(StringBuilder sb, BitSet visited) {
- in(1)._print0(sb.append("("), visited);
- in(2)._print0(sb.append(">>"), visited);
- return sb.append(")");
- }
+ @Override protected String format() { return "(%1>>%2)"; }
@Override
public Type compute() {
diff --git a/chapter15/src/main/java/com/seaofnodes/simple/node/ScopeNode.java b/chapter15/src/main/java/com/seaofnodes/simple/node/ScopeNode.java
index 957202fd..36a5060b 100644
--- a/chapter15/src/main/java/com/seaofnodes/simple/node/ScopeNode.java
+++ b/chapter15/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.IterPeeps;
import com.seaofnodes.simple.Parser;
import com.seaofnodes.simple.Utils;
@@ -39,20 +41,19 @@ public class ScopeNode extends Node {
@Override public String label() { return "Scope"; }
@Override
- StringBuilder _print1(StringBuilder sb, BitSet visited) {
- sb.append("Scope[ ");
+ protected ExprPrinter<Node> _print1(ExprPrinter<Node> p) {
+ p.p("Scope[ ");
String[] names = reverseNames();
for( int j=0; j<nIns(); j++ ) {
- sb.append(names[j]).append(":");
+ p.p(names[j]).p(":");
Node n = in(j);
while( n instanceof ScopeNode loop ) {
- sb.append("Lazy_");
+ p.p("Lazy_");
n = loop.in(j);
}
- n._print0(sb, visited).append(" ");
+ p.n(n).p(" ");
}
- sb.setLength(sb.length()-1);
- return sb.append("]");
+ return p.unchar(' ').p("]");
}
public Node ctrl() { return in(0); }
diff --git a/chapter15/src/main/java/com/seaofnodes/simple/node/ShlNode.java b/chapter15/src/main/java/com/seaofnodes/simple/node/ShlNode.java
index f4da5576..278c8390 100644
--- a/chapter15/src/main/java/com/seaofnodes/simple/node/ShlNode.java
+++ b/chapter15/src/main/java/com/seaofnodes/simple/node/ShlNode.java
@@ -1,21 +1,16 @@
package com.seaofnodes.simple.node;
+
import com.seaofnodes.simple.Parser;
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeInteger;
-import java.util.BitSet;
public class ShlNode extends Node {
public ShlNode(Node lhs, Node rhs) { super(null, lhs, rhs); }
@Override public String label() { return "Shl"; }
- @Override
- StringBuilder _print1(StringBuilder sb, BitSet visited) {
- in(1)._print0(sb.append("("), visited);
- in(2)._print0(sb.append("<<"), visited);
- return sb.append(")");
- }
+ @Override protected String format() { return "(%1<<%2)"; }
@Override
public Type compute() {
diff --git a/chapter15/src/main/java/com/seaofnodes/simple/node/ShrNode.java b/chapter15/src/main/java/com/seaofnodes/simple/node/ShrNode.java
index ead27fb5..70fd630d 100644
--- a/chapter15/src/main/java/com/seaofnodes/simple/node/ShrNode.java
+++ b/chapter15/src/main/java/com/seaofnodes/simple/node/ShrNode.java
@@ -1,21 +1,16 @@
package com.seaofnodes.simple.node;
+
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeInteger;
-import java.util.BitSet;
public class ShrNode extends Node {
public ShrNode(Node lhs, Node rhs) { super(null, lhs, rhs); }
@Override public String label() { return "Shr"; }
- @Override
- StringBuilder _print1(StringBuilder sb, BitSet visited) {
- in(1)._print0(sb.append("("), visited);
- in(2)._print0(sb.append(">>>"), visited);
- return sb.append(")");
- }
+ @Override protected String format() { return "(%1>>>%2)"; }
@Override
public Type compute() {
diff --git a/chapter15/src/main/java/com/seaofnodes/simple/node/StartNode.java b/chapter15/src/main/java/com/seaofnodes/simple/node/StartNode.java
index eaf00be8..812305d5 100644
--- a/chapter15/src/main/java/com/seaofnodes/simple/node/StartNode.java
+++ b/chapter15/src/main/java/com/seaofnodes/simple/node/StartNode.java
@@ -1,5 +1,7 @@
package com.seaofnodes.simple.node;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.type.*;
import java.util.BitSet;
import java.util.HashSet;
@@ -16,9 +18,8 @@ public class StartNode extends CFGNode implements MultiNode {
@Override public String label() { return "Start"; }
- @Override
- 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 isMultiHead() { return true; }
diff --git a/chapter15/src/main/java/com/seaofnodes/simple/node/StopNode.java b/chapter15/src/main/java/com/seaofnodes/simple/node/StopNode.java
index af3a9de6..202afbd2 100644
--- a/chapter15/src/main/java/com/seaofnodes/simple/node/StopNode.java
+++ b/chapter15/src/main/java/com/seaofnodes/simple/node/StopNode.java
@@ -1,12 +1,13 @@
package com.seaofnodes.simple.node;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.Parser;
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.IterPeeps;
import com.seaofnodes.simple.GlobalCodeMotion;
-import java.util.BitSet;
public class StopNode extends CFGNode {
@@ -23,12 +24,12 @@ public class StopNode extends CFGNode {
}
@Override
- StringBuilder _print1(StringBuilder sb, BitSet visited) {
- if( ret()!=null ) return ret()._print0(sb, visited);
- sb.append("Stop[ ");
+ protected ExprPrinter<Node> _print1(ExprPrinter<Node> p) {
+ if( ret()!=null ) return p.n(ret());
+ p.p("Stop[ ");
for( Node ret : _inputs )
- ret._print0(sb, visited).append(" ");
- return sb.append("]");
+ p.n(ret).p(" ");
+ return p.p("]");
}
@Override public boolean blockHead() { return true; }
diff --git a/chapter15/src/main/java/com/seaofnodes/simple/node/StoreNode.java b/chapter15/src/main/java/com/seaofnodes/simple/node/StoreNode.java
index 5c74fa61..485491c0 100644
--- a/chapter15/src/main/java/com/seaofnodes/simple/node/StoreNode.java
+++ b/chapter15/src/main/java/com/seaofnodes/simple/node/StoreNode.java
@@ -1,10 +1,11 @@
package com.seaofnodes.simple.node;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.Utils;
import com.seaofnodes.simple.IterPeeps;
import com.seaofnodes.simple.type.*;
-import java.util.BitSet;
/**
* Store represents setting a value to a memory based object, in chapter 10
@@ -37,8 +38,8 @@ public class StoreNode extends MemOpNode {
public Node val() { return in(4); }
@Override
- 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/chapter15/src/main/java/com/seaofnodes/simple/node/SubFNode.java b/chapter15/src/main/java/com/seaofnodes/simple/node/SubFNode.java
index 27bbda8d..2d218a03 100644
--- a/chapter15/src/main/java/com/seaofnodes/simple/node/SubFNode.java
+++ b/chapter15/src/main/java/com/seaofnodes/simple/node/SubFNode.java
@@ -1,21 +1,16 @@
package com.seaofnodes.simple.node;
+
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeFloat;
-import java.util.BitSet;
public class SubFNode extends Node {
public SubFNode(Node lhs, Node rhs) { super(null, lhs, rhs); }
@Override public String label() { return "SubF"; }
- @Override
- StringBuilder _print1(StringBuilder sb, BitSet visited) {
- in(1)._print0(sb.append("("), visited);
- in(2)._print0(sb.append("-"), visited);
- return sb.append(")");
- }
+ @Override protected String format() { return "(%1-%2)"; }
@Override
public Type compute() {
diff --git a/chapter15/src/main/java/com/seaofnodes/simple/node/SubNode.java b/chapter15/src/main/java/com/seaofnodes/simple/node/SubNode.java
index 237e40ed..134f7cd6 100644
--- a/chapter15/src/main/java/com/seaofnodes/simple/node/SubNode.java
+++ b/chapter15/src/main/java/com/seaofnodes/simple/node/SubNode.java
@@ -1,22 +1,17 @@
package com.seaofnodes.simple.node;
+
import com.seaofnodes.simple.Parser;
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeInteger;
-import java.util.BitSet;
public class SubNode extends Node {
public SubNode(Node lhs, Node rhs) { super(null, lhs, rhs); }
@Override public String label() { return "Sub"; }
- @Override
- StringBuilder _print1(StringBuilder sb, BitSet visited) {
- in(1)._print0(sb.append("("), visited);
- in(2)._print0(sb.append("-"), visited);
- return sb.append(")");
- }
+ @Override protected String format() { return "(%1-%2)"; }
@Override
public Type compute() {
diff --git a/chapter15/src/main/java/com/seaofnodes/simple/node/ToFloatNode.java b/chapter15/src/main/java/com/seaofnodes/simple/node/ToFloatNode.java
index fde483d6..26cf50e1 100644
--- a/chapter15/src/main/java/com/seaofnodes/simple/node/ToFloatNode.java
+++ b/chapter15/src/main/java/com/seaofnodes/simple/node/ToFloatNode.java
@@ -1,20 +1,17 @@
package com.seaofnodes.simple.node;
+
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeFloat;
import com.seaofnodes.simple.type.TypeInteger;
-import java.util.BitSet;
public class ToFloatNode extends Node {
public ToFloatNode(Node lhs) { super(null, lhs); }
@Override public String label() { return "ToFloat"; }
- @Override
- 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/chapter15/src/main/java/com/seaofnodes/simple/node/XCtrlNode.java b/chapter15/src/main/java/com/seaofnodes/simple/node/XCtrlNode.java
index 83779dd2..056dfba1 100644
--- a/chapter15/src/main/java/com/seaofnodes/simple/node/XCtrlNode.java
+++ b/chapter15/src/main/java/com/seaofnodes/simple/node/XCtrlNode.java
@@ -1,13 +1,14 @@
package com.seaofnodes.simple.node;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.Parser;
import com.seaofnodes.simple.type.Type;
-import java.util.BitSet;
public class XCtrlNode extends CFGNode {
public XCtrlNode( ) { super(Parser.START); }
@Override public String label() { return "Xctrl"; }
- @Override StringBuilder _print1(StringBuilder sb, BitSet visited) { return sb.append("Xctrl"); }
+ @Override protected ExprPrinter<Node> _print1(ExprPrinter<Node> p) { return p.p("Xctrl"); }
@Override public Type compute() { return Type.XCONTROL; }
@Override public Node idealize() { return null; }
}
diff --git a/chapter15/src/main/java/com/seaofnodes/simple/node/XorNode.java b/chapter15/src/main/java/com/seaofnodes/simple/node/XorNode.java
index e4ec1b06..0521cc52 100644
--- a/chapter15/src/main/java/com/seaofnodes/simple/node/XorNode.java
+++ b/chapter15/src/main/java/com/seaofnodes/simple/node/XorNode.java
@@ -1,21 +1,16 @@
package com.seaofnodes.simple.node;
+
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeInteger;
-import java.util.BitSet;
public class XorNode extends Node {
public XorNode(Node lhs, Node rhs) { super(null, lhs, rhs); }
@Override public String label() { return "Xor"; }
- @Override
- StringBuilder _print1(StringBuilder sb, BitSet visited) {
- in(1)._print0(sb.append("("), visited);
- in(2)._print0(sb.append("^"), visited);
- return sb.append(")");
- }
+ @Override protected String format() { return "(%1^%2)"; }
@Override
public Type compute() {
diff --git a/chapter15/src/main/java/com/seaofnodes/simple/print/SimpleGraphAdapter.java b/chapter15/src/main/java/com/seaofnodes/simple/print/SimpleGraphAdapter.java
index 99920d24..e2bf366d 100644
--- a/chapter15/src/main/java/com/seaofnodes/simple/print/SimpleGraphAdapter.java
+++ b/chapter15/src/main/java/com/seaofnodes/simple/print/SimpleGraphAdapter.java
@@ -1,43 +1,20 @@
package com.seaofnodes.simple.print;
import com.seaofnodes.graph.GraphAdapter;
-import com.seaofnodes.graph.GraphSnapshot;
import com.seaofnodes.graph.GraphSnapshot.*;
import com.seaofnodes.simple.node.*;
import com.seaofnodes.simple.node.Node;
import com.seaofnodes.simple.type.TypeMem;
-import java.util.ArrayList;
/** Chapter 15's view of the IR; browser, transport and layout are shared. */
public class SimpleGraphAdapter extends GraphAdapter<Node> {
- @Override protected boolean dead(Node n) { return n.isDead(); }
- @Override protected int id(Node n) { return n._nid; }
- @Override protected int nIns(Node n) { return n.nIns(); }
- @Override protected Node in(Node n, int idx) { return n.in(idx); }
- @Override protected int nOuts(Node n) { return n.nOuts(); }
- @Override protected Node out(Node n, int idx) { return n.out(idx); }
- @Override protected int nDeps(Node n) { return n.nDeps(); }
- @Override protected Node dep(Node n, int idx) { return n.dep(idx); }
- private ArrayList<Edge> edges(Node n) {
- var edges = new ArrayList<Edge>();
- String[] names = n instanceof ScopeNode scope && n.nIns() != 0 ? scope.reverseNames() : null;
- for( int i = 0; i < n.nIns(); i++ ) {
- String name = names == null || i >= names.length ? null : names[i];
- edges.add(new Edge(i, ref(n.in(i)), role(n, i), name));
- }
- return edges;
+ @Override protected String[] edgeNames(Node n) {
+ return n instanceof ScopeNode scope && n.nIns()!=0 ? scope.reverseNames() : null;
}
+ @Override protected int projectionIndex(Node n) { return n instanceof ProjNode p ? p._idx : n instanceof CProjNode p ? p._idx : -1; }
- @Override protected GraphSnapshot.Node desc(Node n) {
- Projection proj = n instanceof ProjNode p ? new Projection(ref(n.in(0)), p._idx)
- : n instanceof CProjNode p ? new Projection(ref(n.in(0)), p._idx) : null;
- String label = n.label();
- return new GraphSnapshot.Node(n._nid, label == null ? n.getClass().getSimpleName() : label,
- n._type == null ? null : n._type.toString(), kind(n), edges(n), proj);
- }
-
- 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 StartNode ) return Kind.CTRL;
@@ -47,7 +24,7 @@ public class SimpleGraphAdapter extends GraphAdapter<Node> {
return n instanceof CFGNode ? Kind.CTRL : isMem(n) ? Kind.MEM : Kind.DATA;
}
- private Role role(Node n, int i) {
+ @Override protected Role role(Node n, int i) {
if( n instanceof ScopeNode || n instanceof ConstantNode || n instanceof XCtrlNode ) return Role.ASSOC;
if( n instanceof PhiNode ) return i == 0 ? Role.ASSOC : isMem(n) ? Role.MEM : Role.DATA;
if( n instanceof ProjNode || n instanceof CProjNode )
diff --git a/chapter16/Makefile b/chapter16/Makefile
index 77df7182..3f1e53ff 100644
--- a/chapter16/Makefile
+++ b/chapter16/Makefile
@@ -37,6 +37,7 @@ main_javas := $(wildcard $(SRC)/$(SIMPLE)/*java $(SRC)/$(SIMPLE)/*/*java)
test_javas := $(wildcard $(TST)/$(SIMPLE)/*java $(TST)/$(SIMPLE)/*/*java)
main_classes := $(patsubst $(SRC)/%java,$(CLZDIR)/main/%class,$(main_javas))
include $(firstword $(wildcard ../graph/graph.mk graph/graph.mk))
+include $(firstword $(wildcard ../print/print.mk print/print.mk))
test_classes := $(patsubst $(TST)/%java,$(CLZDIR)/test/%class,$(test_javas))
test_cp := $(patsubst $(TST)/$(SIMPLE)/%.java,com.seaofnodes.simple.%,$(wildcard $(TST)/$(SIMPLE)/*Test.java))
classes = $(main_classes) $(test_classes)
@@ -54,7 +55,7 @@ endif
default: $(default_targets)
# Compile just the out-of-date files
-$(main_classes): build/classes/main/%class: $(SRC)/%java $(graph_javas)
+$(main_classes): build/classes/main/%class: $(SRC)/%java $(graph_javas) $(print_javas)
@echo "compiling " $@ " because " $?
@[ -d $(CLZDIR)/main ] || mkdir -p $(CLZDIR)/main
@javac $(JAVAC_ARGS) -cp "$(CLZDIR)/main$(SEP)$(jars)" -sourcepath $(SRC) -d $(CLZDIR)/main $(main_javas)
diff --git a/chapter16/pom.xml b/chapter16/pom.xml
index c6541455..37dab089 100644
--- a/chapter16/pom.xml
+++ b/chapter16/pom.xml
@@ -13,5 +13,6 @@
<name>Chapter 16</name>
<properties>
<simple.graph.directory>${project.basedir}/../graph</simple.graph.directory>
+ <simple.print.directory>${project.basedir}/../print</simple.print.directory>
</properties>
</project>
diff --git a/chapter16/src/main/java/com/seaofnodes/simple/IRPrinter.java b/chapter16/src/main/java/com/seaofnodes/simple/IRPrinter.java
index bc1e2741..7e93e9da 100644
--- a/chapter16/src/main/java/com/seaofnodes/simple/IRPrinter.java
+++ b/chapter16/src/main/java/com/seaofnodes/simple/IRPrinter.java
@@ -1,306 +1,33 @@
package com.seaofnodes.simple;
+import com.seaofnodes.print.IRAdapter;
import com.seaofnodes.simple.node.*;
-import java.lang.StringBuilder;
-import java.util.ArrayList;
-import java.util.BitSet;
-import java.util.HashMap;
-
-public 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 void _printLine( Node n, StringBuilder sb ) {
- sb.append("%4d %-7.7s ".formatted(n._nid,n.label()));
- if( n.isDead() ) {
- sb.append("DEAD\n");
- return;
- }
- for( Node def : n._inputs )
- sb.append(def==null ? "____ " : "%4d ".formatted(def._nid));
- for( int i = n._inputs.size(); i<4; i++ )
- sb.append(" ");
- sb.append(" [[ ");
- for( Node use : n._outputs )
- sb.append(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.append(" ");
- sb.append(" ]] ");
- if( n._type!= null ) sb.append(n._type.str());
- sb.append("\n");
- }
-
- private static StringBuilder nodeId(StringBuilder sb, Node n) {
- sb.append("%%%d".formatted(n._nid));
- if (n instanceof ProjNode proj) {
- sb.append(".").append(proj._idx);
- }
- return sb;
- }
-
- // Print a node on 1 line, format is inspired by LLVM
- // %id: TYPE = NODE(inputs ....)
- // Nodes as referred to as %id
- public static void _printLineLlvmFormat( Node n, StringBuilder sb ) {
- nodeId(sb, n).append(": ");
- if( n.isDead() ) {
- sb.append("DEAD\n");
- return;
- }
- if( n._type!= null ) n._type.typeName(sb);
- sb.append(" = ").append( n.label() ).append( "(" );
- for( int i = 0; i < n._inputs.size(); i++ ) {
- Node def = n.in(i);
- if (i > 0)
- sb.append(", ");
- if (def == null) sb.append("_");
- else nodeId(sb, def);
- }
- sb.append(")").append("\n");
- }
-
- public static void printLine( Node n, StringBuilder sb, boolean llvmFormat ) {
- if (llvmFormat) _printLineLlvmFormat( n, sb );
- else _printLine ( n, sb );
- }
-
- public static String prettyPrint(Node node, int depth) {
- return Parser.SCHEDULED
- ? prettyPrintScheduled( node, depth, false )
- : prettyPrint( node, depth, false );
- }
-
- // Another bulk pretty-printer. Makes more effort at basic-block grouping.
- public static String prettyPrint( Node node, int depth, boolean llvmFormat ) {
- // First, a Breadth First Search at a fixed depth.
- BFS bfs = new BFS(node,depth);
- // Convert just that set to a post-order
- ArrayList<Node> rpos = new ArrayList<>();
- BitSet visit = new BitSet();
- for( int i=bfs._lim; i< bfs._bfs.size(); i++ )
- postOrd( bfs._bfs.get(i), rpos, visit, bfs._bs);
- // Reverse the post-order walk
- StringBuilder sb = new StringBuilder();
- boolean gap=false;
- for( int i=rpos.size()-1; i>=0; i-- ) {
- Node n = rpos.get(i);
- if( n instanceof CFGNode || n.isMultiHead() ) {
- if( !gap ) sb.append("\n"); // Blank before multihead
- printLine( n, sb, llvmFormat ); // Print head
- while( --i >= 0 ) {
- Node t = rpos.get(i);
- if( !t.isMultiTail() ) { i++; break; }
- printLine( t, sb, llvmFormat );
- }
- sb.append("\n"); // Blank after multitail
- gap = true;
- } else {
- printLine( n, sb, llvmFormat );
- gap = false;
- }
- }
- return sb.toString();
- }
-
- private static void postOrd(Node n, ArrayList<Node> rpos, BitSet visit, BitSet bfs) {
- if( !bfs.get(n._nid) )
- return; // Not in the BFS visit
- if( visit.get(n._nid) ) return; // Already post-order walked
- visit.set(n._nid);
- // First walk the CFG, then everything
- if( n instanceof CFGNode ) {
- for( Node use : n._outputs )
- if( use instanceof CFGNode && use.nOuts() >= 1 && !(use._outputs.get( 0 ) instanceof LoopNode) )
- postOrd(use, rpos,visit,bfs);
- for( Node use : n._outputs )
- if( use instanceof CFGNode )
- postOrd(use,rpos,visit,bfs);
- }
- for( Node use : n._outputs )
- if( use != null )
- postOrd(use, rpos,visit,bfs);
- // Post-order
- rpos.add(n);
- }
-
- // Breadth-first search, broken out in a class to keep in more independent.
- // Maintains a root-set of Nodes at the limit (or past by 1 if MultiHead).
- public static class BFS {
- // A breadth first search, plus MultiHeads for any MultiTails
- public final ArrayList<Node> _bfs;
- public final BitSet _bs; // Visited members by node id
- public final int _depth; // Depth limit
- public final int _lim; // From here to _bfs._len can be roots for a reverse search
- public BFS( Node base, int d ) {
- _depth = d;
- _bfs = new ArrayList<>();
- _bs = new BitSet();
-
- add(base); // Prime the pump
- int idx=0, lim=1; // Limit is where depth counter changes
- while( idx < _bfs.size() ) { // Ran out of nodes below depth
- Node n = _bfs.get(idx++);
- for( Node def : n._inputs )
- if( def!=null && !_bs.get(def._nid) )
- add(def);
- if( idx==lim ) { // Depth counter changes at limit
- if( --d < 0 )
- break; // Ran out of depth
- lim = _bfs.size(); // New depth limit
- }
- }
- // Toss things past the limit except multi-heads
- while( idx < _bfs.size() ) {
- Node n = _bfs.get(idx);
- if( n.isMultiHead() ) idx++;
- else del(idx);
- }
- // Root set is any node with no inputs in the visited set
- lim = _bfs.size();
- for( int i=_bfs.size()-1; i>=0; i-- )
- if( !any_visited(_bfs.get(i)) )
- swap( i,--lim);
- _lim = lim;
- }
- void swap( int x, int y ) {
- if( x==y ) return;
- Node tx = _bfs.get(x);
- Node ty = _bfs.get(y);
- _bfs.set(x,ty);
- _bfs.set(y,tx);
- }
- void add(Node n) {
- _bfs.add(n);
- _bs.set(n._nid);
- }
- void del(int idx) {
- _bs.clear(_bfs.get(idx)._nid);
- Utils.del(_bfs, idx);
- }
- boolean any_visited( Node n ) {
- for( Node def : n._inputs )
- if( def!=null && _bs.get(def._nid) )
- return true;
- return false;
- }
- }
-
- // Diagnostic block ordering from raw control edges. Do not call idepth():
- // it fills compiler caches (and can walk lazy dominator accessors).
- private static int _idepth(CFGNode cfg, HashMap<Integer,Integer> depths) {
- if( cfg == null || cfg instanceof StartNode ) return 0;
- Integer old = depths.get(cfg._nid);
- if( old != null ) return old;
- depths.put(cfg._nid,0); // Break cycles in partially constructed graphs.
- int d = 0;
- if( cfg instanceof LoopNode ) {
- d = _idepth((CFGNode)cfg.in(1),depths)+1;
- } else if( cfg instanceof RegionNode || cfg instanceof StopNode ) {
- for( Node n : cfg._inputs )
- if( n instanceof CFGNode pred ) d = Math.max(d,_idepth(pred,depths)+1);
- } else if( cfg.in(0) instanceof CFGNode pred ) {
- d = _idepth(pred,depths)+1;
- }
- depths.put(cfg._nid,d);
- return d;
- }
-
- // Bulk pretty printer, knowing scheduling information is available
- public static String prettyPrintScheduled( Node node, int depth, boolean llvmFormat ) {
- // Backwards DFS walk to depth.
- HashMap<Integer,Integer> ds = new HashMap<>();
- ArrayList<Node> ns = new ArrayList<>();
- _walk(ds,ns,node,depth);
- // Remove data projections, these are force-printed behind their multinode head
- for( int i=0; i<ns.size(); i++ ) {
- if( ns.get(i) instanceof ProjNode proj && !(proj.in(0) instanceof CFGNode) ) {
- Utils.del(ns,i--);
- ds.remove(proj._nid);
- }
- }
- // Print by block with least diagnostic depth
- HashMap<Integer,Integer> depths = new HashMap<>();
- StringBuilder sb = new StringBuilder();
- ArrayList<Node> bns = new ArrayList<>();
- while( !ds.isEmpty() ) {
- CFGNode blk = null;
- for( Node n : ns ) {
- CFGNode cfg = n instanceof CFGNode cfg0 && cfg0.blockHead() ? cfg0 : n.cfg0();
- if( blk==null || _idepth(cfg,depths) < _idepth(blk,depths) )
- blk = cfg;
- }
- ds.remove(blk._nid);
- ns.remove(blk);
-
- // Print block header
- sb.append("%-13.13s".formatted(label(blk)+":"));
- sb.append( " ".repeat(4) ).append(" [[ ");
- if( blk instanceof RegionNode || blk instanceof StopNode )
- for( int i=(blk instanceof StopNode ? 0 : 1); i<blk.nIns(); i++ )
- label(sb,blk.cfg(i));
- else if( !(blk instanceof StartNode) )
- label(sb,blk.cfg(0));
- sb.append(" ]] \n");
-
- // Collect block contents that are in the depth limit
- bns.clear();
- int xd = Integer.MAX_VALUE;
- for( Node use : blk._outputs ) {
- Integer i = ds.get(use._nid);
- if( i!=null && !(use instanceof CFGNode cfg && cfg.blockHead()) ) {
- bns.add(use);
- xd = Math.min(xd,i);
- }
- }
- // Print Phis up front, if any
- for( int i=0; i<bns.size(); i++ )
- if( bns.get(i) instanceof PhiNode phi )
- printLine( phi, sb, llvmFormat,bns,i--,ds,ns);
-
- // Print block contents in depth order, bumping depth until whole block printed
- for( ; !bns.isEmpty(); xd++ )
- for( int i=0; i<bns.size(); i++ ) {
- Node n = bns.get(i);
- if( ds.get(n._nid)==xd ) {
- printLine( n, sb, llvmFormat, bns, i--, ds,ns );
- if( n instanceof MultiNode && !(n instanceof CFGNode) ) {
- for( Node use : n._outputs ) {
- printLine(use,sb,llvmFormat,bns,bns.indexOf(use),ds,ns);
- }
- }
- }
- }
- sb.append("\n");
- }
- return sb.toString();
- }
-
- private static void _walk( HashMap<Integer,Integer> ds, ArrayList<Node> ns, Node node, int d ) {
- Integer nd = ds.get(node._nid);
- if( nd!=null && d <= nd ) return; // Been there, done that
- if( ds.put(node._nid,d) == null )
- ns.add(node);
- if( d == 0 ) return; // Depth cutoff
- for( Node def : node._inputs )
- if( def != null )
- _walk(ds,ns,def,d-1);
- }
-
- static String label( CFGNode blk ) {
- if( blk instanceof StartNode ) return "START";
- return (blk instanceof LoopNode ? "LOOP" : "L")+blk._nid;
- }
- static void label( StringBuilder sb, CFGNode blk ) {
- if( !blk.blockHead() ) blk = blk.cfg(0);
- sb.append( "%-9.9s ".formatted( label( blk ) ) );
- }
- static void printLine( Node n, StringBuilder sb, boolean llvmFormat, ArrayList<Node> bns, int i, HashMap<Integer,Integer> ds, ArrayList<Node> ns ) {
- printLine( n, sb, llvmFormat );
- if( i != -1 ) Utils.del(bns,i);
- ds.remove(n._nid);
- ns.remove(n);
- }
+/** 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 String type(Node n) { return n._type==null ? "" : n._type.str(); }
+ @Override public String inputMark(Node n, Node def) { return n instanceof MemMergeNode && def instanceof MemMergeNode ? "^" : " "; }
+ @Override public Kind kind(Node n) {
+ if( n instanceof StartNode ) return Kind.START;
+ if( n instanceof StopNode ) return Kind.STOP;
+ if( n instanceof LoopNode ) return Kind.LOOP;
+ if( n instanceof RegionNode ) return Kind.REGION;
+ if( n instanceof PhiNode ) return Kind.PHI;
+ 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;
+ }
+
+ public static String prettyPrint(Node n, int depth) { return PRINT.prettyPrint(n,depth); }
}
diff --git a/chapter16/src/main/java/com/seaofnodes/simple/node/AddFNode.java b/chapter16/src/main/java/com/seaofnodes/simple/node/AddFNode.java
index 5d0a473a..fd713156 100644
--- a/chapter16/src/main/java/com/seaofnodes/simple/node/AddFNode.java
+++ b/chapter16/src/main/java/com/seaofnodes/simple/node/AddFNode.java
@@ -1,21 +1,16 @@
package com.seaofnodes.simple.node;
+
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeFloat;
-import java.util.BitSet;
public class AddFNode extends Node {
public AddFNode(Node lhs, Node rhs) { super(null, lhs, rhs); }
@Override public String label() { return "AddF"; }
- @Override
- StringBuilder _print1(StringBuilder sb, BitSet visited) {
- in(1)._print0(sb.append("("), visited);
- in(2)._print0(sb.append("+"), visited);
- return sb.append(")");
- }
+ @Override protected String format() { return "(%1+%2)"; }
@Override
public Type compute() {
diff --git a/chapter16/src/main/java/com/seaofnodes/simple/node/AddNode.java b/chapter16/src/main/java/com/seaofnodes/simple/node/AddNode.java
index e0d3d204..b08f749a 100644
--- a/chapter16/src/main/java/com/seaofnodes/simple/node/AddNode.java
+++ b/chapter16/src/main/java/com/seaofnodes/simple/node/AddNode.java
@@ -1,20 +1,15 @@
package com.seaofnodes.simple.node;
+
import com.seaofnodes.simple.type.*;
-import java.util.BitSet;
public class AddNode extends Node {
public AddNode(Node lhs, Node rhs) { super(null, lhs, rhs); }
@Override public String label() { return "Add"; }
- @Override
- StringBuilder _print1(StringBuilder sb, BitSet visited) {
- in(1)._print0(sb.append("("), visited);
- in(2)._print0(sb.append("+"), visited);
- return sb.append(")");
- }
+ @Override protected String format() { return "(%1+%2)"; }
@Override
diff --git a/chapter16/src/main/java/com/seaofnodes/simple/node/AndNode.java b/chapter16/src/main/java/com/seaofnodes/simple/node/AndNode.java
index 8ab44858..bd03d6cb 100644
--- a/chapter16/src/main/java/com/seaofnodes/simple/node/AndNode.java
+++ b/chapter16/src/main/java/com/seaofnodes/simple/node/AndNode.java
@@ -1,21 +1,16 @@
package com.seaofnodes.simple.node;
+
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeInteger;
-import java.util.BitSet;
public class AndNode extends Node {
public AndNode(Node lhs, Node rhs) { super(null, lhs, rhs); }
@Override public String label() { return "And"; }
- @Override
- StringBuilder _print1(StringBuilder sb, BitSet visited) {
- in(1)._print0(sb.append("("), visited);
- in(2)._print0(sb.append("&"), visited);
- return sb.append(")");
- }
+ @Override protected String format() { return "(%1&%2)"; }
@Override
public Type compute() {
diff --git a/chapter16/src/main/java/com/seaofnodes/simple/node/BoolNode.java b/chapter16/src/main/java/com/seaofnodes/simple/node/BoolNode.java
index 5d2212b0..6efde623 100644
--- a/chapter16/src/main/java/com/seaofnodes/simple/node/BoolNode.java
+++ b/chapter16/src/main/java/com/seaofnodes/simple/node/BoolNode.java
@@ -1,5 +1,7 @@
package com.seaofnodes.simple.node;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.Parser;
import com.seaofnodes.simple.Utils;
import com.seaofnodes.simple.type.Type;
@@ -7,7 +9,6 @@ import com.seaofnodes.simple.type.TypeInteger;
import com.seaofnodes.simple.type.TypeFloat;
import com.seaofnodes.simple.type.TypeMemPtr;
-import java.util.BitSet;
import static com.seaofnodes.simple.type.TypeInteger.*;
abstract public class BoolNode extends Node {
@@ -21,11 +22,8 @@ abstract public class BoolNode extends Node {
@Override
public String label() { return getClass().getSimpleName(); }
- @Override
- 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/chapter16/src/main/java/com/seaofnodes/simple/node/CProjNode.java b/chapter16/src/main/java/com/seaofnodes/simple/node/CProjNode.java
index 3d6fd1fa..cba63db8 100644
--- a/chapter16/src/main/java/com/seaofnodes/simple/node/CProjNode.java
+++ b/chapter16/src/main/java/com/seaofnodes/simple/node/CProjNode.java
@@ -1,10 +1,11 @@
package com.seaofnodes.simple.node;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.Parser;
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeMem;
import com.seaofnodes.simple.type.TypeTuple;
-import java.util.BitSet;
public class CProjNode extends CFGNode {
@@ -22,7 +23,7 @@ public class CProjNode extends CFGNode {
@Override public String label() { return _label; }
- @Override 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 isMultiTail() { return in(0).isMultiHead(); }
@Override public boolean blockHead() { return true; }
diff --git a/chapter16/src/main/java/com/seaofnodes/simple/node/CastNode.java b/chapter16/src/main/java/com/seaofnodes/simple/node/CastNode.java
index 38d6a126..9ade5a50 100644
--- a/chapter16/src/main/java/com/seaofnodes/simple/node/CastNode.java
+++ b/chapter16/src/main/java/com/seaofnodes/simple/node/CastNode.java
@@ -1,10 +1,11 @@
package com.seaofnodes.simple.node;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeInteger;
import com.seaofnodes.simple.IterPeeps;
-import java.util.BitSet;
// Upcast (join) the input to a t. Used after guard test to lift an input.
// Can also be used to make a type-assertion if ctrl is null.
@@ -18,13 +19,10 @@ public class CastNode extends Node {
@Override public String label() { return "("+_t.str()+")"; }
- @Override
- public String uniqueName() { return "Cast_" + _nid; }
- @Override
- StringBuilder _print1(StringBuilder sb, BitSet visited) {
- return in(1)._print0(sb.append(label()), visited);
+ @Override protected ExprPrinter<Node> _print1(ExprPrinter<Node> p) {
+ return p.p(label()).n(in(1));
}
@Override
diff --git a/chapter16/src/main/java/com/seaofnodes/simple/node/ConstantNode.java b/chapter16/src/main/java/com/seaofnodes/simple/node/ConstantNode.java
index d760c0df..426736ed 100644
--- a/chapter16/src/main/java/com/seaofnodes/simple/node/ConstantNode.java
+++ b/chapter16/src/main/java/com/seaofnodes/simple/node/ConstantNode.java
@@ -1,9 +1,10 @@
package com.seaofnodes.simple.node;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.Parser;
import com.seaofnodes.simple.type.Type;
-import java.util.BitSet;
/**
* A Constant node represents a constant value. At present, the only constants
@@ -24,15 +25,16 @@ public class ConstantNode extends Node {
_con = type;
}
- @Override
- public String label() { return "#"+_con; }
+ @Override protected String repeatName() {
+ return _con==null || _con.toString().length()<=32 ? null : uniqueName();
+ }
@Override
- public String uniqueName() { return "Con_" + _nid; }
+ public String label() { return "Con"; }
- @Override
- StringBuilder _print1(StringBuilder sb, BitSet visited) {
- return _con.print(sb);
+
+ @Override protected ExprPrinter<Node> _print1(ExprPrinter<Node> p) {
+ return p.p(_con);
}
@Override public boolean isMultiTail() { return true; }
diff --git a/chapter16/src/main/java/com/seaofnodes/simple/node/DivFNode.java b/chapter16/src/main/java/com/seaofnodes/simple/node/DivFNode.java
index 6c0c2eb3..a3f4318d 100644
--- a/chapter16/src/main/java/com/seaofnodes/simple/node/DivFNode.java
+++ b/chapter16/src/main/java/com/seaofnodes/simple/node/DivFNode.java
@@ -1,21 +1,16 @@
package com.seaofnodes.simple.node;
+
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeFloat;
-import java.util.BitSet;
public class DivFNode extends Node {
public DivFNode(Node lhs, Node rhs) { super(null, lhs, rhs); }
@Override public String label() { return "DivF"; }
- @Override
- StringBuilder _print1(StringBuilder sb, BitSet visited) {
- in(1)._print0(sb.append("("), visited);
- in(2)._print0(sb.append("/"), visited);
- return sb.append(")");
- }
+ @Override protected String format() { return "(%1/%2)"; }
@Override
public Type compute() {
diff --git a/chapter16/src/main/java/com/seaofnodes/simple/node/DivNode.java b/chapter16/src/main/java/com/seaofnodes/simple/node/DivNode.java
index d13dcacf..cd749a03 100644
--- a/chapter16/src/main/java/com/seaofnodes/simple/node/DivNode.java
+++ b/chapter16/src/main/java/com/seaofnodes/simple/node/DivNode.java
@@ -1,21 +1,16 @@
package com.seaofnodes.simple.node;
+
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeInteger;
-import java.util.BitSet;
public class DivNode extends Node {
public DivNode(Node lhs, Node rhs) { super(null, lhs, rhs); }
@Override public String label() { return "Div"; }
- @Override
- StringBuilder _print1(StringBuilder sb, BitSet visited) {
- in(1)._print0(sb.append("("), visited);
- in(2)._print0(sb.append("/"), visited);
- return sb.append(")");
- }
+ @Override protected String format() { return "(%1/%2)"; }
@Override
public Type compute() {
diff --git a/chapter16/src/main/java/com/seaofnodes/simple/node/IfNode.java b/chapter16/src/main/java/com/seaofnodes/simple/node/IfNode.java
index 3cce89ab..f21894dc 100644
--- a/chapter16/src/main/java/com/seaofnodes/simple/node/IfNode.java
+++ b/chapter16/src/main/java/com/seaofnodes/simple/node/IfNode.java
@@ -1,5 +1,6 @@
package com.seaofnodes.simple.node;
+
import com.seaofnodes.simple.IterPeeps;
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeInteger;
@@ -17,11 +18,7 @@ public class IfNode extends CFGNode implements MultiNode {
@Override
public String label() { return "If"; }
- @Override
- StringBuilder _print1(StringBuilder sb, BitSet visited) {
- sb.append("if( ");
- return in(1)._print0(sb, visited).append(" )");
- }
+ @Override protected String format() { return "if( %1 )"; }
@Override public boolean isMultiHead() { return true; }
diff --git a/chapter16/src/main/java/com/seaofnodes/simple/node/LoadNode.java b/chapter16/src/main/java/com/seaofnodes/simple/node/LoadNode.java
index 46938f7b..8d604b28 100644
--- a/chapter16/src/main/java/com/seaofnodes/simple/node/LoadNode.java
+++ b/chapter16/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.Utils;
import com.seaofnodes.simple.IterPeeps;
import com.seaofnodes.simple.type.*;
@@ -46,7 +48,7 @@ public class LoadNode extends MemOpNode {
// Debugger label
@Override public String label() { return "ld_"+mlabel(); }
@Override
- 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/chapter16/src/main/java/com/seaofnodes/simple/node/MemMergeNode.java b/chapter16/src/main/java/com/seaofnodes/simple/node/MemMergeNode.java
index ff040b99..faf456de 100644
--- a/chapter16/src/main/java/com/seaofnodes/simple/node/MemMergeNode.java
+++ b/chapter16/src/main/java/com/seaofnodes/simple/node/MemMergeNode.java
@@ -1,9 +1,10 @@
package com.seaofnodes.simple.node;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.IterPeeps;
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeMem;
-import java.util.BitSet;
/** A default slice and explicit alias overrides. A null default means partial
* memory: absent aliases are not covered, rather than having unknown contents.
@@ -53,14 +54,14 @@ public class MemMergeNode extends Node {
@Override public String label() { return "MemMerge"; }
@Override public boolean isMem() { return true; }
@Override public Type compute() { return TypeMem.BOT; }
- @Override StringBuilder _print1(StringBuilder sb, BitSet visited) {
- sb.append("MEM[");
+ @Override protected ExprPrinter<Node> _print1(ExprPrinter<Node> p) {
+ p.p("MEM[");
for( int i=1; i<nIns(); i++ )
if( in(i)!=null ) {
- sb.append(i==1 ? "default:" : i+":");
- in(i)._print0(sb,visited).append(" ");
+ p.p(i==1 ? "default:" : i+":");
+ p.n(in(i)).p(" ");
}
- return sb.append("]");
+ return p.p("]");
}
@Override public Node idealize() {
diff --git a/chapter16/src/main/java/com/seaofnodes/simple/node/MinusFNode.java b/chapter16/src/main/java/com/seaofnodes/simple/node/MinusFNode.java
index 7cacf2c9..1b45c7c5 100644
--- a/chapter16/src/main/java/com/seaofnodes/simple/node/MinusFNode.java
+++ b/chapter16/src/main/java/com/seaofnodes/simple/node/MinusFNode.java
@@ -1,20 +1,16 @@
package com.seaofnodes.simple.node;
+
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeFloat;
-import java.util.BitSet;
public class MinusFNode extends Node {
public MinusFNode(Node in) { super(null, in); }
@Override public String label() { return "MinusF"; }
- @Override
- 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/chapter16/src/main/java/com/seaofnodes/simple/node/MinusNode.java b/chapter16/src/main/java/com/seaofnodes/simple/node/MinusNode.java
index 63cfd110..bd8f71ad 100644
--- a/chapter16/src/main/java/com/seaofnodes/simple/node/MinusNode.java
+++ b/chapter16/src/main/java/com/seaofnodes/simple/node/MinusNode.java
@@ -1,20 +1,16 @@
package com.seaofnodes.simple.node;
+
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeInteger;
-import java.util.BitSet;
public class MinusNode extends Node {
public MinusNode(Node in) { super(null, in); }
@Override public String label() { return "Minus"; }
- @Override
- 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/chapter16/src/main/java/com/seaofnodes/simple/node/MulFNode.java b/chapter16/src/main/java/com/seaofnodes/simple/node/MulFNode.java
index 4b753ba7..6a57f3c5 100644
--- a/chapter16/src/main/java/com/seaofnodes/simple/node/MulFNode.java
+++ b/chapter16/src/main/java/com/seaofnodes/simple/node/MulFNode.java
@@ -1,21 +1,16 @@
package com.seaofnodes.simple.node;
+
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeFloat;
-import java.util.BitSet;
public class MulFNode extends Node {
public MulFNode(Node lhs, Node rhs) { super(null, lhs, rhs); }
@Override public String label() { return "MulF"; }
- @Override
- StringBuilder _print1(StringBuilder sb, BitSet visited) {
- in(1)._print0(sb.append("("), visited);
- in(2)._print0(sb.append("*"), visited);
- return sb.append(")");
- }
+ @Override protected String format() { return "(%1*%2)"; }
@Override
public Type compute() {
diff --git a/chapter16/src/main/java/com/seaofnodes/simple/node/MulNode.java b/chapter16/src/main/java/com/seaofnodes/simple/node/MulNode.java
index 65898907..a9ac07e6 100644
--- a/chapter16/src/main/java/com/seaofnodes/simple/node/MulNode.java
+++ b/chapter16/src/main/java/com/seaofnodes/simple/node/MulNode.java
@@ -1,21 +1,16 @@
package com.seaofnodes.simple.node;
+
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeInteger;
-import java.util.BitSet;
public class MulNode extends Node {
public MulNode(Node lhs, Node rhs) { super(null, lhs, rhs); }
@Override public String label() { return "Mul"; }
- @Override
- StringBuilder _print1(StringBuilder sb, BitSet visited) {
- in(1)._print0(sb.append("("), visited);
- in(2)._print0(sb.append("*"), visited);
- return sb.append(")");
- }
+ @Override protected String format() { return "(%1*%2)"; }
@Override
public Type compute() {
diff --git a/chapter16/src/main/java/com/seaofnodes/simple/node/NeverNode.java b/chapter16/src/main/java/com/seaofnodes/simple/node/NeverNode.java
index e77ed653..7e42ccf9 100644
--- a/chapter16/src/main/java/com/seaofnodes/simple/node/NeverNode.java
+++ b/chapter16/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 {
@@ -13,7 +14,7 @@ public class NeverNode extends IfNode {
@Override public String label() { return "Never"; }
- @Override 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/chapter16/src/main/java/com/seaofnodes/simple/node/NewNode.java b/chapter16/src/main/java/com/seaofnodes/simple/node/NewNode.java
index bdccc681..51341c41 100644
--- a/chapter16/src/main/java/com/seaofnodes/simple/node/NewNode.java
+++ b/chapter16/src/main/java/com/seaofnodes/simple/node/NewNode.java
@@ -1,7 +1,8 @@
package com.seaofnodes.simple.node;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.type.*;
-import java.util.BitSet;
/** Allocate and initialize an object. Inputs {ctrl, $mem, size, fields...};
* results {ptr, $mem}.
@@ -33,10 +34,8 @@ public class NewNode extends Node implements MultiNode {
@Override public String label() {
return "new_"+(_ptr._obj.isAry() ? "ary_"+_ptr._obj._fields[1]._type.str() : _ptr._obj.str());
}
- @Override
- StringBuilder _print1(StringBuilder sb, BitSet visited) {
- sb.append("new ");
- return sb.append(_ptr._obj.str());
+ @Override protected ExprPrinter<Node> _print1(ExprPrinter<Node> p) {
+ return p.p("new ").p(_ptr._obj.str());
}
// Find matching alias input
diff --git a/chapter16/src/main/java/com/seaofnodes/simple/node/Node.java b/chapter16/src/main/java/com/seaofnodes/simple/node/Node.java
index b9d2632b..fa25b58a 100644
--- a/chapter16/src/main/java/com/seaofnodes/simple/node/Node.java
+++ b/chapter16/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.Parser;
import com.seaofnodes.simple.Ary;
@@ -16,14 +18,7 @@ import java.util.function.Function;
* The Node class provides common functionality used by all subtypes.
* Subtypes of Node specialize by overriding methods.
*/
-public abstract class Node implements OutNode, 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 OutNode, Cloneable {
/**
* Inputs to the node. These are use-def references to Nodes.
@@ -45,14 +40,12 @@ public abstract class Node implements OutNode, 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;
-
/**
* A private Global Static mutable counter, for unique node id generation.
* To make the compiler multithreaded, this field will have to move into a TLS.
@@ -62,7 +55,7 @@ public abstract class Node implements OutNode, Cloneable {
public static int UID() { return UNIQUE_ID; }
protected Node(Node... inputs) {
- _nid = UNIQUE_ID++; // allocate unique dense ID
+ super(UNIQUE_ID++); // allocate unique dense ID
_inputs = new Ary<>(Node.class);
Collections.addAll(_inputs,inputs);
_outputs = new Ary<>(Node.class);
@@ -74,40 +67,6 @@ public abstract class Node implements OutNode, Cloneable {
// Easy reading label for debugger, e.g. "Add" or "Region" or "EQ"
public abstract String label();
- // Unique label for debugging, e.g. "Add12" or "Region30" or "EQ99"
- public String uniqueName() {
- return label() + _nid;
- }
-
- // ------------------------------------------------------------------------
-
- // 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 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.
- 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 StringBuilder _print1(StringBuilder sb, BitSet visited);
-
public String p(int depth) { return IRPrinter.prettyPrint(this,depth); }
public boolean isMultiHead() { return false; }
@@ -116,6 +75,8 @@ public abstract class Node implements OutNode, 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
@@ -188,7 +149,6 @@ public abstract class Node implements OutNode, Cloneable {
return setDef(idx,new_def);
}
-
/**
* Add a new def to an existing Node. Keep the edges correct by
* adding the corresponding <em>def->use</em> edge.
@@ -262,7 +222,6 @@ public abstract class Node implements OutNode, Cloneable {
// Test "keep" status
public boolean iskeep() { return _outputs.find(null) != -1; }
-
// Replace self with nnn in the graph, making 'this' go dead
public void subsume( Node nnn ) {
assert nnn!=this;
@@ -393,7 +352,6 @@ public abstract class Node implements OutNode, Cloneable {
return old;
}
-
/**
* This function rewrites the current Node into a more "idealized" form.
* This is the bulk of our peephole rewrite rules, and we use this to
@@ -441,7 +399,6 @@ public abstract class Node implements OutNode, 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
@@ -485,7 +442,6 @@ public abstract class Node implements OutNode, Cloneable {
_deps.clear();
}
-
// Global Value Numbering. Hash over opcode and inputs; hits in this table
// are structurally equal.
public static final HashMap<Node,Node> GVN = new HashMap<>();
@@ -507,7 +463,6 @@ public abstract class Node implements OutNode, Cloneable {
// and can assume "this!=n" and has the same Java class.
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
@@ -523,7 +478,6 @@ public abstract class Node implements OutNode, Cloneable {
_hash=0; // Out of table now
}
-
// Hash of opcode and inputs
@Override public final int hashCode() {
if( _hash != 0 ) return _hash;
@@ -546,7 +500,6 @@ public abstract class Node implements OutNode, Cloneable {
/** Return block start from a isCFG() */
public Node getBlockStart() { return null; }
-
// Semantic change to the graph (so NOT a peephole), used by the Parser.
// If any input is a float, flip to a float-flavored opcode and widen any
// non-float input.
@@ -567,7 +520,6 @@ public abstract class Node implements OutNode, Cloneable {
}
Node copyF() { return null; }
-
// ------------------------------------------------------------------------
// Peephole utilities
@@ -596,7 +548,6 @@ public abstract class Node implements OutNode, 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.
@@ -629,7 +580,6 @@ public abstract class Node implements OutNode, Cloneable {
ITER_CNT = ITER_NOP_CNT = 0;
}
-
// Utility to walk the entire graph applying a function; return the first
// not-null result.
private static final BitSet WVISIT = new BitSet();
diff --git a/chapter16/src/main/java/com/seaofnodes/simple/node/NotNode.java b/chapter16/src/main/java/com/seaofnodes/simple/node/NotNode.java
index 38c6c90e..e388f4a3 100644
--- a/chapter16/src/main/java/com/seaofnodes/simple/node/NotNode.java
+++ b/chapter16/src/main/java/com/seaofnodes/simple/node/NotNode.java
@@ -1,19 +1,15 @@
package com.seaofnodes.simple.node;
+
import com.seaofnodes.simple.Utils;
import com.seaofnodes.simple.type.*;
-import java.util.BitSet;
public class NotNode extends Node {
public NotNode(Node in) { super(null, in); }
@Override public String label() { return "Not"; }
- @Override
- 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/chapter16/src/main/java/com/seaofnodes/simple/node/OrNode.java b/chapter16/src/main/java/com/seaofnodes/simple/node/OrNode.java
index 301514f4..5be31b88 100644
--- a/chapter16/src/main/java/com/seaofnodes/simple/node/OrNode.java
+++ b/chapter16/src/main/java/com/seaofnodes/simple/node/OrNode.java
@@ -1,21 +1,16 @@
package com.seaofnodes.simple.node;
+
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeInteger;
-import java.util.BitSet;
public class OrNode extends Node {
public OrNode(Node lhs, Node rhs) { super(null, lhs, rhs); }
@Override public String label() { return "Or"; }
- @Override
- StringBuilder _print1(StringBuilder sb, BitSet visited) {
- in(1)._print0(sb.append("("), visited);
- in(2)._print0(sb.append("|"), visited);
- return sb.append(")");
- }
+ @Override protected String format() { return "(%1|%2)"; }
@Override
public Type compute() {
diff --git a/chapter16/src/main/java/com/seaofnodes/simple/node/PhiNode.java b/chapter16/src/main/java/com/seaofnodes/simple/node/PhiNode.java
index 6a9a8aae..8479b4dc 100644
--- a/chapter16/src/main/java/com/seaofnodes/simple/node/PhiNode.java
+++ b/chapter16/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.type.Type;
import com.seaofnodes.simple.type.TypeMem;
import com.seaofnodes.simple.Utils;
-import java.util.BitSet;
public class PhiNode extends Node {
@@ -23,18 +24,12 @@ public class PhiNode extends Node {
@Override public String label() { return "Phi_"+MemOpNode.mlabel(_label); }
@Override
- 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/chapter16/src/main/java/com/seaofnodes/simple/node/ProjNode.java b/chapter16/src/main/java/com/seaofnodes/simple/node/ProjNode.java
index cd57b85c..668e20ad 100644
--- a/chapter16/src/main/java/com/seaofnodes/simple/node/ProjNode.java
+++ b/chapter16/src/main/java/com/seaofnodes/simple/node/ProjNode.java
@@ -1,10 +1,11 @@
package com.seaofnodes.simple.node;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeMem;
import com.seaofnodes.simple.type.TypeTuple;
-import java.util.BitSet;
public class ProjNode extends Node {
@@ -23,7 +24,7 @@ public class ProjNode extends Node {
@Override public String label() { return _label; }
@Override
- StringBuilder _print1(StringBuilder sb, BitSet visited) { return sb.append(_label); }
+ protected ExprPrinter<Node> _print1(ExprPrinter<Node> p) { return p.p(_label); }
@Override public CFGNode cfg0() { return in(0).cfg0(); }
diff --git a/chapter16/src/main/java/com/seaofnodes/simple/node/RegionNode.java b/chapter16/src/main/java/com/seaofnodes/simple/node/RegionNode.java
index 15efb9d1..08f48a08 100644
--- a/chapter16/src/main/java/com/seaofnodes/simple/node/RegionNode.java
+++ b/chapter16/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.IterPeeps;
import com.seaofnodes.simple.Parser;
import com.seaofnodes.simple.Utils;
@@ -16,9 +18,8 @@ public class RegionNode extends CFGNode {
@Override
public String label() { return "Region"; }
- @Override
- StringBuilder _print1(StringBuilder sb, BitSet visited) {
- return sb.append(label()).append(_nid);
+ @Override protected ExprPrinter<Node> _print1(ExprPrinter<Node> p) {
+ return p.p(label()).p(_nid);
}
@Override public boolean isMultiHead() { return true; }
diff --git a/chapter16/src/main/java/com/seaofnodes/simple/node/ReturnNode.java b/chapter16/src/main/java/com/seaofnodes/simple/node/ReturnNode.java
index 978391e3..eff33954 100644
--- a/chapter16/src/main/java/com/seaofnodes/simple/node/ReturnNode.java
+++ b/chapter16/src/main/java/com/seaofnodes/simple/node/ReturnNode.java
@@ -1,8 +1,9 @@
package com.seaofnodes.simple.node;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.type.*;
-import java.util.BitSet;
/** Keeps all preceding memory effects and the return value alive: {ctrl, $mem, value}. */
public class ReturnNode extends CFGNode {
@@ -20,10 +21,10 @@ public class ReturnNode extends CFGNode {
public String label() { return "Return"; }
@Override
- StringBuilder _print1(StringBuilder sb, BitSet visited) {
- sb.append("return ");
- expr()._print0(sb, visited);
- return sb.append(";");
+ protected ExprPrinter<Node> _print1(ExprPrinter<Node> p) {
+ p.p("return ");
+ p.n(expr());
+ return p.p(";");
}
@Override
diff --git a/chapter16/src/main/java/com/seaofnodes/simple/node/RoundF32Node.java b/chapter16/src/main/java/com/seaofnodes/simple/node/RoundF32Node.java
index 3dd7cbf0..78e7698c 100644
--- a/chapter16/src/main/java/com/seaofnodes/simple/node/RoundF32Node.java
+++ b/chapter16/src/main/java/com/seaofnodes/simple/node/RoundF32Node.java
@@ -1,19 +1,16 @@
package com.seaofnodes.simple.node;
+
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeFloat;
-import java.util.BitSet;
public class RoundF32Node extends Node {
public RoundF32Node(Node lhs) { super(null, lhs); }
@Override public String label() { return "RoundF32"; }
- @Override
- 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/chapter16/src/main/java/com/seaofnodes/simple/node/SarNode.java b/chapter16/src/main/java/com/seaofnodes/simple/node/SarNode.java
index 25ef55e3..44233b3d 100644
--- a/chapter16/src/main/java/com/seaofnodes/simple/node/SarNode.java
+++ b/chapter16/src/main/java/com/seaofnodes/simple/node/SarNode.java
@@ -1,21 +1,16 @@
package com.seaofnodes.simple.node;
+
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeInteger;
-import java.util.BitSet;
public class SarNode extends Node {
public SarNode(Node lhs, Node rhs) { super(null, lhs, rhs); }
@Override public String label() { return "Sar"; }
- @Override
- StringBuilder _print1(StringBuilder sb, BitSet visited) {
- in(1)._print0(sb.append("("), visited);
- in(2)._print0(sb.append(">>"), visited);
- return sb.append(")");
- }
+ @Override protected String format() { return "(%1>>%2)"; }
@Override
public Type compute() {
diff --git a/chapter16/src/main/java/com/seaofnodes/simple/node/ScopeNode.java b/chapter16/src/main/java/com/seaofnodes/simple/node/ScopeNode.java
index baa27134..84937ad7 100644
--- a/chapter16/src/main/java/com/seaofnodes/simple/node/ScopeNode.java
+++ b/chapter16/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.IterPeeps;
import com.seaofnodes.simple.Ary;
import com.seaofnodes.simple.type.*;
@@ -53,28 +55,26 @@ public class ScopeNode extends Node {
@Override
- StringBuilder _print1(StringBuilder sb, BitSet visited) {
- sb.append("Scope[ ");
+ protected ExprPrinter<Node> _print1(ExprPrinter<Node> p) {
+ p.p("Scope[ ");
int j=1;
for( int i=0; i<nIns(); i++ ) {
- if( j < _lexSize._len && i == _lexSize.at(j) ) { sb.append("| "); j++; }
+ if( j < _lexSize._len && i == _lexSize.at(j) ) { p.p("| "); j++; }
Var v = _vars.get(i);
- v._type.print(sb);
- 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/chapter16/src/main/java/com/seaofnodes/simple/node/ShlNode.java b/chapter16/src/main/java/com/seaofnodes/simple/node/ShlNode.java
index 1f558b8f..4d673056 100644
--- a/chapter16/src/main/java/com/seaofnodes/simple/node/ShlNode.java
+++ b/chapter16/src/main/java/com/seaofnodes/simple/node/ShlNode.java
@@ -1,21 +1,16 @@
package com.seaofnodes.simple.node;
+
import com.seaofnodes.simple.Parser;
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeInteger;
-import java.util.BitSet;
public class ShlNode extends Node {
public ShlNode(Node lhs, Node rhs) { super(null, lhs, rhs); }
@Override public String label() { return "Shl"; }
- @Override
- StringBuilder _print1(StringBuilder sb, BitSet visited) {
- in(1)._print0(sb.append("("), visited);
- in(2)._print0(sb.append("<<"), visited);
- return sb.append(")");
- }
+ @Override protected String format() { return "(%1<<%2)"; }
@Override
public Type compute() {
diff --git a/chapter16/src/main/java/com/seaofnodes/simple/node/ShrNode.java b/chapter16/src/main/java/com/seaofnodes/simple/node/ShrNode.java
index e8ae2c1c..bc6881f1 100644
--- a/chapter16/src/main/java/com/seaofnodes/simple/node/ShrNode.java
+++ b/chapter16/src/main/java/com/seaofnodes/simple/node/ShrNode.java
@@ -1,21 +1,16 @@
package com.seaofnodes.simple.node;
+
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeInteger;
-import java.util.BitSet;
public class ShrNode extends Node {
public ShrNode(Node lhs, Node rhs) { super(null, lhs, rhs); }
@Override public String label() { return "Shr"; }
- @Override
- StringBuilder _print1(StringBuilder sb, BitSet visited) {
- in(1)._print0(sb.append("("), visited);
- in(2)._print0(sb.append(">>>"), visited);
- return sb.append(")");
- }
+ @Override protected String format() { return "(%1>>>%2)"; }
@Override
public Type compute() {
diff --git a/chapter16/src/main/java/com/seaofnodes/simple/node/StartNode.java b/chapter16/src/main/java/com/seaofnodes/simple/node/StartNode.java
index 6e1f13ee..23830a18 100644
--- a/chapter16/src/main/java/com/seaofnodes/simple/node/StartNode.java
+++ b/chapter16/src/main/java/com/seaofnodes/simple/node/StartNode.java
@@ -1,5 +1,7 @@
package com.seaofnodes.simple.node;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.type.*;
import java.util.BitSet;
import java.util.HashSet;
@@ -14,9 +16,8 @@ public class StartNode extends CFGNode implements MultiNode {
@Override public String label() { return "Start"; }
- @Override
- 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 isMultiHead() { return true; }
diff --git a/chapter16/src/main/java/com/seaofnodes/simple/node/StopNode.java b/chapter16/src/main/java/com/seaofnodes/simple/node/StopNode.java
index af3a9de6..202afbd2 100644
--- a/chapter16/src/main/java/com/seaofnodes/simple/node/StopNode.java
+++ b/chapter16/src/main/java/com/seaofnodes/simple/node/StopNode.java
@@ -1,12 +1,13 @@
package com.seaofnodes.simple.node;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.Parser;
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.IterPeeps;
import com.seaofnodes.simple.GlobalCodeMotion;
-import java.util.BitSet;
public class StopNode extends CFGNode {
@@ -23,12 +24,12 @@ public class StopNode extends CFGNode {
}
@Override
- StringBuilder _print1(StringBuilder sb, BitSet visited) {
- if( ret()!=null ) return ret()._print0(sb, visited);
- sb.append("Stop[ ");
+ protected ExprPrinter<Node> _print1(ExprPrinter<Node> p) {
+ if( ret()!=null ) return p.n(ret());
+ p.p("Stop[ ");
for( Node ret : _inputs )
- ret._print0(sb, visited).append(" ");
- return sb.append("]");
+ p.n(ret).p(" ");
+ return p.p("]");
}
@Override public boolean blockHead() { return true; }
diff --git a/chapter16/src/main/java/com/seaofnodes/simple/node/StoreNode.java b/chapter16/src/main/java/com/seaofnodes/simple/node/StoreNode.java
index 8d1b9ae1..8eb104a7 100644
--- a/chapter16/src/main/java/com/seaofnodes/simple/node/StoreNode.java
+++ b/chapter16/src/main/java/com/seaofnodes/simple/node/StoreNode.java
@@ -1,10 +1,11 @@
package com.seaofnodes.simple.node;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.Utils;
import com.seaofnodes.simple.IterPeeps;
import com.seaofnodes.simple.type.*;
-import java.util.BitSet;
/**
* Store represents setting a value to a memory based object, in chapter 10
@@ -37,8 +38,8 @@ public class StoreNode extends MemOpNode {
public Node val() { return in(4); }
@Override
- 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/chapter16/src/main/java/com/seaofnodes/simple/node/StructNode.java b/chapter16/src/main/java/com/seaofnodes/simple/node/StructNode.java
index db170ab1..429b49cc 100644
--- a/chapter16/src/main/java/com/seaofnodes/simple/node/StructNode.java
+++ b/chapter16/src/main/java/com/seaofnodes/simple/node/StructNode.java
@@ -1,7 +1,8 @@
package com.seaofnodes.simple.node;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.type.*;
-import java.util.BitSet;
/**
* Build a compound object
@@ -13,16 +14,15 @@ public class StructNode extends Node {
@Override public String label() { return _ts==null ? "STRUCT?" : _ts.str(); }
@Override
- StringBuilder _print1(StringBuilder sb, BitSet visited) {
- if( _ts==null ) return sb.append("STRUCT?");
- sb.append(_ts._name).append(" {");
+ protected ExprPrinter<Node> _print1(ExprPrinter<Node> p) {
+ if( _ts==null ) return p.p("STRUCT?");
+ p.p(_ts._name).p(" {");
for( int i=0; i<nIns(); i++ ) {
- sb.append(_ts._fields[i]._fname).append(":");
- (in(i)==null ? Type.BOTTOM : in(i)._type).print(sb);
- sb.append("; ");
+ p.p(_ts._fields[i]._fname).p(":");
+ p.p(in(i)==null ? Type.BOTTOM : in(i)._type);
+ p.p("; ");
}
- sb.setLength(sb.length()-2);
- return sb.append("}");
+ return p.unchar("; ").p("}");
}
@Override
diff --git a/chapter16/src/main/java/com/seaofnodes/simple/node/SubFNode.java b/chapter16/src/main/java/com/seaofnodes/simple/node/SubFNode.java
index 27bbda8d..2d218a03 100644
--- a/chapter16/src/main/java/com/seaofnodes/simple/node/SubFNode.java
+++ b/chapter16/src/main/java/com/seaofnodes/simple/node/SubFNode.java
@@ -1,21 +1,16 @@
package com.seaofnodes.simple.node;
+
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeFloat;
-import java.util.BitSet;
public class SubFNode extends Node {
public SubFNode(Node lhs, Node rhs) { super(null, lhs, rhs); }
@Override public String label() { return "SubF"; }
- @Override
- StringBuilder _print1(StringBuilder sb, BitSet visited) {
- in(1)._print0(sb.append("("), visited);
- in(2)._print0(sb.append("-"), visited);
- return sb.append(")");
- }
+ @Override protected String format() { return "(%1-%2)"; }
@Override
public Type compute() {
diff --git a/chapter16/src/main/java/com/seaofnodes/simple/node/SubNode.java b/chapter16/src/main/java/com/seaofnodes/simple/node/SubNode.java
index 237e40ed..134f7cd6 100644
--- a/chapter16/src/main/java/com/seaofnodes/simple/node/SubNode.java
+++ b/chapter16/src/main/java/com/seaofnodes/simple/node/SubNode.java
@@ -1,22 +1,17 @@
package com.seaofnodes.simple.node;
+
import com.seaofnodes.simple.Parser;
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeInteger;
-import java.util.BitSet;
public class SubNode extends Node {
public SubNode(Node lhs, Node rhs) { super(null, lhs, rhs); }
@Override public String label() { return "Sub"; }
- @Override
- StringBuilder _print1(StringBuilder sb, BitSet visited) {
- in(1)._print0(sb.append("("), visited);
- in(2)._print0(sb.append("-"), visited);
- return sb.append(")");
- }
+ @Override protected String format() { return "(%1-%2)"; }
@Override
public Type compute() {
diff --git a/chapter16/src/main/java/com/seaofnodes/simple/node/ToFloatNode.java b/chapter16/src/main/java/com/seaofnodes/simple/node/ToFloatNode.java
index fde483d6..26cf50e1 100644
--- a/chapter16/src/main/java/com/seaofnodes/simple/node/ToFloatNode.java
+++ b/chapter16/src/main/java/com/seaofnodes/simple/node/ToFloatNode.java
@@ -1,20 +1,17 @@
package com.seaofnodes.simple.node;
+
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeFloat;
import com.seaofnodes.simple.type.TypeInteger;
-import java.util.BitSet;
public class ToFloatNode extends Node {
public ToFloatNode(Node lhs) { super(null, lhs); }
@Override public String label() { return "ToFloat"; }
- @Override
- 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/chapter16/src/main/java/com/seaofnodes/simple/node/XCtrlNode.java b/chapter16/src/main/java/com/seaofnodes/simple/node/XCtrlNode.java
index 83779dd2..056dfba1 100644
--- a/chapter16/src/main/java/com/seaofnodes/simple/node/XCtrlNode.java
+++ b/chapter16/src/main/java/com/seaofnodes/simple/node/XCtrlNode.java
@@ -1,13 +1,14 @@
package com.seaofnodes.simple.node;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.Parser;
import com.seaofnodes.simple.type.Type;
-import java.util.BitSet;
public class XCtrlNode extends CFGNode {
public XCtrlNode( ) { super(Parser.START); }
@Override public String label() { return "Xctrl"; }
- @Override StringBuilder _print1(StringBuilder sb, BitSet visited) { return sb.append("Xctrl"); }
+ @Override protected ExprPrinter<Node> _print1(ExprPrinter<Node> p) { return p.p("Xctrl"); }
@Override public Type compute() { return Type.XCONTROL; }
@Override public Node idealize() { return null; }
}
diff --git a/chapter16/src/main/java/com/seaofnodes/simple/node/XorNode.java b/chapter16/src/main/java/com/seaofnodes/simple/node/XorNode.java
index 71dce586..ef7273b8 100644
--- a/chapter16/src/main/java/com/seaofnodes/simple/node/XorNode.java
+++ b/chapter16/src/main/java/com/seaofnodes/simple/node/XorNode.java
@@ -1,21 +1,16 @@
package com.seaofnodes.simple.node;
+
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeInteger;
-import java.util.BitSet;
public class XorNode extends Node {
public XorNode(Node lhs, Node rhs) { super(null, lhs, rhs); }
@Override public String label() { return "Xor"; }
- @Override
- StringBuilder _print1(StringBuilder sb, BitSet visited) {
- in(1)._print0(sb.append("("), visited);
- in(2)._print0(sb.append("^"), visited);
- return sb.append(")");
- }
+ @Override protected String format() { return "(%1^%2)"; }
@Override
public Type compute() {
diff --git a/chapter16/src/main/java/com/seaofnodes/simple/print/SimpleGraphAdapter.java b/chapter16/src/main/java/com/seaofnodes/simple/print/SimpleGraphAdapter.java
index dff0de0b..d023e1e7 100644
--- a/chapter16/src/main/java/com/seaofnodes/simple/print/SimpleGraphAdapter.java
+++ b/chapter16/src/main/java/com/seaofnodes/simple/print/SimpleGraphAdapter.java
@@ -1,43 +1,21 @@
package com.seaofnodes.simple.print;
import com.seaofnodes.graph.GraphAdapter;
-import com.seaofnodes.graph.GraphSnapshot;
import com.seaofnodes.graph.GraphSnapshot.*;
import com.seaofnodes.simple.node.*;
import com.seaofnodes.simple.node.Node;
import com.seaofnodes.simple.type.TypeMem;
-import java.util.ArrayList;
/** Chapter 16's view of the IR; browser, transport and layout are shared. */
public class SimpleGraphAdapter extends GraphAdapter<Node> {
- @Override protected boolean dead(Node n) { return n.isDead(); }
- @Override protected int id(Node n) { return n._nid; }
- @Override protected int nIns(Node n) { return n.nIns(); }
- @Override protected Node in(Node n, int idx) { return n.in(idx); }
- @Override protected int nOuts(Node n) { return n.nOuts(); }
- @Override protected Node out(Node n, int idx) { return n.out(idx); }
- @Override protected int nDeps(Node n) { return n.nDeps(); }
- @Override protected Node dep(Node n, int idx) { return n.dep(idx); }
- private ArrayList<Edge> edges(Node n) {
- var edges = new ArrayList<Edge>();
- for( int i = 0; i < n.nIns(); i++ ) {
- String name = n instanceof ScopeNode scope && i < scope._vars.size()
+ @Override protected String edgeName(Node n, int i) {
+ return n instanceof ScopeNode scope && i < scope._vars.size()
? scope._vars.get(i)._name : null;
- edges.add(new Edge(i, ref(n.in(i)), role(n, i), name));
- }
- return edges;
}
+ @Override protected int projectionIndex(Node n) { return n instanceof ProjNode p ? p._idx : n instanceof CProjNode p ? p._idx : -1; }
- @Override protected GraphSnapshot.Node desc(Node n) {
- Projection proj = n instanceof ProjNode p ? new Projection(ref(n.in(0)), p._idx)
- : n instanceof CProjNode p ? new Projection(ref(n.in(0)), p._idx) : null;
- String label = n.label();
- return new GraphSnapshot.Node(n._nid, label == null ? n.getClass().getSimpleName() : label,
- n._type == null ? null : n._type.toString(), kind(n), edges(n), proj);
- }
-
- 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 StartNode ) return Kind.CTRL;
@@ -47,7 +25,7 @@ public class SimpleGraphAdapter extends GraphAdapter<Node> {
return n instanceof CFGNode ? Kind.CTRL : isMem(n) ? Kind.MEM : Kind.DATA;
}
- private Role role(Node n, int i) {
+ @Override protected Role role(Node n, int i) {
if( n instanceof ScopeNode || n instanceof ConstantNode || n instanceof XCtrlNode ) return Role.ASSOC;
if( n instanceof PhiNode ) return i == 0 ? Role.ASSOC : isMem(n) ? Role.MEM : Role.DATA;
if( n instanceof ProjNode || n instanceof CProjNode )
diff --git a/chapter17/Makefile b/chapter17/Makefile
index 77df7182..3f1e53ff 100644
--- a/chapter17/Makefile
+++ b/chapter17/Makefile
@@ -37,6 +37,7 @@ main_javas := $(wildcard $(SRC)/$(SIMPLE)/*java $(SRC)/$(SIMPLE)/*/*java)
test_javas := $(wildcard $(TST)/$(SIMPLE)/*java $(TST)/$(SIMPLE)/*/*java)
main_classes := $(patsubst $(SRC)/%java,$(CLZDIR)/main/%class,$(main_javas))
include $(firstword $(wildcard ../graph/graph.mk graph/graph.mk))
+include $(firstword $(wildcard ../print/print.mk print/print.mk))
test_classes := $(patsubst $(TST)/%java,$(CLZDIR)/test/%class,$(test_javas))
test_cp := $(patsubst $(TST)/$(SIMPLE)/%.java,com.seaofnodes.simple.%,$(wildcard $(TST)/$(SIMPLE)/*Test.java))
classes = $(main_classes) $(test_classes)
@@ -54,7 +55,7 @@ endif
default: $(default_targets)
# Compile just the out-of-date files
-$(main_classes): build/classes/main/%class: $(SRC)/%java $(graph_javas)
+$(main_classes): build/classes/main/%class: $(SRC)/%java $(graph_javas) $(print_javas)
@echo "compiling " $@ " because " $?
@[ -d $(CLZDIR)/main ] || mkdir -p $(CLZDIR)/main
@javac $(JAVAC_ARGS) -cp "$(CLZDIR)/main$(SEP)$(jars)" -sourcepath $(SRC) -d $(CLZDIR)/main $(main_javas)
diff --git a/chapter17/pom.xml b/chapter17/pom.xml
index e6fe1140..13caef71 100644
--- a/chapter17/pom.xml
+++ b/chapter17/pom.xml
@@ -13,5 +13,6 @@
<name>Chapter 17</name>
<properties>
<simple.graph.directory>${project.basedir}/../graph</simple.graph.directory>
+ <simple.print.directory>${project.basedir}/../print</simple.print.directory>
</properties>
</project>
diff --git a/chapter17/src/main/java/com/seaofnodes/simple/IRPrinter.java b/chapter17/src/main/java/com/seaofnodes/simple/IRPrinter.java
index e1e19aae..7e93e9da 100644
--- a/chapter17/src/main/java/com/seaofnodes/simple/IRPrinter.java
+++ b/chapter17/src/main/java/com/seaofnodes/simple/IRPrinter.java
@@ -1,307 +1,33 @@
package com.seaofnodes.simple;
+import com.seaofnodes.print.IRAdapter;
import com.seaofnodes.simple.node.*;
-import java.lang.StringBuilder;
-import java.util.ArrayList;
-import java.util.BitSet;
-import java.util.HashMap;
-
-public 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 void _printLine( Node n, StringBuilder sb ) {
- sb.append("%4d %-7.7s ".formatted(n._nid,n.label()));
- if( n.isDead() ) {
- sb.append("DEAD\n");
- return;
- }
- for( Node def : n._inputs )
- sb.append(def==null ? "____ " : "%4d ".formatted(def._nid));
- for( int i = n._inputs.size(); i<4; i++ )
- sb.append(" ");
- sb.append(" [[ ");
- for( Node use : n._outputs )
- sb.append(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.append(" ");
- sb.append(" ]] ");
- if( n._type!= null ) sb.append(n._type.str());
- sb.append("\n");
- }
-
- private static StringBuilder nodeId(StringBuilder sb, Node n) {
- sb.append("%%%d".formatted(n._nid));
- if (n instanceof ProjNode proj) {
- sb.append(".").append(proj._idx);
- }
- return sb;
- }
-
- // Print a node on 1 line, format is inspired by LLVM
- // %id: TYPE = NODE(inputs ....)
- // Nodes as referred to as %id
- public static void _printLineLlvmFormat( Node n, StringBuilder sb ) {
- nodeId(sb, n).append(": ");
- if( n.isDead() ) {
- sb.append("DEAD\n");
- return;
- }
- if( n._type!= null ) n._type.typeName(sb);
- sb.append(" = ").append( n.label() ).append( "(" );
- for( int i = 0; i < n._inputs.size(); i++ ) {
- Node def = n.in(i);
- if (i > 0)
- sb.append(", ");
- if (def == null) sb.append("_");
- else nodeId(sb, def);
- }
- sb.append(")").append("\n");
- }
-
- public static void printLine( Node n, StringBuilder sb, boolean llvmFormat ) {
- if (llvmFormat) _printLineLlvmFormat( n, sb );
- else _printLine ( n, sb );
- }
-
- public static String prettyPrint(Node node, int depth) {
- return Parser.SCHEDULED
- ? prettyPrintScheduled( node, depth, false )
- : prettyPrint( node, depth, false );
- }
-
- // Another bulk pretty-printer. Makes more effort at basic-block grouping.
- public static String prettyPrint( Node node, int depth, boolean llvmFormat ) {
- // First, a Breadth First Search at a fixed depth.
- BFS bfs = new BFS(node,depth);
- // Convert just that set to a post-order
- ArrayList<Node> rpos = new ArrayList<>();
- BitSet visit = new BitSet();
- for( int i=bfs._lim; i< bfs._bfs.size(); i++ )
- postOrd( bfs._bfs.get(i), rpos, visit, bfs._bs);
- // Reverse the post-order walk
- StringBuilder sb = new StringBuilder();
- boolean gap=false;
- for( int i=rpos.size()-1; i>=0; i-- ) {
- Node n = rpos.get(i);
- if( n instanceof CFGNode || n.isMultiHead() ) {
- if( !gap ) sb.append("\n"); // Blank before multihead
- printLine( n, sb, llvmFormat ); // Print head
- while( --i >= 0 ) {
- Node t = rpos.get(i);
- if( !t.isMultiTail() ) { i++; break; }
- printLine( t, sb, llvmFormat );
- }
- sb.append("\n"); // Blank after multitail
- gap = true;
- } else {
- printLine( n, sb, llvmFormat );
- gap = false;
- }
- }
- return sb.toString();
- }
-
- private static void postOrd(Node n, ArrayList<Node> rpos, BitSet visit, BitSet bfs) {
- if( !bfs.get(n._nid) )
- return; // Not in the BFS visit
- if( visit.get(n._nid) ) return; // Already post-order walked
- visit.set(n._nid);
- // First walk the CFG, then everything
- if( n instanceof CFGNode ) {
- for( Node use : n._outputs )
- if( use instanceof CFGNode && use.nOuts() >= 1 && !(use._outputs.get( 0 ) instanceof LoopNode) )
- postOrd(use, rpos,visit,bfs);
- for( Node use : n._outputs )
- if( use instanceof CFGNode )
- postOrd(use,rpos,visit,bfs);
- }
- for( Node use : n._outputs )
- if( use != null )
- postOrd(use, rpos,visit,bfs);
- // Post-order
- rpos.add(n);
- }
-
- // Breadth-first search, broken out in a class to keep in more independent.
- // Maintains a root-set of Nodes at the limit (or past by 1 if MultiHead).
- public static class BFS {
- // A breadth first search, plus MultiHeads for any MultiTails
- public final ArrayList<Node> _bfs;
- public final BitSet _bs; // Visited members by node id
- public final int _depth; // Depth limit
- public final int _lim; // From here to _bfs._len can be roots for a reverse search
- public BFS( Node base, int d ) {
- _depth = d;
- _bfs = new ArrayList<>();
- _bs = new BitSet();
-
- add(base); // Prime the pump
- int idx=0, lim=1; // Limit is where depth counter changes
- while( idx < _bfs.size() ) { // Ran out of nodes below depth
- Node n = _bfs.get(idx++);
- for( Node def : n._inputs )
- if( def!=null && !_bs.get(def._nid) )
- add(def);
- if( idx==lim ) { // Depth counter changes at limit
- if( --d < 0 )
- break; // Ran out of depth
- lim = _bfs.size(); // New depth limit
- }
- }
- // Toss things past the limit except multi-heads
- while( idx < _bfs.size() ) {
- Node n = _bfs.get(idx);
- if( n.isMultiHead() ) idx++;
- else del(idx);
- }
- // Root set is any node with no inputs in the visited set
- lim = _bfs.size();
- for( int i=_bfs.size()-1; i>=0; i-- )
- if( !any_visited(_bfs.get(i)) )
- swap( i,--lim);
- _lim = lim;
- }
- void swap( int x, int y ) {
- if( x==y ) return;
- Node tx = _bfs.get(x);
- Node ty = _bfs.get(y);
- _bfs.set(x,ty);
- _bfs.set(y,tx);
- }
- void add(Node n) {
- _bfs.add(n);
- _bs.set(n._nid);
- }
- void del(int idx) {
- _bs.clear(_bfs.get(idx)._nid);
- Utils.del(_bfs, idx);
- }
- boolean any_visited( Node n ) {
- for( Node def : n._inputs )
- if( def!=null && _bs.get(def._nid) )
- return true;
- return false;
- }
- }
-
- // Diagnostic block ordering from raw control edges. Do not call idepth():
- // it fills compiler caches (and can walk lazy dominator accessors).
- private static int _idepth(CFGNode cfg, HashMap<Integer,Integer> depths) {
- if( cfg == null || cfg instanceof StartNode ) return 0;
- Integer old = depths.get(cfg._nid);
- if( old != null ) return old;
- depths.put(cfg._nid,0); // Break cycles in partially constructed graphs.
- int d = 0;
- if( cfg instanceof LoopNode ) {
- d = _idepth((CFGNode)cfg.in(1),depths)+1;
- } else if( cfg instanceof RegionNode || cfg instanceof StopNode ) {
- for( Node n : cfg._inputs )
- if( n instanceof CFGNode pred ) d = Math.max(d,_idepth(pred,depths)+1);
- } else if( cfg.in(0) instanceof CFGNode pred ) {
- d = _idepth(pred,depths)+1;
- }
- depths.put(cfg._nid,d);
- return d;
- }
-
- // Bulk pretty printer, knowing scheduling information is available
- public static String prettyPrintScheduled( Node node, int depth, boolean llvmFormat ) {
- // Backwards DFS walk to depth.
- HashMap<Integer,Integer> ds = new HashMap<>();
- ArrayList<Node> ns = new ArrayList<>();
- _walk(ds,ns,node,depth);
- // Remove data projections, these are force-printed behind their multinode head
- for( int i=0; i<ns.size(); i++ ) {
- if( ns.get(i) instanceof ProjNode proj && !(proj.in(0) instanceof CFGNode) ) {
- Utils.del(ns,i--);
- ds.remove(proj._nid);
- }
- }
- // Print by block with least diagnostic depth
- HashMap<Integer,Integer> depths = new HashMap<>();
- StringBuilder sb = new StringBuilder();
- ArrayList<Node> bns = new ArrayList<>();
- while( !ds.isEmpty() ) {
- CFGNode blk = null;
- for( Node n : ns ) {
- CFGNode cfg = n instanceof CFGNode cfg0 && cfg0.blockHead() ? cfg0 : n.cfg0();
- if( blk==null || _idepth(cfg,depths) < _idepth(blk,depths) )
- blk = cfg;
- }
- ds.remove(blk._nid);
- ns.remove(blk);
-
- // Print block header
- sb.append("%-13.13s".formatted(label(blk)+":"));
- sb.append( " ".repeat(4) ).append(" [[ ");
- if( blk instanceof StartNode ) ;
- else if( blk instanceof RegionNode || blk instanceof StopNode )
- for( int i=(blk instanceof StopNode ? 0 : 1); i<blk.nIns(); i++ )
- label(sb,blk.cfg(i));
- else
- label(sb,blk.cfg(0));
- sb.append(" ]] \n");
-
- // Collect block contents that are in the depth limit
- bns.clear();
- int xd = Integer.MAX_VALUE;
- for( Node use : blk._outputs ) {
- Integer i = ds.get(use._nid);
- if( i!=null && !(use instanceof CFGNode cfg && cfg.blockHead()) ) {
- bns.add(use);
- xd = Math.min(xd,i);
- }
- }
- // Print Phis up front, if any
- for( int i=0; i<bns.size(); i++ )
- if( bns.get(i) instanceof PhiNode phi )
- printLine( phi, sb, llvmFormat,bns,i--,ds,ns);
-
- // Print block contents in depth order, bumping depth until whole block printed
- for( ; !bns.isEmpty(); xd++ )
- for( int i=0; i<bns.size(); i++ ) {
- Node n = bns.get(i);
- if( ds.get(n._nid)==xd ) {
- printLine( n, sb, llvmFormat, bns, i--, ds,ns );
- if( n instanceof MultiNode && !(n instanceof CFGNode) ) {
- for( Node use : n._outputs ) {
- printLine(use,sb,llvmFormat,bns,bns.indexOf(use),ds,ns);
- }
- }
- }
- }
- sb.append("\n");
- }
- return sb.toString();
- }
-
- private static void _walk( HashMap<Integer,Integer> ds, ArrayList<Node> ns, Node node, int d ) {
- Integer nd = ds.get(node._nid);
- if( nd!=null && d <= nd ) return; // Been there, done that
- if( ds.put(node._nid,d) == null )
- ns.add(node);
- if( d == 0 ) return; // Depth cutoff
- for( Node def : node._inputs )
- if( def != null )
- _walk(ds,ns,def,d-1);
- }
-
- static String label( CFGNode blk ) {
- if( blk instanceof StartNode ) return "START";
- return (blk instanceof LoopNode ? "LOOP" : "L")+blk._nid;
- }
- static void label( StringBuilder sb, CFGNode blk ) {
- if( !blk.blockHead() ) blk = blk.cfg(0);
- sb.append( "%-9.9s ".formatted( label( blk ) ) );
- }
- static void printLine( Node n, StringBuilder sb, boolean llvmFormat, ArrayList<Node> bns, int i, HashMap<Integer,Integer> ds, ArrayList<Node> ns ) {
- printLine( n, sb, llvmFormat );
- if( i != -1 ) Utils.del(bns,i);
- ds.remove(n._nid);
- ns.remove(n);
- }
+/** 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 String type(Node n) { return n._type==null ? "" : n._type.str(); }
+ @Override public String inputMark(Node n, Node def) { return n instanceof MemMergeNode && def instanceof MemMergeNode ? "^" : " "; }
+ @Override public Kind kind(Node n) {
+ if( n instanceof StartNode ) return Kind.START;
+ if( n instanceof StopNode ) return Kind.STOP;
+ if( n instanceof LoopNode ) return Kind.LOOP;
+ if( n instanceof RegionNode ) return Kind.REGION;
+ if( n instanceof PhiNode ) return Kind.PHI;
+ 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;
+ }
+
+ public static String prettyPrint(Node n, int depth) { return PRINT.prettyPrint(n,depth); }
}
diff --git a/chapter17/src/main/java/com/seaofnodes/simple/node/AddFNode.java b/chapter17/src/main/java/com/seaofnodes/simple/node/AddFNode.java
index 5d0a473a..fd713156 100644
--- a/chapter17/src/main/java/com/seaofnodes/simple/node/AddFNode.java
+++ b/chapter17/src/main/java/com/seaofnodes/simple/node/AddFNode.java
@@ -1,21 +1,16 @@
package com.seaofnodes.simple.node;
+
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeFloat;
-import java.util.BitSet;
public class AddFNode extends Node {
public AddFNode(Node lhs, Node rhs) { super(null, lhs, rhs); }
@Override public String label() { return "AddF"; }
- @Override
- StringBuilder _print1(StringBuilder sb, BitSet visited) {
- in(1)._print0(sb.append("("), visited);
- in(2)._print0(sb.append("+"), visited);
- return sb.append(")");
- }
+ @Override protected String format() { return "(%1+%2)"; }
@Override
public Type compute() {
diff --git a/chapter17/src/main/java/com/seaofnodes/simple/node/AddNode.java b/chapter17/src/main/java/com/seaofnodes/simple/node/AddNode.java
index 5becb4c1..5eb0b0a3 100644
--- a/chapter17/src/main/java/com/seaofnodes/simple/node/AddNode.java
+++ b/chapter17/src/main/java/com/seaofnodes/simple/node/AddNode.java
@@ -1,20 +1,15 @@
package com.seaofnodes.simple.node;
+
import com.seaofnodes.simple.type.*;
-import java.util.BitSet;
public class AddNode extends Node {
public AddNode(Node lhs, Node rhs) { super(null, lhs, rhs); }
@Override public String label() { return "Add"; }
- @Override
- StringBuilder _print1(StringBuilder sb, BitSet visited) {
- in(1)._print0(sb.append("("), visited);
- in(2)._print0(sb.append("+"), visited);
- return sb.append(")");
- }
+ @Override protected String format() { return "(%1+%2)"; }
@Override
diff --git a/chapter17/src/main/java/com/seaofnodes/simple/node/AndNode.java b/chapter17/src/main/java/com/seaofnodes/simple/node/AndNode.java
index 8ab44858..bd03d6cb 100644
--- a/chapter17/src/main/java/com/seaofnodes/simple/node/AndNode.java
+++ b/chapter17/src/main/java/com/seaofnodes/simple/node/AndNode.java
@@ -1,21 +1,16 @@
package com.seaofnodes.simple.node;
+
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeInteger;
-import java.util.BitSet;
public class AndNode extends Node {
public AndNode(Node lhs, Node rhs) { super(null, lhs, rhs); }
@Override public String label() { return "And"; }
- @Override
- StringBuilder _print1(StringBuilder sb, BitSet visited) {
- in(1)._print0(sb.append("("), visited);
- in(2)._print0(sb.append("&"), visited);
- return sb.append(")");
- }
+ @Override protected String format() { return "(%1&%2)"; }
@Override
public Type compute() {
diff --git a/chapter17/src/main/java/com/seaofnodes/simple/node/BoolNode.java b/chapter17/src/main/java/com/seaofnodes/simple/node/BoolNode.java
index 5d2212b0..6efde623 100644
--- a/chapter17/src/main/java/com/seaofnodes/simple/node/BoolNode.java
+++ b/chapter17/src/main/java/com/seaofnodes/simple/node/BoolNode.java
@@ -1,5 +1,7 @@
package com.seaofnodes.simple.node;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.Parser;
import com.seaofnodes.simple.Utils;
import com.seaofnodes.simple.type.Type;
@@ -7,7 +9,6 @@ import com.seaofnodes.simple.type.TypeInteger;
import com.seaofnodes.simple.type.TypeFloat;
import com.seaofnodes.simple.type.TypeMemPtr;
-import java.util.BitSet;
import static com.seaofnodes.simple.type.TypeInteger.*;
abstract public class BoolNode extends Node {
@@ -21,11 +22,8 @@ abstract public class BoolNode extends Node {
@Override
public String label() { return getClass().getSimpleName(); }
- @Override
- 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/chapter17/src/main/java/com/seaofnodes/simple/node/CProjNode.java b/chapter17/src/main/java/com/seaofnodes/simple/node/CProjNode.java
index d2f1bbe1..53348b5a 100644
--- a/chapter17/src/main/java/com/seaofnodes/simple/node/CProjNode.java
+++ b/chapter17/src/main/java/com/seaofnodes/simple/node/CProjNode.java
@@ -1,10 +1,11 @@
package com.seaofnodes.simple.node;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.Parser;
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeMem;
import com.seaofnodes.simple.type.TypeTuple;
-import java.util.BitSet;
public class CProjNode extends CFGNode {
@@ -22,7 +23,7 @@ public class CProjNode extends CFGNode {
@Override public String label() { return _label; }
- @Override 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 isMultiTail() { return in(0).isMultiHead(); }
@Override public boolean blockHead() { return true; }
diff --git a/chapter17/src/main/java/com/seaofnodes/simple/node/CastNode.java b/chapter17/src/main/java/com/seaofnodes/simple/node/CastNode.java
index 38d6a126..9ade5a50 100644
--- a/chapter17/src/main/java/com/seaofnodes/simple/node/CastNode.java
+++ b/chapter17/src/main/java/com/seaofnodes/simple/node/CastNode.java
@@ -1,10 +1,11 @@
package com.seaofnodes.simple.node;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeInteger;
import com.seaofnodes.simple.IterPeeps;
-import java.util.BitSet;
// Upcast (join) the input to a t. Used after guard test to lift an input.
// Can also be used to make a type-assertion if ctrl is null.
@@ -18,13 +19,10 @@ public class CastNode extends Node {
@Override public String label() { return "("+_t.str()+")"; }
- @Override
- public String uniqueName() { return "Cast_" + _nid; }
- @Override
- StringBuilder _print1(StringBuilder sb, BitSet visited) {
- return in(1)._print0(sb.append(label()), visited);
+ @Override protected ExprPrinter<Node> _print1(ExprPrinter<Node> p) {
+ return p.p(label()).n(in(1));
}
@Override
diff --git a/chapter17/src/main/java/com/seaofnodes/simple/node/ConstantNode.java b/chapter17/src/main/java/com/seaofnodes/simple/node/ConstantNode.java
index d760c0df..426736ed 100644
--- a/chapter17/src/main/java/com/seaofnodes/simple/node/ConstantNode.java
+++ b/chapter17/src/main/java/com/seaofnodes/simple/node/ConstantNode.java
@@ -1,9 +1,10 @@
package com.seaofnodes.simple.node;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.Parser;
import com.seaofnodes.simple.type.Type;
-import java.util.BitSet;
/**
* A Constant node represents a constant value. At present, the only constants
@@ -24,15 +25,16 @@ public class ConstantNode extends Node {
_con = type;
}
- @Override
- public String label() { return "#"+_con; }
+ @Override protected String repeatName() {
+ return _con==null || _con.toString().length()<=32 ? null : uniqueName();
+ }
@Override
- public String uniqueName() { return "Con_" + _nid; }
+ public String label() { return "Con"; }
- @Override
- StringBuilder _print1(StringBuilder sb, BitSet visited) {
- return _con.print(sb);
+
+ @Override protected ExprPrinter<Node> _print1(ExprPrinter<Node> p) {
+ return p.p(_con);
}
@Override public boolean isMultiTail() { return true; }
diff --git a/chapter17/src/main/java/com/seaofnodes/simple/node/DivFNode.java b/chapter17/src/main/java/com/seaofnodes/simple/node/DivFNode.java
index 6c0c2eb3..a3f4318d 100644
--- a/chapter17/src/main/java/com/seaofnodes/simple/node/DivFNode.java
+++ b/chapter17/src/main/java/com/seaofnodes/simple/node/DivFNode.java
@@ -1,21 +1,16 @@
package com.seaofnodes.simple.node;
+
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeFloat;
-import java.util.BitSet;
public class DivFNode extends Node {
public DivFNode(Node lhs, Node rhs) { super(null, lhs, rhs); }
@Override public String label() { return "DivF"; }
- @Override
- StringBuilder _print1(StringBuilder sb, BitSet visited) {
- in(1)._print0(sb.append("("), visited);
- in(2)._print0(sb.append("/"), visited);
- return sb.append(")");
- }
+ @Override protected String format() { return "(%1/%2)"; }
@Override
public Type compute() {
diff --git a/chapter17/src/main/java/com/seaofnodes/simple/node/DivNode.java b/chapter17/src/main/java/com/seaofnodes/simple/node/DivNode.java
index d13dcacf..cd749a03 100644
--- a/chapter17/src/main/java/com/seaofnodes/simple/node/DivNode.java
+++ b/chapter17/src/main/java/com/seaofnodes/simple/node/DivNode.java
@@ -1,21 +1,16 @@
package com.seaofnodes.simple.node;
+
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeInteger;
-import java.util.BitSet;
public class DivNode extends Node {
public DivNode(Node lhs, Node rhs) { super(null, lhs, rhs); }
@Override public String label() { return "Div"; }
- @Override
- StringBuilder _print1(StringBuilder sb, BitSet visited) {
- in(1)._print0(sb.append("("), visited);
- in(2)._print0(sb.append("/"), visited);
- return sb.append(")");
- }
+ @Override protected String format() { return "(%1/%2)"; }
@Override
public Type compute() {
diff --git a/chapter17/src/main/java/com/seaofnodes/simple/node/IfNode.java b/chapter17/src/main/java/com/seaofnodes/simple/node/IfNode.java
index 513b4721..2b53b3a3 100644
--- a/chapter17/src/main/java/com/seaofnodes/simple/node/IfNode.java
+++ b/chapter17/src/main/java/com/seaofnodes/simple/node/IfNode.java
@@ -1,10 +1,10 @@
package com.seaofnodes.simple.node;
+
import com.seaofnodes.simple.IterPeeps;
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeInteger;
import com.seaofnodes.simple.type.TypeTuple;
-import java.util.BitSet;
import java.util.HashSet;
public class IfNode extends CFGNode implements MultiNode {
@@ -17,11 +17,7 @@ public class IfNode extends CFGNode implements MultiNode {
@Override
public String label() { return "If"; }
- @Override
- StringBuilder _print1(StringBuilder sb, BitSet visited) {
- sb.append("if( ");
- return in(1)._print0(sb, visited).append(" )");
- }
+ @Override protected String format() { return "if( %1 )"; }
@Override public boolean isMultiHead() { return true; }
diff --git a/chapter17/src/main/java/com/seaofnodes/simple/node/LoadNode.java b/chapter17/src/main/java/com/seaofnodes/simple/node/LoadNode.java
index 2b430df4..c5cc381a 100644
--- a/chapter17/src/main/java/com/seaofnodes/simple/node/LoadNode.java
+++ b/chapter17/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.Utils;
import com.seaofnodes.simple.IterPeeps;
import com.seaofnodes.simple.type.*;
@@ -46,7 +48,7 @@ public class LoadNode extends MemOpNode {
// Debugger label
@Override public String label() { return "ld_"+mlabel(); }
@Override
- 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/chapter17/src/main/java/com/seaofnodes/simple/node/MemMergeNode.java b/chapter17/src/main/java/com/seaofnodes/simple/node/MemMergeNode.java
index ff040b99..faf456de 100644
--- a/chapter17/src/main/java/com/seaofnodes/simple/node/MemMergeNode.java
+++ b/chapter17/src/main/java/com/seaofnodes/simple/node/MemMergeNode.java
@@ -1,9 +1,10 @@
package com.seaofnodes.simple.node;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.IterPeeps;
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeMem;
-import java.util.BitSet;
/** A default slice and explicit alias overrides. A null default means partial
* memory: absent aliases are not covered, rather than having unknown contents.
@@ -53,14 +54,14 @@ public class MemMergeNode extends Node {
@Override public String label() { return "MemMerge"; }
@Override public boolean isMem() { return true; }
@Override public Type compute() { return TypeMem.BOT; }
- @Override StringBuilder _print1(StringBuilder sb, BitSet visited) {
- sb.append("MEM[");
+ @Override protected ExprPrinter<Node> _print1(ExprPrinter<Node> p) {
+ p.p("MEM[");
for( int i=1; i<nIns(); i++ )
if( in(i)!=null ) {
- sb.append(i==1 ? "default:" : i+":");
- in(i)._print0(sb,visited).append(" ");
+ p.p(i==1 ? "default:" : i+":");
+ p.n(in(i)).p(" ");
}
- return sb.append("]");
+ return p.p("]");
}
@Override public Node idealize() {
diff --git a/chapter17/src/main/java/com/seaofnodes/simple/node/MinusFNode.java b/chapter17/src/main/java/com/seaofnodes/simple/node/MinusFNode.java
index 7cacf2c9..1b45c7c5 100644
--- a/chapter17/src/main/java/com/seaofnodes/simple/node/MinusFNode.java
+++ b/chapter17/src/main/java/com/seaofnodes/simple/node/MinusFNode.java
@@ -1,20 +1,16 @@
package com.seaofnodes.simple.node;
+
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeFloat;
-import java.util.BitSet;
public class MinusFNode extends Node {
public MinusFNode(Node in) { super(null, in); }
@Override public String label() { return "MinusF"; }
- @Override
- 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/chapter17/src/main/java/com/seaofnodes/simple/node/MinusNode.java b/chapter17/src/main/java/com/seaofnodes/simple/node/MinusNode.java
index a9e21814..b85af74e 100644
--- a/chapter17/src/main/java/com/seaofnodes/simple/node/MinusNode.java
+++ b/chapter17/src/main/java/com/seaofnodes/simple/node/MinusNode.java
@@ -1,21 +1,17 @@
package com.seaofnodes.simple.node;
+
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeInteger;
import com.seaofnodes.simple.Utils;
-import java.util.BitSet;
public class MinusNode extends Node {
public MinusNode(Node in) { super(null, in); }
@Override public String label() { return "Minus"; }
- @Override
- 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/chapter17/src/main/java/com/seaofnodes/simple/node/MulFNode.java b/chapter17/src/main/java/com/seaofnodes/simple/node/MulFNode.java
index 4b753ba7..6a57f3c5 100644
--- a/chapter17/src/main/java/com/seaofnodes/simple/node/MulFNode.java
+++ b/chapter17/src/main/java/com/seaofnodes/simple/node/MulFNode.java
@@ -1,21 +1,16 @@
package com.seaofnodes.simple.node;
+
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeFloat;
-import java.util.BitSet;
public class MulFNode extends Node {
public MulFNode(Node lhs, Node rhs) { super(null, lhs, rhs); }
@Override public String label() { return "MulF"; }
- @Override
- StringBuilder _print1(StringBuilder sb, BitSet visited) {
- in(1)._print0(sb.append("("), visited);
- in(2)._print0(sb.append("*"), visited);
- return sb.append(")");
- }
+ @Override protected String format() { return "(%1*%2)"; }
@Override
public Type compute() {
diff --git a/chapter17/src/main/java/com/seaofnodes/simple/node/MulNode.java b/chapter17/src/main/java/com/seaofnodes/simple/node/MulNode.java
index 65898907..a9ac07e6 100644
--- a/chapter17/src/main/java/com/seaofnodes/simple/node/MulNode.java
+++ b/chapter17/src/main/java/com/seaofnodes/simple/node/MulNode.java
@@ -1,21 +1,16 @@
package com.seaofnodes.simple.node;
+
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeInteger;
-import java.util.BitSet;
public class MulNode extends Node {
public MulNode(Node lhs, Node rhs) { super(null, lhs, rhs); }
@Override public String label() { return "Mul"; }
- @Override
- StringBuilder _print1(StringBuilder sb, BitSet visited) {
- in(1)._print0(sb.append("("), visited);
- in(2)._print0(sb.append("*"), visited);
- return sb.append(")");
- }
+ @Override protected String format() { return "(%1*%2)"; }
@Override
public Type compute() {
diff --git a/chapter17/src/main/java/com/seaofnodes/simple/node/NeverNode.java b/chapter17/src/main/java/com/seaofnodes/simple/node/NeverNode.java
index e77ed653..7e42ccf9 100644
--- a/chapter17/src/main/java/com/seaofnodes/simple/node/NeverNode.java
+++ b/chapter17/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 {
@@ -13,7 +14,7 @@ public class NeverNode extends IfNode {
@Override public String label() { return "Never"; }
- @Override 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/chapter17/src/main/java/com/seaofnodes/simple/node/NewNode.java b/chapter17/src/main/java/com/seaofnodes/simple/node/NewNode.java
index bdccc681..51341c41 100644
--- a/chapter17/src/main/java/com/seaofnodes/simple/node/NewNode.java
+++ b/chapter17/src/main/java/com/seaofnodes/simple/node/NewNode.java
@@ -1,7 +1,8 @@
package com.seaofnodes.simple.node;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.type.*;
-import java.util.BitSet;
/** Allocate and initialize an object. Inputs {ctrl, $mem, size, fields...};
* results {ptr, $mem}.
@@ -33,10 +34,8 @@ public class NewNode extends Node implements MultiNode {
@Override public String label() {
return "new_"+(_ptr._obj.isAry() ? "ary_"+_ptr._obj._fields[1]._type.str() : _ptr._obj.str());
}
- @Override
- StringBuilder _print1(StringBuilder sb, BitSet visited) {
- sb.append("new ");
- return sb.append(_ptr._obj.str());
+ @Override protected ExprPrinter<Node> _print1(ExprPrinter<Node> p) {
+ return p.p("new ").p(_ptr._obj.str());
}
// Find matching alias input
diff --git a/chapter17/src/main/java/com/seaofnodes/simple/node/Node.java b/chapter17/src/main/java/com/seaofnodes/simple/node/Node.java
index dc952d87..bd1fdffa 100644
--- a/chapter17/src/main/java/com/seaofnodes/simple/node/Node.java
+++ b/chapter17/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.Parser;
import com.seaofnodes.simple.Ary;
@@ -16,14 +18,7 @@ import java.util.function.Function;
* The Node class provides common functionality used by all subtypes.
* Subtypes of Node specialize by overriding methods.
*/
-public abstract class Node implements OutNode, 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 OutNode, Cloneable {
/**
* Inputs to the node. These are use-def references to Nodes.
@@ -45,14 +40,12 @@ public abstract class Node implements OutNode, 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;
-
/**
* A private Global Static mutable counter, for unique node id generation.
* To make the compiler multithreaded, this field will have to move into a TLS.
@@ -62,7 +55,7 @@ public abstract class Node implements OutNode, Cloneable {
public static int UID() { return UNIQUE_ID; }
protected Node(Node... inputs) {
- _nid = UNIQUE_ID++; // allocate unique dense ID
+ super(UNIQUE_ID++); // allocate unique dense ID
_inputs = new Ary<>(Node.class);
Collections.addAll(_inputs,inputs);
_outputs = new Ary<>(Node.class);
@@ -74,40 +67,6 @@ public abstract class Node implements OutNode, Cloneable {
// Easy reading label for debugger, e.g. "Add" or "Region" or "EQ"
public abstract String label();
- // Unique label for debugging, e.g. "Add12" or "Region30" or "EQ99"
- public String uniqueName() {
- return label() + _nid;
- }
-
- // ------------------------------------------------------------------------
-
- // 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 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.
- 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 StringBuilder _print1(StringBuilder sb, BitSet visited);
-
public String p(int depth) { return IRPrinter.prettyPrint(this,depth); }
public boolean isMultiHead() { return false; }
@@ -116,6 +75,8 @@ public abstract class Node implements OutNode, 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
@@ -188,7 +149,6 @@ public abstract class Node implements OutNode, Cloneable {
return setDef(idx,new_def);
}
-
/**
* Add a new def to an existing Node. Keep the edges correct by
* adding the corresponding <em>def->use</em> edge.
@@ -266,7 +226,6 @@ public abstract class Node implements OutNode, Cloneable {
kill();
}
-
// Replace self with nnn in the graph, making 'this' go dead
public void subsume( Node nnn ) {
assert nnn!=this;
@@ -398,7 +357,6 @@ public abstract class Node implements OutNode, Cloneable {
return old;
}
-
/**
* This function rewrites the current Node into a more "idealized" form.
* This is the bulk of our peephole rewrite rules, and we use this to
@@ -446,7 +404,6 @@ public abstract class Node implements OutNode, 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
@@ -490,7 +447,6 @@ public abstract class Node implements OutNode, Cloneable {
_deps.clear();
}
-
// Global Value Numbering. Hash over opcode and inputs; hits in this table
// are structurally equal.
public static final HashMap<Node,Node> GVN = new HashMap<>();
@@ -512,7 +468,6 @@ public abstract class Node implements OutNode, Cloneable {
// and can assume "this!=n" and has the same Java class.
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
@@ -528,7 +483,6 @@ public abstract class Node implements OutNode, Cloneable {
_hash=0; // Out of table now
}
-
// Hash of opcode and inputs
@Override public final int hashCode() {
if( _hash != 0 ) return _hash;
@@ -548,7 +502,6 @@ public abstract class Node implements OutNode, Cloneable {
/** Is this Node Memory related */
public boolean isMem() { return false; }
-
// Semantic change to the graph (so NOT a peephole), used by the Parser.
// If any input is a float, flip to a float-flavored opcode and widen any
// non-float input.
@@ -569,7 +522,6 @@ public abstract class Node implements OutNode, Cloneable {
}
Node copyF() { return null; }
-
// ------------------------------------------------------------------------
// Peephole utilities
@@ -598,7 +550,6 @@ public abstract class Node implements OutNode, 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.
@@ -631,7 +582,6 @@ public abstract class Node implements OutNode, Cloneable {
ITER_CNT = ITER_NOP_CNT = 0;
}
-
// Utility to walk the entire graph applying a function; return the first
// not-null result.
private static final BitSet WVISIT = new BitSet();
diff --git a/chapter17/src/main/java/com/seaofnodes/simple/node/NotNode.java b/chapter17/src/main/java/com/seaofnodes/simple/node/NotNode.java
index 3f4b291c..b9cf4904 100644
--- a/chapter17/src/main/java/com/seaofnodes/simple/node/NotNode.java
+++ b/chapter17/src/main/java/com/seaofnodes/simple/node/NotNode.java
@@ -1,19 +1,15 @@
package com.seaofnodes.simple.node;
+
import com.seaofnodes.simple.Utils;
import com.seaofnodes.simple.type.*;
-import java.util.BitSet;
public class NotNode extends Node {
public NotNode(Node in) { super(null, in); }
@Override public String label() { return "Not"; }
- @Override
- 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/chapter17/src/main/java/com/seaofnodes/simple/node/OrNode.java b/chapter17/src/main/java/com/seaofnodes/simple/node/OrNode.java
index 301514f4..5be31b88 100644
--- a/chapter17/src/main/java/com/seaofnodes/simple/node/OrNode.java
+++ b/chapter17/src/main/java/com/seaofnodes/simple/node/OrNode.java
@@ -1,21 +1,16 @@
package com.seaofnodes.simple.node;
+
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeInteger;
-import java.util.BitSet;
public class OrNode extends Node {
public OrNode(Node lhs, Node rhs) { super(null, lhs, rhs); }
@Override public String label() { return "Or"; }
- @Override
- StringBuilder _print1(StringBuilder sb, BitSet visited) {
- in(1)._print0(sb.append("("), visited);
- in(2)._print0(sb.append("|"), visited);
- return sb.append(")");
- }
+ @Override protected String format() { return "(%1|%2)"; }
@Override
public Type compute() {
diff --git a/chapter17/src/main/java/com/seaofnodes/simple/node/PhiNode.java b/chapter17/src/main/java/com/seaofnodes/simple/node/PhiNode.java
index c6cbd3dd..942748e7 100644
--- a/chapter17/src/main/java/com/seaofnodes/simple/node/PhiNode.java
+++ b/chapter17/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.type.Type;
import com.seaofnodes.simple.type.TypeMem;
import com.seaofnodes.simple.Utils;
-import java.util.BitSet;
public class PhiNode extends Node {
@@ -23,18 +24,12 @@ public class PhiNode extends Node {
@Override public String label() { return "Phi_"+MemOpNode.mlabel(_label); }
@Override
- 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/chapter17/src/main/java/com/seaofnodes/simple/node/ProjNode.java b/chapter17/src/main/java/com/seaofnodes/simple/node/ProjNode.java
index cd57b85c..668e20ad 100644
--- a/chapter17/src/main/java/com/seaofnodes/simple/node/ProjNode.java
+++ b/chapter17/src/main/java/com/seaofnodes/simple/node/ProjNode.java
@@ -1,10 +1,11 @@
package com.seaofnodes.simple.node;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeMem;
import com.seaofnodes.simple.type.TypeTuple;
-import java.util.BitSet;
public class ProjNode extends Node {
@@ -23,7 +24,7 @@ public class ProjNode extends Node {
@Override public String label() { return _label; }
@Override
- StringBuilder _print1(StringBuilder sb, BitSet visited) { return sb.append(_label); }
+ protected ExprPrinter<Node> _print1(ExprPrinter<Node> p) { return p.p(_label); }
@Override public CFGNode cfg0() { return in(0).cfg0(); }
diff --git a/chapter17/src/main/java/com/seaofnodes/simple/node/ReadOnlyNode.java b/chapter17/src/main/java/com/seaofnodes/simple/node/ReadOnlyNode.java
index fddcaa67..fa4e0242 100644
--- a/chapter17/src/main/java/com/seaofnodes/simple/node/ReadOnlyNode.java
+++ b/chapter17/src/main/java/com/seaofnodes/simple/node/ReadOnlyNode.java
@@ -1,9 +1,9 @@
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( Node n ) { super(null,n); }
@Override public String label() { return "ReadOnly"; }
- @Override
- 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/chapter17/src/main/java/com/seaofnodes/simple/node/RegionNode.java b/chapter17/src/main/java/com/seaofnodes/simple/node/RegionNode.java
index 2155bd94..27866139 100644
--- a/chapter17/src/main/java/com/seaofnodes/simple/node/RegionNode.java
+++ b/chapter17/src/main/java/com/seaofnodes/simple/node/RegionNode.java
@@ -1,12 +1,13 @@
package com.seaofnodes.simple.node;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.IterPeeps;
import com.seaofnodes.simple.Parser;
import com.seaofnodes.simple.Utils;
import com.seaofnodes.simple.type.Type;
import java.util.ArrayList;
import java.util.Arrays;
-import java.util.BitSet;
import java.util.HashSet;
public class RegionNode extends CFGNode {
@@ -16,9 +17,8 @@ public class RegionNode extends CFGNode {
@Override
public String label() { return "Region"; }
- @Override
- 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 isMultiHead() { return true; }
diff --git a/chapter17/src/main/java/com/seaofnodes/simple/node/ReturnNode.java b/chapter17/src/main/java/com/seaofnodes/simple/node/ReturnNode.java
index 1049fa18..6c773c42 100644
--- a/chapter17/src/main/java/com/seaofnodes/simple/node/ReturnNode.java
+++ b/chapter17/src/main/java/com/seaofnodes/simple/node/ReturnNode.java
@@ -1,8 +1,9 @@
package com.seaofnodes.simple.node;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.type.*;
-import java.util.BitSet;
/** Keeps all preceding memory effects and the return value alive: {ctrl, $mem, value}. */
public class ReturnNode extends CFGNode {
@@ -20,10 +21,10 @@ public class ReturnNode extends CFGNode {
public String label() { return "Return"; }
@Override
- StringBuilder _print1(StringBuilder sb, BitSet visited) {
- sb.append("return ");
- expr()._print0(sb, visited);
- return sb.append(";");
+ protected ExprPrinter<Node> _print1(ExprPrinter<Node> p) {
+ p.p("return ");
+ p.n(expr());
+ return p.p(";");
}
@Override
diff --git a/chapter17/src/main/java/com/seaofnodes/simple/node/RoundF32Node.java b/chapter17/src/main/java/com/seaofnodes/simple/node/RoundF32Node.java
index 3dd7cbf0..78e7698c 100644
--- a/chapter17/src/main/java/com/seaofnodes/simple/node/RoundF32Node.java
+++ b/chapter17/src/main/java/com/seaofnodes/simple/node/RoundF32Node.java
@@ -1,19 +1,16 @@
package com.seaofnodes.simple.node;
+
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeFloat;
-import java.util.BitSet;
public class RoundF32Node extends Node {
public RoundF32Node(Node lhs) { super(null, lhs); }
@Override public String label() { return "RoundF32"; }
- @Override
- 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/chapter17/src/main/java/com/seaofnodes/simple/node/SarNode.java b/chapter17/src/main/java/com/seaofnodes/simple/node/SarNode.java
index 25ef55e3..44233b3d 100644
--- a/chapter17/src/main/java/com/seaofnodes/simple/node/SarNode.java
+++ b/chapter17/src/main/java/com/seaofnodes/simple/node/SarNode.java
@@ -1,21 +1,16 @@
package com.seaofnodes.simple.node;
+
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeInteger;
-import java.util.BitSet;
public class SarNode extends Node {
public SarNode(Node lhs, Node rhs) { super(null, lhs, rhs); }
@Override public String label() { return "Sar"; }
- @Override
- StringBuilder _print1(StringBuilder sb, BitSet visited) {
- in(1)._print0(sb.append("("), visited);
- in(2)._print0(sb.append(">>"), visited);
- return sb.append(")");
- }
+ @Override protected String format() { return "(%1>>%2)"; }
@Override
public Type compute() {
diff --git a/chapter17/src/main/java/com/seaofnodes/simple/node/ScopeNode.java b/chapter17/src/main/java/com/seaofnodes/simple/node/ScopeNode.java
index d44535dc..b539ff87 100644
--- a/chapter17/src/main/java/com/seaofnodes/simple/node/ScopeNode.java
+++ b/chapter17/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.IterPeeps;
import com.seaofnodes.simple.Parser;
import com.seaofnodes.simple.Ary;
@@ -77,28 +79,26 @@ public class ScopeNode extends Node {
@Override public String label() { return "Scope"; }
@Override
- StringBuilder _print1(StringBuilder sb, BitSet visited) {
- sb.append("Scope[ ");
+ protected ExprPrinter<Node> _print1(ExprPrinter<Node> p) {
+ p.p("Scope[ ");
int j=1;
for( int i=0; i<nIns(); i++ ) {
- if( j < _lexSize._len && i == _lexSize.at(j) ) { sb.append("| "); j++; }
+ if( j < _lexSize._len && i == _lexSize.at(j) ) { p.p("| "); j++; }
Var v = _vars.get(i);
- v.type().print(sb);
- 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/chapter17/src/main/java/com/seaofnodes/simple/node/ShlNode.java b/chapter17/src/main/java/com/seaofnodes/simple/node/ShlNode.java
index 1b2ed6ea..65dfe684 100644
--- a/chapter17/src/main/java/com/seaofnodes/simple/node/ShlNode.java
+++ b/chapter17/src/main/java/com/seaofnodes/simple/node/ShlNode.java
@@ -1,21 +1,16 @@
package com.seaofnodes.simple.node;
+
import com.seaofnodes.simple.Parser;
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeInteger;
-import java.util.BitSet;
public class ShlNode extends Node {
public ShlNode(Node lhs, Node rhs) { super(null, lhs, rhs); }
@Override public String label() { return "Shl"; }
- @Override
- StringBuilder _print1(StringBuilder sb, BitSet visited) {
- in(1)._print0(sb.append("("), visited);
- in(2)._print0(sb.append("<<"), visited);
- return sb.append(")");
- }
+ @Override protected String format() { return "(%1<<%2)"; }
@Override
public Type compute() {
diff --git a/chapter17/src/main/java/com/seaofnodes/simple/node/ShrNode.java b/chapter17/src/main/java/com/seaofnodes/simple/node/ShrNode.java
index e60882d4..757fd69e 100644
--- a/chapter17/src/main/java/com/seaofnodes/simple/node/ShrNode.java
+++ b/chapter17/src/main/java/com/seaofnodes/simple/node/ShrNode.java
@@ -1,21 +1,16 @@
package com.seaofnodes.simple.node;
+
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeInteger;
-import java.util.BitSet;
public class ShrNode extends Node {
public ShrNode(Node lhs, Node rhs) { super(null, lhs, rhs); }
@Override public String label() { return "Shr"; }
- @Override
- StringBuilder _print1(StringBuilder sb, BitSet visited) {
- in(1)._print0(sb.append("("), visited);
- in(2)._print0(sb.append(">>>"), visited);
- return sb.append(")");
- }
+ @Override protected String format() { return "(%1>>>%2)"; }
@Override
public Type compute() {
diff --git a/chapter17/src/main/java/com/seaofnodes/simple/node/StartNode.java b/chapter17/src/main/java/com/seaofnodes/simple/node/StartNode.java
index 0dd10c22..cefa2d72 100644
--- a/chapter17/src/main/java/com/seaofnodes/simple/node/StartNode.java
+++ b/chapter17/src/main/java/com/seaofnodes/simple/node/StartNode.java
@@ -1,7 +1,8 @@
package com.seaofnodes.simple.node;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.type.*;
-import java.util.BitSet;
import java.util.HashSet;
import static com.seaofnodes.simple.Utils.TODO;
@@ -14,9 +15,8 @@ public class StartNode extends LoopNode implements MultiNode {
@Override public String label() { return "Start"; }
- @Override
- 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 isMultiHead() { return true; }
diff --git a/chapter17/src/main/java/com/seaofnodes/simple/node/StopNode.java b/chapter17/src/main/java/com/seaofnodes/simple/node/StopNode.java
index e498141e..d0eb5750 100644
--- a/chapter17/src/main/java/com/seaofnodes/simple/node/StopNode.java
+++ b/chapter17/src/main/java/com/seaofnodes/simple/node/StopNode.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.Parser;
import com.seaofnodes.simple.IterPeeps;
import com.seaofnodes.simple.GlobalCodeMotion;
-import java.util.BitSet;
public class StopNode extends CFGNode {
@@ -22,12 +23,12 @@ public class StopNode extends CFGNode {
}
@Override
- StringBuilder _print1(StringBuilder sb, BitSet visited) {
- if( ret()!=null ) return ret()._print0(sb, visited);
- sb.append("Stop[ ");
+ protected ExprPrinter<Node> _print1(ExprPrinter<Node> p) {
+ if( ret()!=null ) return p.n(ret());
+ p.p("Stop[ ");
for( Node ret : _inputs )
- ret._print0(sb, visited).append(" ");
- return sb.append("]");
+ p.n(ret).p(" ");
+ return p.p("]");
}
@Override public boolean blockHead() { return true; }
diff --git a/chapter17/src/main/java/com/seaofnodes/simple/node/StoreNode.java b/chapter17/src/main/java/com/seaofnodes/simple/node/StoreNode.java
index 4ec106ac..48c8927f 100644
--- a/chapter17/src/main/java/com/seaofnodes/simple/node/StoreNode.java
+++ b/chapter17/src/main/java/com/seaofnodes/simple/node/StoreNode.java
@@ -1,10 +1,11 @@
package com.seaofnodes.simple.node;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.Utils;
import com.seaofnodes.simple.IterPeeps;
import com.seaofnodes.simple.type.*;
-import java.util.BitSet;
/**
* Store represents setting a value to a memory based object, in chapter 10
@@ -37,8 +38,8 @@ public class StoreNode extends MemOpNode {
public Node val() { return in(4); }
@Override
- 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/chapter17/src/main/java/com/seaofnodes/simple/node/StructNode.java b/chapter17/src/main/java/com/seaofnodes/simple/node/StructNode.java
index db170ab1..429b49cc 100644
--- a/chapter17/src/main/java/com/seaofnodes/simple/node/StructNode.java
+++ b/chapter17/src/main/java/com/seaofnodes/simple/node/StructNode.java
@@ -1,7 +1,8 @@
package com.seaofnodes.simple.node;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.type.*;
-import java.util.BitSet;
/**
* Build a compound object
@@ -13,16 +14,15 @@ public class StructNode extends Node {
@Override public String label() { return _ts==null ? "STRUCT?" : _ts.str(); }
@Override
- StringBuilder _print1(StringBuilder sb, BitSet visited) {
- if( _ts==null ) return sb.append("STRUCT?");
- sb.append(_ts._name).append(" {");
+ protected ExprPrinter<Node> _print1(ExprPrinter<Node> p) {
+ if( _ts==null ) return p.p("STRUCT?");
+ p.p(_ts._name).p(" {");
for( int i=0; i<nIns(); i++ ) {
- sb.append(_ts._fields[i]._fname).append(":");
- (in(i)==null ? Type.BOTTOM : in(i)._type).print(sb);
- sb.append("; ");
+ p.p(_ts._fields[i]._fname).p(":");
+ p.p(in(i)==null ? Type.BOTTOM : in(i)._type);
+ p.p("; ");
}
- sb.setLength(sb.length()-2);
- return sb.append("}");
+ return p.unchar("; ").p("}");
}
@Override
diff --git a/chapter17/src/main/java/com/seaofnodes/simple/node/SubFNode.java b/chapter17/src/main/java/com/seaofnodes/simple/node/SubFNode.java
index 27bbda8d..2d218a03 100644
--- a/chapter17/src/main/java/com/seaofnodes/simple/node/SubFNode.java
+++ b/chapter17/src/main/java/com/seaofnodes/simple/node/SubFNode.java
@@ -1,21 +1,16 @@
package com.seaofnodes.simple.node;
+
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeFloat;
-import java.util.BitSet;
public class SubFNode extends Node {
public SubFNode(Node lhs, Node rhs) { super(null, lhs, rhs); }
@Override public String label() { return "SubF"; }
- @Override
- StringBuilder _print1(StringBuilder sb, BitSet visited) {
- in(1)._print0(sb.append("("), visited);
- in(2)._print0(sb.append("-"), visited);
- return sb.append(")");
- }
+ @Override protected String format() { return "(%1-%2)"; }
@Override
public Type compute() {
diff --git a/chapter17/src/main/java/com/seaofnodes/simple/node/SubNode.java b/chapter17/src/main/java/com/seaofnodes/simple/node/SubNode.java
index 2f2a7a05..768cb2bf 100644
--- a/chapter17/src/main/java/com/seaofnodes/simple/node/SubNode.java
+++ b/chapter17/src/main/java/com/seaofnodes/simple/node/SubNode.java
@@ -1,22 +1,17 @@
package com.seaofnodes.simple.node;
+
import com.seaofnodes.simple.Parser;
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeInteger;
-import java.util.BitSet;
public class SubNode extends Node {
public SubNode(Node lhs, Node rhs) { super(null, lhs, rhs); }
@Override public String label() { return "Sub"; }
- @Override
- StringBuilder _print1(StringBuilder sb, BitSet visited) {
- in(1)._print0(sb.append("("), visited);
- in(2)._print0(sb.append("-"), visited);
- return sb.append(")");
- }
+ @Override protected String format() { return "(%1-%2)"; }
@Override
public Type compute() {
diff --git a/chapter17/src/main/java/com/seaofnodes/simple/node/ToFloatNode.java b/chapter17/src/main/java/com/seaofnodes/simple/node/ToFloatNode.java
index fde483d6..26cf50e1 100644
--- a/chapter17/src/main/java/com/seaofnodes/simple/node/ToFloatNode.java
+++ b/chapter17/src/main/java/com/seaofnodes/simple/node/ToFloatNode.java
@@ -1,20 +1,17 @@
package com.seaofnodes.simple.node;
+
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeFloat;
import com.seaofnodes.simple.type.TypeInteger;
-import java.util.BitSet;
public class ToFloatNode extends Node {
public ToFloatNode(Node lhs) { super(null, lhs); }
@Override public String label() { return "ToFloat"; }
- @Override
- 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/chapter17/src/main/java/com/seaofnodes/simple/node/XCtrlNode.java b/chapter17/src/main/java/com/seaofnodes/simple/node/XCtrlNode.java
index 83779dd2..056dfba1 100644
--- a/chapter17/src/main/java/com/seaofnodes/simple/node/XCtrlNode.java
+++ b/chapter17/src/main/java/com/seaofnodes/simple/node/XCtrlNode.java
@@ -1,13 +1,14 @@
package com.seaofnodes.simple.node;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.Parser;
import com.seaofnodes.simple.type.Type;
-import java.util.BitSet;
public class XCtrlNode extends CFGNode {
public XCtrlNode( ) { super(Parser.START); }
@Override public String label() { return "Xctrl"; }
- @Override StringBuilder _print1(StringBuilder sb, BitSet visited) { return sb.append("Xctrl"); }
+ @Override protected ExprPrinter<Node> _print1(ExprPrinter<Node> p) { return p.p("Xctrl"); }
@Override public Type compute() { return Type.XCONTROL; }
@Override public Node idealize() { return null; }
}
diff --git a/chapter17/src/main/java/com/seaofnodes/simple/node/XorNode.java b/chapter17/src/main/java/com/seaofnodes/simple/node/XorNode.java
index 71dce586..ef7273b8 100644
--- a/chapter17/src/main/java/com/seaofnodes/simple/node/XorNode.java
+++ b/chapter17/src/main/java/com/seaofnodes/simple/node/XorNode.java
@@ -1,21 +1,16 @@
package com.seaofnodes.simple.node;
+
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeInteger;
-import java.util.BitSet;
public class XorNode extends Node {
public XorNode(Node lhs, Node rhs) { super(null, lhs, rhs); }
@Override public String label() { return "Xor"; }
- @Override
- StringBuilder _print1(StringBuilder sb, BitSet visited) {
- in(1)._print0(sb.append("("), visited);
- in(2)._print0(sb.append("^"), visited);
- return sb.append(")");
- }
+ @Override protected String format() { return "(%1^%2)"; }
@Override
public Type compute() {
diff --git a/chapter17/src/main/java/com/seaofnodes/simple/print/SimpleGraphAdapter.java b/chapter17/src/main/java/com/seaofnodes/simple/print/SimpleGraphAdapter.java
index 55961293..7ba58e6f 100644
--- a/chapter17/src/main/java/com/seaofnodes/simple/print/SimpleGraphAdapter.java
+++ b/chapter17/src/main/java/com/seaofnodes/simple/print/SimpleGraphAdapter.java
@@ -1,43 +1,21 @@
package com.seaofnodes.simple.print;
import com.seaofnodes.graph.GraphAdapter;
-import com.seaofnodes.graph.GraphSnapshot;
import com.seaofnodes.graph.GraphSnapshot.*;
import com.seaofnodes.simple.node.*;
import com.seaofnodes.simple.node.Node;
import com.seaofnodes.simple.type.TypeMem;
-import java.util.ArrayList;
/** Chapter 17's view of the IR; browser, transport and layout are shared. */
public class SimpleGraphAdapter extends GraphAdapter<Node> {
- @Override protected boolean dead(Node n) { return n.isDead(); }
- @Override protected int id(Node n) { return n._nid; }
- @Override protected int nIns(Node n) { return n.nIns(); }
- @Override protected Node in(Node n, int idx) { return n.in(idx); }
- @Override protected int nOuts(Node n) { return n.nOuts(); }
- @Override protected Node out(Node n, int idx) { return n.out(idx); }
- @Override protected int nDeps(Node n) { return n.nDeps(); }
- @Override protected Node dep(Node n, int idx) { return n.dep(idx); }
- private ArrayList<Edge> edges(Node n) {
- var edges = new ArrayList<Edge>();
- for( int i = 0; i < n.nIns(); i++ ) {
- String name = n instanceof ScopeNode scope && i < scope._vars.size()
+ @Override protected String edgeName(Node n, int i) {
+ return n instanceof ScopeNode scope && i < scope._vars.size()
? scope._vars.get(i)._name : null;
- edges.add(new Edge(i, ref(n.in(i)), role(n, i), name));
- }
- return edges;
}
+ @Override protected int projectionIndex(Node n) { return n instanceof ProjNode p ? p._idx : n instanceof CProjNode p ? p._idx : -1; }
- @Override protected GraphSnapshot.Node desc(Node n) {
- Projection proj = n instanceof ProjNode p ? new Projection(ref(n.in(0)), p._idx)
- : n instanceof CProjNode p ? new Projection(ref(n.in(0)), p._idx) : null;
- String label = n.label();
- return new GraphSnapshot.Node(n._nid, label == null ? n.getClass().getSimpleName() : label,
- n._type == null ? null : n._type.toString(), kind(n), edges(n), proj);
- }
-
- 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 StartNode ) return Kind.CTRL;
@@ -47,7 +25,7 @@ public class SimpleGraphAdapter extends GraphAdapter<Node> {
return n instanceof CFGNode ? Kind.CTRL : isMem(n) ? Kind.MEM : Kind.DATA;
}
- private Role role(Node n, int i) {
+ @Override protected Role role(Node n, int i) {
if( n instanceof ScopeNode || n instanceof ConstantNode || n instanceof XCtrlNode ) return Role.ASSOC;
if( n instanceof PhiNode ) return i == 0 ? Role.ASSOC : isMem(n) ? Role.MEM : Role.DATA;
if( n instanceof ProjNode || n instanceof CProjNode )
diff --git a/chapter18/Makefile b/chapter18/Makefile
index b1ec855b..11a698a8 100644
--- a/chapter18/Makefile
+++ b/chapter18/Makefile
@@ -38,6 +38,7 @@ main_javas := $(wildcard $(SRC)/$(SIMPLE)/*java $(SRC)/$(SIMPLE)/*/*java)
test_javas := $(wildcard $(TST)/$(SIMPLE)/*java $(TST)/$(SIMPLE)/*/*java)
main_classes := $(patsubst $(SRC)/%java,$(CLZDIR)/main/%class,$(main_javas))
include $(firstword $(wildcard ../graph/graph.mk graph/graph.mk))
+include $(firstword $(wildcard ../print/print.mk print/print.mk))
test_classes := $(patsubst $(TST)/%java,$(CLZDIR)/test/%class,$(test_javas))
test_cp := $(patsubst $(TST)/$(SIMPLE)/%.java,com.seaofnodes.simple.%,$(wildcard $(TST)/$(SIMPLE)/*Test.java))
classes = $(main_classes) $(test_classes)
@@ -55,7 +56,7 @@ endif
default: $(default_targets)
# Compile just the out-of-date files
-$(main_classes): build/classes/main/%class: $(SRC)/%java $(graph_javas)
+$(main_classes): build/classes/main/%class: $(SRC)/%java $(graph_javas) $(print_javas)
@echo "compiling " $@ " because " $?
@[ -d $(CLZDIR)/main ] || mkdir -p $(CLZDIR)/main
@javac $(JAVAC_ARGS) -cp "$(CLZDIR)/main$(SEP)$(jars)" -sourcepath $(SRC) -d $(CLZDIR)/main $(main_javas)
diff --git a/chapter18/pom.xml b/chapter18/pom.xml
index e7b4afaa..ae907664 100644
--- a/chapter18/pom.xml
+++ b/chapter18/pom.xml
@@ -13,5 +13,6 @@
<name>Chapter 18</name>
<properties>
<simple.graph.directory>${project.basedir}/../graph</simple.graph.directory>
+ <simple.print.directory>${project.basedir}/../print</simple.print.directory>
</properties>
</project>
diff --git a/chapter18/src/main/java/com/seaofnodes/simple/CodeGen.java b/chapter18/src/main/java/com/seaofnodes/simple/CodeGen.java
index a9dfe476..864b3a1a 100644
--- a/chapter18/src/main/java/com/seaofnodes/simple/CodeGen.java
+++ b/chapter18/src/main/java/com/seaofnodes/simple/CodeGen.java
@@ -129,7 +129,7 @@ public class CodeGen {
// Debugging helper
@Override public String toString() {
- return _stop.p(9999);
+ return IRPrinter.prettyPrint(this);
}
// Debugging helper
diff --git a/chapter18/src/main/java/com/seaofnodes/simple/IRPrinter.java b/chapter18/src/main/java/com/seaofnodes/simple/IRPrinter.java
index bedc7de9..c7ca8cf4 100644
--- a/chapter18/src/main/java/com/seaofnodes/simple/IRPrinter.java
+++ b/chapter18/src/main/java/com/seaofnodes/simple/IRPrinter.java
@@ -1,301 +1,54 @@
package com.seaofnodes.simple;
+import com.seaofnodes.print.IRAdapter;
import com.seaofnodes.simple.node.*;
-import com.seaofnodes.simple.type.TypeFunPtr;
import java.util.ArrayList;
-import java.util.BitSet;
-import java.util.HashMap;
-
-public 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 ) {
- sb.p("%4d %-7.7s ".formatted(n._nid,n.label()));
- if( n.isDead() )
- return sb.p("DEAD\n");
- for( Node def : n._inputs )
- sb.p(def==null ? "____" : "%4d".formatted(def._nid))
- // Lazy Phi indicator
- .p(n instanceof MemMergeNode && def instanceof MemMergeNode ? "^" : " ");
- for( int i = n._inputs.size(); i<4; i++ )
- sb.p(" ");
- sb.p(" [[ ");
- for( Node use : n._outputs )
- sb.p(use==null ? "____ " : "%4d ".formatted(use._nid));
- int lim = 6 - Math.max(n._inputs.size(),4);
- for( int i = n._outputs.size(); i<lim; i++ )
- sb.p(" ");
- sb.p(" ]] ");
- if( n._type!= null ) sb.p(n._type.str());
- return sb.p("\n");
- }
-
-
- public static String prettyPrint(Node node, int depth) {
- return CodeGen.CODE._phase.ordinal() > CodeGen.Phase.Schedule.ordinal()
- ? _prettyPrintScheduled( node, depth )
- : _prettyPrint( node, depth );
- }
-
- // Another bulk pretty-printer. Makes more effort at basic-block grouping.
- private static String _prettyPrint( Node node, int depth ) {
- // First, a Breadth First Search at a fixed depth.
- BFS bfs = new BFS(node,depth);
- // Convert just that set to a post-order
- ArrayList<Node> rpos = new ArrayList<>();
- BitSet visit = new BitSet();
- for( int i=bfs._lim; i< bfs._bfs.size(); i++ )
- postOrd( bfs._bfs.get(i), null, rpos, visit, bfs._bs);
- // Reverse the post-order walk
- SB sb = new SB();
- boolean gap=false;
- for( int i=rpos.size()-1; i>=0; i-- ) {
- Node n = rpos.get(i);
- if( n instanceof CFGNode || n.isMultiHead() ) {
- if( !gap ) sb.p("\n"); // Blank before multihead
- if( n instanceof FunNode fun ) {
- TypeFunPtr sig = fun.sig();
- sig.print(sb.p("--- ").p(sig._name==null ? "" : sig._name).p(" "),false).p("----------------------\n");
- }
- printLine( n, sb ); // Print head
- while( --i >= 0 ) {
- Node t = rpos.get(i);
- if( !t.isMultiTail() ) { i++; break; }
- printLine( t, sb );
- }
- if( n instanceof ReturnNode ret ) {
- TypeFunPtr sig = ret.fun().sig();
- sig.print(sb.p("--- ").p(sig._name==null ? "" : sig._name).p(" "),false).p("----------------------\n");
- }
- if( !(n instanceof CallNode) ) {
- sb.p("\n"); // Blank after multitail
- gap = true;
- }
- } else {
- printLine( n, sb );
- gap = false;
- }
- }
- return sb.toString();
- }
-
- private static void postOrd(Node n, Node prior, ArrayList<Node> rpos, BitSet visit, BitSet bfs) {
- if( !bfs.get(n._nid) )
- return; // Not in the BFS visit
- if( n instanceof FunNode && !(prior instanceof StartNode) )
- return; // Only visit Fun from Start
- if( visit.get(n._nid) ) return; // Already post-order walked
- visit.set(n._nid);
- // First walk the CFG, then everything
- if( n instanceof CFGNode ) {
- for( Node use : n._outputs )
- // Follow CFG, not across call/function borders, and not around backedges
- if( use instanceof CFGNode && !(n instanceof CallNode && use instanceof FunNode) &&
- use.nOuts() >= 1 && !(use._outputs.get(0) instanceof LoopNode) )
- postOrd(use, n, rpos,visit,bfs);
- for( Node use : n._outputs )
- // Follow CFG, not across call/function borders
- if( use instanceof CFGNode && !(n instanceof CallNode && use instanceof FunNode) )
- postOrd(use,n,rpos,visit,bfs);
- }
- // Follow all outputs
- for( Node use : n._outputs )
- if( use != null &&
- !(n instanceof CallNode && use instanceof FunNode) &&
- (n instanceof FunNode || !(use instanceof ParmNode)) )
- postOrd(use, n, rpos,visit,bfs);
- // Post-order
- rpos.add(n);
- }
-
- // Breadth-first search, broken out in a class to keep in more independent.
- // Maintains a root-set of Nodes at the limit (or past by 1 if MultiHead).
- public static class BFS {
- // A breadth first search, plus MultiHeads for any MultiTails
- public final ArrayList<Node> _bfs;
- public final BitSet _bs; // Visited members by node id
- public final int _depth; // Depth limit
- public final int _lim; // From here to _bfs._len can be roots for a reverse search
- public BFS( Node base, int d ) {
- _depth = d;
- _bfs = new ArrayList<>();
- _bs = new BitSet();
-
- add(base); // Prime the pump
- int idx=0, lim=1; // Limit is where depth counter changes
- while( idx < _bfs.size() ) { // Ran out of nodes below depth
- Node n = _bfs.get(idx++);
- for( Node def : n._inputs )
- if( def!=null && !_bs.get(def._nid) )
- add(def);
- if( idx==lim ) { // Depth counter changes at limit
- if( --d < 0 )
- break; // Ran out of depth
- lim = _bfs.size(); // New depth limit
- }
- }
- // Toss things past the limit except multi-heads
- while( idx < _bfs.size() ) {
- Node n = _bfs.get(idx);
- if( n.isMultiHead() ) idx++;
- else del(idx);
- }
- // Root set is any node with no inputs in the visited set
- lim = _bfs.size();
- for( int i=_bfs.size()-1; i>=0; i-- )
- if( !any_visited(_bfs.get(i)) )
- swap( i,--lim);
- _lim = lim;
- }
- void swap( int x, int y ) {
- if( x==y ) return;
- Node tx = _bfs.get(x);
- Node ty = _bfs.get(y);
- _bfs.set(x,ty);
- _bfs.set(y,tx);
- }
- void add(Node n) {
- _bfs.add(n);
- _bs.set(n._nid);
- }
- void del(int idx) {
- _bs.clear(_bfs.get(idx)._nid);
- Utils.del(_bfs, idx);
- }
- boolean any_visited( Node n ) {
- for( Node def : n._inputs )
- if( def!=null && _bs.get(def._nid) )
- return true;
- return false;
- }
- }
-
- // Diagnostic block ordering from raw control edges. Do not call idepth():
- // it fills compiler caches (and can walk lazy dominator accessors).
- private static int _idepth(CFGNode cfg, HashMap<Integer,Integer> depths) {
- if( cfg == null || cfg instanceof StartNode || cfg instanceof FunNode ) return cfg instanceof FunNode ? 1 : 0;
- Integer old = depths.get(cfg._nid);
- if( old != null ) return old;
- depths.put(cfg._nid,0); // Break cycles in partially constructed graphs.
- int d = 0;
- if( cfg instanceof LoopNode ) {
- d = _idepth((CFGNode)cfg.in(1),depths)+1;
- } else if( cfg instanceof RegionNode || cfg instanceof StopNode ) {
- for( Node n : cfg._inputs )
- if( n instanceof CFGNode pred ) d = Math.max(d,_idepth(pred,depths)+1);
- } else if( cfg.in(0) instanceof CFGNode pred ) {
- d = _idepth(pred,depths)+1;
- }
- depths.put(cfg._nid,d);
- return d;
+import com.seaofnodes.simple.SB;
+import com.seaofnodes.simple.CodeGen;
+
+/** This chapter's read-only IR facts and the familiar debugger entry points. */
+public final class IRPrinter extends IRAdapter<Node> {
+ private static final com.seaofnodes.print.IRPrinter<Node> PRINT =
+ new com.seaofnodes.print.IRPrinter<>(new IRPrinter());
+ @Override public String type(Node n) { return n._type==null ? "" : n._type.str(); }
+ @Override public String inputMark(Node n, Node def) { return n instanceof MemMergeNode && def instanceof MemMergeNode ? "^" : " "; }
+ @Override public Kind kind(Node n) {
+ if( n instanceof StartNode ) return Kind.START;
+ if( n instanceof StopNode ) return Kind.STOP;
+ if( n instanceof FunNode ) return Kind.FUN;
+ if( n instanceof LoopNode ) return Kind.LOOP;
+ if( n instanceof RegionNode ) return Kind.REGION;
+ if( n instanceof ParmNode ) return Kind.PARM;
+ if( n instanceof PhiNode ) return Kind.PHI;
+ if( n instanceof CallEndNode ) return Kind.CALL_END;
+ if( n instanceof CallNode ) return Kind.CALL;
+ if( n instanceof ReturnNode ) return Kind.RETURN;
+ if( n instanceof ConstantNode ) return Kind.CONSTANT;
+ if( n instanceof CProjNode ) return Kind.CPROJ;
+ if( n instanceof ProjNode ) return n instanceof CFGNode ? Kind.CPROJ : Kind.PROJ;
+ if( n instanceof CFGNode ) return Kind.CTRL;
+ if( n instanceof MultiNode ) return Kind.MULTI;
+ return Kind.DATA;
+ }
+ @Override public int index(Node n) {
+ if( n instanceof ProjNode p ) return p._idx;
+ if( n instanceof CProjNode p ) return p._idx;
+ return n._nid;
+ }
+ @Override public String functionName(Node n) { return n.label(); }
+ @Override public String signature(Node n) {
+ FunNode fun=(FunNode)n;
+ return fun.sig().str();
+ }
+
+ public static String prettyPrint(Node n, int depth) { return PRINT.prettyPrint(n,depth); }
+ public static SB printLine(Node n, SB sb) { return sb.p(PRINT.line(n)); }
+
+ public static String prettyPrint(CodeGen code) {
+ var units=new ArrayList<com.seaofnodes.print.IRPrinter.Unit<Node>>();
+ var funs=new ArrayList<Node>();
+ for( Node n : code._start._outputs ) if( n instanceof FunNode ) funs.add(n);
+ units.add(new com.seaofnodes.print.IRPrinter.Unit<>(null,null,null,funs));
+ return PRINT.program(code._start,code._stop,units);
}
-
- // Bulk pretty printer, knowing scheduling information is available
- private static String _prettyPrintScheduled( Node node, int depth ) {
- // Backwards DFS walk to depth.
- HashMap<Integer,Integer> ds = new HashMap<>();
- ArrayList<Node> ns = new ArrayList<>();
- _walk(ds,ns,node,depth);
- // Remove data projections, these are force-printed behind their multinode head
- for( int i=0; i<ns.size(); i++ ) {
- if( ns.get(i) instanceof ProjNode proj && !(proj.in(0) instanceof CFGNode) ) {
- Utils.del(ns,i--);
- ds.remove(proj._nid);
- }
- }
- // Print by block with least diagnostic depth
- HashMap<Integer,Integer> depths = new HashMap<>();
- SB sb = new SB();
- Ary<Node> bns = new Ary<>(Node.class);
- while( !ds.isEmpty() ) {
- CFGNode blk = null;
- for( Node n : ns ) {
- CFGNode cfg = n instanceof CFGNode cfg0 && cfg0.blockHead() ? cfg0 : n.cfg0();
- if( blk==null || _idepth(cfg,depths) < _idepth(blk,depths) || (blk instanceof FunNode && !(cfg instanceof FunNode)))
- blk = cfg;
- }
- Integer d = ds.remove(blk._nid);
- ns.remove(blk);
-
- // Print block header
- sb.p("%-13.13s".formatted(label(blk)+":"));
- sb.p( " ".repeat(4) ).p(" [[ ");
- if( blk instanceof StartNode ) ;
- else if( blk instanceof RegionNode || blk instanceof StopNode )
- for( int i=(blk instanceof StopNode ? 3 : 1); i<blk.nIns(); i++ )
- label(sb,blk.cfg(i));
- else
- label(sb,blk.cfg(0));
- sb.p(" ]] \n");
- printLine(blk,sb);
-
- // Collect block contents that are in the depth limit
- bns.clear();
- int xd = Integer.MAX_VALUE;
- for( Node use : blk._outputs ) {
- Integer i = ds.get(use._nid);
- if( i!=null && !(use instanceof CFGNode cfg && cfg.blockHead()) ) {
- if( bns.find(use)==-1 )
- bns.add(use);
- xd = Math.min(xd,i);
- }
- }
- // Print Phis up front, if any
- for( int i=0; i<bns.size(); i++ )
- if( bns.get(i) instanceof PhiNode phi )
- printLine( phi, sb,bns,i--,ds,ns);
-
- // Print block contents in depth order, bumping depth until whole block printed
- for( ; !bns.isEmpty(); xd++ )
- for( int i=0; i<bns.size(); i++ ) {
- Node n = bns.get(i);
- if( ds.get(n._nid)==xd ) {
- printLine( n, sb, bns, i--, ds,ns );
- if( n instanceof MultiNode && !(n instanceof CFGNode) ) {
- for( Node use : n._outputs ) {
- printLine(use,sb,bns,bns.indexOf(use),ds,ns);
- }
- }
- }
- }
- sb.p("\n");
- }
- return sb.toString();
- }
-
- private static void _walk( HashMap<Integer,Integer> ds, ArrayList<Node> ns, Node node, int d ) {
- Integer nd = ds.get(node._nid);
- if( nd!=null && d <= nd ) return; // Been there, done that
- Integer old = ds.put(node._nid,d) ;
- if( old == null )
- ns.add(node);
- if( d == 0 ) return; // Depth cutoff
- for( Node def : node._inputs )
- if( def != null &&
- !(node instanceof LoopNode loop && loop.back()==def) &&
- // Don't walk into or out of functions
- !(node instanceof CallEndNode && def instanceof ReturnNode) &&
- !(node instanceof FunNode && def instanceof CallNode) &&
- !(node instanceof ParmNode && !(def instanceof FunNode))
- )
- _walk(ds,ns,def,d-1);
- }
-
- static String label( CFGNode blk ) {
- if( blk instanceof StartNode ) return "START";
- return (blk instanceof LoopNode ? "LOOP" : "L")+blk._nid;
- }
- static void label( SB sb, CFGNode blk ) {
- if( !blk.blockHead() ) blk = blk.cfg(0);
- sb.p( "%-9.9s ".formatted( label( blk ) ) );
- }
- static void printLine( Node n, SB sb, Ary<Node> bns, int i, HashMap<Integer,Integer> ds, ArrayList<Node> ns ) {
- printLine( n, sb );
- if( i != -1 ) bns.del(i);
- ds.remove(n._nid);
- ns.remove(n);
- }
-
}
diff --git a/chapter18/src/main/java/com/seaofnodes/simple/node/AddFNode.java b/chapter18/src/main/java/com/seaofnodes/simple/node/AddFNode.java
index 5d0a473a..fd713156 100644
--- a/chapter18/src/main/java/com/seaofnodes/simple/node/AddFNode.java
+++ b/chapter18/src/main/java/com/seaofnodes/simple/node/AddFNode.java
@@ -1,21 +1,16 @@
package com.seaofnodes.simple.node;
+
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeFloat;
-import java.util.BitSet;
public class AddFNode extends Node {
public AddFNode(Node lhs, Node rhs) { super(null, lhs, rhs); }
@Override public String label() { return "AddF"; }
- @Override
- StringBuilder _print1(StringBuilder sb, BitSet visited) {
- in(1)._print0(sb.append("("), visited);
- in(2)._print0(sb.append("+"), visited);
- return sb.append(")");
- }
+ @Override protected String format() { return "(%1+%2)"; }
@Override
public Type compute() {
diff --git a/chapter18/src/main/java/com/seaofnodes/simple/node/AddNode.java b/chapter18/src/main/java/com/seaofnodes/simple/node/AddNode.java
index c3c0254d..08c4d356 100644
--- a/chapter18/src/main/java/com/seaofnodes/simple/node/AddNode.java
+++ b/chapter18/src/main/java/com/seaofnodes/simple/node/AddNode.java
@@ -1,20 +1,15 @@
package com.seaofnodes.simple.node;
+
import com.seaofnodes.simple.Parser;
import com.seaofnodes.simple.type.*;
-import java.util.BitSet;
public class AddNode extends Node {
public AddNode(Node lhs, Node rhs) { super(null, lhs, rhs); }
@Override public String label() { return "Add"; }
- @Override
- StringBuilder _print1(StringBuilder sb, BitSet visited) {
- in(1)._print0(sb.append("("), visited);
- in(2)._print0(sb.append("+"), visited);
- return sb.append(")");
- }
+ @Override protected String format() { return "(%1+%2)"; }
@Override
diff --git a/chapter18/src/main/java/com/seaofnodes/simple/node/BoolNode.java b/chapter18/src/main/java/com/seaofnodes/simple/node/BoolNode.java
index 0a885a6a..aa577f61 100644
--- a/chapter18/src/main/java/com/seaofnodes/simple/node/BoolNode.java
+++ b/chapter18/src/main/java/com/seaofnodes/simple/node/BoolNode.java
@@ -1,10 +1,11 @@
package com.seaofnodes.simple.node;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.Parser;
import com.seaofnodes.simple.Utils;
import com.seaofnodes.simple.type.*;
-import java.util.BitSet;
import static com.seaofnodes.simple.type.TypeInteger.*;
abstract public class BoolNode extends Node {
@@ -18,11 +19,8 @@ abstract public class BoolNode extends Node {
@Override
public String label() { return getClass().getSimpleName(); }
- @Override
- 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/chapter18/src/main/java/com/seaofnodes/simple/node/CProjNode.java b/chapter18/src/main/java/com/seaofnodes/simple/node/CProjNode.java
index 01119310..70238f8c 100644
--- a/chapter18/src/main/java/com/seaofnodes/simple/node/CProjNode.java
+++ b/chapter18/src/main/java/com/seaofnodes/simple/node/CProjNode.java
@@ -1,10 +1,11 @@
package com.seaofnodes.simple.node;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.Parser;
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeMem;
import com.seaofnodes.simple.type.TypeTuple;
-import java.util.BitSet;
public class CProjNode extends CFGNode implements MultiUse {
@@ -23,7 +24,7 @@ public class CProjNode extends CFGNode implements MultiUse {
@Override public String label() { return _label; }
@Override public int idx() { return _idx; }
- @Override 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 isMultiTail() { return in(0).isMultiHead(); }
@Override public boolean blockHead() { return true; }
diff --git a/chapter18/src/main/java/com/seaofnodes/simple/node/CallEndNode.java b/chapter18/src/main/java/com/seaofnodes/simple/node/CallEndNode.java
index 54d76bbe..2da09cfc 100644
--- a/chapter18/src/main/java/com/seaofnodes/simple/node/CallEndNode.java
+++ b/chapter18/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.CodeGen;
import com.seaofnodes.simple.IterPeeps;
import com.seaofnodes.simple.Parser;
import com.seaofnodes.simple.Utils;
import com.seaofnodes.simple.type.*;
-import java.util.BitSet;
/**
* CallEnd
@@ -26,13 +27,12 @@ public class CallEndNode extends CFGNode implements MultiNode {
CallNode call() { return (CallNode)in(0); }
@Override
- 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/chapter18/src/main/java/com/seaofnodes/simple/node/CallNode.java b/chapter18/src/main/java/com/seaofnodes/simple/node/CallNode.java
index 246398ee..442a22e5 100644
--- a/chapter18/src/main/java/com/seaofnodes/simple/node/CallNode.java
+++ b/chapter18/src/main/java/com/seaofnodes/simple/node/CallNode.java
@@ -1,12 +1,13 @@
package com.seaofnodes.simple.node;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.CodeGen;
import com.seaofnodes.simple.IterPeeps;
import com.seaofnodes.simple.Parser;
import com.seaofnodes.simple.Utils;
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeFunPtr;
-import java.util.BitSet;
/**
* Call
@@ -22,18 +23,17 @@ public class CallNode extends CFGNode {
public String label() { return "Call"; }
@Override
- StringBuilder _print1(StringBuilder sb, BitSet visited) {
+ protected ExprPrinter<Node> _print1(ExprPrinter<Node> p) {
String fname = null;
Node fptr = fptr();
if( fptr._type instanceof TypeFunPtr tfp && tfp.isConstant() )
fname = tfp._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();
}
Node ctrl() { return in(0); }
diff --git a/chapter18/src/main/java/com/seaofnodes/simple/node/CastNode.java b/chapter18/src/main/java/com/seaofnodes/simple/node/CastNode.java
index 6438abb5..6bf8ee90 100644
--- a/chapter18/src/main/java/com/seaofnodes/simple/node/CastNode.java
+++ b/chapter18/src/main/java/com/seaofnodes/simple/node/CastNode.java
@@ -1,10 +1,11 @@
package com.seaofnodes.simple.node;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.Parser;
import com.seaofnodes.simple.Utils;
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeInteger;
-import java.util.BitSet;
// Upcast (join) the input to a t. Used after guard test to lift an input.
// Can also be used to make a type-assertion if ctrl is null.
@@ -18,14 +19,11 @@ public class CastNode extends Node {
@Override public String label() { return "("+_t.str()+")"; }
- @Override
- public String uniqueName() { return "Cast_" + _nid; }
@Override public boolean isConst() { return true; }
- @Override
- StringBuilder _print1(StringBuilder sb, BitSet visited) {
- return in(1)._print0(sb.append(label()), visited);
+ @Override protected ExprPrinter<Node> _print1(ExprPrinter<Node> p) {
+ return p.p(label()).n(in(1));
}
@Override
diff --git a/chapter18/src/main/java/com/seaofnodes/simple/node/ConstantNode.java b/chapter18/src/main/java/com/seaofnodes/simple/node/ConstantNode.java
index 83747871..02d0289b 100644
--- a/chapter18/src/main/java/com/seaofnodes/simple/node/ConstantNode.java
+++ b/chapter18/src/main/java/com/seaofnodes/simple/node/ConstantNode.java
@@ -1,10 +1,11 @@
package com.seaofnodes.simple.node;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.Parser;
import com.seaofnodes.simple.SB;
import com.seaofnodes.simple.type.Type;
-import java.util.BitSet;
/**
* A Constant node represents a constant value. At present, the only constants
@@ -31,13 +32,14 @@ public class ConstantNode extends Node {
return new ConstantNode(type);
}
- @Override public String label() { return "#"+_con; }
- @Override
- public String uniqueName() { return "Con_" + _nid; }
+ @Override protected String repeatName() {
+ return _con==null || _con.toString().length()<=32 ? null : uniqueName();
+ }
- @Override
- StringBuilder _print1(StringBuilder sb, BitSet visited) {
- return sb.append(_con.print(new SB()));
+ @Override public String label() { return "Con"; }
+
+ @Override protected ExprPrinter<Node> _print1(ExprPrinter<Node> p) {
+ return p.p(_con.print(new SB()));
}
@Override public boolean isMultiTail() { return true; }
diff --git a/chapter18/src/main/java/com/seaofnodes/simple/node/CtrlNode.java b/chapter18/src/main/java/com/seaofnodes/simple/node/CtrlNode.java
index 162417bb..9268381a 100644
--- a/chapter18/src/main/java/com/seaofnodes/simple/node/CtrlNode.java
+++ b/chapter18/src/main/java/com/seaofnodes/simple/node/CtrlNode.java
@@ -1,13 +1,14 @@
package com.seaofnodes.simple.node;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.Parser;
import com.seaofnodes.simple.type.Type;
-import java.util.BitSet;
public class CtrlNode extends CFGNode {
public CtrlNode() { super(Parser.START); }
@Override public String label() { return "Ctrl"; }
- @Override 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/chapter18/src/main/java/com/seaofnodes/simple/node/DivFNode.java b/chapter18/src/main/java/com/seaofnodes/simple/node/DivFNode.java
index 6c0c2eb3..a3f4318d 100644
--- a/chapter18/src/main/java/com/seaofnodes/simple/node/DivFNode.java
+++ b/chapter18/src/main/java/com/seaofnodes/simple/node/DivFNode.java
@@ -1,21 +1,16 @@
package com.seaofnodes.simple.node;
+
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeFloat;
-import java.util.BitSet;
public class DivFNode extends Node {
public DivFNode(Node lhs, Node rhs) { super(null, lhs, rhs); }
@Override public String label() { return "DivF"; }
- @Override
- StringBuilder _print1(StringBuilder sb, BitSet visited) {
- in(1)._print0(sb.append("("), visited);
- in(2)._print0(sb.append("/"), visited);
- return sb.append(")");
- }
+ @Override protected String format() { return "(%1/%2)"; }
@Override
public Type compute() {
diff --git a/chapter18/src/main/java/com/seaofnodes/simple/node/DivNode.java b/chapter18/src/main/java/com/seaofnodes/simple/node/DivNode.java
index 69b151cd..f0ee21e1 100644
--- a/chapter18/src/main/java/com/seaofnodes/simple/node/DivNode.java
+++ b/chapter18/src/main/java/com/seaofnodes/simple/node/DivNode.java
@@ -1,20 +1,15 @@
package com.seaofnodes.simple.node;
+
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeInteger;
-import java.util.BitSet;
public class DivNode extends Node {
public DivNode(Node lhs, Node rhs) { super(null, lhs, rhs); }
@Override public String label() { return "Div"; }
- @Override
- StringBuilder _print1(StringBuilder sb, BitSet visited) {
- in(1)._print0(sb.append("("), visited);
- in(2)._print0(sb.append("/"), visited);
- return sb.append(")");
- }
+ @Override protected String format() { return "(%1/%2)"; }
@Override
public Type compute() {
diff --git a/chapter18/src/main/java/com/seaofnodes/simple/node/FRefNode.java b/chapter18/src/main/java/com/seaofnodes/simple/node/FRefNode.java
index f0c4045d..bf1c5a00 100644
--- a/chapter18/src/main/java/com/seaofnodes/simple/node/FRefNode.java
+++ b/chapter18/src/main/java/com/seaofnodes/simple/node/FRefNode.java
@@ -1,9 +1,10 @@
package com.seaofnodes.simple.node;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.Parser;
import com.seaofnodes.simple.Var;
import com.seaofnodes.simple.type.Type;
-import java.util.BitSet;
/**
* A Forward Reference. Its any final constant, including functions. When
@@ -17,10 +18,9 @@ public class FRefNode extends ConstantNode {
@Override public String label() { return "FRef"+_n; }
- @Override public String uniqueName() { return "FRef_" + _nid; }
- @Override StringBuilder _print1(StringBuilder sb, BitSet visited) {
- return sb.append("FRef_").append(_n);
+ @Override protected ExprPrinter<Node> _print1(ExprPrinter<Node> p) {
+ return p.p("FRef_").p(_n);
}
@Override public Node idealize() {
diff --git a/chapter18/src/main/java/com/seaofnodes/simple/node/IfNode.java b/chapter18/src/main/java/com/seaofnodes/simple/node/IfNode.java
index c49ee662..a3061b63 100644
--- a/chapter18/src/main/java/com/seaofnodes/simple/node/IfNode.java
+++ b/chapter18/src/main/java/com/seaofnodes/simple/node/IfNode.java
@@ -1,8 +1,8 @@
package com.seaofnodes.simple.node;
+
import com.seaofnodes.simple.IterPeeps;
import com.seaofnodes.simple.type.*;
-import java.util.BitSet;
import java.util.HashSet;
public class IfNode extends CFGNode implements MultiNode {
@@ -15,11 +15,7 @@ public class IfNode extends CFGNode implements MultiNode {
@Override
public String label() { return "If"; }
- @Override
- StringBuilder _print1(StringBuilder sb, BitSet visited) {
- sb.append("if( ");
- return in(1)._print0(sb, visited).append(" )");
- }
+ @Override protected String format() { return "if( %1 )"; }
@Override public boolean isMultiHead() { return true; }
diff --git a/chapter18/src/main/java/com/seaofnodes/simple/node/LoadNode.java b/chapter18/src/main/java/com/seaofnodes/simple/node/LoadNode.java
index 0ec7c826..0fab82c3 100644
--- a/chapter18/src/main/java/com/seaofnodes/simple/node/LoadNode.java
+++ b/chapter18/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.Utils;
import com.seaofnodes.simple.IterPeeps;
@@ -47,7 +49,7 @@ public class LoadNode extends MemOpNode {
// Debugger label
@Override public String label() { return "ld_"+mlabel(); }
@Override
- 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/chapter18/src/main/java/com/seaofnodes/simple/node/LogicalNode.java b/chapter18/src/main/java/com/seaofnodes/simple/node/LogicalNode.java
index ccc1f6b5..c59bd948 100644
--- a/chapter18/src/main/java/com/seaofnodes/simple/node/LogicalNode.java
+++ b/chapter18/src/main/java/com/seaofnodes/simple/node/LogicalNode.java
@@ -1,9 +1,10 @@
package com.seaofnodes.simple.node;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.Parser;
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeInteger;
-import java.util.BitSet;
public abstract class LogicalNode extends Node {
// Source location for late reported errors
@@ -12,11 +13,8 @@ public abstract class LogicalNode extends Node {
public LogicalNode(Parser.Lexer loc, Node lhs, Node rhs) { super(null, lhs, rhs); _loc = loc; }
abstract String op();
- @Override
- 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();
}
diff --git a/chapter18/src/main/java/com/seaofnodes/simple/node/MemMergeNode.java b/chapter18/src/main/java/com/seaofnodes/simple/node/MemMergeNode.java
index 07d703f6..5cb908bb 100644
--- a/chapter18/src/main/java/com/seaofnodes/simple/node/MemMergeNode.java
+++ b/chapter18/src/main/java/com/seaofnodes/simple/node/MemMergeNode.java
@@ -1,9 +1,10 @@
package com.seaofnodes.simple.node;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.IterPeeps;
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeMem;
-import java.util.BitSet;
/** A default slice and explicit alias overrides. A null default means partial
* memory: absent aliases are not covered, rather than having unknown contents.
@@ -52,14 +53,14 @@ public class MemMergeNode extends Node {
@Override public String label() { return "MemMerge"; }
@Override public boolean isMem() { return true; }
@Override public Type compute() { return TypeMem.BOT; }
- @Override StringBuilder _print1(StringBuilder sb, BitSet visited) {
- sb.append("MEM[");
+ @Override protected ExprPrinter<Node> _print1(ExprPrinter<Node> p) {
+ p.p("MEM[");
for( int i=1; i<nIns(); i++ )
if( in(i)!=null ) {
- sb.append(i==1 ? "default:" : i+":");
- in(i)._print0(sb,visited).append(" ");
+ p.p(i==1 ? "default:" : i+":");
+ p.n(in(i)).p(" ");
}
- return sb.append("]");
+ return p.p("]");
}
@Override public Node idealize() {
diff --git a/chapter18/src/main/java/com/seaofnodes/simple/node/MinusFNode.java b/chapter18/src/main/java/com/seaofnodes/simple/node/MinusFNode.java
index 129963c2..852e646d 100644
--- a/chapter18/src/main/java/com/seaofnodes/simple/node/MinusFNode.java
+++ b/chapter18/src/main/java/com/seaofnodes/simple/node/MinusFNode.java
@@ -1,20 +1,16 @@
package com.seaofnodes.simple.node;
+
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeFloat;
-import java.util.BitSet;
public class MinusFNode extends Node {
public MinusFNode(Node in) { super(null, in); }
@Override public String label() { return "MinusF"; }
- @Override
- 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/chapter18/src/main/java/com/seaofnodes/simple/node/MinusNode.java b/chapter18/src/main/java/com/seaofnodes/simple/node/MinusNode.java
index dad245fd..20220915 100644
--- a/chapter18/src/main/java/com/seaofnodes/simple/node/MinusNode.java
+++ b/chapter18/src/main/java/com/seaofnodes/simple/node/MinusNode.java
@@ -1,21 +1,17 @@
package com.seaofnodes.simple.node;
+
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeInteger;
import com.seaofnodes.simple.Utils;
-import java.util.BitSet;
public class MinusNode extends Node {
public MinusNode(Node in) { super(null, in); }
@Override public String label() { return "Minus"; }
- @Override
- 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/chapter18/src/main/java/com/seaofnodes/simple/node/MulFNode.java b/chapter18/src/main/java/com/seaofnodes/simple/node/MulFNode.java
index 4b753ba7..6a57f3c5 100644
--- a/chapter18/src/main/java/com/seaofnodes/simple/node/MulFNode.java
+++ b/chapter18/src/main/java/com/seaofnodes/simple/node/MulFNode.java
@@ -1,21 +1,16 @@
package com.seaofnodes.simple.node;
+
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeFloat;
-import java.util.BitSet;
public class MulFNode extends Node {
public MulFNode(Node lhs, Node rhs) { super(null, lhs, rhs); }
@Override public String label() { return "MulF"; }
- @Override
- StringBuilder _print1(StringBuilder sb, BitSet visited) {
- in(1)._print0(sb.append("("), visited);
- in(2)._print0(sb.append("*"), visited);
- return sb.append(")");
- }
+ @Override protected String format() { return "(%1*%2)"; }
@Override
public Type compute() {
diff --git a/chapter18/src/main/java/com/seaofnodes/simple/node/MulNode.java b/chapter18/src/main/java/com/seaofnodes/simple/node/MulNode.java
index 89e35cf2..51dd96cf 100644
--- a/chapter18/src/main/java/com/seaofnodes/simple/node/MulNode.java
+++ b/chapter18/src/main/java/com/seaofnodes/simple/node/MulNode.java
@@ -1,21 +1,16 @@
package com.seaofnodes.simple.node;
+
import com.seaofnodes.simple.Parser;
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeInteger;
-import java.util.BitSet;
public class MulNode extends Node {
public MulNode(Node lhs, Node rhs) { super(null, lhs, rhs); }
@Override public String label() { return "Mul"; }
- @Override
- StringBuilder _print1(StringBuilder sb, BitSet visited) {
- in(1)._print0(sb.append("("), visited);
- in(2)._print0(sb.append("*"), visited);
- return sb.append(")");
- }
+ @Override protected String format() { return "(%1*%2)"; }
@Override
public Type compute() {
diff --git a/chapter18/src/main/java/com/seaofnodes/simple/node/NeverNode.java b/chapter18/src/main/java/com/seaofnodes/simple/node/NeverNode.java
index e77ed653..7e42ccf9 100644
--- a/chapter18/src/main/java/com/seaofnodes/simple/node/NeverNode.java
+++ b/chapter18/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 {
@@ -13,7 +14,7 @@ public class NeverNode extends IfNode {
@Override public String label() { return "Never"; }
- @Override 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/chapter18/src/main/java/com/seaofnodes/simple/node/NewNode.java b/chapter18/src/main/java/com/seaofnodes/simple/node/NewNode.java
index 9f413e7d..cd639d7e 100644
--- a/chapter18/src/main/java/com/seaofnodes/simple/node/NewNode.java
+++ b/chapter18/src/main/java/com/seaofnodes/simple/node/NewNode.java
@@ -1,7 +1,8 @@
package com.seaofnodes.simple.node;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.type.*;
-import java.util.BitSet;
/** Allocate and initialize an object. Inputs {ctrl, $mem, size, fields...};
* results {ptr, $mem}.
@@ -34,10 +35,8 @@ public class NewNode extends Node implements MultiNode {
@Override public String label() {
return "new_"+(_ptr._obj.isAry() ? "ary_"+_ptr._obj._fields[1]._type.str() : _ptr._obj.str());
}
- @Override
- StringBuilder _print1(StringBuilder sb, BitSet visited) {
- sb.append("new ");
- return sb.append(_ptr._obj.str());
+ @Override protected ExprPrinter<Node> _print1(ExprPrinter<Node> p) {
+ return p.p("new ").p(_ptr._obj.str());
}
// Find matching alias input
diff --git a/chapter18/src/main/java/com/seaofnodes/simple/node/Node.java b/chapter18/src/main/java/com/seaofnodes/simple/node/Node.java
index cdd218b5..c96255b1 100644
--- a/chapter18/src/main/java/com/seaofnodes/simple/node/Node.java
+++ b/chapter18/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.CodeGen;
import com.seaofnodes.simple.*;
@@ -13,14 +15,7 @@ import java.util.function.Function;
* 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.
@@ -42,14 +37,12 @@ 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;
-
/**
* A private Global Static mutable counter, for unique node id generation.
* To make the compiler multithreaded, this field will have to move into a TLS.
@@ -59,7 +52,7 @@ public abstract class Node implements Cloneable {
public static int UID() { return UNIQUE_ID; }
protected Node(Node... inputs) {
- _nid = UNIQUE_ID++; // allocate unique dense ID
+ super(UNIQUE_ID++); // allocate unique dense ID
_inputs = new Ary<>(Node.class);
Collections.addAll(_inputs,inputs);
_outputs = new Ary<>(Node.class);
@@ -71,41 +64,6 @@ public abstract class Node implements Cloneable {
// Easy reading label for debugger, e.g. "Add" or "Region" or "EQ"
public abstract String label();
- // Unique label for debugging, e.g. "Add12" or "Region30" or "EQ99"
- public String uniqueName() {
- return label() + _nid;
- }
-
- // ------------------------------------------------------------------------
-
- // 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.
- 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 StringBuilder _print1(StringBuilder sb, BitSet visited);
-
public String p(int depth) { return IRPrinter.prettyPrint(this,depth); }
public boolean isMultiHead() { return false; }
@@ -115,6 +73,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
@@ -189,7 +149,6 @@ public abstract class Node implements Cloneable {
return setDef(idx,new_def);
}
-
/**
* Add a new def to an existing Node. Keep the edges correct by
* adding the corresponding <em>def->use</em> edge.
@@ -267,7 +226,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;
@@ -449,7 +407,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
@@ -493,7 +450,6 @@ public abstract class Node implements Cloneable {
_deps.clear();
}
-
// Global Value Numbering. Hash over opcode and inputs; hits in this table
// are structurally equal.
public static final HashMap<Node,Node> GVN = new HashMap<>();
@@ -515,7 +471,6 @@ public abstract class Node implements Cloneable {
// and can assume "this!=n" and has the same Java class.
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
@@ -531,7 +486,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;
@@ -551,7 +505,6 @@ public abstract class Node implements Cloneable {
/** Is this Node Memory related */
public boolean isMem() { return false; }
-
// Semantic change to the graph (so NOT a peephole), used by the Parser.
// If any input is a float, flip to a float-flavored opcode and widen any
// non-float input.
@@ -572,7 +525,6 @@ public abstract class Node implements Cloneable {
}
Node copyF() { return null; }
-
// ------------------------------------------------------------------------
// Peephole utilities
@@ -599,7 +551,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.
@@ -632,7 +583,6 @@ public abstract class Node implements Cloneable {
ITER_CNT = ITER_NOP_CNT = 0;
}
-
// Utility to walk the entire graph applying a function; return the first
// not-null result.
private static final BitSet WVISIT = new BitSet();
diff --git a/chapter18/src/main/java/com/seaofnodes/simple/node/NotNode.java b/chapter18/src/main/java/com/seaofnodes/simple/node/NotNode.java
index 5e631b78..57fa9301 100644
--- a/chapter18/src/main/java/com/seaofnodes/simple/node/NotNode.java
+++ b/chapter18/src/main/java/com/seaofnodes/simple/node/NotNode.java
@@ -1,19 +1,15 @@
package com.seaofnodes.simple.node;
+
import com.seaofnodes.simple.Utils;
import com.seaofnodes.simple.type.*;
-import java.util.BitSet;
public class NotNode extends Node {
public NotNode(Node in) { super(null, in); }
@Override public String label() { return "Not"; }
- @Override
- 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/chapter18/src/main/java/com/seaofnodes/simple/node/ParmNode.java b/chapter18/src/main/java/com/seaofnodes/simple/node/ParmNode.java
index 78609971..7f5924cc 100644
--- a/chapter18/src/main/java/com/seaofnodes/simple/node/ParmNode.java
+++ b/chapter18/src/main/java/com/seaofnodes/simple/node/ParmNode.java
@@ -1,8 +1,9 @@
package com.seaofnodes.simple.node;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.Utils;
import com.seaofnodes.simple.type.Type;
-import java.util.BitSet;
public class ParmNode extends PhiNode {
@@ -19,18 +20,12 @@ public class ParmNode extends PhiNode {
public FunNode fun() { return (FunNode)in(0); }
@Override
- StringBuilder _print1(StringBuilder sb, BitSet visited) {
+ protected ExprPrinter<Node> _print1(ExprPrinter<Node> p) {
if( "main".equals(fun().sig()._name) && _label.equals("arg") )
- return sb.append("arg");
- sb.append("Parm_").append(_label).append("(");
- for( Node in : _inputs ) {
- if (in == null) sb.append("____");
- else in._print0(sb, visited);
- sb.append(",");
- }
- sb.setLength(sb.length()-1);
- sb.append(")");
- return sb;
+ return p.p("arg");
+ p.p("Parm_").p(_label).open();
+ for( Node in : _inputs ) p.n(in).p(",");
+ return p.unchar(',').close();
}
diff --git a/chapter18/src/main/java/com/seaofnodes/simple/node/PhiNode.java b/chapter18/src/main/java/com/seaofnodes/simple/node/PhiNode.java
index 3fdcd6e5..9b5e1c26 100644
--- a/chapter18/src/main/java/com/seaofnodes/simple/node/PhiNode.java
+++ b/chapter18/src/main/java/com/seaofnodes/simple/node/PhiNode.java
@@ -1,8 +1,9 @@
package com.seaofnodes.simple.node;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.*;
import com.seaofnodes.simple.type.*;
-import java.util.BitSet;
public class PhiNode extends Node {
@@ -29,18 +30,12 @@ public class PhiNode extends Node {
@Override public String label() { return "Phi_"+MemOpNode.mlabel(_label); }
@Override
- 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/chapter18/src/main/java/com/seaofnodes/simple/node/ProjNode.java b/chapter18/src/main/java/com/seaofnodes/simple/node/ProjNode.java
index 81917bef..1e192676 100644
--- a/chapter18/src/main/java/com/seaofnodes/simple/node/ProjNode.java
+++ b/chapter18/src/main/java/com/seaofnodes/simple/node/ProjNode.java
@@ -1,10 +1,11 @@
package com.seaofnodes.simple.node;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeMem;
import com.seaofnodes.simple.type.TypeTuple;
-import java.util.BitSet;
public class ProjNode extends Node implements MultiUse {
@@ -24,11 +25,11 @@ public class ProjNode extends Node implements MultiUse {
@Override public int idx() { return _idx; }
@Override
- 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/chapter18/src/main/java/com/seaofnodes/simple/node/ReadOnlyNode.java b/chapter18/src/main/java/com/seaofnodes/simple/node/ReadOnlyNode.java
index fddcaa67..fa4e0242 100644
--- a/chapter18/src/main/java/com/seaofnodes/simple/node/ReadOnlyNode.java
+++ b/chapter18/src/main/java/com/seaofnodes/simple/node/ReadOnlyNode.java
@@ -1,9 +1,9 @@
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( Node n ) { super(null,n); }
@Override public String label() { return "ReadOnly"; }
- @Override
- 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/chapter18/src/main/java/com/seaofnodes/simple/node/RegionNode.java b/chapter18/src/main/java/com/seaofnodes/simple/node/RegionNode.java
index 157d9109..945398e9 100644
--- a/chapter18/src/main/java/com/seaofnodes/simple/node/RegionNode.java
+++ b/chapter18/src/main/java/com/seaofnodes/simple/node/RegionNode.java
@@ -1,12 +1,13 @@
package com.seaofnodes.simple.node;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.IterPeeps;
import com.seaofnodes.simple.Parser;
import com.seaofnodes.simple.Utils;
import com.seaofnodes.simple.type.Type;
import java.util.ArrayList;
import java.util.Arrays;
-import java.util.BitSet;
import java.util.HashSet;
public class RegionNode extends CFGNode {
@@ -19,9 +20,8 @@ public class RegionNode extends CFGNode {
@Override
public String label() { return "Region"; }
- @Override
- 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 isMultiHead() { return true; }
diff --git a/chapter18/src/main/java/com/seaofnodes/simple/node/ReturnNode.java b/chapter18/src/main/java/com/seaofnodes/simple/node/ReturnNode.java
index 9948d973..d4b4094d 100644
--- a/chapter18/src/main/java/com/seaofnodes/simple/node/ReturnNode.java
+++ b/chapter18/src/main/java/com/seaofnodes/simple/node/ReturnNode.java
@@ -1,10 +1,11 @@
package com.seaofnodes.simple.node;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.Parser;
import com.seaofnodes.simple.SB;
import com.seaofnodes.simple.Utils;
import com.seaofnodes.simple.type.*;
-import java.util.BitSet;
/** Keeps all preceding memory effects and the return value alive: {ctrl, $mem, value, rpc}. */
public class ReturnNode extends CFGNode {
@@ -26,10 +27,10 @@ public class ReturnNode extends CFGNode {
public String label() { return "Return"; }
@Override
- StringBuilder _print1(StringBuilder sb, BitSet visited) {
- sb.append("return ");
- expr()._print0(sb, visited);
- return sb.append(";");
+ protected ExprPrinter<Node> _print1(ExprPrinter<Node> p) {
+ p.p("return ");
+ p.n(expr());
+ return p.p(";");
}
// No one unique control follows; can be many call end sites
diff --git a/chapter18/src/main/java/com/seaofnodes/simple/node/RoundF32Node.java b/chapter18/src/main/java/com/seaofnodes/simple/node/RoundF32Node.java
index 3dd7cbf0..78e7698c 100644
--- a/chapter18/src/main/java/com/seaofnodes/simple/node/RoundF32Node.java
+++ b/chapter18/src/main/java/com/seaofnodes/simple/node/RoundF32Node.java
@@ -1,19 +1,16 @@
package com.seaofnodes.simple.node;
+
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeFloat;
-import java.util.BitSet;
public class RoundF32Node extends Node {
public RoundF32Node(Node lhs) { super(null, lhs); }
@Override public String label() { return "RoundF32"; }
- @Override
- 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/chapter18/src/main/java/com/seaofnodes/simple/node/ScopeNode.java b/chapter18/src/main/java/com/seaofnodes/simple/node/ScopeNode.java
index 0b93cee6..5801cdf5 100644
--- a/chapter18/src/main/java/com/seaofnodes/simple/node/ScopeNode.java
+++ b/chapter18/src/main/java/com/seaofnodes/simple/node/ScopeNode.java
@@ -1,5 +1,7 @@
package com.seaofnodes.simple.node;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.*;
import com.seaofnodes.simple.type.*;
import java.util.*;
@@ -48,28 +50,26 @@ public class ScopeNode extends Node {
@Override public String label() { return "Scope"; }
@Override
- StringBuilder _print1(StringBuilder sb, BitSet visited) {
- sb.append("Scope[ ");
+ protected ExprPrinter<Node> _print1(ExprPrinter<Node> p) {
+ p.p("Scope[ ");
int j=1;
for( int i=0; i<nIns(); i++ ) {
- if( j < _lexSize._len && i == _lexSize.at(j) ) { sb.append("| "); j++; }
+ if( j < _lexSize._len && i == _lexSize.at(j) ) { p.p("| "); j++; }
Var v = _vars.get(i);
- sb.append(v._type().print(new SB()));
- sb.append(" ");
- if( v._final ) sb.append("!");
- sb.append(v._name);
- sb.append("=");
+ p.p(v._type().print(new SB()));
+ p.p(" ");
+ if( v._final ) p.p("!");
+ p.p(v._name);
+ p.p("=");
Node n = in(i);
while( n instanceof ScopeNode loop ) {
- sb.append("Lazy_");
+ p.p("Lazy_");
n = loop.in(i);
}
- if( n==null ) sb.append("___");
- else n._print0(sb, visited);
- sb.append(", ");
+ p.n(n);
+ p.p(", ");
}
- sb.setLength(sb.length()-2);
- return sb.append("]");
+ return p.unchar(", ").p("]");
}
diff --git a/chapter18/src/main/java/com/seaofnodes/simple/node/StartNode.java b/chapter18/src/main/java/com/seaofnodes/simple/node/StartNode.java
index e9ab8380..8bdb60cf 100644
--- a/chapter18/src/main/java/com/seaofnodes/simple/node/StartNode.java
+++ b/chapter18/src/main/java/com/seaofnodes/simple/node/StartNode.java
@@ -1,7 +1,8 @@
package com.seaofnodes.simple.node;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.type.*;
-import java.util.BitSet;
import java.util.HashSet;
import static com.seaofnodes.simple.Utils.TODO;
@@ -14,9 +15,8 @@ public class StartNode extends LoopNode implements MultiNode {
@Override public String label() { return "Start"; }
- @Override
- 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 isMultiHead() { return true; }
diff --git a/chapter18/src/main/java/com/seaofnodes/simple/node/StopNode.java b/chapter18/src/main/java/com/seaofnodes/simple/node/StopNode.java
index cabb7393..a15125a1 100644
--- a/chapter18/src/main/java/com/seaofnodes/simple/node/StopNode.java
+++ b/chapter18/src/main/java/com/seaofnodes/simple/node/StopNode.java
@@ -1,8 +1,9 @@
package com.seaofnodes.simple.node;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.Utils;
import com.seaofnodes.simple.type.Type;
-import java.util.BitSet;
public class StopNode extends CFGNode {
@@ -20,13 +21,13 @@ public class StopNode extends CFGNode {
}
@Override
- 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"
- if( ret()!=null ) return ret()._print0(sb,visited);
- sb.append("Stop[ ");
+ if( ret()!=null ) return p.n(ret());
+ p.p("Stop[ ");
for( Node ret : _inputs )
- ret._print0(sb, visited).append(" ");
- return sb.append("]");
+ p.n(ret).p(" ");
+ return p.p("]");
}
@Override public boolean blockHead() { return true; }
diff --git a/chapter18/src/main/java/com/seaofnodes/simple/node/StoreNode.java b/chapter18/src/main/java/com/seaofnodes/simple/node/StoreNode.java
index 92cd2389..ba367a67 100644
--- a/chapter18/src/main/java/com/seaofnodes/simple/node/StoreNode.java
+++ b/chapter18/src/main/java/com/seaofnodes/simple/node/StoreNode.java
@@ -1,11 +1,12 @@
package com.seaofnodes.simple.node;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.IterPeeps;
import com.seaofnodes.simple.Parser;
import com.seaofnodes.simple.Utils;
import com.seaofnodes.simple.IterPeeps;
import com.seaofnodes.simple.type.*;
-import java.util.BitSet;
/**
* Store represents setting a value to a memory based object, in chapter 10
@@ -38,8 +39,8 @@ public class StoreNode extends MemOpNode {
public Node val() { return in(4); }
@Override
- 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/chapter18/src/main/java/com/seaofnodes/simple/node/StructNode.java b/chapter18/src/main/java/com/seaofnodes/simple/node/StructNode.java
index 076b342a..b9801f63 100644
--- a/chapter18/src/main/java/com/seaofnodes/simple/node/StructNode.java
+++ b/chapter18/src/main/java/com/seaofnodes/simple/node/StructNode.java
@@ -1,8 +1,9 @@
package com.seaofnodes.simple.node;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.SB;
import com.seaofnodes.simple.type.*;
-import java.util.BitSet;
/**
* Build a compound object
@@ -14,16 +15,15 @@ public class StructNode extends Node {
@Override public String label() { return _ts==null ? "STRUCT?" : _ts.str(); }
@Override
- StringBuilder _print1(StringBuilder sb, BitSet visited) {
- if( _ts==null ) return sb.append("STRUCT?");
- sb.append(_ts._name).append(" {");
+ protected ExprPrinter<Node> _print1(ExprPrinter<Node> p) {
+ if( _ts==null ) return p.p("STRUCT?");
+ p.p(_ts._name).p(" {");
for( int i=0; i<nIns(); i++ ) {
- sb.append(_ts._fields[i]._fname).append(":");
- sb.append((in(i)==null ? Type.BOTTOM : in(i)._type).print(new SB()));
- sb.append("; ");
+ p.p(_ts._fields[i]._fname).p(":");
+ p.p((in(i)==null ? Type.BOTTOM : in(i)._type).print(new SB()));
+ p.p("; ");
}
- sb.setLength(sb.length()-2);
- return sb.append("}");
+ return p.unchar("; ").p("}");
}
@Override
diff --git a/chapter18/src/main/java/com/seaofnodes/simple/node/SubFNode.java b/chapter18/src/main/java/com/seaofnodes/simple/node/SubFNode.java
index 27bbda8d..2d218a03 100644
--- a/chapter18/src/main/java/com/seaofnodes/simple/node/SubFNode.java
+++ b/chapter18/src/main/java/com/seaofnodes/simple/node/SubFNode.java
@@ -1,21 +1,16 @@
package com.seaofnodes.simple.node;
+
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeFloat;
-import java.util.BitSet;
public class SubFNode extends Node {
public SubFNode(Node lhs, Node rhs) { super(null, lhs, rhs); }
@Override public String label() { return "SubF"; }
- @Override
- StringBuilder _print1(StringBuilder sb, BitSet visited) {
- in(1)._print0(sb.append("("), visited);
- in(2)._print0(sb.append("-"), visited);
- return sb.append(")");
- }
+ @Override protected String format() { return "(%1-%2)"; }
@Override
public Type compute() {
diff --git a/chapter18/src/main/java/com/seaofnodes/simple/node/SubNode.java b/chapter18/src/main/java/com/seaofnodes/simple/node/SubNode.java
index 034f2fb1..9bf6d83e 100644
--- a/chapter18/src/main/java/com/seaofnodes/simple/node/SubNode.java
+++ b/chapter18/src/main/java/com/seaofnodes/simple/node/SubNode.java
@@ -1,21 +1,16 @@
package com.seaofnodes.simple.node;
+
import com.seaofnodes.simple.Parser;
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeInteger;
-import java.util.BitSet;
public class SubNode extends Node {
public SubNode(Node lhs, Node rhs) { super(null, lhs, rhs); }
@Override public String label() { return "Sub"; }
- @Override
- StringBuilder _print1(StringBuilder sb, BitSet visited) {
- in(1)._print0(sb.append("("), visited);
- in(2)._print0(sb.append("-"), visited);
- return sb.append(")");
- }
+ @Override protected String format() { return "(%1-%2)"; }
@Override
public Type compute() {
diff --git a/chapter18/src/main/java/com/seaofnodes/simple/node/ToFloatNode.java b/chapter18/src/main/java/com/seaofnodes/simple/node/ToFloatNode.java
index a4aa8934..7b0122ce 100644
--- a/chapter18/src/main/java/com/seaofnodes/simple/node/ToFloatNode.java
+++ b/chapter18/src/main/java/com/seaofnodes/simple/node/ToFloatNode.java
@@ -1,20 +1,17 @@
package com.seaofnodes.simple.node;
+
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeFloat;
import com.seaofnodes.simple.type.TypeInteger;
-import java.util.BitSet;
public class ToFloatNode extends Node {
public ToFloatNode(Node lhs) { super(null, lhs); }
@Override public String label() { return "ToFloat"; }
- @Override
- 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/chapter18/src/main/java/com/seaofnodes/simple/node/XCtrlNode.java b/chapter18/src/main/java/com/seaofnodes/simple/node/XCtrlNode.java
index 3c6a5df3..3eae8548 100644
--- a/chapter18/src/main/java/com/seaofnodes/simple/node/XCtrlNode.java
+++ b/chapter18/src/main/java/com/seaofnodes/simple/node/XCtrlNode.java
@@ -1,13 +1,14 @@
package com.seaofnodes.simple.node;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.Parser;
import com.seaofnodes.simple.type.Type;
-import java.util.BitSet;
public class XCtrlNode extends CFGNode {
public XCtrlNode() { super(Parser.START); }
@Override public String label() { return "Xctrl"; }
- @Override 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 boolean isMultiTail() { return true; }
@Override public Type compute() { return Type.XCONTROL; }
diff --git a/chapter18/src/main/java/com/seaofnodes/simple/print/SimpleGraphAdapter.java b/chapter18/src/main/java/com/seaofnodes/simple/print/SimpleGraphAdapter.java
index bd9fe000..3e23968a 100644
--- a/chapter18/src/main/java/com/seaofnodes/simple/print/SimpleGraphAdapter.java
+++ b/chapter18/src/main/java/com/seaofnodes/simple/print/SimpleGraphAdapter.java
@@ -1,45 +1,25 @@
package com.seaofnodes.simple.print;
import com.seaofnodes.graph.GraphAdapter;
-import com.seaofnodes.graph.GraphSnapshot;
import com.seaofnodes.graph.GraphSnapshot.*;
import com.seaofnodes.simple.node.*;
import com.seaofnodes.simple.node.Node;
import com.seaofnodes.simple.type.TypeMem;
-import java.util.ArrayList;
/** Chapter 18's view of the IR; browser, transport and layout are shared. */
public class SimpleGraphAdapter extends GraphAdapter<Node> {
- @Override protected boolean dead(Node n) { return n.isDead(); }
- @Override protected int id(Node n) { return n._nid; }
- @Override protected int nIns(Node n) { return n.nIns(); }
- @Override protected Node in(Node n, int idx) { return n.in(idx); }
- @Override protected int nOuts(Node n) { return n.nOuts(); }
- @Override protected Node out(Node n, int idx) { return n.out(idx); }
- @Override protected int nDeps(Node n) { return n.nDeps(); }
- @Override protected Node dep(Node n, int idx) { return n.dep(idx); }
- private ArrayList<Edge> edges(Node n) {
- var edges = new ArrayList<Edge>();
- for( int i = 0; i < n.nIns(); i++ ) {
- String name = n instanceof ScopeNode scope && i < scope._vars.size()
+ @Override protected String edgeName(Node n, int i) {
+ return n instanceof ScopeNode scope && i < scope._vars.size()
? scope._vars.get(i)._name : null;
- int jump = n instanceof CallEndNode && i>0 && n.in(i) instanceof ReturnNode ret
- ? ref(ret.fun()) : 0;
- edges.add(new Edge(i, ref(n.in(i)), role(n, i), name, jump));
- }
- return edges;
}
-
- @Override protected GraphSnapshot.Node desc(Node n) {
- Projection proj = n instanceof ProjNode p ? new Projection(ref(n.in(0)), p._idx)
- : n instanceof CProjNode p ? new Projection(ref(n.in(0)), p._idx) : null;
- String label = n.label();
- return new GraphSnapshot.Node(n._nid, label == null ? n.getClass().getSimpleName() : label,
- n._type == null ? null : n._type.toString(), kind(n), edges(n), proj, folding(n));
+ @Override protected int edgeJump(Node n, int i) {
+ return n instanceof CallEndNode && i>0 && n.in(i) instanceof ReturnNode ret
+ ? ref(ret.fun()) : 0;
}
+ @Override protected int projectionIndex(Node n) { return n instanceof ProjNode p ? p._idx : n instanceof CProjNode p ? p._idx : -1; }
- private boolean folding(Node n) {
+ @Override protected boolean folding(Node n) {
if( n instanceof FunNode fun ) return fun.folding();
if( n instanceof ReturnNode ret ) return ret.fun().folding();
if( n instanceof CallEndNode cend ) return cend.folding();
@@ -49,7 +29,7 @@ public class SimpleGraphAdapter extends GraphAdapter<Node> {
return false;
}
- private Kind kind(Node n) {
+ @Override protected Kind kind(Node n) {
if( n instanceof StopNode ) return Kind.STOP;
if( n instanceof ScopeNode ) return Kind.SCOPE;
if( n instanceof FunNode ) return Kind.FUN;
@@ -60,7 +40,7 @@ public class SimpleGraphAdapter extends GraphAdapter<Node> {
return n instanceof CFGNode ? Kind.CTRL : isMem(n) ? Kind.MEM : Kind.DATA;
}
- private Role role(Node n, int i) {
+ @Override protected Role role(Node n, int i) {
if( n instanceof ScopeNode || n instanceof ConstantNode || n instanceof CtrlNode || n instanceof XCtrlNode ) return Role.ASSOC;
if( n instanceof PhiNode ) return i == 0 ? Role.ASSOC : isMem(n) ? Role.MEM : Role.DATA;
if( n instanceof ProjNode || n instanceof CProjNode )
diff --git a/chapter19/Makefile b/chapter19/Makefile
index 031c95c6..1102b788 100644
--- a/chapter19/Makefile
+++ b/chapter19/Makefile
@@ -38,6 +38,7 @@ main_javas := $(wildcard $(SRC)/$(SIMPLE)/*java $(SRC)/$(SIMPLE)/*/*java $(SRC
test_javas := $(wildcard $(TST)/$(SIMPLE)/*java $(TST)/$(SIMPLE)/*/*java)
main_classes := $(patsubst $(SRC)/%java,$(CLZDIR)/main/%class,$(main_javas))
include $(firstword $(wildcard ../graph/graph.mk graph/graph.mk))
+include $(firstword $(wildcard ../print/print.mk print/print.mk))
test_classes := $(patsubst $(TST)/%java,$(CLZDIR)/test/%class,$(test_javas))
test_cp := $(patsubst $(TST)/$(SIMPLE)/%.java,com.seaofnodes.simple.%,$(wildcard $(TST)/$(SIMPLE)/*Test.java))
classes = $(main_classes) $(test_classes)
@@ -55,7 +56,7 @@ endif
default: $(default_targets)
# Compile just the out-of-date files
-$(main_classes): build/classes/main/%class: $(SRC)/%java $(graph_javas)
+$(main_classes): build/classes/main/%class: $(SRC)/%java $(graph_javas) $(print_javas)
@echo "compiling " $@ " because " $?
@[ -d $(CLZDIR)/main ] || mkdir -p $(CLZDIR)/main
@javac $(JAVAC_ARGS) -cp "$(CLZDIR)/main$(SEP)$(jars)" -sourcepath $(SRC) -d $(CLZDIR)/main $(main_javas)
diff --git a/chapter19/pom.xml b/chapter19/pom.xml
index a11923ca..18b3c4ae 100644
--- a/chapter19/pom.xml
+++ b/chapter19/pom.xml
@@ -13,5 +13,6 @@
<name>Chapter 19</name>
<properties>
<simple.graph.directory>${project.basedir}/../graph</simple.graph.directory>
+ <simple.print.directory>${project.basedir}/../print</simple.print.directory>
</properties>
</project>
diff --git a/chapter19/src/main/java/com/seaofnodes/simple/ASMPrinter.java b/chapter19/src/main/java/com/seaofnodes/simple/ASMPrinter.java
index 5cc13210..3c4162ea 100644
--- a/chapter19/src/main/java/com/seaofnodes/simple/ASMPrinter.java
+++ b/chapter19/src/main/java/com/seaofnodes/simple/ASMPrinter.java
@@ -1,140 +1,51 @@
package com.seaofnodes.simple;
-import com.seaofnodes.simple.node.*;
+import com.seaofnodes.print.AssemblyAdapter;
+import com.seaofnodes.print.ASMPrinter.Data;
+import com.seaofnodes.print.ASMPrinter.Pool;
+import com.seaofnodes.simple.CodeGen;
import com.seaofnodes.simple.SB;
-import com.seaofnodes.simple.type.TypeFunPtr;
-import com.seaofnodes.simple.type.TypeMem;
-import com.seaofnodes.simple.type.TypeRPC;
-
-public abstract class ASMPrinter {
-
- public static SB print(SB sb, CodeGen code) {
- if( code._cfg==null )
- return sb.p("Need _cfg set, run after GCM");
-
- // instruction address
- int iadr = 0;
- for( int i=0; i<code._cfg._len; i++ )
- if( code._cfg.at(i) instanceof FunNode fun )
- iadr = print(iadr,sb,code,fun,i);
- return sb;
+import com.seaofnodes.simple.node.*;
+import com.seaofnodes.simple.type.*;
+import java.util.ArrayList;
+
+/** Machine-specific facts; traversal, columns and byte display live in print/. */
+public final class ASMPrinter extends AssemblyAdapter<Node> {
+ private final CodeGen _code;
+ private ASMPrinter(CodeGen code) {
+ super(new IRPrinter());
+ _code=code;
}
-
- private static int print(int iadr, SB sb, CodeGen code, FunNode fun, int cfgidx) {
- // Function header
- sb.nl().p("---");
- fun.sig().print(sb);
- sb.p("---------------------------").nl();
-
-
- while( !(code._cfg.at(cfgidx) instanceof ReturnNode) )
- iadr = doBlock(iadr,sb,code,fun,cfgidx++);
-
- // Function separator
- sb.p("---");
- fun.sig().print(sb);
- sb.p("---------------------------").nl();
- return iadr;
+ public static SB print(SB sb, CodeGen code) {
+ return sb.p(new com.seaofnodes.print.ASMPrinter<>(new ASMPrinter(code)).print());
}
-
- static int doBlock(int iadr, SB sb, CodeGen code, FunNode fun, int cfgidx) {
- CFGNode bb = code._cfg.at(cfgidx);
- if( bb != fun && !(bb instanceof IfNode) && !(bb instanceof CallEndNode) && !(bb instanceof CallNode) && !(bb instanceof CProjNode && bb.in(0) instanceof CallEndNode ))
- sb.p("L").p(bb._nid).p(":").nl();
-
- if( !(bb instanceof CallNode) )
- for( Node n : bb._outputs )
- iadr = doInst(iadr, sb,code,fun,bb,n);
-
- return iadr;
+ @Override public ArrayList<Node> blocks() {
+ var blocks=new ArrayList<Node>();
+ var cfg=_code._cfg;
+ if( cfg!=null ) for( Node n : cfg ) blocks.add(n);
+ return blocks;
}
-
- static int doInst(int iadr, SB sb, CodeGen code, FunNode fun, CFGNode bb, Node n) {
- final int encWidth = 8;
- final int opWidth = 5;
- final int argWidth = 30;
-
- if( n instanceof CProjNode ) return iadr;
-
- // Phis are useful before (and during) reg alloc
- if( n instanceof PhiNode phi ) {
- if( phi._type instanceof TypeMem || phi._type instanceof TypeRPC ) return iadr; // Nothing for the hidden ones
- sb.fix(4," ").p(" ").fix(encWidth,"").p(" ").fix(opWidth,phi._label).p(" ");
- sb.p(code.reg(n));
- if( !(n instanceof ParmNode) ) {
- sb.p(" = phi( ");
- for( int i=1; i<n.nIns(); i++ )
- sb.p("N").p(n.in(i)._nid).p(",");
- sb.unchar().p(" )");
- }
- sb.nl();
- return iadr;
+ @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(' ');
}
-
- // 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 && !(n instanceof FunNode) ) {
- sb.hex4(iadr++).p(" ").fix(encWidth,"??").p(" ").fix(opWidth,"JMP").p(" ").fix(argWidth,"L"+n._nid).nl();
- return iadr;
- }
-
- // ProjNodes following a multi (e.g. Call or New results),
- // get indent slightly and just print their index & node#
- if( n instanceof ProjNode proj ) {
- if( proj._type instanceof TypeMem ) return iadr; // Nothing for the hidden ones
- sb.fix(4," ").p(" ").fix(encWidth,"").p(" ").fix(opWidth,proj._label==null ? "---" : proj._label).p(" ").p(code.reg(n)).nl();
- return iadr;
- }
-
- // ADDR ENCODING Op--- dst = src op src // Comment
- // 1234 abcdefgh ld4 RAX = [Rbase + off] // Comment
- sb.hex4(iadr);
- sb.p(" ");
-
- // Encoding
- int size = 1; // TODO: Fake encoding size
- iadr += size;
- sb.fix(encWidth,"??");
- sb.p(" ");
-
- // Op; generally "ld4" or "call"
- sb.fix(opWidth, n instanceof MachNode mach ? mach.op() : n.label());
- sb.p(" ");
-
- // General asm args
- if( n instanceof MachNode mach ) {
- int old = sb.len();
- mach.asm(code,sb);
- sb.fix(argWidth-(sb.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();
-
- // MultiNodes are immediately followed by projection(s)
- if( !(n instanceof CFGNode) && n instanceof MultiNode ) {
- for( Node proj : n._outputs ) {
- assert proj instanceof ProjNode;
- doInst(iadr,sb,code,fun,bb,proj);
- }
- }
-
- return iadr;
+ return sb.toString();
+ }
+ @Override public boolean labelBlock(Node n) {
+ return !(n instanceof FunNode) && !(n instanceof IfNode) && !(n instanceof CallNode) &&
+ !(n instanceof CallEndNode) && !(n instanceof CProjNode && ir.input0(n) instanceof CallEndNode);
+ }
+ @Override public boolean hidden(Node n) {
+ if( n instanceof PhiNode || n instanceof ProjNode )
+ if( n._type instanceof TypeMem || n._type instanceof TypeRPC ) return true;
+ if( n instanceof MemMergeNode ) return true;
+ return n.getClass()==ConstantNode.class;
}
}
diff --git a/chapter19/src/main/java/com/seaofnodes/simple/CodeGen.java b/chapter19/src/main/java/com/seaofnodes/simple/CodeGen.java
index 5baa05a6..0a3a60e8 100644
--- a/chapter19/src/main/java/com/seaofnodes/simple/CodeGen.java
+++ b/chapter19/src/main/java/com/seaofnodes/simple/CodeGen.java
@@ -298,7 +298,7 @@ public class CodeGen {
String print() { return _stop.print(); }
// Debugging helper
- @Override public String toString() { return _stop.p(9999); }
+ @Override public String toString() { return IRPrinter.prettyPrint(this); }
// Debugging helper
public Node f(int idx) { return _stop.find(idx); }
diff --git a/chapter19/src/main/java/com/seaofnodes/simple/IRPrinter.java b/chapter19/src/main/java/com/seaofnodes/simple/IRPrinter.java
index 1b5ade4a..f0ac717a 100644
--- a/chapter19/src/main/java/com/seaofnodes/simple/IRPrinter.java
+++ b/chapter19/src/main/java/com/seaofnodes/simple/IRPrinter.java
@@ -1,300 +1,54 @@
package com.seaofnodes.simple;
+import com.seaofnodes.print.IRAdapter;
import com.seaofnodes.simple.node.*;
-import com.seaofnodes.simple.type.TypeFunPtr;
import java.util.ArrayList;
-import java.util.BitSet;
-import java.util.HashMap;
-
-public abstract class IRPrinter {
-
- // Print a node on 1 line, columnar aligned, as:
- // NNID NNAME DDEF DDEF [[ UUSE UUSE ]] TYPE
- // 1234 sssss 1234 1234 1234 1234 1234 1234 tttttt
- public static SB printLine( Node n, SB sb ) {
- sb.p("%4d %-7.7s ".formatted(n._nid,n.label()));
- if( n.isDead() )
- return sb.p("DEAD\n");
- for( Node def : n._inputs )
- sb.p(def==null ? "____" : "%4d".formatted(def._nid))
- // Lazy Phi indicator
- .p(n instanceof MemMergeNode && def instanceof MemMergeNode ? "^" : " ");
- for( int i = n._inputs.size(); i<4; i++ )
- sb.p(" ");
- sb.p(" [[ ");
- for( Node use : n._outputs )
- sb.p(use==null ? "____ " : "%4d ".formatted(use._nid));
- int lim = 6 - Math.max(n._inputs.size(),4);
- for( int i = n._outputs.size(); i<lim; i++ )
- sb.p(" ");
- sb.p(" ]] ");
- if( n._type!= null ) sb.p(n._type.str());
- return sb.p("\n");
- }
-
-
- public static String prettyPrint(Node node, int depth) {
- return CodeGen.CODE._phase.ordinal() > CodeGen.Phase.Schedule.ordinal()
- ? _prettyPrintScheduled( node, depth )
- : _prettyPrint( node, depth );
- }
-
- // Another bulk pretty-printer. Makes more effort at basic-block grouping.
- private static String _prettyPrint( Node node, int depth ) {
- // First, a Breadth First Search at a fixed depth.
- BFS bfs = new BFS(node,depth);
- // Convert just that set to a post-order
- ArrayList<Node> rpos = new ArrayList<>();
- BitSet visit = new BitSet();
- for( int i=bfs._lim; i< bfs._bfs.size(); i++ )
- postOrd( bfs._bfs.get(i), null, rpos, visit, bfs._bs);
- // Reverse the post-order walk
- SB sb = new SB();
- boolean gap=false;
- for( int i=rpos.size()-1; i>=0; i-- ) {
- Node n = rpos.get(i);
- if( n instanceof CFGNode || n.isMultiHead() ) {
- if( !gap ) sb.p("\n"); // Blank before multihead
- if( n instanceof FunNode fun )
- fun.sig().print(sb.p("--- ").p(fun._name==null ? "" : fun._name).p(" "),false).p("----------------------\n");
- printLine( n, sb ); // Print head
- while( --i >= 0 ) {
- Node t = rpos.get(i);
- if( !t.isMultiTail() ) { i++; break; }
- printLine( t, sb );
- }
- if( n instanceof ReturnNode ret ) {
- FunNode fun = ret.fun();
- fun.sig().print(sb.p("--- ").p(fun._name==null ? "" : fun._name).p(" "),false).p("----------------------\n");
- }
- if( !(n instanceof CallNode) ) {
- sb.p("\n"); // Blank after multitail
- gap = true;
- }
- } else {
- printLine( n, sb );
- gap = false;
- }
- }
- return sb.toString();
- }
-
- private static void postOrd(Node n, Node prior, ArrayList<Node> rpos, BitSet visit, BitSet bfs) {
- if( !bfs.get(n._nid) )
- return; // Not in the BFS visit
- if( n instanceof FunNode && !(prior instanceof StartNode) )
- return; // Only visit Fun from Start
- if( visit.get(n._nid) ) return; // Already post-order walked
- visit.set(n._nid);
- // First walk the CFG, then everything
- if( n instanceof CFGNode ) {
- for( Node use : n._outputs )
- // Follow CFG, not across call/function borders, and not around backedges
- if( use instanceof CFGNode && !(n instanceof CallNode && use instanceof FunNode) &&
- use.nOuts() >= 1 && !(use._outputs.get(0) instanceof LoopNode) )
- postOrd(use, n, rpos,visit,bfs);
- for( Node use : n._outputs )
- // Follow CFG, not across call/function borders
- if( use instanceof CFGNode && !(n instanceof CallNode && use instanceof FunNode) )
- postOrd(use,n,rpos,visit,bfs);
- }
- // Follow all outputs
- for( Node use : n._outputs )
- if( use != null &&
- !(n instanceof CallNode && use instanceof FunNode) &&
- (n instanceof FunNode || !(use instanceof ParmNode)) )
- postOrd(use, n, rpos,visit,bfs);
- // Post-order
- rpos.add(n);
- }
-
- // Breadth-first search, broken out in a class to keep in more independent.
- // Maintains a root-set of Nodes at the limit (or past by 1 if MultiHead).
- public static class BFS {
- // A breadth first search, plus MultiHeads for any MultiTails
- public final ArrayList<Node> _bfs;
- public final BitSet _bs; // Visited members by node id
- public final int _depth; // Depth limit
- public final int _lim; // From here to _bfs._len can be roots for a reverse search
- public BFS( Node base, int d ) {
- _depth = d;
- _bfs = new ArrayList<>();
- _bs = new BitSet();
-
- add(base); // Prime the pump
- int idx=0, lim=1; // Limit is where depth counter changes
- while( idx < _bfs.size() ) { // Ran out of nodes below depth
- Node n = _bfs.get(idx++);
- for( Node def : n._inputs )
- if( def!=null && !_bs.get(def._nid) )
- add(def);
- if( idx==lim ) { // Depth counter changes at limit
- if( --d < 0 )
- break; // Ran out of depth
- lim = _bfs.size(); // New depth limit
- }
- }
- // Toss things past the limit except multi-heads
- while( idx < _bfs.size() ) {
- Node n = _bfs.get(idx);
- if( n.isMultiHead() ) idx++;
- else del(idx);
- }
- // Root set is any node with no inputs in the visited set
- lim = _bfs.size();
- for( int i=_bfs.size()-1; i>=0; i-- )
- if( !any_visited(_bfs.get(i)) )
- swap( i,--lim);
- _lim = lim;
- }
- void swap( int x, int y ) {
- if( x==y ) return;
- Node tx = _bfs.get(x);
- Node ty = _bfs.get(y);
- _bfs.set(x,ty);
- _bfs.set(y,tx);
- }
- void add(Node n) {
- _bfs.add(n);
- _bs.set(n._nid);
- }
- void del(int idx) {
- _bs.clear(_bfs.get(idx)._nid);
- Utils.del(_bfs, idx);
- }
- boolean any_visited( Node n ) {
- for( Node def : n._inputs )
- if( def!=null && _bs.get(def._nid) )
- return true;
- return false;
- }
- }
-
- // Diagnostic block ordering from raw control edges. Do not call idepth():
- // it fills compiler caches (and can walk lazy dominator accessors).
- private static int _idepth(CFGNode cfg, HashMap<Integer,Integer> depths) {
- if( cfg == null || cfg instanceof StartNode || cfg instanceof FunNode ) return cfg instanceof FunNode ? 1 : 0;
- Integer old = depths.get(cfg._nid);
- if( old != null ) return old;
- depths.put(cfg._nid,0); // Break cycles in partially constructed graphs.
- int d = 0;
- if( cfg instanceof LoopNode ) {
- d = _idepth((CFGNode)cfg.in(1),depths)+1;
- } else if( cfg instanceof RegionNode || cfg instanceof StopNode ) {
- for( Node n : cfg._inputs )
- if( n instanceof CFGNode pred ) d = Math.max(d,_idepth(pred,depths)+1);
- } else if( cfg.in(0) instanceof CFGNode pred ) {
- d = _idepth(pred,depths)+1;
- }
- depths.put(cfg._nid,d);
- return d;
+import com.seaofnodes.simple.SB;
+import com.seaofnodes.simple.CodeGen;
+
+/** This chapter's read-only IR facts and the familiar debugger entry points. */
+public final class IRPrinter extends IRAdapter<Node> {
+ private static final com.seaofnodes.print.IRPrinter<Node> PRINT =
+ new com.seaofnodes.print.IRPrinter<>(new IRPrinter());
+ @Override public String type(Node n) { return n._type==null ? "" : n._type.str(); }
+ @Override public String inputMark(Node n, Node def) { return n instanceof MemMergeNode && def instanceof MemMergeNode ? "^" : " "; }
+ @Override public Kind kind(Node n) {
+ if( n instanceof StartNode ) return Kind.START;
+ if( n instanceof StopNode ) return Kind.STOP;
+ if( n instanceof FunNode ) return Kind.FUN;
+ if( n instanceof LoopNode ) return Kind.LOOP;
+ if( n instanceof RegionNode ) return Kind.REGION;
+ if( n instanceof ParmNode ) return Kind.PARM;
+ if( n instanceof PhiNode ) return Kind.PHI;
+ if( n instanceof CallEndNode ) return Kind.CALL_END;
+ if( n instanceof CallNode ) return Kind.CALL;
+ if( n instanceof ReturnNode ) return Kind.RETURN;
+ if( n instanceof ConstantNode ) return Kind.CONSTANT;
+ if( n instanceof CProjNode ) return Kind.CPROJ;
+ if( n instanceof ProjNode ) return n instanceof CFGNode ? Kind.CPROJ : Kind.PROJ;
+ if( n instanceof CFGNode ) return Kind.CTRL;
+ if( n instanceof MultiNode ) return Kind.MULTI;
+ return Kind.DATA;
+ }
+ @Override public int index(Node n) {
+ if( n instanceof ProjNode p ) return p._idx;
+ if( n instanceof CProjNode p ) return p._idx;
+ return n._nid;
+ }
+ @Override public String functionName(Node n) { return ((FunNode)n)._name==null ? "" : ((FunNode)n)._name; }
+ @Override public String signature(Node n) {
+ FunNode fun=(FunNode)n;
+ return (fun._name==null ? "" : fun._name)+" "+fun.sig().str();
+ }
+
+ public static String prettyPrint(Node n, int depth) { return PRINT.prettyPrint(n,depth); }
+ public static SB printLine(Node n, SB sb) { return sb.p(PRINT.line(n)); }
+
+ public static String prettyPrint(CodeGen code) {
+ var units=new ArrayList<com.seaofnodes.print.IRPrinter.Unit<Node>>();
+ var funs=new ArrayList<Node>();
+ for( Node n : code._start._outputs ) if( n instanceof FunNode ) funs.add(n);
+ units.add(new com.seaofnodes.print.IRPrinter.Unit<>(null,null,null,funs));
+ return PRINT.program(code._start,code._stop,units);
}
-
- // Bulk pretty printer, knowing scheduling information is available
- private static String _prettyPrintScheduled( Node node, int depth ) {
- // Backwards DFS walk to depth.
- HashMap<Integer,Integer> ds = new HashMap<>();
- Ary<Node> ns = new Ary<>(Node.class);
- _walk(ds,ns,node,depth);
- // Remove data projections, these are force-printed behind their multinode head
- for( int i=0; i<ns.size(); i++ ) {
- if( ns.get(i) instanceof ProjNode proj && !(proj.in(0) instanceof CFGNode) ) {
- ns.del(i--);
- ds.remove(proj._nid);
- }
- }
- // Print by block with least diagnostic depth
- HashMap<Integer,Integer> depths = new HashMap<>();
- SB sb = new SB();
- Ary<Node> bns = new Ary<>(Node.class);
- while( !ds.isEmpty() ) {
- CFGNode blk = null;
- for( Node n : ns ) {
- CFGNode cfg = n instanceof CFGNode cfg0 && cfg0.blockHead() ? cfg0 : n.cfg0();
- if( blk==null || _idepth(cfg,depths) < _idepth(blk,depths) )
- blk = cfg;
- }
- Integer d = ds.remove(blk._nid);
- ns.del(ns.find(blk));
-
- // Print block header
- sb.p("%-13.13s".formatted(label(blk)+":"));
- sb.p( " ".repeat(4) ).p(" [[ ");
- if( blk instanceof StartNode ) ;
- else if( blk instanceof RegionNode || blk instanceof StopNode )
- for( int i=(blk instanceof StopNode ? 3 : 1); i<blk.nIns(); i++ )
- label(sb,blk.cfg(i));
- else
- label(sb,blk.cfg(0));
- sb.p(" ]] \n");
- printLine(blk,sb);
-
- // Collect block contents that are in the depth limit
- bns.clear();
- int xd = Integer.MAX_VALUE;
- for( Node use : blk._outputs ) {
- Integer i = ds.get(use._nid);
- if( i!=null && !(use instanceof CFGNode cfg && cfg.blockHead()) ) {
- if( bns.find(use)==-1 )
- bns.add(use);
- xd = Math.min(xd,i);
- }
- }
- // Print Phis up front, if any
- for( int i=0; i<bns.size(); i++ )
- if( bns.get(i) instanceof PhiNode phi )
- printLine( phi, sb,bns,i--,ds,ns);
-
- // Print block contents in depth order, bumping depth until whole block printed
- for( ; !bns.isEmpty(); xd++ )
- for( int i=0; i<bns.size(); i++ ) {
- Node n = bns.get(i);
- if( ds.get(n._nid)==xd ) {
- printLine( n, sb, bns, i--, ds,ns );
- if( n instanceof MultiNode && !(n instanceof CFGNode) ) {
- for( Node use : n._outputs ) {
- printLine(use,sb,bns,bns.indexOf(use),ds,ns);
- }
- }
- }
- }
- sb.p("\n");
- }
- return sb.toString();
- }
-
- private static void _walk( HashMap<Integer,Integer> ds, Ary<Node> ns, Node node, int d ) {
- Integer nd = ds.get(node._nid);
- if( nd!=null && d <= nd ) return; // Been there, done that
- Integer old = ds.put(node._nid,d) ;
- if( old == null )
- ns.add(node);
- if( d == 0 ) return; // Depth cutoff
- for( Node def : node._inputs )
- if( def != null &&
- !(node instanceof LoopNode loop && loop.back()==def) &&
- // Don't walk into or out of functions
- !(node instanceof CallEndNode && def instanceof ReturnNode) &&
- !(node instanceof FunNode && def instanceof CallNode) &&
- !(node instanceof ParmNode && !(def instanceof FunNode))
- )
- _walk(ds,ns,def,d-1);
- }
-
- static String label( CFGNode blk ) {
- if( blk instanceof StartNode ) return "START";
- return (blk instanceof LoopNode ? "LOOP" : "L")+blk._nid;
- }
- static void label( SB sb, CFGNode blk ) {
- if( !blk.blockHead() ) blk = blk.cfg(0);
- sb.p( "%-9.9s ".formatted( label( blk ) ) );
- }
- static void printLine( Node n, SB sb, Ary<Node> bns, int i, HashMap<Integer,Integer> ds, Ary<Node> ns ) {
- printLine( n, sb );
- if( i != -1 ) bns.del(i);
- ds.remove(n._nid);
- int idx = ns.find(n);
- if( idx!=-1 ) ns.del(idx);
- }
-
}
diff --git a/chapter19/src/main/java/com/seaofnodes/simple/node/AddFNode.java b/chapter19/src/main/java/com/seaofnodes/simple/node/AddFNode.java
index 5d0a473a..fd713156 100644
--- a/chapter19/src/main/java/com/seaofnodes/simple/node/AddFNode.java
+++ b/chapter19/src/main/java/com/seaofnodes/simple/node/AddFNode.java
@@ -1,21 +1,16 @@
package com.seaofnodes.simple.node;
+
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeFloat;
-import java.util.BitSet;
public class AddFNode extends Node {
public AddFNode(Node lhs, Node rhs) { super(null, lhs, rhs); }
@Override public String label() { return "AddF"; }
- @Override
- StringBuilder _print1(StringBuilder sb, BitSet visited) {
- in(1)._print0(sb.append("("), visited);
- in(2)._print0(sb.append("+"), visited);
- return sb.append(")");
- }
+ @Override protected String format() { return "(%1+%2)"; }
@Override
public Type compute() {
diff --git a/chapter19/src/main/java/com/seaofnodes/simple/node/AddNode.java b/chapter19/src/main/java/com/seaofnodes/simple/node/AddNode.java
index 20b9296c..3a39ce9b 100644
--- a/chapter19/src/main/java/com/seaofnodes/simple/node/AddNode.java
+++ b/chapter19/src/main/java/com/seaofnodes/simple/node/AddNode.java
@@ -1,20 +1,15 @@
package com.seaofnodes.simple.node;
+
import com.seaofnodes.simple.Parser;
import com.seaofnodes.simple.type.*;
-import java.util.BitSet;
public class AddNode extends Node {
public AddNode(Node lhs, Node rhs) { super(null, lhs, rhs); }
@Override public String label() { return "Add"; }
- @Override
- StringBuilder _print1(StringBuilder sb, BitSet visited) {
- in(1)._print0(sb.append("("), visited);
- in(2)._print0(sb.append("+"), visited);
- return sb.append(")");
- }
+ @Override protected String format() { return "(%1+%2)"; }
@Override
diff --git a/chapter19/src/main/java/com/seaofnodes/simple/node/BoolNode.java b/chapter19/src/main/java/com/seaofnodes/simple/node/BoolNode.java
index 7df2caf8..c0ccfd9b 100644
--- a/chapter19/src/main/java/com/seaofnodes/simple/node/BoolNode.java
+++ b/chapter19/src/main/java/com/seaofnodes/simple/node/BoolNode.java
@@ -1,9 +1,10 @@
package com.seaofnodes.simple.node;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.Parser;
import com.seaofnodes.simple.Utils;
import com.seaofnodes.simple.type.*;
-import java.util.BitSet;
import static com.seaofnodes.simple.type.TypeInteger.*;
abstract public class BoolNode extends Node {
@@ -17,11 +18,8 @@ abstract public class BoolNode extends Node {
@Override
public String label() { return getClass().getSimpleName(); }
- @Override
- 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/chapter19/src/main/java/com/seaofnodes/simple/node/CProjNode.java b/chapter19/src/main/java/com/seaofnodes/simple/node/CProjNode.java
index 690ef590..c338ff4c 100644
--- a/chapter19/src/main/java/com/seaofnodes/simple/node/CProjNode.java
+++ b/chapter19/src/main/java/com/seaofnodes/simple/node/CProjNode.java
@@ -1,10 +1,11 @@
package com.seaofnodes.simple.node;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.Parser;
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeMem;
import com.seaofnodes.simple.type.TypeTuple;
-import java.util.BitSet;
public class CProjNode extends CFGNode {
@@ -23,7 +24,7 @@ public class CProjNode extends CFGNode {
@Override public String label() { return _label; }
- @Override 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 isMultiTail() { return in(0).isMultiHead(); }
@Override public boolean blockHead() { return true; }
diff --git a/chapter19/src/main/java/com/seaofnodes/simple/node/CallEndNode.java b/chapter19/src/main/java/com/seaofnodes/simple/node/CallEndNode.java
index 2205db9f..83c98b97 100644
--- a/chapter19/src/main/java/com/seaofnodes/simple/node/CallEndNode.java
+++ b/chapter19/src/main/java/com/seaofnodes/simple/node/CallEndNode.java
@@ -1,8 +1,9 @@
package com.seaofnodes.simple.node;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.*;
import com.seaofnodes.simple.type.*;
-import java.util.BitSet;
/**
* CallEnd
@@ -24,13 +25,12 @@ public class CallEndNode extends CFGNode implements MultiNode {
public CallNode call() { return (CallNode)in(0); }
@Override
- 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/chapter19/src/main/java/com/seaofnodes/simple/node/CallNode.java b/chapter19/src/main/java/com/seaofnodes/simple/node/CallNode.java
index 82cf6d28..7300bfe7 100644
--- a/chapter19/src/main/java/com/seaofnodes/simple/node/CallNode.java
+++ b/chapter19/src/main/java/com/seaofnodes/simple/node/CallNode.java
@@ -1,12 +1,13 @@
package com.seaofnodes.simple.node;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.CodeGen;
import com.seaofnodes.simple.IterPeeps;
import com.seaofnodes.simple.Parser;
import com.seaofnodes.simple.Utils;
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeFunPtr;
-import java.util.BitSet;
/**
* Call
@@ -22,15 +23,14 @@ public class CallNode extends CFGNode {
@Override
public String label() { return "Call"; }
- @Override 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/chapter19/src/main/java/com/seaofnodes/simple/node/CastNode.java b/chapter19/src/main/java/com/seaofnodes/simple/node/CastNode.java
index 6438abb5..6bf8ee90 100644
--- a/chapter19/src/main/java/com/seaofnodes/simple/node/CastNode.java
+++ b/chapter19/src/main/java/com/seaofnodes/simple/node/CastNode.java
@@ -1,10 +1,11 @@
package com.seaofnodes.simple.node;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.Parser;
import com.seaofnodes.simple.Utils;
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeInteger;
-import java.util.BitSet;
// Upcast (join) the input to a t. Used after guard test to lift an input.
// Can also be used to make a type-assertion if ctrl is null.
@@ -18,14 +19,11 @@ public class CastNode extends Node {
@Override public String label() { return "("+_t.str()+")"; }
- @Override
- public String uniqueName() { return "Cast_" + _nid; }
@Override public boolean isConst() { return true; }
- @Override
- StringBuilder _print1(StringBuilder sb, BitSet visited) {
- return in(1)._print0(sb.append(label()), visited);
+ @Override protected ExprPrinter<Node> _print1(ExprPrinter<Node> p) {
+ return p.p(label()).n(in(1));
}
@Override
diff --git a/chapter19/src/main/java/com/seaofnodes/simple/node/ConstantNode.java b/chapter19/src/main/java/com/seaofnodes/simple/node/ConstantNode.java
index 98ce9a7f..89014205 100644
--- a/chapter19/src/main/java/com/seaofnodes/simple/node/ConstantNode.java
+++ b/chapter19/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;
import com.seaofnodes.simple.Parser;
import com.seaofnodes.simple.SB;
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeFunPtr;
-import java.util.BitSet;
/**
* A Constant node represents a constant value. At present, the only constants
@@ -34,18 +35,20 @@ public class ConstantNode extends Node {
return new ConstantNode(type);
}
- @Override public String label() { return "#"+_con; }
- @Override
- public String uniqueName() { return "Con_" + _nid; }
+ @Override protected String repeatName() {
+ return _con==null || _con.toString().length()<=32 ? null : uniqueName();
+ }
+
+ @Override public String label() { return "Con"; }
@Override
- 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.print(new SB()));
+ return p.p(_con.print(new SB()));
}
@Override public boolean isMultiTail() { return true; }
diff --git a/chapter19/src/main/java/com/seaofnodes/simple/node/CtrlNode.java b/chapter19/src/main/java/com/seaofnodes/simple/node/CtrlNode.java
index 0ea060bd..e647a68a 100644
--- a/chapter19/src/main/java/com/seaofnodes/simple/node/CtrlNode.java
+++ b/chapter19/src/main/java/com/seaofnodes/simple/node/CtrlNode.java
@@ -1,14 +1,15 @@
package com.seaofnodes.simple.node;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.CodeGen;
import com.seaofnodes.simple.Parser;
import com.seaofnodes.simple.type.Type;
-import java.util.BitSet;
public class CtrlNode extends CFGNode {
public CtrlNode() { super(CodeGen.CODE._start); }
@Override public String label() { return "Ctrl"; }
- @Override 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/chapter19/src/main/java/com/seaofnodes/simple/node/DivFNode.java b/chapter19/src/main/java/com/seaofnodes/simple/node/DivFNode.java
index 6c0c2eb3..a3f4318d 100644
--- a/chapter19/src/main/java/com/seaofnodes/simple/node/DivFNode.java
+++ b/chapter19/src/main/java/com/seaofnodes/simple/node/DivFNode.java
@@ -1,21 +1,16 @@
package com.seaofnodes.simple.node;
+
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeFloat;
-import java.util.BitSet;
public class DivFNode extends Node {
public DivFNode(Node lhs, Node rhs) { super(null, lhs, rhs); }
@Override public String label() { return "DivF"; }
- @Override
- StringBuilder _print1(StringBuilder sb, BitSet visited) {
- in(1)._print0(sb.append("("), visited);
- in(2)._print0(sb.append("/"), visited);
- return sb.append(")");
- }
+ @Override protected String format() { return "(%1/%2)"; }
@Override
public Type compute() {
diff --git a/chapter19/src/main/java/com/seaofnodes/simple/node/DivNode.java b/chapter19/src/main/java/com/seaofnodes/simple/node/DivNode.java
index 69b151cd..f0ee21e1 100644
--- a/chapter19/src/main/java/com/seaofnodes/simple/node/DivNode.java
+++ b/chapter19/src/main/java/com/seaofnodes/simple/node/DivNode.java
@@ -1,20 +1,15 @@
package com.seaofnodes.simple.node;
+
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeInteger;
-import java.util.BitSet;
public class DivNode extends Node {
public DivNode(Node lhs, Node rhs) { super(null, lhs, rhs); }
@Override public String label() { return "Div"; }
- @Override
- StringBuilder _print1(StringBuilder sb, BitSet visited) {
- in(1)._print0(sb.append("("), visited);
- in(2)._print0(sb.append("/"), visited);
- return sb.append(")");
- }
+ @Override protected String format() { return "(%1/%2)"; }
@Override
public Type compute() {
diff --git a/chapter19/src/main/java/com/seaofnodes/simple/node/FRefNode.java b/chapter19/src/main/java/com/seaofnodes/simple/node/FRefNode.java
index f0c4045d..bf1c5a00 100644
--- a/chapter19/src/main/java/com/seaofnodes/simple/node/FRefNode.java
+++ b/chapter19/src/main/java/com/seaofnodes/simple/node/FRefNode.java
@@ -1,9 +1,10 @@
package com.seaofnodes.simple.node;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.Parser;
import com.seaofnodes.simple.Var;
import com.seaofnodes.simple.type.Type;
-import java.util.BitSet;
/**
* A Forward Reference. Its any final constant, including functions. When
@@ -17,10 +18,9 @@ public class FRefNode extends ConstantNode {
@Override public String label() { return "FRef"+_n; }
- @Override public String uniqueName() { return "FRef_" + _nid; }
- @Override StringBuilder _print1(StringBuilder sb, BitSet visited) {
- return sb.append("FRef_").append(_n);
+ @Override protected ExprPrinter<Node> _print1(ExprPrinter<Node> p) {
+ return p.p("FRef_").p(_n);
}
@Override public Node idealize() {
diff --git a/chapter19/src/main/java/com/seaofnodes/simple/node/IfNode.java b/chapter19/src/main/java/com/seaofnodes/simple/node/IfNode.java
index 9e6d2dff..a01eb8bd 100644
--- a/chapter19/src/main/java/com/seaofnodes/simple/node/IfNode.java
+++ b/chapter19/src/main/java/com/seaofnodes/simple/node/IfNode.java
@@ -1,9 +1,9 @@
package com.seaofnodes.simple.node;
+
import com.seaofnodes.simple.CodeGen;
import com.seaofnodes.simple.IterPeeps;
import com.seaofnodes.simple.type.*;
-import java.util.BitSet;
import java.util.HashSet;
public class IfNode extends CFGNode implements MultiNode {
@@ -17,11 +17,7 @@ public class IfNode extends CFGNode implements MultiNode {
@Override
public String label() { return "If"; }
- @Override
- StringBuilder _print1(StringBuilder sb, BitSet visited) {
- sb.append("if( ");
- return in(1)._print0(sb, visited).append(" )");
- }
+ @Override protected String format() { return "if( %1 )"; }
@Override public boolean isMultiHead() { return true; }
diff --git a/chapter19/src/main/java/com/seaofnodes/simple/node/LoadNode.java b/chapter19/src/main/java/com/seaofnodes/simple/node/LoadNode.java
index 5a04e12d..070789de 100644
--- a/chapter19/src/main/java/com/seaofnodes/simple/node/LoadNode.java
+++ b/chapter19/src/main/java/com/seaofnodes/simple/node/LoadNode.java
@@ -1,10 +1,11 @@
package com.seaofnodes.simple.node;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.CodeGen;
import com.seaofnodes.simple.Parser;
import com.seaofnodes.simple.Utils;
import com.seaofnodes.simple.type.*;
-import java.util.BitSet;
/**
* Load represents extracting a value from inside a memory object,
@@ -46,7 +47,7 @@ public class LoadNode extends MemOpNode {
// Debugger label
@Override public String label() { return "ld_"+mlabel(); }
@Override
- 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/chapter19/src/main/java/com/seaofnodes/simple/node/LogicalNode.java b/chapter19/src/main/java/com/seaofnodes/simple/node/LogicalNode.java
index ccc1f6b5..c59bd948 100644
--- a/chapter19/src/main/java/com/seaofnodes/simple/node/LogicalNode.java
+++ b/chapter19/src/main/java/com/seaofnodes/simple/node/LogicalNode.java
@@ -1,9 +1,10 @@
package com.seaofnodes.simple.node;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.Parser;
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeInteger;
-import java.util.BitSet;
public abstract class LogicalNode extends Node {
// Source location for late reported errors
@@ -12,11 +13,8 @@ public abstract class LogicalNode extends Node {
public LogicalNode(Parser.Lexer loc, Node lhs, Node rhs) { super(null, lhs, rhs); _loc = loc; }
abstract String op();
- @Override
- 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();
}
diff --git a/chapter19/src/main/java/com/seaofnodes/simple/node/MachConcreteNode.java b/chapter19/src/main/java/com/seaofnodes/simple/node/MachConcreteNode.java
index 0c49fc64..c1f007e8 100644
--- a/chapter19/src/main/java/com/seaofnodes/simple/node/MachConcreteNode.java
+++ b/chapter19/src/main/java/com/seaofnodes/simple/node/MachConcreteNode.java
@@ -1,9 +1,10 @@
package com.seaofnodes.simple.node;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.Utils;
import java.io.ByteArrayOutputStream;
-import java.util.BitSet;
// Generic machine-specific class, has a few Node implementations that have to
// exist (abstract) but are not useful past the optimizer.
@@ -16,12 +17,11 @@ public abstract class MachConcreteNode extends Node implements MachNode{
@Override public Type compute () { throw Utils.TODO(); }
@Override public Node idealize() { throw Utils.TODO(); }
- @Override public StringBuilder _print1(StringBuilder sb, BitSet visited) {
- sb.append("(").append(op()).append(",");
+ @Override protected ExprPrinter<Node> _print1(ExprPrinter<Node> p) {
+ p.open().p(op()).p(",");
for( int i=1; i<nIns(); i++ )
- (in(i)==null ? sb.append(" ---") : in(i)._print0(sb, visited)).append(",");
- sb.setLength(sb.length()-1);
- return sb.append(")");
+ (in(i)==null ? p.p(" ---") : p.n(in(i))).p(",");
+ return p.unchar(',').close();
}
}
diff --git a/chapter19/src/main/java/com/seaofnodes/simple/node/MemMergeNode.java b/chapter19/src/main/java/com/seaofnodes/simple/node/MemMergeNode.java
index b9b0c8a4..5f4cf128 100644
--- a/chapter19/src/main/java/com/seaofnodes/simple/node/MemMergeNode.java
+++ b/chapter19/src/main/java/com/seaofnodes/simple/node/MemMergeNode.java
@@ -1,9 +1,10 @@
package com.seaofnodes.simple.node;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.CodeGen;
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeMem;
-import java.util.BitSet;
/** A default slice and explicit alias overrides. A null default means partial
* memory: absent aliases are not covered, rather than having unknown contents.
@@ -53,14 +54,14 @@ public class MemMergeNode extends Node {
@Override public String label() { return "MemMerge"; }
@Override public boolean isMem() { return true; }
@Override public Type compute() { return TypeMem.BOT; }
- @Override StringBuilder _print1(StringBuilder sb, BitSet visited) {
- sb.append("MEM[");
+ @Override protected ExprPrinter<Node> _print1(ExprPrinter<Node> p) {
+ p.p("MEM[");
for( int i=1; i<nIns(); i++ )
if( in(i)!=null ) {
- sb.append(i==1 ? "default:" : i+":");
- in(i)._print0(sb,visited).append(" ");
+ p.p(i==1 ? "default:" : i+":");
+ p.n(in(i)).p(" ");
}
- return sb.append("]");
+ return p.p("]");
}
@Override public Node idealize() {
diff --git a/chapter19/src/main/java/com/seaofnodes/simple/node/MemOpNode.java b/chapter19/src/main/java/com/seaofnodes/simple/node/MemOpNode.java
index e792c152..e9fccc74 100644
--- a/chapter19/src/main/java/com/seaofnodes/simple/node/MemOpNode.java
+++ b/chapter19/src/main/java/com/seaofnodes/simple/node/MemOpNode.java
@@ -1,5 +1,7 @@
package com.seaofnodes.simple.node;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.Parser;
import com.seaofnodes.simple.Utils;
import com.seaofnodes.simple.type.Type;
@@ -48,8 +50,8 @@ public abstract class MemOpNode extends Node {
public Node ptr() { return in(2); }
public Node off() { return in(3); }
- @Override 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/chapter19/src/main/java/com/seaofnodes/simple/node/MinusFNode.java b/chapter19/src/main/java/com/seaofnodes/simple/node/MinusFNode.java
index 129963c2..852e646d 100644
--- a/chapter19/src/main/java/com/seaofnodes/simple/node/MinusFNode.java
+++ b/chapter19/src/main/java/com/seaofnodes/simple/node/MinusFNode.java
@@ -1,20 +1,16 @@
package com.seaofnodes.simple.node;
+
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeFloat;
-import java.util.BitSet;
public class MinusFNode extends Node {
public MinusFNode(Node in) { super(null, in); }
@Override public String label() { return "MinusF"; }
- @Override
- 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/chapter19/src/main/java/com/seaofnodes/simple/node/MinusNode.java b/chapter19/src/main/java/com/seaofnodes/simple/node/MinusNode.java
index dad245fd..20220915 100644
--- a/chapter19/src/main/java/com/seaofnodes/simple/node/MinusNode.java
+++ b/chapter19/src/main/java/com/seaofnodes/simple/node/MinusNode.java
@@ -1,21 +1,17 @@
package com.seaofnodes.simple.node;
+
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeInteger;
import com.seaofnodes.simple.Utils;
-import java.util.BitSet;
public class MinusNode extends Node {
public MinusNode(Node in) { super(null, in); }
@Override public String label() { return "Minus"; }
- @Override
- 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/chapter19/src/main/java/com/seaofnodes/simple/node/MulFNode.java b/chapter19/src/main/java/com/seaofnodes/simple/node/MulFNode.java
index 4b753ba7..6a57f3c5 100644
--- a/chapter19/src/main/java/com/seaofnodes/simple/node/MulFNode.java
+++ b/chapter19/src/main/java/com/seaofnodes/simple/node/MulFNode.java
@@ -1,21 +1,16 @@
package com.seaofnodes.simple.node;
+
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeFloat;
-import java.util.BitSet;
public class MulFNode extends Node {
public MulFNode(Node lhs, Node rhs) { super(null, lhs, rhs); }
@Override public String label() { return "MulF"; }
- @Override
- StringBuilder _print1(StringBuilder sb, BitSet visited) {
- in(1)._print0(sb.append("("), visited);
- in(2)._print0(sb.append("*"), visited);
- return sb.append(")");
- }
+ @Override protected String format() { return "(%1*%2)"; }
@Override
public Type compute() {
diff --git a/chapter19/src/main/java/com/seaofnodes/simple/node/MulNode.java b/chapter19/src/main/java/com/seaofnodes/simple/node/MulNode.java
index 6dcbf456..104a5581 100644
--- a/chapter19/src/main/java/com/seaofnodes/simple/node/MulNode.java
+++ b/chapter19/src/main/java/com/seaofnodes/simple/node/MulNode.java
@@ -1,21 +1,16 @@
package com.seaofnodes.simple.node;
+
import com.seaofnodes.simple.Parser;
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeInteger;
-import java.util.BitSet;
public class MulNode extends Node {
public MulNode(Node lhs, Node rhs) { super(null, lhs, rhs); }
@Override public String label() { return "Mul"; }
- @Override
- StringBuilder _print1(StringBuilder sb, BitSet visited) {
- in(1)._print0(sb.append("("), visited);
- in(2)._print0(sb.append("*"), visited);
- return sb.append(")");
- }
+ @Override protected String format() { return "(%1*%2)"; }
@Override
public Type compute() {
diff --git a/chapter19/src/main/java/com/seaofnodes/simple/node/NeverNode.java b/chapter19/src/main/java/com/seaofnodes/simple/node/NeverNode.java
index e77ed653..7e42ccf9 100644
--- a/chapter19/src/main/java/com/seaofnodes/simple/node/NeverNode.java
+++ b/chapter19/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 {
@@ -13,7 +14,7 @@ public class NeverNode extends IfNode {
@Override public String label() { return "Never"; }
- @Override 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/chapter19/src/main/java/com/seaofnodes/simple/node/NewNode.java b/chapter19/src/main/java/com/seaofnodes/simple/node/NewNode.java
index b9c9de71..68871918 100644
--- a/chapter19/src/main/java/com/seaofnodes/simple/node/NewNode.java
+++ b/chapter19/src/main/java/com/seaofnodes/simple/node/NewNode.java
@@ -1,7 +1,8 @@
package com.seaofnodes.simple.node;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.type.*;
-import java.util.BitSet;
/** Allocate a zeroed object. Inputs {ctrl, $mem, size};
* results {ptr, $mem}.
@@ -34,10 +35,8 @@ public class NewNode extends Node implements MultiNode {
@Override public String label() { return "new_"+(_ptr._obj.isAry() ? "ary_"+_ptr._obj._fields[1]._type.str() : _ptr._obj.str()); }
- @Override
- StringBuilder _print1(StringBuilder sb, BitSet visited) {
- sb.append("new ");
- return sb.append(_ptr._obj.str());
+ @Override protected ExprPrinter<Node> _print1(ExprPrinter<Node> p) {
+ return p.p("new ").p(_ptr._obj.str());
}
diff --git a/chapter19/src/main/java/com/seaofnodes/simple/node/Node.java b/chapter19/src/main/java/com/seaofnodes/simple/node/Node.java
index 13e5fac8..dd37b051 100644
--- a/chapter19/src/main/java/com/seaofnodes/simple/node/Node.java
+++ b/chapter19/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.CodeGen;
import com.seaofnodes.simple.*;
import com.seaofnodes.simple.type.Type;
@@ -14,14 +16,7 @@ import static com.seaofnodes.simple.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.
@@ -43,16 +38,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);
@@ -64,8 +57,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 == CodeGen.Phase.InstructionSelection;
- _nid = CODE.getUID(); // allocate unique dense ID
_inputs = new Ary<>(n._inputs.asAry());
_outputs = new Ary<>(Node.class);
_type = n._type;
@@ -76,45 +69,6 @@ public abstract class Node implements Cloneable {
// Easy reading label for debugger, e.g. "Add" or "Region" or "EQ"
public abstract String label();
- // Unique label for debugging, e.g. "Add12" or "Region30" or "EQ99"
- public String uniqueName() {
- return label() + _nid;
- }
-
- // 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.
- 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 StringBuilder _print1(StringBuilder sb, BitSet visited);
-
public String p(int depth) { return IRPrinter.prettyPrint(this,depth); }
public boolean isMultiHead() { return false; }
@@ -124,6 +78,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
@@ -198,7 +154,6 @@ public abstract class Node implements Cloneable {
return setDef(idx,new_def);
}
-
/**
* Add a new def to an existing Node. Keep the edges correct by
* adding the corresponding <em>def->use</em> edge.
@@ -274,7 +229,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;
@@ -458,7 +412,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
@@ -503,7 +456,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 ) {
@@ -521,7 +473,6 @@ public abstract class Node implements Cloneable {
// and can assume "this!=n" and has the same Java class.
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
@@ -537,7 +488,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;
@@ -557,7 +507,6 @@ public abstract class Node implements Cloneable {
/** Is this Node Memory related */
public boolean isMem() { return false; }
-
// Semantic change to the graph (so NOT a peephole), used by the Parser.
// If any input is a float, flip to a float-flavored opcode and widen any
// non-float input.
@@ -578,7 +527,6 @@ public abstract class Node implements Cloneable {
}
Node copyF() { return null; }
-
// ------------------------------------------------------------------------
// Peephole utilities
@@ -605,7 +553,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/chapter19/src/main/java/com/seaofnodes/simple/node/NotNode.java b/chapter19/src/main/java/com/seaofnodes/simple/node/NotNode.java
index 5e631b78..57fa9301 100644
--- a/chapter19/src/main/java/com/seaofnodes/simple/node/NotNode.java
+++ b/chapter19/src/main/java/com/seaofnodes/simple/node/NotNode.java
@@ -1,19 +1,15 @@
package com.seaofnodes.simple.node;
+
import com.seaofnodes.simple.Utils;
import com.seaofnodes.simple.type.*;
-import java.util.BitSet;
public class NotNode extends Node {
public NotNode(Node in) { super(null, in); }
@Override public String label() { return "Not"; }
- @Override
- 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/chapter19/src/main/java/com/seaofnodes/simple/node/ParmNode.java b/chapter19/src/main/java/com/seaofnodes/simple/node/ParmNode.java
index c7c21171..c3a0cf21 100644
--- a/chapter19/src/main/java/com/seaofnodes/simple/node/ParmNode.java
+++ b/chapter19/src/main/java/com/seaofnodes/simple/node/ParmNode.java
@@ -1,8 +1,9 @@
package com.seaofnodes.simple.node;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.Utils;
import com.seaofnodes.simple.type.Type;
-import java.util.BitSet;
public class ParmNode extends PhiNode {
@@ -20,18 +21,12 @@ public class ParmNode extends PhiNode {
public FunNode fun() { return (FunNode)in(0); }
@Override
- StringBuilder _print1(StringBuilder sb, BitSet visited) {
+ protected ExprPrinter<Node> _print1(ExprPrinter<Node> p) {
if( "main".equals(fun()._name) && _label.equals("arg") )
- return sb.append("arg");
- sb.append("Parm_").append(_label).append("(");
- for( Node in : _inputs ) {
- if (in == null) sb.append("____");
- else in._print0(sb, visited);
- sb.append(",");
- }
- sb.setLength(sb.length()-1);
- sb.append(")");
- return sb;
+ return p.p("arg");
+ p.p("Parm_").p(_label).open();
+ for( Node in : _inputs ) p.n(in).p(",");
+ return p.unchar(',').close();
}
diff --git a/chapter19/src/main/java/com/seaofnodes/simple/node/PhiNode.java b/chapter19/src/main/java/com/seaofnodes/simple/node/PhiNode.java
index 74fa11ab..6fb315b4 100644
--- a/chapter19/src/main/java/com/seaofnodes/simple/node/PhiNode.java
+++ b/chapter19/src/main/java/com/seaofnodes/simple/node/PhiNode.java
@@ -1,8 +1,9 @@
package com.seaofnodes.simple.node;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.*;
import com.seaofnodes.simple.type.*;
-import java.util.BitSet;
public class PhiNode extends Node {
@@ -31,18 +32,12 @@ public class PhiNode extends Node {
@Override public String label() { return "Phi_"+MemOpNode.mlabel(_label); }
@Override
- 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/chapter19/src/main/java/com/seaofnodes/simple/node/ProjNode.java b/chapter19/src/main/java/com/seaofnodes/simple/node/ProjNode.java
index 9e49f67a..6ae4a60d 100644
--- a/chapter19/src/main/java/com/seaofnodes/simple/node/ProjNode.java
+++ b/chapter19/src/main/java/com/seaofnodes/simple/node/ProjNode.java
@@ -1,10 +1,11 @@
package com.seaofnodes.simple.node;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeMem;
import com.seaofnodes.simple.type.TypeTuple;
-import java.util.BitSet;
public class ProjNode extends Node {
@@ -24,11 +25,11 @@ public class ProjNode extends Node {
@Override public String label() { return _label; }
@Override
- 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/chapter19/src/main/java/com/seaofnodes/simple/node/ReadOnlyNode.java b/chapter19/src/main/java/com/seaofnodes/simple/node/ReadOnlyNode.java
index b755af3f..d79f2815 100644
--- a/chapter19/src/main/java/com/seaofnodes/simple/node/ReadOnlyNode.java
+++ b/chapter19/src/main/java/com/seaofnodes/simple/node/ReadOnlyNode.java
@@ -1,9 +1,9 @@
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
@@ -13,10 +13,7 @@ public class ReadOnlyNode extends Node {
public ReadOnlyNode( ReadOnlyNode n ) { super(n); }
@Override public String label() { return "ReadOnly"; }
- @Override
- 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/chapter19/src/main/java/com/seaofnodes/simple/node/RegionNode.java b/chapter19/src/main/java/com/seaofnodes/simple/node/RegionNode.java
index 933bd1af..e1f095a9 100644
--- a/chapter19/src/main/java/com/seaofnodes/simple/node/RegionNode.java
+++ b/chapter19/src/main/java/com/seaofnodes/simple/node/RegionNode.java
@@ -1,5 +1,7 @@
package com.seaofnodes.simple.node;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.*;
import com.seaofnodes.simple.type.Type;
import java.util.*;
@@ -15,9 +17,8 @@ public class RegionNode extends CFGNode {
@Override
public String label() { return "Region"; }
- @Override
- 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 isMultiHead() { return true; }
diff --git a/chapter19/src/main/java/com/seaofnodes/simple/node/ReturnNode.java b/chapter19/src/main/java/com/seaofnodes/simple/node/ReturnNode.java
index f9f51b40..0716aa36 100644
--- a/chapter19/src/main/java/com/seaofnodes/simple/node/ReturnNode.java
+++ b/chapter19/src/main/java/com/seaofnodes/simple/node/ReturnNode.java
@@ -1,10 +1,11 @@
package com.seaofnodes.simple.node;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.Parser;
import com.seaofnodes.simple.SB;
import com.seaofnodes.simple.Utils;
import com.seaofnodes.simple.type.*;
-import java.util.BitSet;
/** Keeps all preceding memory effects and the return value alive: {ctrl, $mem, value, rpc}. */
public class ReturnNode extends CFGNode {
@@ -27,10 +28,10 @@ public class ReturnNode extends CFGNode {
public String label() { return "Return"; }
@Override
- StringBuilder _print1(StringBuilder sb, BitSet visited) {
- sb.append("return ");
- expr()._print0(sb, visited);
- return sb.append(";");
+ protected ExprPrinter<Node> _print1(ExprPrinter<Node> p) {
+ p.p("return ");
+ p.n(expr());
+ return p.p(";");
}
// No one unique control follows; can be many call end sites
diff --git a/chapter19/src/main/java/com/seaofnodes/simple/node/RoundF32Node.java b/chapter19/src/main/java/com/seaofnodes/simple/node/RoundF32Node.java
index 3dd7cbf0..78e7698c 100644
--- a/chapter19/src/main/java/com/seaofnodes/simple/node/RoundF32Node.java
+++ b/chapter19/src/main/java/com/seaofnodes/simple/node/RoundF32Node.java
@@ -1,19 +1,16 @@
package com.seaofnodes.simple.node;
+
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeFloat;
-import java.util.BitSet;
public class RoundF32Node extends Node {
public RoundF32Node(Node lhs) { super(null, lhs); }
@Override public String label() { return "RoundF32"; }
- @Override
- 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/chapter19/src/main/java/com/seaofnodes/simple/node/ScopeNode.java b/chapter19/src/main/java/com/seaofnodes/simple/node/ScopeNode.java
index de7ccdf3..fae45121 100644
--- a/chapter19/src/main/java/com/seaofnodes/simple/node/ScopeNode.java
+++ b/chapter19/src/main/java/com/seaofnodes/simple/node/ScopeNode.java
@@ -1,5 +1,7 @@
package com.seaofnodes.simple.node;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.*;
import com.seaofnodes.simple.type.*;
import java.util.*;
@@ -48,28 +50,26 @@ public class ScopeNode extends Node {
@Override public String label() { return "Scope"; }
@Override
- StringBuilder _print1(StringBuilder sb, BitSet visited) {
- sb.append("Scope[ ");
+ protected ExprPrinter<Node> _print1(ExprPrinter<Node> p) {
+ p.p("Scope[ ");
int j=1;
for( int i=0; i<nIns(); i++ ) {
- if( j < _lexSize._len && i == _lexSize.at(j) ) { sb.append("| "); j++; }
+ if( j < _lexSize._len && i == _lexSize.at(j) ) { p.p("| "); j++; }
Var v = _vars.get(i);
- sb.append(v._type().print(new SB()));
- sb.append(" ");
- if( v._final ) sb.append("!");
- sb.append(v._name);
- sb.append("=");
+ p.p(v._type().print(new SB()));
+ p.p(" ");
+ if( v._final ) p.p("!");
+ p.p(v._name);
+ p.p("=");
Node n = in(i);
while( n instanceof ScopeNode loop ) {
- sb.append("Lazy_");
+ p.p("Lazy_");
n = loop.in(i);
}
- if( n==null ) sb.append("___");
- else n._print0(sb, visited);
- sb.append(", ");
+ p.n(n);
+ p.p(", ");
}
- sb.setLength(sb.length()-2);
- return sb.append("]");
+ return p.unchar(", ").p("]");
}
diff --git a/chapter19/src/main/java/com/seaofnodes/simple/node/StartNode.java b/chapter19/src/main/java/com/seaofnodes/simple/node/StartNode.java
index 630e3bf6..d1151090 100644
--- a/chapter19/src/main/java/com/seaofnodes/simple/node/StartNode.java
+++ b/chapter19/src/main/java/com/seaofnodes/simple/node/StartNode.java
@@ -1,9 +1,10 @@
package com.seaofnodes.simple.node;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.CodeGen;
import com.seaofnodes.simple.Parser;
import com.seaofnodes.simple.type.*;
-import java.util.BitSet;
import java.util.HashSet;
import static com.seaofnodes.simple.Utils.TODO;
@@ -17,9 +18,8 @@ public class StartNode extends LoopNode implements MultiNode {
@Override public String label() { return "Start"; }
- @Override
- 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 isMultiHead() { return true; }
diff --git a/chapter19/src/main/java/com/seaofnodes/simple/node/StopNode.java b/chapter19/src/main/java/com/seaofnodes/simple/node/StopNode.java
index 0992c4de..01199e9b 100644
--- a/chapter19/src/main/java/com/seaofnodes/simple/node/StopNode.java
+++ b/chapter19/src/main/java/com/seaofnodes/simple/node/StopNode.java
@@ -1,8 +1,9 @@
package com.seaofnodes.simple.node;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.Utils;
import com.seaofnodes.simple.type.Type;
-import java.util.BitSet;
public class StopNode extends CFGNode {
@@ -21,13 +22,13 @@ public class StopNode extends CFGNode {
}
@Override
- 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"
- if( ret()!=null ) return ret()._print0(sb,visited);
- sb.append("Stop[ ");
+ if( ret()!=null ) return p.n(ret());
+ p.p("Stop[ ");
for( Node ret : _inputs )
- ret._print0(sb, visited).append(" ");
- return sb.append("]");
+ p.n(ret).p(" ");
+ return p.p("]");
}
@Override public boolean blockHead() { return true; }
diff --git a/chapter19/src/main/java/com/seaofnodes/simple/node/StoreNode.java b/chapter19/src/main/java/com/seaofnodes/simple/node/StoreNode.java
index a909399f..8ac79bf1 100644
--- a/chapter19/src/main/java/com/seaofnodes/simple/node/StoreNode.java
+++ b/chapter19/src/main/java/com/seaofnodes/simple/node/StoreNode.java
@@ -1,8 +1,9 @@
package com.seaofnodes.simple.node;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.*;
import com.seaofnodes.simple.type.*;
-import java.util.BitSet;
/**
* Store represents setting a value to a memory based object, in chapter 10
@@ -35,8 +36,8 @@ public class StoreNode extends MemOpNode {
public Node val() { return in(4); }
@Override
- 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/chapter19/src/main/java/com/seaofnodes/simple/node/StructNode.java b/chapter19/src/main/java/com/seaofnodes/simple/node/StructNode.java
index 076b342a..b9801f63 100644
--- a/chapter19/src/main/java/com/seaofnodes/simple/node/StructNode.java
+++ b/chapter19/src/main/java/com/seaofnodes/simple/node/StructNode.java
@@ -1,8 +1,9 @@
package com.seaofnodes.simple.node;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.SB;
import com.seaofnodes.simple.type.*;
-import java.util.BitSet;
/**
* Build a compound object
@@ -14,16 +15,15 @@ public class StructNode extends Node {
@Override public String label() { return _ts==null ? "STRUCT?" : _ts.str(); }
@Override
- StringBuilder _print1(StringBuilder sb, BitSet visited) {
- if( _ts==null ) return sb.append("STRUCT?");
- sb.append(_ts._name).append(" {");
+ protected ExprPrinter<Node> _print1(ExprPrinter<Node> p) {
+ if( _ts==null ) return p.p("STRUCT?");
+ p.p(_ts._name).p(" {");
for( int i=0; i<nIns(); i++ ) {
- sb.append(_ts._fields[i]._fname).append(":");
- sb.append((in(i)==null ? Type.BOTTOM : in(i)._type).print(new SB()));
- sb.append("; ");
+ p.p(_ts._fields[i]._fname).p(":");
+ p.p((in(i)==null ? Type.BOTTOM : in(i)._type).print(new SB()));
+ p.p("; ");
}
- sb.setLength(sb.length()-2);
- return sb.append("}");
+ return p.unchar("; ").p("}");
}
@Override
diff --git a/chapter19/src/main/java/com/seaofnodes/simple/node/SubFNode.java b/chapter19/src/main/java/com/seaofnodes/simple/node/SubFNode.java
index 27bbda8d..2d218a03 100644
--- a/chapter19/src/main/java/com/seaofnodes/simple/node/SubFNode.java
+++ b/chapter19/src/main/java/com/seaofnodes/simple/node/SubFNode.java
@@ -1,21 +1,16 @@
package com.seaofnodes.simple.node;
+
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeFloat;
-import java.util.BitSet;
public class SubFNode extends Node {
public SubFNode(Node lhs, Node rhs) { super(null, lhs, rhs); }
@Override public String label() { return "SubF"; }
- @Override
- StringBuilder _print1(StringBuilder sb, BitSet visited) {
- in(1)._print0(sb.append("("), visited);
- in(2)._print0(sb.append("-"), visited);
- return sb.append(")");
- }
+ @Override protected String format() { return "(%1-%2)"; }
@Override
public Type compute() {
diff --git a/chapter19/src/main/java/com/seaofnodes/simple/node/SubNode.java b/chapter19/src/main/java/com/seaofnodes/simple/node/SubNode.java
index 034f2fb1..9bf6d83e 100644
--- a/chapter19/src/main/java/com/seaofnodes/simple/node/SubNode.java
+++ b/chapter19/src/main/java/com/seaofnodes/simple/node/SubNode.java
@@ -1,21 +1,16 @@
package com.seaofnodes.simple.node;
+
import com.seaofnodes.simple.Parser;
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeInteger;
-import java.util.BitSet;
public class SubNode extends Node {
public SubNode(Node lhs, Node rhs) { super(null, lhs, rhs); }
@Override public String label() { return "Sub"; }
- @Override
- StringBuilder _print1(StringBuilder sb, BitSet visited) {
- in(1)._print0(sb.append("("), visited);
- in(2)._print0(sb.append("-"), visited);
- return sb.append(")");
- }
+ @Override protected String format() { return "(%1-%2)"; }
@Override
public Type compute() {
diff --git a/chapter19/src/main/java/com/seaofnodes/simple/node/ToFloatNode.java b/chapter19/src/main/java/com/seaofnodes/simple/node/ToFloatNode.java
index a4aa8934..7b0122ce 100644
--- a/chapter19/src/main/java/com/seaofnodes/simple/node/ToFloatNode.java
+++ b/chapter19/src/main/java/com/seaofnodes/simple/node/ToFloatNode.java
@@ -1,20 +1,17 @@
package com.seaofnodes.simple.node;
+
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeFloat;
import com.seaofnodes.simple.type.TypeInteger;
-import java.util.BitSet;
public class ToFloatNode extends Node {
public ToFloatNode(Node lhs) { super(null, lhs); }
@Override public String label() { return "ToFloat"; }
- @Override
- 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/chapter19/src/main/java/com/seaofnodes/simple/node/XCtrlNode.java b/chapter19/src/main/java/com/seaofnodes/simple/node/XCtrlNode.java
index 9b4245c7..891291d0 100644
--- a/chapter19/src/main/java/com/seaofnodes/simple/node/XCtrlNode.java
+++ b/chapter19/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;
import com.seaofnodes.simple.Parser;
import com.seaofnodes.simple.type.Type;
-import java.util.BitSet;
public class XCtrlNode extends CFGNode {
public XCtrlNode() { super(new Node[]{CodeGen.CODE._start}); }
@Override public String label() { return "Xctrl"; }
- @Override 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 boolean isMultiTail() { return true; }
@Override public Type compute() { return Type.XCONTROL; }
diff --git a/chapter19/src/main/java/com/seaofnodes/simple/node/cpus/riscv/MemOpRISC.java b/chapter19/src/main/java/com/seaofnodes/simple/node/cpus/riscv/MemOpRISC.java
index e8134f03..3bf1cf09 100644
--- a/chapter19/src/main/java/com/seaofnodes/simple/node/cpus/riscv/MemOpRISC.java
+++ b/chapter19/src/main/java/com/seaofnodes/simple/node/cpus/riscv/MemOpRISC.java
@@ -1,12 +1,13 @@
package com.seaofnodes.simple.node.cpus.riscv;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.*;
import com.seaofnodes.simple.node.*;
import com.seaofnodes.simple.node.cpus.x86_64_v2.x86_64_v2;
import com.seaofnodes.simple.type.*;
import java.io.ByteArrayOutputStream;
import java.lang.StringBuilder;
-import java.util.BitSet;
public class MemOpRISC extends MemOpNode implements MachNode{
@@ -14,7 +15,7 @@ public class MemOpRISC extends MemOpNode implements MachNode{
MemOpRISC(Node op, MemOpNode mop) {
super(op, mop);
}
- @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 boolean isMem() { return _type instanceof TypeMem; }
diff --git a/chapter19/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/MemOpX86.java b/chapter19/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/MemOpX86.java
index ab40571f..5a79fb09 100644
--- a/chapter19/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/MemOpX86.java
+++ b/chapter19/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.*;
import com.seaofnodes.simple.node.*;
import com.seaofnodes.simple.type.*;
import java.io.ByteArrayOutputStream;
import java.lang.StringBuilder;
-import java.util.BitSet;
// Generic X86 memory operand base.
// inputs:
@@ -51,7 +52,7 @@ public abstract class MemOpX86 extends MemOpNode implements MachNode {
Node idx() { return in(3); }
Node val() { return in(4); }
- @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 boolean isMem() { return _type instanceof TypeMem; }
diff --git a/chapter19/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/StoreX86.java b/chapter19/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/StoreX86.java
index 734f39de..76bd2afb 100644
--- a/chapter19/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/StoreX86.java
+++ b/chapter19/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/StoreX86.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.RegMask;
import com.seaofnodes.simple.SB;
import com.seaofnodes.simple.node.Node;
import com.seaofnodes.simple.node.StoreNode;
-import java.util.BitSet;
public class StoreX86 extends MemOpX86 {
StoreX86( StoreNode st, Node base, Node idx, int off, int scale, int imm, Node val ) {
@@ -14,8 +15,8 @@ public class StoreX86 extends MemOpX86 {
@Override public String op() { return "st"+_sz; }
- @Override public StringBuilder _printMach(StringBuilder sb, BitSet visited) {
- return sb.append(".").append(_name).append("=").append(val()==null ? _imm : val()).append(";");
+ @Override protected ExprPrinter<Node> _printMach(ExprPrinter<Node> p) {
+ return p.p(".").p(_name).p("=").p(val()==null ? _imm : val()).p(";");
}
// Register mask allowed as a result. 0 for no register.
diff --git a/chapter19/src/main/java/com/seaofnodes/simple/print/SimpleGraphAdapter.java b/chapter19/src/main/java/com/seaofnodes/simple/print/SimpleGraphAdapter.java
index fcb1515f..1992a0c0 100644
--- a/chapter19/src/main/java/com/seaofnodes/simple/print/SimpleGraphAdapter.java
+++ b/chapter19/src/main/java/com/seaofnodes/simple/print/SimpleGraphAdapter.java
@@ -1,45 +1,25 @@
package com.seaofnodes.simple.print;
import com.seaofnodes.graph.GraphAdapter;
-import com.seaofnodes.graph.GraphSnapshot;
import com.seaofnodes.graph.GraphSnapshot.*;
import com.seaofnodes.simple.node.*;
import com.seaofnodes.simple.node.Node;
import com.seaofnodes.simple.type.TypeMem;
-import java.util.ArrayList;
/** Chapter 19's view of the IR; browser, transport and layout are shared. */
public class SimpleGraphAdapter extends GraphAdapter<Node> {
- @Override protected boolean dead(Node n) { return n.isDead(); }
- @Override protected int id(Node n) { return n._nid; }
- @Override protected int nIns(Node n) { return n.nIns(); }
- @Override protected Node in(Node n, int idx) { return n.in(idx); }
- @Override protected int nOuts(Node n) { return n.nOuts(); }
- @Override protected Node out(Node n, int idx) { return n.out(idx); }
- @Override protected int nDeps(Node n) { return n.nDeps(); }
- @Override protected Node dep(Node n, int idx) { return n.dep(idx); }
- private ArrayList<Edge> edges(Node n) {
- var edges = new ArrayList<Edge>();
- for( int i = 0; i < n.nIns(); i++ ) {
- String name = n instanceof ScopeNode scope && i < scope._vars.size()
+ @Override protected String edgeName(Node n, int i) {
+ return n instanceof ScopeNode scope && i < scope._vars.size()
? scope._vars.get(i)._name : null;
- int jump = n instanceof CallEndNode && i>0 && n.in(i) instanceof ReturnNode ret
- ? ref(ret.fun()) : 0;
- edges.add(new Edge(i, ref(n.in(i)), role(n, i), name, jump));
- }
- return edges;
}
-
- @Override protected GraphSnapshot.Node desc(Node n) {
- Projection proj = n instanceof ProjNode p ? new Projection(ref(n.in(0)), p._idx)
- : n instanceof CProjNode p ? new Projection(ref(n.in(0)), p._idx) : null;
- String label = n.label();
- return new GraphSnapshot.Node(n._nid, label == null ? n.getClass().getSimpleName() : label,
- n._type == null ? null : n._type.toString(), kind(n), edges(n), proj, folding(n));
+ @Override protected int edgeJump(Node n, int i) {
+ return n instanceof CallEndNode && i>0 && n.in(i) instanceof ReturnNode ret
+ ? ref(ret.fun()) : 0;
}
+ @Override protected int projectionIndex(Node n) { return n instanceof ProjNode p ? p._idx : n instanceof CProjNode p ? p._idx : -1; }
- private boolean folding(Node n) {
+ @Override protected boolean folding(Node n) {
if( n instanceof FunNode fun ) return fun.folding();
if( n instanceof ReturnNode ret ) return ret.fun().folding();
if( n instanceof CallEndNode cend ) return cend.folding();
@@ -49,7 +29,7 @@ public class SimpleGraphAdapter extends GraphAdapter<Node> {
return false;
}
- private Kind kind(Node n) {
+ @Override protected Kind kind(Node n) {
if( n instanceof StopNode ) return Kind.STOP;
if( n instanceof ScopeNode ) return Kind.SCOPE;
if( n instanceof FunNode ) return Kind.FUN;
@@ -60,7 +40,7 @@ public class SimpleGraphAdapter extends GraphAdapter<Node> {
return n instanceof CFGNode ? Kind.CTRL : isMem(n) ? Kind.MEM : Kind.DATA;
}
- private Role role(Node n, int i) {
+ @Override protected Role role(Node n, int i) {
if( n instanceof ScopeNode || n instanceof ConstantNode || n instanceof CtrlNode || n instanceof XCtrlNode ) return Role.ASSOC;
if( n instanceof PhiNode ) return i == 0 ? Role.ASSOC : isMem(n) ? Role.MEM : Role.DATA;
if( n instanceof ProjNode || n instanceof CProjNode )
diff --git a/chapter20/Makefile b/chapter20/Makefile
index 681b350e..30b5f180 100644
--- a/chapter20/Makefile
+++ b/chapter20/Makefile
@@ -37,6 +37,7 @@ main_javas := $(wildcard $(SRC)/$(SIMPLE)/*java $(SRC)/$(SIMPLE)/*/*java $(SRC
test_javas := $(wildcard $(TST)/$(SIMPLE)/*java $(TST)/$(SIMPLE)/*/*java)
main_classes := $(patsubst $(SRC)/%java,$(CLZDIR)/main/%class,$(main_javas))
include $(firstword $(wildcard ../graph/graph.mk graph/graph.mk))
+include $(firstword $(wildcard ../print/print.mk print/print.mk))
test_classes := $(patsubst $(TST)/%java,$(CLZDIR)/test/%class,$(test_javas))
test_cp := $(patsubst $(TST)/$(SIMPLE)/%.java,com.seaofnodes.simple.%,$(wildcard $(TST)/$(SIMPLE)/*Test.java))
classes = $(main_classes) $(test_classes)
@@ -54,7 +55,7 @@ endif
default: $(default_targets)
# Compile just the out-of-date files
-$(main_classes): $(CLZDIR)/main/%class: $(SRC)/%java $(graph_javas)
+$(main_classes): $(CLZDIR)/main/%class: $(SRC)/%java $(graph_javas) $(print_javas)
@echo "compiling " $@ " because " $?
@[ -d $(CLZDIR)/main ] || mkdir -p $(CLZDIR)/main
@javac $(JAVAC_ARGS) -cp "$(CLZDIR)/main$(SEP)$(jars)" -sourcepath $(SRC) -d $(CLZDIR)/main $(main_javas)
diff --git a/chapter20/pom.xml b/chapter20/pom.xml
index efe00a9d..75b41a72 100644
--- a/chapter20/pom.xml
+++ b/chapter20/pom.xml
@@ -13,5 +13,6 @@
<name>Chapter 20</name>
<properties>
<simple.graph.directory>${project.basedir}/../graph</simple.graph.directory>
+ <simple.print.directory>${project.basedir}/../print</simple.print.directory>
</properties>
</project>
diff --git a/chapter20/src/main/java/com/seaofnodes/simple/codegen/CodeGen.java b/chapter20/src/main/java/com/seaofnodes/simple/codegen/CodeGen.java
index 93362799..78cf4c06 100644
--- a/chapter20/src/main/java/com/seaofnodes/simple/codegen/CodeGen.java
+++ b/chapter20/src/main/java/com/seaofnodes/simple/codegen/CodeGen.java
@@ -347,7 +347,7 @@ public class CodeGen {
@Override public String toString() {
return _phase.ordinal() > Phase.Schedule.ordinal()
? IRPrinter._prettyPrint( this )
- : _stop.p(9999);
+ : IRPrinter.prettyPrint(this);
}
// Debugging helper
diff --git a/chapter20/src/main/java/com/seaofnodes/simple/node/AddFNode.java b/chapter20/src/main/java/com/seaofnodes/simple/node/AddFNode.java
index 5d0a473a..fd713156 100644
--- a/chapter20/src/main/java/com/seaofnodes/simple/node/AddFNode.java
+++ b/chapter20/src/main/java/com/seaofnodes/simple/node/AddFNode.java
@@ -1,21 +1,16 @@
package com.seaofnodes.simple.node;
+
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeFloat;
-import java.util.BitSet;
public class AddFNode extends Node {
public AddFNode(Node lhs, Node rhs) { super(null, lhs, rhs); }
@Override public String label() { return "AddF"; }
- @Override
- StringBuilder _print1(StringBuilder sb, BitSet visited) {
- in(1)._print0(sb.append("("), visited);
- in(2)._print0(sb.append("+"), visited);
- return sb.append(")");
- }
+ @Override protected String format() { return "(%1+%2)"; }
@Override
public Type compute() {
diff --git a/chapter20/src/main/java/com/seaofnodes/simple/node/AddNode.java b/chapter20/src/main/java/com/seaofnodes/simple/node/AddNode.java
index e1d16cf3..01cb6bb7 100644
--- a/chapter20/src/main/java/com/seaofnodes/simple/node/AddNode.java
+++ b/chapter20/src/main/java/com/seaofnodes/simple/node/AddNode.java
@@ -1,9 +1,9 @@
package com.seaofnodes.simple.node;
+
import com.seaofnodes.simple.Parser;
import com.seaofnodes.simple.type.*;
-import java.util.BitSet;
import static com.seaofnodes.simple.Parser.con;
@@ -12,12 +12,7 @@ public class AddNode extends Node {
@Override public String label() { return "Add"; }
- @Override
- StringBuilder _print1(StringBuilder sb, BitSet visited) {
- in(1)._print0(sb.append("("), visited);
- in(2)._print0(sb.append("+"), visited);
- return sb.append(")");
- }
+ @Override protected String format() { return "(%1+%2)"; }
@Override
diff --git a/chapter20/src/main/java/com/seaofnodes/simple/node/BoolNode.java b/chapter20/src/main/java/com/seaofnodes/simple/node/BoolNode.java
index 9faa5181..85bcae0f 100644
--- a/chapter20/src/main/java/com/seaofnodes/simple/node/BoolNode.java
+++ b/chapter20/src/main/java/com/seaofnodes/simple/node/BoolNode.java
@@ -1,9 +1,10 @@
package com.seaofnodes.simple.node;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.Parser;
import com.seaofnodes.simple.Utils;
import com.seaofnodes.simple.type.*;
-import java.util.BitSet;
import static com.seaofnodes.simple.type.TypeInteger.*;
abstract public class BoolNode extends Node {
@@ -17,11 +18,8 @@ abstract public class BoolNode extends Node {
@Override
public String label() { return getClass().getSimpleName(); }
- @Override
- 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/chapter20/src/main/java/com/seaofnodes/simple/node/CProjNode.java b/chapter20/src/main/java/com/seaofnodes/simple/node/CProjNode.java
index adc4e66f..bfdcb04b 100644
--- a/chapter20/src/main/java/com/seaofnodes/simple/node/CProjNode.java
+++ b/chapter20/src/main/java/com/seaofnodes/simple/node/CProjNode.java
@@ -1,11 +1,12 @@
package com.seaofnodes.simple.node;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.Parser;
import com.seaofnodes.simple.Utils;
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeMem;
import com.seaofnodes.simple.type.TypeTuple;
-import java.util.BitSet;
public class CProjNode extends CFGNode {
@@ -24,7 +25,7 @@ public class CProjNode extends CFGNode {
@Override public String label() { return _label; }
- @Override 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/chapter20/src/main/java/com/seaofnodes/simple/node/CallEndNode.java b/chapter20/src/main/java/com/seaofnodes/simple/node/CallEndNode.java
index c90e0530..ba04922b 100644
--- a/chapter20/src/main/java/com/seaofnodes/simple/node/CallEndNode.java
+++ b/chapter20/src/main/java/com/seaofnodes/simple/node/CallEndNode.java
@@ -1,9 +1,10 @@
package com.seaofnodes.simple.node;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.*;
import com.seaofnodes.simple.codegen.CodeGen;
import com.seaofnodes.simple.type.*;
-import java.util.BitSet;
/**
* CallEnd
@@ -24,13 +25,12 @@ public class CallEndNode extends CFGNode implements MultiNode {
public CallNode call() { return (CallNode)in(0); }
@Override
- 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/chapter20/src/main/java/com/seaofnodes/simple/node/CallNode.java b/chapter20/src/main/java/com/seaofnodes/simple/node/CallNode.java
index a3f880b6..ba09d1cc 100644
--- a/chapter20/src/main/java/com/seaofnodes/simple/node/CallNode.java
+++ b/chapter20/src/main/java/com/seaofnodes/simple/node/CallNode.java
@@ -1,12 +1,13 @@
package com.seaofnodes.simple.node;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.codegen.CodeGen;
import com.seaofnodes.simple.IterPeeps;
import com.seaofnodes.simple.Parser;
import com.seaofnodes.simple.Utils;
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeFunPtr;
-import java.util.BitSet;
/**
* Call
@@ -21,15 +22,14 @@ public class CallNode extends CFGNode {
@Override public String label() { return "Call"; }
- @Override 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/chapter20/src/main/java/com/seaofnodes/simple/node/CastNode.java b/chapter20/src/main/java/com/seaofnodes/simple/node/CastNode.java
index f3ee1aa2..9aedf53e 100644
--- a/chapter20/src/main/java/com/seaofnodes/simple/node/CastNode.java
+++ b/chapter20/src/main/java/com/seaofnodes/simple/node/CastNode.java
@@ -1,10 +1,11 @@
package com.seaofnodes.simple.node;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.Parser;
import com.seaofnodes.simple.Utils;
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeInteger;
-import java.util.BitSet;
// Upcast (join) the input to a t. Used after guard test to lift an input.
// Can also be used to make a type-assertion if ctrl is null.
@@ -24,14 +25,11 @@ public class CastNode extends Node {
@Override public String label() { return "("+_t.str()+")"; }
- @Override
- public String uniqueName() { return "Cast_" + _nid; }
@Override public boolean isConst() { return true; }
- @Override
- StringBuilder _print1(StringBuilder sb, BitSet visited) {
- return in(1)._print0(sb.append(label()), visited);
+ @Override protected ExprPrinter<Node> _print1(ExprPrinter<Node> p) {
+ return p.p(label()).n(in(1));
}
@Override
diff --git a/chapter20/src/main/java/com/seaofnodes/simple/node/ConstantNode.java b/chapter20/src/main/java/com/seaofnodes/simple/node/ConstantNode.java
index 5ddf47a1..cadb6511 100644
--- a/chapter20/src/main/java/com/seaofnodes/simple/node/ConstantNode.java
+++ b/chapter20/src/main/java/com/seaofnodes/simple/node/ConstantNode.java
@@ -1,11 +1,12 @@
package com.seaofnodes.simple.node;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.codegen.CodeGen;
import com.seaofnodes.simple.Parser;
import com.seaofnodes.simple.SB;
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeFunPtr;
-import java.util.BitSet;
/**
* A Constant node represents a constant value. At present, the only constants
@@ -35,18 +36,20 @@ public class ConstantNode extends Node {
return new ConstantNode(type);
}
- @Override public String label() { return "#"+_con; }
- @Override
- public String uniqueName() { return "Con_" + _nid; }
+ @Override protected String repeatName() {
+ return _con==null || _con.toString().length()<=32 ? null : uniqueName();
+ }
+
+ @Override public String label() { return "Con"; }
@Override
- 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.print(new SB()));
+ return p.p(_con.print(new SB()));
}
@Override public boolean isConst() { return true; }
diff --git a/chapter20/src/main/java/com/seaofnodes/simple/node/CtrlNode.java b/chapter20/src/main/java/com/seaofnodes/simple/node/CtrlNode.java
index 61d9c310..cf630ad4 100644
--- a/chapter20/src/main/java/com/seaofnodes/simple/node/CtrlNode.java
+++ b/chapter20/src/main/java/com/seaofnodes/simple/node/CtrlNode.java
@@ -1,14 +1,15 @@
package com.seaofnodes.simple.node;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.codegen.CodeGen;
import com.seaofnodes.simple.Parser;
import com.seaofnodes.simple.type.Type;
-import java.util.BitSet;
public class CtrlNode extends CFGNode {
public CtrlNode() { super(CodeGen.CODE._start); }
@Override public String label() { return "Ctrl"; }
- @Override 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/chapter20/src/main/java/com/seaofnodes/simple/node/DivFNode.java b/chapter20/src/main/java/com/seaofnodes/simple/node/DivFNode.java
index 258720c8..149499f9 100644
--- a/chapter20/src/main/java/com/seaofnodes/simple/node/DivFNode.java
+++ b/chapter20/src/main/java/com/seaofnodes/simple/node/DivFNode.java
@@ -1,21 +1,16 @@
package com.seaofnodes.simple.node;
+
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeFloat;
-import java.util.BitSet;
public class DivFNode extends Node {
public DivFNode(Node lhs, Node rhs) { super(null, lhs, rhs); }
@Override public String label() { return "DivF"; }
- @Override
- StringBuilder _print1(StringBuilder sb, BitSet visited) {
- in(1)._print0(sb.append("("), visited);
- in(2)._print0(sb.append("/"), visited);
- return sb.append(")");
- }
+ @Override protected String format() { return "(%1/%2)"; }
@Override
public Type compute() {
diff --git a/chapter20/src/main/java/com/seaofnodes/simple/node/DivNode.java b/chapter20/src/main/java/com/seaofnodes/simple/node/DivNode.java
index 69b151cd..f0ee21e1 100644
--- a/chapter20/src/main/java/com/seaofnodes/simple/node/DivNode.java
+++ b/chapter20/src/main/java/com/seaofnodes/simple/node/DivNode.java
@@ -1,20 +1,15 @@
package com.seaofnodes.simple.node;
+
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeInteger;
-import java.util.BitSet;
public class DivNode extends Node {
public DivNode(Node lhs, Node rhs) { super(null, lhs, rhs); }
@Override public String label() { return "Div"; }
- @Override
- StringBuilder _print1(StringBuilder sb, BitSet visited) {
- in(1)._print0(sb.append("("), visited);
- in(2)._print0(sb.append("/"), visited);
- return sb.append(")");
- }
+ @Override protected String format() { return "(%1/%2)"; }
@Override
public Type compute() {
diff --git a/chapter20/src/main/java/com/seaofnodes/simple/node/FRefNode.java b/chapter20/src/main/java/com/seaofnodes/simple/node/FRefNode.java
index f0c4045d..bf1c5a00 100644
--- a/chapter20/src/main/java/com/seaofnodes/simple/node/FRefNode.java
+++ b/chapter20/src/main/java/com/seaofnodes/simple/node/FRefNode.java
@@ -1,9 +1,10 @@
package com.seaofnodes.simple.node;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.Parser;
import com.seaofnodes.simple.Var;
import com.seaofnodes.simple.type.Type;
-import java.util.BitSet;
/**
* A Forward Reference. Its any final constant, including functions. When
@@ -17,10 +18,9 @@ public class FRefNode extends ConstantNode {
@Override public String label() { return "FRef"+_n; }
- @Override public String uniqueName() { return "FRef_" + _nid; }
- @Override StringBuilder _print1(StringBuilder sb, BitSet visited) {
- return sb.append("FRef_").append(_n);
+ @Override protected ExprPrinter<Node> _print1(ExprPrinter<Node> p) {
+ return p.p("FRef_").p(_n);
}
@Override public Node idealize() {
diff --git a/chapter20/src/main/java/com/seaofnodes/simple/node/IfNode.java b/chapter20/src/main/java/com/seaofnodes/simple/node/IfNode.java
index e04522b0..2c4cad70 100644
--- a/chapter20/src/main/java/com/seaofnodes/simple/node/IfNode.java
+++ b/chapter20/src/main/java/com/seaofnodes/simple/node/IfNode.java
@@ -1,9 +1,9 @@
package com.seaofnodes.simple.node;
+
import com.seaofnodes.simple.codegen.CodeGen;
import com.seaofnodes.simple.IterPeeps;
import com.seaofnodes.simple.type.*;
-import java.util.BitSet;
import java.util.HashSet;
public class IfNode extends CFGNode implements MultiNode {
@@ -17,11 +17,7 @@ public class IfNode extends CFGNode implements MultiNode {
@Override
public String label() { return "If"; }
- @Override
- public StringBuilder _print1(StringBuilder sb, BitSet visited) {
- sb.append("if( ");
- return in(1)._print0(sb, visited).append(" )");
- }
+ @Override protected String format() { return "if( %1 )"; }
public Node ctrl() { return in(0); }
public Node pred() { return in(1); }
diff --git a/chapter20/src/main/java/com/seaofnodes/simple/node/LoadNode.java b/chapter20/src/main/java/com/seaofnodes/simple/node/LoadNode.java
index 76125e39..339e4460 100644
--- a/chapter20/src/main/java/com/seaofnodes/simple/node/LoadNode.java
+++ b/chapter20/src/main/java/com/seaofnodes/simple/node/LoadNode.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.Parser;
import com.seaofnodes.simple.Utils;
import com.seaofnodes.simple.type.*;
-import java.util.BitSet;
/**
* Load represents extracting a value from inside a memory object,
@@ -46,7 +47,7 @@ public class LoadNode extends MemOpNode {
// Debugger label
@Override public String label() { return "ld_"+mlabel(); }
@Override
- 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/chapter20/src/main/java/com/seaofnodes/simple/node/LogicalNode.java b/chapter20/src/main/java/com/seaofnodes/simple/node/LogicalNode.java
index 8c3452bf..6ac16d31 100644
--- a/chapter20/src/main/java/com/seaofnodes/simple/node/LogicalNode.java
+++ b/chapter20/src/main/java/com/seaofnodes/simple/node/LogicalNode.java
@@ -1,9 +1,10 @@
package com.seaofnodes.simple.node;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.Parser;
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeInteger;
-import java.util.BitSet;
public abstract class LogicalNode extends Node {
// Source location for late reported errors
@@ -12,11 +13,8 @@ public abstract class LogicalNode extends Node {
public LogicalNode(Parser.Lexer loc, Node lhs, Node rhs) { super(null, lhs, rhs); _loc = loc; }
abstract String op();
- @Override
- 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();
}
diff --git a/chapter20/src/main/java/com/seaofnodes/simple/node/MachConcreteNode.java b/chapter20/src/main/java/com/seaofnodes/simple/node/MachConcreteNode.java
index b01b3308..4f5d9151 100644
--- a/chapter20/src/main/java/com/seaofnodes/simple/node/MachConcreteNode.java
+++ b/chapter20/src/main/java/com/seaofnodes/simple/node/MachConcreteNode.java
@@ -1,9 +1,10 @@
package com.seaofnodes.simple.node;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.Utils;
import java.io.ByteArrayOutputStream;
-import java.util.BitSet;
// Generic machine-specific class, has a few Node implementations that have to
// exist (abstract) but are not useful past the optimizer.
@@ -16,12 +17,11 @@ public abstract class MachConcreteNode extends Node implements MachNode {
@Override public Type compute () { throw Utils.TODO(); }
@Override public Node idealize() { throw Utils.TODO(); }
- @Override public StringBuilder _print1(StringBuilder sb, BitSet visited) {
- sb.append("(").append(op()).append(",");
+ @Override protected ExprPrinter<Node> _print1(ExprPrinter<Node> p) {
+ p.open().p(op()).p(",");
for( int i=1; i<nIns(); i++ )
- (in(i)==null ? sb.append(" ---") : in(i)._print0(sb, visited)).append(",");
- sb.setLength(sb.length()-1);
- return sb.append(")");
+ (in(i)==null ? p.p(" ---") : p.n(in(i))).p(",");
+ return p.unchar(',').close();
}
}
diff --git a/chapter20/src/main/java/com/seaofnodes/simple/node/MemMergeNode.java b/chapter20/src/main/java/com/seaofnodes/simple/node/MemMergeNode.java
index 31c76a93..c8a76714 100644
--- a/chapter20/src/main/java/com/seaofnodes/simple/node/MemMergeNode.java
+++ b/chapter20/src/main/java/com/seaofnodes/simple/node/MemMergeNode.java
@@ -1,5 +1,7 @@
package com.seaofnodes.simple.node;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.*;
import com.seaofnodes.simple.codegen.CodeGen;
import com.seaofnodes.simple.type.*;
@@ -53,14 +55,14 @@ public class MemMergeNode extends Node {
@Override public String label() { return "MemMerge"; }
@Override public boolean isMem() { return true; }
@Override public Type compute() { return TypeMem.BOT; }
- @Override StringBuilder _print1(StringBuilder sb, BitSet visited) {
- sb.append("MEM[");
+ @Override protected ExprPrinter<Node> _print1(ExprPrinter<Node> p) {
+ p.p("MEM[");
for( int i=1; i<nIns(); i++ )
if( in(i)!=null ) {
- sb.append(i==1 ? "default:" : i+":");
- in(i)._print0(sb,visited).append(" ");
+ p.p(i==1 ? "default:" : i+":");
+ p.n(in(i)).p(" ");
}
- return sb.append("]");
+ return p.p("]");
}
@Override public Node idealize() {
diff --git a/chapter20/src/main/java/com/seaofnodes/simple/node/MemOpNode.java b/chapter20/src/main/java/com/seaofnodes/simple/node/MemOpNode.java
index 41760124..4f404846 100644
--- a/chapter20/src/main/java/com/seaofnodes/simple/node/MemOpNode.java
+++ b/chapter20/src/main/java/com/seaofnodes/simple/node/MemOpNode.java
@@ -1,5 +1,7 @@
package com.seaofnodes.simple.node;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.Parser;
import com.seaofnodes.simple.Utils;
import com.seaofnodes.simple.type.Type;
@@ -48,8 +50,8 @@ public abstract class MemOpNode extends Node {
public Node ptr() { return in(2); }
public Node off() { return in(3); }
- @Override 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/chapter20/src/main/java/com/seaofnodes/simple/node/MinusFNode.java b/chapter20/src/main/java/com/seaofnodes/simple/node/MinusFNode.java
index 129963c2..852e646d 100644
--- a/chapter20/src/main/java/com/seaofnodes/simple/node/MinusFNode.java
+++ b/chapter20/src/main/java/com/seaofnodes/simple/node/MinusFNode.java
@@ -1,20 +1,16 @@
package com.seaofnodes.simple.node;
+
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeFloat;
-import java.util.BitSet;
public class MinusFNode extends Node {
public MinusFNode(Node in) { super(null, in); }
@Override public String label() { return "MinusF"; }
- @Override
- 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/chapter20/src/main/java/com/seaofnodes/simple/node/MinusNode.java b/chapter20/src/main/java/com/seaofnodes/simple/node/MinusNode.java
index dad245fd..20220915 100644
--- a/chapter20/src/main/java/com/seaofnodes/simple/node/MinusNode.java
+++ b/chapter20/src/main/java/com/seaofnodes/simple/node/MinusNode.java
@@ -1,21 +1,17 @@
package com.seaofnodes.simple.node;
+
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeInteger;
import com.seaofnodes.simple.Utils;
-import java.util.BitSet;
public class MinusNode extends Node {
public MinusNode(Node in) { super(null, in); }
@Override public String label() { return "Minus"; }
- @Override
- 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/chapter20/src/main/java/com/seaofnodes/simple/node/MulFNode.java b/chapter20/src/main/java/com/seaofnodes/simple/node/MulFNode.java
index 4b753ba7..6a57f3c5 100644
--- a/chapter20/src/main/java/com/seaofnodes/simple/node/MulFNode.java
+++ b/chapter20/src/main/java/com/seaofnodes/simple/node/MulFNode.java
@@ -1,21 +1,16 @@
package com.seaofnodes.simple.node;
+
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeFloat;
-import java.util.BitSet;
public class MulFNode extends Node {
public MulFNode(Node lhs, Node rhs) { super(null, lhs, rhs); }
@Override public String label() { return "MulF"; }
- @Override
- StringBuilder _print1(StringBuilder sb, BitSet visited) {
- in(1)._print0(sb.append("("), visited);
- in(2)._print0(sb.append("*"), visited);
- return sb.append(")");
- }
+ @Override protected String format() { return "(%1*%2)"; }
@Override
public Type compute() {
diff --git a/chapter20/src/main/java/com/seaofnodes/simple/node/MulNode.java b/chapter20/src/main/java/com/seaofnodes/simple/node/MulNode.java
index c7fb620c..e9dc6887 100644
--- a/chapter20/src/main/java/com/seaofnodes/simple/node/MulNode.java
+++ b/chapter20/src/main/java/com/seaofnodes/simple/node/MulNode.java
@@ -1,21 +1,16 @@
package com.seaofnodes.simple.node;
+
import com.seaofnodes.simple.Parser;
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeInteger;
-import java.util.BitSet;
public class MulNode extends Node {
public MulNode(Node lhs, Node rhs) { super(null, lhs, rhs); }
@Override public String label() { return "Mul"; }
- @Override
- StringBuilder _print1(StringBuilder sb, BitSet visited) {
- in(1)._print0(sb.append("("), visited);
- in(2)._print0(sb.append("*"), visited);
- return sb.append(")");
- }
+ @Override protected String format() { return "(%1*%2)"; }
@Override
public Type compute() {
diff --git a/chapter20/src/main/java/com/seaofnodes/simple/node/NeverNode.java b/chapter20/src/main/java/com/seaofnodes/simple/node/NeverNode.java
index 26198500..7e42ccf9 100644
--- a/chapter20/src/main/java/com/seaofnodes/simple/node/NeverNode.java
+++ b/chapter20/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 {
@@ -13,7 +14,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/chapter20/src/main/java/com/seaofnodes/simple/node/NewNode.java b/chapter20/src/main/java/com/seaofnodes/simple/node/NewNode.java
index b9c9de71..68871918 100644
--- a/chapter20/src/main/java/com/seaofnodes/simple/node/NewNode.java
+++ b/chapter20/src/main/java/com/seaofnodes/simple/node/NewNode.java
@@ -1,7 +1,8 @@
package com.seaofnodes.simple.node;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.type.*;
-import java.util.BitSet;
/** Allocate a zeroed object. Inputs {ctrl, $mem, size};
* results {ptr, $mem}.
@@ -34,10 +35,8 @@ public class NewNode extends Node implements MultiNode {
@Override public String label() { return "new_"+(_ptr._obj.isAry() ? "ary_"+_ptr._obj._fields[1]._type.str() : _ptr._obj.str()); }
- @Override
- StringBuilder _print1(StringBuilder sb, BitSet visited) {
- sb.append("new ");
- return sb.append(_ptr._obj.str());
+ @Override protected ExprPrinter<Node> _print1(ExprPrinter<Node> p) {
+ return p.p("new ").p(_ptr._obj.str());
}
diff --git a/chapter20/src/main/java/com/seaofnodes/simple/node/Node.java b/chapter20/src/main/java/com/seaofnodes/simple/node/Node.java
index aecac75c..e038d351 100644
--- a/chapter20/src/main/java/com/seaofnodes/simple/node/Node.java
+++ b/chapter20/src/main/java/com/seaofnodes/simple/node/Node.java
@@ -1,5 +1,7 @@
package com.seaofnodes.simple.node;
+import com.seaofnodes.print.BaseNode;
+
import com.seaofnodes.simple.*;
import com.seaofnodes.simple.codegen.CodeGen;
import com.seaofnodes.simple.print.IRPrinter;
@@ -15,14 +17,7 @@ import static com.seaofnodes.simple.codegen.CodeGen.CODE;
* The Node class provides common functionality used by all subtypes.
* Subtypes of Node specialize by overriding methods.
*/
-public abstract class Node implements Cloneable {
-
- /**
- * Each node has a unique dense Node ID within a compilation context
- * The ID is useful for debugging, for using as an offset in a bitvector,
- * as well as for computing equality of nodes (to be implemented later).
- */
- public int _nid;
+public abstract class Node extends BaseNode<Node> implements Cloneable {
/**
* Inputs to the node. These are use-def references to Nodes.
@@ -44,16 +39,14 @@ public abstract class Node implements Cloneable {
*/
public Ary<Node> _outputs;
-
/**
* Current computed type for this Node. This value changes as the graph
* changes and more knowledge is gained about the program.
*/
public Type _type;
-
Node(Node... inputs) {
- _nid = CODE.getUID(); // allocate unique dense ID
+ super(CODE.getUID()); // allocate unique dense ID
_inputs = new Ary<>(Node.class);
Collections.addAll(_inputs,inputs);
_outputs = new Ary<>(Node.class);
@@ -65,8 +58,8 @@ public abstract class Node implements Cloneable {
// Make a Node using the existing arrays of nodes.
// Used by any pass rewriting all Node classes but not the edges.
Node( Node n ) {
+ super(CODE.getUID()); // allocate unique dense ID
assert CodeGen.CODE._phase.ordinal() >= CodeGen.Phase.InstSelect.ordinal();
- _nid = CODE.getUID(); // allocate unique dense ID
_inputs = new Ary<>(n==null ? new Node[0] : n._inputs.asAry());
_outputs = new Ary<>(Node.class);
_type = n==null ? Type.BOTTOM : n._type;
@@ -77,48 +70,6 @@ public abstract class Node implements Cloneable {
// Easy reading label for debugger, e.g. "Add" or "Region" or "EQ"
public abstract String label();
- // Unique label for debugging, e.g. "Add12" or "Region30" or "EQ99"
- public String uniqueName() {
- return label() + _nid;
- }
-
- // Operator symbol used by assembly/debug printing.
- public String glabel() { return label(); }
-
- // Extra fun stuff, for assembly printing. Jump labels, parser locations,
- // variable types, etc.
- public String comment() { return null; }
-
- // ------------------------------------------------------------------------
-
- // Debugger Printing.
-
- // {@code toString} is what you get in the debugger. It has to print 1
- // line (because this is what a debugger typically displays by default) and
- // has to be robust with broken graph/nodes.
- @Override
- public final String toString() { return print(); }
-
- // This is a *deep* print. We print with a mutually recursive tik-tok
- // style; the common _print0 calls the per-Node _print1, which calls back
- // to _print0;
- public final String print() {
- return _print0(new StringBuilder(), new BitSet()).toString();
- }
-
- // This is the common print: check for repeats, check for DEAD and print
- // "DEAD" else call the per-Node print1.
- public final StringBuilder _print0(StringBuilder sb, BitSet visited) {
- if (visited.get(_nid) && !(this instanceof ConstantNode) )
- return sb.append(label());
- visited.set(_nid);
- return isDead()
- ? sb.append(uniqueName()).append(":DEAD")
- : _print1(sb, visited);
- }
- // Every Node implements this; a partial-line recursive print
- abstract StringBuilder _print1(StringBuilder sb, BitSet visited);
-
public String p(int depth) { return IRPrinter.prettyPrint(this,depth); }
public boolean isConst() { return false; }
@@ -126,6 +77,8 @@ public abstract class Node implements Cloneable {
// ------------------------------------------------------------------------
// Graph Node & Edge manipulation
+ @Override public String typeName() { return _type==null ? null : _type.toString(); }
+
/**
* Gets the ith input node
* @param i Offset of the input node
@@ -204,7 +157,6 @@ public abstract class Node implements Cloneable {
return setDef(idx,new_def);
}
-
/**
* Add a new def to an existing Node. Keep the edges correct by
* adding the corresponding <em>def->use</em> edge.
@@ -280,7 +232,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;
@@ -525,7 +476,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
@@ -570,7 +520,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 ) {
@@ -588,7 +537,6 @@ public abstract class Node implements Cloneable {
// and can assume "this!=n" and has the same Java class.
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
@@ -604,7 +552,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;
@@ -624,7 +571,6 @@ public abstract class Node implements Cloneable {
/** Is this Node Memory related */
public boolean isMem() { return false; }
-
// Semantic change to the graph (so NOT a peephole), used by the Parser.
// If any input is a float, flip to a float-flavored opcode and widen any
// non-float input.
@@ -645,7 +591,6 @@ public abstract class Node implements Cloneable {
}
Node copyF() { return null; }
-
// ------------------------------------------------------------------------
// Peephole utilities
@@ -672,7 +617,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/chapter20/src/main/java/com/seaofnodes/simple/node/NotNode.java b/chapter20/src/main/java/com/seaofnodes/simple/node/NotNode.java
index 5e631b78..57fa9301 100644
--- a/chapter20/src/main/java/com/seaofnodes/simple/node/NotNode.java
+++ b/chapter20/src/main/java/com/seaofnodes/simple/node/NotNode.java
@@ -1,19 +1,15 @@
package com.seaofnodes.simple.node;
+
import com.seaofnodes.simple.Utils;
import com.seaofnodes.simple.type.*;
-import java.util.BitSet;
public class NotNode extends Node {
public NotNode(Node in) { super(null, in); }
@Override public String label() { return "Not"; }
- @Override
- 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/chapter20/src/main/java/com/seaofnodes/simple/node/ParmNode.java b/chapter20/src/main/java/com/seaofnodes/simple/node/ParmNode.java
index c7c21171..c3a0cf21 100644
--- a/chapter20/src/main/java/com/seaofnodes/simple/node/ParmNode.java
+++ b/chapter20/src/main/java/com/seaofnodes/simple/node/ParmNode.java
@@ -1,8 +1,9 @@
package com.seaofnodes.simple.node;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.Utils;
import com.seaofnodes.simple.type.Type;
-import java.util.BitSet;
public class ParmNode extends PhiNode {
@@ -20,18 +21,12 @@ public class ParmNode extends PhiNode {
public FunNode fun() { return (FunNode)in(0); }
@Override
- StringBuilder _print1(StringBuilder sb, BitSet visited) {
+ protected ExprPrinter<Node> _print1(ExprPrinter<Node> p) {
if( "main".equals(fun()._name) && _label.equals("arg") )
- return sb.append("arg");
- sb.append("Parm_").append(_label).append("(");
- for( Node in : _inputs ) {
- if (in == null) sb.append("____");
- else in._print0(sb, visited);
- sb.append(",");
- }
- sb.setLength(sb.length()-1);
- sb.append(")");
- return sb;
+ return p.p("arg");
+ p.p("Parm_").p(_label).open();
+ for( Node in : _inputs ) p.n(in).p(",");
+ return p.unchar(',').close();
}
diff --git a/chapter20/src/main/java/com/seaofnodes/simple/node/PhiNode.java b/chapter20/src/main/java/com/seaofnodes/simple/node/PhiNode.java
index 52298345..a752977b 100644
--- a/chapter20/src/main/java/com/seaofnodes/simple/node/PhiNode.java
+++ b/chapter20/src/main/java/com/seaofnodes/simple/node/PhiNode.java
@@ -1,8 +1,9 @@
package com.seaofnodes.simple.node;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.*;
import com.seaofnodes.simple.type.*;
-import java.util.BitSet;
public class PhiNode extends Node {
@@ -31,18 +32,12 @@ public class PhiNode extends Node {
@Override public String label() { return "Phi_"+MemOpNode.mlabel(_label); }
@Override
- 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/chapter20/src/main/java/com/seaofnodes/simple/node/ProjNode.java b/chapter20/src/main/java/com/seaofnodes/simple/node/ProjNode.java
index 83044156..da5841f6 100644
--- a/chapter20/src/main/java/com/seaofnodes/simple/node/ProjNode.java
+++ b/chapter20/src/main/java/com/seaofnodes/simple/node/ProjNode.java
@@ -1,10 +1,11 @@
package com.seaofnodes.simple.node;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeMem;
import com.seaofnodes.simple.type.TypeTuple;
-import java.util.BitSet;
public class ProjNode extends Node {
@@ -24,11 +25,11 @@ public class ProjNode extends Node {
@Override public String label() { return _label; }
@Override
- 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/chapter20/src/main/java/com/seaofnodes/simple/node/ReadOnlyNode.java b/chapter20/src/main/java/com/seaofnodes/simple/node/ReadOnlyNode.java
index b755af3f..d79f2815 100644
--- a/chapter20/src/main/java/com/seaofnodes/simple/node/ReadOnlyNode.java
+++ b/chapter20/src/main/java/com/seaofnodes/simple/node/ReadOnlyNode.java
@@ -1,9 +1,9 @@
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
@@ -13,10 +13,7 @@ public class ReadOnlyNode extends Node {
public ReadOnlyNode( ReadOnlyNode n ) { super(n); }
@Override public String label() { return "ReadOnly"; }
- @Override
- 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/chapter20/src/main/java/com/seaofnodes/simple/node/RegionNode.java b/chapter20/src/main/java/com/seaofnodes/simple/node/RegionNode.java
index f28952e0..8993a49f 100644
--- a/chapter20/src/main/java/com/seaofnodes/simple/node/RegionNode.java
+++ b/chapter20/src/main/java/com/seaofnodes/simple/node/RegionNode.java
@@ -1,5 +1,7 @@
package com.seaofnodes.simple.node;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.*;
import com.seaofnodes.simple.codegen.CodeGen;
import com.seaofnodes.simple.type.Type;
@@ -16,9 +18,8 @@ public class RegionNode extends CFGNode {
@Override
public String label() { return "Region"; }
- @Override
- 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/chapter20/src/main/java/com/seaofnodes/simple/node/ReturnNode.java b/chapter20/src/main/java/com/seaofnodes/simple/node/ReturnNode.java
index 7858671c..e101ee09 100644
--- a/chapter20/src/main/java/com/seaofnodes/simple/node/ReturnNode.java
+++ b/chapter20/src/main/java/com/seaofnodes/simple/node/ReturnNode.java
@@ -1,10 +1,11 @@
package com.seaofnodes.simple.node;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.Parser;
import com.seaofnodes.simple.SB;
import com.seaofnodes.simple.Utils;
import com.seaofnodes.simple.type.*;
-import java.util.BitSet;
/** Keeps all preceding memory effects and the return value alive: {ctrl, $mem, value, rpc}. */
public class ReturnNode extends CFGNode {
@@ -27,11 +28,11 @@ public class ReturnNode extends CFGNode {
public String label() { return "Return"; }
@Override
- 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/chapter20/src/main/java/com/seaofnodes/simple/node/RoundF32Node.java b/chapter20/src/main/java/com/seaofnodes/simple/node/RoundF32Node.java
index 3dd7cbf0..78e7698c 100644
--- a/chapter20/src/main/java/com/seaofnodes/simple/node/RoundF32Node.java
+++ b/chapter20/src/main/java/com/seaofnodes/simple/node/RoundF32Node.java
@@ -1,19 +1,16 @@
package com.seaofnodes.simple.node;
+
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeFloat;
-import java.util.BitSet;
public class RoundF32Node extends Node {
public RoundF32Node(Node lhs) { super(null, lhs); }
@Override public String label() { return "RoundF32"; }
- @Override
- 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/chapter20/src/main/java/com/seaofnodes/simple/node/ScopeNode.java b/chapter20/src/main/java/com/seaofnodes/simple/node/ScopeNode.java
index 406be11f..2724d0a6 100644
--- a/chapter20/src/main/java/com/seaofnodes/simple/node/ScopeNode.java
+++ b/chapter20/src/main/java/com/seaofnodes/simple/node/ScopeNode.java
@@ -1,5 +1,7 @@
package com.seaofnodes.simple.node;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.*;
import com.seaofnodes.simple.codegen.CodeGen;
import com.seaofnodes.simple.type.*;
@@ -49,28 +51,26 @@ public class ScopeNode extends Node {
@Override public String label() { return "Scope"; }
@Override
- StringBuilder _print1(StringBuilder sb, BitSet visited) {
- sb.append("Scope[ ");
+ protected ExprPrinter<Node> _print1(ExprPrinter<Node> p) {
+ p.p("Scope[ ");
int j=1;
for( int i=0; i<nIns(); i++ ) {
- if( j < _lexSize._len && i == _lexSize.at(j) ) { sb.append("| "); j++; }
+ if( j < _lexSize._len && i == _lexSize.at(j) ) { p.p("| "); j++; }
Var v = _vars.get(i);
- sb.append(v._type().print(new SB()));
- sb.append(" ");
- if( v._final ) sb.append("!");
- sb.append(v._name);
- sb.append("=");
+ p.p(v._type().print(new SB()));
+ p.p(" ");
+ if( v._final ) p.p("!");
+ p.p(v._name);
+ p.p("=");
Node n = in(i);
while( n instanceof ScopeNode loop ) {
- sb.append("Lazy_");
+ p.p("Lazy_");
n = loop.in(i);
}
- if( n==null ) sb.append("___");
- else n._print0(sb, visited);
- sb.append(", ");
+ p.n(n);
+ p.p(", ");
}
- sb.setLength(sb.length()-2);
- return sb.append("]");
+ return p.unchar(", ").p("]");
}
diff --git a/chapter20/src/main/java/com/seaofnodes/simple/node/SplitNode.java b/chapter20/src/main/java/com/seaofnodes/simple/node/SplitNode.java
index 37d1a63d..07166a7c 100644
--- a/chapter20/src/main/java/com/seaofnodes/simple/node/SplitNode.java
+++ b/chapter20/src/main/java/com/seaofnodes/simple/node/SplitNode.java
@@ -1,20 +1,21 @@
package com.seaofnodes.simple.node;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.SB;
import com.seaofnodes.simple.codegen.CodeGen;
import com.seaofnodes.simple.type.Type;
-import java.util.BitSet;
public abstract class SplitNode extends MachConcreteNode {
public final String _kind; // Kind of split
public final byte _round;
public SplitNode(String kind, byte round, Node[] nodes) { super(nodes); _kind = kind; _round = round; }
@Override public String op() { return "mov"; }
- @Override public StringBuilder _print1(StringBuilder sb, BitSet visited) {
- sb.append("mov(");
- if( in(1)==null ) sb.append("---");
- else in(1)._print0(sb,visited);
- return sb.append(")");
+ @Override protected ExprPrinter<Node> _print1(ExprPrinter<Node> p) {
+ p.p("mov(");
+ if( in(1)==null ) p.p("---");
+ else p.n(in(1));
+ return p.close();
}
@Override public Type compute() { return in(0)._type; }
@Override public Node idealize() { return null; }
diff --git a/chapter20/src/main/java/com/seaofnodes/simple/node/StartNode.java b/chapter20/src/main/java/com/seaofnodes/simple/node/StartNode.java
index 2783ab93..cbaefa6a 100644
--- a/chapter20/src/main/java/com/seaofnodes/simple/node/StartNode.java
+++ b/chapter20/src/main/java/com/seaofnodes/simple/node/StartNode.java
@@ -1,9 +1,10 @@
package com.seaofnodes.simple.node;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.codegen.CodeGen;
import com.seaofnodes.simple.Parser;
import com.seaofnodes.simple.type.*;
-import java.util.BitSet;
import java.util.HashSet;
import static com.seaofnodes.simple.Utils.TODO;
@@ -17,9 +18,8 @@ public class StartNode extends LoopNode implements MultiNode {
@Override public String label() { return "Start"; }
- @Override
- 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/chapter20/src/main/java/com/seaofnodes/simple/node/StopNode.java b/chapter20/src/main/java/com/seaofnodes/simple/node/StopNode.java
index 80c911ca..524c6a9e 100644
--- a/chapter20/src/main/java/com/seaofnodes/simple/node/StopNode.java
+++ b/chapter20/src/main/java/com/seaofnodes/simple/node/StopNode.java
@@ -1,8 +1,9 @@
package com.seaofnodes.simple.node;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.Utils;
import com.seaofnodes.simple.type.Type;
-import java.util.BitSet;
public class StopNode extends CFGNode {
@@ -21,13 +22,13 @@ public class StopNode extends CFGNode {
}
@Override
- 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"
- if( ret()!=null ) return ret()._print0(sb,visited);
- sb.append("Stop[ ");
+ if( ret()!=null ) return p.n(ret());
+ p.p("Stop[ ");
for( Node ret : _inputs )
- ret._print0(sb, visited).append(" ");
- return sb.append("]");
+ p.n(ret).p(" ");
+ return p.p("]");
}
@Override public boolean blockHead() { return true; }
diff --git a/chapter20/src/main/java/com/seaofnodes/simple/node/StoreNode.java b/chapter20/src/main/java/com/seaofnodes/simple/node/StoreNode.java
index 4833df39..e9a35a0d 100644
--- a/chapter20/src/main/java/com/seaofnodes/simple/node/StoreNode.java
+++ b/chapter20/src/main/java/com/seaofnodes/simple/node/StoreNode.java
@@ -1,9 +1,10 @@
package com.seaofnodes.simple.node;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.codegen.*;
import com.seaofnodes.simple.*;
import com.seaofnodes.simple.type.*;
-import java.util.BitSet;
/**
* Store represents setting a value to a memory based object, in chapter 10
@@ -36,8 +37,8 @@ public class StoreNode extends MemOpNode {
public Node val() { return in(4); }
@Override
- 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/chapter20/src/main/java/com/seaofnodes/simple/node/StructNode.java b/chapter20/src/main/java/com/seaofnodes/simple/node/StructNode.java
index 076b342a..b9801f63 100644
--- a/chapter20/src/main/java/com/seaofnodes/simple/node/StructNode.java
+++ b/chapter20/src/main/java/com/seaofnodes/simple/node/StructNode.java
@@ -1,8 +1,9 @@
package com.seaofnodes.simple.node;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.SB;
import com.seaofnodes.simple.type.*;
-import java.util.BitSet;
/**
* Build a compound object
@@ -14,16 +15,15 @@ public class StructNode extends Node {
@Override public String label() { return _ts==null ? "STRUCT?" : _ts.str(); }
@Override
- StringBuilder _print1(StringBuilder sb, BitSet visited) {
- if( _ts==null ) return sb.append("STRUCT?");
- sb.append(_ts._name).append(" {");
+ protected ExprPrinter<Node> _print1(ExprPrinter<Node> p) {
+ if( _ts==null ) return p.p("STRUCT?");
+ p.p(_ts._name).p(" {");
for( int i=0; i<nIns(); i++ ) {
- sb.append(_ts._fields[i]._fname).append(":");
- sb.append((in(i)==null ? Type.BOTTOM : in(i)._type).print(new SB()));
- sb.append("; ");
+ p.p(_ts._fields[i]._fname).p(":");
+ p.p((in(i)==null ? Type.BOTTOM : in(i)._type).print(new SB()));
+ p.p("; ");
}
- sb.setLength(sb.length()-2);
- return sb.append("}");
+ return p.unchar("; ").p("}");
}
@Override
diff --git a/chapter20/src/main/java/com/seaofnodes/simple/node/SubFNode.java b/chapter20/src/main/java/com/seaofnodes/simple/node/SubFNode.java
index 27bbda8d..2d218a03 100644
--- a/chapter20/src/main/java/com/seaofnodes/simple/node/SubFNode.java
+++ b/chapter20/src/main/java/com/seaofnodes/simple/node/SubFNode.java
@@ -1,21 +1,16 @@
package com.seaofnodes.simple.node;
+
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeFloat;
-import java.util.BitSet;
public class SubFNode extends Node {
public SubFNode(Node lhs, Node rhs) { super(null, lhs, rhs); }
@Override public String label() { return "SubF"; }
- @Override
- StringBuilder _print1(StringBuilder sb, BitSet visited) {
- in(1)._print0(sb.append("("), visited);
- in(2)._print0(sb.append("-"), visited);
- return sb.append(")");
- }
+ @Override protected String format() { return "(%1-%2)"; }
@Override
public Type compute() {
diff --git a/chapter20/src/main/java/com/seaofnodes/simple/node/SubNode.java b/chapter20/src/main/java/com/seaofnodes/simple/node/SubNode.java
index 034f2fb1..9bf6d83e 100644
--- a/chapter20/src/main/java/com/seaofnodes/simple/node/SubNode.java
+++ b/chapter20/src/main/java/com/seaofnodes/simple/node/SubNode.java
@@ -1,21 +1,16 @@
package com.seaofnodes.simple.node;
+
import com.seaofnodes.simple.Parser;
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeInteger;
-import java.util.BitSet;
public class SubNode extends Node {
public SubNode(Node lhs, Node rhs) { super(null, lhs, rhs); }
@Override public String label() { return "Sub"; }
- @Override
- StringBuilder _print1(StringBuilder sb, BitSet visited) {
- in(1)._print0(sb.append("("), visited);
- in(2)._print0(sb.append("-"), visited);
- return sb.append(")");
- }
+ @Override protected String format() { return "(%1-%2)"; }
@Override
public Type compute() {
diff --git a/chapter20/src/main/java/com/seaofnodes/simple/node/ToFloatNode.java b/chapter20/src/main/java/com/seaofnodes/simple/node/ToFloatNode.java
index a4aa8934..7b0122ce 100644
--- a/chapter20/src/main/java/com/seaofnodes/simple/node/ToFloatNode.java
+++ b/chapter20/src/main/java/com/seaofnodes/simple/node/ToFloatNode.java
@@ -1,20 +1,17 @@
package com.seaofnodes.simple.node;
+
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeFloat;
import com.seaofnodes.simple.type.TypeInteger;
-import java.util.BitSet;
public class ToFloatNode extends Node {
public ToFloatNode(Node lhs) { super(null, lhs); }
@Override public String label() { return "ToFloat"; }
- @Override
- 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/chapter20/src/main/java/com/seaofnodes/simple/node/XCtrlNode.java b/chapter20/src/main/java/com/seaofnodes/simple/node/XCtrlNode.java
index da021246..477b9af8 100644
--- a/chapter20/src/main/java/com/seaofnodes/simple/node/XCtrlNode.java
+++ b/chapter20/src/main/java/com/seaofnodes/simple/node/XCtrlNode.java
@@ -1,14 +1,15 @@
package com.seaofnodes.simple.node;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.codegen.CodeGen;
import com.seaofnodes.simple.Parser;
import com.seaofnodes.simple.type.Type;
-import java.util.BitSet;
public class XCtrlNode extends CFGNode {
public XCtrlNode() { super(new Node[]{CodeGen.CODE._start}); }
@Override public String label() { return "Xctrl"; }
- @Override 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/chapter20/src/main/java/com/seaofnodes/simple/node/cpus/arm/CallARM.java b/chapter20/src/main/java/com/seaofnodes/simple/node/cpus/arm/CallARM.java
index 4359c045..0f883847 100644
--- a/chapter20/src/main/java/com/seaofnodes/simple/node/cpus/arm/CallARM.java
+++ b/chapter20/src/main/java/com/seaofnodes/simple/node/cpus/arm/CallARM.java
@@ -34,7 +34,7 @@ public class CallARM extends CallNode implements MachNode {
}
@Override public void asm(CodeGen code, SB sb) {
- sb.p(_name);
+ sb.p(_name).p(" ");
for( int i=0; i<nargs(); i++ )
sb.p(code.reg(arg(i))).p(" ");
sb.unchar(2);
diff --git a/chapter20/src/main/java/com/seaofnodes/simple/node/cpus/arm/MemOpARM.java b/chapter20/src/main/java/com/seaofnodes/simple/node/cpus/arm/MemOpARM.java
index e874ce15..c22e71f6 100644
--- a/chapter20/src/main/java/com/seaofnodes/simple/node/cpus/arm/MemOpARM.java
+++ b/chapter20/src/main/java/com/seaofnodes/simple/node/cpus/arm/MemOpARM.java
@@ -1,5 +1,7 @@
package com.seaofnodes.simple.node.cpus.arm;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.*;
import com.seaofnodes.simple.codegen.CodeGen;
import com.seaofnodes.simple.codegen.RegMask;
@@ -7,7 +9,6 @@ import com.seaofnodes.simple.node.*;
import com.seaofnodes.simple.type.*;
import java.io.ByteArrayOutputStream;
import java.lang.StringBuilder;
-import java.util.BitSet;
public class MemOpARM extends MemOpNode implements MachNode {
@@ -32,7 +33,7 @@ public class MemOpARM extends MemOpNode implements MachNode {
Node idx() { return in(3); }
Node val() { return in(4); } // Only for stores, includin
- @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 boolean isMem() { return _type instanceof TypeMem; }
diff --git a/chapter20/src/main/java/com/seaofnodes/simple/node/cpus/riscv/BranchRISC.java b/chapter20/src/main/java/com/seaofnodes/simple/node/cpus/riscv/BranchRISC.java
index 6a1cf7dc..30dfd7fe 100644
--- a/chapter20/src/main/java/com/seaofnodes/simple/node/cpus/riscv/BranchRISC.java
+++ b/chapter20/src/main/java/com/seaofnodes/simple/node/cpus/riscv/BranchRISC.java
@@ -1,11 +1,12 @@
package com.seaofnodes.simple.node.cpus.riscv;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.*;
import com.seaofnodes.simple.codegen.CodeGen;
import com.seaofnodes.simple.codegen.RegMask;
import com.seaofnodes.simple.node.*;
import java.io.ByteArrayOutputStream;
-import java.util.BitSet;
// Conditional branch such as: BEQ
public class BranchRISC extends IfNode implements MachNode {
@@ -23,11 +24,11 @@ public class BranchRISC extends IfNode implements MachNode {
@Override public RegMask regmap(int i) { return riscv.RMASK; }
@Override public RegMask outregmap() { return null; }
- @Override public StringBuilder _print1(StringBuilder sb, BitSet visited) {
- in(1)._print0(sb.append("if( "),visited).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( ").n(in(1)).p(_bop);
+ if( in(2)==null ) p.p("0");
+ else p.n(in(2));
+ return p.p(" )");
}
// Encoding is appended into the byte array; size is returned
diff --git a/chapter20/src/main/java/com/seaofnodes/simple/node/cpus/riscv/ImmRISC.java b/chapter20/src/main/java/com/seaofnodes/simple/node/cpus/riscv/ImmRISC.java
index 02191d05..330de299 100644
--- a/chapter20/src/main/java/com/seaofnodes/simple/node/cpus/riscv/ImmRISC.java
+++ b/chapter20/src/main/java/com/seaofnodes/simple/node/cpus/riscv/ImmRISC.java
@@ -1,11 +1,12 @@
package com.seaofnodes.simple.node.cpus.riscv;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.*;
import com.seaofnodes.simple.codegen.CodeGen;
import com.seaofnodes.simple.codegen.RegMask;
import com.seaofnodes.simple.node.*;
import com.seaofnodes.simple.type.TypeInteger;
-import java.util.BitSet;
import java.io.ByteArrayOutputStream;
public abstract class ImmRISC extends MachConcreteNode implements MachNode {
@@ -21,9 +22,8 @@ public abstract class ImmRISC extends MachConcreteNode implements MachNode {
// Register mask allowed as a result. 0 for no register.
@Override public RegMask outregmap() { return riscv.WMASK; }
- @Override public StringBuilder _print1(StringBuilder sb, BitSet visited) {
- in(1)._print0(sb.append("( "), visited);
- return sb.append(String.format(" %s #%d )",glabel(),_imm));
+ @Override protected ExprPrinter<Node> _print1(ExprPrinter<Node> p) {
+ return p.p("( ").n(in(1)).p(String.format(" %s #%d )",glabel(),_imm));
}
abstract int opcode();
diff --git a/chapter20/src/main/java/com/seaofnodes/simple/node/cpus/riscv/MemOpRISC.java b/chapter20/src/main/java/com/seaofnodes/simple/node/cpus/riscv/MemOpRISC.java
index 01f51b57..19869285 100644
--- a/chapter20/src/main/java/com/seaofnodes/simple/node/cpus/riscv/MemOpRISC.java
+++ b/chapter20/src/main/java/com/seaofnodes/simple/node/cpus/riscv/MemOpRISC.java
@@ -1,5 +1,7 @@
package com.seaofnodes.simple.node.cpus.riscv;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.*;
import com.seaofnodes.simple.codegen.CodeGen;
import com.seaofnodes.simple.codegen.RegMask;
@@ -7,7 +9,6 @@ import com.seaofnodes.simple.node.*;
import com.seaofnodes.simple.type.*;
import java.io.ByteArrayOutputStream;
import java.lang.StringBuilder;
-import java.util.BitSet;
public class MemOpRISC extends MemOpNode implements MachNode {
@@ -31,7 +32,7 @@ public class MemOpRISC 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 boolean isMem() { return _type instanceof TypeMem; }
diff --git a/chapter20/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/MemOpX86.java b/chapter20/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/MemOpX86.java
index 1a771081..e74de677 100644
--- a/chapter20/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/MemOpX86.java
+++ b/chapter20/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/MemOpX86.java
@@ -1,5 +1,7 @@
package com.seaofnodes.simple.node.cpus.x86_64_v2;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.*;
import com.seaofnodes.simple.codegen.CodeGen;
import com.seaofnodes.simple.codegen.RegMask;
@@ -7,7 +9,6 @@ import com.seaofnodes.simple.node.*;
import com.seaofnodes.simple.type.*;
import java.io.ByteArrayOutputStream;
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 boolean isMem() { return _type instanceof TypeMem; }
diff --git a/chapter20/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/StoreX86.java b/chapter20/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/StoreX86.java
index 024ef904..08d481fa 100644
--- a/chapter20/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/StoreX86.java
+++ b/chapter20/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/StoreX86.java
@@ -1,11 +1,12 @@
package com.seaofnodes.simple.node.cpus.x86_64_v2;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.SB;
import com.seaofnodes.simple.codegen.CodeGen;
import com.seaofnodes.simple.codegen.RegMask;
import com.seaofnodes.simple.node.Node;
import com.seaofnodes.simple.node.StoreNode;
-import java.util.BitSet;
public class StoreX86 extends MemOpX86 {
StoreX86( StoreNode st, Node base, Node idx, int off, int scale, int imm, Node val ) {
@@ -14,12 +15,12 @@ public class StoreX86 extends MemOpX86 {
@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.
diff --git a/chapter20/src/main/java/com/seaofnodes/simple/print/ASMPrinter.java b/chapter20/src/main/java/com/seaofnodes/simple/print/ASMPrinter.java
index 1a233aa2..a4f768c5 100644
--- a/chapter20/src/main/java/com/seaofnodes/simple/print/ASMPrinter.java
+++ b/chapter20/src/main/java/com/seaofnodes/simple/print/ASMPrinter.java
@@ -1,163 +1,53 @@
package com.seaofnodes.simple.print;
+import com.seaofnodes.print.AssemblyAdapter;
+import com.seaofnodes.print.ASMPrinter.Data;
+import com.seaofnodes.print.ASMPrinter.Pool;
import com.seaofnodes.simple.codegen.CodeGen;
import com.seaofnodes.simple.SB;
import com.seaofnodes.simple.node.*;
-import com.seaofnodes.simple.type.TypeFunPtr;
-import com.seaofnodes.simple.type.TypeMem;
-import com.seaofnodes.simple.type.TypeRPC;
-
-public abstract class ASMPrinter {
-
+import com.seaofnodes.simple.type.*;
+import java.util.ArrayList;
+
+/** Machine-specific facts; traversal, columns and byte display live in print/. */
+public final class ASMPrinter extends AssemblyAdapter<Node> {
+ private final CodeGen _code;
+ private ASMPrinter(CodeGen code) {
+ super(new IRPrinter());
+ _code=code;
+ }
public static SB print(SB sb, CodeGen code) {
- if( code._cfg==null )
- return sb.p("Need _cfg set, run after GCM");
-
- // instruction address
- int iadr = 0;
- for( int i=0; i<code._cfg._len; i++ )
- if( code._cfg.at(i) instanceof FunNode fun )
- iadr = print(iadr,sb,code,fun,i);
- return sb;
+ return sb.p(new com.seaofnodes.print.ASMPrinter<>(new ASMPrinter(code)).print());
}
-
- private static int print(int iadr, SB sb, CodeGen code, 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();
-
-
- while( !(code._cfg.at(cfgidx) instanceof ReturnNode) )
- iadr = doBlock(iadr,sb,code,fun,cfgidx++);
-
- // Function separator
- sb.p("---");
- fun.sig().print(sb);
- sb.p("---------------------------").nl();
- return iadr;
+ @Override public ArrayList<Node> blocks() {
+ var blocks=new ArrayList<Node>();
+ var cfg=_code._cfg;
+ if( cfg!=null ) for( Node n : cfg ) blocks.add(n);
+ return blocks;
}
-
- static private final int encWidth = 8;
- static private final int opWidth = 5;
- static private final int argWidth = 30;
- static int doBlock(int iadr, SB sb, CodeGen code, FunNode fun, int cfgidx) {
- CFGNode bb = code._cfg.at(cfgidx);
- if( bb != fun && !(bb instanceof IfNode) && !(bb instanceof CallEndNode) && !(bb instanceof CallNode) && !(bb instanceof CProjNode && bb.in(0) instanceof CallEndNode ))
- sb.p(bb instanceof LoopNode ? "LOOP" : "L").p(bb._nid).p(":").nl();
- if( bb instanceof CallNode ) return iadr;
- final boolean postAlloc = code._phase.ordinal() > CodeGen.Phase.RegAlloc.ordinal();
-
- // Count Phis
- int nPhi=0;
- for( ; nPhi<bb.nOuts(); nPhi++ )
- if( !(bb.out(nPhi) instanceof PhiNode) )
- break;
-
- if( nPhi>0 ) {
- // Post-alloc phi prints all on one line
- if( postAlloc ) {
- sb.fix(4," ").p(" ").fix(encWidth,"").p(" ");
- for( int i=0; i<nPhi; i++ ) {
- PhiNode phi = (PhiNode)bb.out(i);
- if( !(phi._type instanceof TypeMem || phi._type instanceof TypeRPC) ) // Nothing for the hidden ones
- sb.p(phi._label).p(':').p(code.reg(phi)).p(',');
- }
- sb.unchar().nl();
-
- } else {
- for( int j=0; j<nPhi; j++ ) {
- PhiNode phi = (PhiNode)bb.out(j);
- if( phi._type instanceof TypeMem || phi._type instanceof TypeRPC ) continue; // Nothing for the hidden ones
- sb.fix(4," ").p(" ").fix(encWidth,"").p(" ").fix(opWidth,phi._label).p(" ");
- sb.p(code.reg(phi));
- if( !(phi instanceof ParmNode) ) {
- 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();
- }
- }
+ @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(' ');
}
-
- // All the non-phis
- for( int i=nPhi; i<bb.nOuts(); i++ )
- iadr = doInst(iadr, sb,code,fun,bb,bb.out(i),postAlloc );
-
- return iadr;
+ return sb.toString();
}
-
- static int doInst(int iadr, SB sb, CodeGen code, FunNode fun, CFGNode bb, Node n, boolean postAlloc ) {
- if( n instanceof CProjNode ) return iadr;
- if( n instanceof CalleeSaveNode && postAlloc ) return iadr;
-
- // 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 && !(n instanceof FunNode) ) {
- sb.hex4(iadr++).p(" ").fix(encWidth,"??").p(" ").fix(opWidth,"JMP").p(" ").fix(argWidth,"L"+n._nid).nl();
- return iadr;
- }
-
- // ProjNodes following a multi (e.g. Call or New results),
- // get indent slightly and just print their index & node#
- if( n instanceof ProjNode proj ) {
- if( proj._type instanceof TypeMem ) return iadr; // Nothing for the hidden ones
- sb.fix(4," ").p(" ").fix(encWidth,"").p(" ").fix(opWidth,proj._label==null ? "---" : proj._label).p(" ").p(code.reg(n)).nl();
- return iadr;
- }
-
- // ADDR ENCODING Op--- dst = src op src // Comment
- // 1234 abcdefgh ld4 RAX = [Rbase + off] // Comment
- sb.hex4(iadr);
- sb.p(" ");
-
- // Encoding
- int size = 1; // TODO: Fake encoding size
- iadr += size;
- sb.fix(encWidth,"??");
- sb.p(" ");
-
- // Op; generally "ld4" or "call"
- sb.fix(opWidth, n instanceof MachNode mach ? mach.op() : n.label());
- sb.p(" ");
-
- // General asm args
- if( n instanceof MachNode mach ) {
- int old = sb.len();
- mach.asm(code,sb);
- sb.fix(argWidth-(sb.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();
-
- // MultiNodes are immediately followed by projection(s)
- if( !(n instanceof CFGNode) && n instanceof MultiNode ) {
- for( Node proj : n._outputs ) {
- assert proj instanceof ProjNode;
- doInst(iadr,sb,code,fun,bb,proj,postAlloc);
- }
- }
-
- 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);
+ }
+ @Override public boolean hidden(Node n) {
+ if( n instanceof PhiNode || n instanceof ProjNode )
+ if( n._type instanceof TypeMem || n._type instanceof TypeRPC ) return true;
+ if( postAlloc() && n instanceof CalleeSaveNode ) return true;
+ if( n instanceof MemMergeNode ) return true;
+ return n.getClass()==ConstantNode.class;
}
+ @Override public boolean postAlloc() { return _code._phase.ordinal()>CodeGen.Phase.RegAlloc.ordinal(); }
}
diff --git a/chapter20/src/main/java/com/seaofnodes/simple/print/IRPrinter.java b/chapter20/src/main/java/com/seaofnodes/simple/print/IRPrinter.java
index 0e79d54d..e4d719f4 100644
--- a/chapter20/src/main/java/com/seaofnodes/simple/print/IRPrinter.java
+++ b/chapter20/src/main/java/com/seaofnodes/simple/print/IRPrinter.java
@@ -1,349 +1,61 @@
package com.seaofnodes.simple.print;
-import com.seaofnodes.simple.Ary;
-import com.seaofnodes.simple.SB;
-import com.seaofnodes.simple.Utils;
-import com.seaofnodes.simple.codegen.CodeGen;
+import com.seaofnodes.print.IRAdapter;
import com.seaofnodes.simple.node.*;
-import com.seaofnodes.simple.type.TypeFunPtr;
import java.util.ArrayList;
-import java.util.BitSet;
-import java.util.HashMap;
-
-public abstract class IRPrinter {
-
- // Print a node on 1 line, columnar aligned, as:
- // NNID NNAME DDEF DDEF [[ UUSE UUSE ]] TYPE
- // 1234 sssss 1234 1234 1234 1234 1234 1234 tttttt
- public static SB printLine( Node n, SB sb ) {
- sb.p("%4d %-7.7s ".formatted(n._nid,n.label()));
- if( n.isDead() )
- return sb.p("DEAD\n");
- for( Node def : n._inputs )
- sb.p(def==null ? "____" : "%4d".formatted(def._nid))
- // Lazy Phi indicator
- .p(n instanceof MemMergeNode && def instanceof MemMergeNode ? "^" : " ");
- for( int i = n._inputs.size(); i<4; i++ )
- sb.p(" ");
- sb.p(" [[ ");
- for( Node use : n._outputs )
- sb.p(use==null ? "____ " : "%4d ".formatted(use._nid));
- int lim = 6 - Math.max(n._inputs.size(),4);
- for( int i = n._outputs.size(); i<lim; i++ )
- sb.p(" ");
- sb.p(" ]] ");
- if( n._type!= null ) sb.p(n._type.str());
- return sb.p("\n");
- }
-
-
- public static String prettyPrint(Node node, int depth) {
- return CodeGen.CODE._phase.ordinal() > CodeGen.Phase.Schedule.ordinal()
- ? _prettyPrintScheduled( node, depth )
- : _prettyPrint( node, depth );
- }
-
- // Another bulk pretty-printer. Makes more effort at basic-block grouping.
- private static String _prettyPrint( Node node, int depth ) {
- // First, a Breadth First Search at a fixed depth.
- BFS bfs = new BFS(node,depth);
- // Convert just that set to a post-order
- ArrayList<Node> rpos = new ArrayList<>();
- BitSet visit = new BitSet();
- for( int i=bfs._lim; i< bfs._bfs.size(); i++ )
- postOrd( bfs._bfs.get(i), null, rpos, visit, bfs._bs);
- // Reverse the post-order walk
- SB sb = new SB();
- boolean gap=false;
- for( int i=rpos.size()-1; i>=0; i-- ) {
- Node n = rpos.get(i);
- if( n instanceof CFGNode || n instanceof MultiNode ) {
- if( !gap ) sb.p("\n"); // Blank before multihead
- if( n instanceof FunNode fun )
- fun.sig().print(sb.p("--- ").p(fun._name==null ? "" : fun._name).p(" "),false).p("----------------------\n");
- printLine( n, sb ); // Print head
- while( --i >= 0 ) {
- Node t = rpos.get(i);
- if( !(t.in(0) instanceof MultiNode) ) { i++; break; }
- printLine( t, sb );
- }
- if( n instanceof ReturnNode ret ) {
- FunNode fun = ret.fun();
- sb.p("--- ");
- if( fun != null )
- fun.sig().print(sb.p(fun._name==null ? "" : fun._name).p(" "),false);
- sb.p("----------------------\n");
- }
- if( !(n instanceof CallNode) ) {
- sb.p("\n"); // Blank after multitail
- gap = true;
- }
- } else {
- printLine( n, sb );
- gap = false;
- }
- }
- return sb.toString();
- }
-
- private static void postOrd(Node n, Node prior, ArrayList<Node> rpos, BitSet visit, BitSet bfs) {
- if( !bfs.get(n._nid) )
- return; // Not in the BFS visit
- if( n instanceof FunNode && !(prior instanceof StartNode) )
- return; // Only visit Fun from Start
- if( visit.get(n._nid) ) return; // Already post-order walked
- visit.set(n._nid);
- // First walk the CFG, then everything
- if( n instanceof CFGNode ) {
- for( Node use : n._outputs )
- // Follow CFG, not across call/function borders, and not around backedges
- if( use instanceof CFGNode && !(n instanceof CallNode && use instanceof FunNode) &&
- use.nOuts() >= 1 && !(use._outputs.get(0) instanceof LoopNode) )
- postOrd(use, n, rpos,visit,bfs);
- for( Node use : n._outputs )
- // Follow CFG, not across call/function borders
- if( use instanceof CFGNode && !(n instanceof CallNode && use instanceof FunNode) )
- postOrd(use,n,rpos,visit,bfs);
- }
- // Follow all outputs
- for( Node use : n._outputs )
- if( use != null &&
- !(n instanceof CallNode && use instanceof FunNode) &&
- (n instanceof FunNode || !(use instanceof ParmNode)) )
- postOrd(use, n, rpos,visit,bfs);
- // Post-order
- rpos.add(n);
- }
-
- // Breadth-first search, broken out in a class to keep in more independent.
- // Maintains a root-set of Nodes at the limit (or past by 1 if MultiHead).
- public static class BFS {
- // A breadth first search, plus MultiHeads for any MultiTails
- public final ArrayList<Node> _bfs;
- public final BitSet _bs; // Visited members by node id
- public final int _depth; // Depth limit
- public final int _lim; // From here to _bfs._len can be roots for a reverse search
- public BFS( Node base, int d ) {
- _depth = d;
- _bfs = new ArrayList<>();
- _bs = new BitSet();
-
- add(base); // Prime the pump
- int idx=0, lim=1; // Limit is where depth counter changes
- while( idx < _bfs.size() ) { // Ran out of nodes below depth
- Node n = _bfs.get(idx++);
- for( Node def : n._inputs )
- if( def!=null && !_bs.get(def._nid) )
- add(def);
- if( idx==lim ) { // Depth counter changes at limit
- if( --d < 0 )
- break; // Ran out of depth
- lim = _bfs.size(); // New depth limit
- }
- }
- // Toss things past the limit except multi-heads
- while( idx < _bfs.size() ) {
- Node n = _bfs.get(idx);
- if( n instanceof MultiNode ) idx++;
- else del(idx);
- }
- // Root set is any node with no inputs in the visited set
- lim = _bfs.size();
- for( int i=_bfs.size()-1; i>=0; i-- )
- if( !any_visited(_bfs.get(i)) )
- swap( i,--lim);
- _lim = lim;
- }
- void swap( int x, int y ) {
- if( x==y ) return;
- Node tx = _bfs.get(x);
- Node ty = _bfs.get(y);
- _bfs.set(x,ty);
- _bfs.set(y,tx);
- }
- void add(Node n) {
- _bfs.add(n);
- _bs.set(n._nid);
- }
- void del(int idx) {
- _bs.clear(_bfs.get(idx)._nid);
- Utils.del(_bfs, idx);
- }
- boolean any_visited( Node n ) {
- for( Node def : n._inputs )
- if( def!=null && _bs.get(def._nid) )
- return true;
- return false;
- }
- }
-
- public static String _prettyPrint( CodeGen code ) {
- SB sb = new SB();
- // Print the Start "block"
- printLine(code._start,sb);
- for( Node n : code._start._outputs )
- printLine(n,sb);
- sb.nl();
-
- // Skip start, stop
- for( int i=1; i<code._cfg._len-1; i++ ) {
- CFGNode blk = code._cfg.at(i);
- if( blk.blockHead() && (!(blk instanceof CProjNode) || (blk.cfg0() instanceof IfNode )) ) {
- if( blk instanceof FunNode fun )
- sb.p("--- ").p(fun.label()).p(" ---------------------------").nl();
- // Print block header
- sb.p("%-13.13s".formatted(label(blk)+":"));
- sb.p( " ".repeat(4) ).p(" [[ ");
- if( blk instanceof RegionNode )
- for( int j=1; j<blk.nIns(); j++ )
- label(sb,blk.cfg(j));
- else
- label(sb,blk.cfg(0));
- sb.p(" ]] \n");
- }
- printLine(blk,sb);
- if( blk instanceof ReturnNode ret )
- sb.p("--- ").p(ret.fun().label()).p(" ---------------------------").nl();
-
- // Block contents
- for( Node n : blk._outputs ) {
- if( n instanceof CFGNode cfg ) continue;
- printLine(n,sb);
- if( !(n instanceof CFGNode) && n instanceof MultiNode )
- for( Node use : n._outputs )
- printLine(use,sb);
- }
- }
-
- printLine(code._stop,sb);
- return sb.toString();
- }
-
- // Diagnostic block ordering from raw control edges. Do not call idepth():
- // it fills compiler caches (and can walk lazy dominator accessors).
- private static int _idepth(CFGNode cfg, HashMap<Integer,Integer> depths) {
- if( cfg == null || cfg instanceof StartNode || cfg instanceof FunNode ) return cfg instanceof FunNode ? 1 : 0;
- Integer old = depths.get(cfg._nid);
- if( old != null ) return old;
- depths.put(cfg._nid,0); // Break cycles in partially constructed graphs.
- int d = 0;
- if( cfg instanceof LoopNode ) {
- d = _idepth((CFGNode)cfg.in(1),depths)+1;
- } else if( cfg instanceof RegionNode || cfg instanceof StopNode ) {
- for( Node n : cfg._inputs )
- if( n instanceof CFGNode pred ) d = Math.max(d,_idepth(pred,depths)+1);
- } else if( cfg.in(0) instanceof CFGNode pred ) {
- d = _idepth(pred,depths)+1;
- }
- depths.put(cfg._nid,d);
- return d;
- }
-
- // Bulk pretty printer, knowing scheduling information is available
- private static String _prettyPrintScheduled( Node node, int depth ) {
- // Backwards DFS walk to depth.
- HashMap<Integer,Integer> ds = new HashMap<>();
- Ary<Node> ns = new Ary<>(Node.class);
- _walk(ds,ns,node,depth);
- // Remove data projections, these are force-printed behind their multinode head
- for( int i=0; i<ns.size(); i++ ) {
- if( ns.get(i) instanceof ProjNode proj && !(proj.in(0) instanceof CFGNode) ) {
- ns.del(i--);
- ds.remove(proj._nid);
- }
- }
- // Print by block with least diagnostic depth
- HashMap<Integer,Integer> depths = new HashMap<>();
- SB sb = new SB();
- Ary<Node> bns = new Ary<>(Node.class);
- while( !ds.isEmpty() ) {
- CFGNode blk = null;
- for( Node n : ns ) {
- CFGNode cfg = n instanceof CFGNode cfg0 && cfg0.blockHead() ? cfg0 : n.cfg0();
- if( blk==null || _idepth(cfg,depths) < _idepth(blk,depths) )
- blk = cfg;
- }
- Integer d = ds.remove(blk._nid);
- ns.del(ns.find(blk));
-
- // Print block header
- sb.p("%-13.13s".formatted(label(blk)+":"));
- sb.p( " ".repeat(4) ).p(" [[ ");
- if( blk instanceof StartNode ) ;
- else if( blk instanceof RegionNode || blk instanceof StopNode )
- for( int i=(blk instanceof StopNode ? 3 : 1); i<blk.nIns(); i++ )
- label(sb,blk.cfg(i));
- else
- label(sb,blk.cfg(0));
- sb.p(" ]] \n");
- printLine(blk,sb);
-
- // Collect block contents that are in the depth limit
- bns.clear();
- int xd = Integer.MAX_VALUE;
- for( Node use : blk._outputs ) {
- Integer i = ds.get(use._nid);
- if( i!=null && !(use instanceof CFGNode cfg && cfg.blockHead()) ) {
- if( bns.find(use)==-1 )
- bns.add(use);
- xd = Math.min(xd,i);
- }
- }
- // Print Phis up front, if any
- for( int i=0; i<bns.size(); i++ )
- if( bns.get(i) instanceof PhiNode phi )
- printLine( phi, sb,bns,i--,ds,ns);
-
- // Print block contents in depth order, bumping depth until whole block printed
- for( ; !bns.isEmpty(); xd++ )
- for( int i=0; i<bns.size(); i++ ) {
- Node n = bns.get(i);
- if( ds.get(n._nid)==xd ) {
- printLine( n, sb, bns, i--, ds,ns );
- if( n instanceof MultiNode && !(n instanceof CFGNode) ) {
- for( Node use : n._outputs ) {
- printLine(use,sb,bns,bns.indexOf(use),ds,ns);
- }
- }
- }
- }
- sb.p("\n");
- }
- return sb.toString();
- }
-
- private static void _walk( HashMap<Integer,Integer> ds, Ary<Node> ns, Node node, int d ) {
- Integer nd = ds.get(node._nid);
- if( nd!=null && d <= nd ) return; // Been there, done that
- Integer old = ds.put(node._nid,d) ;
- if( old == null )
- ns.add(node);
- if( d == 0 ) return; // Depth cutoff
- for( Node def : node._inputs )
- if( def != null &&
- !(node instanceof LoopNode loop && loop.back()==def) &&
- // Don't walk into or out of functions
- !(node instanceof CallEndNode && def instanceof ReturnNode) &&
- !(node instanceof FunNode && def instanceof CallNode) &&
- !(node instanceof ParmNode && !(def instanceof FunNode))
- )
- _walk(ds,ns,def,d-1);
- }
+import com.seaofnodes.simple.SB;
+import com.seaofnodes.simple.codegen.CodeGen;
- static String label( CFGNode blk ) {
- if( blk instanceof StartNode ) return "START";
- return (blk instanceof LoopNode ? "LOOP" : "L")+blk._nid;
- }
- static void label( SB sb, CFGNode blk ) {
- if( !blk.blockHead() ) blk = blk.cfg(0);
- sb.p( "%-9.9s ".formatted( label( blk ) ) );
+/** This chapter's read-only IR facts and the familiar debugger entry points. */
+public final class IRPrinter extends IRAdapter<Node> {
+ private static final com.seaofnodes.print.IRPrinter<Node> PRINT =
+ new com.seaofnodes.print.IRPrinter<>(new IRPrinter());
+ @Override public boolean global(Node n) { return n.isConst(); }
+ @Override public String type(Node n) { return n._type==null ? "" : n._type.str(); }
+ @Override public String inputMark(Node n, Node def) { return n instanceof MemMergeNode && def instanceof MemMergeNode ? "^" : " "; }
+ @Override public Kind kind(Node n) {
+ if( n instanceof StartNode ) return Kind.START;
+ if( n instanceof StopNode ) return Kind.STOP;
+ if( n instanceof FunNode ) return Kind.FUN;
+ if( n instanceof LoopNode ) return Kind.LOOP;
+ if( n instanceof RegionNode ) return Kind.REGION;
+ if( n instanceof ParmNode ) return Kind.PARM;
+ if( n instanceof PhiNode ) return Kind.PHI;
+ if( n instanceof CallEndNode ) return Kind.CALL_END;
+ if( n instanceof CallNode ) return Kind.CALL;
+ if( n instanceof ReturnNode ) return Kind.RETURN;
+ if( n instanceof ConstantNode ) return Kind.CONSTANT;
+ if( n instanceof CProjNode ) return Kind.CPROJ;
+ if( n instanceof ProjNode ) return n instanceof CFGNode ? Kind.CPROJ : Kind.PROJ;
+ if( n instanceof CFGNode ) return Kind.CTRL;
+ if( n instanceof MultiNode ) return Kind.MULTI;
+ return Kind.DATA;
+ }
+ @Override public int index(Node n) {
+ if( n instanceof ProjNode p ) return p._idx;
+ if( n instanceof CProjNode p ) return p._idx;
+ return n._nid;
+ }
+ @Override public String functionName(Node n) { return ((FunNode)n)._name==null ? "" : ((FunNode)n)._name; }
+ @Override public String signature(Node n) {
+ FunNode fun=(FunNode)n;
+ return (fun._name==null ? "" : fun._name)+" "+fun.sig().str();
+ }
+
+ public static String prettyPrint(Node n, int depth) { return PRINT.prettyPrint(n,depth); }
+ public static SB printLine(Node n, SB sb) { return sb.p(PRINT.line(n)); }
+
+ public static String prettyPrint(CodeGen code) {
+ var units=new ArrayList<com.seaofnodes.print.IRPrinter.Unit<Node>>();
+ var funs=new ArrayList<Node>();
+ for( Node n : code._start._outputs ) if( n instanceof FunNode ) funs.add(n);
+ units.add(new com.seaofnodes.print.IRPrinter.Unit<>(null,null,null,funs));
+ return PRINT.program(code._start,code._stop,units);
+ }
+ public static String _prettyPrint(CodeGen code) {
+ if( code._cfg==null ) return prettyPrint(code);
+ var blocks=new ArrayList<Node>();
+ for( Node n : code._cfg ) blocks.add(n);
+ return PRINT.scheduled(blocks);
}
- static void printLine( Node n, SB sb, Ary<Node> bns, int i, HashMap<Integer,Integer> ds, Ary<Node> ns ) {
- printLine( n, sb );
- if( i != -1 ) bns.del(i);
- ds.remove(n._nid);
- int idx = ns.find(n);
- if( idx!=-1 ) ns.del(idx);
- }
-
}
diff --git a/chapter20/src/main/java/com/seaofnodes/simple/print/SimpleGraphAdapter.java b/chapter20/src/main/java/com/seaofnodes/simple/print/SimpleGraphAdapter.java
index 7a2025da..0357ff61 100644
--- a/chapter20/src/main/java/com/seaofnodes/simple/print/SimpleGraphAdapter.java
+++ b/chapter20/src/main/java/com/seaofnodes/simple/print/SimpleGraphAdapter.java
@@ -1,45 +1,25 @@
package com.seaofnodes.simple.print;
import com.seaofnodes.graph.GraphAdapter;
-import com.seaofnodes.graph.GraphSnapshot;
import com.seaofnodes.graph.GraphSnapshot.*;
import com.seaofnodes.simple.node.*;
import com.seaofnodes.simple.node.Node;
import com.seaofnodes.simple.type.TypeMem;
-import java.util.ArrayList;
/** Chapter 20's view of the IR; browser, transport and layout are shared. */
public class SimpleGraphAdapter extends GraphAdapter<Node> {
- @Override protected boolean dead(Node n) { return n.isDead(); }
- @Override protected int id(Node n) { return n._nid; }
- @Override protected int nIns(Node n) { return n.nIns(); }
- @Override protected Node in(Node n, int idx) { return n.in(idx); }
- @Override protected int nOuts(Node n) { return n.nOuts(); }
- @Override protected Node out(Node n, int idx) { return n.out(idx); }
- @Override protected int nDeps(Node n) { return n.nDeps(); }
- @Override protected Node dep(Node n, int idx) { return n.dep(idx); }
- private ArrayList<Edge> edges(Node n) {
- var edges = new ArrayList<Edge>();
- for( int i = 0; i < n.nIns(); i++ ) {
- String name = n instanceof ScopeNode scope && i < scope._vars.size()
+ @Override protected String edgeName(Node n, int i) {
+ return n instanceof ScopeNode scope && i < scope._vars.size()
? scope._vars.get(i)._name : null;
- int jump = n instanceof CallEndNode && i>0 && n.in(i) instanceof ReturnNode ret
- ? ref(ret.fun()) : 0;
- edges.add(new Edge(i, ref(n.in(i)), role(n, i), name, jump));
- }
- return edges;
}
-
- @Override protected GraphSnapshot.Node desc(Node n) {
- Projection proj = n instanceof ProjNode p ? new Projection(ref(n.in(0)), p._idx)
- : n instanceof CProjNode p ? new Projection(ref(n.in(0)), p._idx) : null;
- String label = n.label();
- return new GraphSnapshot.Node(n._nid, label == null ? n.getClass().getSimpleName() : label,
- n._type == null ? null : n._type.toString(), kind(n), edges(n), proj, folding(n));
+ @Override protected int edgeJump(Node n, int i) {
+ return n instanceof CallEndNode && i>0 && n.in(i) instanceof ReturnNode ret
+ ? ref(ret.fun()) : 0;
}
+ @Override protected int projectionIndex(Node n) { return n instanceof ProjNode p ? p._idx : n instanceof CProjNode p ? p._idx : -1; }
- private boolean folding(Node n) {
+ @Override protected boolean folding(Node n) {
if( n instanceof FunNode fun ) return fun.folding();
if( n instanceof ReturnNode ret ) return ret.fun().folding();
if( n instanceof CallEndNode cend ) return cend.folding();
@@ -49,7 +29,7 @@ public class SimpleGraphAdapter extends GraphAdapter<Node> {
return false;
}
- private Kind kind(Node n) {
+ @Override protected Kind kind(Node n) {
if( n instanceof StopNode ) return Kind.STOP;
if( n instanceof ScopeNode ) return Kind.SCOPE;
if( n instanceof FunNode ) return Kind.FUN;
@@ -60,7 +40,7 @@ public class SimpleGraphAdapter extends GraphAdapter<Node> {
return n instanceof CFGNode ? Kind.CTRL : isMem(n) ? Kind.MEM : Kind.DATA;
}
- private Role role(Node n, int i) {
+ @Override protected Role role(Node n, int i) {
if( n instanceof ScopeNode || n instanceof ConstantNode || n instanceof CtrlNode || n instanceof XCtrlNode ) return Role.ASSOC;
if( n instanceof PhiNode ) return i == 0 ? Role.ASSOC : isMem(n) ? Role.MEM : Role.DATA;
if( n instanceof ProjNode || n instanceof CProjNode )
diff --git a/chapter21/Makefile b/chapter21/Makefile
index fcb03be8..f9d7e738 100644
--- a/chapter21/Makefile
+++ b/chapter21/Makefile
@@ -37,6 +37,7 @@ main_javas := $(wildcard $(SRC)/$(SIMPLE)/*java $(SRC)/$(SIMPLE)/*/*java $(SRC
test_javas := $(wildcard $(TST)/$(SIMPLE)/*java $(TST)/$(SIMPLE)/*/*java)
main_classes := $(patsubst $(SRC)/%java,$(CLZDIR)/main/%class,$(main_javas))
include $(firstword $(wildcard ../graph/graph.mk graph/graph.mk))
+include $(firstword $(wildcard ../print/print.mk print/print.mk))
test_classes := $(patsubst $(TST)/%java,$(CLZDIR)/test/%class,$(test_javas))
test_cp := $(patsubst $(TST)/$(SIMPLE)/%.java,com.seaofnodes.simple.%,$(wildcard $(TST)/$(SIMPLE)/*Test.java)) com.seaofnodes.simple.codegen.X86EncodingTest
classes = $(main_classes) $(test_classes)
@@ -54,7 +55,7 @@ endif
default: $(default_targets)
# Compile just the out-of-date files
-$(main_classes): $(CLZDIR)/main/%class: $(SRC)/%java $(graph_javas)
+$(main_classes): $(CLZDIR)/main/%class: $(SRC)/%java $(graph_javas) $(print_javas)
@echo "compiling " $@ " because " $?
@[ -d $(CLZDIR)/main ] || mkdir -p $(CLZDIR)/main
@javac $(JAVAC_ARGS) -cp "$(CLZDIR)/main$(SEP)$(jars)" -sourcepath $(SRC) -d $(CLZDIR)/main $(main_javas)
diff --git a/chapter21/pom.xml b/chapter21/pom.xml
index 67e7862b..344f3ce8 100644
--- a/chapter21/pom.xml
+++ b/chapter21/pom.xml
@@ -13,5 +13,6 @@
<name>Chapter 21</name>
<properties>
<simple.graph.directory>${project.basedir}/../graph</simple.graph.directory>
+ <simple.print.directory>${project.basedir}/../print</simple.print.directory>
</properties>
</project>
diff --git a/chapter21/src/main/java/com/seaofnodes/simple/node/AddFNode.java b/chapter21/src/main/java/com/seaofnodes/simple/node/AddFNode.java
index ba5815da..fd713156 100644
--- a/chapter21/src/main/java/com/seaofnodes/simple/node/AddFNode.java
+++ b/chapter21/src/main/java/com/seaofnodes/simple/node/AddFNode.java
@@ -1,21 +1,16 @@
package com.seaofnodes.simple.node;
+
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeFloat;
-import java.util.BitSet;
public class AddFNode extends Node {
public AddFNode(Node lhs, Node rhs) { super(null, lhs, rhs); }
@Override public String label() { return "AddF"; }
- @Override
- public StringBuilder _print1(StringBuilder sb, BitSet visited) {
- in(1)._print0(sb.append("("), visited);
- in(2)._print0(sb.append("+"), visited);
- return sb.append(")");
- }
+ @Override protected String format() { return "(%1+%2)"; }
@Override
public Type compute() {
diff --git a/chapter21/src/main/java/com/seaofnodes/simple/node/AddNode.java b/chapter21/src/main/java/com/seaofnodes/simple/node/AddNode.java
index c8701b5d..663bca6a 100644
--- a/chapter21/src/main/java/com/seaofnodes/simple/node/AddNode.java
+++ b/chapter21/src/main/java/com/seaofnodes/simple/node/AddNode.java
@@ -1,9 +1,9 @@
package com.seaofnodes.simple.node;
+
import com.seaofnodes.simple.Parser;
import com.seaofnodes.simple.type.*;
-import java.util.BitSet;
import static com.seaofnodes.simple.Parser.con;
@@ -12,12 +12,7 @@ public class AddNode extends Node {
@Override public String label() { return "Add"; }
- @Override
- public StringBuilder _print1(StringBuilder sb, BitSet visited) {
- in(1)._print0(sb.append("("), visited);
- in(2)._print0(sb.append("+"), visited);
- return sb.append(")");
- }
+ @Override protected String format() { return "(%1+%2)"; }
@Override
diff --git a/chapter21/src/main/java/com/seaofnodes/simple/node/BoolNode.java b/chapter21/src/main/java/com/seaofnodes/simple/node/BoolNode.java
index b2753fb1..d6a126f5 100644
--- a/chapter21/src/main/java/com/seaofnodes/simple/node/BoolNode.java
+++ b/chapter21/src/main/java/com/seaofnodes/simple/node/BoolNode.java
@@ -1,9 +1,10 @@
package com.seaofnodes.simple.node;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.Parser;
import com.seaofnodes.simple.Utils;
import com.seaofnodes.simple.type.*;
-import java.util.BitSet;
import static com.seaofnodes.simple.type.TypeInteger.*;
abstract public class BoolNode extends Node {
@@ -17,11 +18,8 @@ abstract public class BoolNode extends Node {
@Override
public String label() { return getClass().getSimpleName(); }
- @Override
- public StringBuilder _print1(StringBuilder sb, BitSet visited) {
- in(1)._print0(sb.append("("), visited);
- in(2)._print0(sb.append(op()), visited);
- return sb.append(")");
+ @Override protected ExprPrinter<Node> _print1(ExprPrinter<Node> p) {
+ return p.open().n(in(1)).p(op()).n(in(2)).close();
}
@Override
diff --git a/chapter21/src/main/java/com/seaofnodes/simple/node/CProjNode.java b/chapter21/src/main/java/com/seaofnodes/simple/node/CProjNode.java
index 94770f16..4d3d8d0d 100644
--- a/chapter21/src/main/java/com/seaofnodes/simple/node/CProjNode.java
+++ b/chapter21/src/main/java/com/seaofnodes/simple/node/CProjNode.java
@@ -1,11 +1,12 @@
package com.seaofnodes.simple.node;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.Parser;
import com.seaofnodes.simple.Utils;
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeMem;
import com.seaofnodes.simple.type.TypeTuple;
-import java.util.BitSet;
public class CProjNode extends CFGNode {
@@ -24,7 +25,7 @@ public class CProjNode extends CFGNode {
@Override public String label() { return _label; }
- @Override public StringBuilder _print1(StringBuilder sb, BitSet visited) { return sb.append(_label); }
+ @Override protected ExprPrinter<Node> _print1(ExprPrinter<Node> p) { return p.p(_label); }
@Override public boolean blockHead() { return true; }
diff --git a/chapter21/src/main/java/com/seaofnodes/simple/node/CallEndNode.java b/chapter21/src/main/java/com/seaofnodes/simple/node/CallEndNode.java
index 3005344d..81992327 100644
--- a/chapter21/src/main/java/com/seaofnodes/simple/node/CallEndNode.java
+++ b/chapter21/src/main/java/com/seaofnodes/simple/node/CallEndNode.java
@@ -1,9 +1,10 @@
package com.seaofnodes.simple.node;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.*;
import com.seaofnodes.simple.codegen.*;
import com.seaofnodes.simple.type.*;
-import java.util.BitSet;
/**
* CallEnd
@@ -24,13 +25,12 @@ public class CallEndNode extends CFGNode implements MultiNode {
public CallNode call() { return (CallNode)in(0); }
@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/chapter21/src/main/java/com/seaofnodes/simple/node/CallNode.java b/chapter21/src/main/java/com/seaofnodes/simple/node/CallNode.java
index ea84937b..90999de3 100644
--- a/chapter21/src/main/java/com/seaofnodes/simple/node/CallNode.java
+++ b/chapter21/src/main/java/com/seaofnodes/simple/node/CallNode.java
@@ -1,12 +1,13 @@
package com.seaofnodes.simple.node;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.codegen.CodeGen;
import com.seaofnodes.simple.IterPeeps;
import com.seaofnodes.simple.Parser;
import com.seaofnodes.simple.Utils;
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeFunPtr;
-import java.util.BitSet;
/**
* Call
@@ -21,15 +22,14 @@ public class CallNode extends CFGNode {
@Override public String label() { return "Call"; }
- @Override public StringBuilder _print1(StringBuilder sb, BitSet visited) {
+ @Override protected ExprPrinter<Node> _print1(ExprPrinter<Node> p) {
String fname = name();
- if( fname == null ) fptr()._print0(sb,visited);
- else sb.append(fname);
- sb.append("( ");
+ if( fname == null ) p.n(fptr());
+ else p.p(fname);
+ p.p("( ");
for( int i=2; i<nIns()-1; i++ )
- in(i)._print0(sb,visited).append(",");
- sb.setLength(sb.length()-1);
- return sb.append(")");
+ p.n(in(i)).p(",");
+ return p.unchar(',').unchar(' ').close();
}
public String name() {
if( fptr()._type instanceof TypeFunPtr tfp && tfp.isConstant() && tfp.notNull() ) {
diff --git a/chapter21/src/main/java/com/seaofnodes/simple/node/CastNode.java b/chapter21/src/main/java/com/seaofnodes/simple/node/CastNode.java
index 42e461e5..5598acd8 100644
--- a/chapter21/src/main/java/com/seaofnodes/simple/node/CastNode.java
+++ b/chapter21/src/main/java/com/seaofnodes/simple/node/CastNode.java
@@ -1,10 +1,11 @@
package com.seaofnodes.simple.node;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.Parser;
import com.seaofnodes.simple.Utils;
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeInteger;
-import java.util.BitSet;
// Upcast (join) the input to a t. Used after guard test to lift an input.
// Can also be used to make a type-assertion if ctrl is null.
@@ -24,14 +25,11 @@ public class CastNode extends Node {
@Override public String label() { return "("+_t.str()+")"; }
- @Override
- public String uniqueName() { return "Cast_" + _nid; }
@Override public boolean isConst() { return true; }
- @Override
- public StringBuilder _print1(StringBuilder sb, BitSet visited) {
- return in(1)._print0(sb.append(label()), visited);
+ @Override protected ExprPrinter<Node> _print1(ExprPrinter<Node> p) {
+ return p.p(label()).n(in(1));
}
@Override
diff --git a/chapter21/src/main/java/com/seaofnodes/simple/node/ConstantNode.java b/chapter21/src/main/java/com/seaofnodes/simple/node/ConstantNode.java
index 9785855b..c4a41e5d 100644
--- a/chapter21/src/main/java/com/seaofnodes/simple/node/ConstantNode.java
+++ b/chapter21/src/main/java/com/seaofnodes/simple/node/ConstantNode.java
@@ -1,11 +1,12 @@
package com.seaofnodes.simple.node;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.codegen.CodeGen;
import com.seaofnodes.simple.Parser;
import com.seaofnodes.simple.SB;
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeFunPtr;
-import java.util.BitSet;
/**
* A Constant node represents a constant value. At present, the only constants
@@ -35,18 +36,20 @@ public class ConstantNode extends Node {
return new ConstantNode(type);
}
- @Override public String label() { return "#"+_con; }
- @Override
- public String uniqueName() { return "Con_" + _nid; }
+ @Override protected String repeatName() {
+ return _con==null || _con.toString().length()<=32 ? null : uniqueName();
+ }
+
+ @Override public String label() { return "Con"; }
@Override
- public StringBuilder _print1(StringBuilder sb, BitSet visited) {
+ protected ExprPrinter<Node> _print1(ExprPrinter<Node> p) {
if( _con instanceof TypeFunPtr tfp && tfp.isConstant() && tfp.notNull() ) {
FunNode fun = CodeGen.CODE.link(tfp);
if( fun!=null && fun._name != null )
- return sb.append("{ ").append(fun._name).append("}");
+ return p.p("{ ").p(fun._name).p("}");
}
- return sb.append(_con==null ? "---" : _con.print(new SB()));
+ return p.p(_con==null ? "---" : _con.print(new SB()));
}
@Override public boolean isConst() { return true; }
diff --git a/chapter21/src/main/java/com/seaofnodes/simple/node/CtrlNode.java b/chapter21/src/main/java/com/seaofnodes/simple/node/CtrlNode.java
index eda7d684..cf630ad4 100644
--- a/chapter21/src/main/java/com/seaofnodes/simple/node/CtrlNode.java
+++ b/chapter21/src/main/java/com/seaofnodes/simple/node/CtrlNode.java
@@ -1,14 +1,15 @@
package com.seaofnodes.simple.node;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.codegen.CodeGen;
import com.seaofnodes.simple.Parser;
import com.seaofnodes.simple.type.Type;
-import java.util.BitSet;
public class CtrlNode extends CFGNode {
public CtrlNode() { super(CodeGen.CODE._start); }
@Override public String label() { return "Ctrl"; }
- @Override public StringBuilder _print1(StringBuilder sb, BitSet visited) { return sb.append("Cctrl"); }
+ @Override protected ExprPrinter<Node> _print1(ExprPrinter<Node> p) { return p.p("Cctrl"); }
@Override public boolean isConst() { return true; }
@Override public Type compute() { return Type.CONTROL; }
@Override public Node idealize() { return null; }
diff --git a/chapter21/src/main/java/com/seaofnodes/simple/node/DivFNode.java b/chapter21/src/main/java/com/seaofnodes/simple/node/DivFNode.java
index 2180ab46..149499f9 100644
--- a/chapter21/src/main/java/com/seaofnodes/simple/node/DivFNode.java
+++ b/chapter21/src/main/java/com/seaofnodes/simple/node/DivFNode.java
@@ -1,21 +1,16 @@
package com.seaofnodes.simple.node;
+
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeFloat;
-import java.util.BitSet;
public class DivFNode extends Node {
public DivFNode(Node lhs, Node rhs) { super(null, lhs, rhs); }
@Override public String label() { return "DivF"; }
- @Override
- public StringBuilder _print1(StringBuilder sb, BitSet visited) {
- in(1)._print0(sb.append("("), visited);
- in(2)._print0(sb.append("/"), visited);
- return sb.append(")");
- }
+ @Override protected String format() { return "(%1/%2)"; }
@Override
public Type compute() {
diff --git a/chapter21/src/main/java/com/seaofnodes/simple/node/DivNode.java b/chapter21/src/main/java/com/seaofnodes/simple/node/DivNode.java
index 7aa98bf2..f0ee21e1 100644
--- a/chapter21/src/main/java/com/seaofnodes/simple/node/DivNode.java
+++ b/chapter21/src/main/java/com/seaofnodes/simple/node/DivNode.java
@@ -1,20 +1,15 @@
package com.seaofnodes.simple.node;
+
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeInteger;
-import java.util.BitSet;
public class DivNode extends Node {
public DivNode(Node lhs, Node rhs) { super(null, lhs, rhs); }
@Override public String label() { return "Div"; }
- @Override
- public StringBuilder _print1(StringBuilder sb, BitSet visited) {
- in(1)._print0(sb.append("("), visited);
- in(2)._print0(sb.append("/"), visited);
- return sb.append(")");
- }
+ @Override protected String format() { return "(%1/%2)"; }
@Override
public Type compute() {
diff --git a/chapter21/src/main/java/com/seaofnodes/simple/node/FRefNode.java b/chapter21/src/main/java/com/seaofnodes/simple/node/FRefNode.java
index 6093b8a6..e7333c23 100644
--- a/chapter21/src/main/java/com/seaofnodes/simple/node/FRefNode.java
+++ b/chapter21/src/main/java/com/seaofnodes/simple/node/FRefNode.java
@@ -1,9 +1,10 @@
package com.seaofnodes.simple.node;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.Parser;
import com.seaofnodes.simple.Var;
import com.seaofnodes.simple.type.Type;
-import java.util.BitSet;
/**
* A Forward Reference. Its any final constant, including functions. When
@@ -17,10 +18,9 @@ public class FRefNode extends ConstantNode {
@Override public String label() { return "FRef"+_n; }
- @Override public String uniqueName() { return "FRef_" + _nid; }
- @Override public StringBuilder _print1(StringBuilder sb, BitSet visited) {
- return sb.append("FRef_").append(_n);
+ @Override protected ExprPrinter<Node> _print1(ExprPrinter<Node> p) {
+ return p.p("FRef_").p(_n);
}
@Override public Node idealize() {
diff --git a/chapter21/src/main/java/com/seaofnodes/simple/node/IfNode.java b/chapter21/src/main/java/com/seaofnodes/simple/node/IfNode.java
index 5d90449e..81fbe170 100644
--- a/chapter21/src/main/java/com/seaofnodes/simple/node/IfNode.java
+++ b/chapter21/src/main/java/com/seaofnodes/simple/node/IfNode.java
@@ -1,9 +1,10 @@
package com.seaofnodes.simple.node;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.Utils;
import com.seaofnodes.simple.codegen.CodeGen;
import com.seaofnodes.simple.type.*;
-import java.util.BitSet;
public class IfNode extends CFGNode implements MultiNode {
@@ -17,11 +18,11 @@ public class IfNode extends CFGNode implements MultiNode {
public String label() { return "If"; }
@Override
- public StringBuilder _print1(StringBuilder sb, BitSet visited) {
- sb.append("if( ");
- if( in(1)==null ) sb.append("never");
- else in(1)._print0(sb, visited);
- return sb.append(" )");
+ protected ExprPrinter<Node> _print1(ExprPrinter<Node> p) {
+ p.p("if( ");
+ if( in(1)==null ) p.p("never");
+ else p.n(in(1));
+ return p.p(" )");
}
public Node ctrl() { return in(0); }
diff --git a/chapter21/src/main/java/com/seaofnodes/simple/node/LoadNode.java b/chapter21/src/main/java/com/seaofnodes/simple/node/LoadNode.java
index 0432bcbc..f668d2c3 100644
--- a/chapter21/src/main/java/com/seaofnodes/simple/node/LoadNode.java
+++ b/chapter21/src/main/java/com/seaofnodes/simple/node/LoadNode.java
@@ -1,5 +1,7 @@
package com.seaofnodes.simple.node;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.codegen.CodeGen;
import com.seaofnodes.simple.Parser;
import com.seaofnodes.simple.type.*;
@@ -45,7 +47,7 @@ public class LoadNode extends MemOpNode {
// Debugger label
@Override public String label() { return "ld_"+mlabel(); }
@Override
- public StringBuilder _print1(StringBuilder sb, BitSet visited) { return sb.append(".").append(_name); }
+ protected ExprPrinter<Node> _print1(ExprPrinter<Node> p) { return p.p(".").p(_name); }
@Override
public Type compute() {
diff --git a/chapter21/src/main/java/com/seaofnodes/simple/node/LogicalNode.java b/chapter21/src/main/java/com/seaofnodes/simple/node/LogicalNode.java
index e8552789..6ac16d31 100644
--- a/chapter21/src/main/java/com/seaofnodes/simple/node/LogicalNode.java
+++ b/chapter21/src/main/java/com/seaofnodes/simple/node/LogicalNode.java
@@ -1,9 +1,10 @@
package com.seaofnodes.simple.node;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.Parser;
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeInteger;
-import java.util.BitSet;
public abstract class LogicalNode extends Node {
// Source location for late reported errors
@@ -12,11 +13,8 @@ public abstract class LogicalNode extends Node {
public LogicalNode(Parser.Lexer loc, Node lhs, Node rhs) { super(null, lhs, rhs); _loc = loc; }
abstract String op();
- @Override
- public StringBuilder _print1(StringBuilder sb, BitSet visited) {
- in(1)._print0(sb.append("("), visited);
- in(2)._print0(sb.append(op()), visited);
- return sb.append(")");
+ @Override protected ExprPrinter<Node> _print1(ExprPrinter<Node> p) {
+ return p.open().n(in(1)).p(op()).n(in(2)).close();
}
diff --git a/chapter21/src/main/java/com/seaofnodes/simple/node/MachConcreteNode.java b/chapter21/src/main/java/com/seaofnodes/simple/node/MachConcreteNode.java
index b01b3308..4f5d9151 100644
--- a/chapter21/src/main/java/com/seaofnodes/simple/node/MachConcreteNode.java
+++ b/chapter21/src/main/java/com/seaofnodes/simple/node/MachConcreteNode.java
@@ -1,9 +1,10 @@
package com.seaofnodes.simple.node;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.Utils;
import java.io.ByteArrayOutputStream;
-import java.util.BitSet;
// Generic machine-specific class, has a few Node implementations that have to
// exist (abstract) but are not useful past the optimizer.
@@ -16,12 +17,11 @@ public abstract class MachConcreteNode extends Node implements MachNode {
@Override public Type compute () { throw Utils.TODO(); }
@Override public Node idealize() { throw Utils.TODO(); }
- @Override public StringBuilder _print1(StringBuilder sb, BitSet visited) {
- sb.append("(").append(op()).append(",");
+ @Override protected ExprPrinter<Node> _print1(ExprPrinter<Node> p) {
+ p.open().p(op()).p(",");
for( int i=1; i<nIns(); i++ )
- (in(i)==null ? sb.append(" ---") : in(i)._print0(sb, visited)).append(",");
- sb.setLength(sb.length()-1);
- return sb.append(")");
+ (in(i)==null ? p.p(" ---") : p.n(in(i))).p(",");
+ return p.unchar(',').close();
}
}
diff --git a/chapter21/src/main/java/com/seaofnodes/simple/node/MemMergeNode.java b/chapter21/src/main/java/com/seaofnodes/simple/node/MemMergeNode.java
index c1d11f88..421e4864 100644
--- a/chapter21/src/main/java/com/seaofnodes/simple/node/MemMergeNode.java
+++ b/chapter21/src/main/java/com/seaofnodes/simple/node/MemMergeNode.java
@@ -1,5 +1,7 @@
package com.seaofnodes.simple.node;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.*;
import com.seaofnodes.simple.codegen.CodeGen;
import com.seaofnodes.simple.type.*;
@@ -52,14 +54,14 @@ public class MemMergeNode extends Node {
@Override public String label() { return "MemMerge"; }
@Override public boolean isMem() { return true; }
@Override public Type compute() { return TypeMem.BOT; }
- @Override public StringBuilder _print1(StringBuilder sb, BitSet visited) {
- sb.append("MEM[");
+ @Override protected ExprPrinter<Node> _print1(ExprPrinter<Node> p) {
+ p.p("MEM[");
for( int i=1; i<nIns(); i++ )
if( in(i)!=null ) {
- sb.append(i==1 ? "default:" : i+":");
- in(i)._print0(sb,visited).append(" ");
+ p.p(i==1 ? "default:" : i+":");
+ p.n(in(i)).p(" ");
}
- return sb.append("]");
+ return p.p("]");
}
@Override public Node idealize() {
diff --git a/chapter21/src/main/java/com/seaofnodes/simple/node/MemOpNode.java b/chapter21/src/main/java/com/seaofnodes/simple/node/MemOpNode.java
index 344e8b2c..adfc80a5 100644
--- a/chapter21/src/main/java/com/seaofnodes/simple/node/MemOpNode.java
+++ b/chapter21/src/main/java/com/seaofnodes/simple/node/MemOpNode.java
@@ -1,5 +1,7 @@
package com.seaofnodes.simple.node;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.Parser;
import com.seaofnodes.simple.Utils;
import com.seaofnodes.simple.type.Type;
@@ -86,8 +88,8 @@ public abstract class MemOpNode extends Node {
public Node ptr() { return in(2); }
public Node off() { return in(3); }
- @Override public StringBuilder _print1( StringBuilder sb, BitSet visited ) { return _printMach(sb,visited); }
- public StringBuilder _printMach( StringBuilder sb, BitSet visited ) { throw Utils.TODO(); }
+ @Override protected ExprPrinter<Node> _print1(ExprPrinter<Node> p) { return _printMach(p); }
+ protected ExprPrinter<Node> _printMach(ExprPrinter<Node> p) { throw Utils.TODO(); }
// Extra conditions for factoring matching memory operations through a Phi.
diff --git a/chapter21/src/main/java/com/seaofnodes/simple/node/MinusFNode.java b/chapter21/src/main/java/com/seaofnodes/simple/node/MinusFNode.java
index bfdb41cc..852e646d 100644
--- a/chapter21/src/main/java/com/seaofnodes/simple/node/MinusFNode.java
+++ b/chapter21/src/main/java/com/seaofnodes/simple/node/MinusFNode.java
@@ -1,20 +1,16 @@
package com.seaofnodes.simple.node;
+
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeFloat;
-import java.util.BitSet;
public class MinusFNode extends Node {
public MinusFNode(Node in) { super(null, in); }
@Override public String label() { return "MinusF"; }
- @Override
- public StringBuilder _print1(StringBuilder sb, BitSet visited) {
- in(1)._print0(sb.append("(-"), visited);
- return sb.append(")");
- }
+ @Override protected String format() { return "(-%1)"; }
@Override
public Type compute() {
diff --git a/chapter21/src/main/java/com/seaofnodes/simple/node/MinusNode.java b/chapter21/src/main/java/com/seaofnodes/simple/node/MinusNode.java
index 64f471a8..20220915 100644
--- a/chapter21/src/main/java/com/seaofnodes/simple/node/MinusNode.java
+++ b/chapter21/src/main/java/com/seaofnodes/simple/node/MinusNode.java
@@ -1,21 +1,17 @@
package com.seaofnodes.simple.node;
+
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeInteger;
import com.seaofnodes.simple.Utils;
-import java.util.BitSet;
public class MinusNode extends Node {
public MinusNode(Node in) { super(null, in); }
@Override public String label() { return "Minus"; }
- @Override
- public StringBuilder _print1(StringBuilder sb, BitSet visited) {
- in(1)._print0(sb.append("(-"), visited);
- return sb.append(")");
- }
+ @Override protected String format() { return "(-%1)"; }
@Override
public Type compute() {
diff --git a/chapter21/src/main/java/com/seaofnodes/simple/node/MulFNode.java b/chapter21/src/main/java/com/seaofnodes/simple/node/MulFNode.java
index 0fc062cd..6a57f3c5 100644
--- a/chapter21/src/main/java/com/seaofnodes/simple/node/MulFNode.java
+++ b/chapter21/src/main/java/com/seaofnodes/simple/node/MulFNode.java
@@ -1,21 +1,16 @@
package com.seaofnodes.simple.node;
+
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeFloat;
-import java.util.BitSet;
public class MulFNode extends Node {
public MulFNode(Node lhs, Node rhs) { super(null, lhs, rhs); }
@Override public String label() { return "MulF"; }
- @Override
- public StringBuilder _print1(StringBuilder sb, BitSet visited) {
- in(1)._print0(sb.append("("), visited);
- in(2)._print0(sb.append("*"), visited);
- return sb.append(")");
- }
+ @Override protected String format() { return "(%1*%2)"; }
@Override
public Type compute() {
diff --git a/chapter21/src/main/java/com/seaofnodes/simple/node/MulNode.java b/chapter21/src/main/java/com/seaofnodes/simple/node/MulNode.java
index 7609f1d4..e9dc6887 100644
--- a/chapter21/src/main/java/com/seaofnodes/simple/node/MulNode.java
+++ b/chapter21/src/main/java/com/seaofnodes/simple/node/MulNode.java
@@ -1,21 +1,16 @@
package com.seaofnodes.simple.node;
+
import com.seaofnodes.simple.Parser;
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeInteger;
-import java.util.BitSet;
public class MulNode extends Node {
public MulNode(Node lhs, Node rhs) { super(null, lhs, rhs); }
@Override public String label() { return "Mul"; }
- @Override
- public StringBuilder _print1(StringBuilder sb, BitSet visited) {
- in(1)._print0(sb.append("("), visited);
- in(2)._print0(sb.append("*"), visited);
- return sb.append(")");
- }
+ @Override protected String format() { return "(%1*%2)"; }
@Override
public Type compute() {
diff --git a/chapter21/src/main/java/com/seaofnodes/simple/node/NeverNode.java b/chapter21/src/main/java/com/seaofnodes/simple/node/NeverNode.java
index 516f218b..66879b66 100644
--- a/chapter21/src/main/java/com/seaofnodes/simple/node/NeverNode.java
+++ b/chapter21/src/main/java/com/seaofnodes/simple/node/NeverNode.java
@@ -1,11 +1,12 @@
package com.seaofnodes.simple.node;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.Parser;
import com.seaofnodes.simple.type.TypeInteger;
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeTuple;
-import java.util.BitSet;
// "Never true" for infinite loop exits
public class NeverNode extends IfNode {
@@ -14,7 +15,7 @@ public class NeverNode extends IfNode {
@Override public String label() { return "Never"; }
- @Override public StringBuilder _print1(StringBuilder sb, BitSet visited) { return sb.append("Never"); }
+ @Override protected ExprPrinter<Node> _print1(ExprPrinter<Node> p) { return p.p("Never"); }
@Override public Type compute() { return TypeTuple.IF_BOTH; }
diff --git a/chapter21/src/main/java/com/seaofnodes/simple/node/NewNode.java b/chapter21/src/main/java/com/seaofnodes/simple/node/NewNode.java
index 57d351ef..4179821c 100644
--- a/chapter21/src/main/java/com/seaofnodes/simple/node/NewNode.java
+++ b/chapter21/src/main/java/com/seaofnodes/simple/node/NewNode.java
@@ -1,10 +1,11 @@
package com.seaofnodes.simple.node;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.SB;
import com.seaofnodes.simple.Utils;
import com.seaofnodes.simple.codegen.*;
import com.seaofnodes.simple.type.*;
-import java.util.BitSet;
/** Allocate a zeroed object. Inputs {ctrl, $mem, size};
* results {ptr, $mem}.
@@ -37,10 +38,8 @@ public class NewNode extends Node implements MultiNode {
@Override public String label() { return "new_"+(_ptr._obj.isAry() ? "ary_"+_ptr._obj._fields[1]._type.str() : _ptr._obj.str()); }
- @Override
- public StringBuilder _print1(StringBuilder sb, BitSet visited) {
- sb.append("new ");
- return sb.append(_ptr._obj.str());
+ @Override protected ExprPrinter<Node> _print1(ExprPrinter<Node> p) {
+ return p.p("new ").p(_ptr._obj.str());
}
diff --git a/chapter21/src/main/java/com/seaofnodes/simple/node/Node.java b/chapter21/src/main/java/com/seaofnodes/simple/node/Node.java
index 12faf706..8b0647d0 100644
--- a/chapter21/src/main/java/com/seaofnodes/simple/node/Node.java
+++ b/chapter21/src/main/java/com/seaofnodes/simple/node/Node.java
@@ -1,5 +1,7 @@
package com.seaofnodes.simple.node;
+import com.seaofnodes.print.BaseNode;
+
import com.seaofnodes.simple.*;
import com.seaofnodes.simple.codegen.CodeGen;
import com.seaofnodes.simple.print.IRPrinter;
@@ -15,14 +17,7 @@ import static com.seaofnodes.simple.codegen.CodeGen.CODE;
* The Node class provides common functionality used by all subtypes.
* Subtypes of Node specialize by overriding methods.
*/
-public abstract class Node implements Cloneable {
-
- /**
- * Each node has a unique dense Node ID within a compilation context
- * The ID is useful for debugging, for using as an offset in a bitvector,
- * as well as for computing equality of nodes (to be implemented later).
- */
- public int _nid;
+public abstract class Node extends BaseNode<Node> implements Cloneable {
/**
* Inputs to the node. These are use-def references to Nodes.
@@ -44,16 +39,14 @@ public abstract class Node implements Cloneable {
*/
public Ary<Node> _outputs;
-
/**
* Current computed type for this Node. This value changes as the graph
* changes and more knowledge is gained about the program.
*/
public Type _type;
-
Node(Node... inputs) {
- _nid = CODE.getUID(); // allocate unique dense ID
+ super(CODE.getUID()); // allocate unique dense ID
_inputs = new Ary<>(Node.class);
Collections.addAll(_inputs,inputs);
_outputs = new Ary<>(Node.class);
@@ -65,8 +58,8 @@ public abstract class Node implements Cloneable {
// Make a Node using the existing arrays of nodes.
// Used by any pass rewriting all Node classes but not the edges.
Node( Node n ) {
+ super(CODE.getUID()); // allocate unique dense ID
assert CodeGen.CODE._phase.ordinal() >= CodeGen.Phase.InstSelect.ordinal();
- _nid = CODE.getUID(); // allocate unique dense ID
_inputs = new Ary<>(n==null ? new Node[0] : n._inputs.asAry());
_outputs = new Ary<>(Node.class);
_type = n==null ? Type.BOTTOM : n._type;
@@ -77,48 +70,6 @@ public abstract class Node implements Cloneable {
// Easy reading label for debugger, e.g. "Add" or "Region" or "EQ"
public abstract String label();
- // Unique label for debugging, e.g. "Add12" or "Region30" or "EQ99"
- public String uniqueName() {
- return label() + _nid;
- }
-
- // Operator symbol used by assembly/debug printing.
- public String glabel() { return label(); }
-
- // Extra fun stuff, for assembly printing. Jump labels, parser locations,
- // variable types, etc.
- public String comment() { return null; }
-
- // ------------------------------------------------------------------------
-
- // Debugger Printing.
-
- // {@code toString} is what you get in the debugger. It has to print 1
- // line (because this is what a debugger typically displays by default) and
- // has to be robust with broken graph/nodes.
- @Override
- public final String toString() { return print(); }
-
- // This is a *deep* print. We print with a mutually recursive tik-tok
- // style; the common _print0 calls the per-Node _print1, which calls back
- // to _print0;
- public final String print() {
- return _print0(new StringBuilder(), new BitSet()).toString();
- }
-
- // This is the common print: check for repeats, check for DEAD and print
- // "DEAD" else call the per-Node print1.
- public final StringBuilder _print0(StringBuilder sb, BitSet visited) {
- if (visited.get(_nid) && !(this instanceof ConstantNode) )
- return sb.append(label());
- visited.set(_nid);
- return isDead()
- ? sb.append(uniqueName()).append(":DEAD")
- : _print1(sb, visited);
- }
- // Every Node implements this; a partial-line recursive print
- abstract public StringBuilder _print1(StringBuilder sb, BitSet visited);
-
public String p(int depth) { return IRPrinter.prettyPrint(this,depth); }
public boolean isConst() { return false; }
@@ -126,6 +77,8 @@ public abstract class Node implements Cloneable {
// ------------------------------------------------------------------------
// Graph Node & Edge manipulation
+ @Override public String typeName() { return _type==null ? null : _type.toString(); }
+
/**
* Gets the ith input node
* @param i Offset of the input node
@@ -204,7 +157,6 @@ public abstract class Node implements Cloneable {
return setDef(idx,new_def);
}
-
/**
* Add a new def to an existing Node. Keep the edges correct by
* adding the corresponding <em>def->use</em> edge.
@@ -273,7 +225,6 @@ public abstract class Node implements Cloneable {
kill();
}
-
// Mostly used for asserts and printing.
public boolean isDead() { return isUnused() && nIns()==0 && _type==null; }
@@ -291,7 +242,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;
@@ -532,7 +482,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
@@ -573,7 +522,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 ) {
@@ -591,7 +539,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
@@ -607,7 +554,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;
@@ -627,7 +573,6 @@ public abstract class Node implements Cloneable {
/** Is this Node Memory related */
public boolean isMem() { return false; }
-
// Semantic change to the graph (so NOT a peephole), used by the Parser.
// If any input is a float, flip to a float-flavored opcode and widen any
// non-float input.
@@ -648,7 +593,6 @@ public abstract class Node implements Cloneable {
}
Node copyF() { return null; }
-
// ------------------------------------------------------------------------
// Peephole utilities
@@ -675,7 +619,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/chapter21/src/main/java/com/seaofnodes/simple/node/NotNode.java b/chapter21/src/main/java/com/seaofnodes/simple/node/NotNode.java
index 118ef5c8..57fa9301 100644
--- a/chapter21/src/main/java/com/seaofnodes/simple/node/NotNode.java
+++ b/chapter21/src/main/java/com/seaofnodes/simple/node/NotNode.java
@@ -1,19 +1,15 @@
package com.seaofnodes.simple.node;
+
import com.seaofnodes.simple.Utils;
import com.seaofnodes.simple.type.*;
-import java.util.BitSet;
public class NotNode extends Node {
public NotNode(Node in) { super(null, in); }
@Override public String label() { return "Not"; }
- @Override
- public StringBuilder _print1(StringBuilder sb, BitSet visited) {
- in(1)._print0(sb.append("(!"), visited);
- return sb.append(")");
- }
+ @Override protected String format() { return "(!%1)"; }
@Override
public TypeInteger compute() {
diff --git a/chapter21/src/main/java/com/seaofnodes/simple/node/ParmNode.java b/chapter21/src/main/java/com/seaofnodes/simple/node/ParmNode.java
index 0eb2e5f0..c3a0cf21 100644
--- a/chapter21/src/main/java/com/seaofnodes/simple/node/ParmNode.java
+++ b/chapter21/src/main/java/com/seaofnodes/simple/node/ParmNode.java
@@ -1,8 +1,9 @@
package com.seaofnodes.simple.node;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.Utils;
import com.seaofnodes.simple.type.Type;
-import java.util.BitSet;
public class ParmNode extends PhiNode {
@@ -20,18 +21,12 @@ public class ParmNode extends PhiNode {
public FunNode fun() { return (FunNode)in(0); }
@Override
- public StringBuilder _print1(StringBuilder sb, BitSet visited) {
+ protected ExprPrinter<Node> _print1(ExprPrinter<Node> p) {
if( "main".equals(fun()._name) && _label.equals("arg") )
- return sb.append("arg");
- sb.append("Parm_").append(_label).append("(");
- for( Node in : _inputs ) {
- if (in == null) sb.append("____");
- else in._print0(sb, visited);
- sb.append(",");
- }
- sb.setLength(sb.length()-1);
- sb.append(")");
- return sb;
+ return p.p("arg");
+ p.p("Parm_").p(_label).open();
+ for( Node in : _inputs ) p.n(in).p(",");
+ return p.unchar(',').close();
}
diff --git a/chapter21/src/main/java/com/seaofnodes/simple/node/PhiNode.java b/chapter21/src/main/java/com/seaofnodes/simple/node/PhiNode.java
index 23acd75e..e075ea5c 100644
--- a/chapter21/src/main/java/com/seaofnodes/simple/node/PhiNode.java
+++ b/chapter21/src/main/java/com/seaofnodes/simple/node/PhiNode.java
@@ -1,8 +1,9 @@
package com.seaofnodes.simple.node;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.*;
import com.seaofnodes.simple.type.*;
-import java.util.BitSet;
public class PhiNode extends Node {
@@ -31,18 +32,12 @@ public class PhiNode extends Node {
@Override public String label() { return "Phi_"+MemOpNode.mlabel(_label); }
@Override
- public StringBuilder _print1(StringBuilder sb, BitSet visited) {
+ protected ExprPrinter<Node> _print1(ExprPrinter<Node> p) {
if( !(region() instanceof RegionNode r) || r.inProgress() )
- sb.append("Z");
- sb.append("Phi(");
- for( Node in : _inputs ) {
- if (in == null) sb.append("____");
- else in._print0(sb, visited);
- sb.append(",");
- }
- sb.setLength(sb.length()-1);
- sb.append(")");
- return sb;
+ p.p("Z");
+ p.p("Phi(");
+ for( Node in : _inputs ) p.n(in).p(",");
+ return p.unchar(',').close();
}
public CFGNode region() { return (CFGNode)in(0); }
diff --git a/chapter21/src/main/java/com/seaofnodes/simple/node/ProjNode.java b/chapter21/src/main/java/com/seaofnodes/simple/node/ProjNode.java
index 48f92525..26b3a522 100644
--- a/chapter21/src/main/java/com/seaofnodes/simple/node/ProjNode.java
+++ b/chapter21/src/main/java/com/seaofnodes/simple/node/ProjNode.java
@@ -1,10 +1,11 @@
package com.seaofnodes.simple.node;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeMem;
import com.seaofnodes.simple.type.TypeTuple;
-import java.util.BitSet;
public class ProjNode extends Node {
@@ -24,11 +25,11 @@ public class ProjNode extends Node {
@Override public String label() { return _label; }
@Override
- public StringBuilder _print1(StringBuilder sb, BitSet visited) {
- if( _label != null ) return sb.append(_label);
+ protected ExprPrinter<Node> _print1(ExprPrinter<Node> p) {
+ if( _label != null ) return p.p(_label);
if( in(0) instanceof CallEndNode cend && cend.call()!=null )
- return cend.call()._print0(sb,visited);
- return sb.append("LONELY PROJ");
+ return p.n(cend.call());
+ return p.p("LONELY PROJ");
}
@Override public CFGNode cfg0() {
diff --git a/chapter21/src/main/java/com/seaofnodes/simple/node/ReadOnlyNode.java b/chapter21/src/main/java/com/seaofnodes/simple/node/ReadOnlyNode.java
index e9c25f47..d79f2815 100644
--- a/chapter21/src/main/java/com/seaofnodes/simple/node/ReadOnlyNode.java
+++ b/chapter21/src/main/java/com/seaofnodes/simple/node/ReadOnlyNode.java
@@ -1,9 +1,9 @@
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
@@ -13,10 +13,7 @@ public class ReadOnlyNode extends Node {
public ReadOnlyNode( ReadOnlyNode n ) { super(n); }
@Override public String label() { return "ReadOnly"; }
- @Override
- public StringBuilder _print1(StringBuilder sb, BitSet visited) {
- return in(1)._print0(sb.append("(const)"),visited);
- }
+ @Override protected String format() { return "(const)%1"; }
@Override public Type compute() {
Type t = in(1)._type;
return t instanceof TypeMemPtr tmp ? tmp.makeRO() : t;
diff --git a/chapter21/src/main/java/com/seaofnodes/simple/node/RegionNode.java b/chapter21/src/main/java/com/seaofnodes/simple/node/RegionNode.java
index 84383845..79b7f53a 100644
--- a/chapter21/src/main/java/com/seaofnodes/simple/node/RegionNode.java
+++ b/chapter21/src/main/java/com/seaofnodes/simple/node/RegionNode.java
@@ -1,5 +1,7 @@
package com.seaofnodes.simple.node;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.*;
import com.seaofnodes.simple.Parser;
import com.seaofnodes.simple.codegen.CodeGen;
@@ -17,9 +19,8 @@ public class RegionNode extends CFGNode {
@Override
public String label() { return "Region"; }
- @Override
- public StringBuilder _print1(StringBuilder sb, BitSet visited) {
- return sb.append(label());
+ @Override protected ExprPrinter<Node> _print1(ExprPrinter<Node> p) {
+ return p.p(label());
}
@Override public boolean blockHead() { return true; }
diff --git a/chapter21/src/main/java/com/seaofnodes/simple/node/ReturnNode.java b/chapter21/src/main/java/com/seaofnodes/simple/node/ReturnNode.java
index 05b19682..e0ab863a 100644
--- a/chapter21/src/main/java/com/seaofnodes/simple/node/ReturnNode.java
+++ b/chapter21/src/main/java/com/seaofnodes/simple/node/ReturnNode.java
@@ -1,5 +1,7 @@
package com.seaofnodes.simple.node;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.Parser;
import com.seaofnodes.simple.SB;
import com.seaofnodes.simple.Utils;
@@ -7,7 +9,6 @@ import com.seaofnodes.simple.codegen.CodeGen;
import com.seaofnodes.simple.codegen.RegMask;
import com.seaofnodes.simple.codegen.Encoding;
import com.seaofnodes.simple.type.*;
-import java.util.BitSet;
/** Keeps all preceding memory effects and the return value alive: {ctrl, $mem, value, rpc}. */
public class ReturnNode extends CFGNode {
@@ -30,11 +31,11 @@ public class ReturnNode extends CFGNode {
public String label() { return "Return"; }
@Override
- public StringBuilder _print1(StringBuilder sb, BitSet visited) {
- sb.append("return ");
- if( expr()==null ) sb.append("----");
- else expr()._print0(sb, visited);
- return sb.append(";");
+ protected ExprPrinter<Node> _print1(ExprPrinter<Node> p) {
+ p.p("return ");
+ if( expr()==null ) p.p("----");
+ else p.n(expr());
+ return p.p(";");
}
// No one unique control follows; can be many call end sites
diff --git a/chapter21/src/main/java/com/seaofnodes/simple/node/RoundF32Node.java b/chapter21/src/main/java/com/seaofnodes/simple/node/RoundF32Node.java
index 2ad034d6..78e7698c 100644
--- a/chapter21/src/main/java/com/seaofnodes/simple/node/RoundF32Node.java
+++ b/chapter21/src/main/java/com/seaofnodes/simple/node/RoundF32Node.java
@@ -1,19 +1,16 @@
package com.seaofnodes.simple.node;
+
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeFloat;
-import java.util.BitSet;
public class RoundF32Node extends Node {
public RoundF32Node(Node lhs) { super(null, lhs); }
@Override public String label() { return "RoundF32"; }
- @Override
- public StringBuilder _print1(StringBuilder sb, BitSet visited) {
- return in(1)._print0(sb.append("((f32)"), visited).append(")");
- }
+ @Override protected String format() { return "((f32)%1)"; }
@Override
public Type compute() {
diff --git a/chapter21/src/main/java/com/seaofnodes/simple/node/ScopeNode.java b/chapter21/src/main/java/com/seaofnodes/simple/node/ScopeNode.java
index e8c4f0d5..2724d0a6 100644
--- a/chapter21/src/main/java/com/seaofnodes/simple/node/ScopeNode.java
+++ b/chapter21/src/main/java/com/seaofnodes/simple/node/ScopeNode.java
@@ -1,5 +1,7 @@
package com.seaofnodes.simple.node;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.*;
import com.seaofnodes.simple.codegen.CodeGen;
import com.seaofnodes.simple.type.*;
@@ -49,28 +51,26 @@ public class ScopeNode extends Node {
@Override public String label() { return "Scope"; }
@Override
- public StringBuilder _print1(StringBuilder sb, BitSet visited) {
- sb.append("Scope[ ");
+ protected ExprPrinter<Node> _print1(ExprPrinter<Node> p) {
+ p.p("Scope[ ");
int j=1;
for( int i=0; i<nIns(); i++ ) {
- if( j < _lexSize._len && i == _lexSize.at(j) ) { sb.append("| "); j++; }
+ if( j < _lexSize._len && i == _lexSize.at(j) ) { p.p("| "); j++; }
Var v = _vars.get(i);
- sb.append(v._type().print(new SB()));
- sb.append(" ");
- if( v._final ) sb.append("!");
- sb.append(v._name);
- sb.append("=");
+ p.p(v._type().print(new SB()));
+ p.p(" ");
+ if( v._final ) p.p("!");
+ p.p(v._name);
+ p.p("=");
Node n = in(i);
while( n instanceof ScopeNode loop ) {
- sb.append("Lazy_");
+ p.p("Lazy_");
n = loop.in(i);
}
- if( n==null ) sb.append("___");
- else n._print0(sb, visited);
- sb.append(", ");
+ p.n(n);
+ p.p(", ");
}
- sb.setLength(sb.length()-2);
- return sb.append("]");
+ return p.unchar(", ").p("]");
}
diff --git a/chapter21/src/main/java/com/seaofnodes/simple/node/SplitNode.java b/chapter21/src/main/java/com/seaofnodes/simple/node/SplitNode.java
index 3a1ed011..ff18b292 100644
--- a/chapter21/src/main/java/com/seaofnodes/simple/node/SplitNode.java
+++ b/chapter21/src/main/java/com/seaofnodes/simple/node/SplitNode.java
@@ -1,20 +1,21 @@
package com.seaofnodes.simple.node;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.SB;
import com.seaofnodes.simple.codegen.CodeGen;
import com.seaofnodes.simple.type.Type;
-import java.util.BitSet;
public abstract class SplitNode extends MachConcreteNode {
public final String _kind; // Kind of split
public final byte _round;
public SplitNode(String kind, byte round, Node[] nodes) { super(nodes); _kind = kind; _round = round; }
@Override public String op() { return "mov"; }
- @Override public StringBuilder _print1(StringBuilder sb, BitSet visited) {
- sb.append("mov(");
- if( in(1) == null ) sb.append("---");
- else in(1)._print0(sb,visited);
- return sb.append(")");
+ @Override protected ExprPrinter<Node> _print1(ExprPrinter<Node> p) {
+ p.p("mov(");
+ if( in(1) == null ) p.p("---");
+ else p.n(in(1));
+ return p.close();
}
@Override public Type compute() { return in(0)._type; }
@Override public Node idealize() { return null; }
diff --git a/chapter21/src/main/java/com/seaofnodes/simple/node/StartNode.java b/chapter21/src/main/java/com/seaofnodes/simple/node/StartNode.java
index 91bf85a1..cbaefa6a 100644
--- a/chapter21/src/main/java/com/seaofnodes/simple/node/StartNode.java
+++ b/chapter21/src/main/java/com/seaofnodes/simple/node/StartNode.java
@@ -1,9 +1,10 @@
package com.seaofnodes.simple.node;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.codegen.CodeGen;
import com.seaofnodes.simple.Parser;
import com.seaofnodes.simple.type.*;
-import java.util.BitSet;
import java.util.HashSet;
import static com.seaofnodes.simple.Utils.TODO;
@@ -17,9 +18,8 @@ public class StartNode extends LoopNode implements MultiNode {
@Override public String label() { return "Start"; }
- @Override
- public StringBuilder _print1(StringBuilder sb, BitSet visited) {
- return sb.append(label());
+ @Override protected ExprPrinter<Node> _print1(ExprPrinter<Node> p) {
+ return p.p(label());
}
@Override public boolean blockHead() { return true; }
diff --git a/chapter21/src/main/java/com/seaofnodes/simple/node/StopNode.java b/chapter21/src/main/java/com/seaofnodes/simple/node/StopNode.java
index d381e716..c88dbf51 100644
--- a/chapter21/src/main/java/com/seaofnodes/simple/node/StopNode.java
+++ b/chapter21/src/main/java/com/seaofnodes/simple/node/StopNode.java
@@ -1,8 +1,9 @@
package com.seaofnodes.simple.node;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.Utils;
import com.seaofnodes.simple.type.Type;
-import java.util.BitSet;
public class StopNode extends CFGNode {
@@ -21,14 +22,14 @@ 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"
- if( ret()!=null ) return ret()._print0(sb,visited);
- sb.append("Stop[ ");
+ if( ret()!=null ) return p.n(ret());
+ p.p("Stop[ ");
for( Node ret : _inputs )
if( ret!=null )
- ret._print0(sb, visited).append(" ");
- return sb.append("]");
+ p.n(ret).p(" ");
+ return p.p("]");
}
@Override public boolean blockHead() { return true; }
diff --git a/chapter21/src/main/java/com/seaofnodes/simple/node/StoreNode.java b/chapter21/src/main/java/com/seaofnodes/simple/node/StoreNode.java
index 86dce4fc..f0cb3d1c 100644
--- a/chapter21/src/main/java/com/seaofnodes/simple/node/StoreNode.java
+++ b/chapter21/src/main/java/com/seaofnodes/simple/node/StoreNode.java
@@ -1,9 +1,10 @@
package com.seaofnodes.simple.node;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.codegen.*;
import com.seaofnodes.simple.*;
import com.seaofnodes.simple.type.*;
-import java.util.BitSet;
/**
* Store represents setting a value to a memory based object, in chapter 10
@@ -36,8 +37,8 @@ public class StoreNode extends MemOpNode {
public Node val() { return in(4); }
@Override
- public StringBuilder _print1(StringBuilder sb, BitSet visited) {
- return sb.append(".").append(_name).append("=").append( val()).append(";");
+ protected ExprPrinter<Node> _print1(ExprPrinter<Node> p) {
+ return p.p(".").p(_name).p("=").p( val()).p(";");
}
@Override
diff --git a/chapter21/src/main/java/com/seaofnodes/simple/node/StructNode.java b/chapter21/src/main/java/com/seaofnodes/simple/node/StructNode.java
index 4efc0de9..3782d64a 100644
--- a/chapter21/src/main/java/com/seaofnodes/simple/node/StructNode.java
+++ b/chapter21/src/main/java/com/seaofnodes/simple/node/StructNode.java
@@ -1,8 +1,9 @@
package com.seaofnodes.simple.node;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.SB;
import com.seaofnodes.simple.type.*;
-import java.util.BitSet;
/**
* Build a compound object
@@ -14,16 +15,15 @@ public class StructNode extends Node {
@Override public String label() { return _ts==null ? "STRUCT?" : _ts.str(); }
@Override
- public StringBuilder _print1(StringBuilder sb, BitSet visited) {
- if( _ts==null ) return sb.append("STRUCT?");
- sb.append(_ts._name).append(" {");
+ protected ExprPrinter<Node> _print1(ExprPrinter<Node> p) {
+ if( _ts==null ) return p.p("STRUCT?");
+ p.p(_ts._name).p(" {");
for( int i=0; i<nIns(); i++ ) {
- sb.append(_ts._fields[i]._fname).append(":");
- sb.append((in(i)==null ? Type.BOTTOM : in(i)._type).print(new SB()));
- sb.append("; ");
+ p.p(_ts._fields[i]._fname).p(":");
+ p.p((in(i)==null ? Type.BOTTOM : in(i)._type).print(new SB()));
+ p.p("; ");
}
- sb.setLength(sb.length()-2);
- return sb.append("}");
+ return p.unchar("; ").p("}");
}
@Override
diff --git a/chapter21/src/main/java/com/seaofnodes/simple/node/SubFNode.java b/chapter21/src/main/java/com/seaofnodes/simple/node/SubFNode.java
index 73cf9de5..2d218a03 100644
--- a/chapter21/src/main/java/com/seaofnodes/simple/node/SubFNode.java
+++ b/chapter21/src/main/java/com/seaofnodes/simple/node/SubFNode.java
@@ -1,21 +1,16 @@
package com.seaofnodes.simple.node;
+
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeFloat;
-import java.util.BitSet;
public class SubFNode extends Node {
public SubFNode(Node lhs, Node rhs) { super(null, lhs, rhs); }
@Override public String label() { return "SubF"; }
- @Override
- public StringBuilder _print1(StringBuilder sb, BitSet visited) {
- in(1)._print0(sb.append("("), visited);
- in(2)._print0(sb.append("-"), visited);
- return sb.append(")");
- }
+ @Override protected String format() { return "(%1-%2)"; }
@Override
public Type compute() {
diff --git a/chapter21/src/main/java/com/seaofnodes/simple/node/SubNode.java b/chapter21/src/main/java/com/seaofnodes/simple/node/SubNode.java
index 3b3a6321..9bf6d83e 100644
--- a/chapter21/src/main/java/com/seaofnodes/simple/node/SubNode.java
+++ b/chapter21/src/main/java/com/seaofnodes/simple/node/SubNode.java
@@ -1,21 +1,16 @@
package com.seaofnodes.simple.node;
+
import com.seaofnodes.simple.Parser;
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeInteger;
-import java.util.BitSet;
public class SubNode extends Node {
public SubNode(Node lhs, Node rhs) { super(null, lhs, rhs); }
@Override public String label() { return "Sub"; }
- @Override
- public StringBuilder _print1(StringBuilder sb, BitSet visited) {
- in(1)._print0(sb.append("("), visited);
- in(2)._print0(sb.append("-"), visited);
- return sb.append(")");
- }
+ @Override protected String format() { return "(%1-%2)"; }
@Override
public Type compute() {
diff --git a/chapter21/src/main/java/com/seaofnodes/simple/node/ToFloatNode.java b/chapter21/src/main/java/com/seaofnodes/simple/node/ToFloatNode.java
index 8ef5e40a..7b0122ce 100644
--- a/chapter21/src/main/java/com/seaofnodes/simple/node/ToFloatNode.java
+++ b/chapter21/src/main/java/com/seaofnodes/simple/node/ToFloatNode.java
@@ -1,20 +1,17 @@
package com.seaofnodes.simple.node;
+
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeFloat;
import com.seaofnodes.simple.type.TypeInteger;
-import java.util.BitSet;
public class ToFloatNode extends Node {
public ToFloatNode(Node lhs) { super(null, lhs); }
@Override public String label() { return "ToFloat"; }
- @Override
- public StringBuilder _print1(StringBuilder sb, BitSet visited) {
- return in(1)._print0(sb.append("(flt)"), visited);
- }
+ @Override protected String format() { return "(flt)%1"; }
@Override
public Type compute() {
diff --git a/chapter21/src/main/java/com/seaofnodes/simple/node/XCtrlNode.java b/chapter21/src/main/java/com/seaofnodes/simple/node/XCtrlNode.java
index 8c620a04..477b9af8 100644
--- a/chapter21/src/main/java/com/seaofnodes/simple/node/XCtrlNode.java
+++ b/chapter21/src/main/java/com/seaofnodes/simple/node/XCtrlNode.java
@@ -1,14 +1,15 @@
package com.seaofnodes.simple.node;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.codegen.CodeGen;
import com.seaofnodes.simple.Parser;
import com.seaofnodes.simple.type.Type;
-import java.util.BitSet;
public class XCtrlNode extends CFGNode {
public XCtrlNode() { super(new Node[]{CodeGen.CODE._start}); }
@Override public String label() { return "Xctrl"; }
- @Override public StringBuilder _print1(StringBuilder sb, BitSet visited) { return sb.append("Xctrl"); }
+ @Override protected ExprPrinter<Node> _print1(ExprPrinter<Node> p) { return p.p("Xctrl"); }
@Override public boolean isConst() { return true; }
@Override public Type compute() { return Type.XCONTROL; }
@Override public Node idealize() { return null; }
diff --git a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/CallARM.java b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/CallARM.java
index 7f6fe93c..4fb04f7b 100644
--- a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/CallARM.java
+++ b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/CallARM.java
@@ -39,7 +39,7 @@ public class CallARM extends CallNode implements MachNode, RIPRelSize {
}
@Override public void asm(CodeGen code, SB sb) {
- sb.p(_name);
+ sb.p(_name).p(" ");
for( int i=0; i<nargs(); i++ )
sb.p(code.reg(arg(i+2))).p(" ");
sb.unchar(2);
diff --git a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/MemOpARM.java b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/MemOpARM.java
index bec0acc5..afd8723e 100644
--- a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/MemOpARM.java
+++ b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/MemOpARM.java
@@ -1,12 +1,13 @@
package com.seaofnodes.simple.node.cpus.arm;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.*;
import com.seaofnodes.simple.codegen.*;
import com.seaofnodes.simple.node.*;
import com.seaofnodes.simple.type.*;
import java.lang.StringBuilder;
-import java.util.BitSet;
public abstract class MemOpARM extends MemOpNode implements MachNode {
@@ -32,7 +33,7 @@ public abstract class MemOpARM extends MemOpNode implements MachNode {
@Override public String label() { return op();}
Node val() { return in(4); } // Only for stores
- @Override public StringBuilder _printMach(StringBuilder sb, BitSet visited) { return sb.append(".").append(_name); }
+ @Override protected ExprPrinter<Node> _printMach(ExprPrinter<Node> p) { return p.p(".").p(_name); }
@Override public Type compute() { throw Utils.TODO(); }
@Override public Node idealize() { throw Utils.TODO(); }
diff --git a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/UJmpARM.java b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/UJmpARM.java
index a69c3c7c..bf46a7b1 100644
--- a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/UJmpARM.java
+++ b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/UJmpARM.java
@@ -1,19 +1,17 @@
package com.seaofnodes.simple.node.cpus.arm;
+
import com.seaofnodes.simple.*;
import com.seaofnodes.simple.codegen.*;
import com.seaofnodes.simple.node.*;
import com.seaofnodes.simple.type.Type;
-import java.util.BitSet;
// unconditional jump
public class UJmpARM extends CFGNode implements MachNode, RIPRelSize {
UJmpARM() { }
@Override public String op() { return "jmp"; }
@Override public String label() { return op(); }
- @Override public StringBuilder _print1( StringBuilder sb, BitSet visited ) {
- return sb.append("jmp ");
- }
+ @Override protected String format() { return "jmp "; }
@Override public RegMask regmap(int i) {return null; }
@Override public RegMask outregmap() { return null; }
@Override public Type compute() { throw Utils.TODO(); }
diff --git a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/BranchRISC.java b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/BranchRISC.java
index 44ff4e8b..f6dc5cf2 100644
--- a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/BranchRISC.java
+++ b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/BranchRISC.java
@@ -1,9 +1,10 @@
package com.seaofnodes.simple.node.cpus.riscv;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.*;
import com.seaofnodes.simple.codegen.*;
import com.seaofnodes.simple.node.*;
-import java.util.BitSet;
// Conditional branch such as: BEQ
public class BranchRISC extends IfNode implements MachNode, RIPRelSize {
@@ -30,14 +31,14 @@ public class BranchRISC extends IfNode implements MachNode, RIPRelSize {
}
}
- @Override public StringBuilder _print1(StringBuilder sb, BitSet visited) {
- sb.append("if( ");
- if( in(1)==null ) sb.append("0");
- else in(1)._print0(sb,visited);
- sb.append(_bop);
- if( in(2)==null ) sb.append("0");
- else in(2)._print0(sb,visited);
- return sb.append(" )");
+ @Override protected ExprPrinter<Node> _print1(ExprPrinter<Node> p) {
+ p.p("if( ");
+ if( in(1)==null ) p.p("0");
+ else p.n(in(1));
+ p.p(_bop);
+ if( in(2)==null ) p.p("0");
+ else p.n(in(2));
+ return p.p(" )");
}
@Override public void encoding( Encoding enc ) {
diff --git a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/ImmRISC.java b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/ImmRISC.java
index 9303e566..37cd925f 100644
--- a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/ImmRISC.java
+++ b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/ImmRISC.java
@@ -1,10 +1,11 @@
package com.seaofnodes.simple.node.cpus.riscv;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.*;
import com.seaofnodes.simple.codegen.*;
import com.seaofnodes.simple.node.*;
import com.seaofnodes.simple.type.TypeInteger;
-import java.util.BitSet;
abstract public class ImmRISC extends MachConcreteNode implements MachNode {
public final int _imm12;
@@ -28,10 +29,10 @@ abstract public class ImmRISC extends MachConcreteNode implements MachNode {
return in(1) instanceof LUI || in(1) instanceof AUIPC;
}
- @Override public StringBuilder _print1(StringBuilder sb, BitSet visited) {
+ @Override protected ExprPrinter<Node> _print1(ExprPrinter<Node> p) {
int imm12 = (_imm12<<20)>>20; // Sign extend 12 bits
- in(1)._print0(sb.append("( "), visited);
- return sb.append(String.format(" %s #%d )",glabel(),imm12));
+ p.p("( ").n(in(1));
+ return p.p(String.format(" %s #%d )",glabel(),imm12));
}
abstract int opcode();
diff --git a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/MemOpRISC.java b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/MemOpRISC.java
index b8eb7644..41ab37be 100644
--- a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/MemOpRISC.java
+++ b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/MemOpRISC.java
@@ -1,11 +1,12 @@
package com.seaofnodes.simple.node.cpus.riscv;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.SB;
import com.seaofnodes.simple.Utils;
import com.seaofnodes.simple.codegen.*;
import com.seaofnodes.simple.node.*;
import com.seaofnodes.simple.type.*;
-import java.util.BitSet;
public abstract class MemOpRISC extends MemOpNode implements MachNode {
final int _off; // Limit 12 bits
@@ -23,7 +24,7 @@ public abstract class MemOpRISC extends MemOpNode implements MachNode {
@Override public String label() { return op(); }
Node val() { return in(4); } // Only for stores
- @Override public StringBuilder _printMach(StringBuilder sb, BitSet visited) { return sb.append(".").append(_name); }
+ @Override protected ExprPrinter<Node> _printMach(ExprPrinter<Node> p) { return p.p(".").p(_name); }
@Override public Type compute() { throw Utils.TODO(); }
@Override public Node idealize() { throw Utils.TODO(); }
diff --git a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/UJmpRISC.java b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/UJmpRISC.java
index 6473d81c..3868990d 100644
--- a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/UJmpRISC.java
+++ b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/UJmpRISC.java
@@ -1,16 +1,17 @@
package com.seaofnodes.simple.node.cpus.riscv;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.*;
import com.seaofnodes.simple.codegen.*;
import com.seaofnodes.simple.node.*;
import com.seaofnodes.simple.type.Type;
-import java.util.BitSet;
// unconditional jump
public class UJmpRISC extends CFGNode implements MachNode, RIPRelSize {
@Override public String op() { return "jmp"; }
@Override public String label() { return op(); }
- @Override public StringBuilder _print1( StringBuilder sb, BitSet visited ) { return sb.append("jmp "); }
+ @Override protected ExprPrinter<Node> _print1(ExprPrinter<Node> p) { return p.p("jmp "); }
@Override public RegMask regmap(int i) {return null; }
@Override public RegMask outregmap() { return null; }
@Override public Type compute() { throw Utils.TODO(); }
diff --git a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/MemOpX86.java b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/MemOpX86.java
index 9f80b1f5..fa3cdd13 100644
--- a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/MemOpX86.java
+++ b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/MemOpX86.java
@@ -1,12 +1,13 @@
package com.seaofnodes.simple.node.cpus.x86_64_v2;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.*;
import com.seaofnodes.simple.codegen.*;
import com.seaofnodes.simple.node.*;
import com.seaofnodes.simple.type.*;
import java.lang.StringBuilder;
-import java.util.BitSet;
// Generic X86 memory operand base.
// inputs:
@@ -53,8 +54,8 @@ public abstract class MemOpX86 extends MemOpNode implements MachNode {
Node idx() { return in(3); }
Node val() { return in(4); } // Only for stores, including op-to-memory
- @Override public StringBuilder _printMach(StringBuilder sb, BitSet visited) {
- return sb.append(".").append(_name);
+ @Override protected ExprPrinter<Node> _printMach(ExprPrinter<Node> p) {
+ return p.p(".").p(_name);
}
@Override public String label() { return op(); }
diff --git a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/StoreX86.java b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/StoreX86.java
index 76fb4e8d..22a0bd79 100644
--- a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/StoreX86.java
+++ b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/StoreX86.java
@@ -1,5 +1,7 @@
package com.seaofnodes.simple.node.cpus.x86_64_v2;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.SB;
import com.seaofnodes.simple.codegen.*;
import com.seaofnodes.simple.node.ConstantNode;
@@ -7,19 +9,18 @@ import com.seaofnodes.simple.node.Node;
import com.seaofnodes.simple.node.StoreNode;
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeFloat;
-import java.util.BitSet;
public class StoreX86 extends MemOpX86 {
StoreX86( StoreNode st, Node base, Node idx, int off, int scale, int imm, Node val ) {
super(st,st, base, idx, off, scale, imm, val);
}
@Override public String op() { return "st"+_sz; }
- @Override public StringBuilder _printMach(StringBuilder sb, BitSet visited) {
+ @Override protected ExprPrinter<Node> _printMach(ExprPrinter<Node> p) {
Node val = val();
- sb.append(".").append(_name).append("=");
- if( val==null ) sb.append(_imm);
- else val._print0(sb,visited);
- return sb.append(";");
+ p.p(".").p(_name).p("=");
+ if( val==null ) p.p(_imm);
+ else p.n(val);
+ return p.p(";");
}
// Register mask allowed as a result. 0 for no register.
@Override public RegMask outregmap() { return null; }
diff --git a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/UJmpX86.java b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/UJmpX86.java
index ec4eeb3b..5db9e75e 100644
--- a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/UJmpX86.java
+++ b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/UJmpX86.java
@@ -1,19 +1,17 @@
package com.seaofnodes.simple.node.cpus.x86_64_v2;
+
import com.seaofnodes.simple.*;
import com.seaofnodes.simple.codegen.*;
import com.seaofnodes.simple.node.*;
import com.seaofnodes.simple.type.Type;
-import java.util.BitSet;
// unconditional jump
public class UJmpX86 extends CFGNode implements MachNode, RIPRelSize {
UJmpX86() { }
@Override public String op() { return "jmp"; }
@Override public String label() { return op(); }
- @Override public StringBuilder _print1( StringBuilder sb, BitSet visited ) {
- return sb.append("jmp ");
- }
+ @Override protected String format() { return "jmp "; }
@Override public RegMask regmap(int i) {return null; }
@Override public RegMask outregmap() { return null; }
@Override public Type compute() { throw Utils.TODO(); }
diff --git a/chapter21/src/main/java/com/seaofnodes/simple/print/ASMPrinter.java b/chapter21/src/main/java/com/seaofnodes/simple/print/ASMPrinter.java
index 0582be8c..09ebd51b 100644
--- a/chapter21/src/main/java/com/seaofnodes/simple/print/ASMPrinter.java
+++ b/chapter21/src/main/java/com/seaofnodes/simple/print/ASMPrinter.java
@@ -1,287 +1,85 @@
package com.seaofnodes.simple.print;
-import com.seaofnodes.simple.SB;
-import com.seaofnodes.simple.Utils;
+import com.seaofnodes.print.AssemblyAdapter;
+import com.seaofnodes.print.ASMPrinter.Data;
+import com.seaofnodes.print.ASMPrinter.Pool;
import com.seaofnodes.simple.codegen.CodeGen;
-import com.seaofnodes.simple.codegen.Encoding;
+import com.seaofnodes.simple.SB;
import com.seaofnodes.simple.node.*;
import com.seaofnodes.simple.type.*;
-import java.util.Collections;
-import java.util.IdentityHashMap;
-import java.util.Set;
-
-public abstract class ASMPrinter {
+import java.util.ArrayList;
+import com.seaofnodes.simple.codegen.Encoding;
+/** Machine-specific facts; traversal, columns and byte display live in print/. */
+public final class ASMPrinter extends AssemblyAdapter<Node> {
+ private final CodeGen _code;
+ private final Encoding _enc;
+ private ASMPrinter(CodeGen code) {
+ super(new IRPrinter());
+ _code=code;
+ _enc=code._encoding;
+ }
public static SB print(SB sb, CodeGen code) {
- if( code._cfg==null )
- return sb.p("Need _cfg set, run after GCM");
-
- // instruction address
- int iadr = 0;
- for( int i=0; i<code._cfg._len; i++ )
- if( code._cfg.at(i) instanceof FunNode fun )
- iadr = print(iadr,sb,code,fun,i);
-
- // Skip padding
- while( ((iadr+7) & -8) > iadr )
- iadr++;
-
- // constant pool
- Encoding enc = code._encoding;
- if( enc!=null && !enc._bigCons.isEmpty() ) {
- iadr = (iadr+15)&-16; // pad to 16
- Set<Type> targets = Collections.newSetFromMap(new IdentityHashMap<>());
- sb.p("--- Constant Pool ------").nl();
- // By log size
- for( int log = 3; log >= 0; log-- ) {
- for( Encoding.Relo relo : enc._bigCons.values() ) {
- if( targets.contains(relo._t) ) continue;
- targets.add(relo._t);
- if( relo._align==log ) {
- sb.hex2(iadr).p(" ");
- if( relo._t instanceof TypeTuple tt ) {
- for( Type tx : tt._types ) {
- switch( log ) {
- case 0: sb.hex1(enc.read1(iadr)); break;
- case 1: sb.hex2(enc.read2(iadr)); break;
- case 2: sb.hex4(enc.read4(iadr)); break;
- case 3: sb.hex8(enc.read8(iadr)); break;
- }
- iadr += (1<<log);
- sb.p(" ");
- }
- } else {
- switch( log ) {
- case 0: sb.hex1(enc.read1(iadr)).fix(9-1,""); break;
- case 1: sb.hex2(enc.read2(iadr)).fix(9-2,""); break;
- case 2: sb.hex4(enc.read4(iadr)).fix(9-4,""); break;
- case 3: sb.hex8(enc.read8(iadr)).p(" "); break;
- }
- iadr += (1<<log);
- }
- relo._t.print(sb).nl();
- }
- }
- }
- }
-
-
- return sb;
+ return sb.p(new com.seaofnodes.print.ASMPrinter<>(new ASMPrinter(code)).print());
}
-
- private static int print(int iadr, SB sb, CodeGen code, FunNode fun, int cfgidx) {
- FunNode old=null;
- if( code._encoding!=null ) {
- old = code._encoding._fun;
- code._encoding._fun = fun; // Useful printing after RA
- }
- // Function header
- sb.nl().p("---");
- if( fun._name != null ) sb.p(fun._name).p(" ");
- fun.sig().print(sb);
- sb.p("---------------------------").nl();
- iadr = (iadr + 15)&-16; // All function entries padded to 16 align
-
- if( fun._frameAdjust != 0 )
- iadr = doInst(iadr,sb,code,fun,cfgidx,fun,true,true);
- while( !(code._cfg.at(cfgidx) instanceof ReturnNode) )
- iadr = doBlock(iadr,sb,code,fun,cfgidx++);
-
- // Function separator
- sb.p("---");
- fun.sig().print(sb);
- sb.p("---------------------------").nl();
- if( code._encoding != null )
- code._encoding._fun = old;
- return iadr;
+ @Override public ArrayList<Node> blocks() {
+ var blocks=new ArrayList<Node>();
+ var cfg=_code._cfg;
+ if( cfg!=null ) for( Node n : cfg ) blocks.add(n);
+ return blocks;
}
-
- static private final int opWidth = 5;
- static private final int argWidth = 30;
- static int doBlock(int iadr, SB sb, CodeGen code, FunNode fun, int cfgidx) {
- final int encWidth = code._mach==null ? 2 : code._mach.defaultOpSize()*2;
- CFGNode bb = code._cfg.at(cfgidx);
- if( bb != fun && !(bb instanceof IfNode) && !(bb instanceof CallEndNode) && !(bb instanceof CallNode) && !(bb instanceof CProjNode && bb.in(0) instanceof CallEndNode ))
- sb.p(label(bb)).p(":").nl();
- if( bb instanceof CallNode ) return iadr;
- final boolean postAlloc = code._phase.ordinal() > CodeGen.Phase.RegAlloc.ordinal();
- final boolean postEncode= code._phase.ordinal() >=CodeGen.Phase.Encoding.ordinal();
-
- boolean once=false;
- for( Node n : bb.outs() ) {
- if( !(n instanceof PhiNode phi) ) continue;
- if( phi._type instanceof TypeMem || phi._type instanceof TypeRPC ) continue; // Nothing for the hidden ones
- // Post-RegAlloc phi prints all on one line
- if( postAlloc ) {
- if( !once ) { once=true; sb.fix(4," ").p(" ").fix(encWidth,"").p(" "); }
- sb.p(phi._label).p(':').p(code.reg(phi,fun)).p(',');
- } else {
- // Pre-RegAlloc phi prints one line per
- sb.fix(4," ").p(" ").fix(encWidth,"").p(" ").fix(opWidth,phi._label).p(" ").p(code.reg(phi,fun));
- if( phi.getClass() == PhiNode.class ) {
- sb.p(" = phi( ");
- for( int i=1; i<phi.nIns(); i++ )
- sb.p("N").p(phi.in(i)._nid).p(",");
- sb.unchar().p(" )");
- }
- sb.nl();
- }
+ @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(' ');
}
- if( once ) sb.unchar().nl();
-
- // All the non-phis
- for( int i=0; i<bb.nOuts(); i++ )
- if( !(bb.out(i) instanceof PhiNode) )
- iadr = doInst(iadr, sb,code, fun, cfgidx, bb.out(i),postAlloc, postEncode );
-
- return iadr;
+ return sb.toString();
}
-
- static int doInst( int iadr, SB sb, CodeGen code, FunNode fun, int cfgidx, Node n, boolean postAlloc, boolean postEncode ) {
- if( n==null || n instanceof CProjNode ) return iadr;
- if( postAlloc && n instanceof CalleeSaveNode ) return iadr;
- if( postEncode && n instanceof ProjNode ) return iadr;
- if( n instanceof MemMergeNode ) return iadr;
- if( n.getClass() == ConstantNode.class ) return iadr; // Default placeholders
- final int dopz = code._mach==null ? 2 : code._mach.defaultOpSize();
- final int encWidth = dopz*2;
-
- // All blocks ending in a Region will need to either fall into or jump
- // to this block. Until the post-reg-alloc block layout cleanup, we
- // need to assume a jump. There's no real hardware op here, yet.
- if( n instanceof RegionNode cfg && !(n instanceof FunNode) ) {
- if( postEncode ) return iadr; // All jumps inserted already
- while( cfgidx < code._cfg._len-1 ) {
- CFGNode next = code._cfg.at(++cfgidx);
- if( next == n ) return iadr; // Fall-through, no branch
- if( next.nOuts()>1 )
- break; // Has code in the block, need to jump around
- // No code in the block, can fall through it
- }
- sb.hex2(iadr++).p(" ").fix(encWidth,"??").p(" ").fix(opWidth,"JMP").p(" ").fix(argWidth,label(cfg)).nl();
- return iadr;
- }
-
- // ProjNodes following a multi (e.g. Call or New results),
- // get indent slightly and just print their index & node#
- if( n instanceof ProjNode proj ) {
- if( proj._type instanceof TypeMem ) return iadr; // Nothing for the hidden ones
- sb.fix(4," ").p(" ").fix(encWidth,"").p(" ").fix(opWidth,proj._label==null ? "---" : proj._label).p(" ").p(code.reg(n,fun)).nl();
- return iadr;
- }
-
- // ADDR ENCODING Op--- dst = src op src // Comment
- // 1234 abcdefgh ld4 RAX = [Rbase + off] // Comment
- sb.hex2(iadr).p(" ");
-
- // Encoding
- int fatEncoding = 0;
- if( code._encoding != null ) {
- int size = code._encoding._opLen[n._nid];
- if( code._asmLittle )
- for( int i=0; i<Math.min(size,dopz); i++ )
- sb.hex1(code._encoding._bits.buf()[iadr++]);
- else {
- iadr += Math.min(size,dopz);
- for( int i=0; i<Math.min(size,dopz); i++ )
- sb.hex1(code._encoding._bits.buf()[iadr-i-1]);
- }
- for( int i=size*2; i<encWidth; i++ )
- sb.p(" ");
- fatEncoding = size - (encWidth>>1); // Not-printed parts of encoding
- } else
- sb.fix(encWidth,"");
- sb.p(" ");
-
- // Op; generally "ld4" or "call"
- sb.fix(opWidth, n instanceof MachNode mach ? mach.op() : n.label()).p(" ");
-
- // General asm args
- String isMultiOp = null;
- if( n instanceof MachNode mach ) {
- int old = sb.len();
- mach.asm(code,sb);
- int len = sb.len();
- isMultiOp = isMultiOp(sb,old,len);
- sb.fix(argWidth-(len-old),""); // Pad out
-
- } else if( !(n._type instanceof TypeMem) ) {
- // Room for some inputs
- sb.fix(5, n._nid+":" );
- int off = 0;
- for( int i=0; i<n.nIns(); i++ ) {
- sb.fix(5, n.in(i) == null ? "___" : String.valueOf(n.in(i)._nid));
- off += 5;
- if( off >= argWidth ) break;
- }
- if( off < argWidth ) sb.fix(argWidth-off,"");
- }
- sb.p(" ");
-
- // Comment
- String comment = n.comment();
- if( comment!=null ) sb.p("// ").p(comment);
-
- sb.nl();
-
- // Printing more op bits than fit
- if( isMultiOp != null && code._encoding != null ) {
- // Multiple ops, template style, no RA, no scheduling. Print out
- // one-line-per-newline, with encoding bits up front.
- int size = code._encoding._opLen[n._nid];
- int off = Math.min(size,dopz);
- while( isMultiOp!=null ) {
- sb.hex2(iadr).p(" ");
- int len = Math.min(size-off,dopz);
- for( int i=0; i<len; i++ )
- sb.hex1(code._encoding._bits.buf()[iadr++]);
- off += len;
- for( int i=len; i<dopz; i++ ) sb.p(" ");
- sb.p(" ");
- int x = isMultiOp.indexOf('\n');
- if( x== -1 ) { // Last line
- sb.p(isMultiOp).nl();
- isMultiOp = null;
- } else {
- sb.p(isMultiOp.substring(0,x+1)); // Includes the newline
- isMultiOp = isMultiOp.substring(x+1);
- }
-
- }
-
- } else if( fatEncoding > 0 ) {
- // Extra bytes past the default encoding width, all put on a line by
- // themselves. X86 special for super long encodings
- sb.hex2(iadr).p(" ");
- for( int i=0; i<fatEncoding; i++ )
- sb.hex1(code._encoding._bits.buf()[iadr++]);
- sb.nl();
- }
-
-
- // MultiNodes are immediately followed by projection(s)
- if( !(n instanceof CFGNode) && n instanceof MultiNode ) {
- for( Node proj : n._outputs ) {
- if( proj instanceof ProjNode ) // it could also be an ante-dep
- doInst(iadr,sb,code,fun, cfgidx, proj,postAlloc,postEncode);
- }
- }
-
- return iadr;
+ @Override public boolean labelBlock(Node n) {
+ return !(n instanceof FunNode) && !(n instanceof IfNode) && !(n instanceof CallNode) &&
+ !(n instanceof CallEndNode) && !(n instanceof CProjNode && ir.input0(n) instanceof CallEndNode);
}
-
- private static String label( CFGNode bb ) {
- return (bb instanceof LoopNode ? "LOOP" : "L")+bb._nid;
+ @Override public boolean hidden(Node n) {
+ if( n instanceof PhiNode || n instanceof ProjNode )
+ if( n._type instanceof TypeMem || n._type instanceof TypeRPC ) return true;
+ if( postAlloc() && n instanceof CalleeSaveNode ) return true;
+ if( n instanceof MemMergeNode ) return true;
+ return n.getClass()==ConstantNode.class;
}
-
- private static String isMultiOp(SB sb, int old, int len) {
- for( int i=old; i<len; i++ )
- if( sb.at(i)=='\n' ) {
- String s = sb.subString(i+1,len);
- sb.setLen(i);
- return s;
- }
- return null;
+ @Override public boolean postAlloc() { return _code._phase.ordinal()>CodeGen.Phase.RegAlloc.ordinal(); }
+ @Override public boolean encoded() { return _enc!=null && _code._phase.ordinal()>=CodeGen.Phase.Encoding.ordinal(); }
+ @Override public int defaultSize() { return _code._mach==null ? 2 : _code._mach.defaultOpSize(); }
+ @Override public boolean littleEndian() { return _code._asmLittle; }
+ @Override public boolean prologue(Node n) { return ((FunNode)n)._frameAdjust!=0; }
+ @Override public byte[] bytes() { return encoded() ? _enc._bits.buf() : null; }
+ @Override public int offset(Node n) {
+ return encoded() && _enc._opStart!=null && n._nid<_enc._opStart.length ? _enc._opStart[n._nid] : -1;
+ }
+ @Override public int size(Node n) {
+ return encoded() && _enc._opLen!=null && n._nid<_enc._opLen.length ? _enc._opLen[n._nid]&255 : 0;
+ }
+ private static ArrayList<Data> entries(Iterable<Encoding.Relo> relos) {
+ var data=new ArrayList<Data>();
+ for( Encoding.Relo r : relos ) {
+ int align=1<<r._align;
+ int size=align;
+ if( r._t instanceof TypeTuple t ) size=align*t._types.length;
+ data.add(new Data(r._t,r._t.str(),r._align,size));
+ }
+ return data;
+ }
+ @Override public ArrayList<Pool> pools(int codeEnd) {
+ var pools=new ArrayList<Pool>();
+ if( !encoded() ) return pools;
+ int base=(codeEnd+15)&-16;
+ if( !_enc._bigCons.isEmpty() && base<_enc._bits.size() )
+ pools.add(new Pool("Constant Pool",_enc._bits.buf(),base,base,entries(_enc._bigCons.values())));
+ return pools;
}
-
}
diff --git a/chapter21/src/main/java/com/seaofnodes/simple/print/IRPrinter.java b/chapter21/src/main/java/com/seaofnodes/simple/print/IRPrinter.java
index 54063cf8..e4d719f4 100644
--- a/chapter21/src/main/java/com/seaofnodes/simple/print/IRPrinter.java
+++ b/chapter21/src/main/java/com/seaofnodes/simple/print/IRPrinter.java
@@ -1,517 +1,61 @@
package com.seaofnodes.simple.print;
-import com.seaofnodes.simple.Ary;
-import com.seaofnodes.simple.SB;
-import com.seaofnodes.simple.Utils;
-import com.seaofnodes.simple.codegen.CodeGen;
+import com.seaofnodes.print.IRAdapter;
import com.seaofnodes.simple.node.*;
-import com.seaofnodes.simple.type.TypeFunPtr;
import java.util.ArrayList;
-import java.util.BitSet;
-import java.util.HashMap;
-import java.util.Collections;
-import java.util.Comparator;
-import java.util.IdentityHashMap;
-
-public abstract class IRPrinter {
-
- // Print a node on 1 line, columnar aligned, as:
- // NNID NNAME DDEF DDEF [[ UUSE UUSE ]] TYPE
- // 1234 sssss 1234 1234 1234 1234 1234 1234 tttttt
- public static SB printLine( Node n, SB sb ) {
- if( n==null ) return sb;
- sb.p("%4d %-7.7s ".formatted(n._nid,n.label()));
- if( n.isDead() )
- return sb.p("DEAD\n");
- for( Node def : n._inputs )
- sb.p(def==null ? "____" : "%4d".formatted(def._nid))
- // Lazy Phi indicator
- .p(n instanceof MemMergeNode && def instanceof MemMergeNode ? "^" : " ");
- for( int i = n._inputs.size(); i<4; i++ )
- sb.p(" ");
- sb.p(" [[ ");
- for( Node use : n._outputs )
- sb.p(use==null ? "____ " : "%4d ".formatted(use._nid));
- int lim = 6 - Math.max(n._inputs.size(),4);
- for( int i = n._outputs.size(); i<lim; i++ )
- sb.p(" ");
- sb.p(" ]] ");
- if( n._type!= null ) sb.p(n._type.str());
- return sb.p("\n");
- }
-
-
- public static String prettyPrint(Node node, int depth) {
- return CodeGen.CODE._phase.ordinal() > CodeGen.Phase.Schedule.ordinal()
- ? _prettyPrintScheduled( node, depth )
- : _prettyPrint( node, depth );
- }
-
- // Another bulk pretty-printer. Makes more effort at basic-block grouping.
- private static String _prettyPrint( Node node, int depth ) {
- // First, a Breadth First Search at a fixed depth.
- BFS bfs = new BFS(node,depth);
- // Convert just that set to a post-order
- ArrayList<Node> rpos = new ArrayList<>();
- BitSet visit = new BitSet();
- for( int i=bfs._lim; i< bfs._bfs.size(); i++ )
- postOrd( bfs._bfs.get(i), null, rpos, visit, bfs._bs);
- // Reverse the post-order walk
- SB sb = new SB();
- boolean gap=false;
- for( int i=rpos.size()-1; i>=0; i-- ) {
- Node n = rpos.get(i);
- if( n instanceof CFGNode || n instanceof MultiNode ) {
- if( !gap ) sb.p("\n"); // Blank before multihead
- if( n instanceof FunNode fun )
- fun.sig().print(sb.p("--- ").p(fun._name==null ? "" : fun._name).p(" "),false).p("----------------------\n");
- printLine( n, sb ); // Print head
- while( --i >= 0 ) {
- Node t = rpos.get(i);
- if( !(t.in(0) instanceof MultiNode) ) { i++; break; }
- printLine( t, sb );
- }
- if( n instanceof ReturnNode ret ) {
- FunNode fun = ret.fun();
- sb.p("--- ");
- if( fun != null )
- fun.sig().print(sb.p(fun._name==null ? "" : fun._name).p(" "),false);
- sb.p("----------------------\n");
- }
- if( !(n instanceof CallNode) ) {
- sb.p("\n"); // Blank after multitail
- gap = true;
- }
- } else {
- printLine( n, sb );
- gap = false;
- }
- }
- return sb.toString();
- }
-
- private static void postOrd(Node n, Node prior, ArrayList<Node> rpos, BitSet visit, BitSet bfs) {
- if( !bfs.get(n._nid) )
- return; // Not in the BFS visit
- if( n instanceof FunNode && !(prior instanceof StartNode) )
- return; // Only visit Fun from Start
- if( visit.get(n._nid) ) return; // Already post-order walked
- visit.set(n._nid);
- // First walk the CFG, then everything
- if( n instanceof CFGNode ) {
- for( Node use : n._outputs )
- // Follow CFG, not across call/function borders, and not around backedges
- if( use instanceof CFGNode && !(n instanceof CallNode && use instanceof FunNode) &&
- use.nOuts() >= 1 && !(use._outputs.get(0) instanceof LoopNode) )
- postOrd(use, n, rpos,visit,bfs);
- for( Node use : n._outputs )
- // Follow CFG, not across call/function borders
- if( use instanceof CFGNode && !(n instanceof CallNode && use instanceof FunNode) )
- postOrd(use,n,rpos,visit,bfs);
- }
- // Follow all outputs
- for( Node use : n._outputs )
- if( use != null &&
- !(n instanceof CallNode && use instanceof FunNode) &&
- (n instanceof FunNode || !(use instanceof ParmNode)) )
- postOrd(use, n, rpos,visit,bfs);
- // Post-order
- rpos.add(n);
- }
-
- // Breadth-first search, broken out in a class to keep in more independent.
- // Maintains a root-set of Nodes at the limit (or past by 1 if MultiHead).
- public static class BFS {
- // A breadth first search, plus MultiHeads for any MultiTails
- public final ArrayList<Node> _bfs;
- public final BitSet _bs; // Visited members by node id
- public final int _depth; // Depth limit
- public final int _lim; // From here to _bfs._len can be roots for a reverse search
- public BFS( Node base, int d ) {
- _depth = d;
- _bfs = new ArrayList<>();
- _bs = new BitSet();
-
- add(base); // Prime the pump
- int idx=0, lim=1; // Limit is where depth counter changes
- while( idx < _bfs.size() ) { // Ran out of nodes below depth
- Node n = _bfs.get(idx++);
- for( Node def : n._inputs )
- if( def!=null && !_bs.get(def._nid) )
- add(def);
- if( idx==lim ) { // Depth counter changes at limit
- if( --d < 0 )
- break; // Ran out of depth
- lim = _bfs.size(); // New depth limit
- }
- }
- // Toss things past the limit except multi-heads
- while( idx < _bfs.size() ) {
- Node n = _bfs.get(idx);
- if( n instanceof MultiNode ) idx++;
- else del(idx);
- }
- // Root set is any node with no inputs in the visited set
- lim = _bfs.size();
- for( int i=_bfs.size()-1; i>=0; i-- )
- if( !any_visited(_bfs.get(i)) )
- swap( i,--lim);
- _lim = lim;
- }
- void swap( int x, int y ) {
- if( x==y ) return;
- Node tx = _bfs.get(x);
- Node ty = _bfs.get(y);
- _bfs.set(x,ty);
- _bfs.set(y,tx);
- }
- void add(Node n) {
- _bfs.add(n);
- _bs.set(n._nid);
- }
- void del(int idx) {
- _bs.clear(_bfs.get(idx)._nid);
- Utils.del(_bfs, idx);
- }
- boolean any_visited( Node n ) {
- for( Node def : n._inputs )
- if( def!=null && _bs.get(def._nid) )
- return true;
- return false;
- }
- }
-
- // Whole-program dump before scheduling, using printer-private RPO.
- public static String prettyPrint(CodeGen code) {
- SB sb = new SB();
- printLine(code._start,sb);
- ArrayList<Node> globals = new ArrayList<>();
- ArrayList<FunNode> funs = new ArrayList<>();
- for( Node n : code._start._outputs ) {
- if( n!=null && n.isConst() ) globals.add(n);
- if( n instanceof FunNode fun && !fun.isDead() ) funs.add(fun);
- }
- globals.sort(Comparator.comparingInt(n -> n._nid));
- for( Node n : globals ) printLine(n,sb);
- funs.sort(Comparator.comparingInt(n -> n._nid));
- for( FunNode fun : funs ) printFunction(fun,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(" "),false);
- sb.p("----------------------\n");
-
- IdentityHashMap<Node,Boolean> owned = new IdentityHashMap<>();
- collectFunction(fun,fun,owned);
- ArrayList<CFGNode> post = new ArrayList<>();
- controlPost(fun,owned,new IdentityHashMap<>(),post);
- Collections.reverse(post);
-
- IdentityHashMap<Node,Integer> blocks = new IdentityHashMap<>();
- ArrayList<ArrayList<Node>> body = new ArrayList<>();
- for( int i=0; i<post.size(); i++ ) {
- blocks.put(post.get(i),i);
- body.add(new ArrayList<>());
- }
- ArrayList<Node> nodes = new ArrayList<>(owned.keySet());
- nodes.sort(Comparator.comparingInt(n -> n._nid));
- for( Node n : nodes )
- if( !(n instanceof CFGNode) && !(n instanceof ConstantNode) )
- body.get(block(n,owned,blocks)).add(n);
-
- IdentityHashMap<Node,Boolean> emitted = new IdentityHashMap<>();
- for( int i=0; i<post.size(); i++ ) {
- CFGNode cfg = post.get(i);
- sb.nl();
- emitLocalDefs(cfg,owned,emitted,sb);
- printLine(cfg,sb);
- emitted.put(cfg,Boolean.TRUE);
- if( cfg instanceof MultiNode ) emitProjections(cfg,emitted,sb);
- // Loop-carried inputs belong in the body, not before their Phi.
- for( Node n : body.get(i) )
- if( n instanceof PhiNode ) {
- printLine(n,sb);
- emitted.put(n,Boolean.TRUE);
- }
- for( Node n : body.get(i) ) emit(n,owned,emitted,sb);
- }
- sb.p("--- ").p(fun._name==null ? "" : fun._name).p(" ----------------------\n");
- }
-
- private static void emit(Node n, IdentityHashMap<Node,Boolean> owned,
- IdentityHashMap<Node,Boolean> emitted, SB sb) {
- if( emitted.containsKey(n) || n instanceof CFGNode || n instanceof ConstantNode ||
- n instanceof PhiNode || !owned.containsKey(n) ) return;
- if( n instanceof ProjNode ) {
- emit(input0(n),owned,emitted,sb);
- return;
- }
- emitted.put(n,Boolean.TRUE);
- emitLocalDefs(n,owned,emitted,sb);
- printLine(n,sb);
- if( n instanceof MultiNode ) emitProjections(n,emitted,sb);
- }
-
- private static void emitProjections(Node n, IdentityHashMap<Node,Boolean> emitted, SB sb) {
- for( Node proj : projections(n) ) {
- printLine(proj,sb);
- emitted.put(proj,Boolean.TRUE);
- }
- }
-
- private static void emitLocalDefs(Node n, IdentityHashMap<Node,Boolean> owned,
- IdentityHashMap<Node,Boolean> emitted, SB sb) {
- for( Node def : n._inputs )
- if( def!=null ) emit(def,owned,emitted,sb);
- }
-
- // Diagnostic placement only: anchor data at its latest definition in CFG
- // RPO. Phi inputs do not move the Phi out of its owning header. This uses
- // local identity state, never compiler scheduling or dominator caches.
- private static int block(Node n, IdentityHashMap<Node,Boolean> owned,
- IdentityHashMap<Node,Integer> blocks) {
- Integer old = blocks.get(n);
- if( old!=null ) return old;
- if( !owned.containsKey(n) || n instanceof ConstantNode ) return 0;
- blocks.put(n,0); // Break incomplete data cycles in debugger snapshots.
- int b=0;
- if( input0(n) instanceof CFGNode || n instanceof ProjNode )
- b=block(input0(n),owned,blocks);
- else
- for( Node def : n._inputs )
- if( def!=null ) b=Math.max(b,block(def,owned,blocks));
- blocks.put(n,b);
- return b;
- }
-
- // Complete the CFG walk before inspecting data uses: a Phi's backedge
- // users must not pull the loop's closing Region ahead of its body.
- private static void controlPost(CFGNode n, IdentityHashMap<Node,Boolean> owned,
- IdentityHashMap<Node,Boolean> visit,
- ArrayList<CFGNode> post) {
- if( visit.put(n,Boolean.TRUE)!=null ) return;
- ArrayList<CFGNode> uses = new ArrayList<>();
- if( !(n instanceof ReturnNode) )
- for( Node use : n._outputs )
- if( use instanceof CFGNode cfg && owned.containsKey(cfg) &&
- !(cfg instanceof FunNode) &&
- ((cfg instanceof RegionNode && cfg._inputs.find(n)>0) || input0(cfg)==n) )
- uses.add(cfg);
- uses.sort(Comparator.comparingInt(use -> use._nid));
- for( CFGNode use : uses ) controlPost(use,owned,visit,post);
- post.add(n);
- }
-
- /** Collect one function without following call-graph linkage. */
- private static void collectFunction(Node n, FunNode owner,
- IdentityHashMap<Node,Boolean> visit) {
- if( n==null || n.isDead() || visit.containsKey(n) ) return;
- if( n instanceof FunNode fun && fun!=owner ) return;
- if( n instanceof ParmNode && input0(n)!=owner ) return;
- if( n instanceof StopNode || n instanceof StartNode ) return;
- if( n instanceof CallEndNode && input0(n) instanceof CallNode call &&
- !visit.containsKey(call) ) return;
- visit.put(n,Boolean.TRUE);
- // A Return's users are linkage hooks, not continuation in this function.
- if( !(n instanceof ReturnNode) )
- for( Node use : n._outputs ) collectFunction(use,owner,visit);
- }
-
- private static ArrayList<Node> projections(Node multi) {
- ArrayList<Node> ps = new ArrayList<>();
- for( Node use : multi._outputs )
- if( use instanceof ProjNode && !use.isDead() && input0(use)==multi ) ps.add(use);
- ps.sort(Comparator.comparingInt(IRPrinter::sortOrder));
- return ps;
- }
-
- // 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);
- }
-
+import com.seaofnodes.simple.SB;
+import com.seaofnodes.simple.codegen.CodeGen;
- private static int sortOrder(Node n) {
- if( n instanceof ProjNode proj ) return proj._idx;
- if( n instanceof CProjNode proj ) return proj._idx;
+/** This chapter's read-only IR facts and the familiar debugger entry points. */
+public final class IRPrinter extends IRAdapter<Node> {
+ private static final com.seaofnodes.print.IRPrinter<Node> PRINT =
+ new com.seaofnodes.print.IRPrinter<>(new IRPrinter());
+ @Override public boolean global(Node n) { return n.isConst(); }
+ @Override public String type(Node n) { return n._type==null ? "" : n._type.str(); }
+ @Override public String inputMark(Node n, Node def) { return n instanceof MemMergeNode && def instanceof MemMergeNode ? "^" : " "; }
+ @Override public Kind kind(Node n) {
+ if( n instanceof StartNode ) return Kind.START;
+ if( n instanceof StopNode ) return Kind.STOP;
+ if( n instanceof FunNode ) return Kind.FUN;
+ if( n instanceof LoopNode ) return Kind.LOOP;
+ if( n instanceof RegionNode ) return Kind.REGION;
+ if( n instanceof ParmNode ) return Kind.PARM;
+ if( n instanceof PhiNode ) return Kind.PHI;
+ if( n instanceof CallEndNode ) return Kind.CALL_END;
+ if( n instanceof CallNode ) return Kind.CALL;
+ if( n instanceof ReturnNode ) return Kind.RETURN;
+ if( n instanceof ConstantNode ) return Kind.CONSTANT;
+ if( n instanceof CProjNode ) return Kind.CPROJ;
+ if( n instanceof ProjNode ) return n instanceof CFGNode ? Kind.CPROJ : Kind.PROJ;
+ if( n instanceof CFGNode ) return Kind.CTRL;
+ if( n instanceof MultiNode ) return Kind.MULTI;
+ return Kind.DATA;
+ }
+ @Override public int index(Node n) {
+ if( n instanceof ProjNode p ) return p._idx;
+ if( n instanceof CProjNode p ) return p._idx;
return n._nid;
}
-
- public static String _prettyPrint( CodeGen code ) {
- SB sb = new SB();
- // Print the Start "block"
- printLine(code._start,sb);
- for( Node n : code._start._outputs )
- printLine(n,sb);
- sb.nl();
-
- // Skip start, stop
- for( int i=1; i<code._cfg._len-1; i++ ) {
- CFGNode blk = code._cfg.at(i);
- if( blk.blockHead() && (!(blk instanceof CProjNode) || (blk.cfg0() instanceof IfNode )) ) {
- if( blk instanceof FunNode fun )
- sb.p("--- ").p(fun.label()).p(" ---------------------------").nl();
- // Print block header
- sb.p("%-13.13s".formatted(label(blk)+":"));
- sb.p( " ".repeat(4) ).p(" [[ ");
- if( blk instanceof RegionNode )
- for( int j=1; j<blk.nIns(); j++ )
- label(sb,blk.cfg(j));
- else
- label(sb,blk.cfg(0));
- sb.p(" ]] \n");
- }
- printLine(blk,sb);
- if( blk instanceof ReturnNode ret )
- sb.p("--- ").p(ret.fun().label()).p(" ---------------------------").nl();
-
- // Block contents
- for( Node n : blk._outputs ) {
- if( n instanceof CFGNode cfg ) continue;
- printLine(n,sb);
- if( !(n instanceof CFGNode) && n instanceof MultiNode )
- for( Node use : n._outputs )
- if( use instanceof ProjNode )
- printLine(use,sb);
- }
- }
-
- printLine(code._stop,sb);
- return sb.toString();
- }
-
- // Diagnostic block ordering from raw control edges. Do not call idepth():
- // it fills compiler caches (and can walk lazy dominator accessors).
- private static int _idepth(CFGNode cfg, HashMap<Integer,Integer> depths) {
- if( cfg == null || cfg instanceof StartNode || cfg instanceof FunNode ) return cfg instanceof FunNode ? 1 : 0;
- Integer old = depths.get(cfg._nid);
- if( old != null ) return old;
- depths.put(cfg._nid,0); // Break cycles in partially constructed graphs.
- int d = 0;
- if( cfg instanceof LoopNode ) {
- d = _idepth((CFGNode)cfg.in(1),depths)+1;
- } else if( cfg instanceof RegionNode || cfg instanceof StopNode ) {
- for( Node n : cfg._inputs )
- if( n instanceof CFGNode pred ) d = Math.max(d,_idepth(pred,depths)+1);
- } else if( cfg.in(0) instanceof CFGNode pred ) {
- d = _idepth(pred,depths)+1;
- }
- depths.put(cfg._nid,d);
- return d;
- }
-
- // Bulk pretty printer, knowing scheduling information is available
- private static String _prettyPrintScheduled( Node node, int depth ) {
- // Backwards DFS walk to depth.
- HashMap<Integer,Integer> ds = new HashMap<>();
- Ary<Node> ns = new Ary<>(Node.class);
- _walk(ds,ns,node,depth);
- // Remove data projections, these are force-printed behind their multinode head
- for( int i=0; i<ns.size(); i++ ) {
- if( ns.get(i) instanceof ProjNode proj && !(proj.in(0) instanceof CFGNode) ) {
- ns.del(i--);
- ds.remove(proj._nid);
- }
- }
- // Print by block with least diagnostic depth
- HashMap<Integer,Integer> depths = new HashMap<>();
- SB sb = new SB();
- Ary<Node> bns = new Ary<>(Node.class);
- while( !ds.isEmpty() ) {
- CFGNode blk = null;
- for( Node n : ns ) {
- CFGNode cfg = n instanceof CFGNode cfg0 && cfg0.blockHead() ? cfg0 : n.cfg0();
- if( blk==null || _idepth(cfg,depths) < _idepth(blk,depths) )
- blk = cfg;
- }
- Integer d = ds.remove(blk._nid);
- ns.del(ns.find(blk));
-
- // Print block header
- sb.p("%-13.13s".formatted(label(blk)+":"));
- sb.p( " ".repeat(4) ).p(" [[ ");
- if( blk instanceof StartNode ) ;
- else if( blk instanceof RegionNode || blk instanceof StopNode )
- for( int i=(blk instanceof StopNode ? 3 : 1); i<blk.nIns(); i++ )
- label(sb,blk.cfg(i));
- else
- label(sb,blk.cfg(0));
- sb.p(" ]] \n");
- printLine(blk,sb);
-
- // Collect block contents that are in the depth limit
- bns.clear();
- int xd = Integer.MAX_VALUE;
- for( Node use : blk._outputs ) {
- Integer i = ds.get(use._nid);
- if( i!=null && !(use instanceof CFGNode cfg && cfg.blockHead()) ) {
- if( bns.find(use)==-1 )
- bns.add(use);
- xd = Math.min(xd,i);
- }
- }
- // Print Phis up front, if any
- for( int i=0; i<bns.size(); i++ )
- if( bns.get(i) instanceof PhiNode phi )
- printLine( phi, sb,bns,i--,ds,ns);
-
- // Print block contents in depth order, bumping depth until whole block printed
- for( ; !bns.isEmpty(); xd++ )
- for( int i=0; i<bns.size(); i++ ) {
- Node n = bns.get(i);
- if( ds.get(n._nid)==xd ) {
- printLine( n, sb, bns, i--, ds,ns );
- if( n instanceof MultiNode && !(n instanceof CFGNode) ) {
- for( Node use : n._outputs ) {
- if( use instanceof ProjNode )
- printLine(use,sb,bns,bns.indexOf(use),ds,ns);
- }
- }
- }
- }
- sb.p("\n");
- }
- return sb.toString();
+ @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();
}
- private static void _walk( HashMap<Integer,Integer> ds, Ary<Node> ns, Node node, int d ) {
- Integer nd = ds.get(node._nid);
- if( nd!=null && d <= nd ) return; // Been there, done that
- Integer old = ds.put(node._nid,d) ;
- if( old == null )
- ns.add(node);
- if( d == 0 ) return; // Depth cutoff
- for( Node def : node._inputs )
- if( def != null &&
- !(node instanceof LoopNode loop && loop.back()==def) &&
- // Don't walk into or out of functions
- !(node instanceof CallEndNode && def instanceof ReturnNode) &&
- !(node instanceof FunNode && def instanceof CallNode) &&
- !(node instanceof ParmNode && !(def instanceof FunNode))
- )
- _walk(ds,ns,def,d-1);
- }
+ 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)); }
- static String label( CFGNode blk ) {
- if( blk instanceof StartNode ) return "START";
- return (blk instanceof LoopNode ? "LOOP" : "L")+blk._nid;
- }
- static void label( SB sb, CFGNode blk ) {
- if( !blk.blockHead() ) blk = blk.cfg(0);
- sb.p( "%-9.9s ".formatted( label( blk ) ) );
- }
- static void printLine( Node n, SB sb, Ary<Node> bns, int i, HashMap<Integer,Integer> ds, Ary<Node> ns ) {
- printLine( n, sb );
- if( i != -1 ) bns.del(i);
- ds.remove(n._nid);
- int idx = ns.find(n);
- if( idx!=-1 ) ns.del(idx);
+ public static String prettyPrint(CodeGen code) {
+ var units=new ArrayList<com.seaofnodes.print.IRPrinter.Unit<Node>>();
+ var funs=new ArrayList<Node>();
+ for( Node n : code._start._outputs ) if( n instanceof FunNode ) funs.add(n);
+ units.add(new com.seaofnodes.print.IRPrinter.Unit<>(null,null,null,funs));
+ return PRINT.program(code._start,code._stop,units);
+ }
+ public static String _prettyPrint(CodeGen code) {
+ if( code._cfg==null ) return prettyPrint(code);
+ var blocks=new ArrayList<Node>();
+ for( Node n : code._cfg ) blocks.add(n);
+ return PRINT.scheduled(blocks);
}
-
}
diff --git a/chapter21/src/main/java/com/seaofnodes/simple/print/SimpleGraphAdapter.java b/chapter21/src/main/java/com/seaofnodes/simple/print/SimpleGraphAdapter.java
index a0f1ba74..b9aabba3 100644
--- a/chapter21/src/main/java/com/seaofnodes/simple/print/SimpleGraphAdapter.java
+++ b/chapter21/src/main/java/com/seaofnodes/simple/print/SimpleGraphAdapter.java
@@ -1,45 +1,25 @@
package com.seaofnodes.simple.print;
import com.seaofnodes.graph.GraphAdapter;
-import com.seaofnodes.graph.GraphSnapshot;
import com.seaofnodes.graph.GraphSnapshot.*;
import com.seaofnodes.simple.node.*;
import com.seaofnodes.simple.node.Node;
import com.seaofnodes.simple.type.TypeMem;
-import java.util.ArrayList;
/** Chapter 21's view of the IR; browser, transport and layout are shared. */
public class SimpleGraphAdapter extends GraphAdapter<Node> {
- @Override protected boolean dead(Node n) { return n.isDead(); }
- @Override protected int id(Node n) { return n._nid; }
- @Override protected int nIns(Node n) { return n.nIns(); }
- @Override protected Node in(Node n, int idx) { return n.in(idx); }
- @Override protected int nOuts(Node n) { return n.nOuts(); }
- @Override protected Node out(Node n, int idx) { return n.out(idx); }
- @Override protected int nDeps(Node n) { return n.nDeps(); }
- @Override protected Node dep(Node n, int idx) { return n.dep(idx); }
- private ArrayList<Edge> edges(Node n) {
- var edges = new ArrayList<Edge>();
- for( int i = 0; i < n.nIns(); i++ ) {
- String name = n instanceof ScopeNode scope && i < scope._vars.size()
+ @Override protected String edgeName(Node n, int i) {
+ return n instanceof ScopeNode scope && i < scope._vars.size()
? scope._vars.get(i)._name : null;
- int jump = n instanceof CallEndNode && i>0 && n.in(i) instanceof ReturnNode ret
- ? ref(ret.fun()) : 0;
- edges.add(new Edge(i, ref(n.in(i)), role(n, i), name, jump));
- }
- return edges;
}
-
- @Override protected GraphSnapshot.Node desc(Node n) {
- Projection proj = n instanceof ProjNode p ? new Projection(ref(n.in(0)), p._idx)
- : n instanceof CProjNode p ? new Projection(ref(n.in(0)), p._idx) : null;
- String label = n.label();
- return new GraphSnapshot.Node(n._nid, label == null ? n.getClass().getSimpleName() : label,
- n._type == null ? null : n._type.toString(), kind(n), edges(n), proj, folding(n));
+ @Override protected int edgeJump(Node n, int i) {
+ return n instanceof CallEndNode && i>0 && n.in(i) instanceof ReturnNode ret
+ ? ref(ret.fun()) : 0;
}
+ @Override protected int projectionIndex(Node n) { return n instanceof ProjNode p ? p._idx : n instanceof CProjNode p ? p._idx : -1; }
- private boolean folding(Node n) {
+ @Override protected boolean folding(Node n) {
if( n instanceof FunNode fun ) return fun.folding();
if( n instanceof ReturnNode ret ) return ret.fun().folding();
if( n instanceof CallEndNode cend ) return cend.folding();
@@ -49,7 +29,7 @@ public class SimpleGraphAdapter extends GraphAdapter<Node> {
return false;
}
- private Kind kind(Node n) {
+ @Override protected Kind kind(Node n) {
if( n instanceof StopNode ) return Kind.STOP;
if( n instanceof ScopeNode ) return Kind.SCOPE;
if( n instanceof FunNode ) return Kind.FUN;
@@ -60,7 +40,7 @@ public class SimpleGraphAdapter extends GraphAdapter<Node> {
return n instanceof CFGNode ? Kind.CTRL : isMem(n) ? Kind.MEM : Kind.DATA;
}
- private Role role(Node n, int i) {
+ @Override protected Role role(Node n, int i) {
if( n instanceof ScopeNode || n instanceof ConstantNode || n instanceof CtrlNode || n instanceof XCtrlNode ) return Role.ASSOC;
if( n instanceof PhiNode ) return i == 0 ? Role.ASSOC : isMem(n) ? Role.MEM : Role.DATA;
if( n instanceof ProjNode || n instanceof CProjNode )
diff --git a/chapter22/Makefile b/chapter22/Makefile
index f2c05809..9725bc7d 100644
--- a/chapter22/Makefile
+++ b/chapter22/Makefile
@@ -65,6 +65,7 @@ main_javas := $(wildcard $(SRC)/$(SIMPLE)/*java $(SRC)/$(SIMPLE)/*/*java $(SRC
test_javas := $(wildcard $(TST)/$(SIMPLE)/*java $(TST)/$(SIMPLE)/*/*java)
main_classes := $(patsubst $(SRC)/%java,$(CLZDIR)/main/%class,$(main_javas))
include $(firstword $(wildcard ../graph/graph.mk graph/graph.mk))
+include $(firstword $(wildcard ../print/print.mk print/print.mk))
test_classes := $(patsubst $(TST)/%java,$(CLZDIR)/test/%class,$(test_javas))
test_cp := $(patsubst $(TST)/$(SIMPLE)/%.java,com.seaofnodes.simple.%,$(wildcard $(TST)/$(SIMPLE)/*Test.java)) com.seaofnodes.simple.codegen.X86EncodingTest
classes = $(main_classes) $(test_classes)
diff --git a/chapter22/pom.xml b/chapter22/pom.xml
index d06114f5..d54196f7 100644
--- a/chapter22/pom.xml
+++ b/chapter22/pom.xml
@@ -13,5 +13,6 @@
<name>Chapter 22</name>
<properties>
<simple.graph.directory>${project.basedir}/../graph</simple.graph.directory>
+ <simple.print.directory>${project.basedir}/../print</simple.print.directory>
</properties>
</project>
diff --git a/chapter22/src/main/java/com/seaofnodes/simple/codegen/CodeGen.java b/chapter22/src/main/java/com/seaofnodes/simple/codegen/CodeGen.java
index 7c884b49..8a3d6322 100644
--- a/chapter22/src/main/java/com/seaofnodes/simple/codegen/CodeGen.java
+++ b/chapter22/src/main/java/com/seaofnodes/simple/codegen/CodeGen.java
@@ -450,7 +450,7 @@ public class CodeGen {
@Override public String toString() {
return _phase.ordinal() > Phase.Schedule.ordinal()
? IRPrinter._prettyPrint( this )
- : _stop.p(9999);
+ : IRPrinter.prettyPrint(this);
}
// Debugging helper
diff --git a/chapter22/src/main/java/com/seaofnodes/simple/node/AddFNode.java b/chapter22/src/main/java/com/seaofnodes/simple/node/AddFNode.java
index ba5815da..fd713156 100644
--- a/chapter22/src/main/java/com/seaofnodes/simple/node/AddFNode.java
+++ b/chapter22/src/main/java/com/seaofnodes/simple/node/AddFNode.java
@@ -1,21 +1,16 @@
package com.seaofnodes.simple.node;
+
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeFloat;
-import java.util.BitSet;
public class AddFNode extends Node {
public AddFNode(Node lhs, Node rhs) { super(null, lhs, rhs); }
@Override public String label() { return "AddF"; }
- @Override
- public StringBuilder _print1(StringBuilder sb, BitSet visited) {
- in(1)._print0(sb.append("("), visited);
- in(2)._print0(sb.append("+"), visited);
- return sb.append(")");
- }
+ @Override protected String format() { return "(%1+%2)"; }
@Override
public Type compute() {
diff --git a/chapter22/src/main/java/com/seaofnodes/simple/node/ArithNode.java b/chapter22/src/main/java/com/seaofnodes/simple/node/ArithNode.java
index f9fc2870..e94ccbc6 100644
--- a/chapter22/src/main/java/com/seaofnodes/simple/node/ArithNode.java
+++ b/chapter22/src/main/java/com/seaofnodes/simple/node/ArithNode.java
@@ -1,10 +1,11 @@
package com.seaofnodes.simple.node;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.Parser;
import com.seaofnodes.simple.Utils;
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeInteger;
-import java.util.BitSet;
public abstract class ArithNode extends Node {
// Source location for late reported errors
@@ -13,11 +14,8 @@ public abstract class ArithNode extends Node {
public ArithNode( Parser.Lexer loc, Node lhs, Node rhs) { super(null, lhs, rhs); _loc = loc; }
abstract String op();
- @Override
- public StringBuilder _print1(StringBuilder sb, BitSet visited) {
- in(1)._print0(sb.append("("), visited);
- in(2)._print0(sb.append(op()), visited);
- return sb.append(")");
+ @Override protected ExprPrinter<Node> _print1(ExprPrinter<Node> p) {
+ return p.open().n(in(1)).p(op()).n(in(2)).close();
}
abstract long doOp(long x, long y);
diff --git a/chapter22/src/main/java/com/seaofnodes/simple/node/BoolNode.java b/chapter22/src/main/java/com/seaofnodes/simple/node/BoolNode.java
index 80e8cf46..21ac59d3 100644
--- a/chapter22/src/main/java/com/seaofnodes/simple/node/BoolNode.java
+++ b/chapter22/src/main/java/com/seaofnodes/simple/node/BoolNode.java
@@ -1,9 +1,10 @@
package com.seaofnodes.simple.node;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.Parser;
import com.seaofnodes.simple.Utils;
import com.seaofnodes.simple.type.*;
-import java.util.BitSet;
import static com.seaofnodes.simple.type.TypeInteger.*;
abstract public class BoolNode extends Node {
@@ -17,11 +18,8 @@ abstract public class BoolNode extends Node {
@Override
public String label() { return getClass().getSimpleName(); }
- @Override
- public StringBuilder _print1(StringBuilder sb, BitSet visited) {
- in(1)._print0(sb.append("("), visited);
- in(2)._print0(sb.append(op()), visited);
- return sb.append(")");
+ @Override protected ExprPrinter<Node> _print1(ExprPrinter<Node> p) {
+ return p.open().n(in(1)).p(op()).n(in(2)).close();
}
@Override
diff --git a/chapter22/src/main/java/com/seaofnodes/simple/node/CProjNode.java b/chapter22/src/main/java/com/seaofnodes/simple/node/CProjNode.java
index 94770f16..4d3d8d0d 100644
--- a/chapter22/src/main/java/com/seaofnodes/simple/node/CProjNode.java
+++ b/chapter22/src/main/java/com/seaofnodes/simple/node/CProjNode.java
@@ -1,11 +1,12 @@
package com.seaofnodes.simple.node;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.Parser;
import com.seaofnodes.simple.Utils;
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeMem;
import com.seaofnodes.simple.type.TypeTuple;
-import java.util.BitSet;
public class CProjNode extends CFGNode {
@@ -24,7 +25,7 @@ public class CProjNode extends CFGNode {
@Override public String label() { return _label; }
- @Override public StringBuilder _print1(StringBuilder sb, BitSet visited) { return sb.append(_label); }
+ @Override protected ExprPrinter<Node> _print1(ExprPrinter<Node> p) { return p.p(_label); }
@Override public boolean blockHead() { return true; }
diff --git a/chapter22/src/main/java/com/seaofnodes/simple/node/CallEndNode.java b/chapter22/src/main/java/com/seaofnodes/simple/node/CallEndNode.java
index f37da4f3..264a506e 100644
--- a/chapter22/src/main/java/com/seaofnodes/simple/node/CallEndNode.java
+++ b/chapter22/src/main/java/com/seaofnodes/simple/node/CallEndNode.java
@@ -1,9 +1,10 @@
package com.seaofnodes.simple.node;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.*;
import com.seaofnodes.simple.codegen.*;
import com.seaofnodes.simple.type.*;
-import java.util.BitSet;
/**
* CallEnd
@@ -29,13 +30,12 @@ public class CallEndNode extends CFGNode implements MultiNode {
}
@Override
- public StringBuilder _print1(StringBuilder sb, BitSet visited) {
- sb.append("cend( ");
- sb.append( in(0) instanceof CallNode ? "Call, " : "----, ");
+ protected ExprPrinter<Node> _print1(ExprPrinter<Node> p) {
+ p.p("cend( ");
+ p.p( in(0) instanceof CallNode ? "Call, " : "----, ");
for( int i=1; i<nIns()-1; i++ )
- in(i)._print0(sb,visited).append(",");
- sb.setLength(sb.length()-1);
- return sb.append(")");
+ p.n(in(i)).p(",");
+ return p.unchar(',').unchar(' ').close();
}
@Override
diff --git a/chapter22/src/main/java/com/seaofnodes/simple/node/CallNode.java b/chapter22/src/main/java/com/seaofnodes/simple/node/CallNode.java
index 94935e7c..8871e6a7 100644
--- a/chapter22/src/main/java/com/seaofnodes/simple/node/CallNode.java
+++ b/chapter22/src/main/java/com/seaofnodes/simple/node/CallNode.java
@@ -1,12 +1,13 @@
package com.seaofnodes.simple.node;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.codegen.CodeGen;
import com.seaofnodes.simple.IterPeeps;
import com.seaofnodes.simple.Parser;
import com.seaofnodes.simple.Utils;
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeFunPtr;
-import java.util.BitSet;
/**
* Call
@@ -21,15 +22,14 @@ public class CallNode extends CFGNode {
@Override public String label() { return "Call"; }
- @Override public StringBuilder _print1(StringBuilder sb, BitSet visited) {
+ @Override protected ExprPrinter<Node> _print1(ExprPrinter<Node> p) {
String fname = name();
- if( fname == null ) fptr()._print0(sb,visited);
- else sb.append(fname);
- sb.append("( ");
+ if( fname == null ) p.n(fptr());
+ else p.p(fname);
+ p.p("( ");
for( int i=2; i<nIns()-1; i++ )
- in(i)._print0(sb,visited).append(",");
- sb.setLength(sb.length()-1);
- return sb.append(")");
+ p.n(in(i)).p(",");
+ return p.unchar(',').unchar(' ').close();
}
public String name() {
if( fptr()._type instanceof TypeFunPtr tfp && tfp.isConstant() && tfp.notNull() ) {
diff --git a/chapter22/src/main/java/com/seaofnodes/simple/node/CastNode.java b/chapter22/src/main/java/com/seaofnodes/simple/node/CastNode.java
index beec825c..8ae7b327 100644
--- a/chapter22/src/main/java/com/seaofnodes/simple/node/CastNode.java
+++ b/chapter22/src/main/java/com/seaofnodes/simple/node/CastNode.java
@@ -1,12 +1,13 @@
package com.seaofnodes.simple.node;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.Parser;
import com.seaofnodes.simple.Utils;
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeInteger;
import com.seaofnodes.simple.type.TypeMemPtr;
-import java.util.BitSet;
// Upcast (join) the input to a t. Used after guard test to lift an input.
// Can also be used to make a type-assertion if ctrl is null.
@@ -26,14 +27,11 @@ public class CastNode extends Node {
@Override public String label() { return "("+_t.str()+")"; }
- @Override
- public String uniqueName() { return "Cast_" + _nid; }
@Override public boolean isConst() { return true; }
- @Override
- public StringBuilder _print1(StringBuilder sb, BitSet visited) {
- return in(1)._print0(sb.append(label()), visited);
+ @Override protected ExprPrinter<Node> _print1(ExprPrinter<Node> p) {
+ return p.p(label()).n(in(1));
}
@Override
diff --git a/chapter22/src/main/java/com/seaofnodes/simple/node/ConstantNode.java b/chapter22/src/main/java/com/seaofnodes/simple/node/ConstantNode.java
index 60aa40c4..d3ac24a7 100644
--- a/chapter22/src/main/java/com/seaofnodes/simple/node/ConstantNode.java
+++ b/chapter22/src/main/java/com/seaofnodes/simple/node/ConstantNode.java
@@ -1,11 +1,12 @@
package com.seaofnodes.simple.node;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.codegen.CodeGen;
import com.seaofnodes.simple.Parser;
import com.seaofnodes.simple.SB;
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeFunPtr;
-import java.util.BitSet;
/**
* A Constant node represents a constant value. At present, the only constants
@@ -39,18 +40,20 @@ public class ConstantNode extends Node {
return new ConstantNode(type);
}
- @Override public String label() { return "#"+_con; }
- @Override
- public String uniqueName() { return "Con_" + _nid; }
+ @Override protected String repeatName() {
+ return _con==null || _con.toString().length()<=32 ? null : uniqueName();
+ }
+
+ @Override public String label() { return "Con"; }
@Override
- public StringBuilder _print1(StringBuilder sb, BitSet visited) {
+ protected ExprPrinter<Node> _print1(ExprPrinter<Node> p) {
if( _con instanceof TypeFunPtr tfp && tfp.isConstant() && tfp.notNull() ) {
FunNode fun = CodeGen.CODE.link(tfp);
if( fun!=null && fun._name != null )
- return sb.append("{ ").append(fun._name).append("}");
+ return p.p("{ ").p(fun._name).p("}");
}
- return sb.append(_con==null ? "---" : _con.print(new SB()));
+ return p.p(_con==null ? "---" : _con.print(new SB()));
}
@Override public boolean isConst() { return true; }
diff --git a/chapter22/src/main/java/com/seaofnodes/simple/node/CtrlNode.java b/chapter22/src/main/java/com/seaofnodes/simple/node/CtrlNode.java
index eda7d684..cf630ad4 100644
--- a/chapter22/src/main/java/com/seaofnodes/simple/node/CtrlNode.java
+++ b/chapter22/src/main/java/com/seaofnodes/simple/node/CtrlNode.java
@@ -1,14 +1,15 @@
package com.seaofnodes.simple.node;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.codegen.CodeGen;
import com.seaofnodes.simple.Parser;
import com.seaofnodes.simple.type.Type;
-import java.util.BitSet;
public class CtrlNode extends CFGNode {
public CtrlNode() { super(CodeGen.CODE._start); }
@Override public String label() { return "Ctrl"; }
- @Override public StringBuilder _print1(StringBuilder sb, BitSet visited) { return sb.append("Cctrl"); }
+ @Override protected ExprPrinter<Node> _print1(ExprPrinter<Node> p) { return p.p("Cctrl"); }
@Override public boolean isConst() { return true; }
@Override public Type compute() { return Type.CONTROL; }
@Override public Node idealize() { return null; }
diff --git a/chapter22/src/main/java/com/seaofnodes/simple/node/DivFNode.java b/chapter22/src/main/java/com/seaofnodes/simple/node/DivFNode.java
index 2180ab46..149499f9 100644
--- a/chapter22/src/main/java/com/seaofnodes/simple/node/DivFNode.java
+++ b/chapter22/src/main/java/com/seaofnodes/simple/node/DivFNode.java
@@ -1,21 +1,16 @@
package com.seaofnodes.simple.node;
+
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeFloat;
-import java.util.BitSet;
public class DivFNode extends Node {
public DivFNode(Node lhs, Node rhs) { super(null, lhs, rhs); }
@Override public String label() { return "DivF"; }
- @Override
- public StringBuilder _print1(StringBuilder sb, BitSet visited) {
- in(1)._print0(sb.append("("), visited);
- in(2)._print0(sb.append("/"), visited);
- return sb.append(")");
- }
+ @Override protected String format() { return "(%1/%2)"; }
@Override
public Type compute() {
diff --git a/chapter22/src/main/java/com/seaofnodes/simple/node/ExternNode.java b/chapter22/src/main/java/com/seaofnodes/simple/node/ExternNode.java
index a993d9de..093cc2cb 100644
--- a/chapter22/src/main/java/com/seaofnodes/simple/node/ExternNode.java
+++ b/chapter22/src/main/java/com/seaofnodes/simple/node/ExternNode.java
@@ -16,7 +16,6 @@ public class ExternNode extends ConstantNode {
public ExternNode(Type t, String ex) { super(t); _extern = ex; }
@Override public String label() { return "#"+_con+":"+_extern; }
- @Override public String uniqueName() { return "Extern_" + _nid; }
@Override public boolean eq(Node n) { return this==n; }
}
diff --git a/chapter22/src/main/java/com/seaofnodes/simple/node/FRefNode.java b/chapter22/src/main/java/com/seaofnodes/simple/node/FRefNode.java
index 6093b8a6..e7333c23 100644
--- a/chapter22/src/main/java/com/seaofnodes/simple/node/FRefNode.java
+++ b/chapter22/src/main/java/com/seaofnodes/simple/node/FRefNode.java
@@ -1,9 +1,10 @@
package com.seaofnodes.simple.node;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.Parser;
import com.seaofnodes.simple.Var;
import com.seaofnodes.simple.type.Type;
-import java.util.BitSet;
/**
* A Forward Reference. Its any final constant, including functions. When
@@ -17,10 +18,9 @@ public class FRefNode extends ConstantNode {
@Override public String label() { return "FRef"+_n; }
- @Override public String uniqueName() { return "FRef_" + _nid; }
- @Override public StringBuilder _print1(StringBuilder sb, BitSet visited) {
- return sb.append("FRef_").append(_n);
+ @Override protected ExprPrinter<Node> _print1(ExprPrinter<Node> p) {
+ return p.p("FRef_").p(_n);
}
@Override public Node idealize() {
diff --git a/chapter22/src/main/java/com/seaofnodes/simple/node/FunPtrNode.java b/chapter22/src/main/java/com/seaofnodes/simple/node/FunPtrNode.java
index 7f32698e..43242c32 100644
--- a/chapter22/src/main/java/com/seaofnodes/simple/node/FunPtrNode.java
+++ b/chapter22/src/main/java/com/seaofnodes/simple/node/FunPtrNode.java
@@ -9,5 +9,4 @@ public class FunPtrNode extends ConstantNode {
addDef(ret);
}
public ReturnNode ret() { return (ReturnNode)in(1); }
- @Override public String uniqueName() { return "FunPtr_"+_nid; }
}
diff --git a/chapter22/src/main/java/com/seaofnodes/simple/node/IfNode.java b/chapter22/src/main/java/com/seaofnodes/simple/node/IfNode.java
index 5d90449e..81fbe170 100644
--- a/chapter22/src/main/java/com/seaofnodes/simple/node/IfNode.java
+++ b/chapter22/src/main/java/com/seaofnodes/simple/node/IfNode.java
@@ -1,9 +1,10 @@
package com.seaofnodes.simple.node;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.Utils;
import com.seaofnodes.simple.codegen.CodeGen;
import com.seaofnodes.simple.type.*;
-import java.util.BitSet;
public class IfNode extends CFGNode implements MultiNode {
@@ -17,11 +18,11 @@ public class IfNode extends CFGNode implements MultiNode {
public String label() { return "If"; }
@Override
- public StringBuilder _print1(StringBuilder sb, BitSet visited) {
- sb.append("if( ");
- if( in(1)==null ) sb.append("never");
- else in(1)._print0(sb, visited);
- return sb.append(" )");
+ protected ExprPrinter<Node> _print1(ExprPrinter<Node> p) {
+ p.p("if( ");
+ if( in(1)==null ) p.p("never");
+ else p.n(in(1));
+ return p.p(" )");
}
public Node ctrl() { return in(0); }
diff --git a/chapter22/src/main/java/com/seaofnodes/simple/node/LoadNode.java b/chapter22/src/main/java/com/seaofnodes/simple/node/LoadNode.java
index 0432bcbc..f668d2c3 100644
--- a/chapter22/src/main/java/com/seaofnodes/simple/node/LoadNode.java
+++ b/chapter22/src/main/java/com/seaofnodes/simple/node/LoadNode.java
@@ -1,5 +1,7 @@
package com.seaofnodes.simple.node;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.codegen.CodeGen;
import com.seaofnodes.simple.Parser;
import com.seaofnodes.simple.type.*;
@@ -45,7 +47,7 @@ public class LoadNode extends MemOpNode {
// Debugger label
@Override public String label() { return "ld_"+mlabel(); }
@Override
- public StringBuilder _print1(StringBuilder sb, BitSet visited) { return sb.append(".").append(_name); }
+ protected ExprPrinter<Node> _print1(ExprPrinter<Node> p) { return p.p(".").p(_name); }
@Override
public Type compute() {
diff --git a/chapter22/src/main/java/com/seaofnodes/simple/node/MachConcreteNode.java b/chapter22/src/main/java/com/seaofnodes/simple/node/MachConcreteNode.java
index b01b3308..4f5d9151 100644
--- a/chapter22/src/main/java/com/seaofnodes/simple/node/MachConcreteNode.java
+++ b/chapter22/src/main/java/com/seaofnodes/simple/node/MachConcreteNode.java
@@ -1,9 +1,10 @@
package com.seaofnodes.simple.node;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.Utils;
import java.io.ByteArrayOutputStream;
-import java.util.BitSet;
// Generic machine-specific class, has a few Node implementations that have to
// exist (abstract) but are not useful past the optimizer.
@@ -16,12 +17,11 @@ public abstract class MachConcreteNode extends Node implements MachNode {
@Override public Type compute () { throw Utils.TODO(); }
@Override public Node idealize() { throw Utils.TODO(); }
- @Override public StringBuilder _print1(StringBuilder sb, BitSet visited) {
- sb.append("(").append(op()).append(",");
+ @Override protected ExprPrinter<Node> _print1(ExprPrinter<Node> p) {
+ p.open().p(op()).p(",");
for( int i=1; i<nIns(); i++ )
- (in(i)==null ? sb.append(" ---") : in(i)._print0(sb, visited)).append(",");
- sb.setLength(sb.length()-1);
- return sb.append(")");
+ (in(i)==null ? p.p(" ---") : p.n(in(i))).p(",");
+ return p.unchar(',').close();
}
}
diff --git a/chapter22/src/main/java/com/seaofnodes/simple/node/MemMergeNode.java b/chapter22/src/main/java/com/seaofnodes/simple/node/MemMergeNode.java
index c1d11f88..421e4864 100644
--- a/chapter22/src/main/java/com/seaofnodes/simple/node/MemMergeNode.java
+++ b/chapter22/src/main/java/com/seaofnodes/simple/node/MemMergeNode.java
@@ -1,5 +1,7 @@
package com.seaofnodes.simple.node;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.*;
import com.seaofnodes.simple.codegen.CodeGen;
import com.seaofnodes.simple.type.*;
@@ -52,14 +54,14 @@ public class MemMergeNode extends Node {
@Override public String label() { return "MemMerge"; }
@Override public boolean isMem() { return true; }
@Override public Type compute() { return TypeMem.BOT; }
- @Override public StringBuilder _print1(StringBuilder sb, BitSet visited) {
- sb.append("MEM[");
+ @Override protected ExprPrinter<Node> _print1(ExprPrinter<Node> p) {
+ p.p("MEM[");
for( int i=1; i<nIns(); i++ )
if( in(i)!=null ) {
- sb.append(i==1 ? "default:" : i+":");
- in(i)._print0(sb,visited).append(" ");
+ p.p(i==1 ? "default:" : i+":");
+ p.n(in(i)).p(" ");
}
- return sb.append("]");
+ return p.p("]");
}
@Override public Node idealize() {
diff --git a/chapter22/src/main/java/com/seaofnodes/simple/node/MemOpNode.java b/chapter22/src/main/java/com/seaofnodes/simple/node/MemOpNode.java
index 3428b5a5..db667e6d 100644
--- a/chapter22/src/main/java/com/seaofnodes/simple/node/MemOpNode.java
+++ b/chapter22/src/main/java/com/seaofnodes/simple/node/MemOpNode.java
@@ -1,5 +1,7 @@
package com.seaofnodes.simple.node;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.Parser;
import com.seaofnodes.simple.Utils;
import com.seaofnodes.simple.type.Type;
@@ -85,8 +87,8 @@ public abstract class MemOpNode extends Node {
public Node ptr() { return in(2); }
public Node off() { return in(3); }
- @Override public StringBuilder _print1( StringBuilder sb, BitSet visited ) { return _printMach(sb,visited); }
- public StringBuilder _printMach( StringBuilder sb, BitSet visited ) { throw Utils.TODO(); }
+ @Override protected ExprPrinter<Node> _print1(ExprPrinter<Node> p) { return _printMach(p); }
+ protected ExprPrinter<Node> _printMach(ExprPrinter<Node> p) { throw Utils.TODO(); }
public int log_size() { return _declaredType.log_size(); }
// Extra conditions for factoring matching memory operations through a Phi.
diff --git a/chapter22/src/main/java/com/seaofnodes/simple/node/MinusFNode.java b/chapter22/src/main/java/com/seaofnodes/simple/node/MinusFNode.java
index bfdb41cc..852e646d 100644
--- a/chapter22/src/main/java/com/seaofnodes/simple/node/MinusFNode.java
+++ b/chapter22/src/main/java/com/seaofnodes/simple/node/MinusFNode.java
@@ -1,20 +1,16 @@
package com.seaofnodes.simple.node;
+
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeFloat;
-import java.util.BitSet;
public class MinusFNode extends Node {
public MinusFNode(Node in) { super(null, in); }
@Override public String label() { return "MinusF"; }
- @Override
- public StringBuilder _print1(StringBuilder sb, BitSet visited) {
- in(1)._print0(sb.append("(-"), visited);
- return sb.append(")");
- }
+ @Override protected String format() { return "(-%1)"; }
@Override
public Type compute() {
diff --git a/chapter22/src/main/java/com/seaofnodes/simple/node/MinusNode.java b/chapter22/src/main/java/com/seaofnodes/simple/node/MinusNode.java
index 3a9eb39d..89e65254 100644
--- a/chapter22/src/main/java/com/seaofnodes/simple/node/MinusNode.java
+++ b/chapter22/src/main/java/com/seaofnodes/simple/node/MinusNode.java
@@ -1,21 +1,17 @@
package com.seaofnodes.simple.node;
+
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeInteger;
import com.seaofnodes.simple.Utils;
-import java.util.BitSet;
public class MinusNode extends Node {
public MinusNode(Node in) { super(null, in); }
@Override public String label() { return "Minus"; }
- @Override
- public StringBuilder _print1(StringBuilder sb, BitSet visited) {
- in(1)._print0(sb.append("(-"), visited);
- return sb.append(")");
- }
+ @Override protected String format() { return "(-%1)"; }
@Override
public Type compute() {
diff --git a/chapter22/src/main/java/com/seaofnodes/simple/node/MulFNode.java b/chapter22/src/main/java/com/seaofnodes/simple/node/MulFNode.java
index 0fc062cd..6a57f3c5 100644
--- a/chapter22/src/main/java/com/seaofnodes/simple/node/MulFNode.java
+++ b/chapter22/src/main/java/com/seaofnodes/simple/node/MulFNode.java
@@ -1,21 +1,16 @@
package com.seaofnodes.simple.node;
+
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeFloat;
-import java.util.BitSet;
public class MulFNode extends Node {
public MulFNode(Node lhs, Node rhs) { super(null, lhs, rhs); }
@Override public String label() { return "MulF"; }
- @Override
- public StringBuilder _print1(StringBuilder sb, BitSet visited) {
- in(1)._print0(sb.append("("), visited);
- in(2)._print0(sb.append("*"), visited);
- return sb.append(")");
- }
+ @Override protected String format() { return "(%1*%2)"; }
@Override
public Type compute() {
diff --git a/chapter22/src/main/java/com/seaofnodes/simple/node/NeverNode.java b/chapter22/src/main/java/com/seaofnodes/simple/node/NeverNode.java
index 516f218b..66879b66 100644
--- a/chapter22/src/main/java/com/seaofnodes/simple/node/NeverNode.java
+++ b/chapter22/src/main/java/com/seaofnodes/simple/node/NeverNode.java
@@ -1,11 +1,12 @@
package com.seaofnodes.simple.node;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.Parser;
import com.seaofnodes.simple.type.TypeInteger;
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeTuple;
-import java.util.BitSet;
// "Never true" for infinite loop exits
public class NeverNode extends IfNode {
@@ -14,7 +15,7 @@ public class NeverNode extends IfNode {
@Override public String label() { return "Never"; }
- @Override public StringBuilder _print1(StringBuilder sb, BitSet visited) { return sb.append("Never"); }
+ @Override protected ExprPrinter<Node> _print1(ExprPrinter<Node> p) { return p.p("Never"); }
@Override public Type compute() { return TypeTuple.IF_BOTH; }
diff --git a/chapter22/src/main/java/com/seaofnodes/simple/node/NewNode.java b/chapter22/src/main/java/com/seaofnodes/simple/node/NewNode.java
index 57d351ef..4179821c 100644
--- a/chapter22/src/main/java/com/seaofnodes/simple/node/NewNode.java
+++ b/chapter22/src/main/java/com/seaofnodes/simple/node/NewNode.java
@@ -1,10 +1,11 @@
package com.seaofnodes.simple.node;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.SB;
import com.seaofnodes.simple.Utils;
import com.seaofnodes.simple.codegen.*;
import com.seaofnodes.simple.type.*;
-import java.util.BitSet;
/** Allocate a zeroed object. Inputs {ctrl, $mem, size};
* results {ptr, $mem}.
@@ -37,10 +38,8 @@ public class NewNode extends Node implements MultiNode {
@Override public String label() { return "new_"+(_ptr._obj.isAry() ? "ary_"+_ptr._obj._fields[1]._type.str() : _ptr._obj.str()); }
- @Override
- public StringBuilder _print1(StringBuilder sb, BitSet visited) {
- sb.append("new ");
- return sb.append(_ptr._obj.str());
+ @Override protected ExprPrinter<Node> _print1(ExprPrinter<Node> p) {
+ return p.p("new ").p(_ptr._obj.str());
}
diff --git a/chapter22/src/main/java/com/seaofnodes/simple/node/Node.java b/chapter22/src/main/java/com/seaofnodes/simple/node/Node.java
index 339ef9af..fff1ab14 100644
--- a/chapter22/src/main/java/com/seaofnodes/simple/node/Node.java
+++ b/chapter22/src/main/java/com/seaofnodes/simple/node/Node.java
@@ -1,5 +1,7 @@
package com.seaofnodes.simple.node;
+import com.seaofnodes.print.BaseNode;
+
import com.seaofnodes.simple.*;
import com.seaofnodes.simple.codegen.CodeGen;
import com.seaofnodes.simple.print.IRPrinter;
@@ -15,14 +17,7 @@ import static com.seaofnodes.simple.codegen.CodeGen.CODE;
* The Node class provides common functionality used by all subtypes.
* Subtypes of Node specialize by overriding methods.
*/
-public abstract class Node implements Cloneable {
-
- /**
- * Each node has a unique dense Node ID within a compilation context
- * The ID is useful for debugging, for using as an offset in a bitvector,
- * as well as for computing equality of nodes (to be implemented later).
- */
- public int _nid;
+public abstract class Node extends BaseNode<Node> implements Cloneable {
/**
* Inputs to the node. These are use-def references to Nodes.
@@ -44,16 +39,14 @@ public abstract class Node implements Cloneable {
*/
public Ary<Node> _outputs;
-
/**
* Current computed type for this Node. This value changes as the graph
* changes and more knowledge is gained about the program.
*/
public Type _type;
-
Node(Node... inputs) {
- _nid = CODE.getUID(); // allocate unique dense ID
+ super(CODE.getUID()); // allocate unique dense ID
_inputs = new Ary<>(Node.class);
Collections.addAll(_inputs,inputs);
_outputs = new Ary<>(Node.class);
@@ -65,8 +58,8 @@ public abstract class Node implements Cloneable {
// Make a Node using the existing arrays of nodes.
// Used by any pass rewriting all Node classes but not the edges.
Node( Node n ) {
+ super(CODE.getUID()); // allocate unique dense ID
assert CodeGen.CODE._phase.ordinal() >= CodeGen.Phase.Select.ordinal();
- _nid = CODE.getUID(); // allocate unique dense ID
_inputs = new Ary<>(n==null ? new Node[0] : n._inputs.asAry());
_outputs = new Ary<>(Node.class);
_type = n==null ? Type.BOTTOM : n._type;
@@ -77,48 +70,6 @@ public abstract class Node implements Cloneable {
// Easy reading label for debugger, e.g. "Add" or "Region" or "EQ"
public abstract String label();
- // Unique label for debugging, e.g. "Add12" or "Region30" or "EQ99"
- public String uniqueName() {
- return label() + _nid;
- }
-
- // Operator symbol used by assembly/debug printing.
- public String glabel() { return label(); }
-
- // Extra fun stuff, for assembly printing. Jump labels, parser locations,
- // variable types, etc.
- public String comment() { return null; }
-
- // ------------------------------------------------------------------------
-
- // Debugger Printing.
-
- // {@code toString} is what you get in the debugger. It has to print 1
- // line (because this is what a debugger typically displays by default) and
- // has to be robust with broken graph/nodes.
- @Override
- public final String toString() { return print(); }
-
- // This is a *deep* print. We print with a mutually recursive tik-tok
- // style; the common _print0 calls the per-Node _print1, which calls back
- // to _print0;
- public final String print() {
- return _print0(new StringBuilder(), new BitSet()).toString();
- }
-
- // This is the common print: check for repeats, check for DEAD and print
- // "DEAD" else call the per-Node print1.
- public final StringBuilder _print0(StringBuilder sb, BitSet visited) {
- if (visited.get(_nid) && !(this instanceof ConstantNode) )
- return sb.append(label());
- visited.set(_nid);
- return isDead()
- ? sb.append(uniqueName()).append(":DEAD")
- : _print1(sb, visited);
- }
- // Every Node implements this; a partial-line recursive print
- abstract public StringBuilder _print1(StringBuilder sb, BitSet visited);
-
public String p(int depth) { return IRPrinter.prettyPrint(this,depth); }
public boolean isConst() { return false; }
@@ -126,6 +77,8 @@ public abstract class Node implements Cloneable {
// ------------------------------------------------------------------------
// Graph Node & Edge manipulation
+ @Override public String typeName() { return _type==null ? null : _type.toString(); }
+
/**
* Gets the ith input node
* @param i Offset of the input node
@@ -204,7 +157,6 @@ public abstract class Node implements Cloneable {
return setDef(idx,new_def);
}
-
/**
* Add a new def to an existing Node. Keep the edges correct by
* adding the corresponding <em>def->use</em> edge.
@@ -273,7 +225,6 @@ public abstract class Node implements Cloneable {
kill();
}
-
// Mostly used for asserts and printing.
public boolean isDead() { return isUnused() && nIns()==0 && _type==null; }
@@ -295,7 +246,6 @@ public abstract class Node implements Cloneable {
kill();
}
-
// Replace self with nnn in the graph, making 'this' go dead
public void subsume( Node nnn ) {
assert nnn!=this;
@@ -536,7 +486,6 @@ public abstract class Node implements Cloneable {
*/
public abstract Node idealize();
-
// Some of the peephole rules get complex, and search further afield than
// just the nearest neighbor. These peepholes can fail the pattern match
// on a node some distance away, and if that node ever changes we should
@@ -577,7 +526,6 @@ public abstract class Node implements Cloneable {
_deps.clear();
}
-
// Two nodes are equal if they have the same inputs and the same "opcode"
// which means the same Java class, plus same internal parts.
@Override public final boolean equals( Object o ) {
@@ -595,7 +543,6 @@ public abstract class Node implements Cloneable {
// and can assume "this!=n" and has the same Java class.
public boolean eq( Node n ) { return true; }
-
// Cached hash. If zero, then not computed AND this Node is NOT in the GVN
// table - and can have its edges hacked (which will change his hash
// anyway). If Non-Zero then this Node is IN the GVN table, or is being
@@ -611,7 +558,6 @@ public abstract class Node implements Cloneable {
_hash=0; // Out of table now
}
-
// Hash of opcode and inputs
@Override public final int hashCode() {
if( _hash != 0 ) return _hash;
@@ -631,7 +577,6 @@ public abstract class Node implements Cloneable {
/** Is this Node Memory related */
public boolean isMem() { return false; }
-
// Semantic change to the graph (so NOT a peephole), used by the Parser.
// If any input is a float, flip to a float-flavored opcode and widen any
// non-float input.
@@ -652,7 +597,6 @@ public abstract class Node implements Cloneable {
}
Node copyF() { return null; }
-
// ------------------------------------------------------------------------
// Peephole utilities
@@ -679,7 +623,6 @@ public abstract class Node implements Cloneable {
return true;
}
-
// Make a shallow copy (same class) of this Node, with given inputs and
// empty outputs and a new Node ID. The original inputs are ignored.
// Does not need to be implemented in isCFG() nodes.
diff --git a/chapter22/src/main/java/com/seaofnodes/simple/node/NotNode.java b/chapter22/src/main/java/com/seaofnodes/simple/node/NotNode.java
index 118ef5c8..57fa9301 100644
--- a/chapter22/src/main/java/com/seaofnodes/simple/node/NotNode.java
+++ b/chapter22/src/main/java/com/seaofnodes/simple/node/NotNode.java
@@ -1,19 +1,15 @@
package com.seaofnodes.simple.node;
+
import com.seaofnodes.simple.Utils;
import com.seaofnodes.simple.type.*;
-import java.util.BitSet;
public class NotNode extends Node {
public NotNode(Node in) { super(null, in); }
@Override public String label() { return "Not"; }
- @Override
- public StringBuilder _print1(StringBuilder sb, BitSet visited) {
- in(1)._print0(sb.append("(!"), visited);
- return sb.append(")");
- }
+ @Override protected String format() { return "(!%1)"; }
@Override
public TypeInteger compute() {
diff --git a/chapter22/src/main/java/com/seaofnodes/simple/node/ParmNode.java b/chapter22/src/main/java/com/seaofnodes/simple/node/ParmNode.java
index f75e7c64..3e8e3711 100644
--- a/chapter22/src/main/java/com/seaofnodes/simple/node/ParmNode.java
+++ b/chapter22/src/main/java/com/seaofnodes/simple/node/ParmNode.java
@@ -1,8 +1,9 @@
package com.seaofnodes.simple.node;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.Utils;
import com.seaofnodes.simple.type.Type;
-import java.util.BitSet;
public class ParmNode extends PhiNode {
@@ -20,18 +21,12 @@ public class ParmNode extends PhiNode {
public FunNode fun() { return (FunNode)in(0); }
@Override
- public StringBuilder _print1(StringBuilder sb, BitSet visited) {
+ protected ExprPrinter<Node> _print1(ExprPrinter<Node> p) {
if( "main".equals(fun()._name) && _label.equals("arg") )
- return sb.append("arg");
- sb.append("Parm_").append(_label).append("(");
- for( Node in : _inputs ) {
- if (in == null) sb.append("____");
- else in._print0(sb, visited);
- sb.append(",");
- }
- sb.setLength(sb.length()-1);
- sb.append(")");
- return sb;
+ return p.p("arg");
+ p.p("Parm_").p(_label).open();
+ for( Node in : _inputs ) p.n(in).p(",");
+ return p.unchar(',').close();
}
diff --git a/chapter22/src/main/java/com/seaofnodes/simple/node/PhiNode.java b/chapter22/src/main/java/com/seaofnodes/simple/node/PhiNode.java
index 5d0c842f..8aa123f7 100644
--- a/chapter22/src/main/java/com/seaofnodes/simple/node/PhiNode.java
+++ b/chapter22/src/main/java/com/seaofnodes/simple/node/PhiNode.java
@@ -1,8 +1,9 @@
package com.seaofnodes.simple.node;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.*;
import com.seaofnodes.simple.type.*;
-import java.util.BitSet;
public class PhiNode extends Node {
@@ -31,18 +32,12 @@ public class PhiNode extends Node {
@Override public String label() { return "Phi_"+MemOpNode.mlabel(_label); }
@Override
- public StringBuilder _print1(StringBuilder sb, BitSet visited) {
+ protected ExprPrinter<Node> _print1(ExprPrinter<Node> p) {
if( !(region() instanceof RegionNode r) || r.inProgress() )
- sb.append("Z");
- sb.append("Phi(");
- for( Node in : _inputs ) {
- if (in == null) sb.append("____");
- else in._print0(sb, visited);
- sb.append(",");
- }
- sb.setLength(sb.length()-1);
- sb.append(")");
- return sb;
+ p.p("Z");
+ p.p("Phi(");
+ for( Node in : _inputs ) p.n(in).p(",");
+ return p.unchar(',').close();
}
public CFGNode region() { return (CFGNode)in(0); }
diff --git a/chapter22/src/main/java/com/seaofnodes/simple/node/ProjNode.java b/chapter22/src/main/java/com/seaofnodes/simple/node/ProjNode.java
index 48f92525..26b3a522 100644
--- a/chapter22/src/main/java/com/seaofnodes/simple/node/ProjNode.java
+++ b/chapter22/src/main/java/com/seaofnodes/simple/node/ProjNode.java
@@ -1,10 +1,11 @@
package com.seaofnodes.simple.node;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeMem;
import com.seaofnodes.simple.type.TypeTuple;
-import java.util.BitSet;
public class ProjNode extends Node {
@@ -24,11 +25,11 @@ public class ProjNode extends Node {
@Override public String label() { return _label; }
@Override
- public StringBuilder _print1(StringBuilder sb, BitSet visited) {
- if( _label != null ) return sb.append(_label);
+ protected ExprPrinter<Node> _print1(ExprPrinter<Node> p) {
+ if( _label != null ) return p.p(_label);
if( in(0) instanceof CallEndNode cend && cend.call()!=null )
- return cend.call()._print0(sb,visited);
- return sb.append("LONELY PROJ");
+ return p.n(cend.call());
+ return p.p("LONELY PROJ");
}
@Override public CFGNode cfg0() {
diff --git a/chapter22/src/main/java/com/seaofnodes/simple/node/ReadOnlyNode.java b/chapter22/src/main/java/com/seaofnodes/simple/node/ReadOnlyNode.java
index d8fe6286..94c1b6f6 100644
--- a/chapter22/src/main/java/com/seaofnodes/simple/node/ReadOnlyNode.java
+++ b/chapter22/src/main/java/com/seaofnodes/simple/node/ReadOnlyNode.java
@@ -1,8 +1,8 @@
package com.seaofnodes.simple.node;
+
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeMemPtr;
-import java.util.BitSet;
/**
* Cast a pointer to read-only
@@ -12,10 +12,7 @@ public class ReadOnlyNode extends Node {
public ReadOnlyNode( ReadOnlyNode n ) { super(n); }
@Override public String label() { return "ReadOnly"; }
- @Override
- public StringBuilder _print1(StringBuilder sb, BitSet visited) {
- return in(1)._print0(sb.append("(const)"),visited);
- }
+ @Override protected String format() { return "(const)%1"; }
@Override public Type compute() {
Type t = in(1)._type;
return t instanceof TypeMemPtr tmp ? tmp.makeRO() : t;
diff --git a/chapter22/src/main/java/com/seaofnodes/simple/node/RegionNode.java b/chapter22/src/main/java/com/seaofnodes/simple/node/RegionNode.java
index 84383845..79b7f53a 100644
--- a/chapter22/src/main/java/com/seaofnodes/simple/node/RegionNode.java
+++ b/chapter22/src/main/java/com/seaofnodes/simple/node/RegionNode.java
@@ -1,5 +1,7 @@
package com.seaofnodes.simple.node;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.*;
import com.seaofnodes.simple.Parser;
import com.seaofnodes.simple.codegen.CodeGen;
@@ -17,9 +19,8 @@ public class RegionNode extends CFGNode {
@Override
public String label() { return "Region"; }
- @Override
- public StringBuilder _print1(StringBuilder sb, BitSet visited) {
- return sb.append(label());
+ @Override protected ExprPrinter<Node> _print1(ExprPrinter<Node> p) {
+ return p.p(label());
}
@Override public boolean blockHead() { return true; }
diff --git a/chapter22/src/main/java/com/seaofnodes/simple/node/ReturnNode.java b/chapter22/src/main/java/com/seaofnodes/simple/node/ReturnNode.java
index 05b19682..e0ab863a 100644
--- a/chapter22/src/main/java/com/seaofnodes/simple/node/ReturnNode.java
+++ b/chapter22/src/main/java/com/seaofnodes/simple/node/ReturnNode.java
@@ -1,5 +1,7 @@
package com.seaofnodes.simple.node;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.Parser;
import com.seaofnodes.simple.SB;
import com.seaofnodes.simple.Utils;
@@ -7,7 +9,6 @@ import com.seaofnodes.simple.codegen.CodeGen;
import com.seaofnodes.simple.codegen.RegMask;
import com.seaofnodes.simple.codegen.Encoding;
import com.seaofnodes.simple.type.*;
-import java.util.BitSet;
/** Keeps all preceding memory effects and the return value alive: {ctrl, $mem, value, rpc}. */
public class ReturnNode extends CFGNode {
@@ -30,11 +31,11 @@ public class ReturnNode extends CFGNode {
public String label() { return "Return"; }
@Override
- public StringBuilder _print1(StringBuilder sb, BitSet visited) {
- sb.append("return ");
- if( expr()==null ) sb.append("----");
- else expr()._print0(sb, visited);
- return sb.append(";");
+ protected ExprPrinter<Node> _print1(ExprPrinter<Node> p) {
+ p.p("return ");
+ if( expr()==null ) p.p("----");
+ else p.n(expr());
+ return p.p(";");
}
// No one unique control follows; can be many call end sites
diff --git a/chapter22/src/main/java/com/seaofnodes/simple/node/RoundF32Node.java b/chapter22/src/main/java/com/seaofnodes/simple/node/RoundF32Node.java
index 2ad034d6..78e7698c 100644
--- a/chapter22/src/main/java/com/seaofnodes/simple/node/RoundF32Node.java
+++ b/chapter22/src/main/java/com/seaofnodes/simple/node/RoundF32Node.java
@@ -1,19 +1,16 @@
package com.seaofnodes.simple.node;
+
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeFloat;
-import java.util.BitSet;
public class RoundF32Node extends Node {
public RoundF32Node(Node lhs) { super(null, lhs); }
@Override public String label() { return "RoundF32"; }
- @Override
- public StringBuilder _print1(StringBuilder sb, BitSet visited) {
- return in(1)._print0(sb.append("((f32)"), visited).append(")");
- }
+ @Override protected String format() { return "((f32)%1)"; }
@Override
public Type compute() {
diff --git a/chapter22/src/main/java/com/seaofnodes/simple/node/ScopeNode.java b/chapter22/src/main/java/com/seaofnodes/simple/node/ScopeNode.java
index 0c9bb881..3f110cde 100644
--- a/chapter22/src/main/java/com/seaofnodes/simple/node/ScopeNode.java
+++ b/chapter22/src/main/java/com/seaofnodes/simple/node/ScopeNode.java
@@ -1,5 +1,7 @@
package com.seaofnodes.simple.node;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.*;
import com.seaofnodes.simple.codegen.CodeGen;
import com.seaofnodes.simple.type.*;
@@ -52,28 +54,26 @@ public class ScopeNode extends Node {
@Override public String label() { return "Scope"; }
@Override
- public StringBuilder _print1(StringBuilder sb, BitSet visited) {
- sb.append("Scope[ ");
+ protected ExprPrinter<Node> _print1(ExprPrinter<Node> p) {
+ p.p("Scope[ ");
int j=1;
for( int i=0; i<nIns(); i++ ) {
- if( j < _lexSize._len && i == _lexSize.at(j) ) { sb.append("| "); j++; }
+ if( j < _lexSize._len && i == _lexSize.at(j) ) { p.p("| "); j++; }
Var v = _vars.at(i);
- sb.append(v._type().print(new SB()));
- sb.append(" ");
- if( v._final ) sb.append("!");
- sb.append(v._name);
- sb.append("=");
+ p.p(v._type().print(new SB()));
+ p.p(" ");
+ if( v._final ) p.p("!");
+ p.p(v._name);
+ p.p("=");
Node n = in(i);
while( n instanceof ScopeNode loop ) {
- sb.append("Lazy_");
+ p.p("Lazy_");
n = loop.in(i);
}
- if( n==null ) sb.append("___");
- else n._print0(sb, visited);
- sb.append(", ");
+ p.n(n);
+ p.p(", ");
}
- sb.setLength(sb.length()-2);
- return sb.append("]");
+ return p.unchar(", ").p("]");
}
diff --git a/chapter22/src/main/java/com/seaofnodes/simple/node/SplitNode.java b/chapter22/src/main/java/com/seaofnodes/simple/node/SplitNode.java
index 3a1ed011..ff18b292 100644
--- a/chapter22/src/main/java/com/seaofnodes/simple/node/SplitNode.java
+++ b/chapter22/src/main/java/com/seaofnodes/simple/node/SplitNode.java
@@ -1,20 +1,21 @@
package com.seaofnodes.simple.node;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.SB;
import com.seaofnodes.simple.codegen.CodeGen;
import com.seaofnodes.simple.type.Type;
-import java.util.BitSet;
public abstract class SplitNode extends MachConcreteNode {
public final String _kind; // Kind of split
public final byte _round;
public SplitNode(String kind, byte round, Node[] nodes) { super(nodes); _kind = kind; _round = round; }
@Override public String op() { return "mov"; }
- @Override public StringBuilder _print1(StringBuilder sb, BitSet visited) {
- sb.append("mov(");
- if( in(1) == null ) sb.append("---");
- else in(1)._print0(sb,visited);
- return sb.append(")");
+ @Override protected ExprPrinter<Node> _print1(ExprPrinter<Node> p) {
+ p.p("mov(");
+ if( in(1) == null ) p.p("---");
+ else p.n(in(1));
+ return p.close();
}
@Override public Type compute() { return in(0)._type; }
@Override public Node idealize() { return null; }
diff --git a/chapter22/src/main/java/com/seaofnodes/simple/node/StartNode.java b/chapter22/src/main/java/com/seaofnodes/simple/node/StartNode.java
index 91bf85a1..cbaefa6a 100644
--- a/chapter22/src/main/java/com/seaofnodes/simple/node/StartNode.java
+++ b/chapter22/src/main/java/com/seaofnodes/simple/node/StartNode.java
@@ -1,9 +1,10 @@
package com.seaofnodes.simple.node;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.codegen.CodeGen;
import com.seaofnodes.simple.Parser;
import com.seaofnodes.simple.type.*;
-import java.util.BitSet;
import java.util.HashSet;
import static com.seaofnodes.simple.Utils.TODO;
@@ -17,9 +18,8 @@ public class StartNode extends LoopNode implements MultiNode {
@Override public String label() { return "Start"; }
- @Override
- public StringBuilder _print1(StringBuilder sb, BitSet visited) {
- return sb.append(label());
+ @Override protected ExprPrinter<Node> _print1(ExprPrinter<Node> p) {
+ return p.p(label());
}
@Override public boolean blockHead() { return true; }
diff --git a/chapter22/src/main/java/com/seaofnodes/simple/node/StopNode.java b/chapter22/src/main/java/com/seaofnodes/simple/node/StopNode.java
index 2363db2c..298c24a9 100644
--- a/chapter22/src/main/java/com/seaofnodes/simple/node/StopNode.java
+++ b/chapter22/src/main/java/com/seaofnodes/simple/node/StopNode.java
@@ -1,8 +1,9 @@
package com.seaofnodes.simple.node;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.Utils;
import com.seaofnodes.simple.type.Type;
-import java.util.BitSet;
public class StopNode extends CFGNode {
@@ -21,18 +22,18 @@ public class StopNode extends CFGNode {
}
@Override
- public StringBuilder _print1(StringBuilder sb, BitSet visited) {
+ protected ExprPrinter<Node> _print1(ExprPrinter<Node> p) {
// For the sake of many old tests, and single value prints as "return val"
ReturnNode ret1 = ret();
- if( ret1!=null ) return ret1._print0(sb,visited);
- sb.append("Stop[ ");
+ if( ret1!=null ) return p.n(ret1);
+ p.p("Stop[ ");
for( Node ret : _inputs )
if( ret!=null ) {
String name = ((ReturnNode)ret).fun()._name;
if( name== null || !name.startsWith("sys.") )
- ret._print0(sb, visited).append(" ");
+ p.n(ret).p(" ");
}
- return sb.append("]");
+ return p.p("]");
}
@Override public boolean blockHead() { return true; }
diff --git a/chapter22/src/main/java/com/seaofnodes/simple/node/StoreNode.java b/chapter22/src/main/java/com/seaofnodes/simple/node/StoreNode.java
index 99adfdfc..5e8b77f4 100644
--- a/chapter22/src/main/java/com/seaofnodes/simple/node/StoreNode.java
+++ b/chapter22/src/main/java/com/seaofnodes/simple/node/StoreNode.java
@@ -1,9 +1,10 @@
package com.seaofnodes.simple.node;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.codegen.*;
import com.seaofnodes.simple.*;
import com.seaofnodes.simple.type.*;
-import java.util.BitSet;
/**
* Store represents setting a value to a memory based object, in chapter 10
@@ -36,8 +37,8 @@ public class StoreNode extends MemOpNode {
public Node val() { return in(4); }
@Override
- public StringBuilder _print1(StringBuilder sb, BitSet visited) {
- return sb.append(".").append(_name).append("=").append( val()).append(";");
+ protected ExprPrinter<Node> _print1(ExprPrinter<Node> p) {
+ return p.p(".").p(_name).p("=").p( val()).p(";");
}
@Override
diff --git a/chapter22/src/main/java/com/seaofnodes/simple/node/StructNode.java b/chapter22/src/main/java/com/seaofnodes/simple/node/StructNode.java
index 4efc0de9..3782d64a 100644
--- a/chapter22/src/main/java/com/seaofnodes/simple/node/StructNode.java
+++ b/chapter22/src/main/java/com/seaofnodes/simple/node/StructNode.java
@@ -1,8 +1,9 @@
package com.seaofnodes.simple.node;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.SB;
import com.seaofnodes.simple.type.*;
-import java.util.BitSet;
/**
* Build a compound object
@@ -14,16 +15,15 @@ public class StructNode extends Node {
@Override public String label() { return _ts==null ? "STRUCT?" : _ts.str(); }
@Override
- public StringBuilder _print1(StringBuilder sb, BitSet visited) {
- if( _ts==null ) return sb.append("STRUCT?");
- sb.append(_ts._name).append(" {");
+ protected ExprPrinter<Node> _print1(ExprPrinter<Node> p) {
+ if( _ts==null ) return p.p("STRUCT?");
+ p.p(_ts._name).p(" {");
for( int i=0; i<nIns(); i++ ) {
- sb.append(_ts._fields[i]._fname).append(":");
- sb.append((in(i)==null ? Type.BOTTOM : in(i)._type).print(new SB()));
- sb.append("; ");
+ p.p(_ts._fields[i]._fname).p(":");
+ p.p((in(i)==null ? Type.BOTTOM : in(i)._type).print(new SB()));
+ p.p("; ");
}
- sb.setLength(sb.length()-2);
- return sb.append("}");
+ return p.unchar("; ").p("}");
}
@Override
diff --git a/chapter22/src/main/java/com/seaofnodes/simple/node/SubFNode.java b/chapter22/src/main/java/com/seaofnodes/simple/node/SubFNode.java
index 73cf9de5..2d218a03 100644
--- a/chapter22/src/main/java/com/seaofnodes/simple/node/SubFNode.java
+++ b/chapter22/src/main/java/com/seaofnodes/simple/node/SubFNode.java
@@ -1,21 +1,16 @@
package com.seaofnodes.simple.node;
+
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeFloat;
-import java.util.BitSet;
public class SubFNode extends Node {
public SubFNode(Node lhs, Node rhs) { super(null, lhs, rhs); }
@Override public String label() { return "SubF"; }
- @Override
- public StringBuilder _print1(StringBuilder sb, BitSet visited) {
- in(1)._print0(sb.append("("), visited);
- in(2)._print0(sb.append("-"), visited);
- return sb.append(")");
- }
+ @Override protected String format() { return "(%1-%2)"; }
@Override
public Type compute() {
diff --git a/chapter22/src/main/java/com/seaofnodes/simple/node/ToFloatNode.java b/chapter22/src/main/java/com/seaofnodes/simple/node/ToFloatNode.java
index 8ef5e40a..7b0122ce 100644
--- a/chapter22/src/main/java/com/seaofnodes/simple/node/ToFloatNode.java
+++ b/chapter22/src/main/java/com/seaofnodes/simple/node/ToFloatNode.java
@@ -1,20 +1,17 @@
package com.seaofnodes.simple.node;
+
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeFloat;
import com.seaofnodes.simple.type.TypeInteger;
-import java.util.BitSet;
public class ToFloatNode extends Node {
public ToFloatNode(Node lhs) { super(null, lhs); }
@Override public String label() { return "ToFloat"; }
- @Override
- public StringBuilder _print1(StringBuilder sb, BitSet visited) {
- return in(1)._print0(sb.append("(flt)"), visited);
- }
+ @Override protected String format() { return "(flt)%1"; }
@Override
public Type compute() {
diff --git a/chapter22/src/main/java/com/seaofnodes/simple/node/XCtrlNode.java b/chapter22/src/main/java/com/seaofnodes/simple/node/XCtrlNode.java
index 8c620a04..477b9af8 100644
--- a/chapter22/src/main/java/com/seaofnodes/simple/node/XCtrlNode.java
+++ b/chapter22/src/main/java/com/seaofnodes/simple/node/XCtrlNode.java
@@ -1,14 +1,15 @@
package com.seaofnodes.simple.node;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.codegen.CodeGen;
import com.seaofnodes.simple.Parser;
import com.seaofnodes.simple.type.Type;
-import java.util.BitSet;
public class XCtrlNode extends CFGNode {
public XCtrlNode() { super(new Node[]{CodeGen.CODE._start}); }
@Override public String label() { return "Xctrl"; }
- @Override public StringBuilder _print1(StringBuilder sb, BitSet visited) { return sb.append("Xctrl"); }
+ @Override protected ExprPrinter<Node> _print1(ExprPrinter<Node> p) { return p.p("Xctrl"); }
@Override public boolean isConst() { return true; }
@Override public Type compute() { return Type.XCONTROL; }
@Override public Node idealize() { return null; }
diff --git a/chapter22/src/main/java/com/seaofnodes/simple/node/cpus/arm/MemOpARM.java b/chapter22/src/main/java/com/seaofnodes/simple/node/cpus/arm/MemOpARM.java
index bec0acc5..afd8723e 100644
--- a/chapter22/src/main/java/com/seaofnodes/simple/node/cpus/arm/MemOpARM.java
+++ b/chapter22/src/main/java/com/seaofnodes/simple/node/cpus/arm/MemOpARM.java
@@ -1,12 +1,13 @@
package com.seaofnodes.simple.node.cpus.arm;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.*;
import com.seaofnodes.simple.codegen.*;
import com.seaofnodes.simple.node.*;
import com.seaofnodes.simple.type.*;
import java.lang.StringBuilder;
-import java.util.BitSet;
public abstract class MemOpARM extends MemOpNode implements MachNode {
@@ -32,7 +33,7 @@ public abstract class MemOpARM extends MemOpNode implements MachNode {
@Override public String label() { return op();}
Node val() { return in(4); } // Only for stores
- @Override public StringBuilder _printMach(StringBuilder sb, BitSet visited) { return sb.append(".").append(_name); }
+ @Override protected ExprPrinter<Node> _printMach(ExprPrinter<Node> p) { return p.p(".").p(_name); }
@Override public Type compute() { throw Utils.TODO(); }
@Override public Node idealize() { throw Utils.TODO(); }
diff --git a/chapter22/src/main/java/com/seaofnodes/simple/node/cpus/arm/UJmpARM.java b/chapter22/src/main/java/com/seaofnodes/simple/node/cpus/arm/UJmpARM.java
index a69c3c7c..bf46a7b1 100644
--- a/chapter22/src/main/java/com/seaofnodes/simple/node/cpus/arm/UJmpARM.java
+++ b/chapter22/src/main/java/com/seaofnodes/simple/node/cpus/arm/UJmpARM.java
@@ -1,19 +1,17 @@
package com.seaofnodes.simple.node.cpus.arm;
+
import com.seaofnodes.simple.*;
import com.seaofnodes.simple.codegen.*;
import com.seaofnodes.simple.node.*;
import com.seaofnodes.simple.type.Type;
-import java.util.BitSet;
// unconditional jump
public class UJmpARM extends CFGNode implements MachNode, RIPRelSize {
UJmpARM() { }
@Override public String op() { return "jmp"; }
@Override public String label() { return op(); }
- @Override public StringBuilder _print1( StringBuilder sb, BitSet visited ) {
- return sb.append("jmp ");
- }
+ @Override protected String format() { return "jmp "; }
@Override public RegMask regmap(int i) {return null; }
@Override public RegMask outregmap() { return null; }
@Override public Type compute() { throw Utils.TODO(); }
diff --git a/chapter22/src/main/java/com/seaofnodes/simple/node/cpus/riscv/BranchRISC.java b/chapter22/src/main/java/com/seaofnodes/simple/node/cpus/riscv/BranchRISC.java
index 44ff4e8b..f6dc5cf2 100644
--- a/chapter22/src/main/java/com/seaofnodes/simple/node/cpus/riscv/BranchRISC.java
+++ b/chapter22/src/main/java/com/seaofnodes/simple/node/cpus/riscv/BranchRISC.java
@@ -1,9 +1,10 @@
package com.seaofnodes.simple.node.cpus.riscv;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.*;
import com.seaofnodes.simple.codegen.*;
import com.seaofnodes.simple.node.*;
-import java.util.BitSet;
// Conditional branch such as: BEQ
public class BranchRISC extends IfNode implements MachNode, RIPRelSize {
@@ -30,14 +31,14 @@ public class BranchRISC extends IfNode implements MachNode, RIPRelSize {
}
}
- @Override public StringBuilder _print1(StringBuilder sb, BitSet visited) {
- sb.append("if( ");
- if( in(1)==null ) sb.append("0");
- else in(1)._print0(sb,visited);
- sb.append(_bop);
- if( in(2)==null ) sb.append("0");
- else in(2)._print0(sb,visited);
- return sb.append(" )");
+ @Override protected ExprPrinter<Node> _print1(ExprPrinter<Node> p) {
+ p.p("if( ");
+ if( in(1)==null ) p.p("0");
+ else p.n(in(1));
+ p.p(_bop);
+ if( in(2)==null ) p.p("0");
+ else p.n(in(2));
+ return p.p(" )");
}
@Override public void encoding( Encoding enc ) {
diff --git a/chapter22/src/main/java/com/seaofnodes/simple/node/cpus/riscv/ImmRISC.java b/chapter22/src/main/java/com/seaofnodes/simple/node/cpus/riscv/ImmRISC.java
index 9e7f456a..8847d2b7 100644
--- a/chapter22/src/main/java/com/seaofnodes/simple/node/cpus/riscv/ImmRISC.java
+++ b/chapter22/src/main/java/com/seaofnodes/simple/node/cpus/riscv/ImmRISC.java
@@ -1,10 +1,11 @@
package com.seaofnodes.simple.node.cpus.riscv;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.*;
import com.seaofnodes.simple.codegen.*;
import com.seaofnodes.simple.node.*;
import com.seaofnodes.simple.type.TypeInteger;
-import java.util.BitSet;
abstract public class ImmRISC extends MachConcreteNode implements MachNode {
public final int _imm12;
@@ -28,10 +29,10 @@ abstract public class ImmRISC extends MachConcreteNode implements MachNode {
return in(1) instanceof LUI || in(1) instanceof AUIPC;
}
- @Override public StringBuilder _print1(StringBuilder sb, BitSet visited) {
+ @Override protected ExprPrinter<Node> _print1(ExprPrinter<Node> p) {
int imm12 = (_imm12<<20)>>20; // Sign extend 12 bits
- in(1)._print0(sb.append("( "), visited);
- return sb.append(String.format(" %s #%d )",glabel(),imm12));
+ p.p("( ").n(in(1));
+ return p.p(String.format(" %s #%d )",glabel(),imm12));
}
abstract int opcode();
diff --git a/chapter22/src/main/java/com/seaofnodes/simple/node/cpus/riscv/MemOpRISC.java b/chapter22/src/main/java/com/seaofnodes/simple/node/cpus/riscv/MemOpRISC.java
index 8b84a2b9..c2025a3d 100644
--- a/chapter22/src/main/java/com/seaofnodes/simple/node/cpus/riscv/MemOpRISC.java
+++ b/chapter22/src/main/java/com/seaofnodes/simple/node/cpus/riscv/MemOpRISC.java
@@ -1,11 +1,12 @@
package com.seaofnodes.simple.node.cpus.riscv;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.SB;
import com.seaofnodes.simple.Utils;
import com.seaofnodes.simple.codegen.*;
import com.seaofnodes.simple.node.*;
import com.seaofnodes.simple.type.*;
-import java.util.BitSet;
public abstract class MemOpRISC extends MemOpNode implements MachNode {
final int _off; // Limit 12 bits
@@ -23,7 +24,7 @@ public abstract class MemOpRISC extends MemOpNode implements MachNode {
@Override public String label() { return op(); }
Node val() { return in(4); } // Only for stores
- @Override public StringBuilder _printMach(StringBuilder sb, BitSet visited) { return sb.append(".").append(_name); }
+ @Override protected ExprPrinter<Node> _printMach(ExprPrinter<Node> p) { return p.p(".").p(_name); }
@Override public Type compute() { throw Utils.TODO(); }
@Override public Node idealize() { throw Utils.TODO(); }
diff --git a/chapter22/src/main/java/com/seaofnodes/simple/node/cpus/riscv/UJmpRISC.java b/chapter22/src/main/java/com/seaofnodes/simple/node/cpus/riscv/UJmpRISC.java
index 6473d81c..3868990d 100644
--- a/chapter22/src/main/java/com/seaofnodes/simple/node/cpus/riscv/UJmpRISC.java
+++ b/chapter22/src/main/java/com/seaofnodes/simple/node/cpus/riscv/UJmpRISC.java
@@ -1,16 +1,17 @@
package com.seaofnodes.simple.node.cpus.riscv;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.*;
import com.seaofnodes.simple.codegen.*;
import com.seaofnodes.simple.node.*;
import com.seaofnodes.simple.type.Type;
-import java.util.BitSet;
// unconditional jump
public class UJmpRISC extends CFGNode implements MachNode, RIPRelSize {
@Override public String op() { return "jmp"; }
@Override public String label() { return op(); }
- @Override public StringBuilder _print1( StringBuilder sb, BitSet visited ) { return sb.append("jmp "); }
+ @Override protected ExprPrinter<Node> _print1(ExprPrinter<Node> p) { return p.p("jmp "); }
@Override public RegMask regmap(int i) {return null; }
@Override public RegMask outregmap() { return null; }
@Override public Type compute() { throw Utils.TODO(); }
diff --git a/chapter22/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/MemOpX86.java b/chapter22/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/MemOpX86.java
index 9f80b1f5..fa3cdd13 100644
--- a/chapter22/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/MemOpX86.java
+++ b/chapter22/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/MemOpX86.java
@@ -1,12 +1,13 @@
package com.seaofnodes.simple.node.cpus.x86_64_v2;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.*;
import com.seaofnodes.simple.codegen.*;
import com.seaofnodes.simple.node.*;
import com.seaofnodes.simple.type.*;
import java.lang.StringBuilder;
-import java.util.BitSet;
// Generic X86 memory operand base.
// inputs:
@@ -53,8 +54,8 @@ public abstract class MemOpX86 extends MemOpNode implements MachNode {
Node idx() { return in(3); }
Node val() { return in(4); } // Only for stores, including op-to-memory
- @Override public StringBuilder _printMach(StringBuilder sb, BitSet visited) {
- return sb.append(".").append(_name);
+ @Override protected ExprPrinter<Node> _printMach(ExprPrinter<Node> p) {
+ return p.p(".").p(_name);
}
@Override public String label() { return op(); }
diff --git a/chapter22/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/StoreX86.java b/chapter22/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/StoreX86.java
index 76fb4e8d..22a0bd79 100644
--- a/chapter22/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/StoreX86.java
+++ b/chapter22/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/StoreX86.java
@@ -1,5 +1,7 @@
package com.seaofnodes.simple.node.cpus.x86_64_v2;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.SB;
import com.seaofnodes.simple.codegen.*;
import com.seaofnodes.simple.node.ConstantNode;
@@ -7,19 +9,18 @@ import com.seaofnodes.simple.node.Node;
import com.seaofnodes.simple.node.StoreNode;
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeFloat;
-import java.util.BitSet;
public class StoreX86 extends MemOpX86 {
StoreX86( StoreNode st, Node base, Node idx, int off, int scale, int imm, Node val ) {
super(st,st, base, idx, off, scale, imm, val);
}
@Override public String op() { return "st"+_sz; }
- @Override public StringBuilder _printMach(StringBuilder sb, BitSet visited) {
+ @Override protected ExprPrinter<Node> _printMach(ExprPrinter<Node> p) {
Node val = val();
- sb.append(".").append(_name).append("=");
- if( val==null ) sb.append(_imm);
- else val._print0(sb,visited);
- return sb.append(";");
+ p.p(".").p(_name).p("=");
+ if( val==null ) p.p(_imm);
+ else p.n(val);
+ return p.p(";");
}
// Register mask allowed as a result. 0 for no register.
@Override public RegMask outregmap() { return null; }
diff --git a/chapter22/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/UJmpX86.java b/chapter22/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/UJmpX86.java
index ec4eeb3b..5db9e75e 100644
--- a/chapter22/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/UJmpX86.java
+++ b/chapter22/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/UJmpX86.java
@@ -1,19 +1,17 @@
package com.seaofnodes.simple.node.cpus.x86_64_v2;
+
import com.seaofnodes.simple.*;
import com.seaofnodes.simple.codegen.*;
import com.seaofnodes.simple.node.*;
import com.seaofnodes.simple.type.Type;
-import java.util.BitSet;
// unconditional jump
public class UJmpX86 extends CFGNode implements MachNode, RIPRelSize {
UJmpX86() { }
@Override public String op() { return "jmp"; }
@Override public String label() { return op(); }
- @Override public StringBuilder _print1( StringBuilder sb, BitSet visited ) {
- return sb.append("jmp ");
- }
+ @Override protected String format() { return "jmp "; }
@Override public RegMask regmap(int i) {return null; }
@Override public RegMask outregmap() { return null; }
@Override public Type compute() { throw Utils.TODO(); }
diff --git a/chapter22/src/main/java/com/seaofnodes/simple/print/ASMPrinter.java b/chapter22/src/main/java/com/seaofnodes/simple/print/ASMPrinter.java
index c8082841..1cc83813 100644
--- a/chapter22/src/main/java/com/seaofnodes/simple/print/ASMPrinter.java
+++ b/chapter22/src/main/java/com/seaofnodes/simple/print/ASMPrinter.java
@@ -1,306 +1,85 @@
package com.seaofnodes.simple.print;
-import com.seaofnodes.simple.Ary;
-import com.seaofnodes.simple.SB;
-import com.seaofnodes.simple.Utils;
+import com.seaofnodes.print.AssemblyAdapter;
+import com.seaofnodes.print.ASMPrinter.Data;
+import com.seaofnodes.print.ASMPrinter.Pool;
import com.seaofnodes.simple.codegen.CodeGen;
-import com.seaofnodes.simple.codegen.Encoding;
-import com.seaofnodes.simple.codegen.Encoding.Relo;
+import com.seaofnodes.simple.SB;
import com.seaofnodes.simple.node.*;
import com.seaofnodes.simple.type.*;
-import java.util.Collections;
-import java.util.IdentityHashMap;
-import java.util.Set;
-
-public abstract class ASMPrinter {
+import java.util.ArrayList;
+import com.seaofnodes.simple.codegen.Encoding;
+/** Machine-specific facts; traversal, columns and byte display live in print/. */
+public final class ASMPrinter extends AssemblyAdapter<Node> {
+ private final CodeGen _code;
+ private final Encoding _enc;
+ private ASMPrinter(CodeGen code) {
+ super(new IRPrinter());
+ _code=code;
+ _enc=code._encoding;
+ }
public static SB print(SB sb, CodeGen code) {
- if( code._cfg==null )
- return sb.p("Need _cfg set, run after GCM");
-
- // instruction address
- int iadr = 0;
- for( int i=0; i<code._cfg._len; i++ )
- if( code._cfg.at(i) instanceof FunNode fun )
- iadr = print(iadr,sb,code,fun,i);
-
- // constant pool
- iadr = (iadr+15)&-16; // pad to 16
- Encoding enc = code._encoding;
- if( enc!=null && !enc._bigCons.isEmpty() && iadr < enc._bits.size() ) {
- // radix sort the big constants by alignment
- Ary<Relo>[] raligns = new Ary[5];
- for( Relo relo : enc._bigCons.values() ) {
- int align = relo._align;
- Ary<Relo> relos = raligns[align]==null ? (raligns[align]=new Ary<>( Relo.class)) : raligns[align];
- relos.add(relo);
- }
-
- Set<Type> targets = Collections.newSetFromMap(new IdentityHashMap<>());
- sb.p("--- Constant Pool ------").nl();
-
- // By alignment
- for( int align = 4; align >= 0; align-- ) {
- Ary<Relo> relos = raligns[align];
- if( relos == null ) continue;
- for( Relo relo : relos ) {
- if( targets.contains(relo._t) ) continue;
- targets.add(relo._t);
- sb.hex2(iadr).p(" ");
- switch( relo._t ) {
- case TypeTuple tt -> {
- for( Type tx : tt._types ) {
- pN(enc,sb,iadr,align).p(" ");
- iadr += (1<<align);
- }
- }
-
- case TypeStruct ts -> {
- int sz = relo._structSize;
- int log = 1<<align;
- sz = (sz + (log -1)) & -log; // Round up final padding
- for( int i=0; i<sz; i++ )
- sb.hex1(enc.read1(iadr++));
- }
-
- // Simple primitive (e.g. larger int, float)
- default -> {
- pN(enc,sb,iadr,align).fix(9-(1<<align),"");
- iadr += (1<<align);
- }
- }
- relo._t.print(sb).nl();
- }
- }
- }
-
- return sb;
+ return sb.p(new com.seaofnodes.print.ASMPrinter<>(new ASMPrinter(code)).print());
}
-
- private static SB pN( Encoding enc, SB sb, int iadr, int log ) {
- switch( log ) {
- case 0: sb.hex1(enc.read1(iadr)); break;
- case 1: sb.hex2(enc.read2(iadr)); break;
- case 2: sb.hex4(enc.read4(iadr)); break;
- case 3: sb.hex8(enc.read8(iadr)); break;
- }
- return sb;
+ @Override public ArrayList<Node> blocks() {
+ var blocks=new ArrayList<Node>();
+ var cfg=_code._cfg;
+ if( cfg!=null ) for( Node n : cfg ) blocks.add(n);
+ return blocks;
}
-
-
- private static int print(int iadr, SB sb, CodeGen code, FunNode fun, int cfgidx) {
- FunNode old=null;
- if( code._encoding!=null ) {
- old = code._encoding._fun;
- code._encoding._fun = fun; // Useful printing after RA
+ @Override public String op(Node n) { return n instanceof MachNode m ? m.op() : n.label(); }
+ @Override public String register(Node n) { return _code.reg(n); }
+ @Override public String comment(Node n) { return n.comment(); }
+ @Override public String phiName(Node n) { return ((PhiNode)n)._label; }
+ @Override public String operands(Node n) {
+ SB sb=new SB();
+ if( n instanceof MachNode m ) m.asm(_code,sb);
+ else if( !(n._type instanceof TypeMem) ) {
+ sb.p(n._nid).p(": ");
+ for( Node def : n._inputs ) sb.p(def==null ? "___" : Integer.toString(def._nid)).p(' ');
}
- // Function header
- sb.nl().p("---");
- if( fun._name != null ) sb.p(fun._name).p(" ");
- fun.sig().print(sb);
- sb.p("---------------------------").nl();
- iadr = (iadr + 15)&-16; // All function entries padded to 16 align
-
- if( fun._frameAdjust != 0 )
- iadr = doInst(iadr,sb,code,fun,cfgidx,fun,true,true);
- while( !(code._cfg.at(cfgidx) instanceof ReturnNode) )
- iadr = doBlock(iadr,sb,code,fun,cfgidx++);
-
- // Function separator
- sb.p("---");
- fun.sig().print(sb);
- sb.p("---------------------------").nl();
- if( code._encoding != null )
- code._encoding._fun = old;
- return iadr;
+ return sb.toString();
}
-
- static private final int opWidth = 5;
- static private final int argWidth = 30;
- static int doBlock(int iadr, SB sb, CodeGen code, FunNode fun, int cfgidx) {
- final int encWidth = code._mach==null ? 2 : code._mach.defaultOpSize()*2;
- CFGNode bb = code._cfg.at(cfgidx);
- if( bb != fun && !(bb instanceof IfNode) && !(bb instanceof CallEndNode) && !(bb instanceof CallNode) && !(bb instanceof CProjNode && bb.in(0) instanceof CallEndNode ))
- sb.p(label(bb)).p(":").nl();
- if( bb instanceof CallNode ) return iadr;
- final boolean postAlloc = code._phase.ordinal() > CodeGen.Phase.RegAlloc.ordinal();
- final boolean postEncode= code._phase.ordinal() >=CodeGen.Phase.Encoding.ordinal();
-
- boolean once=false;
- for( Node n : bb.outs() ) {
- if( !(n instanceof PhiNode phi) ) continue;
- if( phi._type instanceof TypeMem || phi._type instanceof TypeRPC ) continue; // Nothing for the hidden ones
- // Post-RegAlloc phi prints all on one line
- if( postAlloc ) {
- if( !once ) { once=true; sb.fix(4," ").p(" ").fix(encWidth,"").p(" "); }
- sb.p(phi._label).p(':').p(code.reg(phi,fun)).p(',');
- } else {
- // Pre-RegAlloc phi prints one line per
- sb.fix(4," ").p(" ").fix(encWidth,"").p(" ").fix(opWidth,phi._label).p(" ").p(code.reg(phi,fun));
- if( phi.getClass() == PhiNode.class ) {
- sb.p(" = phi( ");
- for( int i=1; i<phi.nIns(); i++ )
- sb.p("N").p(phi.in(i)._nid).p(",");
- sb.unchar().p(" )");
- }
- sb.nl();
- }
- }
- if( once ) sb.unchar().nl();
-
- // All the non-phis
- for( int i=0; i<bb.nOuts(); i++ )
- if( !(bb.out(i) instanceof PhiNode) )
- iadr = doInst(iadr, sb,code, fun, cfgidx, bb.out(i),postAlloc, postEncode );
-
- return iadr;
+ @Override public boolean labelBlock(Node n) {
+ return !(n instanceof FunNode) && !(n instanceof IfNode) && !(n instanceof CallNode) &&
+ !(n instanceof CallEndNode) && !(n instanceof CProjNode && ir.input0(n) instanceof CallEndNode);
}
-
- static int doInst( int iadr, SB sb, CodeGen code, FunNode fun, int cfgidx, Node n, boolean postAlloc, boolean postEncode ) {
- if( n==null || n instanceof CProjNode ) return iadr;
- if( postAlloc && n instanceof CalleeSaveNode ) return iadr;
- if( postEncode && n instanceof ProjNode ) return iadr;
- if( n instanceof MemMergeNode ) return iadr;
- if( n.getClass() == ConstantNode.class ) return iadr; // Default placeholders
- final int dopz = code._mach==null ? 2 : code._mach.defaultOpSize();
- final int encWidth = dopz*2;
-
- // All blocks ending in a Region will need to either fall into or jump
- // to this block. Until the post-reg-alloc block layout cleanup, we
- // need to assume a jump. There's no real hardware op here, yet.
- if( n instanceof RegionNode cfg && !(n instanceof FunNode) ) {
- if( postEncode ) return iadr; // All jumps inserted already
- while( cfgidx < code._cfg._len-1 ) {
- CFGNode next = code._cfg.at(++cfgidx);
- if( next == n ) return iadr; // Fall-through, no branch
- if( next.nOuts()>1 )
- break; // Has code in the block, need to jump around
- // No code in the block, can fall through it
- }
- sb.hex2(iadr++).p(" ").fix(encWidth,"??").p(" ").fix(opWidth,"JMP").p(" ").fix(argWidth,label(cfg)).nl();
- return iadr;
- }
-
- // ProjNodes following a multi (e.g. Call or New results),
- // get indent slightly and just print their index & node#
- if( n instanceof ProjNode proj ) {
- if( proj._type instanceof TypeMem ) return iadr; // Nothing for the hidden ones
- sb.fix(4," ").p(" ").fix(encWidth,"").p(" ").fix(opWidth,proj._label==null ? "---" : proj._label).p(" ").p(code.reg(n,fun)).nl();
- return iadr;
- }
-
- // ADDR ENCODING Op--- dst = src op src // Comment
- // 1234 abcdefgh ld4 RAX = [Rbase + off] // Comment
- sb.hex2(iadr).p(" ");
-
- // Encoding
- int fatEncoding = 0;
- if( code._encoding != null && code._encoding._opLen!=null ) {
- int size = code._encoding._opLen[n._nid];
- if( code._asmLittle )
- for( int i=0; i<Math.min(size,dopz); i++ )
- sb.hex1(code._encoding._bits.buf()[iadr++]);
- else {
- iadr += Math.min(size,dopz);
- for( int i=0; i<Math.min(size,dopz); i++ )
- sb.hex1(code._encoding._bits.buf()[iadr-i-1]);
- }
- for( int i=size*2; i<encWidth; i++ )
- sb.p(" ");
- fatEncoding = size - (encWidth>>1); // Not-printed parts of encoding
- } else
- sb.fix(encWidth,"");
- sb.p(" ");
-
- // Op; generally "ld4" or "call"
- sb.fix(opWidth, n instanceof MachNode mach ? mach.op() : n.label()).p(" ");
-
- // General asm args
- String isMultiOp = null;
- if( n instanceof MachNode mach ) {
- int old = sb.len();
- mach.asm(code,sb);
- int len = sb.len();
- isMultiOp = isMultiOp(sb,old,len);
- sb.fix(argWidth-(len-old),""); // Pad out
-
- } else if( !(n._type instanceof TypeMem) ) {
- // Room for some inputs
- sb.fix(5, n._nid+":" );
- int off = 0;
- for( int i=0; i<n.nIns(); i++ ) {
- sb.fix(5, n.in(i) == null ? "___" : String.valueOf(n.in(i)._nid));
- off += 5;
- if( off >= argWidth ) break;
- }
- if( off < argWidth ) sb.fix(argWidth-off,"");
- }
- sb.p(" ");
-
- // Comment
- String comment = n.comment();
- if( comment!=null ) sb.p("// ").p(comment);
-
- sb.nl();
-
- // Printing more op bits than fit
- if( isMultiOp != null && code._encoding != null && code._encoding._opLen!=null ) {
- // Multiple ops, template style, no RA, no scheduling. Print out
- // one-line-per-newline, with encoding bits up front.
- int size = code._encoding._opLen[n._nid];
- int off = Math.min(size,dopz);
- while( isMultiOp!=null ) {
- sb.hex2(iadr).p(" ");
- int len = Math.min(size-off,dopz);
- for( int i=0; i<len; i++ )
- sb.hex1(code._encoding._bits.buf()[iadr++]);
- off += len;
- for( int i=len; i<dopz; i++ ) sb.p(" ");
- sb.p(" ");
- int x = isMultiOp.indexOf('\n');
- if( x== -1 ) { // Last line
- sb.p(isMultiOp).nl();
- isMultiOp = null;
- } else {
- sb.p(isMultiOp.substring(0,x+1)); // Includes the newline
- isMultiOp = isMultiOp.substring(x+1);
- }
-
- }
-
- } else if( fatEncoding > 0 ) {
- // Extra bytes past the default encoding width, all put on a line by
- // themselves. X86 special for super long encodings
- sb.hex2(iadr).p(" ");
- for( int i=0; i<fatEncoding; i++ )
- sb.hex1(code._encoding._bits.buf()[iadr++]);
- sb.nl();
- }
-
-
- // MultiNodes are immediately followed by projection(s)
- if( !(n instanceof CFGNode) && n instanceof MultiNode ) {
- for( Node proj : n._outputs ) {
- if( proj instanceof ProjNode ) // it could also be an ante-dep
- doInst(iadr,sb,code,fun, cfgidx, proj,postAlloc,postEncode);
- }
- }
-
- return iadr;
+ @Override public boolean hidden(Node n) {
+ if( n instanceof PhiNode || n instanceof ProjNode )
+ if( n._type instanceof TypeMem || n._type instanceof TypeRPC ) return true;
+ if( postAlloc() && n instanceof CalleeSaveNode ) return true;
+ if( n instanceof MemMergeNode ) return true;
+ return n.getClass()==ConstantNode.class;
}
-
- private static String label( CFGNode bb ) {
- return (bb instanceof LoopNode ? "LOOP" : "L")+bb._nid;
+ @Override public boolean postAlloc() { return _code._phase.ordinal()>CodeGen.Phase.RegAlloc.ordinal(); }
+ @Override public boolean encoded() { return _enc!=null && _code._phase.ordinal()>=CodeGen.Phase.Encoding.ordinal(); }
+ @Override public int defaultSize() { return _code._mach==null ? 2 : _code._mach.defaultOpSize(); }
+ @Override public boolean littleEndian() { return _code._asmLittle; }
+ @Override public boolean prologue(Node n) { return ((FunNode)n)._frameAdjust!=0; }
+ @Override public byte[] bytes() { return encoded() ? _enc._bits.buf() : null; }
+ @Override public int offset(Node n) {
+ return encoded() && _enc._opStart!=null && n._nid<_enc._opStart.length ? _enc._opStart[n._nid] : -1;
}
-
- private static String isMultiOp(SB sb, int old, int len) {
- for( int i=old; i<len; i++ )
- if( sb.at(i)=='\n' ) {
- String s = sb.subString(i+1,len);
- sb.setLen(i);
- return s;
- }
- return null;
+ @Override public int size(Node n) {
+ return encoded() && _enc._opLen!=null && n._nid<_enc._opLen.length ? _enc._opLen[n._nid]&255 : 0;
+ }
+ private static ArrayList<Data> entries(Iterable<Encoding.Relo> relos) {
+ var data=new ArrayList<Data>();
+ for( Encoding.Relo r : relos ) {
+ int align=1<<r._align;
+ int size=r._t instanceof TypeStruct ? (r._structSize+align-1)&-align : align;
+ if( r._t instanceof TypeTuple t ) size=align*t._types.length;
+ data.add(new Data(r._t,r._t.str(),r._align,size));
+ }
+ return data;
+ }
+ @Override public ArrayList<Pool> pools(int codeEnd) {
+ var pools=new ArrayList<Pool>();
+ if( !encoded() ) return pools;
+ int base=(codeEnd+15)&-16;
+ if( !_enc._bigCons.isEmpty() && base<_enc._bits.size() )
+ pools.add(new Pool("Constant Pool",_enc._bits.buf(),base,base,entries(_enc._bigCons.values())));
+ return pools;
}
-
}
diff --git a/chapter22/src/main/java/com/seaofnodes/simple/print/IRPrinter.java b/chapter22/src/main/java/com/seaofnodes/simple/print/IRPrinter.java
index ffa1d742..e4d719f4 100644
--- a/chapter22/src/main/java/com/seaofnodes/simple/print/IRPrinter.java
+++ b/chapter22/src/main/java/com/seaofnodes/simple/print/IRPrinter.java
@@ -1,352 +1,61 @@
package com.seaofnodes.simple.print;
-import com.seaofnodes.simple.Ary;
-import com.seaofnodes.simple.SB;
-import com.seaofnodes.simple.Utils;
-import com.seaofnodes.simple.codegen.CodeGen;
+import com.seaofnodes.print.IRAdapter;
import com.seaofnodes.simple.node.*;
-import com.seaofnodes.simple.type.TypeFunPtr;
import java.util.ArrayList;
-import java.util.BitSet;
-import java.util.HashMap;
-
-public abstract class IRPrinter {
-
- // Print a node on 1 line, columnar aligned, as:
- // NNID NNAME DDEF DDEF [[ UUSE UUSE ]] TYPE
- // 1234 sssss 1234 1234 1234 1234 1234 1234 tttttt
- public static SB printLine( Node n, SB sb ) {
- if( n==null ) return sb;
- sb.p("%4d %-7.7s ".formatted(n._nid,n.label()));
- if( n.isDead() )
- return sb.p("DEAD\n");
- for( Node def : n._inputs )
- sb.p(def==null ? "____" : "%4d".formatted(def._nid))
- // Lazy Phi indicator
- .p(n instanceof MemMergeNode && def instanceof MemMergeNode ? "^" : " ");
- for( int i = n._inputs.size(); i<4; i++ )
- sb.p(" ");
- sb.p(" [[ ");
- for( Node use : n._outputs )
- sb.p(use==null ? "____ " : "%4d ".formatted(use._nid));
- int lim = 6 - Math.max(n._inputs.size(),4);
- for( int i = n._outputs.size(); i<lim; i++ )
- sb.p(" ");
- sb.p(" ]] ");
- if( n._type!= null ) sb.p(n._type.str());
- return sb.p("\n");
- }
-
-
- public static String prettyPrint(Node node, int depth) {
- return CodeGen.CODE._phase.ordinal() > CodeGen.Phase.Schedule.ordinal()
- ? _prettyPrintScheduled( node, depth )
- : _prettyPrint( node, depth );
- }
-
- // Another bulk pretty-printer. Makes more effort at basic-block grouping.
- private static String _prettyPrint( Node node, int depth ) {
- // First, a Breadth First Search at a fixed depth.
- BFS bfs = new BFS(node,depth);
- // Convert just that set to a post-order
- ArrayList<Node> rpos = new ArrayList<>();
- BitSet visit = new BitSet();
- for( int i=bfs._lim; i< bfs._bfs.size(); i++ )
- postOrd( bfs._bfs.get(i), null, rpos, visit, bfs._bs);
- // Reverse the post-order walk
- SB sb = new SB();
- boolean gap=false;
- for( int i=rpos.size()-1; i>=0; i-- ) {
- Node n = rpos.get(i);
- if( n instanceof CFGNode || n instanceof MultiNode ) {
- if( !gap ) sb.p("\n"); // Blank before multihead
- if( n instanceof FunNode fun )
- fun.sig().print(sb.p("--- ").p(fun._name==null ? "" : fun._name).p(" "),false).p("----------------------\n");
- printLine( n, sb ); // Print head
- while( --i >= 0 ) {
- Node t = rpos.get(i);
- if( !(t.in(0) instanceof MultiNode) ) { i++; break; }
- printLine( t, sb );
- }
- if( n instanceof ReturnNode ret ) {
- FunNode fun = ret.fun();
- sb.p("--- ");
- if( fun != null )
- fun.sig().print(sb.p(fun._name==null ? "" : fun._name).p(" "),false);
- sb.p("----------------------\n");
- }
- if( !(n instanceof CallNode) ) {
- sb.p("\n"); // Blank after multitail
- gap = true;
- }
- } else {
- printLine( n, sb );
- gap = false;
- }
- }
- return sb.toString();
- }
-
- private static void postOrd(Node n, Node prior, ArrayList<Node> rpos, BitSet visit, BitSet bfs) {
- if( !bfs.get(n._nid) )
- return; // Not in the BFS visit
- if( n instanceof FunNode && !(prior instanceof StartNode) )
- return; // Only visit Fun from Start
- if( visit.get(n._nid) ) return; // Already post-order walked
- visit.set(n._nid);
- // First walk the CFG, then everything
- if( n instanceof CFGNode ) {
- for( Node use : n._outputs )
- // Follow CFG, not across call/function borders, and not around backedges
- if( use instanceof CFGNode && !(n instanceof CallNode && use instanceof FunNode) &&
- use.nOuts() >= 1 && !(use._outputs.get(0) instanceof LoopNode) )
- postOrd(use, n, rpos,visit,bfs);
- for( Node use : n._outputs )
- // Follow CFG, not across call/function borders
- if( use instanceof CFGNode && !(n instanceof CallNode && use instanceof FunNode) )
- postOrd(use,n,rpos,visit,bfs);
- }
- // Follow all outputs
- for( Node use : n._outputs )
- if( use != null &&
- !(n instanceof CallNode && use instanceof FunNode) &&
- (n instanceof FunNode || !(use instanceof ParmNode)) )
- postOrd(use, n, rpos,visit,bfs);
- // Post-order
- rpos.add(n);
- }
-
- // Breadth-first search, broken out in a class to keep in more independent.
- // Maintains a root-set of Nodes at the limit (or past by 1 if MultiHead).
- public static class BFS {
- // A breadth first search, plus MultiHeads for any MultiTails
- public final ArrayList<Node> _bfs;
- public final BitSet _bs; // Visited members by node id
- public final int _depth; // Depth limit
- public final int _lim; // From here to _bfs._len can be roots for a reverse search
- public BFS( Node base, int d ) {
- _depth = d;
- _bfs = new ArrayList<>();
- _bs = new BitSet();
-
- add(base); // Prime the pump
- int idx=0, lim=1; // Limit is where depth counter changes
- while( idx < _bfs.size() ) { // Ran out of nodes below depth
- Node n = _bfs.get(idx++);
- for( Node def : n._inputs )
- if( def!=null && !_bs.get(def._nid) )
- add(def);
- if( idx==lim ) { // Depth counter changes at limit
- if( --d < 0 )
- break; // Ran out of depth
- lim = _bfs.size(); // New depth limit
- }
- }
- // Toss things past the limit except multi-heads
- while( idx < _bfs.size() ) {
- Node n = _bfs.get(idx);
- if( n instanceof MultiNode ) idx++;
- else del(idx);
- }
- // Root set is any node with no inputs in the visited set
- lim = _bfs.size();
- for( int i=_bfs.size()-1; i>=0; i-- )
- if( !any_visited(_bfs.get(i)) )
- swap( i,--lim);
- _lim = lim;
- }
- void swap( int x, int y ) {
- if( x==y ) return;
- Node tx = _bfs.get(x);
- Node ty = _bfs.get(y);
- _bfs.set(x,ty);
- _bfs.set(y,tx);
- }
- void add(Node n) {
- _bfs.add(n);
- _bs.set(n._nid);
- }
- void del(int idx) {
- _bs.clear(_bfs.get(idx)._nid);
- Utils.del(_bfs, idx);
- }
- boolean any_visited( Node n ) {
- for( Node def : n._inputs )
- if( def!=null && _bs.get(def._nid) )
- return true;
- return false;
- }
- }
-
- public static String _prettyPrint( CodeGen code ) {
- SB sb = new SB();
- // Print the Start "block"
- printLine(code._start,sb);
- for( Node n : code._start._outputs )
- printLine(n,sb);
- sb.nl();
-
- // Skip start, stop
- for( int i=1; i<code._cfg._len-1; i++ ) {
- CFGNode blk = code._cfg.at(i);
- if( blk.blockHead() && (!(blk instanceof CProjNode) || (blk.cfg0() instanceof IfNode )) ) {
- if( blk instanceof FunNode fun )
- sb.p("--- ").p(fun.label()).p(" ---------------------------").nl();
- // Print block header
- sb.p("%-13.13s".formatted(label(blk)+":"));
- sb.p( " ".repeat(4) ).p(" [[ ");
- if( blk instanceof RegionNode )
- for( int j=1; j<blk.nIns(); j++ )
- label(sb,blk.cfg(j));
- else
- label(sb,blk.cfg(0));
- sb.p(" ]] \n");
- }
- printLine(blk,sb);
- if( blk instanceof ReturnNode ret )
- sb.p("--- ").p(ret.fun().label()).p(" ---------------------------").nl();
-
- // Block contents
- for( Node n : blk._outputs ) {
- if( n instanceof CFGNode cfg ) continue;
- printLine(n,sb);
- if( !(n instanceof CFGNode) && n instanceof MultiNode )
- for( Node use : n._outputs )
- if( use instanceof ProjNode )
- printLine(use,sb);
- }
- }
-
- printLine(code._stop,sb);
- return sb.toString();
- }
-
- // Diagnostic block ordering from raw control edges. Do not call idepth():
- // it fills compiler caches (and can walk lazy dominator accessors).
- private static int _idepth(CFGNode cfg, HashMap<Integer,Integer> depths) {
- if( cfg == null || cfg instanceof StartNode || cfg instanceof FunNode ) return cfg instanceof FunNode ? 1 : 0;
- Integer old = depths.get(cfg._nid);
- if( old != null ) return old;
- depths.put(cfg._nid,0); // Break cycles in partially constructed graphs.
- int d = 0;
- if( cfg instanceof LoopNode ) {
- d = _idepth((CFGNode)cfg.in(1),depths)+1;
- } else if( cfg instanceof RegionNode || cfg instanceof StopNode ) {
- for( Node n : cfg._inputs )
- if( n instanceof CFGNode pred ) d = Math.max(d,_idepth(pred,depths)+1);
- } else if( cfg.in(0) instanceof CFGNode pred ) {
- d = _idepth(pred,depths)+1;
- }
- depths.put(cfg._nid,d);
- return d;
- }
-
- // Bulk pretty printer, knowing scheduling information is available
- private static String _prettyPrintScheduled( Node node, int depth ) {
- // Backwards DFS walk to depth.
- HashMap<Integer,Integer> ds = new HashMap<>();
- Ary<Node> ns = new Ary<>(Node.class);
- _walk(ds,ns,node,depth);
- // Remove data projections, these are force-printed behind their multinode head
- for( int i=0; i<ns.size(); i++ ) {
- if( ns.get(i) instanceof ProjNode proj && !(proj.in(0) instanceof CFGNode) ) {
- ns.del(i--);
- ds.remove(proj._nid);
- }
- }
- // Print by block with least diagnostic depth
- HashMap<Integer,Integer> depths = new HashMap<>();
- SB sb = new SB();
- Ary<Node> bns = new Ary<>(Node.class);
- while( !ds.isEmpty() ) {
- CFGNode blk = null;
- for( Node n : ns ) {
- CFGNode cfg = n instanceof CFGNode cfg0 && cfg0.blockHead() ? cfg0 : n.cfg0();
- if( blk==null || _idepth(cfg,depths) < _idepth(blk,depths) )
- blk = cfg;
- }
- Integer d = ds.remove(blk._nid);
- ns.del(ns.find(blk));
-
- // Print block header
- sb.p("%-13.13s".formatted(label(blk)+":"));
- sb.p( " ".repeat(4) ).p(" [[ ");
- if( blk instanceof StartNode ) ;
- else if( blk instanceof RegionNode || blk instanceof StopNode )
- for( int i=(blk instanceof StopNode ? 3 : 1); i<blk.nIns(); i++ )
- label(sb,blk.cfg(i));
- else
- label(sb,blk.cfg(0));
- sb.p(" ]] \n");
- printLine(blk,sb);
-
- // Collect block contents that are in the depth limit
- bns.clear();
- int xd = Integer.MAX_VALUE;
- for( Node use : blk._outputs ) {
- Integer i = ds.get(use._nid);
- if( i!=null && !(use instanceof CFGNode cfg && cfg.blockHead()) ) {
- if( bns.find(use)==-1 )
- bns.add(use);
- xd = Math.min(xd,i);
- }
- }
- // Print Phis up front, if any
- for( int i=0; i<bns.size(); i++ )
- if( bns.get(i) instanceof PhiNode phi )
- printLine( phi, sb,bns,i--,ds,ns);
-
- // Print block contents in depth order, bumping depth until whole block printed
- for( ; !bns.isEmpty(); xd++ )
- for( int i=0; i<bns.size(); i++ ) {
- Node n = bns.get(i);
- if( ds.get(n._nid)==xd ) {
- printLine( n, sb, bns, i--, ds,ns );
- if( n instanceof MultiNode && !(n instanceof CFGNode) ) {
- for( Node use : n._outputs ) {
- if( use instanceof ProjNode )
- printLine(use,sb,bns,bns.indexOf(use),ds,ns);
- }
- }
- }
- }
- sb.p("\n");
- }
- return sb.toString();
- }
-
- private static void _walk( HashMap<Integer,Integer> ds, Ary<Node> ns, Node node, int d ) {
- Integer nd = ds.get(node._nid);
- if( nd!=null && d <= nd ) return; // Been there, done that
- Integer old = ds.put(node._nid,d) ;
- if( old == null )
- ns.add(node);
- if( d == 0 ) return; // Depth cutoff
- for( Node def : node._inputs )
- if( def != null &&
- !(node instanceof LoopNode loop && loop.back()==def) &&
- // Don't walk into or out of functions
- !(node instanceof CallEndNode && def instanceof ReturnNode) &&
- !(node instanceof FunNode && def instanceof CallNode) &&
- !(node instanceof ParmNode && !(def instanceof FunNode))
- )
- _walk(ds,ns,def,d-1);
- }
+import com.seaofnodes.simple.SB;
+import com.seaofnodes.simple.codegen.CodeGen;
- static String label( CFGNode blk ) {
- if( blk instanceof StartNode ) return "START";
- return (blk instanceof LoopNode ? "LOOP" : "L")+blk._nid;
- }
- static void label( SB sb, CFGNode blk ) {
- if( !blk.blockHead() ) blk = blk.cfg(0);
- sb.p( "%-9.9s ".formatted( label( blk ) ) );
+/** This chapter's read-only IR facts and the familiar debugger entry points. */
+public final class IRPrinter extends IRAdapter<Node> {
+ private static final com.seaofnodes.print.IRPrinter<Node> PRINT =
+ new com.seaofnodes.print.IRPrinter<>(new IRPrinter());
+ @Override public boolean global(Node n) { return n.isConst(); }
+ @Override public String type(Node n) { return n._type==null ? "" : n._type.str(); }
+ @Override public String inputMark(Node n, Node def) { return n instanceof MemMergeNode && def instanceof MemMergeNode ? "^" : " "; }
+ @Override public Kind kind(Node n) {
+ if( n instanceof StartNode ) return Kind.START;
+ if( n instanceof StopNode ) return Kind.STOP;
+ if( n instanceof FunNode ) return Kind.FUN;
+ if( n instanceof LoopNode ) return Kind.LOOP;
+ if( n instanceof RegionNode ) return Kind.REGION;
+ if( n instanceof ParmNode ) return Kind.PARM;
+ if( n instanceof PhiNode ) return Kind.PHI;
+ if( n instanceof CallEndNode ) return Kind.CALL_END;
+ if( n instanceof CallNode ) return Kind.CALL;
+ if( n instanceof ReturnNode ) return Kind.RETURN;
+ if( n instanceof ConstantNode ) return Kind.CONSTANT;
+ if( n instanceof CProjNode ) return Kind.CPROJ;
+ if( n instanceof ProjNode ) return n instanceof CFGNode ? Kind.CPROJ : Kind.PROJ;
+ if( n instanceof CFGNode ) return Kind.CTRL;
+ if( n instanceof MultiNode ) return Kind.MULTI;
+ return Kind.DATA;
+ }
+ @Override public int index(Node n) {
+ if( n instanceof ProjNode p ) return p._idx;
+ if( n instanceof CProjNode p ) return p._idx;
+ return n._nid;
+ }
+ @Override public String functionName(Node n) { return ((FunNode)n)._name==null ? "" : ((FunNode)n)._name; }
+ @Override public String signature(Node n) {
+ FunNode fun=(FunNode)n;
+ return (fun._name==null ? "" : fun._name)+" "+fun.sig().str();
+ }
+
+ public static String prettyPrint(Node n, int depth) { return PRINT.prettyPrint(n,depth); }
+ public static SB printLine(Node n, SB sb) { return sb.p(PRINT.line(n)); }
+
+ public static String prettyPrint(CodeGen code) {
+ var units=new ArrayList<com.seaofnodes.print.IRPrinter.Unit<Node>>();
+ var funs=new ArrayList<Node>();
+ for( Node n : code._start._outputs ) if( n instanceof FunNode ) funs.add(n);
+ units.add(new com.seaofnodes.print.IRPrinter.Unit<>(null,null,null,funs));
+ return PRINT.program(code._start,code._stop,units);
+ }
+ public static String _prettyPrint(CodeGen code) {
+ if( code._cfg==null ) return prettyPrint(code);
+ var blocks=new ArrayList<Node>();
+ for( Node n : code._cfg ) blocks.add(n);
+ return PRINT.scheduled(blocks);
}
- static void printLine( Node n, SB sb, Ary<Node> bns, int i, HashMap<Integer,Integer> ds, Ary<Node> ns ) {
- printLine( n, sb );
- if( i != -1 ) bns.del(i);
- ds.remove(n._nid);
- int idx = ns.find(n);
- if( idx!=-1 ) ns.del(idx);
- }
-
}
diff --git a/chapter22/src/main/java/com/seaofnodes/simple/print/SimpleGraphAdapter.java b/chapter22/src/main/java/com/seaofnodes/simple/print/SimpleGraphAdapter.java
index d3f22a6d..3d10a80c 100644
--- a/chapter22/src/main/java/com/seaofnodes/simple/print/SimpleGraphAdapter.java
+++ b/chapter22/src/main/java/com/seaofnodes/simple/print/SimpleGraphAdapter.java
@@ -1,45 +1,25 @@
package com.seaofnodes.simple.print;
import com.seaofnodes.graph.GraphAdapter;
-import com.seaofnodes.graph.GraphSnapshot;
import com.seaofnodes.graph.GraphSnapshot.*;
import com.seaofnodes.simple.node.*;
import com.seaofnodes.simple.node.Node;
import com.seaofnodes.simple.type.TypeMem;
-import java.util.ArrayList;
/** Chapter 22's view of the IR; browser, transport and layout are shared. */
public class SimpleGraphAdapter extends GraphAdapter<Node> {
- @Override protected boolean dead(Node n) { return n.isDead(); }
- @Override protected int id(Node n) { return n._nid; }
- @Override protected int nIns(Node n) { return n.nIns(); }
- @Override protected Node in(Node n, int idx) { return n.in(idx); }
- @Override protected int nOuts(Node n) { return n.nOuts(); }
- @Override protected Node out(Node n, int idx) { return n.out(idx); }
- @Override protected int nDeps(Node n) { return n.nDeps(); }
- @Override protected Node dep(Node n, int idx) { return n.dep(idx); }
- private ArrayList<Edge> edges(Node n) {
- var edges = new ArrayList<Edge>();
- for( int i = 0; i < n.nIns(); i++ ) {
- String name = n instanceof ScopeNode scope && i < scope._vars.size()
+ @Override protected String edgeName(Node n, int i) {
+ return n instanceof ScopeNode scope && i < scope._vars.size()
? scope._vars.get(i)._name : null;
- int jump = n instanceof CallEndNode && i>0 && n.in(i) instanceof ReturnNode ret
- ? ref(ret.fun()) : 0;
- edges.add(new Edge(i, ref(n.in(i)), role(n, i), name, jump));
- }
- return edges;
}
-
- @Override protected GraphSnapshot.Node desc(Node n) {
- Projection proj = n instanceof ProjNode p ? new Projection(ref(n.in(0)), p._idx)
- : n instanceof CProjNode p ? new Projection(ref(n.in(0)), p._idx) : null;
- String label = n.label();
- return new GraphSnapshot.Node(n._nid, label == null ? n.getClass().getSimpleName() : label,
- n._type == null ? null : n._type.toString(), kind(n), edges(n), proj, folding(n));
+ @Override protected int edgeJump(Node n, int i) {
+ return n instanceof CallEndNode && i>0 && n.in(i) instanceof ReturnNode ret
+ ? ref(ret.fun()) : 0;
}
+ @Override protected int projectionIndex(Node n) { return n instanceof ProjNode p ? p._idx : n instanceof CProjNode p ? p._idx : -1; }
- private boolean folding(Node n) {
+ @Override protected boolean folding(Node n) {
if( n instanceof FunNode fun ) return fun.folding();
if( n instanceof ReturnNode ret ) return ret.fun().folding();
if( n instanceof CallEndNode cend ) return cend.folding();
@@ -49,7 +29,7 @@ public class SimpleGraphAdapter extends GraphAdapter<Node> {
return false;
}
- private Kind kind(Node n) {
+ @Override protected Kind kind(Node n) {
if( n instanceof StopNode ) return Kind.STOP;
if( n instanceof ScopeNode ) return Kind.SCOPE;
if( n instanceof FunNode ) return Kind.FUN;
@@ -60,7 +40,7 @@ public class SimpleGraphAdapter extends GraphAdapter<Node> {
return n instanceof CFGNode ? Kind.CTRL : isMem(n) ? Kind.MEM : Kind.DATA;
}
- private Role role(Node n, int i) {
+ @Override protected Role role(Node n, int i) {
if( n instanceof ScopeNode || n instanceof ConstantNode || n instanceof CtrlNode || n instanceof XCtrlNode ) return Role.ASSOC;
if( n instanceof PhiNode ) return i == 0 ? Role.ASSOC : isMem(n) ? Role.MEM : Role.DATA;
if( n instanceof ProjNode || n instanceof CProjNode )
diff --git a/chapter23/Makefile b/chapter23/Makefile
index f2c05809..9725bc7d 100644
--- a/chapter23/Makefile
+++ b/chapter23/Makefile
@@ -65,6 +65,7 @@ main_javas := $(wildcard $(SRC)/$(SIMPLE)/*java $(SRC)/$(SIMPLE)/*/*java $(SRC
test_javas := $(wildcard $(TST)/$(SIMPLE)/*java $(TST)/$(SIMPLE)/*/*java)
main_classes := $(patsubst $(SRC)/%java,$(CLZDIR)/main/%class,$(main_javas))
include $(firstword $(wildcard ../graph/graph.mk graph/graph.mk))
+include $(firstword $(wildcard ../print/print.mk print/print.mk))
test_classes := $(patsubst $(TST)/%java,$(CLZDIR)/test/%class,$(test_javas))
test_cp := $(patsubst $(TST)/$(SIMPLE)/%.java,com.seaofnodes.simple.%,$(wildcard $(TST)/$(SIMPLE)/*Test.java)) com.seaofnodes.simple.codegen.X86EncodingTest
classes = $(main_classes) $(test_classes)
diff --git a/chapter23/pom.xml b/chapter23/pom.xml
index 7a2b2b78..e3547147 100644
--- a/chapter23/pom.xml
+++ b/chapter23/pom.xml
@@ -13,5 +13,6 @@
<name>Chapter 23</name>
<properties>
<simple.graph.directory>${project.basedir}/../graph</simple.graph.directory>
+ <simple.print.directory>${project.basedir}/../print</simple.print.directory>
</properties>
</project>
diff --git a/chapter23/src/main/java/com/seaofnodes/simple/codegen/CodeGen.java b/chapter23/src/main/java/com/seaofnodes/simple/codegen/CodeGen.java
index 50490689..9bf1aa61 100644
--- a/chapter23/src/main/java/com/seaofnodes/simple/codegen/CodeGen.java
+++ b/chapter23/src/main/java/com/seaofnodes/simple/codegen/CodeGen.java
@@ -472,7 +472,7 @@ public class CodeGen {
@Override public String toString() {
return _phase.ordinal() > Phase.Schedule.ordinal()
? IRPrinter._prettyPrint( this )
- : _stop.p(9999);
+ : IRPrinter.prettyPrint(this);
}
// Debugging helper
diff --git a/chapter23/src/main/java/com/seaofnodes/simple/node/AddFNode.java b/chapter23/src/main/java/com/seaofnodes/simple/node/AddFNode.java
index ba5815da..fd713156 100644
--- a/chapter23/src/main/java/com/seaofnodes/simple/node/AddFNode.java
+++ b/chapter23/src/main/java/com/seaofnodes/simple/node/AddFNode.java
@@ -1,21 +1,16 @@
package com.seaofnodes.simple.node;
+
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeFloat;
-import java.util.BitSet;
public class AddFNode extends Node {
public AddFNode(Node lhs, Node rhs) { super(null, lhs, rhs); }
@Override public String label() { return "AddF"; }
- @Override
- public StringBuilder _print1(StringBuilder sb, BitSet visited) {
- in(1)._print0(sb.append("("), visited);
- in(2)._print0(sb.append("+"), visited);
- return sb.append(")");
- }
+ @Override protected String format() { return "(%1+%2)"; }
@Override
public Type compute() {
diff --git a/chapter23/src/main/java/com/seaofnodes/simple/node/ArithNode.java b/chapter23/src/main/java/com/seaofnodes/simple/node/ArithNode.java
index 2be8e4a2..124acbd7 100644
--- a/chapter23/src/main/java/com/seaofnodes/simple/node/ArithNode.java
+++ b/chapter23/src/main/java/com/seaofnodes/simple/node/ArithNode.java
@@ -1,10 +1,11 @@
package com.seaofnodes.simple.node;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.Parser;
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeInteger;
-import java.util.BitSet;
public abstract class ArithNode extends Node {
// Source location for late reported errors
@@ -13,11 +14,8 @@ public abstract class ArithNode extends Node {
public ArithNode( Parser.Lexer loc, Node lhs, Node rhs) { super(null, lhs, rhs); _loc = loc; }
abstract String op();
- @Override
- public StringBuilder _print1(StringBuilder sb, BitSet visited) {
- in(1)._print0(sb.append("("), visited);
- in(2)._print0(sb.append(op()), visited);
- return sb.append(")");
+ @Override protected ExprPrinter<Node> _print1(ExprPrinter<Node> p) {
+ return p.open().n(in(1)).p(op()).n(in(2)).close();
}
abstract long doOp(long x, long y);
diff --git a/chapter23/src/main/java/com/seaofnodes/simple/node/BoolNode.java b/chapter23/src/main/java/com/seaofnodes/simple/node/BoolNode.java
index 1a837435..0d82c5b9 100644
--- a/chapter23/src/main/java/com/seaofnodes/simple/node/BoolNode.java
+++ b/chapter23/src/main/java/com/seaofnodes/simple/node/BoolNode.java
@@ -1,9 +1,10 @@
package com.seaofnodes.simple.node;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.Parser;
import com.seaofnodes.simple.type.*;
import com.seaofnodes.simple.util.Utils;
-import java.util.BitSet;
import static com.seaofnodes.simple.type.TypeInteger.*;
abstract public class BoolNode extends Node {
@@ -17,11 +18,8 @@ abstract public class BoolNode extends Node {
@Override
public String label() { return getClass().getSimpleName(); }
- @Override
- public StringBuilder _print1(StringBuilder sb, BitSet visited) {
- in(1)._print0(sb.append("("), visited);
- in(2)._print0(sb.append(op()), visited);
- return sb.append(")");
+ @Override protected ExprPrinter<Node> _print1(ExprPrinter<Node> p) {
+ return p.open().n(in(1)).p(op()).n(in(2)).close();
}
@Override
diff --git a/chapter23/src/main/java/com/seaofnodes/simple/node/CProjNode.java b/chapter23/src/main/java/com/seaofnodes/simple/node/CProjNode.java
index a6e21ea0..1225de31 100644
--- a/chapter23/src/main/java/com/seaofnodes/simple/node/CProjNode.java
+++ b/chapter23/src/main/java/com/seaofnodes/simple/node/CProjNode.java
@@ -1,11 +1,12 @@
package com.seaofnodes.simple.node;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.Parser;
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeMem;
import com.seaofnodes.simple.type.TypeTuple;
import com.seaofnodes.simple.util.Utils;
-import java.util.BitSet;
public class CProjNode extends CFGNode {
@@ -24,7 +25,7 @@ public class CProjNode extends CFGNode {
@Override public String label() { return _label; }
- @Override public StringBuilder _print1(StringBuilder sb, BitSet visited) { return sb.append(_label); }
+ @Override protected ExprPrinter<Node> _print1(ExprPrinter<Node> p) { return p.p(_label); }
@Override public boolean blockHead() { return true; }
diff --git a/chapter23/src/main/java/com/seaofnodes/simple/node/CallEndNode.java b/chapter23/src/main/java/com/seaofnodes/simple/node/CallEndNode.java
index 1b702bee..cdf12a12 100644
--- a/chapter23/src/main/java/com/seaofnodes/simple/node/CallEndNode.java
+++ b/chapter23/src/main/java/com/seaofnodes/simple/node/CallEndNode.java
@@ -1,9 +1,10 @@
package com.seaofnodes.simple.node;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.*;
import com.seaofnodes.simple.codegen.*;
import com.seaofnodes.simple.type.*;
-import java.util.BitSet;
/**
* CallEnd
@@ -29,13 +30,12 @@ public class CallEndNode extends CFGNode implements MultiNode {
}
@Override
- public StringBuilder _print1(StringBuilder sb, BitSet visited) {
- sb.append("cend( ");
- sb.append( in(0) instanceof CallNode ? "Call, " : "----, ");
+ protected ExprPrinter<Node> _print1(ExprPrinter<Node> p) {
+ p.p("cend( ");
+ p.p( in(0) instanceof CallNode ? "Call, " : "----, ");
for( int i=1; i<nIns()-1; i++ )
- in(i)._print0(sb,visited).append(",");
- sb.setLength(sb.length()-1);
- return sb.append(")");
+ p.n(in(i)).p(",");
+ return p.unchar(',').unchar(' ').close();
}
@Override
diff --git a/chapter23/src/main/java/com/seaofnodes/simple/node/CallNode.java b/chapter23/src/main/java/com/seaofnodes/simple/node/CallNode.java
index 633197fa..215e3c78 100644
--- a/chapter23/src/main/java/com/seaofnodes/simple/node/CallNode.java
+++ b/chapter23/src/main/java/com/seaofnodes/simple/node/CallNode.java
@@ -1,12 +1,13 @@
package com.seaofnodes.simple.node;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.IterPeeps;
import com.seaofnodes.simple.Parser;
import com.seaofnodes.simple.codegen.CodeGen;
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeFunPtr;
import com.seaofnodes.simple.util.Utils;
-import java.util.BitSet;
/**
* Call
@@ -21,15 +22,14 @@ public class CallNode extends CFGNode {
@Override public String label() { return "Call"; }
- @Override public StringBuilder _print1(StringBuilder sb, BitSet visited) {
+ @Override protected ExprPrinter<Node> _print1(ExprPrinter<Node> p) {
String fname = name();
- if( fname == null ) fptr()._print0(sb,visited);
- else sb.append(fname);
- sb.append("( ");
+ if( fname == null ) p.n(fptr());
+ else p.p(fname);
+ p.p("( ");
for( int i=2; i<nIns()-1; i++ )
- in(i)._print0(sb,visited).append(",");
- sb.setLength(sb.length()-1);
- return sb.append(")");
+ p.n(in(i)).p(",");
+ return p.unchar(',').unchar(' ').close();
}
public String name() {
if( fptr()._type instanceof TypeFunPtr tfp && tfp._isConstant() && tfp.notNull() ) {
diff --git a/chapter23/src/main/java/com/seaofnodes/simple/node/CastNode.java b/chapter23/src/main/java/com/seaofnodes/simple/node/CastNode.java
index f3436f56..08d72e35 100644
--- a/chapter23/src/main/java/com/seaofnodes/simple/node/CastNode.java
+++ b/chapter23/src/main/java/com/seaofnodes/simple/node/CastNode.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.Type;
import com.seaofnodes.simple.type.TypeInteger;
import com.seaofnodes.simple.type.TypeMemPtr;
import com.seaofnodes.simple.util.Utils;
-import java.util.BitSet;
// Upcast (join) the input to a t. Used after guard test to lift an input.
// Can also be used to make a type-assertion if ctrl is null.
@@ -25,14 +26,11 @@ public class CastNode extends Node {
@Override public String label() { return "("+_t.str()+")"; }
- @Override
- public String uniqueName() { return "Cast_" + _nid; }
@Override public boolean isConst() { return true; }
- @Override
- public StringBuilder _print1(StringBuilder sb, BitSet visited) {
- return in(1)._print0(sb.append(label()), visited);
+ @Override protected ExprPrinter<Node> _print1(ExprPrinter<Node> p) {
+ return p.p(label()).n(in(1));
}
@Override
diff --git a/chapter23/src/main/java/com/seaofnodes/simple/node/ConFldOffNode.java b/chapter23/src/main/java/com/seaofnodes/simple/node/ConFldOffNode.java
index 234b37d9..04b88b87 100644
--- a/chapter23/src/main/java/com/seaofnodes/simple/node/ConFldOffNode.java
+++ b/chapter23/src/main/java/com/seaofnodes/simple/node/ConFldOffNode.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.TypeInteger;
import com.seaofnodes.simple.type.TypeStruct;
import com.seaofnodes.simple.util.SB;
-import java.util.BitSet;
/**
* A field offset. This becomes a constant *after* other optimizations which
@@ -21,11 +22,9 @@ public class ConFldOffNode extends ConstantNode {
@Override public String label() {
return _fname == " len" ? "sizeof("+_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());
}
// Convert field offset to an integer
diff --git a/chapter23/src/main/java/com/seaofnodes/simple/node/ConstantNode.java b/chapter23/src/main/java/com/seaofnodes/simple/node/ConstantNode.java
index 0d7c0964..6384228e 100644
--- a/chapter23/src/main/java/com/seaofnodes/simple/node/ConstantNode.java
+++ b/chapter23/src/main/java/com/seaofnodes/simple/node/ConstantNode.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.Type;
import com.seaofnodes.simple.type.TypeFunPtr;
import com.seaofnodes.simple.util.SB;
-import java.util.BitSet;
/**
* A Constant node represents a constant value.
@@ -34,17 +35,20 @@ public class ConstantNode extends Node {
return new ConstantNode(type);
}
- @Override public String label() { return "#"+_con; }
- @Override public String uniqueName() { return "Con_" + _nid; }
+ @Override protected String repeatName() {
+ return _con==null || _con.toString().length()<=32 ? null : uniqueName();
+ }
+
+ @Override public String label() { return "Con"; }
@Override
- public StringBuilder _print1(StringBuilder sb, BitSet visited) {
+ protected ExprPrinter<Node> _print1(ExprPrinter<Node> p) {
if( _con instanceof TypeFunPtr tfp && tfp._isConstant() && tfp.notNull() ) {
FunNode fun = CodeGen.CODE.link(tfp);
if( fun!=null && fun._name != null )
- return sb.append("{ ").append(fun._name).append("}");
+ return p.p("{ ").p(fun._name).p("}");
}
- return sb.append(_con==null ? "---" : _con.toString());
+ return p.p(_con==null ? "---" : _con.toString());
}
@Override public boolean isConst() { return true; }
diff --git a/chapter23/src/main/java/com/seaofnodes/simple/node/CtrlNode.java b/chapter23/src/main/java/com/seaofnodes/simple/node/CtrlNode.java
index eda7d684..cf630ad4 100644
--- a/chapter23/src/main/java/com/seaofnodes/simple/node/CtrlNode.java
+++ b/chapter23/src/main/java/com/seaofnodes/simple/node/CtrlNode.java
@@ -1,14 +1,15 @@
package com.seaofnodes.simple.node;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.codegen.CodeGen;
import com.seaofnodes.simple.Parser;
import com.seaofnodes.simple.type.Type;
-import java.util.BitSet;
public class CtrlNode extends CFGNode {
public CtrlNode() { super(CodeGen.CODE._start); }
@Override public String label() { return "Ctrl"; }
- @Override public StringBuilder _print1(StringBuilder sb, BitSet visited) { return sb.append("Cctrl"); }
+ @Override protected ExprPrinter<Node> _print1(ExprPrinter<Node> p) { return p.p("Cctrl"); }
@Override public boolean isConst() { return true; }
@Override public Type compute() { return Type.CONTROL; }
@Override public Node idealize() { return null; }
diff --git a/chapter23/src/main/java/com/seaofnodes/simple/node/DivFNode.java b/chapter23/src/main/java/com/seaofnodes/simple/node/DivFNode.java
index 2180ab46..149499f9 100644
--- a/chapter23/src/main/java/com/seaofnodes/simple/node/DivFNode.java
+++ b/chapter23/src/main/java/com/seaofnodes/simple/node/DivFNode.java
@@ -1,21 +1,16 @@
package com.seaofnodes.simple.node;
+
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeFloat;
-import java.util.BitSet;
public class DivFNode extends Node {
public DivFNode(Node lhs, Node rhs) { super(null, lhs, rhs); }
@Override public String label() { return "DivF"; }
- @Override
- public StringBuilder _print1(StringBuilder sb, BitSet visited) {
- in(1)._print0(sb.append("("), visited);
- in(2)._print0(sb.append("/"), visited);
- return sb.append(")");
- }
+ @Override protected String format() { return "(%1/%2)"; }
@Override
public Type compute() {
diff --git a/chapter23/src/main/java/com/seaofnodes/simple/node/ExternNode.java b/chapter23/src/main/java/com/seaofnodes/simple/node/ExternNode.java
index 21ef8eff..ccbcfc66 100644
--- a/chapter23/src/main/java/com/seaofnodes/simple/node/ExternNode.java
+++ b/chapter23/src/main/java/com/seaofnodes/simple/node/ExternNode.java
@@ -16,7 +16,6 @@ public class ExternNode extends ConstantNode {
public ExternNode(Type t, String ex) { super(t); _extern = ex; }
@Override public String label() { return "#"+_con+":"+_extern; }
- @Override public String uniqueName() { return "Extern_" + _nid; }
@Override public boolean eq(Node n) { return this==n; }
}
diff --git a/chapter23/src/main/java/com/seaofnodes/simple/node/FRefNode.java b/chapter23/src/main/java/com/seaofnodes/simple/node/FRefNode.java
index 6093b8a6..e7333c23 100644
--- a/chapter23/src/main/java/com/seaofnodes/simple/node/FRefNode.java
+++ b/chapter23/src/main/java/com/seaofnodes/simple/node/FRefNode.java
@@ -1,9 +1,10 @@
package com.seaofnodes.simple.node;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.Parser;
import com.seaofnodes.simple.Var;
import com.seaofnodes.simple.type.Type;
-import java.util.BitSet;
/**
* A Forward Reference. Its any final constant, including functions. When
@@ -17,10 +18,9 @@ public class FRefNode extends ConstantNode {
@Override public String label() { return "FRef"+_n; }
- @Override public String uniqueName() { return "FRef_" + _nid; }
- @Override public StringBuilder _print1(StringBuilder sb, BitSet visited) {
- return sb.append("FRef_").append(_n);
+ @Override protected ExprPrinter<Node> _print1(ExprPrinter<Node> p) {
+ return p.p("FRef_").p(_n);
}
@Override public Node idealize() {
diff --git a/chapter23/src/main/java/com/seaofnodes/simple/node/FunPtrNode.java b/chapter23/src/main/java/com/seaofnodes/simple/node/FunPtrNode.java
index 7f32698e..43242c32 100644
--- a/chapter23/src/main/java/com/seaofnodes/simple/node/FunPtrNode.java
+++ b/chapter23/src/main/java/com/seaofnodes/simple/node/FunPtrNode.java
@@ -9,5 +9,4 @@ public class FunPtrNode extends ConstantNode {
addDef(ret);
}
public ReturnNode ret() { return (ReturnNode)in(1); }
- @Override public String uniqueName() { return "FunPtr_"+_nid; }
}
diff --git a/chapter23/src/main/java/com/seaofnodes/simple/node/IfNode.java b/chapter23/src/main/java/com/seaofnodes/simple/node/IfNode.java
index c5d687e5..da6a0cde 100644
--- a/chapter23/src/main/java/com/seaofnodes/simple/node/IfNode.java
+++ b/chapter23/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 {
@@ -17,11 +18,11 @@ public class IfNode extends CFGNode implements MultiNode {
public String label() { return "If"; }
@Override
- public StringBuilder _print1(StringBuilder sb, BitSet visited) {
- sb.append("if( ");
- if( in(1)==null ) sb.append("never");
- else in(1)._print0(sb, visited);
- return sb.append(" )");
+ protected ExprPrinter<Node> _print1(ExprPrinter<Node> p) {
+ p.p("if( ");
+ if( in(1)==null ) p.p("never");
+ else p.n(in(1));
+ return p.p(" )");
}
public Node ctrl() { return in(0); }
diff --git a/chapter23/src/main/java/com/seaofnodes/simple/node/LoadNode.java b/chapter23/src/main/java/com/seaofnodes/simple/node/LoadNode.java
index 8b526be2..31844741 100644
--- a/chapter23/src/main/java/com/seaofnodes/simple/node/LoadNode.java
+++ b/chapter23/src/main/java/com/seaofnodes/simple/node/LoadNode.java
@@ -1,5 +1,7 @@
package com.seaofnodes.simple.node;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.codegen.CodeGen;
import com.seaofnodes.simple.Parser;
import com.seaofnodes.simple.type.*;
@@ -46,7 +48,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/chapter23/src/main/java/com/seaofnodes/simple/node/MachConcreteNode.java b/chapter23/src/main/java/com/seaofnodes/simple/node/MachConcreteNode.java
index 9440a7ea..9c0755b9 100644
--- a/chapter23/src/main/java/com/seaofnodes/simple/node/MachConcreteNode.java
+++ b/chapter23/src/main/java/com/seaofnodes/simple/node/MachConcreteNode.java
@@ -1,9 +1,10 @@
package com.seaofnodes.simple.node;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.util.Utils;
import java.io.ByteArrayOutputStream;
-import java.util.BitSet;
// Generic machine-specific class, has a few Node implementations that have to
// exist (abstract) but are not useful past the optimizer.
@@ -16,12 +17,11 @@ public abstract class MachConcreteNode extends Node implements MachNode {
@Override public Type compute () { throw Utils.TODO(); }
@Override public Node idealize() { throw Utils.TODO(); }
- @Override public StringBuilder _print1(StringBuilder sb, BitSet visited) {
- sb.append("(").append(op()).append(",");
+ @Override protected ExprPrinter<Node> _print1(ExprPrinter<Node> p) {
+ p.open().p(op()).p(",");
for( int i=1; i<nIns(); i++ )
- (in(i)==null ? sb.append(" ---") : in(i)._print0(sb, visited)).append(",");
- sb.setLength(sb.length()-1);
- return sb.append(")");
+ (in(i)==null ? p.p(" ---") : p.n(in(i))).p(",");
+ return p.unchar(',').close();
}
}
diff --git a/chapter23/src/main/java/com/seaofnodes/simple/node/MemMergeNode.java b/chapter23/src/main/java/com/seaofnodes/simple/node/MemMergeNode.java
index e56eeb06..ad173bc3 100644
--- a/chapter23/src/main/java/com/seaofnodes/simple/node/MemMergeNode.java
+++ b/chapter23/src/main/java/com/seaofnodes/simple/node/MemMergeNode.java
@@ -1,5 +1,7 @@
package com.seaofnodes.simple.node;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.*;
import com.seaofnodes.simple.codegen.CodeGen;
import com.seaofnodes.simple.type.*;
@@ -53,14 +55,14 @@ public class MemMergeNode extends Node {
@Override public String label() { return "MemMerge"; }
@Override public boolean isMem() { return true; }
@Override public Type compute() { return TypeMem.BOT; }
- @Override public StringBuilder _print1(StringBuilder sb, BitSet visited) {
- sb.append("MEM[");
+ @Override protected ExprPrinter<Node> _print1(ExprPrinter<Node> p) {
+ p.p("MEM[");
for( int i=1; i<nIns(); i++ )
if( in(i)!=null ) {
- sb.append(i==1 ? "default:" : i+":");
- in(i)._print0(sb,visited).append(" ");
+ p.p(i==1 ? "default:" : i+":");
+ p.n(in(i)).p(" ");
}
- return sb.append("]");
+ return p.p("]");
}
@Override public Node idealize() {
diff --git a/chapter23/src/main/java/com/seaofnodes/simple/node/MemOpNode.java b/chapter23/src/main/java/com/seaofnodes/simple/node/MemOpNode.java
index 65021110..e7b2c792 100644
--- a/chapter23/src/main/java/com/seaofnodes/simple/node/MemOpNode.java
+++ b/chapter23/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.type.Type;
import com.seaofnodes.simple.type.TypeMemPtr;
@@ -85,8 +87,8 @@ public abstract class MemOpNode extends Node {
public Node ptr() { return in(2); }
public Node off() { return in(3); }
- @Override public StringBuilder _print1( StringBuilder sb, BitSet visited ) { return _printMach(sb,visited); }
- public StringBuilder _printMach( StringBuilder sb, BitSet visited ) { throw Utils.TODO(); }
+ @Override protected ExprPrinter<Node> _print1(ExprPrinter<Node> p) { return _printMach(p); }
+ protected ExprPrinter<Node> _printMach(ExprPrinter<Node> p) { throw Utils.TODO(); }
public int log_size() { return _declaredType.log_size(); }
// Extra conditions for factoring matching memory operations through a Phi.
diff --git a/chapter23/src/main/java/com/seaofnodes/simple/node/MinusFNode.java b/chapter23/src/main/java/com/seaofnodes/simple/node/MinusFNode.java
index bfdb41cc..852e646d 100644
--- a/chapter23/src/main/java/com/seaofnodes/simple/node/MinusFNode.java
+++ b/chapter23/src/main/java/com/seaofnodes/simple/node/MinusFNode.java
@@ -1,20 +1,16 @@
package com.seaofnodes.simple.node;
+
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeFloat;
-import java.util.BitSet;
public class MinusFNode extends Node {
public MinusFNode(Node in) { super(null, in); }
@Override public String label() { return "MinusF"; }
- @Override
- public StringBuilder _print1(StringBuilder sb, BitSet visited) {
- in(1)._print0(sb.append("(-"), visited);
- return sb.append(")");
- }
+ @Override protected String format() { return "(-%1)"; }
@Override
public Type compute() {
diff --git a/chapter23/src/main/java/com/seaofnodes/simple/node/MinusNode.java b/chapter23/src/main/java/com/seaofnodes/simple/node/MinusNode.java
index a0550609..0a2348f7 100644
--- a/chapter23/src/main/java/com/seaofnodes/simple/node/MinusNode.java
+++ b/chapter23/src/main/java/com/seaofnodes/simple/node/MinusNode.java
@@ -1,20 +1,16 @@
package com.seaofnodes.simple.node;
+
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeInteger;
import com.seaofnodes.simple.util.Utils;
-import java.util.BitSet;
public class MinusNode extends Node {
public MinusNode(Node in) { super(null, in); }
@Override public String label() { return "Minus"; }
- @Override
- public StringBuilder _print1(StringBuilder sb, BitSet visited) {
- in(1)._print0(sb.append("(-"), visited);
- return sb.append(")");
- }
+ @Override protected String format() { return "(-%1)"; }
@Override
public Type compute() {
diff --git a/chapter23/src/main/java/com/seaofnodes/simple/node/MulFNode.java b/chapter23/src/main/java/com/seaofnodes/simple/node/MulFNode.java
index 0fc062cd..6a57f3c5 100644
--- a/chapter23/src/main/java/com/seaofnodes/simple/node/MulFNode.java
+++ b/chapter23/src/main/java/com/seaofnodes/simple/node/MulFNode.java
@@ -1,21 +1,16 @@
package com.seaofnodes.simple.node;
+
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeFloat;
-import java.util.BitSet;
public class MulFNode extends Node {
public MulFNode(Node lhs, Node rhs) { super(null, lhs, rhs); }
@Override public String label() { return "MulF"; }
- @Override
- public StringBuilder _print1(StringBuilder sb, BitSet visited) {
- in(1)._print0(sb.append("("), visited);
- in(2)._print0(sb.append("*"), visited);
- return sb.append(")");
- }
+ @Override protected String format() { return "(%1*%2)"; }
@Override
public Type compute() {
diff --git a/chapter23/src/main/java/com/seaofnodes/simple/node/NeverNode.java b/chapter23/src/main/java/com/seaofnodes/simple/node/NeverNode.java
index 516f218b..66879b66 100644
--- a/chapter23/src/main/java/com/seaofnodes/simple/node/NeverNode.java
+++ b/chapter23/src/main/java/com/seaofnodes/simple/node/NeverNode.java
@@ -1,11 +1,12 @@
package com.seaofnodes.simple.node;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.Parser;
import com.seaofnodes.simple.type.TypeInteger;
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeTuple;
-import java.util.BitSet;
// "Never true" for infinite loop exits
public class NeverNode extends IfNode {
@@ -14,7 +15,7 @@ public class NeverNode extends IfNode {
@Override public String label() { return "Never"; }
- @Override public StringBuilder _print1(StringBuilder sb, BitSet visited) { return sb.append("Never"); }
+ @Override protected ExprPrinter<Node> _print1(ExprPrinter<Node> p) { return p.p("Never"); }
@Override public Type compute() { return TypeTuple.IF_BOTH; }
diff --git a/chapter23/src/main/java/com/seaofnodes/simple/node/NewNode.java b/chapter23/src/main/java/com/seaofnodes/simple/node/NewNode.java
index 49a82a87..3c2a8de3 100644
--- a/chapter23/src/main/java/com/seaofnodes/simple/node/NewNode.java
+++ b/chapter23/src/main/java/com/seaofnodes/simple/node/NewNode.java
@@ -1,10 +1,11 @@
package com.seaofnodes.simple.node;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.codegen.*;
import com.seaofnodes.simple.type.*;
import com.seaofnodes.simple.util.SB;
-import java.util.BitSet;
/** Allocate a zeroed object. Inputs {ctrl, $mem, size};
* results {ptr, $mem}.
@@ -37,10 +38,8 @@ public class NewNode extends Node implements MultiNode {
@Override public String label() { return "new_"+(_ptr._obj.isAry() ? "ary_"+_ptr._obj._fields[1]._t.str() : _ptr._obj.str()); }
- @Override
- public StringBuilder _print1(StringBuilder sb, BitSet visited) {
- sb.append("new ");
- return sb.append(_ptr._obj.str());
+ @Override protected ExprPrinter<Node> _print1(ExprPrinter<Node> p) {
+ return p.p("new ").p(_ptr._obj.str());
}
diff --git a/chapter23/src/main/java/com/seaofnodes/simple/node/Node.java b/chapter23/src/main/java/com/seaofnodes/simple/node/Node.java
index c27270b6..3eacbb16 100644
--- a/chapter23/src/main/java/com/seaofnodes/simple/node/Node.java
+++ b/chapter23/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.Parser;
import com.seaofnodes.simple.util.Ary;
import com.seaofnodes.simple.util.Utils;
@@ -17,14 +19,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.
@@ -46,16 +41,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);
@@ -67,8 +60,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;
@@ -79,48 +72,6 @@ public abstract class Node implements Cloneable {
// Easy reading label for debugger, e.g. "Add" or "Region" or "EQ"
public abstract String label();
- // Unique label for debugging, e.g. "Add12" or "Region30" or "EQ99"
- public String uniqueName() {
- return label() + _nid;
- }
-
- // Operator symbol used by assembly/debug printing.
- public String glabel() { return label(); }
-
- // Extra fun stuff, for assembly printing. Jump labels, parser locations,
- // variable types, etc.
- public String comment() { return null; }
-
- // ------------------------------------------------------------------------
-
- // Debugger Printing.
-
- // {@code toString} is what you get in the debugger. It has to print 1
- // line (because this is what a debugger typically displays by default) and
- // has to be robust with broken graph/nodes.
- @Override
- public final String toString() { return print(); }
-
- // This is a *deep* print. We print with a mutually recursive tik-tok
- // style; the common _print0 calls the per-Node _print1, which calls back
- // to _print0;
- public final String print() {
- return _print0(new StringBuilder(), new BitSet()).toString();
- }
-
- // This is the common print: check for repeats, check for DEAD and print
- // "DEAD" else call the per-Node print1.
- public final StringBuilder _print0(StringBuilder sb, BitSet visited) {
- if (visited.get(_nid) && !(this instanceof ConstantNode) )
- return sb.append(label());
- visited.set(_nid);
- return isDead()
- ? sb.append(uniqueName()).append(":DEAD")
- : _print1(sb, visited);
- }
- // Every Node implements this; a partial-line recursive print
- abstract public StringBuilder _print1(StringBuilder sb, BitSet visited);
-
public String p(int depth) { return IRPrinter.prettyPrint(this,depth); }
public boolean isConst() { return false; }
@@ -128,6 +79,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
@@ -206,7 +159,6 @@ public abstract class Node implements Cloneable {
return setDef(idx,new_def);
}
-
/**
* Add a new def to an existing Node. Keep the edges correct by
* adding the corresponding <em>def->use</em> edge.
@@ -275,7 +227,6 @@ public abstract class Node implements Cloneable {
kill();
}
-
// Mostly used for asserts and printing.
public boolean isDead() { return isUnused() && nIns()==0 && _type==null; }
@@ -297,7 +248,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;
@@ -539,7 +489,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
@@ -580,7 +529,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 ) {
@@ -598,7 +546,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
@@ -614,7 +561,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;
@@ -634,7 +580,6 @@ public abstract class Node implements Cloneable {
/** Is this Node Memory related */
public boolean isMem() { return false; }
-
// Semantic change to the graph (so NOT a peephole), used by the Parser.
// If any input is a float, flip to a float-flavored opcode and widen any
// non-float input.
@@ -655,7 +600,6 @@ public abstract class Node implements Cloneable {
}
Node copyF() { return null; }
-
// ------------------------------------------------------------------------
// Peephole utilities
@@ -682,7 +626,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/chapter23/src/main/java/com/seaofnodes/simple/node/NotNode.java b/chapter23/src/main/java/com/seaofnodes/simple/node/NotNode.java
index 1cbd2402..775b069b 100644
--- a/chapter23/src/main/java/com/seaofnodes/simple/node/NotNode.java
+++ b/chapter23/src/main/java/com/seaofnodes/simple/node/NotNode.java
@@ -1,19 +1,15 @@
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 String label() { return "Not"; }
- @Override
- public StringBuilder _print1(StringBuilder sb, BitSet visited) {
- in(1)._print0(sb.append("(!"), visited);
- return sb.append(")");
- }
+ @Override protected String format() { return "(!%1)"; }
@Override
public TypeInteger compute() {
diff --git a/chapter23/src/main/java/com/seaofnodes/simple/node/ParmNode.java b/chapter23/src/main/java/com/seaofnodes/simple/node/ParmNode.java
index 89465d45..8b614624 100644
--- a/chapter23/src/main/java/com/seaofnodes/simple/node/ParmNode.java
+++ b/chapter23/src/main/java/com/seaofnodes/simple/node/ParmNode.java
@@ -1,7 +1,8 @@
package com.seaofnodes.simple.node;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.type.Type;
-import java.util.BitSet;
public class ParmNode extends PhiNode {
@@ -19,18 +20,12 @@ public class ParmNode extends PhiNode {
public FunNode fun() { return (FunNode)in(0); }
@Override
- public StringBuilder _print1(StringBuilder sb, BitSet visited) {
+ protected ExprPrinter<Node> _print1(ExprPrinter<Node> p) {
if( "main".equals(fun()._name) && _label.equals("arg") )
- return sb.append("arg");
- sb.append("Parm_").append(_label).append("(");
- for( Node in : _inputs ) {
- if (in == null) sb.append("____");
- else in._print0(sb, visited);
- sb.append(",");
- }
- sb.setLength(sb.length()-1);
- sb.append(")");
- return sb;
+ return p.p("arg");
+ p.p("Parm_").p(_label).open();
+ for( Node in : _inputs ) p.n(in).p(",");
+ return p.unchar(',').close();
}
diff --git a/chapter23/src/main/java/com/seaofnodes/simple/node/PhiNode.java b/chapter23/src/main/java/com/seaofnodes/simple/node/PhiNode.java
index 8ae94260..88d1a7ef 100644
--- a/chapter23/src/main/java/com/seaofnodes/simple/node/PhiNode.java
+++ b/chapter23/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.CodeGen;
import com.seaofnodes.simple.type.*;
import com.seaofnodes.simple.util.Utils;
-import java.util.BitSet;
public class PhiNode extends Node {
@@ -40,18 +41,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/chapter23/src/main/java/com/seaofnodes/simple/node/ProjNode.java b/chapter23/src/main/java/com/seaofnodes/simple/node/ProjNode.java
index 48f92525..26b3a522 100644
--- a/chapter23/src/main/java/com/seaofnodes/simple/node/ProjNode.java
+++ b/chapter23/src/main/java/com/seaofnodes/simple/node/ProjNode.java
@@ -1,10 +1,11 @@
package com.seaofnodes.simple.node;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeMem;
import com.seaofnodes.simple.type.TypeTuple;
-import java.util.BitSet;
public class ProjNode extends Node {
@@ -24,11 +25,11 @@ public class ProjNode extends Node {
@Override public String label() { return _label; }
@Override
- public StringBuilder _print1(StringBuilder sb, BitSet visited) {
- if( _label != null ) return sb.append(_label);
+ protected ExprPrinter<Node> _print1(ExprPrinter<Node> p) {
+ if( _label != null ) return p.p(_label);
if( in(0) instanceof CallEndNode cend && cend.call()!=null )
- return cend.call()._print0(sb,visited);
- return sb.append("LONELY PROJ");
+ return p.n(cend.call());
+ return p.p("LONELY PROJ");
}
@Override public CFGNode cfg0() {
diff --git a/chapter23/src/main/java/com/seaofnodes/simple/node/ReadOnlyNode.java b/chapter23/src/main/java/com/seaofnodes/simple/node/ReadOnlyNode.java
index d8fe6286..94c1b6f6 100644
--- a/chapter23/src/main/java/com/seaofnodes/simple/node/ReadOnlyNode.java
+++ b/chapter23/src/main/java/com/seaofnodes/simple/node/ReadOnlyNode.java
@@ -1,8 +1,8 @@
package com.seaofnodes.simple.node;
+
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeMemPtr;
-import java.util.BitSet;
/**
* Cast a pointer to read-only
@@ -12,10 +12,7 @@ public class ReadOnlyNode extends Node {
public ReadOnlyNode( ReadOnlyNode n ) { super(n); }
@Override public String label() { return "ReadOnly"; }
- @Override
- public StringBuilder _print1(StringBuilder sb, BitSet visited) {
- return in(1)._print0(sb.append("(const)"),visited);
- }
+ @Override protected String format() { return "(const)%1"; }
@Override public Type compute() {
Type t = in(1)._type;
return t instanceof TypeMemPtr tmp ? tmp.makeRO() : t;
diff --git a/chapter23/src/main/java/com/seaofnodes/simple/node/RegionNode.java b/chapter23/src/main/java/com/seaofnodes/simple/node/RegionNode.java
index 14ba493e..72f0df7e 100644
--- a/chapter23/src/main/java/com/seaofnodes/simple/node/RegionNode.java
+++ b/chapter23/src/main/java/com/seaofnodes/simple/node/RegionNode.java
@@ -1,5 +1,7 @@
package com.seaofnodes.simple.node;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.*;
import com.seaofnodes.simple.Parser;
import com.seaofnodes.simple.codegen.CodeGen;
@@ -17,9 +19,8 @@ public class RegionNode extends CFGNode {
@Override
public String label() { return "Region"; }
- @Override
- public StringBuilder _print1(StringBuilder sb, BitSet visited) {
- return sb.append(label());
+ @Override protected ExprPrinter<Node> _print1(ExprPrinter<Node> p) {
+ return p.p(label());
}
@Override public boolean blockHead() { return true; }
diff --git a/chapter23/src/main/java/com/seaofnodes/simple/node/ReturnNode.java b/chapter23/src/main/java/com/seaofnodes/simple/node/ReturnNode.java
index 212bb875..6d268994 100644
--- a/chapter23/src/main/java/com/seaofnodes/simple/node/ReturnNode.java
+++ b/chapter23/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;
/** Keeps all preceding memory effects and the return value alive: {ctrl, $mem, value, rpc}. */
public class ReturnNode extends CFGNode {
@@ -30,11 +31,11 @@ public class ReturnNode extends CFGNode {
public String label() { return "Return"; }
@Override
- public StringBuilder _print1(StringBuilder sb, BitSet visited) {
- sb.append("return ");
- if( expr()==null ) sb.append("----");
- else expr()._print0(sb, visited);
- return sb.append(";");
+ protected ExprPrinter<Node> _print1(ExprPrinter<Node> p) {
+ p.p("return ");
+ if( expr()==null ) p.p("----");
+ else p.n(expr());
+ return p.p(";");
}
// No one unique control follows; can be many call end sites
diff --git a/chapter23/src/main/java/com/seaofnodes/simple/node/RoundF32Node.java b/chapter23/src/main/java/com/seaofnodes/simple/node/RoundF32Node.java
index 2ad034d6..78e7698c 100644
--- a/chapter23/src/main/java/com/seaofnodes/simple/node/RoundF32Node.java
+++ b/chapter23/src/main/java/com/seaofnodes/simple/node/RoundF32Node.java
@@ -1,19 +1,16 @@
package com.seaofnodes.simple.node;
+
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeFloat;
-import java.util.BitSet;
public class RoundF32Node extends Node {
public RoundF32Node(Node lhs) { super(null, lhs); }
@Override public String label() { return "RoundF32"; }
- @Override
- public StringBuilder _print1(StringBuilder sb, BitSet visited) {
- return in(1)._print0(sb.append("((f32)"), visited).append(")");
- }
+ @Override protected String format() { return "((f32)%1)"; }
@Override
public Type compute() {
diff --git a/chapter23/src/main/java/com/seaofnodes/simple/node/ScopeNode.java b/chapter23/src/main/java/com/seaofnodes/simple/node/ScopeNode.java
index cddb9f24..cd5ab6ff 100644
--- a/chapter23/src/main/java/com/seaofnodes/simple/node/ScopeNode.java
+++ b/chapter23/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;
@@ -63,28 +65,26 @@ public class ScopeNode extends Node {
@Override public String label() { return "Scope"; }
@Override
- public StringBuilder _print1(StringBuilder sb, BitSet visited) {
- sb.append("Scope[ ");
+ protected ExprPrinter<Node> _print1(ExprPrinter<Node> p) {
+ p.p("Scope[ ");
int j=1;
for( int i=0; i<nIns(); i++ ) {
- if( j < depth() && i == _kinds.at(j)._lexSize ) { sb.append("| "); j++; }
+ if( j < depth() && i == _kinds.at(j)._lexSize ) { p.p("| "); j++; }
Var v = _vars.at(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/chapter23/src/main/java/com/seaofnodes/simple/node/SplitNode.java b/chapter23/src/main/java/com/seaofnodes/simple/node/SplitNode.java
index d061cdbd..211489fb 100644
--- a/chapter23/src/main/java/com/seaofnodes/simple/node/SplitNode.java
+++ b/chapter23/src/main/java/com/seaofnodes/simple/node/SplitNode.java
@@ -1,20 +1,21 @@
package com.seaofnodes.simple.node;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.codegen.CodeGen;
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.util.SB;
-import java.util.BitSet;
public abstract class SplitNode extends MachConcreteNode {
public final String _kind; // Kind of split
public final byte _round;
public SplitNode(String kind, byte round, Node[] nodes) { super(nodes); _kind = kind; _round = round; }
@Override public String op() { return "mov"; }
- @Override public StringBuilder _print1(StringBuilder sb, BitSet visited) {
- sb.append("mov(");
- if( in(1) == null ) sb.append("---");
- else in(1)._print0(sb,visited);
- return sb.append(")");
+ @Override protected ExprPrinter<Node> _print1(ExprPrinter<Node> p) {
+ p.p("mov(");
+ if( in(1) == null ) p.p("---");
+ else p.n(in(1));
+ return p.close();
}
@Override public Type compute() { return in(0)._type; }
@Override public Node idealize() { return null; }
diff --git a/chapter23/src/main/java/com/seaofnodes/simple/node/StartNode.java b/chapter23/src/main/java/com/seaofnodes/simple/node/StartNode.java
index 186adfb7..e13d35c0 100644
--- a/chapter23/src/main/java/com/seaofnodes/simple/node/StartNode.java
+++ b/chapter23/src/main/java/com/seaofnodes/simple/node/StartNode.java
@@ -1,9 +1,10 @@
package com.seaofnodes.simple.node;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.codegen.CodeGen;
import com.seaofnodes.simple.Parser;
import com.seaofnodes.simple.type.*;
-import java.util.BitSet;
import java.util.HashSet;
import static com.seaofnodes.simple.util.Utils.TODO;
@@ -17,9 +18,8 @@ public class StartNode extends LoopNode implements MultiNode {
@Override public String label() { return "Start"; }
- @Override
- public StringBuilder _print1(StringBuilder sb, BitSet visited) {
- return sb.append(label());
+ @Override protected ExprPrinter<Node> _print1(ExprPrinter<Node> p) {
+ return p.p(label());
}
@Override public CFGNode cfg0() { return null; }
diff --git a/chapter23/src/main/java/com/seaofnodes/simple/node/StopNode.java b/chapter23/src/main/java/com/seaofnodes/simple/node/StopNode.java
index 98a8d4c3..9f7a925b 100644
--- a/chapter23/src/main/java/com/seaofnodes/simple/node/StopNode.java
+++ b/chapter23/src/main/java/com/seaofnodes/simple/node/StopNode.java
@@ -1,8 +1,9 @@
package com.seaofnodes.simple.node;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.util.Utils;
-import java.util.BitSet;
public class StopNode extends CFGNode {
@@ -21,18 +22,18 @@ public class StopNode extends CFGNode {
}
@Override
- public StringBuilder _print1(StringBuilder sb, BitSet visited) {
+ protected ExprPrinter<Node> _print1(ExprPrinter<Node> p) {
// For the sake of many old tests, and single value prints as "return val"
ReturnNode ret1 = ret();
- if( ret1!=null ) return ret1._print0(sb,visited);
- sb.append("Stop[ ");
+ if( ret1!=null ) return p.n(ret1);
+ p.p("Stop[ ");
for( Node ret : _inputs )
if( ret!=null ) {
String name = ((ReturnNode)ret).fun()._name;
if( name== null || !name.startsWith("sys.") )
- ret._print0(sb, visited).append(" ");
+ p.n(ret).p(" ");
}
- return sb.append("]");
+ return p.p("]");
}
@Override public boolean blockHead() { return true; }
diff --git a/chapter23/src/main/java/com/seaofnodes/simple/node/StoreNode.java b/chapter23/src/main/java/com/seaofnodes/simple/node/StoreNode.java
index ac437788..def61478 100644
--- a/chapter23/src/main/java/com/seaofnodes/simple/node/StoreNode.java
+++ b/chapter23/src/main/java/com/seaofnodes/simple/node/StoreNode.java
@@ -1,9 +1,10 @@
package com.seaofnodes.simple.node;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.codegen.*;
import com.seaofnodes.simple.*;
import com.seaofnodes.simple.type.*;
-import java.util.BitSet;
/**
* Store represents setting a value to a memory based object, in chapter 10
@@ -36,8 +37,8 @@ public class StoreNode extends MemOpNode {
public Node val() { return in(4); }
@Override
- public StringBuilder _print1(StringBuilder sb, BitSet visited) {
- return sb.append(".").append(_name).append("=").append( val()).append(";");
+ protected ExprPrinter<Node> _print1(ExprPrinter<Node> p) {
+ return p.p(".").p(_name).p("=").p( val()).p(";");
}
@Override
diff --git a/chapter23/src/main/java/com/seaofnodes/simple/node/StructNode.java b/chapter23/src/main/java/com/seaofnodes/simple/node/StructNode.java
index b5b59b81..78b20e9f 100644
--- a/chapter23/src/main/java/com/seaofnodes/simple/node/StructNode.java
+++ b/chapter23/src/main/java/com/seaofnodes/simple/node/StructNode.java
@@ -1,8 +1,9 @@
package com.seaofnodes.simple.node;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.type.*;
import com.seaofnodes.simple.util.SB;
-import java.util.BitSet;
/**
* Build a compound object
@@ -15,16 +16,15 @@ public class StructNode extends Node {
@Override public String label() { return _ts==null ? "STRUCT?" : _ts.str(); }
@Override
- public StringBuilder _print1(StringBuilder sb, BitSet visited) {
- if( _ts==null ) return sb.append("STRUCT?");
- sb.append(_ts._name).append(" {");
+ protected ExprPrinter<Node> _print1(ExprPrinter<Node> p) {
+ if( _ts==null ) return p.p("STRUCT?");
+ p.p(_ts._name).p(" {");
for( int i=0; i<nIns(); i++ ) {
- sb.append(_ts._fields[i]._fname).append(":");
- sb.append(in(i)==null ? Type.BOTTOM : in(i)._type);
- sb.append("; ");
+ p.p(_ts._fields[i]._fname).p(":");
+ p.p(in(i)==null ? Type.BOTTOM : in(i)._type);
+ p.p("; ");
}
- sb.setLength(sb.length()-2);
- return sb.append("}");
+ return p.unchar("; ").p("}");
}
@Override
diff --git a/chapter23/src/main/java/com/seaofnodes/simple/node/SubFNode.java b/chapter23/src/main/java/com/seaofnodes/simple/node/SubFNode.java
index 73cf9de5..2d218a03 100644
--- a/chapter23/src/main/java/com/seaofnodes/simple/node/SubFNode.java
+++ b/chapter23/src/main/java/com/seaofnodes/simple/node/SubFNode.java
@@ -1,21 +1,16 @@
package com.seaofnodes.simple.node;
+
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeFloat;
-import java.util.BitSet;
public class SubFNode extends Node {
public SubFNode(Node lhs, Node rhs) { super(null, lhs, rhs); }
@Override public String label() { return "SubF"; }
- @Override
- public StringBuilder _print1(StringBuilder sb, BitSet visited) {
- in(1)._print0(sb.append("("), visited);
- in(2)._print0(sb.append("-"), visited);
- return sb.append(")");
- }
+ @Override protected String format() { return "(%1-%2)"; }
@Override
public Type compute() {
diff --git a/chapter23/src/main/java/com/seaofnodes/simple/node/ToFloatNode.java b/chapter23/src/main/java/com/seaofnodes/simple/node/ToFloatNode.java
index 8ef5e40a..7b0122ce 100644
--- a/chapter23/src/main/java/com/seaofnodes/simple/node/ToFloatNode.java
+++ b/chapter23/src/main/java/com/seaofnodes/simple/node/ToFloatNode.java
@@ -1,20 +1,17 @@
package com.seaofnodes.simple.node;
+
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeFloat;
import com.seaofnodes.simple.type.TypeInteger;
-import java.util.BitSet;
public class ToFloatNode extends Node {
public ToFloatNode(Node lhs) { super(null, lhs); }
@Override public String label() { return "ToFloat"; }
- @Override
- public StringBuilder _print1(StringBuilder sb, BitSet visited) {
- return in(1)._print0(sb.append("(flt)"), visited);
- }
+ @Override protected String format() { return "(flt)%1"; }
@Override
public Type compute() {
diff --git a/chapter23/src/main/java/com/seaofnodes/simple/node/XCtrlNode.java b/chapter23/src/main/java/com/seaofnodes/simple/node/XCtrlNode.java
index 8c620a04..477b9af8 100644
--- a/chapter23/src/main/java/com/seaofnodes/simple/node/XCtrlNode.java
+++ b/chapter23/src/main/java/com/seaofnodes/simple/node/XCtrlNode.java
@@ -1,14 +1,15 @@
package com.seaofnodes.simple.node;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.codegen.CodeGen;
import com.seaofnodes.simple.Parser;
import com.seaofnodes.simple.type.Type;
-import java.util.BitSet;
public class XCtrlNode extends CFGNode {
public XCtrlNode() { super(new Node[]{CodeGen.CODE._start}); }
@Override public String label() { return "Xctrl"; }
- @Override public StringBuilder _print1(StringBuilder sb, BitSet visited) { return sb.append("Xctrl"); }
+ @Override protected ExprPrinter<Node> _print1(ExprPrinter<Node> p) { return p.p("Xctrl"); }
@Override public boolean isConst() { return true; }
@Override public Type compute() { return Type.XCONTROL; }
@Override public Node idealize() { return null; }
diff --git a/chapter23/src/main/java/com/seaofnodes/simple/node/cpus/arm/MemOpARM.java b/chapter23/src/main/java/com/seaofnodes/simple/node/cpus/arm/MemOpARM.java
index 01066f47..9257f25b 100644
--- a/chapter23/src/main/java/com/seaofnodes/simple/node/cpus/arm/MemOpARM.java
+++ b/chapter23/src/main/java/com/seaofnodes/simple/node/cpus/arm/MemOpARM.java
@@ -1,12 +1,13 @@
package com.seaofnodes.simple.node.cpus.arm;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.codegen.*;
import com.seaofnodes.simple.node.*;
import com.seaofnodes.simple.type.*;
import com.seaofnodes.simple.util.SB;
import com.seaofnodes.simple.util.Utils;
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
@@ -31,7 +32,7 @@ public abstract class MemOpARM extends MemOpNode implements MachNode {
@Override public String label() { return op();}
Node val() { return in(4); } // Only for stores
- @Override public StringBuilder _printMach(StringBuilder sb, BitSet visited) { return sb.append(".").append(_name); }
+ @Override protected ExprPrinter<Node> _printMach(ExprPrinter<Node> p) { return p.p(".").p(_name); }
@Override public Type compute() { throw Utils.TODO(); }
@Override public Node idealize() { throw Utils.TODO(); }
diff --git a/chapter23/src/main/java/com/seaofnodes/simple/node/cpus/arm/UJmpARM.java b/chapter23/src/main/java/com/seaofnodes/simple/node/cpus/arm/UJmpARM.java
index 2dd5fd6b..ce4f523c 100644
--- a/chapter23/src/main/java/com/seaofnodes/simple/node/cpus/arm/UJmpARM.java
+++ b/chapter23/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/chapter23/src/main/java/com/seaofnodes/simple/node/cpus/riscv/BranchRISC.java b/chapter23/src/main/java/com/seaofnodes/simple/node/cpus/riscv/BranchRISC.java
index b7284265..b8664679 100644
--- a/chapter23/src/main/java/com/seaofnodes/simple/node/cpus/riscv/BranchRISC.java
+++ b/chapter23/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/chapter23/src/main/java/com/seaofnodes/simple/node/cpus/riscv/ImmRISC.java b/chapter23/src/main/java/com/seaofnodes/simple/node/cpus/riscv/ImmRISC.java
index f2beb25c..b4c87872 100644
--- a/chapter23/src/main/java/com/seaofnodes/simple/node/cpus/riscv/ImmRISC.java
+++ b/chapter23/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/chapter23/src/main/java/com/seaofnodes/simple/node/cpus/riscv/MemOpRISC.java b/chapter23/src/main/java/com/seaofnodes/simple/node/cpus/riscv/MemOpRISC.java
index 93c90052..22dba099 100644
--- a/chapter23/src/main/java/com/seaofnodes/simple/node/cpus/riscv/MemOpRISC.java
+++ b/chapter23/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
@@ -23,7 +24,7 @@ public abstract class MemOpRISC extends MemOpNode implements MachNode {
@Override public String label() { return op(); }
Node val() { return in(4); } // Only for stores
- @Override public StringBuilder _printMach(StringBuilder sb, BitSet visited) { return sb.append(".").append(_name); }
+ @Override protected ExprPrinter<Node> _printMach(ExprPrinter<Node> p) { return p.p(".").p(_name); }
@Override public Type compute() { throw Utils.TODO(); }
@Override public Node idealize() { throw Utils.TODO(); }
diff --git a/chapter23/src/main/java/com/seaofnodes/simple/node/cpus/riscv/UJmpRISC.java b/chapter23/src/main/java/com/seaofnodes/simple/node/cpus/riscv/UJmpRISC.java
index c4d5d8af..160895df 100644
--- a/chapter23/src/main/java/com/seaofnodes/simple/node/cpus/riscv/UJmpRISC.java
+++ b/chapter23/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/chapter23/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/MemOpX86.java b/chapter23/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/MemOpX86.java
index 20578467..309e62d9 100644
--- a/chapter23/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/MemOpX86.java
+++ b/chapter23/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/MemOpX86.java
@@ -1,12 +1,13 @@
package com.seaofnodes.simple.node.cpus.x86_64_v2;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.codegen.*;
import com.seaofnodes.simple.node.*;
import com.seaofnodes.simple.type.*;
import com.seaofnodes.simple.util.SB;
import com.seaofnodes.simple.util.Utils;
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/chapter23/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/StoreX86.java b/chapter23/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/StoreX86.java
index 4403b02b..b7b6c5d3 100644
--- a/chapter23/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/StoreX86.java
+++ b/chapter23/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/chapter23/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/UJmpX86.java b/chapter23/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/UJmpX86.java
index 92d2a87d..6f538d27 100644
--- a/chapter23/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/UJmpX86.java
+++ b/chapter23/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/chapter23/src/main/java/com/seaofnodes/simple/print/ASMPrinter.java b/chapter23/src/main/java/com/seaofnodes/simple/print/ASMPrinter.java
index 9ee26039..48296ce7 100644
--- a/chapter23/src/main/java/com/seaofnodes/simple/print/ASMPrinter.java
+++ b/chapter23/src/main/java/com/seaofnodes/simple/print/ASMPrinter.java
@@ -1,307 +1,85 @@
package com.seaofnodes.simple.print;
+import com.seaofnodes.print.AssemblyAdapter;
+import com.seaofnodes.print.ASMPrinter.Data;
+import com.seaofnodes.print.ASMPrinter.Pool;
import com.seaofnodes.simple.codegen.CodeGen;
-import com.seaofnodes.simple.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.Ary;
-import com.seaofnodes.simple.util.SB;
-import com.seaofnodes.simple.util.Utils;
-import java.util.Collections;
-import java.util.IdentityHashMap;
-import java.util.Set;
-
-public abstract class ASMPrinter {
+import java.util.ArrayList;
+import com.seaofnodes.simple.codegen.Encoding;
+/** Machine-specific facts; traversal, columns and byte display live in print/. */
+public final class ASMPrinter extends AssemblyAdapter<Node> {
+ private final CodeGen _code;
+ private final Encoding _enc;
+ private ASMPrinter(CodeGen code) {
+ super(new IRPrinter());
+ _code=code;
+ _enc=code._encoding;
+ }
public static SB print(SB sb, CodeGen code) {
- if( code._cfg==null )
- return sb.p("Need _cfg set, run after GCM");
-
- // instruction address
- int iadr = 0;
- for( int i=0; i<code._cfg._len; i++ )
- if( code._cfg.at(i) instanceof FunNode fun )
- iadr = print(iadr,sb,code,fun,i);
-
- // constant pool
- iadr = (iadr+15)&-16; // pad to 16
- Encoding enc = code._encoding;
- if( enc!=null && !enc._bigCons.isEmpty() && iadr < enc._bits.size() ) {
- // radix sort the big constants by alignment
- Ary<Relo>[] raligns = new Ary[5];
- for( Relo relo : enc._bigCons.values() ) {
- int align = relo._align;
- Ary<Relo> relos = raligns[align]==null ? (raligns[align]=new Ary<>( Relo.class)) : raligns[align];
- relos.add(relo);
- }
-
- Set<Type> targets = Collections.newSetFromMap(new IdentityHashMap<>());
- sb.p("--- Constant Pool ------").nl();
-
- // By alignment
- for( int align = 4; align >= 0; align-- ) {
- Ary<Relo> relos = raligns[align];
- if( relos == null ) continue;
- for( Relo relo : relos ) {
- if( targets.contains(relo._t) ) continue;
- targets.add(relo._t);
- sb.hex2(iadr).p(" ");
- switch( relo._t ) {
- case TypeTuple tt -> {
- for( Type tx : tt._types ) {
- pN(enc,sb,iadr,align).p(" ");
- iadr += (1<<align);
- }
- }
-
- case TypeStruct ts -> {
- int sz = relo._structSize;
- int log = 1<<align;
- sz = (sz + (log -1)) & -log; // Round up final padding
- for( int i=0; i<sz; i++ )
- sb.hex1(enc.read1(iadr++));
- }
-
- // Simple primitive (e.g. larger int, float)
- default -> {
- pN(enc,sb,iadr,align).fix(9-(1<<align),"");
- iadr += (1<<align);
- }
- }
- relo._t.print(sb).nl();
- }
- }
- }
-
- return sb;
+ return sb.p(new com.seaofnodes.print.ASMPrinter<>(new ASMPrinter(code)).print());
}
-
- private static SB pN( Encoding enc, SB sb, int iadr, int log ) {
- switch( log ) {
- case 0: sb.hex1(enc.read1(iadr)); break;
- case 1: sb.hex2(enc.read2(iadr)); break;
- case 2: sb.hex4(enc.read4(iadr)); break;
- case 3: sb.hex8(enc.read8(iadr)); break;
- }
- return sb;
+ @Override public ArrayList<Node> blocks() {
+ var blocks=new ArrayList<Node>();
+ var cfg=_code._cfg;
+ if( cfg!=null ) for( Node n : cfg ) blocks.add(n);
+ return blocks;
}
-
-
- private static int print(int iadr, SB sb, CodeGen code, FunNode fun, int cfgidx) {
- FunNode old=null;
- if( code._encoding!=null ) {
- old = code._encoding._fun;
- code._encoding._fun = fun; // Useful printing after RA
+ @Override public String op(Node n) { return n instanceof MachNode m ? m.op() : n.label(); }
+ @Override public String register(Node n) { return _code.reg(n); }
+ @Override public String comment(Node n) { return n.comment(); }
+ @Override public String phiName(Node n) { return ((PhiNode)n)._label; }
+ @Override public String operands(Node n) {
+ SB sb=new SB();
+ if( n instanceof MachNode m ) m.asm(_code,sb);
+ else if( !(n._type instanceof TypeMem) ) {
+ sb.p(n._nid).p(": ");
+ for( Node def : n._inputs ) sb.p(def==null ? "___" : Integer.toString(def._nid)).p(' ');
}
- // Function header
- sb.nl().p("---");
- if( fun._name != null ) sb.p(fun._name).p(" ");
- fun.sig().print(sb);
- sb.p("---------------------------").nl();
- if( code._encoding!=null && code._encoding._padFunHeads )
- iadr = (iadr + 15)&-16; // All function entries padded to 16 align
-
- if( fun._frameAdjust != 0 )
- iadr = doInst(iadr,sb,code,fun,cfgidx,fun,true,true);
- while( !(code._cfg.at(cfgidx) instanceof ReturnNode) )
- iadr = doBlock(iadr,sb,code,fun,cfgidx++);
-
- // Function separator
- sb.p("---");
- fun.sig().print(sb);
- sb.p("---------------------------").nl();
- if( code._encoding != null )
- code._encoding._fun = old;
- return iadr;
+ return sb.toString();
}
-
- static private final int opWidth = 5;
- static private final int argWidth = 30;
- static int doBlock(int iadr, SB sb, CodeGen code, FunNode fun, int cfgidx) {
- final int encWidth = code._mach==null ? 2 : code._mach.defaultOpSize()*2;
- CFGNode bb = code._cfg.at(cfgidx);
- if( bb != fun && !(bb instanceof IfNode) && !(bb instanceof CallEndNode) && !(bb instanceof CallNode) && !(bb instanceof CProjNode && bb.in(0) instanceof CallEndNode ))
- sb.p(label(bb)).p(":").nl();
- if( bb instanceof CallNode ) return iadr;
- final boolean postAlloc = code._phase.ordinal() > CodeGen.Phase.RegAlloc.ordinal();
- final boolean postEncode= code._phase.ordinal() >=CodeGen.Phase.Encoding.ordinal();
-
- boolean once=false;
- for( Node n : bb.outs() ) {
- if( !(n instanceof PhiNode phi) ) continue;
- if( phi._type instanceof TypeMem || phi._type instanceof TypeRPC ) continue; // Nothing for the hidden ones
- // Post-RegAlloc phi prints all on one line
- if( postAlloc ) {
- if( !once ) { once=true; sb.fix(4," ").p(" ").fix(encWidth,"").p(" "); }
- sb.p(phi._label).p(':').p(code.reg(phi,fun)).p(',');
- } else {
- // Pre-RegAlloc phi prints one line per
- sb.fix(4," ").p(" ").fix(encWidth,"").p(" ").fix(opWidth,phi._label).p(" ").p(code.reg(phi,fun));
- if( phi.getClass() == PhiNode.class ) {
- sb.p(" = phi( ");
- for( int i=1; i<phi.nIns(); i++ )
- sb.p("N").p(phi.in(i)._nid).p(",");
- sb.unchar().p(" )");
- }
- sb.nl();
- }
- }
- if( once ) sb.unchar().nl();
-
- // All the non-phis
- for( int i=0; i<bb.nOuts(); i++ )
- if( !(bb.out(i) instanceof PhiNode) )
- iadr = doInst(iadr, sb,code, fun, cfgidx, bb.out(i),postAlloc, postEncode );
-
- return iadr;
+ @Override public boolean labelBlock(Node n) {
+ return !(n instanceof FunNode) && !(n instanceof IfNode) && !(n instanceof CallNode) &&
+ !(n instanceof CallEndNode) && !(n instanceof CProjNode && ir.input0(n) instanceof CallEndNode);
}
-
- static int doInst( int iadr, SB sb, CodeGen code, FunNode fun, int cfgidx, Node n, boolean postAlloc, boolean postEncode ) {
- if( n==null || n instanceof CProjNode ) return iadr;
- if( postAlloc && n instanceof CalleeSaveNode ) return iadr;
- if( postEncode && n instanceof ProjNode ) return iadr;
- if( n instanceof MemMergeNode ) return iadr;
- if( n.getClass() == ConstantNode.class ) return iadr; // Default placeholders
- final int dopz = code._mach==null ? 2 : code._mach.defaultOpSize();
- final int encWidth = dopz*2;
-
- // All blocks ending in a Region will need to either fall into or jump
- // to this block. Until the post-reg-alloc block layout cleanup, we
- // need to assume a jump. There's no real hardware op here, yet.
- if( n instanceof RegionNode cfg && !(n instanceof FunNode) ) {
- if( postEncode ) return iadr; // All jumps inserted already
- while( cfgidx < code._cfg._len-1 ) {
- CFGNode next = code._cfg.at(++cfgidx);
- if( next == n ) return iadr; // Fall-through, no branch
- if( next.nOuts()>1 )
- break; // Has code in the block, need to jump around
- // No code in the block, can fall through it
- }
- sb.hex2(iadr++).p(" ").fix(encWidth,"??").p(" ").fix(opWidth,"JMP").p(" ").fix(argWidth,label(cfg)).nl();
- return iadr;
- }
-
- // ProjNodes following a multi (e.g. Call or New results),
- // get indent slightly and just print their index & node#
- if( n instanceof ProjNode proj ) {
- if( proj._type instanceof TypeMem ) return iadr; // Nothing for the hidden ones
- sb.fix(4," ").p(" ").fix(encWidth,"").p(" ").fix(opWidth,proj._label==null ? "---" : proj._label).p(" ").p(code.reg(n,fun)).nl();
- return iadr;
- }
-
- // ADDR ENCODING Op--- dst = src op src // Comment
- // 1234 abcdefgh ld4 RAX = [Rbase + off] // Comment
- sb.hex2(iadr).p(" ");
-
- // Encoding
- int fatEncoding = 0;
- if( code._encoding != null && code._encoding._opLen!=null ) {
- int size = code._encoding._opLen[n._nid];
- if( code._asmLittle )
- for( int i=0; i<Math.min(size,dopz); i++ )
- sb.hex1(code._encoding._bits.buf()[iadr++]);
- else {
- iadr += Math.min(size,dopz);
- for( int i=0; i<Math.min(size,dopz); i++ )
- sb.hex1(code._encoding._bits.buf()[iadr-i-1]);
- }
- for( int i=size*2; i<encWidth; i++ )
- sb.p(" ");
- fatEncoding = size - (encWidth>>1); // Not-printed parts of encoding
- } else
- sb.fix(encWidth,"");
- sb.p(" ");
-
- // Op; generally "ld4" or "call"
- sb.fix(opWidth, n instanceof MachNode mach ? mach.op() : n.label()).p(" ");
-
- // General asm args
- String isMultiOp = null;
- if( n instanceof MachNode mach ) {
- int old = sb.len();
- mach.asm(code,sb);
- int len = sb.len();
- isMultiOp = isMultiOp(sb,old,len);
- sb.fix(argWidth-(len-old),""); // Pad out
-
- } else if( !(n._type instanceof TypeMem) ) {
- // Room for some inputs
- sb.fix(5, n._nid+":" );
- int off = 0;
- for( int i=0; i<n.nIns(); i++ ) {
- sb.fix(5, n.in(i) == null ? "___" : String.valueOf(n.in(i)._nid));
- off += 5;
- if( off >= argWidth ) break;
- }
- if( off < argWidth ) sb.fix(argWidth-off,"");
- }
- sb.p(" ");
-
- // Comment
- String comment = n.comment();
- if( comment!=null ) sb.p("// ").p(comment);
-
- sb.nl();
-
- // Printing more op bits than fit
- if( isMultiOp != null && code._encoding != null && code._encoding._opLen!=null ) {
- // Multiple ops, template style, no RA, no scheduling. Print out
- // one-line-per-newline, with encoding bits up front.
- int size = code._encoding._opLen[n._nid];
- int off = Math.min(size,dopz);
- while( isMultiOp!=null ) {
- sb.hex2(iadr).p(" ");
- int len = Math.min(size-off,dopz);
- for( int i=0; i<len; i++ )
- sb.hex1(code._encoding._bits.buf()[iadr++]);
- off += len;
- for( int i=len; i<dopz; i++ ) sb.p(" ");
- sb.p(" ");
- int x = isMultiOp.indexOf('\n');
- if( x== -1 ) { // Last line
- sb.p(isMultiOp).nl();
- isMultiOp = null;
- } else {
- sb.p(isMultiOp.substring(0,x+1)); // Includes the newline
- isMultiOp = isMultiOp.substring(x+1);
- }
-
- }
-
- } else if( fatEncoding > 0 ) {
- // Extra bytes past the default encoding width, all put on a line by
- // themselves. X86 special for super long encodings
- sb.hex2(iadr).p(" ");
- for( int i=0; i<fatEncoding; i++ )
- sb.hex1(code._encoding._bits.buf()[iadr++]);
- sb.nl();
- }
-
-
- // MultiNodes are immediately followed by projection(s)
- if( !(n instanceof CFGNode) && n instanceof MultiNode ) {
- for( Node proj : n._outputs ) {
- if( proj instanceof ProjNode ) // it could also be an ante-dep
- doInst(iadr,sb,code,fun, cfgidx, proj,postAlloc,postEncode);
- }
- }
-
- return iadr;
+ @Override public boolean hidden(Node n) {
+ if( n instanceof PhiNode || n instanceof ProjNode )
+ if( n._type instanceof TypeMem || n._type instanceof TypeRPC ) return true;
+ if( postAlloc() && n instanceof CalleeSaveNode ) return true;
+ if( n instanceof MemMergeNode ) return true;
+ return n.getClass()==ConstantNode.class;
}
-
- private static String label( CFGNode bb ) {
- return (bb instanceof LoopNode ? "LOOP" : "L")+bb._nid;
+ @Override public boolean postAlloc() { return _code._phase.ordinal()>CodeGen.Phase.RegAlloc.ordinal(); }
+ @Override public boolean encoded() { return _enc!=null && _code._phase.ordinal()>=CodeGen.Phase.Encoding.ordinal(); }
+ @Override public int defaultSize() { return _code._mach==null ? 2 : _code._mach.defaultOpSize(); }
+ @Override public boolean littleEndian() { return _code._asmLittle; }
+ @Override public boolean prologue(Node n) { return ((FunNode)n)._frameAdjust!=0; }
+ @Override public byte[] bytes() { return encoded() ? _enc._bits.buf() : null; }
+ @Override public int offset(Node n) {
+ return encoded() && _enc._opStart!=null && n._nid<_enc._opStart.length ? _enc._opStart[n._nid] : -1;
}
-
- private static String isMultiOp(SB sb, int old, int len) {
- for( int i=old; i<len; i++ )
- if( sb.at(i)=='\n' ) {
- String s = sb.subString(i+1,len);
- sb.setLen(i);
- return s;
- }
- return null;
+ @Override public int size(Node n) {
+ return encoded() && _enc._opLen!=null && n._nid<_enc._opLen.length ? _enc._opLen[n._nid]&255 : 0;
+ }
+ private static ArrayList<Data> entries(Iterable<Encoding.Relo> relos) {
+ var data=new ArrayList<Data>();
+ for( Encoding.Relo r : relos ) {
+ int align=1<<r._align;
+ int size=r._t instanceof TypeStruct ? (r._structSize+align-1)&-align : align;
+ if( r._t instanceof TypeTuple t ) size=align*t._types.length;
+ data.add(new Data(r._t,r._t.str(),r._align,size));
+ }
+ return data;
+ }
+ @Override public ArrayList<Pool> pools(int codeEnd) {
+ var pools=new ArrayList<Pool>();
+ if( !encoded() ) return pools;
+ int base=(codeEnd+15)&-16;
+ if( !_enc._bigCons.isEmpty() && base<_enc._bits.size() )
+ pools.add(new Pool("Constant Pool",_enc._bits.buf(),base,base,entries(_enc._bigCons.values())));
+ return pools;
}
-
}
diff --git a/chapter23/src/main/java/com/seaofnodes/simple/print/IRPrinter.java b/chapter23/src/main/java/com/seaofnodes/simple/print/IRPrinter.java
index 046ffb4a..c912ab77 100644
--- a/chapter23/src/main/java/com/seaofnodes/simple/print/IRPrinter.java
+++ b/chapter23/src/main/java/com/seaofnodes/simple/print/IRPrinter.java
@@ -1,352 +1,61 @@
package com.seaofnodes.simple.print;
-import com.seaofnodes.simple.codegen.CodeGen;
+import com.seaofnodes.print.IRAdapter;
import com.seaofnodes.simple.node.*;
-import com.seaofnodes.simple.type.TypeFunPtr;
-import com.seaofnodes.simple.util.Ary;
-import com.seaofnodes.simple.util.SB;
-import com.seaofnodes.simple.util.Utils;
import java.util.ArrayList;
-import java.util.BitSet;
-import java.util.HashMap;
-
-public abstract class IRPrinter {
-
- // Print a node on 1 line, columnar aligned, as:
- // NNID NNAME DDEF DDEF [[ UUSE UUSE ]] TYPE
- // 1234 sssss 1234 1234 1234 1234 1234 1234 tttttt
- public static SB printLine( Node n, SB sb ) {
- if( n==null ) return sb;
- sb.p("%4d %-7.7s ".formatted(n._nid,n.label()));
- if( n.isDead() )
- return sb.p("DEAD\n");
- for( Node def : n._inputs )
- sb.p(def==null ? "____" : "%4d".formatted(def._nid))
- // Lazy Phi indicator
- .p(n instanceof MemMergeNode && def instanceof MemMergeNode ? "^" : " ");
- for( int i = n._inputs.size(); i<4; i++ )
- sb.p(" ");
- sb.p(" [[ ");
- for( Node use : n._outputs )
- sb.p(use==null ? "____ " : "%4d ".formatted(use._nid));
- int lim = 6 - Math.max(n._inputs.size(),4);
- for( int i = n._outputs.size(); i<lim; i++ )
- sb.p(" ");
- sb.p(" ]] ");
- if( n._type!= null ) sb.p(n._type.str());
- return sb.p("\n");
- }
-
-
- public static String prettyPrint(Node node, int depth) {
- return CodeGen.CODE._phase.ordinal() > CodeGen.Phase.Schedule.ordinal()
- ? _prettyPrintScheduled( node, depth )
- : _prettyPrint( node, depth );
- }
-
- // Another bulk pretty-printer. Makes more effort at basic-block grouping.
- private static String _prettyPrint( Node node, int depth ) {
- // First, a Breadth First Search at a fixed depth.
- BFS bfs = new BFS(node,depth);
- // Convert just that set to a post-order
- ArrayList<Node> rpos = new ArrayList<>();
- BitSet visit = new BitSet();
- for( int i=bfs._lim; i< bfs._bfs.size(); i++ )
- postOrd( bfs._bfs.get(i), null, rpos, visit, bfs._bs);
- // Reverse the post-order walk
- SB sb = new SB();
- boolean gap=false;
- for( int i=rpos.size()-1; i>=0; i-- ) {
- Node n = rpos.get(i);
- if( n instanceof CFGNode || n instanceof MultiNode ) {
- if( !gap ) sb.p("\n"); // Blank before multihead
- if( n instanceof FunNode fun )
- fun.sig().print(sb.p("--- ").p(fun._name==null ? "" : fun._name).p(" ")).p("----------------------\n");
- printLine( n, sb ); // Print head
- while( --i >= 0 ) {
- Node t = rpos.get(i);
- if( !(t.in(0) instanceof MultiNode) ) { i++; break; }
- printLine( t, sb );
- }
- if( n instanceof ReturnNode ret ) {
- FunNode fun = ret.fun();
- sb.p("--- ");
- if( fun != null )
- fun.sig().print(sb.p(fun._name==null ? "" : fun._name).p(" "));
- sb.p("----------------------\n");
- }
- if( !(n instanceof CallNode) ) {
- sb.p("\n"); // Blank after multitail
- gap = true;
- }
- } else {
- printLine( n, sb );
- gap = false;
- }
- }
- return sb.toString();
- }
-
- private static void postOrd(Node n, Node prior, ArrayList<Node> rpos, BitSet visit, BitSet bfs) {
- if( !bfs.get(n._nid) )
- return; // Not in the BFS visit
- if( n instanceof FunNode && !(prior instanceof StartNode) )
- return; // Only visit Fun from Start
- if( visit.get(n._nid) ) return; // Already post-order walked
- visit.set(n._nid);
- // First walk the CFG, then everything
- if( n instanceof CFGNode ) {
- for( Node use : n._outputs )
- // Follow CFG, not across call/function borders, and not around backedges
- if( use instanceof CFGNode && !(n instanceof CallNode && use instanceof FunNode) &&
- use.nOuts() >= 1 && !(use._outputs.get(0) instanceof LoopNode) )
- postOrd(use, n, rpos,visit,bfs);
- for( Node use : n._outputs )
- // Follow CFG, not across call/function borders
- if( use instanceof CFGNode && !(n instanceof CallNode && use instanceof FunNode) )
- postOrd(use,n,rpos,visit,bfs);
- }
- // Follow all outputs
- for( Node use : n._outputs )
- if( use != null &&
- !(n instanceof CallNode && use instanceof FunNode) &&
- (n instanceof FunNode || !(use instanceof ParmNode)) )
- postOrd(use, n, rpos,visit,bfs);
- // Post-order
- rpos.add(n);
- }
-
- // Breadth-first search, broken out in a class to keep in more independent.
- // Maintains a root-set of Nodes at the limit (or past by 1 if MultiHead).
- public static class BFS {
- // A breadth first search, plus MultiHeads for any MultiTails
- public final ArrayList<Node> _bfs;
- public final BitSet _bs; // Visited members by node id
- public final int _depth; // Depth limit
- public final int _lim; // From here to _bfs._len can be roots for a reverse search
- public BFS( Node base, int d ) {
- _depth = d;
- _bfs = new ArrayList<>();
- _bs = new BitSet();
-
- add(base); // Prime the pump
- int idx=0, lim=1; // Limit is where depth counter changes
- while( idx < _bfs.size() ) { // Ran out of nodes below depth
- Node n = _bfs.get(idx++);
- for( Node def : n._inputs )
- if( def!=null && !_bs.get(def._nid) )
- add(def);
- if( idx==lim ) { // Depth counter changes at limit
- if( --d < 0 )
- break; // Ran out of depth
- lim = _bfs.size(); // New depth limit
- }
- }
- // Toss things past the limit except multi-heads
- while( idx < _bfs.size() ) {
- Node n = _bfs.get(idx);
- if( n instanceof MultiNode ) idx++;
- else del(idx);
- }
- // Root set is any node with no inputs in the visited set
- lim = _bfs.size();
- for( int i=_bfs.size()-1; i>=0; i-- )
- if( !any_visited(_bfs.get(i)) )
- swap( i,--lim);
- _lim = lim;
- }
- void swap( int x, int y ) {
- if( x==y ) return;
- Node tx = _bfs.get(x);
- Node ty = _bfs.get(y);
- _bfs.set(x,ty);
- _bfs.set(y,tx);
- }
- void add(Node n) {
- _bfs.add(n);
- _bs.set(n._nid);
- }
- void del(int idx) {
- _bs.clear(_bfs.get(idx)._nid);
- Utils.del(_bfs, idx);
- }
- boolean any_visited( Node n ) {
- for( Node def : n._inputs )
- if( def!=null && _bs.get(def._nid) )
- return true;
- return false;
- }
- }
-
- public static String _prettyPrint( CodeGen code ) {
- SB sb = new SB();
- // Print the Start "block"
- printLine(code._start,sb);
- for( Node n : code._start._outputs )
- printLine(n,sb);
- sb.nl();
-
- // Skip start, stop
- for( int i=1; i<code._cfg._len-1; i++ ) {
- CFGNode blk = code._cfg.at(i);
- if( blk.blockHead() && (!(blk instanceof CProjNode) || (blk.cfg0() instanceof IfNode )) ) {
- if( blk instanceof FunNode fun )
- sb.p("--- ").p(fun.label()).p(" ---------------------------").nl();
- // Print block header
- sb.p("%-13.13s".formatted(label(blk)+":"));
- sb.p( " ".repeat(4) ).p(" [[ ");
- if( blk instanceof RegionNode )
- for( int j=1; j<blk.nIns(); j++ )
- label(sb,blk.cfg(j));
- else
- label(sb,blk.cfg(0));
- sb.p(" ]] \n");
- }
- printLine(blk,sb);
- if( blk instanceof ReturnNode ret )
- sb.p("--- ").p(ret.fun().label()).p(" ---------------------------").nl();
-
- // Block contents
- for( Node n : blk._outputs ) {
- if( n instanceof CFGNode cfg ) continue;
- printLine(n,sb);
- if( !(n instanceof CFGNode) && n instanceof MultiNode )
- for( Node use : n._outputs )
- if( use instanceof ProjNode )
- printLine(use,sb);
- }
- }
-
- printLine(code._stop,sb);
- return sb.toString();
- }
-
- // Diagnostic block ordering from raw control edges. Do not call idepth():
- // it fills compiler caches (and can walk lazy dominator accessors).
- private static int _idepth(CFGNode cfg, HashMap<Integer,Integer> depths) {
- if( cfg == null || cfg instanceof StartNode || cfg instanceof FunNode ) return cfg instanceof FunNode ? 1 : 0;
- Integer old = depths.get(cfg._nid);
- if( old != null ) return old;
- depths.put(cfg._nid,0); // Break cycles in partially constructed graphs.
- int d = 0;
- if( cfg instanceof LoopNode ) {
- d = _idepth((CFGNode)cfg.in(1),depths)+1;
- } else if( cfg instanceof RegionNode || cfg instanceof StopNode ) {
- for( Node n : cfg._inputs )
- if( n instanceof CFGNode pred ) d = Math.max(d,_idepth(pred,depths)+1);
- } else if( cfg.in(0) instanceof CFGNode pred ) {
- d = _idepth(pred,depths)+1;
- }
- depths.put(cfg._nid,d);
- return d;
- }
-
- // Bulk pretty printer, knowing scheduling information is available
- private static String _prettyPrintScheduled( Node node, int depth ) {
- // Backwards DFS walk to depth.
- HashMap<Integer,Integer> ds = new HashMap<>();
- Ary<Node> ns = new Ary<>(Node.class);
- _walk(ds,ns,node,depth);
- // Remove data projections, these are force-printed behind their multinode head
- for( int i=0; i<ns.size(); i++ ) {
- if( ns.get(i) instanceof ProjNode proj && !(proj.in(0) instanceof CFGNode) ) {
- ns.del(i--);
- ds.remove(proj._nid);
- }
- }
- // Print by block with least diagnostic depth
- HashMap<Integer,Integer> depths = new HashMap<>();
- SB sb = new SB();
- Ary<Node> bns = new Ary<>(Node.class);
- while( !ds.isEmpty() ) {
- CFGNode blk = null;
- for( Node n : ns ) {
- CFGNode cfg = n instanceof CFGNode cfg0 && cfg0.blockHead() ? cfg0 : n.cfg0();
- if( blk==null || _idepth(cfg,depths) < _idepth(blk,depths) )
- blk = cfg;
- }
- Integer d = ds.remove(blk._nid);
- ns.del(ns.find(blk));
-
- // Print block header
- sb.p("%-13.13s".formatted(label(blk)+":"));
- sb.p( " ".repeat(4) ).p(" [[ ");
- if( blk instanceof StartNode ) ;
- else if( blk instanceof RegionNode || blk instanceof StopNode )
- for( int i=(blk instanceof StopNode ? 3 : 1); i<blk.nIns(); i++ )
- label(sb,blk.cfg(i));
- else
- label(sb,blk.cfg(0));
- sb.p(" ]] \n");
- printLine(blk,sb);
-
- // Collect block contents that are in the depth limit
- bns.clear();
- int xd = Integer.MAX_VALUE;
- for( Node use : blk._outputs ) {
- Integer i = ds.get(use._nid);
- if( i!=null && !(use instanceof CFGNode cfg && cfg.blockHead()) ) {
- if( bns.find(use)==-1 )
- bns.add(use);
- xd = Math.min(xd,i);
- }
- }
- // Print Phis up front, if any
- for( int i=0; i<bns.size(); i++ )
- if( bns.get(i) instanceof PhiNode phi )
- printLine( phi, sb,bns,i--,ds,ns);
-
- // Print block contents in depth order, bumping depth until whole block printed
- for( ; !bns.isEmpty(); xd++ )
- for( int i=0; i<bns.size(); i++ ) {
- Node n = bns.get(i);
- if( ds.get(n._nid)==xd ) {
- printLine( n, sb, bns, i--, ds,ns );
- if( n instanceof MultiNode && !(n instanceof CFGNode) ) {
- for( Node use : n._outputs ) {
- if( use instanceof ProjNode )
- printLine(use,sb,bns,bns.indexOf(use),ds,ns);
- }
- }
- }
- }
- sb.p("\n");
- }
- return sb.toString();
- }
-
- private static void _walk( HashMap<Integer,Integer> ds, Ary<Node> ns, Node node, int d ) {
- Integer nd = ds.get(node._nid);
- if( nd!=null && d <= nd ) return; // Been there, done that
- Integer old = ds.put(node._nid,d) ;
- if( old == null )
- ns.add(node);
- if( d == 0 ) return; // Depth cutoff
- for( Node def : node._inputs )
- if( def != null &&
- !(node instanceof LoopNode loop && loop.back()==def) &&
- // Don't walk into or out of functions
- !(node instanceof CallEndNode && def instanceof ReturnNode) &&
- !(node instanceof FunNode && def instanceof CallNode) &&
- !(node instanceof ParmNode && !(def instanceof FunNode))
- )
- _walk(ds,ns,def,d-1);
- }
+import com.seaofnodes.simple.util.SB;
+import com.seaofnodes.simple.codegen.CodeGen;
- static String label( CFGNode blk ) {
- if( blk instanceof StartNode ) return "START";
- return (blk instanceof LoopNode ? "LOOP" : "L")+blk._nid;
- }
- static void label( SB sb, CFGNode blk ) {
- if( !blk.blockHead() ) blk = blk.cfg(0);
- sb.p( "%-9.9s ".formatted( label( blk ) ) );
+/** This chapter's read-only IR facts and the familiar debugger entry points. */
+public final class IRPrinter extends IRAdapter<Node> {
+ private static final com.seaofnodes.print.IRPrinter<Node> PRINT =
+ new com.seaofnodes.print.IRPrinter<>(new IRPrinter());
+ @Override public boolean global(Node n) { return n.isConst(); }
+ @Override public String type(Node n) { return n._type==null ? "" : n._type.str(); }
+ @Override public String inputMark(Node n, Node def) { return n instanceof MemMergeNode && def instanceof MemMergeNode ? "^" : " "; }
+ @Override public Kind kind(Node n) {
+ if( n instanceof StartNode ) return Kind.START;
+ if( n instanceof StopNode ) return Kind.STOP;
+ if( n instanceof FunNode ) return Kind.FUN;
+ if( n instanceof LoopNode ) return Kind.LOOP;
+ if( n instanceof RegionNode ) return Kind.REGION;
+ if( n instanceof ParmNode ) return Kind.PARM;
+ if( n instanceof PhiNode ) return Kind.PHI;
+ if( n instanceof CallEndNode ) return Kind.CALL_END;
+ if( n instanceof CallNode ) return Kind.CALL;
+ if( n instanceof ReturnNode ) return Kind.RETURN;
+ if( n instanceof ConstantNode ) return Kind.CONSTANT;
+ if( n instanceof CProjNode ) return Kind.CPROJ;
+ if( n instanceof ProjNode ) return n instanceof CFGNode ? Kind.CPROJ : Kind.PROJ;
+ if( n instanceof CFGNode ) return Kind.CTRL;
+ if( n instanceof MultiNode ) return Kind.MULTI;
+ return Kind.DATA;
+ }
+ @Override public int index(Node n) {
+ if( n instanceof ProjNode p ) return p._idx;
+ if( n instanceof CProjNode p ) return p._idx;
+ return n._nid;
+ }
+ @Override public String functionName(Node n) { return ((FunNode)n)._name==null ? "" : ((FunNode)n)._name; }
+ @Override public String signature(Node n) {
+ FunNode fun=(FunNode)n;
+ return (fun._name==null ? "" : fun._name)+" "+fun.sig().str();
+ }
+
+ public static String prettyPrint(Node n, int depth) { return PRINT.prettyPrint(n,depth); }
+ public static SB printLine(Node n, SB sb) { return sb.p(PRINT.line(n)); }
+
+ public static String prettyPrint(CodeGen code) {
+ var units=new ArrayList<com.seaofnodes.print.IRPrinter.Unit<Node>>();
+ var funs=new ArrayList<Node>();
+ for( Node n : code._start._outputs ) if( n instanceof FunNode ) funs.add(n);
+ units.add(new com.seaofnodes.print.IRPrinter.Unit<>(null,null,null,funs));
+ return PRINT.program(code._start,code._stop,units);
+ }
+ public static String _prettyPrint(CodeGen code) {
+ if( code._cfg==null ) return prettyPrint(code);
+ var blocks=new ArrayList<Node>();
+ for( Node n : code._cfg ) blocks.add(n);
+ return PRINT.scheduled(blocks);
}
- static void printLine( Node n, SB sb, Ary<Node> bns, int i, HashMap<Integer,Integer> ds, Ary<Node> ns ) {
- printLine( n, sb );
- if( i != -1 ) bns.del(i);
- ds.remove(n._nid);
- int idx = ns.find(n);
- if( idx!=-1 ) ns.del(idx);
- }
-
}
diff --git a/chapter23/src/main/java/com/seaofnodes/simple/print/SimpleGraphAdapter.java b/chapter23/src/main/java/com/seaofnodes/simple/print/SimpleGraphAdapter.java
index 6f19fa9d..785049dc 100644
--- a/chapter23/src/main/java/com/seaofnodes/simple/print/SimpleGraphAdapter.java
+++ b/chapter23/src/main/java/com/seaofnodes/simple/print/SimpleGraphAdapter.java
@@ -1,45 +1,25 @@
package com.seaofnodes.simple.print;
import com.seaofnodes.graph.GraphAdapter;
-import com.seaofnodes.graph.GraphSnapshot;
import com.seaofnodes.graph.GraphSnapshot.*;
import com.seaofnodes.simple.node.*;
import com.seaofnodes.simple.node.Node;
import com.seaofnodes.simple.type.TypeMem;
-import java.util.ArrayList;
/** Chapter 23's view of the IR; browser, transport and layout are shared. */
public class SimpleGraphAdapter extends GraphAdapter<Node> {
- @Override protected boolean dead(Node n) { return n.isDead(); }
- @Override protected int id(Node n) { return n._nid; }
- @Override protected int nIns(Node n) { return n.nIns(); }
- @Override protected Node in(Node n, int idx) { return n.in(idx); }
- @Override protected int nOuts(Node n) { return n.nOuts(); }
- @Override protected Node out(Node n, int idx) { return n.out(idx); }
- @Override protected int nDeps(Node n) { return n.nDeps(); }
- @Override protected Node dep(Node n, int idx) { return n.dep(idx); }
- private ArrayList<Edge> edges(Node n) {
- var edges = new ArrayList<Edge>();
- for( int i = 0; i < n.nIns(); i++ ) {
- String name = n instanceof ScopeNode scope && i < scope._vars.size()
+ @Override protected String edgeName(Node n, int i) {
+ return n instanceof ScopeNode scope && i < scope._vars.size()
? scope._vars.get(i)._name : null;
- int jump = n instanceof CallEndNode && i>0 && n.in(i) instanceof ReturnNode ret
- ? ref(ret.fun()) : 0;
- edges.add(new Edge(i, ref(n.in(i)), role(n, i), name, jump));
- }
- return edges;
}
-
- @Override protected GraphSnapshot.Node desc(Node n) {
- Projection proj = n instanceof ProjNode p ? new Projection(ref(n.in(0)), p._idx)
- : n instanceof CProjNode p ? new Projection(ref(n.in(0)), p._idx) : null;
- String label = n.label();
- return new GraphSnapshot.Node(n._nid, label == null ? n.getClass().getSimpleName() : label,
- n._type == null ? null : n._type.toString(), kind(n), edges(n), proj, folding(n));
+ @Override protected int edgeJump(Node n, int i) {
+ return n instanceof CallEndNode && i>0 && n.in(i) instanceof ReturnNode ret
+ ? ref(ret.fun()) : 0;
}
+ @Override protected int projectionIndex(Node n) { return n instanceof ProjNode p ? p._idx : n instanceof CProjNode p ? p._idx : -1; }
- private boolean folding(Node n) {
+ @Override protected boolean folding(Node n) {
if( n instanceof FunNode fun ) return fun.folding();
if( n instanceof ReturnNode ret ) return ret.fun().folding();
if( n instanceof CallEndNode cend ) return cend.folding();
@@ -49,7 +29,7 @@ public class SimpleGraphAdapter extends GraphAdapter<Node> {
return false;
}
- private Kind kind(Node n) {
+ @Override protected Kind kind(Node n) {
if( n instanceof StopNode ) return Kind.STOP;
if( n instanceof ScopeNode ) return Kind.SCOPE;
if( n instanceof FunNode ) return Kind.FUN;
@@ -60,7 +40,7 @@ public class SimpleGraphAdapter extends GraphAdapter<Node> {
return n instanceof CFGNode ? Kind.CTRL : isMem(n) ? Kind.MEM : Kind.DATA;
}
- private Role role(Node n, int i) {
+ @Override protected Role role(Node n, int i) {
if( n instanceof ScopeNode || n instanceof ConstantNode || n instanceof CtrlNode || n instanceof XCtrlNode ) return Role.ASSOC;
if( n instanceof PhiNode ) return i == 0 ? Role.ASSOC : isMem(n) ? Role.MEM : Role.DATA;
if( n instanceof ProjNode || n instanceof CProjNode )
diff --git a/chapter24/Makefile b/chapter24/Makefile
index 94605e84..1c3f409f 100644
--- a/chapter24/Makefile
+++ b/chapter24/Makefile
@@ -65,6 +65,7 @@ main_javas := $(wildcard $(SRC)/$(SIMPLE)/*java $(SRC)/$(SIMPLE)/*/*java $(SRC
test_javas := $(wildcard $(TST)/$(SIMPLE)/*java $(TST)/$(SIMPLE)/*/*java)
main_classes := $(patsubst $(SRC)/%java,$(CLZDIR)/main/%class,$(main_javas))
include $(firstword $(wildcard ../graph/graph.mk graph/graph.mk))
+include $(firstword $(wildcard ../print/print.mk print/print.mk))
test_classes := $(patsubst $(TST)/%java,$(CLZDIR)/test/%class,$(test_javas))
test_cp := $(patsubst $(TST)/$(SIMPLE)/%.java,com.seaofnodes.simple.%,$(wildcard $(TST)/$(SIMPLE)/*Test.java)) com.seaofnodes.simple.codegen.X86EncodingTest
classes = $(main_classes) $(test_classes)
diff --git a/chapter24/pom.xml b/chapter24/pom.xml
index c487fbff..07a943f9 100644
--- a/chapter24/pom.xml
+++ b/chapter24/pom.xml
@@ -13,5 +13,6 @@
<name>Chapter 24</name>
<properties>
<simple.graph.directory>${project.basedir}/../graph</simple.graph.directory>
+ <simple.print.directory>${project.basedir}/../print</simple.print.directory>
</properties>
</project>
diff --git a/chapter24/src/main/java/com/seaofnodes/simple/codegen/CodeGen.java b/chapter24/src/main/java/com/seaofnodes/simple/codegen/CodeGen.java
index 3ae22b68..f3d3dee3 100644
--- a/chapter24/src/main/java/com/seaofnodes/simple/codegen/CodeGen.java
+++ b/chapter24/src/main/java/com/seaofnodes/simple/codegen/CodeGen.java
@@ -440,7 +440,7 @@ public class CodeGen {
@Override public String toString() {
return _phase.ordinal() > Phase.Schedule.ordinal()
? IRPrinter._prettyPrint( this )
- : _stop.p(9999);
+ : IRPrinter.prettyPrint(this);
}
// Debugging helper
diff --git a/chapter24/src/main/java/com/seaofnodes/simple/node/ArithFNode.java b/chapter24/src/main/java/com/seaofnodes/simple/node/ArithFNode.java
index 3c20fa6e..dafba626 100644
--- a/chapter24/src/main/java/com/seaofnodes/simple/node/ArithFNode.java
+++ b/chapter24/src/main/java/com/seaofnodes/simple/node/ArithFNode.java
@@ -1,17 +1,15 @@
package com.seaofnodes.simple.node;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeFloat;
-import java.util.BitSet;
public abstract class ArithFNode extends Node {
public ArithFNode(Node lhs, Node rhs) { super(null, lhs, rhs); }
- @Override
- public StringBuilder _print1(StringBuilder sb, BitSet visited) {
- in(1)._print0(sb.append("("), visited);
- in(2)._print0(sb.append(glabel()), visited);
- return sb.append(")");
+ @Override protected ExprPrinter<Node> _print1(ExprPrinter<Node> p) {
+ return p.open().n(in(1)).p(glabel()).n(in(2)).close();
}
abstract double doOp(double x, double y);
diff --git a/chapter24/src/main/java/com/seaofnodes/simple/node/ArithNode.java b/chapter24/src/main/java/com/seaofnodes/simple/node/ArithNode.java
index e9a60f50..54290330 100644
--- a/chapter24/src/main/java/com/seaofnodes/simple/node/ArithNode.java
+++ b/chapter24/src/main/java/com/seaofnodes/simple/node/ArithNode.java
@@ -1,10 +1,11 @@
package com.seaofnodes.simple.node;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.Parser;
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeInteger;
-import java.util.BitSet;
public abstract class ArithNode extends Node {
// Source location for late reported errors
@@ -13,11 +14,8 @@ public abstract class ArithNode extends Node {
public ArithNode( Parser.Lexer loc, Node lhs, Node rhs) { super(null, lhs, rhs); _loc = loc; }
abstract String op();
- @Override
- public StringBuilder _print1(StringBuilder sb, BitSet visited) {
- in(1)._print0(sb.append("("), visited);
- in(2)._print0(sb.append(op()), visited);
- return sb.append(")");
+ @Override protected ExprPrinter<Node> _print1(ExprPrinter<Node> p) {
+ return p.open().n(in(1)).p(op()).n(in(2)).close();
}
abstract long doOp(long x, long y);
diff --git a/chapter24/src/main/java/com/seaofnodes/simple/node/BoolNode.java b/chapter24/src/main/java/com/seaofnodes/simple/node/BoolNode.java
index 1a837435..0d82c5b9 100644
--- a/chapter24/src/main/java/com/seaofnodes/simple/node/BoolNode.java
+++ b/chapter24/src/main/java/com/seaofnodes/simple/node/BoolNode.java
@@ -1,9 +1,10 @@
package com.seaofnodes.simple.node;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.Parser;
import com.seaofnodes.simple.type.*;
import com.seaofnodes.simple.util.Utils;
-import java.util.BitSet;
import static com.seaofnodes.simple.type.TypeInteger.*;
abstract public class BoolNode extends Node {
@@ -17,11 +18,8 @@ abstract public class BoolNode extends Node {
@Override
public String label() { return getClass().getSimpleName(); }
- @Override
- public StringBuilder _print1(StringBuilder sb, BitSet visited) {
- in(1)._print0(sb.append("("), visited);
- in(2)._print0(sb.append(op()), visited);
- return sb.append(")");
+ @Override protected ExprPrinter<Node> _print1(ExprPrinter<Node> p) {
+ return p.open().n(in(1)).p(op()).n(in(2)).close();
}
@Override
diff --git a/chapter24/src/main/java/com/seaofnodes/simple/node/CProjNode.java b/chapter24/src/main/java/com/seaofnodes/simple/node/CProjNode.java
index d18f779b..c62de840 100644
--- a/chapter24/src/main/java/com/seaofnodes/simple/node/CProjNode.java
+++ b/chapter24/src/main/java/com/seaofnodes/simple/node/CProjNode.java
@@ -1,11 +1,12 @@
package com.seaofnodes.simple.node;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.Parser;
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeMem;
import com.seaofnodes.simple.type.TypeTuple;
import com.seaofnodes.simple.util.Utils;
-import java.util.BitSet;
public class CProjNode extends CFGNode {
@@ -24,7 +25,7 @@ public class CProjNode extends CFGNode {
@Override public String label() { return _label; }
- @Override public StringBuilder _print1(StringBuilder sb, BitSet visited) { return sb.append(_label); }
+ @Override protected ExprPrinter<Node> _print1(ExprPrinter<Node> p) { return p.p(_label); }
@Override public boolean blockHead() { return true; }
diff --git a/chapter24/src/main/java/com/seaofnodes/simple/node/CallEndNode.java b/chapter24/src/main/java/com/seaofnodes/simple/node/CallEndNode.java
index 238f5582..fb57a090 100644
--- a/chapter24/src/main/java/com/seaofnodes/simple/node/CallEndNode.java
+++ b/chapter24/src/main/java/com/seaofnodes/simple/node/CallEndNode.java
@@ -1,9 +1,10 @@
package com.seaofnodes.simple.node;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.*;
import com.seaofnodes.simple.codegen.*;
import com.seaofnodes.simple.type.*;
-import java.util.BitSet;
/**
* CallEnd
@@ -29,13 +30,12 @@ public class CallEndNode extends CFGNode implements MultiNode {
}
@Override
- public StringBuilder _print1(StringBuilder sb, BitSet visited) {
- sb.append("cend( ");
- sb.append( in(0) instanceof CallNode ? "Call, " : "----, ");
+ protected ExprPrinter<Node> _print1(ExprPrinter<Node> p) {
+ p.p("cend( ");
+ p.p( in(0) instanceof CallNode ? "Call, " : "----, ");
for( int i=1; i<nIns()-1; i++ )
- in(i)._print0(sb,visited).append(",");
- sb.setLength(sb.length()-1);
- return sb.append(")");
+ p.n(in(i)).p(",");
+ return p.unchar(',').unchar(' ').close();
}
@Override
diff --git a/chapter24/src/main/java/com/seaofnodes/simple/node/CallNode.java b/chapter24/src/main/java/com/seaofnodes/simple/node/CallNode.java
index 965efd99..569c0877 100644
--- a/chapter24/src/main/java/com/seaofnodes/simple/node/CallNode.java
+++ b/chapter24/src/main/java/com/seaofnodes/simple/node/CallNode.java
@@ -1,12 +1,13 @@
package com.seaofnodes.simple.node;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.IterPeeps;
import com.seaofnodes.simple.Parser;
import com.seaofnodes.simple.codegen.CodeGen;
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeFunPtr;
import com.seaofnodes.simple.util.Utils;
-import java.util.BitSet;
/**
* Call
@@ -21,15 +22,14 @@ public class CallNode extends CFGNode {
@Override public String label() { return "Call"; }
- @Override public StringBuilder _print1(StringBuilder sb, BitSet visited) {
+ @Override protected ExprPrinter<Node> _print1(ExprPrinter<Node> p) {
String fname = name();
- if( fname == null ) fptr()._print0(sb,visited);
- else sb.append(fname);
- sb.append("( ");
+ if( fname == null ) p.n(fptr());
+ else p.p(fname);
+ p.p("( ");
for( int i=2; i<nIns()-1; i++ )
- in(i)._print0(sb,visited).append(",");
- sb.setLength(sb.length()-1);
- return sb.append(")");
+ p.n(in(i)).p(",");
+ return p.unchar(',').unchar(' ').close();
}
public String name() {
if( fptr()._type instanceof TypeFunPtr tfp && tfp._isConstant() && tfp.notNull() ) {
diff --git a/chapter24/src/main/java/com/seaofnodes/simple/node/CastNode.java b/chapter24/src/main/java/com/seaofnodes/simple/node/CastNode.java
index f3436f56..08d72e35 100644
--- a/chapter24/src/main/java/com/seaofnodes/simple/node/CastNode.java
+++ b/chapter24/src/main/java/com/seaofnodes/simple/node/CastNode.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.Type;
import com.seaofnodes.simple.type.TypeInteger;
import com.seaofnodes.simple.type.TypeMemPtr;
import com.seaofnodes.simple.util.Utils;
-import java.util.BitSet;
// Upcast (join) the input to a t. Used after guard test to lift an input.
// Can also be used to make a type-assertion if ctrl is null.
@@ -25,14 +26,11 @@ public class CastNode extends Node {
@Override public String label() { return "("+_t.str()+")"; }
- @Override
- public String uniqueName() { return "Cast_" + _nid; }
@Override public boolean isConst() { return true; }
- @Override
- public StringBuilder _print1(StringBuilder sb, BitSet visited) {
- return in(1)._print0(sb.append(label()), visited);
+ @Override protected ExprPrinter<Node> _print1(ExprPrinter<Node> p) {
+ return p.p(label()).n(in(1));
}
@Override
diff --git a/chapter24/src/main/java/com/seaofnodes/simple/node/ConFldOffNode.java b/chapter24/src/main/java/com/seaofnodes/simple/node/ConFldOffNode.java
index 56c125e2..afdd29be 100644
--- a/chapter24/src/main/java/com/seaofnodes/simple/node/ConFldOffNode.java
+++ b/chapter24/src/main/java/com/seaofnodes/simple/node/ConFldOffNode.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.TypeInteger;
import com.seaofnodes.simple.type.TypeStruct;
import com.seaofnodes.simple.util.SB;
-import java.util.BitSet;
/**
* A field offset. This becomes a constant *after* other optimizations which
@@ -21,11 +22,9 @@ public class ConFldOffNode extends ConstantNode {
@Override public String label() {
return _fname == " len" ? "sizeof("+_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());
}
// Convert field offset to an integer
diff --git a/chapter24/src/main/java/com/seaofnodes/simple/node/ConstantNode.java b/chapter24/src/main/java/com/seaofnodes/simple/node/ConstantNode.java
index d3fe328a..7c330175 100644
--- a/chapter24/src/main/java/com/seaofnodes/simple/node/ConstantNode.java
+++ b/chapter24/src/main/java/com/seaofnodes/simple/node/ConstantNode.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.Type;
import com.seaofnodes.simple.type.TypeFunPtr;
import com.seaofnodes.simple.util.SB;
-import java.util.BitSet;
/**
* A Constant node represents a constant value.
@@ -34,17 +35,20 @@ public class ConstantNode extends Node {
return new ConstantNode(type);
}
- @Override public String label() { return "#"+_con; }
- @Override public String uniqueName() { return "Con_" + _nid; }
+ @Override protected String repeatName() {
+ return _con==null || _con.toString().length()<=32 ? null : uniqueName();
+ }
+
+ @Override public String label() { return "Con"; }
@Override
- public StringBuilder _print1(StringBuilder sb, BitSet visited) {
+ protected ExprPrinter<Node> _print1(ExprPrinter<Node> p) {
if( _con instanceof TypeFunPtr tfp && tfp._isConstant() && tfp.notNull() ) {
FunNode fun = CodeGen.CODE._link(tfp);
if( fun!=null && fun._name != null )
- return sb.append("{ ").append(fun._name).append("}");
+ return p.p("{ ").p(fun._name).p("}");
}
- return sb.append(_con==null ? "---" : _con.toString());
+ return p.p(_con==null ? "---" : _con.toString());
}
@Override public boolean isConst() { return true; }
diff --git a/chapter24/src/main/java/com/seaofnodes/simple/node/CtrlNode.java b/chapter24/src/main/java/com/seaofnodes/simple/node/CtrlNode.java
index eda7d684..cf630ad4 100644
--- a/chapter24/src/main/java/com/seaofnodes/simple/node/CtrlNode.java
+++ b/chapter24/src/main/java/com/seaofnodes/simple/node/CtrlNode.java
@@ -1,14 +1,15 @@
package com.seaofnodes.simple.node;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.codegen.CodeGen;
import com.seaofnodes.simple.Parser;
import com.seaofnodes.simple.type.Type;
-import java.util.BitSet;
public class CtrlNode extends CFGNode {
public CtrlNode() { super(CodeGen.CODE._start); }
@Override public String label() { return "Ctrl"; }
- @Override public StringBuilder _print1(StringBuilder sb, BitSet visited) { return sb.append("Cctrl"); }
+ @Override protected ExprPrinter<Node> _print1(ExprPrinter<Node> p) { return p.p("Cctrl"); }
@Override public boolean isConst() { return true; }
@Override public Type compute() { return Type.CONTROL; }
@Override public Node idealize() { return null; }
diff --git a/chapter24/src/main/java/com/seaofnodes/simple/node/ExternNode.java b/chapter24/src/main/java/com/seaofnodes/simple/node/ExternNode.java
index 21ef8eff..ccbcfc66 100644
--- a/chapter24/src/main/java/com/seaofnodes/simple/node/ExternNode.java
+++ b/chapter24/src/main/java/com/seaofnodes/simple/node/ExternNode.java
@@ -16,7 +16,6 @@ public class ExternNode extends ConstantNode {
public ExternNode(Type t, String ex) { super(t); _extern = ex; }
@Override public String label() { return "#"+_con+":"+_extern; }
- @Override public String uniqueName() { return "Extern_" + _nid; }
@Override public boolean eq(Node n) { return this==n; }
}
diff --git a/chapter24/src/main/java/com/seaofnodes/simple/node/FRefNode.java b/chapter24/src/main/java/com/seaofnodes/simple/node/FRefNode.java
index 6093b8a6..e7333c23 100644
--- a/chapter24/src/main/java/com/seaofnodes/simple/node/FRefNode.java
+++ b/chapter24/src/main/java/com/seaofnodes/simple/node/FRefNode.java
@@ -1,9 +1,10 @@
package com.seaofnodes.simple.node;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.Parser;
import com.seaofnodes.simple.Var;
import com.seaofnodes.simple.type.Type;
-import java.util.BitSet;
/**
* A Forward Reference. Its any final constant, including functions. When
@@ -17,10 +18,9 @@ public class FRefNode extends ConstantNode {
@Override public String label() { return "FRef"+_n; }
- @Override public String uniqueName() { return "FRef_" + _nid; }
- @Override public StringBuilder _print1(StringBuilder sb, BitSet visited) {
- return sb.append("FRef_").append(_n);
+ @Override protected ExprPrinter<Node> _print1(ExprPrinter<Node> p) {
+ return p.p("FRef_").p(_n);
}
@Override public Node idealize() {
diff --git a/chapter24/src/main/java/com/seaofnodes/simple/node/FunPtrNode.java b/chapter24/src/main/java/com/seaofnodes/simple/node/FunPtrNode.java
index 7f32698e..43242c32 100644
--- a/chapter24/src/main/java/com/seaofnodes/simple/node/FunPtrNode.java
+++ b/chapter24/src/main/java/com/seaofnodes/simple/node/FunPtrNode.java
@@ -9,5 +9,4 @@ public class FunPtrNode extends ConstantNode {
addDef(ret);
}
public ReturnNode ret() { return (ReturnNode)in(1); }
- @Override public String uniqueName() { return "FunPtr_"+_nid; }
}
diff --git a/chapter24/src/main/java/com/seaofnodes/simple/node/IfNode.java b/chapter24/src/main/java/com/seaofnodes/simple/node/IfNode.java
index 5d751602..c96993e5 100644
--- a/chapter24/src/main/java/com/seaofnodes/simple/node/IfNode.java
+++ b/chapter24/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 {
@@ -17,11 +18,11 @@ public class IfNode extends CFGNode implements MultiNode {
public String label() { return "If"; }
@Override
- public StringBuilder _print1(StringBuilder sb, BitSet visited) {
- sb.append("if( ");
- if( in(1)==null ) sb.append("never");
- else in(1)._print0(sb, visited);
- return sb.append(" )");
+ protected ExprPrinter<Node> _print1(ExprPrinter<Node> p) {
+ p.p("if( ");
+ if( in(1)==null ) p.p("never");
+ else p.n(in(1));
+ return p.p(" )");
}
public Node ctrl() { return in(0); }
diff --git a/chapter24/src/main/java/com/seaofnodes/simple/node/LoadNode.java b/chapter24/src/main/java/com/seaofnodes/simple/node/LoadNode.java
index 12095868..f39ecf37 100644
--- a/chapter24/src/main/java/com/seaofnodes/simple/node/LoadNode.java
+++ b/chapter24/src/main/java/com/seaofnodes/simple/node/LoadNode.java
@@ -1,5 +1,7 @@
package com.seaofnodes.simple.node;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.codegen.CodeGen;
import com.seaofnodes.simple.Parser;
import com.seaofnodes.simple.type.*;
@@ -46,7 +48,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/chapter24/src/main/java/com/seaofnodes/simple/node/MachConcreteNode.java b/chapter24/src/main/java/com/seaofnodes/simple/node/MachConcreteNode.java
index 9440a7ea..9c0755b9 100644
--- a/chapter24/src/main/java/com/seaofnodes/simple/node/MachConcreteNode.java
+++ b/chapter24/src/main/java/com/seaofnodes/simple/node/MachConcreteNode.java
@@ -1,9 +1,10 @@
package com.seaofnodes.simple.node;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.util.Utils;
import java.io.ByteArrayOutputStream;
-import java.util.BitSet;
// Generic machine-specific class, has a few Node implementations that have to
// exist (abstract) but are not useful past the optimizer.
@@ -16,12 +17,11 @@ public abstract class MachConcreteNode extends Node implements MachNode {
@Override public Type compute () { throw Utils.TODO(); }
@Override public Node idealize() { throw Utils.TODO(); }
- @Override public StringBuilder _print1(StringBuilder sb, BitSet visited) {
- sb.append("(").append(op()).append(",");
+ @Override protected ExprPrinter<Node> _print1(ExprPrinter<Node> p) {
+ p.open().p(op()).p(",");
for( int i=1; i<nIns(); i++ )
- (in(i)==null ? sb.append(" ---") : in(i)._print0(sb, visited)).append(",");
- sb.setLength(sb.length()-1);
- return sb.append(")");
+ (in(i)==null ? p.p(" ---") : p.n(in(i))).p(",");
+ return p.unchar(',').close();
}
}
diff --git a/chapter24/src/main/java/com/seaofnodes/simple/node/MemMergeNode.java b/chapter24/src/main/java/com/seaofnodes/simple/node/MemMergeNode.java
index 2894556c..a9c110ac 100644
--- a/chapter24/src/main/java/com/seaofnodes/simple/node/MemMergeNode.java
+++ b/chapter24/src/main/java/com/seaofnodes/simple/node/MemMergeNode.java
@@ -1,5 +1,7 @@
package com.seaofnodes.simple.node;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.*;
import com.seaofnodes.simple.codegen.CodeGen;
import com.seaofnodes.simple.type.*;
@@ -53,14 +55,14 @@ public class MemMergeNode extends Node {
@Override public String label() { return "MemMerge"; }
@Override public boolean isMem() { return true; }
- @Override public StringBuilder _print1(StringBuilder sb, BitSet visited) {
- sb.append("MEM[");
+ @Override protected ExprPrinter<Node> _print1(ExprPrinter<Node> p) {
+ p.p("MEM[");
for( int i=1; i<nIns(); i++ )
if( in(i)!=null ) {
- sb.append(i==1 ? "default:" : i+":");
- in(i)._print0(sb,visited).append(" ");
+ p.p(i==1 ? "default:" : i+":");
+ p.n(in(i)).p(" ");
}
- return sb.append("]");
+ return p.p("]");
}
diff --git a/chapter24/src/main/java/com/seaofnodes/simple/node/MemOpNode.java b/chapter24/src/main/java/com/seaofnodes/simple/node/MemOpNode.java
index 65021110..e7b2c792 100644
--- a/chapter24/src/main/java/com/seaofnodes/simple/node/MemOpNode.java
+++ b/chapter24/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.type.Type;
import com.seaofnodes.simple.type.TypeMemPtr;
@@ -85,8 +87,8 @@ public abstract class MemOpNode extends Node {
public Node ptr() { return in(2); }
public Node off() { return in(3); }
- @Override public StringBuilder _print1( StringBuilder sb, BitSet visited ) { return _printMach(sb,visited); }
- public StringBuilder _printMach( StringBuilder sb, BitSet visited ) { throw Utils.TODO(); }
+ @Override protected ExprPrinter<Node> _print1(ExprPrinter<Node> p) { return _printMach(p); }
+ protected ExprPrinter<Node> _printMach(ExprPrinter<Node> p) { throw Utils.TODO(); }
public int log_size() { return _declaredType.log_size(); }
// Extra conditions for factoring matching memory operations through a Phi.
diff --git a/chapter24/src/main/java/com/seaofnodes/simple/node/MinusFNode.java b/chapter24/src/main/java/com/seaofnodes/simple/node/MinusFNode.java
index aa66a7f0..74439b8c 100644
--- a/chapter24/src/main/java/com/seaofnodes/simple/node/MinusFNode.java
+++ b/chapter24/src/main/java/com/seaofnodes/simple/node/MinusFNode.java
@@ -1,20 +1,16 @@
package com.seaofnodes.simple.node;
+
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeFloat;
-import java.util.BitSet;
public class MinusFNode extends Node {
public MinusFNode(Node in) { super(null, in); }
@Override public String label() { return "MinusF"; }
- @Override
- public StringBuilder _print1(StringBuilder sb, BitSet visited) {
- in(1)._print0(sb.append("(-"), visited);
- return sb.append(")");
- }
+ @Override protected String format() { return "(-%1)"; }
@Override
public Type compute() {
diff --git a/chapter24/src/main/java/com/seaofnodes/simple/node/MinusNode.java b/chapter24/src/main/java/com/seaofnodes/simple/node/MinusNode.java
index e87d8dd4..900f673f 100644
--- a/chapter24/src/main/java/com/seaofnodes/simple/node/MinusNode.java
+++ b/chapter24/src/main/java/com/seaofnodes/simple/node/MinusNode.java
@@ -1,20 +1,16 @@
package com.seaofnodes.simple.node;
+
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeInteger;
import com.seaofnodes.simple.util.Utils;
-import java.util.BitSet;
public class MinusNode extends Node {
public MinusNode(Node in) { super(null, in); }
@Override public String label() { return "Minus"; }
- @Override
- public StringBuilder _print1(StringBuilder sb, BitSet visited) {
- in(1)._print0(sb.append("(-"), visited);
- return sb.append(")");
- }
+ @Override protected String format() { return "(-%1)"; }
@Override
public Type compute() {
diff --git a/chapter24/src/main/java/com/seaofnodes/simple/node/NeverNode.java b/chapter24/src/main/java/com/seaofnodes/simple/node/NeverNode.java
index 516f218b..66879b66 100644
--- a/chapter24/src/main/java/com/seaofnodes/simple/node/NeverNode.java
+++ b/chapter24/src/main/java/com/seaofnodes/simple/node/NeverNode.java
@@ -1,11 +1,12 @@
package com.seaofnodes.simple.node;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.Parser;
import com.seaofnodes.simple.type.TypeInteger;
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeTuple;
-import java.util.BitSet;
// "Never true" for infinite loop exits
public class NeverNode extends IfNode {
@@ -14,7 +15,7 @@ public class NeverNode extends IfNode {
@Override public String label() { return "Never"; }
- @Override public StringBuilder _print1(StringBuilder sb, BitSet visited) { return sb.append("Never"); }
+ @Override protected ExprPrinter<Node> _print1(ExprPrinter<Node> p) { return p.p("Never"); }
@Override public Type compute() { return TypeTuple.IF_BOTH; }
diff --git a/chapter24/src/main/java/com/seaofnodes/simple/node/NewNode.java b/chapter24/src/main/java/com/seaofnodes/simple/node/NewNode.java
index 5d4d5bf0..840d2759 100644
--- a/chapter24/src/main/java/com/seaofnodes/simple/node/NewNode.java
+++ b/chapter24/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.SB;
import com.seaofnodes.simple.util.Utils;
-import java.util.BitSet;
/** Allocate a zeroed object. Inputs {ctrl, $mem, size};
* results {ptr, $mem}.
@@ -38,10 +39,8 @@ public class NewNode extends Node implements MultiNode {
@Override public String label() { return "new_"+(_ptr._obj.isAry() ? "ary_"+_ptr._obj._fields[1]._t.str() : _ptr._obj.str()); }
- @Override
- public StringBuilder _print1(StringBuilder sb, BitSet visited) {
- sb.append("new ");
- return sb.append(_ptr._obj.str());
+ @Override protected ExprPrinter<Node> _print1(ExprPrinter<Node> p) {
+ return p.p("new ").p(_ptr._obj.str());
}
diff --git a/chapter24/src/main/java/com/seaofnodes/simple/node/Node.java b/chapter24/src/main/java/com/seaofnodes/simple/node/Node.java
index 48e3d63f..414530b4 100644
--- a/chapter24/src/main/java/com/seaofnodes/simple/node/Node.java
+++ b/chapter24/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.util.Ary;
@@ -18,14 +20,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.
@@ -47,16 +42,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);
@@ -68,8 +61,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;
@@ -80,48 +73,6 @@ public abstract class Node implements Cloneable {
// Easy reading label for debugger, e.g. "Add" or "Region" or "EQ"
public abstract String label();
- // Unique label for debugging, e.g. "Add12" or "Region30" or "EQ99"
- public String uniqueName() {
- return label() + _nid;
- }
-
- // Operator symbol used by assembly/debug printing.
- public String glabel() { return label(); }
-
- // Extra fun stuff, for assembly printing. Jump labels, parser locations,
- // variable types, etc.
- public String comment() { return null; }
-
- // ------------------------------------------------------------------------
-
- // Debugger Printing.
-
- // {@code toString} is what you get in the debugger. It has to print 1
- // line (because this is what a debugger typically displays by default) and
- // has to be robust with broken graph/nodes.
- @Override
- public final String toString() { return print(); }
-
- // This is a *deep* print. We print with a mutually recursive tik-tok
- // style; the common _print0 calls the per-Node _print1, which calls back
- // to _print0;
- public final String print() {
- return _print0(new StringBuilder(), new BitSet()).toString();
- }
-
- // This is the common print: check for repeats, check for DEAD and print
- // "DEAD" else call the per-Node print1.
- public final StringBuilder _print0(StringBuilder sb, BitSet visited) {
- if (visited.get(_nid) && !(this instanceof ConstantNode) )
- return sb.append(label());
- visited.set(_nid);
- return isDead()
- ? sb.append(uniqueName()).append(":DEAD")
- : _print1(sb, visited);
- }
- // Every Node implements this; a partial-line recursive print
- abstract public StringBuilder _print1(StringBuilder sb, BitSet visited);
-
public String p(int depth) { return IRPrinter.prettyPrint(this,depth); }
public boolean isConst() { return false; }
@@ -129,6 +80,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
@@ -207,7 +160,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.
@@ -279,7 +231,6 @@ public abstract class Node implements Cloneable {
kill();
}
-
// Mostly used for asserts and printing.
public boolean isDead() { return isUnused() && nIns()==0 && _type==null; }
@@ -301,7 +252,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;
@@ -543,7 +493,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
@@ -602,7 +551,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
@@ -618,7 +566,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;
@@ -638,7 +585,6 @@ public abstract class Node implements Cloneable {
/** Is this Node Memory related */
public boolean isMem() { return false; }
-
// Semantic change to the graph (so NOT a peephole), used by the Parser.
// If any input is a float, flip to a float-flavored opcode and widen any
// non-float input.
@@ -659,7 +605,6 @@ public abstract class Node implements Cloneable {
}
Node copyF() { return null; }
-
// ------------------------------------------------------------------------
// Peephole utilities
@@ -686,7 +631,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/chapter24/src/main/java/com/seaofnodes/simple/node/NotNode.java b/chapter24/src/main/java/com/seaofnodes/simple/node/NotNode.java
index 1cbd2402..775b069b 100644
--- a/chapter24/src/main/java/com/seaofnodes/simple/node/NotNode.java
+++ b/chapter24/src/main/java/com/seaofnodes/simple/node/NotNode.java
@@ -1,19 +1,15 @@
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 String label() { return "Not"; }
- @Override
- public StringBuilder _print1(StringBuilder sb, BitSet visited) {
- in(1)._print0(sb.append("(!"), visited);
- return sb.append(")");
- }
+ @Override protected String format() { return "(!%1)"; }
@Override
public TypeInteger compute() {
diff --git a/chapter24/src/main/java/com/seaofnodes/simple/node/ParmNode.java b/chapter24/src/main/java/com/seaofnodes/simple/node/ParmNode.java
index 48d05e6b..95934e4b 100644
--- a/chapter24/src/main/java/com/seaofnodes/simple/node/ParmNode.java
+++ b/chapter24/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.Parser;
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeMemPtr;
-import java.util.BitSet;
public class ParmNode extends PhiNode {
@@ -21,18 +22,12 @@ public class ParmNode extends PhiNode {
public FunNode fun() { return (FunNode)in(0); }
@Override
- public StringBuilder _print1(StringBuilder sb, BitSet visited) {
+ protected ExprPrinter<Node> _print1(ExprPrinter<Node> p) {
if( "main".equals(fun()._name) && _label.equals("arg") )
- return sb.append("arg");
- sb.append("Parm_").append(_label).append("(");
- for( Node in : _inputs ) {
- if (in == null) sb.append("____");
- else in._print0(sb, visited);
- sb.append(",");
- }
- sb.setLength(sb.length()-1);
- sb.append(")");
- return sb;
+ return p.p("arg");
+ p.p("Parm_").p(_label).open();
+ for( Node in : _inputs ) p.n(in).p(",");
+ return p.unchar(',').close();
}
diff --git a/chapter24/src/main/java/com/seaofnodes/simple/node/PhiNode.java b/chapter24/src/main/java/com/seaofnodes/simple/node/PhiNode.java
index 8d8a276c..6b847b9a 100644
--- a/chapter24/src/main/java/com/seaofnodes/simple/node/PhiNode.java
+++ b/chapter24/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.CodeGen;
import com.seaofnodes.simple.type.*;
import com.seaofnodes.simple.util.Utils;
-import java.util.BitSet;
public class PhiNode extends Node {
@@ -42,18 +43,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/chapter24/src/main/java/com/seaofnodes/simple/node/ProjNode.java b/chapter24/src/main/java/com/seaofnodes/simple/node/ProjNode.java
index fd67f1b1..92c6c2be 100644
--- a/chapter24/src/main/java/com/seaofnodes/simple/node/ProjNode.java
+++ b/chapter24/src/main/java/com/seaofnodes/simple/node/ProjNode.java
@@ -1,10 +1,11 @@
package com.seaofnodes.simple.node;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeMem;
import com.seaofnodes.simple.type.TypeTuple;
-import java.util.BitSet;
public class ProjNode extends Node {
@@ -24,11 +25,11 @@ public class ProjNode extends Node {
@Override public String label() { return _label; }
@Override
- public StringBuilder _print1(StringBuilder sb, BitSet visited) {
- if( _label != null ) return sb.append(_label);
+ protected ExprPrinter<Node> _print1(ExprPrinter<Node> p) {
+ if( _label != null ) return p.p(_label);
if( in(0) instanceof CallEndNode cend && cend.call()!=null )
- return cend.call()._print0(sb,visited);
- return sb.append("LONELY PROJ");
+ return p.n(cend.call());
+ return p.p("LONELY PROJ");
}
@Override public CFGNode cfg0() {
diff --git a/chapter24/src/main/java/com/seaofnodes/simple/node/ReadOnlyNode.java b/chapter24/src/main/java/com/seaofnodes/simple/node/ReadOnlyNode.java
index d8fe6286..94c1b6f6 100644
--- a/chapter24/src/main/java/com/seaofnodes/simple/node/ReadOnlyNode.java
+++ b/chapter24/src/main/java/com/seaofnodes/simple/node/ReadOnlyNode.java
@@ -1,8 +1,8 @@
package com.seaofnodes.simple.node;
+
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeMemPtr;
-import java.util.BitSet;
/**
* Cast a pointer to read-only
@@ -12,10 +12,7 @@ public class ReadOnlyNode extends Node {
public ReadOnlyNode( ReadOnlyNode n ) { super(n); }
@Override public String label() { return "ReadOnly"; }
- @Override
- public StringBuilder _print1(StringBuilder sb, BitSet visited) {
- return in(1)._print0(sb.append("(const)"),visited);
- }
+ @Override protected String format() { return "(const)%1"; }
@Override public Type compute() {
Type t = in(1)._type;
return t instanceof TypeMemPtr tmp ? tmp.makeRO() : t;
diff --git a/chapter24/src/main/java/com/seaofnodes/simple/node/RegionNode.java b/chapter24/src/main/java/com/seaofnodes/simple/node/RegionNode.java
index 1ffbcd60..59030dee 100644
--- a/chapter24/src/main/java/com/seaofnodes/simple/node/RegionNode.java
+++ b/chapter24/src/main/java/com/seaofnodes/simple/node/RegionNode.java
@@ -1,5 +1,7 @@
package com.seaofnodes.simple.node;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.*;
import com.seaofnodes.simple.Parser;
import com.seaofnodes.simple.codegen.CodeGen;
@@ -17,9 +19,8 @@ public class RegionNode extends CFGNode {
@Override
public String label() { return "Region"; }
- @Override
- public StringBuilder _print1(StringBuilder sb, BitSet visited) {
- return sb.append(label());
+ @Override protected ExprPrinter<Node> _print1(ExprPrinter<Node> p) {
+ return p.p(label());
}
@Override public boolean blockHead() { return true; }
diff --git a/chapter24/src/main/java/com/seaofnodes/simple/node/ReturnNode.java b/chapter24/src/main/java/com/seaofnodes/simple/node/ReturnNode.java
index ce6d15bb..266657be 100644
--- a/chapter24/src/main/java/com/seaofnodes/simple/node/ReturnNode.java
+++ b/chapter24/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;
/** Keeps all preceding memory effects and the return value alive: {ctrl, $mem, value, rpc}. */
public class ReturnNode extends CFGNode {
@@ -30,11 +31,11 @@ public class ReturnNode extends CFGNode {
public String label() { return "Return"; }
@Override
- public StringBuilder _print1(StringBuilder sb, BitSet visited) {
- sb.append("return ");
- if( expr()==null ) sb.append("----");
- else expr()._print0(sb, visited);
- return sb.append(";");
+ protected ExprPrinter<Node> _print1(ExprPrinter<Node> p) {
+ p.p("return ");
+ if( expr()==null ) p.p("----");
+ else p.n(expr());
+ return p.p(";");
}
// No one unique control follows; can be many call end sites
diff --git a/chapter24/src/main/java/com/seaofnodes/simple/node/RoundF32Node.java b/chapter24/src/main/java/com/seaofnodes/simple/node/RoundF32Node.java
index 2ad034d6..78e7698c 100644
--- a/chapter24/src/main/java/com/seaofnodes/simple/node/RoundF32Node.java
+++ b/chapter24/src/main/java/com/seaofnodes/simple/node/RoundF32Node.java
@@ -1,19 +1,16 @@
package com.seaofnodes.simple.node;
+
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeFloat;
-import java.util.BitSet;
public class RoundF32Node extends Node {
public RoundF32Node(Node lhs) { super(null, lhs); }
@Override public String label() { return "RoundF32"; }
- @Override
- public StringBuilder _print1(StringBuilder sb, BitSet visited) {
- return in(1)._print0(sb.append("((f32)"), visited).append(")");
- }
+ @Override protected String format() { return "((f32)%1)"; }
@Override
public Type compute() {
diff --git a/chapter24/src/main/java/com/seaofnodes/simple/node/ScopeNode.java b/chapter24/src/main/java/com/seaofnodes/simple/node/ScopeNode.java
index cddb9f24..cd5ab6ff 100644
--- a/chapter24/src/main/java/com/seaofnodes/simple/node/ScopeNode.java
+++ b/chapter24/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;
@@ -63,28 +65,26 @@ public class ScopeNode extends Node {
@Override public String label() { return "Scope"; }
@Override
- public StringBuilder _print1(StringBuilder sb, BitSet visited) {
- sb.append("Scope[ ");
+ protected ExprPrinter<Node> _print1(ExprPrinter<Node> p) {
+ p.p("Scope[ ");
int j=1;
for( int i=0; i<nIns(); i++ ) {
- if( j < depth() && i == _kinds.at(j)._lexSize ) { sb.append("| "); j++; }
+ if( j < depth() && i == _kinds.at(j)._lexSize ) { p.p("| "); j++; }
Var v = _vars.at(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/chapter24/src/main/java/com/seaofnodes/simple/node/SplitNode.java b/chapter24/src/main/java/com/seaofnodes/simple/node/SplitNode.java
index d061cdbd..211489fb 100644
--- a/chapter24/src/main/java/com/seaofnodes/simple/node/SplitNode.java
+++ b/chapter24/src/main/java/com/seaofnodes/simple/node/SplitNode.java
@@ -1,20 +1,21 @@
package com.seaofnodes.simple.node;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.codegen.CodeGen;
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.util.SB;
-import java.util.BitSet;
public abstract class SplitNode extends MachConcreteNode {
public final String _kind; // Kind of split
public final byte _round;
public SplitNode(String kind, byte round, Node[] nodes) { super(nodes); _kind = kind; _round = round; }
@Override public String op() { return "mov"; }
- @Override public StringBuilder _print1(StringBuilder sb, BitSet visited) {
- sb.append("mov(");
- if( in(1) == null ) sb.append("---");
- else in(1)._print0(sb,visited);
- return sb.append(")");
+ @Override protected ExprPrinter<Node> _print1(ExprPrinter<Node> p) {
+ p.p("mov(");
+ if( in(1) == null ) p.p("---");
+ else p.n(in(1));
+ return p.close();
}
@Override public Type compute() { return in(0)._type; }
@Override public Node idealize() { return null; }
diff --git a/chapter24/src/main/java/com/seaofnodes/simple/node/StartNode.java b/chapter24/src/main/java/com/seaofnodes/simple/node/StartNode.java
index 186adfb7..e13d35c0 100644
--- a/chapter24/src/main/java/com/seaofnodes/simple/node/StartNode.java
+++ b/chapter24/src/main/java/com/seaofnodes/simple/node/StartNode.java
@@ -1,9 +1,10 @@
package com.seaofnodes.simple.node;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.codegen.CodeGen;
import com.seaofnodes.simple.Parser;
import com.seaofnodes.simple.type.*;
-import java.util.BitSet;
import java.util.HashSet;
import static com.seaofnodes.simple.util.Utils.TODO;
@@ -17,9 +18,8 @@ public class StartNode extends LoopNode implements MultiNode {
@Override public String label() { return "Start"; }
- @Override
- public StringBuilder _print1(StringBuilder sb, BitSet visited) {
- return sb.append(label());
+ @Override protected ExprPrinter<Node> _print1(ExprPrinter<Node> p) {
+ return p.p(label());
}
@Override public CFGNode cfg0() { return null; }
diff --git a/chapter24/src/main/java/com/seaofnodes/simple/node/StopNode.java b/chapter24/src/main/java/com/seaofnodes/simple/node/StopNode.java
index 98a8d4c3..9f7a925b 100644
--- a/chapter24/src/main/java/com/seaofnodes/simple/node/StopNode.java
+++ b/chapter24/src/main/java/com/seaofnodes/simple/node/StopNode.java
@@ -1,8 +1,9 @@
package com.seaofnodes.simple.node;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.util.Utils;
-import java.util.BitSet;
public class StopNode extends CFGNode {
@@ -21,18 +22,18 @@ public class StopNode extends CFGNode {
}
@Override
- public StringBuilder _print1(StringBuilder sb, BitSet visited) {
+ protected ExprPrinter<Node> _print1(ExprPrinter<Node> p) {
// For the sake of many old tests, and single value prints as "return val"
ReturnNode ret1 = ret();
- if( ret1!=null ) return ret1._print0(sb,visited);
- sb.append("Stop[ ");
+ if( ret1!=null ) return p.n(ret1);
+ p.p("Stop[ ");
for( Node ret : _inputs )
if( ret!=null ) {
String name = ((ReturnNode)ret).fun()._name;
if( name== null || !name.startsWith("sys.") )
- ret._print0(sb, visited).append(" ");
+ p.n(ret).p(" ");
}
- return sb.append("]");
+ return p.p("]");
}
@Override public boolean blockHead() { return true; }
diff --git a/chapter24/src/main/java/com/seaofnodes/simple/node/StoreNode.java b/chapter24/src/main/java/com/seaofnodes/simple/node/StoreNode.java
index 7a75688c..99a6c6a0 100644
--- a/chapter24/src/main/java/com/seaofnodes/simple/node/StoreNode.java
+++ b/chapter24/src/main/java/com/seaofnodes/simple/node/StoreNode.java
@@ -1,9 +1,10 @@
package com.seaofnodes.simple.node;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.codegen.*;
import com.seaofnodes.simple.*;
import com.seaofnodes.simple.type.*;
-import java.util.BitSet;
/**
* Store represents setting a value to a memory based object, in chapter 10
@@ -36,8 +37,8 @@ public class StoreNode extends MemOpNode {
public Node val() { return in(4); }
@Override
- public StringBuilder _print1(StringBuilder sb, BitSet visited) {
- return sb.append(".").append(_name).append("=").append( val()).append(";");
+ protected ExprPrinter<Node> _print1(ExprPrinter<Node> p) {
+ return p.p(".").p(_name).p("=").p( val()).p(";");
}
@Override
diff --git a/chapter24/src/main/java/com/seaofnodes/simple/node/StructNode.java b/chapter24/src/main/java/com/seaofnodes/simple/node/StructNode.java
index b5b59b81..78b20e9f 100644
--- a/chapter24/src/main/java/com/seaofnodes/simple/node/StructNode.java
+++ b/chapter24/src/main/java/com/seaofnodes/simple/node/StructNode.java
@@ -1,8 +1,9 @@
package com.seaofnodes.simple.node;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.type.*;
import com.seaofnodes.simple.util.SB;
-import java.util.BitSet;
/**
* Build a compound object
@@ -15,16 +16,15 @@ public class StructNode extends Node {
@Override public String label() { return _ts==null ? "STRUCT?" : _ts.str(); }
@Override
- public StringBuilder _print1(StringBuilder sb, BitSet visited) {
- if( _ts==null ) return sb.append("STRUCT?");
- sb.append(_ts._name).append(" {");
+ protected ExprPrinter<Node> _print1(ExprPrinter<Node> p) {
+ if( _ts==null ) return p.p("STRUCT?");
+ p.p(_ts._name).p(" {");
for( int i=0; i<nIns(); i++ ) {
- sb.append(_ts._fields[i]._fname).append(":");
- sb.append(in(i)==null ? Type.BOTTOM : in(i)._type);
- sb.append("; ");
+ p.p(_ts._fields[i]._fname).p(":");
+ p.p(in(i)==null ? Type.BOTTOM : in(i)._type);
+ p.p("; ");
}
- sb.setLength(sb.length()-2);
- return sb.append("}");
+ return p.unchar("; ").p("}");
}
@Override
diff --git a/chapter24/src/main/java/com/seaofnodes/simple/node/ToFloatNode.java b/chapter24/src/main/java/com/seaofnodes/simple/node/ToFloatNode.java
index 5734bcbc..840a95ec 100644
--- a/chapter24/src/main/java/com/seaofnodes/simple/node/ToFloatNode.java
+++ b/chapter24/src/main/java/com/seaofnodes/simple/node/ToFloatNode.java
@@ -1,20 +1,17 @@
package com.seaofnodes.simple.node;
+
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeFloat;
import com.seaofnodes.simple.type.TypeInteger;
-import java.util.BitSet;
public class ToFloatNode extends Node {
public ToFloatNode(Node lhs) { super(null, lhs); }
@Override public String label() { return "ToFloat"; }
- @Override
- public StringBuilder _print1(StringBuilder sb, BitSet visited) {
- return in(1)._print0(sb.append("(flt)"), visited);
- }
+ @Override protected String format() { return "(flt)%1"; }
@Override
public Type compute() {
diff --git a/chapter24/src/main/java/com/seaofnodes/simple/node/XCtrlNode.java b/chapter24/src/main/java/com/seaofnodes/simple/node/XCtrlNode.java
index 8c620a04..477b9af8 100644
--- a/chapter24/src/main/java/com/seaofnodes/simple/node/XCtrlNode.java
+++ b/chapter24/src/main/java/com/seaofnodes/simple/node/XCtrlNode.java
@@ -1,14 +1,15 @@
package com.seaofnodes.simple.node;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.codegen.CodeGen;
import com.seaofnodes.simple.Parser;
import com.seaofnodes.simple.type.Type;
-import java.util.BitSet;
public class XCtrlNode extends CFGNode {
public XCtrlNode() { super(new Node[]{CodeGen.CODE._start}); }
@Override public String label() { return "Xctrl"; }
- @Override public StringBuilder _print1(StringBuilder sb, BitSet visited) { return sb.append("Xctrl"); }
+ @Override protected ExprPrinter<Node> _print1(ExprPrinter<Node> p) { return p.p("Xctrl"); }
@Override public boolean isConst() { return true; }
@Override public Type compute() { return Type.XCONTROL; }
@Override public Node idealize() { return null; }
diff --git a/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/arm/MemOpARM.java b/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/arm/MemOpARM.java
index 01066f47..9257f25b 100644
--- a/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/arm/MemOpARM.java
+++ b/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/arm/MemOpARM.java
@@ -1,12 +1,13 @@
package com.seaofnodes.simple.node.cpus.arm;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.codegen.*;
import com.seaofnodes.simple.node.*;
import com.seaofnodes.simple.type.*;
import com.seaofnodes.simple.util.SB;
import com.seaofnodes.simple.util.Utils;
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
@@ -31,7 +32,7 @@ public abstract class MemOpARM extends MemOpNode implements MachNode {
@Override public String label() { return op();}
Node val() { return in(4); } // Only for stores
- @Override public StringBuilder _printMach(StringBuilder sb, BitSet visited) { return sb.append(".").append(_name); }
+ @Override protected ExprPrinter<Node> _printMach(ExprPrinter<Node> p) { return p.p(".").p(_name); }
@Override public Type compute() { throw Utils.TODO(); }
@Override public Node idealize() { throw Utils.TODO(); }
diff --git a/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/arm/UJmpARM.java b/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/arm/UJmpARM.java
index 2dd5fd6b..ce4f523c 100644
--- a/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/arm/UJmpARM.java
+++ b/chapter24/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/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/riscv/BranchRISC.java b/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/riscv/BranchRISC.java
index b7284265..b8664679 100644
--- a/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/riscv/BranchRISC.java
+++ b/chapter24/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/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/riscv/ImmRISC.java b/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/riscv/ImmRISC.java
index f2beb25c..b4c87872 100644
--- a/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/riscv/ImmRISC.java
+++ b/chapter24/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/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/riscv/MemOpRISC.java b/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/riscv/MemOpRISC.java
index b9e6e5ba..adf21848 100644
--- a/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/riscv/MemOpRISC.java
+++ b/chapter24/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
@@ -23,7 +24,7 @@ public abstract class MemOpRISC extends MemOpNode implements MachNode {
@Override public String label() { return op(); }
Node val() { return in(4); } // Only for stores
- @Override public StringBuilder _printMach(StringBuilder sb, BitSet visited) { return sb.append(".").append(_name); }
+ @Override protected ExprPrinter<Node> _printMach(ExprPrinter<Node> p) { return p.p(".").p(_name); }
@Override public Type compute() { throw Utils.TODO(); }
@Override public Node idealize() { throw Utils.TODO(); }
diff --git a/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/riscv/UJmpRISC.java b/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/riscv/UJmpRISC.java
index c4d5d8af..160895df 100644
--- a/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/riscv/UJmpRISC.java
+++ b/chapter24/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/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/MemOpX86.java b/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/MemOpX86.java
index 20578467..309e62d9 100644
--- a/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/MemOpX86.java
+++ b/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/MemOpX86.java
@@ -1,12 +1,13 @@
package com.seaofnodes.simple.node.cpus.x86_64_v2;
+import com.seaofnodes.print.ExprPrinter;
+
import com.seaofnodes.simple.codegen.*;
import com.seaofnodes.simple.node.*;
import com.seaofnodes.simple.type.*;
import com.seaofnodes.simple.util.SB;
import com.seaofnodes.simple.util.Utils;
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/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/StoreX86.java b/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/StoreX86.java
index 4403b02b..b7b6c5d3 100644
--- a/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/StoreX86.java
+++ b/chapter24/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/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/UJmpX86.java b/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/UJmpX86.java
index 92d2a87d..6f538d27 100644
--- a/chapter24/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/UJmpX86.java
+++ b/chapter24/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/chapter24/src/main/java/com/seaofnodes/simple/print/ASMPrinter.java b/chapter24/src/main/java/com/seaofnodes/simple/print/ASMPrinter.java
index 9ee26039..48296ce7 100644
--- a/chapter24/src/main/java/com/seaofnodes/simple/print/ASMPrinter.java
+++ b/chapter24/src/main/java/com/seaofnodes/simple/print/ASMPrinter.java
@@ -1,307 +1,85 @@
package com.seaofnodes.simple.print;
+import com.seaofnodes.print.AssemblyAdapter;
+import com.seaofnodes.print.ASMPrinter.Data;
+import com.seaofnodes.print.ASMPrinter.Pool;
import com.seaofnodes.simple.codegen.CodeGen;
-import com.seaofnodes.simple.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.Ary;
-import com.seaofnodes.simple.util.SB;
-import com.seaofnodes.simple.util.Utils;
-import java.util.Collections;
-import java.util.IdentityHashMap;
-import java.util.Set;
-
-public abstract class ASMPrinter {
+import java.util.ArrayList;
+import com.seaofnodes.simple.codegen.Encoding;
+/** Machine-specific facts; traversal, columns and byte display live in print/. */
+public final class ASMPrinter extends AssemblyAdapter<Node> {
+ private final CodeGen _code;
+ private final Encoding _enc;
+ private ASMPrinter(CodeGen code) {
+ super(new IRPrinter());
+ _code=code;
+ _enc=code._encoding;
+ }
public static SB print(SB sb, CodeGen code) {
- if( code._cfg==null )
- return sb.p("Need _cfg set, run after GCM");
-
- // instruction address
- int iadr = 0;
- for( int i=0; i<code._cfg._len; i++ )
- if( code._cfg.at(i) instanceof FunNode fun )
- iadr = print(iadr,sb,code,fun,i);
-
- // constant pool
- iadr = (iadr+15)&-16; // pad to 16
- Encoding enc = code._encoding;
- if( enc!=null && !enc._bigCons.isEmpty() && iadr < enc._bits.size() ) {
- // radix sort the big constants by alignment
- Ary<Relo>[] raligns = new Ary[5];
- for( Relo relo : enc._bigCons.values() ) {
- int align = relo._align;
- Ary<Relo> relos = raligns[align]==null ? (raligns[align]=new Ary<>( Relo.class)) : raligns[align];
- relos.add(relo);
- }
-
- Set<Type> targets = Collections.newSetFromMap(new IdentityHashMap<>());
- sb.p("--- Constant Pool ------").nl();
-
- // By alignment
- for( int align = 4; align >= 0; align-- ) {
- Ary<Relo> relos = raligns[align];
- if( relos == null ) continue;
- for( Relo relo : relos ) {
- if( targets.contains(relo._t) ) continue;
- targets.add(relo._t);
- sb.hex2(iadr).p(" ");
- switch( relo._t ) {
- case TypeTuple tt -> {
- for( Type tx : tt._types ) {
- pN(enc,sb,iadr,align).p(" ");
- iadr += (1<<align);
- }
- }
-
- case TypeStruct ts -> {
- int sz = relo._structSize;
- int log = 1<<align;
- sz = (sz + (log -1)) & -log; // Round up final padding
- for( int i=0; i<sz; i++ )
- sb.hex1(enc.read1(iadr++));
- }
-
- // Simple primitive (e.g. larger int, float)
- default -> {
- pN(enc,sb,iadr,align).fix(9-(1<<align),"");
- iadr += (1<<align);
- }
- }
- relo._t.print(sb).nl();
- }
- }
- }
-
- return sb;
+ return sb.p(new com.seaofnodes.print.ASMPrinter<>(new ASMPrinter(code)).print());
}
-
- private static SB pN( Encoding enc, SB sb, int iadr, int log ) {
- switch( log ) {
- case 0: sb.hex1(enc.read1(iadr)); break;
- case 1: sb.hex2(enc.read2(iadr)); break;
- case 2: sb.hex4(enc.read4(iadr)); break;
- case 3: sb.hex8(enc.read8(iadr)); break;
- }
- return sb;
+ @Override public ArrayList<Node> blocks() {
+ var blocks=new ArrayList<Node>();
+ var cfg=_code._cfg;
+ if( cfg!=null ) for( Node n : cfg ) blocks.add(n);
+ return blocks;
}
-
-
- private static int print(int iadr, SB sb, CodeGen code, FunNode fun, int cfgidx) {
- FunNode old=null;
- if( code._encoding!=null ) {
- old = code._encoding._fun;
- code._encoding._fun = fun; // Useful printing after RA
+ @Override public String op(Node n) { return n instanceof MachNode m ? m.op() : n.label(); }
+ @Override public String register(Node n) { return _code.reg(n); }
+ @Override public String comment(Node n) { return n.comment(); }
+ @Override public String phiName(Node n) { return ((PhiNode)n)._label; }
+ @Override public String operands(Node n) {
+ SB sb=new SB();
+ if( n instanceof MachNode m ) m.asm(_code,sb);
+ else if( !(n._type instanceof TypeMem) ) {
+ sb.p(n._nid).p(": ");
+ for( Node def : n._inputs ) sb.p(def==null ? "___" : Integer.toString(def._nid)).p(' ');
}
- // Function header
- sb.nl().p("---");
- if( fun._name != null ) sb.p(fun._name).p(" ");
- fun.sig().print(sb);
- sb.p("---------------------------").nl();
- if( code._encoding!=null && code._encoding._padFunHeads )
- iadr = (iadr + 15)&-16; // All function entries padded to 16 align
-
- if( fun._frameAdjust != 0 )
- iadr = doInst(iadr,sb,code,fun,cfgidx,fun,true,true);
- while( !(code._cfg.at(cfgidx) instanceof ReturnNode) )
- iadr = doBlock(iadr,sb,code,fun,cfgidx++);
-
- // Function separator
- sb.p("---");
- fun.sig().print(sb);
- sb.p("---------------------------").nl();
- if( code._encoding != null )
- code._encoding._fun = old;
- return iadr;
+ return sb.toString();
}
-
- static private final int opWidth = 5;
- static private final int argWidth = 30;
- static int doBlock(int iadr, SB sb, CodeGen code, FunNode fun, int cfgidx) {
- final int encWidth = code._mach==null ? 2 : code._mach.defaultOpSize()*2;
- CFGNode bb = code._cfg.at(cfgidx);
- if( bb != fun && !(bb instanceof IfNode) && !(bb instanceof CallEndNode) && !(bb instanceof CallNode) && !(bb instanceof CProjNode && bb.in(0) instanceof CallEndNode ))
- sb.p(label(bb)).p(":").nl();
- if( bb instanceof CallNode ) return iadr;
- final boolean postAlloc = code._phase.ordinal() > CodeGen.Phase.RegAlloc.ordinal();
- final boolean postEncode= code._phase.ordinal() >=CodeGen.Phase.Encoding.ordinal();
-
- boolean once=false;
- for( Node n : bb.outs() ) {
- if( !(n instanceof PhiNode phi) ) continue;
- if( phi._type instanceof TypeMem || phi._type instanceof TypeRPC ) continue; // Nothing for the hidden ones
- // Post-RegAlloc phi prints all on one line
- if( postAlloc ) {
- if( !once ) { once=true; sb.fix(4," ").p(" ").fix(encWidth,"").p(" "); }
- sb.p(phi._label).p(':').p(code.reg(phi,fun)).p(',');
- } else {
- // Pre-RegAlloc phi prints one line per
- sb.fix(4," ").p(" ").fix(encWidth,"").p(" ").fix(opWidth,phi._label).p(" ").p(code.reg(phi,fun));
- if( phi.getClass() == PhiNode.class ) {
- sb.p(" = phi( ");
- for( int i=1; i<phi.nIns(); i++ )
- sb.p("N").p(phi.in(i)._nid).p(",");
- sb.unchar().p(" )");
- }
- sb.nl();
- }
- }
- if( once ) sb.unchar().nl();
-
- // All the non-phis
- for( int i=0; i<bb.nOuts(); i++ )
- if( !(bb.out(i) instanceof PhiNode) )
- iadr = doInst(iadr, sb,code, fun, cfgidx, bb.out(i),postAlloc, postEncode );
-
- return iadr;
+ @Override public boolean labelBlock(Node n) {
+ return !(n instanceof FunNode) && !(n instanceof IfNode) && !(n instanceof CallNode) &&
+ !(n instanceof CallEndNode) && !(n instanceof CProjNode && ir.input0(n) instanceof CallEndNode);
}
-
- static int doInst( int iadr, SB sb, CodeGen code, FunNode fun, int cfgidx, Node n, boolean postAlloc, boolean postEncode ) {
- if( n==null || n instanceof CProjNode ) return iadr;
- if( postAlloc && n instanceof CalleeSaveNode ) return iadr;
- if( postEncode && n instanceof ProjNode ) return iadr;
- if( n instanceof MemMergeNode ) return iadr;
- if( n.getClass() == ConstantNode.class ) return iadr; // Default placeholders
- final int dopz = code._mach==null ? 2 : code._mach.defaultOpSize();
- final int encWidth = dopz*2;
-
- // All blocks ending in a Region will need to either fall into or jump
- // to this block. Until the post-reg-alloc block layout cleanup, we
- // need to assume a jump. There's no real hardware op here, yet.
- if( n instanceof RegionNode cfg && !(n instanceof FunNode) ) {
- if( postEncode ) return iadr; // All jumps inserted already
- while( cfgidx < code._cfg._len-1 ) {
- CFGNode next = code._cfg.at(++cfgidx);
- if( next == n ) return iadr; // Fall-through, no branch
- if( next.nOuts()>1 )
- break; // Has code in the block, need to jump around
- // No code in the block, can fall through it
- }
- sb.hex2(iadr++).p(" ").fix(encWidth,"??").p(" ").fix(opWidth,"JMP").p(" ").fix(argWidth,label(cfg)).nl();
- return iadr;
- }
-
- // ProjNodes following a multi (e.g. Call or New results),
- // get indent slightly and just print their index & node#
- if( n instanceof ProjNode proj ) {
- if( proj._type instanceof TypeMem ) return iadr; // Nothing for the hidden ones
- sb.fix(4," ").p(" ").fix(encWidth,"").p(" ").fix(opWidth,proj._label==null ? "---" : proj._label).p(" ").p(code.reg(n,fun)).nl();
- return iadr;
- }
-
- // ADDR ENCODING Op--- dst = src op src // Comment
- // 1234 abcdefgh ld4 RAX = [Rbase + off] // Comment
- sb.hex2(iadr).p(" ");
-
- // Encoding
- int fatEncoding = 0;
- if( code._encoding != null && code._encoding._opLen!=null ) {
- int size = code._encoding._opLen[n._nid];
- if( code._asmLittle )
- for( int i=0; i<Math.min(size,dopz); i++ )
- sb.hex1(code._encoding._bits.buf()[iadr++]);
- else {
- iadr += Math.min(size,dopz);
- for( int i=0; i<Math.min(size,dopz); i++ )
- sb.hex1(code._encoding._bits.buf()[iadr-i-1]);
- }
- for( int i=size*2; i<encWidth; i++ )
- sb.p(" ");
- fatEncoding = size - (encWidth>>1); // Not-printed parts of encoding
- } else
- sb.fix(encWidth,"");
- sb.p(" ");
-
- // Op; generally "ld4" or "call"
- sb.fix(opWidth, n instanceof MachNode mach ? mach.op() : n.label()).p(" ");
-
- // General asm args
- String isMultiOp = null;
- if( n instanceof MachNode mach ) {
- int old = sb.len();
- mach.asm(code,sb);
- int len = sb.len();
- isMultiOp = isMultiOp(sb,old,len);
- sb.fix(argWidth-(len-old),""); // Pad out
-
- } else if( !(n._type instanceof TypeMem) ) {
- // Room for some inputs
- sb.fix(5, n._nid+":" );
- int off = 0;
- for( int i=0; i<n.nIns(); i++ ) {
- sb.fix(5, n.in(i) == null ? "___" : String.valueOf(n.in(i)._nid));
- off += 5;
- if( off >= argWidth ) break;
- }
- if( off < argWidth ) sb.fix(argWidth-off,"");
- }
- sb.p(" ");
-
- // Comment
- String comment = n.comment();
- if( comment!=null ) sb.p("// ").p(comment);
-
- sb.nl();
-
- // Printing more op bits than fit
- if( isMultiOp != null && code._encoding != null && code._encoding._opLen!=null ) {
- // Multiple ops, template style, no RA, no scheduling. Print out
- // one-line-per-newline, with encoding bits up front.
- int size = code._encoding._opLen[n._nid];
- int off = Math.min(size,dopz);
- while( isMultiOp!=null ) {
- sb.hex2(iadr).p(" ");
- int len = Math.min(size-off,dopz);
- for( int i=0; i<len; i++ )
- sb.hex1(code._encoding._bits.buf()[iadr++]);
- off += len;
- for( int i=len; i<dopz; i++ ) sb.p(" ");
- sb.p(" ");
- int x = isMultiOp.indexOf('\n');
- if( x== -1 ) { // Last line
- sb.p(isMultiOp).nl();
- isMultiOp = null;
- } else {
- sb.p(isMultiOp.substring(0,x+1)); // Includes the newline
- isMultiOp = isMultiOp.substring(x+1);
- }
-
- }
-
- } else if( fatEncoding > 0 ) {
- // Extra bytes past the default encoding width, all put on a line by
- // themselves. X86 special for super long encodings
- sb.hex2(iadr).p(" ");
- for( int i=0; i<fatEncoding; i++ )
- sb.hex1(code._encoding._bits.buf()[iadr++]);
- sb.nl();
- }
-
-
- // MultiNodes are immediately followed by projection(s)
- if( !(n instanceof CFGNode) && n instanceof MultiNode ) {
- for( Node proj : n._outputs ) {
- if( proj instanceof ProjNode ) // it could also be an ante-dep
- doInst(iadr,sb,code,fun, cfgidx, proj,postAlloc,postEncode);
- }
- }
-
- return iadr;
+ @Override public boolean hidden(Node n) {
+ if( n instanceof PhiNode || n instanceof ProjNode )
+ if( n._type instanceof TypeMem || n._type instanceof TypeRPC ) return true;
+ if( postAlloc() && n instanceof CalleeSaveNode ) return true;
+ if( n instanceof MemMergeNode ) return true;
+ return n.getClass()==ConstantNode.class;
}
-
- private static String label( CFGNode bb ) {
- return (bb instanceof LoopNode ? "LOOP" : "L")+bb._nid;
+ @Override public boolean postAlloc() { return _code._phase.ordinal()>CodeGen.Phase.RegAlloc.ordinal(); }
+ @Override public boolean encoded() { return _enc!=null && _code._phase.ordinal()>=CodeGen.Phase.Encoding.ordinal(); }
+ @Override public int defaultSize() { return _code._mach==null ? 2 : _code._mach.defaultOpSize(); }
+ @Override public boolean littleEndian() { return _code._asmLittle; }
+ @Override public boolean prologue(Node n) { return ((FunNode)n)._frameAdjust!=0; }
+ @Override public byte[] bytes() { return encoded() ? _enc._bits.buf() : null; }
+ @Override public int offset(Node n) {
+ return encoded() && _enc._opStart!=null && n._nid<_enc._opStart.length ? _enc._opStart[n._nid] : -1;
}
-
- private static String isMultiOp(SB sb, int old, int len) {
- for( int i=old; i<len; i++ )
- if( sb.at(i)=='\n' ) {
- String s = sb.subString(i+1,len);
- sb.setLen(i);
- return s;
- }
- return null;
+ @Override public int size(Node n) {
+ return encoded() && _enc._opLen!=null && n._nid<_enc._opLen.length ? _enc._opLen[n._nid]&255 : 0;
+ }
+ private static ArrayList<Data> entries(Iterable<Encoding.Relo> relos) {
+ var data=new ArrayList<Data>();
+ for( Encoding.Relo r : relos ) {
+ int align=1<<r._align;
+ int size=r._t instanceof TypeStruct ? (r._structSize+align-1)&-align : align;
+ if( r._t instanceof TypeTuple t ) size=align*t._types.length;
+ data.add(new Data(r._t,r._t.str(),r._align,size));
+ }
+ return data;
+ }
+ @Override public ArrayList<Pool> pools(int codeEnd) {
+ var pools=new ArrayList<Pool>();
+ if( !encoded() ) return pools;
+ int base=(codeEnd+15)&-16;
+ if( !_enc._bigCons.isEmpty() && base<_enc._bits.size() )
+ pools.add(new Pool("Constant Pool",_enc._bits.buf(),base,base,entries(_enc._bigCons.values())));
+ return pools;
}
-
}
diff --git a/chapter24/src/main/java/com/seaofnodes/simple/print/IRPrinter.java b/chapter24/src/main/java/com/seaofnodes/simple/print/IRPrinter.java
index 046ffb4a..c912ab77 100644
--- a/chapter24/src/main/java/com/seaofnodes/simple/print/IRPrinter.java
+++ b/chapter24/src/main/java/com/seaofnodes/simple/print/IRPrinter.java
@@ -1,352 +1,61 @@
package com.seaofnodes.simple.print;
-import com.seaofnodes.simple.codegen.CodeGen;
+import com.seaofnodes.print.IRAdapter;
import com.seaofnodes.simple.node.*;
-import com.seaofnodes.simple.type.TypeFunPtr;
-import com.seaofnodes.simple.util.Ary;
-import com.seaofnodes.simple.util.SB;
-import com.seaofnodes.simple.util.Utils;
import java.util.ArrayList;
-import java.util.BitSet;
-import java.util.HashMap;
-
-public abstract class IRPrinter {
-
- // Print a node on 1 line, columnar aligned, as:
- // NNID NNAME DDEF DDEF [[ UUSE UUSE ]] TYPE
- // 1234 sssss 1234 1234 1234 1234 1234 1234 tttttt
- public static SB printLine( Node n, SB sb ) {
- if( n==null ) return sb;
- sb.p("%4d %-7.7s ".formatted(n._nid,n.label()));
- if( n.isDead() )
- return sb.p("DEAD\n");
- for( Node def : n._inputs )
- sb.p(def==null ? "____" : "%4d".formatted(def._nid))
- // Lazy Phi indicator
- .p(n instanceof MemMergeNode && def instanceof MemMergeNode ? "^" : " ");
- for( int i = n._inputs.size(); i<4; i++ )
- sb.p(" ");
- sb.p(" [[ ");
- for( Node use : n._outputs )
- sb.p(use==null ? "____ " : "%4d ".formatted(use._nid));
- int lim = 6 - Math.max(n._inputs.size(),4);
- for( int i = n._outputs.size(); i<lim; i++ )
- sb.p(" ");
- sb.p(" ]] ");
- if( n._type!= null ) sb.p(n._type.str());
- return sb.p("\n");
- }
-
-
- public static String prettyPrint(Node node, int depth) {
- return CodeGen.CODE._phase.ordinal() > CodeGen.Phase.Schedule.ordinal()
- ? _prettyPrintScheduled( node, depth )
- : _prettyPrint( node, depth );
- }
-
- // Another bulk pretty-printer. Makes more effort at basic-block grouping.
- private static String _prettyPrint( Node node, int depth ) {
- // First, a Breadth First Search at a fixed depth.
- BFS bfs = new BFS(node,depth);
- // Convert just that set to a post-order
- ArrayList<Node> rpos = new ArrayList<>();
- BitSet visit = new BitSet();
- for( int i=bfs._lim; i< bfs._bfs.size(); i++ )
- postOrd( bfs._bfs.get(i), null, rpos, visit, bfs._bs);
- // Reverse the post-order walk
- SB sb = new SB();
- boolean gap=false;
- for( int i=rpos.size()-1; i>=0; i-- ) {
- Node n = rpos.get(i);
- if( n instanceof CFGNode || n instanceof MultiNode ) {
- if( !gap ) sb.p("\n"); // Blank before multihead
- if( n instanceof FunNode fun )
- fun.sig().print(sb.p("--- ").p(fun._name==null ? "" : fun._name).p(" ")).p("----------------------\n");
- printLine( n, sb ); // Print head
- while( --i >= 0 ) {
- Node t = rpos.get(i);
- if( !(t.in(0) instanceof MultiNode) ) { i++; break; }
- printLine( t, sb );
- }
- if( n instanceof ReturnNode ret ) {
- FunNode fun = ret.fun();
- sb.p("--- ");
- if( fun != null )
- fun.sig().print(sb.p(fun._name==null ? "" : fun._name).p(" "));
- sb.p("----------------------\n");
- }
- if( !(n instanceof CallNode) ) {
- sb.p("\n"); // Blank after multitail
- gap = true;
- }
- } else {
- printLine( n, sb );
- gap = false;
- }
- }
- return sb.toString();
- }
-
- private static void postOrd(Node n, Node prior, ArrayList<Node> rpos, BitSet visit, BitSet bfs) {
- if( !bfs.get(n._nid) )
- return; // Not in the BFS visit
- if( n instanceof FunNode && !(prior instanceof StartNode) )
- return; // Only visit Fun from Start
- if( visit.get(n._nid) ) return; // Already post-order walked
- visit.set(n._nid);
- // First walk the CFG, then everything
- if( n instanceof CFGNode ) {
- for( Node use : n._outputs )
- // Follow CFG, not across call/function borders, and not around backedges
- if( use instanceof CFGNode && !(n instanceof CallNode && use instanceof FunNode) &&
- use.nOuts() >= 1 && !(use._outputs.get(0) instanceof LoopNode) )
- postOrd(use, n, rpos,visit,bfs);
- for( Node use : n._outputs )
- // Follow CFG, not across call/function borders
- if( use instanceof CFGNode && !(n instanceof CallNode && use instanceof FunNode) )
- postOrd(use,n,rpos,visit,bfs);
- }
- // Follow all outputs
- for( Node use : n._outputs )
- if( use != null &&
- !(n instanceof CallNode && use instanceof FunNode) &&
- (n instanceof FunNode || !(use instanceof ParmNode)) )
- postOrd(use, n, rpos,visit,bfs);
- // Post-order
- rpos.add(n);
- }
-
- // Breadth-first search, broken out in a class to keep in more independent.
- // Maintains a root-set of Nodes at the limit (or past by 1 if MultiHead).
- public static class BFS {
- // A breadth first search, plus MultiHeads for any MultiTails
- public final ArrayList<Node> _bfs;
- public final BitSet _bs; // Visited members by node id
- public final int _depth; // Depth limit
- public final int _lim; // From here to _bfs._len can be roots for a reverse search
- public BFS( Node base, int d ) {
- _depth = d;
- _bfs = new ArrayList<>();
- _bs = new BitSet();
-
- add(base); // Prime the pump
- int idx=0, lim=1; // Limit is where depth counter changes
- while( idx < _bfs.size() ) { // Ran out of nodes below depth
- Node n = _bfs.get(idx++);
- for( Node def : n._inputs )
- if( def!=null && !_bs.get(def._nid) )
- add(def);
- if( idx==lim ) { // Depth counter changes at limit
- if( --d < 0 )
- break; // Ran out of depth
- lim = _bfs.size(); // New depth limit
- }
- }
- // Toss things past the limit except multi-heads
- while( idx < _bfs.size() ) {
- Node n = _bfs.get(idx);
- if( n instanceof MultiNode ) idx++;
- else del(idx);
- }
- // Root set is any node with no inputs in the visited set
- lim = _bfs.size();
- for( int i=_bfs.size()-1; i>=0; i-- )
- if( !any_visited(_bfs.get(i)) )
- swap( i,--lim);
- _lim = lim;
- }
- void swap( int x, int y ) {
- if( x==y ) return;
- Node tx = _bfs.get(x);
- Node ty = _bfs.get(y);
- _bfs.set(x,ty);
- _bfs.set(y,tx);
- }
- void add(Node n) {
- _bfs.add(n);
- _bs.set(n._nid);
- }
- void del(int idx) {
- _bs.clear(_bfs.get(idx)._nid);
- Utils.del(_bfs, idx);
- }
- boolean any_visited( Node n ) {
- for( Node def : n._inputs )
- if( def!=null && _bs.get(def._nid) )
- return true;
- return false;
- }
- }
-
- public static String _prettyPrint( CodeGen code ) {
- SB sb = new SB();
- // Print the Start "block"
- printLine(code._start,sb);
- for( Node n : code._start._outputs )
- printLine(n,sb);
- sb.nl();
-
- // Skip start, stop
- for( int i=1; i<code._cfg._len-1; i++ ) {
- CFGNode blk = code._cfg.at(i);
- if( blk.blockHead() && (!(blk instanceof CProjNode) || (blk.cfg0() instanceof IfNode )) ) {
- if( blk instanceof FunNode fun )
- sb.p("--- ").p(fun.label()).p(" ---------------------------").nl();
- // Print block header
- sb.p("%-13.13s".formatted(label(blk)+":"));
- sb.p( " ".repeat(4) ).p(" [[ ");
- if( blk instanceof RegionNode )
- for( int j=1; j<blk.nIns(); j++ )
- label(sb,blk.cfg(j));
- else
- label(sb,blk.cfg(0));
- sb.p(" ]] \n");
- }
- printLine(blk,sb);
- if( blk instanceof ReturnNode ret )
- sb.p("--- ").p(ret.fun().label()).p(" ---------------------------").nl();
-
- // Block contents
- for( Node n : blk._outputs ) {
- if( n instanceof CFGNode cfg ) continue;
- printLine(n,sb);
- if( !(n instanceof CFGNode) && n instanceof MultiNode )
- for( Node use : n._outputs )
- if( use instanceof ProjNode )
- printLine(use,sb);
- }
- }
-
- printLine(code._stop,sb);
- return sb.toString();
- }
-
- // Diagnostic block ordering from raw control edges. Do not call idepth():
- // it fills compiler caches (and can walk lazy dominator accessors).
- private static int _idepth(CFGNode cfg, HashMap<Integer,Integer> depths) {
- if( cfg == null || cfg instanceof StartNode || cfg instanceof FunNode ) return cfg instanceof FunNode ? 1 : 0;
- Integer old = depths.get(cfg._nid);
- if( old != null ) return old;
- depths.put(cfg._nid,0); // Break cycles in partially constructed graphs.
- int d = 0;
- if( cfg instanceof LoopNode ) {
- d = _idepth((CFGNode)cfg.in(1),depths)+1;
- } else if( cfg instanceof RegionNode || cfg instanceof StopNode ) {
- for( Node n : cfg._inputs )
- if( n instanceof CFGNode pred ) d = Math.max(d,_idepth(pred,depths)+1);
- } else if( cfg.in(0) instanceof CFGNode pred ) {
- d = _idepth(pred,depths)+1;
- }
- depths.put(cfg._nid,d);
- return d;
- }
-
- // Bulk pretty printer, knowing scheduling information is available
- private static String _prettyPrintScheduled( Node node, int depth ) {
- // Backwards DFS walk to depth.
- HashMap<Integer,Integer> ds = new HashMap<>();
- Ary<Node> ns = new Ary<>(Node.class);
- _walk(ds,ns,node,depth);
- // Remove data projections, these are force-printed behind their multinode head
- for( int i=0; i<ns.size(); i++ ) {
- if( ns.get(i) instanceof ProjNode proj && !(proj.in(0) instanceof CFGNode) ) {
- ns.del(i--);
- ds.remove(proj._nid);
- }
- }
- // Print by block with least diagnostic depth
- HashMap<Integer,Integer> depths = new HashMap<>();
- SB sb = new SB();
- Ary<Node> bns = new Ary<>(Node.class);
- while( !ds.isEmpty() ) {
- CFGNode blk = null;
- for( Node n : ns ) {
- CFGNode cfg = n instanceof CFGNode cfg0 && cfg0.blockHead() ? cfg0 : n.cfg0();
- if( blk==null || _idepth(cfg,depths) < _idepth(blk,depths) )
- blk = cfg;
- }
- Integer d = ds.remove(blk._nid);
- ns.del(ns.find(blk));
-
- // Print block header
- sb.p("%-13.13s".formatted(label(blk)+":"));
- sb.p( " ".repeat(4) ).p(" [[ ");
- if( blk instanceof StartNode ) ;
- else if( blk instanceof RegionNode || blk instanceof StopNode )
- for( int i=(blk instanceof StopNode ? 3 : 1); i<blk.nIns(); i++ )
- label(sb,blk.cfg(i));
- else
- label(sb,blk.cfg(0));
- sb.p(" ]] \n");
- printLine(blk,sb);
-
- // Collect block contents that are in the depth limit
- bns.clear();
- int xd = Integer.MAX_VALUE;
- for( Node use : blk._outputs ) {
- Integer i = ds.get(use._nid);
- if( i!=null && !(use instanceof CFGNode cfg && cfg.blockHead()) ) {
- if( bns.find(use)==-1 )
- bns.add(use);
- xd = Math.min(xd,i);
- }
- }
- // Print Phis up front, if any
- for( int i=0; i<bns.size(); i++ )
- if( bns.get(i) instanceof PhiNode phi )
- printLine( phi, sb,bns,i--,ds,ns);
-
- // Print block contents in depth order, bumping depth until whole block printed
- for( ; !bns.isEmpty(); xd++ )
- for( int i=0; i<bns.size(); i++ ) {
- Node n = bns.get(i);
- if( ds.get(n._nid)==xd ) {
- printLine( n, sb, bns, i--, ds,ns );
- if( n instanceof MultiNode && !(n instanceof CFGNode) ) {
- for( Node use : n._outputs ) {
- if( use instanceof ProjNode )
- printLine(use,sb,bns,bns.indexOf(use),ds,ns);
- }
- }
- }
- }
- sb.p("\n");
- }
- return sb.toString();
- }
-
- private static void _walk( HashMap<Integer,Integer> ds, Ary<Node> ns, Node node, int d ) {
- Integer nd = ds.get(node._nid);
- if( nd!=null && d <= nd ) return; // Been there, done that
- Integer old = ds.put(node._nid,d) ;
- if( old == null )
- ns.add(node);
- if( d == 0 ) return; // Depth cutoff
- for( Node def : node._inputs )
- if( def != null &&
- !(node instanceof LoopNode loop && loop.back()==def) &&
- // Don't walk into or out of functions
- !(node instanceof CallEndNode && def instanceof ReturnNode) &&
- !(node instanceof FunNode && def instanceof CallNode) &&
- !(node instanceof ParmNode && !(def instanceof FunNode))
- )
- _walk(ds,ns,def,d-1);
- }
+import com.seaofnodes.simple.util.SB;
+import com.seaofnodes.simple.codegen.CodeGen;
- static String label( CFGNode blk ) {
- if( blk instanceof StartNode ) return "START";
- return (blk instanceof LoopNode ? "LOOP" : "L")+blk._nid;
- }
- static void label( SB sb, CFGNode blk ) {
- if( !blk.blockHead() ) blk = blk.cfg(0);
- sb.p( "%-9.9s ".formatted( label( blk ) ) );
+/** This chapter's read-only IR facts and the familiar debugger entry points. */
+public final class IRPrinter extends IRAdapter<Node> {
+ private static final com.seaofnodes.print.IRPrinter<Node> PRINT =
+ new com.seaofnodes.print.IRPrinter<>(new IRPrinter());
+ @Override public boolean global(Node n) { return n.isConst(); }
+ @Override public String type(Node n) { return n._type==null ? "" : n._type.str(); }
+ @Override public String inputMark(Node n, Node def) { return n instanceof MemMergeNode && def instanceof MemMergeNode ? "^" : " "; }
+ @Override public Kind kind(Node n) {
+ if( n instanceof StartNode ) return Kind.START;
+ if( n instanceof StopNode ) return Kind.STOP;
+ if( n instanceof FunNode ) return Kind.FUN;
+ if( n instanceof LoopNode ) return Kind.LOOP;
+ if( n instanceof RegionNode ) return Kind.REGION;
+ if( n instanceof ParmNode ) return Kind.PARM;
+ if( n instanceof PhiNode ) return Kind.PHI;
+ if( n instanceof CallEndNode ) return Kind.CALL_END;
+ if( n instanceof CallNode ) return Kind.CALL;
+ if( n instanceof ReturnNode ) return Kind.RETURN;
+ if( n instanceof ConstantNode ) return Kind.CONSTANT;
+ if( n instanceof CProjNode ) return Kind.CPROJ;
+ if( n instanceof ProjNode ) return n instanceof CFGNode ? Kind.CPROJ : Kind.PROJ;
+ if( n instanceof CFGNode ) return Kind.CTRL;
+ if( n instanceof MultiNode ) return Kind.MULTI;
+ return Kind.DATA;
+ }
+ @Override public int index(Node n) {
+ if( n instanceof ProjNode p ) return p._idx;
+ if( n instanceof CProjNode p ) return p._idx;
+ return n._nid;
+ }
+ @Override public String functionName(Node n) { return ((FunNode)n)._name==null ? "" : ((FunNode)n)._name; }
+ @Override public String signature(Node n) {
+ FunNode fun=(FunNode)n;
+ return (fun._name==null ? "" : fun._name)+" "+fun.sig().str();
+ }
+
+ public static String prettyPrint(Node n, int depth) { return PRINT.prettyPrint(n,depth); }
+ public static SB printLine(Node n, SB sb) { return sb.p(PRINT.line(n)); }
+
+ public static String prettyPrint(CodeGen code) {
+ var units=new ArrayList<com.seaofnodes.print.IRPrinter.Unit<Node>>();
+ var funs=new ArrayList<Node>();
+ for( Node n : code._start._outputs ) if( n instanceof FunNode ) funs.add(n);
+ units.add(new com.seaofnodes.print.IRPrinter.Unit<>(null,null,null,funs));
+ return PRINT.program(code._start,code._stop,units);
+ }
+ public static String _prettyPrint(CodeGen code) {
+ if( code._cfg==null ) return prettyPrint(code);
+ var blocks=new ArrayList<Node>();
+ for( Node n : code._cfg ) blocks.add(n);
+ return PRINT.scheduled(blocks);
}
- static void printLine( Node n, SB sb, Ary<Node> bns, int i, HashMap<Integer,Integer> ds, Ary<Node> ns ) {
- printLine( n, sb );
- if( i != -1 ) bns.del(i);
- ds.remove(n._nid);
- int idx = ns.find(n);
- if( idx!=-1 ) ns.del(idx);
- }
-
}
diff --git a/chapter24/src/main/java/com/seaofnodes/simple/print/SimpleGraphAdapter.java b/chapter24/src/main/java/com/seaofnodes/simple/print/SimpleGraphAdapter.java
index 4417ccd1..8dc6ea47 100644
--- a/chapter24/src/main/java/com/seaofnodes/simple/print/SimpleGraphAdapter.java
+++ b/chapter24/src/main/java/com/seaofnodes/simple/print/SimpleGraphAdapter.java
@@ -1,45 +1,25 @@
package com.seaofnodes.simple.print;
import com.seaofnodes.graph.GraphAdapter;
-import com.seaofnodes.graph.GraphSnapshot;
import com.seaofnodes.graph.GraphSnapshot.*;
import com.seaofnodes.simple.node.*;
import com.seaofnodes.simple.node.Node;
import com.seaofnodes.simple.type.TypeMem;
-import java.util.ArrayList;
/** Chapter 24's view of the IR; browser, transport and layout are shared. */
public class SimpleGraphAdapter extends GraphAdapter<Node> {
- @Override protected boolean dead(Node n) { return n.isDead(); }
- @Override protected int id(Node n) { return n._nid; }
- @Override protected int nIns(Node n) { return n.nIns(); }
- @Override protected Node in(Node n, int idx) { return n.in(idx); }
- @Override protected int nOuts(Node n) { return n.nOuts(); }
- @Override protected Node out(Node n, int idx) { return n.out(idx); }
- @Override protected int nDeps(Node n) { return n.nDeps(); }
- @Override protected Node dep(Node n, int idx) { return n.dep(idx); }
- private ArrayList<Edge> edges(Node n) {
- var edges = new ArrayList<Edge>();
- for( int i = 0; i < n.nIns(); i++ ) {
- String name = n instanceof ScopeNode scope && i < scope._vars.size()
+ @Override protected String edgeName(Node n, int i) {
+ return n instanceof ScopeNode scope && i < scope._vars.size()
? scope._vars.get(i)._name : null;
- int jump = n instanceof CallEndNode && i>0 && n.in(i) instanceof ReturnNode ret
- ? ref(ret.fun()) : 0;
- edges.add(new Edge(i, ref(n.in(i)), role(n, i), name, jump));
- }
- return edges;
}
-
- @Override protected GraphSnapshot.Node desc(Node n) {
- Projection proj = n instanceof ProjNode p ? new Projection(ref(n.in(0)), p._idx)
- : n instanceof CProjNode p ? new Projection(ref(n.in(0)), p._idx) : null;
- String label = n.label();
- return new GraphSnapshot.Node(n._nid, label == null ? n.getClass().getSimpleName() : label,
- n._type == null ? null : n._type.toString(), kind(n), edges(n), proj, folding(n));
+ @Override protected int edgeJump(Node n, int i) {
+ return n instanceof CallEndNode && i>0 && n.in(i) instanceof ReturnNode ret
+ ? ref(ret.fun()) : 0;
}
+ @Override protected int projectionIndex(Node n) { return n instanceof ProjNode p ? p._idx : n instanceof CProjNode p ? p._idx : -1; }
- private boolean folding(Node n) {
+ @Override protected boolean folding(Node n) {
if( n instanceof FunNode fun ) return fun.folding();
if( n instanceof ReturnNode ret ) return ret.fun().folding();
if( n instanceof CallEndNode cend ) return cend.folding();
@@ -49,7 +29,7 @@ public class SimpleGraphAdapter extends GraphAdapter<Node> {
return false;
}
- private Kind kind(Node n) {
+ @Override protected Kind kind(Node n) {
if( n instanceof StopNode ) return Kind.STOP;
if( n instanceof ScopeNode ) return Kind.SCOPE;
if( n instanceof FunNode ) return Kind.FUN;
@@ -60,7 +40,7 @@ public class SimpleGraphAdapter extends GraphAdapter<Node> {
return n instanceof CFGNode ? Kind.CTRL : isMem(n) ? Kind.MEM : Kind.DATA;
}
- private Role role(Node n, int i) {
+ @Override protected Role role(Node n, int i) {
if( n instanceof ScopeNode || n instanceof ConstantNode || n instanceof CtrlNode || n instanceof XCtrlNode ) return Role.ASSOC;
if( n instanceof PhiNode ) return i == 0 ? Role.ASSOC : isMem(n) ? Role.MEM : Role.DATA;
if( n instanceof ProjNode || n instanceof CProjNode )
diff --git a/chapter25/Makefile b/chapter25/Makefile
index 14a4c2a2..5b2b2531 100644
--- a/chapter25/Makefile
+++ b/chapter25/Makefile
@@ -66,6 +66,7 @@ test_javas := $(wildcard $(TST)/$(SIMPLE)/*java $(TST)/$(SIMPLE)/*/*java)
simple_driver := $(TST)/$(SIMPLE)/Simple.java
main_classes := $(patsubst $(SRC)/%java,$(CLZDIR)/main/%class,$(main_javas))
include $(firstword $(wildcard ../graph/graph.mk graph/graph.mk))
+include $(firstword $(wildcard ../print/print.mk print/print.mk))
test_classes := $(patsubst $(TST)/%java,$(CLZDIR)/test/%class,$(test_javas))
# These tests do not rely on the stdlib
test_alone := com.seaofnodes.simple.BrainFuckTest com.seaofnodes.simple.MergeSortTest com.seaofnodes.simple.TypeTest
diff --git a/chapter25/pom.xml b/chapter25/pom.xml
index ab9f2ea5..a60f824b 100644
--- a/chapter25/pom.xml
+++ b/chapter25/pom.xml
@@ -13,5 +13,6 @@
<name>Chapter 25</name>
<properties>
<simple.graph.directory>${project.basedir}/../graph</simple.graph.directory>
+ <simple.print.directory>${project.basedir}/../print</simple.print.directory>
</properties>
</project>
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;
diff --git a/docs/chapter-backports.md b/docs/chapter-backports.md
index b50bd25d..871c77f9 100644
--- a/docs/chapter-backports.md
+++ b/docs/chapter-backports.md
@@ -205,7 +205,7 @@ New returns high results while its control is high, and alias contents register
a dependency on that control. The existing integer widening and call-graph
solver remain intact. Register checks run before encoding adds untyped branches.
Private constructor memory, escape tracking, and incomplete-type SSA stay in 25.
-The separate pretty-printer consolidation remains pending.
+Pretty-printer consolidation is implemented below.
### Chapter 25 memory follow-through (implemented, same review batch)
@@ -254,6 +254,63 @@ native cohort-25 checks pass. Logs: `build/copy-forward21-spills-final.log`
through `build/copy-forward24-spills-final.log`, `build/copy-forward25-spills.log`,
`build/copy-forward25-baseline.log`, and `build/copy-forward*-tests*.log`.
+### Shared debug printers: Chapters 2-25 (implemented)
+
+The new [`print/`](../print/README.md) module owns expression recursion, IR
+row formatting and ordering, scheduled dumps, and assembly listing layout.
+Chapters retain their node spelling and small adapters for graph/machine facts.
+All chapter Nodes extend the shared `BaseNode<Node>`, providing one read-only
+node contract for printers and the viewer. Chapter 2 arithmetic needs only a
+one-line `format()` hook such as `"(%1+%2)"`; variable forms use protected hooks
+with `p.p(...)` and `p.n(...)`. Repeat tracking is universal, with repeated
+expansion for short constants. Common graph edge and snapshot construction has
+also moved out of chapter adapters.
+This also addresses issue #259's outside-package subclass use case. PR #260's
+public `_print1` change is superseded by the context API, rather than merged.
+
+The shared CFG-first RPO carries the Chapter 21 BrainFuck ordering correction
+through 25: loop headers precede their bodies, closing Regions follow them,
+and Phis stay with their headers. Function boundaries exclude caller arguments;
+shared floating expressions of constants print once with globals. All traversal
+and placement state is private; raw edges and captured encoding/layout metadata
+keep diagnostics read-only. `Node.toString()`/`print()` remain the expression
+entry points; `Node.p(depth)` starts structured dumps in Chapter 8, and
+`CodeGen.toString()` starts whole-program dumps in Chapter 18. The unused
+Chapter 7 IR adapter, `Node._printLine`, legacy LLVM-format wrappers, and
+`prettyPrintScheduled` aliases are removed. Evaluator/compiler `printLine`
+callers and the scheduled whole-program path in Chapters 20-24 remain.
+The wrapper cleanup passes all 26 chapter suites and the shared printer
+contracts (`build/prune-print-tests.log`, Chapters 1-9, and
+`build/prune-print-later-tests.log`, Chapters 10a-25).
+
+Make, Maven source paths, IDEA module dependencies, release packaging, and
+linearized checkout support include the shared sources. Shared contracts cover
+cycles, function boundaries, shared globals, Phi/projection grouping, multiline
+assembly, and captured pool metadata. Disposable real-graph checks cover
+BrainFuck and call/loop programs through Chapter 25, including repeatability,
+complete unique output, CFG order, and graph/cache identity. An outside-package
+Chapter 2 subclass compiles and prints nested operands using the protected hook.
+
+Validation: all 26 chapter Make suites and the shared contracts pass
+(`build/print-final-tests.log`). Chapters 21-24 each pass 18 real-graph snapshots;
+25 passes 12 (`build/print-probe-*.log`). Assembly checks cover all available
+CPUs in 19-25 before/after allocation and encoding (`build/asm-probe-*.log`).
+Fresh linearized Chapter 2 and 21 releases contain the shared printer classes;
+Chapter 2's fresh tests also pass (`build/print-linear{02,21}.log`). Maven/IDE XML
+parses, the linearization script passes its syntax check, and changes are LF-only.
+
+The subsequent BaseNode cleanup also passes all 26 suites
+(`build/base-early-final-tests.log`, `build/base-late-tests.log`) and the updated
+shared contracts, including multi-digit slots, escaped percent signs, missing
+inputs, cycles and matching-suffix trimming. Three Chapter 5-6 print expectations
+now use a short reference on a repeated Region. Nine Chapter 21 viewer snapshots
+match their pre-cleanup baseline except for canonical constant labels; both 21
+and 25 pass nine read-only, repeatable captures. Outside-package expression and
+format hooks compile. Fresh linearized Chapter 2/21 releases contain BaseNode and
+viewer classes (`build/base-linear{02,21}.log`). The graph IDEA module now depends
+on print. This cleanup removes about 2,800 node-source lines and 550 viewer-adapter
+lines beyond the original extraction.
+
### Other pending corrections
- **Chapter 25 historical String fixtures.** Ten replay entries fail before RA
@@ -277,22 +334,6 @@ through `build/copy-forward24-spills-final.log`, `build/copy-forward25-spills.lo
The Load-search rejection tests put the Store before the read to isolate
the optimization from that separate scheduling defect. Investigate separately.
-- **Forward Chapter 21 whole-program printer ordering through 22-25.**
- `CodeGen.toString()` before scheduling now uses function-local CFG RPO and
- groups every Region/Loop with its Phis. Chapter 25 supplied the function
- ownership and grouping approach, but its combined CFG/data walk still puts
- BrainFuck's closing Region before the body when adapted to 21. Chapter 21
- therefore orders control edges first, then places data for display using
- private identity maps. No scheduling, idom queries, or graph mutation occurs.
- The depth-limited node printer and scheduled whole-program printer retain
- their existing entry points. Checked 18 parse/opto/loop-tree snapshots for
- complete unique output, CFG ordering, Phi adjacency, repeatability, and
- unchanged graph/cache state. Updated BrainFuck dump:
- `build/brain-print-after-opto.txt`; diagnostic probe: `build/Print21Check.java`.
- Release passes. The current full suite passes 430/431 tests; the sole failure
- is the debugger-edited BrainFuck spill golden (42 versus the unchanged 130).
- Those test edits were preserved. Log: `build/printer21-tests.log`.
-
- **Chapter 21 synthetic TOP return allocation.** The original compiler at
`f01ee052` and the memory port both fail in `Coalesce.coalesce`: a Split of
TOP has no input live range. Reproduction: `struct S { int x; int y; };
diff --git a/graph/README.md b/graph/README.md
index 812a7318..a459898f 100644
--- a/graph/README.md
+++ b/graph/README.md
@@ -156,8 +156,9 @@ All chapters share the Java viewer plumbing as well as the browser:
`GraphObserver<N>`. Chapter subclasses compile source, attach/detach the observer,
and supply roots, phase and parser position. Each compilation gets fresh capture
state and a new compilation key, even when the previous compilation failed.
-- `GraphAdapter<N>` supplies node facts and indexed graph/dependency access.
- Dependency access defaults to an empty set in chapters without those lists.
+- `BaseNode<N>` in `print/` supplies identity and indexed graph/dependency access.
+ Dependency access defaults to an empty set. `GraphAdapter<N>` adds viewer roles
+ and grouping facts for the chapter.
Shared Java has no dependency on chapter classes.
The WebSocket listener and built-in asset server bind to 127.0.0.1.
@@ -344,13 +345,12 @@ interactive viewer also loads the web assets from this checkout.
The shared Java code is in `src/main/java/com/seaofnodes/graph/`:
-- `GraphAdapter<N>` is an abstract base with hooks for `id`, `desc`, and indexed
- edge access (`nIns`/`in`, `nOuts`/`out`). Its final `snap` method walks definitions and
- uses iteratively, handles cycles, and sorts the copied records by ID.
-- `GraphSnapshot` is detached data: compilation key, step, roots, active scope, nodes and groups.
- Each node has an ID, plain-text label/type, kind, edges to its defs, and optional
- projection metadata. It contains no chapter classes or layout coordinates.
- Node and edge lists are concrete `ArrayList`s, treated as read-only after capture.
+- `GraphAdapter<N extends BaseNode<N>>` reads identity, edges, dependencies,
+ labels, and types directly from the shared node contract. It constructs node
+ and edge records centrally. Chapter hooks provide kinds, edge roles, scope
+ binding names, projection indices, call shortcuts, and folding state as needed.
+ Its final `snap` method walks definitions and uses iteratively, handles cycles,
+ and sorts the copied records by ID.
Root IDs use `int[]`. Capture uses a node table indexed by ID for visitation and
root deduplication; no boxed integer lists, sets or map keys are needed.
@@ -358,8 +358,9 @@ Indexed edge access reads each chapter's native storage without copying it into
a different collection type.
Every chapter implements `com.seaofnodes.simple.print.SimpleGraphAdapter`,
-extending `GraphAdapter<Node>`. The chapter owns classification and extraction; the base owns traversal
-and snapshot assembly. No new Java interface is involved.
+extending `GraphAdapter<Node>`. The chapter owns semantic classification; the
+base owns edge extraction, traversal, and snapshot assembly. The common
+`BaseNode` class lives in `print/`, which is also an IDEA dependency of `graph/`.
For chapter 4:
diff --git a/graph/graph.iml b/graph/graph.iml
index 8e9a0e43..99b14f9d 100644
--- a/graph/graph.iml
+++ b/graph/graph.iml
@@ -11,5 +11,6 @@
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
+ <orderEntry type="module" module-name="print" />
</component>
</module>
diff --git a/graph/src/main/java/com/seaofnodes/graph/GraphAdapter.java b/graph/src/main/java/com/seaofnodes/graph/GraphAdapter.java
index eaa308f9..9014ce04 100644
--- a/graph/src/main/java/com/seaofnodes/graph/GraphAdapter.java
+++ b/graph/src/main/java/com/seaofnodes/graph/GraphAdapter.java
@@ -1,5 +1,7 @@
package com.seaofnodes.graph;
+import com.seaofnodes.print.BaseNode;
+import static com.seaofnodes.graph.GraphSnapshot.*;
import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Arrays;
@@ -10,18 +12,40 @@ import java.util.Comparator;
* Capture on the compiler thread, while the graph is not being modified.
* Hooks must only read the IR: no computing types, peepholes or scheduling.
*/
-public abstract class GraphAdapter<N> {
- protected abstract int id(N node);
- protected abstract int nIns(N node);
- protected abstract N in(N node, int idx);
- protected abstract int nOuts(N node);
- protected abstract N out(N node, int idx);
- protected abstract GraphSnapshot.Node desc(N node);
- protected abstract boolean dead(N node);
+public abstract class GraphAdapter<N extends BaseNode<N>> {
+ protected final int id(N n) { return n._nid; }
+ protected final int nIns(N n) { return n.nIns(); }
+ protected final N in(N n, int i) { return n.in(i); }
+ protected final int nOuts(N n) { return n.nOuts(); }
+ protected final N out(N n, int i) { return n.out(i); }
+ protected final boolean dead(N n) { return n.isDead(); }
+ protected final int nDeps(N n) { return n.nDeps(); }
+ protected final N dep(N n, int i) { return n.dep(i); }
+
+ // Chapters supply only semantic distinctions that their IR has introduced.
+ protected Kind kind(N n) { return n.isCFG() ? Kind.CTRL : Kind.DATA; }
+ protected Role role(N n, int i) { return i==0 ? Role.CTRL : Role.DATA; }
+ protected String[] edgeNames(N n) { return null; }
+ protected String edgeName(N n, int i) { return null; }
+ protected int edgeJump(N n, int i) { return 0; }
+ protected int projectionIndex(N n) { return -1; }
+ protected boolean folding(N n) { return false; }
// Omit cached helpers with no graph uses; still walk through them.
- protected boolean show(N node) { return true; }
- protected int nDeps(N node) { return 0; }
- protected N dep(N node, int idx) { throw new IndexOutOfBoundsException(idx); }
+ protected boolean show(N n) { return true; }
+
+ protected final GraphSnapshot.Node desc(N n) {
+ var edges=new ArrayList<Edge>();
+ String[] names=edgeNames(n);
+ for( int i=0; i<n.nIns(); i++ ) {
+ String name=names!=null && i<names.length ? names[i] : edgeName(n,i);
+ edges.add(new Edge(i,ref(n.in(i)),role(n,i),name,edgeJump(n,i)));
+ }
+ int idx=projectionIndex(n);
+ Projection proj=idx<0 ? null : new Projection(n.nIns()==0 ? 0 : ref(n.in(0)),idx);
+ String label=n.label();
+ return new GraphSnapshot.Node(n._nid,label==null ? n.getClass().getSimpleName() : label,
+ n.typeName(),kind(n),edges,proj,folding(n));
+ }
protected final int ref(N node) { return node == null ? 0 : id(node); }
diff --git a/graph/src/main/java/com/seaofnodes/graph/GraphCapture.java b/graph/src/main/java/com/seaofnodes/graph/GraphCapture.java
index 966dd701..10071755 100644
--- a/graph/src/main/java/com/seaofnodes/graph/GraphCapture.java
+++ b/graph/src/main/java/com/seaofnodes/graph/GraphCapture.java
@@ -1,12 +1,13 @@
package com.seaofnodes.graph;
+import com.seaofnodes.print.BaseNode;
import java.io.IOException;
import java.util.ArrayList;
import java.util.BitSet;
import java.util.UUID;
/** Shared compilation lifecycle, capture, event nesting and neighborhoods. */
-public abstract class GraphCapture<N> extends GraphObserver<N> {
+public abstract class GraphCapture<N extends BaseNode<N>> extends GraphObserver<N> {
private final GraphAdapter<N> _graph;
private String _comp;
diff --git a/pom.xml b/pom.xml
index 951411f6..4f52e164 100644
--- a/pom.xml
+++ b/pom.xml
@@ -53,6 +53,7 @@
<maven.compiler.target>21</maven.compiler.target>
<!-- Also works at the root of a linearized chapter checkout. -->
<simple.graph.directory>${project.basedir}/graph</simple.graph.directory>
+ <simple.print.directory>${project.basedir}/print</simple.print.directory>
</properties>
<dependencies>
@@ -76,7 +77,10 @@
<phase>generate-sources</phase>
<goals><goal>add-source</goal></goals>
<configuration>
- <sources><source>${simple.graph.directory}/src/main/java</source></sources>
+ <sources>
+ <source>${simple.graph.directory}/src/main/java</source>
+ <source>${simple.print.directory}/src/main/java</source>
+ </sources>
</configuration>
</execution>
</executions>
diff --git a/print/Makefile b/print/Makefile
new file mode 100644
index 00000000..9518b2d1
--- /dev/null
+++ b/print/Makefile
@@ -0,0 +1,14 @@
+SHELL := /bin/bash
+.DEFAULT_GOAL := tests
+.DELETE_ON_ERROR:
+main_javas := $(wildcard src/main/java/com/seaofnodes/print/*.java)
+test_javas := $(wildcard src/test/java/com/seaofnodes/print/*.java)
+
+.PHONY: tests
+tests: build/classes/.tag
+ java -ea -cp build/classes com.seaofnodes.print.PrinterTest
+
+build/classes/.tag: $(main_javas) $(test_javas)
+ @mkdir -p build/classes
+ javac -d build/classes $(main_javas) $(test_javas)
+ @touch $@
diff --git a/print/README.md b/print/README.md
new file mode 100644
index 00000000..76243bc0
--- /dev/null
+++ b/print/README.md
@@ -0,0 +1,112 @@
+# Shared debug printers
+
+Chapters share printing algorithms here while retaining the small hooks that
+describe their own nodes. This module imports no compiler classes and requires
+only the JDK. `make -C print tests` runs its independent contracts; the root
+`make tests` also runs them.
+
+## BaseNode: the common node view
+
+Each chapter's `Node` extends `BaseNode<Node>`. The base provides the node ID
+field, naming, `print()`/`toString()`, and the expression hook. The compiler
+allocates IDs as before, passing one to `super(...)`; cloning still assigns a
+fresh ID from the compiler's allocator. Graph storage and rewrites remain local.
+
+The common read-only contract is `in(i)`, `nIns()`, `out(i)`, and `nOuts()`.
+Optional dependency access defaults to an empty set. Existing `label()` and
+`isDead()` methods fit directly; `typeName()` exposes the chapter's available
+type text. Both printers and the viewer use this contract, so their adapters
+need no ID, edge, dead-node, or dependency forwarding methods.
+
+## Expressions: format strings or fluent hooks
+
+Chapter 2's arithmetic nodes need just one line:
+
+```java
+@Override protected String format() { return "(%1+%2)"; }
+```
+
+`%1` means input slot 1, `%10` means slot 10, and `%%` prints a literal `%`.
+Null or unattached inputs print `____`. A missing `format()` uses the node's
+label. All expression prints track repeats; constants whose type text fits in
+32 characters expand every time. Larger constants use their unique name on
+repeat. Naming defaults to `label()+_nid`, with no separate constant/cast/guard
+prefix protocol; constants use the label `Con` and print their value normally.
+
+Variable-length or conditional output uses the protected hook:
+
+```java
+@Override protected ExprPrinter<Node> _print1(ExprPrinter<Node> p) {
+ p.p("Phi(");
+ for( Node in : _inputs ) p.n(in).p(",");
+ return p.unchar(',').close();
+}
+```
+
+`p()` appends text, `n()` prints a node in the same context, and `open()`/`close()`
+append parentheses. `p.prt(this,"(%1+%2)")` also works inside a custom hook.
+An outside-package subclass can override either hook without exposing it as a
+public compiler API. Calling an operand's `toString()` starts a separate
+context; use `n()` or a format slot to retain repeat tracking.
+
+`unchar(',')` and `unchar(", ")` remove only a matching trailing separator.
+`unchar()` and `unchar(n)` remove one or several characters unconditionally.
+All return the context for chaining.
+
+## IR dumps
+
+From Chapter 8, a chapter's `IRPrinter` is an `IRAdapter<Node>` plus the familiar
+debugger entry points. The common node view supplies raw edges, identity, and
+labels; the adapter adds node kinds and chapter-specific type spelling. Features
+have defaults so early chapters need not implement functions, modules, or memory
+annotations.
+
+The supported paths are `Node.toString()`/`print()` for compact expressions,
+`Node.p(depth)` from Chapter 8 for a bounded IR dump, and `CodeGen.toString()`
+from Chapter 18 for a whole-program dump. Chapters 20-24 use the recorded
+schedule after scheduling. `IRPrinter.printLine(Node, SB)` remains for evaluator
+traces and compiler diagnostics; there is no separate `Node._printLine` entry
+point. The viewer captures `BaseNode` facts through `SimpleGraphObserver` and
+`SimpleGraphAdapter`, independently of the text printers.
+
+The shared IR printer owns row formatting, bounded backward slices, CFG reverse
+postorder, Phi and projection grouping, and diagnostic data placement. It walks
+control before data, keeping a loop's closing merge below its body. Function
+dumps stop at call-graph boundaries. Chapter 25 supplies compilation-unit roots
+and function ownership; the shared code does not know its module representation.
+Scheduled whole-program dumps retain the compiler's existing block order.
+
+Printer state is private. Never compute dominators, schedule code, reorder use
+lists, resolve aliases, or compute a type's layout to produce a dump. The code
+must tolerate missing inputs during graph construction. Print callbacks must
+obey the same read-only rule.
+
+## Assembly listings
+
+`CodeGen.asm()` is the assembly debugger entry point from Chapter 19 onward;
+inside `RegAlloc`, use `_code.asm()`. It calls the chapter's `ASMPrinter`
+adapter and then the shared assembly printer. Keep this path even when it has
+no ordinary source callers: it is an intentional debugger API.
+
+Register spelling comes from `CodeGen.reg(...)`: `N<node-id>` before a live
+range exists, `V<LRG-id>` while that range has no chosen register, then the
+selected register or stack location. Diagnostic LRG lookup follows leaders
+without compressing them or changing the node mapping. After encoding, the
+same entry point includes recorded instruction bytes and constant-pool dumps
+(and static data where supported).
+
+From Chapter 19, `AssemblyAdapter<Node>` supplies machine-specific instruction
+spelling, register names, visibility, and scheduled blocks. Machine nodes retain
+their `asm` hooks. Encoding chapters additionally expose recorded instruction
+offsets, lengths, bytes, and constant-pool metadata. The shared implementation
+owns traversal, columns, Phi rows, byte order, multiline instructions, and data
+sections. Type sizes and alignment come from encoding metadata, never fresh
+layout queries.
+
+## Build integration
+
+`print.mk` adds the shared sources to each chapter's Make build, just as the
+viewer adds its sources through `graph.mk`. Maven source paths and IDEA module
+dependencies include `print/` too. The graph module depends on `print/` for
+`BaseNode`; Make does not require Maven. Linearized
+checkouts carry the shared directory and find it at their repository root.
diff --git a/print/print.iml b/print/print.iml
new file mode 100644
index 00000000..c6c0d587
--- /dev/null
+++ b/print/print.iml
@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<module type="JAVA_MODULE" version="4">
+ <component name="NewModuleRootManager" inherit-compiler-output="false">
+ <output url="file://$MODULE_DIR$/../build/idea/production/print" />
+ <output-test url="file://$MODULE_DIR$/../build/idea/test/print" />
+ <exclude-output />
+ <content url="file://$MODULE_DIR$">
+ <sourceFolder url="file://$MODULE_DIR$/src/main/java" isTestSource="false" />
+ <sourceFolder url="file://$MODULE_DIR$/src/test/java" isTestSource="true" />
+ <excludeFolder url="file://$MODULE_DIR$/build" />
+ <excludeFolder url="file://$MODULE_DIR$/target" />
+ </content>
+ <orderEntry type="inheritedJdk" />
+ <orderEntry type="sourceFolder" forTests="false" />
+ </component>
+</module>
diff --git a/print/print.mk b/print/print.mk
new file mode 100644
index 00000000..2e41db68
--- /dev/null
+++ b/print/print.mk
@@ -0,0 +1,4 @@
+# Shared printing sources, also usable in a linearized chapter checkout.
+PRINT_DIR := $(patsubst %/,%,$(dir $(lastword $(MAKEFILE_LIST))))
+print_javas := $(wildcard $(PRINT_DIR)/src/main/java/com/seaofnodes/print/*.java)
+main_javas += $(print_javas)
diff --git a/print/src/main/java/com/seaofnodes/print/ASMPrinter.java b/print/src/main/java/com/seaofnodes/print/ASMPrinter.java
new file mode 100644
index 00000000..89c64b2c
--- /dev/null
+++ b/print/src/main/java/com/seaofnodes/print/ASMPrinter.java
@@ -0,0 +1,157 @@
+package com.seaofnodes.print;
+
+import java.util.ArrayList;
+import java.util.Comparator;
+import java.util.IdentityHashMap;
+import static com.seaofnodes.print.IRAdapter.Kind;
+
+/** Assembly listing layout shared by every chapter with instruction selection. */
+public final class ASMPrinter<N extends BaseNode<N>> {
+ private final AssemblyAdapter<N> _a;
+ private final IRAdapter<N> _ir;
+ private final StringBuilder _text=new StringBuilder();
+ private final IdentityHashMap<N,Boolean> _seen=new IdentityHashMap<>();
+ private int _address;
+ public ASMPrinter(AssemblyAdapter<N> adapter) { _a=adapter; _ir=adapter.ir; }
+
+ public String print() {
+ _text.setLength(0);
+ _seen.clear();
+ _address=0;
+ ArrayList<N> blocks=_a.blocks();
+ if( blocks.isEmpty() ) return "No scheduled code";
+ for( int i=0; i<blocks.size(); i++ ) {
+ N fun=blocks.get(i);
+ if( _ir.kind(fun)!=Kind.FUN ) continue;
+ _text.append("\n--- ").append(_ir.signature(fun)).append("---------------------------\n");
+ if( _a.encoded() ) _address=(_address+15)&-16;
+ if( _a.prologue(fun) ) instruction(fun,blocks,i);
+ for( ; i<blocks.size() && _ir.kind(blocks.get(i))!=Kind.RETURN; i++ )
+ block(blocks.get(i),blocks,i);
+ _text.append("--- ").append(_ir.functionName(fun)).append("---------------------------\n");
+ }
+ for( Pool pool : _a.pools(_address) ) _text.append(pool(pool));
+ return _text.toString();
+ }
+
+ private String label(N n) { return (_ir.kind(n)==Kind.LOOP ? "LOOP" : "L")+_ir.id(n); }
+ private void block(N bb, ArrayList<N> blocks, int idx) {
+ if( _a.labelBlock(bb) ) _text.append(label(bb)).append(":\n");
+ if( _ir.kind(bb)==Kind.CALL ) return;
+ boolean packed=false;
+ for( int i=0; i<_ir.nOuts(bb); i++ ) {
+ N n=_ir.out(bb,i);
+ if( !_ir.phi(n) || _a.hidden(n) || _seen.put(n,Boolean.TRUE)!=null ) continue;
+ if( _a.postAlloc() ) {
+ if( !packed ) { indent(); packed=true; }
+ _text.append(_a.phiName(n)).append(':').append(_a.register(n)).append(',');
+ } else {
+ indent(); field(_a.phiName(n),5); _text.append(' ').append(_a.register(n));
+ if( _ir.kind(n)!=Kind.PARM ) {
+ _text.append(" = phi( ");
+ for( int j=1; j<_ir.nIns(n); j++ ) {
+ if( j>1 ) _text.append(',');
+ N def=_ir.in(n,j);
+ _text.append(def==null ? "___" : "N"+_ir.id(def));
+ }
+ _text.append(" )");
+ }
+ _text.append('\n');
+ }
+ }
+ if( packed ) { _text.setLength(_text.length()-1); _text.append('\n'); }
+ for( int i=0; i<_ir.nOuts(bb); i++ ) {
+ N n=_ir.out(bb,i);
+ if( n!=null && !_ir.phi(n) ) instruction(n,blocks,idx);
+ }
+ }
+
+ private void instruction(N n, ArrayList<N> blocks, int idx) {
+ if( n==null || _a.hidden(n) || _ir.kind(n)==Kind.CPROJ ) return;
+ if( _ir.region(n) && _ir.kind(n)!=Kind.FUN ) {
+ if( _a.encoded() ) return;
+ // A successor may be reached by falling through empty blocks.
+ for( int j=idx+1; j<blocks.size(); j++ ) {
+ N next=blocks.get(j);
+ if( next==n ) return;
+ if( _ir.nOuts(next)>1 ) break;
+ }
+ address(_address++); field("??",_a.defaultSize()*2);
+ _text.append(" "); field("JMP",5); _text.append(' ').append(label(n)).append('\n');
+ return;
+ }
+ if( _seen.put(n,Boolean.TRUE)!=null ) return;
+ if( _ir.kind(n)==Kind.PROJ ) {
+ if( _a.encoded() ) return;
+ indent(); _text.append(" "); field(_a.register(n),5);
+ _text.append(" // ").append(_ir.label(n)).append('\n');
+ return;
+ }
+ int offset=_a.offset(n), size=Math.max(0,_a.size(n)), width=_a.defaultSize();
+ if( offset>=0 ) _address=offset;
+ String args=_a.operands(n);
+ String[] lines=(args.startsWith("\n") ? args.substring(1) : args).split("\n",-1);
+ int done=0;
+ for( int row=0; row<lines.length || done<size; row++ ) {
+ if( row>0 && done>=size && row==lines.length-1 && lines[row].isEmpty() ) break;
+ address(_address);
+ int count=_a.bytes()==null ? 0 : Math.min(width,size-done);
+ bytes(_address,count,_a.littleEndian());
+ field("",(width-count)*2); _text.append(" ");
+ if( row==0 ) { field(_a.op(n),5); _text.append(' '); }
+ if( row<lines.length ) field(lines[row],row==0 ? 30 : 0);
+ if( row==0 ) {
+ String comment=_a.comment(n);
+ if( comment!=null ) _text.append(" // ").append(comment);
+ }
+ _text.append('\n');
+ done+=count; _address+=count;
+ if( _a.bytes()==null ) {
+ // Before encoding, multiline machine expansions still show
+ // every instruction; byte lengths are not yet available.
+ if( row==0 ) { _address+=size; done=size; }
+ }
+ if( count==0 && row>=lines.length-1 ) break;
+ }
+ if( !_ir.control(n) )
+ for( int i=0; i<_ir.nOuts(n); i++ ) {
+ N proj=_ir.out(n,i);
+ if( proj!=null && _ir.kind(proj)==Kind.PROJ && _ir.input0(proj)==n ) instruction(proj,blocks,idx);
+ }
+ }
+ private void indent() { field("",7+_a.defaultSize()*2); }
+ private void field(String text, int width) {
+ _text.append(text);
+ if( width>text.length() ) _text.append(" ".repeat(width-text.length()));
+ }
+ private void address(int address) { _text.append("%04x ".formatted(address)); }
+ private void bytes(int offset, int count, boolean little) {
+ byte[] bytes=_a.bytes();
+ for( int i=0; i<count; i++ ) {
+ int idx=offset+(little ? i : count-i-1);
+ if( idx<0 || idx>=bytes.length ) _text.append("??");
+ else _text.append("%02x".formatted(bytes[idx]&255));
+ }
+ }
+
+ /** Metadata captured during encoding; printing never computes a type's layout. */
+ public record Data(Object identity, String type, int alignment, int size) {}
+ public record Pool(String name, byte[] bytes, int offset, int address, ArrayList<Data> entries) {}
+
+ public static String pool(Pool pool) {
+ StringBuilder sb=new StringBuilder("--- "+pool.name()+" ------\n");
+ ArrayList<Data> entries=new ArrayList<>(pool.entries());
+ entries.sort(Comparator.comparingInt(Data::alignment).reversed());
+ IdentityHashMap<Object,Boolean> seen=new IdentityHashMap<>();
+ int offset=pool.offset(), address=pool.address();
+ for( Data entry : entries ) {
+ if( seen.put(entry.identity(),Boolean.TRUE)!=null ) continue;
+ sb.append("%04x ".formatted(address));
+ for( int i=0; i<entry.size(); i++ )
+ sb.append(offset+i<pool.bytes().length ? "%02x".formatted(pool.bytes()[offset+i]&255) : "??");
+ sb.append('\t').append(entry.type()).append('\n');
+ offset+=entry.size(); address+=entry.size();
+ }
+ return sb.toString();
+ }
+}
diff --git a/print/src/main/java/com/seaofnodes/print/AssemblyAdapter.java b/print/src/main/java/com/seaofnodes/print/AssemblyAdapter.java
new file mode 100644
index 00000000..a6aaf8d8
--- /dev/null
+++ b/print/src/main/java/com/seaofnodes/print/AssemblyAdapter.java
@@ -0,0 +1,26 @@
+package com.seaofnodes.print;
+
+import java.util.ArrayList;
+
+/** Machine facts for a listing, independent of traversal and column formatting. */
+public abstract class AssemblyAdapter<N extends BaseNode<N>> {
+ public final IRAdapter<N> ir;
+ protected AssemblyAdapter(IRAdapter<N> ir) { this.ir=ir; }
+ public abstract ArrayList<N> blocks();
+ public abstract String op(N n);
+ public abstract String operands(N n);
+ public abstract String register(N n);
+ public String comment(N n) { return null; }
+ public String phiName(N n) { return ir.label(n); }
+ public boolean hidden(N n) { return false; }
+ public boolean labelBlock(N n) { return true; }
+ public boolean postAlloc() { return false; }
+ public boolean encoded() { return false; }
+ public boolean prologue(N fun) { return false; }
+ public int defaultSize() { return 4; }
+ public boolean littleEndian() { return true; }
+ public int offset(N n) { return -1; }
+ public int size(N n) { return 1; }
+ public byte[] bytes() { return null; }
+ public ArrayList<ASMPrinter.Pool> pools(int codeEnd) { return new ArrayList<>(); }
+}
diff --git a/print/src/main/java/com/seaofnodes/print/BaseNode.java b/print/src/main/java/com/seaofnodes/print/BaseNode.java
new file mode 100644
index 00000000..cc196b8c
--- /dev/null
+++ b/print/src/main/java/com/seaofnodes/print/BaseNode.java
@@ -0,0 +1,37 @@
+package com.seaofnodes.print;
+
+/** Common read-only node view for debug printing and graph capture. */
+public abstract class BaseNode<N extends BaseNode<N>> {
+ // Allocated by the compiler. Copies receive a new ID from that same allocator.
+ public int _nid;
+ protected BaseNode(int nid) { _nid=nid; }
+
+ public abstract N in(int i);
+ public abstract int nIns();
+ public abstract N out(int i);
+ public abstract int nOuts();
+ public int nDeps() { return 0; }
+ public N dep(int i) { throw new IndexOutOfBoundsException(i); }
+
+ public String label() { return getClass().getSimpleName(); }
+ public String typeName() { return null; }
+ public boolean isDead() { return false; }
+ public boolean isCFG() { return false; }
+ public String glabel() { return label(); }
+ public String comment() { return null; }
+ public final String uniqueName() { return label()+_nid; }
+
+ // %0, %1, ... name input slots; %% prints a literal percent sign.
+ protected String format() { return null; }
+ protected ExprPrinter<N> _print1(ExprPrinter<N> p) {
+ String fmt=format();
+ return fmt==null ? p.p(label()) : p.prt(self(),fmt);
+ }
+ // Short constants return null to expand their value on each appearance.
+ protected String repeatName() { return label(); }
+
+ @SuppressWarnings("unchecked")
+ private N self() { return (N)this; }
+ public final String print() { return ExprPrinter.print(self()); }
+ @Override public final String toString() { return print(); }
+}
diff --git a/print/src/main/java/com/seaofnodes/print/ExprPrinter.java b/print/src/main/java/com/seaofnodes/print/ExprPrinter.java
new file mode 100644
index 00000000..129be470
--- /dev/null
+++ b/print/src/main/java/com/seaofnodes/print/ExprPrinter.java
@@ -0,0 +1,56 @@
+package com.seaofnodes.print;
+
+import java.util.IdentityHashMap;
+
+/** One expression's buffer and repeat tracking, shared by recursive node hooks. */
+public final class ExprPrinter<N extends BaseNode<N>> {
+ private final StringBuilder _text=new StringBuilder();
+ private final IdentityHashMap<N,Boolean> _seen=new IdentityHashMap<>();
+ private ExprPrinter() {}
+
+ public static <N extends BaseNode<N>> String print(N node) {
+ return new ExprPrinter<N>().n(node).toString();
+ }
+
+ public ExprPrinter<N> n(N node) {
+ if( node==null ) return p("____");
+ if( node.isDead() ) return p(node.uniqueName()).p(":DEAD");
+ if( _seen.put(node,Boolean.TRUE)!=null ) {
+ String ref=node.repeatName();
+ if( ref!=null ) return p(ref);
+ }
+ node._print1(this);
+ return this;
+ }
+
+ /** Input slots are decimal numbers. Missing inputs print like null inputs. */
+ public ExprPrinter<N> prt(N node, String fmt) {
+ for( int i=0; i<fmt.length(); i++ ) {
+ char c=fmt.charAt(i);
+ if( c!='%' ) { p(c); continue; }
+ if( ++i==fmt.length() ) throw new IllegalArgumentException("Trailing % in "+fmt);
+ if( fmt.charAt(i)=='%' ) { p('%'); continue; }
+ int start=i;
+ while( i<fmt.length() && fmt.charAt(i)>='0' && fmt.charAt(i)<='9' ) i++;
+ if( start==i ) throw new IllegalArgumentException("Expected input slot in "+fmt);
+ int slot=Integer.parseInt(fmt.substring(start,i--));
+ n(node==null || slot>=node.nIns() ? null : node.in(slot));
+ }
+ return this;
+ }
+
+ public ExprPrinter<N> p(Object text) { _text.append(text); return this; }
+ public ExprPrinter<N> open() { return p('('); }
+ public ExprPrinter<N> close() { return p(')'); }
+ public ExprPrinter<N> unchar() { return unchar(1); }
+ public ExprPrinter<N> unchar(int n) { _text.setLength(_text.length()-n); return this; }
+ /** Remove a trailing separator only when it matches. */
+ public ExprPrinter<N> unchar(char c) {
+ return _text.length()>0 && _text.charAt(_text.length()-1)==c ? unchar() : this;
+ }
+ public ExprPrinter<N> unchar(String suffix) {
+ int start=_text.length()-suffix.length();
+ return start>=0 && _text.indexOf(suffix,start)==start ? unchar(suffix.length()) : this;
+ }
+ @Override public String toString() { return _text.toString(); }
+}
diff --git a/print/src/main/java/com/seaofnodes/print/IRAdapter.java b/print/src/main/java/com/seaofnodes/print/IRAdapter.java
new file mode 100644
index 00000000..06b169b0
--- /dev/null
+++ b/print/src/main/java/com/seaofnodes/print/IRAdapter.java
@@ -0,0 +1,34 @@
+package com.seaofnodes.print;
+
+/** Read-only facts about a chapter's graph. Needed only for structured IR dumps. */
+public abstract class IRAdapter<N extends BaseNode<N>> {
+ public enum Kind { DATA, CONSTANT, CTRL, START, STOP, REGION, LOOP, PHI, PARM,
+ MULTI, PROJ, CPROJ, FUN, RETURN, CALL, CALL_END, UNIT }
+ public int id(N n) { return n._nid; }
+ public String label(N n) { return n.label(); }
+ public int nIns(N n) { return n.nIns(); }
+ public N in(N n, int i) { return n.in(i); }
+ public int nOuts(N n) { return n.nOuts(); }
+ public N out(N n, int i) { return n.out(i); }
+ public abstract Kind kind(N n);
+ public boolean dead(N n) { return n.isDead(); }
+ public String type(N n) { String t=n.typeName(); return t==null ? "" : t; }
+ public int index(N n) { return id(n); }
+ public String signature(N fun) { return label(fun); }
+ public String functionName(N fun) { return label(fun); }
+ public String inputMark(N n, N def) { return " "; }
+ public boolean global(N n) { return kind(n)==Kind.CONSTANT; }
+ public int inputColumns() { return 4; }
+
+ public final N input0(N n) { return n == null || nIns(n) == 0 ? null : in(n,0); }
+ public final boolean control(N n) {
+ if( n == null ) return false;
+ return switch(kind(n)) {
+ case CTRL, START, STOP, REGION, LOOP, CPROJ, FUN, RETURN, CALL, CALL_END, UNIT -> true;
+ default -> false;
+ };
+ }
+ public final boolean phi(N n) { return n != null && (kind(n) == Kind.PHI || kind(n) == Kind.PARM); }
+ public final boolean projection(N n) { return n != null && (kind(n) == Kind.PROJ || kind(n) == Kind.CPROJ); }
+ public final boolean region(N n) { return n != null && (kind(n) == Kind.REGION || kind(n) == Kind.LOOP || kind(n) == Kind.FUN); }
+}
diff --git a/print/src/main/java/com/seaofnodes/print/IRPrinter.java b/print/src/main/java/com/seaofnodes/print/IRPrinter.java
new file mode 100644
index 00000000..bfe1cb05
--- /dev/null
+++ b/print/src/main/java/com/seaofnodes/print/IRPrinter.java
@@ -0,0 +1,293 @@
+package com.seaofnodes.print;
+
+import java.util.ArrayDeque;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.IdentityHashMap;
+import static com.seaofnodes.print.IRAdapter.Kind;
+
+/** Shared diagnostic traversal. All ownership, ordering and visited state is local. */
+public final class IRPrinter<N extends BaseNode<N>> {
+ private final IRAdapter<N> _a;
+ public IRPrinter(IRAdapter<N> adapter) { _a = adapter; }
+
+ public record Unit<N>(String name, N start, N stop, ArrayList<N> functions) {}
+
+ public String program(N start, N stop, ArrayList<Unit<N>> units) {
+ StringBuilder sb=new StringBuilder(line(start));
+ ArrayList<N> constants=new ArrayList<>();
+ IdentityHashMap<N,Boolean> graph=new IdentityHashMap<>(), global=new IdentityHashMap<>();
+ globals(start,graph,constants);
+ for( N n : constants ) global.put(n,Boolean.TRUE);
+ // GVN can share a floating expression of constants between functions.
+ for( N n : sorted(graph) )
+ if( !_a.global(n) && floatingGlobal(n,global) ) constants.add(n);
+ constants.sort(Comparator.comparingInt(_a::id));
+ for( N n : constants ) sb.append(line(n));
+ ArrayList<Unit<N>> ordered=new ArrayList<>(units);
+ ordered.sort(Comparator.comparing(u -> u.name()==null ? "" : u.name()));
+ for( Unit<N> unit : ordered ) {
+ if( unit.start()!=null ) {
+ if( _a.dead(unit.start()) ) continue;
+ sb.append("\n=== ").append(unit.name()).append(" ===\n").append(line(unit.start()));
+ ArrayList<N> ps=new ArrayList<>();
+ for( int i=0; i<_a.nOuts(unit.start()); i++ ) {
+ N p=_a.out(unit.start(),i);
+ if( _a.projection(p) ) ps.add(p);
+ }
+ ps.sort(Comparator.comparingInt(_a::index));
+ for( N p : ps ) sb.append(line(p));
+ }
+ ArrayList<N> funs=new ArrayList<>(unit.functions());
+ funs.sort(Comparator.comparingInt(_a::id));
+ for( N fun : funs ) if( !_a.dead(fun) ) sb.append(function(fun,global));
+ sb.append(line(unit.stop()));
+ }
+ return sb.append(line(stop)).toString();
+ }
+
+ // Function-pointer constants can be attached to Returns rather than Start.
+ private void globals(N n, IdentityHashMap<N,Boolean> seen, ArrayList<N> constants) {
+ if( n==null || seen.put(n,Boolean.TRUE)!=null ) return;
+ if( _a.global(n) && !_a.dead(n) ) constants.add(n);
+ for( int i=0; i<_a.nIns(n); i++ ) globals(_a.in(n,i),seen,constants);
+ for( int i=0; i<_a.nOuts(n); i++ ) globals(_a.out(n,i),seen,constants);
+ }
+
+ private boolean floatingGlobal(N n, IdentityHashMap<N,Boolean> global) {
+ if( n==null ) return true;
+ Boolean old=global.get(n);
+ if( old!=null ) return old;
+ global.put(n,Boolean.FALSE); // Stop incomplete data cycles.
+ if( _a.dead(n) || _a.kind(n)!=Kind.DATA || _a.input0(n)!=null || _a.nIns(n)==0 ) return false;
+ for( int i=1; i<_a.nIns(n); i++ )
+ if( !floatingGlobal(_a.in(n,i),global) ) return false;
+ global.put(n,Boolean.TRUE);
+ return true;
+ }
+
+ public String line(N n) {
+ if( n == null ) return "";
+ StringBuilder sb = new StringBuilder();
+ sb.append("%4d %-7.7s ".formatted(_a.id(n),_a.label(n)));
+ if( _a.dead(n) ) return sb.append("DEAD\n").toString();
+ for( int i=0; i<_a.nIns(n); i++ ) {
+ N def = _a.in(n,i);
+ sb.append(def == null ? "____" : "%4d".formatted(_a.id(def))).append(_a.inputMark(n,def));
+ }
+ int cols = _a.inputColumns();
+ for( int i=_a.nIns(n); i<cols; i++ ) sb.append(" ");
+ sb.append(" [[ ");
+ for( int i=0; i<_a.nOuts(n); i++ ) {
+ N use = _a.out(n,i);
+ sb.append(use == null ? "____ " : "%4d ".formatted(_a.id(use)));
+ }
+ for( int i=_a.nOuts(n); i<cols+2-Math.max(_a.nIns(n),cols); i++ ) sb.append(" ");
+ return sb.append(" ]] ").append(_a.type(n)).append('\n').toString();
+ }
+
+ /** A bounded backward slice, including the headers of boundary projections/Phis. */
+ public String prettyPrint(N root, int depth) {
+ IdentityHashMap<N,Boolean> nodes = new IdentityHashMap<>();
+ ArrayDeque<N> todo = new ArrayDeque<>();
+ if( root != null ) { nodes.put(root,Boolean.TRUE); todo.add(root); }
+ for( int d=0; d<depth && !todo.isEmpty(); d++ ) {
+ int count=todo.size();
+ while( count-->0 ) {
+ N n=todo.remove();
+ for( int i=0; i<_a.nIns(n); i++ ) {
+ N def=_a.in(n,i);
+ if( def != null && nodes.put(def,Boolean.TRUE)==null ) todo.add(def);
+ }
+ }
+ }
+ for( N n : new ArrayList<>(nodes.keySet()) )
+ if( _a.phi(n) || _a.projection(n) ) {
+ N head=_a.input0(n);
+ if( head != null ) nodes.put(head,Boolean.TRUE);
+ }
+ return render(nodes);
+ }
+
+ /** Dump one function without traversing the caller/callee linkage. */
+ public String function(N fun) {
+ return function(fun,new IdentityHashMap<>());
+ }
+
+ private String function(N fun, IdentityHashMap<N,Boolean> global) {
+ IdentityHashMap<N,Boolean> nodes = new IdentityHashMap<>();
+ collect(fun,fun,nodes);
+ nodes.keySet().removeIf(n -> Boolean.TRUE.equals(global.get(n)));
+ // Floating expressions of constants need not have a forward path from
+ // the function header. Include their definitions from the owned uses.
+ for( N n : new ArrayList<>(nodes.keySet()) )
+ // Parm alternatives are arguments in the callers, not local defs.
+ if( _a.kind(n)!=Kind.PARM )
+ for( int i=0; i<_a.nIns(n); i++ ) collectData(_a.in(n,i),nodes,global);
+ return "\n--- "+_a.signature(fun)+"----------------------\n"+
+ render(nodes)+"--- "+_a.functionName(fun)+" ----------------------\n";
+ }
+
+ private void collect(N n, N owner, IdentityHashMap<N,Boolean> seen) {
+ if( n == null || _a.dead(n) || seen.containsKey(n) || _a.global(n) ) return;
+ Kind k=_a.kind(n);
+ if( (k==Kind.FUN && n!=owner) || (k==Kind.PARM && _a.input0(n)!=owner) ) return;
+ if( k==Kind.START || k==Kind.STOP || k==Kind.UNIT ) return;
+ if( k==Kind.CALL_END && !seen.containsKey(_a.input0(n)) ) return;
+ seen.put(n,Boolean.TRUE);
+ if( k!=Kind.RETURN )
+ for( int i=0; i<_a.nOuts(n); i++ ) collect(_a.out(n,i),owner,seen);
+ }
+
+ private void collectData(N n, IdentityHashMap<N,Boolean> seen, IdentityHashMap<N,Boolean> global) {
+ if( n==null || seen.containsKey(n) || _a.dead(n) || _a.global(n) || _a.control(n) ||
+ Boolean.TRUE.equals(global.get(n)) ) return;
+ N head=_a.input0(n);
+ if( _a.control(head) && !seen.containsKey(head) ) return;
+ seen.put(n,Boolean.TRUE);
+ for( int i=0; i<_a.nIns(n); i++ ) collectData(_a.in(n,i),seen,global);
+ }
+
+ private ArrayList<N> sorted(IdentityHashMap<N,Boolean> nodes) {
+ ArrayList<N> ns = new ArrayList<>(nodes.keySet());
+ ns.sort(Comparator.comparingInt(_a::id));
+ return ns;
+ }
+
+ /** Finish CFG RPO before placing data; data backedges cannot reorder blocks. */
+ private String render(IdentityHashMap<N,Boolean> nodes) {
+ ArrayList<N> ns=sorted(nodes), post=new ArrayList<>();
+ IdentityHashMap<N,Boolean> seen=new IdentityHashMap<>();
+ // Start from CFG roots, then cover disconnected/partially built components.
+ for( N n : ns )
+ if( _a.control(n) && !hasPred(n,nodes) ) controlPost(n,nodes,seen,post);
+ for( N n : ns )
+ if( _a.control(n) ) controlPost(n,nodes,seen,post);
+ Collections.reverse(post);
+ IdentityHashMap<N,Integer> blocks=new IdentityHashMap<>();
+ ArrayList<ArrayList<N>> body=new ArrayList<>();
+ for( int i=0; i<post.size(); i++ ) { blocks.put(post.get(i),i); body.add(new ArrayList<>()); }
+ if( body.isEmpty() ) body.add(new ArrayList<>());
+ for( N n : ns )
+ if( !_a.control(n) ) body.get(block(n,nodes,blocks)).add(n);
+ StringBuilder sb=new StringBuilder();
+ IdentityHashMap<N,Boolean> emitted=new IdentityHashMap<>();
+ for( int i=0; i<body.size(); i++ ) {
+ if( i<post.size() ) {
+ N cfg=post.get(i);
+ sb.append('\n');
+ emitDefs(cfg,nodes,emitted,sb);
+ emitLine(cfg,emitted,sb);
+ // A Phi's backedge belongs in the body, never ahead of the Phi.
+ for( N n : body.get(i) ) if( _a.phi(n) ) emitLine(n,emitted,sb);
+ }
+ for( N n : body.get(i) ) emit(n,nodes,emitted,sb);
+ }
+ // Include unanchored Phis and dead/incomplete nodes exactly once.
+ for( N n : ns ) emitLine(n,emitted,sb);
+ return sb.toString();
+ }
+
+ private boolean edge(N def, N use) {
+ if( !_a.control(use) || _a.kind(use)==Kind.FUN || _a.kind(def)==Kind.RETURN ) return false;
+ if( _a.region(use) || _a.kind(use)==Kind.STOP ) {
+ for( int i=_a.kind(use)==Kind.STOP ? 0 : 1; i<_a.nIns(use); i++ )
+ if( _a.in(use,i)==def ) return true;
+ return false;
+ }
+ return _a.input0(use)==def;
+ }
+ private boolean hasPred(N n, IdentityHashMap<N,Boolean> nodes) {
+ for( int i=0; i<_a.nIns(n); i++ ) {
+ N def=_a.in(n,i);
+ // The loop entry determines its root status, not its backedge.
+ if( _a.kind(n)==Kind.LOOP && i>1 ) break;
+ if( def!=null && nodes.containsKey(def) && _a.control(def) && edge(def,n) ) return true;
+ }
+ return false;
+ }
+ private void controlPost(N n, IdentityHashMap<N,Boolean> nodes,
+ IdentityHashMap<N,Boolean> seen, ArrayList<N> post) {
+ if( seen.put(n,Boolean.TRUE)!=null ) return;
+ ArrayList<N> uses=new ArrayList<>();
+ for( int i=0; i<_a.nOuts(n); i++ ) {
+ N use=_a.out(n,i);
+ if( use!=null && nodes.containsKey(use) && edge(n,use) ) uses.add(use);
+ }
+ uses.sort(Comparator.comparingInt(_a::id));
+ for( N use : uses ) controlPost(use,nodes,seen,post);
+ post.add(n);
+ }
+ private int block(N n, IdentityHashMap<N,Boolean> nodes, IdentityHashMap<N,Integer> blocks) {
+ Integer old=blocks.get(n);
+ if( old!=null ) return old;
+ if( n==null || !nodes.containsKey(n) || _a.kind(n)==Kind.CONSTANT ) return 0;
+ blocks.put(n,0);
+ int b=0;
+ N head=_a.input0(n);
+ if( _a.control(head) || _a.projection(n) ) b=block(head,nodes,blocks);
+ else for( int i=0; i<_a.nIns(n); i++ ) b=Math.max(b,block(_a.in(n,i),nodes,blocks));
+ blocks.put(n,b);
+ return b;
+ }
+ private void emitDefs(N n, IdentityHashMap<N,Boolean> nodes, IdentityHashMap<N,Boolean> emitted,
+ StringBuilder sb) {
+ for( int i=0; i<_a.nIns(n); i++ ) emit(_a.in(n,i),nodes,emitted,sb);
+ }
+ private void emit(N n, IdentityHashMap<N,Boolean> nodes, IdentityHashMap<N,Boolean> emitted,
+ StringBuilder sb) {
+ if( n==null || emitted.containsKey(n) || !nodes.containsKey(n) || _a.control(n) || _a.phi(n) ) return;
+ if( _a.projection(n) && nodes.containsKey(_a.input0(n)) ) {
+ N head=_a.input0(n);
+ if( !emitted.containsKey(head) ) emit(head,nodes,emitted,sb);
+ if( emitted.containsKey(n) ) return;
+ }
+ emitted.put(n,Boolean.TRUE);
+ emitDefs(n,nodes,emitted,sb);
+ sb.append(line(n));
+ projections(n,nodes,emitted,sb);
+ }
+ private void emitLine(N n, IdentityHashMap<N,Boolean> emitted, StringBuilder sb) {
+ if( emitted.put(n,Boolean.TRUE)==null ) sb.append(line(n));
+ }
+ private void projections(N n, IdentityHashMap<N,Boolean> nodes, IdentityHashMap<N,Boolean> emitted,
+ StringBuilder sb) {
+ ArrayList<N> ps=new ArrayList<>();
+ for( int i=0; i<_a.nOuts(n); i++ ) {
+ N p=_a.out(n,i);
+ if( p!=null && nodes.containsKey(p) && _a.kind(p)==Kind.PROJ && _a.input0(p)==n ) ps.add(p);
+ }
+ ps.sort(Comparator.comparingInt(_a::index));
+ for( N p : ps ) emitLine(p,emitted,sb);
+ }
+
+ /** Scheduling already determines order; inspect it without sorting compiler arrays. */
+ public String scheduled(ArrayList<N> blocks) {
+ StringBuilder sb=new StringBuilder();
+ IdentityHashMap<N,Boolean> emitted=new IdentityHashMap<>();
+ for( N block : blocks ) {
+ if( block==null ) continue;
+ sb.append('\n');
+ emitLine(block,emitted,sb);
+ for( int i=0; i<_a.nOuts(block); i++ ) {
+ N use=_a.out(block,i);
+ if( _a.phi(use) ) emitLine(use,emitted,sb);
+ }
+ for( int i=0; i<_a.nOuts(block); i++ ) {
+ N use=_a.out(block,i);
+ if( use!=null && !_a.control(use) ) {
+ emitLine(use,emitted,sb);
+ ArrayList<N> ps=new ArrayList<>();
+ for( int j=0; j<_a.nOuts(use); j++ ) {
+ N p=_a.out(use,j);
+ if( p!=null && _a.kind(p)==Kind.PROJ && _a.input0(p)==use ) ps.add(p);
+ }
+ ps.sort(Comparator.comparingInt(_a::index));
+ for( N p : ps ) emitLine(p,emitted,sb);
+ }
+ }
+ }
+ return sb.toString();
+ }
+}
diff --git a/print/src/test/java/com/seaofnodes/print/PrinterTest.java b/print/src/test/java/com/seaofnodes/print/PrinterTest.java
new file mode 100644
index 00000000..d63cc6cb
--- /dev/null
+++ b/print/src/test/java/com/seaofnodes/print/PrinterTest.java
@@ -0,0 +1,153 @@
+package com.seaofnodes.print;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import static com.seaofnodes.print.IRAdapter.Kind;
+
+/** Small independent contracts for the shared printers. Run with assertions enabled. */
+public class PrinterTest {
+ static class N extends BaseNode<N> {
+ final String name;
+ final Kind kind;
+ final ArrayList<N> ins=new ArrayList<>(), outs=new ArrayList<>();
+ N(int id, String name, Kind kind, N... defs) {
+ super(id);
+ this.name=name; this.kind=kind;
+ for( N def : defs ) add(def);
+ }
+ @Override public N in(int i) { return ins.get(i); }
+ @Override public int nIns() { return ins.size(); }
+ @Override public N out(int i) { return outs.get(i); }
+ @Override public int nOuts() { return outs.size(); }
+ @Override public String label() { return name; }
+ @Override protected String repeatName() { return kind==Kind.CONSTANT ? null : name; }
+ @Override protected String format() { return ins.isEmpty() ? null : "(%0+%1)"; }
+ void add(N def) { ins.add(def); if( def!=null ) def.outs.add(this); }
+ }
+ static class Adapter extends IRAdapter<N> {
+ @Override public Kind kind(N n) { return n.kind; }
+ }
+
+ public static void main(String[] args) {
+ expression(); loop(); functions(); assembly();
+ System.out.println("Shared printer contracts passed");
+ }
+ static void expression() {
+ N one=new N(1,"1",Kind.CONSTANT), add=new N(2,"Add",Kind.DATA,one,one);
+ assert add.print().equals("(1+1)");
+ add.ins.set(1,add);
+ assert add.print().equals("(1+Add)");
+ // A failed callback must not leave another print's repeat state behind.
+ N bad=new N(3,"Bad",Kind.DATA) {
+ @Override protected ExprPrinter<N> _print1(ExprPrinter<N> p) { throw new IllegalStateException(); }
+ };
+ try { bad.print(); } catch( IllegalStateException expected ) {}
+ assert add.print().equals("(1+Add)");
+ N fmt=new N(4,"Format",Kind.DATA) {
+ @Override protected ExprPrinter<N> _print1(ExprPrinter<N> p) { return p.prt(this,"%10 %% %0 %12"); }
+ };
+ for( int i=0; i<11; i++ ) fmt.add(one);
+ assert fmt.print().equals("1 % 1 ____") : fmt.print();
+ N empty=new N(5,"Empty",Kind.DATA) {
+ @Override protected ExprPrinter<N> _print1(ExprPrinter<N> p) { return p.open().unchar(',').unchar(", ").close(); }
+ };
+ assert empty.print().equals("()");
+ }
+ static void loop() {
+ N fun=new N(1,"Fun",Kind.FUN);
+ N loop=new N(2,"Loop",Kind.LOOP,null,fun);
+ N phi=new N(3,"Phi",Kind.PHI,loop,null);
+ N branch=new N(4,"If",Kind.CTRL,loop,phi);
+ N yes=new N(5,"True",Kind.CPROJ,branch), no=new N(6,"False",Kind.CPROJ,branch);
+ N left=new N(7,"Left",Kind.CTRL,yes), right=new N(8,"Right",Kind.CTRL,no);
+ N merge=new N(9,"Merge",Kind.REGION,null,left,right);
+ N value=new N(10,"Add",Kind.DATA,null,phi);
+ phi.add(value); loop.add(merge);
+ N exit=new N(11,"Return",Kind.RETURN,merge,value);
+ // A call linkage must not bring another function's body into this dump.
+ N foreign=new N(12,"Other",Kind.FUN,exit);
+ new N(13,"Foreign",Kind.RETURN,foreign);
+ var nodes=new ArrayList<>(Arrays.asList(fun,loop,phi,branch,yes,no,left,right,merge,value,exit));
+ var inputs=new ArrayList<ArrayList<N>>(); var outputs=new ArrayList<ArrayList<N>>();
+ for( N n : nodes ) { inputs.add(new ArrayList<>(n.ins)); outputs.add(new ArrayList<>(n.outs)); }
+ IRPrinter<N> printer=new IRPrinter<>(new Adapter());
+ String text=printer.function(fun);
+ assert text.equals(printer.function(fun));
+ assert !text.contains("Foreign");
+ int li=row(text,"Loop"), pi=row(text,"Phi"), le=row(text,"Left"), ri=row(text,"Right"), mi=row(text,"Merge");
+ assert li>=0 && pi>li && le>pi && ri>pi && mi>le && mi>ri : text;
+ String[] lines=text.split("\n");
+ for( int i=0; i<lines.length; i++ )
+ if( lines[i].matches("\\s*2 Loop.*") ) assert lines[i+1].matches("\\s*3 Phi.*") : text;
+ for( int i=0; i<nodes.size(); i++ ) {
+ N n=nodes.get(i);
+ assert n.ins.equals(inputs.get(i)) && n.outs.equals(outputs.get(i));
+ int count=0;
+ for( String line : lines ) if( line.matches("\\s*"+n._nid+" "+n.name+" .*")) count++;
+ assert count==1 : n.name+" appears "+count+" times\n"+text;
+ }
+ assert printer.prettyPrint(null,2).isEmpty();
+ }
+ static int row(String text,String name) { return text.indexOf(" "+name+" "); }
+
+ static void functions() {
+ N start=new N(1,"Start",Kind.START), stop=new N(2,"Stop",Kind.STOP);
+ N one=new N(3,"One",Kind.CONSTANT,start);
+ N sum=new N(4,"Sum",Kind.DATA,null,one,one);
+ N caller=new N(5,"Caller",Kind.FUN,start), callee=new N(6,"Callee",Kind.FUN,start);
+ N arg=new N(7,"Arg",Kind.PARM,caller);
+ N load=new N(8,"Load",Kind.DATA,caller,arg);
+ N parm=new N(9,"Parm",Kind.PARM,callee,load);
+ N ret1=new N(10,"Ret1",Kind.RETURN,caller,load,sum);
+ N ret2=new N(11,"Ret2",Kind.RETURN,callee,parm,sum);
+ stop.add(ret1); stop.add(ret2);
+ IRPrinter<N> printer=new IRPrinter<>(new Adapter());
+ var funs=new ArrayList<>(Arrays.asList(caller,callee));
+ var units=new ArrayList<IRPrinter.Unit<N>>();
+ units.add(new IRPrinter.Unit<>("",null,null,funs));
+ String text=printer.program(start,stop,units);
+ for( N n : Arrays.asList(start,stop,one,sum,caller,callee,arg,load,parm,ret1,ret2) ) {
+ long count=text.lines().filter(line -> line.matches("\\s*"+n._nid+" .*" )).count();
+ assert count==1 : n.name+" appears "+count+" times\n"+text;
+ }
+ assert row(text,"Sum")<row(text,"Caller") : text;
+ assert !printer.function(callee).contains(" Load ") : text;
+
+ N alloc=new N(12,"New",Kind.MULTI,caller), ptr=new N(13,"Ptr",Kind.PROJ,alloc);
+ String scheduled=printer.scheduled(new ArrayList<>(Arrays.asList(caller,ret1)));
+ assert row(scheduled,"Ptr")>row(scheduled,"New") : scheduled;
+ }
+
+ static void assembly() {
+ N fun=new N(1,"Fun",Kind.FUN), op=new N(2,"op",Kind.DATA,fun);
+ N ret=new N(3,"Return",Kind.RETURN,fun,op);
+ boolean[] encoded={true};
+ var adapter=new AssemblyAdapter<N>(new Adapter()) {
+ @Override public ArrayList<N> blocks() { return new ArrayList<>(Arrays.asList(fun,ret)); }
+ @Override public String op(N n) { return n.name; }
+ @Override public String operands(N n) { return n==op ? "\nfirst\nsecond" : ""; }
+ @Override public String register(N n) { return "r0"; }
+ @Override public boolean hidden(N n) { return n==ret; }
+ @Override public boolean encoded() { return encoded[0]; }
+ @Override public int defaultSize() { return 2; }
+ @Override public int size(N n) { return 4; }
+ @Override public int offset(N n) { return 0; }
+ @Override public byte[] bytes() { return encoded[0] ? new byte[]{1,2,3,4} : null; }
+ @Override public boolean littleEndian() { return false; }
+ };
+ ASMPrinter<N> printer=new ASMPrinter<>(adapter);
+ String asm=printer.print();
+ assert asm.equals(printer.print());
+ assert asm.contains("0201") && asm.contains("0403") && asm.contains("second") : asm;
+ encoded[0]=false;
+ asm=new ASMPrinter<>(adapter).print();
+ assert asm.contains("first") && asm.contains("second") : asm;
+ Object type=new Object();
+ var entries=new ArrayList<ASMPrinter.Data>();
+ entries.add(new ASMPrinter.Data(type,"Pair",1,2));
+ entries.add(new ASMPrinter.Data(type,"Pair",1,2));
+ String pool=ASMPrinter.pool(new ASMPrinter.Pool("Constants",new byte[]{5,6},0,16,entries));
+ assert pool.indexOf("Pair")==pool.lastIndexOf("Pair") : pool;
+ assert pool.contains("0010 0506") : pool;
+ }
+}
diff --git a/skills/chapter25-codex-notes.md b/skills/chapter25-codex-notes.md
index 041eba8f..c93266ab 100644
--- a/skills/chapter25-codex-notes.md
+++ b/skills/chapter25-codex-notes.md
@@ -648,15 +648,24 @@ Consequences:
## Side-effect-free diagnostics: B09 lessons
-- Chapter 21's pre-scheduling `CodeGen.toString()` uses a separate CFG-only
- RPO walk, then printer-local data placement. Walking CFG and data uses in
- the same DFS can move a loop's closing Region before its body via Phi
- backedges, even when CFG uses are visited first. Keep Loop/Region Phis
- contiguous with their header, without pulling their backedge definitions
- up to the header. Preserve function boundaries at Calls/Returns. This
- correction remains queued for 22-25; 25 supplied the grouping approach but
- still mixes CFG and data traversal. All printer bookkeeping uses identity
- maps and raw edges, without invoking actual scheduling or dominator queries.
+- Shared debug printing lives in `print/`; see its README for the API. All
+ chapter Nodes extend `BaseNode<Node>`, which owns the ID field, unique naming,
+ print/toString, and default expression formatting. Compiler constructors pass
+ IDs from their existing allocator to super; clone still assigns a fresh ID.
+ Simple hooks override `format()` with input slots (`%1`, `%10`, literal `%%`).
+ Custom protected `_print1` hooks use `p.p(...)`, `p.n(...)`, open/close, and
+ matching-suffix unchar. Every print tracks repeats; short constant types expand
+ repeatedly. Both IR and graph adapters consume the common indexed edge and
+ dependency accessors. Graph record/edge construction belongs in GraphAdapter;
+ chapters supply only their semantic roles, names, projections and grouping.
+- Shared IR ordering finishes CFG RPO before placing data. Walking control and
+ data uses together can move a loop's closing Region before its body via Phi
+ backedges. Keep Loop/Region Phis contiguous with their header without pulling
+ backedge definitions up. Parm inputs belong to callers; stop at function
+ boundaries, and print globally shared floating expressions once with globals.
+ All traversal/placement state uses private identity maps and raw edges, without
+ invoking scheduling or dominator queries. Machine hooks must format correctly
+ into an initially empty buffer; multiline expansions are laid out centrally.
- `Node._inputs` remains allocated after `kill()`. Use `isDead()` when printing
or filtering dead nodes; an empty input array alone does not imply death.
@@ -673,7 +682,7 @@ Consequences:
display that recorded layout instead of asking Types to compute one.
- Use the `_` prefix for no-side-effect variants of accessors: `CodeGen._link`,
`RegAlloc._lrg`, `Var._type`, and the existing leaf `_isConstant` predicates.
- The printer's local `_idepth` does not populate compiler dominator caches.
+ Shared printer placement must not populate compiler dominator caches.
Keep mutating compiler accessors available for their normal jobs.
- Audit the whole call chain from `Node.p(depth)`, `print`/`toString`, labels,
scope/graph viewers, and machine `asm` methods. `link` prunes dead functions
diff --git a/skills/graph-viewer-codex-notes.md b/skills/graph-viewer-codex-notes.md
index 5b06bd6a..e4775e91 100644
--- a/skills/graph-viewer-codex-notes.md
+++ b/skills/graph-viewer-codex-notes.md
@@ -51,6 +51,14 @@ chapter25 Chapter13Test (16). This was NOT an all-chapter full test-suite run.
## Durable design and owner preferences
+- Printer/viewer consolidation: all chapters' Node classes now extend
+ `com.seaofnodes.print.BaseNode<Node>`. GraphAdapter reads identity, raw indexed
+ edges, dependencies, labels, deadness and type text from that common contract.
+ It constructs node/edge records centrally. Chapter adapters retain semantic
+ kind/role rules, scope binding names, projection indices, call jumps and folding
+ state. The graph IDEA module depends on print; both Make source sets are already
+ compiled together. Browser protocol and grouping algorithms are unchanged.
+
- Shared Java capture/model and browser code live in graph/. Each chapter keeps
a small SimpleGraphAdapter and SimpleGraphObserver, plus compiler callbacks.
No Maven requirement. DOT compiler/viewer support is gone; existing docs GV/SVG