diff options
| author | Cliff Click <cliffc@acm.org> | 2025-05-05 21:24:06 -0700 |
|---|---|---|
| committer | Cliff Click <cliffc@acm.org> | 2025-05-05 21:24:06 -0700 |
| commit | 31f89ec8f8d2b05e2550b7c6957259380ef21575 (patch) | |
| tree | 0553c3a64f555c5ee641573d35138d8fdab38e8c | |
| parent | 04881a0ea7e84cf8af05054946f10cc6bb14f8fc (diff) | |
| download | Simple-31f89ec8f8d2b05e2550b7c6957259380ef21575.tar.gz Simple-31f89ec8f8d2b05e2550b7c6957259380ef21575.zip | |
Now with risc5
R5 eval handles extern `write` call.
13 files changed, 149 insertions, 29 deletions
diff --git a/chapter22/README.md b/chapter22/README.md index b32451f2..0fdd9d4a 100644 --- a/chapter22/README.md +++ b/chapter22/README.md @@ -411,6 +411,7 @@ math.sin(val. c); // Pass by value `&&` and `||` Drop `int` to `i32`. +Drop `TypeMemPtr` to 4 bytes; using `mmap` to make heap in low 4G. Add optimistic pass SCCP to `opto` Default parser for-loop construction, or partial peel. `for( init; test; next ) body` diff --git a/chapter22/src/main/java/com/seaofnodes/simple/codegen/Encoding.java b/chapter22/src/main/java/com/seaofnodes/simple/codegen/Encoding.java index 722320e8..da4f9ee7 100644 --- a/chapter22/src/main/java/com/seaofnodes/simple/codegen/Encoding.java +++ b/chapter22/src/main/java/com/seaofnodes/simple/codegen/Encoding.java @@ -498,6 +498,7 @@ public class Encoding { // Since no runtime in the JVM process, using magic numbers for the CPU // emulators to pick up on. public static int SENTINAL_CALLOC = -4; + public static int SENTINAL_WRITE = -8; void patchGlobalRelocations() { for( Node src : _externals.keySet() ) { @@ -505,6 +506,7 @@ public class Encoding { String dst = _externals.get(src); int target = switch( dst ) { case "calloc" -> SENTINAL_CALLOC; + case "write" -> SENTINAL_WRITE ; default -> throw Utils.TODO(); }; ((RIPRelSize)src).patch(this, start, _opLen[src._nid], target - start); diff --git a/chapter22/src/main/java/com/seaofnodes/simple/node/cpus/arm/CallARM.java b/chapter22/src/main/java/com/seaofnodes/simple/node/cpus/arm/CallARM.java index 2823d7d1..d5e12b7f 100644 --- a/chapter22/src/main/java/com/seaofnodes/simple/node/cpus/arm/CallARM.java +++ b/chapter22/src/main/java/com/seaofnodes/simple/node/cpus/arm/CallARM.java @@ -23,9 +23,12 @@ public class CallARM extends CallNode implements MachNode, RIPRelSize { @Override public TypeFunPtr tfp() { return _tfp; } @Override public RegMask regmap(int i) { return arm.callInMask(_tfp,i); } @Override public RegMask outregmap() { return null; } + @Override public int nargs() { return nIns()-2; } // Minus control, memory, fptr @Override public void encoding( Encoding enc ) { - enc.relo(this); + FunNode fun = CodeGen.CODE.link(_tfp); + if( fun==null ) enc.external(this,_name); + else enc.relo(this); // BL enc.add4(arm.b(arm.OP_CALL,0)); // Target patched at link time } diff --git a/chapter22/src/main/java/com/seaofnodes/simple/node/cpus/arm/FloatARM.java b/chapter22/src/main/java/com/seaofnodes/simple/node/cpus/arm/FloatARM.java index 6de65b03..63c57770 100644 --- a/chapter22/src/main/java/com/seaofnodes/simple/node/cpus/arm/FloatARM.java +++ b/chapter22/src/main/java/com/seaofnodes/simple/node/cpus/arm/FloatARM.java @@ -20,8 +20,6 @@ public class FloatARM extends ConstantNode implements MachNode, RIPRelSize { @Override public void encoding( Encoding enc ) { enc.largeConstant(this,_con,0,-1/*TODO: ARM-style ELF patching*/); short dst = (short)(enc.reg(this) - arm.D_OFFSET); - double d = ((TypeFloat)_con).value(); - long x = Double.doubleToRawLongBits(d); enc.add4(arm.load_pc(arm.OPF_ARM, 0, dst)); } diff --git a/chapter22/src/main/java/com/seaofnodes/simple/node/cpus/arm/TFPARM.java b/chapter22/src/main/java/com/seaofnodes/simple/node/cpus/arm/TFPARM.java index 76e23c30..908d46d0 100644 --- a/chapter22/src/main/java/com/seaofnodes/simple/node/cpus/arm/TFPARM.java +++ b/chapter22/src/main/java/com/seaofnodes/simple/node/cpus/arm/TFPARM.java @@ -5,7 +5,6 @@ import com.seaofnodes.simple.codegen.*; import com.seaofnodes.simple.node.ConstantNode; import com.seaofnodes.simple.node.MachNode; import com.seaofnodes.simple.node.Node; -import com.seaofnodes.simple.node.cpus.riscv.riscv; import com.seaofnodes.simple.type.TypeFunPtr; public class TFPARM extends ConstantNode implements MachNode, RIPRelSize { @@ -26,8 +25,7 @@ public class TFPARM extends ConstantNode implements MachNode, RIPRelSize { } @Override public byte encSize(int delta) { - if( -(1L<<12) <= delta && delta < (1L<<12) ) return 4; - throw Utils.TODO(); + return 8; } // Delta is from opcode start diff --git a/chapter22/src/main/java/com/seaofnodes/simple/node/cpus/arm/TMPARM.java b/chapter22/src/main/java/com/seaofnodes/simple/node/cpus/arm/TMPARM.java new file mode 100644 index 00000000..7600d66b --- /dev/null +++ b/chapter22/src/main/java/com/seaofnodes/simple/node/cpus/arm/TMPARM.java @@ -0,0 +1,51 @@ +package com.seaofnodes.simple.node.cpus.arm; + +import com.seaofnodes.simple.*; +import com.seaofnodes.simple.codegen.*; +import com.seaofnodes.simple.node.ConstantNode; +import com.seaofnodes.simple.node.MachNode; +import com.seaofnodes.simple.node.Node; +import com.seaofnodes.simple.type.TypeMemPtr; + +public class TMPARM extends ConstantNode implements MachNode, RIPRelSize { + TMPARM( ConstantNode con ) { super(con); } + @Override public String op() { return "ldp"; } + @Override public RegMask regmap(int i) { return null; } + @Override public RegMask outregmap() { return arm.WMASK; } + @Override public boolean isClone() { return true; } + @Override public TMPARM copy() { return new TMPARM(this); } + @Override public void encoding( Encoding enc ) { + enc.largeConstant(this,((TypeMemPtr)_con)._obj,0,-1); + short dst = enc.reg(this); + // adrp x0, 0 + enc.add4(arm.adrp(1,0, arm.OP_ADRP, 0,dst)); + // add x0, x0, 0 + arm.imm_inst(enc,arm.OPI_ADD,0, dst); + } + + @Override public byte encSize(int delta) { + return 8; + } + + // Delta is from opcode start + @Override public void patch( Encoding enc, int opStart, int opLen, int delta ) { + short dst = enc.reg(this); + if(opLen == 8 ) { + // opstart of add + int next = opStart + opLen; + int adrp_delta = delta >> 12; + // patch upper 20 bits via adrp + enc.patch4(opStart, arm.adrp(1, adrp_delta & 0b11, 0b10000, adrp_delta >> 2, dst)); + // low 12 bits via add + enc.patch4(next, arm.imm_inst_l(arm.OPI_ADD, delta & 0xfff, dst)); + } else { + throw Utils.TODO(); + } + } + + @Override public void asm(CodeGen code, SB sb) { + String reg = code.reg(this); + _con.print(sb.p(reg).p(" #")); + } + @Override public boolean eq(Node n) { return this==n; } +} diff --git a/chapter22/src/main/java/com/seaofnodes/simple/node/cpus/arm/arm.java b/chapter22/src/main/java/com/seaofnodes/simple/node/cpus/arm/arm.java index 104929f4..d589dc7d 100644 --- a/chapter22/src/main/java/com/seaofnodes/simple/node/cpus/arm/arm.java +++ b/chapter22/src/main/java/com/seaofnodes/simple/node/cpus/arm/arm.java @@ -567,6 +567,7 @@ public class arm extends Machine { static RegMask callInMask(TypeFunPtr tfp, int idx ) { if( idx==0 ) return CodeGen.CODE._rpcMask; if( idx==1 ) return null; + if( idx-2 >= tfp.nargs() ) return null; // Anti-dependence // Count floats in signature up to index int fcnt=0; for( int i=2; i<idx; i++ ) @@ -729,13 +730,13 @@ public class arm extends Machine { 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 TMPARM(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); }; } diff --git a/chapter22/src/main/java/com/seaofnodes/simple/node/cpus/riscv/CallRISC.java b/chapter22/src/main/java/com/seaofnodes/simple/node/cpus/riscv/CallRISC.java index ad70a661..daef60f2 100644 --- a/chapter22/src/main/java/com/seaofnodes/simple/node/cpus/riscv/CallRISC.java +++ b/chapter22/src/main/java/com/seaofnodes/simple/node/cpus/riscv/CallRISC.java @@ -19,17 +19,18 @@ public class CallRISC extends CallNode implements MachNode, RIPRelSize { @Override public String op() { return "call"; } @Override public String label() { return op(); } - @Override public RegMask regmap(int i) { - return riscv.callInMask(_tfp,i); - } - @Override public RegMask outregmap() { return riscv.RPC_MASK; } @Override public String name() { return _name; } @Override public TypeFunPtr tfp() { return _tfp; } + @Override public RegMask regmap(int i) { return riscv.callInMask(_tfp,i); } + @Override public RegMask outregmap() { return riscv.RPC_MASK; } + @Override public int nargs() { return nIns()-2; } // Minus control, memory, fptr @Override public void encoding( Encoding enc ) { // Short form +/-4K: beq r0,r0,imm12 // Long form: auipc rX,imm20/32; jal r0,[rX+imm12/32] - enc.relo(this); + FunNode fun = CodeGen.CODE.link(_tfp); + if( fun==null ) enc.external(this,_name); + else enc.relo(this); short rpc = enc.reg(this); enc.add4(riscv.j_type(riscv.OP_JAL, rpc, 0)); } diff --git a/chapter22/src/main/java/com/seaofnodes/simple/node/cpus/riscv/TFPRISC.java b/chapter22/src/main/java/com/seaofnodes/simple/node/cpus/riscv/TFPRISC.java index a69cfbe8..15be82bc 100644 --- a/chapter22/src/main/java/com/seaofnodes/simple/node/cpus/riscv/TFPRISC.java +++ b/chapter22/src/main/java/com/seaofnodes/simple/node/cpus/riscv/TFPRISC.java @@ -20,11 +20,9 @@ public class TFPRISC extends ConstantNode implements MachNode, RIPRelSize { short dst = enc.reg(this); TypeFunPtr tfp = (TypeFunPtr)_con; // auipc t0,0 - int auipc = riscv.u_type(riscv.OP_AUIPC, dst, 0); + enc.add4(riscv.u_type(riscv.OP_AUIPC, dst, 0)); // addi t1,t0 + #0 - int addi = riscv.i_type(riscv.OP_IMM, dst, 0, dst, 0); - enc.add4(auipc); - enc.add4(addi); + enc.add4(riscv.i_type(riscv.OP_IMM, dst, 0, dst, 0)); } @Override public byte encSize(int delta) { @@ -39,7 +37,7 @@ public class TFPRISC extends ConstantNode implements MachNode, RIPRelSize { // AUIPC (upper 20 bits) // opstart of add int next = opStart + opLen; - enc.patch4(opStart,riscv.u_type(riscv.OP_AUIPC, rpc, delta)); + enc.patch4(opStart,riscv.u_type(riscv.OP_AUIPC, rpc, delta>>12)); // addi(low 12 bits) enc.patch4(next,riscv.i_type(riscv.OP_IMM, rpc, 0, rpc, delta & 0xFFF)); // addi diff --git a/chapter22/src/main/java/com/seaofnodes/simple/node/cpus/riscv/TMPRISC.java b/chapter22/src/main/java/com/seaofnodes/simple/node/cpus/riscv/TMPRISC.java new file mode 100644 index 00000000..860e5eaf --- /dev/null +++ b/chapter22/src/main/java/com/seaofnodes/simple/node/cpus/riscv/TMPRISC.java @@ -0,0 +1,41 @@ +package com.seaofnodes.simple.node.cpus.riscv; + +import com.seaofnodes.simple.*; +import com.seaofnodes.simple.codegen.*; +import com.seaofnodes.simple.node.ConstantNode; +import com.seaofnodes.simple.node.MachNode; +import com.seaofnodes.simple.node.Node; +import com.seaofnodes.simple.type.TypeMemPtr; + +public class TMPRISC extends ConstantNode implements MachNode, RIPRelSize { + TMPRISC(ConstantNode con) { super(con); } + @Override public String op() { return "ldp"; } + @Override public RegMask regmap(int i) { return null; } + @Override public RegMask outregmap() { return riscv.WMASK; } + @Override public boolean isClone() { return true; } + @Override public TMPRISC copy() { return new TMPRISC(this); } + @Override public void encoding( Encoding enc ) { + enc.largeConstant(this,((TypeMemPtr)_con)._obj,0,-1); + short dst = enc.reg(this); + // AUIPC dst,#hi20_constant_pool + enc.add4(riscv.u_type(riscv.OP_AUIPC, dst, 0)); + // addi dst,[dst+#low12_constant_pool] + enc.add4(riscv.i_type(riscv.OP_IMM, dst, 0, dst, 0)); + } + + @Override public byte encSize(int delta) { return 8; } + + // Delta is from opcode start + @Override public void patch( Encoding enc, int opStart, int opLen, int delta ) { + short dst = enc.reg(this); + // AUIPC dst,#hi20_constant_pool + enc.patch4(opStart , riscv.u_type(riscv.OP_AUIPC, dst, delta>>12)); + // Load dst,[dst+#low12_constant_pool] + enc.patch4(opStart+4, riscv.i_type(riscv.OP_IMM, dst, 0, dst, delta & 0xFFF)); + } + + @Override public void asm(CodeGen code, SB sb) { + _con.print(sb.p(code.reg(this)).p(" #")); + } + @Override public boolean eq(Node n) { return this==n; } +} diff --git a/chapter22/src/main/java/com/seaofnodes/simple/node/cpus/riscv/riscv.java b/chapter22/src/main/java/com/seaofnodes/simple/node/cpus/riscv/riscv.java index 699b867e..c4cde159 100644 --- a/chapter22/src/main/java/com/seaofnodes/simple/node/cpus/riscv/riscv.java +++ b/chapter22/src/main/java/com/seaofnodes/simple/node/cpus/riscv/riscv.java @@ -256,6 +256,7 @@ public class riscv extends Machine { static RegMask callInMask( TypeFunPtr tfp, int idx ) { if( idx==0 ) return RPC_MASK; if( idx==1 ) return null; + if( idx-2 >= tfp.nargs() ) return null; // Anti-dependence // Count floats in signature up to index int fcnt=0; for( int i=2; i<idx; i++ ) @@ -446,7 +447,7 @@ public class riscv extends Machine { // Load from constant pool case TypeFloat tf -> new FltRISC(con); case TypeFunPtr tfp -> new TFPRISC(con); - case TypeMemPtr tmp -> throw Utils.TODO(); + case TypeMemPtr tmp -> new TMPRISC(con); case TypeNil tn -> throw Utils.TODO(); // TOP, BOTTOM, XCtrl, Ctrl, etc. Never any executable code. case Type t -> t==Type.NIL ? new IntRISC(con) : new ConstantNode(con); diff --git a/chapter22/src/test/java/com/seaofnodes/simple/Chapter22Test.java b/chapter22/src/test/java/com/seaofnodes/simple/Chapter22Test.java index de9c35c7..b441aa4a 100644 --- a/chapter22/src/test/java/com/seaofnodes/simple/Chapter22Test.java +++ b/chapter22/src/test/java/com/seaofnodes/simple/Chapter22Test.java @@ -105,10 +105,23 @@ return cc.cz; assertEquals("25", Eval2.eval(code, 0)); } - @Test @Ignore + @Test public void testHelloWorld() throws IOException { - String src = Files.readString(Path.of("src/test/java/com/seaofnodes/simple/progs/helloWorld.smp")); - TestC.run(src,TestC.CALL_CONVENTION,null,null,"build/objs/helloWorld","","Hello, World!",0); + //String src = Files.readString(Path.of("src/test/java/com/seaofnodes/simple/progs/helloWorld.smp")); + //TestC.run(src,TestC.CALL_CONVENTION,null,null,"build/objs/helloWorld","","Hello, World!",0); + // + //// Evaluate on RISC5 emulator + //EvalRisc5 R5 = TestRisc5.build("helloWorld", 0, 2, false); + //int trap = R5.step(100); + //assertEquals(0,trap); + //assertEquals(0,R5.regs[riscv.A0]); + + + // Evaluate on ARM emulator + EvalArm64 arm = TestArm64.build("helloWorld", 0, 2, false); + int trap = arm.step(100); + assertEquals(0,trap); + assertEquals(0,arm.regs[0]); } diff --git a/chapter22/src/test/java/com/seaofnodes/simple/EvalRisc5.java b/chapter22/src/test/java/com/seaofnodes/simple/EvalRisc5.java index fd953342..8fe22bc2 100644 --- a/chapter22/src/test/java/com/seaofnodes/simple/EvalRisc5.java +++ b/chapter22/src/test/java/com/seaofnodes/simple/EvalRisc5.java @@ -11,6 +11,7 @@ import com.seaofnodes.simple.codegen.Encoding; import com.seaofnodes.simple.node.cpus.riscv.riscv; +import java.io.PrintStream; import java.util.Arrays; public class EvalRisc5 { @@ -100,6 +101,17 @@ import java.util.Arrays; if( (reladdy & 0x00100000)!=0 ) reladdy |= 0xffe00000; // Sign extension. rval = pc + 4; pc = pc + reladdy - 4; + if( pc+4 == Encoding.SENTINAL_WRITE ) { + PrintStream ps = switch((int)regs[10]) { + case 1 -> System.out; + case 2 -> System.err; + default -> throw new IllegalArgumentException(); + }; + ps.write(_buf,(int)regs[11],(int)regs[12]); + regs[10] = regs[12]; + rdid = 0; + pc = (int)(rval - 4); // Unwind PC, as-if returned from write + } break; } case 0x67: { // JALR (0b1100111) @@ -233,11 +245,11 @@ import java.util.Arrays; } else { rval = switch( (ir >> 12) & 7 ) { // These could be either op-immediate or op commands. Be careful. case 0 -> (is_reg && (ir & 0x40000000) != 0) ? (rs1 - rs2) : (rs1 + rs2); - case 1 -> rs1 << (rs2 & 0x1F); + case 1 -> rs1 << (rs2 & 0x3F); case 2 -> (rs1 < rs2) ? 1 : 0; case 3 -> (rs1 < rs2) ? 1 : 0; case 4 -> rs1 ^ rs2; - case 5 -> (ir & 0x40000000) != 0 ? (((int) rs1) >> (rs2 & 0x1F)) : (rs1 >> (rs2 & 0x1F)); + case 5 -> (ir & 0x40000000) != 0 ? (rs1 >>> (rs2 & 0x3F)) : (rs1 >> (rs2 & 0x3F)); case 6 -> rs1 | rs2; case 7 -> rs1 & rs2; default -> rval; |
