1*0b57cec5SDimitry Andric //===-- SystemZTDC.cpp - Utilize Test Data Class instruction --------------===// 2*0b57cec5SDimitry Andric // 3*0b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4*0b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 5*0b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6*0b57cec5SDimitry Andric // 7*0b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 8*0b57cec5SDimitry Andric // 9*0b57cec5SDimitry Andric // This pass looks for instructions that can be replaced by a Test Data Class 10*0b57cec5SDimitry Andric // instruction, and replaces them when profitable. 11*0b57cec5SDimitry Andric // 12*0b57cec5SDimitry Andric // Roughly, the following rules are recognized: 13*0b57cec5SDimitry Andric // 14*0b57cec5SDimitry Andric // 1: fcmp pred X, 0 -> tdc X, mask 15*0b57cec5SDimitry Andric // 2: fcmp pred X, +-inf -> tdc X, mask 16*0b57cec5SDimitry Andric // 3: fcmp pred X, +-minnorm -> tdc X, mask 17*0b57cec5SDimitry Andric // 4: tdc (fabs X), mask -> tdc X, newmask 18*0b57cec5SDimitry Andric // 5: icmp slt (bitcast float X to int), 0 -> tdc X, mask [ie. signbit] 19*0b57cec5SDimitry Andric // 6: icmp sgt (bitcast float X to int), -1 -> tdc X, mask 20*0b57cec5SDimitry Andric // 7: icmp ne/eq (call @llvm.s390.tdc.*(X, mask)) -> tdc X, mask/~mask 21*0b57cec5SDimitry Andric // 8: and i1 (tdc X, M1), (tdc X, M2) -> tdc X, (M1 & M2) 22*0b57cec5SDimitry Andric // 9: or i1 (tdc X, M1), (tdc X, M2) -> tdc X, (M1 | M2) 23*0b57cec5SDimitry Andric // 10: xor i1 (tdc X, M1), (tdc X, M2) -> tdc X, (M1 ^ M2) 24*0b57cec5SDimitry Andric // 25*0b57cec5SDimitry Andric // The pass works in 4 steps: 26*0b57cec5SDimitry Andric // 27*0b57cec5SDimitry Andric // 1. All fcmp and icmp instructions in a function are checked for a match 28*0b57cec5SDimitry Andric // with rules 1-3 and 5-7. Their TDC equivalents are stored in 29*0b57cec5SDimitry Andric // the ConvertedInsts mapping. If the operand of a fcmp instruction is 30*0b57cec5SDimitry Andric // a fabs, it's also folded according to rule 4. 31*0b57cec5SDimitry Andric // 2. All and/or/xor i1 instructions whose both operands have been already 32*0b57cec5SDimitry Andric // mapped are mapped according to rules 8-10. LogicOpsWorklist is used 33*0b57cec5SDimitry Andric // as a queue of instructions to check. 34*0b57cec5SDimitry Andric // 3. All mapped instructions that are considered worthy of conversion (ie. 35*0b57cec5SDimitry Andric // replacing them will actually simplify the final code) are replaced 36*0b57cec5SDimitry Andric // with a call to the s390.tdc intrinsic. 37*0b57cec5SDimitry Andric // 4. All intermediate results of replaced instructions are removed if unused. 38*0b57cec5SDimitry Andric // 39*0b57cec5SDimitry Andric // Instructions that match rules 1-3 are considered unworthy of conversion 40*0b57cec5SDimitry Andric // on their own (since a comparison instruction is superior), but are mapped 41*0b57cec5SDimitry Andric // in the hopes of folding the result using rules 4 and 8-10 (likely removing 42*0b57cec5SDimitry Andric // the original comparison in the process). 43*0b57cec5SDimitry Andric // 44*0b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 45*0b57cec5SDimitry Andric 46*0b57cec5SDimitry Andric #include "SystemZ.h" 47*0b57cec5SDimitry Andric #include "llvm/ADT/MapVector.h" 48*0b57cec5SDimitry Andric #include "llvm/IR/Constants.h" 49*0b57cec5SDimitry Andric #include "llvm/IR/IRBuilder.h" 50*0b57cec5SDimitry Andric #include "llvm/IR/InstIterator.h" 51*0b57cec5SDimitry Andric #include "llvm/IR/Instructions.h" 52*0b57cec5SDimitry Andric #include "llvm/IR/IntrinsicInst.h" 53*0b57cec5SDimitry Andric #include "llvm/IR/LegacyPassManager.h" 54*0b57cec5SDimitry Andric #include "llvm/IR/Module.h" 55*0b57cec5SDimitry Andric #include <deque> 56*0b57cec5SDimitry Andric #include <set> 57*0b57cec5SDimitry Andric 58*0b57cec5SDimitry Andric using namespace llvm; 59*0b57cec5SDimitry Andric 60*0b57cec5SDimitry Andric namespace llvm { 61*0b57cec5SDimitry Andric void initializeSystemZTDCPassPass(PassRegistry&); 62*0b57cec5SDimitry Andric } 63*0b57cec5SDimitry Andric 64*0b57cec5SDimitry Andric namespace { 65*0b57cec5SDimitry Andric 66*0b57cec5SDimitry Andric class SystemZTDCPass : public FunctionPass { 67*0b57cec5SDimitry Andric public: 68*0b57cec5SDimitry Andric static char ID; 69*0b57cec5SDimitry Andric SystemZTDCPass() : FunctionPass(ID) { 70*0b57cec5SDimitry Andric initializeSystemZTDCPassPass(*PassRegistry::getPassRegistry()); 71*0b57cec5SDimitry Andric } 72*0b57cec5SDimitry Andric 73*0b57cec5SDimitry Andric bool runOnFunction(Function &F) override; 74*0b57cec5SDimitry Andric private: 75*0b57cec5SDimitry Andric // Maps seen instructions that can be mapped to a TDC, values are 76*0b57cec5SDimitry Andric // (TDC operand, TDC mask, worthy flag) triples. 77*0b57cec5SDimitry Andric MapVector<Instruction *, std::tuple<Value *, int, bool>> ConvertedInsts; 78*0b57cec5SDimitry Andric // The queue of and/or/xor i1 instructions to be potentially folded. 79*0b57cec5SDimitry Andric std::vector<BinaryOperator *> LogicOpsWorklist; 80*0b57cec5SDimitry Andric // Instructions matched while folding, to be removed at the end if unused. 81*0b57cec5SDimitry Andric std::set<Instruction *> PossibleJunk; 82*0b57cec5SDimitry Andric 83*0b57cec5SDimitry Andric // Tries to convert a fcmp instruction. 84*0b57cec5SDimitry Andric void convertFCmp(CmpInst &I); 85*0b57cec5SDimitry Andric 86*0b57cec5SDimitry Andric // Tries to convert an icmp instruction. 87*0b57cec5SDimitry Andric void convertICmp(CmpInst &I); 88*0b57cec5SDimitry Andric 89*0b57cec5SDimitry Andric // Tries to convert an i1 and/or/xor instruction, whose both operands 90*0b57cec5SDimitry Andric // have been already converted. 91*0b57cec5SDimitry Andric void convertLogicOp(BinaryOperator &I); 92*0b57cec5SDimitry Andric 93*0b57cec5SDimitry Andric // Marks an instruction as converted - adds it to ConvertedInsts and adds 94*0b57cec5SDimitry Andric // any and/or/xor i1 users to the queue. 95*0b57cec5SDimitry Andric void converted(Instruction *I, Value *V, int Mask, bool Worthy) { 96*0b57cec5SDimitry Andric ConvertedInsts[I] = std::make_tuple(V, Mask, Worthy); 97*0b57cec5SDimitry Andric auto &M = *I->getFunction()->getParent(); 98*0b57cec5SDimitry Andric auto &Ctx = M.getContext(); 99*0b57cec5SDimitry Andric for (auto *U : I->users()) { 100*0b57cec5SDimitry Andric auto *LI = dyn_cast<BinaryOperator>(U); 101*0b57cec5SDimitry Andric if (LI && LI->getType() == Type::getInt1Ty(Ctx) && 102*0b57cec5SDimitry Andric (LI->getOpcode() == Instruction::And || 103*0b57cec5SDimitry Andric LI->getOpcode() == Instruction::Or || 104*0b57cec5SDimitry Andric LI->getOpcode() == Instruction::Xor)) { 105*0b57cec5SDimitry Andric LogicOpsWorklist.push_back(LI); 106*0b57cec5SDimitry Andric } 107*0b57cec5SDimitry Andric } 108*0b57cec5SDimitry Andric } 109*0b57cec5SDimitry Andric }; 110*0b57cec5SDimitry Andric 111*0b57cec5SDimitry Andric } // end anonymous namespace 112*0b57cec5SDimitry Andric 113*0b57cec5SDimitry Andric char SystemZTDCPass::ID = 0; 114*0b57cec5SDimitry Andric INITIALIZE_PASS(SystemZTDCPass, "systemz-tdc", 115*0b57cec5SDimitry Andric "SystemZ Test Data Class optimization", false, false) 116*0b57cec5SDimitry Andric 117*0b57cec5SDimitry Andric FunctionPass *llvm::createSystemZTDCPass() { 118*0b57cec5SDimitry Andric return new SystemZTDCPass(); 119*0b57cec5SDimitry Andric } 120*0b57cec5SDimitry Andric 121*0b57cec5SDimitry Andric void SystemZTDCPass::convertFCmp(CmpInst &I) { 122*0b57cec5SDimitry Andric Value *Op0 = I.getOperand(0); 123*0b57cec5SDimitry Andric auto *Const = dyn_cast<ConstantFP>(I.getOperand(1)); 124*0b57cec5SDimitry Andric auto Pred = I.getPredicate(); 125*0b57cec5SDimitry Andric // Only comparisons with consts are interesting. 126*0b57cec5SDimitry Andric if (!Const) 127*0b57cec5SDimitry Andric return; 128*0b57cec5SDimitry Andric // Compute the smallest normal number (and its negation). 129*0b57cec5SDimitry Andric auto &Sem = Op0->getType()->getFltSemantics(); 130*0b57cec5SDimitry Andric APFloat Smallest = APFloat::getSmallestNormalized(Sem); 131*0b57cec5SDimitry Andric APFloat NegSmallest = Smallest; 132*0b57cec5SDimitry Andric NegSmallest.changeSign(); 133*0b57cec5SDimitry Andric // Check if Const is one of our recognized consts. 134*0b57cec5SDimitry Andric int WhichConst; 135*0b57cec5SDimitry Andric if (Const->isZero()) { 136*0b57cec5SDimitry Andric // All comparisons with 0 can be converted. 137*0b57cec5SDimitry Andric WhichConst = 0; 138*0b57cec5SDimitry Andric } else if (Const->isInfinity()) { 139*0b57cec5SDimitry Andric // Likewise for infinities. 140*0b57cec5SDimitry Andric WhichConst = Const->isNegative() ? 2 : 1; 141*0b57cec5SDimitry Andric } else if (Const->isExactlyValue(Smallest)) { 142*0b57cec5SDimitry Andric // For Smallest, we cannot do EQ separately from GT. 143*0b57cec5SDimitry Andric if ((Pred & CmpInst::FCMP_OGE) != CmpInst::FCMP_OGE && 144*0b57cec5SDimitry Andric (Pred & CmpInst::FCMP_OGE) != 0) 145*0b57cec5SDimitry Andric return; 146*0b57cec5SDimitry Andric WhichConst = 3; 147*0b57cec5SDimitry Andric } else if (Const->isExactlyValue(NegSmallest)) { 148*0b57cec5SDimitry Andric // Likewise for NegSmallest, we cannot do EQ separately from LT. 149*0b57cec5SDimitry Andric if ((Pred & CmpInst::FCMP_OLE) != CmpInst::FCMP_OLE && 150*0b57cec5SDimitry Andric (Pred & CmpInst::FCMP_OLE) != 0) 151*0b57cec5SDimitry Andric return; 152*0b57cec5SDimitry Andric WhichConst = 4; 153*0b57cec5SDimitry Andric } else { 154*0b57cec5SDimitry Andric // Not one of our special constants. 155*0b57cec5SDimitry Andric return; 156*0b57cec5SDimitry Andric } 157*0b57cec5SDimitry Andric // Partial masks to use for EQ, GT, LT, UN comparisons, respectively. 158*0b57cec5SDimitry Andric static const int Masks[][4] = { 159*0b57cec5SDimitry Andric { // 0 160*0b57cec5SDimitry Andric SystemZ::TDCMASK_ZERO, // eq 161*0b57cec5SDimitry Andric SystemZ::TDCMASK_POSITIVE, // gt 162*0b57cec5SDimitry Andric SystemZ::TDCMASK_NEGATIVE, // lt 163*0b57cec5SDimitry Andric SystemZ::TDCMASK_NAN, // un 164*0b57cec5SDimitry Andric }, 165*0b57cec5SDimitry Andric { // inf 166*0b57cec5SDimitry Andric SystemZ::TDCMASK_INFINITY_PLUS, // eq 167*0b57cec5SDimitry Andric 0, // gt 168*0b57cec5SDimitry Andric (SystemZ::TDCMASK_ZERO | 169*0b57cec5SDimitry Andric SystemZ::TDCMASK_NEGATIVE | 170*0b57cec5SDimitry Andric SystemZ::TDCMASK_NORMAL_PLUS | 171*0b57cec5SDimitry Andric SystemZ::TDCMASK_SUBNORMAL_PLUS), // lt 172*0b57cec5SDimitry Andric SystemZ::TDCMASK_NAN, // un 173*0b57cec5SDimitry Andric }, 174*0b57cec5SDimitry Andric { // -inf 175*0b57cec5SDimitry Andric SystemZ::TDCMASK_INFINITY_MINUS, // eq 176*0b57cec5SDimitry Andric (SystemZ::TDCMASK_ZERO | 177*0b57cec5SDimitry Andric SystemZ::TDCMASK_POSITIVE | 178*0b57cec5SDimitry Andric SystemZ::TDCMASK_NORMAL_MINUS | 179*0b57cec5SDimitry Andric SystemZ::TDCMASK_SUBNORMAL_MINUS), // gt 180*0b57cec5SDimitry Andric 0, // lt 181*0b57cec5SDimitry Andric SystemZ::TDCMASK_NAN, // un 182*0b57cec5SDimitry Andric }, 183*0b57cec5SDimitry Andric { // minnorm 184*0b57cec5SDimitry Andric 0, // eq (unsupported) 185*0b57cec5SDimitry Andric (SystemZ::TDCMASK_NORMAL_PLUS | 186*0b57cec5SDimitry Andric SystemZ::TDCMASK_INFINITY_PLUS), // gt (actually ge) 187*0b57cec5SDimitry Andric (SystemZ::TDCMASK_ZERO | 188*0b57cec5SDimitry Andric SystemZ::TDCMASK_NEGATIVE | 189*0b57cec5SDimitry Andric SystemZ::TDCMASK_SUBNORMAL_PLUS), // lt 190*0b57cec5SDimitry Andric SystemZ::TDCMASK_NAN, // un 191*0b57cec5SDimitry Andric }, 192*0b57cec5SDimitry Andric { // -minnorm 193*0b57cec5SDimitry Andric 0, // eq (unsupported) 194*0b57cec5SDimitry Andric (SystemZ::TDCMASK_ZERO | 195*0b57cec5SDimitry Andric SystemZ::TDCMASK_POSITIVE | 196*0b57cec5SDimitry Andric SystemZ::TDCMASK_SUBNORMAL_MINUS), // gt 197*0b57cec5SDimitry Andric (SystemZ::TDCMASK_NORMAL_MINUS | 198*0b57cec5SDimitry Andric SystemZ::TDCMASK_INFINITY_MINUS), // lt (actually le) 199*0b57cec5SDimitry Andric SystemZ::TDCMASK_NAN, // un 200*0b57cec5SDimitry Andric } 201*0b57cec5SDimitry Andric }; 202*0b57cec5SDimitry Andric // Construct the mask as a combination of the partial masks. 203*0b57cec5SDimitry Andric int Mask = 0; 204*0b57cec5SDimitry Andric if (Pred & CmpInst::FCMP_OEQ) 205*0b57cec5SDimitry Andric Mask |= Masks[WhichConst][0]; 206*0b57cec5SDimitry Andric if (Pred & CmpInst::FCMP_OGT) 207*0b57cec5SDimitry Andric Mask |= Masks[WhichConst][1]; 208*0b57cec5SDimitry Andric if (Pred & CmpInst::FCMP_OLT) 209*0b57cec5SDimitry Andric Mask |= Masks[WhichConst][2]; 210*0b57cec5SDimitry Andric if (Pred & CmpInst::FCMP_UNO) 211*0b57cec5SDimitry Andric Mask |= Masks[WhichConst][3]; 212*0b57cec5SDimitry Andric // A lone fcmp is unworthy of tdc conversion on its own, but may become 213*0b57cec5SDimitry Andric // worthy if combined with fabs. 214*0b57cec5SDimitry Andric bool Worthy = false; 215*0b57cec5SDimitry Andric if (CallInst *CI = dyn_cast<CallInst>(Op0)) { 216*0b57cec5SDimitry Andric Function *F = CI->getCalledFunction(); 217*0b57cec5SDimitry Andric if (F && F->getIntrinsicID() == Intrinsic::fabs) { 218*0b57cec5SDimitry Andric // Fold with fabs - adjust the mask appropriately. 219*0b57cec5SDimitry Andric Mask &= SystemZ::TDCMASK_PLUS; 220*0b57cec5SDimitry Andric Mask |= Mask >> 1; 221*0b57cec5SDimitry Andric Op0 = CI->getArgOperand(0); 222*0b57cec5SDimitry Andric // A combination of fcmp with fabs is a win, unless the constant 223*0b57cec5SDimitry Andric // involved is 0 (which is handled by later passes). 224*0b57cec5SDimitry Andric Worthy = WhichConst != 0; 225*0b57cec5SDimitry Andric PossibleJunk.insert(CI); 226*0b57cec5SDimitry Andric } 227*0b57cec5SDimitry Andric } 228*0b57cec5SDimitry Andric converted(&I, Op0, Mask, Worthy); 229*0b57cec5SDimitry Andric } 230*0b57cec5SDimitry Andric 231*0b57cec5SDimitry Andric void SystemZTDCPass::convertICmp(CmpInst &I) { 232*0b57cec5SDimitry Andric Value *Op0 = I.getOperand(0); 233*0b57cec5SDimitry Andric auto *Const = dyn_cast<ConstantInt>(I.getOperand(1)); 234*0b57cec5SDimitry Andric auto Pred = I.getPredicate(); 235*0b57cec5SDimitry Andric // All our icmp rules involve comparisons with consts. 236*0b57cec5SDimitry Andric if (!Const) 237*0b57cec5SDimitry Andric return; 238*0b57cec5SDimitry Andric if (auto *Cast = dyn_cast<BitCastInst>(Op0)) { 239*0b57cec5SDimitry Andric // Check for icmp+bitcast used for signbit. 240*0b57cec5SDimitry Andric if (!Cast->getSrcTy()->isFloatTy() && 241*0b57cec5SDimitry Andric !Cast->getSrcTy()->isDoubleTy() && 242*0b57cec5SDimitry Andric !Cast->getSrcTy()->isFP128Ty()) 243*0b57cec5SDimitry Andric return; 244*0b57cec5SDimitry Andric Value *V = Cast->getOperand(0); 245*0b57cec5SDimitry Andric int Mask; 246*0b57cec5SDimitry Andric if (Pred == CmpInst::ICMP_SLT && Const->isZero()) { 247*0b57cec5SDimitry Andric // icmp slt (bitcast X), 0 - set if sign bit true 248*0b57cec5SDimitry Andric Mask = SystemZ::TDCMASK_MINUS; 249*0b57cec5SDimitry Andric } else if (Pred == CmpInst::ICMP_SGT && Const->isMinusOne()) { 250*0b57cec5SDimitry Andric // icmp sgt (bitcast X), -1 - set if sign bit false 251*0b57cec5SDimitry Andric Mask = SystemZ::TDCMASK_PLUS; 252*0b57cec5SDimitry Andric } else { 253*0b57cec5SDimitry Andric // Not a sign bit check. 254*0b57cec5SDimitry Andric return; 255*0b57cec5SDimitry Andric } 256*0b57cec5SDimitry Andric PossibleJunk.insert(Cast); 257*0b57cec5SDimitry Andric converted(&I, V, Mask, true); 258*0b57cec5SDimitry Andric } else if (auto *CI = dyn_cast<CallInst>(Op0)) { 259*0b57cec5SDimitry Andric // Check if this is a pre-existing call of our tdc intrinsic. 260*0b57cec5SDimitry Andric Function *F = CI->getCalledFunction(); 261*0b57cec5SDimitry Andric if (!F || F->getIntrinsicID() != Intrinsic::s390_tdc) 262*0b57cec5SDimitry Andric return; 263*0b57cec5SDimitry Andric if (!Const->isZero()) 264*0b57cec5SDimitry Andric return; 265*0b57cec5SDimitry Andric Value *V = CI->getArgOperand(0); 266*0b57cec5SDimitry Andric auto *MaskC = dyn_cast<ConstantInt>(CI->getArgOperand(1)); 267*0b57cec5SDimitry Andric // Bail if the mask is not a constant. 268*0b57cec5SDimitry Andric if (!MaskC) 269*0b57cec5SDimitry Andric return; 270*0b57cec5SDimitry Andric int Mask = MaskC->getZExtValue(); 271*0b57cec5SDimitry Andric Mask &= SystemZ::TDCMASK_ALL; 272*0b57cec5SDimitry Andric if (Pred == CmpInst::ICMP_NE) { 273*0b57cec5SDimitry Andric // icmp ne (call llvm.s390.tdc(...)), 0 -> simple TDC 274*0b57cec5SDimitry Andric } else if (Pred == CmpInst::ICMP_EQ) { 275*0b57cec5SDimitry Andric // icmp eq (call llvm.s390.tdc(...)), 0 -> TDC with inverted mask 276*0b57cec5SDimitry Andric Mask ^= SystemZ::TDCMASK_ALL; 277*0b57cec5SDimitry Andric } else { 278*0b57cec5SDimitry Andric // An unknown comparison - ignore. 279*0b57cec5SDimitry Andric return; 280*0b57cec5SDimitry Andric } 281*0b57cec5SDimitry Andric PossibleJunk.insert(CI); 282*0b57cec5SDimitry Andric converted(&I, V, Mask, false); 283*0b57cec5SDimitry Andric } 284*0b57cec5SDimitry Andric } 285*0b57cec5SDimitry Andric 286*0b57cec5SDimitry Andric void SystemZTDCPass::convertLogicOp(BinaryOperator &I) { 287*0b57cec5SDimitry Andric Value *Op0, *Op1; 288*0b57cec5SDimitry Andric int Mask0, Mask1; 289*0b57cec5SDimitry Andric bool Worthy0, Worthy1; 290*0b57cec5SDimitry Andric std::tie(Op0, Mask0, Worthy0) = ConvertedInsts[cast<Instruction>(I.getOperand(0))]; 291*0b57cec5SDimitry Andric std::tie(Op1, Mask1, Worthy1) = ConvertedInsts[cast<Instruction>(I.getOperand(1))]; 292*0b57cec5SDimitry Andric if (Op0 != Op1) 293*0b57cec5SDimitry Andric return; 294*0b57cec5SDimitry Andric int Mask; 295*0b57cec5SDimitry Andric switch (I.getOpcode()) { 296*0b57cec5SDimitry Andric case Instruction::And: 297*0b57cec5SDimitry Andric Mask = Mask0 & Mask1; 298*0b57cec5SDimitry Andric break; 299*0b57cec5SDimitry Andric case Instruction::Or: 300*0b57cec5SDimitry Andric Mask = Mask0 | Mask1; 301*0b57cec5SDimitry Andric break; 302*0b57cec5SDimitry Andric case Instruction::Xor: 303*0b57cec5SDimitry Andric Mask = Mask0 ^ Mask1; 304*0b57cec5SDimitry Andric break; 305*0b57cec5SDimitry Andric default: 306*0b57cec5SDimitry Andric llvm_unreachable("Unknown op in convertLogicOp"); 307*0b57cec5SDimitry Andric } 308*0b57cec5SDimitry Andric converted(&I, Op0, Mask, true); 309*0b57cec5SDimitry Andric } 310*0b57cec5SDimitry Andric 311*0b57cec5SDimitry Andric bool SystemZTDCPass::runOnFunction(Function &F) { 312*0b57cec5SDimitry Andric ConvertedInsts.clear(); 313*0b57cec5SDimitry Andric LogicOpsWorklist.clear(); 314*0b57cec5SDimitry Andric PossibleJunk.clear(); 315*0b57cec5SDimitry Andric 316*0b57cec5SDimitry Andric // Look for icmp+fcmp instructions. 317*0b57cec5SDimitry Andric for (auto &I : instructions(F)) { 318*0b57cec5SDimitry Andric if (I.getOpcode() == Instruction::FCmp) 319*0b57cec5SDimitry Andric convertFCmp(cast<CmpInst>(I)); 320*0b57cec5SDimitry Andric else if (I.getOpcode() == Instruction::ICmp) 321*0b57cec5SDimitry Andric convertICmp(cast<CmpInst>(I)); 322*0b57cec5SDimitry Andric } 323*0b57cec5SDimitry Andric 324*0b57cec5SDimitry Andric // If none found, bail already. 325*0b57cec5SDimitry Andric if (ConvertedInsts.empty()) 326*0b57cec5SDimitry Andric return false; 327*0b57cec5SDimitry Andric 328*0b57cec5SDimitry Andric // Process the queue of logic instructions. 329*0b57cec5SDimitry Andric while (!LogicOpsWorklist.empty()) { 330*0b57cec5SDimitry Andric BinaryOperator *Op = LogicOpsWorklist.back(); 331*0b57cec5SDimitry Andric LogicOpsWorklist.pop_back(); 332*0b57cec5SDimitry Andric // If both operands mapped, and the instruction itself not yet mapped, 333*0b57cec5SDimitry Andric // convert it. 334*0b57cec5SDimitry Andric if (ConvertedInsts.count(dyn_cast<Instruction>(Op->getOperand(0))) && 335*0b57cec5SDimitry Andric ConvertedInsts.count(dyn_cast<Instruction>(Op->getOperand(1))) && 336*0b57cec5SDimitry Andric !ConvertedInsts.count(Op)) 337*0b57cec5SDimitry Andric convertLogicOp(*Op); 338*0b57cec5SDimitry Andric } 339*0b57cec5SDimitry Andric 340*0b57cec5SDimitry Andric // Time to actually replace the instructions. Do it in the reverse order 341*0b57cec5SDimitry Andric // of finding them, since there's a good chance the earlier ones will be 342*0b57cec5SDimitry Andric // unused (due to being folded into later ones). 343*0b57cec5SDimitry Andric Module &M = *F.getParent(); 344*0b57cec5SDimitry Andric auto &Ctx = M.getContext(); 345*0b57cec5SDimitry Andric Value *Zero32 = ConstantInt::get(Type::getInt32Ty(Ctx), 0); 346*0b57cec5SDimitry Andric bool MadeChange = false; 347*0b57cec5SDimitry Andric for (auto &It : reverse(ConvertedInsts)) { 348*0b57cec5SDimitry Andric Instruction *I = It.first; 349*0b57cec5SDimitry Andric Value *V; 350*0b57cec5SDimitry Andric int Mask; 351*0b57cec5SDimitry Andric bool Worthy; 352*0b57cec5SDimitry Andric std::tie(V, Mask, Worthy) = It.second; 353*0b57cec5SDimitry Andric if (!I->user_empty()) { 354*0b57cec5SDimitry Andric // If used and unworthy of conversion, skip it. 355*0b57cec5SDimitry Andric if (!Worthy) 356*0b57cec5SDimitry Andric continue; 357*0b57cec5SDimitry Andric // Call the intrinsic, compare result with 0. 358*0b57cec5SDimitry Andric Function *TDCFunc = 359*0b57cec5SDimitry Andric Intrinsic::getDeclaration(&M, Intrinsic::s390_tdc, V->getType()); 360*0b57cec5SDimitry Andric IRBuilder<> IRB(I); 361*0b57cec5SDimitry Andric Value *MaskVal = ConstantInt::get(Type::getInt64Ty(Ctx), Mask); 362*0b57cec5SDimitry Andric Instruction *TDC = IRB.CreateCall(TDCFunc, {V, MaskVal}); 363*0b57cec5SDimitry Andric Value *ICmp = IRB.CreateICmp(CmpInst::ICMP_NE, TDC, Zero32); 364*0b57cec5SDimitry Andric I->replaceAllUsesWith(ICmp); 365*0b57cec5SDimitry Andric } 366*0b57cec5SDimitry Andric // If unused, or used and converted, remove it. 367*0b57cec5SDimitry Andric I->eraseFromParent(); 368*0b57cec5SDimitry Andric MadeChange = true; 369*0b57cec5SDimitry Andric } 370*0b57cec5SDimitry Andric 371*0b57cec5SDimitry Andric if (!MadeChange) 372*0b57cec5SDimitry Andric return false; 373*0b57cec5SDimitry Andric 374*0b57cec5SDimitry Andric // We've actually done something - now clear misc accumulated junk (fabs, 375*0b57cec5SDimitry Andric // bitcast). 376*0b57cec5SDimitry Andric for (auto *I : PossibleJunk) 377*0b57cec5SDimitry Andric if (I->user_empty()) 378*0b57cec5SDimitry Andric I->eraseFromParent(); 379*0b57cec5SDimitry Andric 380*0b57cec5SDimitry Andric return true; 381*0b57cec5SDimitry Andric } 382