Skip to content

Commit 8ce7c6f

Browse files
authored
Support specialization constant on WGSL and Metal. (#5780)
1 parent 22b64a4 commit 8ce7c6f

12 files changed

+227
-75
lines changed

docs/user-guide/a2-02-metal-target-specific.md

+18-1
Original file line numberDiff line numberDiff line change
@@ -274,4 +274,21 @@ The HLSL `:register()` semantic is respected when emitting Metal code.
274274

275275
Since metal does not differentiate a constant buffer, a shader resource (read-only) buffer and an unordered access buffer, Slang will map `register(tN)`, `register(uN)` and `register(bN)` to `[[buffer(N)]]` when such `register` semantic is declared on a buffer typed parameter.
276276

277-
`spaceN` specifiers inside `register` semantics are ignored.
277+
`spaceN` specifiers inside `register` semantics are ignored.
278+
279+
## Specialization Constants
280+
281+
Specialization constants declared with the `[SpecializationConstant]` or `[vk::constant_id]` attribute will be translated into a `function_constant` when generating Metal source.
282+
For example:
283+
284+
```csharp
285+
[vk::constant_id(7)]
286+
const int a = 2;
287+
```
288+
289+
Translates to:
290+
291+
```metal
292+
constant int fc_a_0 [[function_constant(7)]];
293+
constant int a_0 = is_function_constant_defined(fc_a_0) ? fc_a_0 : 2;
294+
```

docs/user-guide/a2-03-wgsl-target-specific.md

+17-1
Original file line numberDiff line numberDiff line change
@@ -161,4 +161,20 @@ Since the WGSL matrix multiplication convention is the normal one, where inner p
161161

162162
The `[vk::binding(index,set)]` attribute is respected when emitting WGSL code, and will translate to `@binding(index) @group(set)` in WGSL.
163163

164-
If the `[vk::binding()]` attribute is not specified by a `:register()` semantic is present, Slang will derive the binding from the `register` semantic the same way as the SPIRV and GLSL backends.
164+
If the `[vk::binding()]` attribute is not specified by a `:register()` semantic is present, Slang will derive the binding from the `register` semantic the same way as the SPIRV and GLSL backends.
165+
166+
## Specialization Constants
167+
168+
Specialization constants declared with the `[SpecializationConstant]` or `[vk::constant_id]` attribute will be translated into a global `override` declaration when generating WGSL source.
169+
For example:
170+
171+
```csharp
172+
[vk::constant_id(7)]
173+
const int a = 2;
174+
```
175+
176+
Translates to:
177+
178+
```wgsl
179+
@id(7) override a : i32 = 2;
180+
```

docs/user-guide/toc.html

+2
Original file line numberDiff line numberDiff line change
@@ -234,6 +234,7 @@
234234
<li data-link="metal-target-specific#conservative-rasterization"><span>Conservative Rasterization</span></li>
235235
<li data-link="metal-target-specific#address-space-assignment"><span>Address Space Assignment</span></li>
236236
<li data-link="metal-target-specific#explicit-parameter-binding"><span>Explicit Parameter Binding</span></li>
237+
<li data-link="metal-target-specific#specialization-constants"><span>Specialization Constants</span></li>
237238
</ul>
238239
</li>
239240
<li data-link="wgsl-target-specific"><span>WGSL specific functionalities</span>
@@ -251,6 +252,7 @@
251252
<li data-link="wgsl-target-specific#address-space-assignment"><span>Address Space Assignment</span></li>
252253
<li data-link="wgsl-target-specific#matrix-type-translation"><span>Matrix type translation</span></li>
253254
<li data-link="wgsl-target-specific#explicit-parameter-binding"><span>Explicit Parameter Binding</span></li>
255+
<li data-link="wgsl-target-specific#specialization-constants"><span>Specialization Constants</span></li>
254256
</ul>
255257
</li>
256258
</ul>

source/slang/slang-emit-metal.cpp

+45-1
Original file line numberDiff line numberDiff line change
@@ -1331,17 +1331,60 @@ bool MetalSourceEmitter::_emitUserSemantic(
13311331
return false;
13321332
}
13331333

1334+
bool MetalSourceEmitter::tryEmitGlobalParamImpl(IRGlobalParam* varDecl, IRType* varType)
1335+
{
1336+
auto layout = getVarLayout(varDecl);
1337+
if (!layout)
1338+
return false;
1339+
if (auto specConstLayout = layout->findOffsetAttr(LayoutResourceKind::SpecializationConstant))
1340+
{
1341+
// Emit specialization constant.
1342+
auto name = getName(varDecl);
1343+
auto prefixName = "fc_" + name;
1344+
auto defaultVal = varDecl->findDecoration<IRDefaultValueDecoration>();
1345+
1346+
m_writer->emit("constant ");
1347+
emitType(varType, prefixName);
1348+
m_writer->emit(" ");
1349+
m_writer->emit("[[function_constant(");
1350+
m_writer->emit(specConstLayout->getOffset());
1351+
m_writer->emit(")]];\n");
1352+
1353+
m_writer->emit("constant ");
1354+
emitType(varType, name);
1355+
m_writer->emit(" = ");
1356+
if (defaultVal)
1357+
{
1358+
m_writer->emit("is_function_constant_defined(");
1359+
m_writer->emit(prefixName);
1360+
m_writer->emit(") ? ");
1361+
m_writer->emit(prefixName);
1362+
m_writer->emit(" : ");
1363+
emitVal(defaultVal->getOperand(0), getInfo(EmitOp::General));
1364+
}
1365+
else
1366+
{
1367+
m_writer->emit(prefixName);
1368+
}
1369+
m_writer->emit(";\n");
1370+
return true;
1371+
}
1372+
return false;
1373+
}
1374+
13341375
void MetalSourceEmitter::emitSemanticsImpl(IRInst* inst, bool allowOffsets)
13351376
{
13361377
SLANG_UNUSED(allowOffsets);
1378+
1379+
auto varLayout = findVarLayout(inst);
1380+
13371381
if (inst->getOp() == kIROp_StructKey)
13381382
{
13391383
// Only emit [[attribute(n)]] on struct keys.
13401384

13411385
if (maybeEmitSystemSemantic(inst))
13421386
return;
13431387

1344-
auto varLayout = findVarLayout(inst);
13451388
bool hasSemantic = false;
13461389

13471390
if (varLayout)
@@ -1378,6 +1421,7 @@ void MetalSourceEmitter::emitSemanticsImpl(IRInst* inst, bool allowOffsets)
13781421
semanticDecor->getSemanticIndex());
13791422
}
13801423
}
1424+
return;
13811425
}
13821426
}
13831427

source/slang/slang-emit-metal.h

+1
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ class MetalSourceEmitter : public CLikeSourceEmitter
4040

4141
virtual void emitRateQualifiersAndAddressSpaceImpl(IRRate* rate, AddressSpace addressSpace)
4242
SLANG_OVERRIDE;
43+
virtual bool tryEmitGlobalParamImpl(IRGlobalParam* varDecl, IRType* varType) SLANG_OVERRIDE;
4344
virtual void emitSemanticsImpl(IRInst* inst, bool allowOffsets) SLANG_OVERRIDE;
4445
virtual void emitSimpleFuncParamImpl(IRParam* param) SLANG_OVERRIDE;
4546
virtual void emitPostDeclarationAttributesForType(IRInst* type) SLANG_OVERRIDE;

source/slang/slang-emit-wgsl.cpp

+32-1
Original file line numberDiff line numberDiff line change
@@ -643,6 +643,21 @@ void WGSLSourceEmitter::emitSimpleTypeImpl(IRType* type)
643643
}
644644
}
645645

646+
void WGSLSourceEmitter::emitGlobalParamDefaultVal(IRGlobalParam* varDecl)
647+
{
648+
auto layout = getVarLayout(varDecl);
649+
if (!layout)
650+
return;
651+
if (layout->findOffsetAttr(LayoutResourceKind::SpecializationConstant))
652+
{
653+
if (auto defaultValDecor = varDecl->findDecoration<IRDefaultValueDecoration>())
654+
{
655+
m_writer->emit(" = ");
656+
emitInstExpr(defaultValDecor->getOperand(0), EmitOpInfo());
657+
}
658+
}
659+
}
660+
646661
void WGSLSourceEmitter::emitLayoutQualifiersImpl(IRVarLayout* layout)
647662
{
648663

@@ -668,6 +683,14 @@ void WGSLSourceEmitter::emitLayoutQualifiersImpl(IRVarLayout* layout)
668683
m_writer->emit(space);
669684
m_writer->emit(") ");
670685

686+
return;
687+
}
688+
else if (kind == LayoutResourceKind::SpecializationConstant)
689+
{
690+
m_writer->emit("@id(");
691+
m_writer->emit(attr->getOffset());
692+
m_writer->emit(") ");
693+
671694
return;
672695
}
673696
}
@@ -708,7 +731,15 @@ void WGSLSourceEmitter::emitVarKeywordImpl(IRType* type, IRInst* varDecl)
708731
case kIROp_GlobalParam:
709732
case kIROp_GlobalVar:
710733
case kIROp_Var:
711-
m_writer->emit("var");
734+
{
735+
auto layout = getVarLayout(varDecl);
736+
if (layout && layout->findOffsetAttr(LayoutResourceKind::SpecializationConstant))
737+
{
738+
m_writer->emit("override");
739+
break;
740+
}
741+
m_writer->emit("var");
742+
}
712743
break;
713744
default:
714745
if (isStaticConst(varDecl))

source/slang/slang-emit-wgsl.h

+1
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ class WGSLSourceEmitter : public CLikeSourceEmitter
5252
UnownedStringSlice intrinsicDefinition,
5353
IRInst* intrinsicInst,
5454
EmitOpInfo const& inOuterPrec) SLANG_OVERRIDE;
55+
virtual void emitGlobalParamDefaultVal(IRGlobalParam* varDecl) SLANG_OVERRIDE;
5556

5657
void emit(const AddressSpace addressSpace);
5758

source/slang/slang-ir-explicit-global-context.cpp

+21-3
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33

44
#include "slang-ir-clone.h"
55
#include "slang-ir-insts.h"
6+
#include "slang-ir-util.h"
67

78
namespace Slang
89
{
@@ -39,7 +40,8 @@ struct IntroduceExplicitGlobalContextPass
3940
class ExplicitContextPolicy
4041
{
4142
public:
42-
ExplicitContextPolicy(CodeGenTarget target)
43+
ExplicitContextPolicy(CodeGenTarget inTarget)
44+
: target(inTarget)
4345
{
4446
switch (target)
4547
{
@@ -74,7 +76,7 @@ struct IntroduceExplicitGlobalContextPass
7476
return (UInt)hoistableGlobalObjectKind & (UInt)hoistable;
7577
}
7678

77-
bool canHoistGlobalVar(IRGlobalVar* inst)
79+
bool canHoistGlobalVar(IRInst* inst)
7880
{
7981
if (!((UInt)hoistGlobalVarOptions & (UInt)HoistGlobalVarOptions::SharedGlobal) &&
8082
as<IRGroupSharedRate>(inst->getRate()))
@@ -99,6 +101,19 @@ struct IntroduceExplicitGlobalContextPass
99101
}
100102
}
101103

104+
// Do not move specialization constants to context.
105+
switch (target)
106+
{
107+
case CodeGenTarget::Metal:
108+
case CodeGenTarget::MetalLib:
109+
case CodeGenTarget::MetalLibAssembly:
110+
{
111+
auto varLayout = findVarLayout(inst);
112+
if (varLayout &&
113+
varLayout->findOffsetAttr(LayoutResourceKind::SpecializationConstant))
114+
return false;
115+
}
116+
}
102117
return true;
103118
}
104119

@@ -111,6 +126,7 @@ struct IntroduceExplicitGlobalContextPass
111126
GlobalObjectKind hoistableGlobalObjectKind = GlobalObjectKind::All;
112127
bool requiresFuncTypeCorrectionPass = false;
113128
AddressSpace addressSpaceOfLocals = AddressSpace::ThreadLocal;
129+
CodeGenTarget target;
114130
};
115131

116132
IntroduceExplicitGlobalContextPass(IRModule* module, CodeGenTarget target)
@@ -134,7 +150,7 @@ struct IntroduceExplicitGlobalContextPass
134150

135151
bool canHoistType(GlobalObjectKind hoistable) { return m_options.canHoistType(hoistable); }
136152

137-
bool canHoistGlobalVar(IRGlobalVar* inst) { return m_options.canHoistGlobalVar(inst); }
153+
bool canHoistGlobalVar(IRInst* inst) { return m_options.canHoistGlobalVar(inst); }
138154

139155
void processModule()
140156
{
@@ -183,6 +199,8 @@ struct IntroduceExplicitGlobalContextPass
183199
//
184200
auto globalParam = cast<IRGlobalParam>(inst);
185201

202+
if (!canHoistGlobalVar(globalParam))
203+
continue;
186204

187205
// One detail we need to be careful about is that as a result
188206
// of legalizing the varying parameters of compute kernels to

0 commit comments

Comments
 (0)