summaryrefslogtreecommitdiff
path: root/llvm/lib
diff options
context:
space:
mode:
authorSanjay Patel <spatel@rotateright.com>2021-03-28 12:23:57 -0400
committerSanjay Patel <spatel@rotateright.com>2021-03-28 13:13:04 -0400
commit01ae6e5ead64c033134a1ee68fb0bf6ec93b4c40 (patch)
treead3d57b6ade002e114498386c3f22a57dc20e4ef /llvm/lib
parent4f349739ef696fd6b633550ea94adffcbcf7994f (diff)
[InstCombine] sink min/max intrinsics with common op after select
This is another step towards parity with cmp+select min/max idioms. See D98152.
Diffstat (limited to 'llvm/lib')
-rw-r--r--llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp29
1 files changed, 29 insertions, 0 deletions
diff --git a/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp b/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp
index 7d7a52b4de31..a1ec11e95081 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp
@@ -327,6 +327,35 @@ Instruction *InstCombinerImpl::foldSelectOpOp(SelectInst &SI, Instruction *TI,
return UnaryOperator::CreateFNegFMF(NewSel, TI);
}
+ // Min/max intrinsic with a common operand can have the common operand pulled
+ // after the select. This is the same transform as below for binops, but
+ // specialized for intrinsic matching and without the restrictive uses clause.
+ auto *TII = dyn_cast<IntrinsicInst>(TI);
+ auto *FII = dyn_cast<IntrinsicInst>(FI);
+ if (TII && FII && TII->getIntrinsicID() == FII->getIntrinsicID() &&
+ (TII->hasOneUse() || FII->hasOneUse())) {
+ Value *T0, *T1, *F0, *F1;
+ if (match(TII, m_MaxOrMin(m_Value(T0), m_Value(T1))) &&
+ match(FII, m_MaxOrMin(m_Value(F0), m_Value(F1)))) {
+ if (T0 == F0) {
+ Value *NewSel = Builder.CreateSelect(Cond, T1, F1, "minmaxop", &SI);
+ return CallInst::Create(TII->getCalledFunction(), {NewSel, T0});
+ }
+ if (T0 == F1) {
+ Value *NewSel = Builder.CreateSelect(Cond, T1, F0, "minmaxop", &SI);
+ return CallInst::Create(TII->getCalledFunction(), {NewSel, T0});
+ }
+ if (T1 == F0) {
+ Value *NewSel = Builder.CreateSelect(Cond, T0, F1, "minmaxop", &SI);
+ return CallInst::Create(TII->getCalledFunction(), {NewSel, T1});
+ }
+ if (T1 == F1) {
+ Value *NewSel = Builder.CreateSelect(Cond, T0, F0, "minmaxop", &SI);
+ return CallInst::Create(TII->getCalledFunction(), {NewSel, T1});
+ }
+ }
+ }
+
// Only handle binary operators (including two-operand getelementptr) with
// one-use here. As with the cast case above, it may be possible to relax the
// one-use constraint, but that needs be examined carefully since it may not