summaryrefslogtreecommitdiff
path: root/src/main/java/com/seaofnodes
diff options
context:
space:
mode:
Diffstat (limited to 'src/main/java/com/seaofnodes')
-rw-r--r--src/main/java/com/seaofnodes/simple/IterPeeps.java2
-rw-r--r--src/main/java/com/seaofnodes/simple/Parser.java493
-rw-r--r--src/main/java/com/seaofnodes/simple/codegen/Coalesce.java4
-rw-r--r--src/main/java/com/seaofnodes/simple/codegen/CodeGen.java66
-rw-r--r--src/main/java/com/seaofnodes/simple/codegen/ElfFile.java3
-rw-r--r--src/main/java/com/seaofnodes/simple/codegen/Encoding.java24
-rw-r--r--src/main/java/com/seaofnodes/simple/codegen/GlobalCodeMotion.java6
-rw-r--r--src/main/java/com/seaofnodes/simple/codegen/IFG.java4
-rw-r--r--src/main/java/com/seaofnodes/simple/codegen/LRG.java7
-rw-r--r--src/main/java/com/seaofnodes/simple/codegen/LinkMem.java2
-rw-r--r--src/main/java/com/seaofnodes/simple/codegen/ListScheduler.java4
-rw-r--r--src/main/java/com/seaofnodes/simple/codegen/RegAlloc.java8
-rw-r--r--src/main/java/com/seaofnodes/simple/codegen/RegMask.java4
-rw-r--r--src/main/java/com/seaofnodes/simple/node/AddNode.java9
-rw-r--r--src/main/java/com/seaofnodes/simple/node/ArithNode.java9
-rw-r--r--src/main/java/com/seaofnodes/simple/node/BoolNode.java4
-rw-r--r--src/main/java/com/seaofnodes/simple/node/CFGNode.java7
-rw-r--r--src/main/java/com/seaofnodes/simple/node/CProjNode.java2
-rw-r--r--src/main/java/com/seaofnodes/simple/node/CallEndMach.java2
-rw-r--r--src/main/java/com/seaofnodes/simple/node/CallEndNode.java10
-rw-r--r--src/main/java/com/seaofnodes/simple/node/CallNode.java10
-rw-r--r--src/main/java/com/seaofnodes/simple/node/CastMach.java2
-rw-r--r--src/main/java/com/seaofnodes/simple/node/CastNode.java15
-rw-r--r--src/main/java/com/seaofnodes/simple/node/ConFldOffNode.java43
-rw-r--r--src/main/java/com/seaofnodes/simple/node/ConstantNode.java38
-rw-r--r--src/main/java/com/seaofnodes/simple/node/ExternNode.java6
-rw-r--r--src/main/java/com/seaofnodes/simple/node/FunNode.java9
-rw-r--r--src/main/java/com/seaofnodes/simple/node/IfNode.java6
-rw-r--r--src/main/java/com/seaofnodes/simple/node/LoadNode.java41
-rw-r--r--src/main/java/com/seaofnodes/simple/node/LoopNode.java24
-rw-r--r--src/main/java/com/seaofnodes/simple/node/MachConcreteNode.java2
-rw-r--r--src/main/java/com/seaofnodes/simple/node/MachNode.java2
-rw-r--r--src/main/java/com/seaofnodes/simple/node/MemMergeNode.java9
-rw-r--r--src/main/java/com/seaofnodes/simple/node/MemOpNode.java2
-rw-r--r--src/main/java/com/seaofnodes/simple/node/MinusNode.java3
-rw-r--r--src/main/java/com/seaofnodes/simple/node/MultiNode.java2
-rw-r--r--src/main/java/com/seaofnodes/simple/node/NewNode.java34
-rw-r--r--src/main/java/com/seaofnodes/simple/node/Node.java7
-rw-r--r--src/main/java/com/seaofnodes/simple/node/NotNode.java4
-rw-r--r--src/main/java/com/seaofnodes/simple/node/ParmNode.java11
-rw-r--r--src/main/java/com/seaofnodes/simple/node/PhiNode.java77
-rw-r--r--src/main/java/com/seaofnodes/simple/node/ReadOnlyMach.java2
-rw-r--r--src/main/java/com/seaofnodes/simple/node/RegionNode.java8
-rw-r--r--src/main/java/com/seaofnodes/simple/node/ReturnNode.java15
-rw-r--r--src/main/java/com/seaofnodes/simple/node/ScopeNode.java111
-rw-r--r--src/main/java/com/seaofnodes/simple/node/SplitNode.java2
-rw-r--r--src/main/java/com/seaofnodes/simple/node/StartNode.java11
-rw-r--r--src/main/java/com/seaofnodes/simple/node/StopNode.java2
-rw-r--r--src/main/java/com/seaofnodes/simple/node/StoreNode.java15
-rw-r--r--src/main/java/com/seaofnodes/simple/node/StructNode.java9
-rw-r--r--src/main/java/com/seaofnodes/simple/node/cpus/arm/AddARM.java2
-rw-r--r--src/main/java/com/seaofnodes/simple/node/cpus/arm/AddFARM.java2
-rw-r--r--src/main/java/com/seaofnodes/simple/node/cpus/arm/AddIARM.java2
-rw-r--r--src/main/java/com/seaofnodes/simple/node/cpus/arm/AndARM.java2
-rw-r--r--src/main/java/com/seaofnodes/simple/node/cpus/arm/AndIARM.java2
-rw-r--r--src/main/java/com/seaofnodes/simple/node/cpus/arm/AsrARM.java2
-rw-r--r--src/main/java/com/seaofnodes/simple/node/cpus/arm/AsrIARM.java2
-rw-r--r--src/main/java/com/seaofnodes/simple/node/cpus/arm/BranchARM.java3
-rw-r--r--src/main/java/com/seaofnodes/simple/node/cpus/arm/CallARM.java6
-rw-r--r--src/main/java/com/seaofnodes/simple/node/cpus/arm/CallRRARM.java4
-rw-r--r--src/main/java/com/seaofnodes/simple/node/cpus/arm/CmpARM.java2
-rw-r--r--src/main/java/com/seaofnodes/simple/node/cpus/arm/CmpFARM.java2
-rw-r--r--src/main/java/com/seaofnodes/simple/node/cpus/arm/CmpIARM.java2
-rw-r--r--src/main/java/com/seaofnodes/simple/node/cpus/arm/DivARM.java2
-rw-r--r--src/main/java/com/seaofnodes/simple/node/cpus/arm/DivFARM.java2
-rw-r--r--src/main/java/com/seaofnodes/simple/node/cpus/arm/FloatARM.java4
-rw-r--r--src/main/java/com/seaofnodes/simple/node/cpus/arm/FunARM.java4
-rw-r--r--src/main/java/com/seaofnodes/simple/node/cpus/arm/I2F8ARM.java2
-rw-r--r--src/main/java/com/seaofnodes/simple/node/cpus/arm/IntARM.java2
-rw-r--r--src/main/java/com/seaofnodes/simple/node/cpus/arm/LoadARM.java2
-rw-r--r--src/main/java/com/seaofnodes/simple/node/cpus/arm/LslARM.java2
-rw-r--r--src/main/java/com/seaofnodes/simple/node/cpus/arm/LslIARM.java2
-rw-r--r--src/main/java/com/seaofnodes/simple/node/cpus/arm/LsrARM.java2
-rw-r--r--src/main/java/com/seaofnodes/simple/node/cpus/arm/LsrIARM.java3
-rw-r--r--src/main/java/com/seaofnodes/simple/node/cpus/arm/MemOpARM.java5
-rw-r--r--src/main/java/com/seaofnodes/simple/node/cpus/arm/MulARM.java2
-rw-r--r--src/main/java/com/seaofnodes/simple/node/cpus/arm/MulFARM.java2
-rw-r--r--src/main/java/com/seaofnodes/simple/node/cpus/arm/NegARM.java2
-rw-r--r--src/main/java/com/seaofnodes/simple/node/cpus/arm/NewARM.java3
-rw-r--r--src/main/java/com/seaofnodes/simple/node/cpus/arm/NotARM.java3
-rw-r--r--src/main/java/com/seaofnodes/simple/node/cpus/arm/OrARM.java2
-rw-r--r--src/main/java/com/seaofnodes/simple/node/cpus/arm/OrIARM.java2
-rw-r--r--src/main/java/com/seaofnodes/simple/node/cpus/arm/SetARM.java2
-rw-r--r--src/main/java/com/seaofnodes/simple/node/cpus/arm/SplitARM.java5
-rw-r--r--src/main/java/com/seaofnodes/simple/node/cpus/arm/StoreARM.java4
-rw-r--r--src/main/java/com/seaofnodes/simple/node/cpus/arm/SubARM.java2
-rw-r--r--src/main/java/com/seaofnodes/simple/node/cpus/arm/SubFARM.java2
-rw-r--r--src/main/java/com/seaofnodes/simple/node/cpus/arm/SubIARM.java5
-rw-r--r--src/main/java/com/seaofnodes/simple/node/cpus/arm/TFPARM.java3
-rw-r--r--src/main/java/com/seaofnodes/simple/node/cpus/arm/TMPARM.java3
-rw-r--r--src/main/java/com/seaofnodes/simple/node/cpus/arm/UJmpARM.java3
-rw-r--r--src/main/java/com/seaofnodes/simple/node/cpus/arm/XorARM.java2
-rw-r--r--src/main/java/com/seaofnodes/simple/node/cpus/arm/XorIARM.java7
-rw-r--r--src/main/java/com/seaofnodes/simple/node/cpus/arm/arm.java2
-rw-r--r--src/main/java/com/seaofnodes/simple/node/cpus/riscv/AUIPC.java3
-rw-r--r--src/main/java/com/seaofnodes/simple/node/cpus/riscv/AddFRISC.java2
-rw-r--r--src/main/java/com/seaofnodes/simple/node/cpus/riscv/AddIRISC.java2
-rw-r--r--src/main/java/com/seaofnodes/simple/node/cpus/riscv/AddRISC.java2
-rw-r--r--src/main/java/com/seaofnodes/simple/node/cpus/riscv/AndIRISC.java2
-rw-r--r--src/main/java/com/seaofnodes/simple/node/cpus/riscv/AndRISC.java2
-rw-r--r--src/main/java/com/seaofnodes/simple/node/cpus/riscv/BranchRISC.java3
-rw-r--r--src/main/java/com/seaofnodes/simple/node/cpus/riscv/CallRISC.java6
-rw-r--r--src/main/java/com/seaofnodes/simple/node/cpus/riscv/CallRRISC.java4
-rw-r--r--src/main/java/com/seaofnodes/simple/node/cpus/riscv/DivFRISC.java2
-rw-r--r--src/main/java/com/seaofnodes/simple/node/cpus/riscv/DivRISC.java2
-rw-r--r--src/main/java/com/seaofnodes/simple/node/cpus/riscv/FltRISC.java4
-rw-r--r--src/main/java/com/seaofnodes/simple/node/cpus/riscv/FunRISC.java4
-rw-r--r--src/main/java/com/seaofnodes/simple/node/cpus/riscv/I2F8RISC.java2
-rw-r--r--src/main/java/com/seaofnodes/simple/node/cpus/riscv/ImmRISC.java2
-rw-r--r--src/main/java/com/seaofnodes/simple/node/cpus/riscv/Int8RISC.java5
-rw-r--r--src/main/java/com/seaofnodes/simple/node/cpus/riscv/IntRISC.java2
-rw-r--r--src/main/java/com/seaofnodes/simple/node/cpus/riscv/LUI.java2
-rw-r--r--src/main/java/com/seaofnodes/simple/node/cpus/riscv/LoadRISC.java2
-rw-r--r--src/main/java/com/seaofnodes/simple/node/cpus/riscv/MemOpRISC.java4
-rw-r--r--src/main/java/com/seaofnodes/simple/node/cpus/riscv/MulFRISC.java2
-rw-r--r--src/main/java/com/seaofnodes/simple/node/cpus/riscv/MulRISC.java2
-rw-r--r--src/main/java/com/seaofnodes/simple/node/cpus/riscv/NegRISC.java2
-rw-r--r--src/main/java/com/seaofnodes/simple/node/cpus/riscv/NewRISC.java3
-rw-r--r--src/main/java/com/seaofnodes/simple/node/cpus/riscv/NotRISC.java2
-rw-r--r--src/main/java/com/seaofnodes/simple/node/cpus/riscv/OrIRISC.java2
-rw-r--r--src/main/java/com/seaofnodes/simple/node/cpus/riscv/OrRISC.java2
-rw-r--r--src/main/java/com/seaofnodes/simple/node/cpus/riscv/RetRISC.java4
-rw-r--r--src/main/java/com/seaofnodes/simple/node/cpus/riscv/SetFRISC.java2
-rw-r--r--src/main/java/com/seaofnodes/simple/node/cpus/riscv/SetIRISC.java2
-rw-r--r--src/main/java/com/seaofnodes/simple/node/cpus/riscv/SetRISC.java2
-rw-r--r--src/main/java/com/seaofnodes/simple/node/cpus/riscv/SllIRISC.java2
-rw-r--r--src/main/java/com/seaofnodes/simple/node/cpus/riscv/SllRISC.java2
-rw-r--r--src/main/java/com/seaofnodes/simple/node/cpus/riscv/SplitRISC.java4
-rw-r--r--src/main/java/com/seaofnodes/simple/node/cpus/riscv/SraIRISC.java2
-rw-r--r--src/main/java/com/seaofnodes/simple/node/cpus/riscv/SraRISC.java2
-rw-r--r--src/main/java/com/seaofnodes/simple/node/cpus/riscv/SrlIRISC.java2
-rw-r--r--src/main/java/com/seaofnodes/simple/node/cpus/riscv/SrlRISC.java2
-rw-r--r--src/main/java/com/seaofnodes/simple/node/cpus/riscv/StoreRISC.java4
-rw-r--r--src/main/java/com/seaofnodes/simple/node/cpus/riscv/SubFRISC.java2
-rw-r--r--src/main/java/com/seaofnodes/simple/node/cpus/riscv/SubRISC.java2
-rw-r--r--src/main/java/com/seaofnodes/simple/node/cpus/riscv/TFPRISC.java3
-rw-r--r--src/main/java/com/seaofnodes/simple/node/cpus/riscv/TMPRISC.java2
-rw-r--r--src/main/java/com/seaofnodes/simple/node/cpus/riscv/UJmpRISC.java3
-rw-r--r--src/main/java/com/seaofnodes/simple/node/cpus/riscv/XorIRISC.java2
-rw-r--r--src/main/java/com/seaofnodes/simple/node/cpus/riscv/XorRISC.java2
-rw-r--r--src/main/java/com/seaofnodes/simple/node/cpus/riscv/riscv.java2
-rw-r--r--src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/AddFMemX86.java4
-rw-r--r--src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/AddFX86.java2
-rw-r--r--src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/AddIX86.java4
-rw-r--r--src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/AddMemX86.java2
-rw-r--r--src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/CallRX86.java2
-rw-r--r--src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/CallX86.java4
-rw-r--r--src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/CmpFX86.java2
-rw-r--r--src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/CmpIX86.java2
-rw-r--r--src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/CmpMemX86.java2
-rw-r--r--src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/CmpX86.java2
-rw-r--r--src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/DivFX86.java2
-rw-r--r--src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/DivX86.java2
-rw-r--r--src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/FltX86.java2
-rw-r--r--src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/FunX86.java2
-rw-r--r--src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/I2f8X86.java2
-rw-r--r--src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/ImmX86.java2
-rw-r--r--src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/IntX86.java2
-rw-r--r--src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/JmpX86.java3
-rw-r--r--src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/LeaX86.java2
-rw-r--r--src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/LoadX86.java9
-rw-r--r--src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/MemAddX86.java2
-rw-r--r--src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/MemOpX86.java4
-rw-r--r--src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/MulFX86.java2
-rw-r--r--src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/MulIX86.java4
-rw-r--r--src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/MulX86.java2
-rw-r--r--src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/NegX86.java3
-rw-r--r--src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/NewX86.java2
-rw-r--r--src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/NotX86.java2
-rw-r--r--src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/RegX86.java2
-rw-r--r--src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/SarIX86.java5
-rw-r--r--src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/SarX86.java2
-rw-r--r--src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/SetX86.java3
-rw-r--r--src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/ShlIX86.java5
-rw-r--r--src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/ShlX86.java2
-rw-r--r--src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/ShrIX86.java5
-rw-r--r--src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/ShrX86.java2
-rw-r--r--src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/SplitX86.java4
-rw-r--r--src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/StoreX86.java2
-rw-r--r--src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/SubFX86.java2
-rw-r--r--src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/TFPX86.java2
-rw-r--r--src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/TMPX86.java8
-rw-r--r--src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/UJmpX86.java3
-rw-r--r--src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/x86_64_v2.java5
-rw-r--r--src/main/java/com/seaofnodes/simple/print/ASMPrinter.java11
-rw-r--r--src/main/java/com/seaofnodes/simple/print/GraphVisualizer.java8
-rw-r--r--src/main/java/com/seaofnodes/simple/print/IRPrinter.java10
-rw-r--r--src/main/java/com/seaofnodes/simple/print/JSViewer.java10
-rw-r--r--src/main/java/com/seaofnodes/simple/print/SimpleWebSocket.java2
-rw-r--r--src/main/java/com/seaofnodes/simple/sys/sys.smp58
-rw-r--r--src/main/java/com/seaofnodes/simple/type/Field.java124
-rw-r--r--src/main/java/com/seaofnodes/simple/type/Type.java370
-rw-r--r--src/main/java/com/seaofnodes/simple/type/TypeConAry.java53
-rw-r--r--src/main/java/com/seaofnodes/simple/type/TypeConAryB.java6
-rw-r--r--src/main/java/com/seaofnodes/simple/type/TypeConAryI.java6
-rw-r--r--src/main/java/com/seaofnodes/simple/type/TypeFloat.java55
-rw-r--r--src/main/java/com/seaofnodes/simple/type/TypeFunPtr.java234
-rw-r--r--src/main/java/com/seaofnodes/simple/type/TypeInteger.java79
-rw-r--r--src/main/java/com/seaofnodes/simple/type/TypeMem.java87
-rw-r--r--src/main/java/com/seaofnodes/simple/type/TypeMemPtr.java87
-rw-r--r--src/main/java/com/seaofnodes/simple/type/TypeNil.java14
-rw-r--r--src/main/java/com/seaofnodes/simple/type/TypePtr.java18
-rw-r--r--src/main/java/com/seaofnodes/simple/type/TypeRPC.java13
-rw-r--r--src/main/java/com/seaofnodes/simple/type/TypeStruct.java491
-rw-r--r--src/main/java/com/seaofnodes/simple/type/TypeTuple.java113
-rw-r--r--src/main/java/com/seaofnodes/simple/util/Ary.java (renamed from src/main/java/com/seaofnodes/simple/Ary.java)3
-rw-r--r--src/main/java/com/seaofnodes/simple/util/AryInt.java192
-rw-r--r--src/main/java/com/seaofnodes/simple/util/SB.java (renamed from src/main/java/com/seaofnodes/simple/SB.java)2
-rw-r--r--src/main/java/com/seaofnodes/simple/util/Utils.java (renamed from src/main/java/com/seaofnodes/simple/Utils.java)2
209 files changed, 2427 insertions, 1181 deletions
diff --git a/src/main/java/com/seaofnodes/simple/IterPeeps.java b/src/main/java/com/seaofnodes/simple/IterPeeps.java
index 66e8a4a8..9ae4231e 100644
--- a/src/main/java/com/seaofnodes/simple/IterPeeps.java
+++ b/src/main/java/com/seaofnodes/simple/IterPeeps.java
@@ -1,6 +1,7 @@
package com.seaofnodes.simple;
import com.seaofnodes.simple.codegen.CodeGen;
+import com.seaofnodes.simple.util.Ary;
import com.seaofnodes.simple.node.*;
import com.seaofnodes.simple.print.JSViewer;
import java.util.Arrays;
@@ -81,6 +82,7 @@ public class IterPeeps {
// there's a new user), and replace in the graph.
if( x != n ) {
for( Node z : n. _inputs ) _work.push(z);
+ for( Node z : x._outputs ) _work.push(z);
n.subsume(x);
}
}
diff --git a/src/main/java/com/seaofnodes/simple/Parser.java b/src/main/java/com/seaofnodes/simple/Parser.java
index 23e9ddee..8a6b1967 100644
--- a/src/main/java/com/seaofnodes/simple/Parser.java
+++ b/src/main/java/com/seaofnodes/simple/Parser.java
@@ -4,7 +4,9 @@ import com.seaofnodes.simple.codegen.CodeGen;
import com.seaofnodes.simple.node.*;
import com.seaofnodes.simple.print.GraphVisualizer;
import com.seaofnodes.simple.type.*;
-
+import com.seaofnodes.simple.util.Ary;
+import com.seaofnodes.simple.util.Utils;
+import com.seaofnodes.simple.node.ScopeNode.Kind;
import java.util.*;
/**
@@ -82,8 +84,7 @@ public class Parser {
FunNode _fun; // Current function being parsed
// Mapping from a type name to a Type. The string name matches
- // `type.str()` call. No TypeMemPtrs are in here, because Simple does not
- // have C-style '*ptr' references.
+ // `type.str()` call.
public static HashMap<String, Type> TYPES = defaultTypes();
// Mapping from a type name to the constructor for a Type.
@@ -152,7 +153,7 @@ public class Parser {
_xScopes.push(_scope);
// Parse whole program, as-if function header "{ int arg -> body }"
- parseFunctionBody(_code._main,loc(),"arg");
+ parseFunctionBody( _code._main,loc(),"arg");
// Kill an empty default main. Keep only if it was explicitly defined
// (programmer asked for a "main") or it has stuff (i.e. beginner
@@ -188,10 +189,16 @@ public class Parser {
/**
* Parses a function body, assuming the header is parsed.
*/
- private ReturnNode parseFunctionBody(TypeFunPtr sig, Lexer loc, String... ids) {
+ private ReturnNode parseFunctionBody( TypeFunPtr sig, Lexer loc, String... ids) {
+ // If this is a method, record & restore the existing struct fields,
+ // which are also the struct initializers. The method might update
+ // mutable fields, so when the function parse is done reset back to
+ // pre-function-parse values.
+ Node[] preParse = new Node[_scope.nIns()];
+ for( int i=0; i<_scope.nIns(); i++ )
+ preParse[i] = _scope.in(i)==null ? null : _scope.in(i).keep();
+
// Stack parser state on the local Java stack, and unstack it later
- Node oldctrl = ctrl().keep();
- Node oldmem = _scope.mem().keep();
FunNode oldfun = _fun;
ScopeNode breakScope = _breakScope; _breakScope = null;
ScopeNode continueScope = _continueScope; _continueScope = null;
@@ -206,7 +213,7 @@ public class Parser {
Node rpc = new ParmNode("$rpc",0,TypeRPC.BOT,fun,con(TypeRPC.BOT)).peephole();
// Build a multi-exit return point for all function returns
- RegionNode r = new RegionNode((Lexer)null,null,null).init();
+ RegionNode r = new RegionNode( null,null,null).init();
assert r.inProgress();
PhiNode rmem = new PhiNode(ScopeNode.MEM0,TypeMem.BOT,r,null).init();
PhiNode rrez = new PhiNode(ScopeNode.ARG0,Type.BOTTOM,r,null).init();
@@ -215,10 +222,11 @@ public class Parser {
assert ret.inProgress();
_code._stop.addDef(ret);
+
// Pre-call the function from Start, with worse-case arguments. This
// represents all the future, yet-to-be-parsed functions calls and
// external calls.
- _scope.push(ScopeNode.Kind.Function);
+ _scope.push(new Kind.Func());
ctrl(fun); // Scope control from function
// Private mem alias tracking per function
MemMergeNode mem = new MemMergeNode(true);
@@ -237,8 +245,13 @@ public class Parser {
last = parseStatement();
// Last expression is the return except for the top-level main
- if( ctrl()._type==Type.CONTROL && fun.sig() != _code._main )
- fun.addReturn(ctrl(), _scope.mem().merge(), last);
+ if( ctrl()._type==Type.CONTROL )
+ if( fun.sig() != _code._main )
+ fun.addReturn(ctrl(), _scope.mem().merge(), last);
+ else {
+ fun.setDef(1,XCTRL); // Kill default main
+ _code.addAll(fun._outputs);
+ }
// Pop off the inProgress node on the multi-exit Region merge
assert r.inProgress();
@@ -259,9 +272,10 @@ public class Parser {
_fun = oldfun;
_breakScope = breakScope;
_continueScope = continueScope;
- // Reset control and memory to pre-function parsing days
- ctrl(oldctrl.unkeep());
- _scope.mem(oldmem.unkeep());
+
+ // Reset all fields to pre-parse days
+ for( int i=0; i<preParse.length; i++ )
+ _scope.setDef(i,preParse[i]==null ? null : preParse[i].unkeep());
return ret;
}
@@ -275,7 +289,7 @@ public class Parser {
* Does not parse the opening or closing '{}'
* @return a {@link Node} or {@code null}
*/
- private Node parseBlock(ScopeNode.Kind kind) {
+ private Node parseBlock(Kind kind) {
// Enter a new scope
_scope.push(kind);
Node last = ZERO;
@@ -308,7 +322,7 @@ public class Parser {
// Break ambiguity around leading function types and starting a block
else if (peek('{') && !isTypeFun() ) {
match("{");
- return require(parseBlock(ScopeNode.Kind.Block),"}");
+ return require(parseBlock(new Kind.Block()),"}");
}
// Declaration or normal assignment/expression
else return parseDeclarationStatement();
@@ -344,8 +358,8 @@ public class Parser {
// }
// }
require("(");
- _scope.push(ScopeNode.Kind.Block); // Scope for the index variables
- if( !match(";") ) // Can be empty init "for(;test;next) body"
+ _scope.push(new Kind.Block()); // Scope for the index variables
+ if( !match(";") ) // Can be empty init "for(;test;next) body"
parseDeclarationStatement(); // Non-empty init
Node rez = parseLooping(true);
_scope.pop(); // Exit index variable scope
@@ -462,7 +476,7 @@ public class Parser {
ctrl(XCTRL); // Kill current scope
// Prune nested lexical scopes that have depth > than the loop head
// We use _breakScope as a proxy for the loop head scope to obtain the depth
- while( cur._lexSize.size() > _breakScope._lexSize.size() )
+ while( cur.depth() > _breakScope.depth() )
cur.pop();
// If this is a continue then first time the target is null
// So we just use the pruned current scope as the base for the
@@ -470,7 +484,7 @@ public class Parser {
if( toScope == null )
return cur;
// toScope is either the break scope, or a scope that was created here
- assert toScope._lexSize.size() <= _breakScope._lexSize.size();
+ assert toScope.depth() <= _breakScope.depth();
toScope.ctrl(toScope.mergeScopes(cur,loc()).peephole());
return toScope;
}
@@ -521,11 +535,11 @@ public class Parser {
// Parse predicate
require("(");
var pred = require(parseAsgn(), ")");
- return parseTrinary(pred,true,"else");
+ return parseTrinary(pred,"else");
}
// Parse a conditional expression, merging results.
- private Node parseTrinary( Node pred, boolean stmt, String fside ) {
+ private Node parseTrinary( Node pred, String fside ) {
pred.keep();
// IfNode takes current control and predicate
@@ -541,7 +555,15 @@ public class Parser {
// Parse the true side
ctrl(ifT.unkeep()); // set ctrl token to ifTrue projection
_scope.addGuards(ifT,pred,false); // Up-cast predicate
- Node lhs = (stmt ? parseStatement() : parseAsgn()).keep(); // Parse true-side
+ // Parse true-side flavor
+ Node lhs = switch( fside ) {
+ case "else" -> parseStatement(); // if( pred ) stmts;
+ case ":" -> parseAsgn(); // pred ? asgn;
+ case "&&" -> parseLogical(); // pred && expr
+ case "||" -> pred; // pred || expr_is_ignored
+ default -> throw Utils.TODO();
+ };
+ lhs.keep();
_scope.removeGuards(ifT);
// See if a one-sided def was made: "if(pred) int x = 1;" and throw.
@@ -557,17 +579,23 @@ public class Parser {
// Up-cast predicate, even if not else clause, because predicate can
// remain true if the true clause exits: `if( !ptr ) return 0; return ptr.fld;`
_scope.addGuards(ifF,pred,true);
- boolean doRHS = match(fside);
- Node rhs = (doRHS
- ? (stmt ? parseStatement() : parseAsgn())
- : con(lhs._type.makeZero())).keep();
+ // Parse false-side flavor
+ boolean doRHS = false; // RHS is optional for if/else and trinary
+ Node rhs = switch( fside ) {
+ case "else" -> (doRHS=match(fside)) ? parseStatement() : con(lhs._type.makeZero());
+ case ":" -> (doRHS=match(fside)) ? parseAsgn() : con(lhs._type.makeZero());
+ case "&&" -> rhs = pred;
+ case "||" -> rhs = parseLogical();
+ default -> throw Utils.TODO();
+ };
+ rhs.keep();
_scope.removeGuards(ifF);
if( doRHS )
fScope = _scope;
pred.unkeep();
// Check the trinary widening int/flt
- if( !stmt ) {
+ if( !fside.equals("else") ) {
rhs = widenInt( rhs.unkeep(), lhs._type ).keep();
lhs = widenInt( lhs.unkeep(), rhs._type ).keep();
}
@@ -581,10 +609,10 @@ public class Parser {
// Merge results
RegionNode r = ctrl(tScope.mergeScopes(fScope,loc()));
- Node ret = peep(new PhiNode("",lhs._type.meet(rhs._type),r,lhs.unkeep(),rhs.unkeep()));
+ Node ret = peep(new PhiNode("",lhs._type.meet(rhs._type).glb(false),r,lhs.unkeep(),rhs.unkeep()));
// Immediately fail e.g. `arg ? 7 : ptr`
ParseException err;
- if( !stmt && (err=ret.err()) !=null ) throw err;
+ if( !fside.equals("else") && (err=ret.err()) !=null ) throw err;
r.peephole();
return ret;
}
@@ -621,27 +649,37 @@ public class Parser {
private Node parseAsgn() {
int old = pos();
String name = _lexer.matchId();
+ int old_pre_equals = pos();
// Just a plain expression, no assignment.
// Distinguish `var==expr` from `var=expr`
if( name==null || KEYWORDS.contains(name) || !matchOpx('=','=') )
{ pos(old); return parseExpression(); }
- // Parse assignment expression
- Node expr = parseAsgn();
-
- // Final variable to update
+ // Find variable to update
Var def = _scope.lookup(name);
if( def==null )
throw error("Undefined name '" + name + "'");
+ // If a method var, allow nested blocks and methods, but not fcns or other structs.
+ // Else safety check for accessing fields out of function scope.
+ if( instance(def) ) {
+ pos(old_pre_equals); // setup for `self.name = expr`
+ Node self = _scope.in(_scope.lookup("self")); // Insert self reference
+ return parsePostfixName(self,name);
+ }
+
// TOP fields are for late-initialized fields; these have never
// been written to, and this must be the final write. Other writes
// outside the constructor need to check the final bit.
if( _scope.in(def._idx)._type!=Type.TOP && def._final &&
- // Inside a constructor, final assign is OK, outside nope
- !(_scope.inConstructor() && def._idx >= _scope._lexSize.last()) )
+ // Inside an allocation, final assign is OK, outside nope.
+ // The alloc() call added the allocation scope
+ !(_scope.inAllocation() && def._idx >= _scope._kinds.last(-1)._lexSize) )
throw error("Cannot reassign final '"+name+"'");
+ // Parse assignment expression
+ Node expr = parseAsgn();
+
// Lift expression, based on type
Node lift = liftExpr(expr.keep(), def.type(), def._final, true);
// Update
@@ -653,7 +691,7 @@ public class Parser {
// Make finals deep; widen ints to floats; narrow wide int types.
// Early error if types do not match variable.
private Node liftExpr( Node expr, Type t, boolean xfinal, boolean isLoad ) {
- if( expr._type instanceof TypeMemPtr tmp && tmp.isFRef() )
+ if( expr._type instanceof TypeMemPtr tmp && TYPES.get(tmp._obj._name).isFRef() )
throw error("Must define forward ref "+tmp._obj._name);
// Final is deep on ptrs
if( xfinal && t instanceof TypeMemPtr tmp ) {
@@ -662,7 +700,7 @@ public class Parser {
}
// Auto-widen array to i64 (cast ptr to raw int bits)
if( t == TypeInteger.BOT && expr._type instanceof TypeMemPtr tmp && tmp._obj.isAry() )
- expr = peep(new AddNode(peep(new CastNode(t,ctrl(),expr)),con(tmp._obj.aryBase())));
+ expr = peep(new AddNode(peep(new CastNode(t,ctrl(),expr)),off(tmp._obj,"[]")));
// Auto-widen int to float
expr = widenInt( expr, t );
// Auto-narrow wide ints to narrow ints. For loads, emit code to force
@@ -674,7 +712,7 @@ public class Parser {
// Type is sane
if( et!=Type.BOTTOM && !et.shallowISA(t) )
- throw error("Type " + et.str() + " is not of declared type " + t.str());
+ expr = peep(new CastNode(t,null,expr));
return expr;
}
@@ -715,6 +753,7 @@ public class Parser {
String name = requireId();
// Optional initializing expression follows
boolean xfinal = false;
+ boolean fld_final = false; // Field is final, but not deeply final
Node expr;
if( match("=") ) {
expr = isExternDecl()
@@ -722,14 +761,18 @@ public class Parser {
: parseAsgn();
// TOP means val and val is always final
xfinal = (t==Type.TOP) ||
+ expr instanceof ExternNode ||
// BOTTOM is var and var is always not-final
(t!=Type.BOTTOM &&
// no Bang AND
!hasBang &&
+ // Locals are not-final by default
+ !_scope.inFunction() &&
// not-null (expecting null to be set to not-null)
expr._type != Type.NIL &&
// Pointers are final by default; int/flt are not-final by default.
(t instanceof TypeNil));
+
// var/val, then type comes from expression
if( inferType ) {
if( expr._type==Type.NIL )
@@ -760,11 +803,15 @@ public class Parser {
// the constructor and that's when we'll discover the type.
case Type tt -> { assert tt==Type.BOTTOM; yield con(tt); }
};
+ // Nullable fields are set in the constructor, but remain shallow final.
+ // e.g. final pointer to a r/w array
+ if( t instanceof TypeNil tn && !tn.nullable() && !hasBang )
+ fld_final = true;
}
// Lift expression, based on type
Node lift = liftExpr(expr, t, xfinal, true);
-
+ // Rebuild the deep RO 't', not returned from liftExpr
if( xfinal && t instanceof TypeMemPtr tmp )
t = tmp.makeRO();
@@ -773,7 +820,7 @@ public class Parser {
if( !lift._type.isa(t) )
lift = peep(new CastNode(t,null,lift));
// Define a new name
- if( !_scope.define(name,t,xfinal,lift, loc) )
+ if( !_scope.define(name,t,xfinal || fld_final,lift, loc) )
throw error("Redefining name '" + name + "'", loc);
return lift;
}
@@ -793,30 +840,46 @@ public class Parser {
String typeName = requireId();
if( old!=null ) typeName = old+"."+typeName;
_nestedType = typeName;
+ // New declared or forward-ref type
+ TypeStruct ts = TYPES.get(typeName) instanceof TypeMemPtr tmp ? tmp._obj : TypeStruct.open(typeName);
+ TYPES.put(typeName,TypeMemPtr.make(ts));
// A Block scope parse, and inspect the scope afterward for fields.
- _scope.push(ScopeNode.Kind.Constructor);
+ _scope.push(new Kind.Define(TypeMemPtr.make(ts)));
require("{");
- while (!peek('}') && !_lexer.isEOF())
+ int lexlen = _scope._kinds.last()._lexSize, nvar=lexlen;
+ while (!peek('}') && !_lexer.isEOF()) {
parseStatement().isKill();
+ while( nvar < _scope._vars._len ) {
+ Var v = _scope.var(nvar++);
+ if( !v.isFRef() ) {
+ ts = ts.add( Field.make( v._name, v.type(), _code.getALIAS(), v._final, v._final && _scope.in( v._idx )._type != Type.TOP ) );
+ TYPES.put( typeName, TypeMemPtr.make( ts ) );
+ }
+ }
+ }
- // Grab the declarations and build fields and a Struct
- int lexlen = _scope._lexSize.last();
+ // Count struct declarations
int varlen = _scope._vars._len;
- StructNode s = new StructNode();
- Ary<Field> fs = new Ary<>(Field.class);
- for( int i=lexlen; i<varlen; i++ ) {
- Var v = _scope.var(i);
- if( v.isFRef() ) continue; // Promote to outer scope, not defined here
- s.addDef(_scope.in(i)); // Keep the program code to generate instance
- fs.push(Field.make(v._name,v.type(),_code.getALIAS(),v._final));
- }
+ ts = ts.close();
+ TYPES.put(typeName,TypeMemPtr.make(ts));
+
+ // Generate an initializing struct
+ StructNode s = new StructNode(ts);
+ for( int i=lexlen; i<varlen; i++ )
+ if( !_scope.var(i).isFRef() ) // Promote to outer scope, not defined here
+ s.addDef(_scope.in(i)); // Keep the program code to generate instance
+
// Save instance default constructor
- TypeStruct ts = s._ts = TypeStruct.make(typeName, fs.asAry());
s.setType(s.compute()); // Do not call peephole, in case the entire struct is a big plain constant
- TYPES.put(typeName, TypeMemPtr.make(ts));
INITS.put(typeName,s.keep());
+ // Having finalized the struct, upgrade all the 'self' pointers
+ for( Node n : s._inputs )
+ if( n._type instanceof TypeFunPtr tfp && _code.link(tfp) instanceof FunNode fun )
+ _code.addAll( fun._outputs );
+
+
// Done with struct/block scope
_nestedType = old;
require("}");
@@ -861,7 +924,7 @@ public class Parser {
}
// Still no type found? Assume forward reference
- Type t1 = t0 == null ? TypeMemPtr.make(TypeStruct.makeFRef(tname)) :t0; // Null: assume a forward ref type
+ Type t1 = t0 == null ? TypeMemPtr.make(TypeStruct.open(tname)) :t0; // Null: assume a forward ref type
// Nest arrays and '?' as needed
Type t2 = t1;
while( true ) {
@@ -871,10 +934,9 @@ public class Parser {
if( tmp.nullable() ) throw error("Type "+t2+" already allows null");
t2 = tmp.makeNullable();
} else if( match("[~]") ) {
- TypeMemPtr tmp = typeAry(t2);
- t2 = tmp.makeFrom(tmp._obj.makeRO());
+ t2 = typeAry(t2,true);
} else if( match("[]") ) {
- t2 = typeAry(t2);
+ t2 = typeAry(t2,false);
} else
break;
}
@@ -896,17 +958,18 @@ public class Parser {
}
// Make an array type of t
- private TypeMemPtr typeAry( Type t ) {
+ private TypeMemPtr typeAry( Type t, boolean efinal ) {
if( t instanceof TypeMemPtr tmp && tmp.notNull() )
throw error("Arrays of reference types must always be nullable");
- String tname = "["+t.str()+"]";
- Type ta = TYPES.get(tname);
- if( ta != null ) return (TypeMemPtr)ta;
- TypeStruct ts = TypeStruct.makeAry(tname,TypeInteger.U32,_code.getALIAS(),t,_code.getALIAS());
- assert ts.str().equals(tname);
- TypeMemPtr tary = TypeMemPtr.make(ts);
- TYPES.put(tname,tary);
- return tary;
+ String tname = "[]"+t.str();
+ TypeMemPtr ta = (TypeMemPtr)TYPES.get(tname);
+ if( ta==null )
+ // Remember final version
+ TYPES.put(tname, ta = TypeMemPtr.make( TypeStruct.makeAry(tname,TypeInteger.U32,_code.getALIAS(),t,_code.getALIAS(),true) ));
+ Field elem = ta._obj.field("[]");
+ if( elem._final == efinal )
+ return ta;
+ return TypeMemPtr.make( ta._obj.replace(elem.makeFrom(efinal)));
}
// A function type is `{ type... -> type }` or `{ type }`.
@@ -916,7 +979,7 @@ public class Parser {
Type t0 = type(); // Either return or first arg
if( t0==null ) return posT(old); // Not a function
if( match("}") ) // No-arg function { -> type }
- return TypeFunPtr.make(match("?"),TypeTuple.BOT,t0);
+ return TypeFunPtr.make(match("?"),false,TypeFunPtr.TEMPTY,t0);
Ary<Type> ts = new Ary<>(Type.class);
ts.push(t0); // First argument
while( true ) {
@@ -924,7 +987,7 @@ public class Parser {
Type ret = type();
if( ret==null || !match("}") )
return posT(old); // Not a function
- return TypeFunPtr.make(match("?"),TypeTuple.make(ts.asAry()),ret);
+ return TypeFunPtr.make(match("?"),false,ts.asAry(),ret);
}
Type t1 = type();
if( t1==null ) return posT(old); // Not a function
@@ -949,8 +1012,8 @@ public class Parser {
* @return an expression {@link Node}, never {@code null}
*/
private Node parseExpression() {
- Node expr = parseBitwise();
- return match("?") ? parseTrinary(expr,false,":") : expr;
+ Node expr = parseLogical();
+ return match("?") ? parseTrinary(expr,":") : expr;
}
/**
@@ -961,13 +1024,25 @@ public class Parser {
* </pre>
* @return a bitwise expression {@link Node}, never {@code null}
*/
+
+ private Node parseLogical() {
+ Node lhs = parseBitwise();
+ while (true) {
+ if( false ) ;
+ else if( match("&&") ) lhs = parseTrinary(lhs, "&&");
+ else if( match("||") ) lhs = parseTrinary(lhs, "||");
+ else break;
+ }
+ return lhs;
+ }
+
private Node parseBitwise() {
Node lhs = parseComparison();
while( true ) {
if( false ) ;
- else if( match("&") ) lhs = new AndNode(loc(),lhs,null);
- else if( match("|") ) lhs = new OrNode(loc(),lhs,null);
- else if( match("^") ) lhs = new XorNode(loc(),lhs,null);
+ else if( matchOp('&') ) lhs = new AndNode(loc(),lhs,null);
+ else if( matchOp('|') ) lhs = new OrNode(loc(),lhs,null);
+ else if( match ("^") ) lhs = new XorNode(loc(),lhs,null);
else break;
lhs.setDef(2,parseComparison());
lhs = peep(lhs);
@@ -1103,14 +1178,17 @@ public class Parser {
}
if (match("-")) return peep(new MinusNode(parseUnary()).widen());
if (match("!")) return peep(new NotNode(parseUnary()));
- return parsePostfix(parsePrimary());
+ // Else be a primary expression
+ return parsePrimary();
}
/**
* Parse a primary expression:
*
* <pre>
- * primaryExpr : integerLiteral | true | false | null | new Type | '(' expression ')' | Id['++','--']
+ * primaryExpr : integerLiteral | "string" | 'char' | true | false | null |
+ * new Type | '(' expression ')' | Id['++','--'] |
+ * [static.]* Id
* </pre>
* @return a primary {@link Node}, never {@code null}
*/
@@ -1121,43 +1199,96 @@ public class Parser {
if( matchx("false") ) return ZERO;
if( matchx("null" ) ) return NIL;
if( match ("'" ) ) return parseChar();
- if( match ("(" ) ) return require(parseAsgn(), ")");
- if( matchx("new" ) ) return alloc();
- if( match ("{" ) ) return require(func(),"}");
+ if( match ("(" ) ) return parsePostfix(require(parseAsgn(), ")"));
+ if( matchx("new" ) ) return parsePostfix(alloc());
+ if( match ("{" ) ) return parsePostfix(require(func(),"}"));
// Parse static variable lookup: `type.fld` in the type namespace
+ // CNC: not a full type parse, just a typename parse
+ int pos = pos();
Type t = type();
- if( t!=null && match(".") ) {
- String fld = requireId();
- TypeMemPtr tmp = ((TypeMemPtr)t);
- String tname = tmp._obj._name;
- StructNode init = INITS.get(tname);
- int idx = tmp._obj.find(fld);
- if( idx == -1 )
- throw error("Accessing unknown STATIC field");
- return init.in(idx);
+ if( t!=null ) {
+ if( peek('.') )
+ return parsePostfix(con(t));
+ //pos(pos); // TODO: not a `type.fld`
+ //return null;
+ throw Utils.TODO();
}
// Expect an identifier now
- Var n = requireLookupId();
- Node rvalue = _scope.in(n);
+
+ // - if null, make fref, normal var handling
+ // - if final constant, normal var handling
+ // - if method var, scan skipping blocks & methods, must hit correct struct no fcns
+ // - if normal var, scan skipping blocks, allowing last fcn
+ // - NO fcns nested in methods, NO methods nested in fcns
+
+ String id = _lexer.matchId();
+ if( id == null || KEYWORDS.contains(id) )
+ throw errorSyntax("an identifier or expression");
+ Var var = _scope.lookup(id);
+
+ if( var==null ) {
+ // If missing, assume a forward reference
+ _scope.define(id, FRefNode.FREF_TYPE, true, XCTRL, loc());
+ var = _scope.lookup(id);
+ }
+
+ // If a method var, allow nested blocks and methods, but not fcns or other structs.
+ // Else safety check for accessing fields out of function scope.
+ if( instance(var) ) {
+ Node self = _scope.in(_scope.lookup("self")); // Insert self reference
+ return parsePostfixName(self,id);
+ }
+
+ // Load local value
+ Node rvalue = _scope.in(var);
if( rvalue._type == Type.BOTTOM )
- if( rvalue instanceof FRefNode ) return rvalue;
- else throw error("Cannot read uninitialized field '"+n._name+"'");
+ if( rvalue instanceof FRefNode )
+ return parsePostfix(rvalue);
+ else throw error("Cannot read uninitialized field '"+id+"'");
+
// Check for assign-update, x += e0;
char ch = _lexer.matchOperAssign();
- if( ch==0 ) return rvalue;
- Node op = opAssign(ch,rvalue,n._final,n.type(),n._name);
- _scope.update(n,op);
+ if( ch==0 ) // Normal primary, check for postfix updates
+ return parsePostfix(rvalue);
+ // Assign-update direct into Scope
+ Node op = opAssign(ch,rvalue, var.type() );
+ _scope.update(var,op);
return postfix(ch) ? rvalue.unkeep() : op;
}
+ // true if instance variable lookup (var is in any number of nested blocks,
+ // then an instance function then inside a struct declaration).
+ private boolean instance(Var var ) {
+ // If a method var, allow nested blocks and methods, but not fcns or other structs
+ Kind kind = _scope.kind(var);
+ if( kind instanceof Kind.Define ) {
+ for( int i = _scope.depth()-1; i>=0 && var._idx < _scope._kinds.at(i)._lexSize; i-- ) {
+ Kind xkind = _scope._kinds.at(i);
+ if( xkind instanceof Kind.Block ) continue;
+ if( xkind instanceof Kind.Func ) {
+ if( _scope._kinds.at(i-1)==kind )
+ return true; // Instance variable: lookup in a method in a decl
+ }
+ throw Utils.TODO();
+ }
+ } else {
+ // If a normal var, allow any nested blocks, and a last fcn -
+ // but not functions further out (which involves capture).
+ Node def = _scope.in(var._idx);
+ for( int i = _scope.depth()-1; i>=0 && var._idx < _scope._kinds.at(i)._lexSize; i-- )
+ if( _scope._kinds.at(i) instanceof Kind.Func &&
+ !(def instanceof FRefNode) && !(var._final && def._type.isConstant()) )
+ throw error("Variable '"+var._name+"' is out of function scope and must be a final constant");
+ }
+ return false;
+ }
+
// Check for assign-update, "x += e0".
// Returns "x + e0"; the caller assigns value.
// if ch is postfix, then lhs is kept and caller will unkeep and return it.
- private Node opAssign(char ch, Node lhs, boolean xfinal, Type t, String name ) {
- if( xfinal )
- throw error("Cannot reassign final '"+name+"'");
+ private Node opAssign( char ch, Node lhs, Type t ) {
// RHS of the update.
lhs.keep(); // Alive across parseAsgn
Node rhs =
@@ -1184,30 +1315,6 @@ public class Parser {
}
- // Expect an ID here. If not found, assume a forward reference function
- Var requireLookupId() {
- // Try in the normal variable namespace
- String id = _lexer.matchId();
- if( id == null || KEYWORDS.contains(id) )
- throw errorSyntax("an identifier or expression");
- Var n = _scope.lookup(id);
- // If missing, assume a forward reference
- if( n==null ) {
- _scope.define(id, FRefNode.FREF_TYPE, true, XCTRL, loc());
- n = _scope.lookup(id);
- } else {
- // Lookup worked on an out-of-function value.
- if( _scope.outOfFunction(n) ) {
- // No closures, so this has to be a final constant (which
- // includes forward refs)
- Node def = _scope.in(n._idx);
- if( !(def instanceof FRefNode) && !(n._final && def._type.isConstant()) )
- throw error("Variable '"+n._name+"' is out of function scope and must be a final constant");
- }
- }
- return n;
- }
-
/**
Parse an allocation
*/
@@ -1222,7 +1329,7 @@ public class Parser {
if( !(len._type instanceof TypeInteger) )
throw error("Cannot allocate an array with length "+len._type);
require("]");
- TypeMemPtr tmp = typeAry(t);
+ TypeMemPtr tmp = typeAry(t,false);
return newArray(tmp._obj,len);
}
@@ -1241,19 +1348,23 @@ public class Parser {
if( hasConstructor ) {
idx = _scope.nIns();
// Push a scope, and pre-assign all struct fields.
- _scope.push(ScopeNode.Kind.Block);
+ _scope.push(new Kind.Block());
Lexer loc = loc();
for( int i=0; i<fs.length; i++ )
- _scope.define(fs[i]._fname, fs[i]._type, fs[i]._final, s.in(i)._type==Type.TOP ? con(Type.BOTTOM) : s.in(i), loc);
+ // An initial TOP means the field needs to be initialized. We
+ // store a BOT initially; any partial init will fall to BOT
+ // (merge BOT and the partial) and be obviously only a partial
+ // init. To be initialized the field needs a full clobber.
+ _scope.define(fs[i]._fname, fs[i]._t, fs[i]._final, s.in(i)._type==Type.TOP ? con(Type.BOTTOM) : s.in(i), loc);
// Parse the constructor body
- require(parseBlock(ScopeNode.Kind.Constructor),"}");
+ require(parseBlock(new Kind.Alloc(tmp)),"}");
init = _scope._inputs;
}
// Check that all fields are initialized
for( int i=idx; i<init.size(); i++ )
if( init.at(i)._type == Type.TOP || init.at(i)._type == Type.BOTTOM )
throw error("'"+tmp._obj._name+"' is not fully initialized, field '" + fs[i-idx]._fname + "' needs to be set in a constructor");
- Node ptr = newStruct(tmp._obj, con(tmp._obj.offset(fs.length)), idx, init );
+ Node ptr = newStruct(tmp._obj, off(tmp._obj, " len"), idx, init );
if( hasConstructor )
_scope.pop();
return ptr;
@@ -1276,18 +1387,20 @@ public class Parser {
ns[1] = size;
// Memory aliases for every field
for( int i = 0; i < len; i++ )
- ns[2+i] = memAlias(fs[i]._alias);
+ if( !fs[i]._one )
+ ns[2+i] = memAlias(fs[i]._alias);
Node nnn = new NewNode(TypeMemPtr.make(obj), ns).peephole().keep();
for( int i = 0; i < len; i++ )
- memAlias(fs[i]._alias, new ProjNode(nnn,i+2,memName(fs[i]._alias)).peephole());
+ if( !fs[i]._one )
+ memAlias(fs[i]._alias, new ProjNode(nnn,i+2,memName(fs[i]._alias)).peephole());
Node ptr = new ProjNode(nnn.unkeep(),1,obj._name).peephole().keep();
// Initial nonzero values for every field
for( int i = 0; i < len; i++ ) {
Node val = init.get( i + idx );
- if( val._type != val._type.makeZero() ) {
+ if( !fs[i]._one && val._type != val._type.makeZero() ) {
Node mem = memAlias(fs[i]._alias);
- Node st = new StoreNode(loc(),fs[i]._fname,fs[i]._alias,fs[i]._type,mem,ptr,con(obj.offset(i)),val,true).peephole();
+ Node st = new StoreNode(loc(),fs[i]._fname,fs[i]._alias,fs[i]._t,mem,ptr,off(obj,fs[i]._fname),val,true).peephole();
memAlias(fs[i]._alias,st);
}
}
@@ -1297,14 +1410,14 @@ public class Parser {
private static final Ary<Node> ALTMP = new Ary<>(Node.class);
private Node newArray(TypeStruct ary, Node len) {
- int base = ary.aryBase ();
+ ConFldOffNode base = off(ary, "[]");
int scale= ary.aryScale();
- Node size = peep(new AddNode(con(base),peep(new ShlNode(null,len.keep(),con(scale)))));
- ALTMP.clear(); ALTMP.add(len.unkeep()); ALTMP.add(con(ary._fields[1]._type.makeZero()));
+ Node size = peep(new AddNode(base,peep(new ShlNode(null,len.keep(),con(scale)))));
+ ALTMP.clear(); ALTMP.add(len.unkeep()); ALTMP.add(con(ary._fields[1]._t.makeZero()));
return newStruct(ary,size,0,ALTMP);
}
private Node newString(String s) {
- TypeMemPtr tmp = typeAry(TypeInteger.U8);
+ TypeMemPtr tmp = typeAry(TypeInteger.U8,true);
int lenAlias = tmp._obj.field("#" )._alias;
int elemAlias = tmp._obj.field("[]")._alias;
TypeConAryB con = TypeConAryB.make(s);
@@ -1312,7 +1425,8 @@ public class Parser {
// Make a TMP, not-null (byte)2, singleton (true) (requires text
// strings are hash-interned), with a TypeStruct having a constant
// array body.
- TypeMemPtr str = TypeMemPtr.make((byte)2,TypeStruct.makeAry("[u8]", TypeInteger.U32, lenAlias, elem, elemAlias, true, con),true);
+ TypeMemPtr str = TypeMemPtr.make((byte)2,TypeStruct.makeAry("[]u8", TypeInteger.constant(s.length()), lenAlias, con, elemAlias, true),true);
+ assert str.isConstant();
return con(str);
}
@@ -1341,9 +1455,24 @@ public class Parser {
if( match(".") ) name = requireId();
else if( match("#") ) name = "#";
else if( match("[") ) name = "[]";
- else if( match("(") ) return parsePostfix(require(functionCall(expr),")"));
+ else if( match("(") ) return parsePostfix(require(functionCall(expr,null),")"));
else return expr; // No postfix
+ return parsePostfixName(expr,name);
+ }
+
+ /**
+ * Parse postfix expression; this can be a field expression, an array
+ * lookup or a postfix operator like '#'
+ *
+ * <pre>
+ * expr ['++' | '--' ] // Postfix unary write operator
+ * expr [ [op]= expr ] // Field reference
+ * expr ('[' expr ']')* [ [op]= expr ] // Array reference
+ * </pre>
+ */
+ private Node parsePostfixName(Node expr, String name) {
+
if( expr._type==Type.NIL )
throw error("Accessing unknown field '" + name + "' from 'null'");
@@ -1352,23 +1481,25 @@ public class Parser {
throw error( "Expected "+(name=="#" || name=="[]" ? "array" : "reference")+" but found " + expr._type.str() );
// Find the field from the Type. Lookup in the base object field names.
+ TypeMemPtr ptr2 = (TypeMemPtr)TYPES.get(ptr._obj._name);
+ ptr = (TypeMemPtr)ptr.join(ptr2);// Upgrade to latest TYPES
TypeStruct base = ptr._obj;
- assert !base.isFRef();
int fidx = base.find(name);
- if( fidx == -1 ) throw error("Accessing unknown field '" + name + "' from '" + ptr.str() + "'");
+ if( fidx == -1 )
+ throw error("Accessing unknown field '" + name + "' from '" + ptr.str() + "'");
// Get field type and layout offset from base type and field index fidx
Field f = base._fields[fidx]; // Field from field index
- Type tf = f._type;
+ Type tf = f._t;
if( tf instanceof TypeMemPtr ftmp && ftmp.isFRef() )
tf = ftmp.makeFrom(((TypeMemPtr)(TYPES.get(ftmp._obj._name)))._obj);
// Field offset; fixed for structs, computed for arrays
Node off = (name.equals("[]") // If field is an array body
// Array index math
- ? peep(new AddNode(con(base.aryBase()),peep(new ShlNode(null,require(parseAsgn(),"]"),con(base.aryScale())))))
+ ? peep(new AddNode(off(base,"[]"),peep(new ShlNode(null,require(parseAsgn(),"]"),con(base.aryScale())))))
// Struct field offsets are hardwired
- : con(base.offset(fidx))).keep();
+ : off(base,name)).keep();
// Disambiguate "obj.fld==x" boolean test from "obj.fld=x" field assignment
if( matchOpx('=','=') ) {
@@ -1384,7 +1515,12 @@ public class Parser {
return val.unkeep(); // "obj.a = expr" returns the expression while updating memory
}
- Node load = new LoadNode(loc(),name, f._alias, tf, memAlias(f._alias), expr.keep(), off);
+ // Keep expr for possible store update
+ expr.keep();
+ // Load field
+ Node load = f._one && INITS.containsKey( base._name )
+ ? INITS.get(base._name).in(base.find(name))
+ : new LoadNode(loc(),name, f._alias, tf, memAlias(f._alias), expr, off);
// Arrays include control, as a proxy for a safety range check
// Structs don't need this; they only need a NPE check which is
// done via the type system.
@@ -1394,8 +1530,8 @@ public class Parser {
// Check for assign-update, "ptr.fld += expr" or "ary[idx]++"
char ch = _lexer.matchOperAssign();
if( ch!=0 ) {
- Node op = opAssign(ch,load,f._final,tf,name);
- Node st = new StoreNode(loc(), name, f._alias, tf, memAlias(f._alias), expr.unkeep(), off, op, false);
+ Node op = opAssign(ch,load, tf );
+ Node st = new StoreNode(loc(), name, f._alias, tf, memAlias(f._alias), expr.unkeep(), off.unkeep(), op, false);
// Arrays include control, as a proxy for a safety range check.
// Structs don't need this; they only need a NPE check which is
// done via the type system.
@@ -1403,8 +1539,25 @@ public class Parser {
memAlias(f._alias, peep(st));
load = postfix(ch) ? load.unkeep() : op;
// And use the original loaded value as the result
- } else expr.unkill();
- off.unkill();
+ return load;
+ //throw Utils.TODO(); // NO POSTFIX AFTER STORE, JUST RETURN
+ } else {
+ off.unkill();
+ // Method call: Loaded a function from a named field, AND the base
+ // field type is final.
+ if( load._type instanceof TypeFunPtr && name!="[]" &&
+ !(load instanceof ExternNode) &&
+ ((TypeMemPtr)TYPES.get(base._name))._obj.field(name)._final &&
+ // And calling a function
+ match("(") ) {
+ return parsePostfix(require(functionCall(load,expr),")"));
+ }
+
+ // Drop expr, keeping load alive
+ load.keep();
+ expr.unkill();
+ load.unkeep();
+ }
return parsePostfix(load);
}
@@ -1440,6 +1593,17 @@ public class Parser {
private Node func() {
Ary<Type> ts = new Ary<>(Type.class);
Ary<String> ids = new Ary<>(String.class);
+
+ // Defined in constructor? Add `self` argument. "static" calls still
+ // add a `self` they just ignore it.
+ if( _scope._kinds.last() instanceof Kind.Define define ) {
+ // Upgrade defined struct to latest fields
+ TypeMemPtr tmp = (TypeMemPtr)TYPES.get(define._tmp._obj._name);
+ ts .push(tmp);
+ ids.push("self");
+ }
+
+ // Parse other arguments
_lexer.skipWhiteSpace();
Lexer loc = loc(); // First argument location
while( true ) {
@@ -1452,7 +1616,7 @@ public class Parser {
}
require("->");
// Make a concrete function type, with a fidx
- TypeFunPtr tfp = _code.makeFun(TypeTuple.make(ts.asAry()),Type.BOTTOM);
+ TypeFunPtr tfp = _code.makeFun(TypeFunPtr.make(false,false,ts.asAry(),Type.BOTTOM));
ReturnNode ret = parseFunctionBody(tfp,loc,ids.asAry());
return con(ret._fun.sig());
}
@@ -1463,16 +1627,18 @@ public class Parser {
* ( arg* )
* </pre>
*/
- private Node functionCall(Node expr) {
- if( expr._type == Type.NIL )
+ private Node functionCall(Node fcn, Node self) {
+ if( fcn._type == Type.NIL )
throw error("Calling a null function pointer");
- if( !(expr instanceof FRefNode) && !expr._type.isa(TypeFunPtr.BOT) )
- throw error("Expected a function but got "+expr._type.glb(false).str());
- expr.keep(); // Keep while parsing args
+ if( !(fcn instanceof FRefNode) && !fcn._type.isa(TypeFunPtr.BOT) )
+ throw error("Expected a function but got "+fcn._type.glb(false).str());
+ fcn.keep(); // Keep while parsing args
Ary<Node> args = new Ary<>( Node.class );
args.push(null); // Space for ctrl,mem
args.push(null);
+ if( self != null ) // Method call has a self
+ args.push(self);
while( !peek(')') ) {
Node arg = parseAsgn();
if( arg==null ) break;
@@ -1482,7 +1648,7 @@ public class Parser {
// Control & memory after parsing args
args.set(0,ctrl().keep());
args.set(1,_scope.mem().merge().keep());
- args.push(expr); // Function pointer
+ args.push(fcn); // Function pointer
// Unkeep them all
for( Node arg : args )
arg.unkeep();
@@ -1521,8 +1687,8 @@ public class Parser {
}
// External linked constant
private Node externDecl( String ex, Type t ) {
- if( t instanceof TypeFunPtr tfp ) // Generic TFP from type parse
- t = _code.makeFun(tfp._sig,tfp._ret); // Get a FIDX, becomes a constant
+ if( t instanceof TypeFunPtr tfp ) // Generic TFP from type parse
+ t = _code.makeFun(tfp); // Get a FIDX, becomes a constant
return new ExternNode(t,ex).peephole();
}
@@ -1537,6 +1703,7 @@ public class Parser {
private ConstantNode parseLiteral() { return con(_lexer.parseNumber()); }
public static Node con( long con ) { return con==0 ? ZERO : con(TypeInteger.constant(con)); }
public static ConstantNode con( Type t ) { return (ConstantNode)new ConstantNode(t).peephole(); }
+ public static ConFldOffNode off( TypeStruct base, String fname ) { return (ConFldOffNode)(new ConFldOffNode(base._name,fname).peephole()); }
public Node peep( Node n ) {
// Peephole, then improve with lexically scoped guards
return _scope.upcastGuard(n.peephole());
@@ -1565,6 +1732,7 @@ public class Parser {
private boolean match (String syntax) { return _lexer.match (syntax); }
// Match must be "exact", not be followed by more id letters
private boolean matchx(String syntax) { return _lexer.matchx(syntax); }
+ private boolean matchOp(char c0 ) { return _lexer.matchOp(c0); }
private boolean matchOpx(char c0, char c1) { return _lexer.matchOpx(c0,c1); }
// Return true and do NOT skip if 'ch' is next
private boolean peek(char ch) { return _lexer.peek(ch); }
@@ -1740,6 +1908,16 @@ public class Parser {
_position -= syntax.length();
return false;
}
+ // Match this char, and the next char must be different.
+ // Handles '&&' vs '&'
+ boolean matchOp( char c0 ) {
+ skipWhiteSpace();
+ if( _position+1 >= _input.length || _input[_position]!=c0 || _input[_position+1]==c0 )
+ return false;
+ inc();
+ return true;
+ }
+ // Match these two characters in a row
boolean matchOpx(char c0, char c1) {
skipWhiteSpace();
if( _position+1 >= _input.length || _input[_position]!=c0 || _input[_position+1]==c1 )
@@ -1861,4 +2039,5 @@ public class Parser {
//String msg = "src:"+_line_number+":"+(_position-_line_start)+" "+errorMessage;
ParseException( String msg, Lexer loc ) { super(msg); _loc = loc; }
}
+
}
diff --git a/src/main/java/com/seaofnodes/simple/codegen/Coalesce.java b/src/main/java/com/seaofnodes/simple/codegen/Coalesce.java
index e2fac779..689ceceb 100644
--- a/src/main/java/com/seaofnodes/simple/codegen/Coalesce.java
+++ b/src/main/java/com/seaofnodes/simple/codegen/Coalesce.java
@@ -1,8 +1,8 @@
package com.seaofnodes.simple.codegen;
-import com.seaofnodes.simple.Ary;
-import com.seaofnodes.simple.Utils;
import com.seaofnodes.simple.node.*;
+import com.seaofnodes.simple.util.Ary;
+import com.seaofnodes.simple.util.Utils;
import java.util.BitSet;
import java.util.IdentityHashMap;
diff --git a/src/main/java/com/seaofnodes/simple/codegen/CodeGen.java b/src/main/java/com/seaofnodes/simple/codegen/CodeGen.java
index adb71413..6c958f32 100644
--- a/src/main/java/com/seaofnodes/simple/codegen/CodeGen.java
+++ b/src/main/java/com/seaofnodes/simple/codegen/CodeGen.java
@@ -1,13 +1,14 @@
package com.seaofnodes.simple.codegen;
-import com.seaofnodes.simple.*;
+import com.seaofnodes.simple.IterPeeps;
+import com.seaofnodes.simple.Parser;
import com.seaofnodes.simple.node.*;
import com.seaofnodes.simple.print.*;
import com.seaofnodes.simple.type.*;
+import com.seaofnodes.simple.util.Ary;
+import com.seaofnodes.simple.util.SB;
import java.io.IOException;
-import java.util.BitSet;
-import java.util.HashMap;
-import java.util.IdentityHashMap;
+import java.util.*;
@SuppressWarnings("unchecked")
public class CodeGen {
@@ -37,9 +38,13 @@ public class CodeGen {
public final TypeInteger _arg;
// ---------------------------
- public CodeGen( String src ) { this(src, TypeInteger.BOT, 123L ); }
- public CodeGen( String src, TypeInteger arg, long workListSeed ) {
+ public CodeGen( String src ) { this(src, TypeInteger.BOT, 123L, true ); }
+ public CodeGen( String src, TypeInteger arg) { this(src, arg==null ? TypeInteger.BOT : arg, 123L, true ); }
+
+ public CodeGen( String src, TypeInteger arg, long workListSeed, boolean reset ) {
CODE = this;
+ if( reset ) Type.reset();
+ _main = makeFun(TypeFunPtr.MAIN);
_phase = null;
_callingConv = null;
_start = new StartNode(arg);
@@ -119,18 +124,15 @@ public class CodeGen {
// are structurally equal.
public final HashMap<Node,Node> _gvn = new HashMap<>();
- // Compute "function indices": FIDX.
- // Each new request at the same signature gets a new FIDX.
- private final HashMap<TypeTuple,Integer> FIDXS = new HashMap<>();
- public TypeFunPtr makeFun( TypeTuple sig, Type ret ) {
- Integer i = FIDXS.get(sig);
- int fidx = i==null ? 0 : i;
- FIDXS.put(sig,fidx+1); // Track count per sig
+ //
+ private int _fidx =0;
+ public TypeFunPtr makeFun( TypeFunPtr fun ) {
+ int fidx = _fidx++;
assert fidx<64; // TODO: need a larger FIDX space
- return TypeFunPtr.make((byte)2,sig,ret, 1L<<fidx );
+ return fun.makeFrom(fidx);
}
// Signature for MAIN
- public final TypeFunPtr _main = makeFun(TypeTuple.MAIN,Type.BOTTOM);
+ public final TypeFunPtr _main;
// Reverse from a constant function pointer to the IR function being called
public FunNode link( TypeFunPtr tfp ) {
assert tfp.isConstant();
@@ -186,24 +188,44 @@ public class CodeGen {
// Pessimistic peephole optimization on a worklist
_iter.iterate(this);
+ // OPTIMISTIC PASS GOES HERE
+
// Not really a true optimistic pass, but look for unlinked functions.
// This can be removed, which may trigger another round of pessimistic.
// This is the point where we flip from a virtual Call Graph (any call
// can call any function) to having a correct (but conservative) CG.
+ int progress = 0;
+ while( progress != _start.nOuts() ) {
+ progress = _start.nOuts();
+ FunNode main = link(_main);
+ for( int i=0; i<_start.nOuts(); i++ ) {
+ Node use = _start.out(i);
+ if( use instanceof FunNode fun &&
+ fun.nIns()==2 && fun.in(1)==_start && fun != main &&
+ (fun._name==null || fun._name.startsWith("sys.")) ) {
+ add(fun).setDef(1,Parser.XCTRL);
+ addAll(fun._outputs);
+ i--;
+ }
+ }
+ _iter.iterate(this);
+ }
- FunNode main = link(_main);
+ // Freeze field sizes; do struct layouts; convert field offsets into
+ // constants.
for( int i=0; i<_start.nOuts(); i++ ) {
Node use = _start.out(i);
- if( use instanceof FunNode fun &&
- fun.nIns()==2 && fun.in(1)==_start && fun != main &&
- (fun._name==null || fun._name.startsWith("sys.")) ) {
- add(fun).setDef(1,Parser.XCTRL);
- addAll(fun._outputs);
+ if( use instanceof ConFldOffNode off ) {
+ TypeMemPtr tmp = (TypeMemPtr) Parser.TYPES.get(off._name);
+ off.subsume( off.asOffset(tmp._obj) );
i--;
}
}
_iter.iterate(this);
+ // To help with testing, sort StopNode returns by NID
+ Arrays.sort(_stop._inputs._es,0,_stop.nIns(),(x,y) -> x._nid - y._nid );
+
_tOpto = (int)(System.currentTimeMillis() - t0);
// TODO:
@@ -212,7 +234,7 @@ public class CodeGen {
// loop unroll, peel, RCE, etc
return this;
}
- public <N extends Node> N add( N n ) { return (N)_iter.add(n); }
+ public <N extends Node> N add( N n ) { return _iter.add(n); }
public void addAll( Ary<Node> ary ) { _iter.addAll(ary); }
diff --git a/src/main/java/com/seaofnodes/simple/codegen/ElfFile.java b/src/main/java/com/seaofnodes/simple/codegen/ElfFile.java
index 0eaaae7b..8f9e2981 100644
--- a/src/main/java/com/seaofnodes/simple/codegen/ElfFile.java
+++ b/src/main/java/com/seaofnodes/simple/codegen/ElfFile.java
@@ -1,9 +1,10 @@
package com.seaofnodes.simple.codegen;
import com.seaofnodes.simple.*;
+import com.seaofnodes.simple.codegen.Encoding.BAOS;
import com.seaofnodes.simple.node.*;
import com.seaofnodes.simple.type.*;
-import com.seaofnodes.simple.codegen.Encoding.BAOS;
+import com.seaofnodes.simple.util.Ary;
import java.io.*;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
diff --git a/src/main/java/com/seaofnodes/simple/codegen/Encoding.java b/src/main/java/com/seaofnodes/simple/codegen/Encoding.java
index db799b98..1065cd9f 100644
--- a/src/main/java/com/seaofnodes/simple/codegen/Encoding.java
+++ b/src/main/java/com/seaofnodes/simple/codegen/Encoding.java
@@ -1,11 +1,11 @@
package com.seaofnodes.simple.codegen;
-import com.seaofnodes.simple.Ary;
-import com.seaofnodes.simple.SB;
-import com.seaofnodes.simple.Utils;
import com.seaofnodes.simple.node.*;
import com.seaofnodes.simple.print.IRPrinter;
import com.seaofnodes.simple.type.*;
+import com.seaofnodes.simple.util.Ary;
+import com.seaofnodes.simple.util.SB;
+import com.seaofnodes.simple.util.Utils;
import java.io.ByteArrayOutputStream;
import java.util.*;
@@ -45,6 +45,9 @@ public class Encoding {
public int [] _opStart; // Start of opcodes, by _nid
public byte[] _opLen; // Length of opcodes, by _nid
+ // Function headers now padded when printing
+ public boolean _padFunHeads;
+
// Big Constant relocation info.
public static class Relo {
public final Node _op;
@@ -290,6 +293,9 @@ public class Encoding {
// Fall/false into a full block, Jump/true to an empty block.
if( f.nOuts()>1 && t.nOuts()==1 ) return false;
if( t.nOuts()>1 && f.nOuts()==1 ) return true ;
+ // Jump to a merge point, assuming other things are jumping there as well
+ if( f.out(0) instanceof RegionNode ) return true ;
+ if( t.out(0) instanceof RegionNode ) return false;
// Everything else equal, use pre-order
return t._pre > f._pre;
}
@@ -397,7 +403,7 @@ public class Encoding {
if( n instanceof MachNode && !(n instanceof CFGNode) )
_opStart[n._nid] += slide;
}
-
+ _padFunHeads = true;
// Copy/slide the bits to make space for all the longer branches
int grow = _opStart[_code._cfg.at(len-1)._nid] - oldStarts[len-1];
@@ -414,6 +420,7 @@ public class Encoding {
}
_bits.set(bits,bits.length);
}
+
}
@@ -492,12 +499,11 @@ public class Encoding {
while( off < foff ) { bits.write(0); off++; };
// Constant array fields are special
if( f._fname=="[]" ) { // Must be a constant array
- ts._con.write(bits); // Write the constant array bits
- off += ts._con.len();
+ ((TypeConAry)f._t).write(bits);
+ off += ((TypeConAry)f._t).len();
} else {
- int log = f._type.log_size();
- if( f._fname=="#" ) addN(log,ts._con.len(),bits); // Must be a constant array
- else addN(log,f._type ,bits);
+ int log = f._t.log_size();
+ addN(log,f._t,bits);
off += 1<<log;
}
}
diff --git a/src/main/java/com/seaofnodes/simple/codegen/GlobalCodeMotion.java b/src/main/java/com/seaofnodes/simple/codegen/GlobalCodeMotion.java
index 04a119c2..d9c7a6ad 100644
--- a/src/main/java/com/seaofnodes/simple/codegen/GlobalCodeMotion.java
+++ b/src/main/java/com/seaofnodes/simple/codegen/GlobalCodeMotion.java
@@ -1,10 +1,10 @@
package com.seaofnodes.simple.codegen;
-import com.seaofnodes.simple.Ary;
import com.seaofnodes.simple.IterPeeps.WorkList;
-import com.seaofnodes.simple.Utils;
import com.seaofnodes.simple.node.*;
import com.seaofnodes.simple.type.*;
+import com.seaofnodes.simple.util.Ary;
+import com.seaofnodes.simple.util.Utils;
import java.util.*;
public abstract class GlobalCodeMotion {
@@ -36,7 +36,7 @@ public abstract class GlobalCodeMotion {
return; // Been there, done that
if( def instanceof ReturnNode && use instanceof CallEndNode )
return;
- assert !( def instanceof CallNode && use instanceof FunNode );
+ assert !( def instanceof CallNode && use instanceof FunNode ); // All calls unwired now
visit.set(cfg._nid);
for( Node useuse : cfg._outputs )
_rpo_cfg(cfg,useuse,visit,rpo);
diff --git a/src/main/java/com/seaofnodes/simple/codegen/IFG.java b/src/main/java/com/seaofnodes/simple/codegen/IFG.java
index fdd4e2f9..6dd6fbf1 100644
--- a/src/main/java/com/seaofnodes/simple/codegen/IFG.java
+++ b/src/main/java/com/seaofnodes/simple/codegen/IFG.java
@@ -1,8 +1,8 @@
package com.seaofnodes.simple.codegen;
-import com.seaofnodes.simple.Ary;
-import com.seaofnodes.simple.Utils;
import com.seaofnodes.simple.node.*;
+import com.seaofnodes.simple.util.Ary;
+import com.seaofnodes.simple.util.Utils;
import java.util.BitSet;
import java.util.IdentityHashMap;
diff --git a/src/main/java/com/seaofnodes/simple/codegen/LRG.java b/src/main/java/com/seaofnodes/simple/codegen/LRG.java
index ec254a2e..009ddcdb 100644
--- a/src/main/java/com/seaofnodes/simple/codegen/LRG.java
+++ b/src/main/java/com/seaofnodes/simple/codegen/LRG.java
@@ -1,10 +1,9 @@
package com.seaofnodes.simple.codegen;
-import com.seaofnodes.simple.Ary;
-import com.seaofnodes.simple.SB;
-import com.seaofnodes.simple.Utils;
import com.seaofnodes.simple.node.*;
-
+import com.seaofnodes.simple.util.Ary;
+import com.seaofnodes.simple.util.SB;
+import com.seaofnodes.simple.util.Utils;
import java.util.IdentityHashMap;
/** A Live Range
diff --git a/src/main/java/com/seaofnodes/simple/codegen/LinkMem.java b/src/main/java/com/seaofnodes/simple/codegen/LinkMem.java
index e1e849e6..2415203d 100644
--- a/src/main/java/com/seaofnodes/simple/codegen/LinkMem.java
+++ b/src/main/java/com/seaofnodes/simple/codegen/LinkMem.java
@@ -1,7 +1,7 @@
package com.seaofnodes.simple.codegen;
-import com.seaofnodes.simple.Utils;
import com.seaofnodes.simple.node.Node;
+import com.seaofnodes.simple.util.Utils;
// In-memory linking
public class LinkMem {
diff --git a/src/main/java/com/seaofnodes/simple/codegen/ListScheduler.java b/src/main/java/com/seaofnodes/simple/codegen/ListScheduler.java
index de4fadc4..ddf5a679 100644
--- a/src/main/java/com/seaofnodes/simple/codegen/ListScheduler.java
+++ b/src/main/java/com/seaofnodes/simple/codegen/ListScheduler.java
@@ -1,10 +1,10 @@
package com.seaofnodes.simple.codegen;
-import com.seaofnodes.simple.Ary;
import com.seaofnodes.simple.IterPeeps.WorkList;
-import com.seaofnodes.simple.Utils;
import com.seaofnodes.simple.node.*;
import com.seaofnodes.simple.type.*;
+import com.seaofnodes.simple.util.Ary;
+import com.seaofnodes.simple.util.Utils;
import java.util.*;
public abstract class ListScheduler {
diff --git a/src/main/java/com/seaofnodes/simple/codegen/RegAlloc.java b/src/main/java/com/seaofnodes/simple/codegen/RegAlloc.java
index 57d0d90c..da521082 100644
--- a/src/main/java/com/seaofnodes/simple/codegen/RegAlloc.java
+++ b/src/main/java/com/seaofnodes/simple/codegen/RegAlloc.java
@@ -1,7 +1,7 @@
package com.seaofnodes.simple.codegen;
-import com.seaofnodes.simple.Ary;
-import com.seaofnodes.simple.Utils;
+import com.seaofnodes.simple.util.Ary;
+import com.seaofnodes.simple.util.Utils;
import com.seaofnodes.simple.node.*;
import java.util.Arrays;
import java.util.BitSet;
@@ -398,8 +398,8 @@ public class RegAlloc {
// If the minLoopDepth is less than the maxLoopDepth: for-all defs and
// uses, if at minLoopDepth or lower, split after def and before use.
for( Node n : _ns ) {
- if( n instanceof SplitNode ) continue; // Ignoring splits; since spilling need to split in a deeper loop
- if( n.isDead() ) continue; // Some Clonable went dead by other spill changes
+ if( n instanceof SplitNode && min!=max ) continue; // Ignoring splits; since spilling need to split in a deeper loop
+ if( n.isDead() ) continue; // Some Cloneable went dead by other spill changes
// If this is a 2-address commutable op (e.g. AddX86, MulX86) and the rhs has only a single user,
// commute the inputs... which chops the LHS live ranges' upper bound to just the RHS.
if( n instanceof MachNode mach && lrg(n)==lrg && mach.twoAddress()==1 && mach.commutes() && n.in(2).nOuts()==1 )
diff --git a/src/main/java/com/seaofnodes/simple/codegen/RegMask.java b/src/main/java/com/seaofnodes/simple/codegen/RegMask.java
index ec0c4e30..c7dda1da 100644
--- a/src/main/java/com/seaofnodes/simple/codegen/RegMask.java
+++ b/src/main/java/com/seaofnodes/simple/codegen/RegMask.java
@@ -1,7 +1,7 @@
package com.seaofnodes.simple.codegen;
-import com.seaofnodes.simple.Utils;
-import com.seaofnodes.simple.SB;
+import com.seaofnodes.simple.util.SB;
+import com.seaofnodes.simple.util.Utils;
/** RegMask
* A "register mask" - 1 bit set for each allowed register. In addition,
diff --git a/src/main/java/com/seaofnodes/simple/node/AddNode.java b/src/main/java/com/seaofnodes/simple/node/AddNode.java
index 0f472829..c5ba14de 100644
--- a/src/main/java/com/seaofnodes/simple/node/AddNode.java
+++ b/src/main/java/com/seaofnodes/simple/node/AddNode.java
@@ -1,10 +1,7 @@
package com.seaofnodes.simple.node;
-import com.seaofnodes.simple.Parser;
import com.seaofnodes.simple.type.*;
-import java.util.BitSet;
-
import static com.seaofnodes.simple.Parser.con;
public class AddNode extends ArithNode {
@@ -129,7 +126,7 @@ public class AddNode extends ArithNode {
for( int i=1; i<ns.length; i++ )
ns[i] = op.copy(lphi.in(i), rhs instanceof PhiNode ? rhs.in(i) : rhs).peephole();
String label = lphi._label + (rhs instanceof PhiNode rphi ? rphi._label : "");
- Node phi = new PhiNode(label,lphi._declaredType,ns).peephole();
+ Node phi = new PhiNode(label,lphi._minType.meet(op._type),ns).peephole();
// Rotate needs another op, otherwise just the phi
return lhs==lphi ? phi : op.copy(lhs.in(1),phi);
}
@@ -151,8 +148,8 @@ public class AddNode extends ArithNode {
// Ties with in a category sort by node ID.
// TRUE if swapping hi and lo.
static boolean spine_cmp( Node hi, Node lo, Node dep ) {
- if( lo._type.isConstant() ) return false;
- if( hi._type.isConstant() ) return true ;
+ if( lo._type.isConstant() || lo instanceof ConFldOffNode ) return false;
+ if( hi._type.isConstant() || hi instanceof ConFldOffNode ) return true ;
if( lo instanceof PhiNode lphi && lphi.region()._type==Type.XCONTROL ) return false;
if( hi instanceof PhiNode hphi && hphi.region()._type==Type.XCONTROL ) return false;
diff --git a/src/main/java/com/seaofnodes/simple/node/ArithNode.java b/src/main/java/com/seaofnodes/simple/node/ArithNode.java
index 3e376418..96067c8e 100644
--- a/src/main/java/com/seaofnodes/simple/node/ArithNode.java
+++ b/src/main/java/com/seaofnodes/simple/node/ArithNode.java
@@ -1,9 +1,9 @@
package com.seaofnodes.simple.node;
import com.seaofnodes.simple.Parser;
-import com.seaofnodes.simple.Utils;
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeInteger;
+
import java.util.BitSet;
public abstract class ArithNode extends Node {
@@ -56,7 +56,10 @@ public abstract class ArithNode extends Node {
if( in(1) instanceof PhiNode lhs &&
in(2) instanceof PhiNode rhs &&
lhs.nIns() >= 2 && !lhs.inProgress() &&
- lhs.region()==rhs.region() ) {
+ lhs.region()==rhs.region() &&
+ lhs.nIns()>2 && // A 1-input Phi will collapse already
+ // Disallow with self-looping phi; these will collapse
+ (lhs.in(2)!=lhs && rhs.in(2)!=rhs) ) {
// Profit check: only 1 instance of `this` will remain, all the
// others will fold to constants.
int cnt=0;
@@ -73,7 +76,7 @@ public abstract class ArithNode extends Node {
: copy(lhs.in(i), rhs.in(i)).peephole();
}
String label = lhs._label==rhs._label ? lhs._label : lhs._label + rhs._label;
- return new PhiNode(label,lhs._declaredType,ns).peephole();
+ return new PhiNode(label,lhs._minType,ns).peephole();
}
}
return null;
diff --git a/src/main/java/com/seaofnodes/simple/node/BoolNode.java b/src/main/java/com/seaofnodes/simple/node/BoolNode.java
index 301e1517..2765c308 100644
--- a/src/main/java/com/seaofnodes/simple/node/BoolNode.java
+++ b/src/main/java/com/seaofnodes/simple/node/BoolNode.java
@@ -1,8 +1,8 @@
package com.seaofnodes.simple.node;
import com.seaofnodes.simple.Parser;
-import com.seaofnodes.simple.Utils;
import com.seaofnodes.simple.type.*;
+import com.seaofnodes.simple.util.Utils;
import java.util.BitSet;
import static com.seaofnodes.simple.type.TypeInteger.*;
@@ -33,7 +33,7 @@ abstract public class BoolNode extends Node {
Type t2 = in(2)._type;
// Exactly equals?
if( t1.isHigh() || t2.isHigh() )
- return BOOL.dual();
+ return (TypeInteger)BOOL.dual();
if( in(1)==in(2) )
// LT fails, both EQ and LE succeed
return this instanceof LT ? FALSE : TRUE;
diff --git a/src/main/java/com/seaofnodes/simple/node/CFGNode.java b/src/main/java/com/seaofnodes/simple/node/CFGNode.java
index 1dddc171..b9c70e5f 100644
--- a/src/main/java/com/seaofnodes/simple/node/CFGNode.java
+++ b/src/main/java/com/seaofnodes/simple/node/CFGNode.java
@@ -1,10 +1,10 @@
package com.seaofnodes.simple.node;
-import com.seaofnodes.simple.Ary;
import com.seaofnodes.simple.Parser;
-import com.seaofnodes.simple.Utils;
import com.seaofnodes.simple.codegen.CodeGen;
import com.seaofnodes.simple.type.*;
+import com.seaofnodes.simple.util.Ary;
+import com.seaofnodes.simple.util.Utils;
import java.util.BitSet;
import java.util.HashMap;
import java.util.HashSet;
@@ -59,7 +59,7 @@ public abstract class CFGNode extends Node {
// Used by the encoding / final BB layout
public CFGNode uctrlSkipEmpty() {
CFGNode x = this, y;
- while( x.nOuts() == 1 && (y=x.uctrl())!=null ) // Skip empty blocks
+ while( x.nOuts() == 1 && (y=x.uctrl())!=null && !(y instanceof CallNode) ) // Skip empty blocks
x = y;
return x;
}
@@ -89,6 +89,7 @@ public abstract class CFGNode extends Node {
var comp = lhs.idepth() - rhs.idepth();
if( comp >= 0 ) lhs = (dep==null ? lhs : dep.addDep(lhs)).idom();
if( comp <= 0 ) rhs = (dep==null ? rhs : dep.addDep(rhs)).idom();
+ if( lhs==null || rhs==null ) return null;
}
return lhs;
}
diff --git a/src/main/java/com/seaofnodes/simple/node/CProjNode.java b/src/main/java/com/seaofnodes/simple/node/CProjNode.java
index 94770f16..a6e21ea0 100644
--- a/src/main/java/com/seaofnodes/simple/node/CProjNode.java
+++ b/src/main/java/com/seaofnodes/simple/node/CProjNode.java
@@ -1,10 +1,10 @@
package com.seaofnodes.simple.node;
import com.seaofnodes.simple.Parser;
-import com.seaofnodes.simple.Utils;
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeMem;
import com.seaofnodes.simple.type.TypeTuple;
+import com.seaofnodes.simple.util.Utils;
import java.util.BitSet;
public class CProjNode extends CFGNode {
diff --git a/src/main/java/com/seaofnodes/simple/node/CallEndMach.java b/src/main/java/com/seaofnodes/simple/node/CallEndMach.java
index 47cab07a..d26ea33b 100644
--- a/src/main/java/com/seaofnodes/simple/node/CallEndMach.java
+++ b/src/main/java/com/seaofnodes/simple/node/CallEndMach.java
@@ -1,7 +1,7 @@
package com.seaofnodes.simple.node;
-import com.seaofnodes.simple.SB;
import com.seaofnodes.simple.codegen.*;
+import com.seaofnodes.simple.util.SB;
public class CallEndMach extends CallEndNode implements MachNode {
public CallEndMach( CallEndNode n ) { super(n); }
diff --git a/src/main/java/com/seaofnodes/simple/node/CallEndNode.java b/src/main/java/com/seaofnodes/simple/node/CallEndNode.java
index cf3f337c..d95af697 100644
--- a/src/main/java/com/seaofnodes/simple/node/CallEndNode.java
+++ b/src/main/java/com/seaofnodes/simple/node/CallEndNode.java
@@ -74,10 +74,10 @@ public class CallEndNode extends CFGNode implements MultiNode {
assert fun.in(1) instanceof StartNode && fun.in(2)==call;
// Disallow self-recursive inlining (loop unrolling by another name)
CFGNode idom = call;
- while( !(idom instanceof FunNode) )
+ while( !(idom instanceof FunNode) && idom!=null )
idom = idom.idom();
// Inline?
- if( idom != fun ) {
+ if( idom != fun && idom != null ) {
// Trivial inline: rewrite
_folding = true;
// Rewrite Fun so the normal RegionNode ideal collapses
@@ -86,6 +86,11 @@ public class CallEndNode extends CFGNode implements MultiNode {
fun.setDef(2,call.ctrl()); // Bypass the Call;
fun.ret().setDef(3,null); // Return is folding also
CodeGen.CODE.addAll(fun._outputs);
+ // Repeat defs 1 layer down, for users of Parm (Phis)
+ for( Node parm : fun._outputs )
+ if( parm instanceof ParmNode )
+ CodeGen.CODE.addAll(parm._outputs);
+
// Inlining immediately blows all cache idepth fields past the inline point.
// Bump the global version number invalidating them en-masse.
CodeGen.CODE.invalidateIDepthCaches();
@@ -105,5 +110,4 @@ public class CallEndNode extends CFGNode implements MultiNode {
@Override public Node pcopy(int idx) {
return _folding ? in(1).in(idx) : null;
}
-
}
diff --git a/src/main/java/com/seaofnodes/simple/node/CallNode.java b/src/main/java/com/seaofnodes/simple/node/CallNode.java
index 8b243e87..ba08c87a 100644
--- a/src/main/java/com/seaofnodes/simple/node/CallNode.java
+++ b/src/main/java/com/seaofnodes/simple/node/CallNode.java
@@ -1,11 +1,11 @@
package com.seaofnodes.simple.node;
-import com.seaofnodes.simple.codegen.CodeGen;
import com.seaofnodes.simple.IterPeeps;
import com.seaofnodes.simple.Parser;
-import com.seaofnodes.simple.Utils;
+import com.seaofnodes.simple.codegen.CodeGen;
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeFunPtr;
+import com.seaofnodes.simple.util.Utils;
import java.util.BitSet;
/**
@@ -162,8 +162,10 @@ public class CallNode extends CFGNode {
// Check for args
for( int i=0; i<tfp.nargs(); i++ )
- if( !arg(i+2)._type.isa(tfp.arg(i)) )
- return Parser.error( "Argument #"+i+" isa "+arg(i+2)._type+", but must be a "+tfp.arg(i), _loc);
+ if( !arg(i+2)._type.isa(tfp.arg(i)) ) {
+ cend().addDep(arg(i+2)); // Upgrading arg type may allow inlining
+ return Parser.error( "Argument #" + i + " isa " + arg(i+2)._type + ", but must be a " + tfp.arg(i), _loc );
+ }
if( tfp.fidxs() < 0 )
throw Utils.TODO(); // Infinite unknown TFPs? Should be fairly precise CG
diff --git a/src/main/java/com/seaofnodes/simple/node/CastMach.java b/src/main/java/com/seaofnodes/simple/node/CastMach.java
index 92822433..e45898f5 100644
--- a/src/main/java/com/seaofnodes/simple/node/CastMach.java
+++ b/src/main/java/com/seaofnodes/simple/node/CastMach.java
@@ -1,9 +1,9 @@
package com.seaofnodes.simple.node;
-import com.seaofnodes.simple.SB;
import com.seaofnodes.simple.codegen.CodeGen;
import com.seaofnodes.simple.codegen.Encoding;
import com.seaofnodes.simple.codegen.RegMask;
+import com.seaofnodes.simple.util.SB;
/**
* Cast a pointer to read-only
diff --git a/src/main/java/com/seaofnodes/simple/node/CastNode.java b/src/main/java/com/seaofnodes/simple/node/CastNode.java
index 8d8f0257..6dc8e9fe 100644
--- a/src/main/java/com/seaofnodes/simple/node/CastNode.java
+++ b/src/main/java/com/seaofnodes/simple/node/CastNode.java
@@ -1,11 +1,10 @@
package com.seaofnodes.simple.node;
import com.seaofnodes.simple.Parser;
-import com.seaofnodes.simple.Utils;
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeInteger;
import com.seaofnodes.simple.type.TypeMemPtr;
-
+import com.seaofnodes.simple.util.Utils;
import java.util.BitSet;
// Upcast (join) the input to a t. Used after guard test to lift an input.
@@ -40,9 +39,15 @@ public class CastNode extends Node {
@Override
public Type compute() {
// Cast array to int
- if( _t == TypeInteger.BOT && in(1)._type instanceof TypeMemPtr tmp && tmp._obj.isAry() )
+ Type t1 = in(1)._type;
+ if( _t == TypeInteger.BOT && t1 instanceof TypeMemPtr tmp && tmp._obj.isAry() )
return _t;
- return in(1)._type.join(_t);
+ // Freeze if the join is high but both inputs are low
+ Type tj = t1.join(_t);
+ if( tj.isHigh() && !t1.isHigh() )
+ return _type==null ? _t : _type;
+
+ return tj;
}
@Override
@@ -64,6 +69,6 @@ public class CastNode extends Node {
// Has a condition to test, so OK
if( in(0) != null ) return null;
// No condition to test, so this must optimize away
- throw Utils.TODO();
+ return Parser.error( "Type " + in(1)._type.str() + " is not of declared type " + _t.str(), null );
}
}
diff --git a/src/main/java/com/seaofnodes/simple/node/ConFldOffNode.java b/src/main/java/com/seaofnodes/simple/node/ConFldOffNode.java
new file mode 100644
index 00000000..3e1d3c69
--- /dev/null
+++ b/src/main/java/com/seaofnodes/simple/node/ConFldOffNode.java
@@ -0,0 +1,43 @@
+package com.seaofnodes.simple.node;
+
+import com.seaofnodes.simple.codegen.CodeGen;
+import com.seaofnodes.simple.type.Type;
+import com.seaofnodes.simple.type.TypeInteger;
+import com.seaofnodes.simple.type.TypeStruct;
+import com.seaofnodes.simple.util.SB;
+import java.util.BitSet;
+
+/**
+ * A field offset. This becomes a constant *after* other optimizations which
+ * determine field sizes - some fields might be dead, or hold only zeros or
+ * small values.
+ */
+
+public class ConFldOffNode extends ConstantNode {
+ public final String _name; // Struct name
+ public final String _fname; // Field name
+ public ConFldOffNode( String name, String fname ) { super(TypeInteger.BOT); _name = name; _fname = fname; }
+
+ @Override public String label() {
+ return _fname == " len" ? "sizeof("+_name+")" : "#"+_fname;
+ }
+ @Override public String glabel() { return label(); }
+ @Override public String uniqueName() { return "Off_" + _nid; }
+
+ @Override
+ public StringBuilder _print1(StringBuilder sb, BitSet visited) {
+ return sb.append(label());
+ }
+
+ // Convert field offset to an integer
+ public Node asOffset(TypeStruct ts) {
+ return new ConstantNode(TypeInteger.constant(ts.offset(_fname==" len" ? ts._fields.length : ts.find(_fname)))).peephole();
+ }
+
+
+ @Override public boolean eq(Node n) {
+ ConFldOffNode off = (ConFldOffNode)n; // Invariant
+ return _name==off._name && _fname==off._fname && super.eq(n);
+ }
+ @Override int hash() { return super.hash() * _name.hashCode() * _fname.hashCode(); }
+}
diff --git a/src/main/java/com/seaofnodes/simple/node/ConstantNode.java b/src/main/java/com/seaofnodes/simple/node/ConstantNode.java
index 79f301c1..22bf03c4 100644
--- a/src/main/java/com/seaofnodes/simple/node/ConstantNode.java
+++ b/src/main/java/com/seaofnodes/simple/node/ConstantNode.java
@@ -1,17 +1,13 @@
package com.seaofnodes.simple.node;
import com.seaofnodes.simple.codegen.CodeGen;
-import com.seaofnodes.simple.Parser;
-import com.seaofnodes.simple.SB;
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeFunPtr;
+import com.seaofnodes.simple.util.SB;
import java.util.BitSet;
/**
- * A Constant node represents a constant value. At present, the only constants
- * that we allow are integer literals; therefore Constants contain an integer
- * value. As we add other types of constants, we will refactor how we represent
- * Constants.
+ * A Constant node represents a constant value.
* <p>
* Constants have no semantic inputs. However, we set Start as an input to
* Constants to enable a forward graph walk. This edge carries no semantic
@@ -26,8 +22,7 @@ public class ConstantNode extends Node {
super(new Node[]{CodeGen.CODE._start});
_con = _type = type;
}
- public ConstantNode( Node con, Type t ) { super(con); _con = t; }
- public ConstantNode( ConstantNode con ) { this(con,con._type); }
+ public ConstantNode( ConstantNode con ) { super(con); _con = con._type; }
public static Node make( Type type ) {
if( type==Type. CONTROL ) return new CtrlNode();
@@ -36,10 +31,8 @@ public class ConstantNode extends Node {
}
@Override public String label() { return "#"+_con; }
- @Override public String glabel() { return _con.gprint(new SB().p("#")).toString(); }
-
- @Override
- public String uniqueName() { return "Con_" + _nid; }
+ @Override public String glabel() { return "#"+_con.gprint(); }
+ @Override public String uniqueName() { return "Con_" + _nid; }
@Override
public StringBuilder _print1(StringBuilder sb, BitSet visited) {
@@ -48,23 +41,12 @@ public class ConstantNode extends Node {
if( fun!=null && fun._name != null )
return sb.append("{ ").append(fun._name).append("}");
}
- return sb.append(_con==null ? "---" : _con.print(new SB()));
+ return sb.append(_con==null ? "---" : _con.toString());
}
@Override public boolean isConst() { return true; }
-
- @Override
- public Type compute() { return _con; }
-
- @Override
- public Node idealize() { return null; }
-
- @Override
- public boolean eq(Node n) {
- ConstantNode con = (ConstantNode)n; // Contract
- return _con==con._con;
- }
-
- @Override
- int hash() { return _con.hashCode(); }
+ @Override public Type compute() { return _con; }
+ @Override public Node idealize() { return null; }
+ @Override public boolean eq(Node n) { return _con==((ConstantNode)n)._con; }
+ @Override int hash() { return _con.hashCode(); }
}
diff --git a/src/main/java/com/seaofnodes/simple/node/ExternNode.java b/src/main/java/com/seaofnodes/simple/node/ExternNode.java
index 33fc0c1e..a10bb84a 100644
--- a/src/main/java/com/seaofnodes/simple/node/ExternNode.java
+++ b/src/main/java/com/seaofnodes/simple/node/ExternNode.java
@@ -1,10 +1,10 @@
package com.seaofnodes.simple.node;
-import com.seaofnodes.simple.codegen.CodeGen;
import com.seaofnodes.simple.Parser;
-import com.seaofnodes.simple.SB;
+import com.seaofnodes.simple.codegen.CodeGen;
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeFunPtr;
+import com.seaofnodes.simple.util.SB;
import java.util.BitSet;
/**
@@ -16,7 +16,7 @@ public class ExternNode extends ConstantNode {
public ExternNode(Type t, String ex) { super(t); _extern = ex; }
@Override public String label() { return "#"+_con+":"+_extern; }
- @Override public String glabel() { return _con.gprint(new SB().p("#")).p(":").p(_extern).toString(); }
+ @Override public String glabel() { return _con.print(new SB().p("#"), new BitSet(), true).p(":").p(_extern).toString(); }
@Override public String uniqueName() { return "Extern_" + _nid; }
@Override public boolean eq(Node n) { return this==n; }
diff --git a/src/main/java/com/seaofnodes/simple/node/FunNode.java b/src/main/java/com/seaofnodes/simple/node/FunNode.java
index 81fa627a..4bd0fd97 100644
--- a/src/main/java/com/seaofnodes/simple/node/FunNode.java
+++ b/src/main/java/com/seaofnodes/simple/node/FunNode.java
@@ -1,13 +1,14 @@
package com.seaofnodes.simple.node;
-
-import com.seaofnodes.simple.*;
+import com.seaofnodes.simple.Parser;
import com.seaofnodes.simple.codegen.CodeGen;
import com.seaofnodes.simple.codegen.Encoding;
import com.seaofnodes.simple.codegen.RegMask;
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeFunPtr;
import com.seaofnodes.simple.type.TypeTuple;
+import com.seaofnodes.simple.util.SB;
+import com.seaofnodes.simple.util.Utils;
import java.util.BitSet;
import static com.seaofnodes.simple.codegen.CodeGen.CODE;
@@ -125,10 +126,10 @@ public class FunNode extends RegionNode {
return _folding ? super.idepth() : CodeGen.CODE.iDepthAt(1);
}
// Bypass Region idom, always assume idom is Start
- @Override public CFGNode idom(Node dep) { return _folding && nIns()==3 ? cfg(2) : cfg(1); }
+ @Override public CFGNode idom(Node dep) { return _folding && nIns()==3 ? cfg(2) : (nIns()>1 ? cfg(1) : null); }
// Always in-progress until we run out of unknown callers
- public boolean unknownCallers() { return nIns()<2 || in(1) instanceof StartNode; }
+ public boolean unknownCallers() { return nIns()>=2 && in(1) instanceof StartNode; }
@Override public boolean inProgress() { return unknownCallers(); }
diff --git a/src/main/java/com/seaofnodes/simple/node/IfNode.java b/src/main/java/com/seaofnodes/simple/node/IfNode.java
index 5d90449e..c5d687e5 100644
--- a/src/main/java/com/seaofnodes/simple/node/IfNode.java
+++ b/src/main/java/com/seaofnodes/simple/node/IfNode.java
@@ -1,8 +1,8 @@
package com.seaofnodes.simple.node;
-import com.seaofnodes.simple.Utils;
import com.seaofnodes.simple.codegen.CodeGen;
import com.seaofnodes.simple.type.*;
+import com.seaofnodes.simple.util.Utils;
import java.util.BitSet;
public class IfNode extends CFGNode implements MultiNode {
@@ -87,8 +87,8 @@ public class IfNode extends CFGNode implements MultiNode {
return switch( bop ) {
case "<" -> ">" ;
case "<=" -> ">=";
- case "==" -> "!=";
- case "!=" -> "==";
+ case "==" -> "==";
+ case "!=" -> "!=";
case ">" -> "<" ;
case ">=" -> "<=";
default -> throw Utils.TODO();
diff --git a/src/main/java/com/seaofnodes/simple/node/LoadNode.java b/src/main/java/com/seaofnodes/simple/node/LoadNode.java
index eebe94a3..b58ea498 100644
--- a/src/main/java/com/seaofnodes/simple/node/LoadNode.java
+++ b/src/main/java/com/seaofnodes/simple/node/LoadNode.java
@@ -1,8 +1,9 @@
package com.seaofnodes.simple.node;
import com.seaofnodes.simple.Parser;
-import com.seaofnodes.simple.Utils;
+import com.seaofnodes.simple.codegen.CodeGen;
import com.seaofnodes.simple.type.*;
+import com.seaofnodes.simple.util.Utils;
import java.util.BitSet;
/**
@@ -33,15 +34,21 @@ public class LoadNode extends MemOpNode {
@Override
public Type compute() {
- if( mem()._type instanceof TypeMem mem ) {
- // Update declared forward ref to the actual
- if( _declaredType.isFRef() && mem._t instanceof TypeMemPtr tmp && !tmp.isFRef() )
- _declaredType = tmp;
- // No lifting if ptr might null-check
- if( err()==null )
- return _declaredType.join(mem._t);
+ if( !(mem()._type instanceof TypeMem mem) )
+ return _declaredType; // No memory yet? Declared type
+ assert !_declaredType.isFRef();
+ // No lifting if ptr might null-check
+ if( err()!=null || !(ptr()._type instanceof TypeMemPtr tmp) )
+ return _declaredType; // No pointer yet? Declared type
+ Type t = tmp._obj.field(_name)._t;
+ if( t instanceof TypeConAry ary ) {
+ t = ary.elem(); // TODO: if offset is known, can peek the constant
}
- return _declaredType;
+ // Lift from declared type and memory input
+ t = t.join(_declaredType).join(mem._t);
+ if( _declaredType.isFinal() )
+ t = t.makeRO(); // Deep final applied
+ return t;
}
@Override
@@ -49,6 +56,11 @@ public class LoadNode extends MemOpNode {
Node ptr = ptr();
Node mem = mem();
+ if( mem instanceof CastNode cast ) {
+ setDef(1,cast.in(1));
+ return this;
+ }
+
// Simple Load-after-Store on same address.
if( mem instanceof StoreNode st &&
ptr == st.ptr() && off() == st.off() ) { // Must check same object
@@ -58,7 +70,11 @@ public class LoadNode extends MemOpNode {
// Simple load-after-MemMerge to a known alias can bypass. Happens when inlining.
if( mem instanceof MemMergeNode mem2 ) {
- setDef(1,mem2.alias(_alias));
+ Node memA = mem2.alias(_alias);
+ for( Node ld : memA._outputs )
+ if( ld instanceof LoadNode )
+ CodeGen.CODE.add(ld);
+ setDef(1,memA);
return this;
}
@@ -111,6 +127,7 @@ public class LoadNode extends MemOpNode {
default: throw Utils.TODO();
}
break;
+ case CastNode cast: mem = cast.in(1); break;
case MemMergeNode merge: mem = merge.alias(_alias); break;
default:
@@ -147,7 +164,7 @@ public class LoadNode extends MemOpNode {
// Load a flavored zero from a New
private Node zero(NewNode nnn) {
TypeStruct ts = nnn._ptr._obj;
- Type zero = ts._fields[ts.findAlias(_alias)]._type.makeZero();
+ Type zero = ts._fields[ts.findAlias(_alias)]._t.makeZero();
return castRO(new ConstantNode(zero).peephole());
}
@@ -187,7 +204,7 @@ public class LoadNode extends MemOpNode {
Node px = phi.in(idx);
if( px==null ) return false;
if( px._type instanceof TypeMem mem && mem._t.isHighOrConst() ) return true;
- if( px instanceof StoreNode st1 && ptr()==st1.ptr() && off()==st1.off() ) return true;
+ if( px instanceof StoreNode st1 && ptr()==addDep(st1.ptr() )&& off()==st1.off() ) return true;
addDep(px);
return false;
}
diff --git a/src/main/java/com/seaofnodes/simple/node/LoopNode.java b/src/main/java/com/seaofnodes/simple/node/LoopNode.java
index ec9055dc..fc50e17f 100644
--- a/src/main/java/com/seaofnodes/simple/node/LoopNode.java
+++ b/src/main/java/com/seaofnodes/simple/node/LoopNode.java
@@ -1,11 +1,11 @@
package com.seaofnodes.simple.node;
import com.seaofnodes.simple.Parser;
-import com.seaofnodes.simple.Utils;
import com.seaofnodes.simple.codegen.CodeGen;
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeInteger;
import com.seaofnodes.simple.type.TypeMem;
+import com.seaofnodes.simple.util.Utils;
import java.util.BitSet;
import java.util.HashSet;
@@ -48,7 +48,7 @@ public class LoopNode extends RegionNode {
x = x.idom();
}
// Found a no-exit loop. Insert an exit
- NeverNode iff = new NeverNode(back()); // Ideal never-branch
+ NeverNode iff = (NeverNode)new NeverNode(back()).peephole(); // Ideal never-branch
CProjNode t = new CProjNode(iff,0,"True" ).init();
CProjNode f = new CProjNode(iff,1,"False").init();
setDef(2,t); // True continues loop, False (never) exits loop
@@ -78,17 +78,19 @@ public class LoopNode extends RegionNode {
expr = new PhiNode(r,expr).init();
}
// Append new Never exit
- ctrl.addDef(f );
- mem .addDef(memout);
- expr.addDef(top);
+ ctrl.keep().addDef(f );
+ mem .keep().addDef(memout);
+ expr.keep().addDef(top);
} else {
- ctrl = f;
- mem = memout;
- expr = top;
+ ctrl = f .keep();
+ mem = memout.keep();
+ expr = top .keep();
}
- ret.setDef(0,ctrl);
- ret.setDef(1,mem );
- ret.setDef(2,expr);
+ ret.setDef(0,ctrl.unkeep());
+ ret.setDef(1,mem .unkeep());
+ ret.setDef(2,expr.unkeep());
+ ret._type = null; // This may LIFT the Return type, from [XCtrl,mem,expr] to [Ctrl,mem,expr]
+ ret.setType(ret.compute());
return stop;
}
diff --git a/src/main/java/com/seaofnodes/simple/node/MachConcreteNode.java b/src/main/java/com/seaofnodes/simple/node/MachConcreteNode.java
index b01b3308..9440a7ea 100644
--- a/src/main/java/com/seaofnodes/simple/node/MachConcreteNode.java
+++ b/src/main/java/com/seaofnodes/simple/node/MachConcreteNode.java
@@ -1,7 +1,7 @@
package com.seaofnodes.simple.node;
import com.seaofnodes.simple.type.Type;
-import com.seaofnodes.simple.Utils;
+import com.seaofnodes.simple.util.Utils;
import java.io.ByteArrayOutputStream;
import java.util.BitSet;
diff --git a/src/main/java/com/seaofnodes/simple/node/MachNode.java b/src/main/java/com/seaofnodes/simple/node/MachNode.java
index f63b3651..c0b3af66 100644
--- a/src/main/java/com/seaofnodes/simple/node/MachNode.java
+++ b/src/main/java/com/seaofnodes/simple/node/MachNode.java
@@ -2,6 +2,8 @@ package com.seaofnodes.simple.node;
import com.seaofnodes.simple.*;
import com.seaofnodes.simple.codegen.*;
+import com.seaofnodes.simple.util.SB;
+import com.seaofnodes.simple.util.Utils;
public interface MachNode {
diff --git a/src/main/java/com/seaofnodes/simple/node/MemMergeNode.java b/src/main/java/com/seaofnodes/simple/node/MemMergeNode.java
index 9f2fdd16..19acc5b9 100644
--- a/src/main/java/com/seaofnodes/simple/node/MemMergeNode.java
+++ b/src/main/java/com/seaofnodes/simple/node/MemMergeNode.java
@@ -67,9 +67,12 @@ public class MemMergeNode extends Node {
// Fold defaults into the default
boolean progress=false, allDefault=true;
- for( int i=2; i<nIns(); i++ )
+ for( int i=2; i<nIns(); i++ ) {
+ if( in(i) instanceof CastNode cast )
+ { setDef(i,cast.in(1)); progress=true; }
if( in(1) == in(i) ) { setDef(i,null); progress=true; }
else { allDefault=false; }
+ }
// If not merging any memory (all memory is just the default)
if( allDefault )
@@ -121,7 +124,7 @@ public class MemMergeNode extends Node {
// Set real Phi in the loop head
// The phi takes its one input (no backedge yet) from a recursive
// lookup, which might have insert a Phi in every loop nest.
- : loopmem.alias(alias, new PhiNode(Parser.memName(alias), TypeMem.BOT,loop.ctrl(),loopmem._mem(alias,null),null).peephole() );
+ : loopmem.alias(alias, new PhiNode(Parser.memName(alias), TypeMem.make(alias,Type.BOTTOM),loop.ctrl(),loopmem._mem(alias,null),null).peephole() );
alias(alias,old);
}
// Memory projections are made lazily; expand as needed
@@ -137,7 +140,7 @@ public class MemMergeNode extends Node {
// by alias as it will trigger a phi creation
Node lhs = this._mem(i,null);
Node rhs = that._mem(i,null);
- alias(i, new PhiNode(Parser.memName(i), lhs._type.glb(true).meet(rhs._type.glb(true)), r, lhs, rhs).peephole());
+ alias(i, new PhiNode(Parser.memName(i), lhs._type.meet(rhs._type).glb(true), r, lhs, rhs).peephole());
}
}
diff --git a/src/main/java/com/seaofnodes/simple/node/MemOpNode.java b/src/main/java/com/seaofnodes/simple/node/MemOpNode.java
index bb84019e..ead82322 100644
--- a/src/main/java/com/seaofnodes/simple/node/MemOpNode.java
+++ b/src/main/java/com/seaofnodes/simple/node/MemOpNode.java
@@ -1,9 +1,9 @@
package com.seaofnodes.simple.node;
import com.seaofnodes.simple.Parser;
-import com.seaofnodes.simple.Utils;
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeMemPtr;
+import com.seaofnodes.simple.util.Utils;
import java.lang.StringBuilder;
import java.util.BitSet;
diff --git a/src/main/java/com/seaofnodes/simple/node/MinusNode.java b/src/main/java/com/seaofnodes/simple/node/MinusNode.java
index 059d0d00..f26ce37e 100644
--- a/src/main/java/com/seaofnodes/simple/node/MinusNode.java
+++ b/src/main/java/com/seaofnodes/simple/node/MinusNode.java
@@ -2,8 +2,7 @@ package com.seaofnodes.simple.node;
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeInteger;
-import com.seaofnodes.simple.Utils;
-
+import com.seaofnodes.simple.util.Utils;
import java.util.BitSet;
public class MinusNode extends Node {
diff --git a/src/main/java/com/seaofnodes/simple/node/MultiNode.java b/src/main/java/com/seaofnodes/simple/node/MultiNode.java
index 17d00881..b4d6d78e 100644
--- a/src/main/java/com/seaofnodes/simple/node/MultiNode.java
+++ b/src/main/java/com/seaofnodes/simple/node/MultiNode.java
@@ -1,6 +1,6 @@
package com.seaofnodes.simple.node;
-import com.seaofnodes.simple.Ary;
+import com.seaofnodes.simple.util.Ary;
public interface MultiNode {
diff --git a/src/main/java/com/seaofnodes/simple/node/NewNode.java b/src/main/java/com/seaofnodes/simple/node/NewNode.java
index 5a8c1b6b..1785af4e 100644
--- a/src/main/java/com/seaofnodes/simple/node/NewNode.java
+++ b/src/main/java/com/seaofnodes/simple/node/NewNode.java
@@ -1,9 +1,9 @@
package com.seaofnodes.simple.node;
-import com.seaofnodes.simple.SB;
-import com.seaofnodes.simple.Utils;
import com.seaofnodes.simple.codegen.*;
import com.seaofnodes.simple.type.*;
+import com.seaofnodes.simple.util.SB;
+
import java.util.BitSet;
/**
@@ -27,8 +27,7 @@ public class NewNode extends Node implements MultiNode {
// Malloc-length in slot 1
assert nodes[1]._type instanceof TypeInteger || nodes[1]._type==Type.NIL;
for( int i=0; i<_len; i++ )
- // Memory slices for all fields.
- assert nodes[2+i]._type.isa(TypeMem.BOT);
+ assert ptr._obj._fields[i]._one || nodes[2 + i]._type.isa( TypeMem.BOT );
}
public NewNode(NewNode nnn) { super(nnn); _ptr = nnn._ptr; _len = nnn._len; }
@@ -37,7 +36,7 @@ public class NewNode extends Node implements MultiNode {
@Override public String label() { return "new_"+glabel(); }
@Override public String glabel() {
- return _ptr._obj.isAry() ? "ary_"+_ptr._obj._fields[1]._type.str() : _ptr._obj.str();
+ return _ptr._obj.isAry() ? "ary_"+_ptr._obj._fields[1]._t.str() : _ptr._obj.str();
}
@Override
@@ -65,17 +64,30 @@ public class NewNode extends Node implements MultiNode {
ts[0] = Type.CONTROL;
ts[1] = _ptr;
for( int i=0; i<fs.length; i++ ) {
- Type mt = in(i+2)._type;
- TypeMem mem = mt==Type.TOP ? TypeMem.TOP : (TypeMem)mt;
- Type tfld = mem._t.meet(mem._t.makeZero());
- Type tfld2 = tfld.join(fs[i]._type);
- ts[i+2] = TypeMem.make(fs[i]._alias,tfld2);
+ if( _ptr._obj._fields[i]._one ) {
+ // Once-only fields use the declared type
+ ts[i+2] = _ptr._obj._fields[i]._t;
+ } else {
+ // Others take from the inputs
+ Type mt = in(i+2)._type;
+ TypeMem mem = mt==Type.TOP ? TypeMem.TOP : (TypeMem)mt;
+ Type tfld = mem._t.meet(mem._t.makeZero());
+ Type tfld2 = tfld.join(fs[i]._t );
+ ts[i+2] = TypeMem.make(fs[i]._alias,tfld2);
+ }
}
return TypeTuple.make(ts);
}
@Override
- public Node idealize() { return null; }
+ public Node idealize() {
+ Node progress=null;
+ for( int i=1; i<nIns(); i++ ) {
+ if( in(i) instanceof CastNode cast )
+ progress = setDef(i,cast.in(1));
+ }
+ return progress == null ? null : this;
+ }
@Override
public boolean eq(Node n) { return this == n; }
diff --git a/src/main/java/com/seaofnodes/simple/node/Node.java b/src/main/java/com/seaofnodes/simple/node/Node.java
index 064f295f..8981ab0d 100644
--- a/src/main/java/com/seaofnodes/simple/node/Node.java
+++ b/src/main/java/com/seaofnodes/simple/node/Node.java
@@ -1,6 +1,8 @@
package com.seaofnodes.simple.node;
-import com.seaofnodes.simple.*;
+import com.seaofnodes.simple.Parser;
+import com.seaofnodes.simple.util.Ary;
+import com.seaofnodes.simple.util.Utils;
import com.seaofnodes.simple.codegen.CodeGen;
import com.seaofnodes.simple.print.IRPrinter;
import com.seaofnodes.simple.print.JSViewer;
@@ -307,6 +309,7 @@ public abstract class Node implements Cloneable {
int idx = n._inputs.find(this);
n._inputs.set(idx,nnn);
nnn.addUse(n);
+ CODE.add(n);
CODE.addAll(n._outputs);
}
kill();
@@ -411,7 +414,7 @@ public abstract class Node implements Cloneable {
// node. If peeps are disabled, still allow high Phis to collapse;
// they typically come from dead Regions, and we want the Region to
// collapse, which requires the Phis to die first.
- if( _type.isHighOrConst() && !isConst() )
+ if( !isConst() && _type.isHighOrConst() )
return ConstantNode.make(_type).peephole();
// Global Value Numbering
diff --git a/src/main/java/com/seaofnodes/simple/node/NotNode.java b/src/main/java/com/seaofnodes/simple/node/NotNode.java
index 0314841d..4b80e61c 100644
--- a/src/main/java/com/seaofnodes/simple/node/NotNode.java
+++ b/src/main/java/com/seaofnodes/simple/node/NotNode.java
@@ -1,7 +1,7 @@
package com.seaofnodes.simple.node;
-import com.seaofnodes.simple.Utils;
import com.seaofnodes.simple.type.*;
+import com.seaofnodes.simple.util.Utils;
import java.util.BitSet;
public class NotNode extends Node {
@@ -20,7 +20,7 @@ public class NotNode extends Node {
@Override
public TypeInteger compute() {
Type t0 = in(1)._type;
- if( t0.isHigh() ) return TypeInteger.BOOL.dual();
+ if( t0.isHigh() ) return (TypeInteger)TypeInteger.BOOL.dual();
if( t0 == Type.NIL || t0 == TypeInteger.ZERO ) return TypeInteger.TRUE;
if( t0 instanceof TypeNil tn && tn.notNull() ) return TypeInteger.FALSE;
if( t0 instanceof TypeInteger i && (i._min > 0 || i._max < 0) ) return TypeInteger.FALSE;
diff --git a/src/main/java/com/seaofnodes/simple/node/ParmNode.java b/src/main/java/com/seaofnodes/simple/node/ParmNode.java
index 32e41f54..a14a4fb9 100644
--- a/src/main/java/com/seaofnodes/simple/node/ParmNode.java
+++ b/src/main/java/com/seaofnodes/simple/node/ParmNode.java
@@ -1,6 +1,5 @@
package com.seaofnodes.simple.node;
-import com.seaofnodes.simple.Utils;
import com.seaofnodes.simple.type.Type;
import java.util.BitSet;
@@ -13,7 +12,7 @@ public class ParmNode extends PhiNode {
super(label,declaredType,inputs);
_idx = idx;
}
- public ParmNode(ParmNode parm) { super(parm, parm._label, parm._declaredType); _idx = parm._idx; }
+ public ParmNode(ParmNode parm) { super(parm, parm._label, parm._minType ); _idx = parm._idx; }
@Override public String label() { return MemOpNode.mlabel(_label); }
@@ -37,14 +36,8 @@ public class ParmNode extends PhiNode {
}
- @Override
- public Node idealize() {
- if( inProgress() ) return null;
- return super.idealize();
- }
-
// Always in-progress until we run out of unknown callers
- @Override public boolean inProgress() { return fun().inProgress(); }
+ @Override public boolean inProgress() { return in(0) instanceof FunNode fun && fun.inProgress(); }
@Override public boolean eq( Node n ) {
return ((ParmNode)n)._idx==_idx && super.eq(n);
diff --git a/src/main/java/com/seaofnodes/simple/node/PhiNode.java b/src/main/java/com/seaofnodes/simple/node/PhiNode.java
index 971b52ae..fcbacbc9 100644
--- a/src/main/java/com/seaofnodes/simple/node/PhiNode.java
+++ b/src/main/java/com/seaofnodes/simple/node/PhiNode.java
@@ -1,25 +1,34 @@
package com.seaofnodes.simple.node;
import com.seaofnodes.simple.*;
+import com.seaofnodes.simple.codegen.CodeGen;
import com.seaofnodes.simple.type.*;
+import com.seaofnodes.simple.util.Utils;
import java.util.BitSet;
public class PhiNode extends Node {
public final String _label;
- // The Phi type we compute must stay within the domain of the Phi.
- // Example Int stays Int, Ptr stays Ptr, Control stays Control, Mem stays Mem.
- final Type _declaredType;
-
- public PhiNode(String label, Type declaredType, Node... inputs) { super(inputs); _label = label; assert declaredType!=null; _declaredType = declaredType; }
- public PhiNode(PhiNode phi, String label, Type declaredType) { super(phi); _label = label; _type = _declaredType = declaredType; }
- public PhiNode(PhiNode phi) { super(phi); _label = phi._label; _declaredType = phi._declaredType; }
+ // The Phi type we compute must stay within the domain of the Phi. Example
+ // Int stays Int, Ptr stays Ptr, Control stays Control, Mem stays Mem.
+ Type _minType;
+ public PhiNode(String label, Type minType, Node... inputs) {
+ super(inputs);
+ _label = label;
+ assert minType!=null;
+ _minType = minType;
+ }
+ // Used by ParmNode
+ public PhiNode(PhiNode phi, String label, Type minType) { super(phi); _label = label; _type = _minType = minType; }
+ // Used by instruction Selection
+ public PhiNode(PhiNode phi) { this(phi,phi._label,phi._minType ); }
+ // Used by the infinite-loop exit breaker
public PhiNode(RegionNode r, Node sample) {
super(new Node[]{r});
_label = "";
- _declaredType = sample._type;
+ _minType = sample._type;
while( nIns() < r.nIns() )
addDef(sample);
}
@@ -44,7 +53,7 @@ public class PhiNode extends Node {
}
public CFGNode region() { return (CFGNode)in(0); }
- @Override public boolean isMem() { return _declaredType instanceof TypeMem; }
+ @Override public boolean isMem() { return _minType instanceof TypeMem; }
@Override public boolean isPinned() { return true; }
@Override
@@ -52,14 +61,19 @@ public class PhiNode extends Node {
if( !(region() instanceof RegionNode r) )
return region()._type==Type.XCONTROL ? (_type instanceof TypeMem ? TypeMem.TOP : Type.TOP) : _type;
// During parsing Phis have to be computed type pessimistically.
- if( r.inProgress() ) return _declaredType;
+ if( r.inProgress() ) return _minType;
// Set type to local top of the starting type
- Type t = _declaredType.glb(false).dual();//Type.TOP;
+ //Type t = _minType.dual();
+ Type t = Type.TOP;
for (int i = 1; i < nIns(); i++)
// If the region's control input is live, add this as a dependency
// to the control because we can be peeped should it become dead.
- if( addDep(r.in(i))._type != Type.XCONTROL )
+ if( addDep(r.in(i))._type != Type.XCONTROL ) {
+ if( in(i)._type==Type.BOTTOM )
+ return Type.BOTTOM;
t = t.meet(in(i)._type);
+ }
+ t = t.join( _minType );
return t;
}
@@ -67,19 +81,40 @@ public class PhiNode extends Node {
public Node idealize() {
if( !(region() instanceof RegionNode r ) )
return in(1); // Input has collapse to e.g. starting control.
+ // Can upgrade minType even while in-progress
+ if( _minType instanceof TypeMemPtr tmp && _minType.isFRef() ) {
+ TypeMemPtr tmp2 = (TypeMemPtr)CodeGen.CODE.P.TYPES.get(tmp._obj._name);
+ if( tmp2!=null && tmp2 != _minType ) {
+ _minType = tmp2;
+ return this;
+ }
+ }
if( r.inProgress() || r.nIns()<=1 )
return null; // Input is in-progress
// If we have only a single unique input, become it.
Node live = singleUniqueInput();
- if (live != null)
- return live;
+ if( live != null ) {
+ if( live._type.isa(_type) )
+ return live;
+ // Keep the Phi upcast
+ return new CastNode(_type,null,live);
+ }
// No bother if region is going to fold dead paths soon
for( int i=1; i<nIns(); i++ )
if( r.in(i)._type == Type.XCONTROL )
return null;
+ // Simple Phi-after-MemMerge to a known alias can bypass. Happens when inlining.
+ if( _type instanceof TypeMem tmem && tmem._alias!=1 ) {
+ for( int i=1; i<nIns(); i++ )
+ if( in(i) instanceof MemMergeNode mem ) {
+ setDef(i,mem.alias(tmem._alias));
+ return this;
+ }
+ }
+
// Generic "pull down op"
Node progress;
if( same_op() && (progress = drop_same_op()) != null )
@@ -197,9 +232,19 @@ public class PhiNode extends Node {
return in(nIns()-1) == null;
}
- // Never equal if inProgress
+ // Never equal if inProgress.
+ // Also, joins
@Override public boolean eq( Node n ) {
- return !inProgress();
+ if( inProgress() ) return false;
+ Type min = ((PhiNode)n)._minType;
+ if( _minType==min ) return true;
+ Type mt = min.meet(_minType);
+ if( min!=mt && _minType!=mt ) return false;
+ //// Theory says these 2 Phis CAN be merged/GVNd, but I need to pick the
+ //// most general minType.
+ //_minType = ((PhiNode)n)._minType = mt;
+ //return true;
+ return false;
}
@Override
diff --git a/src/main/java/com/seaofnodes/simple/node/ReadOnlyMach.java b/src/main/java/com/seaofnodes/simple/node/ReadOnlyMach.java
index 86d17f9b..a35f5a1d 100644
--- a/src/main/java/com/seaofnodes/simple/node/ReadOnlyMach.java
+++ b/src/main/java/com/seaofnodes/simple/node/ReadOnlyMach.java
@@ -1,9 +1,9 @@
package com.seaofnodes.simple.node;
-import com.seaofnodes.simple.SB;
import com.seaofnodes.simple.codegen.CodeGen;
import com.seaofnodes.simple.codegen.Encoding;
import com.seaofnodes.simple.codegen.RegMask;
+import com.seaofnodes.simple.util.SB;
/**
* Cast a pointer to read-only
diff --git a/src/main/java/com/seaofnodes/simple/node/RegionNode.java b/src/main/java/com/seaofnodes/simple/node/RegionNode.java
index 8f65d0e5..2b467a8c 100644
--- a/src/main/java/com/seaofnodes/simple/node/RegionNode.java
+++ b/src/main/java/com/seaofnodes/simple/node/RegionNode.java
@@ -45,7 +45,7 @@ public class RegionNode extends CFGNode {
return in(1); // Collapse if no Phis; 1-input Phis will collapse on their own
// If a CFG diamond with no merging, delete: "if( pred ) {} else {};"
- if( !hasPhi() && // No Phi users, just a control user
+ if( !hasPhi() && nIns()>3 && // No Phi users, just a control user
in(1) instanceof CProjNode p1 &&
in(2) instanceof CProjNode p2 &&
addDep(p1.in(0))==addDep(p2.in(0)) &&
@@ -57,8 +57,8 @@ public class RegionNode extends CFGNode {
return delDef(2);
}
- // Flatten stack regions (no loops involved)
- if( getClass() == RegionNode.class ) {
+ // Flatten stacked regions (no loops involved)
+ if( getClass() == RegionNode.class && nIns()>2 ) {
for( int i=1; i<nIns(); i++ )
if( cfg(i) instanceof RegionNode region && region.getClass() == RegionNode.class && region.nIns()>2 && !hasMidUser(region) ) {
assert !region.inProgress();
@@ -130,7 +130,7 @@ public class RegionNode extends CFGNode {
if( use instanceof PhiNode ) {
for( Node data : use._outputs ) {
if( !(data instanceof PhiNode phi2) || phi2.region()!=this )
- { addDep(use); addDep(data); return true; }
+ { addDep(use); if( data!=null ) addDep(data); return true; }
}
} else
{ addDep(use); return true; } // Control user
diff --git a/src/main/java/com/seaofnodes/simple/node/ReturnNode.java b/src/main/java/com/seaofnodes/simple/node/ReturnNode.java
index b4173871..7971733a 100644
--- a/src/main/java/com/seaofnodes/simple/node/ReturnNode.java
+++ b/src/main/java/com/seaofnodes/simple/node/ReturnNode.java
@@ -1,12 +1,12 @@
package com.seaofnodes.simple.node;
import com.seaofnodes.simple.Parser;
-import com.seaofnodes.simple.SB;
-import com.seaofnodes.simple.Utils;
import com.seaofnodes.simple.codegen.CodeGen;
-import com.seaofnodes.simple.codegen.RegMask;
import com.seaofnodes.simple.codegen.Encoding;
+import com.seaofnodes.simple.codegen.RegMask;
import com.seaofnodes.simple.type.*;
+import com.seaofnodes.simple.util.SB;
+import com.seaofnodes.simple.util.Utils;
import java.util.BitSet;
/**
@@ -61,11 +61,10 @@ public class ReturnNode extends CFGNode {
// Upgrade signature based on return type
Type ret = expr()._type;
TypeFunPtr fcn = _fun.sig();
- assert ret.isa(fcn.ret());
- if( ret != fcn.ret() )
+ if( ret != fcn.ret() && ret.isa(fcn.ret()) )
_fun.setSig(fcn.makeFrom(ret));
- // If dead (cant be reached; infinite loop), kill the exit values
+ // If dead (cannot be reached; infinite loop), kill the exit values
if( ctrl()._type==Type.XCONTROL &&
!(mem() instanceof ConstantNode && expr() instanceof ConstantNode) ) {
Node top = new ConstantNode(Type.TOP).peephole();
@@ -100,8 +99,8 @@ public class ReturnNode extends CFGNode {
// Merge path into the One True Return
RegionNode r = (RegionNode)ctrl();
// Assert that the Phis are in particular outputs; not reordered or shuffled
- PhiNode mem = (PhiNode)r.out(0); assert mem._declaredType == TypeMem.BOT;
- PhiNode rez = (PhiNode)r.out(1); assert rez._declaredType == Type.BOTTOM;
+ PhiNode mem = (PhiNode)r.out(0); assert mem._minType == TypeMem.BOT;
+ PhiNode rez = (PhiNode)r.out(1); assert rez._minType == Type.BOTTOM;
// Pop "inProgress" null off
r ._inputs.pop();
mem._inputs.pop();
diff --git a/src/main/java/com/seaofnodes/simple/node/ScopeNode.java b/src/main/java/com/seaofnodes/simple/node/ScopeNode.java
index 3127e491..36746a81 100644
--- a/src/main/java/com/seaofnodes/simple/node/ScopeNode.java
+++ b/src/main/java/com/seaofnodes/simple/node/ScopeNode.java
@@ -1,8 +1,13 @@
package com.seaofnodes.simple.node;
-import com.seaofnodes.simple.*;
+import com.seaofnodes.simple.Parser;
+import com.seaofnodes.simple.Var;
import com.seaofnodes.simple.codegen.CodeGen;
import com.seaofnodes.simple.type.*;
+import com.seaofnodes.simple.util.Ary;
+import com.seaofnodes.simple.util.AryInt;
+import com.seaofnodes.simple.util.Utils;
+
import java.util.*;
/**
@@ -19,18 +24,26 @@ public class ScopeNode extends MemMergeNode {
public static final String ARG0 = "arg";
public static final String MEM0 = "$mem";
- // All active/live variables in all nested scopes, all run together
+ // All active/live variables in all nested scopes, all run together.
+ // Maps 1-to-1 to the _inputs array.
public final Ary<Var> _vars;
- // Size of each nested lexical scope
- public final Ary<Integer> _lexSize;
-
// Lexical scope is typed:
- // - Block scope - basic block scoping
- // - Constructor - struct type is defined, and here we give values to all fields
- // - Function - out-of-scope lookups restricted to final constants
- public enum Kind { Block, Constructor, Function };
+ public static class Kind {
+ // Basic block scoping
+ public static class Block extends Kind { }
+ // Function scope
+ public static class Func extends Kind { }
+ // Struct definition, mapping types to fields
+ public static class Define extends Kind { public Define(TypeMemPtr tmp) { _tmp=tmp; } public final TypeMemPtr _tmp; }
+ // Struct allocation, mapping values to fields
+ public static class Alloc extends Kind { public Alloc (TypeMemPtr tmp) { _tmp=tmp; } public final TypeMemPtr _tmp; }
+
+ public int _lexSize; // Number of Vars in this scope
+ }
public final Ary<Kind> _kinds;
+ // Lexical scope nesting depth
+ public int depth() { return _kinds._len; }
// Extra guards; tested predicates and casted results
private final Ary<Node> _guards;
@@ -38,10 +51,9 @@ public class ScopeNode extends MemMergeNode {
// A new ScopeNode
public ScopeNode() {
super(true);
- _vars = new Ary<>(Var .class);
- _lexSize= new Ary<>(Integer.class);
- _kinds = new Ary<>(Kind .class);
- _guards = new Ary<>(Node .class);
+ _vars = new Ary<>(Var .class);
+ _kinds = new Ary<>(Kind.class);
+ _guards = new Ary<>(Node.class);
}
@Override public String label() { return "Scope"; }
@@ -51,9 +63,9 @@ public class ScopeNode extends MemMergeNode {
sb.append("Scope[ ");
int j=1;
for( int i=0; i<nIns(); i++ ) {
- if( j < _lexSize._len && i == _lexSize.at(j) ) { sb.append("| "); j++; }
+ if( j < depth() && i == _kinds.at(j)._lexSize ) { sb.append("| "); j++; }
Var v = _vars.at(i);
- sb.append(v.type().print(new SB()));
+ sb.append(v.type());
sb.append(" ");
if( v._final ) sb.append("!");
sb.append(v._name);
@@ -90,17 +102,14 @@ public class ScopeNode extends MemMergeNode {
public Node mem(Node n) { return setDef(1,n); }
public void push( Kind kind ) {
- assert _lexSize._len==_kinds._len;
- _lexSize.push(_vars.size());
- _kinds .push(kind);
+ kind._lexSize = _vars.size();
+ _kinds.push(kind);
}
// Pop a lexical scope
public void pop() {
- assert _lexSize._len==_kinds._len;
promote(); // Promote forward references to the next outer scope
- int n = _lexSize.pop();
- _kinds.pop();
+ int n = _kinds.pop()._lexSize;
popUntil(n); // Pop off inputs going out of scope
_vars.setLen(n); // Pop off variables going out of scope
}
@@ -109,29 +118,56 @@ public class ScopeNode extends MemMergeNode {
// Look for forward references in the last lexical scope and promote to the
// next outer lexical scope. At the last scope declare them an error.
public void promote() {
- int n = _lexSize.last();
+ Kind kind = _kinds.last();
+ int n = kind._lexSize;
for( int i=n; i<nIns(); i++ ) {
Var v = var(i);
if( !v.isFRef() ) continue;
- if( _lexSize._len==1 )
+ if( depth()==1 )
throw Parser.error("Undefined name '" + v._name + "'",v._loc);
- _vars.swap(n,i);
+ _vars .swap(n,i);
_inputs.swap(n,i);
v._idx = n;
- n++;
- _lexSize.set(_lexSize._len-1,n);
+ kind._lexSize = ++n;
}
}
- public boolean inConstructor() { return _kinds.last() == Kind.Constructor; }
+ public boolean inConstructor() { return _kinds.last() instanceof Kind.Define; }
+ public boolean inAllocation () { return _kinds.last() instanceof Kind.Alloc ; }
+ public boolean inFunction () { return _kinds.last() instanceof Kind.Func ; }
+
+ public Kind kind( Var v ) {
+ for( int i=depth()-1; i>=0; i-- )
+ if( v._idx >= _kinds.at(i)._lexSize )
+ return _kinds.at(i);
+ throw Utils.TODO();
+ }
+
+ // Return the kind for the defining scope, or a function scope if found
+ // first. Block scopes means the variable can be r/w directly in the
+ // scope, Function scopes require final constants (no capture), and
+ // Constructor scopes mean an instance variable reference.
+
+ // Walk up-lexical scope looking for defining lexical Kind.
+ // - Skip any amount of nested block scopes
+ // - Walking out of a function requires v be a final constant (for now) -
+ // and we can stop walking.
+
+ // - Walking out of a method and (skipping Blocks) into the matching struct
+ // is OK, and this is a instance var load.
+
+ // - Walking out of a method and into the wrong struct is an error;
+ // including nested structs containing (no nested classes yet)
+
+ // Returns error, forward-ref, ok containing struct, ok containing function/block.
- // Is v outside any current function scope?
- public boolean outOfFunction( Var v ) {
- for( int i=_lexSize._len-1; i>=0 && v._idx<_lexSize.at(i); i-- )
- if( _kinds.at(i)==Kind.Function )
- return true;
- return false;
+ public String outOfFunction( Var v ) {
+ //if( v==null ) return null; // Prolly forward reference
+ //int i; for( i=_lexSize._len-1; i>=0 && v._idx<_lexSize.at(i); i-- )
+ // if( _kinds.at(i)=="{->}" ) return "{->}";
+ //return _kinds.at(i);
+ throw Utils.TODO();
}
@@ -149,9 +185,9 @@ public class ScopeNode extends MemMergeNode {
* Create a new variable name in the current scope
*/
public boolean define( String name, Type declaredType, boolean xfinal, Node init, Parser.Lexer loc ) {
- assert _lexSize.isEmpty() || name.charAt(0)!='$' ; // Later scopes do not define memory
- if( _lexSize._len > 0 )
- for( int i=_vars.size()-1; i>=_lexSize.last(); i-- ) {
+ assert _kinds.isEmpty() || name.charAt(0)!='$' ; // Later scopes do not define memory
+ if( depth() > 0 )
+ for( int i=_vars.size()-1; i>=_kinds.last()._lexSize; i-- ) {
Var n = var(i);
if( n._name.equals(name) ) {
if( !n.isFRef() ) return false; // Double define
@@ -214,7 +250,7 @@ public class ScopeNode extends MemMergeNode {
: loop.setDef(v._idx,new PhiNode(v._name, v.type(), loop.ctrl(), loop.in(loop.update(v,null)._idx),null).peephole());
setDef(v._idx,old);
}
- assert !v._final || st==null;
+ //assert !v._final || st==null;
if( st!=null ) setDef(v._idx,st); // Set new value
return v;
}
@@ -240,7 +276,6 @@ public class ScopeNode extends MemMergeNode {
// 2) Make the new ScopeNode a user of all the nodes bound
// 3) Ensure that the order of defs is the same to allow easy merging
dup._vars .addAll(_vars );
- dup._lexSize.addAll(_lexSize);
dup._kinds .addAll(_kinds );
dup._guards .addAll(_guards );
// The dup'd guards all need dup'd keepers, to keep proper accounting
diff --git a/src/main/java/com/seaofnodes/simple/node/SplitNode.java b/src/main/java/com/seaofnodes/simple/node/SplitNode.java
index 3a1ed011..d061cdbd 100644
--- a/src/main/java/com/seaofnodes/simple/node/SplitNode.java
+++ b/src/main/java/com/seaofnodes/simple/node/SplitNode.java
@@ -1,8 +1,8 @@
package com.seaofnodes.simple.node;
-import com.seaofnodes.simple.SB;
import com.seaofnodes.simple.codegen.CodeGen;
import com.seaofnodes.simple.type.Type;
+import com.seaofnodes.simple.util.SB;
import java.util.BitSet;
public abstract class SplitNode extends MachConcreteNode {
diff --git a/src/main/java/com/seaofnodes/simple/node/StartNode.java b/src/main/java/com/seaofnodes/simple/node/StartNode.java
index f40203b4..e3806de7 100644
--- a/src/main/java/com/seaofnodes/simple/node/StartNode.java
+++ b/src/main/java/com/seaofnodes/simple/node/StartNode.java
@@ -6,11 +6,11 @@ import com.seaofnodes.simple.type.*;
import java.util.Arrays;
import java.util.BitSet;
import java.util.HashSet;
-import static com.seaofnodes.simple.Utils.TODO;
+import static com.seaofnodes.simple.util.Utils.TODO;
/**
* The Start node represents the start of the function.
- *
+ * <p>
* Start initially has 1 input (arg) from outside and the initial control.
* In ch10 we also add mem aliases as structs get defined; each field in struct
* adds a distinct alias to Start's tuple.
@@ -19,7 +19,7 @@ public class StartNode extends LoopNode implements MultiNode {
final Type _arg;
- public StartNode(Type arg) { super((Parser.Lexer)null,null); _arg = arg; _type = compute(); }
+ public StartNode(Type arg) { super(null,null); _arg = arg; _type = compute(); }
public StartNode(StartNode start) { super(start); _arg = start==null ? null : start._arg; }
@Override public String label() { return "Start"; }
@@ -29,13 +29,12 @@ public class StartNode extends LoopNode implements MultiNode {
return sb.append(label());
}
- @Override public boolean blockHead() { return true; }
- @Override public CFGNode cfg0() { return null; }
+ @Override public CFGNode cfg0() { return null; }
// Get the one control following; error to call with more than one e.g. an
// IfNode or other multi-way branch. For Start, its "main"
@Override public CFGNode uctrl() {
- // Find "main", its the start.
+ // Find "main", it's the start.
CFGNode C = null;
for( Node use : _outputs )
if( use instanceof FunNode fun && fun.sig().isa(CodeGen.CODE._main) )
diff --git a/src/main/java/com/seaofnodes/simple/node/StopNode.java b/src/main/java/com/seaofnodes/simple/node/StopNode.java
index b65535f1..4b03bf4e 100644
--- a/src/main/java/com/seaofnodes/simple/node/StopNode.java
+++ b/src/main/java/com/seaofnodes/simple/node/StopNode.java
@@ -1,7 +1,7 @@
package com.seaofnodes.simple.node;
-import com.seaofnodes.simple.Utils;
import com.seaofnodes.simple.type.Type;
+import com.seaofnodes.simple.util.Utils;
import java.util.BitSet;
public class StopNode extends CFGNode {
diff --git a/src/main/java/com/seaofnodes/simple/node/StoreNode.java b/src/main/java/com/seaofnodes/simple/node/StoreNode.java
index 9b561bed..5fb274db 100644
--- a/src/main/java/com/seaofnodes/simple/node/StoreNode.java
+++ b/src/main/java/com/seaofnodes/simple/node/StoreNode.java
@@ -40,14 +40,16 @@ public class StoreNode extends MemOpNode {
@Override
public Type compute() {
Type val = val()._type;
- TypeMem mem = (TypeMem)mem()._type; // Invariant
+ Type mem0 = mem()._type;
+ if( mem0 == Type.TOP ) return TypeMem.TOP;
+ TypeMem mem = (TypeMem)mem0; // Invariant
if( mem == TypeMem.TOP ) return TypeMem.TOP;
Type t = Type.BOTTOM; // No idea on field contents
// Same alias, lift val to the declared type and then meet into other fields
if( mem._alias == _alias ) {
- // Update declared forward ref to the actual
- if( _declaredType.isFRef() && val instanceof TypeMemPtr tmp && !tmp.isFRef() )
- _declaredType = tmp;
+ assert !_declaredType.isFRef();
+ // Sharpen memory value; required for narrowing stores where the parser inserts
+ // zero/sign masking and somebody reads the TypeMem type.
val = val.join(_declaredType);
t = val.meet(mem._t);
}
@@ -57,6 +59,11 @@ public class StoreNode extends MemOpNode {
@Override
public Node idealize() {
+ if( mem() instanceof CastNode cast ) {
+ setDef(1,cast.in(1));
+ return this;
+ }
+
// Simple store-after-store on same address. Should pick up the
// required init-store being stomped by a first user store.
if( mem() instanceof StoreNode st &&
diff --git a/src/main/java/com/seaofnodes/simple/node/StructNode.java b/src/main/java/com/seaofnodes/simple/node/StructNode.java
index 4efc0de9..b5b59b81 100644
--- a/src/main/java/com/seaofnodes/simple/node/StructNode.java
+++ b/src/main/java/com/seaofnodes/simple/node/StructNode.java
@@ -1,7 +1,7 @@
package com.seaofnodes.simple.node;
-import com.seaofnodes.simple.SB;
import com.seaofnodes.simple.type.*;
+import com.seaofnodes.simple.util.SB;
import java.util.BitSet;
/**
@@ -9,7 +9,8 @@ import java.util.BitSet;
*/
public class StructNode extends Node {
- public TypeStruct _ts;
+ public final TypeStruct _ts;
+ public StructNode(TypeStruct ts) { _ts=ts; assert !ts._open; }
@Override public String label() { return _ts==null ? "STRUCT?" : _ts.str(); }
@@ -19,7 +20,7 @@ public class StructNode extends Node {
sb.append(_ts._name).append(" {");
for( int i=0; i<nIns(); i++ ) {
sb.append(_ts._fields[i]._fname).append(":");
- sb.append((in(i)==null ? Type.BOTTOM : in(i)._type).print(new SB()));
+ sb.append(in(i)==null ? Type.BOTTOM : in(i)._type);
sb.append("; ");
}
sb.setLength(sb.length()-2);
@@ -32,7 +33,7 @@ public class StructNode extends Node {
Field[] fs = new Field[_ts._fields.length];
for( int i=0; i<fs.length; i++ )
fs[i] = _ts._fields[i].makeFrom(in(i)==null ? Type.TOP : in(i)._type);
- return TypeStruct.make(_ts._name,fs);
+ return TypeStruct.make(_ts._name,false,fs);
}
@Override
diff --git a/src/main/java/com/seaofnodes/simple/node/cpus/arm/AddARM.java b/src/main/java/com/seaofnodes/simple/node/cpus/arm/AddARM.java
index f37738bf..1c865254 100644
--- a/src/main/java/com/seaofnodes/simple/node/cpus/arm/AddARM.java
+++ b/src/main/java/com/seaofnodes/simple/node/cpus/arm/AddARM.java
@@ -1,8 +1,8 @@
package com.seaofnodes.simple.node.cpus.arm;
-import com.seaofnodes.simple.*;
import com.seaofnodes.simple.codegen.*;
import com.seaofnodes.simple.node.*;
+import com.seaofnodes.simple.util.SB;
public class AddARM extends MachConcreteNode implements MachNode {
AddARM( Node add) { super(add); }
diff --git a/src/main/java/com/seaofnodes/simple/node/cpus/arm/AddFARM.java b/src/main/java/com/seaofnodes/simple/node/cpus/arm/AddFARM.java
index 209f24f4..eb75c1a0 100644
--- a/src/main/java/com/seaofnodes/simple/node/cpus/arm/AddFARM.java
+++ b/src/main/java/com/seaofnodes/simple/node/cpus/arm/AddFARM.java
@@ -1,8 +1,8 @@
package com.seaofnodes.simple.node.cpus.arm;
-import com.seaofnodes.simple.SB;
import com.seaofnodes.simple.codegen.*;
import com.seaofnodes.simple.node.*;
+import com.seaofnodes.simple.util.SB;
public class AddFARM extends MachConcreteNode implements MachNode {
AddFARM(Node addf) { super(addf); }
diff --git a/src/main/java/com/seaofnodes/simple/node/cpus/arm/AddIARM.java b/src/main/java/com/seaofnodes/simple/node/cpus/arm/AddIARM.java
index a1cd8306..93c9e8c3 100644
--- a/src/main/java/com/seaofnodes/simple/node/cpus/arm/AddIARM.java
+++ b/src/main/java/com/seaofnodes/simple/node/cpus/arm/AddIARM.java
@@ -1,6 +1,6 @@
package com.seaofnodes.simple.node.cpus.arm;
-import com.seaofnodes.simple.*;
+import com.seaofnodes.simple.util.SB;
import com.seaofnodes.simple.codegen.*;
import com.seaofnodes.simple.node.*;
diff --git a/src/main/java/com/seaofnodes/simple/node/cpus/arm/AndARM.java b/src/main/java/com/seaofnodes/simple/node/cpus/arm/AndARM.java
index ad76ca4c..77115d54 100644
--- a/src/main/java/com/seaofnodes/simple/node/cpus/arm/AndARM.java
+++ b/src/main/java/com/seaofnodes/simple/node/cpus/arm/AndARM.java
@@ -1,10 +1,10 @@
package com.seaofnodes.simple.node.cpus.arm;
-import com.seaofnodes.simple.SB;
import com.seaofnodes.simple.codegen.*;
import com.seaofnodes.simple.node.MachConcreteNode;
import com.seaofnodes.simple.node.MachNode;
import com.seaofnodes.simple.node.Node;
+import com.seaofnodes.simple.util.SB;
public class AndARM extends MachConcreteNode implements MachNode {
AndARM(Node and) { super(and); }
diff --git a/src/main/java/com/seaofnodes/simple/node/cpus/arm/AndIARM.java b/src/main/java/com/seaofnodes/simple/node/cpus/arm/AndIARM.java
index 1f12ef13..5b739cd3 100644
--- a/src/main/java/com/seaofnodes/simple/node/cpus/arm/AndIARM.java
+++ b/src/main/java/com/seaofnodes/simple/node/cpus/arm/AndIARM.java
@@ -1,8 +1,8 @@
package com.seaofnodes.simple.node.cpus.arm;
-import com.seaofnodes.simple.*;
import com.seaofnodes.simple.codegen.*;
import com.seaofnodes.simple.node.*;
+import com.seaofnodes.simple.util.SB;
public class AndIARM extends MachConcreteNode implements MachNode {
final int _imm;
diff --git a/src/main/java/com/seaofnodes/simple/node/cpus/arm/AsrARM.java b/src/main/java/com/seaofnodes/simple/node/cpus/arm/AsrARM.java
index 342b7519..b83fb3cb 100644
--- a/src/main/java/com/seaofnodes/simple/node/cpus/arm/AsrARM.java
+++ b/src/main/java/com/seaofnodes/simple/node/cpus/arm/AsrARM.java
@@ -1,8 +1,8 @@
package com.seaofnodes.simple.node.cpus.arm;
-import com.seaofnodes.simple.*;
import com.seaofnodes.simple.codegen.*;
import com.seaofnodes.simple.node.*;
+import com.seaofnodes.simple.util.SB;
// Arithmetic Shift Right (register)
public class AsrARM extends MachConcreteNode implements MachNode {
diff --git a/src/main/java/com/seaofnodes/simple/node/cpus/arm/AsrIARM.java b/src/main/java/com/seaofnodes/simple/node/cpus/arm/AsrIARM.java
index a1775dde..38373e67 100644
--- a/src/main/java/com/seaofnodes/simple/node/cpus/arm/AsrIARM.java
+++ b/src/main/java/com/seaofnodes/simple/node/cpus/arm/AsrIARM.java
@@ -1,12 +1,12 @@
package com.seaofnodes.simple.node.cpus.arm;
-import com.seaofnodes.simple.SB;
import com.seaofnodes.simple.codegen.CodeGen;
import com.seaofnodes.simple.codegen.Encoding;
import com.seaofnodes.simple.codegen.RegMask;
import com.seaofnodes.simple.node.MachConcreteNode;
import com.seaofnodes.simple.node.MachNode;
import com.seaofnodes.simple.node.Node;
+import com.seaofnodes.simple.util.SB;
public class AsrIARM extends MachConcreteNode implements MachNode {
final int _imm;
diff --git a/src/main/java/com/seaofnodes/simple/node/cpus/arm/BranchARM.java b/src/main/java/com/seaofnodes/simple/node/cpus/arm/BranchARM.java
index b36a395b..b9ede544 100644
--- a/src/main/java/com/seaofnodes/simple/node/cpus/arm/BranchARM.java
+++ b/src/main/java/com/seaofnodes/simple/node/cpus/arm/BranchARM.java
@@ -1,8 +1,9 @@
package com.seaofnodes.simple.node.cpus.arm;
-import com.seaofnodes.simple.*;
import com.seaofnodes.simple.codegen.*;
import com.seaofnodes.simple.node.*;
+import com.seaofnodes.simple.util.SB;
+import com.seaofnodes.simple.util.Utils;
// Jump on flags, uses flags
public class BranchARM extends IfNode implements MachNode, RIPRelSize {
diff --git a/src/main/java/com/seaofnodes/simple/node/cpus/arm/CallARM.java b/src/main/java/com/seaofnodes/simple/node/cpus/arm/CallARM.java
index 989bd366..427cf2e2 100644
--- a/src/main/java/com/seaofnodes/simple/node/cpus/arm/CallARM.java
+++ b/src/main/java/com/seaofnodes/simple/node/cpus/arm/CallARM.java
@@ -1,9 +1,9 @@
package com.seaofnodes.simple.node.cpus.arm;
-import com.seaofnodes.simple.*;
import com.seaofnodes.simple.codegen.*;
import com.seaofnodes.simple.node.*;
import com.seaofnodes.simple.type.TypeFunPtr;
+import com.seaofnodes.simple.util.SB;
public class CallARM extends CallNode implements MachNode, RIPRelSize {
final TypeFunPtr _tfp;
@@ -42,9 +42,9 @@ public class CallARM extends CallNode implements MachNode, RIPRelSize {
}
@Override public void asm(CodeGen code, SB sb) {
- sb.p(_name);
+ sb.p(_name).p(" ");
for( int i=0; i<nargs(); i++ )
- sb.p(code.reg(arg(i+2))).p(" ");
+ sb.p(code.reg(arg(i+2))).p(", ");
sb.unchar(2);
}
}
diff --git a/src/main/java/com/seaofnodes/simple/node/cpus/arm/CallRRARM.java b/src/main/java/com/seaofnodes/simple/node/cpus/arm/CallRRARM.java
index 87dde38c..c84aa9e5 100644
--- a/src/main/java/com/seaofnodes/simple/node/cpus/arm/CallRRARM.java
+++ b/src/main/java/com/seaofnodes/simple/node/cpus/arm/CallRRARM.java
@@ -1,8 +1,8 @@
package com.seaofnodes.simple.node.cpus.arm;
-import com.seaofnodes.simple.*;
import com.seaofnodes.simple.codegen.*;
import com.seaofnodes.simple.node.*;
+import com.seaofnodes.simple.util.SB;
public class CallRRARM extends CallNode implements MachNode {
CallRRARM(CallNode call) { super(call); }
@@ -25,7 +25,7 @@ public class CallRRARM extends CallNode implements MachNode {
@Override public void asm(CodeGen code, SB sb) {
sb.p(code.reg(fptr())).p(" ");
for( int i=0; i<nargs(); i++ )
- sb.p(code.reg(arg(i))).p(" ");
+ sb.p(code.reg(arg(i))).p(", ");
sb.unchar(2);
}
diff --git a/src/main/java/com/seaofnodes/simple/node/cpus/arm/CmpARM.java b/src/main/java/com/seaofnodes/simple/node/cpus/arm/CmpARM.java
index dbc86f62..794ff0c9 100644
--- a/src/main/java/com/seaofnodes/simple/node/cpus/arm/CmpARM.java
+++ b/src/main/java/com/seaofnodes/simple/node/cpus/arm/CmpARM.java
@@ -1,8 +1,8 @@
package com.seaofnodes.simple.node.cpus.arm;
-import com.seaofnodes.simple.SB;
import com.seaofnodes.simple.codegen.*;
import com.seaofnodes.simple.node.*;
+import com.seaofnodes.simple.util.SB;
public class CmpARM extends MachConcreteNode implements MachNode {
CmpARM( Node cmp ) { super(cmp); }
diff --git a/src/main/java/com/seaofnodes/simple/node/cpus/arm/CmpFARM.java b/src/main/java/com/seaofnodes/simple/node/cpus/arm/CmpFARM.java
index e82a2ee3..67ffc27b 100644
--- a/src/main/java/com/seaofnodes/simple/node/cpus/arm/CmpFARM.java
+++ b/src/main/java/com/seaofnodes/simple/node/cpus/arm/CmpFARM.java
@@ -1,8 +1,8 @@
package com.seaofnodes.simple.node.cpus.arm;
-import com.seaofnodes.simple.*;
import com.seaofnodes.simple.codegen.*;
import com.seaofnodes.simple.node.*;
+import com.seaofnodes.simple.util.SB;
// compare instruction on float regs input(D-registers)
public class CmpFARM extends MachConcreteNode implements MachNode{
diff --git a/src/main/java/com/seaofnodes/simple/node/cpus/arm/CmpIARM.java b/src/main/java/com/seaofnodes/simple/node/cpus/arm/CmpIARM.java
index 8a4f242a..f84a1649 100644
--- a/src/main/java/com/seaofnodes/simple/node/cpus/arm/CmpIARM.java
+++ b/src/main/java/com/seaofnodes/simple/node/cpus/arm/CmpIARM.java
@@ -1,8 +1,8 @@
package com.seaofnodes.simple.node.cpus.arm;
-import com.seaofnodes.simple.*;
import com.seaofnodes.simple.codegen.*;
import com.seaofnodes.simple.node.*;
+import com.seaofnodes.simple.util.SB;
// Compare with immediate.
// CMP (immediate) - SUBS
diff --git a/src/main/java/com/seaofnodes/simple/node/cpus/arm/DivARM.java b/src/main/java/com/seaofnodes/simple/node/cpus/arm/DivARM.java
index 40bd8387..de254eeb 100644
--- a/src/main/java/com/seaofnodes/simple/node/cpus/arm/DivARM.java
+++ b/src/main/java/com/seaofnodes/simple/node/cpus/arm/DivARM.java
@@ -1,8 +1,8 @@
package com.seaofnodes.simple.node.cpus.arm;
-import com.seaofnodes.simple.*;
import com.seaofnodes.simple.codegen.*;
import com.seaofnodes.simple.node.*;
+import com.seaofnodes.simple.util.SB;
public class DivARM extends MachConcreteNode implements MachNode {
DivARM( Node div ) { super(div); }
diff --git a/src/main/java/com/seaofnodes/simple/node/cpus/arm/DivFARM.java b/src/main/java/com/seaofnodes/simple/node/cpus/arm/DivFARM.java
index 72b76444..813bebe4 100644
--- a/src/main/java/com/seaofnodes/simple/node/cpus/arm/DivFARM.java
+++ b/src/main/java/com/seaofnodes/simple/node/cpus/arm/DivFARM.java
@@ -1,8 +1,8 @@
package com.seaofnodes.simple.node.cpus.arm;
-import com.seaofnodes.simple.*;
import com.seaofnodes.simple.codegen.*;
import com.seaofnodes.simple.node.*;
+import com.seaofnodes.simple.util.SB;
public class DivFARM extends MachConcreteNode implements MachNode {
DivFARM( Node divf) { super(divf); }
diff --git a/src/main/java/com/seaofnodes/simple/node/cpus/arm/FloatARM.java b/src/main/java/com/seaofnodes/simple/node/cpus/arm/FloatARM.java
index 63c57770..b47b65ad 100644
--- a/src/main/java/com/seaofnodes/simple/node/cpus/arm/FloatARM.java
+++ b/src/main/java/com/seaofnodes/simple/node/cpus/arm/FloatARM.java
@@ -1,11 +1,11 @@
package com.seaofnodes.simple.node.cpus.arm;
-import com.seaofnodes.simple.SB;
-import com.seaofnodes.simple.Utils;
import com.seaofnodes.simple.codegen.*;
import com.seaofnodes.simple.node.ConstantNode;
import com.seaofnodes.simple.node.MachNode;
import com.seaofnodes.simple.type.TypeFloat;
+import com.seaofnodes.simple.util.SB;
+import com.seaofnodes.simple.util.Utils;
//FMOV (scalar, immediate)
//Floating-point move immediate.
diff --git a/src/main/java/com/seaofnodes/simple/node/cpus/arm/FunARM.java b/src/main/java/com/seaofnodes/simple/node/cpus/arm/FunARM.java
index 32777f03..44a417f9 100644
--- a/src/main/java/com/seaofnodes/simple/node/cpus/arm/FunARM.java
+++ b/src/main/java/com/seaofnodes/simple/node/cpus/arm/FunARM.java
@@ -1,10 +1,10 @@
package com.seaofnodes.simple.node.cpus.arm;
-import com.seaofnodes.simple.SB;
-import com.seaofnodes.simple.Utils;
import com.seaofnodes.simple.codegen.*;
import com.seaofnodes.simple.node.FunNode;
import com.seaofnodes.simple.node.MachNode;
+import com.seaofnodes.simple.util.SB;
+import com.seaofnodes.simple.util.Utils;
public class FunARM extends FunNode implements MachNode {
FunARM(FunNode fun) { super(fun); }
diff --git a/src/main/java/com/seaofnodes/simple/node/cpus/arm/I2F8ARM.java b/src/main/java/com/seaofnodes/simple/node/cpus/arm/I2F8ARM.java
index 5ecc98b6..f1fa162f 100644
--- a/src/main/java/com/seaofnodes/simple/node/cpus/arm/I2F8ARM.java
+++ b/src/main/java/com/seaofnodes/simple/node/cpus/arm/I2F8ARM.java
@@ -1,8 +1,8 @@
package com.seaofnodes.simple.node.cpus.arm;
-import com.seaofnodes.simple.*;
import com.seaofnodes.simple.codegen.*;
import com.seaofnodes.simple.node.*;
+import com.seaofnodes.simple.util.SB;
public class I2F8ARM extends MachConcreteNode implements MachNode {
I2F8ARM(Node i2f8) { super(i2f8); }
diff --git a/src/main/java/com/seaofnodes/simple/node/cpus/arm/IntARM.java b/src/main/java/com/seaofnodes/simple/node/cpus/arm/IntARM.java
index 0a07b07a..ee74b95e 100644
--- a/src/main/java/com/seaofnodes/simple/node/cpus/arm/IntARM.java
+++ b/src/main/java/com/seaofnodes/simple/node/cpus/arm/IntARM.java
@@ -1,11 +1,11 @@
package com.seaofnodes.simple.node.cpus.arm;
-import com.seaofnodes.simple.*;
import com.seaofnodes.simple.codegen.*;
import com.seaofnodes.simple.node.ConstantNode;
import com.seaofnodes.simple.node.MachNode;
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeInteger;
+import com.seaofnodes.simple.util.SB;
// Integer constants
public class IntARM extends ConstantNode implements MachNode {
diff --git a/src/main/java/com/seaofnodes/simple/node/cpus/arm/LoadARM.java b/src/main/java/com/seaofnodes/simple/node/cpus/arm/LoadARM.java
index 44c13321..1e5d2094 100644
--- a/src/main/java/com/seaofnodes/simple/node/cpus/arm/LoadARM.java
+++ b/src/main/java/com/seaofnodes/simple/node/cpus/arm/LoadARM.java
@@ -1,10 +1,10 @@
package com.seaofnodes.simple.node.cpus.arm;
-import com.seaofnodes.simple.SB;
import com.seaofnodes.simple.codegen.*;
import com.seaofnodes.simple.node.LoadNode;
import com.seaofnodes.simple.node.Node;
import com.seaofnodes.simple.type.TypeFloat;
+import com.seaofnodes.simple.util.SB;
// Load memory addressing on ARM
// Support imm, reg(direct), or reg+off(indirect) addressing
diff --git a/src/main/java/com/seaofnodes/simple/node/cpus/arm/LslARM.java b/src/main/java/com/seaofnodes/simple/node/cpus/arm/LslARM.java
index 055d6dcc..80ce493f 100644
--- a/src/main/java/com/seaofnodes/simple/node/cpus/arm/LslARM.java
+++ b/src/main/java/com/seaofnodes/simple/node/cpus/arm/LslARM.java
@@ -1,8 +1,8 @@
package com.seaofnodes.simple.node.cpus.arm;
-import com.seaofnodes.simple.*;
import com.seaofnodes.simple.codegen.*;
import com.seaofnodes.simple.node.*;
+import com.seaofnodes.simple.util.SB;
// Logical Shift Left (register)
public class LslARM extends MachConcreteNode implements MachNode {
diff --git a/src/main/java/com/seaofnodes/simple/node/cpus/arm/LslIARM.java b/src/main/java/com/seaofnodes/simple/node/cpus/arm/LslIARM.java
index 94d3e25b..7fe16cbe 100644
--- a/src/main/java/com/seaofnodes/simple/node/cpus/arm/LslIARM.java
+++ b/src/main/java/com/seaofnodes/simple/node/cpus/arm/LslIARM.java
@@ -1,12 +1,12 @@
package com.seaofnodes.simple.node.cpus.arm;
-import com.seaofnodes.simple.SB;
import com.seaofnodes.simple.codegen.CodeGen;
import com.seaofnodes.simple.codegen.Encoding;
import com.seaofnodes.simple.codegen.RegMask;
import com.seaofnodes.simple.node.MachConcreteNode;
import com.seaofnodes.simple.node.MachNode;
import com.seaofnodes.simple.node.Node;
+import com.seaofnodes.simple.util.SB;
public class LslIARM extends MachConcreteNode implements MachNode {
final int _imm;
diff --git a/src/main/java/com/seaofnodes/simple/node/cpus/arm/LsrARM.java b/src/main/java/com/seaofnodes/simple/node/cpus/arm/LsrARM.java
index a691e0fe..fc005e04 100644
--- a/src/main/java/com/seaofnodes/simple/node/cpus/arm/LsrARM.java
+++ b/src/main/java/com/seaofnodes/simple/node/cpus/arm/LsrARM.java
@@ -1,8 +1,8 @@
package com.seaofnodes.simple.node.cpus.arm;
-import com.seaofnodes.simple.*;
import com.seaofnodes.simple.codegen.*;
import com.seaofnodes.simple.node.*;
+import com.seaofnodes.simple.util.SB;
// Logical Shift Right (register)
public class LsrARM extends MachConcreteNode implements MachNode {
diff --git a/src/main/java/com/seaofnodes/simple/node/cpus/arm/LsrIARM.java b/src/main/java/com/seaofnodes/simple/node/cpus/arm/LsrIARM.java
index 094cd30f..78844b0a 100644
--- a/src/main/java/com/seaofnodes/simple/node/cpus/arm/LsrIARM.java
+++ b/src/main/java/com/seaofnodes/simple/node/cpus/arm/LsrIARM.java
@@ -1,9 +1,8 @@
package com.seaofnodes.simple.node.cpus.arm;
-
-import com.seaofnodes.simple.*;
import com.seaofnodes.simple.codegen.*;
import com.seaofnodes.simple.node.*;
+import com.seaofnodes.simple.util.SB;
// logical right shift immediate
public class LsrIARM extends MachConcreteNode implements MachNode {
diff --git a/src/main/java/com/seaofnodes/simple/node/cpus/arm/MemOpARM.java b/src/main/java/com/seaofnodes/simple/node/cpus/arm/MemOpARM.java
index 6d8344a2..e877931d 100644
--- a/src/main/java/com/seaofnodes/simple/node/cpus/arm/MemOpARM.java
+++ b/src/main/java/com/seaofnodes/simple/node/cpus/arm/MemOpARM.java
@@ -1,14 +1,13 @@
package com.seaofnodes.simple.node.cpus.arm;
-import com.seaofnodes.simple.*;
import com.seaofnodes.simple.codegen.*;
import com.seaofnodes.simple.node.*;
import com.seaofnodes.simple.type.*;
-
+import com.seaofnodes.simple.util.SB;
+import com.seaofnodes.simple.util.Utils;
import java.lang.StringBuilder;
import java.util.BitSet;
-
public abstract class MemOpARM extends MemOpNode implements MachNode {
final int _off; // Limit 9 bits sized, or (13 bits<<logsize) unsigned
final int _imm; // Limit ? bits
diff --git a/src/main/java/com/seaofnodes/simple/node/cpus/arm/MulARM.java b/src/main/java/com/seaofnodes/simple/node/cpus/arm/MulARM.java
index 3514db9b..a23ec75b 100644
--- a/src/main/java/com/seaofnodes/simple/node/cpus/arm/MulARM.java
+++ b/src/main/java/com/seaofnodes/simple/node/cpus/arm/MulARM.java
@@ -1,8 +1,8 @@
package com.seaofnodes.simple.node.cpus.arm;
-import com.seaofnodes.simple.*;
import com.seaofnodes.simple.codegen.*;
import com.seaofnodes.simple.node.*;
+import com.seaofnodes.simple.util.SB;
// mulh signed multiply instruction(no-imm form)
public class MulARM extends MachConcreteNode implements MachNode {
diff --git a/src/main/java/com/seaofnodes/simple/node/cpus/arm/MulFARM.java b/src/main/java/com/seaofnodes/simple/node/cpus/arm/MulFARM.java
index 89dba172..73ebbf00 100644
--- a/src/main/java/com/seaofnodes/simple/node/cpus/arm/MulFARM.java
+++ b/src/main/java/com/seaofnodes/simple/node/cpus/arm/MulFARM.java
@@ -1,8 +1,8 @@
package com.seaofnodes.simple.node.cpus.arm;
-import com.seaofnodes.simple.*;
import com.seaofnodes.simple.codegen.*;
import com.seaofnodes.simple.node.*;
+import com.seaofnodes.simple.util.SB;
public class MulFARM extends MachConcreteNode implements MachNode{
MulFARM(Node mulf) {super(mulf);}
diff --git a/src/main/java/com/seaofnodes/simple/node/cpus/arm/NegARM.java b/src/main/java/com/seaofnodes/simple/node/cpus/arm/NegARM.java
index b7c3c803..881b41f9 100644
--- a/src/main/java/com/seaofnodes/simple/node/cpus/arm/NegARM.java
+++ b/src/main/java/com/seaofnodes/simple/node/cpus/arm/NegARM.java
@@ -1,10 +1,10 @@
package com.seaofnodes.simple.node.cpus.arm;
-import com.seaofnodes.simple.*;
import com.seaofnodes.simple.codegen.*;
import com.seaofnodes.simple.node.*;
import com.seaofnodes.simple.node.MachConcreteNode;
import com.seaofnodes.simple.type.TypeInteger;
+import com.seaofnodes.simple.util.SB;
public class NegARM extends MachConcreteNode implements MachNode {
NegARM(Node sub) {
diff --git a/src/main/java/com/seaofnodes/simple/node/cpus/arm/NewARM.java b/src/main/java/com/seaofnodes/simple/node/cpus/arm/NewARM.java
index cb51eea2..c1aad15f 100644
--- a/src/main/java/com/seaofnodes/simple/node/cpus/arm/NewARM.java
+++ b/src/main/java/com/seaofnodes/simple/node/cpus/arm/NewARM.java
@@ -1,8 +1,9 @@
package com.seaofnodes.simple.node.cpus.arm;
-import com.seaofnodes.simple.*;
import com.seaofnodes.simple.codegen.*;
import com.seaofnodes.simple.node.*;
+import com.seaofnodes.simple.util.SB;
+import com.seaofnodes.simple.util.Utils;
public class NewARM extends NewNode implements MachNode, RIPRelSize {
// A pre-zeroed chunk of memory.
diff --git a/src/main/java/com/seaofnodes/simple/node/cpus/arm/NotARM.java b/src/main/java/com/seaofnodes/simple/node/cpus/arm/NotARM.java
index 5a8d882d..027a8128 100644
--- a/src/main/java/com/seaofnodes/simple/node/cpus/arm/NotARM.java
+++ b/src/main/java/com/seaofnodes/simple/node/cpus/arm/NotARM.java
@@ -1,10 +1,9 @@
package com.seaofnodes.simple.node.cpus.arm;
-import com.seaofnodes.simple.*;
import com.seaofnodes.simple.codegen.*;
import com.seaofnodes.simple.node.*;
-
import com.seaofnodes.simple.node.MachConcreteNode;
+import com.seaofnodes.simple.util.SB;
public class NotARM extends MachConcreteNode implements MachNode{
NotARM(NotNode not) {super(not);}
diff --git a/src/main/java/com/seaofnodes/simple/node/cpus/arm/OrARM.java b/src/main/java/com/seaofnodes/simple/node/cpus/arm/OrARM.java
index b5cfa8cf..e8245749 100644
--- a/src/main/java/com/seaofnodes/simple/node/cpus/arm/OrARM.java
+++ b/src/main/java/com/seaofnodes/simple/node/cpus/arm/OrARM.java
@@ -1,8 +1,8 @@
package com.seaofnodes.simple.node.cpus.arm;
-import com.seaofnodes.simple.SB;
import com.seaofnodes.simple.codegen.*;
import com.seaofnodes.simple.node.*;
+import com.seaofnodes.simple.util.SB;
// Not using the ORRS variant.
public class OrARM extends MachConcreteNode implements MachNode {
diff --git a/src/main/java/com/seaofnodes/simple/node/cpus/arm/OrIARM.java b/src/main/java/com/seaofnodes/simple/node/cpus/arm/OrIARM.java
index 2a2d199a..a48caa51 100644
--- a/src/main/java/com/seaofnodes/simple/node/cpus/arm/OrIARM.java
+++ b/src/main/java/com/seaofnodes/simple/node/cpus/arm/OrIARM.java
@@ -1,8 +1,8 @@
package com.seaofnodes.simple.node.cpus.arm;
-import com.seaofnodes.simple.*;
import com.seaofnodes.simple.codegen.*;
import com.seaofnodes.simple.node.*;
+import com.seaofnodes.simple.util.SB;
public class OrIARM extends MachConcreteNode implements MachNode {
final int _imm;
diff --git a/src/main/java/com/seaofnodes/simple/node/cpus/arm/SetARM.java b/src/main/java/com/seaofnodes/simple/node/cpus/arm/SetARM.java
index 246e482a..01b46b8d 100644
--- a/src/main/java/com/seaofnodes/simple/node/cpus/arm/SetARM.java
+++ b/src/main/java/com/seaofnodes/simple/node/cpus/arm/SetARM.java
@@ -1,8 +1,8 @@
package com.seaofnodes.simple.node.cpus.arm;
-import com.seaofnodes.simple.*;
import com.seaofnodes.simple.codegen.*;
import com.seaofnodes.simple.node.*;
+import com.seaofnodes.simple.util.SB;
// conditional set?
// e.g CSET, stores flag info into GPRS after compare
diff --git a/src/main/java/com/seaofnodes/simple/node/cpus/arm/SplitARM.java b/src/main/java/com/seaofnodes/simple/node/cpus/arm/SplitARM.java
index 62bb75aa..5af45892 100644
--- a/src/main/java/com/seaofnodes/simple/node/cpus/arm/SplitARM.java
+++ b/src/main/java/com/seaofnodes/simple/node/cpus/arm/SplitARM.java
@@ -1,12 +1,11 @@
package com.seaofnodes.simple.node.cpus.arm;
-import com.seaofnodes.simple.SB;
-import com.seaofnodes.simple.Utils;
import com.seaofnodes.simple.codegen.*;
import com.seaofnodes.simple.node.FunNode;
import com.seaofnodes.simple.node.Node;
import com.seaofnodes.simple.node.SplitNode;
-import com.seaofnodes.simple.node.cpus.riscv.riscv;
+import com.seaofnodes.simple.util.SB;
+import com.seaofnodes.simple.util.Utils;
public class SplitARM extends SplitNode {
SplitARM(String kind, byte round) { super(kind,round,new Node[2]);}
diff --git a/src/main/java/com/seaofnodes/simple/node/cpus/arm/StoreARM.java b/src/main/java/com/seaofnodes/simple/node/cpus/arm/StoreARM.java
index 688d8731..91385ac9 100644
--- a/src/main/java/com/seaofnodes/simple/node/cpus/arm/StoreARM.java
+++ b/src/main/java/com/seaofnodes/simple/node/cpus/arm/StoreARM.java
@@ -1,10 +1,10 @@
package com.seaofnodes.simple.node.cpus.arm;
-import com.seaofnodes.simple.SB;
import com.seaofnodes.simple.codegen.*;
-import com.seaofnodes.simple.node.StoreNode;
import com.seaofnodes.simple.node.Node;
+import com.seaofnodes.simple.node.StoreNode;
import com.seaofnodes.simple.type.TypeFloat;
+import com.seaofnodes.simple.util.SB;
// Store memory addressing on ARM
// Support imm, reg(direct), or reg+off(indirect) addressing
diff --git a/src/main/java/com/seaofnodes/simple/node/cpus/arm/SubARM.java b/src/main/java/com/seaofnodes/simple/node/cpus/arm/SubARM.java
index 552b46df..e3b95e50 100644
--- a/src/main/java/com/seaofnodes/simple/node/cpus/arm/SubARM.java
+++ b/src/main/java/com/seaofnodes/simple/node/cpus/arm/SubARM.java
@@ -1,8 +1,8 @@
package com.seaofnodes.simple.node.cpus.arm;
-import com.seaofnodes.simple.SB;
import com.seaofnodes.simple.codegen.*;
import com.seaofnodes.simple.node.*;
+import com.seaofnodes.simple.util.SB;
public class SubARM extends MachConcreteNode implements MachNode {
SubARM(Node sub) { super(sub); }
diff --git a/src/main/java/com/seaofnodes/simple/node/cpus/arm/SubFARM.java b/src/main/java/com/seaofnodes/simple/node/cpus/arm/SubFARM.java
index 0d8d3c10..a252e542 100644
--- a/src/main/java/com/seaofnodes/simple/node/cpus/arm/SubFARM.java
+++ b/src/main/java/com/seaofnodes/simple/node/cpus/arm/SubFARM.java
@@ -1,8 +1,8 @@
package com.seaofnodes.simple.node.cpus.arm;
-import com.seaofnodes.simple.SB;
import com.seaofnodes.simple.codegen.*;
import com.seaofnodes.simple.node.*;
+import com.seaofnodes.simple.util.SB;
public class SubFARM extends MachConcreteNode implements MachNode {
SubFARM(Node subf) {super(subf);}
diff --git a/src/main/java/com/seaofnodes/simple/node/cpus/arm/SubIARM.java b/src/main/java/com/seaofnodes/simple/node/cpus/arm/SubIARM.java
index b882c5a4..b50107c9 100644
--- a/src/main/java/com/seaofnodes/simple/node/cpus/arm/SubIARM.java
+++ b/src/main/java/com/seaofnodes/simple/node/cpus/arm/SubIARM.java
@@ -1,11 +1,10 @@
package com.seaofnodes.simple.node.cpus.arm;
import com.seaofnodes.simple.codegen.*;
-import com.seaofnodes.simple.node.MachConcreteNode;
-
-import com.seaofnodes.simple.*;
import com.seaofnodes.simple.node.*;
+import com.seaofnodes.simple.node.MachConcreteNode;
import com.seaofnodes.simple.type.TypeInteger;
+import com.seaofnodes.simple.util.SB;
public class SubIARM extends MachConcreteNode implements MachNode {
final int _imm;
diff --git a/src/main/java/com/seaofnodes/simple/node/cpus/arm/TFPARM.java b/src/main/java/com/seaofnodes/simple/node/cpus/arm/TFPARM.java
index 606b03f0..29d490ef 100644
--- a/src/main/java/com/seaofnodes/simple/node/cpus/arm/TFPARM.java
+++ b/src/main/java/com/seaofnodes/simple/node/cpus/arm/TFPARM.java
@@ -1,11 +1,12 @@
package com.seaofnodes.simple.node.cpus.arm;
-import com.seaofnodes.simple.*;
import com.seaofnodes.simple.codegen.*;
import com.seaofnodes.simple.node.ConstantNode;
import com.seaofnodes.simple.node.MachNode;
import com.seaofnodes.simple.node.Node;
import com.seaofnodes.simple.type.TypeFunPtr;
+import com.seaofnodes.simple.util.SB;
+import com.seaofnodes.simple.util.Utils;
public class TFPARM extends ConstantNode implements MachNode, RIPRelSize {
TFPARM( ConstantNode con ) { super(con); }
diff --git a/src/main/java/com/seaofnodes/simple/node/cpus/arm/TMPARM.java b/src/main/java/com/seaofnodes/simple/node/cpus/arm/TMPARM.java
index 68e32c78..cdcaa433 100644
--- a/src/main/java/com/seaofnodes/simple/node/cpus/arm/TMPARM.java
+++ b/src/main/java/com/seaofnodes/simple/node/cpus/arm/TMPARM.java
@@ -1,11 +1,12 @@
package com.seaofnodes.simple.node.cpus.arm;
-import com.seaofnodes.simple.*;
import com.seaofnodes.simple.codegen.*;
import com.seaofnodes.simple.node.ConstantNode;
import com.seaofnodes.simple.node.MachNode;
import com.seaofnodes.simple.node.Node;
import com.seaofnodes.simple.type.TypeMemPtr;
+import com.seaofnodes.simple.util.SB;
+import com.seaofnodes.simple.util.Utils;
public class TMPARM extends ConstantNode implements MachNode, RIPRelSize {
TMPARM( ConstantNode con ) { super(con); }
diff --git a/src/main/java/com/seaofnodes/simple/node/cpus/arm/UJmpARM.java b/src/main/java/com/seaofnodes/simple/node/cpus/arm/UJmpARM.java
index a69c3c7c..2dd5fd6b 100644
--- a/src/main/java/com/seaofnodes/simple/node/cpus/arm/UJmpARM.java
+++ b/src/main/java/com/seaofnodes/simple/node/cpus/arm/UJmpARM.java
@@ -1,9 +1,10 @@
package com.seaofnodes.simple.node.cpus.arm;
-import com.seaofnodes.simple.*;
import com.seaofnodes.simple.codegen.*;
import com.seaofnodes.simple.node.*;
import com.seaofnodes.simple.type.Type;
+import com.seaofnodes.simple.util.SB;
+import com.seaofnodes.simple.util.Utils;
import java.util.BitSet;
// unconditional jump
diff --git a/src/main/java/com/seaofnodes/simple/node/cpus/arm/XorARM.java b/src/main/java/com/seaofnodes/simple/node/cpus/arm/XorARM.java
index ec86cfa5..52bda021 100644
--- a/src/main/java/com/seaofnodes/simple/node/cpus/arm/XorARM.java
+++ b/src/main/java/com/seaofnodes/simple/node/cpus/arm/XorARM.java
@@ -1,8 +1,8 @@
package com.seaofnodes.simple.node.cpus.arm;
-import com.seaofnodes.simple.SB;
import com.seaofnodes.simple.codegen.*;
import com.seaofnodes.simple.node.*;
+import com.seaofnodes.simple.util.SB;
public class XorARM extends MachConcreteNode implements MachNode{
XorARM(Node xor) {super(xor);}
diff --git a/src/main/java/com/seaofnodes/simple/node/cpus/arm/XorIARM.java b/src/main/java/com/seaofnodes/simple/node/cpus/arm/XorIARM.java
index e2582d22..23b29644 100644
--- a/src/main/java/com/seaofnodes/simple/node/cpus/arm/XorIARM.java
+++ b/src/main/java/com/seaofnodes/simple/node/cpus/arm/XorIARM.java
@@ -1,11 +1,10 @@
package com.seaofnodes.simple.node.cpus.arm;
-import com.seaofnodes.simple.node.MachConcreteNode;
-import com.seaofnodes.simple.node.MachNode;
-
-import com.seaofnodes.simple.*;
import com.seaofnodes.simple.codegen.*;
import com.seaofnodes.simple.node.*;
+import com.seaofnodes.simple.node.MachConcreteNode;
+import com.seaofnodes.simple.node.MachNode;
+import com.seaofnodes.simple.util.SB;
public class XorIARM extends MachConcreteNode implements MachNode {
final int _imm;
diff --git a/src/main/java/com/seaofnodes/simple/node/cpus/arm/arm.java b/src/main/java/com/seaofnodes/simple/node/cpus/arm/arm.java
index e6f64158..9dbf724d 100644
--- a/src/main/java/com/seaofnodes/simple/node/cpus/arm/arm.java
+++ b/src/main/java/com/seaofnodes/simple/node/cpus/arm/arm.java
@@ -1,9 +1,9 @@
package com.seaofnodes.simple.node.cpus.arm;
-import com.seaofnodes.simple.Utils;
import com.seaofnodes.simple.codegen.*;
import com.seaofnodes.simple.node.*;
import com.seaofnodes.simple.type.*;
+import com.seaofnodes.simple.util.Utils;
public class arm extends Machine {
public arm( CodeGen code ) {
diff --git a/src/main/java/com/seaofnodes/simple/node/cpus/riscv/AUIPC.java b/src/main/java/com/seaofnodes/simple/node/cpus/riscv/AUIPC.java
index 37383608..2cd00845 100644
--- a/src/main/java/com/seaofnodes/simple/node/cpus/riscv/AUIPC.java
+++ b/src/main/java/com/seaofnodes/simple/node/cpus/riscv/AUIPC.java
@@ -1,10 +1,11 @@
package com.seaofnodes.simple.node.cpus.riscv;
-import com.seaofnodes.simple.*;
import com.seaofnodes.simple.codegen.*;
import com.seaofnodes.simple.node.ConstantNode;
import com.seaofnodes.simple.node.MachNode;
import com.seaofnodes.simple.type.Type;
+import com.seaofnodes.simple.util.SB;
+import com.seaofnodes.simple.util.Utils;
// Add upper 20bits to PC. Immediate comes from the relocation info.
public class AUIPC extends ConstantNode implements MachNode, RIPRelSize {
diff --git a/src/main/java/com/seaofnodes/simple/node/cpus/riscv/AddFRISC.java b/src/main/java/com/seaofnodes/simple/node/cpus/riscv/AddFRISC.java
index 4d2ac916..8636df9f 100644
--- a/src/main/java/com/seaofnodes/simple/node/cpus/riscv/AddFRISC.java
+++ b/src/main/java/com/seaofnodes/simple/node/cpus/riscv/AddFRISC.java
@@ -1,8 +1,8 @@
package com.seaofnodes.simple.node.cpus.riscv;
-import com.seaofnodes.simple.SB;
import com.seaofnodes.simple.codegen.*;
import com.seaofnodes.simple.node.*;
+import com.seaofnodes.simple.util.SB;
// fadd.d
public class AddFRISC extends MachConcreteNode implements MachNode {
diff --git a/src/main/java/com/seaofnodes/simple/node/cpus/riscv/AddIRISC.java b/src/main/java/com/seaofnodes/simple/node/cpus/riscv/AddIRISC.java
index a85ce5d0..511b0583 100644
--- a/src/main/java/com/seaofnodes/simple/node/cpus/riscv/AddIRISC.java
+++ b/src/main/java/com/seaofnodes/simple/node/cpus/riscv/AddIRISC.java
@@ -1,7 +1,7 @@
package com.seaofnodes.simple.node.cpus.riscv;
-import com.seaofnodes.simple.Utils;
import com.seaofnodes.simple.node.Node;
+import com.seaofnodes.simple.util.Utils;
public class AddIRISC extends ImmRISC {
// Used to inst-selection as a direct match against an ideal Add/Sub
diff --git a/src/main/java/com/seaofnodes/simple/node/cpus/riscv/AddRISC.java b/src/main/java/com/seaofnodes/simple/node/cpus/riscv/AddRISC.java
index df392a0e..7010916f 100644
--- a/src/main/java/com/seaofnodes/simple/node/cpus/riscv/AddRISC.java
+++ b/src/main/java/com/seaofnodes/simple/node/cpus/riscv/AddRISC.java
@@ -1,8 +1,8 @@
package com.seaofnodes.simple.node.cpus.riscv;
-import com.seaofnodes.simple.SB;
import com.seaofnodes.simple.codegen.*;
import com.seaofnodes.simple.node.*;
+import com.seaofnodes.simple.util.SB;
public class AddRISC extends MachConcreteNode implements MachNode {
public AddRISC( Node add ) { super(add); }
diff --git a/src/main/java/com/seaofnodes/simple/node/cpus/riscv/AndIRISC.java b/src/main/java/com/seaofnodes/simple/node/cpus/riscv/AndIRISC.java
index ba88bb48..842c8bdc 100644
--- a/src/main/java/com/seaofnodes/simple/node/cpus/riscv/AndIRISC.java
+++ b/src/main/java/com/seaofnodes/simple/node/cpus/riscv/AndIRISC.java
@@ -1,7 +1,7 @@
package com.seaofnodes.simple.node.cpus.riscv;
-import com.seaofnodes.simple.Utils;
import com.seaofnodes.simple.node.Node;
+import com.seaofnodes.simple.util.Utils;
public class AndIRISC extends ImmRISC {
public AndIRISC( Node and, int imm) { super(and,imm); }
diff --git a/src/main/java/com/seaofnodes/simple/node/cpus/riscv/AndRISC.java b/src/main/java/com/seaofnodes/simple/node/cpus/riscv/AndRISC.java
index 93ef95c0..1845985e 100644
--- a/src/main/java/com/seaofnodes/simple/node/cpus/riscv/AndRISC.java
+++ b/src/main/java/com/seaofnodes/simple/node/cpus/riscv/AndRISC.java
@@ -1,8 +1,8 @@
package com.seaofnodes.simple.node.cpus.riscv;
-import com.seaofnodes.simple.SB;
import com.seaofnodes.simple.codegen.*;
import com.seaofnodes.simple.node.*;
+import com.seaofnodes.simple.util.SB;
public class AndRISC extends MachConcreteNode implements MachNode {
public AndRISC(Node and) { super(and); }
diff --git a/src/main/java/com/seaofnodes/simple/node/cpus/riscv/BranchRISC.java b/src/main/java/com/seaofnodes/simple/node/cpus/riscv/BranchRISC.java
index 44ff4e8b..b7284265 100644
--- a/src/main/java/com/seaofnodes/simple/node/cpus/riscv/BranchRISC.java
+++ b/src/main/java/com/seaofnodes/simple/node/cpus/riscv/BranchRISC.java
@@ -1,8 +1,9 @@
package com.seaofnodes.simple.node.cpus.riscv;
-import com.seaofnodes.simple.*;
import com.seaofnodes.simple.codegen.*;
import com.seaofnodes.simple.node.*;
+import com.seaofnodes.simple.util.SB;
+import com.seaofnodes.simple.util.Utils;
import java.util.BitSet;
// Conditional branch such as: BEQ
diff --git a/src/main/java/com/seaofnodes/simple/node/cpus/riscv/CallRISC.java b/src/main/java/com/seaofnodes/simple/node/cpus/riscv/CallRISC.java
index 89b2c865..bd5dabe5 100644
--- a/src/main/java/com/seaofnodes/simple/node/cpus/riscv/CallRISC.java
+++ b/src/main/java/com/seaofnodes/simple/node/cpus/riscv/CallRISC.java
@@ -1,9 +1,10 @@
package com.seaofnodes.simple.node.cpus.riscv;
-import com.seaofnodes.simple.*;
import com.seaofnodes.simple.codegen.*;
import com.seaofnodes.simple.node.*;
import com.seaofnodes.simple.type.TypeFunPtr;
+import com.seaofnodes.simple.util.SB;
+import com.seaofnodes.simple.util.Utils;
public class CallRISC extends CallNode implements MachNode, RIPRelSize {
final TypeFunPtr _tfp;
@@ -56,7 +57,6 @@ public class CallRISC extends CallNode implements MachNode, RIPRelSize {
sb.p(_name).p(" ");
for( int i=0; i<nargs(); i++ )
sb.p(code.reg(arg(i+2))).p(", ");
- sb.unchar(2).p(" ").p(code.reg(fptr()));
-
+ sb.unchar(2);
}
}
diff --git a/src/main/java/com/seaofnodes/simple/node/cpus/riscv/CallRRISC.java b/src/main/java/com/seaofnodes/simple/node/cpus/riscv/CallRRISC.java
index dcc53cbf..298789e8 100644
--- a/src/main/java/com/seaofnodes/simple/node/cpus/riscv/CallRRISC.java
+++ b/src/main/java/com/seaofnodes/simple/node/cpus/riscv/CallRRISC.java
@@ -1,8 +1,8 @@
package com.seaofnodes.simple.node.cpus.riscv;
-import com.seaofnodes.simple.*;
import com.seaofnodes.simple.codegen.*;
import com.seaofnodes.simple.node.*;
+import com.seaofnodes.simple.util.SB;
public class CallRRISC extends CallNode implements MachNode {
CallRRISC( CallNode call ) { super(call); }
@@ -25,7 +25,7 @@ public class CallRRISC extends CallNode implements MachNode {
@Override public void asm(CodeGen code, SB sb) {
sb.p(code.reg(fptr())).p(" ");
for( int i=0; i<nargs(); i++ )
- sb.p(code.reg(arg(i))).p(" ");
+ sb.p(code.reg(arg(i))).p(", ");
sb.unchar(2);
}
}
diff --git a/src/main/java/com/seaofnodes/simple/node/cpus/riscv/DivFRISC.java b/src/main/java/com/seaofnodes/simple/node/cpus/riscv/DivFRISC.java
index c67d7b3d..68ed6f6c 100644
--- a/src/main/java/com/seaofnodes/simple/node/cpus/riscv/DivFRISC.java
+++ b/src/main/java/com/seaofnodes/simple/node/cpus/riscv/DivFRISC.java
@@ -1,8 +1,8 @@
package com.seaofnodes.simple.node.cpus.riscv;
-import com.seaofnodes.simple.SB;
import com.seaofnodes.simple.codegen.*;
import com.seaofnodes.simple.node.*;
+import com.seaofnodes.simple.util.SB;
// fdiv.d
public class DivFRISC extends MachConcreteNode implements MachNode{
diff --git a/src/main/java/com/seaofnodes/simple/node/cpus/riscv/DivRISC.java b/src/main/java/com/seaofnodes/simple/node/cpus/riscv/DivRISC.java
index 8367ee68..515ffa47 100644
--- a/src/main/java/com/seaofnodes/simple/node/cpus/riscv/DivRISC.java
+++ b/src/main/java/com/seaofnodes/simple/node/cpus/riscv/DivRISC.java
@@ -1,6 +1,6 @@
package com.seaofnodes.simple.node.cpus.riscv;
-import com.seaofnodes.simple.SB;
+import com.seaofnodes.simple.util.SB;
import com.seaofnodes.simple.codegen.*;
import com.seaofnodes.simple.node.*;
diff --git a/src/main/java/com/seaofnodes/simple/node/cpus/riscv/FltRISC.java b/src/main/java/com/seaofnodes/simple/node/cpus/riscv/FltRISC.java
index be699280..81726200 100644
--- a/src/main/java/com/seaofnodes/simple/node/cpus/riscv/FltRISC.java
+++ b/src/main/java/com/seaofnodes/simple/node/cpus/riscv/FltRISC.java
@@ -1,11 +1,11 @@
package com.seaofnodes.simple.node.cpus.riscv;
-import com.seaofnodes.simple.SB;
-import com.seaofnodes.simple.Utils;
import com.seaofnodes.simple.codegen.*;
import com.seaofnodes.simple.node.ConstantNode;
import com.seaofnodes.simple.node.MachNode;
import com.seaofnodes.simple.type.TypeFloat;
+import com.seaofnodes.simple.util.SB;
+import com.seaofnodes.simple.util.Utils;
public class FltRISC extends ConstantNode implements MachNode, RIPRelSize {
FltRISC(ConstantNode con) { super(con); }
diff --git a/src/main/java/com/seaofnodes/simple/node/cpus/riscv/FunRISC.java b/src/main/java/com/seaofnodes/simple/node/cpus/riscv/FunRISC.java
index 84f0f4c7..6fce6244 100644
--- a/src/main/java/com/seaofnodes/simple/node/cpus/riscv/FunRISC.java
+++ b/src/main/java/com/seaofnodes/simple/node/cpus/riscv/FunRISC.java
@@ -1,10 +1,10 @@
package com.seaofnodes.simple.node.cpus.riscv;
-import com.seaofnodes.simple.SB;
-import com.seaofnodes.simple.Utils;
import com.seaofnodes.simple.codegen.*;
import com.seaofnodes.simple.node.FunNode;
import com.seaofnodes.simple.node.MachNode;
+import com.seaofnodes.simple.util.SB;
+import com.seaofnodes.simple.util.Utils;
public class FunRISC extends FunNode implements MachNode {
FunRISC(FunNode fun) {super(fun);}
diff --git a/src/main/java/com/seaofnodes/simple/node/cpus/riscv/I2F8RISC.java b/src/main/java/com/seaofnodes/simple/node/cpus/riscv/I2F8RISC.java
index 5519fe5b..db0547fe 100644
--- a/src/main/java/com/seaofnodes/simple/node/cpus/riscv/I2F8RISC.java
+++ b/src/main/java/com/seaofnodes/simple/node/cpus/riscv/I2F8RISC.java
@@ -1,8 +1,8 @@
package com.seaofnodes.simple.node.cpus.riscv;
-import com.seaofnodes.simple.*;
import com.seaofnodes.simple.codegen.*;
import com.seaofnodes.simple.node.*;
+import com.seaofnodes.simple.util.SB;
// fcvt.d.w
// Converts a 32-bit signed integer, in integer register rs1 into a double-precision floating-point number in floating-point register rd.
diff --git a/src/main/java/com/seaofnodes/simple/node/cpus/riscv/ImmRISC.java b/src/main/java/com/seaofnodes/simple/node/cpus/riscv/ImmRISC.java
index 9e7f456a..f2beb25c 100644
--- a/src/main/java/com/seaofnodes/simple/node/cpus/riscv/ImmRISC.java
+++ b/src/main/java/com/seaofnodes/simple/node/cpus/riscv/ImmRISC.java
@@ -1,9 +1,9 @@
package com.seaofnodes.simple.node.cpus.riscv;
-import com.seaofnodes.simple.*;
import com.seaofnodes.simple.codegen.*;
import com.seaofnodes.simple.node.*;
import com.seaofnodes.simple.type.TypeInteger;
+import com.seaofnodes.simple.util.SB;
import java.util.BitSet;
abstract public class ImmRISC extends MachConcreteNode implements MachNode {
diff --git a/src/main/java/com/seaofnodes/simple/node/cpus/riscv/Int8RISC.java b/src/main/java/com/seaofnodes/simple/node/cpus/riscv/Int8RISC.java
index f9b7daee..edd1850f 100644
--- a/src/main/java/com/seaofnodes/simple/node/cpus/riscv/Int8RISC.java
+++ b/src/main/java/com/seaofnodes/simple/node/cpus/riscv/Int8RISC.java
@@ -1,10 +1,9 @@
package com.seaofnodes.simple.node.cpus.riscv;
-import com.seaofnodes.simple.node.ConstantNode;
-
-import com.seaofnodes.simple.*;
import com.seaofnodes.simple.codegen.*;
+import com.seaofnodes.simple.node.ConstantNode;
import com.seaofnodes.simple.node.MachNode;
+import com.seaofnodes.simple.util.SB;
// Special instruction for loading 8 byte constants from the constant pool.
diff --git a/src/main/java/com/seaofnodes/simple/node/cpus/riscv/IntRISC.java b/src/main/java/com/seaofnodes/simple/node/cpus/riscv/IntRISC.java
index 70d5c18f..f8af913a 100644
--- a/src/main/java/com/seaofnodes/simple/node/cpus/riscv/IntRISC.java
+++ b/src/main/java/com/seaofnodes/simple/node/cpus/riscv/IntRISC.java
@@ -1,11 +1,11 @@
package com.seaofnodes.simple.node.cpus.riscv;
-import com.seaofnodes.simple.*;
import com.seaofnodes.simple.codegen.*;
import com.seaofnodes.simple.node.ConstantNode;
import com.seaofnodes.simple.node.MachNode;
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeInteger;
+import com.seaofnodes.simple.util.SB;
// 12-bit integer constant. Larger constants are made up in the instruction
// selection by adding with a LUI.
diff --git a/src/main/java/com/seaofnodes/simple/node/cpus/riscv/LUI.java b/src/main/java/com/seaofnodes/simple/node/cpus/riscv/LUI.java
index b65afc79..7333f2b7 100644
--- a/src/main/java/com/seaofnodes/simple/node/cpus/riscv/LUI.java
+++ b/src/main/java/com/seaofnodes/simple/node/cpus/riscv/LUI.java
@@ -1,10 +1,10 @@
package com.seaofnodes.simple.node.cpus.riscv;
-import com.seaofnodes.simple.*;
import com.seaofnodes.simple.codegen.*;
import com.seaofnodes.simple.node.ConstantNode;
import com.seaofnodes.simple.node.MachNode;
import com.seaofnodes.simple.type.TypeInteger;
+import com.seaofnodes.simple.util.SB;
// Load upper 20bits.
public class LUI extends ConstantNode implements MachNode {
diff --git a/src/main/java/com/seaofnodes/simple/node/cpus/riscv/LoadRISC.java b/src/main/java/com/seaofnodes/simple/node/cpus/riscv/LoadRISC.java
index 7b0e9138..7e08a01d 100644
--- a/src/main/java/com/seaofnodes/simple/node/cpus/riscv/LoadRISC.java
+++ b/src/main/java/com/seaofnodes/simple/node/cpus/riscv/LoadRISC.java
@@ -1,8 +1,8 @@
package com.seaofnodes.simple.node.cpus.riscv;
-import com.seaofnodes.simple.*;
import com.seaofnodes.simple.codegen.*;
import com.seaofnodes.simple.node.*;
+import com.seaofnodes.simple.util.SB;
// Load memory addressing on RISC
// Support imm, reg(direct), or reg+off(indirect) addressing
diff --git a/src/main/java/com/seaofnodes/simple/node/cpus/riscv/MemOpRISC.java b/src/main/java/com/seaofnodes/simple/node/cpus/riscv/MemOpRISC.java
index 8b84a2b9..93c90052 100644
--- a/src/main/java/com/seaofnodes/simple/node/cpus/riscv/MemOpRISC.java
+++ b/src/main/java/com/seaofnodes/simple/node/cpus/riscv/MemOpRISC.java
@@ -1,7 +1,7 @@
package com.seaofnodes.simple.node.cpus.riscv;
-import com.seaofnodes.simple.SB;
-import com.seaofnodes.simple.Utils;
+import com.seaofnodes.simple.util.SB;
+import com.seaofnodes.simple.util.Utils;
import com.seaofnodes.simple.codegen.*;
import com.seaofnodes.simple.node.*;
import com.seaofnodes.simple.type.*;
diff --git a/src/main/java/com/seaofnodes/simple/node/cpus/riscv/MulFRISC.java b/src/main/java/com/seaofnodes/simple/node/cpus/riscv/MulFRISC.java
index c9917b4f..5cc40079 100644
--- a/src/main/java/com/seaofnodes/simple/node/cpus/riscv/MulFRISC.java
+++ b/src/main/java/com/seaofnodes/simple/node/cpus/riscv/MulFRISC.java
@@ -1,8 +1,8 @@
package com.seaofnodes.simple.node.cpus.riscv;
-import com.seaofnodes.simple.SB;
import com.seaofnodes.simple.codegen.*;
import com.seaofnodes.simple.node.*;
+import com.seaofnodes.simple.util.SB;
// fmul.d
public class MulFRISC extends MachConcreteNode implements MachNode {
diff --git a/src/main/java/com/seaofnodes/simple/node/cpus/riscv/MulRISC.java b/src/main/java/com/seaofnodes/simple/node/cpus/riscv/MulRISC.java
index a7961627..9cb9ace7 100644
--- a/src/main/java/com/seaofnodes/simple/node/cpus/riscv/MulRISC.java
+++ b/src/main/java/com/seaofnodes/simple/node/cpus/riscv/MulRISC.java
@@ -1,8 +1,8 @@
package com.seaofnodes.simple.node.cpus.riscv;
-import com.seaofnodes.simple.SB;
import com.seaofnodes.simple.codegen.*;
import com.seaofnodes.simple.node.*;
+import com.seaofnodes.simple.util.SB;
// mulh signed multiply instruction(no-imm form)
public class MulRISC extends MachConcreteNode implements MachNode{
diff --git a/src/main/java/com/seaofnodes/simple/node/cpus/riscv/NegRISC.java b/src/main/java/com/seaofnodes/simple/node/cpus/riscv/NegRISC.java
index 77f4a497..d8183d09 100644
--- a/src/main/java/com/seaofnodes/simple/node/cpus/riscv/NegRISC.java
+++ b/src/main/java/com/seaofnodes/simple/node/cpus/riscv/NegRISC.java
@@ -1,8 +1,8 @@
package com.seaofnodes.simple.node.cpus.riscv;
-import com.seaofnodes.simple.SB;
import com.seaofnodes.simple.codegen.*;
import com.seaofnodes.simple.node.*;
+import com.seaofnodes.simple.util.SB;
public class NegRISC extends MachConcreteNode implements MachNode {
public NegRISC( Node neg ) { super(neg); }
diff --git a/src/main/java/com/seaofnodes/simple/node/cpus/riscv/NewRISC.java b/src/main/java/com/seaofnodes/simple/node/cpus/riscv/NewRISC.java
index e395a811..6c03bda6 100644
--- a/src/main/java/com/seaofnodes/simple/node/cpus/riscv/NewRISC.java
+++ b/src/main/java/com/seaofnodes/simple/node/cpus/riscv/NewRISC.java
@@ -1,9 +1,10 @@
package com.seaofnodes.simple.node.cpus.riscv;
-import com.seaofnodes.simple.*;
import com.seaofnodes.simple.codegen.*;
import com.seaofnodes.simple.node.*;
import com.seaofnodes.simple.print.ASMPrinter;
+import com.seaofnodes.simple.util.SB;
+import com.seaofnodes.simple.util.Utils;
public class NewRISC extends NewNode implements MachNode, RIPRelSize {
// A pre-zeroed chunk of memory.
diff --git a/src/main/java/com/seaofnodes/simple/node/cpus/riscv/NotRISC.java b/src/main/java/com/seaofnodes/simple/node/cpus/riscv/NotRISC.java
index 9cbd5025..1369ee76 100644
--- a/src/main/java/com/seaofnodes/simple/node/cpus/riscv/NotRISC.java
+++ b/src/main/java/com/seaofnodes/simple/node/cpus/riscv/NotRISC.java
@@ -1,10 +1,10 @@
package com.seaofnodes.simple.node.cpus.riscv;
-import com.seaofnodes.simple.SB;
import com.seaofnodes.simple.codegen.*;
import com.seaofnodes.simple.node.MachConcreteNode;
import com.seaofnodes.simple.node.MachNode;
import com.seaofnodes.simple.node.NotNode;
+import com.seaofnodes.simple.util.SB;
public class NotRISC extends MachConcreteNode implements MachNode {
public NotRISC(NotNode not) { super(not); }
diff --git a/src/main/java/com/seaofnodes/simple/node/cpus/riscv/OrIRISC.java b/src/main/java/com/seaofnodes/simple/node/cpus/riscv/OrIRISC.java
index f6a888d9..963b9d50 100644
--- a/src/main/java/com/seaofnodes/simple/node/cpus/riscv/OrIRISC.java
+++ b/src/main/java/com/seaofnodes/simple/node/cpus/riscv/OrIRISC.java
@@ -1,7 +1,7 @@
package com.seaofnodes.simple.node.cpus.riscv;
-import com.seaofnodes.simple.Utils;
import com.seaofnodes.simple.node.Node;
+import com.seaofnodes.simple.util.Utils;
public class OrIRISC extends ImmRISC {
public OrIRISC( Node and, int imm) { super(and,imm); }
diff --git a/src/main/java/com/seaofnodes/simple/node/cpus/riscv/OrRISC.java b/src/main/java/com/seaofnodes/simple/node/cpus/riscv/OrRISC.java
index 103d4c7d..a310a1f4 100644
--- a/src/main/java/com/seaofnodes/simple/node/cpus/riscv/OrRISC.java
+++ b/src/main/java/com/seaofnodes/simple/node/cpus/riscv/OrRISC.java
@@ -1,8 +1,8 @@
package com.seaofnodes.simple.node.cpus.riscv;
-import com.seaofnodes.simple.SB;
import com.seaofnodes.simple.codegen.*;
import com.seaofnodes.simple.node.*;
+import com.seaofnodes.simple.util.SB;
public class OrRISC extends MachConcreteNode implements MachNode {
public OrRISC(Node or) { super(or); }
diff --git a/src/main/java/com/seaofnodes/simple/node/cpus/riscv/RetRISC.java b/src/main/java/com/seaofnodes/simple/node/cpus/riscv/RetRISC.java
index 8a8186cd..7e4631d3 100644
--- a/src/main/java/com/seaofnodes/simple/node/cpus/riscv/RetRISC.java
+++ b/src/main/java/com/seaofnodes/simple/node/cpus/riscv/RetRISC.java
@@ -1,12 +1,12 @@
package com.seaofnodes.simple.node.cpus.riscv;
-import com.seaofnodes.simple.*;
import com.seaofnodes.simple.codegen.CodeGen;
import com.seaofnodes.simple.codegen.Encoding;
import com.seaofnodes.simple.codegen.RegMask;
import com.seaofnodes.simple.node.FunNode;
-import com.seaofnodes.simple.node.ReturnNode;
import com.seaofnodes.simple.node.MachNode;
+import com.seaofnodes.simple.node.ReturnNode;
+import com.seaofnodes.simple.util.Utils;
public class RetRISC extends ReturnNode implements MachNode {
public RetRISC(ReturnNode ret, FunNode fun) { super(ret, fun); fun.setRet(this); }
diff --git a/src/main/java/com/seaofnodes/simple/node/cpus/riscv/SetFRISC.java b/src/main/java/com/seaofnodes/simple/node/cpus/riscv/SetFRISC.java
index 9ee19e42..3424cd01 100644
--- a/src/main/java/com/seaofnodes/simple/node/cpus/riscv/SetFRISC.java
+++ b/src/main/java/com/seaofnodes/simple/node/cpus/riscv/SetFRISC.java
@@ -1,10 +1,10 @@
package com.seaofnodes.simple.node.cpus.riscv;
-import com.seaofnodes.simple.SB;
import com.seaofnodes.simple.codegen.*;
import com.seaofnodes.simple.node.BoolNode;
import com.seaofnodes.simple.node.MachConcreteNode;
import com.seaofnodes.simple.node.MachNode;
+import com.seaofnodes.simple.util.SB;
// corresponds to feq.d = equal
// fle.d = less than or equal
diff --git a/src/main/java/com/seaofnodes/simple/node/cpus/riscv/SetIRISC.java b/src/main/java/com/seaofnodes/simple/node/cpus/riscv/SetIRISC.java
index f270bf12..690e2102 100644
--- a/src/main/java/com/seaofnodes/simple/node/cpus/riscv/SetIRISC.java
+++ b/src/main/java/com/seaofnodes/simple/node/cpus/riscv/SetIRISC.java
@@ -1,6 +1,6 @@
package com.seaofnodes.simple.node.cpus.riscv;
-import com.seaofnodes.simple.Utils;
+import com.seaofnodes.simple.util.Utils;
import com.seaofnodes.simple.node.Node;
// corresponds to slti,sltiu
diff --git a/src/main/java/com/seaofnodes/simple/node/cpus/riscv/SetRISC.java b/src/main/java/com/seaofnodes/simple/node/cpus/riscv/SetRISC.java
index 8d4a2f71..848cc59f 100644
--- a/src/main/java/com/seaofnodes/simple/node/cpus/riscv/SetRISC.java
+++ b/src/main/java/com/seaofnodes/simple/node/cpus/riscv/SetRISC.java
@@ -1,8 +1,8 @@
package com.seaofnodes.simple.node.cpus.riscv;
-import com.seaofnodes.simple.SB;
import com.seaofnodes.simple.codegen.*;
import com.seaofnodes.simple.node.*;
+import com.seaofnodes.simple.util.SB;
// corresponds to slt sltu
public class SetRISC extends MachConcreteNode implements MachNode {
diff --git a/src/main/java/com/seaofnodes/simple/node/cpus/riscv/SllIRISC.java b/src/main/java/com/seaofnodes/simple/node/cpus/riscv/SllIRISC.java
index 4edecc04..12c0ddec 100644
--- a/src/main/java/com/seaofnodes/simple/node/cpus/riscv/SllIRISC.java
+++ b/src/main/java/com/seaofnodes/simple/node/cpus/riscv/SllIRISC.java
@@ -1,7 +1,7 @@
package com.seaofnodes.simple.node.cpus.riscv;
-import com.seaofnodes.simple.Utils;
import com.seaofnodes.simple.node.Node;
+import com.seaofnodes.simple.util.Utils;
public class SllIRISC extends ImmRISC {
public SllIRISC( Node and, int imm) { super(and,imm); }
diff --git a/src/main/java/com/seaofnodes/simple/node/cpus/riscv/SllRISC.java b/src/main/java/com/seaofnodes/simple/node/cpus/riscv/SllRISC.java
index 87e6693e..5a4d4cc6 100644
--- a/src/main/java/com/seaofnodes/simple/node/cpus/riscv/SllRISC.java
+++ b/src/main/java/com/seaofnodes/simple/node/cpus/riscv/SllRISC.java
@@ -1,8 +1,8 @@
package com.seaofnodes.simple.node.cpus.riscv;
-import com.seaofnodes.simple.SB;
import com.seaofnodes.simple.codegen.*;
import com.seaofnodes.simple.node.*;
+import com.seaofnodes.simple.util.SB;
// Shift left logical
public class SllRISC extends MachConcreteNode implements MachNode {
diff --git a/src/main/java/com/seaofnodes/simple/node/cpus/riscv/SplitRISC.java b/src/main/java/com/seaofnodes/simple/node/cpus/riscv/SplitRISC.java
index 569fa2e0..6082cbbf 100644
--- a/src/main/java/com/seaofnodes/simple/node/cpus/riscv/SplitRISC.java
+++ b/src/main/java/com/seaofnodes/simple/node/cpus/riscv/SplitRISC.java
@@ -1,11 +1,11 @@
package com.seaofnodes.simple.node.cpus.riscv;
-import com.seaofnodes.simple.SB;
-import com.seaofnodes.simple.Utils;
import com.seaofnodes.simple.codegen.*;
import com.seaofnodes.simple.node.FunNode;
import com.seaofnodes.simple.node.Node;
import com.seaofnodes.simple.node.SplitNode;
+import com.seaofnodes.simple.util.SB;
+import com.seaofnodes.simple.util.Utils;
public class SplitRISC extends SplitNode {
SplitRISC( String kind, byte round ) { super(kind,round, new Node[2]); }
diff --git a/src/main/java/com/seaofnodes/simple/node/cpus/riscv/SraIRISC.java b/src/main/java/com/seaofnodes/simple/node/cpus/riscv/SraIRISC.java
index 1533003c..fcfa0774 100644
--- a/src/main/java/com/seaofnodes/simple/node/cpus/riscv/SraIRISC.java
+++ b/src/main/java/com/seaofnodes/simple/node/cpus/riscv/SraIRISC.java
@@ -1,7 +1,7 @@
package com.seaofnodes.simple.node.cpus.riscv;
-import com.seaofnodes.simple.Utils;
import com.seaofnodes.simple.node.Node;
+import com.seaofnodes.simple.util.Utils;
public class SraIRISC extends ImmRISC {
public SraIRISC( Node and, int imm) {
diff --git a/src/main/java/com/seaofnodes/simple/node/cpus/riscv/SraRISC.java b/src/main/java/com/seaofnodes/simple/node/cpus/riscv/SraRISC.java
index 1e930e72..e2e34415 100644
--- a/src/main/java/com/seaofnodes/simple/node/cpus/riscv/SraRISC.java
+++ b/src/main/java/com/seaofnodes/simple/node/cpus/riscv/SraRISC.java
@@ -1,8 +1,8 @@
package com.seaofnodes.simple.node.cpus.riscv;
-import com.seaofnodes.simple.SB;
import com.seaofnodes.simple.codegen.*;
import com.seaofnodes.simple.node.*;
+import com.seaofnodes.simple.util.SB;
// Right Shift Arithmetic
public class SraRISC extends MachConcreteNode implements MachNode {
diff --git a/src/main/java/com/seaofnodes/simple/node/cpus/riscv/SrlIRISC.java b/src/main/java/com/seaofnodes/simple/node/cpus/riscv/SrlIRISC.java
index ed697678..2f73e139 100644
--- a/src/main/java/com/seaofnodes/simple/node/cpus/riscv/SrlIRISC.java
+++ b/src/main/java/com/seaofnodes/simple/node/cpus/riscv/SrlIRISC.java
@@ -1,7 +1,7 @@
package com.seaofnodes.simple.node.cpus.riscv;
-import com.seaofnodes.simple.Utils;
import com.seaofnodes.simple.node.Node;
+import com.seaofnodes.simple.util.Utils;
public class SrlIRISC extends ImmRISC {
public SrlIRISC( Node and, int imm, boolean pop) { super(and,imm,pop); }
diff --git a/src/main/java/com/seaofnodes/simple/node/cpus/riscv/SrlRISC.java b/src/main/java/com/seaofnodes/simple/node/cpus/riscv/SrlRISC.java
index 47712585..1eccc1c8 100644
--- a/src/main/java/com/seaofnodes/simple/node/cpus/riscv/SrlRISC.java
+++ b/src/main/java/com/seaofnodes/simple/node/cpus/riscv/SrlRISC.java
@@ -1,8 +1,8 @@
package com.seaofnodes.simple.node.cpus.riscv;
-import com.seaofnodes.simple.SB;
import com.seaofnodes.simple.codegen.*;
import com.seaofnodes.simple.node.*;
+import com.seaofnodes.simple.util.SB;
// Right Shift Logical
public class SrlRISC extends MachConcreteNode implements MachNode {
diff --git a/src/main/java/com/seaofnodes/simple/node/cpus/riscv/StoreRISC.java b/src/main/java/com/seaofnodes/simple/node/cpus/riscv/StoreRISC.java
index 7305c4d9..d06c0c35 100644
--- a/src/main/java/com/seaofnodes/simple/node/cpus/riscv/StoreRISC.java
+++ b/src/main/java/com/seaofnodes/simple/node/cpus/riscv/StoreRISC.java
@@ -1,10 +1,10 @@
package com.seaofnodes.simple.node.cpus.riscv;
-import com.seaofnodes.simple.SB;
-import com.seaofnodes.simple.Utils;
import com.seaofnodes.simple.codegen.*;
import com.seaofnodes.simple.codegen.RegMask;
import com.seaofnodes.simple.node.*;
+import com.seaofnodes.simple.util.SB;
+import com.seaofnodes.simple.util.Utils;
// Store memory addressing on ARM
// Support imm, reg(direct), or reg+off(indirect) addressing
diff --git a/src/main/java/com/seaofnodes/simple/node/cpus/riscv/SubFRISC.java b/src/main/java/com/seaofnodes/simple/node/cpus/riscv/SubFRISC.java
index 1e1b43c7..da3e92f4 100644
--- a/src/main/java/com/seaofnodes/simple/node/cpus/riscv/SubFRISC.java
+++ b/src/main/java/com/seaofnodes/simple/node/cpus/riscv/SubFRISC.java
@@ -1,8 +1,8 @@
package com.seaofnodes.simple.node.cpus.riscv;
-import com.seaofnodes.simple.SB;
import com.seaofnodes.simple.codegen.*;
import com.seaofnodes.simple.node.*;
+import com.seaofnodes.simple.util.SB;
// fsub.d
public class SubFRISC extends MachConcreteNode implements MachNode {
diff --git a/src/main/java/com/seaofnodes/simple/node/cpus/riscv/SubRISC.java b/src/main/java/com/seaofnodes/simple/node/cpus/riscv/SubRISC.java
index 7ab4f904..2adfce23 100644
--- a/src/main/java/com/seaofnodes/simple/node/cpus/riscv/SubRISC.java
+++ b/src/main/java/com/seaofnodes/simple/node/cpus/riscv/SubRISC.java
@@ -1,8 +1,8 @@
package com.seaofnodes.simple.node.cpus.riscv;
-import com.seaofnodes.simple.*;
import com.seaofnodes.simple.codegen.*;
import com.seaofnodes.simple.node.*;
+import com.seaofnodes.simple.util.SB;
public class SubRISC extends MachConcreteNode implements MachNode {
public SubRISC( Node sub ) { super(sub); }
diff --git a/src/main/java/com/seaofnodes/simple/node/cpus/riscv/TFPRISC.java b/src/main/java/com/seaofnodes/simple/node/cpus/riscv/TFPRISC.java
index 15be82bc..7e057507 100644
--- a/src/main/java/com/seaofnodes/simple/node/cpus/riscv/TFPRISC.java
+++ b/src/main/java/com/seaofnodes/simple/node/cpus/riscv/TFPRISC.java
@@ -1,11 +1,12 @@
package com.seaofnodes.simple.node.cpus.riscv;
-import com.seaofnodes.simple.*;
import com.seaofnodes.simple.codegen.*;
import com.seaofnodes.simple.node.ConstantNode;
import com.seaofnodes.simple.node.MachNode;
import com.seaofnodes.simple.node.Node;
import com.seaofnodes.simple.type.TypeFunPtr;
+import com.seaofnodes.simple.util.SB;
+import com.seaofnodes.simple.util.Utils;
public class TFPRISC extends ConstantNode implements MachNode, RIPRelSize {
TFPRISC(ConstantNode con) { super(con); }
diff --git a/src/main/java/com/seaofnodes/simple/node/cpus/riscv/TMPRISC.java b/src/main/java/com/seaofnodes/simple/node/cpus/riscv/TMPRISC.java
index 860e5eaf..44e73d1d 100644
--- a/src/main/java/com/seaofnodes/simple/node/cpus/riscv/TMPRISC.java
+++ b/src/main/java/com/seaofnodes/simple/node/cpus/riscv/TMPRISC.java
@@ -1,11 +1,11 @@
package com.seaofnodes.simple.node.cpus.riscv;
-import com.seaofnodes.simple.*;
import com.seaofnodes.simple.codegen.*;
import com.seaofnodes.simple.node.ConstantNode;
import com.seaofnodes.simple.node.MachNode;
import com.seaofnodes.simple.node.Node;
import com.seaofnodes.simple.type.TypeMemPtr;
+import com.seaofnodes.simple.util.SB;
public class TMPRISC extends ConstantNode implements MachNode, RIPRelSize {
TMPRISC(ConstantNode con) { super(con); }
diff --git a/src/main/java/com/seaofnodes/simple/node/cpus/riscv/UJmpRISC.java b/src/main/java/com/seaofnodes/simple/node/cpus/riscv/UJmpRISC.java
index 6473d81c..c4d5d8af 100644
--- a/src/main/java/com/seaofnodes/simple/node/cpus/riscv/UJmpRISC.java
+++ b/src/main/java/com/seaofnodes/simple/node/cpus/riscv/UJmpRISC.java
@@ -1,9 +1,10 @@
package com.seaofnodes.simple.node.cpus.riscv;
-import com.seaofnodes.simple.*;
import com.seaofnodes.simple.codegen.*;
import com.seaofnodes.simple.node.*;
import com.seaofnodes.simple.type.Type;
+import com.seaofnodes.simple.util.SB;
+import com.seaofnodes.simple.util.Utils;
import java.util.BitSet;
// unconditional jump
diff --git a/src/main/java/com/seaofnodes/simple/node/cpus/riscv/XorIRISC.java b/src/main/java/com/seaofnodes/simple/node/cpus/riscv/XorIRISC.java
index 27098033..19ea6bc7 100644
--- a/src/main/java/com/seaofnodes/simple/node/cpus/riscv/XorIRISC.java
+++ b/src/main/java/com/seaofnodes/simple/node/cpus/riscv/XorIRISC.java
@@ -1,7 +1,7 @@
package com.seaofnodes.simple.node.cpus.riscv;
-import com.seaofnodes.simple.Utils;
import com.seaofnodes.simple.node.Node;
+import com.seaofnodes.simple.util.Utils;
public class XorIRISC extends ImmRISC {
public XorIRISC( Node and, int imm) { super(and,imm); }
diff --git a/src/main/java/com/seaofnodes/simple/node/cpus/riscv/XorRISC.java b/src/main/java/com/seaofnodes/simple/node/cpus/riscv/XorRISC.java
index 725d2b78..413a7c3b 100644
--- a/src/main/java/com/seaofnodes/simple/node/cpus/riscv/XorRISC.java
+++ b/src/main/java/com/seaofnodes/simple/node/cpus/riscv/XorRISC.java
@@ -1,8 +1,8 @@
package com.seaofnodes.simple.node.cpus.riscv;
-import com.seaofnodes.simple.SB;
import com.seaofnodes.simple.codegen.*;
import com.seaofnodes.simple.node.*;
+import com.seaofnodes.simple.util.SB;
public class XorRISC extends MachConcreteNode implements MachNode {
public XorRISC(Node or) { super(or); }
diff --git a/src/main/java/com/seaofnodes/simple/node/cpus/riscv/riscv.java b/src/main/java/com/seaofnodes/simple/node/cpus/riscv/riscv.java
index 9c5bfa10..7a6361bc 100644
--- a/src/main/java/com/seaofnodes/simple/node/cpus/riscv/riscv.java
+++ b/src/main/java/com/seaofnodes/simple/node/cpus/riscv/riscv.java
@@ -1,9 +1,9 @@
package com.seaofnodes.simple.node.cpus.riscv;
-import com.seaofnodes.simple.Utils;
import com.seaofnodes.simple.codegen.*;
import com.seaofnodes.simple.node.*;
import com.seaofnodes.simple.type.*;
+import com.seaofnodes.simple.util.Utils;
public class riscv extends Machine {
diff --git a/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/AddFMemX86.java b/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/AddFMemX86.java
index d54c7c31..2513de37 100644
--- a/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/AddFMemX86.java
+++ b/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/AddFMemX86.java
@@ -1,9 +1,9 @@
package com.seaofnodes.simple.node.cpus.x86_64_v2;
-import com.seaofnodes.simple.SB;
-import com.seaofnodes.simple.Utils;
import com.seaofnodes.simple.codegen.*;
import com.seaofnodes.simple.node.*;
+import com.seaofnodes.simple.util.SB;
+import com.seaofnodes.simple.util.Utils;
public class AddFMemX86 extends MemOpX86 {
AddFMemX86( AddFNode add, LoadNode ld , Node base, Node idx, int off, int scale, Node val ) {
diff --git a/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/AddFX86.java b/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/AddFX86.java
index a4166bc7..02e0c7ea 100644
--- a/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/AddFX86.java
+++ b/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/AddFX86.java
@@ -1,8 +1,8 @@
package com.seaofnodes.simple.node.cpus.x86_64_v2;
-import com.seaofnodes.simple.*;
import com.seaofnodes.simple.codegen.*;
import com.seaofnodes.simple.node.*;
+import com.seaofnodes.simple.util.SB;
public class AddFX86 extends MachConcreteNode implements MachNode {
AddFX86( Node addf ) { super(addf); }
diff --git a/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/AddIX86.java b/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/AddIX86.java
index 050451f1..0ba390c6 100644
--- a/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/AddIX86.java
+++ b/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/AddIX86.java
@@ -1,9 +1,9 @@
package com.seaofnodes.simple.node.cpus.x86_64_v2;
-import com.seaofnodes.simple.SB;
-import com.seaofnodes.simple.Utils;
import com.seaofnodes.simple.codegen.Encoding;
import com.seaofnodes.simple.node.Node;
+import com.seaofnodes.simple.util.SB;
+import com.seaofnodes.simple.util.Utils;
public class AddIX86 extends ImmX86 {
AddIX86( Node add, int imm ) { super(add,imm); }
diff --git a/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/AddMemX86.java b/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/AddMemX86.java
index f97a7cb8..3ee721e3 100644
--- a/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/AddMemX86.java
+++ b/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/AddMemX86.java
@@ -1,8 +1,8 @@
package com.seaofnodes.simple.node.cpus.x86_64_v2;
-import com.seaofnodes.simple.SB;
import com.seaofnodes.simple.codegen.*;
import com.seaofnodes.simple.node.*;
+import com.seaofnodes.simple.util.SB;
public class AddMemX86 extends MemOpX86 {
AddMemX86( AddNode add, LoadNode ld , Node base, Node idx, int off, int scale, int imm, Node val ) {
diff --git a/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/CallRX86.java b/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/CallRX86.java
index 1a74f817..460f568b 100644
--- a/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/CallRX86.java
+++ b/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/CallRX86.java
@@ -1,9 +1,9 @@
package com.seaofnodes.simple.node.cpus.x86_64_v2;
-import com.seaofnodes.simple.SB;
import com.seaofnodes.simple.codegen.*;
import com.seaofnodes.simple.node.CallNode;
import com.seaofnodes.simple.node.MachNode;
+import com.seaofnodes.simple.util.SB;
public class CallRX86 extends CallNode implements MachNode {
CallRX86( CallNode call ) { super(call); }
diff --git a/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/CallX86.java b/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/CallX86.java
index 4696c859..d74e3833 100644
--- a/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/CallX86.java
+++ b/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/CallX86.java
@@ -1,9 +1,9 @@
package com.seaofnodes.simple.node.cpus.x86_64_v2;
-import com.seaofnodes.simple.SB;
import com.seaofnodes.simple.codegen.*;
import com.seaofnodes.simple.node.*;
import com.seaofnodes.simple.type.TypeFunPtr;
+import com.seaofnodes.simple.util.SB;
public class CallX86 extends CallNode implements MachNode, RIPRelSize {
final TypeFunPtr _tfp;
@@ -42,7 +42,7 @@ public class CallX86 extends CallNode implements MachNode, RIPRelSize {
@Override public void asm(CodeGen code, SB sb) {
sb.p(_name).p(" ");
for( int i=0; i<nargs(); i++ )
- sb.p(code.reg(in(i+2))).p(" ");
+ sb.p(code.reg(in(i+2))).p(", ");
sb.unchar(2);
}
}
diff --git a/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/CmpFX86.java b/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/CmpFX86.java
index 35b92170..5b97ef63 100644
--- a/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/CmpFX86.java
+++ b/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/CmpFX86.java
@@ -1,8 +1,8 @@
package com.seaofnodes.simple.node.cpus.x86_64_v2;
-import com.seaofnodes.simple.*;
import com.seaofnodes.simple.codegen.*;
import com.seaofnodes.simple.node.*;
+import com.seaofnodes.simple.util.SB;
public class CmpFX86 extends MachConcreteNode implements MachNode {
CmpFX86( Node cmp ) { super(cmp); }
diff --git a/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/CmpIX86.java b/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/CmpIX86.java
index 91b6d43c..8b8318eb 100644
--- a/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/CmpIX86.java
+++ b/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/CmpIX86.java
@@ -1,8 +1,8 @@
package com.seaofnodes.simple.node.cpus.x86_64_v2;
-import com.seaofnodes.simple.SB;
import com.seaofnodes.simple.codegen.*;
import com.seaofnodes.simple.node.*;
+import com.seaofnodes.simple.util.SB;
// Compare immediate. Sets flags.
public class CmpIX86 extends MachConcreteNode implements MachNode {
diff --git a/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/CmpMemX86.java b/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/CmpMemX86.java
index a1845363..11f900ed 100644
--- a/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/CmpMemX86.java
+++ b/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/CmpMemX86.java
@@ -1,10 +1,10 @@
package com.seaofnodes.simple.node.cpus.x86_64_v2;
-import com.seaofnodes.simple.SB;
import com.seaofnodes.simple.codegen.*;
import com.seaofnodes.simple.node.*;
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeFloat;
+import com.seaofnodes.simple.util.SB;
public class CmpMemX86 extends MemOpX86 {
final boolean _swap; // Op switched LHS, RHS
diff --git a/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/CmpX86.java b/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/CmpX86.java
index 3e4200c0..e7305cdf 100644
--- a/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/CmpX86.java
+++ b/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/CmpX86.java
@@ -1,8 +1,8 @@
package com.seaofnodes.simple.node.cpus.x86_64_v2;
-import com.seaofnodes.simple.*;
import com.seaofnodes.simple.codegen.*;
import com.seaofnodes.simple.node.*;
+import com.seaofnodes.simple.util.SB;
public class CmpX86 extends MachConcreteNode implements MachNode {
CmpX86( Node add ) { super(add); }
diff --git a/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/DivFX86.java b/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/DivFX86.java
index 9509a1f5..3427aea5 100644
--- a/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/DivFX86.java
+++ b/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/DivFX86.java
@@ -1,8 +1,8 @@
package com.seaofnodes.simple.node.cpus.x86_64_v2;
-import com.seaofnodes.simple.*;
import com.seaofnodes.simple.codegen.*;
import com.seaofnodes.simple.node.*;
+import com.seaofnodes.simple.util.SB;
public class DivFX86 extends MachConcreteNode implements MachNode {
DivFX86( Node divf) { super(divf); }
diff --git a/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/DivX86.java b/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/DivX86.java
index 06f001b0..b5904a7f 100644
--- a/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/DivX86.java
+++ b/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/DivX86.java
@@ -1,8 +1,8 @@
package com.seaofnodes.simple.node.cpus.x86_64_v2;
-import com.seaofnodes.simple.*;
import com.seaofnodes.simple.codegen.*;
import com.seaofnodes.simple.node.*;
+import com.seaofnodes.simple.util.SB;
public class DivX86 extends MachConcreteNode implements MachNode {
DivX86( Node div ) { super(div); }
diff --git a/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/FltX86.java b/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/FltX86.java
index e3b20003..9bcbac8f 100644
--- a/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/FltX86.java
+++ b/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/FltX86.java
@@ -1,8 +1,8 @@
package com.seaofnodes.simple.node.cpus.x86_64_v2;
-import com.seaofnodes.simple.SB;
import com.seaofnodes.simple.codegen.*;
import com.seaofnodes.simple.node.*;
+import com.seaofnodes.simple.util.SB;
public class FltX86 extends ConstantNode implements MachNode, RIPRelSize{
private byte _encSize;
diff --git a/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/FunX86.java b/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/FunX86.java
index 07418eb0..cbd5fdbf 100644
--- a/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/FunX86.java
+++ b/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/FunX86.java
@@ -1,10 +1,10 @@
package com.seaofnodes.simple.node.cpus.x86_64_v2;
-import com.seaofnodes.simple.SB;
import com.seaofnodes.simple.codegen.CodeGen;
import com.seaofnodes.simple.codegen.Encoding;
import com.seaofnodes.simple.node.FunNode;
import com.seaofnodes.simple.node.MachNode;
+import com.seaofnodes.simple.util.SB;
public class FunX86 extends FunNode implements MachNode {
FunX86( FunNode fun ) { super(fun); }
diff --git a/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/I2f8X86.java b/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/I2f8X86.java
index d3213ae4..9f3d7905 100644
--- a/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/I2f8X86.java
+++ b/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/I2f8X86.java
@@ -1,8 +1,8 @@
package com.seaofnodes.simple.node.cpus.x86_64_v2;
-import com.seaofnodes.simple.*;
import com.seaofnodes.simple.codegen.*;
import com.seaofnodes.simple.node.*;
+import com.seaofnodes.simple.util.SB;
public class I2f8X86 extends MachConcreteNode implements MachNode {
I2f8X86(Node i2f8 ) { super(i2f8); }
diff --git a/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/ImmX86.java b/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/ImmX86.java
index 95f617e7..5e406911 100644
--- a/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/ImmX86.java
+++ b/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/ImmX86.java
@@ -1,9 +1,9 @@
package com.seaofnodes.simple.node.cpus.x86_64_v2;
-import com.seaofnodes.simple.*;
import com.seaofnodes.simple.codegen.*;
import com.seaofnodes.simple.node.*;
import com.seaofnodes.simple.type.TypeInteger;
+import com.seaofnodes.simple.util.SB;
public abstract class ImmX86 extends MachConcreteNode implements MachNode {
final int _imm;
diff --git a/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/IntX86.java b/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/IntX86.java
index 6d9110f2..3f2f696c 100644
--- a/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/IntX86.java
+++ b/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/IntX86.java
@@ -1,10 +1,10 @@
package com.seaofnodes.simple.node.cpus.x86_64_v2;
-import com.seaofnodes.simple.*;
import com.seaofnodes.simple.codegen.*;
import com.seaofnodes.simple.node.*;
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeInteger;
+import com.seaofnodes.simple.util.SB;
// Integer constants
public class IntX86 extends ConstantNode implements MachNode {
diff --git a/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/JmpX86.java b/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/JmpX86.java
index d7acf8b8..de27aa5c 100644
--- a/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/JmpX86.java
+++ b/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/JmpX86.java
@@ -1,8 +1,9 @@
package com.seaofnodes.simple.node.cpus.x86_64_v2;
-import com.seaofnodes.simple.*;
import com.seaofnodes.simple.codegen.*;
import com.seaofnodes.simple.node.*;
+import com.seaofnodes.simple.util.SB;
+import com.seaofnodes.simple.util.Utils;
// Jump on flags, uses flags
public class JmpX86 extends IfNode implements MachNode, RIPRelSize {
diff --git a/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/LeaX86.java b/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/LeaX86.java
index dce8a49a..2cd6018f 100644
--- a/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/LeaX86.java
+++ b/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/LeaX86.java
@@ -1,8 +1,8 @@
package com.seaofnodes.simple.node.cpus.x86_64_v2;
-import com.seaofnodes.simple.*;
import com.seaofnodes.simple.codegen.*;
import com.seaofnodes.simple.node.*;
+import com.seaofnodes.simple.util.SB;
public class LeaX86 extends MachConcreteNode implements MachNode {
final int _scale;
diff --git a/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/LoadX86.java b/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/LoadX86.java
index 6e72a540..441cf693 100644
--- a/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/LoadX86.java
+++ b/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/LoadX86.java
@@ -1,14 +1,11 @@
package com.seaofnodes.simple.node.cpus.x86_64_v2;
-import com.seaofnodes.simple.SB;
-import com.seaofnodes.simple.Utils;
import com.seaofnodes.simple.codegen.*;
import com.seaofnodes.simple.node.LoadNode;
import com.seaofnodes.simple.node.Node;
-import com.seaofnodes.simple.type.Type;
-import com.seaofnodes.simple.type.TypeFloat;
-import com.seaofnodes.simple.type.TypeInteger;
-import com.seaofnodes.simple.type.TypeMemPtr;
+import com.seaofnodes.simple.type.*;
+import com.seaofnodes.simple.util.SB;
+import com.seaofnodes.simple.util.Utils;
public class LoadX86 extends MemOpX86 {
LoadX86( LoadNode ld, Node base, Node idx, int off, int scale ) {
diff --git a/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/MemAddX86.java b/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/MemAddX86.java
index f0d01b3d..bd56d022 100644
--- a/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/MemAddX86.java
+++ b/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/MemAddX86.java
@@ -1,8 +1,8 @@
package com.seaofnodes.simple.node.cpus.x86_64_v2;
-import com.seaofnodes.simple.SB;
import com.seaofnodes.simple.codegen.*;
import com.seaofnodes.simple.node.*;
+import com.seaofnodes.simple.util.SB;
public class MemAddX86 extends MemOpX86 {
MemAddX86( StoreNode st, Node base, Node idx, int off, int scale, int imm, Node val ) {
diff --git a/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/MemOpX86.java b/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/MemOpX86.java
index 97586d87..5f090717 100644
--- a/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/MemOpX86.java
+++ b/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/MemOpX86.java
@@ -1,10 +1,10 @@
package com.seaofnodes.simple.node.cpus.x86_64_v2;
-import com.seaofnodes.simple.*;
import com.seaofnodes.simple.codegen.*;
import com.seaofnodes.simple.node.*;
import com.seaofnodes.simple.type.*;
-
+import com.seaofnodes.simple.util.SB;
+import com.seaofnodes.simple.util.Utils;
import java.lang.StringBuilder;
import java.util.BitSet;
diff --git a/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/MulFX86.java b/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/MulFX86.java
index c1edb082..7932c893 100644
--- a/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/MulFX86.java
+++ b/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/MulFX86.java
@@ -1,8 +1,8 @@
package com.seaofnodes.simple.node.cpus.x86_64_v2;
-import com.seaofnodes.simple.*;
import com.seaofnodes.simple.codegen.*;
import com.seaofnodes.simple.node.*;
+import com.seaofnodes.simple.util.SB;
public class MulFX86 extends MachConcreteNode implements MachNode {
MulFX86( Node mulf) { super(mulf); }
diff --git a/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/MulIX86.java b/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/MulIX86.java
index 0dc16ab1..280b8185 100644
--- a/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/MulIX86.java
+++ b/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/MulIX86.java
@@ -1,8 +1,8 @@
package com.seaofnodes.simple.node.cpus.x86_64_v2;
-import com.seaofnodes.simple.SB;
-import com.seaofnodes.simple.node.*;
import com.seaofnodes.simple.codegen.*;
+import com.seaofnodes.simple.node.*;
+import com.seaofnodes.simple.util.SB;
public class MulIX86 extends MachConcreteNode implements MachNode {
final int _imm;
diff --git a/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/MulX86.java b/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/MulX86.java
index 3cd1f795..4d2a11ed 100644
--- a/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/MulX86.java
+++ b/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/MulX86.java
@@ -1,8 +1,8 @@
package com.seaofnodes.simple.node.cpus.x86_64_v2;
-import com.seaofnodes.simple.*;
import com.seaofnodes.simple.codegen.*;
import com.seaofnodes.simple.node.*;
+import com.seaofnodes.simple.util.SB;
public class MulX86 extends MachConcreteNode implements MachNode {
MulX86( Node mul ) { super(mul); }
diff --git a/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/NegX86.java b/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/NegX86.java
index b8b83cb0..0c2baced 100644
--- a/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/NegX86.java
+++ b/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/NegX86.java
@@ -1,8 +1,8 @@
package com.seaofnodes.simple.node.cpus.x86_64_v2;
-import com.seaofnodes.simple.SB;
import com.seaofnodes.simple.codegen.*;
import com.seaofnodes.simple.node.*;
+import com.seaofnodes.simple.util.SB;
public class NegX86 extends MachConcreteNode implements MachNode {
NegX86(MinusNode not) { super(not); }
@@ -10,6 +10,7 @@ public class NegX86 extends MachConcreteNode implements MachNode {
@Override public RegMask regmap(int i) { return x86_64_v2.RMASK; }
@Override public RegMask outregmap() { return x86_64_v2.RMASK; }
@Override public RegMask killmap() { return x86_64_v2.FLAGS_MASK; }
+ @Override public int twoAddress() { return 1; }
@Override public void encoding( Encoding enc ) {
short dst = enc.reg(this );
diff --git a/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/NewX86.java b/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/NewX86.java
index 0439adfd..fc896dce 100644
--- a/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/NewX86.java
+++ b/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/NewX86.java
@@ -1,9 +1,9 @@
package com.seaofnodes.simple.node.cpus.x86_64_v2;
-import com.seaofnodes.simple.*;
import com.seaofnodes.simple.codegen.*;
import com.seaofnodes.simple.node.*;
import com.seaofnodes.simple.type.TypeFunPtr;
+import com.seaofnodes.simple.util.SB;
public class NewX86 extends NewNode implements MachNode {
// A pre-zeroed chunk of memory.
diff --git a/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/NotX86.java b/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/NotX86.java
index b23249b8..d9056be9 100644
--- a/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/NotX86.java
+++ b/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/NotX86.java
@@ -1,8 +1,8 @@
package com.seaofnodes.simple.node.cpus.x86_64_v2;
-import com.seaofnodes.simple.SB;
import com.seaofnodes.simple.codegen.*;
import com.seaofnodes.simple.node.*;
+import com.seaofnodes.simple.util.SB;
public class NotX86 extends MachConcreteNode implements MachNode {
NotX86(NotNode not) { super(not); }
diff --git a/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/RegX86.java b/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/RegX86.java
index a4a6a814..5a475efe 100644
--- a/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/RegX86.java
+++ b/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/RegX86.java
@@ -1,8 +1,8 @@
package com.seaofnodes.simple.node.cpus.x86_64_v2;
-import com.seaofnodes.simple.*;
import com.seaofnodes.simple.codegen.*;
import com.seaofnodes.simple.node.*;
+import com.seaofnodes.simple.util.SB;
public abstract class RegX86 extends MachConcreteNode {
RegX86( Node add ) { super(add); }
diff --git a/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/SarIX86.java b/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/SarIX86.java
index 07256604..95e0c336 100644
--- a/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/SarIX86.java
+++ b/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/SarIX86.java
@@ -1,13 +1,12 @@
package com.seaofnodes.simple.node.cpus.x86_64_v2;
-import com.seaofnodes.simple.SB;
import com.seaofnodes.simple.codegen.CodeGen;
import com.seaofnodes.simple.codegen.Encoding;
import com.seaofnodes.simple.codegen.RegMask;
+import com.seaofnodes.simple.node.*;
import com.seaofnodes.simple.node.MachNode;
import com.seaofnodes.simple.node.Node;
-
-import com.seaofnodes.simple.node.*;
+import com.seaofnodes.simple.util.SB;
// Arithmetic Right Shift
public class SarIX86 extends MachConcreteNode implements MachNode {
diff --git a/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/SarX86.java b/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/SarX86.java
index b1be643c..4cc8b558 100644
--- a/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/SarX86.java
+++ b/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/SarX86.java
@@ -1,8 +1,8 @@
package com.seaofnodes.simple.node.cpus.x86_64_v2;
-import com.seaofnodes.simple.Utils;
import com.seaofnodes.simple.codegen.*;
import com.seaofnodes.simple.node.Node;
+import com.seaofnodes.simple.util.Utils;
public class SarX86 extends RegX86 {
SarX86( Node add ) { super(add); }
diff --git a/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/SetX86.java b/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/SetX86.java
index 775ea8eb..0eff2afe 100644
--- a/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/SetX86.java
+++ b/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/SetX86.java
@@ -1,8 +1,9 @@
package com.seaofnodes.simple.node.cpus.x86_64_v2;
-import com.seaofnodes.simple.*;
import com.seaofnodes.simple.codegen.*;
import com.seaofnodes.simple.node.*;
+import com.seaofnodes.simple.util.SB;
+import com.seaofnodes.simple.util.Utils;
// Corresponds to the x86 instruction "sete && setne".
// Use result of comparison without jump.
diff --git a/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/ShlIX86.java b/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/ShlIX86.java
index 0b75b456..f7b2f28a 100644
--- a/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/ShlIX86.java
+++ b/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/ShlIX86.java
@@ -1,10 +1,9 @@
package com.seaofnodes.simple.node.cpus.x86_64_v2;
-import com.seaofnodes.simple.node.Node;
-
-import com.seaofnodes.simple.*;
import com.seaofnodes.simple.codegen.*;
import com.seaofnodes.simple.node.*;
+import com.seaofnodes.simple.node.Node;
+import com.seaofnodes.simple.util.SB;
public class ShlIX86 extends MachConcreteNode implements MachNode {
final int _imm;
diff --git a/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/ShlX86.java b/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/ShlX86.java
index 9f358575..5fee72d9 100644
--- a/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/ShlX86.java
+++ b/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/ShlX86.java
@@ -1,8 +1,8 @@
package com.seaofnodes.simple.node.cpus.x86_64_v2;
-import com.seaofnodes.simple.Utils;
import com.seaofnodes.simple.codegen.*;
import com.seaofnodes.simple.node.Node;
+import com.seaofnodes.simple.util.Utils;
public class ShlX86 extends RegX86 {
ShlX86( Node add ) { super(add); }
diff --git a/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/ShrIX86.java b/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/ShrIX86.java
index 893eb23d..7e0378b1 100644
--- a/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/ShrIX86.java
+++ b/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/ShrIX86.java
@@ -1,10 +1,9 @@
package com.seaofnodes.simple.node.cpus.x86_64_v2;
-import com.seaofnodes.simple.node.Node;
-
-import com.seaofnodes.simple.*;
import com.seaofnodes.simple.codegen.*;
import com.seaofnodes.simple.node.*;
+import com.seaofnodes.simple.node.Node;
+import com.seaofnodes.simple.util.SB;
public class ShrIX86 extends MachConcreteNode implements MachNode {
final int _imm;
diff --git a/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/ShrX86.java b/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/ShrX86.java
index d869260f..67dcf055 100644
--- a/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/ShrX86.java
+++ b/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/ShrX86.java
@@ -1,8 +1,8 @@
package com.seaofnodes.simple.node.cpus.x86_64_v2;
-import com.seaofnodes.simple.Utils;
import com.seaofnodes.simple.codegen.*;
import com.seaofnodes.simple.node.Node;
+import com.seaofnodes.simple.util.Utils;
public class ShrX86 extends RegX86 {
ShrX86( Node add ) { super(add); }
diff --git a/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/SplitX86.java b/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/SplitX86.java
index 960ea6f8..4a14240a 100644
--- a/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/SplitX86.java
+++ b/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/SplitX86.java
@@ -1,7 +1,5 @@
package com.seaofnodes.simple.node.cpus.x86_64_v2;
-import com.seaofnodes.simple.SB;
-import com.seaofnodes.simple.Utils;
import com.seaofnodes.simple.codegen.*;
import com.seaofnodes.simple.node.FunNode;
import com.seaofnodes.simple.node.Node;
@@ -9,6 +7,8 @@ import com.seaofnodes.simple.node.SplitNode;
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeFloat;
import com.seaofnodes.simple.type.TypeInteger;
+import com.seaofnodes.simple.util.SB;
+import com.seaofnodes.simple.util.Utils;
public class SplitX86 extends SplitNode {
SplitX86( String kind, byte round ) { super(kind,round, new Node[2]); }
diff --git a/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/StoreX86.java b/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/StoreX86.java
index 76fb4e8d..4403b02b 100644
--- a/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/StoreX86.java
+++ b/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/StoreX86.java
@@ -1,12 +1,12 @@
package com.seaofnodes.simple.node.cpus.x86_64_v2;
-import com.seaofnodes.simple.SB;
import com.seaofnodes.simple.codegen.*;
import com.seaofnodes.simple.node.ConstantNode;
import com.seaofnodes.simple.node.Node;
import com.seaofnodes.simple.node.StoreNode;
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeFloat;
+import com.seaofnodes.simple.util.SB;
import java.util.BitSet;
public class StoreX86 extends MemOpX86 {
diff --git a/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/SubFX86.java b/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/SubFX86.java
index 0a169a22..b6530a87 100644
--- a/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/SubFX86.java
+++ b/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/SubFX86.java
@@ -1,8 +1,8 @@
package com.seaofnodes.simple.node.cpus.x86_64_v2;
-import com.seaofnodes.simple.*;
import com.seaofnodes.simple.codegen.*;
import com.seaofnodes.simple.node.*;
+import com.seaofnodes.simple.util.SB;
public class SubFX86 extends MachConcreteNode implements MachNode {
SubFX86( Node subf) { super(subf); }
diff --git a/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/TFPX86.java b/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/TFPX86.java
index d7566f9e..359b6d83 100644
--- a/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/TFPX86.java
+++ b/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/TFPX86.java
@@ -1,11 +1,11 @@
package com.seaofnodes.simple.node.cpus.x86_64_v2;
-import com.seaofnodes.simple.*;
import com.seaofnodes.simple.codegen.*;
import com.seaofnodes.simple.node.*;
import com.seaofnodes.simple.node.cpus.riscv.riscv;
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeFunPtr;
+import com.seaofnodes.simple.util.SB;
// Function constants
public class TFPX86 extends ConstantNode implements MachNode, RIPRelSize {
diff --git a/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/TMPX86.java b/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/TMPX86.java
index c44cf2f9..c23f6c5f 100644
--- a/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/TMPX86.java
+++ b/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/TMPX86.java
@@ -1,9 +1,9 @@
package com.seaofnodes.simple.node.cpus.x86_64_v2;
-import com.seaofnodes.simple.SB;
import com.seaofnodes.simple.codegen.*;
import com.seaofnodes.simple.node.*;
import com.seaofnodes.simple.type.TypeMemPtr;
+import com.seaofnodes.simple.util.SB;
public class TMPX86 extends ConstantNode implements MachNode, RIPRelSize{
TMPX86(ConstantNode con ) { super(con); }
@@ -17,7 +17,11 @@ public class TMPX86 extends ConstantNode implements MachNode, RIPRelSize{
short dst = enc.reg(this);
x86_64_v2.rexF(dst, 0, 0, true, enc);
enc.add1(0x8D).add1(x86_64_v2.modrm(x86_64_v2.MOD.INDIRECT, dst, 0b101)).add4(0);
- enc.largeConstant(this,((TypeMemPtr)_con)._obj,7-4,2/*ELF encoding PC32*/);
+ int opLen = 1/*rexF*/+1/*opcode 0x8D*/+1/*modrm*/+4/*pc rel offset*/;
+ // Base of constant array
+ TypeMemPtr tmp = (TypeMemPtr)_con;
+ int baseOff = tmp._obj.aryBase();
+ enc.largeConstant(this,tmp._obj,opLen-baseOff,2/*ELF encoding PC32*/);
}
// Delta is from opcode start
diff --git a/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/UJmpX86.java b/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/UJmpX86.java
index ec4eeb3b..92d2a87d 100644
--- a/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/UJmpX86.java
+++ b/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/UJmpX86.java
@@ -1,9 +1,10 @@
package com.seaofnodes.simple.node.cpus.x86_64_v2;
-import com.seaofnodes.simple.*;
import com.seaofnodes.simple.codegen.*;
import com.seaofnodes.simple.node.*;
import com.seaofnodes.simple.type.Type;
+import com.seaofnodes.simple.util.SB;
+import com.seaofnodes.simple.util.Utils;
import java.util.BitSet;
// unconditional jump
diff --git a/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/x86_64_v2.java b/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/x86_64_v2.java
index 6706635f..026e12aa 100644
--- a/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/x86_64_v2.java
+++ b/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/x86_64_v2.java
@@ -1,9 +1,9 @@
package com.seaofnodes.simple.node.cpus.x86_64_v2;
-import com.seaofnodes.simple.Utils;
import com.seaofnodes.simple.codegen.*;
import com.seaofnodes.simple.node.*;
import com.seaofnodes.simple.type.*;
+import com.seaofnodes.simple.util.Utils;
public class x86_64_v2 extends Machine {
public x86_64_v2( CodeGen code ) {}
@@ -486,7 +486,8 @@ public class x86_64_v2 extends Machine {
return new CmpMemX86(bool, address(ld), ld.ptr(), idx, off, scale, imm(rhs), val, false);
// Operands swap in the encoding directly, no need for Set/Jmp to swap `bop`
- if( rhs instanceof LoadNode ld && ld.nOuts() == 1 && lhs._type.isa(ld._declaredType))
+ if( rhs instanceof LoadNode ld && ld.nOuts() == 1 && lhs._type.isa(ld._declaredType) &&
+ (val!=null || bool.op()=="==" || bool.op()=="!=") )
return new CmpMemX86(bool, address(ld), ld.ptr(), idx, off, scale, imm(lhs), val, true );
// Vs immediate
diff --git a/src/main/java/com/seaofnodes/simple/print/ASMPrinter.java b/src/main/java/com/seaofnodes/simple/print/ASMPrinter.java
index 366ae376..a9f86ce8 100644
--- a/src/main/java/com/seaofnodes/simple/print/ASMPrinter.java
+++ b/src/main/java/com/seaofnodes/simple/print/ASMPrinter.java
@@ -1,13 +1,13 @@
package com.seaofnodes.simple.print;
-import com.seaofnodes.simple.Ary;
-import com.seaofnodes.simple.SB;
-import com.seaofnodes.simple.Utils;
import com.seaofnodes.simple.codegen.CodeGen;
-import com.seaofnodes.simple.codegen.Encoding;
import com.seaofnodes.simple.codegen.Encoding.Relo;
+import com.seaofnodes.simple.codegen.Encoding;
import com.seaofnodes.simple.node.*;
import com.seaofnodes.simple.type.*;
+import com.seaofnodes.simple.util.Ary;
+import com.seaofnodes.simple.util.SB;
+import com.seaofnodes.simple.util.Utils;
import java.util.HashSet;
public abstract class ASMPrinter {
@@ -98,7 +98,8 @@ public abstract class ASMPrinter {
if( fun._name != null ) sb.p(fun._name).p(" ");
fun.sig().print(sb);
sb.p("---------------------------").nl();
- iadr = (iadr + 15)&-16; // All function entries padded to 16 align
+ if( code._encoding!=null && code._encoding._padFunHeads )
+ iadr = (iadr + 15)&-16; // All function entries padded to 16 align
if( fun._frameAdjust != 0 )
iadr = doInst(iadr,sb,code,fun,cfgidx,fun,true,true);
diff --git a/src/main/java/com/seaofnodes/simple/print/GraphVisualizer.java b/src/main/java/com/seaofnodes/simple/print/GraphVisualizer.java
index e4cf2c31..20c8439a 100644
--- a/src/main/java/com/seaofnodes/simple/print/GraphVisualizer.java
+++ b/src/main/java/com/seaofnodes/simple/print/GraphVisualizer.java
@@ -3,7 +3,7 @@ package com.seaofnodes.simple.print;
import com.seaofnodes.simple.Parser;
import com.seaofnodes.simple.node.*;
import java.util.*;
-import static com.seaofnodes.simple.Utils.TODO;
+import static com.seaofnodes.simple.util.Utils.TODO;
/**
* Simple visualizer that outputs GraphViz dot format.
@@ -155,7 +155,7 @@ public class GraphVisualizer {
private void scope( StringBuilder sb, ScopeNode scope ) {
sb.append("\tnode [shape=plaintext];\n");
int last = scope.nIns();
- int max = scope._lexSize.size();
+ int max = scope.depth();
for( int i = 0; i < max; i++ ) {
int level = max-i-1;
String scopeName = makeScopeName(scope, level);
@@ -169,7 +169,7 @@ public class GraphVisualizer {
sb.append("\t\t\t<TABLE BORDER=\"0\" CELLBORDER=\"1\" CELLSPACING=\"0\">\n");
// Add the scope level
sb.append("\t\t\t<TR><TD BGCOLOR=\"cyan\">").append(level).append("</TD>");
- int lexStart=scope._lexSize.at(level);
+ int lexStart = scope._kinds.at(level)._lexSize;
for( int j=lexStart; j<last; j++ ) {
var v = scope._vars.at(j);
sb.append("<TD PORT=\"").append(makePortName(scopeName, v._name)).append("\">").append(v._name).append("</TD>");
@@ -243,7 +243,7 @@ public class GraphVisualizer {
while( def instanceof ScopeNode lazy )
def = lazy.in(v._idx);
if( def==null ) continue;
- while( level < scope._lexSize.size() && v._idx >= scope._lexSize.at(level) )
+ while( level < scope.depth() && v._idx >= scope._kinds.at(level)._lexSize )
level++;
String scopeName = makeScopeName(scope, level-1);
sb.append("\t")
diff --git a/src/main/java/com/seaofnodes/simple/print/IRPrinter.java b/src/main/java/com/seaofnodes/simple/print/IRPrinter.java
index c6e478c5..d1265bef 100644
--- a/src/main/java/com/seaofnodes/simple/print/IRPrinter.java
+++ b/src/main/java/com/seaofnodes/simple/print/IRPrinter.java
@@ -1,11 +1,11 @@
package com.seaofnodes.simple.print;
-import com.seaofnodes.simple.Ary;
-import com.seaofnodes.simple.SB;
-import com.seaofnodes.simple.Utils;
import com.seaofnodes.simple.codegen.CodeGen;
import com.seaofnodes.simple.node.*;
import com.seaofnodes.simple.type.TypeFunPtr;
+import com.seaofnodes.simple.util.Ary;
+import com.seaofnodes.simple.util.SB;
+import com.seaofnodes.simple.util.Utils;
import java.util.ArrayList;
import java.util.BitSet;
import java.util.HashMap;
@@ -61,7 +61,7 @@ public abstract class IRPrinter {
if( n instanceof CFGNode || n instanceof MultiNode ) {
if( !gap ) sb.p("\n"); // Blank before multihead
if( n instanceof FunNode fun )
- fun.sig().print(sb.p("--- ").p(fun._name==null ? "" : fun._name).p(" "),false).p("----------------------\n");
+ fun.sig().print(sb.p("--- ").p(fun._name==null ? "" : fun._name).p(" ")).p("----------------------\n");
printLine( n, sb ); // Print head
while( --i >= 0 ) {
Node t = rpos.get(i);
@@ -72,7 +72,7 @@ public abstract class IRPrinter {
FunNode fun = ret.fun();
sb.p("--- ");
if( fun != null )
- fun.sig().print(sb.p(fun._name==null ? "" : fun._name).p(" "),false);
+ fun.sig().print(sb.p(fun._name==null ? "" : fun._name).p(" "));
sb.p("----------------------\n");
}
if( !(n instanceof CallNode) ) {
diff --git a/src/main/java/com/seaofnodes/simple/print/JSViewer.java b/src/main/java/com/seaofnodes/simple/print/JSViewer.java
index 76c64c71..62ff0001 100644
--- a/src/main/java/com/seaofnodes/simple/print/JSViewer.java
+++ b/src/main/java/com/seaofnodes/simple/print/JSViewer.java
@@ -1,10 +1,10 @@
package com.seaofnodes.simple.print;
-import com.seaofnodes.simple.SB;
-import com.seaofnodes.simple.Utils;
import com.seaofnodes.simple.codegen.CodeGen;
import com.seaofnodes.simple.node.*;
import com.seaofnodes.simple.type.*;
+import com.seaofnodes.simple.util.SB;
+import com.seaofnodes.simple.util.Utils;
import java.io.IOException;
import java.nio.file.Paths;
import java.util.Collection;
@@ -192,14 +192,14 @@ public class JSViewer implements AutoCloseable {
private static void scope( SB sb, ScopeNode scope ) {
sb.i().p("node [shape=plaintext];\n");
int last = scope.nIns();
- int max = scope._lexSize.size()+1; // One more than lexsize
+ int max = scope.depth()+1; // One more than lexsize
for( int i = 0; i < max; i++ ) {
int level = max-i-1;
String scopeName = makeScopeName(scope, level);
sb.i().p("subgraph cluster_").p(scopeName).p(" {\n").ii(); // Magic "cluster_" in the subgraph name
sb.i().p(scopeName).p(" [label=<\n").ii();
sb.i().p("<TABLE BORDER=\"0\" CELLBORDER=\"1\" CELLSPACING=\"0\">\n");
- int lexStart = level==0 ? 0 : scope._lexSize.at(level-1);
+ int lexStart = level==0 ? 0 : scope._kinds.at(level-1)._lexSize;
// Special for memory ScopeMinNode
MemMergeNode n = scope.nIns()>1 ? scope.mem() : null;
@@ -365,7 +365,7 @@ public class JSViewer implements AutoCloseable {
while( def instanceof ScopeNode lazy )
def = lazy.in(v._idx);
if( def==null ) continue;
- while( level < scope._lexSize.size() && v._idx >= scope._lexSize.at(level) )
+ while( level < scope.depth() && v._idx >= scope._kinds.at(level)._lexSize )
level++;
String scopeName = makeScopeName(scope, level);
sb.i()
diff --git a/src/main/java/com/seaofnodes/simple/print/SimpleWebSocket.java b/src/main/java/com/seaofnodes/simple/print/SimpleWebSocket.java
index 7655213d..4077533d 100644
--- a/src/main/java/com/seaofnodes/simple/print/SimpleWebSocket.java
+++ b/src/main/java/com/seaofnodes/simple/print/SimpleWebSocket.java
@@ -1,6 +1,6 @@
package com.seaofnodes.simple.print;
-import com.seaofnodes.simple.Utils;
+import com.seaofnodes.simple.util.Utils;
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
diff --git a/src/main/java/com/seaofnodes/simple/sys/sys.smp b/src/main/java/com/seaofnodes/simple/sys/sys.smp
deleted file mode 100644
index 4ac925db..00000000
--- a/src/main/java/com/seaofnodes/simple/sys/sys.smp
+++ /dev/null
@@ -1,58 +0,0 @@
-// -*- mode: java; -*-
-
-// top-level default import
-struct sys {
- // libc bindings
- /** https://www.man7.org/linux/man-pages/man2/<libc call>.2.html */
- struct libc {
- i32 errno = "C";
- // fd buf len -> len
- { i32 i64 u32 -> u32 } write = "C";
- // fd buf len -> len
- { i32 i64 u32 -> u32 } read = "C";
- // status
- { i32 -> i32 } _exit = "C";
- // addr len prot flags fd off -> void*
- { i64 i64 i32 i32 i32 i32 -> i64 } mmap = "C";
- // mmap flags
- i32 PROT_EXEC = 4;
- i32 PROT_READ = 1;
- i32 PROT_WRITE= 2;
- i32 PROT_NONE = 0;
- i32 MAP_PRIVATE = 2;
- i32 MAP_ANON = 32;
- };
- struct ary {
- val copy = { u8[] dst, int doff, u8[~] src, int soff, int len ->
- for( int i=0; i<len; i++ )
- dst[i+doff] = src[i+soff];
- return dst;
- };
- };
- struct io {
- // Print string to stdout
- val p = { u8[~] str ->
- i64 ptr = str; // cast array base to i64
- return sys.libc.write(1,ptr,str#);
- };
-
- // Return stdin as a u8[]
- val stdin = { ->
- var buf = new u8[8*1024];
- i64 ptr = buf;
- int len = 0;
- while( true ) {
- int rez = sys.libc.read(0,ptr,buf#);
- if( rez < 0 ) sys.libc._exit(sys.libc.errno);
- len += rez;
- if( rez < buf# )
- break;
- sys.libc._exit(-2); // Need to implement
- }
- // Compress
- var dst = new u8[len];
- return sys.ary.copy(dst,0,buf,0,len);
- };
-
- };
-};
diff --git a/src/main/java/com/seaofnodes/simple/type/Field.java b/src/main/java/com/seaofnodes/simple/type/Field.java
index ad96369b..b2b2deca 100644
--- a/src/main/java/com/seaofnodes/simple/type/Field.java
+++ b/src/main/java/com/seaofnodes/simple/type/Field.java
@@ -1,8 +1,8 @@
package com.seaofnodes.simple.type;
-import com.seaofnodes.simple.SB;
-import com.seaofnodes.simple.Utils;
-import java.util.ArrayList;
+import com.seaofnodes.simple.util.Ary;
+import com.seaofnodes.simple.util.SB;
+import java.util.*;
/**
* Represents a field in a struct. This is not a Type in the type system.
@@ -12,65 +12,125 @@ public class Field extends Type {
// The pair {fieldName,type} uniquely identifies a field.
// Field name
- public final String _fname;
+ public String _fname;
// Type of the field
- public final Type _type;
+ public Type _t;
// Unique memory alias, not sensibly part of a "type" but very convenient here.
- public final int _alias;
+ public int _alias;
// Field must be written to exactly once, no more, no less
- public final boolean _final;
+ public boolean _final;
+ // Field is final in the declaration; value is the same for all instances
+ // and will be moved to the class object
+ public boolean _one;
- private Field(String fname, Type type, int alias, boolean xfinal ) {
- super(TFLD);
+ private static final Ary<Field> FREE = new Ary<>(Field.class);
+ private Field(String fname, Type type, int alias, boolean xfinal, boolean one ) { super(TFLD); init(fname,type,alias,xfinal,one); }
+ private Field init(String fname, Type type, int alias, boolean xfinal, boolean one ) {
_fname = fname;
- _type = type;
+ _t = type;
_alias = alias;
_final = xfinal;
+ _one = one;
+ return this;
}
- // Make with existing alias
- public static Field make( String fname, Type type, int alias, boolean xfinal ) {
- return new Field(fname,type,alias,xfinal).intern();
+
+ // Return a filled-in Field; either from free list or alloc new.
+ private static Field malloc(String fname, Type type, int alias, boolean xfinal, boolean one ) {
+ return FREE.isEmpty() ? new Field(fname,type,alias,xfinal,one) : FREE.pop().init(fname,type,alias,xfinal,one);
+ }
+ // Malloc-from
+ public Field malloc( ) { return malloc(_fname,null,_alias,_final,_one); }
+ @Override Field free(Type t) {
+ Field f = (Field)t;
+ assert !f.isFree() && !f._terned;
+ f._t = null;
+ f._dual = null;
+ f._hash = 0;
+ FREE.push(f);
+ return this;
+ }
+ @Override boolean isFree() { return _t ==null; }
+
+ // Make and intern with listed fields
+ public static Field make( String fname, Type type, int alias, boolean xfinal, boolean one ) {
+ Field f = malloc(fname,type,alias,xfinal,one);
+ Field f2 = f.intern();
+ if( f2==f ) return f;
+ return VISIT.isEmpty() ? f2.free(f) : f2.delayFree(f);
}
public Field makeFrom( Type type ) {
- return type == _type ? this : new Field(_fname,type,_alias,_final).intern();
+ return type == _t ? this : make(_fname,type,_alias,_final,_one);
+ }
+ public Field makeFrom( boolean xfinal ) {
+ return xfinal == _final ? this : make(_fname,_t,_alias,xfinal,_one);
}
- @Override public Field makeRO() { return _final ? this : make(_fname,_type.makeRO(),_alias,true); }
- @Override public boolean isFinal() { return _final && _type.isFinal(); }
- public static final Field TEST = make("test",Type.NIL,-2,false);
- public static final Field TEST2= make("test",Type.NIL,-2,true);
- public static void gather(ArrayList<Type> ts) { ts.add(TEST); ts.add(TEST2); }
+ // Cycle-making-breaking
+ void setType(Type t) { assert _t ==null; _t = t; }
+
+ public static final Field BOT = make(" ",Type.BOTTOM,-999,true,false);
+ public static final Field TEST = make("test",Type.NIL,-2,false,false);
+ public static final Field TEST2 = make("test",Type.NIL,-2,true, false);
+ public static final Field FLT = make("flt ",TypeFloat.F32,-2,false,false);
+ public static void gather(ArrayList<Type> ts) { ts.add(TEST); ts.add(TEST2); ts.add(FLT); }
@Override Field xmeet( Type that ) {
Field fld = (Field)that; // Invariant
- assert _fname.equals(fld._fname);
+ if( this==BOT || fld==BOT ) return BOT;
+ if( this==BOT.dual() ) return fld ;
+ if( fld ==BOT.dual() ) return this;
+ if( _fname!=fld._fname ) { assert !_fname.equals(fld._fname); return BOT; }
assert _alias==fld._alias;
- return make(_fname,_type.meet(fld._type),_alias,_final | fld._final);
+ assert _one ==fld._one ;
+ return make(_fname, _t.meet(fld._t ),_alias,_final | fld._final, _one);
}
@Override
- public Field dual() { return make(_fname,_type.dual(),_alias,!_final); }
+ Field xdual() { return malloc(_fname, _t.dual(),_alias,!_final,_one); }
- @Override public boolean isConstant() { return _type.isConstant(); }
+ @Override Field rdual() {
+ if( _dual!=null ) return dual();
+ assert !_terned;
+ Field d = malloc(_fname,null,_alias,!_final,_one);
+ (_dual = d)._dual = this; // Cross link duals
+ d._t = _t._terned ? _t.dual() : _t.rdual();
+ return d;
+ }
- @Override public Field glb(boolean mem) {
- Type glb = _type.glb(mem);
- return (glb==_type && _final) ? this : make(_fname,glb,_alias,true);
+ @Override boolean _isConstant() { return _t._isConstant(); }
+ @Override boolean _isFinal() { return _final && _t._isFinal(); }
+ @Override Field _makeRO() { return _final ? this : make(_fname, _t._makeRO(),_alias,true,_one); }
+ boolean isGLB2() { return _final && _t._isGLB(true); }
+ Field glb2() {
+ Type glb = _t._glb(true);
+ return (glb== _t && _final ) ? this : make(_fname,glb,_alias,true,_one);
}
+ @Override Field _close() { return makeFrom( _t._close()); }
// Override in subclasses
- int hash() { return _fname.hashCode() ^ _type.hashCode() ^ _alias ^ (_final ? 1024 : 0); }
+ int hash() { return _fname.hashCode() ^ _t.hashCode() ^ _alias ^ (_final ? 1024 : 0) ^ (_one ? 2048 : 0); }
- boolean eq(Type t) {
+ private boolean static_eq( Field f ) {
+ return _fname.equals(f._fname) && _alias==f._alias && _final==f._final && _one==f._one && _t !=null && f._t !=null;
+ }
+ @Override boolean eq( Type t ) {
+ Field f = (Field)t;
+ return static_eq(f) && _t ==f._t;
+ }
+ @Override boolean cycle_eq(Type t) {
Field f = (Field)t;
- return _fname.equals(f._fname) && _type==f._type && _alias==f._alias && _final==f._final;
+ return static_eq(f) && _t.cycle_eq(f._t );
}
+ @Override int nkids() { return 1; }
+ @Override Type at( int idx ) { return _t; }
+ @Override void set( int idx, Type t ) { _t = t; }
@Override
- public SB print( SB sb ) {
- return _type.print(sb.p(_final?"":"!").p(_fname).p(":").p(_alias).p(" : "));
+ public SB _print( SB sb, BitSet visit, boolean html ) {
+ sb.p(_final?"":"!").p(_one?"$":"").p(_fname).p(":").p(_alias).p(" : ");
+ return _t ==null ? sb.p("---") : _t.print(sb,visit,html);
}
- @Override public String str() { return (_final?"":"!")+_fname; }
+ @Override public String str() { return (_final?"":"!")+(_one?"$":"")+_fname; }
}
diff --git a/src/main/java/com/seaofnodes/simple/type/Type.java b/src/main/java/com/seaofnodes/simple/type/Type.java
index a44cdd61..b7a8408e 100644
--- a/src/main/java/com/seaofnodes/simple/type/Type.java
+++ b/src/main/java/com/seaofnodes/simple/type/Type.java
@@ -1,9 +1,7 @@
package com.seaofnodes.simple.type;
-import com.seaofnodes.simple.SB;
-import com.seaofnodes.simple.Utils;
-import java.util.ArrayList;
-import java.util.HashMap;
+import com.seaofnodes.simple.util.*;
+import java.util.*;
/**
* These types are part of a Monotone Analysis Framework,
@@ -21,8 +19,33 @@ import java.util.HashMap;
* simple constant folding e.g. 1+2 == 3 stuff.
*/
-public class Type {
+public class Type /*implements Cloneable*/ {
+ // Interning tables
+
+ // Main intern table; a collection of all unique types.
static final HashMap<Type,Type> INTERN = new HashMap<>();
+ // Starting intern table; used to rapidly reset the main table between tests
+ private static final HashMap<Type,Type> INTERN0= new HashMap<>();
+ // Lifetime management during cyclic installs is complex; this is used to
+ // track created-but-already-interned objects
+ private static final Ary<Type> FREES = new Ary<>(Type.class);
+ // "visit" bit management, based solely on _uid
+ static final BitSet BITS = new BitSet();
+
+ // "visit" bit management. Key varies by kind of visit:
+
+ // - "close" an open cyclic type. Used by the Parser, it will hit on
+ // same-named structs, even if the structs have different states of
+ // completion/fields.
+ // - "uid/name" - Either the UID or name works (unlike "close" which must
+ // use the name). Used to make cyclic copies with changes, like make
+ // read-only where there should be only 1 copy of a name in a cycle.
+ // - "pair of uids" - For recursive MEET, where we need to key off two types
+ static final HashMap<Object,Type> VISIT = new HashMap<>();
+
+ // Every Type has a UID to allow visit bits on cyclic visits
+ private static int UID=1;
+ public char _uid; // Unique ID for every type
// ----------------------------------------------------------
// Simple types are implemented fully here. "Simple" means: the code and
@@ -38,33 +61,42 @@ public class Type {
static final byte TPTR = 7; // All nil-able scalar values
static final byte TINT = 8; // All Integers; see TypeInteger
static final byte TFLT = 9; // All Floats ; see TypeFloat
- static final byte TMEMPTR =10; // Memory pointer to a struct type
- static final byte TFUNPTR =11; // Function pointer; unique signature and code address (just a bit)
+ static final byte TCONARY =10; // Constant array
+ static final byte TRPC =11; // Return Program Control (Return PC or RPC)
static final byte TTUPLE =12; // Tuples; finite collections of unrelated Types, kept in parallel
- static final byte TMEM =13; // All memory (alias 0) or A slice of memory - with specific alias
- static final byte TSTRUCT =14; // Structs; tuples with named fields
- static final byte TFLD =15; // Named fields in structs
- static final byte TCONARY =16; // Constant array
- static final byte TRPC =17; // Return Program Control (Return PC or RPC)
+ static final byte TCYCLIC =13; // Has internal pointers, needs recursive treatment
+ static final byte TMEMPTR =13; // Memory pointer to a struct type
+ static final byte TFUNPTR =14; // Function pointer; unique signature and code address (just a bit)
+ static final byte TMEM =15; // All memory (alias 0) or A slice of memory - with specific alias
+ static final byte TSTRUCT =16; // Structs; tuples with named fields
+ static final byte TFLD =17; // Named fields in structs
+
+ // Basic RTTI, useful for a lot of fast tests.
public final byte _type;
+ public boolean _terned;
public boolean is_simple() { return _type < TSIMPLE; }
private static final String[] STRS = new String[]{"Bot","Top","Ctrl","~Ctrl","null","~nil"};
- protected Type(byte type) { _type = type; }
+ static final int[] CNTS = new int[TFLD+1];
+ protected Type(byte type) {
+ _type = type; // RTTI
+ _uid = (char)UID++; // A unique ID for every type
+ assert _uid!=0; // Overflow
+ CNTS[type]++;
+ }
public static final Type BOTTOM = new Type( TBOT ).intern(); // ALL
- public static final Type TOP = new Type( TTOP ).intern(); // ANY
+ public static final Type TOP = BOTTOM.dual();
public static final Type CONTROL = new Type( TCTRL ).intern(); // Ctrl
- public static final Type XCONTROL = new Type( TXCTRL ).intern(); // ~Ctrl
+ public static final Type XCONTROL = CONTROL.dual();
public static final Type NIL = new Type( TNIL ).intern(); // low null of all flavors
- public static final Type XNIL = new Type( TXNIL ).intern(); // high or choice null
+ public static final Type XNIL = NIL.dual();
public static Type[] gather() {
ArrayList<Type> ts = new ArrayList<>();
ts.add(BOTTOM);
ts.add(CONTROL);
ts.add(NIL);
- ts.add(XNIL);
TypeNil.gather(ts);
TypePtr.gather(ts);
TypeInteger.gather(ts);
@@ -77,6 +109,7 @@ public class Type {
TypeTuple.gather(ts);
TypeRPC.gather(ts);
TypeConAry.gather(ts);
+
int sz = ts.size();
for( int i = 0; i < sz; i++ )
ts.add(ts.get(i).dual());
@@ -87,10 +120,6 @@ public class Type {
public boolean isHigh () { return _type==TTOP || _type==TXCTRL || _type==TXNIL; }
public boolean isHighOrConst() { return isHigh() || isConstant(); }
- // Strict constant values, things on the lattice centerline.
- // Excludes both high and low values
- public boolean isConstant() { return _type==TNIL; }
-
// ----------------------------------------------------------
// Notes on Type interning: At the moment it is not easy to reset the
@@ -106,14 +135,68 @@ public class Type {
// Factory method which interns "this"
@SuppressWarnings("unchecked")
- public <T extends Type> T intern() {
- T nnn = (T)INTERN.get(this);
- if( nnn==null )
- INTERN.put(nnn=(T)this,this);
- return nnn;
+ <T extends Type> T intern() {
+ //assert check();
+ assert !_terned; // Do not ask for already-interned
+ T t2 = (T)INTERN.get(this);
+ if( t2!=null ) {
+ assert t2._dual != null; // Prior is complete with dual
+ assert this != t2; // Do not hashcons twice, should not get self back
+ return t2; // Return prior
+ }
+ // Mid recursive type construction
+ if( !VISIT.isEmpty() && _type >= TCYCLIC ) {
+ // No intern attempt at all
+ return (T)this;
+ }
+ // Not in type table
+ _dual = null; // No dual yet
+ INTERN.put(this,this); // Put in table without dual
+ _terned = true;
+ //Util.hash_quality_check_per(INTERN,"INTERN");
+ T d = xdual(); // Compute dual without requiring table lookup, and not setting name
+ _dual = d;
+ if( this==d ) return d; // Self-symmetric? Dual is self
+ assert !equals(d); // Self-symmetric is handled by caller
+ assert d._dual==null; // Else dual-dual not computed yet
+ assert INTERN.get(d)==null;
+ d._dual = (T)this;
+ INTERN.put(d,d); // Install dual also
+ d._terned = true;
+ //assert check();
+ return (T)this;
+ }
+
+ // Recursive visit elsewhere, interns with dual already
+ <T extends Type> T _intern() {
+ //assert check();
+ assert !_terned;
+ Type t = INTERN.get(this);
+ if( t!=null ) return (T)t.delayFree(this).delayFree(_dual);
+ assert !INTERN.containsKey( _dual );
+ INTERN.put(this,this);
+ INTERN.put(_dual,_dual);
+ _terned = _dual._terned = true;
+ //assert check();
+ return (T)this;
}
- private int _hash; // Hash cache; not-zero when set.
+ private static boolean check() {
+ for( Type t : INTERN.keySet() ) {
+ Type t2 = INTERN.get(t);
+ assert t==t2;
+ }
+ return true;
+ }
+
+ public static Type find(int uid) {
+ for( Type t : INTERN.keySet() )
+ if( t._uid==uid ) return t;
+ return null;
+ }
+
+
+ int _hash; // Hash cache; not-zero when set.
@Override
public final int hashCode() {
if( _hash!=0 ) return _hash;
@@ -132,8 +215,42 @@ public class Type {
return eq(t);
}
// Overridden in subclasses; subclass can assume "this!=t" and java classes are same
- boolean eq(Type t) { return true; }
+ boolean eq(Type t) { return this==t; }
+ boolean cycle_eq(Type t) { assert _type < TCYCLIC; return eq(t); }
+ // A pair of uids
+ int pid( Type that ) {
+ return _uid < that._uid ? (_uid<<16 | that._uid) : (that._uid<<16 | _uid);
+ }
+ // At/Set child at 'idx' to t
+ Type at ( int idx ) { throw Utils.TODO(); }
+ void set( int idx, Type t ) { throw Utils.TODO(); }
+ int nkids() { assert _type < TTUPLE; return 0; } // Number of kids
+
+
+ // Clear and re-insert the basic Type INTERN table
+ public static void reset() {
+ VISIT.clear();
+ FREES.clear();
+ if( INTERN0.isEmpty() ) {
+ // First time run all <clinit> and collect basic types
+ Type t = TypeRPC .BOT; // Force class load, intern
+ Type u = TypeTuple.BOT; // Force class load, intern
+ Type w = TypePtr .PTR; // Force class load, intern
+ INTERN0.putAll(INTERN);
+ } else {
+ // Later times, reset back to first time
+ VISIT.put(0,CONTROL); // Defeat assert
+ for( Iterator<Type> it = INTERN.keySet().iterator(); it.hasNext(); ) {
+ Type t = it.next();
+ if( !INTERN0.containsKey(t) )
+ { t._terned=false; t.free(t); }
+ it.remove();
+ }
+ VISIT.clear();
+ INTERN.putAll(INTERN0);
+ }
+ }
// ----------------------------------------------------------
public final Type meet(Type t) {
@@ -172,18 +289,24 @@ public class Type {
return _type==TCTRL || t._type==TCTRL ? CONTROL : XCONTROL;
}
- public Type dual() {
- return switch( _type ) {
- case TBOT -> TOP;
- case TTOP -> BOTTOM;
- case TCTRL ->XCONTROL;
- case TXCTRL-> CONTROL;
- case TNIL ->XNIL;
- case TXNIL -> NIL;
+
+ // The dual is pre-computed on creation and available "for free" thereafter
+ Type _dual;
+ public final <T extends Type> T dual() { return (T)_dual; }
+
+ <T extends Type> T xdual() {
+ return (T)new Type(switch( _type ) {
+ case TBOT -> TTOP;
+ case TTOP -> TBOT;
+ case TCTRL -> TXCTRL;
+ case TXCTRL-> TCTRL;
+ case TNIL -> TXNIL;
+ case TXNIL -> TNIL;
default -> throw Utils.TODO(); // Should not reach here
- };
+ });
}
+
// ----------------------------------------------------------
// Our lattice is defined with a MEET and a DUAL.
// JOIN is dual of meet of both duals.
@@ -203,18 +326,157 @@ public class Type {
// Make a zero version of this type, 0 for integers and null for pointers.
public Type makeZero() { return Type.NIL; }
- /** Compute greatest lower bound in the lattice. If values are in memory,
- * ints and floats cannot widen. */
- public Type glb(boolean mem) { return Type.BOTTOM; }
-
// Is forward-reference
public boolean isFRef() { return false; }
- // All reachable struct Fields are final
- public boolean isFinal() { return true; }
+ // ----------------------------------------------------------
- // Make all reachable struct Fields final
- public Type makeRO() { return this; }
+ // Cyclic types! Flag the start of a cyclic type by putting a sentinel in
+ // VISIT (and eventually clearing VISIT when done). Then do a normal
+ // recursive descent visit of all types; this will accumilate types without
+ // interning them. When done we have to visit the possibly cyclic type and
+ // intern the whole cycle, possibly hitting the entire cycle on a prior
+ // interned cycle. Any sub-part might also be interned, including whole
+ // disjoint cycles.
+
+ // E.g. a new type: "A<->B -> C1<->D1" gets created; the "C1<->D1" cycle
+ // already exists as "C0<->D0", but the "A<->B" cycle is new. The "A<->B"
+ // cycle will get interned - except the pointer to C1 needs to get replaced
+ // with C0. The "C1<->D1" cycle gets freed and "B" will point to the
+ // "C0<->D0" cycle.
+
+ Type recurOpen() { assert VISIT.isEmpty(); VISIT.put(0L,BOTTOM); return this; }
+ Type recurClose() {
+ VISIT.remove(0L); // Just ignore the sentinel
+ Ary<Type> ts = new Ary<>(Type.class);
+ ts.addAll(VISIT.values());
+ if( ts.find(this)== -1 ) ts.add(this);
+
+ // Pass #1: replace already interned fields
+ assert BITS.isEmpty();
+ for( int i=0; i<ts._len; i++ )
+ if( ts.at(i).tern()._terned )
+ ts.del(i--);
+ BITS.clear();
+
+ // Pass#2: compute recursive duals
+ for( Type t : ts )
+ t.rdual();
+
+ // Pass#3: Recursive install
+ for( Type t : ts )
+ if( !t._terned && INTERN.get(t)==null )
+ t.install();
+ // Upgrade the result
+ Type rez = INTERN.get(this);
+ assert rez!=null;
+
+ // Pass#4?: Free up any created-but-already interned
+ for( Type t : FREES )
+ t.rfree();
+ FREES.clear();
+ VISIT.clear();
+ return rez;
+ }
+
+ // Read-only recursive visits do not *make* cyclic types and so the cleanup
+ // is much easier.
+ static boolean recurClose(boolean rez) { VISIT.clear(); return rez; }
+
+ final Type tern() {
+ if( _terned ) return this;
+ if( !BITS.get(_uid) ) {
+ BITS.set(_uid);
+ int nkids = nkids();
+ for( int i=0; i<nkids; i++ )
+ set(i,at(i).tern());
+ }
+ Type told = INTERN.get(this);
+ return told==null ? this : told.delayFree(this);
+ }
+
+ // Recursive dual. Visit all types recursively. Each visited type is
+ // *new*, and hits in the intern table, or not. If not, we recursively
+ // call rdual to get its dual, and cross-link the duals. If hitting, we
+ // use the intern type and mark the prior type for freeing.
+ Type rdual() { assert !_terned; return xdual(); }
+
+ // Recursively free type and children
+ final void rfree() {
+ if( isFree() ) return;
+ int nkids = nkids();
+ for( int i=0; i<nkids; i++ )
+ if( !at(i)._terned )
+ at(i).rfree();
+ free(this);
+ }
+
+ Type free(Type free) { return this; }
+ boolean isFree() { return false; }
+
+ <T extends Type> T delayFree(Type free) {
+ assert !free._terned;
+ FREES.push(free);
+ return (T)this;
+ }
+
+ final Type install() {
+ if( this instanceof TypeStruct ) {
+ Type x = _intern(); // Stop the recursion
+ assert x==this;
+ }
+ int nkids = nkids();
+ for( int i=0; i<nkids; i++ ) {
+ Type kid = at(i);
+ if( !kid._terned ) {
+ Type ikid = kid.install();
+ if( ikid != kid ) {
+ set(i,ikid);
+ _dual.set(i,ikid.dual());
+ }
+ }
+ }
+ return this instanceof TypeStruct ? this : _intern();
+ }
+
+ // Strict constant values, things on the lattice centerline.
+ // Excludes both high and low values
+ public final boolean isConstant() { return recurClose(recurOpen()._isConstant()); }
+ boolean _isConstant() { return _type==TNIL; }
+
+ // Are all reachable struct Fields are final?
+ public final boolean isFinal() { return recurClose(recurOpen()._isFinal()); }
+ boolean _isFinal() { assert _type < TCYCLIC; return true; }
+
+ public final Type makeRO() {
+ if( isFinal() ) return this;
+ return recurOpen()._makeRO().recurClose();
+ }
+ Type _makeRO() { return this; }
+
+ // Compute greatest lower bound in the lattice. If values are in memory,
+ // ints and floats cannot widen.
+ public final boolean isGLB(boolean mem) { return recurClose(recurOpen()._isGLB(mem)); };
+ boolean _isGLB(boolean mem) {
+ return switch(_type) {
+ case TBOT -> false;
+ case TNIL -> false;
+ case TCTRL -> true;
+ case TXCTRL -> false;
+ case TXNIL -> false;
+ case TTOP -> false;
+ default -> throw Utils.TODO();
+ };
+ }
+ public final Type glb(boolean mem) {
+ if( isGLB(mem) ) return this;
+ Type glb = recurOpen()._glb(mem).recurClose();
+ assert this.isa(glb);
+ return glb;
+ }
+ Type _glb(boolean mem) { assert is_simple(); return Type.BOTTOM; }
+
+ Type _close() { return this; }
// ----------------------------------------------------------
@@ -231,11 +493,21 @@ public class Type {
// This is a more verbose dev-friendly print.
@Override
public final String toString() {
- return print(new SB()).toString();
+ return print(new SB(), new BitSet(), false).toString();
}
-
- public SB print(SB sb) { return sb.p(str()); }
- public SB gprint(SB sb) { return print(sb); }
+ public final String gprint() {
+ return print(new SB(), new BitSet(), true).toString();
+ }
+ public final SB print(SB sb) { return print(sb, new BitSet(), false); }
+ public final SB gprint(SB sb) { return print(sb, new BitSet(), true ); }
+
+ // Used during recursive printing, or combined with SB Node printing
+ public final SB print(SB sb, BitSet visit, boolean html ) {
+ if( visit.get(_uid) ) return sb.p(str());
+ visit.set(_uid);
+ return _print(sb,visit,html);
+ }
+ SB _print(SB sb, BitSet visit, boolean html ) { return sb.p(str()); }
// This is used by error messages, and is a shorted print.
public String str() { return STRS[_type]; }
diff --git a/src/main/java/com/seaofnodes/simple/type/TypeConAry.java b/src/main/java/com/seaofnodes/simple/type/TypeConAry.java
index 29496af6..d4003f87 100644
--- a/src/main/java/com/seaofnodes/simple/type/TypeConAry.java
+++ b/src/main/java/com/seaofnodes/simple/type/TypeConAry.java
@@ -1,9 +1,9 @@
package com.seaofnodes.simple.type;
-import com.seaofnodes.simple.SB;
-import com.seaofnodes.simple.Utils;
-import java.util.ArrayList;
+import com.seaofnodes.simple.util.SB;
+import com.seaofnodes.simple.util.Utils;
import java.io.ByteArrayOutputStream;
+import java.util.ArrayList;
/**
* Represents a constant array of primitives
@@ -13,9 +13,8 @@ public class TypeConAry<A> extends Type {
// One of byte,short,int,long,float,double array
public final A _ary;
- TypeConAry( boolean any, A ary ) { super(TCONARY); _any = any; _ary = ary; }
- private static final TypeConAry TOP = new TypeConAry(true ,null).intern();
- public static final TypeConAry BOT = new TypeConAry(false,null).intern();
+ TypeConAry( boolean any, byte type, A ary ) { super(type); _any = any; _ary = ary; }
+ public static final TypeConAry BOT = new TypeConAry(false, TINT, null).intern();
public static void gather(ArrayList<Type> ts) {
ts.add(BOT);
TypeConAryB.gather(ts);
@@ -23,42 +22,56 @@ public class TypeConAry<A> extends Type {
}
@Override public String str() { return (_any?"~":"") + "[]"; }
- @Override public boolean isConstant() { return true; }
- @Override public TypeConAry dual() {
- if( this== BOT ) return TOP;
- if( this== TOP ) return BOT;
+ @Override TypeConAry xdual() {
+ if( _ary==null )
+ return new TypeConAry(!_any,_type,null);
return this;
}
@Override Type xmeet(Type t) {
+ if( t instanceof TypeInteger ti ) return imeet(ti);
TypeConAry ary = (TypeConAry)t; // Invariant
- if( this==TOP ) return ary ;
- if( ary ==TOP ) return this;
+ if( this==BOT ) return BOT;
+ if( ary ==BOT ) return BOT;
+ if( this==BOT.dual() ) return ary ;
+ if( ary ==BOT.dual() ) return this;
assert _ary!=ary._ary; // Already interned and this!=t
- return BOT;
+ return elem().meet(ary.elem());
+ }
+ Type imeet( TypeInteger ti ) {
+ if( this==BOT.dual() ) return ti;
+ if( this==BOT ) return BOT;
+ Type elem = elem();
+ if( !(elem instanceof TypeInteger) ) return BOTTOM;
+ if( ti.isHigh() && elem.isa(ti.dual()) )
+ return this;
+ return elem.meet(ti);
}
+
+ @Override public boolean isHigh() { return this==TOP; }
+ @Override boolean _isConstant() { return true; }
+
// Meet-over-elements type
public Type elem() {
if( _ary==null )
- return _any ? TOP : BOTTOM;
+ return _any ? Type.TOP : BOTTOM;
int len = len();
long min = Long.MAX_VALUE;
long max = Long.MIN_VALUE;
for( int i=0; i<len; i++ ) {
- min = Math.min(min,at(i));
- max = Math.max(max,at(i));
+ min = Math.min(min,at8(i));
+ max = Math.max(max,at8(i));
}
return TypeInteger.make(min,max);
}
- public long at(int idx) { throw Utils.TODO(); }
+ public long at8(int idx) { throw Utils.TODO(); }
public int len() { throw Utils.TODO(); }
- @Override public int alignment() { return 0; }
+ @Override public int log_size() { throw Utils.TODO(); }
public void write( ByteArrayOutputStream baos ) { throw Utils.TODO(); }
@Override boolean eq(Type t) {
- TypeConAry ary = (TypeConAry)t; // Invariant
- return _any==ary._any && ary._ary==null;
+ return t instanceof TypeConAry ary && _any==ary._any && ary._ary==null;
}
@Override int hash() {
diff --git a/src/main/java/com/seaofnodes/simple/type/TypeConAryB.java b/src/main/java/com/seaofnodes/simple/type/TypeConAryB.java
index c057c6a5..fd2b2635 100644
--- a/src/main/java/com/seaofnodes/simple/type/TypeConAryB.java
+++ b/src/main/java/com/seaofnodes/simple/type/TypeConAryB.java
@@ -5,15 +5,15 @@ import java.util.Arrays;
import java.io.ByteArrayOutputStream;
public class TypeConAryB extends TypeConAry<byte[]> {
- private TypeConAryB(byte[] bs) { super(false,bs); }
+ private TypeConAryB(byte[] bs) { super(false,TINT,bs); }
public static TypeConAryB make( byte[] bs ) { return new TypeConAryB(bs).intern(); }
public static TypeConAryB make( String s ) { return make(s.getBytes()); }
static final TypeConAryB ABC = make("abc");
static final TypeConAryB ABCD = make("abcd");
public static void gather(ArrayList<Type> ts) { ts.add(ABC); ts.add(ABCD); }
- @Override public long at(int idx) { return _ary[idx]; }
+ @Override public long at8(int idx) { return _ary[idx]; }
@Override public int len() { return _ary.length; }
- @Override public int alignment() { return 0; }
+ @Override public int log_size() { return 0; }
@Override public String str() { return "[\""+new String(_ary)+"\"]"; }
@Override boolean eq(Type t) { return Arrays.equals(_ary,((TypeConAryB)t)._ary); }
@Override int hash() { return Arrays.hashCode(_ary); }
diff --git a/src/main/java/com/seaofnodes/simple/type/TypeConAryI.java b/src/main/java/com/seaofnodes/simple/type/TypeConAryI.java
index f888a93d..924e3d73 100644
--- a/src/main/java/com/seaofnodes/simple/type/TypeConAryI.java
+++ b/src/main/java/com/seaofnodes/simple/type/TypeConAryI.java
@@ -4,12 +4,14 @@ import java.util.ArrayList;
import java.util.Arrays;
public class TypeConAryI extends TypeConAry<int[]> {
- private TypeConAryI(int[] bs) { super(false,bs); }
+ private TypeConAryI(int[] bs) { super(false,TINT,bs); }
public static TypeConAryI make( int[] bs ) { return new TypeConAryI(bs).intern(); }
private static final TypeConAryI I123 = make(new int[]{1,2,3});
public static void gather(ArrayList<Type> ts) { ts.add(I123); }
+ @Override public long at8(int idx) { return _ary[idx]; }
+ @Override public int len() { return _ary.length; }
+ @Override public int log_size() { return 2; }
@Override public String str() { return "[i32]"; }
- @Override public int alignment() { return 2; }
@Override boolean eq(Type t) { return Arrays.equals(_ary,((TypeConAryI)t)._ary); }
@Override int hash() { return Arrays.hashCode(_ary); }
}
diff --git a/src/main/java/com/seaofnodes/simple/type/TypeFloat.java b/src/main/java/com/seaofnodes/simple/type/TypeFloat.java
index a0940f8b..f3de581c 100644
--- a/src/main/java/com/seaofnodes/simple/type/TypeFloat.java
+++ b/src/main/java/com/seaofnodes/simple/type/TypeFloat.java
@@ -1,7 +1,8 @@
package com.seaofnodes.simple.type;
-import com.seaofnodes.simple.SB;
-import com.seaofnodes.simple.Utils;
+import com.seaofnodes.simple.util.SB;
+import com.seaofnodes.simple.util.Utils;
+import com.seaofnodes.simple.util.Ary;
import java.util.ArrayList;
/**
@@ -9,30 +10,38 @@ import java.util.ArrayList;
*/
public class TypeFloat extends Type {
- public final static TypeFloat ONE = constant(1.0);
- public final static TypeFloat FZERO = constant(0.0);
- public final static TypeFloat F32 = make(32, 0);
- public final static TypeFloat F64 = make(64, 0);
-
// - high -64, high -32, con 0, low +32, low +64
- public final byte _sz;
+ public byte _sz;
/**
* The constant value or 0
*/
- public final double _con;
+ public double _con;
- private TypeFloat(byte sz, double con) {
- super(TFLT);
- _sz = sz;
- _con = con;
- }
+ private static final Ary<TypeFloat> FREE = new Ary<>(TypeFloat.class);
+ private TypeFloat(byte sz, double con) { super(TFLT); init(sz,con); }
+ private TypeFloat init( byte sz, double con ) { _sz = sz; _con = con; return this; }
+ public static TypeFloat malloc(byte sz, double con) { return FREE.isEmpty() ? new TypeFloat(sz,con) : FREE.pop().init(sz,con); }
private static TypeFloat make(int sz, double con) {
- return new TypeFloat((byte)sz,con).intern();
+ TypeFloat f = malloc((byte)sz,con);
+ TypeFloat t2 = f.intern();
+ return t2==f ? f : t2.free(f);
+ }
+ @Override TypeFloat free(Type t) {
+ TypeFloat f = (TypeFloat)t;
+ f._hash = 0;
+ f._dual=null;
+ FREE.push(f);
+ return this;
}
public static TypeFloat constant(double con) { return make(0, con); }
+ public final static TypeFloat ONE = constant(1.0);
+ public final static TypeFloat FZERO = constant(0.0);
+ public final static TypeFloat F32 = make(32, 0);
+ public final static TypeFloat F64 = make(64, 0);
+
public static void gather(ArrayList<Type> ts) { ts.add(F64); ts.add(F32); ts.add(constant(3.141592653589793)); }
@Override public String str() {
@@ -48,7 +57,6 @@ public class TypeFloat extends Type {
private boolean isF32() { return ((float)_con)==_con; }
@Override public boolean isHigh () { return _sz< 0; }
- @Override public boolean isConstant() { return _sz==0; }
@Override public int log_size() { return _sz==32 || _sz==-32 ? 2 : 3; }
public double value() { return _con; }
@@ -76,13 +84,20 @@ public class TypeFloat extends Type {
}
@Override
- public Type dual() {
- return isConstant() ? this : make(-_sz,0); // Constants are a self-dual
+ TypeFloat xdual() {
+ return _isConstant() ? this : new TypeFloat((byte)-_sz,0); // Constants are a self-dual
}
- @Override public Type makeZero() { return FZERO; }
- @Override public Type glb(boolean mem) { return mem ? (isHigh() ? dual() : this) : F64; }
+ @Override boolean _isGLB(boolean mem) { return _glb(mem)==this; }
+ @Override Type _glb(boolean mem) {
+ if( !mem ) return F64;
+ if( _isConstant() ) return isF32() ? F32 : F64;
+ return isHigh() ? dual() : this;
+ }
+ @Override boolean _isConstant() { return _sz==0; }
+
+ @Override public Type makeZero() { return FZERO; }
@Override
int hash() { return (int)(Double.hashCode(_con) ^ _sz ^ (1<<17)); }
@Override
diff --git a/src/main/java/com/seaofnodes/simple/type/TypeFunPtr.java b/src/main/java/com/seaofnodes/simple/type/TypeFunPtr.java
index abfcf1e3..b21dd451 100644
--- a/src/main/java/com/seaofnodes/simple/type/TypeFunPtr.java
+++ b/src/main/java/com/seaofnodes/simple/type/TypeFunPtr.java
@@ -1,9 +1,9 @@
package com.seaofnodes.simple.type;
-import com.seaofnodes.simple.SB;
-import com.seaofnodes.simple.Utils;
-import java.util.ArrayList;
-import java.util.HashMap;
+import com.seaofnodes.simple.util.SB;
+import com.seaofnodes.simple.util.Utils;
+import com.seaofnodes.simple.util.Ary;
+import java.util.*;
/**
* Represents a Pointer to a function.
@@ -19,86 +19,220 @@ import java.util.HashMap;
*/
public class TypeFunPtr extends TypeNil {
// A TypeFunPtr is Signature and a set of functions.
- public final TypeTuple _sig;
- public final Type _ret;
+ public Type[] _sig;
+ public Type _ret;
+ // TODO:
+ boolean _open; // Extra args are true:BOTTOM, false:TOP
// Cheesy easy implementation for a small set; 1 bit per unique function
- // within the TypeTuple. Can be upgraded to a BitSet for larger classes of
- // functions. Negative means "these 63 concrete bits plus infinite unknown more"
- public final long _fidxs; // 63 unique functions per signature
-
- private TypeFunPtr(byte nil, TypeTuple sig, Type ret, long fidxs) {
- super(TFUNPTR,nil);
+ // within the same Type[]. Can be upgraded to a BitSet for larger classes
+ // of functions. Negative means "these 63 concrete bits plus infinite
+ // unknown more"
+ public long _fidxs; // 63 unique functions per signature
+
+ private static final Ary<TypeFunPtr> FREE = new Ary<>(TypeFunPtr.class);
+ private TypeFunPtr(byte nil, boolean open, Type[] sig, Type ret, long fidxs) { super(TFUNPTR,nil); init(nil,open,sig,ret,fidxs); }
+ private TypeFunPtr init(byte nil, boolean open, Type[] sig, Type ret, long fidxs ) {
assert sig != null;
- _sig = sig;
- _ret = ret;
- _fidxs = fidxs;
+ _nil = nil;
+ _open = open;
+ _sig = sig;
+ _ret = ret;
+ _fidxs= fidxs;
+ return this;
+ }
+ static TypeFunPtr malloc( byte nil, boolean open, Type[] sig, Type ret, long fidxs ) {
+ return FREE.isEmpty() ? new TypeFunPtr(nil,open,sig,ret,fidxs) : FREE.pop().init(nil,open,sig,ret,fidxs);
+ }
+ @Override TypeFunPtr free(Type t) {
+ TypeFunPtr fun = (TypeFunPtr)t;
+ assert !fun.isFree() && !fun._terned;
+ fun._sig = null;
+ fun._ret = null;
+ fun._dual = null;
+ fun._hash = 0;
+ FREE.push(fun);
+ return this;
}
+ @Override boolean isFree() { return _sig==null; }
+
+ // All fields directly listed
+ public static TypeFunPtr make( byte nil, boolean open, Type[] sig, Type ret, long fidxs ) {
+ TypeFunPtr fun = malloc(nil,open,sig,ret,fidxs);
+ TypeFunPtr f2 = fun.intern();
+ if( f2==fun ) return fun;
+ return VISIT.isEmpty() ? f2.free(fun) : f2.delayFree(fun);
+ }
+ public static TypeFunPtr make( boolean nil, boolean open, Type[] sig, Type ret ) { return make((byte)(nil ? 3 : 2),open,sig,ret,-1); }
+
+
+ @Override TypeFunPtr makeFrom( byte nil ) { return nil ==_nil ? this : make( nil,_open,_sig,_ret, _fidxs); }
+ public TypeFunPtr makeFrom( Type ret ) { return ret ==_ret ? this : make( _nil,_open,_sig, ret, _fidxs); }
+ public TypeFunPtr makeFrom( int fidx ) { return make((byte)2, _open, _sig,_ret,1L<<fidx ); }
- public static TypeFunPtr make( byte nil, TypeTuple sig, Type ret, long fidxs ) { return new TypeFunPtr(nil,sig,ret,fidxs).intern(); }
- public static TypeFunPtr make( boolean nil, TypeTuple sig, Type ret ) { return make((byte)(nil ? 3 : 2),sig,ret,-1); }
- @Override TypeFunPtr makeFrom( byte nil ) { return nil ==_nil ? this : make( nil,_sig,_ret, _fidxs); }
- public TypeFunPtr makeFrom( Type ret ) { return ret ==_ret ? this : make( _nil,_sig, ret, _fidxs); }
- public TypeFunPtr makeFrom( int fidx ) { return make((byte)2, _sig,_ret,1L<<fidx ); }
- public static TypeFunPtr BOT = make((byte)3,TypeTuple.BOT,Type.BOTTOM,-1);
- public static TypeFunPtr TEST = make((byte)2,TypeTuple.TEST,TypeInteger.BOT,1);
- public static TypeFunPtr TEST0 = make((byte)3,TypeTuple.TEST,TypeInteger.BOT,3);
- public static TypeFunPtr MAIN = make((byte)3,TypeTuple.MAIN,TypeInteger.BOT,-1);
- public static TypeFunPtr CALLOC= make((byte)3,TypeTuple.CALLOC,TypeMemPtr.BOT,-1);
- public static void gather(ArrayList<Type> ts) { ts.add(TEST); ts.add(TEST0); ts.add(BOT); ts.add(MAIN); }
+ public static final Type[] TEMPTY = new Type[0];
+ static final Type[] TINT = new Type[]{TypeInteger.BOT};
+ static final Type[] TINTMEM = new Type[]{TypeInteger.BOT,TypeFloat.F32};
+ static final Type[] TINTINT = new Type[]{TypeInteger.BOT,TypeInteger.BOT};
+ public static TypeFunPtr BOT = make((byte)3,true ,TEMPTY,Type.BOTTOM,-1);
+ public static TypeFunPtr TEST = make((byte)2,false,TINTMEM,TypeInteger.BOT, 1);
+ public static TypeFunPtr TEST0 = make((byte)3,false,TINTMEM,TypeInteger.BOT, 3);
+ public static TypeFunPtr MAIN = make((byte)3,false,TINT ,Type.BOTTOM,-1); // Main can return anything
+ public static TypeFunPtr CALLOC= make((byte)3,false,TINTINT,TypeMemPtr .BOT,-1);
+ public static void gather(ArrayList<Type> ts) { ts.add(TEST); ts.add(TEST0); ts.add(BOT); ts.add(MAIN);ts.add(CALLOC); }
@Override
Type xmeet(Type t) {
TypeFunPtr that = (TypeFunPtr) t;
- return TypeFunPtr.make(xmeet0(that),(TypeTuple)_sig.meet(that._sig), _ret.meet(that._ret), _fidxs | that._fidxs);
+ // if equal, no matters.
+ // if short is BOT, chop ; recurPre on short.
+ // if short is TOP, copy long; recurPre on long.
+ TypeFunPtr min = _sig.length < that._sig.length ? this : that;
+ if( _sig.length != that._sig.length && (min._open ^ min==this) )
+ return that.xmeet(this);
+ // Recurse all common fields
+ Type[] args = new Type[_sig.length];
+ for( int i=0; i<min._sig.length; i++ )
+ args[i] = _sig[i].meet(that._sig[i]);
+ // Handle extra args
+ for( int i=min._sig.length; i<_sig.length; i++ )
+ args[i] = _sig[i];
+ return make(xmeet0(that),_open | that._open, args, _ret.meet(that._ret), _fidxs | that._fidxs);
+ }
+ static Type[] xmeet( Type[] ts0, Type[] ts1) {
+ if( ts0==ts1 ) return ts0;
+ assert ts0.length==ts1.length;
+ Type[] ts = new Type[ts0.length];
+ for( int i=0; i<ts0.length; i++ )
+ ts[i] = ts0[i].meet(ts1[i]);
+ return ts;
}
- @Override
- public TypeFunPtr dual() { return TypeFunPtr.make(dual0(), _sig.dual(), _ret.dual(), ~_fidxs); }
+ @Override TypeFunPtr xdual() { return malloc(dual0(), !_open, xdual(_sig), _ret.dual(), ~_fidxs); }
+ static Type[] xdual(Type[] ts) {
+ Type[] dual = new Type[ts.length];
+ for( int i=0; i<ts.length; i++ )
+ dual[i] = ts[i].dual();
+ return dual;
+ }
+
+ @Override TypeFunPtr rdual() {
+ if( _dual!=null ) return dual();
+ assert !_terned;
+ Type[] sigs = new Type[_sig.length];
+ TypeFunPtr d = malloc(dual0(),!_open,sigs,null,~_fidxs);
+ (_dual = d)._dual = this; // Cross link duals
+ // Return rdual
+ d._ret = _ret._terned ? _ret.dual() : _ret.rdual();
+ // Signature rdual
+ for( int i=0; i<_sig.length; i++ )
+ sigs[i] = _sig[i]._terned ? _sig[i].dual() : _sig[i].rdual();
+ return d;
+ }
// RHS is NIL; do not deep-dual when crossing the centerline
- @Override public Type meet0() { return _nil==3 ? this : make((byte)3,_sig,_ret,_fidxs); }
+ @Override public Type meet0() { return _nil==3 ? this : make((byte)3,_open,_sig,_ret,_fidxs); }
- @Override public TypeFunPtr glb(boolean mem) { return make((byte)3,_sig,_ret,-1L); }
+ @Override public boolean isHigh() { return _nil <= 1 || (_nil==2 && _fidxs==0); }
- @Override public boolean isHigh () { return _nil <= 1 || (_nil==2 && _fidxs==0); }
- @Override public boolean isConstant() { return (_nil==2 && Long.bitCount(_fidxs)==1) || (_nil==3 && _fidxs==0); }
+ @Override boolean _isConstant() { return (_nil==2 && Long.bitCount(_fidxs)==1) || (_nil==3 && _fidxs==0); }
+
+ @Override boolean _isFinal() { return true; }
+ @Override boolean _isGLB(boolean mem) { return true; }
+ @Override TypeFunPtr _glb(boolean mem) { return this; }
+ @Override TypeFunPtr _close() {
+ Type[] sig = new Type[_sig.length];
+ TypeFunPtr fun = malloc(_nil,false,sig,null,_fidxs);
+ // Now start the recursion
+ fun._ret = _ret._close();
+ for( int i=0; i<sig.length; i++ )
+ sig[i] = _sig[i]._close();
+
+ return fun;
+ }
@Override public int log_size() { return 2; } // (1<<2)==4-byte pointers
- public Type arg(int i) { return _sig._types[i]; }
+ public Type arg(int i) { return _sig[i]; }
public long fidxs() { return _fidxs; }
public Type ret() { return _ret; }
- public int nargs() { return _sig._types.length; }
+ public int nargs() { return _sig.length; }
public int fidx() { assert Long.bitCount(_fidxs)==1; return Long.numberOfTrailingZeros(_fidxs); }
+
+ @Override int nkids() { return _sig.length+1; }
+ @Override Type at( int idx ) {
+ return idx == _sig.length ? _ret : _sig[idx];
+ }
+ @Override void set( int idx, Type t ) {
+ if( idx == _sig.length ) _ret = t;
+ else _sig[idx] = t;
+ }
+
@Override
- int hash() { return Utils.fold(_sig.hashCode() ^ _ret.hashCode() ^ _fidxs ^ super.hash()); }
+ int hash() {
+ long hash = _ret.hashCode() ^ _fidxs ^ super.hash();
+ for( Type arg : _sig )
+ hash = hash*19 ^ arg.hashCode();
+ return Utils.fold(hash);
+ }
@Override
boolean eq(Type t) {
- TypeFunPtr ptr = (TypeFunPtr)t; // Invariant
- return _sig == ptr._sig && _ret == ptr._ret && _fidxs == ptr._fidxs && super.eq(ptr);
+ // Recursive; so use cyclic equals
+ if( !VISIT.isEmpty() ) {
+ assert TypeStruct.CEQUALS.isEmpty();
+ boolean rez = cycle_eq(t);
+ TypeStruct.CEQUALS.clear();
+ return rez;
+ }
+ TypeFunPtr fun = (TypeFunPtr)t; // Invariant
+ if( !super.eq(fun) || _open != fun._open || _fidxs != fun._fidxs || _sig.length != fun._sig.length ) return false;
+ if( _sig == fun._sig && _ret == fun._ret ) return true;
+
+ if( !_ret.eq(fun._ret) ) return false;
+ for( int i = 0; i < _sig.length; i++ )
+ if( !_sig[i].eq(fun._sig[i]) )
+ return false;
+ return true;
+ }
+ @Override boolean cycle_eq(Type t) {
+ if( t._type != TFUNPTR ) return false;
+ TypeFunPtr fun = (TypeFunPtr)t; // Invariant
+ if( !super.eq(fun) || _open != fun._open || _fidxs != fun._fidxs || _sig.length != fun._sig.length ) return false;
+ if( _sig == fun._sig && _ret == fun._ret ) return true;
+
+ // Check to see if we've ever compared this pair of types before;
+ // if so, then assume the cycle is equal here.
+ int pid = pid(fun);
+ if( TypeStruct.CEQUALS.find(pid)!= -1 ) return true;
+ TypeStruct.CEQUALS.push(pid);
+ if( !_ret.cycle_eq(fun._ret) ) return false;
+ for( int i = 0; i < _sig.length; i++ )
+ if( !_sig[i].cycle_eq(fun._sig[i]) )
+ return false;
+ return true;
}
- @Override public String str() { return print(new SB()).toString(); }
- @Override public SB print(SB sb) { return _print(sb,false,true); }
- public SB print(SB sb, boolean n) { return _print(sb,false,n); }
- @Override public SB gprint(SB sb) { return _print(sb,true ,true); }
- private static SB _print(SB sb, boolean g, Type t) { return g ? t.gprint(sb) : t.print(sb); }
- private SB _print(SB sb, boolean g, boolean n) {
+ @Override public String str() { return "{"+printFIDX()+"}"; }
+
+ SB _print(SB sb, BitSet visit, boolean html ) {
sb.p(x()).p("{ ");
- if( _sig._types!=null )
- for( Type t : _sig._types )
- _print(sb,g,t).p(" ");
- _print(sb.p(g ? "&rarr; " : "-> "),g,_ret).p(" #");
- if( isHigh() ) sb.p("~");
+ if( _sig!=null )
+ for( Type t : _sig )
+ sb.p(t.str()).p(" "); // Short form in signature
+ _ret.print(sb.p(html ? "&rarr; " : "-> "),visit,html).p(" #");
+ // Print fidxs
+ return sb.p(printFIDX()).p("}").p(q());
+ }
+ String printFIDX() {
+ String tilde = isHigh() ? "~" : "";
long fidxs = isHigh() ? ~_fidxs : _fidxs;
String fidx = fidxs==0 ? ""
: Long.bitCount(fidxs) == 1 ? ""+Long.numberOfTrailingZeros(fidxs)
: fidxs == -1 ? "ALL"
: "b"+Long.toBinaryString(fidxs); // Just some function bits
- return sb.p(fidx).p("}").p(q());
+ return tilde+fidx;
}
// Usage: for( long fidxs=fidxs(); fidxs!=0; fidxs=nextFIDX(fidxs) { int fidxs = Long.numberOfTrailingZeros(fidxs); ... }
diff --git a/src/main/java/com/seaofnodes/simple/type/TypeInteger.java b/src/main/java/com/seaofnodes/simple/type/TypeInteger.java
index 59378ef3..99f237a9 100644
--- a/src/main/java/com/seaofnodes/simple/type/TypeInteger.java
+++ b/src/main/java/com/seaofnodes/simple/type/TypeInteger.java
@@ -1,24 +1,54 @@
package com.seaofnodes.simple.type;
-import com.seaofnodes.simple.SB;
-import com.seaofnodes.simple.Utils;
+import com.seaofnodes.simple.util.Ary;
+import com.seaofnodes.simple.util.SB;
+import com.seaofnodes.simple.util.Utils;
import java.util.ArrayList;
/**
* Integer Type
*/
public class TypeInteger extends Type {
+ /**
+ * Describes an integer *range* - everything from min to max; both min and
+ * max are inclusive. If min==max, this is a constant.
+ * <br>
+ * If min <= max, this is a below center (towards bottom).
+ * If min > max, this is an above center (towards top).
+ */
+ public long _min, _max;
+
+ private static final Ary<TypeInteger> FREE = new Ary<>(TypeInteger.class);
+ private TypeInteger(long min, long max) { super(TINT); init(min,max); }
+ private TypeInteger init(long min, long max) { _min = min; _max = max; return this; }
+ public static TypeInteger malloc(long lo, long hi) { return FREE.isEmpty() ? new TypeInteger(lo,hi) : FREE.pop().init(lo,hi); }
+ public static TypeInteger make(long lo, long hi) {
+ TypeInteger i = malloc(lo,hi);
+ TypeInteger t2 = i.intern();
+ return t2==i ? i : t2.free(i);
+ }
+ @Override TypeInteger free(Type t) {
+ TypeInteger i = (TypeInteger)t;
+ i._min = i._max = 0;
+ i._hash = 0;
+ i._dual = null;
+ FREE.push(i);
+ return this;
+ }
+
+ public static TypeInteger constant(long con) { return make(con, con); }
public final static TypeInteger ZERO= make(0,0);
public final static TypeInteger FALSE=ZERO;
public final static TypeInteger TRUE= make(1,1);
+ public final static TypeInteger TWO = make(2,2); // Shows up in some Simple tests as the starting argument
public final static TypeInteger I1 = make(-1,0);
public final static TypeInteger I8 = make(-128,127);
public final static TypeInteger I16 = make(-32768,32767);
public final static TypeInteger I32 = make(-1L<<31,(1L<<31)-1);
public final static TypeInteger BOT = make(Long.MIN_VALUE,Long.MAX_VALUE);
- public final static TypeInteger TOP = BOT.dual();
+ public final static TypeInteger TOP = (TypeInteger)BOT.dual();
public final static TypeInteger U1 = make(0,1);
public final static TypeInteger BOOL= U1;
@@ -26,30 +56,10 @@ public class TypeInteger extends Type {
public final static TypeInteger U16 = make(0,65535);
public final static TypeInteger U32 = make(0,(1L<<32)-1);
- /**
- * Describes an integer *range* - everything from min to max; both min and
- * max are inclusive. If min==max, this is a constant.
- * <br>
- * If min <= max, this is a below center (towards bottom).
- * If min > max, this is an above center (towards top).
- */
- public final long _min, _max;
-
- private TypeInteger(long min, long max) {
- super(TINT);
- _min = min;
- _max = max;
- }
-
- // Strict non-zero contract
- public static TypeInteger make(long lo, long hi) { return new TypeInteger(lo,hi).intern(); }
-
- public static TypeInteger constant(long con) { return make(con, con); }
-
public static void gather(ArrayList<Type> ts) { ts.add(I32); ts.add(BOT); ts.add(U1); ts.add(I1); ts.add(U8); }
@Override public String str() {
- if( isConstant() ) return ""+_min;
+ if( _isConstant() ) return ""+_min;
long lo = _min, hi = _max;
String x = "";
if( hi < lo ) {
@@ -59,7 +69,7 @@ public class TypeInteger extends Type {
return x+_str(lo,hi);
}
private static String _str(long lo, long hi) {
- if( lo==Long.MIN_VALUE && hi==Long.MAX_VALUE ) return "int";
+ if( lo==Long.MIN_VALUE && hi==Long.MAX_VALUE ) return "i64";
if( lo== 0 && hi== 1 ) return "bool";
if( lo== -1 && hi== 0 ) return "i1";
if( lo== -128 && hi== 127 ) return "i8";
@@ -72,7 +82,6 @@ public class TypeInteger extends Type {
}
@Override public boolean isHigh () { return _min > _max; }
- @Override public boolean isConstant() { return _min == _max; }
@Override public int log_size() {
if( isHigh() ) return 0; // High types are dead, and should never hit code emission.
@@ -110,12 +119,15 @@ public class TypeInteger extends Type {
@Override
public Type xmeet(Type other) {
+ if( other instanceof TypeConAry ary ) return ary.imeet(this);
// Invariant from caller: 'this' != 'other' and same class (TypeInteger)
TypeInteger i = (TypeInteger)other; // Contract
return make(Math.min(_min,i._min), Math.max(_max,i._max));
}
- @Override public TypeInteger dual() { return make(_max,_min); }
+ @Override TypeInteger xdual() {
+ return _min==_max ? this : malloc(_max,_min);
+ }
@Override public TypeInteger nonZero() {
if( isHigh() ) return this;
@@ -125,10 +137,17 @@ public class TypeInteger extends Type {
return this;
}
@Override public Type makeZero() { return ZERO; }
- @Override public Type glb(boolean mem) { return mem ? (isHigh() ? dual() : this) : BOT; }
+ @Override boolean _isConstant() { return _min == _max; }
+ @Override boolean _isGLB(boolean mem) { return _glb(mem)==this; }
+ @Override Type _glb(boolean mem) {
+ if( !mem ) return BOT;
+ // GLB is not well-defined in memory; depends on the size of the memory field
+ if( _isConstant() ) return BOT;
+ return isHigh() ? dual() : this;
+ }
+
@Override int hash() { return Utils.fold(_min) * Utils.fold(_max); }
@Override public boolean eq( Type t ) {
- TypeInteger i = (TypeInteger)t; // Contract
- return _min==i._min && _max==i._max;
+ return t instanceof TypeInteger i && _min==i._min && _max==i._max;
}
}
diff --git a/src/main/java/com/seaofnodes/simple/type/TypeMem.java b/src/main/java/com/seaofnodes/simple/type/TypeMem.java
index 63fb30ce..99b19c75 100644
--- a/src/main/java/com/seaofnodes/simple/type/TypeMem.java
+++ b/src/main/java/com/seaofnodes/simple/type/TypeMem.java
@@ -1,10 +1,10 @@
package com.seaofnodes.simple.type;
-import com.seaofnodes.simple.SB;
-import com.seaofnodes.simple.Utils;
-import java.lang.Long;
-import java.util.BitSet;
+import com.seaofnodes.simple.util.Ary;
+import com.seaofnodes.simple.util.SB;
+import com.seaofnodes.simple.util.Utils;
import java.util.ArrayList;
+import java.util.BitSet;
/**
@@ -13,24 +13,44 @@ import java.util.ArrayList;
public class TypeMem extends Type {
// Which slice of memory?
- // 0 means TOP, no slice.
- // 0 means BOT, all memory.
- // N means slice#N.
- public final int _alias;
- public final Type _t; // Memory contents, some scalar type
-
- private TypeMem(int alias, Type t) {
- super(TMEM);
- assert alias!=0 || (t==Type.TOP || t==Type.BOTTOM);
+ // 1 and TOP means no slice.
+ // 1 and BOT means all memory.
+ // N means alias slice#N.
+ public int _alias;
+ public Type _t; // Memory contents, some scalar type
+
+ private static final Ary<TypeMem> FREE = new Ary<>(TypeMem.class);
+ private TypeMem(int alias, Type t) { super(TMEM); init(alias,t); }
+ private TypeMem init(int alias, Type t) {
+ assert alias>1 || (t==Type.TOP || t==Type.BOTTOM);
_alias = alias;
_t = t;
+ return this;
+ }
+ @Override TypeMem free(Type t) {
+ TypeMem mem = (TypeMem)t;
+ mem._alias= -99;
+ mem._dual = null;
+ mem._hash = 0;
+ FREE.push(mem);
+ return this;
+ }
+ @Override boolean isFree() { return _alias == -99; }
+
+ public static TypeMem malloc(int alias, Type t) {
+ return FREE.isEmpty() ? new TypeMem(alias,t) : FREE.pop().init(alias,t);
+ }
+ public static TypeMem make(int alias, Type t) {
+ TypeMem f = malloc(alias,t);
+ TypeMem f2 = f.intern();
+ if( f2==f ) return f;
+ return VISIT.isEmpty() ? f2.free(f) : f2.delayFree(f);
}
- public static TypeMem make(int alias, Type t) { return new TypeMem(alias,t).intern(); }
- public static final TypeMem TOP = make(0, Type.TOP );
- public static final TypeMem BOT = make(0, Type.BOTTOM);
+ public static final TypeMem TOP = make(1, Type.TOP );
+ public static final TypeMem BOT = make(1, Type.BOTTOM);
- public static void gather(ArrayList<Type> ts) { ts.add(make(1,Type.NIL)); ts.add(make(1,TypeInteger.ZERO)); ts.add(BOT); }
+ public static void gather(ArrayList<Type> ts) { ts.add(make(2,Type.NIL)); ts.add(make(2,TypeInteger.ZERO)); ts.add(BOT); }
@Override
TypeMem xmeet(Type t) {
@@ -39,19 +59,28 @@ public class TypeMem extends Type {
if( that==TOP ) return this;
if( this==BOT ) return BOT;
if( that==BOT ) return BOT;
- int alias = _alias==that._alias ? _alias : 0;
+ int alias = _alias==that._alias ? _alias : 1;
Type mt = _t.meet(that._t);
return make(alias,mt);
}
@Override
- public Type dual() {
- return make(_alias,_t.dual());
+ Type xdual() { return _t._dual==_t ? this : malloc(_alias,_t.dual()); }
+
+ @Override TypeMem rdual() {
+ if( _dual!=null ) return dual();
+ assert !_terned;
+ TypeMem d = malloc(_alias,null);
+ (_dual = d)._dual = this; // Cross link duals
+ d._t = _t._terned ? _t.dual() : _t.rdual();
+ return d;
}
@Override public boolean isHigh() { return _t.isHigh(); }
@Override public int log_size() { throw Utils.TODO(); }
- @Override public Type glb(boolean mem) { return make(_alias,_t.glb(true)); }
+ @Override boolean _isFinal() { return _t._isFinal(); }
+ @Override boolean _isGLB(boolean mem) { return _t._isGLB(true); }
+ @Override public Type _glb(boolean mem) { return make(_alias,_t._glb(true)); }
@Override int hash() { return 9876543 + _alias + _t.hashCode(); }
@@ -60,15 +89,19 @@ public class TypeMem extends Type {
return _alias == that._alias && _t == that._t;
}
- @Override public SB print(SB sb) {
- sb.p("#");
- if( _alias==0 ) return sb.p(_t._type==TTOP ? "TOP" : "BOT");
- return _t.print(sb.p(_alias).p(":"));
+ @Override boolean cycle_eq(Type t) {
+ TypeMem that = (TypeMem) t; // Invariant
+ return _alias == that._alias && _t.cycle_eq(that._t);
}
- @Override public SB gprint(SB sb) {
+
+ @Override int nkids() { return 1; }
+ @Override Type at( int idx ) { return _t; }
+ @Override void set( int idx, Type t ) { _t = t; }
+
+ @Override public SB _print(SB sb, BitSet visit, boolean html) {
sb.p("#");
if( _alias==0 ) return sb.p(_t._type==TTOP ? "TOP" : "BOT");
- return _t.gprint(sb.p(_alias).p(":"));
+ return _t.print(sb.p(_alias).p(":"),visit,html);
}
@Override public String str() { return toString(); }
diff --git a/src/main/java/com/seaofnodes/simple/type/TypeMemPtr.java b/src/main/java/com/seaofnodes/simple/type/TypeMemPtr.java
index 78605e81..6041155d 100644
--- a/src/main/java/com/seaofnodes/simple/type/TypeMemPtr.java
+++ b/src/main/java/com/seaofnodes/simple/type/TypeMemPtr.java
@@ -1,8 +1,9 @@
package com.seaofnodes.simple.type;
-import com.seaofnodes.simple.SB;
-import com.seaofnodes.simple.Utils;
-import java.util.ArrayList;
+import com.seaofnodes.simple.util.Ary;
+import com.seaofnodes.simple.util.SB;
+import com.seaofnodes.simple.util.Utils;
+import java.util.*;
/**
* Represents a Pointer to memory.
@@ -24,16 +25,35 @@ public class TypeMemPtr extends TypeNil {
// (BOT ,false) - a not-nil void* (unspecified struct)
// (TOP ,true ) - a nil
- public final TypeStruct _obj;
- public final boolean _one; // Singleton instance
+ public TypeStruct _obj;
+ public boolean _one; // Singleton instance
- private TypeMemPtr(byte nil, TypeStruct obj, boolean singleton) {
- super(TMEMPTR,nil);
- assert obj!=null;
- _obj = obj;
- _one = singleton;
+ private static final Ary<TypeMemPtr> FREE = new Ary<>(TypeMemPtr.class);
+ private TypeMemPtr(byte nil, TypeStruct obj, boolean one) { super(TMEMPTR,nil); init(nil,obj,one); }
+ private TypeMemPtr init(byte nil, TypeStruct obj, boolean one) { _nil=nil; _obj=obj; _one=one; return this; }
+ // Return a filled-in TypeMemPtr; either from free list or alloc new.
+ private static TypeMemPtr malloc(byte nil, TypeStruct obj, boolean one) {
+ return FREE.isEmpty() ? new TypeMemPtr(nil,obj,one) : FREE.pop().init(nil,obj,one);
}
- public static TypeMemPtr make(byte nil, TypeStruct obj, boolean one) { return new TypeMemPtr(nil, obj, one).intern(); }
+
+ // All fields directly listed
+ public static TypeMemPtr make(byte nil, TypeStruct obj, boolean one) {
+ TypeMemPtr tmp = malloc(nil, obj, one);
+ TypeMemPtr t2 = tmp.intern();
+ if( t2==tmp ) return tmp;
+ return VISIT.isEmpty() ? t2.free(tmp) : t2.delayFree(tmp);
+ }
+ @Override TypeMemPtr free(Type t) {
+ TypeMemPtr tmp = (TypeMemPtr)t;
+ tmp._nil = -99;
+ tmp._obj = null;
+ tmp._dual = null;
+ tmp._hash = 0;
+ FREE.push(tmp);
+ return this;
+ }
+ @Override boolean isFree() { return _obj==null; }
+
static TypeMemPtr make(byte nil, TypeStruct obj) { return make(nil, obj, false); }
public static TypeMemPtr make (TypeStruct obj) { return make((byte)2, obj); }
public static TypeMemPtr makeNullable(TypeStruct obj) { return make((byte)3, obj); }
@@ -41,8 +61,6 @@ public class TypeMemPtr extends TypeNil {
public TypeMemPtr makeFrom(TypeStruct obj) { return obj==_obj ? this : make(_nil, obj, _one); }
public TypeMemPtr makeNullable() { return makeFrom((byte)3); }
@Override TypeMemPtr makeFrom(byte nil) { return nil==_nil ? this : make(nil, _obj, _one); }
- @Override public TypeMemPtr makeRO() { return makeFrom(_obj.makeRO()); }
- @Override public boolean isFinal() { return _obj.isFinal(); }
// An abstract pointer, pointing to either a Struct or an Array.
// Can also be null or not, so 4 choices {TOP,BOT} x {nil,not}
@@ -56,16 +74,32 @@ public class TypeMemPtr extends TypeNil {
@Override
public TypeNil xmeet(Type t) {
TypeMemPtr that = (TypeMemPtr) t;
+ assert !isFree() && !that.isFree();
return make(xmeet0(that), (TypeStruct)_obj.meet(that._obj), _one & that._one);
}
@Override
- public TypeMemPtr dual() { return make( dual0(), _obj.dual(), !_one); }
+ TypeMemPtr xdual() { return malloc( dual0(), _obj.dual(), _one); }
+
+ @Override TypeMemPtr rdual() {
+ if( _dual!=null ) return dual();
+ assert !_terned;
+ TypeMemPtr d = malloc(dual0(), null, _one);
+ (_dual = d)._dual = this; // Cross link duals
+ d._obj = _obj._terned ? _obj.dual() : _obj.rdual();
+ return d;
+ }
- // RHS is NIL; do not deep-dual when crossing the centerline
+ // RHS is NIL; do not deep-dual when crossing the center line
@Override Type meet0() { return _nil==3 ? this : make((byte)3,_obj); }
- @Override public boolean isConstant() { return _one && _obj.isConstant(); }
+ @Override boolean _isConstant() { return _one && _obj._isConstant(); }
+ @Override boolean _isFinal() { return _obj._isFinal(); }
+ @Override TypeMemPtr _makeRO() { return makeFrom(_obj._makeRO()); }
+ @Override boolean _isGLB(boolean mem) { return _obj.isGLB2(); }
+ @Override TypeMemPtr _glb(boolean mem) { return make((byte)3,_obj.glb2()); }
+ @Override TypeMemPtr _close() { return makeFrom(_obj._close()); }
+
// True if this "isa" t up to named structures
@Override public boolean shallowISA( Type t ) {
@@ -78,7 +112,6 @@ public class TypeMemPtr extends TypeNil {
throw Utils.TODO(); // return _obj.shallowISA(that._obj);
}
- @Override public TypeMemPtr glb(boolean mem) { return make((byte)3,_obj.glb(true)); }
// Is forward-reference
@Override public boolean isFRef() { return _obj.isFRef(); }
@@ -88,8 +121,17 @@ public class TypeMemPtr extends TypeNil {
@Override boolean eq(Type t) {
TypeMemPtr ptr = (TypeMemPtr)t; // Invariant
- return _obj == ptr._obj && _one == ptr._one && super.eq(ptr);
+ return super.eq(ptr) && _one == ptr._one && _obj == ptr._obj;
}
+ @Override boolean cycle_eq(Type t) {
+ if( t._type != TMEMPTR ) return false;
+ TypeMemPtr ptr = (TypeMemPtr)t; // Invariant
+ return super.eq(ptr) && _one == ptr._one && _obj.cycle_eq(ptr._obj);
+ }
+
+ @Override int nkids() { return 1; }
+ @Override Type at( int idx ) { return _obj; }
+ @Override void set( int idx, Type t ) { _obj = (TypeStruct)t; }
@Override public String str() {
if( this== NOTBOT) return "*void";
@@ -97,14 +139,9 @@ public class TypeMemPtr extends TypeNil {
return x()+"*"+_obj.str()+q();
}
- @Override public SB print(SB sb) {
- if( this== NOTBOT) return sb.p("*void");
- if( this== BOT) return sb.p("*void?");
- return _obj.print(sb.p(x()).p("*")).p(q());
- }
- @Override public SB gprint(SB sb) {
+ @Override SB _print(SB sb, BitSet visit, boolean html ) {
if( this== NOTBOT) return sb.p("*void");
if( this== BOT) return sb.p("*void?");
- return _obj.gprint(sb.p(x()).p("*")).p(q());
+ return _obj.print(sb.p(x()).p("*"),visit,html).p(q());
}
}
diff --git a/src/main/java/com/seaofnodes/simple/type/TypeNil.java b/src/main/java/com/seaofnodes/simple/type/TypeNil.java
index 3902c40b..56d73b00 100644
--- a/src/main/java/com/seaofnodes/simple/type/TypeNil.java
+++ b/src/main/java/com/seaofnodes/simple/type/TypeNil.java
@@ -1,7 +1,7 @@
package com.seaofnodes.simple.type;
-import com.seaofnodes.simple.SB;
-import com.seaofnodes.simple.Utils;
+import com.seaofnodes.simple.util.SB;
+import com.seaofnodes.simple.util.Utils;
import java.util.ArrayList;
/**
@@ -12,7 +12,7 @@ public abstract class TypeNil extends Type {
// 1 = high-subclass no nil
// 2 = low -subclass no nil
// 3 = low -subclass also nil
- final byte _nil;
+ byte _nil;
TypeNil(byte t, byte nil ) { super(t); _nil = nil; }
@@ -45,18 +45,18 @@ public abstract class TypeNil extends Type {
}
@Override public boolean isHigh () { return _nil <= 1; }
- @Override public boolean isConstant () { return false; }
@Override public boolean isHighOrConst() { return isHigh() || isConstant(); }
- @Override public Type glb(boolean mem) { return Type.NIL; }
-
public boolean notNull() { return _nil==1 || _nil==2; }
public boolean nullable() { return _nil==3; }
+ @Override boolean _isConstant() { return false; }
+ @Override Type _glb(boolean mem) { return Type.NIL; }
+
final String q() { return _nil == 1 || _nil == 2 ? "" : "?"; }
final String x() { return isHigh() ? "~" : ""; }
int hash() { return _nil<<17; }
- boolean eq(TypeNil ptr) { return _nil == ptr._nil; }
+ @Override boolean eq(Type ptr) { return ptr instanceof TypeNil nil && _nil ==nil._nil; }
}
diff --git a/src/main/java/com/seaofnodes/simple/type/TypePtr.java b/src/main/java/com/seaofnodes/simple/type/TypePtr.java
index d9de5cd7..75478119 100644
--- a/src/main/java/com/seaofnodes/simple/type/TypePtr.java
+++ b/src/main/java/com/seaofnodes/simple/type/TypePtr.java
@@ -1,13 +1,15 @@
package com.seaofnodes.simple.type;
-import com.seaofnodes.simple.SB;
-import com.seaofnodes.simple.Utils;
+import com.seaofnodes.simple.util.SB;
+import com.seaofnodes.simple.util.Utils;
import java.util.ArrayList;
+import java.util.BitSet;
/**
* Represents a Scalar; a single register-sized value.
*/
public class TypePtr extends TypeNil {
+ private static final String[] STRS = new String[]{"~ptr","~nptr","nptr","ptr"};
private TypePtr(byte nil) { super(TPTR,nil); }
@@ -15,8 +17,8 @@ public class TypePtr extends TypeNil {
// Can also be null or not, so 4 choices {TOP,BOT} x {nil,not}
public static TypePtr XPTR = new TypePtr((byte)0).intern();
public static TypePtr XNPTR= new TypePtr((byte)1).intern();
- public static TypePtr NPTR = new TypePtr((byte)2).intern();
- public static TypePtr PTR = new TypePtr((byte)3).intern();
+ public static TypePtr NPTR = (TypePtr)XNPTR.dual();
+ public static TypePtr PTR = (TypePtr)XPTR.dual();
private static final TypePtr[] PTRS = new TypePtr[]{XPTR,XNPTR,NPTR,PTR};
public static void gather(ArrayList<Type> ts) { ts.add(PTR); ts.add(NPTR); }
@@ -28,7 +30,7 @@ public class TypePtr extends TypeNil {
return PTRS[xmeet0(that)];
}
- @Override public TypePtr dual() { return PTRS[dual0()]; }
+ @Override TypePtr xdual() { return new TypePtr((byte)(3-_nil)); }
// High scalar loses, low scalar wins
@Override TypeNil nmeet(TypeNil tn) {
@@ -45,9 +47,9 @@ public class TypePtr extends TypeNil {
// 0->xscalar, 1->nscalar, 2->nscalar, 3->scalar
@Override Type meetX() { return _nil==0 ? XNIL : (_nil==3 ? PTR : NPTR); }
- @Override public TypePtr glb(boolean mem) { return PTR; }
+ boolean _isGLB(boolean mem) { return this==PTR; }
+ @Override TypePtr _glb(boolean mem) { return PTR; }
- private static final String[] STRS = new String[]{"~ptr","~nptr","nptr","ptr"};
@Override public String str() { return STRS[_nil]; }
- @Override public SB print(SB sb) { return sb.p(str()); }
+ @Override public SB _print(SB sb, BitSet visit, boolean html) { return sb.p(str()); }
}
diff --git a/src/main/java/com/seaofnodes/simple/type/TypeRPC.java b/src/main/java/com/seaofnodes/simple/type/TypeRPC.java
index ec2f5f0a..bd5e2923 100644
--- a/src/main/java/com/seaofnodes/simple/type/TypeRPC.java
+++ b/src/main/java/com/seaofnodes/simple/type/TypeRPC.java
@@ -1,7 +1,7 @@
package com.seaofnodes.simple.type;
-import com.seaofnodes.simple.SB;
-import com.seaofnodes.simple.Utils;
+import com.seaofnodes.simple.util.SB;
+import com.seaofnodes.simple.util.Utils;
import java.util.ArrayList;
import java.util.BitSet;
import java.util.HashSet;
@@ -48,10 +48,6 @@ public class TypeRPC extends Type {
return "$["+(_any ? "-" : "")+_rpcs+"]";
}
- @Override public boolean isConstant() {
- return !_any && _rpcs.size()==1;
- }
-
@Override
public TypeRPC xmeet(Type other) {
TypeRPC rpc = (TypeRPC)other;
@@ -87,7 +83,10 @@ public class TypeRPC extends Type {
}
@Override
- public Type dual() { return make(!_any,_rpcs); }
+ Type xdual() { return new TypeRPC(!_any,_rpcs); }
+
+ @Override boolean _isConstant() { return !_any && _rpcs.size()==1; }
+ @Override boolean _isGLB(boolean mem) { return true; }
@Override
int hash() { return _rpcs.hashCode() ^ (_any ? -1 : 0) ; }
diff --git a/src/main/java/com/seaofnodes/simple/type/TypeStruct.java b/src/main/java/com/seaofnodes/simple/type/TypeStruct.java
index 66a37d41..73fecdab 100644
--- a/src/main/java/com/seaofnodes/simple/type/TypeStruct.java
+++ b/src/main/java/com/seaofnodes/simple/type/TypeStruct.java
@@ -1,8 +1,8 @@
package com.seaofnodes.simple.type;
-import com.seaofnodes.simple.SB;
-import com.seaofnodes.simple.Utils;
-import java.util.ArrayList;
+import com.seaofnodes.simple.codegen.CodeGen;
+import com.seaofnodes.simple.util.*;
+import java.util.*;
/**
* Represents a struct type.
@@ -11,69 +11,129 @@ public class TypeStruct extends Type {
// A Struct has a name and a set of fields; the fields themselves have
// names, types and aliases. The name has no semantic meaning, but is
- // useful for debugging. Briefly during parsing a Struct can be a
- // forward-ref; in this case the _fields array is null.
-
- // Its illegal to attempt to load a field from a forward-ref struct.
-
- // Example: "int rez = new S.x; struct S { int x; } return rez;" // Error, S not defined
- // Rewrite: "struct S { int x; } int rez = new S.x; return rez;" // Ok, no forward ref
- //
- // During the normal optimization run, struct types "bottom out" at further
- // struct references, so we don't have to handle e.g. cyclic types. The
- // "bottom out" is again the forward-ref struct.
- public final String _name;
- public final Field[] _fields;
- public final TypeConAry _con; // Optional, constant array contents
-
- private TypeStruct(String name, TypeConAry con, Field[] fields) {
+ // useful for debugging.
+
+ // During parsing a mid-declaration struct is flagged as a "open". It is
+ // treated as having infinite fields with correct name and type BOTTOM.
+
+ public String _name; // Struct name
+ public boolean _open; // infinite fields are all true:BOTTOM, false:TOP
+ public Field[] _fields;
+
+ private TypeStruct(String name, boolean open, Field[] fields) {
super(TSTRUCT);
_name = name;
+ _open = open;
_fields = fields;
- _con = con;
}
+ private static final Ary<TypeStruct> FREE = new Ary<>(TypeStruct.class);
+ // Return a filled-in TypeStruct; either from free list or alloc new.
+ private static TypeStruct malloc(String name, boolean open, Field[] fields) {
+ if( FREE.isEmpty() ) return new TypeStruct(name,open,fields);
+ TypeStruct ts = FREE.pop();
+ assert ts.isFree();
+ ts._name = name;
+ ts._open = open;
+ ts._fields = fields;
+ return ts;
+ }
+ // Free ts; return this.
+ @Override TypeStruct free(Type t) {
+ TypeStruct ts = (TypeStruct)t;
+ assert !ts.isFree() && !ts._terned;
+ ts._fields = null;
+ ts._offs = null;
+ ts._dual = null;
+ ts._hash = 0;
+ FREE.push(ts);
+ return this;
+ }
+ @Override boolean isFree() { return _fields==null; }
+
+
// All fields directly listed
- public static TypeStruct make(String name, TypeConAry con, Field... fields) { return new TypeStruct(name, con, fields).intern(); }
- public static TypeStruct make(String name, Field... fields) { return make(name, TypeConAry.BOT, fields); }
- public static final TypeStruct TOP = make("$TOP",new Field[0]);
- public static final TypeStruct BOT = make("$BOT",new Field[0]);
- public static final TypeStruct TEST = make("test",new Field[]{Field.TEST});
- // Forward-ref version
- public static TypeStruct makeFRef(String name) { return make(name, (Field[])null); }
- // Make a read-only version
- @Override public TypeStruct makeRO() {
- if( isFinal() ) return this;
- Field[] flds = new Field[_fields.length];
- for( int i=0; i<flds.length; i++ )
- flds[i] = _fields[i].makeRO();
- return make(_name,flds);
+ public static TypeStruct make(String name, boolean open, Field... fields) {
+ TypeStruct ts = malloc(name, open, fields);
+ TypeStruct t2 = ts.intern();
+ if( t2==ts ) return ts;
+ return VISIT.isEmpty() ? t2.free(ts) : ts.delayFree(ts);
}
+ // New open struct with no fields
+ public static TypeStruct open( String name ) { return make(name,true); }
// Array
- public static TypeStruct makeAry(String name, TypeInteger len, int lenAlias, Type body, int bodyAlias) {
- return makeAry(name,len,lenAlias,body,bodyAlias,false,TypeConAry.BOT);
+ public static TypeStruct makeAry(String name, TypeInteger len, int lenAlias, Type body, int bodyAlias, boolean efinal) {
+ return make(name,false,
+ Field.make("#" ,len , lenAlias,true ,false),
+ Field.make("[]",body,bodyAlias,efinal,false));
}
- public static TypeStruct makeAry(String name, TypeInteger len, int lenAlias, Type body, int bodyAlias, boolean efinal, TypeConAry con) {
- assert body instanceof TypeInteger || body instanceof TypeFloat || (body instanceof TypeNil tn && tn.nullable());
- assert efinal || con==TypeConAry.BOT; // No mutable constant arrays
- return make(name,
- con,
- Field.make("#" ,len , lenAlias,true ),
- Field.make("[]",body,bodyAlias,efinal));
+
+ public TypeStruct add( Field f ) {
+ assert _open && find(f._fname)==-1; // No double field names
+ Field[] flds = Arrays.copyOf(_fields,_fields.length+1);
+ flds[_fields.length] = f;
+ return make(_name,true,flds);
+ }
+ public TypeStruct replace( Field f ) {
+ assert !_open;
+ Field[] flds = Arrays.copyOf(_fields,_fields.length);
+ flds[find(f._fname)] = f;
+ return make(_name,false,flds);
}
- // A pair of self-cyclic types
- private static final TypeStruct S1F = makeFRef("S1");
- private static final TypeStruct S2F = makeFRef("S2");
- public static final TypeStruct S1 = make("S1", Field.make("a", TypeInteger.BOT, -1, false), Field.make("s2",TypeMemPtr.make((byte)2,S2F),-2, false) );
- private static final TypeStruct S2 = make("S2", Field.make("b", TypeFloat .F64, -3, false), Field.make("s1",TypeMemPtr.make((byte)2,S1F),-4, false) );
- private static final TypeStruct ARY = makeAry("[i64]",TypeInteger.U32,-1,TypeInteger.BOT,-2);
- private static final TypeStruct STR = makeAry("[u8]",TypeInteger.U32,-1,TypeInteger.U8,-2);
- private static final TypeStruct HELLO= makeAry("[u8]",TypeInteger.constant(3),-1,TypeInteger.U8,-2,true,TypeConAryB.ABC);
+ public final TypeStruct close() {
+ return (TypeStruct)recurOpen()._close().recurClose();
+ }
+ @Override TypeStruct _close() {
+ TypeStruct ts = (TypeStruct)VISIT.get(_name);
+ if( ts!=null ) return ts;
+ ts = recurPre(_name,false);
+ Field[] flds = ts._fields;
+
+ // Now start the recursion
+ for( int i=0; i<flds.length; i++ )
+ flds[i].setType(_fields[i]._t._close());
+
+ return ts;
+ }
+
+ static final AryInt CEQUALS = new AryInt();
- public static void gather(ArrayList<Type> ts) { ts.add(TEST); ts.add(BOT); ts.add(S1); ts.add(S2); ts.add(ARY); ts.add(STR); ts.add(HELLO); }
+ public static final TypeStruct BOT = open("$STRUCT");
+ public static final TypeStruct TOP = BOT.dual();
+ public static final TypeStruct TEST= make("test",false,Field.TEST);
+ private static final TypeStruct ARY = makeAry("[]i64",TypeInteger.U32,-1,TypeInteger.BOT,-2,false);
+ private static final TypeStruct STR = makeAry("[]u8" ,TypeInteger.U32,-1,TypeInteger.U8 ,-4,false);
+ private static final TypeStruct ABC = makeAry("[]u8",TypeInteger.constant(3),-1,TypeConAryB.ABC,-4,true);
+
+ // A pair of self-cyclic types
+ private static final TypeStruct SINT0 = open("%SINT");
+ private static final TypeStruct SFLT0 = open("%SFLT");
+ private static final TypeStruct SINT1 = SINT0.add(Field.make("a", TypeInteger.U32, -1, false, false)).add(Field.make("s2",TypeMemPtr.make((byte)2,SFLT0),-2, false, false));
+ private static final TypeStruct SFLT1 = SFLT0.add(Field.make("b", TypeFloat .F32, -3, false, false)).add(Field.make("s1",TypeMemPtr.make((byte)2,SINT1),-4, false, false));
+ public static final TypeStruct SFLT2 = SFLT1.close();
+
+
+ public static void gather(ArrayList<Type> ts) {
+ ts.add(BOT);
+ ts.add(TEST);
+ ts.add(ARY);
+ ts.add(STR);
+ ts.add(ABC);
+ ts.add(SINT0);
+ ts.add(SFLT0);
+ ts.add(SINT1);
+ ts.add(SFLT1);
+ ts.add(SFLT2);
+ ts.add(((TypeMemPtr)(SFLT2.field("s1")._t))._obj);
+ // Break cyclic init: built a struct
+ Field fcalloc = Field.make("calloc",TypeFunPtr.CALLOC,-2,true,true);
+ TypeStruct scalloc = make("calloc",false,fcalloc);
+ ts.add(scalloc);
+
+ }
// Find field index by name
public int find(String fname) {
@@ -95,10 +155,10 @@ public class TypeStruct extends Type {
return -1;
}
-
@Override
- Type xmeet(Type t) {
+ TypeStruct xmeet(Type t) {
TypeStruct that = (TypeStruct) t;
+ assert !isFree() && !that.isFree();
if( this==TOP ) return that;
if( that==TOP ) return this;
if( this==BOT ) return BOT;
@@ -112,96 +172,154 @@ public class TypeStruct extends Type {
// And the answer is: "don't ask".
if( !_name.equals(that._name) )
return BOT; // It's a struct; that's about all we know
- if( this._fields==null ) return that;
- if( that._fields==null ) return this;
- if( _fields.length != that._fields.length ) return BOT;
- // Just do field meets
- Field[] flds = new Field[_fields.length];
- for( int i=0; i<_fields.length; i++ ) {
+
+ // if equal, no matters.
+ // if short is BOT, chop ; recurPre on short.
+ // if short is TOP, copy long; recurPre on long.
+ TypeStruct min = _fields.length < that._fields.length ? this : that;
+ if( _fields.length != that._fields.length && (min._open ^ min==this) )
+ return that.xmeet(this);
+
+ // Check all other fields are sanely similar; same struct type but
+ // different field contents (e.g. field "age" is either 'int' or '18').
+ int len = Math.min(_fields.length,that._fields.length);
+ for( int i=0; i<len; i++ ) {
Field f0 = _fields[i], f1 = that._fields[i];
- if( !f0._fname.equals(f1._fname) || f0._alias != f1._alias )
+ if( !f0._fname.equals(f1._fname) || f0._alias != f1._alias || f0._one != f1._one )
return BOT;
- flds[i] = (Field)f0.meet(f1);
}
- TypeConAry con = (TypeConAry)_con.meet(that._con);
- return make(_name, con, flds);
+
+ // See if we get a mid-recursion hit; breaks cycles
+ Integer pid = pid(that);
+ TypeStruct ts = (TypeStruct)VISIT.get(pid);
+ if( ts!=null ) return ts;
+ // If not mid-recursion, we are now; flag recursion.
+ boolean notRecur = VISIT.isEmpty();
+ if( notRecur ) recurOpen();
+
+ // Setup and install the type, prior to recursing, so we can find our
+ // recursive self again.
+ ts = recurPre(pid,_open | that._open);
+
+ // Recurse all common fields
+ Field[] flds = ts._fields;
+ for( int i=0; i<len; i++ ) {
+ Field f0 = _fields[i], f1 = that._fields[i];
+ flds[i].setType(f0._t.meet(f1._t ));
+ flds[i]._final = f0._final | f1._final;
+ }
+
+ // Handle extra fields via `_open`
+ for( int i=len; i<_fields.length; i++ )
+ flds[i].setType(_fields[i]._t );
+
+ // Cleanup post-recursion; intern/install at cycle end
+ if( notRecur ) ts = (TypeStruct)ts.recurClose();
+ return ts;
}
@Override
- public TypeStruct dual() {
- if( this==TOP ) return BOT;
- if( this==BOT ) return TOP;
- if( _fields == null ) return this;
+ TypeStruct xdual() {
+ if( _name=="$STRUCT" )
+ return malloc("$STRUCT",false,new Field[0]);
Field[] flds = new Field[_fields.length];
for( int i=0; i<_fields.length; i++ )
flds[i] = _fields[i].dual();
- TypeConAry con = _con.dual();
- return make(_name,con,flds);
+ return malloc(_name,!_open,flds);
}
- // Keeps the same struct, but lower-bounds all fields.
- @Override public TypeStruct glb(boolean mem) {
- if( _glb(mem) ) return this;
- // Need to glb each field
+ // Recursive dual
+ @Override TypeStruct rdual() {
+ if( _dual!=null ) return dual();
+ assert !_terned;
Field[] flds = new Field[_fields.length];
+ TypeStruct d = malloc(_name,!_open,flds);
+ (_dual = d)._dual = this; // Cross link duals
for( int i=0; i<_fields.length; i++ )
- flds[i] = _fields[i].glb(mem);
- return make(_name,flds);
- }
- private boolean _glb(boolean mem) {
- if( _fields!=null )
- for( Field f : _fields )
- if( f.glb(mem) != f )
- return false;
- return true;
+ flds[i] = _fields[i]._terned ? _fields[i].dual() : _fields[i].rdual();
+ return d;
}
// Is forward-reference
- @Override public boolean isFRef() { return _fields==null; }
+ @Override public boolean isFRef() { return _open; }
+
+ @Override boolean _isConstant() {
+ if( VISIT.containsKey(_uid) ) return true; // Cycles assume constant
+ VISIT.put(_uid,this);
+ // Check all fields for being constant
+ for( Field field : _fields )
+ if( !field._isConstant() )
+ return false;
+ return true;
+ }
+
// All fields are final
- @Override public boolean isFinal() {
- if( _fields==null ) return true;
+ @Override boolean _isFinal() {
+ if( _open ) return false; // May have more more non-final fields
+ if( VISIT.containsKey(_uid) ) // Test: been here before?
+ return true; // Cycles assume final
+ VISIT.put(_uid,this); // Set: dont do this again
for( Field fld : _fields )
- if( !fld.isFinal() )
+ if( !fld._isFinal() )
return false;
return true;
}
- @Override public boolean isConstant() {
- int len = _fields.length;
- // If we have a constant array, then ignore the last 2 array fields-
- // they are effectively constant.
-
- // Fields are given sizes according to their types at *offset time*.
- // And thus layout, packing & padding are determined by the Types
- // at *offset-time*, which means *offset-time* has to be picked
- // when types are Stable - post/during TypeCheck.
-
- // The array-length field is shared with other like-sized arrays, so
- // you are allowed to mix "abc" and "very_hugh_>256_char_string" and
- // the resulting TMP can query the length field (getting 3 or >256
- // respectively), and reading from a prolly 16bit length field.
-
- // Basically asking: forward-flow declared-types, are these compatible?
- // Only array-lengths have an issue here? So internally name fields
- // `#0` or `#1` or `#2` or `#3`.
- //
- // Also means I cannot track exact array length without losing the
- // "declared type requires a 4-byte field".
- //
- // Same-same for all fields in a struct, space in memory is based on
- // declared-type at least, possible (future work) optimized where all
- // memory versions of the same field get a smaller footprint (or even a
- // constant past or moved into prototype) past construction
-
- if( _con!=TypeConAry.BOT ) len -= 2;
- // Check all fields for being constant
- for( int i=0; i<len; i++ )
- if( !_fields[i].isConstant() )
+ private TypeStruct recurPre(Object key, boolean open) {
+ // Make a clone of original; suitable for hashing so can build
+ // e.g. TMPs to clone as part of cycles - but will fail the 'eq' check
+ // until the entire cycle is built.
+ Field[] flds = new Field[_fields.length];
+ for( int i=0; i<flds.length; i++ )
+ flds[i] = _fields[i].malloc(); // Blank copy, but can be hashed
+ TypeStruct ts = malloc(_name, open, flds );
+ VISIT.put(key,ts);
+ return ts;
+ }
+
+ // Make a read-only version
+ @Override TypeStruct _makeRO() {
+ // Check for already visited
+ TypeStruct ts = (TypeStruct)VISIT.get(_name);
+ if( ts!=null ) return ts; // Already visited
+ ts = recurPre(_name,_open); // Make a new type with blank fields
+ Field[] flds = ts._fields;
+ for( Field fld : flds ) fld._final = true;
+
+ // Now start the recursion
+ for( int i=0; i<flds.length; i++ )
+ flds[i].setType(_fields[i]._t._makeRO());
+
+ return ts;
+ }
+
+
+ // All fields are at GLB already
+ boolean isGLB2() {
+ if( VISIT.containsKey(_uid) ) return true; // Cycles assume GLB
+ VISIT.put(_uid,this);
+ for( Field fld : _fields )
+ if( !fld.isGLB2() )
return false;
return true;
}
+ // Keeps the same struct, but lower-bounds all fields.
+ public TypeStruct glb2() {
+ TypeStruct ts = (TypeStruct)VISIT.get(_name);
+ if( ts!=null ) return ts;
+ ts = recurPre(_name,_open);
+ Field[] flds = ts._fields;
+ for( int i=0; i<flds.length; i++ )
+ flds[i]._final = true ;
+
+ // Now start the recursion
+ for( int i=0; i<flds.length; i++ )
+ flds[i].setType(_fields[i]._t._glb(true));
+
+ return ts;
+ }
+
// log_size for a struct is not defined, unless its exactly some power of
// 2. *Total size* is well-defined, and is available in the offsets.
@Override public int log_size() { throw Utils.TODO(); }
@@ -209,48 +327,79 @@ public class TypeStruct extends Type {
@Override public int alignment() {
int align = 0;
for( Field f : _fields )
- align = Math.max(align, (f._fname!="[]" || _con==TypeConAry.BOT ? f._type : _con).alignment());
+ align = Math.max(align, f._t.alignment());
return align;
}
- @Override
- boolean eq(Type t) {
+ // If false, always false.
+ // If true , maybe true, need to check recursive fields.
+ private boolean static_eq( TypeStruct ts ) {
+ return _name.equals(ts._name) && _open==ts._open && _fields.length==ts._fields.length;
+ }
+
+ @Override boolean eq(Type t) {
+ // Recursive; so use cyclic equals
+ if( !VISIT.isEmpty() ) {
+ assert CEQUALS.isEmpty();
+ boolean rez = cycle_eq(t);
+ CEQUALS.clear();
+ return rez;
+ }
+ // Normal equals
+ TypeStruct ts = (TypeStruct)t; // Invariant
+ if( !static_eq(ts) ) return false;
+ if( _fields==ts._fields ) return true;
+ for( int i = 0; i < _fields.length; i++ )
+ if( !_fields[i].eq(ts._fields[i]) )
+ return false;
+ return true;
+ }
+
+ @Override boolean cycle_eq(Type t) {
+ if( this==t ) return true;
TypeStruct ts = (TypeStruct)t; // Invariant
- if( !_name.equals(ts._name) || _con!=ts._con )
- return false;
- if( _fields == ts._fields ) return true;
- if( _fields==null || ts._fields==null ) return false;
- if( _fields.length!=ts._fields.length )
- return false;
+ if( !static_eq(ts) ) return false;
+ if( _fields==ts._fields ) return true;
+ // Check to see if we've ever compared this pair of types before;
+ // if so, then assume the cycle is equal here.
+ int pid = pid(ts);
+ if( CEQUALS.find(pid)!= -1 ) return true;
+ CEQUALS.push(pid);
+ // Recursively check fields
for( int i = 0; i < _fields.length; i++ )
- if( _fields[i] != ts._fields[i] )
+ if( !_fields[i].cycle_eq(ts._fields[i]) )
return false;
return true;
}
@Override
int hash() {
- long hash = _name.hashCode();
- if( _fields != null )
- for( Field f : _fields )
- hash = Utils.rot(hash,13) ^ f.hashCode();
- return Utils.fold(hash ^ _con.hashCode());
+ long hash = _name.hashCode() ^ (_open ? 4 : 0);
+ for( Field f : _fields )
+ hash = Utils.rot(hash,13) ^ ((long)f._fname.hashCode() * f._alias);
+ return Utils.fold(hash);
}
+ @Override int nkids() { return _fields.length; }
+ @Override Type at( int idx ) { return _fields[idx]; }
+ @Override void set( int idx, Type t ) { _fields[idx] = (Field)t; }
+
@Override
- public SB print(SB sb) {
- if( _con!=TypeConAry.BOT ) return sb.p(_con.str());
+ SB _print(SB sb, BitSet visit, boolean html ) {
+ if( isFree() ) return sb.p("FREE:").p(_name);
+ if( isAry() && field("[]")._t instanceof TypeConAry con )
+ return sb.p(con.str());
sb.p(_name);
- if( _fields == null || isAry() ) // Forward reference struct, just print the name
- return sb.p(isFinal() ? "" : "!");
+ if( html || isAry() )
+ return sb;
sb.p(" {");
for( Field f : _fields )
- f._type.print(sb).p(f._final ? " " : " !").p(f._fname).p("; ");
+ (f._t ==null ? sb.p("---") : f._t.print(sb,visit,html)).p(f._final ? " " : " !").p(f._fname).p("; ");
+ if( _open ) sb.p("... ");
return sb.p("}");
}
- @Override public SB gprint( SB sb ) { return sb.p(_name); }
- @Override public String str() { return _con==TypeConAry.BOT ? _name : _con.str(); }
+ @Override public String str() { return (isFree() ? "FREE:":"")+_name; }
public boolean isAry() { return _fields.length>=2 && _fields[_fields.length-1]._fname=="[]"; }
@@ -262,7 +411,7 @@ public class TypeStruct extends Type {
}
public int aryScale() {
assert isAry();
- return _fields[1]._type.log_size();
+ return _fields[1]._t.log_size();
}
@@ -273,42 +422,44 @@ public class TypeStruct extends Type {
return _offs[idx];
}
private int[] offsets() { // Field byte offsets
+ assert CodeGen.CODE._phase.ordinal() >= CodeGen.Phase.Opto.ordinal();
// Compute a layout for a collection of fields
assert _fields != null; // No forward refs
// Compute a layout
- int[] cnts = new int[5]; // Count of fields at log field size
- int flen = _fields.length;
- if( isAry() ) flen--; // Array field is aligned differently
- for( int i=0; i<flen; i++ )
- cnts[_fields[i]._type.log_size()]++; // Log size is 0(byte), 1(i16/u16), 2(i32/f32), 3(i64/dbl)
- int off = 0, idx = 0; // Base common struct fields go here, e.g. Mark/Klass
- // Compute offsets to the start of each power-of-2 aligned fields.
- int[] offs = new int[4];
- for( int i=3; i>=0; i-- ) {
- offs[i] = off;
- off += cnts[i]<<i;
- }
- // Assign offsets to all fields.
- // Really a hidden radix sort.
_offs = new int[_fields.length+1];
- for( int i=0; i<flen; i++ ) {
- int log = _fields[i]._type.log_size();
- _offs[idx++] = offs[log]; // Field offset
- offs[log] += 1<<log; // Next field offset at same alignment
- cnts[log]--; // Count down, should be all zero at end
- }
-
- // Array bits
- if( isAry() ) {
+ if( isAry() ) { // Arrays used fixed u32 len, padding to elems, var length
+ assert _fields[1]._fname=="[]";
// Pad out to the element alignment
- int align = (_fields[flen]._fname!="[]" || _con==TypeConAry.BOT ? _fields[flen]._type : _con).alignment();
- off = (off + ((1<<align)-1)) & -(1<<align);
- _offs[flen] = off;
- if( _con!=TypeConAry.BOT )
- _offs[flen+1] = off+_con.len();
- } else
+ int align = _fields[1]._t.alignment();
+ _offs[1] = (4 + ((1<<align)-1)) & -(1<<align);
+ if( _fields[1]._t instanceof TypeConAry ary ) // Array length is well-defined for constants, not defined for runtime arrays
+ _offs[2] = _offs[1]+ary.len();
+
+ } else {
+ int[] cnts = new int[5]; // Count of fields at log field size
+ int flen = _fields.length;
+ for( int i=0; i<flen; i++ )
+ if( !_fields[i]._one )
+ cnts[_fields[i]._t.log_size()]++; // Log size is 0(byte), 1(i16/u16), 2(i32/f32), 3(i64/dbl)
+ int off = 0, idx = 0; // Base common struct fields go here, e.g. Mark/Klass
+ // Compute offsets to the start of each power-of-2 aligned fields.
+ int[] offs = new int[4];
+ for( int i=3; i>=0; i-- ) {
+ offs[i] = off;
+ off += cnts[i]<<i;
+ }
+ // Assign offsets to all fields.
+ // Really a hidden radix sort.
+ for( int i=0; i<flen; i++ ) {
+ if( _fields[i]._one ) continue;
+ int log = _fields[i]._t.log_size();
+ _offs[idx++] = offs[log]; // Field offset
+ offs[log] += 1<<log; // Next field offset at same alignment
+ cnts[log]--; // Count down, should be all zero at end
+ }
_offs[flen] = off; // Max struct size, no trailing padding
+ }
return _offs;
}
diff --git a/src/main/java/com/seaofnodes/simple/type/TypeTuple.java b/src/main/java/com/seaofnodes/simple/type/TypeTuple.java
index bc57871a..df9aba31 100644
--- a/src/main/java/com/seaofnodes/simple/type/TypeTuple.java
+++ b/src/main/java/com/seaofnodes/simple/type/TypeTuple.java
@@ -1,67 +1,75 @@
package com.seaofnodes.simple.type;
-import com.seaofnodes.simple.SB;
-import com.seaofnodes.simple.Utils;
-import java.util.ArrayList;
+import com.seaofnodes.simple.util.Ary;
+import com.seaofnodes.simple.util.SB;
+import com.seaofnodes.simple.util.Utils;
+import java.util.*;
public class TypeTuple extends Type {
- public final Type[] _types;
+ public Type[] _types;
+ private static final Ary<TypeTuple> FREE = new Ary<>(TypeTuple.class);
private TypeTuple(Type[] types) { super(TTUPLE); _types = types; }
- public static TypeTuple make(Type... types) { return new TypeTuple(types).intern(); }
+ private TypeTuple init( Type[] types ) { _types = types; return this; }
+ private static TypeTuple malloc(Type[] types) {
+ return FREE.isEmpty() ? new TypeTuple(types) : FREE.pop().init(types);
+ }
+ // All fields directly listed
+ public static TypeTuple make(Type... types) {
+ TypeTuple tt = malloc(types);
+ TypeTuple t2 = tt.intern();
+ return t2==tt ? tt : t2.free(tt);
+ }
+ @Override TypeTuple free(Type t) {
+ TypeTuple tt = (TypeTuple)t;
+ tt._types = null;
+ tt._dual = null;
+ tt._hash = 0;
+ FREE.push(tt);
+ return this;
+ }
+ @Override boolean isFree() { return _types==null; }
- public static final TypeTuple BOT = new TypeTuple(new Type[0]).intern();
- public static final TypeTuple TOP = new TypeTuple(null).intern();
+
+ public static final TypeTuple BOT = malloc(new Type[0]).intern();
+ public static final TypeTuple TOP = BOT.dual();
public static final TypeTuple TEST = make(TypeInteger.BOT,TypeMemPtr.TEST);
public static final TypeTuple START= make(Type.CONTROL,TypeMem.TOP,TypeInteger.BOT);
- public static final TypeTuple MAIN = make(TypeInteger.BOT);
public static final TypeTuple RET = make(Type.CONTROL,TypeMem.BOT,Type.BOTTOM);
- public static final TypeTuple CALLOC = make(TypeInteger.BOT,TypeInteger.BOT);
- public static final TypeTuple IF_BOTH = make(new Type[]{Type. CONTROL,Type. CONTROL});
- public static final TypeTuple IF_NEITHER = make(new Type[]{Type.XCONTROL,Type.XCONTROL});
- public static final TypeTuple IF_TRUE = make(new Type[]{Type. CONTROL,Type.XCONTROL});
- public static final TypeTuple IF_FALSE = make(new Type[]{Type.XCONTROL,Type. CONTROL});
+ public static final TypeTuple IF_BOTH = make(Type. CONTROL,Type. CONTROL);
+ public static final TypeTuple IF_NEITHER = make(Type.XCONTROL,Type.XCONTROL);
+ public static final TypeTuple IF_TRUE = make(Type. CONTROL,Type.XCONTROL);
+ public static final TypeTuple IF_FALSE = make(Type.XCONTROL,Type. CONTROL);
- public static void gather(ArrayList<Type> ts) { ts.add(BOT); ts.add(TEST); ts.add(START); ts.add(MAIN); ts.add(IF_TRUE); }
+ public static void gather(ArrayList<Type> ts) { ts.add(BOT); ts.add(TEST); ts.add(START); ts.add(IF_TRUE); }
@Override
Type xmeet(Type other) {
- TypeTuple tt = (TypeTuple)other; // contract from xmeet
- if( this==TOP ) return other;
- if( tt ==TOP ) return this ;
- if( _types.length != tt._types.length )
+ TypeTuple that = (TypeTuple)other; // contract from xmeet
+ if( this==TOP ) return that;
+ if( that==TOP ) return this;
+ if( _types.length != that._types.length )
return BOT;
- Type[] ts = new Type[_types.length];
- for( int i=0; i<_types.length; i++ )
- ts[i] = _types[i].meet(tt._types[i]);
- return make(ts);
+ return make(TypeFunPtr.xmeet(_types,that._types));
}
- @Override public TypeTuple dual() {
- if( this==TOP ) return BOT;
- if( this==BOT ) return TOP;
- Type[] ts = new Type[_types.length];
- for( int i=0; i<_types.length; i++ )
- ts[i] = _types[i].dual();
- return make(ts);
- }
-
- @Override public Type glb(boolean mem) {
- Type[] ts = new Type[_types.length];
- for( int i=0; i<_types.length; i++ )
- ts[i] = _types[i].glb(mem);
- return make(ts);
+ @Override TypeTuple xdual() {
+ if( _types.length==0 ) return malloc(null);
+ return malloc(TypeFunPtr.xdual(_types));
}
- @Override public boolean isConstant() {
+ @Override boolean _isConstant() {
for( Type t : _types )
- if( !t.isConstant() )
+ if( !t._isConstant() )
return false;
return true;
}
+ @Override boolean _isFinal() { throw Utils.TODO(); }
+
+ @Override TypeMemPtr _makeRO() { throw Utils.TODO(); }
@Override public int log_size() { throw Utils.TODO(); }
@Override public int alignment() {
@@ -74,25 +82,17 @@ public class TypeTuple extends Type {
public Type ret() { assert _types.length==3; return _types[2]; }
- @Override public String str() { return print(new SB()).toString(); }
-
- @Override public SB print(SB sb) {
+ @Override SB _print(SB sb, BitSet visit, boolean html ) {
if( this==TOP ) return sb.p("[TOP]");
if( this==BOT ) return sb.p("[BOT]");
sb.p("[ ");
for( Type t : _types )
- t.print(sb).p(", ");
- return sb.unchar(2).p("]");
- }
- @Override public SB gprint(SB sb) {
- if( this==TOP ) return sb.p("[TOP]");
- if( this==BOT ) return sb.p("[BOT]");
- sb.p("[ ");
- for( Type t : _types )
- t.gprint(sb).p(", ");
+ t.print(sb,visit,html).p(", ");
return sb.unchar(2).p("]");
}
+ @Override public String str() { return print(new SB(),new BitSet(),false).toString(); }
+
@Override
int hash() {
int sum = 0;
@@ -102,15 +102,18 @@ public class TypeTuple extends Type {
@Override
boolean eq( Type t ) {
- TypeTuple tt = (TypeTuple)t; // Contract
- if( _types==null && tt._types==null ) return true;
- if( _types==null || tt._types==null ) return false;
- if( _types.length != tt._types.length ) return false;
+ TypeTuple that = (TypeTuple)t; // Contract
+ if( _types==null && that._types==null ) return true;
+ if( _types==null || that._types==null ) return false;
+ if( _types.length != that._types.length ) return false;
for( int i=0; i<_types.length; i++ )
- if( _types[i]!=tt._types[i] )
+ if( _types[i]!=that._types[i] )
return false;
return true;
}
+ @Override int nkids() { return _types.length; }
+ @Override Type at( int idx ) { return _types[idx]; }
+ @Override void set( int idx, Type t ) { _types[idx] = t; }
}
diff --git a/src/main/java/com/seaofnodes/simple/Ary.java b/src/main/java/com/seaofnodes/simple/util/Ary.java
index f43179ad..d67801c2 100644
--- a/src/main/java/com/seaofnodes/simple/Ary.java
+++ b/src/main/java/com/seaofnodes/simple/util/Ary.java
@@ -1,4 +1,4 @@
-package com.seaofnodes.simple;
+package com.seaofnodes.simple.util;
import java.lang.StringBuilder;
import java.lang.reflect.Array;
@@ -36,6 +36,7 @@ public class Ary<E> extends AbstractList<E> implements List<E> {
/** @return last element */
public E last( ) { return at(_len-1); }
+ public E last(int x ) { return at(_len-1+x); }
/** Add element in amortized constant time
* @param e Element to add at end of list
diff --git a/src/main/java/com/seaofnodes/simple/util/AryInt.java b/src/main/java/com/seaofnodes/simple/util/AryInt.java
new file mode 100644
index 00000000..b498fd78
--- /dev/null
+++ b/src/main/java/com/seaofnodes/simple/util/AryInt.java
@@ -0,0 +1,192 @@
+package com.seaofnodes.simple.util;
+
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.function.IntUnaryOperator;
+
+// ArrayList with saner syntax
+public class AryInt {
+ public int[] _es;
+ public int _len;
+ public AryInt(int[] es) { this(es,es.length); }
+ public AryInt(int[] es, int len) { _es=es; _len=len; }
+ public AryInt() { this(new int[1],0); }
+
+ /** @return list is empty */
+ public boolean isEmpty() { return _len==0; }
+ /** @return active list length */
+ public int len() { return _len; }
+ /** @param i element index
+ * @return element being returned; throws if OOB */
+ public int at( int i ) {
+ range_check(i);
+ return _es[i];
+ }
+ /** @param i element index
+ * @return element being returned, or 0 if OOB */
+ public int atX( int i ) {
+ return i < _len ? _es[i] : 0;
+ }
+ /** @return last element */
+ public int last( ) { return at(_len-1); }
+ public int last(int x ) { return at(_len-1+x); }
+
+ /** @return remove and return last element */
+ public int pop( ) {
+ range_check(0);
+ return _es[--_len];
+ }
+
+ /** Add element in amortized constant time
+ * @param e element to add at end of list
+ * @return 'this' for flow-coding */
+ public AryInt push( int e ) {
+ if( _len >= _es.length ) _es = Arrays.copyOf(_es,Math.max(1,_es.length<<1));
+ _es[_len++] = e;
+ return this;
+ }
+
+ /** Slow, linear-time, element insert. Preserves order.
+ * @param i index to insert at, between 0 and _len inclusive.
+ * @param e intlement to insert
+ */
+ public void insert( int i, int e ) {
+ if( i < 0 || i>_len )
+ throw new ArrayIndexOutOfBoundsException(""+i+" >= "+_len);
+ if( _len >= _es.length ) _es = Arrays.copyOf(_es,Math.max(1,_es.length<<1));
+ System.arraycopy(_es,i,_es,i+1,(_len++)-i);
+ _es[i] = e;
+ }
+
+ /** Fast, constant-time, element removal. Does not preserve order
+ * @param i element to be removed
+ * @return element removed */
+ public int del( int i ) {
+ range_check(i);
+ int tmp = _es[i];
+ _es[i]=_es[--_len];
+ return tmp;
+ }
+
+ /** Slow, linear-time, element removal. Preserves order.
+ * @param i element to be removed
+ * @return element removed */
+ public int remove( int i ) {
+ range_check(i);
+ int e = _es[i];
+ System.arraycopy(_es,i+1,_es,i,(--_len)-i);
+ return e;
+ }
+
+ /** Remove all elements */
+ public void clear( ) { Arrays.fill(_es,0,_len,0); _len=0; }
+
+ // Extend and set
+ public int setX( int i, int e ) {
+ while( i>= _es.length ) _es = Arrays.copyOf(_es,_es.length<<1);
+ if( i >= _len ) _len = i+1;
+ return (_es[i] = e);
+ }
+
+ public int set( int i, int e ) {
+ range_check(i);
+ return (_es[i] = e);
+ }
+
+ public AryInt set_as( int e ) { _es[0] = e; _len=1; return this; }
+ public AryInt set_len( int len ) {
+ if( len > _len )
+ while( len>= _es.length ) _es = Arrays.copyOf(_es,_es.length<<1);
+ _len = len;
+ while( _es.length > (len<<1) ) // Shrink if hugely too large
+ _es = Arrays.copyOf(_es,_es.length>>1);
+ return this;
+ }
+
+ /** @param c Collection to be added */
+ public AryInt addAll( Collection<? extends Integer> c ) { for( int e : c ) push(e); return this; }
+
+ /** @param es Array to be added */
+ public AryInt addAll( int[] es ) {
+ if( es.length==0 ) return this;
+ while( _len+es.length > _es.length ) _es = Arrays.copyOf(_es,_es.length<<1);
+ System.arraycopy(es,0,_es,_len,es.length);
+ _len += es.length;
+ return this;
+ }
+
+ /** @param es Array to be added */
+ public AryInt addAll( AryInt ary ) {
+ if( ary._len==0 ) return this;
+ while( _len+ary._len > _es.length ) _es = Arrays.copyOf(_es,_es.length<<1);
+ System.arraycopy(ary._es,0,_es,_len,ary._len);
+ _len += ary._len;
+ return this;
+ }
+
+ public AryInt map_update( IntUnaryOperator f ) { for( int i = 0; i<_len; i++ ) _es[i] = f.applyAsInt(_es[i]); return this; }
+
+ /** @return compact array version, using the internal base array where possible. */
+ public int[] asAry() { return _len==_es.length ? _es : Arrays.copyOf(_es,_len); }
+
+ /** Sorts in-place */
+ public void sort_update() { Arrays.sort(_es, 0, _len); }
+ /** Find the first matching element using ==, or -1 if none. Note that
+ * most del calls shuffle the list, so the first element might be random.
+ * @param e intlement to find
+ * @return index of first matching element, or -1 if none */
+ public int find( int e ) {
+ for( int i=0; i<_len; i++ ) if( _es[i]==e ) return i;
+ return -1;
+ }
+
+ @Override public String toString() {
+ SB sb = new SB().p('[');
+ for( int i=0; i<_len; i++ )
+ sb.p(_es[i]).p(',');
+ return sb.unchar().p(']').toString();
+ }
+
+ private void range_check( int i ) {
+ if( i < 0 || i>=_len )
+ throw new ArrayIndexOutOfBoundsException(""+i+" >= "+_len);
+ }
+
+ // Binary search sorted _es. Returns insertion point.
+ // Undefined results if _es is not sorted.
+ public int binary_search( int e ) {
+ int lo=0, hi=_len-1;
+ while( lo <= hi ) {
+ int mid = (hi + lo) >>> 1; // midpoint, rounded down
+ int mval = _es[mid];
+ if( e==mval ) {
+ // If dups, get to the first.
+ while( mid>0 && e==_es[mid-1] ) mid--;
+ return mid;
+ }
+ if( e >mval ) lo = mid+1;
+ else hi = mid-1;
+ }
+ return lo;
+ }
+
+ // Note that the hashCode() and equals() are not invariant to changes in the
+ // underlying array. If the hashCode() is used (e.g., inserting into a
+ // HashMap) and the then the array changes, the hashCode() will change also.
+ @Override public boolean equals( Object o ) {
+ if( this==o ) return true;
+ if( !(o instanceof AryInt ary) ) return false;
+ if( _len != ary._len ) return false;
+ if( _es == ary._es ) return true;
+ for( int i=0; i<_len; i++ )
+ if( _es[i] != ary._es[i] )
+ return false;
+ return true;
+ }
+ @Override public int hashCode( ) {
+ int sum=_len;
+ for( int i=0; i<_len; i++ )
+ sum += _es[i];
+ return sum;
+ }
+}
diff --git a/src/main/java/com/seaofnodes/simple/SB.java b/src/main/java/com/seaofnodes/simple/util/SB.java
index 978fbed9..d7afd6eb 100644
--- a/src/main/java/com/seaofnodes/simple/SB.java
+++ b/src/main/java/com/seaofnodes/simple/util/SB.java
@@ -1,4 +1,4 @@
-package com.seaofnodes.simple;
+package com.seaofnodes.simple.util;
/** Tight/tiny StringBuilder wrapper.
* Short short names on purpose; so they don't obscure the printing.
diff --git a/src/main/java/com/seaofnodes/simple/Utils.java b/src/main/java/com/seaofnodes/simple/util/Utils.java
index 1346c3ea..577a60af 100644
--- a/src/main/java/com/seaofnodes/simple/Utils.java
+++ b/src/main/java/com/seaofnodes/simple/util/Utils.java
@@ -1,4 +1,4 @@
-package com.seaofnodes.simple;
+package com.seaofnodes.simple.util;
import java.util.ArrayList;