clang 20.0.0git
CGHLSLRuntime.cpp
Go to the documentation of this file.
1//===----- CGHLSLRuntime.cpp - Interface to HLSL Runtimes -----------------===//
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 provides an abstract class for HLSL code generation. Concrete
10// subclasses of this implement code generation for specific HLSL
11// runtime libraries.
12//
13//===----------------------------------------------------------------------===//
14
15#include "CGHLSLRuntime.h"
16#include "CGDebugInfo.h"
17#include "CodeGenModule.h"
18#include "TargetInfo.h"
19#include "clang/AST/Decl.h"
21#include "llvm/IR/Metadata.h"
22#include "llvm/IR/Module.h"
23#include "llvm/Support/FormatVariadic.h"
24
25using namespace clang;
26using namespace CodeGen;
27using namespace clang::hlsl;
28using namespace llvm;
29
30namespace {
31
32void addDxilValVersion(StringRef ValVersionStr, llvm::Module &M) {
33 // The validation of ValVersionStr is done at HLSLToolChain::TranslateArgs.
34 // Assume ValVersionStr is legal here.
35 VersionTuple Version;
36 if (Version.tryParse(ValVersionStr) || Version.getBuild() ||
37 Version.getSubminor() || !Version.getMinor()) {
38 return;
39 }
40
41 uint64_t Major = Version.getMajor();
42 uint64_t Minor = *Version.getMinor();
43
44 auto &Ctx = M.getContext();
45 IRBuilder<> B(M.getContext());
46 MDNode *Val = MDNode::get(Ctx, {ConstantAsMetadata::get(B.getInt32(Major)),
47 ConstantAsMetadata::get(B.getInt32(Minor))});
48 StringRef DXILValKey = "dx.valver";
49 auto *DXILValMD = M.getOrInsertNamedMetadata(DXILValKey);
50 DXILValMD->addOperand(Val);
51}
52void addDisableOptimizations(llvm::Module &M) {
53 StringRef Key = "dx.disable_optimizations";
54 M.addModuleFlag(llvm::Module::ModFlagBehavior::Override, Key, 1);
55}
56// cbuffer will be translated into global variable in special address space.
57// If translate into C,
58// cbuffer A {
59// float a;
60// float b;
61// }
62// float foo() { return a + b; }
63//
64// will be translated into
65//
66// struct A {
67// float a;
68// float b;
69// } cbuffer_A __attribute__((address_space(4)));
70// float foo() { return cbuffer_A.a + cbuffer_A.b; }
71//
72// layoutBuffer will create the struct A type.
73// replaceBuffer will replace use of global variable a and b with cbuffer_A.a
74// and cbuffer_A.b.
75//
76void layoutBuffer(CGHLSLRuntime::Buffer &Buf, const DataLayout &DL) {
77 if (Buf.Constants.empty())
78 return;
79
80 std::vector<llvm::Type *> EltTys;
81 for (auto &Const : Buf.Constants) {
82 GlobalVariable *GV = Const.first;
83 Const.second = EltTys.size();
84 llvm::Type *Ty = GV->getValueType();
85 EltTys.emplace_back(Ty);
86 }
87 Buf.LayoutStruct = llvm::StructType::get(EltTys[0]->getContext(), EltTys);
88}
89
90GlobalVariable *replaceBuffer(CGHLSLRuntime::Buffer &Buf) {
91 // Create global variable for CB.
92 GlobalVariable *CBGV = new GlobalVariable(
93 Buf.LayoutStruct, /*isConstant*/ true,
94 GlobalValue::LinkageTypes::ExternalLinkage, nullptr,
95 llvm::formatv("{0}{1}", Buf.Name, Buf.IsCBuffer ? ".cb." : ".tb."),
96 GlobalValue::NotThreadLocal);
97
98 IRBuilder<> B(CBGV->getContext());
99 Value *ZeroIdx = B.getInt32(0);
100 // Replace Const use with CB use.
101 for (auto &[GV, Offset] : Buf.Constants) {
102 Value *GEP =
103 B.CreateGEP(Buf.LayoutStruct, CBGV, {ZeroIdx, B.getInt32(Offset)});
104
105 assert(Buf.LayoutStruct->getElementType(Offset) == GV->getValueType() &&
106 "constant type mismatch");
107
108 // Replace.
109 GV->replaceAllUsesWith(GEP);
110 // Erase GV.
111 GV->removeDeadConstantUsers();
112 GV->eraseFromParent();
113 }
114 return CBGV;
115}
116
117} // namespace
118
120 assert(T->isHLSLSpecificType() && "Not an HLSL specific type!");
121
122 // Check if the target has a specific translation for this type first.
123 if (llvm::Type *TargetTy = CGM.getTargetCodeGenInfo().getHLSLType(CGM, T))
124 return TargetTy;
125
126 llvm_unreachable("Generic handling of HLSL types is not supported.");
127}
128
129llvm::Triple::ArchType CGHLSLRuntime::getArch() {
130 return CGM.getTarget().getTriple().getArch();
131}
132
133void CGHLSLRuntime::addConstant(VarDecl *D, Buffer &CB) {
134 if (D->getStorageClass() == SC_Static) {
135 // For static inside cbuffer, take as global static.
136 // Don't add to cbuffer.
138 return;
139 }
140
141 auto *GV = cast<GlobalVariable>(CGM.GetAddrOfGlobalVar(D));
142 // Add debug info for constVal.
144 if (CGM.getCodeGenOpts().getDebugInfo() >=
145 codegenoptions::DebugInfoKind::LimitedDebugInfo)
146 DI->EmitGlobalVariable(cast<GlobalVariable>(GV), D);
147
148 // FIXME: support packoffset.
149 // See https://github.com/llvm/llvm-project/issues/57914.
150 uint32_t Offset = 0;
151 bool HasUserOffset = false;
152
153 unsigned LowerBound = HasUserOffset ? Offset : UINT_MAX;
154 CB.Constants.emplace_back(std::make_pair(GV, LowerBound));
155}
156
157void CGHLSLRuntime::addBufferDecls(const DeclContext *DC, Buffer &CB) {
158 for (Decl *it : DC->decls()) {
159 if (auto *ConstDecl = dyn_cast<VarDecl>(it)) {
160 addConstant(ConstDecl, CB);
161 } else if (isa<CXXRecordDecl, EmptyDecl>(it)) {
162 // Nothing to do for this declaration.
163 } else if (isa<FunctionDecl>(it)) {
164 // A function within an cbuffer is effectively a top-level function,
165 // as it only refers to globally scoped declarations.
167 }
168 }
169}
170
172 Buffers.emplace_back(Buffer(D));
173 addBufferDecls(D, Buffers.back());
174}
175
177 auto &TargetOpts = CGM.getTarget().getTargetOpts();
178 llvm::Module &M = CGM.getModule();
179 Triple T(M.getTargetTriple());
180 if (T.getArch() == Triple::ArchType::dxil)
181 addDxilValVersion(TargetOpts.DxilValidatorVersion, M);
182
184 if (CGM.getCodeGenOpts().OptimizationLevel == 0)
185 addDisableOptimizations(M);
186
187 const DataLayout &DL = M.getDataLayout();
188
189 for (auto &Buf : Buffers) {
190 layoutBuffer(Buf, DL);
191 GlobalVariable *GV = replaceBuffer(Buf);
192 M.insertGlobalVariable(GV);
193 llvm::hlsl::ResourceClass RC = Buf.IsCBuffer
194 ? llvm::hlsl::ResourceClass::CBuffer
195 : llvm::hlsl::ResourceClass::SRV;
196 llvm::hlsl::ResourceKind RK = Buf.IsCBuffer
197 ? llvm::hlsl::ResourceKind::CBuffer
198 : llvm::hlsl::ResourceKind::TBuffer;
199 addBufferResourceAnnotation(GV, RC, RK, /*IsROV=*/false,
200 llvm::hlsl::ElementType::Invalid, Buf.Binding);
201 }
202}
203
205 : Name(D->getName()), IsCBuffer(D->isCBuffer()),
206 Binding(D->getAttr<HLSLResourceBindingAttr>()) {}
207
208void CGHLSLRuntime::addBufferResourceAnnotation(llvm::GlobalVariable *GV,
209 llvm::hlsl::ResourceClass RC,
210 llvm::hlsl::ResourceKind RK,
211 bool IsROV,
212 llvm::hlsl::ElementType ET,
213 BufferResBinding &Binding) {
214 llvm::Module &M = CGM.getModule();
215
216 NamedMDNode *ResourceMD = nullptr;
217 switch (RC) {
218 case llvm::hlsl::ResourceClass::UAV:
219 ResourceMD = M.getOrInsertNamedMetadata("hlsl.uavs");
220 break;
221 case llvm::hlsl::ResourceClass::SRV:
222 ResourceMD = M.getOrInsertNamedMetadata("hlsl.srvs");
223 break;
224 case llvm::hlsl::ResourceClass::CBuffer:
225 ResourceMD = M.getOrInsertNamedMetadata("hlsl.cbufs");
226 break;
227 default:
228 assert(false && "Unsupported buffer type!");
229 return;
230 }
231 assert(ResourceMD != nullptr &&
232 "ResourceMD must have been set by the switch above.");
233
234 llvm::hlsl::FrontendResource Res(
235 GV, RK, ET, IsROV, Binding.Reg.value_or(UINT_MAX), Binding.Space);
236 ResourceMD->addOperand(Res.getMetadata());
237}
238
239static llvm::hlsl::ElementType
240calculateElementType(const ASTContext &Context, const clang::Type *ResourceTy) {
241 using llvm::hlsl::ElementType;
242
243 // TODO: We may need to update this when we add things like ByteAddressBuffer
244 // that don't have a template parameter (or, indeed, an element type).
245 const auto *TST = ResourceTy->getAs<TemplateSpecializationType>();
246 assert(TST && "Resource types must be template specializations");
247 ArrayRef<TemplateArgument> Args = TST->template_arguments();
248 assert(!Args.empty() && "Resource has no element type");
249
250 // At this point we have a resource with an element type, so we can assume
251 // that it's valid or we would have diagnosed the error earlier.
252 QualType ElTy = Args[0].getAsType();
253
254 // We should either have a basic type or a vector of a basic type.
255 if (const auto *VecTy = ElTy->getAs<clang::VectorType>())
256 ElTy = VecTy->getElementType();
257
258 if (ElTy->isSignedIntegerType()) {
259 switch (Context.getTypeSize(ElTy)) {
260 case 16:
261 return ElementType::I16;
262 case 32:
263 return ElementType::I32;
264 case 64:
265 return ElementType::I64;
266 }
267 } else if (ElTy->isUnsignedIntegerType()) {
268 switch (Context.getTypeSize(ElTy)) {
269 case 16:
270 return ElementType::U16;
271 case 32:
272 return ElementType::U32;
273 case 64:
274 return ElementType::U64;
275 }
276 } else if (ElTy->isSpecificBuiltinType(BuiltinType::Half))
277 return ElementType::F16;
278 else if (ElTy->isSpecificBuiltinType(BuiltinType::Float))
279 return ElementType::F32;
280 else if (ElTy->isSpecificBuiltinType(BuiltinType::Double))
281 return ElementType::F64;
282
283 // TODO: We need to handle unorm/snorm float types here once we support them
284 llvm_unreachable("Invalid element type for resource");
285}
286
287void CGHLSLRuntime::annotateHLSLResource(const VarDecl *D, GlobalVariable *GV) {
288 const Type *Ty = D->getType()->getPointeeOrArrayElementType();
289 if (!Ty)
290 return;
291 const auto *RD = Ty->getAsCXXRecordDecl();
292 if (!RD)
293 return;
294 // the resource related attributes are on the handle member
295 // inside the record decl
296 for (auto *FD : RD->fields()) {
297 const auto *HLSLResAttr = FD->getAttr<HLSLResourceAttr>();
298 const auto *HLSLResClassAttr = FD->getAttr<HLSLResourceClassAttr>();
299 if (!HLSLResAttr || !HLSLResClassAttr)
300 continue;
301
302 llvm::hlsl::ResourceClass RC = HLSLResClassAttr->getResourceClass();
303 llvm::hlsl::ResourceKind RK = HLSLResAttr->getResourceKind();
304 bool IsROV = HLSLResAttr->getIsROV();
305 llvm::hlsl::ElementType ET = calculateElementType(CGM.getContext(), Ty);
306
307 BufferResBinding Binding(D->getAttr<HLSLResourceBindingAttr>());
308 addBufferResourceAnnotation(GV, RC, RK, IsROV, ET, Binding);
309 }
310}
311
313 HLSLResourceBindingAttr *Binding) {
314 if (Binding) {
315 llvm::APInt RegInt(64, 0);
316 Binding->getSlot().substr(1).getAsInteger(10, RegInt);
317 Reg = RegInt.getLimitedValue();
318 llvm::APInt SpaceInt(64, 0);
319 Binding->getSpace().substr(5).getAsInteger(10, SpaceInt);
320 Space = SpaceInt.getLimitedValue();
321 } else {
322 Space = 0;
323 }
324}
325
327 const FunctionDecl *FD, llvm::Function *Fn) {
328 const auto *ShaderAttr = FD->getAttr<HLSLShaderAttr>();
329 assert(ShaderAttr && "All entry functions must have a HLSLShaderAttr");
330 const StringRef ShaderAttrKindStr = "hlsl.shader";
331 Fn->addFnAttr(ShaderAttrKindStr,
332 llvm::Triple::getEnvironmentTypeName(ShaderAttr->getType()));
333 if (HLSLNumThreadsAttr *NumThreadsAttr = FD->getAttr<HLSLNumThreadsAttr>()) {
334 const StringRef NumThreadsKindStr = "hlsl.numthreads";
335 std::string NumThreadsStr =
336 formatv("{0},{1},{2}", NumThreadsAttr->getX(), NumThreadsAttr->getY(),
337 NumThreadsAttr->getZ());
338 Fn->addFnAttr(NumThreadsKindStr, NumThreadsStr);
339 }
340}
341
342static Value *buildVectorInput(IRBuilder<> &B, Function *F, llvm::Type *Ty) {
343 if (const auto *VT = dyn_cast<FixedVectorType>(Ty)) {
344 Value *Result = PoisonValue::get(Ty);
345 for (unsigned I = 0; I < VT->getNumElements(); ++I) {
346 Value *Elt = B.CreateCall(F, {B.getInt32(I)});
347 Result = B.CreateInsertElement(Result, Elt, I);
348 }
349 return Result;
350 }
351 return B.CreateCall(F, {B.getInt32(0)});
352}
353
354llvm::Value *CGHLSLRuntime::emitInputSemantic(IRBuilder<> &B,
355 const ParmVarDecl &D,
356 llvm::Type *Ty) {
357 assert(D.hasAttrs() && "Entry parameter missing annotation attribute!");
358 if (D.hasAttr<HLSLSV_GroupIndexAttr>()) {
359 llvm::Function *DxGroupIndex =
360 CGM.getIntrinsic(Intrinsic::dx_flattened_thread_id_in_group);
361 return B.CreateCall(FunctionCallee(DxGroupIndex));
362 }
363 if (D.hasAttr<HLSLSV_DispatchThreadIDAttr>()) {
364 llvm::Function *ThreadIDIntrinsic =
365 CGM.getIntrinsic(getThreadIdIntrinsic());
366 return buildVectorInput(B, ThreadIDIntrinsic, Ty);
367 }
368 assert(false && "Unhandled parameter attribute");
369 return nullptr;
370}
371
373 llvm::Function *Fn) {
374 llvm::Module &M = CGM.getModule();
375 llvm::LLVMContext &Ctx = M.getContext();
376 auto *EntryTy = llvm::FunctionType::get(llvm::Type::getVoidTy(Ctx), false);
377 Function *EntryFn =
378 Function::Create(EntryTy, Function::ExternalLinkage, FD->getName(), &M);
379
380 // Copy function attributes over, we have no argument or return attributes
381 // that can be valid on the real entry.
382 AttributeList NewAttrs = AttributeList::get(Ctx, AttributeList::FunctionIndex,
383 Fn->getAttributes().getFnAttrs());
384 EntryFn->setAttributes(NewAttrs);
385 setHLSLEntryAttributes(FD, EntryFn);
386
387 // Set the called function as internal linkage.
388 Fn->setLinkage(GlobalValue::InternalLinkage);
389
390 BasicBlock *BB = BasicBlock::Create(Ctx, "entry", EntryFn);
391 IRBuilder<> B(BB);
393 // FIXME: support struct parameters where semantics are on members.
394 // See: https://github.com/llvm/llvm-project/issues/57874
395 unsigned SRetOffset = 0;
396 for (const auto &Param : Fn->args()) {
397 if (Param.hasStructRetAttr()) {
398 // FIXME: support output.
399 // See: https://github.com/llvm/llvm-project/issues/57874
400 SRetOffset = 1;
401 Args.emplace_back(PoisonValue::get(Param.getType()));
402 continue;
403 }
404 const ParmVarDecl *PD = FD->getParamDecl(Param.getArgNo() - SRetOffset);
405 Args.push_back(emitInputSemantic(B, *PD, Param.getType()));
406 }
407
408 CallInst *CI = B.CreateCall(FunctionCallee(Fn), Args);
409 (void)CI;
410 // FIXME: Handle codegen for return type semantics.
411 // See: https://github.com/llvm/llvm-project/issues/57875
412 B.CreateRetVoid();
413}
414
416 llvm::Function *Fn) {
417 if (FD->isInExportDeclContext()) {
418 const StringRef ExportAttrKindStr = "hlsl.export";
419 Fn->addFnAttr(ExportAttrKindStr);
420 }
421}
422
423static void gatherFunctions(SmallVectorImpl<Function *> &Fns, llvm::Module &M,
424 bool CtorOrDtor) {
425 const auto *GV =
426 M.getNamedGlobal(CtorOrDtor ? "llvm.global_ctors" : "llvm.global_dtors");
427 if (!GV)
428 return;
429 const auto *CA = dyn_cast<ConstantArray>(GV->getInitializer());
430 if (!CA)
431 return;
432 // The global_ctor array elements are a struct [Priority, Fn *, COMDat].
433 // HLSL neither supports priorities or COMDat values, so we will check those
434 // in an assert but not handle them.
435
437 for (const auto &Ctor : CA->operands()) {
438 if (isa<ConstantAggregateZero>(Ctor))
439 continue;
440 ConstantStruct *CS = cast<ConstantStruct>(Ctor);
441
442 assert(cast<ConstantInt>(CS->getOperand(0))->getValue() == 65535 &&
443 "HLSL doesn't support setting priority for global ctors.");
444 assert(isa<ConstantPointerNull>(CS->getOperand(2)) &&
445 "HLSL doesn't support COMDat for global ctors.");
446 Fns.push_back(cast<Function>(CS->getOperand(1)));
447 }
448}
449
451 llvm::Module &M = CGM.getModule();
454 gatherFunctions(CtorFns, M, true);
455 gatherFunctions(DtorFns, M, false);
456
457 // Insert a call to the global constructor at the beginning of the entry block
458 // to externally exported functions. This is a bit of a hack, but HLSL allows
459 // global constructors, but doesn't support driver initialization of globals.
460 for (auto &F : M.functions()) {
461 if (!F.hasFnAttribute("hlsl.shader"))
462 continue;
463 IRBuilder<> B(&F.getEntryBlock(), F.getEntryBlock().begin());
464 for (auto *Fn : CtorFns)
465 B.CreateCall(FunctionCallee(Fn));
466
467 // Insert global dtors before the terminator of the last instruction
468 B.SetInsertPoint(F.back().getTerminator());
469 for (auto *Fn : DtorFns)
470 B.CreateCall(FunctionCallee(Fn));
471 }
472
473 // No need to keep global ctors/dtors for non-lib profile after call to
474 // ctors/dtors added for entry.
475 Triple T(M.getTargetTriple());
476 if (T.getEnvironment() != Triple::EnvironmentType::Library) {
477 if (auto *GV = M.getNamedGlobal("llvm.global_ctors"))
478 GV->eraseFromParent();
479 if (auto *GV = M.getNamedGlobal("llvm.global_dtors"))
480 GV->eraseFromParent();
481 }
482}
static llvm::hlsl::ElementType calculateElementType(const ASTContext &Context, const clang::Type *ResourceTy)
static void gatherFunctions(SmallVectorImpl< Function * > &Fns, llvm::Module &M, bool CtorOrDtor)
static Value * buildVectorInput(IRBuilder<> &B, Function *F, llvm::Type *Ty)
const Decl * D
static std::string getName(const CallEvent &Call)
Defines the clang::TargetOptions class.
Holds long-lived AST nodes (such as types and decls) that can be referred to throughout the semantic ...
Definition: ASTContext.h:187
uint64_t getTypeSize(QualType T) const
Return the size of the specified (complete) type T, in bits.
Definition: ASTContext.h:2394
This class gathers all debug information during compilation and is responsible for emitting to llvm g...
Definition: CGDebugInfo.h:58
void setHLSLEntryAttributes(const FunctionDecl *FD, llvm::Function *Fn)
void setHLSLFunctionAttributes(const FunctionDecl *FD, llvm::Function *Fn)
void emitEntryFunction(const FunctionDecl *FD, llvm::Function *Fn)
llvm::Type * convertHLSLSpecificType(const Type *T)
llvm::Value * emitInputSemantic(llvm::IRBuilder<> &B, const ParmVarDecl &D, llvm::Type *Ty)
void annotateHLSLResource(const VarDecl *D, llvm::GlobalVariable *GV)
void addBuffer(const HLSLBufferDecl *D)
llvm::Module & getModule() const
CGDebugInfo * getModuleDebugInfo()
const TargetInfo & getTarget() const
void EmitGlobal(GlobalDecl D)
Emit code for a single global function or var decl.
ASTContext & getContext() const
llvm::Constant * GetAddrOfGlobalVar(const VarDecl *D, llvm::Type *Ty=nullptr, ForDefinition_t IsForDefinition=NotForDefinition)
Return the llvm::Constant for the address of the given global variable.
const TargetCodeGenInfo & getTargetCodeGenInfo()
const CodeGenOptions & getCodeGenOpts() const
llvm::Function * getIntrinsic(unsigned IID, ArrayRef< llvm::Type * > Tys=std::nullopt)
void EmitTopLevelDecl(Decl *D)
Emit code for a single top level declaration.
virtual llvm::Type * getHLSLType(CodeGenModule &CGM, const Type *T) const
Return an LLVM type that corresponds to a HLSL type.
Definition: TargetInfo.h:422
DeclContext - This is used only as base class of specific decl types that can act as declaration cont...
Definition: DeclBase.h:1436
decl_range decls() const
decls_begin/decls_end - Iterate over the declarations stored in this context.
Definition: DeclBase.h:2350
Decl - This represents one declaration (or definition), e.g.
Definition: DeclBase.h:86
T * getAttr() const
Definition: DeclBase.h:580
bool hasAttrs() const
Definition: DeclBase.h:525
bool isInExportDeclContext() const
Whether this declaration was exported in a lexical context.
Definition: DeclBase.cpp:1112
bool hasAttr() const
Definition: DeclBase.h:584
Represents a function declaration or definition.
Definition: Decl.h:1932
const ParmVarDecl * getParamDecl(unsigned i) const
Definition: Decl.h:2669
HLSLBufferDecl - Represent a cbuffer or tbuffer declaration.
Definition: Decl.h:4920
StringRef getName() const
Get the name of identifier for this declaration as a StringRef.
Definition: Decl.h:276
Represents a parameter to a function.
Definition: Decl.h:1722
A (possibly-)qualified type.
Definition: Type.h:941
TargetOptions & getTargetOpts() const
Retrieve the target options.
Definition: TargetInfo.h:312
const llvm::Triple & getTriple() const
Returns the target triple of the primary target.
Definition: TargetInfo.h:1256
Represents a type template specialization; the template must be a class template, a type alias templa...
Definition: Type.h:6480
The base class of the type hierarchy.
Definition: Type.h:1829
CXXRecordDecl * getAsCXXRecordDecl() const
Retrieves the CXXRecordDecl that this type refers to, either because the type is a RecordType or beca...
Definition: Type.cpp:1882
bool isSignedIntegerType() const
Return true if this is an integer type that is signed, according to C99 6.2.5p4 [char,...
Definition: Type.cpp:2146
bool isSpecificBuiltinType(unsigned K) const
Test for a particular builtin type.
Definition: Type.h:8288
bool isHLSLSpecificType() const
Definition: Type.h:8277
bool isUnsignedIntegerType() const
Return true if this is an integer type that is unsigned, according to C99 6.2.5p6 [which returns true...
Definition: Type.cpp:2196
const T * getAs() const
Member-template getAs<specific type>'.
Definition: Type.h:8540
QualType getType() const
Definition: Decl.h:678
Represents a variable declaration or definition.
Definition: Decl.h:879
Represents a GCC generic vector type.
Definition: Type.h:4021
#define UINT_MAX
Definition: limits.h:64
bool Const(InterpState &S, CodePtr OpPC, const T &Arg)
Definition: Interp.h:1181
The JSON file list parser is used to communicate input to InstallAPI.
@ SC_Static
Definition: Specifiers.h:252
@ Result
The result type of a method or function.
const FunctionProtoType * T
unsigned long uint64_t
Diagnostic wrappers for TextAPI types for error reporting.
Definition: Dominators.h:30
BufferResBinding(HLSLResourceBindingAttr *Attr)
std::vector< std::pair< llvm::GlobalVariable *, unsigned > > Constants