summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCliff Click <cliffc@acm.org>2025-04-24 14:42:24 -0700
committerCliff Click <cliffc@acm.org>2025-04-24 14:42:24 -0700
commit7aed4a93e6a863dbe996a717cdd0ca45f1b8e5c7 (patch)
tree480ba4d027f2bcad53de089312c73fb86bbcfccb
parent00389065a6f626b4d8504944147e98ecc24d0480 (diff)
parent5d026780154ddd9ca111303df4dce9eac1c2d1c2 (diff)
downloadSimple-7aed4a93e6a863dbe996a717cdd0ca45f1b8e5c7.tar.gz
Simple-7aed4a93e6a863dbe996a717cdd0ca45f1b8e5c7.zip
Merge branch 'main' into ch22
-rw-r--r--README.md2
-rw-r--r--chapter21/simple0
-rw-r--r--chapter21/src/main/java/com/seaofnodes/simple/codegen/CodeGen.java9
-rw-r--r--chapter21/src/main/java/com/seaofnodes/simple/codegen/Encoding.java10
-rw-r--r--chapter21/src/main/java/com/seaofnodes/simple/node/LoopNode.java14
-rw-r--r--chapter21/src/main/java/com/seaofnodes/simple/node/PhiNode.java4
-rw-r--r--chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/AddARM.java2
-rw-r--r--chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/AddIARM.java2
-rw-r--r--chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/AndARM.java2
-rw-r--r--chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/AndIARM.java4
-rw-r--r--chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/AsrARM.java2
-rw-r--r--chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/AsrIARM.java2
-rw-r--r--chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/DivARM.java2
-rw-r--r--chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/LoadARM.java16
-rw-r--r--chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/LslARM.java2
-rw-r--r--chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/LslIARM.java2
-rw-r--r--chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/LsrARM.java2
-rw-r--r--chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/LsrIARM.java2
-rw-r--r--chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/MemOpARM.java8
-rw-r--r--chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/MulARM.java2
-rw-r--r--chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/NegARM.java2
-rw-r--r--chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/NewARM.java16
-rw-r--r--chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/NotARM.java2
-rw-r--r--chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/OrARM.java2
-rw-r--r--chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/OrIARM.java2
-rw-r--r--chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/SetARM.java2
-rw-r--r--chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/SplitARM.java4
-rw-r--r--chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/StoreARM.java16
-rw-r--r--chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/SubARM.java2
-rw-r--r--chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/SubIARM.java6
-rw-r--r--chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/XorARM.java2
-rw-r--r--chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/XorIARM.java2
-rw-r--r--chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/arm.java186
-rw-r--r--chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/NewRISC.java8
-rw-r--r--chapter21/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/NewX86.java8
-rw-r--r--chapter21/src/main/java/com/seaofnodes/simple/print/ASMPrinter.java2
-rw-r--r--chapter21/src/test/java/com/seaofnodes/simple/BrainFuckTest.java12
-rw-r--r--chapter21/src/test/java/com/seaofnodes/simple/Chapter20Test.java2
-rw-r--r--chapter21/src/test/java/com/seaofnodes/simple/Chapter21Test.java39
-rw-r--r--chapter21/src/test/java/com/seaofnodes/simple/EvalArm64.java437
-rw-r--r--chapter21/src/test/java/com/seaofnodes/simple/EvalRisc5.java19
-rw-r--r--chapter21/src/test/java/com/seaofnodes/simple/TestArm64.java10
-rw-r--r--chapter21/src/test/java/com/seaofnodes/simple/TestRisc5.java6
-rw-r--r--chapter21/src/test/java/com/seaofnodes/simple/progs/jig.smp9
-rw-r--r--chapter21/src/test/java/com/seaofnodes/simple/progs/sieve.smp2
45 files changed, 692 insertions, 195 deletions
diff --git a/README.md b/README.md
index 79b289ad..a00b4a90 100644
--- a/README.md
+++ b/README.md
@@ -65,5 +65,5 @@ The Simple language is styled after a subset of C or Java.
* [Chapter 19](chapter19/README.md): Instruction selection and portable compilation
* [Chapter 20](chapter20/README.md): Graph Coloring Register Allocation
* [Chapter 21](chapter21/README.md): Instruction Encodings & ELF
-* [Chapter 22](chapter22/README.md): Strings And Such
+* [Chapter 22](chapter22/README.md): Strings And I/O
diff --git a/chapter21/simple b/chapter21/simple
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/chapter21/simple
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 91553f38..86cbfe97 100644
--- a/chapter21/src/main/java/com/seaofnodes/simple/codegen/CodeGen.java
+++ b/chapter21/src/main/java/com/seaofnodes/simple/codegen/CodeGen.java
@@ -421,6 +421,15 @@ public class CodeGen {
// Debugging helper
public Node f(int idx) { return _stop.find(idx); }
+
+ String printCFG() {
+ if( _cfg==null ) return "no CFG";
+ SB sb = new SB();
+ for( CFGNode cfg : _cfg )
+ IRPrinter.printLine(cfg,sb);
+ return sb.toString();
+ }
+
public static void print_as_hex(Encoding enc) {
for (byte b : enc._bits.toByteArray()) {
System.out.print(String.format("%02X", b));
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 3d6cd209..d7057839 100644
--- a/chapter21/src/main/java/com/seaofnodes/simple/codegen/Encoding.java
+++ b/chapter21/src/main/java/com/seaofnodes/simple/codegen/Encoding.java
@@ -459,7 +459,7 @@ public class Encoding {
// A series of libc/external calls that Simple can link against in a JIT.
// Since no runtime in the JVM process, using magic numbers for the CPU
// emulators to pick up on.
- public static int SENTINAL_CALLOC = -2;
+ public static int SENTINAL_CALLOC = -4;
void patchGlobalRelocations() {
for( Node src : _externals.keySet() ) {
@@ -472,12 +472,4 @@ public class Encoding {
((RIPRelSize)src).patch(this, start, _opLen[src._nid], target - start);
}
}
-
- String printCFG() {
- if( _code._cfg==null ) return "no CFG";
- SB sb = new SB();
- for( CFGNode cfg : _code._cfg )
- IRPrinter.printLine(cfg,sb);
- return sb.toString();
- }
}
diff --git a/chapter21/src/main/java/com/seaofnodes/simple/node/LoopNode.java b/chapter21/src/main/java/com/seaofnodes/simple/node/LoopNode.java
index 1ba182b9..cacf9c99 100644
--- a/chapter21/src/main/java/com/seaofnodes/simple/node/LoopNode.java
+++ b/chapter21/src/main/java/com/seaofnodes/simple/node/LoopNode.java
@@ -58,20 +58,10 @@ public class LoopNode extends RegionNode {
// XCtrl or a bunch of prior NeverNode exits.
Node top = new ConstantNode(Type.TOP).peephole();
Node memout = new MemMergeNode(false);
- memout.addDef(null); // placeholder for control
+ memout.addDef(f); // placeholder for control
for( Node u : _outputs )
if( u instanceof PhiNode phi && phi._type.isa(TypeMem.BOT) )
memout.addDef(phi);
- if( memout.nIns()>2 )
- memout.setDef(0, ret.cfg0());
- else {
- if( memout.nIns()==1 ) memout=top;
- else {
- Node tmp=memout;
- memout=memout.in(1);
- tmp.setDef(1, null);
- }
- }
Node ctrl = ret.ctrl(), mem = ret.mem(), expr = ret.expr();
if( ctrl!=null && ctrl._type != Type.XCONTROL ) {
@@ -81,7 +71,7 @@ public class LoopNode extends RegionNode {
expr instanceof PhiNode prez && prez.region()==r ) ) {
// Nope, insert an aligned exit layer
RegionNode r = new RegionNode(_loc,null,ctrl).init();
- ctrl = r; r._ltree = _ltree;
+ ctrl = r; r._ltree = stop._ltree;
mem = new PhiNode(r,mem ).init();
expr = new PhiNode(r,expr).init();
}
diff --git a/chapter21/src/main/java/com/seaofnodes/simple/node/PhiNode.java b/chapter21/src/main/java/com/seaofnodes/simple/node/PhiNode.java
index ed46c8f9..0579ecd0 100644
--- a/chapter21/src/main/java/com/seaofnodes/simple/node/PhiNode.java
+++ b/chapter21/src/main/java/com/seaofnodes/simple/node/PhiNode.java
@@ -122,7 +122,9 @@ public class PhiNode extends Node {
if( in(1).getClass() != op.getClass() || op.in(0)!=null || in(1).nIns() != op.nIns() )
return false; // Wrong class or CFG bound or mismatched inputs
if( op.nOuts() > 1 ) { // Too many users, but addDep in case lose users
- for( Node out : op._outputs ) if( out!=null ) addDep(out);
+ for( Node out : op._outputs )
+ if( out!=null && out!=this )
+ addDep(out);
return false;
}
}
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 205ab6e4..f37738bf 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
@@ -8,7 +8,7 @@ public class AddARM extends MachConcreteNode implements MachNode {
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; }
+ @Override public RegMask outregmap() { return arm.WMASK; }
// ADD (shifted register)
@Override public void encoding( Encoding enc ) { arm.r_reg(enc,this,arm.OP_ADD); }
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 fe4ecead..a1cd8306 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
@@ -15,7 +15,7 @@ public class AddIARM extends MachConcreteNode implements MachNode {
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 RegMask outregmap() { return arm.WMASK; }
//ADD (immediate)
@Override public void encoding( Encoding enc ) {
arm.imm_inst(enc,this, in(1), arm.OPI_ADD,_imm);
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 d125174b..ad76ca4c 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
@@ -11,7 +11,7 @@ public class AndARM extends MachConcreteNode implements MachNode {
@Override public String op() { return "and"; }
@Override public String glabel() { return "&"; }
@Override public RegMask regmap(int i) { return arm.RMASK; }
- @Override public RegMask outregmap() { return arm.RMASK; }
+ @Override public RegMask outregmap() { return arm.WMASK; }
// AND (shifted register)
@Override public void encoding( Encoding enc ) { arm.r_reg(enc,this,arm.OP_AND); }
// General form: #rd = rs1 & rs2
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
index 76f5fa39..1f12ef13 100644
--- 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
@@ -13,12 +13,12 @@ public class AndIARM extends MachConcreteNode implements MachNode {
}
@Override public String op() { return "andi"; }
@Override public RegMask regmap(int i) { return arm.RMASK; }
- @Override public RegMask outregmap() { return arm.RMASK; }
+ @Override public RegMask outregmap() { return arm.WMASK; }
@Override public void encoding( Encoding enc ) {
arm.imm_inst_n(enc,this, in(1), arm.OPI_AND,_imm);
}
// 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(" & #").p(_imm);
+ sb.p(code.reg(this)).p(" = ").p(code.reg(in(1))).p(" & #").p(arm.decodeImm12(_imm));
}
} \ 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 b1603338..342b7519 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
@@ -9,7 +9,7 @@ public class AsrARM extends MachConcreteNode implements MachNode {
AsrARM(Node asr) {super(asr);}
@Override public String op() { return "sar"; }
@Override public RegMask regmap(int i) { return arm.RMASK; }
- @Override public RegMask outregmap() { return arm.RMASK; }
+ @Override public RegMask outregmap() { return arm.DMASK; }
@Override public void encoding( Encoding enc ) { arm.shift_reg(enc,this,arm.OP_ASR); }
@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/arm/AsrIARM.java b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/AsrIARM.java
index eb535201..a1775dde 100644
--- 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
@@ -17,7 +17,7 @@ public class AsrIARM extends MachConcreteNode implements MachNode {
}
@Override public String op() { return "asri"; }
@Override public RegMask regmap(int i) { return arm.RMASK; }
- @Override public RegMask outregmap() { return arm.RMASK; }
+ @Override public RegMask outregmap() { return arm.WMASK; }
@Override public void encoding( Encoding enc ) {
short rd = enc.reg(this);
short rn = enc.reg(in(1));
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 8b8af5c3..40bd8387 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
@@ -8,7 +8,7 @@ public class DivARM extends MachConcreteNode implements MachNode {
DivARM( Node div ) { super(div); }
@Override public String op() { return "div"; }
@Override public RegMask regmap(int i) { return arm.RMASK; }
- @Override public RegMask outregmap() { return arm.RMASK; }
+ @Override public RegMask outregmap() { return arm.WMASK; }
// SDIV
@Override public void encoding( Encoding enc ) { arm.madd(enc,this,arm.OP_DIV,3); }
// General form: "div dst /= src"
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 daf221f3..44c13321 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
@@ -18,13 +18,19 @@ public class LoadARM extends MemOpARM {
}
@Override public String op() { return "ld"+_sz; }
@Override public RegMask outregmap() { return arm.MEM_MASK; }
+
+ private static final int[] OP_LOADS = new int[]{ arm.OP_LOAD_IMM_8, arm.OP_LOAD_IMM_16, arm.OP_LOAD_IMM_32, arm.OP_LOAD_IMM_64, };
+ private int imm_op() {
+ return _declaredType == TypeFloat.F32 ? arm.OPF_LOAD_IMM_32
+ : _declaredType == TypeFloat.F64 ? arm.OPF_LOAD_IMM_64
+ : OP_LOADS[_declaredType.log_size()];
+ }
+
+ private static final int[] OP_LOAD_RS = new int[]{ arm.OP_LOAD_R_8 , arm.OP_LOAD_R_16 , arm.OP_LOAD_R_32 , arm.OP_LOAD_R_64, };
+
// ldr(immediate - unsigned offset) | ldr(register)
@Override public void encoding( Encoding enc ) {
- if(_declaredType == TypeFloat.F32 || _declaredType == TypeFloat.F64) {
- ldst_encode(enc, arm.OPF_LOAD_IMM, arm.OPF_LOAD_R, this, true);
- } else {
- ldst_encode(enc, arm.OP_LOAD_IMM, arm.OP_LOAD_R, this, false);
- }
+ ldst_encode(enc, imm_op(), OP_LOAD_RS[_declaredType.log_size()], this, size());
}
@Override public void asm(CodeGen code, SB sb) {
sb.p(code.reg(this)).p(",");
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 5c664c40..055d6dcc 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
@@ -9,7 +9,7 @@ public class LslARM extends MachConcreteNode implements MachNode {
LslARM(Node asr) {super(asr);}
@Override public String op() { return "shr"; }
@Override public RegMask regmap(int i) { return arm.RMASK; }
- @Override public RegMask outregmap() { return arm.RMASK; }
+ @Override public RegMask outregmap() { return arm.WMASK; }
@Override public void encoding( Encoding enc ) { arm.shift_reg(enc,this,arm.OP_LSL); }
@Override public void asm(CodeGen code, SB sb) {
diff --git a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/LslIARM.java b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/LslIARM.java
index 5e35b4c0..94d3e25b 100644
--- a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/LslIARM.java
+++ b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/LslIARM.java
@@ -17,7 +17,7 @@ public class LslIARM extends MachConcreteNode implements MachNode {
}
@Override public String op() { return "lsli"; }
@Override public RegMask regmap(int i) { return arm.RMASK; }
- @Override public RegMask outregmap() { return arm.RMASK; }
+ @Override public RegMask outregmap() { return arm.WMASK; }
@Override public void encoding( Encoding enc ) {
short rd = enc.reg(this);
short rn = enc.reg(in(1));
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 f22c1264..a691e0fe 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
@@ -9,7 +9,7 @@ public class LsrARM extends MachConcreteNode implements MachNode {
LsrARM(Node asr) {super(asr);}
@Override public String op() { return "shr"; }
@Override public RegMask regmap(int i) { return arm.RMASK; }
- @Override public RegMask outregmap() { return arm.RMASK; }
+ @Override public RegMask outregmap() { return arm.WMASK; }
@Override public void encoding( Encoding enc ) { arm.shift_reg(enc,this,arm.OP_LSR); }
@Override public void asm(CodeGen code, SB sb) {
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
index e349d46f..094cd30f 100644
--- 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
@@ -15,7 +15,7 @@ public class LsrIARM extends MachConcreteNode implements MachNode {
}
@Override public String op() { return "lsri"; }
@Override public RegMask regmap(int i) { return arm.RMASK; }
- @Override public RegMask outregmap() { return arm.RMASK; }
+ @Override public RegMask outregmap() { return arm.WMASK; }
@Override public void encoding( Encoding enc ) {
short rd = enc.reg(this);
short rn = enc.reg(in(1));
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 d0ae385a..6d8344a2 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
@@ -29,7 +29,7 @@ public abstract class MemOpARM extends MemOpNode implements MachNode {
_inputs.setX(4,val);
}
- @Override public String label() { return op(); }
+ @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); }
@@ -37,6 +37,8 @@ public abstract class MemOpARM extends MemOpNode implements MachNode {
@Override public Type compute() { throw Utils.TODO(); }
@Override public Node idealize() { throw Utils.TODO(); }
+ int size() { return 1<<_declaredType.log_size(); }
+
// Wider mask to store both GPRs and FPRs
@Override public RegMask regmap(int i) {
// 0 - ctrl
@@ -48,12 +50,12 @@ public abstract class MemOpARM extends MemOpNode implements MachNode {
}
// Shared encoding for loads and stores(int and float)
- public void ldst_encode( Encoding enc, int opcode_imm, int opcode_reg, Node xval, boolean float_type ) {
+ public void ldst_encode( Encoding enc, int opcode_imm, int opcode_reg, Node xval, int size) {
short ptr = enc.reg(ptr());
short off = enc.reg(off());
short val = enc.reg(xval);
int body = off() == null
- ? arm.load_str_imm(opcode_imm, _off, ptr, val)
+ ? arm.load_str_imm(opcode_imm, _off, ptr, val, size)
: arm.indr_adr(opcode_reg, off, arm.STORE_LOAD_OPTION.SXTX, 0, ptr, val);
enc.add4(body);
}
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 261327cb..3514db9b 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
@@ -9,7 +9,7 @@ public class MulARM extends MachConcreteNode implements MachNode {
MulARM(Node mul) {super(mul);}
@Override public String op() { return "mul"; }
@Override public RegMask regmap(int i) { return arm.RMASK; }
- @Override public RegMask outregmap() { return arm.RMASK; }
+ @Override public RegMask outregmap() { return arm.WMASK; }
@Override public void encoding( Encoding enc ) { arm.madd(enc,this,arm.OP_MUL,31); }
// General form: "rd = rs1 * rs2"
diff --git a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/NegARM.java b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/NegARM.java
index 74289797..b7c3c803 100644
--- a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/NegARM.java
+++ b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/NegARM.java
@@ -13,7 +13,7 @@ public class NegARM extends MachConcreteNode implements MachNode {
}
@Override public String op() { return "neg"; }
@Override public RegMask regmap(int i) { return arm.RMASK; }
- @Override public RegMask outregmap() { return arm.RMASK; }
+ @Override public RegMask outregmap() { return arm.WMASK; }
@Override public void encoding( Encoding enc ) {
// reverse subtract with immediate 0
arm.imm_inst(enc,this, in(1), 0b00100110, 0);
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 967847a9..cb51eea2 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
@@ -9,20 +9,28 @@ public class NewARM extends NewNode implements MachNode, RIPRelSize {
NewARM(NewNode nnn) { super(nnn); }
@Override public void encoding( Encoding enc ) {
// BL(branch with link)
- enc.external(this,"calloc").add4(arm.b(arm.OP_CALL, 0));
+ enc.external(this,"calloc").
+ add4(arm.mov(arm.OP_MOVZ, 0, 1, 0)). // movz x0,#1
+ add4(arm.b(arm.OP_CALL, 0));
}
// Patch is for running "new" in a JIT.
// Delta is from opcode start
- @Override public byte encSize(int delta) { return 4; }
+ @Override public byte encSize(int delta) { return 4*2; }
// Patch is for running "new" in a JIT.
// Delta is from opcode start
@Override public void patch(Encoding enc, int opStart, int opLen, int delta ) {
- if((delta & 3) != 0) {
- enc.patch4(opStart, arm.b_calloc(arm.OP_CALL, delta));
+ // Negative patches are JIT emulator targets.
+ if( opStart+delta < 0 ) {
+ enc.patch4(opStart+4, arm.b_calloc(arm.OP_CALL, delta-4));
} else {
throw Utils.TODO();
}
}
+ // General form: "alloc #bytes PC"
+ @Override public void asm(CodeGen code, SB sb) {
+ sb.p("ldi x0=#1\n");
+ sb.p("call #calloc");
+ }
}
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
index 7efae38d..5a8d882d 100644
--- 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
@@ -10,7 +10,7 @@ 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 outregmap() { return arm.WMASK; }
@Override public RegMask killmap() { return arm.FLAGS_MASK; }
@Override public void encoding( Encoding enc ) {
// subs xzr, rs, #0
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 593c0c6c..b5cfa8cf 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
@@ -10,7 +10,7 @@ public class OrARM extends MachConcreteNode implements MachNode {
@Override public String op() { return "or"; }
@Override public String glabel() { return "|"; }
@Override public RegMask regmap(int i) { return arm.RMASK; }
- @Override public RegMask outregmap() { return arm.RMASK; }
+ @Override public RegMask outregmap() { return arm.WMASK; }
@Override public void encoding( Encoding enc ) { arm.r_reg(enc,this,arm.OP_OR); }
// General form: #rd = rs1 & rs2
@Override public void asm(CodeGen code, SB sb) {
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
index f6f4e472..2a2d199a 100644
--- 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
@@ -13,7 +13,7 @@ public class OrIARM extends MachConcreteNode implements MachNode {
}
@Override public String op() { return "ori"; }
@Override public RegMask regmap(int i) { return arm.RMASK; }
- @Override public RegMask outregmap() { return arm.RMASK; }
+ @Override public RegMask outregmap() { return arm.WMASK; }
@Override public void encoding( Encoding enc ) {
arm.imm_inst_n(enc, this, in(1), arm.OPI_OR, _imm);
}
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 52f448df..246e482a 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
@@ -17,7 +17,7 @@ public class SetARM extends MachConcreteNode implements MachNode {
}
@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; }
+ @Override public RegMask outregmap() { return arm.WMASK; }
@Override public void encoding( Encoding enc ) {
int body = arm.cset(arm.OP_CSET,0b11111, arm.make_condition(_bop), 0b011111, enc.reg(this));
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 ba39eead..62bb75aa 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
@@ -27,7 +27,7 @@ public class SplitARM extends SplitNode {
}
int off = enc._fun.computeStackOffset(enc._code,dst);
if( srcX ) src -= arm.D_OFFSET;
- enc.add4(arm.load_str_imm(arm.OP_STORE_IMM, off, arm.RSP, src));
+ enc.add4(arm.load_str_imm(arm.OP_STORE_IMM_64, off, arm.RSP, src, 8));
return;
}
@@ -35,7 +35,7 @@ public class SplitARM extends SplitNode {
// Load from SP
int off = enc._fun.computeStackOffset(enc._code,src);
if( dstX ) dst -= arm.D_OFFSET;
- enc.add4(arm.load_str_imm(arm.OP_LOAD_IMM, off, arm.RSP, dst));
+ enc.add4(arm.load_str_imm(arm.OP_LOAD_IMM_64, off, arm.RSP, dst, 8));
return;
}
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 ffeac3eb..688d8731 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
@@ -22,12 +22,18 @@ public class StoreARM extends MemOpARM {
}
@Override public String op() { return "st"+_sz; }
@Override public RegMask outregmap() { return null; }
+
+ private static final int[] OP_STORES = new int[]{ arm.OP_STORE_IMM_8, arm.OP_STORE_IMM_16, arm.OP_STORE_IMM_32, arm.OP_STORE_IMM_64, };
+ private int imm_op() {
+ return _declaredType == TypeFloat.F32 ? arm.OPF_STORE_IMM_32
+ : _declaredType == TypeFloat.F64 ? arm.OPF_STORE_IMM_64
+ : OP_STORES[_declaredType.log_size()];
+ }
+
+ private static final int[] OP_STORE_RS = new int[]{ arm.OP_STORE_R_8, arm.OP_STORE_R_16, arm.OP_STORE_R_32, arm.OP_STORE_R_64, };
+
@Override public void encoding( Encoding enc ) {
- if(_declaredType == TypeFloat.F32 || _declaredType == TypeFloat.F64) {
- ldst_encode(enc, arm.OPF_STORE_IMM,arm.OPF_STORE_R, val(), true);
- } else {
- ldst_encode(enc, arm.OP_STORE_IMM, arm.OP_STORE_R, val(), false);
- }
+ ldst_encode(enc, imm_op(), OP_STORE_RS[_declaredType.log_size()], val(), size());
}
@Override public void asm(CodeGen code, SB sb) {
asm_address(code,sb).p(",");
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 feb59853..552b46df 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
@@ -8,7 +8,7 @@ public class SubARM extends MachConcreteNode implements MachNode {
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; }
+ @Override public RegMask outregmap() { return arm.WMASK; }
@Override public void encoding( Encoding enc ) { arm.r_reg(enc,this,arm.OP_SUB); }
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
index 29ce71b6..b882c5a4 100644
--- 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
@@ -16,9 +16,11 @@ public class SubIARM extends MachConcreteNode implements MachNode {
}
@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; }
+ @Override public RegMask outregmap() { return arm.WMASK; }
- @Override public void encoding( Encoding enc ) { arm.imm_inst(enc,this, in(1), 0b1101000100,_imm); }
+ @Override public void encoding( Encoding enc ) {
+ arm.imm_inst(enc,this, in(1), arm.OPI_SUB,_imm);
+ }
// General form: "subi rd = rs1 - imm"
@Override public void asm(CodeGen code, SB sb) {
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 9afd2e5d..ec86cfa5 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
@@ -9,7 +9,7 @@ public class XorARM extends MachConcreteNode implements MachNode{
@Override public String op() { return "xor"; }
@Override public String glabel() { return "^"; }
@Override public RegMask regmap(int i) { return arm.RMASK; }
- @Override public RegMask outregmap() { return arm.RMASK; }
+ @Override public RegMask outregmap() { return arm.WMASK; }
@Override public void encoding( Encoding enc ) { arm.r_reg(enc,this,arm.OP_XOR); }
// General form: "rd = x1 ^ x2"
@Override public void asm(CodeGen code, SB sb) {
diff --git a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/XorIARM.java b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/XorIARM.java
index 95e2c932..e2582d22 100644
--- a/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/XorIARM.java
+++ b/chapter21/src/main/java/com/seaofnodes/simple/node/cpus/arm/XorIARM.java
@@ -17,7 +17,7 @@ public class XorIARM extends MachConcreteNode implements MachNode {
@Override public String op() { return "xori"; }
@Override public RegMask regmap(int i) { return arm.RMASK; }
- @Override public RegMask outregmap() { return arm.RMASK; }
+ @Override public RegMask outregmap() { return arm.WMASK; }
// General form: "xori rd = rs1 ^ imm"
@Override public void encoding( Encoding enc ) { arm.imm_inst_n(enc,this, in(1), arm.OPI_XOR,_imm); }
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 fabfe2fe..104929f4 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
@@ -31,15 +31,15 @@ public class arm extends Machine {
public static final int D_OFFSET = 32;
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[] regs() { return REGS; }
@@ -60,8 +60,6 @@ public class arm extends Machine {
static final RegMask SPLIT_MASK = new RegMask(WR_BITS | FP_BITS, -2L/*skip flags*/);
static final RegMask FLAGS_MASK = new RegMask(FLAGS);
- // x30 (LR): Procedure link register, used to return from subroutines.
- //static final RegMask RPC_MASK = new RegMask(1L << X30);
// Arguments masks
static final RegMask X0_MASK = new RegMask(X0);
@@ -89,6 +87,7 @@ public class arm extends Machine {
public static int OPF_OP_ADD = 0b00_101_0;
public static int OPI_ADD = 0b10_010_00100;
+ public static int OPI_SUB = 0b11_010_00100;
public static int OP_UJMP = 0b000101;
public static int OP_ADRP = 0b10000;
@@ -140,17 +139,39 @@ public class arm extends Machine {
public static int OP_RET = 0b1101011001011111000000;
// Store/load opcodes
- public static int OP_LOAD_R = 0b11111000011;
- public static int OP_LOAD_IMM = 0b1111100101;
+ public static int OP_LOAD_R_64 = 0b11111000011;
+ public static int OP_LOAD_R_32 = 0b10111000011;
+ public static int OP_LOAD_R_16 = 0b01111000010;
+ public static int OP_LOAD_R_8 = 0b00111000011;
- public static int OPF_LOAD_R = 0b11111100011;
- public static int OPF_LOAD_IMM = 0b1111110101;
+ public static int OP_LOAD_IMM_64 = 0b1111100101;
+ public static int OP_LOAD_IMM_32 = 0b1011100101;
+ public static int OP_LOAD_IMM_16 = 0b0111100101;
+ public static int OP_LOAD_IMM_8 = 0b0011100101;
- public static int OP_STORE_R = 0b11111000001;
- public static int OP_STORE_IMM = 0b1111100100;
+ // load
+ public static int OPF_LOAD_R_64 = 0b11111100011;
+ public static int OPF_LOAD_R_32 = 0b10111100011;
+
+ public static int OPF_LOAD_IMM_64 = 0b1111110101;
+ public static int OPF_LOAD_IMM_32 = 0b1011110101;
+
+ public static int OP_STORE_R_64 = 0b11111000001;
+ public static int OP_STORE_R_32 = 0b10111000001;
+ public static int OP_STORE_R_16 = 0b01111000001;
+ public static int OP_STORE_R_8 = 0b00111000001;
+
+ public static int OP_STORE_IMM_64 = 0b1111100100;
+ public static int OP_STORE_IMM_32 = 0b1011100100;
+ public static int OP_STORE_IMM_16 = 0b0111100100;
+ public static int OP_STORE_IMM_8 = 0b0011100100;
+
+ public static int OPF_STORE_R_64 = 0b11111100001;
+ public static int OPF_STORE_R_32 = 0b10111100001;
+
+ public static int OPF_STORE_IMM_32 = 0b1111110100;
+ public static int OPF_STORE_IMM_64 = 0b1111110100;
- public static int OPF_STORE_R = 0b11111100001;
- public static int OPF_STORE_IMM = 0b1111110100;
public static int OP_FMOV = 0b10011110;
public static int OP_FMOV_REG = 0b00011110;
@@ -160,24 +181,24 @@ 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,
};
// ARM ENCODING
@@ -251,10 +272,16 @@ public class arm extends Machine {
if (val == 0 || val == -1) return -1; // Special cases are not allowed
int immr = 0;
// Rotate until we have 0[...]1
+
+ // Rotate until:
+ // The number is negative (MSB is 1)
+ // Or the LSB is not 1
while (val < 0 || (val & 1)==0) {
+ // circular rotation
val = (val >>> 63) | (val << 1);
immr++;
}
+ // Start by assuming that val might be made of two 32-bit chunks that repeat.
int size = 32;
long pattern = val;
// Is upper half of pattern the same as the lower?
@@ -289,6 +316,7 @@ public class arm extends Machine {
public static void imm_inst(Encoding enc, Node n,Node n2, int opcode, int imm12) {
short self = enc.reg(n);
short reg1 = enc.reg(n2);
+
int body = imm_inst(opcode, imm12&0xFFF, reg1, self);
enc.add4(body);
}
@@ -309,7 +337,6 @@ public class arm extends Machine {
public static void imm_inst_n(Encoding enc, Node n, Node n2, int opcode, int imm13) {
short self = enc.reg(n);
short reg1 = enc.reg(n2);
-
int body = imm_inst_n(opcode, imm13, reg1, self);
enc.add4(body);
}
@@ -325,7 +352,7 @@ public class arm extends Machine {
public static int imm_inst_l(int opcode, int imm12, int self) {
int body = imm_inst(opcode, imm12&0xFFF, self, self);
return body;
- }
+ }
// for cases where rs1 and dst are the same, eg add x0, x0, 1
public static int imm_inst_l(Encoding enc, Node n, int opcode, int imm12) {
@@ -342,14 +369,14 @@ public class arm extends Machine {
assert 0 <= rn && rn < 32;
assert 0 <= rd && rd < 32;
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 >= 32 ? reg1: self);
- enc.add4(body);
- }
+ }
+ 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 >= 32 ? reg1: self);
+ enc.add4(body);
+ }
public static void r_reg_subs(Encoding enc, Node n, int opcode) {
short reg1 = enc.reg(n.in(1));
@@ -447,10 +474,15 @@ public class arm extends Machine {
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 imm12, int ptr, int rt) {
+ public static int load_str_imm(int opcode, int imm12, int ptr, int rt, int size) {
assert 0 <= ptr && ptr < 32;
assert 0 <= rt && rt < 32;
- return (opcode << 22) | (imm12 << 10) |(ptr << 5) | rt;
+
+ if(size == 8) imm12 = imm12 >> 3;
+ if(size == 4) imm12 = imm12 >> 2;
+ if(size == 2) imm12 = imm12 >> 1;
+ // size == 1 imm12 = imm12
+ return (opcode << 22) | ((imm12) << 10) | (ptr << 5) | rt;
}
// encoding for vcvt, size is encoded in operand
@@ -523,7 +555,7 @@ public class arm extends Machine {
delta &= (1L<<26)-1; // Zero extend
return (opcode << 26) | delta;
}
- // no aligned assert
+ // no aligned assert(assert (delta&3)==0;)
public static int b_calloc(int opcode, int delta) {
assert -(1<<26) <= delta && delta < (1<<26);
delta>>=2;
@@ -551,6 +583,30 @@ public class arm extends Machine {
}
throw Utils.TODO(); // Pass on stack slot
}
+
+ public static long decodeImm12(int imm12) {
+ int immr = (imm12 >> 6) & 0x3F;
+ int imms = imm12 & 0x3F;
+ int size;
+ if ((imm12 & 0x1000) != 0) {
+ size = 64;
+ } else {
+ size = 31-(imms >> 1);
+ size |= size >> 1;
+ size |= size >> 2;
+ size |= size >> 4;
+ size++;
+ imms &= ~((32-size) << 1);
+ }
+ long val = (2L << imms)-1;
+ while (size < 64) {
+ val |= val << size;
+ size <<= 1;
+ }
+ val = (val >>> immr) | val << (64-immr);
+ return val;
+ }
+
// Return the max stack slot used by this signature, or 0
@Override public short maxArgSlot( TypeFunPtr tfp ) {
int icnt=0, fcnt=0; // Count of ints, floats
@@ -639,8 +695,8 @@ public class arm extends Machine {
if( bool.isFloat() )
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);
+ ? new CmpIARM(bool, (int)ti.value())
+ : new CmpARM(bool);
}
private Node ld(LoadNode ld) {
@@ -660,40 +716,40 @@ public class arm extends Machine {
private Node add(AddNode add) {
return add.in(2) instanceof ConstantNode off && off._con instanceof TypeInteger ti && imm12(ti)
- ? new AddIARM(add, (int)ti.value())
- : new AddARM(add);
+ ? 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 && imm12(ti)
- ? new AddIARM(sub, (int)(-ti.value()))
- : new SubARM(sub);
+ ? 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 -> t==Type.NIL ? new IntARM(con) : 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 -> t==Type.NIL ? new IntARM(con) : new ConstantNode(con);
};
}
private Node call(CallNode call){
return call.fptr() instanceof ConstantNode con && con._con instanceof TypeFunPtr tfp
- ? new CallARM(call, tfp)
- : new CallRRARM(call);
+ ? new CallARM(call, tfp)
+ : new CallRRARM(call);
}
private Node or(OrNode or) {
int imm12;
return or.in(2) instanceof ConstantNode off && off._con instanceof TypeInteger ti && (imm12 = imm12Logical(ti)) != -1
- ? new OrIARM(or, imm12)
- : new OrARM(or);
+ ? new OrIARM(or, imm12)
+ : new OrARM(or);
}
private Node xor(XorNode xor) {
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 3b0018c2..e395a811 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
@@ -25,11 +25,9 @@ public class NewRISC extends NewNode implements MachNode, RIPRelSize {
// Patch is for running "new" in a JIT.
// Delta is from opcode start
@Override public void patch( Encoding enc, int opStart, int opLen, int delta ) {
- // Odd-number patches are JIT emulator targets.
- if( (delta&3)!=0 ) {
- //enc.patch4(opStart+4, riscv.i_type(riscv.OP_IMM, riscv.ZERO , 0, riscv.ZERO, 0));
- //enc.patch4(opStart,riscv.j_type(riscv.OP_JAL, riscv.RPC, opStart+delta));
-
+ // Negative patches are JIT emulator targets.
+ if( opStart+delta < 0 ) {
+ delta -= 4; // Offset from the AUIPC start
int imm20 = delta>>12;
if( ((delta>>11)&1)==1 ) imm20++; // Correct accidental sign extension
int imm12 = delta&0xFFF;
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 170fc8c5..0439adfd 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
@@ -10,12 +10,16 @@ public class NewX86 extends NewNode implements MachNode {
NewX86( NewNode nnn ) { super(nnn); }
@Override public void encoding( Encoding enc ) {
enc.external(this,"calloc");
- // This has to call the *native* ABI, regardless of how Simple is
- // being compiled, because it links against the native calloc.
// ldi rcx,#1 // number of elements to calloc
enc.add1(0xB8 + _arg2Reg).add4(1);
// E8 cd CALL rel32;
enc.add1(0xE8);
enc.add4(0); // offset
}
+ // General form: "alloc #bytes PC"
+ @Override public void asm(CodeGen code, SB sb) {
+ sb.p("ldi rcx = #1\n");
+ sb.p("call #calloc");
+ }
+
}
diff --git a/chapter21/src/main/java/com/seaofnodes/simple/print/ASMPrinter.java b/chapter21/src/main/java/com/seaofnodes/simple/print/ASMPrinter.java
index cf3bdde3..da269d31 100644
--- a/chapter21/src/main/java/com/seaofnodes/simple/print/ASMPrinter.java
+++ b/chapter21/src/main/java/com/seaofnodes/simple/print/ASMPrinter.java
@@ -235,7 +235,7 @@ public abstract class ASMPrinter {
for( int i=0; i<len; i++ )
sb.hex1(code._encoding._bits.buf()[iadr++]);
off += len;
- for( int i=size-off; i<dopz; i++ ) sb.p(" ");
+ for( int i=len; i<dopz; i++ ) sb.p(" ");
sb.p(" ");
int x = isMultiOp.indexOf('\n');
if( x== -1 ) { // Last line
diff --git a/chapter21/src/test/java/com/seaofnodes/simple/BrainFuckTest.java b/chapter21/src/test/java/com/seaofnodes/simple/BrainFuckTest.java
index 391bba67..2733620e 100644
--- a/chapter21/src/test/java/com/seaofnodes/simple/BrainFuckTest.java
+++ b/chapter21/src/test/java/com/seaofnodes/simple/BrainFuckTest.java
@@ -1,6 +1,7 @@
package com.seaofnodes.simple;
import com.seaofnodes.simple.codegen.CodeGen;
+import com.seaofnodes.simple.node.cpus.arm.arm;
import com.seaofnodes.simple.node.cpus.riscv.riscv;
import java.io.IOException;
import java.nio.file.Files;
@@ -23,10 +24,15 @@ public class BrainFuckTest {
for( int i=0; i<brain_fuck.length(); i++ )
assertEquals(brain_fuck.charAt(i), R5.ld1z(ptr+4+i));
- // TODO: replace with ARM Eval
- String src = Files.readString(Path.of("src/test/java/com/seaofnodes/simple/progs/brain_fuck.smp"));
- Chapter21Test.testCPU(src,"arm", "SystemV",26,null);
+ EvalArm64 A5 = TestArm64.build("brain_fuck", 0, 28, false);
+ int trap_arm = A5.step(100000);
+ assertEquals(0,trap_arm);
+ assertEquals(0,trap);
+ int ptr_arm = (int)A5.regs[arm.X0];
+ assertEquals(brain_fuck.length(),A5.ld4s(ptr_arm));
+ for( int i=0; i<brain_fuck.length(); i++ )
+ assertEquals(brain_fuck.charAt(i), A5.ld1z(ptr+4+i));
}
}
diff --git a/chapter21/src/test/java/com/seaofnodes/simple/Chapter20Test.java b/chapter21/src/test/java/com/seaofnodes/simple/Chapter20Test.java
index 83902b6d..5b33d1e7 100644
--- a/chapter21/src/test/java/com/seaofnodes/simple/Chapter20Test.java
+++ b/chapter21/src/test/java/com/seaofnodes/simple/Chapter20Test.java
@@ -84,7 +84,7 @@ return sqrt(arg) + sqrt(arg+2);
String src = "int[] !xs = new int[3]; xs[arg]=1; return xs[arg&1];";
testCPU(src,"x86_64_v2", "SystemV",-1,"return .[];");
testCPU(src,"riscv" , "SystemV", 6,"return .[];");
- testCPU(src,"arm" , "SystemV", 4,"return .[];");
+ testCPU(src,"arm" , "SystemV", 6,"return .[];");
}
diff --git a/chapter21/src/test/java/com/seaofnodes/simple/Chapter21Test.java b/chapter21/src/test/java/com/seaofnodes/simple/Chapter21Test.java
index 1857367b..ea23728c 100644
--- a/chapter21/src/test/java/com/seaofnodes/simple/Chapter21Test.java
+++ b/chapter21/src/test/java/com/seaofnodes/simple/Chapter21Test.java
@@ -113,7 +113,7 @@ public class Chapter21Test {
@Test public void testSieve() throws IOException {
// The primes
- int[] primes = new int[] { 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, };
+ int[] primes = new int[] { 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, };
SB sb = new SB().p(primes.length).p("[");
for( int prime : primes )
sb.p(prime).p(", ");
@@ -134,15 +134,16 @@ public class Chapter21Test {
for( int i=0; i<primes.length; i++ )
assertEquals(primes[i], R5.ld4s(ary + 4 + i*4));
- //// Evaluate on ARM5 emulator; expect return of an array of primes in the simulated heap.
- //EvalArm64 A5 = TestArm64.build("sieve", 100, 160, false);
- //int trap_arm = A5.step(10000);
- //assertEquals(0, trap_arm);
- //int ary_arm = (int)A5.regs[arm.X0];
- //// Memory layout starting at ary(length,pad, prime1, primt2, prime3, prime4)
- //assertEquals(primes.length, A5.ld4s(ary_arm));
- //for(int i = 0; i<primes.length; i++)
- // assertEquals(primes[i], A5.ld4s(ary_arm + 4 + i * 4));
+ // Evaluate on ARM5 emulator; expect return of an array of primes in
+ // the simulated heap.
+ EvalArm64 A5 = TestArm64.build("sieve", 100, 160, false);
+ int trap_arm = A5.step(10000);
+ assertEquals(0, trap_arm);
+ int ary_arm = (int)A5.regs[arm.X0];
+ // Memory layout starting at ary(length,pad, prime1, primt2, prime3, prime4)
+ assertEquals(primes.length, A5.ld4s(ary_arm));
+ for( int i = 0; i<primes.length; i++ )
+ assertEquals(primes[i], A5.ld4s(ary_arm + 4 + i * 4));
}
@Test public void testFibExport() throws IOException {
@@ -168,7 +169,7 @@ public class Chapter21Test {
TestC.run("person", person, 0);
// Memory layout starting at PS:
- int ps = 1<<16; // Person array pointer
+ int ps = 1<<16; // Person array pointer starts at heap start
// Person[3] = { len,pad,P0,P1,P2 }; // sizeof = 4*8
// P0 = { age } // sizeof=8
int p0 = ps+4*8+0*8;
@@ -191,6 +192,22 @@ public class Chapter21Test {
assertEquals( 5+0,R5.ld8(p0));
assertEquals(17+1,R5.ld8(p1));
assertEquals(60+0,R5.ld8(p2));
+
+ EvalArm64 A5 = TestArm64.build("person", ps, 0, false);
+ A5.regs[arm.X1] = 1; // Index 1
+ A5.st4(ps, 3);
+ A5.st8(ps+1*8,p0);
+ A5.st8(ps+2*8,p1);
+ A5.st8(ps+3*8,p2);
+ A5.st8(p0, 5); // age= 5
+ A5.st8(p1,17); // age=17
+ A5.st8(p2,60); // age=60
+
+ int trap_arm = A5.step(100);
+ assertEquals(0,trap_arm);
+ assertEquals( 5+0, A5.ld8(p0));
+ assertEquals(17+1, A5.ld8(p1));
+ assertEquals(60+0, A5.ld8(p2));
}
@Test public void testArgCount() throws IOException {
diff --git a/chapter21/src/test/java/com/seaofnodes/simple/EvalArm64.java b/chapter21/src/test/java/com/seaofnodes/simple/EvalArm64.java
index 4a4cf25c..3ea9bea0 100644
--- a/chapter21/src/test/java/com/seaofnodes/simple/EvalArm64.java
+++ b/chapter21/src/test/java/com/seaofnodes/simple/EvalArm64.java
@@ -13,10 +13,9 @@ public class EvalArm64 {
final double[] fregs;
int _pc;
-
+ int SENTINEL_CALLOC = -4;
// Start of free memory for allocation
int _heap;
-
// Cycle counters
int _cycle;
@@ -39,7 +38,8 @@ public class EvalArm64 {
public int ld1s(int x) { return _buf[x ] ; }
public int ld1z(int x) { return _buf[x ]&0xFF; }
public int ld2s(int x) { return ld1z(x) | ld1s(x+1)<< 8; }
- public int ld2z(int x) { return ld1z(x) | ld1z(x+1)<< 8; }
+ public int ld2z(int x) {
+ return ld1z(x) | ld1z(x+1)<< 8; }
public int ld4s(int x) { return ld2z(x) | ld2s(x+2)<<16; }
public long ld8 (int x) { return (long)ld4s(x)&0xFFFFFFFFL | ((long)ld4s(x+4))<<32; }
@@ -52,7 +52,6 @@ public class EvalArm64 {
public void st4(int x, int val) { st2(x,val); st2(x+2,val>>16); }
public void st8(int x, long val) { st4(x,(int)val); st2(x+4,(int)(val>>32)); }
-
public int step(int maxops) {
int trap = 0;
long rval = 0;
@@ -66,7 +65,6 @@ public class EvalArm64 {
rval = 0;
frval = 0;
cycle++;
-
if( pc >= _buf.length ) {
trap = 1 + 1; // Handle access violation on instruction read.
break;
@@ -85,6 +83,7 @@ public class EvalArm64 {
int opcode1 = (ir >> 24) & 0xFF;
// [31:26]
int opcode2 = (ir >> 26) & 0x3F;
+
switch(opcode2) {
case 5: {
//b
@@ -108,13 +107,12 @@ public class EvalArm64 {
int imm26 = (ir & 0x03FFFFFF);
int imm = (imm26 << 6) >> 6;
pc = pc + (imm << 2) ;
-
- if (pc == Encoding.SENTINAL_CALLOC) {
+ if (pc == SENTINEL_CALLOC) {
long size = regs[arm.X0]*regs[arm.X1];
regs[arm.X0] = _heap;
_heap += (int)size;
// unwind pc
- pc = (int)rval - 4;
+ pc = (int)rval;
}
continue;
}
@@ -127,6 +125,136 @@ public class EvalArm64 {
rval = (ir >> 5) & 0x7FFF;
break;
}
+ case 0x38: {
+ // STRB/LDRB(register)
+ int opc = ir >> 21 & 0x7;
+ int rn = (ir >> 5) & 0x1F;
+ int rm = (ir >> 16) & 0x1F;
+ // full opcode
+ opcode1 = (ir >> 21) & 0x7FF;
+ switch(opc) {
+ case 0x1: {
+ // store
+ if(opcode1 == arm.OP_STORE_R_8) {
+ st1((int)regs[rn] + (int)regs[rm], (int)regs[rdid]);
+ }else {
+ trap = (2+1);
+ }
+ rdid = -1;
+ break;
+ }
+ case 0x3: {
+ // load
+ if(opcode1 == arm.OP_LOAD_R_8) {
+ rval = ld1s((int)regs[rn] + (int)regs[rm]);
+ } else {
+ trap = (2+1);
+ }
+ break;
+ }
+ default: trap = (2+1);
+ }
+ break;
+ }
+ case 0x39: {
+ // STRB/LDRB(immediate)
+ // str/ldr(immediate)
+ // rn
+ int base = ir >> 5 & 0x1F;
+ int imm = (ir >> 10) & 0xFFF;
+ rval = regs[base] + imm;
+ int opc = (ir >> 22) & 0x3;
+ // full opcode
+ opcode1 = (ir >> 22) & 0x3FF;
+
+ switch(opc) {
+ case 0x0: {
+ // store
+ if(opcode1 == arm.OP_STORE_IMM_8) {
+ st1((int)rval, (int)regs[rdid]);
+ } else trap = (2+1);
+ rdid = -1;
+
+ break;
+ }
+ case 0x1: {
+ // LDR (immediate)
+ if(opcode1 == arm.OP_LOAD_IMM_8) {
+ rval = ld1s((int)rval);
+ } else trap = (2+1);
+ rdid = -1;
+ break;
+ }
+ default: trap = (2+1);
+ }
+ break;
+ }
+ case 0x78: {
+ // STRH/LDRH(register)
+ int opc = ir >> 21 & 0x7;
+ int rn = (ir >> 5) & 0x1F;
+ int rm = (ir >> 16) & 0x1F;
+ // full opcode
+ opcode1 = (ir >> 21) & 0x7FF;
+ switch(opc) {
+ case 0x1: {
+ // store
+ if(opcode1 == arm.OP_STORE_R_16) {
+ st1((int)regs[rn] + (int)regs[rm], (int)regs[rdid]);
+ }else {
+ trap = (2+1);
+ }
+ rdid = -1;
+ break;
+ }
+ case 0x3: {
+ // load
+ if(opcode1 == arm.OP_LOAD_R_16) {
+ rval = ld1s((int)regs[rn] + (int)regs[rm]);
+ } else {
+ trap = (2+1);
+ }
+ break;
+ }
+ default: trap = (2+1);
+ }
+ break;
+ }
+
+ case 0x79: {
+ // STRH/LDRH(immediate)
+ int base = ir >> 5 & 0x1F;
+ int imm = (ir >> 10) & 0xFFF;
+ imm *= 2;
+ rval = regs[base] + imm;
+ int opc = (ir >> 22) & 0x3;
+ // full opcode
+ opcode1 = (ir >> 22) & 0x3FF;
+
+ switch(opc) {
+ case 0x0: {
+ // store
+ if(opcode1 == arm.OP_STORE_IMM_16) {
+ st2((int)rval, (int)regs[rdid]);
+ } else trap = (2+1);
+ rdid = -1;
+
+ break;
+ }
+ case 0x1: {
+ // LDR (immediate)
+ if(opcode1 == arm.OP_LOAD_IMM_16) {
+ rval = ld2s((int)rval);
+ } else trap = (2+1);
+ rdid = -1;
+ break;
+ }
+ default: trap = (2+1);
+ }
+ break;
+ }
+
+
case 0x5c: {
// ldr
is_f = true;
@@ -137,30 +265,276 @@ public class EvalArm64 {
frval = ld8f(pc + address);
break;
}
+ case 0xB9: {
+ // str/ldr(immediate) 32 bits
+ int base = ir >> 5 & 0x1F;
+ int imm = (ir >> 10) & 0xFFF;
+ imm *= 4;
+ rval = regs[base] + imm;
+ int opc = (ir >> 22) & 0x3;
+
+ opcode1 = (ir >> 22) & 0x3FF;
+ switch(opc) {
+ case 0x0: {
+ // store
+ if(opcode1 == arm.OP_STORE_IMM_32) {
+ st4((int)rval, (int)regs[rdid]);
+ } else trap = (2+1);
+
+ rdid = -1;
+ break;
+ }
+ case 0x1: {
+ // LDR (immediate)
+ if(opcode1 == arm.OP_LOAD_IMM_32) {
+ rval = ld4s((int) rval);
+ } else trap = (2+1);
+ break;
+ }
+ default: trap = (2+1);
+ }
+ break;
+ }
case 0xF9: {
- // str
- // rn
+ // str/ldr(immediate) 64 bits
int base = ir >> 5 & 0x1F;
int imm = (ir >> 10) & 0xFFF;
+
+ imm *= 8;
+
rval = regs[base] + imm;
- switch(ir <<8 >> 30) {
+ int opc = (ir >> 22) & 0x3;
+ // full opcode
+ opcode1 = (ir >> 22) & 0x3FF;
+ switch(opc) {
case 0x0: {
// store
- _buf[(int)rval] = (byte)regs[rdid];
- if(rdid == 30) {
- System.out.print("Here");
+ if(opcode1 == arm.OP_STORE_IMM_64) {
+ st8((int)rval, regs[rdid]);
+ } else trap = (2+1);
+
+ rdid = -1;
+ break;
+ }
+ case 0x1: {
+ // LDR (immediate)
+ if(opcode1 == arm.OP_LOAD_IMM_64) {
+ rval = ld8((int)rval);
+ } else trap = (2+1);
+ break;
+ }
+ default: trap = (2+1);
+ }
+ break;
+ }
+ case 0xf8: {
+ // LDR/STR (register + index) 64 bits
+ int opc = ir >> 21 & 0x7;
+ int rn = (ir >> 5) & 0x1F;
+ int rm = (ir >> 16) & 0x1F;
+ // full opcode
+ opcode1 = (ir >> 21) & 0x7FF;
+ switch(opc) {
+ case 0x1: {
+ if(opcode1 == arm.OP_STORE_R_64) {
+ st8((int)regs[rn] + (int)regs[rm], regs[rdid]);
+ }else {
+ trap = (2+1);
+ }
+ // store(expected to store the length here)
+
+ rdid = -1;
+ break;
+ }
+ case 0x3: {
+ // load
+ if(opcode1 == arm.OP_LOAD_R_64) {
+ rval = ld8((int) (regs[rn] + regs[rm]));
+ } else {
+ trap = (2+1);
+ }
+ break;
+ }
+ default: trap = (2+1);
+ }
+
+ break;
+ }
+
+ case 0xB8: {
+ // LDR/STR (register + index) 32 bits
+ int opc = ir >> 21 & 0x7;
+ int rn = (ir >> 5) & 0x1F;
+ int rm = (ir >> 16) & 0x1F;
+ // full opcode
+ opcode1 = (ir >> 21) & 0x7FF;
+ switch(opc) {
+ case 0x1: {
+ if(opcode1 == arm.OP_STORE_R_32) {
+ st4((int)regs[rn] + (int)regs[rm], (int)regs[rdid]);
+ }else {
+ trap = (2+1);
}
+ // store(expected to store the length here)
+
rdid = -1;
break;
}
+ case 0x3: {
+ // load
+ if( opcode1 == arm.OP_LOAD_R_32) {
+ rval = ld4s((int) (regs[rn] + regs[rm]));
+ } else {
+ trap = (2+1);
+ }
+ break;
+ }
+ default: trap = (2+1);
+ }
+
+ break;
+ }
+
+ case 0xFC: {
+ // LDR/STR (register + index) float 64 bits
+ int opc = ir >> 21 & 0x7;
+ int rn = (ir >> 5) & 0x1F;
+ int rm = (ir >> 16) & 0x1F;
+ is_f = true;
+ // full opcode
+ opcode1 = (ir >> 21) & 0x7FF;
+ switch(opc) {
case 0x1: {
+ if(opcode1 == arm.OPF_STORE_R_64) {
+ st8((int)regs[rn] + (int)regs[rm], (int)regs[rdid]);
+ }else {
+ trap = (2+1);
+ }
+ // store(expected to store the length here)
+
+ rdid = -1;
+ break;
+ }
+ case 0x3: {
// load
- rval = _buf[(int)rval];
+ if(opcode1 == arm.OPF_LOAD_R_64) {
+ frval = ld8f((int) (regs[rn] + regs[rm]));
+ } else {
+ trap = (2+1);
+ }
break;
}
default: trap = (2+1);
}
+
+ break;
+ }
+
+ case 0xBC: {
+ // LDR/STR (register + index) float 32 bits
+ int opc = ir >> 21 & 0x7;
+ int rn = (ir >> 5) & 0x1F;
+ int rm = (ir >> 16) & 0x1F;
+ is_f = true;
+ // full opcode
+ opcode1 = (ir >> 21) & 0x7FF;
+ switch(opc) {
+ case 0x1: {
+ if(opcode1 == arm.OPF_STORE_R_32) {
+ st4((int)regs[rn] + (int)regs[rm], (int)regs[rdid]);
+ }else {
+ trap = (2+1);
+ }
+ // store(expected to store the length here)
+
+ rdid = -1;
+ break;
+ }
+ case 0x3: {
+ // load
+ if(opcode1 == arm.OPF_LOAD_R_32) {
+ frval = ld4f((int) (regs[rn] + regs[rm]));
+ } else {
+ trap = (2+1);
+ }
+ break;
+ }
+ default: trap = (2+1);
+ }
+
+ break;
+ }
+
+ case 0xBD: {
+ // LDR/STR(immediate) 32 bits floats
+ int base = ir >> 5 & 0x1F;
+ int imm = (ir >> 10) & 0xFFF;
+
+ imm *= 4;
+ is_f = true;
+ rval = regs[base] + imm;
+ int opc = (ir >> 22) & 0x3;
+ // full opcode
+ opcode1 = (ir >> 22) & 0x3FF;
+ switch(opc) {
+ case 0x0: {
+ // store
+ if(opcode1 == arm.OPF_STORE_IMM_32) {
+ st4((int)rval, (int)regs[rdid]);
+ } else trap = (2+1);
+
+ rdid = -1;
+ break;
+ }
+ case 0x1: {
+ // LDR (immediate)
+ if(opcode1 == arm.OPF_LOAD_IMM_32) {
+ frval = ld4s((int)rval);
+ } else trap = (2+1);
+ break;
+ }
+ default: trap = (2+1);
+ }
+ break;
+ }
+ case 0xFD: {
+ // LDR/STR(immediate) 64 bits floats
+ int base = ir >> 5 & 0x1F;
+ int imm = (ir >> 10) & 0xFFF;
+
+ imm *= 4;
+ is_f = true;
+ rval = regs[base] + imm;
+ int opc = (ir >> 22) & 0x3;
+ // full opcode
+ opcode1 = (ir >> 22) & 0x3FF;
+ switch(opc) {
+ case 0x0: {
+ // store
+ if(opcode1 == arm.OPF_STORE_IMM_64) {
+ st8((int)rval, regs[rdid]);
+ } else trap = (2+1);
+
+ rdid = -1;
+ break;
+ }
+ case 0x1: {
+ // LDR (immediate)
+ if(opcode1 == arm.OPF_LOAD_IMM_64) {
+ frval = ld8((int)rval);
+ } else trap = (2+1);
+ break;
+ }
+ default: trap = (2+1);
+ }
+ break;
+ }
+ case 0x9b: {
+ // mul
+ int rn = (ir >> 5) & 0x1F;
+ int rm = (ir >> 16) & 0x1F;
+ rval = regs[rn] * regs[rm];
break;
}
case 0x54: {
@@ -209,17 +583,17 @@ public class EvalArm64 {
case 0xD: if(Z || N != V) rval = regs[rm]; break; // le
case 0xE: rval = regs[rm]; break; // always executed(al)
default: {
- rval = regs[(ir >> 5) & 0x1F];
+ rval = regs[(ir >> 5) & 0x1F];
}
}
break;
}
case 0xeb: {
// subs(shifted register)
- int rn = (ir >> 5) & 0x1F;
+ int rn = (ir >> 5) & 0x1F;
int rm = (ir >> 16) & 0x1F;
- int lhs = (int)regs[rn];
- int rhs = (int)regs[rm];
+ long lhs = regs[rn];
+ long rhs = regs[rm];
rval = lhs - rhs;
// set flags as a side effect
@@ -238,7 +612,7 @@ public class EvalArm64 {
// subs(immediate)
int rn = (ir >> 5) & 0x1F;
int immediate = ir << 10 >> 20;
- int lhs = (int)regs[rn];
+ long lhs = regs[rn];
rval = lhs - immediate;
@@ -267,13 +641,30 @@ public class EvalArm64 {
// add(immediate)
int rn = (ir >> 5) & 0x1F;
int immediate = ir << 10 >> 20;
+ // only hit it twice
rval = regs[rn] + immediate;
break;
}
case 0xD3: {
- // lsl
- int immr = ir << 10 >> 26;
- rval = 64 - immr;
+ // lsl(immediate)
+ int imm = (ir >> 16) & 0x3F;
+ int rn = (ir >> 5) & 0x1F;
+ rval = regs[rn] << (64 - imm);
+ break;
+ }
+ case 0x93: {
+ // asr(immediate)
+ int imm = (ir >> 16) & 0x3F;
+ int rn = (ir >> 5) & 0x1F;
+ rval = regs[rn] >> (imm);
+ break;
+ }
+ case 0x92: {
+ // and(immediate)
+ int imm12 = (ir >> 10) & 0x1FFF;
+ long immediate = arm.decodeImm12(imm12);
+ int rn = (ir >> 5) & 0x1F;
+ rval = regs[rn] & immediate;
break;
}
case 0xAA: {
diff --git a/chapter21/src/test/java/com/seaofnodes/simple/EvalRisc5.java b/chapter21/src/test/java/com/seaofnodes/simple/EvalRisc5.java
index bad22d52..fd953342 100644
--- a/chapter21/src/test/java/com/seaofnodes/simple/EvalRisc5.java
+++ b/chapter21/src/test/java/com/seaofnodes/simple/EvalRisc5.java
@@ -54,7 +54,7 @@ import java.util.Arrays;
public void st1(int x, int val) { _buf[x] = (byte)val; }
public void st2(int x, int val) { st1(x,val); st1(x+1,val>> 8); }
- public void st4(int x, int val) { st2(x,val); st2(x+2,val>>16); }
+ public void st4(int x, int val) {st2(x,val); st2(x+2,val>>16); }
public void st8(int x, long val) { st4(x,(int)val); st2(x+4,(int)(val>>32)); }
// Note: only a few bits are used. (Machine = 3, User = 0)
@@ -84,7 +84,6 @@ import java.util.Arrays;
trap = 1; // Handle PC-misaligned access
break;
}
-
// Load instruction from image buffer at PC
ir = ld4s( pc );
int rdid = (ir >> 7) & 0x1f;
@@ -104,13 +103,11 @@ import java.util.Arrays;
break;
}
case 0x67: { // JALR (0b1100111)
- int imm = ir >> 20;
-
- int imm_se = imm | (( (imm & 0x800)!=0 ) ? 0xfffff000 : 0);
+ int imm_se = ir >> 20; // Sign extend 12 bits
rval = pc + 4;
- pc = ( ((int)regs[ (ir >> 15) & 0x1f ] + imm_se) & ~1) - 4;
+ pc = ((int)regs[ (ir >> 15) & 0x1f ] + imm_se) & ~1;
// Return from top-level ; exit sim
- if( pc+4==0 ) {
+ if( pc==0 ) {
if( rdid!=0 ) regs[rdid] = rval; // Write PC into register before exit
break outer;
}
@@ -122,7 +119,8 @@ import java.util.Arrays;
// Arrays.fill(_buf,_heap,_heap+size, (byte) 0 );
_heap += size;
pc = (int)(rval - 4); // Unwind PC, as-if returned from calloc
- }
+ } else
+ pc -= 4;
break;
}
case 0x63: { // Branch (0b1100011)
@@ -195,7 +193,6 @@ import java.util.Arrays;
if( (addy & 0x800)!=0 ) addy |= 0xfffff000;
addy += rs1;
rdid = 0;
-
if( addy >= _buf.length-3 ) {
trap = (7+1); // Store access fault.
rval = addy;
@@ -218,6 +215,10 @@ import java.util.Arrays;
boolean is_reg = (ir & 0x20)!=0;
long rs2 = is_reg ? regs[imm & 0x1f] : imm;
+ // Insert the detection here
+ int rs1id = (ir >> 15) & 0x1f;
+ int funct3 = (ir >> 12) & 0x7;
+
if( is_reg && ( ir & 0x02000000 )!=0 ) {
switch( (ir>>12)&7 ) { //0x02000000 = RV32M
case 0: rval = rs1 * rs2; break; // MUL
diff --git a/chapter21/src/test/java/com/seaofnodes/simple/TestArm64.java b/chapter21/src/test/java/com/seaofnodes/simple/TestArm64.java
index 739f5b1e..5d7d1361 100644
--- a/chapter21/src/test/java/com/seaofnodes/simple/TestArm64.java
+++ b/chapter21/src/test/java/com/seaofnodes/simple/TestArm64.java
@@ -13,21 +13,21 @@ import static org.junit.Assert.assertEquals;
// Runs 32-bit ARM code in an emulator
public class TestArm64 {
- public static EvalArm64 build(String file, int arg, int spills, boolean print) throws IOException {
+ public static EvalArm64 build( String file, int arg, int spills, boolean print ) throws IOException {
return build("src/test/java/com/seaofnodes/simple/progs",file, arg, spills, print);
}
// Compile and run a simple program
- public static EvalArm64 build(String dir, String file, int arg, int spills, boolean print) throws IOException {
+ public static EvalArm64 build( String dir, String file, int arg, int spills, boolean print ) throws IOException {
// Compile and export Simple
String src = Files.readString(Path.of(dir+"/"+file+".smp"));
CodeGen code = new CodeGen(src).driver("arm", "SystemV",null);
- if(print) {code.print_as_hex(); System.out.print(code.asm());}
+ if( print ) { code.print_as_hex(); System.out.print(code.asm()); }
// Allocation quality not degraded
int delta = spills>>3;
- if(delta == 0) delta =1;
- if(spills != -1) assertEquals("Expect spills:", spills, code._regAlloc._spillScaled, delta);
+ if( delta == 0 ) delta =1;
+ if( spills != -1 ) assertEquals("Expect spills:", spills, code._regAlloc._spillScaled, delta);
// Image
byte[] image = new byte[1<<20]; // A megabyte (1024*1024 bytes)
diff --git a/chapter21/src/test/java/com/seaofnodes/simple/TestRisc5.java b/chapter21/src/test/java/com/seaofnodes/simple/TestRisc5.java
index b7642540..041ed833 100644
--- a/chapter21/src/test/java/com/seaofnodes/simple/TestRisc5.java
+++ b/chapter21/src/test/java/com/seaofnodes/simple/TestRisc5.java
@@ -12,16 +12,16 @@ import static org.junit.Assert.*;
// Runs 32-bit R5 code in an emulator
public abstract class TestRisc5 {
- public static EvalRisc5 build( String file, int arg, int spills, boolean print) throws IOException {
+ public static EvalRisc5 build( String file, int arg, int spills, boolean print ) throws IOException {
return build("src/test/java/com/seaofnodes/simple/progs",file, null, arg, spills, print);
}
// Compile and run a simple program
- public static EvalRisc5 build( String dir, String file, String main, int arg, int spills, boolean print) throws IOException {
+ public static EvalRisc5 build( String dir, String file, String main, int arg, int spills, boolean print ) throws IOException {
// Compile and export Simple
String src = Files.readString(Path.of(dir+"/"+file+".smp"));
CodeGen code = new CodeGen(src).driver("riscv", "SystemV",null);
- if(print) {code.print_as_hex(); System.out.print(code.asm());}
+ if( print ) { code.print_as_hex(); System.out.print(code.asm()); }
// Allocation quality not degraded
int delta = spills>>3;
diff --git a/chapter21/src/test/java/com/seaofnodes/simple/progs/jig.smp b/chapter21/src/test/java/com/seaofnodes/simple/progs/jig.smp
index 64c15dd7..00c2a161 100644
--- a/chapter21/src/test/java/com/seaofnodes/simple/progs/jig.smp
+++ b/chapter21/src/test/java/com/seaofnodes/simple/progs/jig.smp
@@ -1,2 +1,9 @@
// -*- mode: java; -*-
-val allocIA = { int N -> return new u32[N]; };
+struct s0 {
+ i16 v1;
+ u8 v2;
+};
+s0 !l4Hi9BCnsd = new s0;
+if( new s0.v2+arg )
+ while(1) l4Hi9BCnsd=new s0;
+while(new s0.v2+new s0.v1<=0) {}
diff --git a/chapter21/src/test/java/com/seaofnodes/simple/progs/sieve.smp b/chapter21/src/test/java/com/seaofnodes/simple/progs/sieve.smp
index 6d160b1e..569dbb96 100644
--- a/chapter21/src/test/java/com/seaofnodes/simple/progs/sieve.smp
+++ b/chapter21/src/test/java/com/seaofnodes/simple/progs/sieve.smp
@@ -1,6 +1,6 @@
// -*- mode: java; -*-
-// The main Sieve array
val sieve = { int N ->
+ // The main Sieve array
bool[] !ary = new bool[N];
// The primes less than N
u32[] !primes = new u32[N>>1];