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