← board

arm32 + i386: Int64→Double conversion drops the high word

Repro

var i: int64; d: double;
begin
  i := int64(1) shl 40;
  d := i;
  writeln(d:0:0);   { FPC/x86-64/aarch64/riscv32: 1099511627776 }
                    { arm32, i386: 0 }
  i := -i;
  d := i;
  writeln(d:0:0);   { -1099511627776; arm32/i386: 0 }
end.

The 32-bit backends' int→double conversion (vcvt/cvtsi2sd/fild-style paths and the IR_STORE float coercions) consume only the low register of the lo:hi pair. Values that fit 32 bits convert fine, which is why nothing in the suite caught it. riscv32 is CORRECT (its soft conversion handles the full pair, signed and unsigned both — verified with 2^63 qwords), so the riscv32 lowering is the reference for the fix.

QWord (unsigned) sources on these targets additionally need the unsigned interpretation — fold that in with the same fix ([[bug-pascal-qword-to-double-signed]] covers x86-64/aarch64/riscv32; arm32 and i386 inherit it here). Correct sequence: d = hi * 2^32 + lo(unsigned), with hi signed for Int64 / unsigned for QWord.

Acceptance

Log