LLVM: lib/Target/SPIRV/SPIRVPrepareFunctions.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

33#include "llvm/IR/IntrinsicsSPIRV.h"

36#include

37

38using namespace llvm;

39

40namespace {

41

42class SPIRVPrepareFunctions : public ModulePass {

43 const SPIRVTargetMachine &TM;

44 bool substituteIntrinsicCalls(Function *F);

45 Function *removeAggregateTypesFromSignature(Function *F);

46 bool removeAggregateTypesFromCalls(Function *F);

47

48public:

49 static char ID;

50 SPIRVPrepareFunctions(const SPIRVTargetMachine &TM)

51 : ModulePass(ID), TM(TM) {}

52

53 bool runOnModule(Module &M) override;

54

55 StringRef getPassName() const override { return "SPIRV prepare functions"; }

56

57 void getAnalysisUsage(AnalysisUsage &AU) const override {

58 ModulePass::getAnalysisUsage(AU);

59 }

60};

61

64 cl::desc("Emit unknown intrinsics as calls to external functions. A "

65 "comma-separated input list of intrinsic prefixes must be "

66 "provided, and only intrinsics carrying a listed prefix get "

67 "emitted as described."),

69}

70

71char SPIRVPrepareFunctions::ID = 0;

72

74 "SPIRV prepare functions", false, false)

75

77 Function *IntrinsicFunc = II->getCalledFunction();

78 assert(IntrinsicFunc && "Missing function");

79 std::string FuncName = IntrinsicFunc->getName().str();

81 FuncName = "spirv." + FuncName;

82 return FuncName;

83}

84

89 Function *F = M->getFunction(Name);

90 if (F && F->getFunctionType() == FT)

91 return F;

93 if (F)

96 return NewF;

97}

98

100

101

102

103

106 return false;

107

109 std::string FuncName = lowerLLVMIntrinsicName(Intrinsic);

111 FuncName += ".volatile";

112

113 Function *F = M->getFunction(FuncName);

114 if (F) {

116 return true;

117 }

118

120 M->getOrInsertFunction(FuncName, Intrinsic->getFunctionType());

121 auto IntrinsicID = Intrinsic->getIntrinsicID();

122 Intrinsic->setCalledFunction(FC);

123

125 assert(F && "Callee must be a function");

126

127 switch (IntrinsicID) {

128 case Intrinsic::memset: {

133 Argument *IsVolatile = F->getArg(3);

136 Len->setName("len");

137 IsVolatile->setName("isvolatile");

140 auto *MemSet = IRB.CreateMemSet(Dest, Val, Len, MSI->getDestAlign(),

141 MSI->isVolatile());

144 MemSet->eraseFromParent();

145 break;

146 }

147 case Intrinsic::bswap: {

151 F->getArg(0));

155 break;

156 }

157 default:

158 break;

159 }

160 return true;

161}

162

165 AnnoVal = Ref->getOperand(0);

167 OptAnnoVal = Ref->getOperand(0);

168

169 std::string Anno;

173 Anno = Str;

174 }

175

176

178 C && C->getNumOperands()) {

179 Value *MaybeStruct = C->getOperand(0);

181 for (unsigned I = 0, E = Struct->getNumOperands(); I != E; ++I) {

183 Anno += (I == 0 ? ": " : ", ") +

184 std::to_string(CInt->getType()->getIntegerBitWidth() == 1

185 ? CInt->getZExtValue()

186 : CInt->getSExtValue());

187 }

189

190 for (unsigned I = 0, E = Struct->getType()->getStructNumElements();

191 I != E; ++I)

192 Anno += I == 0 ? ": 0" : ", 0";

193 }

194 }

195 return Anno;

196}

197

199 const std::string &Anno,

202

203

204

205

206 static const std::regex R(

207 "\\{(\\d+)(?:[:,](\\d+|\"[^\"]*\")(?:,(\\d+|\"[^\"]*\"))*)?\\}");

209 int Pos = 0;

210 for (std::sregex_iterator

211 It = std::sregex_iterator(Anno.begin(), Anno.end(), R),

212 ItEnd = std::sregex_iterator();

213 It != ItEnd; ++It) {

214 if (It->position() != Pos)

216 Pos = It->position() + It->length();

217 std::smatch Match = *It;

219 for (std::size_t i = 1; i < Match.size(); ++i) {

220 std::ssub_match SMatch = Match[i];

221 std::string Item = SMatch.str();

222 if (Item.length() == 0)

223 break;

224 if (Item[0] == '"') {

225 Item = Item.substr(1, Item.length() - 2);

226

227 static const std::regex RStr("^(\\d+)(?:,(\\d+))*$");

228 if (std::smatch MatchStr; std::regex_match(Item, MatchStr, RStr)) {

229 for (std::size_t SubIdx = 1; SubIdx < MatchStr.size(); ++SubIdx)

230 if (std::string SubStr = MatchStr[SubIdx].str(); SubStr.length())

232 ConstantInt::get(Int32Ty, std::stoi(SubStr))));

233 } else {

235 }

239 } else {

241 }

242 }

243 if (MDsItem.size() == 0)

246 }

247 return Pos == static_cast<int>(Anno.length()) ? std::move(MDs)

249}

250

254

255

256 Value *PtrArg = nullptr;

258 PtrArg = BI->getOperand(0);

259 else

260 PtrArg = II->getOperand(0);

261 std::string Anno =

263 4 < II->arg_size() ? II->getArgOperand(4) : nullptr);

264

265

267

268

269

270

271

272 if (MDs.size() == 0) {

274 Int32Ty, static_cast<uint32_t>(SPIRV::Decoration::UserSemantic)));

276 }

277

278

282 Intrinsic::spv_assign_decoration, {PtrArg->getType()},

284 II->replaceAllUsesWith(II->getOperand(0));

285}

286

288

289

290

291

294 Type *FSHRetTy = FSHFuncTy->getReturnType();

295 const std::string FuncName = lowerLLVMIntrinsicName(FSHIntrinsic);

298

299 if (!FSHFunc->empty()) {

301 return;

302 }

306

307

308

311 unsigned BitWidth = IntTy->getIntegerBitWidth();

313 Value *BitWidthForInsts =

314 VectorTy

316 : BitWidthConstant;

317 Value *RotateModVal =

318 IRB.CreateURem( FSHFunc->getArg(2), BitWidthForInsts);

319 Value *FirstShift = nullptr, *SecShift = nullptr;

320 if (FSHIntrinsic->getIntrinsicID() == Intrinsic::fshr) {

321

322

323 FirstShift = IRB.CreateLShr(FSHFunc->getArg(1), RotateModVal);

324 } else {

325

326

327 FirstShift = IRB.CreateShl(FSHFunc->getArg(0), RotateModVal);

328 }

329

330

331

332 Value *SubRotateVal = IRB.CreateSub(BitWidthForInsts, RotateModVal);

333 if (FSHIntrinsic->getIntrinsicID() == Intrinsic::fshr) {

334

335

336 SecShift = IRB.CreateShl(FSHFunc->getArg(0), SubRotateVal);

337 } else {

338

339

341 }

342

344

346}

347

351 if (!ConstrainedCmpIntrinsic)

352 return;

353

357 IRBuilder<> Builder(ConstrainedCmpIntrinsic);

358 Value *FCmp = Builder.CreateFCmp(Pred, LHS, RHS);

361}

362

364

365

366

367

368

369

370

371

372

373 if (II->getIntrinsicID() == Intrinsic::assume) {

375 II->getModule(), Intrinsic::SPVIntrinsics::spv_assume);

376 II->setCalledFunction(F);

377 } else if (II->getIntrinsicID() == Intrinsic::expect) {

379 II->getModule(), Intrinsic::SPVIntrinsics::spv_expect,

380 {II->getOperand(0)->getType()});

381 II->setCalledFunction(F);

382 } else {

384 }

385}

386

390 std::optional Size =

391 Alloca->getAllocationSize(Alloca->getDataLayout());

392 Value *SizeVal = Builder.getInt64(Size ? *Size : -1);

393 Builder.CreateIntrinsic(NewID, Alloca->getType(),

394 {SizeVal, II->getArgOperand(0)});

395 II->eraseFromParent();

396 return true;

397}

398

399

400

401bool SPIRVPrepareFunctions::substituteIntrinsicCalls(Function *F) {

403 const SPIRVSubtarget &STI = TM.getSubtarget(*F);

405 for (BasicBlock &BB : *F) {

409 continue;

412 continue;

414 switch (II->getIntrinsicID()) {

415 case Intrinsic::memset:

416 case Intrinsic::bswap:

418 break;

419 case Intrinsic::fshl:

420 case Intrinsic::fshr:

423 break;

424 case Intrinsic::assume:

425 case Intrinsic::expect:

426 if (STI.canUseExtension(SPIRV::Extension::SPV_KHR_expect_assume))

429 break;

430 case Intrinsic::lifetime_start:

433 II, Intrinsic::SPVIntrinsics::spv_lifetime_start);

434 } else {

435 II->eraseFromParent();

437 }

438 break;

439 case Intrinsic::lifetime_end:

442 II, Intrinsic::SPVIntrinsics::spv_lifetime_end);

443 } else {

444 II->eraseFromParent();

446 }

447 break;

448 case Intrinsic::ptr_annotation:

451 break;

452 case Intrinsic::experimental_constrained_fcmp:

453 case Intrinsic::experimental_constrained_fcmps:

455 EraseFromParent);

457 break;

458 default:

460 any_of(SPVAllowUnknownIntrinsics, [II](auto &&Prefix) {

462 return false;

463 return II->getCalledFunction()->getName().starts_with(Prefix);

464 }))

466 break;

467 }

468 }

469 }

470 for (auto *I : EraseFromParent)

471 I->eraseFromParent();

473}

474

475static void

477 SmallVector<std::pair<int, Type *>> ChangedTys,

479

482

485 transform(ChangedTys, std::back_inserter(MDArgs), [=, &Ctx](auto &&CTy) {

489 });

491}

492

493

494

496SPIRVPrepareFunctions::removeAggregateTypesFromSignature(Function *F) {

497 bool IsRetAggr = F->getReturnType()->isAggregateType();

498

499 if (F->isIntrinsic() && IsRetAggr)

500 return F;

501

503

504 bool HasAggrArg = llvm::any_of(F->args(), [](Argument &Arg) {

505 return Arg.getType()->isAggregateType();

506 });

507 bool DoClone = IsRetAggr || HasAggrArg;

508 if (!DoClone)

509 return F;

511 Type *RetType = IsRetAggr ? B.getInt32Ty() : F->getReturnType();

512 if (IsRetAggr)

513 ChangedTypes.push_back(std::pair<int, Type *>(-1, F->getReturnType()));

515 for (const auto &Arg : F->args()) {

516 if (Arg.getType()->isAggregateType()) {

519 std::pair<int, Type *>(Arg.getArgNo(), Arg.getType()));

520 } else

521 ArgTypes.push_back(Arg.getType());

522 }

523 FunctionType *NewFTy =

524 FunctionType::get(RetType, ArgTypes, F->getFunctionType()->isVarArg());

527 F->getName(), F->getParent());

528

530 auto NewFArgIt = NewF->arg_begin();

531 for (auto &Arg : F->args()) {

532 StringRef ArgName = Arg.getName();

533 NewFArgIt->setName(ArgName);

534 VMap[&Arg] = &(*NewFArgIt++);

535 }

537

538 CloneFunctionInto(NewF, F, VMap, CloneFunctionChangeType::LocalChangesOnly,

539 Returns);

541

544 std::move(ChangedTypes), NewF->getName());

545

547 if (CallInst *CI;

551 C->handleOperandChange(F, NewF);

552 else

553 U->replaceUsesOfWith(F, NewF);

554 }

555

556

557 if (RetType != F->getReturnType())

558 TM.getSubtarget(*F).getSPIRVGlobalRegistry()->addMutated(

559 NewF, F->getReturnType());

560 return NewF;

561}

562

563

564

565

566bool SPIRVPrepareFunctions::removeAggregateTypesFromCalls(Function *F) {

567 if (F->isDeclaration() || F->isIntrinsic())

568 return false;

569

573 if (!CB->getCalledOperand() || CB->getCalledFunction())

574 continue;

575 if (CB->getType()->isAggregateType() ||

577 [](auto &&Arg) { return Arg->getType()->isAggregateType(); }))

579 }

580 }

581

582 if (Calls.empty())

583 return false;

584

586

587 for (auto &&[CB, NewFnTy] : Calls) {

590

591 Type *RetTy = CB->getType();

595 }

596

597 for (auto &&Arg : CB->args()) {

598 if (Arg->getType()->isAggregateType()) {

599 NewArgTypes.push_back(B.getInt32Ty());

600 ChangedTypes.emplace_back(Arg.getOperandNo(), Arg->getType());

601 } else {

602 NewArgTypes.push_back(Arg->getType());

603 }

604 }

605 NewFnTy = FunctionType::get(RetTy, NewArgTypes,

606 CB->getFunctionType()->isVarArg());

607

608 if (!CB->hasName())

609 CB->setName("spv.mutated_callsite." + F->getName());

610 else

611 CB->setName("spv.named_mutated_callsite." + F->getName() + "." +

612 CB->getName());

613

615 F->getParent()->getOrInsertNamedMetadata("spv.mutated_callsites"),

616 std::move(ChangedTypes), CB->getName());

617 }

618

619 for (auto &&[CB, NewFTy] : Calls) {

620 if (NewFTy->getReturnType() != CB->getType())

621 TM.getSubtarget(*F).getSPIRVGlobalRegistry()->addMutated(

622 CB, CB->getType());

623 CB->mutateFunctionType(NewFTy);

624 }

625

626 return true;

627}

628

629bool SPIRVPrepareFunctions::runOnModule(Module &M) {

631 for (Function &F : M) {

632 Changed |= substituteIntrinsicCalls(&F);

634 Changed |= removeAggregateTypesFromCalls(&F);

635 }

636

637 std::vector<Function *> FuncsWorklist;

638 for (auto &F : M)

639 FuncsWorklist.push_back(&F);

640

641 for (auto *F : FuncsWorklist) {

642 Function *NewF = removeAggregateTypesFromSignature(F);

643

644 if (NewF != F) {

645 F->eraseFromParent();

647 }

648 }

650}

651

652ModulePass *

654 return new SPIRVPrepareFunctions(TM);

655}

assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")

Expand Atomic instructions

static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")

static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")

Machine Check Debug Module

uint64_t IntrinsicInst * II

#define INITIALIZE_PASS(passName, arg, name, cfg, analysis)

static void lowerFunnelShifts(IntrinsicInst *FSHIntrinsic)

Definition SPIRVPrepareFunctions.cpp:287

static std::string getAnnotation(Value *AnnoVal, Value *OptAnnoVal)

Definition SPIRVPrepareFunctions.cpp:163

static bool lowerIntrinsicToFunction(IntrinsicInst *Intrinsic)

Definition SPIRVPrepareFunctions.cpp:99

static void lowerConstrainedFPCmpIntrinsic(ConstrainedFPCmpIntrinsic *ConstrainedCmpIntrinsic, SmallVector< Instruction * > &EraseFromParent)

Definition SPIRVPrepareFunctions.cpp:348

static void lowerPtrAnnotation(IntrinsicInst *II)

Definition SPIRVPrepareFunctions.cpp:251

static SmallVector< Metadata * > parseAnnotation(Value *I, const std::string &Anno, LLVMContext &Ctx, Type *Int32Ty)

Definition SPIRVPrepareFunctions.cpp:198

static bool toSpvLifetimeIntrinsic(IntrinsicInst *II, Intrinsic::ID NewID)

Definition SPIRVPrepareFunctions.cpp:387

static void lowerExpectAssume(IntrinsicInst *II)

Definition SPIRVPrepareFunctions.cpp:363

static void addFunctionTypeMutation(NamedMDNode *NMD, SmallVector< std::pair< int, Type * > > ChangedTys, StringRef Name)

Definition SPIRVPrepareFunctions.cpp:476

static Function * getOrCreateFunction(Module *M, Type *RetTy, ArrayRef< Type * > ArgTypes, StringRef Name)

Definition SPIRVPrepareFunctions.cpp:85

This class represents an incoming formal argument to a Function.

ArrayRef - Represent a constant reference to an array (0 or more elements consecutively in memory),...

LLVM Basic Block Representation.

static BasicBlock * Create(LLVMContext &Context, const Twine &Name="", Function *Parent=nullptr, BasicBlock *InsertBefore=nullptr)

Creates a new BasicBlock.

Function * getCalledFunction() const

Returns the function called, or null if this is an indirect function invocation or the function signa...

Value * getArgOperand(unsigned i) const

FunctionType * getFunctionType() const

void setCalledFunction(Function *Fn)

Sets the function called, including updating the function type.

Predicate

This enumeration lists the possible predicates for CmpInst subclasses.

This is the shared class of boolean and integer constants.

static LLVM_ABI Constant * getNullValue(Type *Ty)

Constructor to create a '0' constant of arbitrary type.

Constrained floating point compare intrinsics.

LLVM_ABI FCmpInst::Predicate getPredicate() const

Class to represent fixed width SIMD vectors.

unsigned getNumElements() const

A handy container for a FunctionType+Callee-pointer pair, which can be passed around as a single enti...

static LLVM_ABI FunctionType * get(Type *Result, ArrayRef< Type * > Params, bool isVarArg)

This static method is the primary way of constructing a FunctionType.

static Function * Create(FunctionType *Ty, LinkageTypes Linkage, unsigned AddrSpace, const Twine &N="", Module *M=nullptr)

FunctionType * getFunctionType() const

Returns the FunctionType for me.

bool isIntrinsic() const

isIntrinsic - Returns true if the function's name starts with "llvm.".

Type * getReturnType() const

Returns the type of the ret val.

void setCallingConv(CallingConv::ID CC)

Argument * getArg(unsigned i) const

Module * getParent()

Get the module that this global value is contained inside of...

void setDSOLocal(bool Local)

@ ExternalLinkage

Externally visible function.

LLVM_ABI Value * CreateVectorSplat(unsigned NumElts, Value *V, const Twine &Name="")

Return a vector value that contains.

Value * CreateLShr(Value *LHS, Value *RHS, const Twine &Name="", bool isExact=false)

ReturnInst * CreateRet(Value *V)

Create a 'ret ' instruction.

LLVM_ABI CallInst * CreateIntrinsic(Intrinsic::ID ID, ArrayRef< Type * > Types, ArrayRef< Value * > Args, FMFSource FMFSource={}, const Twine &Name="")

Create a call to intrinsic ID with Args, mangled using Types.

Value * CreateSub(Value *LHS, Value *RHS, const Twine &Name="", bool HasNUW=false, bool HasNSW=false)

Value * CreateShl(Value *LHS, Value *RHS, const Twine &Name="", bool HasNUW=false, bool HasNSW=false)

CallInst * CreateMemSet(Value *Ptr, Value *Val, uint64_t Size, MaybeAlign Align, bool isVolatile=false, const AAMDNodes &AAInfo=AAMDNodes())

Create and insert a memset to the specified pointer and the specified value.

ReturnInst * CreateRetVoid()

Create a 'ret void' instruction.

void SetInsertPoint(BasicBlock *TheBB)

This specifies that created instructions should be appended to the end of the specified block.

Value * CreateOr(Value *LHS, Value *RHS, const Twine &Name="", bool IsDisjoint=false)

ConstantInt * getInt(const APInt &AI)

Get a constant integer value.

Value * CreateURem(Value *LHS, Value *RHS, const Twine &Name="")

This provides a uniform API for creating instructions and inserting them into a basic block: either a...

LLVM_ABI const Module * getModule() const

Return the module owning the function this instruction belongs to or nullptr it the function does not...

A wrapper class for inspecting calls to intrinsic functions.

Intrinsic::ID getIntrinsicID() const

Return the intrinsic ID of this intrinsic.

void LowerIntrinsicCall(CallInst *CI)

Replace a call to the specified intrinsic function.

This is an important class for using LLVM in a threaded context.

static MDTuple * get(LLVMContext &Context, ArrayRef< Metadata * > MDs)

static LLVM_ABI MDString * get(LLVMContext &Context, StringRef Str)

This class wraps the llvm.memset and llvm.memset.inline intrinsics.

ModulePass class - This class is used to implement unstructured interprocedural optimizations and ana...

A Module instance is used to store all the information related to an LLVM module.

LLVMContext & getContext() const

Get the global data context.

NamedMDNode * getOrInsertNamedMetadata(StringRef Name)

Return the named MDNode in the module with the specified name.

Module * getParent()

Get the module that holds this named metadata collection.

LLVM_ABI void addOperand(MDNode *M)

bool canUseExtension(SPIRV::Extension::Extension E) const

reference emplace_back(ArgTypes &&... Args)

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.

std::string str() const

str - Get the contents as an std::string.

const Triple & getTargetTriple() const

const STC & getSubtarget(const Function &F) const

This method returns a pointer to the specified type of TargetSubtargetInfo.

VendorType getVendor() const

Get the parsed vendor type of this triple.

The instances of the Type class are immutable: once they are created, they are never changed.

static LLVM_ABI IntegerType * getInt32Ty(LLVMContext &C)

bool isAggregateType() const

Return true if the type is an aggregate type.

LLVM Value Representation.

Type * getType() const

All values are typed, get the type of this value.

LLVM_ABI void setName(const Twine &Name)

Change the name of the value.

LLVM_ABI void replaceAllUsesWith(Value *V)

Change all uses of this to point to a new Value.

LLVM_ABI StringRef getName() const

Return a constant reference to the value's name.

LLVM_ABI void takeName(Value *V)

Transfer the name from V to this value.

Type * getElementType() const

#define llvm_unreachable(msg)

Marks that the current location is not supposed to be reachable.

@ SPIR_FUNC

Used for SPIR non-kernel device functions.

@ C

The default llvm calling convention, compatible with C.

This namespace contains an enum with a value for every intrinsic/builtin function known by LLVM.

LLVM_ABI Function * getOrInsertDeclaration(Module *M, ID id, ArrayRef< Type * > Tys={})

Look up the Function declaration of the intrinsic id in the Module M.

This is an optimization pass for GlobalISel generic memory operations.

decltype(auto) dyn_cast(const From &Val)

dyn_cast - Return the argument parameter cast to the specified type.

FunctionAddr VTableAddr uintptr_t uintptr_t Int32Ty

LLVM_ABI bool getConstantStringInfo(const Value *V, StringRef &Str, bool TrimAtNul=true)

This function computes the length of a null-terminated C string pointed to by V.

iterator_range< early_inc_iterator_impl< detail::IterOfRange< RangeT > > > make_early_inc_range(RangeT &&Range)

Make a range that does early increment to allow mutation of the underlying range without disrupting i...

bool sortBlocks(Function &F)

auto dyn_cast_or_null(const Y &Val)

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 any_of(R &&range, UnaryPredicate P)

Provide wrappers to std::any_of which take ranges instead of having to pass begin/end explicitly.

class LLVM_GSL_OWNER SmallVector

Forward declaration of SmallVector so that calculateSmallVectorDefaultInlinedElements can reference s...

bool isa(const From &Val)

isa - Return true if the parameter to the template is an instance of one of the template type argu...

@ Ref

The access may reference the value stored in memory.

IRBuilder(LLVMContext &, FolderTy, InserterTy, MDNode *, ArrayRef< OperandBundleDef >) -> IRBuilder< FolderTy, InserterTy >

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.

constexpr unsigned BitWidth

ValueMap< const Value *, WeakTrackingVH > ValueToValueMapTy

LLVM_ABI void CloneFunctionInto(Function *NewFunc, const Function *OldFunc, ValueToValueMapTy &VMap, CloneFunctionChangeType Changes, SmallVectorImpl< ReturnInst * > &Returns, const char *NameSuffix="", ClonedCodeInfo *CodeInfo=nullptr, ValueMapTypeRemapper *TypeMapper=nullptr, ValueMaterializer *Materializer=nullptr)

Clone OldFunc into NewFunc, transforming the old arguments into references to VMap values.

decltype(auto) cast(const From &Val)

cast - Return the argument parameter cast to the specified type.

bool to_integer(StringRef S, N &Num, unsigned Base=0)

Convert the string S to an integer of the specified type using the radix Base. If Base is 0,...

ModulePass * createSPIRVPrepareFunctionsPass(const SPIRVTargetMachine &TM)

Definition SPIRVPrepareFunctions.cpp:653

LLVM_ABI void expandMemSetAsLoop(MemSetInst *MemSet)

Expand MemSet as a loop. MemSet is not deleted.

Implement std::hash so that hash_code can be used in STL containers.