[spirv-writer] Handle non-pointer struct member accessors

These map to OpCompositeExtract instructions.

Fixed: tint:662
Change-Id: Ibd865bdb16326de7932157cbdfe543394415b3ff
Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/45940
Auto-Submit: James Price <jrprice@google.com>
Kokoro: Kokoro <noreply+kokoro@google.com>
Reviewed-by: Ben Clayton <bclayton@google.com>
Reviewed-by: David Neto <dneto@google.com>
Commit-Queue: James Price <jrprice@google.com>
This commit is contained in:
James Price 2021-03-25 20:16:48 +00:00 committed by Commit Bot service account
parent cea744d558
commit ea855a9144
2 changed files with 112 additions and 44 deletions

View File

@ -861,30 +861,43 @@ bool Builder::GenerateMemberAccessor(ast::MemberAccessorExpression* expr,
// If the data_type is a structure we're accessing a member, if it's a // If the data_type is a structure we're accessing a member, if it's a
// vector we're accessing a swizzle. // vector we're accessing a swizzle.
if (data_type->Is<type::Struct>()) { if (data_type->Is<type::Struct>()) {
if (!info->source_type->Is<type::Pointer>()) {
error_ =
"Attempting to access a struct member on a non-pointer. Something is "
"wrong";
return false;
}
auto* strct = data_type->As<type::Struct>()->impl(); auto* strct = data_type->As<type::Struct>()->impl();
auto symbol = expr->member()->symbol(); auto symbol = expr->member()->symbol();
uint32_t i = 0; uint32_t idx = 0;
for (; i < strct->members().size(); ++i) { for (; idx < strct->members().size(); ++idx) {
auto* member = strct->members()[i]; auto* member = strct->members()[idx];
if (member->symbol() == symbol) { if (member->symbol() == symbol) {
break; break;
} }
} }
auto idx_id = GenerateConstantIfNeeded(ScalarConstant::U32(i)); if (info->source_type->Is<type::Pointer>()) {
if (idx_id == 0) { auto idx_id = GenerateConstantIfNeeded(ScalarConstant::U32(idx));
return 0; if (idx_id == 0) {
return 0;
}
info->access_chain_indices.push_back(idx_id);
info->source_type = expr_type;
} else {
auto result_type_id = GenerateTypeIfNeeded(expr_type);
if (result_type_id == 0) {
return false;
}
auto extract = result_op();
auto extract_id = extract.to_i();
if (!push_function_inst(
spv::Op::OpCompositeExtract,
{Operand::Int(result_type_id), extract,
Operand::Int(info->source_id), Operand::Int(idx)})) {
return false;
}
info->source_id = extract_id;
info->source_type = expr_type;
} }
info->access_chain_indices.push_back(idx_id);
info->source_type = expr_type;
return true; return true;
} }

View File

@ -255,6 +255,7 @@ TEST_F(BuilderTest, MemberAccessor) {
TEST_F(BuilderTest, MemberAccessor_Nested) { TEST_F(BuilderTest, MemberAccessor_Nested) {
// inner_struct { // inner_struct {
// a : f32 // a : f32
// b : f32
// } // }
// my_struct { // my_struct {
// inner : inner_struct // inner : inner_struct
@ -270,7 +271,7 @@ TEST_F(BuilderTest, MemberAccessor_Nested) {
auto* s_type = Structure("my_struct", {Member("inner", inner_struct)}); auto* s_type = Structure("my_struct", {Member("inner", inner_struct)});
auto* var = Global("ident", s_type, ast::StorageClass::kFunction); auto* var = Global("ident", s_type, ast::StorageClass::kFunction);
auto* expr = MemberAccessor(MemberAccessor("ident", "inner"), "a"); auto* expr = MemberAccessor(MemberAccessor("ident", "inner"), "b");
WrapInFunction(expr); WrapInFunction(expr);
spirv::Builder& b = Build(); spirv::Builder& b = Build();
@ -278,7 +279,7 @@ TEST_F(BuilderTest, MemberAccessor_Nested) {
b.push_function(Function{}); b.push_function(Function{});
ASSERT_TRUE(b.GenerateFunctionVariable(var)) << b.error(); ASSERT_TRUE(b.GenerateFunctionVariable(var)) << b.error();
EXPECT_EQ(b.GenerateAccessorExpression(expr), 10u); EXPECT_EQ(b.GenerateAccessorExpression(expr), 11u);
EXPECT_EQ(DumpInstructions(b.types()), R"(%5 = OpTypeFloat 32 EXPECT_EQ(DumpInstructions(b.types()), R"(%5 = OpTypeFloat 32
%4 = OpTypeStruct %5 %5 %4 = OpTypeStruct %5 %5
@ -287,13 +288,92 @@ TEST_F(BuilderTest, MemberAccessor_Nested) {
%6 = OpConstantNull %3 %6 = OpConstantNull %3
%7 = OpTypeInt 32 0 %7 = OpTypeInt 32 0
%8 = OpConstant %7 0 %8 = OpConstant %7 0
%9 = OpTypePointer Function %5 %9 = OpConstant %7 1
%10 = OpTypePointer Function %5
)"); )");
EXPECT_EQ(DumpInstructions(b.functions()[0].variables()), EXPECT_EQ(DumpInstructions(b.functions()[0].variables()),
R"(%1 = OpVariable %2 Function %6 R"(%1 = OpVariable %2 Function %6
)"); )");
EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
R"(%10 = OpAccessChain %9 %1 %8 %8 R"(%11 = OpAccessChain %10 %1 %8 %9
)");
}
TEST_F(BuilderTest, MemberAccessor_NonPointer) {
// my_struct {
// a : f32
// b : f32
// }
// const ident : my_struct = my_struct();
// ident.b
auto* s = Structure("my_struct", {
Member("a", ty.f32()),
Member("b", ty.f32()),
});
auto* var = GlobalConst("ident", s, Construct(s, 0.f, 0.f));
auto* expr = MemberAccessor("ident", "b");
WrapInFunction(expr);
spirv::Builder& b = Build();
b.push_function(Function{});
ASSERT_TRUE(b.GenerateFunctionVariable(var)) << b.error();
EXPECT_EQ(b.GenerateAccessorExpression(expr), 5u);
EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 32
%1 = OpTypeStruct %2 %2
%3 = OpConstant %2 0
%4 = OpConstantComposite %1 %3 %3
)");
EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
R"(%5 = OpCompositeExtract %2 %4 1
)");
}
TEST_F(BuilderTest, MemberAccessor_Nested_NonPointer) {
// inner_struct {
// a : f32
// b : f32
// }
// my_struct {
// inner : inner_struct
// }
//
// const ident : my_struct = my_struct();
// ident.inner.a
auto* inner_struct = Structure("Inner", {
Member("a", ty.f32()),
Member("b", ty.f32()),
});
auto* s_type = Structure("my_struct", {Member("inner", inner_struct)});
auto* var = GlobalConst("ident", s_type,
Construct(s_type, Construct(inner_struct, 0.f, 0.f)));
auto* expr = MemberAccessor(MemberAccessor("ident", "inner"), "b");
WrapInFunction(expr);
spirv::Builder& b = Build();
b.push_function(Function{});
ASSERT_TRUE(b.GenerateFunctionVariable(var)) << b.error();
EXPECT_EQ(b.GenerateAccessorExpression(expr), 8u);
EXPECT_EQ(DumpInstructions(b.types()), R"(%3 = OpTypeFloat 32
%2 = OpTypeStruct %3 %3
%1 = OpTypeStruct %2
%4 = OpConstant %3 0
%5 = OpConstantComposite %2 %4 %4
%6 = OpConstantComposite %1 %5
)");
EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
R"(%7 = OpCompositeExtract %2 %6 0
%8 = OpCompositeExtract %3 %7 1
)"); )");
} }
@ -753,31 +833,6 @@ TEST_F(BuilderTest, DISABLED_Accessor_Array_NonPointer) {
// out of the ScalarConstructor as extract requires integer indices. // out of the ScalarConstructor as extract requires integer indices.
} }
TEST_F(BuilderTest, DISABLED_Accessor_Struct_NonPointer) {
// type A = struct {
// a : f32;
// b : f32;
// };
// const b : A;
// b.b
//
// This needs to do an OpCompositeExtract on the struct.
}
TEST_F(BuilderTest, DISABLED_Accessor_NonPointer_Multi) {
// type A = struct {
// a : f32;
// b : vec3<f32, 3>;
// };
// type B = struct {
// c : A;
// }
// const b : array<B, 3>;
// b[2].c.b.yx.x
//
// This needs to do an OpCompositeExtract similar to the AccessChain case
}
} // namespace } // namespace
} // namespace spirv } // namespace spirv
} // namespace writer } // namespace writer