File: | llvm/lib/Target/AMDGPU/AMDGPUPrintfRuntimeBinding.cpp |
Warning: | line 258, column 48 Called C++ object pointer is null |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | //=== AMDGPUPrintfRuntimeBinding.cpp - OpenCL printf implementation -------===// | ||||
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 | // \file | ||||
9 | // | ||||
10 | // The pass bind printfs to a kernel arg pointer that will be bound to a buffer | ||||
11 | // later by the runtime. | ||||
12 | // | ||||
13 | // This pass traverses the functions in the module and converts | ||||
14 | // each call to printf to a sequence of operations that | ||||
15 | // store the following into the printf buffer: | ||||
16 | // - format string (passed as a module's metadata unique ID) | ||||
17 | // - bitwise copies of printf arguments | ||||
18 | // The backend passes will need to store metadata in the kernel | ||||
19 | //===----------------------------------------------------------------------===// | ||||
20 | |||||
21 | #include "AMDGPU.h" | ||||
22 | #include "llvm/Analysis/InstructionSimplify.h" | ||||
23 | #include "llvm/Analysis/TargetLibraryInfo.h" | ||||
24 | #include "llvm/IR/Dominators.h" | ||||
25 | #include "llvm/IR/IRBuilder.h" | ||||
26 | #include "llvm/IR/Instructions.h" | ||||
27 | #include "llvm/InitializePasses.h" | ||||
28 | #include "llvm/Transforms/Utils/BasicBlockUtils.h" | ||||
29 | |||||
30 | using namespace llvm; | ||||
31 | |||||
32 | #define DEBUG_TYPE"printfToRuntime" "printfToRuntime" | ||||
33 | #define DWORD_ALIGN4 4 | ||||
34 | |||||
35 | namespace { | ||||
36 | class AMDGPUPrintfRuntimeBinding final : public ModulePass { | ||||
37 | |||||
38 | public: | ||||
39 | static char ID; | ||||
40 | |||||
41 | explicit AMDGPUPrintfRuntimeBinding(); | ||||
42 | |||||
43 | private: | ||||
44 | bool runOnModule(Module &M) override; | ||||
45 | |||||
46 | void getAnalysisUsage(AnalysisUsage &AU) const override { | ||||
47 | AU.addRequired<TargetLibraryInfoWrapperPass>(); | ||||
48 | AU.addRequired<DominatorTreeWrapperPass>(); | ||||
49 | } | ||||
50 | }; | ||||
51 | |||||
52 | class AMDGPUPrintfRuntimeBindingImpl { | ||||
53 | public: | ||||
54 | AMDGPUPrintfRuntimeBindingImpl( | ||||
55 | function_ref<const DominatorTree &(Function &)> GetDT, | ||||
56 | function_ref<const TargetLibraryInfo &(Function &)> GetTLI) | ||||
57 | : GetDT(GetDT), GetTLI(GetTLI) {} | ||||
58 | bool run(Module &M); | ||||
59 | |||||
60 | private: | ||||
61 | void getConversionSpecifiers(SmallVectorImpl<char> &OpConvSpecifiers, | ||||
62 | StringRef fmt, size_t num_ops) const; | ||||
63 | |||||
64 | bool shouldPrintAsStr(char Specifier, Type *OpType) const; | ||||
65 | bool lowerPrintfForGpu(Module &M); | ||||
66 | |||||
67 | Value *simplify(Instruction *I, const TargetLibraryInfo *TLI, | ||||
68 | const DominatorTree *DT) { | ||||
69 | return SimplifyInstruction(I, {*TD, TLI, DT}); | ||||
70 | } | ||||
71 | |||||
72 | const DataLayout *TD; | ||||
73 | function_ref<const DominatorTree &(Function &)> GetDT; | ||||
74 | function_ref<const TargetLibraryInfo &(Function &)> GetTLI; | ||||
75 | SmallVector<CallInst *, 32> Printfs; | ||||
76 | }; | ||||
77 | } // namespace | ||||
78 | |||||
79 | char AMDGPUPrintfRuntimeBinding::ID = 0; | ||||
80 | |||||
81 | INITIALIZE_PASS_BEGIN(AMDGPUPrintfRuntimeBinding,static void *initializeAMDGPUPrintfRuntimeBindingPassOnce(PassRegistry &Registry) { | ||||
82 | "amdgpu-printf-runtime-binding", "AMDGPU Printf lowering",static void *initializeAMDGPUPrintfRuntimeBindingPassOnce(PassRegistry &Registry) { | ||||
83 | false, false)static void *initializeAMDGPUPrintfRuntimeBindingPassOnce(PassRegistry &Registry) { | ||||
84 | INITIALIZE_PASS_DEPENDENCY(TargetLibraryInfoWrapperPass)initializeTargetLibraryInfoWrapperPassPass(Registry); | ||||
85 | INITIALIZE_PASS_DEPENDENCY(DominatorTreeWrapperPass)initializeDominatorTreeWrapperPassPass(Registry); | ||||
86 | INITIALIZE_PASS_END(AMDGPUPrintfRuntimeBinding, "amdgpu-printf-runtime-binding",PassInfo *PI = new PassInfo( "AMDGPU Printf lowering", "amdgpu-printf-runtime-binding" , &AMDGPUPrintfRuntimeBinding::ID, PassInfo::NormalCtor_t (callDefaultCtor<AMDGPUPrintfRuntimeBinding>), false, false ); Registry.registerPass(*PI, true); return PI; } static llvm ::once_flag InitializeAMDGPUPrintfRuntimeBindingPassFlag; void llvm::initializeAMDGPUPrintfRuntimeBindingPass(PassRegistry & Registry) { llvm::call_once(InitializeAMDGPUPrintfRuntimeBindingPassFlag , initializeAMDGPUPrintfRuntimeBindingPassOnce, std::ref(Registry )); } | ||||
87 | "AMDGPU Printf lowering", false, false)PassInfo *PI = new PassInfo( "AMDGPU Printf lowering", "amdgpu-printf-runtime-binding" , &AMDGPUPrintfRuntimeBinding::ID, PassInfo::NormalCtor_t (callDefaultCtor<AMDGPUPrintfRuntimeBinding>), false, false ); Registry.registerPass(*PI, true); return PI; } static llvm ::once_flag InitializeAMDGPUPrintfRuntimeBindingPassFlag; void llvm::initializeAMDGPUPrintfRuntimeBindingPass(PassRegistry & Registry) { llvm::call_once(InitializeAMDGPUPrintfRuntimeBindingPassFlag , initializeAMDGPUPrintfRuntimeBindingPassOnce, std::ref(Registry )); } | ||||
88 | |||||
89 | char &llvm::AMDGPUPrintfRuntimeBindingID = AMDGPUPrintfRuntimeBinding::ID; | ||||
90 | |||||
91 | namespace llvm { | ||||
92 | ModulePass *createAMDGPUPrintfRuntimeBinding() { | ||||
93 | return new AMDGPUPrintfRuntimeBinding(); | ||||
94 | } | ||||
95 | } // namespace llvm | ||||
96 | |||||
97 | AMDGPUPrintfRuntimeBinding::AMDGPUPrintfRuntimeBinding() : ModulePass(ID) { | ||||
98 | initializeAMDGPUPrintfRuntimeBindingPass(*PassRegistry::getPassRegistry()); | ||||
99 | } | ||||
100 | |||||
101 | void AMDGPUPrintfRuntimeBindingImpl::getConversionSpecifiers( | ||||
102 | SmallVectorImpl<char> &OpConvSpecifiers, StringRef Fmt, | ||||
103 | size_t NumOps) const { | ||||
104 | // not all format characters are collected. | ||||
105 | // At this time the format characters of interest | ||||
106 | // are %p and %s, which use to know if we | ||||
107 | // are either storing a literal string or a | ||||
108 | // pointer to the printf buffer. | ||||
109 | static const char ConvSpecifiers[] = "cdieEfgGaosuxXp"; | ||||
110 | size_t CurFmtSpecifierIdx = 0; | ||||
111 | size_t PrevFmtSpecifierIdx = 0; | ||||
112 | |||||
113 | while ((CurFmtSpecifierIdx = Fmt.find_first_of( | ||||
114 | ConvSpecifiers, CurFmtSpecifierIdx)) != StringRef::npos) { | ||||
115 | bool ArgDump = false; | ||||
116 | StringRef CurFmt = Fmt.substr(PrevFmtSpecifierIdx, | ||||
117 | CurFmtSpecifierIdx - PrevFmtSpecifierIdx); | ||||
118 | size_t pTag = CurFmt.find_last_of("%"); | ||||
119 | if (pTag != StringRef::npos) { | ||||
120 | ArgDump = true; | ||||
121 | while (pTag && CurFmt[--pTag] == '%') { | ||||
122 | ArgDump = !ArgDump; | ||||
123 | } | ||||
124 | } | ||||
125 | |||||
126 | if (ArgDump) | ||||
127 | OpConvSpecifiers.push_back(Fmt[CurFmtSpecifierIdx]); | ||||
128 | |||||
129 | PrevFmtSpecifierIdx = ++CurFmtSpecifierIdx; | ||||
130 | } | ||||
131 | } | ||||
132 | |||||
133 | bool AMDGPUPrintfRuntimeBindingImpl::shouldPrintAsStr(char Specifier, | ||||
134 | Type *OpType) const { | ||||
135 | if (Specifier != 's') | ||||
136 | return false; | ||||
137 | const PointerType *PT = dyn_cast<PointerType>(OpType); | ||||
138 | if (!PT
| ||||
139 | return false; | ||||
140 | Type *ElemType = PT->getContainedType(0); | ||||
141 | if (ElemType->getTypeID() != Type::IntegerTyID) | ||||
142 | return false; | ||||
143 | IntegerType *ElemIType = cast<IntegerType>(ElemType); | ||||
144 | return ElemIType->getBitWidth() == 8; | ||||
145 | } | ||||
146 | |||||
147 | bool AMDGPUPrintfRuntimeBindingImpl::lowerPrintfForGpu(Module &M) { | ||||
148 | LLVMContext &Ctx = M.getContext(); | ||||
149 | IRBuilder<> Builder(Ctx); | ||||
150 | Type *I32Ty = Type::getInt32Ty(Ctx); | ||||
151 | unsigned UniqID = 0; | ||||
152 | // NB: This is important for this string size to be divizable by 4 | ||||
153 | const char NonLiteralStr[4] = "???"; | ||||
154 | |||||
155 | for (auto CI : Printfs) { | ||||
| |||||
156 | unsigned NumOps = CI->getNumArgOperands(); | ||||
157 | |||||
158 | SmallString<16> OpConvSpecifiers; | ||||
159 | Value *Op = CI->getArgOperand(0); | ||||
160 | |||||
161 | if (auto LI = dyn_cast<LoadInst>(Op)) { | ||||
162 | Op = LI->getPointerOperand(); | ||||
163 | for (auto Use : Op->users()) { | ||||
164 | if (auto SI = dyn_cast<StoreInst>(Use)) { | ||||
165 | Op = SI->getValueOperand(); | ||||
166 | break; | ||||
167 | } | ||||
168 | } | ||||
169 | } | ||||
170 | |||||
171 | if (auto I = dyn_cast<Instruction>(Op)) { | ||||
172 | Value *Op_simplified = | ||||
173 | simplify(I, &GetTLI(*I->getFunction()), &GetDT(*I->getFunction())); | ||||
174 | if (Op_simplified) | ||||
175 | Op = Op_simplified; | ||||
176 | } | ||||
177 | |||||
178 | ConstantExpr *ConstExpr = dyn_cast<ConstantExpr>(Op); | ||||
179 | |||||
180 | if (ConstExpr) { | ||||
181 | GlobalVariable *GVar = dyn_cast<GlobalVariable>(ConstExpr->getOperand(0)); | ||||
182 | |||||
183 | StringRef Str("unknown"); | ||||
184 | if (GVar && GVar->hasInitializer()) { | ||||
185 | auto Init = GVar->getInitializer(); | ||||
186 | if (auto CA = dyn_cast<ConstantDataArray>(Init)) { | ||||
187 | if (CA->isString()) | ||||
188 | Str = CA->getAsCString(); | ||||
189 | } else if (isa<ConstantAggregateZero>(Init)) { | ||||
190 | Str = ""; | ||||
191 | } | ||||
192 | // | ||||
193 | // we need this call to ascertain | ||||
194 | // that we are printing a string | ||||
195 | // or a pointer. It takes out the | ||||
196 | // specifiers and fills up the first | ||||
197 | // arg | ||||
198 | getConversionSpecifiers(OpConvSpecifiers, Str, NumOps - 1); | ||||
199 | } | ||||
200 | // Add metadata for the string | ||||
201 | std::string AStreamHolder; | ||||
202 | raw_string_ostream Sizes(AStreamHolder); | ||||
203 | int Sum = DWORD_ALIGN4; | ||||
204 | Sizes << CI->getNumArgOperands() - 1; | ||||
205 | Sizes << ':'; | ||||
206 | for (unsigned ArgCount = 1; ArgCount < CI->getNumArgOperands() && | ||||
207 | ArgCount <= OpConvSpecifiers.size(); | ||||
208 | ArgCount++) { | ||||
209 | Value *Arg = CI->getArgOperand(ArgCount); | ||||
210 | Type *ArgType = Arg->getType(); | ||||
211 | unsigned ArgSize = TD->getTypeAllocSizeInBits(ArgType); | ||||
212 | ArgSize = ArgSize / 8; | ||||
213 | // | ||||
214 | // ArgSize by design should be a multiple of DWORD_ALIGN, | ||||
215 | // expand the arguments that do not follow this rule. | ||||
216 | // | ||||
217 | if (ArgSize % DWORD_ALIGN4 != 0) { | ||||
218 | llvm::Type *ResType = llvm::Type::getInt32Ty(Ctx); | ||||
219 | auto *LLVMVecType = llvm::dyn_cast<llvm::FixedVectorType>(ArgType); | ||||
220 | int NumElem = LLVMVecType ? LLVMVecType->getNumElements() : 1; | ||||
221 | if (LLVMVecType && NumElem > 1) | ||||
222 | ResType = llvm::FixedVectorType::get(ResType, NumElem); | ||||
223 | Builder.SetInsertPoint(CI); | ||||
224 | Builder.SetCurrentDebugLocation(CI->getDebugLoc()); | ||||
225 | if (OpConvSpecifiers[ArgCount - 1] == 'x' || | ||||
226 | OpConvSpecifiers[ArgCount - 1] == 'X' || | ||||
227 | OpConvSpecifiers[ArgCount - 1] == 'u' || | ||||
228 | OpConvSpecifiers[ArgCount - 1] == 'o') | ||||
229 | Arg = Builder.CreateZExt(Arg, ResType); | ||||
230 | else | ||||
231 | Arg = Builder.CreateSExt(Arg, ResType); | ||||
232 | ArgType = Arg->getType(); | ||||
233 | ArgSize = TD->getTypeAllocSizeInBits(ArgType); | ||||
234 | ArgSize = ArgSize / 8; | ||||
235 | CI->setOperand(ArgCount, Arg); | ||||
236 | } | ||||
237 | if (OpConvSpecifiers[ArgCount - 1] == 'f') { | ||||
238 | ConstantFP *FpCons = dyn_cast<ConstantFP>(Arg); | ||||
239 | if (FpCons) | ||||
240 | ArgSize = 4; | ||||
241 | else { | ||||
242 | FPExtInst *FpExt = dyn_cast<FPExtInst>(Arg); | ||||
243 | if (FpExt && FpExt->getType()->isDoubleTy() && | ||||
244 | FpExt->getOperand(0)->getType()->isFloatTy()) | ||||
245 | ArgSize = 4; | ||||
246 | } | ||||
247 | } | ||||
248 | if (shouldPrintAsStr(OpConvSpecifiers[ArgCount - 1], ArgType)) { | ||||
249 | if (ConstantExpr *ConstExpr
| ||||
250 | GlobalVariable *GV = | ||||
251 | dyn_cast<GlobalVariable>(ConstExpr->getOperand(0)); | ||||
252 | if (GV
| ||||
253 | Constant *Init = GV->getInitializer(); | ||||
254 | ConstantDataArray *CA = dyn_cast<ConstantDataArray>(Init); | ||||
255 | if (Init->isZeroValue() || CA->isString()) { | ||||
256 | size_t SizeStr = Init->isZeroValue() | ||||
257 | ? 1 | ||||
258 | : (strlen(CA->getAsCString().data()) + 1); | ||||
| |||||
259 | size_t Rem = SizeStr % DWORD_ALIGN4; | ||||
260 | size_t NSizeStr = 0; | ||||
261 | LLVM_DEBUG(dbgs() << "Printf string original size = " << SizeStrdo { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType ("printfToRuntime")) { dbgs() << "Printf string original size = " << SizeStr << '\n'; } } while (false) | ||||
262 | << '\n')do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType ("printfToRuntime")) { dbgs() << "Printf string original size = " << SizeStr << '\n'; } } while (false); | ||||
263 | if (Rem) { | ||||
264 | NSizeStr = SizeStr + (DWORD_ALIGN4 - Rem); | ||||
265 | } else { | ||||
266 | NSizeStr = SizeStr; | ||||
267 | } | ||||
268 | ArgSize = NSizeStr; | ||||
269 | } | ||||
270 | } else { | ||||
271 | ArgSize = sizeof(NonLiteralStr); | ||||
272 | } | ||||
273 | } else { | ||||
274 | ArgSize = sizeof(NonLiteralStr); | ||||
275 | } | ||||
276 | } | ||||
277 | LLVM_DEBUG(dbgs() << "Printf ArgSize (in buffer) = " << ArgSizedo { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType ("printfToRuntime")) { dbgs() << "Printf ArgSize (in buffer) = " << ArgSize << " for type: " << *ArgType << '\n'; } } while (false) | ||||
278 | << " for type: " << *ArgType << '\n')do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType ("printfToRuntime")) { dbgs() << "Printf ArgSize (in buffer) = " << ArgSize << " for type: " << *ArgType << '\n'; } } while (false); | ||||
279 | Sizes << ArgSize << ':'; | ||||
280 | Sum += ArgSize; | ||||
281 | } | ||||
282 | LLVM_DEBUG(dbgs() << "Printf format string in source = " << Str.str()do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType ("printfToRuntime")) { dbgs() << "Printf format string in source = " << Str.str() << '\n'; } } while (false) | ||||
283 | << '\n')do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType ("printfToRuntime")) { dbgs() << "Printf format string in source = " << Str.str() << '\n'; } } while (false); | ||||
284 | for (size_t I = 0; I < Str.size(); ++I) { | ||||
285 | // Rest of the C escape sequences (e.g. \') are handled correctly | ||||
286 | // by the MDParser | ||||
287 | switch (Str[I]) { | ||||
288 | case '\a': | ||||
289 | Sizes << "\\a"; | ||||
290 | break; | ||||
291 | case '\b': | ||||
292 | Sizes << "\\b"; | ||||
293 | break; | ||||
294 | case '\f': | ||||
295 | Sizes << "\\f"; | ||||
296 | break; | ||||
297 | case '\n': | ||||
298 | Sizes << "\\n"; | ||||
299 | break; | ||||
300 | case '\r': | ||||
301 | Sizes << "\\r"; | ||||
302 | break; | ||||
303 | case '\v': | ||||
304 | Sizes << "\\v"; | ||||
305 | break; | ||||
306 | case ':': | ||||
307 | // ':' cannot be scanned by Flex, as it is defined as a delimiter | ||||
308 | // Replace it with it's octal representation \72 | ||||
309 | Sizes << "\\72"; | ||||
310 | break; | ||||
311 | default: | ||||
312 | Sizes << Str[I]; | ||||
313 | break; | ||||
314 | } | ||||
315 | } | ||||
316 | |||||
317 | // Insert the printf_alloc call | ||||
318 | Builder.SetInsertPoint(CI); | ||||
319 | Builder.SetCurrentDebugLocation(CI->getDebugLoc()); | ||||
320 | |||||
321 | AttributeList Attr = AttributeList::get(Ctx, AttributeList::FunctionIndex, | ||||
322 | Attribute::NoUnwind); | ||||
323 | |||||
324 | Type *SizetTy = Type::getInt32Ty(Ctx); | ||||
325 | |||||
326 | Type *Tys_alloc[1] = {SizetTy}; | ||||
327 | Type *I8Ptr = PointerType::get(Type::getInt8Ty(Ctx), 1); | ||||
328 | FunctionType *FTy_alloc = FunctionType::get(I8Ptr, Tys_alloc, false); | ||||
329 | FunctionCallee PrintfAllocFn = | ||||
330 | M.getOrInsertFunction(StringRef("__printf_alloc"), FTy_alloc, Attr); | ||||
331 | |||||
332 | LLVM_DEBUG(dbgs() << "Printf metadata = " << Sizes.str() << '\n')do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType ("printfToRuntime")) { dbgs() << "Printf metadata = " << Sizes.str() << '\n'; } } while (false); | ||||
333 | std::string fmtstr = itostr(++UniqID) + ":" + Sizes.str().c_str(); | ||||
334 | MDString *fmtStrArray = MDString::get(Ctx, fmtstr); | ||||
335 | |||||
336 | // Instead of creating global variables, the | ||||
337 | // printf format strings are extracted | ||||
338 | // and passed as metadata. This avoids | ||||
339 | // polluting llvm's symbol tables in this module. | ||||
340 | // Metadata is going to be extracted | ||||
341 | // by the backend passes and inserted | ||||
342 | // into the OpenCL binary as appropriate. | ||||
343 | StringRef amd("llvm.printf.fmts"); | ||||
344 | NamedMDNode *metaD = M.getOrInsertNamedMetadata(amd); | ||||
345 | MDNode *myMD = MDNode::get(Ctx, fmtStrArray); | ||||
346 | metaD->addOperand(myMD); | ||||
347 | Value *sumC = ConstantInt::get(SizetTy, Sum, false); | ||||
348 | SmallVector<Value *, 1> alloc_args; | ||||
349 | alloc_args.push_back(sumC); | ||||
350 | CallInst *pcall = | ||||
351 | CallInst::Create(PrintfAllocFn, alloc_args, "printf_alloc_fn", CI); | ||||
352 | |||||
353 | // | ||||
354 | // Insert code to split basicblock with a | ||||
355 | // piece of hammock code. | ||||
356 | // basicblock splits after buffer overflow check | ||||
357 | // | ||||
358 | ConstantPointerNull *zeroIntPtr = | ||||
359 | ConstantPointerNull::get(PointerType::get(Type::getInt8Ty(Ctx), 1)); | ||||
360 | ICmpInst *cmp = | ||||
361 | dyn_cast<ICmpInst>(Builder.CreateICmpNE(pcall, zeroIntPtr, "")); | ||||
362 | if (!CI->use_empty()) { | ||||
363 | Value *result = | ||||
364 | Builder.CreateSExt(Builder.CreateNot(cmp), I32Ty, "printf_res"); | ||||
365 | CI->replaceAllUsesWith(result); | ||||
366 | } | ||||
367 | SplitBlock(CI->getParent(), cmp); | ||||
368 | Instruction *Brnch = | ||||
369 | SplitBlockAndInsertIfThen(cmp, cmp->getNextNode(), false); | ||||
370 | |||||
371 | Builder.SetInsertPoint(Brnch); | ||||
372 | |||||
373 | // store unique printf id in the buffer | ||||
374 | // | ||||
375 | SmallVector<Value *, 1> ZeroIdxList; | ||||
376 | ConstantInt *zeroInt = | ||||
377 | ConstantInt::get(Ctx, APInt(32, StringRef("0"), 10)); | ||||
378 | ZeroIdxList.push_back(zeroInt); | ||||
379 | |||||
380 | GetElementPtrInst *BufferIdx = GetElementPtrInst::Create( | ||||
381 | nullptr, pcall, ZeroIdxList, "PrintBuffID", Brnch); | ||||
382 | |||||
383 | Type *idPointer = PointerType::get(I32Ty, AMDGPUAS::GLOBAL_ADDRESS); | ||||
384 | Value *id_gep_cast = | ||||
385 | new BitCastInst(BufferIdx, idPointer, "PrintBuffIdCast", Brnch); | ||||
386 | |||||
387 | new StoreInst(ConstantInt::get(I32Ty, UniqID), id_gep_cast, Brnch); | ||||
388 | |||||
389 | SmallVector<Value *, 2> FourthIdxList; | ||||
390 | ConstantInt *fourInt = | ||||
391 | ConstantInt::get(Ctx, APInt(32, StringRef("4"), 10)); | ||||
392 | |||||
393 | FourthIdxList.push_back(fourInt); // 1st 4 bytes hold the printf_id | ||||
394 | // the following GEP is the buffer pointer | ||||
395 | BufferIdx = GetElementPtrInst::Create(nullptr, pcall, FourthIdxList, | ||||
396 | "PrintBuffGep", Brnch); | ||||
397 | |||||
398 | Type *Int32Ty = Type::getInt32Ty(Ctx); | ||||
399 | Type *Int64Ty = Type::getInt64Ty(Ctx); | ||||
400 | for (unsigned ArgCount = 1; ArgCount < CI->getNumArgOperands() && | ||||
401 | ArgCount <= OpConvSpecifiers.size(); | ||||
402 | ArgCount++) { | ||||
403 | Value *Arg = CI->getArgOperand(ArgCount); | ||||
404 | Type *ArgType = Arg->getType(); | ||||
405 | SmallVector<Value *, 32> WhatToStore; | ||||
406 | if (ArgType->isFPOrFPVectorTy() && !isa<VectorType>(ArgType)) { | ||||
407 | Type *IType = (ArgType->isFloatTy()) ? Int32Ty : Int64Ty; | ||||
408 | if (OpConvSpecifiers[ArgCount - 1] == 'f') { | ||||
409 | if (auto *FpCons = dyn_cast<ConstantFP>(Arg)) { | ||||
410 | APFloat Val(FpCons->getValueAPF()); | ||||
411 | bool Lost = false; | ||||
412 | Val.convert(APFloat::IEEEsingle(), APFloat::rmNearestTiesToEven, | ||||
413 | &Lost); | ||||
414 | Arg = ConstantFP::get(Ctx, Val); | ||||
415 | IType = Int32Ty; | ||||
416 | } else if (auto *FpExt = dyn_cast<FPExtInst>(Arg)) { | ||||
417 | if (FpExt->getType()->isDoubleTy() && | ||||
418 | FpExt->getOperand(0)->getType()->isFloatTy()) { | ||||
419 | Arg = FpExt->getOperand(0); | ||||
420 | IType = Int32Ty; | ||||
421 | } | ||||
422 | } | ||||
423 | } | ||||
424 | Arg = new BitCastInst(Arg, IType, "PrintArgFP", Brnch); | ||||
425 | WhatToStore.push_back(Arg); | ||||
426 | } else if (ArgType->getTypeID() == Type::PointerTyID) { | ||||
427 | if (shouldPrintAsStr(OpConvSpecifiers[ArgCount - 1], ArgType)) { | ||||
428 | const char *S = NonLiteralStr; | ||||
429 | if (auto *ConstExpr = dyn_cast<ConstantExpr>(Arg)) { | ||||
430 | auto *GV = dyn_cast<GlobalVariable>(ConstExpr->getOperand(0)); | ||||
431 | if (GV && GV->hasInitializer()) { | ||||
432 | Constant *Init = GV->getInitializer(); | ||||
433 | ConstantDataArray *CA = dyn_cast<ConstantDataArray>(Init); | ||||
434 | if (Init->isZeroValue() || CA->isString()) { | ||||
435 | S = Init->isZeroValue() ? "" : CA->getAsCString().data(); | ||||
436 | } | ||||
437 | } | ||||
438 | } | ||||
439 | size_t SizeStr = strlen(S) + 1; | ||||
440 | size_t Rem = SizeStr % DWORD_ALIGN4; | ||||
441 | size_t NSizeStr = 0; | ||||
442 | if (Rem) { | ||||
443 | NSizeStr = SizeStr + (DWORD_ALIGN4 - Rem); | ||||
444 | } else { | ||||
445 | NSizeStr = SizeStr; | ||||
446 | } | ||||
447 | if (S[0]) { | ||||
448 | char *MyNewStr = new char[NSizeStr](); | ||||
449 | strcpy(MyNewStr, S); | ||||
450 | int NumInts = NSizeStr / 4; | ||||
451 | int CharC = 0; | ||||
452 | while (NumInts) { | ||||
453 | int ANum = *(int *)(MyNewStr + CharC); | ||||
454 | CharC += 4; | ||||
455 | NumInts--; | ||||
456 | Value *ANumV = ConstantInt::get(Int32Ty, ANum, false); | ||||
457 | WhatToStore.push_back(ANumV); | ||||
458 | } | ||||
459 | delete[] MyNewStr; | ||||
460 | } else { | ||||
461 | // Empty string, give a hint to RT it is no NULL | ||||
462 | Value *ANumV = ConstantInt::get(Int32Ty, 0xFFFFFF00, false); | ||||
463 | WhatToStore.push_back(ANumV); | ||||
464 | } | ||||
465 | } else { | ||||
466 | uint64_t Size = TD->getTypeAllocSizeInBits(ArgType); | ||||
467 | assert((Size == 32 || Size == 64) && "unsupported size")(((Size == 32 || Size == 64) && "unsupported size") ? static_cast<void> (0) : __assert_fail ("(Size == 32 || Size == 64) && \"unsupported size\"" , "/build/llvm-toolchain-snapshot-12~++20210125100614+2cdb34efdac5/llvm/lib/Target/AMDGPU/AMDGPUPrintfRuntimeBinding.cpp" , 467, __PRETTY_FUNCTION__)); | ||||
468 | Type *DstType = (Size == 32) ? Int32Ty : Int64Ty; | ||||
469 | Arg = new PtrToIntInst(Arg, DstType, "PrintArgPtr", Brnch); | ||||
470 | WhatToStore.push_back(Arg); | ||||
471 | } | ||||
472 | } else if (isa<FixedVectorType>(ArgType)) { | ||||
473 | Type *IType = NULL__null; | ||||
474 | uint32_t EleCount = cast<FixedVectorType>(ArgType)->getNumElements(); | ||||
475 | uint32_t EleSize = ArgType->getScalarSizeInBits(); | ||||
476 | uint32_t TotalSize = EleCount * EleSize; | ||||
477 | if (EleCount == 3) { | ||||
478 | ShuffleVectorInst *Shuffle = | ||||
479 | new ShuffleVectorInst(Arg, Arg, ArrayRef<int>{0, 1, 2, 2}); | ||||
480 | Shuffle->insertBefore(Brnch); | ||||
481 | Arg = Shuffle; | ||||
482 | ArgType = Arg->getType(); | ||||
483 | TotalSize += EleSize; | ||||
484 | } | ||||
485 | switch (EleSize) { | ||||
486 | default: | ||||
487 | EleCount = TotalSize / 64; | ||||
488 | IType = Type::getInt64Ty(ArgType->getContext()); | ||||
489 | break; | ||||
490 | case 8: | ||||
491 | if (EleCount >= 8) { | ||||
492 | EleCount = TotalSize / 64; | ||||
493 | IType = Type::getInt64Ty(ArgType->getContext()); | ||||
494 | } else if (EleCount >= 3) { | ||||
495 | EleCount = 1; | ||||
496 | IType = Type::getInt32Ty(ArgType->getContext()); | ||||
497 | } else { | ||||
498 | EleCount = 1; | ||||
499 | IType = Type::getInt16Ty(ArgType->getContext()); | ||||
500 | } | ||||
501 | break; | ||||
502 | case 16: | ||||
503 | if (EleCount >= 3) { | ||||
504 | EleCount = TotalSize / 64; | ||||
505 | IType = Type::getInt64Ty(ArgType->getContext()); | ||||
506 | } else { | ||||
507 | EleCount = 1; | ||||
508 | IType = Type::getInt32Ty(ArgType->getContext()); | ||||
509 | } | ||||
510 | break; | ||||
511 | } | ||||
512 | if (EleCount > 1) { | ||||
513 | IType = FixedVectorType::get(IType, EleCount); | ||||
514 | } | ||||
515 | Arg = new BitCastInst(Arg, IType, "PrintArgVect", Brnch); | ||||
516 | WhatToStore.push_back(Arg); | ||||
517 | } else { | ||||
518 | WhatToStore.push_back(Arg); | ||||
519 | } | ||||
520 | for (unsigned I = 0, E = WhatToStore.size(); I != E; ++I) { | ||||
521 | Value *TheBtCast = WhatToStore[I]; | ||||
522 | unsigned ArgSize = | ||||
523 | TD->getTypeAllocSizeInBits(TheBtCast->getType()) / 8; | ||||
524 | SmallVector<Value *, 1> BuffOffset; | ||||
525 | BuffOffset.push_back(ConstantInt::get(I32Ty, ArgSize)); | ||||
526 | |||||
527 | Type *ArgPointer = PointerType::get(TheBtCast->getType(), 1); | ||||
528 | Value *CastedGEP = | ||||
529 | new BitCastInst(BufferIdx, ArgPointer, "PrintBuffPtrCast", Brnch); | ||||
530 | StoreInst *StBuff = new StoreInst(TheBtCast, CastedGEP, Brnch); | ||||
531 | LLVM_DEBUG(dbgs() << "inserting store to printf buffer:\n"do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType ("printfToRuntime")) { dbgs() << "inserting store to printf buffer:\n" << *StBuff << '\n'; } } while (false) | ||||
532 | << *StBuff << '\n')do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType ("printfToRuntime")) { dbgs() << "inserting store to printf buffer:\n" << *StBuff << '\n'; } } while (false); | ||||
533 | (void)StBuff; | ||||
534 | if (I + 1 == E && ArgCount + 1 == CI->getNumArgOperands()) | ||||
535 | break; | ||||
536 | BufferIdx = GetElementPtrInst::Create(nullptr, BufferIdx, BuffOffset, | ||||
537 | "PrintBuffNextPtr", Brnch); | ||||
538 | LLVM_DEBUG(dbgs() << "inserting gep to the printf buffer:\n"do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType ("printfToRuntime")) { dbgs() << "inserting gep to the printf buffer:\n" << *BufferIdx << '\n'; } } while (false) | ||||
539 | << *BufferIdx << '\n')do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType ("printfToRuntime")) { dbgs() << "inserting gep to the printf buffer:\n" << *BufferIdx << '\n'; } } while (false); | ||||
540 | } | ||||
541 | } | ||||
542 | } | ||||
543 | } | ||||
544 | |||||
545 | // erase the printf calls | ||||
546 | for (auto CI : Printfs) | ||||
547 | CI->eraseFromParent(); | ||||
548 | |||||
549 | Printfs.clear(); | ||||
550 | return true; | ||||
551 | } | ||||
552 | |||||
553 | bool AMDGPUPrintfRuntimeBindingImpl::run(Module &M) { | ||||
554 | Triple TT(M.getTargetTriple()); | ||||
555 | if (TT.getArch() == Triple::r600) | ||||
556 | return false; | ||||
557 | |||||
558 | auto PrintfFunction = M.getFunction("printf"); | ||||
559 | if (!PrintfFunction) | ||||
560 | return false; | ||||
561 | |||||
562 | for (auto &U : PrintfFunction->uses()) { | ||||
563 | if (auto *CI = dyn_cast<CallInst>(U.getUser())) { | ||||
564 | if (CI->isCallee(&U)) | ||||
565 | Printfs.push_back(CI); | ||||
566 | } | ||||
567 | } | ||||
568 | |||||
569 | if (Printfs.empty()) | ||||
570 | return false; | ||||
571 | |||||
572 | if (auto HostcallFunction = M.getFunction("__ockl_hostcall_internal")) { | ||||
573 | for (auto &U : HostcallFunction->uses()) { | ||||
574 | if (auto *CI = dyn_cast<CallInst>(U.getUser())) { | ||||
575 | M.getContext().emitError( | ||||
576 | CI, "Cannot use both printf and hostcall in the same module"); | ||||
577 | } | ||||
578 | } | ||||
579 | } | ||||
580 | |||||
581 | TD = &M.getDataLayout(); | ||||
582 | |||||
583 | return lowerPrintfForGpu(M); | ||||
584 | } | ||||
585 | |||||
586 | bool AMDGPUPrintfRuntimeBinding::runOnModule(Module &M) { | ||||
587 | auto GetDT = [this](Function &F) -> DominatorTree & { | ||||
588 | return this->getAnalysis<DominatorTreeWrapperPass>(F).getDomTree(); | ||||
589 | }; | ||||
590 | auto GetTLI = [this](Function &F) -> TargetLibraryInfo & { | ||||
591 | return this->getAnalysis<TargetLibraryInfoWrapperPass>().getTLI(F); | ||||
592 | }; | ||||
593 | |||||
594 | return AMDGPUPrintfRuntimeBindingImpl(GetDT, GetTLI).run(M); | ||||
595 | } | ||||
596 | |||||
597 | PreservedAnalyses | ||||
598 | AMDGPUPrintfRuntimeBindingPass::run(Module &M, ModuleAnalysisManager &AM) { | ||||
599 | FunctionAnalysisManager &FAM = | ||||
600 | AM.getResult<FunctionAnalysisManagerModuleProxy>(M).getManager(); | ||||
601 | auto GetDT = [&FAM](Function &F) -> DominatorTree & { | ||||
602 | return FAM.getResult<DominatorTreeAnalysis>(F); | ||||
603 | }; | ||||
604 | auto GetTLI = [&FAM](Function &F) -> TargetLibraryInfo & { | ||||
605 | return FAM.getResult<TargetLibraryAnalysis>(F); | ||||
606 | }; | ||||
607 | bool Changed = AMDGPUPrintfRuntimeBindingImpl(GetDT, GetTLI).run(M); | ||||
608 | return Changed ? PreservedAnalyses::none() : PreservedAnalyses::all(); | ||||
609 | } |
1 | //===-- llvm/GlobalVariable.h - GlobalVariable class ------------*- C++ -*-===// |
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 file contains the declaration of the GlobalVariable class, which |
10 | // represents a single global variable (or constant) in the VM. |
11 | // |
12 | // Global variables are constant pointers that refer to hunks of space that are |
13 | // allocated by either the VM, or by the linker in a static compiler. A global |
14 | // variable may have an initial value, which is copied into the executables .data |
15 | // area. Global Constants are required to have initializers. |
16 | // |
17 | //===----------------------------------------------------------------------===// |
18 | |
19 | #ifndef LLVM_IR_GLOBALVARIABLE_H |
20 | #define LLVM_IR_GLOBALVARIABLE_H |
21 | |
22 | #include "llvm/ADT/Twine.h" |
23 | #include "llvm/ADT/ilist_node.h" |
24 | #include "llvm/IR/Attributes.h" |
25 | #include "llvm/IR/GlobalObject.h" |
26 | #include "llvm/IR/OperandTraits.h" |
27 | #include "llvm/IR/Value.h" |
28 | #include <cassert> |
29 | #include <cstddef> |
30 | |
31 | namespace llvm { |
32 | |
33 | class Constant; |
34 | class Module; |
35 | |
36 | template <typename ValueSubClass> class SymbolTableListTraits; |
37 | class DIGlobalVariable; |
38 | class DIGlobalVariableExpression; |
39 | |
40 | class GlobalVariable : public GlobalObject, public ilist_node<GlobalVariable> { |
41 | friend class SymbolTableListTraits<GlobalVariable>; |
42 | |
43 | AttributeSet Attrs; |
44 | bool isConstantGlobal : 1; // Is this a global constant? |
45 | bool isExternallyInitializedConstant : 1; // Is this a global whose value |
46 | // can change from its initial |
47 | // value before global |
48 | // initializers are run? |
49 | |
50 | public: |
51 | /// GlobalVariable ctor - If a parent module is specified, the global is |
52 | /// automatically inserted into the end of the specified modules global list. |
53 | GlobalVariable(Type *Ty, bool isConstant, LinkageTypes Linkage, |
54 | Constant *Initializer = nullptr, const Twine &Name = "", |
55 | ThreadLocalMode = NotThreadLocal, unsigned AddressSpace = 0, |
56 | bool isExternallyInitialized = false); |
57 | /// GlobalVariable ctor - This creates a global and inserts it before the |
58 | /// specified other global. |
59 | GlobalVariable(Module &M, Type *Ty, bool isConstant, LinkageTypes Linkage, |
60 | Constant *Initializer, const Twine &Name = "", |
61 | GlobalVariable *InsertBefore = nullptr, |
62 | ThreadLocalMode = NotThreadLocal, |
63 | Optional<unsigned> AddressSpace = None, |
64 | bool isExternallyInitialized = false); |
65 | GlobalVariable(const GlobalVariable &) = delete; |
66 | GlobalVariable &operator=(const GlobalVariable &) = delete; |
67 | |
68 | ~GlobalVariable() { |
69 | dropAllReferences(); |
70 | } |
71 | |
72 | // allocate space for exactly one operand |
73 | void *operator new(size_t s) { |
74 | return User::operator new(s, 1); |
75 | } |
76 | |
77 | // delete space for exactly one operand as created in the corresponding new operator |
78 | void operator delete(void *ptr){ |
79 | assert(ptr != nullptr && "must not be nullptr")((ptr != nullptr && "must not be nullptr") ? static_cast <void> (0) : __assert_fail ("ptr != nullptr && \"must not be nullptr\"" , "/build/llvm-toolchain-snapshot-12~++20210125100614+2cdb34efdac5/llvm/include/llvm/IR/GlobalVariable.h" , 79, __PRETTY_FUNCTION__)); |
80 | User *Obj = static_cast<User *>(ptr); |
81 | // Number of operands can be set to 0 after construction and initialization. Make sure |
82 | // that number of operands is reset to 1, as this is needed in User::operator delete |
83 | Obj->setGlobalVariableNumOperands(1); |
84 | User::operator delete(Obj); |
85 | } |
86 | |
87 | /// Provide fast operand accessors |
88 | DECLARE_TRANSPARENT_OPERAND_ACCESSORS(Value)public: inline Value *getOperand(unsigned) const; inline void setOperand(unsigned, Value*); inline op_iterator op_begin(); inline const_op_iterator op_begin() const; inline op_iterator op_end(); inline const_op_iterator op_end() const; protected : template <int> inline Use &Op(); template <int > inline const Use &Op() const; public: inline unsigned getNumOperands() const; |
89 | |
90 | /// Definitions have initializers, declarations don't. |
91 | /// |
92 | inline bool hasInitializer() const { return !isDeclaration(); } |
93 | |
94 | /// hasDefinitiveInitializer - Whether the global variable has an initializer, |
95 | /// and any other instances of the global (this can happen due to weak |
96 | /// linkage) are guaranteed to have the same initializer. |
97 | /// |
98 | /// Note that if you want to transform a global, you must use |
99 | /// hasUniqueInitializer() instead, because of the *_odr linkage type. |
100 | /// |
101 | /// Example: |
102 | /// |
103 | /// @a = global SomeType* null - Initializer is both definitive and unique. |
104 | /// |
105 | /// @b = global weak SomeType* null - Initializer is neither definitive nor |
106 | /// unique. |
107 | /// |
108 | /// @c = global weak_odr SomeType* null - Initializer is definitive, but not |
109 | /// unique. |
110 | inline bool hasDefinitiveInitializer() const { |
111 | return hasInitializer() && |
112 | // The initializer of a global variable may change to something arbitrary |
113 | // at link time. |
114 | !isInterposable() && |
115 | // The initializer of a global variable with the externally_initialized |
116 | // marker may change at runtime before C++ initializers are evaluated. |
117 | !isExternallyInitialized(); |
118 | } |
119 | |
120 | /// hasUniqueInitializer - Whether the global variable has an initializer, and |
121 | /// any changes made to the initializer will turn up in the final executable. |
122 | inline bool hasUniqueInitializer() const { |
123 | return |
124 | // We need to be sure this is the definition that will actually be used |
125 | isStrongDefinitionForLinker() && |
126 | // It is not safe to modify initializers of global variables with the |
127 | // external_initializer marker since the value may be changed at runtime |
128 | // before C++ initializers are evaluated. |
129 | !isExternallyInitialized(); |
130 | } |
131 | |
132 | /// getInitializer - Return the initializer for this global variable. It is |
133 | /// illegal to call this method if the global is external, because we cannot |
134 | /// tell what the value is initialized to! |
135 | /// |
136 | inline const Constant *getInitializer() const { |
137 | assert(hasInitializer() && "GV doesn't have initializer!")((hasInitializer() && "GV doesn't have initializer!") ? static_cast<void> (0) : __assert_fail ("hasInitializer() && \"GV doesn't have initializer!\"" , "/build/llvm-toolchain-snapshot-12~++20210125100614+2cdb34efdac5/llvm/include/llvm/IR/GlobalVariable.h" , 137, __PRETTY_FUNCTION__)); |
138 | return static_cast<Constant*>(Op<0>().get()); |
139 | } |
140 | inline Constant *getInitializer() { |
141 | assert(hasInitializer() && "GV doesn't have initializer!")((hasInitializer() && "GV doesn't have initializer!") ? static_cast<void> (0) : __assert_fail ("hasInitializer() && \"GV doesn't have initializer!\"" , "/build/llvm-toolchain-snapshot-12~++20210125100614+2cdb34efdac5/llvm/include/llvm/IR/GlobalVariable.h" , 141, __PRETTY_FUNCTION__)); |
142 | return static_cast<Constant*>(Op<0>().get()); |
143 | } |
144 | /// setInitializer - Sets the initializer for this global variable, removing |
145 | /// any existing initializer if InitVal==NULL. If this GV has type T*, the |
146 | /// initializer must have type T. |
147 | void setInitializer(Constant *InitVal); |
148 | |
149 | /// If the value is a global constant, its value is immutable throughout the |
150 | /// runtime execution of the program. Assigning a value into the constant |
151 | /// leads to undefined behavior. |
152 | /// |
153 | bool isConstant() const { return isConstantGlobal; } |
154 | void setConstant(bool Val) { isConstantGlobal = Val; } |
155 | |
156 | bool isExternallyInitialized() const { |
157 | return isExternallyInitializedConstant; |
158 | } |
159 | void setExternallyInitialized(bool Val) { |
160 | isExternallyInitializedConstant = Val; |
161 | } |
162 | |
163 | /// copyAttributesFrom - copy all additional attributes (those not needed to |
164 | /// create a GlobalVariable) from the GlobalVariable Src to this one. |
165 | void copyAttributesFrom(const GlobalVariable *Src); |
166 | |
167 | /// removeFromParent - This method unlinks 'this' from the containing module, |
168 | /// but does not delete it. |
169 | /// |
170 | void removeFromParent(); |
171 | |
172 | /// eraseFromParent - This method unlinks 'this' from the containing module |
173 | /// and deletes it. |
174 | /// |
175 | void eraseFromParent(); |
176 | |
177 | /// Drop all references in preparation to destroy the GlobalVariable. This |
178 | /// drops not only the reference to the initializer but also to any metadata. |
179 | void dropAllReferences(); |
180 | |
181 | /// Attach a DIGlobalVariableExpression. |
182 | void addDebugInfo(DIGlobalVariableExpression *GV); |
183 | |
184 | /// Fill the vector with all debug info attachements. |
185 | void getDebugInfo(SmallVectorImpl<DIGlobalVariableExpression *> &GVs) const; |
186 | |
187 | /// Add attribute to this global. |
188 | void addAttribute(Attribute::AttrKind Kind) { |
189 | Attrs = Attrs.addAttribute(getContext(), Kind); |
190 | } |
191 | |
192 | /// Add attribute to this global. |
193 | void addAttribute(StringRef Kind, StringRef Val = StringRef()) { |
194 | Attrs = Attrs.addAttribute(getContext(), Kind, Val); |
195 | } |
196 | |
197 | /// Return true if the attribute exists. |
198 | bool hasAttribute(Attribute::AttrKind Kind) const { |
199 | return Attrs.hasAttribute(Kind); |
200 | } |
201 | |
202 | /// Return true if the attribute exists. |
203 | bool hasAttribute(StringRef Kind) const { |
204 | return Attrs.hasAttribute(Kind); |
205 | } |
206 | |
207 | /// Return true if any attributes exist. |
208 | bool hasAttributes() const { |
209 | return Attrs.hasAttributes(); |
210 | } |
211 | |
212 | /// Return the attribute object. |
213 | Attribute getAttribute(Attribute::AttrKind Kind) const { |
214 | return Attrs.getAttribute(Kind); |
215 | } |
216 | |
217 | /// Return the attribute object. |
218 | Attribute getAttribute(StringRef Kind) const { |
219 | return Attrs.getAttribute(Kind); |
220 | } |
221 | |
222 | /// Return the attribute set for this global |
223 | AttributeSet getAttributes() const { |
224 | return Attrs; |
225 | } |
226 | |
227 | /// Return attribute set as list with index. |
228 | /// FIXME: This may not be required once ValueEnumerators |
229 | /// in bitcode-writer can enumerate attribute-set. |
230 | AttributeList getAttributesAsList(unsigned index) const { |
231 | if (!hasAttributes()) |
232 | return AttributeList(); |
233 | std::pair<unsigned, AttributeSet> AS[1] = {{index, Attrs}}; |
234 | return AttributeList::get(getContext(), AS); |
235 | } |
236 | |
237 | /// Set attribute list for this global |
238 | void setAttributes(AttributeSet A) { |
239 | Attrs = A; |
240 | } |
241 | |
242 | /// Check if section name is present |
243 | bool hasImplicitSection() const { |
244 | return getAttributes().hasAttribute("bss-section") || |
245 | getAttributes().hasAttribute("data-section") || |
246 | getAttributes().hasAttribute("relro-section") || |
247 | getAttributes().hasAttribute("rodata-section"); |
248 | } |
249 | |
250 | // Methods for support type inquiry through isa, cast, and dyn_cast: |
251 | static bool classof(const Value *V) { |
252 | return V->getValueID() == Value::GlobalVariableVal; |
253 | } |
254 | }; |
255 | |
256 | template <> |
257 | struct OperandTraits<GlobalVariable> : |
258 | public OptionalOperandTraits<GlobalVariable> { |
259 | }; |
260 | |
261 | DEFINE_TRANSPARENT_OPERAND_ACCESSORS(GlobalVariable, Value)GlobalVariable::op_iterator GlobalVariable::op_begin() { return OperandTraits<GlobalVariable>::op_begin(this); } GlobalVariable ::const_op_iterator GlobalVariable::op_begin() const { return OperandTraits<GlobalVariable>::op_begin(const_cast< GlobalVariable*>(this)); } GlobalVariable::op_iterator GlobalVariable ::op_end() { return OperandTraits<GlobalVariable>::op_end (this); } GlobalVariable::const_op_iterator GlobalVariable::op_end () const { return OperandTraits<GlobalVariable>::op_end (const_cast<GlobalVariable*>(this)); } Value *GlobalVariable ::getOperand(unsigned i_nocapture) const { ((i_nocapture < OperandTraits<GlobalVariable>::operands(this) && "getOperand() out of range!") ? static_cast<void> (0) : __assert_fail ("i_nocapture < OperandTraits<GlobalVariable>::operands(this) && \"getOperand() out of range!\"" , "/build/llvm-toolchain-snapshot-12~++20210125100614+2cdb34efdac5/llvm/include/llvm/IR/GlobalVariable.h" , 261, __PRETTY_FUNCTION__)); return cast_or_null<Value> ( OperandTraits<GlobalVariable>::op_begin(const_cast< GlobalVariable*>(this))[i_nocapture].get()); } void GlobalVariable ::setOperand(unsigned i_nocapture, Value *Val_nocapture) { (( i_nocapture < OperandTraits<GlobalVariable>::operands (this) && "setOperand() out of range!") ? static_cast <void> (0) : __assert_fail ("i_nocapture < OperandTraits<GlobalVariable>::operands(this) && \"setOperand() out of range!\"" , "/build/llvm-toolchain-snapshot-12~++20210125100614+2cdb34efdac5/llvm/include/llvm/IR/GlobalVariable.h" , 261, __PRETTY_FUNCTION__)); OperandTraits<GlobalVariable >::op_begin(this)[i_nocapture] = Val_nocapture; } unsigned GlobalVariable::getNumOperands() const { return OperandTraits <GlobalVariable>::operands(this); } template <int Idx_nocapture > Use &GlobalVariable::Op() { return this->OpFrom< Idx_nocapture>(this); } template <int Idx_nocapture> const Use &GlobalVariable::Op() const { return this-> OpFrom<Idx_nocapture>(this); } |
262 | |
263 | } // end namespace llvm |
264 | |
265 | #endif // LLVM_IR_GLOBALVARIABLE_H |