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 (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

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 (I && !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;

243 Op = I->getOperand(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

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 (G->hasInitializer())

343 }

344 }

345}

346

347template

352 return !Reachable.contains(F);

353

354 return false;

355 });

356

359 return F.isIntrinsic() && !Reachable.contains(&F);

360 });

361

363}

364

366 if (F)

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 (N.second)

416 continue;

417 if (N.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 (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

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 (F.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.