Skip to content

Commit

Permalink
Fold Select with a Const Operand to BinOp
Browse files Browse the repository at this point in the history
  • Loading branch information
veera-sivarajan committed Nov 23, 2024
1 parent 4fe3c73 commit 9e08cac
Show file tree
Hide file tree
Showing 7 changed files with 123 additions and 91 deletions.
44 changes: 18 additions & 26 deletions clang/test/CodeGen/attr-counted-by.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
//
Expand All @@ -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]]
Expand Down Expand Up @@ -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
//
Expand All @@ -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]]
Expand Down Expand Up @@ -588,19 +584,17 @@ 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(
// NO-SANITIZE-WITH-ATTR-SAME: ptr nocapture noundef readonly [[P:%.*]]) local_unnamed_addr #[[ATTR2]] {
// 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(
Expand Down Expand Up @@ -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
//
Expand All @@ -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]]
Expand Down
4 changes: 4 additions & 0 deletions llvm/include/llvm/Analysis/ValueTracking.h
Original file line number Diff line number Diff line change
Expand Up @@ -1182,6 +1182,10 @@ SelectPatternResult matchDecomposedSelectPattern(
/// minimum/maximum flavor.
CmpInst::Predicate getMinMaxPred(SelectPatternFlavor SPF, bool Ordered = false);

/// Convert given `SPF` to equivalent min/max intrinsic.
/// Caller must ensure `SPF` is a 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);
Expand Down
15 changes: 15 additions & 0 deletions llvm/lib/Analysis/ValueTracking.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8960,6 +8960,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;
Expand Down
70 changes: 53 additions & 17 deletions llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}

Expand Down Expand Up @@ -1898,6 +1882,55 @@ static Instruction *foldSelectICmpEq(SelectInst &SI, ICmpInst *ICI,
return nullptr;
}

// Turn select (Cmp X C1) (BOp X C2) C3
// -> BOp (min/max X C1) C2
// iff C3 == BOp C1 C2
// Fold `select` with a const operand to a binary operation.
// This allows for better canonicalization.
static Value *foldSelectWithConstOpToBinOp(ICmpInst *Cmp, Value *TrueVal,
Value *FalseVal,
IRBuilderBase &Builder) {
BinaryOperator *BOp;
Constant *C1, *C2, *C3;
Value *X, *NewTrue, *NewFalse;
ICmpInst::Predicate Predicate;

if (!match(Cmp, m_ICmp(Predicate, m_Value(X), m_Constant(C1))))
return nullptr;

if (match(TrueVal, m_Constant())) {
std::swap(FalseVal, TrueVal);
NewTrue = C1;
NewFalse = X;
} else {
NewTrue = X;
NewFalse = C1;
}

if (!match(TrueVal, m_BinOp(BOp)) || !match(FalseVal, m_Constant(C3)))
return nullptr;

if (!match(BOp, m_OneUse(m_c_BinOp(m_Specific(X), m_Constant(C2)))))
return nullptr;

// `select (Cmp X C1) (sub C2 X) (sub C1 C2)` cannot be transformed
// into something like `sub (select (Cmp X C1) X C1) C2`
if (!BOp->isCommutative() && BOp->getOperand(0) != X)
return nullptr;

if (!ICmpInst::isRelational(Predicate) ||
C3 != ConstantFoldBinaryOpOperands(BOp->getOpcode(), C1, C2,
BOp->getDataLayout()))
return nullptr;

Value *LHS, *RHS;
SelectPatternFlavor SPF =
matchDecomposedSelectPattern(Cmp, NewTrue, NewFalse, LHS, RHS).Flavor;
Intrinsic::ID IntrinsicID = getMinMaxIntrinsic(SPF);
Value *Intrinsic = Builder.CreateBinaryIntrinsic(IntrinsicID, LHS, 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) {
Expand Down Expand Up @@ -1987,6 +2020,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;
}

Expand Down
67 changes: 27 additions & 40 deletions llvm/test/Transforms/InstCombine/canonicalize-const-to-bop.ll
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
Expand All @@ -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
Expand All @@ -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
Expand All @@ -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
Expand All @@ -74,9 +69,8 @@ define i8 @mul_and_ult(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
Expand All @@ -88,9 +82,8 @@ define i8 @mul_ult_noflags(i8 %x) {
define i8 @udiv_and_slt(i8 %x) {
; CHECK-LABEL: define i8 @udiv_and_slt(
; CHECK-SAME: i8 [[X:%.*]]) {
; CHECK-NEXT: [[SUB:%.*]] = udiv i8 [[X]], 10
; CHECK-NEXT: [[CMP:%.*]] = icmp slt i8 [[X]], 100
; CHECK-NEXT: [[S:%.*]] = select i1 [[CMP]], i8 10, i8 [[SUB]]
; CHECK-NEXT: [[TMP1:%.*]] = call i8 @llvm.smax.i8(i8 [[X]], i8 100)
; CHECK-NEXT: [[S:%.*]] = udiv i8 [[TMP1]], 10
; CHECK-NEXT: ret i8 [[S]]
;
%sub = udiv i8 %x, 10
Expand All @@ -102,9 +95,8 @@ define i8 @udiv_and_slt(i8 %x) {
define i8 @udiv_slt_exact(i8 %x) {
; CHECK-LABEL: define i8 @udiv_slt_exact(
; CHECK-SAME: i8 [[X:%.*]]) {
; CHECK-NEXT: [[SUB:%.*]] = udiv exact i8 [[X]], 10
; CHECK-NEXT: [[CMP:%.*]] = icmp slt i8 [[X]], 100
; CHECK-NEXT: [[S:%.*]] = select i1 [[CMP]], i8 10, i8 [[SUB]]
; CHECK-NEXT: [[TMP1:%.*]] = call i8 @llvm.smax.i8(i8 [[X]], i8 100)
; CHECK-NEXT: [[S:%.*]] = udiv i8 [[TMP1]], 10
; CHECK-NEXT: ret i8 [[S]]
;
%sub = udiv exact i8 %x, 10
Expand All @@ -116,9 +108,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
Expand All @@ -133,10 +124,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]]
;
Expand All @@ -155,11 +146,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
;
Expand All @@ -182,9 +171,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]], <i8 1, i8 0>
; CHECK-NEXT: [[CMP:%.*]] = icmp sgt <2 x i8> [[X]], <i8 0, i8 1>
; 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> <i8 0, i8 1>)
; CHECK-NEXT: [[S:%.*]] = add nuw <2 x i8> [[TMP1]], <i8 1, i8 0>
; CHECK-NEXT: ret <2 x i8> [[S]]
;
%add = add <2 x i8> %x, <i8 1, i8 0>
Expand All @@ -196,9 +184,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, <i8 1, i8 1>
Expand Down
Loading

0 comments on commit 9e08cac

Please sign in to comment.