return false;
}
+/// Match clamp pattern for float types without care about NaNs or signed zeros.
+/// Given non-min/max outer cmp/select from the clamp pattern this
+/// function recognizes if it can be substitued by a "canonical" min/max
+/// pattern.
+static SelectPatternResult matchFastFloatClamp(CmpInst::Predicate Pred,
+ Value *CmpLHS, Value *CmpRHS,
+ Value *TrueVal, Value *FalseVal,
+ Value *&LHS, Value *&RHS) {
+ // Try to match
+ // X < C1 ? C1 : Min(X, C2) --> Max(C1, Min(X, C2))
+ // X > C1 ? C1 : Max(X, C2) --> Min(C1, Max(X, C2))
+ // and return description of the outer Max/Min.
+
+ // First, check if select has inverse order:
+ if (CmpRHS == FalseVal) {
+ std::swap(TrueVal, FalseVal);
+ Pred = CmpInst::getInversePredicate(Pred);
+ }
+
+ // Assume success now. If there's no match, callers should not use these anyway.
+ LHS = TrueVal;
+ RHS = FalseVal;
+
+ const APFloat *FC1;
+ if (CmpRHS != TrueVal || !match(CmpRHS, m_APFloat(FC1)) || !FC1->isFinite())
+ return {SPF_UNKNOWN, SPNB_NA, false};
+
+ const APFloat *FC2;
+ switch (Pred) {
+ case CmpInst::FCMP_OLT:
+ case CmpInst::FCMP_OLE:
+ case CmpInst::FCMP_ULT:
+ case CmpInst::FCMP_ULE:
+ if (match(FalseVal,
+ m_CombineOr(m_OrdFMin(m_Specific(CmpLHS), m_APFloat(FC2)),
+ m_UnordFMin(m_Specific(CmpLHS), m_APFloat(FC2)))) &&
+ FC1->compare(*FC2) == APFloat::cmpResult::cmpLessThan)
+ return {SPF_FMAXNUM, SPNB_RETURNS_ANY, false};
+ break;
+ case CmpInst::FCMP_OGT:
+ case CmpInst::FCMP_OGE:
+ case CmpInst::FCMP_UGT:
+ case CmpInst::FCMP_UGE:
+ if (match(FalseVal,
+ m_CombineOr(m_OrdFMax(m_Specific(CmpLHS), m_APFloat(FC2)),
+ m_UnordFMax(m_Specific(CmpLHS), m_APFloat(FC2)))) &&
+ FC1->compare(*FC2) == APFloat::cmpResult::cmpGreaterThan)
+ return {SPF_FMINNUM, SPNB_RETURNS_ANY, false};
+ break;
+ default:
+ break;
+ }
+
+ return {SPF_UNKNOWN, SPNB_NA, false};
+}
+
/// Match non-obvious integer minimum and maximum sequences.
static SelectPatternResult matchMinMax(CmpInst::Predicate Pred,
Value *CmpLHS, Value *CmpRHS,
}
}
- return matchMinMax(Pred, CmpLHS, CmpRHS, TrueVal, FalseVal, LHS, RHS);
+ if (CmpInst::isIntPredicate(Pred))
+ return matchMinMax(Pred, CmpLHS, CmpRHS, TrueVal, FalseVal, LHS, RHS);
+
+ // According to (IEEE 754-2008 5.3.1), minNum(0.0, -0.0) and similar
+ // may return either -0.0 or 0.0, so fcmp/select pair has stricter
+ // semantics than minNum. Be conservative in such case.
+ if (NaNBehavior != SPNB_RETURNS_ANY ||
+ (!FMF.noSignedZeros() && !isKnownNonZero(CmpLHS) &&
+ !isKnownNonZero(CmpRHS)))
+ return {SPF_UNKNOWN, SPNB_NA, false};
+
+ return matchFastFloatClamp(Pred, CmpLHS, CmpRHS, TrueVal, FalseVal, LHS, RHS);
}
static Value *lookThroughCast(CmpInst *CmpI, Value *V1, Value *V2,
; CHECK-LABEL: @clamp_float_fast_ordered_strict_maxmin(
; CHECK-NEXT: [[CMP2:%.*]] = fcmp fast olt float [[X:%.*]], 2.550000e+02
; CHECK-NEXT: [[MIN:%.*]] = select i1 [[CMP2]], float [[X]], float 2.550000e+02
-; CHECK-NEXT: [[CMP1:%.*]] = fcmp fast olt float [[X]], 1.000000e+00
-; CHECK-NEXT: [[R:%.*]] = select i1 [[CMP1]], float 1.000000e+00, float [[MIN]]
-; CHECK-NEXT: ret float [[R]]
+; CHECK-NEXT: [[DOTINV:%.*]] = fcmp fast oge float [[MIN]], 1.000000e+00
+; CHECK-NEXT: [[R1:%.*]] = select i1 [[DOTINV]], float [[MIN]], float 1.000000e+00
+; CHECK-NEXT: ret float [[R1]]
;
%cmp2 = fcmp fast olt float %x, 255.0
%min = select i1 %cmp2, float %x, float 255.0
; CHECK-LABEL: @clamp_float_fast_ordered_nonstrict_maxmin(
; CHECK-NEXT: [[CMP2:%.*]] = fcmp fast olt float [[X:%.*]], 2.550000e+02
; CHECK-NEXT: [[MIN:%.*]] = select i1 [[CMP2]], float [[X]], float 2.550000e+02
-; CHECK-NEXT: [[CMP1:%.*]] = fcmp fast ole float [[X]], 1.000000e+00
-; CHECK-NEXT: [[R:%.*]] = select i1 [[CMP1]], float 1.000000e+00, float [[MIN]]
-; CHECK-NEXT: ret float [[R]]
+; CHECK-NEXT: [[DOTINV:%.*]] = fcmp fast oge float [[MIN]], 1.000000e+00
+; CHECK-NEXT: [[R1:%.*]] = select i1 [[DOTINV]], float [[MIN]], float 1.000000e+00
+; CHECK-NEXT: ret float [[R1]]
;
%cmp2 = fcmp fast olt float %x, 255.0
%min = select i1 %cmp2, float %x, float 255.0
; CHECK-LABEL: @clamp_float_fast_ordered_strict_minmax(
; CHECK-NEXT: [[CMP2:%.*]] = fcmp fast ogt float [[X:%.*]], 1.000000e+00
; CHECK-NEXT: [[MAX:%.*]] = select i1 [[CMP2]], float [[X]], float 1.000000e+00
-; CHECK-NEXT: [[CMP1:%.*]] = fcmp fast ogt float [[X]], 2.550000e+02
-; CHECK-NEXT: [[R:%.*]] = select i1 [[CMP1]], float 2.550000e+02, float [[MAX]]
-; CHECK-NEXT: ret float [[R]]
+; CHECK-NEXT: [[DOTINV:%.*]] = fcmp fast ole float [[MAX]], 2.550000e+02
+; CHECK-NEXT: [[R1:%.*]] = select i1 [[DOTINV]], float [[MAX]], float 2.550000e+02
+; CHECK-NEXT: ret float [[R1]]
;
%cmp2 = fcmp fast ogt float %x, 1.0
%max = select i1 %cmp2, float %x, float 1.0
; CHECK-LABEL: @clamp_float_fast_ordered_nonstrict_minmax(
; CHECK-NEXT: [[CMP2:%.*]] = fcmp fast ogt float [[X:%.*]], 1.000000e+00
; CHECK-NEXT: [[MAX:%.*]] = select i1 [[CMP2]], float [[X]], float 1.000000e+00
-; CHECK-NEXT: [[CMP1:%.*]] = fcmp fast oge float [[X]], 2.550000e+02
-; CHECK-NEXT: [[R:%.*]] = select i1 [[CMP1]], float 2.550000e+02, float [[MAX]]
-; CHECK-NEXT: ret float [[R]]
+; CHECK-NEXT: [[DOTINV:%.*]] = fcmp fast ole float [[MAX]], 2.550000e+02
+; CHECK-NEXT: [[R1:%.*]] = select i1 [[DOTINV]], float [[MAX]], float 2.550000e+02
+; CHECK-NEXT: ret float [[R1]]
;
%cmp2 = fcmp fast ogt float %x, 1.0
%max = select i1 %cmp2, float %x, float 1.0
; CHECK-LABEL: @clamp_float_fast_unordered_strict_maxmin(
; CHECK-NEXT: [[CMP2_INV:%.*]] = fcmp fast oge float [[X:%.*]], 2.550000e+02
; CHECK-NEXT: [[MIN:%.*]] = select i1 [[CMP2_INV]], float 2.550000e+02, float [[X]]
-; CHECK-NEXT: [[CMP1:%.*]] = fcmp fast ult float [[X]], 1.000000e+00
-; CHECK-NEXT: [[R:%.*]] = select i1 [[CMP1]], float 1.000000e+00, float [[MIN]]
-; CHECK-NEXT: ret float [[R]]
+; CHECK-NEXT: [[DOTINV:%.*]] = fcmp fast oge float [[MIN]], 1.000000e+00
+; CHECK-NEXT: [[R1:%.*]] = select i1 [[DOTINV]], float [[MIN]], float 1.000000e+00
+; CHECK-NEXT: ret float [[R1]]
;
%cmp2 = fcmp fast ult float %x, 255.0
%min = select i1 %cmp2, float %x, float 255.0
; CHECK-LABEL: @clamp_float_fast_unordered_nonstrict_maxmin(
; CHECK-NEXT: [[CMP2_INV:%.*]] = fcmp fast oge float [[X:%.*]], 2.550000e+02
; CHECK-NEXT: [[MIN:%.*]] = select i1 [[CMP2_INV]], float 2.550000e+02, float [[X]]
-; CHECK-NEXT: [[CMP1:%.*]] = fcmp fast ule float [[X]], 1.000000e+00
-; CHECK-NEXT: [[R:%.*]] = select i1 [[CMP1]], float 1.000000e+00, float [[MIN]]
-; CHECK-NEXT: ret float [[R]]
+; CHECK-NEXT: [[DOTINV:%.*]] = fcmp fast oge float [[MIN]], 1.000000e+00
+; CHECK-NEXT: [[R1:%.*]] = select i1 [[DOTINV]], float [[MIN]], float 1.000000e+00
+; CHECK-NEXT: ret float [[R1]]
;
%cmp2 = fcmp fast ult float %x, 255.0
%min = select i1 %cmp2, float %x, float 255.0
; CHECK-LABEL: @clamp_float_fast_unordered_strict_minmax(
; CHECK-NEXT: [[CMP2_INV:%.*]] = fcmp fast ole float [[X:%.*]], 1.000000e+00
; CHECK-NEXT: [[MAX:%.*]] = select i1 [[CMP2_INV]], float 1.000000e+00, float [[X]]
-; CHECK-NEXT: [[CMP1:%.*]] = fcmp fast ugt float [[X]], 2.550000e+02
-; CHECK-NEXT: [[R:%.*]] = select i1 [[CMP1]], float 2.550000e+02, float [[MAX]]
-; CHECK-NEXT: ret float [[R]]
+; CHECK-NEXT: [[DOTINV:%.*]] = fcmp fast ole float [[MAX]], 2.550000e+02
+; CHECK-NEXT: [[R1:%.*]] = select i1 [[DOTINV]], float [[MAX]], float 2.550000e+02
+; CHECK-NEXT: ret float [[R1]]
;
%cmp2 = fcmp fast ugt float %x, 1.0
%max = select i1 %cmp2, float %x, float 1.0
; CHECK-LABEL: @clamp_float_fast_unordered_nonstrict_minmax(
; CHECK-NEXT: [[CMP2_INV:%.*]] = fcmp fast ole float [[X:%.*]], 1.000000e+00
; CHECK-NEXT: [[MAX:%.*]] = select i1 [[CMP2_INV]], float 1.000000e+00, float [[X]]
-; CHECK-NEXT: [[CMP1:%.*]] = fcmp fast uge float [[X]], 2.550000e+02
-; CHECK-NEXT: [[R:%.*]] = select i1 [[CMP1]], float 2.550000e+02, float [[MAX]]
-; CHECK-NEXT: ret float [[R]]
+; CHECK-NEXT: [[DOTINV:%.*]] = fcmp fast ole float [[MAX]], 2.550000e+02
+; CHECK-NEXT: [[R1:%.*]] = select i1 [[DOTINV]], float [[MAX]], float 2.550000e+02
+; CHECK-NEXT: ret float [[R1]]
;
%cmp2 = fcmp fast ugt float %x, 1.0
%max = select i1 %cmp2, float %x, float 1.0
; CHECK-LABEL: @clamp_test_1(
; CHECK-NEXT: [[INNER_CMP_INV:%.*]] = fcmp fast oge float [[X:%.*]], 2.550000e+02
; CHECK-NEXT: [[INNER_SEL:%.*]] = select i1 [[INNER_CMP_INV]], float 2.550000e+02, float [[X]]
-; CHECK-NEXT: [[OUTER_CMP:%.*]] = fcmp fast ugt float [[X]], 1.000000e+00
-; CHECK-NEXT: [[R:%.*]] = select i1 [[OUTER_CMP]], float [[INNER_SEL]], float 1.000000e+00
-; CHECK-NEXT: ret float [[R]]
+; CHECK-NEXT: [[DOTINV:%.*]] = fcmp fast oge float [[INNER_SEL]], 1.000000e+00
+; CHECK-NEXT: [[R1:%.*]] = select i1 [[DOTINV]], float [[INNER_SEL]], float 1.000000e+00
+; CHECK-NEXT: ret float [[R1]]
;
%inner_cmp = fcmp fast ult float %x, 255.0
%inner_sel = select i1 %inner_cmp, float %x, float 255.0
;; Check casts behavior
define float @ui32_clamp_and_cast_to_float(i32 %x) {
; CHECK-LABEL: @ui32_clamp_and_cast_to_float(
-; CHECK-NEXT: [[F_X:%.*]] = uitofp i32 [[X:%.*]] to float
-; CHECK-NEXT: [[UP_CMP:%.*]] = icmp ugt i32 [[X]], 255
-; CHECK-NEXT: [[LO_CMP:%.*]] = icmp eq i32 [[X]], 0
-; CHECK-NEXT: [[MIN:%.*]] = select i1 [[UP_CMP]], float 2.550000e+02, float [[F_X]]
-; CHECK-NEXT: [[R:%.*]] = select i1 [[LO_CMP]], float 1.000000e+00, float [[MIN]]
+; CHECK-NEXT: [[LO_CMP:%.*]] = icmp eq i32 [[X:%.*]], 0
+; CHECK-NEXT: [[TMP1:%.*]] = icmp ult i32 [[X]], 255
+; CHECK-NEXT: [[MIN1:%.*]] = select i1 [[TMP1]], i32 [[X]], i32 255
+; CHECK-NEXT: [[TMP2:%.*]] = uitofp i32 [[MIN1]] to float
+; CHECK-NEXT: [[R:%.*]] = select i1 [[LO_CMP]], float 1.000000e+00, float [[TMP2]]
; CHECK-NEXT: ret float [[R]]
;
%f_x = uitofp i32 %x to float
; CHECK-LABEL: @mixed_clamp_to_float_1(
; CHECK-NEXT: [[TMP1:%.*]] = icmp slt i32 [[X:%.*]], 255
; CHECK-NEXT: [[SI_MIN:%.*]] = select i1 [[TMP1]], i32 [[X]], i32 255
-; CHECK-NEXT: [[F_MIN:%.*]] = sitofp i32 [[SI_MIN]] to float
-; CHECK-NEXT: [[LO_CMP:%.*]] = icmp slt i32 [[X]], 1
-; CHECK-NEXT: [[R:%.*]] = select i1 [[LO_CMP]], float 1.000000e+00, float [[F_MIN]]
-; CHECK-NEXT: ret float [[R]]
+; CHECK-NEXT: [[TMP2:%.*]] = icmp sgt i32 [[SI_MIN]], 1
+; CHECK-NEXT: [[R1:%.*]] = select i1 [[TMP2]], i32 [[SI_MIN]], i32 1
+; CHECK-NEXT: [[TMP3:%.*]] = sitofp i32 [[R1]] to float
+; CHECK-NEXT: ret float [[TMP3]]
;
%si_min_cmp = icmp sgt i32 %x, 255
%si_min = select i1 %si_min_cmp, i32 255, i32 %x
; CHECK-LABEL: @mixed_clamp_to_float_2(
; CHECK-NEXT: [[TMP1:%.*]] = icmp slt i32 [[X:%.*]], 255
; CHECK-NEXT: [[SI_MIN:%.*]] = select i1 [[TMP1]], i32 [[X]], i32 255
-; CHECK-NEXT: [[F_MIN:%.*]] = sitofp i32 [[SI_MIN]] to float
-; CHECK-NEXT: [[LO_CMP:%.*]] = icmp slt i32 [[X]], 1
-; CHECK-NEXT: [[R:%.*]] = select i1 [[LO_CMP]], float 1.000000e+00, float [[F_MIN]]
-; CHECK-NEXT: ret float [[R]]
+; CHECK-NEXT: [[TMP2:%.*]] = icmp sgt i32 [[SI_MIN]], 1
+; CHECK-NEXT: [[R1:%.*]] = select i1 [[TMP2]], i32 [[SI_MIN]], i32 1
+; CHECK-NEXT: [[TMP3:%.*]] = sitofp i32 [[R1]] to float
+; CHECK-NEXT: ret float [[TMP3]]
;
%si_min_cmp = icmp sgt i32 %x, 255
%si_min = select i1 %si_min_cmp, i32 255, i32 %x