10b57cec5SDimitry Andric //===-- SystemZTDC.cpp - Utilize Test Data Class instruction --------------===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric //
90b57cec5SDimitry Andric // This pass looks for instructions that can be replaced by a Test Data Class
100b57cec5SDimitry Andric // instruction, and replaces them when profitable.
110b57cec5SDimitry Andric //
120b57cec5SDimitry Andric // Roughly, the following rules are recognized:
130b57cec5SDimitry Andric //
140b57cec5SDimitry Andric // 1: fcmp pred X, 0 -> tdc X, mask
150b57cec5SDimitry Andric // 2: fcmp pred X, +-inf -> tdc X, mask
160b57cec5SDimitry Andric // 3: fcmp pred X, +-minnorm -> tdc X, mask
170b57cec5SDimitry Andric // 4: tdc (fabs X), mask -> tdc X, newmask
180b57cec5SDimitry Andric // 5: icmp slt (bitcast float X to int), 0 -> tdc X, mask [ie. signbit]
190b57cec5SDimitry Andric // 6: icmp sgt (bitcast float X to int), -1 -> tdc X, mask
200b57cec5SDimitry Andric // 7: icmp ne/eq (call @llvm.s390.tdc.*(X, mask)) -> tdc X, mask/~mask
210b57cec5SDimitry Andric // 8: and i1 (tdc X, M1), (tdc X, M2) -> tdc X, (M1 & M2)
220b57cec5SDimitry Andric // 9: or i1 (tdc X, M1), (tdc X, M2) -> tdc X, (M1 | M2)
230b57cec5SDimitry Andric // 10: xor i1 (tdc X, M1), (tdc X, M2) -> tdc X, (M1 ^ M2)
240b57cec5SDimitry Andric //
250b57cec5SDimitry Andric // The pass works in 4 steps:
260b57cec5SDimitry Andric //
270b57cec5SDimitry Andric // 1. All fcmp and icmp instructions in a function are checked for a match
280b57cec5SDimitry Andric //    with rules 1-3 and 5-7.  Their TDC equivalents are stored in
290b57cec5SDimitry Andric //    the ConvertedInsts mapping.  If the operand of a fcmp instruction is
300b57cec5SDimitry Andric //    a fabs, it's also folded according to rule 4.
310b57cec5SDimitry Andric // 2. All and/or/xor i1 instructions whose both operands have been already
320b57cec5SDimitry Andric //    mapped are mapped according to rules 8-10.  LogicOpsWorklist is used
330b57cec5SDimitry Andric //    as a queue of instructions to check.
340b57cec5SDimitry Andric // 3. All mapped instructions that are considered worthy of conversion (ie.
350b57cec5SDimitry Andric //    replacing them will actually simplify the final code) are replaced
360b57cec5SDimitry Andric //    with a call to the s390.tdc intrinsic.
370b57cec5SDimitry Andric // 4. All intermediate results of replaced instructions are removed if unused.
380b57cec5SDimitry Andric //
390b57cec5SDimitry Andric // Instructions that match rules 1-3 are considered unworthy of conversion
400b57cec5SDimitry Andric // on their own (since a comparison instruction is superior), but are mapped
410b57cec5SDimitry Andric // in the hopes of folding the result using rules 4 and 8-10 (likely removing
420b57cec5SDimitry Andric // the original comparison in the process).
430b57cec5SDimitry Andric //
440b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
450b57cec5SDimitry Andric 
460b57cec5SDimitry Andric #include "SystemZ.h"
475ffd83dbSDimitry Andric #include "SystemZSubtarget.h"
480b57cec5SDimitry Andric #include "llvm/ADT/MapVector.h"
495ffd83dbSDimitry Andric #include "llvm/CodeGen/TargetPassConfig.h"
500b57cec5SDimitry Andric #include "llvm/IR/Constants.h"
510b57cec5SDimitry Andric #include "llvm/IR/IRBuilder.h"
520b57cec5SDimitry Andric #include "llvm/IR/InstIterator.h"
530b57cec5SDimitry Andric #include "llvm/IR/Instructions.h"
540b57cec5SDimitry Andric #include "llvm/IR/IntrinsicInst.h"
55480093f4SDimitry Andric #include "llvm/IR/IntrinsicsS390.h"
560b57cec5SDimitry Andric #include "llvm/IR/LegacyPassManager.h"
570b57cec5SDimitry Andric #include "llvm/IR/Module.h"
585ffd83dbSDimitry Andric #include "llvm/Target/TargetMachine.h"
590b57cec5SDimitry Andric #include <deque>
600b57cec5SDimitry Andric #include <set>
610b57cec5SDimitry Andric 
620b57cec5SDimitry Andric using namespace llvm;
630b57cec5SDimitry Andric 
640b57cec5SDimitry Andric namespace {
650b57cec5SDimitry Andric 
660b57cec5SDimitry Andric class SystemZTDCPass : public FunctionPass {
670b57cec5SDimitry Andric public:
680b57cec5SDimitry Andric   static char ID;
SystemZTDCPass()690b57cec5SDimitry Andric   SystemZTDCPass() : FunctionPass(ID) {
700b57cec5SDimitry Andric     initializeSystemZTDCPassPass(*PassRegistry::getPassRegistry());
710b57cec5SDimitry Andric   }
720b57cec5SDimitry Andric 
730b57cec5SDimitry Andric   bool runOnFunction(Function &F) override;
745ffd83dbSDimitry Andric 
getAnalysisUsage(AnalysisUsage & AU) const755ffd83dbSDimitry Andric   void getAnalysisUsage(AnalysisUsage &AU) const override {
765ffd83dbSDimitry Andric     AU.addRequired<TargetPassConfig>();
775ffd83dbSDimitry Andric  }
785ffd83dbSDimitry Andric 
790b57cec5SDimitry Andric private:
800b57cec5SDimitry Andric   // Maps seen instructions that can be mapped to a TDC, values are
810b57cec5SDimitry Andric   // (TDC operand, TDC mask, worthy flag) triples.
820b57cec5SDimitry Andric   MapVector<Instruction *, std::tuple<Value *, int, bool>> ConvertedInsts;
830b57cec5SDimitry Andric   // The queue of and/or/xor i1 instructions to be potentially folded.
840b57cec5SDimitry Andric   std::vector<BinaryOperator *> LogicOpsWorklist;
850b57cec5SDimitry Andric   // Instructions matched while folding, to be removed at the end if unused.
860b57cec5SDimitry Andric   std::set<Instruction *> PossibleJunk;
870b57cec5SDimitry Andric 
880b57cec5SDimitry Andric   // Tries to convert a fcmp instruction.
890b57cec5SDimitry Andric   void convertFCmp(CmpInst &I);
900b57cec5SDimitry Andric 
910b57cec5SDimitry Andric   // Tries to convert an icmp instruction.
920b57cec5SDimitry Andric   void convertICmp(CmpInst &I);
930b57cec5SDimitry Andric 
940b57cec5SDimitry Andric   // Tries to convert an i1 and/or/xor instruction, whose both operands
950b57cec5SDimitry Andric   // have been already converted.
960b57cec5SDimitry Andric   void convertLogicOp(BinaryOperator &I);
970b57cec5SDimitry Andric 
980b57cec5SDimitry Andric   // Marks an instruction as converted - adds it to ConvertedInsts and adds
990b57cec5SDimitry Andric   // any and/or/xor i1 users to the queue.
converted(Instruction * I,Value * V,int Mask,bool Worthy)1000b57cec5SDimitry Andric   void converted(Instruction *I, Value *V, int Mask, bool Worthy) {
1010b57cec5SDimitry Andric     ConvertedInsts[I] = std::make_tuple(V, Mask, Worthy);
1020b57cec5SDimitry Andric     auto &M = *I->getFunction()->getParent();
1030b57cec5SDimitry Andric     auto &Ctx = M.getContext();
1040b57cec5SDimitry Andric     for (auto *U : I->users()) {
1050b57cec5SDimitry Andric       auto *LI = dyn_cast<BinaryOperator>(U);
1060b57cec5SDimitry Andric       if (LI && LI->getType() == Type::getInt1Ty(Ctx) &&
1070b57cec5SDimitry Andric           (LI->getOpcode() == Instruction::And ||
1080b57cec5SDimitry Andric            LI->getOpcode() == Instruction::Or ||
1090b57cec5SDimitry Andric            LI->getOpcode() == Instruction::Xor)) {
1100b57cec5SDimitry Andric         LogicOpsWorklist.push_back(LI);
1110b57cec5SDimitry Andric       }
1120b57cec5SDimitry Andric     }
1130b57cec5SDimitry Andric   }
1140b57cec5SDimitry Andric };
1150b57cec5SDimitry Andric 
1160b57cec5SDimitry Andric } // end anonymous namespace
1170b57cec5SDimitry Andric 
1180b57cec5SDimitry Andric char SystemZTDCPass::ID = 0;
1190b57cec5SDimitry Andric INITIALIZE_PASS(SystemZTDCPass, "systemz-tdc",
1200b57cec5SDimitry Andric                 "SystemZ Test Data Class optimization", false, false)
1210b57cec5SDimitry Andric 
createSystemZTDCPass()1220b57cec5SDimitry Andric FunctionPass *llvm::createSystemZTDCPass() {
1230b57cec5SDimitry Andric   return new SystemZTDCPass();
1240b57cec5SDimitry Andric }
1250b57cec5SDimitry Andric 
convertFCmp(CmpInst & I)1260b57cec5SDimitry Andric void SystemZTDCPass::convertFCmp(CmpInst &I) {
1270b57cec5SDimitry Andric   Value *Op0 = I.getOperand(0);
1280b57cec5SDimitry Andric   auto *Const = dyn_cast<ConstantFP>(I.getOperand(1));
1290b57cec5SDimitry Andric   auto Pred = I.getPredicate();
1300b57cec5SDimitry Andric   // Only comparisons with consts are interesting.
1310b57cec5SDimitry Andric   if (!Const)
1320b57cec5SDimitry Andric     return;
1330b57cec5SDimitry Andric   // Compute the smallest normal number (and its negation).
1340b57cec5SDimitry Andric   auto &Sem = Op0->getType()->getFltSemantics();
1350b57cec5SDimitry Andric   APFloat Smallest = APFloat::getSmallestNormalized(Sem);
1360b57cec5SDimitry Andric   APFloat NegSmallest = Smallest;
1370b57cec5SDimitry Andric   NegSmallest.changeSign();
1380b57cec5SDimitry Andric   // Check if Const is one of our recognized consts.
1390b57cec5SDimitry Andric   int WhichConst;
1400b57cec5SDimitry Andric   if (Const->isZero()) {
1410b57cec5SDimitry Andric     // All comparisons with 0 can be converted.
1420b57cec5SDimitry Andric     WhichConst = 0;
1430b57cec5SDimitry Andric   } else if (Const->isInfinity()) {
1440b57cec5SDimitry Andric     // Likewise for infinities.
1450b57cec5SDimitry Andric     WhichConst = Const->isNegative() ? 2 : 1;
1460b57cec5SDimitry Andric   } else if (Const->isExactlyValue(Smallest)) {
1470b57cec5SDimitry Andric     // For Smallest, we cannot do EQ separately from GT.
1480b57cec5SDimitry Andric     if ((Pred & CmpInst::FCMP_OGE) != CmpInst::FCMP_OGE &&
1490b57cec5SDimitry Andric         (Pred & CmpInst::FCMP_OGE) != 0)
1500b57cec5SDimitry Andric       return;
1510b57cec5SDimitry Andric     WhichConst = 3;
1520b57cec5SDimitry Andric   } else if (Const->isExactlyValue(NegSmallest)) {
1530b57cec5SDimitry Andric     // Likewise for NegSmallest, we cannot do EQ separately from LT.
1540b57cec5SDimitry Andric     if ((Pred & CmpInst::FCMP_OLE) != CmpInst::FCMP_OLE &&
1550b57cec5SDimitry Andric         (Pred & CmpInst::FCMP_OLE) != 0)
1560b57cec5SDimitry Andric       return;
1570b57cec5SDimitry Andric     WhichConst = 4;
1580b57cec5SDimitry Andric   } else {
1590b57cec5SDimitry Andric     // Not one of our special constants.
1600b57cec5SDimitry Andric     return;
1610b57cec5SDimitry Andric   }
1620b57cec5SDimitry Andric   // Partial masks to use for EQ, GT, LT, UN comparisons, respectively.
1630b57cec5SDimitry Andric   static const int Masks[][4] = {
1640b57cec5SDimitry Andric     { // 0
1650b57cec5SDimitry Andric       SystemZ::TDCMASK_ZERO,              // eq
1660b57cec5SDimitry Andric       SystemZ::TDCMASK_POSITIVE,          // gt
1670b57cec5SDimitry Andric       SystemZ::TDCMASK_NEGATIVE,          // lt
1680b57cec5SDimitry Andric       SystemZ::TDCMASK_NAN,               // un
1690b57cec5SDimitry Andric     },
1700b57cec5SDimitry Andric     { // inf
1710b57cec5SDimitry Andric       SystemZ::TDCMASK_INFINITY_PLUS,     // eq
1720b57cec5SDimitry Andric       0,                                  // gt
1730b57cec5SDimitry Andric       (SystemZ::TDCMASK_ZERO |
1740b57cec5SDimitry Andric        SystemZ::TDCMASK_NEGATIVE |
1750b57cec5SDimitry Andric        SystemZ::TDCMASK_NORMAL_PLUS |
1760b57cec5SDimitry Andric        SystemZ::TDCMASK_SUBNORMAL_PLUS),  // lt
1770b57cec5SDimitry Andric       SystemZ::TDCMASK_NAN,               // un
1780b57cec5SDimitry Andric     },
1790b57cec5SDimitry Andric     { // -inf
1800b57cec5SDimitry Andric       SystemZ::TDCMASK_INFINITY_MINUS,    // eq
1810b57cec5SDimitry Andric       (SystemZ::TDCMASK_ZERO |
1820b57cec5SDimitry Andric        SystemZ::TDCMASK_POSITIVE |
1830b57cec5SDimitry Andric        SystemZ::TDCMASK_NORMAL_MINUS |
1840b57cec5SDimitry Andric        SystemZ::TDCMASK_SUBNORMAL_MINUS), // gt
1850b57cec5SDimitry Andric       0,                                  // lt
1860b57cec5SDimitry Andric       SystemZ::TDCMASK_NAN,               // un
1870b57cec5SDimitry Andric     },
1880b57cec5SDimitry Andric     { // minnorm
1890b57cec5SDimitry Andric       0,                                  // eq (unsupported)
1900b57cec5SDimitry Andric       (SystemZ::TDCMASK_NORMAL_PLUS |
1910b57cec5SDimitry Andric        SystemZ::TDCMASK_INFINITY_PLUS),   // gt (actually ge)
1920b57cec5SDimitry Andric       (SystemZ::TDCMASK_ZERO |
1930b57cec5SDimitry Andric        SystemZ::TDCMASK_NEGATIVE |
1940b57cec5SDimitry Andric        SystemZ::TDCMASK_SUBNORMAL_PLUS),  // lt
1950b57cec5SDimitry Andric       SystemZ::TDCMASK_NAN,               // un
1960b57cec5SDimitry Andric     },
1970b57cec5SDimitry Andric     { // -minnorm
1980b57cec5SDimitry Andric       0,                                  // eq (unsupported)
1990b57cec5SDimitry Andric       (SystemZ::TDCMASK_ZERO |
2000b57cec5SDimitry Andric        SystemZ::TDCMASK_POSITIVE |
2010b57cec5SDimitry Andric        SystemZ::TDCMASK_SUBNORMAL_MINUS), // gt
2020b57cec5SDimitry Andric       (SystemZ::TDCMASK_NORMAL_MINUS |
2030b57cec5SDimitry Andric        SystemZ::TDCMASK_INFINITY_MINUS),  // lt (actually le)
2040b57cec5SDimitry Andric       SystemZ::TDCMASK_NAN,               // un
2050b57cec5SDimitry Andric     }
2060b57cec5SDimitry Andric   };
2070b57cec5SDimitry Andric   // Construct the mask as a combination of the partial masks.
2080b57cec5SDimitry Andric   int Mask = 0;
2090b57cec5SDimitry Andric   if (Pred & CmpInst::FCMP_OEQ)
2100b57cec5SDimitry Andric     Mask |= Masks[WhichConst][0];
2110b57cec5SDimitry Andric   if (Pred & CmpInst::FCMP_OGT)
2120b57cec5SDimitry Andric     Mask |= Masks[WhichConst][1];
2130b57cec5SDimitry Andric   if (Pred & CmpInst::FCMP_OLT)
2140b57cec5SDimitry Andric     Mask |= Masks[WhichConst][2];
2150b57cec5SDimitry Andric   if (Pred & CmpInst::FCMP_UNO)
2160b57cec5SDimitry Andric     Mask |= Masks[WhichConst][3];
2170b57cec5SDimitry Andric   // A lone fcmp is unworthy of tdc conversion on its own, but may become
2180b57cec5SDimitry Andric   // worthy if combined with fabs.
2190b57cec5SDimitry Andric   bool Worthy = false;
2200b57cec5SDimitry Andric   if (CallInst *CI = dyn_cast<CallInst>(Op0)) {
2210b57cec5SDimitry Andric     Function *F = CI->getCalledFunction();
2220b57cec5SDimitry Andric     if (F && F->getIntrinsicID() == Intrinsic::fabs) {
2230b57cec5SDimitry Andric       // Fold with fabs - adjust the mask appropriately.
2240b57cec5SDimitry Andric       Mask &= SystemZ::TDCMASK_PLUS;
2250b57cec5SDimitry Andric       Mask |= Mask >> 1;
2260b57cec5SDimitry Andric       Op0 = CI->getArgOperand(0);
2270b57cec5SDimitry Andric       // A combination of fcmp with fabs is a win, unless the constant
2280b57cec5SDimitry Andric       // involved is 0 (which is handled by later passes).
2290b57cec5SDimitry Andric       Worthy = WhichConst != 0;
2300b57cec5SDimitry Andric       PossibleJunk.insert(CI);
2310b57cec5SDimitry Andric     }
2320b57cec5SDimitry Andric   }
2330b57cec5SDimitry Andric   converted(&I, Op0, Mask, Worthy);
2340b57cec5SDimitry Andric }
2350b57cec5SDimitry Andric 
convertICmp(CmpInst & I)2360b57cec5SDimitry Andric void SystemZTDCPass::convertICmp(CmpInst &I) {
2370b57cec5SDimitry Andric   Value *Op0 = I.getOperand(0);
2380b57cec5SDimitry Andric   auto *Const = dyn_cast<ConstantInt>(I.getOperand(1));
2390b57cec5SDimitry Andric   auto Pred = I.getPredicate();
2400b57cec5SDimitry Andric   // All our icmp rules involve comparisons with consts.
2410b57cec5SDimitry Andric   if (!Const)
2420b57cec5SDimitry Andric     return;
2430b57cec5SDimitry Andric   if (auto *Cast = dyn_cast<BitCastInst>(Op0)) {
2440b57cec5SDimitry Andric     // Check for icmp+bitcast used for signbit.
2450b57cec5SDimitry Andric     if (!Cast->getSrcTy()->isFloatTy() &&
2460b57cec5SDimitry Andric         !Cast->getSrcTy()->isDoubleTy() &&
2470b57cec5SDimitry Andric         !Cast->getSrcTy()->isFP128Ty())
2480b57cec5SDimitry Andric       return;
2490b57cec5SDimitry Andric     Value *V = Cast->getOperand(0);
2500b57cec5SDimitry Andric     int Mask;
2510b57cec5SDimitry Andric     if (Pred == CmpInst::ICMP_SLT && Const->isZero()) {
2520b57cec5SDimitry Andric       // icmp slt (bitcast X), 0 - set if sign bit true
2530b57cec5SDimitry Andric       Mask = SystemZ::TDCMASK_MINUS;
2540b57cec5SDimitry Andric     } else if (Pred == CmpInst::ICMP_SGT && Const->isMinusOne()) {
2550b57cec5SDimitry Andric       // icmp sgt (bitcast X), -1 - set if sign bit false
2560b57cec5SDimitry Andric       Mask = SystemZ::TDCMASK_PLUS;
2570b57cec5SDimitry Andric     } else {
2580b57cec5SDimitry Andric       // Not a sign bit check.
2590b57cec5SDimitry Andric       return;
2600b57cec5SDimitry Andric     }
2610b57cec5SDimitry Andric     PossibleJunk.insert(Cast);
2620b57cec5SDimitry Andric     converted(&I, V, Mask, true);
2630b57cec5SDimitry Andric   } else if (auto *CI = dyn_cast<CallInst>(Op0)) {
2640b57cec5SDimitry Andric     // Check if this is a pre-existing call of our tdc intrinsic.
2650b57cec5SDimitry Andric     Function *F = CI->getCalledFunction();
2660b57cec5SDimitry Andric     if (!F || F->getIntrinsicID() != Intrinsic::s390_tdc)
2670b57cec5SDimitry Andric       return;
2680b57cec5SDimitry Andric     if (!Const->isZero())
2690b57cec5SDimitry Andric       return;
2700b57cec5SDimitry Andric     Value *V = CI->getArgOperand(0);
2710b57cec5SDimitry Andric     auto *MaskC = dyn_cast<ConstantInt>(CI->getArgOperand(1));
2720b57cec5SDimitry Andric     // Bail if the mask is not a constant.
2730b57cec5SDimitry Andric     if (!MaskC)
2740b57cec5SDimitry Andric       return;
2750b57cec5SDimitry Andric     int Mask = MaskC->getZExtValue();
2760b57cec5SDimitry Andric     Mask &= SystemZ::TDCMASK_ALL;
2770b57cec5SDimitry Andric     if (Pred == CmpInst::ICMP_NE) {
2780b57cec5SDimitry Andric       // icmp ne (call llvm.s390.tdc(...)), 0 -> simple TDC
2790b57cec5SDimitry Andric     } else if (Pred == CmpInst::ICMP_EQ) {
2800b57cec5SDimitry Andric       // icmp eq (call llvm.s390.tdc(...)), 0 -> TDC with inverted mask
2810b57cec5SDimitry Andric       Mask ^= SystemZ::TDCMASK_ALL;
2820b57cec5SDimitry Andric     } else {
2830b57cec5SDimitry Andric       // An unknown comparison - ignore.
2840b57cec5SDimitry Andric       return;
2850b57cec5SDimitry Andric     }
2860b57cec5SDimitry Andric     PossibleJunk.insert(CI);
2870b57cec5SDimitry Andric     converted(&I, V, Mask, false);
2880b57cec5SDimitry Andric   }
2890b57cec5SDimitry Andric }
2900b57cec5SDimitry Andric 
convertLogicOp(BinaryOperator & I)2910b57cec5SDimitry Andric void SystemZTDCPass::convertLogicOp(BinaryOperator &I) {
2920b57cec5SDimitry Andric   Value *Op0, *Op1;
2930b57cec5SDimitry Andric   int Mask0, Mask1;
2940b57cec5SDimitry Andric   bool Worthy0, Worthy1;
2950b57cec5SDimitry Andric   std::tie(Op0, Mask0, Worthy0) = ConvertedInsts[cast<Instruction>(I.getOperand(0))];
2960b57cec5SDimitry Andric   std::tie(Op1, Mask1, Worthy1) = ConvertedInsts[cast<Instruction>(I.getOperand(1))];
2970b57cec5SDimitry Andric   if (Op0 != Op1)
2980b57cec5SDimitry Andric     return;
2990b57cec5SDimitry Andric   int Mask;
3000b57cec5SDimitry Andric   switch (I.getOpcode()) {
3010b57cec5SDimitry Andric     case Instruction::And:
3020b57cec5SDimitry Andric       Mask = Mask0 & Mask1;
3030b57cec5SDimitry Andric       break;
3040b57cec5SDimitry Andric     case Instruction::Or:
3050b57cec5SDimitry Andric       Mask = Mask0 | Mask1;
3060b57cec5SDimitry Andric       break;
3070b57cec5SDimitry Andric     case Instruction::Xor:
3080b57cec5SDimitry Andric       Mask = Mask0 ^ Mask1;
3090b57cec5SDimitry Andric       break;
3100b57cec5SDimitry Andric     default:
3110b57cec5SDimitry Andric       llvm_unreachable("Unknown op in convertLogicOp");
3120b57cec5SDimitry Andric   }
3130b57cec5SDimitry Andric   converted(&I, Op0, Mask, true);
3140b57cec5SDimitry Andric }
3150b57cec5SDimitry Andric 
runOnFunction(Function & F)3160b57cec5SDimitry Andric bool SystemZTDCPass::runOnFunction(Function &F) {
3175ffd83dbSDimitry Andric   auto &TPC = getAnalysis<TargetPassConfig>();
3185ffd83dbSDimitry Andric   if (TPC.getTM<TargetMachine>()
3195ffd83dbSDimitry Andric           .getSubtarget<SystemZSubtarget>(F)
3205ffd83dbSDimitry Andric           .hasSoftFloat())
3215ffd83dbSDimitry Andric     return false;
3225ffd83dbSDimitry Andric 
3230b57cec5SDimitry Andric   ConvertedInsts.clear();
3240b57cec5SDimitry Andric   LogicOpsWorklist.clear();
3250b57cec5SDimitry Andric   PossibleJunk.clear();
3260b57cec5SDimitry Andric 
3270b57cec5SDimitry Andric   // Look for icmp+fcmp instructions.
3280b57cec5SDimitry Andric   for (auto &I : instructions(F)) {
3290b57cec5SDimitry Andric     if (I.getOpcode() == Instruction::FCmp)
3300b57cec5SDimitry Andric       convertFCmp(cast<CmpInst>(I));
3310b57cec5SDimitry Andric     else if (I.getOpcode() == Instruction::ICmp)
3320b57cec5SDimitry Andric       convertICmp(cast<CmpInst>(I));
3330b57cec5SDimitry Andric   }
3340b57cec5SDimitry Andric 
3350b57cec5SDimitry Andric   // If none found, bail already.
3360b57cec5SDimitry Andric   if (ConvertedInsts.empty())
3370b57cec5SDimitry Andric     return false;
3380b57cec5SDimitry Andric 
3390b57cec5SDimitry Andric   // Process the queue of logic instructions.
3400b57cec5SDimitry Andric   while (!LogicOpsWorklist.empty()) {
3410b57cec5SDimitry Andric     BinaryOperator *Op = LogicOpsWorklist.back();
3420b57cec5SDimitry Andric     LogicOpsWorklist.pop_back();
3430b57cec5SDimitry Andric     // If both operands mapped, and the instruction itself not yet mapped,
3440b57cec5SDimitry Andric     // convert it.
3450b57cec5SDimitry Andric     if (ConvertedInsts.count(dyn_cast<Instruction>(Op->getOperand(0))) &&
3460b57cec5SDimitry Andric         ConvertedInsts.count(dyn_cast<Instruction>(Op->getOperand(1))) &&
3470b57cec5SDimitry Andric         !ConvertedInsts.count(Op))
3480b57cec5SDimitry Andric       convertLogicOp(*Op);
3490b57cec5SDimitry Andric   }
3500b57cec5SDimitry Andric 
3510b57cec5SDimitry Andric   // Time to actually replace the instructions.  Do it in the reverse order
3520b57cec5SDimitry Andric   // of finding them, since there's a good chance the earlier ones will be
3530b57cec5SDimitry Andric   // unused (due to being folded into later ones).
3540b57cec5SDimitry Andric   Module &M = *F.getParent();
3550b57cec5SDimitry Andric   auto &Ctx = M.getContext();
3560b57cec5SDimitry Andric   Value *Zero32 = ConstantInt::get(Type::getInt32Ty(Ctx), 0);
3570b57cec5SDimitry Andric   bool MadeChange = false;
3580b57cec5SDimitry Andric   for (auto &It : reverse(ConvertedInsts)) {
3590b57cec5SDimitry Andric     Instruction *I = It.first;
3600b57cec5SDimitry Andric     Value *V;
3610b57cec5SDimitry Andric     int Mask;
3620b57cec5SDimitry Andric     bool Worthy;
3630b57cec5SDimitry Andric     std::tie(V, Mask, Worthy) = It.second;
3640b57cec5SDimitry Andric     if (!I->user_empty()) {
3650b57cec5SDimitry Andric       // If used and unworthy of conversion, skip it.
3660b57cec5SDimitry Andric       if (!Worthy)
3670b57cec5SDimitry Andric         continue;
3680b57cec5SDimitry Andric       // Call the intrinsic, compare result with 0.
3690b57cec5SDimitry Andric       Function *TDCFunc =
3700b57cec5SDimitry Andric           Intrinsic::getDeclaration(&M, Intrinsic::s390_tdc, V->getType());
3710b57cec5SDimitry Andric       IRBuilder<> IRB(I);
3720b57cec5SDimitry Andric       Value *MaskVal = ConstantInt::get(Type::getInt64Ty(Ctx), Mask);
3730b57cec5SDimitry Andric       Instruction *TDC = IRB.CreateCall(TDCFunc, {V, MaskVal});
3740b57cec5SDimitry Andric       Value *ICmp = IRB.CreateICmp(CmpInst::ICMP_NE, TDC, Zero32);
3750b57cec5SDimitry Andric       I->replaceAllUsesWith(ICmp);
3760b57cec5SDimitry Andric     }
3770b57cec5SDimitry Andric     // If unused, or used and converted, remove it.
3780b57cec5SDimitry Andric     I->eraseFromParent();
3790b57cec5SDimitry Andric     MadeChange = true;
3800b57cec5SDimitry Andric   }
3810b57cec5SDimitry Andric 
3820b57cec5SDimitry Andric   if (!MadeChange)
3830b57cec5SDimitry Andric     return false;
3840b57cec5SDimitry Andric 
3850b57cec5SDimitry Andric   // We've actually done something - now clear misc accumulated junk (fabs,
3860b57cec5SDimitry Andric   // bitcast).
3870b57cec5SDimitry Andric   for (auto *I : PossibleJunk)
3880b57cec5SDimitry Andric     if (I->user_empty())
3890b57cec5SDimitry Andric       I->eraseFromParent();
3900b57cec5SDimitry Andric 
3910b57cec5SDimitry Andric   return true;
3920b57cec5SDimitry Andric }
393