Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[AArch64] Avoid overflow when using shl lower mul #97148

Merged
merged 3 commits into from
Jun 29, 2024

Conversation

DianQK
Copy link
Member

@DianQK DianQK commented Jun 29, 2024

Fixes #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.

DianQK added 2 commits June 29, 2024 15:02
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.
@llvmbot
Copy link
Member

llvmbot commented Jun 29, 2024

@llvm/pr-subscribers-backend-aarch64

Author: DianQK (DianQK)

Changes

Fixes #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.


Full diff: https://github.com/llvm/llvm-project/pull/97148.diff

2 Files Affected:

  • (modified) llvm/lib/Target/AArch64/AArch64ISelLowering.cpp (+13-1)
  • (modified) llvm/test/CodeGen/AArch64/mul_pow2.ll (+19)
diff --git a/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp b/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp
index 0d53f71a4def8..e022646969b62 100644
--- a/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp
+++ b/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp
@@ -18059,16 +18059,28 @@ static SDValue performMulCombine(SDNode *N, SelectionDAG &DAG,
   unsigned ShiftAmt;
 
   auto Shl = [&](SDValue N0, unsigned N1) {
+    if (!N0.getNode())
+      return SDValue();
     SDValue RHS = DAG.getConstant(N1, DL, MVT::i64);
-    return DAG.getNode(ISD::SHL, DL, VT, N0, RHS);
+    SDValue SHL = DAG.getNode(ISD::SHL, DL, VT, N0, RHS);
+    // If shift causes overflow, ignore this combine.
+    if (SHL->isUndef())
+      return SDValue();
+    return SHL;
   };
   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);
   };
diff --git a/llvm/test/CodeGen/AArch64/mul_pow2.ll b/llvm/test/CodeGen/AArch64/mul_pow2.ll
index c4839175ded5a..16a47c9a49a05 100644
--- a/llvm/test/CodeGen/AArch64/mul_pow2.ll
+++ b/llvm/test/CodeGen/AArch64/mul_pow2.ll
@@ -992,3 +992,22 @@ 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
+}

@vfdff
Copy link
Contributor

vfdff commented Jun 29, 2024

LGTM, thanks very much for helping fix this issue.

Copy link
Collaborator

@davemgreen davemgreen left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for looking into this. Could we change it to a check for shift amount > bitwidth? It would feel a little more reliable than checking if the result was folded to undef.

@DianQK
Copy link
Member Author

DianQK commented Jun 29, 2024

Thanks for looking into this. Could we change it to a check for shift amount > bitwidth? It would feel a little more reliable than checking if the result was folded to undef.

I guess I should use getValueSizeInBits. I also added a test case that just doesn't overflow.

Copy link
Collaborator

@davemgreen davemgreen left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks. LGTM

@DianQK DianQK merged commit 4a96803 into llvm:main Jun 29, 2024
5 of 7 checks passed
@DianQK DianQK deleted the aarch64-isel-mul-shl branch June 29, 2024 22:23
@llvm-ci
Copy link
Collaborator

llvm-ci commented Jun 29, 2024

LLVM Buildbot has detected a new failure on builder clang-armv8-quick running on linaro-clang-armv8-quick while building llvm at step 5 "ninja check 1".

Full details are available at: https://lab.llvm.org/buildbot/#/builders/154/builds/712

Here is the relevant piece of the build log for the reference:

Step 5 (ninja check 1) failure: stage 1 checked (failure)
******************** TEST 'LLVM :: Analysis/StructuralHash/structural-hash-printer.ll' FAILED ********************
Exit Code: 1

Command Output (stderr):
--
RUN: at line 1: /home/tcwg-buildbot/worker/clang-armv8-quick/stage1/bin/opt -passes='print<structural-hash>' -disable-output /home/tcwg-buildbot/worker/clang-armv8-quick/llvm/llvm/test/Analysis/StructuralHash/structural-hash-printer.ll 2>&1 | /home/tcwg-buildbot/worker/clang-armv8-quick/stage1/bin/FileCheck /home/tcwg-buildbot/worker/clang-armv8-quick/llvm/llvm/test/Analysis/StructuralHash/structural-hash-printer.ll
+ /home/tcwg-buildbot/worker/clang-armv8-quick/stage1/bin/opt '-passes=print<structural-hash>' -disable-output /home/tcwg-buildbot/worker/clang-armv8-quick/llvm/llvm/test/Analysis/StructuralHash/structural-hash-printer.ll
+ /home/tcwg-buildbot/worker/clang-armv8-quick/stage1/bin/FileCheck /home/tcwg-buildbot/worker/clang-armv8-quick/llvm/llvm/test/Analysis/StructuralHash/structural-hash-printer.ll
RUN: at line 2: /home/tcwg-buildbot/worker/clang-armv8-quick/stage1/bin/opt -passes='print<structural-hash><detailed>' -disable-output /home/tcwg-buildbot/worker/clang-armv8-quick/llvm/llvm/test/Analysis/StructuralHash/structural-hash-printer.ll 2>&1 | /home/tcwg-buildbot/worker/clang-armv8-quick/stage1/bin/FileCheck /home/tcwg-buildbot/worker/clang-armv8-quick/llvm/llvm/test/Analysis/StructuralHash/structural-hash-printer.ll -check-prefix=DETAILED-HASH
+ /home/tcwg-buildbot/worker/clang-armv8-quick/stage1/bin/opt '-passes=print<structural-hash><detailed>' -disable-output /home/tcwg-buildbot/worker/clang-armv8-quick/llvm/llvm/test/Analysis/StructuralHash/structural-hash-printer.ll
+ /home/tcwg-buildbot/worker/clang-armv8-quick/stage1/bin/FileCheck /home/tcwg-buildbot/worker/clang-armv8-quick/llvm/llvm/test/Analysis/StructuralHash/structural-hash-printer.ll -check-prefix=DETAILED-HASH
/home/tcwg-buildbot/worker/clang-armv8-quick/llvm/llvm/test/Analysis/StructuralHash/structural-hash-printer.ll:21:18: error: DETAILED-HASH: expected string not found in input
; DETAILED-HASH: Module Hash: {{([a-z0-9]{14,})}}
                 ^
<stdin>:1:1: note: scanning from here
Module Hash: b88d71c254a5c
^

Input file: <stdin>
Check file: /home/tcwg-buildbot/worker/clang-armv8-quick/llvm/llvm/test/Analysis/StructuralHash/structural-hash-printer.ll

-dump-input=help explains the following input dump.

Input was:
<<<<<<
          1: Module Hash: b88d71c254a5c 
check:21     X~~~~~~~~~~~~~~~~~~~~~~~~~~ error: no match found
          2: Function f1 Hash: 8933af6f80a7d453 
check:21     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
          3: Function f2 Hash: cf63b3f551222a7c 
check:21     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
>>>>>>

--

********************


DianQK added a commit to DianQK/llvm-project that referenced this pull request Jun 30, 2024
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)
nikic pushed a commit to rust-lang/llvm-project that referenced this pull request Jun 30, 2024
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)
lravenclaw pushed a commit to lravenclaw/llvm-project that referenced this pull request Jul 3, 2024
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.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

[AArch64] The multiplication instruction is missing
5 participants