Skip to content

Commit 934954a

Browse files
dianqknikic
authored andcommitted
[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. (cherry picked from commit 4a96803)
1 parent 5a5152f commit 934954a

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
@@ -17153,16 +17153,27 @@ static SDValue performMulCombine(SDNode *N, SelectionDAG &DAG,
1715317153
unsigned ShiftAmt;
1715417154

1715517155
auto Shl = [&](SDValue N0, unsigned N1) {
17156+
if (!N0.getNode())
17157+
return SDValue();
17158+
// If shift causes overflow, ignore this combine.
17159+
if (N1 >= N0.getValueSizeInBits())
17160+
return SDValue();
1715617161
SDValue RHS = DAG.getConstant(N1, DL, MVT::i64);
1715717162
return DAG.getNode(ISD::SHL, DL, VT, N0, RHS);
1715817163
};
1715917164
auto Add = [&](SDValue N0, SDValue N1) {
17165+
if (!N0.getNode() || !N1.getNode())
17166+
return SDValue();
1716017167
return DAG.getNode(ISD::ADD, DL, VT, N0, N1);
1716117168
};
1716217169
auto Sub = [&](SDValue N0, SDValue N1) {
17170+
if (!N0.getNode() || !N1.getNode())
17171+
return SDValue();
1716317172
return DAG.getNode(ISD::SUB, DL, VT, N0, N1);
1716417173
};
1716517174
auto Negate = [&](SDValue N) {
17175+
if (!N0.getNode())
17176+
return SDValue();
1716617177
SDValue Zero = DAG.getConstant(0, DL, VT);
1716717178
return DAG.getNode(ISD::SUB, DL, VT, Zero, N);
1716817179
};

llvm/test/CodeGen/AArch64/mul_pow2.ll

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -869,3 +869,41 @@ define <4 x i32> @muladd_demand_commute(<4 x i32> %x, <4 x i32> %y) {
869869
%r = and <4 x i32> %a, <i32 131071, i32 131071, i32 131071, i32 131071>
870870
ret <4 x i32> %r
871871
}
872+
873+
; Transforming `(mul x, -(2^(N-M) - 1) * 2^M)` to `(sub (shl x, M), (shl x, N))`
874+
; will cause overflow when N is 32 and M is 31.
875+
define i32 @shift_overflow(i32 %x) {
876+
; CHECK-LABEL: shift_overflow:
877+
; CHECK: // %bb.0:
878+
; CHECK-NEXT: mov w8, #-2147483648 // =0x80000000
879+
; CHECK-NEXT: mul w0, w0, w8
880+
; CHECK-NEXT: ret
881+
;
882+
; GISEL-LABEL: shift_overflow:
883+
; GISEL: // %bb.0:
884+
; GISEL-NEXT: mov w8, #-2147483648 // =0x80000000
885+
; GISEL-NEXT: mul w0, w0, w8
886+
; GISEL-NEXT: ret
887+
%const = bitcast i32 2147483648 to i32
888+
%r = mul i32 %x, %const
889+
ret i32 %r
890+
}
891+
892+
; Transforming `(mul x, -(2^(N-M) - 1) * 2^M)` to `(sub (shl x, M), (shl x, N))`
893+
; will not cause overflow when N is 31 and M is 30.
894+
define i32 @shift_no_overflow(i32 %x) {
895+
; CHECK-LABEL: shift_no_overflow:
896+
; CHECK: // %bb.0:
897+
; CHECK-NEXT: lsl w8, w0, #31
898+
; CHECK-NEXT: sub w0, w8, w0, lsl #30
899+
; CHECK-NEXT: ret
900+
;
901+
; GISEL-LABEL: shift_no_overflow:
902+
; GISEL: // %bb.0:
903+
; GISEL-NEXT: mov w8, #1073741824 // =0x40000000
904+
; GISEL-NEXT: mul w0, w0, w8
905+
; GISEL-NEXT: ret
906+
%const = bitcast i32 1073741824 to i32
907+
%r = mul i32 %x, %const
908+
ret i32 %r
909+
}

0 commit comments

Comments
 (0)