-
Notifications
You must be signed in to change notification settings - Fork 14.3k
[InstCombine] Prevent infinite loop with two shifts #118806
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
Conversation
@llvm/pr-subscribers-llvm-transforms Author: Maurice Heumann (momo5502) ChangesThe following pattern: However, this should not be done when This fixes #118798 Full diff: https://github.com/llvm/llvm-project/pull/118806.diff 2 Files Affected:
diff --git a/llvm/lib/Transforms/InstCombine/InstCombineShifts.cpp b/llvm/lib/Transforms/InstCombine/InstCombineShifts.cpp
index 10c3ccdb2243a1..3fb094579d585a 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineShifts.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineShifts.cpp
@@ -786,7 +786,9 @@ Instruction *InstCombinerImpl::FoldShiftByConstant(Value *Op0, Constant *C1,
Constant *C2;
Value *X;
bool IsLeftShift = I.getOpcode() == Instruction::Shl;
- if (match(Op0, m_BinOp(I.getOpcode(), m_ImmConstant(C2), m_Value(X)))) {
+ if (match(Op0,
+ m_BinOp(I.getOpcode(), m_ImmConstant(C2),
+ m_CombineAnd(m_Value(X), m_Unless(m_Constant()))))) {
Instruction *R = BinaryOperator::Create(
I.getOpcode(), Builder.CreateBinOp(I.getOpcode(), C2, C1), X);
BinaryOperator *BO0 = cast<BinaryOperator>(Op0);
diff --git a/llvm/test/Transforms/InstCombine/shl-twice-constant.ll b/llvm/test/Transforms/InstCombine/shl-twice-constant.ll
new file mode 100644
index 00000000000000..54c5611400f46c
--- /dev/null
+++ b/llvm/test/Transforms/InstCombine/shl-twice-constant.ll
@@ -0,0 +1,22 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
+; RUN: opt < %s -passes=instcombine -S | FileCheck %s
+
+@c = external constant i8
+@c2 = external constant i8
+
+define i16 @testfunc() {
+; CHECK-LABEL: @testfunc(
+; CHECK-NEXT: entry:
+; CHECK-NEXT: [[TMP0:%.*]] = shl nuw i64 1, ptrtoint (ptr @c2 to i64)
+; CHECK-NEXT: [[TMP1:%.*]] = shl i64 [[TMP0]], ptrtoint (ptr @c to i64)
+; CHECK-NEXT: [[TMP2:%.*]] = inttoptr i64 [[TMP1]] to ptr
+; CHECK-NEXT: [[TMP3:%.*]] = load i16, ptr [[TMP2]], align 1
+; CHECK-NEXT: ret i16 [[TMP3]]
+;
+entry:
+ %0 = shl i64 1, ptrtoint (ptr @c2 to i64)
+ %1 = shl i64 %0, ptrtoint (ptr @c to i64)
+ %2 = inttoptr i64 %1 to ptr
+ %3 = load i16, ptr %2, align 1
+ ret i16 %3
+}
|
✅ With the latest revision this PR passed the C/C++ code formatter. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it may be better to address this by replacing the check in
if (Constant *CUI = dyn_cast<Constant>(Op1)) |
done |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LG
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The last two instructions in this test shouldn't be needed, it can be reduced to:
@c = external constant i8
@c2 = external constant i8
define i64 @testfunc() {
%shl1 = shl i64 1, ptrtoint (ptr @c2 to i64)
%shl2 = shl i64 %shl1, ptrtoint (ptr @c to i64)
ret i64 %shl2
}
```.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
test adjusted. thank you for the review :)
The following pattern: `(C2 << X) << C1` will usually be transformed into `(C2 << C1) << X`, essentially swapping `X` and `C1`. However, this should not only done when `C1` is an immediate constant, otherwise this can lead to both constants being swapped forever This fixes llvm#118798
I think this might have broken some combines with scalable vectors, beforehand this define <vscale x 4 x i8> @f(<vscale x 4 x i8> %x) {
%1 = and <vscale x 4 x i8> %x, splat (i8 2)
%2 = shl <vscale x 4 x i8> %1, splat (i8 2)
ret <vscale x 4 x i8> %2
} used to get combined to define <vscale x 4 x i8> @f(<vscale x 4 x i8> %x) {
%1 = shl <vscale x 4 x i8> %x, splat (i8 2)
%2 = and <vscale x 4 x i8> %1, splat (i8 8)
ret <vscale x 4 x i8> %2
} But now this fails because a scalable splat vector is a constant expression IIUC. Maybe we need some sort of pattern matcher that matches constant immediates + constant splats? |
#118806 fixed an infinite loop in FoldShiftByConstant that could occur when the shift amount was a ConstantExpr. However this meant that FoldShiftByConstant no longer kicked in for scalable vectors because scalable splats are represented by ConstantExprs. This fixes it by allowing scalable splats of non-ConstantExprs in m_ImmConstant, which also fixes a few other test cases where scalable splats were being missed. But I'm also hoping that UseConstantIntForScalableSplat will eventually remove the need for this. I noticed this when trying to reverse a combine on RISC-V in #132245, and saw that the resulting vector and scalar forms were different. --------- Co-authored-by: Yingwei Zheng <[email protected]>
…" (#134262) This reapplies #132522. Previously casts of scalable m_ImmConstant splats weren't being folded by ConstantFoldCastOperand, triggering the "Constant-fold of ImmConstant should not fail" assertion. There are no changes to the code in this PR, instead we just needed #133207 to land first. A test has been added for the assertion in llvm/test/Transforms/InstSimplify/vec-icmp-of-cast.ll @icmp_ult_sext_scalable_splat_is_true. <hr/> #118806 fixed an infinite loop in FoldShiftByConstant that could occur when the shift amount was a ConstantExpr. However this meant that FoldShiftByConstant no longer kicked in for scalable vectors because scalable splats are represented by ConstantExprs. This fixes it by allowing scalable splats of non-ConstantExprs in m_ImmConstant, which also fixes a few other test cases where scalable splats were being missed. But I'm also hoping that UseConstantIntForScalableSplat will eventually remove the need for this. I noticed this when trying to reverse a combine on RISC-V in #132245, and saw that the resulting vector and scalar forms were different.
The following pattern:
(C2 << X) << C1
will usually be transformed into(C2 << C1) << X
, essentially swappingX
andC1
.However, this should only be done when
C1
is an immediate constant, otherwise thiscan lead to both constants being swapped forever
This fixes #118798