2020-03-25 19:43:20 +00:00
|
|
|
// 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 <string>
|
|
|
|
|
|
|
|
#include "gtest/gtest.h"
|
|
|
|
#include "spirv/unified1/spirv.h"
|
|
|
|
#include "spirv/unified1/spirv.hpp11"
|
2020-11-05 14:52:32 +00:00
|
|
|
#include "src/ast/decorated_variable.h"
|
2020-11-18 18:25:30 +00:00
|
|
|
#include "src/ast/discard_statement.h"
|
2020-03-25 19:43:20 +00:00
|
|
|
#include "src/ast/function.h"
|
2020-06-22 20:09:23 +00:00
|
|
|
#include "src/ast/identifier_expression.h"
|
2020-11-05 14:52:32 +00:00
|
|
|
#include "src/ast/member_accessor_expression.h"
|
2020-05-01 19:05:03 +00:00
|
|
|
#include "src/ast/return_statement.h"
|
2020-11-05 14:52:32 +00:00
|
|
|
#include "src/ast/stage_decoration.h"
|
|
|
|
#include "src/ast/struct.h"
|
|
|
|
#include "src/ast/struct_block_decoration.h"
|
|
|
|
#include "src/ast/struct_member_offset_decoration.h"
|
|
|
|
#include "src/ast/type/access_control_type.h"
|
2020-06-22 20:09:23 +00:00
|
|
|
#include "src/ast/type/f32_type.h"
|
|
|
|
#include "src/ast/type/i32_type.h"
|
2020-11-05 14:52:32 +00:00
|
|
|
#include "src/ast/type/struct_type.h"
|
2020-03-25 19:43:20 +00:00
|
|
|
#include "src/ast/type/void_type.h"
|
2020-06-22 20:09:23 +00:00
|
|
|
#include "src/ast/variable.h"
|
2020-11-05 14:52:32 +00:00
|
|
|
#include "src/ast/variable_decl_statement.h"
|
2020-10-26 14:27:08 +00:00
|
|
|
#include "src/context.h"
|
|
|
|
#include "src/type_determiner.h"
|
2020-03-25 19:43:20 +00:00
|
|
|
#include "src/writer/spirv/builder.h"
|
|
|
|
#include "src/writer/spirv/spv_dump.h"
|
2020-11-13 18:13:24 +00:00
|
|
|
#include "src/writer/spirv/test_helper.h"
|
2020-03-25 19:43:20 +00:00
|
|
|
|
|
|
|
namespace tint {
|
|
|
|
namespace writer {
|
|
|
|
namespace spirv {
|
2020-03-26 15:31:43 +00:00
|
|
|
namespace {
|
2020-03-25 19:43:20 +00:00
|
|
|
|
2020-11-13 18:13:24 +00:00
|
|
|
using BuilderTest = TestHelper;
|
2020-03-25 19:43:20 +00:00
|
|
|
|
|
|
|
TEST_F(BuilderTest, Function_Empty) {
|
|
|
|
ast::type::VoidType void_type;
|
2020-11-14 01:13:04 +00:00
|
|
|
ast::Function func("a_func", {}, &void_type, create<ast::BlockStatement>());
|
2020-03-25 19:43:20 +00:00
|
|
|
|
|
|
|
ASSERT_TRUE(b.GenerateFunction(&func));
|
2020-11-18 18:25:30 +00:00
|
|
|
EXPECT_EQ(DumpBuilder(b), R"(OpName %3 "tint_615f66756e63"
|
|
|
|
%2 = OpTypeVoid
|
|
|
|
%1 = OpTypeFunction %2
|
|
|
|
%3 = OpFunction %2 None %1
|
|
|
|
%4 = OpLabel
|
|
|
|
OpReturn
|
|
|
|
OpFunctionEnd
|
2020-03-25 19:43:20 +00:00
|
|
|
)");
|
2020-11-18 18:25:30 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
TEST_F(BuilderTest, Function_Terminator_Return) {
|
|
|
|
ast::type::VoidType void_type;
|
|
|
|
|
|
|
|
auto* body = create<ast::BlockStatement>();
|
|
|
|
body->append(create<ast::ReturnStatement>());
|
|
|
|
|
|
|
|
ast::Function func("a_func", {}, &void_type, body);
|
|
|
|
|
|
|
|
ASSERT_TRUE(b.GenerateFunction(&func));
|
|
|
|
EXPECT_EQ(DumpBuilder(b), R"(OpName %3 "tint_615f66756e63"
|
|
|
|
%2 = OpTypeVoid
|
2020-03-25 19:43:20 +00:00
|
|
|
%1 = OpTypeFunction %2
|
2020-11-18 18:25:30 +00:00
|
|
|
%3 = OpFunction %2 None %1
|
|
|
|
%4 = OpLabel
|
|
|
|
OpReturn
|
|
|
|
OpFunctionEnd
|
2020-03-25 19:43:20 +00:00
|
|
|
)");
|
2020-11-18 18:25:30 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
TEST_F(BuilderTest, Function_Terminator_ReturnValue) {
|
|
|
|
ast::type::VoidType void_type;
|
|
|
|
ast::type::F32Type f32;
|
|
|
|
|
|
|
|
auto* var_a = create<ast::Variable>("a", ast::StorageClass::kPrivate, &f32);
|
|
|
|
td.RegisterVariableForTesting(var_a);
|
2020-04-01 23:40:53 +00:00
|
|
|
|
2020-11-18 18:25:30 +00:00
|
|
|
auto* body = create<ast::BlockStatement>();
|
|
|
|
body->append(
|
|
|
|
create<ast::ReturnStatement>(create<ast::IdentifierExpression>("a")));
|
|
|
|
ASSERT_TRUE(td.DetermineResultType(body)) << td.error();
|
|
|
|
|
|
|
|
ast::Function func("a_func", {}, &void_type, body);
|
|
|
|
|
|
|
|
ASSERT_TRUE(b.GenerateGlobalVariable(var_a)) << b.error();
|
|
|
|
ASSERT_TRUE(b.GenerateFunction(&func)) << b.error();
|
|
|
|
EXPECT_EQ(DumpBuilder(b), R"(OpName %1 "tint_61"
|
|
|
|
OpName %7 "tint_615f66756e63"
|
|
|
|
%3 = OpTypeFloat 32
|
|
|
|
%2 = OpTypePointer Private %3
|
|
|
|
%4 = OpConstantNull %3
|
|
|
|
%1 = OpVariable %2 Private %4
|
|
|
|
%6 = OpTypeVoid
|
|
|
|
%5 = OpTypeFunction %6
|
|
|
|
%7 = OpFunction %6 None %5
|
|
|
|
%8 = OpLabel
|
|
|
|
%9 = OpLoad %3 %1
|
|
|
|
OpReturnValue %9
|
|
|
|
OpFunctionEnd
|
|
|
|
)");
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST_F(BuilderTest, Function_Terminator_Discard) {
|
|
|
|
ast::type::VoidType void_type;
|
|
|
|
|
|
|
|
auto* body = create<ast::BlockStatement>();
|
|
|
|
body->append(create<ast::DiscardStatement>());
|
|
|
|
|
|
|
|
ast::Function func("a_func", {}, &void_type, body);
|
|
|
|
|
|
|
|
ASSERT_TRUE(b.GenerateFunction(&func));
|
|
|
|
EXPECT_EQ(DumpBuilder(b), R"(OpName %3 "tint_615f66756e63"
|
|
|
|
%2 = OpTypeVoid
|
|
|
|
%1 = OpTypeFunction %2
|
|
|
|
%3 = OpFunction %2 None %1
|
|
|
|
%4 = OpLabel
|
|
|
|
OpKill
|
|
|
|
OpFunctionEnd
|
2020-03-25 19:43:20 +00:00
|
|
|
)");
|
|
|
|
}
|
|
|
|
|
2020-06-22 20:09:23 +00:00
|
|
|
TEST_F(BuilderTest, Function_WithParams) {
|
|
|
|
ast::type::VoidType void_type;
|
|
|
|
ast::type::F32Type f32;
|
|
|
|
ast::type::I32Type i32;
|
|
|
|
|
|
|
|
ast::VariableList params;
|
2020-11-16 16:31:07 +00:00
|
|
|
auto* var_a = create<ast::Variable>("a", ast::StorageClass::kFunction, &f32);
|
2020-10-26 14:27:08 +00:00
|
|
|
var_a->set_is_const(true);
|
2020-11-16 16:41:47 +00:00
|
|
|
params.push_back(var_a);
|
2020-11-16 16:31:07 +00:00
|
|
|
auto* var_b = create<ast::Variable>("b", ast::StorageClass::kFunction, &i32);
|
2020-10-26 14:27:08 +00:00
|
|
|
var_b->set_is_const(true);
|
2020-11-16 16:41:47 +00:00
|
|
|
params.push_back(var_b);
|
2020-06-22 20:09:23 +00:00
|
|
|
|
2020-11-16 16:31:07 +00:00
|
|
|
auto* body = create<ast::BlockStatement>();
|
2020-11-14 01:09:04 +00:00
|
|
|
body->append(
|
|
|
|
create<ast::ReturnStatement>(create<ast::IdentifierExpression>("a")));
|
2020-11-16 16:41:47 +00:00
|
|
|
ast::Function func("a_func", params, &f32, body);
|
2020-06-22 20:09:23 +00:00
|
|
|
|
2020-11-16 16:31:07 +00:00
|
|
|
td.RegisterVariableForTesting(func.params()[0]);
|
|
|
|
td.RegisterVariableForTesting(func.params()[1]);
|
2020-10-26 14:27:08 +00:00
|
|
|
EXPECT_TRUE(td.DetermineFunction(&func));
|
|
|
|
|
2020-06-22 20:09:23 +00:00
|
|
|
ASSERT_TRUE(b.GenerateFunction(&func));
|
2020-11-10 21:49:56 +00:00
|
|
|
EXPECT_EQ(DumpBuilder(b), R"(OpName %4 "tint_615f66756e63"
|
|
|
|
OpName %5 "tint_61"
|
|
|
|
OpName %6 "tint_62"
|
2020-06-22 20:09:23 +00:00
|
|
|
%2 = OpTypeFloat 32
|
|
|
|
%3 = OpTypeInt 32 1
|
|
|
|
%1 = OpTypeFunction %2 %2 %3
|
|
|
|
%4 = OpFunction %2 None %1
|
|
|
|
%5 = OpFunctionParameter %2
|
|
|
|
%6 = OpFunctionParameter %3
|
|
|
|
%7 = OpLabel
|
|
|
|
OpReturnValue %5
|
|
|
|
OpFunctionEnd
|
2020-10-26 14:27:08 +00:00
|
|
|
)") << DumpBuilder(b);
|
2020-06-22 20:09:23 +00:00
|
|
|
}
|
2020-03-25 19:43:20 +00:00
|
|
|
|
2020-05-01 19:05:03 +00:00
|
|
|
TEST_F(BuilderTest, Function_WithBody) {
|
|
|
|
ast::type::VoidType void_type;
|
|
|
|
|
2020-11-16 16:31:07 +00:00
|
|
|
auto* body = create<ast::BlockStatement>();
|
2020-11-14 01:09:04 +00:00
|
|
|
body->append(create<ast::ReturnStatement>());
|
2020-05-01 19:05:03 +00:00
|
|
|
|
2020-11-16 16:41:47 +00:00
|
|
|
ast::Function func("a_func", {}, &void_type, body);
|
2020-05-01 19:05:03 +00:00
|
|
|
|
|
|
|
ASSERT_TRUE(b.GenerateFunction(&func));
|
2020-11-10 21:49:56 +00:00
|
|
|
EXPECT_EQ(DumpBuilder(b), R"(OpName %3 "tint_615f66756e63"
|
2020-05-01 19:05:03 +00:00
|
|
|
%2 = OpTypeVoid
|
|
|
|
%1 = OpTypeFunction %2
|
|
|
|
%3 = OpFunction %2 None %1
|
|
|
|
%4 = OpLabel
|
|
|
|
OpReturn
|
|
|
|
OpFunctionEnd
|
|
|
|
)");
|
|
|
|
}
|
2020-03-25 19:43:20 +00:00
|
|
|
|
|
|
|
TEST_F(BuilderTest, FunctionType) {
|
|
|
|
ast::type::VoidType void_type;
|
2020-11-14 01:13:04 +00:00
|
|
|
ast::Function func("a_func", {}, &void_type, create<ast::BlockStatement>());
|
2020-03-25 19:43:20 +00:00
|
|
|
|
|
|
|
ASSERT_TRUE(b.GenerateFunction(&func));
|
|
|
|
EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeVoid
|
|
|
|
%1 = OpTypeFunction %2
|
|
|
|
)");
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST_F(BuilderTest, FunctionType_DeDuplicate) {
|
|
|
|
ast::type::VoidType void_type;
|
2020-11-14 01:13:04 +00:00
|
|
|
ast::Function func1("a_func", {}, &void_type, create<ast::BlockStatement>());
|
|
|
|
ast::Function func2("b_func", {}, &void_type, create<ast::BlockStatement>());
|
2020-03-25 19:43:20 +00:00
|
|
|
|
|
|
|
ASSERT_TRUE(b.GenerateFunction(&func1));
|
|
|
|
ASSERT_TRUE(b.GenerateFunction(&func2));
|
|
|
|
EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeVoid
|
|
|
|
%1 = OpTypeFunction %2
|
|
|
|
)");
|
|
|
|
}
|
|
|
|
|
2020-11-05 14:52:32 +00:00
|
|
|
// https://crbug.com/tint/297
|
|
|
|
TEST_F(BuilderTest, Emit_Multiple_EntryPoint_With_Same_ModuleVar) {
|
|
|
|
// [[block]] struct Data {
|
|
|
|
// [[offset(0)]] d : f32;
|
|
|
|
// };
|
|
|
|
// [[binding(0), set(0)]] var<storage_buffer> data : Data;
|
|
|
|
//
|
|
|
|
// [[stage(compute)]]
|
|
|
|
// fn a() -> void {
|
|
|
|
// return;
|
|
|
|
// }
|
|
|
|
//
|
|
|
|
// [[stage(compute)]]
|
|
|
|
// fn b() -> void {
|
|
|
|
// return;
|
|
|
|
// }
|
|
|
|
|
|
|
|
ast::type::VoidType void_type;
|
|
|
|
ast::type::F32Type f32;
|
|
|
|
|
|
|
|
ast::StructMemberList members;
|
|
|
|
ast::StructMemberDecorationList a_deco;
|
2020-11-14 01:09:04 +00:00
|
|
|
a_deco.push_back(create<ast::StructMemberOffsetDecoration>(0, Source{}));
|
2020-11-16 16:41:47 +00:00
|
|
|
members.push_back(create<ast::StructMember>("d", &f32, a_deco));
|
2020-11-05 14:52:32 +00:00
|
|
|
|
|
|
|
ast::StructDecorationList s_decos;
|
2020-11-14 01:09:04 +00:00
|
|
|
s_decos.push_back(create<ast::StructBlockDecoration>(Source{}));
|
2020-11-05 14:52:32 +00:00
|
|
|
|
2020-11-16 16:41:47 +00:00
|
|
|
auto* str = create<ast::Struct>(s_decos, members);
|
2020-11-05 14:52:32 +00:00
|
|
|
|
2020-11-16 16:41:47 +00:00
|
|
|
ast::type::StructType s("Data", str);
|
2020-11-05 14:52:32 +00:00
|
|
|
ast::type::AccessControlType ac(ast::AccessControl::kReadWrite, &s);
|
|
|
|
|
2020-11-16 16:31:07 +00:00
|
|
|
auto* data_var = create<ast::DecoratedVariable>(
|
2020-11-14 01:09:04 +00:00
|
|
|
create<ast::Variable>("data", ast::StorageClass::kStorageBuffer, &ac));
|
2020-11-05 14:52:32 +00:00
|
|
|
|
|
|
|
ast::VariableDecorationList decos;
|
2020-11-14 01:09:04 +00:00
|
|
|
decos.push_back(create<ast::BindingDecoration>(0, Source{}));
|
|
|
|
decos.push_back(create<ast::SetDecoration>(0, Source{}));
|
2020-11-16 16:41:47 +00:00
|
|
|
data_var->set_decorations(decos);
|
2020-11-05 14:52:32 +00:00
|
|
|
|
2020-11-18 20:58:20 +00:00
|
|
|
mod->AddConstructedType(&s);
|
2020-11-05 14:52:32 +00:00
|
|
|
|
2020-11-16 16:31:07 +00:00
|
|
|
td.RegisterVariableForTesting(data_var);
|
2020-11-18 20:58:20 +00:00
|
|
|
mod->AddGlobalVariable(data_var);
|
2020-11-05 14:52:32 +00:00
|
|
|
|
|
|
|
{
|
|
|
|
ast::VariableList params;
|
2020-11-16 16:31:07 +00:00
|
|
|
auto* var = create<ast::Variable>("v", ast::StorageClass::kFunction, &f32);
|
2020-11-14 01:09:04 +00:00
|
|
|
var->set_constructor(create<ast::MemberAccessorExpression>(
|
|
|
|
create<ast::IdentifierExpression>("data"),
|
|
|
|
create<ast::IdentifierExpression>("d")));
|
|
|
|
|
2020-11-16 16:31:07 +00:00
|
|
|
auto* body = create<ast::BlockStatement>();
|
2020-11-16 16:41:47 +00:00
|
|
|
body->append(create<ast::VariableDeclStatement>(var));
|
2020-11-14 01:09:04 +00:00
|
|
|
body->append(create<ast::ReturnStatement>());
|
2020-11-14 01:13:04 +00:00
|
|
|
|
2020-11-16 16:41:47 +00:00
|
|
|
auto* func = create<ast::Function>("a", params, &void_type, body);
|
2020-11-14 01:13:04 +00:00
|
|
|
func->add_decoration(
|
|
|
|
create<ast::StageDecoration>(ast::PipelineStage::kCompute, Source{}));
|
2020-11-05 14:52:32 +00:00
|
|
|
|
2020-11-18 20:58:20 +00:00
|
|
|
mod->AddFunction(func);
|
2020-11-05 14:52:32 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
{
|
|
|
|
ast::VariableList params;
|
2020-11-16 16:31:07 +00:00
|
|
|
auto* var = create<ast::Variable>("v", ast::StorageClass::kFunction, &f32);
|
2020-11-14 01:09:04 +00:00
|
|
|
var->set_constructor(create<ast::MemberAccessorExpression>(
|
|
|
|
create<ast::IdentifierExpression>("data"),
|
|
|
|
create<ast::IdentifierExpression>("d")));
|
|
|
|
|
2020-11-16 16:31:07 +00:00
|
|
|
auto* body = create<ast::BlockStatement>();
|
2020-11-16 16:41:47 +00:00
|
|
|
body->append(create<ast::VariableDeclStatement>(var));
|
2020-11-14 01:09:04 +00:00
|
|
|
body->append(create<ast::ReturnStatement>());
|
2020-11-14 01:13:04 +00:00
|
|
|
|
2020-11-16 16:41:47 +00:00
|
|
|
auto* func = create<ast::Function>("b", params, &void_type, body);
|
2020-11-14 01:13:04 +00:00
|
|
|
func->add_decoration(
|
|
|
|
create<ast::StageDecoration>(ast::PipelineStage::kCompute, Source{}));
|
2020-11-05 14:52:32 +00:00
|
|
|
|
2020-11-18 20:58:20 +00:00
|
|
|
mod->AddFunction(func);
|
2020-11-05 14:52:32 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
ASSERT_TRUE(td.Determine()) << td.error();
|
|
|
|
|
|
|
|
ASSERT_TRUE(b.Build());
|
|
|
|
EXPECT_EQ(DumpBuilder(b), R"(OpCapability Shader
|
2020-11-07 02:03:45 +00:00
|
|
|
OpMemoryModel Logical GLSL450
|
2020-11-12 15:42:20 +00:00
|
|
|
OpEntryPoint GLCompute %7 "a"
|
|
|
|
OpEntryPoint GLCompute %17 "b"
|
2020-11-05 14:52:32 +00:00
|
|
|
OpExecutionMode %7 LocalSize 1 1 1
|
|
|
|
OpExecutionMode %17 LocalSize 1 1 1
|
2020-11-10 21:49:56 +00:00
|
|
|
OpName %3 "tint_44617461"
|
|
|
|
OpMemberName %3 0 "tint_64"
|
|
|
|
OpName %1 "tint_64617461"
|
|
|
|
OpName %7 "tint_61"
|
2020-11-16 15:06:37 +00:00
|
|
|
OpName %14 "tint_76"
|
2020-11-10 21:49:56 +00:00
|
|
|
OpName %17 "tint_62"
|
2020-11-16 15:06:37 +00:00
|
|
|
OpName %21 "tint_76"
|
2020-11-05 14:52:32 +00:00
|
|
|
OpDecorate %3 Block
|
|
|
|
OpMemberDecorate %3 0 Offset 0
|
|
|
|
OpDecorate %1 Binding 0
|
|
|
|
OpDecorate %1 DescriptorSet 0
|
|
|
|
%4 = OpTypeFloat 32
|
|
|
|
%3 = OpTypeStruct %4
|
|
|
|
%2 = OpTypePointer StorageBuffer %3
|
|
|
|
%1 = OpVariable %2 StorageBuffer
|
|
|
|
%6 = OpTypeVoid
|
|
|
|
%5 = OpTypeFunction %6
|
|
|
|
%9 = OpTypeInt 32 0
|
|
|
|
%10 = OpConstant %9 0
|
|
|
|
%11 = OpTypePointer StorageBuffer %4
|
2020-11-16 15:06:37 +00:00
|
|
|
%15 = OpTypePointer Function %4
|
|
|
|
%16 = OpConstantNull %4
|
2020-11-05 14:52:32 +00:00
|
|
|
%7 = OpFunction %6 None %5
|
|
|
|
%8 = OpLabel
|
2020-11-16 15:06:37 +00:00
|
|
|
%14 = OpVariable %15 Function %16
|
2020-11-05 14:52:32 +00:00
|
|
|
%12 = OpAccessChain %11 %1 %10
|
2020-11-16 15:06:37 +00:00
|
|
|
%13 = OpLoad %4 %12
|
|
|
|
OpStore %14 %13
|
2020-11-05 14:52:32 +00:00
|
|
|
OpReturn
|
|
|
|
OpFunctionEnd
|
|
|
|
%17 = OpFunction %6 None %5
|
|
|
|
%18 = OpLabel
|
2020-11-16 15:06:37 +00:00
|
|
|
%21 = OpVariable %15 Function %16
|
2020-11-05 14:52:32 +00:00
|
|
|
%19 = OpAccessChain %11 %1 %10
|
2020-11-16 15:06:37 +00:00
|
|
|
%20 = OpLoad %4 %19
|
|
|
|
OpStore %21 %20
|
2020-11-05 14:52:32 +00:00
|
|
|
OpReturn
|
|
|
|
OpFunctionEnd
|
|
|
|
)");
|
|
|
|
}
|
|
|
|
|
2020-03-26 15:31:43 +00:00
|
|
|
} // namespace
|
2020-03-25 19:43:20 +00:00
|
|
|
} // namespace spirv
|
|
|
|
} // namespace writer
|
|
|
|
} // namespace tint
|