LLVM: lib/Transforms/HipStdPar/HipStdPar.cpp Source File (original) (raw)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
53
65
66#include
67#include
68#include
69
70using namespace llvm;
71
72template
74 ToErase.replaceAllUsesWith(PoisonValue::get(ToErase.getType()));
75 ToErase.eraseFromParent();
76}
77
79 if (.isThreadLocal())
80 return true;
81
82 G.dropDroppableUses();
83
84 if (.isConstantUsed())
85 return true;
86
87 std::string W;
89
90 OS << "Accelerator does not support the thread_local variable "
91 << G.getName();
92
96 do {
97 auto U = std::move(Tmp.back());
99
100 if (!Visited.insert(U).second)
101 continue;
102
105 else
106 Tmp.insert(Tmp.end(), U->user_begin(), U->user_end());
107 } while ( && !Tmp.empty());
108
109 assert(I && "thread_local global should have at least one non-constant use.");
110
111 G.getContext().diagnose(
114
115 return false;
116}
117
119 while (!M.functions().empty())
121 while (!M.globals().empty())
123 while (!M.aliases().empty())
125 while (!M.ifuncs().empty())
127}
128
131
133
135 while (!Stack.empty()) {
136 Use &U = Stack.pop_back_val();
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
145}
146
148
149
152
153 GlobalVariable *N = G->getParent()->getOrInsertGlobal("", CDS->getType());
154 N->setInitializer(CDS);
156 N->setConstant(true);
157
158 return N;
159}
160
162
163
164
166 M->getContext(), M->getDataLayout().getDefaultGlobalsAddressSpace());
167 GlobalVariable *NewG = M->getOrInsertGlobal("", PtrTy);
168
173
174 return NewG;
175}
176
182
184 auto *SymbolListTy = cast(InitTy->getStructElementType(2));
185 Type *NameTy = SymbolListTy->getElementType(0);
186 Type *IndirectTy = SymbolListTy->getElementType(1);
187
193 SymbolIndirections.push_back(Entry);
194
195 return IndirectG;
196}
197
201 size_t SymCnt = Indirections.size();
202
205 auto *SymbolTy = cast(InitTy->getStructElementType(2));
206
207 Constant *Count = ConstantInt::get(InitTy->getStructElementType(0), SymCnt);
208 M->removeGlobalVariable(IndirectionTable);
210 M->getOrInsertGlobal("", ArrayType::get(SymbolTy, SymCnt));
212 Symbols->setInitializer(
214 Symbols->setConstant(true);
215
219 M->insertGlobalVariable(IndirectionTable);
221}
222
226
228 unsigned OpIdx = U.getOperandNo();
230
231
232
233
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;
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
254 std::string W;
256
258 bool Valid = false;
259
261 OS << "The Indirection Table must be a struct type; ";
262 Ty->print(OS);
263 OS << " is incorrect.\n";
265 OS << "The Indirection Table must have 3 elements; "
266 << cast(Ty)->getNumElements() << " is incorrect.\n";
268 OS << "The first element in the Indirection Table must be an integer; ";
270 OS << " is incorrect.\n";
272 OS << "The second element in the Indirection Table must be a pointer; ";
274 OS << " is incorrect.\n";
276 OS << "The third element in the Indirection Table must be a struct type; ";
278 OS << " is incorrect.\n";
279 } else {
280 Valid = true;
281 }
282
283 if (!Valid)
285
286 return Valid;
287}
288
291
292
293
295 for (auto &&G : ToIndirect) {
297
298 if (Uses.empty())
299 continue;
300
303
306
308 }
309
310 if (SymbolIndirections.empty())
311 return;
312
314}
315
317 unsigned GlobAS = M.getDataLayout().getDefaultGlobalsAddressSpace();
318
320 for (auto &&G : M.globals()) {
323 if (G.getAddressSpace() != GlobAS)
324 continue;
325 if (G.isConstant() && G.hasInitializer() && G.hasAtLeastLocalUnnamedAddr())
326 continue;
327
329 }
330
331 if (ToIndirect.empty())
332 return;
333
334 if (auto *IT = M.getNamedGlobal("__hipstdpar_symbol_indirection_table")) {
338 } else {
339 for (auto &&G : ToIndirect) {
340
341 if (->hasInitializer())
343 }
344 }
345}
346
347template
352 return !Reachable.contains(F);
353
354 return false;
355 });
356
359 return .isIntrinsic() && !Reachable.contains(&F);
360 });
361
363}
364
366 if ()
367 return false;
368
370}
371
373 const auto Dx = F->getName().rfind("__hipstdpar_unsupported");
374
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"
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
401
403 for (auto &&CGN : CGA) {
405 continue;
406
407 Reachable.insert(CGN.first);
408
410 do {
411 auto F = std::move(Tmp.back());
413
414 for (auto &&N : *CGA[F]) {
415 if (.second)
416 continue;
417 if (.second->getFunction())
418 continue;
419 if (Reachable.contains(N.second->getFunction()))
420 continue;
421
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))
434 else
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
486
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
497
498 for (auto &&F : M) {
499 if (.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
516 F.getSubprogram(),
518 }
519 }
520
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
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())
580
582 for (auto &&F : M) {
583 if (.hasName())
584 continue;
585
588
589 switch (ID) {
591 auto It =
594 continue;
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:🪵
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
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!")
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")))
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.
MachineInstr unsigned OpIdx
ModuleAnalysisManager MAM
Remove Loads Into Fake Uses
static unsigned getNumElements(Type *Ty)
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.
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)
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)
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
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(Type *ElementType, unsigned AddressSpace)
This constructs a pointer to an object of the specified type 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.
StringRef - 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.
LLVM_ABI LLVMContext & getContext() const
All values hold a context through their type.
const ParentTy * getParent() const
A raw_ostream that writes to an std::string.
unsigned ID
LLVM IR allows to use arbitrary numbers as calling convention identifiers.
@ AMDGPU_KERNEL
Used for AMDGPU code object kernels.
@ C
The default llvm calling convention, compatible with C.
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 - 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.
FunctionAddr VTableAddr Count
bool isa(const From &Val)
isa - 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.
DWARFExpression::Operation Op
decltype(auto) cast(const From &Val)
cast - 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.