13ca95b02SDimitry Andric //===-- SystemZTDC.cpp - Utilize Test Data Class instruction --------------===//
23ca95b02SDimitry Andric //
33ca95b02SDimitry Andric //                     The LLVM Compiler Infrastructure
43ca95b02SDimitry Andric //
53ca95b02SDimitry Andric // This file is distributed under the University of Illinois Open Source
63ca95b02SDimitry Andric // License. See LICENSE.TXT for details.
73ca95b02SDimitry Andric //
83ca95b02SDimitry Andric //===----------------------------------------------------------------------===//
93ca95b02SDimitry Andric //
103ca95b02SDimitry Andric // This pass looks for instructions that can be replaced by a Test Data Class
113ca95b02SDimitry Andric // instruction, and replaces them when profitable.
123ca95b02SDimitry Andric //
133ca95b02SDimitry Andric // Roughly, the following rules are recognized:
143ca95b02SDimitry Andric //
153ca95b02SDimitry Andric // 1: fcmp pred X, 0 -> tdc X, mask
163ca95b02SDimitry Andric // 2: fcmp pred X, +-inf -> tdc X, mask
173ca95b02SDimitry Andric // 3: fcmp pred X, +-minnorm -> tdc X, mask
183ca95b02SDimitry Andric // 4: tdc (fabs X), mask -> tdc X, newmask
193ca95b02SDimitry Andric // 5: icmp slt (bitcast float X to int), 0 -> tdc X, mask [ie. signbit]
203ca95b02SDimitry Andric // 6: icmp sgt (bitcast float X to int), -1 -> tdc X, mask
213ca95b02SDimitry Andric // 7: icmp ne/eq (call @llvm.s390.tdc.*(X, mask)) -> tdc X, mask/~mask
223ca95b02SDimitry Andric // 8: and i1 (tdc X, M1), (tdc X, M2) -> tdc X, (M1 & M2)
233ca95b02SDimitry Andric // 9: or i1 (tdc X, M1), (tdc X, M2) -> tdc X, (M1 | M2)
243ca95b02SDimitry Andric // 10: xor i1 (tdc X, M1), (tdc X, M2) -> tdc X, (M1 ^ M2)
253ca95b02SDimitry Andric //
263ca95b02SDimitry Andric // The pass works in 4 steps:
273ca95b02SDimitry Andric //
283ca95b02SDimitry Andric // 1. All fcmp and icmp instructions in a function are checked for a match
293ca95b02SDimitry Andric //    with rules 1-3 and 5-7.  Their TDC equivalents are stored in
303ca95b02SDimitry Andric //    the ConvertedInsts mapping.  If the operand of a fcmp instruction is
313ca95b02SDimitry Andric //    a fabs, it's also folded according to rule 4.
323ca95b02SDimitry Andric // 2. All and/or/xor i1 instructions whose both operands have been already
333ca95b02SDimitry Andric //    mapped are mapped according to rules 8-10.  LogicOpsWorklist is used
343ca95b02SDimitry Andric //    as a queue of instructions to check.
353ca95b02SDimitry Andric // 3. All mapped instructions that are considered worthy of conversion (ie.
363ca95b02SDimitry Andric //    replacing them will actually simplify the final code) are replaced
373ca95b02SDimitry Andric //    with a call to the s390.tdc intrinsic.
383ca95b02SDimitry Andric // 4. All intermediate results of replaced instructions are removed if unused.
393ca95b02SDimitry Andric //
403ca95b02SDimitry Andric // Instructions that match rules 1-3 are considered unworthy of conversion
413ca95b02SDimitry Andric // on their own (since a comparison instruction is superior), but are mapped
423ca95b02SDimitry Andric // in the hopes of folding the result using rules 4 and 8-10 (likely removing
433ca95b02SDimitry Andric // the original comparison in the process).
443ca95b02SDimitry Andric //
453ca95b02SDimitry Andric //===----------------------------------------------------------------------===//
463ca95b02SDimitry Andric 
473ca95b02SDimitry Andric #include "SystemZ.h"
483ca95b02SDimitry Andric #include "llvm/ADT/MapVector.h"
493ca95b02SDimitry Andric #include "llvm/IR/Constants.h"
503ca95b02SDimitry Andric #include "llvm/IR/IRBuilder.h"
51*db17bf38SDimitry Andric #include "llvm/IR/InstIterator.h"
52*db17bf38SDimitry Andric #include "llvm/IR/Instructions.h"
53*db17bf38SDimitry Andric #include "llvm/IR/IntrinsicInst.h"
543ca95b02SDimitry Andric #include "llvm/IR/LegacyPassManager.h"
553ca95b02SDimitry Andric #include "llvm/IR/Module.h"
563ca95b02SDimitry Andric #include <deque>
573ca95b02SDimitry Andric #include <set>
583ca95b02SDimitry Andric 
593ca95b02SDimitry Andric using namespace llvm;
603ca95b02SDimitry Andric 
613ca95b02SDimitry Andric namespace llvm {
623ca95b02SDimitry Andric   void initializeSystemZTDCPassPass(PassRegistry&);
633ca95b02SDimitry Andric }
643ca95b02SDimitry Andric 
653ca95b02SDimitry Andric namespace {
663ca95b02SDimitry Andric 
673ca95b02SDimitry Andric class SystemZTDCPass : public FunctionPass {
683ca95b02SDimitry Andric public:
693ca95b02SDimitry Andric   static char ID;
SystemZTDCPass()703ca95b02SDimitry Andric   SystemZTDCPass() : FunctionPass(ID) {
713ca95b02SDimitry Andric     initializeSystemZTDCPassPass(*PassRegistry::getPassRegistry());
723ca95b02SDimitry Andric   }
733ca95b02SDimitry Andric 
743ca95b02SDimitry Andric   bool runOnFunction(Function &F) override;
753ca95b02SDimitry Andric private:
763ca95b02SDimitry Andric   // Maps seen instructions that can be mapped to a TDC, values are
773ca95b02SDimitry Andric   // (TDC operand, TDC mask, worthy flag) triples.
783ca95b02SDimitry Andric   MapVector<Instruction *, std::tuple<Value *, int, bool>> ConvertedInsts;
793ca95b02SDimitry Andric   // The queue of and/or/xor i1 instructions to be potentially folded.
803ca95b02SDimitry Andric   std::vector<BinaryOperator *> LogicOpsWorklist;
813ca95b02SDimitry Andric   // Instructions matched while folding, to be removed at the end if unused.
823ca95b02SDimitry Andric   std::set<Instruction *> PossibleJunk;
833ca95b02SDimitry Andric 
843ca95b02SDimitry Andric   // Tries to convert a fcmp instruction.
853ca95b02SDimitry Andric   void convertFCmp(CmpInst &I);
863ca95b02SDimitry Andric 
873ca95b02SDimitry Andric   // Tries to convert an icmp instruction.
883ca95b02SDimitry Andric   void convertICmp(CmpInst &I);
893ca95b02SDimitry Andric 
903ca95b02SDimitry Andric   // Tries to convert an i1 and/or/xor instruction, whose both operands
913ca95b02SDimitry Andric   // have been already converted.
923ca95b02SDimitry Andric   void convertLogicOp(BinaryOperator &I);
933ca95b02SDimitry Andric 
943ca95b02SDimitry Andric   // Marks an instruction as converted - adds it to ConvertedInsts and adds
953ca95b02SDimitry Andric   // any and/or/xor i1 users to the queue.
converted(Instruction * I,Value * V,int Mask,bool Worthy)963ca95b02SDimitry Andric   void converted(Instruction *I, Value *V, int Mask, bool Worthy) {
973ca95b02SDimitry Andric     ConvertedInsts[I] = std::make_tuple(V, Mask, Worthy);
983ca95b02SDimitry Andric     auto &M = *I->getFunction()->getParent();
993ca95b02SDimitry Andric     auto &Ctx = M.getContext();
1003ca95b02SDimitry Andric     for (auto *U : I->users()) {
1013ca95b02SDimitry Andric       auto *LI = dyn_cast<BinaryOperator>(U);
1023ca95b02SDimitry Andric       if (LI && LI->getType() == Type::getInt1Ty(Ctx) &&
1033ca95b02SDimitry Andric           (LI->getOpcode() == Instruction::And ||
1043ca95b02SDimitry Andric            LI->getOpcode() == Instruction::Or ||
1053ca95b02SDimitry Andric            LI->getOpcode() == Instruction::Xor)) {
1063ca95b02SDimitry Andric         LogicOpsWorklist.push_back(LI);
1073ca95b02SDimitry Andric       }
1083ca95b02SDimitry Andric     }
1093ca95b02SDimitry Andric   }
1103ca95b02SDimitry Andric };
1113ca95b02SDimitry Andric 
1123ca95b02SDimitry Andric } // end anonymous namespace
1133ca95b02SDimitry Andric 
1143ca95b02SDimitry Andric char SystemZTDCPass::ID = 0;
1153ca95b02SDimitry Andric INITIALIZE_PASS(SystemZTDCPass, "systemz-tdc",
1163ca95b02SDimitry Andric                 "SystemZ Test Data Class optimization", false, false)
1173ca95b02SDimitry Andric 
createSystemZTDCPass()1183ca95b02SDimitry Andric FunctionPass *llvm::createSystemZTDCPass() {
1193ca95b02SDimitry Andric   return new SystemZTDCPass();
1203ca95b02SDimitry Andric }
1213ca95b02SDimitry Andric 
convertFCmp(CmpInst & I)1223ca95b02SDimitry Andric void SystemZTDCPass::convertFCmp(CmpInst &I) {
1233ca95b02SDimitry Andric   Value *Op0 = I.getOperand(0);
1243ca95b02SDimitry Andric   auto *Const = dyn_cast<ConstantFP>(I.getOperand(1));
1253ca95b02SDimitry Andric   auto Pred = I.getPredicate();
1263ca95b02SDimitry Andric   // Only comparisons with consts are interesting.
1273ca95b02SDimitry Andric   if (!Const)
1283ca95b02SDimitry Andric     return;
1293ca95b02SDimitry Andric   // Compute the smallest normal number (and its negation).
1303ca95b02SDimitry Andric   auto &Sem = Op0->getType()->getFltSemantics();
1313ca95b02SDimitry Andric   APFloat Smallest = APFloat::getSmallestNormalized(Sem);
1323ca95b02SDimitry Andric   APFloat NegSmallest = Smallest;
1333ca95b02SDimitry Andric   NegSmallest.changeSign();
1343ca95b02SDimitry Andric   // Check if Const is one of our recognized consts.
1353ca95b02SDimitry Andric   int WhichConst;
1363ca95b02SDimitry Andric   if (Const->isZero()) {
1373ca95b02SDimitry Andric     // All comparisons with 0 can be converted.
1383ca95b02SDimitry Andric     WhichConst = 0;
1393ca95b02SDimitry Andric   } else if (Const->isInfinity()) {
1403ca95b02SDimitry Andric     // Likewise for infinities.
1413ca95b02SDimitry Andric     WhichConst = Const->isNegative() ? 2 : 1;
1423ca95b02SDimitry Andric   } else if (Const->isExactlyValue(Smallest)) {
1433ca95b02SDimitry Andric     // For Smallest, we cannot do EQ separately from GT.
1443ca95b02SDimitry Andric     if ((Pred & CmpInst::FCMP_OGE) != CmpInst::FCMP_OGE &&
1453ca95b02SDimitry Andric         (Pred & CmpInst::FCMP_OGE) != 0)
1463ca95b02SDimitry Andric       return;
1473ca95b02SDimitry Andric     WhichConst = 3;
1483ca95b02SDimitry Andric   } else if (Const->isExactlyValue(NegSmallest)) {
1493ca95b02SDimitry Andric     // Likewise for NegSmallest, we cannot do EQ separately from LT.
1503ca95b02SDimitry Andric     if ((Pred & CmpInst::FCMP_OLE) != CmpInst::FCMP_OLE &&
1513ca95b02SDimitry Andric         (Pred & CmpInst::FCMP_OLE) != 0)
1523ca95b02SDimitry Andric       return;
1533ca95b02SDimitry Andric     WhichConst = 4;
1543ca95b02SDimitry Andric   } else {
1553ca95b02SDimitry Andric     // Not one of our special constants.
1563ca95b02SDimitry Andric     return;
1573ca95b02SDimitry Andric   }
1583ca95b02SDimitry Andric   // Partial masks to use for EQ, GT, LT, UN comparisons, respectively.
1593ca95b02SDimitry Andric   static const int Masks[][4] = {
1603ca95b02SDimitry Andric     { // 0
1613ca95b02SDimitry Andric       SystemZ::TDCMASK_ZERO,              // eq
1623ca95b02SDimitry Andric       SystemZ::TDCMASK_POSITIVE,          // gt
1633ca95b02SDimitry Andric       SystemZ::TDCMASK_NEGATIVE,          // lt
1643ca95b02SDimitry Andric       SystemZ::TDCMASK_NAN,               // un
1653ca95b02SDimitry Andric     },
1663ca95b02SDimitry Andric     { // inf
1673ca95b02SDimitry Andric       SystemZ::TDCMASK_INFINITY_PLUS,     // eq
1683ca95b02SDimitry Andric       0,                                  // gt
1693ca95b02SDimitry Andric       (SystemZ::TDCMASK_ZERO |
1703ca95b02SDimitry Andric        SystemZ::TDCMASK_NEGATIVE |
1713ca95b02SDimitry Andric        SystemZ::TDCMASK_NORMAL_PLUS |
1723ca95b02SDimitry Andric        SystemZ::TDCMASK_SUBNORMAL_PLUS),  // lt
1733ca95b02SDimitry Andric       SystemZ::TDCMASK_NAN,               // un
1743ca95b02SDimitry Andric     },
1753ca95b02SDimitry Andric     { // -inf
1763ca95b02SDimitry Andric       SystemZ::TDCMASK_INFINITY_MINUS,    // eq
1773ca95b02SDimitry Andric       (SystemZ::TDCMASK_ZERO |
1783ca95b02SDimitry Andric        SystemZ::TDCMASK_POSITIVE |
1793ca95b02SDimitry Andric        SystemZ::TDCMASK_NORMAL_MINUS |
1803ca95b02SDimitry Andric        SystemZ::TDCMASK_SUBNORMAL_MINUS), // gt
1813ca95b02SDimitry Andric       0,                                  // lt
1823ca95b02SDimitry Andric       SystemZ::TDCMASK_NAN,               // un
1833ca95b02SDimitry Andric     },
1843ca95b02SDimitry Andric     { // minnorm
1853ca95b02SDimitry Andric       0,                                  // eq (unsupported)
1863ca95b02SDimitry Andric       (SystemZ::TDCMASK_NORMAL_PLUS |
1873ca95b02SDimitry Andric        SystemZ::TDCMASK_INFINITY_PLUS),   // gt (actually ge)
1883ca95b02SDimitry Andric       (SystemZ::TDCMASK_ZERO |
1893ca95b02SDimitry Andric        SystemZ::TDCMASK_NEGATIVE |
1903ca95b02SDimitry Andric        SystemZ::TDCMASK_SUBNORMAL_PLUS),  // lt
1913ca95b02SDimitry Andric       SystemZ::TDCMASK_NAN,               // un
1923ca95b02SDimitry Andric     },
1933ca95b02SDimitry Andric     { // -minnorm
1943ca95b02SDimitry Andric       0,                                  // eq (unsupported)
1953ca95b02SDimitry Andric       (SystemZ::TDCMASK_ZERO |
1963ca95b02SDimitry Andric        SystemZ::TDCMASK_POSITIVE |
1973ca95b02SDimitry Andric        SystemZ::TDCMASK_SUBNORMAL_MINUS), // gt
1983ca95b02SDimitry Andric       (SystemZ::TDCMASK_NORMAL_MINUS |
1993ca95b02SDimitry Andric        SystemZ::TDCMASK_INFINITY_MINUS),  // lt (actually le)
2003ca95b02SDimitry Andric       SystemZ::TDCMASK_NAN,               // un
2013ca95b02SDimitry Andric     }
2023ca95b02SDimitry Andric   };
2033ca95b02SDimitry Andric   // Construct the mask as a combination of the partial masks.
2043ca95b02SDimitry Andric   int Mask = 0;
2053ca95b02SDimitry Andric   if (Pred & CmpInst::FCMP_OEQ)
2063ca95b02SDimitry Andric     Mask |= Masks[WhichConst][0];
2073ca95b02SDimitry Andric   if (Pred & CmpInst::FCMP_OGT)
2083ca95b02SDimitry Andric     Mask |= Masks[WhichConst][1];
2093ca95b02SDimitry Andric   if (Pred & CmpInst::FCMP_OLT)
2103ca95b02SDimitry Andric     Mask |= Masks[WhichConst][2];
2113ca95b02SDimitry Andric   if (Pred & CmpInst::FCMP_UNO)
2123ca95b02SDimitry Andric     Mask |= Masks[WhichConst][3];
2133ca95b02SDimitry Andric   // A lone fcmp is unworthy of tdc conversion on its own, but may become
2143ca95b02SDimitry Andric   // worthy if combined with fabs.
2153ca95b02SDimitry Andric   bool Worthy = false;
2163ca95b02SDimitry Andric   if (CallInst *CI = dyn_cast<CallInst>(Op0)) {
2173ca95b02SDimitry Andric     Function *F = CI->getCalledFunction();
2183ca95b02SDimitry Andric     if (F && F->getIntrinsicID() == Intrinsic::fabs) {
2193ca95b02SDimitry Andric       // Fold with fabs - adjust the mask appropriately.
2203ca95b02SDimitry Andric       Mask &= SystemZ::TDCMASK_PLUS;
2213ca95b02SDimitry Andric       Mask |= Mask >> 1;
2223ca95b02SDimitry Andric       Op0 = CI->getArgOperand(0);
2233ca95b02SDimitry Andric       // A combination of fcmp with fabs is a win, unless the constant
2243ca95b02SDimitry Andric       // involved is 0 (which is handled by later passes).
2253ca95b02SDimitry Andric       Worthy = WhichConst != 0;
2263ca95b02SDimitry Andric       PossibleJunk.insert(CI);
2273ca95b02SDimitry Andric     }
2283ca95b02SDimitry Andric   }
2293ca95b02SDimitry Andric   converted(&I, Op0, Mask, Worthy);
2303ca95b02SDimitry Andric }
2313ca95b02SDimitry Andric 
convertICmp(CmpInst & I)2323ca95b02SDimitry Andric void SystemZTDCPass::convertICmp(CmpInst &I) {
2333ca95b02SDimitry Andric   Value *Op0 = I.getOperand(0);
2343ca95b02SDimitry Andric   auto *Const = dyn_cast<ConstantInt>(I.getOperand(1));
2353ca95b02SDimitry Andric   auto Pred = I.getPredicate();
2363ca95b02SDimitry Andric   // All our icmp rules involve comparisons with consts.
2373ca95b02SDimitry Andric   if (!Const)
2383ca95b02SDimitry Andric     return;
2393ca95b02SDimitry Andric   if (auto *Cast = dyn_cast<BitCastInst>(Op0)) {
2403ca95b02SDimitry Andric     // Check for icmp+bitcast used for signbit.
2413ca95b02SDimitry Andric     if (!Cast->getSrcTy()->isFloatTy() &&
2423ca95b02SDimitry Andric         !Cast->getSrcTy()->isDoubleTy() &&
2433ca95b02SDimitry Andric         !Cast->getSrcTy()->isFP128Ty())
2443ca95b02SDimitry Andric       return;
2453ca95b02SDimitry Andric     Value *V = Cast->getOperand(0);
2463ca95b02SDimitry Andric     int Mask;
2473ca95b02SDimitry Andric     if (Pred == CmpInst::ICMP_SLT && Const->isZero()) {
2483ca95b02SDimitry Andric       // icmp slt (bitcast X), 0 - set if sign bit true
2493ca95b02SDimitry Andric       Mask = SystemZ::TDCMASK_MINUS;
2503ca95b02SDimitry Andric     } else if (Pred == CmpInst::ICMP_SGT && Const->isMinusOne()) {
2513ca95b02SDimitry Andric       // icmp sgt (bitcast X), -1 - set if sign bit false
2523ca95b02SDimitry Andric       Mask = SystemZ::TDCMASK_PLUS;
2533ca95b02SDimitry Andric     } else {
2543ca95b02SDimitry Andric       // Not a sign bit check.
2553ca95b02SDimitry Andric       return;
2563ca95b02SDimitry Andric     }
2573ca95b02SDimitry Andric     PossibleJunk.insert(Cast);
2583ca95b02SDimitry Andric     converted(&I, V, Mask, true);
2593ca95b02SDimitry Andric   } else if (auto *CI = dyn_cast<CallInst>(Op0)) {
2603ca95b02SDimitry Andric     // Check if this is a pre-existing call of our tdc intrinsic.
2613ca95b02SDimitry Andric     Function *F = CI->getCalledFunction();
2623ca95b02SDimitry Andric     if (!F || F->getIntrinsicID() != Intrinsic::s390_tdc)
2633ca95b02SDimitry Andric       return;
2643ca95b02SDimitry Andric     if (!Const->isZero())
2653ca95b02SDimitry Andric       return;
2663ca95b02SDimitry Andric     Value *V = CI->getArgOperand(0);
2673ca95b02SDimitry Andric     auto *MaskC = dyn_cast<ConstantInt>(CI->getArgOperand(1));
2683ca95b02SDimitry Andric     // Bail if the mask is not a constant.
2693ca95b02SDimitry Andric     if (!MaskC)
2703ca95b02SDimitry Andric       return;
2713ca95b02SDimitry Andric     int Mask = MaskC->getZExtValue();
2723ca95b02SDimitry Andric     Mask &= SystemZ::TDCMASK_ALL;
2733ca95b02SDimitry Andric     if (Pred == CmpInst::ICMP_NE) {
2743ca95b02SDimitry Andric       // icmp ne (call llvm.s390.tdc(...)), 0 -> simple TDC
2753ca95b02SDimitry Andric     } else if (Pred == CmpInst::ICMP_EQ) {
2763ca95b02SDimitry Andric       // icmp eq (call llvm.s390.tdc(...)), 0 -> TDC with inverted mask
2773ca95b02SDimitry Andric       Mask ^= SystemZ::TDCMASK_ALL;
2783ca95b02SDimitry Andric     } else {
2793ca95b02SDimitry Andric       // An unknown comparison - ignore.
2803ca95b02SDimitry Andric       return;
2813ca95b02SDimitry Andric     }
2823ca95b02SDimitry Andric     PossibleJunk.insert(CI);
2833ca95b02SDimitry Andric     converted(&I, V, Mask, false);
2843ca95b02SDimitry Andric   }
2853ca95b02SDimitry Andric }
2863ca95b02SDimitry Andric 
convertLogicOp(BinaryOperator & I)2873ca95b02SDimitry Andric void SystemZTDCPass::convertLogicOp(BinaryOperator &I) {
2883ca95b02SDimitry Andric   Value *Op0, *Op1;
2893ca95b02SDimitry Andric   int Mask0, Mask1;
2903ca95b02SDimitry Andric   bool Worthy0, Worthy1;
2913ca95b02SDimitry Andric   std::tie(Op0, Mask0, Worthy0) = ConvertedInsts[cast<Instruction>(I.getOperand(0))];
2923ca95b02SDimitry Andric   std::tie(Op1, Mask1, Worthy1) = ConvertedInsts[cast<Instruction>(I.getOperand(1))];
2933ca95b02SDimitry Andric   if (Op0 != Op1)
2943ca95b02SDimitry Andric     return;
2953ca95b02SDimitry Andric   int Mask;
2963ca95b02SDimitry Andric   switch (I.getOpcode()) {
2973ca95b02SDimitry Andric     case Instruction::And:
2983ca95b02SDimitry Andric       Mask = Mask0 & Mask1;
2993ca95b02SDimitry Andric       break;
3003ca95b02SDimitry Andric     case Instruction::Or:
3013ca95b02SDimitry Andric       Mask = Mask0 | Mask1;
3023ca95b02SDimitry Andric       break;
3033ca95b02SDimitry Andric     case Instruction::Xor:
3043ca95b02SDimitry Andric       Mask = Mask0 ^ Mask1;
3053ca95b02SDimitry Andric       break;
3063ca95b02SDimitry Andric     default:
3073ca95b02SDimitry Andric       llvm_unreachable("Unknown op in convertLogicOp");
3083ca95b02SDimitry Andric   }
3093ca95b02SDimitry Andric   converted(&I, Op0, Mask, true);
3103ca95b02SDimitry Andric }
3113ca95b02SDimitry Andric 
runOnFunction(Function & F)3123ca95b02SDimitry Andric bool SystemZTDCPass::runOnFunction(Function &F) {
3133ca95b02SDimitry Andric   ConvertedInsts.clear();
3143ca95b02SDimitry Andric   LogicOpsWorklist.clear();
3153ca95b02SDimitry Andric   PossibleJunk.clear();
3163ca95b02SDimitry Andric 
3173ca95b02SDimitry Andric   // Look for icmp+fcmp instructions.
3183ca95b02SDimitry Andric   for (auto &I : instructions(F)) {
3193ca95b02SDimitry Andric     if (I.getOpcode() == Instruction::FCmp)
3203ca95b02SDimitry Andric       convertFCmp(cast<CmpInst>(I));
3213ca95b02SDimitry Andric     else if (I.getOpcode() == Instruction::ICmp)
3223ca95b02SDimitry Andric       convertICmp(cast<CmpInst>(I));
3233ca95b02SDimitry Andric   }
3243ca95b02SDimitry Andric 
3253ca95b02SDimitry Andric   // If none found, bail already.
3263ca95b02SDimitry Andric   if (ConvertedInsts.empty())
3273ca95b02SDimitry Andric     return false;
3283ca95b02SDimitry Andric 
3293ca95b02SDimitry Andric   // Process the queue of logic instructions.
3303ca95b02SDimitry Andric   while (!LogicOpsWorklist.empty()) {
3313ca95b02SDimitry Andric     BinaryOperator *Op = LogicOpsWorklist.back();
3323ca95b02SDimitry Andric     LogicOpsWorklist.pop_back();
3333ca95b02SDimitry Andric     // If both operands mapped, and the instruction itself not yet mapped,
3343ca95b02SDimitry Andric     // convert it.
3353ca95b02SDimitry Andric     if (ConvertedInsts.count(dyn_cast<Instruction>(Op->getOperand(0))) &&
3363ca95b02SDimitry Andric         ConvertedInsts.count(dyn_cast<Instruction>(Op->getOperand(1))) &&
3373ca95b02SDimitry Andric         !ConvertedInsts.count(Op))
3383ca95b02SDimitry Andric       convertLogicOp(*Op);
3393ca95b02SDimitry Andric   }
3403ca95b02SDimitry Andric 
3413ca95b02SDimitry Andric   // Time to actually replace the instructions.  Do it in the reverse order
3423ca95b02SDimitry Andric   // of finding them, since there's a good chance the earlier ones will be
3433ca95b02SDimitry Andric   // unused (due to being folded into later ones).
3443ca95b02SDimitry Andric   Module &M = *F.getParent();
3453ca95b02SDimitry Andric   auto &Ctx = M.getContext();
3463ca95b02SDimitry Andric   Value *Zero32 = ConstantInt::get(Type::getInt32Ty(Ctx), 0);
3473ca95b02SDimitry Andric   bool MadeChange = false;
3483ca95b02SDimitry Andric   for (auto &It : reverse(ConvertedInsts)) {
3493ca95b02SDimitry Andric     Instruction *I = It.first;
3503ca95b02SDimitry Andric     Value *V;
3513ca95b02SDimitry Andric     int Mask;
3523ca95b02SDimitry Andric     bool Worthy;
3533ca95b02SDimitry Andric     std::tie(V, Mask, Worthy) = It.second;
3543ca95b02SDimitry Andric     if (!I->user_empty()) {
3553ca95b02SDimitry Andric       // If used and unworthy of conversion, skip it.
3563ca95b02SDimitry Andric       if (!Worthy)
3573ca95b02SDimitry Andric         continue;
3583ca95b02SDimitry Andric       // Call the intrinsic, compare result with 0.
3593ca95b02SDimitry Andric       Value *TDCFunc = Intrinsic::getDeclaration(&M, Intrinsic::s390_tdc,
3603ca95b02SDimitry Andric                                                  V->getType());
3613ca95b02SDimitry Andric       IRBuilder<> IRB(I);
3623ca95b02SDimitry Andric       Value *MaskVal = ConstantInt::get(Type::getInt64Ty(Ctx), Mask);
3633ca95b02SDimitry Andric       Instruction *TDC = IRB.CreateCall(TDCFunc, {V, MaskVal});
3643ca95b02SDimitry Andric       Value *ICmp = IRB.CreateICmp(CmpInst::ICMP_NE, TDC, Zero32);
3653ca95b02SDimitry Andric       I->replaceAllUsesWith(ICmp);
3663ca95b02SDimitry Andric     }
3673ca95b02SDimitry Andric     // If unused, or used and converted, remove it.
3683ca95b02SDimitry Andric     I->eraseFromParent();
3693ca95b02SDimitry Andric     MadeChange = true;
3703ca95b02SDimitry Andric   }
3713ca95b02SDimitry Andric 
3723ca95b02SDimitry Andric   if (!MadeChange)
3733ca95b02SDimitry Andric     return false;
3743ca95b02SDimitry Andric 
3753ca95b02SDimitry Andric   // We've actually done something - now clear misc accumulated junk (fabs,
3763ca95b02SDimitry Andric   // bitcast).
3773ca95b02SDimitry Andric   for (auto *I : PossibleJunk)
3783ca95b02SDimitry Andric     if (I->user_empty())
3793ca95b02SDimitry Andric       I->eraseFromParent();
3803ca95b02SDimitry Andric 
3813ca95b02SDimitry Andric   return true;
3823ca95b02SDimitry Andric }
383