From 454e837bd2d8d84710433ce60a6ffab7a8cf518d Mon Sep 17 00:00:00 2001 From: Matt Arsenault Date: Mon, 24 Nov 2014 23:15:18 +0000 Subject: [PATCH] Bug 21610: Canonicalize min/max fcmp selects to use ordered comparisons llvm-svn: 222705 --- .../InstCombine/InstCombineSelect.cpp | 31 ++++- .../InstCombine/unordered-fcmp-select.ll | 125 ++++++++++++++++++ .../LoopVectorize/minmax_reduction.ll | 16 +-- 3 files changed, 163 insertions(+), 9 deletions(-) create mode 100644 test/Transforms/InstCombine/unordered-fcmp-select.ll diff --git a/lib/Transforms/InstCombine/InstCombineSelect.cpp b/lib/Transforms/InstCombine/InstCombineSelect.cpp index 079ae34fbef..2c185264faf 100644 --- a/lib/Transforms/InstCombine/InstCombineSelect.cpp +++ b/lib/Transforms/InstCombine/InstCombineSelect.cpp @@ -928,8 +928,22 @@ Instruction *InstCombiner::visitSelectInst(SelectInst &SI) { !CFPf->getValueAPF().isZero())) 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){ // Transform (X == Y) ? Y : X -> X if (FCI->getPredicate() == FCmpInst::FCMP_OEQ) { @@ -955,6 +969,21 @@ Instruction *InstCombiner::visitSelectInst(SelectInst &SI) { !CFPf->getValueAPF().isZero())) 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 ABS diff --git a/test/Transforms/InstCombine/unordered-fcmp-select.ll b/test/Transforms/InstCombine/unordered-fcmp-select.ll new file mode 100644 index 00000000000..0eb729047e7 --- /dev/null +++ b/test/Transforms/InstCombine/unordered-fcmp-select.ll @@ -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 +} diff --git a/test/Transforms/LoopVectorize/minmax_reduction.ll b/test/Transforms/LoopVectorize/minmax_reduction.ll index e73e69db570..1984cdd892d 100644 --- a/test/Transforms/LoopVectorize/minmax_reduction.ll +++ b/test/Transforms/LoopVectorize/minmax_reduction.ll @@ -516,7 +516,7 @@ for.end: } ; CHECK-LABEL: @unordered_max_red_float( -; CHECK: fcmp ugt <2 x float> +; CHECK: fcmp ole <2 x float> ; CHECK: select <2 x i1> ; CHECK: middle.block ; CHECK: fcmp ogt <2 x float> @@ -542,7 +542,7 @@ for.end: } ; 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: middle.block ; CHECK: fcmp ogt <2 x float> @@ -568,7 +568,7 @@ for.end: } ; 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: middle.block ; CHECK: fcmp ogt <2 x float> @@ -594,7 +594,7 @@ for.end: } ; 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: middle.block ; CHECK: fcmp ogt <2 x float> @@ -727,7 +727,7 @@ for.end: } ; CHECK-LABEL: @unordered_min_red_float( -; CHECK: fcmp ult <2 x float> +; CHECK: fcmp oge <2 x float> ; CHECK: select <2 x i1> ; CHECK: middle.block ; CHECK: fcmp olt <2 x float> @@ -753,7 +753,7 @@ for.end: } ; 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: middle.block ; CHECK: fcmp olt <2 x float> @@ -779,7 +779,7 @@ for.end: } ; 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: middle.block ; CHECK: fcmp olt <2 x float> @@ -805,7 +805,7 @@ for.end: } ; 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: middle.block ; CHECK: fcmp olt <2 x float>