diff options
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->XCTRL -->
-<g id="edge1" class="edge">
-<title>TOP->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->INT_TOP -->
-<g id="edge4" class="edge">
-<title>TOP->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->FLT_TOP -->
-<g id="edge18" class="edge">
-<title>TOP->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->PTR -->
-<g id="edge33" class="edge">
-<title>TOP->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->STRUCT_TOP -->
-<g id="edge36" class="edge">
-<title>TOP->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->MEM_TOP -->
-<g id="edge46" class="edge">
-<title>TOP->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->TUPLE_TOP -->
-<g id="edge56" class="edge">
-<title>TOP->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->CTRL -->
-<g id="edge2" class="edge">
-<title>XCTRL->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->BOT -->
-<g id="edge3" class="edge">
-<title>CTRL->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>max]</text>
-</g>
-<!-- INT_TOP->INT_HI -->
-<g id="edge5" class="edge">
-<title>INT_TOP->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->BOT -->
-<g id="edge15" class="edge">
-<title>INT_BOT->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->INT_XBOOL -->
-<g id="edge6" class="edge">
-<title>INT_HI->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->INT_CON -->
-<g id="edge9" class="edge">
-<title>INT_HI->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->INT_CON0 -->
-<g id="edge7" class="edge">
-<title>INT_XBOOL->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->INT_CON1 -->
-<g id="edge8" class="edge">
-<title>INT_XBOOL->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<max]</text>
-</g>
-<!-- INT_CON->INT_LO -->
-<g id="edge13" class="edge">
-<title>INT_CON->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->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->INT_BOOL -->
-<g id="edge10" class="edge">
-<title>INT_CON0->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->INT_CON -->
-<!-- INT_CON1->INT_BOOL -->
-<g id="edge11" class="edge">
-<title>INT_CON1->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->INT_LO -->
-<g id="edge12" class="edge">
-<title>INT_BOOL->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->INT_BOT -->
-<g id="edge14" class="edge">
-<title>INT_LO->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->FLT_CON64 -->
-<g id="edge19" class="edge">
-<title>FLT_TOP->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->FLT_CONPI -->
-<g id="edge20" class="edge">
-<title>FLT_TOP->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->FLT_X32 -->
-<g id="edge23" class="edge">
-<title>FLT_TOP->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->BOT -->
-<g id="edge29" class="edge">
-<title>FLT_BOT->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->FLT_BOT -->
-<g id="edge21" class="edge">
-<title>FLT_CON64->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->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->FLT_32 -->
-<g id="edge27" class="edge">
-<title>FLT_CON32->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->FLT_BOT -->
-<g id="edge22" class="edge">
-<title>FLT_CONPI->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->FLT_CON64 -->
-<!-- FLT_X32->FLT_CON32 -->
-<g id="edge25" class="edge">
-<title>FLT_X32->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->FLT_CON0 -->
-<g id="edge24" class="edge">
-<title>FLT_X32->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->FLT_CON32 -->
-<!-- FLT_CON0->FLT_32 -->
-<g id="edge26" class="edge">
-<title>FLT_CON0->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->FLT_BOT -->
-<g id="edge28" class="edge">
-<title>FLT_32->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->PTR0 -->
-<g id="edge34" class="edge">
-<title>PTR->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->BOT -->
-<g id="edge35" class="edge">
-<title>PTR0->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->STRUCT_S1 -->
-<g id="edge37" class="edge">
-<title>STRUCT_TOP->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->STRUCT_S2 -->
-<g id="edge38" class="edge">
-<title>STRUCT_TOP->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">...  </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->STRUCT_SN -->
-<g id="edge39" class="edge">
-<title>STRUCT_TOP->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->BOT -->
-<g id="edge43" class="edge">
-<title>STRUCT_BOT->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->STRUCT_BOT -->
-<g id="edge40" class="edge">
-<title>STRUCT_S1->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->STRUCT_S2 -->
-<!-- STRUCT_S2->STRUCT_BOT -->
-<g id="edge41" class="edge">
-<title>STRUCT_S2->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->STRUCT_SN -->
-<!-- STRUCT_SN->STRUCT_BOT -->
-<g id="edge42" class="edge">
-<title>STRUCT_SN->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->MEM_ALIAS1 -->
-<g id="edge47" class="edge">
-<title>MEM_TOP->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->MEM_ALIASDOTS -->
-<g id="edge48" class="edge">
-<title>MEM_TOP->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->MEM_ALIASN -->
-<g id="edge49" class="edge">
-<title>MEM_TOP->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->BOT -->
-<g id="edge53" class="edge">
-<title>MEM_BOT->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->MEM_BOT -->
-<g id="edge50" class="edge">
-<title>MEM_ALIAS1->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->MEM_ALIASDOTS -->
-<!-- MEM_ALIASDOTS->MEM_BOT -->
-<g id="edge51" class="edge">
-<title>MEM_ALIASDOTS->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->MEM_ALIASN -->
-<!-- MEM_ALIASN->MEM_BOT -->
-<g id="edge52" class="edge">
-<title>MEM_ALIASN->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->TUPLE1 -->
-<g id="edge57" class="edge">
-<title>TUPLE_TOP->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->TUPLE2 -->
-<g id="edge58" class="edge">
-<title>TUPLE_TOP->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->TUPLEN -->
-<g id="edge59" class="edge">
-<title>TUPLE_TOP->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->BOT -->
-<g id="edge63" class="edge">
-<title>TUPLE_BOT->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->TUPLE_BOT -->
-<g id="edge60" class="edge">
-<title>TUPLE1->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->TUPLE_BOT -->
-<g id="edge61" class="edge">
-<title>TUPLE2->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->TUPLE_BOT -->
-<g id="edge62" class="edge">
-<title>TUPLEN->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->XCTRL --> +<g id="edge1" class="edge"> +<title>TOP->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->INT_TOP --> +<g id="edge4" class="edge"> +<title>TOP->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->FLT_TOP --> +<g id="edge18" class="edge"> +<title>TOP->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->PTR --> +<g id="edge33" class="edge"> +<title>TOP->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->STRUCT_TOP --> +<g id="edge36" class="edge"> +<title>TOP->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->MEM_TOP --> +<g id="edge46" class="edge"> +<title>TOP->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->TUPLE_TOP --> +<g id="edge56" class="edge"> +<title>TOP->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->CTRL --> +<g id="edge2" class="edge"> +<title>XCTRL->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->BOT --> +<g id="edge3" class="edge"> +<title>CTRL->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>max]</text> +</g> +<!-- INT_TOP->INT_HI --> +<g id="edge5" class="edge"> +<title>INT_TOP->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->BOT --> +<g id="edge15" class="edge"> +<title>INT_BOT->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->INT_XBOOL --> +<g id="edge6" class="edge"> +<title>INT_HI->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->INT_CON --> +<g id="edge9" class="edge"> +<title>INT_HI->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->INT_CON0 --> +<g id="edge7" class="edge"> +<title>INT_XBOOL->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->INT_CON1 --> +<g id="edge8" class="edge"> +<title>INT_XBOOL->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<max]</text> +</g> +<!-- INT_CON->INT_LO --> +<g id="edge13" class="edge"> +<title>INT_CON->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->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->INT_BOOL --> +<g id="edge10" class="edge"> +<title>INT_CON0->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->INT_CON --> +<!-- INT_CON1->INT_BOOL --> +<g id="edge11" class="edge"> +<title>INT_CON1->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->INT_LO --> +<g id="edge12" class="edge"> +<title>INT_BOOL->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->INT_BOT --> +<g id="edge14" class="edge"> +<title>INT_LO->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->FLT_CON64 --> +<g id="edge19" class="edge"> +<title>FLT_TOP->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->FLT_CONPI --> +<g id="edge20" class="edge"> +<title>FLT_TOP->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->FLT_X32 --> +<g id="edge23" class="edge"> +<title>FLT_TOP->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->BOT --> +<g id="edge29" class="edge"> +<title>FLT_BOT->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->FLT_BOT --> +<g id="edge21" class="edge"> +<title>FLT_CON64->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->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->FLT_32 --> +<g id="edge27" class="edge"> +<title>FLT_CON32->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->FLT_BOT --> +<g id="edge22" class="edge"> +<title>FLT_CONPI->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->FLT_CON64 --> +<!-- FLT_X32->FLT_CON32 --> +<g id="edge25" class="edge"> +<title>FLT_X32->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->FLT_CON0 --> +<g id="edge24" class="edge"> +<title>FLT_X32->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->FLT_CON32 --> +<!-- FLT_CON0->FLT_32 --> +<g id="edge26" class="edge"> +<title>FLT_CON0->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->FLT_BOT --> +<g id="edge28" class="edge"> +<title>FLT_32->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->PTR0 --> +<g id="edge34" class="edge"> +<title>PTR->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->BOT --> +<g id="edge35" class="edge"> +<title>PTR0->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->STRUCT_S1 --> +<g id="edge37" class="edge"> +<title>STRUCT_TOP->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->STRUCT_S2 --> +<g id="edge38" class="edge"> +<title>STRUCT_TOP->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">...  </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->STRUCT_SN --> +<g id="edge39" class="edge"> +<title>STRUCT_TOP->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->BOT --> +<g id="edge43" class="edge"> +<title>STRUCT_BOT->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->STRUCT_BOT --> +<g id="edge40" class="edge"> +<title>STRUCT_S1->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->STRUCT_S2 --> +<!-- STRUCT_S2->STRUCT_BOT --> +<g id="edge41" class="edge"> +<title>STRUCT_S2->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->STRUCT_SN --> +<!-- STRUCT_SN->STRUCT_BOT --> +<g id="edge42" class="edge"> +<title>STRUCT_SN->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->MEM_ALIAS1 --> +<g id="edge47" class="edge"> +<title>MEM_TOP->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->MEM_ALIASDOTS --> +<g id="edge48" class="edge"> +<title>MEM_TOP->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->MEM_ALIASN --> +<g id="edge49" class="edge"> +<title>MEM_TOP->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->BOT --> +<g id="edge53" class="edge"> +<title>MEM_BOT->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->MEM_BOT --> +<g id="edge50" class="edge"> +<title>MEM_ALIAS1->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->MEM_ALIASDOTS --> +<!-- MEM_ALIASDOTS->MEM_BOT --> +<g id="edge51" class="edge"> +<title>MEM_ALIASDOTS->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->MEM_ALIASN --> +<!-- MEM_ALIASN->MEM_BOT --> +<g id="edge52" class="edge"> +<title>MEM_ALIASN->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->TUPLE1 --> +<g id="edge57" class="edge"> +<title>TUPLE_TOP->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->TUPLE2 --> +<g id="edge58" class="edge"> +<title>TUPLE_TOP->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->TUPLEN --> +<g id="edge59" class="edge"> +<title>TUPLE_TOP->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->BOT --> +<g id="edge63" class="edge"> +<title>TUPLE_BOT->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->TUPLE_BOT --> +<g id="edge60" class="edge"> +<title>TUPLE1->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->TUPLE_BOT --> +<g id="edge61" class="edge"> +<title>TUPLE2->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->TUPLE_BOT --> +<g id="edge62" class="edge"> +<title>TUPLEN->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->PTRHQ -->
-<g id="edge1" class="edge">
-<title>TOP->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->VALH_ -->
-<g id="edge2" class="edge">
-<title>TOP->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->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->INTHQ -->
-<g id="edge3" class="edge">
-<title>TOP->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->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->PTRH_ -->
-<g id="edge8" class="edge">
-<title>PTRHQ->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->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->NILX_ -->
-<g id="edge12" class="edge">
-<title>PTRHQ->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_->INTHQ -->
-<!-- VALH_->PTRH_ -->
-<g id="edge7" class="edge">
-<title>VALH_->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_->INTH_ -->
-<g id="edge9" class="edge">
-<title>VALH_->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_->NIL__ -->
-<g id="edge13" class="edge">
-<title>VALH_->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_->VALL_ -->
-<!-- INTHQ->INTH_ -->
-<g id="edge10" class="edge">
-<title>INTHQ->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->INTH_ -->
-<!-- INTHQ->NILX_ -->
-<g id="edge11" class="edge">
-<title>INTHQ->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->VALH_ -->
-<!-- LEFTHI->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_->PTRL_ -->
-<g id="edge15" class="edge">
-<title>PTRH_->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_->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_->INTL_ -->
-<g id="edge16" class="edge">
-<title>INTH_->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_->INTL_ -->
-<!-- NILX_->NIL__ -->
-<!-- NILX_->VALL_ -->
-<g id="edge21" class="edge">
-<title>NILX_->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__->PTRL0 -->
-<g id="edge18" class="edge">
-<title>NIL__->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__->INTL0 -->
-<g id="edge23" class="edge">
-<title>NIL__->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_->PTRL0 -->
-<g id="edge17" class="edge">
-<title>PTRL_->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_->PTRL0 -->
-<!-- PTRL_->VALL_ -->
-<g id="edge19" class="edge">
-<title>PTRL_->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_->VALL_ -->
-<g id="edge20" class="edge">
-<title>INTL_->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_->INTL0 -->
-<g id="edge22" class="edge">
-<title>INTL_->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_->INTL0 -->
-<!-- PTRL0->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->BOT -->
-<g id="edge26" class="edge">
-<title>PTRL0->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_->INTL0 -->
-<!-- VALL_->BOT -->
-<g id="edge28" class="edge">
-<title>VALL_->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_->BOT -->
-<!-- INTL0->BOT -->
-<g id="edge27" class="edge">
-<title>INTL0->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->PTRHQ --> +<g id="edge1" class="edge"> +<title>TOP->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->VALH_ --> +<g id="edge2" class="edge"> +<title>TOP->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->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->INTHQ --> +<g id="edge3" class="edge"> +<title>TOP->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->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->PTRH_ --> +<g id="edge8" class="edge"> +<title>PTRHQ->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->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->NILX_ --> +<g id="edge12" class="edge"> +<title>PTRHQ->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_->INTHQ --> +<!-- VALH_->PTRH_ --> +<g id="edge7" class="edge"> +<title>VALH_->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_->INTH_ --> +<g id="edge9" class="edge"> +<title>VALH_->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_->NIL__ --> +<g id="edge13" class="edge"> +<title>VALH_->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_->VALL_ --> +<!-- INTHQ->INTH_ --> +<g id="edge10" class="edge"> +<title>INTHQ->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->INTH_ --> +<!-- INTHQ->NILX_ --> +<g id="edge11" class="edge"> +<title>INTHQ->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->VALH_ --> +<!-- LEFTHI->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_->PTRL_ --> +<g id="edge15" class="edge"> +<title>PTRH_->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_->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_->INTL_ --> +<g id="edge16" class="edge"> +<title>INTH_->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_->INTL_ --> +<!-- NILX_->NIL__ --> +<!-- NILX_->VALL_ --> +<g id="edge21" class="edge"> +<title>NILX_->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__->PTRL0 --> +<g id="edge18" class="edge"> +<title>NIL__->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__->INTL0 --> +<g id="edge23" class="edge"> +<title>NIL__->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_->PTRL0 --> +<g id="edge17" class="edge"> +<title>PTRL_->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_->PTRL0 --> +<!-- PTRL_->VALL_ --> +<g id="edge19" class="edge"> +<title>PTRL_->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_->VALL_ --> +<g id="edge20" class="edge"> +<title>INTL_->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_->INTL0 --> +<g id="edge22" class="edge"> +<title>INTL_->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_->INTL0 --> +<!-- PTRL0->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->BOT --> +<g id="edge26" class="edge"> +<title>PTRL0->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_->INTL0 --> +<!-- VALL_->BOT --> +<g id="edge28" class="edge"> +<title>VALL_->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_->BOT --> +<!-- INTL0->BOT --> +<g id="edge27" class="edge"> +<title>INTL0->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; |
