From 5ea32e69433d0c850d02bbc1e6c4a260bc095fec Mon Sep 17 00:00:00 2001 From: Cliff Click Date: Thu, 1 Oct 2026 12:01:57 -0700 Subject: Move debug printing into shared space Same as the graph viewer, moves a lot of code out of all Nodes --- .github/workflows/linearize.sh | 4 +- .gitignore | 1 + Makefile | 5 + README.md | 5 + build-support/early-chapter.mk | 1 + chapter01/pom.xml | 1 + .../com/seaofnodes/simple/node/ConstantNode.java | 4 + .../main/java/com/seaofnodes/simple/node/Node.java | 18 +- .../simple/print/SimpleGraphAdapter.java | 28 +- chapter02/pom.xml | 1 + .../java/com/seaofnodes/simple/node/AddNode.java | 8 +- .../com/seaofnodes/simple/node/ConstantNode.java | 15 +- .../java/com/seaofnodes/simple/node/DivNode.java | 8 +- .../java/com/seaofnodes/simple/node/MinusNode.java | 7 +- .../java/com/seaofnodes/simple/node/MulNode.java | 8 +- .../main/java/com/seaofnodes/simple/node/Node.java | 56 +-- .../com/seaofnodes/simple/node/ReturnNode.java | 6 +- .../java/com/seaofnodes/simple/node/StartNode.java | 7 +- .../simple/print/SimpleGraphAdapter.java | 28 +- chapter03/pom.xml | 1 + .../java/com/seaofnodes/simple/node/AddNode.java | 8 +- .../com/seaofnodes/simple/node/ConstantNode.java | 15 +- .../java/com/seaofnodes/simple/node/DivNode.java | 8 +- .../java/com/seaofnodes/simple/node/MinusNode.java | 7 +- .../java/com/seaofnodes/simple/node/MulNode.java | 8 +- .../main/java/com/seaofnodes/simple/node/Node.java | 56 +-- .../com/seaofnodes/simple/node/ReturnNode.java | 6 +- .../java/com/seaofnodes/simple/node/ScopeNode.java | 20 +- .../java/com/seaofnodes/simple/node/StartNode.java | 7 +- .../java/com/seaofnodes/simple/node/SubNode.java | 8 +- .../simple/print/SimpleGraphAdapter.java | 29 +- chapter04/Makefile | 3 +- chapter04/pom.xml | 1 + .../java/com/seaofnodes/simple/node/AddNode.java | 8 +- .../java/com/seaofnodes/simple/node/BoolNode.java | 9 +- .../com/seaofnodes/simple/node/ConstantNode.java | 15 +- .../java/com/seaofnodes/simple/node/DivNode.java | 8 +- .../java/com/seaofnodes/simple/node/MinusNode.java | 7 +- .../java/com/seaofnodes/simple/node/MulNode.java | 8 +- .../main/java/com/seaofnodes/simple/node/Node.java | 48 +- .../java/com/seaofnodes/simple/node/NotNode.java | 7 +- .../java/com/seaofnodes/simple/node/ProjNode.java | 4 +- .../com/seaofnodes/simple/node/ReturnNode.java | 6 +- .../java/com/seaofnodes/simple/node/ScopeNode.java | 20 +- .../java/com/seaofnodes/simple/node/StartNode.java | 7 +- .../java/com/seaofnodes/simple/node/SubNode.java | 8 +- .../simple/print/SimpleGraphAdapter.java | 33 +- chapter05/pom.xml | 1 + .../java/com/seaofnodes/simple/node/AddNode.java | 8 +- .../java/com/seaofnodes/simple/node/BoolNode.java | 9 +- .../com/seaofnodes/simple/node/ConstantNode.java | 15 +- .../java/com/seaofnodes/simple/node/DivNode.java | 8 +- .../java/com/seaofnodes/simple/node/IfNode.java | 7 +- .../java/com/seaofnodes/simple/node/MinusNode.java | 7 +- .../java/com/seaofnodes/simple/node/MulNode.java | 8 +- .../main/java/com/seaofnodes/simple/node/Node.java | 48 +- .../java/com/seaofnodes/simple/node/NotNode.java | 7 +- .../java/com/seaofnodes/simple/node/PhiNode.java | 12 +- .../java/com/seaofnodes/simple/node/ProjNode.java | 4 +- .../com/seaofnodes/simple/node/RegionNode.java | 7 +- .../com/seaofnodes/simple/node/ReturnNode.java | 6 +- .../java/com/seaofnodes/simple/node/ScopeNode.java | 20 +- .../java/com/seaofnodes/simple/node/StartNode.java | 7 +- .../java/com/seaofnodes/simple/node/StopNode.java | 12 +- .../java/com/seaofnodes/simple/node/SubNode.java | 8 +- .../simple/print/SimpleGraphAdapter.java | 30 +- .../java/com/seaofnodes/simple/Chapter05Test.java | 2 +- chapter06/Makefile | 3 +- chapter06/pom.xml | 1 + .../java/com/seaofnodes/simple/node/AddNode.java | 8 +- .../java/com/seaofnodes/simple/node/BoolNode.java | 9 +- .../com/seaofnodes/simple/node/ConstantNode.java | 15 +- .../java/com/seaofnodes/simple/node/DivNode.java | 8 +- .../java/com/seaofnodes/simple/node/IfNode.java | 7 +- .../java/com/seaofnodes/simple/node/MinusNode.java | 7 +- .../java/com/seaofnodes/simple/node/MulNode.java | 8 +- .../main/java/com/seaofnodes/simple/node/Node.java | 50 +- .../java/com/seaofnodes/simple/node/NotNode.java | 7 +- .../java/com/seaofnodes/simple/node/PhiNode.java | 12 +- .../java/com/seaofnodes/simple/node/ProjNode.java | 4 +- .../com/seaofnodes/simple/node/RegionNode.java | 7 +- .../com/seaofnodes/simple/node/ReturnNode.java | 6 +- .../java/com/seaofnodes/simple/node/ScopeNode.java | 20 +- .../java/com/seaofnodes/simple/node/StartNode.java | 7 +- .../java/com/seaofnodes/simple/node/StopNode.java | 12 +- .../java/com/seaofnodes/simple/node/SubNode.java | 8 +- .../simple/print/SimpleGraphAdapter.java | 30 +- .../java/com/seaofnodes/simple/Chapter05Test.java | 2 +- .../java/com/seaofnodes/simple/Chapter06Test.java | 2 +- chapter07/Makefile | 3 +- chapter07/pom.xml | 1 + .../main/java/com/seaofnodes/simple/IRPrinter.java | 124 ----- .../java/com/seaofnodes/simple/node/AddNode.java | 9 +- .../java/com/seaofnodes/simple/node/BoolNode.java | 10 +- .../com/seaofnodes/simple/node/ConstantNode.java | 16 +- .../java/com/seaofnodes/simple/node/DivNode.java | 9 +- .../java/com/seaofnodes/simple/node/IfNode.java | 8 +- .../java/com/seaofnodes/simple/node/MinusNode.java | 8 +- .../java/com/seaofnodes/simple/node/MulNode.java | 9 +- .../main/java/com/seaofnodes/simple/node/Node.java | 80 +-- .../java/com/seaofnodes/simple/node/NotNode.java | 8 +- .../java/com/seaofnodes/simple/node/PhiNode.java | 19 +- .../java/com/seaofnodes/simple/node/ProjNode.java | 5 +- .../com/seaofnodes/simple/node/RegionNode.java | 8 +- .../com/seaofnodes/simple/node/ReturnNode.java | 7 +- .../java/com/seaofnodes/simple/node/ScopeNode.java | 13 +- .../java/com/seaofnodes/simple/node/StartNode.java | 8 +- .../java/com/seaofnodes/simple/node/StopNode.java | 13 +- .../java/com/seaofnodes/simple/node/SubNode.java | 9 +- .../simple/print/SimpleGraphAdapter.java | 30 +- chapter08/Makefile | 3 +- chapter08/pom.xml | 1 + .../main/java/com/seaofnodes/simple/IRPrinter.java | 141 +----- .../java/com/seaofnodes/simple/node/AddNode.java | 9 +- .../java/com/seaofnodes/simple/node/BoolNode.java | 10 +- .../com/seaofnodes/simple/node/ConstantNode.java | 16 +- .../java/com/seaofnodes/simple/node/DivNode.java | 9 +- .../java/com/seaofnodes/simple/node/IfNode.java | 8 +- .../java/com/seaofnodes/simple/node/MinusNode.java | 8 +- .../java/com/seaofnodes/simple/node/MulNode.java | 9 +- .../main/java/com/seaofnodes/simple/node/Node.java | 83 +-- .../java/com/seaofnodes/simple/node/NotNode.java | 8 +- .../java/com/seaofnodes/simple/node/PhiNode.java | 19 +- .../java/com/seaofnodes/simple/node/ProjNode.java | 5 +- .../com/seaofnodes/simple/node/RegionNode.java | 8 +- .../com/seaofnodes/simple/node/ReturnNode.java | 7 +- .../java/com/seaofnodes/simple/node/ScopeNode.java | 15 +- .../java/com/seaofnodes/simple/node/StartNode.java | 8 +- .../java/com/seaofnodes/simple/node/StopNode.java | 13 +- .../java/com/seaofnodes/simple/node/SubNode.java | 9 +- .../simple/print/SimpleGraphAdapter.java | 30 +- chapter09/Makefile | 3 +- chapter09/pom.xml | 1 + .../main/java/com/seaofnodes/simple/IRPrinter.java | 142 +----- .../java/com/seaofnodes/simple/node/AddNode.java | 9 +- .../java/com/seaofnodes/simple/node/BoolNode.java | 10 +- .../com/seaofnodes/simple/node/ConstantNode.java | 16 +- .../java/com/seaofnodes/simple/node/DivNode.java | 9 +- .../java/com/seaofnodes/simple/node/IfNode.java | 8 +- .../java/com/seaofnodes/simple/node/MinusNode.java | 8 +- .../java/com/seaofnodes/simple/node/MulNode.java | 9 +- .../main/java/com/seaofnodes/simple/node/Node.java | 87 +--- .../java/com/seaofnodes/simple/node/NotNode.java | 8 +- .../java/com/seaofnodes/simple/node/PhiNode.java | 19 +- .../java/com/seaofnodes/simple/node/ProjNode.java | 5 +- .../com/seaofnodes/simple/node/RegionNode.java | 8 +- .../com/seaofnodes/simple/node/ReturnNode.java | 7 +- .../java/com/seaofnodes/simple/node/ScopeNode.java | 15 +- .../java/com/seaofnodes/simple/node/StartNode.java | 8 +- .../java/com/seaofnodes/simple/node/StopNode.java | 13 +- .../java/com/seaofnodes/simple/node/SubNode.java | 9 +- .../simple/print/SimpleGraphAdapter.java | 32 +- chapter10a/chapter10a.iml | 1 + chapter10a/pom.xml | 1 + .../main/java/com/seaofnodes/simple/IRPrinter.java | 213 ++------ .../java/com/seaofnodes/simple/node/AddNode.java | 9 +- .../java/com/seaofnodes/simple/node/BoolNode.java | 10 +- .../java/com/seaofnodes/simple/node/CastNode.java | 10 +- .../com/seaofnodes/simple/node/ConstantNode.java | 16 +- .../java/com/seaofnodes/simple/node/DivNode.java | 9 +- .../java/com/seaofnodes/simple/node/IfNode.java | 8 +- .../java/com/seaofnodes/simple/node/LoadNode.java | 5 +- .../java/com/seaofnodes/simple/node/MinusNode.java | 8 +- .../java/com/seaofnodes/simple/node/MulNode.java | 9 +- .../java/com/seaofnodes/simple/node/NewNode.java | 9 +- .../main/java/com/seaofnodes/simple/node/Node.java | 65 +-- .../java/com/seaofnodes/simple/node/NotNode.java | 8 +- .../java/com/seaofnodes/simple/node/PhiNode.java | 19 +- .../java/com/seaofnodes/simple/node/ProjNode.java | 5 +- .../com/seaofnodes/simple/node/RegionNode.java | 8 +- .../com/seaofnodes/simple/node/ReturnNode.java | 11 +- .../java/com/seaofnodes/simple/node/ScopeNode.java | 15 +- .../java/com/seaofnodes/simple/node/StartNode.java | 8 +- .../java/com/seaofnodes/simple/node/StopNode.java | 13 +- .../java/com/seaofnodes/simple/node/StoreNode.java | 7 +- .../java/com/seaofnodes/simple/node/SubNode.java | 9 +- .../simple/print/SimpleGraphAdapter.java | 32 +- chapter10b/chapter10b.iml | 1 + chapter10b/pom.xml | 1 + .../main/java/com/seaofnodes/simple/IRPrinter.java | 214 ++------ .../java/com/seaofnodes/simple/node/AddNode.java | 9 +- .../java/com/seaofnodes/simple/node/BoolNode.java | 10 +- .../java/com/seaofnodes/simple/node/CastNode.java | 10 +- .../com/seaofnodes/simple/node/ConstantNode.java | 16 +- .../java/com/seaofnodes/simple/node/DivNode.java | 9 +- .../java/com/seaofnodes/simple/node/IfNode.java | 8 +- .../java/com/seaofnodes/simple/node/LoadNode.java | 5 +- .../com/seaofnodes/simple/node/MemMergeNode.java | 13 +- .../java/com/seaofnodes/simple/node/MinusNode.java | 8 +- .../java/com/seaofnodes/simple/node/MulNode.java | 9 +- .../java/com/seaofnodes/simple/node/NewNode.java | 9 +- .../main/java/com/seaofnodes/simple/node/Node.java | 65 +-- .../java/com/seaofnodes/simple/node/NotNode.java | 8 +- .../java/com/seaofnodes/simple/node/PhiNode.java | 19 +- .../java/com/seaofnodes/simple/node/ProjNode.java | 5 +- .../com/seaofnodes/simple/node/RegionNode.java | 8 +- .../com/seaofnodes/simple/node/ReturnNode.java | 11 +- .../java/com/seaofnodes/simple/node/ScopeNode.java | 15 +- .../java/com/seaofnodes/simple/node/StartNode.java | 8 +- .../java/com/seaofnodes/simple/node/StopNode.java | 13 +- .../java/com/seaofnodes/simple/node/StoreNode.java | 7 +- .../java/com/seaofnodes/simple/node/SubNode.java | 9 +- .../simple/print/SimpleGraphAdapter.java | 32 +- chapter11/Makefile | 3 +- chapter11/pom.xml | 1 + .../main/java/com/seaofnodes/simple/IRPrinter.java | 311 ++---------- .../java/com/seaofnodes/simple/node/AddNode.java | 9 +- .../java/com/seaofnodes/simple/node/BoolNode.java | 10 +- .../java/com/seaofnodes/simple/node/CProjNode.java | 5 +- .../java/com/seaofnodes/simple/node/CastNode.java | 10 +- .../com/seaofnodes/simple/node/ConstantNode.java | 16 +- .../java/com/seaofnodes/simple/node/DivNode.java | 9 +- .../java/com/seaofnodes/simple/node/IfNode.java | 7 +- .../java/com/seaofnodes/simple/node/LoadNode.java | 5 +- .../com/seaofnodes/simple/node/MemMergeNode.java | 13 +- .../java/com/seaofnodes/simple/node/MinusNode.java | 8 +- .../java/com/seaofnodes/simple/node/MulNode.java | 9 +- .../java/com/seaofnodes/simple/node/NeverNode.java | 5 +- .../java/com/seaofnodes/simple/node/NewNode.java | 9 +- .../main/java/com/seaofnodes/simple/node/Node.java | 63 +-- .../java/com/seaofnodes/simple/node/NotNode.java | 8 +- .../java/com/seaofnodes/simple/node/PhiNode.java | 19 +- .../java/com/seaofnodes/simple/node/ProjNode.java | 5 +- .../com/seaofnodes/simple/node/RegionNode.java | 7 +- .../com/seaofnodes/simple/node/ReturnNode.java | 11 +- .../java/com/seaofnodes/simple/node/ScopeNode.java | 15 +- .../java/com/seaofnodes/simple/node/StartNode.java | 7 +- .../java/com/seaofnodes/simple/node/StopNode.java | 13 +- .../java/com/seaofnodes/simple/node/StoreNode.java | 7 +- .../java/com/seaofnodes/simple/node/SubNode.java | 9 +- .../java/com/seaofnodes/simple/node/XCtrlNode.java | 5 +- .../simple/print/SimpleGraphAdapter.java | 33 +- chapter12/Makefile | 3 +- chapter12/pom.xml | 1 + .../main/java/com/seaofnodes/simple/IRPrinter.java | 311 ++---------- .../java/com/seaofnodes/simple/node/AddFNode.java | 9 +- .../java/com/seaofnodes/simple/node/AddNode.java | 9 +- .../java/com/seaofnodes/simple/node/BoolNode.java | 10 +- .../java/com/seaofnodes/simple/node/CProjNode.java | 5 +- .../java/com/seaofnodes/simple/node/CastNode.java | 10 +- .../com/seaofnodes/simple/node/ConstantNode.java | 16 +- .../java/com/seaofnodes/simple/node/DivFNode.java | 9 +- .../java/com/seaofnodes/simple/node/DivNode.java | 9 +- .../java/com/seaofnodes/simple/node/IfNode.java | 7 +- .../java/com/seaofnodes/simple/node/LoadNode.java | 5 +- .../com/seaofnodes/simple/node/MemMergeNode.java | 13 +- .../com/seaofnodes/simple/node/MinusFNode.java | 8 +- .../java/com/seaofnodes/simple/node/MinusNode.java | 8 +- .../java/com/seaofnodes/simple/node/MulFNode.java | 9 +- .../java/com/seaofnodes/simple/node/MulNode.java | 9 +- .../java/com/seaofnodes/simple/node/NeverNode.java | 5 +- .../java/com/seaofnodes/simple/node/NewNode.java | 9 +- .../main/java/com/seaofnodes/simple/node/Node.java | 64 +-- .../java/com/seaofnodes/simple/node/NotNode.java | 8 +- .../java/com/seaofnodes/simple/node/PhiNode.java | 19 +- .../java/com/seaofnodes/simple/node/ProjNode.java | 5 +- .../com/seaofnodes/simple/node/RegionNode.java | 7 +- .../com/seaofnodes/simple/node/ReturnNode.java | 11 +- .../java/com/seaofnodes/simple/node/ScopeNode.java | 15 +- .../java/com/seaofnodes/simple/node/StartNode.java | 7 +- .../java/com/seaofnodes/simple/node/StopNode.java | 13 +- .../java/com/seaofnodes/simple/node/StoreNode.java | 7 +- .../java/com/seaofnodes/simple/node/SubFNode.java | 9 +- .../java/com/seaofnodes/simple/node/SubNode.java | 9 +- .../com/seaofnodes/simple/node/ToFloatNode.java | 7 +- .../java/com/seaofnodes/simple/node/XCtrlNode.java | 5 +- .../simple/print/SimpleGraphAdapter.java | 33 +- chapter13/Makefile | 3 +- chapter13/pom.xml | 1 + .../main/java/com/seaofnodes/simple/IRPrinter.java | 311 ++---------- .../java/com/seaofnodes/simple/node/AddFNode.java | 9 +- .../java/com/seaofnodes/simple/node/AddNode.java | 9 +- .../java/com/seaofnodes/simple/node/BoolNode.java | 10 +- .../java/com/seaofnodes/simple/node/CProjNode.java | 5 +- .../java/com/seaofnodes/simple/node/CastNode.java | 10 +- .../com/seaofnodes/simple/node/ConstantNode.java | 16 +- .../java/com/seaofnodes/simple/node/DivFNode.java | 9 +- .../java/com/seaofnodes/simple/node/DivNode.java | 9 +- .../java/com/seaofnodes/simple/node/IfNode.java | 7 +- .../java/com/seaofnodes/simple/node/LoadNode.java | 5 +- .../com/seaofnodes/simple/node/MemMergeNode.java | 13 +- .../com/seaofnodes/simple/node/MinusFNode.java | 8 +- .../java/com/seaofnodes/simple/node/MinusNode.java | 8 +- .../java/com/seaofnodes/simple/node/MulFNode.java | 9 +- .../java/com/seaofnodes/simple/node/MulNode.java | 9 +- .../java/com/seaofnodes/simple/node/NeverNode.java | 5 +- .../java/com/seaofnodes/simple/node/NewNode.java | 9 +- .../main/java/com/seaofnodes/simple/node/Node.java | 64 +-- .../java/com/seaofnodes/simple/node/NotNode.java | 8 +- .../java/com/seaofnodes/simple/node/PhiNode.java | 19 +- .../java/com/seaofnodes/simple/node/ProjNode.java | 5 +- .../com/seaofnodes/simple/node/RegionNode.java | 7 +- .../com/seaofnodes/simple/node/ReturnNode.java | 11 +- .../java/com/seaofnodes/simple/node/ScopeNode.java | 15 +- .../java/com/seaofnodes/simple/node/StartNode.java | 7 +- .../java/com/seaofnodes/simple/node/StopNode.java | 13 +- .../java/com/seaofnodes/simple/node/StoreNode.java | 7 +- .../java/com/seaofnodes/simple/node/SubFNode.java | 9 +- .../java/com/seaofnodes/simple/node/SubNode.java | 9 +- .../com/seaofnodes/simple/node/ToFloatNode.java | 7 +- .../java/com/seaofnodes/simple/node/XCtrlNode.java | 5 +- .../simple/print/SimpleGraphAdapter.java | 33 +- chapter14/Makefile | 3 +- chapter14/pom.xml | 1 + .../main/java/com/seaofnodes/simple/IRPrinter.java | 311 ++---------- .../java/com/seaofnodes/simple/node/AddFNode.java | 9 +- .../java/com/seaofnodes/simple/node/AddNode.java | 9 +- .../java/com/seaofnodes/simple/node/AndNode.java | 9 +- .../java/com/seaofnodes/simple/node/BoolNode.java | 10 +- .../java/com/seaofnodes/simple/node/CProjNode.java | 5 +- .../java/com/seaofnodes/simple/node/CastNode.java | 10 +- .../com/seaofnodes/simple/node/ConstantNode.java | 16 +- .../java/com/seaofnodes/simple/node/DivFNode.java | 9 +- .../java/com/seaofnodes/simple/node/DivNode.java | 9 +- .../java/com/seaofnodes/simple/node/IfNode.java | 7 +- .../java/com/seaofnodes/simple/node/LoadNode.java | 5 +- .../com/seaofnodes/simple/node/MemMergeNode.java | 13 +- .../com/seaofnodes/simple/node/MinusFNode.java | 8 +- .../java/com/seaofnodes/simple/node/MinusNode.java | 8 +- .../java/com/seaofnodes/simple/node/MulFNode.java | 9 +- .../java/com/seaofnodes/simple/node/MulNode.java | 9 +- .../java/com/seaofnodes/simple/node/NeverNode.java | 5 +- .../java/com/seaofnodes/simple/node/NewNode.java | 9 +- .../main/java/com/seaofnodes/simple/node/Node.java | 62 +-- .../java/com/seaofnodes/simple/node/NotNode.java | 8 +- .../java/com/seaofnodes/simple/node/OrNode.java | 9 +- .../java/com/seaofnodes/simple/node/PhiNode.java | 19 +- .../java/com/seaofnodes/simple/node/ProjNode.java | 5 +- .../com/seaofnodes/simple/node/RegionNode.java | 7 +- .../com/seaofnodes/simple/node/ReturnNode.java | 11 +- .../com/seaofnodes/simple/node/RoundF32Node.java | 7 +- .../java/com/seaofnodes/simple/node/SarNode.java | 9 +- .../java/com/seaofnodes/simple/node/ScopeNode.java | 15 +- .../java/com/seaofnodes/simple/node/ShlNode.java | 9 +- .../java/com/seaofnodes/simple/node/ShrNode.java | 9 +- .../java/com/seaofnodes/simple/node/StartNode.java | 7 +- .../java/com/seaofnodes/simple/node/StopNode.java | 13 +- .../java/com/seaofnodes/simple/node/StoreNode.java | 7 +- .../java/com/seaofnodes/simple/node/SubFNode.java | 9 +- .../java/com/seaofnodes/simple/node/SubNode.java | 9 +- .../com/seaofnodes/simple/node/ToFloatNode.java | 7 +- .../java/com/seaofnodes/simple/node/XCtrlNode.java | 5 +- .../java/com/seaofnodes/simple/node/XorNode.java | 9 +- .../simple/print/SimpleGraphAdapter.java | 33 +- chapter15/Makefile | 3 +- chapter15/pom.xml | 1 + .../main/java/com/seaofnodes/simple/IRPrinter.java | 329 ++---------- .../java/com/seaofnodes/simple/node/AddFNode.java | 9 +- .../java/com/seaofnodes/simple/node/AddNode.java | 9 +- .../java/com/seaofnodes/simple/node/AndNode.java | 9 +- .../java/com/seaofnodes/simple/node/BoolNode.java | 10 +- .../java/com/seaofnodes/simple/node/CProjNode.java | 5 +- .../java/com/seaofnodes/simple/node/CastNode.java | 10 +- .../com/seaofnodes/simple/node/ConstantNode.java | 16 +- .../java/com/seaofnodes/simple/node/DivFNode.java | 9 +- .../java/com/seaofnodes/simple/node/DivNode.java | 9 +- .../java/com/seaofnodes/simple/node/IfNode.java | 7 +- .../java/com/seaofnodes/simple/node/LoadNode.java | 4 +- .../com/seaofnodes/simple/node/MemMergeNode.java | 13 +- .../com/seaofnodes/simple/node/MinusFNode.java | 8 +- .../java/com/seaofnodes/simple/node/MinusNode.java | 8 +- .../java/com/seaofnodes/simple/node/MulFNode.java | 9 +- .../java/com/seaofnodes/simple/node/MulNode.java | 9 +- .../java/com/seaofnodes/simple/node/NeverNode.java | 5 +- .../java/com/seaofnodes/simple/node/NewNode.java | 9 +- .../main/java/com/seaofnodes/simple/node/Node.java | 61 +-- .../java/com/seaofnodes/simple/node/NotNode.java | 8 +- .../java/com/seaofnodes/simple/node/OrNode.java | 9 +- .../java/com/seaofnodes/simple/node/PhiNode.java | 19 +- .../java/com/seaofnodes/simple/node/ProjNode.java | 5 +- .../com/seaofnodes/simple/node/RegionNode.java | 7 +- .../com/seaofnodes/simple/node/ReturnNode.java | 11 +- .../com/seaofnodes/simple/node/RoundF32Node.java | 7 +- .../java/com/seaofnodes/simple/node/SarNode.java | 9 +- .../java/com/seaofnodes/simple/node/ScopeNode.java | 15 +- .../java/com/seaofnodes/simple/node/ShlNode.java | 9 +- .../java/com/seaofnodes/simple/node/ShrNode.java | 9 +- .../java/com/seaofnodes/simple/node/StartNode.java | 7 +- .../java/com/seaofnodes/simple/node/StopNode.java | 13 +- .../java/com/seaofnodes/simple/node/StoreNode.java | 7 +- .../java/com/seaofnodes/simple/node/SubFNode.java | 9 +- .../java/com/seaofnodes/simple/node/SubNode.java | 9 +- .../com/seaofnodes/simple/node/ToFloatNode.java | 7 +- .../java/com/seaofnodes/simple/node/XCtrlNode.java | 5 +- .../java/com/seaofnodes/simple/node/XorNode.java | 9 +- .../simple/print/SimpleGraphAdapter.java | 33 +- chapter16/Makefile | 3 +- chapter16/pom.xml | 1 + .../main/java/com/seaofnodes/simple/IRPrinter.java | 329 ++---------- .../java/com/seaofnodes/simple/node/AddFNode.java | 9 +- .../java/com/seaofnodes/simple/node/AddNode.java | 9 +- .../java/com/seaofnodes/simple/node/AndNode.java | 9 +- .../java/com/seaofnodes/simple/node/BoolNode.java | 10 +- .../java/com/seaofnodes/simple/node/CProjNode.java | 5 +- .../java/com/seaofnodes/simple/node/CastNode.java | 10 +- .../com/seaofnodes/simple/node/ConstantNode.java | 16 +- .../java/com/seaofnodes/simple/node/DivFNode.java | 9 +- .../java/com/seaofnodes/simple/node/DivNode.java | 9 +- .../java/com/seaofnodes/simple/node/IfNode.java | 7 +- .../java/com/seaofnodes/simple/node/LoadNode.java | 4 +- .../com/seaofnodes/simple/node/MemMergeNode.java | 13 +- .../com/seaofnodes/simple/node/MinusFNode.java | 8 +- .../java/com/seaofnodes/simple/node/MinusNode.java | 8 +- .../java/com/seaofnodes/simple/node/MulFNode.java | 9 +- .../java/com/seaofnodes/simple/node/MulNode.java | 9 +- .../java/com/seaofnodes/simple/node/NeverNode.java | 5 +- .../java/com/seaofnodes/simple/node/NewNode.java | 9 +- .../main/java/com/seaofnodes/simple/node/Node.java | 62 +-- .../java/com/seaofnodes/simple/node/NotNode.java | 8 +- .../java/com/seaofnodes/simple/node/OrNode.java | 9 +- .../java/com/seaofnodes/simple/node/PhiNode.java | 19 +- .../java/com/seaofnodes/simple/node/ProjNode.java | 5 +- .../com/seaofnodes/simple/node/RegionNode.java | 7 +- .../com/seaofnodes/simple/node/ReturnNode.java | 11 +- .../com/seaofnodes/simple/node/RoundF32Node.java | 7 +- .../java/com/seaofnodes/simple/node/SarNode.java | 9 +- .../java/com/seaofnodes/simple/node/ScopeNode.java | 28 +- .../java/com/seaofnodes/simple/node/ShlNode.java | 9 +- .../java/com/seaofnodes/simple/node/ShrNode.java | 9 +- .../java/com/seaofnodes/simple/node/StartNode.java | 7 +- .../java/com/seaofnodes/simple/node/StopNode.java | 13 +- .../java/com/seaofnodes/simple/node/StoreNode.java | 7 +- .../com/seaofnodes/simple/node/StructNode.java | 18 +- .../java/com/seaofnodes/simple/node/SubFNode.java | 9 +- .../java/com/seaofnodes/simple/node/SubNode.java | 9 +- .../com/seaofnodes/simple/node/ToFloatNode.java | 7 +- .../java/com/seaofnodes/simple/node/XCtrlNode.java | 5 +- .../java/com/seaofnodes/simple/node/XorNode.java | 9 +- .../simple/print/SimpleGraphAdapter.java | 32 +- chapter17/Makefile | 3 +- chapter17/pom.xml | 1 + .../main/java/com/seaofnodes/simple/IRPrinter.java | 330 ++---------- .../java/com/seaofnodes/simple/node/AddFNode.java | 9 +- .../java/com/seaofnodes/simple/node/AddNode.java | 9 +- .../java/com/seaofnodes/simple/node/AndNode.java | 9 +- .../java/com/seaofnodes/simple/node/BoolNode.java | 10 +- .../java/com/seaofnodes/simple/node/CProjNode.java | 5 +- .../java/com/seaofnodes/simple/node/CastNode.java | 10 +- .../com/seaofnodes/simple/node/ConstantNode.java | 16 +- .../java/com/seaofnodes/simple/node/DivFNode.java | 9 +- .../java/com/seaofnodes/simple/node/DivNode.java | 9 +- .../java/com/seaofnodes/simple/node/IfNode.java | 8 +- .../java/com/seaofnodes/simple/node/LoadNode.java | 4 +- .../com/seaofnodes/simple/node/MemMergeNode.java | 13 +- .../com/seaofnodes/simple/node/MinusFNode.java | 8 +- .../java/com/seaofnodes/simple/node/MinusNode.java | 8 +- .../java/com/seaofnodes/simple/node/MulFNode.java | 9 +- .../java/com/seaofnodes/simple/node/MulNode.java | 9 +- .../java/com/seaofnodes/simple/node/NeverNode.java | 5 +- .../java/com/seaofnodes/simple/node/NewNode.java | 9 +- .../main/java/com/seaofnodes/simple/node/Node.java | 62 +-- .../java/com/seaofnodes/simple/node/NotNode.java | 8 +- .../java/com/seaofnodes/simple/node/OrNode.java | 9 +- .../java/com/seaofnodes/simple/node/PhiNode.java | 19 +- .../java/com/seaofnodes/simple/node/ProjNode.java | 5 +- .../com/seaofnodes/simple/node/ReadOnlyNode.java | 7 +- .../com/seaofnodes/simple/node/RegionNode.java | 8 +- .../com/seaofnodes/simple/node/ReturnNode.java | 11 +- .../com/seaofnodes/simple/node/RoundF32Node.java | 7 +- .../java/com/seaofnodes/simple/node/SarNode.java | 9 +- .../java/com/seaofnodes/simple/node/ScopeNode.java | 28 +- .../java/com/seaofnodes/simple/node/ShlNode.java | 9 +- .../java/com/seaofnodes/simple/node/ShrNode.java | 9 +- .../java/com/seaofnodes/simple/node/StartNode.java | 8 +- .../java/com/seaofnodes/simple/node/StopNode.java | 13 +- .../java/com/seaofnodes/simple/node/StoreNode.java | 7 +- .../com/seaofnodes/simple/node/StructNode.java | 18 +- .../java/com/seaofnodes/simple/node/SubFNode.java | 9 +- .../java/com/seaofnodes/simple/node/SubNode.java | 9 +- .../com/seaofnodes/simple/node/ToFloatNode.java | 7 +- .../java/com/seaofnodes/simple/node/XCtrlNode.java | 5 +- .../java/com/seaofnodes/simple/node/XorNode.java | 9 +- .../simple/print/SimpleGraphAdapter.java | 32 +- chapter18/Makefile | 3 +- chapter18/pom.xml | 1 + .../main/java/com/seaofnodes/simple/CodeGen.java | 2 +- .../main/java/com/seaofnodes/simple/IRPrinter.java | 343 ++----------- .../java/com/seaofnodes/simple/node/AddFNode.java | 9 +- .../java/com/seaofnodes/simple/node/AddNode.java | 9 +- .../java/com/seaofnodes/simple/node/BoolNode.java | 10 +- .../java/com/seaofnodes/simple/node/CProjNode.java | 5 +- .../com/seaofnodes/simple/node/CallEndNode.java | 14 +- .../java/com/seaofnodes/simple/node/CallNode.java | 16 +- .../java/com/seaofnodes/simple/node/CastNode.java | 10 +- .../com/seaofnodes/simple/node/ConstantNode.java | 16 +- .../java/com/seaofnodes/simple/node/CtrlNode.java | 5 +- .../java/com/seaofnodes/simple/node/DivFNode.java | 9 +- .../java/com/seaofnodes/simple/node/DivNode.java | 9 +- .../java/com/seaofnodes/simple/node/FRefNode.java | 8 +- .../java/com/seaofnodes/simple/node/IfNode.java | 8 +- .../java/com/seaofnodes/simple/node/LoadNode.java | 4 +- .../com/seaofnodes/simple/node/LogicalNode.java | 10 +- .../com/seaofnodes/simple/node/MemMergeNode.java | 13 +- .../com/seaofnodes/simple/node/MinusFNode.java | 8 +- .../java/com/seaofnodes/simple/node/MinusNode.java | 8 +- .../java/com/seaofnodes/simple/node/MulFNode.java | 9 +- .../java/com/seaofnodes/simple/node/MulNode.java | 9 +- .../java/com/seaofnodes/simple/node/NeverNode.java | 5 +- .../java/com/seaofnodes/simple/node/NewNode.java | 9 +- .../main/java/com/seaofnodes/simple/node/Node.java | 62 +-- .../java/com/seaofnodes/simple/node/NotNode.java | 8 +- .../java/com/seaofnodes/simple/node/ParmNode.java | 19 +- .../java/com/seaofnodes/simple/node/PhiNode.java | 19 +- .../java/com/seaofnodes/simple/node/ProjNode.java | 11 +- .../com/seaofnodes/simple/node/ReadOnlyNode.java | 7 +- .../com/seaofnodes/simple/node/RegionNode.java | 8 +- .../com/seaofnodes/simple/node/ReturnNode.java | 11 +- .../com/seaofnodes/simple/node/RoundF32Node.java | 7 +- .../java/com/seaofnodes/simple/node/ScopeNode.java | 28 +- .../java/com/seaofnodes/simple/node/StartNode.java | 8 +- .../java/com/seaofnodes/simple/node/StopNode.java | 13 +- .../java/com/seaofnodes/simple/node/StoreNode.java | 7 +- .../com/seaofnodes/simple/node/StructNode.java | 18 +- .../java/com/seaofnodes/simple/node/SubFNode.java | 9 +- .../java/com/seaofnodes/simple/node/SubNode.java | 9 +- .../com/seaofnodes/simple/node/ToFloatNode.java | 7 +- .../java/com/seaofnodes/simple/node/XCtrlNode.java | 5 +- .../simple/print/SimpleGraphAdapter.java | 38 +- chapter19/Makefile | 3 +- chapter19/pom.xml | 1 + .../java/com/seaofnodes/simple/ASMPrinter.java | 173 ++----- .../main/java/com/seaofnodes/simple/CodeGen.java | 2 +- .../main/java/com/seaofnodes/simple/IRPrinter.java | 342 ++----------- .../java/com/seaofnodes/simple/node/AddFNode.java | 9 +- .../java/com/seaofnodes/simple/node/AddNode.java | 9 +- .../java/com/seaofnodes/simple/node/BoolNode.java | 10 +- .../java/com/seaofnodes/simple/node/CProjNode.java | 5 +- .../com/seaofnodes/simple/node/CallEndNode.java | 14 +- .../java/com/seaofnodes/simple/node/CallNode.java | 16 +- .../java/com/seaofnodes/simple/node/CastNode.java | 10 +- .../com/seaofnodes/simple/node/ConstantNode.java | 17 +- .../java/com/seaofnodes/simple/node/CtrlNode.java | 5 +- .../java/com/seaofnodes/simple/node/DivFNode.java | 9 +- .../java/com/seaofnodes/simple/node/DivNode.java | 9 +- .../java/com/seaofnodes/simple/node/FRefNode.java | 8 +- .../java/com/seaofnodes/simple/node/IfNode.java | 8 +- .../java/com/seaofnodes/simple/node/LoadNode.java | 5 +- .../com/seaofnodes/simple/node/LogicalNode.java | 10 +- .../seaofnodes/simple/node/MachConcreteNode.java | 12 +- .../com/seaofnodes/simple/node/MemMergeNode.java | 13 +- .../java/com/seaofnodes/simple/node/MemOpNode.java | 6 +- .../com/seaofnodes/simple/node/MinusFNode.java | 8 +- .../java/com/seaofnodes/simple/node/MinusNode.java | 8 +- .../java/com/seaofnodes/simple/node/MulFNode.java | 9 +- .../java/com/seaofnodes/simple/node/MulNode.java | 9 +- .../java/com/seaofnodes/simple/node/NeverNode.java | 5 +- .../java/com/seaofnodes/simple/node/NewNode.java | 9 +- .../main/java/com/seaofnodes/simple/node/Node.java | 67 +-- .../java/com/seaofnodes/simple/node/NotNode.java | 8 +- .../java/com/seaofnodes/simple/node/ParmNode.java | 19 +- .../java/com/seaofnodes/simple/node/PhiNode.java | 19 +- .../java/com/seaofnodes/simple/node/ProjNode.java | 11 +- .../com/seaofnodes/simple/node/ReadOnlyNode.java | 7 +- .../com/seaofnodes/simple/node/RegionNode.java | 7 +- .../com/seaofnodes/simple/node/ReturnNode.java | 11 +- .../com/seaofnodes/simple/node/RoundF32Node.java | 7 +- .../java/com/seaofnodes/simple/node/ScopeNode.java | 28 +- .../java/com/seaofnodes/simple/node/StartNode.java | 8 +- .../java/com/seaofnodes/simple/node/StopNode.java | 13 +- .../java/com/seaofnodes/simple/node/StoreNode.java | 7 +- .../com/seaofnodes/simple/node/StructNode.java | 18 +- .../java/com/seaofnodes/simple/node/SubFNode.java | 9 +- .../java/com/seaofnodes/simple/node/SubNode.java | 9 +- .../com/seaofnodes/simple/node/ToFloatNode.java | 7 +- .../java/com/seaofnodes/simple/node/XCtrlNode.java | 5 +- .../simple/node/cpus/riscv/MemOpRISC.java | 5 +- .../simple/node/cpus/x86_64_v2/MemOpX86.java | 5 +- .../simple/node/cpus/x86_64_v2/StoreX86.java | 7 +- .../simple/print/SimpleGraphAdapter.java | 38 +- chapter20/Makefile | 3 +- chapter20/pom.xml | 1 + .../com/seaofnodes/simple/codegen/CodeGen.java | 2 +- .../java/com/seaofnodes/simple/node/AddFNode.java | 9 +- .../java/com/seaofnodes/simple/node/AddNode.java | 9 +- .../java/com/seaofnodes/simple/node/BoolNode.java | 10 +- .../java/com/seaofnodes/simple/node/CProjNode.java | 5 +- .../com/seaofnodes/simple/node/CallEndNode.java | 14 +- .../java/com/seaofnodes/simple/node/CallNode.java | 16 +- .../java/com/seaofnodes/simple/node/CastNode.java | 10 +- .../com/seaofnodes/simple/node/ConstantNode.java | 17 +- .../java/com/seaofnodes/simple/node/CtrlNode.java | 5 +- .../java/com/seaofnodes/simple/node/DivFNode.java | 9 +- .../java/com/seaofnodes/simple/node/DivNode.java | 9 +- .../java/com/seaofnodes/simple/node/FRefNode.java | 8 +- .../java/com/seaofnodes/simple/node/IfNode.java | 8 +- .../java/com/seaofnodes/simple/node/LoadNode.java | 5 +- .../com/seaofnodes/simple/node/LogicalNode.java | 10 +- .../seaofnodes/simple/node/MachConcreteNode.java | 12 +- .../com/seaofnodes/simple/node/MemMergeNode.java | 12 +- .../java/com/seaofnodes/simple/node/MemOpNode.java | 6 +- .../com/seaofnodes/simple/node/MinusFNode.java | 8 +- .../java/com/seaofnodes/simple/node/MinusNode.java | 8 +- .../java/com/seaofnodes/simple/node/MulFNode.java | 9 +- .../java/com/seaofnodes/simple/node/MulNode.java | 9 +- .../java/com/seaofnodes/simple/node/NeverNode.java | 5 +- .../java/com/seaofnodes/simple/node/NewNode.java | 9 +- .../main/java/com/seaofnodes/simple/node/Node.java | 70 +-- .../java/com/seaofnodes/simple/node/NotNode.java | 8 +- .../java/com/seaofnodes/simple/node/ParmNode.java | 19 +- .../java/com/seaofnodes/simple/node/PhiNode.java | 19 +- .../java/com/seaofnodes/simple/node/ProjNode.java | 11 +- .../com/seaofnodes/simple/node/ReadOnlyNode.java | 7 +- .../com/seaofnodes/simple/node/RegionNode.java | 7 +- .../com/seaofnodes/simple/node/ReturnNode.java | 13 +- .../com/seaofnodes/simple/node/RoundF32Node.java | 7 +- .../java/com/seaofnodes/simple/node/ScopeNode.java | 28 +- .../java/com/seaofnodes/simple/node/SplitNode.java | 13 +- .../java/com/seaofnodes/simple/node/StartNode.java | 8 +- .../java/com/seaofnodes/simple/node/StopNode.java | 13 +- .../java/com/seaofnodes/simple/node/StoreNode.java | 7 +- .../com/seaofnodes/simple/node/StructNode.java | 18 +- .../java/com/seaofnodes/simple/node/SubFNode.java | 9 +- .../java/com/seaofnodes/simple/node/SubNode.java | 9 +- .../com/seaofnodes/simple/node/ToFloatNode.java | 7 +- .../java/com/seaofnodes/simple/node/XCtrlNode.java | 5 +- .../seaofnodes/simple/node/cpus/arm/CallARM.java | 2 +- .../seaofnodes/simple/node/cpus/arm/MemOpARM.java | 5 +- .../simple/node/cpus/riscv/BranchRISC.java | 13 +- .../seaofnodes/simple/node/cpus/riscv/ImmRISC.java | 8 +- .../simple/node/cpus/riscv/MemOpRISC.java | 5 +- .../simple/node/cpus/x86_64_v2/MemOpX86.java | 7 +- .../simple/node/cpus/x86_64_v2/StoreX86.java | 13 +- .../com/seaofnodes/simple/print/ASMPrinter.java | 192 ++----- .../com/seaofnodes/simple/print/IRPrinter.java | 396 ++------------- .../simple/print/SimpleGraphAdapter.java | 38 +- chapter21/Makefile | 3 +- chapter21/pom.xml | 1 + .../java/com/seaofnodes/simple/node/AddFNode.java | 9 +- .../java/com/seaofnodes/simple/node/AddNode.java | 9 +- .../java/com/seaofnodes/simple/node/BoolNode.java | 10 +- .../java/com/seaofnodes/simple/node/CProjNode.java | 5 +- .../com/seaofnodes/simple/node/CallEndNode.java | 14 +- .../java/com/seaofnodes/simple/node/CallNode.java | 16 +- .../java/com/seaofnodes/simple/node/CastNode.java | 10 +- .../com/seaofnodes/simple/node/ConstantNode.java | 17 +- .../java/com/seaofnodes/simple/node/CtrlNode.java | 5 +- .../java/com/seaofnodes/simple/node/DivFNode.java | 9 +- .../java/com/seaofnodes/simple/node/DivNode.java | 9 +- .../java/com/seaofnodes/simple/node/FRefNode.java | 8 +- .../java/com/seaofnodes/simple/node/IfNode.java | 13 +- .../java/com/seaofnodes/simple/node/LoadNode.java | 4 +- .../com/seaofnodes/simple/node/LogicalNode.java | 10 +- .../seaofnodes/simple/node/MachConcreteNode.java | 12 +- .../com/seaofnodes/simple/node/MemMergeNode.java | 12 +- .../java/com/seaofnodes/simple/node/MemOpNode.java | 6 +- .../com/seaofnodes/simple/node/MinusFNode.java | 8 +- .../java/com/seaofnodes/simple/node/MinusNode.java | 8 +- .../java/com/seaofnodes/simple/node/MulFNode.java | 9 +- .../java/com/seaofnodes/simple/node/MulNode.java | 9 +- .../java/com/seaofnodes/simple/node/NeverNode.java | 5 +- .../java/com/seaofnodes/simple/node/NewNode.java | 9 +- .../main/java/com/seaofnodes/simple/node/Node.java | 71 +-- .../java/com/seaofnodes/simple/node/NotNode.java | 8 +- .../java/com/seaofnodes/simple/node/ParmNode.java | 19 +- .../java/com/seaofnodes/simple/node/PhiNode.java | 19 +- .../java/com/seaofnodes/simple/node/ProjNode.java | 11 +- .../com/seaofnodes/simple/node/ReadOnlyNode.java | 7 +- .../com/seaofnodes/simple/node/RegionNode.java | 7 +- .../com/seaofnodes/simple/node/ReturnNode.java | 13 +- .../com/seaofnodes/simple/node/RoundF32Node.java | 7 +- .../java/com/seaofnodes/simple/node/ScopeNode.java | 28 +- .../java/com/seaofnodes/simple/node/SplitNode.java | 13 +- .../java/com/seaofnodes/simple/node/StartNode.java | 8 +- .../java/com/seaofnodes/simple/node/StopNode.java | 13 +- .../java/com/seaofnodes/simple/node/StoreNode.java | 7 +- .../com/seaofnodes/simple/node/StructNode.java | 18 +- .../java/com/seaofnodes/simple/node/SubFNode.java | 9 +- .../java/com/seaofnodes/simple/node/SubNode.java | 9 +- .../com/seaofnodes/simple/node/ToFloatNode.java | 7 +- .../java/com/seaofnodes/simple/node/XCtrlNode.java | 5 +- .../seaofnodes/simple/node/cpus/arm/CallARM.java | 2 +- .../seaofnodes/simple/node/cpus/arm/MemOpARM.java | 5 +- .../seaofnodes/simple/node/cpus/arm/UJmpARM.java | 6 +- .../simple/node/cpus/riscv/BranchRISC.java | 19 +- .../seaofnodes/simple/node/cpus/riscv/ImmRISC.java | 9 +- .../simple/node/cpus/riscv/MemOpRISC.java | 5 +- .../simple/node/cpus/riscv/UJmpRISC.java | 5 +- .../simple/node/cpus/x86_64_v2/MemOpX86.java | 7 +- .../simple/node/cpus/x86_64_v2/StoreX86.java | 13 +- .../simple/node/cpus/x86_64_v2/UJmpX86.java | 6 +- .../com/seaofnodes/simple/print/ASMPrinter.java | 342 +++---------- .../com/seaofnodes/simple/print/IRPrinter.java | 554 ++------------------- .../simple/print/SimpleGraphAdapter.java | 38 +- chapter22/Makefile | 1 + chapter22/pom.xml | 1 + .../com/seaofnodes/simple/codegen/CodeGen.java | 2 +- .../java/com/seaofnodes/simple/node/AddFNode.java | 9 +- .../java/com/seaofnodes/simple/node/ArithNode.java | 10 +- .../java/com/seaofnodes/simple/node/BoolNode.java | 10 +- .../java/com/seaofnodes/simple/node/CProjNode.java | 5 +- .../com/seaofnodes/simple/node/CallEndNode.java | 14 +- .../java/com/seaofnodes/simple/node/CallNode.java | 16 +- .../java/com/seaofnodes/simple/node/CastNode.java | 10 +- .../com/seaofnodes/simple/node/ConstantNode.java | 17 +- .../java/com/seaofnodes/simple/node/CtrlNode.java | 5 +- .../java/com/seaofnodes/simple/node/DivFNode.java | 9 +- .../com/seaofnodes/simple/node/ExternNode.java | 1 - .../java/com/seaofnodes/simple/node/FRefNode.java | 8 +- .../com/seaofnodes/simple/node/FunPtrNode.java | 1 - .../java/com/seaofnodes/simple/node/IfNode.java | 13 +- .../java/com/seaofnodes/simple/node/LoadNode.java | 4 +- .../seaofnodes/simple/node/MachConcreteNode.java | 12 +- .../com/seaofnodes/simple/node/MemMergeNode.java | 12 +- .../java/com/seaofnodes/simple/node/MemOpNode.java | 6 +- .../com/seaofnodes/simple/node/MinusFNode.java | 8 +- .../java/com/seaofnodes/simple/node/MinusNode.java | 8 +- .../java/com/seaofnodes/simple/node/MulFNode.java | 9 +- .../java/com/seaofnodes/simple/node/NeverNode.java | 5 +- .../java/com/seaofnodes/simple/node/NewNode.java | 9 +- .../main/java/com/seaofnodes/simple/node/Node.java | 71 +-- .../java/com/seaofnodes/simple/node/NotNode.java | 8 +- .../java/com/seaofnodes/simple/node/ParmNode.java | 19 +- .../java/com/seaofnodes/simple/node/PhiNode.java | 19 +- .../java/com/seaofnodes/simple/node/ProjNode.java | 11 +- .../com/seaofnodes/simple/node/ReadOnlyNode.java | 7 +- .../com/seaofnodes/simple/node/RegionNode.java | 7 +- .../com/seaofnodes/simple/node/ReturnNode.java | 13 +- .../com/seaofnodes/simple/node/RoundF32Node.java | 7 +- .../java/com/seaofnodes/simple/node/ScopeNode.java | 28 +- .../java/com/seaofnodes/simple/node/SplitNode.java | 13 +- .../java/com/seaofnodes/simple/node/StartNode.java | 8 +- .../java/com/seaofnodes/simple/node/StopNode.java | 13 +- .../java/com/seaofnodes/simple/node/StoreNode.java | 7 +- .../com/seaofnodes/simple/node/StructNode.java | 18 +- .../java/com/seaofnodes/simple/node/SubFNode.java | 9 +- .../com/seaofnodes/simple/node/ToFloatNode.java | 7 +- .../java/com/seaofnodes/simple/node/XCtrlNode.java | 5 +- .../seaofnodes/simple/node/cpus/arm/MemOpARM.java | 5 +- .../seaofnodes/simple/node/cpus/arm/UJmpARM.java | 6 +- .../simple/node/cpus/riscv/BranchRISC.java | 19 +- .../seaofnodes/simple/node/cpus/riscv/ImmRISC.java | 9 +- .../simple/node/cpus/riscv/MemOpRISC.java | 5 +- .../simple/node/cpus/riscv/UJmpRISC.java | 5 +- .../simple/node/cpus/x86_64_v2/MemOpX86.java | 7 +- .../simple/node/cpus/x86_64_v2/StoreX86.java | 13 +- .../simple/node/cpus/x86_64_v2/UJmpX86.java | 6 +- .../com/seaofnodes/simple/print/ASMPrinter.java | 359 +++---------- .../com/seaofnodes/simple/print/IRPrinter.java | 399 ++------------- .../simple/print/SimpleGraphAdapter.java | 38 +- chapter23/Makefile | 1 + chapter23/pom.xml | 1 + .../com/seaofnodes/simple/codegen/CodeGen.java | 2 +- .../java/com/seaofnodes/simple/node/AddFNode.java | 9 +- .../java/com/seaofnodes/simple/node/ArithNode.java | 10 +- .../java/com/seaofnodes/simple/node/BoolNode.java | 10 +- .../java/com/seaofnodes/simple/node/CProjNode.java | 5 +- .../com/seaofnodes/simple/node/CallEndNode.java | 14 +- .../java/com/seaofnodes/simple/node/CallNode.java | 16 +- .../java/com/seaofnodes/simple/node/CastNode.java | 10 +- .../com/seaofnodes/simple/node/ConFldOffNode.java | 9 +- .../com/seaofnodes/simple/node/ConstantNode.java | 16 +- .../java/com/seaofnodes/simple/node/CtrlNode.java | 5 +- .../java/com/seaofnodes/simple/node/DivFNode.java | 9 +- .../com/seaofnodes/simple/node/ExternNode.java | 1 - .../java/com/seaofnodes/simple/node/FRefNode.java | 8 +- .../com/seaofnodes/simple/node/FunPtrNode.java | 1 - .../java/com/seaofnodes/simple/node/IfNode.java | 13 +- .../java/com/seaofnodes/simple/node/LoadNode.java | 4 +- .../seaofnodes/simple/node/MachConcreteNode.java | 12 +- .../com/seaofnodes/simple/node/MemMergeNode.java | 12 +- .../java/com/seaofnodes/simple/node/MemOpNode.java | 6 +- .../com/seaofnodes/simple/node/MinusFNode.java | 8 +- .../java/com/seaofnodes/simple/node/MinusNode.java | 8 +- .../java/com/seaofnodes/simple/node/MulFNode.java | 9 +- .../java/com/seaofnodes/simple/node/NeverNode.java | 5 +- .../java/com/seaofnodes/simple/node/NewNode.java | 9 +- .../main/java/com/seaofnodes/simple/node/Node.java | 71 +-- .../java/com/seaofnodes/simple/node/NotNode.java | 8 +- .../java/com/seaofnodes/simple/node/ParmNode.java | 19 +- .../java/com/seaofnodes/simple/node/PhiNode.java | 19 +- .../java/com/seaofnodes/simple/node/ProjNode.java | 11 +- .../com/seaofnodes/simple/node/ReadOnlyNode.java | 7 +- .../com/seaofnodes/simple/node/RegionNode.java | 7 +- .../com/seaofnodes/simple/node/ReturnNode.java | 13 +- .../com/seaofnodes/simple/node/RoundF32Node.java | 7 +- .../java/com/seaofnodes/simple/node/ScopeNode.java | 28 +- .../java/com/seaofnodes/simple/node/SplitNode.java | 13 +- .../java/com/seaofnodes/simple/node/StartNode.java | 8 +- .../java/com/seaofnodes/simple/node/StopNode.java | 13 +- .../java/com/seaofnodes/simple/node/StoreNode.java | 7 +- .../com/seaofnodes/simple/node/StructNode.java | 18 +- .../java/com/seaofnodes/simple/node/SubFNode.java | 9 +- .../com/seaofnodes/simple/node/ToFloatNode.java | 7 +- .../java/com/seaofnodes/simple/node/XCtrlNode.java | 5 +- .../seaofnodes/simple/node/cpus/arm/MemOpARM.java | 5 +- .../seaofnodes/simple/node/cpus/arm/UJmpARM.java | 6 +- .../simple/node/cpus/riscv/BranchRISC.java | 19 +- .../seaofnodes/simple/node/cpus/riscv/ImmRISC.java | 9 +- .../simple/node/cpus/riscv/MemOpRISC.java | 5 +- .../simple/node/cpus/riscv/UJmpRISC.java | 5 +- .../simple/node/cpus/x86_64_v2/MemOpX86.java | 7 +- .../simple/node/cpus/x86_64_v2/StoreX86.java | 13 +- .../simple/node/cpus/x86_64_v2/UJmpX86.java | 6 +- .../com/seaofnodes/simple/print/ASMPrinter.java | 360 +++---------- .../com/seaofnodes/simple/print/IRPrinter.java | 399 ++------------- .../simple/print/SimpleGraphAdapter.java | 38 +- chapter24/Makefile | 1 + chapter24/pom.xml | 1 + .../com/seaofnodes/simple/codegen/CodeGen.java | 2 +- .../com/seaofnodes/simple/node/ArithFNode.java | 10 +- .../java/com/seaofnodes/simple/node/ArithNode.java | 10 +- .../java/com/seaofnodes/simple/node/BoolNode.java | 10 +- .../java/com/seaofnodes/simple/node/CProjNode.java | 5 +- .../com/seaofnodes/simple/node/CallEndNode.java | 14 +- .../java/com/seaofnodes/simple/node/CallNode.java | 16 +- .../java/com/seaofnodes/simple/node/CastNode.java | 10 +- .../com/seaofnodes/simple/node/ConFldOffNode.java | 9 +- .../com/seaofnodes/simple/node/ConstantNode.java | 16 +- .../java/com/seaofnodes/simple/node/CtrlNode.java | 5 +- .../com/seaofnodes/simple/node/ExternNode.java | 1 - .../java/com/seaofnodes/simple/node/FRefNode.java | 8 +- .../com/seaofnodes/simple/node/FunPtrNode.java | 1 - .../java/com/seaofnodes/simple/node/IfNode.java | 13 +- .../java/com/seaofnodes/simple/node/LoadNode.java | 4 +- .../seaofnodes/simple/node/MachConcreteNode.java | 12 +- .../com/seaofnodes/simple/node/MemMergeNode.java | 12 +- .../java/com/seaofnodes/simple/node/MemOpNode.java | 6 +- .../com/seaofnodes/simple/node/MinusFNode.java | 8 +- .../java/com/seaofnodes/simple/node/MinusNode.java | 8 +- .../java/com/seaofnodes/simple/node/NeverNode.java | 5 +- .../java/com/seaofnodes/simple/node/NewNode.java | 9 +- .../main/java/com/seaofnodes/simple/node/Node.java | 70 +-- .../java/com/seaofnodes/simple/node/NotNode.java | 8 +- .../java/com/seaofnodes/simple/node/ParmNode.java | 19 +- .../java/com/seaofnodes/simple/node/PhiNode.java | 19 +- .../java/com/seaofnodes/simple/node/ProjNode.java | 11 +- .../com/seaofnodes/simple/node/ReadOnlyNode.java | 7 +- .../com/seaofnodes/simple/node/RegionNode.java | 7 +- .../com/seaofnodes/simple/node/ReturnNode.java | 13 +- .../com/seaofnodes/simple/node/RoundF32Node.java | 7 +- .../java/com/seaofnodes/simple/node/ScopeNode.java | 28 +- .../java/com/seaofnodes/simple/node/SplitNode.java | 13 +- .../java/com/seaofnodes/simple/node/StartNode.java | 8 +- .../java/com/seaofnodes/simple/node/StopNode.java | 13 +- .../java/com/seaofnodes/simple/node/StoreNode.java | 7 +- .../com/seaofnodes/simple/node/StructNode.java | 18 +- .../com/seaofnodes/simple/node/ToFloatNode.java | 7 +- .../java/com/seaofnodes/simple/node/XCtrlNode.java | 5 +- .../seaofnodes/simple/node/cpus/arm/MemOpARM.java | 5 +- .../seaofnodes/simple/node/cpus/arm/UJmpARM.java | 6 +- .../simple/node/cpus/riscv/BranchRISC.java | 19 +- .../seaofnodes/simple/node/cpus/riscv/ImmRISC.java | 9 +- .../simple/node/cpus/riscv/MemOpRISC.java | 5 +- .../simple/node/cpus/riscv/UJmpRISC.java | 5 +- .../simple/node/cpus/x86_64_v2/MemOpX86.java | 7 +- .../simple/node/cpus/x86_64_v2/StoreX86.java | 13 +- .../simple/node/cpus/x86_64_v2/UJmpX86.java | 6 +- .../com/seaofnodes/simple/print/ASMPrinter.java | 360 +++---------- .../com/seaofnodes/simple/print/IRPrinter.java | 399 ++------------- .../simple/print/SimpleGraphAdapter.java | 38 +- chapter25/Makefile | 1 + chapter25/pom.xml | 1 + .../java/com/seaofnodes/simple/node/ArithNode.java | 10 +- .../java/com/seaofnodes/simple/node/BoolNode.java | 10 +- .../java/com/seaofnodes/simple/node/CProjNode.java | 5 +- .../com/seaofnodes/simple/node/CallEndNode.java | 14 +- .../java/com/seaofnodes/simple/node/CallNode.java | 16 +- .../com/seaofnodes/simple/node/ConFldOffNode.java | 9 +- .../com/seaofnodes/simple/node/ConstantNode.java | 16 +- .../com/seaofnodes/simple/node/ConvertNode.java | 7 +- .../java/com/seaofnodes/simple/node/CtrlNode.java | 5 +- .../com/seaofnodes/simple/node/EscapeNode.java | 17 +- .../com/seaofnodes/simple/node/ExternNode.java | 1 - .../java/com/seaofnodes/simple/node/FRefNode.java | 8 +- .../com/seaofnodes/simple/node/FldOffNode.java | 9 +- .../com/seaofnodes/simple/node/FunPtrNode.java | 10 +- .../java/com/seaofnodes/simple/node/GuardNode.java | 8 +- .../java/com/seaofnodes/simple/node/IfNode.java | 13 +- .../java/com/seaofnodes/simple/node/LoadNode.java | 4 +- .../seaofnodes/simple/node/MachConcreteNode.java | 12 +- .../com/seaofnodes/simple/node/MemMergeNode.java | 19 +- .../java/com/seaofnodes/simple/node/MemOpNode.java | 6 +- .../java/com/seaofnodes/simple/node/MinusNode.java | 8 +- .../java/com/seaofnodes/simple/node/NeverNode.java | 5 +- .../java/com/seaofnodes/simple/node/NewNode.java | 8 +- .../main/java/com/seaofnodes/simple/node/Node.java | 70 +-- .../java/com/seaofnodes/simple/node/NotNode.java | 8 +- .../java/com/seaofnodes/simple/node/ParmNode.java | 19 +- .../java/com/seaofnodes/simple/node/PhiNode.java | 19 +- .../java/com/seaofnodes/simple/node/ProjNode.java | 11 +- .../com/seaofnodes/simple/node/PtrToIntNode.java | 6 +- .../com/seaofnodes/simple/node/ReadOnlyNode.java | 7 +- .../com/seaofnodes/simple/node/RegionNode.java | 7 +- .../com/seaofnodes/simple/node/ReturnNode.java | 13 +- .../com/seaofnodes/simple/node/RoundF32Node.java | 7 +- .../java/com/seaofnodes/simple/node/ScopeNode.java | 28 +- .../java/com/seaofnodes/simple/node/SplitNode.java | 13 +- .../java/com/seaofnodes/simple/node/StartNode.java | 8 +- .../java/com/seaofnodes/simple/node/StopNode.java | 13 +- .../java/com/seaofnodes/simple/node/StoreNode.java | 7 +- .../com/seaofnodes/simple/node/ToFloatNode.java | 7 +- .../java/com/seaofnodes/simple/node/XCtrlNode.java | 5 +- .../seaofnodes/simple/node/cpus/arm/MemOpARM.java | 5 +- .../seaofnodes/simple/node/cpus/arm/UJmpARM.java | 6 +- .../simple/node/cpus/riscv/BranchRISC.java | 19 +- .../seaofnodes/simple/node/cpus/riscv/ImmRISC.java | 9 +- .../simple/node/cpus/riscv/MemOpRISC.java | 5 +- .../simple/node/cpus/riscv/UJmpRISC.java | 5 +- .../simple/node/cpus/x86_64_v2/MemOpX86.java | 7 +- .../simple/node/cpus/x86_64_v2/StoreX86.java | 13 +- .../simple/node/cpus/x86_64_v2/UJmpX86.java | 6 +- .../com/seaofnodes/simple/print/ASMPrinter.java | 367 +++----------- .../com/seaofnodes/simple/print/IRPrinter.java | 329 ++---------- .../simple/print/SimpleGraphAdapter.java | 42 +- docs/chapter-backports.md | 75 ++- graph/README.md | 23 +- graph/graph.iml | 1 + .../java/com/seaofnodes/graph/GraphAdapter.java | 46 +- .../java/com/seaofnodes/graph/GraphCapture.java | 3 +- pom.xml | 6 +- print/Makefile | 14 + print/README.md | 112 +++++ print/print.iml | 16 + print/print.mk | 4 + .../main/java/com/seaofnodes/print/ASMPrinter.java | 157 ++++++ .../java/com/seaofnodes/print/AssemblyAdapter.java | 26 + .../main/java/com/seaofnodes/print/BaseNode.java | 37 ++ .../java/com/seaofnodes/print/ExprPrinter.java | 56 +++ .../main/java/com/seaofnodes/print/IRAdapter.java | 34 ++ .../main/java/com/seaofnodes/print/IRPrinter.java | 293 +++++++++++ .../java/com/seaofnodes/print/PrinterTest.java | 153 ++++++ skills/chapter25-codex-notes.md | 29 +- skills/graph-viewer-codex-notes.md | 8 + 923 files changed, 5724 insertions(+), 13691 deletions(-) delete mode 100644 chapter07/src/main/java/com/seaofnodes/simple/IRPrinter.java create mode 100644 print/Makefile create mode 100644 print/README.md create mode 100644 print/print.iml create mode 100644 print/print.mk create mode 100644 print/src/main/java/com/seaofnodes/print/ASMPrinter.java create mode 100644 print/src/main/java/com/seaofnodes/print/AssemblyAdapter.java create mode 100644 print/src/main/java/com/seaofnodes/print/BaseNode.java create mode 100644 print/src/main/java/com/seaofnodes/print/ExprPrinter.java create mode 100644 print/src/main/java/com/seaofnodes/print/IRAdapter.java create mode 100644 print/src/main/java/com/seaofnodes/print/IRPrinter.java create mode 100644 print/src/test/java/com/seaofnodes/print/PrinterTest.java 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 @@ Chapter 1 ${project.basedir}/../graph + ${project.basedir}/../print 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 { /** * 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 { - @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 edges(Node n) { - var edges = new ArrayList(); - 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 @@ Chapter 2 ${project.basedir}/../graph + ${project.basedir}/../print 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 _print1(ExprPrinter 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 { /** * Inputs to the node. These are use-def references to Nodes. @@ -41,7 +36,6 @@ public abstract class Node { */ public final ArrayList _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 def into a Node. Keeps the edges correct, by removing * the corresponding use->def edge. This may make the original @@ -217,7 +172,6 @@ public abstract class Node { return null; // No progress } - /** * This function needs to be * Monotonic 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 _print1(ExprPrinter 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 _print1(ExprPrinter 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 { - @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 edges(Node n) { - var edges = new ArrayList(); - 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 @@ Chapter 3 ${project.basedir}/../graph + ${project.basedir}/../print 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 _print1(ExprPrinter 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 { /** * Inputs to the node. These are use-def references to Nodes. @@ -41,7 +36,6 @@ public abstract class Node { */ public final ArrayList _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 def into a Node. Keeps the edges correct, by removing * the corresponding use->def 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 _print1(ExprPrinter 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 _print1(ExprPrinter p) { + p.p(label()); for( HashMap 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 _print1(ExprPrinter 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 { - @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 edges(Node n) { - var edges = new ArrayList(); - 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 @@ Chapter 4 ${project.basedir}/../graph + ${project.basedir}/../print 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 _print1(ExprPrinter 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 _print1(ExprPrinter 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 { /** * Inputs to the node. These are use-def references to Nodes. @@ -39,7 +34,6 @@ public abstract class Node { */ public final ArrayList _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 def into a Node. Keeps the edges correct, by removing * the corresponding use->def 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 _print1(ExprPrinter 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 _print1(ExprPrinter 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 _print1(ExprPrinter p) { + p.p(label()); for( HashMap 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 _print1(ExprPrinter 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 { - @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 edges(Node n) { - String[] names = n instanceof ScopeNode scope && n.nIns() != 0 ? scope.reverseNames() : null; - var edges = new ArrayList(); - 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 @@ Chapter 5 ${project.basedir}/../graph + ${project.basedir}/../print 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 _print1(ExprPrinter 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 _print1(ExprPrinter 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 { /** * Inputs to the node. These are use-def references to Nodes. @@ -39,7 +34,6 @@ public abstract class Node { */ public final ArrayList _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 def into a Node. Keeps the edges correct, by removing * the corresponding use->def 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 _print1(ExprPrinter 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 _print1(ExprPrinter 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 _print1(ExprPrinter 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 _print1(ExprPrinter 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 _print1(ExprPrinter p) { + p.p(label()); for( HashMap 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 _print1(ExprPrinter 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 _print1(ExprPrinter 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 { - @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 edges(Node n) { - var edges = new ArrayList(); - 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 { 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 @@ Chapter 6 ${project.basedir}/../graph + ${project.basedir}/../print 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 _print1(ExprPrinter 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 _print1(ExprPrinter 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 { /** * Inputs to the node. These are use-def references to Nodes. @@ -41,14 +36,12 @@ public abstract class Node { */ public final ArrayList _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 def into a Node. Keeps the edges correct, by removing * the corresponding use->def 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 _print1(ExprPrinter 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 _print1(ExprPrinter 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 _print1(ExprPrinter 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 _print1(ExprPrinter 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 _print1(ExprPrinter p) { + p.p(label()); for( HashMap 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 _print1(ExprPrinter 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 _print1(ExprPrinter 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 { - @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 edges(Node n) { - var edges = new ArrayList(); - 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 { 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 @@ Chapter 7 ${project.basedir}/../graph + ${project.basedir}/../print 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 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 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 _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 _print1(ExprPrinter 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 _print1(ExprPrinter 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 { /** * Inputs to the node. These are use-def references to Nodes. @@ -41,14 +36,12 @@ public abstract class Node { */ public final ArrayList _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(); idef into a Node. Keeps the edges correct, by removing * the corresponding use->def edge. This may make the original @@ -262,7 +197,6 @@ public abstract class Node { // Remove bogus null. public 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 _print1(ExprPrinter 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 _print1(ExprPrinter 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 _print1(ExprPrinter 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 _print1(ExprPrinter 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 _print1(ExprPrinter p) { + p.p("Scope[ "); String[] names = reverseNames(); for( int j=0; j _print1(ExprPrinter 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 _print1(ExprPrinter 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 { - @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 edges(Node n) { - var edges = new ArrayList(); - 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 { 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 @@ Chapter 8 ${project.basedir}/../graph + ${project.basedir}/../print 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 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 { + private static final com.seaofnodes.print.IRPrinter 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 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 _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 _print1(ExprPrinter 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 _print1(ExprPrinter 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 { /** * Inputs to the node. These are use-def references to Nodes. @@ -42,14 +37,12 @@ public abstract class Node { */ public final ArrayList _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(); idef into a Node. Keeps the edges correct, by removing * the corresponding use->def edge. This may make the original @@ -264,7 +200,6 @@ public abstract class Node { // Remove bogus null. public 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 _print1(ExprPrinter 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 _print1(ExprPrinter 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 _print1(ExprPrinter 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 _print1(ExprPrinter 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 _print1(ExprPrinter p) { + p.p("Scope[ "); String[] names = reverseNames(); for( int j=0; j _print1(ExprPrinter 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 _print1(ExprPrinter 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 { - @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 edges(Node n) { - var edges = new ArrayList(); - 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 { 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 @@ Chapter 9 ${project.basedir}/../graph + ${project.basedir}/../print 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 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 { + private static final com.seaofnodes.print.IRPrinter 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 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 _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 _print1(ExprPrinter 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 _print1(ExprPrinter 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 { /** * Inputs to the node. These are use-def references to Nodes. @@ -44,14 +39,12 @@ public abstract class Node { */ public final ArrayList _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(); idef into a Node. Keeps the edges correct, by removing * the corresponding use->def edge. This may make the original @@ -283,7 +217,6 @@ public abstract class Node { // Remove bogus null. public 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 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 _print1(ExprPrinter 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 _print1(ExprPrinter 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 _print1(ExprPrinter 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 _print1(ExprPrinter 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 _print1(ExprPrinter p) { + p.p("Scope[ "); String[] names = reverseNames(); for( int j=0; j _print1(ExprPrinter 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 _print1(ExprPrinter 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 { - @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 edges(Node n) { - var edges = new ArrayList(); - 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 { 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 @@ + 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 @@ Chapter 10a ${project.basedir}/../graph + ${project.basedir}/../print 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 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 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 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 _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 { + private static final com.seaofnodes.print.IRPrinter 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 _print1(ExprPrinter 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 _print1(ExprPrinter 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 _print1(ExprPrinter 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 _print1(ExprPrinter 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 _print1(ExprPrinter 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 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 _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 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 _print1(ExprPrinter 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 _print1(ExprPrinter 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 _print1(ExprPrinter 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 _print1(ExprPrinter 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 _print1(ExprPrinter p) { + p.p("Scope[ "); String[] names = reverseNames(); for( int j=0; j _print1(ExprPrinter 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 _print1(ExprPrinter 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 _print1(ExprPrinter 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 { - @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 edges(Node n) { - var edges = new ArrayList(); - 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 { 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 @@ + 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 @@ Chapter 10b ${project.basedir}/../graph + ${project.basedir}/../print 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 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 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 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 _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 { + private static final com.seaofnodes.print.IRPrinter 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 _print1(ExprPrinter 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 _print1(ExprPrinter 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 _print1(ExprPrinter 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 _print1(ExprPrinter 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 _print1(ExprPrinter p) { + p.p("MEM["); for( int i=1; i _print1(ExprPrinter 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 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 _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 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 _print1(ExprPrinter 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 _print1(ExprPrinter 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 _print1(ExprPrinter 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 _print1(ExprPrinter 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 _print1(ExprPrinter p) { + p.p("Scope[ "); String[] names = reverseNames(); for( int j=0; j _print1(ExprPrinter 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 _print1(ExprPrinter 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 _print1(ExprPrinter 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 { - @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 edges(Node n) { - var edges = new ArrayList(); - 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 { 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 @@ Chapter 11 ${project.basedir}/../graph + ${project.basedir}/../print 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 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 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 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 _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 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 ds = new IdentityHashMap<>(); - _walk(ds,node,depth); - // Print by block with least diagnostic depth - HashMap depths = new HashMap<>(); - StringBuilder sb = new StringBuilder(); - ArrayList 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 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 bns, int i, IdentityHashMap 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 { + private static final com.seaofnodes.print.IRPrinter 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 _print1(ExprPrinter 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 _print1(ExprPrinter 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 _print1(ExprPrinter 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 _print1(ExprPrinter 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 _print1(ExprPrinter 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 _print1(ExprPrinter p) { + p.p("MEM["); for( int i=1; i _print1(ExprPrinter 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 _print1(ExprPrinter 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 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 _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 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 _print1(ExprPrinter 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 _print1(ExprPrinter 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 _print1(ExprPrinter 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 _print1(ExprPrinter 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 _print1(ExprPrinter p) { + p.p("Scope[ "); String[] names = reverseNames(); for( int j=0; j _print1(ExprPrinter 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 _print1(ExprPrinter 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 _print1(ExprPrinter 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 _print1(ExprPrinter 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 { - @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 edges(Node n) { - var edges = new ArrayList(); - 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 { 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 @@ Chapter 12 ${project.basedir}/../graph + ${project.basedir}/../print 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 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 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 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 _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 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 ds = new IdentityHashMap<>(); - _walk(ds,node,depth); - // Print by block with least diagnostic depth - HashMap depths = new HashMap<>(); - StringBuilder sb = new StringBuilder(); - ArrayList 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 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 bns, int i, IdentityHashMap 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 { + private static final com.seaofnodes.print.IRPrinter 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 _print1(ExprPrinter 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 _print1(ExprPrinter 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 _print1(ExprPrinter 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 _print1(ExprPrinter 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 _print1(ExprPrinter 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 _print1(ExprPrinter p) { + p.p("MEM["); for( int i=1; i _print1(ExprPrinter 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 _print1(ExprPrinter 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 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 _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 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 _print1(ExprPrinter 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 _print1(ExprPrinter 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 _print1(ExprPrinter 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 _print1(ExprPrinter 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 _print1(ExprPrinter p) { + p.p("Scope[ "); String[] names = reverseNames(); for( int j=0; j _print1(ExprPrinter 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 _print1(ExprPrinter 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 _print1(ExprPrinter 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 _print1(ExprPrinter 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 { - @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 edges(Node n) { - var edges = new ArrayList(); - 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 { 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 @@ Chapter 13 ${project.basedir}/../graph + ${project.basedir}/../print 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 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 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 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 _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 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 ds = new IdentityHashMap<>(); - _walk(ds,node,depth); - // Print by block with least diagnostic depth - HashMap depths = new HashMap<>(); - StringBuilder sb = new StringBuilder(); - ArrayList 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 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 bns, int i, IdentityHashMap 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 { + private static final com.seaofnodes.print.IRPrinter 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 _print1(ExprPrinter 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 _print1(ExprPrinter 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 _print1(ExprPrinter 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 _print1(ExprPrinter 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 _print1(ExprPrinter 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 _print1(ExprPrinter p) { + p.p("MEM["); for( int i=1; i _print1(ExprPrinter 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 _print1(ExprPrinter 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 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 _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 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 _print1(ExprPrinter 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 _print1(ExprPrinter 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 _print1(ExprPrinter 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 _print1(ExprPrinter 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 _print1(ExprPrinter p) { + p.p("Scope[ "); String[] names = reverseNames(); for( int j=0; j _print1(ExprPrinter 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 _print1(ExprPrinter 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 _print1(ExprPrinter 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 _print1(ExprPrinter 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 { - @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 edges(Node n) { - var edges = new ArrayList(); - 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 { 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 @@ Chapter 14 ${project.basedir}/../graph + ${project.basedir}/../print 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 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 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 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 _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 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 ds = new IdentityHashMap<>(); - _walk(ds,node,depth); - // Print by block with least diagnostic depth - HashMap depths = new HashMap<>(); - StringBuilder sb = new StringBuilder(); - ArrayList 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 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 bns, int i, IdentityHashMap 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 { + private static final com.seaofnodes.print.IRPrinter 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 _print1(ExprPrinter 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 _print1(ExprPrinter 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 _print1(ExprPrinter 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 _print1(ExprPrinter 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 _print1(ExprPrinter 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 _print1(ExprPrinter p) { + p.p("MEM["); for( int i=1; i _print1(ExprPrinter 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 _print1(ExprPrinter 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 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 _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 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 _print1(ExprPrinter 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 _print1(ExprPrinter 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 _print1(ExprPrinter 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 _print1(ExprPrinter 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 _print1(ExprPrinter p) { + p.p("Scope[ "); String[] names = reverseNames(); for( int j=0; j>>"), 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 _print1(ExprPrinter 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 _print1(ExprPrinter 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 _print1(ExprPrinter 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 _print1(ExprPrinter 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 { - @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 edges(Node n) { - var edges = new ArrayList(); - 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 { 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 @@ Chapter 15 ${project.basedir}/../graph + ${project.basedir}/../print 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 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 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 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 _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 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 ds = new HashMap<>(); - ArrayList ns = new ArrayList<>(); - _walk(ds,ns,node,depth); - // Remove data projections, these are force-printed behind their multinode head - for( int i=0; i depths = new HashMap<>(); - StringBuilder sb = new StringBuilder(); - ArrayList 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 ds, ArrayList 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 bns, int i, HashMap ds, ArrayList 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 { + private static final com.seaofnodes.print.IRPrinter 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 _print1(ExprPrinter 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 _print1(ExprPrinter 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 _print1(ExprPrinter 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 _print1(ExprPrinter 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 _print1(ExprPrinter 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 _print1(ExprPrinter p) { + p.p("MEM["); for( int i=1; i _print1(ExprPrinter 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 _print1(ExprPrinter 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 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 _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 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 _print1(ExprPrinter 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 _print1(ExprPrinter 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 _print1(ExprPrinter 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 _print1(ExprPrinter 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 _print1(ExprPrinter p) { + p.p("Scope[ "); String[] names = reverseNames(); for( int j=0; j>>"), 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 _print1(ExprPrinter 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 _print1(ExprPrinter 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 _print1(ExprPrinter 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 _print1(ExprPrinter 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 { - @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 edges(Node n) { - var edges = new ArrayList(); - 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 { 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 @@ Chapter 16 ${project.basedir}/../graph + ${project.basedir}/../print 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 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 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 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 _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 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 ds = new HashMap<>(); - ArrayList ns = new ArrayList<>(); - _walk(ds,ns,node,depth); - // Remove data projections, these are force-printed behind their multinode head - for( int i=0; i depths = new HashMap<>(); - StringBuilder sb = new StringBuilder(); - ArrayList 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 ds, ArrayList 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 bns, int i, HashMap ds, ArrayList 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 { + private static final com.seaofnodes.print.IRPrinter 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 _print1(ExprPrinter 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 _print1(ExprPrinter 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 _print1(ExprPrinter 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 _print1(ExprPrinter 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 _print1(ExprPrinter 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 _print1(ExprPrinter p) { + p.p("MEM["); for( int i=1; i _print1(ExprPrinter 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 _print1(ExprPrinter 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 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 _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 def->use 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 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 _print1(ExprPrinter 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 _print1(ExprPrinter 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 _print1(ExprPrinter 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 _print1(ExprPrinter 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 _print1(ExprPrinter p) { + p.p("Scope[ "); int j=1; for( int i=0; i>>"), 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 _print1(ExprPrinter 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 _print1(ExprPrinter 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 _print1(ExprPrinter 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 _print1(ExprPrinter p) { + if( _ts==null ) return p.p("STRUCT?"); + p.p(_ts._name).p(" {"); for( int i=0; i _print1(ExprPrinter 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 { - @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 edges(Node n) { - var edges = new ArrayList(); - 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 { 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 @@ Chapter 17 ${project.basedir}/../graph + ${project.basedir}/../print 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 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 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 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 _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 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 ds = new HashMap<>(); - ArrayList ns = new ArrayList<>(); - _walk(ds,ns,node,depth); - // Remove data projections, these are force-printed behind their multinode head - for( int i=0; i depths = new HashMap<>(); - StringBuilder sb = new StringBuilder(); - ArrayList 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 ds, ArrayList 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 bns, int i, HashMap ds, ArrayList 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 { + private static final com.seaofnodes.print.IRPrinter 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 _print1(ExprPrinter 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 _print1(ExprPrinter 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 _print1(ExprPrinter 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 _print1(ExprPrinter 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 _print1(ExprPrinter 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 _print1(ExprPrinter p) { + p.p("MEM["); for( int i=1; i _print1(ExprPrinter 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 _print1(ExprPrinter 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 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 _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 def->use 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 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 _print1(ExprPrinter 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 _print1(ExprPrinter 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 _print1(ExprPrinter 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 _print1(ExprPrinter 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 _print1(ExprPrinter p) { + p.p("Scope[ "); int j=1; for( int i=0; i>>"), 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 _print1(ExprPrinter 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 _print1(ExprPrinter 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 _print1(ExprPrinter 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 _print1(ExprPrinter p) { + if( _ts==null ) return p.p("STRUCT?"); + p.p(_ts._name).p(" {"); for( int i=0; i _print1(ExprPrinter 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 { - @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 edges(Node n) { - var edges = new ArrayList(); - 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 { 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 @@ Chapter 18 ${project.basedir}/../graph + ${project.basedir}/../print 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 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 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 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 _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 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 { + private static final com.seaofnodes.print.IRPrinter 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>(); + var funs=new ArrayList(); + 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 ds = new HashMap<>(); - ArrayList ns = new ArrayList<>(); - _walk(ds,ns,node,depth); - // Remove data projections, these are force-printed behind their multinode head - for( int i=0; i depths = new HashMap<>(); - SB sb = new SB(); - Ary 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 ds, ArrayList 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 bns, int i, HashMap ds, ArrayList 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 _print1(ExprPrinter 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 _print1(ExprPrinter 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 _print1(ExprPrinter p) { + p.p("cend( "); + p.p( in(0) instanceof CallNode ? "Call, " : "----, "); for( int i=1; i _print1(ExprPrinter 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 _print1(ExprPrinter 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 _print1(ExprPrinter 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 _print1(ExprPrinter 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 _print1(ExprPrinter 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 _print1(ExprPrinter 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 _print1(ExprPrinter 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 _print1(ExprPrinter p) { + p.p("MEM["); for( int i=1; i _print1(ExprPrinter 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 _print1(ExprPrinter 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 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 _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 def->use 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 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 _print1(ExprPrinter 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 _print1(ExprPrinter 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 _print1(ExprPrinter 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 _print1(ExprPrinter 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 _print1(ExprPrinter 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 _print1(ExprPrinter p) { + p.p("Scope[ "); int j=1; for( int i=0; i _print1(ExprPrinter 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 _print1(ExprPrinter 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 _print1(ExprPrinter 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 _print1(ExprPrinter p) { + if( _ts==null ) return p.p("STRUCT?"); + p.p(_ts._name).p(" {"); for( int i=0; i _print1(ExprPrinter 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 { - @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 edges(Node n) { - var edges = new ArrayList(); - 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 { 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 { 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 @@ Chapter 19 ${project.basedir}/../graph + ${project.basedir}/../print 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 { + 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 blocks() { + var blocks=new ArrayList(); + 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