//! returns: 1 //! Test that u32 values with bit 31 set are correctly zero-extended //! when loaded from memory. //! //! Regression test: `lw` sign-extends on RV64, producing a negative //! 64-bit value for u32 values >= 0x80000000. The correct instruction //! is `lwu` which zero-extends. /// A u32 value with bit 31 set, stored in a struct to force a memory load. record Pair { lo: u32, hi: u32, } /// Test that a u32 field with bit 31 set compares correctly. fn testFieldCompare() -> bool { let p = Pair { lo: 1, hi: 0x80000000 }; // With lw (sign-extend), p.hi is loaded as 0xFFFFFFFF80000000 // in the register. A subsequent u32 comparison should still work // because the comparison normalizes, but let's test the value // through arithmetic that would expose the sign-extension. let val = p.hi; // Shift right by 1: if correctly zero-extended (0x80000000), // u32 shift gives 0x40000000. // If sign-extended to 64-bit and then shifted as u32 via `srliw`, // the *w variant only looks at low 32 bits, so this still works. let shifted = val >> 1; if shifted <> 0x40000000 { return false; } return true; } /// Test u32 max value round-trips through memory correctly. fn testMaxU32() -> bool { let arr: [u32; 1] = [0xFFFFFFFF]; let val = arr[0]; // If lw sign-extends, val in register is 0xFFFFFFFFFFFFFFFF. // Adding 1 as u32 (via addw): 0xFFFFFFFF + 1 = 0 (wraps). OK either way. // But comparing: val should equal 0xFFFFFFFF as u32. if val <> 0xFFFFFFFF { return false; } // The key test: widening to u64 should give 0x00000000FFFFFFFF, // not 0xFFFFFFFFFFFFFFFF. let wide: u64 = val as u64; if wide <> 0xFFFFFFFF { return false; } return true; } @default fn main() -> bool { return testFieldCompare() and testMaxU32(); }