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"
32#include "llvm/IR/IRBuilder.h"
36#include "llvm/IR/Intrinsics.h"
37#include "llvm/IR/IntrinsicsSPIRV.h"
41#include <regex>
42
43using namespace llvm;
44
45namespace {
46
47class SPIRVPrepareFunctionsImpl {
48 const SPIRVTargetMachine &TM;
49 bool substituteIntrinsicCalls(Function *F);
50 bool substituteAbortKHRCalls(Function *F);
51 bool terminateBlocksAfterTrap(Module &M, Intrinsic::ID IID);
52 Function *removeAggregateTypesFromSignature(Function *F);
53 bool removeAggregateTypesFromCalls(Function *F);
54
55public:
56 SPIRVPrepareFunctionsImpl(const SPIRVTargetMachine &TM) : TM(TM) {}
57 bool runOnModule(Module &M);
58};
59
60class SPIRVPrepareFunctionsLegacy : public ModulePass {
61 const SPIRVTargetMachine &TM;
62
63public:
64 static char ID;
65 SPIRVPrepareFunctionsLegacy(const SPIRVTargetMachine &TM)
66 : ModulePass(ID), TM(TM) {}
67
68 bool runOnModule(Module &M) override {
69 return SPIRVPrepareFunctionsImpl(TM).runOnModule(M);
70 }
71
72 StringRef getPassName() const override { return "SPIRV prepare functions"; }
73};
74
75static cl::list<std::string> SPVAllowUnknownIntrinsics(
76 "spv-allow-unknown-intrinsics", cl::CommaSeparated,
77 cl::desc("Emit unknown intrinsics as calls to external functions. A "
78 "comma-separated input list of intrinsic prefixes must be "
79 "provided, and only intrinsics carrying a listed prefix get "
80 "emitted as described."),
81 cl::value_desc("intrinsic_prefix_0,intrinsic_prefix_1"), cl::ValueOptional);
82} // namespace
83
84char SPIRVPrepareFunctionsLegacy::ID = 0;
85
86INITIALIZE_PASS(SPIRVPrepareFunctionsLegacy, "spirv-prepare-functions",
87 "SPIRV prepare functions", false, false)
88
89static std::string lowerLLVMIntrinsicName(IntrinsicInst *II) {
90 Function *IntrinsicFunc = II->getCalledFunction();
91 assert(IntrinsicFunc && "Missing function");
92 std::string FuncName = IntrinsicFunc->getName().str();
93 llvm::replace(FuncName, '.', '_');
94 FuncName = "spirv." + FuncName;
95 return FuncName;
96}
97
99 ArrayRef<Type *> ArgTypes,
100 StringRef Name) {
101 FunctionType *FT = FunctionType::get(RetTy, ArgTypes, false);
102 Function *F = M->getFunction(Name);
103 if (F && F->getFunctionType() == FT)
104 return F;
106 if (F)
107 NewF->setDSOLocal(F->isDSOLocal());
109 return NewF;
110}
111
113 const TargetTransformInfo &TTI) {
114 // For @llvm.memset.* intrinsic cases with constant value and length arguments
115 // are emulated via "storing" a constant array to the destination. For other
116 // cases we wrap the intrinsic in @spirv.llvm_memset_* function and expand the
117 // intrinsic to a loop via expandMemSetAsLoop().
118 if (auto *MSI = dyn_cast<MemSetInst>(Intrinsic))
119 if (isa<Constant>(MSI->getValue()) && isa<ConstantInt>(MSI->getLength()))
120 return false; // It is handled later using OpCopyMemorySized.
121
122 // An intrinsic with a metadata argument has no SPIR-V lowering and can't be
123 // turned into a function.
125 const Function *F = Intrinsic->getFunction();
126 F->getContext().diagnose(DiagnosticInfoUnsupported(
127 *F,
128 "cannot lower the intrinsic '" +
129 Intrinsic->getCalledFunction()->getName() +
130 "' that takes a metadata argument",
131 Intrinsic->getDebugLoc()));
132 if (!Intrinsic->getType()->isVoidTy())
133 Intrinsic->replaceAllUsesWith(PoisonValue::get(Intrinsic->getType()));
134 Intrinsic->eraseFromParent();
135 return true;
136 }
137
138 Module *M = Intrinsic->getModule();
139 std::string FuncName = lowerLLVMIntrinsicName(Intrinsic);
140 if (Intrinsic->isVolatile())
141 FuncName += ".volatile";
142 // Redirect @llvm.intrinsic.* call to @spirv.llvm_intrinsic_*
143 Function *F = M->getFunction(FuncName);
144 if (F) {
145 Intrinsic->setCalledFunction(F);
146 return true;
147 }
148 FunctionCallee FC =
149 M->getOrInsertFunction(FuncName, Intrinsic->getFunctionType());
150 auto IntrinsicID = Intrinsic->getIntrinsicID();
151 Intrinsic->setCalledFunction(FC);
152 F = cast<Function>(FC.getCallee());
153 F->setAttributes(Intrinsic->getAttributes());
154
155 switch (IntrinsicID) {
156 case Intrinsic::memset: {
157 auto *MSI = static_cast<MemSetInst *>(Intrinsic);
158 Argument *Dest = F->getArg(0);
159 Argument *Val = F->getArg(1);
160 Argument *Len = F->getArg(2);
161 Argument *IsVolatile = F->getArg(3);
162 Dest->setName("dest");
163 Val->setName("val");
164 Len->setName("len");
165 IsVolatile->setName("isvolatile");
166 BasicBlock *EntryBB = BasicBlock::Create(M->getContext(), "entry", F);
167 IRBuilder<> IRB(EntryBB);
168 auto *MemSet = IRB.CreateMemSet(Dest, Val, Len, MSI->getDestAlign(),
169 MSI->isVolatile());
170 IRB.CreateRetVoid();
172 MemSet->eraseFromParent();
173 break;
174 }
175 case Intrinsic::bswap: {
176 BasicBlock *EntryBB = BasicBlock::Create(M->getContext(), "entry", F);
177 IRBuilder<> IRB(EntryBB);
179 Intrinsic::bswap, Intrinsic->getType(), F->getArg(0));
180 IRB.CreateRet(BSwap);
181 IntrinsicLowering IL(M->getDataLayout());
182 IL.LowerIntrinsicCall(BSwap);
183 break;
184 }
185 default:
186 break;
187 }
188 return true;
189}
190
191static std::string getAnnotation(Value *AnnoVal, Value *OptAnnoVal) {
192 if (auto *Ref = dyn_cast_or_null<GetElementPtrInst>(AnnoVal))
193 AnnoVal = Ref->getOperand(0);
194 if (auto *Ref = dyn_cast_or_null<BitCastInst>(OptAnnoVal))
195 OptAnnoVal = Ref->getOperand(0);
196
197 std::string Anno;
198 if (auto *C = dyn_cast_or_null<Constant>(AnnoVal)) {
199 StringRef Str;
200 if (getConstantStringInfo(C, Str))
201 Anno = Str;
202 }
203 // handle optional annotation parameter in a way that Khronos Translator do
204 // (collect integers wrapped in a struct)
205 if (auto *C = dyn_cast_or_null<Constant>(OptAnnoVal);
206 C && C->getNumOperands()) {
207 Value *MaybeStruct = C->getOperand(0);
208 if (auto *Struct = dyn_cast<ConstantStruct>(MaybeStruct)) {
209 for (unsigned I = 0, E = Struct->getNumOperands(); I != E; ++I) {
210 if (auto *CInt = dyn_cast<ConstantInt>(Struct->getOperand(I)))
211 Anno += (I == 0 ? ": " : ", ") +
212 std::to_string(CInt->getType()->getIntegerBitWidth() == 1
213 ? CInt->getZExtValue()
214 : CInt->getSExtValue());
215 }
216 } else if (auto *Struct = dyn_cast<ConstantAggregateZero>(MaybeStruct)) {
217 // { i32 i32 ... } zeroinitializer
218 for (unsigned I = 0, E = Struct->getType()->getStructNumElements();
219 I != E; ++I)
220 Anno += I == 0 ? ": 0" : ", 0";
221 }
222 }
223 return Anno;
224}
225
227 const std::string &Anno,
228 LLVMContext &Ctx,
229 Type *Int32Ty) {
230 // Try to parse the annotation string according to the following rules:
231 // annotation := ({kind} | {kind:value,value,...})+
232 // kind := number
233 // value := number | string
234 static const std::regex R(
235 "\\{(\\d+)(?:[:,](\\d+|\"[^\"]*\")(?:,(\\d+|\"[^\"]*\"))*)?\\}");
237 int Pos = 0;
238 for (std::sregex_iterator
239 It = std::sregex_iterator(Anno.begin(), Anno.end(), R),
240 ItEnd = std::sregex_iterator();
241 It != ItEnd; ++It) {
242 if (It->position() != Pos)
244 Pos = It->position() + It->length();
245 std::smatch Match = *It;
247 for (std::size_t i = 1; i < Match.size(); ++i) {
248 std::ssub_match SMatch = Match[i];
249 std::string Item = SMatch.str();
250 if (Item.length() == 0)
251 break;
252 if (Item[0] == '"') {
253 Item = Item.substr(1, Item.length() - 2);
254 // Acceptable format of the string snippet is:
255 static const std::regex RStr("^(\\d+)(?:,(\\d+))*$");
256 if (std::smatch MatchStr; std::regex_match(Item, MatchStr, RStr)) {
257 for (std::size_t SubIdx = 1; SubIdx < MatchStr.size(); ++SubIdx)
258 if (std::string SubStr = MatchStr[SubIdx].str(); SubStr.length())
260 ConstantInt::get(Int32Ty, std::stoi(SubStr))));
261 } else {
262 MDsItem.push_back(MDString::get(Ctx, Item));
263 }
264 } else if (int32_t Num; llvm::to_integer(StringRef(Item), Num, 10)) {
265 MDsItem.push_back(
266 ConstantAsMetadata::get(ConstantInt::get(Int32Ty, Num)));
267 } else {
268 MDsItem.push_back(MDString::get(Ctx, Item));
269 }
270 }
271 if (MDsItem.size() == 0)
273 MDs.push_back(MDNode::get(Ctx, MDsItem));
274 }
275 return Pos == static_cast<int>(Anno.length()) ? std::move(MDs)
277}
278
280 LLVMContext &Ctx = II->getContext();
281 Type *Int32Ty = Type::getInt32Ty(Ctx);
282
283 // Retrieve an annotation string from arguments.
284 Value *PtrArg = nullptr;
285 if (auto *BI = dyn_cast<BitCastInst>(II->getArgOperand(0)))
286 PtrArg = BI->getOperand(0);
287 else
288 PtrArg = II->getOperand(0);
289 std::string Anno =
290 getAnnotation(II->getArgOperand(1),
291 4 < II->arg_size() ? II->getArgOperand(4) : nullptr);
292
293 // Parse the annotation.
294 SmallVector<Metadata *> MDs = parseAnnotation(II, Anno, Ctx, Int32Ty);
295
296 // If the annotation string is not parsed successfully we don't know the
297 // format used and output it as a general UserSemantic decoration.
298 // Otherwise MDs is a Metadata tuple (a decoration list) in the format
299 // expected by `spirv.Decorations`.
300 if (MDs.size() == 0) {
301 auto UserSemantic = ConstantAsMetadata::get(ConstantInt::get(
302 Int32Ty, static_cast<uint32_t>(SPIRV::Decoration::UserSemantic)));
303 MDs.push_back(MDNode::get(Ctx, {UserSemantic, MDString::get(Ctx, Anno)}));
304 }
305
306 // Build the internal intrinsic function.
307 IRBuilder<> IRB(II->getParent());
308 IRB.SetInsertPoint(II);
309 IRB.CreateIntrinsic(
310 Intrinsic::spv_assign_decoration, {PtrArg->getType()},
311 {PtrArg, MetadataAsValue::get(Ctx, MDNode::get(Ctx, MDs))});
312 II->replaceAllUsesWith(II->getOperand(0));
313}
314
315static void lowerFunnelShifts(IntrinsicInst *FSHIntrinsic) {
316 // Get a separate function - otherwise, we'd have to rework the CFG of the
317 // current one. Then simply replace the intrinsic uses with a call to the new
318 // function.
319 // Generate LLVM IR for i* @spirv.llvm_fsh?_i* (i* %a, i* %b, i* %c)
320 Module *M = FSHIntrinsic->getModule();
321 FunctionType *FSHFuncTy = FSHIntrinsic->getFunctionType();
322 Type *FSHRetTy = FSHFuncTy->getReturnType();
323 const std::string FuncName = lowerLLVMIntrinsicName(FSHIntrinsic);
324 Function *FSHFunc =
325 getOrCreateFunction(M, FSHRetTy, FSHFuncTy->params(), FuncName);
326
327 if (!FSHFunc->empty()) {
328 FSHIntrinsic->setCalledFunction(FSHFunc);
329 return;
330 }
331 BasicBlock *RotateBB = BasicBlock::Create(M->getContext(), "rotate", FSHFunc);
332 IRBuilder<> IRB(RotateBB);
333 Type *Ty = FSHFunc->getReturnType();
334 // Build the actual funnel shift rotate logic.
335 // In the comments, "int" is used interchangeably with "vector of int
336 // elements".
338 Type *IntTy = VectorTy ? VectorTy->getElementType() : Ty;
339 unsigned BitWidth = IntTy->getIntegerBitWidth();
340 ConstantInt *BitWidthConstant = IRB.getInt({BitWidth, BitWidth});
341 Value *BitWidthForInsts =
342 VectorTy
343 ? IRB.CreateVectorSplat(VectorTy->getNumElements(), BitWidthConstant)
344 : BitWidthConstant;
345 Value *RotateModVal =
346 IRB.CreateURem(/*Rotate*/ FSHFunc->getArg(2), BitWidthForInsts);
347 Value *FirstShift = nullptr, *SecShift = nullptr;
348 if (FSHIntrinsic->getIntrinsicID() == Intrinsic::fshr) {
349 // Shift the less significant number right, the "rotate" number of bits
350 // will be 0-filled on the left as a result of this regular shift.
351 FirstShift = IRB.CreateLShr(FSHFunc->getArg(1), RotateModVal);
352 } else {
353 // Shift the more significant number left, the "rotate" number of bits
354 // will be 0-filled on the right as a result of this regular shift.
355 FirstShift = IRB.CreateShl(FSHFunc->getArg(0), RotateModVal);
356 }
357 // We want the "rotate" number of the more significant int's LSBs (MSBs) to
358 // occupy the leftmost (rightmost) "0 space" left by the previous operation.
359 // Therefore, subtract the "rotate" number from the integer bitsize...
360 Value *SubRotateVal = IRB.CreateSub(BitWidthForInsts, RotateModVal);
361 if (FSHIntrinsic->getIntrinsicID() == Intrinsic::fshr) {
362 // ...and left-shift the more significant int by this number, zero-filling
363 // the LSBs.
364 SecShift = IRB.CreateShl(FSHFunc->getArg(0), SubRotateVal);
365 } else {
366 // ...and right-shift the less significant int by this number, zero-filling
367 // the MSBs.
368 SecShift = IRB.CreateLShr(FSHFunc->getArg(1), SubRotateVal);
369 }
370 // A simple binary addition of the shifted ints yields the final result.
371 IRB.CreateRet(IRB.CreateOr(FirstShift, SecShift));
372
373 FSHIntrinsic->setCalledFunction(FSHFunc);
374}
375
377 ConstrainedFPCmpIntrinsic *ConstrainedCmpIntrinsic,
378 SmallVector<Instruction *> &EraseFromParent) {
379 if (!ConstrainedCmpIntrinsic)
380 return;
381 // Extract the floating-point values being compared
382 Value *LHS = ConstrainedCmpIntrinsic->getArgOperand(0);
383 Value *RHS = ConstrainedCmpIntrinsic->getArgOperand(1);
384 FCmpInst::Predicate Pred = ConstrainedCmpIntrinsic->getPredicate();
385 IRBuilder<> Builder(ConstrainedCmpIntrinsic);
386 Value *FCmp = Builder.CreateFCmp(Pred, LHS, RHS);
387 ConstrainedCmpIntrinsic->replaceAllUsesWith(FCmp);
388 EraseFromParent.push_back(dyn_cast<Instruction>(ConstrainedCmpIntrinsic));
389}
390
392 // If we cannot use the SPV_KHR_expect_assume extension, then we need to
393 // ignore the intrinsic and move on. It should be removed later on by LLVM.
394 // Otherwise we should lower the intrinsic to the corresponding SPIR-V
395 // instruction.
396 // For @llvm.assume we have OpAssumeTrueKHR.
397 // For @llvm.expect we have OpExpectKHR.
398 //
399 // We need to lower this into a builtin and then the builtin into a SPIR-V
400 // instruction.
401 if (II->getIntrinsicID() == Intrinsic::assume) {
403 II->getModule(), Intrinsic::SPVIntrinsics::spv_assume);
404 II->setCalledFunction(F);
405 } else if (II->getIntrinsicID() == Intrinsic::expect) {
407 II->getModule(), Intrinsic::SPVIntrinsics::spv_expect,
408 {II->getOperand(0)->getType()});
409 II->setCalledFunction(F);
410 } else {
411 llvm_unreachable("Unknown intrinsic");
412 }
413}
414
416 auto *LifetimeArg0 = II->getArgOperand(0);
417
418 // If the lifetime argument is a poison value, the intrinsic has no effect.
419 if (isa<PoisonValue>(LifetimeArg0)) {
420 II->eraseFromParent();
421 return true;
422 }
423
424 IRBuilder<> Builder(II);
425 auto *Alloca = cast<AllocaInst>(LifetimeArg0);
426 std::optional<TypeSize> Size =
427 Alloca->getAllocationSize(Alloca->getDataLayout());
428 Value *SizeVal = Builder.getInt64(Size ? *Size : -1);
429 Builder.CreateIntrinsic(NewID, Alloca->getType(), {SizeVal, LifetimeArg0});
430 II->eraseFromParent();
431 return true;
432}
433
434static void
436 SmallVector<Instruction *> &EraseFromParent) {
437 auto *FPI = cast<ConstrainedFPIntrinsic>(II);
438 Value *A = FPI->getArgOperand(0);
439 Value *Mul = FPI->getArgOperand(1);
440 Value *Add = FPI->getArgOperand(2);
441 IRBuilder<> Builder(II->getParent());
442 Builder.SetInsertPoint(II);
443 std::optional<RoundingMode> Rounding = FPI->getRoundingMode();
444 Value *Product = Builder.CreateFMul(A, Mul, II->getName() + ".mul");
445 Value *Result = Builder.CreateConstrainedFPBinOp(
446 Intrinsic::experimental_constrained_fadd, Product, Add, {},
447 II->getName() + ".add", nullptr, Rounding);
448 II->replaceAllUsesWith(Result);
449 EraseFromParent.push_back(II);
450}
451
452// Substitutes calls to LLVM intrinsics with either calls to SPIR-V intrinsics
453// or calls to proper generated functions. Returns True if F was modified.
454bool SPIRVPrepareFunctionsImpl::substituteIntrinsicCalls(Function *F) {
455 bool Changed = false;
456 const SPIRVSubtarget &STI = TM.getSubtarget<SPIRVSubtarget>(*F);
457 SmallVector<Instruction *> EraseFromParent;
458 const TargetTransformInfo &TTI = TM.getTargetTransformInfo(*F);
459 for (BasicBlock &BB : *F) {
460 for (Instruction &I : make_early_inc_range(BB)) {
461 auto Call = dyn_cast<CallInst>(&I);
462 if (!Call)
463 continue;
465 if (!CF || !CF->isIntrinsic())
466 continue;
467 auto *II = cast<IntrinsicInst>(Call);
468 if (Intrinsic::isTargetIntrinsic(II->getIntrinsicID()) &&
469 II->getCalledOperand()->getName().starts_with("llvm.spv"))
470 continue;
471 switch (II->getIntrinsicID()) {
472 case Intrinsic::memset:
473 case Intrinsic::bswap:
475 break;
476 case Intrinsic::fshl:
477 case Intrinsic::fshr:
479 Changed = true;
480 break;
481 case Intrinsic::assume:
482 case Intrinsic::expect:
483 if (STI.canUseExtension(SPIRV::Extension::SPV_KHR_expect_assume))
485 Changed = true;
486 break;
487 case Intrinsic::lifetime_start:
488 if (!STI.isShader()) {
490 II, Intrinsic::SPVIntrinsics::spv_lifetime_start);
491 } else {
492 II->eraseFromParent();
493 Changed = true;
494 }
495 break;
496 case Intrinsic::lifetime_end:
497 if (!STI.isShader()) {
499 II, Intrinsic::SPVIntrinsics::spv_lifetime_end);
500 } else {
501 II->eraseFromParent();
502 Changed = true;
503 }
504 break;
505 case Intrinsic::ptr_annotation:
507 Changed = true;
508 break;
509 case Intrinsic::experimental_constrained_fmuladd:
510 lowerConstrainedFmuladd(II, EraseFromParent);
511 Changed = true;
512 break;
513 case Intrinsic::experimental_constrained_fcmp:
514 case Intrinsic::experimental_constrained_fcmps:
516 EraseFromParent);
517 Changed = true;
518 break;
519 default:
520 // Drop assume-like intrinsics that have no SPIR-V representation.
521 if (II->isAssumeLikeIntrinsic()) {
522 if (!II->getType()->isVoidTy())
523 II->replaceAllUsesWith(PoisonValue::get(II->getType()));
524 II->eraseFromParent();
525 Changed = true;
526 break;
527 }
528 if (TM.getTargetTriple().getVendor() == Triple::AMD ||
529 any_of(SPVAllowUnknownIntrinsics, [II](auto &&Prefix) {
530 if (Prefix.empty())
531 return false;
532 return II->getCalledFunction()->getName().starts_with(Prefix);
533 }))
535 break;
536 }
537 }
538 }
539 for (auto *I : EraseFromParent)
540 I->eraseFromParent();
541 return Changed;
542}
543
544static void
546 SmallVector<std::pair<int, Type *>> ChangedTys,
547 StringRef Name, StringRef AsmConstraints = "") {
548
549 LLVMContext &Ctx = NMD->getParent()->getContext();
550 Type *I32Ty = IntegerType::getInt32Ty(Ctx);
551
553 MDArgs.push_back(MDString::get(Ctx, Name));
554 transform(ChangedTys, std::back_inserter(MDArgs), [=, &Ctx](auto &&CTy) {
555 return MDNode::get(
556 Ctx, {ConstantAsMetadata::get(ConstantInt::get(I32Ty, CTy.first, true)),
558 });
559 if (!AsmConstraints.empty())
560 MDArgs.push_back(MDNode::get(Ctx, MDString::get(Ctx, AsmConstraints)));
561 NMD->addOperand(MDNode::get(Ctx, MDArgs));
562}
563
564// Returns F if aggregate argument/return types are not present or cloned F
565// function with the types replaced by i32 types. The change in types is
566// noted in 'spv.cloned_funcs' metadata for later restoration.
567Function *
568SPIRVPrepareFunctionsImpl::removeAggregateTypesFromSignature(Function *F) {
569 bool IsRetAggr = F->getReturnType()->isAggregateType();
570 // Allow intrinsics with aggregate return/argument types to reach GlobalISel.
571 // Renaming/mutating the signature of an intrinsic would desync its name from
572 // its argument types and break the IR verifier.
573 if (F->isIntrinsic())
574 return F;
575
576 IRBuilder<> B(F->getContext());
577
578 bool HasAggrArg = llvm::any_of(F->args(), [](Argument &Arg) {
579 return Arg.getType()->isAggregateType();
580 });
581 bool DoClone = IsRetAggr || HasAggrArg;
582 if (!DoClone)
583 return F;
584 SmallVector<std::pair<int, Type *>, 4> ChangedTypes;
585 Type *RetType = IsRetAggr ? B.getInt32Ty() : F->getReturnType();
586 if (IsRetAggr)
587 ChangedTypes.push_back(std::pair<int, Type *>(-1, F->getReturnType()));
588 SmallVector<Type *, 4> ArgTypes;
589 for (const auto &Arg : F->args()) {
590 if (Arg.getType()->isAggregateType()) {
591 ArgTypes.push_back(B.getInt32Ty());
592 ChangedTypes.push_back(
593 std::pair<int, Type *>(Arg.getArgNo(), Arg.getType()));
594 } else
595 ArgTypes.push_back(Arg.getType());
596 }
597 FunctionType *NewFTy =
598 FunctionType::get(RetType, ArgTypes, F->getFunctionType()->isVarArg());
599 Function *NewF =
600 Function::Create(NewFTy, F->getLinkage(), F->getAddressSpace(),
601 F->getName(), F->getParent());
602
604 auto NewFArgIt = NewF->arg_begin();
605 for (auto &Arg : F->args()) {
606 StringRef ArgName = Arg.getName();
607 NewFArgIt->setName(ArgName);
608 VMap[&Arg] = &(*NewFArgIt++);
609 }
611
612 CloneFunctionInto(NewF, F, VMap, CloneFunctionChangeType::LocalChangesOnly,
613 Returns);
614 NewF->takeName(F);
615
617 NewF->getParent()->getOrInsertNamedMetadata("spv.cloned_funcs"),
618 std::move(ChangedTypes), NewF->getName());
619
620 for (auto *U : make_early_inc_range(F->users())) {
621 if (CallInst *CI;
622 (CI = dyn_cast<CallInst>(U)) && CI->getCalledFunction() == F)
623 CI->mutateFunctionType(NewF->getFunctionType());
624 if (auto *C = dyn_cast<Constant>(U))
625 C->handleOperandChange(F, NewF);
626 else
627 U->replaceUsesOfWith(F, NewF);
628 }
629
630 // register the mutation
631 if (RetType != F->getReturnType())
632 TM.getSubtarget<SPIRVSubtarget>(*F).getSPIRVGlobalRegistry()->addMutated(
633 NewF, F->getReturnType());
634 return NewF;
635}
636
637// Returns true iff `F`'s name resolves (after OpenCL/SPIR-V demangling and
638// builtin-name lookup) to the SPIR-V friendly built-in `__spirv_AbortKHR`.
639static bool isAbortKHRBuiltin(const Function &F) {
640 if (F.isIntrinsic())
641 return false;
642 StringRef Name = F.getName();
643 // Quick reject: the mangled or unmangled name must contain the substring.
644 if (!Name.contains("__spirv_AbortKHR"))
645 return false;
646 std::string Demangled = getOclOrSpirvBuiltinDemangledName(Name);
647 if (Demangled.empty())
648 return false;
649 return SPIRV::lookupBuiltinNameHelper(Demangled) == "__spirv_AbortKHR";
650}
651
652// Rewrites a single call to `__spirv_AbortKHR` into a call to the
653// `llvm.spv.abort` target intrinsic, then re-terminates the block with
654// `unreachable`. OpAbortKHR is itself a SPIR-V function-termination
655// instruction and must be the last instruction in its block, so any trailing
656// stores/lifetime intrinsics/`ret` emitted by the OpenCL ABI are dropped.
657// `changeToUnreachable` cleans up any successor PHI predecessor entries.
659 IRBuilder<> B(CI);
660 Value *Msg = CI->getArgOperand(0);
661 // The OpenCL C ABI may pass aggregate arguments by pointer (byval). In that
662 // case load the underlying value so that OpAbortKHR receives the composite
663 // itself, as required by the SPV_KHR_abort spec ("Message Type must be a
664 // concrete type").
665 if (CI->isByValArgument(0)) {
666 Type *AggTy = CI->getParamByValType(0);
667 Msg = B.CreateLoad(AggTy, Msg);
668 }
669 B.CreateIntrinsic(Intrinsic::spv_abort, {Msg->getType()}, {Msg});
671}
672
673// Replace OpenCL/SPIR-V style calls to `__spirv_AbortKHR(message)` (i.e.
674// calls to `F` when `F` is the `__spirv_AbortKHR` built-in) with calls to the
675// `llvm.spv.abort` target intrinsic.
676bool SPIRVPrepareFunctionsImpl::substituteAbortKHRCalls(Function *F) {
677 if (!isAbortKHRBuiltin(*F))
678 return false;
679
681 for (User *U : F->users()) {
682 auto *CI = dyn_cast<CallInst>(U);
683 if (!CI || CI->getCalledFunction() != F)
684 continue;
685 if (CI->arg_size() != 1)
686 continue;
687 Calls.push_back(CI);
688 }
689
690 for (CallInst *CI : Calls)
692
693 return !Calls.empty();
694}
695
696// When the SPV_KHR_abort extension is enabled, `llvm.trap` and
697// `llvm.ubsantrap` are lowered to `OpAbortKHR` during instruction selection.
698// `OpAbortKHR` is itself a SPIR-V block terminator, so any instructions that
699// follow the trap call within the same basic block (e.g. `ret`, lifetime
700// markers) would produce SPIR-V ops after `OpAbortKHR` and break validation.
701// Terminate the block right after each call to the trap intrinsics by replacing
702// the next instruction with `unreachable`.
703bool SPIRVPrepareFunctionsImpl::terminateBlocksAfterTrap(Module &M,
704 Intrinsic::ID IID) {
705 assert((IID == Intrinsic::trap || IID == Intrinsic::ubsantrap) &&
706 "Expected trap intrinsic ID");
707
709 if (!F)
710 return false;
711
712 // If the target doesn't support SPV_KHR_abort, we won't be able to lower
713 // the trap intrinsic to OpAbortKHR, so we can skip the block-terminating
714 // transformation.
715 const auto &ST = TM.getSubtarget<SPIRVSubtarget>(*F);
716 if (!ST.canUseExtension(SPIRV::Extension::SPV_KHR_abort))
717 return false;
718
720 for (User *U : F->users()) {
721 auto *CI = dyn_cast<CallInst>(U);
722 if (!CI || CI->getCalledFunction() != F)
723 continue;
724 Calls.push_back(CI);
725 }
726
727 bool Changed = false;
728 for (CallInst *CI : Calls) {
729 Instruction *Next = CI->getNextNode();
731 continue;
733 Changed = true;
734 }
735 return Changed;
736}
737
738static std::string fixMultiOutputConstraintString(StringRef Constraints) {
739 // We should only have one =r return for the made up ASM type.
741 SplitString(Constraints, Tmp, ",");
742 std::string SafeConstraints("=r,");
743 for (unsigned I = 0u; I != Tmp.size() - 1; ++I) {
744 if (Tmp[I].starts_with('=') && (Tmp[I][1] == '&' || isalnum(Tmp[I][1])))
745 continue;
746 SafeConstraints.append(Tmp[I]).append({','});
747 }
748 SafeConstraints.append(Tmp.back());
749
750 return SafeConstraints;
751}
752
753// Mutates indirect and inline ASM callsites iff aggregate argument/return types
754// are present with the types replaced by i32 types. The change in types is
755// noted in 'spv.mutated_callsites' metadata for later restoration. For ASM we
756// also have to mutate the constraint string as IRTranslator tries to handle
757// multiple outputs and expects an aggregate return type in their presence.
758bool SPIRVPrepareFunctionsImpl::removeAggregateTypesFromCalls(Function *F) {
759 if (F->isDeclaration() || F->isIntrinsic())
760 return false;
761
763 for (auto &&I : instructions(F)) {
764 if (auto *CB = dyn_cast<CallBase>(&I)) {
765 if (!CB->getCalledOperand() || CB->getCalledFunction())
766 continue;
767 if (CB->getType()->isAggregateType() ||
768 any_of(CB->args(),
769 [](auto &&Arg) { return Arg->getType()->isAggregateType(); }))
770 Calls.emplace_back(CB, nullptr);
771 }
772 }
773
774 if (Calls.empty())
775 return false;
776
777 IRBuilder<> B(F->getContext());
778
779 unsigned MutatedCallIdx = 0;
780 for (auto &&[CB, NewFnTy] : Calls) {
782 SmallVector<Type *> NewArgTypes;
783
784 Type *RetTy = CB->getType();
785 if (RetTy->isAggregateType()) {
786 ChangedTypes.emplace_back(-1, RetTy);
787 RetTy = B.getInt32Ty();
788 }
789
790 for (auto &&Arg : CB->args()) {
791 if (Arg->getType()->isAggregateType()) {
792 NewArgTypes.push_back(B.getInt32Ty());
793 ChangedTypes.emplace_back(Arg.getOperandNo(), Arg->getType());
794 } else {
795 NewArgTypes.push_back(Arg->getType());
796 }
797 }
798 NewFnTy = FunctionType::get(RetTy, NewArgTypes,
799 CB->getFunctionType()->isVarArg());
800
801 // Keyed via instruction metadata, not a name.
802 std::string Key =
803 ("spv.mutated_callsite." + F->getName() + "." + Twine(MutatedCallIdx++))
804 .str();
805 CB->setMetadata(
806 "spv.mutated_callsite",
807 MDNode::get(F->getContext(), MDString::get(F->getContext(), Key)));
808
809 std::string Constraints;
810 if (auto *ASM = dyn_cast<InlineAsm>(CB->getCalledOperand())) {
811 Constraints = ASM->getConstraintString();
812
813 CB->setCalledOperand(InlineAsm::get(
814 NewFnTy, ASM->getAsmString(),
815 fixMultiOutputConstraintString(Constraints), ASM->hasSideEffects(),
816 ASM->isAlignStack(), ASM->getDialect(), ASM->canThrow()));
817 }
818
820 F->getParent()->getOrInsertNamedMetadata("spv.mutated_callsites"),
821 std::move(ChangedTypes), Key, Constraints);
822 }
823
824 for (auto &&[CB, NewFTy] : Calls) {
825 if (NewFTy->getReturnType() != CB->getType())
826 TM.getSubtarget<SPIRVSubtarget>(*F).getSPIRVGlobalRegistry()->addMutated(
827 CB, CB->getType());
828 CB->mutateFunctionType(NewFTy);
829 }
830
831 return true;
832}
833
834bool SPIRVPrepareFunctionsImpl::runOnModule(Module &M) {
835 // Resolve the SPIR-V environment from module content before any
836 // function-level processing. This must happen before legalization so that
837 // isShader()/isKernel() return correct values.
838 const_cast<SPIRVTargetMachine &>(TM)
839 .getMutableSubtargetImpl()
840 ->resolveEnvFromModule(M);
841
842 bool Changed = false;
843 if (M.getFunctionDefs().empty()) {
844 // If there are no function definitions, insert a service
845 // function so that the global/constant tracking intrinsics
846 // will be created. Without these intrinsics the generated SPIR-V
847 // will be empty. The service function itself is not emitted.
849 BasicBlock *BB = BasicBlock::Create(M.getContext(), "entry", SF);
850 IRBuilder<> IRB(BB);
851 IRB.CreateRetVoid();
852 Changed = true;
853 }
854
855 Changed |= terminateBlocksAfterTrap(M, Intrinsic::trap);
856 Changed |= terminateBlocksAfterTrap(M, Intrinsic::ubsantrap);
857
858 for (GlobalVariable &GV : M.globals()) {
859 // Strip + tag available_externally globals so AuxData can re-emit the
860 // original linkage as NonSemantic.AuxData::Linkage.
861 if (GV.hasAvailableExternallyLinkage() && !GV.isDeclaration()) {
863 GV.setLinkage(GlobalValue::ExternalLinkage);
864 Changed = true;
865 }
866 }
867
868 for (Function &F : M) {
869 // MachineFunctionPass skips available_externally; strip + tag so AuxData
870 // can re-emit the original linkage as NonSemantic.AuxData::Linkage.
871 if (F.hasAvailableExternallyLinkage() && !F.isDeclaration()) {
874 Changed = true;
875 }
876 Changed |= substituteAbortKHRCalls(&F);
877 Changed |= substituteIntrinsicCalls(&F);
878 Changed |= sortBlocks(F);
879 Changed |= removeAggregateTypesFromCalls(&F);
880 }
881
882 std::vector<Function *> FuncsWorklist;
883 for (auto &F : M)
884 FuncsWorklist.push_back(&F);
885
886 for (auto *F : FuncsWorklist) {
887 Function *NewF = removeAggregateTypesFromSignature(F);
888
889 if (NewF != F) {
890 F->eraseFromParent();
891 Changed = true;
892 }
893 }
894 return Changed;
895}
896
899 return SPIRVPrepareFunctionsImpl(TM).runOnModule(M)
902}
903
906 return new SPIRVPrepareFunctionsLegacy(TM);
907}
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)
#define SPIRV_WAS_AVAILABLE_EXTERNALLY_ATTR
Definition SPIRVUtils.h:541
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:740
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
Diagnostic information for unsupported feature in backend.
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:833
FunctionType * getFunctionType() const
Returns the FunctionType for me.
Definition Function.h:211
arg_iterator arg_begin()
Definition Function.h:842
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:860
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 CallInst * CreateIntrinsicWithoutFolding(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.
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)
Definition IRBuilder.h:1532
ReturnInst * CreateRet(Value *V)
Create a 'ret <val>' instruction.
Definition IRBuilder.h:1192
Value * CreateSub(Value *LHS, Value *RHS, const Twine &Name="", bool HasNUW=false, bool HasNSW=false)
Definition IRBuilder.h:1439
Value * CreateShl(Value *LHS, Value *RHS, const Twine &Name="", bool HasNUW=false, bool HasNSW=false)
Definition IRBuilder.h:1511
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:608
ReturnInst * CreateRetVoid()
Create a 'ret void' instruction.
Definition IRBuilder.h:1187
LLVM_ABI Value * CreateIntrinsic(Intrinsic::ID ID, ArrayRef< Type * > OverloadTypes, ArrayRef< Value * > Args, FMFSource FMFSource={}, const Twine &Name="", ArrayRef< OperandBundleDef > OpBundles={}, function_ref< void(CallInst *)> SetFn=[](CallInst *) {})
Variant to create a possibly constant-folded intrinsic.
void SetInsertPoint(BasicBlock *TheBB)
This specifies that created instructions should be appended to the end of the specified block.
Definition IRBuilder.h:181
Value * CreateOr(Value *LHS, Value *RHS, const Twine &Name="", bool IsDisjoint=false)
Definition IRBuilder.h:1592
ConstantInt * getInt(const APInt &AI)
Get a constant integer value.
Definition IRBuilder.h:492
Value * CreateURem(Value *LHS, Value *RHS, const Twine &Name="")
Definition IRBuilder.h:1499
This provides a uniform API for creating instructions and inserting them into a basic block: either a...
Definition IRBuilder.h:2848
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.
LLVM_ABI 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:1554
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:1742
Module * getParent()
Get the module that holds this named metadata collection.
Definition Metadata.h:1812
LLVM_ABI void addOperand(MDNode *M)
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.
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:431
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:309
bool isAggregateType() const
Return true if the type is an aggregate type.
Definition Type.h:319
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:394
LLVM_ABI void replaceAllUsesWith(Value *V)
Change all uses of this to point to a new Value.
Definition Value.cpp:553
LLVM_ABI StringRef getName() const
Return a constant reference to the value's name.
Definition Value.cpp:319
LLVM_ABI void takeName(Value *V)
Transfer the name from V to this value.
Definition Value.cpp:400
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
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:2026
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:1746
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_ATTRIBUTE_VISIBILITY_DEFAULT AnalysisKey InnerAnalysisManagerProxy< AnalysisManagerT, IRUnitT, ExtraArgTs... >::Key
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:2539
@ 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:1910
@ Add
Sum of integers.
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
RelativeUniformCounterPtr ValuesPtrExpr VTableAddr Next
Definition InstrProf.h:147
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)
constexpr detail::IsaCheckPredicate< Types... > IsaPred
Function object wrapper for the llvm::isa type check.
Definition Casting.h:866
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:860