Skip to content

Commit ddf3d55

Browse files
author
Tim Foley
authored
Change how global-scope constants are handled (shader-slang#1001)
Before this change, global and function-scope `static const` declarations were represented as instructions of type `IRGlobalConstant`, which was represented similarly to an `IRGlobalVar`: with a "body" block of instructions that compute/return the initial value. This representation inhibited optimizations (because a reference to a global constant would not in general be replaced with a reference to its value), and also caused problems for resource type legalization because the logic for type legalization did not (and still does not) handle initializers on globals (so global *variables* that contain resource types are still unsupported). The change here is simple at the high level: we get rid of `IRGlobalConstant` and instead handle global-scope constants as "ordinary" instructions at the global scope. E.g., if we have a declaration like: static const int a[] = { ... } that will be represented in the IR as a `makeArray` instruction at the global scope, referencing other global-scope instructions that represent the values in the array. This simple choice addresses both of the main limitations. A `static const` variable of integer/float/whatever type is now represented as just a reference to the given IR value and thus enables all the same optimizations. When a `static const` variable uses a type with resources, the existing legalization logic (which can handle most of the "ordinary" instructions already) applies. Another secondary benefit of this approach is that the hacky `IREmitMode` enumeration is no longer needed to help us special-case source code emit for `static const` variables. Beyond just removing `IRGlobalConstant`, and updating the lowering logic to use the initializer direclty, the main change here is to the emit logic to make it properly handle "ordinary" instructions that might appear at global scope. One open issue with this change, that could be addressed in a follow-up change, is that "extern" global constants that need to be imported from another module (but which might not have a known value when the current module is compiled) aren't supported - we don't have a way to put a linkage decoration on them. A future change might re-introduce global constants as a distinct IR instruction type that just references the value as an operand (if it is available). We would then need to replace references to an IR constant with references to its value right after linking.
1 parent 749634a commit ddf3d55

19 files changed

+298
-395
lines changed

.gitignore

+5
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,11 @@ build.*/
2323
*.actual.png
2424
*.actual.txt
2525

26+
tests/**/*.exp
27+
tests/**/*.lib
28+
tests/**/*.dll
29+
tests/**/*.cpp
30+
2631
# Files generated by other shader compilers
2732

2833
*.spv

source/slang/slang-emit-c-like.cpp

+93-149
Large diffs are not rendered by default.

source/slang/slang-emit-c-like.h

+13-25
Original file line numberDiff line numberDiff line change
@@ -63,13 +63,6 @@ class CLikeSourceEmitter: public RefObject
6363
kESemanticMask_Default = kESemanticMask_NoPackOffset,
6464
};
6565

66-
// Hack to allow IR emit for global constant to override behavior
67-
enum class IREmitMode
68-
{
69-
Default,
70-
GlobalConstant,
71-
};
72-
7366
struct IRDeclaratorInfo;
7467
struct EDeclarator;
7568
struct ComputeEmitActionsContext;
@@ -184,11 +177,11 @@ class CLikeSourceEmitter: public RefObject
184177
void emitDeclarator(IRDeclaratorInfo* declarator);
185178
void emitSimpleValue(IRInst* inst);
186179

187-
bool shouldFoldInstIntoUseSites(IRInst* inst, IREmitMode mode);
180+
bool shouldFoldInstIntoUseSites(IRInst* inst);
188181

189-
void emitOperand(IRInst* inst, IREmitMode mode, EmitOpInfo const& outerPrec);
182+
void emitOperand(IRInst* inst, EmitOpInfo const& outerPrec);
190183

191-
void emitArgs(IRInst* inst, IREmitMode mode);
184+
void emitArgs(IRInst* inst);
192185

193186

194187
void emitRateQualifiers(IRInst* value);
@@ -206,23 +199,21 @@ class CLikeSourceEmitter: public RefObject
206199
IRCall* inst,
207200
IRFunc* /* func */,
208201
IRTargetIntrinsicDecoration* targetIntrinsic,
209-
IREmitMode mode,
210-
EmitOpInfo const& inOuterPrec);
202+
EmitOpInfo const& inOuterPrec);
211203

212204
void emitIntrinsicCallExpr(
213-
IRCall* inst,
214-
IRFunc* func,
215-
IREmitMode mode,
216-
EmitOpInfo const& inOuterPrec);
205+
IRCall* inst,
206+
IRFunc* func,
207+
EmitOpInfo const& inOuterPrec);
217208

218-
void emitCallExpr(IRCall* inst, IREmitMode mode, EmitOpInfo outerPrec);
209+
void emitCallExpr(IRCall* inst, EmitOpInfo outerPrec);
219210

220-
void emitInstExpr(IRInst* inst, IREmitMode mode, EmitOpInfo const& inOuterPrec);
221-
void defaultEmitInstExpr(IRInst* inst, IREmitMode mode, EmitOpInfo const& inOuterPrec);
211+
void emitInstExpr(IRInst* inst, EmitOpInfo const& inOuterPrec);
212+
void defaultEmitInstExpr(IRInst* inst, EmitOpInfo const& inOuterPrec);
222213

223214
BaseType extractBaseType(IRType* inType);
224215

225-
void emitInst(IRInst* inst, IREmitMode mode);
216+
void emitInst(IRInst* inst);
226217

227218
void emitSemantics(VarLayout* varLayout);
228219
void emitSemantics(IRInst* inst);
@@ -302,9 +293,6 @@ class CLikeSourceEmitter: public RefObject
302293

303294
void emitGlobalVar(IRGlobalVar* varDecl);
304295
void emitGlobalParam(IRGlobalParam* varDecl);
305-
void emitGlobalConstantInitializer(IRGlobalConstant* valDecl);
306-
307-
void emitGlobalConstant(IRGlobalConstant* valDecl);
308296

309297
void emitGlobalInst(IRInst* inst);
310298

@@ -356,12 +344,12 @@ class CLikeSourceEmitter: public RefObject
356344
virtual void handleCallExprDecorationsImpl(IRInst* funcValue) { SLANG_UNUSED(funcValue); }
357345

358346
virtual bool tryEmitGlobalParamImpl(IRGlobalParam* varDecl, IRType* varType) { SLANG_UNUSED(varDecl); SLANG_UNUSED(varType); return false; }
359-
virtual bool tryEmitInstExprImpl(IRInst* inst, IREmitMode mode, const EmitOpInfo& inOuterPrec) { SLANG_UNUSED(inst); SLANG_UNUSED(mode); SLANG_UNUSED(inOuterPrec); return false; }
347+
virtual bool tryEmitInstExprImpl(IRInst* inst, const EmitOpInfo& inOuterPrec) { SLANG_UNUSED(inst); SLANG_UNUSED(inOuterPrec); return false; }
360348

361349
void _emitArrayType(IRArrayType* arrayType, EDeclarator* declarator);
362350
void _emitUnsizedArrayType(IRUnsizedArrayType* arrayType, EDeclarator* declarator);
363351
void _emitType(IRType* type, EDeclarator* declarator);
364-
void _emitInst(IRInst* inst, IREmitMode mode);
352+
void _emitInst(IRInst* inst);
365353

366354
BackEndCompileRequest* m_compileRequest = nullptr;
367355

source/slang/slang-emit-cpp.cpp

+25-25
Original file line numberDiff line numberDiff line change
@@ -1076,7 +1076,7 @@ CPPSourceEmitter::SpecializedIntrinsic CPPSourceEmitter::getSpecializedOperation
10761076
return specOp;
10771077
}
10781078

1079-
void CPPSourceEmitter::emitCall(const SpecializedIntrinsic& specOp, IRInst* inst, const IRUse* operands, int numOperands, CLikeSourceEmitter::IREmitMode mode, const EmitOpInfo& inOuterPrec)
1079+
void CPPSourceEmitter::emitCall(const SpecializedIntrinsic& specOp, IRInst* inst, const IRUse* operands, int numOperands, const EmitOpInfo& inOuterPrec)
10801080
{
10811081
SLANG_UNUSED(inOuterPrec);
10821082
SourceWriter* writer = getSourceWriter();
@@ -1107,7 +1107,7 @@ void CPPSourceEmitter::emitCall(const SpecializedIntrinsic& specOp, IRInst* inst
11071107
{
11081108
writer->emit(", ");
11091109
}
1110-
emitOperand(operands[i].get(), mode, getInfo(EmitOp::General));
1110+
emitOperand(operands[i].get(), getInfo(EmitOp::General));
11111111
}
11121112

11131113
writer->emitChar('}');
@@ -1131,7 +1131,7 @@ void CPPSourceEmitter::emitCall(const SpecializedIntrinsic& specOp, IRInst* inst
11311131
{
11321132
writer->emit(", ");
11331133
}
1134-
emitOperand(operands[j].get(), mode, getInfo(EmitOp::General));
1134+
emitOperand(operands[j].get(), getInfo(EmitOp::General));
11351135
}
11361136

11371137
writer->emitChar('}');
@@ -1146,7 +1146,7 @@ void CPPSourceEmitter::emitCall(const SpecializedIntrinsic& specOp, IRInst* inst
11461146
writer->emit(getBuiltinTypeName(retType->op));
11471147
writer->emitChar('(');
11481148

1149-
emitOperand(operands[0].get(), mode, getInfo(EmitOp::General));
1149+
emitOperand(operands[0].get(), getInfo(EmitOp::General));
11501150

11511151
writer->emitChar(')');
11521152
break;
@@ -1166,7 +1166,7 @@ void CPPSourceEmitter::emitCall(const SpecializedIntrinsic& specOp, IRInst* inst
11661166

11671167
if (elementCount == 1)
11681168
{
1169-
defaultEmitInstExpr(inst, mode, inOuterPrec);
1169+
defaultEmitInstExpr(inst, inOuterPrec);
11701170
}
11711171
else
11721172
{
@@ -1185,7 +1185,7 @@ void CPPSourceEmitter::emitCall(const SpecializedIntrinsic& specOp, IRInst* inst
11851185
auto outerPrec = getInfo(EmitOp::General);
11861186

11871187
auto prec = getInfo(EmitOp::Postfix);
1188-
emitOperand(swizzleInst->getBase(), mode, leftSide(outerPrec, prec));
1188+
emitOperand(swizzleInst->getBase(), leftSide(outerPrec, prec));
11891189

11901190
writer->emit(".");
11911191

@@ -1217,7 +1217,7 @@ void CPPSourceEmitter::emitCall(const SpecializedIntrinsic& specOp, IRInst* inst
12171217
if (isOperator)
12181218
{
12191219
// Just do the default output
1220-
defaultEmitInstExpr(inst, mode, inOuterPrec);
1220+
defaultEmitInstExpr(inst, inOuterPrec);
12211221
}
12221222
else
12231223
{
@@ -1230,7 +1230,7 @@ void CPPSourceEmitter::emitCall(const SpecializedIntrinsic& specOp, IRInst* inst
12301230
{
12311231
writer->emit(", ");
12321232
}
1233-
emitOperand(operands[i].get(), mode, getInfo(EmitOp::General));
1233+
emitOperand(operands[i].get(), getInfo(EmitOp::General));
12341234
}
12351235

12361236
writer->emitChar(')');
@@ -1290,7 +1290,7 @@ StringSlicePool::Handle CPPSourceEmitter::_calcFuncName(const SpecializedIntrins
12901290
}
12911291
}
12921292

1293-
void CPPSourceEmitter::emitOperationCall(IntrinsicOp op, IRInst* inst, IRUse* operands, int operandCount, IRType* retType, CLikeSourceEmitter::IREmitMode mode, const EmitOpInfo& inOuterPrec)
1293+
void CPPSourceEmitter::emitOperationCall(IntrinsicOp op, IRInst* inst, IRUse* operands, int operandCount, IRType* retType, const EmitOpInfo& inOuterPrec)
12941294
{
12951295
if (operandCount > 8)
12961296
{
@@ -1302,7 +1302,7 @@ void CPPSourceEmitter::emitOperationCall(IntrinsicOp op, IRInst* inst, IRUse* op
13021302
argTypes[i] = operands[i].get()->getDataType();
13031303
}
13041304
SpecializedIntrinsic specOp = getSpecializedOperation(op, argTypes.getBuffer(), operandCount, retType);
1305-
emitCall(specOp, inst, operands, operandCount, mode, inOuterPrec);
1305+
emitCall(specOp, inst, operands, operandCount, inOuterPrec);
13061306
}
13071307
else
13081308
{
@@ -1313,7 +1313,7 @@ void CPPSourceEmitter::emitOperationCall(IntrinsicOp op, IRInst* inst, IRUse* op
13131313
argTypes[i] = operands[i].get()->getDataType();
13141314
}
13151315
SpecializedIntrinsic specOp = getSpecializedOperation(op, argTypes, operandCount, retType);
1316-
emitCall(specOp, inst, operands, operandCount, mode, inOuterPrec);
1316+
emitCall(specOp, inst, operands, operandCount, inOuterPrec);
13171317
}
13181318
}
13191319

@@ -1426,7 +1426,7 @@ void CPPSourceEmitter::emitTypeImpl(IRType* type, const StringSliceLoc* nameLoc)
14261426
}
14271427
}
14281428

1429-
void CPPSourceEmitter::emitIntrinsicCallExpr(IRCall* inst, IRFunc* func, IREmitMode mode, EmitOpInfo const& inOuterPrec)
1429+
void CPPSourceEmitter::emitIntrinsicCallExpr(IRCall* inst, IRFunc* func, EmitOpInfo const& inOuterPrec)
14301430
{
14311431
auto outerPrec = inOuterPrec;
14321432
bool needClose = false;
@@ -1492,15 +1492,15 @@ void CPPSourceEmitter::emitIntrinsicCallExpr(IRCall* inst, IRFunc* func, IREmitM
14921492
auto prec = getInfo(EmitOp::Postfix);
14931493
needClose = maybeEmitParens(outerPrec, prec);
14941494

1495-
emitOperand(inst->getOperand(operandIndex++), mode, leftSide(outerPrec, prec));
1495+
emitOperand(inst->getOperand(operandIndex++), leftSide(outerPrec, prec));
14961496
m_writer->emit("[");
1497-
emitOperand(inst->getOperand(operandIndex++), mode, getInfo(EmitOp::General));
1497+
emitOperand(inst->getOperand(operandIndex++), getInfo(EmitOp::General));
14981498
m_writer->emit("]");
14991499

15001500
if (operandIndex < operandCount)
15011501
{
15021502
m_writer->emit(" = ");
1503-
emitOperand(inst->getOperand(operandIndex++), mode, getInfo(EmitOp::General));
1503+
emitOperand(inst->getOperand(operandIndex++), getInfo(EmitOp::General));
15041504
}
15051505

15061506
maybeCloseParens(needClose);
@@ -1520,7 +1520,7 @@ void CPPSourceEmitter::emitIntrinsicCallExpr(IRCall* inst, IRFunc* func, IREmitM
15201520
if (argCount != paramCount)
15211521
{
15221522
// Looks like a member function call
1523-
emitOperand(inst->getOperand(operandIndex), mode, leftSide(outerPrec, prec));
1523+
emitOperand(inst->getOperand(operandIndex), leftSide(outerPrec, prec));
15241524
m_writer->emit(".");
15251525
operandIndex++;
15261526
}
@@ -1530,7 +1530,7 @@ void CPPSourceEmitter::emitIntrinsicCallExpr(IRCall* inst, IRFunc* func, IREmitM
15301530
if (op != IntrinsicOp::Invalid)
15311531
{
15321532
IRUse* operands = inst->getOperands() + operandIndex;
1533-
emitOperationCall(op, inst, operands, int(operandCount - operandIndex), inst->getDataType(), mode, inOuterPrec);
1533+
emitOperationCall(op, inst, operands, int(operandCount - operandIndex), inst->getDataType(), inOuterPrec);
15341534
return;
15351535
}
15361536
}
@@ -1541,14 +1541,14 @@ void CPPSourceEmitter::emitIntrinsicCallExpr(IRCall* inst, IRFunc* func, IREmitM
15411541
for (; operandIndex < operandCount; ++operandIndex)
15421542
{
15431543
if (!first) m_writer->emit(", ");
1544-
emitOperand(inst->getOperand(operandIndex), mode, getInfo(EmitOp::General));
1544+
emitOperand(inst->getOperand(operandIndex), getInfo(EmitOp::General));
15451545
first = false;
15461546
}
15471547
m_writer->emit(")");
15481548
maybeCloseParens(needClose);
15491549
}
15501550

1551-
bool CPPSourceEmitter::tryEmitInstExprImpl(IRInst* inst, IREmitMode mode, const EmitOpInfo& inOuterPrec)
1551+
bool CPPSourceEmitter::tryEmitInstExprImpl(IRInst* inst, const EmitOpInfo& inOuterPrec)
15521552
{
15531553
SLANG_UNUSED(inOuterPrec);
15541554

@@ -1558,24 +1558,24 @@ bool CPPSourceEmitter::tryEmitInstExprImpl(IRInst* inst, IREmitMode mode, const
15581558
case kIROp_makeVector:
15591559
case kIROp_MakeMatrix:
15601560
{
1561-
emitOperationCall(IntrinsicOp::Init, inst, inst->getOperands(), int(inst->getOperandCount()), inst->getDataType(), mode, inOuterPrec);
1561+
emitOperationCall(IntrinsicOp::Init, inst, inst->getOperands(), int(inst->getOperandCount()), inst->getDataType(), inOuterPrec);
15621562
return true;
15631563
}
15641564
case kIROp_Mul_Matrix_Matrix:
15651565
case kIROp_Mul_Matrix_Vector:
15661566
case kIROp_Mul_Vector_Matrix:
15671567
{
1568-
emitOperationCall(IntrinsicOp::VecMatMul, inst, inst->getOperands(), int(inst->getOperandCount()), inst->getDataType(), mode, inOuterPrec);
1568+
emitOperationCall(IntrinsicOp::VecMatMul, inst, inst->getOperands(), int(inst->getOperandCount()), inst->getDataType(), inOuterPrec);
15691569
return true;
15701570
}
15711571
case kIROp_Dot:
15721572
{
1573-
emitOperationCall(IntrinsicOp::Dot, inst, inst->getOperands(), int(inst->getOperandCount()), inst->getDataType(), mode, inOuterPrec);
1573+
emitOperationCall(IntrinsicOp::Dot, inst, inst->getOperands(), int(inst->getOperandCount()), inst->getDataType(), inOuterPrec);
15741574
return true;
15751575
}
15761576
case kIROp_swizzle:
15771577
{
1578-
emitOperationCall(IntrinsicOp::Swizzle, inst, inst->getOperands(), int(inst->getOperandCount()), inst->getDataType(), mode, inOuterPrec);
1578+
emitOperationCall(IntrinsicOp::Swizzle, inst, inst->getOperands(), int(inst->getOperandCount()), inst->getDataType(), inOuterPrec);
15791579
return true;
15801580
}
15811581
case kIROp_Call:
@@ -1589,7 +1589,7 @@ bool CPPSourceEmitter::tryEmitInstExprImpl(IRInst* inst, IREmitMode mode, const
15891589
// that we can emit it directly without mangling, etc.
15901590
if (auto irFunc = asTargetIntrinsic(funcValue))
15911591
{
1592-
emitIntrinsicCallExpr(static_cast<IRCall*>(inst), irFunc, mode, inOuterPrec);
1592+
emitIntrinsicCallExpr(static_cast<IRCall*>(inst), irFunc, inOuterPrec);
15931593
return true;
15941594
}
15951595

@@ -1600,7 +1600,7 @@ bool CPPSourceEmitter::tryEmitInstExprImpl(IRInst* inst, IREmitMode mode, const
16001600
IntrinsicOp op = getOperation(inst->op);
16011601
if (op != IntrinsicOp::Invalid)
16021602
{
1603-
emitOperationCall(op, inst, inst->getOperands(), int(inst->getOperandCount()), inst->getDataType(), mode, inOuterPrec);
1603+
emitOperationCall(op, inst, inst->getOperands(), int(inst->getOperandCount()), inst->getDataType(), inOuterPrec);
16041604
return true;
16051605
}
16061606
return false;

source/slang/slang-emit-cpp.h

+4-4
Original file line numberDiff line numberDiff line change
@@ -153,11 +153,11 @@ class CPPSourceEmitter: public CLikeSourceEmitter
153153

154154
virtual SpecializedIntrinsic getSpecializedOperation(IntrinsicOp op, IRType*const* argTypes, int argTypesCount, IRType* retType);
155155
virtual void useType(IRType* type);
156-
virtual void emitCall(const SpecializedIntrinsic& specOp, IRInst* inst, const IRUse* operands, int numOperands, CLikeSourceEmitter::IREmitMode mode, const EmitOpInfo& inOuterPrec);
156+
virtual void emitCall(const SpecializedIntrinsic& specOp, IRInst* inst, const IRUse* operands, int numOperands, const EmitOpInfo& inOuterPrec);
157157
virtual void emitTypeDefinition(IRType* type);
158158
virtual void emitSpecializedOperationDefinition(const SpecializedIntrinsic& specOp);
159159

160-
void emitOperationCall(IntrinsicOp op, IRInst* inst, IRUse* operands, int operandCount, IRType* retType, CLikeSourceEmitter::IREmitMode mode, const EmitOpInfo& inOuterPrec);
160+
void emitOperationCall(IntrinsicOp op, IRInst* inst, IRUse* operands, int operandCount, IRType* retType, const EmitOpInfo& inOuterPrec);
161161

162162
static UnownedStringSlice getBuiltinTypeName(IROp op);
163163

@@ -179,10 +179,10 @@ class CPPSourceEmitter: public CLikeSourceEmitter
179179
virtual void emitSimpleTypeImpl(IRType* type) SLANG_OVERRIDE;
180180
virtual void emitTypeImpl(IRType* type, const StringSliceLoc* nameLoc) SLANG_OVERRIDE;
181181
virtual void emitVectorTypeNameImpl(IRType* elementType, IRIntegerValue elementCount) SLANG_OVERRIDE;
182-
virtual bool tryEmitInstExprImpl(IRInst* inst, IREmitMode mode, const EmitOpInfo& inOuterPrec) SLANG_OVERRIDE;
182+
virtual bool tryEmitInstExprImpl(IRInst* inst, const EmitOpInfo& inOuterPrec) SLANG_OVERRIDE;
183183
virtual void emitPreprocessorDirectivesImpl() SLANG_OVERRIDE;
184184

185-
void emitIntrinsicCallExpr(IRCall* inst, IRFunc* func, IREmitMode mode, EmitOpInfo const& inOuterPrec);
185+
void emitIntrinsicCallExpr(IRCall* inst, IRFunc* func, EmitOpInfo const& inOuterPrec);
186186

187187
void _emitVecMatMulDefinition(const UnownedStringSlice& funcName, const SpecializedIntrinsic& specOp);
188188

0 commit comments

Comments
 (0)