Skip to content

Commit a217ac7

Browse files
[SPIR-V] Initialize base classes first (microsoft#5894)
When using an initializer list to initialize a class with base classes, the base classes should be initialized first, and then used as members of the child class. This seems to be something of a niche case, but it is one of the asserts that are failing for microsoft#5638.
1 parent e44cae1 commit a217ac7

File tree

4 files changed

+129
-97
lines changed

4 files changed

+129
-97
lines changed

tools/clang/lib/SPIRV/InitListHandler.cpp

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -394,7 +394,30 @@ InitListHandler::createInitForStructType(QualType type, SourceLocation srcLoc,
394394
}
395395

396396
llvm::SmallVector<SpirvInstruction *, 4> fields;
397+
398+
// Initialize base classes first.
399+
llvm::SmallVector<SpirvInstruction *, 4> base_fields;
397400
const RecordDecl *structDecl = type->getAsStructureType()->getDecl();
401+
if (auto *cxxStructDecl = dyn_cast<CXXRecordDecl>(structDecl)) {
402+
for (CXXBaseSpecifier base : cxxStructDecl->bases()) {
403+
QualType baseType = base.getType();
404+
const RecordType *baseStructType = baseType->getAsStructureType();
405+
if (baseStructType == nullptr) {
406+
continue;
407+
}
408+
const RecordDecl *baseStructDecl = baseStructType->getDecl();
409+
for (const auto *field : baseStructDecl->fields()) {
410+
base_fields.push_back(
411+
createInitForType(field->getType(), field->getLocation(), range));
412+
if (!base_fields.back())
413+
return nullptr;
414+
}
415+
fields.push_back(spvBuilder.createCompositeConstruct(
416+
baseType, base_fields, srcLoc, range));
417+
base_fields.clear();
418+
}
419+
}
420+
398421
for (const auto *field : structDecl->fields()) {
399422
fields.push_back(
400423
createInitForType(field->getType(), field->getLocation(), range));

tools/clang/test/CodeGenSPIRV/var.init.struct.hlsl

Lines changed: 0 additions & 96 deletions
This file was deleted.
Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
// RUN: %dxc -T vs_6_0 -E main -fcgl %s -spirv | FileCheck %s
2+
3+
struct S {
4+
int3 a;
5+
uint b;
6+
float2x2 c;
7+
};
8+
9+
struct T {
10+
// Same fields as S
11+
int3 h;
12+
uint i;
13+
float2x2 j;
14+
15+
// Additional field
16+
bool2 k;
17+
18+
// Embedded S
19+
S l;
20+
21+
// Similar to S but need some casts
22+
float3 m;
23+
int n;
24+
float2x2 o;
25+
};
26+
27+
struct O {
28+
int x;
29+
};
30+
31+
struct P {
32+
O y;
33+
float z;
34+
};
35+
36+
struct Q : O {
37+
float z;
38+
};
39+
40+
struct W {
41+
float4 color;
42+
};
43+
44+
void main() {
45+
// CHECK-LABEL: %bb_entry = OpLabel
46+
47+
// Flat initializer list
48+
// CHECK: [[a:%[0-9]+]] = OpCompositeConstruct %v3int %int_1 %int_2 %int_3
49+
// CHECK-NEXT: [[c0:%[0-9]+]] = OpCompositeConstruct %v2float %float_1 %float_2
50+
// CHECK-NEXT: [[c1:%[0-9]+]] = OpCompositeConstruct %v2float %float_3 %float_4
51+
// CHECK-NEXT: [[c:%[0-9]+]] = OpCompositeConstruct %mat2v2float [[c0]] [[c1]]
52+
// CHECK-NEXT: [[s1:%[0-9]+]] = OpCompositeConstruct %S [[a]] %uint_42 [[c]]
53+
// CHECK-NEXT: OpStore %s1 [[s1]]
54+
S s1 = {1, 2, 3, 42, 1., 2., 3., 4.};
55+
56+
// Random parentheses
57+
// CHECK: [[a:%[0-9]+]] = OpCompositeConstruct %v3int %int_1 %int_2 %int_3
58+
// CHECK-NEXT: [[c0:%[0-9]+]] = OpCompositeConstruct %v2float %float_1 %float_2
59+
// CHECK-NEXT: [[c1:%[0-9]+]] = OpCompositeConstruct %v2float %float_3 %float_4
60+
// CHECK-NEXT: [[c:%[0-9]+]] = OpCompositeConstruct %mat2v2float [[c0]] [[c1]]
61+
// CHECK-NEXT: [[s2:%[0-9]+]] = OpCompositeConstruct %S [[a]] %uint_42 [[c]]
62+
// CHECK-NEXT: OpStore %s2 [[s2]]
63+
S s2 = {{1, 2}, 3, {{42}, {{1.}}}, {2., {3., 4.}}};
64+
65+
// Flat initalizer list for nested structs
66+
// CHECK: [[y:%[0-9]+]] = OpCompositeConstruct %O %int_1
67+
// CHECK-NEXT: [[p:%[0-9]+]] = OpCompositeConstruct %P [[y]] %float_2
68+
// CHECK-NEXT: OpStore %p [[p]]
69+
P p = {1, 2.};
70+
71+
// Initalizer list for struct with inheritance.
72+
// CHECK: [[y:%[0-9]+]] = OpCompositeConstruct %O %int_1
73+
// CHECK-NEXT: [[q:%[0-9]+]] = OpCompositeConstruct %Q [[y]] %float_2
74+
// CHECK-NEXT: OpStore %q [[q]]
75+
Q q = {1, 2.};
76+
77+
// Mixed case: use struct as a whole, decomposing struct, type casting
78+
79+
// CHECK-NEXT: [[s1_val:%[0-9]+]] = OpLoad %S %s1
80+
// CHECK-NEXT: [[l:%[0-9]+]] = OpLoad %S %s2
81+
// CHECK-NEXT: [[s2_val:%[0-9]+]] = OpLoad %S %s2
82+
// CHECK-NEXT: [[h:%[0-9]+]] = OpCompositeExtract %v3int [[s1_val]] 0
83+
// CHECK-NEXT: [[i:%[0-9]+]] = OpCompositeExtract %uint [[s1_val]] 1
84+
// CHECK-NEXT: [[j:%[0-9]+]] = OpCompositeExtract %mat2v2float [[s1_val]] 2
85+
86+
// CHECK-NEXT: [[k:%[0-9]+]] = OpCompositeConstruct %v2bool %true %false
87+
88+
// CHECK-NEXT: [[s2av:%[0-9]+]] = OpCompositeExtract %v3int [[s2_val]] 0
89+
// CHECK-NEXT: [[s2bv:%[0-9]+]] = OpCompositeExtract %uint [[s2_val]] 1
90+
// CHECK-NEXT: [[o:%[0-9]+]] = OpCompositeExtract %mat2v2float [[s2_val]] 2
91+
// CHECK-NEXT: [[m:%[0-9]+]] = OpConvertSToF %v3float [[s2av]]
92+
// CHECK-NEXT: [[n:%[0-9]+]] = OpBitcast %int [[s2bv]]
93+
// CHECK-NEXT: [[t:%[0-9]+]] = OpCompositeConstruct %T [[h]] [[i]] [[j]] [[k]] [[l]] [[m]] [[n]] [[o]]
94+
// CHECK-NEXT: OpStore %t [[t]]
95+
T t = {s1, // Decomposing struct
96+
true, false, // constructing field from scalar
97+
s2, // Embedded struct
98+
s2 // Decomposing struct + type casting
99+
};
100+
101+
// Using InitListExpr
102+
// CHECK: [[int4_zero:%[0-9]+]] = OpCompositeConstruct %v4int %int_0 %int_0 %int_0 %int_0
103+
// CHECK-NEXT: [[float4_zero:%[0-9]+]] = OpConvertSToF %v4float [[int4_zero]]
104+
// CHECK-NEXT: {{%[0-9]+}} = OpCompositeConstruct %W [[float4_zero]]
105+
W w = { (0).xxxx };
106+
}

tools/clang/unittests/SPIRV/CodeGenSpirvTest.cpp

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -163,7 +163,6 @@ TEST_F(FileTest, LiteralVecTimesScalar) {
163163

164164
// For variables
165165
TEST_F(FileTest, VarInitScalarVector) { runFileTest("var.init.hlsl"); }
166-
TEST_F(FileTest, VarInitStruct) { runFileTest("var.init.struct.hlsl"); }
167166
TEST_F(FileTest, VarInitArray) { runFileTest("var.init.array.hlsl"); }
168167

169168
TEST_F(FileTest, VarInitCrossStorageClass) {

0 commit comments

Comments
 (0)