diff --git a/src/backend/pass/emit/x86/x86_lower_ops.cpp b/src/backend/pass/emit/x86/x86_lower_ops.cpp index c48f4b7..d8f56ba 100644 --- a/src/backend/pass/emit/x86/x86_lower_ops.cpp +++ b/src/backend/pass/emit/x86/x86_lower_ops.cpp @@ -1038,9 +1038,14 @@ namespace rat { case Opcode::FPTrunc: fstpSse(vregFor(n), opWidth(n->getType()), x); return; - case Opcode::SIToFP: - fild(x87SlotOf(n), s); + case Opcode::SIToFP: { + // fild reads all 64 bits, a narrower source loaded from memory is zero extended + VReg wide = fresh(detail::kGp); + mov(wide, s); + signExtBits(wide, intBits(st)); + fild(x87SlotOf(n), wide); return; + } case Opcode::UIToFP: emitUIntToX87(n, s, intBits(st)); return; diff --git a/src/compiler/test/correctness/custom/x87_from_narrow_int_noopt.c b/src/compiler/test/correctness/custom/x87_from_narrow_int_noopt.c new file mode 100644 index 0000000..c4a08c1 --- /dev/null +++ b/src/compiler/test/correctness/custom/x87_from_narrow_int_noopt.c @@ -0,0 +1,10 @@ +// expect: 1 +// passes: + +// a negative int read back from memory, converted to long double +long double widen(int s) { + int* p = &s; + return *p; +} + +int main(void) { return widen(-1) == -1.0L; }