[HLSL][SPIRV] Add vk::constant_id attribute. (#143544)
The vk::constant_id attribute is used to indicate that a global const variable represents a specialization constant in SPIR-V. This PR adds this attribute to clang. The documentation for the attribute is [here](https://github.com/microsoft/DirectXShaderCompiler/blob/main/docs/SPIR-V.rst#specialization-constants). The strategy is to to modify the initializer to get the value of a specialize constant for a builtin defined in the SPIR-V backend. Implements https://github.com/llvm/wg-hlsl/pull/287 Fixes https://github.com/llvm/llvm-project/issues/142448 --------- Co-authored-by: Nathan Gauër <github@keenuts.net>
This commit is contained in:
parent
561eca44e7
commit
acde20b560
@ -5023,6 +5023,14 @@ def HLSLVkExtBuiltinInput : InheritableAttr {
|
||||
let Documentation = [HLSLVkExtBuiltinInputDocs];
|
||||
}
|
||||
|
||||
def HLSLVkConstantId : InheritableAttr {
|
||||
let Spellings = [CXX11<"vk", "constant_id">];
|
||||
let Args = [IntArgument<"Id">];
|
||||
let Subjects = SubjectList<[ExternalGlobalVar]>;
|
||||
let LangOpts = [HLSL];
|
||||
let Documentation = [VkConstantIdDocs];
|
||||
}
|
||||
|
||||
def RandomizeLayout : InheritableAttr {
|
||||
let Spellings = [GCC<"randomize_layout">];
|
||||
let Subjects = SubjectList<[Record]>;
|
||||
|
||||
@ -8252,6 +8252,21 @@ and https://microsoft.github.io/hlsl-specs/proposals/0013-wave-size-range.html
|
||||
}];
|
||||
}
|
||||
|
||||
def VkConstantIdDocs : Documentation {
|
||||
let Category = DocCatFunction;
|
||||
let Content = [{
|
||||
The ``vk::constant_id`` attribute specifies the id for a SPIR-V specialization
|
||||
constant. The attribute applies to const global scalar variables. The variable must be initialized with a C++11 constexpr.
|
||||
In SPIR-V, the
|
||||
variable will be replaced with an `OpSpecConstant` with the given id.
|
||||
The syntax is:
|
||||
|
||||
.. code-block:: text
|
||||
|
||||
``[[vk::constant_id(<Id>)]] const T Name = <Init>``
|
||||
}];
|
||||
}
|
||||
|
||||
def RootSignatureDocs : Documentation {
|
||||
let Category = DocCatFunction;
|
||||
let Content = [{
|
||||
|
||||
@ -5065,6 +5065,19 @@ def HLSLGroupMemoryBarrierWithGroupSync: LangBuiltin<"HLSL_LANG"> {
|
||||
let Prototype = "void()";
|
||||
}
|
||||
|
||||
class HLSLScalarTemplate
|
||||
: Template<["bool", "char", "short", "int", "long long int",
|
||||
"unsigned short", "unsigned int", "unsigned long long int",
|
||||
"__fp16", "float", "double"],
|
||||
["_bool", "_char", "_short", "_int", "_longlong", "_ushort",
|
||||
"_uint", "_ulonglong", "_half", "_float", "_double"]>;
|
||||
|
||||
def HLSLGetSpirvSpecConstant : LangBuiltin<"HLSL_LANG">, HLSLScalarTemplate {
|
||||
let Spellings = ["__builtin_get_spirv_spec_constant"];
|
||||
let Attributes = [NoThrow, Const, Pure];
|
||||
let Prototype = "T(unsigned int, T)";
|
||||
}
|
||||
|
||||
// Builtins for XRay.
|
||||
def XRayCustomEvent : Builtin {
|
||||
let Spellings = ["__xray_customevent"];
|
||||
|
||||
@ -12927,6 +12927,10 @@ def err_spirv_enum_not_int : Error<
|
||||
def err_spirv_enum_not_valid : Error<
|
||||
"invalid value for %select{storage class}0 argument">;
|
||||
|
||||
def err_specialization_const
|
||||
: Error<"variable with 'vk::constant_id' attribute must be a const "
|
||||
"int/float/enum/bool and be initialized with a literal">;
|
||||
|
||||
// errors of expect.with.probability
|
||||
def err_probability_not_constant_float : Error<
|
||||
"probability argument to __builtin_expect_with_probability must be constant "
|
||||
|
||||
@ -98,6 +98,8 @@ public:
|
||||
HLSLWaveSizeAttr *mergeWaveSizeAttr(Decl *D, const AttributeCommonInfo &AL,
|
||||
int Min, int Max, int Preferred,
|
||||
int SpelledArgsCount);
|
||||
HLSLVkConstantIdAttr *
|
||||
mergeVkConstantIdAttr(Decl *D, const AttributeCommonInfo &AL, int Id);
|
||||
HLSLShaderAttr *mergeShaderAttr(Decl *D, const AttributeCommonInfo &AL,
|
||||
llvm::Triple::EnvironmentType ShaderType);
|
||||
HLSLParamModifierAttr *
|
||||
@ -135,6 +137,7 @@ public:
|
||||
void handleRootSignatureAttr(Decl *D, const ParsedAttr &AL);
|
||||
void handleNumThreadsAttr(Decl *D, const ParsedAttr &AL);
|
||||
void handleWaveSizeAttr(Decl *D, const ParsedAttr &AL);
|
||||
void handleVkConstantIdAttr(Decl *D, const ParsedAttr &AL);
|
||||
void handleSV_DispatchThreadIDAttr(Decl *D, const ParsedAttr &AL);
|
||||
void handleSV_GroupThreadIDAttr(Decl *D, const ParsedAttr &AL);
|
||||
void handleSV_GroupIDAttr(Decl *D, const ParsedAttr &AL);
|
||||
@ -171,7 +174,7 @@ public:
|
||||
QualType getInoutParameterType(QualType Ty);
|
||||
|
||||
bool transformInitList(const InitializedEntity &Entity, InitListExpr *Init);
|
||||
|
||||
bool handleInitialization(VarDecl *VDecl, Expr *&Init);
|
||||
void deduceAddressSpace(VarDecl *Decl);
|
||||
|
||||
private:
|
||||
|
||||
@ -12,6 +12,7 @@
|
||||
|
||||
#include "CGBuiltin.h"
|
||||
#include "CGHLSLRuntime.h"
|
||||
#include "CodeGenFunction.h"
|
||||
|
||||
using namespace clang;
|
||||
using namespace CodeGen;
|
||||
@ -214,6 +215,43 @@ static Intrinsic::ID getWaveActiveMaxIntrinsic(llvm::Triple::ArchType Arch,
|
||||
}
|
||||
}
|
||||
|
||||
// Returns the mangled name for a builtin function that the SPIR-V backend
|
||||
// will expand into a spec Constant.
|
||||
static std::string getSpecConstantFunctionName(clang::QualType SpecConstantType,
|
||||
ASTContext &Context) {
|
||||
// The parameter types for our conceptual intrinsic function.
|
||||
QualType ClangParamTypes[] = {Context.IntTy, SpecConstantType};
|
||||
|
||||
// Create a temporary FunctionDecl for the builtin fuction. It won't be
|
||||
// added to the AST.
|
||||
FunctionProtoType::ExtProtoInfo EPI;
|
||||
QualType FnType =
|
||||
Context.getFunctionType(SpecConstantType, ClangParamTypes, EPI);
|
||||
DeclarationName FuncName = &Context.Idents.get("__spirv_SpecConstant");
|
||||
FunctionDecl *FnDeclForMangling = FunctionDecl::Create(
|
||||
Context, Context.getTranslationUnitDecl(), SourceLocation(),
|
||||
SourceLocation(), FuncName, FnType, /*TSI=*/nullptr, SC_Extern);
|
||||
|
||||
// Attach the created parameter declarations to the function declaration.
|
||||
SmallVector<ParmVarDecl *, 2> ParamDecls;
|
||||
for (QualType ParamType : ClangParamTypes) {
|
||||
ParmVarDecl *PD = ParmVarDecl::Create(
|
||||
Context, FnDeclForMangling, SourceLocation(), SourceLocation(),
|
||||
/*IdentifierInfo*/ nullptr, ParamType, /*TSI*/ nullptr, SC_None,
|
||||
/*DefaultArg*/ nullptr);
|
||||
ParamDecls.push_back(PD);
|
||||
}
|
||||
FnDeclForMangling->setParams(ParamDecls);
|
||||
|
||||
// Get the mangled name.
|
||||
std::string Name;
|
||||
llvm::raw_string_ostream MangledNameStream(Name);
|
||||
MangleContext *Mangler = Context.createMangleContext();
|
||||
Mangler->mangleName(FnDeclForMangling, MangledNameStream);
|
||||
MangledNameStream.flush();
|
||||
return Name;
|
||||
}
|
||||
|
||||
Value *CodeGenFunction::EmitHLSLBuiltinExpr(unsigned BuiltinID,
|
||||
const CallExpr *E,
|
||||
ReturnValueSlot ReturnValue) {
|
||||
@ -773,6 +811,42 @@ Value *CodeGenFunction::EmitHLSLBuiltinExpr(unsigned BuiltinID,
|
||||
return EmitRuntimeCall(
|
||||
Intrinsic::getOrInsertDeclaration(&CGM.getModule(), ID));
|
||||
}
|
||||
case Builtin::BI__builtin_get_spirv_spec_constant_bool:
|
||||
case Builtin::BI__builtin_get_spirv_spec_constant_short:
|
||||
case Builtin::BI__builtin_get_spirv_spec_constant_ushort:
|
||||
case Builtin::BI__builtin_get_spirv_spec_constant_int:
|
||||
case Builtin::BI__builtin_get_spirv_spec_constant_uint:
|
||||
case Builtin::BI__builtin_get_spirv_spec_constant_longlong:
|
||||
case Builtin::BI__builtin_get_spirv_spec_constant_ulonglong:
|
||||
case Builtin::BI__builtin_get_spirv_spec_constant_half:
|
||||
case Builtin::BI__builtin_get_spirv_spec_constant_float:
|
||||
case Builtin::BI__builtin_get_spirv_spec_constant_double: {
|
||||
llvm::Function *SpecConstantFn = getSpecConstantFunction(E->getType());
|
||||
llvm::Value *SpecId = EmitScalarExpr(E->getArg(0));
|
||||
llvm::Value *DefaultVal = EmitScalarExpr(E->getArg(1));
|
||||
llvm::Value *Args[] = {SpecId, DefaultVal};
|
||||
return Builder.CreateCall(SpecConstantFn, Args);
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
llvm::Function *clang::CodeGen::CodeGenFunction::getSpecConstantFunction(
|
||||
const clang::QualType &SpecConstantType) {
|
||||
|
||||
// Find or create the declaration for the function.
|
||||
llvm::Module *M = &CGM.getModule();
|
||||
std::string MangledName =
|
||||
getSpecConstantFunctionName(SpecConstantType, getContext());
|
||||
llvm::Function *SpecConstantFn = M->getFunction(MangledName);
|
||||
|
||||
if (!SpecConstantFn) {
|
||||
llvm::Type *IntType = ConvertType(getContext().IntTy);
|
||||
llvm::Type *RetTy = ConvertType(SpecConstantType);
|
||||
llvm::Type *ArgTypes[] = {IntType, RetTy};
|
||||
llvm::FunctionType *FnTy = llvm::FunctionType::get(RetTy, ArgTypes, false);
|
||||
SpecConstantFn = llvm::Function::Create(
|
||||
FnTy, llvm::GlobalValue::ExternalLinkage, MangledName, M);
|
||||
}
|
||||
return SpecConstantFn;
|
||||
}
|
||||
|
||||
@ -4850,6 +4850,12 @@ public:
|
||||
llvm::Value *EmitAMDGPUBuiltinExpr(unsigned BuiltinID, const CallExpr *E);
|
||||
llvm::Value *EmitHLSLBuiltinExpr(unsigned BuiltinID, const CallExpr *E,
|
||||
ReturnValueSlot ReturnValue);
|
||||
|
||||
// Returns a builtin function that the SPIR-V backend will expand into a spec
|
||||
// constant.
|
||||
llvm::Function *
|
||||
getSpecConstantFunction(const clang::QualType &SpecConstantType);
|
||||
|
||||
llvm::Value *EmitDirectXBuiltinExpr(unsigned BuiltinID, const CallExpr *E);
|
||||
llvm::Value *EmitSPIRVBuiltinExpr(unsigned BuiltinID, const CallExpr *E);
|
||||
llvm::Value *EmitScalarOrConstFoldImmArg(unsigned ICEArguments, unsigned Idx,
|
||||
|
||||
@ -2890,6 +2890,8 @@ static bool mergeDeclAttribute(Sema &S, NamedDecl *D,
|
||||
NewAttr = S.HLSL().mergeWaveSizeAttr(D, *WS, WS->getMin(), WS->getMax(),
|
||||
WS->getPreferred(),
|
||||
WS->getSpelledArgsCount());
|
||||
else if (const auto *CI = dyn_cast<HLSLVkConstantIdAttr>(Attr))
|
||||
NewAttr = S.HLSL().mergeVkConstantIdAttr(D, *CI, CI->getId());
|
||||
else if (const auto *SA = dyn_cast<HLSLShaderAttr>(Attr))
|
||||
NewAttr = S.HLSL().mergeShaderAttr(D, *SA, SA->getType());
|
||||
else if (isa<SuppressAttr>(Attr))
|
||||
@ -13757,6 +13759,10 @@ void Sema::AddInitializerToDecl(Decl *RealDecl, Expr *Init, bool DirectInit) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (getLangOpts().HLSL)
|
||||
if (!HLSL().handleInitialization(VDecl, Init))
|
||||
return;
|
||||
|
||||
// Get the decls type and save a reference for later, since
|
||||
// CheckInitializerTypes may change it.
|
||||
QualType DclT = VDecl->getType(), SavT = DclT;
|
||||
@ -14179,6 +14185,13 @@ void Sema::ActOnUninitializedDecl(Decl *RealDecl) {
|
||||
}
|
||||
}
|
||||
|
||||
// HLSL variable with the `vk::constant_id` attribute must be initialized.
|
||||
if (!Var->isInvalidDecl() && Var->hasAttr<HLSLVkConstantIdAttr>()) {
|
||||
Diag(Var->getLocation(), diag::err_specialization_const);
|
||||
Var->setInvalidDecl();
|
||||
return;
|
||||
}
|
||||
|
||||
if (!Var->isInvalidDecl() && RealDecl->hasAttr<LoaderUninitializedAttr>()) {
|
||||
if (Var->getStorageClass() == SC_Extern) {
|
||||
Diag(Var->getLocation(), diag::err_loader_uninitialized_extern_decl)
|
||||
|
||||
@ -7590,6 +7590,9 @@ ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, const ParsedAttr &AL,
|
||||
case ParsedAttr::AT_HLSLVkExtBuiltinInput:
|
||||
S.HLSL().handleVkExtBuiltinInputAttr(D, AL);
|
||||
break;
|
||||
case ParsedAttr::AT_HLSLVkConstantId:
|
||||
S.HLSL().handleVkConstantIdAttr(D, AL);
|
||||
break;
|
||||
case ParsedAttr::AT_HLSLSV_GroupThreadID:
|
||||
S.HLSL().handleSV_GroupThreadIDAttr(D, AL);
|
||||
break;
|
||||
|
||||
@ -119,6 +119,40 @@ static ResourceClass getResourceClass(RegisterType RT) {
|
||||
llvm_unreachable("unexpected RegisterType value");
|
||||
}
|
||||
|
||||
static Builtin::ID getSpecConstBuiltinId(QualType Type) {
|
||||
const auto *BT = dyn_cast<BuiltinType>(Type);
|
||||
if (!BT) {
|
||||
if (!Type->isEnumeralType())
|
||||
return Builtin::NotBuiltin;
|
||||
return Builtin::BI__builtin_get_spirv_spec_constant_int;
|
||||
}
|
||||
|
||||
switch (BT->getKind()) {
|
||||
case BuiltinType::Bool:
|
||||
return Builtin::BI__builtin_get_spirv_spec_constant_bool;
|
||||
case BuiltinType::Short:
|
||||
return Builtin::BI__builtin_get_spirv_spec_constant_short;
|
||||
case BuiltinType::Int:
|
||||
return Builtin::BI__builtin_get_spirv_spec_constant_int;
|
||||
case BuiltinType::LongLong:
|
||||
return Builtin::BI__builtin_get_spirv_spec_constant_longlong;
|
||||
case BuiltinType::UShort:
|
||||
return Builtin::BI__builtin_get_spirv_spec_constant_ushort;
|
||||
case BuiltinType::UInt:
|
||||
return Builtin::BI__builtin_get_spirv_spec_constant_uint;
|
||||
case BuiltinType::ULongLong:
|
||||
return Builtin::BI__builtin_get_spirv_spec_constant_ulonglong;
|
||||
case BuiltinType::Half:
|
||||
return Builtin::BI__builtin_get_spirv_spec_constant_half;
|
||||
case BuiltinType::Float:
|
||||
return Builtin::BI__builtin_get_spirv_spec_constant_float;
|
||||
case BuiltinType::Double:
|
||||
return Builtin::BI__builtin_get_spirv_spec_constant_double;
|
||||
default:
|
||||
return Builtin::NotBuiltin;
|
||||
}
|
||||
}
|
||||
|
||||
DeclBindingInfo *ResourceBindings::addDeclBindingInfo(const VarDecl *VD,
|
||||
ResourceClass ResClass) {
|
||||
assert(getDeclBindingInfo(VD, ResClass) == nullptr &&
|
||||
@ -607,6 +641,41 @@ HLSLWaveSizeAttr *SemaHLSL::mergeWaveSizeAttr(Decl *D,
|
||||
return Result;
|
||||
}
|
||||
|
||||
HLSLVkConstantIdAttr *
|
||||
SemaHLSL::mergeVkConstantIdAttr(Decl *D, const AttributeCommonInfo &AL,
|
||||
int Id) {
|
||||
|
||||
auto &TargetInfo = getASTContext().getTargetInfo();
|
||||
if (TargetInfo.getTriple().getArch() != llvm::Triple::spirv) {
|
||||
Diag(AL.getLoc(), diag::warn_attribute_ignored) << AL;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
auto *VD = cast<VarDecl>(D);
|
||||
|
||||
if (getSpecConstBuiltinId(VD->getType()) == Builtin::NotBuiltin) {
|
||||
Diag(VD->getLocation(), diag::err_specialization_const);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (!VD->getType().isConstQualified()) {
|
||||
Diag(VD->getLocation(), diag::err_specialization_const);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (HLSLVkConstantIdAttr *CI = D->getAttr<HLSLVkConstantIdAttr>()) {
|
||||
if (CI->getId() != Id) {
|
||||
Diag(CI->getLocation(), diag::err_hlsl_attribute_param_mismatch) << AL;
|
||||
Diag(AL.getLoc(), diag::note_conflicting_attribute);
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
HLSLVkConstantIdAttr *Result =
|
||||
::new (getASTContext()) HLSLVkConstantIdAttr(getASTContext(), AL, Id);
|
||||
return Result;
|
||||
}
|
||||
|
||||
HLSLShaderAttr *
|
||||
SemaHLSL::mergeShaderAttr(Decl *D, const AttributeCommonInfo &AL,
|
||||
llvm::Triple::EnvironmentType ShaderType) {
|
||||
@ -1157,6 +1226,15 @@ void SemaHLSL::handleVkExtBuiltinInputAttr(Decl *D, const ParsedAttr &AL) {
|
||||
HLSLVkExtBuiltinInputAttr(getASTContext(), AL, ID));
|
||||
}
|
||||
|
||||
void SemaHLSL::handleVkConstantIdAttr(Decl *D, const ParsedAttr &AL) {
|
||||
uint32_t Id;
|
||||
if (!SemaRef.checkUInt32Argument(AL, AL.getArgAsExpr(0), Id))
|
||||
return;
|
||||
HLSLVkConstantIdAttr *NewAttr = mergeVkConstantIdAttr(D, AL, Id);
|
||||
if (NewAttr)
|
||||
D->addAttr(NewAttr);
|
||||
}
|
||||
|
||||
bool SemaHLSL::diagnoseInputIDType(QualType T, const ParsedAttr &AL) {
|
||||
const auto *VT = T->getAs<VectorType>();
|
||||
|
||||
@ -3206,6 +3284,7 @@ static bool IsDefaultBufferConstantDecl(VarDecl *VD) {
|
||||
return VD->getDeclContext()->isTranslationUnit() &&
|
||||
QT.getAddressSpace() == LangAS::Default &&
|
||||
VD->getStorageClass() != SC_Static &&
|
||||
!VD->hasAttr<HLSLVkConstantIdAttr>() &&
|
||||
!isInvalidConstantBufferLeafElementType(QT.getTypePtr());
|
||||
}
|
||||
|
||||
@ -3273,7 +3352,8 @@ void SemaHLSL::ActOnVariableDeclarator(VarDecl *VD) {
|
||||
const Type *VarType = VD->getType().getTypePtr();
|
||||
while (VarType->isArrayType())
|
||||
VarType = VarType->getArrayElementTypeNoTypeQual();
|
||||
if (VarType->isHLSLResourceRecord()) {
|
||||
if (VarType->isHLSLResourceRecord() ||
|
||||
VD->hasAttr<HLSLVkConstantIdAttr>()) {
|
||||
// Make the variable for resources static. The global externally visible
|
||||
// storage is accessed through the handle, which is a member. The variable
|
||||
// itself is not externally visible.
|
||||
@ -3696,3 +3776,41 @@ bool SemaHLSL::transformInitList(const InitializedEntity &Entity,
|
||||
Init->updateInit(Ctx, I, NewInit->getInit(I));
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SemaHLSL::handleInitialization(VarDecl *VDecl, Expr *&Init) {
|
||||
const HLSLVkConstantIdAttr *ConstIdAttr =
|
||||
VDecl->getAttr<HLSLVkConstantIdAttr>();
|
||||
if (!ConstIdAttr)
|
||||
return true;
|
||||
|
||||
ASTContext &Context = SemaRef.getASTContext();
|
||||
|
||||
APValue InitValue;
|
||||
if (!Init->isCXX11ConstantExpr(Context, &InitValue)) {
|
||||
Diag(VDecl->getLocation(), diag::err_specialization_const);
|
||||
VDecl->setInvalidDecl();
|
||||
return false;
|
||||
}
|
||||
|
||||
Builtin::ID BID = getSpecConstBuiltinId(VDecl->getType());
|
||||
|
||||
// Argument 1: The ID from the attribute
|
||||
int ConstantID = ConstIdAttr->getId();
|
||||
llvm::APInt IDVal(Context.getIntWidth(Context.IntTy), ConstantID);
|
||||
Expr *IdExpr = IntegerLiteral::Create(Context, IDVal, Context.IntTy,
|
||||
ConstIdAttr->getLocation());
|
||||
|
||||
SmallVector<Expr *, 2> Args = {IdExpr, Init};
|
||||
Expr *C = SemaRef.BuildBuiltinCallExpr(Init->getExprLoc(), BID, Args);
|
||||
if (C->getType()->getCanonicalTypeUnqualified() !=
|
||||
VDecl->getType()->getCanonicalTypeUnqualified()) {
|
||||
C = SemaRef
|
||||
.BuildCStyleCastExpr(SourceLocation(),
|
||||
Context.getTrivialTypeSourceInfo(
|
||||
Init->getType(), Init->getExprLoc()),
|
||||
SourceLocation(), C)
|
||||
.get();
|
||||
}
|
||||
Init = C;
|
||||
return true;
|
||||
}
|
||||
|
||||
130
clang/test/AST/HLSL/vk.spec-constant.usage.hlsl
Normal file
130
clang/test/AST/HLSL/vk.spec-constant.usage.hlsl
Normal file
@ -0,0 +1,130 @@
|
||||
// RUN: %clang_cc1 -finclude-default-header -triple spirv-unknown-vulkan-compute -x hlsl -ast-dump -o - %s | FileCheck %s
|
||||
|
||||
// CHECK: VarDecl {{.*}} bool_const 'const hlsl_private bool' static cinit
|
||||
// CHECK-NEXT: CallExpr {{.*}} 'bool'
|
||||
// CHECK-NEXT: ImplicitCastExpr {{.*}} 'bool (*)(unsigned int, bool) noexcept' <FunctionToPointerDecay>
|
||||
// CHECK-NEXT: DeclRefExpr {{.*}} 'bool (unsigned int, bool) noexcept' lvalue Function {{.*}} '__builtin_get_spirv_spec_constant_bool' 'bool (unsigned int, bool) noexcept'
|
||||
// CHECK-NEXT: ImplicitCastExpr {{.*}} 'unsigned int' <IntegralCast>
|
||||
// CHECK-NEXT: IntegerLiteral {{.*}} 'int' 1
|
||||
// CHECK-NEXT: CXXBoolLiteralExpr {{.*}} 'bool' true
|
||||
[[vk::constant_id(1)]]
|
||||
const bool bool_const = true;
|
||||
|
||||
// CHECK: VarDecl {{.*}} short_const 'const hlsl_private short' static cinit
|
||||
// CHECK-NEXT: CallExpr {{.*}} 'short'
|
||||
// CHECK-NEXT: ImplicitCastExpr {{.*}} 'short (*)(unsigned int, short) noexcept' <FunctionToPointerDecay>
|
||||
// CHECK-NEXT: DeclRefExpr {{.*}} 'short (unsigned int, short) noexcept' lvalue Function {{.*}} '__builtin_get_spirv_spec_constant_short' 'short (unsigned int, short) noexcept'
|
||||
// CHECK-NEXT: ImplicitCastExpr {{.*}} 'unsigned int' <IntegralCast>
|
||||
// CHECK-NEXT: IntegerLiteral {{.*}} 'int' 2
|
||||
// CHECK-NEXT: ImplicitCastExpr {{.*}} 'short' <IntegralCast>
|
||||
// CHECK-NEXT: IntegerLiteral {{.*}} 'int' 4
|
||||
[[vk::constant_id(2)]]
|
||||
const short short_const = 4;
|
||||
|
||||
// CHECK: VarDecl {{.*}} int_const 'const hlsl_private int' static cinit
|
||||
// CHECK-NEXT: CallExpr {{.*}} 'int'
|
||||
// CHECK-NEXT: ImplicitCastExpr {{.*}} 'int (*)(unsigned int, int) noexcept' <FunctionToPointerDecay>
|
||||
// CHECK-NEXT: DeclRefExpr {{.*}} 'int (unsigned int, int) noexcept' lvalue Function {{.*}} '__builtin_get_spirv_spec_constant_int' 'int (unsigned int, int) noexcept'
|
||||
// CHECK-NEXT: ImplicitCastExpr {{.*}} 'unsigned int' <IntegralCast>
|
||||
// CHECK-NEXT: IntegerLiteral {{.*}} 'int' 3
|
||||
// CHECK-NEXT: IntegerLiteral {{.*}} 'int' 5
|
||||
[[vk::constant_id(3)]]
|
||||
const int int_const = 5;
|
||||
|
||||
// CHECK: VarDecl {{.*}} long_const 'const hlsl_private long long' static cinit
|
||||
// CHECK-NEXT: CallExpr {{.*}} 'long long'
|
||||
// CHECK-NEXT: ImplicitCastExpr {{.*}} 'long long (*)(unsigned int, long long) noexcept' <FunctionToPointerDecay>
|
||||
// CHECK-NEXT: DeclRefExpr {{.*}} 'long long (unsigned int, long long) noexcept' lvalue Function {{.*}} '__builtin_get_spirv_spec_constant_longlong' 'long long (unsigned int, long long) noexcept'
|
||||
// CHECK-NEXT: ImplicitCastExpr {{.*}} 'unsigned int' <IntegralCast>
|
||||
// CHECK-NEXT: IntegerLiteral {{.*}} 'int' 4
|
||||
// CHECK-NEXT: ImplicitCastExpr {{.*}} 'long long' <IntegralCast>
|
||||
// CHECK-NEXT: IntegerLiteral {{.*}} 'int' 8
|
||||
[[vk::constant_id(4)]]
|
||||
const long long long_const = 8;
|
||||
|
||||
// CHECK: VarDecl {{.*}} ushort_const 'const hlsl_private unsigned short' static cinit
|
||||
// CHECK-NEXT: CallExpr {{.*}} 'unsigned short'
|
||||
// CHECK-NEXT: ImplicitCastExpr {{.*}} 'unsigned short (*)(unsigned int, unsigned short) noexcept' <FunctionToPointerDecay>
|
||||
// CHECK-NEXT: DeclRefExpr {{.*}} 'unsigned short (unsigned int, unsigned short) noexcept' lvalue Function {{.*}} '__builtin_get_spirv_spec_constant_ushort' 'unsigned short (unsigned int, unsigned short) noexcept'
|
||||
// CHECK-NEXT: ImplicitCastExpr {{.*}} 'unsigned int' <IntegralCast>
|
||||
// CHECK-NEXT: IntegerLiteral {{.*}} 'int' 5
|
||||
// CHECK-NEXT: ImplicitCastExpr {{.*}} 'unsigned short' <IntegralCast>
|
||||
// CHECK-NEXT: IntegerLiteral {{.*}} 'int' 10
|
||||
[[vk::constant_id(5)]]
|
||||
const unsigned short ushort_const = 10;
|
||||
|
||||
// CHECK: VarDecl {{.*}} uint_const 'const hlsl_private unsigned int' static cinit
|
||||
// CHECK-NEXT: CallExpr {{.*}} 'unsigned int'
|
||||
// CHECK-NEXT: ImplicitCastExpr {{.*}} 'unsigned int (*)(unsigned int, unsigned int) noexcept' <FunctionToPointerDecay>
|
||||
// CHECK-NEXT: DeclRefExpr {{.*}} 'unsigned int (unsigned int, unsigned int) noexcept' lvalue Function {{.*}} '__builtin_get_spirv_spec_constant_uint' 'unsigned int (unsigned int, unsigned int) noexcept'
|
||||
// CHECK-NEXT: ImplicitCastExpr {{.*}} 'unsigned int' <IntegralCast>
|
||||
// CHECK-NEXT: IntegerLiteral {{.*}} 'int' 6
|
||||
// CHECK-NEXT: ImplicitCastExpr {{.*}} 'unsigned int' <IntegralCast>
|
||||
// CHECK-NEXT: IntegerLiteral {{.*}} 'int' 12
|
||||
[[vk::constant_id(6)]]
|
||||
const unsigned int uint_const = 12;
|
||||
|
||||
|
||||
// CHECK: VarDecl {{.*}} ulong_const 'const hlsl_private unsigned long long' static cinit
|
||||
// CHECK-NEXT: CallExpr {{.*}} 'unsigned long long'
|
||||
// CHECK-NEXT: ImplicitCastExpr {{.*}} 'unsigned long long (*)(unsigned int, unsigned long long) noexcept' <FunctionToPointerDecay>
|
||||
// CHECK-NEXT: DeclRefExpr {{.*}} 'unsigned long long (unsigned int, unsigned long long) noexcept' lvalue Function {{.*}} '__builtin_get_spirv_spec_constant_ulonglong' 'unsigned long long (unsigned int, unsigned long long) noexcept'
|
||||
// CHECK-NEXT: ImplicitCastExpr {{.*}} 'unsigned int' <IntegralCast>
|
||||
// CHECK-NEXT: IntegerLiteral {{.*}} 'int' 7
|
||||
// CHECK-NEXT: ImplicitCastExpr {{.*}} 'unsigned long long' <IntegralCast>
|
||||
// CHECK-NEXT: IntegerLiteral {{.*}} 'int' 25
|
||||
[[vk::constant_id(7)]]
|
||||
const unsigned long long ulong_const = 25;
|
||||
|
||||
// CHECK: VarDecl {{.*}} half_const 'const hlsl_private half' static cinit
|
||||
// CHECK-NEXT: CallExpr {{.*}} 'half'
|
||||
// CHECK-NEXT: ImplicitCastExpr {{.*}} 'half (*)(unsigned int, half) noexcept' <FunctionToPointerDecay>
|
||||
// CHECK-NEXT: DeclRefExpr {{.*}} 'half (unsigned int, half) noexcept' lvalue Function {{.*}} '__builtin_get_spirv_spec_constant_half' 'half (unsigned int, half) noexcept'
|
||||
// CHECK-NEXT: ImplicitCastExpr {{.*}} 'unsigned int' <IntegralCast>
|
||||
// CHECK-NEXT: IntegerLiteral {{.*}} 'int' 8
|
||||
// CHECK-NEXT: ImplicitCastExpr {{.*}} 'half' <FloatingCast>
|
||||
// CHECK-NEXT: FloatingLiteral {{.*}} 'float' 4.040000e+01
|
||||
[[vk::constant_id(8)]]
|
||||
const half half_const = 40.4;
|
||||
|
||||
// CHECK: VarDecl {{.*}} float_const 'const hlsl_private float' static cinit
|
||||
// CHECK-NEXT: CallExpr {{.*}} 'float'
|
||||
// CHECK-NEXT: ImplicitCastExpr {{.*}} 'float (*)(unsigned int, float) noexcept' <FunctionToPointerDecay>
|
||||
// CHECK-NEXT: DeclRefExpr {{.*}} 'float (unsigned int, float) noexcept' lvalue Function {{.*}} '__builtin_get_spirv_spec_constant_float' 'float (unsigned int, float) noexcept'
|
||||
// CHECK-NEXT: ImplicitCastExpr {{.*}} 'unsigned int' <IntegralCast>
|
||||
// CHECK-NEXT: IntegerLiteral {{.*}} 'int' 8
|
||||
// CHECK-NEXT: ImplicitCastExpr {{.*}} 'float' <IntegralToFloating>
|
||||
// CHECK-NEXT: IntegerLiteral {{.*}} 'int' 50
|
||||
[[vk::constant_id(8)]]
|
||||
const float float_const = 50;
|
||||
|
||||
// CHECK: VarDecl {{.*}} double_const 'const hlsl_private double' static cinit
|
||||
// CHECK-NEXT: CallExpr {{.*}} 'double'
|
||||
// CHECK-NEXT: ImplicitCastExpr {{.*}} 'double (*)(unsigned int, double) noexcept' <FunctionToPointerDecay>
|
||||
// CHECK-NEXT: DeclRefExpr {{.*}} 'double (unsigned int, double) noexcept' lvalue Function {{.*}} '__builtin_get_spirv_spec_constant_double' 'double (unsigned int, double) noexcept'
|
||||
// CHECK-NEXT: ImplicitCastExpr {{.*}} 'unsigned int' <IntegralCast>
|
||||
// CHECK-NEXT: IntegerLiteral {{.*}} 'int' 9
|
||||
// CHECK-NEXT: ImplicitCastExpr {{.*}} 'double' <IntegralToFloating>
|
||||
// CHECK-NEXT: IntegerLiteral {{.*}} 'int' 100
|
||||
[[vk::constant_id(9)]]
|
||||
const double double_const = 100;
|
||||
|
||||
// CHECK: VarDecl {{.*}} enum_const 'const hlsl_private E' static cinit
|
||||
// CHECK-NEXT: CStyleCastExpr {{.*}} 'E' <IntegralCast>
|
||||
// CHECK-NEXT: CallExpr {{.*}} 'int'
|
||||
// CHECK-NEXT: ImplicitCastExpr {{.*}} 'int (*)(unsigned int, int) noexcept' <FunctionToPointerDecay>
|
||||
// CHECK-NEXT: DeclRefExpr {{.*}} 'int (unsigned int, int) noexcept' lvalue Function {{.*}} '__builtin_get_spirv_spec_constant_int' 'int (unsigned int, int) noexcept'
|
||||
// CHECK-NEXT: ImplicitCastExpr {{.*}} 'unsigned int' <IntegralCast>
|
||||
// CHECK-NEXT: IntegerLiteral {{.*}} 'int' 10
|
||||
// CHECK-NEXT: ImplicitCastExpr {{.*}} 'int' <IntegralCast>
|
||||
// CHECK-NEXT: DeclRefExpr {{.*}} 'E' EnumConstant {{.*}} 'e2' 'E'
|
||||
enum E {
|
||||
e0 = 10,
|
||||
e1 = 20,
|
||||
e2 = 30
|
||||
};
|
||||
|
||||
[[vk::constant_id(10)]]
|
||||
const E enum_const = e2;
|
||||
|
||||
// CHECK-NOT: CXXRecordDecl {{.*}} implicit struct __cblayout_$Globals definition
|
||||
210
clang/test/CodeGenHLSL/vk-features/vk.spec-constant.hlsl
Normal file
210
clang/test/CodeGenHLSL/vk-features/vk.spec-constant.hlsl
Normal file
@ -0,0 +1,210 @@
|
||||
// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py UTC_ARGS: --check-globals all --include-generated-funcs --version 5
|
||||
// RUN: %clang_cc1 -finclude-default-header -x hlsl -triple \
|
||||
// RUN: spirv-unknown-vulkan-compute %s -emit-llvm -disable-llvm-passes \
|
||||
// RUN: -o - | FileCheck %s
|
||||
|
||||
[[vk::constant_id(1)]]
|
||||
const bool bool_const = true;
|
||||
|
||||
[[vk::constant_id(1)]]
|
||||
const short short_const = 4;
|
||||
|
||||
[[vk::constant_id(3)]]
|
||||
const int int_const = 5;
|
||||
|
||||
[[vk::constant_id(4)]]
|
||||
const long long long_const = 8;
|
||||
|
||||
[[vk::constant_id(5)]]
|
||||
const unsigned short ushort_const = 10;
|
||||
|
||||
[[vk::constant_id(6)]]
|
||||
const unsigned int uint_const = 12;
|
||||
|
||||
[[vk::constant_id(7)]]
|
||||
const unsigned long long ulong_const = 25;
|
||||
|
||||
[[vk::constant_id(8)]]
|
||||
const half half_const = 40.4;
|
||||
|
||||
[[vk::constant_id(8)]]
|
||||
const float float_const = 50.5;
|
||||
|
||||
[[vk::constant_id(9)]]
|
||||
const double double_const = 100.2;
|
||||
|
||||
enum E {
|
||||
e0 = 10,
|
||||
e1 = 20,
|
||||
e2 = 30
|
||||
};
|
||||
|
||||
[[vk::constant_id(10)]]
|
||||
const E enum_const = e2;
|
||||
|
||||
[numthreads(1,1,1)]
|
||||
void main() {
|
||||
bool b = bool_const;
|
||||
short s = short_const;
|
||||
int i = int_const;
|
||||
long long l = long_const;
|
||||
unsigned short us = ushort_const;
|
||||
unsigned int ui = uint_const;
|
||||
unsigned long long ul = ulong_const;
|
||||
half h = half_const;
|
||||
float f = float_const;
|
||||
double d = double_const;
|
||||
E e = enum_const;
|
||||
}
|
||||
//.
|
||||
// CHECK: @_ZL10bool_const = internal addrspace(10) global i32 0, align 4
|
||||
// CHECK: @_ZL11short_const = internal addrspace(10) global i16 0, align 2
|
||||
// CHECK: @_ZL9int_const = internal addrspace(10) global i32 0, align 4
|
||||
// CHECK: @_ZL10long_const = internal addrspace(10) global i64 0, align 8
|
||||
// CHECK: @_ZL12ushort_const = internal addrspace(10) global i16 0, align 2
|
||||
// CHECK: @_ZL10uint_const = internal addrspace(10) global i32 0, align 4
|
||||
// CHECK: @_ZL11ulong_const = internal addrspace(10) global i64 0, align 8
|
||||
// CHECK: @_ZL10half_const = internal addrspace(10) global float 0.000000e+00, align 4
|
||||
// CHECK: @_ZL11float_const = internal addrspace(10) global float 0.000000e+00, align 4
|
||||
// CHECK: @_ZL12double_const = internal addrspace(10) global double 0.000000e+00, align 8
|
||||
// CHECK: @_ZL10enum_const = internal addrspace(10) global i32 0, align 4
|
||||
//.
|
||||
// CHECK-LABEL: define internal spir_func void @_Z4mainv(
|
||||
// CHECK-SAME: ) #[[ATTR0:[0-9]+]] {
|
||||
// CHECK-NEXT: [[ENTRY:.*:]]
|
||||
// CHECK-NEXT: [[TMP0:%.*]] = call token @llvm.experimental.convergence.entry()
|
||||
// CHECK-NEXT: [[B:%.*]] = alloca i32, align 4
|
||||
// CHECK-NEXT: [[S:%.*]] = alloca i16, align 2
|
||||
// CHECK-NEXT: [[I:%.*]] = alloca i32, align 4
|
||||
// CHECK-NEXT: [[L:%.*]] = alloca i64, align 8
|
||||
// CHECK-NEXT: [[US:%.*]] = alloca i16, align 2
|
||||
// CHECK-NEXT: [[UI:%.*]] = alloca i32, align 4
|
||||
// CHECK-NEXT: [[UL:%.*]] = alloca i64, align 8
|
||||
// CHECK-NEXT: [[H:%.*]] = alloca float, align 4
|
||||
// CHECK-NEXT: [[F:%.*]] = alloca float, align 4
|
||||
// CHECK-NEXT: [[D:%.*]] = alloca double, align 8
|
||||
// CHECK-NEXT: [[E:%.*]] = alloca i32, align 4
|
||||
// CHECK-NEXT: [[TMP1:%.*]] = load i32, ptr addrspace(10) @_ZL10bool_const, align 4
|
||||
// CHECK-NEXT: [[LOADEDV:%.*]] = trunc i32 [[TMP1]] to i1
|
||||
// CHECK-NEXT: [[STOREDV:%.*]] = zext i1 [[LOADEDV]] to i32
|
||||
// CHECK-NEXT: store i32 [[STOREDV]], ptr [[B]], align 4
|
||||
// CHECK-NEXT: [[TMP2:%.*]] = load i16, ptr addrspace(10) @_ZL11short_const, align 2
|
||||
// CHECK-NEXT: store i16 [[TMP2]], ptr [[S]], align 2
|
||||
// CHECK-NEXT: [[TMP3:%.*]] = load i32, ptr addrspace(10) @_ZL9int_const, align 4
|
||||
// CHECK-NEXT: store i32 [[TMP3]], ptr [[I]], align 4
|
||||
// CHECK-NEXT: [[TMP4:%.*]] = load i64, ptr addrspace(10) @_ZL10long_const, align 8
|
||||
// CHECK-NEXT: store i64 [[TMP4]], ptr [[L]], align 8
|
||||
// CHECK-NEXT: [[TMP5:%.*]] = load i16, ptr addrspace(10) @_ZL12ushort_const, align 2
|
||||
// CHECK-NEXT: store i16 [[TMP5]], ptr [[US]], align 2
|
||||
// CHECK-NEXT: [[TMP6:%.*]] = load i32, ptr addrspace(10) @_ZL10uint_const, align 4
|
||||
// CHECK-NEXT: store i32 [[TMP6]], ptr [[UI]], align 4
|
||||
// CHECK-NEXT: [[TMP7:%.*]] = load i64, ptr addrspace(10) @_ZL11ulong_const, align 8
|
||||
// CHECK-NEXT: store i64 [[TMP7]], ptr [[UL]], align 8
|
||||
// CHECK-NEXT: [[TMP8:%.*]] = load float, ptr addrspace(10) @_ZL10half_const, align 4
|
||||
// CHECK-NEXT: store float [[TMP8]], ptr [[H]], align 4
|
||||
// CHECK-NEXT: [[TMP9:%.*]] = load float, ptr addrspace(10) @_ZL11float_const, align 4
|
||||
// CHECK-NEXT: store float [[TMP9]], ptr [[F]], align 4
|
||||
// CHECK-NEXT: [[TMP10:%.*]] = load double, ptr addrspace(10) @_ZL12double_const, align 8
|
||||
// CHECK-NEXT: store double [[TMP10]], ptr [[D]], align 8
|
||||
// CHECK-NEXT: [[TMP11:%.*]] = load i32, ptr addrspace(10) @_ZL10enum_const, align 4
|
||||
// CHECK-NEXT: store i32 [[TMP11]], ptr [[E]], align 4
|
||||
// CHECK-NEXT: ret void
|
||||
//
|
||||
// CHECK-LABEL: define internal spir_func void @__cxx_global_var_init(
|
||||
// CHECK-SAME: ) #[[ATTR3:[0-9]+]] {
|
||||
// CHECK-NEXT: [[ENTRY:.*:]]
|
||||
// CHECK-NEXT: [[TMP0:%.*]] = call token @llvm.experimental.convergence.entry()
|
||||
// CHECK-NEXT: [[TMP1:%.*]] = call i1 @_Z20__spirv_SpecConstantib(i32 1, i1 true)
|
||||
// CHECK-NEXT: [[STOREDV:%.*]] = zext i1 [[TMP1]] to i32
|
||||
// CHECK-NEXT: store i32 [[STOREDV]], ptr addrspace(10) @_ZL10bool_const, align 4
|
||||
// CHECK-NEXT: ret void
|
||||
//
|
||||
//
|
||||
// CHECK-LABEL: define internal spir_func void @__cxx_global_var_init.1(
|
||||
// CHECK-SAME: ) #[[ATTR3]] {
|
||||
// CHECK-NEXT: [[ENTRY:.*:]]
|
||||
// CHECK-NEXT: [[TMP0:%.*]] = call token @llvm.experimental.convergence.entry()
|
||||
// CHECK-NEXT: [[TMP1:%.*]] = call i16 @_Z20__spirv_SpecConstantis(i32 1, i16 4)
|
||||
// CHECK-NEXT: store i16 [[TMP1]], ptr addrspace(10) @_ZL11short_const, align 2
|
||||
// CHECK-NEXT: ret void
|
||||
//
|
||||
//
|
||||
// CHECK-LABEL: define internal spir_func void @__cxx_global_var_init.2(
|
||||
// CHECK-SAME: ) #[[ATTR3]] {
|
||||
// CHECK-NEXT: [[ENTRY:.*:]]
|
||||
// CHECK-NEXT: [[TMP0:%.*]] = call token @llvm.experimental.convergence.entry()
|
||||
// CHECK-NEXT: [[TMP1:%.*]] = call i32 @_Z20__spirv_SpecConstantii(i32 3, i32 5)
|
||||
// CHECK-NEXT: store i32 [[TMP1]], ptr addrspace(10) @_ZL9int_const, align 4
|
||||
// CHECK-NEXT: ret void
|
||||
//
|
||||
//
|
||||
// CHECK-LABEL: define internal spir_func void @__cxx_global_var_init.3(
|
||||
// CHECK-SAME: ) #[[ATTR3]] {
|
||||
// CHECK-NEXT: [[ENTRY:.*:]]
|
||||
// CHECK-NEXT: [[TMP0:%.*]] = call token @llvm.experimental.convergence.entry()
|
||||
// CHECK-NEXT: [[TMP1:%.*]] = call i64 @_Z20__spirv_SpecConstantix(i32 4, i64 8)
|
||||
// CHECK-NEXT: store i64 [[TMP1]], ptr addrspace(10) @_ZL10long_const, align 8
|
||||
// CHECK-NEXT: ret void
|
||||
//
|
||||
//
|
||||
// CHECK-LABEL: define internal spir_func void @__cxx_global_var_init.4(
|
||||
// CHECK-SAME: ) #[[ATTR3]] {
|
||||
// CHECK-NEXT: [[ENTRY:.*:]]
|
||||
// CHECK-NEXT: [[TMP0:%.*]] = call token @llvm.experimental.convergence.entry()
|
||||
// CHECK-NEXT: [[TMP1:%.*]] = call i16 @_Z20__spirv_SpecConstantit(i32 5, i16 10)
|
||||
// CHECK-NEXT: store i16 [[TMP1]], ptr addrspace(10) @_ZL12ushort_const, align 2
|
||||
// CHECK-NEXT: ret void
|
||||
//
|
||||
//
|
||||
// CHECK-LABEL: define internal spir_func void @__cxx_global_var_init.5(
|
||||
// CHECK-SAME: ) #[[ATTR3]] {
|
||||
// CHECK-NEXT: [[ENTRY:.*:]]
|
||||
// CHECK-NEXT: [[TMP0:%.*]] = call token @llvm.experimental.convergence.entry()
|
||||
// CHECK-NEXT: [[TMP1:%.*]] = call i32 @_Z20__spirv_SpecConstantij(i32 6, i32 12)
|
||||
// CHECK-NEXT: store i32 [[TMP1]], ptr addrspace(10) @_ZL10uint_const, align 4
|
||||
// CHECK-NEXT: ret void
|
||||
//
|
||||
//
|
||||
// CHECK-LABEL: define internal spir_func void @__cxx_global_var_init.6(
|
||||
// CHECK-SAME: ) #[[ATTR3]] {
|
||||
// CHECK-NEXT: [[ENTRY:.*:]]
|
||||
// CHECK-NEXT: [[TMP0:%.*]] = call token @llvm.experimental.convergence.entry()
|
||||
// CHECK-NEXT: [[TMP1:%.*]] = call i64 @_Z20__spirv_SpecConstantiy(i32 7, i64 25)
|
||||
// CHECK-NEXT: store i64 [[TMP1]], ptr addrspace(10) @_ZL11ulong_const, align 8
|
||||
// CHECK-NEXT: ret void
|
||||
//
|
||||
//
|
||||
// CHECK-LABEL: define internal spir_func void @__cxx_global_var_init.7(
|
||||
// CHECK-SAME: ) #[[ATTR3]] {
|
||||
// CHECK-NEXT: [[ENTRY:.*:]]
|
||||
// CHECK-NEXT: [[TMP0:%.*]] = call token @llvm.experimental.convergence.entry()
|
||||
// CHECK-NEXT: [[TMP1:%.*]] = call reassoc nnan ninf nsz arcp afn float @_Z20__spirv_SpecConstantiDh(i32 8, float 0x4044333340000000)
|
||||
// CHECK-NEXT: store float [[TMP1]], ptr addrspace(10) @_ZL10half_const, align 4
|
||||
// CHECK-NEXT: ret void
|
||||
//
|
||||
//
|
||||
// CHECK-LABEL: define internal spir_func void @__cxx_global_var_init.8(
|
||||
// CHECK-SAME: ) #[[ATTR3]] {
|
||||
// CHECK-NEXT: [[ENTRY:.*:]]
|
||||
// CHECK-NEXT: [[TMP0:%.*]] = call token @llvm.experimental.convergence.entry()
|
||||
// CHECK-NEXT: [[TMP1:%.*]] = call reassoc nnan ninf nsz arcp afn float @_Z20__spirv_SpecConstantif(i32 8, float 5.050000e+01)
|
||||
// CHECK-NEXT: store float [[TMP1]], ptr addrspace(10) @_ZL11float_const, align 4
|
||||
// CHECK-NEXT: ret void
|
||||
//
|
||||
//
|
||||
// CHECK-LABEL: define internal spir_func void @__cxx_global_var_init.9(
|
||||
// CHECK-SAME: ) #[[ATTR3]] {
|
||||
// CHECK-NEXT: [[ENTRY:.*:]]
|
||||
// CHECK-NEXT: [[TMP0:%.*]] = call token @llvm.experimental.convergence.entry()
|
||||
// CHECK-NEXT: [[TMP1:%.*]] = call reassoc nnan ninf nsz arcp afn double @_Z20__spirv_SpecConstantid(i32 9, double 0x40590CCCC0000000)
|
||||
// CHECK-NEXT: store double [[TMP1]], ptr addrspace(10) @_ZL12double_const, align 8
|
||||
// CHECK-NEXT: ret void
|
||||
//
|
||||
//
|
||||
// CHECK-LABEL: define internal spir_func void @__cxx_global_var_init.10(
|
||||
// CHECK-SAME: ) #[[ATTR3]] {
|
||||
// CHECK-NEXT: [[ENTRY:.*:]]
|
||||
// CHECK-NEXT: [[TMP0:%.*]] = call token @llvm.experimental.convergence.entry()
|
||||
// CHECK-NEXT: [[TMP1:%.*]] = call i32 @_Z20__spirv_SpecConstantii(i32 10, i32 30)
|
||||
// CHECK-NEXT: store i32 [[TMP1]], ptr addrspace(10) @_ZL10enum_const, align 4
|
||||
// CHECK-NEXT: ret void
|
||||
37
clang/test/SemaHLSL/vk.spec-constant.error.hlsl
Normal file
37
clang/test/SemaHLSL/vk.spec-constant.error.hlsl
Normal file
@ -0,0 +1,37 @@
|
||||
// RUN: %clang_cc1 -finclude-default-header -triple spirv-pc-vulkan1.3-compute -verify %s
|
||||
// RUN: %clang_cc1 -finclude-default-header -triple dxil-pc-shadermodel6.8-compute -verify %s
|
||||
|
||||
#ifndef __spirv__
|
||||
// expected-warning@+2{{'constant_id' attribute ignored}}
|
||||
#endif
|
||||
[[vk::constant_id(0)]]
|
||||
const bool sc0 = true;
|
||||
|
||||
#ifdef __spirv__
|
||||
// expected-error@+2{{variable with 'vk::constant_id' attribute must be a const int/float/enum/bool and be initialized with a literal}}
|
||||
[[vk::constant_id(1)]]
|
||||
const bool sc1 = sc0; // error
|
||||
|
||||
// expected-warning@+1{{'constant_id' attribute only applies to external global variables}}
|
||||
[[vk::constant_id(2)]]
|
||||
static const bool sc2 = false; // error
|
||||
|
||||
// expected-error@+2{{variable with 'vk::constant_id' attribute must be a const int/float/enum/bool and be initialized with a literal}}
|
||||
[[vk::constant_id(3)]]
|
||||
const bool sc3; // error
|
||||
|
||||
// expected-error@+2{{variable with 'vk::constant_id' attribute must be a const int/float/enum/bool and be initialized with a literal}}
|
||||
[[vk::constant_id(4)]]
|
||||
bool sc4 = false; // error
|
||||
|
||||
// expected-error@+2{{variable with 'vk::constant_id' attribute must be a const int/float/enum/bool and be initialized with a literal}}
|
||||
[[vk::constant_id(5)]]
|
||||
const int2 sc5 = {0,0}; // error
|
||||
|
||||
[numthreads(1,1,1)]
|
||||
void main() {
|
||||
// expected-warning@+1{{'constant_id' attribute only applies to external global variables}}
|
||||
[[vk::constant_id(6)]]
|
||||
const bool sc6 = false; // error
|
||||
}
|
||||
#endif
|
||||
Loading…
x
Reference in New Issue
Block a user