Skip to content

Commit 3dff5a5

Browse files
author
Tim Foley
authored
IR: add lowering for initializer list expressions (shader-slang#290)
* IR: add lowering for initializer list expressions This is relatively straightforward in the easy cases, because the front-end will have already type-checked the elements of the initializer list, and attached an appropriate type to the overall expression. Notes: - We are assuming in this code that if the user provides a "flattened" initializer list when dealing with nested aggregates, then the front-end is responsible for grouping things up apprporiately (this is not actually implemented in the front-end today). - I have only handled arrays and `struct` types here, so uses of initializer lists for anything else will fail. - I have not tried to handle the common HLSL idiom of using `{0}` as a way to default-initialize things, even when their first field is not compatible with the expression `0` - I have not implemented support for default-initializing fields/elements beyond those for which explicit initializers were provided. This can be addressed as a follow-on change. This change is one clear place where the front-end lowering logic could potentially be made much cleaner using a "destination-driven" code generation strategy. For example, given the following code ```hlsl struct A { int a0; a1; }; struct B { A b0; A b1; }; struct C { B c0; B c1; }; // ... C c = { { { 0, 1 }, {2, 3}, }, /* ... */ }; ``` Our current code generator will end up allocating local variables for 1 instance of `C`, two instances of `B`, and four instances of `C`, for over 3x the allocation that would be done by a good destination-driven code generator. Yes, later optimization passes should be able to clean up the waste, but avoiding the waste from the start should result in faster compiles and also easier debugging (since intermediate IR won't be as messy in general). * Fixup: try to appease clang compiler
1 parent ba594d0 commit 3dff5a5

File tree

3 files changed

+114
-2
lines changed

3 files changed

+114
-2
lines changed

source/slang/lower-to-ir.cpp

+80-2
Original file line numberDiff line numberDiff line change
@@ -1107,9 +1107,87 @@ struct ExprLoweringVisitorBase : ExprVisitor<Derived, LoweredValInfo>
11071107
return lowerSubExpr(expr->base);
11081108
}
11091109

1110-
LoweredValInfo visitInitializerListExpr(InitializerListExpr* /*expr*/)
1110+
LoweredValInfo visitInitializerListExpr(InitializerListExpr* expr)
11111111
{
1112-
SLANG_UNIMPLEMENTED_X("codegen for initializer list expression");
1112+
// Allocate a temporary of the given type
1113+
RefPtr<Type> type = lowerSimpleType(context, expr->type);
1114+
LoweredValInfo val = createVar(context, type);
1115+
1116+
UInt argCount = expr->args.Count();
1117+
1118+
// Now for each argument in the initializer list,
1119+
// fill in the appropriate field of the result
1120+
if (auto arrayType = type->As<ArrayExpressionType>())
1121+
{
1122+
UInt elementCount = (UInt) GetIntVal(arrayType->ArrayLength);
1123+
auto elementType = lowerType(context, arrayType->baseType);
1124+
for (UInt ee = 0; ee < elementCount; ++ee)
1125+
{
1126+
IRValue* indexVal = context->irBuilder->getIntValue(
1127+
getIntType(context),
1128+
ee);
1129+
LoweredValInfo elemVal = subscriptValue(
1130+
elementType,
1131+
val,
1132+
indexVal);
1133+
1134+
if (ee < argCount)
1135+
{
1136+
auto argExpr = expr->args[ee];
1137+
LoweredValInfo argVal = lowerRValueExpr(context, argExpr);
1138+
1139+
assign(context, elemVal, argVal);
1140+
}
1141+
else
1142+
{
1143+
SLANG_UNEXPECTED("need to default-initialize array elements");
1144+
}
1145+
}
1146+
}
1147+
else if (auto declRefType = type->As<DeclRefType>())
1148+
{
1149+
DeclRef<Decl> declRef = declRefType->declRef;
1150+
if (auto aggTypeDeclRef = declRef.As<AggTypeDecl>())
1151+
{
1152+
UInt argCounter = 0;
1153+
for (auto ff : getMembersOfType<StructField>(aggTypeDeclRef))
1154+
{
1155+
if (ff.getDecl()->HasModifier<HLSLStaticModifier>())
1156+
continue;
1157+
1158+
auto loweredFieldType = lowerType(
1159+
context,
1160+
GetType(ff));
1161+
LoweredValInfo fieldVal = extractField(
1162+
loweredFieldType,
1163+
val,
1164+
ff);
1165+
1166+
UInt argIndex = argCounter++;
1167+
if (argIndex < argCount)
1168+
{
1169+
auto argExpr = expr->args[argIndex];
1170+
LoweredValInfo argVal = lowerRValueExpr(context, argExpr);
1171+
assign(context, fieldVal, argVal);
1172+
}
1173+
else
1174+
{
1175+
SLANG_UNEXPECTED("need to default-initialize struct fields");
1176+
}
1177+
}
1178+
}
1179+
else
1180+
{
1181+
SLANG_UNEXPECTED("not sure how to initialize this type");
1182+
}
1183+
}
1184+
else
1185+
{
1186+
SLANG_UNEXPECTED("not sure how to initialize this type");
1187+
}
1188+
1189+
1190+
return val;
11131191
}
11141192

11151193
LoweredValInfo visitConstantExpr(ConstantExpr* expr)

tests/compute/initializer-list.slang

+30
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
//TEST(compute):COMPARE_COMPUTE:-xslang -use-ir
2+
3+
//TEST_INPUT: ubuffer(data=[0 0 0 0], stride=4):dxbinding(0),glbinding(0),out
4+
5+
struct Test
6+
{
7+
float4 a;
8+
uint b;
9+
float c;
10+
};
11+
12+
13+
uint test(uint val)
14+
{
15+
Test t = { float4(1.0f), 16, 99.0f };
16+
return val + t.b;
17+
}
18+
19+
RWStructuredBuffer<uint> outputBuffer;
20+
21+
[numthreads(4, 1, 1)]
22+
void computeMain(uint3 dispatchThreadID : SV_DispatchThreadID)
23+
{
24+
uint tid = dispatchThreadID.x;
25+
26+
uint inVal = tid;
27+
uint outVal = test(inVal);
28+
29+
outputBuffer[tid] = outVal;
30+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
10
2+
11
3+
12
4+
13

0 commit comments

Comments
 (0)