Index: lib/Transforms/InstCombine/InstCombineCompares.cpp =================================================================== --- lib/Transforms/InstCombine/InstCombineCompares.cpp +++ lib/Transforms/InstCombine/InstCombineCompares.cpp @@ -4997,6 +4997,24 @@ ConstantExpr::getFNeg(RHSC)); break; } + case Instruction::FDiv: { + if (I.getFastMathFlags().noInfs() && + LHSI->getFastMathFlags().noInfs() && RHSC->isZeroValue()) { + Value *Op; + const APFloat *C; + if (match(LHSI, m_FDiv(m_APFloat(C), m_Value(Op)))) { + // fcmp ninf pred (fdiv ninf 1.0, x), 0 -> fcmp pred x, 0 + if (C->isExactlyValue(1.0)) + return new FCmpInst(I.getPredicate(), Op, + ConstantFP::getNullValue(LHSI->getType())); + // fcmp ninf pred (fdiv ninf -1.0, x), 0 -> fcmp swap(pred) x, 0 + if (C->isExactlyValue(-1.0)) + return new FCmpInst(I.getSwappedPredicate(), Op, + ConstantFP::getNullValue(LHSI->getType())); + } + } + break; + } case Instruction::Load: if (GetElementPtrInst *GEP = dyn_cast(LHSI->getOperand(0))) { Index: test/Transforms/InstCombine/fcmp_reciproc.ll =================================================================== --- /dev/null +++ test/Transforms/InstCombine/fcmp_reciproc.ll @@ -0,0 +1,212 @@ +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py +; RUN: opt < %s -instcombine -S | FileCheck %s + +define i1 @cmp_olt_recip(double %x) { +; CHECK-LABEL: @cmp_olt_recip( +; CHECK-NEXT: [[CMP:%.*]] = fcmp olt double [[X:%.*]], 0.000000e+00 +; CHECK-NEXT: ret i1 [[CMP]] +; + %div = fdiv ninf double 1.0, %x + %cmp = fcmp ninf olt double %div, 0.0 + ret i1 %cmp +} + +define i1 @cmp_ole_recip(double %x) { +; CHECK-LABEL: @cmp_ole_recip( +; CHECK-NEXT: [[CMP:%.*]] = fcmp ole double [[X:%.*]], 0.000000e+00 +; CHECK-NEXT: ret i1 [[CMP]] +; + %div = fdiv ninf double 1.0, %x + %cmp = fcmp ninf ole double %div, 0.0 + ret i1 %cmp +} + +define i1 @cmp_ogt_recip(double %x) { +; CHECK-LABEL: @cmp_ogt_recip( +; CHECK-NEXT: [[CMP:%.*]] = fcmp ogt double [[X:%.*]], 0.000000e+00 +; CHECK-NEXT: ret i1 [[CMP]] +; + %div = fdiv ninf double 1.0, %x + %cmp = fcmp ninf ogt double %div, 0.0 + ret i1 %cmp +} + +define i1 @cmp_oge_recip(double %x) { +; CHECK-LABEL: @cmp_oge_recip( +; CHECK-NEXT: [[CMP:%.*]] = fcmp oge double [[X:%.*]], 0.000000e+00 +; CHECK-NEXT: ret i1 [[CMP]] +; + %div = fdiv ninf double 1.0, %x + %cmp = fcmp ninf oge double %div, 0.0 + ret i1 %cmp +} + +define i1 @cmp_oeq_recip(double %x) { +; CHECK-LABEL: @cmp_oeq_recip( +; CHECK-NEXT: [[CMP:%.*]] = fcmp oeq double [[X:%.*]], 0.000000e+00 +; CHECK-NEXT: ret i1 [[CMP]] +; + %div = fdiv ninf double 1.0, %x + %cmp = fcmp ninf oeq double %div, 0.0 + ret i1 %cmp +} + +define i1 @cmp_une_recip(double %x) { +; CHECK-LABEL: @cmp_une_recip( +; CHECK-NEXT: [[CMP:%.*]] = fcmp une double [[X:%.*]], 0.000000e+00 +; CHECK-NEXT: ret i1 [[CMP]] +; + %div = fdiv ninf double 1.0, %x + %cmp = fcmp ninf une double %div, 0.0 + ret i1 %cmp +} + +; Could test all 16 fcmp variants, but they're really all the same... + +define i1 @cmp_olt_neg_recip(double %x) { +; CHECK-LABEL: @cmp_olt_neg_recip( +; CHECK-NEXT: [[CMP:%.*]] = fcmp ogt double [[X:%.*]], 0.000000e+00 +; CHECK-NEXT: ret i1 [[CMP]] +; + %div = fdiv ninf double -1.0, %x + %cmp = fcmp ninf olt double %div, 0.0 + ret i1 %cmp +} + +define i1 @cmp_ole_neg_recip(double %x) { +; CHECK-LABEL: @cmp_ole_neg_recip( +; CHECK-NEXT: [[CMP:%.*]] = fcmp oge double [[X:%.*]], 0.000000e+00 +; CHECK-NEXT: ret i1 [[CMP]] +; + %div = fdiv ninf double -1.0, %x + %cmp = fcmp ninf ole double %div, 0.0 + ret i1 %cmp +} + +define i1 @cmp_ogt_neg_recip(double %x) { +; CHECK-LABEL: @cmp_ogt_neg_recip( +; CHECK-NEXT: [[CMP:%.*]] = fcmp olt double [[X:%.*]], 0.000000e+00 +; CHECK-NEXT: ret i1 [[CMP]] +; + %div = fdiv ninf double -1.0, %x + %cmp = fcmp ninf ogt double %div, 0.0 + ret i1 %cmp +} + +define i1 @cmp_oge_neg_recip(double %x) { +; CHECK-LABEL: @cmp_oge_neg_recip( +; CHECK-NEXT: [[CMP:%.*]] = fcmp ole double [[X:%.*]], 0.000000e+00 +; CHECK-NEXT: ret i1 [[CMP]] +; + %div = fdiv ninf double -1.0, %x + %cmp = fcmp ninf oge double %div, 0.0 + ret i1 %cmp +} + +define i1 @cmp_olt_recip_sz(double %x) { +; CHECK-LABEL: @cmp_olt_recip_sz( +; CHECK-NEXT: [[CMP:%.*]] = fcmp olt double [[X:%.*]], 0.000000e+00 +; CHECK-NEXT: ret i1 [[CMP]] +; + %div = fdiv ninf double 1.0, %x + %cmp = fcmp ninf olt double %div, -0.0 + ret i1 %cmp +} + +define i1 @cmp_ole_recip_sz(double %x) { +; CHECK-LABEL: @cmp_ole_recip_sz( +; CHECK-NEXT: [[CMP:%.*]] = fcmp ole double [[X:%.*]], 0.000000e+00 +; CHECK-NEXT: ret i1 [[CMP]] +; + %div = fdiv ninf double 1.0, %x + %cmp = fcmp ninf ole double %div, -0.0 + ret i1 %cmp +} + +define i1 @cmp_ogt_recip_sz(double %x) { +; CHECK-LABEL: @cmp_ogt_recip_sz( +; CHECK-NEXT: [[CMP:%.*]] = fcmp ogt double [[X:%.*]], 0.000000e+00 +; CHECK-NEXT: ret i1 [[CMP]] +; + %div = fdiv ninf double 1.0, %x + %cmp = fcmp ninf ogt double %div, -0.0 + ret i1 %cmp +} + +define i1 @cmp_oge_recip_sz(double %x) { +; CHECK-LABEL: @cmp_oge_recip_sz( +; CHECK-NEXT: [[CMP:%.*]] = fcmp oge double [[X:%.*]], 0.000000e+00 +; CHECK-NEXT: ret i1 [[CMP]] +; + %div = fdiv ninf double 1.0, %x + %cmp = fcmp ninf oge double %div, -0.0 + ret i1 %cmp +} + + + +define i1 @noopt0(double %x) { +; CHECK-LABEL: @noopt0( +; CHECK-NEXT: [[DIV:%.*]] = fdiv ninf double 1.100000e+00, [[X:%.*]] +; CHECK-NEXT: [[CMP:%.*]] = fcmp ninf oeq double [[DIV]], 0.000000e+00 +; CHECK-NEXT: ret i1 [[CMP]] +; + %div = fdiv ninf double 1.1, %x + %cmp = fcmp ninf oeq double %div, 0.0 + ret i1 %cmp +} + +define i1 @noopt1(double %x) { +; CHECK-LABEL: @noopt1( +; CHECK-NEXT: [[DIV:%.*]] = fdiv ninf double 1.000000e+00, [[X:%.*]] +; CHECK-NEXT: [[CMP:%.*]] = fcmp ninf oeq double [[DIV]], 1.000000e-01 +; CHECK-NEXT: ret i1 [[CMP]] +; + %div = fdiv ninf double 1.0, %x + %cmp = fcmp ninf oeq double %div, 0.1 + ret i1 %cmp +} + +define i1 @noopt2(double %x) { +; CHECK-LABEL: @noopt2( +; CHECK-NEXT: [[DIV:%.*]] = fdiv double 1.000000e+00, [[X:%.*]] +; CHECK-NEXT: [[CMP:%.*]] = fcmp ninf oeq double [[DIV]], 0.000000e+00 +; CHECK-NEXT: ret i1 [[CMP]] +; + %div = fdiv double 1.0, %x + %cmp = fcmp ninf oeq double %div, 0.0 + ret i1 %cmp +} + +define i1 @noopt3(double %x) { +; CHECK-LABEL: @noopt3( +; CHECK-NEXT: [[DIV:%.*]] = fdiv ninf double 1.000000e+00, [[X:%.*]] +; CHECK-NEXT: [[CMP:%.*]] = fcmp oeq double [[DIV]], 0.000000e+00 +; CHECK-NEXT: ret i1 [[CMP]] +; + %div = fdiv ninf double 1.0, %x + %cmp = fcmp oeq double %div, 0.0 + ret i1 %cmp +} + +define i1 @noopt4(double %x) { +; CHECK-LABEL: @noopt4( +; CHECK-NEXT: [[DIV:%.*]] = fdiv ninf double 1.000000e+00, [[X:%.*]] +; CHECK-NEXT: [[CMP:%.*]] = fcmp nnan oeq double [[DIV]], 0.000000e+00 +; CHECK-NEXT: ret i1 [[CMP]] +; + %div = fdiv ninf double 1.0, %x + %cmp = fcmp nnan oeq double %div, 0.0 + ret i1 %cmp +} + +define i1 @noopt5(double %x) { +; CHECK-LABEL: @noopt5( +; CHECK-NEXT: [[DIV:%.*]] = fdiv nnan double 1.000000e+00, [[X:%.*]] +; CHECK-NEXT: [[CMP:%.*]] = fcmp ninf oeq double [[DIV]], 0.000000e+00 +; CHECK-NEXT: ret i1 [[CMP]] +; + %div = fdiv nnan double 1.0, %x + %cmp = fcmp ninf oeq double %div, 0.0 + ret i1 %cmp +}