@@ -2765,14 +2765,14 @@ struct SPIRVEmitContext
2765
2765
if (isQuad)
2766
2766
{
2767
2767
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);
2770
2770
}
2771
2771
else
2772
2772
{
2773
2773
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);
2776
2776
}
2777
2777
}
2778
2778
@@ -2790,7 +2790,7 @@ struct SPIRVEmitContext
2790
2790
case kIROp_BeginFragmentShaderInterlock :
2791
2791
ensureExtensionDeclaration (UnownedStringSlice (" SPV_EXT_fragment_shader_interlock" ));
2792
2792
requireSPIRVCapability (SpvCapabilityFragmentShaderPixelInterlockEXT);
2793
- emitOpExecutionMode ( getSection (SpvLogicalSectionID::ExecutionModes), nullptr , getParentFunc (inst), SpvExecutionModePixelInterlockOrderedEXT);
2793
+ requireSPIRVExecutionMode ( nullptr , getIRInstSpvID ( getParentFunc (inst) ), SpvExecutionModePixelInterlockOrderedEXT);
2794
2794
result = emitOpBeginInvocationInterlockEXT (parent, inst);
2795
2795
break ;
2796
2796
case kIROp_EndFragmentShaderInterlock :
@@ -3130,10 +3130,7 @@ struct SPIRVEmitContext
3130
3130
if (mode == SpvExecutionModeMax)
3131
3131
return ;
3132
3132
3133
- emitOpExecutionMode (getSection (SpvLogicalSectionID::ExecutionModes),
3134
- nullptr ,
3135
- entryPoint,
3136
- mode);
3133
+ requireSPIRVExecutionMode (nullptr , getIRInstSpvID (entryPoint), mode);
3137
3134
}
3138
3135
3139
3136
// Make user type name conform to `SPV_GOOGLE_user_type` spec.
@@ -3252,14 +3249,14 @@ struct SPIRVEmitContext
3252
3249
{
3253
3250
case Stage::Fragment:
3254
3251
// OpExecutionMode %main OriginUpperLeft
3255
- emitOpExecutionMode ( getSection (SpvLogicalSectionID::ExecutionModes), nullptr , dstID , SpvExecutionModeOriginUpperLeft);
3252
+ requireSPIRVExecutionMode ( nullptr , getIRInstSpvID (entryPoint) , SpvExecutionModeOriginUpperLeft);
3256
3253
maybeEmitEntryPointDepthReplacingExecutionMode (entryPoint, referencedBuiltinIRVars);
3257
3254
for (auto decor : entryPoint->getDecorations ())
3258
3255
{
3259
3256
switch (decor->getOp ())
3260
3257
{
3261
3258
case kIROp_EarlyDepthStencilDecoration :
3262
- emitOpExecutionMode ( getSection (SpvLogicalSectionID::ExecutionModes), nullptr , dstID , SpvExecutionModeEarlyFragmentTests);
3259
+ requireSPIRVExecutionMode ( nullptr , getIRInstSpvID (entryPoint) , SpvExecutionModeEarlyFragmentTests);
3263
3260
break ;
3264
3261
default :
3265
3262
break ;
@@ -3293,8 +3290,6 @@ struct SPIRVEmitContext
3293
3290
// [3.6. Execution Mode]: LocalSize
3294
3291
case kIROp_NumThreadsDecoration :
3295
3292
{
3296
- auto section = getSection (SpvLogicalSectionID::ExecutionModes);
3297
-
3298
3293
// TODO: The `LocalSize` execution mode option requires
3299
3294
// literal values for the X,Y,Z thread-group sizes.
3300
3295
// There is a `LocalSizeId` variant that takes `<id>`s
@@ -3305,10 +3300,10 @@ struct SPIRVEmitContext
3305
3300
// in those positions in the Slang IR).
3306
3301
//
3307
3302
auto numThreads = cast<IRNumThreadsDecoration>(decoration);
3308
- emitOpExecutionModeLocalSize (
3309
- section,
3303
+ requireSPIRVExecutionMode (
3310
3304
decoration,
3311
3305
dstID,
3306
+ SpvExecutionModeLocalSize,
3312
3307
SpvLiteralInteger::from32 (int32_t (numThreads->getX ()->getValue ())),
3313
3308
SpvLiteralInteger::from32 (int32_t (numThreads->getY ()->getValue ())),
3314
3309
SpvLiteralInteger::from32 (int32_t (numThreads->getZ ()->getValue ()))
@@ -3324,8 +3319,7 @@ struct SPIRVEmitContext
3324
3319
{
3325
3320
auto decor = as<IRInstanceDecoration>(decoration);
3326
3321
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));
3329
3323
}
3330
3324
break ;
3331
3325
case kIROp_TriangleInputPrimitiveTypeDecoration :
@@ -3343,31 +3337,30 @@ struct SPIRVEmitContext
3343
3337
switch (inputDecor->getOp ())
3344
3338
{
3345
3339
case kIROp_TriangleInputPrimitiveTypeDecoration :
3346
- emitOpExecutionMode ( getSection (SpvLogicalSectionID::ExecutionModes), inputDecor, dstID, SpvExecutionModeTriangles);
3340
+ requireSPIRVExecutionMode ( inputDecor, dstID, SpvExecutionModeTriangles);
3347
3341
break ;
3348
3342
case kIROp_LineInputPrimitiveTypeDecoration :
3349
- emitOpExecutionMode ( getSection (SpvLogicalSectionID::ExecutionModes), inputDecor, dstID, SpvExecutionModeInputLines);
3343
+ requireSPIRVExecutionMode ( inputDecor, dstID, SpvExecutionModeInputLines);
3350
3344
break ;
3351
3345
case kIROp_LineAdjInputPrimitiveTypeDecoration :
3352
- emitOpExecutionMode ( getSection (SpvLogicalSectionID::ExecutionModes), inputDecor, dstID, SpvExecutionModeInputLinesAdjacency);
3346
+ requireSPIRVExecutionMode ( inputDecor, dstID, SpvExecutionModeInputLinesAdjacency);
3353
3347
break ;
3354
3348
case kIROp_PointInputPrimitiveTypeDecoration :
3355
- emitOpExecutionMode ( getSection (SpvLogicalSectionID::ExecutionModes), inputDecor, dstID, SpvExecutionModeInputPoints);
3349
+ requireSPIRVExecutionMode ( inputDecor, dstID, SpvExecutionModeInputPoints);
3356
3350
break ;
3357
3351
case kIROp_TriangleAdjInputPrimitiveTypeDecoration :
3358
- emitOpExecutionMode ( getSection (SpvLogicalSectionID::ExecutionModes), inputDecor, dstID, SpvExecutionModeInputTrianglesAdjacency);
3352
+ requireSPIRVExecutionMode ( inputDecor, dstID, SpvExecutionModeInputTrianglesAdjacency);
3359
3353
break ;
3360
3354
}
3361
3355
}
3362
3356
// SPIRV requires MaxVertexCount decoration to appear before OutputTopologyDecoration,
3363
3357
// so we emit them here.
3364
3358
if (auto maxVertexCount = decoration->getParent ()->findDecoration <IRMaxVertexCountDecoration>())
3365
3359
{
3366
- auto section = getSection (SpvLogicalSectionID::ExecutionModes);
3367
- emitOpExecutionModeOutputVertices (
3368
- section,
3360
+ requireSPIRVExecutionMode (
3369
3361
maxVertexCount,
3370
3362
dstID,
3363
+ SpvExecutionModeOutputVertices,
3371
3364
SpvLiteralInteger::from32 (int32_t (getIntVal (maxVertexCount->getCount ())))
3372
3365
);
3373
3366
}
@@ -3378,13 +3371,13 @@ struct SPIRVEmitContext
3378
3371
switch (type->getOp ())
3379
3372
{
3380
3373
case kIROp_HLSLPointStreamType :
3381
- emitOpExecutionMode ( getSection (SpvLogicalSectionID::ExecutionModes), decoration, dstID, SpvExecutionModeOutputPoints);
3374
+ requireSPIRVExecutionMode ( decoration, dstID, SpvExecutionModeOutputPoints);
3382
3375
break ;
3383
3376
case kIROp_HLSLLineStreamType :
3384
- emitOpExecutionMode ( getSection (SpvLogicalSectionID::ExecutionModes), decoration, dstID, SpvExecutionModeOutputLineStrip);
3377
+ requireSPIRVExecutionMode ( decoration, dstID, SpvExecutionModeOutputLineStrip);
3385
3378
break ;
3386
3379
case kIROp_HLSLTriangleStreamType :
3387
- emitOpExecutionMode ( getSection (SpvLogicalSectionID::ExecutionModes), decoration, dstID, SpvExecutionModeOutputTriangleStrip);
3380
+ requireSPIRVExecutionMode ( decoration, dstID, SpvExecutionModeOutputTriangleStrip);
3388
3381
break ;
3389
3382
default : SLANG_ASSERT (!" Unknown stream out type" );
3390
3383
}
@@ -3433,17 +3426,17 @@ struct SPIRVEmitContext
3433
3426
: t == " point" ? SpvExecutionModeOutputPoints
3434
3427
: SpvExecutionModeMax;
3435
3428
SLANG_ASSERT (m != SpvExecutionModeMax);
3436
- emitOpExecutionMode ( getSection (SpvLogicalSectionID::ExecutionModes), decoration, dstID, m);
3429
+ requireSPIRVExecutionMode ( decoration, dstID, m);
3437
3430
}
3438
3431
break ;
3439
3432
3440
3433
case kIROp_VerticesDecoration :
3441
3434
{
3442
3435
const auto c = cast<IRVerticesDecoration>(decoration);
3443
- emitOpExecutionModeOutputVertices (
3444
- getSection (SpvLogicalSectionID::ExecutionModes),
3436
+ requireSPIRVExecutionMode (
3445
3437
decoration,
3446
3438
dstID,
3439
+ SpvExecutionModeOutputVertices,
3447
3440
SpvLiteralInteger::from32 (int32_t (c->getMaxSize ()->getValue ()))
3448
3441
);
3449
3442
}
@@ -3452,10 +3445,10 @@ struct SPIRVEmitContext
3452
3445
case kIROp_PrimitivesDecoration :
3453
3446
{
3454
3447
const auto c = cast<IRPrimitivesDecoration>(decoration);
3455
- emitOpExecutionModeOutputPrimitivesEXT (
3456
- getSection (SpvLogicalSectionID::ExecutionModes),
3448
+ requireSPIRVExecutionMode (
3457
3449
decoration,
3458
3450
dstID,
3451
+ SpvExecutionModeOutputPrimitivesEXT,
3459
3452
SpvLiteralInteger::from32 (int32_t (c->getMaxSize ()->getValue ()))
3460
3453
);
3461
3454
}
@@ -6136,7 +6129,6 @@ struct SPIRVEmitContext
6136
6129
}
6137
6130
6138
6131
OrderedHashSet<SpvCapability> m_capabilities;
6139
-
6140
6132
void requireSPIRVCapability (SpvCapability capability)
6141
6133
{
6142
6134
if (m_capabilities.add (capability))
@@ -6149,6 +6141,39 @@ struct SPIRVEmitContext
6149
6141
}
6150
6142
}
6151
6143
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
+
6152
6177
SPIRVEmitContext (IRModule* module, TargetProgram* program, DiagnosticSink* sink)
6153
6178
: SPIRVEmitSharedContext(module, program, sink)
6154
6179
, m_irModule(module)
0 commit comments