summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--chapter20/src/main/java/com/seaofnodes/simple/codegen/RegAlloc.java2
-rw-r--r--chapter20/src/main/java/com/seaofnodes/simple/node/cpus/arm/NotARM.java26
-rw-r--r--chapter20/src/main/java/com/seaofnodes/simple/node/cpus/arm/SubIARM.java (renamed from chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/LslIARM.java)30
-rw-r--r--chapter20/src/main/java/com/seaofnodes/simple/node/cpus/riscv/NotRISC.java25
-rw-r--r--chapter20/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/CallRX86.java7
-rw-r--r--chapter20/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/CallX86.java8
-rw-r--r--chapter20/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/FunX86.java2
-rw-r--r--chapter20/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/NotX86.java26
-rw-r--r--chapter20/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/ParmX86.java4
-rw-r--r--chapter20/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/ProjX86.java2
-rw-r--r--chapter20/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/RetX86.java7
-rw-r--r--chapter20/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/XorX86.java (renamed from chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/XorIARM.java)29
-rw-r--r--chapter21/README.md7
-rw-r--r--chapter21/docs/lattice.svg1382
-rw-r--r--chapter21/docs/lattice2.svg520
-rw-r--r--chapter21/src/main/java/com/seaofnodes/simple/codegen/CodeGen.java37
-rw-r--r--chapter21/src/main/java/com/seaofnodes/simple/codegen/ElfExpr.java87
-rw-r--r--chapter21/src/main/java/com/seaofnodes/simple/codegen/Encoding.java67
-rw-r--r--chapter21/src/main/java/com/seaofnodes/simple/codegen/IFG.java4
-rw-r--r--chapter21/src/main/java/com/seaofnodes/simple/codegen/RegAlloc.java2
-rw-r--r--chapter21/src/main/java/com/seaofnodes/simple/node/CalleeSaveNode.java6
-rw-r--r--chapter21/src/main/java/com/seaofnodes/simple/node/MachNode.java7
-rw-r--r--chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/AddARM.java26
-rw-r--r--chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/AddFARM.java21
-rw-r--r--chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/AddIARM.java51
-rw-r--r--chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/AndARM.java20
-rw-r--r--chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/AndIARM.java56
-rw-r--r--chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/AsrARM.java30
-rw-r--r--chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/AsrIARM.java41
-rw-r--r--chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/BranchARM.java33
-rw-r--r--chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/CallARM.java20
-rw-r--r--chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/CallEndARM.java17
-rw-r--r--chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/CallRRARM.java13
-rw-r--r--chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/CmpARM.java18
-rw-r--r--chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/CmpFARM.java20
-rw-r--r--chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/CmpIARM.java35
-rw-r--r--chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/DivARM.java23
-rw-r--r--chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/DivFARM.java21
-rw-r--r--chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/FloatARM.java18
-rw-r--r--chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/FunARM.java16
-rw-r--r--chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/I2F8ARM.java25
-rw-r--r--chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/IntARM.java18
-rw-r--r--chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/LoadARM.java18
-rw-r--r--chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/LslARM.java31
-rw-r--r--chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/LsrARM.java30
-rw-r--r--chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/LsrIARM.java41
-rw-r--r--chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/MemOpARM.java44
-rw-r--r--chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/MulARM.java26
-rw-r--r--chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/MulFARM.java20
-rw-r--r--chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/MulIARM.java4
-rw-r--r--chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/NewARM.java19
-rw-r--r--chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/NotARM.java28
-rw-r--r--chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/OrARM.java35
-rw-r--r--chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/OrIARM.java40
-rw-r--r--chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/ParmARM.java12
-rw-r--r--chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/ProjARM.java12
-rw-r--r--chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/RetARM.java41
-rw-r--r--chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/SetARM.java18
-rw-r--r--chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/SplitARM.java15
-rw-r--r--chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/StoreARM.java42
-rw-r--r--chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/SubARM.java24
-rw-r--r--chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/SubFARM.java26
-rw-r--r--chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/SubIARM.java27
-rw-r--r--chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/TFPARM.java24
-rw-r--r--chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/XorARM.java37
-rw-r--r--chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/arm.java471
-rw-r--r--chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/i2f8.java4
-rw-r--r--chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/AUIPC.java28
-rw-r--r--chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/AddFRISC.java25
-rw-r--r--chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/AddIRISC.java3
-rw-r--r--chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/AddRISC.java26
-rw-r--r--chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/AndIRISC.java3
-rw-r--r--chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/AndRISC.java31
-rw-r--r--chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/BranchRISC.java27
-rw-r--r--chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/CallEndRISC.java18
-rw-r--r--chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/CallRISC.java32
-rw-r--r--chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/CallRRISC.java21
-rw-r--r--chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/CastRISC.java6
-rw-r--r--chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/DivFRISC.java21
-rw-r--r--chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/DivRISC.java25
-rw-r--r--chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/FltRISC.java30
-rw-r--r--chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/FunRISC.java12
-rw-r--r--chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/I2F8RISC.java23
-rw-r--r--chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/ImmRISC.java29
-rw-r--r--chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/IntRISC.java27
-rw-r--r--chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/LUI.java32
-rw-r--r--chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/LoadRISC.java32
-rw-r--r--chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/MemOpRISC.java69
-rw-r--r--chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/MulFRISC.java25
-rw-r--r--chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/MulRISC.java23
-rw-r--r--chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/NewRISC.java22
-rw-r--r--chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/NotRISC.java16
-rw-r--r--chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/OrIRISC.java3
-rw-r--r--chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/OrRISC.java35
-rw-r--r--chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/ParmRISC.java15
-rw-r--r--chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/ProjRISC.java14
-rw-r--r--chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/RetRISC.java36
-rw-r--r--chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/SetFRISC.java22
-rw-r--r--chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/SetIRISC.java20
-rw-r--r--chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/SetRISC.java32
-rw-r--r--chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/SllIRISC.java3
-rw-r--r--chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/SllRISC.java36
-rw-r--r--chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/SplitRISC.java16
-rw-r--r--chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/SraIRISC.java3
-rw-r--r--chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/SraRISC.java33
-rw-r--r--chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/SrlIRISC.java3
-rw-r--r--chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/SrlRISC.java33
-rw-r--r--chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/StoreRISC.java40
-rw-r--r--chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/SubFRISC.java25
-rw-r--r--chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/SubRISC.java19
-rw-r--r--chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/TFPRISC.java35
-rw-r--r--chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/XorIRISC.java3
-rw-r--r--chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/XorRISC.java37
-rw-r--r--chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/riscv.java305
-rw-r--r--chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/AddFMemX86.java21
-rw-r--r--chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/AddFX86.java25
-rw-r--r--chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/AddIX86.java42
-rw-r--r--chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/AddMemX86.java21
-rw-r--r--chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/AddX86.java32
-rw-r--r--chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/AndIX86.java45
-rw-r--r--chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/AndX86.java32
-rw-r--r--chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/CallEndX86.java18
-rw-r--r--chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/CallRX86.java17
-rw-r--r--chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/CallX86.java23
-rw-r--r--chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/CastX86.java8
-rw-r--r--chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/CmpFX86.java22
-rw-r--r--chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/CmpIX86.java50
-rw-r--r--chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/CmpMemX86.java28
-rw-r--r--chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/CmpX86.java28
-rw-r--r--chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/DivFX86.java33
-rw-r--r--chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/DivX86.java28
-rw-r--r--chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/FltX86.java36
-rw-r--r--chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/FunX86.java13
-rw-r--r--chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/I2f8X86.java27
-rw-r--r--chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/ImmX86.java38
-rw-r--r--chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/IntX86.java48
-rw-r--r--chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/JmpX86.java29
-rw-r--r--chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/LeaX86.java38
-rw-r--r--chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/LoadX86.java16
-rw-r--r--chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/MemAddX86.java25
-rw-r--r--chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/MemOpX86.java8
-rw-r--r--chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/MulFX86.java28
-rw-r--r--chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/MulIX86.java40
-rw-r--r--chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/MulX86.java23
-rw-r--r--chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/NewX86.java12
-rw-r--r--chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/NotX86.java39
-rw-r--r--chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/OrIX86.java42
-rw-r--r--chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/OrX86.java36
-rw-r--r--chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/ParmX86.java14
-rw-r--r--chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/ProjX86.java12
-rw-r--r--chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/RegX86.java25
-rw-r--r--chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/RetX86.java24
-rw-r--r--chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/SarIX86.java39
-rw-r--r--chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/SarX86.java49
-rw-r--r--chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/SetX86.java34
-rw-r--r--chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/ShlIX86.java41
-rw-r--r--chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/ShlX86.java47
-rw-r--r--chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/ShrIX86.java42
-rw-r--r--chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/ShrX86.java48
-rw-r--r--chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/SplitX86.java71
-rw-r--r--chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/StoreX86.java21
-rw-r--r--chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/SubFX86.java24
-rw-r--r--chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/SubX86.java31
-rw-r--r--chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/TFPX86.java46
-rw-r--r--chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/UJmpX86.java24
-rw-r--r--chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/XorIX86.java40
-rw-r--r--chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/XorX86.java11
-rw-r--r--chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/x86_64_v2.java477
168 files changed, 3530 insertions, 3833 deletions
diff --git a/chapter20/src/main/java/com/seaofnodes/simple/codegen/RegAlloc.java b/chapter20/src/main/java/com/seaofnodes/simple/codegen/RegAlloc.java
index 9e607349..badec740 100644
--- a/chapter20/src/main/java/com/seaofnodes/simple/codegen/RegAlloc.java
+++ b/chapter20/src/main/java/com/seaofnodes/simple/codegen/RegAlloc.java
@@ -123,7 +123,7 @@ public class RegAlloc {
}
- public int regnum( Node n ) {
+ public short regnum( Node n ) {
LRG lrg = lrg(n);
return lrg==null ? -1 : lrg._reg;
}
diff --git a/chapter20/src/main/java/com/seaofnodes/simple/node/cpus/arm/NotARM.java b/chapter20/src/main/java/com/seaofnodes/simple/node/cpus/arm/NotARM.java
new file mode 100644
index 00000000..28ebd60d
--- /dev/null
+++ b/chapter20/src/main/java/com/seaofnodes/simple/node/cpus/arm/NotARM.java
@@ -0,0 +1,26 @@
+package com.seaofnodes.simple.node.cpus.arm;
+
+import com.seaofnodes.simple.*;
+import com.seaofnodes.simple.codegen.CodeGen;
+import com.seaofnodes.simple.codegen.LRG;
+import com.seaofnodes.simple.codegen.RegMask;
+import com.seaofnodes.simple.node.*;
+import com.seaofnodes.simple.type.TypeInteger;
+import java.io.ByteArrayOutputStream;
+
+import com.seaofnodes.simple.node.MachConcreteNode;
+
+public class NotARM extends MachConcreteNode implements MachNode{
+ NotARM(NotNode not) {super(not);}
+ @Override public RegMask regmap(int i) { return arm.RMASK; }
+ @Override public RegMask outregmap() { return arm.RMASK; }
+
+ @Override public int twoAddress( ) { return 0; }
+
+ @Override public int encoding(ByteArrayOutputStream bytes) {
+ throw Utils.TODO();
+ }
+
+ @Override public void asm(CodeGen code, SB sb) { sb.p(code.reg(this)); }
+ @Override public String op() { return "not"; }
+}
diff --git a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/LslIARM.java b/chapter20/src/main/java/com/seaofnodes/simple/node/cpus/arm/SubIARM.java
index 7a7014f4..d19210cb 100644
--- a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/LslIARM.java
+++ b/chapter20/src/main/java/com/seaofnodes/simple/node/cpus/arm/SubIARM.java
@@ -1,27 +1,25 @@
package com.seaofnodes.simple.node.cpus.arm;
+import com.seaofnodes.simple.node.MachConcreteNode;
import com.seaofnodes.simple.*;
import com.seaofnodes.simple.codegen.CodeGen;
+import com.seaofnodes.simple.codegen.LRG;
import com.seaofnodes.simple.codegen.RegMask;
import com.seaofnodes.simple.node.*;
-import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeInteger;
import java.io.ByteArrayOutputStream;
-import java.util.BitSet;
-import java.lang.StringBuilder;
-
-// Logical Shift Left (immediate)
-public class LslIARM extends MachConcreteNode implements MachNode {
+public class SubIARM extends MachConcreteNode implements MachNode {
final TypeInteger _ti;
- LslIARM(Node lsli, TypeInteger ti) {super(lsli); _inputs.pop(); _ti = ti;}
+ SubIARM(Node sub, TypeInteger ti) {
+ super(sub);
+ _inputs.pop();
+ _ti = ti;
+ }
// Register mask allowed on input i.
- // This is the normal calling convention
- @Override public RegMask regmap(int i) {
- // assert i==1;
- return arm.RMASK; }
+ @Override public RegMask regmap(int i) { return arm.RMASK; }
// Register mask allowed as a result. 0 for no register.
@Override public RegMask outregmap() { return arm.RMASK; }
@@ -31,12 +29,14 @@ public class LslIARM extends MachConcreteNode implements MachNode {
throw Utils.TODO();
}
- // General form
- // General form: "lsli rd, rs1, imm"
+ // General form: "subi rd = rs1 - imm"
@Override public void asm(CodeGen code, SB sb) {
- sb.p(code.reg(this)).p(" = ").p(code.reg(in(1))).p(" << #");
+ sb.p(code.reg(this)).p(" = ").p(code.reg(in(1))).p(" - #");
_ti.print(sb);
}
- @Override public String op() { return "lsli"; }
+ @Override public String op() {
+ return (_ti.value() == -1 ? "dec" : "subi");
+ }
+
}
diff --git a/chapter20/src/main/java/com/seaofnodes/simple/node/cpus/riscv/NotRISC.java b/chapter20/src/main/java/com/seaofnodes/simple/node/cpus/riscv/NotRISC.java
new file mode 100644
index 00000000..6d30cd1c
--- /dev/null
+++ b/chapter20/src/main/java/com/seaofnodes/simple/node/cpus/riscv/NotRISC.java
@@ -0,0 +1,25 @@
+package com.seaofnodes.simple.node.cpus.riscv;
+
+import com.seaofnodes.simple.*;
+import com.seaofnodes.simple.codegen.CodeGen;
+import com.seaofnodes.simple.codegen.LRG;
+import com.seaofnodes.simple.codegen.RegMask;
+import com.seaofnodes.simple.node.*;
+import com.seaofnodes.simple.node.MachConcreteNode;
+import com.seaofnodes.simple.type.TypeInteger;
+import java.io.ByteArrayOutputStream;
+
+public class NotRISC extends MachConcreteNode implements MachNode {
+ NotRISC(NotNode not) {super(not);}
+ @Override public RegMask regmap(int i) { return riscv.RMASK; }
+ @Override public RegMask outregmap() { return riscv.RMASK; }
+
+ @Override public int twoAddress( ) { return 0; }
+
+ @Override public int encoding(ByteArrayOutputStream bytes) {
+ throw Utils.TODO();
+ }
+
+ @Override public void asm(CodeGen code, SB sb) { sb.p(code.reg(this)); }
+ @Override public String op() { return "not"; }
+}
diff --git a/chapter20/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/CallRX86.java b/chapter20/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/CallRX86.java
index ec6f9993..ac35d17b 100644
--- a/chapter20/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/CallRX86.java
+++ b/chapter20/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/CallRX86.java
@@ -21,7 +21,12 @@ public class CallRX86 extends CallNode implements MachNode {
// Encoding is appended into the byte array; size is returned
@Override public int encoding(ByteArrayOutputStream bytes) {
- throw Utils.TODO();
+ bytes.write(0xe8);
+ int beforeSize = bytes.size();
+ // address
+ //TODO: relocs
+ bytes.write(0x00);
+ return bytes.size() - beforeSize;
}
@Override public void asm(CodeGen code, SB sb) {
diff --git a/chapter20/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/CallX86.java b/chapter20/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/CallX86.java
index 959ec81e..e2f68c1f 100644
--- a/chapter20/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/CallX86.java
+++ b/chapter20/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/CallX86.java
@@ -32,7 +32,13 @@ public class CallX86 extends CallNode implements MachNode {
// Encoding is appended into the byte array; size is returned
@Override public int encoding(ByteArrayOutputStream bytes) {
- throw Utils.TODO();
+ // linker will fix this up
+ bytes.write(0xe8);
+ int beforeSize = bytes.size();
+ // TODO: relocs
+ // address
+ bytes.write(0x00);
+ return bytes.size() - beforeSize;
}
@Override public void asm(CodeGen code, SB sb) {
diff --git a/chapter20/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/FunX86.java b/chapter20/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/FunX86.java
index 5239670b..7346ae05 100644
--- a/chapter20/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/FunX86.java
+++ b/chapter20/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/FunX86.java
@@ -17,6 +17,6 @@ public class FunX86 extends FunNode implements MachNode {
// Encoding is appended into the byte array; size is returned
@Override public int encoding(ByteArrayOutputStream bytes) {
- throw Utils.TODO();
+ return 0;
}
}
diff --git a/chapter20/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/NotX86.java b/chapter20/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/NotX86.java
new file mode 100644
index 00000000..a4b82de8
--- /dev/null
+++ b/chapter20/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/NotX86.java
@@ -0,0 +1,26 @@
+package com.seaofnodes.simple.node.cpus.x86_64_v2;
+
+import com.seaofnodes.simple.SB;
+import com.seaofnodes.simple.Utils;
+import com.seaofnodes.simple.codegen.CodeGen;
+import com.seaofnodes.simple.codegen.LRG;
+import com.seaofnodes.simple.codegen.RegMask;
+import com.seaofnodes.simple.node.*;
+import java.io.ByteArrayOutputStream;
+
+public class NotX86 extends MachConcreteNode implements MachNode {
+ NotX86(NotNode not) {super(not);}
+ @Override public RegMask regmap(int i) { return x86_64_v2.RMASK; }
+ @Override public RegMask outregmap() { return x86_64_v2.RMASK; }
+
+ @Override public int twoAddress( ) { return 0; }
+
+ // NotNode(BoolNode) = Inverted BoolNode(1)
+ // NotNode(NotNode(BoolNode)) = BoolNode(2)
+ // anything else to test & setz(3)
+ @Override public int encoding(ByteArrayOutputStream bytes) {
+ throw Utils.TODO();
+ }
+ @Override public void asm(CodeGen code, SB sb) { sb.p(code.reg(this)); }
+ @Override public String op() { return "not"; }
+}
diff --git a/chapter20/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/ParmX86.java b/chapter20/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/ParmX86.java
index 4d47f76d..69ebb74e 100644
--- a/chapter20/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/ParmX86.java
+++ b/chapter20/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/ParmX86.java
@@ -21,5 +21,7 @@ public class ParmX86 extends ParmNode implements MachNode {
@Override public RegMask outregmap() { return _rmask; }
// Encoding is appended into the byte array. Returns size
- @Override public int encoding(ByteArrayOutputStream bytes) { return 0; }
+ @Override public int encoding(ByteArrayOutputStream bytes) {
+ return 0;
+ }
}
diff --git a/chapter20/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/ProjX86.java b/chapter20/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/ProjX86.java
index 40d8b6c2..7ac014e6 100644
--- a/chapter20/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/ProjX86.java
+++ b/chapter20/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/ProjX86.java
@@ -18,6 +18,6 @@ public class ProjX86 extends ProjNode implements MachNode {
// Encoding is appended into the byte array; size is returned
@Override public int encoding(ByteArrayOutputStream bytes) {
- throw Utils.TODO();
+ return 0;
}
}
diff --git a/chapter20/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/RetX86.java b/chapter20/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/RetX86.java
index cdb20fd4..433f64cc 100644
--- a/chapter20/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/RetX86.java
+++ b/chapter20/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/RetX86.java
@@ -28,7 +28,12 @@ public class RetX86 extends ReturnNode implements MachNode {
// Encoding is appended into the byte array; size is returned
@Override public int encoding(ByteArrayOutputStream bytes) {
- throw Utils.TODO();
+ // Without imm form
+ // Near return
+ int beforeSize = bytes.size();
+ bytes.write(0xC3); // opcode
+
+ return bytes.size() - beforeSize;
}
@Override public void asm(CodeGen code, SB sb) {
diff --git a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/XorIARM.java b/chapter20/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/XorX86.java
index d230ea47..3322d951 100644
--- a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/XorIARM.java
+++ b/chapter20/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/XorX86.java
@@ -1,8 +1,9 @@
-package com.seaofnodes.simple.node.cpus.arm;
+package com.seaofnodes.simple.node.cpus.x86_64_v2;
import com.seaofnodes.simple.SB;
import com.seaofnodes.simple.Utils;
import com.seaofnodes.simple.codegen.CodeGen;
+import com.seaofnodes.simple.codegen.LRG;
import com.seaofnodes.simple.codegen.RegMask;
import com.seaofnodes.simple.node.MachConcreteNode;
import com.seaofnodes.simple.node.MachNode;
@@ -10,19 +11,11 @@ import com.seaofnodes.simple.node.Node;
import com.seaofnodes.simple.type.TypeInteger;
import java.io.ByteArrayOutputStream;
-public class XorIARM extends MachConcreteNode implements MachNode{
- final TypeInteger _ti;
- XorIARM(Node xor, TypeInteger ti) {super(xor); _inputs.pop(); _ti = ti;}
+public class XorX86 extends MachConcreteNode implements MachNode{
+ XorX86(Node xor) {super(xor);}
- // Register mask allowed on input i.
- // This is the normal calling convention
- @Override public RegMask regmap(int i) {
- assert i==1 || i==2;
-
- return arm.RMASK; }
-
- // Register mask allowed as a result. 0 for no register.
- @Override public RegMask outregmap() { return arm.RMASK; }
+ @Override public RegMask regmap(int i) { return x86_64_v2.WMASK; }
+ @Override public RegMask outregmap() { return x86_64_v2.WMASK; }
// Output is same register as input#1
@Override public int twoAddress() { return 1; }
@@ -33,11 +26,11 @@ public class XorIARM extends MachConcreteNode implements MachNode{
}
// General form
- // General form: "rd = rs1 ^ imm"
+ // General form: "xor ^ reg
@Override public void asm(CodeGen code, SB sb) {
- sb.p(code.reg(this)).p(" = ").p(code.reg(in(1))).p(" ^ #");
- _ti.print(sb);
+ sb.p(code.reg(this)).p(" = ").p(code.reg(in(1))).p(" ^ ").p(code.reg(in(2)));
}
- @Override public String op() { return "eor"; }
-} \ No newline at end of file
+ @Override public String op() { return "xor"; }
+
+}
diff --git a/chapter21/README.md b/chapter21/README.md
index 42f61f73..9b1e8e86 100644
--- a/chapter21/README.md
+++ b/chapter21/README.md
@@ -1,5 +1,12 @@
# Chapter 21: Instruction Encoding and ELF
+This chapter has encodings for:
+
+*x86_64 v2*,
+*RISC V 64I*
+*Arm V8*
+
+
## Instruction Encodings
### Lots of Bits
diff --git a/chapter21/docs/lattice.svg b/chapter21/docs/lattice.svg
index 030f4826..e72b473b 100644
--- a/chapter21/docs/lattice.svg
+++ b/chapter21/docs/lattice.svg
@@ -1,691 +1,691 @@
-<?xml version="1.0" encoding="UTF-8" standalone="no"?>
-<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
- "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
-<!-- Generated by graphviz version 12.2.0 (20241103.1931)
- -->
-<!-- Title: Lattice Pages: 1 -->
-<svg width="1330pt" height="584pt"
- viewBox="0.00 0.00 1329.51 583.54" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
-<g id="graph0" class="graph" transform="scale(1 1) rotate(0) translate(4 579.54)">
-<title>Lattice</title>
-<polygon fill="white" stroke="none" points="-4,4 -4,-579.54 1325.51,-579.54 1325.51,4 -4,4"/>
-<!-- TOP -->
-<g id="node1" class="node">
-<title>TOP</title>
-<ellipse fill="black" stroke="black" cx="641.51" cy="-554.42" rx="21.12" ry="21.12"/>
-<text text-anchor="start" x="633.63" y="-549.99" font-family="Times New Roman,serif" font-weight="bold" font-size="14.00" fill="white">⊤</text>
-</g>
-<!-- XCTRL -->
-<g id="node3" class="node">
-<title>XCTRL</title>
-<ellipse fill="yellow" stroke="black" cx="36.51" cy="-492.79" rx="36.51" ry="18"/>
-<text text-anchor="start" x="17.76" y="-488.74" font-family="Times New Roman,serif" font-weight="bold" font-size="14.00">⊤</text>
-<text text-anchor="start" x="33.51" y="-488.74" font-family="Times New Roman,serif" font-size="14.00">:ctrl</text>
-</g>
-<!-- TOP&#45;&gt;XCTRL -->
-<g id="edge1" class="edge">
-<title>TOP&#45;&gt;XCTRL</title>
-<path fill="none" stroke="black" d="M620.33,-551.33C533.82,-542.8 206.01,-510.5 83.28,-498.4"/>
-<polygon fill="black" stroke="black" points="83.86,-494.94 73.56,-497.44 83.17,-501.91 83.86,-494.94"/>
-</g>
-<!-- INT_TOP -->
-<g id="node5" class="node">
-<title>INT_TOP</title>
-<ellipse fill="lightblue" stroke="black" cx="316.51" cy="-492.79" rx="33.95" ry="18"/>
-<text text-anchor="start" x="299.63" y="-488.74" font-family="Times New Roman,serif" font-weight="bold" font-size="14.00">⊤</text>
-<text text-anchor="start" x="315.38" y="-488.74" font-family="Times New Roman,serif" font-size="14.00">:int</text>
-</g>
-<!-- TOP&#45;&gt;INT_TOP -->
-<g id="edge4" class="edge">
-<title>TOP&#45;&gt;INT_TOP</title>
-<path fill="none" stroke="black" d="M620.68,-549.6C568.33,-539.99 430.36,-514.68 359.64,-501.71"/>
-<polygon fill="black" stroke="black" points="360.44,-498.29 349.97,-499.93 359.18,-505.18 360.44,-498.29"/>
-</g>
-<!-- FLT_TOP -->
-<g id="node14" class="node">
-<title>FLT_TOP</title>
-<ellipse fill="aqua" stroke="black" cx="494.51" cy="-492.79" rx="32.41" ry="18"/>
-<text text-anchor="start" x="478.76" y="-488.74" font-family="Times New Roman,serif" font-weight="bold" font-size="14.00">⊤</text>
-<text text-anchor="start" x="494.51" y="-488.74" font-family="Times New Roman,serif" font-size="14.00">:flt</text>
-</g>
-<!-- TOP&#45;&gt;FLT_TOP -->
-<g id="edge18" class="edge">
-<title>TOP&#45;&gt;FLT_TOP</title>
-<path fill="none" stroke="black" d="M621.99,-545.5C598.79,-536.09 559.6,-520.19 530.78,-508.5"/>
-<polygon fill="black" stroke="black" points="532.29,-505.34 521.7,-504.82 529.65,-511.82 532.29,-505.34"/>
-</g>
-<!-- PTR -->
-<g id="node22" class="node">
-<title>PTR</title>
-<polygon fill="none" stroke="none" points="668.51,-519.29 614.51,-519.29 614.51,-466.29 668.51,-466.29 668.51,-519.29"/>
-<polygon fill="green" stroke="none" points="623.51,-492.79 623.51,-515.29 659.51,-515.29 659.51,-492.79 623.51,-492.79"/>
-<polygon fill="none" stroke="black" points="623.51,-492.79 623.51,-515.29 659.51,-515.29 659.51,-492.79 623.51,-492.79"/>
-<text text-anchor="start" x="630.63" y="-498.99" font-family="Times New Roman,serif" font-size="14.00" fill="white">*ptr</text>
-<polygon fill="lightgreen" stroke="none" points="623.51,-470.29 623.51,-492.79 659.51,-492.79 659.51,-470.29 623.51,-470.29"/>
-<polygon fill="none" stroke="black" points="623.51,-470.29 623.51,-492.79 659.51,-492.79 659.51,-470.29 623.51,-470.29"/>
-<text text-anchor="start" x="626.51" y="-476.49" font-family="Times New Roman,serif" font-size="14.00">struct</text>
-</g>
-<!-- TOP&#45;&gt;PTR -->
-<g id="edge33" class="edge">
-<title>TOP&#45;&gt;PTR</title>
-<path fill="none" stroke="black" d="M641.51,-532.9C641.51,-532.06 641.51,-531.22 641.51,-530.37"/>
-<polygon fill="black" stroke="black" points="645.01,-530.61 641.51,-520.61 638.01,-530.61 645.01,-530.61"/>
-</g>
-<!-- STRUCT_TOP -->
-<g id="node24" class="node">
-<title>STRUCT_TOP</title>
-<ellipse fill="lightgreen" stroke="black" cx="746.51" cy="-492.79" rx="44.7" ry="18"/>
-<text text-anchor="start" x="721.76" y="-488.74" font-family="Times New Roman,serif" font-weight="bold" font-size="14.00">⊤</text>
-<text text-anchor="start" x="737.51" y="-488.74" font-family="Times New Roman,serif" font-size="14.00">:struct</text>
-</g>
-<!-- TOP&#45;&gt;STRUCT_TOP -->
-<g id="edge36" class="edge">
-<title>TOP&#45;&gt;STRUCT_TOP</title>
-<path fill="none" stroke="black" d="M659.8,-543.03C674.04,-534.94 694.24,-523.47 711.55,-513.64"/>
-<polygon fill="black" stroke="black" points="713.07,-516.81 720.03,-508.83 709.61,-510.72 713.07,-516.81"/>
-</g>
-<!-- MEM_TOP -->
-<g id="node29" class="node">
-<title>MEM_TOP</title>
-<ellipse fill="blue" stroke="black" cx="998.51" cy="-492.79" rx="43.67" ry="18"/>
-<text text-anchor="start" x="974.51" y="-488.74" font-family="Times New Roman,serif" font-weight="bold" font-size="14.00" fill="white">⊤</text>
-<text text-anchor="start" x="990.26" y="-488.74" font-family="Times New Roman,serif" font-size="14.00" fill="white">:mem</text>
-</g>
-<!-- TOP&#45;&gt;MEM_TOP -->
-<g id="edge46" class="edge">
-<title>TOP&#45;&gt;MEM_TOP</title>
-<path fill="none" stroke="black" d="M662.51,-549.91C717.64,-540.7 867.72,-515.64 947.33,-502.34"/>
-<polygon fill="black" stroke="black" points="947.77,-505.82 957.06,-500.72 946.62,-498.91 947.77,-505.82"/>
-</g>
-<!-- TUPLE_TOP -->
-<g id="node34" class="node">
-<title>TUPLE_TOP</title>
-<ellipse fill="pink" stroke="black" cx="1182.51" cy="-492.79" rx="42.65" ry="18"/>
-<text text-anchor="start" x="1159.26" y="-488.74" font-family="Times New Roman,serif" font-weight="bold" font-size="14.00">⊤</text>
-<text text-anchor="start" x="1175.01" y="-488.74" font-family="Times New Roman,serif" font-size="14.00">:tuple</text>
-</g>
-<!-- TOP&#45;&gt;TUPLE_TOP -->
-<g id="edge56" class="edge">
-<title>TOP&#45;&gt;TUPLE_TOP</title>
-<path fill="none" stroke="black" d="M662.72,-551.08C740.91,-542.46 1014.51,-512.31 1130.21,-499.56"/>
-<polygon fill="black" stroke="black" points="1130.5,-503.05 1140.05,-498.47 1129.73,-496.09 1130.5,-503.05"/>
-</g>
-<!-- BOT -->
-<g id="node2" class="node">
-<title>BOT</title>
-<ellipse fill="black" stroke="black" cx="641.51" cy="-21.12" rx="21.12" ry="21.12"/>
-<text text-anchor="start" x="633.63" y="-16.7" font-family="Times New Roman,serif" font-weight="bold" font-size="14.00" fill="white">⊥</text>
-</g>
-<!-- CTRL -->
-<g id="node4" class="node">
-<title>CTRL</title>
-<ellipse fill="yellow" stroke="black" cx="49.51" cy="-82.75" rx="36.51" ry="18"/>
-<text text-anchor="start" x="30.76" y="-78.7" font-family="Times New Roman,serif" font-weight="bold" font-size="14.00">⊥</text>
-<text text-anchor="start" x="46.51" y="-78.7" font-family="Times New Roman,serif" font-size="14.00">:ctrl</text>
-</g>
-<!-- XCTRL&#45;&gt;CTRL -->
-<g id="edge2" class="edge">
-<title>XCTRL&#45;&gt;CTRL</title>
-<path fill="none" stroke="black" d="M37.09,-474.38C39.15,-409.6 46.05,-191.88 48.57,-112.25"/>
-<polygon fill="black" stroke="black" points="52.06,-112.73 48.88,-102.63 45.06,-112.51 52.06,-112.73"/>
-</g>
-<!-- CTRL&#45;&gt;BOT -->
-<g id="edge3" class="edge">
-<title>CTRL&#45;&gt;BOT</title>
-<path fill="none" stroke="black" d="M85.21,-78.15C191.74,-67.42 506.36,-35.74 608.84,-25.41"/>
-<polygon fill="black" stroke="black" points="609.15,-28.9 618.75,-24.42 608.45,-21.94 609.15,-28.9"/>
-</g>
-<!-- INT_HI -->
-<g id="node7" class="node">
-<title>INT_HI</title>
-<ellipse fill="lightblue" stroke="black" cx="174.51" cy="-434.29" rx="53.91" ry="18"/>
-<text text-anchor="middle" x="174.51" y="-429.24" font-family="Times New Roman,serif" font-size="14.00">[min&gt;max]</text>
-</g>
-<!-- INT_TOP&#45;&gt;INT_HI -->
-<g id="edge5" class="edge">
-<title>INT_TOP&#45;&gt;INT_HI</title>
-<path fill="none" stroke="black" d="M289.8,-481.17C269.89,-473.25 242.26,-462.25 219.03,-453.01"/>
-<polygon fill="black" stroke="black" points="220.37,-449.77 209.78,-449.33 217.78,-456.28 220.37,-449.77"/>
-</g>
-<!-- INT_BOT -->
-<g id="node6" class="node">
-<title>INT_BOT</title>
-<ellipse fill="lightblue" stroke="black" cx="329.51" cy="-82.75" rx="33.95" ry="18"/>
-<text text-anchor="start" x="312.63" y="-78.7" font-family="Times New Roman,serif" font-weight="bold" font-size="14.00">⊥</text>
-<text text-anchor="start" x="328.38" y="-78.7" font-family="Times New Roman,serif" font-size="14.00">:int</text>
-</g>
-<!-- INT_BOT&#45;&gt;BOT -->
-<g id="edge15" class="edge">
-<title>INT_BOT&#45;&gt;BOT</title>
-<path fill="none" stroke="black" d="M361.14,-75.7C420.84,-64.3 549.47,-39.71 609.47,-28.25"/>
-<polygon fill="black" stroke="black" points="609.86,-31.73 619.03,-26.42 608.55,-24.86 609.86,-31.73"/>
-</g>
-<!-- INT_XBOOL -->
-<g id="node8" class="node">
-<title>INT_XBOOL</title>
-<ellipse fill="lightblue" stroke="black" cx="97.51" cy="-373.97" rx="33.95" ry="18"/>
-<text text-anchor="middle" x="97.51" y="-368.92" font-family="Times New Roman,serif" font-size="14.00">[1...0]</text>
-</g>
-<!-- INT_HI&#45;&gt;INT_XBOOL -->
-<g id="edge6" class="edge">
-<title>INT_HI&#45;&gt;INT_XBOOL</title>
-<path fill="none" stroke="black" d="M153.47,-417.36C144.79,-410.78 134.6,-403.06 125.31,-396.03"/>
-<polygon fill="black" stroke="black" points="127.71,-393.46 117.63,-390.21 123.48,-399.04 127.71,-393.46"/>
-</g>
-<!-- INT_CON -->
-<g id="node9" class="node">
-<title>INT_CON</title>
-<ellipse fill="lightblue" stroke="black" cx="174.51" cy="-282.65" rx="45.21" ry="18"/>
-<text text-anchor="middle" x="174.51" y="-277.6" font-family="Times New Roman,serif" font-size="14.00">constants</text>
-</g>
-<!-- INT_HI&#45;&gt;INT_CON -->
-<g id="edge9" class="edge">
-<title>INT_HI&#45;&gt;INT_CON</title>
-<path fill="none" stroke="black" d="M174.51,-416C174.51,-390.27 174.51,-343.1 174.51,-312.31"/>
-<polygon fill="black" stroke="black" points="178.01,-312.52 174.51,-302.52 171.01,-312.52 178.01,-312.52"/>
-</g>
-<!-- INT_CON0 -->
-<g id="node10" class="node">
-<title>INT_CON0</title>
-<ellipse fill="lightblue" stroke="black" cx="47.51" cy="-282.65" rx="18" ry="18"/>
-<text text-anchor="middle" x="47.51" y="-277.6" font-family="Times New Roman,serif" font-size="14.00">0</text>
-</g>
-<!-- INT_XBOOL&#45;&gt;INT_CON0 -->
-<g id="edge7" class="edge">
-<title>INT_XBOOL&#45;&gt;INT_CON0</title>
-<path fill="none" stroke="black" d="M88.34,-356.59C80.82,-343.17 70.07,-323.96 61.49,-308.62"/>
-<polygon fill="black" stroke="black" points="64.63,-307.08 56.69,-300.06 58.53,-310.5 64.63,-307.08"/>
-</g>
-<!-- INT_CON1 -->
-<g id="node11" class="node">
-<title>INT_CON1</title>
-<ellipse fill="lightblue" stroke="black" cx="97.51" cy="-282.65" rx="18" ry="18"/>
-<text text-anchor="middle" x="97.51" y="-277.6" font-family="Times New Roman,serif" font-size="14.00">1</text>
-</g>
-<!-- INT_XBOOL&#45;&gt;INT_CON1 -->
-<g id="edge8" class="edge">
-<title>INT_XBOOL&#45;&gt;INT_CON1</title>
-<path fill="none" stroke="black" d="M97.51,-355.75C97.51,-343.47 97.51,-326.68 97.51,-312.39"/>
-<polygon fill="black" stroke="black" points="101.01,-312.64 97.51,-302.64 94.01,-312.64 101.01,-312.64"/>
-</g>
-<!-- INT_LO -->
-<g id="node13" class="node">
-<title>INT_LO</title>
-<ellipse fill="lightblue" stroke="black" cx="174.51" cy="-141.25" rx="53.91" ry="18"/>
-<text text-anchor="middle" x="174.51" y="-136.2" font-family="Times New Roman,serif" font-size="14.00">[min&lt;max]</text>
-</g>
-<!-- INT_CON&#45;&gt;INT_LO -->
-<g id="edge13" class="edge">
-<title>INT_CON&#45;&gt;INT_LO</title>
-<path fill="none" stroke="black" d="M174.51,-264.17C174.51,-240.45 174.51,-199.04 174.51,-170.9"/>
-<polygon fill="black" stroke="black" points="178.01,-171.25 174.51,-161.25 171.01,-171.25 178.01,-171.25"/>
-</g>
-<!-- INT_CON0&#45;&gt;INT_CON1 -->
-<!-- INT_BOOL -->
-<g id="node12" class="node">
-<title>INT_BOOL</title>
-<ellipse fill="lightblue" stroke="black" cx="97.51" cy="-196.45" rx="33.95" ry="18"/>
-<text text-anchor="middle" x="97.51" y="-191.4" font-family="Times New Roman,serif" font-size="14.00">[0...1]</text>
-</g>
-<!-- INT_CON0&#45;&gt;INT_BOOL -->
-<g id="edge10" class="edge">
-<title>INT_CON0&#45;&gt;INT_BOOL</title>
-<path fill="none" stroke="black" d="M56.45,-266.6C63.5,-254.72 73.51,-237.87 81.88,-223.77"/>
-<polygon fill="black" stroke="black" points="84.75,-225.79 86.85,-215.41 78.73,-222.22 84.75,-225.79"/>
-</g>
-<!-- INT_CON1&#45;&gt;INT_CON -->
-<!-- INT_CON1&#45;&gt;INT_BOOL -->
-<g id="edge11" class="edge">
-<title>INT_CON1&#45;&gt;INT_BOOL</title>
-<path fill="none" stroke="black" d="M97.51,-264.21C97.51,-253.25 97.51,-238.87 97.51,-226.25"/>
-<polygon fill="black" stroke="black" points="101.01,-226.39 97.51,-216.39 94.01,-226.39 101.01,-226.39"/>
-</g>
-<!-- INT_BOOL&#45;&gt;INT_LO -->
-<g id="edge12" class="edge">
-<title>INT_BOOL&#45;&gt;INT_LO</title>
-<path fill="none" stroke="black" d="M117.34,-181.75C124.98,-176.47 133.91,-170.3 142.42,-164.42"/>
-<polygon fill="black" stroke="black" points="144.27,-167.4 150.5,-158.83 140.29,-161.64 144.27,-167.4"/>
-</g>
-<!-- INT_LO&#45;&gt;INT_BOT -->
-<g id="edge14" class="edge">
-<title>INT_LO&#45;&gt;INT_BOT</title>
-<path fill="none" stroke="black" d="M210.07,-127.29C234.52,-118.37 266.93,-106.56 291.82,-97.49"/>
-<polygon fill="black" stroke="black" points="292.71,-100.89 300.91,-94.17 290.31,-94.31 292.71,-100.89"/>
-</g>
-<!-- FLT_CON64 -->
-<g id="node16" class="node">
-<title>FLT_CON64</title>
-<ellipse fill="aqua" stroke="black" cx="564.51" cy="-282.65" rx="55.33" ry="40.66"/>
-<text text-anchor="middle" x="564.51" y="-294.1" font-family="Times New Roman,serif" font-size="14.00">64b consts</text>
-<text text-anchor="middle" x="564.51" y="-277.6" font-family="Times New Roman,serif" font-size="14.00">[excludes</text>
-<text text-anchor="middle" x="564.51" y="-261.1" font-family="Times New Roman,serif" font-size="14.00">32b consts]</text>
-</g>
-<!-- FLT_TOP&#45;&gt;FLT_CON64 -->
-<g id="edge19" class="edge">
-<title>FLT_TOP&#45;&gt;FLT_CON64</title>
-<path fill="none" stroke="black" d="M500.48,-474.88C510.8,-443.88 532.35,-379.2 547.59,-333.44"/>
-<polygon fill="black" stroke="black" points="550.9,-334.57 550.74,-323.98 544.26,-332.36 550.9,-334.57"/>
-</g>
-<!-- FLT_CONPI -->
-<g id="node18" class="node">
-<title>FLT_CONPI</title>
-<ellipse fill="aqua" stroke="black" cx="446.51" cy="-282.65" rx="48.79" ry="18"/>
-<text text-anchor="middle" x="446.51" y="-277.6" font-family="Times New Roman,serif" font-size="14.00">3.14159...</text>
-</g>
-<!-- FLT_TOP&#45;&gt;FLT_CONPI -->
-<g id="edge20" class="edge">
-<title>FLT_TOP&#45;&gt;FLT_CONPI</title>
-<path fill="none" stroke="black" d="M490.33,-474.51C482.02,-438.11 463.32,-356.27 453.25,-312.16"/>
-<polygon fill="black" stroke="black" points="456.69,-311.49 451.05,-302.52 449.86,-313.04 456.69,-311.49"/>
-</g>
-<!-- FLT_X32 -->
-<g id="node19" class="node">
-<title>FLT_X32</title>
-<ellipse fill="aqua" stroke="black" cx="333.51" cy="-373.97" rx="28.32" ry="28.32"/>
-<text text-anchor="middle" x="333.51" y="-368.92" font-family="Times New Roman,serif" font-size="14.00">~f32</text>
-</g>
-<!-- FLT_TOP&#45;&gt;FLT_X32 -->
-<g id="edge23" class="edge">
-<title>FLT_TOP&#45;&gt;FLT_X32</title>
-<path fill="none" stroke="black" d="M474.77,-478.22C447.56,-458.14 398.22,-421.73 365.65,-397.69"/>
-<polygon fill="black" stroke="black" points="367.88,-394.99 357.75,-391.86 363.72,-400.62 367.88,-394.99"/>
-</g>
-<!-- FLT_BOT -->
-<g id="node15" class="node">
-<title>FLT_BOT</title>
-<ellipse fill="aqua" stroke="black" cx="507.51" cy="-82.75" rx="32.41" ry="18"/>
-<text text-anchor="start" x="491.76" y="-78.7" font-family="Times New Roman,serif" font-weight="bold" font-size="14.00">⊥</text>
-<text text-anchor="start" x="507.51" y="-78.7" font-family="Times New Roman,serif" font-size="14.00">:flt</text>
-</g>
-<!-- FLT_BOT&#45;&gt;BOT -->
-<g id="edge29" class="edge">
-<title>FLT_BOT&#45;&gt;BOT</title>
-<path fill="none" stroke="black" d="M532.4,-70.67C554.98,-60.63 588.29,-45.81 612.16,-35.19"/>
-<polygon fill="black" stroke="black" points="613.29,-38.51 621,-31.25 610.44,-32.12 613.29,-38.51"/>
-</g>
-<!-- FLT_CON64&#45;&gt;FLT_BOT -->
-<g id="edge21" class="edge">
-<title>FLT_CON64&#45;&gt;FLT_BOT</title>
-<path fill="none" stroke="black" d="M553.11,-242.68C542.05,-203.88 525.53,-145.95 515.71,-111.5"/>
-<polygon fill="black" stroke="black" points="519.17,-110.89 513.06,-102.23 512.44,-112.81 519.17,-110.89"/>
-</g>
-<!-- FLT_CON32 -->
-<g id="node17" class="node">
-<title>FLT_CON32</title>
-<ellipse fill="aqua" stroke="black" cx="333.51" cy="-282.65" rx="50.33" ry="18"/>
-<text text-anchor="middle" x="333.51" y="-277.6" font-family="Times New Roman,serif" font-size="14.00">32b consts</text>
-</g>
-<!-- FLT_CON32&#45;&gt;FLT_CONPI -->
-<!-- FLT_32 -->
-<g id="node21" class="node">
-<title>FLT_32</title>
-<ellipse fill="aqua" stroke="black" cx="333.51" cy="-196.45" rx="23.2" ry="23.2"/>
-<text text-anchor="middle" x="333.51" y="-191.4" font-family="Times New Roman,serif" font-size="14.00">f32</text>
-</g>
-<!-- FLT_CON32&#45;&gt;FLT_32 -->
-<g id="edge27" class="edge">
-<title>FLT_CON32&#45;&gt;FLT_32</title>
-<path fill="none" stroke="black" d="M333.51,-264.21C333.51,-254.7 333.51,-242.59 333.51,-231.31"/>
-<polygon fill="black" stroke="black" points="337.01,-231.51 333.51,-221.51 330.01,-231.51 337.01,-231.51"/>
-</g>
-<!-- FLT_CONPI&#45;&gt;FLT_BOT -->
-<g id="edge22" class="edge">
-<title>FLT_CONPI&#45;&gt;FLT_BOT</title>
-<path fill="none" stroke="black" d="M452.03,-264.56C462.62,-229.86 485.86,-153.69 498.65,-111.79"/>
-<polygon fill="black" stroke="black" points="501.94,-112.98 501.51,-102.39 495.25,-110.93 501.94,-112.98"/>
-</g>
-<!-- FLT_CONPI&#45;&gt;FLT_CON64 -->
-<!-- FLT_X32&#45;&gt;FLT_CON32 -->
-<g id="edge25" class="edge">
-<title>FLT_X32&#45;&gt;FLT_CON32</title>
-<path fill="none" stroke="black" d="M333.51,-345.2C333.51,-334.71 333.51,-322.76 333.51,-312.19"/>
-<polygon fill="black" stroke="black" points="337.01,-312.52 333.51,-302.52 330.01,-312.53 337.01,-312.52"/>
-</g>
-<!-- FLT_CON0 -->
-<g id="node20" class="node">
-<title>FLT_CON0</title>
-<ellipse fill="aqua" stroke="black" cx="251.51" cy="-282.65" rx="18.08" ry="18.08"/>
-<text text-anchor="middle" x="251.51" y="-277.6" font-family="Times New Roman,serif" font-size="14.00">0.</text>
-</g>
-<!-- FLT_X32&#45;&gt;FLT_CON0 -->
-<g id="edge24" class="edge">
-<title>FLT_X32&#45;&gt;FLT_CON0</title>
-<path fill="none" stroke="black" d="M314.9,-352.7C301.83,-338.47 284.38,-319.46 271.1,-304.99"/>
-<polygon fill="black" stroke="black" points="273.81,-302.77 264.47,-297.77 268.65,-307.5 273.81,-302.77"/>
-</g>
-<!-- FLT_CON0&#45;&gt;FLT_CON32 -->
-<!-- FLT_CON0&#45;&gt;FLT_32 -->
-<g id="edge26" class="edge">
-<title>FLT_CON0&#45;&gt;FLT_32</title>
-<path fill="none" stroke="black" d="M263.96,-268.86C276.06,-256.44 294.74,-237.26 309.69,-221.91"/>
-<polygon fill="black" stroke="black" points="312.03,-224.53 316.5,-214.92 307.01,-219.64 312.03,-224.53"/>
-</g>
-<!-- FLT_32&#45;&gt;FLT_BOT -->
-<g id="edge28" class="edge">
-<title>FLT_32&#45;&gt;FLT_BOT</title>
-<path fill="none" stroke="black" d="M353.13,-183.63C383.19,-163.99 440.9,-126.28 476.61,-102.94"/>
-<polygon fill="black" stroke="black" points="478.34,-105.99 484.79,-97.59 474.51,-100.13 478.34,-105.99"/>
-</g>
-<!-- PTR0 -->
-<g id="node23" class="node">
-<title>PTR0</title>
-<polygon fill="none" stroke="none" points="668.51,-109.25 614.51,-109.25 614.51,-56.25 668.51,-56.25 668.51,-109.25"/>
-<polygon fill="green" stroke="none" points="623.51,-82.75 623.51,-105.25 659.51,-105.25 659.51,-82.75 623.51,-82.75"/>
-<polygon fill="none" stroke="black" points="623.51,-82.75 623.51,-105.25 659.51,-105.25 659.51,-82.75 623.51,-82.75"/>
-<text text-anchor="start" x="627.63" y="-88.95" font-family="Times New Roman,serif" font-size="14.00" fill="white">*ptr?</text>
-<polygon fill="lightgreen" stroke="none" points="623.51,-60.25 623.51,-82.75 659.51,-82.75 659.51,-60.25 623.51,-60.25"/>
-<polygon fill="none" stroke="black" points="623.51,-60.25 623.51,-82.75 659.51,-82.75 659.51,-60.25 623.51,-60.25"/>
-<text text-anchor="start" x="626.51" y="-66.45" font-family="Times New Roman,serif" font-size="14.00">struct</text>
-</g>
-<!-- PTR&#45;&gt;PTR0 -->
-<g id="edge34" class="edge">
-<title>PTR&#45;&gt;PTR0</title>
-<path fill="none" stroke="black" d="M641.51,-466.52C641.51,-396.01 641.51,-202.44 641.51,-120.34"/>
-<polygon fill="black" stroke="black" points="645.01,-120.58 641.51,-110.58 638.01,-120.58 645.01,-120.58"/>
-</g>
-<!-- PTR0&#45;&gt;BOT -->
-<g id="edge35" class="edge">
-<title>PTR0&#45;&gt;BOT</title>
-<path fill="none" stroke="black" d="M641.51,-56.46C641.51,-55.58 641.51,-54.7 641.51,-53.81"/>
-<polygon fill="black" stroke="black" points="645.01,-53.9 641.51,-43.9 638.01,-53.9 645.01,-53.9"/>
-</g>
-<!-- STRUCT_S1 -->
-<g id="node26" class="node">
-<title>STRUCT_S1</title>
-<polygon fill="none" stroke="none" points="741.38,-300.65 663.63,-300.65 663.63,-264.65 741.38,-264.65 741.38,-300.65"/>
-<polygon fill="lightgreen" stroke="none" points="671.63,-273.4 671.63,-291.9 698.38,-291.9 698.38,-273.4 671.63,-273.4"/>
-<polygon fill="none" stroke="black" points="671.63,-273.4 671.63,-291.9 698.38,-291.9 698.38,-273.4 671.63,-273.4"/>
-<text text-anchor="start" x="672.63" y="-277.6" font-family="Times New Roman,serif" font-size="14.00">field</text>
-<defs>
-<linearGradient id="l_0" gradientUnits="userSpaceOnUse" x1="703.51" y1="-289.19" x2="728.26" y2="-276.11" >
-<stop offset="0" style="stop-color:lightblue;stop-opacity:1.;"/>
-<stop offset="1" style="stop-color:green;stop-opacity:1.;"/>
-</linearGradient>
-</defs>
-<polygon fill="url(#l_0)" stroke="none" points="698.38,-273.4 698.38,-291.9 733.38,-291.9 733.38,-273.4 698.38,-273.4"/>
-<polygon fill="none" stroke="black" points="698.38,-273.4 698.38,-291.9 733.38,-291.9 733.38,-273.4 698.38,-273.4"/>
-<text text-anchor="start" x="699.38" y="-277.6" font-family="Times New Roman,serif" font-size="14.00">int/ptr</text>
-</g>
-<!-- STRUCT_TOP&#45;&gt;STRUCT_S1 -->
-<g id="edge37" class="edge">
-<title>STRUCT_TOP&#45;&gt;STRUCT_S1</title>
-<path fill="none" stroke="black" d="M742.68,-474.51C735.02,-437.92 717.75,-355.45 708.55,-311.5"/>
-<polygon fill="black" stroke="black" points="712.02,-311 706.54,-301.93 705.17,-312.43 712.02,-311"/>
-</g>
-<!-- STRUCT_S2 -->
-<g id="node27" class="node">
-<title>STRUCT_S2</title>
-<polygon fill="none" stroke="none" points="841.38,-309.15 755.63,-309.15 755.63,-256.15 841.38,-256.15 841.38,-309.15"/>
-<polygon fill="lightgreen" stroke="none" points="763.63,-282.65 763.63,-305.15 794.38,-305.15 794.38,-282.65 763.63,-282.65"/>
-<polygon fill="none" stroke="black" points="763.63,-282.65 763.63,-305.15 794.38,-305.15 794.38,-282.65 763.63,-282.65"/>
-<text text-anchor="start" x="766.63" y="-288.85" font-family="Times New Roman,serif" font-size="14.00">field</text>
-<defs>
-<linearGradient id="l_1" gradientUnits="userSpaceOnUse" x1="800.1" y1="-301.86" x2="827.67" y2="-285.95" >
-<stop offset="0" style="stop-color:lightblue;stop-opacity:1.;"/>
-<stop offset="1" style="stop-color:green;stop-opacity:1.;"/>
-</linearGradient>
-</defs>
-<polygon fill="url(#l_1)" stroke="none" points="794.38,-282.65 794.38,-305.15 833.38,-305.15 833.38,-282.65 794.38,-282.65"/>
-<polygon fill="none" stroke="black" points="794.38,-282.65 794.38,-305.15 833.38,-305.15 833.38,-282.65 794.38,-282.65"/>
-<text text-anchor="start" x="797.38" y="-288.85" font-family="Times New Roman,serif" font-size="14.00">int/ptr</text>
-<polygon fill="lightgreen" stroke="none" points="763.63,-260.15 763.63,-282.65 794.38,-282.65 794.38,-260.15 763.63,-260.15"/>
-<polygon fill="none" stroke="black" points="763.63,-260.15 763.63,-282.65 794.38,-282.65 794.38,-260.15 763.63,-260.15"/>
-<text text-anchor="start" x="766.63" y="-266.35" font-family="Times New Roman,serif" font-size="14.00">field</text>
-<defs>
-<linearGradient id="l_2" gradientUnits="userSpaceOnUse" x1="800.1" y1="-279.36" x2="827.67" y2="-263.45" >
-<stop offset="0" style="stop-color:lightblue;stop-opacity:1.;"/>
-<stop offset="1" style="stop-color:green;stop-opacity:1.;"/>
-</linearGradient>
-</defs>
-<polygon fill="url(#l_2)" stroke="none" points="794.38,-260.15 794.38,-282.65 833.38,-282.65 833.38,-260.15 794.38,-260.15"/>
-<polygon fill="none" stroke="black" points="794.38,-260.15 794.38,-282.65 833.38,-282.65 833.38,-260.15 794.38,-260.15"/>
-<text text-anchor="start" x="797.38" y="-266.35" font-family="Times New Roman,serif" font-size="14.00">int/ptr</text>
-</g>
-<!-- STRUCT_TOP&#45;&gt;STRUCT_S2 -->
-<g id="edge38" class="edge">
-<title>STRUCT_TOP&#45;&gt;STRUCT_S2</title>
-<path fill="none" stroke="black" d="M751.03,-474.51C759.53,-440.16 778.05,-365.34 789.28,-319.95"/>
-<polygon fill="black" stroke="black" points="792.67,-320.83 791.67,-310.28 785.87,-319.15 792.67,-320.83"/>
-</g>
-<!-- STRUCT_SN -->
-<g id="node28" class="node">
-<title>STRUCT_SN</title>
-<polygon fill="none" stroke="none" points="941.38,-320.4 855.63,-320.4 855.63,-244.9 941.38,-244.9 941.38,-320.4"/>
-<polygon fill="lightgreen" stroke="none" points="863.63,-293.9 863.63,-316.4 894.38,-316.4 894.38,-293.9 863.63,-293.9"/>
-<polygon fill="none" stroke="black" points="863.63,-293.9 863.63,-316.4 894.38,-316.4 894.38,-293.9 863.63,-293.9"/>
-<text text-anchor="start" x="866.63" y="-300.1" font-family="Times New Roman,serif" font-size="14.00">field</text>
-<defs>
-<linearGradient id="l_3" gradientUnits="userSpaceOnUse" x1="900.1" y1="-313.11" x2="927.67" y2="-297.2" >
-<stop offset="0" style="stop-color:lightblue;stop-opacity:1.;"/>
-<stop offset="1" style="stop-color:green;stop-opacity:1.;"/>
-</linearGradient>
-</defs>
-<polygon fill="url(#l_3)" stroke="none" points="894.38,-293.9 894.38,-316.4 933.38,-316.4 933.38,-293.9 894.38,-293.9"/>
-<polygon fill="none" stroke="black" points="894.38,-293.9 894.38,-316.4 933.38,-316.4 933.38,-293.9 894.38,-293.9"/>
-<text text-anchor="start" x="897.38" y="-300.1" font-family="Times New Roman,serif" font-size="14.00">int/ptr</text>
-<polygon fill="lightgreen" stroke="none" points="863.63,-271.4 863.63,-293.9 894.38,-293.9 894.38,-271.4 863.63,-271.4"/>
-<polygon fill="none" stroke="black" points="863.63,-271.4 863.63,-293.9 894.38,-293.9 894.38,-271.4 863.63,-271.4"/>
-<text text-anchor="start" x="869.63" y="-277.6" font-family="Times New Roman,serif" font-size="14.00">... &#160;</text>
-<defs>
-<linearGradient id="l_4" gradientUnits="userSpaceOnUse" x1="900.1" y1="-290.61" x2="927.67" y2="-274.7" >
-<stop offset="0" style="stop-color:lightblue;stop-opacity:1.;"/>
-<stop offset="1" style="stop-color:green;stop-opacity:1.;"/>
-</linearGradient>
-</defs>
-<polygon fill="url(#l_4)" stroke="none" points="894.38,-271.4 894.38,-293.9 933.38,-293.9 933.38,-271.4 894.38,-271.4"/>
-<polygon fill="none" stroke="black" points="894.38,-271.4 894.38,-293.9 933.38,-293.9 933.38,-271.4 894.38,-271.4"/>
-<text text-anchor="start" x="897.38" y="-277.6" font-family="Times New Roman,serif" font-size="14.00">int/ptr</text>
-<polygon fill="lightgreen" stroke="none" points="863.63,-248.9 863.63,-271.4 894.38,-271.4 894.38,-248.9 863.63,-248.9"/>
-<polygon fill="none" stroke="black" points="863.63,-248.9 863.63,-271.4 894.38,-271.4 894.38,-248.9 863.63,-248.9"/>
-<text text-anchor="start" x="866.63" y="-255.1" font-family="Times New Roman,serif" font-size="14.00">field</text>
-<defs>
-<linearGradient id="l_5" gradientUnits="userSpaceOnUse" x1="900.1" y1="-268.11" x2="927.67" y2="-252.2" >
-<stop offset="0" style="stop-color:lightblue;stop-opacity:1.;"/>
-<stop offset="1" style="stop-color:green;stop-opacity:1.;"/>
-</linearGradient>
-</defs>
-<polygon fill="url(#l_5)" stroke="none" points="894.38,-248.9 894.38,-271.4 933.38,-271.4 933.38,-248.9 894.38,-248.9"/>
-<polygon fill="none" stroke="black" points="894.38,-248.9 894.38,-271.4 933.38,-271.4 933.38,-248.9 894.38,-248.9"/>
-<text text-anchor="start" x="897.38" y="-255.1" font-family="Times New Roman,serif" font-size="14.00">int/ptr</text>
-</g>
-<!-- STRUCT_TOP&#45;&gt;STRUCT_SN -->
-<g id="edge39" class="edge">
-<title>STRUCT_TOP&#45;&gt;STRUCT_SN</title>
-<path fill="none" stroke="black" d="M759.21,-475.24C782.17,-443.49 831.3,-375.56 864.63,-329.48"/>
-<polygon fill="black" stroke="black" points="867.37,-331.67 870.4,-321.52 861.7,-327.57 867.37,-331.67"/>
-</g>
-<!-- STRUCT_BOT -->
-<g id="node25" class="node">
-<title>STRUCT_BOT</title>
-<ellipse fill="lightgreen" stroke="black" cx="751.51" cy="-82.75" rx="44.7" ry="18"/>
-<text text-anchor="start" x="726.76" y="-78.7" font-family="Times New Roman,serif" font-weight="bold" font-size="14.00">⊥</text>
-<text text-anchor="start" x="742.51" y="-78.7" font-family="Times New Roman,serif" font-size="14.00">:struct</text>
-</g>
-<!-- STRUCT_BOT&#45;&gt;BOT -->
-<g id="edge43" class="edge">
-<title>STRUCT_BOT&#45;&gt;BOT</title>
-<path fill="none" stroke="black" d="M725.72,-67.77C709,-58.7 687.2,-46.89 669.97,-37.55"/>
-<polygon fill="black" stroke="black" points="671.71,-34.51 661.25,-32.82 668.37,-40.67 671.71,-34.51"/>
-</g>
-<!-- STRUCT_S1&#45;&gt;STRUCT_BOT -->
-<g id="edge40" class="edge">
-<title>STRUCT_S1&#45;&gt;STRUCT_BOT</title>
-<path fill="none" stroke="black" d="M706.86,-264.91C715.3,-230.49 733.97,-154.31 744.29,-112.19"/>
-<polygon fill="black" stroke="black" points="747.69,-113.04 746.67,-102.5 740.89,-111.37 747.69,-113.04"/>
-</g>
-<!-- STRUCT_S1&#45;&gt;STRUCT_S2 -->
-<!-- STRUCT_S2&#45;&gt;STRUCT_BOT -->
-<g id="edge41" class="edge">
-<title>STRUCT_S2&#45;&gt;STRUCT_BOT</title>
-<path fill="none" stroke="black" d="M792.36,-256.52C783.62,-219.3 767.61,-151.25 758.45,-112.26"/>
-<polygon fill="black" stroke="black" points="761.88,-111.57 756.18,-102.64 755.07,-113.17 761.88,-111.57"/>
-</g>
-<!-- STRUCT_S2&#45;&gt;STRUCT_SN -->
-<!-- STRUCT_SN&#45;&gt;STRUCT_BOT -->
-<g id="edge42" class="edge">
-<title>STRUCT_SN&#45;&gt;STRUCT_BOT</title>
-<path fill="none" stroke="black" d="M870.86,-245.05C841.74,-205.46 796.64,-144.13 771.03,-109.3"/>
-<polygon fill="black" stroke="black" points="773.99,-107.42 765.25,-101.44 768.36,-111.57 773.99,-107.42"/>
-</g>
-<!-- MEM_ALIAS1 -->
-<g id="node31" class="node">
-<title>MEM_ALIAS1</title>
-<ellipse fill="blue" stroke="black" cx="975.51" cy="-282.65" rx="20.13" ry="20.13"/>
-<text text-anchor="middle" x="975.51" y="-277.6" font-family="Times New Roman,serif" font-size="14.00" fill="white">#1</text>
-</g>
-<!-- MEM_TOP&#45;&gt;MEM_ALIAS1 -->
-<g id="edge47" class="edge">
-<title>MEM_TOP&#45;&gt;MEM_ALIAS1</title>
-<path fill="none" stroke="black" d="M996.51,-474.51C992.58,-438.66 983.84,-358.73 978.96,-314.18"/>
-<polygon fill="black" stroke="black" points="982.45,-313.94 977.89,-304.38 975.5,-314.7 982.45,-313.94"/>
-</g>
-<!-- MEM_ALIASDOTS -->
-<g id="node32" class="node">
-<title>MEM_ALIASDOTS</title>
-<ellipse fill="blue" stroke="black" cx="1036.51" cy="-282.65" rx="27" ry="18"/>
-<text text-anchor="middle" x="1036.51" y="-277.6" font-family="Times New Roman,serif" font-size="14.00" fill="white">...</text>
-</g>
-<!-- MEM_TOP&#45;&gt;MEM_ALIASDOTS -->
-<g id="edge48" class="edge">
-<title>MEM_TOP&#45;&gt;MEM_ALIASDOTS</title>
-<path fill="none" stroke="black" d="M1001.81,-474.51C1008.41,-438.02 1023.27,-355.86 1031.23,-311.83"/>
-<polygon fill="black" stroke="black" points="1034.63,-312.69 1032.97,-302.23 1027.74,-311.45 1034.63,-312.69"/>
-</g>
-<!-- MEM_ALIASN -->
-<g id="node33" class="node">
-<title>MEM_ALIASN</title>
-<ellipse fill="blue" stroke="black" cx="1097.51" cy="-282.65" rx="20.13" ry="20.13"/>
-<text text-anchor="middle" x="1097.51" y="-277.6" font-family="Times New Roman,serif" font-size="14.00" fill="white">#n</text>
-</g>
-<!-- MEM_TOP&#45;&gt;MEM_ALIASN -->
-<g id="edge49" class="edge">
-<title>MEM_TOP&#45;&gt;MEM_ALIASN</title>
-<path fill="none" stroke="black" d="M1006.95,-474.88C1024.11,-438.46 1063.18,-355.52 1083.95,-311.44"/>
-<polygon fill="black" stroke="black" points="1087.07,-313.03 1088.16,-302.49 1080.73,-310.05 1087.07,-313.03"/>
-</g>
-<!-- MEM_BOT -->
-<g id="node30" class="node">
-<title>MEM_BOT</title>
-<ellipse fill="blue" stroke="black" cx="998.51" cy="-82.75" rx="43.67" ry="18"/>
-<text text-anchor="start" x="974.51" y="-78.7" font-family="Times New Roman,serif" font-weight="bold" font-size="14.00" fill="white">⊥</text>
-<text text-anchor="start" x="990.26" y="-78.7" font-family="Times New Roman,serif" font-size="14.00" fill="white">:mem</text>
-</g>
-<!-- MEM_BOT&#45;&gt;BOT -->
-<g id="edge53" class="edge">
-<title>MEM_BOT&#45;&gt;BOT</title>
-<path fill="none" stroke="black" d="M958.6,-75.08C887.17,-63.15 738.86,-38.38 673.56,-27.48"/>
-<polygon fill="black" stroke="black" points="674.3,-24.05 663.86,-25.86 673.15,-30.96 674.3,-24.05"/>
-</g>
-<!-- MEM_ALIAS1&#45;&gt;MEM_BOT -->
-<g id="edge50" class="edge">
-<title>MEM_ALIAS1&#45;&gt;MEM_BOT</title>
-<path fill="none" stroke="black" d="M977.84,-262.38C981.92,-226.96 990.35,-153.62 995.09,-112.45"/>
-<polygon fill="black" stroke="black" points="998.57,-112.87 996.23,-102.53 991.61,-112.07 998.57,-112.87"/>
-</g>
-<!-- MEM_ALIAS1&#45;&gt;MEM_ALIASDOTS -->
-<!-- MEM_ALIASDOTS&#45;&gt;MEM_BOT -->
-<g id="edge51" class="edge">
-<title>MEM_ALIASDOTS&#45;&gt;MEM_BOT</title>
-<path fill="none" stroke="black" d="M1033.07,-264.56C1026.49,-229.93 1012.06,-154.01 1004.08,-112.06"/>
-<polygon fill="black" stroke="black" points="1007.56,-111.6 1002.25,-102.43 1000.68,-112.91 1007.56,-111.6"/>
-</g>
-<!-- MEM_ALIASDOTS&#45;&gt;MEM_ALIASN -->
-<!-- MEM_ALIASN&#45;&gt;MEM_BOT -->
-<g id="edge52" class="edge">
-<title>MEM_ALIASN&#45;&gt;MEM_BOT</title>
-<path fill="none" stroke="black" d="M1088.37,-264.2C1070.97,-229.07 1032.98,-152.35 1012.41,-110.82"/>
-<polygon fill="black" stroke="black" points="1015.58,-109.34 1008.01,-101.93 1009.31,-112.45 1015.58,-109.34"/>
-</g>
-<!-- TUPLE1 -->
-<g id="node36" class="node">
-<title>TUPLE1</title>
-<polygon fill="none" stroke="none" points="1185.51,-309.15 1131.51,-309.15 1131.51,-256.15 1185.51,-256.15 1185.51,-309.15"/>
-<polygon fill="pink" stroke="none" points="1139.76,-282.65 1139.76,-305.15 1177.26,-305.15 1177.26,-282.65 1139.76,-282.65"/>
-<polygon fill="none" stroke="black" points="1139.76,-282.65 1139.76,-305.15 1177.26,-305.15 1177.26,-282.65 1139.76,-282.65"/>
-<text text-anchor="start" x="1142.76" y="-288.85" font-family="Times New Roman,serif" font-size="14.00">Tuple</text>
-<polygon fill="black" stroke="none" points="1139.76,-260.15 1139.76,-282.65 1177.26,-282.65 1177.26,-260.15 1139.76,-260.15"/>
-<polygon fill="none" stroke="black" points="1139.76,-260.15 1139.76,-282.65 1177.26,-282.65 1177.26,-260.15 1139.76,-260.15"/>
-<text text-anchor="start" x="1146.88" y="-266.35" font-family="Times New Roman,serif" font-size="14.00" fill="white">type</text>
-</g>
-<!-- TUPLE_TOP&#45;&gt;TUPLE1 -->
-<g id="edge57" class="edge">
-<title>TUPLE_TOP&#45;&gt;TUPLE1</title>
-<path fill="none" stroke="black" d="M1180.42,-474.51C1176.51,-440.23 1167.99,-365.66 1162.8,-320.24"/>
-<polygon fill="black" stroke="black" points="1166.28,-319.86 1161.67,-310.32 1159.33,-320.65 1166.28,-319.86"/>
-</g>
-<!-- TUPLE2 -->
-<g id="node37" class="node">
-<title>TUPLE2</title>
-<polygon fill="none" stroke="none" points="1253.51,-320.4 1199.51,-320.4 1199.51,-244.9 1253.51,-244.9 1253.51,-320.4"/>
-<polygon fill="pink" stroke="none" points="1207.76,-293.9 1207.76,-316.4 1245.26,-316.4 1245.26,-293.9 1207.76,-293.9"/>
-<polygon fill="none" stroke="black" points="1207.76,-293.9 1207.76,-316.4 1245.26,-316.4 1245.26,-293.9 1207.76,-293.9"/>
-<text text-anchor="start" x="1210.76" y="-300.1" font-family="Times New Roman,serif" font-size="14.00">Tuple</text>
-<polygon fill="black" stroke="none" points="1207.76,-271.4 1207.76,-293.9 1245.26,-293.9 1245.26,-271.4 1207.76,-271.4"/>
-<polygon fill="none" stroke="black" points="1207.76,-271.4 1207.76,-293.9 1245.26,-293.9 1245.26,-271.4 1207.76,-271.4"/>
-<text text-anchor="start" x="1214.88" y="-277.6" font-family="Times New Roman,serif" font-size="14.00" fill="white">type</text>
-<polygon fill="black" stroke="none" points="1207.76,-248.9 1207.76,-271.4 1245.26,-271.4 1245.26,-248.9 1207.76,-248.9"/>
-<polygon fill="none" stroke="black" points="1207.76,-248.9 1207.76,-271.4 1245.26,-271.4 1245.26,-248.9 1207.76,-248.9"/>
-<text text-anchor="start" x="1214.88" y="-255.1" font-family="Times New Roman,serif" font-size="14.00" fill="white">type</text>
-</g>
-<!-- TUPLE_TOP&#45;&gt;TUPLE2 -->
-<g id="edge58" class="edge">
-<title>TUPLE_TOP&#45;&gt;TUPLE2</title>
-<path fill="none" stroke="black" d="M1186.34,-474.51C1192.95,-442.94 1206.72,-377.19 1216.28,-331.51"/>
-<polygon fill="black" stroke="black" points="1219.68,-332.35 1218.3,-321.85 1212.83,-330.92 1219.68,-332.35"/>
-</g>
-<!-- TUPLEN -->
-<g id="node38" class="node">
-<title>TUPLEN</title>
-<polygon fill="none" stroke="none" points="1321.51,-331.65 1267.51,-331.65 1267.51,-233.65 1321.51,-233.65 1321.51,-331.65"/>
-<polygon fill="pink" stroke="none" points="1275.76,-305.15 1275.76,-327.65 1313.26,-327.65 1313.26,-305.15 1275.76,-305.15"/>
-<polygon fill="none" stroke="black" points="1275.76,-305.15 1275.76,-327.65 1313.26,-327.65 1313.26,-305.15 1275.76,-305.15"/>
-<text text-anchor="start" x="1278.76" y="-311.35" font-family="Times New Roman,serif" font-size="14.00">Tuple</text>
-<polygon fill="black" stroke="none" points="1275.76,-282.65 1275.76,-305.15 1313.26,-305.15 1313.26,-282.65 1275.76,-282.65"/>
-<polygon fill="none" stroke="black" points="1275.76,-282.65 1275.76,-305.15 1313.26,-305.15 1313.26,-282.65 1275.76,-282.65"/>
-<text text-anchor="start" x="1282.88" y="-288.85" font-family="Times New Roman,serif" font-size="14.00" fill="white">type</text>
-<polygon fill="black" stroke="none" points="1275.76,-260.15 1275.76,-282.65 1313.26,-282.65 1313.26,-260.15 1275.76,-260.15"/>
-<polygon fill="none" stroke="black" points="1275.76,-260.15 1275.76,-282.65 1313.26,-282.65 1313.26,-260.15 1275.76,-260.15"/>
-<text text-anchor="start" x="1288.88" y="-266.35" font-family="Times New Roman,serif" font-size="14.00" fill="white">...</text>
-<polygon fill="black" stroke="none" points="1275.76,-237.65 1275.76,-260.15 1313.26,-260.15 1313.26,-237.65 1275.76,-237.65"/>
-<polygon fill="none" stroke="black" points="1275.76,-237.65 1275.76,-260.15 1313.26,-260.15 1313.26,-237.65 1275.76,-237.65"/>
-<text text-anchor="start" x="1282.88" y="-243.85" font-family="Times New Roman,serif" font-size="14.00" fill="white">type</text>
-</g>
-<!-- TUPLE_TOP&#45;&gt;TUPLEN -->
-<g id="edge59" class="edge">
-<title>TUPLE_TOP&#45;&gt;TUPLEN</title>
-<path fill="none" stroke="black" d="M1192.06,-474.88C1207.65,-445.62 1239.24,-386.36 1263.24,-341.32"/>
-<polygon fill="black" stroke="black" points="1266.22,-343.18 1267.83,-332.71 1260.04,-339.88 1266.22,-343.18"/>
-</g>
-<!-- TUPLE_BOT -->
-<g id="node35" class="node">
-<title>TUPLE_BOT</title>
-<ellipse fill="pink" stroke="black" cx="1192.51" cy="-82.75" rx="42.65" ry="18"/>
-<text text-anchor="start" x="1169.26" y="-78.7" font-family="Times New Roman,serif" font-weight="bold" font-size="14.00">⊥</text>
-<text text-anchor="start" x="1185.01" y="-78.7" font-family="Times New Roman,serif" font-size="14.00">:tuple</text>
-</g>
-<!-- TUPLE_BOT&#45;&gt;BOT -->
-<g id="edge63" class="edge">
-<title>TUPLE_BOT&#45;&gt;BOT</title>
-<path fill="none" stroke="black" d="M1151.54,-77.32C1046.53,-65.95 769.32,-35.95 674.14,-25.65"/>
-<polygon fill="black" stroke="black" points="674.52,-22.18 664.2,-24.58 673.77,-29.14 674.52,-22.18"/>
-</g>
-<!-- TUPLE1&#45;&gt;TUPLE_BOT -->
-<g id="edge60" class="edge">
-<title>TUPLE1&#45;&gt;TUPLE_BOT</title>
-<path fill="none" stroke="black" d="M1162.95,-256.52C1169.28,-219.3 1180.86,-151.25 1187.49,-112.26"/>
-<polygon fill="black" stroke="black" points="1190.9,-113.1 1189.12,-102.66 1184,-111.93 1190.9,-113.1"/>
-</g>
-<!-- TUPLE2&#45;&gt;TUPLE_BOT -->
-<g id="edge61" class="edge">
-<title>TUPLE2&#45;&gt;TUPLE_BOT</title>
-<path fill="none" stroke="black" d="M1220.11,-245.05C1213.55,-206.44 1203.46,-147.16 1197.47,-111.94"/>
-<polygon fill="black" stroke="black" points="1200.99,-111.74 1195.86,-102.47 1194.09,-112.92 1200.99,-111.74"/>
-</g>
-<!-- TUPLEN&#45;&gt;TUPLE_BOT -->
-<g id="edge62" class="edge">
-<title>TUPLEN&#45;&gt;TUPLE_BOT</title>
-<path fill="none" stroke="black" d="M1269.56,-233.75C1249.85,-195.12 1223.04,-142.58 1206.8,-110.75"/>
-<polygon fill="black" stroke="black" points="1210.07,-109.46 1202.41,-102.15 1203.83,-112.65 1210.07,-109.46"/>
-</g>
-</g>
-</svg>
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
+ "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+<!-- Generated by graphviz version 12.2.0 (20241103.1931)
+ -->
+<!-- Title: Lattice Pages: 1 -->
+<svg width="1330pt" height="584pt"
+ viewBox="0.00 0.00 1329.51 583.54" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
+<g id="graph0" class="graph" transform="scale(1 1) rotate(0) translate(4 579.54)">
+<title>Lattice</title>
+<polygon fill="white" stroke="none" points="-4,4 -4,-579.54 1325.51,-579.54 1325.51,4 -4,4"/>
+<!-- TOP -->
+<g id="node1" class="node">
+<title>TOP</title>
+<ellipse fill="black" stroke="black" cx="641.51" cy="-554.42" rx="21.12" ry="21.12"/>
+<text text-anchor="start" x="633.63" y="-549.99" font-family="Times New Roman,serif" font-weight="bold" font-size="14.00" fill="white">⊤</text>
+</g>
+<!-- XCTRL -->
+<g id="node3" class="node">
+<title>XCTRL</title>
+<ellipse fill="yellow" stroke="black" cx="36.51" cy="-492.79" rx="36.51" ry="18"/>
+<text text-anchor="start" x="17.76" y="-488.74" font-family="Times New Roman,serif" font-weight="bold" font-size="14.00">⊤</text>
+<text text-anchor="start" x="33.51" y="-488.74" font-family="Times New Roman,serif" font-size="14.00">:ctrl</text>
+</g>
+<!-- TOP&#45;&gt;XCTRL -->
+<g id="edge1" class="edge">
+<title>TOP&#45;&gt;XCTRL</title>
+<path fill="none" stroke="black" d="M620.33,-551.33C533.82,-542.8 206.01,-510.5 83.28,-498.4"/>
+<polygon fill="black" stroke="black" points="83.86,-494.94 73.56,-497.44 83.17,-501.91 83.86,-494.94"/>
+</g>
+<!-- INT_TOP -->
+<g id="node5" class="node">
+<title>INT_TOP</title>
+<ellipse fill="lightblue" stroke="black" cx="316.51" cy="-492.79" rx="33.95" ry="18"/>
+<text text-anchor="start" x="299.63" y="-488.74" font-family="Times New Roman,serif" font-weight="bold" font-size="14.00">⊤</text>
+<text text-anchor="start" x="315.38" y="-488.74" font-family="Times New Roman,serif" font-size="14.00">:int</text>
+</g>
+<!-- TOP&#45;&gt;INT_TOP -->
+<g id="edge4" class="edge">
+<title>TOP&#45;&gt;INT_TOP</title>
+<path fill="none" stroke="black" d="M620.68,-549.6C568.33,-539.99 430.36,-514.68 359.64,-501.71"/>
+<polygon fill="black" stroke="black" points="360.44,-498.29 349.97,-499.93 359.18,-505.18 360.44,-498.29"/>
+</g>
+<!-- FLT_TOP -->
+<g id="node14" class="node">
+<title>FLT_TOP</title>
+<ellipse fill="aqua" stroke="black" cx="494.51" cy="-492.79" rx="32.41" ry="18"/>
+<text text-anchor="start" x="478.76" y="-488.74" font-family="Times New Roman,serif" font-weight="bold" font-size="14.00">⊤</text>
+<text text-anchor="start" x="494.51" y="-488.74" font-family="Times New Roman,serif" font-size="14.00">:flt</text>
+</g>
+<!-- TOP&#45;&gt;FLT_TOP -->
+<g id="edge18" class="edge">
+<title>TOP&#45;&gt;FLT_TOP</title>
+<path fill="none" stroke="black" d="M621.99,-545.5C598.79,-536.09 559.6,-520.19 530.78,-508.5"/>
+<polygon fill="black" stroke="black" points="532.29,-505.34 521.7,-504.82 529.65,-511.82 532.29,-505.34"/>
+</g>
+<!-- PTR -->
+<g id="node22" class="node">
+<title>PTR</title>
+<polygon fill="none" stroke="none" points="668.51,-519.29 614.51,-519.29 614.51,-466.29 668.51,-466.29 668.51,-519.29"/>
+<polygon fill="green" stroke="none" points="623.51,-492.79 623.51,-515.29 659.51,-515.29 659.51,-492.79 623.51,-492.79"/>
+<polygon fill="none" stroke="black" points="623.51,-492.79 623.51,-515.29 659.51,-515.29 659.51,-492.79 623.51,-492.79"/>
+<text text-anchor="start" x="630.63" y="-498.99" font-family="Times New Roman,serif" font-size="14.00" fill="white">*ptr</text>
+<polygon fill="lightgreen" stroke="none" points="623.51,-470.29 623.51,-492.79 659.51,-492.79 659.51,-470.29 623.51,-470.29"/>
+<polygon fill="none" stroke="black" points="623.51,-470.29 623.51,-492.79 659.51,-492.79 659.51,-470.29 623.51,-470.29"/>
+<text text-anchor="start" x="626.51" y="-476.49" font-family="Times New Roman,serif" font-size="14.00">struct</text>
+</g>
+<!-- TOP&#45;&gt;PTR -->
+<g id="edge33" class="edge">
+<title>TOP&#45;&gt;PTR</title>
+<path fill="none" stroke="black" d="M641.51,-532.9C641.51,-532.06 641.51,-531.22 641.51,-530.37"/>
+<polygon fill="black" stroke="black" points="645.01,-530.61 641.51,-520.61 638.01,-530.61 645.01,-530.61"/>
+</g>
+<!-- STRUCT_TOP -->
+<g id="node24" class="node">
+<title>STRUCT_TOP</title>
+<ellipse fill="lightgreen" stroke="black" cx="746.51" cy="-492.79" rx="44.7" ry="18"/>
+<text text-anchor="start" x="721.76" y="-488.74" font-family="Times New Roman,serif" font-weight="bold" font-size="14.00">⊤</text>
+<text text-anchor="start" x="737.51" y="-488.74" font-family="Times New Roman,serif" font-size="14.00">:struct</text>
+</g>
+<!-- TOP&#45;&gt;STRUCT_TOP -->
+<g id="edge36" class="edge">
+<title>TOP&#45;&gt;STRUCT_TOP</title>
+<path fill="none" stroke="black" d="M659.8,-543.03C674.04,-534.94 694.24,-523.47 711.55,-513.64"/>
+<polygon fill="black" stroke="black" points="713.07,-516.81 720.03,-508.83 709.61,-510.72 713.07,-516.81"/>
+</g>
+<!-- MEM_TOP -->
+<g id="node29" class="node">
+<title>MEM_TOP</title>
+<ellipse fill="blue" stroke="black" cx="998.51" cy="-492.79" rx="43.67" ry="18"/>
+<text text-anchor="start" x="974.51" y="-488.74" font-family="Times New Roman,serif" font-weight="bold" font-size="14.00" fill="white">⊤</text>
+<text text-anchor="start" x="990.26" y="-488.74" font-family="Times New Roman,serif" font-size="14.00" fill="white">:mem</text>
+</g>
+<!-- TOP&#45;&gt;MEM_TOP -->
+<g id="edge46" class="edge">
+<title>TOP&#45;&gt;MEM_TOP</title>
+<path fill="none" stroke="black" d="M662.51,-549.91C717.64,-540.7 867.72,-515.64 947.33,-502.34"/>
+<polygon fill="black" stroke="black" points="947.77,-505.82 957.06,-500.72 946.62,-498.91 947.77,-505.82"/>
+</g>
+<!-- TUPLE_TOP -->
+<g id="node34" class="node">
+<title>TUPLE_TOP</title>
+<ellipse fill="pink" stroke="black" cx="1182.51" cy="-492.79" rx="42.65" ry="18"/>
+<text text-anchor="start" x="1159.26" y="-488.74" font-family="Times New Roman,serif" font-weight="bold" font-size="14.00">⊤</text>
+<text text-anchor="start" x="1175.01" y="-488.74" font-family="Times New Roman,serif" font-size="14.00">:tuple</text>
+</g>
+<!-- TOP&#45;&gt;TUPLE_TOP -->
+<g id="edge56" class="edge">
+<title>TOP&#45;&gt;TUPLE_TOP</title>
+<path fill="none" stroke="black" d="M662.72,-551.08C740.91,-542.46 1014.51,-512.31 1130.21,-499.56"/>
+<polygon fill="black" stroke="black" points="1130.5,-503.05 1140.05,-498.47 1129.73,-496.09 1130.5,-503.05"/>
+</g>
+<!-- BOT -->
+<g id="node2" class="node">
+<title>BOT</title>
+<ellipse fill="black" stroke="black" cx="641.51" cy="-21.12" rx="21.12" ry="21.12"/>
+<text text-anchor="start" x="633.63" y="-16.7" font-family="Times New Roman,serif" font-weight="bold" font-size="14.00" fill="white">⊥</text>
+</g>
+<!-- CTRL -->
+<g id="node4" class="node">
+<title>CTRL</title>
+<ellipse fill="yellow" stroke="black" cx="49.51" cy="-82.75" rx="36.51" ry="18"/>
+<text text-anchor="start" x="30.76" y="-78.7" font-family="Times New Roman,serif" font-weight="bold" font-size="14.00">⊥</text>
+<text text-anchor="start" x="46.51" y="-78.7" font-family="Times New Roman,serif" font-size="14.00">:ctrl</text>
+</g>
+<!-- XCTRL&#45;&gt;CTRL -->
+<g id="edge2" class="edge">
+<title>XCTRL&#45;&gt;CTRL</title>
+<path fill="none" stroke="black" d="M37.09,-474.38C39.15,-409.6 46.05,-191.88 48.57,-112.25"/>
+<polygon fill="black" stroke="black" points="52.06,-112.73 48.88,-102.63 45.06,-112.51 52.06,-112.73"/>
+</g>
+<!-- CTRL&#45;&gt;BOT -->
+<g id="edge3" class="edge">
+<title>CTRL&#45;&gt;BOT</title>
+<path fill="none" stroke="black" d="M85.21,-78.15C191.74,-67.42 506.36,-35.74 608.84,-25.41"/>
+<polygon fill="black" stroke="black" points="609.15,-28.9 618.75,-24.42 608.45,-21.94 609.15,-28.9"/>
+</g>
+<!-- INT_HI -->
+<g id="node7" class="node">
+<title>INT_HI</title>
+<ellipse fill="lightblue" stroke="black" cx="174.51" cy="-434.29" rx="53.91" ry="18"/>
+<text text-anchor="middle" x="174.51" y="-429.24" font-family="Times New Roman,serif" font-size="14.00">[min&gt;max]</text>
+</g>
+<!-- INT_TOP&#45;&gt;INT_HI -->
+<g id="edge5" class="edge">
+<title>INT_TOP&#45;&gt;INT_HI</title>
+<path fill="none" stroke="black" d="M289.8,-481.17C269.89,-473.25 242.26,-462.25 219.03,-453.01"/>
+<polygon fill="black" stroke="black" points="220.37,-449.77 209.78,-449.33 217.78,-456.28 220.37,-449.77"/>
+</g>
+<!-- INT_BOT -->
+<g id="node6" class="node">
+<title>INT_BOT</title>
+<ellipse fill="lightblue" stroke="black" cx="329.51" cy="-82.75" rx="33.95" ry="18"/>
+<text text-anchor="start" x="312.63" y="-78.7" font-family="Times New Roman,serif" font-weight="bold" font-size="14.00">⊥</text>
+<text text-anchor="start" x="328.38" y="-78.7" font-family="Times New Roman,serif" font-size="14.00">:int</text>
+</g>
+<!-- INT_BOT&#45;&gt;BOT -->
+<g id="edge15" class="edge">
+<title>INT_BOT&#45;&gt;BOT</title>
+<path fill="none" stroke="black" d="M361.14,-75.7C420.84,-64.3 549.47,-39.71 609.47,-28.25"/>
+<polygon fill="black" stroke="black" points="609.86,-31.73 619.03,-26.42 608.55,-24.86 609.86,-31.73"/>
+</g>
+<!-- INT_XBOOL -->
+<g id="node8" class="node">
+<title>INT_XBOOL</title>
+<ellipse fill="lightblue" stroke="black" cx="97.51" cy="-373.97" rx="33.95" ry="18"/>
+<text text-anchor="middle" x="97.51" y="-368.92" font-family="Times New Roman,serif" font-size="14.00">[1...0]</text>
+</g>
+<!-- INT_HI&#45;&gt;INT_XBOOL -->
+<g id="edge6" class="edge">
+<title>INT_HI&#45;&gt;INT_XBOOL</title>
+<path fill="none" stroke="black" d="M153.47,-417.36C144.79,-410.78 134.6,-403.06 125.31,-396.03"/>
+<polygon fill="black" stroke="black" points="127.71,-393.46 117.63,-390.21 123.48,-399.04 127.71,-393.46"/>
+</g>
+<!-- INT_CON -->
+<g id="node9" class="node">
+<title>INT_CON</title>
+<ellipse fill="lightblue" stroke="black" cx="174.51" cy="-282.65" rx="45.21" ry="18"/>
+<text text-anchor="middle" x="174.51" y="-277.6" font-family="Times New Roman,serif" font-size="14.00">constants</text>
+</g>
+<!-- INT_HI&#45;&gt;INT_CON -->
+<g id="edge9" class="edge">
+<title>INT_HI&#45;&gt;INT_CON</title>
+<path fill="none" stroke="black" d="M174.51,-416C174.51,-390.27 174.51,-343.1 174.51,-312.31"/>
+<polygon fill="black" stroke="black" points="178.01,-312.52 174.51,-302.52 171.01,-312.52 178.01,-312.52"/>
+</g>
+<!-- INT_CON0 -->
+<g id="node10" class="node">
+<title>INT_CON0</title>
+<ellipse fill="lightblue" stroke="black" cx="47.51" cy="-282.65" rx="18" ry="18"/>
+<text text-anchor="middle" x="47.51" y="-277.6" font-family="Times New Roman,serif" font-size="14.00">0</text>
+</g>
+<!-- INT_XBOOL&#45;&gt;INT_CON0 -->
+<g id="edge7" class="edge">
+<title>INT_XBOOL&#45;&gt;INT_CON0</title>
+<path fill="none" stroke="black" d="M88.34,-356.59C80.82,-343.17 70.07,-323.96 61.49,-308.62"/>
+<polygon fill="black" stroke="black" points="64.63,-307.08 56.69,-300.06 58.53,-310.5 64.63,-307.08"/>
+</g>
+<!-- INT_CON1 -->
+<g id="node11" class="node">
+<title>INT_CON1</title>
+<ellipse fill="lightblue" stroke="black" cx="97.51" cy="-282.65" rx="18" ry="18"/>
+<text text-anchor="middle" x="97.51" y="-277.6" font-family="Times New Roman,serif" font-size="14.00">1</text>
+</g>
+<!-- INT_XBOOL&#45;&gt;INT_CON1 -->
+<g id="edge8" class="edge">
+<title>INT_XBOOL&#45;&gt;INT_CON1</title>
+<path fill="none" stroke="black" d="M97.51,-355.75C97.51,-343.47 97.51,-326.68 97.51,-312.39"/>
+<polygon fill="black" stroke="black" points="101.01,-312.64 97.51,-302.64 94.01,-312.64 101.01,-312.64"/>
+</g>
+<!-- INT_LO -->
+<g id="node13" class="node">
+<title>INT_LO</title>
+<ellipse fill="lightblue" stroke="black" cx="174.51" cy="-141.25" rx="53.91" ry="18"/>
+<text text-anchor="middle" x="174.51" y="-136.2" font-family="Times New Roman,serif" font-size="14.00">[min&lt;max]</text>
+</g>
+<!-- INT_CON&#45;&gt;INT_LO -->
+<g id="edge13" class="edge">
+<title>INT_CON&#45;&gt;INT_LO</title>
+<path fill="none" stroke="black" d="M174.51,-264.17C174.51,-240.45 174.51,-199.04 174.51,-170.9"/>
+<polygon fill="black" stroke="black" points="178.01,-171.25 174.51,-161.25 171.01,-171.25 178.01,-171.25"/>
+</g>
+<!-- INT_CON0&#45;&gt;INT_CON1 -->
+<!-- INT_BOOL -->
+<g id="node12" class="node">
+<title>INT_BOOL</title>
+<ellipse fill="lightblue" stroke="black" cx="97.51" cy="-196.45" rx="33.95" ry="18"/>
+<text text-anchor="middle" x="97.51" y="-191.4" font-family="Times New Roman,serif" font-size="14.00">[0...1]</text>
+</g>
+<!-- INT_CON0&#45;&gt;INT_BOOL -->
+<g id="edge10" class="edge">
+<title>INT_CON0&#45;&gt;INT_BOOL</title>
+<path fill="none" stroke="black" d="M56.45,-266.6C63.5,-254.72 73.51,-237.87 81.88,-223.77"/>
+<polygon fill="black" stroke="black" points="84.75,-225.79 86.85,-215.41 78.73,-222.22 84.75,-225.79"/>
+</g>
+<!-- INT_CON1&#45;&gt;INT_CON -->
+<!-- INT_CON1&#45;&gt;INT_BOOL -->
+<g id="edge11" class="edge">
+<title>INT_CON1&#45;&gt;INT_BOOL</title>
+<path fill="none" stroke="black" d="M97.51,-264.21C97.51,-253.25 97.51,-238.87 97.51,-226.25"/>
+<polygon fill="black" stroke="black" points="101.01,-226.39 97.51,-216.39 94.01,-226.39 101.01,-226.39"/>
+</g>
+<!-- INT_BOOL&#45;&gt;INT_LO -->
+<g id="edge12" class="edge">
+<title>INT_BOOL&#45;&gt;INT_LO</title>
+<path fill="none" stroke="black" d="M117.34,-181.75C124.98,-176.47 133.91,-170.3 142.42,-164.42"/>
+<polygon fill="black" stroke="black" points="144.27,-167.4 150.5,-158.83 140.29,-161.64 144.27,-167.4"/>
+</g>
+<!-- INT_LO&#45;&gt;INT_BOT -->
+<g id="edge14" class="edge">
+<title>INT_LO&#45;&gt;INT_BOT</title>
+<path fill="none" stroke="black" d="M210.07,-127.29C234.52,-118.37 266.93,-106.56 291.82,-97.49"/>
+<polygon fill="black" stroke="black" points="292.71,-100.89 300.91,-94.17 290.31,-94.31 292.71,-100.89"/>
+</g>
+<!-- FLT_CON64 -->
+<g id="node16" class="node">
+<title>FLT_CON64</title>
+<ellipse fill="aqua" stroke="black" cx="564.51" cy="-282.65" rx="55.33" ry="40.66"/>
+<text text-anchor="middle" x="564.51" y="-294.1" font-family="Times New Roman,serif" font-size="14.00">64b consts</text>
+<text text-anchor="middle" x="564.51" y="-277.6" font-family="Times New Roman,serif" font-size="14.00">[excludes</text>
+<text text-anchor="middle" x="564.51" y="-261.1" font-family="Times New Roman,serif" font-size="14.00">32b consts]</text>
+</g>
+<!-- FLT_TOP&#45;&gt;FLT_CON64 -->
+<g id="edge19" class="edge">
+<title>FLT_TOP&#45;&gt;FLT_CON64</title>
+<path fill="none" stroke="black" d="M500.48,-474.88C510.8,-443.88 532.35,-379.2 547.59,-333.44"/>
+<polygon fill="black" stroke="black" points="550.9,-334.57 550.74,-323.98 544.26,-332.36 550.9,-334.57"/>
+</g>
+<!-- FLT_CONPI -->
+<g id="node18" class="node">
+<title>FLT_CONPI</title>
+<ellipse fill="aqua" stroke="black" cx="446.51" cy="-282.65" rx="48.79" ry="18"/>
+<text text-anchor="middle" x="446.51" y="-277.6" font-family="Times New Roman,serif" font-size="14.00">3.14159...</text>
+</g>
+<!-- FLT_TOP&#45;&gt;FLT_CONPI -->
+<g id="edge20" class="edge">
+<title>FLT_TOP&#45;&gt;FLT_CONPI</title>
+<path fill="none" stroke="black" d="M490.33,-474.51C482.02,-438.11 463.32,-356.27 453.25,-312.16"/>
+<polygon fill="black" stroke="black" points="456.69,-311.49 451.05,-302.52 449.86,-313.04 456.69,-311.49"/>
+</g>
+<!-- FLT_X32 -->
+<g id="node19" class="node">
+<title>FLT_X32</title>
+<ellipse fill="aqua" stroke="black" cx="333.51" cy="-373.97" rx="28.32" ry="28.32"/>
+<text text-anchor="middle" x="333.51" y="-368.92" font-family="Times New Roman,serif" font-size="14.00">~f32</text>
+</g>
+<!-- FLT_TOP&#45;&gt;FLT_X32 -->
+<g id="edge23" class="edge">
+<title>FLT_TOP&#45;&gt;FLT_X32</title>
+<path fill="none" stroke="black" d="M474.77,-478.22C447.56,-458.14 398.22,-421.73 365.65,-397.69"/>
+<polygon fill="black" stroke="black" points="367.88,-394.99 357.75,-391.86 363.72,-400.62 367.88,-394.99"/>
+</g>
+<!-- FLT_BOT -->
+<g id="node15" class="node">
+<title>FLT_BOT</title>
+<ellipse fill="aqua" stroke="black" cx="507.51" cy="-82.75" rx="32.41" ry="18"/>
+<text text-anchor="start" x="491.76" y="-78.7" font-family="Times New Roman,serif" font-weight="bold" font-size="14.00">⊥</text>
+<text text-anchor="start" x="507.51" y="-78.7" font-family="Times New Roman,serif" font-size="14.00">:flt</text>
+</g>
+<!-- FLT_BOT&#45;&gt;BOT -->
+<g id="edge29" class="edge">
+<title>FLT_BOT&#45;&gt;BOT</title>
+<path fill="none" stroke="black" d="M532.4,-70.67C554.98,-60.63 588.29,-45.81 612.16,-35.19"/>
+<polygon fill="black" stroke="black" points="613.29,-38.51 621,-31.25 610.44,-32.12 613.29,-38.51"/>
+</g>
+<!-- FLT_CON64&#45;&gt;FLT_BOT -->
+<g id="edge21" class="edge">
+<title>FLT_CON64&#45;&gt;FLT_BOT</title>
+<path fill="none" stroke="black" d="M553.11,-242.68C542.05,-203.88 525.53,-145.95 515.71,-111.5"/>
+<polygon fill="black" stroke="black" points="519.17,-110.89 513.06,-102.23 512.44,-112.81 519.17,-110.89"/>
+</g>
+<!-- FLT_CON32 -->
+<g id="node17" class="node">
+<title>FLT_CON32</title>
+<ellipse fill="aqua" stroke="black" cx="333.51" cy="-282.65" rx="50.33" ry="18"/>
+<text text-anchor="middle" x="333.51" y="-277.6" font-family="Times New Roman,serif" font-size="14.00">32b consts</text>
+</g>
+<!-- FLT_CON32&#45;&gt;FLT_CONPI -->
+<!-- FLT_32 -->
+<g id="node21" class="node">
+<title>FLT_32</title>
+<ellipse fill="aqua" stroke="black" cx="333.51" cy="-196.45" rx="23.2" ry="23.2"/>
+<text text-anchor="middle" x="333.51" y="-191.4" font-family="Times New Roman,serif" font-size="14.00">f32</text>
+</g>
+<!-- FLT_CON32&#45;&gt;FLT_32 -->
+<g id="edge27" class="edge">
+<title>FLT_CON32&#45;&gt;FLT_32</title>
+<path fill="none" stroke="black" d="M333.51,-264.21C333.51,-254.7 333.51,-242.59 333.51,-231.31"/>
+<polygon fill="black" stroke="black" points="337.01,-231.51 333.51,-221.51 330.01,-231.51 337.01,-231.51"/>
+</g>
+<!-- FLT_CONPI&#45;&gt;FLT_BOT -->
+<g id="edge22" class="edge">
+<title>FLT_CONPI&#45;&gt;FLT_BOT</title>
+<path fill="none" stroke="black" d="M452.03,-264.56C462.62,-229.86 485.86,-153.69 498.65,-111.79"/>
+<polygon fill="black" stroke="black" points="501.94,-112.98 501.51,-102.39 495.25,-110.93 501.94,-112.98"/>
+</g>
+<!-- FLT_CONPI&#45;&gt;FLT_CON64 -->
+<!-- FLT_X32&#45;&gt;FLT_CON32 -->
+<g id="edge25" class="edge">
+<title>FLT_X32&#45;&gt;FLT_CON32</title>
+<path fill="none" stroke="black" d="M333.51,-345.2C333.51,-334.71 333.51,-322.76 333.51,-312.19"/>
+<polygon fill="black" stroke="black" points="337.01,-312.52 333.51,-302.52 330.01,-312.53 337.01,-312.52"/>
+</g>
+<!-- FLT_CON0 -->
+<g id="node20" class="node">
+<title>FLT_CON0</title>
+<ellipse fill="aqua" stroke="black" cx="251.51" cy="-282.65" rx="18.08" ry="18.08"/>
+<text text-anchor="middle" x="251.51" y="-277.6" font-family="Times New Roman,serif" font-size="14.00">0.</text>
+</g>
+<!-- FLT_X32&#45;&gt;FLT_CON0 -->
+<g id="edge24" class="edge">
+<title>FLT_X32&#45;&gt;FLT_CON0</title>
+<path fill="none" stroke="black" d="M314.9,-352.7C301.83,-338.47 284.38,-319.46 271.1,-304.99"/>
+<polygon fill="black" stroke="black" points="273.81,-302.77 264.47,-297.77 268.65,-307.5 273.81,-302.77"/>
+</g>
+<!-- FLT_CON0&#45;&gt;FLT_CON32 -->
+<!-- FLT_CON0&#45;&gt;FLT_32 -->
+<g id="edge26" class="edge">
+<title>FLT_CON0&#45;&gt;FLT_32</title>
+<path fill="none" stroke="black" d="M263.96,-268.86C276.06,-256.44 294.74,-237.26 309.69,-221.91"/>
+<polygon fill="black" stroke="black" points="312.03,-224.53 316.5,-214.92 307.01,-219.64 312.03,-224.53"/>
+</g>
+<!-- FLT_32&#45;&gt;FLT_BOT -->
+<g id="edge28" class="edge">
+<title>FLT_32&#45;&gt;FLT_BOT</title>
+<path fill="none" stroke="black" d="M353.13,-183.63C383.19,-163.99 440.9,-126.28 476.61,-102.94"/>
+<polygon fill="black" stroke="black" points="478.34,-105.99 484.79,-97.59 474.51,-100.13 478.34,-105.99"/>
+</g>
+<!-- PTR0 -->
+<g id="node23" class="node">
+<title>PTR0</title>
+<polygon fill="none" stroke="none" points="668.51,-109.25 614.51,-109.25 614.51,-56.25 668.51,-56.25 668.51,-109.25"/>
+<polygon fill="green" stroke="none" points="623.51,-82.75 623.51,-105.25 659.51,-105.25 659.51,-82.75 623.51,-82.75"/>
+<polygon fill="none" stroke="black" points="623.51,-82.75 623.51,-105.25 659.51,-105.25 659.51,-82.75 623.51,-82.75"/>
+<text text-anchor="start" x="627.63" y="-88.95" font-family="Times New Roman,serif" font-size="14.00" fill="white">*ptr?</text>
+<polygon fill="lightgreen" stroke="none" points="623.51,-60.25 623.51,-82.75 659.51,-82.75 659.51,-60.25 623.51,-60.25"/>
+<polygon fill="none" stroke="black" points="623.51,-60.25 623.51,-82.75 659.51,-82.75 659.51,-60.25 623.51,-60.25"/>
+<text text-anchor="start" x="626.51" y="-66.45" font-family="Times New Roman,serif" font-size="14.00">struct</text>
+</g>
+<!-- PTR&#45;&gt;PTR0 -->
+<g id="edge34" class="edge">
+<title>PTR&#45;&gt;PTR0</title>
+<path fill="none" stroke="black" d="M641.51,-466.52C641.51,-396.01 641.51,-202.44 641.51,-120.34"/>
+<polygon fill="black" stroke="black" points="645.01,-120.58 641.51,-110.58 638.01,-120.58 645.01,-120.58"/>
+</g>
+<!-- PTR0&#45;&gt;BOT -->
+<g id="edge35" class="edge">
+<title>PTR0&#45;&gt;BOT</title>
+<path fill="none" stroke="black" d="M641.51,-56.46C641.51,-55.58 641.51,-54.7 641.51,-53.81"/>
+<polygon fill="black" stroke="black" points="645.01,-53.9 641.51,-43.9 638.01,-53.9 645.01,-53.9"/>
+</g>
+<!-- STRUCT_S1 -->
+<g id="node26" class="node">
+<title>STRUCT_S1</title>
+<polygon fill="none" stroke="none" points="741.38,-300.65 663.63,-300.65 663.63,-264.65 741.38,-264.65 741.38,-300.65"/>
+<polygon fill="lightgreen" stroke="none" points="671.63,-273.4 671.63,-291.9 698.38,-291.9 698.38,-273.4 671.63,-273.4"/>
+<polygon fill="none" stroke="black" points="671.63,-273.4 671.63,-291.9 698.38,-291.9 698.38,-273.4 671.63,-273.4"/>
+<text text-anchor="start" x="672.63" y="-277.6" font-family="Times New Roman,serif" font-size="14.00">field</text>
+<defs>
+<linearGradient id="l_0" gradientUnits="userSpaceOnUse" x1="703.51" y1="-289.19" x2="728.26" y2="-276.11" >
+<stop offset="0" style="stop-color:lightblue;stop-opacity:1.;"/>
+<stop offset="1" style="stop-color:green;stop-opacity:1.;"/>
+</linearGradient>
+</defs>
+<polygon fill="url(#l_0)" stroke="none" points="698.38,-273.4 698.38,-291.9 733.38,-291.9 733.38,-273.4 698.38,-273.4"/>
+<polygon fill="none" stroke="black" points="698.38,-273.4 698.38,-291.9 733.38,-291.9 733.38,-273.4 698.38,-273.4"/>
+<text text-anchor="start" x="699.38" y="-277.6" font-family="Times New Roman,serif" font-size="14.00">int/ptr</text>
+</g>
+<!-- STRUCT_TOP&#45;&gt;STRUCT_S1 -->
+<g id="edge37" class="edge">
+<title>STRUCT_TOP&#45;&gt;STRUCT_S1</title>
+<path fill="none" stroke="black" d="M742.68,-474.51C735.02,-437.92 717.75,-355.45 708.55,-311.5"/>
+<polygon fill="black" stroke="black" points="712.02,-311 706.54,-301.93 705.17,-312.43 712.02,-311"/>
+</g>
+<!-- STRUCT_S2 -->
+<g id="node27" class="node">
+<title>STRUCT_S2</title>
+<polygon fill="none" stroke="none" points="841.38,-309.15 755.63,-309.15 755.63,-256.15 841.38,-256.15 841.38,-309.15"/>
+<polygon fill="lightgreen" stroke="none" points="763.63,-282.65 763.63,-305.15 794.38,-305.15 794.38,-282.65 763.63,-282.65"/>
+<polygon fill="none" stroke="black" points="763.63,-282.65 763.63,-305.15 794.38,-305.15 794.38,-282.65 763.63,-282.65"/>
+<text text-anchor="start" x="766.63" y="-288.85" font-family="Times New Roman,serif" font-size="14.00">field</text>
+<defs>
+<linearGradient id="l_1" gradientUnits="userSpaceOnUse" x1="800.1" y1="-301.86" x2="827.67" y2="-285.95" >
+<stop offset="0" style="stop-color:lightblue;stop-opacity:1.;"/>
+<stop offset="1" style="stop-color:green;stop-opacity:1.;"/>
+</linearGradient>
+</defs>
+<polygon fill="url(#l_1)" stroke="none" points="794.38,-282.65 794.38,-305.15 833.38,-305.15 833.38,-282.65 794.38,-282.65"/>
+<polygon fill="none" stroke="black" points="794.38,-282.65 794.38,-305.15 833.38,-305.15 833.38,-282.65 794.38,-282.65"/>
+<text text-anchor="start" x="797.38" y="-288.85" font-family="Times New Roman,serif" font-size="14.00">int/ptr</text>
+<polygon fill="lightgreen" stroke="none" points="763.63,-260.15 763.63,-282.65 794.38,-282.65 794.38,-260.15 763.63,-260.15"/>
+<polygon fill="none" stroke="black" points="763.63,-260.15 763.63,-282.65 794.38,-282.65 794.38,-260.15 763.63,-260.15"/>
+<text text-anchor="start" x="766.63" y="-266.35" font-family="Times New Roman,serif" font-size="14.00">field</text>
+<defs>
+<linearGradient id="l_2" gradientUnits="userSpaceOnUse" x1="800.1" y1="-279.36" x2="827.67" y2="-263.45" >
+<stop offset="0" style="stop-color:lightblue;stop-opacity:1.;"/>
+<stop offset="1" style="stop-color:green;stop-opacity:1.;"/>
+</linearGradient>
+</defs>
+<polygon fill="url(#l_2)" stroke="none" points="794.38,-260.15 794.38,-282.65 833.38,-282.65 833.38,-260.15 794.38,-260.15"/>
+<polygon fill="none" stroke="black" points="794.38,-260.15 794.38,-282.65 833.38,-282.65 833.38,-260.15 794.38,-260.15"/>
+<text text-anchor="start" x="797.38" y="-266.35" font-family="Times New Roman,serif" font-size="14.00">int/ptr</text>
+</g>
+<!-- STRUCT_TOP&#45;&gt;STRUCT_S2 -->
+<g id="edge38" class="edge">
+<title>STRUCT_TOP&#45;&gt;STRUCT_S2</title>
+<path fill="none" stroke="black" d="M751.03,-474.51C759.53,-440.16 778.05,-365.34 789.28,-319.95"/>
+<polygon fill="black" stroke="black" points="792.67,-320.83 791.67,-310.28 785.87,-319.15 792.67,-320.83"/>
+</g>
+<!-- STRUCT_SN -->
+<g id="node28" class="node">
+<title>STRUCT_SN</title>
+<polygon fill="none" stroke="none" points="941.38,-320.4 855.63,-320.4 855.63,-244.9 941.38,-244.9 941.38,-320.4"/>
+<polygon fill="lightgreen" stroke="none" points="863.63,-293.9 863.63,-316.4 894.38,-316.4 894.38,-293.9 863.63,-293.9"/>
+<polygon fill="none" stroke="black" points="863.63,-293.9 863.63,-316.4 894.38,-316.4 894.38,-293.9 863.63,-293.9"/>
+<text text-anchor="start" x="866.63" y="-300.1" font-family="Times New Roman,serif" font-size="14.00">field</text>
+<defs>
+<linearGradient id="l_3" gradientUnits="userSpaceOnUse" x1="900.1" y1="-313.11" x2="927.67" y2="-297.2" >
+<stop offset="0" style="stop-color:lightblue;stop-opacity:1.;"/>
+<stop offset="1" style="stop-color:green;stop-opacity:1.;"/>
+</linearGradient>
+</defs>
+<polygon fill="url(#l_3)" stroke="none" points="894.38,-293.9 894.38,-316.4 933.38,-316.4 933.38,-293.9 894.38,-293.9"/>
+<polygon fill="none" stroke="black" points="894.38,-293.9 894.38,-316.4 933.38,-316.4 933.38,-293.9 894.38,-293.9"/>
+<text text-anchor="start" x="897.38" y="-300.1" font-family="Times New Roman,serif" font-size="14.00">int/ptr</text>
+<polygon fill="lightgreen" stroke="none" points="863.63,-271.4 863.63,-293.9 894.38,-293.9 894.38,-271.4 863.63,-271.4"/>
+<polygon fill="none" stroke="black" points="863.63,-271.4 863.63,-293.9 894.38,-293.9 894.38,-271.4 863.63,-271.4"/>
+<text text-anchor="start" x="869.63" y="-277.6" font-family="Times New Roman,serif" font-size="14.00">... &#160;</text>
+<defs>
+<linearGradient id="l_4" gradientUnits="userSpaceOnUse" x1="900.1" y1="-290.61" x2="927.67" y2="-274.7" >
+<stop offset="0" style="stop-color:lightblue;stop-opacity:1.;"/>
+<stop offset="1" style="stop-color:green;stop-opacity:1.;"/>
+</linearGradient>
+</defs>
+<polygon fill="url(#l_4)" stroke="none" points="894.38,-271.4 894.38,-293.9 933.38,-293.9 933.38,-271.4 894.38,-271.4"/>
+<polygon fill="none" stroke="black" points="894.38,-271.4 894.38,-293.9 933.38,-293.9 933.38,-271.4 894.38,-271.4"/>
+<text text-anchor="start" x="897.38" y="-277.6" font-family="Times New Roman,serif" font-size="14.00">int/ptr</text>
+<polygon fill="lightgreen" stroke="none" points="863.63,-248.9 863.63,-271.4 894.38,-271.4 894.38,-248.9 863.63,-248.9"/>
+<polygon fill="none" stroke="black" points="863.63,-248.9 863.63,-271.4 894.38,-271.4 894.38,-248.9 863.63,-248.9"/>
+<text text-anchor="start" x="866.63" y="-255.1" font-family="Times New Roman,serif" font-size="14.00">field</text>
+<defs>
+<linearGradient id="l_5" gradientUnits="userSpaceOnUse" x1="900.1" y1="-268.11" x2="927.67" y2="-252.2" >
+<stop offset="0" style="stop-color:lightblue;stop-opacity:1.;"/>
+<stop offset="1" style="stop-color:green;stop-opacity:1.;"/>
+</linearGradient>
+</defs>
+<polygon fill="url(#l_5)" stroke="none" points="894.38,-248.9 894.38,-271.4 933.38,-271.4 933.38,-248.9 894.38,-248.9"/>
+<polygon fill="none" stroke="black" points="894.38,-248.9 894.38,-271.4 933.38,-271.4 933.38,-248.9 894.38,-248.9"/>
+<text text-anchor="start" x="897.38" y="-255.1" font-family="Times New Roman,serif" font-size="14.00">int/ptr</text>
+</g>
+<!-- STRUCT_TOP&#45;&gt;STRUCT_SN -->
+<g id="edge39" class="edge">
+<title>STRUCT_TOP&#45;&gt;STRUCT_SN</title>
+<path fill="none" stroke="black" d="M759.21,-475.24C782.17,-443.49 831.3,-375.56 864.63,-329.48"/>
+<polygon fill="black" stroke="black" points="867.37,-331.67 870.4,-321.52 861.7,-327.57 867.37,-331.67"/>
+</g>
+<!-- STRUCT_BOT -->
+<g id="node25" class="node">
+<title>STRUCT_BOT</title>
+<ellipse fill="lightgreen" stroke="black" cx="751.51" cy="-82.75" rx="44.7" ry="18"/>
+<text text-anchor="start" x="726.76" y="-78.7" font-family="Times New Roman,serif" font-weight="bold" font-size="14.00">⊥</text>
+<text text-anchor="start" x="742.51" y="-78.7" font-family="Times New Roman,serif" font-size="14.00">:struct</text>
+</g>
+<!-- STRUCT_BOT&#45;&gt;BOT -->
+<g id="edge43" class="edge">
+<title>STRUCT_BOT&#45;&gt;BOT</title>
+<path fill="none" stroke="black" d="M725.72,-67.77C709,-58.7 687.2,-46.89 669.97,-37.55"/>
+<polygon fill="black" stroke="black" points="671.71,-34.51 661.25,-32.82 668.37,-40.67 671.71,-34.51"/>
+</g>
+<!-- STRUCT_S1&#45;&gt;STRUCT_BOT -->
+<g id="edge40" class="edge">
+<title>STRUCT_S1&#45;&gt;STRUCT_BOT</title>
+<path fill="none" stroke="black" d="M706.86,-264.91C715.3,-230.49 733.97,-154.31 744.29,-112.19"/>
+<polygon fill="black" stroke="black" points="747.69,-113.04 746.67,-102.5 740.89,-111.37 747.69,-113.04"/>
+</g>
+<!-- STRUCT_S1&#45;&gt;STRUCT_S2 -->
+<!-- STRUCT_S2&#45;&gt;STRUCT_BOT -->
+<g id="edge41" class="edge">
+<title>STRUCT_S2&#45;&gt;STRUCT_BOT</title>
+<path fill="none" stroke="black" d="M792.36,-256.52C783.62,-219.3 767.61,-151.25 758.45,-112.26"/>
+<polygon fill="black" stroke="black" points="761.88,-111.57 756.18,-102.64 755.07,-113.17 761.88,-111.57"/>
+</g>
+<!-- STRUCT_S2&#45;&gt;STRUCT_SN -->
+<!-- STRUCT_SN&#45;&gt;STRUCT_BOT -->
+<g id="edge42" class="edge">
+<title>STRUCT_SN&#45;&gt;STRUCT_BOT</title>
+<path fill="none" stroke="black" d="M870.86,-245.05C841.74,-205.46 796.64,-144.13 771.03,-109.3"/>
+<polygon fill="black" stroke="black" points="773.99,-107.42 765.25,-101.44 768.36,-111.57 773.99,-107.42"/>
+</g>
+<!-- MEM_ALIAS1 -->
+<g id="node31" class="node">
+<title>MEM_ALIAS1</title>
+<ellipse fill="blue" stroke="black" cx="975.51" cy="-282.65" rx="20.13" ry="20.13"/>
+<text text-anchor="middle" x="975.51" y="-277.6" font-family="Times New Roman,serif" font-size="14.00" fill="white">#1</text>
+</g>
+<!-- MEM_TOP&#45;&gt;MEM_ALIAS1 -->
+<g id="edge47" class="edge">
+<title>MEM_TOP&#45;&gt;MEM_ALIAS1</title>
+<path fill="none" stroke="black" d="M996.51,-474.51C992.58,-438.66 983.84,-358.73 978.96,-314.18"/>
+<polygon fill="black" stroke="black" points="982.45,-313.94 977.89,-304.38 975.5,-314.7 982.45,-313.94"/>
+</g>
+<!-- MEM_ALIASDOTS -->
+<g id="node32" class="node">
+<title>MEM_ALIASDOTS</title>
+<ellipse fill="blue" stroke="black" cx="1036.51" cy="-282.65" rx="27" ry="18"/>
+<text text-anchor="middle" x="1036.51" y="-277.6" font-family="Times New Roman,serif" font-size="14.00" fill="white">...</text>
+</g>
+<!-- MEM_TOP&#45;&gt;MEM_ALIASDOTS -->
+<g id="edge48" class="edge">
+<title>MEM_TOP&#45;&gt;MEM_ALIASDOTS</title>
+<path fill="none" stroke="black" d="M1001.81,-474.51C1008.41,-438.02 1023.27,-355.86 1031.23,-311.83"/>
+<polygon fill="black" stroke="black" points="1034.63,-312.69 1032.97,-302.23 1027.74,-311.45 1034.63,-312.69"/>
+</g>
+<!-- MEM_ALIASN -->
+<g id="node33" class="node">
+<title>MEM_ALIASN</title>
+<ellipse fill="blue" stroke="black" cx="1097.51" cy="-282.65" rx="20.13" ry="20.13"/>
+<text text-anchor="middle" x="1097.51" y="-277.6" font-family="Times New Roman,serif" font-size="14.00" fill="white">#n</text>
+</g>
+<!-- MEM_TOP&#45;&gt;MEM_ALIASN -->
+<g id="edge49" class="edge">
+<title>MEM_TOP&#45;&gt;MEM_ALIASN</title>
+<path fill="none" stroke="black" d="M1006.95,-474.88C1024.11,-438.46 1063.18,-355.52 1083.95,-311.44"/>
+<polygon fill="black" stroke="black" points="1087.07,-313.03 1088.16,-302.49 1080.73,-310.05 1087.07,-313.03"/>
+</g>
+<!-- MEM_BOT -->
+<g id="node30" class="node">
+<title>MEM_BOT</title>
+<ellipse fill="blue" stroke="black" cx="998.51" cy="-82.75" rx="43.67" ry="18"/>
+<text text-anchor="start" x="974.51" y="-78.7" font-family="Times New Roman,serif" font-weight="bold" font-size="14.00" fill="white">⊥</text>
+<text text-anchor="start" x="990.26" y="-78.7" font-family="Times New Roman,serif" font-size="14.00" fill="white">:mem</text>
+</g>
+<!-- MEM_BOT&#45;&gt;BOT -->
+<g id="edge53" class="edge">
+<title>MEM_BOT&#45;&gt;BOT</title>
+<path fill="none" stroke="black" d="M958.6,-75.08C887.17,-63.15 738.86,-38.38 673.56,-27.48"/>
+<polygon fill="black" stroke="black" points="674.3,-24.05 663.86,-25.86 673.15,-30.96 674.3,-24.05"/>
+</g>
+<!-- MEM_ALIAS1&#45;&gt;MEM_BOT -->
+<g id="edge50" class="edge">
+<title>MEM_ALIAS1&#45;&gt;MEM_BOT</title>
+<path fill="none" stroke="black" d="M977.84,-262.38C981.92,-226.96 990.35,-153.62 995.09,-112.45"/>
+<polygon fill="black" stroke="black" points="998.57,-112.87 996.23,-102.53 991.61,-112.07 998.57,-112.87"/>
+</g>
+<!-- MEM_ALIAS1&#45;&gt;MEM_ALIASDOTS -->
+<!-- MEM_ALIASDOTS&#45;&gt;MEM_BOT -->
+<g id="edge51" class="edge">
+<title>MEM_ALIASDOTS&#45;&gt;MEM_BOT</title>
+<path fill="none" stroke="black" d="M1033.07,-264.56C1026.49,-229.93 1012.06,-154.01 1004.08,-112.06"/>
+<polygon fill="black" stroke="black" points="1007.56,-111.6 1002.25,-102.43 1000.68,-112.91 1007.56,-111.6"/>
+</g>
+<!-- MEM_ALIASDOTS&#45;&gt;MEM_ALIASN -->
+<!-- MEM_ALIASN&#45;&gt;MEM_BOT -->
+<g id="edge52" class="edge">
+<title>MEM_ALIASN&#45;&gt;MEM_BOT</title>
+<path fill="none" stroke="black" d="M1088.37,-264.2C1070.97,-229.07 1032.98,-152.35 1012.41,-110.82"/>
+<polygon fill="black" stroke="black" points="1015.58,-109.34 1008.01,-101.93 1009.31,-112.45 1015.58,-109.34"/>
+</g>
+<!-- TUPLE1 -->
+<g id="node36" class="node">
+<title>TUPLE1</title>
+<polygon fill="none" stroke="none" points="1185.51,-309.15 1131.51,-309.15 1131.51,-256.15 1185.51,-256.15 1185.51,-309.15"/>
+<polygon fill="pink" stroke="none" points="1139.76,-282.65 1139.76,-305.15 1177.26,-305.15 1177.26,-282.65 1139.76,-282.65"/>
+<polygon fill="none" stroke="black" points="1139.76,-282.65 1139.76,-305.15 1177.26,-305.15 1177.26,-282.65 1139.76,-282.65"/>
+<text text-anchor="start" x="1142.76" y="-288.85" font-family="Times New Roman,serif" font-size="14.00">Tuple</text>
+<polygon fill="black" stroke="none" points="1139.76,-260.15 1139.76,-282.65 1177.26,-282.65 1177.26,-260.15 1139.76,-260.15"/>
+<polygon fill="none" stroke="black" points="1139.76,-260.15 1139.76,-282.65 1177.26,-282.65 1177.26,-260.15 1139.76,-260.15"/>
+<text text-anchor="start" x="1146.88" y="-266.35" font-family="Times New Roman,serif" font-size="14.00" fill="white">type</text>
+</g>
+<!-- TUPLE_TOP&#45;&gt;TUPLE1 -->
+<g id="edge57" class="edge">
+<title>TUPLE_TOP&#45;&gt;TUPLE1</title>
+<path fill="none" stroke="black" d="M1180.42,-474.51C1176.51,-440.23 1167.99,-365.66 1162.8,-320.24"/>
+<polygon fill="black" stroke="black" points="1166.28,-319.86 1161.67,-310.32 1159.33,-320.65 1166.28,-319.86"/>
+</g>
+<!-- TUPLE2 -->
+<g id="node37" class="node">
+<title>TUPLE2</title>
+<polygon fill="none" stroke="none" points="1253.51,-320.4 1199.51,-320.4 1199.51,-244.9 1253.51,-244.9 1253.51,-320.4"/>
+<polygon fill="pink" stroke="none" points="1207.76,-293.9 1207.76,-316.4 1245.26,-316.4 1245.26,-293.9 1207.76,-293.9"/>
+<polygon fill="none" stroke="black" points="1207.76,-293.9 1207.76,-316.4 1245.26,-316.4 1245.26,-293.9 1207.76,-293.9"/>
+<text text-anchor="start" x="1210.76" y="-300.1" font-family="Times New Roman,serif" font-size="14.00">Tuple</text>
+<polygon fill="black" stroke="none" points="1207.76,-271.4 1207.76,-293.9 1245.26,-293.9 1245.26,-271.4 1207.76,-271.4"/>
+<polygon fill="none" stroke="black" points="1207.76,-271.4 1207.76,-293.9 1245.26,-293.9 1245.26,-271.4 1207.76,-271.4"/>
+<text text-anchor="start" x="1214.88" y="-277.6" font-family="Times New Roman,serif" font-size="14.00" fill="white">type</text>
+<polygon fill="black" stroke="none" points="1207.76,-248.9 1207.76,-271.4 1245.26,-271.4 1245.26,-248.9 1207.76,-248.9"/>
+<polygon fill="none" stroke="black" points="1207.76,-248.9 1207.76,-271.4 1245.26,-271.4 1245.26,-248.9 1207.76,-248.9"/>
+<text text-anchor="start" x="1214.88" y="-255.1" font-family="Times New Roman,serif" font-size="14.00" fill="white">type</text>
+</g>
+<!-- TUPLE_TOP&#45;&gt;TUPLE2 -->
+<g id="edge58" class="edge">
+<title>TUPLE_TOP&#45;&gt;TUPLE2</title>
+<path fill="none" stroke="black" d="M1186.34,-474.51C1192.95,-442.94 1206.72,-377.19 1216.28,-331.51"/>
+<polygon fill="black" stroke="black" points="1219.68,-332.35 1218.3,-321.85 1212.83,-330.92 1219.68,-332.35"/>
+</g>
+<!-- TUPLEN -->
+<g id="node38" class="node">
+<title>TUPLEN</title>
+<polygon fill="none" stroke="none" points="1321.51,-331.65 1267.51,-331.65 1267.51,-233.65 1321.51,-233.65 1321.51,-331.65"/>
+<polygon fill="pink" stroke="none" points="1275.76,-305.15 1275.76,-327.65 1313.26,-327.65 1313.26,-305.15 1275.76,-305.15"/>
+<polygon fill="none" stroke="black" points="1275.76,-305.15 1275.76,-327.65 1313.26,-327.65 1313.26,-305.15 1275.76,-305.15"/>
+<text text-anchor="start" x="1278.76" y="-311.35" font-family="Times New Roman,serif" font-size="14.00">Tuple</text>
+<polygon fill="black" stroke="none" points="1275.76,-282.65 1275.76,-305.15 1313.26,-305.15 1313.26,-282.65 1275.76,-282.65"/>
+<polygon fill="none" stroke="black" points="1275.76,-282.65 1275.76,-305.15 1313.26,-305.15 1313.26,-282.65 1275.76,-282.65"/>
+<text text-anchor="start" x="1282.88" y="-288.85" font-family="Times New Roman,serif" font-size="14.00" fill="white">type</text>
+<polygon fill="black" stroke="none" points="1275.76,-260.15 1275.76,-282.65 1313.26,-282.65 1313.26,-260.15 1275.76,-260.15"/>
+<polygon fill="none" stroke="black" points="1275.76,-260.15 1275.76,-282.65 1313.26,-282.65 1313.26,-260.15 1275.76,-260.15"/>
+<text text-anchor="start" x="1288.88" y="-266.35" font-family="Times New Roman,serif" font-size="14.00" fill="white">...</text>
+<polygon fill="black" stroke="none" points="1275.76,-237.65 1275.76,-260.15 1313.26,-260.15 1313.26,-237.65 1275.76,-237.65"/>
+<polygon fill="none" stroke="black" points="1275.76,-237.65 1275.76,-260.15 1313.26,-260.15 1313.26,-237.65 1275.76,-237.65"/>
+<text text-anchor="start" x="1282.88" y="-243.85" font-family="Times New Roman,serif" font-size="14.00" fill="white">type</text>
+</g>
+<!-- TUPLE_TOP&#45;&gt;TUPLEN -->
+<g id="edge59" class="edge">
+<title>TUPLE_TOP&#45;&gt;TUPLEN</title>
+<path fill="none" stroke="black" d="M1192.06,-474.88C1207.65,-445.62 1239.24,-386.36 1263.24,-341.32"/>
+<polygon fill="black" stroke="black" points="1266.22,-343.18 1267.83,-332.71 1260.04,-339.88 1266.22,-343.18"/>
+</g>
+<!-- TUPLE_BOT -->
+<g id="node35" class="node">
+<title>TUPLE_BOT</title>
+<ellipse fill="pink" stroke="black" cx="1192.51" cy="-82.75" rx="42.65" ry="18"/>
+<text text-anchor="start" x="1169.26" y="-78.7" font-family="Times New Roman,serif" font-weight="bold" font-size="14.00">⊥</text>
+<text text-anchor="start" x="1185.01" y="-78.7" font-family="Times New Roman,serif" font-size="14.00">:tuple</text>
+</g>
+<!-- TUPLE_BOT&#45;&gt;BOT -->
+<g id="edge63" class="edge">
+<title>TUPLE_BOT&#45;&gt;BOT</title>
+<path fill="none" stroke="black" d="M1151.54,-77.32C1046.53,-65.95 769.32,-35.95 674.14,-25.65"/>
+<polygon fill="black" stroke="black" points="674.52,-22.18 664.2,-24.58 673.77,-29.14 674.52,-22.18"/>
+</g>
+<!-- TUPLE1&#45;&gt;TUPLE_BOT -->
+<g id="edge60" class="edge">
+<title>TUPLE1&#45;&gt;TUPLE_BOT</title>
+<path fill="none" stroke="black" d="M1162.95,-256.52C1169.28,-219.3 1180.86,-151.25 1187.49,-112.26"/>
+<polygon fill="black" stroke="black" points="1190.9,-113.1 1189.12,-102.66 1184,-111.93 1190.9,-113.1"/>
+</g>
+<!-- TUPLE2&#45;&gt;TUPLE_BOT -->
+<g id="edge61" class="edge">
+<title>TUPLE2&#45;&gt;TUPLE_BOT</title>
+<path fill="none" stroke="black" d="M1220.11,-245.05C1213.55,-206.44 1203.46,-147.16 1197.47,-111.94"/>
+<polygon fill="black" stroke="black" points="1200.99,-111.74 1195.86,-102.47 1194.09,-112.92 1200.99,-111.74"/>
+</g>
+<!-- TUPLEN&#45;&gt;TUPLE_BOT -->
+<g id="edge62" class="edge">
+<title>TUPLEN&#45;&gt;TUPLE_BOT</title>
+<path fill="none" stroke="black" d="M1269.56,-233.75C1249.85,-195.12 1223.04,-142.58 1206.8,-110.75"/>
+<polygon fill="black" stroke="black" points="1210.07,-109.46 1202.41,-102.15 1203.83,-112.65 1210.07,-109.46"/>
+</g>
+</g>
+</svg>
diff --git a/chapter21/docs/lattice2.svg b/chapter21/docs/lattice2.svg
index 857bca2d..8b682aa7 100644
--- a/chapter21/docs/lattice2.svg
+++ b/chapter21/docs/lattice2.svg
@@ -1,260 +1,260 @@
-<?xml version="1.0" encoding="UTF-8" standalone="no"?>
-<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
- "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
-<!-- Generated by graphviz version 12.2.0 (20241103.1931)
- -->
-<!-- Title: Lattice Pages: 1 -->
-<svg width="478pt" height="501pt"
- viewBox="0.00 0.00 477.96 500.90" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
-<g id="graph0" class="graph" transform="scale(1 1) rotate(0) translate(4 496.9)">
-<title>Lattice</title>
-<polygon fill="white" stroke="none" points="-4,4 -4,-496.9 473.96,-496.9 473.96,4 -4,4"/>
-<!-- TOP -->
-<g id="node1" class="node">
-<title>TOP</title>
-<ellipse fill="black" stroke="black" cx="240.13" cy="-463.91" rx="59.04" ry="28.99"/>
-<text text-anchor="middle" x="240.13" y="-467.11" font-family="Times New Roman,serif" font-size="14.00" fill="white">~scalar</text>
-<text text-anchor="middle" x="240.13" y="-450.61" font-family="Times New Roman,serif" font-size="14.00" fill="white">+int+tmp+0</text>
-</g>
-<!-- PTRHQ -->
-<g id="node2" class="node">
-<title>PTRHQ</title>
-<ellipse fill="green" stroke="black" cx="43.13" cy="-376.92" rx="43.13" ry="28.99"/>
-<text text-anchor="middle" x="43.13" y="-380.12" font-family="Times New Roman,serif" font-size="14.00" fill="white">~tmp</text>
-<text text-anchor="middle" x="43.13" y="-363.62" font-family="Times New Roman,serif" font-size="14.00" fill="white">+tmp+0</text>
-</g>
-<!-- TOP&#45;&gt;PTRHQ -->
-<g id="edge1" class="edge">
-<title>TOP&#45;&gt;PTRHQ</title>
-<path fill="none" stroke="black" d="M196.41,-444.04C164.74,-430.38 121.99,-411.94 89.68,-398"/>
-<polygon fill="black" stroke="black" points="91.11,-394.81 80.55,-394.06 88.34,-401.24 91.11,-394.81"/>
-</g>
-<!-- VALH_ -->
-<g id="node3" class="node">
-<title>VALH_</title>
-<ellipse fill="white" stroke="black" cx="240.13" cy="-376.92" rx="48.44" ry="28.99"/>
-<text text-anchor="middle" x="240.13" y="-380.12" font-family="Times New Roman,serif" font-size="14.00">~nscalar</text>
-<text text-anchor="middle" x="240.13" y="-363.62" font-family="Times New Roman,serif" font-size="14.00">+int+tmp</text>
-</g>
-<!-- TOP&#45;&gt;VALH_ -->
-<g id="edge2" class="edge">
-<title>TOP&#45;&gt;VALH_</title>
-<path fill="none" stroke="black" d="M235.15,-434.61C234.93,-429.02 234.85,-423.06 234.9,-417.18"/>
-<polygon fill="black" stroke="black" points="238.39,-417.69 235.12,-407.61 231.39,-417.52 238.39,-417.69"/>
-</g>
-<!-- TOP&#45;&gt;VALH_ -->
-<!-- INTHQ -->
-<g id="node4" class="node">
-<title>INTHQ</title>
-<ellipse fill="lightblue" stroke="black" cx="432.13" cy="-376.92" rx="37.83" ry="28.99"/>
-<text text-anchor="middle" x="432.13" y="-380.12" font-family="Times New Roman,serif" font-size="14.00">~int</text>
-<text text-anchor="middle" x="432.13" y="-363.62" font-family="Times New Roman,serif" font-size="14.00">+int+0</text>
-</g>
-<!-- TOP&#45;&gt;INTHQ -->
-<g id="edge3" class="edge">
-<title>TOP&#45;&gt;INTHQ</title>
-<path fill="none" stroke="black" d="M283.22,-443.83C314.91,-429.81 357.78,-410.83 389.39,-396.84"/>
-<polygon fill="black" stroke="black" points="390.53,-400.16 398.26,-392.92 387.7,-393.76 390.53,-400.16"/>
-</g>
-<!-- LEFTHI -->
-<!-- PTRHQ&#45;&gt;LEFTHI -->
-<!-- PTRH_ -->
-<g id="node6" class="node">
-<title>PTRH_</title>
-<ellipse fill="green" stroke="black" cx="43.13" cy="-289.94" rx="36.77" ry="28.99"/>
-<text text-anchor="middle" x="43.13" y="-293.14" font-family="Times New Roman,serif" font-size="14.00" fill="white">~ntmp</text>
-<text text-anchor="middle" x="43.13" y="-276.64" font-family="Times New Roman,serif" font-size="14.00" fill="white">+tmp</text>
-</g>
-<!-- PTRHQ&#45;&gt;PTRH_ -->
-<g id="edge8" class="edge">
-<title>PTRHQ&#45;&gt;PTRH_</title>
-<path fill="none" stroke="black" d="M38.15,-347.62C37.93,-342.03 37.85,-336.07 37.9,-330.2"/>
-<polygon fill="black" stroke="black" points="41.39,-330.71 38.12,-320.63 34.39,-330.54 41.39,-330.71"/>
-</g>
-<!-- PTRHQ&#45;&gt;PTRH_ -->
-<!-- NILX_ -->
-<g id="node8" class="node">
-<title>NILX_</title>
-<ellipse fill="aqua" stroke="black" cx="150.13" cy="-289.94" rx="56.39" ry="28.99"/>
-<text text-anchor="middle" x="150.13" y="-293.14" font-family="Times New Roman,serif" font-size="14.00">~nil</text>
-<text text-anchor="middle" x="150.13" y="-276.64" font-family="Times New Roman,serif" font-size="14.00">[int,tmp]+0</text>
-</g>
-<!-- PTRHQ&#45;&gt;NILX_ -->
-<g id="edge12" class="edge">
-<title>PTRHQ&#45;&gt;NILX_</title>
-<path fill="none" stroke="black" d="M70.41,-354.26C82.91,-344.33 97.94,-332.4 111.56,-321.58"/>
-<polygon fill="black" stroke="black" points="113.43,-324.56 119.09,-315.6 109.08,-319.08 113.43,-324.56"/>
-</g>
-<!-- VALH_&#45;&gt;INTHQ -->
-<!-- VALH_&#45;&gt;PTRH_ -->
-<g id="edge7" class="edge">
-<title>VALH_&#45;&gt;PTRH_</title>
-<path fill="none" stroke="black" d="M201.21,-359.13C167.78,-344.71 119.68,-323.96 85.33,-309.14"/>
-<polygon fill="black" stroke="black" points="87.1,-306.09 76.53,-305.35 84.33,-312.52 87.1,-306.09"/>
-</g>
-<!-- INTH_ -->
-<g id="node7" class="node">
-<title>INTH_</title>
-<ellipse fill="lightblue" stroke="black" cx="432.13" cy="-289.94" rx="31.47" ry="28.99"/>
-<text text-anchor="middle" x="432.13" y="-293.14" font-family="Times New Roman,serif" font-size="14.00">~nint</text>
-<text text-anchor="middle" x="432.13" y="-276.64" font-family="Times New Roman,serif" font-size="14.00">+int</text>
-</g>
-<!-- VALH_&#45;&gt;INTH_ -->
-<g id="edge9" class="edge">
-<title>VALH_&#45;&gt;INTH_</title>
-<path fill="none" stroke="black" d="M278.53,-358.93C311.9,-344.16 360.02,-322.86 393.48,-308.05"/>
-<polygon fill="black" stroke="black" points="394.67,-311.35 402.4,-304.1 391.84,-304.95 394.67,-311.35"/>
-</g>
-<!-- NIL__ -->
-<g id="node9" class="node">
-<title>NIL__</title>
-<ellipse fill="pink" stroke="black" cx="324.13" cy="-289.94" rx="62.23" ry="28.99"/>
-<text text-anchor="middle" x="324.13" y="-293.14" font-family="Times New Roman,serif" font-size="14.00">nil</text>
-<text text-anchor="middle" x="324.13" y="-276.64" font-family="Times New Roman,serif" font-size="14.00">[+int+tmp],0</text>
-</g>
-<!-- VALH_&#45;&gt;NIL__ -->
-<g id="edge13" class="edge">
-<title>VALH_&#45;&gt;NIL__</title>
-<path fill="none" stroke="black" d="M264.43,-351.34C272.67,-343.01 282.01,-333.55 290.83,-324.64"/>
-<polygon fill="black" stroke="black" points="293.12,-327.3 297.66,-317.72 288.14,-322.38 293.12,-327.3"/>
-</g>
-<!-- VALL_ -->
-<g id="node13" class="node">
-<title>VALL_</title>
-<ellipse fill="white" stroke="black" cx="240.13" cy="-115.97" rx="39.42" ry="28.99"/>
-<text text-anchor="middle" x="240.13" y="-119.17" font-family="Times New Roman,serif" font-size="14.00">nscalar</text>
-<text text-anchor="middle" x="240.13" y="-102.67" font-family="Times New Roman,serif" font-size="14.00">int,tmp</text>
-</g>
-<!-- VALH_&#45;&gt;VALL_ -->
-<!-- INTHQ&#45;&gt;INTH_ -->
-<g id="edge10" class="edge">
-<title>INTHQ&#45;&gt;INTH_</title>
-<path fill="none" stroke="black" d="M427.17,-348.1C426.94,-342.37 426.85,-336.25 426.9,-330.21"/>
-<polygon fill="black" stroke="black" points="430.39,-330.42 427.13,-320.34 423.39,-330.26 430.39,-330.42"/>
-</g>
-<!-- INTHQ&#45;&gt;INTH_ -->
-<!-- INTHQ&#45;&gt;NILX_ -->
-<g id="edge11" class="edge">
-<title>INTHQ&#45;&gt;NILX_</title>
-<path fill="none" stroke="black" d="M396.99,-365.33C350,-351.17 266.03,-325.87 209.23,-308.75"/>
-<polygon fill="black" stroke="black" points="210.28,-305.41 199.69,-305.88 208.26,-312.11 210.28,-305.41"/>
-</g>
-<!-- LEFTHI&#45;&gt;VALH_ -->
-<!-- LEFTHI&#45;&gt;NILX_ -->
-<!-- PTRL_ -->
-<g id="node10" class="node">
-<title>PTRL_</title>
-<ellipse fill="green" stroke="black" cx="43.13" cy="-202.96" rx="31.47" ry="28.99"/>
-<text text-anchor="middle" x="43.13" y="-206.16" font-family="Times New Roman,serif" font-size="14.00" fill="white">ntmp</text>
-<text text-anchor="middle" x="43.13" y="-189.66" font-family="Times New Roman,serif" font-size="14.00" fill="white">tmp</text>
-</g>
-<!-- PTRH_&#45;&gt;PTRL_ -->
-<g id="edge15" class="edge">
-<title>PTRH_&#45;&gt;PTRL_</title>
-<path fill="none" stroke="black" d="M38.17,-261.11C37.94,-255.39 37.85,-249.26 37.9,-243.22"/>
-<polygon fill="black" stroke="black" points="41.39,-243.44 38.13,-233.36 34.39,-243.27 41.39,-243.44"/>
-</g>
-<!-- PTRH_&#45;&gt;PTRL_ -->
-<!-- INTL_ -->
-<g id="node11" class="node">
-<title>INTL_</title>
-<ellipse fill="lightblue" stroke="black" cx="432.13" cy="-202.96" rx="27" ry="28.99"/>
-<text text-anchor="middle" x="432.13" y="-206.16" font-family="Times New Roman,serif" font-size="14.00">nint</text>
-<text text-anchor="middle" x="432.13" y="-189.66" font-family="Times New Roman,serif" font-size="14.00">int</text>
-</g>
-<!-- INTH_&#45;&gt;INTL_ -->
-<g id="edge16" class="edge">
-<title>INTH_&#45;&gt;INTL_</title>
-<path fill="none" stroke="black" d="M427.17,-261.11C426.94,-255.39 426.85,-249.26 426.9,-243.22"/>
-<polygon fill="black" stroke="black" points="430.39,-243.44 427.13,-233.36 423.39,-243.27 430.39,-243.44"/>
-</g>
-<!-- INTH_&#45;&gt;INTL_ -->
-<!-- NILX_&#45;&gt;NIL__ -->
-<!-- NILX_&#45;&gt;VALL_ -->
-<g id="edge21" class="edge">
-<title>NILX_&#45;&gt;VALL_</title>
-<path fill="none" stroke="black" d="M164.79,-261.6C180.03,-232.15 203.95,-185.91 220.74,-153.45"/>
-<polygon fill="black" stroke="black" points="223.74,-155.27 225.23,-144.78 217.53,-152.06 223.74,-155.27"/>
-</g>
-<!-- PTRL0 -->
-<g id="node12" class="node">
-<title>PTRL0</title>
-<ellipse fill="green" stroke="black" cx="43.13" cy="-115.97" rx="34.12" ry="28.99"/>
-<text text-anchor="middle" x="43.13" y="-119.17" font-family="Times New Roman,serif" font-size="14.00" fill="white">tmp</text>
-<text text-anchor="middle" x="43.13" y="-102.67" font-family="Times New Roman,serif" font-size="14.00" fill="white">tmp,0</text>
-</g>
-<!-- NIL__&#45;&gt;PTRL0 -->
-<g id="edge18" class="edge">
-<title>NIL__&#45;&gt;PTRL0</title>
-<path fill="none" stroke="black" d="M286.24,-266.48C232.36,-233.13 134.24,-172.38 80.6,-139.17"/>
-<polygon fill="black" stroke="black" points="82.76,-136.39 72.41,-134.1 79.07,-142.34 82.76,-136.39"/>
-</g>
-<!-- INTL0 -->
-<g id="node14" class="node">
-<title>INTL0</title>
-<ellipse fill="lightblue" stroke="black" cx="432.13" cy="-115.97" rx="28.81" ry="28.99"/>
-<text text-anchor="middle" x="432.13" y="-119.17" font-family="Times New Roman,serif" font-size="14.00">int</text>
-<text text-anchor="middle" x="432.13" y="-102.67" font-family="Times New Roman,serif" font-size="14.00">int,0</text>
-</g>
-<!-- NIL__&#45;&gt;INTL0 -->
-<g id="edge23" class="edge">
-<title>NIL__&#45;&gt;INTL0</title>
-<path fill="none" stroke="black" d="M341.49,-261.99C360.34,-231.61 390.49,-183.05 410.79,-150.35"/>
-<polygon fill="black" stroke="black" points="413.65,-152.38 415.95,-142.04 407.7,-148.69 413.65,-152.38"/>
-</g>
-<!-- PTRL_&#45;&gt;PTRL0 -->
-<g id="edge17" class="edge">
-<title>PTRL_&#45;&gt;PTRL0</title>
-<path fill="none" stroke="black" d="M38.17,-174.13C37.94,-168.47 37.85,-162.41 37.9,-156.43"/>
-<polygon fill="black" stroke="black" points="41.39,-156.75 38.12,-146.67 34.39,-156.58 41.39,-156.75"/>
-</g>
-<!-- PTRL_&#45;&gt;PTRL0 -->
-<!-- PTRL_&#45;&gt;VALL_ -->
-<g id="edge19" class="edge">
-<title>PTRL_&#45;&gt;VALL_</title>
-<path fill="none" stroke="black" d="M71.36,-189.78C103.94,-175.73 157.92,-152.44 196.04,-135.99"/>
-<polygon fill="black" stroke="black" points="197.16,-139.32 204.96,-132.15 194.39,-132.9 197.16,-139.32"/>
-</g>
-<!-- INTL_&#45;&gt;VALL_ -->
-<g id="edge20" class="edge">
-<title>INTL_&#45;&gt;VALL_</title>
-<path fill="none" stroke="black" d="M407.43,-191.02C376.23,-177.21 322.01,-153.22 283.77,-136.29"/>
-<polygon fill="black" stroke="black" points="285.39,-133.18 274.83,-132.33 282.55,-139.58 285.39,-133.18"/>
-</g>
-<!-- INTL_&#45;&gt;INTL0 -->
-<g id="edge22" class="edge">
-<title>INTL_&#45;&gt;INTL0</title>
-<path fill="none" stroke="black" d="M427.17,-174.13C426.94,-168.41 426.85,-162.28 426.9,-156.24"/>
-<polygon fill="black" stroke="black" points="430.39,-156.46 427.13,-146.38 423.39,-156.29 430.39,-156.46"/>
-</g>
-<!-- INTL_&#45;&gt;INTL0 -->
-<!-- PTRL0&#45;&gt;VALL_ -->
-<!-- BOT -->
-<g id="node15" class="node">
-<title>BOT</title>
-<ellipse fill="black" stroke="black" cx="240.13" cy="-28.99" rx="46.85" ry="28.99"/>
-<text text-anchor="middle" x="240.13" y="-32.19" font-family="Times New Roman,serif" font-size="14.00" fill="white">scalar</text>
-<text text-anchor="middle" x="240.13" y="-15.69" font-family="Times New Roman,serif" font-size="14.00" fill="white">int,tmp,0</text>
-</g>
-<!-- PTRL0&#45;&gt;BOT -->
-<g id="edge26" class="edge">
-<title>PTRL0&#45;&gt;BOT</title>
-<path fill="none" stroke="black" d="M73.48,-101.88C105.02,-88.28 154.83,-66.79 191.79,-50.85"/>
-<polygon fill="black" stroke="black" points="193.14,-54.08 200.94,-46.9 190.37,-47.65 193.14,-54.08"/>
-</g>
-<!-- VALL_&#45;&gt;INTL0 -->
-<!-- VALL_&#45;&gt;BOT -->
-<g id="edge28" class="edge">
-<title>VALL_&#45;&gt;BOT</title>
-<path fill="none" stroke="black" d="M235.17,-87.15C234.94,-81.48 234.85,-75.42 234.9,-69.44"/>
-<polygon fill="black" stroke="black" points="238.39,-69.76 235.12,-59.68 231.39,-69.6 238.39,-69.76"/>
-</g>
-<!-- VALL_&#45;&gt;BOT -->
-<!-- INTL0&#45;&gt;BOT -->
-<g id="edge27" class="edge">
-<title>INTL0&#45;&gt;BOT</title>
-<path fill="none" stroke="black" d="M405.84,-103.34C375.52,-89.91 325.06,-67.58 287.78,-51.08"/>
-<polygon fill="black" stroke="black" points="289.59,-48.05 279.03,-47.21 286.75,-54.45 289.59,-48.05"/>
-</g>
-</g>
-</svg>
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
+ "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+<!-- Generated by graphviz version 12.2.0 (20241103.1931)
+ -->
+<!-- Title: Lattice Pages: 1 -->
+<svg width="478pt" height="501pt"
+ viewBox="0.00 0.00 477.96 500.90" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
+<g id="graph0" class="graph" transform="scale(1 1) rotate(0) translate(4 496.9)">
+<title>Lattice</title>
+<polygon fill="white" stroke="none" points="-4,4 -4,-496.9 473.96,-496.9 473.96,4 -4,4"/>
+<!-- TOP -->
+<g id="node1" class="node">
+<title>TOP</title>
+<ellipse fill="black" stroke="black" cx="240.13" cy="-463.91" rx="59.04" ry="28.99"/>
+<text text-anchor="middle" x="240.13" y="-467.11" font-family="Times New Roman,serif" font-size="14.00" fill="white">~scalar</text>
+<text text-anchor="middle" x="240.13" y="-450.61" font-family="Times New Roman,serif" font-size="14.00" fill="white">+int+tmp+0</text>
+</g>
+<!-- PTRHQ -->
+<g id="node2" class="node">
+<title>PTRHQ</title>
+<ellipse fill="green" stroke="black" cx="43.13" cy="-376.92" rx="43.13" ry="28.99"/>
+<text text-anchor="middle" x="43.13" y="-380.12" font-family="Times New Roman,serif" font-size="14.00" fill="white">~tmp</text>
+<text text-anchor="middle" x="43.13" y="-363.62" font-family="Times New Roman,serif" font-size="14.00" fill="white">+tmp+0</text>
+</g>
+<!-- TOP&#45;&gt;PTRHQ -->
+<g id="edge1" class="edge">
+<title>TOP&#45;&gt;PTRHQ</title>
+<path fill="none" stroke="black" d="M196.41,-444.04C164.74,-430.38 121.99,-411.94 89.68,-398"/>
+<polygon fill="black" stroke="black" points="91.11,-394.81 80.55,-394.06 88.34,-401.24 91.11,-394.81"/>
+</g>
+<!-- VALH_ -->
+<g id="node3" class="node">
+<title>VALH_</title>
+<ellipse fill="white" stroke="black" cx="240.13" cy="-376.92" rx="48.44" ry="28.99"/>
+<text text-anchor="middle" x="240.13" y="-380.12" font-family="Times New Roman,serif" font-size="14.00">~nscalar</text>
+<text text-anchor="middle" x="240.13" y="-363.62" font-family="Times New Roman,serif" font-size="14.00">+int+tmp</text>
+</g>
+<!-- TOP&#45;&gt;VALH_ -->
+<g id="edge2" class="edge">
+<title>TOP&#45;&gt;VALH_</title>
+<path fill="none" stroke="black" d="M235.15,-434.61C234.93,-429.02 234.85,-423.06 234.9,-417.18"/>
+<polygon fill="black" stroke="black" points="238.39,-417.69 235.12,-407.61 231.39,-417.52 238.39,-417.69"/>
+</g>
+<!-- TOP&#45;&gt;VALH_ -->
+<!-- INTHQ -->
+<g id="node4" class="node">
+<title>INTHQ</title>
+<ellipse fill="lightblue" stroke="black" cx="432.13" cy="-376.92" rx="37.83" ry="28.99"/>
+<text text-anchor="middle" x="432.13" y="-380.12" font-family="Times New Roman,serif" font-size="14.00">~int</text>
+<text text-anchor="middle" x="432.13" y="-363.62" font-family="Times New Roman,serif" font-size="14.00">+int+0</text>
+</g>
+<!-- TOP&#45;&gt;INTHQ -->
+<g id="edge3" class="edge">
+<title>TOP&#45;&gt;INTHQ</title>
+<path fill="none" stroke="black" d="M283.22,-443.83C314.91,-429.81 357.78,-410.83 389.39,-396.84"/>
+<polygon fill="black" stroke="black" points="390.53,-400.16 398.26,-392.92 387.7,-393.76 390.53,-400.16"/>
+</g>
+<!-- LEFTHI -->
+<!-- PTRHQ&#45;&gt;LEFTHI -->
+<!-- PTRH_ -->
+<g id="node6" class="node">
+<title>PTRH_</title>
+<ellipse fill="green" stroke="black" cx="43.13" cy="-289.94" rx="36.77" ry="28.99"/>
+<text text-anchor="middle" x="43.13" y="-293.14" font-family="Times New Roman,serif" font-size="14.00" fill="white">~ntmp</text>
+<text text-anchor="middle" x="43.13" y="-276.64" font-family="Times New Roman,serif" font-size="14.00" fill="white">+tmp</text>
+</g>
+<!-- PTRHQ&#45;&gt;PTRH_ -->
+<g id="edge8" class="edge">
+<title>PTRHQ&#45;&gt;PTRH_</title>
+<path fill="none" stroke="black" d="M38.15,-347.62C37.93,-342.03 37.85,-336.07 37.9,-330.2"/>
+<polygon fill="black" stroke="black" points="41.39,-330.71 38.12,-320.63 34.39,-330.54 41.39,-330.71"/>
+</g>
+<!-- PTRHQ&#45;&gt;PTRH_ -->
+<!-- NILX_ -->
+<g id="node8" class="node">
+<title>NILX_</title>
+<ellipse fill="aqua" stroke="black" cx="150.13" cy="-289.94" rx="56.39" ry="28.99"/>
+<text text-anchor="middle" x="150.13" y="-293.14" font-family="Times New Roman,serif" font-size="14.00">~nil</text>
+<text text-anchor="middle" x="150.13" y="-276.64" font-family="Times New Roman,serif" font-size="14.00">[int,tmp]+0</text>
+</g>
+<!-- PTRHQ&#45;&gt;NILX_ -->
+<g id="edge12" class="edge">
+<title>PTRHQ&#45;&gt;NILX_</title>
+<path fill="none" stroke="black" d="M70.41,-354.26C82.91,-344.33 97.94,-332.4 111.56,-321.58"/>
+<polygon fill="black" stroke="black" points="113.43,-324.56 119.09,-315.6 109.08,-319.08 113.43,-324.56"/>
+</g>
+<!-- VALH_&#45;&gt;INTHQ -->
+<!-- VALH_&#45;&gt;PTRH_ -->
+<g id="edge7" class="edge">
+<title>VALH_&#45;&gt;PTRH_</title>
+<path fill="none" stroke="black" d="M201.21,-359.13C167.78,-344.71 119.68,-323.96 85.33,-309.14"/>
+<polygon fill="black" stroke="black" points="87.1,-306.09 76.53,-305.35 84.33,-312.52 87.1,-306.09"/>
+</g>
+<!-- INTH_ -->
+<g id="node7" class="node">
+<title>INTH_</title>
+<ellipse fill="lightblue" stroke="black" cx="432.13" cy="-289.94" rx="31.47" ry="28.99"/>
+<text text-anchor="middle" x="432.13" y="-293.14" font-family="Times New Roman,serif" font-size="14.00">~nint</text>
+<text text-anchor="middle" x="432.13" y="-276.64" font-family="Times New Roman,serif" font-size="14.00">+int</text>
+</g>
+<!-- VALH_&#45;&gt;INTH_ -->
+<g id="edge9" class="edge">
+<title>VALH_&#45;&gt;INTH_</title>
+<path fill="none" stroke="black" d="M278.53,-358.93C311.9,-344.16 360.02,-322.86 393.48,-308.05"/>
+<polygon fill="black" stroke="black" points="394.67,-311.35 402.4,-304.1 391.84,-304.95 394.67,-311.35"/>
+</g>
+<!-- NIL__ -->
+<g id="node9" class="node">
+<title>NIL__</title>
+<ellipse fill="pink" stroke="black" cx="324.13" cy="-289.94" rx="62.23" ry="28.99"/>
+<text text-anchor="middle" x="324.13" y="-293.14" font-family="Times New Roman,serif" font-size="14.00">nil</text>
+<text text-anchor="middle" x="324.13" y="-276.64" font-family="Times New Roman,serif" font-size="14.00">[+int+tmp],0</text>
+</g>
+<!-- VALH_&#45;&gt;NIL__ -->
+<g id="edge13" class="edge">
+<title>VALH_&#45;&gt;NIL__</title>
+<path fill="none" stroke="black" d="M264.43,-351.34C272.67,-343.01 282.01,-333.55 290.83,-324.64"/>
+<polygon fill="black" stroke="black" points="293.12,-327.3 297.66,-317.72 288.14,-322.38 293.12,-327.3"/>
+</g>
+<!-- VALL_ -->
+<g id="node13" class="node">
+<title>VALL_</title>
+<ellipse fill="white" stroke="black" cx="240.13" cy="-115.97" rx="39.42" ry="28.99"/>
+<text text-anchor="middle" x="240.13" y="-119.17" font-family="Times New Roman,serif" font-size="14.00">nscalar</text>
+<text text-anchor="middle" x="240.13" y="-102.67" font-family="Times New Roman,serif" font-size="14.00">int,tmp</text>
+</g>
+<!-- VALH_&#45;&gt;VALL_ -->
+<!-- INTHQ&#45;&gt;INTH_ -->
+<g id="edge10" class="edge">
+<title>INTHQ&#45;&gt;INTH_</title>
+<path fill="none" stroke="black" d="M427.17,-348.1C426.94,-342.37 426.85,-336.25 426.9,-330.21"/>
+<polygon fill="black" stroke="black" points="430.39,-330.42 427.13,-320.34 423.39,-330.26 430.39,-330.42"/>
+</g>
+<!-- INTHQ&#45;&gt;INTH_ -->
+<!-- INTHQ&#45;&gt;NILX_ -->
+<g id="edge11" class="edge">
+<title>INTHQ&#45;&gt;NILX_</title>
+<path fill="none" stroke="black" d="M396.99,-365.33C350,-351.17 266.03,-325.87 209.23,-308.75"/>
+<polygon fill="black" stroke="black" points="210.28,-305.41 199.69,-305.88 208.26,-312.11 210.28,-305.41"/>
+</g>
+<!-- LEFTHI&#45;&gt;VALH_ -->
+<!-- LEFTHI&#45;&gt;NILX_ -->
+<!-- PTRL_ -->
+<g id="node10" class="node">
+<title>PTRL_</title>
+<ellipse fill="green" stroke="black" cx="43.13" cy="-202.96" rx="31.47" ry="28.99"/>
+<text text-anchor="middle" x="43.13" y="-206.16" font-family="Times New Roman,serif" font-size="14.00" fill="white">ntmp</text>
+<text text-anchor="middle" x="43.13" y="-189.66" font-family="Times New Roman,serif" font-size="14.00" fill="white">tmp</text>
+</g>
+<!-- PTRH_&#45;&gt;PTRL_ -->
+<g id="edge15" class="edge">
+<title>PTRH_&#45;&gt;PTRL_</title>
+<path fill="none" stroke="black" d="M38.17,-261.11C37.94,-255.39 37.85,-249.26 37.9,-243.22"/>
+<polygon fill="black" stroke="black" points="41.39,-243.44 38.13,-233.36 34.39,-243.27 41.39,-243.44"/>
+</g>
+<!-- PTRH_&#45;&gt;PTRL_ -->
+<!-- INTL_ -->
+<g id="node11" class="node">
+<title>INTL_</title>
+<ellipse fill="lightblue" stroke="black" cx="432.13" cy="-202.96" rx="27" ry="28.99"/>
+<text text-anchor="middle" x="432.13" y="-206.16" font-family="Times New Roman,serif" font-size="14.00">nint</text>
+<text text-anchor="middle" x="432.13" y="-189.66" font-family="Times New Roman,serif" font-size="14.00">int</text>
+</g>
+<!-- INTH_&#45;&gt;INTL_ -->
+<g id="edge16" class="edge">
+<title>INTH_&#45;&gt;INTL_</title>
+<path fill="none" stroke="black" d="M427.17,-261.11C426.94,-255.39 426.85,-249.26 426.9,-243.22"/>
+<polygon fill="black" stroke="black" points="430.39,-243.44 427.13,-233.36 423.39,-243.27 430.39,-243.44"/>
+</g>
+<!-- INTH_&#45;&gt;INTL_ -->
+<!-- NILX_&#45;&gt;NIL__ -->
+<!-- NILX_&#45;&gt;VALL_ -->
+<g id="edge21" class="edge">
+<title>NILX_&#45;&gt;VALL_</title>
+<path fill="none" stroke="black" d="M164.79,-261.6C180.03,-232.15 203.95,-185.91 220.74,-153.45"/>
+<polygon fill="black" stroke="black" points="223.74,-155.27 225.23,-144.78 217.53,-152.06 223.74,-155.27"/>
+</g>
+<!-- PTRL0 -->
+<g id="node12" class="node">
+<title>PTRL0</title>
+<ellipse fill="green" stroke="black" cx="43.13" cy="-115.97" rx="34.12" ry="28.99"/>
+<text text-anchor="middle" x="43.13" y="-119.17" font-family="Times New Roman,serif" font-size="14.00" fill="white">tmp</text>
+<text text-anchor="middle" x="43.13" y="-102.67" font-family="Times New Roman,serif" font-size="14.00" fill="white">tmp,0</text>
+</g>
+<!-- NIL__&#45;&gt;PTRL0 -->
+<g id="edge18" class="edge">
+<title>NIL__&#45;&gt;PTRL0</title>
+<path fill="none" stroke="black" d="M286.24,-266.48C232.36,-233.13 134.24,-172.38 80.6,-139.17"/>
+<polygon fill="black" stroke="black" points="82.76,-136.39 72.41,-134.1 79.07,-142.34 82.76,-136.39"/>
+</g>
+<!-- INTL0 -->
+<g id="node14" class="node">
+<title>INTL0</title>
+<ellipse fill="lightblue" stroke="black" cx="432.13" cy="-115.97" rx="28.81" ry="28.99"/>
+<text text-anchor="middle" x="432.13" y="-119.17" font-family="Times New Roman,serif" font-size="14.00">int</text>
+<text text-anchor="middle" x="432.13" y="-102.67" font-family="Times New Roman,serif" font-size="14.00">int,0</text>
+</g>
+<!-- NIL__&#45;&gt;INTL0 -->
+<g id="edge23" class="edge">
+<title>NIL__&#45;&gt;INTL0</title>
+<path fill="none" stroke="black" d="M341.49,-261.99C360.34,-231.61 390.49,-183.05 410.79,-150.35"/>
+<polygon fill="black" stroke="black" points="413.65,-152.38 415.95,-142.04 407.7,-148.69 413.65,-152.38"/>
+</g>
+<!-- PTRL_&#45;&gt;PTRL0 -->
+<g id="edge17" class="edge">
+<title>PTRL_&#45;&gt;PTRL0</title>
+<path fill="none" stroke="black" d="M38.17,-174.13C37.94,-168.47 37.85,-162.41 37.9,-156.43"/>
+<polygon fill="black" stroke="black" points="41.39,-156.75 38.12,-146.67 34.39,-156.58 41.39,-156.75"/>
+</g>
+<!-- PTRL_&#45;&gt;PTRL0 -->
+<!-- PTRL_&#45;&gt;VALL_ -->
+<g id="edge19" class="edge">
+<title>PTRL_&#45;&gt;VALL_</title>
+<path fill="none" stroke="black" d="M71.36,-189.78C103.94,-175.73 157.92,-152.44 196.04,-135.99"/>
+<polygon fill="black" stroke="black" points="197.16,-139.32 204.96,-132.15 194.39,-132.9 197.16,-139.32"/>
+</g>
+<!-- INTL_&#45;&gt;VALL_ -->
+<g id="edge20" class="edge">
+<title>INTL_&#45;&gt;VALL_</title>
+<path fill="none" stroke="black" d="M407.43,-191.02C376.23,-177.21 322.01,-153.22 283.77,-136.29"/>
+<polygon fill="black" stroke="black" points="285.39,-133.18 274.83,-132.33 282.55,-139.58 285.39,-133.18"/>
+</g>
+<!-- INTL_&#45;&gt;INTL0 -->
+<g id="edge22" class="edge">
+<title>INTL_&#45;&gt;INTL0</title>
+<path fill="none" stroke="black" d="M427.17,-174.13C426.94,-168.41 426.85,-162.28 426.9,-156.24"/>
+<polygon fill="black" stroke="black" points="430.39,-156.46 427.13,-146.38 423.39,-156.29 430.39,-156.46"/>
+</g>
+<!-- INTL_&#45;&gt;INTL0 -->
+<!-- PTRL0&#45;&gt;VALL_ -->
+<!-- BOT -->
+<g id="node15" class="node">
+<title>BOT</title>
+<ellipse fill="black" stroke="black" cx="240.13" cy="-28.99" rx="46.85" ry="28.99"/>
+<text text-anchor="middle" x="240.13" y="-32.19" font-family="Times New Roman,serif" font-size="14.00" fill="white">scalar</text>
+<text text-anchor="middle" x="240.13" y="-15.69" font-family="Times New Roman,serif" font-size="14.00" fill="white">int,tmp,0</text>
+</g>
+<!-- PTRL0&#45;&gt;BOT -->
+<g id="edge26" class="edge">
+<title>PTRL0&#45;&gt;BOT</title>
+<path fill="none" stroke="black" d="M73.48,-101.88C105.02,-88.28 154.83,-66.79 191.79,-50.85"/>
+<polygon fill="black" stroke="black" points="193.14,-54.08 200.94,-46.9 190.37,-47.65 193.14,-54.08"/>
+</g>
+<!-- VALL_&#45;&gt;INTL0 -->
+<!-- VALL_&#45;&gt;BOT -->
+<g id="edge28" class="edge">
+<title>VALL_&#45;&gt;BOT</title>
+<path fill="none" stroke="black" d="M235.17,-87.15C234.94,-81.48 234.85,-75.42 234.9,-69.44"/>
+<polygon fill="black" stroke="black" points="238.39,-69.76 235.12,-59.68 231.39,-69.6 238.39,-69.76"/>
+</g>
+<!-- VALL_&#45;&gt;BOT -->
+<!-- INTL0&#45;&gt;BOT -->
+<g id="edge27" class="edge">
+<title>INTL0&#45;&gt;BOT</title>
+<path fill="none" stroke="black" d="M405.84,-103.34C375.52,-89.91 325.06,-67.58 287.78,-51.08"/>
+<polygon fill="black" stroke="black" points="289.59,-48.05 279.03,-47.21 286.75,-54.45 289.59,-48.05"/>
+</g>
+</g>
+</svg>
diff --git a/chapter21/src/main/java/com/seaofnodes/simple/codegen/CodeGen.java b/chapter21/src/main/java/com/seaofnodes/simple/codegen/CodeGen.java
index 4215233e..214b597d 100644
--- a/chapter21/src/main/java/com/seaofnodes/simple/codegen/CodeGen.java
+++ b/chapter21/src/main/java/com/seaofnodes/simple/codegen/CodeGen.java
@@ -2,8 +2,11 @@ package com.seaofnodes.simple.codegen;
import com.seaofnodes.simple.*;
import com.seaofnodes.simple.node.*;
+
import com.seaofnodes.simple.print.*;
import com.seaofnodes.simple.type.*;
+
+import java.io.ByteArrayOutputStream;
import java.util.BitSet;
import java.util.HashMap;
import java.util.IdentityHashMap;
@@ -292,6 +295,32 @@ public class CodeGen {
_tRegAlloc = (int)(System.currentTimeMillis() - t0);
return this;
}
+
+ //public static void print_as_hex(ByteArrayOutputStream outputStream) {
+ // byte[] encodedBytes = outputStream.toByteArray();
+ // for (byte b : encodedBytes) {
+ // System.out.print(String.format("%02X", b));
+ // }
+ // System.out.println();
+ //}
+ //
+ //// Debug purposes for now
+ //public CodeGen printENCODING() {
+ // ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
+ //
+ // for(Node bb : CodeGen.CODE._cfg) {
+ // for(Node n: bb.outs()) {
+ // if(n instanceof MachNode) {
+ // ((MachNode) n).encoding(outputStream);
+ // }
+ // }
+ // }
+ //
+ // print_as_hex(outputStream);
+ // // Get the raw bytes from the output stream
+ // return this;
+ //}
+
public String reg(Node n) {
if( _phase.ordinal() >= Phase.RegAlloc.ordinal() ) {
String s = _regAlloc.reg(n);
@@ -303,14 +332,14 @@ public class CodeGen {
// ---------------------------
// Encoding
int _tEncode;
- public Encoding _encoding;
public CodeGen encode() {
assert _phase == Phase.RegAlloc;
_phase = Phase.Encoding;
long t0 = System.currentTimeMillis();
- _encoding = new Encoding(this);
- _encoding.encode();
- _tEncode = (int)(System.currentTimeMillis() - t0);
+
+
+ //_tEncode = (int)(System.currentTimeMillis() - t0);
+ //throw Utils.TODO();
return this;
}
// Encoded binary, no relocation info
diff --git a/chapter21/src/main/java/com/seaofnodes/simple/codegen/ElfExpr.java b/chapter21/src/main/java/com/seaofnodes/simple/codegen/ElfExpr.java
new file mode 100644
index 00000000..9d9b8a1c
--- /dev/null
+++ b/chapter21/src/main/java/com/seaofnodes/simple/codegen/ElfExpr.java
@@ -0,0 +1,87 @@
+package com.seaofnodes.simple.codegen;
+
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+
+public class ElfExpr {
+ public static void main(String[] args) {
+ try (FileOutputStream fos = new FileOutputStream("hello.o")) {
+ ByteBuffer buffer = ByteBuffer.allocate(512);
+ buffer.order(ByteOrder.LITTLE_ENDIAN);
+
+ // === ELF HEADER (64 bytes) ===
+ buffer.put(new byte[]{
+ 0x7F, 'E', 'L', 'F', // ELF Magic
+ 2, 1, 1, 0, // 64-bit, little-endian, version
+ 0, 0, 0, 0, 0, 0, 0, // ABI padding
+ 2, 0, // Type: Executable (ET_EXEC)
+ 0x3E, 0x00, // Machine: x86-64
+ 1, 0, 0, 0, // ELF version
+ 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Entry point
+ 0, 0, 0, 0, 0, 0, 0, 0, // Program header offset
+ 64, 0, 0, 0, 0, 0, 0, 0, // Section header offset
+ 0, 0, 0, 0, // Flags
+ 64, 0, // ELF header size
+ 0, 0, // Program header entry size
+ 0, 0, // Number of program header entries
+ 40, 0, // Section header entry size
+ 2, 0, // Number of section headers
+ 1, 0 // Section header string table index
+ });
+
+ // === .TEXT SECTION (Executable Code) ===
+ byte[] textSection = {
+ // sys_write (write(1, message, 13))
+ (byte) 0x48, (byte) 0xC7, (byte) 0xC0, 0x01, 0x00, 0x00, 0x00, // mov rax, 1
+ (byte) 0x48, (byte) 0xC7, (byte) 0xC7, 0x01, 0x00, 0x00, 0x00, // mov rdi, 1
+ (byte) 0x48, (byte) 0xBE, (byte)0x90, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // mov rsi, message
+ (byte) 0x48, (byte) 0xC7, (byte) 0xC2, 0x0D, 0x00, 0x00, 0x00, // mov rdx, 13
+ (byte) 0x0F, (byte) 0x05, // syscall
+
+ // sys_exit (exit(0))
+ (byte) 0x48, (byte) 0xC7, (byte) 0xC0, 0x3C, 0x00, 0x00, 0x00, // mov rax, 60
+ (byte) 0x48, (byte) 0x31, (byte) 0xFF, // xor rdi, rdi
+ (byte) 0x0F, (byte) 0x05 // syscall
+ };
+
+ // Append section data
+ buffer.position(256);
+ buffer.put(textSection);
+
+ // === STRING MESSAGE (.data Section) ===
+ byte[] message = "Hello, World!\n".getBytes();
+ buffer.position(400);
+ buffer.put(message);
+
+ // === SECTION HEADERS ===
+ buffer.position(64);
+
+ // Null Section (required as first entry)
+ buffer.put(new byte[40]);
+
+ // .text Section
+ buffer.putInt(1); // Offset in section string table (".text")
+ buffer.putInt(1); // Type: SHT_PROGBITS
+ buffer.putLong(6); // Flags: Executable | Allocatable
+ buffer.putLong(0); // Virtual address
+ buffer.putLong(256); // Offset to section data
+ buffer.putLong(textSection.length); // Section size
+ buffer.putInt(0); // Link
+ buffer.putInt(0); // Info
+ buffer.putLong(4); // Address alignment
+ buffer.putLong(0); // No extra entries
+
+ // === SECTION HEADER STRING TABLE ===
+ buffer.position(500);
+ buffer.put(".text".getBytes());
+ buffer.put((byte) 0x00); // Null terminator
+
+ fos.write(buffer.array());
+ System.out.println("ELF object file 'hello.o' created.");
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+}
diff --git a/chapter21/src/main/java/com/seaofnodes/simple/codegen/Encoding.java b/chapter21/src/main/java/com/seaofnodes/simple/codegen/Encoding.java
index 86cf9daa..cae007f7 100644
--- a/chapter21/src/main/java/com/seaofnodes/simple/codegen/Encoding.java
+++ b/chapter21/src/main/java/com/seaofnodes/simple/codegen/Encoding.java
@@ -3,6 +3,8 @@ package com.seaofnodes.simple.codegen;
import com.seaofnodes.simple.Utils;
import com.seaofnodes.simple.Ary;
import com.seaofnodes.simple.node.*;
+import com.seaofnodes.simple.type.TypeFunPtr;
+import com.seaofnodes.simple.type.Type;
import java.io.ByteArrayOutputStream;
import java.util.BitSet;
@@ -35,19 +37,58 @@ public class Encoding {
final ByteArrayOutputStream _bits;
-
Encoding( CodeGen code ) {
_code = code;
_bits = new ByteArrayOutputStream();
}
+ // Short cut to the defining register
+ public short reg(Node n) {
+ return _code._regAlloc.regnum(n);
+ }
+
+ public void add1( int op ) { _bits.write(op); }
+
+ // Little endian write of a 32b opcode
+ public void add4( int op ) {
+ _bits.write(op );
+ _bits.write(op>> 8);
+ _bits.write(op>>16);
+ _bits.write(op>>24);
+ }
+ public void add8( long i64 ) {
+ add4((int) i64 );
+ add4((int)(i64>>32));
+ }
+
+
+ // Relocation thinking:
+ // `encoding()` calls back with info (TFP needed, branch target needed).
+ // Record start of op & TFP/target info.
+
+ // During some future RELO phase, after TFP layout/targets known
+ // call back with `ReloNode.patch(byte[],src_offset,TFP,dst_offset)`
+ // X86 gets a special pass for expanding short jumps.
+
+ public void relo( Node relo, TypeFunPtr t ) {
+ // TODO: record call relocation info
+ }
+ public void relo( NewNode nnn ) {
+ // TODO: record alloc relocation info
+ }
+ // Store t as a 32/64 bit constant in the code space; generate RIP-relative
+ // addressing to load it
+ public void largeConstant( Node relo, Type t ) {
+ assert t.isConstant();
+ // TODO:
+ }
+ public void jump( IfNode jmp, CProjNode target ) {
+ // TDOO: also support 1-byte offset and short jump and compressing the binary
+ // TODO: record and patch
+ }
void encode() {
- // Basic block layout. Now that RegAlloc is finished, no more spill
- // code will appear. We can change our BB layout from RPO to something
- // that minimizes actual branches, takes advantage of fall-through
- // edges, and tries to help simple branch predictions: back branches
- // are predicted taken, forward not-taken.
+ // Basic block layout
Ary<CFGNode> rpo = new Ary<>(CFGNode.class);
BitSet visit = _code.visit();
for( Node n : _code._start._outputs )
@@ -61,13 +102,17 @@ public class Encoding {
_code._cfg = rpo; // Save the new ordering
// Write encoding bits in order
- //for( CFGNode bb : _code._cfg )
- // for( Node n : bb._outputs )
- // if( n instanceof MachNode mach )
- // throw Utils.TODO();
+ for( CFGNode bb : _code._cfg )
+ for( Node n : bb._outputs )
+ if( n instanceof MachNode mach )
+ throw Utils.TODO();
}
- // Post-Order of CFG
+ // Basic block layout. Now that RegAlloc is finished, no more spill code
+ // will appear. We can change our BB layout from RPO to something that
+ // minimizes actual branches, takes advantage of fall-through edges, and
+ // tries to help simple branch predictions: back branches are predicted
+ // taken, forward not-taken.
private static void _rpo_cfg(CFGNode bb, BitSet visit, Ary<CFGNode> rpo) {
if( visit.get(bb._nid) ) return;
visit.set(bb._nid);
diff --git a/chapter21/src/main/java/com/seaofnodes/simple/codegen/IFG.java b/chapter21/src/main/java/com/seaofnodes/simple/codegen/IFG.java
index 1f3186ff..bd6c2d56 100644
--- a/chapter21/src/main/java/com/seaofnodes/simple/codegen/IFG.java
+++ b/chapter21/src/main/java/com/seaofnodes/simple/codegen/IFG.java
@@ -209,10 +209,8 @@ abstract public class IFG {
// Special case for Intel XOR used to zero.
if( m.isClone() )
alloc.fail(alloc.lrg((Node)m));
- else if( !tlrg.sub(killMask) ) {
- tlrg._killed = true; // Failed by a kill-mask
+ else if( !tlrg.sub(killMask) )
alloc.fail(tlrg);
- }
}
}
}
diff --git a/chapter21/src/main/java/com/seaofnodes/simple/codegen/RegAlloc.java b/chapter21/src/main/java/com/seaofnodes/simple/codegen/RegAlloc.java
index 9e607349..badec740 100644
--- a/chapter21/src/main/java/com/seaofnodes/simple/codegen/RegAlloc.java
+++ b/chapter21/src/main/java/com/seaofnodes/simple/codegen/RegAlloc.java
@@ -123,7 +123,7 @@ public class RegAlloc {
}
- public int regnum( Node n ) {
+ public short regnum( Node n ) {
LRG lrg = lrg(n);
return lrg==null ? -1 : lrg._reg;
}
diff --git a/chapter21/src/main/java/com/seaofnodes/simple/node/CalleeSaveNode.java b/chapter21/src/main/java/com/seaofnodes/simple/node/CalleeSaveNode.java
index d4a937bd..0afc5827 100644
--- a/chapter21/src/main/java/com/seaofnodes/simple/node/CalleeSaveNode.java
+++ b/chapter21/src/main/java/com/seaofnodes/simple/node/CalleeSaveNode.java
@@ -1,10 +1,8 @@
package com.seaofnodes.simple.node;
-import com.seaofnodes.simple.Utils;
+import com.seaofnodes.simple.codegen.Encoding;
import com.seaofnodes.simple.codegen.RegMask;
import com.seaofnodes.simple.type.Type;
-import java.util.BitSet;
-import java.io.ByteArrayOutputStream;
public class CalleeSaveNode extends ProjNode implements MachNode {
final RegMask _mask;
@@ -18,7 +16,7 @@ public class CalleeSaveNode extends ProjNode implements MachNode {
}
@Override public RegMask regmap(int i) { return null; }
@Override public RegMask outregmap() { return _mask; }
- @Override public int encoding(ByteArrayOutputStream bytes) { return 0; }
+ @Override public void encoding( Encoding enc ) { }
@Override public Type compute() { return Type.BOTTOM; }
@Override public Node idealize() { return null; }
diff --git a/chapter21/src/main/java/com/seaofnodes/simple/node/MachNode.java b/chapter21/src/main/java/com/seaofnodes/simple/node/MachNode.java
index ecdbc651..2c67ff2d 100644
--- a/chapter21/src/main/java/com/seaofnodes/simple/node/MachNode.java
+++ b/chapter21/src/main/java/com/seaofnodes/simple/node/MachNode.java
@@ -1,10 +1,7 @@
package com.seaofnodes.simple.node;
import com.seaofnodes.simple.*;
-import com.seaofnodes.simple.codegen.Machine;
-import com.seaofnodes.simple.codegen.CodeGen;
-import com.seaofnodes.simple.codegen.RegMask;
-import java.io.ByteArrayOutputStream;
+import com.seaofnodes.simple.codegen.*;
public interface MachNode {
@@ -48,7 +45,7 @@ public interface MachNode {
default Node copy() { return null; }
// Encoding is appended into the byte array; size is returned
- int encoding(ByteArrayOutputStream bytes);
+ void encoding( Encoding enc );
// Human-readable form appended to the SB. Things like the encoding,
// indentation, leading address or block labels not printed here.
diff --git a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/AddARM.java b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/AddARM.java
index c4014571..b95e3719 100644
--- a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/AddARM.java
+++ b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/AddARM.java
@@ -1,34 +1,18 @@
package com.seaofnodes.simple.node.cpus.arm;
import com.seaofnodes.simple.*;
-import com.seaofnodes.simple.codegen.CodeGen;
-import com.seaofnodes.simple.codegen.RegMask;
+import com.seaofnodes.simple.codegen.*;
import com.seaofnodes.simple.node.*;
-import com.seaofnodes.simple.type.TypeInteger;
-import java.io.ByteArrayOutputStream;
public class AddARM extends MachConcreteNode implements MachNode {
-
- AddARM( Node add) {super(add); }
-
- // Register mask allowed on input i.
- @Override public RegMask regmap(int i) {
- assert i== 1 || i == 2 || i == 3;
- return arm.RMASK;
- }
- // Register mask allowed as a result. 0 for no register.
+ AddARM( Node add) { super(add); }
+ @Override public String op() { return "add"; }
+ @Override public RegMask regmap(int i) { return arm.RMASK; }
@Override public RegMask outregmap() { return arm.RMASK; }
-
- // Encoding is appended into the byte array; size is returned
- @Override public int encoding(ByteArrayOutputStream bytes) {
- throw Utils.TODO();
- }
-
+ @Override public void encoding( Encoding enc ) { arm.r_reg(enc,this,139); }
// General form: "rd = rs1 + rs2"
@Override public void asm(CodeGen code, SB sb) {
sb.p(code.reg(this)).p(" = ").p(code.reg(in(1))).p(" + ").p(code.reg(in(2)));
}
- @Override public String op() {
- return "add";}
}
diff --git a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/AddFARM.java b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/AddFARM.java
index 098ab8c1..35d1eef1 100644
--- a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/AddFARM.java
+++ b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/AddFARM.java
@@ -1,25 +1,15 @@
package com.seaofnodes.simple.node.cpus.arm;
-
-import com.seaofnodes.simple.*;
-import com.seaofnodes.simple.codegen.CodeGen;
-import com.seaofnodes.simple.codegen.RegMask;
+import com.seaofnodes.simple.SB;
+import com.seaofnodes.simple.codegen.*;
import com.seaofnodes.simple.node.*;
-import com.seaofnodes.simple.type.TypeInteger;
-import java.io.ByteArrayOutputStream;
public class AddFARM extends MachConcreteNode implements MachNode {
AddFARM(Node addf) { super(addf); }
-
- // Register mask allowed on input i.
- @Override public RegMask regmap(int i) { assert i==1 || i==2; return arm.DMASK; }
- // Register mask allowed as a result. 0 for no register.
+ @Override public String op() { return "addf"; }
+ @Override public RegMask regmap(int i) { return arm.DMASK; }
@Override public RegMask outregmap() { return arm.DMASK; }
-
- // Encoding is appended into the byte array; size is returned
- @Override public int encoding(ByteArrayOutputStream bytes) {
- throw Utils.TODO();
- }
+ @Override public void encoding( Encoding enc ) { arm.f_scalar(enc,this,10); }
// Default on double precision for now(64 bits)
// General form: "vadd.32 rd = src1 + src2
@@ -27,5 +17,4 @@ public class AddFARM extends MachConcreteNode implements MachNode {
sb.p(code.reg(this)).p(" = ").p(code.reg(in(1))).p(" + ").p(code.reg(in(2)));
}
- @Override public String op() { return "addf"; }
}
diff --git a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/AddIARM.java b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/AddIARM.java
index c8f5f8dd..b37fadee 100644
--- a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/AddIARM.java
+++ b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/AddIARM.java
@@ -1,51 +1,24 @@
package com.seaofnodes.simple.node.cpus.arm;
import com.seaofnodes.simple.*;
-import com.seaofnodes.simple.codegen.CodeGen;
-import com.seaofnodes.simple.codegen.RegMask;
+import com.seaofnodes.simple.codegen.*;
import com.seaofnodes.simple.node.*;
-import com.seaofnodes.simple.type.TypeInteger;
-import java.io.ByteArrayOutputStream;
public class AddIARM extends MachConcreteNode implements MachNode {
- final TypeInteger _ti;
-
- AddIARM(Node add, TypeInteger ti) {
+ final int _imm;
+ AddIARM(Node add, int imm) {
super(add);
_inputs.pop();
- _ti = ti;
- }
-
- // Register mask allowed on input i.
- @Override
- public RegMask regmap(int i) {
- // assert i== i;
- return arm.RMASK;
+ _imm = imm;
}
-
- // Register mask allowed as a result. 0 for no register.
- @Override
- public RegMask outregmap() {
- return arm.RMASK;
- }
-
- // Encoding is appended into the byte array; size is returned
- @Override
- public int encoding(ByteArrayOutputStream bytes) {
- throw Utils.TODO();
+ @Override public String op() {
+ return _imm == 1 ? "inc" : (_imm == -1 ? "dec" : "addi");
}
-
+ @Override public RegMask regmap(int i) { return arm.RMASK; }
+ @Override public RegMask outregmap() { return arm.RMASK; }
+ @Override public void encoding( Encoding enc ) { arm.imm_inst(enc,this,580,_imm); }
// General form: "addi rd = rs1 + imm"
- @Override
- public void asm(CodeGen code, SB sb) {
- sb.p(code.reg(this)).p(" = ").p(code.reg(in(1))).p(" + #");
- _ti.print(sb);
+ @Override public void asm(CodeGen code, SB sb) {
+ sb.p(code.reg(this)).p(" = ").p(code.reg(in(1))).p(" + #").p(_imm);
}
-
- @Override
- public String op() {
- return _ti.value() == 1 ? "inc" : (_ti.value() == -1 ? "dec" : "addi");
-
- }
-
-} \ No newline at end of file
+}
diff --git a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/AndARM.java b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/AndARM.java
index d4a384d1..7c9cc3d7 100644
--- a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/AndARM.java
+++ b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/AndARM.java
@@ -1,34 +1,18 @@
package com.seaofnodes.simple.node.cpus.arm;
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.*;
import com.seaofnodes.simple.node.MachConcreteNode;
import com.seaofnodes.simple.node.MachNode;
import com.seaofnodes.simple.node.Node;
-import java.io.ByteArrayOutputStream;
-
public class AndARM extends MachConcreteNode implements MachNode {
AndARM(Node and) { super(and); }
-
- // Register mask allowed on input i.
- // This is the normal calling convention
@Override public RegMask regmap(int i) { return arm.RMASK; }
-
- // Register mask allowed as a result. 0 for no register.
@Override public RegMask outregmap() { return arm.RMASK; }
-
- // Encoding is appended into the byte array; size is returned
- @Override public int encoding(ByteArrayOutputStream bytes) {
- throw Utils.TODO();
- }
-
- // General form
+ @Override public void encoding( Encoding enc ) { arm.r_reg(enc,this,138); }
// General form: #rd = rs1 & rs2
@Override public void asm(CodeGen code, SB sb){
sb.p(code.reg(this)).p(" = ").p(code.reg(in(1))).p(" & ").p(code.reg(in(2)));
}
- @Override public String op() { return "and"; }
}
diff --git a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/AndIARM.java b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/AndIARM.java
deleted file mode 100644
index ee05654b..00000000
--- a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/AndIARM.java
+++ /dev/null
@@ -1,56 +0,0 @@
-package com.seaofnodes.simple.node.cpus.arm;
-
-
-import com.seaofnodes.simple.*;
-import com.seaofnodes.simple.codegen.CodeGen;
-import com.seaofnodes.simple.codegen.RegMask;
-import com.seaofnodes.simple.node.*;
-import com.seaofnodes.simple.type.Type;
-import com.seaofnodes.simple.type.TypeInteger;
-import java.io.ByteArrayOutputStream;
-import java.util.BitSet;
-import java.lang.StringBuilder;
-
-public class AndIARM extends MachConcreteNode implements MachNode {
- final TypeInteger _ti;
-
- AndIARM(AndNode and, TypeInteger ti) {
- super(and);
- _inputs.pop();
- _ti = ti;
- }
-
- // Register mask allowed on input i.
- // This is the normal calling convention
- @Override
- public RegMask regmap(int i) {
- assert i == 1 || i == 2;
- return arm.RMASK;
- }
-
- // Register mask allowed as a result. 0 for no register.
- @Override
- public RegMask outregmap() {
- return arm.RMASK;
- }
-
- // Encoding is appended into the byte array; size is returned
- @Override
- public int encoding(ByteArrayOutputStream bytes) {
- throw Utils.TODO();
- }
-
- // General form
- // General form: "andi rd = rs1 & imm"
- @Override
- public void asm(CodeGen code, SB sb) {
- sb.p(code.reg(this)).p(" = ").p(code.reg(in(1))).p(" & #");
- _ti.print(sb);
- }
-
- @Override
- public String op() {
- return "andi";
- }
-
-} \ No newline at end of file
diff --git a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/AsrARM.java b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/AsrARM.java
index a79de49b..d91a18ab 100644
--- a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/AsrARM.java
+++ b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/AsrARM.java
@@ -1,40 +1,18 @@
package com.seaofnodes.simple.node.cpus.arm;
import com.seaofnodes.simple.*;
-import com.seaofnodes.simple.codegen.CodeGen;
-import com.seaofnodes.simple.codegen.RegMask;
+import com.seaofnodes.simple.codegen.*;
import com.seaofnodes.simple.node.*;
-import com.seaofnodes.simple.type.Type;
-import com.seaofnodes.simple.type.TypeInteger;
-import java.io.ByteArrayOutputStream;
-import java.util.BitSet;
-import java.lang.StringBuilder;
// Arithmetic Shift Right (register)
public class AsrARM extends MachConcreteNode implements MachNode {
AsrARM(Node asr) {super(asr);}
- // Register mask allowed on input i.
- // This is the normal calling convention
- @Override public RegMask regmap(int i) {
- // assert i==1;
- return arm.RMASK; }
- // Register mask allowed as a result. 0 for no register.
+ @Override public String op() { return "sar"; }
+ @Override public RegMask regmap(int i) { return arm.RMASK; }
@Override public RegMask outregmap() { return arm.RMASK; }
-
- // Output is same register as input#1
- @Override public int twoAddress() { return 1; }
-
- // Encoding is appended into the byte array; size is returned
- @Override public int encoding(ByteArrayOutputStream bytes) {
- throw Utils.TODO();
- }
-
- // General form
- // General form: "asr rd, rs1, rs2"
+ @Override public void encoding( Encoding enc ) { arm.shift_reg(enc,this,10); }
@Override public void asm(CodeGen code, SB sb) {
-
sb.p(code.reg(this)).p(" = ").p(code.reg(in(1))).p(" >> ").p(code.reg(in(2)));
}
- @Override public String op() { return "asr"; }
}
diff --git a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/AsrIARM.java b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/AsrIARM.java
deleted file mode 100644
index 099c3699..00000000
--- a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/AsrIARM.java
+++ /dev/null
@@ -1,41 +0,0 @@
-package com.seaofnodes.simple.node.cpus.arm;
-
-
-import com.seaofnodes.simple.*;
-import com.seaofnodes.simple.codegen.CodeGen;
-import com.seaofnodes.simple.codegen.RegMask;
-import com.seaofnodes.simple.node.*;
-import com.seaofnodes.simple.type.Type;
-import com.seaofnodes.simple.type.TypeInteger;
-import java.io.ByteArrayOutputStream;
-import java.util.BitSet;
-import java.lang.StringBuilder;
-
-// Arithmetic Shift Right (immediate)
-public class AsrIARM extends MachConcreteNode implements MachNode {
- final TypeInteger _ti;
- AsrIARM(Node asri, TypeInteger ti) {super(asri); _inputs.pop(); _ti = ti;}
-
- // Register mask allowed on input i.
- // This is the normal calling convention
- @Override public RegMask regmap(int i) {
- // assert i==1;
- return arm.RMASK; }
-
- // Register mask allowed as a result. 0 for no register.
- @Override public RegMask outregmap() { return arm.RMASK; }
-
- // Encoding is appended into the byte array; size is returned
- @Override public int encoding(ByteArrayOutputStream bytes) {
- throw Utils.TODO();
- }
-
- // General form
- // General form: "asri rd, rs1, imm"
- @Override public void asm(CodeGen code, SB sb) {
- sb.p(code.reg(this)).p(" = ").p(code.reg(in(1))).p(" >> #");
- _ti.print(sb);
- }
-
- @Override public String op() { return "asri"; }
-}
diff --git a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/BranchARM.java b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/BranchARM.java
index 66a6a9ae..9ec69f62 100644
--- a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/BranchARM.java
+++ b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/BranchARM.java
@@ -1,19 +1,18 @@
package com.seaofnodes.simple.node.cpus.arm;
import com.seaofnodes.simple.*;
-import com.seaofnodes.simple.codegen.CodeGen;
-import com.seaofnodes.simple.codegen.RegMask;
+import com.seaofnodes.simple.codegen.*;
import com.seaofnodes.simple.node.*;
-import java.io.ByteArrayOutputStream;
+
// Jump on flags, uses flags
public class BranchARM extends IfNode implements MachNode{
- String _bop;
+ final String _bop;
BranchARM(IfNode iff, String bop ) {
super(iff);
_bop = bop;
}
-
+ @Override public String op() { return "j"+_bop; }
@Override public String label() { return op(); }
@Override public void postSelect() {
@@ -30,18 +29,24 @@ public class BranchARM extends IfNode implements MachNode{
@Override public RegMask outregmap() { return null; }
// Encoding is appended into the byte array; size is returned
- @Override public int encoding(ByteArrayOutputStream bytes) {
- throw Utils.TODO();
+ @Override public void encoding( Encoding enc ) {
+ // Assuming that condition flags are already set. These flags are set
+ // by comparison (or sub). No need for regs because it uses flags
+ arm.COND cond = switch (_bop) {
+ case "==" -> arm.COND.EQ;
+ case "!=" -> arm.COND.NE;
+ case "<" -> arm.COND.LE;
+ case "<=" -> arm.COND.LT;
+ case ">=" -> arm.COND.GT;
+ case ">" -> arm.COND.GE;
+ default -> throw Utils.TODO();
+ };
+ int body = arm.b_cond(84, 0, cond);
+ enc.add4(body);
}
-
@Override public void asm(CodeGen code, SB sb) {
String src = code.reg(in(1));
if( src!="flags" ) sb.p(src);
}
-
- @Override public String op() { return "j"+_bop; }
- @Override public String comment() {
- return "L"+cproj(1)._nid+", L"+cproj(0)._nid;
- }
- @Override public void invert() { _bop = invert(_bop); }
+ @Override public String comment() { return "L"+cproj(1)._nid+", L"+cproj(0)._nid; }
}
diff --git a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/CallARM.java b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/CallARM.java
index 4359c045..3058e7c8 100644
--- a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/CallARM.java
+++ b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/CallARM.java
@@ -1,11 +1,9 @@
package com.seaofnodes.simple.node.cpus.arm;
import com.seaofnodes.simple.*;
-import com.seaofnodes.simple.codegen.CodeGen;
-import com.seaofnodes.simple.codegen.RegMask;
+import com.seaofnodes.simple.codegen.*;
import com.seaofnodes.simple.node.*;
import com.seaofnodes.simple.type.TypeFunPtr;
-import java.io.ByteArrayOutputStream;
public class CallARM extends CallNode implements MachNode {
final TypeFunPtr _tfp;
@@ -19,18 +17,17 @@ public class CallARM extends CallNode implements MachNode {
_name = CodeGen.CODE.link(tfp)._name;
}
+ @Override public String op() { return "call"; }
@Override public String label() { return op(); }
- @Override public RegMask regmap(int i) {
- return arm.callInMask(_tfp,i); // Normal argument
- }
- @Override public RegMask outregmap() { return null; }
-
@Override public String name() { return _name; }
@Override public TypeFunPtr tfp() { return _tfp; }
+ @Override public RegMask regmap(int i) { return arm.callInMask(_tfp,i); }
+ @Override public RegMask outregmap() { return null; }
// Encoding is appended into the byte array; size is returned
- @Override public int encoding(ByteArrayOutputStream bytes) {
- throw Utils.TODO();
+ @Override public void encoding( Encoding enc ) {
+ enc.relo(this,_tfp); // Record relo info
+ enc.add4(arm.b(37,0));
}
@Override public void asm(CodeGen code, SB sb) {
@@ -39,7 +36,4 @@ public class CallARM extends CallNode implements MachNode {
sb.p(code.reg(arg(i))).p(" ");
sb.unchar(2);
}
-
- @Override public String op() { return "call"; }
-
}
diff --git a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/CallEndARM.java b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/CallEndARM.java
index 6177c5ea..0d9663c4 100644
--- a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/CallEndARM.java
+++ b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/CallEndARM.java
@@ -1,14 +1,10 @@
package com.seaofnodes.simple.node.cpus.arm;
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.*;
import com.seaofnodes.simple.node.CallEndNode;
import com.seaofnodes.simple.node.MachNode;
-import com.seaofnodes.simple.type.TypeFloat;
import com.seaofnodes.simple.type.TypeFunPtr;
-import java.io.ByteArrayOutputStream;
public class CallEndARM extends CallEndNode implements MachNode {
final TypeFunPtr _tfp;
@@ -17,19 +13,12 @@ public class CallEndARM extends CallEndNode implements MachNode {
_tfp = (TypeFunPtr)(cend.call().fptr()._type);
}
+ @Override public String op() { return "cend"; }
@Override public String label() { return op(); }
@Override public RegMask regmap(int i) { return null; }
@Override public RegMask outregmap() { return null; }
@Override public RegMask outregmap(int idx) { return idx == 2 ? arm.retMask(_tfp,2) : null; }
@Override public RegMask killmap() { return arm.armCallerSave(); }
-
- // Encoding is appended into the byte array; size is returned
- @Override public int encoding(ByteArrayOutputStream bytes) {
- throw Utils.TODO();
- }
-
+ @Override public void encoding( Encoding enc ) { }
@Override public void asm(CodeGen code, SB sb) { }
-
- @Override public String op() { return "cend"; }
-
}
diff --git a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/CallRRARM.java b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/CallRRARM.java
index db85a9a9..1d76b621 100644
--- a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/CallRRARM.java
+++ b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/CallRRARM.java
@@ -1,25 +1,23 @@
package com.seaofnodes.simple.node.cpus.arm;
import com.seaofnodes.simple.*;
-import com.seaofnodes.simple.codegen.CodeGen;
-import com.seaofnodes.simple.codegen.RegMask;
+import com.seaofnodes.simple.codegen.*;
import com.seaofnodes.simple.node.*;
-import java.io.ByteArrayOutputStream;
public class CallRRARM extends CallNode implements MachNode {
- CallRRARM(CallNode call) {super(call);}
+ CallRRARM(CallNode call) { super(call); }
@Override public String op() { return "callr"; }
@Override public String label() { return op(); }
@Override public RegMask regmap(int i) {
- // Todo: float or int?
return i==_inputs._len
? arm.RMASK // Function call target
: arm.callInMask(tfp(),i); // Normal argument
}
@Override public RegMask outregmap() { return null; }
- // Encoding is appended into the byte array; size is returned
- @Override public int encoding(ByteArrayOutputStream bytes) {
+ @Override public void encoding( Encoding enc ) {
+ //enc.add4(arm.b(37, 0));
+ // Needs a register, typically a jump-and-link-register opcode
throw Utils.TODO();
}
@@ -29,4 +27,5 @@ public class CallRRARM extends CallNode implements MachNode {
sb.p(code.reg(arg(i))).p(" ");
sb.unchar(2);
}
+
}
diff --git a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/CmpARM.java b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/CmpARM.java
index f4f6242d..f97fdeda 100644
--- a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/CmpARM.java
+++ b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/CmpARM.java
@@ -1,25 +1,15 @@
package com.seaofnodes.simple.node.cpus.arm;
-import com.seaofnodes.simple.*;
-import com.seaofnodes.simple.codegen.CodeGen;
-import com.seaofnodes.simple.codegen.RegMask;
+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.TypeFunPtr;
-import java.io.ByteArrayOutputStream;
public class CmpARM extends MachConcreteNode implements MachNode {
CmpARM( Node cmp ) { super(cmp); }
@Override public String op() { return "cmp"; }
-
-
- @Override public RegMask regmap(int i) { assert i==1 || i==2; return arm.RMASK; }
+ @Override public RegMask regmap(int i) { return arm.RMASK; }
@Override public RegMask outregmap() { return arm.FLAGS_MASK; }
-
- // Encoding is appended into the byte array; size is returned
- @Override public int encoding(ByteArrayOutputStream bytes) {
- throw Utils.TODO();
- }
+ @Override public void encoding( Encoding enc ) { arm.r_reg(enc,this,235); }
// General form: "cmp rs1, rs2"
@Override public void asm(CodeGen code, SB sb) {
diff --git a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/CmpFARM.java b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/CmpFARM.java
index 9c287fcb..f2880078 100644
--- a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/CmpFARM.java
+++ b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/CmpFARM.java
@@ -1,31 +1,21 @@
package com.seaofnodes.simple.node.cpus.arm;
import com.seaofnodes.simple.*;
-import com.seaofnodes.simple.codegen.CodeGen;
-import com.seaofnodes.simple.codegen.RegMask;
+import com.seaofnodes.simple.codegen.*;
import com.seaofnodes.simple.node.*;
-import com.seaofnodes.simple.type.Type;
-import com.seaofnodes.simple.type.TypeFunPtr;
-import java.io.ByteArrayOutputStream;
// compare instruction on float regs input(D-registers)
public class CmpFARM extends MachConcreteNode implements MachNode{
CmpFARM(Node cmp) {super(cmp);}
-
+ @Override public String op() { return "cmpf"; }
+ @Override public RegMask regmap(int i) { return arm.DMASK; }
+ @Override public RegMask outregmap() { return arm.FLAGS_MASK; }
// Encoding is appended into the byte array; size is returned
- @Override public int encoding(ByteArrayOutputStream bytes) {
- throw Utils.TODO();
- }
-
+ @Override public void encoding( Encoding enc ) { arm.f_cmp(enc,this); }
// General form: "cmp d0, d1"
@Override public void asm(CodeGen code, SB sb) {
String dst = code.reg(this);
if( dst!="flags" ) sb.p(dst).p(" = ");
sb.p(code.reg(in(1))).p(", ").p(code.reg(in(2)));
}
-
- @Override public RegMask regmap(int i) { assert i==1 || i==2; return arm.DMASK; }
- @Override public RegMask outregmap() { return arm.FLAGS_MASK; }
-
- @Override public String op() { return "cmpf"; }
}
diff --git a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/CmpIARM.java b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/CmpIARM.java
index a0b10ba4..b00ddfbe 100644
--- a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/CmpIARM.java
+++ b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/CmpIARM.java
@@ -1,46 +1,25 @@
package com.seaofnodes.simple.node.cpus.arm;
import com.seaofnodes.simple.*;
-import com.seaofnodes.simple.codegen.CodeGen;
-import com.seaofnodes.simple.codegen.RegMask;
+import com.seaofnodes.simple.codegen.*;
import com.seaofnodes.simple.node.*;
-import com.seaofnodes.simple.type.Type;
-import com.seaofnodes.simple.type.TypeInteger;
-import java.io.ByteArrayOutputStream;
// Compare with immediate.
// Conditional compare (immediate)? e.g CCMP(immediate)
public class CmpIARM extends MachConcreteNode implements MachNode {
final int _imm;
final String _bop;
- CmpIARM(BoolNode bool, TypeInteger ti) {
+ CmpIARM(BoolNode bool, int imm) {
super(bool);
_inputs.pop();
_bop = bool.op();
- _imm = (int)ti.value();
- assert _imm == ti.value();
+ _imm = imm;
}
- // Copy constructor does not set reverse edges in, because the basic block
- // is changing from the original node - and it must be properly placed in a
- // new block.
- CmpIARM( CmpIARM cmp ) {
- super(cmp);
- _bop = cmp._bop;
- _imm = cmp._imm;
- // While in(0) will be handled by the caller, all other edges must be
- // handled in the constructor.
- cmp.in(1)._outputs.push(this);
- }
-
- @Override public RegMask regmap(int i) { assert i==1; return arm.RMASK; }
+ @Override public String op() { return _imm==0 ? "test" : "cmp"; }
+ @Override public RegMask regmap(int i) { return arm.RMASK; }
@Override public RegMask outregmap() { return arm.FLAGS_MASK; }
- @Override public boolean isClone() { return true; }
- @Override public Node copy() { return new CmpIARM(this); }
-
// Encoding is appended into the byte array; size is returned
- @Override public int encoding(ByteArrayOutputStream bytes) {
- throw Utils.TODO();
- }
+ @Override public void encoding( Encoding enc ) { arm.imm_inst(enc,this,964,_imm); }
// General form: "cmp rs1, 1"
@Override public void asm(CodeGen code, SB sb) {
@@ -49,6 +28,4 @@ public class CmpIARM extends MachConcreteNode implements MachNode {
sb.p(code.reg(in(1)));
if( _imm != 0 ) sb.p(", #").p(_imm);
}
- @Override public String op() { return _imm==0 ? "test" : "cmp"; }
-
}
diff --git a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/DivARM.java b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/DivARM.java
index 7c67e2dd..62ce9827 100644
--- a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/DivARM.java
+++ b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/DivARM.java
@@ -1,33 +1,18 @@
package com.seaofnodes.simple.node.cpus.arm;
import com.seaofnodes.simple.*;
-import com.seaofnodes.simple.codegen.CodeGen;
-import com.seaofnodes.simple.codegen.RegMask;
+import com.seaofnodes.simple.codegen.*;
import com.seaofnodes.simple.node.*;
-import com.seaofnodes.simple.type.TypeInteger;
-import java.io.ByteArrayOutputStream;
public class DivARM extends MachConcreteNode implements MachNode {
DivARM( Node div ) { super(div); }
-
- // Register mask allowed on input i.
- @Override public RegMask regmap(int i) {
- assert i==1 || i==2;
- return arm.RMASK; }
- // Register mask allowed as a result. 0 for no register.
+ @Override public String op() { return "div"; }
+ @Override public RegMask regmap(int i) { return arm.RMASK; }
@Override public RegMask outregmap() { return arm.RMASK; }
- // Output is same register as input#1
- @Override public int twoAddress() { return 1; }
-
- // Encoding is appended into the byte array; size is returned
- @Override public int encoding(ByteArrayOutputStream bytes) {
- throw Utils.TODO();
- }
-
+ @Override public void encoding( Encoding enc ) { arm.madd(enc,this,1238,3); }
// General form: "div dst /= src"
@Override public void asm(CodeGen code, SB sb) {
sb.p(code.reg(this)).p(" = ").p(code.reg(in(1))).p(" / ").p(code.reg(in(2)));
}
- @Override public String op() { return "div"; }
}
diff --git a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/DivFARM.java b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/DivFARM.java
index 2137c01c..8ffb14ec 100644
--- a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/DivFARM.java
+++ b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/DivFARM.java
@@ -1,30 +1,17 @@
package com.seaofnodes.simple.node.cpus.arm;
import com.seaofnodes.simple.*;
-import com.seaofnodes.simple.codegen.CodeGen;
-import com.seaofnodes.simple.codegen.RegMask;
+import com.seaofnodes.simple.codegen.*;
import com.seaofnodes.simple.node.*;
-import com.seaofnodes.simple.type.TypeInteger;
-import java.io.ByteArrayOutputStream;
public class DivFARM extends MachConcreteNode implements MachNode {
DivFARM( Node divf) { super(divf); }
-
- // Register mask allowed on input i.
- @Override public RegMask regmap(int i) { assert i==1 || i==2; return arm.DMASK; }
- // Register mask allowed as a result. 0 for no register.
+ @Override public String op() { return "divf"; }
+ @Override public RegMask regmap(int i) { return arm.DMASK; }
@Override public RegMask outregmap() { return arm.DMASK; }
-
- // Encoding is appended into the byte array; size is returned
- @Override public int encoding(ByteArrayOutputStream bytes) {
- throw Utils.TODO();
- }
-
-
+ @Override public void encoding( Encoding enc ) { arm.f_scalar(enc,this,6); }
// General form: "VDIF = dst /= src"
@Override public void asm(CodeGen code, SB sb) {
sb.p(code.reg(this)).p(" = ").p(code.reg(in(1))).p(" / ").p(code.reg(in(2)));
}
-
- @Override public String op() { return "divf"; }
}
diff --git a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/FloatARM.java b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/FloatARM.java
index 7fafc31c..70e4b085 100644
--- a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/FloatARM.java
+++ b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/FloatARM.java
@@ -2,19 +2,18 @@ package com.seaofnodes.simple.node.cpus.arm;
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.*;
import com.seaofnodes.simple.node.ConstantNode;
import com.seaofnodes.simple.node.MachNode;
-import java.io.ByteArrayOutputStream;
+import com.seaofnodes.simple.type.TypeFloat;
//FMOV (scalar, immediate)
//Floating-point move immediate.
public class FloatARM extends ConstantNode implements MachNode {
FloatARM(ConstantNode con) { super(con); }
- @Override public String op() { return "fld"; }
// Register mask allowed on input i. 0 for no register.
@Override public RegMask regmap(int i) { return null; }
+
// General int registers
@Override public RegMask outregmap() { return arm.DMASK; }
@@ -22,7 +21,12 @@ public class FloatARM extends ConstantNode implements MachNode {
@Override public FloatARM copy() { return new FloatARM(this); }
// Encoding is appended into the byte array; size is returned
- @Override public int encoding(ByteArrayOutputStream bytes) {
+ @Override public void encoding( Encoding enc ) {
+ short self = (short)(enc.reg(this) - arm.D_OFFSET);
+ double d = ((TypeFloat)_con).value();
+ long x = Double.doubleToRawLongBits(d);
+ // Any number that can be expressed as +/-n * 2-r,where n and r are integers, 16 <= n <= 31, 0 <= r <= 7.
+ //arm.f_mov(30,3,imm8,self);
throw Utils.TODO();
}
@@ -33,4 +37,8 @@ public class FloatARM extends ConstantNode implements MachNode {
@Override public void asm(CodeGen code, SB sb) {
_con.print(sb.p(code.reg(this)).p(" #"));
}
+
+ @Override public String op() {
+ return "fld"; // Some fancier encoding
+ }
}
diff --git a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/FunARM.java b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/FunARM.java
index 0134911f..736bca47 100644
--- a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/FunARM.java
+++ b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/FunARM.java
@@ -1,21 +1,13 @@
package com.seaofnodes.simple.node.cpus.arm;
-import com.seaofnodes.simple.codegen.CodeGen;
+import com.seaofnodes.simple.codegen.Encoding;
import com.seaofnodes.simple.codegen.RegMask;
-import com.seaofnodes.simple.Utils;
import com.seaofnodes.simple.node.FunNode;
import com.seaofnodes.simple.node.MachNode;
-import java.io.ByteArrayOutputStream;
-public class FunARM extends FunNode implements MachNode{
- FunARM(FunNode fun) {super(fun);}
- // Register mask allowed on input i. 0 for no register.
+public class FunARM extends FunNode implements MachNode {
+ FunARM(FunNode fun) { super(fun); }
@Override public RegMask regmap(int i) { return null; }
- // Register mask allowed as a result. 0 for no register.
@Override public RegMask outregmap() { return null; }
-
- // Encoding is appended into the byte array; size is returned
- @Override public int encoding(ByteArrayOutputStream bytes) {
- throw Utils.TODO();
- }
+ @Override public void encoding( Encoding enc ) { }
}
diff --git a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/I2F8ARM.java b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/I2F8ARM.java
index b106ab8a..f1286630 100644
--- a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/I2F8ARM.java
+++ b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/I2F8ARM.java
@@ -1,29 +1,24 @@
package com.seaofnodes.simple.node.cpus.arm;
import com.seaofnodes.simple.*;
-import com.seaofnodes.simple.codegen.CodeGen;
-import com.seaofnodes.simple.codegen.RegMask;
+import com.seaofnodes.simple.codegen.*;
import com.seaofnodes.simple.node.*;
-import com.seaofnodes.simple.type.TypeInteger;
-import java.io.ByteArrayOutputStream;
-// VCVT (between floating-point and integer)
public class I2F8ARM extends MachConcreteNode implements MachNode {
- I2F8ARM(Node i2f8) {super(i2f8);}
- @Override public String op() { return "i2f8"; }
-
- // Register mask allowed on input i.
- @Override public RegMask regmap(int i) { assert i==1; return arm.RMASK; }
- // Register mask allowed as a result. 0 for no register.
+ I2F8ARM(Node i2f8) { super(i2f8); }
+ @Override public String op() { return "cvt"; }
+ @Override public RegMask regmap(int i) { return arm.RMASK; }
@Override public RegMask outregmap() { return arm.DMASK; }
-
- // Encoding is appended into the byte array; size is returned
- @Override public int encoding(ByteArrayOutputStream bytes) {
- throw Utils.TODO();
+ @Override public void encoding( Encoding enc ) {
+ short self = (short)(enc.reg(this )-arm.D_OFFSET);
+ short reg1 = enc.reg(in(1));
+ int body = arm.float_cast(158, 1, reg1, self);
+ enc.add4(body);
}
// General form: "i2f8 (flt)int_value"
@Override public void asm(CodeGen code, SB sb) {
sb.p(code.reg(this)).p(" = ").p("(flt)").p(code.reg(in(1)));
}
+
}
diff --git a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/IntARM.java b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/IntARM.java
index 1f81300e..d44e108e 100644
--- a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/IntARM.java
+++ b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/IntARM.java
@@ -1,30 +1,30 @@
package com.seaofnodes.simple.node.cpus.arm;
import com.seaofnodes.simple.*;
-import com.seaofnodes.simple.codegen.CodeGen;
-import com.seaofnodes.simple.codegen.RegMask;
+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 java.io.ByteArrayOutputStream;
// Integer constants
public class IntARM extends ConstantNode implements MachNode {
IntARM( ConstantNode con ) { super(con); }
- @Override public String op() { return "ldi"; }
- // Register mask allowed on input i. 0 for no register.
+ @Override public String op() { return "ldi"; }
@Override public RegMask regmap(int i) { return null; }
- // General int registers
@Override public RegMask outregmap() { return arm.WMASK; }
@Override public boolean isClone() { return true; }
@Override public IntARM copy() { return new IntARM(this); }
// Encoding is appended into the byte array; size is returned
- @Override public int encoding(ByteArrayOutputStream bytes) {
- throw Utils.TODO();
+ @Override public void encoding( Encoding enc ) {
+ short self = enc.reg(this);
+ long x = ((TypeInteger)_con).value();
+ if( (short)x == x )
+ enc.add4(arm.mov(485, 0, (int)(x&0xFFFF), self));
+ else
+ throw Utils.TODO("Handle cases bigger than 16 bits");
}
// Human-readable form appended to the SB. Things like the encoding,
diff --git a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/LoadARM.java b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/LoadARM.java
index 0d59cc47..4fa16a74 100644
--- a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/LoadARM.java
+++ b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/LoadARM.java
@@ -1,13 +1,10 @@
package com.seaofnodes.simple.node.cpus.arm;
-
import com.seaofnodes.simple.SB;
-import com.seaofnodes.simple.codegen.CodeGen;
-import com.seaofnodes.simple.codegen.RegMask;
+import com.seaofnodes.simple.codegen.*;
import com.seaofnodes.simple.node.LoadNode;
import com.seaofnodes.simple.node.Node;
-
// Load memory addressing on ARM
// Support imm, reg(direct), or reg+off(indirect) addressing
// Base = base - base pointer, offset is added to base
@@ -18,20 +15,11 @@ public class LoadARM extends MemOpARM{
LoadARM(LoadNode ld,Node base, Node idx, int off) {
super(ld, base, idx, off, 0);
}
-
- @Override public RegMask regmap(int i) {
- return arm.RMASK;
- }
-
- // Wide mask loads both ints and floats; encoding varies.
- @Override public RegMask outregmap() { return arm.MEM_MASK; }
-
-
@Override public String op() { return "ld"+_sz; }
-
+ @Override public RegMask outregmap() { return arm.MEM_MASK; }
+ @Override public void encoding( Encoding enc ) { arm.ldst_encode(enc,this,1986,this); }
@Override public void asm(CodeGen code, SB sb) {
sb.p(code.reg(this)).p(",");
asm_address(code,sb);
}
-
}
diff --git a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/LslARM.java b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/LslARM.java
index 6108c889..c97608d5 100644
--- a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/LslARM.java
+++ b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/LslARM.java
@@ -1,41 +1,18 @@
package com.seaofnodes.simple.node.cpus.arm;
import com.seaofnodes.simple.*;
-import com.seaofnodes.simple.codegen.CodeGen;
-import com.seaofnodes.simple.codegen.RegMask;
+import com.seaofnodes.simple.codegen.*;
import com.seaofnodes.simple.node.*;
-import com.seaofnodes.simple.type.Type;
-import com.seaofnodes.simple.type.TypeInteger;
-import java.io.ByteArrayOutputStream;
-import java.util.BitSet;
-import java.lang.StringBuilder;
-
// Logical Shift Left (register)
public class LslARM extends MachConcreteNode implements MachNode {
LslARM(Node asr) {super(asr);}
- // Register mask allowed on input i.
- // This is the normal calling convention
- @Override public RegMask regmap(int i) {
- // assert i==1;
- return arm.RMASK; }
- // Register mask allowed as a result. 0 for no register.
+ @Override public String op() { return "shr"; }
+ @Override public RegMask regmap(int i) { return arm.RMASK; }
@Override public RegMask outregmap() { return arm.RMASK; }
-
- // Output is same register as input#1
- @Override public int twoAddress() { return 1; }
-
- // Encoding is appended into the byte array; size is returned
- @Override public int encoding(ByteArrayOutputStream bytes) {
- throw Utils.TODO();
- }
-
- // General form
- // General form: "lsl rd, rs1, rs2"
+ @Override public void encoding( Encoding enc ) { arm.shift_reg(enc,this,8); }
@Override public void asm(CodeGen code, SB sb) {
-
sb.p(code.reg(this)).p(" = ").p(code.reg(in(1))).p(" << ").p(code.reg(in(2)));
}
- @Override public String op() { return "lsl"; }
}
diff --git a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/LsrARM.java b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/LsrARM.java
index e6168dee..848f96f9 100644
--- a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/LsrARM.java
+++ b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/LsrARM.java
@@ -1,40 +1,18 @@
package com.seaofnodes.simple.node.cpus.arm;
-
import com.seaofnodes.simple.*;
-import com.seaofnodes.simple.codegen.CodeGen;
-import com.seaofnodes.simple.codegen.RegMask;
+import com.seaofnodes.simple.codegen.*;
import com.seaofnodes.simple.node.*;
-import com.seaofnodes.simple.type.Type;
-import com.seaofnodes.simple.type.TypeInteger;
-import java.io.ByteArrayOutputStream;
-import java.util.BitSet;
-import java.lang.StringBuilder;
// Logical Shift Right (register)
public class LsrARM extends MachConcreteNode implements MachNode {
LsrARM(Node asr) {super(asr);}
- // Register mask allowed on input i.
- // This is the normal calling convention
- @Override public RegMask regmap(int i) {
- // assert i==1;
- return arm.RMASK; }
- // Register mask allowed as a result. 0 for no register.
+ @Override public String op() { return "shr"; }
+ @Override public RegMask regmap(int i) { return arm.RMASK; }
@Override public RegMask outregmap() { return arm.RMASK; }
-
- // Output is same register as input#1
- @Override public int twoAddress() { return 1; }
-
- // Encoding is appended into the byte array; size is returned
- @Override public int encoding(ByteArrayOutputStream bytes) {
- throw Utils.TODO();
- }
-
- // General form
- // General form: "lsr rd, rs1, rs2"
+ @Override public void encoding( Encoding enc ) { arm.shift_reg(enc,this,9); }
@Override public void asm(CodeGen code, SB sb) {
sb.p(code.reg(this)).p(" = ").p(code.reg(in(1))).p(" >>> ").p(code.reg(in(2)));
}
- @Override public String op() { return "lsr"; }
}
diff --git a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/LsrIARM.java b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/LsrIARM.java
deleted file mode 100644
index 8fb20cb2..00000000
--- a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/LsrIARM.java
+++ /dev/null
@@ -1,41 +0,0 @@
-package com.seaofnodes.simple.node.cpus.arm;
-
-
-import com.seaofnodes.simple.*;
-import com.seaofnodes.simple.codegen.CodeGen;
-import com.seaofnodes.simple.codegen.RegMask;
-import com.seaofnodes.simple.node.*;
-import com.seaofnodes.simple.type.Type;
-import com.seaofnodes.simple.type.TypeInteger;
-import java.io.ByteArrayOutputStream;
-import java.util.BitSet;
-import java.lang.StringBuilder;
-
-// Logical Shift Right (immediate)
-public class LsrIARM extends MachConcreteNode implements MachNode{
- final TypeInteger _ti;
- LsrIARM(Node lsri, TypeInteger ti) {super(lsri); _inputs.pop(); _ti = ti;}
-
- // Register mask allowed on input i.
- // This is the normal calling convention
- @Override public RegMask regmap(int i) {
- // assert i==1;
- return arm.RMASK; }
-
- // Register mask allowed as a result. 0 for no register.
- @Override public RegMask outregmap() { return arm.RMASK; }
-
- // Encoding is appended into the byte array; size is returned
- @Override public int encoding(ByteArrayOutputStream bytes) {
- throw Utils.TODO();
- }
-
- // General form
- // General form: "lsrl rd, rs1, imm"
- @Override public void asm(CodeGen code, SB sb) {
- sb.p(code.reg(this)).p(" = ").p(code.reg(in(1))).p(" >>> #");
- _ti.print(sb);
- }
-
- @Override public String op() { return "lsrl"; }
-}
diff --git a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/MemOpARM.java b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/MemOpARM.java
index adffa501..0d49d025 100644
--- a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/MemOpARM.java
+++ b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/MemOpARM.java
@@ -1,57 +1,55 @@
package com.seaofnodes.simple.node.cpus.arm;
import com.seaofnodes.simple.*;
-import com.seaofnodes.simple.codegen.CodeGen;
-import com.seaofnodes.simple.codegen.RegMask;
+import com.seaofnodes.simple.codegen.*;
import com.seaofnodes.simple.node.*;
import com.seaofnodes.simple.type.*;
-import java.io.ByteArrayOutputStream;
+
import java.lang.StringBuilder;
import java.util.BitSet;
-public class MemOpARM extends MemOpNode implements MachNode {
- final int _off; // Limit 32 bits
- final int _imm; // Limit 32 bits
+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
final char _sz = (char)('0'+(1<<_declaredType.log_size()));
- MemOpARM(MemOpNode mop, Node base, Node idx, int off, int imm) {
+ MemOpARM(MemOpNode mop, Node ptr, Node idx, int off, int imm) {
super(mop,mop);
- assert base._type instanceof TypeMemPtr && !(base instanceof AddNode);
- assert ptr() == base;
- _inputs.setX(3,idx);
+ assert ptr._type instanceof TypeMemPtr && !(ptr instanceof AddNode);
+ assert ptr() == ptr;
+ _inputs.setX(2, ptr);
+ _inputs.setX(3, idx);
_off = off;
_imm = imm;
}
// Store-based flavors have a value edge
- MemOpARM( MemOpNode mop, Node base, Node idx, int off, int imm, Node val ) {
- this(mop,base,idx,off,imm);
+ MemOpARM( MemOpNode mop, Node ptr, Node idx, int off, int imm, Node val ) {
+ this(mop,ptr,idx,off,imm);
_inputs.setX(4,val);
}
- Node idx() { return in(3); }
- Node val() { return in(4); } // Only for stores, includin
+ @Override public String label() { return op(); }
+ Node val() { return in(4); } // Only for stores
@Override public StringBuilder _printMach(StringBuilder sb, BitSet visited) { return sb.append(".").append(_name); }
- @Override public String label() { return op(); }
@Override public Type compute() { throw Utils.TODO(); }
@Override public Node idealize() { throw Utils.TODO(); }
-
-
- // Register mask allowed on input i.
+ // Wider mask to store both GPRs and FPRs
@Override public RegMask regmap(int i) {
+ // 0 - ctrl
+ // 1 - memory
+ if( i==2 ) return arm.RMASK; // ptr/base
+ if( i==3 ) return arm.RMASK; // off/index
+ if( i==4 ) return arm.RMASK; // value
throw Utils.TODO();
}
- // Register mask allowed as a result. 0 for no register.
- @Override public RegMask outregmap() { throw Utils.TODO(); }
-
- @Override public int encoding(ByteArrayOutputStream bytes) { throw Utils.TODO(); }
SB asm_address(CodeGen code, SB sb) {
sb.p("[").p(code.reg(ptr())).p("+");
- if( idx() != null ) sb.p(code.reg(idx()));
+ if( off() != null ) sb.p(code.reg(off()));
else sb.p(_off);
return sb.p("]");
}
diff --git a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/MulARM.java b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/MulARM.java
index 582b97d4..706922a7 100644
--- a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/MulARM.java
+++ b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/MulARM.java
@@ -1,34 +1,18 @@
package com.seaofnodes.simple.node.cpus.arm;
import com.seaofnodes.simple.*;
-import com.seaofnodes.simple.codegen.CodeGen;
-import com.seaofnodes.simple.codegen.RegMask;
+import com.seaofnodes.simple.codegen.*;
import com.seaofnodes.simple.node.*;
-import com.seaofnodes.simple.type.TypeInteger;
-import java.io.ByteArrayOutputStream;
-
// mulh signed multiply instruction(no-imm form)
-public class MulARM extends MachConcreteNode implements MachNode{
+public class MulARM extends MachConcreteNode implements MachNode {
MulARM(Node mul) {super(mul);}
-
- // Register mask allowed on input i.
- @Override public RegMask regmap(int i) { assert i==1 || i==2; return arm.RMASK; }
- // Register mask allowed as a result. 0 for no register.
+ @Override public String op() { return "mul"; }
+ @Override public RegMask regmap(int i) { return arm.RMASK; }
@Override public RegMask outregmap() { return arm.RMASK; }
- // Output is same register as input#1
- @Override public int twoAddress() { return 1; }
-
- // Encoding is appended into the byte array; size is returned
- @Override public int encoding(ByteArrayOutputStream bytes) {
- throw Utils.TODO();
- }
-
+ @Override public void encoding( Encoding enc ) { arm.madd(enc,this,1240,31); }
// General form: "rd = rs1 * rs2"
@Override public void asm(CodeGen code, SB sb) {
sb.p(code.reg(this)).p(" = ").p(code.reg(in(1))).p(" * ").p(code.reg(in(2)));
}
-
- @Override public String op() { return "mul"; }
-
}
diff --git a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/MulFARM.java b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/MulFARM.java
index b71b412d..0e59bd96 100644
--- a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/MulFARM.java
+++ b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/MulFARM.java
@@ -1,30 +1,18 @@
package com.seaofnodes.simple.node.cpus.arm;
import com.seaofnodes.simple.*;
-import com.seaofnodes.simple.codegen.CodeGen;
-import com.seaofnodes.simple.codegen.RegMask;
+import com.seaofnodes.simple.codegen.*;
import com.seaofnodes.simple.node.*;
-import java.io.ByteArrayOutputStream;
public class MulFARM extends MachConcreteNode implements MachNode{
MulFARM(Node mulf) {super(mulf);}
-
- // Register mask allowed on input i.
- @Override public RegMask regmap(int i) { assert i==1 || i==2; return arm.DMASK; }
- // Register mask allowed as a result. 0 for no register.
+ @Override public String op() { return "mulf"; }
+ @Override public RegMask regmap(int i) { return arm.DMASK; }
@Override public RegMask outregmap() { return arm.DMASK; }
-
- // Encoding is appended into the byte array; size is returned
- @Override public int encoding(ByteArrayOutputStream bytes) {
- throw Utils.TODO();
- }
-
+ @Override public void encoding( Encoding enc ) { arm.f_scalar(enc,this,2); }
// Default on double precision for now(64 bits)
// General form: "VMUL.f32 rd = src1 * src2
@Override public void asm(CodeGen code, SB sb) {
sb.p(code.reg(this)).p(" = ").p(code.reg(in(1))).p(" * ").p(code.reg(in(2)));
}
-
- @Override public String op() { return "mulf"; }
-
}
diff --git a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/MulIARM.java b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/MulIARM.java
index c118b00a..e617ee13 100644
--- a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/MulIARM.java
+++ b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/MulIARM.java
@@ -2,10 +2,10 @@ package com.seaofnodes.simple.node.cpus.arm;
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.*;
import com.seaofnodes.simple.type.TypeInteger;
-import java.io.ByteArrayOutputStream;
public class MulIARM extends MachConcreteNode implements MachNode{
final TypeInteger _ti;
@@ -28,7 +28,7 @@ public class MulIARM extends MachConcreteNode implements MachNode{
@Override public int twoAddress() { return 1; }
// Encoding is appended into the byte array; size is returned
- @Override public int encoding(ByteArrayOutputStream bytes) {
+ @Override public void encoding( Encoding enc ) {
throw Utils.TODO();
}
diff --git a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/NewARM.java b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/NewARM.java
index bd88fa83..cdac48a3 100644
--- a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/NewARM.java
+++ b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/NewARM.java
@@ -1,31 +1,24 @@
package com.seaofnodes.simple.node.cpus.arm;
-
import com.seaofnodes.simple.*;
-import com.seaofnodes.simple.codegen.CodeGen;
-import com.seaofnodes.simple.codegen.RegMask;
+import com.seaofnodes.simple.codegen.*;
import com.seaofnodes.simple.node.*;
-import java.io.ByteArrayOutputStream;
-
public class NewARM extends NewNode implements MachNode {
// A pre-zeroed chunk of memory.
NewARM(NewNode nnn) { super(nnn); }
- // Size and pointer result in standard calling convention; null for all the
- // memory aliases edges
+ @Override public String op() { return "alloc"; }
@Override public RegMask regmap(int i) { return i == 1 ? arm. X0_MASK : null; }
@Override public RegMask outregmap(int i) { return i == 1 ? arm. X0_MASK : null; }
@Override public RegMask outregmap() { return null; }
+ @Override public RegMask killmap() { return arm.armCallerSave(); }
- // Encoding is appended into the byte array; size is returned
- @Override public int encoding(ByteArrayOutputStream bytes) {
- throw Utils.TODO();
+ @Override public void encoding( Encoding enc ) {
+ enc.relo(this);
+ enc.add4(arm.b(37, 0));
}
- // General form: "alloc #bytes"
@Override public void asm(CodeGen code, SB sb) {
sb.p(code.reg(size()));
}
-
- @Override public String op() { return "alloc"; }
}
diff --git a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/NotARM.java b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/NotARM.java
new file mode 100644
index 00000000..1092c931
--- /dev/null
+++ b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/NotARM.java
@@ -0,0 +1,28 @@
+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;
+
+public class NotARM extends MachConcreteNode implements MachNode{
+ NotARM(NotNode not) {super(not);}
+ @Override public String op() { return "not"; }
+ @Override public RegMask regmap(int i) { return arm.RMASK; }
+ @Override public RegMask outregmap() { return arm.RMASK; }
+ @Override public RegMask killmap() { return arm.FLAGS_MASK; }
+ @Override public void encoding( Encoding enc ) {
+ // subs xzr, rs, #0
+ // cset rd, eq // Set rd to 1 if rs == 0 (equal), else 0
+ // subtracting zero from rs will just yield rs, it sets the zero flag and then it's used in cset
+ short self = enc.reg(this );
+ short reg1 = enc.reg(in(1));
+ int subs = arm.imm_inst(964, 0, reg1, self);
+ enc.add4(subs);
+ int cset = arm.cond_set(1236, 31, arm.COND.EQ, 63, reg1);
+ enc.add4(cset);
+ }
+
+ @Override public void asm(CodeGen code, SB sb) { sb.p(code.reg(this)); }
+}
diff --git a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/OrARM.java b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/OrARM.java
index 12ea8265..61626855 100644
--- a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/OrARM.java
+++ b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/OrARM.java
@@ -1,42 +1,19 @@
package com.seaofnodes.simple.node.cpus.arm;
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.node.MachConcreteNode;
-import com.seaofnodes.simple.node.MachNode;
-import com.seaofnodes.simple.node.Node;
-
-import java.io.ByteArrayOutputStream;
+import com.seaofnodes.simple.codegen.*;
+import com.seaofnodes.simple.node.*;
// Not using the ORRS variant.
public class OrARM extends MachConcreteNode implements MachNode {
- OrARM(Node and) {
- super(and);
- }
-
- // Register mask allowed on input i.
- // This is the normal calling convention
- @Override public RegMask regmap(int i) {
- assert i==1 || i==2;
- return arm.RMASK;
- }
-
- // Register mask allowed as a result. 0 for no register.
+ OrARM(Node and) { super(and); }
+ @Override public String op() { return "orr"; }
+ @Override public RegMask regmap(int i) { return arm.RMASK; }
@Override public RegMask outregmap() { return arm.RMASK; }
-
- // Encoding is appended into the byte array; size is returned
- @Override public int encoding(ByteArrayOutputStream bytes) {
- throw Utils.TODO();
- }
-
- // General form
+ @Override public void encoding( Encoding enc ) { arm.r_reg(enc,this,170); }
// General form: #rd = rs1 & rs2
@Override public void asm(CodeGen code, SB sb) {
-
sb.p(code.reg(this)).p(" = ").p(code.reg(in(1))).p(" | ").p(code.reg(in(2)));
}
- @Override public String op() { return "orr"; }
}
diff --git a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/OrIARM.java b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/OrIARM.java
deleted file mode 100644
index f257a867..00000000
--- a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/OrIARM.java
+++ /dev/null
@@ -1,40 +0,0 @@
-package com.seaofnodes.simple.node.cpus.arm;
-
-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.node.MachConcreteNode;
-import com.seaofnodes.simple.node.MachNode;
-import com.seaofnodes.simple.node.Node;
-
-import com.seaofnodes.simple.type.Type;
-import com.seaofnodes.simple.type.TypeInteger;
-import java.io.ByteArrayOutputStream;
-
-public class OrIARM extends MachConcreteNode implements MachNode{
- final TypeInteger _ti;
- OrIARM(Node or, TypeInteger ti) {super(or); _inputs.pop(); _ti = ti;}
- // Register mask allowed on input i.
- // This is the normal calling convention
- @Override public RegMask regmap(int i) {
- assert i==1 || i==2;
- return arm.RMASK;
- }
- // Register mask allowed as a result. 0 for no register.
- @Override public RegMask outregmap() { return arm.RMASK; }
-
- // Encoding is appended into the byte array; size is returned
- @Override public int encoding(ByteArrayOutputStream bytes) {
- throw Utils.TODO();
- }
-
- // General form
- // General form: "rd = rs1 | imm"
- @Override public void asm(CodeGen code, SB sb) {
- sb.p(code.reg(this)).p(" = ").p(code.reg(in(1))).p(" | #");
- _ti.print(sb);
- }
-
- @Override public String op() { return "ori"; }
-}
diff --git a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/ParmARM.java b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/ParmARM.java
index c3fa132c..4d0f95ab 100644
--- a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/ParmARM.java
+++ b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/ParmARM.java
@@ -1,25 +1,17 @@
package com.seaofnodes.simple.node.cpus.arm;
-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.RegMask;
import com.seaofnodes.simple.node.MachNode;
import com.seaofnodes.simple.node.ParmNode;
-import java.io.ByteArrayOutputStream;
public class ParmARM extends ParmNode implements MachNode {
final RegMask _rmask;
ParmARM(ParmNode parm) {
super(parm);
- // Assume int
_rmask = arm.callInMask(fun().sig(),_idx);
}
- // Register mask allowed on input i. 0 for no register.
@Override public RegMask regmap(int i) { return null; }
- // Register mask allowed as a result. Calling convention register
@Override public RegMask outregmap() { return _rmask; }
-
- // Encoding is appended into the byte array. Returns size
- @Override public int encoding(ByteArrayOutputStream bytes) { return 0; }
+ @Override public void encoding( Encoding enc ) { }
}
diff --git a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/ProjARM.java b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/ProjARM.java
index b2add015..4b7d6f13 100644
--- a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/ProjARM.java
+++ b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/ProjARM.java
@@ -1,23 +1,15 @@
package com.seaofnodes.simple.node.cpus.arm;
-import com.seaofnodes.simple.Utils;
+import com.seaofnodes.simple.codegen.Encoding;
import com.seaofnodes.simple.codegen.RegMask;
import com.seaofnodes.simple.node.MachNode;
import com.seaofnodes.simple.node.ProjNode;
-import java.io.ByteArrayOutputStream;
public class ProjARM extends ProjNode implements MachNode {
ProjARM( ProjNode p ) { super(p); }
-
- // Register mask allowed on input i. 0 for no register.
@Override public RegMask regmap(int i) { return null; }
- // Register mask allowed as a result. 0 for no register.
@Override public RegMask outregmap() {
return ((MachNode)in(0)).outregmap(_idx);
}
-
- // Encoding is appended into the byte array; size is returned
- @Override public int encoding(ByteArrayOutputStream bytes) {
- throw Utils.TODO();
- }
+ @Override public void encoding( Encoding enc ) { }
}
diff --git a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/RetARM.java b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/RetARM.java
index c7d0dd4c..9066925e 100644
--- a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/RetARM.java
+++ b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/RetARM.java
@@ -1,29 +1,21 @@
package com.seaofnodes.simple.node.cpus.arm;
import com.seaofnodes.simple.*;
-import com.seaofnodes.simple.codegen.CodeGen;
-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.type.TypeFloat;
-
-import java.io.ByteArrayOutputStream;
-
+import com.seaofnodes.simple.codegen.*;
+import com.seaofnodes.simple.node.*;
public class RetARM extends ReturnNode implements MachNode {
RetARM(ReturnNode ret, FunNode fun) { super(ret, fun); fun.setRet(this); }
-
- // Register mask allowed on input i.
- // This is the normal calling convention
+ @Override public String op() { return "ret"; }
+ // Correct Nodes outside the normal edges
+ @Override public void postSelect() {
+ FunNode fun = (FunNode)rpc().in(0);
+ _fun = fun;
+ fun.setRet(this);
+ }
@Override public RegMask regmap(int i) { return arm.retMask(_fun.sig(),i); }
- // Register mask allowed as a result. 0 for no register.
@Override public RegMask outregmap() { return null; }
-
- // Encoding is appended into the byte array; size is returned
- @Override public int encoding(ByteArrayOutputStream bytes) {
- throw Utils.TODO();
- }
+ @Override public void encoding( Encoding enc ) { enc.add4(arm.ret(3512256)); }
@Override public void asm(CodeGen code, SB sb) {
// Post code-gen, just print the "ret"
@@ -34,16 +26,7 @@ public class RetARM extends ReturnNode implements MachNode {
sb.p(code.reg(in(i))).p(" ");
// Post-allocation, if we did not get the expected return register, print what we got
- else if( code._regAlloc.regnum(in(3)) != arm.X30 )
- sb.p("[").p(code.reg(in(3))).p("]");
- }
-
- // Correct Nodes outside the normal edges
- @Override public void postSelect() {
- FunNode fun = (FunNode)rpc().in(0);
- _fun = fun;
- fun.setRet(this);
+ else if( code._regAlloc.regnum(rpc()) != arm.X30 )
+ sb.p("[").p(code.reg(rpc())).p("]");
}
-
- @Override public String op() { return "ret"; }
}
diff --git a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/SetARM.java b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/SetARM.java
index c3945d1a..0f958e38 100644
--- a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/SetARM.java
+++ b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/SetARM.java
@@ -1,20 +1,13 @@
package com.seaofnodes.simple.node.cpus.arm;
import com.seaofnodes.simple.*;
-import com.seaofnodes.simple.codegen.CodeGen;
-import com.seaofnodes.simple.codegen.RegMask;
+import com.seaofnodes.simple.codegen.*;
import com.seaofnodes.simple.node.*;
-import com.seaofnodes.simple.type.Type;
-import com.seaofnodes.simple.type.TypeInteger;
-import java.io.ByteArrayOutputStream;
-
// conditional set?
// e.g CSET, stores flag info into GPRS after compare
-
public class SetARM extends MachConcreteNode implements MachNode {
final String _bop; // One of <,<=,==
-
SetARM(Node cmp, String bop) {
super(cmp);
_inputs.setLen(1); // Pop the cmp inputs
@@ -22,13 +15,14 @@ public class SetARM extends MachConcreteNode implements MachNode {
_inputs.push(cmp);
_bop = bop;
}
-
+ @Override public String op() { return "set"+_bop; }
@Override public RegMask regmap(int i) { assert i==1; return arm.FLAGS_MASK; }
@Override public RegMask outregmap() { return arm.RMASK; }
// Encoding is appended into the byte array; size is returned
- @Override public int encoding(ByteArrayOutputStream bytes) {
- throw Utils.TODO();
+ @Override public void encoding( Encoding enc ) {
+ //arm.cond_set(???);
+ Utils.TODO();
}
@Override public void asm(CodeGen code, SB sb) {
@@ -36,6 +30,4 @@ public class SetARM extends MachConcreteNode implements MachNode {
String src = code.reg(in(1));
if( src!="flags" ) sb.p(" = ").p(src);
}
-
- @Override public String op() { return "set"+_bop; }
}
diff --git a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/SplitARM.java b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/SplitARM.java
index 85771842..defb4f92 100644
--- a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/SplitARM.java
+++ b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/SplitARM.java
@@ -1,22 +1,19 @@
package com.seaofnodes.simple.node.cpus.arm;
-import com.seaofnodes.simple.Utils;
-import com.seaofnodes.simple.codegen.RegMask;
+import com.seaofnodes.simple.codegen.*;
import com.seaofnodes.simple.node.Node;
import com.seaofnodes.simple.node.SplitNode;
-import java.io.ByteArrayOutputStream;
public class SplitARM extends SplitNode {
SplitARM(String kind, byte round) { super(kind,round,new Node[2]);}
-
- // Register mask allowed on input i.
@Override public RegMask regmap(int i) { return arm.SPLIT_MASK; }
-
- // Register mask allowed as a result. 0 for no register.
@Override public RegMask outregmap() { return arm.SPLIT_MASK; }
// Encoding is appended into the byte array; size is returned
- @Override public int encoding(ByteArrayOutputStream bytes) {
- throw Utils.TODO();
+ @Override public void encoding( Encoding enc ) {
+ short self = enc.reg(this );
+ short reg1 = enc.reg(in(1));
+ int body = arm.r_reg(170, 0, reg1, 0, 31, self);
+ enc.add4(body);
}
}
diff --git a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/StoreARM.java b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/StoreARM.java
index 49045b28..ae7e88d9 100644
--- a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/StoreARM.java
+++ b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/StoreARM.java
@@ -1,49 +1,27 @@
package com.seaofnodes.simple.node.cpus.arm;
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.node.MachConcreteNode;
-import com.seaofnodes.simple.node.MachNode;
-import com.seaofnodes.simple.node.Node;
+import com.seaofnodes.simple.codegen.*;
import com.seaofnodes.simple.node.StoreNode;
-import java.io.ByteArrayOutputStream;
-import java.util.BitSet;
+import com.seaofnodes.simple.node.Node;
// Store memory addressing on ARM
// Support imm, reg(direct), or reg+off(indirect) addressing
-// Base = base - base pointer, offset is added to base
-// idx = null
-// off = off - offset added to base)
-// imm = imm - immediate value to store
-// val = Node of immediate value to store(null if its a constant immediate)
+// base - base pointer, offset is added to base
+// null - index never allowed (no [reg+reg] mode)
+// off - offset added to base
+// imm - immediate value to store, only if val is null
+// val - value to store or null
//e.g s.cs[0] = 67; // C
// base = s.cs, off = 4, imm = 67, val = null
public class StoreARM extends MemOpARM {
- StoreARM(StoreNode st, Node base, Node idx, int off, int imm, Node val) {
- super(st, base, idx, off, imm, val);
+ StoreARM(StoreNode st, Node base, Node idx, int off, Node val) {
+ super(st, base, idx, off, 0, val);
}
-
@Override public String op() { return "st"+_sz; }
-
- // Wider mask to store both GPRs and FPRs
- @Override public RegMask regmap(int i) {
- if( i==1 ) return arm.MEM_MASK;
- if( i==2 ) return arm.RMASK;
- if( i==3 ) return arm.RMASK;
- if( i==4 ) return arm.RMASK;
- throw Utils.TODO();
- }
- // Register mask allowed as a result. 0 for no register.
@Override public RegMask outregmap() { return null; }
-
- // Encoding is appended into the byte array; size is returned
- @Override public int encoding(ByteArrayOutputStream bytes) {
- throw Utils.TODO();
- }
-
+ @Override public void encoding( Encoding enc ) { arm.ldst_encode(enc,this,1984,val()); }
@Override public void asm(CodeGen code, SB sb) {
asm_address(code,sb).p(",");
if( val()==null ) sb.p("#").p(_imm);
diff --git a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/SubARM.java b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/SubARM.java
index 27555b53..df85199c 100644
--- a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/SubARM.java
+++ b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/SubARM.java
@@ -1,30 +1,18 @@
package com.seaofnodes.simple.node.cpus.arm;
-import com.seaofnodes.simple.*;
-import com.seaofnodes.simple.codegen.CodeGen;
-import com.seaofnodes.simple.codegen.RegMask;
+import com.seaofnodes.simple.SB;
+import com.seaofnodes.simple.codegen.*;
import com.seaofnodes.simple.node.*;
-import com.seaofnodes.simple.type.TypeInteger;
-import java.io.ByteArrayOutputStream;
-
public class SubARM extends MachConcreteNode implements MachNode {
- SubARM(Node sub) {super(sub);}
-
- // Register mask allowed on input i.
- @Override public RegMask regmap(int i) { assert i==1 || i==2; return arm.RMASK; }
- // Register mask allowed as a result. 0 for no register.
+ SubARM(Node sub) { super(sub); }
+ @Override public String op() { return "sub"; }
+ @Override public RegMask regmap(int i) { return arm.RMASK; }
@Override public RegMask outregmap() { return arm.RMASK; }
-
- // Encoding is appended into the byte array; size is returned
- @Override public int encoding(ByteArrayOutputStream bytes) {
- throw Utils.TODO();
- }
+ @Override public void encoding( Encoding enc ) { arm.r_reg(enc,this,203); }
// General form: "sub # rd = rs1 - rs2"
@Override public void asm(CodeGen code, SB sb) {
sb.p(code.reg(this)).p(" = ").p(code.reg(in(1))).p(" - ").p(code.reg(in(2)));
}
-
- @Override public String op() { return "sub"; }
}
diff --git a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/SubFARM.java b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/SubFARM.java
index 8ae05b40..b5aacc52 100644
--- a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/SubFARM.java
+++ b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/SubFARM.java
@@ -1,32 +1,18 @@
package com.seaofnodes.simple.node.cpus.arm;
-
-import com.seaofnodes.simple.*;
-import com.seaofnodes.simple.codegen.CodeGen;
-import com.seaofnodes.simple.codegen.RegMask;
+import com.seaofnodes.simple.SB;
+import com.seaofnodes.simple.codegen.*;
import com.seaofnodes.simple.node.*;
-import com.seaofnodes.simple.type.TypeInteger;
-import java.io.ByteArrayOutputStream;
-public class SubFARM extends MachConcreteNode implements MachNode{
+public class SubFARM extends MachConcreteNode implements MachNode {
SubFARM(Node subf) {super(subf);}
-
- // Register mask allowed on input i.
- @Override public RegMask regmap(int i) { assert i==1 || i==2; return arm.DMASK; }
- // Register mask allowed as a result. 0 for no register.
+ @Override public String op() { return "subf"; }
+ @Override public RegMask regmap(int i) { return arm.DMASK; }
@Override public RegMask outregmap() { return arm.DMASK; }
-
- // Encoding is appended into the byte array; size is returned
- @Override public int encoding(ByteArrayOutputStream bytes) {
- throw Utils.TODO();
- }
-
+ @Override public void encoding( Encoding enc ) { arm.f_scalar(enc,this,14); }
// Default on double precision for now(64 bits)
// General form: "vsub.f32 rd = src1 + src2
@Override public void asm(CodeGen code, SB sb) {
sb.p(code.reg(this)).p(" = ").p(code.reg(in(1))).p(" - ").p(code.reg(in(2)));
}
-
- @Override public String op() { return "subf"; }
-
}
diff --git a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/SubIARM.java b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/SubIARM.java
new file mode 100644
index 00000000..bda6681e
--- /dev/null
+++ b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/SubIARM.java
@@ -0,0 +1,27 @@
+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.type.TypeInteger;
+
+public class SubIARM extends MachConcreteNode implements MachNode {
+ final int _imm;
+ SubIARM(Node sub, int imm) {
+ super(sub);
+ _inputs.pop();
+ _imm = imm;
+ }
+ @Override public String op() { return _imm == -1 ? "dec" : "subi"; }
+ @Override public RegMask regmap(int i) { return arm.RMASK; }
+ @Override public RegMask outregmap() { return arm.RMASK; }
+ // Encoding is appended into the byte array; size is returned
+ @Override public void encoding( Encoding enc ) { arm.imm_inst(enc,this,836,_imm); }
+
+ // General form: "subi rd = rs1 - imm"
+ @Override public void asm(CodeGen code, SB sb) {
+ sb.p(code.reg(this)).p(" = ").p(code.reg(in(1))).p(" - #").p(_imm);
+ }
+}
diff --git a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/TFPARM.java b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/TFPARM.java
index cdb2b6ec..36125048 100644
--- a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/TFPARM.java
+++ b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/TFPARM.java
@@ -1,37 +1,29 @@
package com.seaofnodes.simple.node.cpus.arm;
import com.seaofnodes.simple.*;
-import com.seaofnodes.simple.codegen.CodeGen;
-import com.seaofnodes.simple.codegen.RegMask;
+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.TypeFunPtr;
-import java.io.ByteArrayOutputStream;
public class TFPARM extends ConstantNode implements MachNode {
TFPARM( ConstantNode con ) { super(con); }
@Override public String op() { return "ldx"; }
- // Register mask allowed on input i. 0 for no register.
@Override public RegMask regmap(int i) { return null; }
- // General int registers
@Override public RegMask outregmap() { return arm.WMASK; }
-
@Override public boolean isClone() { return true; }
@Override public TFPARM copy() { return new TFPARM(this); }
-
- // Encoding is appended into the byte array; size is returned
- @Override public int encoding(ByteArrayOutputStream bytes) {
+ @Override public void encoding( Encoding enc ) {
+ enc.relo(this,(TypeFunPtr)_con);
+ short self = enc.reg(this);
+ // Limit of 16bit address for function constants???
+ int body = arm.load_adr(1986,0,0,self);
+ enc.add4(body);
+ // Surely need to split into 2 ops?
throw Utils.TODO();
}
-
- // Human-readable form appended to the SB. Things like the encoding,
- // indentation, leading address or block labels not printed here.
- // Just something like "ld4\tR17=[R18+12] // Load array base".
- // General form: "op\tdst=src+src"
@Override public void asm(CodeGen code, SB sb) {
String reg = code.reg(this);
_con.print(sb.p(reg).p(" #"));
}
-
}
diff --git a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/XorARM.java b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/XorARM.java
index fd127b18..ebdfe094 100644
--- a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/XorARM.java
+++ b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/XorARM.java
@@ -1,41 +1,18 @@
package com.seaofnodes.simple.node.cpus.arm;
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.node.MachConcreteNode;
-import com.seaofnodes.simple.node.MachNode;
-import com.seaofnodes.simple.node.Node;
-import com.seaofnodes.simple.type.TypeInteger;
-import java.io.ByteArrayOutputStream;
+import com.seaofnodes.simple.codegen.*;
+import com.seaofnodes.simple.node.*;
public class XorARM extends MachConcreteNode implements MachNode{
- XorARM(Node xor) {super(xor); _inputs.pop();}
-
- // Register mask allowed on input i.
- // This is the normal calling convention
- @Override public RegMask regmap(int i) {
- assert i==1 || i==2;
-
- return arm.RMASK; }
-
- // Register mask allowed as a result. 0 for no register.
+ XorARM(Node xor) {super(xor);}
+ @Override public String op() { return "xor"; }
+ @Override public RegMask regmap(int i) { return arm.RMASK; }
@Override public RegMask outregmap() { return arm.RMASK; }
-
- // Output is same register as input#1
- @Override public int twoAddress() { return 1; }
-
- // Encoding is appended into the byte array; size is returned
- @Override public int encoding(ByteArrayOutputStream bytes) {
- throw Utils.TODO();
- }
-
- // General form
+ @Override public void encoding( Encoding enc ) { arm.r_reg(enc,this,202); }
// General form: "rd = x1 ^ x2"
@Override public void asm(CodeGen code, SB sb) {
sb.p(code.reg(this)).p(" = ").p(code.reg(in(1))).p(" ^ ").p(code.reg(in(2)));
}
- @Override public String op() { return "eor"; }
-} \ No newline at end of file
+}
diff --git a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/arm.java b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/arm.java
index fd207157..ca92b63e 100644
--- a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/arm.java
+++ b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/arm.java
@@ -1,15 +1,14 @@
package com.seaofnodes.simple.node.cpus.arm;
import com.seaofnodes.simple.Utils;
-import com.seaofnodes.simple.codegen.LRG;
-import com.seaofnodes.simple.codegen.Machine;
-import com.seaofnodes.simple.codegen.RegMask;
+import com.seaofnodes.simple.codegen.*;
import com.seaofnodes.simple.node.*;
import com.seaofnodes.simple.type.*;
+import java.io.ByteArrayOutputStream;
public class arm extends Machine {
- // X86-64 V2. Includes e.g. SSE4.2 and POPCNT.
+ // ARM64
@Override public String name() { return "arm"; }
// GPR(S)
@@ -24,18 +23,19 @@ public class arm extends Machine {
static final int D16 = 48, D17 = 49, D18 = 50, D19 = 51, D20 = 52, D21 = 53, D22 = 54, D23 = 55;
static final int D24 = 56, D25 = 57, D26 = 58, D27 = 59, D28 = 60, D29 = 61, D30 = 62, D31 = 63;
+ static final int D_OFFSET = 31;
static final int FLAGS = 64;
static final String[] REGS = new String[] {
- "X0", "X1", "X2", "X3", "X4", "X5", "X6", "X7",
- "X8", "X9", "X10", "X11", "X12", "X13", "X14", "X15",
- "X16", "X17", "X18", "X19", "X20", "X21", "X22", "X23",
- "X24", "X25", "X26", "X27", "X28", "X29", "RPC", "RSP",
- "D0", "D1", "D2", "D3", "D4", "D5", "D6", "D7",
- "D8", "D9", "D10", "D11", "D12", "D13", "D14", "D15",
- "D16", "D17", "D18", "D19", "D20", "D21", "D22", "D23",
- "D24", "D25", "D26", "D27", "D28", "D29", "D30", "D31",
- "flags"
+ "X0", "X1", "X2", "X3", "X4", "X5", "X6", "X7",
+ "X8", "X9", "X10", "X11", "X12", "X13", "X14", "X15",
+ "X16", "X17", "X18", "X19", "X20", "X21", "X22", "X23",
+ "X24", "X25", "X26", "X27", "X28", "X29", "RPC", "RSP",
+ "D0", "D1", "D2", "D3", "D4", "D5", "D6", "D7",
+ "D8", "D9", "D10", "D11", "D12", "D13", "D14", "D15",
+ "D16", "D17", "D18", "D19", "D20", "D21", "D22", "D23",
+ "D24", "D25", "D26", "D27", "D28", "D29", "D30", "D31",
+ "flags"
};
@Override public String reg( int reg ) {
return reg < REGS.length ? REGS[reg] : "[rsp+"+(reg-REGS.length)*4+"]";
@@ -85,33 +85,225 @@ public class arm extends Machine {
// for incoming argument idx.
// index 0 for control, 1 for memory, real args start at index 2
static final RegMask[] CALLINMASK = new RegMask[] {
- X0_MASK,
- X1_MASK,
- X2_MASK,
- X3_MASK,
- X4_MASK,
- X5_MASK,
- X6_MASK,
- X7_MASK,
+ X0_MASK,
+ X1_MASK,
+ X2_MASK,
+ X3_MASK,
+ X4_MASK,
+ X5_MASK,
+ X6_MASK,
+ X7_MASK,
};
static final RegMask[] XMMS = new RegMask[] {
- D0_MASK,
- D1_MASK,
- D2_MASK,
- D3_MASK,
- D4_MASK,
- D5_MASK,
- D6_MASK,
- D7_MASK,
+ D0_MASK,
+ D1_MASK,
+ D2_MASK,
+ D3_MASK,
+ D4_MASK,
+ D5_MASK,
+ D6_MASK,
+ D7_MASK,
};
- static RegMask callInMask( TypeFunPtr tfp, int idx ) {
+ // ARM ENCODING
+ public enum OPTION {
+ UXTB,
+ UXTH,
+ UXTX,
+ SXTB,
+ SXTH,
+ SXTW,
+ SXTX,
+ }
+
+ public enum STORE_LOAD_OPTION {
+ UXTW, // base+ u32 index [<< logsize]
+ UXTX, // base+ u64 index [<< logsize]
+ SXTW, // base+ s32 index [<< logsize]
+ SXTX, // base+ s64 index [<< logsize]
+ }
+
+ static public String invert(String op) {
+ return switch (op) {
+ case "==" -> "!=";
+ case "!=" -> "==";
+ case ">" -> "<=";
+ case "<" -> ">=";
+ case ">=" -> "<";
+ case "<=" -> ">";
+ default -> throw new IllegalStateException("Unexpected value: " + op);
+ };
+ }
+ public enum COND {
+ EQ,
+ NE,
+ CS,
+ CC,
+ MI,
+ PL,
+ VS,
+ VC,
+ HI,
+ LS,
+ GE,
+ LT,
+ GT,
+ LE,
+ AL,
+ NV
+ }
+
+ // True if signed 9-bit immediate
+ private static boolean imm9(TypeInteger ti) {
+ // 55 = 64-9
+ return ti.isConstant() && ((ti.value()<<55)>>55) == ti.value();
+ }
+ // True if signed 12-bit immediate
+ private static boolean imm12(TypeInteger ti) {
+ // 52 = 64-12
+ return ti.isConstant() && ((ti.value()<<52)>>52) == ti.value();
+ }
+
+ // sh is encoded in opcdoe
+ public static int imm_inst(int opcode, int imm12, int rn, int rd) {
+ return (opcode << 22) | (imm12 << 10) | (rn << 5) | rd;
+ }
+ public static void imm_inst(Encoding enc, Node n, int opcode, int imm12) {
+ short self = enc.reg(n);
+ short reg1 = enc.reg(n.in(1));
+ int body = imm_inst(opcode, imm12, reg1, self);
+ enc.add4(body);
+ }
+
+ // for normal add, reg1, reg2 cases (reg-to-reg)
+ // using shifted-reg form
+ public static int r_reg(int opcode, int shift, int rm, int imm6, int rn, int rd) {
+ return (opcode << 24) | (shift << 21) | (rm << 16) | (imm6 << 10) << (rn << 5) | rd;
+ }
+ public static void r_reg(Encoding enc, Node n, int opcode) {
+ short self = enc.reg(n);
+ short reg1 = enc.reg(n.in(1));
+ short reg2 = enc.reg(n.in(2));
+ int body = r_reg(opcode, 0, reg2, 0, reg1, self);
+ enc.add4(body);
+ }
+
+ public static int shift_reg(int opcode, int rm, int op2, int rn, int rd) {
+ return (opcode << 21) | (rm << 16) | (op2 << 10) | (rn << 5) | rd;
+ }
+ public static void shift_reg(Encoding enc, Node n, int op2) {
+ short self = enc.reg(n);
+ short reg1 = enc.reg(n.in(1));
+ short reg2 = enc.reg(n.in(2));
+ int body = shift_reg(1238, reg2, op2, reg1, self);
+ enc.add4(body);
+ }
+
+ // MUL can be considered an alias for MADD with the third operand Ra being set to 0
+ public static int madd(int opcode, int rm, int ra, int rn, int rd) {
+ return (opcode << 21) | (rm << 16) | (ra << 10) | (rn << 5) | rd;
+ }
+ public static void madd(Encoding enc, Node n, int opcode, int ra) {
+ short self = enc.reg(n);
+ short reg1 = enc.reg(n.in(1));
+ short reg2 = enc.reg(n.in(2));
+ int body = madd(opcode, reg2, ra, reg1, self);
+ enc.add4(body);
+ }
+
+ // encodes movk
+ public static int mov(int opcode, int shift, int imm16, int rd) {
+ return (opcode << 23) | (shift << 21) | (imm16 << 5) | rd;
+ }
+
+ public static int ret(int opcode) {
+ return (opcode << 10);
+ }
+
+ // FMOV (scalar, immediate)
+ public static int f_mov(int opcode, int ftype, int imm8, int rd) {
+ return (opcode << 24) | (ftype << 21) |(imm8 << 13) | (128 << 5) | rd;
+ }
+
+ public static int f_scalar(int opcode, int ftype, int rm, int op, int rn, int rd) {
+ return (opcode << 24) | (ftype << 22) | (1 << 21) | (rm << 16) | (op << 10) | (rn << 5) | rd;
+ }
+ public static void f_scalar(Encoding enc, Node n, int op ) {
+ short self = (short)(enc.reg(n) -D_OFFSET);
+ short reg1 = (short)(enc.reg(n.in(1))-D_OFFSET);
+ short reg2 = (short)(enc.reg(n.in(2))-D_OFFSET);
+ int body = f_scalar(30, 1, reg2, op, reg1, self);
+ enc.add4(body);
+ }
+
+ public static int load_adr(int opcode, int offset, int base, int rt) {
+ return (opcode << 21) | (offset << 12) | (3 << 10) | (base << 5) | rt;
+ }
+
+ // [Rptr+Roff]
+ public static int indr_adr(int opcode, int off, STORE_LOAD_OPTION option, int s, int ptr, int rt) {
+ return (opcode << 21) | (off << 16) | (option.ordinal() << 13) | (s << 12) | (2 << 10) | (ptr << 5) | rt;
+ }
+ // [Rptr+imm9]
+ public static int load_str_imm(int opcode, int imm9, int ptr, int rt) {
+ return (opcode << 21) | (imm9 << 12) |(1 << 10) |(ptr << 5) | rt;
+ }
+ public static void ldst_encode( Encoding enc, MemOpARM n, int op, Node xval ) {
+ short ptr = enc.reg(n.ptr());
+ short off = enc.reg(n.off());
+ short val = enc.reg(xval) ;
+ int body = n.off() == null
+ ? load_str_imm(op, off, ptr, val)
+ : indr_adr(op+1, off, arm.STORE_LOAD_OPTION.SXTX, 0, ptr, val);
+ enc.add4(body);
+ }
+
+ // encoding for vcvt, size is encoded in operand
+ // <Qd>, <Qm>
+ // F32.S32
+ //encoded as op = 0b00, size = 0b10.
+ // VCVT<c>.<Td>.<Tm> <Dd>, <Dm>
+ // opcode is broken down into 4 pieces
+ public static int f_convert(int opcode_1, int opcode_2, int opcode_3, int opcode_4, int vd, int vm) {
+ return (opcode_1 << 28) | (opcode_2 << 24) | (opcode_3 << 20) | (opcode_4 << 16) |
+ (vd << 12) | (0x01100010 << 4) | vm;
+ }
+ public static int float_cast(int opcode, int ftype, int rn, int rd) {
+ return (opcode << 24) | (ftype << 22) | (2176 << 10) | (rn << 5) | rd;
+ }
+
+
+ // ftype = 3
+ public static int f_cmp(int opcode, int ftype, int rm, int rn) {
+ return (opcode << 24) | (ftype << 21) | (rm << 16) | (8 << 10) | (rn << 5) | 8;
+ }
+ public static void f_cmp(Encoding enc, Node n) {
+ short reg1 = (short)(enc.reg(n.in(1))-arm.D_OFFSET);
+ short reg2 = (short)(enc.reg(n.in(2))-arm.D_OFFSET);
+ int body = f_cmp(30, 3, reg1, reg2);
+ enc.add4(body);
+ }
+
+ // Todo: maybe missing zero here after label << 5
+ public static int b_cond(int opcode, int label, COND cond) {
+ return (opcode << 24) | (label << 5) | cond.ordinal();
+ }
+
+ public static int cond_set(int opcode, int rm, COND cond, int rn, int rd) {
+ return (opcode << 21) | (rm << 16) | (cond.ordinal() << 12) | (rn << 5) | rd;
+ }
+
+ public static int b(int opcode, int imm26) {
+ return (opcode << 26) | imm26;
+ }
+
+ static RegMask callInMask(TypeFunPtr tfp, int idx ) {
if( idx==0 ) return RPC_MASK;
if( idx==1 ) return null;
// Count floats in signature up to index
int fcnt=0;
for( int i=2; i<idx; i++ )
- if( tfp.arg(i-2) instanceof TypeFloat )
+ if( tfp.arg(i-2) instanceof TypeFloat)
fcnt++;
// Floats up to XMMS in XMM registers
if( tfp.arg(idx-2) instanceof TypeFloat ) {
@@ -126,12 +318,12 @@ public class arm extends Machine {
}
static final long CALLEE_SAVE =
- 1L<<X19 |
- 1L<<X20 | 1L<<X21 | 1L<<X22 | 1L<<X23 |
- 1L<<X24 | 1L<<X25 | 1L<<X26 | 1L<<X27 |
- 1L<<X28 |
- 1L<<D9 | 1L<<D10 | 1L<<D11 |
- 1L<<D12 | 1L<<D13 | 1L<<D14 | 1L<<D15;
+ 1L<<X19 |
+ 1L<<X20 | 1L<<X21 | 1L<<X22 | 1L<<X23 |
+ 1L<<X24 | 1L<<X25 | 1L<<X26 | 1L<<X27 |
+ 1L<<X28 |
+ 1L<<D9 | 1L<<D10 | 1L<<D11 |
+ 1L<<D12 | 1L<<D13 | 1L<<D14 | 1L<<D15;
static final RegMask CALLER_SAVE_MASK;
static {
@@ -164,8 +356,8 @@ public class arm extends Machine {
}
static RegMask retMask( TypeFunPtr tfp, int i ) {
return i==2
- ? (tfp.ret() instanceof TypeFloat ? D0_MASK : X0_MASK)
- : RET_MASKS[i];
+ ? (tfp.ret() instanceof TypeFloat ? D0_MASK : X0_MASK)
+ : RET_MASKS[i];
}
// Create a split op; any register to any register, including stack slots
@@ -177,69 +369,67 @@ public class arm extends Machine {
}
// Break an infinite loop
- @Override public IfNode never( CFGNode ctrl ) {
+ @Override public IfNode never(CFGNode ctrl ) {
throw Utils.TODO();
}
// Instruction selection
- @Override public Node instSelect( Node n ) {
+ @Override public Node instSelect(Node n ) {
return switch( n ) {
- case AddFNode addf -> addf(addf);
- case AddNode add -> add(add);
- case AndNode and -> and(and);
- case BoolNode bool -> cmp(bool);
- case CallNode call -> call(call);
- case CastNode cast -> new CastNode(cast);
- case CallEndNode cend -> new CallEndARM(cend);
- case CProjNode c -> new CProjNode(c);
- case ConstantNode con -> con(con);
- case DivFNode divf -> new DivFARM(divf);
- case DivNode div -> new DivARM(div);
- case FunNode fun -> new FunARM(fun);
- case IfNode iff -> jmp(iff);
- case LoadNode ld -> ld(ld);
- case MemMergeNode mem -> new MemMergeNode(mem);
- case MulFNode mulf -> new MulFARM(mulf);
- case MulNode mul -> mul(mul);
- case NewNode nnn -> new NewARM(nnn);
- case OrNode or -> or(or);
- case ParmNode parm -> new ParmARM(parm);
- case PhiNode phi -> new PhiNode(phi);
- case ProjNode prj -> prj(prj);
+ case AddFNode addf -> new AddFARM(addf);
+ case AddNode add -> add(add);
+ case AndNode and -> new AndARM(and);
+ case BoolNode bool -> cmp(bool);
+ case CallNode call -> call(call);
+ case CastNode cast -> new CastNode(cast);
+ case CallEndNode cend -> new CallEndARM(cend);
+ case CProjNode c -> new CProjNode(c);
+ case ConstantNode con -> con(con);
+ case DivFNode divf -> new DivFARM(divf);
+ case DivNode div -> new DivARM(div);
+ case FunNode fun -> new FunARM(fun);
+ case IfNode iff -> jmp(iff);
+ case LoadNode ld -> ld(ld);
+ case MemMergeNode mem -> new MemMergeNode(mem);
+ case MulFNode mulf -> new MulFARM(mulf);
+ case MulNode mul -> new MulARM(mul);
+ case NewNode nnn -> new NewARM(nnn);
+ case NotNode not -> new NotARM(not);
+ case OrNode or -> new OrARM(or);
+ case ParmNode parm -> new ParmARM(parm);
+ case PhiNode phi -> new PhiNode(phi);
+ case ProjNode prj -> new ProjARM(prj);
case ReadOnlyNode read -> new ReadOnlyNode(read);
- case ReturnNode ret -> new RetARM(ret,ret.fun());
- case SarNode sar -> sar(sar);
- case ShlNode shl -> shl(shl);
- case ShrNode shr -> shr(shr);
- case StartNode start -> new StartNode(start);
- case StopNode stop -> new StopNode(stop);
- case StoreNode st -> st(st);
- case SubFNode subf -> new SubFARM(subf);
- case SubNode sub -> sub(sub);
- case ToFloatNode tfn -> i2f8(tfn);
- case XorNode xor -> xor(xor);
-
- case LoopNode loop -> new LoopNode(loop);
- case RegionNode region-> new RegionNode(region);
+ case ReturnNode ret -> new RetARM(ret,ret.fun());
+ case SarNode sar -> new AsrARM(sar);
+ case ShlNode shl -> new LslARM(shl);
+ case ShrNode shr -> new LsrARM(shr);
+ case StartNode start -> new StartNode(start);
+ case StopNode stop -> new StopNode(stop);
+ case StoreNode st -> st(st);
+ case SubFNode subf -> new SubFARM(subf);
+ case SubNode sub -> sub(sub);
+ case ToFloatNode tfn-> new I2F8ARM(tfn);
+ case XorNode xor -> new XorARM(xor);
+
+ case LoopNode loop -> new LoopNode(loop);
+ case RegionNode region-> new RegionNode(region);
default -> throw Utils.TODO();
};
}
- private Node mul(MulNode mul) {
- Node rhs = mul.in(2);
- if( rhs instanceof ConstantNode off && off._con instanceof TypeInteger toff ) {
- return new MulIARM(mul, toff);
- }
- return new MulARM(mul);
- }
private Node cmp(BoolNode bool){
Node cmp = _cmp(bool);
return new SetARM(cmp, bool.op());
}
-
- private Node i2f8(ToFloatNode tfn) {
- assert tfn.in(1)._type instanceof TypeInteger ti;
- return new I2F8ARM(tfn);
+ private Node _cmp(BoolNode bool) {
+ if( bool instanceof BoolNode.EQF ||
+ bool instanceof BoolNode.LTF ||
+ bool instanceof BoolNode.LEF )
+ return new CmpFARM(bool);
+ return bool.in(2) instanceof ConstantNode con && con._con instanceof TypeInteger ti
+ ? new CmpIARM(bool, (int)ti.value())
+ : new CmpARM(bool);
}
private Node ld(LoadNode ld) {
@@ -252,127 +442,58 @@ public class arm extends Machine {
// Loads do not set the flags, and will need an explicit TEST
if( !(iff.in(1) instanceof BoolNode) )
iff.setDef(1,new BoolNode.EQ(iff.in(1),new ConstantNode(TypeInteger.ZERO)));
- return new BranchARM(iff, ((BoolNode)iff.in(1)).op());
- }
-
- private Node _cmp(BoolNode bool) {
- if( bool instanceof BoolNode.EQF ||
- bool instanceof BoolNode.LTF ||
- bool instanceof BoolNode.LEF )
- return new CmpFARM(bool);
-
-
- return bool.in(2) instanceof ConstantNode con && con._con instanceof TypeInteger ti
- ? new CmpIARM(bool, ti)
- : new CmpARM(bool);
- }
-
-
- private Node addf(AddFNode addf) {
- return new AddFARM(addf);
+ return new BranchARM(iff, invert(((BoolNode)iff.in(1)).op()));
}
private Node add(AddNode add) {
- Node rhs = add.in(2);
- if( rhs instanceof ConstantNode off && off._con instanceof TypeInteger toff ) {
- return new AddIARM(add, toff);
- }
- return new AddARM(add);
+ return add.in(2) instanceof ConstantNode off && off._con instanceof TypeInteger ti && imm12(ti)
+ ? new AddIARM(add, (int)ti.value())
+ : new AddARM(add);
}
private Node sub(SubNode sub) {
- return sub.in(2) instanceof ConstantNode con && con._con instanceof TypeInteger ti
- ? new AddIARM(sub, TypeInteger.constant(-ti.value()))
- : new SubARM(sub);
- }
-
- private Node and(AndNode and) {
- if( and.in(2) instanceof ConstantNode con && con._con instanceof TypeInteger ti )
- return new AndIARM(and, ti);
- return new AndARM(and);
- }
-
- private Node or(OrNode or) {
- if(or.in(2) instanceof ConstantNode con && con._con instanceof TypeInteger ti)
- return new OrIARM(or, ti);
-
- return new OrARM(or);
- }
-
- private Node xor(XorNode xor) {
- if(xor.in(2) instanceof ConstantNode con && con._con instanceof TypeInteger ti)
- return new XorIARM(xor, ti);
- return new XorARM(xor);
+ return sub.in(2) instanceof ConstantNode con && con._con instanceof TypeInteger ti && imm12(ti)
+ ? new SubIARM(sub, (int)ti.value())
+ : new SubARM(sub);
}
private Node con(ConstantNode con) {
if( !con._con.isConstant() ) return new ConstantNode( con ); // Default unknown caller inputs
return switch( con._con ) {
- case TypeInteger ti -> new IntARM(con);
- case TypeFloat tf -> new FloatARM(con);
- case TypeFunPtr tfp -> new TFPARM(con);
- case TypeMemPtr tmp -> new ConstantNode(con);
- case TypeNil tn -> throw Utils.TODO();
- // TOP, BOTTOM, XCtrl, Ctrl, etc. Never any executable code.
- case Type t -> new ConstantNode(con);
+ case TypeInteger ti -> new IntARM(con);
+ case TypeFloat tf -> new FloatARM(con);
+ case TypeFunPtr tfp -> new TFPARM(con);
+ case TypeMemPtr tmp -> new ConstantNode(con);
+ case TypeNil tn -> throw Utils.TODO();
+ // TOP, BOTTOM, XCtrl, Ctrl, etc. Never any executable code.
+ case Type t -> new ConstantNode(con);
};
}
- private Node sar(SarNode sar){
- if( sar.in(2) instanceof ConstantNode con && con._con instanceof TypeInteger ti)
- return new AsrIARM(sar, ti);
- return new AsrARM(sar);
- }
-
- private Node shl(ShlNode shl) {
- if( shl.in(2) instanceof ConstantNode con && con._con instanceof TypeInteger ti)
- return new LslIARM(shl, ti);
- return new LslARM(shl);
-
- }
-
- private Node shr(ShrNode shr) {
- if( shr.in(2) instanceof ConstantNode con && con._con instanceof TypeInteger ti)
- return new LsrIARM(shr, ti);
- return new LsrARM(shr);
- }
-
private Node call(CallNode call){
if(call.fptr() instanceof ConstantNode con && con._con instanceof TypeFunPtr tfp)
return new CallARM(call, tfp);
return new CallRRARM(call);
}
- private Node prj(ProjNode prj) {
- return new ProjARM(prj);
- }
-
-
private static int off;
private static Node idx;
private Node st(StoreNode st) {
- int imm=0;
- Node xval = st.val();
- // e.g store this s.cs[0] = 67; // C
- if( xval instanceof ConstantNode con && con._con instanceof TypeInteger ti ) {
- xval = null;
- imm = (int)ti.value();
- assert imm == ti.value(); // In 32-bit range
- }
- return new StoreARM(address(st),st.ptr(),idx,off,imm,xval);
+ Node xval = st.val() instanceof ConstantNode con && con._con == TypeInteger.ZERO ? null : st.val();
+ return new StoreARM(address(st),st.ptr(),idx,off,xval);
}
// Gather addressing mode bits prior to constructing. This is a builder
// pattern, but saving the bits in a *local* *global* here to keep mess
// contained.
- private <N extends MemOpNode> N address( N mop ) {
+ private <N extends MemOpNode> N address(N mop ) {
off = 0; // Reset
idx = null;
Node base = mop.ptr();
// Skip/throw-away a ReadOnly, only used to typecheck
if( base instanceof ReadOnlyNode read ) base = read.in(1);
assert !(base instanceof AddNode) && base._type instanceof TypeMemPtr; // Base ptr always, not some derived
- if( mop.off() instanceof ConstantNode con && con._con instanceof TypeInteger ti ) {
+ if( mop.off() instanceof ConstantNode con && con._con instanceof TypeInteger ti && imm9(ti) ) {
off = (int)ti.value();
assert off == ti.value(); // In 32-bit range
} else {
diff --git a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/i2f8.java b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/i2f8.java
deleted file mode 100644
index e0792669..00000000
--- a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/i2f8.java
+++ /dev/null
@@ -1,4 +0,0 @@
-package com.seaofnodes.simple.node.cpus.arm;
-
-public class i2f8 {
-}
diff --git a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/AUIPC.java b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/AUIPC.java
new file mode 100644
index 00000000..5bcb6165
--- /dev/null
+++ b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/AUIPC.java
@@ -0,0 +1,28 @@
+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.TypeFunPtr;
+
+// Add upper 20bits to PC. Immediate comes from the relocation info.
+public class AUIPC extends ConstantNode implements MachNode {
+ AUIPC( TypeFunPtr tfp ) { super(tfp); }
+ @Override public RegMask regmap(int i) { return null; }
+ @Override public RegMask outregmap() { return riscv.WMASK; }
+ @Override public boolean isClone() { return true; }
+ @Override public AUIPC copy() { return new AUIPC((TypeFunPtr)_con); }
+ @Override public String op() { return "auipc"; }
+ @Override public void encoding( Encoding enc ) {
+ enc.relo(this,(TypeFunPtr)_con);
+ short dst = enc.reg(this);
+ int auipc = riscv.u_type(0x17, dst, 0);
+ enc.add4(auipc);
+ }
+
+ @Override public void asm(CodeGen code, SB sb) {
+ String reg = code.reg(this);
+ _con.print(sb.p(reg).p(" = PC+#"));
+ }
+}
diff --git a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/AddFRISC.java b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/AddFRISC.java
index 2417aeb6..a1c23861 100644
--- a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/AddFRISC.java
+++ b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/AddFRISC.java
@@ -1,30 +1,17 @@
package com.seaofnodes.simple.node.cpus.riscv;
-import com.seaofnodes.simple.*;
-import com.seaofnodes.simple.codegen.CodeGen;
-import com.seaofnodes.simple.codegen.RegMask;
+import com.seaofnodes.simple.SB;
+import com.seaofnodes.simple.codegen.*;
import com.seaofnodes.simple.node.*;
-import com.seaofnodes.simple.type.TypeInteger;
-import java.io.ByteArrayOutputStream;
-public class AddFRISC extends MachConcreteNode implements MachNode{
+// fadd.s
+public class AddFRISC extends MachConcreteNode implements MachNode {
AddFRISC(Node addf) {super(addf);}
-
- // Register mask allowed on input i.
+ @Override public String op() { return "addf"; }
@Override public RegMask regmap(int i) { assert i==1 || i==2; return riscv.FMASK; }
- // Register mask allowed as a result. 0 for no register.
@Override public RegMask outregmap() { return riscv.FMASK; }
-
- // Encoding is appended into the byte array; size is returned
- @Override public int encoding(ByteArrayOutputStream bytes) {
- throw Utils.TODO();
- }
-
- // Default on double precision for now(64 bits)
- // General form: "fadd.d rd = src1 + src2
+ @Override public void encoding( Encoding enc ) { riscv.rf_type(enc,this,0x53,riscv.RM.RNE,0); }
@Override public void asm(CodeGen code, SB sb) {
sb.p(code.reg(this)).p(" = ").p(code.reg(in(1))).p(" + ").p(code.reg(in(2)));
}
-
- @Override public String op() { return "addf"; }
}
diff --git a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/AddIRISC.java b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/AddIRISC.java
index e92a7b08..fce8c499 100644
--- a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/AddIRISC.java
+++ b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/AddIRISC.java
@@ -5,7 +5,8 @@ import com.seaofnodes.simple.node.Node;
public class AddIRISC extends ImmRISC {
AddIRISC( Node add, int imm ) { super(add,imm); }
- @Override int opcode() { throw Utils.TODO(); }
+ @Override int opcode() { return riscv.I_TYPE; }
+ @Override int func3() {return 0;}
@Override public String glabel() { return "+"; }
@Override public String op() { return "addi"; }
}
diff --git a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/AddRISC.java b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/AddRISC.java
index 344c217d..b01b259a 100644
--- a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/AddRISC.java
+++ b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/AddRISC.java
@@ -1,29 +1,21 @@
package com.seaofnodes.simple.node.cpus.riscv;
-import com.seaofnodes.simple.*;
-import com.seaofnodes.simple.codegen.CodeGen;
-import com.seaofnodes.simple.codegen.RegMask;
+import com.seaofnodes.simple.SB;
+import com.seaofnodes.simple.codegen.*;
import com.seaofnodes.simple.node.*;
-import com.seaofnodes.simple.type.TypeInteger;
-import java.io.ByteArrayOutputStream;
public class AddRISC extends MachConcreteNode implements MachNode {
- AddRISC( Node add) {super(add); }
+ AddRISC( Node add ) { super(add); }
+ AddRISC( Node base, Node off ) {
+ super(new Node[3]);
+ _inputs.set(1,base);
+ _inputs.set(2,off );
+ }
@Override public String op() { return "add"; }
-
- // Register mask allowed on input i.
@Override public RegMask regmap(int i) { return riscv.RMASK; }
- // Register mask allowed as a result. 0 for no register.
@Override public RegMask outregmap() { return riscv.WMASK; }
-
- // Encoding is appended into the byte array; size is returned
- @Override public int encoding(ByteArrayOutputStream bytes) {
- throw Utils.TODO();
- }
-
- // General form: "rd = rs1 + rs2"
+ @Override public void encoding( Encoding enc ) { riscv.r_type(enc,this,0,0); }
@Override public void asm(CodeGen code, SB sb) {
sb.p(code.reg(this)).p(" = ").p(code.reg(in(1))).p(" + ").p(code.reg(in(2)));
}
-
}
diff --git a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/AndIRISC.java b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/AndIRISC.java
index ddbf5aa4..57de8a83 100644
--- a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/AndIRISC.java
+++ b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/AndIRISC.java
@@ -5,7 +5,8 @@ import com.seaofnodes.simple.node.Node;
public class AndIRISC extends ImmRISC {
AndIRISC( Node and, int imm) { super(and,imm); }
- @Override int opcode() { throw Utils.TODO(); }
+ @Override int opcode() { return riscv.I_TYPE; }
+ @Override int func3() {return 7;}
@Override public String glabel() { return "&"; }
@Override public String op() { return "andi"; }
}
diff --git a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/AndRISC.java b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/AndRISC.java
index 4defc1b0..855821c8 100644
--- a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/AndRISC.java
+++ b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/AndRISC.java
@@ -1,37 +1,16 @@
package com.seaofnodes.simple.node.cpus.riscv;
-import com.seaofnodes.simple.*;
-import com.seaofnodes.simple.codegen.CodeGen;
-import com.seaofnodes.simple.codegen.RegMask;
+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.TypeInteger;
-import java.io.ByteArrayOutputStream;
-import java.util.BitSet;
-import java.lang.StringBuilder;
public class AndRISC extends MachConcreteNode implements MachNode {
AndRISC(Node and) { super(and); }
-
- // Register mask allowed on input i.
- // This is the normal calling convention
- @Override public RegMask regmap(int i) {
- assert i==1 || i==2;
- return riscv.RMASK;
- }
-
- // Register mask allowed as a result. 0 for no register.
+ @Override public String op() { return "and"; }
+ @Override public RegMask regmap(int i) { return riscv.RMASK; }
@Override public RegMask outregmap() { return riscv.WMASK; }
-
- // Encoding is appended into the byte array; size is returned
- @Override public int encoding(ByteArrayOutputStream bytes) {
- throw Utils.TODO();
- }
-
- // General form
- // General form: #rd = rs1 & rs2
+ @Override public void encoding( Encoding enc ) { riscv.r_type(enc,this,7,0); }
@Override public void asm(CodeGen code, SB sb) {
sb.p(code.reg(this)).p(" = ").p(code.reg(in(1))).p(" & ").p(code.reg(in(2)));
}
- @Override public String op() { return "and"; }
}
diff --git a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/BranchRISC.java b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/BranchRISC.java
index f6168d8e..fec15b55 100644
--- a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/BranchRISC.java
+++ b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/BranchRISC.java
@@ -1,15 +1,14 @@
package com.seaofnodes.simple.node.cpus.riscv;
import com.seaofnodes.simple.*;
-import com.seaofnodes.simple.codegen.CodeGen;
-import com.seaofnodes.simple.codegen.RegMask;
+import com.seaofnodes.simple.codegen.*;
import com.seaofnodes.simple.node.*;
-import java.io.ByteArrayOutputStream;
+
import java.util.BitSet;
// Conditional branch such as: BEQ
public class BranchRISC extends IfNode implements MachNode {
- String _bop;
+ final String _bop;
// label is obtained implicitly
BranchRISC( IfNode iff, String bop, Node n1, Node n2 ) {
super(iff);
@@ -18,8 +17,9 @@ public class BranchRISC extends IfNode implements MachNode {
_inputs.setX(2,n2);
}
+ @Override public String op() { return "b"+_bop; }
@Override public String label() { return op(); }
-
+ @Override public String comment() { return "L"+cproj(1)._nid+", L"+cproj(0)._nid; }
@Override public RegMask regmap(int i) { return riscv.RMASK; }
@Override public RegMask outregmap() { return null; }
@@ -31,19 +31,14 @@ public class BranchRISC extends IfNode implements MachNode {
}
// Encoding is appended into the byte array; size is returned
- @Override public int encoding(ByteArrayOutputStream bytes) {
- throw Utils.TODO();
+ @Override public void encoding( Encoding enc ) {
+ // Todo: relocs (for offset - immf)
+ short src1 = enc.reg(in(1));
+ short src2 = in(2)==null ? (short)riscv.ZERO : enc.reg(in(2));
+ int body = riscv.b_type(0x63, 0, riscv.jumpop(_bop), src1, src2, 0);
+ enc.add4(body);
}
-
@Override public void asm(CodeGen code, SB sb) {
sb.p(code.reg(in(1))).p(" ").p(_bop).p(" ").p(in(2)==null ? "#0" : code.reg(in(2)));
}
-
- @Override public String op() { return "b"+_bop; }
-
- @Override public String comment() {
- return "L"+cproj(1)._nid+", L"+cproj(0)._nid;
- }
-
- @Override public void invert() { _bop = invert(_bop); }
}
diff --git a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/CallEndRISC.java b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/CallEndRISC.java
index fd1ba7c3..3dca37b8 100644
--- a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/CallEndRISC.java
+++ b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/CallEndRISC.java
@@ -1,14 +1,10 @@
package com.seaofnodes.simple.node.cpus.riscv;
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.*;
import com.seaofnodes.simple.node.CallEndNode;
import com.seaofnodes.simple.node.MachNode;
-import com.seaofnodes.simple.type.TypeFloat;
import com.seaofnodes.simple.type.TypeFunPtr;
-import java.io.ByteArrayOutputStream;
public class CallEndRISC extends CallEndNode implements MachNode {
final TypeFunPtr _tfp;
@@ -16,20 +12,12 @@ public class CallEndRISC extends CallEndNode implements MachNode {
super(cend);
_tfp = (TypeFunPtr)(cend.call().fptr()._type);
}
-
+ @Override public String op() { return "cend"; }
@Override public String label() { return op(); }
@Override public RegMask regmap(int i) { return null; }
@Override public RegMask outregmap() { return null; }
@Override public RegMask outregmap(int idx) { return idx == 2 ? riscv.retMask(_tfp,2) : null; }
@Override public RegMask killmap() { return riscv.riscCallerSave(); }
-
- // Encoding is appended into the byte array; size is returned
- @Override public int encoding(ByteArrayOutputStream bytes) {
- throw Utils.TODO();
- }
-
+ @Override public void encoding( Encoding enc ) { }
@Override public void asm(CodeGen code, SB sb) { }
-
- @Override public String op() { return "cend"; }
-
}
diff --git a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/CallRISC.java b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/CallRISC.java
index 54f4fba9..e93852da 100644
--- a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/CallRISC.java
+++ b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/CallRISC.java
@@ -1,36 +1,40 @@
package com.seaofnodes.simple.node.cpus.riscv;
import com.seaofnodes.simple.*;
-import com.seaofnodes.simple.codegen.CodeGen;
-import com.seaofnodes.simple.codegen.RegMask;
+import com.seaofnodes.simple.codegen.*;
import com.seaofnodes.simple.node.*;
import com.seaofnodes.simple.type.TypeFunPtr;
-import java.io.ByteArrayOutputStream;
-public class CallRISC extends CallNode implements MachNode{
+public class CallRISC extends CallNode implements MachNode {
final TypeFunPtr _tfp;
final String _name;
-
- CallRISC( CallNode call, TypeFunPtr tfp ) {
+ CallRISC( CallNode call, TypeFunPtr tfp, AUIPC auipc ) {
super(call);
- _inputs.pop(); // Pop constant target
assert tfp.isConstant();
+ _inputs.pop(); // Pop constant target
+ _inputs.add(auipc); // Add high-half address
_tfp = tfp;
_name = CodeGen.CODE.link(tfp)._name;
}
+ @Override public String op() { return "call"; }
@Override public String label() { return op(); }
@Override public RegMask regmap(int i) {
- return riscv.callInMask(_tfp,i); // Normal argument
+ // Last call input is AUIPC
+ if( i == nIns()-1 ) return riscv.RMASK;
+ return riscv.callInMask(_tfp,i);
}
- @Override public RegMask outregmap() { return null; }
-
+ @Override public RegMask outregmap() { return riscv.RPC_MASK; }
@Override public String name() { return _name; }
@Override public TypeFunPtr tfp() { return _tfp; }
- // Encoding is appended into the byte array; size is returned
- @Override public int encoding(ByteArrayOutputStream bytes) {
- throw Utils.TODO();
+ @Override public void encoding( Encoding enc ) {
+ enc.relo(this,_tfp);
+ short rpc = enc.reg(this);
+ // High half is where the TFP constant used to be, the last input
+ short auipc = enc.reg(in(_inputs._len-1));
+ int body = riscv.i_type(0x67, rpc, 0/*JALR.C*/, auipc, 0);
+ enc.add4(body);
}
@Override public void asm(CodeGen code, SB sb) {
@@ -39,6 +43,4 @@ public class CallRISC extends CallNode implements MachNode{
sb.p(code.reg(arg(i))).p(" ");
sb.unchar(2);
}
-
- @Override public String op() { return "call"; }
}
diff --git a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/CallRRISC.java b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/CallRRISC.java
index 3bae656d..d209ad5f 100644
--- a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/CallRRISC.java
+++ b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/CallRRISC.java
@@ -1,26 +1,26 @@
package com.seaofnodes.simple.node.cpus.riscv;
import com.seaofnodes.simple.*;
-import com.seaofnodes.simple.codegen.CodeGen;
-import com.seaofnodes.simple.codegen.RegMask;
+import com.seaofnodes.simple.codegen.*;
import com.seaofnodes.simple.node.*;
-import java.io.ByteArrayOutputStream;
-public class CallRRISC extends CallNode implements MachNode{
+public class CallRRISC extends CallNode implements MachNode {
CallRRISC( CallNode call ) { super(call); }
-
+ @Override public String op() { return "callr"; }
@Override public String label() { return op(); }
@Override public RegMask regmap(int i) {
- // Todo: float or int?
- return i==_inputs._len
+ return i==_inputs._len-1
? riscv.RMASK // Function call target
: riscv.callInMask(tfp(),i); // Normal argument
}
@Override public RegMask outregmap() { return null; }
// Encoding is appended into the byte array; size is returned
- @Override public int encoding(ByteArrayOutputStream bytes) {
- throw Utils.TODO();
+ @Override public void encoding( Encoding enc ) {
+ short rpc = enc.reg(this);
+ short src = enc.reg(in(_inputs._len-1));
+ int body = riscv.i_type(0x67, rpc, 0, src, 0);
+ enc.add4(body);
}
@Override public void asm(CodeGen code, SB sb) {
@@ -29,7 +29,4 @@ public class CallRRISC extends CallNode implements MachNode{
sb.p(code.reg(arg(i))).p(" ");
sb.unchar(2);
}
-
- @Override public String op() { return "callr"; }
-
}
diff --git a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/CastRISC.java b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/CastRISC.java
index a0d0df90..dee01217 100644
--- a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/CastRISC.java
+++ b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/CastRISC.java
@@ -2,17 +2,17 @@ package com.seaofnodes.simple.node.cpus.riscv;
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.CastNode;
import com.seaofnodes.simple.node.MachNode;
-import java.io.ByteArrayOutputStream;
public class CastRISC extends CastNode implements MachNode {
CastRISC( CastNode cast ) { super(cast); }
+ @Override public String op() { return label(); }
@Override public RegMask regmap(int i) { assert i==1; return RegMask.FULL; }
@Override public RegMask outregmap() { return RegMask.FULL; }
@Override public int twoAddress( ) { return 1; }
- @Override public int encoding(ByteArrayOutputStream bytes) { return 0; /*no encoding*/ }
+ @Override public void encoding( Encoding enc ) { }
@Override public void asm(CodeGen code, SB sb) { _t.print(sb.p(code.reg(in(1))).p(" isa ")); }
- @Override public String op() { return label(); }
}
diff --git a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/DivFRISC.java b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/DivFRISC.java
index d360bea6..fa3c0249 100644
--- a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/DivFRISC.java
+++ b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/DivFRISC.java
@@ -1,30 +1,19 @@
package com.seaofnodes.simple.node.cpus.riscv;
-import com.seaofnodes.simple.*;
-import com.seaofnodes.simple.codegen.CodeGen;
-import com.seaofnodes.simple.codegen.RegMask;
+import com.seaofnodes.simple.SB;
+import com.seaofnodes.simple.codegen.*;
import com.seaofnodes.simple.node.*;
-import java.io.ByteArrayOutputStream;
+// fdiv.s
public class DivFRISC extends MachConcreteNode implements MachNode{
DivFRISC(Node divf) {super(divf);}
-
- // Register mask allowed on input i.
+ @Override public String op() { return "divf"; }
@Override public RegMask regmap(int i) { assert i==1 || i==2; return riscv.FMASK; }
- // Register mask allowed as a result. 0 for no register.
@Override public RegMask outregmap() { return riscv.FMASK; }
-
- // Encoding is appended into the byte array; size is returned
- @Override public int encoding(ByteArrayOutputStream bytes) {
- throw Utils.TODO();
- }
-
+ @Override public void encoding( Encoding enc ) { riscv.rf_type(enc,this,0x53,riscv.RM.RUP,0xC); }
// Default on double precision for now(64 bits)
// General form: "fdiv.d rd = src1 / src2
@Override public void asm(CodeGen code, SB sb) {
sb.p(code.reg(this)).p(" = ").p(code.reg(in(1))).p(" / ").p(code.reg(in(2)));
}
-
- @Override public String op() { return "divf"; }
-
}
diff --git a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/DivRISC.java b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/DivRISC.java
index ee49a883..884d7bf9 100644
--- a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/DivRISC.java
+++ b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/DivRISC.java
@@ -1,32 +1,17 @@
package com.seaofnodes.simple.node.cpus.riscv;
-import com.seaofnodes.simple.*;
-import com.seaofnodes.simple.codegen.CodeGen;
-import com.seaofnodes.simple.codegen.RegMask;
+import com.seaofnodes.simple.SB;
+import com.seaofnodes.simple.codegen.*;
import com.seaofnodes.simple.node.*;
-import com.seaofnodes.simple.type.TypeInteger;
-import java.io.ByteArrayOutputStream;
public class DivRISC extends MachConcreteNode implements MachNode{
DivRISC(Node div) {super(div);}
-
- // Register mask allowed on input i.
- @Override public RegMask regmap(int i) {
- assert i==1 || i==2;
- return riscv.RMASK; }
- // Register mask allowed as a result. 0 for no register.
+ @Override public String op() { return "div"; }
+ @Override public RegMask regmap(int i) { return riscv.RMASK; }
@Override public RegMask outregmap() { return riscv.WMASK; }
-
- // Encoding is appended into the byte array; size is returned
- @Override public int encoding(ByteArrayOutputStream bytes) {
- throw Utils.TODO();
- }
-
- // Signed division
- // General form: "rd = rs1 / rs"
+ @Override public void encoding( Encoding enc ) { riscv.r_type(enc,this,4,1); }
@Override public void asm(CodeGen code, SB sb) {
sb.p(code.reg(this)).p(" = ").p(code.reg(in(1))).p(" / ").p(code.reg(in(2)));
}
- @Override public String op() { return "div"; }
}
diff --git a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/FltRISC.java b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/FltRISC.java
index 2832ac52..0242d333 100644
--- a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/FltRISC.java
+++ b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/FltRISC.java
@@ -2,30 +2,34 @@ package com.seaofnodes.simple.node.cpus.riscv;
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.*;
import com.seaofnodes.simple.node.ConstantNode;
import com.seaofnodes.simple.node.MachNode;
-import java.io.ByteArrayOutputStream;
+import com.seaofnodes.simple.type.TypeFloat;
public class FltRISC extends ConstantNode implements MachNode{
- FltRISC(ConstantNode con) { super(con); }
+ FltRISC(ConstantNode con) { super(con); }
@Override public String op() { return "flw"; }
- // Register mask allowed on input i. 0 for no register.
@Override public RegMask regmap(int i) { return null; }
- // General int registers! Must-split into the floats
- @Override public RegMask outregmap() { return riscv.RMASK; }
-
+ @Override public RegMask outregmap() { return riscv.FMASK; }
+ @Override public boolean isClone() { return true; }
+ @Override public FltRISC copy() { return new FltRISC(this); }
// Encoding is appended into the byte array; size is returned
- @Override public int encoding(ByteArrayOutputStream bytes) {
+ @Override public void encoding( Encoding enc ) {
+ short dst = (short)(enc.reg(this) - riscv.F_OFFSET);
+ double d = ((TypeFloat)_con).value();
+ long x = Double.doubleToRawLongBits(d);
+
+ // Encode as either a memory slot and load, or stuff into an integer
+ // register (probably 2 int ops), then a fmv.w.x so 3 ops.
+
+ //int body = riscv.i_type(0x07, dst, 0X03, fpr_reg - riscv.F_OFFSET, x);
+ //enc.push_add4(body);
throw Utils.TODO();
}
- // Human-readable form appended to the SB. Things like the encoding,
- // indentation, leading address or block labels not printed here.
- // Just something like "ld4\tR17=[R18+12] // Load array base".
- // General form: "op\tdst=src+src"
@Override public void asm(CodeGen code, SB sb) {
_con.print(sb.p(code.reg(this)).p(" #"));
}
+
}
diff --git a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/FunRISC.java b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/FunRISC.java
index 3b7d9a34..0e931e02 100644
--- a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/FunRISC.java
+++ b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/FunRISC.java
@@ -1,21 +1,13 @@
package com.seaofnodes.simple.node.cpus.riscv;
-import com.seaofnodes.simple.Utils;
-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.MachNode;
-import java.io.ByteArrayOutputStream;
public class FunRISC extends FunNode implements MachNode {
FunRISC(FunNode fun) {super(fun);}
- // Register mask allowed on input i. 0 for no register.
@Override public RegMask regmap(int i) { return null; }
- // Register mask allowed as a result. 0 for no register.
@Override public RegMask outregmap() { return null; }
-
- // Encoding is appended into the byte array; size is returned
- @Override public int encoding(ByteArrayOutputStream bytes) {
- throw Utils.TODO();
- }
+ @Override public void encoding( Encoding enc ) { }
}
diff --git a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/I2F8RISC.java b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/I2F8RISC.java
index 560d1b38..12ffe364 100644
--- a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/I2F8RISC.java
+++ b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/I2F8RISC.java
@@ -1,30 +1,23 @@
package com.seaofnodes.simple.node.cpus.riscv;
import com.seaofnodes.simple.*;
-import com.seaofnodes.simple.codegen.CodeGen;
-import com.seaofnodes.simple.codegen.RegMask;
+import com.seaofnodes.simple.codegen.*;
import com.seaofnodes.simple.node.*;
-import com.seaofnodes.simple.type.TypeInteger;
-import java.io.ByteArrayOutputStream;
// 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.
public class I2F8RISC extends MachConcreteNode implements MachNode {
I2F8RISC(Node i2f8) {super(i2f8);}
-
- // Register mask allowed on input i.
+ @Override public String op() { return "cvtf"; }
@Override public RegMask regmap(int i) { assert i==1; return riscv.RMASK; }
- // Register mask allowed as a result. 0 for no register.
@Override public RegMask outregmap() { return riscv.FMASK; }
-
- // Encoding is appended into the byte array; size is returned
- @Override public int encoding(ByteArrayOutputStream bytes) {
- throw Utils.TODO();
+ @Override public void encoding( Encoding enc ) {
+ short dst = (short)(enc.reg(this )-riscv.F_OFFSET);
+ short src1 = enc.reg(in(1));
+ int body = riscv.r_type(riscv.OP_FP,dst,riscv.RM.RNE.ordinal(),src1,0,0x68);
+ enc.add4(body);
}
-
- // General form: "i2f8 (flt)int_value"
@Override public void asm(CodeGen code, SB sb) {
sb.p(code.reg(this)).p(" = ").p("(flt)").p(code.reg(in(1)));
}
-
- @Override public String op() { return "i2f8"; }
}
diff --git a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/ImmRISC.java b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/ImmRISC.java
index 02191d05..bac9ea6d 100644
--- a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/ImmRISC.java
+++ b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/ImmRISC.java
@@ -1,40 +1,39 @@
package com.seaofnodes.simple.node.cpus.riscv;
import com.seaofnodes.simple.*;
-import com.seaofnodes.simple.codegen.CodeGen;
-import com.seaofnodes.simple.codegen.RegMask;
+import com.seaofnodes.simple.codegen.*;
import com.seaofnodes.simple.node.*;
-import com.seaofnodes.simple.type.TypeInteger;
+
import java.util.BitSet;
-import java.io.ByteArrayOutputStream;
-public abstract class ImmRISC extends MachConcreteNode implements MachNode {
- final int _imm;
- ImmRISC( Node add, int imm ) {
+abstract public class ImmRISC extends MachConcreteNode implements MachNode {
+ final int _imm12;
+ ImmRISC( Node add, int imm12 ) {
super(add);
_inputs.pop();
- _imm = imm;
+ _imm12 = imm12;
}
-
- // Register mask allowed on input i.
@Override public RegMask regmap(int i) { return riscv.RMASK; }
- // Register mask allowed as a result. 0 for no register.
@Override public RegMask outregmap() { return riscv.WMASK; }
@Override public StringBuilder _print1(StringBuilder sb, BitSet visited) {
in(1)._print0(sb.append("( "), visited);
- return sb.append(String.format(" %s #%d )",glabel(),_imm));
+ return sb.append(String.format(" %s #%d )",glabel(),_imm12));
}
abstract int opcode();
+ abstract int func3();
// Encoding is appended into the byte array; size is returned
- @Override public int encoding(ByteArrayOutputStream bytes) {
- throw Utils.TODO();
+ @Override public void encoding( Encoding enc ) {
+ short dst = enc.reg(this );
+ short src = enc.reg(in(1));
+ int body = riscv.i_type(opcode(), dst, func3(), src, _imm12);
+ enc.add4(body);
}
// General form: "addi rd = rs1 + imm"
@Override public void asm(CodeGen code, SB sb) {
- sb.p(code.reg(this)).p(" = ").p(code.reg(in(1))).p(" ").p(glabel()).p(" #").p(_imm);
+ sb.p(code.reg(this)).p(" = ").p(code.reg(in(1))).p(" ").p(glabel()).p(" #").p(_imm12);
}
}
diff --git a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/IntRISC.java b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/IntRISC.java
index e792b055..eb88203c 100644
--- a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/IntRISC.java
+++ b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/IntRISC.java
@@ -1,33 +1,28 @@
package com.seaofnodes.simple.node.cpus.riscv;
import com.seaofnodes.simple.*;
-import com.seaofnodes.simple.codegen.CodeGen;
-import com.seaofnodes.simple.codegen.RegMask;
+import com.seaofnodes.simple.codegen.*;
import com.seaofnodes.simple.node.ConstantNode;
import com.seaofnodes.simple.node.MachNode;
-import java.io.ByteArrayOutputStream;
+import com.seaofnodes.simple.type.TypeInteger;
-// Integer constants
+// 12-bit integer constant. Larger constants are made up in the instruction
+// selection by adding with a LUI.
public class IntRISC extends ConstantNode implements MachNode {
IntRISC(ConstantNode con) { super(con); }
@Override public String op() { return "ldi"; }
- // Register mask allowed on input i. 0 for no register.
@Override public RegMask regmap(int i) { return null; }
- // General int registers
@Override public RegMask outregmap() { return riscv.WMASK; }
-
@Override public boolean isClone() { return true; }
@Override public IntRISC copy() { return new IntRISC(this); }
-
- // Encoding is appended into the byte array; size is returned
- @Override public int encoding(ByteArrayOutputStream bytes) {
- throw Utils.TODO();
+ @Override public void encoding( Encoding enc ) {
+ short dst = enc.reg(this);
+ TypeInteger ti = (TypeInteger)_con;
+ // Explicit truncation of larger immediates; this will sign-extend on
+ // load and this is handled during instruction selection.
+ int body = riscv.i_type(riscv.I_TYPE, dst, 0, riscv.ZERO, (int)(ti.value() & 0xFFF));
+ enc.add4(body);
}
-
- // Human-readable form appended to the SB. Things like the encoding,
- // indentation, leading address or block labels not printed here.
- // Just something like "ld4\tR17=[R18+12] // Load array base".
- // General form: "op\tdst=src+src"
@Override public void asm(CodeGen code, SB sb) {
String reg = code.reg(this);
_con.print(sb.p(reg).p(" = #"));
diff --git a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/LUI.java b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/LUI.java
new file mode 100644
index 00000000..38e7e4b1
--- /dev/null
+++ b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/LUI.java
@@ -0,0 +1,32 @@
+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;
+
+// Load upper 20bits.
+public class LUI extends ConstantNode implements MachNode {
+ LUI( TypeInteger ti ) {
+ super(ti);
+ assert riscv.imm20Exact(ti);
+ }
+ @Override public RegMask regmap(int i) { return null; }
+ @Override public RegMask outregmap() { return riscv.WMASK; }
+ @Override public boolean isClone() { return true; }
+ @Override public LUI copy() { return new LUI((TypeInteger)_con); }
+ @Override public String op() { return "lui"; }
+ @Override public void encoding( Encoding enc ) {
+ long x = ((TypeInteger)_con).value();
+ int imm20 = (int)(x>>12) & 0xFFFFF;
+ short dst = enc.reg(this);
+ int lui = riscv.u_type(0x17, dst, imm20);
+ enc.add4(lui);
+ }
+
+ @Override public void asm(CodeGen code, SB sb) {
+ String reg = code.reg(this);
+ _con.print(sb.p(reg).p(" = #"));
+ }
+}
diff --git a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/LoadRISC.java b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/LoadRISC.java
index 3fe8f44e..b5ca3137 100644
--- a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/LoadRISC.java
+++ b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/LoadRISC.java
@@ -1,40 +1,28 @@
package com.seaofnodes.simple.node.cpus.riscv;
import com.seaofnodes.simple.*;
-import com.seaofnodes.simple.codegen.CodeGen;
-import com.seaofnodes.simple.codegen.RegMask;
+import com.seaofnodes.simple.codegen.*;
import com.seaofnodes.simple.node.*;
-import com.seaofnodes.simple.type.TypeInteger;
-import java.io.ByteArrayOutputStream;
-
// Load memory addressing on RISC
// Support imm, reg(direct), or reg+off(indirect) addressing
// Base = base - base pointer, offset is added to base
// idx = null
-// off = off - offset added to base
-
+// off = off - imm12 added to base
public class LoadRISC extends MemOpRISC {
- LoadRISC(LoadNode ld, Node base, Node idx, int off) {
- super(ld, base, idx, off, 0);
- }
-
- @Override public RegMask regmap(int i) {
- return riscv.RMASK;
- }
- // Wide mask loads both ints and floats; encoding varies.
+ LoadRISC(LoadNode ld, int off) { super(ld, off, null); }
+ @Override public String op() { return "ld" +_sz; }
+ @Override public RegMask regmap(int i) { return riscv.RMASK; }
@Override public RegMask outregmap() { return riscv.MEM_MASK; }
-
-
- // Encoding is appended into the byte array; size is returned
- @Override public int encoding(ByteArrayOutputStream bytes) {
- throw Utils.TODO();
+ @Override public void encoding( Encoding enc ) {
+ short dst = xreg(enc);
+ short ptr = enc.reg(ptr());
+ int body = riscv.i_type(opcode(enc), dst, func3(), ptr, _off);
+ enc.add4(body);
}
@Override public void asm(CodeGen code, SB sb) {
sb.p(code.reg(this)).p(",");
asm_address(code,sb);
}
-
- @Override public String op() { return "ld" +_sz; }
}
diff --git a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/MemOpRISC.java b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/MemOpRISC.java
index bcd7924e..ea56f765 100644
--- a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/MemOpRISC.java
+++ b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/MemOpRISC.java
@@ -1,57 +1,66 @@
package com.seaofnodes.simple.node.cpus.riscv;
-import com.seaofnodes.simple.*;
-import com.seaofnodes.simple.codegen.CodeGen;
-import com.seaofnodes.simple.codegen.RegMask;
+import com.seaofnodes.simple.SB;
+import com.seaofnodes.simple.Utils;
+import com.seaofnodes.simple.codegen.*;
import com.seaofnodes.simple.node.*;
import com.seaofnodes.simple.type.*;
-import java.io.ByteArrayOutputStream;
-import java.lang.StringBuilder;
import java.util.BitSet;
-
-public class MemOpRISC extends MemOpNode implements MachNode {
- final int _off; // Limit 32 bits
- final int _imm; // Limit 32 bits
+public abstract class MemOpRISC extends MemOpNode implements MachNode {
+ final int _off; // Limit 12 bits
final char _sz = (char)('0'+(1<<_declaredType.log_size()));
- MemOpRISC( MemOpNode mop, Node base, Node idx, int off, int imm) {
+ MemOpRISC(MemOpNode mop, int off, Node val) {
super(mop,mop);
- assert base._type instanceof TypeMemPtr && !(base instanceof AddNode);
- assert ptr() == base;
- _inputs.setX(3,idx);
+ assert mop.ptr()._type instanceof TypeMemPtr && !(mop.ptr() instanceof AddNode);
+ _inputs.setX(2, mop.ptr() );
+ _inputs.setX(3, null); // Never an index
+ _inputs.setX(4, val );
_off = off;
- _imm = imm;
- }
- // Store-based flavors have a value edge
- MemOpRISC( MemOpNode mop, Node base, Node idx, int off, int imm, Node val ) {
- this(mop,base,idx,off,imm);
- _inputs.setX(4,val);
}
- Node idx() { return in(3); }
- Node val() { return in(4); } // Only for stores, including op-to-memory
+ @Override public String label() { return op(); }
+ Node val() { return in(4); } // Only for stores
@Override public StringBuilder _printMach(StringBuilder sb, BitSet visited) { return sb.append(".").append(_name); }
- @Override public String label() { return op(); }
@Override public Type compute() { throw Utils.TODO(); }
@Override public Node idealize() { throw Utils.TODO(); }
+ // func3 is based on load/store size and extend
+ int func3() {
+ int func3 = -1;
+ if( _declaredType == TypeInteger. I8 ) func3=0; // LB SB
+ if( _declaredType == TypeInteger.I16 ) func3=1; // LH SH
+ if( _declaredType == TypeInteger.I32 ) func3=2; // LW SW
+ if( _declaredType == TypeInteger.BOT ) func3=3; // LD SD
+ if( _declaredType == TypeInteger. U8 ) func3=4; // LBU
+ if( _declaredType == TypeInteger.BOOL) func3=4; // LBU
+ if( _declaredType == TypeInteger.U16 ) func3=5; // LHU
+ if( _declaredType == TypeInteger.U32 ) func3=6; // LWU
+ if( func3 == -1 ) throw Utils.TODO();
+ return func3;
+ }
+
+ // 7 bits, 00 000 11 or 00 001 11 for FP
+ int opcode(Encoding enc) { return enc.reg(this ) < riscv.F_OFFSET ? 3 : 7; }
+ short xreg(Encoding enc) {
+ short xreg = enc.reg(this );
+ return xreg < riscv.F_OFFSET ? xreg : (short)(xreg-riscv.F_OFFSET);
+ }
// Register mask allowed on input i.
@Override public RegMask regmap(int i) {
+ // 0 - ctrl
+ // 1 - memory
+ if( i==2 ) return riscv.RMASK; // base
+ // 2 - index
+ if( i==4 ) return riscv.MEM_MASK; // value
throw Utils.TODO();
}
- // Register mask allowed as a result. 0 for no register.
- @Override public RegMask outregmap() { throw Utils.TODO(); }
-
- @Override public int encoding(ByteArrayOutputStream bytes) { throw Utils.TODO(); }
-
SB asm_address(CodeGen code, SB sb) {
sb.p("[").p(code.reg(ptr())).p("+");
- if( idx() != null ) sb.p(code.reg(idx()));
- else sb.p(_off);
- return sb.p("]");
+ return sb.p(_off).p("]");
}
}
diff --git a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/MulFRISC.java b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/MulFRISC.java
index 8a066ab1..1612854d 100644
--- a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/MulFRISC.java
+++ b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/MulFRISC.java
@@ -1,30 +1,17 @@
package com.seaofnodes.simple.node.cpus.riscv;
-import com.seaofnodes.simple.*;
-import com.seaofnodes.simple.codegen.CodeGen;
-import com.seaofnodes.simple.codegen.RegMask;
+import com.seaofnodes.simple.SB;
+import com.seaofnodes.simple.codegen.*;
import com.seaofnodes.simple.node.*;
-import java.io.ByteArrayOutputStream;
-public class MulFRISC extends MachConcreteNode implements MachNode{
+// fmul.s
+public class MulFRISC extends MachConcreteNode implements MachNode {
MulFRISC(Node mulf) {super(mulf);}
-
- // Register mask allowed on input i.
+ @Override public String op() { return "mulf"; }
@Override public RegMask regmap(int i) { assert i==1 || i==2; return riscv.FMASK; }
- // Register mask allowed as a result. 0 for no register.
@Override public RegMask outregmap() { return riscv.FMASK; }
-
- // Encoding is appended into the byte array; size is returned
- @Override public int encoding(ByteArrayOutputStream bytes) {
- throw Utils.TODO();
- }
-
- // Default on double precision for now(64 bits)
- // General form: "fmul.d rd = src1 * src2
+ @Override public void encoding( Encoding enc ) { riscv.rf_type(enc,this,0x53,riscv.RM.RNE,0x9); }
@Override public void asm(CodeGen code, SB sb) {
sb.p(code.reg(this)).p(" = ").p(code.reg(in(1))).p(" * ").p(code.reg(in(2)));
}
-
- @Override public String op() { return "mulf"; }
-
}
diff --git a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/MulRISC.java b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/MulRISC.java
index 0e2d35a3..12bed9eb 100644
--- a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/MulRISC.java
+++ b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/MulRISC.java
@@ -1,32 +1,17 @@
package com.seaofnodes.simple.node.cpus.riscv;
-import com.seaofnodes.simple.*;
-import com.seaofnodes.simple.codegen.CodeGen;
-import com.seaofnodes.simple.codegen.RegMask;
+import com.seaofnodes.simple.SB;
+import com.seaofnodes.simple.codegen.*;
import com.seaofnodes.simple.node.*;
-import com.seaofnodes.simple.type.TypeInteger;
-import java.io.ByteArrayOutputStream;
-
// mulh signed multiply instruction(no-imm form)
public class MulRISC extends MachConcreteNode implements MachNode{
MulRISC(Node mul) {super(mul);}
-
- // Register mask allowed on input i.
+ @Override public String op() { return "mul"; }
@Override public RegMask regmap(int i) { assert i==1 || i==2; return riscv.RMASK; }
- // Register mask allowed as a result. 0 for no register.
@Override public RegMask outregmap() { return riscv.WMASK; }
-
- // Encoding is appended into the byte array; size is returned
- @Override public int encoding(ByteArrayOutputStream bytes) {
- throw Utils.TODO();
- }
-
- // General form: "rd = rs1 * rs2"
+ @Override public void encoding( Encoding enc ) { riscv.r_type(enc,this,0,1); }
@Override public void asm(CodeGen code, SB sb) {
sb.p(code.reg(this)).p(" = ").p(code.reg(in(1))).p(" * ").p(code.reg(in(2)));
}
-
- @Override public String op() { return "mul"; }
-
}
diff --git a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/NewRISC.java b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/NewRISC.java
index 53ad0af2..5faf17f5 100644
--- a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/NewRISC.java
+++ b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/NewRISC.java
@@ -1,29 +1,35 @@
package com.seaofnodes.simple.node.cpus.riscv;
import com.seaofnodes.simple.*;
-import com.seaofnodes.simple.codegen.CodeGen;
-import com.seaofnodes.simple.codegen.RegMask;
+import com.seaofnodes.simple.codegen.*;
import com.seaofnodes.simple.node.*;
-import java.io.ByteArrayOutputStream;
public class NewRISC extends NewNode implements MachNode {
// A pre-zeroed chunk of memory.
- NewRISC( NewNode nnn ) { super(nnn); }
+ NewRISC( NewNode nnn, AUIPC auipc ) {
+ super(nnn);
+ _inputs.add(auipc); // Add high-half address
+ }
+ @Override public String op() { return "alloc"; }
// Size and pointer result in standard calling convention; null for all the
// memory aliases edges
@Override public RegMask regmap(int i) { return i == 1 ? riscv.A0_MASK : null; }
@Override public RegMask outregmap(int i) { return i == 1 ? riscv.A0_MASK : null; }
@Override public RegMask outregmap() { return null; }
+ @Override public RegMask killmap() { return riscv.riscCallerSave(); }
// Encoding is appended into the byte array; size is returned
- @Override public int encoding(ByteArrayOutputStream bytes) {
- throw Utils.TODO();
+ @Override public void encoding( Encoding enc ) {
+ enc.relo(this);
+ short rpc = enc.reg(this);
+ // High half is where the TFP constant used to be, the last input
+ short auipc = enc.reg(in(_inputs._len-1));
+ int body = riscv.i_type(0x67, rpc, 0/*JALR.C*/, auipc, 0);
+ enc.add4(body);
}
// General form: "alloc #bytes"
@Override public void asm(CodeGen code, SB sb) {
sb.p(code.reg(size()));
}
-
- @Override public String op() { return "alloc"; }
}
diff --git a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/NotRISC.java b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/NotRISC.java
new file mode 100644
index 00000000..cca0327c
--- /dev/null
+++ b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/NotRISC.java
@@ -0,0 +1,16 @@
+package com.seaofnodes.simple.node.cpus.riscv;
+
+import com.seaofnodes.simple.SB;
+import com.seaofnodes.simple.codegen.*;
+import com.seaofnodes.simple.node.NotNode;
+
+public class NotRISC extends ImmRISC {
+ NotRISC(NotNode not) { super(not,1); }
+ @Override public RegMask regmap(int i) { return riscv.RMASK; }
+ @Override public RegMask outregmap() { return riscv.RMASK; }
+ @Override public String op() { return "not"; }
+ // sltiu: x <u 1 ? 1 : 0; only zero is unsigned-less-than 1
+ @Override int opcode() { return 19; }
+ @Override int func3() { return 2; }
+ @Override public void asm(CodeGen code, SB sb) { sb.p(code.reg(this)); }
+}
diff --git a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/OrIRISC.java b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/OrIRISC.java
index f41d7162..70cd9c48 100644
--- a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/OrIRISC.java
+++ b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/OrIRISC.java
@@ -5,7 +5,8 @@ import com.seaofnodes.simple.node.Node;
public class OrIRISC extends ImmRISC {
OrIRISC( Node and, int imm) { super(and,imm); }
- @Override int opcode() { throw Utils.TODO(); }
+ @Override int opcode() { return riscv.I_TYPE; }
+ @Override int func3() { return 6; }
@Override public String glabel() { return "|"; }
@Override public String op() { return "ori"; }
}
diff --git a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/OrRISC.java b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/OrRISC.java
index 7f808f90..6039fa32 100644
--- a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/OrRISC.java
+++ b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/OrRISC.java
@@ -1,39 +1,16 @@
package com.seaofnodes.simple.node.cpus.riscv;
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.node.MachConcreteNode;
-import com.seaofnodes.simple.node.MachNode;
-import com.seaofnodes.simple.node.Node;
-import java.io.ByteArrayOutputStream;
+import com.seaofnodes.simple.codegen.*;
+import com.seaofnodes.simple.node.*;
public class OrRISC extends MachConcreteNode implements MachNode {
- OrRISC(Node or) {
- super(or);
- }
-
- // Register mask allowed on input i.
- // This is the normal calling convention
- @Override public RegMask regmap(int i) {
- assert i==1 || i==2;
- return riscv.RMASK;
- }
-
- // Register mask allowed as a result. 0 for no register.
+ OrRISC(Node or) { super(or); }
+ @Override public String op() { return "or"; }
+ @Override public RegMask regmap(int i) { return riscv.RMASK; }
@Override public RegMask outregmap() { return riscv.WMASK; }
-
- // Encoding is appended into the byte array; size is returned
- @Override public int encoding(ByteArrayOutputStream bytes) {
- throw Utils.TODO();
- }
-
- // General form
- // General form: # rd = rs1 | rs2
+ @Override public void encoding( Encoding enc ) { riscv.r_type(enc,this,6,0); }
@Override public void asm(CodeGen code, SB sb) {
sb.p(code.reg(this)).p(" = ").p(code.reg(in(1))).p(" | ").p(code.reg(in(2)));
}
-
- @Override public String op() { return "or"; }
}
diff --git a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/ParmRISC.java b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/ParmRISC.java
index 75674f37..02d53560 100644
--- a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/ParmRISC.java
+++ b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/ParmRISC.java
@@ -1,26 +1,17 @@
package com.seaofnodes.simple.node.cpus.riscv;
-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.RegMask;
import com.seaofnodes.simple.node.MachNode;
import com.seaofnodes.simple.node.ParmNode;
-import java.io.ByteArrayOutputStream;
public class ParmRISC extends ParmNode implements MachNode {
final RegMask _rmask;
ParmRISC(ParmNode parm) {
super(parm);
- // Assume int
_rmask = riscv.callInMask(fun().sig(),_idx);
}
-
- // Register mask allowed on input i. 0 for no register.
- @Override public RegMask regmap(int i) { return _rmask; }
- // Register mask allowed as a result. Calling convention register
+ @Override public RegMask regmap(int i) { return null; }
@Override public RegMask outregmap() { return _rmask; }
-
- // Encoding is appended into the byte array. Returns size
- @Override public int encoding(ByteArrayOutputStream bytes) { return 0; }
+ @Override public void encoding( Encoding enc ) { }
}
diff --git a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/ProjRISC.java b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/ProjRISC.java
index 42d5dc9b..2f9ac469 100644
--- a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/ProjRISC.java
+++ b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/ProjRISC.java
@@ -1,25 +1,15 @@
package com.seaofnodes.simple.node.cpus.riscv;
-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.RegMask;
import com.seaofnodes.simple.node.MachNode;
import com.seaofnodes.simple.node.ProjNode;
-import java.io.ByteArrayOutputStream;
public class ProjRISC extends ProjNode implements MachNode {
ProjRISC(ProjNode p) { super(p); }
-
- // Register mask allowed on input i. 0 for no register.
@Override public RegMask regmap(int i) { return null; }
- // Register mask allowed as a result.
@Override public RegMask outregmap() {
return ((MachNode)in(0)).outregmap(_idx);
}
-
- // Encoding is appended into the byte array; size is returned
- @Override public int encoding(ByteArrayOutputStream bytes) {
- throw Utils.TODO();
- }
+ @Override public void encoding( Encoding enc ) { }
}
diff --git a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/RetRISC.java b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/RetRISC.java
index c9fa7fac..42f34d85 100644
--- a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/RetRISC.java
+++ b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/RetRISC.java
@@ -2,26 +2,27 @@ 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.type.TypeFloat;
-
-import java.io.ByteArrayOutputStream;
public class RetRISC extends ReturnNode implements MachNode{
RetRISC(ReturnNode ret, FunNode fun) { super(ret, fun); fun.setRet(this); }
-
- // Register mask allowed on input i.
- // This is the normal calling convention
+ @Override public String op() { return "ret"; }
+ // Correct Nodes outside the normal edges
+ @Override public void postSelect() {
+ FunNode fun = (FunNode)rpc().in(0);
+ _fun = fun;
+ fun.setRet(this);
+ }
@Override public RegMask regmap(int i) { return riscv.retMask(_fun.sig(),i); }
- // Register mask allowed as a result. 0 for no register.
@Override public RegMask outregmap() { return null; }
-
- // Encoding is appended into the byte array; size is returned
- @Override public int encoding(ByteArrayOutputStream bytes) {
- throw Utils.TODO();
+ @Override public void encoding( Encoding enc ) {
+ short rpc = enc.reg(this);
+ int body = riscv.i_type(0x67, riscv.ZERO, 0, rpc, 0);
+ enc.add4(body);
}
@Override public void asm(CodeGen code, SB sb) {
@@ -33,16 +34,7 @@ public class RetRISC extends ReturnNode implements MachNode{
sb.p(code.reg(in(i))).p(" ");
// Post-allocation, if we did not get the expected return register, print what we got
- else if( code._regAlloc.regnum(in(3)) != riscv.RPC )
- sb.p("[").p(code.reg(in(3))).p("]");
+ else if( code._regAlloc.regnum(rpc()) != riscv.RPC )
+ sb.p("[").p(code.reg(rpc())).p("]");
}
-
- // Correct Nodes outside the normal edges
- @Override public void postSelect() {
- FunNode fun = (FunNode)rpc().in(0);
- _fun = fun;
- fun.setRet(this);
- }
-
- @Override public String op() { return "ret"; }
}
diff --git a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/SetFRISC.java b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/SetFRISC.java
index 3f9fc192..52a3c24d 100644
--- a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/SetFRISC.java
+++ b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/SetFRISC.java
@@ -1,15 +1,14 @@
package com.seaofnodes.simple.node.cpus.riscv;
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.*;
import com.seaofnodes.simple.node.BoolNode;
import com.seaofnodes.simple.node.MachConcreteNode;
import com.seaofnodes.simple.node.MachNode;
-import java.io.ByteArrayOutputStream;
-// corresponds to slt,sltu,slti,sltiu, seqz
+// corresponds to feq.d = equal
+// fle.d = less than or equal
+// flt.d = less than
public class SetFRISC extends MachConcreteNode implements MachNode {
final String _bop; // One of <,<=,==
SetFRISC( BoolNode bool ) {
@@ -17,17 +16,18 @@ public class SetFRISC extends MachConcreteNode implements MachNode {
assert bool.isFloat();
_bop = bool.op();
}
+ @Override public String op() { return "set"+_bop; }
@Override public RegMask regmap(int i) { return riscv.FMASK; }
@Override public RegMask outregmap() { return riscv.WMASK; }
-
- // Encoding is appended into the byte array; size is returned
- @Override public int encoding(ByteArrayOutputStream bytes) {
- throw Utils.TODO();
+ @Override public void encoding( Encoding enc ) {
+ short dst = enc.reg(this );
+ short src1 = (short)(enc.reg(in(1))-riscv.F_OFFSET);
+ short src2 = (short)(enc.reg(in(2))-riscv.F_OFFSET);
+ int body = riscv.r_type(0x53,dst,riscv.fsetop(_bop),src1,src2,0);
+ enc.add4(body);
}
@Override public void asm(CodeGen code, SB sb) {
sb.p(code.reg(in(1))).p(" ").p(_bop).p(" ").p(code.reg(in(2)));
}
-
- @Override public String op() { return "set"+_bop; }
}
diff --git a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/SetIRISC.java b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/SetIRISC.java
index 3c0f76ae..22115e3f 100644
--- a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/SetIRISC.java
+++ b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/SetIRISC.java
@@ -1,17 +1,17 @@
package com.seaofnodes.simple.node.cpus.riscv;
import com.seaofnodes.simple.Utils;
-import com.seaofnodes.simple.node.BoolNode;
+import com.seaofnodes.simple.node.Node;
-// corresponds to slt,sltu,slti,sltiu, seqz
+// corresponds to slti,sltiu
public class SetIRISC extends ImmRISC {
- final String _bop; // One of <,<=,==
- SetIRISC( BoolNode bool, int imm ) {
- super(bool,imm);
- assert !bool.isFloat();
- _bop = bool.op();
+ final boolean _unsigned; // slti vs sltiu
+ SetIRISC( Node src, int imm12, boolean unsigned ) {
+ super(src,imm12);
+ _unsigned = unsigned;
}
- @Override int opcode() { throw Utils.TODO(); }
- @Override public String glabel() { return _bop; }
- @Override public String op() { return "set"+_bop; }
+ @Override public String op() { return "setlt" + (_unsigned ? "u":""); }
+ @Override public String glabel() { return op(); }
+ @Override int opcode() { return 19; }
+ @Override int func3() { return 2; }
}
diff --git a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/SetRISC.java b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/SetRISC.java
index fb7650c7..cae450c5 100644
--- a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/SetRISC.java
+++ b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/SetRISC.java
@@ -1,33 +1,17 @@
package com.seaofnodes.simple.node.cpus.riscv;
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.node.BoolNode;
-import com.seaofnodes.simple.node.MachConcreteNode;
-import com.seaofnodes.simple.node.MachNode;
-import java.io.ByteArrayOutputStream;
+import com.seaofnodes.simple.codegen.*;
+import com.seaofnodes.simple.node.*;
-// corresponds to slt,sltu,slti,sltiu, seqz
+// corresponds to slt (and NOT sltu, slti, sltiu)
public class SetRISC extends MachConcreteNode implements MachNode {
- final String _bop; // One of <,<=,==
- SetRISC( BoolNode bool ) {
- super(bool);
- assert !bool.isFloat();
- _bop = bool.op();
- }
- @Override public RegMask regmap(int i) { throw Utils.TODO(); }
+ SetRISC( Node cmp ) { super(cmp); }
+ @Override public String op() { return "slt"; }
+ @Override public RegMask regmap(int i) { return riscv.RMASK; }
@Override public RegMask outregmap() { return riscv.WMASK; }
-
- // Encoding is appended into the byte array; size is returned
- @Override public int encoding(ByteArrayOutputStream bytes) {
- throw Utils.TODO();
- }
-
+ @Override public void encoding( Encoding enc ) { riscv.r_type(enc,this,2,0); }
@Override public void asm(CodeGen code, SB sb) {
- sb.p(code.reg(in(1))).p(" ").p(_bop).p(" ").p(code.reg(in(2)));
+ sb.p(code.reg(in(1))).p(" < ").p(code.reg(in(2)));
}
-
- @Override public String op() { return "set"+_bop; }
}
diff --git a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/SllIRISC.java b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/SllIRISC.java
index b5202908..dedbf783 100644
--- a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/SllIRISC.java
+++ b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/SllIRISC.java
@@ -5,7 +5,8 @@ import com.seaofnodes.simple.node.Node;
public class SllIRISC extends ImmRISC {
SllIRISC( Node and, int imm) { super(and,imm); }
- @Override int opcode() { throw Utils.TODO(); }
+ @Override int opcode() { return riscv.I_TYPE; }
+ @Override int func3() { return 1; }
@Override public String glabel() { return "<<"; }
@Override public String op() { return "slli"; }
}
diff --git a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/SllRISC.java b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/SllRISC.java
index 447f604a..8fd8fb06 100644
--- a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/SllRISC.java
+++ b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/SllRISC.java
@@ -1,37 +1,17 @@
package com.seaofnodes.simple.node.cpus.riscv;
-import com.seaofnodes.simple.*;
-import com.seaofnodes.simple.codegen.CodeGen;
-import com.seaofnodes.simple.codegen.RegMask;
+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.TypeInteger;
-import java.io.ByteArrayOutputStream;
-import java.util.BitSet;
-public class SllRISC extends MachConcreteNode implements MachNode{
- SllRISC(Node sll) {super(sll);}
-
- // Register mask allowed on input i.
- // This is the normal calling convention
- @Override public RegMask regmap(int i) {
- //assert i==1;
- return riscv.RMASK; }
- // Register mask allowed as a result. 0 for no register.
+// Shift left logical
+public class SllRISC extends MachConcreteNode implements MachNode {
+ SllRISC(Node sll) { super(sll); }
+ @Override public String op() { return "shl"; }
+ @Override public RegMask regmap(int i) { return riscv.RMASK; }
@Override public RegMask outregmap() { return riscv.WMASK; }
-
- // Encoding is appended into the byte array; size is returned
- @Override public int encoding(ByteArrayOutputStream bytes) {
- throw Utils.TODO();
- }
-
- // General form
- // General form: "sll rd, rs1, rs2"
+ @Override public void encoding( Encoding enc ) { riscv.r_type(enc,this,1,0); }
@Override public void asm(CodeGen code, SB sb) {
-
sb.p(code.reg(this)).p(" = ").p(code.reg(in(1))).p(" << ").p(code.reg(in(2)));
-
}
-
- @Override public String op() { return "sll"; }
}
diff --git a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/SplitRISC.java b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/SplitRISC.java
index b5076ba0..54a6db38 100644
--- a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/SplitRISC.java
+++ b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/SplitRISC.java
@@ -1,21 +1,17 @@
package com.seaofnodes.simple.node.cpus.riscv;
-import com.seaofnodes.simple.Utils;
-import com.seaofnodes.simple.codegen.RegMask;
+import com.seaofnodes.simple.codegen.*;
import com.seaofnodes.simple.node.Node;
import com.seaofnodes.simple.node.SplitNode;
-import java.io.ByteArrayOutputStream;
public class SplitRISC extends SplitNode {
SplitRISC( String kind, byte round ) { super(kind,round, new Node[2]); }
-
- // Register mask allowed on input i.
@Override public RegMask regmap(int i) { return riscv.SPLIT_MASK; }
- // Register mask allowed as a result. 0 for no register.
@Override public RegMask outregmap() { return riscv.SPLIT_MASK; }
-
- // Encoding is appended into the byte array; size is returned
- @Override public int encoding(ByteArrayOutputStream bytes) {
- throw Utils.TODO();
+ @Override public void encoding( Encoding enc ) {
+ short dst = enc.reg(this );
+ short src1 = enc.reg(in(1));
+ int body = riscv.r_type(riscv.OP,dst,0,src1,riscv.ZERO,0);
+ enc.add4(body);
}
}
diff --git a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/SraIRISC.java b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/SraIRISC.java
index d5ab5e08..94270f3a 100644
--- a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/SraIRISC.java
+++ b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/SraIRISC.java
@@ -5,7 +5,8 @@ import com.seaofnodes.simple.node.Node;
public class SraIRISC extends ImmRISC {
SraIRISC( Node and, int imm) { super(and,imm); }
- @Override int opcode() { throw Utils.TODO(); }
+ @Override int opcode() { return riscv.I_TYPE; }
+ @Override int func3() { return 5;}
@Override public String glabel() { return ">>"; }
@Override public String op() { return "srai"; }
}
diff --git a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/SraRISC.java b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/SraRISC.java
index 0726e292..e878df7f 100644
--- a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/SraRISC.java
+++ b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/SraRISC.java
@@ -1,38 +1,17 @@
package com.seaofnodes.simple.node.cpus.riscv;
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.node.MachConcreteNode;
-import com.seaofnodes.simple.node.MachNode;
-import com.seaofnodes.simple.node.Node;
-import com.seaofnodes.simple.type.TypeInteger;
-import java.io.ByteArrayOutputStream;
+import com.seaofnodes.simple.codegen.*;
+import com.seaofnodes.simple.node.*;
// Right Shift Arithmetic
public class SraRISC extends MachConcreteNode implements MachNode {
-
- SraRISC(Node sra) {super(sra);}
-
- // Register mask allowed on input i.
- // This is the normal calling convention
- @Override public RegMask regmap(int i) {
- // assert i==1;
- return riscv.RMASK; }
- // Register mask allowed as a result. 0 for no register.
+ SraRISC(Node sra) { super(sra); }
+ @Override public String op() { return "sar"; }
+ @Override public RegMask regmap(int i) { return riscv.RMASK; }
@Override public RegMask outregmap() { return riscv.WMASK; }
-
- // Encoding is appended into the byte array; size is returned
- @Override public int encoding(ByteArrayOutputStream bytes) {
- throw Utils.TODO();
- }
-
- // General form
- // General form: "sra rd, rs1, rs2"
+ @Override public void encoding( Encoding enc ) { riscv.r_type(enc,this,5,0x20); }
@Override public void asm(CodeGen code, SB sb) {
sb.p(code.reg(this)).p(" = ").p(code.reg(in(1))).p(" >> ").p(code.reg(in(2)));
}
-
- @Override public String op() { return "sra"; }
}
diff --git a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/SrlIRISC.java b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/SrlIRISC.java
index a4eb99bc..7a28d598 100644
--- a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/SrlIRISC.java
+++ b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/SrlIRISC.java
@@ -5,7 +5,8 @@ import com.seaofnodes.simple.node.Node;
public class SrlIRISC extends ImmRISC {
SrlIRISC( Node and, int imm) { super(and,imm); }
- @Override int opcode() { throw Utils.TODO(); }
+ @Override int opcode() { return riscv.I_TYPE; }
+ @Override int func3() { return 5; }
@Override public String glabel() { return ">>>"; }
@Override public String op() { return "srli"; }
}
diff --git a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/SrlRISC.java b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/SrlRISC.java
index d1435540..67a5d40e 100644
--- a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/SrlRISC.java
+++ b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/SrlRISC.java
@@ -1,38 +1,17 @@
package com.seaofnodes.simple.node.cpus.riscv;
-import com.seaofnodes.simple.*;
-import com.seaofnodes.simple.codegen.CodeGen;
-import com.seaofnodes.simple.codegen.RegMask;
+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.TypeInteger;
-import java.io.ByteArrayOutputStream;
-import java.util.BitSet;
-import java.lang.StringBuilder;
// Right Shift Logical
public class SrlRISC extends MachConcreteNode implements MachNode {
- SrlRISC(Node srli) {super(srli);}
-
- // Register mask allowed on input i.
- // This is the normal calling convention
- @Override public RegMask regmap(int i) {
- // assert i==1;
- return riscv.RMASK; }
- // Register mask allowed as a result. 0 for no register.
+ SrlRISC(Node srli) { super(srli); }
+ @Override public String op() { return "shr"; }
+ @Override public RegMask regmap(int i) { return riscv.RMASK; }
@Override public RegMask outregmap() { return riscv.WMASK; }
-
- // Encoding is appended into the byte array; size is returned
- @Override public int encoding(ByteArrayOutputStream bytes) {
- throw Utils.TODO();
- }
-
- // General form
- // General form: "srl rd, rs1, rs2"
+ @Override public void encoding( Encoding enc ) { riscv.r_type(enc,this,7,0); }
@Override public void asm(CodeGen code, SB sb) {
-
sb.p(code.reg(this)).p(" = ").p(code.reg(in(1))).p(" >>> ").p(code.reg(in(2)));
}
-
- @Override public String op() { return "srl"; }
}
diff --git a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/StoreRISC.java b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/StoreRISC.java
index c57cf11d..b78eac1f 100644
--- a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/StoreRISC.java
+++ b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/StoreRISC.java
@@ -2,14 +2,9 @@ package com.seaofnodes.simple.node.cpus.riscv;
import com.seaofnodes.simple.SB;
import com.seaofnodes.simple.Utils;
-import com.seaofnodes.simple.codegen.CodeGen;
+import com.seaofnodes.simple.codegen.*;
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.node.StoreNode;
-import java.io.ByteArrayOutputStream;
-import java.util.BitSet;
+import com.seaofnodes.simple.node.*;
// Store memory addressing on ARM
// Support imm, reg(direct), or reg+off(indirect) addressing
@@ -24,33 +19,28 @@ import java.util.BitSet;
// sw rs2,offset(rs1)
public class StoreRISC extends MemOpRISC {
- StoreRISC( StoreNode st, Node base, Node idx, int off, int imm, Node val ) {
- super(st, base, idx, off, imm, val);
- }
-
- // Wider mask to store both GPRs and FPRs
+ StoreRISC( StoreNode st, int off, Node val ) { super(st, off, val); }
+ @Override public String op() { return "st"+_sz; }
@Override public RegMask regmap(int i) {
- if( i==1 ) return riscv.MEM_MASK;
- if( i==2 ) return riscv.RMASK;
- if( i==3 ) return riscv.RMASK;
- if( i==4 ) return riscv.RMASK;
+ // 0 - ctrl
+ // 1 - mem
+ if( i==2 ) return riscv.RMASK; // ptr
+ // 2 - index
+ if( i==4 ) return riscv.MEM_MASK; // Wide mask to store GPR and FPR
throw Utils.TODO();
}
-
-
- // Register mask allowed as a result. 0 for no register.
@Override public RegMask outregmap() { return null; }
- // Encoding is appended into the byte array; size is returned
- @Override public int encoding(ByteArrayOutputStream bytes) {
- throw Utils.TODO();
+ @Override public void encoding( Encoding enc ) {
+ short val = xreg(enc);
+ short ptr = enc.reg(ptr());
+ int body = riscv.s_type(opcode(enc), ptr, func3()&3, val, _off);
+ enc.add4(body);
}
@Override public void asm(CodeGen code, SB sb) {
asm_address(code,sb).p(",");
- if( val()==null ) sb.p("#").p(_imm);
+ if( val()==null ) sb.p("#").p("0");
else sb.p(code.reg(val()));
}
-
- @Override public String op() { return "st"+_sz; }
}
diff --git a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/SubFRISC.java b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/SubFRISC.java
index e6fe3012..c59a70b4 100644
--- a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/SubFRISC.java
+++ b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/SubFRISC.java
@@ -1,30 +1,17 @@
package com.seaofnodes.simple.node.cpus.riscv;
-import com.seaofnodes.simple.*;
-import com.seaofnodes.simple.codegen.CodeGen;
-import com.seaofnodes.simple.codegen.RegMask;
+import com.seaofnodes.simple.SB;
+import com.seaofnodes.simple.codegen.*;
import com.seaofnodes.simple.node.*;
-import com.seaofnodes.simple.type.TypeInteger;
-import java.io.ByteArrayOutputStream;
-public class SubFRISC extends MachConcreteNode implements MachNode{
+// fsub.s
+public class SubFRISC extends MachConcreteNode implements MachNode {
SubFRISC(Node subf) {super(subf);}
-
- // Register mask allowed on input i.
+ @Override public String op() { return "subf"; }
@Override public RegMask regmap(int i) { assert i==1 || i==2; return riscv.FMASK; }
- // Register mask allowed as a result. 0 for no register.
@Override public RegMask outregmap() { return riscv.FMASK; }
-
- // Encoding is appended into the byte array; size is returned
- @Override public int encoding(ByteArrayOutputStream bytes) {
- throw Utils.TODO();
- }
-
- // Default on double precision for now(64 bits)
- // General form: "fsub.d rd = src1 - src2
+ @Override public void encoding( Encoding enc ) { riscv.rf_type(enc,this,0x53,riscv.RM.RNE,0x5); }
@Override public void asm(CodeGen code, SB sb) {
sb.p(code.reg(this)).p(" = ").p(code.reg(in(1))).p(" + ").p(code.reg(in(2)));
}
-
- @Override public String op() { return "subf"; }
}
diff --git a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/SubRISC.java b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/SubRISC.java
index c37aea98..ce20f1e1 100644
--- a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/SubRISC.java
+++ b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/SubRISC.java
@@ -1,29 +1,16 @@
package com.seaofnodes.simple.node.cpus.riscv;
import com.seaofnodes.simple.*;
-import com.seaofnodes.simple.codegen.CodeGen;
-import com.seaofnodes.simple.codegen.RegMask;
+import com.seaofnodes.simple.codegen.*;
import com.seaofnodes.simple.node.*;
-import com.seaofnodes.simple.type.TypeInteger;
-import java.io.ByteArrayOutputStream;
public class SubRISC extends MachConcreteNode implements MachNode {
SubRISC( Node sub ) { super(sub); }
-
- // Register mask allowed on input i.
+ @Override public String op() { return "sub"; }
@Override public RegMask regmap(int i) { assert i==1 || i==2; return riscv.RMASK; }
- // Register mask allowed as a result. 0 for no register.
@Override public RegMask outregmap() { return riscv.WMASK; }
-
- // Encoding is appended into the byte array; size is returned
- @Override public int encoding(ByteArrayOutputStream bytes) {
- throw Utils.TODO();
- }
-
- // General form: "sub # rd = rs1 - rs2"
+ @Override public void encoding( Encoding enc ) { riscv.r_type(enc,this,0,0x20); }
@Override public void asm(CodeGen code, SB sb) {
sb.p(code.reg(this)).p(" = ").p(code.reg(in(1))).p(" - ").p(code.reg(in(2)));
}
-
- @Override public String op() { return "sub"; }
}
diff --git a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/TFPRISC.java b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/TFPRISC.java
index 23fb6a74..ac2eac39 100644
--- a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/TFPRISC.java
+++ b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/TFPRISC.java
@@ -1,39 +1,30 @@
package com.seaofnodes.simple.node.cpus.riscv;
import com.seaofnodes.simple.*;
-import com.seaofnodes.simple.codegen.CodeGen;
-import com.seaofnodes.simple.codegen.RegMask;
+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.TypeFunPtr;
-import java.io.ByteArrayOutputStream;
-public class TFPRISC extends ConstantNode implements MachNode{
- TFPRISC(ConstantNode con) {super(con);}
- @Override public String op() { return _con == Type.NIL ? "xor" : "ldx"; }
- // Register mask allowed on input i. 0 for no register.
+public class TFPRISC extends ConstantNode implements MachNode {
+ TFPRISC(ConstantNode con) { super(con); }
+ @Override public String op() { return "ldx"; }
@Override public RegMask regmap(int i) { return null; }
- // General int registers
@Override public RegMask outregmap() { return riscv.WMASK; }
-
@Override public boolean isClone() { return true; }
@Override public TFPRISC copy() { return new TFPRISC(this); }
-
- // Encoding is appended into the byte array; size is returned
- @Override public int encoding(ByteArrayOutputStream bytes) {
+ @Override public void encoding( Encoding enc ) {
+ enc.relo(this,(TypeFunPtr)_con);
+ short dst = enc.reg(this);
+ TypeFunPtr tfp = (TypeFunPtr)_con;
+ //int body = riscv.i_type(riscv.I_TYPE, dst, 0, riscv.ZERO, (int)(ti.value() & 0xFFF));
+ //enc.add4(body);
+ // Surely need to split into 2 ops?
throw Utils.TODO();
}
- // Human-readable form appended to the SB. Things like the encoding,
- // indentation, leading address or block labels not printed here.
- // Just something like "ld4\tR17=[R18+12] // Load array base".
- // General form: "op\tdst=src+src"
@Override public void asm(CodeGen code, SB sb) {
- String reg = code.reg(this);
- if( _con == Type.NIL )
- sb.p(reg).p(",").p(reg);
- else
- _con.print(sb.p(reg).p(" #"));
+ _con.print(sb.p(code.reg(this)).p(" #"));
}
+
}
diff --git a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/XorIRISC.java b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/XorIRISC.java
index a2e32f06..5842f04d 100644
--- a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/XorIRISC.java
+++ b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/XorIRISC.java
@@ -5,7 +5,8 @@ import com.seaofnodes.simple.node.Node;
public class XorIRISC extends ImmRISC {
XorIRISC( Node and, int imm) { super(and,imm); }
- @Override int opcode() { throw Utils.TODO(); }
+ @Override int opcode() { return riscv.I_TYPE; }
+ @Override int func3() { return 4; }
@Override public String glabel() { return "^"; }
@Override public String op() { return "xori"; }
}
diff --git a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/XorRISC.java b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/XorRISC.java
index f4ecb430..420b59e3 100644
--- a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/XorRISC.java
+++ b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/XorRISC.java
@@ -1,41 +1,16 @@
package com.seaofnodes.simple.node.cpus.riscv;
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.node.MachConcreteNode;
-import com.seaofnodes.simple.node.MachNode;
-import com.seaofnodes.simple.node.Node;
-import com.seaofnodes.simple.type.TypeInteger;
-import java.io.ByteArrayOutputStream;
+import com.seaofnodes.simple.codegen.*;
+import com.seaofnodes.simple.node.*;
public class XorRISC extends MachConcreteNode implements MachNode {
-
- XorRISC(Node or) {
- super(or);
- }
-
- // Register mask allowed on input i.
- // This is the normal calling convention
- @Override public RegMask regmap(int i) {
- assert i==1 || i==2;
- return riscv.RMASK;
- }
-
- // Register mask allowed as a result. 0 for no register.
+ XorRISC(Node or) { super(or); }
+ @Override public String op() { return "xor"; }
+ @Override public RegMask regmap(int i) { return riscv.RMASK; }
@Override public RegMask outregmap() { return riscv.WMASK; }
-
- // Encoding is appended into the byte array; size is returned
- @Override public int encoding(ByteArrayOutputStream bytes) {
- throw Utils.TODO();
- }
-
- // General form
- // General form: # # rd = rs1 ^ rs2
+ @Override public void encoding( Encoding enc ) { riscv.r_type(enc,this,4,0); }
@Override public void asm(CodeGen code, SB sb) {
-
sb.p(code.reg(this)).p(" = ").p(code.reg(in(1))).p(" ^ ").p(code.reg(in(2)));
-
}
}
diff --git a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/riscv.java b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/riscv.java
index 83706cbf..3367a520 100644
--- a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/riscv.java
+++ b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/riscv.java
@@ -1,43 +1,41 @@
package com.seaofnodes.simple.node.cpus.riscv;
import com.seaofnodes.simple.Utils;
-import com.seaofnodes.simple.codegen.LRG;
-import com.seaofnodes.simple.codegen.Machine;
-import com.seaofnodes.simple.codegen.RegMask;
+import com.seaofnodes.simple.codegen.*;
import com.seaofnodes.simple.node.*;
import com.seaofnodes.simple.type.*;
+import java.io.ByteArrayOutputStream;
+
public class riscv extends Machine {
@Override public String name() {return "riscv";}
// Using ABI names instead of register names
- static final int RPC= 1, SP = 2, GP = 3, TP = 4, T0 = 5, T1 = 6, T2 = 7;
- static final int S0 = 8, S1 = 9, A0 = 10, A1 = 11, A2 = 12, A3 = 13, A4 = 14, A5 = 15;
- static final int A6 = 16, A7 = 17, S2 = 18, S3 = 19, S4 = 20, S5 = 21, S6 = 22, S7 = 23;
- static final int S8 = 24, S9 = 25, S10 = 26, S11 = 27, T3 = 28, T4 = 29, T5 = 30, T6 = 31;
+ public static int ZERO = 0, RPC= 1, SP = 2, GP = 3, TP = 4, T0 = 5, T1 = 6, T2 = 7;
+ public static int S0 = 8, S1 = 9, A0 = 10, A1 = 11, A2 = 12, A3 = 13, A4 = 14, A5 = 15;
+ public static int A6 = 16, A7 = 17, S2 = 18, S3 = 19, S4 = 20, S5 = 21, S6 = 22, S7 = 23;
+ public static int S8 = 24, S9 = 25, S10 = 26, S11 = 27, T3 = 28, T4 = 29, T5 = 30, T6 = 31;
// FP registers
- static final int F0 = 32, F1 = 33, F2 = 34, F3 = 35, F4 = 36, F5 = 37, F6 = 38, F7 = 39;
- static final int FS0 = 40, FS1 = 41, FA0 = 42, FA1 = 43, FA2 = 44, FA3 = 45, FA4 = 46, FA5 = 47;
- static final int FA6 = 48, FA7 = 49, FS2 = 50, FS3 = 51, FS4 = 52, FS5 = 53, FS6 = 54, FS7 = 55;
- static final int FS8 = 56, FS9 = 57, FS10 = 58, FS11 = 59, FT8 = 60, FT9 = 61, FT10 = 62, FT11 = 63;
+ static int F0 = 32, F1 = 33, F2 = 34, F3 = 35, F4 = 36, F5 = 37, F6 = 38, F7 = 39;
+ static int FS0 = 40, FS1 = 41, FA0 = 42, FA1 = 43, FA2 = 44, FA3 = 45, FA4 = 46, FA5 = 47;
+ static int FA6 = 48, FA7 = 49, FS2 = 50, FS3 = 51, FS4 = 52, FS5 = 53, FS6 = 54, FS7 = 55;
+ static int FS8 = 56, FS9 = 57, FS10 = 58, FS11 = 59, FT8 = 60, FT9 = 61, FT10 = 62, FT11 = 63;
static final int MAX_REG = 61;
+ static final int F_OFFSET = 31;
+
static final String[] REGS = new String[] {
- "zero", "r1" , "rsp" , "r3" , "r4" , "r5" , "r6" , "r7" ,
- "r8" , "r9" , "r10" , "r11" , "r12" , "r13" , "r14" , "r15" ,
- "r16" , "r17" , "r18" , "r19" , "r20" , "r21" , "r22" , "r23" ,
- "r24" , "r25" , "r26" , "r27" , "r28" , "r29" , "r30" , "r31" ,
- "f0" , "f1" , "f2" , "f3" , "f4" , "f5" , "f6" , "f7" ,
- "fs0" , "fs1" , "fa0" , "fa1" , "fa2" , "fa3" , "fa4" , "fa5" ,
- "fa6" , "fa7" , "fs2" , "fs3" , "fs4" , "fs5" , "fs6" , "fs7" ,
- "fs8" , "fs9" , "fs10", "fs11", "ft8" , "ft9" , "ft10", "ft11"
+ "zero","rpc" , "sp" , "gp" , "tp" , "t0" , "t1" , "t2" ,
+ "s0" , "s1" , "a0" , "a1" , "a2" , "a3" , "a4" , "a5" ,
+ "a6" , "a7" , "s2" , "s3" , "s4" , "s5" , "s6" , "s7" ,
+ "s8" , "s9" , "s10" , "s11" , "t3" , "t4" , "t5" , "t6" ,
+ "f0" , "f1" , "f2" , "f3" , "f4" , "f5" , "f6" , "f7" ,
+ "fs0" , "fs1" , "fa0" , "fa1" , "fa2" , "fa3" , "fa4" , "fa5" ,
+ "fa6" , "fa7" , "fs2" , "fs3" , "fs4" , "fs5" , "fs6" , "fs7" ,
+ "fs8" , "fs9" , "fs10", "fs11", "ft8" , "ft9" , "ft10", "ft11"
};
- @Override public String reg( int reg ) {
- return reg < REGS.length ? REGS[reg] : "[rsp+"+(reg-REGS.length)*4+"]";
- }
-
// General purpose register mask: pointers and ints, not floats
static final long RD_BITS = 0b11111111111111111111111111111111L; // All the GPRs
@@ -56,26 +54,26 @@ public class riscv extends Machine {
// Arguments masks
- static final RegMask A0_MASK = new RegMask(A0);
- static final RegMask A1_MASK = new RegMask(A1);
- static final RegMask A2_MASK = new RegMask(A2);
- static final RegMask A3_MASK = new RegMask(A3);
- static final RegMask A4_MASK = new RegMask(A4);
- static final RegMask A5_MASK = new RegMask(A5);
- static final RegMask A6_MASK = new RegMask(A6);
- static final RegMask A7_MASK = new RegMask(A7);
+ public static RegMask A0_MASK = new RegMask(A0);
+ public static RegMask A1_MASK = new RegMask(A1);
+ public static RegMask A2_MASK = new RegMask(A2);
+ public static RegMask A3_MASK = new RegMask(A3);
+ public static RegMask A4_MASK = new RegMask(A4);
+ public static RegMask A5_MASK = new RegMask(A5);
+ public static RegMask A6_MASK = new RegMask(A6);
+ public static RegMask A7_MASK = new RegMask(A7);
static final RegMask RPC_MASK = new RegMask(RPC);
// Float arguments masks
- static final RegMask FA0_MASK = new RegMask(FA0);
- static final RegMask FA1_MASK = new RegMask(FA1);
- static final RegMask FA2_MASK = new RegMask(FA2);
- static final RegMask FA3_MASK = new RegMask(FA3);
- static final RegMask FA4_MASK = new RegMask(FA4);
- static final RegMask FA5_MASK = new RegMask(FA5);
- static final RegMask FA6_MASK = new RegMask(FA6);
- static final RegMask FA7_MASK = new RegMask(FA7);
+ public static RegMask FA0_MASK = new RegMask(FA0);
+ public static RegMask FA1_MASK = new RegMask(FA1);
+ public static RegMask FA2_MASK = new RegMask(FA2);
+ public static RegMask FA3_MASK = new RegMask(FA3);
+ public static RegMask FA4_MASK = new RegMask(FA4);
+ public static RegMask FA5_MASK = new RegMask(FA5);
+ public static RegMask FA6_MASK = new RegMask(FA6);
+ public static RegMask FA7_MASK = new RegMask(FA7);
// Int arguments calling conv
static RegMask[] CALLINMASK = new RegMask[] {
@@ -99,6 +97,128 @@ public class riscv extends Machine {
FA6_MASK,
FA7_MASK
};
+ //
+ // major opcode: OP
+ public static int OP = 0b01_100_11;
+ public static int OP_FP = 0b11_100_11;
+
+ //I_type opcode: 0010 0011
+ public static int I_TYPE = 0x13;
+
+ // 0110 0111
+ public static int I_JALR = 0x67;
+
+ // Since riscv instructions are fixed we can just or them togehter
+ public static int r_type(int opcode, int rd, int func3, int rs1, int rs2, int func7) {
+ return (func7 << 25) | (rs2 << 20) | (rs1 << 15) | (func3 << 12) | (rd << 7) | opcode;
+ }
+ public static void r_type(Encoding enc, Node n, int func3, int func7) {
+ short dst = enc.reg(n);
+ short src1 = enc.reg(n.in(1));
+ short src2 = enc.reg(n.in(2));
+ int body = r_type(OP,dst,func3,src1,src2,func7);
+ enc.add4(body);
+ }
+ public static void rf_type(Encoding enc, Node n, int opcode, RM func3, int func7) {
+ short dst = (short)(enc.reg(n )-F_OFFSET);
+ short src1 = (short)(enc.reg(n.in(1))-F_OFFSET);
+ short src2 = (short)(enc.reg(n.in(2))-F_OFFSET);
+ int body = r_type(OP_FP,dst,func3.ordinal(),src1,src2,func7);
+ enc.add4(body);
+ }
+
+
+ public static int u_type(int opcode, int rd, int imm20) {
+ return (imm20 << 12) | (rd << 7) | opcode;
+ }
+
+ public static int i_type(int opcode, int rd, int func3, int rs1, int imm12) {
+ assert opcode >= 0 && rd >=0 && func3 >=0 && rs1 >=0 && imm12 >= 0; // Zero-extend by caller
+ return (imm12 << 20) | (rs1 << 15) | (func3 << 12) | (rd << 7) | opcode;
+ }
+ //public static int i_type(int opcode, int rd, int func3, int rs1, int imm12) {
+ // return i_type(opcode,rd,func3,rs1,imm,0);
+ //}
+
+
+ // S-type instructions(store)
+ public static int s_type(int opcode, int offset1, int func3, int rs1, int rs2, int offset2) {
+ return (offset2 << 25) | (rs2 << 20) | (rs1 << 15) | (func3 << 12) | (offset1 << 7) | opcode;
+ }
+ public static int s_type(int opcode, int func3, int rs1, int rs2, int imm12) {
+ assert imm12 >= 0; // Masked to high zero bits by caller
+ int imm_lo = imm12 & 0x1F;
+ int imm_hi = imm12 >> 5;
+ return (imm_hi << 25) | (rs2 << 20) | (rs1 << 15) | (func3 << 12) | (imm_lo << 7) | opcode;
+ }
+
+ // immf = first imm
+ // immd = second imm
+ // BRANCH
+ public static int b_type(int opcode, int immf, int func3, int rs1, int rs2, int immd) {
+ return (immd << 25 ) | (rs2 << 20) | (rs1 << 15) | (func3 << 12) | (immf << 7) | opcode;
+ }
+
+ public enum RM {
+ RNE, // Round to Nearest, ties to Even
+ RTZ, // Round towards Zero
+ RDN, // Round Down
+ RUP, // Round Up
+ DIRECT, // Round to Nearest, ties to Max Magnitude
+ RESERVED1, // Reserved for futue use
+ RESERVED2, // Reserved for future use
+ DYN, // In instruction’s rm field, selects dynamic rounding mode; In Rounding Mode register, reserved
+ }
+
+ // seqz ( sltiu rd, rs, 1 ) - 0001 0011
+ static public int setop(String op) {
+ return switch(op) {
+ case "<" -> 0x33;
+ case "<=" -> 0x13;
+ case "==" -> 0x33;
+ default -> throw Utils.TODO();
+ };
+ }
+ // Since opcode is the same just return back func3
+ // BEQ: 01100011
+ // BLT: 01100011
+ // BLE: bge rt, rs, offset:
+ static public int jumpop(String op) {
+ return switch(op) {
+ case "<" -> 0x4;
+ case "<=" -> 0x5;
+ case "==" -> 0;
+ default -> throw Utils.TODO();
+ };
+ }
+
+ // Since opcode is the same just return back func3
+ static public int fsetop(String op) {
+ return switch(op) {
+ case "<" -> 1;
+ case "<=" -> 0;
+ case "==" -> 2;
+ default -> throw Utils.TODO();
+ };
+ }
+
+ public static void push_4_bytes(int value, ByteArrayOutputStream bytes) { throw Utils.TODO(); }
+
+// public static void print_as_hex(ByteArrayOutputStream outputStream) {
+// StringBuilder hexString = new StringBuilder();
+// for (byte b : outputStream.toByteArray()) {
+// hexString.append(String.format("%02X", b)); // Format as uppercase hex without space
+// }
+// System.out.println(hexString.toString());
+// }
+
+// // rs1 - rs2
+// public static int r_source(int rs1, int rs2) {
+// return (rs2 << 4) | rs1;
+// }
+// public static int r_func7(int f) {
+// return f & 7;
+// }
static RegMask callInMask( TypeFunPtr tfp, int idx ) {
if( idx==0 ) return RPC_MASK;
@@ -163,6 +283,9 @@ public class riscv extends Machine {
: RET_MASKS[i];
}
+ @Override public String reg( int reg ) {
+ return reg < REGS.length ? REGS[reg] : "[rsp+"+(reg-REGS.length)*4+"]";
+ }
// Return a MachNode unconditional branch
@Override public CFGNode jump() {
@@ -179,10 +302,16 @@ public class riscv extends Machine {
// True if signed 12-bit immediate
private static boolean imm12(TypeInteger ti) {
- // 64-12==52
+ // 52 = 64-12
return ti.isConstant() && ((ti.value()<<52)>>52) == ti.value();
}
-
+ // True if HIGH 20-bit signed immediate, with all zeros low.
+ static boolean imm20Exact(TypeInteger ti) {
+ // shift left 32 to clear out the upper 32 bits.
+ // shift right SIGNED to sign-extend upper 32 bits; then shift 12 more to clear out lower 12 bits.
+ // shift left 12 to re-center the bits.
+ return ti.isConstant() && (((ti.value()<<32)>>>44)<<12) == ti.value();
+ }
@Override public Node instSelect( Node n ) {
return switch (n) {
@@ -202,8 +331,9 @@ public class riscv extends Machine {
case LoadNode ld -> ld(ld);
case MemMergeNode mem -> new MemMergeNode(mem);
case MulFNode mulf -> new MulFRISC(mulf);
- case MulNode mul -> new MulRISC(mul);
- case NewNode nnn -> new NewRISC(nnn);
+ case MulNode mul -> mul(mul);
+ case NewNode nnn -> nnn(nnn);
+ case NotNode not -> new NotRISC(not);
case OrNode or -> or(or);
case ParmNode parm -> new ParmRISC(parm);
case PhiNode phi -> new PhiNode(phi);
@@ -244,24 +374,64 @@ public class riscv extends Machine {
}
private Node call(CallNode call) {
+ // Options here are:
+ // 4G range in 2ops and either PC-relative or absolute
+ // 4K range in 1op absolute
+ // Since 4K is too small, we're going with 4G PC-relative in 2 ops
if( call.fptr() instanceof ConstantNode con && con._con instanceof TypeFunPtr tfp )
- return new CallRISC(call, tfp);
+ return new CallRISC(call, tfp, new AUIPC(tfp));
return new CallRRISC(call);
}
+ private Node nnn(NewNode nnn) {
+ // TODO: pass in the TFP for alloc
+ return new NewRISC(nnn, new AUIPC((TypeFunPtr)null));
+ }
private Node cmp(BoolNode bool) {
- if( bool.in(2) instanceof ConstantNode off && off._con instanceof TypeInteger toff )
- return new SetIRISC(bool, (int)toff.value());
- // Float variant
+ // Float variant directly implemented in hardware
if( bool.isFloat() )
return new SetFRISC(bool);
- return new SetRISC(bool);
+
+ // Only < and <u are implemented in hardware.
+ // x < y - as-is
+ // x <= y - flip and invert; !(y < x); `slt tmp=y,x; xori dst=tmp,#1`
+ // x == y - sub and vs0 == `sub tmp=x-y; sltu dst=tmp,#1`
+
+ // x > y - swap; y < x
+ // x >= y - swap and invert; !(x < y); `slt tmp=y,x;` then NOT.
+ // x != y - sub and vs0 == `sub tmp=x-y; sltu dst=tmp,#1` then NOT.
+
+ // The ">", ">=" and "!=" in Simple include a NotNode, which can be
+ // implemented with a XOR. If one of the above is followed by a NOT
+ // we can remove the double XOR in the encodings.
+
+ return switch( bool.op() ) {
+ case "<" -> bool.in(2) instanceof ConstantNode con && con._con instanceof TypeInteger ti && imm12(ti)
+ ? new SetIRISC(bool, (int)ti.value(),false)
+ : new SetRISC(bool);
+ // x <= y - flip and invert; !(y < x); `slt tmp=y,x; xori dst=tmp,#1`
+ case "<=" -> new XorIRISC(new SetRISC(bool.swap12()),1);
+ // x == y - sub and vs0 == `sub tmp=x-y; sltu dst=tmp,#1`
+ case "==" -> new SetIRISC(new SubRISC(bool),1,true);
+ default -> throw Utils.TODO();
+ };
}
private Node con( ConstantNode con ) {
if( !con._con.isConstant() ) return new ConstantNode( con ); // Default unknown caller inputs
return switch( con._con ) {
- case TypeInteger ti -> new IntRISC(con);
+ case TypeInteger ti -> {
+ if( imm12(ti) ) yield new IntRISC(con);
+ if( imm20Exact(ti) ) yield new LUI(ti);
+ long x = ti.value();
+ if( (x<<32)>>32 == x ) // Signed lower 32-bit immediate
+ // Here, the low 12 bits get sign-extended, which means if
+ // bit11 is set, the value is negative and lowers the LUI
+ // value. Add a bit 12 to compensate
+ yield new AddIRISC(new LUI(((x>>12)&1)==1 ? TypeInteger.constant(x+0x1000) : ti), (int)(x & 0xFFF));
+ // Need more complex sequence for larger constants
+ throw Utils.TODO();
+ }
case TypeFloat tf -> new FltRISC(con);
case TypeFunPtr tfp -> new TFPRISC(con);
case TypeMemPtr tmp -> throw Utils.TODO();
@@ -272,44 +442,47 @@ public class riscv extends Machine {
}
private Node jmp( IfNode iff ) {
- if( iff.in(1) instanceof BoolNode bool && !bool.isFloat() )
+ if( iff.in(1) instanceof BoolNode bool && !bool.isFloat() ) {
+ // if less than or equal switch inputs
+ if (bool.op().equals("<=")) return new BranchRISC(iff, bool.op(), bool.in(2), bool.in(1));
return new BranchRISC(iff, bool.op(), bool.in(1), bool.in(2));
+ }
// Vs zero
return new BranchRISC(iff, "==", iff.in(1), null);
}
private Node or(OrNode or) {
- if( or.in(2) instanceof ConstantNode con && con._con instanceof TypeInteger ti && imm12(ti) )
+ if( or.in(2) instanceof ConstantNode con && con._con instanceof TypeInteger ti && imm12(ti) && imm12(ti) )
return new OrIRISC(or, (int)ti.value());
return new OrRISC(or);
}
private Node xor(XorNode xor) {
- if( xor.in(2) instanceof ConstantNode con && con._con instanceof TypeInteger ti && imm12(ti) )
+ if( xor.in(2) instanceof ConstantNode con && con._con instanceof TypeInteger ti && imm12(ti) && imm12(ti))
return new XorIRISC(xor, (int)ti.value());
return new XorRISC(xor);
}
private Node sra(SarNode sar) {
- if( sar.in(2) instanceof ConstantNode con && con._con instanceof TypeInteger ti && imm12(ti) )
+ if( sar.in(2) instanceof ConstantNode con && con._con instanceof TypeInteger ti && imm12(ti) && imm12(ti))
return new SraIRISC(sar, (int)ti.value());
return new SraRISC(sar);
}
private Node srl(ShrNode shr) {
- if( shr.in(2) instanceof ConstantNode con && con._con instanceof TypeInteger ti && imm12(ti) )
+ if( shr.in(2) instanceof ConstantNode con && con._con instanceof TypeInteger ti && imm12(ti) && imm12(ti))
return new SrlIRISC(shr, (int)ti.value());
return new SrlRISC(shr);
}
private Node sll(ShlNode sll) {
- if( sll.in(2) instanceof ConstantNode con && con._con instanceof TypeInteger ti && imm12(ti) )
+ if( sll.in(2) instanceof ConstantNode con && con._con instanceof TypeInteger ti && imm12(ti) && imm12(ti))
return new SllIRISC(sll, (int)ti.value());
return new SllRISC(sll);
}
private Node sub(SubNode sub) {
- return sub.in(2) instanceof ConstantNode con && con._con instanceof TypeInteger ti && imm12(ti)
+ return sub.in(2) instanceof ConstantNode con && con._con instanceof TypeInteger ti && imm12(ti) && imm12(ti)
? new AddIRISC(sub, (int)(-ti.value()))
: new SubRISC(sub);
}
@@ -323,29 +496,25 @@ public class riscv extends Machine {
return new ProjRISC(prj);
}
+ private Node mul(MulNode mul) {
+ return new MulRISC(mul);
+ }
+
private Node ld(LoadNode ld) {
- return new LoadRISC(address(ld),ld.ptr(),idx,off);
+ return new LoadRISC(address(ld),off);
}
private Node st(StoreNode st) {
- int imm=0;
- Node xval = st.val();
- if( xval instanceof ConstantNode con && con._con instanceof TypeInteger ti && imm12(ti) ) {
- xval = null;
- imm = (int)ti.value();
- assert imm == ti.value(); // In 32-bit range
- }
- return new StoreRISC(address(st),st.ptr(),idx,off,imm,xval);
+ Node xval = st.val() instanceof ConstantNode con && con._con == TypeInteger.ZERO ? null : st.val();
+ return new StoreRISC(address(st), off, xval);
}
// Gather addressing mode bits prior to constructing. This is a builder
// pattern, but saving the bits in a *local* *global* here to keep mess
// contained.
private static int off;
- private static Node idx;
private <N extends MemOpNode> N address( N mop ) {
off = 0; // Reset
- idx = null;
Node base = mop.ptr();
// Skip/throw-away a ReadOnly, only used to typecheck
if( base instanceof ReadOnlyNode read ) base = read.in(1);
@@ -353,7 +522,7 @@ public class riscv extends Machine {
if( mop.off() instanceof ConstantNode con && con._con instanceof TypeInteger ti && imm12(ti) ) {
off = (int)ti.value();
} else {
- idx = mop.off();
+ base = new AddRISC(base,mop.off());
}
return mop;
}
diff --git a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/AddFMemX86.java b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/AddFMemX86.java
index ffc6966e..9a38c990 100644
--- a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/AddFMemX86.java
+++ b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/AddFMemX86.java
@@ -2,15 +2,14 @@ package com.seaofnodes.simple.node.cpus.x86_64_v2;
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.*;
import com.seaofnodes.simple.node.*;
public class AddFMemX86 extends MemOpX86 {
AddFMemX86( AddFNode add, LoadNode ld , Node base, Node idx, int off, int scale, Node val ) {
super(add,ld, base, idx, off, scale, 0, val );
}
-
+ @Override public String op() { return "addf"+_sz; }
@Override public RegMask regmap(int i) {
if( i==1 ) return null; // Memory
if( i==2 ) return x86_64_v2.RMASK; // base
@@ -18,10 +17,21 @@ public class AddFMemX86 extends MemOpX86 {
if( i==4 ) return x86_64_v2.XMASK; // value
throw Utils.TODO();
}
-
- // Register mask allowed as a result. 0 for no register.
@Override public RegMask outregmap() { return x86_64_v2.XMASK; }
+ @Override public int twoAddress() { return 4; }
+ @Override public void encoding( Encoding enc ) {
+ // addsd xmm0, DWORD PTR [rdi+0xc]
+ short dst = enc.reg(this );
+ short ptr = enc.reg(ptr());
+ short idx = enc.reg(idx());
+ // F opcode
+ enc.add1(0xF2);
+ // FP ADD
+ enc.add1(0x0F);
+ enc.add1(0x58);
+ x86_64_v2.indirectAdr(_scale, idx, ptr, _off, dst, enc);
+ }
// General form: "add dst = src + [base + idx<<2 + 12]"
@Override public void asm(CodeGen code, SB sb) {
@@ -29,5 +39,4 @@ public class AddFMemX86 extends MemOpX86 {
sb.p(val()==null ? "#"+_imm : code.reg(val())).p(" + ");
asm_address(code,sb);
}
- @Override public String op() { return "addf"+_sz; }
}
diff --git a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/AddFX86.java b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/AddFX86.java
index d4ea9162..86b3b365 100644
--- a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/AddFX86.java
+++ b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/AddFX86.java
@@ -1,33 +1,32 @@
package com.seaofnodes.simple.node.cpus.x86_64_v2;
import com.seaofnodes.simple.*;
-import com.seaofnodes.simple.codegen.CodeGen;
-import com.seaofnodes.simple.codegen.RegMask;
+import com.seaofnodes.simple.codegen.*;
import com.seaofnodes.simple.node.*;
-import com.seaofnodes.simple.type.TypeInteger;
-import java.io.ByteArrayOutputStream;
public class AddFX86 extends MachConcreteNode implements MachNode {
AddFX86( Node addf ) { super(addf); }
-
- // Register mask allowed on input i.
+ @Override public String op() { return "addf"; }
@Override public RegMask regmap(int i) { assert i==1 || i==2; return x86_64_v2.XMASK; }
- // Register mask allowed as a result. 0 for no register.
@Override public RegMask outregmap() { return x86_64_v2.XMASK; }
- // Output is same register as input#1
@Override public int twoAddress() { return 1; }
- // Ok to swap arguments
@Override public boolean commutes() { return true; }
// Encoding is appended into the byte array; size is returned
- @Override public int encoding(ByteArrayOutputStream bytes) {
- throw Utils.TODO();
+ @Override public void encoding( Encoding enc ) {
+ // F2 0F 58 /r ADDSD xmm1, xmm2/m64
+ short dst = (short)(enc.reg(this ) - x86_64_v2.XMM_OFFSET);
+ short src = (short)(enc.reg(in(2)) - x86_64_v2.XMM_OFFSET);
+ enc.add1(x86_64_v2.rex(dst, src,0));
+ // Fopcode
+ enc.add1(0xF2);
+ enc.add1(0x0F);
+ enc.add1(0x58);
+ enc.add1(x86_64_v2.modrm(x86_64_v2.MOD.DIRECT, dst, src));
}
// General form: "addf dst += src"
@Override public void asm(CodeGen code, SB sb) {
sb.p(code.reg(this)).p(" = ").p(code.reg(in(1))).p(" + ").p(code.reg(in(2)));
}
-
- @Override public String op() { return "addf"; }
}
diff --git a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/AddIX86.java b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/AddIX86.java
index c7f92ff1..569be754 100644
--- a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/AddIX86.java
+++ b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/AddIX86.java
@@ -1,41 +1,13 @@
package com.seaofnodes.simple.node.cpus.x86_64_v2;
-import com.seaofnodes.simple.*;
-import com.seaofnodes.simple.codegen.CodeGen;
-import com.seaofnodes.simple.codegen.RegMask;
-import com.seaofnodes.simple.node.*;
-import com.seaofnodes.simple.type.TypeInteger;
-import java.io.ByteArrayOutputStream;
-
-public class AddIX86 extends MachConcreteNode implements MachNode {
- final TypeInteger _ti;
- AddIX86( Node add, TypeInteger ti ) {
- super(add);
- _inputs.pop();
- _ti = ti;
- }
-
- // Register mask allowed on input i.
- @Override public RegMask regmap(int i) {
- // assert i== i;
- return x86_64_v2.WMASK; }
- // Register mask allowed as a result. 0 for no register.
- @Override public RegMask outregmap() { return x86_64_v2.WMASK; }
- // Output is same register as input#1
- @Override public int twoAddress() { return 1; }
-
- // Encoding is appended into the byte array; size is returned
- @Override public int encoding(ByteArrayOutputStream bytes) {
- throw Utils.TODO();
- }
-
- // General form: "addi dst += #imm"
- @Override public void asm(CodeGen code, SB sb) {
- sb.p(code.reg(this)).p(" = ").p(code.reg(in(1))).p(" + #");
- _ti.print(sb);
- }
+import com.seaofnodes.simple.node.Node;
+public class AddIX86 extends ImmX86 {
+ AddIX86( Node add, int imm ) { super(add,imm); }
@Override public String op() {
- return _ti.value() == 1 ? "inc" : (_ti.value() == -1 ? "dec" : "addi");
+ return _imm == 1 ? "inc" : (_imm == -1 ? "dec" : "addi");
}
+ @Override public String glabel() { return "+"; }
+ @Override int opcode() { return 0x81; }
+ @Override int mod() { return 0; }
}
diff --git a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/AddMemX86.java b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/AddMemX86.java
index 3d4fac41..acf4d4b9 100644
--- a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/AddMemX86.java
+++ b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/AddMemX86.java
@@ -1,21 +1,30 @@
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.RegMask;
+import com.seaofnodes.simple.codegen.*;
import com.seaofnodes.simple.node.*;
public class AddMemX86 extends MemOpX86 {
AddMemX86( AddNode add, LoadNode ld , Node base, Node idx, int off, int scale, int imm, Node val ) {
super(add,ld, base, idx, off, scale, imm, val );
}
-
@Override public String op() { return "add"+_sz; }
-
- // Register mask allowed as a result. 0 for no register.
@Override public RegMask outregmap() { return x86_64_v2.WMASK; }
- // Output is same register as val()
@Override public int twoAddress() { return 4; }
+ @Override public void encoding( Encoding enc ) {
+ // add something to register from memory
+ // add eax,DWORD PTR [rdi+0xc]
+ // REX.W + 03 /r ADD r64, r/m64
+ short dst = enc.reg(this );
+ short ptr = enc.reg(ptr());
+ short idx = enc.reg(idx());
+
+ enc.add1(x86_64_v2.rex(dst, ptr, idx));
+ // opcode
+ enc.add1(0x03);
+
+ x86_64_v2.indirectAdr(_scale, idx, ptr, _off, dst, enc);
+ }
// General form: "add dst = src + [base + idx<<2 + 12]"
@Override public void asm(CodeGen code, SB sb) {
diff --git a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/AddX86.java b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/AddX86.java
index 9553d499..84543e8f 100644
--- a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/AddX86.java
+++ b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/AddX86.java
@@ -1,33 +1,11 @@
package com.seaofnodes.simple.node.cpus.x86_64_v2;
-import com.seaofnodes.simple.*;
-import com.seaofnodes.simple.codegen.CodeGen;
-import com.seaofnodes.simple.codegen.RegMask;
-import com.seaofnodes.simple.node.*;
-import com.seaofnodes.simple.type.TypeInteger;
-import java.io.ByteArrayOutputStream;
+import com.seaofnodes.simple.node.Node;
-public class AddX86 extends MachConcreteNode {
+public class AddX86 extends RegX86 {
AddX86( Node add ) { super(add); }
-
- // Register mask allowed on input i.
- @Override public RegMask regmap(int i) { assert i==1 || i==2; return x86_64_v2.RMASK; }
- // Register mask allowed as a result. 0 for no register.
- @Override public RegMask outregmap() { return x86_64_v2.WMASK; }
- // Output is same register as input#1
- @Override public int twoAddress() { return 1; }
- // Ok to swap arguments
- @Override public boolean commutes() { return true; }
-
- // Encoding is appended into the byte array; size is returned
- @Override public int encoding(ByteArrayOutputStream bytes) {
- throw Utils.TODO();
- }
-
- // General form: "add dst += src"
- @Override public void asm(CodeGen code, SB sb) {
- sb.p(code.reg(this)).p(" = ").p(code.reg(in(1))).p(" + ").p(code.reg(in(2)));
- }
-
@Override public String op() { return "add"; }
+ @Override public String glabel() { return "+"; }
+ @Override int opcode() { return 0x03; }
+ @Override public boolean commutes() { return true; }
}
diff --git a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/AndIX86.java b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/AndIX86.java
index a7f1801e..3c1b567c 100644
--- a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/AndIX86.java
+++ b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/AndIX86.java
@@ -1,44 +1,11 @@
package com.seaofnodes.simple.node.cpus.x86_64_v2;
-import com.seaofnodes.simple.*;
-import com.seaofnodes.simple.codegen.CodeGen;
-import com.seaofnodes.simple.codegen.RegMask;
-import com.seaofnodes.simple.node.*;
-import com.seaofnodes.simple.type.Type;
-import com.seaofnodes.simple.type.TypeInteger;
-import java.io.ByteArrayOutputStream;
-import java.util.BitSet;
-import java.lang.StringBuilder;
-
-public class AndIX86 extends MachConcreteNode implements MachNode {
- final TypeInteger _ti;
- AndIX86(Node and, TypeInteger ti) {
- super(and);
- _inputs.pop();
- _ti = ti;
- }
-
- // Register mask allowed on input i.
- // This is the normal calling convention
- @Override public RegMask regmap(int i) { assert i==1; return x86_64_v2.WMASK; }
- // Register mask allowed as a result. 0 for no register.
- @Override public RegMask outregmap() { return x86_64_v2.WMASK; }
-
-
- // Output is same register as input#1
- @Override public int twoAddress() { return 1; }
-
- // Encoding is appended into the byte array; size is returned
- @Override public int encoding(ByteArrayOutputStream bytes) {
- throw Utils.TODO();
- }
-
- // General form
- // General form: "andi dst & #imm"
- @Override public void asm(CodeGen code, SB sb) {
- sb.p(code.reg(this)).p(" = ").p(code.reg(in(1))).p(" & #");
- _ti.print(sb);
- }
+import com.seaofnodes.simple.node.Node;
+public class AndIX86 extends ImmX86 {
+ AndIX86( Node add, int imm ) { super(add,imm); }
@Override public String op() { return "andi"; }
+ @Override public String glabel() { return "&"; }
+ @Override int opcode() { return 0x81; }
+ @Override int mod() { return 4; }
}
diff --git a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/AndX86.java b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/AndX86.java
index 24a88846..dedbce45 100644
--- a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/AndX86.java
+++ b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/AndX86.java
@@ -1,31 +1,11 @@
package com.seaofnodes.simple.node.cpus.x86_64_v2;
-import com.seaofnodes.simple.*;
-import com.seaofnodes.simple.codegen.CodeGen;
-import com.seaofnodes.simple.codegen.RegMask;
-import com.seaofnodes.simple.node.*;
-import java.io.ByteArrayOutputStream;
+import com.seaofnodes.simple.node.Node;
-public class AndX86 extends MachConcreteNode implements MachNode {
- AndX86(Node and) { super(and); }
- // Register mask allowed on input i.
- // This is the normal calling convention
- @Override public RegMask regmap(int i) { assert i==1; return x86_64_v2.WMASK; }
-
- @Override public RegMask outregmap() { return x86_64_v2.WMASK; }
-
- // Output is same register as input#1
- @Override public int twoAddress() { return 1; }
-
- // Encoding is appended into the byte array; size is returned
- @Override public int encoding(ByteArrayOutputStream bytes) {
- throw Utils.TODO();
- }
-
- // General form
- // General form: "and dst & src"
- @Override public void asm(CodeGen code, SB sb) {
- sb.p(code.reg(this)).p(" = ").p(code.reg(in(1))).p(" & ").p(code.reg(in(2)));;
- }
+public class AndX86 extends RegX86 {
+ AndX86( Node add ) { super(add); }
@Override public String op() { return "and"; }
+ @Override public String glabel() { return "&"; }
+ @Override int opcode() { return 0x23; }
+ @Override public boolean commutes() { return true; }
}
diff --git a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/CallEndX86.java b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/CallEndX86.java
index b9cc5659..2bb589a1 100644
--- a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/CallEndX86.java
+++ b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/CallEndX86.java
@@ -1,14 +1,10 @@
package com.seaofnodes.simple.node.cpus.x86_64_v2;
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.*;
import com.seaofnodes.simple.node.CallEndNode;
import com.seaofnodes.simple.node.MachNode;
-import com.seaofnodes.simple.type.TypeFloat;
import com.seaofnodes.simple.type.TypeFunPtr;
-import java.io.ByteArrayOutputStream;
public class CallEndX86 extends CallEndNode implements MachNode {
final TypeFunPtr _tfp;
@@ -16,20 +12,12 @@ public class CallEndX86 extends CallEndNode implements MachNode {
super(cend);
_tfp = (TypeFunPtr)(cend.call().fptr()._type);
}
-
+ @Override public String op() { return "cend"; }
@Override public String label() { return op(); }
@Override public RegMask regmap(int i) { return null; }
@Override public RegMask outregmap() { return null; }
@Override public RegMask outregmap(int idx) { return idx == 2 ? x86_64_v2.retMask(_tfp,2) : null; }
@Override public RegMask killmap() { return x86_64_v2.x86CallerSave(); }
-
- // Encoding is appended into the byte array; size is returned
- @Override public int encoding(ByteArrayOutputStream bytes) {
- throw Utils.TODO();
- }
-
+ @Override public void encoding( Encoding enc ) { }
@Override public void asm(CodeGen code, SB sb) { }
-
- @Override public String op() { return "cend"; }
-
}
diff --git a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/CallRX86.java b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/CallRX86.java
index ec6f9993..4eac27a8 100644
--- a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/CallRX86.java
+++ b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/CallRX86.java
@@ -1,16 +1,13 @@
package com.seaofnodes.simple.node.cpus.x86_64_v2;
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.*;
import com.seaofnodes.simple.node.CallNode;
import com.seaofnodes.simple.node.MachNode;
-import java.io.ByteArrayOutputStream;
public class CallRX86 extends CallNode implements MachNode {
CallRX86( CallNode call ) { super(call); }
-
+ @Override public String op() { return "callr"; }
@Override public String label() { return op(); }
@Override public RegMask regmap(int i) {
return i==_inputs._len
@@ -18,10 +15,11 @@ public class CallRX86 extends CallNode implements MachNode {
: x86_64_v2.callInMask(tfp(),i); // Normal argument
}
@Override public RegMask outregmap() { return null; }
-
- // Encoding is appended into the byte array; size is returned
- @Override public int encoding(ByteArrayOutputStream bytes) {
- throw Utils.TODO();
+ @Override public void encoding( Encoding enc ) {
+ // 0xFF/2
+ short src = enc.reg(fptr());
+ enc.add1(0xFF);
+ enc.add1(x86_64_v2.modrm(x86_64_v2.MOD.INDIRECT,2,src));
}
@Override public void asm(CodeGen code, SB sb) {
@@ -31,5 +29,4 @@ public class CallRX86 extends CallNode implements MachNode {
sb.unchar(2);
}
- @Override public String op() { return "callr"; }
}
diff --git a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/CallX86.java b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/CallX86.java
index 959ec81e..bb5cf7bb 100644
--- a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/CallX86.java
+++ b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/CallX86.java
@@ -1,13 +1,12 @@
package com.seaofnodes.simple.node.cpus.x86_64_v2;
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.RegMask;
import com.seaofnodes.simple.node.CallNode;
import com.seaofnodes.simple.node.MachNode;
import com.seaofnodes.simple.type.TypeFunPtr;
-import java.io.ByteArrayOutputStream;
public class CallX86 extends CallNode implements MachNode {
final TypeFunPtr _tfp;
@@ -19,20 +18,19 @@ public class CallX86 extends CallNode implements MachNode {
_tfp = tfp;
_name = CodeGen.CODE.link(tfp)._name;
}
-
+ @Override public String op() { return "call"; }
@Override public String label() { return op(); }
- @Override public RegMask regmap(int i) {
- return x86_64_v2.callInMask(_tfp,i); // Normal argument
- }
- @Override public RegMask outregmap() { return null; }
- @Override public int nargs() { return nIns()-2; } // Minus control, memory, fptr
-
@Override public String name() { return _name; }
@Override public TypeFunPtr tfp() { return _tfp; }
+ @Override public RegMask regmap(int i) { return x86_64_v2.callInMask(_tfp,i); }
+ @Override public RegMask outregmap() { return null; }
+ @Override public int nargs() { return nIns()-2; } // Minus control, memory, fptr
// Encoding is appended into the byte array; size is returned
- @Override public int encoding(ByteArrayOutputStream bytes) {
- throw Utils.TODO();
+ @Override public void encoding( Encoding enc ) {
+ enc.relo(this,_tfp);
+ enc.add1(0xe8);
+ enc.add4(0); // Target patched at link time
}
@Override public void asm(CodeGen code, SB sb) {
@@ -41,7 +39,4 @@ public class CallX86 extends CallNode implements MachNode {
sb.p(code.reg(in(i+2))).p(" ");
sb.unchar(2);
}
-
- @Override public String op() { return "call"; }
-
}
diff --git a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/CastX86.java b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/CastX86.java
index b620b89c..9537cfb3 100644
--- a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/CastX86.java
+++ b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/CastX86.java
@@ -1,18 +1,16 @@
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.RegMask;
+import com.seaofnodes.simple.codegen.*;
import com.seaofnodes.simple.node.CastNode;
import com.seaofnodes.simple.node.MachNode;
-import java.io.ByteArrayOutputStream;
public class CastX86 extends CastNode implements MachNode {
CastX86( CastNode cast ) { super(cast); }
+ @Override public String op() { return label(); }
@Override public RegMask regmap(int i) { assert i==1; return RegMask.FULL; }
@Override public RegMask outregmap() { return RegMask.FULL; }
@Override public int twoAddress( ) { return 1; }
- @Override public int encoding(ByteArrayOutputStream bytes) { return 0; /*no encoding*/ }
+ @Override public void encoding( Encoding enc ) { }
@Override public void asm(CodeGen code, SB sb) { _t.print(sb.p(code.reg(in(1))).p(" isa ")); }
- @Override public String op() { return label(); }
}
diff --git a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/CmpFX86.java b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/CmpFX86.java
index e9b0dacd..31c03ccf 100644
--- a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/CmpFX86.java
+++ b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/CmpFX86.java
@@ -1,21 +1,25 @@
package com.seaofnodes.simple.node.cpus.x86_64_v2;
import com.seaofnodes.simple.*;
-import com.seaofnodes.simple.codegen.CodeGen;
-import com.seaofnodes.simple.codegen.RegMask;
+import com.seaofnodes.simple.codegen.*;
import com.seaofnodes.simple.node.*;
-import com.seaofnodes.simple.type.TypeInteger;
-import java.io.ByteArrayOutputStream;
public class CmpFX86 extends MachConcreteNode implements MachNode {
CmpFX86( Node cmp ) { super(cmp); }
-
- @Override public RegMask regmap(int i) { assert i==1 || i==2; return x86_64_v2.XMASK; }
+ @Override public String op() { return "cmpf"; }
+ @Override public RegMask regmap(int i) { return x86_64_v2.XMASK; }
@Override public RegMask outregmap() { return x86_64_v2.FLAGS_MASK; }
// Encoding is appended into the byte array; size is returned
- @Override public int encoding(ByteArrayOutputStream bytes) {
- throw Utils.TODO();
+ @Override public void encoding( Encoding enc ) {
+ short src1 = (short)(enc.reg(in(1)) - x86_64_v2.XMM_OFFSET);
+ short src2 = (short)(enc.reg(in(2)) - x86_64_v2.XMM_OFFSET);
+ enc.add1(x86_64_v2.rex(src1, src2, 0));
+ // float opcode
+ enc.add1(0x66);
+ enc.add1(0x0F);
+ enc.add1(0x2E);
+ enc.add1(x86_64_v2.modrm(x86_64_v2.MOD.DIRECT, src1, src2));
}
// General form: "cmp src1,src2"
@@ -24,6 +28,4 @@ public class CmpFX86 extends MachConcreteNode implements MachNode {
if( dst!="flags" ) sb.p(dst).p(" = ");
sb.p(code.reg(in(1))).p(", ").p(code.reg(in(2)));
}
-
- @Override public String op() { return "cmpf"; }
}
diff --git a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/CmpIX86.java b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/CmpIX86.java
index fcba397d..5b992581 100644
--- a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/CmpIX86.java
+++ b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/CmpIX86.java
@@ -1,53 +1,21 @@
package com.seaofnodes.simple.node.cpus.x86_64_v2;
-import com.seaofnodes.simple.*;
-import com.seaofnodes.simple.codegen.CodeGen;
-import com.seaofnodes.simple.codegen.RegMask;
-import com.seaofnodes.simple.node.*;
-import com.seaofnodes.simple.type.Type;
-import com.seaofnodes.simple.type.TypeInteger;
-import java.io.ByteArrayOutputStream;
+import com.seaofnodes.simple.SB;
+import com.seaofnodes.simple.codegen.*;
+import com.seaofnodes.simple.node.Node;
// Compare immediate. Sets flags.
-public class CmpIX86 extends MachConcreteNode implements MachNode {
- final int _imm;
- final String _bop;
- CmpIX86( BoolNode bool, TypeInteger ti ) {
- super(bool);
- _inputs.pop(); // Toss ideal ConstantNode away, embedded into machine op
- _bop = bool.op(); // One of <,<=,==
- _imm = (int)ti.value();
- assert _imm == ti.value();
- }
- // Copy constructor does not set reverse edges in, because the basic block
- // is changing from the original node - and it must be properly placed in a
- // new block.
- CmpIX86( CmpIX86 cmp ) {
- super(cmp);
- _bop = cmp._bop;
- _imm = cmp._imm;
- // While in(0) will be handled by the caller, all other edges must be
- // handled in the constructor.
- cmp.in(1)._outputs.push(this);
- }
-
- @Override public RegMask regmap(int i) { assert i==1; return x86_64_v2.RMASK; }
+public class CmpIX86 extends ImmX86 {
+ CmpIX86( Node add, int imm ) { super(add,imm); }
+ @Override public String op() { return _imm==0 ? "test" : "cmp"; }
@Override public RegMask outregmap() { return x86_64_v2.FLAGS_MASK; }
- @Override public boolean isClone() { return true; }
- @Override public Node copy() { return new CmpIX86(this); }
-
- // Encoding is appended into the byte array; size is returned
- @Override public int encoding(ByteArrayOutputStream bytes) {
- throw Utils.TODO();
- }
-
+ @Override public int twoAddress() { return 0; }
+ @Override int opcode() { return 0x81; }
+ @Override int mod() { return 7; }
@Override public void asm(CodeGen code, SB sb) {
String dst = code.reg(this);
if( dst!="flags" ) sb.p(dst).p(" = ");
sb.p(code.reg(in(1)));
if( _imm != 0 ) sb.p(", #").p(_imm);
}
-
- @Override public String op() { return _imm==0 ? "test" : "cmp"; }
-
}
diff --git a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/CmpMemX86.java b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/CmpMemX86.java
index f9ace702..b6aa5e97 100644
--- a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/CmpMemX86.java
+++ b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/CmpMemX86.java
@@ -1,24 +1,37 @@
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.RegMask;
+import com.seaofnodes.simple.codegen.*;
import com.seaofnodes.simple.node.*;
public class CmpMemX86 extends MemOpX86 {
final boolean _invert; // Op switched LHS, RHS
- CmpMemX86( BoolNode bool, LoadNode ld , Node base, Node idx, int off, int scale, int imm, Node val, boolean invert ) {
+ CmpMemX86( BoolNode bool, LoadNode ld, Node base, Node idx, int off, int scale, int imm, Node val, boolean invert ) {
super(bool,ld, base, idx, off, scale, imm, val );
_invert = invert;
}
-
- // Register mask allowed as a result. 0 for no register.
+ @Override public String op() { return ((val()==null && _imm==0) ? "test" : "cmp") + _sz; }
@Override public RegMask outregmap() { return x86_64_v2.FLAGS_MASK; }
+ @Override public void encoding( Encoding enc ) {
+ // REX.W + 81 /7 id CMP r/m64, imm32 | REX.W + 39 /r CMP r/m64,r64
+ // CMP [mem], imm32
+ short ptr = enc.reg(ptr());
+ short idx = enc.reg(idx());
+ short src = enc.reg(val());
+
+ enc.add1(x86_64_v2.rex(src, ptr, idx));
+ // opcode varies by immediate
+ enc.add1( src == -1 ? 0x39 : 0x81 );
+
+ // includes modrm
+ x86_64_v2.indirectAdr(_scale, idx, ptr, _off, src == -1 ? 7 : src, enc);
+ if( src == -1 ) enc.add4(_imm);
+ }
// General form: "cmp dst = src, [base + idx<<2 + 12]"
@Override public void asm(CodeGen code, SB sb) {
String dst = code.reg(this);
- if( dst!="FLAGS" ) sb.p(dst).p(" = ");
+ if( dst!="flags" ) sb.p(dst).p(" = ");
if( _invert ) asm_address(code,sb).p(",");
if( val()==null ) {
if( _imm!=0 ) sb.p("#").p(_imm);
@@ -27,7 +40,4 @@ public class CmpMemX86 extends MemOpX86 {
}
if( !_invert ) asm_address(code,sb.p(", "));
}
-
- @Override public String op() { return ((val()==null && _imm==0) ? "test" : "cmp") + _sz; }
-
}
diff --git a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/CmpX86.java b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/CmpX86.java
index 41ce33d2..ca3ef758 100644
--- a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/CmpX86.java
+++ b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/CmpX86.java
@@ -1,29 +1,17 @@
package com.seaofnodes.simple.node.cpus.x86_64_v2;
-import com.seaofnodes.simple.*;
-import com.seaofnodes.simple.codegen.CodeGen;
-import com.seaofnodes.simple.codegen.RegMask;
-import com.seaofnodes.simple.node.*;
-import com.seaofnodes.simple.type.TypeInteger;
-import java.io.ByteArrayOutputStream;
+import com.seaofnodes.simple.SB;
+import com.seaofnodes.simple.codegen.*;
+import com.seaofnodes.simple.node.Node;
-public class CmpX86 extends MachConcreteNode implements MachNode {
- CmpX86( Node cmp ) { super(cmp); }
-
- @Override public RegMask regmap(int i) { assert i==1 || i==2; return x86_64_v2.RMASK; }
+public class CmpX86 extends RegX86 {
+ CmpX86( Node add ) { super(add); }
+ @Override public String op() { return "cmp"; }
+ @Override int opcode() { return 0x3B; }
@Override public RegMask outregmap() { return x86_64_v2.FLAGS_MASK; }
-
- // Encoding is appended into the byte array; size is returned
- @Override public int encoding(ByteArrayOutputStream bytes) {
- throw Utils.TODO();
- }
-
- // General form: "add dst += src"
@Override public void asm(CodeGen code, SB sb) {
String dst = code.reg(this);
- if( dst!="FLAGS" ) sb.p(dst).p(" = ");
+ if( dst!="flags" ) sb.p(dst).p(" = ");
sb.p(code.reg(in(1))).p(", ").p(code.reg(in(2)));
}
-
- @Override public String op() { return "cmp"; }
}
diff --git a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/DivFX86.java b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/DivFX86.java
index f74b7348..bfd57b34 100644
--- a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/DivFX86.java
+++ b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/DivFX86.java
@@ -1,25 +1,29 @@
package com.seaofnodes.simple.node.cpus.x86_64_v2;
import com.seaofnodes.simple.*;
-import com.seaofnodes.simple.codegen.CodeGen;
-import com.seaofnodes.simple.codegen.RegMask;
+import com.seaofnodes.simple.codegen.*;
import com.seaofnodes.simple.node.*;
-import com.seaofnodes.simple.type.TypeInteger;
-import java.io.ByteArrayOutputStream;
public class DivFX86 extends MachConcreteNode implements MachNode {
DivFX86( Node divf) { super(divf); }
-
- // Register mask allowed on input i.
- @Override public RegMask regmap(int i) { assert i==1 || i==2; return x86_64_v2.XMASK; }
- // Register mask allowed as a result. 0 for no register.
- @Override public RegMask outregmap() { return x86_64_v2.XMASK; }
- // Output is same register as input#1
+ @Override public String op() { return "divf"; }
+ @Override public RegMask regmap(int i) { return x86_64_v2.XMASK; }
+ @Override public RegMask outregmap() { return x86_64_v2.XMASK; }
@Override public int twoAddress() { return 1; }
// Encoding is appended into the byte array; size is returned
- @Override public int encoding(ByteArrayOutputStream bytes) {
- throw Utils.TODO();
+ @Override public void encoding( Encoding enc ) {
+ // F2 0F 5E /r DIVSD xmm1, xmm2/m64
+ short dst = (short)(enc.reg(this ) - x86_64_v2.XMM_OFFSET);
+ short src = (short)(enc.reg(in(2)) - x86_64_v2.XMM_OFFSET);
+ enc.add1(x86_64_v2.rex(dst, src, 0));
+
+ // Fopcode
+ enc.add1(0xF2);
+ enc.add1(0x0F);
+ enc.add1(0x5E);
+
+ enc.add1(x86_64_v2.modrm(x86_64_v2.MOD.DIRECT, dst, src));
}
@@ -27,9 +31,4 @@ public class DivFX86 extends MachConcreteNode implements MachNode {
@Override public void asm(CodeGen code, SB sb) {
sb.p(code.reg(this)).p(" = ").p(code.reg(in(1))).p(" / ").p(code.reg(in(2)));
}
-
- @Override public String op() {
- // 8 bytes = 64 bits
- return "divf";
- }
}
diff --git a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/DivX86.java b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/DivX86.java
index 54372629..87b8b0c3 100644
--- a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/DivX86.java
+++ b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/DivX86.java
@@ -1,35 +1,33 @@
package com.seaofnodes.simple.node.cpus.x86_64_v2;
import com.seaofnodes.simple.*;
-import com.seaofnodes.simple.codegen.CodeGen;
-import com.seaofnodes.simple.codegen.RegMask;
+import com.seaofnodes.simple.codegen.*;
import com.seaofnodes.simple.node.*;
-import com.seaofnodes.simple.type.TypeInteger;
-import java.io.ByteArrayOutputStream;
public class DivX86 extends MachConcreteNode implements MachNode {
DivX86( Node div ) { super(div); }
-
- // Register mask allowed on input i.
+ @Override public String op() { return "div"; }
@Override public RegMask regmap(int i) {
return (i==1) ? x86_64_v2.RAX_MASK : x86_64_v2.RMASK;
}
- // Register mask allowed as a result. 0 for no register.
@Override public RegMask outregmap() { return x86_64_v2.RAX_MASK; }
-
- // DIV encodes a CQO which sign extends RAX into RDX, killing RDX.
@Override public RegMask killmap() { return x86_64_v2.RDX_MASK; }
- // Encoding is appended into the byte array; size is returned
- @Override public int encoding(ByteArrayOutputStream bytes) {
- throw Utils.TODO();
+ @Override public void encoding( Encoding enc ) {
+ // REX.W + F7 /7 IDIV r/m64
+ short src = enc.reg(in(2));
+ // sign extend rax before 128/64 bits division
+ // sign extend rax to rdx:rax
+ enc.add1(x86_64_v2.REX_W);
+ enc.add1(0x99);
+ enc.add1(x86_64_v2.rex(0, src, 0));
+ // divide
+ enc.add1(0xF7); // opcode
+ enc.add1(x86_64_v2.modrm(x86_64_v2.MOD.DIRECT, 0x07, src));
}
-
// General form: "div dst /= src"
@Override public void asm(CodeGen code, SB sb) {
sb.p(code.reg(this)).p(" = ").p(code.reg(in(1))).p(" / ").p(code.reg(in(2)));
}
-
- @Override public String op() { return "div"; }
@Override public String comment() { return "kill rdx"; }
}
diff --git a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/FltX86.java b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/FltX86.java
index 47f7149d..5c4002e1 100644
--- a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/FltX86.java
+++ b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/FltX86.java
@@ -1,35 +1,37 @@
package com.seaofnodes.simple.node.cpus.x86_64_v2;
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.node.ConstantNode;
-import com.seaofnodes.simple.node.MachNode;
-import java.io.ByteArrayOutputStream;
+import com.seaofnodes.simple.codegen.*;
+import com.seaofnodes.simple.node.*;
public class FltX86 extends ConstantNode implements MachNode {
FltX86(ConstantNode con ) { super(con); }
@Override public String op() { return "fld"; }
-
- // Register mask allowed on input i. 0 for no register.
@Override public RegMask regmap(int i) { return null; }
- // General int registers
@Override public RegMask outregmap() { return x86_64_v2.XMASK; }
@Override public boolean isClone() { return true; }
- @Override public FltX86 copy() { return new FltX86(this); }
+ @Override public Node copy() { return new FltX86(this); }
// Encoding is appended into the byte array; size is returned
- @Override public int encoding(ByteArrayOutputStream bytes) {
- throw Utils.TODO();
+ @Override public void encoding( Encoding enc ) {
+ enc.largeConstant(this,_con);
+ // Simply move the constant into a FPR
+ // movsd xmm, [rip + 0]
+ // F2 0F 10 /r MOVSD xmm1, m64
+ short dst = (short)(enc.reg(this ) - x86_64_v2.XMM_OFFSET);
+ enc.add1(x86_64_v2.rex(dst, 0, 0));
+
+ // Fopcode
+ enc.add1(0xF2);
+ enc.add1(0x0F);
+ enc.add1(0x10);
+
+ // hard-code rip here
+ enc.add1(x86_64_v2.modrm(x86_64_v2.MOD.INDIRECT, dst, 0x05));
+ enc.add4(0);
}
- // Human-readable form appended to the SB. Things like the encoding,
- // indentation, leading address or block labels not printed here.
- // Just something like "ld4\tR17=[R18+12] // Load array base".
- // General form: "op\tdst=src+src"
@Override public void asm(CodeGen code, SB sb) {
_con.print(sb.p(code.reg(this)).p(" #"));
}
-
}
diff --git a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/FunX86.java b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/FunX86.java
index 5239670b..120053fa 100644
--- a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/FunX86.java
+++ b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/FunX86.java
@@ -1,22 +1,13 @@
package com.seaofnodes.simple.node.cpus.x86_64_v2;
-import com.seaofnodes.simple.codegen.CodeGen;
+import com.seaofnodes.simple.codegen.Encoding;
import com.seaofnodes.simple.codegen.RegMask;
-import com.seaofnodes.simple.Utils;
import com.seaofnodes.simple.node.FunNode;
import com.seaofnodes.simple.node.MachNode;
-import java.io.ByteArrayOutputStream;
public class FunX86 extends FunNode implements MachNode {
FunX86( FunNode fun ) { super(fun); }
-
- // Register mask allowed on input i. 0 for no register.
@Override public RegMask regmap(int i) { return null; }
- // Register mask allowed as a result. 0 for no register.
@Override public RegMask outregmap() { return null; }
-
- // Encoding is appended into the byte array; size is returned
- @Override public int encoding(ByteArrayOutputStream bytes) {
- throw Utils.TODO();
- }
+ @Override public void encoding( Encoding enc ) { }
}
diff --git a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/I2f8X86.java b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/I2f8X86.java
index d99c92a8..22134ac4 100644
--- a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/I2f8X86.java
+++ b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/I2f8X86.java
@@ -1,30 +1,31 @@
package com.seaofnodes.simple.node.cpus.x86_64_v2;
import com.seaofnodes.simple.*;
-import com.seaofnodes.simple.codegen.CodeGen;
-import com.seaofnodes.simple.codegen.RegMask;
+import com.seaofnodes.simple.codegen.*;
import com.seaofnodes.simple.node.*;
-import com.seaofnodes.simple.type.TypeInteger;
-import java.io.ByteArrayOutputStream;
public class I2f8X86 extends MachConcreteNode implements MachNode {
I2f8X86(Node i2f8 ) { super(i2f8); }
-
- // Register mask allowed on input i.
+ @Override public String op() { return "cvtf"; }
@Override public RegMask regmap(int i) { assert i==1; return x86_64_v2.WMASK; }
- // Register mask allowed as a result. 0 for no register.
@Override public RegMask outregmap() { return x86_64_v2.XMASK; }
// Encoding is appended into the byte array; size is returned
- @Override public int encoding(ByteArrayOutputStream bytes) {
- throw Utils.TODO();
- }
+ @Override public void encoding( Encoding enc ) {
+ // F2 0F 2A /r CVTSI2SD xmm1, r32/m32
+ short dst = (short)(enc.reg(this ) - x86_64_v2.XMM_OFFSET);
+ short src = enc.reg(in(1));
- // General form: "i2f8 (flt)int_value"
+ // Fopcode
+ enc.add1(0xF2);
+ enc.add1(x86_64_v2.rex(dst, src, 0));
+ enc.add1(0x0F);
+ enc.add1(0x2A);
+
+ enc.add1(x86_64_v2.modrm(x86_64_v2.MOD.DIRECT, dst, src));
+ }
@Override public void asm(CodeGen code, SB sb) {
sb.p(code.reg(this)).p(" = ").p("(flt)").p(code.reg(in(1)));
}
-
- @Override public String op() { return "i2f8"; }
}
diff --git a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/ImmX86.java b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/ImmX86.java
new file mode 100644
index 00000000..e3285d55
--- /dev/null
+++ b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/ImmX86.java
@@ -0,0 +1,38 @@
+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;
+
+public abstract class ImmX86 extends MachConcreteNode implements MachNode {
+ final int _imm;
+ ImmX86( Node add, int imm ) {
+ super(add);
+ _inputs.pop(); // Pop constant input off
+ _imm = imm;
+ }
+ @Override public RegMask regmap(int i) { return x86_64_v2.RMASK; }
+ @Override public RegMask outregmap() { return x86_64_v2.WMASK; }
+ @Override public int twoAddress() { return 1; }
+
+ abstract int opcode();
+ abstract int mod();
+
+ // Encoding is appended into the byte array; size is returned
+ @Override public final void encoding( Encoding enc ) {
+ short dst = enc.reg(this); // Also src1
+ enc.add1(x86_64_v2.rex(0, dst, 0));
+ // opcode; 0x81 or 0x83; 0x69 or 0x6B
+ enc.add1( opcode() + (x86_64_v2.imm8(_imm) ? 2 : 0) );
+ enc.add1( x86_64_v2.modrm(x86_64_v2.MOD.DIRECT, mod(), dst) );
+ // immediate(4 bytes) 32 bits or (1 byte)8 bits
+ if( x86_64_v2.imm8(_imm) ) enc.add1(_imm);
+ else enc.add4(_imm);
+ }
+
+ // General form: "addi dst += #imm"
+ @Override public void asm(CodeGen code, SB sb) {
+ sb.p(code.reg(this)).p(" ").p(glabel()).p("= #").p(_imm);
+ }
+}
diff --git a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/IntX86.java b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/IntX86.java
index fcd39e3f..d9836e00 100644
--- a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/IntX86.java
+++ b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/IntX86.java
@@ -1,40 +1,52 @@
package com.seaofnodes.simple.node.cpus.x86_64_v2;
import com.seaofnodes.simple.*;
-import com.seaofnodes.simple.codegen.CodeGen;
-import com.seaofnodes.simple.codegen.RegMask;
-import com.seaofnodes.simple.node.ConstantNode;
-import com.seaofnodes.simple.node.MachNode;
-import com.seaofnodes.simple.node.Node;
+import com.seaofnodes.simple.codegen.*;
+import com.seaofnodes.simple.node.*;
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeInteger;
-import java.io.ByteArrayOutputStream;
-
// Integer constants
public class IntX86 extends ConstantNode implements MachNode {
IntX86( ConstantNode con ) { super(con); }
-
@Override public String op() {
return _con == Type.NIL || _con == TypeInteger.ZERO ? "xor" : "ldi";
}
-
- // Register mask allowed on input i. 0 for no register.
+ @Override public boolean isClone() { return true; }
+ @Override public Node copy() { return new IntX86(this); }
@Override public RegMask regmap(int i) { return null; }
- // General int registers
@Override public RegMask outregmap() { return x86_64_v2.WMASK; }
-
// Zero-set uses XOR kills flags
@Override public RegMask killmap() {
return _con == Type.NIL || _con == TypeInteger.ZERO ? x86_64_v2.FLAGS_MASK : null;
}
- @Override public boolean isClone() { return true; }
- @Override public Node copy() { return new IntX86(this); }
-
- // Encoding is appended into the byte array; size is returned
- @Override public int encoding(ByteArrayOutputStream bytes) {
- throw Utils.TODO();
+ @Override public void encoding( Encoding enc ) {
+ short dst = enc.reg(this);
+ // Short form for zero
+ if( _con==Type.NIL || _con==TypeInteger.ZERO ) {
+ // XOR dst,dst. Can skip REX is dst is low 8, makes this a 32b
+ // xor, which will also zero the high bits.
+ if( dst >= 8 ) enc.add1(x86_64_v2.rex(dst, dst, 0));
+ enc.add1(0x33); // opcode
+ enc.add1(x86_64_v2.modrm(x86_64_v2.MOD.DIRECT, dst, dst));
+ return;
+ }
+
+ // Simply move the constant into a GPR
+ // Conditional encoding based on 64 or 32 bits
+ //REX.W + C7 /0 id MOV r/m64, imm32
+ enc.add1(x86_64_v2.rex(0, dst, 0));
+
+ long imm = ((TypeInteger)_con).value();
+ if( (int)imm == imm ) {
+ enc.add1(0xC7); // 32 bits encoding
+ enc.add1(x86_64_v2.modrm(x86_64_v2.MOD.DIRECT, 0x00, dst));
+ enc.add4((int)imm);
+ } else {
+ enc.add1(0xB8 + (dst & 0x07));
+ enc.add8(imm); // 64 bits encoding
+ }
}
// Human-readable form appended to the SB. Things like the encoding,
diff --git a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/JmpX86.java b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/JmpX86.java
index 0f6c8fa7..5790d294 100644
--- a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/JmpX86.java
+++ b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/JmpX86.java
@@ -1,21 +1,18 @@
package com.seaofnodes.simple.node.cpus.x86_64_v2;
import com.seaofnodes.simple.*;
-import com.seaofnodes.simple.codegen.CodeGen;
-import com.seaofnodes.simple.codegen.RegMask;
+import com.seaofnodes.simple.codegen.*;
import com.seaofnodes.simple.node.*;
-import com.seaofnodes.simple.type.Type;
-import com.seaofnodes.simple.type.TypeInteger;
-import java.io.ByteArrayOutputStream;
// Jump on flags, uses flags
public class JmpX86 extends IfNode implements MachNode {
- String _bop;
+ final String _bop;
JmpX86( IfNode iff, String bop ) {
super(iff);
_bop = bop;
}
+ @Override public String op() { return "j"+_bop; }
@Override public String label() { return op(); }
@Override public void postSelect() {
@@ -31,20 +28,20 @@ public class JmpX86 extends IfNode implements MachNode {
@Override public RegMask outregmap() { return null; }
// Encoding is appended into the byte array; size is returned
- @Override public int encoding(ByteArrayOutputStream bytes) {
- throw Utils.TODO();
+ @Override public void encoding( Encoding enc ) {
+ enc.jump(this,cproj(0));
+ // common opcode
+ enc.add1(0x0F);
+ enc.add1(x86_64_v2.jumpop(_bop));
+ enc.add4(0); // Offset patched later
}
@Override public void asm(CodeGen code, SB sb) {
String src = code.reg(in(1));
- if( src!="flags" ) sb.p(src);
- }
-
- @Override public String op() { return "j"+_bop; }
-
- @Override public String comment() {
- return "L"+cproj(1)._nid+", L"+cproj(0)._nid;
+ if( src!="flags" ) sb.p(src);
+ Node prj = cproj(0);
+ sb.p(prj instanceof LoopNode ? "LOOP" : "L").p(prj._nid);
}
- @Override public void invert() { _bop = invert(_bop); }
+ @Override public String comment() { return "L"+cproj(1)._nid; }
}
diff --git a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/LeaX86.java b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/LeaX86.java
index 229c0151..e4d63133 100644
--- a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/LeaX86.java
+++ b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/LeaX86.java
@@ -1,18 +1,15 @@
package com.seaofnodes.simple.node.cpus.x86_64_v2;
import com.seaofnodes.simple.*;
-import com.seaofnodes.simple.codegen.CodeGen;
-import com.seaofnodes.simple.codegen.RegMask;
+import com.seaofnodes.simple.codegen.*;
import com.seaofnodes.simple.node.*;
-import com.seaofnodes.simple.type.TypeInteger;
-import java.io.ByteArrayOutputStream;
public class LeaX86 extends MachConcreteNode implements MachNode {
final int _scale;
- final long _offset;
- LeaX86( Node add, Node base, Node idx, int scale, long offset ) {
+ final int _offset;
+ LeaX86( Node add, Node base, Node idx, int scale, int offset ) {
super(add);
- assert scale==1 || scale==2 || scale==4 || scale==8;
+ assert scale==0 || scale==1 || scale==2 || scale==3;
_inputs.pop();
_inputs.pop();
_inputs.push(base);
@@ -21,14 +18,31 @@ public class LeaX86 extends MachConcreteNode implements MachNode {
_offset = offset;
}
- // Register mask allowed on input i.
+ @Override public String op() { return "lea"; }
@Override public RegMask regmap(int i) { assert i==1 || i==2; return x86_64_v2.RMASK; }
- // Register mask allowed as a result. 0 for no register.
@Override public RegMask outregmap() { return x86_64_v2.WMASK; }
// Encoding is appended into the byte array; size is returned
- @Override public int encoding(ByteArrayOutputStream bytes) {
- throw Utils.TODO();
+ @Override public void encoding( Encoding enc ) {
+ // REX.W + 8D /r LEA r64,m
+ short dst = enc.reg(this);
+ short ptr = enc.reg(in(1));
+ short idx = enc.reg(in(2));
+ // ptr is null
+ // just do: [(index * s) + disp32]
+ if( ptr == -1 ) {
+ enc.add1(x86_64_v2.rex(dst, 0, idx));
+ enc.add1(0x8D); // opcode
+ enc.add1(x86_64_v2.modrm(x86_64_v2.MOD.INDIRECT, dst, 0x04));
+ enc.add1(x86_64_v2.sib(_scale, idx, x86_64_v2.RBP));
+ enc.add4(_offset);
+ return;
+ }
+
+ enc.add1(x86_64_v2.rex(dst, ptr, idx));
+ enc.add1(0x8D); // opcode
+ // rsp is hard-coded here(0x04)
+ x86_64_v2.indirectAdr(_scale, idx, ptr, _offset, dst, enc);
}
// General form: "lea dst = base + 4*idx + 12"
@@ -39,6 +53,4 @@ public class LeaX86 extends MachConcreteNode implements MachNode {
sb.p(code.reg(in(2))).p("*").p(_scale);
if( _offset!=0 ) sb.p(" + #").p(_offset);
}
-
- @Override public String op() { return "lea"; }
}
diff --git a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/LoadX86.java b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/LoadX86.java
index 893772a6..39525ed1 100644
--- a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/LoadX86.java
+++ b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/LoadX86.java
@@ -1,8 +1,7 @@
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.RegMask;
+import com.seaofnodes.simple.codegen.*;
import com.seaofnodes.simple.node.LoadNode;
import com.seaofnodes.simple.node.Node;
@@ -10,12 +9,19 @@ public class LoadX86 extends MemOpX86 {
LoadX86( LoadNode ld, Node base, Node idx, int off, int scale ) {
super(ld,ld, base, idx, off, scale, 0);
}
-
@Override public String op() { return "ld"+_sz; }
-
- // Register mask allowed as a result. 0 for no register.
@Override public RegMask outregmap() { return x86_64_v2.MEM_MASK; }
+ @Override public void encoding( Encoding enc ) {
+ // REX.W + 8B /r MOV r64, r/m64
+ short dst = enc.reg(this );
+ short ptr = enc.reg(ptr());
+ short idx = enc.reg(idx());
+ enc.add1(x86_64_v2.rex(dst, ptr, idx));
+ enc.add1(0x8B); // opcode
+ // includes modrm internally
+ x86_64_v2.indirectAdr(_scale, idx, ptr, _off, dst, enc);
+ }
// General form: "ldN dst,[base + idx<<2 + 12]"
@Override public void asm(CodeGen code, SB sb) {
diff --git a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/MemAddX86.java b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/MemAddX86.java
index 6d39a2b4..906d0ce9 100644
--- a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/MemAddX86.java
+++ b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/MemAddX86.java
@@ -1,19 +1,34 @@
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.RegMask;
+import com.seaofnodes.simple.codegen.*;
import com.seaofnodes.simple.node.*;
public class MemAddX86 extends MemOpX86 {
MemAddX86( StoreNode st, Node base, Node idx, int off, int scale, int imm, Node val ) {
super(st, st, base, idx, off, scale, imm, val );
}
-
+ @Override public String op() {
+ return (_imm == 1 ? "inc" : (_imm == -1 ? "dec" : "add")) + _sz;
+ }
// Register mask allowed as a result. 0 for no register.
@Override public RegMask outregmap() { return null; }
+ @Override public void encoding( Encoding enc ) {
+ // add something to memory
+ // REX.W + 01 /r | REX.W + 81 /0 id
+ // ADD [mem], imm32/reg
+ short ptr = enc.reg(ptr());
+ short idx = enc.reg(idx());
+ short src = enc.reg(val());
+ enc.add1(x86_64_v2.rex(src, ptr, idx));
+ // opcode
+ enc.add1( src == -1 ? 0x01 : 0x81 );
+ // includes modrm
+ x86_64_v2.indirectAdr(_scale, idx, ptr, _off, src == -1 ? 0 : src, enc);
+ if( src == -1 ) enc.add4(_imm);
+ }
// General form: "add [base + idx<<2 + 12] += src"
@Override public void asm(CodeGen code, SB sb) {
asm_address(code,sb);
@@ -21,8 +36,4 @@ public class MemAddX86 extends MemOpX86 {
if( _imm != 1 && _imm != -1 ) sb.p(" += #").p(_imm);
} else sb.p(" += ").p(code.reg(val()));
}
-
- @Override public String op() {
- return (_imm == 1 ? "inc" : (_imm == -1 ? "dec" : "add")) + _sz;
- }
}
diff --git a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/MemOpX86.java b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/MemOpX86.java
index dee4afd4..b1992ff7 100644
--- a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/MemOpX86.java
+++ b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/MemOpX86.java
@@ -1,11 +1,10 @@
package com.seaofnodes.simple.node.cpus.x86_64_v2;
import com.seaofnodes.simple.*;
-import com.seaofnodes.simple.codegen.CodeGen;
-import com.seaofnodes.simple.codegen.RegMask;
+import com.seaofnodes.simple.codegen.*;
import com.seaofnodes.simple.node.*;
import com.seaofnodes.simple.type.*;
-import java.io.ByteArrayOutputStream;
+
import java.lang.StringBuilder;
import java.util.BitSet;
@@ -70,9 +69,6 @@ public abstract class MemOpX86 extends MemOpNode implements MachNode {
throw Utils.TODO();
}
- @Override public int encoding(ByteArrayOutputStream bytes) { throw Utils.TODO(); }
-
-
// "[base + idx<<2 + 12]"
SB asm_address(CodeGen code, SB sb) {
sb.p("[").p(code.reg(ptr()));
diff --git a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/MulFX86.java b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/MulFX86.java
index 9e996130..bac84140 100644
--- a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/MulFX86.java
+++ b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/MulFX86.java
@@ -1,34 +1,34 @@
package com.seaofnodes.simple.node.cpus.x86_64_v2;
import com.seaofnodes.simple.*;
-import com.seaofnodes.simple.codegen.CodeGen;
-import com.seaofnodes.simple.codegen.RegMask;
+import com.seaofnodes.simple.codegen.*;
import com.seaofnodes.simple.node.*;
-import com.seaofnodes.simple.type.TypeFloat;
-import com.seaofnodes.simple.type.TypeInteger;
-import java.io.ByteArrayOutputStream;
public class MulFX86 extends MachConcreteNode implements MachNode {
MulFX86( Node mulf) { super(mulf); }
-
- // Register mask allowed on input i.
+ @Override public String op() { return "mulf"; }
@Override public RegMask regmap(int i) { assert i==1 || i==2; return x86_64_v2.XMASK; }
- // Register mask allowed as a result. 0 for no register.
@Override public RegMask outregmap() { return x86_64_v2.XMASK; }
- // Output is same register as input#1
@Override public int twoAddress() { return 1; }
- // Ok to swap arguments
@Override public boolean commutes() { return true; }
// Encoding is appended into the byte array; size is returned
- @Override public int encoding(ByteArrayOutputStream bytes) {
- throw Utils.TODO();
+ @Override public void encoding( Encoding enc ) {
+ // F2 0F 59 /r MULSD xmm1,xmm2/m64
+ short dst = (short)(enc.reg(this ) - x86_64_v2.XMM_OFFSET);
+ short src = (short)(enc.reg(in(2)) - x86_64_v2.XMM_OFFSET);
+ enc.add1(x86_64_v2.rex(dst, src, 0));
+
+ // Fopcode
+ enc.add1(0xF2);
+ enc.add1(0x0F);
+ enc.add1(0x59);
+
+ enc.add1(x86_64_v2.modrm(x86_64_v2.MOD.DIRECT, dst, src));
}
// General form: "mulf dst *= src"
@Override public void asm(CodeGen code, SB sb) {
sb.p(code.reg(this)).p(" = ").p(code.reg(in(1))).p(" * ").p(code.reg(in(2)));
}
-
- @Override public String op() { return "mulf"; }
}
diff --git a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/MulIX86.java b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/MulIX86.java
index b41a5720..a9a83fb7 100644
--- a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/MulIX86.java
+++ b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/MulIX86.java
@@ -1,41 +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.CodeGen;
-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.type.TypeInteger;
-import java.io.ByteArrayOutputStream;
-
-public class MulIX86 extends MachConcreteNode implements MachNode {
- final TypeInteger _ti;
- MulIX86(Node mul, TypeInteger ti) {super(mul); _inputs.pop(); _ti = ti;}
-
- // Register mask allowed on input i.
- // This is the normal calling convention
- @Override public RegMask regmap(int i) {
- // assert i==1;
- return x86_64_v2.WMASK; }
- // Register mask allowed as a result. 0 for no register.
- @Override public RegMask outregmap() { return x86_64_v2.WMASK; }
-
-
- // Output is same register as input#1
- @Override public int twoAddress() { return 1; }
-
- // Encoding is appended into the byte array; size is returned
- @Override public int encoding(ByteArrayOutputStream bytes) {
- throw Utils.TODO();
- }
- // General form
- // General form: "muli dst * #imm"
- @Override public void asm(CodeGen code, SB sb) {
- sb.p(code.reg(this)).p(" = ").p(code.reg(in(1))).p(" * #");
- _ti.print(sb);
- }
+public class MulIX86 extends ImmX86 {
+ MulIX86( Node add, int imm ) { super(add,imm); }
@Override public String op() { return "muli"; }
+ @Override public String glabel() { return "*"; }
+ @Override int opcode() { return 0x69; }
+ @Override int mod() { return 0; }
}
diff --git a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/MulX86.java b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/MulX86.java
index d880208e..8800f159 100644
--- a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/MulX86.java
+++ b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/MulX86.java
@@ -1,33 +1,30 @@
package com.seaofnodes.simple.node.cpus.x86_64_v2;
import com.seaofnodes.simple.*;
-import com.seaofnodes.simple.codegen.CodeGen;
-import com.seaofnodes.simple.codegen.RegMask;
+import com.seaofnodes.simple.codegen.*;
import com.seaofnodes.simple.node.*;
-import com.seaofnodes.simple.type.TypeInteger;
-import java.io.ByteArrayOutputStream;
public class MulX86 extends MachConcreteNode implements MachNode {
MulX86( Node mul ) { super(mul); }
-
- // Register mask allowed on input i.
+ @Override public String op() { return "mul"; }
@Override public RegMask regmap(int i) { assert i==1 || i==2; return x86_64_v2.RMASK; }
- // Register mask allowed as a result. 0 for no register.
@Override public RegMask outregmap() { return x86_64_v2.WMASK; }
- // Output is same register as input#1
@Override public int twoAddress() { return 1; }
- // Ok to swap arguments
@Override public boolean commutes() { return true; }
// Encoding is appended into the byte array; size is returned
- @Override public int encoding(ByteArrayOutputStream bytes) {
- throw Utils.TODO();
+ @Override public void encoding( Encoding enc ) {
+ // REX.W + 0F AF /r IMUL r64, r/m64
+ short dst = enc.reg(this ); // src1
+ short src = enc.reg(in(2)); // src2
+ enc.add1(x86_64_v2.rex(dst, src, 0));
+ enc.add1(0x0F); // opcode
+ enc.add1(0xAF); // opcode
+ enc.add1(x86_64_v2.modrm(x86_64_v2.MOD.DIRECT, dst, src));
}
// General form: "mul dst *= src"
@Override public void asm(CodeGen code, SB sb) {
sb.p(code.reg(this)).p(" = ").p(code.reg(in(1))).p(" * ").p(code.reg(in(2)));
}
-
- @Override public String op() { return "mul"; }
}
diff --git a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/NewX86.java b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/NewX86.java
index cd47c64b..ea05e14c 100644
--- a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/NewX86.java
+++ b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/NewX86.java
@@ -2,22 +2,27 @@ package com.seaofnodes.simple.node.cpus.x86_64_v2;
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.*;
-import java.io.ByteArrayOutputStream;
public class NewX86 extends NewNode implements MachNode {
// A pre-zeroed chunk of memory.
NewX86( NewNode nnn ) { super(nnn); }
+ @Override public String op() { return "alloc"; }
// Size and pointer result in standard calling convention; null for all the
// memory aliases edges
@Override public RegMask regmap(int i) { return i == 1 ? x86_64_v2.RDI_MASK : null; }
@Override public RegMask outregmap(int i) { return i == 1 ? x86_64_v2.RAX_MASK : null; }
@Override public RegMask outregmap() { return null; }
+ @Override public RegMask killmap() { return x86_64_v2.x86CallerSave(); }
// Encoding is appended into the byte array; size is returned
- @Override public int encoding(ByteArrayOutputStream bytes) {
- throw Utils.TODO();
+ @Override public void encoding( Encoding enc ) {
+ enc.relo(this);
+ // E8 cd CALL rel32;
+ enc.add1(0xE8);
+ enc.add4(0); // offset
}
// General form: "alloc #bytes"
@@ -25,5 +30,4 @@ public class NewX86 extends NewNode implements MachNode {
sb.p(code.reg(size()));
}
- @Override public String op() { return "alloc"; }
}
diff --git a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/NotX86.java b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/NotX86.java
new file mode 100644
index 00000000..b23249b8
--- /dev/null
+++ b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/NotX86.java
@@ -0,0 +1,39 @@
+package com.seaofnodes.simple.node.cpus.x86_64_v2;
+
+import com.seaofnodes.simple.SB;
+import com.seaofnodes.simple.codegen.*;
+import com.seaofnodes.simple.node.*;
+
+public class NotX86 extends MachConcreteNode implements MachNode {
+ NotX86(NotNode not) { super(not); }
+ @Override public String op() { return "not"; }
+ @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 void encoding( Encoding enc ) {
+ assert !(in(1) instanceof NotNode); // Cleared out by peeps
+ assert !(in(1) instanceof BoolNode); // Cleared out by peeps
+ short dst = enc.reg(this );
+ short src = enc.reg(in(1));
+
+ // Pre-zero using XOR dst,dst; since zero'd will not have a
+ // byte-dependency from the setz. Can skip REX is dst is low 8, makes
+ // this a 32b xor, which will also zero the high bits.
+ if( dst >= 8 ) enc.add1(x86_64_v2.rex(dst, dst, 0));
+ enc.add1(0x33); // opcode
+ enc.add1(x86_64_v2.modrm(x86_64_v2.MOD.DIRECT, dst, dst));
+
+ // test rdi,rdi
+ enc.add1(x86_64_v2.rex(src, src, 0));
+ enc.add1(0x85);
+ enc.add1(x86_64_v2.modrm(x86_64_v2.MOD.DIRECT, src, src));
+
+ // setz (sete dil)
+ enc.add1(x86_64_v2.rex(dst, 0, 0));
+ enc.add1(0x0F);
+ enc.add1(0x94);
+ enc.add1(x86_64_v2.modrm(x86_64_v2.MOD.DIRECT, dst, 0));
+ }
+ @Override public void asm(CodeGen code, SB sb) { sb.p(code.reg(this)); }
+}
diff --git a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/OrIX86.java b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/OrIX86.java
index 949ac6c2..15f4824d 100644
--- a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/OrIX86.java
+++ b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/OrIX86.java
@@ -1,43 +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.CodeGen;
-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.type.TypeInteger;
-import java.io.ByteArrayOutputStream;
-
-public class OrIX86 extends MachConcreteNode implements MachNode {
-
- final TypeInteger _ti;
- OrIX86(Node or, TypeInteger ti) {super(or); _inputs.pop(); _ti = ti;}
-
- // Register mask allowed on input i.
- // This is the normal calling convention
- @Override public RegMask regmap(int i) {
- //assert i==1;
- return x86_64_v2.WMASK; }
- // Register mask allowed as a result. 0 for no register.
- @Override public RegMask outregmap() { return x86_64_v2.WMASK; }
-
-
- // Output is same register as input#1
- @Override public int twoAddress() { return 1; }
-
- // Encoding is appended into the byte array; size is returned
- @Override public int encoding(ByteArrayOutputStream bytes) {
- throw Utils.TODO();
- }
-
- // General form
- // General form: "ori ori | #imm"
- @Override public void asm(CodeGen code, SB sb) {
- sb.p(code.reg(this)).p(" = ").p(code.reg(in(1))).p(" | #");
- _ti.print(sb);
- }
+public class OrIX86 extends ImmX86 {
+ OrIX86( Node add, int imm ) { super(add,imm); }
@Override public String op() { return "ori"; }
+ @Override public String glabel() { return "|"; }
+ @Override int opcode() { return 0x81; }
+ @Override int mod() { return 1; }
}
diff --git a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/OrX86.java b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/OrX86.java
index 6d99fe3b..bc8f0ea8 100644
--- a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/OrX86.java
+++ b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/OrX86.java
@@ -1,35 +1,11 @@
package com.seaofnodes.simple.node.cpus.x86_64_v2;
-import com.seaofnodes.simple.*;
-import com.seaofnodes.simple.codegen.CodeGen;
-import com.seaofnodes.simple.codegen.RegMask;
-import com.seaofnodes.simple.node.*;
-import java.io.ByteArrayOutputStream;
-
-public class OrX86 extends MachConcreteNode implements MachNode{
- OrX86(Node or) {
- super(or);
- }
-
- // Register mask allowed on input i.
- // This is the normal calling convention
- @Override public RegMask regmap(int i) { assert i==1; return x86_64_v2.WMASK; }
-
- @Override public RegMask outregmap() { return x86_64_v2.WMASK; }
-
- // Output is same register as input#1
- @Override public int twoAddress() { return 1; }
-
- // Encoding is appended into the byte array; size is returned
- @Override public int encoding(ByteArrayOutputStream bytes) {
- throw Utils.TODO();
- }
-
- // General form
- // General form: "or dst | src"
- @Override public void asm(CodeGen code, SB sb) {
- sb.p(code.reg(this)).p(" = ").p(code.reg(in(1)));
- }
+import com.seaofnodes.simple.node.Node;
+public class OrX86 extends RegX86 {
+ OrX86( Node add ) { super(add); }
@Override public String op() { return "or"; }
+ @Override public String glabel() { return "|"; }
+ @Override int opcode() { return 0x0B; }
+ @Override public boolean commutes() { return true; }
}
diff --git a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/ParmX86.java b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/ParmX86.java
index 4d47f76d..7a6dbb13 100644
--- a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/ParmX86.java
+++ b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/ParmX86.java
@@ -1,12 +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.CodeGen;
+import com.seaofnodes.simple.codegen.Encoding;
import com.seaofnodes.simple.codegen.RegMask;
import com.seaofnodes.simple.node.MachNode;
import com.seaofnodes.simple.node.ParmNode;
-import java.io.ByteArrayOutputStream;
public class ParmX86 extends ParmNode implements MachNode {
final RegMask _rmask;
@@ -14,12 +11,7 @@ public class ParmX86 extends ParmNode implements MachNode {
super(parm);
_rmask = x86_64_v2.callInMask(fun().sig(),_idx);
}
-
- // Register mask allowed on input i. 0 for no register.
- @Override public RegMask regmap(int i) { return _rmask; }
- // Register mask allowed as a result. Calling convention register
+ @Override public RegMask regmap(int i) { return null; }
@Override public RegMask outregmap() { return _rmask; }
-
- // Encoding is appended into the byte array. Returns size
- @Override public int encoding(ByteArrayOutputStream bytes) { return 0; }
+ @Override public void encoding( Encoding enc ) { }
}
diff --git a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/ProjX86.java b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/ProjX86.java
index 40d8b6c2..046c7b4c 100644
--- a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/ProjX86.java
+++ b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/ProjX86.java
@@ -1,23 +1,15 @@
package com.seaofnodes.simple.node.cpus.x86_64_v2;
-import com.seaofnodes.simple.Utils;
+import com.seaofnodes.simple.codegen.Encoding;
import com.seaofnodes.simple.codegen.RegMask;
import com.seaofnodes.simple.node.MachNode;
import com.seaofnodes.simple.node.ProjNode;
-import java.io.ByteArrayOutputStream;
public class ProjX86 extends ProjNode implements MachNode {
ProjX86( ProjNode p ) { super(p); }
-
- // Register mask allowed on input i. 0 for no register.
@Override public RegMask regmap(int i) { return null; }
- // Register mask allowed as a result. 0 for no register.
@Override public RegMask outregmap() {
return ((MachNode)in(0)).outregmap(_idx);
}
-
- // Encoding is appended into the byte array; size is returned
- @Override public int encoding(ByteArrayOutputStream bytes) {
- throw Utils.TODO();
- }
+ @Override public void encoding( Encoding enc ) {}
}
diff --git a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/RegX86.java b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/RegX86.java
new file mode 100644
index 00000000..25064e37
--- /dev/null
+++ b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/RegX86.java
@@ -0,0 +1,25 @@
+package com.seaofnodes.simple.node.cpus.x86_64_v2;
+
+import com.seaofnodes.simple.*;
+import com.seaofnodes.simple.codegen.*;
+import com.seaofnodes.simple.node.*;
+
+public abstract class RegX86 extends MachConcreteNode {
+ RegX86( Node add ) { super(add); }
+ @Override public RegMask regmap(int i) { return x86_64_v2.RMASK; }
+ @Override public RegMask outregmap() { return x86_64_v2.WMASK; }
+ @Override public int twoAddress() { return 1; }
+ abstract int opcode();
+ @Override public void encoding( Encoding enc ) {
+ // REX.W + 01 /r
+ short dst = enc.reg(this ); // src1
+ short src = enc.reg(in(2)); // src2
+ enc.add1(x86_64_v2.rex(dst, src, 0));
+ enc.add1(opcode()); // opcode
+ enc.add1(x86_64_v2.modrm(x86_64_v2.MOD.DIRECT, dst, src));
+ }
+ // General form: "add dst += src"
+ @Override public void asm(CodeGen code, SB sb) {
+ sb.p(code.reg(this)).p(" ").p(glabel()).p("= ").p(code.reg(in(2)));
+ }
+}
diff --git a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/RetX86.java b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/RetX86.java
index cdb20fd4..1a08bb4c 100644
--- a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/RetX86.java
+++ b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/RetX86.java
@@ -1,35 +1,21 @@
package com.seaofnodes.simple.node.cpus.x86_64_v2;
import com.seaofnodes.simple.*;
-import com.seaofnodes.simple.codegen.CodeGen;
-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.type.TypeFloat;
-import java.io.ByteArrayOutputStream;
+import com.seaofnodes.simple.codegen.*;
+import com.seaofnodes.simple.node.*;
-// Return
public class RetX86 extends ReturnNode implements MachNode {
RetX86( ReturnNode ret, FunNode fun ) { super(ret, fun); fun.setRet(this); }
-
+ @Override public String op() { return "ret"; }
// Correct Nodes outside the normal edges
@Override public void postSelect() {
FunNode fun = (FunNode)rpc().in(0);
_fun = fun;
fun.setRet(this);
}
-
- // Register mask allowed on input i.
- // This is the normal calling convention
@Override public RegMask regmap(int i) { return x86_64_v2.retMask(_fun.sig(),i); }
- // Register mask allowed as a result. 0 for no register.
@Override public RegMask outregmap() { return null; }
-
- // Encoding is appended into the byte array; size is returned
- @Override public int encoding(ByteArrayOutputStream bytes) {
- throw Utils.TODO();
- }
+ @Override public void encoding( Encoding enc ) { enc.add1(0xC3); }
@Override public void asm(CodeGen code, SB sb) {
// Post code-gen, just print the "ret"
@@ -39,6 +25,4 @@ public class RetX86 extends ReturnNode implements MachNode {
for( int i=2; i<nIns(); i++ )
sb.p(code.reg(in(i))).p(" ");
}
-
- @Override public String op() { return "ret"; }
}
diff --git a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/SarIX86.java b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/SarIX86.java
index 9f942cc6..d6c977a5 100644
--- a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/SarIX86.java
+++ b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/SarIX86.java
@@ -1,39 +1,12 @@
package com.seaofnodes.simple.node.cpus.x86_64_v2;
-import com.seaofnodes.simple.*;
-import com.seaofnodes.simple.codegen.CodeGen;
-import com.seaofnodes.simple.codegen.RegMask;
-import com.seaofnodes.simple.node.*;
-import com.seaofnodes.simple.type.TypeInteger;
-import java.io.ByteArrayOutputStream;
+import com.seaofnodes.simple.node.Node;
// Arithmetic Right Shift
-public class SarIX86 extends MachConcreteNode implements MachNode {
- final TypeInteger _ti;
- SarIX86(Node sar, TypeInteger ti) {super(sar); _inputs.pop(); _ti = ti;}
-
- // Register mask allowed on input i.
- // This is the normal calling convention
- @Override public RegMask regmap(int i) {
- // assert i==1;
- return x86_64_v2.RMASK; }
- // Register mask allowed as a result. 0 for no register.
- @Override public RegMask outregmap() { return x86_64_v2.WMASK; }
-
- // Output is same register as input#1
- @Override public int twoAddress() { return 1; }
-
- // Encoding is appended into the byte array; size is returned
- @Override public int encoding(ByteArrayOutputStream bytes) {
- throw Utils.TODO();
- }
-
- // General form
- // General form: "sari dst << #imm"
- @Override public void asm(CodeGen code, SB sb) {
- sb.p(code.reg(this)).p(" = ").p(code.reg(in(1))).p(" >> #");
- _ti.print(sb);
- }
-
+public class SarIX86 extends ImmX86 {
+ SarIX86( Node add, int imm ) { super(add,imm); assert x86_64_v2.imm8(imm); }
@Override public String op() { return "sari"; }
+ @Override public String glabel() { return ">>"; }
+ @Override int opcode() { return 0xC1; }
+ @Override int mod() { return 7; }
}
diff --git a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/SarX86.java b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/SarX86.java
index ee7a2f56..b1be643c 100644
--- a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/SarX86.java
+++ b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/SarX86.java
@@ -1,41 +1,24 @@
package com.seaofnodes.simple.node.cpus.x86_64_v2;
-import com.seaofnodes.simple.*;
-import com.seaofnodes.simple.codegen.CodeGen;
-import com.seaofnodes.simple.codegen.RegMask;
-import com.seaofnodes.simple.node.*;
-import com.seaofnodes.simple.type.Type;
-import com.seaofnodes.simple.type.TypeInteger;
-import java.io.ByteArrayOutputStream;
-import java.util.BitSet;
-import java.lang.StringBuilder;
+import com.seaofnodes.simple.Utils;
+import com.seaofnodes.simple.codegen.*;
+import com.seaofnodes.simple.node.Node;
-
-public class SarX86 extends MachConcreteNode implements MachNode {
- SarX86(Node sar) { super(sar); }
-
- // Register mask allowed on input i.
- // This is the normal calling convention
+public class SarX86 extends RegX86 {
+ SarX86( Node add ) { super(add); }
+ @Override public String op() { return "sar"; }
+ @Override public String glabel() { return ">>"; }
@Override public RegMask regmap(int i) {
- if(i == 1) return x86_64_v2.WMASK;
- if(i == 2) return x86_64_v2.RCX_MASK;
- throw Utils.TODO();
- }
- // Register mask allowed as a result. 0 for no register.
- @Override public RegMask outregmap() { return x86_64_v2.WMASK; }
-
- // Output is same register as input#1
- @Override public int twoAddress() { return 1; }
-
- // Encoding is appended into the byte array; size is returned
- @Override public int encoding(ByteArrayOutputStream bytes) {
+ if (i == 1) return x86_64_v2.WMASK;
+ if (i == 2) return x86_64_v2.RCX_MASK;
throw Utils.TODO();
}
-
- // General form
- @Override public void asm(CodeGen code, SB sb) {
- sb.p(code.reg(this)).p(" >> ").p(code.reg(in(1)));
+ @Override int opcode() { return 0xD3; }
+ @Override public void encoding( Encoding enc ) {
+ short dst = enc.reg(this ); // src1
+ short src = enc.reg(in(2)); // src2
+ enc.add1(x86_64_v2.rex(0, dst, 0));
+ enc.add1(opcode()); // opcode
+ enc.add1(x86_64_v2.modrm(x86_64_v2.MOD.DIRECT, 7, dst));
}
-
- @Override public String op() { return "sar"; }
}
diff --git a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/SetX86.java b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/SetX86.java
index 53237538..1d8fa127 100644
--- a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/SetX86.java
+++ b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/SetX86.java
@@ -1,14 +1,9 @@
package com.seaofnodes.simple.node.cpus.x86_64_v2;
import com.seaofnodes.simple.*;
-import com.seaofnodes.simple.codegen.CodeGen;
-import com.seaofnodes.simple.codegen.RegMask;
+import com.seaofnodes.simple.codegen.*;
import com.seaofnodes.simple.node.*;
-import com.seaofnodes.simple.type.Type;
-import com.seaofnodes.simple.type.TypeInteger;
-import java.io.ByteArrayOutputStream;
-// Compare immediate. Sets flags.
// Corresponds to the x86 instruction "sete && setne".
// Use result of comparison without jump.
public class SetX86 extends MachConcreteNode implements MachNode {
@@ -21,13 +16,31 @@ public class SetX86 extends MachConcreteNode implements MachNode {
_inputs.push(cmp);
_bop = bop;
}
-
+ @Override public String op() { return "set"+_bop; }
@Override public RegMask regmap(int i) { assert i==1; return x86_64_v2.FLAGS_MASK; }
@Override public RegMask outregmap() { return x86_64_v2.WMASK; }
// Encoding is appended into the byte array; size is returned
- @Override public int encoding(ByteArrayOutputStream bytes) {
- throw Utils.TODO();
+ @Override public void encoding( Encoding enc ) {
+ // REX + 0F 94
+ short dst = enc.reg(this );
+
+ // Optional rex, for dst
+ if( dst >= 8 ) enc.add1(x86_64_v2.rex(0, dst, 0));
+ enc.add1(0x0F); // opcode
+ enc.add1(switch (_bop) {
+ case "==" -> 0x94; // SETE
+ case "<" -> 0x9C; // SETL
+ case "<=" -> 0X9E; // SETLE
+ default -> throw Utils.TODO();
+ });
+ enc.add1(x86_64_v2.modrm(x86_64_v2.MOD.DIRECT, 0, dst));
+
+ // low 8 bites are set, now zero extend for next instruction
+ if( dst >= 8 ) enc.add1(x86_64_v2.rex(0, dst, 0));
+ enc.add1(0x0F); // opcode
+ enc.add1(0xB6); // opcode
+ enc.add1(x86_64_v2.modrm(x86_64_v2.MOD.DIRECT, dst, dst));
}
@Override public void asm(CodeGen code, SB sb) {
@@ -35,7 +48,4 @@ public class SetX86 extends MachConcreteNode implements MachNode {
String src = code.reg(in(1));
if( src!="flags" ) sb.p(" = ").p(src);
}
-
- @Override public String op() { return "set"+_bop; }
-
}
diff --git a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/ShlIX86.java b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/ShlIX86.java
index c18007cd..35818a91 100644
--- a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/ShlIX86.java
+++ b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/ShlIX86.java
@@ -1,40 +1,11 @@
package com.seaofnodes.simple.node.cpus.x86_64_v2;
-import com.seaofnodes.simple.*;
-import com.seaofnodes.simple.codegen.CodeGen;
-import com.seaofnodes.simple.codegen.RegMask;
-import com.seaofnodes.simple.node.*;
-import com.seaofnodes.simple.type.Type;
-import com.seaofnodes.simple.type.TypeInteger;
-import java.io.ByteArrayOutputStream;
-import java.util.BitSet;
-
-public class ShlIX86 extends MachConcreteNode implements MachNode{
- final TypeInteger _ti;
- ShlIX86(Node shl, TypeInteger ti) {super(shl); _inputs.pop(); _ti = ti;}
-
- // Register mask allowed on input i.
- // This is the normal calling convention
- @Override public RegMask regmap(int i) {
- //assert i==1;
- return x86_64_v2.RMASK; }
- // Register mask allowed as a result. 0 for no register.
- @Override public RegMask outregmap() { return x86_64_v2.WMASK; }
-
- // Output is same register as input#1
- @Override public int twoAddress() { return 1; }
-
- // Encoding is appended into the byte array; size is returned
- @Override public int encoding(ByteArrayOutputStream bytes) {
- throw Utils.TODO();
- }
-
- // General form
- // General form: "shli dst << #imm"
- @Override public void asm(CodeGen code, SB sb) {
- sb.p(code.reg(this)).p(" = ").p(code.reg(in(1))).p(" << #");
- _ti.print(sb);
- }
+import com.seaofnodes.simple.node.Node;
+public class ShlIX86 extends ImmX86 {
+ ShlIX86( Node add, int imm ) { super(add,imm); }
@Override public String op() { return "shli"; }
+ @Override public String glabel() { return "<<"; }
+ @Override int opcode() { return 0xC1; }
+ @Override int mod() { return 4; }
}
diff --git a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/ShlX86.java b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/ShlX86.java
index a3de5347..9f358575 100644
--- a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/ShlX86.java
+++ b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/ShlX86.java
@@ -1,39 +1,24 @@
package com.seaofnodes.simple.node.cpus.x86_64_v2;
-import com.seaofnodes.simple.*;
-import com.seaofnodes.simple.codegen.CodeGen;
-import com.seaofnodes.simple.codegen.RegMask;
-import com.seaofnodes.simple.node.*;
-import java.io.ByteArrayOutputStream;
+import com.seaofnodes.simple.Utils;
+import com.seaofnodes.simple.codegen.*;
+import com.seaofnodes.simple.node.Node;
-public class ShlX86 extends MachConcreteNode implements MachNode {
- ShlX86(Node shl) { super(shl); };
-
- // Register mask allowed on input i.
- // This is the normal calling convention
-
- // CL register must be used for input(2)
+public class ShlX86 extends RegX86 {
+ ShlX86( Node add ) { super(add); }
+ @Override public String op() { return "shl"; }
+ @Override public String glabel() { return "<<"; }
@Override public RegMask regmap(int i) {
- if(i == 1) return x86_64_v2.WMASK;
- if(i == 2) return x86_64_v2.RCX_MASK;
+ if (i == 1) return x86_64_v2.WMASK;
+ if (i == 2) return x86_64_v2.RCX_MASK;
throw Utils.TODO();
}
-
- @Override public RegMask outregmap() { return x86_64_v2.WMASK; }
-
- // Output is same register as input#1
- @Override public int twoAddress() { return 1; }
-
- // Encoding is appended into the byte array; size is returned
- @Override public int encoding(ByteArrayOutputStream bytes) {
- throw Utils.TODO();
- }
-
- // General form
- // General form: "shl dst << src"
- @Override public void asm(CodeGen code, SB sb) {
- sb.p(code.reg(this)).p(" << ").p(code.reg(in(1)));
+ @Override int opcode() { return 0xD3; }
+ @Override public final void encoding( Encoding enc ) {
+ short dst = enc.reg(this ); // src1
+ short src = enc.reg(in(2)); // src2
+ enc.add1(x86_64_v2.rex(0, dst, 0));
+ enc.add1(opcode()); // opcode
+ enc.add1(x86_64_v2.modrm(x86_64_v2.MOD.DIRECT, 4, dst));
}
-
- @Override public String op() { return "shl"; }
}
diff --git a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/ShrIX86.java b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/ShrIX86.java
index d17ee734..0e96962b 100644
--- a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/ShrIX86.java
+++ b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/ShrIX86.java
@@ -1,41 +1,11 @@
package com.seaofnodes.simple.node.cpus.x86_64_v2;
-import com.seaofnodes.simple.*;
-import com.seaofnodes.simple.codegen.CodeGen;
-import com.seaofnodes.simple.codegen.RegMask;
-import com.seaofnodes.simple.node.*;
-import com.seaofnodes.simple.type.Type;
-import com.seaofnodes.simple.type.TypeInteger;
-import java.io.ByteArrayOutputStream;
-import java.util.BitSet;
-import java.lang.StringBuilder;
-
-public class ShrIX86 extends MachConcreteNode implements MachNode{
- final TypeInteger _ti;
- ShrIX86(Node shr, TypeInteger ti) {super(shr); _inputs.pop(); _ti = ti;}
-
- // Register mask allowed on input i.
- // This is the normal calling convention
- @Override public RegMask regmap(int i) {
- //assert i==1;
- return x86_64_v2.RMASK; }
- // Register mask allowed as a result. 0 for no register.
- @Override public RegMask outregmap() { return x86_64_v2.WMASK; }
-
- // Output is same register as input#1
- @Override public int twoAddress() { return 1; }
-
- // Encoding is appended into the byte array; size is returned
- @Override public int encoding(ByteArrayOutputStream bytes) {
- throw Utils.TODO();
- }
-
- // General form
- // General form: "shri dst >>> #imm"
- @Override public void asm(CodeGen code, SB sb) {
- sb.p(code.reg(this)).p(" = ").p(code.reg(in(1))).p(" >>> #");
- _ti.print(sb);
- }
+import com.seaofnodes.simple.node.Node;
+public class ShrIX86 extends ImmX86 {
+ ShrIX86( Node add, int imm ) { super(add,imm); }
@Override public String op() { return "shri"; }
+ @Override public String glabel() { return ">>>"; }
+ @Override int opcode() { return 0xC1; }
+ @Override int mod() { return 5; }
}
diff --git a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/ShrX86.java b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/ShrX86.java
index 757d9b8e..d869260f 100644
--- a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/ShrX86.java
+++ b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/ShrX86.java
@@ -1,40 +1,24 @@
package com.seaofnodes.simple.node.cpus.x86_64_v2;
-import com.seaofnodes.simple.*;
-import com.seaofnodes.simple.codegen.CodeGen;
-import com.seaofnodes.simple.codegen.RegMask;
-import com.seaofnodes.simple.node.*;
-import java.io.ByteArrayOutputStream;
+import com.seaofnodes.simple.Utils;
+import com.seaofnodes.simple.codegen.*;
+import com.seaofnodes.simple.node.Node;
-public class ShrX86 extends MachConcreteNode implements MachNode {
- ShrX86(Node shr) {
- super(shr);
- };
- // Register mask allowed on input i.
- // This is the normal calling convention
-
- // CL register must be used for input(2)
+public class ShrX86 extends RegX86 {
+ ShrX86( Node add ) { super(add); }
+ @Override public String op() { return "shr"; }
+ @Override public String glabel() { return ">>>"; }
@Override public RegMask regmap(int i) {
- if(i == 1) return x86_64_v2.WMASK;
- if(i == 2) return x86_64_v2.RCX_MASK;
- throw Utils.TODO();
- }
-
- @Override public RegMask outregmap() { return x86_64_v2.WMASK; }
-
- // Output is same register as input#1
- @Override public int twoAddress() { return 1; }
-
- // Encoding is appended into the byte array; size is returned
- @Override public int encoding(ByteArrayOutputStream bytes) {
+ if (i == 1) return x86_64_v2.WMASK;
+ if (i == 2) return x86_64_v2.RCX_MASK;
throw Utils.TODO();
}
-
- // General form
- // General form: "shr dst >>> src"
- @Override public void asm(CodeGen code, SB sb) {
- sb.p(code.reg(this)).p(" >>> ").p(code.reg(in(1)));
+ @Override int opcode() { return 0xD3; }
+ @Override public final void encoding( Encoding enc ) {
+ short dst = enc.reg(this ); // src1
+ short src = enc.reg(in(2)); // src2
+ enc.add1(x86_64_v2.rex(0, dst, 0));
+ enc.add1(opcode()); // opcode
+ enc.add1(x86_64_v2.modrm(x86_64_v2.MOD.DIRECT, 5, dst));
}
-
- @Override public String op() { return "shr"; }
}
diff --git a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/SplitX86.java b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/SplitX86.java
index ea283a87..21c20b81 100644
--- a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/SplitX86.java
+++ b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/SplitX86.java
@@ -1,21 +1,76 @@
package com.seaofnodes.simple.node.cpus.x86_64_v2;
-import com.seaofnodes.simple.Utils;
-import com.seaofnodes.simple.codegen.RegMask;
+import com.seaofnodes.simple.SB;
+import com.seaofnodes.simple.codegen.*;
import com.seaofnodes.simple.node.Node;
import com.seaofnodes.simple.node.SplitNode;
-import java.io.ByteArrayOutputStream;
public class SplitX86 extends SplitNode {
SplitX86( String kind, byte round ) { super(kind,round, new Node[2]); }
-
- // Register mask allowed on input i.
+ @Override public String op() { return "mov"; }
@Override public RegMask regmap(int i) { return x86_64_v2.SPLIT_MASK; }
- // Register mask allowed as a result. 0 for no register.
@Override public RegMask outregmap() { return x86_64_v2.SPLIT_MASK; }
+ // Need to handle 8 cases: . reg->reg, reg->xmm, reg->flags, xmm->reg, xmm->xmm, xmm->flags, flags->reg, flags->xmm,
+ // flags->flags.
+ // Currently not handling flags
// Encoding is appended into the byte array; size is returned
- @Override public int encoding(ByteArrayOutputStream bytes) {
- throw Utils.TODO();
+ @Override public void encoding( Encoding enc ) {
+ // REX.W + 8B /r MOV r64, r/m64
+ short dst = enc.reg(this );
+ short src = enc.reg(in(1));
+
+ if( dst == x86_64_v2.FLAGS ) {
+ // mov reg, flags
+ // push rcx
+ // popf (Pop the top of the stack into the FLAGS register)
+ // 50+rd PUSH r64
+ enc.add1(0x50 + src);
+ // popf
+ enc.add1(0x9D);
+ return;
+ }
+ if( src == x86_64_v2.FLAGS ) {
+ // mov flags, reg
+ // pushf; pop reg
+ enc.add1(0x9C);
+ // 58+ rd POP r64
+ enc.add1(0x58 + dst);
+ return;
+ }
+
+ boolean dstX = dst >= x86_64_v2.XMM_OFFSET;
+ boolean srcX = src >= x86_64_v2.XMM_OFFSET;
+ if( dstX ) dst -= x86_64_v2.XMM_OFFSET;
+ if( srcX ) src -= x86_64_v2.XMM_OFFSET;
+
+ // 0x66 if moving between register classes
+ if( dstX ^ srcX ) enc.add1(0x66);
+ enc.add1(x86_64_v2.rex(dst, src, 0));
+
+ // pick opcode based on regs
+ if( !dstX && !srcX ) {
+ // reg->reg (MOV r64, r/m64)
+ enc.add1(0x8B);
+ } else if( dstX && srcX ) {
+ // xmm->xmm (NP 0F 28 /r MOVAPS xmm1, xmm2/m128)
+ enc.add1(0x0F);
+ enc.add1(0x28);
+ } else if( dstX && !srcX ) {
+ // xmm->reg (66 REX.W 0F 6E /r MOVQ xmm, r/m64)
+ enc.add1(0x0F);
+ enc.add1(0x6E);
+ } else if( !dstX && srcX ) {
+ // reg->xmm(66 REX.W 0F 7E /r MOVQ r/m64, xmm)
+ enc.add1(0x0F);
+ enc.add1(0x7E);
+ }
+
+ enc.add1(x86_64_v2.modrm(x86_64_v2.MOD.DIRECT, dst, src));
+ }
+
+ // General form: "mov dst = src"
+ @Override public void asm(CodeGen code, SB sb) {
+ sb.p(code.reg(this)).p(" = ").p(code.reg(in(1)));
}
}
diff --git a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/StoreX86.java b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/StoreX86.java
index 024ef904..4a54663d 100644
--- a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/StoreX86.java
+++ b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/StoreX86.java
@@ -1,8 +1,7 @@
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.RegMask;
+import com.seaofnodes.simple.codegen.*;
import com.seaofnodes.simple.node.Node;
import com.seaofnodes.simple.node.StoreNode;
import java.util.BitSet;
@@ -11,9 +10,7 @@ public class StoreX86 extends MemOpX86 {
StoreX86( StoreNode st, Node base, Node idx, int off, int scale, int imm, Node val ) {
super(st,st, base, idx, off, scale, imm, val);
}
-
@Override public String op() { return "st"+_sz; }
-
@Override public StringBuilder _printMach(StringBuilder sb, BitSet visited) {
Node val = val();
sb.append(".").append(_name).append("=");
@@ -21,9 +18,23 @@ public class StoreX86 extends MemOpX86 {
else val._print0(sb,visited);
return sb.append(";");
}
-
// Register mask allowed as a result. 0 for no register.
@Override public RegMask outregmap() { return null; }
+ @Override public void encoding( Encoding enc ) {
+ // REX.W + C7 /0 id MOV r/m64, imm32 |
+ // REX.W + 89 /r MOV r/m64, r64
+ short ptr = enc.reg(ptr());
+ short idx = enc.reg(idx());
+ short src = enc.reg(val());
+
+ enc.add1(x86_64_v2.rex(src, ptr, idx));
+
+ // switch on opcode depending on instruction
+ enc.add1( src == -1 ? 0xC7 : 0x89 );
+
+ x86_64_v2.indirectAdr(_scale, idx, ptr, _off, src, enc);
+ if( src == -1 ) enc.add4(_imm);
+ }
// General form: "stN [base + idx<<2 + 12],val"
@Override public void asm(CodeGen code, SB sb) {
diff --git a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/SubFX86.java b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/SubFX86.java
index ceaf0636..d727d429 100644
--- a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/SubFX86.java
+++ b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/SubFX86.java
@@ -1,31 +1,31 @@
package com.seaofnodes.simple.node.cpus.x86_64_v2;
import com.seaofnodes.simple.*;
-import com.seaofnodes.simple.codegen.CodeGen;
-import com.seaofnodes.simple.codegen.RegMask;
+import com.seaofnodes.simple.codegen.*;
import com.seaofnodes.simple.node.*;
-import java.io.ByteArrayOutputStream;
public class SubFX86 extends MachConcreteNode implements MachNode {
SubFX86( Node subf) { super(subf); }
-
-
- // Register mask allowed on input i.
+ @Override public String op() { return "subf"; }
@Override public RegMask regmap(int i) { assert i==1 || i==2; return x86_64_v2.XMASK; }
- // Register mask allowed as a result. 0 for no register.
@Override public RegMask outregmap() { return x86_64_v2.XMASK; }
- // Output is same register as input#1
@Override public int twoAddress() { return 1; }
// Encoding is appended into the byte array; size is returned
- @Override public int encoding(ByteArrayOutputStream bytes) {
- throw Utils.TODO();
+ @Override public void encoding( Encoding enc ) {
+ // F2 0F 5C /r SUBSD xmm1, xmm2/m64
+ short dst = (short)(enc.reg(this ) - x86_64_v2.XMM_OFFSET);
+ short src = (short)(enc.reg(in(2)) - x86_64_v2.XMM_OFFSET);
+ enc.add1(x86_64_v2.rex(dst, src,0));
+ // Fopcode
+ enc.add1(0xF2);
+ enc.add1(0x0F);
+ enc.add1(0x5C);
+ enc.add1(x86_64_v2.modrm(x86_64_v2.MOD.DIRECT, dst, src));
}
// General form: "subf dst -= src"
@Override public void asm(CodeGen code, SB sb) {
sb.p(code.reg(this)).p(" = ").p(code.reg(in(1))).p(" - ").p(code.reg(in(2)));
}
-
- @Override public String op() { return "subf"; }
}
diff --git a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/SubX86.java b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/SubX86.java
index da44a838..8da34bf5 100644
--- a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/SubX86.java
+++ b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/SubX86.java
@@ -1,31 +1,10 @@
package com.seaofnodes.simple.node.cpus.x86_64_v2;
-import com.seaofnodes.simple.*;
-import com.seaofnodes.simple.codegen.CodeGen;
-import com.seaofnodes.simple.codegen.RegMask;
-import com.seaofnodes.simple.node.*;
-import com.seaofnodes.simple.type.TypeInteger;
-import java.io.ByteArrayOutputStream;
-
-public class SubX86 extends MachConcreteNode implements MachNode {
- SubX86( Node sub ) { super(sub); }
-
- // Register mask allowed on input i.
- @Override public RegMask regmap(int i) { assert i==1 || i==2; return x86_64_v2.RMASK; }
- // Register mask allowed as a result. 0 for no register.
- @Override public RegMask outregmap() { return x86_64_v2.WMASK; }
- // Output is same register as input#1
- @Override public int twoAddress() { return 1; }
-
- // Encoding is appended into the byte array; size is returned
- @Override public int encoding(ByteArrayOutputStream bytes) {
- throw Utils.TODO();
- }
-
- // General form: "sub dst -= src"
- @Override public void asm(CodeGen code, SB sb) {
- sb.p(code.reg(this)).p(" = ").p(code.reg(in(1))).p(" - ").p(code.reg(in(2)));
- }
+import com.seaofnodes.simple.node.Node;
+public class SubX86 extends RegX86 {
+ SubX86( Node add ) { super(add); }
@Override public String op() { return "sub"; }
+ @Override public String glabel() { return "-"; }
+ @Override int opcode() { return 0x2B; }
}
diff --git a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/TFPX86.java b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/TFPX86.java
index 2b4de2ca..4167962b 100644
--- a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/TFPX86.java
+++ b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/TFPX86.java
@@ -1,28 +1,46 @@
package com.seaofnodes.simple.node.cpus.x86_64_v2;
import com.seaofnodes.simple.*;
-import com.seaofnodes.simple.codegen.CodeGen;
-import com.seaofnodes.simple.codegen.RegMask;
-import com.seaofnodes.simple.node.ConstantNode;
-import com.seaofnodes.simple.node.MachNode;
+import com.seaofnodes.simple.codegen.*;
+import com.seaofnodes.simple.node.*;
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeFunPtr;
-import java.io.ByteArrayOutputStream;
-
// Function constants
public class TFPX86 extends ConstantNode implements MachNode {
TFPX86( ConstantNode con ) { super(con); }
- @Override public String op() { return _con == Type.NIL ? "xor" : "ldx"; }
- // Register mask allowed on input i. 0 for no register.
+ @Override public String op() {
+ return _con == Type.NIL ? "xor" : "ldx";
+ }
+ @Override public boolean isClone() { return true; }
+ @Override public Node copy() { return new TFPX86(this); }
@Override public RegMask regmap(int i) { return null; }
- // General int registers
@Override public RegMask outregmap() { return x86_64_v2.WMASK; }
- @Override public boolean isClone() { return true; }
- @Override public TFPX86 copy() { return new TFPX86(this); }
+ // Zero-set uses XOR kills flags
+ @Override public RegMask killmap() {
+ return _con == Type.NIL ? x86_64_v2.FLAGS_MASK : null;
+ }
+
+ @Override public void encoding( Encoding enc ) {
+ short dst = enc.reg(this);
+ // Short form for zero
+ if( _con==Type.NIL ) {
+ // XOR dst,dst. Can skip REX is dst is low 8, makes this a 32b
+ // xor, which will also zero the high bits.
+ if( dst >= 8 ) enc.add1(x86_64_v2.rex(dst, dst, 0));
+ enc.add1(0x33); // opcode
+ enc.add1(x86_64_v2.modrm(x86_64_v2.MOD.DIRECT, dst, dst));
+ return;
+ }
- // Encoding is appended into the byte array; size is returned
- @Override public int encoding(ByteArrayOutputStream bytes) {
+ enc.relo(this,(TypeFunPtr)_con);
+ // Simply move the constant into a GPR
+ // Conditional encoding based on 64 or 32 bits
+ //REX.W + C7 /0 id MOV r/m64, imm32
+ enc.add1(x86_64_v2.rex(0, dst, 0));
+ enc.add1(0xC7); // 32 bits encoding
+ enc.add1(x86_64_v2.modrm(x86_64_v2.MOD.DIRECT, 0x00, dst));
+ //enc.add4((int)imm);
throw Utils.TODO();
}
@@ -35,6 +53,6 @@ public class TFPX86 extends ConstantNode implements MachNode {
if( _con == Type.NIL )
sb.p(reg).p(",").p(reg);
else
- _con.print(sb.p(reg).p(" #"));
+ _con.print(sb.p(reg).p(" = #"));
}
}
diff --git a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/UJmpX86.java b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/UJmpX86.java
new file mode 100644
index 00000000..6d52df9d
--- /dev/null
+++ b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/UJmpX86.java
@@ -0,0 +1,24 @@
+package com.seaofnodes.simple.node.cpus.x86_64_v2;
+
+import com.seaofnodes.simple.*;
+import com.seaofnodes.simple.codegen.*;
+import com.seaofnodes.simple.node.*;
+
+// unconditional jump
+// E9 cd JMP rel32
+public class UJmpX86 implements MachNode {
+ UJmpX86() { }
+ @Override public String op() { return "jmp"; }
+ @Override public RegMask regmap(int i) {return null; }
+ @Override public RegMask outregmap() { return null; }
+ // Encoding is appended into the byte array; size is returned
+ @Override public void encoding( Encoding enc ) {
+ //enc.jump();
+ //// E9 cd JMP rel32
+ //enc.add1(0xE9);
+ //enc.add4(0);
+ throw Utils.TODO();
+ }
+
+ @Override public void asm(CodeGen code, SB sb) { }
+}
diff --git a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/XorIX86.java b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/XorIX86.java
index 47c6be73..2d989a50 100644
--- a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/XorIX86.java
+++ b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/XorIX86.java
@@ -1,41 +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.CodeGen;
-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.type.TypeInteger;
-import java.io.ByteArrayOutputStream;
-
-public class XorIX86 extends MachConcreteNode implements MachNode {
-
- final TypeInteger _ti;
- XorIX86(Node xor, TypeInteger ti) {super(xor); _inputs.pop(); _ti = ti;}
-
- // Register mask allowed on input i.
- // This is the normal calling convention
- @Override public RegMask regmap(int i) { assert i==1; return x86_64_v2.WMASK; }
- // Register mask allowed as a result. 0 for no register.
- @Override public RegMask outregmap() { return x86_64_v2.WMASK; }
-
-
- // Output is same register as input#1
- @Override public int twoAddress() { return 1; }
-
- // Encoding is appended into the byte array; size is returned
- @Override public int encoding(ByteArrayOutputStream bytes) {
- throw Utils.TODO();
- }
-
- // General form
- // General form: "ori xori ^ #imm"
- @Override public void asm(CodeGen code, SB sb) {
- sb.p(code.reg(this)).p(" = ").p(code.reg(in(1))).p(" ^ #");
- _ti.print(sb);
- }
+public class XorIX86 extends ImmX86 {
+ XorIX86( Node add, int imm ) { super(add,imm); }
@Override public String op() { return "xori"; }
+ @Override public String glabel() { return "^"; }
+ @Override int opcode() { return 0x81; }
+ @Override int mod() { return 6; }
}
diff --git a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/XorX86.java b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/XorX86.java
new file mode 100644
index 00000000..86703903
--- /dev/null
+++ b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/XorX86.java
@@ -0,0 +1,11 @@
+package com.seaofnodes.simple.node.cpus.x86_64_v2;
+
+import com.seaofnodes.simple.node.Node;
+
+public class XorX86 extends RegX86 {
+ XorX86( Node add ) { super(add); }
+ @Override public String op() { return "xor"; }
+ @Override public String glabel() { return "^"; }
+ @Override int opcode() { return 0x33; }
+ @Override public boolean commutes() { return true; }
+}
diff --git a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/x86_64_v2.java b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/x86_64_v2.java
index aacd2352..9263616e 100644
--- a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/x86_64_v2.java
+++ b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/x86_64_v2.java
@@ -1,26 +1,26 @@
package com.seaofnodes.simple.node.cpus.x86_64_v2;
import com.seaofnodes.simple.Utils;
-import com.seaofnodes.simple.codegen.CodeGen;
-import com.seaofnodes.simple.codegen.LRG;
-import com.seaofnodes.simple.codegen.Machine;
-import com.seaofnodes.simple.codegen.RegMask;
+import com.seaofnodes.simple.codegen.*;
import com.seaofnodes.simple.node.*;
import com.seaofnodes.simple.type.*;
+import java.io.ByteArrayOutputStream;
+
public class x86_64_v2 extends Machine {
// X86-64 V2. Includes e.g. SSE4.2 and POPCNT.
@Override public String name() { return "x86_64_v2"; }
- static final int RAX = 0, RCX = 1, RDX = 2, RBX = 3, RSP = 4, RBP = 5, RSI = 6, RDI = 7;
- static final int R08 = 8, R09 = 9, R10 = 10, R11 = 11, R12 = 12, R13 = 13, R14 = 14, R15 = 15;
+ public static int RAX = 0, RCX = 1, RDX = 2, RBX = 3, RSP = 4, RBP = 5, RSI = 6, RDI = 7;
+ public static int R08 = 8, R09 = 9, R10 = 10, R11 = 11, R12 = 12, R13 = 13, R14 = 14, R15 = 15;
- static final int XMM0 = 16, XMM1 = 17, XMM2 = 18, XMM3 = 19, XMM4 = 20, XMM5 = 21, XMM6 = 22, XMM7 = 23;
- static final int XMM8 = 24, XMM9 = 25, XMM10 = 26, XMM11 = 27, XMM12 = 28, XMM13 = 29, XMM14 = 30, XMM15 = 31;
- static final int FLAGS = 32;
- static final int MAX_REG = 33;
- static final int RPC = 33;
+ public static final int XMM0 = 16, XMM1 = 17, XMM2 = 18, XMM3 = 19, XMM4 = 20, XMM5 = 21, XMM6 = 22, XMM7 = 23;
+ public static final int XMM8 = 24, XMM9 = 25, XMM10 = 26, XMM11 = 27, XMM12 = 28, XMM13 = 29, XMM14 = 30, XMM15 = 31;
+ public static final int FLAGS = 32;
+ public static final int MAX_REG = 33;
+ public static final int RPC = 33;
+ public static int XMM_OFFSET = 16;
// General purpose register mask: pointers and ints, not floats
static final long RD_BITS = 0b1111111111111111L; // All the GPRs
static RegMask RMASK = new RegMask(RD_BITS);
@@ -29,9 +29,9 @@ public class x86_64_v2 extends Machine {
static RegMask WMASK = new RegMask(WR_BITS);
// Xmm register mask
static final long FP_BITS = 0b1111111111111111L << XMM0; // All the XMMs
- static final RegMask XMASK = new RegMask(FP_BITS);
- static final RegMask FLAGS_MASK = new RegMask(FLAGS);
- static final RegMask RPC_MASK = new RegMask(RPC);
+ static RegMask XMASK = new RegMask(FP_BITS);
+ static RegMask FLAGS_MASK = new RegMask(FLAGS);
+ static RegMask RPC_MASK = new RegMask(RPC);
static final long SPILLS = -(1L << MAX_REG);
static final RegMask SPLIT_MASK = new RegMask(WR_BITS | FP_BITS | (1L<<FLAGS) | SPILLS, -1L );
@@ -39,24 +39,139 @@ public class x86_64_v2 extends Machine {
// Load/store mask; both GPR and FPR
static RegMask MEM_MASK = new RegMask(WR_BITS | FP_BITS);
- static final RegMask RAX_MASK = new RegMask(RAX);
- static final RegMask RCX_MASK = new RegMask(RCX);
- static final RegMask RDX_MASK = new RegMask(RDX);
- static final RegMask RDI_MASK = new RegMask(RDI);
- static final RegMask R08_MASK = new RegMask(R08);
- static final RegMask R09_MASK = new RegMask(R09);
- static final RegMask RSI_MASK = new RegMask(RSI);
+ public static RegMask RAX_MASK = new RegMask(RAX);
+ public static RegMask RCX_MASK = new RegMask(RCX);
+ public static RegMask RDX_MASK = new RegMask(RDX);
+ public static RegMask RDI_MASK = new RegMask(RDI);
+ public static RegMask R08_MASK = new RegMask(R08);
+ public static RegMask R09_MASK = new RegMask(R09);
+ public static RegMask RSI_MASK = new RegMask(RSI);
+
+ public static RegMask XMM0_MASK = new RegMask(XMM0);
+
+ // Encoding
+ public static int REX_W = 0x48;
+ public static int REX_WR = 0x4C;
+ public static int REX_WRB= 0x4D;
+ public static int REX_WB = 0x49;
+
+ public enum MOD {
+ INDIRECT, // [mem]
+ INDIRECT_disp8, // [mem + 0x12]
+ INDIRECT_disp32,// [mem + 0x12345678]
+ DIRECT, // mem
+ };
+
+ // Inverting IfNode
+ static public String invert(String op) {
+ return switch (op) {
+ case "==" -> "!=";
+ case "!=" -> "==";
+ case ">" -> "<=";
+ case "<" -> ">=";
+ case ">=" -> "<" ;
+ case "<=" -> ">" ;
+ default -> throw new IllegalStateException("Unexpected value: " + op);
+ };
+ }
+ // opcode included here
+ // 0F 84 cd JE rel32
+ // 0F 85 cd JNE rel32
+ // 0F 8F cd JG rel32
+ // 0F 8C cd JL rel32
+ // 0F 8E cd JLE rel32
+ // 0F 8D cd JGE rel32
+
+
+ static public int jumpop(String op) {
+ return switch (op) {
+ case "==" -> 0x84;
+ case "!=" -> 0x85;
+ case ">" -> 0x8F;
+ case "<" -> 0x8C;
+ case "<=" -> 0x8E;
+ case ">=" -> 0X8D;
+ default -> throw new IllegalArgumentException("Too many arguments");
+ };
+ }
+
+ public static int modrm(MOD mod, int reg, int m_r) {
+ // combine all the bits
+ return (mod.ordinal() << 6) | ((reg & 0x07) << 3) | m_r & 0x07;
+ }
+
+ // 00 000 000
+ // same bit-layout as modrm
+ public static int sib(int scale, int index, int base) {
+ return (scale << 6) | ((index & 0x07) << 3) | base & 0x07;
+ }
+
+ // reg1 is reg(R)
+ // reg2 is r/mem(B)
+ // reg3 is X(index)
+ // reg4 is X(base)
+
+ // 0 denotes no direct register
+ public static int rex(int reg, int ptr, int idx) {
+ // assuming 64 bit by default so: 0100 1000
+ int rex = REX_W; // Default REX.W
+ if( 8 <= reg && reg <= 15 ) rex |= 0b00000100; // REX.R
+ if( 8 <= ptr && ptr <= 15 ) rex |= 0b00000001; // REX.B
+ if( 8 <= idx && idx <= 15 ) rex |= 0b00000010; // REX.X
+ return rex;
+ }
+
+ // Function used for encoding indirect memory addresses
+ // Does not always generate SIB byte e.g index == -1.
+ // -1 denotes empty value, not set - note 0 is different from -1 as it can represent rax.
+ // Looks for best mod locally
+ public static void indirectAdr( int scale, short index, short base, int offset, int reg, Encoding enc ) {
+ // Assume indirect
+ assert 0 <= base && base < 16;
+ assert index != RSP;
+
+ MOD mod = MOD.INDIRECT;
+ // is 1 byte enough or need more?
+ if( offset != 0 )
+ mod = imm8(offset)
+ ? MOD.INDIRECT_disp8
+ : MOD.INDIRECT_disp32;
+
+ // needs to pick optimal displacement mod if we want to encode base
+ if( mod == MOD.INDIRECT && (base == RBP || base == R13) )
+ mod = MOD.INDIRECT_disp8;
+
+ // special encoding for [base +offset]
+ if( index == -1 ) {
+ // Case for mov reg, [disp] (load)
+ enc.add1(modrm(mod, reg == -1 ? 0 : reg, base));
+ } else {
+ // rsp is hard-coded here(0x04)
+ enc.add1(modrm(mod, reg, 0x04));
+ enc.add1(sib(scale, index, base));
+ }
- static final RegMask XMM0_MASK = new RegMask(XMM0);
+ if( mod == MOD.INDIRECT_disp8 ) {
+ enc.add1(offset);
+ } else if( mod == MOD.INDIRECT_disp32 ) {
+ enc.add4(offset);
+ }
+ }
+
+ // Calling conv metadata
+ public int GPR_COUNT_CONV_WIN64 = 4; // RCX, RDX, R9, R9
+ public int XMM_COUNT_CONV_WIN64 = 4; // XMM0L, XMM1L, XMM2L, XMM3L
+ public int GPR_COUNT_CONV_SYSTEM_V = 6; // RDI, RSI, RDX, RCX, R8, R9
+ public int XMM_COUNT_CONV_SYSTEM_V = 4; // XMM0, XMM1, XMM2, XMM3 ....
// Human-readable name for a register number, e.g. "RAX".
// Hard crash for bad register number, fix yer bugs!
- static final String[] REGS = new String[] {
- "rax" , "rcx" , "rdx" , "rbx" , "rsp" , "rbp" , "rsi" , "rdi" ,
- "r8" , "r9" , "r10" , "r11" , "r12" , "r13" , "r14" , "r15" ,
- "xmm0", "xmm1", "xmm2" , "xmm3" , "xmm4" , "xmm5" , "xmm6" , "xmm7" ,
- "xmm8", "xmm9", "xmm10", "xmm11", "xmm12", "xmm13", "xmm14", "xmm15",
- "flags","[rsp-4]",
+ public static final String[] REGS = new String[]{
+ "rax", "rcx", "rdx", "rbx", "rsp", "rbp", "rsi", "rdi",
+ "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15",
+ "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6", "xmm7",
+ "xmm8", "xmm9", "xmm10", "xmm11", "xmm12", "xmm13", "xmm14", "xmm15",
+ "flags", "[rsp-4]",
};
@Override public String reg( int reg ) {
return reg < REGS.length ? REGS[reg] : "[rsp+"+(reg-REGS.length)*4+"]";
@@ -111,12 +226,18 @@ public class x86_64_v2 extends Machine {
throw Utils.TODO(); // Pass on stack slot
}
+ // Return single int/ptr register. Used by CallEnd output and Return input.
+ static RegMask retMask( TypeFunPtr tfp ) {
+ return tfp.ret() instanceof TypeFloat ? XMM0_MASK : RAX_MASK;
+ }
+
+
// caller saved(systemv)
static final long SYSTEM5_CALLER_SAVE =
(1L<< RAX) | (1L<< RCX) | (1L<< RDX) |
- (1L<< RDI) | (1L<< RSI) |
- (1L<< R08) | (1L<< R09) | (1L<< R10) | (1L<< R11) |
- (1L<<FLAGS)| // Flags are killed
+ (1L << RDI) | (1L << RSI) |
+ (1L << R08) | (1L << R09) | (1L << R10) | (1L << R11) |
+ (1L << FLAGS) | // Flags are killed
// All FP regs are killed
FP_BITS;
static final RegMask SYSTEM5_CALLER_SAVE_MASK = new RegMask(SYSTEM5_CALLER_SAVE);
@@ -132,16 +253,21 @@ public class x86_64_v2 extends Machine {
static final RegMask WIN64_CALLER_SAVE_MASK = new RegMask(WIN64_CALLER_SAVE);
static RegMask x86CallerSave() {
- return switch( CodeGen.CODE._callingConv ) {
- case "SystemV" -> SYSTEM5_CALLER_SAVE_MASK;
- case "Win64" -> WIN64_CALLER_SAVE_MASK;
- default -> throw new IllegalArgumentException("Unknown calling convention: "+CodeGen.CODE._callingConv);
+ return switch (CodeGen.CODE._callingConv) {
+ case "SystemV" -> SYSTEM5_CALLER_SAVE_MASK;
+ case "Win64" -> WIN64_CALLER_SAVE_MASK;
+ default -> throw new IllegalArgumentException("Unknown calling convention: " + CodeGen.CODE._callingConv);
};
}
- @Override public RegMask callerSave() { return x86CallerSave(); }
+
+ @Override
+ public RegMask callerSave() {
+ return x86CallerSave();
+ }
static final RegMask SYSTEM5_CALLEE_SAVE_MASK;
static final RegMask WIN64_CALLEE_SAVE_MASK;
+
static {
long callee = ~SYSTEM5_CALLER_SAVE;
// Remove the spills
@@ -191,7 +317,7 @@ public class x86_64_v2 extends Machine {
static RegMask retMask( TypeFunPtr tfp, int i ) {
if( i==2 )
return tfp.ret() instanceof TypeFloat ? XMM0_MASK : RAX_MASK;
- RegMask[] masks = switch( CodeGen.CODE._callingConv ) {
+ RegMask[] masks = switch (CodeGen.CODE._callingConv) {
case "SystemV" -> SYS5_RET_MASKS;
case "Win64" -> WIN64_RET_MASKS;
default -> throw new IllegalArgumentException("Unknown calling convention: "+CodeGen.CODE._callingConv);
@@ -200,165 +326,180 @@ public class x86_64_v2 extends Machine {
}
// Create a split op; any register to any register, including stack slots
- @Override public SplitNode split(String kind, byte round, LRG lrg) { return new SplitX86(kind,round); }
+ @Override
+ public SplitNode split(String kind, byte round, LRG lrg) {
+ return new SplitX86(kind, round);
+ }
// Return a MachNode unconditional branch
- @Override public CFGNode jump() {
+ @Override
+ public CFGNode jump() {
throw Utils.TODO();
}
// Break an infinite loop
- @Override public IfNode never( CFGNode ctrl ) {
+ @Override
+ public IfNode never(CFGNode ctrl) {
throw Utils.TODO();
}
// Instruction selection
- @Override public Node instSelect( Node n ) {
- return switch( n ) {
- case AddFNode addf -> addf(addf);
- case AddNode add -> add(add);
- case AndNode and -> and(and);
- case BoolNode bool -> cmp(bool);
- case CallEndNode cend -> new CallEndX86(cend);
- case CallNode call -> call(call);
- case CastNode cast -> new CastX86(cast);
- case CProjNode c -> new CProjNode(c);
- case ConstantNode con -> con(con);
- case DivFNode divf -> new DivFX86(divf);
- case DivNode div -> new DivX86(div);
- case FunNode fun -> new FunX86(fun);
- case IfNode iff -> jmp(iff);
- case LoadNode ld -> ld(ld);
- case MemMergeNode mem -> new MemMergeNode(mem);
- case MulFNode mulf -> new MulFX86(mulf);
- case MulNode mul -> mul(mul);
- case NewNode nnn -> new NewX86(nnn);
- case OrNode or -> or(or);
- case ParmNode parm -> new ParmX86(parm);
- case PhiNode phi -> new PhiNode(phi);
- case ProjNode prj -> prj(prj);
- case ReadOnlyNode read -> new ReadOnlyNode(read);
- case ReturnNode ret -> new RetX86(ret,ret.fun());
- case SarNode sar -> sar(sar);
- case ShlNode shl -> shl(shl);
- case ShrNode shr -> shr(shr);
- case StartNode start -> new StartNode(start);
- case StopNode stop -> new StopNode(stop);
- case StoreNode st -> st(st);
- case SubFNode subf -> new SubFX86(subf);
- case SubNode sub -> sub(sub);
- case ToFloatNode tfn -> i2f8(tfn);
- case XorNode xor -> xor(xor);
-
- case LoopNode loop -> new LoopNode(loop);
- case RegionNode region-> new RegionNode(region);
- default -> throw Utils.TODO();
+ @Override
+ public Node instSelect(Node n) {
+ return switch (n) {
+ case AddFNode addf -> addf(addf);
+ case AddNode add -> add(add);
+ case AndNode and -> and(and);
+ case BoolNode bool -> cmp(bool);
+ case CallEndNode cend -> new CallEndX86(cend);
+ case CallNode call -> call(call);
+ case CastNode cast -> new CastX86(cast);
+ case CProjNode c -> new CProjNode(c);
+ case ConstantNode con -> con(con);
+ case DivFNode divf -> new DivFX86(divf);
+ case DivNode div -> new DivX86(div);
+ case FunNode fun -> new FunX86(fun);
+ case IfNode iff -> jmp(iff);
+ case LoadNode ld -> ld(ld);
+ case MemMergeNode mem -> new MemMergeNode(mem);
+ case MulFNode mulf -> new MulFX86(mulf);
+ case MulNode mul -> mul(mul);
+ case NewNode nnn -> new NewX86(nnn);
+ case NotNode not -> new NotX86(not);
+ case OrNode or -> or(or);
+ case ParmNode parm -> new ParmX86(parm);
+ case PhiNode phi -> new PhiNode(phi);
+ case ProjNode prj -> prj(prj);
+ case ReadOnlyNode read -> new ReadOnlyNode(read);
+ case ReturnNode ret -> new RetX86(ret, ret.fun());
+ case SarNode sar -> sar(sar);
+ case ShlNode shl -> shl(shl);
+ case ShrNode shr -> shr(shr);
+ case StartNode start -> new StartNode(start);
+ case StopNode stop -> new StopNode(stop);
+ case StoreNode st -> st(st);
+ case SubFNode subf -> new SubFX86(subf);
+ case SubNode sub -> sub(sub);
+ case ToFloatNode tfn -> i2f8(tfn);
+ case XorNode xor -> xor(xor);
+
+ case LoopNode loop -> new LoopNode(loop);
+ case RegionNode region -> new RegionNode(region);
+ default -> throw Utils.TODO();
};
}
+ public static boolean imm8( long imm ) { return -128 <= imm && imm <= 127; }
+ public static boolean imm32( long imm ) { return (int)imm==imm; }
// Attempt a full LEA-style break down.
- private Node add( AddNode add ) {
+ private Node add(AddNode add) {
Node lhs = add.in(1);
Node rhs = add.in(2);
- if( lhs instanceof LoadNode ld && ld.nOuts()==1 )
- return new AddMemX86(add,address(ld),ld.ptr(),idx,off,scale, imm(rhs),val);
+ if( lhs instanceof LoadNode ld && ld.nOuts() == 1 )
+ return new AddMemX86(add, address(ld), ld.ptr(), idx, off, scale, imm(rhs), val);
- if( rhs instanceof LoadNode ld && ld.nOuts()==1 )
+ if(rhs instanceof LoadNode ld && ld.nOuts() == 1)
throw Utils.TODO(); // Swap load sides
// Attempt a full LEA-style break down.
// Returns one of AddX86, AddIX86, LeaX86, or LHS
if( rhs instanceof ConstantNode off && off._con instanceof TypeInteger toff ) {
+ long imm = toff.value();
+ assert imm!=0; // Folded in peeps
+ if( (int)imm != imm ) // Full 64bit immediate
+ return new AddX86(add);
+ // Now imm <= 32bits
if( lhs instanceof AddNode ladd )
// ((base + (idx << scale)) + off)
- return _lea(add,ladd.in(1),ladd.in(2),toff.value());
+ return _lea(add, ladd.in(1), ladd.in(2), (int)imm);
if( lhs instanceof ShlNode shift )
// (idx << scale) + off; no base
- return _lea(add,null,shift,toff.value());
+ return _lea(add, null, shift, (int)imm);
// lhs + rhs1
- if( toff.value()==0 ) return add;
- return new AddIX86(add, toff);
+ return new AddIX86(add, (int)imm);
}
- return _lea(add,lhs,rhs,0);
+ return _lea(add, lhs, rhs, 0);
}
- private Node addf( AddFNode addf ) {
- if( addf.in(1) instanceof LoadNode ld && ld.nOuts()==1 )
- return new AddFMemX86(addf,address(ld),ld.ptr(),idx,off,scale, addf.in(2));
+ private Node addf(AddFNode addf) {
+ if(addf.in(1) instanceof LoadNode ld && ld.nOuts() == 1)
+ return new AddFMemX86(addf, address(ld), ld.ptr(), idx, off, scale, addf.in(2));
- if( addf.in(2) instanceof LoadNode ld && ld.nOuts()==1 )
+ if(addf.in(2) instanceof LoadNode ld && ld.nOuts() == 1)
throw Utils.TODO(); // Swap load sides
return new AddFX86(addf);
}
- private Node _lea( Node add, Node base, Node idx, long off ) {
- int scale = 1;
- if( base instanceof ShlNode && !(idx instanceof ShlNode) ) throw Utils.TODO(); // Bug in canonicalization, should on RHS
+ private Node _lea(Node add, Node base, Node idx, int off) {
+ int scale = 0;
+ if( base instanceof ShlNode && !(idx instanceof ShlNode) )
+ throw Utils.TODO(); // Bug in canonicalization, should on RHS
if( idx instanceof ShlNode shift && shift.in(2) instanceof ConstantNode shfcon &&
shfcon._con instanceof TypeInteger tscale && 0 <= tscale.value() && tscale.value() <= 3 ) {
idx = shift.in(1);
- scale = 1 << ((int)tscale.value());
+ scale = ((int) tscale.value());
}
// (base + idx) + off
- return off==0 && scale==1
+ return off == 0 && scale == 0
? new AddX86(add)
- : new LeaX86(add,base,idx,scale,off);
+ : new LeaX86(add, base, idx, scale, off);
}
private Node and(AndNode and) {
- if( and.in(2) instanceof ConstantNode con && con._con instanceof TypeInteger ti )
- return new AndIX86(and, ti);
+ if( and.in(2) instanceof ConstantNode con && con._con instanceof TypeInteger ti && imm32(ti.value()) )
+ return new AndIX86(and, (int)ti.value());
return new AndX86(and);
}
private Node call(CallNode call) {
if( call.fptr() instanceof ConstantNode con && con._con instanceof TypeFunPtr tfp )
return new CallX86(call, tfp);
- return new CallRX86( call );
+ return new CallRX86(call);
}
// Because X86 flags, a normal ideal Bool is 2 X86 ops: a "cmp" and at "setz".
// Ideal If reading from a setz will skip it and use the "cmp" instead.
private Node cmp( BoolNode bool ) {
Node cmp = _cmp(bool);
- return new SetX86(cmp,bool.op());
+ return new SetX86(cmp, bool.op());
}
- private Node _cmp( BoolNode bool ) {
+
+ private Node _cmp(BoolNode bool) {
// Float variant
if( bool.isFloat() )
return new CmpFX86(bool);
Node lhs = bool.in(1);
Node rhs = bool.in(2);
- if( lhs instanceof LoadNode ld && ld.nOuts()==1 )
- return new CmpMemX86(bool,address(ld),ld.ptr(),idx,off,scale, imm(rhs),val,false);
+ if(lhs instanceof LoadNode ld && ld.nOuts() == 1)
+ return new CmpMemX86(bool, address(ld), ld.ptr(), idx, off, scale, imm(rhs), val, false);
- if( rhs instanceof LoadNode ld && ld.nOuts()==1 )
- return new CmpMemX86(bool,address(ld),ld.ptr(),idx,off,scale, imm(lhs),val,true);
+ if(rhs instanceof LoadNode ld && ld.nOuts() == 1)
+ return new CmpMemX86(bool, address(ld), ld.ptr(), idx, off, scale, imm(lhs), val, true);
// Vs immediate
- if( rhs instanceof ConstantNode con && con._con instanceof TypeInteger ti )
- return new CmpIX86(bool, ti);
+ if( rhs instanceof ConstantNode con && con._con instanceof TypeInteger ti && imm32(ti.value()) )
+ return new CmpIX86(bool, (int)ti.value());
// x vs y
return new CmpX86(bool);
}
- private Node con( ConstantNode con ) {
- if( !con._con.isConstant() ) return new ConstantNode( con ); // Default unknown caller inputs
- return switch( con._con ) {
- case TypeInteger ti -> new IntX86(con);
- case TypeFloat tf -> new FltX86(con);
- case TypeFunPtr tfp -> new TFPX86(con);
- case TypeMemPtr tmp -> throw Utils.TODO();
- case TypeNil tn -> throw Utils.TODO();
- // TOP, BOTTOM, XCtrl, Ctrl, etc. Never any executable code.
- case Type t -> t==Type.NIL ? new IntX86(con) : new ConstantNode(con);
+ private Node con(ConstantNode con) {
+ if(!con._con.isConstant()) return new ConstantNode(con); // Default unknown caller inputs
+ return switch (con._con) {
+ case TypeInteger ti -> new IntX86(con);
+ case TypeFloat tf -> new FltX86(con);
+ case TypeFunPtr tfp -> new TFPX86(con);
+ case TypeMemPtr tmp -> throw Utils.TODO();
+ case TypeNil tn -> throw Utils.TODO();
+ // TOP, BOTTOM, XCtrl, Ctrl, etc. Never any executable code.
+ case Type t -> t == Type.NIL ? new IntX86(con) : new ConstantNode(con);
};
}
@@ -367,28 +508,28 @@ public class x86_64_v2 extends Machine {
return new I2f8X86(tfn);
}
- private Node jmp( IfNode iff ) {
+ private Node jmp(IfNode iff) {
// If/Bool combos will match to a Cmp/Set which sets flags.
// Most general arith ops will also set flags, which the Jmp needs directly.
// Loads do not set the flags, and will need an explicit TEST
- if( !(iff.in(1) instanceof BoolNode) )
- iff.setDef(1,new BoolNode.EQ(iff.in(1),new ConstantNode(TypeInteger.ZERO)));
- return new JmpX86(iff, ((BoolNode)iff.in(1)).op());
+ if(!(iff.in(1) instanceof BoolNode))
+ iff.setDef(1, new BoolNode.EQ(iff.in(1), new ConstantNode(TypeInteger.ZERO)));
+ return new JmpX86(iff, invert(((BoolNode) iff.in(1)).op()));
}
- private Node ld( LoadNode ld ) {
- return new LoadX86(address(ld),ld.ptr(),idx,off,scale);
+ private Node ld(LoadNode ld) {
+ return new LoadX86(address(ld), ld.ptr(), idx, off, scale);
}
private Node mul(MulNode mul) {
- return mul.in(2) instanceof ConstantNode con && con._con instanceof TypeInteger ti
- ? new MulIX86(mul, ti)
- : new MulX86(mul);
+ if( mul.in(2) instanceof ConstantNode con && con._con instanceof TypeInteger ti && imm32(ti.value()) )
+ return new MulIX86(mul, (int)ti.value());
+ return new MulX86(mul);
}
private Node or(OrNode or) {
- if( or.in(2) instanceof ConstantNode con && con._con instanceof TypeInteger ti)
- return new OrIX86(or, ti);
+ if( or.in(2) instanceof ConstantNode con && con._con instanceof TypeInteger ti && imm32(ti.value()) )
+ return new OrIX86(or, (int)ti.value());
return new OrX86(or);
}
@@ -396,80 +537,78 @@ public class x86_64_v2 extends Machine {
return new ProjX86(prj);
}
- private Node sar( SarNode sar ) {
- if( sar.in(2) instanceof ConstantNode con && con._con instanceof TypeInteger ti)
- return new SarIX86(sar, ti);
+ private Node sar(SarNode sar) {
+ if( sar.in(2) instanceof ConstantNode con && con._con instanceof TypeInteger ti )
+ return new SarIX86(sar, (int)(ti.value() & 0x03f) );
return new SarX86(sar);
}
- private Node shl( ShlNode shl ) {
+ private Node shl(ShlNode shl) {
if( shl.in(2) instanceof ConstantNode con && con._con instanceof TypeInteger ti )
- return new ShlIX86(shl, ti);
+ return new ShlIX86(shl, (int)(ti.value() & 0x03f) );
return new ShlX86(shl);
}
- private Node shr(ShrNode shr) {
+ private Node shr( ShrNode shr ) {
if( shr.in(2) instanceof ConstantNode con && con._con instanceof TypeInteger ti )
- return new ShrIX86(shr, ti);
+ return new ShrIX86(shr, (int)(ti.value() & 0x03f) );
return new ShrX86(shr);
}
- private Node st( StoreNode st ) {
+ private Node st (StoreNode st ){
// Look for "*ptr op= val"
Node op = st.val();
- if( op instanceof AddNode ) {
- if( op.in(1) instanceof LoadNode ld &&
- ld.in(0)==st.in(0) &&
- ld.mem()==st.mem() &&
- ld.ptr()==st.ptr() &&
- ld.off()==st.off() ) {
- if( op instanceof AddNode ) {
- return new MemAddX86(address(st),st.ptr(),idx,off,scale,imm(op.in(2)),val);
- }
+ if(op instanceof AddNode) {
+ if(op.in(1) instanceof LoadNode ld &&
+ ld.in(0) == st.in(0) &&
+ ld.mem() == st.mem() &&
+ ld.ptr() == st.ptr() &&
+ ld.off() == st.off()) {
+ if( op instanceof AddNode )
+ return new MemAddX86(address(st), st.ptr(), idx, off, scale, imm(op.in(2)), val);
throw Utils.TODO();
}
}
- return new StoreX86(address(st),st.ptr(),idx,off,scale,imm(st.val()),val);
+ return new StoreX86(address(st), st.ptr(), idx, off, scale, imm(st.val()), val);
}
- private Node sub( SubNode sub ) {
+ private Node sub (SubNode sub ){
return sub.in(2) instanceof ConstantNode con && con._con instanceof TypeInteger ti
- ? new AddIX86(sub, TypeInteger.constant(-ti.value()))
+ ? new AddIX86(sub, (int)-ti.value())
: new SubX86(sub);
}
- private Node xor(XorNode xor) {
- if(xor.in(2) instanceof ConstantNode con && con._con instanceof TypeInteger ti)
- return new XorIX86(xor, ti);
- throw Utils.TODO();
+ private Node xor (XorNode xor){
+ if( xor.in(2) instanceof ConstantNode con && con._con instanceof TypeInteger ti && imm32(ti.value()) )
+ return new XorIX86(xor, (int)ti.value());
+ return new XorX86(xor);
}
-
// Gather X86 addressing mode bits prior to constructing. This is a
// builder pattern, but saving the bits in a *local* *global* here to keep
// mess contained.
private static int off, scale, imm;
private static Node idx, val;
- private <N extends MemOpNode> N address( N mop ) {
+ private <N extends MemOpNode > N address(N mop) {
off = scale = imm = 0; // Reset
idx = val = null;
Node base = mop.ptr();
// Skip/throw-away a ReadOnly, only used to typecheck
- if( base instanceof ReadOnlyNode read ) base = read.in(1);
+ if(base instanceof ReadOnlyNode read) base = read.in(1);
assert !(base instanceof AddNode) && base._type instanceof TypeMemPtr; // Base ptr always, not some derived
- if( mop.off() instanceof AddNode add && add.in(2) instanceof ConstantNode con && con._con instanceof TypeInteger ti ) {
- off = (int)ti.value();
+ if(mop.off() instanceof AddNode add && add.in(2) instanceof ConstantNode con && con._con instanceof TypeInteger ti) {
+ off = (int) ti.value();
assert off == ti.value(); // In 32-bit range
idx = add.in(1);
- if( idx instanceof ShlNode shift && shift.in(2) instanceof ConstantNode shfcon &&
- shfcon._con instanceof TypeInteger tscale && 0 <= tscale.value() && tscale.value() <= 3 ) {
+ if(idx instanceof ShlNode shift && shift.in(2) instanceof ConstantNode shfcon &&
+ shfcon._con instanceof TypeInteger tscale && 0 <= tscale.value() && tscale.value() <= 3) {
idx = shift.in(1);
- scale = (int)tscale.value();
+ scale = (int) tscale.value();
}
} else {
- if( mop.off() instanceof ConstantNode con && con._con instanceof TypeInteger ti ) {
- off = (int)ti.value();
+ if(mop.off() instanceof ConstantNode con && con._con instanceof TypeInteger ti) {
+ off = (int) ti.value();
assert off == ti.value(); // In 32-bit range
} else {
idx = mop.off();
@@ -478,11 +617,11 @@ public class x86_64_v2 extends Machine {
return mop;
}
- private int imm( Node xval ) {
- assert val==null && imm==0;
- if( xval instanceof ConstantNode con && con._con instanceof TypeInteger ti ) {
+ private int imm (Node xval ){
+ assert val == null && imm == 0;
+ if( xval instanceof ConstantNode con && con._con instanceof TypeInteger ti) {
val = null;
- imm = (int)ti.value();
+ imm = (int) ti.value();
assert imm == ti.value(); // In 32-bit range
} else {
val = xval;