From aaec6f8136df6f7020bfc05f79ff5273adf73de1 Mon Sep 17 00:00:00 2001 From: Cliff Click Date: Wed, 7 Oct 2026 12:57:31 -0700 Subject: flt->int conversion --- isa/src/main/java/com/seaofnodes/isa/Arm64.java | 6 ++++++ isa/src/main/java/com/seaofnodes/isa/RiscV.java | 10 ++++++++++ isa/src/main/java/com/seaofnodes/isa/X86.java | 16 ++++++++++++++++ .../java/com/seaofnodes/isa/eval/EvalArm64.java | 9 ++++++--- .../java/com/seaofnodes/isa/eval/EvalRisc5.java | 20 +++++++++++++++++++- isa/src/test/java/com/seaofnodes/isa/RiscTest.java | 22 ++++++++++++++++++++++ isa/src/test/java/com/seaofnodes/isa/X86Test.java | 4 ++++ 7 files changed, 83 insertions(+), 4 deletions(-) (limited to 'isa') diff --git a/isa/src/main/java/com/seaofnodes/isa/Arm64.java b/isa/src/main/java/com/seaofnodes/isa/Arm64.java index 2c969da0..ce7f7b11 100644 --- a/isa/src/main/java/com/seaofnodes/isa/Arm64.java +++ b/isa/src/main/java/com/seaofnodes/isa/Arm64.java @@ -236,6 +236,12 @@ public final class Arm64 { (vd << 12) | (0x01100010 << 4) | vm; } + /** FCVTZS Xd,Dn: truncate, saturate overflow, and convert NaN to zero. */ + public static int floatToInteger(int rn, int rd) { + assert 0<=rn && rn<32 && 0<=rd && rd<32; + return 0x9E780000 | (rn<<5) | rd; + } + public static int float_cast(int opcode, int ftype, int rn, int rd) { assert 0 <= rd && rd < 32; assert 0 <= rn && rn < 32; diff --git a/isa/src/main/java/com/seaofnodes/isa/RiscV.java b/isa/src/main/java/com/seaofnodes/isa/RiscV.java index cb446a6a..0ecd1cec 100644 --- a/isa/src/main/java/com/seaofnodes/isa/RiscV.java +++ b/isa/src/main/java/com/seaofnodes/isa/RiscV.java @@ -59,6 +59,16 @@ public final class RiscV { return bits << 12 | rd << 7 | opcode; } + /** FCVT.L.D with RTZ saturates overflow; explicitly map either NaN to zero. */ + public static void floatToInteger(CodeSink out, int dst, int src) { + out.add4(r_type(OP_FP,dst,1,src,0,0x71)); // FCLASS.D + out.add4(i_type(OP_IMM,dst,7,dst,0x300)); // ANDI: NaN classification bits + out.add4(b_type(OP_BRANCH,1,(short)dst,(short)0,12)); // BNE nan + out.add4(r_type(OP_FP,dst,RM.RTZ.ordinal(),src,2,0x61)); // FCVT.L.D + out.add4(j_type(OP_JAL,0,8)); // J done + out.add4(i_type(OP_IMM,dst,0,0,0)); // nan: LI dst,0 + } + public static int i_type(int opcode, int rd, int func3, int rs1, int imm12) { assert 0 <= rd && rd < 32; assert 0 <= rs1 && rs1 < 32; diff --git a/isa/src/main/java/com/seaofnodes/isa/X86.java b/isa/src/main/java/com/seaofnodes/isa/X86.java index 99d61dff..78fa3da5 100644 --- a/isa/src/main/java/com/seaofnodes/isa/X86.java +++ b/isa/src/main/java/com/seaofnodes/isa/X86.java @@ -60,6 +60,22 @@ public final class X86 { out.add1(0x48).add1(0x99); // CQO: sign-extend rax into rdx:rax. unary(out,0xF7,7,src); } + /** Truncate f64 to i64, saturating overflow and mapping NaN to zero. */ + public static void floatToInteger(CodeSink out, int dst, int src) { + sse(out,0xF2,0x0F2C,true,dst,src); // CVTTSD2SI + imm(out,0x81,7,dst,1); // CMP dst,1: OF iff dst is MIN_VALUE + out.add1(0x71).add1((src>=8 ? 5 : 4)+24); // JNO done + sse(out,0x66,0x0F2E,false,src,src); // UCOMISD: unordered iff NaN + out.add1(0x7A).add1(19); // JP nan + sse(out,0x66,0x0F7E,true,src,dst); // MOVQ: inspect the float's sign + shift(out,7,dst,63); // SAR: 0 or -1 + unary(out,0xF7,2,dst); // NOT: -1 or 0 + reg(out,0x0FBA,7,dst); // BTC sign bit: MAX_VALUE or MIN_VALUE + out.add1(63); + out.add1(0xEB).add1(3); // JMP done + reg(out,0x33,dst,dst); // nan: XOR dst,dst + } + public static void sse(CodeSink out, int prefix, int op, boolean wide, int dst, int src) { if( prefix!=0 ) out.add1(prefix); rexF(dst,src,-1,wide,out); diff --git a/isa/src/test-support/java/com/seaofnodes/isa/eval/EvalArm64.java b/isa/src/test-support/java/com/seaofnodes/isa/eval/EvalArm64.java index 2a4a2708..2fa4aec1 100644 --- a/isa/src/test-support/java/com/seaofnodes/isa/eval/EvalArm64.java +++ b/isa/src/test-support/java/com/seaofnodes/isa/eval/EvalArm64.java @@ -404,10 +404,13 @@ public class EvalArm64 { break; } case 0x9E: { - // scvtf - is_f = true; int rs1 = (ir >> 5) & 0x1F; - frval = (double)regs[rs1]; + if( (ir & 0xFFFFFC00)==0x9E780000 ) { // FCVTZS Xd,Dn + rval = (long)fregs[rs1]; + } else { // SCVTF + is_f = true; + frval = (double)regs[rs1]; + } break; } diff --git a/isa/src/test-support/java/com/seaofnodes/isa/eval/EvalRisc5.java b/isa/src/test-support/java/com/seaofnodes/isa/eval/EvalRisc5.java index f618075d..46baf447 100644 --- a/isa/src/test-support/java/com/seaofnodes/isa/eval/EvalRisc5.java +++ b/isa/src/test-support/java/com/seaofnodes/isa/eval/EvalRisc5.java @@ -334,7 +334,25 @@ public class EvalRisc5 { default -> throw new UnsupportedOperationException(); }; break; - case 26: frval = (double)regs[rs1]; break; // fcvt.w.d + case 24: // FCVT.L.D, RTZ + if( rs2!=2 || ((ir>>12)&7)!=1 ) throw new UnsupportedOperationException(); + is_f = false; + rval = Double.isNaN(lhs) ? Long.MAX_VALUE : (long)lhs; + break; + case 26: frval = (double)regs[rs1]; break; // fcvt.d.l + case 28: { // FCLASS.D + if( rs2!=0 || ((ir>>12)&7)!=1 ) throw new UnsupportedOperationException(); + is_f = false; + long bits = Double.doubleToRawLongBits(lhs); + boolean neg = bits<0; + int kind = Double.isNaN(lhs) ? ((bits&(1L<<51))==0 ? 8 : 9) + : Double.isInfinite(lhs) ? (neg ? 0 : 7) + : lhs==0 ? (neg ? 3 : 4) + : Math.abs(lhs) X86.floatToInteger(b,0,0)); + check("f24d0f2cca4983f901711d66450f2ed27a13664d0f7ed149c1f93f49f7d1490fbaf93feb034d33c9", + b -> X86.floatToInteger(b,9,10)); check("4d03ca", b -> X86.reg(b,0x03,9,10)); check("4d0fafca", b -> X86.reg(b,0x0FAF,9,10)); check("4981c17fffffff", b -> X86.imm(b,0x81,0,9,-129)); -- cgit v1.2.3