Skip to content

Commit 4a96803

Browse files
authored
[AArch64] Avoid overflow when using shl lower mul (llvm#97148)
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.
1 parent 56b2fcf commit 4a96803

File tree

2 files changed

+49
-0
lines changed

2 files changed

+49
-0
lines changed

llvm/lib/Target/AArch64/AArch64ISelLowering.cpp

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18059,16 +18059,27 @@ static SDValue performMulCombine(SDNode *N, SelectionDAG &DAG,
1805918059
unsigned ShiftAmt;
1806018060

1806118061
auto Shl = [&](SDValue N0, unsigned N1) {
18062+
if (!N0.getNode())
18063+
return SDValue();
18064+
// If shift causes overflow, ignore this combine.
18065+
if (N1 >= N0.getValueSizeInBits())
18066+
return SDValue();
1806218067
SDValue RHS = DAG.getConstant(N1, DL, MVT::i64);
1806318068
return DAG.getNode(ISD::SHL, DL, VT, N0, RHS);
1806418069
};
1806518070
auto Add = [&](SDValue N0, SDValue N1) {
18071+
if (!N0.getNode() || !N1.getNode())
18072+
return SDValue();
1806618073
return DAG.getNode(ISD::ADD, DL, VT, N0, N1);
1806718074
};
1806818075
auto Sub = [&](SDValue N0, SDValue N1) {
18076+
if (!N0.getNode() || !N1.getNode())
18077+
return SDValue();
1806918078
return DAG.getNode(ISD::SUB, DL, VT, N0, N1);
1807018079
};
1807118080
auto Negate = [&](SDValue N) {
18081+
if (!N0.getNode())
18082+
return SDValue();
1807218083
SDValue Zero = DAG.getConstant(0, DL, VT);
1807318084
return DAG.getNode(ISD::SUB, DL, VT, Zero, N);
1807418085
};

llvm/test/CodeGen/AArch64/mul_pow2.ll

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -992,3 +992,41 @@ define <4 x i32> @muladd_demand_commute(<4 x i32> %x, <4 x i32> %y) {
992992
%r = and <4 x i32> %a, <i32 131071, i32 131071, i32 131071, i32 131071>
993993
ret <4 x i32> %r
994994
}
995+
996+
; Transforming `(mul x, -(2^(N-M) - 1) * 2^M)` to `(sub (shl x, M), (shl x, N))`
997+
; will cause overflow when N is 32 and M is 31.
998+
define i32 @shift_overflow(i32 %x) {
999+
; CHECK-LABEL: shift_overflow:
1000+
; CHECK: // %bb.0:
1001+
; CHECK-NEXT: mov w8, #-2147483648 // =0x80000000
1002+
; CHECK-NEXT: mul w0, w0, w8
1003+
; CHECK-NEXT: ret
1004+
;
1005+
; GISEL-LABEL: shift_overflow:
1006+
; GISEL: // %bb.0:
1007+
; GISEL-NEXT: mov w8, #-2147483648 // =0x80000000
1008+
; GISEL-NEXT: mul w0, w0, w8
1009+
; GISEL-NEXT: ret
1010+
%const = bitcast i32 2147483648 to i32
1011+
%r = mul i32 %x, %const
1012+
ret i32 %r
1013+
}
1014+
1015+
; Transforming `(mul x, -(2^(N-M) - 1) * 2^M)` to `(sub (shl x, M), (shl x, N))`
1016+
; will not cause overflow when N is 31 and M is 30.
1017+
define i32 @shift_no_overflow(i32 %x) {
1018+
; CHECK-LABEL: shift_no_overflow:
1019+
; CHECK: // %bb.0:
1020+
; CHECK-NEXT: lsl w8, w0, #31
1021+
; CHECK-NEXT: sub w0, w8, w0, lsl #30
1022+
; CHECK-NEXT: ret
1023+
;
1024+
; GISEL-LABEL: shift_no_overflow:
1025+
; GISEL: // %bb.0:
1026+
; GISEL-NEXT: mov w8, #1073741824 // =0x40000000
1027+
; GISEL-NEXT: mul w0, w0, w8
1028+
; GISEL-NEXT: ret
1029+
%const = bitcast i32 1073741824 to i32
1030+
%r = mul i32 %x, %const
1031+
ret i32 %r
1032+
}

0 commit comments

Comments
 (0)