summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCliff Click <cliffc@acm.org>2025-04-15 19:41:55 -0700
committerCliff Click <cliffc@acm.org>2025-04-15 19:41:55 -0700
commit2a3b2d4d4bc6099ab9fead00cfaa3f0a8e6aeb9f (patch)
tree6a94bfc5734ba84497083d233281a569ffe0c67f
parent2fb0ec312d76f22534331023c86e68b7a62b98e6 (diff)
downloadSimple-2a3b2d4d4bc6099ab9fead00cfaa3f0a8e6aeb9f.tar.gz
Simple-2a3b2d4d4bc6099ab9fead00cfaa3f0a8e6aeb9f.zip
R5 fcmp, flt load from pool
exportELF(null) now patches the cpool entries as well as globals. Repeated cpool entries folded. Fixed FltRISC, FCMP encoding.
-rw-r--r--chapter21/src/main/java/com/seaofnodes/simple/codegen/CodeGen.java5
-rw-r--r--chapter21/src/main/java/com/seaofnodes/simple/codegen/Encoding.java32
-rw-r--r--chapter21/src/main/java/com/seaofnodes/simple/codegen/LinkMem.java10
-rw-r--r--chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/FltRISC.java6
-rw-r--r--chapter21/src/main/java/com/seaofnodes/simple/node/cpus/riscv/SetFRISC.java2
-rw-r--r--chapter21/src/main/java/com/seaofnodes/simple/print/ASMPrinter.java5
-rw-r--r--chapter21/src/test/java/com/seaofnodes/simple/Chapter21Test.java9
-rw-r--r--chapter21/src/test/java/com/seaofnodes/simple/EvalRisc5.java113
-rw-r--r--chapter21/src/test/java/com/seaofnodes/simple/TestArm64.java2
-rw-r--r--chapter21/src/test/java/com/seaofnodes/simple/TestRisc5.java2
10 files changed, 90 insertions, 96 deletions
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 146c016a..2e1a4709 100644
--- a/chapter21/src/main/java/com/seaofnodes/simple/codegen/CodeGen.java
+++ b/chapter21/src/main/java/com/seaofnodes/simple/codegen/CodeGen.java
@@ -379,17 +379,16 @@ public class CodeGen {
public int _tEncode;
public Encoding _encoding; // Encoding object
public void preEncode() { } // overridden by alternative ports
- public CodeGen encode(boolean jit) {
+ public CodeGen encode() {
assert _phase == Phase.RegAlloc;
_phase = Phase.Encoding;
long t0 = System.currentTimeMillis();
_encoding = new Encoding(this);
preEncode();
- _encoding.encode(jit);
+ _encoding.encode();
_tEncode = (int)(System.currentTimeMillis() - t0);
return this;
}
- public CodeGen encode() { return encode(false); }
// ---------------------------
// Exporting to external formats
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 118ca47c..395b3d46 100644
--- a/chapter21/src/main/java/com/seaofnodes/simple/codegen/Encoding.java
+++ b/chapter21/src/main/java/com/seaofnodes/simple/codegen/Encoding.java
@@ -153,7 +153,7 @@ public class Encoding {
_bigCons.put(relo,new Relo(relo,t,(byte)off,(byte)elf));
}
- void encode(boolean jit) {
+ void encode() {
// Basic block layout: invert branches to keep blocks in-order; insert
// unconditional jumps. Attempt to keep backwards branches taken,
// forwards not-taken (this is the default prediction on most
@@ -170,10 +170,6 @@ public class Encoding {
// Patch RIP-relative and local encodings now.
patchLocalRelocations();
-
- // If JIT'ing (in memory execution), patch the global relocations now
- if( jit )
- patchGlobalRelocations();
}
// Basic block layout: invert branches to keep blocks in-order; insert
@@ -382,14 +378,10 @@ public class Encoding {
// Write the constant pool into the BAOS and optionally patch locally
void writeConstantPool( BAOS bits, boolean patch ) {
- HashSet<Relo> ts = new HashSet<>();
- for( Relo t : _bigCons.values() ) {
- if( ts.contains(t) )
- throw Utils.TODO(); // Dup! Compress!
- ts.add(t);
- }
padN(16,bits);
+ HashMap<Type,Integer> targets = new HashMap<>();
+
// By log size
for( int log = 3; log >= 0; log-- ) {
// Write the 8-byte constants
@@ -397,17 +389,21 @@ public class Encoding {
Relo relo = _bigCons.get(op);
if( relo._t.log_size()==log ) {
// Map from relo to constant start and patch
- relo._target = bits.size();
+ Integer target = targets.get(relo._t);
+ if( target==null ) {
+ targets.put(relo._t,target = bits.size());
+ // Put constant into code space.
+ if( relo._t instanceof TypeTuple tt ) // Constant tuples put all entries
+ for( Type tx : tt._types )
+ addN(log,tx,bits);
+ else
+ addN(log,relo._t,bits);
+ }
+ relo._target = target;
relo._opStart= _opStart[op._nid];
// Go ahead and locally patch in-memory
if( patch )
((RIPRelSize)op).patch(this, relo._opStart, _opLen[op._nid], relo._target - relo._opStart);
- // Put constant into code space.
- if( relo._t instanceof TypeTuple tt ) // Constant tuples put all entries
- for( Type tx : tt._types )
- addN(log,tx,bits);
- else
- addN(log,relo._t,bits);
}
}
}
diff --git a/chapter21/src/main/java/com/seaofnodes/simple/codegen/LinkMem.java b/chapter21/src/main/java/com/seaofnodes/simple/codegen/LinkMem.java
index 07a5dd12..e1e849e6 100644
--- a/chapter21/src/main/java/com/seaofnodes/simple/codegen/LinkMem.java
+++ b/chapter21/src/main/java/com/seaofnodes/simple/codegen/LinkMem.java
@@ -1,14 +1,22 @@
package com.seaofnodes.simple.codegen;
+import com.seaofnodes.simple.Utils;
+import com.seaofnodes.simple.node.Node;
+
// In-memory linking
public class LinkMem {
final CodeGen _code;
LinkMem( CodeGen code ) { _code = code; }
public CodeGen link() {
+ Encoding enc = _code._encoding;
+
+ // Patch external calls internally
+ enc.patchGlobalRelocations();
+
// Write any large constants into a constant pool; they
// are accessed by RIP-relative addressing.
- _code._encoding.writeConstantPool(_code._encoding._bits,true);
+ enc.writeConstantPool(enc._bits,true);
return _code;
}
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 0a7b02e3..35de7e04 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
@@ -22,7 +22,7 @@ public class FltRISC extends ConstantNode implements MachNode, RIPRelSize {
// AUIPC dst,#hi20_constant_pool
enc.add4(riscv.u_type(riscv.OP_AUIPC, tmp, 0));
// Load dst,[dst+#low12_constant_pool]
- enc.add4(riscv.i_type(riscv.OP_LOAD, dst, 0b11, tmp, 0));
+ enc.add4(riscv.i_type(riscv.OP_LOADFP, dst, 0b11, tmp, 0));
}
@Override public RegMask killmap() { return new RegMask(riscv.T6); }
@@ -35,9 +35,9 @@ public class FltRISC extends ConstantNode implements MachNode, RIPRelSize {
short dst = (short)(enc.reg(this) - riscv.F_OFFSET);
short tmp = (short)riscv.T6;
// AUIPC dst,#hi20_constant_pool
- enc.patch4(opStart , riscv.u_type(riscv.OP_AUIPC, tmp, delta));
+ enc.patch4(opStart , riscv.u_type(riscv.OP_AUIPC, tmp, delta>>12));
// Load dst,[dst+#low12_constant_pool]
- enc.patch4(opStart+4, riscv.i_type(riscv.OP_LOAD, dst, 0b11, tmp, delta));
+ enc.patch4(opStart+4, riscv.i_type(riscv.OP_LOADFP, dst, 0b11, tmp, delta & 0xFFF));
}
@Override public void asm(CodeGen code, SB sb) {
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 64440536..9ee19e42 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
@@ -23,7 +23,7 @@ public class SetFRISC extends MachConcreteNode implements MachNode {
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(riscv.OP_FP,dst,riscv.fsetop(_bop),src1,src2,0);
+ int body = riscv.r_type(riscv.OP_FP,dst,riscv.fsetop(_bop),src1,src2,0b1010001/*FCMP*/);
enc.add4(body);
}
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 902aa3c2..8f3c9bb2 100644
--- a/chapter21/src/main/java/com/seaofnodes/simple/print/ASMPrinter.java
+++ b/chapter21/src/main/java/com/seaofnodes/simple/print/ASMPrinter.java
@@ -6,6 +6,7 @@ import com.seaofnodes.simple.codegen.CodeGen;
import com.seaofnodes.simple.codegen.Encoding;
import com.seaofnodes.simple.node.*;
import com.seaofnodes.simple.type.*;
+import java.util.HashSet;
public abstract class ASMPrinter {
@@ -26,11 +27,15 @@ public abstract class ASMPrinter {
// constant pool
Encoding enc = code._encoding;
if( enc!=null && !enc._bigCons.isEmpty() ) {
+ iadr = (iadr+15)&-16; // pad to 16
+ HashSet<Type> targets = new HashSet<>();
sb.p("--- Constant Pool ------").nl();
// By log size
for( int log = 3; log >= 0; log-- ) {
for( Node op : enc._bigCons.keySet() ) {
Encoding.Relo relo = enc._bigCons.get(op);
+ if( targets.contains(relo._t) ) continue;
+ targets.add(relo._t);
if( relo._t.log_size()==log ) {
sb.hex2(iadr).p(" ");
if( relo._t instanceof TypeTuple tt ) {
diff --git a/chapter21/src/test/java/com/seaofnodes/simple/Chapter21Test.java b/chapter21/src/test/java/com/seaofnodes/simple/Chapter21Test.java
index faf21b4f..cf088835 100644
--- a/chapter21/src/test/java/com/seaofnodes/simple/Chapter21Test.java
+++ b/chapter21/src/test/java/com/seaofnodes/simple/Chapter21Test.java
@@ -101,13 +101,14 @@ public class Chapter21Test {
8 2.828427
9 3.000000
""";
- TestC.run("newtonFloat",result);
+ //TestC.run("newtonFloat",result);
+
EvalRisc5 R5 = TestRisc5.build("newtonFloat", 0);
- R5.fregs[riscv.FA0 - riscv.F_OFFSET] = 4.0;
- int trap = R5.step(100);
+ R5.fregs[riscv.FA0 - riscv.F_OFFSET] = 3.0;
+ int trap = R5.step(1000);
assertEquals(0,trap);
// Return register A0 holds fib(8)==55
- assertEquals(2.0,R5.fregs[riscv.FA0 - riscv.F_OFFSET], 0.00001);
+ assertEquals(1.732051,R5.fregs[riscv.FA0 - riscv.F_OFFSET], 0.00001);
}
@Test public void testSieve() throws IOException {
diff --git a/chapter21/src/test/java/com/seaofnodes/simple/EvalRisc5.java b/chapter21/src/test/java/com/seaofnodes/simple/EvalRisc5.java
index 50e52095..e48dd34c 100644
--- a/chapter21/src/test/java/com/seaofnodes/simple/EvalRisc5.java
+++ b/chapter21/src/test/java/com/seaofnodes/simple/EvalRisc5.java
@@ -47,6 +47,10 @@ import java.util.Arrays;
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; }
+ public float ld4f(int x) { return Float.intBitsToFloat(ld4s(x)); }
+ public double ld8f(int x) { return Double.longBitsToDouble(ld8(x)); }
+
+
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); }
@@ -85,17 +89,6 @@ import java.util.Arrays;
int rdid = (ir >> 7) & 0x1f;
switch( ir & 0x7f ) {
- // floats
- case 0x7: {
- is_f = true;
- // does not handle rsp case
-
- long rs1 = (ir >> 15) & 0x1f;
- // Todo: look for stack case
- if (rs1 == 2) break;
- frval = ir & 0x7FF000;
- break;
- }
case 0x37: // LUI (0b0110111)
rval = ( ir & 0xfffff000 );
break;
@@ -174,6 +167,27 @@ import java.util.Arrays;
}
break;
}
+ // floats
+ case 0x7: {
+ is_f = true;
+ int rs1 = (int)regs[(ir >> 15) & 0x1f]; // Address chop to 32b
+ int imm = ir >> 20;
+ int imm_se = imm | (( (imm & 0x800)!=0 ) ? 0xfffff000 : 0 );
+ int rsval = rs1 + imm_se;
+
+ if( rsval >= _buf.length-3 ) {
+ trap = (5+1);
+ rval = rsval;
+ } else {
+ switch( ( ir >> 12 ) & 0x7 ) {
+ case 2: frval = ld4f( rsval ); break;
+ case 3: frval = ld8f( rsval ); break;
+ default: trap = (2+1);
+ }
+ }
+ break;
+ }
+
case 0x23: { // Store 0b0100011
int rs1 = (int)regs[(ir >> 15) & 0x1f]; // Address chop to 32b
long rs2 = regs[(ir >> 20) & 0x1f];
@@ -279,66 +293,37 @@ import java.util.Arrays;
}
case 0x53: {
- // differentiate between fcvt.d.w and fadd.d
is_f = true;
- int rs1;
- int rs1_int;
- int rs2;
- int func5 = (ir >> 27) & 0x1F;;
+ int rs1 = (ir >> 15) & 0x1F;
+ int rs2 = (ir >> 20) & 0x1F;
+ double lhs = fregs[rs1];
+ double rhs = fregs[rs2];
+ int func5 = (ir >> 27) & 0x1F;
int func2 = (ir >> 25) & 0x3;
-// if(func5 == 0 && func2 == 1) {
-// }
- if(func5 == 0) {
- // fadd.d
- rs1 = (ir >> 15) & 0x1F;
- rs2 = (ir >> 20) & 0x1F;
- double lhs = fregs[rs1];
- double rhs = fregs[rs2];
- frval = lhs + rhs;
+ if( func2 != 1 ) throw Utils.TODO(); // 1==double
+ switch( func5 ) {
+ case 0: frval = lhs + rhs; break; // fadd.d
+ case 1: frval = lhs - rhs; break; // fsub.d
+ case 2: frval = lhs * rhs; break; // fmul.d
+ case 3: frval = lhs / rhs; break; // fdiv.d
+ case 5: frval = Math.min(lhs,rhs); break; // fmin.d, also used for move
+ case 20:
+ is_f = false; // Output into a GPR
+ rval = switch( (ir >> 12) & 7 ) {
+ case 0 -> lhs <= rhs ? 1 : 0;
+ case 1 -> lhs == rhs ? 1 : 0;
+ case 2 -> lhs < rhs ? 1 : 0;
+ default -> throw Utils.TODO();
+ };
break;
- } else if(func5 == 26) {
- //fcvt.d.w
- rs1_int = (ir >> 15) & 0x1F;
- long value = regs[rs1_int];
- frval = (double)value;
- break;
- } else if (func5 == 5) {
- // fmin.d
- rs1 = (ir >> 15) & 0x1F;
- rs2 = (ir >> 20) & 0x1F;
- // just pick one as they are the same
- frval = fregs[rs1];
- break;
- } else if(func5 == 3) {
- // fdiv.d
- rs1 = (ir >> 15) & 0x1F;
- rs2 = (ir >> 20) & 0x1F;
- double lhs = fregs[rs1];
- double rhs = fregs[rs2];
- frval = lhs / rhs;
- break;
- } else if(func5 == 2) {
- // fmul.d
- rs1 = (ir >> 15) & 0x1F;
- rs2 = (ir >> 20) & 0x1F;
- double lhs = fregs[rs1];
- double rhs = fregs[rs2];
- frval = lhs * rhs;
- break;
-
- } else if(func5 == 1) {
- // fsub.d
- rs1 = (ir >> 15) & 0x1F;
- rs2 = (ir >> 20) & 0x1F;
- double lhs = fregs[rs1];
- double rhs = fregs[rs2];
- frval = lhs - rhs;
- break;
- } else {
+ case 26: frval = (double)regs[rs1]; break; // fcvt.w.d
+ default:
trap = (2+1); // Fault: Invalid opcode.
throw Utils.TODO();
}
+ break;
}
+
default: trap = (2+1); // Fault: Invalid opcode.
}
diff --git a/chapter21/src/test/java/com/seaofnodes/simple/TestArm64.java b/chapter21/src/test/java/com/seaofnodes/simple/TestArm64.java
index 96aa5b74..1325f1e1 100644
--- a/chapter21/src/test/java/com/seaofnodes/simple/TestArm64.java
+++ b/chapter21/src/test/java/com/seaofnodes/simple/TestArm64.java
@@ -19,7 +19,7 @@ public class TestArm64 {
public static EvalArm64 build(String dir, String file, int arg) throws IOException {
// Compile and export Simple
String src = Files.readString(Path.of(dir+"/"+file+".smp"));
- CodeGen code = new CodeGen(src).driver(CodeGen.Phase.RegAlloc,"arm", "SystemV").encode(true);
+ CodeGen code = new CodeGen(src).driver("arm", "SystemV",null);
// 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 8b9b8884..a72dbd1d 100644
--- a/chapter21/src/test/java/com/seaofnodes/simple/TestRisc5.java
+++ b/chapter21/src/test/java/com/seaofnodes/simple/TestRisc5.java
@@ -18,7 +18,7 @@ public abstract class TestRisc5 {
public static EvalRisc5 build( String dir, String file, int arg ) throws IOException {
// Compile and export Simple
String src = Files.readString(Path.of(dir+"/"+file+".smp"));
- CodeGen code = new CodeGen(src).driver(CodeGen.Phase.RegAlloc,"riscv", "SystemV").encode(true);
+ CodeGen code = new CodeGen(src).driver("riscv", "SystemV",null);
// Image
byte[] image = new byte[1<<20]; // A megabyte (1024*1024 bytes)