Skip to content

Commit 7e43211

Browse files
authored
riscv64: Fix uadd_overflow for 32-bit integers (#12951)
This commit fixes a mistake from #11583 where the implementation of `uadd_overflow` on riscv64 was not correct for some inputs. This fix generates the same codegen as `uadd_overflow_trap` which is to zero-extend both inputs, perform a 64-bit add, and use the 33rd bit as the overflow flag. This sequence does notably differ from what LLVM generates. For example this input function #[unsafe(no_mangle)] pub fn uadd_overflow(a: u64, b: u64) -> (u32, bool) { (a as u32).overflowing_add(b as u32) } generates: uadd_overflow: addw a0, a0, a1 sext.w a1, a1 sltu a1, a0, a1 ret While this is probably correct I find it tough to reason about how `addw` produces a sign-extended result, `sext.w` sign-extends one of the operands, and then an unsigned comparison is used to generate the overflow flag for an unsigned addition. Overall I felt it was easier to just match the `uadd_overflow_trap` codegen.
1 parent 2a50190 commit 7e43211

2 files changed

Lines changed: 6 additions & 4 deletions

File tree

cranelift/codegen/src/isa/riscv64/lower.isle

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -330,9 +330,10 @@
330330

331331
;; i32 case (on RV64 use addw to detect 32-bit overflow correctly)
332332
(rule 1 (lower (has_type $I32 (uadd_overflow _ x y)))
333-
(let ((x64 XReg (zext x))
334-
(sum XReg (rv_addw x y))
335-
(overflow XReg (rv_sltu sum x64)))
333+
(let ((x64 XReg (zext x))
334+
(y64 XReg (zext y))
335+
(sum XReg (rv_add x64 y64))
336+
(overflow XReg (rv_srli sum (imm12_const 32))))
336337
(output_pair sum overflow)))
337338

338339
;; For i128, we need to handle the high and low parts separately
@@ -347,7 +348,7 @@
347348
(carry XReg (rv_sltu sum_lo x_lo))
348349
(sum_hi XReg (rv_add x_hi y_hi))
349350
(sum_hi_with_carry XReg (rv_add sum_hi carry))
350-
(overflow XReg (rv_or (rv_sltu sum_hi_with_carry x_hi)
351+
(overflow XReg (rv_or (rv_sltu sum_hi_with_carry x_hi)
351352
(rv_and carry (rv_seqz (rv_xor sum_hi_with_carry x_hi))))))
352353
(output_pair (value_regs sum_lo sum_hi_with_carry) overflow)))
353354

cranelift/filetests/filetests/runtests/uadd_overflow.clif

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,3 +40,4 @@ block0(v0: i32, v1: i32):
4040
; run: %uaddof_i32(100, 28) == [128, 0]
4141
; run: %uaddof_i32(3000000000, 1294967295) == [-1, 0]
4242
; run: %uaddof_i32(3000000000, 1294967296) == [0, 1]
43+
; run: %uaddof_i32(0x80000001, -1) == [0x80000000, 1]

0 commit comments

Comments
 (0)