Skip to content

Commit ab5b0a7

Browse files
authored
Enable lower-generics pass universally. (shader-slang#1518)
* Enable lower-generics pass universally. * Exclude builtin interfaces and functions from lower-generics pass. * Update stdlib. * Fixup. * Fixes handling of nested intrinsic generic functions. * Fixes. * Fixes.
1 parent e9bf8de commit ab5b0a7

29 files changed

+179
-47
lines changed

source/slang/core.meta.slang

+12
Original file line numberDiff line numberDiff line change
@@ -19,10 +19,12 @@ syntax globallycoherent : GloballyCoherentModifier;
1919

2020
// A type that can be used as an operand for builtins
2121
[sealed]
22+
[builtin]
2223
interface __BuiltinType {}
2324

2425
// A type that can be used for arithmetic operations
2526
[sealed]
27+
[builtin]
2628
interface __BuiltinArithmeticType : __BuiltinType
2729
{
2830
/// Initialize from a 32-bit signed integer value.
@@ -31,23 +33,28 @@ interface __BuiltinArithmeticType : __BuiltinType
3133

3234
/// A type that can be used for logical/bitwsie operations
3335
[sealed]
36+
[builtin]
3437
interface __BuiltinLogicalType : __BuiltinType {}
3538

3639
// A type that logically has a sign (positive/negative/zero)
3740
[sealed]
41+
[builtin]
3842
interface __BuiltinSignedArithmeticType : __BuiltinArithmeticType {}
3943

4044
// A type that can represent integers
4145
[sealed]
46+
[builtin]
4247
interface __BuiltinIntegerType : __BuiltinArithmeticType
4348
{}
4449

4550
// A type that can represent non-integers
4651
[sealed]
52+
[builtin]
4753
interface __BuiltinRealType : __BuiltinSignedArithmeticType {}
4854

4955
// A type that uses a floating-point representation
5056
[sealed]
57+
[builtin]
5158
interface __BuiltinFloatingPointType : __BuiltinRealType
5259
{
5360
/// Initialize from a 32-bit floating-point value.
@@ -58,6 +65,7 @@ interface __BuiltinFloatingPointType : __BuiltinRealType
5865
}
5966

6067
// A type resulting from an `enum` declaration.
68+
[builtin]
6169
__magic_type(EnumTypeType)
6270
interface __EnumType
6371
{
@@ -112,6 +120,7 @@ extension __EnumType
112120

113121
// A type resulting from an `enum` declaration
114122
// with the `[flags]` attribute.
123+
[builtin]
115124
interface __FlagsEnumType : __EnumType
116125
{
117126
};
@@ -2042,3 +2051,6 @@ attribute_syntax [open] : OpenAttribute;
20422051

20432052
__attributeTarget(InterfaceDecl)
20442053
attribute_syntax [anyValueSize(size:int)] : AnyValueSizeAttribute;
2054+
2055+
__attributeTarget(DeclBase)
2056+
attribute_syntax [builtin] : BuiltinAttribute;

source/slang/hlsl.meta.slang

+1
Original file line numberDiff line numberDiff line change
@@ -4302,6 +4302,7 @@ void DispatchMesh<P>(uint threadGroupCountX, uint threadGroupCountY, uint thread
43024302
// But slang enums are always 'enum class like', so I use an empty struct type here
43034303

43044304
[sealed]
4305+
[builtin]
43054306
interface __BuiltinSamplerFeedbackType {};
43064307

43074308
[sealed]

source/slang/slang-ast-modifier.h

+6
Original file line numberDiff line numberDiff line change
@@ -878,6 +878,12 @@ class OpenAttribute : public InheritanceControlAttribute { SLANG_CLASS(OpenAttri
878878
/// An attribute that marks a type declaration as disallowing the type to be inherited from in other modules.
879879
class SealedAttribute : public InheritanceControlAttribute { SLANG_CLASS(SealedAttribute) };
880880

881+
/// An attribute that marks a decl as a compiler built-in object.
882+
class BuiltinAttribute : public Attribute
883+
{
884+
SLANG_CLASS(BuiltinAttribute)
885+
};
886+
881887
/// An attribute that defines the size of `AnyValue` type to represent a polymoprhic value that conforms to
882888
/// the decorated interface type.
883889
class AnyValueSizeAttribute : public Attribute

source/slang/slang-compiler.h

+2-2
Original file line numberDiff line numberDiff line change
@@ -1760,8 +1760,8 @@ namespace Slang
17601760
bool shouldEmitSPIRVDirectly = false;
17611761

17621762

1763-
// If true will allow generating dynamic dispatch code for generics.
1764-
bool allowDynamicCode = false;
1763+
// If true will disable generics/existential value specialization pass.
1764+
bool disableSpecialization = false;
17651765

17661766
String m_dumpIntermediatePrefix;
17671767

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

-8
Original file line numberDiff line numberDiff line change
@@ -299,7 +299,6 @@ void CLikeSourceEmitter::_emitType(IRType* type, EDeclarator* declarator)
299299
void CLikeSourceEmitter::emitWitnessTable(IRWitnessTable* witnessTable)
300300
{
301301
SLANG_UNUSED(witnessTable);
302-
SLANG_DIAGNOSE_UNEXPECTED(getSink(), SourceLoc(), "Unimplemented emit: IROpWitnessTable.");
303302
}
304303

305304
void CLikeSourceEmitter::emitInterface(IRInterfaceType* interfaceType)
@@ -3824,13 +3823,6 @@ void CLikeSourceEmitter::ensureGlobalInst(ComputeEmitActionsContext* ctx, IRInst
38243823
// Skip certain instructions that don't affect output.
38253824
switch(inst->op)
38263825
{
3827-
case kIROp_WitnessTable:
3828-
// Only skip witness tables when we are generating
3829-
// static code.
3830-
if (!m_compileRequest->allowDynamicCode)
3831-
return;
3832-
break;
3833-
38343826
case kIROp_InterfaceRequirementEntry:
38353827
case kIROp_Generic:
38363828
return;

source/slang/slang-emit-cpp.cpp

+5
Original file line numberDiff line numberDiff line change
@@ -1607,6 +1607,11 @@ void CPPSourceEmitter::emitParamTypeImpl(IRType* type, String const& name)
16071607
void CPPSourceEmitter::emitWitnessTable(IRWitnessTable* witnessTable)
16081608
{
16091609
auto interfaceType = cast<IRInterfaceType>(witnessTable->getOperand(0));
1610+
1611+
// Ignore witness tables for builtin interface types.
1612+
if (isBuiltin(interfaceType))
1613+
return;
1614+
16101615
auto witnessTableItems = witnessTable->getChildren();
16111616
_maybeEmitWitnessTableTypeDefinition(interfaceType);
16121617

source/slang/slang-emit.cpp

+11-7
Original file line numberDiff line numberDiff line change
@@ -302,20 +302,20 @@ Result linkAndOptimizeIR(
302302
// perform specialization of functions based on parameter
303303
// values that need to be compile-time constants.
304304
//
305-
if (!compileRequest->allowDynamicCode)
305+
if (!compileRequest->disableSpecialization)
306306
specializeModule(irModule);
307307

308+
eliminateDeadCode(irModule);
309+
308310
switch (target)
309311
{
310312
case CodeGenTarget::CPPSource:
311313
// For targets that supports dynamic dispatch, we need to lower the
312314
// generics / interface types to ordinary functions and types using
313315
// function pointers.
314-
if (compileRequest->allowDynamicCode)
315-
{
316-
lowerGenerics(irModule, sink);
317-
dumpIRIfEnabled(compileRequest, irModule, "LOWER-GENERICS");
318-
}
316+
dumpIRIfEnabled(compileRequest, irModule, "BEFORE-LOWER-GENERICS");
317+
lowerGenerics(irModule, sink);
318+
dumpIRIfEnabled(compileRequest, irModule, "LOWER-GENERICS");
319319
break;
320320
default:
321321
break;
@@ -658,12 +658,16 @@ Result linkAndOptimizeIR(
658658
break;
659659
}
660660

661-
if (!compileRequest->allowDynamicCode)
661+
switch (target)
662662
{
663+
case CodeGenTarget::CPPSource:
664+
break;
665+
default:
663666
// For all targets that don't support true dynamic dispatch through
664667
// witness tables, we need to eliminate witness tables from the IR so
665668
// that they don't keep symbols live that we don't actually need.
666669
stripWitnessTables(irModule);
670+
break;
667671
}
668672

669673
#if 0

source/slang/slang-ir-generics-lowering-context.cpp

+8
Original file line numberDiff line numberDiff line change
@@ -142,13 +142,17 @@ namespace Slang
142142
{
143143
if (auto anyValueSizeDecor = paramType->findDecoration<IRTypeConstraintDecoration>())
144144
{
145+
if (isBuiltin(anyValueSizeDecor->getConstraintType()))
146+
return (IRType*)paramType;
145147
anyValueSize = getInterfaceAnyValueSize(anyValueSizeDecor->getConstraintType(), paramType->sourceLoc);
146148
return builder->getAnyValueType(anyValueSize);
147149
}
148150
sink->diagnose(paramType, Diagnostics::unconstrainedGenericParameterNotAllowedInDynamicFunction, paramType);
149151
return builder->getAnyValueType(kInvalidAnyValueSize);
150152
}
151153
case kIROp_ThisType:
154+
if (isBuiltin(cast<IRThisType>(paramType)->getConstraintType()))
155+
return (IRType*)paramType;
152156
anyValueSize = getInterfaceAnyValueSize(
153157
cast<IRThisType>(paramType)->getConstraintType(),
154158
paramType->sourceLoc);
@@ -159,6 +163,8 @@ namespace Slang
159163
}
160164
case kIROp_InterfaceType:
161165
{
166+
if (isBuiltin(paramType))
167+
return (IRType*)paramType;
162168
// An existential type translates into a tuple of (AnyValue, WitnessTable, RTTI*)
163169
anyValueSize = getInterfaceAnyValueSize(paramType, paramType->sourceLoc);
164170
auto anyValueType = builder->getAnyValueType(anyValueSize);
@@ -172,6 +178,8 @@ namespace Slang
172178
auto lookupInterface = static_cast<IRLookupWitnessMethod*>(paramType);
173179
auto interfaceType = cast<IRInterfaceType>(cast<IRWitnessTableType>(
174180
lookupInterface->getWitnessTable()->getDataType())->getConformanceType());
181+
if (isBuiltin(interfaceType))
182+
return (IRType*)paramType;
175183
// Make sure we are looking up inside the original interface type (prior to lowering).
176184
// Only in the original interface type will an associated type entry have an IRAssociatedType value.
177185
// We need to extract AnyValueSize from this IRAssociatedType.

source/slang/slang-ir-inst-defs.h

+2
Original file line numberDiff line numberDiff line change
@@ -561,6 +561,8 @@ INST(HighLevelDeclDecoration, highLevelDecl, 1, 0)
561561
INST(TypeConstraintDecoration, TypeConstraintDecoration, 1, 0)
562562
INST_RANGE(LinkageDecoration, ImportDecoration, ExportDecoration)
563563

564+
INST(BuiltinDecoration, BuiltinDecoration, 0, 0)
565+
564566
INST(SemanticDecoration, semantic, 2, 0)
565567

566568
INST_RANGE(Decoration, HighLevelDeclDecoration, SemanticDecoration)

source/slang/slang-ir-insts.h

+14
Original file line numberDiff line numberDiff line change
@@ -423,6 +423,15 @@ struct IRNaturalOffsetDecoration : IRDecoration
423423
IRIntegerValue getOffset() { return getOffsetOperand()->getValue(); }
424424
};
425425

426+
struct IRBuiltinDecoration : IRDecoration
427+
{
428+
enum
429+
{
430+
kOp = kIROp_BuiltinDecoration
431+
};
432+
IR_LEAF_ISA(BuiltinDecoration)
433+
};
434+
426435
// An instruction that specializes another IR value
427436
// (representing a generic) to a particular set of generic arguments
428437
// (instructions representing types, witness tables, etc.)
@@ -2457,6 +2466,11 @@ struct IRBuilder
24572466
{
24582467
addDecoration(inst, kIROp_TypeConstraintDecoration, constraintType);
24592468
}
2469+
2470+
void addBuiltinDecoration(IRInst* inst)
2471+
{
2472+
addDecoration(inst, kIROp_BuiltinDecoration);
2473+
}
24602474
};
24612475

24622476
void addHoistableInst(

source/slang/slang-ir-lower-generic-call.cpp

+26-1
Original file line numberDiff line numberDiff line change
@@ -170,6 +170,14 @@ namespace Slang
170170
}
171171
}
172172

173+
IRInst* findInnerMostSpecializingBase(IRSpecialize* inst)
174+
{
175+
auto result = inst->getBase();
176+
while (auto specialize = as<IRSpecialize>(result))
177+
result = specialize->getBase();
178+
return result;
179+
}
180+
173181
void lowerCallToSpecializedFunc(IRCall* callInst, IRSpecialize* specializeInst)
174182
{
175183
// If we see a call(specialize(gFunc, Targs), args),
@@ -180,9 +188,23 @@ namespace Slang
180188
// them here.
181189
if (loweredFunc->op == kIROp_Generic)
182190
{
183-
// This is an intrinsic function, don't transform.
184191
return;
185192
}
193+
else if (loweredFunc->op == kIROp_Specialize)
194+
{
195+
// All nested generic functions are supposed to be flattend before this pass.
196+
// If they are not, they represent an intrinsic function that should not be
197+
// modified in this pass.
198+
auto innerMostFunc = findInnerMostSpecializingBase(static_cast<IRSpecialize*>(loweredFunc));
199+
if (innerMostFunc && innerMostFunc->op == kIROp_Generic)
200+
{
201+
innerMostFunc =
202+
findInnerMostGenericReturnVal(static_cast<IRGeneric*>(innerMostFunc));
203+
}
204+
if (innerMostFunc->findDecoration<IRTargetIntrinsicDecoration>())
205+
return;
206+
SLANG_UNEXPECTED("Nested generics specialization.");
207+
}
186208
IRFuncType* funcType = cast<IRFuncType>(loweredFunc->getDataType());
187209
translateCallInst(callInst, funcType, loweredFunc, specializeInst);
188210
}
@@ -193,6 +215,9 @@ namespace Slang
193215
// all occurences of associatedtypes.
194216
auto funcType = cast<IRFuncType>(lookupInst->getDataType());
195217
auto loweredFunc = lookupInst;
218+
if (isBuiltin(cast<IRWitnessTableType>(
219+
lookupInst->getWitnessTable()->getDataType())->getConformanceType()))
220+
return;
196221
translateCallInst(callInst, funcType, loweredFunc, nullptr);
197222
}
198223

source/slang/slang-ir-lower-generic-function.cpp

+17-1
Original file line numberDiff line numberDiff line change
@@ -21,9 +21,21 @@ namespace Slang
2121
IRInst* result = nullptr;
2222
if (sharedContext->loweredGenericFunctions.TryGetValue(genericValue, result))
2323
return result;
24+
// Do not lower intrinsic functions.
25+
if (genericValue->findDecoration<IRTargetIntrinsicDecoration>())
26+
return genericValue;
2427
auto genericParent = as<IRGeneric>(genericValue);
2528
SLANG_ASSERT(genericParent);
2629
auto func = as<IRFunc>(findGenericReturnVal(genericParent));
30+
if (!func)
31+
{
32+
// Nested generic functions are supposed to be flattened before entering
33+
// this pass. The reason we are still seeing them must be that they are
34+
// intrinsic functions. In this case we ignore the function.
35+
SLANG_ASSERT(findInnerMostGenericReturnVal(genericParent)
36+
->findDecoration<IRTargetIntrinsicDecoration>() != nullptr);
37+
return genericValue;
38+
}
2739
SLANG_ASSERT(func);
2840
if (!func->isDefinition())
2941
{
@@ -133,7 +145,9 @@ namespace Slang
133145
return loweredType;
134146
if (sharedContext->mapLoweredInterfaceToOriginal.ContainsKey(interfaceType))
135147
return interfaceType;
136-
148+
// Do not lower intrinsic interfaces.
149+
if (isBuiltin(interfaceType))
150+
return interfaceType;
137151
List<IRInterfaceRequirementEntry*> newEntries;
138152

139153
IRBuilder builder;
@@ -189,6 +203,8 @@ namespace Slang
189203
auto interfaceType = maybeLowerInterfaceType(cast<IRInterfaceType>(witnessTable->getConformanceType()));
190204
if (interfaceType != witnessTable->getConformanceType())
191205
witnessTable->setConformanceType(interfaceType);
206+
if (isBuiltin(interfaceType))
207+
return;
192208
for (auto child : witnessTable->getChildren())
193209
{
194210
auto entry = as<IRWitnessTableEntry>(child);

source/slang/slang-ir-witness-table-wrapper.cpp

+2
Original file line numberDiff line numberDiff line change
@@ -174,6 +174,8 @@ namespace Slang
174174
void lowerWitnessTable(IRWitnessTable* witnessTable)
175175
{
176176
auto interfaceType = cast<IRInterfaceType>(witnessTable->getConformanceType());
177+
if (isBuiltin(interfaceType))
178+
return;
177179
for (auto child : witnessTable->getChildren())
178180
{
179181
auto entry = as<IRWitnessTableEntry>(child);

source/slang/slang-ir.cpp

+16-1
Original file line numberDiff line numberDiff line change
@@ -5263,6 +5263,7 @@ namespace Slang
52635263
case kIROp_GlobalGenericParam:
52645264
case kIROp_WitnessTable:
52655265
case kIROp_WitnessTableEntry:
5266+
case kIROp_InterfaceRequirementEntry:
52665267
case kIROp_Block:
52675268
return false;
52685269

@@ -5384,6 +5385,14 @@ namespace Slang
53845385
auto val = returnInst->getVal();
53855386
return val;
53865387
}
5388+
5389+
IRInst* findInnerMostGenericReturnVal(IRGeneric* generic)
5390+
{
5391+
IRInst* inst = generic;
5392+
while (auto genericInst = as<IRGeneric>(inst))
5393+
inst = findGenericReturnVal(genericInst);
5394+
return inst;
5395+
}
53875396

53885397
IRGeneric* findSpecializedGeneric(IRSpecialize* specialize)
53895398
{
@@ -5488,9 +5497,15 @@ namespace Slang
54885497
{
54895498
return ptrType && ptrType->op == kIROp_PtrType && ptrType->getOperand(0) == elementType;
54905499
}
5500+
54915501
bool isPointerOfType(IRInst* ptrType, IROp opCode)
54925502
{
54935503
return ptrType && ptrType->op == kIROp_PtrType && ptrType->getOperand(0) &&
54945504
ptrType->getOperand(0)->op == opCode;
54955505
}
5496-
}
5506+
bool isBuiltin(IRInst* inst)
5507+
{
5508+
return inst->findDecoration<IRBuiltinDecoration>() != nullptr;
5509+
}
5510+
} // namespace Slang
5511+

0 commit comments

Comments
 (0)