@@ -2765,14 +2765,14 @@ struct SPIRVEmitContext
27652765 if (isQuad)
27662766 {
27672767 verifyComputeDerivativeGroupModifiers (this ->m_sink , inst->sourceLoc , true , false , numThreadsDecor);
2768- emitOpExecutionMode ( getSection (SpvLogicalSectionID::ExecutionModes), nullptr , entryPoint, SpvExecutionModeDerivativeGroupQuadsNV);
2769- emitOpCapability ( getSection (SpvLogicalSectionID::Capabilities), nullptr , SpvCapabilityComputeDerivativeGroupQuadsNV);
2768+ requireSPIRVExecutionMode ( nullptr , getIRInstSpvID ( entryPoint) , SpvExecutionModeDerivativeGroupQuadsNV);
2769+ requireSPIRVCapability ( SpvCapabilityComputeDerivativeGroupQuadsNV);
27702770 }
27712771 else
27722772 {
27732773 verifyComputeDerivativeGroupModifiers (this ->m_sink , inst->sourceLoc , false , true , numThreadsDecor);
2774- emitOpExecutionMode ( getSection (SpvLogicalSectionID::ExecutionModes), nullptr , entryPoint, SpvExecutionModeDerivativeGroupLinearNV);
2775- emitOpCapability ( getSection (SpvLogicalSectionID::Capabilities), nullptr , SpvCapabilityComputeDerivativeGroupLinearNV);
2774+ requireSPIRVExecutionMode ( nullptr , getIRInstSpvID ( entryPoint) , SpvExecutionModeDerivativeGroupLinearNV);
2775+ requireSPIRVCapability ( SpvCapabilityComputeDerivativeGroupLinearNV);
27762776 }
27772777 }
27782778
@@ -2790,7 +2790,7 @@ struct SPIRVEmitContext
27902790 case kIROp_BeginFragmentShaderInterlock :
27912791 ensureExtensionDeclaration (UnownedStringSlice (" SPV_EXT_fragment_shader_interlock" ));
27922792 requireSPIRVCapability (SpvCapabilityFragmentShaderPixelInterlockEXT);
2793- emitOpExecutionMode ( getSection (SpvLogicalSectionID::ExecutionModes), nullptr , getParentFunc (inst), SpvExecutionModePixelInterlockOrderedEXT);
2793+ requireSPIRVExecutionMode ( nullptr , getIRInstSpvID ( getParentFunc (inst) ), SpvExecutionModePixelInterlockOrderedEXT);
27942794 result = emitOpBeginInvocationInterlockEXT (parent, inst);
27952795 break ;
27962796 case kIROp_EndFragmentShaderInterlock :
@@ -3130,10 +3130,7 @@ struct SPIRVEmitContext
31303130 if (mode == SpvExecutionModeMax)
31313131 return ;
31323132
3133- emitOpExecutionMode (getSection (SpvLogicalSectionID::ExecutionModes),
3134- nullptr ,
3135- entryPoint,
3136- mode);
3133+ requireSPIRVExecutionMode (nullptr , getIRInstSpvID (entryPoint), mode);
31373134 }
31383135
31393136 // Make user type name conform to `SPV_GOOGLE_user_type` spec.
@@ -3252,14 +3249,14 @@ struct SPIRVEmitContext
32523249 {
32533250 case Stage::Fragment:
32543251 // OpExecutionMode %main OriginUpperLeft
3255- emitOpExecutionMode ( getSection (SpvLogicalSectionID::ExecutionModes), nullptr , dstID , SpvExecutionModeOriginUpperLeft);
3252+ requireSPIRVExecutionMode ( nullptr , getIRInstSpvID (entryPoint) , SpvExecutionModeOriginUpperLeft);
32563253 maybeEmitEntryPointDepthReplacingExecutionMode (entryPoint, referencedBuiltinIRVars);
32573254 for (auto decor : entryPoint->getDecorations ())
32583255 {
32593256 switch (decor->getOp ())
32603257 {
32613258 case kIROp_EarlyDepthStencilDecoration :
3262- emitOpExecutionMode ( getSection (SpvLogicalSectionID::ExecutionModes), nullptr , dstID , SpvExecutionModeEarlyFragmentTests);
3259+ requireSPIRVExecutionMode ( nullptr , getIRInstSpvID (entryPoint) , SpvExecutionModeEarlyFragmentTests);
32633260 break ;
32643261 default :
32653262 break ;
@@ -3293,8 +3290,6 @@ struct SPIRVEmitContext
32933290 // [3.6. Execution Mode]: LocalSize
32943291 case kIROp_NumThreadsDecoration :
32953292 {
3296- auto section = getSection (SpvLogicalSectionID::ExecutionModes);
3297-
32983293 // TODO: The `LocalSize` execution mode option requires
32993294 // literal values for the X,Y,Z thread-group sizes.
33003295 // There is a `LocalSizeId` variant that takes `<id>`s
@@ -3305,10 +3300,10 @@ struct SPIRVEmitContext
33053300 // in those positions in the Slang IR).
33063301 //
33073302 auto numThreads = cast<IRNumThreadsDecoration>(decoration);
3308- emitOpExecutionModeLocalSize (
3309- section,
3303+ requireSPIRVExecutionMode (
33103304 decoration,
33113305 dstID,
3306+ SpvExecutionModeLocalSize,
33123307 SpvLiteralInteger::from32 (int32_t (numThreads->getX ()->getValue ())),
33133308 SpvLiteralInteger::from32 (int32_t (numThreads->getY ()->getValue ())),
33143309 SpvLiteralInteger::from32 (int32_t (numThreads->getZ ()->getValue ()))
@@ -3324,8 +3319,7 @@ struct SPIRVEmitContext
33243319 {
33253320 auto decor = as<IRInstanceDecoration>(decoration);
33263321 auto count = int32_t (getIntVal (decor->getCount ()));
3327- auto section = getSection (SpvLogicalSectionID::ExecutionModes);
3328- emitOpExecutionModeInvocations (section, decoration, dstID, SpvLiteralInteger::from32 (count));
3322+ requireSPIRVExecutionMode (decoration, dstID, SpvExecutionModeInvocations, SpvLiteralInteger::from32 (count));
33293323 }
33303324 break ;
33313325 case kIROp_TriangleInputPrimitiveTypeDecoration :
@@ -3343,31 +3337,30 @@ struct SPIRVEmitContext
33433337 switch (inputDecor->getOp ())
33443338 {
33453339 case kIROp_TriangleInputPrimitiveTypeDecoration :
3346- emitOpExecutionMode ( getSection (SpvLogicalSectionID::ExecutionModes), inputDecor, dstID, SpvExecutionModeTriangles);
3340+ requireSPIRVExecutionMode ( inputDecor, dstID, SpvExecutionModeTriangles);
33473341 break ;
33483342 case kIROp_LineInputPrimitiveTypeDecoration :
3349- emitOpExecutionMode ( getSection (SpvLogicalSectionID::ExecutionModes), inputDecor, dstID, SpvExecutionModeInputLines);
3343+ requireSPIRVExecutionMode ( inputDecor, dstID, SpvExecutionModeInputLines);
33503344 break ;
33513345 case kIROp_LineAdjInputPrimitiveTypeDecoration :
3352- emitOpExecutionMode ( getSection (SpvLogicalSectionID::ExecutionModes), inputDecor, dstID, SpvExecutionModeInputLinesAdjacency);
3346+ requireSPIRVExecutionMode ( inputDecor, dstID, SpvExecutionModeInputLinesAdjacency);
33533347 break ;
33543348 case kIROp_PointInputPrimitiveTypeDecoration :
3355- emitOpExecutionMode ( getSection (SpvLogicalSectionID::ExecutionModes), inputDecor, dstID, SpvExecutionModeInputPoints);
3349+ requireSPIRVExecutionMode ( inputDecor, dstID, SpvExecutionModeInputPoints);
33563350 break ;
33573351 case kIROp_TriangleAdjInputPrimitiveTypeDecoration :
3358- emitOpExecutionMode ( getSection (SpvLogicalSectionID::ExecutionModes), inputDecor, dstID, SpvExecutionModeInputTrianglesAdjacency);
3352+ requireSPIRVExecutionMode ( inputDecor, dstID, SpvExecutionModeInputTrianglesAdjacency);
33593353 break ;
33603354 }
33613355 }
33623356 // SPIRV requires MaxVertexCount decoration to appear before OutputTopologyDecoration,
33633357 // so we emit them here.
33643358 if (auto maxVertexCount = decoration->getParent ()->findDecoration <IRMaxVertexCountDecoration>())
33653359 {
3366- auto section = getSection (SpvLogicalSectionID::ExecutionModes);
3367- emitOpExecutionModeOutputVertices (
3368- section,
3360+ requireSPIRVExecutionMode (
33693361 maxVertexCount,
33703362 dstID,
3363+ SpvExecutionModeOutputVertices,
33713364 SpvLiteralInteger::from32 (int32_t (getIntVal (maxVertexCount->getCount ())))
33723365 );
33733366 }
@@ -3378,13 +3371,13 @@ struct SPIRVEmitContext
33783371 switch (type->getOp ())
33793372 {
33803373 case kIROp_HLSLPointStreamType :
3381- emitOpExecutionMode ( getSection (SpvLogicalSectionID::ExecutionModes), decoration, dstID, SpvExecutionModeOutputPoints);
3374+ requireSPIRVExecutionMode ( decoration, dstID, SpvExecutionModeOutputPoints);
33823375 break ;
33833376 case kIROp_HLSLLineStreamType :
3384- emitOpExecutionMode ( getSection (SpvLogicalSectionID::ExecutionModes), decoration, dstID, SpvExecutionModeOutputLineStrip);
3377+ requireSPIRVExecutionMode ( decoration, dstID, SpvExecutionModeOutputLineStrip);
33853378 break ;
33863379 case kIROp_HLSLTriangleStreamType :
3387- emitOpExecutionMode ( getSection (SpvLogicalSectionID::ExecutionModes), decoration, dstID, SpvExecutionModeOutputTriangleStrip);
3380+ requireSPIRVExecutionMode ( decoration, dstID, SpvExecutionModeOutputTriangleStrip);
33883381 break ;
33893382 default : SLANG_ASSERT (!" Unknown stream out type" );
33903383 }
@@ -3433,17 +3426,17 @@ struct SPIRVEmitContext
34333426 : t == " point" ? SpvExecutionModeOutputPoints
34343427 : SpvExecutionModeMax;
34353428 SLANG_ASSERT (m != SpvExecutionModeMax);
3436- emitOpExecutionMode ( getSection (SpvLogicalSectionID::ExecutionModes), decoration, dstID, m);
3429+ requireSPIRVExecutionMode ( decoration, dstID, m);
34373430 }
34383431 break ;
34393432
34403433 case kIROp_VerticesDecoration :
34413434 {
34423435 const auto c = cast<IRVerticesDecoration>(decoration);
3443- emitOpExecutionModeOutputVertices (
3444- getSection (SpvLogicalSectionID::ExecutionModes),
3436+ requireSPIRVExecutionMode (
34453437 decoration,
34463438 dstID,
3439+ SpvExecutionModeOutputVertices,
34473440 SpvLiteralInteger::from32 (int32_t (c->getMaxSize ()->getValue ()))
34483441 );
34493442 }
@@ -3452,10 +3445,10 @@ struct SPIRVEmitContext
34523445 case kIROp_PrimitivesDecoration :
34533446 {
34543447 const auto c = cast<IRPrimitivesDecoration>(decoration);
3455- emitOpExecutionModeOutputPrimitivesEXT (
3456- getSection (SpvLogicalSectionID::ExecutionModes),
3448+ requireSPIRVExecutionMode (
34573449 decoration,
34583450 dstID,
3451+ SpvExecutionModeOutputPrimitivesEXT,
34593452 SpvLiteralInteger::from32 (int32_t (c->getMaxSize ()->getValue ()))
34603453 );
34613454 }
@@ -6136,7 +6129,6 @@ struct SPIRVEmitContext
61366129 }
61376130
61386131 OrderedHashSet<SpvCapability> m_capabilities;
6139-
61406132 void requireSPIRVCapability (SpvCapability capability)
61416133 {
61426134 if (m_capabilities.add (capability))
@@ -6149,6 +6141,39 @@ struct SPIRVEmitContext
61496141 }
61506142 }
61516143
6144+ // https://registry.khronos.org/SPIR-V/specs/unified1/SPIRV.html#OpExecutionMode
6145+ Dictionary<SpvWord, OrderedHashSet<SpvExecutionMode>> m_executionModes;
6146+ template <typename ... Operands>
6147+ void requireSPIRVExecutionMode (IRInst* parentInst, SpvWord entryPoint, SpvExecutionMode executionMode, const Operands& ...ops)
6148+ {
6149+ if (m_executionModes[entryPoint].add (executionMode))
6150+ {
6151+ emitInst (
6152+ getSection (SpvLogicalSectionID::ExecutionModes),
6153+ parentInst,
6154+ SpvOpExecutionMode,
6155+ entryPoint,
6156+ executionMode,
6157+ ops...
6158+ );
6159+ }
6160+ }
6161+
6162+ template <typename T1, typename T2, typename T3>
6163+ SpvInst* emitOpExecutionModeLocalSizeId (
6164+ IRInst* inst,
6165+ SpvWord entryPoint,
6166+ const T1& xSize,
6167+ const T2& ySize,
6168+ const T3& zSize
6169+ )
6170+ {
6171+ static_assert (isSingular<T1>);
6172+ static_assert (isSingular<T2>);
6173+ static_assert (isSingular<T3>);
6174+ requireSPIRVExecutionMode (inst, entryPoint, SpvExecutionModeLocalSizeId, xSize, ySize, zSize);
6175+ }
6176+
61526177 SPIRVEmitContext (IRModule* module , TargetProgram* program, DiagnosticSink* sink)
61536178 : SPIRVEmitSharedContext(module , program, sink)
61546179 , m_irModule(module )
0 commit comments