From 41be002e89358649da46c33c8245aa786afdad6a Mon Sep 17 00:00:00 2001 From: Cliff Click Date: Mon, 28 Sep 2026 16:25:01 -0700 Subject: Extend smaller-width C results to full width --- .../java/com/seaofnodes/simple/Chapter21Test.java | 17 ++++++ .../java/com/seaofnodes/simple/Chapter22Test.java | 71 ++++++++++++++++++++++ .../java/com/seaofnodes/simple/Chapter25Test.java | 2 +- .../test/java/com/seaofnodes/simple/EvalArm64.java | 21 +++---- .../java/com/seaofnodes/simple/progs/c_returns.c | 28 +++++++++ 5 files changed, 126 insertions(+), 13 deletions(-) create mode 100644 chapter25/src/test/java/com/seaofnodes/simple/progs/c_returns.c (limited to 'chapter25/src/test/java/com') diff --git a/chapter25/src/test/java/com/seaofnodes/simple/Chapter21Test.java b/chapter25/src/test/java/com/seaofnodes/simple/Chapter21Test.java index 4307a3b6..88e963c0 100644 --- a/chapter25/src/test/java/com/seaofnodes/simple/Chapter21Test.java +++ b/chapter25/src/test/java/com/seaofnodes/simple/Chapter21Test.java @@ -10,6 +10,23 @@ import org.junit.Test; import static org.junit.Assert.*; public class Chapter21Test { + + @Test public void testArmBitfieldExtracts() { + // Independent SXT/UXT instruction words, plus ASR, LSR and LSL aliases. + int[] ops = {0x93401c20,0xd3401c20,0x93403c20,0xd3403c20, + 0x93407c20,0xd3407c20,0x9344fc20,0xd344fc20,0xd37cec20}; + long value = 0xa5a5a5a580008080L; + long[] expected = {(byte)value,value&255,(short)value,value&65535, + (int)value,value&0xffffffffL,value>>4,value>>>4,value<<4}; + for( int i=0; i n instanceof com.seaofnodes.simple.node.CallNode ? n : null); + int start = enc.opStart(call); + ((com.seaofnodes.simple.codegen.RIPRelSize)call).patch(enc,start,enc.opLen(call),0x1000-start); + for( long value : values ) { + long expected = switch(i) { + case 0 -> (byte)value; case 1 -> value&255; + case 2 -> (short)value; case 3 -> value&65535; + case 4 -> (int)value; case 5 -> value&0xffffffffL; + default -> value; + }; + byte[] image = new byte[1<<16]; + byte[] bits = enc.bits(); + System.arraycopy(bits,0,image,0,bits.length); + if( target.equals("arm") ) { + EvalArm64 cpu = new EvalArm64(image,1<<15); + // MOVZ X0,0x1100; LDR X0,[X0]; RET X30. + cpu.st4(0x1000,0xd2822000); cpu.st4(0x1004,0xf9400000); + cpu.st4(0x1008,0xd65f03c0); + cpu.st8(0x1100,value); + assertEquals(0,cpu.step(1000)); + assertEquals(0,cpu._pc); + assertEquals(types[i],expected,cpu.regs[0]); + } else { + EvalRisc5 cpu = new EvalRisc5(image,1<<15); + // AUIPC a0,0; LD a0,12(a0); RET. + cpu.st4(0x1000,0x00000517); cpu.st4(0x1004,0x00c53503); + cpu.st4(0x1008,0x00008067); + // RV64 widens even u32 returns by sign-extending bit 31. + cpu.st8(0x100c,i==6 ? value : (int)expected); + assertEquals(0,cpu.step(1000)); + assertEquals(0,cpu._pc); + assertEquals(types[i],expected,cpu.regs[riscv.A0]); + } + } + } + } + + @Test public void testNarrowCReturns() throws IOException { + String src = """ + {i8} c_i8="C"; {u8} c_u8="C"; + {i16} c_i16="C"; {u16} c_u16="C"; + {i32} c_i32="C"; {u32} c_u32="C"; + {int} c_i64="C"; + val test_i8={->return c_i8();}; + val test_u8={->return c_u8();}; + val test_i16={->return c_i16();}; + val test_u16={->return c_u16();}; + val test_i32={->return c_i32();}; + val test_u32={->return c_u32();}; + val test_i64={->return c_i64();}; + val test_cmp={->return c_i32()==-1;}; + """; + for( String conv : new String[]{"SystemV","win64"} ) + TestC.run(src,"c_returns"+conv,null,conv, + conv.equals("SystemV") ? "sysv_abi" : "ms_abi", + TestC.C_DRIVERS_DIR+"c_returns.c","",-1); + } + + @Test public void testSubZeroTypeError() { try { new CodeGen("return null-0;").parse().opto().typeCheck(); diff --git a/chapter25/src/test/java/com/seaofnodes/simple/Chapter25Test.java b/chapter25/src/test/java/com/seaofnodes/simple/Chapter25Test.java index bde25ab7..346c503a 100644 --- a/chapter25/src/test/java/com/seaofnodes/simple/Chapter25Test.java +++ b/chapter25/src/test/java/com/seaofnodes/simple/Chapter25Test.java @@ -394,7 +394,7 @@ return rez < buf# ? 0 : sys.libc._exit(-2); @Test public void testErrnoAccessor() throws IOException { - String src = "sys.libc.close(-1); return sys.libc.errno()==0;"; + String src = "val status=sys.libc.close(-1); return status != -1 || sys.libc.errno()==0;"; TestC.run(src,"errnoAccessor",new Ary<>(new String[]{SYS_BLDDIR}), TestC.CALL_CONVENTION,null,null,"",-1); } diff --git a/chapter25/src/test/java/com/seaofnodes/simple/EvalArm64.java b/chapter25/src/test/java/com/seaofnodes/simple/EvalArm64.java index e8121927..86fcf96f 100644 --- a/chapter25/src/test/java/com/seaofnodes/simple/EvalArm64.java +++ b/chapter25/src/test/java/com/seaofnodes/simple/EvalArm64.java @@ -321,11 +321,15 @@ public class EvalArm64 { rval = regs[rn] & immediate; break; } - case 0x93: { - // asr(immediate) - int imm = (ir >> 16) & 0x3F; - int rn = (ir >> 5) & 0x1F; - rval = regs[rn] >> (imm); + case 0x93, 0xD3: { // SBFM/UBFM: shifts and signed/unsigned extracts + int immr = (ir >>> 16) & 63; + int imms = (ir >>> 10) & 63; + int rn = (ir >>> 5) & 31; + boolean signed = (ir & 0x40000000)==0; + long value = regs[rn] << (63-imms); + value = signed ? value >> (63-imms) : value >>> (63-imms); + rval = immr > imms ? value << (64-immr) + : signed ? value >> immr : value >>> immr; break; } @@ -568,13 +572,6 @@ public class EvalArm64 { break; } - case 0xD3: { - // lsl(immediate) - int imm = (ir >> 16) & 0x3F; - int rn = (ir >> 5) & 0x1F; - rval = regs[rn] << (64 - imm); - break; - } case 0xD6: { int op = ir & 0xFFFFFC1F; int rn = (ir >>> 5) & 31; diff --git a/chapter25/src/test/java/com/seaofnodes/simple/progs/c_returns.c b/chapter25/src/test/java/com/seaofnodes/simple/progs/c_returns.c new file mode 100644 index 00000000..6d0ff2fe --- /dev/null +++ b/chapter25/src/test/java/com/seaofnodes/simple/progs/c_returns.c @@ -0,0 +1,28 @@ +#include +#include + +uint64_t c_bits; +// Legal narrow C returns: unused RAX bits deliberately contain garbage. +#define RET(name) __asm__(".text\n.globl " #name "\n" #name ":\nmovq c_bits(%rip), %rax\nret\n"); +RET(c_i8) RET(c_u8) RET(c_i16) RET(c_u16) RET(c_i32) RET(c_u32) RET(c_i64) +#define DECL(name) extern int64_t __attribute__((CALL_CONV)) name(void); +DECL(test_i8) DECL(test_u8) DECL(test_i16) DECL(test_u16) +DECL(test_i32) DECL(test_u32) DECL(test_i64) DECL(test_cmp) + +int main(void) { + uint64_t values[] = {0xa5a5a5a500000000ULL, 0xa5a5a5a50000007fULL, + 0xa5a5a5a500000080ULL, 0xa5a5a5a500007fffULL, 0xa5a5a5a500008000ULL, + 0xa5a5a5a57fffffffULL, 0xa5a5a5a580000000ULL, 0xa5a5a5a5ffffffffULL}; + for(unsigned i=0; i