Skip to content

Commit

Permalink
[AArch64] Avoid overflow when using shl lower mul (llvm#97148)
Browse files Browse the repository at this point in the history
Fixes llvm#97147.

Transforming `(mul x, -(2^(N-M) - 1) * 2^M)` to `(sub (shl x, M), (shl
x, N))` will cause overflow when N is 32 and M is 31. I still added
checks for all scenarios, even other scenarios, don't seem to cause overflow.
  • Loading branch information
DianQK authored Jun 29, 2024
1 parent 56b2fcf commit 4a96803
Show file tree
Hide file tree
Showing 2 changed files with 49 additions and 0 deletions.
11 changes: 11 additions & 0 deletions llvm/lib/Target/AArch64/AArch64ISelLowering.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18059,16 +18059,27 @@ static SDValue performMulCombine(SDNode *N, SelectionDAG &DAG,
unsigned ShiftAmt;

auto Shl = [&](SDValue N0, unsigned N1) {
if (!N0.getNode())
return SDValue();
// If shift causes overflow, ignore this combine.
if (N1 >= N0.getValueSizeInBits())
return SDValue();
SDValue RHS = DAG.getConstant(N1, DL, MVT::i64);
return DAG.getNode(ISD::SHL, DL, VT, N0, RHS);
};
auto Add = [&](SDValue N0, SDValue N1) {
if (!N0.getNode() || !N1.getNode())
return SDValue();
return DAG.getNode(ISD::ADD, DL, VT, N0, N1);
};
auto Sub = [&](SDValue N0, SDValue N1) {
if (!N0.getNode() || !N1.getNode())
return SDValue();
return DAG.getNode(ISD::SUB, DL, VT, N0, N1);
};
auto Negate = [&](SDValue N) {
if (!N0.getNode())
return SDValue();
SDValue Zero = DAG.getConstant(0, DL, VT);
return DAG.getNode(ISD::SUB, DL, VT, Zero, N);
};
Expand Down
38 changes: 38 additions & 0 deletions llvm/test/CodeGen/AArch64/mul_pow2.ll
Original file line number Diff line number Diff line change
Expand Up @@ -992,3 +992,41 @@ define <4 x i32> @muladd_demand_commute(<4 x i32> %x, <4 x i32> %y) {
%r = and <4 x i32> %a, <i32 131071, i32 131071, i32 131071, i32 131071>
ret <4 x i32> %r
}

; Transforming `(mul x, -(2^(N-M) - 1) * 2^M)` to `(sub (shl x, M), (shl x, N))`
; will cause overflow when N is 32 and M is 31.
define i32 @shift_overflow(i32 %x) {
; CHECK-LABEL: shift_overflow:
; CHECK: // %bb.0:
; CHECK-NEXT: mov w8, #-2147483648 // =0x80000000
; CHECK-NEXT: mul w0, w0, w8
; CHECK-NEXT: ret
;
; GISEL-LABEL: shift_overflow:
; GISEL: // %bb.0:
; GISEL-NEXT: mov w8, #-2147483648 // =0x80000000
; GISEL-NEXT: mul w0, w0, w8
; GISEL-NEXT: ret
%const = bitcast i32 2147483648 to i32
%r = mul i32 %x, %const
ret i32 %r
}

; Transforming `(mul x, -(2^(N-M) - 1) * 2^M)` to `(sub (shl x, M), (shl x, N))`
; will not cause overflow when N is 31 and M is 30.
define i32 @shift_no_overflow(i32 %x) {
; CHECK-LABEL: shift_no_overflow:
; CHECK: // %bb.0:
; CHECK-NEXT: lsl w8, w0, #31
; CHECK-NEXT: sub w0, w8, w0, lsl #30
; CHECK-NEXT: ret
;
; GISEL-LABEL: shift_no_overflow:
; GISEL: // %bb.0:
; GISEL-NEXT: mov w8, #1073741824 // =0x40000000
; GISEL-NEXT: mul w0, w0, w8
; GISEL-NEXT: ret
%const = bitcast i32 1073741824 to i32
%r = mul i32 %x, %const
ret i32 %r
}

0 comments on commit 4a96803

Please sign in to comment.