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