-
Notifications
You must be signed in to change notification settings - Fork 12.6k
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
[ValueTracking] Extend LHS/RHS with matching operand to work without constants. #85557
Conversation
@llvm/pr-subscribers-llvm-transforms Author: None (goldsteinn) ChangesPreviously we only handled the We can get more out of the analysis using general constant ranges For example, In general, any strict comparison on Full diff: https://github.com/llvm/llvm-project/pull/85557.diff 7 Files Affected:
diff --git a/llvm/lib/Analysis/ValueTracking.cpp b/llvm/lib/Analysis/ValueTracking.cpp
index edbeede910d7f7..b2846274a36e73 100644
--- a/llvm/lib/Analysis/ValueTracking.cpp
+++ b/llvm/lib/Analysis/ValueTracking.cpp
@@ -8499,20 +8499,20 @@ isImpliedCondMatchingOperands(CmpInst::Predicate LPred,
return std::nullopt;
}
-/// Return true if "icmp LPred X, LC" implies "icmp RPred X, RC" is true.
-/// Return false if "icmp LPred X, LC" implies "icmp RPred X, RC" is false.
+/// Return true if "icmp LPred X, LCR" implies "icmp RPred X, RCR" is true.
+/// Return false if "icmp LPred X, LCR" implies "icmp RPred X, RCR" is false.
/// Otherwise, return std::nullopt if we can't infer anything.
-static std::optional<bool> isImpliedCondCommonOperandWithConstants(
- CmpInst::Predicate LPred, const APInt &LC, CmpInst::Predicate RPred,
- const APInt &RC) {
- ConstantRange DomCR = ConstantRange::makeExactICmpRegion(LPred, LC);
- ConstantRange CR = ConstantRange::makeExactICmpRegion(RPred, RC);
- ConstantRange Intersection = DomCR.intersectWith(CR);
- ConstantRange Difference = DomCR.difference(CR);
- if (Intersection.isEmptySet())
- return false;
- if (Difference.isEmptySet())
+static std::optional<bool>
+isImpliedCondCommonOperandWithCR(CmpInst::Predicate LPred, ConstantRange LCR,
+ CmpInst::Predicate RPred, ConstantRange RCR) {
+ ConstantRange DomCR = ConstantRange::makeAllowedICmpRegion(LPred, LCR);
+ // If all true values for lhs and true for rhs, lhs implies rhs
+ if (DomCR.icmp(RPred, RCR))
return true;
+
+ // If there is no overlap, lhs implies not rhs
+ if (DomCR.icmp(CmpInst::getInversePredicate(RPred), RCR))
+ return false;
return std::nullopt;
}
@@ -8532,11 +8532,38 @@ static std::optional<bool> isImpliedCondICmps(const ICmpInst *LHS,
CmpInst::Predicate LPred =
LHSIsTrue ? LHS->getPredicate() : LHS->getInversePredicate();
- // Can we infer anything when the 0-operands match and the 1-operands are
- // constants (not necessarily matching)?
- const APInt *LC, *RC;
- if (L0 == R0 && match(L1, m_APInt(LC)) && match(R1, m_APInt(RC)))
- return isImpliedCondCommonOperandWithConstants(LPred, *LC, RPred, *RC);
+ if (L0 == R1) {
+ std::swap(R0, R1);
+ RPred = ICmpInst::getSwappedPredicate(RPred);
+ }
+ if (L1 == R0) {
+ std::swap(L0, L1);
+ LPred = ICmpInst::getSwappedPredicate(LPred);
+ }
+
+ // See if we can infer anything if operand-0 matches and we have at least one
+ // constant operand-1.
+ if (L0 == R0 && L0->getType()->isIntOrIntVectorTy()) {
+ // Potential TODO: We could also further use the constant range of L0/R0 to
+ // further constraint the constant ranges. At the moment this leads to
+ // several regressions related to not transforming `multi_use(A + C0) eq/ne
+ // C1` (see discussion: D58633).
+ ConstantRange LCR = computeConstantRange(
+ L1, ICmpInst::isSigned(LPred), /* UseInstrInfo=*/true, /*AC=*/nullptr,
+ /*CxtI=*/nullptr, /*DT=*/nullptr, Depth);
+ ConstantRange RCR = computeConstantRange(
+ R1, ICmpInst::isSigned(RPred), /* UseInstrInfo=*/true, /*AC=*/nullptr,
+ /*CxtI=*/nullptr, /*DT=*/nullptr, Depth);
+ // Even if L1/R1 are not both constant, we can still sometimes deduce
+ // relationship from a single constant. For example X u> Y implies X != 0.
+ if (auto R = isImpliedCondCommonOperandWithCR(LPred, LCR, RPred, RCR))
+ return R;
+ // If both L1/R1 where exact constant ranges and we didn't get anything
+ // here, we won't be able to deduce this.
+ const APInt *Unused;
+ if (match(L1, m_APInt(Unused)) && match(R1, m_APInt(Unused)))
+ return std::nullopt;
+ }
// Can we infer anything when the two compares have matching operands?
bool AreSwappedOps;
diff --git a/llvm/test/Transforms/InstCombine/assume.ll b/llvm/test/Transforms/InstCombine/assume.ll
index 927f0a86b0a252..87c75fb2b55592 100644
--- a/llvm/test/Transforms/InstCombine/assume.ll
+++ b/llvm/test/Transforms/InstCombine/assume.ll
@@ -386,7 +386,7 @@ define i1 @nonnull5(ptr %a) {
define i32 @assumption_conflicts_with_known_bits(i32 %a, i32 %b) {
; CHECK-LABEL: @assumption_conflicts_with_known_bits(
; CHECK-NEXT: store i1 true, ptr poison, align 1
-; CHECK-NEXT: ret i32 1
+; CHECK-NEXT: ret i32 poison
;
%and1 = and i32 %b, 3
%B1 = lshr i32 %and1, %and1
diff --git a/llvm/test/Transforms/InstCombine/range-check.ll b/llvm/test/Transforms/InstCombine/range-check.ll
index 0d138b6ba7e79d..210e57c1d1fe4c 100644
--- a/llvm/test/Transforms/InstCombine/range-check.ll
+++ b/llvm/test/Transforms/InstCombine/range-check.ll
@@ -340,11 +340,7 @@ define i1 @negative4_logical(i32 %x, i32 %n) {
define i1 @negative5(i32 %x, i32 %n) {
; CHECK-LABEL: @negative5(
-; CHECK-NEXT: [[NN:%.*]] = and i32 [[N:%.*]], 2147483647
-; CHECK-NEXT: [[A:%.*]] = icmp sgt i32 [[NN]], [[X:%.*]]
-; CHECK-NEXT: [[B:%.*]] = icmp sgt i32 [[X]], -1
-; CHECK-NEXT: [[C:%.*]] = or i1 [[A]], [[B]]
-; CHECK-NEXT: ret i1 [[C]]
+; CHECK-NEXT: ret i1 true
;
%nn = and i32 %n, 2147483647
%a = icmp slt i32 %x, %nn
@@ -355,11 +351,7 @@ define i1 @negative5(i32 %x, i32 %n) {
define i1 @negative5_logical(i32 %x, i32 %n) {
; CHECK-LABEL: @negative5_logical(
-; CHECK-NEXT: [[NN:%.*]] = and i32 [[N:%.*]], 2147483647
-; CHECK-NEXT: [[A:%.*]] = icmp sgt i32 [[NN]], [[X:%.*]]
-; CHECK-NEXT: [[B:%.*]] = icmp sgt i32 [[X]], -1
-; CHECK-NEXT: [[C:%.*]] = or i1 [[A]], [[B]]
-; CHECK-NEXT: ret i1 [[C]]
+; CHECK-NEXT: ret i1 true
;
%nn = and i32 %n, 2147483647
%a = icmp slt i32 %x, %nn
diff --git a/llvm/test/Transforms/InstCombine/select.ll b/llvm/test/Transforms/InstCombine/select.ll
index a84904106eced4..d9734242a86891 100644
--- a/llvm/test/Transforms/InstCombine/select.ll
+++ b/llvm/test/Transforms/InstCombine/select.ll
@@ -2925,10 +2925,8 @@ define i8 @select_replacement_loop3(i32 noundef %x) {
define i16 @select_replacement_loop4(i16 noundef %p_12) {
; CHECK-LABEL: @select_replacement_loop4(
-; CHECK-NEXT: [[CMP1:%.*]] = icmp ult i16 [[P_12:%.*]], 2
-; CHECK-NEXT: [[AND1:%.*]] = and i16 [[P_12]], 1
-; CHECK-NEXT: [[AND2:%.*]] = select i1 [[CMP1]], i16 [[AND1]], i16 0
-; CHECK-NEXT: [[CMP2:%.*]] = icmp eq i16 [[AND2]], [[P_12]]
+; CHECK-NEXT: [[AND1:%.*]] = and i16 [[P_12:%.*]], 1
+; CHECK-NEXT: [[CMP2:%.*]] = icmp ult i16 [[P_12]], 2
; CHECK-NEXT: [[AND3:%.*]] = select i1 [[CMP2]], i16 [[AND1]], i16 0
; CHECK-NEXT: ret i16 [[AND3]]
;
diff --git a/llvm/test/Transforms/InstCombine/shift.ll b/llvm/test/Transforms/InstCombine/shift.ll
index 62f32c28683711..bef7fc81a7d1f9 100644
--- a/llvm/test/Transforms/InstCombine/shift.ll
+++ b/llvm/test/Transforms/InstCombine/shift.ll
@@ -1751,12 +1751,11 @@ define void @ashr_out_of_range_1(ptr %A) {
; CHECK-NEXT: [[L:%.*]] = load i177, ptr [[A:%.*]], align 4
; CHECK-NEXT: [[L_FROZEN:%.*]] = freeze i177 [[L]]
; CHECK-NEXT: [[TMP1:%.*]] = icmp eq i177 [[L_FROZEN]], -1
-; CHECK-NEXT: [[B:%.*]] = select i1 [[TMP1]], i177 0, i177 [[L_FROZEN]]
-; CHECK-NEXT: [[TMP2:%.*]] = trunc i177 [[B]] to i64
+; CHECK-NEXT: [[TMP6:%.*]] = trunc i177 [[L_FROZEN]] to i64
+; CHECK-NEXT: [[TMP2:%.*]] = select i1 [[TMP1]], i64 0, i64 [[TMP6]]
; CHECK-NEXT: [[TMP3:%.*]] = getelementptr i177, ptr [[A]], i64 [[TMP2]]
; CHECK-NEXT: [[G11:%.*]] = getelementptr i8, ptr [[TMP3]], i64 -24
-; CHECK-NEXT: [[C17:%.*]] = icmp sgt i177 [[B]], [[L_FROZEN]]
-; CHECK-NEXT: [[TMP4:%.*]] = sext i1 [[C17]] to i64
+; CHECK-NEXT: [[TMP4:%.*]] = sext i1 [[TMP1]] to i64
; CHECK-NEXT: [[G62:%.*]] = getelementptr i177, ptr [[G11]], i64 [[TMP4]]
; CHECK-NEXT: [[TMP5:%.*]] = icmp eq i177 [[L_FROZEN]], -1
; CHECK-NEXT: [[B28:%.*]] = select i1 [[TMP5]], i177 0, i177 [[L_FROZEN]]
diff --git a/llvm/test/Transforms/LoopVectorize/X86/pr23997.ll b/llvm/test/Transforms/LoopVectorize/X86/pr23997.ll
index 0b16d80a4adbc5..5aeac1101fe223 100644
--- a/llvm/test/Transforms/LoopVectorize/X86/pr23997.ll
+++ b/llvm/test/Transforms/LoopVectorize/X86/pr23997.ll
@@ -12,8 +12,7 @@ define void @foo(ptr addrspace(1) align 8 dereferenceable_or_null(16), ptr addrs
; CHECK: preheader:
; CHECK-NEXT: [[DOT10:%.*]] = getelementptr inbounds i8, ptr addrspace(1) [[TMP0:%.*]], i64 16
; CHECK-NEXT: [[DOT12:%.*]] = getelementptr inbounds i8, ptr addrspace(1) [[TMP1:%.*]], i64 16
-; CHECK-NEXT: [[UMAX2:%.*]] = call i64 @llvm.umax.i64(i64 [[TMP2:%.*]], i64 1)
-; CHECK-NEXT: [[MIN_ITERS_CHECK:%.*]] = icmp ult i64 [[TMP2]], 16
+; CHECK-NEXT: [[MIN_ITERS_CHECK:%.*]] = icmp ult i64 [[TMP2:%.*]], 16
; CHECK-NEXT: br i1 [[MIN_ITERS_CHECK]], label [[SCALAR_PH:%.*]], label [[VECTOR_MEMCHECK:%.*]]
; CHECK: vector.memcheck:
; CHECK-NEXT: [[TMP3:%.*]] = shl i64 [[TMP2]], 3
@@ -25,7 +24,7 @@ define void @foo(ptr addrspace(1) align 8 dereferenceable_or_null(16), ptr addrs
; CHECK-NEXT: [[FOUND_CONFLICT:%.*]] = and i1 [[BOUND0]], [[BOUND1]]
; CHECK-NEXT: br i1 [[FOUND_CONFLICT]], label [[SCALAR_PH]], label [[VECTOR_PH:%.*]]
; CHECK: vector.ph:
-; CHECK-NEXT: [[N_VEC:%.*]] = and i64 [[UMAX2]], -16
+; CHECK-NEXT: [[N_VEC:%.*]] = and i64 [[TMP2]], -16
; CHECK-NEXT: br label [[VECTOR_BODY:%.*]]
; CHECK: vector.body:
; CHECK-NEXT: [[INDEX:%.*]] = phi i64 [ 0, [[VECTOR_PH]] ], [ [[INDEX_NEXT:%.*]], [[VECTOR_BODY]] ]
@@ -49,7 +48,7 @@ define void @foo(ptr addrspace(1) align 8 dereferenceable_or_null(16), ptr addrs
; CHECK-NEXT: [[TMP13:%.*]] = icmp eq i64 [[INDEX_NEXT]], [[N_VEC]]
; CHECK-NEXT: br i1 [[TMP13]], label [[MIDDLE_BLOCK:%.*]], label [[VECTOR_BODY]], !llvm.loop [[LOOP5:![0-9]+]]
; CHECK: middle.block:
-; CHECK-NEXT: [[CMP_N:%.*]] = icmp eq i64 [[UMAX2]], [[N_VEC]]
+; CHECK-NEXT: [[CMP_N:%.*]] = icmp eq i64 [[N_VEC]], [[TMP2]]
; CHECK-NEXT: br i1 [[CMP_N]], label [[LOOPEXIT:%.*]], label [[SCALAR_PH]]
; CHECK: scalar.ph:
; CHECK-NEXT: [[BC_RESUME_VAL:%.*]] = phi i64 [ [[N_VEC]], [[MIDDLE_BLOCK]] ], [ 0, [[PREHEADER]] ], [ 0, [[VECTOR_MEMCHECK]] ]
diff --git a/llvm/test/Transforms/NewGVN/pr35125.ll b/llvm/test/Transforms/NewGVN/pr35125.ll
index 9a96594e3446db..6724538a5a7f29 100644
--- a/llvm/test/Transforms/NewGVN/pr35125.ll
+++ b/llvm/test/Transforms/NewGVN/pr35125.ll
@@ -18,15 +18,12 @@ define i32 @main() #0 {
; CHECK-NEXT: [[CMP2:%.*]] = icmp ult i32 [[STOREMERGE]], [[PHIOFOPS]]
; CHECK-NEXT: br i1 [[CMP2]], label [[IF_THEN3:%.*]], label [[IF_END6:%.*]]
; CHECK: if.then3:
-; CHECK-NEXT: [[TOBOOL:%.*]] = icmp eq i32 [[STOREMERGE]], -1
-; CHECK-NEXT: br i1 [[TOBOOL]], label [[LOR_RHS:%.*]], label [[LOR_END:%.*]]
+; CHECK-NEXT: br i1 false, label [[LOR_RHS:%.*]], label [[LOR_END:%.*]]
; CHECK: lor.rhs:
-; CHECK-NEXT: [[TOBOOL5:%.*]] = icmp ne i32 [[TMP0]], 0
-; CHECK-NEXT: [[PHITMP:%.*]] = zext i1 [[TOBOOL5]] to i32
+; CHECK-NEXT: store i8 poison, ptr null, align 1
; CHECK-NEXT: br label [[LOR_END]]
; CHECK: lor.end:
-; CHECK-NEXT: [[TMP1:%.*]] = phi i32 [ 1, [[IF_THEN3]] ], [ [[PHITMP]], [[LOR_RHS]] ]
-; CHECK-NEXT: store i32 [[TMP1]], ptr @a, align 4
+; CHECK-NEXT: store i32 1, ptr @a, align 4
; CHECK-NEXT: br label [[IF_END6]]
; CHECK: if.end6:
; CHECK-NEXT: [[TMP2:%.*]] = load i32, ptr @a, align 4
|
@llvm/pr-subscribers-llvm-analysis Author: None (goldsteinn) ChangesPreviously we only handled the We can get more out of the analysis using general constant ranges For example, In general, any strict comparison on Full diff: https://github.com/llvm/llvm-project/pull/85557.diff 7 Files Affected:
diff --git a/llvm/lib/Analysis/ValueTracking.cpp b/llvm/lib/Analysis/ValueTracking.cpp
index edbeede910d7f7..b2846274a36e73 100644
--- a/llvm/lib/Analysis/ValueTracking.cpp
+++ b/llvm/lib/Analysis/ValueTracking.cpp
@@ -8499,20 +8499,20 @@ isImpliedCondMatchingOperands(CmpInst::Predicate LPred,
return std::nullopt;
}
-/// Return true if "icmp LPred X, LC" implies "icmp RPred X, RC" is true.
-/// Return false if "icmp LPred X, LC" implies "icmp RPred X, RC" is false.
+/// Return true if "icmp LPred X, LCR" implies "icmp RPred X, RCR" is true.
+/// Return false if "icmp LPred X, LCR" implies "icmp RPred X, RCR" is false.
/// Otherwise, return std::nullopt if we can't infer anything.
-static std::optional<bool> isImpliedCondCommonOperandWithConstants(
- CmpInst::Predicate LPred, const APInt &LC, CmpInst::Predicate RPred,
- const APInt &RC) {
- ConstantRange DomCR = ConstantRange::makeExactICmpRegion(LPred, LC);
- ConstantRange CR = ConstantRange::makeExactICmpRegion(RPred, RC);
- ConstantRange Intersection = DomCR.intersectWith(CR);
- ConstantRange Difference = DomCR.difference(CR);
- if (Intersection.isEmptySet())
- return false;
- if (Difference.isEmptySet())
+static std::optional<bool>
+isImpliedCondCommonOperandWithCR(CmpInst::Predicate LPred, ConstantRange LCR,
+ CmpInst::Predicate RPred, ConstantRange RCR) {
+ ConstantRange DomCR = ConstantRange::makeAllowedICmpRegion(LPred, LCR);
+ // If all true values for lhs and true for rhs, lhs implies rhs
+ if (DomCR.icmp(RPred, RCR))
return true;
+
+ // If there is no overlap, lhs implies not rhs
+ if (DomCR.icmp(CmpInst::getInversePredicate(RPred), RCR))
+ return false;
return std::nullopt;
}
@@ -8532,11 +8532,38 @@ static std::optional<bool> isImpliedCondICmps(const ICmpInst *LHS,
CmpInst::Predicate LPred =
LHSIsTrue ? LHS->getPredicate() : LHS->getInversePredicate();
- // Can we infer anything when the 0-operands match and the 1-operands are
- // constants (not necessarily matching)?
- const APInt *LC, *RC;
- if (L0 == R0 && match(L1, m_APInt(LC)) && match(R1, m_APInt(RC)))
- return isImpliedCondCommonOperandWithConstants(LPred, *LC, RPred, *RC);
+ if (L0 == R1) {
+ std::swap(R0, R1);
+ RPred = ICmpInst::getSwappedPredicate(RPred);
+ }
+ if (L1 == R0) {
+ std::swap(L0, L1);
+ LPred = ICmpInst::getSwappedPredicate(LPred);
+ }
+
+ // See if we can infer anything if operand-0 matches and we have at least one
+ // constant operand-1.
+ if (L0 == R0 && L0->getType()->isIntOrIntVectorTy()) {
+ // Potential TODO: We could also further use the constant range of L0/R0 to
+ // further constraint the constant ranges. At the moment this leads to
+ // several regressions related to not transforming `multi_use(A + C0) eq/ne
+ // C1` (see discussion: D58633).
+ ConstantRange LCR = computeConstantRange(
+ L1, ICmpInst::isSigned(LPred), /* UseInstrInfo=*/true, /*AC=*/nullptr,
+ /*CxtI=*/nullptr, /*DT=*/nullptr, Depth);
+ ConstantRange RCR = computeConstantRange(
+ R1, ICmpInst::isSigned(RPred), /* UseInstrInfo=*/true, /*AC=*/nullptr,
+ /*CxtI=*/nullptr, /*DT=*/nullptr, Depth);
+ // Even if L1/R1 are not both constant, we can still sometimes deduce
+ // relationship from a single constant. For example X u> Y implies X != 0.
+ if (auto R = isImpliedCondCommonOperandWithCR(LPred, LCR, RPred, RCR))
+ return R;
+ // If both L1/R1 where exact constant ranges and we didn't get anything
+ // here, we won't be able to deduce this.
+ const APInt *Unused;
+ if (match(L1, m_APInt(Unused)) && match(R1, m_APInt(Unused)))
+ return std::nullopt;
+ }
// Can we infer anything when the two compares have matching operands?
bool AreSwappedOps;
diff --git a/llvm/test/Transforms/InstCombine/assume.ll b/llvm/test/Transforms/InstCombine/assume.ll
index 927f0a86b0a252..87c75fb2b55592 100644
--- a/llvm/test/Transforms/InstCombine/assume.ll
+++ b/llvm/test/Transforms/InstCombine/assume.ll
@@ -386,7 +386,7 @@ define i1 @nonnull5(ptr %a) {
define i32 @assumption_conflicts_with_known_bits(i32 %a, i32 %b) {
; CHECK-LABEL: @assumption_conflicts_with_known_bits(
; CHECK-NEXT: store i1 true, ptr poison, align 1
-; CHECK-NEXT: ret i32 1
+; CHECK-NEXT: ret i32 poison
;
%and1 = and i32 %b, 3
%B1 = lshr i32 %and1, %and1
diff --git a/llvm/test/Transforms/InstCombine/range-check.ll b/llvm/test/Transforms/InstCombine/range-check.ll
index 0d138b6ba7e79d..210e57c1d1fe4c 100644
--- a/llvm/test/Transforms/InstCombine/range-check.ll
+++ b/llvm/test/Transforms/InstCombine/range-check.ll
@@ -340,11 +340,7 @@ define i1 @negative4_logical(i32 %x, i32 %n) {
define i1 @negative5(i32 %x, i32 %n) {
; CHECK-LABEL: @negative5(
-; CHECK-NEXT: [[NN:%.*]] = and i32 [[N:%.*]], 2147483647
-; CHECK-NEXT: [[A:%.*]] = icmp sgt i32 [[NN]], [[X:%.*]]
-; CHECK-NEXT: [[B:%.*]] = icmp sgt i32 [[X]], -1
-; CHECK-NEXT: [[C:%.*]] = or i1 [[A]], [[B]]
-; CHECK-NEXT: ret i1 [[C]]
+; CHECK-NEXT: ret i1 true
;
%nn = and i32 %n, 2147483647
%a = icmp slt i32 %x, %nn
@@ -355,11 +351,7 @@ define i1 @negative5(i32 %x, i32 %n) {
define i1 @negative5_logical(i32 %x, i32 %n) {
; CHECK-LABEL: @negative5_logical(
-; CHECK-NEXT: [[NN:%.*]] = and i32 [[N:%.*]], 2147483647
-; CHECK-NEXT: [[A:%.*]] = icmp sgt i32 [[NN]], [[X:%.*]]
-; CHECK-NEXT: [[B:%.*]] = icmp sgt i32 [[X]], -1
-; CHECK-NEXT: [[C:%.*]] = or i1 [[A]], [[B]]
-; CHECK-NEXT: ret i1 [[C]]
+; CHECK-NEXT: ret i1 true
;
%nn = and i32 %n, 2147483647
%a = icmp slt i32 %x, %nn
diff --git a/llvm/test/Transforms/InstCombine/select.ll b/llvm/test/Transforms/InstCombine/select.ll
index a84904106eced4..d9734242a86891 100644
--- a/llvm/test/Transforms/InstCombine/select.ll
+++ b/llvm/test/Transforms/InstCombine/select.ll
@@ -2925,10 +2925,8 @@ define i8 @select_replacement_loop3(i32 noundef %x) {
define i16 @select_replacement_loop4(i16 noundef %p_12) {
; CHECK-LABEL: @select_replacement_loop4(
-; CHECK-NEXT: [[CMP1:%.*]] = icmp ult i16 [[P_12:%.*]], 2
-; CHECK-NEXT: [[AND1:%.*]] = and i16 [[P_12]], 1
-; CHECK-NEXT: [[AND2:%.*]] = select i1 [[CMP1]], i16 [[AND1]], i16 0
-; CHECK-NEXT: [[CMP2:%.*]] = icmp eq i16 [[AND2]], [[P_12]]
+; CHECK-NEXT: [[AND1:%.*]] = and i16 [[P_12:%.*]], 1
+; CHECK-NEXT: [[CMP2:%.*]] = icmp ult i16 [[P_12]], 2
; CHECK-NEXT: [[AND3:%.*]] = select i1 [[CMP2]], i16 [[AND1]], i16 0
; CHECK-NEXT: ret i16 [[AND3]]
;
diff --git a/llvm/test/Transforms/InstCombine/shift.ll b/llvm/test/Transforms/InstCombine/shift.ll
index 62f32c28683711..bef7fc81a7d1f9 100644
--- a/llvm/test/Transforms/InstCombine/shift.ll
+++ b/llvm/test/Transforms/InstCombine/shift.ll
@@ -1751,12 +1751,11 @@ define void @ashr_out_of_range_1(ptr %A) {
; CHECK-NEXT: [[L:%.*]] = load i177, ptr [[A:%.*]], align 4
; CHECK-NEXT: [[L_FROZEN:%.*]] = freeze i177 [[L]]
; CHECK-NEXT: [[TMP1:%.*]] = icmp eq i177 [[L_FROZEN]], -1
-; CHECK-NEXT: [[B:%.*]] = select i1 [[TMP1]], i177 0, i177 [[L_FROZEN]]
-; CHECK-NEXT: [[TMP2:%.*]] = trunc i177 [[B]] to i64
+; CHECK-NEXT: [[TMP6:%.*]] = trunc i177 [[L_FROZEN]] to i64
+; CHECK-NEXT: [[TMP2:%.*]] = select i1 [[TMP1]], i64 0, i64 [[TMP6]]
; CHECK-NEXT: [[TMP3:%.*]] = getelementptr i177, ptr [[A]], i64 [[TMP2]]
; CHECK-NEXT: [[G11:%.*]] = getelementptr i8, ptr [[TMP3]], i64 -24
-; CHECK-NEXT: [[C17:%.*]] = icmp sgt i177 [[B]], [[L_FROZEN]]
-; CHECK-NEXT: [[TMP4:%.*]] = sext i1 [[C17]] to i64
+; CHECK-NEXT: [[TMP4:%.*]] = sext i1 [[TMP1]] to i64
; CHECK-NEXT: [[G62:%.*]] = getelementptr i177, ptr [[G11]], i64 [[TMP4]]
; CHECK-NEXT: [[TMP5:%.*]] = icmp eq i177 [[L_FROZEN]], -1
; CHECK-NEXT: [[B28:%.*]] = select i1 [[TMP5]], i177 0, i177 [[L_FROZEN]]
diff --git a/llvm/test/Transforms/LoopVectorize/X86/pr23997.ll b/llvm/test/Transforms/LoopVectorize/X86/pr23997.ll
index 0b16d80a4adbc5..5aeac1101fe223 100644
--- a/llvm/test/Transforms/LoopVectorize/X86/pr23997.ll
+++ b/llvm/test/Transforms/LoopVectorize/X86/pr23997.ll
@@ -12,8 +12,7 @@ define void @foo(ptr addrspace(1) align 8 dereferenceable_or_null(16), ptr addrs
; CHECK: preheader:
; CHECK-NEXT: [[DOT10:%.*]] = getelementptr inbounds i8, ptr addrspace(1) [[TMP0:%.*]], i64 16
; CHECK-NEXT: [[DOT12:%.*]] = getelementptr inbounds i8, ptr addrspace(1) [[TMP1:%.*]], i64 16
-; CHECK-NEXT: [[UMAX2:%.*]] = call i64 @llvm.umax.i64(i64 [[TMP2:%.*]], i64 1)
-; CHECK-NEXT: [[MIN_ITERS_CHECK:%.*]] = icmp ult i64 [[TMP2]], 16
+; CHECK-NEXT: [[MIN_ITERS_CHECK:%.*]] = icmp ult i64 [[TMP2:%.*]], 16
; CHECK-NEXT: br i1 [[MIN_ITERS_CHECK]], label [[SCALAR_PH:%.*]], label [[VECTOR_MEMCHECK:%.*]]
; CHECK: vector.memcheck:
; CHECK-NEXT: [[TMP3:%.*]] = shl i64 [[TMP2]], 3
@@ -25,7 +24,7 @@ define void @foo(ptr addrspace(1) align 8 dereferenceable_or_null(16), ptr addrs
; CHECK-NEXT: [[FOUND_CONFLICT:%.*]] = and i1 [[BOUND0]], [[BOUND1]]
; CHECK-NEXT: br i1 [[FOUND_CONFLICT]], label [[SCALAR_PH]], label [[VECTOR_PH:%.*]]
; CHECK: vector.ph:
-; CHECK-NEXT: [[N_VEC:%.*]] = and i64 [[UMAX2]], -16
+; CHECK-NEXT: [[N_VEC:%.*]] = and i64 [[TMP2]], -16
; CHECK-NEXT: br label [[VECTOR_BODY:%.*]]
; CHECK: vector.body:
; CHECK-NEXT: [[INDEX:%.*]] = phi i64 [ 0, [[VECTOR_PH]] ], [ [[INDEX_NEXT:%.*]], [[VECTOR_BODY]] ]
@@ -49,7 +48,7 @@ define void @foo(ptr addrspace(1) align 8 dereferenceable_or_null(16), ptr addrs
; CHECK-NEXT: [[TMP13:%.*]] = icmp eq i64 [[INDEX_NEXT]], [[N_VEC]]
; CHECK-NEXT: br i1 [[TMP13]], label [[MIDDLE_BLOCK:%.*]], label [[VECTOR_BODY]], !llvm.loop [[LOOP5:![0-9]+]]
; CHECK: middle.block:
-; CHECK-NEXT: [[CMP_N:%.*]] = icmp eq i64 [[UMAX2]], [[N_VEC]]
+; CHECK-NEXT: [[CMP_N:%.*]] = icmp eq i64 [[N_VEC]], [[TMP2]]
; CHECK-NEXT: br i1 [[CMP_N]], label [[LOOPEXIT:%.*]], label [[SCALAR_PH]]
; CHECK: scalar.ph:
; CHECK-NEXT: [[BC_RESUME_VAL:%.*]] = phi i64 [ [[N_VEC]], [[MIDDLE_BLOCK]] ], [ 0, [[PREHEADER]] ], [ 0, [[VECTOR_MEMCHECK]] ]
diff --git a/llvm/test/Transforms/NewGVN/pr35125.ll b/llvm/test/Transforms/NewGVN/pr35125.ll
index 9a96594e3446db..6724538a5a7f29 100644
--- a/llvm/test/Transforms/NewGVN/pr35125.ll
+++ b/llvm/test/Transforms/NewGVN/pr35125.ll
@@ -18,15 +18,12 @@ define i32 @main() #0 {
; CHECK-NEXT: [[CMP2:%.*]] = icmp ult i32 [[STOREMERGE]], [[PHIOFOPS]]
; CHECK-NEXT: br i1 [[CMP2]], label [[IF_THEN3:%.*]], label [[IF_END6:%.*]]
; CHECK: if.then3:
-; CHECK-NEXT: [[TOBOOL:%.*]] = icmp eq i32 [[STOREMERGE]], -1
-; CHECK-NEXT: br i1 [[TOBOOL]], label [[LOR_RHS:%.*]], label [[LOR_END:%.*]]
+; CHECK-NEXT: br i1 false, label [[LOR_RHS:%.*]], label [[LOR_END:%.*]]
; CHECK: lor.rhs:
-; CHECK-NEXT: [[TOBOOL5:%.*]] = icmp ne i32 [[TMP0]], 0
-; CHECK-NEXT: [[PHITMP:%.*]] = zext i1 [[TOBOOL5]] to i32
+; CHECK-NEXT: store i8 poison, ptr null, align 1
; CHECK-NEXT: br label [[LOR_END]]
; CHECK: lor.end:
-; CHECK-NEXT: [[TMP1:%.*]] = phi i32 [ 1, [[IF_THEN3]] ], [ [[PHITMP]], [[LOR_RHS]] ]
-; CHECK-NEXT: store i32 [[TMP1]], ptr @a, align 4
+; CHECK-NEXT: store i32 1, ptr @a, align 4
; CHECK-NEXT: br label [[IF_END6]]
; CHECK: if.end6:
; CHECK-NEXT: [[TMP2:%.*]] = load i32, ptr @a, align 4
|
Minimal (but existing) compile time impact: https://llvm-compile-time-tracker.com/compare.php?from=e77378cc14ec712942452aca155addacbe904c8f&to=4fe7d1d86ee416afa476594b4e5d38f342f76498&stat=instructions%3Au Alternative if we req at least one of L1/R1 to be constant has lower compile time regression but misses a few of the folds: |
@dtcxzyw Can you please test this? |
I am not sure whether it is suitable to use See also nikic's comment: #69840 (comment) |
Yeah, I can't say I'm particularly fond of the direction. From the test diffs, a fold we're missing is this: https://alive2.llvm.org/ce/z/-njJr8 Particularly profitable if the new comparison folds later, but also seems generally beneficial. |
So originally my goal was just to handle cases like My first attempt was a bespoke set of switching statements, but pretty quickly saw that just changing to CR would be an easier and less bugprone way to impl that. At that point I wasn't using Then figured, if there is no big compile time impact just using My point is I think basically each step seems like a reasonable improvement on the alternative. If the compile time impact is a proper concern, think it may make sense to constrain |
Would think its more principled to more generally handle the implication between conditions rather than add a transform for each possible case. |
This is still an implied condition based transform. In fact, now that I look for it, it seems like foldSelectICmp() should be doing exactly that. I think maybe it doesn't trigger because the condition becomes (This is not intended as a full replacement for what you want here, just something I noticed in the tests.) |
Ah, I think the reason I saw it in the diffs is that this patch adds the non-canonical order handling -- the improvement is not actually related to the constant range support at all. Could you please split this out into a separate patch? |
Didn't realize |
Separate patch please. |
Done, see: #85575 |
69ab890
to
cc7df74
Compare
Rebased |
This patch seems to block SROA: dtcxzyw/llvm-opt-benchmark#419 (comment). |
Seems to boil down to simplifications happening earlier. A reduced form:
Where we go awry is when fold:
->
Which eventually results in the following diff after inlining:
Then finally:
vs
Essentially we throw away the information that the low 3 bits of the pointer are zero Looking into a fix... Edit: Similiar to last time, there is no point where it seems we make a "bad decision", |
The only really thing I can think of is to preserve the information w/ assumes Don't think thats really a great path to go down although some |
@nikic, is the idea of this patch okay? Or are you strongly opposed to using |
We met the same issue in dtcxzyw/llvm-opt-benchmark#49 (comment). |
Yeah I think its a fairly common issue. And it seems you guys |
cc7df74
to
2f155d6
Compare
Rebased, limited CR analysis to MaxRecursiveDepth - 1. My feeling is this is mostly to capture relationships like |
Using MaxRecursiveDepth - 1 is not particularly useful in this context, because computeConstantRange() is already essentially non-recursive. This change would be ok if it were free, but it isn't (https://llvm-compile-time-tracker.com/compare.php?from=7d60232b38b66138dae1b31027d73ee5b9df5c58&to=2f155d6f9baacec48a9f69abffbfbca91ef57b46&stat=instructions:u). I don't think that it justifies the cost. |
Okay, ill work to make it free. |
2f155d6
to
98198d7
Compare
@nikic, limited to requiring one constant (either |
ping |
ping2 |
ping |
This problem is still outstanding. Any thoughts about preserving information from the |
I think this is a more general problem that we don't have any good solution for. Think the diff is net positive so would prefer to not block this patch w/ the potentially intractable problem of folds throwing away information |
ping |
1 similar comment
ping |
ping @nikic, I think the compile time concerns have been addressed and this has value. Can we get this in? |
Compile time measurement:
|
98198d7
to
c74b101
Compare
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.
LGTM. Thank you!
c74b101
to
e026598
Compare
CmpInst::Predicate RPred, const ConstantRange &RCR) { | ||
ConstantRange DomCR = ConstantRange::makeAllowedICmpRegion(LPred, LCR); | ||
// If all true values for lhs and true for rhs, lhs implies rhs | ||
if (DomCR.icmp(RPred, RCR)) |
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.
@nikic, did you comment a concern here then delete it, or is my github not updating properly? I see the email notification but nothing here.
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.
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.
Thanks. I believe this is correct aswell b.c icmp
uses makeSatisfyingICmpRegion
. @nikic assuming you deleted your comment.
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.
Yeah, I deleted my comment because I realized I was thinking about it the wrong way around right after I posted it. Sorry for the confusion.
Assuming no objects, im going to push this in the next few days (I'll re-verify the compile-time impact before I do). |
See dtcxzyw/llvm-opt-benchmark#680 (comment). Hopefully it helps you :) |
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.
LGTM
CmpInst::Predicate RPred, const ConstantRange &RCR) { | ||
ConstantRange DomCR = ConstantRange::makeAllowedICmpRegion(LPred, LCR); | ||
// If all true values for lhs and true for rhs, lhs implies rhs | ||
if (DomCR.icmp(RPred, RCR)) |
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.
Yeah, I deleted my comment because I realized I was thinking about it the wrong way around right after I posted it. Sorry for the confusion.
…constants. Previously we only handled the `L0 == R0` case if both `L1` and `R1` where constant. We can get more out of the analysis using general constant ranges instead. For example, `X u> Y` implies `X != 0`. In general, any strict comparison on `X` implies that `X` is not equal to the boundary value for the sign and constant ranges with/without sign bits can be useful in deducing implications.
e026598
to
435e044
Compare
…constants. Previously we only handled the `L0 == R0` case if both `L1` and `R1` where constant. We can get more out of the analysis using general constant ranges instead. For example, `X u> Y` implies `X != 0`. In general, any strict comparison on `X` implies that `X` is not equal to the boundary value for the sign and constant ranges with/without sign bits can be useful in deducing implications. Closes llvm#85557
…constants. Previously we only handled the `L0 == R0` case if both `L1` and `R1` where constant. We can get more out of the analysis using general constant ranges instead. For example, `X u> Y` implies `X != 0`. In general, any strict comparison on `X` implies that `X` is not equal to the boundary value for the sign and constant ranges with/without sign bits can be useful in deducing implications. Closes llvm#85557
Previously we only handled the
L0 == R0
case if bothL1
andR1
where constant.
We can get more out of the analysis using general constant ranges
instead.
For example,
X u> Y
impliesX != 0
.In general, any strict comparison on
X
implies thatX
is not equalto the boundary value for the sign and constant ranges with/without
sign bits can be useful in deducing implications.