-
Notifications
You must be signed in to change notification settings - Fork 14k
[ValueTracking] Fix poison propagation in matchFastFloatClamp
#144215
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
base: main
Are you sure you want to change the base?
Conversation
@llvm/pr-subscribers-llvm-analysis @llvm/pr-subscribers-llvm-transforms Author: Yingwei Zheng (dtcxzyw) Changeshttps://reviews.llvm.org/D33186 converts BTW, I think it is effectively dead as it is unlikely to set FMF on the second fcmp+select pair, while the first one is guaranteed not to generate poison. In addition, Full diff: https://github.com/llvm/llvm-project/pull/144215.diff 2 Files Affected:
diff --git a/llvm/lib/Analysis/ValueTracking.cpp b/llvm/lib/Analysis/ValueTracking.cpp
index d8c1096049dce..ca8564556d6a4 100644
--- a/llvm/lib/Analysis/ValueTracking.cpp
+++ b/llvm/lib/Analysis/ValueTracking.cpp
@@ -8181,7 +8181,8 @@ static SelectPatternResult matchFastFloatClamp(CmpInst::Predicate Pred,
RHS = FalseVal;
const APFloat *FC1;
- if (CmpRHS != TrueVal || !match(CmpRHS, m_APFloat(FC1)) || !FC1->isFinite())
+ if (CmpRHS != TrueVal || !match(CmpRHS, m_APFloat(FC1)) || !FC1->isFinite() ||
+ !isGuaranteedNotToBePoison(FalseVal))
return {SPF_UNKNOWN, SPNB_NA, false};
const APFloat *FC2;
diff --git a/llvm/test/Transforms/InstCombine/clamp-to-minmax.ll b/llvm/test/Transforms/InstCombine/clamp-to-minmax.ll
index 7f3276608c5da..ccceb315785ef 100644
--- a/llvm/test/Transforms/InstCombine/clamp-to-minmax.ll
+++ b/llvm/test/Transforms/InstCombine/clamp-to-minmax.ll
@@ -3,15 +3,15 @@
; RUN: opt < %s -passes=instcombine -use-constant-fp-for-fixed-length-splat -use-constant-int-for-fixed-length-splat -S | FileCheck %s
; (X < C1) ? C1 : MIN(X, C2)
-define float @clamp_float_fast_ordered_strict_maxmin(float %x) {
+define float @clamp_float_fast_ordered_strict_maxmin(float noundef %x) {
; CHECK-LABEL: @clamp_float_fast_ordered_strict_maxmin(
-; CHECK-NEXT: [[CMP2:%.*]] = fcmp fast olt float [[X:%.*]], 2.550000e+02
+; CHECK-NEXT: [[CMP2:%.*]] = fcmp olt float [[X:%.*]], 2.550000e+02
; CHECK-NEXT: [[MIN:%.*]] = select i1 [[CMP2]], float [[X]], float 2.550000e+02
; CHECK-NEXT: [[DOTINV:%.*]] = fcmp fast oge float [[MIN]], 1.000000e+00
; CHECK-NEXT: [[R1:%.*]] = select nnan ninf i1 [[DOTINV]], float [[MIN]], float 1.000000e+00
; CHECK-NEXT: ret float [[R1]]
;
- %cmp2 = fcmp fast olt float %x, 255.0
+ %cmp2 = fcmp olt float %x, 255.0
%min = select i1 %cmp2, float %x, float 255.0
%cmp1 = fcmp fast olt float %x, 1.0
%r = select i1 %cmp1, float 1.0, float %min
@@ -19,15 +19,15 @@ define float @clamp_float_fast_ordered_strict_maxmin(float %x) {
}
; (X <= C1) ? C1 : MIN(X, C2)
-define float @clamp_float_fast_ordered_nonstrict_maxmin(float %x) {
+define float @clamp_float_fast_ordered_nonstrict_maxmin(float noundef %x) {
; CHECK-LABEL: @clamp_float_fast_ordered_nonstrict_maxmin(
-; CHECK-NEXT: [[CMP2:%.*]] = fcmp fast olt float [[X:%.*]], 2.550000e+02
+; CHECK-NEXT: [[CMP2:%.*]] = fcmp olt float [[X:%.*]], 2.550000e+02
; CHECK-NEXT: [[MIN:%.*]] = select i1 [[CMP2]], float [[X]], float 2.550000e+02
; CHECK-NEXT: [[DOTINV:%.*]] = fcmp fast oge float [[MIN]], 1.000000e+00
; CHECK-NEXT: [[R1:%.*]] = select nnan ninf i1 [[DOTINV]], float [[MIN]], float 1.000000e+00
; CHECK-NEXT: ret float [[R1]]
;
- %cmp2 = fcmp fast olt float %x, 255.0
+ %cmp2 = fcmp olt float %x, 255.0
%min = select i1 %cmp2, float %x, float 255.0
%cmp1 = fcmp fast ole float %x, 1.0
%r = select i1 %cmp1, float 1.0, float %min
@@ -35,15 +35,15 @@ define float @clamp_float_fast_ordered_nonstrict_maxmin(float %x) {
}
; (X > C1) ? C1 : MAX(X, C2)
-define float @clamp_float_fast_ordered_strict_minmax(float %x) {
+define float @clamp_float_fast_ordered_strict_minmax(float noundef %x) {
; CHECK-LABEL: @clamp_float_fast_ordered_strict_minmax(
-; CHECK-NEXT: [[CMP2:%.*]] = fcmp fast ogt float [[X:%.*]], 1.000000e+00
+; CHECK-NEXT: [[CMP2:%.*]] = fcmp ogt float [[X:%.*]], 1.000000e+00
; CHECK-NEXT: [[MAX:%.*]] = select i1 [[CMP2]], float [[X]], float 1.000000e+00
; CHECK-NEXT: [[DOTINV:%.*]] = fcmp fast ole float [[MAX]], 2.550000e+02
; CHECK-NEXT: [[R1:%.*]] = select nnan ninf i1 [[DOTINV]], float [[MAX]], float 2.550000e+02
; CHECK-NEXT: ret float [[R1]]
;
- %cmp2 = fcmp fast ogt float %x, 1.0
+ %cmp2 = fcmp ogt float %x, 1.0
%max = select i1 %cmp2, float %x, float 1.0
%cmp1 = fcmp fast ogt float %x, 255.0
%r = select i1 %cmp1, float 255.0, float %max
@@ -51,15 +51,15 @@ define float @clamp_float_fast_ordered_strict_minmax(float %x) {
}
; (X >= C1) ? C1 : MAX(X, C2)
-define float @clamp_float_fast_ordered_nonstrict_minmax(float %x) {
+define float @clamp_float_fast_ordered_nonstrict_minmax(float noundef %x) {
; CHECK-LABEL: @clamp_float_fast_ordered_nonstrict_minmax(
-; CHECK-NEXT: [[CMP2:%.*]] = fcmp fast ogt float [[X:%.*]], 1.000000e+00
+; CHECK-NEXT: [[CMP2:%.*]] = fcmp ogt float [[X:%.*]], 1.000000e+00
; CHECK-NEXT: [[MAX:%.*]] = select i1 [[CMP2]], float [[X]], float 1.000000e+00
; CHECK-NEXT: [[DOTINV:%.*]] = fcmp fast ole float [[MAX]], 2.550000e+02
; CHECK-NEXT: [[R1:%.*]] = select nnan ninf i1 [[DOTINV]], float [[MAX]], float 2.550000e+02
; CHECK-NEXT: ret float [[R1]]
;
- %cmp2 = fcmp fast ogt float %x, 1.0
+ %cmp2 = fcmp ogt float %x, 1.0
%max = select i1 %cmp2, float %x, float 1.0
%cmp1 = fcmp fast oge float %x, 255.0
%r = select i1 %cmp1, float 255.0, float %max
@@ -70,15 +70,15 @@ define float @clamp_float_fast_ordered_nonstrict_minmax(float %x) {
; The same for unordered
; (X < C1) ? C1 : MIN(X, C2)
-define float @clamp_float_fast_unordered_strict_maxmin(float %x) {
+define float @clamp_float_fast_unordered_strict_maxmin(float noundef %x) {
; CHECK-LABEL: @clamp_float_fast_unordered_strict_maxmin(
-; CHECK-NEXT: [[CMP2_INV:%.*]] = fcmp fast oge float [[X:%.*]], 2.550000e+02
-; CHECK-NEXT: [[MIN:%.*]] = select nnan ninf i1 [[CMP2_INV]], float 2.550000e+02, float [[X]]
+; CHECK-NEXT: [[CMP2_INV:%.*]] = fcmp oge float [[X:%.*]], 2.550000e+02
+; CHECK-NEXT: [[MIN:%.*]] = select i1 [[CMP2_INV]], float 2.550000e+02, float [[X]]
; CHECK-NEXT: [[DOTINV:%.*]] = fcmp fast oge float [[MIN]], 1.000000e+00
; CHECK-NEXT: [[R:%.*]] = select nnan ninf i1 [[DOTINV]], float [[MIN]], float 1.000000e+00
; CHECK-NEXT: ret float [[R]]
;
- %cmp2 = fcmp fast ult float %x, 255.0
+ %cmp2 = fcmp ult float %x, 255.0
%min = select i1 %cmp2, float %x, float 255.0
%cmp1 = fcmp fast ult float %x, 1.0
%r = select i1 %cmp1, float 1.0, float %min
@@ -86,15 +86,15 @@ define float @clamp_float_fast_unordered_strict_maxmin(float %x) {
}
; (X <= C1) ? C1 : MIN(X, C2)
-define float @clamp_float_fast_unordered_nonstrict_maxmin(float %x) {
+define float @clamp_float_fast_unordered_nonstrict_maxmin(float noundef %x) {
; CHECK-LABEL: @clamp_float_fast_unordered_nonstrict_maxmin(
-; CHECK-NEXT: [[CMP2_INV:%.*]] = fcmp fast oge float [[X:%.*]], 2.550000e+02
-; CHECK-NEXT: [[MIN:%.*]] = select nnan ninf i1 [[CMP2_INV]], float 2.550000e+02, float [[X]]
+; CHECK-NEXT: [[CMP2_INV:%.*]] = fcmp oge float [[X:%.*]], 2.550000e+02
+; CHECK-NEXT: [[MIN:%.*]] = select i1 [[CMP2_INV]], float 2.550000e+02, float [[X]]
; CHECK-NEXT: [[DOTINV:%.*]] = fcmp fast oge float [[MIN]], 1.000000e+00
; CHECK-NEXT: [[R:%.*]] = select nnan ninf i1 [[DOTINV]], float [[MIN]], float 1.000000e+00
; CHECK-NEXT: ret float [[R]]
;
- %cmp2 = fcmp fast ult float %x, 255.0
+ %cmp2 = fcmp ult float %x, 255.0
%min = select i1 %cmp2, float %x, float 255.0
%cmp1 = fcmp fast ule float %x, 1.0
%r = select i1 %cmp1, float 1.0, float %min
@@ -102,15 +102,15 @@ define float @clamp_float_fast_unordered_nonstrict_maxmin(float %x) {
}
; (X > C1) ? C1 : MAX(X, C2)
-define float @clamp_float_fast_unordered_strict_minmax(float %x) {
+define float @clamp_float_fast_unordered_strict_minmax(float noundef %x) {
; CHECK-LABEL: @clamp_float_fast_unordered_strict_minmax(
-; CHECK-NEXT: [[CMP2_INV:%.*]] = fcmp fast ole float [[X:%.*]], 1.000000e+00
-; CHECK-NEXT: [[MAX:%.*]] = select nnan ninf i1 [[CMP2_INV]], float 1.000000e+00, float [[X]]
+; CHECK-NEXT: [[CMP2_INV:%.*]] = fcmp ole float [[X:%.*]], 1.000000e+00
+; CHECK-NEXT: [[MAX:%.*]] = select i1 [[CMP2_INV]], float 1.000000e+00, float [[X]]
; CHECK-NEXT: [[DOTINV:%.*]] = fcmp fast ole float [[MAX]], 2.550000e+02
; CHECK-NEXT: [[R:%.*]] = select nnan ninf i1 [[DOTINV]], float [[MAX]], float 2.550000e+02
; CHECK-NEXT: ret float [[R]]
;
- %cmp2 = fcmp fast ugt float %x, 1.0
+ %cmp2 = fcmp ugt float %x, 1.0
%max = select i1 %cmp2, float %x, float 1.0
%cmp1 = fcmp fast ugt float %x, 255.0
%r = select i1 %cmp1, float 255.0, float %max
@@ -118,15 +118,15 @@ define float @clamp_float_fast_unordered_strict_minmax(float %x) {
}
; (X >= C1) ? C1 : MAX(X, C2)
-define float @clamp_float_fast_unordered_nonstrict_minmax(float %x) {
+define float @clamp_float_fast_unordered_nonstrict_minmax(float noundef %x) {
; CHECK-LABEL: @clamp_float_fast_unordered_nonstrict_minmax(
-; CHECK-NEXT: [[CMP2_INV:%.*]] = fcmp fast ole float [[X:%.*]], 1.000000e+00
-; CHECK-NEXT: [[MAX:%.*]] = select nnan ninf i1 [[CMP2_INV]], float 1.000000e+00, float [[X]]
+; CHECK-NEXT: [[CMP2_INV:%.*]] = fcmp ole float [[X:%.*]], 1.000000e+00
+; CHECK-NEXT: [[MAX:%.*]] = select i1 [[CMP2_INV]], float 1.000000e+00, float [[X]]
; CHECK-NEXT: [[DOTINV:%.*]] = fcmp fast ole float [[MAX]], 2.550000e+02
; CHECK-NEXT: [[R:%.*]] = select nnan ninf i1 [[DOTINV]], float [[MAX]], float 2.550000e+02
; CHECK-NEXT: ret float [[R]]
;
- %cmp2 = fcmp fast ugt float %x, 1.0
+ %cmp2 = fcmp ugt float %x, 1.0
%max = select i1 %cmp2, float %x, float 1.0
%cmp1 = fcmp fast uge float %x, 255.0
%r = select i1 %cmp1, float 255.0, float %max
@@ -136,15 +136,15 @@ define float @clamp_float_fast_unordered_nonstrict_minmax(float %x) {
; Some more checks with fast
; (X > 1.0) ? min(x, 255.0) : 1.0
-define float @clamp_test_1(float %x) {
+define float @clamp_test_1(float noundef %x) {
; CHECK-LABEL: @clamp_test_1(
-; CHECK-NEXT: [[INNER_CMP_INV:%.*]] = fcmp fast oge float [[X:%.*]], 2.550000e+02
-; CHECK-NEXT: [[INNER_SEL:%.*]] = select nnan ninf i1 [[INNER_CMP_INV]], float 2.550000e+02, float [[X]]
-; CHECK-NEXT: [[OUTER_CMP:%.*]] = fcmp fast oge float [[INNER_SEL]], 1.000000e+00
-; CHECK-NEXT: [[R:%.*]] = select nnan ninf i1 [[OUTER_CMP]], float [[INNER_SEL]], float 1.000000e+00
+; CHECK-NEXT: [[INNER_CMP_INV:%.*]] = fcmp oge float [[X:%.*]], 2.550000e+02
+; CHECK-NEXT: [[INNER_SEL:%.*]] = select i1 [[INNER_CMP_INV]], float 2.550000e+02, float [[X]]
+; CHECK-NEXT: [[DOTINV:%.*]] = fcmp fast oge float [[INNER_SEL]], 1.000000e+00
+; CHECK-NEXT: [[R:%.*]] = select nnan ninf i1 [[DOTINV]], float [[INNER_SEL]], float 1.000000e+00
; CHECK-NEXT: ret float [[R]]
;
- %inner_cmp = fcmp fast ult float %x, 255.0
+ %inner_cmp = fcmp ult float %x, 255.0
%inner_sel = select i1 %inner_cmp, float %x, float 255.0
%outer_cmp = fcmp fast ugt float %x, 1.0
%r = select i1 %outer_cmp, float %inner_sel, float 1.0
@@ -185,6 +185,22 @@ define float @clamp_negative_same_op(float %x) {
ret float %r
}
+define float @clamp_negative_propagate_poison(float %x) {
+; CHECK-LABEL: @clamp_negative_propagate_poison(
+; CHECK-NEXT: [[CMP1:%.*]] = fcmp ninf ole float [[X:%.*]], 1.000000e+00
+; CHECK-NEXT: [[MAX:%.*]] = select i1 [[CMP1]], float 1.000000e+00, float [[X]]
+; CHECK-NEXT: [[CMP2:%.*]] = fcmp nnan ole float [[X]], 2.550000e+02
+; CHECK-NEXT: [[R1:%.*]] = select i1 [[CMP2]], float [[MAX]], float 2.550000e+02
+; CHECK-NEXT: ret float [[R1]]
+;
+ %cmp1 = fcmp ninf ole float %x, 1.000000e+00
+ %max = select i1 %cmp1, float 1.000000e+00, float %x
+ %cmp2 = fcmp nnan ole float %x, 2.550000e+02
+ %r = select i1 %cmp2, float %max, float 2.550000e+02
+ ret float %r
+}
+
+
; And now without fast.
|
I think I'd favor completely removing the fold in that case -- or moving it to InstCombine so we can drop flags as needed. Keeping the code to handle an unlikely mixed FMF case doesn't seem worthwhile... |
https://reviews.llvm.org/D33186 converts
X < C1 ? C1 : Min(X, C2) --> Max(C1, Min(X, C2))
. However, it is problematic sinceMin(X, C2)
may introduce poison (due to FMF on fcmp or select).Closes #143120.
BTW, I think it is effectively dead as it is unlikely to set FMF on the second fcmp+select pair, while the first one is guaranteed not to generate poison. In addition,
*FC1 < *FC2
never holds on real-world code: https://dtcxzyw.github.io/llvm-opt-benchmark/coverage/data/zyw/opt-ci/actions-runner/_work/llvm-opt-benchmark/llvm-opt-benchmark/llvm/llvm-project/llvm/lib/Analysis/ValueTracking.cpp.html#L8187