summaryrefslogtreecommitdiffstats
path: root/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp')
-rw-r--r--llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp42
1 files changed, 42 insertions, 0 deletions
diff --git a/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp b/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp
index 2c6b92ed295..98b92970566 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp
@@ -500,9 +500,51 @@ static bool adjustMinMax(SelectInst &Sel, ICmpInst &Cmp) {
return true;
}
+/// If this is an integer min/max where the select's 'true' operand is a
+/// constant, canonicalize that constant to the 'false' operand:
+/// select (icmp Pred X, C), C, X --> select (icmp Pred' X, C), X, C
+static Instruction *
+canonicalizeMinMaxWithConstant(SelectInst &Sel, ICmpInst &Cmp,
+ InstCombiner::BuilderTy &Builder) {
+ // TODO: We should also canonicalize min/max when the select has a different
+ // constant value than the cmp constant, but we need to fix the backend first.
+ if (!Cmp.hasOneUse() || !isa<Constant>(Cmp.getOperand(1)) ||
+ !isa<Constant>(Sel.getTrueValue()) ||
+ isa<Constant>(Sel.getFalseValue()) ||
+ Cmp.getOperand(1) != Sel.getTrueValue())
+ return nullptr;
+
+ // Canonicalize the compare predicate based on whether we have min or max.
+ Value *LHS, *RHS;
+ ICmpInst::Predicate NewPred;
+ SelectPatternResult SPR = matchSelectPattern(&Sel, LHS, RHS);
+ switch (SPR.Flavor) {
+ case SPF_SMIN: NewPred = ICmpInst::ICMP_SLT; break;
+ case SPF_UMIN: NewPred = ICmpInst::ICMP_ULT; break;
+ case SPF_SMAX: NewPred = ICmpInst::ICMP_SGT; break;
+ case SPF_UMAX: NewPred = ICmpInst::ICMP_UGT; break;
+ default: return nullptr;
+ }
+
+ // Canonicalize the constant to the right side.
+ if (isa<Constant>(LHS))
+ std::swap(LHS, RHS);
+
+ Value *NewCmp = Builder.CreateICmp(NewPred, LHS, RHS);
+ SelectInst *NewSel = SelectInst::Create(NewCmp, LHS, RHS);
+ NewSel->copyMetadata(Sel);
+
+ // We swapped the select operands, so swap the metadata too.
+ NewSel->swapProfMetadata();
+ return NewSel;
+}
+
/// Visit a SelectInst that has an ICmpInst as its first operand.
Instruction *InstCombiner::foldSelectInstWithICmp(SelectInst &SI,
ICmpInst *ICI) {
+ if (Instruction *NewSel = canonicalizeMinMaxWithConstant(SI, *ICI, *Builder))
+ return NewSel;
+
bool Changed = adjustMinMax(SI, *ICI);
ICmpInst::Predicate Pred = ICI->getPredicate();
OpenPOWER on IntegriCloud