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