diff --git a/src/writer/spirv/builder.cc b/src/writer/spirv/builder.cc index 4d8e140dc7..be2c64ee3e 100644 --- a/src/writer/spirv/builder.cc +++ b/src/writer/spirv/builder.cc @@ -215,6 +215,9 @@ uint32_t Builder::GenerateExpression(ast::Expression* expr) { if (expr->IsIdentifier()) { return GenerateIdentifierExpression(expr->AsIdentifier()); } + if (expr->IsMemberAccessor()) { + return GenerateAccessorExpression(expr->AsMemberAccessor()); + } if (expr->IsUnaryOp()) { return GenerateUnaryOpExpression(expr->AsUnaryOp()); } @@ -479,7 +482,14 @@ uint32_t Builder::GenerateAccessorExpression(ast::Expression* expr) { break; } - idx_list.insert(idx_list.begin(), Operand::Int(i)); + + ast::type::U32Type u32; + ast::IntLiteral idx(&u32, i); + auto idx_id = GenerateLiteralIfNeeded(&idx); + if (idx_id == 0) { + return false; + } + idx_list.insert(idx_list.begin(), Operand::Int(idx_id)); } else if (data_type->IsVector()) { // TODO(dsinclair): Handle swizzle diff --git a/src/writer/spirv/builder_accessor_expression_test.cc b/src/writer/spirv/builder_accessor_expression_test.cc index 53275f30d5..9aa4a0efc3 100644 --- a/src/writer/spirv/builder_accessor_expression_test.cc +++ b/src/writer/spirv/builder_accessor_expression_test.cc @@ -16,11 +16,15 @@ #include "src/ast/array_accessor_expression.h" #include "src/ast/identifier_expression.h" #include "src/ast/int_literal.h" +#include "src/ast/member_accessor_expression.h" #include "src/ast/module.h" #include "src/ast/scalar_constructor_expression.h" +#include "src/ast/struct.h" +#include "src/ast/struct_member.h" #include "src/ast/type/array_type.h" #include "src/ast/type/f32_type.h" #include "src/ast/type/i32_type.h" +#include "src/ast/type/struct_type.h" #include "src/ast/type/vector_type.h" #include "src/ast/variable.h" #include "src/context.h" @@ -125,6 +129,123 @@ TEST_F(BuilderTest, ArrayAccessor_MultiLevel) { )"); } +TEST_F(BuilderTest, MemberAccessor) { + ast::type::F32Type f32; + + ast::StructMemberDecorationList decos; + ast::StructMemberList members; + members.push_back( + std::make_unique("a", &f32, std::move(decos))); + members.push_back( + std::make_unique("b", &f32, std::move(decos))); + + auto s = std::make_unique(ast::StructDecoration::kNone, + std::move(members)); + ast::type::StructType s_type(std::move(s)); + s_type.set_name("my_struct"); + + ast::Variable var("ident", ast::StorageClass::kFunction, &s_type); + + ast::MemberAccessorExpression expr( + std::make_unique("ident"), + std::make_unique("b")); + + Context ctx; + ast::Module mod; + TypeDeterminer td(&ctx, &mod); + td.RegisterVariableForTesting(&var); + ASSERT_TRUE(td.DetermineResultType(&expr)) << td.error(); + + Builder b(&mod); + b.push_function(Function{}); + ASSERT_TRUE(b.GenerateFunctionVariable(&var)) << b.error(); + + EXPECT_EQ(b.GenerateAccessorExpression(&expr), 5u); + + EXPECT_EQ(DumpInstructions(b.types()), R"(%4 = OpTypeFloat 32 +%3 = OpTypeStruct %4 %4 +%2 = OpTypePointer Function %3 +%6 = OpTypeInt 32 0 +%7 = OpConstant %6 1 +%8 = OpTypePointer Function %4 +)"); + EXPECT_EQ(DumpInstructions(b.functions()[0].variables()), + R"(%1 = OpVariable %2 Function +)"); + EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), + R"(%5 = OpAccessChain %8 %1 %7 +)"); +} + +TEST_F(BuilderTest, MemberAccessor_Nested) { + ast::type::F32Type f32; + + ast::StructMemberDecorationList decos; + ast::StructMemberList inner_members; + inner_members.push_back( + std::make_unique("a", &f32, std::move(decos))); + inner_members.push_back( + std::make_unique("b", &f32, std::move(decos))); + + ast::type::StructType inner_struct(std::make_unique( + ast::StructDecoration::kNone, std::move(inner_members))); + + ast::StructMemberList outer_members; + outer_members.push_back(std::make_unique( + "inner", &inner_struct, std::move(decos))); + + ast::type::StructType s_type(std::make_unique( + ast::StructDecoration::kNone, std::move(outer_members))); + s_type.set_name("my_struct"); + + ast::Variable var("ident", ast::StorageClass::kFunction, &s_type); + + ast::MemberAccessorExpression expr( + std::make_unique( + std::make_unique("ident"), + std::make_unique("inner")), + std::make_unique("a")); + + Context ctx; + ast::Module mod; + TypeDeterminer td(&ctx, &mod); + td.RegisterVariableForTesting(&var); + ASSERT_TRUE(td.DetermineResultType(&expr)) << td.error(); + + Builder b(&mod); + b.push_function(Function{}); + ASSERT_TRUE(b.GenerateFunctionVariable(&var)) << b.error(); + + EXPECT_EQ(b.GenerateAccessorExpression(&expr), 6u); + + EXPECT_EQ(DumpInstructions(b.types()), R"(%5 = OpTypeFloat 32 +%4 = OpTypeStruct %5 %5 +%3 = OpTypeStruct %4 +%2 = OpTypePointer Function %3 +%7 = OpTypeInt 32 0 +%8 = OpConstant %7 0 +%9 = OpTypePointer Function %5 +)"); + EXPECT_EQ(DumpInstructions(b.functions()[0].variables()), + R"(%1 = OpVariable %2 Function +)"); + EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), + R"(%6 = OpAccessChain %9 %1 %8 %8 +)"); +} + +TEST_F(BuilderTest, DISABLED_MemberAccessor_Swizzle_Single) { + // vec.x +} + +TEST_F(BuilderTest, DISABLED_MemberAccessor_Swizzle_Multiple) { + // vec.xy +} + +TEST_F(BuilderTest, DISABLED_Accessor_Mixed) { + // a[0].foo[2].bar.baz.yx +} + } // namespace } // namespace spirv } // namespace writer