xref: /freebsd/contrib/llvm-project/llvm/lib/Target/SystemZ/SystemZTDC.cpp (revision 5ffd83dbcc34f10e07f6d3e968ae6365869615f4)
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"
47*5ffd83dbSDimitry Andric #include "SystemZSubtarget.h"
480b57cec5SDimitry Andric #include "llvm/ADT/MapVector.h"
49*5ffd83dbSDimitry 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"
58*5ffd83dbSDimitry 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 llvm {
650b57cec5SDimitry Andric   void initializeSystemZTDCPassPass(PassRegistry&);
660b57cec5SDimitry Andric }
670b57cec5SDimitry Andric 
680b57cec5SDimitry Andric namespace {
690b57cec5SDimitry Andric 
700b57cec5SDimitry Andric class SystemZTDCPass : public FunctionPass {
710b57cec5SDimitry Andric public:
720b57cec5SDimitry Andric   static char ID;
730b57cec5SDimitry Andric   SystemZTDCPass() : FunctionPass(ID) {
740b57cec5SDimitry Andric     initializeSystemZTDCPassPass(*PassRegistry::getPassRegistry());
750b57cec5SDimitry Andric   }
760b57cec5SDimitry Andric 
770b57cec5SDimitry Andric   bool runOnFunction(Function &F) override;
78*5ffd83dbSDimitry Andric 
79*5ffd83dbSDimitry Andric   void getAnalysisUsage(AnalysisUsage &AU) const override {
80*5ffd83dbSDimitry Andric     AU.addRequired<TargetPassConfig>();
81*5ffd83dbSDimitry Andric  }
82*5ffd83dbSDimitry Andric 
830b57cec5SDimitry Andric private:
840b57cec5SDimitry Andric   // Maps seen instructions that can be mapped to a TDC, values are
850b57cec5SDimitry Andric   // (TDC operand, TDC mask, worthy flag) triples.
860b57cec5SDimitry Andric   MapVector<Instruction *, std::tuple<Value *, int, bool>> ConvertedInsts;
870b57cec5SDimitry Andric   // The queue of and/or/xor i1 instructions to be potentially folded.
880b57cec5SDimitry Andric   std::vector<BinaryOperator *> LogicOpsWorklist;
890b57cec5SDimitry Andric   // Instructions matched while folding, to be removed at the end if unused.
900b57cec5SDimitry Andric   std::set<Instruction *> PossibleJunk;
910b57cec5SDimitry Andric 
920b57cec5SDimitry Andric   // Tries to convert a fcmp instruction.
930b57cec5SDimitry Andric   void convertFCmp(CmpInst &I);
940b57cec5SDimitry Andric 
950b57cec5SDimitry Andric   // Tries to convert an icmp instruction.
960b57cec5SDimitry Andric   void convertICmp(CmpInst &I);
970b57cec5SDimitry Andric 
980b57cec5SDimitry Andric   // Tries to convert an i1 and/or/xor instruction, whose both operands
990b57cec5SDimitry Andric   // have been already converted.
1000b57cec5SDimitry Andric   void convertLogicOp(BinaryOperator &I);
1010b57cec5SDimitry Andric 
1020b57cec5SDimitry Andric   // Marks an instruction as converted - adds it to ConvertedInsts and adds
1030b57cec5SDimitry Andric   // any and/or/xor i1 users to the queue.
1040b57cec5SDimitry Andric   void converted(Instruction *I, Value *V, int Mask, bool Worthy) {
1050b57cec5SDimitry Andric     ConvertedInsts[I] = std::make_tuple(V, Mask, Worthy);
1060b57cec5SDimitry Andric     auto &M = *I->getFunction()->getParent();
1070b57cec5SDimitry Andric     auto &Ctx = M.getContext();
1080b57cec5SDimitry Andric     for (auto *U : I->users()) {
1090b57cec5SDimitry Andric       auto *LI = dyn_cast<BinaryOperator>(U);
1100b57cec5SDimitry Andric       if (LI && LI->getType() == Type::getInt1Ty(Ctx) &&
1110b57cec5SDimitry Andric           (LI->getOpcode() == Instruction::And ||
1120b57cec5SDimitry Andric            LI->getOpcode() == Instruction::Or ||
1130b57cec5SDimitry Andric            LI->getOpcode() == Instruction::Xor)) {
1140b57cec5SDimitry Andric         LogicOpsWorklist.push_back(LI);
1150b57cec5SDimitry Andric       }
1160b57cec5SDimitry Andric     }
1170b57cec5SDimitry Andric   }
1180b57cec5SDimitry Andric };
1190b57cec5SDimitry Andric 
1200b57cec5SDimitry Andric } // end anonymous namespace
1210b57cec5SDimitry Andric 
1220b57cec5SDimitry Andric char SystemZTDCPass::ID = 0;
1230b57cec5SDimitry Andric INITIALIZE_PASS(SystemZTDCPass, "systemz-tdc",
1240b57cec5SDimitry Andric                 "SystemZ Test Data Class optimization", false, false)
1250b57cec5SDimitry Andric 
1260b57cec5SDimitry Andric FunctionPass *llvm::createSystemZTDCPass() {
1270b57cec5SDimitry Andric   return new SystemZTDCPass();
1280b57cec5SDimitry Andric }
1290b57cec5SDimitry Andric 
1300b57cec5SDimitry Andric void SystemZTDCPass::convertFCmp(CmpInst &I) {
1310b57cec5SDimitry Andric   Value *Op0 = I.getOperand(0);
1320b57cec5SDimitry Andric   auto *Const = dyn_cast<ConstantFP>(I.getOperand(1));
1330b57cec5SDimitry Andric   auto Pred = I.getPredicate();
1340b57cec5SDimitry Andric   // Only comparisons with consts are interesting.
1350b57cec5SDimitry Andric   if (!Const)
1360b57cec5SDimitry Andric     return;
1370b57cec5SDimitry Andric   // Compute the smallest normal number (and its negation).
1380b57cec5SDimitry Andric   auto &Sem = Op0->getType()->getFltSemantics();
1390b57cec5SDimitry Andric   APFloat Smallest = APFloat::getSmallestNormalized(Sem);
1400b57cec5SDimitry Andric   APFloat NegSmallest = Smallest;
1410b57cec5SDimitry Andric   NegSmallest.changeSign();
1420b57cec5SDimitry Andric   // Check if Const is one of our recognized consts.
1430b57cec5SDimitry Andric   int WhichConst;
1440b57cec5SDimitry Andric   if (Const->isZero()) {
1450b57cec5SDimitry Andric     // All comparisons with 0 can be converted.
1460b57cec5SDimitry Andric     WhichConst = 0;
1470b57cec5SDimitry Andric   } else if (Const->isInfinity()) {
1480b57cec5SDimitry Andric     // Likewise for infinities.
1490b57cec5SDimitry Andric     WhichConst = Const->isNegative() ? 2 : 1;
1500b57cec5SDimitry Andric   } else if (Const->isExactlyValue(Smallest)) {
1510b57cec5SDimitry Andric     // For Smallest, we cannot do EQ separately from GT.
1520b57cec5SDimitry Andric     if ((Pred & CmpInst::FCMP_OGE) != CmpInst::FCMP_OGE &&
1530b57cec5SDimitry Andric         (Pred & CmpInst::FCMP_OGE) != 0)
1540b57cec5SDimitry Andric       return;
1550b57cec5SDimitry Andric     WhichConst = 3;
1560b57cec5SDimitry Andric   } else if (Const->isExactlyValue(NegSmallest)) {
1570b57cec5SDimitry Andric     // Likewise for NegSmallest, we cannot do EQ separately from LT.
1580b57cec5SDimitry Andric     if ((Pred & CmpInst::FCMP_OLE) != CmpInst::FCMP_OLE &&
1590b57cec5SDimitry Andric         (Pred & CmpInst::FCMP_OLE) != 0)
1600b57cec5SDimitry Andric       return;
1610b57cec5SDimitry Andric     WhichConst = 4;
1620b57cec5SDimitry Andric   } else {
1630b57cec5SDimitry Andric     // Not one of our special constants.
1640b57cec5SDimitry Andric     return;
1650b57cec5SDimitry Andric   }
1660b57cec5SDimitry Andric   // Partial masks to use for EQ, GT, LT, UN comparisons, respectively.
1670b57cec5SDimitry Andric   static const int Masks[][4] = {
1680b57cec5SDimitry Andric     { // 0
1690b57cec5SDimitry Andric       SystemZ::TDCMASK_ZERO,              // eq
1700b57cec5SDimitry Andric       SystemZ::TDCMASK_POSITIVE,          // gt
1710b57cec5SDimitry Andric       SystemZ::TDCMASK_NEGATIVE,          // lt
1720b57cec5SDimitry Andric       SystemZ::TDCMASK_NAN,               // un
1730b57cec5SDimitry Andric     },
1740b57cec5SDimitry Andric     { // inf
1750b57cec5SDimitry Andric       SystemZ::TDCMASK_INFINITY_PLUS,     // eq
1760b57cec5SDimitry Andric       0,                                  // gt
1770b57cec5SDimitry Andric       (SystemZ::TDCMASK_ZERO |
1780b57cec5SDimitry Andric        SystemZ::TDCMASK_NEGATIVE |
1790b57cec5SDimitry Andric        SystemZ::TDCMASK_NORMAL_PLUS |
1800b57cec5SDimitry Andric        SystemZ::TDCMASK_SUBNORMAL_PLUS),  // lt
1810b57cec5SDimitry Andric       SystemZ::TDCMASK_NAN,               // un
1820b57cec5SDimitry Andric     },
1830b57cec5SDimitry Andric     { // -inf
1840b57cec5SDimitry Andric       SystemZ::TDCMASK_INFINITY_MINUS,    // eq
1850b57cec5SDimitry Andric       (SystemZ::TDCMASK_ZERO |
1860b57cec5SDimitry Andric        SystemZ::TDCMASK_POSITIVE |
1870b57cec5SDimitry Andric        SystemZ::TDCMASK_NORMAL_MINUS |
1880b57cec5SDimitry Andric        SystemZ::TDCMASK_SUBNORMAL_MINUS), // gt
1890b57cec5SDimitry Andric       0,                                  // lt
1900b57cec5SDimitry Andric       SystemZ::TDCMASK_NAN,               // un
1910b57cec5SDimitry Andric     },
1920b57cec5SDimitry Andric     { // minnorm
1930b57cec5SDimitry Andric       0,                                  // eq (unsupported)
1940b57cec5SDimitry Andric       (SystemZ::TDCMASK_NORMAL_PLUS |
1950b57cec5SDimitry Andric        SystemZ::TDCMASK_INFINITY_PLUS),   // gt (actually ge)
1960b57cec5SDimitry Andric       (SystemZ::TDCMASK_ZERO |
1970b57cec5SDimitry Andric        SystemZ::TDCMASK_NEGATIVE |
1980b57cec5SDimitry Andric        SystemZ::TDCMASK_SUBNORMAL_PLUS),  // lt
1990b57cec5SDimitry Andric       SystemZ::TDCMASK_NAN,               // un
2000b57cec5SDimitry Andric     },
2010b57cec5SDimitry Andric     { // -minnorm
2020b57cec5SDimitry Andric       0,                                  // eq (unsupported)
2030b57cec5SDimitry Andric       (SystemZ::TDCMASK_ZERO |
2040b57cec5SDimitry Andric        SystemZ::TDCMASK_POSITIVE |
2050b57cec5SDimitry Andric        SystemZ::TDCMASK_SUBNORMAL_MINUS), // gt
2060b57cec5SDimitry Andric       (SystemZ::TDCMASK_NORMAL_MINUS |
2070b57cec5SDimitry Andric        SystemZ::TDCMASK_INFINITY_MINUS),  // lt (actually le)
2080b57cec5SDimitry Andric       SystemZ::TDCMASK_NAN,               // un
2090b57cec5SDimitry Andric     }
2100b57cec5SDimitry Andric   };
2110b57cec5SDimitry Andric   // Construct the mask as a combination of the partial masks.
2120b57cec5SDimitry Andric   int Mask = 0;
2130b57cec5SDimitry Andric   if (Pred & CmpInst::FCMP_OEQ)
2140b57cec5SDimitry Andric     Mask |= Masks[WhichConst][0];
2150b57cec5SDimitry Andric   if (Pred & CmpInst::FCMP_OGT)
2160b57cec5SDimitry Andric     Mask |= Masks[WhichConst][1];
2170b57cec5SDimitry Andric   if (Pred & CmpInst::FCMP_OLT)
2180b57cec5SDimitry Andric     Mask |= Masks[WhichConst][2];
2190b57cec5SDimitry Andric   if (Pred & CmpInst::FCMP_UNO)
2200b57cec5SDimitry Andric     Mask |= Masks[WhichConst][3];
2210b57cec5SDimitry Andric   // A lone fcmp is unworthy of tdc conversion on its own, but may become
2220b57cec5SDimitry Andric   // worthy if combined with fabs.
2230b57cec5SDimitry Andric   bool Worthy = false;
2240b57cec5SDimitry Andric   if (CallInst *CI = dyn_cast<CallInst>(Op0)) {
2250b57cec5SDimitry Andric     Function *F = CI->getCalledFunction();
2260b57cec5SDimitry Andric     if (F && F->getIntrinsicID() == Intrinsic::fabs) {
2270b57cec5SDimitry Andric       // Fold with fabs - adjust the mask appropriately.
2280b57cec5SDimitry Andric       Mask &= SystemZ::TDCMASK_PLUS;
2290b57cec5SDimitry Andric       Mask |= Mask >> 1;
2300b57cec5SDimitry Andric       Op0 = CI->getArgOperand(0);
2310b57cec5SDimitry Andric       // A combination of fcmp with fabs is a win, unless the constant
2320b57cec5SDimitry Andric       // involved is 0 (which is handled by later passes).
2330b57cec5SDimitry Andric       Worthy = WhichConst != 0;
2340b57cec5SDimitry Andric       PossibleJunk.insert(CI);
2350b57cec5SDimitry Andric     }
2360b57cec5SDimitry Andric   }
2370b57cec5SDimitry Andric   converted(&I, Op0, Mask, Worthy);
2380b57cec5SDimitry Andric }
2390b57cec5SDimitry Andric 
2400b57cec5SDimitry Andric void SystemZTDCPass::convertICmp(CmpInst &I) {
2410b57cec5SDimitry Andric   Value *Op0 = I.getOperand(0);
2420b57cec5SDimitry Andric   auto *Const = dyn_cast<ConstantInt>(I.getOperand(1));
2430b57cec5SDimitry Andric   auto Pred = I.getPredicate();
2440b57cec5SDimitry Andric   // All our icmp rules involve comparisons with consts.
2450b57cec5SDimitry Andric   if (!Const)
2460b57cec5SDimitry Andric     return;
2470b57cec5SDimitry Andric   if (auto *Cast = dyn_cast<BitCastInst>(Op0)) {
2480b57cec5SDimitry Andric     // Check for icmp+bitcast used for signbit.
2490b57cec5SDimitry Andric     if (!Cast->getSrcTy()->isFloatTy() &&
2500b57cec5SDimitry Andric         !Cast->getSrcTy()->isDoubleTy() &&
2510b57cec5SDimitry Andric         !Cast->getSrcTy()->isFP128Ty())
2520b57cec5SDimitry Andric       return;
2530b57cec5SDimitry Andric     Value *V = Cast->getOperand(0);
2540b57cec5SDimitry Andric     int Mask;
2550b57cec5SDimitry Andric     if (Pred == CmpInst::ICMP_SLT && Const->isZero()) {
2560b57cec5SDimitry Andric       // icmp slt (bitcast X), 0 - set if sign bit true
2570b57cec5SDimitry Andric       Mask = SystemZ::TDCMASK_MINUS;
2580b57cec5SDimitry Andric     } else if (Pred == CmpInst::ICMP_SGT && Const->isMinusOne()) {
2590b57cec5SDimitry Andric       // icmp sgt (bitcast X), -1 - set if sign bit false
2600b57cec5SDimitry Andric       Mask = SystemZ::TDCMASK_PLUS;
2610b57cec5SDimitry Andric     } else {
2620b57cec5SDimitry Andric       // Not a sign bit check.
2630b57cec5SDimitry Andric       return;
2640b57cec5SDimitry Andric     }
2650b57cec5SDimitry Andric     PossibleJunk.insert(Cast);
2660b57cec5SDimitry Andric     converted(&I, V, Mask, true);
2670b57cec5SDimitry Andric   } else if (auto *CI = dyn_cast<CallInst>(Op0)) {
2680b57cec5SDimitry Andric     // Check if this is a pre-existing call of our tdc intrinsic.
2690b57cec5SDimitry Andric     Function *F = CI->getCalledFunction();
2700b57cec5SDimitry Andric     if (!F || F->getIntrinsicID() != Intrinsic::s390_tdc)
2710b57cec5SDimitry Andric       return;
2720b57cec5SDimitry Andric     if (!Const->isZero())
2730b57cec5SDimitry Andric       return;
2740b57cec5SDimitry Andric     Value *V = CI->getArgOperand(0);
2750b57cec5SDimitry Andric     auto *MaskC = dyn_cast<ConstantInt>(CI->getArgOperand(1));
2760b57cec5SDimitry Andric     // Bail if the mask is not a constant.
2770b57cec5SDimitry Andric     if (!MaskC)
2780b57cec5SDimitry Andric       return;
2790b57cec5SDimitry Andric     int Mask = MaskC->getZExtValue();
2800b57cec5SDimitry Andric     Mask &= SystemZ::TDCMASK_ALL;
2810b57cec5SDimitry Andric     if (Pred == CmpInst::ICMP_NE) {
2820b57cec5SDimitry Andric       // icmp ne (call llvm.s390.tdc(...)), 0 -> simple TDC
2830b57cec5SDimitry Andric     } else if (Pred == CmpInst::ICMP_EQ) {
2840b57cec5SDimitry Andric       // icmp eq (call llvm.s390.tdc(...)), 0 -> TDC with inverted mask
2850b57cec5SDimitry Andric       Mask ^= SystemZ::TDCMASK_ALL;
2860b57cec5SDimitry Andric     } else {
2870b57cec5SDimitry Andric       // An unknown comparison - ignore.
2880b57cec5SDimitry Andric       return;
2890b57cec5SDimitry Andric     }
2900b57cec5SDimitry Andric     PossibleJunk.insert(CI);
2910b57cec5SDimitry Andric     converted(&I, V, Mask, false);
2920b57cec5SDimitry Andric   }
2930b57cec5SDimitry Andric }
2940b57cec5SDimitry Andric 
2950b57cec5SDimitry Andric void SystemZTDCPass::convertLogicOp(BinaryOperator &I) {
2960b57cec5SDimitry Andric   Value *Op0, *Op1;
2970b57cec5SDimitry Andric   int Mask0, Mask1;
2980b57cec5SDimitry Andric   bool Worthy0, Worthy1;
2990b57cec5SDimitry Andric   std::tie(Op0, Mask0, Worthy0) = ConvertedInsts[cast<Instruction>(I.getOperand(0))];
3000b57cec5SDimitry Andric   std::tie(Op1, Mask1, Worthy1) = ConvertedInsts[cast<Instruction>(I.getOperand(1))];
3010b57cec5SDimitry Andric   if (Op0 != Op1)
3020b57cec5SDimitry Andric     return;
3030b57cec5SDimitry Andric   int Mask;
3040b57cec5SDimitry Andric   switch (I.getOpcode()) {
3050b57cec5SDimitry Andric     case Instruction::And:
3060b57cec5SDimitry Andric       Mask = Mask0 & Mask1;
3070b57cec5SDimitry Andric       break;
3080b57cec5SDimitry Andric     case Instruction::Or:
3090b57cec5SDimitry Andric       Mask = Mask0 | Mask1;
3100b57cec5SDimitry Andric       break;
3110b57cec5SDimitry Andric     case Instruction::Xor:
3120b57cec5SDimitry Andric       Mask = Mask0 ^ Mask1;
3130b57cec5SDimitry Andric       break;
3140b57cec5SDimitry Andric     default:
3150b57cec5SDimitry Andric       llvm_unreachable("Unknown op in convertLogicOp");
3160b57cec5SDimitry Andric   }
3170b57cec5SDimitry Andric   converted(&I, Op0, Mask, true);
3180b57cec5SDimitry Andric }
3190b57cec5SDimitry Andric 
3200b57cec5SDimitry Andric bool SystemZTDCPass::runOnFunction(Function &F) {
321*5ffd83dbSDimitry Andric   auto &TPC = getAnalysis<TargetPassConfig>();
322*5ffd83dbSDimitry Andric   if (TPC.getTM<TargetMachine>()
323*5ffd83dbSDimitry Andric           .getSubtarget<SystemZSubtarget>(F)
324*5ffd83dbSDimitry Andric           .hasSoftFloat())
325*5ffd83dbSDimitry Andric     return false;
326*5ffd83dbSDimitry Andric 
3270b57cec5SDimitry Andric   ConvertedInsts.clear();
3280b57cec5SDimitry Andric   LogicOpsWorklist.clear();
3290b57cec5SDimitry Andric   PossibleJunk.clear();
3300b57cec5SDimitry Andric 
3310b57cec5SDimitry Andric   // Look for icmp+fcmp instructions.
3320b57cec5SDimitry Andric   for (auto &I : instructions(F)) {
3330b57cec5SDimitry Andric     if (I.getOpcode() == Instruction::FCmp)
3340b57cec5SDimitry Andric       convertFCmp(cast<CmpInst>(I));
3350b57cec5SDimitry Andric     else if (I.getOpcode() == Instruction::ICmp)
3360b57cec5SDimitry Andric       convertICmp(cast<CmpInst>(I));
3370b57cec5SDimitry Andric   }
3380b57cec5SDimitry Andric 
3390b57cec5SDimitry Andric   // If none found, bail already.
3400b57cec5SDimitry Andric   if (ConvertedInsts.empty())
3410b57cec5SDimitry Andric     return false;
3420b57cec5SDimitry Andric 
3430b57cec5SDimitry Andric   // Process the queue of logic instructions.
3440b57cec5SDimitry Andric   while (!LogicOpsWorklist.empty()) {
3450b57cec5SDimitry Andric     BinaryOperator *Op = LogicOpsWorklist.back();
3460b57cec5SDimitry Andric     LogicOpsWorklist.pop_back();
3470b57cec5SDimitry Andric     // If both operands mapped, and the instruction itself not yet mapped,
3480b57cec5SDimitry Andric     // convert it.
3490b57cec5SDimitry Andric     if (ConvertedInsts.count(dyn_cast<Instruction>(Op->getOperand(0))) &&
3500b57cec5SDimitry Andric         ConvertedInsts.count(dyn_cast<Instruction>(Op->getOperand(1))) &&
3510b57cec5SDimitry Andric         !ConvertedInsts.count(Op))
3520b57cec5SDimitry Andric       convertLogicOp(*Op);
3530b57cec5SDimitry Andric   }
3540b57cec5SDimitry Andric 
3550b57cec5SDimitry Andric   // Time to actually replace the instructions.  Do it in the reverse order
3560b57cec5SDimitry Andric   // of finding them, since there's a good chance the earlier ones will be
3570b57cec5SDimitry Andric   // unused (due to being folded into later ones).
3580b57cec5SDimitry Andric   Module &M = *F.getParent();
3590b57cec5SDimitry Andric   auto &Ctx = M.getContext();
3600b57cec5SDimitry Andric   Value *Zero32 = ConstantInt::get(Type::getInt32Ty(Ctx), 0);
3610b57cec5SDimitry Andric   bool MadeChange = false;
3620b57cec5SDimitry Andric   for (auto &It : reverse(ConvertedInsts)) {
3630b57cec5SDimitry Andric     Instruction *I = It.first;
3640b57cec5SDimitry Andric     Value *V;
3650b57cec5SDimitry Andric     int Mask;
3660b57cec5SDimitry Andric     bool Worthy;
3670b57cec5SDimitry Andric     std::tie(V, Mask, Worthy) = It.second;
3680b57cec5SDimitry Andric     if (!I->user_empty()) {
3690b57cec5SDimitry Andric       // If used and unworthy of conversion, skip it.
3700b57cec5SDimitry Andric       if (!Worthy)
3710b57cec5SDimitry Andric         continue;
3720b57cec5SDimitry Andric       // Call the intrinsic, compare result with 0.
3730b57cec5SDimitry Andric       Function *TDCFunc =
3740b57cec5SDimitry Andric           Intrinsic::getDeclaration(&M, Intrinsic::s390_tdc, V->getType());
3750b57cec5SDimitry Andric       IRBuilder<> IRB(I);
3760b57cec5SDimitry Andric       Value *MaskVal = ConstantInt::get(Type::getInt64Ty(Ctx), Mask);
3770b57cec5SDimitry Andric       Instruction *TDC = IRB.CreateCall(TDCFunc, {V, MaskVal});
3780b57cec5SDimitry Andric       Value *ICmp = IRB.CreateICmp(CmpInst::ICMP_NE, TDC, Zero32);
3790b57cec5SDimitry Andric       I->replaceAllUsesWith(ICmp);
3800b57cec5SDimitry Andric     }
3810b57cec5SDimitry Andric     // If unused, or used and converted, remove it.
3820b57cec5SDimitry Andric     I->eraseFromParent();
3830b57cec5SDimitry Andric     MadeChange = true;
3840b57cec5SDimitry Andric   }
3850b57cec5SDimitry Andric 
3860b57cec5SDimitry Andric   if (!MadeChange)
3870b57cec5SDimitry Andric     return false;
3880b57cec5SDimitry Andric 
3890b57cec5SDimitry Andric   // We've actually done something - now clear misc accumulated junk (fabs,
3900b57cec5SDimitry Andric   // bitcast).
3910b57cec5SDimitry Andric   for (auto *I : PossibleJunk)
3920b57cec5SDimitry Andric     if (I->user_empty())
3930b57cec5SDimitry Andric       I->eraseFromParent();
3940b57cec5SDimitry Andric 
3950b57cec5SDimitry Andric   return true;
3960b57cec5SDimitry Andric }
397