From 2a3b2d4d4bc6099ab9fead00cfaa3f0a8e6aeb9f Mon Sep 17 00:00:00 2001 From: Cliff Click Date: Tue, 15 Apr 2025 19:41:55 -0700 Subject: 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. --- .../com/seaofnodes/simple/codegen/CodeGen.java | 5 +- .../com/seaofnodes/simple/codegen/Encoding.java | 32 +++--- .../com/seaofnodes/simple/codegen/LinkMem.java | 10 +- .../seaofnodes/simple/node/cpus/riscv/FltRISC.java | 6 +- .../simple/node/cpus/riscv/SetFRISC.java | 2 +- .../com/seaofnodes/simple/print/ASMPrinter.java | 5 + .../java/com/seaofnodes/simple/Chapter21Test.java | 9 +- .../test/java/com/seaofnodes/simple/EvalRisc5.java | 113 +++++++++------------ .../test/java/com/seaofnodes/simple/TestArm64.java | 2 +- .../test/java/com/seaofnodes/simple/TestRisc5.java | 2 +- 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 ts = new HashSet<>(); - for( Relo t : _bigCons.values() ) { - if( ts.contains(t) ) - throw Utils.TODO(); // Dup! Compress! - ts.add(t); - } padN(16,bits); + HashMap 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 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) -- cgit v1.2.3