Bug 21610: Canonicalize min/max fcmp selects to use ordered comparisons

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@222705 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Matt Arsenault 2014-11-24 23:15:18 +00:00
parent 3ff3cb7fe3
commit 2543acd169
3 changed files with 163 additions and 9 deletions

View File

@ -928,8 +928,22 @@ Instruction *InstCombiner::visitSelectInst(SelectInst &SI) {
!CFPf->getValueAPF().isZero())) !CFPf->getValueAPF().isZero()))
return ReplaceInstUsesWith(SI, TrueVal); return ReplaceInstUsesWith(SI, TrueVal);
} }
// NOTE: if we wanted to, this is where to detect MIN/MAX
// Canonicalize to use ordered comparisons by swapping the select
// operands.
//
// e.g.
// (X ugt Y) ? X : Y -> (X ole Y) ? Y : X
if (FCI->hasOneUse() && FCmpInst::isUnordered(FCI->getPredicate())) {
FCmpInst::Predicate InvPred = FCI->getInversePredicate();
Value *NewCond = Builder->CreateFCmp(InvPred, TrueVal, FalseVal,
FCI->getName() + ".inv");
return SelectInst::Create(NewCond, FalseVal, TrueVal,
SI.getName() + ".p");
}
// NOTE: if we wanted to, this is where to detect MIN/MAX
} else if (FCI->getOperand(0) == FalseVal && FCI->getOperand(1) == TrueVal){ } else if (FCI->getOperand(0) == FalseVal && FCI->getOperand(1) == TrueVal){
// Transform (X == Y) ? Y : X -> X // Transform (X == Y) ? Y : X -> X
if (FCI->getPredicate() == FCmpInst::FCMP_OEQ) { if (FCI->getPredicate() == FCmpInst::FCMP_OEQ) {
@ -955,6 +969,21 @@ Instruction *InstCombiner::visitSelectInst(SelectInst &SI) {
!CFPf->getValueAPF().isZero())) !CFPf->getValueAPF().isZero()))
return ReplaceInstUsesWith(SI, TrueVal); return ReplaceInstUsesWith(SI, TrueVal);
} }
// Canonicalize to use ordered comparisons by swapping the select
// operands.
//
// e.g.
// (X ugt Y) ? X : Y -> (X ole Y) ? X : Y
if (FCI->hasOneUse() && FCmpInst::isUnordered(FCI->getPredicate())) {
FCmpInst::Predicate InvPred = FCI->getInversePredicate();
Value *NewCond = Builder->CreateFCmp(InvPred, FalseVal, TrueVal,
FCI->getName() + ".inv");
return SelectInst::Create(NewCond, FalseVal, TrueVal,
SI.getName() + ".p");
}
// NOTE: if we wanted to, this is where to detect MIN/MAX // NOTE: if we wanted to, this is where to detect MIN/MAX
} }
// NOTE: if we wanted to, this is where to detect ABS // NOTE: if we wanted to, this is where to detect ABS

View File

@ -0,0 +1,125 @@
; RUN: opt -S -instcombine < %s | FileCheck %s
; CHECK-LABEL: @select_max_ugt(
; CHECK: %cmp.inv = fcmp ole float %a, %b
; CHECK-NEXT: %sel = select i1 %cmp.inv, float %b, float %a
; CHECK-NEXT: ret float %sel
define float @select_max_ugt(float %a, float %b) {
%cmp = fcmp ugt float %a, %b
%sel = select i1 %cmp, float %a, float %b
ret float %sel
}
; CHECK-LABEL: @select_max_uge(
; CHECK: %cmp.inv = fcmp olt float %a, %b
; CHECK-NEXT: %sel = select i1 %cmp.inv, float %b, float %a
; CHECK-NEXT: ret float %sel
define float @select_max_uge(float %a, float %b) {
%cmp = fcmp uge float %a, %b
%sel = select i1 %cmp, float %a, float %b
ret float %sel
}
; CHECK-LABEL: @select_min_ugt(
; CHECK: %cmp.inv = fcmp ole float %a, %b
; CHECK-NEXT: %sel = select i1 %cmp.inv, float %a, float %b
; CHECK-NEXT: ret float %sel
define float @select_min_ugt(float %a, float %b) {
%cmp = fcmp ugt float %a, %b
%sel = select i1 %cmp, float %b, float %a
ret float %sel
}
; CHECK-LABEL: @select_min_uge(
; CHECK: %cmp.inv = fcmp olt float %a, %b
; CHECK-NEXT: %sel = select i1 %cmp.inv, float %a, float %b
; CHECK-NEXT: ret float %sel
define float @select_min_uge(float %a, float %b) {
%cmp = fcmp uge float %a, %b
%sel = select i1 %cmp, float %b, float %a
ret float %sel
}
; CHECK-LABEL: @select_max_ult(
; CHECK: %cmp.inv = fcmp oge float %a, %b
; CHECK-NEXT: %sel = select i1 %cmp.inv, float %a, float %b
; CHECK-NEXT: ret float %sel
define float @select_max_ult(float %a, float %b) {
%cmp = fcmp ult float %a, %b
%sel = select i1 %cmp, float %b, float %a
ret float %sel
}
; CHECK-LABEL: @select_max_ule(
; CHECK: %cmp.inv = fcmp ogt float %a, %b
; CHECK-NEXT: %sel = select i1 %cmp.inv, float %a, float %b
; CHECK: ret float %sel
define float @select_max_ule(float %a, float %b) {
%cmp = fcmp ule float %a, %b
%sel = select i1 %cmp, float %b, float %a
ret float %sel
}
; CHECK-LABEL: @select_min_ult(
; CHECK: %cmp.inv = fcmp oge float %a, %b
; CHECK-NEXT: %sel = select i1 %cmp.inv, float %b, float %a
; CHECK-NEXT: ret float %sel
define float @select_min_ult(float %a, float %b) {
%cmp = fcmp ult float %a, %b
%sel = select i1 %cmp, float %a, float %b
ret float %sel
}
; CHECK-LABEL: @select_min_ule(
; CHECK: %cmp.inv = fcmp ogt float %a, %b
; CHECK-NEXT: %sel = select i1 %cmp.inv, float %b, float %a
; CHECK-NEXT: ret float %sel
define float @select_min_ule(float %a, float %b) {
%cmp = fcmp ule float %a, %b
%sel = select i1 %cmp, float %a, float %b
ret float %sel
}
; CHECK-LABEL: @select_fcmp_une(
; CHECK: %cmp.inv = fcmp oeq float %a, %b
; CHECK-NEXT: %sel = select i1 %cmp.inv, float %b, float %a
; CHECK-NEXT: ret float %sel
define float @select_fcmp_une(float %a, float %b) {
%cmp = fcmp une float %a, %b
%sel = select i1 %cmp, float %a, float %b
ret float %sel
}
; CHECK-LABEL: @select_fcmp_ueq
; CHECK: %cmp.inv = fcmp one float %a, %b
; CHECK-NEXT: %sel = select i1 %cmp.inv, float %b, float %a
; CHECK-NEXT: ret float %sel
define float @select_fcmp_ueq(float %a, float %b) {
%cmp = fcmp ueq float %a, %b
%sel = select i1 %cmp, float %a, float %b
ret float %sel
}
declare void @foo(i1)
; CHECK-LABEL: @select_max_ugt_2_use_cmp(
; CHECK: fcmp ugt
; CHECK-NOT: fcmp
; CHECK: ret
define float @select_max_ugt_2_use_cmp(float %a, float %b) {
%cmp = fcmp ugt float %a, %b
call void @foo(i1 %cmp)
%sel = select i1 %cmp, float %a, float %b
ret float %sel
}
; CHECK-LABEL: @select_min_uge_2_use_cmp(
; CHECK: fcmp uge
; CHECK-NOT: fcmp
; CHECK: ret
define float @select_min_uge_2_use_cmp(float %a, float %b) {
%cmp = fcmp uge float %a, %b
call void @foo(i1 %cmp)
%sel = select i1 %cmp, float %b, float %a
ret float %sel
}

View File

@ -516,7 +516,7 @@ for.end:
} }
; CHECK-LABEL: @unordered_max_red_float( ; CHECK-LABEL: @unordered_max_red_float(
; CHECK: fcmp ugt <2 x float> ; CHECK: fcmp ole <2 x float>
; CHECK: select <2 x i1> ; CHECK: select <2 x i1>
; CHECK: middle.block ; CHECK: middle.block
; CHECK: fcmp ogt <2 x float> ; CHECK: fcmp ogt <2 x float>
@ -542,7 +542,7 @@ for.end:
} }
; CHECK-LABEL: @unordered_max_red_float_ge( ; CHECK-LABEL: @unordered_max_red_float_ge(
; CHECK: fcmp uge <2 x float> ; CHECK: fcmp olt <2 x float>
; CHECK: select <2 x i1> ; CHECK: select <2 x i1>
; CHECK: middle.block ; CHECK: middle.block
; CHECK: fcmp ogt <2 x float> ; CHECK: fcmp ogt <2 x float>
@ -568,7 +568,7 @@ for.end:
} }
; CHECK-LABEL: @inverted_unordered_max_red_float( ; CHECK-LABEL: @inverted_unordered_max_red_float(
; CHECK: fcmp ult <2 x float> ; CHECK: fcmp oge <2 x float>
; CHECK: select <2 x i1> ; CHECK: select <2 x i1>
; CHECK: middle.block ; CHECK: middle.block
; CHECK: fcmp ogt <2 x float> ; CHECK: fcmp ogt <2 x float>
@ -594,7 +594,7 @@ for.end:
} }
; CHECK-LABEL: @inverted_unordered_max_red_float_le( ; CHECK-LABEL: @inverted_unordered_max_red_float_le(
; CHECK: fcmp ule <2 x float> ; CHECK: fcmp ogt <2 x float>
; CHECK: select <2 x i1> ; CHECK: select <2 x i1>
; CHECK: middle.block ; CHECK: middle.block
; CHECK: fcmp ogt <2 x float> ; CHECK: fcmp ogt <2 x float>
@ -727,7 +727,7 @@ for.end:
} }
; CHECK-LABEL: @unordered_min_red_float( ; CHECK-LABEL: @unordered_min_red_float(
; CHECK: fcmp ult <2 x float> ; CHECK: fcmp oge <2 x float>
; CHECK: select <2 x i1> ; CHECK: select <2 x i1>
; CHECK: middle.block ; CHECK: middle.block
; CHECK: fcmp olt <2 x float> ; CHECK: fcmp olt <2 x float>
@ -753,7 +753,7 @@ for.end:
} }
; CHECK-LABEL: @unordered_min_red_float_le( ; CHECK-LABEL: @unordered_min_red_float_le(
; CHECK: fcmp ule <2 x float> ; CHECK: fcmp ogt <2 x float>
; CHECK: select <2 x i1> ; CHECK: select <2 x i1>
; CHECK: middle.block ; CHECK: middle.block
; CHECK: fcmp olt <2 x float> ; CHECK: fcmp olt <2 x float>
@ -779,7 +779,7 @@ for.end:
} }
; CHECK-LABEL: @inverted_unordered_min_red_float( ; CHECK-LABEL: @inverted_unordered_min_red_float(
; CHECK: fcmp ugt <2 x float> ; CHECK: fcmp ole <2 x float>
; CHECK: select <2 x i1> ; CHECK: select <2 x i1>
; CHECK: middle.block ; CHECK: middle.block
; CHECK: fcmp olt <2 x float> ; CHECK: fcmp olt <2 x float>
@ -805,7 +805,7 @@ for.end:
} }
; CHECK-LABEL: @inverted_unordered_min_red_float_ge( ; CHECK-LABEL: @inverted_unordered_min_red_float_ge(
; CHECK: fcmp uge <2 x float> ; CHECK: fcmp olt <2 x float>
; CHECK: select <2 x i1> ; CHECK: select <2 x i1>
; CHECK: middle.block ; CHECK: middle.block
; CHECK: fcmp olt <2 x float> ; CHECK: fcmp olt <2 x float>