[llvm-branch-commits] [llvm] a710137 - [LVI][CVP] Treat undef like a full range on abs(x, false) (#68711)
Tobias Hieta via llvm-branch-commits
llvm-branch-commits at lists.llvm.org
Mon Oct 23 23:31:30 PDT 2023
Author: DianQK
Date: 2023-10-24T08:24:50+02:00
New Revision: a7101379d75e9a3d9a3d9bf32c10ae01f909209a
URL: https://github.com/llvm/llvm-project/commit/a7101379d75e9a3d9a3d9bf32c10ae01f909209a
DIFF: https://github.com/llvm/llvm-project/commit/a7101379d75e9a3d9a3d9bf32c10ae01f909209a.diff
LOG: [LVI][CVP] Treat undef like a full range on abs(x, false) (#68711)
Fixes #68682.
(cherry picked from commit 2ad9a658005e6a4204d7ee617c3949632a707aa5)
Added:
Modified:
llvm/lib/Transforms/Scalar/CorrelatedValuePropagation.cpp
llvm/test/Transforms/CorrelatedValuePropagation/abs.ll
Removed:
################################################################################
diff --git a/llvm/lib/Transforms/Scalar/CorrelatedValuePropagation.cpp b/llvm/lib/Transforms/Scalar/CorrelatedValuePropagation.cpp
index 48b27a1ea0a2984..523196e5e6eab71 100644
--- a/llvm/lib/Transforms/Scalar/CorrelatedValuePropagation.cpp
+++ b/llvm/lib/Transforms/Scalar/CorrelatedValuePropagation.cpp
@@ -470,17 +470,17 @@ static bool processBinOp(BinaryOperator *BinOp, LazyValueInfo *LVI);
// because it is negation-invariant.
static bool processAbsIntrinsic(IntrinsicInst *II, LazyValueInfo *LVI) {
Value *X = II->getArgOperand(0);
- bool IsIntMinPoison = cast<ConstantInt>(II->getArgOperand(1))->isOne();
-
Type *Ty = X->getType();
- Constant *IntMin =
- ConstantInt::get(Ty, APInt::getSignedMinValue(Ty->getScalarSizeInBits()));
- LazyValueInfo::Tristate Result;
+ if (!Ty->isIntegerTy())
+ return false;
+
+ bool IsIntMinPoison = cast<ConstantInt>(II->getArgOperand(1))->isOne();
+ APInt IntMin = APInt::getSignedMinValue(Ty->getScalarSizeInBits());
+ ConstantRange Range = LVI->getConstantRangeAtUse(
+ II->getOperandUse(0), /*UndefAllowed*/ IsIntMinPoison);
// Is X in [0, IntMin]? NOTE: INT_MIN is fine!
- Result = LVI->getPredicateAt(CmpInst::Predicate::ICMP_ULE, X, IntMin, II,
- /*UseBlockValue=*/true);
- if (Result == LazyValueInfo::True) {
+ if (Range.icmp(CmpInst::ICMP_ULE, IntMin)) {
++NumAbs;
II->replaceAllUsesWith(X);
II->eraseFromParent();
@@ -488,40 +488,30 @@ static bool processAbsIntrinsic(IntrinsicInst *II, LazyValueInfo *LVI) {
}
// Is X in [IntMin, 0]? NOTE: INT_MIN is fine!
- Constant *Zero = ConstantInt::getNullValue(Ty);
- Result = LVI->getPredicateAt(CmpInst::Predicate::ICMP_SLE, X, Zero, II,
- /*UseBlockValue=*/true);
- assert(Result != LazyValueInfo::False && "Should have been handled already.");
-
- if (Result == LazyValueInfo::Unknown) {
- // Argument's range crosses zero.
- bool Changed = false;
- if (!IsIntMinPoison) {
- // Can we at least tell that the argument is never INT_MIN?
- Result = LVI->getPredicateAt(CmpInst::Predicate::ICMP_NE, X, IntMin, II,
- /*UseBlockValue=*/true);
- if (Result == LazyValueInfo::True) {
- ++NumNSW;
- ++NumSubNSW;
- II->setArgOperand(1, ConstantInt::getTrue(II->getContext()));
- Changed = true;
- }
- }
- return Changed;
- }
+ if (Range.getSignedMax().isNonPositive()) {
+ IRBuilder<> B(II);
+ Value *NegX = B.CreateNeg(X, II->getName(), /*HasNUW=*/false,
+ /*HasNSW=*/IsIntMinPoison);
+ ++NumAbs;
+ II->replaceAllUsesWith(NegX);
+ II->eraseFromParent();
- IRBuilder<> B(II);
- Value *NegX = B.CreateNeg(X, II->getName(), /*HasNUW=*/false,
- /*HasNSW=*/IsIntMinPoison);
- ++NumAbs;
- II->replaceAllUsesWith(NegX);
- II->eraseFromParent();
+ // See if we can infer some no-wrap flags.
+ if (auto *BO = dyn_cast<BinaryOperator>(NegX))
+ processBinOp(BO, LVI);
- // See if we can infer some no-wrap flags.
- if (auto *BO = dyn_cast<BinaryOperator>(NegX))
- processBinOp(BO, LVI);
+ return true;
+ }
- return true;
+ // Argument's range crosses zero.
+ // Can we at least tell that the argument is never INT_MIN?
+ if (!IsIntMinPoison && !Range.contains(IntMin)) {
+ ++NumNSW;
+ ++NumSubNSW;
+ II->setArgOperand(1, ConstantInt::getTrue(II->getContext()));
+ return true;
+ }
+ return false;
}
// See if this min/max intrinsic always picks it's one specific operand.
diff --git a/llvm/test/Transforms/CorrelatedValuePropagation/abs.ll b/llvm/test/Transforms/CorrelatedValuePropagation/abs.ll
index 6231b05a851cb3f..7f10ce63e2fdcdc 100644
--- a/llvm/test/Transforms/CorrelatedValuePropagation/abs.ll
+++ b/llvm/test/Transforms/CorrelatedValuePropagation/abs.ll
@@ -2,6 +2,7 @@
; RUN: opt < %s -passes=correlated-propagation -S | FileCheck %s
declare void @llvm.assume(i1)
+declare i32 @llvm.abs.i32(i32, i1)
declare i8 @llvm.abs.i8(i8, i1)
declare i1 @llvm.abs.i1(i1, i1)
@@ -379,11 +380,139 @@ define i8 @test27(i8 %x) {
define i1 @pr59887(i1 %x, i1 %c) {
; CHECK-LABEL: @pr59887(
-; CHECK-NEXT: [[ABS:%.*]] = call i1 @llvm.abs.i1(i1 [[X:%.*]], i1 false)
-; CHECK-NEXT: [[RES:%.*]] = select i1 [[C:%.*]], i1 [[ABS]], i1 false
+; CHECK-NEXT: [[RES:%.*]] = select i1 [[C:%.*]], i1 [[X:%.*]], i1 false
; CHECK-NEXT: ret i1 [[RES]]
;
%abs = call i1 @llvm.abs.i1(i1 %x, i1 false)
%res = select i1 %c, i1 %abs, i1 false
ret i1 %res
}
+
+; Because of `undef`, We can't delete `abs`.
+; We can't replace the `abs` argument with true either.
+define i32 @pr68381_undef_abs_false(i1 %c0, i1 %c1, i8 %v1) {
+; CHECK-LABEL: @pr68381_undef_abs_false(
+; CHECK-NEXT: start:
+; CHECK-NEXT: br i1 [[C0:%.*]], label [[BB0:%.*]], label [[BB1:%.*]]
+; CHECK: bb0:
+; CHECK-NEXT: [[V1_I32:%.*]] = zext i8 [[V1:%.*]] to i32
+; CHECK-NEXT: br label [[BB1]]
+; CHECK: bb1:
+; CHECK-NEXT: [[X:%.*]] = phi i32 [ [[V1_I32]], [[BB0]] ], [ undef, [[START:%.*]] ]
+; CHECK-NEXT: br i1 [[C1:%.*]], label [[BB0]], label [[BB2:%.*]]
+; CHECK: bb2:
+; CHECK-NEXT: [[Z:%.*]] = call i32 @llvm.abs.i32(i32 [[X]], i1 false)
+; CHECK-NEXT: ret i32 [[Z]]
+;
+start:
+ br i1 %c0, label %bb0, label %bb1
+
+bb0:
+ %v1_i32 = zext i8 %v1 to i32
+ br label %bb1
+
+bb1:
+ %x = phi i32 [ %v1_i32, %bb0 ], [ undef, %start ]
+ br i1 %c1, label %bb0, label %bb2
+
+bb2:
+ %z = call i32 @llvm.abs.i32(i32 %x, i1 false)
+ ret i32 %z
+}
+
+; Because of `and`, we can delete `abs`.
+define i32 @pr68381_undef_abs_false_and(i1 %c0, i1 %c1, i8 %v1) {
+; CHECK-LABEL: @pr68381_undef_abs_false_and(
+; CHECK-NEXT: start:
+; CHECK-NEXT: br i1 [[C0:%.*]], label [[BB0:%.*]], label [[BB1:%.*]]
+; CHECK: bb0:
+; CHECK-NEXT: [[V1_I32:%.*]] = zext i8 [[V1:%.*]] to i32
+; CHECK-NEXT: br label [[BB1]]
+; CHECK: bb1:
+; CHECK-NEXT: [[X:%.*]] = phi i32 [ [[V1_I32]], [[BB0]] ], [ undef, [[START:%.*]] ]
+; CHECK-NEXT: br i1 [[C1:%.*]], label [[BB0]], label [[BB2:%.*]]
+; CHECK: bb2:
+; CHECK-NEXT: [[Y:%.*]] = and i32 [[X]], 255
+; CHECK-NEXT: ret i32 [[Y]]
+;
+start:
+ br i1 %c0, label %bb0, label %bb1
+
+bb0:
+ %v1_i32 = zext i8 %v1 to i32
+ br label %bb1
+
+bb1:
+ %x = phi i32 [ %v1_i32, %bb0 ], [ undef, %start ]
+ br i1 %c1, label %bb0, label %bb2
+
+bb2:
+ %y = and i32 %x, 255
+ %z = call i32 @llvm.abs.i32(i32 %y, i1 false)
+ ret i32 %z
+}
+
+; Because of `undef`, we can't replace `abs` with `sub`.
+define i32 @pr68381_undef_abs_false_sub(i1 %c0, i1 %c1, i32 %v1, i32 %v2) {
+; CHECK-LABEL: @pr68381_undef_abs_false_sub(
+; CHECK-NEXT: start:
+; CHECK-NEXT: br i1 [[C0:%.*]], label [[BB0:%.*]], label [[BB1:%.*]]
+; CHECK: bb0:
+; CHECK-NEXT: [[V3:%.*]] = add i32 [[V1:%.*]], [[V2:%.*]]
+; CHECK-NEXT: [[LIM:%.*]] = icmp sle i32 [[V3]], -1
+; CHECK-NEXT: call void @llvm.assume(i1 [[LIM]])
+; CHECK-NEXT: br label [[BB1]]
+; CHECK: bb1:
+; CHECK-NEXT: [[X:%.*]] = phi i32 [ [[V3]], [[BB0]] ], [ undef, [[START:%.*]] ]
+; CHECK-NEXT: br i1 [[C1:%.*]], label [[BB0]], label [[BB2:%.*]]
+; CHECK: bb2:
+; CHECK-NEXT: [[Z:%.*]] = call i32 @llvm.abs.i32(i32 [[X]], i1 false)
+; CHECK-NEXT: ret i32 [[Z]]
+;
+start:
+ br i1 %c0, label %bb0, label %bb1
+
+bb0:
+ %v3 = add i32 %v1, %v2
+ %lim = icmp sle i32 %v3, -1
+ call void @llvm.assume(i1 %lim)
+ br label %bb1
+
+bb1:
+ %x = phi i32 [ %v3, %bb0 ], [ undef, %start ]
+ br i1 %c1, label %bb0, label %bb2
+
+bb2:
+ %z = call i32 @llvm.abs.i32(i32 %x, i1 false)
+ ret i32 %z
+}
+
+; We can delete `abs`.
+define i32 @pr68381_undef_abs_true(i1 %c0, i1 %c1, i8 %v1) {
+; CHECK-LABEL: @pr68381_undef_abs_true(
+; CHECK-NEXT: start:
+; CHECK-NEXT: br i1 [[C0:%.*]], label [[BB0:%.*]], label [[BB1:%.*]]
+; CHECK: bb0:
+; CHECK-NEXT: [[V1_I32:%.*]] = zext i8 [[V1:%.*]] to i32
+; CHECK-NEXT: br label [[BB1]]
+; CHECK: bb1:
+; CHECK-NEXT: [[X:%.*]] = phi i32 [ [[V1_I32]], [[BB0]] ], [ undef, [[START:%.*]] ]
+; CHECK-NEXT: br i1 [[C1:%.*]], label [[BB0]], label [[BB2:%.*]]
+; CHECK: bb2:
+; CHECK-NEXT: ret i32 [[X]]
+;
+start:
+ br i1 %c0, label %bb0, label %bb1
+
+bb0:
+ %v1_i32 = zext i8 %v1 to i32
+ br label %bb1
+
+bb1:
+ %x = phi i32 [ %v1_i32, %bb0 ], [ undef, %start ]
+ br i1 %c1, label %bb0, label %bb2
+
+bb2:
+ %z = call i32 @llvm.abs.i32(i32 %x, i1 true)
+ ret i32 %z
+}
More information about the llvm-branch-commits
mailing list