LLVM 22.0.0git
HipStdPar.cpp
Go to the documentation of this file.
1//===----- HipStdPar.cpp - HIP C++ Standard Parallelism Support Passes ----===//
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// This file implements two passes that enable HIP C++ Standard Parallelism
9// Support:
10//
11// 1. AcceleratorCodeSelection (required): Given that only algorithms are
12// accelerated, and that the accelerated implementation exists in the form of
13// a compute kernel, we assume that only the kernel, and all functions
14// reachable from it, constitute code that the user expects the accelerator
15// to execute. Thus, we identify the set of all functions reachable from
16// kernels, and then remove all unreachable ones. This last part is necessary
17// because it is possible for code that the user did not expect to execute on
18// an accelerator to contain constructs that cannot be handled by the target
19// BE, which cannot be provably demonstrated to be dead code in general, and
20// thus can lead to mis-compilation. The degenerate case of this is when a
21// Module contains no kernels (the parent TU had no algorithm invocations fit
22// for acceleration), which we handle by completely emptying said module.
23// **NOTE**: The above does not handle indirectly reachable functions i.e.
24// it is possible to obtain a case where the target of an indirect
25// call is otherwise unreachable and thus is removed; this
26// restriction is aligned with the current `-hipstdpar` limitations
27// and will be relaxed in the future.
28//
29// 2. AllocationInterposition (required only when on-demand paging is
30// unsupported): Some accelerators or operating systems might not support
31// transparent on-demand paging. Thus, they would only be able to access
32// memory that is allocated by an accelerator-aware mechanism. For such cases
33// the user can opt into enabling allocation / deallocation interposition,
34// whereby we replace calls to known allocation / deallocation functions with
35// calls to runtime implemented equivalents that forward the requests to
36// accelerator-aware interfaces. We also support freeing system allocated
37// memory that ends up in one of the runtime equivalents, since this can
38// happen if e.g. a library that was compiled without interposition returns
39// an allocation that can be validly passed to `free`.
40//
41// 3. MathFixup (required): Some accelerators might have an incomplete
42// implementation for the intrinsics used to implement some of the math
43// functions in <cmath> / their corresponding libcall lowerings. Since this
44// can vary quite significantly between accelerators, we replace calls to a
45// set of intrinsics / lib functions known to be problematic with calls to a
46// HIPSTDPAR specific forwarding layer, which gives an uniform interface for
47// accelerators to implement in their own runtime components. This pass
48// should run before AcceleratorCodeSelection so as to prevent the spurious
49// removal of the HIPSTDPAR specific forwarding functions.
50//===----------------------------------------------------------------------===//
51
53
54#include "llvm/ADT/STLExtras.h"
59#include "llvm/IR/Constants.h"
60#include "llvm/IR/Function.h"
61#include "llvm/IR/IRBuilder.h"
62#include "llvm/IR/Intrinsics.h"
63#include "llvm/IR/Module.h"
65
66#include <cassert>
67#include <string>
68#include <utility>
69
70using namespace llvm;
71
72template<typename T>
73static inline void eraseFromModule(T &ToErase) {
74 ToErase.replaceAllUsesWith(PoisonValue::get(ToErase.getType()));
75 ToErase.eraseFromParent();
76}
77
79 if (!G.isThreadLocal())
80 return true;
81
82 G.dropDroppableUses();
83
84 if (!G.isConstantUsed())
85 return true;
86
87 std::string W;
89
90 OS << "Accelerator does not support the thread_local variable "
91 << G.getName();
92
93 Instruction *I = nullptr;
94 SmallVector<User *> Tmp(G.users());
96 do {
97 auto U = std::move(Tmp.back());
98 Tmp.pop_back();
99
100 if (!Visited.insert(U).second)
101 continue;
102
103 if (isa<Instruction>(U))
104 I = cast<Instruction>(U);
105 else
106 Tmp.insert(Tmp.end(), U->user_begin(), U->user_end());
107 } while (!I && !Tmp.empty());
108
109 assert(I && "thread_local global should have at least one non-constant use.");
110
111 G.getContext().diagnose(
112 DiagnosticInfoUnsupported(*I->getParent()->getParent(), W,
113 I->getDebugLoc(), DS_Error));
114
115 return false;
116}
117
118static inline void clearModule(Module &M) { // TODO: simplify.
119 while (!M.functions().empty())
120 eraseFromModule(*M.begin());
121 while (!M.globals().empty())
122 eraseFromModule(*M.globals().begin());
123 while (!M.aliases().empty())
124 eraseFromModule(*M.aliases().begin());
125 while (!M.ifuncs().empty())
126 eraseFromModule(*M.ifuncs().begin());
127}
128
131 // We are interested only in use chains that end in an Instruction.
133
134 SmallVector<std::reference_wrapper<Use>> Stack(G->use_begin(), G->use_end());
135 while (!Stack.empty()) {
136 Use &U = Stack.pop_back_val();
137 if (isa<Instruction>(U.getUser()))
138 Uses.emplace_back(U);
139 else
140 transform(U.getUser()->uses(), std::back_inserter(Stack),
141 [](auto &&U) { return std::ref(U); });
142 }
143
144 return Uses;
145}
146
148 // Create an anonymous global which stores the variable's name, which will be
149 // used by the HIPSTDPAR runtime to look up the program-wide symbol.
150 LLVMContext &Ctx = G->getContext();
151 auto *CDS = ConstantDataArray::getString(Ctx, G->getName());
152
153 GlobalVariable *N = G->getParent()->getOrInsertGlobal("", CDS->getType());
154 N->setInitializer(CDS);
155 N->setLinkage(GlobalValue::LinkageTypes::PrivateLinkage);
156 N->setConstant(true);
157
158 return N;
159}
160
162 // Create an anonymous global which stores a pointer to a pointer, which will
163 // be externally initialised by the HIPSTDPAR runtime with the address of the
164 // program-wide symbol.
165 Type *PtrTy = PointerType::get(
166 M->getContext(), M->getDataLayout().getDefaultGlobalsAddressSpace());
167 GlobalVariable *NewG = M->getOrInsertGlobal("", PtrTy);
168
170 NewG->setLinkage(GlobalValue::LinkageTypes::PrivateLinkage);
171 NewG->setConstant(true);
172 NewG->setExternallyInitialized(true);
173
174 return NewG;
175}
176
177static Constant *
179 SmallVector<Constant *> &SymbolIndirections,
180 GlobalVariable *ToIndirect) {
181 Module *M = ToIndirect->getParent();
182
183 auto *InitTy = cast<StructType>(IndirectionTable->getValueType());
184 auto *SymbolListTy = cast<StructType>(InitTy->getStructElementType(2));
185 Type *NameTy = SymbolListTy->getElementType(0);
186 Type *IndirectTy = SymbolListTy->getElementType(1);
187
188 Constant *NameG = getGlobalForName(ToIndirect);
189 Constant *IndirectG = getIndirectionGlobal(M);
191 SymbolListTy, {ConstantExpr::getAddrSpaceCast(NameG, NameTy),
192 ConstantExpr::getAddrSpaceCast(IndirectG, IndirectTy)});
193 SymbolIndirections.push_back(Entry);
194
195 return IndirectG;
196}
197
198static void fillIndirectionTable(GlobalVariable *IndirectionTable,
199 SmallVector<Constant *> Indirections) {
200 Module *M = IndirectionTable->getParent();
201 size_t SymCnt = Indirections.size();
202
203 auto *InitTy = cast<StructType>(IndirectionTable->getValueType());
204 Type *SymbolListTy = InitTy->getStructElementType(1);
205 auto *SymbolTy = cast<StructType>(InitTy->getStructElementType(2));
206
207 Constant *Count = ConstantInt::get(InitTy->getStructElementType(0), SymCnt);
208 M->removeGlobalVariable(IndirectionTable);
209 GlobalVariable *Symbols =
210 M->getOrInsertGlobal("", ArrayType::get(SymbolTy, SymCnt));
211 Symbols->setLinkage(GlobalValue::LinkageTypes::PrivateLinkage);
212 Symbols->setInitializer(
213 ConstantArray::get(ArrayType::get(SymbolTy, SymCnt), {Indirections}));
214 Symbols->setConstant(true);
215
216 Constant *ASCSymbols = ConstantExpr::getAddrSpaceCast(Symbols, SymbolListTy);
218 InitTy, {Count, ASCSymbols, PoisonValue::get(SymbolTy)});
219 M->insertGlobalVariable(IndirectionTable);
220 IndirectionTable->setInitializer(Init);
221}
222
223static void replaceWithIndirectUse(const Use &U, const GlobalVariable *G,
224 Constant *IndirectedG) {
225 auto *I = cast<Instruction>(U.getUser());
226
227 IRBuilder<> Builder(I);
228 unsigned OpIdx = U.getOperandNo();
229 Value *Op = I->getOperand(OpIdx);
230
231 // We walk back up the use chain, which could be an arbitrarily long sequence
232 // of constexpr AS casts, ptr-to-int and GEP instructions, until we reach the
233 // indirected global.
234 while (auto *CE = dyn_cast<ConstantExpr>(Op)) {
235 assert((CE->getOpcode() == Instruction::GetElementPtr ||
236 CE->getOpcode() == Instruction::AddrSpaceCast ||
237 CE->getOpcode() == Instruction::PtrToInt) &&
238 "Only GEP, ASCAST or PTRTOINT constant uses supported!");
239
240 Instruction *NewI = Builder.Insert(CE->getAsInstruction());
241 I->replaceUsesOfWith(Op, NewI);
242 I = NewI;
243 Op = I->getOperand(0);
244 OpIdx = 0;
245 Builder.SetInsertPoint(I);
246 }
247
248 assert(Op == G && "Must reach indirected global!");
249
250 I->setOperand(OpIdx, Builder.CreateLoad(G->getType(), IndirectedG));
251}
252
253static inline bool isValidIndirectionTable(GlobalVariable *IndirectionTable) {
254 std::string W;
256
257 Type *Ty = IndirectionTable->getValueType();
258 bool Valid = false;
259
260 if (!isa<StructType>(Ty)) {
261 OS << "The Indirection Table must be a struct type; ";
262 Ty->print(OS);
263 OS << " is incorrect.\n";
264 } else if (cast<StructType>(Ty)->getNumElements() != 3u) {
265 OS << "The Indirection Table must have 3 elements; "
266 << cast<StructType>(Ty)->getNumElements() << " is incorrect.\n";
267 } else if (!isa<IntegerType>(cast<StructType>(Ty)->getStructElementType(0))) {
268 OS << "The first element in the Indirection Table must be an integer; ";
269 cast<StructType>(Ty)->getStructElementType(0)->print(OS);
270 OS << " is incorrect.\n";
271 } else if (!isa<PointerType>(cast<StructType>(Ty)->getStructElementType(1))) {
272 OS << "The second element in the Indirection Table must be a pointer; ";
273 cast<StructType>(Ty)->getStructElementType(1)->print(OS);
274 OS << " is incorrect.\n";
275 } else if (!isa<StructType>(cast<StructType>(Ty)->getStructElementType(2))) {
276 OS << "The third element in the Indirection Table must be a struct type; ";
277 cast<StructType>(Ty)->getStructElementType(2)->print(OS);
278 OS << " is incorrect.\n";
279 } else {
280 Valid = true;
281 }
282
283 if (!Valid)
284 IndirectionTable->getContext().diagnose(DiagnosticInfoGeneric(W, DS_Error));
285
286 return Valid;
287}
288
289static void indirectGlobals(GlobalVariable *IndirectionTable,
291 // We replace globals with an indirected access via a pointer that will get
292 // set by the HIPSTDPAR runtime, using their accessible, program-wide unique
293 // address as set by the host linker-loader.
294 SmallVector<Constant *> SymbolIndirections;
295 for (auto &&G : ToIndirect) {
297
298 if (Uses.empty())
299 continue;
300
301 Constant *IndirectedGlobal =
302 appendIndirectedGlobal(IndirectionTable, SymbolIndirections, G);
303
305 [=](auto &&U) { replaceWithIndirectUse(U, G, IndirectedGlobal); });
306
308 }
309
310 if (SymbolIndirections.empty())
311 return;
312
313 fillIndirectionTable(IndirectionTable, std::move(SymbolIndirections));
314}
315
316static inline void maybeHandleGlobals(Module &M) {
317 unsigned GlobAS = M.getDataLayout().getDefaultGlobalsAddressSpace();
318
320 for (auto &&G : M.globals()) {
321 if (!checkIfSupported(G))
322 return clearModule(M);
323 if (G.getAddressSpace() != GlobAS)
324 continue;
325 if (G.isConstant() && G.hasInitializer() && G.hasAtLeastLocalUnnamedAddr())
326 continue;
327
328 ToIndirect.push_back(&G);
329 }
330
331 if (ToIndirect.empty())
332 return;
333
334 if (auto *IT = M.getNamedGlobal("__hipstdpar_symbol_indirection_table")) {
336 return clearModule(M);
337 return indirectGlobals(IT, std::move(ToIndirect));
338 } else {
339 for (auto &&G : ToIndirect) {
340 // We will internalise these, so we provide a poison initialiser.
341 if (!G->hasInitializer())
342 G->setInitializer(PoisonValue::get(G->getValueType()));
343 }
344 }
345}
346
347template<unsigned N>
348static inline void removeUnreachableFunctions(
349 const SmallPtrSet<const Function *, N>& Reachable, Module &M) {
351 if (auto F = dyn_cast<Function>(C))
352 return !Reachable.contains(F);
353
354 return false;
355 });
356
358 copy_if(M, std::back_inserter(ToRemove), [&](auto &&F) {
359 return !F.isIntrinsic() && !Reachable.contains(&F);
360 });
361
362 for_each(ToRemove, eraseFromModule<Function>);
363}
364
365static inline bool isAcceleratorExecutionRoot(const Function *F) {
366 if (!F)
367 return false;
368
369 return F->getCallingConv() == CallingConv::AMDGPU_KERNEL;
370}
371
372static inline bool checkIfSupported(const Function *F, const CallBase *CB) {
373 const auto Dx = F->getName().rfind("__hipstdpar_unsupported");
374
375 if (Dx == StringRef::npos)
376 return true;
377
378 const auto N = F->getName().substr(0, Dx);
379
380 std::string W;
382
383 if (N == "__ASM")
384 OS << "Accelerator does not support the ASM block:\n"
385 << cast<ConstantDataArray>(CB->getArgOperand(0))->getAsCString();
386 else
387 OS << "Accelerator does not support the " << N << " function.";
388
389 auto Caller = CB->getParent()->getParent();
390
391 Caller->getContext().diagnose(
393
394 return false;
395}
396
400 auto &CGA = MAM.getResult<CallGraphAnalysis>(M);
401
403 for (auto &&CGN : CGA) {
404 if (!isAcceleratorExecutionRoot(CGN.first))
405 continue;
406
407 Reachable.insert(CGN.first);
408
409 SmallVector<const Function *> Tmp({CGN.first});
410 do {
411 auto F = std::move(Tmp.back());
412 Tmp.pop_back();
413
414 for (auto &&N : *CGA[F]) {
415 if (!N.second)
416 continue;
417 if (!N.second->getFunction())
418 continue;
419 if (Reachable.contains(N.second->getFunction()))
420 continue;
421
422 if (!checkIfSupported(N.second->getFunction(),
423 dyn_cast<CallBase>(*N.first)))
425
426 Reachable.insert(N.second->getFunction());
427 Tmp.push_back(N.second->getFunction());
428 }
429 } while (!std::empty(Tmp));
430 }
431
432 if (std::empty(Reachable))
433 clearModule(M);
434 else
435 removeUnreachableFunctions(Reachable, M);
436
438
440}
441
442static constexpr std::pair<StringLiteral, StringLiteral> ReplaceMap[]{
443 {"aligned_alloc", "__hipstdpar_aligned_alloc"},
444 {"calloc", "__hipstdpar_calloc"},
445 {"free", "__hipstdpar_free"},
446 {"malloc", "__hipstdpar_malloc"},
447 {"memalign", "__hipstdpar_aligned_alloc"},
448 {"mmap", "__hipstdpar_mmap"},
449 {"munmap", "__hipstdpar_munmap"},
450 {"posix_memalign", "__hipstdpar_posix_aligned_alloc"},
451 {"realloc", "__hipstdpar_realloc"},
452 {"reallocarray", "__hipstdpar_realloc_array"},
453 {"_ZdaPv", "__hipstdpar_operator_delete"},
454 {"_ZdaPvm", "__hipstdpar_operator_delete_sized"},
455 {"_ZdaPvSt11align_val_t", "__hipstdpar_operator_delete_aligned"},
456 {"_ZdaPvmSt11align_val_t", "__hipstdpar_operator_delete_aligned_sized"},
457 {"_ZdlPv", "__hipstdpar_operator_delete"},
458 {"_ZdlPvm", "__hipstdpar_operator_delete_sized"},
459 {"_ZdlPvSt11align_val_t", "__hipstdpar_operator_delete_aligned"},
460 {"_ZdlPvmSt11align_val_t", "__hipstdpar_operator_delete_aligned_sized"},
461 {"_Znam", "__hipstdpar_operator_new"},
462 {"_ZnamRKSt9nothrow_t", "__hipstdpar_operator_new_nothrow"},
463 {"_ZnamSt11align_val_t", "__hipstdpar_operator_new_aligned"},
464 {"_ZnamSt11align_val_tRKSt9nothrow_t",
465 "__hipstdpar_operator_new_aligned_nothrow"},
466
467 {"_Znwm", "__hipstdpar_operator_new"},
468 {"_ZnwmRKSt9nothrow_t", "__hipstdpar_operator_new_nothrow"},
469 {"_ZnwmSt11align_val_t", "__hipstdpar_operator_new_aligned"},
470 {"_ZnwmSt11align_val_tRKSt9nothrow_t",
471 "__hipstdpar_operator_new_aligned_nothrow"},
472 {"__builtin_calloc", "__hipstdpar_calloc"},
473 {"__builtin_free", "__hipstdpar_free"},
474 {"__builtin_malloc", "__hipstdpar_malloc"},
475 {"__builtin_operator_delete", "__hipstdpar_operator_delete"},
476 {"__builtin_operator_new", "__hipstdpar_operator_new"},
477 {"__builtin_realloc", "__hipstdpar_realloc"},
478 {"__libc_calloc", "__hipstdpar_calloc"},
479 {"__libc_free", "__hipstdpar_free"},
480 {"__libc_malloc", "__hipstdpar_malloc"},
481 {"__libc_memalign", "__hipstdpar_aligned_alloc"},
482 {"__libc_realloc", "__hipstdpar_realloc"}};
483
484static constexpr std::pair<StringLiteral, StringLiteral> HiddenMap[]{
485 // hidden_malloc and hidden_free are only kept for backwards compatibility /
486 // legacy purposes, and we should remove them in the future
487 {"__hipstdpar_hidden_malloc", "__libc_malloc"},
488 {"__hipstdpar_hidden_free", "__libc_free"},
489 {"__hipstdpar_hidden_memalign", "__libc_memalign"},
490 {"__hipstdpar_hidden_mmap", "mmap"},
491 {"__hipstdpar_hidden_munmap", "munmap"}};
492
495 SmallDenseMap<StringRef, StringRef> AllocReplacements(std::cbegin(ReplaceMap),
496 std::cend(ReplaceMap));
497
498 for (auto &&F : M) {
499 if (!F.hasName())
500 continue;
501 auto It = AllocReplacements.find(F.getName());
502 if (It == AllocReplacements.end())
503 continue;
504
505 if (auto R = M.getFunction(It->second)) {
506 F.replaceAllUsesWith(R);
507 } else {
508 std::string W;
510
511 OS << "cannot be interposed, missing: " << AllocReplacements[F.getName()]
512 << ". Tried to run the allocation interposition pass without the "
513 << "replacement functions available.";
514
515 F.getContext().diagnose(DiagnosticInfoUnsupported(F, W,
516 F.getSubprogram(),
517 DS_Warning));
518 }
519 }
520
521 for (auto &&HR : HiddenMap) {
522 if (auto F = M.getFunction(HR.first)) {
523 auto R = M.getOrInsertFunction(HR.second, F->getFunctionType(),
524 F->getAttributes());
525 F->replaceAllUsesWith(R.getCallee());
526
528 }
529 }
530
532}
533
534static constexpr std::pair<StringLiteral, StringLiteral> MathLibToHipStdPar[]{
535 {"acosh", "__hipstdpar_acosh_f64"},
536 {"acoshf", "__hipstdpar_acosh_f32"},
537 {"asinh", "__hipstdpar_asinh_f64"},
538 {"asinhf", "__hipstdpar_asinh_f32"},
539 {"atanh", "__hipstdpar_atanh_f64"},
540 {"atanhf", "__hipstdpar_atanh_f32"},
541 {"cbrt", "__hipstdpar_cbrt_f64"},
542 {"cbrtf", "__hipstdpar_cbrt_f32"},
543 {"erf", "__hipstdpar_erf_f64"},
544 {"erff", "__hipstdpar_erf_f32"},
545 {"erfc", "__hipstdpar_erfc_f64"},
546 {"erfcf", "__hipstdpar_erfc_f32"},
547 {"fdim", "__hipstdpar_fdim_f64"},
548 {"fdimf", "__hipstdpar_fdim_f32"},
549 {"expm1", "__hipstdpar_expm1_f64"},
550 {"expm1f", "__hipstdpar_expm1_f32"},
551 {"hypot", "__hipstdpar_hypot_f64"},
552 {"hypotf", "__hipstdpar_hypot_f32"},
553 {"ilogb", "__hipstdpar_ilogb_f64"},
554 {"ilogbf", "__hipstdpar_ilogb_f32"},
555 {"lgamma", "__hipstdpar_lgamma_f64"},
556 {"lgammaf", "__hipstdpar_lgamma_f32"},
557 {"log1p", "__hipstdpar_log1p_f64"},
558 {"log1pf", "__hipstdpar_log1p_f32"},
559 {"logb", "__hipstdpar_logb_f64"},
560 {"logbf", "__hipstdpar_logb_f32"},
561 {"nextafter", "__hipstdpar_nextafter_f64"},
562 {"nextafterf", "__hipstdpar_nextafter_f32"},
563 {"nexttoward", "__hipstdpar_nexttoward_f64"},
564 {"nexttowardf", "__hipstdpar_nexttoward_f32"},
565 {"remainder", "__hipstdpar_remainder_f64"},
566 {"remainderf", "__hipstdpar_remainder_f32"},
567 {"remquo", "__hipstdpar_remquo_f64"},
568 {"remquof", "__hipstdpar_remquo_f32"},
569 {"scalbln", "__hipstdpar_scalbln_f64"},
570 {"scalblnf", "__hipstdpar_scalbln_f32"},
571 {"scalbn", "__hipstdpar_scalbn_f64"},
572 {"scalbnf", "__hipstdpar_scalbn_f32"},
573 {"tgamma", "__hipstdpar_tgamma_f64"},
574 {"tgammaf", "__hipstdpar_tgamma_f32"}};
575
578 if (M.empty())
579 return PreservedAnalyses::all();
580
582 for (auto &&F : M) {
583 if (!F.hasName())
584 continue;
585
586 StringRef N = F.getName();
587 Intrinsic::ID ID = F.getIntrinsicID();
588
589 switch (ID) {
591 auto It =
592 find_if(MathLibToHipStdPar, [&](auto &&M) { return M.first == N; });
593 if (It == std::cend(MathLibToHipStdPar))
594 continue;
595 ToReplace.emplace_back(&F, It->second);
596 break;
597 }
598 case Intrinsic::acos:
599 case Intrinsic::asin:
600 case Intrinsic::atan:
601 case Intrinsic::atan2:
602 case Intrinsic::cosh:
603 case Intrinsic::modf:
604 case Intrinsic::sinh:
605 case Intrinsic::tan:
606 case Intrinsic::tanh:
607 break;
608 default: {
609 if (F.getReturnType()->isDoubleTy()) {
610 switch (ID) {
611 case Intrinsic::cos:
612 case Intrinsic::exp:
613 case Intrinsic::exp2:
614 case Intrinsic::log:
615 case Intrinsic::log10:
616 case Intrinsic::log2:
617 case Intrinsic::pow:
618 case Intrinsic::sin:
619 break;
620 default:
621 continue;
622 }
623 break;
624 }
625 continue;
626 }
627 }
628
629 ToReplace.emplace_back(&F, N);
630 llvm::replace(ToReplace.back().second, '.', '_');
631 StringRef Prefix = "llvm";
632 ToReplace.back().second.replace(0, Prefix.size(), "__hipstdpar");
633 }
634 for (auto &&[F, NewF] : ToReplace)
635 F->replaceAllUsesWith(
636 M.getOrInsertFunction(NewF, F->getFunctionType()).getCallee());
637
639}
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
ReachingDefAnalysis InstSet & ToRemove
static cl::opt< ITMode > IT(cl::desc("IT block support"), cl::Hidden, cl::init(DefaultIT), cl::values(clEnumValN(DefaultIT, "arm-default-it", "Generate any type of IT block"), clEnumValN(RestrictedIT, "arm-restrict-it", "Disallow complex IT blocks")))
This file provides interfaces used to build and manipulate a call graph, which is a very useful tool ...
This file contains the declarations for the subclasses of Constant, which represent the different fla...
static constexpr std::pair< StringLiteral, StringLiteral > HiddenMap[]
Definition: HipStdPar.cpp:484
static SmallVector< std::reference_wrapper< Use > > collectIndirectableUses(GlobalVariable *G)
Definition: HipStdPar.cpp:130
static constexpr std::pair< StringLiteral, StringLiteral > ReplaceMap[]
Definition: HipStdPar.cpp:442
static void maybeHandleGlobals(Module &M)
Definition: HipStdPar.cpp:316
static void replaceWithIndirectUse(const Use &U, const GlobalVariable *G, Constant *IndirectedG)
Definition: HipStdPar.cpp:223
static bool isAcceleratorExecutionRoot(const Function *F)
Definition: HipStdPar.cpp:365
static void eraseFromModule(T &ToErase)
Definition: HipStdPar.cpp:73
static void removeUnreachableFunctions(const SmallPtrSet< const Function *, N > &Reachable, Module &M)
Definition: HipStdPar.cpp:348
static constexpr std::pair< StringLiteral, StringLiteral > MathLibToHipStdPar[]
Definition: HipStdPar.cpp:534
static void fillIndirectionTable(GlobalVariable *IndirectionTable, SmallVector< Constant * > Indirections)
Definition: HipStdPar.cpp:198
static bool checkIfSupported(GlobalVariable &G)
Definition: HipStdPar.cpp:78
static void indirectGlobals(GlobalVariable *IndirectionTable, SmallVector< GlobalVariable * > ToIndirect)
Definition: HipStdPar.cpp:289
static GlobalVariable * getGlobalForName(GlobalVariable *G)
Definition: HipStdPar.cpp:147
static GlobalVariable * getIndirectionGlobal(Module *M)
Definition: HipStdPar.cpp:161
static Constant * appendIndirectedGlobal(const GlobalVariable *IndirectionTable, SmallVector< Constant * > &SymbolIndirections, GlobalVariable *ToIndirect)
Definition: HipStdPar.cpp:178
static void clearModule(Module &M)
Definition: HipStdPar.cpp:118
static bool isValidIndirectionTable(GlobalVariable *IndirectionTable)
Definition: HipStdPar.cpp:253
AcceleratorCodeSelection - Identify all functions reachable from a kernel, removing those that are un...
Module.h This file contains the declarations for the Module class.
#define F(x, y, z)
Definition: MD5.cpp:55
#define I(x, y, z)
Definition: MD5.cpp:58
#define G(x, y, z)
Definition: MD5.cpp:56
MachineInstr unsigned OpIdx
ModuleAnalysisManager MAM
Remove Loads Into Fake Uses
static unsigned getNumElements(Type *Ty)
This file contains some templates that are useful if you are working with the STL at all.
raw_pwrite_stream & OS
This file defines the SmallPtrSet class.
This file defines the SmallVector class.
A container for analyses that lazily runs them and caches their results.
Definition: PassManager.h:255
PassT::Result & getResult(IRUnitT &IR, ExtraArgTs... ExtraArgs)
Get the result of an analysis pass for a given IR unit.
Definition: PassManager.h:412
Base class for all callable instructions (InvokeInst and CallInst) Holds everything related to callin...
Definition: InstrTypes.h:1116
Value * getArgOperand(unsigned i) const
Definition: InstrTypes.h:1292
An analysis pass to compute the CallGraph for a Module.
Definition: CallGraph.h:286
static LLVM_ABI Constant * get(ArrayType *T, ArrayRef< Constant * > V)
Definition: Constants.cpp:1314
static LLVM_ABI Constant * getString(LLVMContext &Context, StringRef Initializer, bool AddNull=true)
This method constructs a CDS and initializes it with a text string.
Definition: Constants.cpp:2989
static LLVM_ABI Constant * getAddrSpaceCast(Constant *C, Type *Ty, bool OnlyIfReduced=false)
Definition: Constants.cpp:2340
static LLVM_ABI Constant * get(StructType *T, ArrayRef< Constant * > V)
Definition: Constants.cpp:1380
This is an important base class in LLVM.
Definition: Constant.h:43
This class represents an Operation in the Expression.
iterator find(const_arg_type_t< KeyT > Val)
Definition: DenseMap.h:177
iterator end()
Definition: DenseMap.h:87
Diagnostic information for unsupported feature in backend.
void setLinkage(LinkageTypes LT)
Definition: GlobalValue.h:539
Module * getParent()
Get the module that this global value is contained inside of...
Definition: GlobalValue.h:663
Type * getValueType() const
Definition: GlobalValue.h:298
LLVM_ABI void setInitializer(Constant *InitVal)
setInitializer - Sets the initializer for this global variable, removing any existing initializer if ...
Definition: Globals.cpp:511
void setConstant(bool Val)
void setExternallyInitialized(bool Val)
LLVM_ABI PreservedAnalyses run(Module &M, ModuleAnalysisManager &MAM)
Definition: HipStdPar.cpp:398
LLVM_ABI PreservedAnalyses run(Module &M, ModuleAnalysisManager &MAM)
Definition: HipStdPar.cpp:494
LLVM_ABI PreservedAnalyses run(Module &M, ModuleAnalysisManager &MAM)
Definition: HipStdPar.cpp:576
InstTy * Insert(InstTy *I, const Twine &Name="") const
Insert and return the specified instruction.
Definition: IRBuilder.h:172
LoadInst * CreateLoad(Type *Ty, Value *Ptr, const char *Name)
Provided to resolve 'CreateLoad(Ty, Ptr, "...")' correctly, instead of converting the string to 'bool...
Definition: IRBuilder.h:1847
void SetInsertPoint(BasicBlock *TheBB)
This specifies that created instructions should be appended to the end of the specified block.
Definition: IRBuilder.h:207
This provides a uniform API for creating instructions and inserting them into a basic block: either a...
Definition: IRBuilder.h:2780
const DebugLoc & getDebugLoc() const
Return the debug location for this node as a DebugLoc.
Definition: Instruction.h:513
This is an important class for using LLVM in a threaded context.
Definition: LLVMContext.h:68
LLVM_ABI void diagnose(const DiagnosticInfo &DI)
Report a message to the currently installed diagnostic handler.
A Module instance is used to store all the information related to an LLVM module.
Definition: Module.h:67
static LLVM_ABI PoisonValue * get(Type *T)
Static factory methods - Return an 'poison' object of the specified type.
Definition: Constants.cpp:1885
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
std::pair< iterator, bool > insert(PtrType Ptr)
Inserts Ptr if and only if there is no element in the container equal to Ptr.
Definition: SmallPtrSet.h:401
bool contains(ConstPtrType Ptr) const
Definition: SmallPtrSet.h:476
SmallPtrSet - This class implements a set which is optimized for holding SmallSize or less elements.
Definition: SmallPtrSet.h:541
bool empty() const
Definition: SmallVector.h:82
size_t size() const
Definition: SmallVector.h:79
reference emplace_back(ArgTypes &&... Args)
Definition: SmallVector.h:938
iterator insert(iterator I, T &&Elt)
Definition: SmallVector.h:806
void push_back(const T &Elt)
Definition: SmallVector.h:414
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
Definition: SmallVector.h:1197
StringRef - Represent a constant reference to a string, i.e.
Definition: StringRef.h:55
static constexpr size_t npos
Definition: StringRef.h:57
The instances of the Type class are immutable: once they are created, they are never changed.
Definition: Type.h:45
LLVM_ABI Type * getStructElementType(unsigned N) const
LLVM_ABI void print(raw_ostream &O, bool IsForDebug=false, bool NoDetails=false) const
Print the current type.
A Use represents the edge between a Value definition and its users.
Definition: Use.h:35
LLVM Value Representation.
Definition: Value.h:75
LLVM_ABI LLVMContext & getContext() const
All values hold a context through their type.
Definition: Value.cpp:1098
const ParentTy * getParent() const
Definition: ilist_node.h:34
A raw_ostream that writes to an std::string.
Definition: raw_ostream.h:662
@ AMDGPU_KERNEL
Used for AMDGPU code object kernels.
Definition: CallingConv.h:200
@ C
The default llvm calling convention, compatible with C.
Definition: CallingConv.h:34
This is an optimization pass for GlobalISel generic memory operations.
Definition: AddressRanges.h:18
UnaryFunction for_each(R &&Range, UnaryFunction F)
Provide wrappers to std::for_each which take ranges instead of having to pass begin/end explicitly.
Definition: STLExtras.h:1737
OutputIt copy_if(R &&Range, OutputIt Out, UnaryPredicate P)
Provide wrappers to std::copy_if which take ranges instead of having to pass begin/end explicitly.
Definition: STLExtras.h:1796
OutputIt transform(R &&Range, OutputIt d_first, UnaryFunction F)
Wrapper function around std::transform to apply a function to a range and store the result elsewhere.
Definition: STLExtras.h:1987
LLVM_ABI void removeFromUsedLists(Module &M, function_ref< bool(Constant *)> ShouldRemove)
Removes global values from the llvm.used and llvm.compiler.used arrays.
void replace(R &&Range, const T &OldValue, const T &NewValue)
Provide wrappers to std::replace which take ranges instead of having to pass begin/end explicitly.
Definition: STLExtras.h:1879
@ DS_Warning
@ DS_Error
auto find_if(R &&Range, UnaryPredicate P)
Provide wrappers to std::find_if which take ranges instead of having to pass begin/end explicitly.
Definition: STLExtras.h:1777
#define N