diff --git a/clang/test/CodeGen/attr-counted-by.c b/clang/test/CodeGen/attr-counted-by.c index f70e552bca26ab..d3f12bc5e07abc 100644 --- a/clang/test/CodeGen/attr-counted-by.c +++ b/clang/test/CodeGen/attr-counted-by.c @@ -119,9 +119,8 @@ void test1(struct annotated *p, int index, int val) { // SANITIZE-WITH-ATTR: cont3: // SANITIZE-WITH-ATTR-NEXT: [[ARRAY:%.*]] = getelementptr inbounds nuw i8, ptr [[P]], i64 12 // SANITIZE-WITH-ATTR-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds nuw [0 x i32], ptr [[ARRAY]], i64 0, i64 [[INDEX]] -// SANITIZE-WITH-ATTR-NEXT: [[TMP2:%.*]] = shl i32 [[DOT_COUNTED_BY_LOAD]], 2 -// SANITIZE-WITH-ATTR-NEXT: [[DOTINV:%.*]] = icmp slt i32 [[DOT_COUNTED_BY_LOAD]], 0 -// SANITIZE-WITH-ATTR-NEXT: [[CONV:%.*]] = select i1 [[DOTINV]], i32 0, i32 [[TMP2]] +// SANITIZE-WITH-ATTR-NEXT: [[TMP2:%.*]] = tail call i32 @llvm.smax.i32(i32 [[DOT_COUNTED_BY_LOAD]], i32 0) +// SANITIZE-WITH-ATTR-NEXT: [[CONV:%.*]] = shl i32 [[TMP2]], 2 // SANITIZE-WITH-ATTR-NEXT: store i32 [[CONV]], ptr [[ARRAYIDX]], align 4, !tbaa [[TBAA4]] // SANITIZE-WITH-ATTR-NEXT: ret void // @@ -130,9 +129,8 @@ void test1(struct annotated *p, int index, int val) { // NO-SANITIZE-WITH-ATTR-NEXT: entry: // NO-SANITIZE-WITH-ATTR-NEXT: [[DOT_COUNTED_BY_GEP:%.*]] = getelementptr inbounds i8, ptr [[P]], i64 8 // NO-SANITIZE-WITH-ATTR-NEXT: [[DOT_COUNTED_BY_LOAD:%.*]] = load i32, ptr [[DOT_COUNTED_BY_GEP]], align 4 -// NO-SANITIZE-WITH-ATTR-NEXT: [[TMP0:%.*]] = shl i32 [[DOT_COUNTED_BY_LOAD]], 2 -// NO-SANITIZE-WITH-ATTR-NEXT: [[DOTINV:%.*]] = icmp slt i32 [[DOT_COUNTED_BY_LOAD]], 0 -// NO-SANITIZE-WITH-ATTR-NEXT: [[CONV:%.*]] = select i1 [[DOTINV]], i32 0, i32 [[TMP0]] +// NO-SANITIZE-WITH-ATTR-NEXT: [[TMP0:%.*]] = tail call i32 @llvm.smax.i32(i32 [[DOT_COUNTED_BY_LOAD]], i32 0) +// NO-SANITIZE-WITH-ATTR-NEXT: [[CONV:%.*]] = shl i32 [[TMP0]], 2 // NO-SANITIZE-WITH-ATTR-NEXT: [[ARRAY:%.*]] = getelementptr inbounds nuw i8, ptr [[P]], i64 12 // NO-SANITIZE-WITH-ATTR-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds nuw [0 x i32], ptr [[ARRAY]], i64 0, i64 [[INDEX]] // NO-SANITIZE-WITH-ATTR-NEXT: store i32 [[CONV]], ptr [[ARRAYIDX]], align 4, !tbaa [[TBAA2]] @@ -539,10 +537,9 @@ size_t test5_bdos(struct anon_struct *p) { // SANITIZE-WITH-ATTR: cont3: // SANITIZE-WITH-ATTR-NEXT: [[TMP1:%.*]] = getelementptr inbounds nuw i8, ptr [[P]], i64 16 // SANITIZE-WITH-ATTR-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds [0 x i32], ptr [[TMP1]], i64 0, i64 [[IDXPROM]] -// SANITIZE-WITH-ATTR-NEXT: [[DOTINV:%.*]] = icmp slt i64 [[DOT_COUNTED_BY_LOAD]], 0 -// SANITIZE-WITH-ATTR-NEXT: [[DOT_COUNTED_BY_LOAD_TR:%.*]] = trunc i64 [[DOT_COUNTED_BY_LOAD]] to i32 -// SANITIZE-WITH-ATTR-NEXT: [[TMP2:%.*]] = shl i32 [[DOT_COUNTED_BY_LOAD_TR]], 2 -// SANITIZE-WITH-ATTR-NEXT: [[CONV:%.*]] = select i1 [[DOTINV]], i32 0, i32 [[TMP2]] +// SANITIZE-WITH-ATTR-NEXT: [[TMP2:%.*]] = tail call i64 @llvm.smax.i64(i64 [[DOT_COUNTED_BY_LOAD]], i64 0) +// SANITIZE-WITH-ATTR-NEXT: [[DOTTR:%.*]] = trunc i64 [[TMP2]] to i32 +// SANITIZE-WITH-ATTR-NEXT: [[CONV:%.*]] = shl i32 [[DOTTR]], 2 // SANITIZE-WITH-ATTR-NEXT: store i32 [[CONV]], ptr [[ARRAYIDX]], align 4, !tbaa [[TBAA4]] // SANITIZE-WITH-ATTR-NEXT: ret void // @@ -551,10 +548,9 @@ size_t test5_bdos(struct anon_struct *p) { // NO-SANITIZE-WITH-ATTR-NEXT: entry: // NO-SANITIZE-WITH-ATTR-NEXT: [[DOT_COUNTED_BY_GEP:%.*]] = getelementptr inbounds i8, ptr [[P]], i64 8 // NO-SANITIZE-WITH-ATTR-NEXT: [[DOT_COUNTED_BY_LOAD:%.*]] = load i64, ptr [[DOT_COUNTED_BY_GEP]], align 4 -// NO-SANITIZE-WITH-ATTR-NEXT: [[DOTINV:%.*]] = icmp slt i64 [[DOT_COUNTED_BY_LOAD]], 0 -// NO-SANITIZE-WITH-ATTR-NEXT: [[DOT_COUNTED_BY_LOAD_TR:%.*]] = trunc i64 [[DOT_COUNTED_BY_LOAD]] to i32 -// NO-SANITIZE-WITH-ATTR-NEXT: [[TMP0:%.*]] = shl i32 [[DOT_COUNTED_BY_LOAD_TR]], 2 -// NO-SANITIZE-WITH-ATTR-NEXT: [[CONV:%.*]] = select i1 [[DOTINV]], i32 0, i32 [[TMP0]] +// NO-SANITIZE-WITH-ATTR-NEXT: [[TMP0:%.*]] = tail call i64 @llvm.smax.i64(i64 [[DOT_COUNTED_BY_LOAD]], i64 0) +// NO-SANITIZE-WITH-ATTR-NEXT: [[DOTTR:%.*]] = trunc i64 [[TMP0]] to i32 +// NO-SANITIZE-WITH-ATTR-NEXT: [[CONV:%.*]] = shl i32 [[DOTTR]], 2 // NO-SANITIZE-WITH-ATTR-NEXT: [[TMP1:%.*]] = getelementptr inbounds nuw i8, ptr [[P]], i64 16 // NO-SANITIZE-WITH-ATTR-NEXT: [[IDXPROM:%.*]] = sext i32 [[INDEX]] to i64 // NO-SANITIZE-WITH-ATTR-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds [0 x i32], ptr [[TMP1]], i64 0, i64 [[IDXPROM]] @@ -588,9 +584,8 @@ void test6(struct anon_struct *p, int index) { // SANITIZE-WITH-ATTR-NEXT: entry: // SANITIZE-WITH-ATTR-NEXT: [[DOT_COUNTED_BY_GEP:%.*]] = getelementptr inbounds i8, ptr [[P]], i64 8 // SANITIZE-WITH-ATTR-NEXT: [[DOT_COUNTED_BY_LOAD:%.*]] = load i64, ptr [[DOT_COUNTED_BY_GEP]], align 4 -// SANITIZE-WITH-ATTR-NEXT: [[TMP0:%.*]] = shl nuw i64 [[DOT_COUNTED_BY_LOAD]], 2 -// SANITIZE-WITH-ATTR-NEXT: [[DOTINV:%.*]] = icmp slt i64 [[DOT_COUNTED_BY_LOAD]], 0 -// SANITIZE-WITH-ATTR-NEXT: [[TMP1:%.*]] = select i1 [[DOTINV]], i64 0, i64 [[TMP0]] +// SANITIZE-WITH-ATTR-NEXT: [[TMP0:%.*]] = tail call i64 @llvm.smax.i64(i64 [[DOT_COUNTED_BY_LOAD]], i64 0) +// SANITIZE-WITH-ATTR-NEXT: [[TMP1:%.*]] = shl i64 [[TMP0]], 2 // SANITIZE-WITH-ATTR-NEXT: ret i64 [[TMP1]] // // NO-SANITIZE-WITH-ATTR-LABEL: define dso_local range(i64 0, -3) i64 @test6_bdos( @@ -598,9 +593,8 @@ void test6(struct anon_struct *p, int index) { // NO-SANITIZE-WITH-ATTR-NEXT: entry: // NO-SANITIZE-WITH-ATTR-NEXT: [[DOT_COUNTED_BY_GEP:%.*]] = getelementptr inbounds i8, ptr [[P]], i64 8 // NO-SANITIZE-WITH-ATTR-NEXT: [[DOT_COUNTED_BY_LOAD:%.*]] = load i64, ptr [[DOT_COUNTED_BY_GEP]], align 4 -// NO-SANITIZE-WITH-ATTR-NEXT: [[TMP0:%.*]] = shl nuw i64 [[DOT_COUNTED_BY_LOAD]], 2 -// NO-SANITIZE-WITH-ATTR-NEXT: [[DOTINV:%.*]] = icmp slt i64 [[DOT_COUNTED_BY_LOAD]], 0 -// NO-SANITIZE-WITH-ATTR-NEXT: [[TMP1:%.*]] = select i1 [[DOTINV]], i64 0, i64 [[TMP0]] +// NO-SANITIZE-WITH-ATTR-NEXT: [[TMP0:%.*]] = tail call i64 @llvm.smax.i64(i64 [[DOT_COUNTED_BY_LOAD]], i64 0) +// NO-SANITIZE-WITH-ATTR-NEXT: [[TMP1:%.*]] = shl i64 [[TMP0]], 2 // NO-SANITIZE-WITH-ATTR-NEXT: ret i64 [[TMP1]] // // SANITIZE-WITHOUT-ATTR-LABEL: define dso_local i64 @test6_bdos( @@ -1740,9 +1734,8 @@ struct annotated_struct_array { // SANITIZE-WITH-ATTR: cont20: // SANITIZE-WITH-ATTR-NEXT: [[ARRAY:%.*]] = getelementptr inbounds nuw i8, ptr [[TMP2]], i64 12 // SANITIZE-WITH-ATTR-NEXT: [[ARRAYIDX18:%.*]] = getelementptr inbounds [0 x i32], ptr [[ARRAY]], i64 0, i64 [[IDXPROM15]] -// SANITIZE-WITH-ATTR-NEXT: [[TMP5:%.*]] = shl i32 [[DOT_COUNTED_BY_LOAD]], 2 -// SANITIZE-WITH-ATTR-NEXT: [[DOTINV:%.*]] = icmp slt i32 [[DOT_COUNTED_BY_LOAD]], 0 -// SANITIZE-WITH-ATTR-NEXT: [[CONV:%.*]] = select i1 [[DOTINV]], i32 0, i32 [[TMP5]] +// SANITIZE-WITH-ATTR-NEXT: [[TMP5:%.*]] = tail call i32 @llvm.smax.i32(i32 [[DOT_COUNTED_BY_LOAD]], i32 0) +// SANITIZE-WITH-ATTR-NEXT: [[CONV:%.*]] = shl i32 [[TMP5]], 2 // SANITIZE-WITH-ATTR-NEXT: store i32 [[CONV]], ptr [[ARRAYIDX18]], align 4, !tbaa [[TBAA4]] // SANITIZE-WITH-ATTR-NEXT: ret void // @@ -1754,9 +1747,8 @@ struct annotated_struct_array { // NO-SANITIZE-WITH-ATTR-NEXT: [[TMP0:%.*]] = load ptr, ptr [[ARRAYIDX]], align 8, !tbaa [[TBAA11]] // NO-SANITIZE-WITH-ATTR-NEXT: [[DOT_COUNTED_BY_GEP:%.*]] = getelementptr inbounds i8, ptr [[TMP0]], i64 8 // NO-SANITIZE-WITH-ATTR-NEXT: [[DOT_COUNTED_BY_LOAD:%.*]] = load i32, ptr [[DOT_COUNTED_BY_GEP]], align 4 -// NO-SANITIZE-WITH-ATTR-NEXT: [[TMP1:%.*]] = shl i32 [[DOT_COUNTED_BY_LOAD]], 2 -// NO-SANITIZE-WITH-ATTR-NEXT: [[DOTINV:%.*]] = icmp slt i32 [[DOT_COUNTED_BY_LOAD]], 0 -// NO-SANITIZE-WITH-ATTR-NEXT: [[CONV:%.*]] = select i1 [[DOTINV]], i32 0, i32 [[TMP1]] +// NO-SANITIZE-WITH-ATTR-NEXT: [[TMP1:%.*]] = tail call i32 @llvm.smax.i32(i32 [[DOT_COUNTED_BY_LOAD]], i32 0) +// NO-SANITIZE-WITH-ATTR-NEXT: [[CONV:%.*]] = shl i32 [[TMP1]], 2 // NO-SANITIZE-WITH-ATTR-NEXT: [[ARRAY:%.*]] = getelementptr inbounds nuw i8, ptr [[TMP0]], i64 12 // NO-SANITIZE-WITH-ATTR-NEXT: [[IDXPROM4:%.*]] = sext i32 [[IDX2]] to i64 // NO-SANITIZE-WITH-ATTR-NEXT: [[ARRAYIDX5:%.*]] = getelementptr inbounds [0 x i32], ptr [[ARRAY]], i64 0, i64 [[IDXPROM4]] diff --git a/llvm/include/llvm/Analysis/ValueTracking.h b/llvm/include/llvm/Analysis/ValueTracking.h index 2b0377903ac8e3..bd74d27e0c49b1 100644 --- a/llvm/include/llvm/Analysis/ValueTracking.h +++ b/llvm/include/llvm/Analysis/ValueTracking.h @@ -1178,10 +1178,20 @@ SelectPatternResult matchDecomposedSelectPattern( CmpInst *CmpI, Value *TrueVal, Value *FalseVal, Value *&LHS, Value *&RHS, Instruction::CastOps *CastOp = nullptr, unsigned Depth = 0); +/// Determine the pattern for predicate `X Pred Y ? X : Y`. +SelectPatternResult +getSelectPattern(CmpInst::Predicate Pred, + SelectPatternNaNBehavior NaNBehavior = SPNB_NA, + bool Ordered = false); + /// Return the canonical comparison predicate for the specified /// minimum/maximum flavor. CmpInst::Predicate getMinMaxPred(SelectPatternFlavor SPF, bool Ordered = false); +/// Convert given `SPF` to equivalent min/max intrinsic. +/// Caller must ensure `SPF` is an integer min or max pattern. +Intrinsic::ID getMinMaxIntrinsic(SelectPatternFlavor SPF); + /// Return the inverse minimum/maximum flavor of the specified flavor. /// For example, signed minimum is the inverse of signed maximum. SelectPatternFlavor getInverseMinMaxFlavor(SelectPatternFlavor SPF); diff --git a/llvm/lib/Analysis/ValueTracking.cpp b/llvm/lib/Analysis/ValueTracking.cpp index c48068afc04816..25740473fd5a14 100644 --- a/llvm/lib/Analysis/ValueTracking.cpp +++ b/llvm/lib/Analysis/ValueTracking.cpp @@ -8589,6 +8589,37 @@ bool llvm::isKnownInversion(const Value *X, const Value *Y) { return CR1.inverse() == CR2; } +SelectPatternResult llvm::getSelectPattern(CmpInst::Predicate Pred, + SelectPatternNaNBehavior NaNBehavior, + bool Ordered) { + switch (Pred) { + default: + return {SPF_UNKNOWN, SPNB_NA, false}; // Equality. + case ICmpInst::ICMP_UGT: + case ICmpInst::ICMP_UGE: + return {SPF_UMAX, SPNB_NA, false}; + case ICmpInst::ICMP_SGT: + case ICmpInst::ICMP_SGE: + return {SPF_SMAX, SPNB_NA, false}; + case ICmpInst::ICMP_ULT: + case ICmpInst::ICMP_ULE: + return {SPF_UMIN, SPNB_NA, false}; + case ICmpInst::ICMP_SLT: + case ICmpInst::ICMP_SLE: + return {SPF_SMIN, SPNB_NA, false}; + case FCmpInst::FCMP_UGT: + case FCmpInst::FCMP_UGE: + case FCmpInst::FCMP_OGT: + case FCmpInst::FCMP_OGE: + return {SPF_FMAXNUM, NaNBehavior, Ordered}; + case FCmpInst::FCMP_ULT: + case FCmpInst::FCMP_ULE: + case FCmpInst::FCMP_OLT: + case FCmpInst::FCMP_OLE: + return {SPF_FMINNUM, NaNBehavior, Ordered}; + } +} + static SelectPatternResult matchSelectPattern(CmpInst::Predicate Pred, FastMathFlags FMF, Value *CmpLHS, Value *CmpRHS, @@ -8696,27 +8727,8 @@ static SelectPatternResult matchSelectPattern(CmpInst::Predicate Pred, } // ([if]cmp X, Y) ? X : Y - if (TrueVal == CmpLHS && FalseVal == CmpRHS) { - switch (Pred) { - default: return {SPF_UNKNOWN, SPNB_NA, false}; // Equality. - case ICmpInst::ICMP_UGT: - case ICmpInst::ICMP_UGE: return {SPF_UMAX, SPNB_NA, false}; - case ICmpInst::ICMP_SGT: - case ICmpInst::ICMP_SGE: return {SPF_SMAX, SPNB_NA, false}; - case ICmpInst::ICMP_ULT: - case ICmpInst::ICMP_ULE: return {SPF_UMIN, SPNB_NA, false}; - case ICmpInst::ICMP_SLT: - case ICmpInst::ICMP_SLE: return {SPF_SMIN, SPNB_NA, false}; - case FCmpInst::FCMP_UGT: - case FCmpInst::FCMP_UGE: - case FCmpInst::FCMP_OGT: - case FCmpInst::FCMP_OGE: return {SPF_FMAXNUM, NaNBehavior, Ordered}; - case FCmpInst::FCMP_ULT: - case FCmpInst::FCMP_ULE: - case FCmpInst::FCMP_OLT: - case FCmpInst::FCMP_OLE: return {SPF_FMINNUM, NaNBehavior, Ordered}; - } - } + if (TrueVal == CmpLHS && FalseVal == CmpRHS) + return getSelectPattern(Pred, NaNBehavior, Ordered); if (isKnownNegation(TrueVal, FalseVal)) { // Sign-extending LHS does not change its sign, so TrueVal/FalseVal can @@ -8960,6 +8972,21 @@ CmpInst::Predicate llvm::getMinMaxPred(SelectPatternFlavor SPF, bool Ordered) { llvm_unreachable("unhandled!"); } +Intrinsic::ID llvm::getMinMaxIntrinsic(SelectPatternFlavor SPF) { + switch (SPF) { + case SelectPatternFlavor::SPF_UMIN: + return Intrinsic::umin; + case SelectPatternFlavor::SPF_UMAX: + return Intrinsic::umax; + case SelectPatternFlavor::SPF_SMIN: + return Intrinsic::smin; + case SelectPatternFlavor::SPF_SMAX: + return Intrinsic::smax; + default: + llvm_unreachable("Unexpected SPF"); + } +} + SelectPatternFlavor llvm::getInverseMinMaxFlavor(SelectPatternFlavor SPF) { if (SPF == SPF_SMIN) return SPF_SMAX; if (SPF == SPF_UMIN) return SPF_UMAX; diff --git a/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp b/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp index e5525133e5dbb5..027a45b95a6de3 100644 --- a/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp +++ b/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp @@ -1257,23 +1257,7 @@ static Value *canonicalizeSPF(ICmpInst &Cmp, Value *TrueVal, Value *FalseVal, } if (SelectPatternResult::isMinOrMax(SPF)) { - Intrinsic::ID IntrinsicID; - switch (SPF) { - case SelectPatternFlavor::SPF_UMIN: - IntrinsicID = Intrinsic::umin; - break; - case SelectPatternFlavor::SPF_UMAX: - IntrinsicID = Intrinsic::umax; - break; - case SelectPatternFlavor::SPF_SMIN: - IntrinsicID = Intrinsic::smin; - break; - case SelectPatternFlavor::SPF_SMAX: - IntrinsicID = Intrinsic::smax; - break; - default: - llvm_unreachable("Unexpected SPF"); - } + Intrinsic::ID IntrinsicID = getMinMaxIntrinsic(SPF); return IC.Builder.CreateBinaryIntrinsic(IntrinsicID, LHS, RHS); } @@ -1898,6 +1882,60 @@ static Instruction *foldSelectICmpEq(SelectInst &SI, ICmpInst *ICI, return nullptr; } +/// Fold `X Pred C1 ? X BOp C2 : C1 BOp C2` to `min/max(X, C1) BOp C2`. +/// This allows for better canonicalization. +static Value *foldSelectWithConstOpToBinOp(ICmpInst *Cmp, Value *TrueVal, + Value *FalseVal, + IRBuilderBase &Builder) { + BinaryOperator *BOp; + Constant *C1, *C2, *C3; + Value *X; + ICmpInst::Predicate Predicate; + + if (!match(Cmp, m_ICmp(Predicate, m_Value(X), m_Constant(C1)))) + return nullptr; + + if (!ICmpInst::isRelational(Predicate)) + return nullptr; + + if (match(TrueVal, m_Constant())) { + std::swap(FalseVal, TrueVal); + Predicate = ICmpInst::getInversePredicate(Predicate); + } + + if (!match(TrueVal, m_BinOp(BOp)) || !match(FalseVal, m_Constant(C3))) + return nullptr; + + unsigned Opcode = BOp->getOpcode(); + + if (Instruction::isIntDivRem(Opcode)) + return nullptr; + + if (!match(BOp, m_OneUse(m_BinOp(m_Specific(X), m_Constant(C2))))) + return nullptr; + + Value *RHS; + SelectPatternFlavor SPF; + const DataLayout &Layout = BOp->getDataLayout(); + auto Flipped = + InstCombiner::getFlippedStrictnessPredicateAndConstant(Predicate, C1); + + if (C3 == ConstantFoldBinaryOpOperands(Opcode, C1, C2, Layout)) { + SPF = getSelectPattern(Predicate).Flavor; + RHS = C1; + } else if (Flipped && C3 == ConstantFoldBinaryOpOperands( + Opcode, Flipped->second, C2, Layout)) { + SPF = getSelectPattern(Flipped->first).Flavor; + RHS = Flipped->second; + } else { + return nullptr; + } + + Intrinsic::ID IntrinsicID = getMinMaxIntrinsic(SPF); + Value *Intrinsic = Builder.CreateBinaryIntrinsic(IntrinsicID, X, RHS); + return Builder.CreateBinOp(BOp->getOpcode(), Intrinsic, C2); +} + /// Visit a SelectInst that has an ICmpInst as its first operand. Instruction *InstCombinerImpl::foldSelectInstWithICmp(SelectInst &SI, ICmpInst *ICI) { @@ -1987,6 +2025,9 @@ Instruction *InstCombinerImpl::foldSelectInstWithICmp(SelectInst &SI, if (Value *V = foldAbsDiff(ICI, TrueVal, FalseVal, Builder)) return replaceInstUsesWith(SI, V); + if (Value *V = foldSelectWithConstOpToBinOp(ICI, TrueVal, FalseVal, Builder)) + return replaceInstUsesWith(SI, V); + return Changed ? &SI : nullptr; } diff --git a/llvm/test/Transforms/InstCombine/canonicalize-const-to-bop.ll b/llvm/test/Transforms/InstCombine/canonicalize-const-to-bop.ll index a23fc84aebd2e3..68049ca230191e 100644 --- a/llvm/test/Transforms/InstCombine/canonicalize-const-to-bop.ll +++ b/llvm/test/Transforms/InstCombine/canonicalize-const-to-bop.ll @@ -4,9 +4,8 @@ define i8 @add_and_sgt(i8 %x) { ; CHECK-LABEL: define i8 @add_and_sgt( ; CHECK-SAME: i8 [[X:%.*]]) { -; CHECK-NEXT: [[ADD:%.*]] = add nsw i8 [[X]], 16 -; CHECK-NEXT: [[CMP:%.*]] = icmp sgt i8 [[X]], 8 -; CHECK-NEXT: [[S:%.*]] = select i1 [[CMP]], i8 [[ADD]], i8 24 +; CHECK-NEXT: [[TMP1:%.*]] = call i8 @llvm.smax.i8(i8 [[X]], i8 8) +; CHECK-NEXT: [[S:%.*]] = add nuw i8 [[TMP1]], 16 ; CHECK-NEXT: ret i8 [[S]] ; %add = add nsw i8 %x, 16 @@ -18,9 +17,8 @@ define i8 @add_and_sgt(i8 %x) { define i8 @add_sgt_nuw(i8 %x) { ; CHECK-LABEL: define i8 @add_sgt_nuw( ; CHECK-SAME: i8 [[X:%.*]]) { -; CHECK-NEXT: [[ADD:%.*]] = add nuw i8 [[X]], 16 -; CHECK-NEXT: [[CMP:%.*]] = icmp sgt i8 [[X]], 8 -; CHECK-NEXT: [[S:%.*]] = select i1 [[CMP]], i8 [[ADD]], i8 24 +; CHECK-NEXT: [[TMP1:%.*]] = call i8 @llvm.smax.i8(i8 [[X]], i8 8) +; CHECK-NEXT: [[S:%.*]] = add nuw i8 [[TMP1]], 16 ; CHECK-NEXT: ret i8 [[S]] ; %add = add nuw i8 %x, 16 @@ -32,9 +30,8 @@ define i8 @add_sgt_nuw(i8 %x) { define i8 @sub_and_ugt(i8 %x) { ; CHECK-LABEL: define i8 @sub_and_ugt( ; CHECK-SAME: i8 [[X:%.*]]) { -; CHECK-NEXT: [[SUB:%.*]] = add nsw i8 [[X]], -50 -; CHECK-NEXT: [[CMP:%.*]] = icmp ugt i8 [[X]], 100 -; CHECK-NEXT: [[S:%.*]] = select i1 [[CMP]], i8 50, i8 [[SUB]] +; CHECK-NEXT: [[TMP1:%.*]] = call i8 @llvm.umin.i8(i8 [[X]], i8 100) +; CHECK-NEXT: [[S:%.*]] = add nsw i8 [[TMP1]], -50 ; CHECK-NEXT: ret i8 [[S]] ; %sub = sub nsw i8 %x, 50 @@ -46,9 +43,8 @@ define i8 @sub_and_ugt(i8 %x) { define i8 @sub_ugt_nuw_nsw(i8 %x) { ; CHECK-LABEL: define i8 @sub_ugt_nuw_nsw( ; CHECK-SAME: i8 [[X:%.*]]) { -; CHECK-NEXT: [[SUB:%.*]] = add nsw i8 [[X]], -50 -; CHECK-NEXT: [[CMP:%.*]] = icmp ugt i8 [[X]], 100 -; CHECK-NEXT: [[S:%.*]] = select i1 [[CMP]], i8 50, i8 [[SUB]] +; CHECK-NEXT: [[TMP1:%.*]] = call i8 @llvm.umin.i8(i8 [[X]], i8 100) +; CHECK-NEXT: [[S:%.*]] = add nsw i8 [[TMP1]], -50 ; CHECK-NEXT: ret i8 [[S]] ; %sub = sub nuw nsw i8 %x, 50 @@ -60,9 +56,8 @@ define i8 @sub_ugt_nuw_nsw(i8 %x) { define i8 @mul_and_ult(i8 %x) { ; CHECK-LABEL: define i8 @mul_and_ult( ; CHECK-SAME: i8 [[X:%.*]]) { -; CHECK-NEXT: [[ADD:%.*]] = mul nsw i8 [[X]], 10 -; CHECK-NEXT: [[CMP:%.*]] = icmp ugt i8 [[X]], 10 -; CHECK-NEXT: [[S:%.*]] = select i1 [[CMP]], i8 100, i8 [[ADD]] +; CHECK-NEXT: [[TMP1:%.*]] = call i8 @llvm.umin.i8(i8 [[X]], i8 10) +; CHECK-NEXT: [[S:%.*]] = mul nuw i8 [[TMP1]], 10 ; CHECK-NEXT: ret i8 [[S]] ; %add = mul nsw i8 %x, 10 @@ -74,9 +69,8 @@ define i8 @mul_and_ult(i8 %x) { define i8 @mul_and_non_strict_predicate(i8 %x) { ; CHECK-LABEL: define i8 @mul_and_non_strict_predicate( ; CHECK-SAME: i8 [[X:%.*]]) { -; CHECK-NEXT: [[ADD:%.*]] = mul nsw i8 [[X]], 10 -; CHECK-NEXT: [[CMP:%.*]] = icmp sgt i8 [[X]], 9 -; CHECK-NEXT: [[S:%.*]] = select i1 [[CMP]], i8 100, i8 [[ADD]] +; CHECK-NEXT: [[TMP1:%.*]] = call i8 @llvm.smin.i8(i8 [[X]], i8 10) +; CHECK-NEXT: [[S:%.*]] = mul i8 [[TMP1]], 10 ; CHECK-NEXT: ret i8 [[S]] ; %add = mul nsw i8 %x, 10 @@ -88,9 +82,8 @@ define i8 @mul_and_non_strict_predicate(i8 %x) { define i8 @mul_ult_noflags(i8 %x) { ; CHECK-LABEL: define i8 @mul_ult_noflags( ; CHECK-SAME: i8 [[X:%.*]]) { -; CHECK-NEXT: [[ADD:%.*]] = mul i8 [[X]], 10 -; CHECK-NEXT: [[CMP:%.*]] = icmp ugt i8 [[X]], 10 -; CHECK-NEXT: [[S:%.*]] = select i1 [[CMP]], i8 100, i8 [[ADD]] +; CHECK-NEXT: [[TMP1:%.*]] = call i8 @llvm.umin.i8(i8 [[X]], i8 10) +; CHECK-NEXT: [[S:%.*]] = mul nuw i8 [[TMP1]], 10 ; CHECK-NEXT: ret i8 [[S]] ; %add = mul i8 %x, 10 @@ -130,9 +123,8 @@ define i8 @udiv_slt_exact(i8 %x) { define i8 @canonicalize_icmp_operands(i8 %x) { ; CHECK-LABEL: define i8 @canonicalize_icmp_operands( ; CHECK-SAME: i8 [[X:%.*]]) { -; CHECK-NEXT: [[ADD:%.*]] = add nsw i8 [[X]], 8 -; CHECK-NEXT: [[CMP:%.*]] = icmp sgt i8 [[X]], 119 -; CHECK-NEXT: [[S:%.*]] = select i1 [[CMP]], i8 127, i8 [[ADD]] +; CHECK-NEXT: [[TMP1:%.*]] = call i8 @llvm.smin.i8(i8 [[X]], i8 119) +; CHECK-NEXT: [[S:%.*]] = add nsw i8 [[TMP1]], 8 ; CHECK-NEXT: ret i8 [[S]] ; %add = add nsw i8 %x, 8 @@ -144,9 +136,8 @@ define i8 @canonicalize_icmp_operands(i8 %x) { define i8 @flipped_strictness_predicate_and_constant(i8 %x, i8 %y) { ; CHECK-LABEL: define i8 @flipped_strictness_predicate_and_constant( ; CHECK-SAME: i8 [[X:%.*]], i8 [[Y:%.*]]) { -; CHECK-NEXT: [[A:%.*]] = add i8 [[X]], -2 -; CHECK-NEXT: [[C:%.*]] = icmp ult i8 [[X]], 2 -; CHECK-NEXT: [[R:%.*]] = select i1 [[C]], i8 -1, i8 [[A]] +; CHECK-NEXT: [[TMP1:%.*]] = call i8 @llvm.umax.i8(i8 [[X]], i8 1) +; CHECK-NEXT: [[R:%.*]] = add i8 [[TMP1]], -2 ; CHECK-NEXT: ret i8 [[R]] ; %a = add i8 %x, -2 @@ -161,10 +152,10 @@ declare void @use_byte(i8) define i8 @multi_use_cond_and_sel(i8 %x) { ; CHECK-LABEL: define i8 @multi_use_cond_and_sel( ; CHECK-SAME: i8 [[X:%.*]]) { -; CHECK-NEXT: [[ADD:%.*]] = add nsw i8 [[X]], 16 ; CHECK-NEXT: [[CMP:%.*]] = icmp sgt i8 [[X]], 8 ; CHECK-NEXT: call void @use(i1 [[CMP]]) -; CHECK-NEXT: [[S:%.*]] = select i1 [[CMP]], i8 [[ADD]], i8 24 +; CHECK-NEXT: [[TMP1:%.*]] = call i8 @llvm.smax.i8(i8 [[X]], i8 8) +; CHECK-NEXT: [[S:%.*]] = add nuw i8 [[TMP1]], 16 ; CHECK-NEXT: call void @use_byte(i8 [[S]]) ; CHECK-NEXT: ret i8 [[S]] ; @@ -183,11 +174,9 @@ define void @rust_noop_loop() { ; CHECK: [[BB2_I]]: ; CHECK-NEXT: [[ITER_SROA_0_07:%.*]] = phi i32 [ 0, %[[START]] ], [ [[SPEC_SELECT5:%.*]], %[[BB2_I]] ] ; CHECK-NEXT: [[_0_I3_I:%.*]] = icmp sgt i32 [[ITER_SROA_0_07]], 99 -; CHECK-NEXT: [[TMP0:%.*]] = add nsw i32 [[ITER_SROA_0_07]], 1 -; CHECK-NEXT: [[SPEC_SELECT5]] = select i1 [[_0_I3_I]], i32 100, i32 [[TMP0]] -; CHECK-NEXT: [[_0_I_NOT_I:%.*]] = icmp sgt i32 [[SPEC_SELECT5]], 100 -; CHECK-NEXT: [[OR_COND:%.*]] = select i1 [[_0_I3_I]], i1 true, i1 [[_0_I_NOT_I]] -; CHECK-NEXT: br i1 [[OR_COND]], label %[[BASICBLOCK4:.*]], label %[[BB2_I]] +; CHECK-NEXT: [[TMP0:%.*]] = call i32 @llvm.smin.i32(i32 [[ITER_SROA_0_07]], i32 99) +; CHECK-NEXT: [[SPEC_SELECT5]] = add nsw i32 [[TMP0]], 1 +; CHECK-NEXT: br i1 [[_0_I3_I]], label %[[BASICBLOCK4:.*]], label %[[BB2_I]] ; CHECK: [[BASICBLOCK4]]: ; CHECK-NEXT: ret void ; @@ -210,9 +199,8 @@ basicblock4: define <2 x i8> @add_non_splat_vector(<2 x i8> %x) { ; CHECK-LABEL: define <2 x i8> @add_non_splat_vector( ; CHECK-SAME: <2 x i8> [[X:%.*]]) { -; CHECK-NEXT: [[ADD:%.*]] = add <2 x i8> [[X]], -; CHECK-NEXT: [[CMP:%.*]] = icmp sgt <2 x i8> [[X]], -; CHECK-NEXT: [[S:%.*]] = select <2 x i1> [[CMP]], <2 x i8> [[ADD]], <2 x i8> splat (i8 1) +; CHECK-NEXT: [[TMP1:%.*]] = call <2 x i8> @llvm.smax.v2i8(<2 x i8> [[X]], <2 x i8> ) +; CHECK-NEXT: [[S:%.*]] = add nuw <2 x i8> [[TMP1]], ; CHECK-NEXT: ret <2 x i8> [[S]] ; %add = add <2 x i8> %x, @@ -224,9 +212,8 @@ define <2 x i8> @add_non_splat_vector(<2 x i8> %x) { define <2 x i8> @or_splat_vector(<2 x i8> %x) { ; CHECK-LABEL: define <2 x i8> @or_splat_vector( ; CHECK-SAME: <2 x i8> [[X:%.*]]) { -; CHECK-NEXT: [[ADD:%.*]] = or <2 x i8> [[X]], splat (i8 1) -; CHECK-NEXT: [[CMP_INV:%.*]] = icmp slt <2 x i8> [[X]], splat (i8 1) -; CHECK-NEXT: [[S:%.*]] = select <2 x i1> [[CMP_INV]], <2 x i8> splat (i8 1), <2 x i8> [[ADD]] +; CHECK-NEXT: [[TMP1:%.*]] = call <2 x i8> @llvm.smax.v2i8(<2 x i8> [[X]], <2 x i8> splat (i8 1)) +; CHECK-NEXT: [[S:%.*]] = or <2 x i8> [[TMP1]], splat (i8 1) ; CHECK-NEXT: ret <2 x i8> [[S]] ; %add = or <2 x i8> %x, diff --git a/llvm/test/Transforms/InstCombine/minmax-fold.ll b/llvm/test/Transforms/InstCombine/minmax-fold.ll index ccdf4400b16b54..2e267958d0476e 100644 --- a/llvm/test/Transforms/InstCombine/minmax-fold.ll +++ b/llvm/test/Transforms/InstCombine/minmax-fold.ll @@ -1358,11 +1358,10 @@ define i8 @PR14613_smax(i8 %x) { define i8 @PR46271(<2 x i8> %x) { ; CHECK-LABEL: @PR46271( -; CHECK-NEXT: [[TMP1:%.*]] = xor <2 x i8> [[X:%.*]], -; CHECK-NEXT: [[A_INV:%.*]] = icmp slt <2 x i8> [[X]], zeroinitializer -; CHECK-NEXT: [[NOT:%.*]] = select <2 x i1> [[A_INV]], <2 x i8> , <2 x i8> [[TMP1]] +; CHECK-NEXT: [[NOT:%.*]] = call <2 x i8> @llvm.smax.v2i8(<2 x i8> [[X:%.*]], <2 x i8> splat (i8 -1)) ; CHECK-NEXT: [[R:%.*]] = extractelement <2 x i8> [[NOT]], i64 1 -; CHECK-NEXT: ret i8 [[R]] +; CHECK-NEXT: [[R1:%.*]] = xor i8 [[R]], -1 +; CHECK-NEXT: ret i8 [[R1]] ; %a = icmp sgt <2 x i8> %x, %b = select <2 x i1> %a, <2 x i8> %x, <2 x i8> diff --git a/llvm/test/Transforms/InstCombine/saturating-add-sub.ll b/llvm/test/Transforms/InstCombine/saturating-add-sub.ll index 9236d96f59a55b..e050ca762dad46 100644 --- a/llvm/test/Transforms/InstCombine/saturating-add-sub.ll +++ b/llvm/test/Transforms/InstCombine/saturating-add-sub.ll @@ -1793,10 +1793,9 @@ define i32 @not_uadd_sat(i32 %x, i32 %y) { define i32 @not_uadd_sat2(i32 %x, i32 %y) { ; CHECK-LABEL: @not_uadd_sat2( -; CHECK-NEXT: [[A:%.*]] = add i32 [[X:%.*]], -2 -; CHECK-NEXT: [[C:%.*]] = icmp ugt i32 [[X]], 1 -; CHECK-NEXT: [[R:%.*]] = select i1 [[C]], i32 [[A]], i32 -1 -; CHECK-NEXT: ret i32 [[R]] +; CHECK-NEXT: [[X:%.*]] = call i32 @llvm.umax.i32(i32 [[X1:%.*]], i32 1) +; CHECK-NEXT: [[A:%.*]] = add i32 [[X]], -2 +; CHECK-NEXT: ret i32 [[A]] ; %a = add i32 %x, -2 %c = icmp ugt i32 %x, 1 diff --git a/llvm/test/Transforms/InstCombine/select.ll b/llvm/test/Transforms/InstCombine/select.ll index a3221d7388b8fa..82c079d681284d 100644 --- a/llvm/test/Transforms/InstCombine/select.ll +++ b/llvm/test/Transforms/InstCombine/select.ll @@ -2989,10 +2989,9 @@ define i8 @select_replacement_loop3(i32 noundef %x) { define i16 @select_replacement_loop4(i16 noundef %p_12) { ; CHECK-LABEL: @select_replacement_loop4( -; CHECK-NEXT: [[AND1:%.*]] = and i16 [[P_12:%.*]], 1 -; CHECK-NEXT: [[CMP21:%.*]] = icmp ult i16 [[P_12]], 2 -; CHECK-NEXT: [[AND3:%.*]] = select i1 [[CMP21]], i16 [[AND1]], i16 0 -; CHECK-NEXT: ret i16 [[AND3]] +; CHECK-NEXT: [[P_12:%.*]] = call i16 @llvm.umin.i16(i16 [[P_13:%.*]], i16 2) +; CHECK-NEXT: [[AND1:%.*]] = and i16 [[P_12]], 1 +; CHECK-NEXT: ret i16 [[AND1]] ; %cmp1 = icmp ult i16 %p_12, 2 %and1 = and i16 %p_12, 1 diff --git a/llvm/test/Transforms/InstCombine/unsigned_saturated_sub.ll b/llvm/test/Transforms/InstCombine/unsigned_saturated_sub.ll index 1509a42872922a..15fe84369d3a0a 100644 --- a/llvm/test/Transforms/InstCombine/unsigned_saturated_sub.ll +++ b/llvm/test/Transforms/InstCombine/unsigned_saturated_sub.ll @@ -376,10 +376,9 @@ define i32 @max_sub_ugt_c10(i32 %a) { define i32 @max_sub_ugt_c910(i32 %a) { ; CHECK-LABEL: @max_sub_ugt_c910( -; CHECK-NEXT: [[CMP:%.*]] = icmp ugt i32 [[A:%.*]], 9 +; CHECK-NEXT: [[A:%.*]] = call i32 @llvm.umax.i32(i32 [[A1:%.*]], i32 10) ; CHECK-NEXT: [[SUB:%.*]] = add i32 [[A]], -10 -; CHECK-NEXT: [[SEL:%.*]] = select i1 [[CMP]], i32 [[SUB]], i32 0 -; CHECK-NEXT: ret i32 [[SEL]] +; CHECK-NEXT: ret i32 [[SUB]] ; %cmp = icmp ugt i32 %a, 9 %sub = add i32 %a, -10 @@ -412,10 +411,9 @@ define i32 @max_sub_ugt_c0(i32 %a) { define i32 @max_sub_ugt_cmiss(i32 %a) { ; CHECK-LABEL: @max_sub_ugt_cmiss( -; CHECK-NEXT: [[CMP:%.*]] = icmp ugt i32 [[A:%.*]], 1 +; CHECK-NEXT: [[A:%.*]] = call i32 @llvm.umax.i32(i32 [[A1:%.*]], i32 2) ; CHECK-NEXT: [[SUB:%.*]] = add i32 [[A]], -2 -; CHECK-NEXT: [[SEL:%.*]] = select i1 [[CMP]], i32 [[SUB]], i32 0 -; CHECK-NEXT: ret i32 [[SEL]] +; CHECK-NEXT: ret i32 [[SUB]] ; %cmp = icmp ugt i32 %a, 1 %sub = add i32 %a, -2 @@ -479,9 +477,8 @@ define i32 @max_sub_ult_c2_oneusesub(i32 %a) { define i32 @max_sub_ult_c32(i32 %a) { ; CHECK-LABEL: @max_sub_ult_c32( -; CHECK-NEXT: [[CMP:%.*]] = icmp ult i32 [[A:%.*]], 3 -; CHECK-NEXT: [[SUB:%.*]] = add i32 [[A]], -2 -; CHECK-NEXT: [[SEL:%.*]] = select i1 [[CMP]], i32 [[SUB]], i32 0 +; CHECK-NEXT: [[TMP1:%.*]] = call i32 @llvm.umin.i32(i32 [[A:%.*]], i32 2) +; CHECK-NEXT: [[SEL:%.*]] = add nsw i32 [[TMP1]], -2 ; CHECK-NEXT: ret i32 [[SEL]] ; %cmp = icmp ult i32 %a, 3 @@ -492,9 +489,8 @@ define i32 @max_sub_ult_c32(i32 %a) { define i32 @max_sub_ugt_c32(i32 %a) { ; CHECK-LABEL: @max_sub_ugt_c32( -; CHECK-NEXT: [[CMP:%.*]] = icmp ult i32 [[A:%.*]], 3 -; CHECK-NEXT: [[SUB:%.*]] = add i32 [[A]], -2 -; CHECK-NEXT: [[SEL:%.*]] = select i1 [[CMP]], i32 [[SUB]], i32 0 +; CHECK-NEXT: [[TMP1:%.*]] = call i32 @llvm.umin.i32(i32 [[A:%.*]], i32 2) +; CHECK-NEXT: [[SEL:%.*]] = add nsw i32 [[TMP1]], -2 ; CHECK-NEXT: ret i32 [[SEL]] ; %cmp = icmp ugt i32 3, %a @@ -505,9 +501,8 @@ define i32 @max_sub_ugt_c32(i32 %a) { define i32 @max_sub_uge_c32(i32 %a) { ; CHECK-LABEL: @max_sub_uge_c32( -; CHECK-NEXT: [[CMP:%.*]] = icmp ult i32 [[A:%.*]], 3 -; CHECK-NEXT: [[SUB:%.*]] = add i32 [[A]], -2 -; CHECK-NEXT: [[SEL:%.*]] = select i1 [[CMP]], i32 [[SUB]], i32 0 +; CHECK-NEXT: [[TMP1:%.*]] = call i32 @llvm.umin.i32(i32 [[A:%.*]], i32 2) +; CHECK-NEXT: [[SEL:%.*]] = add nsw i32 [[TMP1]], -2 ; CHECK-NEXT: ret i32 [[SEL]] ; %cmp = icmp uge i32 2, %a