Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[spirv] support vk::ext_execution_mode_id(..) #4190

Merged
merged 4 commits into from
Jan 21, 2022
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions include/dxc/HlslIntrinsicOp.h
Original file line number Diff line number Diff line change
Expand Up @@ -229,6 +229,9 @@ enum class IntrinsicOp { IOP_AcceptHitAndEndSearch,
#endif // ENABLE_SPIRV_CODEGEN
#ifdef ENABLE_SPIRV_CODEGEN
IOP_Vkext_execution_mode,
#endif // ENABLE_SPIRV_CODEGEN
#ifdef ENABLE_SPIRV_CODEGEN
IOP_Vkext_execution_mode_id,
#endif // ENABLE_SPIRV_CODEGEN
MOP_Append,
MOP_RestartStrip,
Expand Down
1 change: 1 addition & 0 deletions lib/HLSL/HLOperationLower.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5663,6 +5663,7 @@ IntrinsicLower gLowerTable[] = {
{ IntrinsicOp::IOP_VkReadClock, UnsupportedVulkanIntrinsic, DXIL::OpCode::NumOpCodes },
{ IntrinsicOp::IOP_VkRawBufferLoad, UnsupportedVulkanIntrinsic, DXIL::OpCode::NumOpCodes },
{ IntrinsicOp::IOP_Vkext_execution_mode, UnsupportedVulkanIntrinsic, DXIL::OpCode::NumOpCodes },
{ IntrinsicOp::IOP_Vkext_execution_mode_id, UnsupportedVulkanIntrinsic, DXIL::OpCode::NumOpCodes },
#endif // ENABLE_SPIRV_CODEGEN
{IntrinsicOp::MOP_Append, StreamOutputLower, DXIL::OpCode::EmitStream},
{IntrinsicOp::MOP_RestartStrip, StreamOutputLower, DXIL::OpCode::CutStream},
Expand Down
9 changes: 5 additions & 4 deletions tools/clang/include/clang/SPIRV/SpirvBuilder.h
Original file line number Diff line number Diff line change
Expand Up @@ -585,7 +585,8 @@ class SpirvBuilder {
inline SpirvInstruction *addExecutionMode(SpirvFunction *entryPoint,
spv::ExecutionMode em,
llvm::ArrayRef<uint32_t> params,
SourceLocation);
SourceLocation,
bool useIdParams = false);

/// \brief Adds an OpModuleProcessed instruction to the module under
/// construction.
Expand Down Expand Up @@ -888,9 +889,9 @@ SpirvBuilder::setDebugSource(uint32_t major, uint32_t minor,
SpirvInstruction *
SpirvBuilder::addExecutionMode(SpirvFunction *entryPoint, spv::ExecutionMode em,
llvm::ArrayRef<uint32_t> params,
SourceLocation loc) {
auto mode =
new (context) SpirvExecutionMode(loc, entryPoint, em, params, false);
SourceLocation loc, bool useIdParams) {
auto mode = new (context)
SpirvExecutionMode(loc, entryPoint, em, params, useIdParams);
mod->addExecutionMode(mode);

return mode;
Expand Down
12 changes: 10 additions & 2 deletions tools/clang/lib/SPIRV/EmitVisitor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -587,8 +587,16 @@ bool EmitVisitor::visit(SpirvExecutionMode *inst) {
initInstruction(inst);
curInst.push_back(getOrAssignResultId<SpirvFunction>(inst->getEntryPoint()));
curInst.push_back(static_cast<uint32_t>(inst->getExecutionMode()));
curInst.insert(curInst.end(), inst->getParams().begin(),
inst->getParams().end());
if (inst->getopcode() == spv::Op::OpExecutionMode) {
curInst.insert(curInst.end(), inst->getParams().begin(),
inst->getParams().end());
} else {
for (uint32_t param : inst->getParams()) {
curInst.push_back(typeHandler.getOrCreateConstantInt(
llvm::APInt(32, param), context.getUIntType(32),
/*isSpecConst */ false));
}
}
finalizeInstruction(&preambleBinary);
return true;
}
Expand Down
113 changes: 62 additions & 51 deletions tools/clang/lib/SPIRV/SpirvEmitter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -924,11 +924,21 @@ void SpirvEmitter::doStmt(const Stmt *stmt,
doForStmt(forStmt, attrs);
} else if (dyn_cast<NullStmt>(stmt)) {
// For the null statement ";". We don't need to do anything.
} else if (const auto *expr = dyn_cast<Expr>(stmt)) {
// All cases for expressions used as statements
doExpr(expr);
} else if (const auto *attrStmt = dyn_cast<AttributedStmt>(stmt)) {
doStmt(attrStmt->getSubStmt(), attrStmt->getAttrs());
} else if (const auto *expr = dyn_cast<Expr>(stmt)) {
// All cases for expressions used as statements
SpirvInstruction *result = doExpr(expr);

if (result && result->getKind() == SpirvInstruction::IK_ExecutionMode &&
!attrs.empty()) {
// Handle [[vk::ext_capability(..)]] and [[vk::ext_extension(..)]]
// attributes for vk::ext_execution_mode[_id](..).
createSpirvIntrInstExt(
attrs, QualType(), expr->getExprLoc(),
/*spvArgs*/ llvm::SmallVector<SpirvInstruction *, 1>{},
/*isInstr*/ false);
}
} else {
emitError("statement class '%0' unimplemented", stmt->getLocStart())
<< stmt->getStmtClassName() << stmt->getSourceRange();
Expand Down Expand Up @@ -7776,7 +7786,10 @@ SpirvEmitter::processIntrinsicCallExpr(const CallExpr *callExpr) {
retVal = processRawBufferLoad(callExpr);
break;
case hlsl::IntrinsicOp::IOP_Vkext_execution_mode:
retVal = processIntrinsicExecutionMode(callExpr);
retVal = processIntrinsicExecutionMode(callExpr, false);
break;
case hlsl::IntrinsicOp::IOP_Vkext_execution_mode_id:
retVal = processIntrinsicExecutionMode(callExpr, true);
break;
case hlsl::IntrinsicOp::IOP_saturate:
retVal = processIntrinsicSaturate(callExpr);
Expand Down Expand Up @@ -12720,32 +12733,45 @@ SpirvEmitter::processRayQueryIntrinsics(const CXXMemberCallExpr *expr,
return retVal;
}

SpirvInstruction *
SpirvEmitter::processSpvIntrinsicCallExpr(const CallExpr *expr) {
auto funcDecl = expr->getDirectCallee();
auto &attrs = funcDecl->getAttrs();
QualType retType = funcDecl->getReturnType();

SpirvInstruction *SpirvEmitter::createSpirvIntrInstExt(
llvm::ArrayRef<const Attr *> attrs, QualType retType, SourceLocation loc,
const llvm::SmallVectorImpl<SpirvInstruction *> &spvArgs, bool isInstr) {
llvm::SmallVector<uint32_t, 2> capbilities;
llvm::SmallVector<llvm::StringRef, 2> extensions;
llvm::StringRef instSet = "";
uint32_t op = 0;
// For [[vk::ext_type_def]], we use dummy OpNop with no semantic meaning,
// with possible extension and capabilities.
uint32_t op = static_cast<unsigned>(spv::Op::OpNop);
for (auto &attr : attrs) {
if (auto capAttr = dyn_cast<VKCapabilityExtAttr>(attr)) {
capbilities.push_back(capAttr->getCapability());
} else if (auto extAttr = dyn_cast<VKExtensionExtAttr>(attr)) {
extensions.push_back(extAttr->getName());
} else if (auto instAttr = dyn_cast<VKInstructionExtAttr>(attr)) {
}
if (!isInstr)
continue;
if (auto instAttr = dyn_cast<VKInstructionExtAttr>(attr)) {
op = instAttr->getOpcode();
instSet = instAttr->getInstruction_set();
}
}

llvm::SmallVector<SpirvInstruction *, 8> spvArgs;
SpirvInstruction *retVal = spvBuilder.createSpirvIntrInstExt(
op, retType, spvArgs, extensions, instSet, capbilities, loc);

// TODO: Revisit this r-value setting when handling vk::ext_result_id<T> ?
retVal->setRValue();

return retVal;
}

SpirvInstruction *
SpirvEmitter::processSpvIntrinsicCallExpr(const CallExpr *expr) {
const auto *funcDecl = expr->getDirectCallee();
llvm::SmallVector<SpirvInstruction *, 8> spvArgs;
const auto args = expr->getArgs();
for (uint32_t i = 0; i < expr->getNumArgs(); ++i) {
auto param = funcDecl->getParamDecl(i);
const auto *param = funcDecl->getParamDecl(i);
const Expr *arg = args[i]->IgnoreParenLValueCasts();
SpirvInstruction *argInst = doExpr(arg);
if (param->hasAttr<VKReferenceExtAttr>()) {
Expand All @@ -12766,14 +12792,9 @@ SpirvEmitter::processSpvIntrinsicCallExpr(const CallExpr *expr) {
}
}

const auto loc = expr->getExprLoc();

SpirvInstruction *retVal = spvBuilder.createSpirvIntrInstExt(
op, retType, spvArgs, extensions, instSet, capbilities, loc);

// TODO: Revisit this r-value setting when handling vk::ext_result_id<T> ?
retVal->setRValue();
return retVal;
return createSpirvIntrInstExt(funcDecl->getAttrs(), funcDecl->getReturnType(),
expr->getExprLoc(), spvArgs,
/*isInstr*/ true);
}

SpirvInstruction *SpirvEmitter::processRawBufferLoad(const CallExpr *callExpr) {
Expand Down Expand Up @@ -12803,18 +12824,22 @@ SpirvInstruction *SpirvEmitter::processRawBufferLoad(const CallExpr *callExpr) {
}

SpirvInstruction *
SpirvEmitter::processIntrinsicExecutionMode(const CallExpr *expr) {
SpirvEmitter::processIntrinsicExecutionMode(const CallExpr *expr,
bool useIdParams) {
llvm::SmallVector<uint32_t, 2> execModesParams;
uint32_t exeMode = 0;
const auto args = expr->getArgs();
for (uint32_t i = 0; i < expr->getNumArgs(); ++i) {
SpirvConstantInteger *argInst =
dyn_cast<SpirvConstantInteger>(doExpr(args[i]));
if (argInst == nullptr) {
emitError("argument should be constant interger", expr->getExprLoc());
const auto *intLiteral =
dyn_cast<IntegerLiteral>(args[i]->IgnoreImplicit());
if (intLiteral == nullptr) {
emitError("argument should be constant integer", expr->getExprLoc());
return nullptr;
}
unsigned argInteger = argInst->getValue().getZExtValue();

uint32_t argInteger =
static_cast<uint32_t>(intLiteral->getValue().getZExtValue());

if (i > 0)
execModesParams.push_back(argInteger);
else
Expand All @@ -12823,26 +12848,14 @@ SpirvEmitter::processIntrinsicExecutionMode(const CallExpr *expr) {
assert(entryFunction != nullptr);
assert(exeMode != 0);

return spvBuilder.addExecutionMode(entryFunction,
static_cast<spv::ExecutionMode>(exeMode),
execModesParams, expr->getExprLoc());
return spvBuilder.addExecutionMode(
entryFunction, static_cast<spv::ExecutionMode>(exeMode), execModesParams,
expr->getExprLoc(), useIdParams);
}

SpirvInstruction *
SpirvEmitter::processSpvIntrinsicTypeDef(const CallExpr *expr) {
auto funcDecl = expr->getDirectCallee();
auto typeDefAttr = funcDecl->getAttr<VKTypeDefExtAttr>();
llvm::SmallVector<uint32_t, 2> capbilities;
llvm::SmallVector<llvm::StringRef, 2> extensions;

for (auto &attr : funcDecl->getAttrs()) {
if (auto capAttr = dyn_cast<VKCapabilityExtAttr>(attr)) {
capbilities.push_back(capAttr->getCapability());
} else if (auto extAttr = dyn_cast<VKExtensionExtAttr>(attr)) {
extensions.push_back(extAttr->getName());
}
}

SmallVector<SpvIntrinsicTypeOperand, 3> operands;
const auto args = expr->getArgs();
for (uint32_t i = 0; i < expr->getNumArgs(); ++i) {
Expand All @@ -12867,17 +12880,15 @@ SpirvEmitter::processSpvIntrinsicTypeDef(const CallExpr *expr) {
operands.emplace_back(loadIfGLValue(arg));
}
}

auto typeDefAttr = funcDecl->getAttr<VKTypeDefExtAttr>();
spvContext.getSpirvIntrinsicType(typeDefAttr->getId(),
typeDefAttr->getOpcode(), operands);

// Emit dummy OpNop with no semantic meaning, with possible extension and
// capabilities
SpirvInstruction *retVal = spvBuilder.createSpirvIntrInstExt(
static_cast<unsigned>(spv::Op::OpNop), QualType(), {}, extensions, {},
capbilities, expr->getExprLoc());
retVal->setRValue();

return retVal;
return createSpirvIntrInstExt(
funcDecl->getAttrs(), QualType(), expr->getExprLoc(),
/*spvArgs*/ llvm::SmallVector<SpirvInstruction *, 1>{},
/*isInstr*/ false);
}

bool SpirvEmitter::spirvToolsValidate(std::vector<uint32_t> *mod,
Expand Down
9 changes: 8 additions & 1 deletion tools/clang/lib/SPIRV/SpirvEmitter.h
Original file line number Diff line number Diff line change
Expand Up @@ -613,6 +613,12 @@ class SpirvEmitter : public ASTConsumer {
/// Process ray query intrinsics
SpirvInstruction *processRayQueryIntrinsics(const CXXMemberCallExpr *expr,
hlsl::IntrinsicOp opcode);

/// Create SpirvIntrinsicInstruction for arbitrary SPIR-V instructions
/// specified by [[vk::ext_instruction(..)]] or [[vk::ext_type_def(..)]]
SpirvInstruction *createSpirvIntrInstExt(
llvm::ArrayRef<const Attr *> attrs, QualType retType, SourceLocation loc,
jaebaek marked this conversation as resolved.
Show resolved Hide resolved
const llvm::SmallVectorImpl<SpirvInstruction *> &spvArgs, bool isInstr);
/// Process spirv intrinsic instruction
SpirvInstruction *processSpvIntrinsicCallExpr(const CallExpr *expr);

Expand All @@ -622,7 +628,8 @@ class SpirvEmitter : public ASTConsumer {
/// Custom intrinsic to support basic buffer_reference use case
SpirvInstruction *processRawBufferLoad(const CallExpr *callExpr);
/// Process vk::ext_execution_mode intrinsic
SpirvInstruction *processIntrinsicExecutionMode(const CallExpr *expr);
SpirvInstruction *processIntrinsicExecutionMode(const CallExpr *expr,
bool useIdParams);

private:
/// Returns the <result-id> for constant value 0 of the given type.
Expand Down
18 changes: 18 additions & 0 deletions tools/clang/lib/Sema/SemaHLSL.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12173,6 +12173,24 @@ Attr *hlsl::ProcessStmtAttributeForHLSL(Sema &S, Stmt *St, const AttributeList &
Attr * result = nullptr;
Handled = true;

// SPIRV Change Starts
if (A.hasScope() && A.getScopeName()->getName().equals("vk")) {
switch (A.getKind()) {
case AttributeList::AT_VKCapabilityExt:
return ::new (S.Context) VKCapabilityExtAttr(
A.getRange(), S.Context, ValidateAttributeIntArg(S, A),
A.getAttributeSpellingListIndex());
case AttributeList::AT_VKExtensionExt:
return ::new (S.Context) VKExtensionExtAttr(
A.getRange(), S.Context, ValidateAttributeStringArg(S, A, nullptr),
A.getAttributeSpellingListIndex());
default:
Handled = false;
return nullptr;
}
}
// SPIRV Change Ends

switch (A.getKind())
{
case AttributeList::AT_HLSLUnroll:
Expand Down
7 changes: 5 additions & 2 deletions tools/clang/test/CodeGenSPIRV/spv.intrinsicExecutionMode.hlsl
Original file line number Diff line number Diff line change
@@ -1,14 +1,17 @@
// RUN: %dxc -T ps_6_0 -E main -spirv


// CHECK: OpCapability ShaderClockKHR
// CHECK: OpExtension "SPV_KHR_shader_clock"
// CHECK: OpExecutionMode {{%\w+}} StencilRefReplacingEXT
// CHECK: OpExecutionMode {{%\w+}} SubgroupSize 32
// CHECK: OpDecorate {{%\w+}} BuiltIn FragStencilRefEXT

[[vk::ext_decorate(11, 5014)]]
int main() : SV_Target0 {

[[vk::ext_capability(5055)]]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the vk::ext_execution_mode function call with extension and capability looks a little bit heavy

i think we might introduce new intrinsic functions directly.
vk::ext_capability(5055);
vk::ext_extension("SPV_KHR_shader_clock")

or
put these vk::attributes before entry functions.

[[vk::ext_capability(5055)]]
[[vk::ext_extension("SPV_KHR_shader_clock")]]
[[vk::ext_decorate(11, 5014)]]
int main() : SV_Target0 {
}

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually I also thought we have to add separate functions for capabilities and extensions.

However, in our email discussion (between you and me and Tobias Hector) a few months ago, Tobias Hector said

users don’t have to think about which extensions/capabilities they need to use when pulling in a header, and so they could pull in headers without any worry that they’re adding unnecessary capabilities to their code. So if you wanted to use e.g. clockRealtime2x32EXT, you’d just include the header and call clockRealtime2x32EXT. If you include the header and don’t call it? No worries – no extra capabilities/extensions specified.

This is the motivation to add capabilities and extensions as attributes in the initial GLSL version of GL_EXT_spirv_intrinsics design.

For example, I think Tobias Hector is worried about the following case:

// Separate functions for capabilities and extensions:
#ifdef ENABLE_DEMOTE_TO_HELPER
vk::ext_capability(/* DemoteToHelperInvocationEXT */ 5379);
vk::ext_extension("SPV_EXT_demote_to_helper_invocation");
#endif

#ifdef OPTION1
[[vk::ext_instruction(/*OpDemoteToHelperInvocationEXT*/ 5380)]]
void DemoteToHelperInvocation();
#endif

#ifdef OPTION2
[[vk::ext_instruction(/*OpIsHelperInvocationEXT*/ 5381)]]
bool IsHelperInvocation();
#endif

// With attributes
#ifdef OPTION1
[[vk::ext_capability(/* DemoteToHelperInvocationEXT */ 5379)]]
[[vk::ext_extension("SPV_EXT_demote_to_helper_invocation")]]
[[vk::ext_instruction(/*OpDemoteToHelperInvocationEXT*/ 5380)]]
void DemoteToHelperInvocation();
#endif

#ifdef OPTION2
[[vk::ext_capability(/* DemoteToHelperInvocationEXT */ 5379)]]
[[vk::ext_extension("SPV_EXT_demote_to_helper_invocation")]]
[[vk::ext_instruction(/*OpIsHelperInvocationEXT*/ 5381)]]
bool IsHelperInvocation();
#endif

When the code size becomes big e.g., more than 3000 lines and many preprocessor based options and header files, users can miss enabling capabilites and extensions if we separate them from vk::ext_instruction or vk::ext_execution_mode or vk::ext_type_def.

I agree with Tobias Hector's opinion. Just I think it would be unlikely that users use this feature for actual game shaders that has more than 1000 lines. I guess it would be mainly used by hardware vendors to test new specs.
However, since we can prevent users from making mistakes using some language design, I think this is a reasonable direction to go.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually I also thought we have to add separate functions for capabilities and extensions.

However, in our email discussion (between you and me and Tobias Hector) a few months ago, Tobias Hector said

users don’t have to think about which extensions/capabilities they need to use when pulling in a header, and so they could pull in headers without any worry that they’re adding unnecessary capabilities to their code. So if you wanted to use e.g. clockRealtime2x32EXT, you’d just include the header and call clockRealtime2x32EXT. If you include the header and don’t call it? No worries – no extra capabilities/extensions specified.

This is the motivation to add capabilities and extensions as attributes in the initial GLSL version of GL_EXT_spirv_intrinsics design.

For example, I think Tobias Hector is worried about the following case:

// Separate functions for capabilities and extensions:
#ifdef ENABLE_DEMOTE_TO_HELPER
vk::ext_capability(/* DemoteToHelperInvocationEXT */ 5379);
vk::ext_extension("SPV_EXT_demote_to_helper_invocation");
#endif

#ifdef OPTION1
[[vk::ext_instruction(/*OpDemoteToHelperInvocationEXT*/ 5380)]]
void DemoteToHelperInvocation();
#endif

#ifdef OPTION2
[[vk::ext_instruction(/*OpIsHelperInvocationEXT*/ 5381)]]
bool IsHelperInvocation();
#endif

// With attributes
#ifdef OPTION1
[[vk::ext_capability(/* DemoteToHelperInvocationEXT */ 5379)]]
[[vk::ext_extension("SPV_EXT_demote_to_helper_invocation")]]
[[vk::ext_instruction(/*OpDemoteToHelperInvocationEXT*/ 5380)]]
void DemoteToHelperInvocation();
#endif

#ifdef OPTION2
[[vk::ext_capability(/* DemoteToHelperInvocationEXT */ 5379)]]
[[vk::ext_extension("SPV_EXT_demote_to_helper_invocation")]]
[[vk::ext_instruction(/*OpIsHelperInvocationEXT*/ 5381)]]
bool IsHelperInvocation();
#endif

When the code size becomes big e.g., more than 3000 lines and many preprocessor based options and header files, users can miss enabling capabilites and extensions if we separate them from vk::ext_instruction or vk::ext_execution_mode or vk::ext_type_def.

I agree with Tobias Hector's opinion. Just I think it would be unlikely that users use this feature for actual game shaders that has more than 1000 lines. I guess it would be mainly used by hardware vendors to test new specs. However, since we can prevent users from making mistakes using some language design, I think this is a reasonable direction to go.

thanks, it makes sense.

[[vk::ext_extension("SPV_KHR_shader_clock")]]
vk::ext_execution_mode(/*StencilRefReplacingEXT*/5027);

vk::ext_execution_mode(/*SubgroupSize*/35, 32);
return 3;
}
16 changes: 16 additions & 0 deletions tools/clang/test/CodeGenSPIRV/spv.intrinsicExecutionModeId.hlsl
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
// RUN: %dxc -T ps_6_0 -E main -spirv

// CHECK: OpCapability ShaderClockKHR
// CHECK: OpExtension "SPV_KHR_shader_clock"
// CHECK: OpExecutionModeId {{%\w+}} LocalSizeId %uint_8 %uint_8 %uint_8
// CHECK: OpExecutionModeId {{%\w+}} LocalSizeHintId %uint_4 %uint_4 %uint_4

int main() : SV_Target0 {
vk::ext_execution_mode_id(/*LocalSizeId*/38, 8, 8, 8);

[[vk::ext_capability(5055)]]
[[vk::ext_extension("SPV_KHR_shader_clock")]]
vk::ext_execution_mode_id(/*LocalSizeHintId*/39, 4, 4, 4);

return 3;
}
1 change: 1 addition & 0 deletions tools/clang/unittests/SPIRV/CodeGenSpirvTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1344,6 +1344,7 @@ TEST_F(FileTest, IntrinsicsSpirv) {
runFileTest("spv.intrinsicLiteral.hlsl");
runFileTest("spv.intrinsicDecorate.hlsl", Expect::Success, false);
runFileTest("spv.intrinsicExecutionMode.hlsl", Expect::Success, false);
runFileTest("spv.intrinsicExecutionModeId.hlsl", Expect::Success, false);
runFileTest("spv.intrinsicStorageClass.hlsl", Expect::Success, false);
runFileTest("spv.intrinsicTypeInteger.hlsl");
runFileTest("spv.intrinsicTypeRayquery.hlsl", Expect::Success, false);
Expand Down
3 changes: 2 additions & 1 deletion utils/hct/gen_intrin_main.txt
Original file line number Diff line number Diff line change
Expand Up @@ -379,7 +379,8 @@ namespace VkIntrinsics {

u64 [[]] ReadClock(in uint scope);
uint [[ro]] RawBufferLoad(in u64 addr);
void [[]] ext_execution_mode(...);
void [[]] ext_execution_mode(in uint mode, ...);
void [[]] ext_execution_mode_id(in uint mode, ...);

} namespace
// SPIRV Change Ends
Expand Down