[spirv-writer] Generate any intrinsic
This CL adds the necessary code to generate an OpAny instruction. Bug: tint:5 Change-Id: I558b2cbf4bade3b4ab17997d24dcffddc32e2b41 Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/22620 Reviewed-by: David Neto <dneto@google.com>
This commit is contained in:
parent
06d49471a0
commit
3e7dc82b35
3
BUILD.gn
3
BUILD.gn
|
@ -250,6 +250,8 @@ source_set("libtint_core_src") {
|
|||
"src/ast/import.h",
|
||||
"src/ast/int_literal.cc",
|
||||
"src/ast/int_literal.h",
|
||||
"src/ast/intrinsic.cc",
|
||||
"src/ast/intrinsic.h",
|
||||
"src/ast/kill_statement.cc",
|
||||
"src/ast/kill_statement.h",
|
||||
"src/ast/literal.cc",
|
||||
|
@ -686,6 +688,7 @@ source_set("tint_unittests_spv_writer_src") {
|
|||
"src/writer/spirv/builder_global_variable_test.cc",
|
||||
"src/writer/spirv/builder_ident_expression_test.cc",
|
||||
"src/writer/spirv/builder_if_test.cc",
|
||||
"src/writer/spirv/builder_intrinsic_test.cc",
|
||||
"src/writer/spirv/builder_kill_test.cc",
|
||||
"src/writer/spirv/builder_literal_test.cc",
|
||||
"src/writer/spirv/builder_loop_test.cc",
|
||||
|
|
|
@ -87,6 +87,8 @@ set(TINT_LIB_SRCS
|
|||
ast/import.h
|
||||
ast/int_literal.cc
|
||||
ast/int_literal.h
|
||||
ast/intrinsic.cc
|
||||
ast/intrinsic.h
|
||||
ast/kill_statement.cc
|
||||
ast/kill_statement.h
|
||||
ast/literal.h
|
||||
|
@ -422,6 +424,7 @@ if(${TINT_BUILD_SPV_WRITER})
|
|||
writer/spirv/builder_global_variable_test.cc
|
||||
writer/spirv/builder_ident_expression_test.cc
|
||||
writer/spirv/builder_if_test.cc
|
||||
writer/spirv/builder_intrinsic_test.cc
|
||||
writer/spirv/builder_kill_test.cc
|
||||
writer/spirv/builder_literal_test.cc
|
||||
writer/spirv/builder_loop_test.cc
|
||||
|
|
|
@ -0,0 +1,40 @@
|
|||
// 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 "src/ast/intrinsic.h"
|
||||
|
||||
namespace tint {
|
||||
namespace ast {
|
||||
namespace intrinsic {
|
||||
|
||||
bool IsDerivative(const std::string& name) {
|
||||
return name == "dpdx" || name == "dpdx_fine" || name == "dpdx_coarse" ||
|
||||
name == "dpdy" || name == "dpdy_fine" || name == "dpdy_coarse" ||
|
||||
name == "fwidth" || name == "fwidth_fine" || name == "fwidth_coarse";
|
||||
}
|
||||
|
||||
bool IsFloatClassificationIntrinsic(const std::string& name) {
|
||||
return name == "is_finite" || name == "is_inf" || name == "is_nan" ||
|
||||
name == "is_normal";
|
||||
}
|
||||
|
||||
bool IsIntrinsic(const std::string& name) {
|
||||
return IsDerivative(name) || name == "all" || name == "any" ||
|
||||
IsFloatClassificationIntrinsic(name) || name == "dot" ||
|
||||
name == "outer_product";
|
||||
}
|
||||
|
||||
} // namespace intrinsic
|
||||
} // namespace ast
|
||||
} // namespace tint
|
|
@ -0,0 +1,43 @@
|
|||
// 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.
|
||||
|
||||
#ifndef SRC_AST_INTRINSIC_H_
|
||||
#define SRC_AST_INTRINSIC_H_
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace tint {
|
||||
namespace ast {
|
||||
namespace intrinsic {
|
||||
|
||||
/// Determine if the given |name | is a derivative intrinsic
|
||||
/// @param name the name to check
|
||||
/// @returns true if the given |name| is a derivative intrinsic
|
||||
bool IsDerivative(const std::string& name);
|
||||
|
||||
/// Determines if the given |name| is a float classification intrinsic
|
||||
/// @param name the name to check
|
||||
/// @returns true if the given |name| is a float intrinsic
|
||||
bool IsFloatClassificationIntrinsic(const std::string& name);
|
||||
|
||||
/// Determines if the given |name| is an intrinsic
|
||||
/// @param name the name to check
|
||||
/// @returns true if the given |name| is an intrinsic
|
||||
bool IsIntrinsic(const std::string& name);
|
||||
|
||||
} // namespace intrinsic
|
||||
} // namespace ast
|
||||
} // namespace tint
|
||||
|
||||
#endif // SRC_AST_INTRINSIC_H_
|
|
@ -29,6 +29,7 @@
|
|||
#include "src/ast/else_statement.h"
|
||||
#include "src/ast/identifier_expression.h"
|
||||
#include "src/ast/if_statement.h"
|
||||
#include "src/ast/intrinsic.h"
|
||||
#include "src/ast/loop_statement.h"
|
||||
#include "src/ast/member_accessor_expression.h"
|
||||
#include "src/ast/return_statement.h"
|
||||
|
@ -46,25 +47,6 @@
|
|||
#include "src/ast/variable_decl_statement.h"
|
||||
|
||||
namespace tint {
|
||||
namespace {
|
||||
|
||||
bool IsDerivative(const std::string& name) {
|
||||
return name == "dpdx" || name == "dpdx_fine" || name == "dpdx_coarse" ||
|
||||
name == "dpdy" || name == "dpdy_fine" || name == "dpdy_coarse" ||
|
||||
name == "fwidth" || name == "fwidth_fine" || name == "fwidth_coarse";
|
||||
}
|
||||
|
||||
bool IsFloatIntrinsic(const std::string& name) {
|
||||
return name == "is_finite" || name == "is_inf" || name == "is_nan" ||
|
||||
name == "is_normal";
|
||||
}
|
||||
|
||||
bool IsIntrinsic(const std::string& name) {
|
||||
return IsDerivative(name) || name == "all" || name == "any" ||
|
||||
IsFloatIntrinsic(name) || name == "dot" || name == "outer_product";
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
TypeDeterminer::TypeDeterminer(Context* ctx, ast::Module* mod)
|
||||
: ctx_(*ctx), mod_(mod) {}
|
||||
|
@ -321,7 +303,7 @@ bool TypeDeterminer::DetermineCall(ast::CallExpression* expr) {
|
|||
if (expr->func()->IsIdentifier()) {
|
||||
auto* ident = expr->func()->AsIdentifier();
|
||||
|
||||
if (IsIntrinsic(ident->name())) {
|
||||
if (ast::intrinsic::IsIntrinsic(ident->name())) {
|
||||
if (!DetermineIntrinsic(ident->name(), expr))
|
||||
return false;
|
||||
|
||||
|
@ -364,7 +346,7 @@ bool TypeDeterminer::DetermineCall(ast::CallExpression* expr) {
|
|||
|
||||
bool TypeDeterminer::DetermineIntrinsic(const std::string& name,
|
||||
ast::CallExpression* expr) {
|
||||
if (IsDerivative(name)) {
|
||||
if (ast::intrinsic::IsDerivative(name)) {
|
||||
if (expr->params().size() != 1) {
|
||||
set_error(expr->source(), "incorrect number of parameters for " + name);
|
||||
return false;
|
||||
|
@ -383,7 +365,7 @@ bool TypeDeterminer::DetermineIntrinsic(const std::string& name,
|
|||
ctx_.type_mgr().Get(std::make_unique<ast::type::BoolType>()));
|
||||
return true;
|
||||
}
|
||||
if (IsFloatIntrinsic(name)) {
|
||||
if (ast::intrinsic::IsFloatClassificationIntrinsic(name)) {
|
||||
if (expr->params().size() != 1) {
|
||||
set_error(expr->source(), "incorrect number of parameters for " + name);
|
||||
return false;
|
||||
|
|
|
@ -33,6 +33,7 @@
|
|||
#include "src/ast/float_literal.h"
|
||||
#include "src/ast/identifier_expression.h"
|
||||
#include "src/ast/if_statement.h"
|
||||
#include "src/ast/intrinsic.h"
|
||||
#include "src/ast/location_decoration.h"
|
||||
#include "src/ast/loop_statement.h"
|
||||
#include "src/ast/member_accessor_expression.h"
|
||||
|
@ -1163,15 +1164,23 @@ uint32_t Builder::GenerateBinaryExpression(ast::BinaryExpression* expr) {
|
|||
}
|
||||
|
||||
uint32_t Builder::GenerateCallExpression(ast::CallExpression* expr) {
|
||||
// TODO(dsinclair): Support regular function calls
|
||||
if (!expr->func()->IsIdentifier() ||
|
||||
!expr->func()->AsIdentifier()->has_path()) {
|
||||
error_ = "function calls not supported yet.";
|
||||
if (!expr->func()->IsIdentifier()) {
|
||||
error_ = "invalid function name";
|
||||
return 0;
|
||||
}
|
||||
|
||||
auto* ident = expr->func()->AsIdentifier();
|
||||
|
||||
if (!ident->has_path() && ast::intrinsic::IsIntrinsic(ident->name())) {
|
||||
return GenerateIntrinsic(ident->name(), expr);
|
||||
}
|
||||
|
||||
// TODO(dsinclair): Support regular function calls
|
||||
if (!ident->has_path()) {
|
||||
error_ = "function calls not supported yet.";
|
||||
return 0;
|
||||
}
|
||||
|
||||
auto type_id = GenerateTypeIfNeeded(expr->func()->result_type());
|
||||
if (type_id == 0) {
|
||||
return 0;
|
||||
|
@ -1215,6 +1224,40 @@ uint32_t Builder::GenerateCallExpression(ast::CallExpression* expr) {
|
|||
return result_id;
|
||||
}
|
||||
|
||||
uint32_t Builder::GenerateIntrinsic(const std::string& name,
|
||||
ast::CallExpression* call) {
|
||||
auto result = result_op();
|
||||
auto result_id = result.to_i();
|
||||
|
||||
auto result_type_id = GenerateTypeIfNeeded(call->result_type());
|
||||
if (result_type_id == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
std::vector<Operand> params = {Operand::Int(result_type_id), result};
|
||||
for (const auto& p : call->params()) {
|
||||
auto val_id = GenerateExpression(p.get());
|
||||
if (val_id == 0) {
|
||||
return 0;
|
||||
}
|
||||
val_id = GenerateLoadIfNeeded(p->result_type(), val_id);
|
||||
|
||||
params.push_back(Operand::Int(val_id));
|
||||
}
|
||||
|
||||
spv::Op op = spv::Op::OpNop;
|
||||
if (name == "any") {
|
||||
op = spv::Op::OpAny;
|
||||
}
|
||||
if (op == spv::Op::OpNop) {
|
||||
error_ = "unable to determine operator for: " + name;
|
||||
return 0;
|
||||
}
|
||||
push_function_inst(op, params);
|
||||
|
||||
return result_id;
|
||||
}
|
||||
|
||||
uint32_t Builder::GenerateCastExpression(ast::CastExpression* cast) {
|
||||
auto result = result_op();
|
||||
auto result_id = result.to_i();
|
||||
|
|
|
@ -286,6 +286,12 @@ class Builder {
|
|||
/// @param expr the expression to generate
|
||||
/// @returns the expression ID on success or 0 otherwise
|
||||
uint32_t GenerateCallExpression(ast::CallExpression* expr);
|
||||
/// Generates an intrinsic call
|
||||
/// @param name the intrinsic name
|
||||
/// @param call the call expression
|
||||
/// @returns the expression ID on success or 0 otherwise
|
||||
uint32_t GenerateIntrinsic(const std::string& name,
|
||||
ast::CallExpression* call);
|
||||
/// Generates a cast expression
|
||||
/// @param expr the expression to generate
|
||||
/// @returns the expression ID on success or 0 otherwise
|
||||
|
|
|
@ -0,0 +1,74 @@
|
|||
// 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 "gtest/gtest.h"
|
||||
#include "src/ast/call_expression.h"
|
||||
#include "src/ast/identifier_expression.h"
|
||||
#include "src/ast/type/bool_type.h"
|
||||
#include "src/ast/type/vector_type.h"
|
||||
#include "src/ast/variable.h"
|
||||
#include "src/context.h"
|
||||
#include "src/type_determiner.h"
|
||||
#include "src/writer/spirv/builder.h"
|
||||
#include "src/writer/spirv/spv_dump.h"
|
||||
|
||||
namespace tint {
|
||||
namespace writer {
|
||||
namespace spirv {
|
||||
namespace {
|
||||
|
||||
using BuilderTest = testing::Test;
|
||||
|
||||
TEST_F(BuilderTest, Call_Any) {
|
||||
ast::type::BoolType bool_type;
|
||||
ast::type::VectorType vec3(&bool_type, 3);
|
||||
|
||||
auto var =
|
||||
std::make_unique<ast::Variable>("v", ast::StorageClass::kPrivate, &vec3);
|
||||
|
||||
ast::ExpressionList params;
|
||||
params.push_back(std::make_unique<ast::IdentifierExpression>("v"));
|
||||
ast::CallExpression expr(std::make_unique<ast::IdentifierExpression>("any"),
|
||||
std::move(params));
|
||||
|
||||
Context ctx;
|
||||
ast::Module mod;
|
||||
TypeDeterminer td(&ctx, &mod);
|
||||
td.RegisterVariableForTesting(var.get());
|
||||
|
||||
ASSERT_TRUE(td.DetermineResultType(&expr)) << td.error();
|
||||
|
||||
Builder b(&mod);
|
||||
b.push_function(Function{});
|
||||
ASSERT_TRUE(b.GenerateGlobalVariable(var.get())) << b.error();
|
||||
|
||||
EXPECT_EQ(b.GenerateCallExpression(&expr), 6u) << b.error();
|
||||
EXPECT_EQ(DumpInstructions(b.types()), R"(%4 = OpTypeBool
|
||||
%3 = OpTypeVector %4 3
|
||||
%2 = OpTypePointer Private %3
|
||||
%5 = OpConstantNull %3
|
||||
%1 = OpVariable %2 Private %5
|
||||
)");
|
||||
EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
|
||||
R"(%7 = OpLoad %3 %1
|
||||
%6 = OpAny %4 %7
|
||||
)");
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace spirv
|
||||
} // namespace writer
|
||||
} // namespace tint
|
Loading…
Reference in New Issue