LLVM 23.0.0git
SPIRVPrepareFunctions.cpp
Go to the documentation of this file.
1//===-- SPIRVPrepareFunctions.cpp - modify function signatures --*- C++ -*-===//
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//
9// This pass modifies function signatures containing aggregate arguments
10// and/or return value before IRTranslator. Information about the original
11// signatures is stored in metadata. It is used during call lowering to
12// restore correct SPIR-V types of function arguments and return values.
13// This pass also substitutes some llvm intrinsic calls with calls to newly
14// generated functions (as the Khronos LLVM/SPIR-V Translator does).
15//
16// NOTE: this pass is a module-level one due to the necessity to modify
17// GVs/functions.
18//
19//===----------------------------------------------------------------------===//
20
22#include "SPIRV.h"
23#include "SPIRVBuiltins.h"
24#include "SPIRVSubtarget.h"
25#include "SPIRVTargetMachine.h"
26#include "SPIRVUtils.h"
31#include "llvm/IR/IRBuilder.h"
35#include "llvm/IR/Intrinsics.h"
36#include "llvm/IR/IntrinsicsSPIRV.h"
40#include <regex>
41
42using namespace llvm;
43
44namespace {
45
46class SPIRVPrepareFunctionsImpl {
47 const SPIRVTargetMachine &TM;
48 bool substituteIntrinsicCalls(Function *F);
49 bool substituteAbortKHRCalls(Function *F);
50 bool terminateBlocksAfterTrap(Module &M, Intrinsic::ID IID);
51 Function *removeAggregateTypesFromSignature(Function *F);
52 bool removeAggregateTypesFromCalls(Function *F);
53
54public:
55 SPIRVPrepareFunctionsImpl(const SPIRVTargetMachine &TM) : TM(TM) {}
56 bool runOnModule(Module &M);
57};
58
59class SPIRVPrepareFunctionsLegacy : public ModulePass {
60 const SPIRVTargetMachine &TM;
61
62public:
63 static char ID;
64 SPIRVPrepareFunctionsLegacy(const SPIRVTargetMachine &TM)
65 : ModulePass(ID), TM(TM) {}
66
67 bool runOnModule(Module &M) override {
68 return SPIRVPrepareFunctionsImpl(TM).runOnModule(M);
69 }
70
71 StringRef getPassName() const override { return "SPIRV prepare functions"; }
72};
73
74static cl::list<std::string> SPVAllowUnknownIntrinsics(
75 "spv-allow-unknown-intrinsics", cl::CommaSeparated,
76 cl::desc("Emit unknown intrinsics as calls to external functions. A "
77 "comma-separated input list of intrinsic prefixes must be "
78 "provided, and only intrinsics carrying a listed prefix get "
79 "emitted as described."),
80 cl::value_desc("intrinsic_prefix_0,intrinsic_prefix_1"), cl::ValueOptional);
81} // namespace
82
83char SPIRVPrepareFunctionsLegacy::ID = 0;
84
85INITIALIZE_PASS(SPIRVPrepareFunctionsLegacy, "spirv-prepare-functions",
86 "SPIRV prepare functions", false, false)
87
88static std::string lowerLLVMIntrinsicName(IntrinsicInst *II) {
89 Function *IntrinsicFunc = II->getCalledFunction();
90 assert(IntrinsicFunc && "Missing function");
91 std::string FuncName = IntrinsicFunc->getName().str();
92 llvm::replace(FuncName, '.', '_');
93 FuncName = "spirv." + FuncName;
94 return FuncName;
95}
96
98 ArrayRef<Type *> ArgTypes,
99 StringRef Name) {
100 FunctionType *FT = FunctionType::get(RetTy, ArgTypes, false);
101 Function *F = M->getFunction(Name);
102 if (F && F->getFunctionType() == FT)
103 return F;
105 if (F)
106 NewF->setDSOLocal(F->isDSOLocal());
108 return NewF;
109}
110
112 const TargetTransformInfo &TTI) {
113 // For @llvm.memset.* intrinsic cases with constant value and length arguments
114 // are emulated via "storing" a constant array to the destination. For other
115 // cases we wrap the intrinsic in @spirv.llvm_memset_* function and expand the
116 // intrinsic to a loop via expandMemSetAsLoop().
117 if (auto *MSI = dyn_cast<MemSetInst>(Intrinsic))
118 if (isa<Constant>(MSI->getValue()) && isa<ConstantInt>(MSI->getLength()))
119 return false; // It is handled later using OpCopyMemorySized.
120
121 Module *M = Intrinsic->getModule();
122 std::string FuncName = lowerLLVMIntrinsicName(Intrinsic);
123 if (Intrinsic->isVolatile())
124 FuncName += ".volatile";
125 // Redirect @llvm.intrinsic.* call to @spirv.llvm_intrinsic_*
126 Function *F = M->getFunction(FuncName);
127 if (F) {
128 Intrinsic->setCalledFunction(F);
129 return true;
130 }
131 // TODO copy arguments attributes: nocapture writeonly.
132 FunctionCallee FC =
133 M->getOrInsertFunction(FuncName, Intrinsic->getFunctionType());
134 auto IntrinsicID = Intrinsic->getIntrinsicID();
135 Intrinsic->setCalledFunction(FC);
136
137 F = dyn_cast<Function>(FC.getCallee());
138 assert(F && "Callee must be a function");
139
140 switch (IntrinsicID) {
141 case Intrinsic::memset: {
142 auto *MSI = static_cast<MemSetInst *>(Intrinsic);
143 Argument *Dest = F->getArg(0);
144 Argument *Val = F->getArg(1);
145 Argument *Len = F->getArg(2);
146 Argument *IsVolatile = F->getArg(3);
147 Dest->setName("dest");
148 Val->setName("val");
149 Len->setName("len");
150 IsVolatile->setName("isvolatile");
151 BasicBlock *EntryBB = BasicBlock::Create(M->getContext(), "entry", F);
152 IRBuilder<> IRB(EntryBB);
153 auto *MemSet = IRB.CreateMemSet(Dest, Val, Len, MSI->getDestAlign(),
154 MSI->isVolatile());
155 IRB.CreateRetVoid();
157 MemSet->eraseFromParent();
158 break;
159 }
160 case Intrinsic::bswap: {
161 BasicBlock *EntryBB = BasicBlock::Create(M->getContext(), "entry", F);
162 IRBuilder<> IRB(EntryBB);
163 auto *BSwap = IRB.CreateIntrinsic(Intrinsic::bswap, Intrinsic->getType(),
164 F->getArg(0));
165 IRB.CreateRet(BSwap);
166 IntrinsicLowering IL(M->getDataLayout());
167 IL.LowerIntrinsicCall(BSwap);
168 break;
169 }
170 default:
171 break;
172 }
173 return true;
174}
175
176static std::string getAnnotation(Value *AnnoVal, Value *OptAnnoVal) {
177 if (auto *Ref = dyn_cast_or_null<GetElementPtrInst>(AnnoVal))
178 AnnoVal = Ref->getOperand(0);
179 if (auto *Ref = dyn_cast_or_null<BitCastInst>(OptAnnoVal))
180 OptAnnoVal = Ref->getOperand(0);
181
182 std::string Anno;
183 if (auto *C = dyn_cast_or_null<Constant>(AnnoVal)) {
184 StringRef Str;
185 if (getConstantStringInfo(C, Str))
186 Anno = Str;
187 }
188 // handle optional annotation parameter in a way that Khronos Translator do
189 // (collect integers wrapped in a struct)
190 if (auto *C = dyn_cast_or_null<Constant>(OptAnnoVal);
191 C && C->getNumOperands()) {
192 Value *MaybeStruct = C->getOperand(0);
193 if (auto *Struct = dyn_cast<ConstantStruct>(MaybeStruct)) {
194 for (unsigned I = 0, E = Struct->getNumOperands(); I != E; ++I) {
195 if (auto *CInt = dyn_cast<ConstantInt>(Struct->getOperand(I)))
196 Anno += (I == 0 ? ": " : ", ") +
197 std::to_string(CInt->getType()->getIntegerBitWidth() == 1
198 ? CInt->getZExtValue()
199 : CInt->getSExtValue());
200 }
201 } else if (auto *Struct = dyn_cast<ConstantAggregateZero>(MaybeStruct)) {
202 // { i32 i32 ... } zeroinitializer
203 for (unsigned I = 0, E = Struct->getType()->getStructNumElements();
204 I != E; ++I)
205 Anno += I == 0 ? ": 0" : ", 0";
206 }
207 }
208 return Anno;
209}
210
212 const std::string &Anno,
213 LLVMContext &Ctx,
214 Type *Int32Ty) {
215 // Try to parse the annotation string according to the following rules:
216 // annotation := ({kind} | {kind:value,value,...})+
217 // kind := number
218 // value := number | string
219 static const std::regex R(
220 "\\{(\\d+)(?:[:,](\\d+|\"[^\"]*\")(?:,(\\d+|\"[^\"]*\"))*)?\\}");
222 int Pos = 0;
223 for (std::sregex_iterator
224 It = std::sregex_iterator(Anno.begin(), Anno.end(), R),
225 ItEnd = std::sregex_iterator();
226 It != ItEnd; ++It) {
227 if (It->position() != Pos)
229 Pos = It->position() + It->length();
230 std::smatch Match = *It;
232 for (std::size_t i = 1; i < Match.size(); ++i) {
233 std::ssub_match SMatch = Match[i];
234 std::string Item = SMatch.str();
235 if (Item.length() == 0)
236 break;
237 if (Item[0] == '"') {
238 Item = Item.substr(1, Item.length() - 2);
239 // Acceptable format of the string snippet is:
240 static const std::regex RStr("^(\\d+)(?:,(\\d+))*$");
241 if (std::smatch MatchStr; std::regex_match(Item, MatchStr, RStr)) {
242 for (std::size_t SubIdx = 1; SubIdx < MatchStr.size(); ++SubIdx)
243 if (std::string SubStr = MatchStr[SubIdx].str(); SubStr.length())
245 ConstantInt::get(Int32Ty, std::stoi(SubStr))));
246 } else {
247 MDsItem.push_back(MDString::get(Ctx, Item));
248 }
249 } else if (int32_t Num; llvm::to_integer(StringRef(Item), Num, 10)) {
250 MDsItem.push_back(
251 ConstantAsMetadata::get(ConstantInt::get(Int32Ty, Num)));
252 } else {
253 MDsItem.push_back(MDString::get(Ctx, Item));
254 }
255 }
256 if (MDsItem.size() == 0)
258 MDs.push_back(MDNode::get(Ctx, MDsItem));
259 }
260 return Pos == static_cast<int>(Anno.length()) ? std::move(MDs)
262}
263
265 LLVMContext &Ctx = II->getContext();
267
268 // Retrieve an annotation string from arguments.
269 Value *PtrArg = nullptr;
270 if (auto *BI = dyn_cast<BitCastInst>(II->getArgOperand(0)))
271 PtrArg = BI->getOperand(0);
272 else
273 PtrArg = II->getOperand(0);
274 std::string Anno =
275 getAnnotation(II->getArgOperand(1),
276 4 < II->arg_size() ? II->getArgOperand(4) : nullptr);
277
278 // Parse the annotation.
280
281 // If the annotation string is not parsed successfully we don't know the
282 // format used and output it as a general UserSemantic decoration.
283 // Otherwise MDs is a Metadata tuple (a decoration list) in the format
284 // expected by `spirv.Decorations`.
285 if (MDs.size() == 0) {
286 auto UserSemantic = ConstantAsMetadata::get(ConstantInt::get(
287 Int32Ty, static_cast<uint32_t>(SPIRV::Decoration::UserSemantic)));
288 MDs.push_back(MDNode::get(Ctx, {UserSemantic, MDString::get(Ctx, Anno)}));
289 }
290
291 // Build the internal intrinsic function.
292 IRBuilder<> IRB(II->getParent());
293 IRB.SetInsertPoint(II);
294 IRB.CreateIntrinsic(
295 Intrinsic::spv_assign_decoration, {PtrArg->getType()},
296 {PtrArg, MetadataAsValue::get(Ctx, MDNode::get(Ctx, MDs))});
297 II->replaceAllUsesWith(II->getOperand(0));
298}
299
300static void lowerFunnelShifts(IntrinsicInst *FSHIntrinsic) {
301 // Get a separate function - otherwise, we'd have to rework the CFG of the
302 // current one. Then simply replace the intrinsic uses with a call to the new
303 // function.
304 // Generate LLVM IR for i* @spirv.llvm_fsh?_i* (i* %a, i* %b, i* %c)
305 Module *M = FSHIntrinsic->getModule();
306 FunctionType *FSHFuncTy = FSHIntrinsic->getFunctionType();
307 Type *FSHRetTy = FSHFuncTy->getReturnType();
308 const std::string FuncName = lowerLLVMIntrinsicName(FSHIntrinsic);
309 Function *FSHFunc =
310 getOrCreateFunction(M, FSHRetTy, FSHFuncTy->params(), FuncName);
311
312 if (!FSHFunc->empty()) {
313 FSHIntrinsic->setCalledFunction(FSHFunc);
314 return;
315 }
316 BasicBlock *RotateBB = BasicBlock::Create(M->getContext(), "rotate", FSHFunc);
317 IRBuilder<> IRB(RotateBB);
318 Type *Ty = FSHFunc->getReturnType();
319 // Build the actual funnel shift rotate logic.
320 // In the comments, "int" is used interchangeably with "vector of int
321 // elements".
323 Type *IntTy = VectorTy ? VectorTy->getElementType() : Ty;
324 unsigned BitWidth = IntTy->getIntegerBitWidth();
325 ConstantInt *BitWidthConstant = IRB.getInt({BitWidth, BitWidth});
326 Value *BitWidthForInsts =
327 VectorTy
328 ? IRB.CreateVectorSplat(VectorTy->getNumElements(), BitWidthConstant)
329 : BitWidthConstant;
330 Value *RotateModVal =
331 IRB.CreateURem(/*Rotate*/ FSHFunc->getArg(2), BitWidthForInsts);
332 Value *FirstShift = nullptr, *SecShift = nullptr;
333 if (FSHIntrinsic->getIntrinsicID() == Intrinsic::fshr) {
334 // Shift the less significant number right, the "rotate" number of bits
335 // will be 0-filled on the left as a result of this regular shift.
336 FirstShift = IRB.CreateLShr(FSHFunc->getArg(1), RotateModVal);
337 } else {
338 // Shift the more significant number left, the "rotate" number of bits
339 // will be 0-filled on the right as a result of this regular shift.
340 FirstShift = IRB.CreateShl(FSHFunc->getArg(0), RotateModVal);
341 }
342 // We want the "rotate" number of the more significant int's LSBs (MSBs) to
343 // occupy the leftmost (rightmost) "0 space" left by the previous operation.
344 // Therefore, subtract the "rotate" number from the integer bitsize...
345 Value *SubRotateVal = IRB.CreateSub(BitWidthForInsts, RotateModVal);
346 if (FSHIntrinsic->getIntrinsicID() == Intrinsic::fshr) {
347 // ...and left-shift the more significant int by this number, zero-filling
348 // the LSBs.
349 SecShift = IRB.CreateShl(FSHFunc->getArg(0), SubRotateVal);
350 } else {
351 // ...and right-shift the less significant int by this number, zero-filling
352 // the MSBs.
353 SecShift = IRB.CreateLShr(FSHFunc->getArg(1), SubRotateVal);
354 }
355 // A simple binary addition of the shifted ints yields the final result.
356 IRB.CreateRet(IRB.CreateOr(FirstShift, SecShift));
357
358 FSHIntrinsic->setCalledFunction(FSHFunc);
359}
360
362 ConstrainedFPCmpIntrinsic *ConstrainedCmpIntrinsic,
363 SmallVector<Instruction *> &EraseFromParent) {
364 if (!ConstrainedCmpIntrinsic)
365 return;
366 // Extract the floating-point values being compared
367 Value *LHS = ConstrainedCmpIntrinsic->getArgOperand(0);
368 Value *RHS = ConstrainedCmpIntrinsic->getArgOperand(1);
369 FCmpInst::Predicate Pred = ConstrainedCmpIntrinsic->getPredicate();
370 IRBuilder<> Builder(ConstrainedCmpIntrinsic);
371 Value *FCmp = Builder.CreateFCmp(Pred, LHS, RHS);
372 ConstrainedCmpIntrinsic->replaceAllUsesWith(FCmp);
373 EraseFromParent.push_back(dyn_cast<Instruction>(ConstrainedCmpIntrinsic));
374}
375
377 // If we cannot use the SPV_KHR_expect_assume extension, then we need to
378 // ignore the intrinsic and move on. It should be removed later on by LLVM.
379 // Otherwise we should lower the intrinsic to the corresponding SPIR-V
380 // instruction.
381 // For @llvm.assume we have OpAssumeTrueKHR.
382 // For @llvm.expect we have OpExpectKHR.
383 //
384 // We need to lower this into a builtin and then the builtin into a SPIR-V
385 // instruction.
386 if (II->getIntrinsicID() == Intrinsic::assume) {
388 II->getModule(), Intrinsic::SPVIntrinsics::spv_assume);
389 II->setCalledFunction(F);
390 } else if (II->getIntrinsicID() == Intrinsic::expect) {
392 II->getModule(), Intrinsic::SPVIntrinsics::spv_expect,
393 {II->getOperand(0)->getType()});
394 II->setCalledFunction(F);
395 } else {
396 llvm_unreachable("Unknown intrinsic");
397 }
398}
399
401 auto *LifetimeArg0 = II->getArgOperand(0);
402
403 // If the lifetime argument is a poison value, the intrinsic has no effect.
404 if (isa<PoisonValue>(LifetimeArg0)) {
405 II->eraseFromParent();
406 return true;
407 }
408
409 IRBuilder<> Builder(II);
410 auto *Alloca = cast<AllocaInst>(LifetimeArg0);
411 std::optional<TypeSize> Size =
412 Alloca->getAllocationSize(Alloca->getDataLayout());
413 Value *SizeVal = Builder.getInt64(Size ? *Size : -1);
414 Builder.CreateIntrinsic(NewID, Alloca->getType(), {SizeVal, LifetimeArg0});
415 II->eraseFromParent();
416 return true;
417}
418
419static void
421 SmallVector<Instruction *> &EraseFromParent) {
422 auto *FPI = cast<ConstrainedFPIntrinsic>(II);
423 Value *A = FPI->getArgOperand(0);
424 Value *Mul = FPI->getArgOperand(1);
425 Value *Add = FPI->getArgOperand(2);
426 IRBuilder<> Builder(II->getParent());
427 Builder.SetInsertPoint(II);
428 std::optional<RoundingMode> Rounding = FPI->getRoundingMode();
429 Value *Product = Builder.CreateFMul(A, Mul, II->getName() + ".mul");
430 Value *Result = Builder.CreateConstrainedFPBinOp(
431 Intrinsic::experimental_constrained_fadd, Product, Add, {},
432 II->getName() + ".add", nullptr, Rounding);
433 II->replaceAllUsesWith(Result);
434 EraseFromParent.push_back(II);
435}
436
437// Substitutes calls to LLVM intrinsics with either calls to SPIR-V intrinsics
438// or calls to proper generated functions. Returns True if F was modified.
439bool SPIRVPrepareFunctionsImpl::substituteIntrinsicCalls(Function *F) {
440 bool Changed = false;
441 const SPIRVSubtarget &STI = TM.getSubtarget<SPIRVSubtarget>(*F);
442 SmallVector<Instruction *> EraseFromParent;
443 const TargetTransformInfo &TTI = TM.getTargetTransformInfo(*F);
444 for (BasicBlock &BB : *F) {
445 for (Instruction &I : make_early_inc_range(BB)) {
446 auto Call = dyn_cast<CallInst>(&I);
447 if (!Call)
448 continue;
450 if (!CF || !CF->isIntrinsic())
451 continue;
452 auto *II = cast<IntrinsicInst>(Call);
453 if (Intrinsic::isTargetIntrinsic(II->getIntrinsicID()) &&
454 II->getCalledOperand()->getName().starts_with("llvm.spv"))
455 continue;
456 switch (II->getIntrinsicID()) {
457 case Intrinsic::memset:
458 case Intrinsic::bswap:
460 break;
461 case Intrinsic::fshl:
462 case Intrinsic::fshr:
464 Changed = true;
465 break;
466 case Intrinsic::assume:
467 case Intrinsic::expect:
468 if (STI.canUseExtension(SPIRV::Extension::SPV_KHR_expect_assume))
470 Changed = true;
471 break;
472 case Intrinsic::lifetime_start:
473 if (!STI.isShader()) {
475 II, Intrinsic::SPVIntrinsics::spv_lifetime_start);
476 } else {
477 II->eraseFromParent();
478 Changed = true;
479 }
480 break;
481 case Intrinsic::lifetime_end:
482 if (!STI.isShader()) {
484 II, Intrinsic::SPVIntrinsics::spv_lifetime_end);
485 } else {
486 II->eraseFromParent();
487 Changed = true;
488 }
489 break;
490 case Intrinsic::ptr_annotation:
492 Changed = true;
493 break;
494 case Intrinsic::experimental_constrained_fmuladd:
495 lowerConstrainedFmuladd(II, EraseFromParent);
496 Changed = true;
497 break;
498 case Intrinsic::experimental_constrained_fcmp:
499 case Intrinsic::experimental_constrained_fcmps:
501 EraseFromParent);
502 Changed = true;
503 break;
504 default:
505 if (TM.getTargetTriple().getVendor() == Triple::AMD ||
506 any_of(SPVAllowUnknownIntrinsics, [II](auto &&Prefix) {
507 if (Prefix.empty())
508 return false;
509 return II->getCalledFunction()->getName().starts_with(Prefix);
510 }))
512 break;
513 }
514 }
515 }
516 for (auto *I : EraseFromParent)
517 I->eraseFromParent();
518 return Changed;
519}
520
521static void
523 SmallVector<std::pair<int, Type *>> ChangedTys,
524 StringRef Name, StringRef AsmConstraints = "") {
525
526 LLVMContext &Ctx = NMD->getParent()->getContext();
527 Type *I32Ty = IntegerType::getInt32Ty(Ctx);
528
530 MDArgs.push_back(MDString::get(Ctx, Name));
531 transform(ChangedTys, std::back_inserter(MDArgs), [=, &Ctx](auto &&CTy) {
532 return MDNode::get(
533 Ctx, {ConstantAsMetadata::get(ConstantInt::get(I32Ty, CTy.first, true)),
535 });
536 if (!AsmConstraints.empty())
537 MDArgs.push_back(MDNode::get(Ctx, MDString::get(Ctx, AsmConstraints)));
538 NMD->addOperand(MDNode::get(Ctx, MDArgs));
539}
540
541// Returns F if aggregate argument/return types are not present or cloned F
542// function with the types replaced by i32 types. The change in types is
543// noted in 'spv.cloned_funcs' metadata for later restoration.
544Function *
545SPIRVPrepareFunctionsImpl::removeAggregateTypesFromSignature(Function *F) {
546 bool IsRetAggr = F->getReturnType()->isAggregateType();
547 // Allow intrinsics with aggregate return/argument types to reach GlobalISel.
548 // Renaming/mutating the signature of an intrinsic would desync its name from
549 // its argument types and break the IR verifier.
550 if (F->isIntrinsic())
551 return F;
552
553 IRBuilder<> B(F->getContext());
554
555 bool HasAggrArg = llvm::any_of(F->args(), [](Argument &Arg) {
556 return Arg.getType()->isAggregateType();
557 });
558 bool DoClone = IsRetAggr || HasAggrArg;
559 if (!DoClone)
560 return F;
561 SmallVector<std::pair<int, Type *>, 4> ChangedTypes;
562 Type *RetType = IsRetAggr ? B.getInt32Ty() : F->getReturnType();
563 if (IsRetAggr)
564 ChangedTypes.push_back(std::pair<int, Type *>(-1, F->getReturnType()));
565 SmallVector<Type *, 4> ArgTypes;
566 for (const auto &Arg : F->args()) {
567 if (Arg.getType()->isAggregateType()) {
568 ArgTypes.push_back(B.getInt32Ty());
569 ChangedTypes.push_back(
570 std::pair<int, Type *>(Arg.getArgNo(), Arg.getType()));
571 } else
572 ArgTypes.push_back(Arg.getType());
573 }
574 FunctionType *NewFTy =
575 FunctionType::get(RetType, ArgTypes, F->getFunctionType()->isVarArg());
576 Function *NewF =
577 Function::Create(NewFTy, F->getLinkage(), F->getAddressSpace(),
578 F->getName(), F->getParent());
579
581 auto NewFArgIt = NewF->arg_begin();
582 for (auto &Arg : F->args()) {
583 StringRef ArgName = Arg.getName();
584 NewFArgIt->setName(ArgName);
585 VMap[&Arg] = &(*NewFArgIt++);
586 }
588
589 CloneFunctionInto(NewF, F, VMap, CloneFunctionChangeType::LocalChangesOnly,
590 Returns);
591 NewF->takeName(F);
592
594 NewF->getParent()->getOrInsertNamedMetadata("spv.cloned_funcs"),
595 std::move(ChangedTypes), NewF->getName());
596
597 for (auto *U : make_early_inc_range(F->users())) {
598 if (CallInst *CI;
599 (CI = dyn_cast<CallInst>(U)) && CI->getCalledFunction() == F)
600 CI->mutateFunctionType(NewF->getFunctionType());
601 if (auto *C = dyn_cast<Constant>(U))
602 C->handleOperandChange(F, NewF);
603 else
604 U->replaceUsesOfWith(F, NewF);
605 }
606
607 // register the mutation
608 if (RetType != F->getReturnType())
609 TM.getSubtarget<SPIRVSubtarget>(*F).getSPIRVGlobalRegistry()->addMutated(
610 NewF, F->getReturnType());
611 return NewF;
612}
613
614// Returns true iff `F`'s name resolves (after OpenCL/SPIR-V demangling and
615// builtin-name lookup) to the SPIR-V friendly built-in `__spirv_AbortKHR`.
616static bool isAbortKHRBuiltin(const Function &F) {
617 if (F.isIntrinsic())
618 return false;
619 StringRef Name = F.getName();
620 // Quick reject: the mangled or unmangled name must contain the substring.
621 if (!Name.contains("__spirv_AbortKHR"))
622 return false;
623 std::string Demangled = getOclOrSpirvBuiltinDemangledName(Name);
624 if (Demangled.empty())
625 return false;
626 return SPIRV::lookupBuiltinNameHelper(Demangled) == "__spirv_AbortKHR";
627}
628
629// Rewrites a single call to `__spirv_AbortKHR` into a call to the
630// `llvm.spv.abort` target intrinsic, then re-terminates the block with
631// `unreachable`. OpAbortKHR is itself a SPIR-V function-termination
632// instruction and must be the last instruction in its block, so any trailing
633// stores/lifetime intrinsics/`ret` emitted by the OpenCL ABI are dropped.
634// `changeToUnreachable` cleans up any successor PHI predecessor entries.
636 IRBuilder<> B(CI);
637 Value *Msg = CI->getArgOperand(0);
638 // The OpenCL C ABI may pass aggregate arguments by pointer (byval). In that
639 // case load the underlying value so that OpAbortKHR receives the composite
640 // itself, as required by the SPV_KHR_abort spec ("Message Type must be a
641 // concrete type").
642 if (CI->isByValArgument(0)) {
643 Type *AggTy = CI->getParamByValType(0);
644 Msg = B.CreateLoad(AggTy, Msg);
645 }
646 B.CreateIntrinsic(Intrinsic::spv_abort, {Msg->getType()}, {Msg});
648}
649
650// Replace OpenCL/SPIR-V style calls to `__spirv_AbortKHR(message)` (i.e.
651// calls to `F` when `F` is the `__spirv_AbortKHR` built-in) with calls to the
652// `llvm.spv.abort` target intrinsic.
653bool SPIRVPrepareFunctionsImpl::substituteAbortKHRCalls(Function *F) {
654 if (!isAbortKHRBuiltin(*F))
655 return false;
656
658 for (User *U : F->users()) {
659 auto *CI = dyn_cast<CallInst>(U);
660 if (!CI || CI->getCalledFunction() != F)
661 continue;
662 if (CI->arg_size() != 1)
663 continue;
664 Calls.push_back(CI);
665 }
666
667 for (CallInst *CI : Calls)
669
670 return !Calls.empty();
671}
672
673// When the SPV_KHR_abort extension is enabled, `llvm.trap` and
674// `llvm.ubsantrap` are lowered to `OpAbortKHR` during instruction selection.
675// `OpAbortKHR` is itself a SPIR-V block terminator, so any instructions that
676// follow the trap call within the same basic block (e.g. `ret`, lifetime
677// markers) would produce SPIR-V ops after `OpAbortKHR` and break validation.
678// Terminate the block right after each call to the trap intrinsics by replacing
679// the next instruction with `unreachable`.
680bool SPIRVPrepareFunctionsImpl::terminateBlocksAfterTrap(Module &M,
681 Intrinsic::ID IID) {
682 assert((IID == Intrinsic::trap || IID == Intrinsic::ubsantrap) &&
683 "Expected trap intrinsic ID");
684
686 if (!F)
687 return false;
688
689 // If the target doesn't support SPV_KHR_abort, we won't be able to lower
690 // the trap intrinsic to OpAbortKHR, so we can skip the block-terminating
691 // transformation.
692 const auto &ST = TM.getSubtarget<SPIRVSubtarget>(*F);
693 if (!ST.canUseExtension(SPIRV::Extension::SPV_KHR_abort))
694 return false;
695
697 for (User *U : F->users()) {
698 auto *CI = dyn_cast<CallInst>(U);
699 if (!CI || CI->getCalledFunction() != F)
700 continue;
701 Calls.push_back(CI);
702 }
703
704 bool Changed = false;
705 for (CallInst *CI : Calls) {
706 Instruction *Next = CI->getNextNode();
708 continue;
710 Changed = true;
711 }
712 return Changed;
713}
714
715static std::string fixMultiOutputConstraintString(StringRef Constraints) {
716 // We should only have one =r return for the made up ASM type.
718 SplitString(Constraints, Tmp, ",");
719 std::string SafeConstraints("=r,");
720 for (unsigned I = 0u; I != Tmp.size() - 1; ++I) {
721 if (Tmp[I].starts_with('=') && (Tmp[I][1] == '&' || isalnum(Tmp[I][1])))
722 continue;
723 SafeConstraints.append(Tmp[I]).append({','});
724 }
725 SafeConstraints.append(Tmp.back());
726
727 return SafeConstraints;
728}
729
730// Mutates indirect and inline ASM callsites iff aggregate argument/return types
731// are present with the types replaced by i32 types. The change in types is
732// noted in 'spv.mutated_callsites' metadata for later restoration. For ASM we
733// also have to mutate the constraint string as IRTranslator tries to handle
734// multiple outputs and expects an aggregate return type in their presence.
735bool SPIRVPrepareFunctionsImpl::removeAggregateTypesFromCalls(Function *F) {
736 if (F->isDeclaration() || F->isIntrinsic())
737 return false;
738
740 for (auto &&I : instructions(F)) {
741 if (auto *CB = dyn_cast<CallBase>(&I)) {
742 if (!CB->getCalledOperand() || CB->getCalledFunction())
743 continue;
744 if (CB->getType()->isAggregateType() ||
745 any_of(CB->args(),
746 [](auto &&Arg) { return Arg->getType()->isAggregateType(); }))
747 Calls.emplace_back(CB, nullptr);
748 }
749 }
750
751 if (Calls.empty())
752 return false;
753
754 IRBuilder<> B(F->getContext());
755
756 for (auto &&[CB, NewFnTy] : Calls) {
758 SmallVector<Type *> NewArgTypes;
759
760 Type *RetTy = CB->getType();
761 if (RetTy->isAggregateType()) {
762 ChangedTypes.emplace_back(-1, RetTy);
763 RetTy = B.getInt32Ty();
764 }
765
766 for (auto &&Arg : CB->args()) {
767 if (Arg->getType()->isAggregateType()) {
768 NewArgTypes.push_back(B.getInt32Ty());
769 ChangedTypes.emplace_back(Arg.getOperandNo(), Arg->getType());
770 } else {
771 NewArgTypes.push_back(Arg->getType());
772 }
773 }
774 NewFnTy = FunctionType::get(RetTy, NewArgTypes,
775 CB->getFunctionType()->isVarArg());
776
777 if (!CB->hasName())
778 CB->setName("spv.mutated_callsite." + F->getName());
779 else
780 CB->setName("spv.named_mutated_callsite." + F->getName() + "." +
781 CB->getName());
782
783 std::string Constraints;
784 if (auto *ASM = dyn_cast<InlineAsm>(CB->getCalledOperand())) {
785 Constraints = ASM->getConstraintString();
786
787 CB->setCalledOperand(InlineAsm::get(
788 NewFnTy, ASM->getAsmString(),
789 fixMultiOutputConstraintString(Constraints), ASM->hasSideEffects(),
790 ASM->isAlignStack(), ASM->getDialect(), ASM->canThrow()));
791 }
792
794 F->getParent()->getOrInsertNamedMetadata("spv.mutated_callsites"),
795 std::move(ChangedTypes), CB->getName(), Constraints);
796 }
797
798 for (auto &&[CB, NewFTy] : Calls) {
799 if (NewFTy->getReturnType() != CB->getType())
800 TM.getSubtarget<SPIRVSubtarget>(*F).getSPIRVGlobalRegistry()->addMutated(
801 CB, CB->getType());
802 CB->mutateFunctionType(NewFTy);
803 }
804
805 return true;
806}
807
808bool SPIRVPrepareFunctionsImpl::runOnModule(Module &M) {
809 // Resolve the SPIR-V environment from module content before any
810 // function-level processing. This must happen before legalization so that
811 // isShader()/isKernel() return correct values.
812 const_cast<SPIRVTargetMachine &>(TM)
813 .getMutableSubtargetImpl()
814 ->resolveEnvFromModule(M);
815
816 bool Changed = false;
817 if (M.functions().empty()) {
818 // If there are no functions, insert a service
819 // function so that the global/constant tracking intrinsics
820 // will be created. Without these intrinsics the generated SPIR-V
821 // will be empty. The service function itself is not emitted.
823 BasicBlock *BB = BasicBlock::Create(M.getContext(), "entry", SF);
824 IRBuilder<> IRB(BB);
825 IRB.CreateRetVoid();
826 Changed = true;
827 }
828
829 Changed |= terminateBlocksAfterTrap(M, Intrinsic::trap);
830 Changed |= terminateBlocksAfterTrap(M, Intrinsic::ubsantrap);
831
832 for (Function &F : M) {
833 Changed |= substituteAbortKHRCalls(&F);
834 Changed |= substituteIntrinsicCalls(&F);
835 Changed |= sortBlocks(F);
836 Changed |= removeAggregateTypesFromCalls(&F);
837 }
838
839 std::vector<Function *> FuncsWorklist;
840 for (auto &F : M)
841 FuncsWorklist.push_back(&F);
842
843 for (auto *F : FuncsWorklist) {
844 Function *NewF = removeAggregateTypesFromSignature(F);
845
846 if (NewF != F) {
847 F->eraseFromParent();
848 Changed = true;
849 }
850 }
851 return Changed;
852}
853
856 return SPIRVPrepareFunctionsImpl(TM).runOnModule(M)
859}
860
863 return new SPIRVPrepareFunctionsLegacy(TM);
864}
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
Expand Atomic instructions
static GCRegistry::Add< ErlangGC > A("erlang", "erlang-compatible garbage collector")
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")
#define F(x, y, z)
Definition MD5.cpp:54
#define I(x, y, z)
Definition MD5.cpp:57
Machine Check Debug Module
uint64_t IntrinsicInst * II
#define INITIALIZE_PASS(passName, arg, name, cfg, analysis)
Definition PassSupport.h:56
static void lowerFunnelShifts(IntrinsicInst *FSHIntrinsic)
static std::string getAnnotation(Value *AnnoVal, Value *OptAnnoVal)
static void lowerConstrainedFPCmpIntrinsic(ConstrainedFPCmpIntrinsic *ConstrainedCmpIntrinsic, SmallVector< Instruction * > &EraseFromParent)
static void lowerConstrainedFmuladd(IntrinsicInst *II, SmallVector< Instruction * > &EraseFromParent)
static void lowerPtrAnnotation(IntrinsicInst *II)
static bool lowerIntrinsicToFunction(IntrinsicInst *Intrinsic, const TargetTransformInfo &TTI)
static bool isAbortKHRBuiltin(const Function &F)
static SmallVector< Metadata * > parseAnnotation(Value *I, const std::string &Anno, LLVMContext &Ctx, Type *Int32Ty)
static std::string fixMultiOutputConstraintString(StringRef Constraints)
static void rewriteAbortKHRCall(CallInst *CI)
static void addFunctionTypeMutation(NamedMDNode *NMD, SmallVector< std::pair< int, Type * > > ChangedTys, StringRef Name, StringRef AsmConstraints="")
static bool toSpvLifetimeIntrinsic(IntrinsicInst *II, Intrinsic::ID NewID)
static void lowerExpectAssume(IntrinsicInst *II)
static Function * getOrCreateFunction(Module *M, Type *RetTy, ArrayRef< Type * > ArgTypes, StringRef Name)
This file contains some functions that are useful when dealing with strings.
DEMANGLE_NAMESPACE_BEGIN bool starts_with(std::string_view self, char C) noexcept
This pass exposes codegen information to IR-level passes.
Value * RHS
Value * LHS
BinaryOperator * Mul
This class represents an incoming formal argument to a Function.
Definition Argument.h:32
Represent a constant reference to an array (0 or more elements consecutively in memory),...
Definition ArrayRef.h:40
LLVM Basic Block Representation.
Definition BasicBlock.h:62
static BasicBlock * Create(LLVMContext &Context, const Twine &Name="", Function *Parent=nullptr, BasicBlock *InsertBefore=nullptr)
Creates a new BasicBlock.
Definition BasicBlock.h:206
Function * getCalledFunction() const
Returns the function called, or null if this is an indirect function invocation or the function signa...
bool isByValArgument(unsigned ArgNo) const
Determine whether this argument is passed by value.
Type * getParamByValType(unsigned ArgNo) const
Extract the byval type for a call or parameter.
Value * getArgOperand(unsigned i) const
FunctionType * getFunctionType() const
void setCalledFunction(Function *Fn)
Sets the function called, including updating the function type.
This class represents a function call, abstracting a target machine's calling convention.
Predicate
This enumeration lists the possible predicates for CmpInst subclasses.
Definition InstrTypes.h:676
static ConstantAsMetadata * get(Constant *C)
Definition Metadata.h:537
This is the shared class of boolean and integer constants.
Definition Constants.h:87
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)
Definition Function.h:168
bool empty() const
Definition Function.h:859
FunctionType * getFunctionType() const
Returns the FunctionType for me.
Definition Function.h:211
arg_iterator arg_begin()
Definition Function.h:868
bool isIntrinsic() const
isIntrinsic - Returns true if the function's name starts with "llvm.".
Definition Function.h:251
Type * getReturnType() const
Returns the type of the ret val.
Definition Function.h:216
void setCallingConv(CallingConv::ID CC)
Definition Function.h:276
Argument * getArg(unsigned i) const
Definition Function.h:886
Module * getParent()
Get the module that this global value is contained inside of...
void setDSOLocal(bool Local)
@ ExternalLinkage
Externally visible function.
Definition GlobalValue.h:53
LLVM_ABI Value * CreateVectorSplat(unsigned NumElts, Value *V, const Twine &Name="")
Return a vector value that contains.
LLVM_ABI CallInst * CreateIntrinsic(Intrinsic::ID ID, ArrayRef< Type * > OverloadTypes, ArrayRef< Value * > Args, FMFSource FMFSource={}, const Twine &Name="", ArrayRef< OperandBundleDef > OpBundles={})
Create a call to intrinsic ID with Args, mangled using OverloadTypes.
Value * CreateLShr(Value *LHS, Value *RHS, const Twine &Name="", bool isExact=false)
Definition IRBuilder.h:1554
ReturnInst * CreateRet(Value *V)
Create a 'ret <val>' instruction.
Definition IRBuilder.h:1214
Value * CreateSub(Value *LHS, Value *RHS, const Twine &Name="", bool HasNUW=false, bool HasNSW=false)
Definition IRBuilder.h:1461
Value * CreateShl(Value *LHS, Value *RHS, const Twine &Name="", bool HasNUW=false, bool HasNSW=false)
Definition IRBuilder.h:1533
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.
Definition IRBuilder.h:660
ReturnInst * CreateRetVoid()
Create a 'ret void' instruction.
Definition IRBuilder.h:1209
void SetInsertPoint(BasicBlock *TheBB)
This specifies that created instructions should be appended to the end of the specified block.
Definition IRBuilder.h:207
Value * CreateOr(Value *LHS, Value *RHS, const Twine &Name="", bool IsDisjoint=false)
Definition IRBuilder.h:1614
ConstantInt * getInt(const APInt &AI)
Get a constant integer value.
Definition IRBuilder.h:544
Value * CreateURem(Value *LHS, Value *RHS, const Twine &Name="")
Definition IRBuilder.h:1521
This provides a uniform API for creating instructions and inserting them into a basic block: either a...
Definition IRBuilder.h:2858
static LLVM_ABI InlineAsm * get(FunctionType *Ty, StringRef AsmString, StringRef Constraints, bool hasSideEffects, bool isAlignStack=false, AsmDialect asmDialect=AD_ATT, bool canThrow=false)
InlineAsm::get - Return the specified uniqued inline asm string.
Definition InlineAsm.cpp:43
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.
Definition LLVMContext.h:68
static MDTuple * get(LLVMContext &Context, ArrayRef< Metadata * > MDs)
Definition Metadata.h:1572
static LLVM_ABI MDString * get(LLVMContext &Context, StringRef Str)
Definition Metadata.cpp:614
This class wraps the llvm.memset and llvm.memset.inline intrinsics.
static LLVM_ABI MetadataAsValue * get(LLVMContext &Context, Metadata *MD)
Definition Metadata.cpp:110
ModulePass class - This class is used to implement unstructured interprocedural optimizations and ana...
Definition Pass.h:255
A Module instance is used to store all the information related to an LLVM module.
Definition Module.h:67
LLVMContext & getContext() const
Get the global data context.
Definition Module.h:287
NamedMDNode * getOrInsertNamedMetadata(StringRef Name)
Return the named MDNode in the module with the specified name.
Definition Module.cpp:308
A tuple of MDNodes.
Definition Metadata.h:1760
Module * getParent()
Get the module that holds this named metadata collection.
Definition Metadata.h:1830
LLVM_ABI void addOperand(MDNode *M)
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
PreservedAnalyses run(Module &M, ModuleAnalysisManager &AM)
bool canUseExtension(SPIRV::Extension::Extension E) const
TargetTransformInfo getTargetTransformInfo(const Function &F) const override
Get a TargetTransformInfo implementation for the target.
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.
Represent a constant reference to a string, i.e.
Definition StringRef.h:56
std::string str() const
Get the contents as an std::string.
Definition StringRef.h:222
const Triple & getTargetTriple() const
const STC & getSubtarget(const Function &F) const
This method returns a pointer to the specified type of TargetSubtargetInfo.
This pass provides access to the codegen interfaces that are needed for IR-level transformations.
VendorType getVendor() const
Get the parsed vendor type of this triple.
Definition Triple.h:442
The instances of the Type class are immutable: once they are created, they are never changed.
Definition Type.h:46
static LLVM_ABI IntegerType * getInt32Ty(LLVMContext &C)
Definition Type.cpp:313
bool isAggregateType() const
Return true if the type is an aggregate type.
Definition Type.h:321
static LLVM_ABI ValueAsMetadata * get(Value *V)
Definition Metadata.cpp:509
LLVM Value Representation.
Definition Value.h:75
Type * getType() const
All values are typed, get the type of this value.
Definition Value.h:255
LLVM_ABI void setName(const Twine &Name)
Change the name of the value.
Definition Value.cpp:393
LLVM_ABI void replaceAllUsesWith(Value *V)
Change all uses of this to point to a new Value.
Definition Value.cpp:549
LLVM_ABI StringRef getName() const
Return a constant reference to the value's name.
Definition Value.cpp:318
LLVM_ABI void takeName(Value *V)
Transfer the name from V to this value.
Definition Value.cpp:399
Type * getElementType() const
CallInst * Call
Changed
#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.
Definition CallingConv.h:34
@ BasicBlock
Various leaf nodes.
Definition ISDOpcodes.h:81
This namespace contains an enum with a value for every intrinsic/builtin function known by LLVM.
LLVM_ABI Function * getDeclarationIfExists(const Module *M, ID id)
Look up the Function declaration of the intrinsic id in the Module M and return it if it exists.
LLVM_ABI Function * getOrInsertDeclaration(Module *M, ID id, ArrayRef< Type * > OverloadTys={})
Look up the Function declaration of the intrinsic id in the Module M.
LLVM_ABI bool isTargetIntrinsic(ID IID)
isTargetIntrinsic - Returns true if IID is an intrinsic specific to a certain target.
std::string lookupBuiltinNameHelper(StringRef DemangledCall, FPDecorationId *DecorationId)
Parses the name part of the demangled builtin call.
friend class Instruction
Iterator for Instructions in a `BasicBlock.
Definition BasicBlock.h:73
This is an optimization pass for GlobalISel generic memory operations.
decltype(auto) dyn_cast(const From &Val)
dyn_cast<X> - Return the argument parameter cast to the specified type.
Definition Casting.h:643
FunctionAddr VTableAddr uintptr_t uintptr_t Int32Ty
Definition InstrProf.h:328
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...
Definition STLExtras.h:633
bool sortBlocks(Function &F)
LLVM_ABI void SplitString(StringRef Source, SmallVectorImpl< StringRef > &OutFragments, StringRef Delimiters=" \t\n\v\f\r")
SplitString - Split up the specified string according to the specified delimiters,...
Function * getOrCreateBackendServiceFunction(Module &M)
std::string getOclOrSpirvBuiltinDemangledName(StringRef Name)
auto dyn_cast_or_null(const Y &Val)
Definition Casting.h:753
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:2025
bool any_of(R &&range, UnaryPredicate P)
Provide wrappers to std::any_of which take ranges instead of having to pass begin/end explicitly.
Definition STLExtras.h:1745
class LLVM_GSL_OWNER SmallVector
Forward declaration of SmallVector so that calculateSmallVectorDefaultInlinedElements can reference s...
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...
Definition Casting.h:547
LLVM_ABI unsigned changeToUnreachable(Instruction *I, bool PreserveLCSSA=false, DomTreeUpdater *DTU=nullptr, MemorySSAUpdater *MSSAU=nullptr)
Insert an unreachable instruction before the specified instruction, making it and the rest of the cod...
Definition Local.cpp:2528
@ Ref
The access may reference the value stored in memory.
Definition ModRef.h:32
TargetTransformInfo TTI
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.
Definition STLExtras.h:1909
@ Add
Sum of integers.
FunctionAddr VTableAddr Next
Definition InstrProf.h:141
constexpr unsigned BitWidth
ValueMap< const Value *, WeakTrackingVH > ValueToValueMapTy
LLVM_ABI void expandMemSetAsLoop(MemSetInst *MemSet, const TargetTransformInfo *TTI=nullptr)
Expand MemSet as a loop.
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<X> - Return the argument parameter cast to the specified type.
Definition Casting.h:559
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)
AnalysisManager< Module > ModuleAnalysisManager
Convenience typedef for the Module analysis manager.
Definition MIRParser.h:39
Implement std::hash so that hash_code can be used in STL containers.
Definition BitVector.h:874