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