LLVM 24.0.0git
SystemZTDC.cpp
Go to the documentation of this file.
1//===-- SystemZTDC.cpp - Utilize Test Data Class instruction --------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8//
9// This pass looks for instructions that can be replaced by a Test Data Class
10// instruction, and replaces them when profitable.
11//
12// Roughly, the following rules are recognized:
13//
14// 1: fcmp pred X, 0 -> tdc X, mask
15// 2: fcmp pred X, +-inf -> tdc X, mask
16// 3: fcmp pred X, +-minnorm -> tdc X, mask
17// 4: tdc (fabs X), mask -> tdc X, newmask
18// 5: icmp slt (bitcast float X to int), 0 -> tdc X, mask [ie. signbit]
19// 6: icmp sgt (bitcast float X to int), -1 -> tdc X, mask
20// 7: icmp ne/eq (call @llvm.s390.tdc.*(X, mask)) -> tdc X, mask/~mask
21// 8: and i1 (tdc X, M1), (tdc X, M2) -> tdc X, (M1 & M2)
22// 9: or i1 (tdc X, M1), (tdc X, M2) -> tdc X, (M1 | M2)
23// 10: xor i1 (tdc X, M1), (tdc X, M2) -> tdc X, (M1 ^ M2)
24//
25// The pass works in 4 steps:
26//
27// 1. All fcmp and icmp instructions in a function are checked for a match
28// with rules 1-3 and 5-7. Their TDC equivalents are stored in
29// the ConvertedInsts mapping. If the operand of a fcmp instruction is
30// a fabs, it's also folded according to rule 4.
31// 2. All and/or/xor i1 instructions whose both operands have been already
32// mapped are mapped according to rules 8-10. LogicOpsWorklist is used
33// as a queue of instructions to check.
34// 3. All mapped instructions that are considered worthy of conversion (ie.
35// replacing them will actually simplify the final code) are replaced
36// with a call to the s390.tdc intrinsic.
37// 4. All intermediate results of replaced instructions are removed if unused.
38//
39// Instructions that match rules 1-3 are considered unworthy of conversion
40// on their own (since a comparison instruction is superior), but are mapped
41// in the hopes of folding the result using rules 4 and 8-10 (likely removing
42// the original comparison in the process).
43//
44//===----------------------------------------------------------------------===//
45
46#include "SystemZ.h"
47#include "SystemZSubtarget.h"
49#include "llvm/ADT/MapVector.h"
51#include "llvm/IR/Analysis.h"
52#include "llvm/IR/Constants.h"
53#include "llvm/IR/IRBuilder.h"
56#include "llvm/IR/IntrinsicsS390.h"
58#include "llvm/IR/Module.h"
59#include "llvm/IR/PassManager.h"
61#include <set>
62
63using namespace llvm;
64
65namespace {
66
67class SystemZTDCLegacy : public FunctionPass {
68public:
69 static char ID;
70 SystemZTDCLegacy() : FunctionPass(ID) {}
71
72 bool runOnFunction(Function &F) override;
73
74 void getAnalysisUsage(AnalysisUsage &AU) const override {
75 AU.addRequired<TargetPassConfig>();
76 AU.setPreservesCFG();
77 }
78};
79
80class SystemZTDCImpl {
81 // Maps seen instructions that can be mapped to a TDC, values are
82 // (TDC operand, TDC mask, worthy flag) triples.
83 MapVector<Instruction *, std::tuple<Value *, int, bool>> ConvertedInsts;
84 // The queue of and/or/xor i1 instructions to be potentially folded.
85 std::vector<BinaryOperator *> LogicOpsWorklist;
86 // Instructions matched while folding, to be removed at the end if unused.
87 std::set<Instruction *> PossibleJunk;
88
89 // Tries to convert a fcmp instruction.
90 void convertFCmp(CmpInst &I);
91
92 // Tries to convert an icmp instruction.
93 void convertICmp(CmpInst &I);
94
95 // Tries to convert an i1 and/or/xor instruction, whose both operands
96 // have been already converted.
97 void convertLogicOp(BinaryOperator &I);
98
99 // Marks an instruction as converted - adds it to ConvertedInsts and adds
100 // any and/or/xor i1 users to the queue.
101 void converted(Instruction *I, Value *V, int Mask, bool Worthy) {
102 ConvertedInsts[I] = std::make_tuple(V, Mask, Worthy);
103 auto &M = *I->getFunction()->getParent();
104 auto &Ctx = M.getContext();
105 for (auto *U : I->users()) {
106 auto *LI = dyn_cast<BinaryOperator>(U);
107 if (LI && LI->getType() == Type::getInt1Ty(Ctx) &&
108 (LI->getOpcode() == Instruction::And ||
109 LI->getOpcode() == Instruction::Or ||
110 LI->getOpcode() == Instruction::Xor)) {
111 LogicOpsWorklist.push_back(LI);
112 }
113 }
114 }
115
116public:
117 bool runOnFunction(Function &F, SystemZTargetMachine &TM);
118};
119
120} // end anonymous namespace
121
122char SystemZTDCLegacy::ID = 0;
123INITIALIZE_PASS(SystemZTDCLegacy, "systemz-tdc",
124 "SystemZ Test Data Class optimization", false, false)
125
127 return new SystemZTDCLegacy();
128}
129
130void SystemZTDCImpl::convertFCmp(CmpInst &I) {
131 Value *Op0 = I.getOperand(0);
132 auto *Const = dyn_cast<ConstantFP>(I.getOperand(1));
133 auto Pred = I.getPredicate();
134 // Only scalar comparisons with consts are interesting.
135 if (!Const || !Const->getType()->isFloatingPointTy())
136 return;
137 // Compute the smallest normal number (and its negation).
138 auto &Sem = Op0->getType()->getFltSemantics();
140 APFloat NegSmallest = Smallest;
141 NegSmallest.changeSign();
142 // Check if Const is one of our recognized consts.
143 int WhichConst;
144 if (Const->isZero()) {
145 // All comparisons with 0 can be converted.
146 WhichConst = 0;
147 } else if (Const->isInfinity()) {
148 // Likewise for infinities.
149 WhichConst = Const->isNegative() ? 2 : 1;
150 } else if (Const->isExactlyValue(Smallest)) {
151 // For Smallest, we cannot do EQ separately from GT.
153 (Pred & CmpInst::FCMP_OGE) != 0)
154 return;
155 WhichConst = 3;
156 } else if (Const->isExactlyValue(NegSmallest)) {
157 // Likewise for NegSmallest, we cannot do EQ separately from LT.
159 (Pred & CmpInst::FCMP_OLE) != 0)
160 return;
161 WhichConst = 4;
162 } else {
163 // Not one of our special constants.
164 return;
165 }
166 // Partial masks to use for EQ, GT, LT, UN comparisons, respectively.
167 static const int Masks[][4] = {
168 { // 0
173 },
174 { // inf
176 0, // gt
182 },
183 { // -inf
189 0, // lt
191 },
192 { // minnorm
193 0, // eq (unsupported)
195 SystemZ::TDCMASK_INFINITY_PLUS), // gt (actually ge)
200 },
201 { // -minnorm
202 0, // eq (unsupported)
207 SystemZ::TDCMASK_INFINITY_MINUS), // lt (actually le)
209 }
210 };
211 // Construct the mask as a combination of the partial masks.
212 int Mask = 0;
214 Mask |= Masks[WhichConst][0];
216 Mask |= Masks[WhichConst][1];
218 Mask |= Masks[WhichConst][2];
220 Mask |= Masks[WhichConst][3];
221 // A lone fcmp is unworthy of tdc conversion on its own, but may become
222 // worthy if combined with fabs.
223 bool Worthy = false;
224 if (CallInst *CI = dyn_cast<CallInst>(Op0)) {
225 Function *F = CI->getCalledFunction();
226 if (F && F->getIntrinsicID() == Intrinsic::fabs) {
227 // Fold with fabs - adjust the mask appropriately.
229 Mask |= Mask >> 1;
230 Op0 = CI->getArgOperand(0);
231 // A combination of fcmp with fabs is a win, unless the constant
232 // involved is 0 (which is handled by later passes).
233 Worthy = WhichConst != 0;
234 PossibleJunk.insert(CI);
235 }
236 }
237 converted(&I, Op0, Mask, Worthy);
238}
239
240void SystemZTDCImpl::convertICmp(CmpInst &I) {
241 Value *Op0 = I.getOperand(0);
242 auto *Const = dyn_cast<ConstantInt>(I.getOperand(1));
243 auto Pred = I.getPredicate();
244 // All our icmp rules involve comparisons with consts.
245 if (!Const)
246 return;
247 if (auto *Cast = dyn_cast<BitCastInst>(Op0)) {
248 // Check for icmp+bitcast used for signbit.
249 if (!Cast->getSrcTy()->isFloatTy() &&
250 !Cast->getSrcTy()->isDoubleTy() &&
251 !Cast->getSrcTy()->isFP128Ty())
252 return;
253 Value *V = Cast->getOperand(0);
254 int Mask;
255 if (Pred == CmpInst::ICMP_SLT && Const->isZero()) {
256 // icmp slt (bitcast X), 0 - set if sign bit true
258 } else if (Pred == CmpInst::ICMP_SGT && Const->isMinusOne()) {
259 // icmp sgt (bitcast X), -1 - set if sign bit false
261 } else {
262 // Not a sign bit check.
263 return;
264 }
265 PossibleJunk.insert(Cast);
266 converted(&I, V, Mask, true);
267 } else if (auto *CI = dyn_cast<CallInst>(Op0)) {
268 // Check if this is a pre-existing call of our tdc intrinsic.
269 Function *F = CI->getCalledFunction();
270 if (!F || F->getIntrinsicID() != Intrinsic::s390_tdc)
271 return;
272 if (!Const->isZero())
273 return;
274 Value *V = CI->getArgOperand(0);
275 auto *MaskC = dyn_cast<ConstantInt>(CI->getArgOperand(1));
276 // Bail if the mask is not a constant.
277 if (!MaskC)
278 return;
279 int Mask = MaskC->getZExtValue();
281 if (Pred == CmpInst::ICMP_NE) {
282 // icmp ne (call llvm.s390.tdc(...)), 0 -> simple TDC
283 } else if (Pred == CmpInst::ICMP_EQ) {
284 // icmp eq (call llvm.s390.tdc(...)), 0 -> TDC with inverted mask
286 } else {
287 // An unknown comparison - ignore.
288 return;
289 }
290 PossibleJunk.insert(CI);
291 converted(&I, V, Mask, false);
292 }
293}
294
295void SystemZTDCImpl::convertLogicOp(BinaryOperator &I) {
296 Value *Op0, *Op1;
297 int Mask0, Mask1;
298 bool Worthy0, Worthy1;
299 std::tie(Op0, Mask0, Worthy0) = ConvertedInsts[cast<Instruction>(I.getOperand(0))];
300 std::tie(Op1, Mask1, Worthy1) = ConvertedInsts[cast<Instruction>(I.getOperand(1))];
301 if (Op0 != Op1)
302 return;
303 int Mask;
304 switch (I.getOpcode()) {
305 case Instruction::And:
306 Mask = Mask0 & Mask1;
307 break;
308 case Instruction::Or:
309 Mask = Mask0 | Mask1;
310 break;
311 case Instruction::Xor:
312 Mask = Mask0 ^ Mask1;
313 break;
314 default:
315 llvm_unreachable("Unknown op in convertLogicOp");
316 }
317 converted(&I, Op0, Mask, true);
318}
319
320bool SystemZTDCImpl::runOnFunction(Function &F, SystemZTargetMachine &TM) {
321 if (TM.getSubtarget<SystemZSubtarget>(F).hasSoftFloat())
322 return false;
323
324 ConvertedInsts.clear();
325 LogicOpsWorklist.clear();
326 PossibleJunk.clear();
327
328 // Look for icmp+fcmp instructions.
329 for (auto &I : instructions(F)) {
330 if (I.getOpcode() == Instruction::FCmp)
331 convertFCmp(cast<CmpInst>(I));
332 else if (I.getOpcode() == Instruction::ICmp)
333 convertICmp(cast<CmpInst>(I));
334 }
335
336 // If none found, bail already.
337 if (ConvertedInsts.empty())
338 return false;
339
340 // Process the queue of logic instructions.
341 while (!LogicOpsWorklist.empty()) {
342 BinaryOperator *Op = LogicOpsWorklist.back();
343 LogicOpsWorklist.pop_back();
344 // If both operands mapped, and the instruction itself not yet mapped,
345 // convert it.
346 if (ConvertedInsts.count(dyn_cast<Instruction>(Op->getOperand(0))) &&
347 ConvertedInsts.count(dyn_cast<Instruction>(Op->getOperand(1))) &&
348 !ConvertedInsts.count(Op))
349 convertLogicOp(*Op);
350 }
351
352 // Time to actually replace the instructions. Do it in the reverse order
353 // of finding them, since there's a good chance the earlier ones will be
354 // unused (due to being folded into later ones).
355 Module &M = *F.getParent();
356 auto &Ctx = M.getContext();
357 Value *Zero32 = ConstantInt::get(Type::getInt32Ty(Ctx), 0);
358 bool MadeChange = false;
359 for (auto &It : reverse(ConvertedInsts)) {
360 Instruction *I = It.first;
361 Value *V;
362 int Mask;
363 bool Worthy;
364 std::tie(V, Mask, Worthy) = It.second;
365 if (!I->user_empty()) {
366 // If used and unworthy of conversion, skip it.
367 if (!Worthy)
368 continue;
369 // Call the intrinsic, compare result with 0.
370 IRBuilder<> IRB(I);
371 Value *MaskVal = ConstantInt::get(Type::getInt64Ty(Ctx), Mask);
372 Value *TDC =
373 IRB.CreateIntrinsic(Intrinsic::s390_tdc, V->getType(), {V, MaskVal});
374 Value *ICmp = IRB.CreateICmp(CmpInst::ICMP_NE, TDC, Zero32);
375 I->replaceAllUsesWith(ICmp);
376 }
377 // If unused, or used and converted, remove it.
378 I->eraseFromParent();
379 MadeChange = true;
380 }
381
382 if (!MadeChange)
383 return false;
384
385 // We've actually done something - now clear misc accumulated junk (fabs,
386 // bitcast).
387 for (auto *I : PossibleJunk)
388 if (I->user_empty())
389 I->eraseFromParent();
390
391 return true;
392}
393
394bool SystemZTDCLegacy::runOnFunction(Function &F) {
395 auto &TPC = getAnalysis<TargetPassConfig>();
396 SystemZTDCImpl Impl;
397 return Impl.runOnFunction(F, TPC.getTM<SystemZTargetMachine>());
398}
399
402 SystemZTDCImpl Impl;
403 bool Changed = Impl.runOnFunction(F, TM);
404 if (!Changed)
405 return PreservedAnalyses::all();
407}
SDValue Pred
Expand Atomic instructions
This file contains the declarations for the subclasses of Constant, which represent the different fla...
static bool runOnFunction(Function &F, bool PostInlining)
Module.h This file contains the declarations for the Module class.
This header defines various interfaces for pass management in LLVM.
#define F(x, y, z)
Definition MD5.cpp:54
#define I(x, y, z)
Definition MD5.cpp:57
Machine Check Debug Module
This file implements a map that provides insertion order iteration.
FunctionAnalysisManager FAM
#define INITIALIZE_PASS(passName, arg, name, cfg, analysis)
Definition PassSupport.h:56
Target-Independent Code Generator Pass Configuration Options pass.
static APFloat getSmallestNormalized(const fltSemantics &Sem, bool Negative=false)
Returns the smallest (by magnitude) normalized finite number in the given semantics.
Definition APFloat.h:1262
void changeSign()
Definition APFloat.h:1401
AnalysisUsage & addRequired()
LLVM_ABI void setPreservesCFG()
This function should be called by the pass, iff they do not:
Definition Pass.cpp:280
Represents analyses that only rely on functions' control flow.
Definition Analysis.h:73
This class is the base class for the comparison instructions.
Definition InstrTypes.h:728
@ FCMP_OEQ
0 0 0 1 True if ordered and equal
Definition InstrTypes.h:743
@ ICMP_SLT
signed less than
Definition InstrTypes.h:769
@ FCMP_OLT
0 1 0 0 True if ordered and less than
Definition InstrTypes.h:746
@ FCMP_OGT
0 0 1 0 True if ordered and greater than
Definition InstrTypes.h:744
@ FCMP_OGE
0 0 1 1 True if ordered and greater than or equal
Definition InstrTypes.h:745
@ ICMP_SGT
signed greater than
Definition InstrTypes.h:767
@ FCMP_OLE
0 1 0 1 True if ordered and less than or equal
Definition InstrTypes.h:747
@ ICMP_NE
not equal
Definition InstrTypes.h:762
@ FCMP_UNO
1 0 0 0 True if unordered: isnan(X) | isnan(Y)
Definition InstrTypes.h:750
FunctionPass class - This class is used to implement most global optimizations.
Definition Pass.h:312
bool empty() const
Definition MapVector.h:80
size_type count(const KeyT &Key) const
Definition MapVector.h:153
A set of analyses that are preserved following a run of a transformation pass.
Definition Analysis.h:112
static PreservedAnalyses none()
Convenience factory function for the empty preserved set.
Definition Analysis.h:115
static PreservedAnalyses all()
Construct a special preserved set that preserves all passes.
Definition Analysis.h:118
PreservedAnalyses & preserveSet()
Mark an analysis set as preserved.
Definition Analysis.h:151
PreservedAnalyses run(Function &F, FunctionAnalysisManager &FAM)
const STC & getSubtarget(const Function &F) const
This method returns a pointer to the specified type of TargetSubtargetInfo.
LLVM_ABI const fltSemantics & getFltSemantics() const
Definition Type.cpp:96
Type * getType() const
All values are typed, get the type of this value.
Definition Value.h:257
Pass manager infrastructure for declaring and invalidating analyses.
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
constexpr std::underlying_type_t< E > Mask()
Get a bitmask with 1s in all places up to the high-order bit of E's largest value.
const unsigned TDCMASK_NEGATIVE
Definition SystemZ.h:142
const unsigned TDCMASK_NORMAL_MINUS
Definition SystemZ.h:128
const unsigned TDCMASK_MINUS
Definition SystemZ.h:153
const unsigned TDCMASK_SUBNORMAL_MINUS
Definition SystemZ.h:130
const unsigned TDCMASK_ZERO
Definition SystemZ.h:138
const unsigned TDCMASK_NORMAL_PLUS
Definition SystemZ.h:127
const unsigned TDCMASK_ALL
Definition SystemZ.h:157
const unsigned TDCMASK_SUBNORMAL_PLUS
Definition SystemZ.h:129
const unsigned TDCMASK_INFINITY_PLUS
Definition SystemZ.h:131
const unsigned TDCMASK_POSITIVE
Definition SystemZ.h:139
const unsigned TDCMASK_INFINITY_MINUS
Definition SystemZ.h:132
const unsigned TDCMASK_NAN
Definition SystemZ.h:145
const unsigned TDCMASK_PLUS
Definition SystemZ.h:149
friend class Instruction
Iterator for Instructions in a `BasicBlock.
Definition BasicBlock.h:73
This is an optimization pass for GlobalISel generic memory operations.
decltype(auto) dyn_cast(const From &Val)
dyn_cast<X> - Return the argument parameter cast to the specified type.
Definition Casting.h:643
RelativeUniformCounterPtr ValuesPtrExpr VTableAddr Value
Definition InstrProf.h:143
auto reverse(ContainerTy &&C)
Definition STLExtras.h:408
IRBuilder(LLVMContext &, FolderTy, InserterTy) -> IRBuilder< FolderTy, InserterTy >
FunctionPass * createSystemZTDCLegacyPass()
DWARFExpression::Operation Op
decltype(auto) cast(const From &Val)
cast<X> - Return the argument parameter cast to the specified type.
Definition Casting.h:559
AnalysisManager< Function > FunctionAnalysisManager
Convenience typedef for the Function analysis manager.