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