mirror of
https://github.com/encounter/dawn-cmake.git
synced 2025-05-13 19:01:24 +00:00
Update builtin methods.
This CL removes the import mechanism, the identifier paths and updates all of the standard library methods to be builtins. Bug: tint:242 Change-Id: If09b98a155ae49ced3986ba2c9b517a060693006 Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/28720 Commit-Queue: dan sinclair <dsinclair@chromium.org> Reviewed-by: Ryan Harrison <rharrison@chromium.org>
This commit is contained in:
parent
5f8126271d
commit
b4fee2f824
5
BUILD.gn
5
BUILD.gn
@ -269,8 +269,6 @@ source_set("libtint_core_src") {
|
|||||||
"src/ast/identifier_expression.h",
|
"src/ast/identifier_expression.h",
|
||||||
"src/ast/if_statement.cc",
|
"src/ast/if_statement.cc",
|
||||||
"src/ast/if_statement.h",
|
"src/ast/if_statement.h",
|
||||||
"src/ast/import.cc",
|
|
||||||
"src/ast/import.h",
|
|
||||||
"src/ast/int_literal.cc",
|
"src/ast/int_literal.cc",
|
||||||
"src/ast/int_literal.h",
|
"src/ast/int_literal.h",
|
||||||
"src/ast/intrinsic.cc",
|
"src/ast/intrinsic.cc",
|
||||||
@ -710,7 +708,6 @@ source_set("tint_unittests_core_src") {
|
|||||||
"src/ast/function_test.cc",
|
"src/ast/function_test.cc",
|
||||||
"src/ast/identifier_expression_test.cc",
|
"src/ast/identifier_expression_test.cc",
|
||||||
"src/ast/if_statement_test.cc",
|
"src/ast/if_statement_test.cc",
|
||||||
"src/ast/import_test.cc",
|
|
||||||
"src/ast/int_literal_test.cc",
|
"src/ast/int_literal_test.cc",
|
||||||
"src/ast/location_decoration_test.cc",
|
"src/ast/location_decoration_test.cc",
|
||||||
"src/ast/loop_statement_test.cc",
|
"src/ast/loop_statement_test.cc",
|
||||||
@ -908,7 +905,6 @@ source_set("tint_unittests_wgsl_reader_src") {
|
|||||||
"src/reader/wgsl/parser_impl_global_variable_decl_test.cc",
|
"src/reader/wgsl/parser_impl_global_variable_decl_test.cc",
|
||||||
"src/reader/wgsl/parser_impl_if_stmt_test.cc",
|
"src/reader/wgsl/parser_impl_if_stmt_test.cc",
|
||||||
"src/reader/wgsl/parser_impl_image_storage_type_test.cc",
|
"src/reader/wgsl/parser_impl_image_storage_type_test.cc",
|
||||||
"src/reader/wgsl/parser_impl_import_decl_test.cc",
|
|
||||||
"src/reader/wgsl/parser_impl_inclusive_or_expression_test.cc",
|
"src/reader/wgsl/parser_impl_inclusive_or_expression_test.cc",
|
||||||
"src/reader/wgsl/parser_impl_logical_and_expression_test.cc",
|
"src/reader/wgsl/parser_impl_logical_and_expression_test.cc",
|
||||||
"src/reader/wgsl/parser_impl_logical_or_expression_test.cc",
|
"src/reader/wgsl/parser_impl_logical_or_expression_test.cc",
|
||||||
@ -991,7 +987,6 @@ source_set("tint_unittests_wgsl_writer_src") {
|
|||||||
"src/writer/wgsl/generator_impl_function_test.cc",
|
"src/writer/wgsl/generator_impl_function_test.cc",
|
||||||
"src/writer/wgsl/generator_impl_identifier_test.cc",
|
"src/writer/wgsl/generator_impl_identifier_test.cc",
|
||||||
"src/writer/wgsl/generator_impl_if_test.cc",
|
"src/writer/wgsl/generator_impl_if_test.cc",
|
||||||
"src/writer/wgsl/generator_impl_import_test.cc",
|
|
||||||
"src/writer/wgsl/generator_impl_loop_test.cc",
|
"src/writer/wgsl/generator_impl_loop_test.cc",
|
||||||
"src/writer/wgsl/generator_impl_member_accessor_test.cc",
|
"src/writer/wgsl/generator_impl_member_accessor_test.cc",
|
||||||
"src/writer/wgsl/generator_impl_return_test.cc",
|
"src/writer/wgsl/generator_impl_return_test.cc",
|
||||||
|
@ -90,8 +90,6 @@ set(TINT_LIB_SRCS
|
|||||||
ast/identifier_expression.h
|
ast/identifier_expression.h
|
||||||
ast/if_statement.cc
|
ast/if_statement.cc
|
||||||
ast/if_statement.h
|
ast/if_statement.h
|
||||||
ast/import.cc
|
|
||||||
ast/import.h
|
|
||||||
ast/int_literal.cc
|
ast/int_literal.cc
|
||||||
ast/int_literal.h
|
ast/int_literal.h
|
||||||
ast/intrinsic.cc
|
ast/intrinsic.cc
|
||||||
@ -319,7 +317,6 @@ set(TINT_TEST_SRCS
|
|||||||
ast/function_test.cc
|
ast/function_test.cc
|
||||||
ast/identifier_expression_test.cc
|
ast/identifier_expression_test.cc
|
||||||
ast/if_statement_test.cc
|
ast/if_statement_test.cc
|
||||||
ast/import_test.cc
|
|
||||||
ast/int_literal_test.cc
|
ast/int_literal_test.cc
|
||||||
ast/location_decoration_test.cc
|
ast/location_decoration_test.cc
|
||||||
ast/loop_statement_test.cc
|
ast/loop_statement_test.cc
|
||||||
@ -439,7 +436,6 @@ if(${TINT_BUILD_WGSL_READER})
|
|||||||
reader/wgsl/parser_impl_global_variable_decl_test.cc
|
reader/wgsl/parser_impl_global_variable_decl_test.cc
|
||||||
reader/wgsl/parser_impl_if_stmt_test.cc
|
reader/wgsl/parser_impl_if_stmt_test.cc
|
||||||
reader/wgsl/parser_impl_image_storage_type_test.cc
|
reader/wgsl/parser_impl_image_storage_type_test.cc
|
||||||
reader/wgsl/parser_impl_import_decl_test.cc
|
|
||||||
reader/wgsl/parser_impl_inclusive_or_expression_test.cc
|
reader/wgsl/parser_impl_inclusive_or_expression_test.cc
|
||||||
reader/wgsl/parser_impl_logical_and_expression_test.cc
|
reader/wgsl/parser_impl_logical_and_expression_test.cc
|
||||||
reader/wgsl/parser_impl_logical_or_expression_test.cc
|
reader/wgsl/parser_impl_logical_or_expression_test.cc
|
||||||
@ -538,7 +534,6 @@ if(${TINT_BUILD_WGSL_WRITER})
|
|||||||
writer/wgsl/generator_impl_function_test.cc
|
writer/wgsl/generator_impl_function_test.cc
|
||||||
writer/wgsl/generator_impl_identifier_test.cc
|
writer/wgsl/generator_impl_identifier_test.cc
|
||||||
writer/wgsl/generator_impl_if_test.cc
|
writer/wgsl/generator_impl_if_test.cc
|
||||||
writer/wgsl/generator_impl_import_test.cc
|
|
||||||
writer/wgsl/generator_impl_loop_test.cc
|
writer/wgsl/generator_impl_loop_test.cc
|
||||||
writer/wgsl/generator_impl_member_accessor_test.cc
|
writer/wgsl/generator_impl_member_accessor_test.cc
|
||||||
writer/wgsl/generator_impl_return_test.cc
|
writer/wgsl/generator_impl_return_test.cc
|
||||||
|
@ -18,62 +18,27 @@ namespace tint {
|
|||||||
namespace ast {
|
namespace ast {
|
||||||
|
|
||||||
IdentifierExpression::IdentifierExpression(const std::string& name)
|
IdentifierExpression::IdentifierExpression(const std::string& name)
|
||||||
: Expression(), segments_({name}) {}
|
: Expression(), name_(name) {}
|
||||||
|
|
||||||
IdentifierExpression::IdentifierExpression(const Source& source,
|
IdentifierExpression::IdentifierExpression(const Source& source,
|
||||||
const std::string& name)
|
const std::string& name)
|
||||||
: Expression(source), segments_({name}) {}
|
: Expression(source), name_(name) {}
|
||||||
|
|
||||||
IdentifierExpression::IdentifierExpression(std::vector<std::string> segments)
|
|
||||||
: Expression(), segments_(std::move(segments)) {}
|
|
||||||
|
|
||||||
IdentifierExpression::IdentifierExpression(const Source& source,
|
|
||||||
std::vector<std::string> segments)
|
|
||||||
: Expression(source), segments_(std::move(segments)) {}
|
|
||||||
|
|
||||||
IdentifierExpression::IdentifierExpression(IdentifierExpression&&) = default;
|
IdentifierExpression::IdentifierExpression(IdentifierExpression&&) = default;
|
||||||
|
|
||||||
IdentifierExpression::~IdentifierExpression() = default;
|
IdentifierExpression::~IdentifierExpression() = default;
|
||||||
|
|
||||||
std::string IdentifierExpression::path() const {
|
|
||||||
if (segments_.size() < 2) {
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string path = "";
|
|
||||||
// We skip the last segment as that's the name, not part of the path
|
|
||||||
for (size_t i = 0; i < segments_.size() - 1; ++i) {
|
|
||||||
if (i > 0) {
|
|
||||||
path += "::";
|
|
||||||
}
|
|
||||||
path += segments_[i];
|
|
||||||
}
|
|
||||||
return path;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool IdentifierExpression::IsIdentifier() const {
|
bool IdentifierExpression::IsIdentifier() const {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool IdentifierExpression::IsValid() const {
|
bool IdentifierExpression::IsValid() const {
|
||||||
if (segments_.size() == 0)
|
return !name_.empty();
|
||||||
return false;
|
|
||||||
|
|
||||||
for (const auto& segment : segments_) {
|
|
||||||
if (segment.size() == 0)
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void IdentifierExpression::to_str(std::ostream& out, size_t indent) const {
|
void IdentifierExpression::to_str(std::ostream& out, size_t indent) const {
|
||||||
make_indent(out, indent);
|
make_indent(out, indent);
|
||||||
out << "Identifier{";
|
out << "Identifier{" << name_ << "}" << std::endl;
|
||||||
if (has_path()) {
|
|
||||||
out << path() << "::";
|
|
||||||
}
|
|
||||||
out << name();
|
|
||||||
out << "}" << std::endl;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace ast
|
} // namespace ast
|
||||||
|
@ -16,10 +16,9 @@
|
|||||||
#define SRC_AST_IDENTIFIER_EXPRESSION_H_
|
#define SRC_AST_IDENTIFIER_EXPRESSION_H_
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <utility>
|
|
||||||
#include <vector>
|
|
||||||
|
|
||||||
#include "src/ast/expression.h"
|
#include "src/ast/expression.h"
|
||||||
|
#include "src/ast/intrinsic.h"
|
||||||
|
|
||||||
namespace tint {
|
namespace tint {
|
||||||
namespace ast {
|
namespace ast {
|
||||||
@ -34,31 +33,20 @@ class IdentifierExpression : public Expression {
|
|||||||
/// @param source the source
|
/// @param source the source
|
||||||
/// @param name the name
|
/// @param name the name
|
||||||
IdentifierExpression(const Source& source, const std::string& name);
|
IdentifierExpression(const Source& source, const std::string& name);
|
||||||
/// Constructor
|
|
||||||
/// @param segments the name segments
|
|
||||||
explicit IdentifierExpression(std::vector<std::string> segments);
|
|
||||||
/// Constructor
|
|
||||||
/// @param source the identifier expression source
|
|
||||||
/// @param segments the name segments
|
|
||||||
IdentifierExpression(const Source& source, std::vector<std::string> segments);
|
|
||||||
/// Move constructor
|
/// Move constructor
|
||||||
IdentifierExpression(IdentifierExpression&&);
|
IdentifierExpression(IdentifierExpression&&);
|
||||||
~IdentifierExpression() override;
|
~IdentifierExpression() override;
|
||||||
|
|
||||||
/// Sets the name segments
|
|
||||||
/// @param segments the name segments
|
|
||||||
void set_segments(std::vector<std::string> segments) {
|
|
||||||
segments_ = std::move(segments);
|
|
||||||
}
|
|
||||||
/// @returns the name
|
|
||||||
std::vector<std::string> segments() const { return segments_; }
|
|
||||||
|
|
||||||
/// @returns true if this identifier has a path component
|
|
||||||
bool has_path() const { return segments_.size() > 1; }
|
|
||||||
/// @returns the path part of the identifier or blank if no path
|
|
||||||
std::string path() const;
|
|
||||||
/// @returns the name part of the identifier
|
/// @returns the name part of the identifier
|
||||||
std::string name() const { return segments_.back(); }
|
std::string name() const { return name_; }
|
||||||
|
|
||||||
|
/// Sets the intrinsic for this identifier
|
||||||
|
/// @param i the intrinsic to set
|
||||||
|
void set_intrinsic(Intrinsic i) { intrinsic_ = i; }
|
||||||
|
/// @returns the intrinsic this identifier represents
|
||||||
|
Intrinsic intrinsic() const { return intrinsic_; }
|
||||||
|
/// @returns true if this identifier is for an intrinsic
|
||||||
|
bool IsIntrinsic() const { return intrinsic_ != Intrinsic::kNone; }
|
||||||
|
|
||||||
/// @returns true if this is an identifier expression
|
/// @returns true if this is an identifier expression
|
||||||
bool IsIdentifier() const override;
|
bool IsIdentifier() const override;
|
||||||
@ -74,7 +62,8 @@ class IdentifierExpression : public Expression {
|
|||||||
private:
|
private:
|
||||||
IdentifierExpression(const IdentifierExpression&) = delete;
|
IdentifierExpression(const IdentifierExpression&) = delete;
|
||||||
|
|
||||||
std::vector<std::string> segments_;
|
Intrinsic intrinsic_ = Intrinsic::kNone;
|
||||||
|
std::string name_;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace ast
|
} // namespace ast
|
||||||
|
@ -24,19 +24,11 @@ using IdentifierExpressionTest = testing::Test;
|
|||||||
|
|
||||||
TEST_F(IdentifierExpressionTest, Creation) {
|
TEST_F(IdentifierExpressionTest, Creation) {
|
||||||
IdentifierExpression i("ident");
|
IdentifierExpression i("ident");
|
||||||
ASSERT_EQ(i.segments().size(), 1u);
|
|
||||||
EXPECT_EQ(i.segments()[0], "ident");
|
|
||||||
EXPECT_EQ(i.path(), "");
|
|
||||||
EXPECT_EQ(i.name(), "ident");
|
EXPECT_EQ(i.name(), "ident");
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(IdentifierExpressionTest, Creation_WithSource) {
|
TEST_F(IdentifierExpressionTest, Creation_WithSource) {
|
||||||
IdentifierExpression i(Source{20, 2}, {"ns1", "ns2", "ident"});
|
IdentifierExpression i(Source{20, 2}, "ident");
|
||||||
ASSERT_EQ(i.segments().size(), 3u);
|
|
||||||
EXPECT_EQ(i.segments()[0], "ns1");
|
|
||||||
EXPECT_EQ(i.segments()[1], "ns2");
|
|
||||||
EXPECT_EQ(i.segments()[2], "ident");
|
|
||||||
EXPECT_EQ(i.path(), "ns1::ns2");
|
|
||||||
EXPECT_EQ(i.name(), "ident");
|
EXPECT_EQ(i.name(), "ident");
|
||||||
|
|
||||||
auto src = i.source();
|
auto src = i.source();
|
||||||
@ -54,21 +46,11 @@ TEST_F(IdentifierExpressionTest, IsValid) {
|
|||||||
EXPECT_TRUE(i.IsValid());
|
EXPECT_TRUE(i.IsValid());
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(IdentifierExpressionTest, IsValid_WithNamespaces) {
|
|
||||||
IdentifierExpression i({"ns1", "n2", "ident"});
|
|
||||||
EXPECT_TRUE(i.IsValid());
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(IdentifierExpressionTest, IsValid_BlankName) {
|
TEST_F(IdentifierExpressionTest, IsValid_BlankName) {
|
||||||
IdentifierExpression i("");
|
IdentifierExpression i("");
|
||||||
EXPECT_FALSE(i.IsValid());
|
EXPECT_FALSE(i.IsValid());
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(IdentifierExpressionTest, IsValid_BlankNamespace) {
|
|
||||||
IdentifierExpression i({"ns1", "", "ident"});
|
|
||||||
EXPECT_FALSE(i.IsValid());
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(IdentifierExpressionTest, ToStr) {
|
TEST_F(IdentifierExpressionTest, ToStr) {
|
||||||
IdentifierExpression i("ident");
|
IdentifierExpression i("ident");
|
||||||
std::ostringstream out;
|
std::ostringstream out;
|
||||||
@ -77,14 +59,6 @@ TEST_F(IdentifierExpressionTest, ToStr) {
|
|||||||
)");
|
)");
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(IdentifierExpressionTest, ToStr_WithNamespace) {
|
|
||||||
IdentifierExpression i({"ns1", "ns2", "ident"});
|
|
||||||
std::ostringstream out;
|
|
||||||
i.to_str(out, 2);
|
|
||||||
EXPECT_EQ(out.str(), R"( Identifier{ns1::ns2::ident}
|
|
||||||
)");
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
} // namespace ast
|
} // namespace ast
|
||||||
} // namespace tint
|
} // namespace tint
|
||||||
|
@ -1,60 +0,0 @@
|
|||||||
// 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/import.h"
|
|
||||||
|
|
||||||
#include <cctype>
|
|
||||||
|
|
||||||
namespace tint {
|
|
||||||
namespace ast {
|
|
||||||
|
|
||||||
Import::Import() = default;
|
|
||||||
|
|
||||||
Import::Import(const std::string& path, const std::string& name)
|
|
||||||
: Node(), path_(path), name_(name) {}
|
|
||||||
|
|
||||||
Import::Import(const Source& source,
|
|
||||||
const std::string& path,
|
|
||||||
const std::string& name)
|
|
||||||
: Node(source), path_(path), name_(name) {}
|
|
||||||
|
|
||||||
Import::Import(Import&&) = default;
|
|
||||||
|
|
||||||
Import::~Import() = default;
|
|
||||||
|
|
||||||
bool Import::IsValid() const {
|
|
||||||
if (path_.length() == 0) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto len = name_.length();
|
|
||||||
if (len == 0) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Verify the import name ends in a character, number or _
|
|
||||||
if (len > 2 && !std::isalnum(name_[len - 1]) && name_[len] != '_') {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Import::to_str(std::ostream& out, size_t indent) const {
|
|
||||||
make_indent(out, indent);
|
|
||||||
out << R"(Import{")" + path_ + R"(" as )" + name_ + "}" << std::endl;
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace ast
|
|
||||||
} // namespace tint
|
|
101
src/ast/import.h
101
src/ast/import.h
@ -1,101 +0,0 @@
|
|||||||
// 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_IMPORT_H_
|
|
||||||
#define SRC_AST_IMPORT_H_
|
|
||||||
|
|
||||||
#include <memory>
|
|
||||||
#include <ostream>
|
|
||||||
#include <string>
|
|
||||||
#include <unordered_map>
|
|
||||||
#include <vector>
|
|
||||||
|
|
||||||
#include "src/ast/node.h"
|
|
||||||
|
|
||||||
namespace tint {
|
|
||||||
namespace ast {
|
|
||||||
|
|
||||||
/// An import statement.
|
|
||||||
class Import : public Node {
|
|
||||||
public:
|
|
||||||
/// Create a new empty import statement
|
|
||||||
Import();
|
|
||||||
/// Create a new import statement
|
|
||||||
/// @param path The import path e.g. GLSL.std.450
|
|
||||||
/// @param name The import reference name e.g. std
|
|
||||||
Import(const std::string& path, const std::string& name);
|
|
||||||
/// Create a new import statement
|
|
||||||
/// @param source The input source for the import statement
|
|
||||||
/// @param path The import path e.g. GLSL.std.430
|
|
||||||
/// @param name The import reference name e.g. std
|
|
||||||
Import(const Source& source,
|
|
||||||
const std::string& path,
|
|
||||||
const std::string& name);
|
|
||||||
/// Move constructor
|
|
||||||
Import(Import&&);
|
|
||||||
|
|
||||||
~Import() override;
|
|
||||||
|
|
||||||
/// Sets the import path
|
|
||||||
/// @param path the path to set
|
|
||||||
void set_path(const std::string& path) { path_ = path; }
|
|
||||||
/// @returns the import path
|
|
||||||
const std::string& path() const { return path_; }
|
|
||||||
/// Sets the import name
|
|
||||||
/// @param name the name to set
|
|
||||||
void set_name(const std::string& name) { name_ = name; }
|
|
||||||
/// @returns the import name
|
|
||||||
const std::string& name() const { return name_; }
|
|
||||||
|
|
||||||
/// Add the given |name| to map to the given |id|
|
|
||||||
/// @param name the name to map
|
|
||||||
/// @param id the id to map too
|
|
||||||
void AddMethodId(const std::string& name, uint32_t id) {
|
|
||||||
method_to_id_map_[name] = id;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Retrieves the id for a given name
|
|
||||||
/// @param name the name to lookup
|
|
||||||
/// @returns the id for the given name or 0 on failure
|
|
||||||
uint32_t GetIdForMethod(const std::string& name) const {
|
|
||||||
auto val = method_to_id_map_.find(name);
|
|
||||||
if (val == method_to_id_map_.end()) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
return val->second;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// @returns true if the name and path are both present
|
|
||||||
bool IsValid() const override;
|
|
||||||
|
|
||||||
/// Writes a representation of the node to the output stream
|
|
||||||
/// @param out the stream to write to
|
|
||||||
/// @param indent number of spaces to indent the node when writing
|
|
||||||
void to_str(std::ostream& out, size_t indent) const override;
|
|
||||||
|
|
||||||
private:
|
|
||||||
Import(const Import&) = delete;
|
|
||||||
|
|
||||||
std::string path_;
|
|
||||||
std::string name_;
|
|
||||||
std::unordered_map<std::string, uint32_t> method_to_id_map_;
|
|
||||||
};
|
|
||||||
|
|
||||||
/// A list of unique imports
|
|
||||||
using ImportList = std::vector<std::unique_ptr<Import>>;
|
|
||||||
|
|
||||||
} // namespace ast
|
|
||||||
} // namespace tint
|
|
||||||
|
|
||||||
#endif // SRC_AST_IMPORT_H_
|
|
@ -1,93 +0,0 @@
|
|||||||
// 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/import.h"
|
|
||||||
|
|
||||||
#include <sstream>
|
|
||||||
|
|
||||||
#include "gtest/gtest.h"
|
|
||||||
|
|
||||||
namespace tint {
|
|
||||||
namespace ast {
|
|
||||||
namespace {
|
|
||||||
|
|
||||||
using ImportTest = testing::Test;
|
|
||||||
|
|
||||||
TEST_F(ImportTest, Creation) {
|
|
||||||
Import i("GLSL.std.430", "std::glsl");
|
|
||||||
|
|
||||||
EXPECT_EQ(i.path(), "GLSL.std.430");
|
|
||||||
EXPECT_EQ(i.name(), "std::glsl");
|
|
||||||
EXPECT_EQ(i.line(), 0u);
|
|
||||||
EXPECT_EQ(i.column(), 0u);
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(ImportTest, CreationWithSource) {
|
|
||||||
Source s{27, 4};
|
|
||||||
Import i(s, "GLSL.std.430", "std::glsl");
|
|
||||||
|
|
||||||
EXPECT_EQ(i.path(), "GLSL.std.430");
|
|
||||||
EXPECT_EQ(i.name(), "std::glsl");
|
|
||||||
EXPECT_EQ(i.line(), 27u);
|
|
||||||
EXPECT_EQ(i.column(), 4u);
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(ImportTest, CreationEmpty) {
|
|
||||||
Source s{27, 4};
|
|
||||||
Import i;
|
|
||||||
i.set_source(s);
|
|
||||||
i.set_path("GLSL.std.430");
|
|
||||||
i.set_name("std::glsl");
|
|
||||||
|
|
||||||
EXPECT_EQ(i.path(), "GLSL.std.430");
|
|
||||||
EXPECT_EQ(i.name(), "std::glsl");
|
|
||||||
EXPECT_EQ(i.line(), 27u);
|
|
||||||
EXPECT_EQ(i.column(), 4u);
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(ImportTest, to_str) {
|
|
||||||
Import i{"GLSL.std.430", "std::glsl"};
|
|
||||||
std::ostringstream out;
|
|
||||||
i.to_str(out, 2);
|
|
||||||
EXPECT_EQ(out.str(), " Import{\"GLSL.std.430\" as std::glsl}\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(ImportTest, IsValid) {
|
|
||||||
Import i{"GLSL.std.430", "std::glsl"};
|
|
||||||
EXPECT_TRUE(i.IsValid());
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(ImportTest, IsValid_MissingPath) {
|
|
||||||
Import i{"", "std::glsl"};
|
|
||||||
EXPECT_FALSE(i.IsValid());
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(ImportTest, IsValid_MissingName) {
|
|
||||||
Import i{"GLSL.std.430", ""};
|
|
||||||
EXPECT_FALSE(i.IsValid());
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(ImportTest, IsValid_MissingBoth) {
|
|
||||||
Import i;
|
|
||||||
EXPECT_FALSE(i.IsValid());
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(ImportTest, IsValid_InvalidEndingCharacter) {
|
|
||||||
Import i{"GLSL.std.430", "std::glsl::"};
|
|
||||||
EXPECT_FALSE(i.IsValid());
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace
|
|
||||||
} // namespace ast
|
|
||||||
} // namespace tint
|
|
@ -16,37 +16,242 @@
|
|||||||
|
|
||||||
namespace tint {
|
namespace tint {
|
||||||
namespace ast {
|
namespace ast {
|
||||||
|
|
||||||
|
std::ostream& operator<<(std::ostream& out, Intrinsic i) {
|
||||||
|
switch (i) {
|
||||||
|
case Intrinsic::kAbs:
|
||||||
|
out << "abs";
|
||||||
|
break;
|
||||||
|
case Intrinsic::kAcos:
|
||||||
|
out << "acos";
|
||||||
|
break;
|
||||||
|
case Intrinsic::kAll:
|
||||||
|
out << "all";
|
||||||
|
break;
|
||||||
|
case Intrinsic::kAny:
|
||||||
|
out << "any";
|
||||||
|
break;
|
||||||
|
case Intrinsic::kAsin:
|
||||||
|
out << "asin";
|
||||||
|
break;
|
||||||
|
case Intrinsic::kAtan:
|
||||||
|
out << "atan";
|
||||||
|
break;
|
||||||
|
case Intrinsic::kAtan2:
|
||||||
|
out << "atan2";
|
||||||
|
break;
|
||||||
|
case Intrinsic::kCeil:
|
||||||
|
out << "ceil";
|
||||||
|
break;
|
||||||
|
case Intrinsic::kClamp:
|
||||||
|
out << "clamp";
|
||||||
|
break;
|
||||||
|
case Intrinsic::kCos:
|
||||||
|
out << "cos";
|
||||||
|
break;
|
||||||
|
case Intrinsic::kCosh:
|
||||||
|
out << "cosh";
|
||||||
|
break;
|
||||||
|
case Intrinsic::kCountOneBits:
|
||||||
|
out << "countOneBits";
|
||||||
|
break;
|
||||||
|
case Intrinsic::kCross:
|
||||||
|
out << "cross";
|
||||||
|
break;
|
||||||
|
case Intrinsic::kDeterminant:
|
||||||
|
out << "determinant";
|
||||||
|
break;
|
||||||
|
case Intrinsic::kDistance:
|
||||||
|
out << "distance";
|
||||||
|
break;
|
||||||
|
case Intrinsic::kDot:
|
||||||
|
out << "dot";
|
||||||
|
break;
|
||||||
|
case Intrinsic::kDpdx:
|
||||||
|
out << "dpdx";
|
||||||
|
break;
|
||||||
|
case Intrinsic::kDpdxCoarse:
|
||||||
|
out << "dpdxCoarse";
|
||||||
|
break;
|
||||||
|
case Intrinsic::kDpdxFine:
|
||||||
|
out << "dpdxFine";
|
||||||
|
break;
|
||||||
|
case Intrinsic::kDpdy:
|
||||||
|
out << "dpdy";
|
||||||
|
break;
|
||||||
|
case Intrinsic::kDpdyCoarse:
|
||||||
|
out << "dpdyCoarse";
|
||||||
|
break;
|
||||||
|
case Intrinsic::kDpdyFine:
|
||||||
|
out << "dpdyFine";
|
||||||
|
break;
|
||||||
|
case Intrinsic::kExp:
|
||||||
|
out << "exp";
|
||||||
|
break;
|
||||||
|
case Intrinsic::kExp2:
|
||||||
|
out << "exp2";
|
||||||
|
break;
|
||||||
|
case Intrinsic::kFaceForward:
|
||||||
|
out << "faceForward";
|
||||||
|
break;
|
||||||
|
case Intrinsic::kFloor:
|
||||||
|
out << "floor";
|
||||||
|
break;
|
||||||
|
case Intrinsic::kFma:
|
||||||
|
out << "fma";
|
||||||
|
break;
|
||||||
|
case Intrinsic::kFract:
|
||||||
|
out << "fract";
|
||||||
|
break;
|
||||||
|
case Intrinsic::kFrexp:
|
||||||
|
out << "frexp";
|
||||||
|
break;
|
||||||
|
case Intrinsic::kFwidth:
|
||||||
|
out << "fwidth";
|
||||||
|
break;
|
||||||
|
case Intrinsic::kFwidthCoarse:
|
||||||
|
out << "fwidthCoarse";
|
||||||
|
break;
|
||||||
|
case Intrinsic::kFwidthFine:
|
||||||
|
out << "fwidthFine";
|
||||||
|
break;
|
||||||
|
case Intrinsic::kInverseSqrt:
|
||||||
|
out << "inverseSqrt";
|
||||||
|
break;
|
||||||
|
case Intrinsic::kIsFinite:
|
||||||
|
out << "isFinite";
|
||||||
|
break;
|
||||||
|
case Intrinsic::kIsInf:
|
||||||
|
out << "isInf";
|
||||||
|
break;
|
||||||
|
case Intrinsic::kIsNan:
|
||||||
|
out << "isNan";
|
||||||
|
break;
|
||||||
|
case Intrinsic::kIsNormal:
|
||||||
|
out << "isNormal";
|
||||||
|
break;
|
||||||
|
case Intrinsic::kLdexp:
|
||||||
|
out << "ldexp";
|
||||||
|
break;
|
||||||
|
case Intrinsic::kLength:
|
||||||
|
out << "length";
|
||||||
|
break;
|
||||||
|
case Intrinsic::kLog:
|
||||||
|
out << "log";
|
||||||
|
break;
|
||||||
|
case Intrinsic::kLog2:
|
||||||
|
out << "log2";
|
||||||
|
break;
|
||||||
|
case Intrinsic::kMax:
|
||||||
|
out << "max";
|
||||||
|
break;
|
||||||
|
case Intrinsic::kMin:
|
||||||
|
out << "min";
|
||||||
|
break;
|
||||||
|
case Intrinsic::kMix:
|
||||||
|
out << "mix";
|
||||||
|
break;
|
||||||
|
case Intrinsic::kModf:
|
||||||
|
out << "modf";
|
||||||
|
break;
|
||||||
|
case Intrinsic::kNormalize:
|
||||||
|
out << "normalize";
|
||||||
|
break;
|
||||||
|
case Intrinsic::kOuterProduct:
|
||||||
|
out << "outerProduct";
|
||||||
|
break;
|
||||||
|
case Intrinsic::kPow:
|
||||||
|
out << "pow";
|
||||||
|
break;
|
||||||
|
case Intrinsic::kReflect:
|
||||||
|
out << "reflect";
|
||||||
|
break;
|
||||||
|
case Intrinsic::kReverseBits:
|
||||||
|
out << "reverseBits";
|
||||||
|
break;
|
||||||
|
case Intrinsic::kRound:
|
||||||
|
out << "round";
|
||||||
|
break;
|
||||||
|
case Intrinsic::kSelect:
|
||||||
|
out << "select";
|
||||||
|
break;
|
||||||
|
case Intrinsic::kSign:
|
||||||
|
out << "sign";
|
||||||
|
break;
|
||||||
|
case Intrinsic::kSin:
|
||||||
|
out << "sin";
|
||||||
|
break;
|
||||||
|
case Intrinsic::kSinh:
|
||||||
|
out << "sinh";
|
||||||
|
break;
|
||||||
|
case Intrinsic::kSmoothStep:
|
||||||
|
out << "smoothStep";
|
||||||
|
break;
|
||||||
|
case Intrinsic::kSqrt:
|
||||||
|
out << "sqrt";
|
||||||
|
break;
|
||||||
|
case Intrinsic::kStep:
|
||||||
|
out << "step";
|
||||||
|
break;
|
||||||
|
case Intrinsic::kTan:
|
||||||
|
out << "tan";
|
||||||
|
break;
|
||||||
|
case Intrinsic::kTanh:
|
||||||
|
out << "tanh";
|
||||||
|
break;
|
||||||
|
case Intrinsic::kTextureLoad:
|
||||||
|
out << "textureLoad";
|
||||||
|
break;
|
||||||
|
case Intrinsic::kTextureSample:
|
||||||
|
out << "textureSample";
|
||||||
|
break;
|
||||||
|
case Intrinsic::kTextureSampleBias:
|
||||||
|
out << "textureSampleBias";
|
||||||
|
break;
|
||||||
|
case Intrinsic::kTextureSampleCompare:
|
||||||
|
out << "textureSampleCompare";
|
||||||
|
break;
|
||||||
|
case Intrinsic::kTextureSampleLevel:
|
||||||
|
out << "textureSampleLevel";
|
||||||
|
break;
|
||||||
|
case Intrinsic::kTrunc:
|
||||||
|
out << "trunc";
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
out << "Unknown";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
namespace intrinsic {
|
namespace intrinsic {
|
||||||
|
|
||||||
bool IsCoarseDerivative(const std::string& name) {
|
bool IsCoarseDerivative(ast::Intrinsic i) {
|
||||||
return name == "dpdxCoarse" || name == "dpdyCoarse" || name == "fwidthCoarse";
|
return i == Intrinsic::kDpdxCoarse ||
|
||||||
|
i == Intrinsic::kDpdyCoarse | i == Intrinsic::kFwidthCoarse;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool IsFineDerivative(const std::string& name) {
|
bool IsFineDerivative(ast::Intrinsic i) {
|
||||||
return name == "dpdxFine" || name == "dpdyFine" || name == "fwidthFine";
|
return i == Intrinsic::kDpdxFine || i == Intrinsic::kDpdyFine ||
|
||||||
|
i == Intrinsic::kFwidthFine;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool IsDerivative(const std::string& name) {
|
bool IsDerivative(ast::Intrinsic i) {
|
||||||
return name == "dpdx" || name == "dpdy" || name == "fwidth" ||
|
return i == Intrinsic::kDpdx || i == Intrinsic::kDpdy ||
|
||||||
IsCoarseDerivative(name) || IsFineDerivative(name);
|
i == Intrinsic::kFwidth || IsCoarseDerivative(i) ||
|
||||||
|
IsFineDerivative(i);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool IsFloatClassificationIntrinsic(const std::string& name) {
|
bool IsFloatClassificationIntrinsic(ast::Intrinsic i) {
|
||||||
return name == "isFinite" || name == "isInf" || name == "isNan" ||
|
return i == Intrinsic::kIsFinite || i == Intrinsic::kIsInf ||
|
||||||
name == "isNormal";
|
i == Intrinsic::kIsNan || i == Intrinsic::kIsNormal;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool IsTextureOperationIntrinsic(const std::string& name) {
|
bool IsTextureIntrinsic(ast::Intrinsic i) {
|
||||||
return name == "textureLoad" || name == "textureSample" ||
|
return i == Intrinsic::kTextureLoad || i == Intrinsic::kTextureSample ||
|
||||||
name == "textureSampleLevel" || name == "textureSampleBias" ||
|
i == Intrinsic::kTextureSampleLevel ||
|
||||||
name == "textureSampleCompare";
|
i == Intrinsic::kTextureSampleBias ||
|
||||||
}
|
i == Intrinsic::kTextureSampleCompare;
|
||||||
|
|
||||||
bool IsIntrinsic(const std::string& name) {
|
|
||||||
return IsDerivative(name) || name == "all" || name == "any" ||
|
|
||||||
IsFloatClassificationIntrinsic(name) ||
|
|
||||||
IsTextureOperationIntrinsic(name) || name == "dot" ||
|
|
||||||
name == "outerProduct" || name == "select";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace intrinsic
|
} // namespace intrinsic
|
||||||
|
@ -15,41 +15,111 @@
|
|||||||
#ifndef SRC_AST_INTRINSIC_H_
|
#ifndef SRC_AST_INTRINSIC_H_
|
||||||
#define SRC_AST_INTRINSIC_H_
|
#define SRC_AST_INTRINSIC_H_
|
||||||
|
|
||||||
|
#include <ostream>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
namespace tint {
|
namespace tint {
|
||||||
namespace ast {
|
namespace ast {
|
||||||
|
|
||||||
|
enum class Intrinsic {
|
||||||
|
kNone = -1,
|
||||||
|
|
||||||
|
kAbs,
|
||||||
|
kAcos,
|
||||||
|
kAll,
|
||||||
|
kAny,
|
||||||
|
kAsin,
|
||||||
|
kAtan,
|
||||||
|
kAtan2,
|
||||||
|
kCeil,
|
||||||
|
kClamp,
|
||||||
|
kCos,
|
||||||
|
kCosh,
|
||||||
|
kCountOneBits,
|
||||||
|
kCross,
|
||||||
|
kDeterminant,
|
||||||
|
kDistance,
|
||||||
|
kDot,
|
||||||
|
kDpdx,
|
||||||
|
kDpdxCoarse,
|
||||||
|
kDpdxFine,
|
||||||
|
kDpdy,
|
||||||
|
kDpdyCoarse,
|
||||||
|
kDpdyFine,
|
||||||
|
kExp,
|
||||||
|
kExp2,
|
||||||
|
kFaceForward,
|
||||||
|
kFloor,
|
||||||
|
kFma,
|
||||||
|
kFract,
|
||||||
|
kFrexp,
|
||||||
|
kFwidth,
|
||||||
|
kFwidthCoarse,
|
||||||
|
kFwidthFine,
|
||||||
|
kInverseSqrt,
|
||||||
|
kIsFinite,
|
||||||
|
kIsInf,
|
||||||
|
kIsNan,
|
||||||
|
kIsNormal,
|
||||||
|
kLdexp,
|
||||||
|
kLength,
|
||||||
|
kLog,
|
||||||
|
kLog2,
|
||||||
|
kMax,
|
||||||
|
kMin,
|
||||||
|
kMix,
|
||||||
|
kModf,
|
||||||
|
kNormalize,
|
||||||
|
kOuterProduct,
|
||||||
|
kPow,
|
||||||
|
kReflect,
|
||||||
|
kReverseBits,
|
||||||
|
kRound,
|
||||||
|
kSelect,
|
||||||
|
kSign,
|
||||||
|
kSin,
|
||||||
|
kSinh,
|
||||||
|
kSmoothStep,
|
||||||
|
kSqrt,
|
||||||
|
kStep,
|
||||||
|
kTan,
|
||||||
|
kTanh,
|
||||||
|
kTextureLoad,
|
||||||
|
kTextureSample,
|
||||||
|
kTextureSampleBias,
|
||||||
|
kTextureSampleCompare,
|
||||||
|
kTextureSampleLevel,
|
||||||
|
kTrunc
|
||||||
|
};
|
||||||
|
|
||||||
|
std::ostream& operator<<(std::ostream& out, Intrinsic i);
|
||||||
|
|
||||||
namespace intrinsic {
|
namespace intrinsic {
|
||||||
|
|
||||||
/// Determines if the given |name| is a coarse derivative
|
/// Determines if the given |name| is a coarse derivative
|
||||||
/// @param name the name to check
|
/// @param i the intrinsic
|
||||||
/// @returns true if the given derivative is coarse.
|
/// @returns true if the given derivative is coarse.
|
||||||
bool IsCoarseDerivative(const std::string& name);
|
bool IsCoarseDerivative(ast::Intrinsic i);
|
||||||
|
|
||||||
/// Determines if the given |name| is a fine derivative
|
/// Determines if the given |name| is a fine derivative
|
||||||
/// @param name the name to check
|
/// @param i the intrinsic
|
||||||
/// @returns true if the given derivative is fine.
|
/// @returns true if the given derivative is fine.
|
||||||
bool IsFineDerivative(const std::string& name);
|
bool IsFineDerivative(ast::Intrinsic i);
|
||||||
|
|
||||||
/// Determine if the given |name| is a derivative intrinsic
|
/// Determine if the given |name| is a derivative intrinsic
|
||||||
/// @param name the name to check
|
/// @param i the intrinsic
|
||||||
/// @returns true if the given |name| is a derivative intrinsic
|
/// @returns true if the given |name| is a derivative intrinsic
|
||||||
bool IsDerivative(const std::string& name);
|
bool IsDerivative(ast::Intrinsic i);
|
||||||
|
|
||||||
/// Determines if the given |name| is a float classification intrinsic
|
/// Determines if the given |name| is a float classification intrinsic
|
||||||
/// @param name the name to check
|
/// @param i the intrinsic
|
||||||
/// @returns true if the given |name| is a float intrinsic
|
/// @returns true if the given |name| is a float intrinsic
|
||||||
bool IsFloatClassificationIntrinsic(const std::string& name);
|
bool IsFloatClassificationIntrinsic(ast::Intrinsic i);
|
||||||
|
|
||||||
/// Determines if the given |name| is a texture operation intrinsic
|
/// Determines if the given |name| is a texture operation intrinsic
|
||||||
/// @param name the name to check
|
/// @param i the intrinsic
|
||||||
/// @returns true if the given |name| is a texture operation intrinsic
|
/// @returns true if the given |name| is a texture operation intrinsic
|
||||||
bool IsTextureOperationIntrinsic(const std::string& name);
|
bool IsTextureIntrinsic(ast::Intrinsic i);
|
||||||
|
|
||||||
/// 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 intrinsic
|
||||||
} // namespace ast
|
} // namespace ast
|
||||||
|
@ -27,15 +27,6 @@ Module::Module(Module&&) = default;
|
|||||||
|
|
||||||
Module::~Module() = default;
|
Module::~Module() = default;
|
||||||
|
|
||||||
Import* Module::FindImportByName(const std::string& name) const {
|
|
||||||
for (const auto& import : imports_) {
|
|
||||||
if (import->name() == name) {
|
|
||||||
return import.get();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
Function* Module::FindFunctionByName(const std::string& name) const {
|
Function* Module::FindFunctionByName(const std::string& name) const {
|
||||||
for (const auto& func : functions_) {
|
for (const auto& func : functions_) {
|
||||||
if (func->name() == name) {
|
if (func->name() == name) {
|
||||||
@ -56,11 +47,6 @@ Function* Module::FindFunctionByNameAndStage(const std::string& name,
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool Module::IsValid() const {
|
bool Module::IsValid() const {
|
||||||
for (const auto& import : imports_) {
|
|
||||||
if (import == nullptr || !import->IsValid()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for (const auto& var : global_variables_) {
|
for (const auto& var : global_variables_) {
|
||||||
if (var == nullptr || !var->IsValid()) {
|
if (var == nullptr || !var->IsValid()) {
|
||||||
return false;
|
return false;
|
||||||
@ -84,9 +70,6 @@ std::string Module::to_str() const {
|
|||||||
|
|
||||||
out << "Module{" << std::endl;
|
out << "Module{" << std::endl;
|
||||||
const auto indent = 2;
|
const auto indent = 2;
|
||||||
for (const auto& import : imports_) {
|
|
||||||
import->to_str(out, indent);
|
|
||||||
}
|
|
||||||
for (const auto& var : global_variables_) {
|
for (const auto& var : global_variables_) {
|
||||||
var->to_str(out, indent);
|
var->to_str(out, indent);
|
||||||
}
|
}
|
||||||
|
@ -21,7 +21,6 @@
|
|||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include "src/ast/function.h"
|
#include "src/ast/function.h"
|
||||||
#include "src/ast/import.h"
|
|
||||||
#include "src/ast/type/alias_type.h"
|
#include "src/ast/type/alias_type.h"
|
||||||
#include "src/ast/variable.h"
|
#include "src/ast/variable.h"
|
||||||
|
|
||||||
@ -36,18 +35,6 @@ class Module {
|
|||||||
Module(Module&&);
|
Module(Module&&);
|
||||||
~Module();
|
~Module();
|
||||||
|
|
||||||
/// Add the given import to the module
|
|
||||||
/// @param import The import to add.
|
|
||||||
void AddImport(std::unique_ptr<Import> import) {
|
|
||||||
imports_.push_back(std::move(import));
|
|
||||||
}
|
|
||||||
/// @returns the imports for this module
|
|
||||||
const ImportList& imports() const { return imports_; }
|
|
||||||
/// Find the import of the given name
|
|
||||||
/// @param name The import name to search for
|
|
||||||
/// @returns the import with the given name if found, nullptr otherwise.
|
|
||||||
Import* FindImportByName(const std::string& name) const;
|
|
||||||
|
|
||||||
/// Add a global variable to the module
|
/// Add a global variable to the module
|
||||||
/// @param var the variable to add
|
/// @param var the variable to add
|
||||||
void AddGlobalVariable(std::unique_ptr<Variable> var) {
|
void AddGlobalVariable(std::unique_ptr<Variable> var) {
|
||||||
@ -94,7 +81,6 @@ class Module {
|
|||||||
private:
|
private:
|
||||||
Module(const Module&) = delete;
|
Module(const Module&) = delete;
|
||||||
|
|
||||||
ImportList imports_;
|
|
||||||
VariableList global_variables_;
|
VariableList global_variables_;
|
||||||
// The alias types are owned by the type manager
|
// The alias types are owned by the type manager
|
||||||
std::vector<type::AliasType*> alias_types_;
|
std::vector<type::AliasType*> alias_types_;
|
||||||
|
@ -19,7 +19,6 @@
|
|||||||
|
|
||||||
#include "gmock/gmock.h"
|
#include "gmock/gmock.h"
|
||||||
#include "src/ast/function.h"
|
#include "src/ast/function.h"
|
||||||
#include "src/ast/import.h"
|
|
||||||
#include "src/ast/type/f32_type.h"
|
#include "src/ast/type/f32_type.h"
|
||||||
#include "src/ast/variable.h"
|
#include "src/ast/variable.h"
|
||||||
|
|
||||||
@ -32,7 +31,7 @@ using ModuleTest = testing::Test;
|
|||||||
TEST_F(ModuleTest, Creation) {
|
TEST_F(ModuleTest, Creation) {
|
||||||
Module m;
|
Module m;
|
||||||
|
|
||||||
EXPECT_EQ(m.imports().size(), 0u);
|
EXPECT_EQ(m.functions().size(), 0u);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ModuleTest, ToStrEmitsPreambleAndPostamble) {
|
TEST_F(ModuleTest, ToStrEmitsPreambleAndPostamble) {
|
||||||
@ -42,44 +41,6 @@ TEST_F(ModuleTest, ToStrEmitsPreambleAndPostamble) {
|
|||||||
EXPECT_EQ(str, expected);
|
EXPECT_EQ(str, expected);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ModuleTest, Imports) {
|
|
||||||
Module m;
|
|
||||||
|
|
||||||
m.AddImport(std::make_unique<Import>("GLSL.std.430", "std::glsl"));
|
|
||||||
m.AddImport(std::make_unique<Import>("OpenCL.debug.100", "std::debug"));
|
|
||||||
|
|
||||||
EXPECT_EQ(2u, m.imports().size());
|
|
||||||
EXPECT_EQ("std::glsl", m.imports()[0]->name());
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(ModuleTest, ToStrWithImport) {
|
|
||||||
Module m;
|
|
||||||
m.AddImport(std::make_unique<Import>("GLSL.std.430", "std::glsl"));
|
|
||||||
const auto str = m.to_str();
|
|
||||||
EXPECT_EQ(str, R"(Module{
|
|
||||||
Import{"GLSL.std.430" as std::glsl}
|
|
||||||
}
|
|
||||||
)");
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(ModuleTest, LookupImport) {
|
|
||||||
Module m;
|
|
||||||
|
|
||||||
auto i = std::make_unique<Import>("GLSL.std.430", "std::glsl");
|
|
||||||
m.AddImport(std::move(i));
|
|
||||||
m.AddImport(std::make_unique<Import>("OpenCL.debug.100", "std::debug"));
|
|
||||||
|
|
||||||
auto* import = m.FindImportByName("std::glsl");
|
|
||||||
ASSERT_NE(nullptr, import);
|
|
||||||
EXPECT_EQ(import->path(), "GLSL.std.430");
|
|
||||||
EXPECT_EQ(import->name(), "std::glsl");
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(ModuleTest, LookupImportMissing) {
|
|
||||||
Module m;
|
|
||||||
EXPECT_EQ(nullptr, m.FindImportByName("Missing"));
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(ModuleTest, LookupFunction) {
|
TEST_F(ModuleTest, LookupFunction) {
|
||||||
type::F32Type f32;
|
type::F32Type f32;
|
||||||
Module m;
|
Module m;
|
||||||
@ -100,24 +61,6 @@ TEST_F(ModuleTest, IsValid_Empty) {
|
|||||||
EXPECT_TRUE(m.IsValid());
|
EXPECT_TRUE(m.IsValid());
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ModuleTest, IsValid_Import) {
|
|
||||||
Module m;
|
|
||||||
m.AddImport(std::make_unique<Import>("GLSL.std.430", "std::glsl"));
|
|
||||||
EXPECT_TRUE(m.IsValid());
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(ModuleTest, IsValid_Null_Import) {
|
|
||||||
Module m;
|
|
||||||
m.AddImport(nullptr);
|
|
||||||
EXPECT_FALSE(m.IsValid());
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(ModuleTest, IsValid_Invalid_Import) {
|
|
||||||
Module m;
|
|
||||||
m.AddImport(std::make_unique<Import>());
|
|
||||||
EXPECT_FALSE(m.IsValid());
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(ModuleTest, IsValid_GlobalVariable) {
|
TEST_F(ModuleTest, IsValid_GlobalVariable) {
|
||||||
type::F32Type f32;
|
type::F32Type f32;
|
||||||
auto var = std::make_unique<Variable>("var", StorageClass::kInput, &f32);
|
auto var = std::make_unique<Variable>("var", StorageClass::kInput, &f32);
|
||||||
|
@ -327,7 +327,7 @@ std::string GetGlslStd450FuncName(uint32_t ext_opcode) {
|
|||||||
case GLSLstd450Normalize:
|
case GLSLstd450Normalize:
|
||||||
return "normalize";
|
return "normalize";
|
||||||
case GLSLstd450FClamp:
|
case GLSLstd450FClamp:
|
||||||
return "fclamp";
|
return "clamp";
|
||||||
case GLSLstd450Length:
|
case GLSLstd450Length:
|
||||||
return "length";
|
return "length";
|
||||||
default:
|
default:
|
||||||
@ -2805,8 +2805,8 @@ TypedExpression FunctionEmitter::EmitGlslStd450ExtInst(
|
|||||||
Fail() << "unhandled GLSL.std.450 instruction " << ext_opcode;
|
Fail() << "unhandled GLSL.std.450 instruction " << ext_opcode;
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
auto func = std::make_unique<ast::IdentifierExpression>(
|
|
||||||
std::vector<std::string>{parser_impl_.GlslStd450Prefix(), name});
|
auto func = std::make_unique<ast::IdentifierExpression>(name);
|
||||||
ast::ExpressionList operands;
|
ast::ExpressionList operands;
|
||||||
// All parameters to GLSL.std.450 extended instructions are IDs.
|
// All parameters to GLSL.std.450 extended instructions are IDs.
|
||||||
for (uint32_t iarg = 2; iarg < inst.NumInOperands(); ++iarg) {
|
for (uint32_t iarg = 2; iarg < inst.NumInOperands(); ++iarg) {
|
||||||
|
@ -434,30 +434,28 @@ TEST_P(SpvParserTest_GlslStd450_Floating_FloatingFloatingFloating, Vector) {
|
|||||||
|
|
||||||
INSTANTIATE_TEST_SUITE_P(Samples,
|
INSTANTIATE_TEST_SUITE_P(Samples,
|
||||||
SpvParserTest_GlslStd450_Float_Floating,
|
SpvParserTest_GlslStd450_Float_Floating,
|
||||||
::testing::Values(GlslStd450Case{
|
::testing::Values(GlslStd450Case{"Length", "length"}));
|
||||||
"Length", "std::glsl::length"}));
|
|
||||||
|
|
||||||
INSTANTIATE_TEST_SUITE_P(Samples,
|
INSTANTIATE_TEST_SUITE_P(Samples,
|
||||||
SpvParserTest_GlslStd450_Float_FloatingFloating,
|
SpvParserTest_GlslStd450_Float_FloatingFloating,
|
||||||
::testing::Values(GlslStd450Case{
|
::testing::Values(GlslStd450Case{"Distance",
|
||||||
"Distance", "std::glsl::distance"}));
|
"distance"}));
|
||||||
|
|
||||||
INSTANTIATE_TEST_SUITE_P(
|
INSTANTIATE_TEST_SUITE_P(Samples,
|
||||||
Samples,
|
SpvParserTest_GlslStd450_Floating_Floating,
|
||||||
SpvParserTest_GlslStd450_Floating_Floating,
|
::testing::Values(GlslStd450Case{"Sin", "sin"},
|
||||||
::testing::Values(GlslStd450Case{"Sin", "std::glsl::sin"},
|
GlslStd450Case{"Cos", "cos"},
|
||||||
GlslStd450Case{"Cos", "std::glsl::cos"},
|
GlslStd450Case{"Normalize",
|
||||||
GlslStd450Case{"Normalize", "std::glsl::normalize"}));
|
"normalize"}));
|
||||||
|
|
||||||
INSTANTIATE_TEST_SUITE_P(Samples,
|
INSTANTIATE_TEST_SUITE_P(Samples,
|
||||||
SpvParserTest_GlslStd450_Floating_FloatingFloating,
|
SpvParserTest_GlslStd450_Floating_FloatingFloating,
|
||||||
::testing::Values(GlslStd450Case{"Atan2",
|
::testing::Values(GlslStd450Case{"Atan2", "atan2"}));
|
||||||
"std::glsl::atan2"}));
|
|
||||||
|
|
||||||
INSTANTIATE_TEST_SUITE_P(
|
INSTANTIATE_TEST_SUITE_P(
|
||||||
Samples,
|
Samples,
|
||||||
SpvParserTest_GlslStd450_Floating_FloatingFloatingFloating,
|
SpvParserTest_GlslStd450_Floating_FloatingFloatingFloating,
|
||||||
::testing::Values(GlslStd450Case{"FClamp", "std::glsl::fclamp"}));
|
::testing::Values(GlslStd450Case{"FClamp", "clamp"}));
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
} // namespace spirv
|
} // namespace spirv
|
||||||
|
@ -453,7 +453,6 @@ void ParserImpl::ResetInternalModule() {
|
|||||||
type_mgr_ = nullptr;
|
type_mgr_ = nullptr;
|
||||||
deco_mgr_ = nullptr;
|
deco_mgr_ = nullptr;
|
||||||
|
|
||||||
import_map_.clear();
|
|
||||||
glsl_std_450_imports_.clear();
|
glsl_std_450_imports_.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -544,14 +543,6 @@ bool ParserImpl::RegisterExtendedInstructionImports() {
|
|||||||
reinterpret_cast<const char*>(import.GetInOperand(0).words.data()));
|
reinterpret_cast<const char*>(import.GetInOperand(0).words.data()));
|
||||||
// TODO(dneto): Handle other extended instruction sets when needed.
|
// TODO(dneto): Handle other extended instruction sets when needed.
|
||||||
if (name == "GLSL.std.450") {
|
if (name == "GLSL.std.450") {
|
||||||
// Only create the AST import once, so we can use import name 'std::glsl'.
|
|
||||||
// This is a canonicalization.
|
|
||||||
if (glsl_std_450_imports_.empty()) {
|
|
||||||
auto ast_import =
|
|
||||||
std::make_unique<tint::ast::Import>(name, GlslStd450Prefix());
|
|
||||||
import_map_[import.result_id()] = ast_import.get();
|
|
||||||
ast_module_.AddImport(std::move(ast_import));
|
|
||||||
}
|
|
||||||
glsl_std_450_imports_.insert(import.result_id());
|
glsl_std_450_imports_.insert(import.result_id());
|
||||||
} else {
|
} else {
|
||||||
return Fail() << "Unrecognized extended instruction set: " << name;
|
return Fail() << "Unrecognized extended instruction set: " << name;
|
||||||
|
@ -32,7 +32,6 @@
|
|||||||
#include "source/opt/types.h"
|
#include "source/opt/types.h"
|
||||||
#include "spirv-tools/libspirv.hpp"
|
#include "spirv-tools/libspirv.hpp"
|
||||||
#include "src/ast/expression.h"
|
#include "src/ast/expression.h"
|
||||||
#include "src/ast/import.h"
|
|
||||||
#include "src/ast/module.h"
|
#include "src/ast/module.h"
|
||||||
#include "src/ast/struct_member_decoration.h"
|
#include "src/ast/struct_member_decoration.h"
|
||||||
#include "src/ast/type/alias_type.h"
|
#include "src/ast/type/alias_type.h"
|
||||||
@ -136,9 +135,6 @@ class ParserImpl : Reader {
|
|||||||
return glsl_std_450_imports_;
|
return glsl_std_450_imports_;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @returns the import prefix to use for the GLSL.std.450 import.
|
|
||||||
std::string GlslStd450Prefix() const { return "std::glsl"; }
|
|
||||||
|
|
||||||
/// Converts a SPIR-V type to a Tint type, and saves it for fast lookup.
|
/// Converts a SPIR-V type to a Tint type, and saves it for fast lookup.
|
||||||
/// If the type is only used for builtins, then register that specially,
|
/// If the type is only used for builtins, then register that specially,
|
||||||
/// and return null.
|
/// and return null.
|
||||||
@ -460,8 +456,6 @@ class ParserImpl : Reader {
|
|||||||
// instruction is line 1.
|
// instruction is line 1.
|
||||||
std::unordered_map<const spvtools::opt::Instruction*, Source> inst_source_;
|
std::unordered_map<const spvtools::opt::Instruction*, Source> inst_source_;
|
||||||
|
|
||||||
/// Maps a SPIR-V ID for an external instruction import to an AST import
|
|
||||||
std::unordered_map<uint32_t, ast::Import*> import_map_;
|
|
||||||
// The set of IDs that are imports of the GLSL.std.450 extended instruction
|
// The set of IDs that are imports of the GLSL.std.450 extended instruction
|
||||||
// sets.
|
// sets.
|
||||||
std::unordered_set<uint32_t> glsl_std_450_imports_;
|
std::unordered_set<uint32_t> glsl_std_450_imports_;
|
||||||
|
@ -44,23 +44,6 @@ TEST_F(SpvParserTest, Import_ImportGlslStd450) {
|
|||||||
EXPECT_TRUE(p->BuildAndParseInternalModule());
|
EXPECT_TRUE(p->BuildAndParseInternalModule());
|
||||||
EXPECT_TRUE(p->error().empty());
|
EXPECT_TRUE(p->error().empty());
|
||||||
EXPECT_THAT(p->glsl_std_450_imports(), ElementsAre(1));
|
EXPECT_THAT(p->glsl_std_450_imports(), ElementsAre(1));
|
||||||
const auto module_ast = p->module().to_str();
|
|
||||||
EXPECT_THAT(module_ast, HasSubstr(R"(Import{"GLSL.std.450" as std::glsl})"));
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(SpvParserTest, Import_ImportGlslStd450Twice) {
|
|
||||||
auto* p = parser(test::Assemble(R"(
|
|
||||||
%1 = OpExtInstImport "GLSL.std.450"
|
|
||||||
%42 = OpExtInstImport "GLSL.std.450"
|
|
||||||
)"));
|
|
||||||
EXPECT_TRUE(p->BuildAndParseInternalModule());
|
|
||||||
EXPECT_TRUE(p->error().empty());
|
|
||||||
EXPECT_THAT(p->glsl_std_450_imports(), UnorderedElementsAre(1, 42));
|
|
||||||
const auto module = p->module();
|
|
||||||
EXPECT_EQ(module.imports().size(), 1u);
|
|
||||||
const auto module_ast = module.to_str();
|
|
||||||
// TODO(dneto): Use a matcher to show there is only one import.
|
|
||||||
EXPECT_THAT(module_ast, HasSubstr(R"(Import{"GLSL.std.450" as std::glsl})"));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO(dneto): We don't currently support other kinds of extended instruction
|
// TODO(dneto): We don't currently support other kinds of extended instruction
|
||||||
|
@ -203,7 +203,6 @@ void ParserImpl::translation_unit() {
|
|||||||
|
|
||||||
// global_decl
|
// global_decl
|
||||||
// : SEMICOLON
|
// : SEMICOLON
|
||||||
// | import_decl SEMICOLON
|
|
||||||
// | global_variable_decl SEMICLON
|
// | global_variable_decl SEMICLON
|
||||||
// | global_constant_decl SEMICOLON
|
// | global_constant_decl SEMICOLON
|
||||||
// | type_alias SEMICOLON
|
// | type_alias SEMICOLON
|
||||||
@ -218,19 +217,6 @@ void ParserImpl::global_decl() {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto import = import_decl();
|
|
||||||
if (has_error())
|
|
||||||
return;
|
|
||||||
if (import != nullptr) {
|
|
||||||
t = next();
|
|
||||||
if (!t.IsSemicolon()) {
|
|
||||||
set_error(t, "missing ';' for import");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
module_.AddImport(std::move(import));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto gv = global_variable_decl();
|
auto gv = global_variable_decl();
|
||||||
if (has_error())
|
if (has_error())
|
||||||
return;
|
return;
|
||||||
@ -281,69 +267,6 @@ void ParserImpl::global_decl() {
|
|||||||
set_error(t);
|
set_error(t);
|
||||||
}
|
}
|
||||||
|
|
||||||
// import_decl
|
|
||||||
// : IMPORT STRING_LITERAL AS (IDENT NAMESPACE)* IDENT
|
|
||||||
std::unique_ptr<ast::Import> ParserImpl::import_decl() {
|
|
||||||
auto t = peek();
|
|
||||||
if (!t.IsImport())
|
|
||||||
return {};
|
|
||||||
|
|
||||||
auto source = t.source();
|
|
||||||
next(); // consume the import token
|
|
||||||
|
|
||||||
t = next();
|
|
||||||
if (!t.IsStringLiteral()) {
|
|
||||||
set_error(t, "missing path for import");
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
auto path = t.to_str();
|
|
||||||
if (path.length() == 0) {
|
|
||||||
set_error(t, "import path must not be empty");
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
t = next();
|
|
||||||
if (!t.IsAs()) {
|
|
||||||
set_error(t, "missing 'as' for import");
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string name = "";
|
|
||||||
for (;;) {
|
|
||||||
t = peek();
|
|
||||||
if (!t.IsIdentifier()) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
next(); // consume the peek
|
|
||||||
|
|
||||||
name += t.to_str();
|
|
||||||
|
|
||||||
t = peek();
|
|
||||||
if (!t.IsNamespace()) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
next(); // consume the peek
|
|
||||||
|
|
||||||
name += "::";
|
|
||||||
}
|
|
||||||
if (name.length() == 0) {
|
|
||||||
if (t.IsEof() || t.IsSemicolon()) {
|
|
||||||
set_error(t, "missing name for import");
|
|
||||||
} else {
|
|
||||||
set_error(t, "invalid name for import");
|
|
||||||
}
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
if (name.length() > 2) {
|
|
||||||
auto end = name.length() - 1;
|
|
||||||
if (name[end] == ':' && name[end - 1] == ':') {
|
|
||||||
set_error(t, "invalid name for import");
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return std::make_unique<ast::Import>(source, path, name);
|
|
||||||
}
|
|
||||||
|
|
||||||
// global_variable_decl
|
// global_variable_decl
|
||||||
// : variable_decoration_list variable_decl
|
// : variable_decoration_list variable_decl
|
||||||
// | variable_decoration_list variable_decl EQUAL const_expr
|
// | variable_decoration_list variable_decl EQUAL const_expr
|
||||||
@ -2840,7 +2763,7 @@ std::unique_ptr<ast::BlockStatement> ParserImpl::continuing_stmt() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// primary_expression
|
// primary_expression
|
||||||
// : (IDENT NAMESPACE)* IDENT
|
// : IDENT
|
||||||
// | type_decl PAREN_LEFT argument_expression_list* PAREN_RIGHT
|
// | type_decl PAREN_LEFT argument_expression_list* PAREN_RIGHT
|
||||||
// | const_literal
|
// | const_literal
|
||||||
// | paren_rhs_stmt
|
// | paren_rhs_stmt
|
||||||
@ -2911,24 +2834,7 @@ std::unique_ptr<ast::Expression> ParserImpl::primary_expression() {
|
|||||||
} else if (t.IsIdentifier()) {
|
} else if (t.IsIdentifier()) {
|
||||||
next(); // Consume the peek
|
next(); // Consume the peek
|
||||||
|
|
||||||
std::vector<std::string> ident;
|
return std::make_unique<ast::IdentifierExpression>(source, t.to_str());
|
||||||
ident.push_back(t.to_str());
|
|
||||||
for (;;) {
|
|
||||||
t = peek();
|
|
||||||
if (!t.IsNamespace())
|
|
||||||
break;
|
|
||||||
|
|
||||||
next(); // Consume the peek
|
|
||||||
t = next();
|
|
||||||
if (!t.IsIdentifier()) {
|
|
||||||
set_error(t, "identifier expected");
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
ident.push_back(t.to_str());
|
|
||||||
}
|
|
||||||
return std::make_unique<ast::IdentifierExpression>(source,
|
|
||||||
std::move(ident));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
auto* type = type_decl();
|
auto* type = type_decl();
|
||||||
|
@ -28,7 +28,6 @@
|
|||||||
#include "src/ast/constructor_expression.h"
|
#include "src/ast/constructor_expression.h"
|
||||||
#include "src/ast/else_statement.h"
|
#include "src/ast/else_statement.h"
|
||||||
#include "src/ast/function.h"
|
#include "src/ast/function.h"
|
||||||
#include "src/ast/import.h"
|
|
||||||
#include "src/ast/literal.h"
|
#include "src/ast/literal.h"
|
||||||
#include "src/ast/loop_statement.h"
|
#include "src/ast/loop_statement.h"
|
||||||
#include "src/ast/module.h"
|
#include "src/ast/module.h"
|
||||||
@ -123,9 +122,6 @@ class ParserImpl {
|
|||||||
void translation_unit();
|
void translation_unit();
|
||||||
/// Parses the `global_decl` grammar element
|
/// Parses the `global_decl` grammar element
|
||||||
void global_decl();
|
void global_decl();
|
||||||
/// Parses the `import_decl grammar element
|
|
||||||
/// @returns the import object or nullptr if an error was encountered
|
|
||||||
std::unique_ptr<ast::Import> import_decl();
|
|
||||||
/// Parses a `global_variable_decl` grammar element
|
/// Parses a `global_variable_decl` grammar element
|
||||||
/// @returns the variable parsed or nullptr
|
/// @returns the variable parsed or nullptr
|
||||||
std::unique_ptr<ast::Variable> global_variable_decl();
|
std::unique_ptr<ast::Variable> global_variable_decl();
|
||||||
|
@ -27,35 +27,6 @@ TEST_F(ParserImplTest, GlobalDecl_Semicolon) {
|
|||||||
ASSERT_FALSE(p->has_error()) << p->error();
|
ASSERT_FALSE(p->has_error()) << p->error();
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ParserImplTest, GlobalDecl_Import) {
|
|
||||||
auto* p = parser(R"(import "GLSL.std.430" as glsl;)");
|
|
||||||
p->global_decl();
|
|
||||||
ASSERT_FALSE(p->has_error()) << p->error();
|
|
||||||
|
|
||||||
auto m = p->module();
|
|
||||||
ASSERT_EQ(1u, m.imports().size());
|
|
||||||
|
|
||||||
const auto& import = m.imports()[0];
|
|
||||||
EXPECT_EQ("GLSL.std.430", import->path());
|
|
||||||
EXPECT_EQ("glsl", import->name());
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(ParserImplTest, GlobalDecl_Import_Invalid) {
|
|
||||||
auto* p = parser(R"(import as glsl;)");
|
|
||||||
p->global_decl();
|
|
||||||
|
|
||||||
ASSERT_TRUE(p->has_error());
|
|
||||||
EXPECT_EQ(p->error(), "1:8: missing path for import");
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(ParserImplTest, GlobalDecl_Import_Invalid_MissingSemicolon) {
|
|
||||||
auto* p = parser(R"(import "GLSL.std.430" as glsl)");
|
|
||||||
p->global_decl();
|
|
||||||
|
|
||||||
ASSERT_TRUE(p->has_error());
|
|
||||||
EXPECT_EQ(p->error(), "1:30: missing ';' for import");
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(ParserImplTest, GlobalDecl_GlobalVariable) {
|
TEST_F(ParserImplTest, GlobalDecl_GlobalVariable) {
|
||||||
auto* p = parser("var<out> a : vec2<i32> = vec2<i32>(1, 2);");
|
auto* p = parser("var<out> a : vec2<i32> = vec2<i32>(1, 2);");
|
||||||
p->global_decl();
|
p->global_decl();
|
||||||
|
@ -1,96 +0,0 @@
|
|||||||
// 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 "gtest/gtest.h"
|
|
||||||
#include "src/reader/wgsl/parser_impl.h"
|
|
||||||
#include "src/reader/wgsl/parser_impl_test_helper.h"
|
|
||||||
|
|
||||||
namespace tint {
|
|
||||||
namespace reader {
|
|
||||||
namespace wgsl {
|
|
||||||
namespace {
|
|
||||||
|
|
||||||
TEST_F(ParserImplTest, ImportDecl_Import) {
|
|
||||||
auto* p = parser(R"(import "GLSL.std.450" as glsl)");
|
|
||||||
|
|
||||||
auto import = p->import_decl();
|
|
||||||
ASSERT_NE(import, nullptr);
|
|
||||||
ASSERT_FALSE(p->has_error()) << p->error();
|
|
||||||
|
|
||||||
EXPECT_EQ("GLSL.std.450", import->path());
|
|
||||||
EXPECT_EQ("glsl", import->name());
|
|
||||||
EXPECT_EQ(1u, import->line());
|
|
||||||
EXPECT_EQ(1u, import->column());
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(ParserImplTest, ImportDecl_Import_WithNamespace) {
|
|
||||||
auto* p = parser(R"(import "GLSL.std.450" as std::glsl)");
|
|
||||||
auto import = p->import_decl();
|
|
||||||
ASSERT_NE(import, nullptr);
|
|
||||||
ASSERT_FALSE(p->has_error()) << p->error();
|
|
||||||
EXPECT_EQ("std::glsl", import->name());
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(ParserImplTest, ImportDecl_Invalid_MissingPath) {
|
|
||||||
auto* p = parser(R"(import as glsl)");
|
|
||||||
auto import = p->import_decl();
|
|
||||||
ASSERT_EQ(import, nullptr);
|
|
||||||
ASSERT_TRUE(p->has_error());
|
|
||||||
EXPECT_EQ(p->error(), "1:8: missing path for import");
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(ParserImplTest, ImportDecl_Invalid_EmptyPath) {
|
|
||||||
auto* p = parser(R"(import "" as glsl)");
|
|
||||||
auto import = p->import_decl();
|
|
||||||
ASSERT_EQ(import, nullptr);
|
|
||||||
ASSERT_TRUE(p->has_error());
|
|
||||||
EXPECT_EQ(p->error(), "1:8: import path must not be empty");
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(ParserImplTest, ImportDecl_Invalid_NameMissingTerminatingIdentifier) {
|
|
||||||
auto* p = parser(R"(import "GLSL.std.450" as glsl::)");
|
|
||||||
auto import = p->import_decl();
|
|
||||||
ASSERT_EQ(import, nullptr);
|
|
||||||
ASSERT_TRUE(p->has_error());
|
|
||||||
EXPECT_EQ(p->error(), "1:32: invalid name for import");
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(ParserImplTest, ImportDecl_Invalid_NameInvalid) {
|
|
||||||
auto* p = parser(R"(import "GLSL.std.450" as 12glsl)");
|
|
||||||
auto import = p->import_decl();
|
|
||||||
ASSERT_EQ(import, nullptr);
|
|
||||||
ASSERT_TRUE(p->has_error());
|
|
||||||
EXPECT_EQ(p->error(), "1:26: invalid name for import");
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(ParserImplTest, ImportDecl_Invalid_MissingName) {
|
|
||||||
auto* p = parser(R"(import "GLSL.std.450" as)");
|
|
||||||
auto import = p->import_decl();
|
|
||||||
ASSERT_EQ(import, nullptr);
|
|
||||||
ASSERT_TRUE(p->has_error());
|
|
||||||
EXPECT_EQ(p->error(), "1:25: missing name for import");
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(ParserImplTest, ImportDecl_Invalid_MissingAs) {
|
|
||||||
auto* p = parser(R"(import "GLSL.std.450" glsl)");
|
|
||||||
auto import = p->import_decl();
|
|
||||||
ASSERT_EQ(import, nullptr);
|
|
||||||
ASSERT_TRUE(p->has_error());
|
|
||||||
EXPECT_EQ(p->error(), "1:23: missing 'as' for import");
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace
|
|
||||||
} // namespace wgsl
|
|
||||||
} // namespace reader
|
|
||||||
} // namespace tint
|
|
@ -105,7 +105,7 @@ TEST_F(ParserImplTest, PostfixExpression_Call_Empty) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ParserImplTest, PostfixExpression_Call_WithArgs) {
|
TEST_F(ParserImplTest, PostfixExpression_Call_WithArgs) {
|
||||||
auto* p = parser("std::test(1, b, 2 + 3 / b)");
|
auto* p = parser("test(1, b, 2 + 3 / b)");
|
||||||
auto e = p->postfix_expression();
|
auto e = p->postfix_expression();
|
||||||
ASSERT_FALSE(p->has_error()) << p->error();
|
ASSERT_FALSE(p->has_error()) << p->error();
|
||||||
ASSERT_NE(e, nullptr);
|
ASSERT_NE(e, nullptr);
|
||||||
@ -115,7 +115,6 @@ TEST_F(ParserImplTest, PostfixExpression_Call_WithArgs) {
|
|||||||
|
|
||||||
ASSERT_TRUE(c->func()->IsIdentifier());
|
ASSERT_TRUE(c->func()->IsIdentifier());
|
||||||
auto* func = c->func()->AsIdentifier();
|
auto* func = c->func()->AsIdentifier();
|
||||||
EXPECT_EQ(func->path(), "std");
|
|
||||||
EXPECT_EQ(func->name(), "test");
|
EXPECT_EQ(func->name(), "test");
|
||||||
|
|
||||||
EXPECT_EQ(c->params().size(), 3u);
|
EXPECT_EQ(c->params().size(), 3u);
|
||||||
|
@ -43,25 +43,6 @@ TEST_F(ParserImplTest, PrimaryExpression_Ident) {
|
|||||||
EXPECT_EQ(ident->name(), "a");
|
EXPECT_EQ(ident->name(), "a");
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ParserImplTest, PrimaryExpression_Ident_WithNamespace) {
|
|
||||||
auto* p = parser("a::b::c::d");
|
|
||||||
auto e = p->primary_expression();
|
|
||||||
ASSERT_FALSE(p->has_error()) << p->error();
|
|
||||||
ASSERT_NE(e, nullptr);
|
|
||||||
ASSERT_TRUE(e->IsIdentifier());
|
|
||||||
auto* ident = e->AsIdentifier();
|
|
||||||
EXPECT_EQ(ident->path(), "a::b::c");
|
|
||||||
EXPECT_EQ(ident->name(), "d");
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(ParserImplTest, PrimaryExpression_Ident_MissingIdent) {
|
|
||||||
auto* p = parser("a::");
|
|
||||||
auto e = p->primary_expression();
|
|
||||||
ASSERT_TRUE(p->has_error());
|
|
||||||
ASSERT_EQ(e, nullptr);
|
|
||||||
EXPECT_EQ(p->error(), "1:4: identifier expected");
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(ParserImplTest, PrimaryExpression_TypeDecl) {
|
TEST_F(ParserImplTest, PrimaryExpression_TypeDecl) {
|
||||||
auto* p = parser("vec4<i32>(1, 2, 3, 4))");
|
auto* p = parser("vec4<i32>(1, 2, 3, 4))");
|
||||||
auto e = p->primary_expression();
|
auto e = p->primary_expression();
|
||||||
|
@ -30,8 +30,6 @@ TEST_F(ParserImplTest, Empty) {
|
|||||||
|
|
||||||
TEST_F(ParserImplTest, Parses) {
|
TEST_F(ParserImplTest, Parses) {
|
||||||
auto* p = parser(R"(
|
auto* p = parser(R"(
|
||||||
import "GLSL.std.430" as glsl;
|
|
||||||
|
|
||||||
[[location(0)]] var<out> gl_FragColor : vec4<f32>;
|
[[location(0)]] var<out> gl_FragColor : vec4<f32>;
|
||||||
|
|
||||||
[[stage(vertex)]]
|
[[stage(vertex)]]
|
||||||
@ -42,22 +40,19 @@ fn main() -> void {
|
|||||||
ASSERT_TRUE(p->Parse()) << p->error();
|
ASSERT_TRUE(p->Parse()) << p->error();
|
||||||
|
|
||||||
auto m = p->module();
|
auto m = p->module();
|
||||||
ASSERT_EQ(1u, m.imports().size());
|
|
||||||
ASSERT_EQ(1u, m.functions().size());
|
ASSERT_EQ(1u, m.functions().size());
|
||||||
ASSERT_EQ(1u, m.global_variables().size());
|
ASSERT_EQ(1u, m.global_variables().size());
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ParserImplTest, HandlesError) {
|
TEST_F(ParserImplTest, HandlesError) {
|
||||||
auto* p = parser(R"(
|
auto* p = parser(R"(
|
||||||
import "GLSL.std.430" as glsl;
|
|
||||||
|
|
||||||
fn main() -> { # missing return type
|
fn main() -> { # missing return type
|
||||||
return;
|
return;
|
||||||
})");
|
})");
|
||||||
|
|
||||||
ASSERT_FALSE(p->Parse());
|
ASSERT_FALSE(p->Parse());
|
||||||
ASSERT_TRUE(p->has_error());
|
ASSERT_TRUE(p->has_error());
|
||||||
EXPECT_EQ(p->error(), "4:15: unable to determine function return type");
|
EXPECT_EQ(p->error(), "2:15: unable to determine function return type");
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ParserImplTest, GetRegisteredType) {
|
TEST_F(ParserImplTest, GetRegisteredType) {
|
||||||
|
@ -34,8 +34,6 @@ TEST_F(ParserTest, Parses) {
|
|||||||
Context ctx;
|
Context ctx;
|
||||||
|
|
||||||
Parser p(&ctx, R"(
|
Parser p(&ctx, R"(
|
||||||
import "GLSL.std.430" as glsl;
|
|
||||||
|
|
||||||
[[location(0)]] var<out> gl_FragColor : vec4<f32>;
|
[[location(0)]] var<out> gl_FragColor : vec4<f32>;
|
||||||
|
|
||||||
[[stage(vertex)]]
|
[[stage(vertex)]]
|
||||||
@ -46,7 +44,6 @@ fn main() -> void {
|
|||||||
ASSERT_TRUE(p.Parse()) << p.error();
|
ASSERT_TRUE(p.Parse()) << p.error();
|
||||||
|
|
||||||
auto m = p.module();
|
auto m = p.module();
|
||||||
ASSERT_EQ(1u, m.imports().size());
|
|
||||||
ASSERT_EQ(1u, m.functions().size());
|
ASSERT_EQ(1u, m.functions().size());
|
||||||
ASSERT_EQ(1u, m.global_variables().size());
|
ASSERT_EQ(1u, m.global_variables().size());
|
||||||
}
|
}
|
||||||
@ -54,15 +51,13 @@ fn main() -> void {
|
|||||||
TEST_F(ParserTest, HandlesError) {
|
TEST_F(ParserTest, HandlesError) {
|
||||||
Context ctx;
|
Context ctx;
|
||||||
Parser p(&ctx, R"(
|
Parser p(&ctx, R"(
|
||||||
import "GLSL.std.430" as glsl;
|
|
||||||
|
|
||||||
fn main() -> { # missing return type
|
fn main() -> { # missing return type
|
||||||
return;
|
return;
|
||||||
})");
|
})");
|
||||||
|
|
||||||
ASSERT_FALSE(p.Parse());
|
ASSERT_FALSE(p.Parse());
|
||||||
ASSERT_TRUE(p.has_error());
|
ASSERT_TRUE(p.has_error());
|
||||||
EXPECT_EQ(p.error(), "4:15: unable to determine function return type");
|
EXPECT_EQ(p.error(), "2:15: unable to determine function return type");
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
@ -17,7 +17,6 @@
|
|||||||
#include <memory>
|
#include <memory>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include "spirv/unified1/GLSL.std.450.h"
|
|
||||||
#include "src/ast/array_accessor_expression.h"
|
#include "src/ast/array_accessor_expression.h"
|
||||||
#include "src/ast/as_expression.h"
|
#include "src/ast/as_expression.h"
|
||||||
#include "src/ast/assignment_statement.h"
|
#include "src/ast/assignment_statement.h"
|
||||||
@ -56,104 +55,6 @@
|
|||||||
#include "src/ast/variable_decl_statement.h"
|
#include "src/ast/variable_decl_statement.h"
|
||||||
|
|
||||||
namespace tint {
|
namespace tint {
|
||||||
namespace {
|
|
||||||
|
|
||||||
// Most of these are floating-point general except the below which are only
|
|
||||||
// FP16 and FP32. We only have FP32 at this point so the below works, if we
|
|
||||||
// get FP64 support or otherwise we'll need to differentiate.
|
|
||||||
// * radians
|
|
||||||
// * degrees
|
|
||||||
// * sin, cos, tan
|
|
||||||
// * asin, acos, atan
|
|
||||||
// * sinh, cosh, tanh
|
|
||||||
// * asinh, acosh, atanh
|
|
||||||
// * exp, exp2
|
|
||||||
// * log, log2
|
|
||||||
enum class GlslDataType {
|
|
||||||
kFloatScalarOrVector,
|
|
||||||
kIntScalarOrVector,
|
|
||||||
kFloatVector,
|
|
||||||
kMatrix
|
|
||||||
};
|
|
||||||
struct GlslData {
|
|
||||||
const char* name;
|
|
||||||
uint8_t param_count;
|
|
||||||
uint32_t op_id;
|
|
||||||
GlslDataType type;
|
|
||||||
uint8_t vector_count;
|
|
||||||
};
|
|
||||||
|
|
||||||
constexpr const GlslData kGlslData[] = {
|
|
||||||
{"acos", 1, GLSLstd450Acos, GlslDataType::kFloatScalarOrVector, 0},
|
|
||||||
{"acosh", 1, GLSLstd450Acosh, GlslDataType::kFloatScalarOrVector, 0},
|
|
||||||
{"asin", 1, GLSLstd450Asin, GlslDataType::kFloatScalarOrVector, 0},
|
|
||||||
{"asinh", 1, GLSLstd450Asinh, GlslDataType::kFloatScalarOrVector, 0},
|
|
||||||
{"atan", 1, GLSLstd450Atan, GlslDataType::kFloatScalarOrVector, 0},
|
|
||||||
{"atan2", 2, GLSLstd450Atan2, GlslDataType::kFloatScalarOrVector, 0},
|
|
||||||
{"atanh", 1, GLSLstd450Atanh, GlslDataType::kFloatScalarOrVector, 0},
|
|
||||||
{"ceil", 1, GLSLstd450Ceil, GlslDataType::kFloatScalarOrVector, 0},
|
|
||||||
{"cos", 1, GLSLstd450Cos, GlslDataType::kFloatScalarOrVector, 0},
|
|
||||||
{"cosh", 1, GLSLstd450Cosh, GlslDataType::kFloatScalarOrVector, 0},
|
|
||||||
{"cross", 2, GLSLstd450Cross, GlslDataType::kFloatVector, 3},
|
|
||||||
{"degrees", 1, GLSLstd450Degrees, GlslDataType::kFloatScalarOrVector, 0},
|
|
||||||
{"determinant", 1, GLSLstd450Determinant, GlslDataType::kMatrix, 0},
|
|
||||||
{"distance", 2, GLSLstd450Distance, GlslDataType::kFloatScalarOrVector, 0},
|
|
||||||
{"exp", 1, GLSLstd450Exp, GlslDataType::kFloatScalarOrVector, 0},
|
|
||||||
{"exp2", 1, GLSLstd450Exp2, GlslDataType::kFloatScalarOrVector, 0},
|
|
||||||
{"fabs", 1, GLSLstd450FAbs, GlslDataType::kFloatScalarOrVector, 0},
|
|
||||||
{"faceforward", 3, GLSLstd450FaceForward,
|
|
||||||
GlslDataType::kFloatScalarOrVector, 0},
|
|
||||||
{"fclamp", 3, GLSLstd450FClamp, GlslDataType::kFloatScalarOrVector, 0},
|
|
||||||
{"findilsb", 1, GLSLstd450FindILsb, GlslDataType::kIntScalarOrVector, 0},
|
|
||||||
{"findumsb", 1, GLSLstd450FindUMsb, GlslDataType::kIntScalarOrVector, 0},
|
|
||||||
{"findsmsb", 1, GLSLstd450FindSMsb, GlslDataType::kIntScalarOrVector, 0},
|
|
||||||
{"floor", 1, GLSLstd450Floor, GlslDataType::kFloatScalarOrVector, 0},
|
|
||||||
{"fma", 3, GLSLstd450Fma, GlslDataType::kFloatScalarOrVector, 0},
|
|
||||||
{"fmax", 2, GLSLstd450FMax, GlslDataType::kFloatScalarOrVector, 0},
|
|
||||||
{"fmin", 2, GLSLstd450FMin, GlslDataType::kFloatScalarOrVector, 0},
|
|
||||||
{"fmix", 3, GLSLstd450FMix, GlslDataType::kFloatScalarOrVector, 0},
|
|
||||||
{"fract", 1, GLSLstd450Fract, GlslDataType::kFloatScalarOrVector, 0},
|
|
||||||
{"fsign", 1, GLSLstd450FSign, GlslDataType::kFloatScalarOrVector, 0},
|
|
||||||
{"interpolateatcentroid", 1, GLSLstd450InterpolateAtCentroid,
|
|
||||||
GlslDataType::kFloatScalarOrVector, 0},
|
|
||||||
{"inversesqrt", 1, GLSLstd450InverseSqrt,
|
|
||||||
GlslDataType::kFloatScalarOrVector, 0},
|
|
||||||
{"length", 1, GLSLstd450Length, GlslDataType::kFloatScalarOrVector, 0},
|
|
||||||
{"log", 1, GLSLstd450Log, GlslDataType::kFloatScalarOrVector, 0},
|
|
||||||
{"log2", 1, GLSLstd450Log2, GlslDataType::kFloatScalarOrVector, 0},
|
|
||||||
{"matrixinverse", 1, GLSLstd450MatrixInverse, GlslDataType::kMatrix, 0},
|
|
||||||
{"nclamp", 3, GLSLstd450NClamp, GlslDataType::kFloatScalarOrVector, 0},
|
|
||||||
{"nmax", 2, GLSLstd450NMax, GlslDataType::kFloatScalarOrVector, 0},
|
|
||||||
{"nmin", 2, GLSLstd450NMin, GlslDataType::kFloatScalarOrVector, 0},
|
|
||||||
{"normalize", 1, GLSLstd450Normalize, GlslDataType::kFloatScalarOrVector,
|
|
||||||
0},
|
|
||||||
{"pow", 2, GLSLstd450Pow, GlslDataType::kFloatScalarOrVector, 0},
|
|
||||||
{"radians", 1, GLSLstd450Radians, GlslDataType::kFloatScalarOrVector, 0},
|
|
||||||
{"reflect", 2, GLSLstd450Reflect, GlslDataType::kFloatScalarOrVector, 0},
|
|
||||||
{"round", 1, GLSLstd450Round, GlslDataType::kFloatScalarOrVector, 0},
|
|
||||||
{"roundeven", 1, GLSLstd450RoundEven, GlslDataType::kFloatScalarOrVector,
|
|
||||||
0},
|
|
||||||
{"sabs", 1, GLSLstd450SAbs, GlslDataType::kIntScalarOrVector, 0},
|
|
||||||
{"sclamp", 3, GLSLstd450SClamp, GlslDataType::kIntScalarOrVector, 0},
|
|
||||||
{"sin", 1, GLSLstd450Sin, GlslDataType::kFloatScalarOrVector, 0},
|
|
||||||
{"sinh", 1, GLSLstd450Sinh, GlslDataType::kFloatScalarOrVector, 0},
|
|
||||||
{"smax", 2, GLSLstd450SMax, GlslDataType::kIntScalarOrVector, 0},
|
|
||||||
{"smin", 2, GLSLstd450SMin, GlslDataType::kIntScalarOrVector, 0},
|
|
||||||
{"smoothstep", 3, GLSLstd450SmoothStep, GlslDataType::kFloatScalarOrVector,
|
|
||||||
0},
|
|
||||||
{"sqrt", 1, GLSLstd450Sqrt, GlslDataType::kFloatScalarOrVector, 0},
|
|
||||||
{"ssign", 1, GLSLstd450SSign, GlslDataType::kIntScalarOrVector, 0},
|
|
||||||
{"step", 2, GLSLstd450Step, GlslDataType::kFloatScalarOrVector, 0},
|
|
||||||
{"tan", 1, GLSLstd450Tan, GlslDataType::kFloatScalarOrVector, 0},
|
|
||||||
{"tanh", 1, GLSLstd450Tanh, GlslDataType::kFloatScalarOrVector, 0},
|
|
||||||
{"trunc", 1, GLSLstd450Trunc, GlslDataType::kFloatScalarOrVector, 0},
|
|
||||||
{"uclamp", 3, GLSLstd450UClamp, GlslDataType::kIntScalarOrVector, 0},
|
|
||||||
{"umax", 2, GLSLstd450UMax, GlslDataType::kIntScalarOrVector, 0},
|
|
||||||
{"umin", 2, GLSLstd450UMin, GlslDataType::kIntScalarOrVector, 0},
|
|
||||||
};
|
|
||||||
constexpr const uint32_t kGlslDataCount = sizeof(kGlslData) / sizeof(GlslData);
|
|
||||||
|
|
||||||
} // namespace
|
|
||||||
|
|
||||||
TypeDeterminer::TypeDeterminer(Context* ctx, ast::Module* mod)
|
TypeDeterminer::TypeDeterminer(Context* ctx, ast::Module* mod)
|
||||||
: ctx_(*ctx), mod_(mod) {}
|
: ctx_(*ctx), mod_(mod) {}
|
||||||
@ -471,6 +372,9 @@ bool TypeDeterminer::DetermineAs(ast::AsExpression* expr) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool TypeDeterminer::DetermineCall(ast::CallExpression* expr) {
|
bool TypeDeterminer::DetermineCall(ast::CallExpression* expr) {
|
||||||
|
if (!DetermineResultType(expr->func())) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
if (!DetermineResultType(expr->params())) {
|
if (!DetermineResultType(expr->params())) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -481,31 +385,10 @@ bool TypeDeterminer::DetermineCall(ast::CallExpression* expr) {
|
|||||||
if (expr->func()->IsIdentifier()) {
|
if (expr->func()->IsIdentifier()) {
|
||||||
auto* ident = expr->func()->AsIdentifier();
|
auto* ident = expr->func()->AsIdentifier();
|
||||||
|
|
||||||
if (ast::intrinsic::IsIntrinsic(ident->name())) {
|
if (ident->IsIntrinsic()) {
|
||||||
if (!DetermineIntrinsic(ident->name(), expr))
|
if (!DetermineIntrinsic(ident, expr)) {
|
||||||
return false;
|
|
||||||
|
|
||||||
} else if (ident->has_path()) {
|
|
||||||
auto* imp = mod_->FindImportByName(ident->path());
|
|
||||||
if (imp == nullptr) {
|
|
||||||
set_error(expr->source(), "Unable to find import for " + ident->name());
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t ext_id = 0;
|
|
||||||
auto* result_type = GetImportData(expr->source(), imp->path(),
|
|
||||||
ident->name(), expr->params(), &ext_id);
|
|
||||||
if (result_type == nullptr) {
|
|
||||||
if (error_.empty()) {
|
|
||||||
set_error(expr->source(),
|
|
||||||
"Unable to determine result type for GLSL expression " +
|
|
||||||
ident->name());
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
imp->AddMethodId(ident->name(), ext_id);
|
|
||||||
expr->func()->set_result_type(result_type);
|
|
||||||
} else {
|
} else {
|
||||||
if (current_function_) {
|
if (current_function_) {
|
||||||
caller_to_callee_[current_function_->name()].push_back(ident->name());
|
caller_to_callee_[current_function_->name()].push_back(ident->name());
|
||||||
@ -547,41 +430,111 @@ bool TypeDeterminer::DetermineCall(ast::CallExpression* expr) {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool TypeDeterminer::DetermineIntrinsic(const std::string& name,
|
namespace {
|
||||||
|
|
||||||
|
enum class IntrinsicDataType {
|
||||||
|
kFloatOrIntScalarOrVector,
|
||||||
|
kFloatScalarOrVector,
|
||||||
|
kIntScalarOrVector,
|
||||||
|
kFloatVector,
|
||||||
|
kMatrix,
|
||||||
|
};
|
||||||
|
struct IntrinsicData {
|
||||||
|
ast::Intrinsic intrinsic;
|
||||||
|
uint8_t param_count;
|
||||||
|
IntrinsicDataType data_type;
|
||||||
|
uint8_t vector_size;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Note, this isn't all the intrinsics. Some are handled specially before
|
||||||
|
// we get to the generic code. See the DetermineIntrinsic code below.
|
||||||
|
constexpr const IntrinsicData kIntrinsicData[] = {
|
||||||
|
{ast::Intrinsic::kAbs, 1, IntrinsicDataType::kFloatOrIntScalarOrVector, 0},
|
||||||
|
{ast::Intrinsic::kAcos, 1, IntrinsicDataType::kFloatScalarOrVector, 0},
|
||||||
|
{ast::Intrinsic::kAsin, 1, IntrinsicDataType::kFloatScalarOrVector, 0},
|
||||||
|
{ast::Intrinsic::kAtan, 1, IntrinsicDataType::kFloatScalarOrVector, 0},
|
||||||
|
{ast::Intrinsic::kAtan2, 2, IntrinsicDataType::kFloatScalarOrVector, 0},
|
||||||
|
{ast::Intrinsic::kCeil, 1, IntrinsicDataType::kFloatScalarOrVector, 0},
|
||||||
|
{ast::Intrinsic::kClamp, 3, IntrinsicDataType::kFloatOrIntScalarOrVector,
|
||||||
|
0},
|
||||||
|
{ast::Intrinsic::kCos, 1, IntrinsicDataType::kFloatScalarOrVector, 0},
|
||||||
|
{ast::Intrinsic::kCosh, 1, IntrinsicDataType::kFloatScalarOrVector, 0},
|
||||||
|
{ast::Intrinsic::kCountOneBits, 1, IntrinsicDataType::kIntScalarOrVector,
|
||||||
|
0},
|
||||||
|
{ast::Intrinsic::kCross, 2, IntrinsicDataType::kFloatVector, 3},
|
||||||
|
{ast::Intrinsic::kDeterminant, 1, IntrinsicDataType::kMatrix, 0},
|
||||||
|
{ast::Intrinsic::kDistance, 2, IntrinsicDataType::kFloatScalarOrVector, 0},
|
||||||
|
{ast::Intrinsic::kExp, 1, IntrinsicDataType::kFloatScalarOrVector, 0},
|
||||||
|
{ast::Intrinsic::kExp2, 1, IntrinsicDataType::kFloatScalarOrVector, 0},
|
||||||
|
{ast::Intrinsic::kFaceForward, 3, IntrinsicDataType::kFloatScalarOrVector,
|
||||||
|
0},
|
||||||
|
{ast::Intrinsic::kFloor, 1, IntrinsicDataType::kFloatScalarOrVector, 0},
|
||||||
|
{ast::Intrinsic::kFma, 3, IntrinsicDataType::kFloatScalarOrVector, 0},
|
||||||
|
{ast::Intrinsic::kFract, 1, IntrinsicDataType::kFloatScalarOrVector, 0},
|
||||||
|
{ast::Intrinsic::kFrexp, 2, IntrinsicDataType::kFloatScalarOrVector, 0},
|
||||||
|
{ast::Intrinsic::kInverseSqrt, 1, IntrinsicDataType::kFloatScalarOrVector,
|
||||||
|
0},
|
||||||
|
{ast::Intrinsic::kLdexp, 2, IntrinsicDataType::kFloatScalarOrVector, 0},
|
||||||
|
{ast::Intrinsic::kLength, 1, IntrinsicDataType::kFloatScalarOrVector, 0},
|
||||||
|
{ast::Intrinsic::kLog, 1, IntrinsicDataType::kFloatScalarOrVector, 0},
|
||||||
|
{ast::Intrinsic::kLog2, 1, IntrinsicDataType::kFloatScalarOrVector, 0},
|
||||||
|
{ast::Intrinsic::kMax, 2, IntrinsicDataType::kFloatOrIntScalarOrVector, 0},
|
||||||
|
{ast::Intrinsic::kMin, 2, IntrinsicDataType::kFloatOrIntScalarOrVector, 0},
|
||||||
|
{ast::Intrinsic::kMix, 3, IntrinsicDataType::kFloatScalarOrVector, 0},
|
||||||
|
{ast::Intrinsic::kModf, 2, IntrinsicDataType::kFloatScalarOrVector, 0},
|
||||||
|
{ast::Intrinsic::kNormalize, 1, IntrinsicDataType::kFloatScalarOrVector, 0},
|
||||||
|
{ast::Intrinsic::kPow, 2, IntrinsicDataType::kFloatScalarOrVector, 0},
|
||||||
|
{ast::Intrinsic::kReflect, 2, IntrinsicDataType::kFloatScalarOrVector, 0},
|
||||||
|
{ast::Intrinsic::kReverseBits, 1, IntrinsicDataType::kIntScalarOrVector, 0},
|
||||||
|
{ast::Intrinsic::kRound, 1, IntrinsicDataType::kFloatScalarOrVector, 0},
|
||||||
|
{ast::Intrinsic::kSign, 1, IntrinsicDataType::kFloatScalarOrVector, 0},
|
||||||
|
{ast::Intrinsic::kSin, 1, IntrinsicDataType::kFloatScalarOrVector, 0},
|
||||||
|
{ast::Intrinsic::kSinh, 1, IntrinsicDataType::kFloatScalarOrVector, 0},
|
||||||
|
{ast::Intrinsic::kSmoothStep, 3, IntrinsicDataType::kFloatScalarOrVector,
|
||||||
|
0},
|
||||||
|
{ast::Intrinsic::kSqrt, 1, IntrinsicDataType::kFloatScalarOrVector, 0},
|
||||||
|
{ast::Intrinsic::kStep, 2, IntrinsicDataType::kFloatScalarOrVector, 0},
|
||||||
|
{ast::Intrinsic::kTan, 1, IntrinsicDataType::kFloatScalarOrVector, 0},
|
||||||
|
{ast::Intrinsic::kTanh, 1, IntrinsicDataType::kFloatScalarOrVector, 0},
|
||||||
|
{ast::Intrinsic::kTrunc, 1, IntrinsicDataType::kFloatScalarOrVector, 0},
|
||||||
|
};
|
||||||
|
|
||||||
|
constexpr const uint32_t kIntrinsicDataCount =
|
||||||
|
sizeof(kIntrinsicData) / sizeof(IntrinsicData);
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
bool TypeDeterminer::DetermineIntrinsic(ast::IdentifierExpression* ident,
|
||||||
ast::CallExpression* expr) {
|
ast::CallExpression* expr) {
|
||||||
if (ast::intrinsic::IsDerivative(name)) {
|
if (ast::intrinsic::IsDerivative(ident->intrinsic())) {
|
||||||
if (expr->params().size() != 1) {
|
if (expr->params().size() != 1) {
|
||||||
set_error(expr->source(), "incorrect number of parameters for " + name);
|
set_error(expr->source(),
|
||||||
|
"incorrect number of parameters for " + ident->name());
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// The result type must be the same as the type of the parameter.
|
// The result type must be the same as the type of the parameter.
|
||||||
auto& param = expr->params()[0];
|
auto* param_type = expr->params()[0]->result_type()->UnwrapPtrIfNeeded();
|
||||||
if (!DetermineResultType(param.get())) {
|
expr->func()->set_result_type(param_type);
|
||||||
return false;
|
|
||||||
}
|
|
||||||
expr->func()->set_result_type(param->result_type()->UnwrapPtrIfNeeded());
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (name == "any" || name == "all") {
|
if (ident->intrinsic() == ast::Intrinsic::kAny ||
|
||||||
|
ident->intrinsic() == ast::Intrinsic::kAll) {
|
||||||
expr->func()->set_result_type(
|
expr->func()->set_result_type(
|
||||||
ctx_.type_mgr().Get(std::make_unique<ast::type::BoolType>()));
|
ctx_.type_mgr().Get(std::make_unique<ast::type::BoolType>()));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (ast::intrinsic::IsFloatClassificationIntrinsic(name)) {
|
if (ast::intrinsic::IsFloatClassificationIntrinsic(ident->intrinsic())) {
|
||||||
if (expr->params().size() != 1) {
|
if (expr->params().size() != 1) {
|
||||||
set_error(expr->source(), "incorrect number of parameters for " + name);
|
set_error(expr->source(),
|
||||||
|
"incorrect number of parameters for " + ident->name());
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto* bool_type =
|
auto* bool_type =
|
||||||
ctx_.type_mgr().Get(std::make_unique<ast::type::BoolType>());
|
ctx_.type_mgr().Get(std::make_unique<ast::type::BoolType>());
|
||||||
|
|
||||||
auto& param = expr->params()[0];
|
auto* param_type = expr->params()[0]->result_type()->UnwrapPtrIfNeeded();
|
||||||
if (!DetermineResultType(param.get())) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
auto* param_type = param->result_type()->UnwrapPtrIfNeeded();
|
|
||||||
if (param_type->IsVector()) {
|
if (param_type->IsVector()) {
|
||||||
expr->func()->set_result_type(
|
expr->func()->set_result_type(
|
||||||
ctx_.type_mgr().Get(std::make_unique<ast::type::VectorType>(
|
ctx_.type_mgr().Get(std::make_unique<ast::type::VectorType>(
|
||||||
@ -591,31 +544,31 @@ bool TypeDeterminer::DetermineIntrinsic(const std::string& name,
|
|||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (ast::intrinsic::IsTextureOperationIntrinsic(name)) {
|
if (ast::intrinsic::IsTextureIntrinsic(ident->intrinsic())) {
|
||||||
// TODO: Remove the LOD param from textureLoad on storage textures when
|
// TODO: Remove the LOD param from textureLoad on storage textures when
|
||||||
// https://github.com/gpuweb/gpuweb/pull/1032 gets merged.
|
// https://github.com/gpuweb/gpuweb/pull/1032 gets merged.
|
||||||
uint32_t num_of_params =
|
uint32_t num_of_params =
|
||||||
(name == "textureLoad" || name == "textureSample") ? 3 : 4;
|
(ident->intrinsic() == ast::Intrinsic::kTextureLoad ||
|
||||||
|
ident->intrinsic() == ast::Intrinsic::kTextureSample)
|
||||||
|
? 3
|
||||||
|
: 4;
|
||||||
if (expr->params().size() != num_of_params) {
|
if (expr->params().size() != num_of_params) {
|
||||||
set_error(expr->source(),
|
set_error(expr->source(),
|
||||||
"incorrect number of parameters for " + name + ", got " +
|
"incorrect number of parameters for " + ident->name() +
|
||||||
std::to_string(expr->params().size()) + " and expected " +
|
", got " + std::to_string(expr->params().size()) +
|
||||||
std::to_string(num_of_params));
|
" and expected " + std::to_string(num_of_params));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (name == "textureSampleCompare") {
|
if (ident->intrinsic() == ast::Intrinsic::kTextureSampleCompare) {
|
||||||
expr->func()->set_result_type(
|
expr->func()->set_result_type(
|
||||||
ctx_.type_mgr().Get(std::make_unique<ast::type::F32Type>()));
|
ctx_.type_mgr().Get(std::make_unique<ast::type::F32Type>()));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto& texture_param = expr->params()[0];
|
auto& texture_param = expr->params()[0];
|
||||||
if (!DetermineResultType(texture_param.get())) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (!texture_param->result_type()->UnwrapPtrIfNeeded()->IsTexture()) {
|
if (!texture_param->result_type()->UnwrapPtrIfNeeded()->IsTexture()) {
|
||||||
set_error(expr->source(), "invalid first argument for " + name);
|
set_error(expr->source(), "invalid first argument for " + ident->name());
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
ast::type::TextureType* texture =
|
ast::type::TextureType* texture =
|
||||||
@ -623,7 +576,7 @@ bool TypeDeterminer::DetermineIntrinsic(const std::string& name,
|
|||||||
|
|
||||||
if (!texture->IsStorage() &&
|
if (!texture->IsStorage() &&
|
||||||
!(texture->IsSampled() || texture->IsMultisampled())) {
|
!(texture->IsSampled() || texture->IsMultisampled())) {
|
||||||
set_error(expr->source(), "invalid texture for " + name);
|
set_error(expr->source(), "invalid texture for " + ident->name());
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -642,29 +595,22 @@ bool TypeDeterminer::DetermineIntrinsic(const std::string& name,
|
|||||||
ctx_.type_mgr().Get(std::make_unique<ast::type::VectorType>(type, 4)));
|
ctx_.type_mgr().Get(std::make_unique<ast::type::VectorType>(type, 4)));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (name == "dot") {
|
if (ident->intrinsic() == ast::Intrinsic::kDot) {
|
||||||
expr->func()->set_result_type(
|
expr->func()->set_result_type(
|
||||||
ctx_.type_mgr().Get(std::make_unique<ast::type::F32Type>()));
|
ctx_.type_mgr().Get(std::make_unique<ast::type::F32Type>()));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (name == "outerProduct") {
|
if (ident->intrinsic() == ast::Intrinsic::kOuterProduct) {
|
||||||
if (expr->params().size() != 2) {
|
if (expr->params().size() != 2) {
|
||||||
set_error(expr->source(),
|
set_error(expr->source(),
|
||||||
"incorrect number of parameters for outer_product");
|
"incorrect number of parameters for " + ident->name());
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto& param0 = expr->params()[0];
|
auto* param0_type = expr->params()[0]->result_type()->UnwrapPtrIfNeeded();
|
||||||
auto& param1 = expr->params()[1];
|
auto* param1_type = expr->params()[1]->result_type()->UnwrapPtrIfNeeded();
|
||||||
if (!DetermineResultType(param0.get()) ||
|
|
||||||
!DetermineResultType(param1.get())) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto* param0_type = param0->result_type()->UnwrapPtrIfNeeded();
|
|
||||||
auto* param1_type = param1->result_type()->UnwrapPtrIfNeeded();
|
|
||||||
if (!param0_type->IsVector() || !param1_type->IsVector()) {
|
if (!param0_type->IsVector() || !param1_type->IsVector()) {
|
||||||
set_error(expr->source(), "invalid parameter type for outer_product");
|
set_error(expr->source(), "invalid parameter type for " + ident->name());
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -674,24 +620,121 @@ bool TypeDeterminer::DetermineIntrinsic(const std::string& name,
|
|||||||
param0_type->AsVector()->size(), param1_type->AsVector()->size())));
|
param0_type->AsVector()->size(), param1_type->AsVector()->size())));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (name == "select") {
|
if (ident->intrinsic() == ast::Intrinsic::kSelect) {
|
||||||
if (expr->params().size() != 3) {
|
if (expr->params().size() != 3) {
|
||||||
set_error(expr->source(),
|
set_error(expr->source(), "incorrect number of parameters for " +
|
||||||
"incorrect number of parameters for select expected 3 got " +
|
ident->name() + " expected 3 got " +
|
||||||
std::to_string(expr->params().size()));
|
std::to_string(expr->params().size()));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// The result type must be the same as the type of the parameter.
|
// The result type must be the same as the type of the parameter.
|
||||||
auto& param = expr->params()[0];
|
auto* param_type = expr->params()[0]->result_type()->UnwrapPtrIfNeeded();
|
||||||
if (!DetermineResultType(param.get())) {
|
expr->func()->set_result_type(param_type);
|
||||||
return false;
|
|
||||||
}
|
|
||||||
expr->func()->set_result_type(param->result_type()->UnwrapPtrIfNeeded());
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
const IntrinsicData* data = nullptr;
|
||||||
|
for (uint32_t i = 0; i < kIntrinsicDataCount; ++i) {
|
||||||
|
if (ident->intrinsic() == kIntrinsicData[i].intrinsic) {
|
||||||
|
data = &kIntrinsicData[i];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (data == nullptr) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (expr->params().size() != data->param_count) {
|
||||||
|
set_error(expr->source(), "incorrect number of parameters for " +
|
||||||
|
ident->name() + ". Expected " +
|
||||||
|
std::to_string(data->param_count) + " got " +
|
||||||
|
std::to_string(expr->params().size()));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<ast::type::Type*> result_types;
|
||||||
|
for (uint32_t i = 0; i < data->param_count; ++i) {
|
||||||
|
result_types.push_back(
|
||||||
|
expr->params()[i]->result_type()->UnwrapPtrIfNeeded());
|
||||||
|
|
||||||
|
switch (data->data_type) {
|
||||||
|
case IntrinsicDataType::kFloatOrIntScalarOrVector:
|
||||||
|
if (!result_types.back()->is_float_scalar_or_vector() &&
|
||||||
|
!result_types.back()->is_integer_scalar_or_vector()) {
|
||||||
|
set_error(expr->source(),
|
||||||
|
"incorrect type for " + ident->name() + ". " +
|
||||||
|
"Requires float or int, scalar or vector values");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case IntrinsicDataType::kFloatScalarOrVector:
|
||||||
|
if (!result_types.back()->is_float_scalar_or_vector()) {
|
||||||
|
set_error(expr->source(),
|
||||||
|
"incorrect type for " + ident->name() + ". " +
|
||||||
|
"Requires float scalar or float vector values");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
case IntrinsicDataType::kIntScalarOrVector:
|
||||||
|
if (!result_types.back()->is_integer_scalar_or_vector()) {
|
||||||
|
set_error(expr->source(),
|
||||||
|
"incorrect type for " + ident->name() + ". " +
|
||||||
|
"Requires integer scalar or integer vector values");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case IntrinsicDataType::kFloatVector:
|
||||||
|
if (!result_types.back()->is_float_vector()) {
|
||||||
|
set_error(expr->source(), "incorrect type for " + ident->name() +
|
||||||
|
". " + "Requires float vector values");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (data->vector_size > 0 &&
|
||||||
|
result_types.back()->AsVector()->size() != data->vector_size) {
|
||||||
|
set_error(expr->source(), "incorrect vector size for " +
|
||||||
|
ident->name() + ". " + "Requires " +
|
||||||
|
std::to_string(data->vector_size) +
|
||||||
|
" elements");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case IntrinsicDataType::kMatrix:
|
||||||
|
if (!result_types.back()->IsMatrix()) {
|
||||||
|
set_error(expr->source(), "incorrect type for " + ident->name() +
|
||||||
|
". Requires matrix value");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Verify all the parameter types match
|
||||||
|
for (size_t i = 1; i < data->param_count; ++i) {
|
||||||
|
if (result_types[0] != result_types[i]) {
|
||||||
|
set_error(expr->source(),
|
||||||
|
"mismatched parameter types for " + ident->name());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle functions which aways return the type, even if a vector is
|
||||||
|
// provided.
|
||||||
|
if (ident->intrinsic() == ast::Intrinsic::kLength ||
|
||||||
|
ident->intrinsic() == ast::Intrinsic::kDistance) {
|
||||||
|
expr->func()->set_result_type(result_types[0]->is_float_scalar()
|
||||||
|
? result_types[0]
|
||||||
|
: result_types[0]->AsVector()->type());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
// The determinant returns the component type of the columns
|
||||||
|
if (ident->intrinsic() == ast::Intrinsic::kDeterminant) {
|
||||||
|
expr->func()->set_result_type(result_types[0]->AsMatrix()->type());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
expr->func()->set_result_type(result_types[0]);
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool TypeDeterminer::DetermineCast(ast::CastExpression* expr) {
|
bool TypeDeterminer::DetermineCast(ast::CastExpression* expr) {
|
||||||
@ -719,12 +762,6 @@ bool TypeDeterminer::DetermineConstructor(ast::ConstructorExpression* expr) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool TypeDeterminer::DetermineIdentifier(ast::IdentifierExpression* expr) {
|
bool TypeDeterminer::DetermineIdentifier(ast::IdentifierExpression* expr) {
|
||||||
if (expr->has_path()) {
|
|
||||||
set_error(expr->source(),
|
|
||||||
"determine identifier should not be called with imports");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto name = expr->name();
|
auto name = expr->name();
|
||||||
ast::Variable* var;
|
ast::Variable* var;
|
||||||
if (variable_stack_.get(name, &var)) {
|
if (variable_stack_.get(name, &var)) {
|
||||||
@ -750,9 +787,147 @@ bool TypeDeterminer::DetermineIdentifier(ast::IdentifierExpression* expr) {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SetIntrinsicIfNeeded(expr);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void TypeDeterminer::SetIntrinsicIfNeeded(ast::IdentifierExpression* ident) {
|
||||||
|
if (ident->name() == "abs") {
|
||||||
|
ident->set_intrinsic(ast::Intrinsic::kAbs);
|
||||||
|
} else if (ident->name() == "acos") {
|
||||||
|
ident->set_intrinsic(ast::Intrinsic::kAcos);
|
||||||
|
} else if (ident->name() == "all") {
|
||||||
|
ident->set_intrinsic(ast::Intrinsic::kAll);
|
||||||
|
} else if (ident->name() == "any") {
|
||||||
|
ident->set_intrinsic(ast::Intrinsic::kAny);
|
||||||
|
} else if (ident->name() == "asin") {
|
||||||
|
ident->set_intrinsic(ast::Intrinsic::kAsin);
|
||||||
|
} else if (ident->name() == "atan") {
|
||||||
|
ident->set_intrinsic(ast::Intrinsic::kAtan);
|
||||||
|
} else if (ident->name() == "atan2") {
|
||||||
|
ident->set_intrinsic(ast::Intrinsic::kAtan2);
|
||||||
|
} else if (ident->name() == "ceil") {
|
||||||
|
ident->set_intrinsic(ast::Intrinsic::kCeil);
|
||||||
|
} else if (ident->name() == "clamp") {
|
||||||
|
ident->set_intrinsic(ast::Intrinsic::kClamp);
|
||||||
|
} else if (ident->name() == "cos") {
|
||||||
|
ident->set_intrinsic(ast::Intrinsic::kCos);
|
||||||
|
} else if (ident->name() == "cosh") {
|
||||||
|
ident->set_intrinsic(ast::Intrinsic::kCosh);
|
||||||
|
} else if (ident->name() == "countOneBits") {
|
||||||
|
ident->set_intrinsic(ast::Intrinsic::kCountOneBits);
|
||||||
|
} else if (ident->name() == "cross") {
|
||||||
|
ident->set_intrinsic(ast::Intrinsic::kCross);
|
||||||
|
} else if (ident->name() == "determinant") {
|
||||||
|
ident->set_intrinsic(ast::Intrinsic::kDeterminant);
|
||||||
|
} else if (ident->name() == "distance") {
|
||||||
|
ident->set_intrinsic(ast::Intrinsic::kDistance);
|
||||||
|
} else if (ident->name() == "dot") {
|
||||||
|
ident->set_intrinsic(ast::Intrinsic::kDot);
|
||||||
|
} else if (ident->name() == "dpdx") {
|
||||||
|
ident->set_intrinsic(ast::Intrinsic::kDpdx);
|
||||||
|
} else if (ident->name() == "dpdxCoarse") {
|
||||||
|
ident->set_intrinsic(ast::Intrinsic::kDpdxCoarse);
|
||||||
|
} else if (ident->name() == "dpdxFine") {
|
||||||
|
ident->set_intrinsic(ast::Intrinsic::kDpdxFine);
|
||||||
|
} else if (ident->name() == "dpdy") {
|
||||||
|
ident->set_intrinsic(ast::Intrinsic::kDpdy);
|
||||||
|
} else if (ident->name() == "dpdyCoarse") {
|
||||||
|
ident->set_intrinsic(ast::Intrinsic::kDpdyCoarse);
|
||||||
|
} else if (ident->name() == "dpdyFine") {
|
||||||
|
ident->set_intrinsic(ast::Intrinsic::kDpdyFine);
|
||||||
|
} else if (ident->name() == "exp") {
|
||||||
|
ident->set_intrinsic(ast::Intrinsic::kExp);
|
||||||
|
} else if (ident->name() == "exp2") {
|
||||||
|
ident->set_intrinsic(ast::Intrinsic::kExp2);
|
||||||
|
} else if (ident->name() == "faceForward") {
|
||||||
|
ident->set_intrinsic(ast::Intrinsic::kFaceForward);
|
||||||
|
} else if (ident->name() == "floor") {
|
||||||
|
ident->set_intrinsic(ast::Intrinsic::kFloor);
|
||||||
|
} else if (ident->name() == "fma") {
|
||||||
|
ident->set_intrinsic(ast::Intrinsic::kFma);
|
||||||
|
} else if (ident->name() == "fract") {
|
||||||
|
ident->set_intrinsic(ast::Intrinsic::kFract);
|
||||||
|
} else if (ident->name() == "frexp") {
|
||||||
|
ident->set_intrinsic(ast::Intrinsic::kFrexp);
|
||||||
|
} else if (ident->name() == "fwidth") {
|
||||||
|
ident->set_intrinsic(ast::Intrinsic::kFwidth);
|
||||||
|
} else if (ident->name() == "fwidthCoarse") {
|
||||||
|
ident->set_intrinsic(ast::Intrinsic::kFwidthCoarse);
|
||||||
|
} else if (ident->name() == "fwidthFine") {
|
||||||
|
ident->set_intrinsic(ast::Intrinsic::kFwidthFine);
|
||||||
|
} else if (ident->name() == "inverseSqrt") {
|
||||||
|
ident->set_intrinsic(ast::Intrinsic::kInverseSqrt);
|
||||||
|
} else if (ident->name() == "isFinite") {
|
||||||
|
ident->set_intrinsic(ast::Intrinsic::kIsFinite);
|
||||||
|
} else if (ident->name() == "isInf") {
|
||||||
|
ident->set_intrinsic(ast::Intrinsic::kIsInf);
|
||||||
|
} else if (ident->name() == "isNan") {
|
||||||
|
ident->set_intrinsic(ast::Intrinsic::kIsNan);
|
||||||
|
} else if (ident->name() == "isNormal") {
|
||||||
|
ident->set_intrinsic(ast::Intrinsic::kIsNormal);
|
||||||
|
} else if (ident->name() == "ldexp") {
|
||||||
|
ident->set_intrinsic(ast::Intrinsic::kLdexp);
|
||||||
|
} else if (ident->name() == "length") {
|
||||||
|
ident->set_intrinsic(ast::Intrinsic::kLength);
|
||||||
|
} else if (ident->name() == "log") {
|
||||||
|
ident->set_intrinsic(ast::Intrinsic::kLog);
|
||||||
|
} else if (ident->name() == "log2") {
|
||||||
|
ident->set_intrinsic(ast::Intrinsic::kLog2);
|
||||||
|
} else if (ident->name() == "max") {
|
||||||
|
ident->set_intrinsic(ast::Intrinsic::kMax);
|
||||||
|
} else if (ident->name() == "min") {
|
||||||
|
ident->set_intrinsic(ast::Intrinsic::kMin);
|
||||||
|
} else if (ident->name() == "mix") {
|
||||||
|
ident->set_intrinsic(ast::Intrinsic::kMix);
|
||||||
|
} else if (ident->name() == "modf") {
|
||||||
|
ident->set_intrinsic(ast::Intrinsic::kModf);
|
||||||
|
} else if (ident->name() == "normalize") {
|
||||||
|
ident->set_intrinsic(ast::Intrinsic::kNormalize);
|
||||||
|
} else if (ident->name() == "outerProduct") {
|
||||||
|
ident->set_intrinsic(ast::Intrinsic::kOuterProduct);
|
||||||
|
} else if (ident->name() == "pow") {
|
||||||
|
ident->set_intrinsic(ast::Intrinsic::kPow);
|
||||||
|
} else if (ident->name() == "reflect") {
|
||||||
|
ident->set_intrinsic(ast::Intrinsic::kReflect);
|
||||||
|
} else if (ident->name() == "reverseBits") {
|
||||||
|
ident->set_intrinsic(ast::Intrinsic::kReverseBits);
|
||||||
|
} else if (ident->name() == "round") {
|
||||||
|
ident->set_intrinsic(ast::Intrinsic::kRound);
|
||||||
|
} else if (ident->name() == "select") {
|
||||||
|
ident->set_intrinsic(ast::Intrinsic::kSelect);
|
||||||
|
} else if (ident->name() == "sign") {
|
||||||
|
ident->set_intrinsic(ast::Intrinsic::kSign);
|
||||||
|
} else if (ident->name() == "sin") {
|
||||||
|
ident->set_intrinsic(ast::Intrinsic::kSin);
|
||||||
|
} else if (ident->name() == "sinh") {
|
||||||
|
ident->set_intrinsic(ast::Intrinsic::kSinh);
|
||||||
|
} else if (ident->name() == "smoothStep") {
|
||||||
|
ident->set_intrinsic(ast::Intrinsic::kSmoothStep);
|
||||||
|
} else if (ident->name() == "sqrt") {
|
||||||
|
ident->set_intrinsic(ast::Intrinsic::kSqrt);
|
||||||
|
} else if (ident->name() == "step") {
|
||||||
|
ident->set_intrinsic(ast::Intrinsic::kStep);
|
||||||
|
} else if (ident->name() == "tan") {
|
||||||
|
ident->set_intrinsic(ast::Intrinsic::kTan);
|
||||||
|
} else if (ident->name() == "tanh") {
|
||||||
|
ident->set_intrinsic(ast::Intrinsic::kTanh);
|
||||||
|
} else if (ident->name() == "textureLoad") {
|
||||||
|
ident->set_intrinsic(ast::Intrinsic::kTextureLoad);
|
||||||
|
} else if (ident->name() == "textureSample") {
|
||||||
|
ident->set_intrinsic(ast::Intrinsic::kTextureSample);
|
||||||
|
} else if (ident->name() == "textureSampleBias") {
|
||||||
|
ident->set_intrinsic(ast::Intrinsic::kTextureSampleBias);
|
||||||
|
} else if (ident->name() == "textureSampleCompare") {
|
||||||
|
ident->set_intrinsic(ast::Intrinsic::kTextureSampleCompare);
|
||||||
|
} else if (ident->name() == "textureSampleLevel") {
|
||||||
|
ident->set_intrinsic(ast::Intrinsic::kTextureSampleLevel);
|
||||||
|
} else if (ident->name() == "trunc") {
|
||||||
|
ident->set_intrinsic(ast::Intrinsic::kTrunc);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
bool TypeDeterminer::DetermineMemberAccessor(
|
bool TypeDeterminer::DetermineMemberAccessor(
|
||||||
ast::MemberAccessorExpression* expr) {
|
ast::MemberAccessorExpression* expr) {
|
||||||
if (!DetermineResultType(expr->structure())) {
|
if (!DetermineResultType(expr->structure())) {
|
||||||
@ -962,101 +1137,4 @@ bool TypeDeterminer::DetermineStorageTextureSubtype(
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
ast::type::Type* TypeDeterminer::GetImportData(
|
|
||||||
const Source& source,
|
|
||||||
const std::string& path,
|
|
||||||
const std::string& name,
|
|
||||||
const ast::ExpressionList& params,
|
|
||||||
uint32_t* id) {
|
|
||||||
if (path != "GLSL.std.450") {
|
|
||||||
set_error(source, "unknown import path " + path);
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
const GlslData* data = nullptr;
|
|
||||||
for (uint32_t i = 0; i < kGlslDataCount; ++i) {
|
|
||||||
if (name == kGlslData[i].name) {
|
|
||||||
data = &kGlslData[i];
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (data == nullptr) {
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (params.size() != data->param_count) {
|
|
||||||
set_error(source, "incorrect number of parameters for " + name +
|
|
||||||
". Expected " + std::to_string(data->param_count) +
|
|
||||||
" got " + std::to_string(params.size()));
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<ast::type::Type*> result_types;
|
|
||||||
for (uint32_t i = 0; i < data->param_count; ++i) {
|
|
||||||
result_types.push_back(params[i]->result_type()->UnwrapPtrIfNeeded());
|
|
||||||
|
|
||||||
switch (data->type) {
|
|
||||||
case GlslDataType::kFloatScalarOrVector:
|
|
||||||
if (!result_types.back()->is_float_scalar_or_vector()) {
|
|
||||||
set_error(source, "incorrect type for " + name + ". " +
|
|
||||||
"Requires float scalar or float vector values");
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
|
||||||
case GlslDataType::kIntScalarOrVector:
|
|
||||||
if (!result_types.back()->is_integer_scalar_or_vector()) {
|
|
||||||
set_error(source,
|
|
||||||
"incorrect type for " + name + ". " +
|
|
||||||
"Requires integer scalar or integer vector values");
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case GlslDataType::kFloatVector:
|
|
||||||
if (!result_types.back()->is_float_vector()) {
|
|
||||||
set_error(source, "incorrect type for " + name + ". " +
|
|
||||||
"Requires float vector values");
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
if (data->vector_count > 0 &&
|
|
||||||
result_types.back()->AsVector()->size() != data->vector_count) {
|
|
||||||
set_error(source,
|
|
||||||
"incorrect vector size for " + name + ". " + "Requires " +
|
|
||||||
std::to_string(data->vector_count) + " elements");
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case GlslDataType::kMatrix:
|
|
||||||
if (!result_types.back()->IsMatrix()) {
|
|
||||||
set_error(source,
|
|
||||||
"incorrect type for " + name + ". Requires matrix value");
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Verify all the parameter types match
|
|
||||||
for (size_t i = 1; i < data->param_count; ++i) {
|
|
||||||
if (result_types[0] != result_types[i]) {
|
|
||||||
error_ = "mismatched parameter types for " + name;
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
*id = data->op_id;
|
|
||||||
|
|
||||||
// Handle functions which aways return the type, even if a vector is provided.
|
|
||||||
if (name == "length" || name == "distance") {
|
|
||||||
return result_types[0]->is_float_scalar()
|
|
||||||
? result_types[0]
|
|
||||||
: result_types[0]->AsVector()->type();
|
|
||||||
}
|
|
||||||
// The determinant returns the component type of the columns
|
|
||||||
if (name == "determinant") {
|
|
||||||
return result_types[0]->AsMatrix()->type();
|
|
||||||
}
|
|
||||||
return result_types[0];
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace tint
|
} // namespace tint
|
||||||
|
@ -107,6 +107,10 @@ class TypeDeterminer {
|
|||||||
const ast::ExpressionList& params,
|
const ast::ExpressionList& params,
|
||||||
uint32_t* id);
|
uint32_t* id);
|
||||||
|
|
||||||
|
/// Sets the intrinsic data information for the identifier if needed
|
||||||
|
/// @param ident the identifier expression
|
||||||
|
void SetIntrinsicIfNeeded(ast::IdentifierExpression* ident);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void set_error(const Source& src, const std::string& msg);
|
void set_error(const Source& src, const std::string& msg);
|
||||||
void set_referenced_from_function_if_needed(ast::Variable* var);
|
void set_referenced_from_function_if_needed(ast::Variable* var);
|
||||||
@ -119,7 +123,8 @@ class TypeDeterminer {
|
|||||||
bool DetermineCast(ast::CastExpression* expr);
|
bool DetermineCast(ast::CastExpression* expr);
|
||||||
bool DetermineConstructor(ast::ConstructorExpression* expr);
|
bool DetermineConstructor(ast::ConstructorExpression* expr);
|
||||||
bool DetermineIdentifier(ast::IdentifierExpression* expr);
|
bool DetermineIdentifier(ast::IdentifierExpression* expr);
|
||||||
bool DetermineIntrinsic(const std::string& name, ast::CallExpression* expr);
|
bool DetermineIntrinsic(ast::IdentifierExpression* name,
|
||||||
|
ast::CallExpression* expr);
|
||||||
bool DetermineMemberAccessor(ast::MemberAccessorExpression* expr);
|
bool DetermineMemberAccessor(ast::MemberAccessorExpression* expr);
|
||||||
bool DetermineUnaryOp(ast::UnaryOpExpression* expr);
|
bool DetermineUnaryOp(ast::UnaryOpExpression* expr);
|
||||||
|
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -46,9 +46,6 @@ bool ValidatorImpl::Validate(const ast::Module* module) {
|
|||||||
if (!ValidateGlobalVariables(module->global_variables())) {
|
if (!ValidateGlobalVariables(module->global_variables())) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (!CheckImports(module)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (!ValidateFunctions(module->functions())) {
|
if (!ValidateFunctions(module->functions())) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -330,9 +327,7 @@ bool ValidatorImpl::ValidateCallExpr(const ast::CallExpression* expr) {
|
|||||||
if (expr->func()->IsIdentifier()) {
|
if (expr->func()->IsIdentifier()) {
|
||||||
auto* ident = expr->func()->AsIdentifier();
|
auto* ident = expr->func()->AsIdentifier();
|
||||||
auto func_name = ident->name();
|
auto func_name = ident->name();
|
||||||
if (ident->has_path()) {
|
if (ident->IsIntrinsic()) {
|
||||||
// TODO(sarahM0): validate import statements
|
|
||||||
} else if (ast::intrinsic::IsIntrinsic(ident->name())) {
|
|
||||||
// TODO(sarahM0): validate intrinsics - tied with type-determiner
|
// TODO(sarahM0): validate intrinsics - tied with type-determiner
|
||||||
} else {
|
} else {
|
||||||
if (!function_stack_.has(func_name)) {
|
if (!function_stack_.has(func_name)) {
|
||||||
@ -433,14 +428,4 @@ bool ValidatorImpl::ValidateIdentifier(const ast::IdentifierExpression* ident) {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ValidatorImpl::CheckImports(const ast::Module* module) {
|
|
||||||
for (const auto& import : module->imports()) {
|
|
||||||
if (import->path() != "GLSL.std.450") {
|
|
||||||
set_error(import->source(), "v-0001: unknown import: " + import->path());
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace tint
|
} // namespace tint
|
||||||
|
@ -76,10 +76,6 @@ class ValidatorImpl {
|
|||||||
/// @param assign the assignment to check
|
/// @param assign the assignment to check
|
||||||
/// @returns true if the validation was successful
|
/// @returns true if the validation was successful
|
||||||
bool ValidateAssign(const ast::AssignmentStatement* assign);
|
bool ValidateAssign(const ast::AssignmentStatement* assign);
|
||||||
/// Validates v-0001: Only allowed import is "GLSL.std.450"
|
|
||||||
/// @param module the modele to check imports
|
|
||||||
/// @returns ture if input complies with v-0001 rule
|
|
||||||
bool CheckImports(const ast::Module* module);
|
|
||||||
/// Validates an expression
|
/// Validates an expression
|
||||||
/// @param expr the expression to check
|
/// @param expr the expression to check
|
||||||
/// @return true if the expression is valid
|
/// @return true if the expression is valid
|
||||||
|
@ -63,33 +63,6 @@ namespace {
|
|||||||
|
|
||||||
class ValidatorTest : public ValidatorTestHelper, public testing::Test {};
|
class ValidatorTest : public ValidatorTestHelper, public testing::Test {};
|
||||||
|
|
||||||
TEST_F(ValidatorTest, Import) {
|
|
||||||
ast::Module m;
|
|
||||||
m.AddImport(std::make_unique<ast::Import>("GLSL.std.450", "glsl"));
|
|
||||||
|
|
||||||
EXPECT_TRUE(v()->CheckImports(&m));
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(ValidatorTest, Import_Fail_NotGLSL) {
|
|
||||||
ast::Module m;
|
|
||||||
m.AddImport(
|
|
||||||
std::make_unique<ast::Import>(Source{12, 34}, "not.GLSL", "glsl"));
|
|
||||||
|
|
||||||
EXPECT_FALSE(v()->CheckImports(&m));
|
|
||||||
ASSERT_TRUE(v()->has_error());
|
|
||||||
EXPECT_EQ(v()->error(), "12:34: v-0001: unknown import: not.GLSL");
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(ValidatorTest, Import_Fail_Typo) {
|
|
||||||
ast::Module m;
|
|
||||||
m.AddImport(
|
|
||||||
std::make_unique<ast::Import>(Source{12, 34}, "GLSL.std.4501", "glsl"));
|
|
||||||
|
|
||||||
EXPECT_FALSE(v()->CheckImports(&m));
|
|
||||||
ASSERT_TRUE(v()->has_error());
|
|
||||||
EXPECT_EQ(v()->error(), "12:34: v-0001: unknown import: GLSL.std.4501");
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(ValidatorTest, DISABLED_AssignToScalar_Fail) {
|
TEST_F(ValidatorTest, DISABLED_AssignToScalar_Fail) {
|
||||||
// 1 = my_var;
|
// 1 = my_var;
|
||||||
ast::type::I32Type i32;
|
ast::type::I32Type i32;
|
||||||
|
@ -16,7 +16,6 @@
|
|||||||
|
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
|
|
||||||
#include "spirv/unified1/GLSL.std.450.h"
|
|
||||||
#include "src/ast/array_accessor_expression.h"
|
#include "src/ast/array_accessor_expression.h"
|
||||||
#include "src/ast/as_expression.h"
|
#include "src/ast/as_expression.h"
|
||||||
#include "src/ast/assignment_statement.h"
|
#include "src/ast/assignment_statement.h"
|
||||||
@ -31,7 +30,6 @@
|
|||||||
#include "src/ast/float_literal.h"
|
#include "src/ast/float_literal.h"
|
||||||
#include "src/ast/identifier_expression.h"
|
#include "src/ast/identifier_expression.h"
|
||||||
#include "src/ast/if_statement.h"
|
#include "src/ast/if_statement.h"
|
||||||
#include "src/ast/intrinsic.h"
|
|
||||||
#include "src/ast/loop_statement.h"
|
#include "src/ast/loop_statement.h"
|
||||||
#include "src/ast/member_accessor_expression.h"
|
#include "src/ast/member_accessor_expression.h"
|
||||||
#include "src/ast/return_statement.h"
|
#include "src/ast/return_statement.h"
|
||||||
@ -469,44 +467,46 @@ bool GeneratorImpl::EmitBreak(std::ostream& out, ast::BreakStatement*) {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string GeneratorImpl::generate_intrinsic_name(const std::string& name) {
|
std::string GeneratorImpl::generate_intrinsic_name(ast::Intrinsic intrinsic) {
|
||||||
if (name == "any") {
|
if (intrinsic == ast::Intrinsic::kAny) {
|
||||||
return "any";
|
return "any";
|
||||||
}
|
}
|
||||||
if (name == "all") {
|
if (intrinsic == ast::Intrinsic::kAll) {
|
||||||
return "all";
|
return "all";
|
||||||
}
|
}
|
||||||
if (name == "dot") {
|
if (intrinsic == ast::Intrinsic::kDot) {
|
||||||
return "dot";
|
return "dot";
|
||||||
}
|
}
|
||||||
if (name == "is_finite") {
|
if (intrinsic == ast::Intrinsic::kIsFinite) {
|
||||||
return "isfinite";
|
return "isfinite";
|
||||||
}
|
}
|
||||||
if (name == "is_inf") {
|
if (intrinsic == ast::Intrinsic::kIsInf) {
|
||||||
return "isinf";
|
return "isinf";
|
||||||
}
|
}
|
||||||
if (name == "is_nan") {
|
if (intrinsic == ast::Intrinsic::kIsNan) {
|
||||||
return "isnan";
|
return "isnan";
|
||||||
}
|
}
|
||||||
if (name == "dpdy") {
|
if (intrinsic == ast::Intrinsic::kDpdy) {
|
||||||
return "ddy";
|
return "ddy";
|
||||||
}
|
}
|
||||||
if (name == "dpdy_fine") {
|
if (intrinsic == ast::Intrinsic::kDpdyFine) {
|
||||||
return "ddy_fine";
|
return "ddy_fine";
|
||||||
}
|
}
|
||||||
if (name == "dpdy_coarse") {
|
if (intrinsic == ast::Intrinsic::kDpdyCoarse) {
|
||||||
return "ddy_coarse";
|
return "ddy_coarse";
|
||||||
}
|
}
|
||||||
if (name == "dpdx") {
|
if (intrinsic == ast::Intrinsic::kDpdx) {
|
||||||
return "ddx";
|
return "ddx";
|
||||||
}
|
}
|
||||||
if (name == "dpdx_fine") {
|
if (intrinsic == ast::Intrinsic::kDpdxFine) {
|
||||||
return "ddx_fine";
|
return "ddx_fine";
|
||||||
}
|
}
|
||||||
if (name == "dpdx_coarse") {
|
if (intrinsic == ast::Intrinsic::kDpdxCoarse) {
|
||||||
return "ddx_coarse";
|
return "ddx_coarse";
|
||||||
}
|
}
|
||||||
if (name == "fwidth" || name == "fwidth_fine" || name == "fwidth_coarse") {
|
if (intrinsic == ast::Intrinsic::kFwidth ||
|
||||||
|
intrinsic == ast::Intrinsic::kFwidthFine ||
|
||||||
|
intrinsic == ast::Intrinsic::kFwidthCoarse) {
|
||||||
return "fwidth";
|
return "fwidth";
|
||||||
}
|
}
|
||||||
return "";
|
return "";
|
||||||
@ -521,15 +521,15 @@ bool GeneratorImpl::EmitCall(std::ostream& pre,
|
|||||||
}
|
}
|
||||||
|
|
||||||
auto* ident = expr->func()->AsIdentifier();
|
auto* ident = expr->func()->AsIdentifier();
|
||||||
if (!ident->has_path() && ast::intrinsic::IsIntrinsic(ident->name())) {
|
if (ident->IsIntrinsic()) {
|
||||||
const auto& params = expr->params();
|
const auto& params = expr->params();
|
||||||
if (ident->name() == "select") {
|
if (ident->intrinsic() == ast::Intrinsic::kSelect) {
|
||||||
error_ = "select not supported in HLSL backend yet";
|
error_ = "select not supported in HLSL backend yet";
|
||||||
return false;
|
return false;
|
||||||
} else if (ident->name() == "is_normal") {
|
} else if (ident->intrinsic() == ast::Intrinsic::kIsNormal) {
|
||||||
error_ = "is_normal not supported in HLSL backend yet";
|
error_ = "is_normal not supported in HLSL backend yet";
|
||||||
return false;
|
return false;
|
||||||
} else if (ident->name() == "outer_product") {
|
} else if (ident->intrinsic() == ast::Intrinsic::kOuterProduct) {
|
||||||
error_ = "outer_product not supported yet";
|
error_ = "outer_product not supported yet";
|
||||||
return false;
|
return false;
|
||||||
// TODO(dsinclair): This gets tricky. We need to generate two variables to
|
// TODO(dsinclair): This gets tricky. We need to generate two variables to
|
||||||
@ -582,11 +582,15 @@ bool GeneratorImpl::EmitCall(std::ostream& pre,
|
|||||||
|
|
||||||
// out << ")";
|
// out << ")";
|
||||||
} else {
|
} else {
|
||||||
auto name = generate_intrinsic_name(ident->name());
|
auto name = generate_intrinsic_name(ident->intrinsic());
|
||||||
if (name.empty()) {
|
if (name.empty()) {
|
||||||
error_ = "unable to determine intrinsic name for intrinsic: " +
|
if (ast::intrinsic::IsTextureIntrinsic(ident->intrinsic())) {
|
||||||
ident->name();
|
error_ = "Textures not implemented yet";
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
if (!EmitBuiltinName(pre, out, expr)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
make_indent(out);
|
make_indent(out);
|
||||||
@ -609,162 +613,39 @@ bool GeneratorImpl::EmitCall(std::ostream& pre,
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!ident->has_path()) {
|
auto name = ident->name();
|
||||||
auto name = ident->name();
|
auto it = ep_func_name_remapped_.find(current_ep_name_ + "_" + name);
|
||||||
auto it = ep_func_name_remapped_.find(current_ep_name_ + "_" + name);
|
if (it != ep_func_name_remapped_.end()) {
|
||||||
if (it != ep_func_name_remapped_.end()) {
|
name = it->second;
|
||||||
name = it->second;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
auto* func = module_->FindFunctionByName(ident->name());
|
auto* func = module_->FindFunctionByName(ident->name());
|
||||||
if (func == nullptr) {
|
if (func == nullptr) {
|
||||||
error_ = "Unable to find function: " + name;
|
error_ = "Unable to find function: " + name;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
out << name << "(";
|
out << name << "(";
|
||||||
|
|
||||||
bool first = true;
|
bool first = true;
|
||||||
if (has_referenced_in_var_needing_struct(func)) {
|
if (has_referenced_in_var_needing_struct(func)) {
|
||||||
auto var_name = current_ep_var_name(VarType::kIn);
|
auto var_name = current_ep_var_name(VarType::kIn);
|
||||||
if (!var_name.empty()) {
|
if (!var_name.empty()) {
|
||||||
out << var_name;
|
out << var_name;
|
||||||
first = false;
|
first = false;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if (has_referenced_out_var_needing_struct(func)) {
|
}
|
||||||
auto var_name = current_ep_var_name(VarType::kOut);
|
if (has_referenced_out_var_needing_struct(func)) {
|
||||||
if (!var_name.empty()) {
|
auto var_name = current_ep_var_name(VarType::kOut);
|
||||||
if (!first) {
|
if (!var_name.empty()) {
|
||||||
out << ", ";
|
|
||||||
}
|
|
||||||
first = false;
|
|
||||||
out << var_name;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const auto& params = expr->params();
|
|
||||||
for (const auto& param : params) {
|
|
||||||
if (!first) {
|
if (!first) {
|
||||||
out << ", ";
|
out << ", ";
|
||||||
}
|
}
|
||||||
first = false;
|
first = false;
|
||||||
|
out << var_name;
|
||||||
if (!EmitExpression(pre, out, param.get())) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
out << ")";
|
|
||||||
} else {
|
|
||||||
return EmitImportFunction(pre, out, expr);
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool GeneratorImpl::EmitImportFunction(std::ostream& pre,
|
|
||||||
std::ostream& out,
|
|
||||||
ast::CallExpression* expr) {
|
|
||||||
auto* ident = expr->func()->AsIdentifier();
|
|
||||||
|
|
||||||
auto* imp = module_->FindImportByName(ident->path());
|
|
||||||
if (imp == nullptr) {
|
|
||||||
error_ = "unable to find import for " + ident->path();
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
auto id = imp->GetIdForMethod(ident->name());
|
|
||||||
if (id == 0) {
|
|
||||||
error_ = "unable to lookup: " + ident->name() + " in " + ident->path();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (id) {
|
|
||||||
case GLSLstd450Acos:
|
|
||||||
case GLSLstd450Asin:
|
|
||||||
case GLSLstd450Atan:
|
|
||||||
case GLSLstd450Atan2:
|
|
||||||
case GLSLstd450Ceil:
|
|
||||||
case GLSLstd450Cos:
|
|
||||||
case GLSLstd450Cosh:
|
|
||||||
case GLSLstd450Cross:
|
|
||||||
case GLSLstd450Degrees:
|
|
||||||
case GLSLstd450Determinant:
|
|
||||||
case GLSLstd450Distance:
|
|
||||||
case GLSLstd450Exp:
|
|
||||||
case GLSLstd450Exp2:
|
|
||||||
case GLSLstd450FaceForward:
|
|
||||||
case GLSLstd450Floor:
|
|
||||||
case GLSLstd450Fma:
|
|
||||||
case GLSLstd450Length:
|
|
||||||
case GLSLstd450Log:
|
|
||||||
case GLSLstd450Log2:
|
|
||||||
case GLSLstd450Normalize:
|
|
||||||
case GLSLstd450Pow:
|
|
||||||
case GLSLstd450Radians:
|
|
||||||
case GLSLstd450Reflect:
|
|
||||||
case GLSLstd450Round:
|
|
||||||
case GLSLstd450Sin:
|
|
||||||
case GLSLstd450Sinh:
|
|
||||||
case GLSLstd450SmoothStep:
|
|
||||||
case GLSLstd450Sqrt:
|
|
||||||
case GLSLstd450Step:
|
|
||||||
case GLSLstd450Tan:
|
|
||||||
case GLSLstd450Tanh:
|
|
||||||
case GLSLstd450Trunc:
|
|
||||||
out << ident->name();
|
|
||||||
break;
|
|
||||||
case GLSLstd450Fract:
|
|
||||||
out << "frac";
|
|
||||||
break;
|
|
||||||
case GLSLstd450InterpolateAtCentroid:
|
|
||||||
out << "EvaluateAttributeAtCentroid";
|
|
||||||
break;
|
|
||||||
case GLSLstd450InverseSqrt:
|
|
||||||
out << "rsqrt";
|
|
||||||
break;
|
|
||||||
case GLSLstd450FMix:
|
|
||||||
out << "mix";
|
|
||||||
break;
|
|
||||||
case GLSLstd450SSign:
|
|
||||||
case GLSLstd450FSign:
|
|
||||||
out << "sign";
|
|
||||||
break;
|
|
||||||
case GLSLstd450FAbs:
|
|
||||||
case GLSLstd450SAbs:
|
|
||||||
out << "abs";
|
|
||||||
break;
|
|
||||||
case GLSLstd450FMax:
|
|
||||||
case GLSLstd450NMax:
|
|
||||||
case GLSLstd450SMax:
|
|
||||||
case GLSLstd450UMax:
|
|
||||||
out << "max";
|
|
||||||
break;
|
|
||||||
case GLSLstd450FMin:
|
|
||||||
case GLSLstd450NMin:
|
|
||||||
case GLSLstd450SMin:
|
|
||||||
case GLSLstd450UMin:
|
|
||||||
out << "min";
|
|
||||||
break;
|
|
||||||
case GLSLstd450FClamp:
|
|
||||||
case GLSLstd450SClamp:
|
|
||||||
case GLSLstd450NClamp:
|
|
||||||
case GLSLstd450UClamp:
|
|
||||||
out << "clamp";
|
|
||||||
break;
|
|
||||||
// TODO(dsinclair): Determine mappings for the following
|
|
||||||
case GLSLstd450Atanh:
|
|
||||||
case GLSLstd450Asinh:
|
|
||||||
case GLSLstd450Acosh:
|
|
||||||
case GLSLstd450FindILsb:
|
|
||||||
case GLSLstd450FindUMsb:
|
|
||||||
case GLSLstd450FindSMsb:
|
|
||||||
case GLSLstd450MatrixInverse:
|
|
||||||
case GLSLstd450RoundEven:
|
|
||||||
error_ = "Unknown import method: " + ident->name();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
out << "(";
|
|
||||||
bool first = true;
|
|
||||||
const auto& params = expr->params();
|
const auto& params = expr->params();
|
||||||
for (const auto& param : params) {
|
for (const auto& param : params) {
|
||||||
if (!first) {
|
if (!first) {
|
||||||
@ -776,11 +657,73 @@ bool GeneratorImpl::EmitImportFunction(std::ostream& pre,
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
out << ")";
|
out << ")";
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool GeneratorImpl::EmitBuiltinName(std::ostream&,
|
||||||
|
std::ostream& out,
|
||||||
|
ast::CallExpression* expr) {
|
||||||
|
auto* ident = expr->func()->AsIdentifier();
|
||||||
|
switch (ident->intrinsic()) {
|
||||||
|
case ast::Intrinsic::kAcos:
|
||||||
|
case ast::Intrinsic::kAsin:
|
||||||
|
case ast::Intrinsic::kAtan:
|
||||||
|
case ast::Intrinsic::kAtan2:
|
||||||
|
case ast::Intrinsic::kCeil:
|
||||||
|
case ast::Intrinsic::kCos:
|
||||||
|
case ast::Intrinsic::kCosh:
|
||||||
|
case ast::Intrinsic::kCross:
|
||||||
|
case ast::Intrinsic::kDeterminant:
|
||||||
|
case ast::Intrinsic::kDistance:
|
||||||
|
case ast::Intrinsic::kExp:
|
||||||
|
case ast::Intrinsic::kExp2:
|
||||||
|
case ast::Intrinsic::kFloor:
|
||||||
|
case ast::Intrinsic::kFma:
|
||||||
|
case ast::Intrinsic::kLength:
|
||||||
|
case ast::Intrinsic::kLog:
|
||||||
|
case ast::Intrinsic::kLog2:
|
||||||
|
case ast::Intrinsic::kNormalize:
|
||||||
|
case ast::Intrinsic::kPow:
|
||||||
|
case ast::Intrinsic::kReflect:
|
||||||
|
case ast::Intrinsic::kRound:
|
||||||
|
case ast::Intrinsic::kSin:
|
||||||
|
case ast::Intrinsic::kSinh:
|
||||||
|
case ast::Intrinsic::kSqrt:
|
||||||
|
case ast::Intrinsic::kStep:
|
||||||
|
case ast::Intrinsic::kTan:
|
||||||
|
case ast::Intrinsic::kTanh:
|
||||||
|
case ast::Intrinsic::kTrunc:
|
||||||
|
case ast::Intrinsic::kMix:
|
||||||
|
case ast::Intrinsic::kSign:
|
||||||
|
case ast::Intrinsic::kAbs:
|
||||||
|
case ast::Intrinsic::kMax:
|
||||||
|
case ast::Intrinsic::kMin:
|
||||||
|
case ast::Intrinsic::kClamp:
|
||||||
|
out << ident->name();
|
||||||
|
break;
|
||||||
|
case ast::Intrinsic::kFaceForward:
|
||||||
|
out << "faceforward";
|
||||||
|
break;
|
||||||
|
case ast::Intrinsic::kFract:
|
||||||
|
out << "frac";
|
||||||
|
break;
|
||||||
|
case ast::Intrinsic::kInverseSqrt:
|
||||||
|
out << "rsqrt";
|
||||||
|
break;
|
||||||
|
case ast::Intrinsic::kSmoothStep:
|
||||||
|
out << "smoothstep";
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
error_ = "Unknown builtin method: " + ident->name();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
bool GeneratorImpl::EmitCast(std::ostream& pre,
|
bool GeneratorImpl::EmitCast(std::ostream& pre,
|
||||||
std::ostream& out,
|
std::ostream& out,
|
||||||
ast::CastExpression* expr) {
|
ast::CastExpression* expr) {
|
||||||
@ -957,12 +900,6 @@ bool GeneratorImpl::EmitIdentifier(std::ostream&,
|
|||||||
std::ostream& out,
|
std::ostream& out,
|
||||||
ast::IdentifierExpression* expr) {
|
ast::IdentifierExpression* expr) {
|
||||||
auto* ident = expr->AsIdentifier();
|
auto* ident = expr->AsIdentifier();
|
||||||
if (ident->has_path()) {
|
|
||||||
// TODO(dsinclair): Handle identifier with path
|
|
||||||
error_ = "Identifier paths not handled yet.";
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
ast::Variable* var = nullptr;
|
ast::Variable* var = nullptr;
|
||||||
if (global_variables_.get(ident->name(), &var)) {
|
if (global_variables_.get(ident->name(), &var)) {
|
||||||
if (global_is_in_struct(var)) {
|
if (global_is_in_struct(var)) {
|
||||||
@ -1832,10 +1769,6 @@ bool GeneratorImpl::is_storage_buffer_access(
|
|||||||
// Check if this is a storage buffer variable
|
// Check if this is a storage buffer variable
|
||||||
if (structure->IsIdentifier()) {
|
if (structure->IsIdentifier()) {
|
||||||
auto* ident = expr->structure()->AsIdentifier();
|
auto* ident = expr->structure()->AsIdentifier();
|
||||||
if (ident->has_path()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
ast::Variable* var = nullptr;
|
ast::Variable* var = nullptr;
|
||||||
if (!global_variables_.get(ident->name(), &var)) {
|
if (!global_variables_.get(ident->name(), &var)) {
|
||||||
return false;
|
return false;
|
||||||
|
@ -15,6 +15,7 @@
|
|||||||
#ifndef SRC_WRITER_HLSL_GENERATOR_IMPL_H_
|
#ifndef SRC_WRITER_HLSL_GENERATOR_IMPL_H_
|
||||||
#define SRC_WRITER_HLSL_GENERATOR_IMPL_H_
|
#define SRC_WRITER_HLSL_GENERATOR_IMPL_H_
|
||||||
|
|
||||||
|
#include "src/ast/intrinsic.h"
|
||||||
#include "src/ast/literal.h"
|
#include "src/ast/literal.h"
|
||||||
#include "src/ast/module.h"
|
#include "src/ast/module.h"
|
||||||
#include "src/ast/scalar_constructor_expression.h"
|
#include "src/ast/scalar_constructor_expression.h"
|
||||||
@ -206,14 +207,14 @@ class GeneratorImpl {
|
|||||||
/// @param stmt the statement to emit
|
/// @param stmt the statement to emit
|
||||||
/// @returns true if the statement was successfully emitted
|
/// @returns true if the statement was successfully emitted
|
||||||
bool EmitIf(std::ostream& out, ast::IfStatement* stmt);
|
bool EmitIf(std::ostream& out, ast::IfStatement* stmt);
|
||||||
/// Handles genreating an import expression
|
/// Handles generating a builtin method name
|
||||||
/// @param pre the preamble for the expression stream
|
/// @param pre the preamble for the expression stream
|
||||||
/// @param out the output of the expression stream
|
/// @param out the output of the expression stream
|
||||||
/// @param expr the expression
|
/// @param expr the expression
|
||||||
/// @returns true if the expression was successfully emitted.
|
/// @returns true if the name was successfully emitted.
|
||||||
bool EmitImportFunction(std::ostream& pre,
|
bool EmitBuiltinName(std::ostream& pre,
|
||||||
std::ostream& out,
|
std::ostream& out,
|
||||||
ast::CallExpression* expr);
|
ast::CallExpression* expr);
|
||||||
/// Handles a literal
|
/// Handles a literal
|
||||||
/// @param out the output stream
|
/// @param out the output stream
|
||||||
/// @param lit the literal to emit
|
/// @param lit the literal to emit
|
||||||
@ -327,9 +328,9 @@ class GeneratorImpl {
|
|||||||
/// @returns the name
|
/// @returns the name
|
||||||
std::string generate_name(const std::string& prefix);
|
std::string generate_name(const std::string& prefix);
|
||||||
/// Generates an intrinsic name from the given name
|
/// Generates an intrinsic name from the given name
|
||||||
/// @param name the name to convert to an intrinsic
|
/// @param intrinsic the intrinsic to convert to a name
|
||||||
/// @returns the intrinsic name or blank on error
|
/// @returns the intrinsic name or blank on error
|
||||||
std::string generate_intrinsic_name(const std::string& name);
|
std::string generate_intrinsic_name(ast::Intrinsic intrinsic);
|
||||||
/// Converts a builtin to an attribute name
|
/// Converts a builtin to an attribute name
|
||||||
/// @param builtin the builtin to convert
|
/// @param builtin the builtin to convert
|
||||||
/// @returns the string name of the builtin or blank on error
|
/// @returns the string name of the builtin or blank on error
|
||||||
|
@ -23,13 +23,7 @@ namespace {
|
|||||||
|
|
||||||
using HlslGeneratorImplTest_Identifier = TestHelper;
|
using HlslGeneratorImplTest_Identifier = TestHelper;
|
||||||
|
|
||||||
TEST_F(HlslGeneratorImplTest_Identifier, DISABLED_EmitExpression_Identifier) {
|
TEST_F(HlslGeneratorImplTest_Identifier, EmitIdentifierExpression) {
|
||||||
ast::IdentifierExpression i(std::vector<std::string>{"std", "glsl"});
|
|
||||||
ASSERT_TRUE(gen().EmitExpression(pre(), out(), &i)) << gen().error();
|
|
||||||
EXPECT_EQ(result(), "std::glsl");
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(HlslGeneratorImplTest_Identifier, EmitIdentifierExpression_Single) {
|
|
||||||
ast::IdentifierExpression i("foo");
|
ast::IdentifierExpression i("foo");
|
||||||
ASSERT_TRUE(gen().EmitExpression(pre(), out(), &i)) << gen().error();
|
ASSERT_TRUE(gen().EmitExpression(pre(), out(), &i)) << gen().error();
|
||||||
EXPECT_EQ(result(), "foo");
|
EXPECT_EQ(result(), "foo");
|
||||||
@ -42,14 +36,6 @@ TEST_F(HlslGeneratorImplTest_Identifier,
|
|||||||
EXPECT_EQ(result(), "virtual_tint_0");
|
EXPECT_EQ(result(), "virtual_tint_0");
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO(dsinclair): Handle import names
|
|
||||||
TEST_F(HlslGeneratorImplTest_Identifier,
|
|
||||||
DISABLED_EmitIdentifierExpression_MultipleNames) {
|
|
||||||
ast::IdentifierExpression i({"std", "glsl", "init"});
|
|
||||||
ASSERT_TRUE(gen().EmitExpression(pre(), out(), &i)) << gen().error();
|
|
||||||
EXPECT_EQ(result(), "std::glsl::init");
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
} // namespace hlsl
|
} // namespace hlsl
|
||||||
} // namespace writer
|
} // namespace writer
|
||||||
|
@ -58,59 +58,40 @@ TEST_P(HlslImportData_SingleParamTest, FloatScalar) {
|
|||||||
params.push_back(std::make_unique<ast::ScalarConstructorExpression>(
|
params.push_back(std::make_unique<ast::ScalarConstructorExpression>(
|
||||||
std::make_unique<ast::FloatLiteral>(&f32, 1.f)));
|
std::make_unique<ast::FloatLiteral>(&f32, 1.f)));
|
||||||
|
|
||||||
ast::CallExpression expr(std::make_unique<ast::IdentifierExpression>(
|
auto ident = std::make_unique<ast::IdentifierExpression>(param.name);
|
||||||
std::vector<std::string>{"std", param.name}),
|
ast::CallExpression expr(std::move(ident), std::move(params));
|
||||||
std::move(params));
|
|
||||||
|
|
||||||
mod()->AddImport(std::make_unique<ast::Import>("GLSL.std.450", "std"));
|
|
||||||
|
|
||||||
ASSERT_TRUE(td().DetermineResultType(&expr)) << td().error();
|
ASSERT_TRUE(td().DetermineResultType(&expr)) << td().error();
|
||||||
ASSERT_TRUE(gen().EmitImportFunction(pre(), out(), &expr)) << gen().error();
|
ASSERT_TRUE(gen().EmitCall(pre(), out(), &expr)) << gen().error();
|
||||||
EXPECT_EQ(result(), std::string(param.hlsl_name) + "(1.00000000f)");
|
EXPECT_EQ(result(), std::string(param.hlsl_name) + "(1.00000000f)");
|
||||||
}
|
}
|
||||||
INSTANTIATE_TEST_SUITE_P(
|
INSTANTIATE_TEST_SUITE_P(HlslGeneratorImplTest_Import,
|
||||||
HlslGeneratorImplTest_Import,
|
HlslImportData_SingleParamTest,
|
||||||
HlslImportData_SingleParamTest,
|
testing::Values(HlslImportData{"abs", "abs"},
|
||||||
testing::Values(HlslImportData{"acos", "acos"},
|
HlslImportData{"acos", "acos"},
|
||||||
HlslImportData{"asin", "asin"},
|
HlslImportData{"asin", "asin"},
|
||||||
HlslImportData{"atan", "atan"},
|
HlslImportData{"atan", "atan"},
|
||||||
HlslImportData{"cos", "cos"},
|
HlslImportData{"cos", "cos"},
|
||||||
HlslImportData{"cosh", "cosh"},
|
HlslImportData{"cosh", "cosh"},
|
||||||
HlslImportData{"ceil", "ceil"},
|
HlslImportData{"ceil", "ceil"},
|
||||||
HlslImportData{"degrees", "degrees"},
|
HlslImportData{"exp", "exp"},
|
||||||
HlslImportData{"exp", "exp"},
|
HlslImportData{"exp2", "exp2"},
|
||||||
HlslImportData{"exp2", "exp2"},
|
HlslImportData{"floor", "floor"},
|
||||||
HlslImportData{"fabs", "abs"},
|
HlslImportData{"fract", "frac"},
|
||||||
HlslImportData{"floor", "floor"},
|
HlslImportData{"inverseSqrt", "rsqrt"},
|
||||||
HlslImportData{"fract", "frac"},
|
HlslImportData{"length", "length"},
|
||||||
HlslImportData{"interpolateatcentroid",
|
HlslImportData{"log", "log"},
|
||||||
"EvaluateAttributeAtCentroid"},
|
HlslImportData{"log2", "log2"},
|
||||||
HlslImportData{"inversesqrt", "rsqrt"},
|
HlslImportData{"normalize",
|
||||||
HlslImportData{"length", "length"},
|
"normalize"},
|
||||||
HlslImportData{"log", "log"},
|
HlslImportData{"round", "round"},
|
||||||
HlslImportData{"log2", "log2"},
|
HlslImportData{"sign", "sign"},
|
||||||
HlslImportData{"normalize", "normalize"},
|
HlslImportData{"sin", "sin"},
|
||||||
HlslImportData{"radians", "radians"},
|
HlslImportData{"sinh", "sinh"},
|
||||||
HlslImportData{"round", "round"},
|
HlslImportData{"sqrt", "sqrt"},
|
||||||
HlslImportData{"fsign", "sign"},
|
HlslImportData{"tan", "tan"},
|
||||||
HlslImportData{"sin", "sin"},
|
HlslImportData{"tanh", "tanh"},
|
||||||
HlslImportData{"sinh", "sinh"},
|
HlslImportData{"trunc", "trunc"}));
|
||||||
HlslImportData{"sqrt", "sqrt"},
|
|
||||||
HlslImportData{"tan", "tan"},
|
|
||||||
HlslImportData{"tanh", "tanh"},
|
|
||||||
HlslImportData{"trunc", "trunc"}));
|
|
||||||
|
|
||||||
TEST_F(HlslGeneratorImplTest_Import, DISABLED_HlslImportData_Acosh) {
|
|
||||||
FAIL();
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(HlslGeneratorImplTest_Import, DISABLED_HlslImportData_ASinh) {
|
|
||||||
FAIL();
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(HlslGeneratorImplTest_Import, DISABLED_HlslImportData_ATanh) {
|
|
||||||
FAIL();
|
|
||||||
}
|
|
||||||
|
|
||||||
using HlslImportData_SingleIntParamTest =
|
using HlslImportData_SingleIntParamTest =
|
||||||
TestHelperBase<testing::TestWithParam<HlslImportData>>;
|
TestHelperBase<testing::TestWithParam<HlslImportData>>;
|
||||||
@ -123,20 +104,17 @@ TEST_P(HlslImportData_SingleIntParamTest, IntScalar) {
|
|||||||
params.push_back(std::make_unique<ast::ScalarConstructorExpression>(
|
params.push_back(std::make_unique<ast::ScalarConstructorExpression>(
|
||||||
std::make_unique<ast::SintLiteral>(&i32, 1)));
|
std::make_unique<ast::SintLiteral>(&i32, 1)));
|
||||||
|
|
||||||
ast::CallExpression expr(std::make_unique<ast::IdentifierExpression>(
|
ast::CallExpression expr(
|
||||||
std::vector<std::string>{"std", param.name}),
|
std::make_unique<ast::IdentifierExpression>(param.name),
|
||||||
std::move(params));
|
std::move(params));
|
||||||
|
|
||||||
mod()->AddImport(std::make_unique<ast::Import>("GLSL.std.450", "std"));
|
|
||||||
|
|
||||||
ASSERT_TRUE(td().DetermineResultType(&expr)) << td().error();
|
ASSERT_TRUE(td().DetermineResultType(&expr)) << td().error();
|
||||||
ASSERT_TRUE(gen().EmitImportFunction(pre(), out(), &expr)) << gen().error();
|
ASSERT_TRUE(gen().EmitCall(pre(), out(), &expr)) << gen().error();
|
||||||
EXPECT_EQ(result(), std::string(param.hlsl_name) + "(1)");
|
EXPECT_EQ(result(), std::string(param.hlsl_name) + "(1)");
|
||||||
}
|
}
|
||||||
INSTANTIATE_TEST_SUITE_P(HlslGeneratorImplTest_Import,
|
INSTANTIATE_TEST_SUITE_P(HlslGeneratorImplTest_Import,
|
||||||
HlslImportData_SingleIntParamTest,
|
HlslImportData_SingleIntParamTest,
|
||||||
testing::Values(HlslImportData{"sabs", "abs"},
|
testing::Values(HlslImportData{"abs", "abs"}));
|
||||||
HlslImportData{"ssign", "sign"}));
|
|
||||||
|
|
||||||
using HlslImportData_DualParamTest =
|
using HlslImportData_DualParamTest =
|
||||||
TestHelperBase<testing::TestWithParam<HlslImportData>>;
|
TestHelperBase<testing::TestWithParam<HlslImportData>>;
|
||||||
@ -151,14 +129,12 @@ TEST_P(HlslImportData_DualParamTest, FloatScalar) {
|
|||||||
params.push_back(std::make_unique<ast::ScalarConstructorExpression>(
|
params.push_back(std::make_unique<ast::ScalarConstructorExpression>(
|
||||||
std::make_unique<ast::FloatLiteral>(&f32, 2.f)));
|
std::make_unique<ast::FloatLiteral>(&f32, 2.f)));
|
||||||
|
|
||||||
ast::CallExpression expr(std::make_unique<ast::IdentifierExpression>(
|
ast::CallExpression expr(
|
||||||
std::vector<std::string>{"std", param.name}),
|
std::make_unique<ast::IdentifierExpression>(param.name),
|
||||||
std::move(params));
|
std::move(params));
|
||||||
|
|
||||||
mod()->AddImport(std::make_unique<ast::Import>("GLSL.std.450", "std"));
|
|
||||||
|
|
||||||
ASSERT_TRUE(td().DetermineResultType(&expr)) << td().error();
|
ASSERT_TRUE(td().DetermineResultType(&expr)) << td().error();
|
||||||
ASSERT_TRUE(gen().EmitImportFunction(pre(), out(), &expr)) << gen().error();
|
ASSERT_TRUE(gen().EmitCall(pre(), out(), &expr)) << gen().error();
|
||||||
EXPECT_EQ(result(),
|
EXPECT_EQ(result(),
|
||||||
std::string(param.hlsl_name) + "(1.00000000f, 2.00000000f)");
|
std::string(param.hlsl_name) + "(1.00000000f, 2.00000000f)");
|
||||||
}
|
}
|
||||||
@ -166,10 +142,8 @@ INSTANTIATE_TEST_SUITE_P(HlslGeneratorImplTest_Import,
|
|||||||
HlslImportData_DualParamTest,
|
HlslImportData_DualParamTest,
|
||||||
testing::Values(HlslImportData{"atan2", "atan2"},
|
testing::Values(HlslImportData{"atan2", "atan2"},
|
||||||
HlslImportData{"distance", "distance"},
|
HlslImportData{"distance", "distance"},
|
||||||
HlslImportData{"fmax", "max"},
|
HlslImportData{"max", "max"},
|
||||||
HlslImportData{"fmin", "min"},
|
HlslImportData{"min", "min"},
|
||||||
HlslImportData{"nmax", "max"},
|
|
||||||
HlslImportData{"nmin", "min"},
|
|
||||||
HlslImportData{"pow", "pow"},
|
HlslImportData{"pow", "pow"},
|
||||||
HlslImportData{"reflect", "reflect"},
|
HlslImportData{"reflect", "reflect"},
|
||||||
HlslImportData{"step", "step"}));
|
HlslImportData{"step", "step"}));
|
||||||
@ -203,14 +177,12 @@ TEST_P(HlslImportData_DualParam_VectorTest, FloatVector) {
|
|||||||
params.push_back(std::make_unique<ast::TypeConstructorExpression>(
|
params.push_back(std::make_unique<ast::TypeConstructorExpression>(
|
||||||
&vec, std::move(type_params)));
|
&vec, std::move(type_params)));
|
||||||
|
|
||||||
ast::CallExpression expr(std::make_unique<ast::IdentifierExpression>(
|
ast::CallExpression expr(
|
||||||
std::vector<std::string>{"std", param.name}),
|
std::make_unique<ast::IdentifierExpression>(param.name),
|
||||||
std::move(params));
|
std::move(params));
|
||||||
|
|
||||||
mod()->AddImport(std::make_unique<ast::Import>("GLSL.std.450", "std"));
|
|
||||||
|
|
||||||
ASSERT_TRUE(td().DetermineResultType(&expr)) << td().error();
|
ASSERT_TRUE(td().DetermineResultType(&expr)) << td().error();
|
||||||
ASSERT_TRUE(gen().EmitImportFunction(pre(), out(), &expr)) << gen().error();
|
ASSERT_TRUE(gen().EmitCall(pre(), out(), &expr)) << gen().error();
|
||||||
EXPECT_EQ(result(),
|
EXPECT_EQ(result(),
|
||||||
std::string(param.hlsl_name) +
|
std::string(param.hlsl_name) +
|
||||||
"(vector<float, 3>(1.00000000f, 2.00000000f, 3.00000000f), "
|
"(vector<float, 3>(1.00000000f, 2.00000000f, 3.00000000f), "
|
||||||
@ -233,22 +205,18 @@ TEST_P(HlslImportData_DualParam_Int_Test, IntScalar) {
|
|||||||
params.push_back(std::make_unique<ast::ScalarConstructorExpression>(
|
params.push_back(std::make_unique<ast::ScalarConstructorExpression>(
|
||||||
std::make_unique<ast::SintLiteral>(&i32, 2)));
|
std::make_unique<ast::SintLiteral>(&i32, 2)));
|
||||||
|
|
||||||
ast::CallExpression expr(std::make_unique<ast::IdentifierExpression>(
|
ast::CallExpression expr(
|
||||||
std::vector<std::string>{"std", param.name}),
|
std::make_unique<ast::IdentifierExpression>(param.name),
|
||||||
std::move(params));
|
std::move(params));
|
||||||
|
|
||||||
mod()->AddImport(std::make_unique<ast::Import>("GLSL.std.450", "std"));
|
|
||||||
|
|
||||||
ASSERT_TRUE(td().DetermineResultType(&expr)) << td().error();
|
ASSERT_TRUE(td().DetermineResultType(&expr)) << td().error();
|
||||||
ASSERT_TRUE(gen().EmitImportFunction(pre(), out(), &expr)) << gen().error();
|
ASSERT_TRUE(gen().EmitCall(pre(), out(), &expr)) << gen().error();
|
||||||
EXPECT_EQ(result(), std::string(param.hlsl_name) + "(1, 2)");
|
EXPECT_EQ(result(), std::string(param.hlsl_name) + "(1, 2)");
|
||||||
}
|
}
|
||||||
INSTANTIATE_TEST_SUITE_P(HlslGeneratorImplTest_Import,
|
INSTANTIATE_TEST_SUITE_P(HlslGeneratorImplTest_Import,
|
||||||
HlslImportData_DualParam_Int_Test,
|
HlslImportData_DualParam_Int_Test,
|
||||||
testing::Values(HlslImportData{"smax", "max"},
|
testing::Values(HlslImportData{"max", "max"},
|
||||||
HlslImportData{"smin", "min"},
|
HlslImportData{"min", "min"}));
|
||||||
HlslImportData{"umax", "max"},
|
|
||||||
HlslImportData{"umin", "min"}));
|
|
||||||
|
|
||||||
using HlslImportData_TripleParamTest =
|
using HlslImportData_TripleParamTest =
|
||||||
TestHelperBase<testing::TestWithParam<HlslImportData>>;
|
TestHelperBase<testing::TestWithParam<HlslImportData>>;
|
||||||
@ -265,25 +233,22 @@ TEST_P(HlslImportData_TripleParamTest, FloatScalar) {
|
|||||||
params.push_back(std::make_unique<ast::ScalarConstructorExpression>(
|
params.push_back(std::make_unique<ast::ScalarConstructorExpression>(
|
||||||
std::make_unique<ast::FloatLiteral>(&f32, 3.f)));
|
std::make_unique<ast::FloatLiteral>(&f32, 3.f)));
|
||||||
|
|
||||||
ast::CallExpression expr(std::make_unique<ast::IdentifierExpression>(
|
ast::CallExpression expr(
|
||||||
std::vector<std::string>{"std", param.name}),
|
std::make_unique<ast::IdentifierExpression>(param.name),
|
||||||
std::move(params));
|
std::move(params));
|
||||||
|
|
||||||
mod()->AddImport(std::make_unique<ast::Import>("GLSL.std.450", "std"));
|
|
||||||
|
|
||||||
ASSERT_TRUE(td().DetermineResultType(&expr)) << td().error();
|
ASSERT_TRUE(td().DetermineResultType(&expr)) << td().error();
|
||||||
ASSERT_TRUE(gen().EmitImportFunction(pre(), out(), &expr)) << gen().error();
|
ASSERT_TRUE(gen().EmitCall(pre(), out(), &expr)) << gen().error();
|
||||||
EXPECT_EQ(result(), std::string(param.hlsl_name) +
|
EXPECT_EQ(result(), std::string(param.hlsl_name) +
|
||||||
"(1.00000000f, 2.00000000f, 3.00000000f)");
|
"(1.00000000f, 2.00000000f, 3.00000000f)");
|
||||||
}
|
}
|
||||||
INSTANTIATE_TEST_SUITE_P(
|
INSTANTIATE_TEST_SUITE_P(
|
||||||
HlslGeneratorImplTest_Import,
|
HlslGeneratorImplTest_Import,
|
||||||
HlslImportData_TripleParamTest,
|
HlslImportData_TripleParamTest,
|
||||||
testing::Values(HlslImportData{"faceforward", "faceforward"},
|
testing::Values(HlslImportData{"faceForward", "faceforward"},
|
||||||
HlslImportData{"fma", "fma"},
|
HlslImportData{"fma", "fma"},
|
||||||
HlslImportData{"fclamp", "clamp"},
|
HlslImportData{"clamp", "clamp"},
|
||||||
HlslImportData{"nclamp", "clamp"},
|
HlslImportData{"smoothStep", "smoothstep"}));
|
||||||
HlslImportData{"smoothstep", "smoothstep"}));
|
|
||||||
|
|
||||||
TEST_F(HlslGeneratorImplTest_Import, DISABLED_HlslImportData_FMix) {
|
TEST_F(HlslGeneratorImplTest_Import, DISABLED_HlslImportData_FMix) {
|
||||||
FAIL();
|
FAIL();
|
||||||
@ -304,20 +269,17 @@ TEST_P(HlslImportData_TripleParam_Int_Test, IntScalar) {
|
|||||||
params.push_back(std::make_unique<ast::ScalarConstructorExpression>(
|
params.push_back(std::make_unique<ast::ScalarConstructorExpression>(
|
||||||
std::make_unique<ast::SintLiteral>(&i32, 3)));
|
std::make_unique<ast::SintLiteral>(&i32, 3)));
|
||||||
|
|
||||||
ast::CallExpression expr(std::make_unique<ast::IdentifierExpression>(
|
ast::CallExpression expr(
|
||||||
std::vector<std::string>{"std", param.name}),
|
std::make_unique<ast::IdentifierExpression>(param.name),
|
||||||
std::move(params));
|
std::move(params));
|
||||||
|
|
||||||
mod()->AddImport(std::make_unique<ast::Import>("GLSL.std.450", "std"));
|
|
||||||
|
|
||||||
ASSERT_TRUE(td().DetermineResultType(&expr)) << td().error();
|
ASSERT_TRUE(td().DetermineResultType(&expr)) << td().error();
|
||||||
ASSERT_TRUE(gen().EmitImportFunction(pre(), out(), &expr)) << gen().error();
|
ASSERT_TRUE(gen().EmitCall(pre(), out(), &expr)) << gen().error();
|
||||||
EXPECT_EQ(result(), std::string(param.hlsl_name) + "(1, 2, 3)");
|
EXPECT_EQ(result(), std::string(param.hlsl_name) + "(1, 2, 3)");
|
||||||
}
|
}
|
||||||
INSTANTIATE_TEST_SUITE_P(HlslGeneratorImplTest_Import,
|
INSTANTIATE_TEST_SUITE_P(HlslGeneratorImplTest_Import,
|
||||||
HlslImportData_TripleParam_Int_Test,
|
HlslImportData_TripleParam_Int_Test,
|
||||||
testing::Values(HlslImportData{"sclamp", "clamp"},
|
testing::Values(HlslImportData{"clamp", "clamp"}));
|
||||||
HlslImportData{"uclamp", "clamp"}));
|
|
||||||
|
|
||||||
TEST_F(HlslGeneratorImplTest_Import, HlslImportData_Determinant) {
|
TEST_F(HlslGeneratorImplTest_Import, HlslImportData_Determinant) {
|
||||||
ast::type::F32Type f32;
|
ast::type::F32Type f32;
|
||||||
@ -329,17 +291,16 @@ TEST_F(HlslGeneratorImplTest_Import, HlslImportData_Determinant) {
|
|||||||
ast::ExpressionList params;
|
ast::ExpressionList params;
|
||||||
params.push_back(std::make_unique<ast::IdentifierExpression>("var"));
|
params.push_back(std::make_unique<ast::IdentifierExpression>("var"));
|
||||||
|
|
||||||
ast::CallExpression expr(std::make_unique<ast::IdentifierExpression>(
|
ast::CallExpression expr(
|
||||||
std::vector<std::string>{"std", "determinant"}),
|
std::make_unique<ast::IdentifierExpression>("determinant"),
|
||||||
std::move(params));
|
std::move(params));
|
||||||
|
|
||||||
mod()->AddGlobalVariable(std::move(var));
|
mod()->AddGlobalVariable(std::move(var));
|
||||||
mod()->AddImport(std::make_unique<ast::Import>("GLSL.std.450", "std"));
|
|
||||||
|
|
||||||
// Register the global
|
// Register the global
|
||||||
ASSERT_TRUE(td().Determine()) << td().error();
|
ASSERT_TRUE(td().Determine()) << td().error();
|
||||||
ASSERT_TRUE(td().DetermineResultType(&expr)) << td().error();
|
ASSERT_TRUE(td().DetermineResultType(&expr)) << td().error();
|
||||||
ASSERT_TRUE(gen().EmitImportFunction(pre(), out(), &expr)) << gen().error();
|
ASSERT_TRUE(gen().EmitCall(pre(), out(), &expr)) << gen().error();
|
||||||
EXPECT_EQ(result(), std::string("determinant(var)"));
|
EXPECT_EQ(result(), std::string("determinant(var)"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -29,36 +29,36 @@ namespace {
|
|||||||
using HlslGeneratorImplTest_Intrinsic = TestHelper;
|
using HlslGeneratorImplTest_Intrinsic = TestHelper;
|
||||||
|
|
||||||
struct IntrinsicData {
|
struct IntrinsicData {
|
||||||
const char* name;
|
ast::Intrinsic intrinsic;
|
||||||
const char* hlsl_name;
|
const char* hlsl_name;
|
||||||
};
|
};
|
||||||
inline std::ostream& operator<<(std::ostream& out, IntrinsicData data) {
|
inline std::ostream& operator<<(std::ostream& out, IntrinsicData data) {
|
||||||
out << data.name;
|
out << data.hlsl_name;
|
||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
using HlslIntrinsicTest = TestHelperBase<testing::TestWithParam<IntrinsicData>>;
|
using HlslIntrinsicTest = TestHelperBase<testing::TestWithParam<IntrinsicData>>;
|
||||||
TEST_P(HlslIntrinsicTest, Emit) {
|
TEST_P(HlslIntrinsicTest, Emit) {
|
||||||
auto param = GetParam();
|
auto param = GetParam();
|
||||||
EXPECT_EQ(gen().generate_intrinsic_name(param.name), param.hlsl_name);
|
EXPECT_EQ(gen().generate_intrinsic_name(param.intrinsic), param.hlsl_name);
|
||||||
}
|
}
|
||||||
INSTANTIATE_TEST_SUITE_P(
|
INSTANTIATE_TEST_SUITE_P(
|
||||||
HlslGeneratorImplTest_Intrinsic,
|
HlslGeneratorImplTest_Intrinsic,
|
||||||
HlslIntrinsicTest,
|
HlslIntrinsicTest,
|
||||||
testing::Values(IntrinsicData{"any", "any"},
|
testing::Values(IntrinsicData{ast::Intrinsic::kAny, "any"},
|
||||||
IntrinsicData{"all", "all"},
|
IntrinsicData{ast::Intrinsic::kAll, "all"},
|
||||||
IntrinsicData{"dot", "dot"},
|
IntrinsicData{ast::Intrinsic::kDot, "dot"},
|
||||||
IntrinsicData{"dpdx", "ddx"},
|
IntrinsicData{ast::Intrinsic::kDpdx, "ddx"},
|
||||||
IntrinsicData{"dpdx_coarse", "ddx_coarse"},
|
IntrinsicData{ast::Intrinsic::kDpdxCoarse, "ddx_coarse"},
|
||||||
IntrinsicData{"dpdx_fine", "ddx_fine"},
|
IntrinsicData{ast::Intrinsic::kDpdxFine, "ddx_fine"},
|
||||||
IntrinsicData{"dpdy", "ddy"},
|
IntrinsicData{ast::Intrinsic::kDpdy, "ddy"},
|
||||||
IntrinsicData{"dpdy_coarse", "ddy_coarse"},
|
IntrinsicData{ast::Intrinsic::kDpdyCoarse, "ddy_coarse"},
|
||||||
IntrinsicData{"dpdy_fine", "ddy_fine"},
|
IntrinsicData{ast::Intrinsic::kDpdyFine, "ddy_fine"},
|
||||||
IntrinsicData{"fwidth", "fwidth"},
|
IntrinsicData{ast::Intrinsic::kFwidth, "fwidth"},
|
||||||
IntrinsicData{"fwidth_coarse", "fwidth"},
|
IntrinsicData{ast::Intrinsic::kFwidthCoarse, "fwidth"},
|
||||||
IntrinsicData{"fwidth_fine", "fwidth"},
|
IntrinsicData{ast::Intrinsic::kFwidthFine, "fwidth"},
|
||||||
IntrinsicData{"is_finite", "isfinite"},
|
IntrinsicData{ast::Intrinsic::kIsFinite, "isfinite"},
|
||||||
IntrinsicData{"is_inf", "isinf"},
|
IntrinsicData{ast::Intrinsic::kIsInf, "isinf"},
|
||||||
IntrinsicData{"is_nan", "isnan"}));
|
IntrinsicData{ast::Intrinsic::kIsNan, "isnan"}));
|
||||||
|
|
||||||
TEST_F(HlslGeneratorImplTest_Intrinsic, DISABLED_Intrinsic_IsNormal) {
|
TEST_F(HlslGeneratorImplTest_Intrinsic, DISABLED_Intrinsic_IsNormal) {
|
||||||
FAIL();
|
FAIL();
|
||||||
@ -101,7 +101,7 @@ TEST_F(HlslGeneratorImplTest_Intrinsic, DISABLED_Intrinsic_OuterProduct) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(HlslGeneratorImplTest_Intrinsic, Intrinsic_Bad_Name) {
|
TEST_F(HlslGeneratorImplTest_Intrinsic, Intrinsic_Bad_Name) {
|
||||||
EXPECT_EQ(gen().generate_intrinsic_name("unknown name"), "");
|
EXPECT_EQ(gen().generate_intrinsic_name(ast::Intrinsic::kNone), "");
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(HlslGeneratorImplTest_Intrinsic, Intrinsic_Call) {
|
TEST_F(HlslGeneratorImplTest_Intrinsic, Intrinsic_Call) {
|
||||||
@ -112,6 +112,8 @@ TEST_F(HlslGeneratorImplTest_Intrinsic, Intrinsic_Call) {
|
|||||||
ast::CallExpression call(std::make_unique<ast::IdentifierExpression>("dot"),
|
ast::CallExpression call(std::make_unique<ast::IdentifierExpression>("dot"),
|
||||||
std::move(params));
|
std::move(params));
|
||||||
|
|
||||||
|
ASSERT_TRUE(td().DetermineResultType(&call)) << td().error();
|
||||||
|
|
||||||
gen().increment_indent();
|
gen().increment_indent();
|
||||||
ASSERT_TRUE(gen().EmitExpression(pre(), out(), &call)) << gen().error();
|
ASSERT_TRUE(gen().EmitExpression(pre(), out(), &call)) << gen().error();
|
||||||
EXPECT_EQ(result(), " dot(param1, param2)");
|
EXPECT_EQ(result(), " dot(param1, param2)");
|
||||||
|
@ -14,7 +14,6 @@
|
|||||||
|
|
||||||
#include "src/writer/msl/generator_impl.h"
|
#include "src/writer/msl/generator_impl.h"
|
||||||
|
|
||||||
#include "spirv/unified1/GLSL.std.450.h"
|
|
||||||
#include "src/ast/array_accessor_expression.h"
|
#include "src/ast/array_accessor_expression.h"
|
||||||
#include "src/ast/as_expression.h"
|
#include "src/ast/as_expression.h"
|
||||||
#include "src/ast/assignment_statement.h"
|
#include "src/ast/assignment_statement.h"
|
||||||
@ -33,7 +32,6 @@
|
|||||||
#include "src/ast/function.h"
|
#include "src/ast/function.h"
|
||||||
#include "src/ast/identifier_expression.h"
|
#include "src/ast/identifier_expression.h"
|
||||||
#include "src/ast/if_statement.h"
|
#include "src/ast/if_statement.h"
|
||||||
#include "src/ast/intrinsic.h"
|
|
||||||
#include "src/ast/location_decoration.h"
|
#include "src/ast/location_decoration.h"
|
||||||
#include "src/ast/loop_statement.h"
|
#include "src/ast/loop_statement.h"
|
||||||
#include "src/ast/member_accessor_expression.h"
|
#include "src/ast/member_accessor_expression.h"
|
||||||
@ -409,38 +407,44 @@ std::string GeneratorImpl::current_ep_var_name(VarType type) {
|
|||||||
return name;
|
return name;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string GeneratorImpl::generate_intrinsic_name(const std::string& name) {
|
std::string GeneratorImpl::generate_intrinsic_name(ast::Intrinsic intrinsic) {
|
||||||
if (name == "any") {
|
if (intrinsic == ast::Intrinsic::kAny) {
|
||||||
return "any";
|
return "any";
|
||||||
}
|
}
|
||||||
if (name == "all") {
|
if (intrinsic == ast::Intrinsic::kAll) {
|
||||||
return "all";
|
return "all";
|
||||||
}
|
}
|
||||||
if (name == "dot") {
|
if (intrinsic == ast::Intrinsic::kDot) {
|
||||||
return "dot";
|
return "dot";
|
||||||
}
|
}
|
||||||
if (name == "is_finite") {
|
if (intrinsic == ast::Intrinsic::kIsFinite) {
|
||||||
return "isfinite";
|
return "isfinite";
|
||||||
}
|
}
|
||||||
if (name == "is_inf") {
|
if (intrinsic == ast::Intrinsic::kIsInf) {
|
||||||
return "isinf";
|
return "isinf";
|
||||||
}
|
}
|
||||||
if (name == "is_nan") {
|
if (intrinsic == ast::Intrinsic::kIsNan) {
|
||||||
return "isnan";
|
return "isnan";
|
||||||
}
|
}
|
||||||
if (name == "is_normal") {
|
if (intrinsic == ast::Intrinsic::kIsNormal) {
|
||||||
return "isnormal";
|
return "isnormal";
|
||||||
}
|
}
|
||||||
if (name == "select") {
|
if (intrinsic == ast::Intrinsic::kSelect) {
|
||||||
return "select";
|
return "select";
|
||||||
}
|
}
|
||||||
if (name == "dpdy" || name == "dpdy_fine" || name == "dpdy_coarse") {
|
if (intrinsic == ast::Intrinsic::kDpdy ||
|
||||||
|
intrinsic == ast::Intrinsic::kDpdyFine ||
|
||||||
|
intrinsic == ast::Intrinsic::kDpdyCoarse) {
|
||||||
return "dfdy";
|
return "dfdy";
|
||||||
}
|
}
|
||||||
if (name == "dpdx" || name == "dpdx_fine" || name == "dpdx_coarse") {
|
if (intrinsic == ast::Intrinsic::kDpdx ||
|
||||||
|
intrinsic == ast::Intrinsic::kDpdxFine ||
|
||||||
|
intrinsic == ast::Intrinsic::kDpdxCoarse) {
|
||||||
return "dfdx";
|
return "dfdx";
|
||||||
}
|
}
|
||||||
if (name == "fwidth" || name == "fwidth_fine" || name == "fwidth_coarse") {
|
if (intrinsic == ast::Intrinsic::kFwidth ||
|
||||||
|
intrinsic == ast::Intrinsic::kFwidthFine ||
|
||||||
|
intrinsic == ast::Intrinsic::kFwidthCoarse) {
|
||||||
return "fwidth";
|
return "fwidth";
|
||||||
}
|
}
|
||||||
return "";
|
return "";
|
||||||
@ -453,9 +457,9 @@ bool GeneratorImpl::EmitCall(ast::CallExpression* expr) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
auto* ident = expr->func()->AsIdentifier();
|
auto* ident = expr->func()->AsIdentifier();
|
||||||
if (!ident->has_path() && ast::intrinsic::IsIntrinsic(ident->name())) {
|
if (ident->IsIntrinsic()) {
|
||||||
const auto& params = expr->params();
|
const auto& params = expr->params();
|
||||||
if (ident->name() == "outer_product") {
|
if (ident->intrinsic() == ast::Intrinsic::kOuterProduct) {
|
||||||
error_ = "outer_product not supported yet";
|
error_ = "outer_product not supported yet";
|
||||||
return false;
|
return false;
|
||||||
// TODO(dsinclair): This gets tricky. We need to generate two variables to
|
// TODO(dsinclair): This gets tricky. We need to generate two variables to
|
||||||
@ -508,11 +512,15 @@ bool GeneratorImpl::EmitCall(ast::CallExpression* expr) {
|
|||||||
|
|
||||||
// out_ << ")";
|
// out_ << ")";
|
||||||
} else {
|
} else {
|
||||||
auto name = generate_intrinsic_name(ident->name());
|
auto name = generate_intrinsic_name(ident->intrinsic());
|
||||||
if (name.empty()) {
|
if (name.empty()) {
|
||||||
error_ = "unable to determine intrinsic name for intrinsic: " +
|
if (ast::intrinsic::IsTextureIntrinsic(ident->intrinsic())) {
|
||||||
ident->name();
|
error_ = "Textures not implemented yet";
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
if (!EmitBuiltinName(ident)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
make_indent();
|
make_indent();
|
||||||
@ -535,191 +543,69 @@ bool GeneratorImpl::EmitCall(ast::CallExpression* expr) {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!ident->has_path()) {
|
auto name = ident->name();
|
||||||
auto name = ident->name();
|
auto it = ep_func_name_remapped_.find(current_ep_name_ + "_" + name);
|
||||||
auto it = ep_func_name_remapped_.find(current_ep_name_ + "_" + name);
|
if (it != ep_func_name_remapped_.end()) {
|
||||||
if (it != ep_func_name_remapped_.end()) {
|
name = it->second;
|
||||||
name = it->second;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto* func = module_->FindFunctionByName(ident->name());
|
|
||||||
if (func == nullptr) {
|
|
||||||
error_ = "Unable to find function: " + name;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
out_ << name << "(";
|
|
||||||
|
|
||||||
bool first = true;
|
|
||||||
if (has_referenced_in_var_needing_struct(func)) {
|
|
||||||
auto var_name = current_ep_var_name(VarType::kIn);
|
|
||||||
if (!var_name.empty()) {
|
|
||||||
out_ << var_name;
|
|
||||||
first = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (has_referenced_out_var_needing_struct(func)) {
|
|
||||||
auto var_name = current_ep_var_name(VarType::kOut);
|
|
||||||
if (!var_name.empty()) {
|
|
||||||
if (!first) {
|
|
||||||
out_ << ", ";
|
|
||||||
}
|
|
||||||
first = false;
|
|
||||||
out_ << var_name;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (const auto& data : func->referenced_builtin_variables()) {
|
|
||||||
auto* var = data.first;
|
|
||||||
if (var->storage_class() != ast::StorageClass::kInput) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (!first) {
|
|
||||||
out_ << ", ";
|
|
||||||
}
|
|
||||||
first = false;
|
|
||||||
out_ << var->name();
|
|
||||||
}
|
|
||||||
|
|
||||||
for (const auto& data : func->referenced_uniform_variables()) {
|
|
||||||
auto* var = data.first;
|
|
||||||
if (!first) {
|
|
||||||
out_ << ", ";
|
|
||||||
}
|
|
||||||
first = false;
|
|
||||||
out_ << var->name();
|
|
||||||
}
|
|
||||||
|
|
||||||
for (const auto& data : func->referenced_storagebuffer_variables()) {
|
|
||||||
auto* var = data.first;
|
|
||||||
if (!first) {
|
|
||||||
out_ << ", ";
|
|
||||||
}
|
|
||||||
first = false;
|
|
||||||
out_ << var->name();
|
|
||||||
}
|
|
||||||
|
|
||||||
const auto& params = expr->params();
|
|
||||||
for (const auto& param : params) {
|
|
||||||
if (!first) {
|
|
||||||
out_ << ", ";
|
|
||||||
}
|
|
||||||
first = false;
|
|
||||||
|
|
||||||
if (!EmitExpression(param.get())) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
out_ << ")";
|
|
||||||
} else {
|
|
||||||
return EmitImportFunction(expr);
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool GeneratorImpl::EmitImportFunction(ast::CallExpression* expr) {
|
|
||||||
auto* ident = expr->func()->AsIdentifier();
|
|
||||||
|
|
||||||
auto* imp = module_->FindImportByName(ident->path());
|
|
||||||
if (imp == nullptr) {
|
|
||||||
error_ = "unable to find import for " + ident->path();
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
auto id = imp->GetIdForMethod(ident->name());
|
|
||||||
if (id == 0) {
|
|
||||||
error_ = "unable to lookup: " + ident->name() + " in " + ident->path();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
out_ << "metal::";
|
auto* func = module_->FindFunctionByName(ident->name());
|
||||||
switch (id) {
|
if (func == nullptr) {
|
||||||
case GLSLstd450Acos:
|
error_ = "Unable to find function: " + name;
|
||||||
case GLSLstd450Acosh:
|
return false;
|
||||||
case GLSLstd450Asin:
|
|
||||||
case GLSLstd450Asinh:
|
|
||||||
case GLSLstd450Atan:
|
|
||||||
case GLSLstd450Atan2:
|
|
||||||
case GLSLstd450Atanh:
|
|
||||||
case GLSLstd450Ceil:
|
|
||||||
case GLSLstd450Cos:
|
|
||||||
case GLSLstd450Cosh:
|
|
||||||
case GLSLstd450Cross:
|
|
||||||
case GLSLstd450Determinant:
|
|
||||||
case GLSLstd450Distance:
|
|
||||||
case GLSLstd450Exp:
|
|
||||||
case GLSLstd450Exp2:
|
|
||||||
case GLSLstd450FAbs:
|
|
||||||
case GLSLstd450FaceForward:
|
|
||||||
case GLSLstd450Floor:
|
|
||||||
case GLSLstd450Fma:
|
|
||||||
case GLSLstd450Fract:
|
|
||||||
case GLSLstd450Length:
|
|
||||||
case GLSLstd450Log:
|
|
||||||
case GLSLstd450Log2:
|
|
||||||
case GLSLstd450Normalize:
|
|
||||||
case GLSLstd450Pow:
|
|
||||||
case GLSLstd450Reflect:
|
|
||||||
case GLSLstd450Round:
|
|
||||||
case GLSLstd450Sin:
|
|
||||||
case GLSLstd450Sinh:
|
|
||||||
case GLSLstd450SmoothStep:
|
|
||||||
case GLSLstd450Sqrt:
|
|
||||||
case GLSLstd450Step:
|
|
||||||
case GLSLstd450Tan:
|
|
||||||
case GLSLstd450Tanh:
|
|
||||||
case GLSLstd450Trunc:
|
|
||||||
out_ << ident->name();
|
|
||||||
break;
|
|
||||||
case GLSLstd450InverseSqrt:
|
|
||||||
out_ << "rsqrt";
|
|
||||||
break;
|
|
||||||
case GLSLstd450FMax:
|
|
||||||
case GLSLstd450NMax:
|
|
||||||
out_ << "fmax";
|
|
||||||
break;
|
|
||||||
case GLSLstd450FMin:
|
|
||||||
case GLSLstd450NMin:
|
|
||||||
out_ << "fmin";
|
|
||||||
break;
|
|
||||||
case GLSLstd450FMix:
|
|
||||||
out_ << "mix";
|
|
||||||
break;
|
|
||||||
case GLSLstd450FSign:
|
|
||||||
out_ << "sign";
|
|
||||||
break;
|
|
||||||
case GLSLstd450SAbs:
|
|
||||||
out_ << "abs";
|
|
||||||
break;
|
|
||||||
case GLSLstd450SMax:
|
|
||||||
case GLSLstd450UMax:
|
|
||||||
out_ << "max";
|
|
||||||
break;
|
|
||||||
case GLSLstd450SMin:
|
|
||||||
case GLSLstd450UMin:
|
|
||||||
out_ << "min";
|
|
||||||
break;
|
|
||||||
case GLSLstd450FClamp:
|
|
||||||
case GLSLstd450SClamp:
|
|
||||||
case GLSLstd450NClamp:
|
|
||||||
case GLSLstd450UClamp:
|
|
||||||
out_ << "clamp";
|
|
||||||
break;
|
|
||||||
// TODO(dsinclair): Determine mappings for the following
|
|
||||||
case GLSLstd450Degrees:
|
|
||||||
case GLSLstd450FindILsb:
|
|
||||||
case GLSLstd450FindUMsb:
|
|
||||||
case GLSLstd450FindSMsb:
|
|
||||||
case GLSLstd450InterpolateAtCentroid:
|
|
||||||
case GLSLstd450MatrixInverse:
|
|
||||||
case GLSLstd450Radians:
|
|
||||||
case GLSLstd450RoundEven:
|
|
||||||
case GLSLstd450SSign:
|
|
||||||
error_ = "Unknown import method: " + ident->name();
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
out_ << "(";
|
out_ << name << "(";
|
||||||
|
|
||||||
bool first = true;
|
bool first = true;
|
||||||
|
if (has_referenced_in_var_needing_struct(func)) {
|
||||||
|
auto var_name = current_ep_var_name(VarType::kIn);
|
||||||
|
if (!var_name.empty()) {
|
||||||
|
out_ << var_name;
|
||||||
|
first = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (has_referenced_out_var_needing_struct(func)) {
|
||||||
|
auto var_name = current_ep_var_name(VarType::kOut);
|
||||||
|
if (!var_name.empty()) {
|
||||||
|
if (!first) {
|
||||||
|
out_ << ", ";
|
||||||
|
}
|
||||||
|
first = false;
|
||||||
|
out_ << var_name;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const auto& data : func->referenced_builtin_variables()) {
|
||||||
|
auto* var = data.first;
|
||||||
|
if (var->storage_class() != ast::StorageClass::kInput) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (!first) {
|
||||||
|
out_ << ", ";
|
||||||
|
}
|
||||||
|
first = false;
|
||||||
|
out_ << var->name();
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const auto& data : func->referenced_uniform_variables()) {
|
||||||
|
auto* var = data.first;
|
||||||
|
if (!first) {
|
||||||
|
out_ << ", ";
|
||||||
|
}
|
||||||
|
first = false;
|
||||||
|
out_ << var->name();
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const auto& data : func->referenced_storagebuffer_variables()) {
|
||||||
|
auto* var = data.first;
|
||||||
|
if (!first) {
|
||||||
|
out_ << ", ";
|
||||||
|
}
|
||||||
|
first = false;
|
||||||
|
out_ << var->name();
|
||||||
|
}
|
||||||
|
|
||||||
const auto& params = expr->params();
|
const auto& params = expr->params();
|
||||||
for (const auto& param : params) {
|
for (const auto& param : params) {
|
||||||
if (!first) {
|
if (!first) {
|
||||||
@ -731,11 +617,89 @@ bool GeneratorImpl::EmitImportFunction(ast::CallExpression* expr) {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
out_ << ")";
|
out_ << ")";
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool GeneratorImpl::EmitBuiltinName(ast::IdentifierExpression* ident) {
|
||||||
|
out_ << "metal::";
|
||||||
|
switch (ident->intrinsic()) {
|
||||||
|
case ast::Intrinsic::kAcos:
|
||||||
|
case ast::Intrinsic::kAsin:
|
||||||
|
case ast::Intrinsic::kAtan:
|
||||||
|
case ast::Intrinsic::kAtan2:
|
||||||
|
case ast::Intrinsic::kCeil:
|
||||||
|
case ast::Intrinsic::kCos:
|
||||||
|
case ast::Intrinsic::kCosh:
|
||||||
|
case ast::Intrinsic::kCross:
|
||||||
|
case ast::Intrinsic::kDeterminant:
|
||||||
|
case ast::Intrinsic::kDistance:
|
||||||
|
case ast::Intrinsic::kExp:
|
||||||
|
case ast::Intrinsic::kExp2:
|
||||||
|
case ast::Intrinsic::kFloor:
|
||||||
|
case ast::Intrinsic::kFma:
|
||||||
|
case ast::Intrinsic::kFract:
|
||||||
|
case ast::Intrinsic::kLength:
|
||||||
|
case ast::Intrinsic::kLog:
|
||||||
|
case ast::Intrinsic::kLog2:
|
||||||
|
case ast::Intrinsic::kMix:
|
||||||
|
case ast::Intrinsic::kNormalize:
|
||||||
|
case ast::Intrinsic::kPow:
|
||||||
|
case ast::Intrinsic::kReflect:
|
||||||
|
case ast::Intrinsic::kRound:
|
||||||
|
case ast::Intrinsic::kSin:
|
||||||
|
case ast::Intrinsic::kSinh:
|
||||||
|
case ast::Intrinsic::kSqrt:
|
||||||
|
case ast::Intrinsic::kStep:
|
||||||
|
case ast::Intrinsic::kTan:
|
||||||
|
case ast::Intrinsic::kTanh:
|
||||||
|
case ast::Intrinsic::kTrunc:
|
||||||
|
case ast::Intrinsic::kSign:
|
||||||
|
case ast::Intrinsic::kClamp:
|
||||||
|
out_ << ident->name();
|
||||||
|
break;
|
||||||
|
case ast::Intrinsic::kAbs:
|
||||||
|
if (ident->result_type()->IsF32()) {
|
||||||
|
out_ << "fabs";
|
||||||
|
} else if (ident->result_type()->IsU32() ||
|
||||||
|
ident->result_type()->IsI32()) {
|
||||||
|
out_ << "abs";
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case ast::Intrinsic::kMax:
|
||||||
|
if (ident->result_type()->IsF32()) {
|
||||||
|
out_ << "fmax";
|
||||||
|
} else if (ident->result_type()->IsU32() ||
|
||||||
|
ident->result_type()->IsI32()) {
|
||||||
|
out_ << "max";
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case ast::Intrinsic::kMin:
|
||||||
|
if (ident->result_type()->IsF32()) {
|
||||||
|
out_ << "fmin";
|
||||||
|
} else if (ident->result_type()->IsU32() ||
|
||||||
|
ident->result_type()->IsI32()) {
|
||||||
|
out_ << "min";
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case ast::Intrinsic::kFaceForward:
|
||||||
|
out_ << "faceforward";
|
||||||
|
break;
|
||||||
|
case ast::Intrinsic::kSmoothStep:
|
||||||
|
out_ << "smoothstep";
|
||||||
|
break;
|
||||||
|
case ast::Intrinsic::kInverseSqrt:
|
||||||
|
out_ << "rsqrt";
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
error_ = "Unknown import method: " + ident->name();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
bool GeneratorImpl::EmitCase(ast::CaseStatement* stmt) {
|
bool GeneratorImpl::EmitCase(ast::CaseStatement* stmt) {
|
||||||
make_indent();
|
make_indent();
|
||||||
|
|
||||||
@ -1402,12 +1366,6 @@ bool GeneratorImpl::global_is_in_struct(ast::Variable* var) const {
|
|||||||
|
|
||||||
bool GeneratorImpl::EmitIdentifier(ast::IdentifierExpression* expr) {
|
bool GeneratorImpl::EmitIdentifier(ast::IdentifierExpression* expr) {
|
||||||
auto* ident = expr->AsIdentifier();
|
auto* ident = expr->AsIdentifier();
|
||||||
if (ident->has_path()) {
|
|
||||||
// TODO(dsinclair): Handle identifier with path
|
|
||||||
error_ = "Identifier paths not handled yet.";
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
ast::Variable* var = nullptr;
|
ast::Variable* var = nullptr;
|
||||||
if (global_variables_.get(ident->name(), &var)) {
|
if (global_variables_.get(ident->name(), &var)) {
|
||||||
if (global_is_in_struct(var)) {
|
if (global_is_in_struct(var)) {
|
||||||
|
@ -19,6 +19,7 @@
|
|||||||
#include <string>
|
#include <string>
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
|
|
||||||
|
#include "src/ast/intrinsic.h"
|
||||||
#include "src/ast/literal.h"
|
#include "src/ast/literal.h"
|
||||||
#include "src/ast/module.h"
|
#include "src/ast/module.h"
|
||||||
#include "src/ast/scalar_constructor_expression.h"
|
#include "src/ast/scalar_constructor_expression.h"
|
||||||
@ -150,10 +151,10 @@ class GeneratorImpl : public TextGenerator {
|
|||||||
/// @param stmt the statement to emit
|
/// @param stmt the statement to emit
|
||||||
/// @returns true if the statement was successfully emitted
|
/// @returns true if the statement was successfully emitted
|
||||||
bool EmitIf(ast::IfStatement* stmt);
|
bool EmitIf(ast::IfStatement* stmt);
|
||||||
/// Handles genreating an import expression
|
/// Handles generating a builtin name
|
||||||
/// @param expr the expression
|
/// @param ident the identifier to build the name from
|
||||||
/// @returns true if the expression was successfully emitted.
|
/// @returns true if the name was successfully emitted.
|
||||||
bool EmitImportFunction(ast::CallExpression* expr);
|
bool EmitBuiltinName(ast::IdentifierExpression* ident);
|
||||||
/// Handles a literal
|
/// Handles a literal
|
||||||
/// @param lit the literal to emit
|
/// @param lit the literal to emit
|
||||||
/// @returns true if the literal was successfully emitted
|
/// @returns true if the literal was successfully emitted
|
||||||
@ -230,9 +231,9 @@ class GeneratorImpl : public TextGenerator {
|
|||||||
/// @returns the name
|
/// @returns the name
|
||||||
std::string generate_name(const std::string& prefix);
|
std::string generate_name(const std::string& prefix);
|
||||||
/// Generates an intrinsic name from the given name
|
/// Generates an intrinsic name from the given name
|
||||||
/// @param name the name to convert to an intrinsic
|
/// @param intrinsic the intrinsic to convert to an method name
|
||||||
/// @returns the intrinsic name or blank on error
|
/// @returns the intrinsic name or blank on error
|
||||||
std::string generate_intrinsic_name(const std::string& name);
|
std::string generate_intrinsic_name(ast::Intrinsic intrinsic);
|
||||||
|
|
||||||
/// Checks if the global variable is in an input or output struct
|
/// Checks if the global variable is in an input or output struct
|
||||||
/// @param var the variable to check
|
/// @param var the variable to check
|
||||||
|
@ -24,16 +24,7 @@ namespace {
|
|||||||
|
|
||||||
using MslGeneratorImplTest = testing::Test;
|
using MslGeneratorImplTest = testing::Test;
|
||||||
|
|
||||||
TEST_F(MslGeneratorImplTest, DISABLED_EmitExpression_Identifier) {
|
TEST_F(MslGeneratorImplTest, EmitIdentifierExpression) {
|
||||||
ast::IdentifierExpression i(std::vector<std::string>{"std", "glsl"});
|
|
||||||
|
|
||||||
ast::Module m;
|
|
||||||
GeneratorImpl g(&m);
|
|
||||||
ASSERT_TRUE(g.EmitExpression(&i)) << g.error();
|
|
||||||
EXPECT_EQ(g.result(), "std::glsl");
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(MslGeneratorImplTest, EmitIdentifierExpression_Single) {
|
|
||||||
ast::IdentifierExpression i("foo");
|
ast::IdentifierExpression i("foo");
|
||||||
|
|
||||||
ast::Module m;
|
ast::Module m;
|
||||||
@ -51,16 +42,6 @@ TEST_F(MslGeneratorImplTest, EmitIdentifierExpression_Single_WithCollision) {
|
|||||||
EXPECT_EQ(g.result(), "virtual_tint_0");
|
EXPECT_EQ(g.result(), "virtual_tint_0");
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO(dsinclair): Handle import names
|
|
||||||
TEST_F(MslGeneratorImplTest, DISABLED_EmitIdentifierExpression_MultipleNames) {
|
|
||||||
ast::IdentifierExpression i({"std", "glsl", "init"});
|
|
||||||
|
|
||||||
ast::Module m;
|
|
||||||
GeneratorImpl g(&m);
|
|
||||||
ASSERT_TRUE(g.EmitExpression(&i)) << g.error();
|
|
||||||
EXPECT_EQ(g.result(), "std::glsl::init");
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
} // namespace msl
|
} // namespace msl
|
||||||
} // namespace writer
|
} // namespace writer
|
||||||
|
@ -57,46 +57,41 @@ TEST_P(MslImportData_SingleParamTest, FloatScalar) {
|
|||||||
params.push_back(std::make_unique<ast::ScalarConstructorExpression>(
|
params.push_back(std::make_unique<ast::ScalarConstructorExpression>(
|
||||||
std::make_unique<ast::FloatLiteral>(&f32, 1.f)));
|
std::make_unique<ast::FloatLiteral>(&f32, 1.f)));
|
||||||
|
|
||||||
ast::CallExpression expr(std::make_unique<ast::IdentifierExpression>(
|
auto ident = std::make_unique<ast::IdentifierExpression>(param.name);
|
||||||
std::vector<std::string>{"std", param.name}),
|
auto* ident_ptr = ident.get();
|
||||||
std::move(params));
|
|
||||||
|
ast::CallExpression call(std::move(ident), std::move(params));
|
||||||
|
|
||||||
Context ctx;
|
Context ctx;
|
||||||
ast::Module mod;
|
ast::Module mod;
|
||||||
TypeDeterminer td(&ctx, &mod);
|
TypeDeterminer td(&ctx, &mod);
|
||||||
mod.AddImport(std::make_unique<ast::Import>("GLSL.std.450", "std"));
|
|
||||||
|
|
||||||
ASSERT_TRUE(td.DetermineResultType(&expr)) << td.error();
|
// The call type determination will set the intrinsic data for the ident
|
||||||
|
ASSERT_TRUE(td.DetermineResultType(&call)) << td.error();
|
||||||
|
|
||||||
GeneratorImpl g(&mod);
|
GeneratorImpl g(&mod);
|
||||||
ASSERT_TRUE(g.EmitImportFunction(&expr)) << g.error();
|
ASSERT_TRUE(g.EmitBuiltinName(ident_ptr)) << g.error();
|
||||||
EXPECT_EQ(g.result(),
|
EXPECT_EQ(g.result(), std::string("metal::") + param.msl_name);
|
||||||
std::string("metal::") + param.msl_name + "(1.00000000f)");
|
|
||||||
}
|
}
|
||||||
INSTANTIATE_TEST_SUITE_P(MslGeneratorImplTest,
|
INSTANTIATE_TEST_SUITE_P(MslGeneratorImplTest,
|
||||||
MslImportData_SingleParamTest,
|
MslImportData_SingleParamTest,
|
||||||
testing::Values(MslImportData{"acos", "acos"},
|
testing::Values(MslImportData{"abs", "fabs"},
|
||||||
MslImportData{"acosh", "acosh"},
|
MslImportData{"acos", "acos"},
|
||||||
MslImportData{"asin", "asin"},
|
MslImportData{"asin", "asin"},
|
||||||
MslImportData{"asinh", "asinh"},
|
|
||||||
MslImportData{"atan", "atan"},
|
MslImportData{"atan", "atan"},
|
||||||
MslImportData{"atanh", "atanh"},
|
MslImportData{"ceil", "ceil"},
|
||||||
MslImportData{"cos", "cos"},
|
MslImportData{"cos", "cos"},
|
||||||
MslImportData{"cosh", "cosh"},
|
MslImportData{"cosh", "cosh"},
|
||||||
MslImportData{"ceil", "ceil"},
|
|
||||||
MslImportData{"exp", "exp"},
|
MslImportData{"exp", "exp"},
|
||||||
MslImportData{"exp2", "exp2"},
|
MslImportData{"exp2", "exp2"},
|
||||||
MslImportData{"fabs", "fabs"},
|
|
||||||
MslImportData{"floor", "floor"},
|
MslImportData{"floor", "floor"},
|
||||||
MslImportData{"fract", "fract"},
|
MslImportData{"fract", "fract"},
|
||||||
MslImportData{"inversesqrt", "rsqrt"},
|
MslImportData{"inverseSqrt", "rsqrt"},
|
||||||
MslImportData{"length", "length"},
|
MslImportData{"length", "length"},
|
||||||
MslImportData{"log", "log"},
|
MslImportData{"log", "log"},
|
||||||
MslImportData{"log2", "log2"},
|
MslImportData{"log2", "log2"},
|
||||||
MslImportData{"normalize",
|
|
||||||
"normalize"},
|
|
||||||
MslImportData{"round", "round"},
|
MslImportData{"round", "round"},
|
||||||
MslImportData{"fsign", "sign"},
|
MslImportData{"sign", "sign"},
|
||||||
MslImportData{"sin", "sin"},
|
MslImportData{"sin", "sin"},
|
||||||
MslImportData{"sinh", "sinh"},
|
MslImportData{"sinh", "sinh"},
|
||||||
MslImportData{"sqrt", "sqrt"},
|
MslImportData{"sqrt", "sqrt"},
|
||||||
@ -111,19 +106,17 @@ TEST_F(MslGeneratorImplTest, MslImportData_SingleParamTest_IntScalar) {
|
|||||||
params.push_back(std::make_unique<ast::ScalarConstructorExpression>(
|
params.push_back(std::make_unique<ast::ScalarConstructorExpression>(
|
||||||
std::make_unique<ast::SintLiteral>(&i32, 1)));
|
std::make_unique<ast::SintLiteral>(&i32, 1)));
|
||||||
|
|
||||||
ast::CallExpression expr(std::make_unique<ast::IdentifierExpression>(
|
ast::CallExpression expr(std::make_unique<ast::IdentifierExpression>("abs"),
|
||||||
std::vector<std::string>{"std", "sabs"}),
|
|
||||||
std::move(params));
|
std::move(params));
|
||||||
|
|
||||||
Context ctx;
|
Context ctx;
|
||||||
ast::Module mod;
|
ast::Module mod;
|
||||||
TypeDeterminer td(&ctx, &mod);
|
TypeDeterminer td(&ctx, &mod);
|
||||||
mod.AddImport(std::make_unique<ast::Import>("GLSL.std.450", "std"));
|
|
||||||
|
|
||||||
ASSERT_TRUE(td.DetermineResultType(&expr)) << td.error();
|
ASSERT_TRUE(td.DetermineResultType(&expr)) << td.error();
|
||||||
|
|
||||||
GeneratorImpl g(&mod);
|
GeneratorImpl g(&mod);
|
||||||
ASSERT_TRUE(g.EmitImportFunction(&expr)) << g.error();
|
ASSERT_TRUE(g.EmitCall(&expr)) << g.error();
|
||||||
EXPECT_EQ(g.result(), R"(metal::abs(1))");
|
EXPECT_EQ(g.result(), R"(metal::abs(1))");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -139,19 +132,18 @@ TEST_P(MslImportData_DualParamTest, FloatScalar) {
|
|||||||
params.push_back(std::make_unique<ast::ScalarConstructorExpression>(
|
params.push_back(std::make_unique<ast::ScalarConstructorExpression>(
|
||||||
std::make_unique<ast::FloatLiteral>(&f32, 2.f)));
|
std::make_unique<ast::FloatLiteral>(&f32, 2.f)));
|
||||||
|
|
||||||
ast::CallExpression expr(std::make_unique<ast::IdentifierExpression>(
|
ast::CallExpression expr(
|
||||||
std::vector<std::string>{"std", param.name}),
|
std::make_unique<ast::IdentifierExpression>(param.name),
|
||||||
std::move(params));
|
std::move(params));
|
||||||
|
|
||||||
Context ctx;
|
Context ctx;
|
||||||
ast::Module mod;
|
ast::Module mod;
|
||||||
TypeDeterminer td(&ctx, &mod);
|
TypeDeterminer td(&ctx, &mod);
|
||||||
mod.AddImport(std::make_unique<ast::Import>("GLSL.std.450", "std"));
|
|
||||||
|
|
||||||
ASSERT_TRUE(td.DetermineResultType(&expr)) << td.error();
|
ASSERT_TRUE(td.DetermineResultType(&expr)) << td.error();
|
||||||
|
|
||||||
GeneratorImpl g(&mod);
|
GeneratorImpl g(&mod);
|
||||||
ASSERT_TRUE(g.EmitImportFunction(&expr)) << g.error();
|
ASSERT_TRUE(g.EmitCall(&expr)) << g.error();
|
||||||
EXPECT_EQ(g.result(), std::string("metal::") + param.msl_name +
|
EXPECT_EQ(g.result(), std::string("metal::") + param.msl_name +
|
||||||
"(1.00000000f, 2.00000000f)");
|
"(1.00000000f, 2.00000000f)");
|
||||||
}
|
}
|
||||||
@ -159,10 +151,8 @@ INSTANTIATE_TEST_SUITE_P(MslGeneratorImplTest,
|
|||||||
MslImportData_DualParamTest,
|
MslImportData_DualParamTest,
|
||||||
testing::Values(MslImportData{"atan2", "atan2"},
|
testing::Values(MslImportData{"atan2", "atan2"},
|
||||||
MslImportData{"distance", "distance"},
|
MslImportData{"distance", "distance"},
|
||||||
MslImportData{"fmax", "fmax"},
|
MslImportData{"max", "fmax"},
|
||||||
MslImportData{"fmin", "fmin"},
|
MslImportData{"min", "fmin"},
|
||||||
MslImportData{"nmax", "fmax"},
|
|
||||||
MslImportData{"nmin", "fmin"},
|
|
||||||
MslImportData{"pow", "pow"},
|
MslImportData{"pow", "pow"},
|
||||||
MslImportData{"reflect", "reflect"},
|
MslImportData{"reflect", "reflect"},
|
||||||
MslImportData{"step", "step"}));
|
MslImportData{"step", "step"}));
|
||||||
@ -196,19 +186,18 @@ TEST_P(MslImportData_DualParam_VectorTest, FloatVector) {
|
|||||||
params.push_back(std::make_unique<ast::TypeConstructorExpression>(
|
params.push_back(std::make_unique<ast::TypeConstructorExpression>(
|
||||||
&vec, std::move(type_params)));
|
&vec, std::move(type_params)));
|
||||||
|
|
||||||
ast::CallExpression expr(std::make_unique<ast::IdentifierExpression>(
|
ast::CallExpression expr(
|
||||||
std::vector<std::string>{"std", param.name}),
|
std::make_unique<ast::IdentifierExpression>(param.name),
|
||||||
std::move(params));
|
std::move(params));
|
||||||
|
|
||||||
Context ctx;
|
Context ctx;
|
||||||
ast::Module mod;
|
ast::Module mod;
|
||||||
TypeDeterminer td(&ctx, &mod);
|
TypeDeterminer td(&ctx, &mod);
|
||||||
mod.AddImport(std::make_unique<ast::Import>("GLSL.std.450", "std"));
|
|
||||||
|
|
||||||
ASSERT_TRUE(td.DetermineResultType(&expr)) << td.error();
|
ASSERT_TRUE(td.DetermineResultType(&expr)) << td.error();
|
||||||
|
|
||||||
GeneratorImpl g(&mod);
|
GeneratorImpl g(&mod);
|
||||||
ASSERT_TRUE(g.EmitImportFunction(&expr)) << g.error();
|
ASSERT_TRUE(g.EmitCall(&expr)) << g.error();
|
||||||
EXPECT_EQ(g.result(), std::string("metal::") + param.msl_name +
|
EXPECT_EQ(g.result(), std::string("metal::") + param.msl_name +
|
||||||
"(float3(1.00000000f, 2.00000000f, 3.00000000f), "
|
"(float3(1.00000000f, 2.00000000f, 3.00000000f), "
|
||||||
"float3(4.00000000f, 5.00000000f, 6.00000000f))");
|
"float3(4.00000000f, 5.00000000f, 6.00000000f))");
|
||||||
@ -229,27 +218,24 @@ TEST_P(MslImportData_DualParam_Int_Test, IntScalar) {
|
|||||||
params.push_back(std::make_unique<ast::ScalarConstructorExpression>(
|
params.push_back(std::make_unique<ast::ScalarConstructorExpression>(
|
||||||
std::make_unique<ast::SintLiteral>(&i32, 2)));
|
std::make_unique<ast::SintLiteral>(&i32, 2)));
|
||||||
|
|
||||||
ast::CallExpression expr(std::make_unique<ast::IdentifierExpression>(
|
ast::CallExpression expr(
|
||||||
std::vector<std::string>{"std", param.name}),
|
std::make_unique<ast::IdentifierExpression>(param.name),
|
||||||
std::move(params));
|
std::move(params));
|
||||||
|
|
||||||
Context ctx;
|
Context ctx;
|
||||||
ast::Module mod;
|
ast::Module mod;
|
||||||
TypeDeterminer td(&ctx, &mod);
|
TypeDeterminer td(&ctx, &mod);
|
||||||
mod.AddImport(std::make_unique<ast::Import>("GLSL.std.450", "std"));
|
|
||||||
|
|
||||||
ASSERT_TRUE(td.DetermineResultType(&expr)) << td.error();
|
ASSERT_TRUE(td.DetermineResultType(&expr)) << td.error();
|
||||||
|
|
||||||
GeneratorImpl g(&mod);
|
GeneratorImpl g(&mod);
|
||||||
ASSERT_TRUE(g.EmitImportFunction(&expr)) << g.error();
|
ASSERT_TRUE(g.EmitCall(&expr)) << g.error();
|
||||||
EXPECT_EQ(g.result(), std::string("metal::") + param.msl_name + "(1, 2)");
|
EXPECT_EQ(g.result(), std::string("metal::") + param.msl_name + "(1, 2)");
|
||||||
}
|
}
|
||||||
INSTANTIATE_TEST_SUITE_P(MslGeneratorImplTest,
|
INSTANTIATE_TEST_SUITE_P(MslGeneratorImplTest,
|
||||||
MslImportData_DualParam_Int_Test,
|
MslImportData_DualParam_Int_Test,
|
||||||
testing::Values(MslImportData{"smax", "max"},
|
testing::Values(MslImportData{"max", "max"},
|
||||||
MslImportData{"smin", "min"},
|
MslImportData{"min", "min"}));
|
||||||
MslImportData{"umax", "max"},
|
|
||||||
MslImportData{"umin", "min"}));
|
|
||||||
|
|
||||||
using MslImportData_TripleParamTest = testing::TestWithParam<MslImportData>;
|
using MslImportData_TripleParamTest = testing::TestWithParam<MslImportData>;
|
||||||
TEST_P(MslImportData_TripleParamTest, FloatScalar) {
|
TEST_P(MslImportData_TripleParamTest, FloatScalar) {
|
||||||
@ -265,31 +251,29 @@ TEST_P(MslImportData_TripleParamTest, FloatScalar) {
|
|||||||
params.push_back(std::make_unique<ast::ScalarConstructorExpression>(
|
params.push_back(std::make_unique<ast::ScalarConstructorExpression>(
|
||||||
std::make_unique<ast::FloatLiteral>(&f32, 3.f)));
|
std::make_unique<ast::FloatLiteral>(&f32, 3.f)));
|
||||||
|
|
||||||
ast::CallExpression expr(std::make_unique<ast::IdentifierExpression>(
|
ast::CallExpression expr(
|
||||||
std::vector<std::string>{"std", param.name}),
|
std::make_unique<ast::IdentifierExpression>(param.name),
|
||||||
std::move(params));
|
std::move(params));
|
||||||
|
|
||||||
Context ctx;
|
Context ctx;
|
||||||
ast::Module mod;
|
ast::Module mod;
|
||||||
TypeDeterminer td(&ctx, &mod);
|
TypeDeterminer td(&ctx, &mod);
|
||||||
mod.AddImport(std::make_unique<ast::Import>("GLSL.std.450", "std"));
|
|
||||||
|
|
||||||
ASSERT_TRUE(td.DetermineResultType(&expr)) << td.error();
|
ASSERT_TRUE(td.DetermineResultType(&expr)) << td.error();
|
||||||
|
|
||||||
GeneratorImpl g(&mod);
|
GeneratorImpl g(&mod);
|
||||||
ASSERT_TRUE(g.EmitImportFunction(&expr)) << g.error();
|
ASSERT_TRUE(g.EmitCall(&expr)) << g.error();
|
||||||
EXPECT_EQ(g.result(), std::string("metal::") + param.msl_name +
|
EXPECT_EQ(g.result(), std::string("metal::") + param.msl_name +
|
||||||
"(1.00000000f, 2.00000000f, 3.00000000f)");
|
"(1.00000000f, 2.00000000f, 3.00000000f)");
|
||||||
}
|
}
|
||||||
INSTANTIATE_TEST_SUITE_P(
|
INSTANTIATE_TEST_SUITE_P(
|
||||||
MslGeneratorImplTest,
|
MslGeneratorImplTest,
|
||||||
MslImportData_TripleParamTest,
|
MslImportData_TripleParamTest,
|
||||||
testing::Values(MslImportData{"faceforward", "faceforward"},
|
testing::Values(MslImportData{"faceForward", "faceforward"},
|
||||||
MslImportData{"fma", "fma"},
|
MslImportData{"fma", "fma"},
|
||||||
MslImportData{"fclamp", "clamp"},
|
MslImportData{"mix", "mix"},
|
||||||
MslImportData{"fmix", "mix"},
|
MslImportData{"clamp", "clamp"},
|
||||||
MslImportData{"nclamp", "clamp"},
|
MslImportData{"smoothStep", "smoothstep"}));
|
||||||
MslImportData{"smoothstep", "smoothstep"}));
|
|
||||||
|
|
||||||
using MslImportData_TripleParam_Int_Test =
|
using MslImportData_TripleParam_Int_Test =
|
||||||
testing::TestWithParam<MslImportData>;
|
testing::TestWithParam<MslImportData>;
|
||||||
@ -306,25 +290,24 @@ TEST_P(MslImportData_TripleParam_Int_Test, IntScalar) {
|
|||||||
params.push_back(std::make_unique<ast::ScalarConstructorExpression>(
|
params.push_back(std::make_unique<ast::ScalarConstructorExpression>(
|
||||||
std::make_unique<ast::SintLiteral>(&i32, 3)));
|
std::make_unique<ast::SintLiteral>(&i32, 3)));
|
||||||
|
|
||||||
ast::CallExpression expr(std::make_unique<ast::IdentifierExpression>(
|
ast::CallExpression expr(
|
||||||
std::vector<std::string>{"std", param.name}),
|
std::make_unique<ast::IdentifierExpression>(param.name),
|
||||||
std::move(params));
|
std::move(params));
|
||||||
|
|
||||||
Context ctx;
|
Context ctx;
|
||||||
ast::Module mod;
|
ast::Module mod;
|
||||||
TypeDeterminer td(&ctx, &mod);
|
TypeDeterminer td(&ctx, &mod);
|
||||||
mod.AddImport(std::make_unique<ast::Import>("GLSL.std.450", "std"));
|
|
||||||
|
|
||||||
ASSERT_TRUE(td.DetermineResultType(&expr)) << td.error();
|
ASSERT_TRUE(td.DetermineResultType(&expr)) << td.error();
|
||||||
|
|
||||||
GeneratorImpl g(&mod);
|
GeneratorImpl g(&mod);
|
||||||
ASSERT_TRUE(g.EmitImportFunction(&expr)) << g.error();
|
ASSERT_TRUE(g.EmitCall(&expr)) << g.error();
|
||||||
EXPECT_EQ(g.result(), std::string("metal::") + param.msl_name + "(1, 2, 3)");
|
EXPECT_EQ(g.result(), std::string("metal::") + param.msl_name + "(1, 2, 3)");
|
||||||
}
|
}
|
||||||
INSTANTIATE_TEST_SUITE_P(MslGeneratorImplTest,
|
INSTANTIATE_TEST_SUITE_P(MslGeneratorImplTest,
|
||||||
MslImportData_TripleParam_Int_Test,
|
MslImportData_TripleParam_Int_Test,
|
||||||
testing::Values(MslImportData{"sclamp", "clamp"},
|
testing::Values(MslImportData{"clamp", "clamp"},
|
||||||
MslImportData{"uclamp", "clamp"}));
|
MslImportData{"clamp", "clamp"}));
|
||||||
|
|
||||||
TEST_F(MslGeneratorImplTest, MslImportData_Determinant) {
|
TEST_F(MslGeneratorImplTest, MslImportData_Determinant) {
|
||||||
ast::type::F32Type f32;
|
ast::type::F32Type f32;
|
||||||
@ -336,14 +319,13 @@ TEST_F(MslGeneratorImplTest, MslImportData_Determinant) {
|
|||||||
ast::ExpressionList params;
|
ast::ExpressionList params;
|
||||||
params.push_back(std::make_unique<ast::IdentifierExpression>("var"));
|
params.push_back(std::make_unique<ast::IdentifierExpression>("var"));
|
||||||
|
|
||||||
ast::CallExpression expr(std::make_unique<ast::IdentifierExpression>(
|
ast::CallExpression expr(
|
||||||
std::vector<std::string>{"std", "determinant"}),
|
std::make_unique<ast::IdentifierExpression>("determinant"),
|
||||||
std::move(params));
|
std::move(params));
|
||||||
|
|
||||||
Context ctx;
|
Context ctx;
|
||||||
ast::Module mod;
|
ast::Module mod;
|
||||||
mod.AddGlobalVariable(std::move(var));
|
mod.AddGlobalVariable(std::move(var));
|
||||||
mod.AddImport(std::make_unique<ast::Import>("GLSL.std.450", "std"));
|
|
||||||
|
|
||||||
TypeDeterminer td(&ctx, &mod);
|
TypeDeterminer td(&ctx, &mod);
|
||||||
// Register the global
|
// Register the global
|
||||||
@ -351,7 +333,7 @@ TEST_F(MslGeneratorImplTest, MslImportData_Determinant) {
|
|||||||
ASSERT_TRUE(td.DetermineResultType(&expr)) << td.error();
|
ASSERT_TRUE(td.DetermineResultType(&expr)) << td.error();
|
||||||
|
|
||||||
GeneratorImpl g(&mod);
|
GeneratorImpl g(&mod);
|
||||||
ASSERT_TRUE(g.EmitImportFunction(&expr)) << g.error();
|
ASSERT_TRUE(g.EmitCall(&expr)) << g.error();
|
||||||
EXPECT_EQ(g.result(), std::string("metal::determinant(var)"));
|
EXPECT_EQ(g.result(), std::string("metal::determinant(var)"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -30,11 +30,11 @@ namespace {
|
|||||||
using MslGeneratorImplTest = testing::Test;
|
using MslGeneratorImplTest = testing::Test;
|
||||||
|
|
||||||
struct IntrinsicData {
|
struct IntrinsicData {
|
||||||
const char* name;
|
ast::Intrinsic intrinsic;
|
||||||
const char* msl_name;
|
const char* msl_name;
|
||||||
};
|
};
|
||||||
inline std::ostream& operator<<(std::ostream& out, IntrinsicData data) {
|
inline std::ostream& operator<<(std::ostream& out, IntrinsicData data) {
|
||||||
out << data.name;
|
out << data.msl_name;
|
||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
using MslIntrinsicTest = testing::TestWithParam<IntrinsicData>;
|
using MslIntrinsicTest = testing::TestWithParam<IntrinsicData>;
|
||||||
@ -43,28 +43,28 @@ TEST_P(MslIntrinsicTest, Emit) {
|
|||||||
|
|
||||||
ast::Module m;
|
ast::Module m;
|
||||||
GeneratorImpl g(&m);
|
GeneratorImpl g(&m);
|
||||||
EXPECT_EQ(g.generate_intrinsic_name(param.name), param.msl_name);
|
EXPECT_EQ(g.generate_intrinsic_name(param.intrinsic), param.msl_name);
|
||||||
}
|
}
|
||||||
INSTANTIATE_TEST_SUITE_P(MslGeneratorImplTest,
|
INSTANTIATE_TEST_SUITE_P(
|
||||||
MslIntrinsicTest,
|
MslGeneratorImplTest,
|
||||||
testing::Values(IntrinsicData{"any", "any"},
|
MslIntrinsicTest,
|
||||||
IntrinsicData{"all", "all"},
|
testing::Values(IntrinsicData{ast::Intrinsic::kAny, "any"},
|
||||||
IntrinsicData{"dot", "dot"},
|
IntrinsicData{ast::Intrinsic::kAll, "all"},
|
||||||
IntrinsicData{"dpdx", "dfdx"},
|
IntrinsicData{ast::Intrinsic::kDot, "dot"},
|
||||||
IntrinsicData{"dpdx_coarse", "dfdx"},
|
IntrinsicData{ast::Intrinsic::kDpdx, "dfdx"},
|
||||||
IntrinsicData{"dpdx_fine", "dfdx"},
|
IntrinsicData{ast::Intrinsic::kDpdxCoarse, "dfdx"},
|
||||||
IntrinsicData{"dpdy", "dfdy"},
|
IntrinsicData{ast::Intrinsic::kDpdxFine, "dfdx"},
|
||||||
IntrinsicData{"dpdy_coarse", "dfdy"},
|
IntrinsicData{ast::Intrinsic::kDpdy, "dfdy"},
|
||||||
IntrinsicData{"dpdy_fine", "dfdy"},
|
IntrinsicData{ast::Intrinsic::kDpdyCoarse, "dfdy"},
|
||||||
IntrinsicData{"fwidth", "fwidth"},
|
IntrinsicData{ast::Intrinsic::kDpdyFine, "dfdy"},
|
||||||
IntrinsicData{"fwidth_coarse",
|
IntrinsicData{ast::Intrinsic::kFwidth, "fwidth"},
|
||||||
"fwidth"},
|
IntrinsicData{ast::Intrinsic::kFwidthCoarse, "fwidth"},
|
||||||
IntrinsicData{"fwidth_fine", "fwidth"},
|
IntrinsicData{ast::Intrinsic::kFwidthFine, "fwidth"},
|
||||||
IntrinsicData{"is_finite", "isfinite"},
|
IntrinsicData{ast::Intrinsic::kIsFinite, "isfinite"},
|
||||||
IntrinsicData{"is_inf", "isinf"},
|
IntrinsicData{ast::Intrinsic::kIsInf, "isinf"},
|
||||||
IntrinsicData{"is_nan", "isnan"},
|
IntrinsicData{ast::Intrinsic::kIsNan, "isnan"},
|
||||||
IntrinsicData{"is_normal", "isnormal"},
|
IntrinsicData{ast::Intrinsic::kIsNormal, "isnormal"},
|
||||||
IntrinsicData{"select", "select"}));
|
IntrinsicData{ast::Intrinsic::kSelect, "select"}));
|
||||||
|
|
||||||
TEST_F(MslGeneratorImplTest, DISABLED_Intrinsic_OuterProduct) {
|
TEST_F(MslGeneratorImplTest, DISABLED_Intrinsic_OuterProduct) {
|
||||||
ast::type::F32Type f32;
|
ast::type::F32Type f32;
|
||||||
@ -106,7 +106,7 @@ TEST_F(MslGeneratorImplTest, DISABLED_Intrinsic_OuterProduct) {
|
|||||||
TEST_F(MslGeneratorImplTest, Intrinsic_Bad_Name) {
|
TEST_F(MslGeneratorImplTest, Intrinsic_Bad_Name) {
|
||||||
ast::Module m;
|
ast::Module m;
|
||||||
GeneratorImpl g(&m);
|
GeneratorImpl g(&m);
|
||||||
EXPECT_EQ(g.generate_intrinsic_name("unknown name"), "");
|
EXPECT_EQ(g.generate_intrinsic_name(ast::Intrinsic::kNone), "");
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(MslGeneratorImplTest, Intrinsic_Call) {
|
TEST_F(MslGeneratorImplTest, Intrinsic_Call) {
|
||||||
@ -117,7 +117,11 @@ TEST_F(MslGeneratorImplTest, Intrinsic_Call) {
|
|||||||
ast::CallExpression call(std::make_unique<ast::IdentifierExpression>("dot"),
|
ast::CallExpression call(std::make_unique<ast::IdentifierExpression>("dot"),
|
||||||
std::move(params));
|
std::move(params));
|
||||||
|
|
||||||
|
Context ctx;
|
||||||
ast::Module m;
|
ast::Module m;
|
||||||
|
TypeDeterminer td(&ctx, &m);
|
||||||
|
ASSERT_TRUE(td.DetermineResultType(&call)) << td.error();
|
||||||
|
|
||||||
GeneratorImpl g(&m);
|
GeneratorImpl g(&m);
|
||||||
g.increment_indent();
|
g.increment_indent();
|
||||||
ASSERT_TRUE(g.EmitExpression(&call)) << g.error();
|
ASSERT_TRUE(g.EmitExpression(&call)) << g.error();
|
||||||
|
@ -17,6 +17,7 @@
|
|||||||
#include <sstream>
|
#include <sstream>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
|
|
||||||
|
#include "spirv/unified1/GLSL.std.450.h"
|
||||||
#include "spirv/unified1/spirv.h"
|
#include "spirv/unified1/spirv.h"
|
||||||
#include "src/ast/array_accessor_expression.h"
|
#include "src/ast/array_accessor_expression.h"
|
||||||
#include "src/ast/as_expression.h"
|
#include "src/ast/as_expression.h"
|
||||||
@ -68,11 +69,15 @@
|
|||||||
#include "src/ast/unary_op_expression.h"
|
#include "src/ast/unary_op_expression.h"
|
||||||
#include "src/ast/variable_decl_statement.h"
|
#include "src/ast/variable_decl_statement.h"
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
namespace tint {
|
namespace tint {
|
||||||
namespace writer {
|
namespace writer {
|
||||||
namespace spirv {
|
namespace spirv {
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
|
const char kGLSLstd450[] = "GLSL.std.450";
|
||||||
|
|
||||||
uint32_t size_of(const InstructionList& instructions) {
|
uint32_t size_of(const InstructionList& instructions) {
|
||||||
uint32_t size = 0;
|
uint32_t size = 0;
|
||||||
for (const auto& inst : instructions)
|
for (const auto& inst : instructions)
|
||||||
@ -147,6 +152,119 @@ ast::type::MatrixType* GetNestedMatrixType(ast::type::Type* type) {
|
|||||||
return type->IsMatrix() ? type->AsMatrix() : nullptr;
|
return type->IsMatrix() ? type->AsMatrix() : nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint32_t intrinsic_to_glsl_method(ast::type::Type* type,
|
||||||
|
ast::Intrinsic intrinsic) {
|
||||||
|
switch (intrinsic) {
|
||||||
|
case ast::Intrinsic::kAbs:
|
||||||
|
if (type->is_float_scalar_or_vector()) {
|
||||||
|
return GLSLstd450FAbs;
|
||||||
|
} else {
|
||||||
|
return GLSLstd450SAbs;
|
||||||
|
}
|
||||||
|
case ast::Intrinsic::kAcos:
|
||||||
|
return GLSLstd450Acos;
|
||||||
|
case ast::Intrinsic::kAsin:
|
||||||
|
return GLSLstd450Asin;
|
||||||
|
case ast::Intrinsic::kAtan:
|
||||||
|
return GLSLstd450Atan;
|
||||||
|
case ast::Intrinsic::kAtan2:
|
||||||
|
return GLSLstd450Atan2;
|
||||||
|
case ast::Intrinsic::kCeil:
|
||||||
|
return GLSLstd450Ceil;
|
||||||
|
case ast::Intrinsic::kClamp:
|
||||||
|
if (type->is_float_scalar_or_vector()) {
|
||||||
|
return GLSLstd450NClamp;
|
||||||
|
} else if (type->is_unsigned_scalar_or_vector()) {
|
||||||
|
return GLSLstd450UClamp;
|
||||||
|
} else {
|
||||||
|
return GLSLstd450SClamp;
|
||||||
|
}
|
||||||
|
case ast::Intrinsic::kCos:
|
||||||
|
return GLSLstd450Cos;
|
||||||
|
case ast::Intrinsic::kCosh:
|
||||||
|
return GLSLstd450Cosh;
|
||||||
|
case ast::Intrinsic::kCross:
|
||||||
|
return GLSLstd450Cross;
|
||||||
|
case ast::Intrinsic::kDeterminant:
|
||||||
|
return GLSLstd450Determinant;
|
||||||
|
case ast::Intrinsic::kDistance:
|
||||||
|
return GLSLstd450Distance;
|
||||||
|
case ast::Intrinsic::kExp:
|
||||||
|
return GLSLstd450Exp;
|
||||||
|
case ast::Intrinsic::kExp2:
|
||||||
|
return GLSLstd450Exp2;
|
||||||
|
case ast::Intrinsic::kFaceForward:
|
||||||
|
return GLSLstd450FaceForward;
|
||||||
|
case ast::Intrinsic::kFloor:
|
||||||
|
return GLSLstd450Floor;
|
||||||
|
case ast::Intrinsic::kFma:
|
||||||
|
return GLSLstd450Fma;
|
||||||
|
case ast::Intrinsic::kFract:
|
||||||
|
return GLSLstd450Fract;
|
||||||
|
case ast::Intrinsic::kFrexp:
|
||||||
|
return GLSLstd450Frexp;
|
||||||
|
case ast::Intrinsic::kInverseSqrt:
|
||||||
|
return GLSLstd450InverseSqrt;
|
||||||
|
case ast::Intrinsic::kLdexp:
|
||||||
|
return GLSLstd450Ldexp;
|
||||||
|
case ast::Intrinsic::kLength:
|
||||||
|
return GLSLstd450Length;
|
||||||
|
case ast::Intrinsic::kLog:
|
||||||
|
return GLSLstd450Log;
|
||||||
|
case ast::Intrinsic::kLog2:
|
||||||
|
return GLSLstd450Log2;
|
||||||
|
case ast::Intrinsic::kMax:
|
||||||
|
if (type->is_float_scalar_or_vector()) {
|
||||||
|
return GLSLstd450NMax;
|
||||||
|
} else if (type->is_unsigned_scalar_or_vector()) {
|
||||||
|
return GLSLstd450UMax;
|
||||||
|
} else {
|
||||||
|
return GLSLstd450SMax;
|
||||||
|
}
|
||||||
|
case ast::Intrinsic::kMin:
|
||||||
|
if (type->is_float_scalar_or_vector()) {
|
||||||
|
return GLSLstd450NMin;
|
||||||
|
} else if (type->is_unsigned_scalar_or_vector()) {
|
||||||
|
return GLSLstd450UMin;
|
||||||
|
} else {
|
||||||
|
return GLSLstd450SMin;
|
||||||
|
}
|
||||||
|
case ast::Intrinsic::kMix:
|
||||||
|
return GLSLstd450FMix;
|
||||||
|
case ast::Intrinsic::kModf:
|
||||||
|
return GLSLstd450Modf;
|
||||||
|
case ast::Intrinsic::kNormalize:
|
||||||
|
return GLSLstd450Normalize;
|
||||||
|
case ast::Intrinsic::kPow:
|
||||||
|
return GLSLstd450Pow;
|
||||||
|
case ast::Intrinsic::kReflect:
|
||||||
|
return GLSLstd450Reflect;
|
||||||
|
case ast::Intrinsic::kRound:
|
||||||
|
return GLSLstd450Round;
|
||||||
|
case ast::Intrinsic::kSign:
|
||||||
|
return GLSLstd450FSign;
|
||||||
|
case ast::Intrinsic::kSin:
|
||||||
|
return GLSLstd450Sin;
|
||||||
|
case ast::Intrinsic::kSinh:
|
||||||
|
return GLSLstd450Sinh;
|
||||||
|
case ast::Intrinsic::kSmoothStep:
|
||||||
|
return GLSLstd450SmoothStep;
|
||||||
|
case ast::Intrinsic::kSqrt:
|
||||||
|
return GLSLstd450Sqrt;
|
||||||
|
case ast::Intrinsic::kStep:
|
||||||
|
return GLSLstd450Step;
|
||||||
|
case ast::Intrinsic::kTan:
|
||||||
|
return GLSLstd450Tan;
|
||||||
|
case ast::Intrinsic::kTanh:
|
||||||
|
return GLSLstd450Tanh;
|
||||||
|
case ast::Intrinsic::kTrunc:
|
||||||
|
return GLSLstd450Trunc;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
Builder::AccessorInfo::AccessorInfo() : source_id(0), source_type(nullptr) {}
|
Builder::AccessorInfo::AccessorInfo() : source_id(0), source_type(nullptr) {}
|
||||||
@ -165,10 +283,6 @@ bool Builder::Build() {
|
|||||||
push_preamble(spv::Op::OpExtension,
|
push_preamble(spv::Op::OpExtension,
|
||||||
{Operand::String("SPV_KHR_vulkan_memory_model")});
|
{Operand::String("SPV_KHR_vulkan_memory_model")});
|
||||||
|
|
||||||
for (const auto& imp : mod_->imports()) {
|
|
||||||
GenerateImport(imp.get());
|
|
||||||
}
|
|
||||||
|
|
||||||
push_preamble(spv::Op::OpMemoryModel,
|
push_preamble(spv::Op::OpMemoryModel,
|
||||||
{Operand::Int(SpvAddressingModelLogical),
|
{Operand::Int(SpvAddressingModelLogical),
|
||||||
Operand::Int(SpvMemoryModelVulkanKHR)});
|
Operand::Int(SpvMemoryModelVulkanKHR)});
|
||||||
@ -853,18 +967,6 @@ uint32_t Builder::GenerateAccessorExpression(ast::Expression* expr) {
|
|||||||
uint32_t Builder::GenerateIdentifierExpression(
|
uint32_t Builder::GenerateIdentifierExpression(
|
||||||
ast::IdentifierExpression* expr) {
|
ast::IdentifierExpression* expr) {
|
||||||
uint32_t val = 0;
|
uint32_t val = 0;
|
||||||
if (expr->has_path()) {
|
|
||||||
auto* imp = mod_->FindImportByName(expr->path());
|
|
||||||
if (imp == nullptr) {
|
|
||||||
error_ = "unable to find import for " + expr->path();
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
val = imp->GetIdForMethod(expr->name());
|
|
||||||
if (val == 0) {
|
|
||||||
error_ = "unable to lookup: " + expr->name() + " in " + expr->path();
|
|
||||||
}
|
|
||||||
return val;
|
|
||||||
}
|
|
||||||
if (scope_stack_.get(expr->name(), &val)) {
|
if (scope_stack_.get(expr->name(), &val)) {
|
||||||
return val;
|
return val;
|
||||||
}
|
}
|
||||||
@ -920,14 +1022,18 @@ uint32_t Builder::GenerateUnaryOpExpression(ast::UnaryOpExpression* expr) {
|
|||||||
return result_id;
|
return result_id;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Builder::GenerateImport(ast::Import* imp) {
|
void Builder::GenerateGLSLstd450Import() {
|
||||||
|
if (import_name_to_id_.find(kGLSLstd450) != import_name_to_id_.end()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
auto result = result_op();
|
auto result = result_op();
|
||||||
auto id = result.to_i();
|
auto id = result.to_i();
|
||||||
|
|
||||||
push_preamble(spv::Op::OpExtInstImport,
|
push_preamble(spv::Op::OpExtInstImport,
|
||||||
{result, Operand::String(imp->path())});
|
{result, Operand::String(kGLSLstd450)});
|
||||||
|
|
||||||
import_name_to_id_[imp->name()] = id;
|
import_name_to_id_[kGLSLstd450] = id;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t Builder::GenerateConstructorExpression(
|
uint32_t Builder::GenerateConstructorExpression(
|
||||||
@ -1361,8 +1467,8 @@ uint32_t Builder::GenerateCallExpression(ast::CallExpression* expr) {
|
|||||||
|
|
||||||
auto* ident = expr->func()->AsIdentifier();
|
auto* ident = expr->func()->AsIdentifier();
|
||||||
|
|
||||||
if (!ident->has_path() && ast::intrinsic::IsIntrinsic(ident->name())) {
|
if (ident->IsIntrinsic()) {
|
||||||
return GenerateIntrinsic(ident->name(), expr);
|
return GenerateIntrinsic(ident, expr);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto type_id = GenerateTypeIfNeeded(expr->func()->result_type());
|
auto type_id = GenerateTypeIfNeeded(expr->func()->result_type());
|
||||||
@ -1373,45 +1479,14 @@ uint32_t Builder::GenerateCallExpression(ast::CallExpression* expr) {
|
|||||||
auto result = result_op();
|
auto result = result_op();
|
||||||
auto result_id = result.to_i();
|
auto result_id = result.to_i();
|
||||||
|
|
||||||
spv::Op op = spv::Op::OpNop;
|
|
||||||
OperandList ops = {Operand::Int(type_id), result};
|
OperandList ops = {Operand::Int(type_id), result};
|
||||||
|
|
||||||
// Handle regular function calls
|
auto func_id = func_name_to_id_[ident->name()];
|
||||||
if (!ident->has_path()) {
|
if (func_id == 0) {
|
||||||
auto func_id = func_name_to_id_[ident->name()];
|
error_ = "unable to find called function: " + ident->name();
|
||||||
if (func_id == 0) {
|
return 0;
|
||||||
error_ = "unable to find called function: " + ident->name();
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
ops.push_back(Operand::Int(func_id));
|
|
||||||
|
|
||||||
op = spv::Op::OpFunctionCall;
|
|
||||||
} else {
|
|
||||||
// Imported function call
|
|
||||||
auto set_iter = import_name_to_id_.find(ident->path());
|
|
||||||
if (set_iter == import_name_to_id_.end()) {
|
|
||||||
error_ = "unknown import " + ident->path();
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
auto set_id = set_iter->second;
|
|
||||||
|
|
||||||
auto* imp = mod_->FindImportByName(ident->path());
|
|
||||||
if (imp == nullptr) {
|
|
||||||
error_ = "unknown import " + ident->path();
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto inst_id = imp->GetIdForMethod(ident->name());
|
|
||||||
if (inst_id == 0) {
|
|
||||||
error_ = "unknown method " + ident->name();
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
ops.push_back(Operand::Int(set_id));
|
|
||||||
ops.push_back(Operand::Int(inst_id));
|
|
||||||
|
|
||||||
op = spv::Op::OpExtInst;
|
|
||||||
}
|
}
|
||||||
|
ops.push_back(Operand::Int(func_id));
|
||||||
|
|
||||||
for (const auto& param : expr->params()) {
|
for (const auto& param : expr->params()) {
|
||||||
auto id = GenerateExpression(param.get());
|
auto id = GenerateExpression(param.get());
|
||||||
@ -1422,12 +1497,12 @@ uint32_t Builder::GenerateCallExpression(ast::CallExpression* expr) {
|
|||||||
ops.push_back(Operand::Int(id));
|
ops.push_back(Operand::Int(id));
|
||||||
}
|
}
|
||||||
|
|
||||||
push_function_inst(op, std::move(ops));
|
push_function_inst(spv::Op::OpFunctionCall, std::move(ops));
|
||||||
|
|
||||||
return result_id;
|
return result_id;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t Builder::GenerateIntrinsic(const std::string& name,
|
uint32_t Builder::GenerateIntrinsic(ast::IdentifierExpression* ident,
|
||||||
ast::CallExpression* call) {
|
ast::CallExpression* call) {
|
||||||
auto result = result_op();
|
auto result = result_op();
|
||||||
auto result_id = result.to_i();
|
auto result_id = result.to_i();
|
||||||
@ -1438,6 +1513,76 @@ uint32_t Builder::GenerateIntrinsic(const std::string& name,
|
|||||||
}
|
}
|
||||||
|
|
||||||
OperandList params = {Operand::Int(result_type_id), result};
|
OperandList params = {Operand::Int(result_type_id), result};
|
||||||
|
|
||||||
|
auto intrinsic = ident->intrinsic();
|
||||||
|
if (ast::intrinsic::IsFineDerivative(intrinsic) ||
|
||||||
|
ast::intrinsic::IsCoarseDerivative(intrinsic)) {
|
||||||
|
push_capability(SpvCapabilityDerivativeControl);
|
||||||
|
}
|
||||||
|
|
||||||
|
spv::Op op = spv::Op::OpNop;
|
||||||
|
if (intrinsic == ast::Intrinsic::kAny) {
|
||||||
|
op = spv::Op::OpAny;
|
||||||
|
} else if (intrinsic == ast::Intrinsic::kAll) {
|
||||||
|
op = spv::Op::OpAll;
|
||||||
|
} else if (intrinsic == ast::Intrinsic::kCountOneBits) {
|
||||||
|
op = spv::Op::OpBitCount;
|
||||||
|
} else if (intrinsic == ast::Intrinsic::kDot) {
|
||||||
|
op = spv::Op::OpDot;
|
||||||
|
} else if (intrinsic == ast::Intrinsic::kDpdx) {
|
||||||
|
op = spv::Op::OpDPdx;
|
||||||
|
} else if (intrinsic == ast::Intrinsic::kDpdxCoarse) {
|
||||||
|
op = spv::Op::OpDPdxCoarse;
|
||||||
|
} else if (intrinsic == ast::Intrinsic::kDpdxFine) {
|
||||||
|
op = spv::Op::OpDPdxFine;
|
||||||
|
} else if (intrinsic == ast::Intrinsic::kDpdy) {
|
||||||
|
op = spv::Op::OpDPdy;
|
||||||
|
} else if (intrinsic == ast::Intrinsic::kDpdyCoarse) {
|
||||||
|
op = spv::Op::OpDPdyCoarse;
|
||||||
|
} else if (intrinsic == ast::Intrinsic::kDpdyFine) {
|
||||||
|
op = spv::Op::OpDPdyFine;
|
||||||
|
} else if (intrinsic == ast::Intrinsic::kFwidth) {
|
||||||
|
op = spv::Op::OpFwidth;
|
||||||
|
} else if (intrinsic == ast::Intrinsic::kFwidthCoarse) {
|
||||||
|
op = spv::Op::OpFwidthCoarse;
|
||||||
|
} else if (intrinsic == ast::Intrinsic::kFwidthFine) {
|
||||||
|
op = spv::Op::OpFwidthFine;
|
||||||
|
} else if (intrinsic == ast::Intrinsic::kIsInf) {
|
||||||
|
op = spv::Op::OpIsInf;
|
||||||
|
} else if (intrinsic == ast::Intrinsic::kIsNan) {
|
||||||
|
op = spv::Op::OpIsNan;
|
||||||
|
} else if (intrinsic == ast::Intrinsic::kOuterProduct) {
|
||||||
|
op = spv::Op::OpOuterProduct;
|
||||||
|
} else if (intrinsic == ast::Intrinsic::kReverseBits) {
|
||||||
|
op = spv::Op::OpBitReverse;
|
||||||
|
} else if (intrinsic == ast::Intrinsic::kSelect) {
|
||||||
|
op = spv::Op::OpSelect;
|
||||||
|
} else if (!ast::intrinsic::IsTextureIntrinsic(intrinsic)) {
|
||||||
|
GenerateGLSLstd450Import();
|
||||||
|
|
||||||
|
auto set_iter = import_name_to_id_.find(kGLSLstd450);
|
||||||
|
if (set_iter == import_name_to_id_.end()) {
|
||||||
|
error_ = std::string("unknown import ") + kGLSLstd450;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
auto set_id = set_iter->second;
|
||||||
|
auto inst_id =
|
||||||
|
intrinsic_to_glsl_method(ident->result_type(), ident->intrinsic());
|
||||||
|
if (inst_id == 0) {
|
||||||
|
error_ = "unknown method " + ident->name();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
params.push_back(Operand::Int(set_id));
|
||||||
|
params.push_back(Operand::Int(inst_id));
|
||||||
|
|
||||||
|
op = spv::Op::OpExtInst;
|
||||||
|
}
|
||||||
|
if (!ast::intrinsic::IsTextureIntrinsic(intrinsic) && op == spv::Op::OpNop) {
|
||||||
|
error_ = "unable to determine operator for: " + ident->name();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
for (const auto& p : call->params()) {
|
for (const auto& p : call->params()) {
|
||||||
auto val_id = GenerateExpression(p.get());
|
auto val_id = GenerateExpression(p.get());
|
||||||
if (val_id == 0) {
|
if (val_id == 0) {
|
||||||
@ -1448,59 +1593,16 @@ uint32_t Builder::GenerateIntrinsic(const std::string& name,
|
|||||||
params.push_back(Operand::Int(val_id));
|
params.push_back(Operand::Int(val_id));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ast::intrinsic::IsTextureOperationIntrinsic(name)) {
|
if (ast::intrinsic::IsTextureIntrinsic(intrinsic)) {
|
||||||
return GenerateTextureIntrinsic(name, call, result_id, params);
|
return GenerateTextureIntrinsic(ident, call, result_id, params);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ast::intrinsic::IsFineDerivative(name) ||
|
|
||||||
ast::intrinsic::IsCoarseDerivative(name)) {
|
|
||||||
push_capability(SpvCapabilityDerivativeControl);
|
|
||||||
}
|
|
||||||
|
|
||||||
spv::Op op = spv::Op::OpNop;
|
|
||||||
if (name == "any") {
|
|
||||||
op = spv::Op::OpAny;
|
|
||||||
} else if (name == "all") {
|
|
||||||
op = spv::Op::OpAll;
|
|
||||||
} else if (name == "dot") {
|
|
||||||
op = spv::Op::OpDot;
|
|
||||||
} else if (name == "dpdx") {
|
|
||||||
op = spv::Op::OpDPdx;
|
|
||||||
} else if (name == "dpdxCoarse") {
|
|
||||||
op = spv::Op::OpDPdxCoarse;
|
|
||||||
} else if (name == "dpdxFine") {
|
|
||||||
op = spv::Op::OpDPdxFine;
|
|
||||||
} else if (name == "dpdy") {
|
|
||||||
op = spv::Op::OpDPdy;
|
|
||||||
} else if (name == "dpdyCoarse") {
|
|
||||||
op = spv::Op::OpDPdyCoarse;
|
|
||||||
} else if (name == "dpdyFine") {
|
|
||||||
op = spv::Op::OpDPdyFine;
|
|
||||||
} else if (name == "fwidth") {
|
|
||||||
op = spv::Op::OpFwidth;
|
|
||||||
} else if (name == "fwidthCoarse") {
|
|
||||||
op = spv::Op::OpFwidthCoarse;
|
|
||||||
} else if (name == "fwidthFine") {
|
|
||||||
op = spv::Op::OpFwidthFine;
|
|
||||||
} else if (name == "isInf") {
|
|
||||||
op = spv::Op::OpIsInf;
|
|
||||||
} else if (name == "isNan") {
|
|
||||||
op = spv::Op::OpIsNan;
|
|
||||||
} else if (name == "outerProduct") {
|
|
||||||
op = spv::Op::OpOuterProduct;
|
|
||||||
} else if (name == "select") {
|
|
||||||
op = spv::Op::OpSelect;
|
|
||||||
}
|
|
||||||
if (op == spv::Op::OpNop) {
|
|
||||||
error_ = "unable to determine operator for: " + name;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
push_function_inst(op, params);
|
push_function_inst(op, params);
|
||||||
|
|
||||||
return result_id;
|
return result_id;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t Builder::GenerateTextureIntrinsic(const std::string& name,
|
uint32_t Builder::GenerateTextureIntrinsic(ast::IdentifierExpression* ident,
|
||||||
ast::CallExpression* call,
|
ast::CallExpression* call,
|
||||||
uint32_t result_id,
|
uint32_t result_id,
|
||||||
OperandList wgsl_params) {
|
OperandList wgsl_params) {
|
||||||
@ -1512,7 +1614,7 @@ uint32_t Builder::GenerateTextureIntrinsic(const std::string& name,
|
|||||||
|
|
||||||
// TODO: Remove the LOD param from textureLoad on storage textures when
|
// TODO: Remove the LOD param from textureLoad on storage textures when
|
||||||
// https://github.com/gpuweb/gpuweb/pull/1032 gets merged.
|
// https://github.com/gpuweb/gpuweb/pull/1032 gets merged.
|
||||||
if (name == "textureLoad") {
|
if (ident->intrinsic() == ast::Intrinsic::kTextureLoad) {
|
||||||
std::vector<Operand> spirv_params = {
|
std::vector<Operand> spirv_params = {
|
||||||
std::move(wgsl_params[0]), std::move(wgsl_params[1]),
|
std::move(wgsl_params[0]), std::move(wgsl_params[1]),
|
||||||
std::move(wgsl_params[2]), std::move(wgsl_params[3])};
|
std::move(wgsl_params[2]), std::move(wgsl_params[3])};
|
||||||
@ -1538,17 +1640,17 @@ uint32_t Builder::GenerateTextureIntrinsic(const std::string& name,
|
|||||||
std::move(wgsl_params[3]))),
|
std::move(wgsl_params[3]))),
|
||||||
std::move(wgsl_params[4])};
|
std::move(wgsl_params[4])};
|
||||||
|
|
||||||
if (name == "textureSample") {
|
if (ident->intrinsic() == ast::Intrinsic::kTextureSample) {
|
||||||
op = spv::Op::OpImageSampleImplicitLod;
|
op = spv::Op::OpImageSampleImplicitLod;
|
||||||
} else if (name == "textureSampleLevel") {
|
} else if (ident->intrinsic() == ast::Intrinsic::kTextureSampleLevel) {
|
||||||
op = spv::Op::OpImageSampleExplicitLod;
|
op = spv::Op::OpImageSampleExplicitLod;
|
||||||
spirv_params.push_back(Operand::Int(SpvImageOperandsLodMask));
|
spirv_params.push_back(Operand::Int(SpvImageOperandsLodMask));
|
||||||
spirv_params.push_back(std::move(wgsl_params[5]));
|
spirv_params.push_back(std::move(wgsl_params[5]));
|
||||||
} else if (name == "textureSampleBias") {
|
} else if (ident->intrinsic() == ast::Intrinsic::kTextureSampleBias) {
|
||||||
op = spv::Op::OpImageSampleImplicitLod;
|
op = spv::Op::OpImageSampleImplicitLod;
|
||||||
spirv_params.push_back(Operand::Int(SpvImageOperandsBiasMask));
|
spirv_params.push_back(Operand::Int(SpvImageOperandsBiasMask));
|
||||||
spirv_params.push_back(std::move(wgsl_params[5]));
|
spirv_params.push_back(std::move(wgsl_params[5]));
|
||||||
} else if (name == "textureSampleCompare") {
|
} else if (ident->intrinsic() == ast::Intrinsic::kTextureSampleCompare) {
|
||||||
op = spv::Op::OpImageSampleDrefExplicitLod;
|
op = spv::Op::OpImageSampleDrefExplicitLod;
|
||||||
spirv_params.push_back(std::move(wgsl_params[5]));
|
spirv_params.push_back(std::move(wgsl_params[5]));
|
||||||
|
|
||||||
@ -1558,7 +1660,7 @@ uint32_t Builder::GenerateTextureIntrinsic(const std::string& name,
|
|||||||
spirv_params.push_back(Operand::Int(GenerateLiteralIfNeeded(&float_0)));
|
spirv_params.push_back(Operand::Int(GenerateLiteralIfNeeded(&float_0)));
|
||||||
}
|
}
|
||||||
if (op == spv::Op::OpNop) {
|
if (op == spv::Op::OpNop) {
|
||||||
error_ = "unable to determine operator for: " + name;
|
error_ = "unable to determine operator for: " + ident->name();
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
push_function_inst(op, spirv_params);
|
push_function_inst(op, spirv_params);
|
||||||
|
@ -247,8 +247,7 @@ class Builder {
|
|||||||
/// @returns true on success
|
/// @returns true on success
|
||||||
bool GenerateIfStatement(ast::IfStatement* stmt);
|
bool GenerateIfStatement(ast::IfStatement* stmt);
|
||||||
/// Generates an import instruction
|
/// Generates an import instruction
|
||||||
/// @param imp the import
|
void GenerateGLSLstd450Import();
|
||||||
void GenerateImport(ast::Import* imp);
|
|
||||||
/// Generates a constructor expression
|
/// Generates a constructor expression
|
||||||
/// @param expr the expression to generate
|
/// @param expr the expression to generate
|
||||||
/// @param is_global_init set true if this is a global variable constructor
|
/// @param is_global_init set true if this is a global variable constructor
|
||||||
@ -283,19 +282,19 @@ class Builder {
|
|||||||
/// @returns the expression ID on success or 0 otherwise
|
/// @returns the expression ID on success or 0 otherwise
|
||||||
uint32_t GenerateCallExpression(ast::CallExpression* expr);
|
uint32_t GenerateCallExpression(ast::CallExpression* expr);
|
||||||
/// Generates an intrinsic call
|
/// Generates an intrinsic call
|
||||||
/// @param name the intrinsic name
|
/// @param ident the intrinsic expression
|
||||||
/// @param call the call expression
|
/// @param call the call expression
|
||||||
/// @returns the expression ID on success or 0 otherwise
|
/// @returns the expression ID on success or 0 otherwise
|
||||||
uint32_t GenerateIntrinsic(const std::string& name,
|
uint32_t GenerateIntrinsic(ast::IdentifierExpression* ident,
|
||||||
ast::CallExpression* call);
|
ast::CallExpression* call);
|
||||||
/// Generates a texture intrinsic call
|
/// Generates a texture intrinsic call
|
||||||
/// @param name the texture intrinsic name
|
/// @param ident the texture intrinsic
|
||||||
/// @param call the call expression
|
/// @param call the call expression
|
||||||
/// @param result_id result ID of the texture instruction
|
/// @param result_id result ID of the texture instruction
|
||||||
/// @param wgsl_params SPIR-V arguments for WGSL-specific intrinsic's call
|
/// @param wgsl_params SPIR-V arguments for WGSL-specific intrinsic's call
|
||||||
/// parameters
|
/// parameters
|
||||||
/// @returns the expression ID on success or 0 otherwise
|
/// @returns the expression ID on success or 0 otherwise
|
||||||
uint32_t GenerateTextureIntrinsic(const std::string& name,
|
uint32_t GenerateTextureIntrinsic(ast::IdentifierExpression* ident,
|
||||||
ast::CallExpression* call,
|
ast::CallExpression* call,
|
||||||
uint32_t result_id,
|
uint32_t result_id,
|
||||||
OperandList wgsl_params);
|
OperandList wgsl_params);
|
||||||
|
@ -38,98 +38,6 @@ namespace {
|
|||||||
|
|
||||||
using BuilderTest = testing::Test;
|
using BuilderTest = testing::Test;
|
||||||
|
|
||||||
TEST_F(BuilderTest, Call_GLSLMethod) {
|
|
||||||
ast::type::F32Type f32;
|
|
||||||
ast::type::VoidType void_type;
|
|
||||||
|
|
||||||
ast::ExpressionList params;
|
|
||||||
params.push_back(std::make_unique<ast::ScalarConstructorExpression>(
|
|
||||||
std::make_unique<ast::FloatLiteral>(&f32, 1.f)));
|
|
||||||
|
|
||||||
ast::CallExpression expr(std::make_unique<ast::IdentifierExpression>(
|
|
||||||
std::vector<std::string>{"std", "round"}),
|
|
||||||
std::move(params));
|
|
||||||
|
|
||||||
Context ctx;
|
|
||||||
ast::Module mod;
|
|
||||||
TypeDeterminer td(&ctx, &mod);
|
|
||||||
|
|
||||||
auto imp = std::make_unique<ast::Import>("GLSL.std.450", "std");
|
|
||||||
auto* glsl = imp.get();
|
|
||||||
mod.AddImport(std::move(imp));
|
|
||||||
|
|
||||||
ASSERT_TRUE(td.DetermineResultType(&expr)) << td.error();
|
|
||||||
|
|
||||||
ast::Function func("a_func", {}, &void_type);
|
|
||||||
|
|
||||||
Builder b(&mod);
|
|
||||||
b.GenerateImport(glsl);
|
|
||||||
ASSERT_TRUE(b.GenerateFunction(&func)) << b.error();
|
|
||||||
|
|
||||||
EXPECT_EQ(b.GenerateCallExpression(&expr), 7u) << b.error();
|
|
||||||
EXPECT_EQ(DumpBuilder(b), R"(%1 = OpExtInstImport "GLSL.std.450"
|
|
||||||
OpName %4 "a_func"
|
|
||||||
%3 = OpTypeVoid
|
|
||||||
%2 = OpTypeFunction %3
|
|
||||||
%6 = OpTypeFloat 32
|
|
||||||
%8 = OpConstant %6 1
|
|
||||||
%4 = OpFunction %3 None %2
|
|
||||||
%5 = OpLabel
|
|
||||||
%7 = OpExtInst %6 %1 Round %8
|
|
||||||
OpFunctionEnd
|
|
||||||
)");
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(BuilderTest, Call_GLSLMethod_WithLoad) {
|
|
||||||
ast::type::F32Type f32;
|
|
||||||
ast::type::VoidType void_type;
|
|
||||||
|
|
||||||
auto var = std::make_unique<ast::Variable>("ident",
|
|
||||||
ast::StorageClass::kPrivate, &f32);
|
|
||||||
|
|
||||||
ast::ExpressionList params;
|
|
||||||
params.push_back(std::make_unique<ast::IdentifierExpression>("ident"));
|
|
||||||
|
|
||||||
ast::CallExpression expr(std::make_unique<ast::IdentifierExpression>(
|
|
||||||
std::vector<std::string>{"std", "round"}),
|
|
||||||
std::move(params));
|
|
||||||
|
|
||||||
Context ctx;
|
|
||||||
ast::Module mod;
|
|
||||||
TypeDeterminer td(&ctx, &mod);
|
|
||||||
td.RegisterVariableForTesting(var.get());
|
|
||||||
|
|
||||||
auto imp = std::make_unique<ast::Import>("GLSL.std.450", "std");
|
|
||||||
auto* glsl = imp.get();
|
|
||||||
mod.AddImport(std::move(imp));
|
|
||||||
|
|
||||||
ASSERT_TRUE(td.DetermineResultType(&expr)) << td.error();
|
|
||||||
|
|
||||||
ast::Function func("a_func", {}, &void_type);
|
|
||||||
|
|
||||||
Builder b(&mod);
|
|
||||||
b.GenerateImport(glsl);
|
|
||||||
ASSERT_TRUE(b.GenerateGlobalVariable(var.get())) << b.error();
|
|
||||||
ASSERT_TRUE(b.GenerateFunction(&func)) << b.error();
|
|
||||||
|
|
||||||
EXPECT_EQ(b.GenerateCallExpression(&expr), 10u) << b.error();
|
|
||||||
EXPECT_EQ(DumpBuilder(b), R"(%1 = OpExtInstImport "GLSL.std.450"
|
|
||||||
OpName %2 "ident"
|
|
||||||
OpName %8 "a_func"
|
|
||||||
%4 = OpTypeFloat 32
|
|
||||||
%3 = OpTypePointer Private %4
|
|
||||||
%5 = OpConstantNull %4
|
|
||||||
%2 = OpVariable %3 Private %5
|
|
||||||
%7 = OpTypeVoid
|
|
||||||
%6 = OpTypeFunction %7
|
|
||||||
%8 = OpFunction %7 None %6
|
|
||||||
%9 = OpLabel
|
|
||||||
%11 = OpLoad %4 %2
|
|
||||||
%10 = OpExtInst %4 %1 Round %11
|
|
||||||
OpFunctionEnd
|
|
||||||
)");
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(BuilderTest, Expression_Call) {
|
TEST_F(BuilderTest, Expression_Call) {
|
||||||
ast::type::F32Type f32;
|
ast::type::F32Type f32;
|
||||||
ast::type::VoidType void_type;
|
ast::type::VoidType void_type;
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -19,7 +19,6 @@
|
|||||||
#include "gtest/gtest.h"
|
#include "gtest/gtest.h"
|
||||||
#include "spirv/unified1/spirv.h"
|
#include "spirv/unified1/spirv.h"
|
||||||
#include "spirv/unified1/spirv.hpp11"
|
#include "spirv/unified1/spirv.hpp11"
|
||||||
#include "src/ast/import.h"
|
|
||||||
#include "src/ast/module.h"
|
#include "src/ast/module.h"
|
||||||
#include "src/writer/spirv/spv_dump.h"
|
#include "src/writer/spirv/spv_dump.h"
|
||||||
|
|
||||||
@ -30,24 +29,7 @@ namespace {
|
|||||||
|
|
||||||
using BuilderTest = testing::Test;
|
using BuilderTest = testing::Test;
|
||||||
|
|
||||||
TEST_F(BuilderTest, InsertsPreambleWithImport) {
|
TEST_F(BuilderTest, InsertsPreamble) {
|
||||||
ast::Module m;
|
|
||||||
m.AddImport(std::make_unique<ast::Import>("GLSL.std.450", "glsl"));
|
|
||||||
|
|
||||||
Builder b(&m);
|
|
||||||
ASSERT_TRUE(b.Build());
|
|
||||||
ASSERT_EQ(b.capabilities().size(), 2u);
|
|
||||||
ASSERT_EQ(b.preamble().size(), 3u);
|
|
||||||
|
|
||||||
EXPECT_EQ(DumpBuilder(b), R"(OpCapability Shader
|
|
||||||
OpCapability VulkanMemoryModel
|
|
||||||
OpExtension "SPV_KHR_vulkan_memory_model"
|
|
||||||
%1 = OpExtInstImport "GLSL.std.450"
|
|
||||||
OpMemoryModel Logical Vulkan
|
|
||||||
)");
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(BuilderTest, InsertsPreambleWithoutImport) {
|
|
||||||
ast::Module m;
|
ast::Module m;
|
||||||
Builder b(&m);
|
Builder b(&m);
|
||||||
ASSERT_TRUE(b.Build());
|
ASSERT_TRUE(b.Build());
|
||||||
|
@ -75,15 +75,6 @@ GeneratorImpl::GeneratorImpl() = default;
|
|||||||
GeneratorImpl::~GeneratorImpl() = default;
|
GeneratorImpl::~GeneratorImpl() = default;
|
||||||
|
|
||||||
bool GeneratorImpl::Generate(const ast::Module& module) {
|
bool GeneratorImpl::Generate(const ast::Module& module) {
|
||||||
for (const auto& import : module.imports()) {
|
|
||||||
if (!EmitImport(import.get())) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!module.imports().empty()) {
|
|
||||||
out_ << std::endl;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (auto* const alias : module.alias_types()) {
|
for (auto* const alias : module.alias_types()) {
|
||||||
if (!EmitAliasType(alias)) {
|
if (!EmitAliasType(alias)) {
|
||||||
return false;
|
return false;
|
||||||
@ -114,16 +105,6 @@ bool GeneratorImpl::Generate(const ast::Module& module) {
|
|||||||
bool GeneratorImpl::GenerateEntryPoint(const ast::Module& module,
|
bool GeneratorImpl::GenerateEntryPoint(const ast::Module& module,
|
||||||
ast::PipelineStage stage,
|
ast::PipelineStage stage,
|
||||||
const std::string& name) {
|
const std::string& name) {
|
||||||
// TODO(dsinclair): We're always emitting imports even if they aren't needed.
|
|
||||||
for (const auto& import : module.imports()) {
|
|
||||||
if (!EmitImport(import.get())) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!module.imports().empty()) {
|
|
||||||
out_ << std::endl;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto* func = module.FindFunctionByNameAndStage(name, stage);
|
auto* func = module.FindFunctionByNameAndStage(name, stage);
|
||||||
if (func == nullptr) {
|
if (func == nullptr) {
|
||||||
error_ = "Unable to find requested entry point: " + name;
|
error_ = "Unable to find requested entry point: " + name;
|
||||||
@ -365,20 +346,10 @@ bool GeneratorImpl::EmitLiteral(ast::Literal* lit) {
|
|||||||
|
|
||||||
bool GeneratorImpl::EmitIdentifier(ast::IdentifierExpression* expr) {
|
bool GeneratorImpl::EmitIdentifier(ast::IdentifierExpression* expr) {
|
||||||
auto* ident = expr->AsIdentifier();
|
auto* ident = expr->AsIdentifier();
|
||||||
if (ident->has_path()) {
|
|
||||||
out_ << ident->path() << "::";
|
|
||||||
}
|
|
||||||
out_ << ident->name();
|
out_ << ident->name();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool GeneratorImpl::EmitImport(const ast::Import* import) {
|
|
||||||
make_indent();
|
|
||||||
out_ << R"(import ")" << import->path() << R"(" as )" << import->name() << ";"
|
|
||||||
<< std::endl;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool GeneratorImpl::EmitFunction(ast::Function* func) {
|
bool GeneratorImpl::EmitFunction(ast::Function* func) {
|
||||||
for (auto& deco : func->decorations()) {
|
for (auto& deco : func->decorations()) {
|
||||||
make_indent();
|
make_indent();
|
||||||
|
@ -21,7 +21,6 @@
|
|||||||
#include "src/ast/array_accessor_expression.h"
|
#include "src/ast/array_accessor_expression.h"
|
||||||
#include "src/ast/constructor_expression.h"
|
#include "src/ast/constructor_expression.h"
|
||||||
#include "src/ast/identifier_expression.h"
|
#include "src/ast/identifier_expression.h"
|
||||||
#include "src/ast/import.h"
|
|
||||||
#include "src/ast/module.h"
|
#include "src/ast/module.h"
|
||||||
#include "src/ast/scalar_constructor_expression.h"
|
#include "src/ast/scalar_constructor_expression.h"
|
||||||
#include "src/ast/type/alias_type.h"
|
#include "src/ast/type/alias_type.h"
|
||||||
@ -135,10 +134,6 @@ class GeneratorImpl : public TextGenerator {
|
|||||||
/// @param stmt the statement to emit
|
/// @param stmt the statement to emit
|
||||||
/// @returns true if the statement was successfully emitted
|
/// @returns true if the statement was successfully emitted
|
||||||
bool EmitIf(ast::IfStatement* stmt);
|
bool EmitIf(ast::IfStatement* stmt);
|
||||||
/// Handles generating an import command
|
|
||||||
/// @param import the import to generate
|
|
||||||
/// @returns true if the import was emitted
|
|
||||||
bool EmitImport(const ast::Import* import);
|
|
||||||
/// Handles generating constructor expressions
|
/// Handles generating constructor expressions
|
||||||
/// @param expr the constructor expression
|
/// @param expr the constructor expression
|
||||||
/// @returns true if the expression was emitted
|
/// @returns true if the expression was emitted
|
||||||
|
@ -22,14 +22,6 @@ namespace {
|
|||||||
|
|
||||||
using WgslGeneratorImplTest = testing::Test;
|
using WgslGeneratorImplTest = testing::Test;
|
||||||
|
|
||||||
TEST_F(WgslGeneratorImplTest, EmitExpression_Identifier) {
|
|
||||||
ast::IdentifierExpression i(std::vector<std::string>{"std", "glsl"});
|
|
||||||
|
|
||||||
GeneratorImpl g;
|
|
||||||
ASSERT_TRUE(g.EmitExpression(&i)) << g.error();
|
|
||||||
EXPECT_EQ(g.result(), "std::glsl");
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(WgslGeneratorImplTest, EmitIdentifierExpression_Single) {
|
TEST_F(WgslGeneratorImplTest, EmitIdentifierExpression_Single) {
|
||||||
ast::IdentifierExpression i("glsl");
|
ast::IdentifierExpression i("glsl");
|
||||||
|
|
||||||
@ -38,14 +30,6 @@ TEST_F(WgslGeneratorImplTest, EmitIdentifierExpression_Single) {
|
|||||||
EXPECT_EQ(g.result(), "glsl");
|
EXPECT_EQ(g.result(), "glsl");
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(WgslGeneratorImplTest, EmitIdentifierExpression_MultipleNames) {
|
|
||||||
ast::IdentifierExpression i({"std", "glsl", "init"});
|
|
||||||
|
|
||||||
GeneratorImpl g;
|
|
||||||
ASSERT_TRUE(g.EmitExpression(&i)) << g.error();
|
|
||||||
EXPECT_EQ(g.result(), "std::glsl::init");
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
} // namespace wgsl
|
} // namespace wgsl
|
||||||
} // namespace writer
|
} // namespace writer
|
||||||
|
@ -1,37 +0,0 @@
|
|||||||
// 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 "gtest/gtest.h"
|
|
||||||
#include "src/writer/wgsl/generator_impl.h"
|
|
||||||
|
|
||||||
namespace tint {
|
|
||||||
namespace writer {
|
|
||||||
namespace wgsl {
|
|
||||||
namespace {
|
|
||||||
|
|
||||||
using WgslGeneratorImplTest = testing::Test;
|
|
||||||
|
|
||||||
TEST_F(WgslGeneratorImplTest, EmitImport) {
|
|
||||||
ast::Import import("GLSL.std.450", "std::glsl");
|
|
||||||
|
|
||||||
GeneratorImpl g;
|
|
||||||
ASSERT_TRUE(g.EmitImport(&import)) << g.error();
|
|
||||||
EXPECT_EQ(g.result(), R"(import "GLSL.std.450" as std::glsl;
|
|
||||||
)");
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace
|
|
||||||
} // namespace wgsl
|
|
||||||
} // namespace writer
|
|
||||||
} // namespace tint
|
|
@ -17,6 +17,9 @@
|
|||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
#include "gtest/gtest.h"
|
#include "gtest/gtest.h"
|
||||||
|
#include "src/ast/function.h"
|
||||||
|
#include "src/ast/module.h"
|
||||||
|
#include "src/ast/type/void_type.h"
|
||||||
|
|
||||||
namespace tint {
|
namespace tint {
|
||||||
namespace writer {
|
namespace writer {
|
||||||
@ -26,13 +29,17 @@ namespace {
|
|||||||
using WgslGeneratorImplTest = testing::Test;
|
using WgslGeneratorImplTest = testing::Test;
|
||||||
|
|
||||||
TEST_F(WgslGeneratorImplTest, Generate) {
|
TEST_F(WgslGeneratorImplTest, Generate) {
|
||||||
|
ast::type::VoidType void_type;
|
||||||
|
|
||||||
ast::Module m;
|
ast::Module m;
|
||||||
m.AddImport(std::make_unique<ast::Import>("GLSL.std.430", "a"));
|
m.AddFunction(std::make_unique<ast::Function>("my_func", ast::VariableList{},
|
||||||
|
&void_type));
|
||||||
|
|
||||||
GeneratorImpl g;
|
GeneratorImpl g;
|
||||||
|
|
||||||
ASSERT_TRUE(g.Generate(m)) << g.error();
|
ASSERT_TRUE(g.Generate(m)) << g.error();
|
||||||
EXPECT_EQ(g.result(), R"(import "GLSL.std.430" as a;
|
EXPECT_EQ(g.result(), R"(fn my_func() -> void {
|
||||||
|
}
|
||||||
|
|
||||||
)");
|
)");
|
||||||
}
|
}
|
||||||
|
@ -12,8 +12,6 @@
|
|||||||
# See the License for the specific language governing permissions and
|
# See the License for the specific language governing permissions and
|
||||||
# limitations under the License.
|
# limitations under the License.
|
||||||
|
|
||||||
import "GLSL.std.450" as std;
|
|
||||||
|
|
||||||
# vertex shader
|
# vertex shader
|
||||||
|
|
||||||
[[location(0)]] var<in> a_particlePos : vec2<f32>;
|
[[location(0)]] var<in> a_particlePos : vec2<f32>;
|
||||||
@ -23,10 +21,10 @@ import "GLSL.std.450" as std;
|
|||||||
|
|
||||||
[[stage(vertex)]]
|
[[stage(vertex)]]
|
||||||
fn vert_main() -> void {
|
fn vert_main() -> void {
|
||||||
var angle : f32 = -std::atan2(a_particleVel.x, a_particleVel.y);
|
var angle : f32 = -atan2(a_particleVel.x, a_particleVel.y);
|
||||||
var pos : vec2<f32> = vec2<f32>(
|
var pos : vec2<f32> = vec2<f32>(
|
||||||
(a_pos.x * std::cos(angle)) - (a_pos.y * std::sin(angle)),
|
(a_pos.x * cos(angle)) - (a_pos.y * sin(angle)),
|
||||||
(a_pos.x * std::sin(angle)) + (a_pos.y * std::cos(angle)));
|
(a_pos.x * sin(angle)) + (a_pos.y * cos(angle)));
|
||||||
gl_Position = vec4<f32>(pos + a_particlePos, 0.0, 1.0);
|
gl_Position = vec4<f32>(pos + a_particlePos, 0.0, 1.0);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -97,14 +95,14 @@ fn comp_main() -> void {
|
|||||||
pos = particlesA.particles[i].pos.xy;
|
pos = particlesA.particles[i].pos.xy;
|
||||||
vel = particlesA.particles[i].vel.xy;
|
vel = particlesA.particles[i].vel.xy;
|
||||||
|
|
||||||
if (std::distance(pos, vPos) < params.rule1Distance) {
|
if (distance(pos, vPos) < params.rule1Distance) {
|
||||||
cMass = cMass + pos;
|
cMass = cMass + pos;
|
||||||
cMassCount = cMassCount + 1;
|
cMassCount = cMassCount + 1;
|
||||||
}
|
}
|
||||||
if (std::distance(pos, vPos) < params.rule2Distance) {
|
if (distance(pos, vPos) < params.rule2Distance) {
|
||||||
colVel = colVel - (pos - vPos);
|
colVel = colVel - (pos - vPos);
|
||||||
}
|
}
|
||||||
if (std::distance(pos, vPos) < params.rule3Distance) {
|
if (distance(pos, vPos) < params.rule3Distance) {
|
||||||
cVel = cVel + vel;
|
cVel = cVel + vel;
|
||||||
cVelCount = cVelCount + 1;
|
cVelCount = cVelCount + 1;
|
||||||
}
|
}
|
||||||
@ -125,7 +123,7 @@ fn comp_main() -> void {
|
|||||||
(cVel * params.rule3Scale);
|
(cVel * params.rule3Scale);
|
||||||
|
|
||||||
# clamp velocity for a more pleasing simulation
|
# clamp velocity for a more pleasing simulation
|
||||||
vVel = std::normalize(vVel) * std::fclamp(std::length(vVel), 0.0, 0.1);
|
vVel = normalize(vVel) * clamp(length(vVel), 0.0, 0.1);
|
||||||
|
|
||||||
# kinematic update
|
# kinematic update
|
||||||
vPos = vPos + (vVel * params.deltaT);
|
vPos = vPos + (vVel * params.deltaT);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user