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