xref: /freebsd/contrib/llvm-project/llvm/lib/Target/SystemZ/SystemZTDC.cpp (revision 0b57cec536236d46e3dba9bd041533462f33dbb7)
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