Skip to content

Commit 07c29d8

Browse files
ArielG-NVcsyonghe
andauthored
Emit execution mode of type per entry point once. Emit SPIRV capability once per shader program. (shader-slang#4189)
* Emit only 1 execution mode of type per entry point Added a dictionary<SpvWord,Hash<ExecutionMode>> to ensure we don't emit multiple. * get inst->id directly * address review + fix test --------- Co-authored-by: Yong He <yonghe@outlook.com>
1 parent 62b7219 commit 07c29d8

File tree

3 files changed

+63
-129
lines changed

3 files changed

+63
-129
lines changed

source/slang/slang-emit-spirv-ops.h

-95
Original file line numberDiff line numberDiff line change
@@ -73,101 +73,6 @@ SpvInst* emitOpEntryPoint(
7373
return emitInst(parent, inst, SpvOpEntryPoint, executionModel, entryPoint, name, interfaces);
7474
}
7575

76-
// https://registry.khronos.org/SPIR-V/specs/unified1/SPIRV.html#OpExecutionMode
77-
template<typename T>
78-
SpvInst* emitOpExecutionMode(
79-
SpvInstParent* parent,
80-
IRInst* inst,
81-
const T& entryPoint,
82-
SpvExecutionMode mode
83-
)
84-
{
85-
static_assert(isSingular<T>);
86-
return emitInst(parent, inst, SpvOpExecutionMode, entryPoint, mode);
87-
}
88-
89-
// https://registry.khronos.org/SPIR-V/specs/unified1/SPIRV.html#OpExecutionMode
90-
template<typename T>
91-
SpvInst* emitOpExecutionModeLocalSize(
92-
SpvInstParent* parent,
93-
IRInst* inst,
94-
const T& entryPoint,
95-
const SpvLiteralInteger& xSize,
96-
const SpvLiteralInteger& ySize,
97-
const SpvLiteralInteger& zSize
98-
)
99-
{
100-
static_assert(isSingular<T>);
101-
return emitInst(
102-
parent, inst, SpvOpExecutionMode, entryPoint, SpvExecutionModeLocalSize, xSize, ySize, zSize
103-
);
104-
}
105-
106-
// https://registry.khronos.org/SPIR-V/specs/unified1/SPIRV.html#OpExecutionMode
107-
template<typename T1, typename T2, typename T3, typename T4>
108-
SpvInst* emitOpExecutionModeLocalSizeId(
109-
SpvInstParent* parent,
110-
IRInst* inst,
111-
const T1& entryPoint,
112-
const T2& xSize,
113-
const T3& ySize,
114-
const T4& zSize
115-
)
116-
{
117-
static_assert(isSingular<T1>);
118-
static_assert(isSingular<T2>);
119-
static_assert(isSingular<T3>);
120-
static_assert(isSingular<T4>);
121-
return emitInst(
122-
parent, inst, SpvOpExecutionMode, entryPoint, SpvExecutionModeLocalSizeId, xSize, ySize, zSize
123-
);
124-
}
125-
126-
// https://registry.khronos.org/SPIR-V/specs/unified1/SPIRV.html#OpExecutionMode
127-
template<typename T>
128-
SpvInst* emitOpExecutionModeOutputVertices(
129-
SpvInstParent* parent,
130-
IRInst* inst,
131-
const T& entryPoint,
132-
const SpvLiteralInteger& vertexCount
133-
)
134-
{
135-
static_assert(isSingular<T>);
136-
return emitInst(
137-
parent, inst, SpvOpExecutionMode, entryPoint, SpvExecutionModeOutputVertices, vertexCount
138-
);
139-
}
140-
141-
// https://registry.khronos.org/SPIR-V/specs/unified1/SPIRV.html#OpExecutionMode
142-
template<typename T>
143-
SpvInst* emitOpExecutionModeOutputPrimitivesEXT(
144-
SpvInstParent* parent,
145-
IRInst* inst,
146-
const T& entryPoint,
147-
const SpvLiteralInteger& primitiveCount
148-
)
149-
{
150-
static_assert(isSingular<T>);
151-
return emitInst(
152-
parent, inst, SpvOpExecutionMode, entryPoint, SpvExecutionModeOutputPrimitivesEXT, primitiveCount
153-
);
154-
}
155-
156-
// https://registry.khronos.org/SPIR-V/specs/unified1/SPIRV.html#OpExecutionMode
157-
template<typename T>
158-
SpvInst* emitOpExecutionModeInvocations(
159-
SpvInstParent* parent,
160-
IRInst* inst,
161-
const T& entryPoint,
162-
const SpvLiteralInteger& invocations
163-
)
164-
{
165-
static_assert(isSingular<T>);
166-
return emitInst(
167-
parent, inst, SpvOpExecutionMode, entryPoint, SpvExecutionModeInvocations, invocations
168-
);
169-
}
170-
17176
// https://registry.khronos.org/SPIR-V/specs/unified1/SPIRV.html#OpCapability
17277
SpvInst* emitOpCapability(SpvInstParent* parent, IRInst* inst, SpvCapability capability)
17378
{

source/slang/slang-emit-spirv.cpp

+59-34
Original file line numberDiff line numberDiff line change
@@ -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)

tests/glsl-intrinsic/compute-derivative/intrinsic-derivative-function-in-compute.slang

+4
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,15 @@
1111

1212
//TEST:SIMPLE(filecheck=CHECK_SPV_QUAD_C): -allow-glsl -stage compute -entry computeMain -target spirv -DQUAD -DCOMPUTE
1313
// CHECK_SPV_QUAD_C: DerivativeGroupQuadsNV
14+
// CHECK_SPV_QUAD_C-NOT: DerivativeGroupQuadsNV
1415
// CHECK_SPV_QUAD_C: "SPV_NV_compute_shader_derivatives"
16+
// CHECK_SPV_QUAD_C-NOT: "SPV_NV_compute_shader_derivatives"
1517

1618
//TEST:SIMPLE(filecheck=CHECK_SPV_LINEAR_C): -allow-glsl -stage compute -entry computeMain -target spirv -DLINEAR -DCOMPUTE
1719
// CHECK_SPV_LINEAR_C: DerivativeGroupLinearNV
20+
// CHECK_SPV_LINEAR_C-NOT: DerivativeGroupLinearNV
1821
// CHECK_SPV_LINEAR_C: "SPV_NV_compute_shader_derivatives"
22+
// CHECK_SPV_LINEAR_C-NOT: "SPV_NV_compute_shader_derivatives"
1923

2024
//TEST:SIMPLE(filecheck=CHECK_HLSL_C): -allow-glsl -stage compute -entry computeMain -target hlsl -DCOMPUTE
2125
// CHECK_HLSL_C: computeMain(

0 commit comments

Comments
 (0)