From 8db90725cb4c256641492145ada42369c702f714 Mon Sep 17 00:00:00 2001 From: Evan Cheng Date: Tue, 14 Oct 2008 17:15:11 +0000 Subject: [PATCH] Optimize anding of two fcmp into a single fcmp if the operands are the same. e.g. uno && ueq -> ueq ord && olt -> olt ord && ueq -> oeq git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@57507 91177308-0d34-0410-b5e6-96231b3b80d8 --- .../Scalar/InstructionCombining.cpp | 114 +++++++++++++++++- test/Transforms/InstCombine/and-fcmp.ll | 26 ++++ 2 files changed, 137 insertions(+), 3 deletions(-) create mode 100644 test/Transforms/InstCombine/and-fcmp.ll diff --git a/lib/Transforms/Scalar/InstructionCombining.cpp b/lib/Transforms/Scalar/InstructionCombining.cpp index b85f77dab15..391e61e0748 100644 --- a/lib/Transforms/Scalar/InstructionCombining.cpp +++ b/lib/Transforms/Scalar/InstructionCombining.cpp @@ -3116,10 +3116,35 @@ static unsigned getICmpCode(const ICmpInst *ICI) { } } +/// getFCmpCode - Similar to getICmpCode but for FCmpInst. This encodes a fcmp +/// predicate into a three bit mask. It also returns whether it is an ordered +/// predicate by reference. +static unsigned getFCmpCode(FCmpInst::Predicate CC, bool &isOrdered) { + isOrdered = false; + switch (CC) { + case FCmpInst::FCMP_ORD: isOrdered = true; return 0; // 000 + case FCmpInst::FCMP_UNO: return 0; // 000 + case FCmpInst::FCMP_OEQ: isOrdered = true; return 1; // 001 + case FCmpInst::FCMP_UEQ: return 1; // 001 + case FCmpInst::FCMP_OGT: isOrdered = true; return 2; // 010 + case FCmpInst::FCMP_UGT: return 2; // 010 + case FCmpInst::FCMP_OGE: isOrdered = true; return 3; // 011 + case FCmpInst::FCMP_UGE: return 3; // 011 + case FCmpInst::FCMP_OLT: isOrdered = true; return 4; // 100 + case FCmpInst::FCMP_ULT: return 4; // 100 + case FCmpInst::FCMP_OLE: isOrdered = true; return 6; // 110 + case FCmpInst::FCMP_ULE: return 6; // 110 + default: + // Not expecting FCMP_FALSE and FCMP_TRUE; + assert(0 && "Unexpected FCmp predicate!"); + return 0; + } +} + /// getICmpValue - This is the complement of getICmpCode, which turns an /// opcode and two operands into either a constant true or false, or a brand /// new ICmp instruction. The sign is passed in to determine which kind -/// of predicate to use in new icmp instructions. +/// of predicate to use in the new icmp instruction. static Value *getICmpValue(bool sign, unsigned code, Value *LHS, Value *RHS) { switch (code) { default: assert(0 && "Illegal ICmp code!"); @@ -3150,6 +3175,47 @@ static Value *getICmpValue(bool sign, unsigned code, Value *LHS, Value *RHS) { } } +/// getFCmpValue - This is the complement of getFCmpCode, which turns an +/// opcode and two operands into either a FCmp instruction. isordered is passed +/// in to determine which kind of predicate to use in the new fcmp instruction. +static Value *getFCmpValue(bool isordered, unsigned code, + Value *LHS, Value *RHS) { + switch (code) { + default: assert(0 && "Illegal ICmp code!"); + case 0: + if (isordered) + return new FCmpInst(FCmpInst::FCMP_ORD, LHS, RHS); + else + return new FCmpInst(FCmpInst::FCMP_UNO, LHS, RHS); + case 1: + if (isordered) + return new FCmpInst(FCmpInst::FCMP_OEQ, LHS, RHS); + else + return new FCmpInst(FCmpInst::FCMP_UEQ, LHS, RHS); + case 2: + if (isordered) + return new FCmpInst(FCmpInst::FCMP_OGT, LHS, RHS); + else + return new FCmpInst(FCmpInst::FCMP_UGT, LHS, RHS); + case 3: + if (isordered) + return new FCmpInst(FCmpInst::FCMP_OGE, LHS, RHS); + else + return new FCmpInst(FCmpInst::FCMP_UGE, LHS, RHS); + case 4: + if (isordered) + return new FCmpInst(FCmpInst::FCMP_OLT, LHS, RHS); + else + return new FCmpInst(FCmpInst::FCMP_ULT, LHS, RHS); + case 5: + if (isordered) + return new FCmpInst(FCmpInst::FCMP_OLE, LHS, RHS); + else + return new FCmpInst(FCmpInst::FCMP_ULE, LHS, RHS); + } +} + + static bool PredicatesFoldable(ICmpInst::Predicate p1, ICmpInst::Predicate p2) { return (ICmpInst::isSignedPredicate(p1) == ICmpInst::isSignedPredicate(p2)) || (ICmpInst::isSignedPredicate(p1) && @@ -3887,11 +3953,12 @@ Instruction *InstCombiner::visitAnd(BinaryOperator &I) { } } - // (fcmp ord x, c) & (fcmp ord y, c) -> (fcmp ord x, y) + // If and'ing two fcmp, try combine them into one. if (FCmpInst *LHS = dyn_cast(I.getOperand(0))) { if (FCmpInst *RHS = dyn_cast(I.getOperand(1))) { if (LHS->getPredicate() == FCmpInst::FCMP_ORD && - RHS->getPredicate() == FCmpInst::FCMP_ORD) + RHS->getPredicate() == FCmpInst::FCMP_ORD) { + // (fcmp ord x, c) & (fcmp ord y, c) -> (fcmp ord x, y) if (ConstantFP *LHSC = dyn_cast(LHS->getOperand(1))) if (ConstantFP *RHSC = dyn_cast(RHS->getOperand(1))) { // If either of the constants are nans, then the whole thing returns @@ -3901,6 +3968,47 @@ Instruction *InstCombiner::visitAnd(BinaryOperator &I) { return new FCmpInst(FCmpInst::FCMP_ORD, LHS->getOperand(0), RHS->getOperand(0)); } + } else { + Value *Op0LHS, *Op0RHS, *Op1LHS, *Op1RHS; + FCmpInst::Predicate Op0CC, Op1CC; + if (match(Op0, m_FCmp(Op0CC, m_Value(Op0LHS), m_Value(Op0RHS))) && + match(Op1, m_FCmp(Op1CC, m_Value(Op1LHS), m_Value(Op1RHS)))) { + if (Op0LHS == Op1LHS && Op0RHS == Op1RHS) { + // Simplify (fcmp cc0 x, y) & (fcmp cc1 x, y). + if (Op0CC == Op1CC) + return new FCmpInst((FCmpInst::Predicate)Op0CC, Op0LHS, Op0RHS); + else if (Op0CC == FCmpInst::FCMP_FALSE || + Op1CC == FCmpInst::FCMP_FALSE) + return ReplaceInstUsesWith(I, ConstantInt::getFalse()); + else if (Op0CC == FCmpInst::FCMP_TRUE) + return ReplaceInstUsesWith(I, Op1); + else if (Op1CC == FCmpInst::FCMP_TRUE) + return ReplaceInstUsesWith(I, Op0); + bool Op0Ordered; + bool Op1Ordered; + unsigned Op0Pred = getFCmpCode(Op0CC, Op0Ordered); + unsigned Op1Pred = getFCmpCode(Op1CC, Op1Ordered); + if (Op1Pred == 0) { + std::swap(Op0, Op1); + std::swap(Op0Pred, Op1Pred); + std::swap(Op0Ordered, Op1Ordered); + } + if (Op0Pred == 0) { + // uno && ueq -> uno && (uno || eq) -> ueq + // ord && olt -> ord && (ord && lt) -> olt + if (Op0Ordered == Op1Ordered) + return ReplaceInstUsesWith(I, Op1); + // uno && oeq -> uno && (ord && eq) -> false + // uno && ord -> false + if (!Op0Ordered) + return ReplaceInstUsesWith(I, ConstantInt::getFalse()); + // ord && ueq -> ord && (uno || eq) -> oeq + return cast(getFCmpValue(true, Op1Pred, + Op0LHS, Op0RHS)); + } + } + } + } } } diff --git a/test/Transforms/InstCombine/and-fcmp.ll b/test/Transforms/InstCombine/and-fcmp.ll new file mode 100644 index 00000000000..9eecc219831 --- /dev/null +++ b/test/Transforms/InstCombine/and-fcmp.ll @@ -0,0 +1,26 @@ +; RUN: llvm-as < %s | opt -instcombine | llvm-dis | grep fcmp | count 2 +; RUN: llvm-as < %s | opt -instcombine | llvm-dis | grep ret | grep 0 + +define zeroext i8 @t1(float %x, float %y) nounwind { + %a = fcmp ueq float %x, %y + %b = fcmp ord float %x, %y + %c = and i1 %a, %b + %retval = zext i1 %c to i8 + ret i8 %retval +} + +define zeroext i8 @t2(float %x, float %y) nounwind { + %a = fcmp olt float %x, %y + %b = fcmp ord float %x, %y + %c = and i1 %a, %b + %retval = zext i1 %c to i8 + ret i8 %retval +} + +define zeroext i8 @t3(float %x, float %y) nounwind { + %a = fcmp oge float %x, %y + %b = fcmp uno float %x, %y + %c = and i1 %a, %b + %retval = zext i1 %c to i8 + ret i8 %retval +}