blob: 34be49008ab6d2e16379892305e182a88037c0cf [file] [log] [blame]
// Copyright 2020 The Tint Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include <memory>
#include "src/ast/array_accessor_expression.h"
#include "src/ast/assignment_statement.h"
#include "src/ast/binary_expression.h"
#include "src/ast/decorated_variable.h"
#include "src/ast/float_literal.h"
#include "src/ast/identifier_expression.h"
#include "src/ast/member_accessor_expression.h"
#include "src/ast/module.h"
#include "src/ast/scalar_constructor_expression.h"
#include "src/ast/sint_literal.h"
#include "src/ast/struct.h"
#include "src/ast/struct_member.h"
#include "src/ast/struct_member_offset_decoration.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/type_constructor_expression.h"
#include "src/context.h"
#include "src/type_determiner.h"
#include "src/writer/hlsl/test_helper.h"
namespace tint {
namespace writer {
namespace hlsl {
namespace {
class HlslGeneratorImplTest_MemberAccessor : public TestHelper,
public testing::Test {};
TEST_F(HlslGeneratorImplTest_MemberAccessor, EmitExpression_MemberAccessor) {
ast::type::F32Type f32;
ast::StructMemberList members;
ast::StructMemberDecorationList deco;
deco.push_back(std::make_unique<ast::StructMemberOffsetDecoration>(0));
members.push_back(
std::make_unique<ast::StructMember>("mem", &f32, std::move(deco)));
auto strct = std::make_unique<ast::Struct>();
strct->set_members(std::move(members));
ast::type::StructType s(std::move(strct));
s.set_name("Str");
auto str_var = std::make_unique<ast::DecoratedVariable>(
std::make_unique<ast::Variable>("str", ast::StorageClass::kPrivate, &s));
auto str = std::make_unique<ast::IdentifierExpression>("str");
auto mem = std::make_unique<ast::IdentifierExpression>("mem");
ast::MemberAccessorExpression expr(std::move(str), std::move(mem));
td().RegisterVariableForTesting(str_var.get());
gen().register_global(str_var.get());
mod()->AddGlobalVariable(std::move(str_var));
ASSERT_TRUE(td().DetermineResultType(&expr)) << td().error();
ASSERT_TRUE(gen().EmitExpression(out(), &expr)) << gen().error();
EXPECT_EQ(result(), "str.mem");
}
TEST_F(HlslGeneratorImplTest_MemberAccessor,
EmitExpression_MemberAccessor_StorageBuffer_Load) {
// struct Data {
// [[offset 0]] a : i32;
// [[offset 4]] b : f32;
// };
// var<storage_buffer> data : Data;
// data.b;
//
// -> asfloat(data.Load(4));
ast::type::F32Type f32;
ast::type::I32Type i32;
ast::StructMemberList members;
ast::StructMemberDecorationList a_deco;
a_deco.push_back(std::make_unique<ast::StructMemberOffsetDecoration>(0));
members.push_back(
std::make_unique<ast::StructMember>("a", &i32, std::move(a_deco)));
ast::StructMemberDecorationList b_deco;
b_deco.push_back(std::make_unique<ast::StructMemberOffsetDecoration>(4));
members.push_back(
std::make_unique<ast::StructMember>("b", &f32, std::move(b_deco)));
auto str = std::make_unique<ast::Struct>();
str->set_members(std::move(members));
ast::type::StructType s(std::move(str));
s.set_name("Data");
auto coord_var =
std::make_unique<ast::DecoratedVariable>(std::make_unique<ast::Variable>(
"data", ast::StorageClass::kStorageBuffer, &s));
ast::MemberAccessorExpression expr(
std::make_unique<ast::IdentifierExpression>("data"),
std::make_unique<ast::IdentifierExpression>("b"));
td().RegisterVariableForTesting(coord_var.get());
gen().register_global(coord_var.get());
mod()->AddGlobalVariable(std::move(coord_var));
ASSERT_TRUE(td().Determine()) << td().error();
ASSERT_TRUE(td().DetermineResultType(&expr));
ASSERT_TRUE(gen().EmitExpression(out(), &expr)) << gen().error();
EXPECT_EQ(result(), "asfloat(data.Load(4))");
}
TEST_F(HlslGeneratorImplTest_MemberAccessor,
EmitExpression_MemberAccessor_StorageBuffer_Load_Int) {
// struct Data {
// [[offset 0]] a : i32;
// [[offset 4]] b : f32;
// };
// var<storage_buffer> data : Data;
// data.a;
//
// -> asint(data.Load(0));
ast::type::F32Type f32;
ast::type::I32Type i32;
ast::StructMemberList members;
ast::StructMemberDecorationList a_deco;
a_deco.push_back(std::make_unique<ast::StructMemberOffsetDecoration>(0));
members.push_back(
std::make_unique<ast::StructMember>("a", &i32, std::move(a_deco)));
ast::StructMemberDecorationList b_deco;
b_deco.push_back(std::make_unique<ast::StructMemberOffsetDecoration>(4));
members.push_back(
std::make_unique<ast::StructMember>("b", &f32, std::move(b_deco)));
auto str = std::make_unique<ast::Struct>();
str->set_members(std::move(members));
ast::type::StructType s(std::move(str));
s.set_name("Data");
auto coord_var =
std::make_unique<ast::DecoratedVariable>(std::make_unique<ast::Variable>(
"data", ast::StorageClass::kStorageBuffer, &s));
ast::MemberAccessorExpression expr(
std::make_unique<ast::IdentifierExpression>("data"),
std::make_unique<ast::IdentifierExpression>("a"));
td().RegisterVariableForTesting(coord_var.get());
gen().register_global(coord_var.get());
mod()->AddGlobalVariable(std::move(coord_var));
ASSERT_TRUE(td().Determine()) << td().error();
ASSERT_TRUE(td().DetermineResultType(&expr));
ASSERT_TRUE(gen().EmitExpression(out(), &expr)) << gen().error();
EXPECT_EQ(result(), "asint(data.Load(0))");
}
TEST_F(HlslGeneratorImplTest_MemberAccessor,
EmitExpression_ArrayAccessor_StorageBuffer_Load_Int_FromArray) {
// struct Data {
// [[offset 0]] a : [[stride 4]] array<i32, 5>;
// };
// var<storage_buffer> data : Data;
// data.a[2];
//
// -> asint(data.Load((2 * 4));
ast::type::F32Type f32;
ast::type::I32Type i32;
ast::type::ArrayType ary(&i32, 5);
ary.set_array_stride(4);
ast::StructMemberList members;
ast::StructMemberDecorationList a_deco;
a_deco.push_back(std::make_unique<ast::StructMemberOffsetDecoration>(0));
members.push_back(
std::make_unique<ast::StructMember>("a", &ary, std::move(a_deco)));
auto str = std::make_unique<ast::Struct>();
str->set_members(std::move(members));
ast::type::StructType s(std::move(str));
s.set_name("Data");
auto coord_var =
std::make_unique<ast::DecoratedVariable>(std::make_unique<ast::Variable>(
"data", ast::StorageClass::kStorageBuffer, &s));
ast::ArrayAccessorExpression expr(
std::make_unique<ast::MemberAccessorExpression>(
std::make_unique<ast::IdentifierExpression>("data"),
std::make_unique<ast::IdentifierExpression>("a")),
std::make_unique<ast::ScalarConstructorExpression>(
std::make_unique<ast::SintLiteral>(&i32, 2)));
td().RegisterVariableForTesting(coord_var.get());
gen().register_global(coord_var.get());
mod()->AddGlobalVariable(std::move(coord_var));
ASSERT_TRUE(td().Determine()) << td().error();
ASSERT_TRUE(td().DetermineResultType(&expr)) << td().error();
ASSERT_TRUE(gen().EmitExpression(out(), &expr)) << gen().error();
EXPECT_EQ(result(), "asint(data.Load((4 * 2) + 0))");
}
TEST_F(HlslGeneratorImplTest_MemberAccessor,
EmitExpression_ArrayAccessor_StorageBuffer_Load_Int_FromArray_ExprIdx) {
// struct Data {
// [[offset 0]] a : [[stride 4]] array<i32, 5>;
// };
// var<storage_buffer> data : Data;
// data.a[(2 + 4) - 3];
//
// -> asint(data.Load((4 * ((2 + 4) - 3)));
ast::type::F32Type f32;
ast::type::I32Type i32;
ast::type::ArrayType ary(&i32, 5);
ary.set_array_stride(4);
ast::StructMemberList members;
ast::StructMemberDecorationList a_deco;
a_deco.push_back(std::make_unique<ast::StructMemberOffsetDecoration>(0));
members.push_back(
std::make_unique<ast::StructMember>("a", &ary, std::move(a_deco)));
auto str = std::make_unique<ast::Struct>();
str->set_members(std::move(members));
ast::type::StructType s(std::move(str));
s.set_name("Data");
auto coord_var =
std::make_unique<ast::DecoratedVariable>(std::make_unique<ast::Variable>(
"data", ast::StorageClass::kStorageBuffer, &s));
ast::ArrayAccessorExpression expr(
std::make_unique<ast::MemberAccessorExpression>(
std::make_unique<ast::IdentifierExpression>("data"),
std::make_unique<ast::IdentifierExpression>("a")),
std::make_unique<ast::BinaryExpression>(
ast::BinaryOp::kSubtract,
std::make_unique<ast::BinaryExpression>(
ast::BinaryOp::kAdd,
std::make_unique<ast::ScalarConstructorExpression>(
std::make_unique<ast::SintLiteral>(&i32, 2)),
std::make_unique<ast::ScalarConstructorExpression>(
std::make_unique<ast::SintLiteral>(&i32, 4))),
std::make_unique<ast::ScalarConstructorExpression>(
std::make_unique<ast::SintLiteral>(&i32, 3))));
td().RegisterVariableForTesting(coord_var.get());
gen().register_global(coord_var.get());
mod()->AddGlobalVariable(std::move(coord_var));
ASSERT_TRUE(td().Determine()) << td().error();
ASSERT_TRUE(td().DetermineResultType(&expr)) << td().error();
ASSERT_TRUE(gen().EmitExpression(out(), &expr)) << gen().error();
EXPECT_EQ(result(), "asint(data.Load((4 * ((2 + 4) - 3)) + 0))");
}
TEST_F(HlslGeneratorImplTest_MemberAccessor,
EmitExpression_MemberAccessor_StorageBuffer_Store) {
// struct Data {
// [[offset 0]] a : i32;
// [[offset 4]] b : f32;
// };
// var<storage_buffer> data : Data;
// data.b = 2.3f;
//
// -> data.Store(0, asuint(2.0f));
ast::type::F32Type f32;
ast::type::I32Type i32;
ast::StructMemberList members;
ast::StructMemberDecorationList a_deco;
a_deco.push_back(std::make_unique<ast::StructMemberOffsetDecoration>(0));
members.push_back(
std::make_unique<ast::StructMember>("a", &i32, std::move(a_deco)));
ast::StructMemberDecorationList b_deco;
b_deco.push_back(std::make_unique<ast::StructMemberOffsetDecoration>(4));
members.push_back(
std::make_unique<ast::StructMember>("b", &f32, std::move(b_deco)));
auto str = std::make_unique<ast::Struct>();
str->set_members(std::move(members));
ast::type::StructType s(std::move(str));
s.set_name("Data");
auto coord_var =
std::make_unique<ast::DecoratedVariable>(std::make_unique<ast::Variable>(
"data", ast::StorageClass::kStorageBuffer, &s));
td().RegisterVariableForTesting(coord_var.get());
gen().register_global(coord_var.get());
mod()->AddGlobalVariable(std::move(coord_var));
ASSERT_TRUE(td().Determine()) << td().error();
auto lhs = std::make_unique<ast::MemberAccessorExpression>(
std::make_unique<ast::IdentifierExpression>("data"),
std::make_unique<ast::IdentifierExpression>("b"));
auto rhs = std::make_unique<ast::ScalarConstructorExpression>(
std::make_unique<ast::FloatLiteral>(&f32, 2.0f));
ast::AssignmentStatement assign(std::move(lhs), std::move(rhs));
ASSERT_TRUE(td().DetermineResultType(&assign));
ASSERT_TRUE(gen().EmitStatement(out(), &assign)) << gen().error();
EXPECT_EQ(result(), R"(data.Store(4, asuint(2.00000000f));
)");
}
TEST_F(HlslGeneratorImplTest_MemberAccessor,
EmitExpression_MemberAccessor_StorageBuffer_Store_ToArray) {
// struct Data {
// [[offset 0]] a : [[stride 4]] array<i32, 5>;
// };
// var<storage_buffer> data : Data;
// data.a[2] = 2;
//
// -> data.Store((2 * 4), asuint(2.3f));
ast::type::F32Type f32;
ast::type::I32Type i32;
ast::type::ArrayType ary(&i32, 5);
ary.set_array_stride(4);
ast::StructMemberList members;
ast::StructMemberDecorationList a_deco;
a_deco.push_back(std::make_unique<ast::StructMemberOffsetDecoration>(0));
members.push_back(
std::make_unique<ast::StructMember>("a", &ary, std::move(a_deco)));
auto str = std::make_unique<ast::Struct>();
str->set_members(std::move(members));
ast::type::StructType s(std::move(str));
s.set_name("Data");
auto coord_var =
std::make_unique<ast::DecoratedVariable>(std::make_unique<ast::Variable>(
"data", ast::StorageClass::kStorageBuffer, &s));
td().RegisterVariableForTesting(coord_var.get());
gen().register_global(coord_var.get());
mod()->AddGlobalVariable(std::move(coord_var));
ASSERT_TRUE(td().Determine()) << td().error();
auto lhs = std::make_unique<ast::ArrayAccessorExpression>(
std::make_unique<ast::MemberAccessorExpression>(
std::make_unique<ast::IdentifierExpression>("data"),
std::make_unique<ast::IdentifierExpression>("a")),
std::make_unique<ast::ScalarConstructorExpression>(
std::make_unique<ast::SintLiteral>(&i32, 2)));
auto rhs = std::make_unique<ast::ScalarConstructorExpression>(
std::make_unique<ast::SintLiteral>(&i32, 2));
ast::AssignmentStatement assign(std::move(lhs), std::move(rhs));
ASSERT_TRUE(td().DetermineResultType(&assign)) << td().error();
ASSERT_TRUE(gen().EmitStatement(out(), &assign)) << gen().error();
EXPECT_EQ(result(), R"(data.Store((4 * 2) + 0, asuint(2));
)");
}
TEST_F(HlslGeneratorImplTest_MemberAccessor,
EmitExpression_MemberAccessor_StorageBuffer_Store_Int) {
// struct Data {
// [[offset 0]] a : i32;
// [[offset 4]] b : f32;
// };
// var<storage_buffer> data : Data;
// data.a = 2;
//
// -> data.Store(0, asuint(2));
ast::type::F32Type f32;
ast::type::I32Type i32;
ast::StructMemberList members;
ast::StructMemberDecorationList a_deco;
a_deco.push_back(std::make_unique<ast::StructMemberOffsetDecoration>(0));
members.push_back(
std::make_unique<ast::StructMember>("a", &i32, std::move(a_deco)));
ast::StructMemberDecorationList b_deco;
b_deco.push_back(std::make_unique<ast::StructMemberOffsetDecoration>(4));
members.push_back(
std::make_unique<ast::StructMember>("b", &f32, std::move(b_deco)));
auto str = std::make_unique<ast::Struct>();
str->set_members(std::move(members));
ast::type::StructType s(std::move(str));
s.set_name("Data");
auto coord_var =
std::make_unique<ast::DecoratedVariable>(std::make_unique<ast::Variable>(
"data", ast::StorageClass::kStorageBuffer, &s));
td().RegisterVariableForTesting(coord_var.get());
gen().register_global(coord_var.get());
mod()->AddGlobalVariable(std::move(coord_var));
ASSERT_TRUE(td().Determine()) << td().error();
auto lhs = std::make_unique<ast::MemberAccessorExpression>(
std::make_unique<ast::IdentifierExpression>("data"),
std::make_unique<ast::IdentifierExpression>("a"));
auto rhs = std::make_unique<ast::ScalarConstructorExpression>(
std::make_unique<ast::SintLiteral>(&i32, 2));
ast::AssignmentStatement assign(std::move(lhs), std::move(rhs));
ASSERT_TRUE(td().DetermineResultType(&assign));
ASSERT_TRUE(gen().EmitStatement(out(), &assign)) << gen().error();
EXPECT_EQ(result(), R"(data.Store(0, asuint(2));
)");
}
TEST_F(HlslGeneratorImplTest_MemberAccessor,
EmitExpression_MemberAccessor_StorageBuffer_Load_Vec3) {
// struct Data {
// [[offset 0]] a : vec3<i32>;
// [[offset 16]] b : vec3<f32>;
// };
// var<storage_buffer> data : Data;
// data.b;
//
// -> asfloat(data.Load(16));
ast::type::F32Type f32;
ast::type::I32Type i32;
ast::type::VectorType ivec3(&i32, 3);
ast::type::VectorType fvec3(&f32, 3);
ast::StructMemberList members;
ast::StructMemberDecorationList a_deco;
a_deco.push_back(std::make_unique<ast::StructMemberOffsetDecoration>(0));
members.push_back(
std::make_unique<ast::StructMember>("a", &ivec3, std::move(a_deco)));
ast::StructMemberDecorationList b_deco;
b_deco.push_back(std::make_unique<ast::StructMemberOffsetDecoration>(16));
members.push_back(
std::make_unique<ast::StructMember>("b", &fvec3, std::move(b_deco)));
auto str = std::make_unique<ast::Struct>();
str->set_members(std::move(members));
ast::type::StructType s(std::move(str));
s.set_name("Data");
auto coord_var =
std::make_unique<ast::DecoratedVariable>(std::make_unique<ast::Variable>(
"data", ast::StorageClass::kStorageBuffer, &s));
td().RegisterVariableForTesting(coord_var.get());
gen().register_global(coord_var.get());
mod()->AddGlobalVariable(std::move(coord_var));
ASSERT_TRUE(td().Determine()) << td().error();
ast::MemberAccessorExpression expr(
std::make_unique<ast::IdentifierExpression>("data"),
std::make_unique<ast::IdentifierExpression>("b"));
ASSERT_TRUE(td().DetermineResultType(&expr));
ASSERT_TRUE(gen().EmitExpression(out(), &expr)) << gen().error();
EXPECT_EQ(result(), "asfloat(data.Load3(16))");
}
TEST_F(HlslGeneratorImplTest_MemberAccessor,
EmitExpression_MemberAccessor_StorageBuffer_Store_Vec3) {
// struct Data {
// [[offset 0]] a : vec3<i32>;
// [[offset 16]] b : vec3<f32>;
// };
// var<storage_buffer> data : Data;
// data.b = vec3<f32>(2.3f, 1.2f, 0.2f);
//
// -> data.Store(16, asuint(vector<float, 3>(2.3f, 1.2f, 0.2f)));
ast::type::F32Type f32;
ast::type::I32Type i32;
ast::type::VectorType ivec3(&i32, 3);
ast::type::VectorType fvec3(&f32, 3);
ast::StructMemberList members;
ast::StructMemberDecorationList a_deco;
a_deco.push_back(std::make_unique<ast::StructMemberOffsetDecoration>(0));
members.push_back(
std::make_unique<ast::StructMember>("a", &ivec3, std::move(a_deco)));
ast::StructMemberDecorationList b_deco;
b_deco.push_back(std::make_unique<ast::StructMemberOffsetDecoration>(16));
members.push_back(
std::make_unique<ast::StructMember>("b", &fvec3, std::move(b_deco)));
auto str = std::make_unique<ast::Struct>();
str->set_members(std::move(members));
ast::type::StructType s(std::move(str));
s.set_name("Data");
auto coord_var =
std::make_unique<ast::DecoratedVariable>(std::make_unique<ast::Variable>(
"data", ast::StorageClass::kStorageBuffer, &s));
td().RegisterVariableForTesting(coord_var.get());
gen().register_global(coord_var.get());
mod()->AddGlobalVariable(std::move(coord_var));
ASSERT_TRUE(td().Determine()) << td().error();
auto lit1 = std::make_unique<ast::FloatLiteral>(&f32, 1.f);
auto lit2 = std::make_unique<ast::FloatLiteral>(&f32, 2.f);
auto lit3 = std::make_unique<ast::FloatLiteral>(&f32, 3.f);
ast::ExpressionList values;
values.push_back(
std::make_unique<ast::ScalarConstructorExpression>(std::move(lit1)));
values.push_back(
std::make_unique<ast::ScalarConstructorExpression>(std::move(lit2)));
values.push_back(
std::make_unique<ast::ScalarConstructorExpression>(std::move(lit3)));
auto lhs = std::make_unique<ast::MemberAccessorExpression>(
std::make_unique<ast::IdentifierExpression>("data"),
std::make_unique<ast::IdentifierExpression>("b"));
auto rhs = std::make_unique<ast::TypeConstructorExpression>(
&fvec3, std::move(values));
ast::AssignmentStatement assign(std::move(lhs), std::move(rhs));
ASSERT_TRUE(td().DetermineResultType(&assign));
ASSERT_TRUE(gen().EmitStatement(out(), &assign)) << gen().error();
EXPECT_EQ(
result(),
R"(data.Store3(16, asuint(vector<float, 3>(1.00000000f, 2.00000000f, 3.00000000f)));
)");
}
TEST_F(HlslGeneratorImplTest_MemberAccessor,
EmitExpression_MemberAccessor_StorageBuffer_Load_MultiLevel) {
// struct Data {
// [[offset 0]] a : vec3<i32>;
// [[offset 16]] b : vec3<f32>;
// };
// struct Pre {
// var c : [[stride 32]] array<Data, 4>;
// };
//
// var<storage_buffer> data : Pre;
// data.c[2].b
//
// -> asfloat(data.Load3(16 + (2 * 32)))
ast::type::F32Type f32;
ast::type::I32Type i32;
ast::type::VectorType ivec3(&i32, 3);
ast::type::VectorType fvec3(&f32, 3);
ast::StructMemberList members;
ast::StructMemberDecorationList deco;
deco.push_back(std::make_unique<ast::StructMemberOffsetDecoration>(0));
members.push_back(
std::make_unique<ast::StructMember>("a", &ivec3, std::move(deco)));
deco.push_back(std::make_unique<ast::StructMemberOffsetDecoration>(16));
members.push_back(
std::make_unique<ast::StructMember>("b", &fvec3, std::move(deco)));
auto data_str = std::make_unique<ast::Struct>();
data_str->set_members(std::move(members));
ast::type::StructType data(std::move(data_str));
data.set_name("Data");
ast::type::ArrayType ary(&data, 4);
ary.set_array_stride(32);
deco.push_back(std::make_unique<ast::StructMemberOffsetDecoration>(0));
members.push_back(
std::make_unique<ast::StructMember>("c", &ary, std::move(deco)));
auto pre_str = std::make_unique<ast::Struct>();
pre_str->set_members(std::move(members));
ast::type::StructType pre(std::move(pre_str));
pre.set_name("Pre");
auto coord_var =
std::make_unique<ast::DecoratedVariable>(std::make_unique<ast::Variable>(
"data", ast::StorageClass::kStorageBuffer, &pre));
td().RegisterVariableForTesting(coord_var.get());
gen().register_global(coord_var.get());
mod()->AddGlobalVariable(std::move(coord_var));
ASSERT_TRUE(td().Determine()) << td().error();
ast::MemberAccessorExpression expr(
std::make_unique<ast::ArrayAccessorExpression>(
std::make_unique<ast::MemberAccessorExpression>(
std::make_unique<ast::IdentifierExpression>("data"),
std::make_unique<ast::IdentifierExpression>("c")),
std::make_unique<ast::ScalarConstructorExpression>(
std::make_unique<ast::SintLiteral>(&i32, 2))),
std::make_unique<ast::IdentifierExpression>("b"));
ASSERT_TRUE(td().DetermineResultType(&expr));
ASSERT_TRUE(gen().EmitExpression(out(), &expr)) << gen().error();
EXPECT_EQ(result(), "asfloat(data.Load3(16 + (32 * 2) + 0))");
}
TEST_F(HlslGeneratorImplTest_MemberAccessor,
EmitExpression_MemberAccessor_StorageBuffer_Load_MultiLevel_Swizzle) {
// struct Data {
// [[offset 0]] a : vec3<i32>;
// [[offset 16]] b : vec3<f32>;
// };
// struct Pre {
// var c : [[stride 32]] array<Data, 4>;
// };
//
// var<storage_buffer> data : Pre;
// data.c[2].b.xy
//
// -> asfloat(data.Load3(16 + (2 * 32))).xy
ast::type::F32Type f32;
ast::type::I32Type i32;
ast::type::VectorType ivec3(&i32, 3);
ast::type::VectorType fvec3(&f32, 3);
ast::StructMemberList members;
ast::StructMemberDecorationList deco;
deco.push_back(std::make_unique<ast::StructMemberOffsetDecoration>(0));
members.push_back(
std::make_unique<ast::StructMember>("a", &ivec3, std::move(deco)));
deco.push_back(std::make_unique<ast::StructMemberOffsetDecoration>(16));
members.push_back(
std::make_unique<ast::StructMember>("b", &fvec3, std::move(deco)));
auto data_str = std::make_unique<ast::Struct>();
data_str->set_members(std::move(members));
ast::type::StructType data(std::move(data_str));
data.set_name("Data");
ast::type::ArrayType ary(&data, 4);
ary.set_array_stride(32);
deco.push_back(std::make_unique<ast::StructMemberOffsetDecoration>(0));
members.push_back(
std::make_unique<ast::StructMember>("c", &ary, std::move(deco)));
auto pre_str = std::make_unique<ast::Struct>();
pre_str->set_members(std::move(members));
ast::type::StructType pre(std::move(pre_str));
pre.set_name("Pre");
auto coord_var =
std::make_unique<ast::DecoratedVariable>(std::make_unique<ast::Variable>(
"data", ast::StorageClass::kStorageBuffer, &pre));
td().RegisterVariableForTesting(coord_var.get());
gen().register_global(coord_var.get());
mod()->AddGlobalVariable(std::move(coord_var));
ASSERT_TRUE(td().Determine()) << td().error();
ast::MemberAccessorExpression expr(
std::make_unique<ast::MemberAccessorExpression>(
std::make_unique<ast::ArrayAccessorExpression>(
std::make_unique<ast::MemberAccessorExpression>(
std::make_unique<ast::IdentifierExpression>("data"),
std::make_unique<ast::IdentifierExpression>("c")),
std::make_unique<ast::ScalarConstructorExpression>(
std::make_unique<ast::SintLiteral>(&i32, 2))),
std::make_unique<ast::IdentifierExpression>("b")),
std::make_unique<ast::IdentifierExpression>("xy"));
ASSERT_TRUE(td().DetermineResultType(&expr));
ASSERT_TRUE(gen().EmitExpression(out(), &expr)) << gen().error();
EXPECT_EQ(result(), "asfloat(data.Load3(16 + (32 * 2) + 0)).xy");
}
TEST_F(
HlslGeneratorImplTest_MemberAccessor,
EmitExpression_MemberAccessor_StorageBuffer_Load_MultiLevel_Swizzle_SingleLetter) {
// struct Data {
// [[offset 0]] a : vec3<i32>;
// [[offset 16]] b : vec3<f32>;
// };
// struct Pre {
// var c : [[stride 32]] array<Data, 4>;
// };
//
// var<storage_buffer> data : Pre;
// data.c[2].b.g
//
// -> asfloat(data.Load((4 * 1) + 16 + (2 * 32) + 0))
ast::type::F32Type f32;
ast::type::I32Type i32;
ast::type::VectorType ivec3(&i32, 3);
ast::type::VectorType fvec3(&f32, 3);
ast::StructMemberList members;
ast::StructMemberDecorationList deco;
deco.push_back(std::make_unique<ast::StructMemberOffsetDecoration>(0));
members.push_back(
std::make_unique<ast::StructMember>("a", &ivec3, std::move(deco)));
deco.push_back(std::make_unique<ast::StructMemberOffsetDecoration>(16));
members.push_back(
std::make_unique<ast::StructMember>("b", &fvec3, std::move(deco)));
auto data_str = std::make_unique<ast::Struct>();
data_str->set_members(std::move(members));
ast::type::StructType data(std::move(data_str));
data.set_name("Data");
ast::type::ArrayType ary(&data, 4);
ary.set_array_stride(32);
deco.push_back(std::make_unique<ast::StructMemberOffsetDecoration>(0));
members.push_back(
std::make_unique<ast::StructMember>("c", &ary, std::move(deco)));
auto pre_str = std::make_unique<ast::Struct>();
pre_str->set_members(std::move(members));
ast::type::StructType pre(std::move(pre_str));
pre.set_name("Pre");
auto coord_var =
std::make_unique<ast::DecoratedVariable>(std::make_unique<ast::Variable>(
"data", ast::StorageClass::kStorageBuffer, &pre));
td().RegisterVariableForTesting(coord_var.get());
gen().register_global(coord_var.get());
mod()->AddGlobalVariable(std::move(coord_var));
ASSERT_TRUE(td().Determine()) << td().error();
ast::MemberAccessorExpression expr(
std::make_unique<ast::MemberAccessorExpression>(
std::make_unique<ast::ArrayAccessorExpression>(
std::make_unique<ast::MemberAccessorExpression>(
std::make_unique<ast::IdentifierExpression>("data"),
std::make_unique<ast::IdentifierExpression>("c")),
std::make_unique<ast::ScalarConstructorExpression>(
std::make_unique<ast::SintLiteral>(&i32, 2))),
std::make_unique<ast::IdentifierExpression>("b")),
std::make_unique<ast::IdentifierExpression>("g"));
ASSERT_TRUE(td().DetermineResultType(&expr));
ASSERT_TRUE(gen().EmitExpression(out(), &expr)) << gen().error();
EXPECT_EQ(result(), "asfloat(data.Load((4 * 1) + 16 + (32 * 2) + 0))");
}
TEST_F(HlslGeneratorImplTest_MemberAccessor,
EmitExpression_MemberAccessor_StorageBuffer_Load_MultiLevel_Index) {
// struct Data {
// [[offset 0]] a : vec3<i32>;
// [[offset 16]] b : vec3<f32>;
// };
// struct Pre {
// var c : [[stride 32]] array<Data, 4>;
// };
//
// var<storage_buffer> data : Pre;
// data.c[2].b[1]
//
// -> asfloat(data.Load(4 + 16 + (2 * 32)))
ast::type::F32Type f32;
ast::type::I32Type i32;
ast::type::VectorType ivec3(&i32, 3);
ast::type::VectorType fvec3(&f32, 3);
ast::StructMemberList members;
ast::StructMemberDecorationList deco;
deco.push_back(std::make_unique<ast::StructMemberOffsetDecoration>(0));
members.push_back(
std::make_unique<ast::StructMember>("a", &ivec3, std::move(deco)));
deco.push_back(std::make_unique<ast::StructMemberOffsetDecoration>(16));
members.push_back(
std::make_unique<ast::StructMember>("b", &fvec3, std::move(deco)));
auto data_str = std::make_unique<ast::Struct>();
data_str->set_members(std::move(members));
ast::type::StructType data(std::move(data_str));
data.set_name("Data");
ast::type::ArrayType ary(&data, 4);
ary.set_array_stride(32);
deco.push_back(std::make_unique<ast::StructMemberOffsetDecoration>(0));
members.push_back(
std::make_unique<ast::StructMember>("c", &ary, std::move(deco)));
auto pre_str = std::make_unique<ast::Struct>();
pre_str->set_members(std::move(members));
ast::type::StructType pre(std::move(pre_str));
pre.set_name("Pre");
auto coord_var =
std::make_unique<ast::DecoratedVariable>(std::make_unique<ast::Variable>(
"data", ast::StorageClass::kStorageBuffer, &pre));
td().RegisterVariableForTesting(coord_var.get());
gen().register_global(coord_var.get());
mod()->AddGlobalVariable(std::move(coord_var));
ASSERT_TRUE(td().Determine()) << td().error();
ast::ArrayAccessorExpression expr(
std::make_unique<ast::MemberAccessorExpression>(
std::make_unique<ast::ArrayAccessorExpression>(
std::make_unique<ast::MemberAccessorExpression>(
std::make_unique<ast::IdentifierExpression>("data"),
std::make_unique<ast::IdentifierExpression>("c")),
std::make_unique<ast::ScalarConstructorExpression>(
std::make_unique<ast::SintLiteral>(&i32, 2))),
std::make_unique<ast::IdentifierExpression>("b")),
std::make_unique<ast::ScalarConstructorExpression>(
std::make_unique<ast::SintLiteral>(&i32, 1)));
ASSERT_TRUE(td().DetermineResultType(&expr));
ASSERT_TRUE(gen().EmitExpression(out(), &expr)) << gen().error();
EXPECT_EQ(result(), "asfloat(data.Load((4 * 1) + 16 + (32 * 2) + 0))");
}
TEST_F(HlslGeneratorImplTest_MemberAccessor,
EmitExpression_MemberAccessor_StorageBuffer_Store_MultiLevel) {
// struct Data {
// [[offset 0]] a : vec3<i32>;
// [[offset 16]] b : vec3<f32>;
// };
// struct Pre {
// var c : [[stride 32]] array<Data, 4>;
// };
//
// var<storage_buffer> data : Pre;
// data.c[2].b = vec3<f32>(1.f, 2.f, 3.f);
//
// -> data.Store3(16 + (2 * 32), asuint(vector<float, 3>(1.0f, 2.0f, 3.0f)));
ast::type::F32Type f32;
ast::type::I32Type i32;
ast::type::VectorType ivec3(&i32, 3);
ast::type::VectorType fvec3(&f32, 3);
ast::StructMemberList members;
ast::StructMemberDecorationList deco;
deco.push_back(std::make_unique<ast::StructMemberOffsetDecoration>(0));
members.push_back(
std::make_unique<ast::StructMember>("a", &ivec3, std::move(deco)));
deco.push_back(std::make_unique<ast::StructMemberOffsetDecoration>(16));
members.push_back(
std::make_unique<ast::StructMember>("b", &fvec3, std::move(deco)));
auto data_str = std::make_unique<ast::Struct>();
data_str->set_members(std::move(members));
ast::type::StructType data(std::move(data_str));
data.set_name("Data");
ast::type::ArrayType ary(&data, 4);
ary.set_array_stride(32);
deco.push_back(std::make_unique<ast::StructMemberOffsetDecoration>(0));
members.push_back(
std::make_unique<ast::StructMember>("c", &ary, std::move(deco)));
auto pre_str = std::make_unique<ast::Struct>();
pre_str->set_members(std::move(members));
ast::type::StructType pre(std::move(pre_str));
pre.set_name("Pre");
auto coord_var =
std::make_unique<ast::DecoratedVariable>(std::make_unique<ast::Variable>(
"data", ast::StorageClass::kStorageBuffer, &pre));
td().RegisterVariableForTesting(coord_var.get());
gen().register_global(coord_var.get());
mod()->AddGlobalVariable(std::move(coord_var));
ASSERT_TRUE(td().Determine()) << td().error();
auto lhs = std::make_unique<ast::MemberAccessorExpression>(
std::make_unique<ast::ArrayAccessorExpression>(
std::make_unique<ast::MemberAccessorExpression>(
std::make_unique<ast::IdentifierExpression>("data"),
std::make_unique<ast::IdentifierExpression>("c")),
std::make_unique<ast::ScalarConstructorExpression>(
std::make_unique<ast::SintLiteral>(&i32, 2))),
std::make_unique<ast::IdentifierExpression>("b"));
auto lit1 = std::make_unique<ast::FloatLiteral>(&f32, 1.f);
auto lit2 = std::make_unique<ast::FloatLiteral>(&f32, 2.f);
auto lit3 = std::make_unique<ast::FloatLiteral>(&f32, 3.f);
ast::ExpressionList values;
values.push_back(
std::make_unique<ast::ScalarConstructorExpression>(std::move(lit1)));
values.push_back(
std::make_unique<ast::ScalarConstructorExpression>(std::move(lit2)));
values.push_back(
std::make_unique<ast::ScalarConstructorExpression>(std::move(lit3)));
auto rhs = std::make_unique<ast::TypeConstructorExpression>(
&fvec3, std::move(values));
ast::AssignmentStatement assign(std::move(lhs), std::move(rhs));
ASSERT_TRUE(td().DetermineResultType(&assign));
ASSERT_TRUE(gen().EmitStatement(out(), &assign)) << gen().error();
EXPECT_EQ(
result(),
R"(data.Store3(16 + (32 * 2) + 0, asuint(vector<float, 3>(1.00000000f, 2.00000000f, 3.00000000f)));
)");
}
TEST_F(HlslGeneratorImplTest_MemberAccessor,
EmitExpression_MemberAccessor_StorageBuffer_Store_Swizzle_SingleLetter) {
// struct Data {
// [[offset 0]] a : vec3<i32>;
// [[offset 16]] b : vec3<f32>;
// };
// struct Pre {
// var c : [[stride 32]] array<Data, 4>;
// };
//
// var<storage_buffer> data : Pre;
// data.c[2].b.y = 1.f;
//
// -> data.Store((4 * 1) + 16 + (2 * 32) + 0, asuint(1.0f));
ast::type::F32Type f32;
ast::type::I32Type i32;
ast::type::VectorType ivec3(&i32, 3);
ast::type::VectorType fvec3(&f32, 3);
ast::StructMemberList members;
ast::StructMemberDecorationList deco;
deco.push_back(std::make_unique<ast::StructMemberOffsetDecoration>(0));
members.push_back(
std::make_unique<ast::StructMember>("a", &ivec3, std::move(deco)));
deco.push_back(std::make_unique<ast::StructMemberOffsetDecoration>(16));
members.push_back(
std::make_unique<ast::StructMember>("b", &fvec3, std::move(deco)));
auto data_str = std::make_unique<ast::Struct>();
data_str->set_members(std::move(members));
ast::type::StructType data(std::move(data_str));
data.set_name("Data");
ast::type::ArrayType ary(&data, 4);
ary.set_array_stride(32);
deco.push_back(std::make_unique<ast::StructMemberOffsetDecoration>(0));
members.push_back(
std::make_unique<ast::StructMember>("c", &ary, std::move(deco)));
auto pre_str = std::make_unique<ast::Struct>();
pre_str->set_members(std::move(members));
ast::type::StructType pre(std::move(pre_str));
pre.set_name("Pre");
auto coord_var =
std::make_unique<ast::DecoratedVariable>(std::make_unique<ast::Variable>(
"data", ast::StorageClass::kStorageBuffer, &pre));
td().RegisterVariableForTesting(coord_var.get());
gen().register_global(coord_var.get());
mod()->AddGlobalVariable(std::move(coord_var));
ASSERT_TRUE(td().Determine()) << td().error();
auto lhs = std::make_unique<ast::MemberAccessorExpression>(
std::make_unique<ast::MemberAccessorExpression>(
std::make_unique<ast::ArrayAccessorExpression>(
std::make_unique<ast::MemberAccessorExpression>(
std::make_unique<ast::IdentifierExpression>("data"),
std::make_unique<ast::IdentifierExpression>("c")),
std::make_unique<ast::ScalarConstructorExpression>(
std::make_unique<ast::SintLiteral>(&i32, 2))),
std::make_unique<ast::IdentifierExpression>("b")),
std::make_unique<ast::IdentifierExpression>("y"));
auto rhs = std::make_unique<ast::ScalarConstructorExpression>(
std::make_unique<ast::FloatLiteral>(&i32, 1.f));
ast::AssignmentStatement assign(std::move(lhs), std::move(rhs));
ASSERT_TRUE(td().DetermineResultType(&assign));
ASSERT_TRUE(gen().EmitStatement(out(), &assign)) << gen().error();
EXPECT_EQ(result(),
R"(data.Store((4 * 1) + 16 + (32 * 2) + 0, asuint(1.00000000f));
)");
}
} // namespace
} // namespace hlsl
} // namespace writer
} // namespace tint