76 ToErase.eraseFromParent();
80 if (!
G.isThreadLocal())
83 G.dropDroppableUses();
85 if (!
G.isConstantUsed())
91 OS <<
"Accelerator does not support the thread_local variable "
98 auto U = std::move(Tmp.
back());
101 if (!Visited.
insert(U).second)
107 Tmp.
insert(Tmp.
end(), U->user_begin(), U->user_end());
108 }
while (!
I && !Tmp.
empty());
110 assert(
I &&
"thread_local global should have at least one non-constant use.");
112 G.getContext().diagnose(
120 while (!M.functions().empty())
122 while (!M.globals().empty())
124 while (!M.aliases().empty())
126 while (!M.ifuncs().empty())
136 while (!Stack.empty()) {
137 Use &U = Stack.pop_back_val();
139 Uses.emplace_back(U);
141 transform(U.getUser()->uses(), std::back_inserter(Stack),
142 [](
auto &&U) { return std::ref(U); });
155 N->setInitializer(CDS);
157 N->setConstant(
true);
167 M->getContext(), M->getDataLayout().getDefaultGlobalsAddressSpace());
186 Type *NameTy = SymbolListTy->getElementType(0);
187 Type *IndirectTy = SymbolListTy->getElementType(1);
202 size_t SymCnt = Indirections.
size();
208 Constant *
Count = ConstantInt::get(InitTy->getStructElementType(0), SymCnt);
209 M->removeGlobalVariable(IndirectionTable);
213 Symbols->setInitializer(
215 Symbols->setConstant(
true);
220 M->insertGlobalVariable(IndirectionTable);
229 unsigned OpIdx = U.getOperandNo();
236 assert((CE->getOpcode() == Instruction::GetElementPtr ||
237 CE->getOpcode() == Instruction::AddrSpaceCast ||
238 CE->getOpcode() == Instruction::PtrToInt) &&
239 "Only GEP, ASCAST or PTRTOINT constant uses supported!");
241 Instruction *NewI = Builder.Insert(CE->getAsInstruction());
242 I->replaceUsesOfWith(
Op, NewI);
244 Op =
I->getOperand(0);
246 Builder.SetInsertPoint(
I);
249 assert(
Op ==
G &&
"Must reach indirected global!");
251 I->setOperand(OpIdx, Builder.CreateLoad(
G->getType(), IndirectedG));
262 OS <<
"The Indirection Table must be a struct type; ";
264 OS <<
" is incorrect.\n";
266 OS <<
"The Indirection Table must have 3 elements; "
269 OS <<
"The first element in the Indirection Table must be an integer; ";
271 OS <<
" is incorrect.\n";
273 OS <<
"The second element in the Indirection Table must be a pointer; ";
275 OS <<
" is incorrect.\n";
277 OS <<
"The third element in the Indirection Table must be a struct type; ";
279 OS <<
" is incorrect.\n";
296 for (
auto &&
G : ToIndirect) {
311 if (SymbolIndirections.
empty())
318 unsigned GlobAS = M.getDataLayout().getDefaultGlobalsAddressSpace();
321 for (
auto &&
G : M.globals()) {
324 if (
G.getAddressSpace() != GlobAS)
326 if (
G.isConstant() &&
G.hasInitializer() &&
G.hasAtLeastLocalUnnamedAddr())
332 if (ToIndirect.
empty())
335 if (
auto *
IT = M.getNamedGlobal(
"__hipstdpar_symbol_indirection_table")) {
340 for (
auto &&
G : ToIndirect) {
342 if (!
G->hasInitializer())
353 return !Reachable.contains(
F);
360 return !
F.isIntrinsic() && !Reachable.contains(&
F);
374 return Name ==
"__cxa_throw" || Name ==
"__cxa_rethrow" ||
375 Name ==
"__cxa_bad_cast" || Name ==
"__cxa_bad_typeid" ||
376 Name ==
"__cxa_throw_bad_array_new_length" ||
377 Name ==
"__cxa_rethrow_primary_exception" ||
378 Name ==
"__cxa_call_unexpected";
389 *
F,
"Accelerator does not support C++ exception handling.",
400 const auto Dx = Name.rfind(
"__hipstdpar_unsupported");
412 if (IsCXXException) {
413 OS <<
"Accelerator does not support C++ exception handling.";
415 const auto N = Name.substr(0, Dx);
416 if (
N ==
"__CXX_EXCEPTION")
417 OS <<
"Accelerator does not support C++ exception handling.";
418 else if (
N ==
"__ASM")
419 OS <<
"Accelerator does not support the ASM block:\n"
422 OS <<
"Accelerator does not support the " <<
N <<
" function.";
425 auto Caller = CB->
getParent()->getParent();
427 Caller->getContext().diagnose(
439 for (
auto &&CGN : CGA) {
443 Reachable.insert(CGN.first);
447 auto F = std::move(Tmp.
back());
453 for (
auto &&
N : *CGA[
F]) {
456 if (!
N.second->getFunction())
458 if (Reachable.contains(
N.second->getFunction()))
465 Reachable.insert(
N.second->getFunction());
468 }
while (!std::empty(Tmp));
471 if (std::empty(Reachable))
481static constexpr std::pair<StringLiteral, StringLiteral>
ReplaceMap[]{
482 {
"aligned_alloc",
"__hipstdpar_aligned_alloc"},
483 {
"calloc",
"__hipstdpar_calloc"},
484 {
"free",
"__hipstdpar_free"},
485 {
"malloc",
"__hipstdpar_malloc"},
486 {
"memalign",
"__hipstdpar_aligned_alloc"},
487 {
"mmap",
"__hipstdpar_mmap"},
488 {
"munmap",
"__hipstdpar_munmap"},
489 {
"posix_memalign",
"__hipstdpar_posix_aligned_alloc"},
490 {
"realloc",
"__hipstdpar_realloc"},
491 {
"reallocarray",
"__hipstdpar_realloc_array"},
492 {
"_ZdaPv",
"__hipstdpar_operator_delete"},
493 {
"_ZdaPvm",
"__hipstdpar_operator_delete_sized"},
494 {
"_ZdaPvSt11align_val_t",
"__hipstdpar_operator_delete_aligned"},
495 {
"_ZdaPvmSt11align_val_t",
"__hipstdpar_operator_delete_aligned_sized"},
496 {
"_ZdlPv",
"__hipstdpar_operator_delete"},
497 {
"_ZdlPvm",
"__hipstdpar_operator_delete_sized"},
498 {
"_ZdlPvSt11align_val_t",
"__hipstdpar_operator_delete_aligned"},
499 {
"_ZdlPvmSt11align_val_t",
"__hipstdpar_operator_delete_aligned_sized"},
500 {
"_Znam",
"__hipstdpar_operator_new"},
501 {
"_ZnamRKSt9nothrow_t",
"__hipstdpar_operator_new_nothrow"},
502 {
"_ZnamSt11align_val_t",
"__hipstdpar_operator_new_aligned"},
503 {
"_ZnamSt11align_val_tRKSt9nothrow_t",
504 "__hipstdpar_operator_new_aligned_nothrow"},
506 {
"_Znwm",
"__hipstdpar_operator_new"},
507 {
"_ZnwmRKSt9nothrow_t",
"__hipstdpar_operator_new_nothrow"},
508 {
"_ZnwmSt11align_val_t",
"__hipstdpar_operator_new_aligned"},
509 {
"_ZnwmSt11align_val_tRKSt9nothrow_t",
510 "__hipstdpar_operator_new_aligned_nothrow"},
511 {
"__builtin_calloc",
"__hipstdpar_calloc"},
512 {
"__builtin_free",
"__hipstdpar_free"},
513 {
"__builtin_malloc",
"__hipstdpar_malloc"},
514 {
"__builtin_operator_delete",
"__hipstdpar_operator_delete"},
515 {
"__builtin_operator_new",
"__hipstdpar_operator_new"},
516 {
"__builtin_realloc",
"__hipstdpar_realloc"},
517 {
"__libc_calloc",
"__hipstdpar_calloc"},
518 {
"__libc_free",
"__hipstdpar_free"},
519 {
"__libc_malloc",
"__hipstdpar_malloc"},
520 {
"__libc_memalign",
"__hipstdpar_aligned_alloc"},
521 {
"__libc_realloc",
"__hipstdpar_realloc"}};
523static constexpr std::pair<StringLiteral, StringLiteral>
HiddenMap[]{
526 {
"__hipstdpar_hidden_malloc",
"__libc_malloc"},
527 {
"__hipstdpar_hidden_free",
"__libc_free"},
528 {
"__hipstdpar_hidden_memalign",
"__libc_memalign"},
529 {
"__hipstdpar_hidden_mmap",
"mmap"},
530 {
"__hipstdpar_hidden_munmap",
"munmap"}};
540 auto It = AllocReplacements.
find(
F.getName());
541 if (It == AllocReplacements.
end())
544 if (
auto R = M.getFunction(It->second)) {
545 F.replaceAllUsesWith(R);
550 OS <<
"cannot be interposed, missing: " << AllocReplacements[
F.getName()]
551 <<
". Tried to run the allocation interposition pass without the "
552 <<
"replacement functions available.";
561 if (
auto F = M.getFunction(HR.first)) {
562 auto R = M.getOrInsertFunction(HR.second,
F->getFunctionType(),
564 F->replaceAllUsesWith(R.getCallee());
574 {
"acosh",
"__hipstdpar_acosh_f64"},
575 {
"acoshf",
"__hipstdpar_acosh_f32"},
576 {
"asinh",
"__hipstdpar_asinh_f64"},
577 {
"asinhf",
"__hipstdpar_asinh_f32"},
578 {
"atanh",
"__hipstdpar_atanh_f64"},
579 {
"atanhf",
"__hipstdpar_atanh_f32"},
580 {
"cbrt",
"__hipstdpar_cbrt_f64"},
581 {
"cbrtf",
"__hipstdpar_cbrt_f32"},
582 {
"erf",
"__hipstdpar_erf_f64"},
583 {
"erff",
"__hipstdpar_erf_f32"},
584 {
"erfc",
"__hipstdpar_erfc_f64"},
585 {
"erfcf",
"__hipstdpar_erfc_f32"},
586 {
"fdim",
"__hipstdpar_fdim_f64"},
587 {
"fdimf",
"__hipstdpar_fdim_f32"},
588 {
"expm1",
"__hipstdpar_expm1_f64"},
589 {
"expm1f",
"__hipstdpar_expm1_f32"},
590 {
"hypot",
"__hipstdpar_hypot_f64"},
591 {
"hypotf",
"__hipstdpar_hypot_f32"},
592 {
"ilogb",
"__hipstdpar_ilogb_f64"},
593 {
"ilogbf",
"__hipstdpar_ilogb_f32"},
594 {
"lgamma",
"__hipstdpar_lgamma_f64"},
595 {
"lgammaf",
"__hipstdpar_lgamma_f32"},
596 {
"log1p",
"__hipstdpar_log1p_f64"},
597 {
"log1pf",
"__hipstdpar_log1p_f32"},
598 {
"logb",
"__hipstdpar_logb_f64"},
599 {
"logbf",
"__hipstdpar_logb_f32"},
600 {
"nextafter",
"__hipstdpar_nextafter_f64"},
601 {
"nextafterf",
"__hipstdpar_nextafter_f32"},
602 {
"nexttoward",
"__hipstdpar_nexttoward_f64"},
603 {
"nexttowardf",
"__hipstdpar_nexttoward_f32"},
604 {
"remainder",
"__hipstdpar_remainder_f64"},
605 {
"remainderf",
"__hipstdpar_remainder_f32"},
606 {
"remquo",
"__hipstdpar_remquo_f64"},
607 {
"remquof",
"__hipstdpar_remquo_f32"},
608 {
"scalbln",
"__hipstdpar_scalbln_f64"},
609 {
"scalblnf",
"__hipstdpar_scalbln_f32"},
610 {
"scalbn",
"__hipstdpar_scalbn_f64"},
611 {
"scalbnf",
"__hipstdpar_scalbn_f32"},
612 {
"tgamma",
"__hipstdpar_tgamma_f64"},
613 {
"tgammaf",
"__hipstdpar_tgamma_f32"}};
637 case Intrinsic::acos:
638 case Intrinsic::asin:
639 case Intrinsic::atan:
640 case Intrinsic::atan2:
641 case Intrinsic::cosh:
642 case Intrinsic::modf:
643 case Intrinsic::sincos:
644 case Intrinsic::sinh:
646 case Intrinsic::tanh:
649 if (
F.getReturnType()->isDoubleTy()) {
653 case Intrinsic::exp2:
655 case Intrinsic::log10:
656 case Intrinsic::log2:
672 ToReplace.
back().second.replace(0, Prefix.size(),
"__hipstdpar");
674 for (
auto &&[
F, NewF] : ToReplace)
675 F->replaceAllUsesWith(
676 M.getOrInsertFunction(NewF,
F->getFunctionType()).getCallee());
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
ReachingDefInfo 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")))
static GCRegistry::Add< ShadowStackGC > C("shadow-stack", "Very portable GC for uncooperative code generators")
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[]
static SmallVector< std::reference_wrapper< Use > > collectIndirectableUses(GlobalVariable *G)
static constexpr std::pair< StringLiteral, StringLiteral > ReplaceMap[]
static bool checkIfExceptionHandlingIsSupported(const Function *F)
static void maybeHandleGlobals(Module &M)
static void replaceWithIndirectUse(const Use &U, const GlobalVariable *G, Constant *IndirectedG)
static bool isAcceleratorExecutionRoot(const Function *F)
static void eraseFromModule(T &ToErase)
static bool isCXXExceptionRuntimeFunction(StringRef Name)
static void removeUnreachableFunctions(const SmallPtrSet< const Function *, N > &Reachable, Module &M)
static constexpr std::pair< StringLiteral, StringLiteral > MathLibToHipStdPar[]
static void fillIndirectionTable(GlobalVariable *IndirectionTable, SmallVector< Constant * > Indirections)
static bool checkIfSupported(GlobalVariable &G)
static void indirectGlobals(GlobalVariable *IndirectionTable, SmallVector< GlobalVariable * > ToIndirect)
static GlobalVariable * getGlobalForName(GlobalVariable *G)
static GlobalVariable * getIndirectionGlobal(Module *M)
static Constant * appendIndirectedGlobal(const GlobalVariable *IndirectionTable, SmallVector< Constant * > &SymbolIndirections, GlobalVariable *ToIndirect)
static void clearModule(Module &M)
static bool isValidIndirectionTable(GlobalVariable *IndirectionTable)
AcceleratorCodeSelection - Identify all functions reachable from a kernel, removing those that are un...
Module.h This file contains the declarations for the Module class.
ModuleAnalysisManager MAM
Remove Loads Into Fake Uses
This file defines the SmallPtrSet class.
This file defines the SmallVector class.
static LLVM_ABI ArrayType * get(Type *ElementType, uint64_t NumElements)
This static method is the primary way to construct an ArrayType.
LLVM Basic Block Representation.
Base class for all callable instructions (InvokeInst and CallInst) Holds everything related to callin...
Value * getArgOperand(unsigned i) const
An analysis pass to compute the CallGraph for a Module.
static LLVM_ABI Constant * get(ArrayType *T, ArrayRef< Constant * > V)
static LLVM_ABI Constant * getString(LLVMContext &Context, StringRef Initializer, bool AddNull=true, bool ByteString=false)
This method constructs a CDS and initializes it with a text string.
static LLVM_ABI Constant * getAddrSpaceCast(Constant *C, Type *Ty, bool OnlyIfReduced=false)
static LLVM_ABI Constant * get(StructType *T, ArrayRef< Constant * > V)
This is an important base class in LLVM.
iterator find(const_arg_type_t< KeyT > Val)
Diagnostic information for unsupported feature in backend.
void setLinkage(LinkageTypes LT)
Module * getParent()
Get the module that this global value is contained inside of...
@ PrivateLinkage
Like Internal, but omit from symbol table.
Type * getValueType() const
LLVM_ABI void setInitializer(Constant *InitVal)
setInitializer - Sets the initializer for this global variable, removing any existing initializer if ...
void setConstant(bool Val)
void setExternallyInitialized(bool Val)
LLVM_ABI PreservedAnalyses run(Module &M, ModuleAnalysisManager &MAM)
LLVM_ABI PreservedAnalyses run(Module &M, ModuleAnalysisManager &MAM)
LLVM_ABI PreservedAnalyses run(Module &M, ModuleAnalysisManager &MAM)
This provides a uniform API for creating instructions and inserting them into a basic block: either a...
const DebugLoc & getDebugLoc() const
Return the debug location for this node as a DebugLoc.
This is an important class for using LLVM in a threaded context.
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.
static LLVM_ABI PointerType * get(LLVMContext &C, unsigned AddressSpace)
This constructs an opaque pointer to an object in a numbered address space.
static LLVM_ABI PoisonValue * get(Type *T)
Static factory methods - Return an 'poison' object of the specified type.
A set of analyses that are preserved following a run of a transformation pass.
static PreservedAnalyses none()
Convenience factory function for the empty preserved set.
static PreservedAnalyses all()
Construct a special preserved set that preserves all passes.
std::pair< iterator, bool > insert(PtrType Ptr)
Inserts Ptr if and only if there is no element in the container equal to Ptr.
SmallPtrSet - This class implements a set which is optimized for holding SmallSize or less elements.
reference emplace_back(ArgTypes &&... Args)
iterator insert(iterator I, T &&Elt)
void push_back(const T &Elt)
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
Represent a constant reference to a string, i.e.
static constexpr size_t npos
The instances of the Type class are immutable: once they are created, they are never changed.
LLVM_ABI Type * getStructElementType(unsigned N) const
A Use represents the edge between a Value definition and its users.
LLVM Value Representation.
LLVMContext & getContext() const
All values hold a context through their type.
const ParentTy * getParent() const
A raw_ostream that writes to an std::string.
@ AMDGPU_KERNEL
Used for AMDGPU code object kernels.
This is an optimization pass for GlobalISel generic memory operations.
UnaryFunction for_each(R &&Range, UnaryFunction F)
Provide wrappers to std::for_each which take ranges instead of having to pass begin/end explicitly.
decltype(auto) dyn_cast(const From &Val)
dyn_cast<X> - Return the argument parameter cast to the specified type.
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.
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.
bool isa(const From &Val)
isa<X> - Return true if the parameter to the template is an instance of one of the template type argu...
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.
RelativeUniformCounterPtr ValuesPtrExpr VTableAddr Count
DWARFExpression::Operation Op
decltype(auto) cast(const From &Val)
cast<X> - Return the argument parameter cast to the specified type.
auto find_if(R &&Range, UnaryPredicate P)
Provide wrappers to std::find_if which take ranges instead of having to pass begin/end explicitly.
AnalysisManager< Module > ModuleAnalysisManager
Convenience typedef for the Module analysis manager.