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