Remove cast operator.
This CL removes the cast operator and converts the tests over to using
type constructors.
Bug: tint:241
Change-Id: I2526acb61f5624b2e1c068612a2ddcc748c92aed
Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/28860
Commit-Queue: dan sinclair <dsinclair@chromium.org>
Reviewed-by: Ryan Harrison <rharrison@chromium.org>
diff --git a/BUILD.gn b/BUILD.gn
index a1ed133..ea3b979 100644
--- a/BUILD.gn
+++ b/BUILD.gn
@@ -243,8 +243,6 @@
"src/ast/call_statement.h",
"src/ast/case_statement.cc",
"src/ast/case_statement.h",
- "src/ast/cast_expression.cc",
- "src/ast/cast_expression.h",
"src/ast/constructor_expression.cc",
"src/ast/constructor_expression.h",
"src/ast/continue_statement.cc",
@@ -697,7 +695,6 @@
"src/ast/call_expression_test.cc",
"src/ast/call_statement_test.cc",
"src/ast/case_statement_test.cc",
- "src/ast/cast_expression_test.cc",
"src/ast/continue_statement_test.cc",
"src/ast/decorated_variable_test.cc",
"src/ast/discard_statement_test.cc",
@@ -831,7 +828,6 @@
"src/writer/spirv/builder_bitcast_expression_test.cc",
"src/writer/spirv/builder_block_test.cc",
"src/writer/spirv/builder_call_test.cc",
- "src/writer/spirv/builder_cast_expression_test.cc",
"src/writer/spirv/builder_constructor_expression_test.cc",
"src/writer/spirv/builder_discard_test.cc",
"src/writer/spirv/builder_format_conversion_test.cc",
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 7c16a03..b2d4885 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -64,8 +64,6 @@
ast/call_statement.h
ast/case_statement.cc
ast/case_statement.h
- ast/cast_expression.cc
- ast/cast_expression.h
ast/constructor_expression.cc
ast/constructor_expression.h
ast/continue_statement.cc
@@ -306,7 +304,6 @@
ast/call_expression_test.cc
ast/call_statement_test.cc
ast/case_statement_test.cc
- ast/cast_expression_test.cc
ast/continue_statement_test.cc
ast/discard_statement_test.cc
ast/decorated_variable_test.cc
@@ -489,7 +486,6 @@
writer/spirv/builder_bitcast_expression_test.cc
writer/spirv/builder_block_test.cc
writer/spirv/builder_call_test.cc
- writer/spirv/builder_cast_expression_test.cc
writer/spirv/builder_constructor_expression_test.cc
writer/spirv/builder_discard_test.cc
writer/spirv/builder_format_conversion_test.cc
diff --git a/src/ast/cast_expression.cc b/src/ast/cast_expression.cc
deleted file mode 100644
index 327c37d..0000000
--- a/src/ast/cast_expression.cc
+++ /dev/null
@@ -1,54 +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/cast_expression.h"
-
-namespace tint {
-namespace ast {
-
-CastExpression::CastExpression() : Expression() {}
-
-CastExpression::CastExpression(type::Type* type,
- std::unique_ptr<Expression> expr)
- : Expression(), type_(type), expr_(std::move(expr)) {}
-
-CastExpression::CastExpression(const Source& source,
- type::Type* type,
- std::unique_ptr<Expression> expr)
- : Expression(source), type_(type), expr_(std::move(expr)) {}
-
-CastExpression::CastExpression(CastExpression&&) = default;
-
-CastExpression::~CastExpression() = default;
-
-bool CastExpression::IsCast() const {
- return true;
-}
-
-bool CastExpression::IsValid() const {
- if (expr_ == nullptr || !expr_->IsValid())
- return false;
- return type_ != nullptr;
-}
-
-void CastExpression::to_str(std::ostream& out, size_t indent) const {
- make_indent(out, indent);
- out << "Cast<" << type_->type_name() << ">(" << std::endl;
- expr_->to_str(out, indent + 2);
- make_indent(out, indent);
- out << ")" << std::endl;
-}
-
-} // namespace ast
-} // namespace tint
diff --git a/src/ast/cast_expression.h b/src/ast/cast_expression.h
deleted file mode 100644
index b1db7fe..0000000
--- a/src/ast/cast_expression.h
+++ /dev/null
@@ -1,81 +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_CAST_EXPRESSION_H_
-#define SRC_AST_CAST_EXPRESSION_H_
-
-#include <memory>
-#include <utility>
-
-#include "src/ast/expression.h"
-#include "src/ast/literal.h"
-#include "src/ast/type/type.h"
-
-namespace tint {
-namespace ast {
-
-/// A cast expression
-class CastExpression : public Expression {
- public:
- /// Constructor
- CastExpression();
- /// Constructor
- /// @param type the type
- /// @param expr the expr
- CastExpression(type::Type* type, std::unique_ptr<Expression> expr);
- /// Constructor
- /// @param source the cast expression source
- /// @param type the type
- /// @param expr the expr
- CastExpression(const Source& source,
- type::Type* type,
- std::unique_ptr<Expression> expr);
- /// Move constructor
- CastExpression(CastExpression&&);
- ~CastExpression() override;
-
- /// Sets the type
- /// @param type the type
- void set_type(type::Type* type) { type_ = std::move(type); }
- /// @returns the left side expression
- type::Type* type() const { return type_; }
-
- /// Sets the expr
- /// @param expr the expression
- void set_expr(std::unique_ptr<Expression> expr) { expr_ = std::move(expr); }
- /// @returns the expression
- Expression* expr() const { return expr_.get(); }
-
- /// @returns true if this is a cast expression
- bool IsCast() const override;
-
- /// @returns true if the node is valid
- 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:
- CastExpression(const CastExpression&) = delete;
-
- type::Type* type_ = nullptr;
- std::unique_ptr<Expression> expr_;
-};
-
-} // namespace ast
-} // namespace tint
-
-#endif // SRC_AST_CAST_EXPRESSION_H_
diff --git a/src/ast/cast_expression_test.cc b/src/ast/cast_expression_test.cc
deleted file mode 100644
index 4fe7566..0000000
--- a/src/ast/cast_expression_test.cc
+++ /dev/null
@@ -1,98 +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/cast_expression.h"
-
-#include "gtest/gtest.h"
-#include "src/ast/identifier_expression.h"
-#include "src/ast/type/f32_type.h"
-
-namespace tint {
-namespace ast {
-namespace {
-
-using CastExpressionTest = testing::Test;
-
-TEST_F(CastExpressionTest, Creation) {
- type::F32Type f32;
- auto expr = std::make_unique<IdentifierExpression>("expr");
- auto* expr_ptr = expr.get();
-
- CastExpression c(&f32, std::move(expr));
- EXPECT_EQ(c.type(), &f32);
- EXPECT_EQ(c.expr(), expr_ptr);
-}
-
-TEST_F(CastExpressionTest, Creation_withSource) {
- type::F32Type f32;
- auto expr = std::make_unique<IdentifierExpression>("expr");
-
- CastExpression c(Source{20, 2}, &f32, std::move(expr));
- auto src = c.source();
- EXPECT_EQ(src.line, 20u);
- EXPECT_EQ(src.column, 2u);
-}
-
-TEST_F(CastExpressionTest, IsCast) {
- CastExpression c;
- EXPECT_TRUE(c.IsCast());
-}
-
-TEST_F(CastExpressionTest, IsValid) {
- type::F32Type f32;
- auto expr = std::make_unique<IdentifierExpression>("expr");
-
- CastExpression c(&f32, std::move(expr));
- EXPECT_TRUE(c.IsValid());
-}
-
-TEST_F(CastExpressionTest, IsValid_MissingType) {
- auto expr = std::make_unique<IdentifierExpression>("expr");
-
- CastExpression c;
- c.set_expr(std::move(expr));
- EXPECT_FALSE(c.IsValid());
-}
-
-TEST_F(CastExpressionTest, IsValid_MissingExpression) {
- type::F32Type f32;
-
- CastExpression c;
- c.set_type(&f32);
- EXPECT_FALSE(c.IsValid());
-}
-
-TEST_F(CastExpressionTest, IsValid_InvalidExpression) {
- type::F32Type f32;
- auto expr = std::make_unique<IdentifierExpression>("");
- CastExpression c(&f32, std::move(expr));
- EXPECT_FALSE(c.IsValid());
-}
-
-TEST_F(CastExpressionTest, ToStr) {
- type::F32Type f32;
- auto expr = std::make_unique<IdentifierExpression>("expr");
-
- CastExpression c(Source{20, 2}, &f32, std::move(expr));
- std::ostringstream out;
- c.to_str(out, 2);
- EXPECT_EQ(out.str(), R"( Cast<__f32>(
- Identifier{expr}
- )
-)");
-}
-
-} // namespace
-} // namespace ast
-} // namespace tint
diff --git a/src/ast/expression.cc b/src/ast/expression.cc
index 2e1ad97..f58c138 100644
--- a/src/ast/expression.cc
+++ b/src/ast/expression.cc
@@ -20,7 +20,6 @@
#include "src/ast/binary_expression.h"
#include "src/ast/bitcast_expression.h"
#include "src/ast/call_expression.h"
-#include "src/ast/cast_expression.h"
#include "src/ast/constructor_expression.h"
#include "src/ast/identifier_expression.h"
#include "src/ast/member_accessor_expression.h"
@@ -96,11 +95,6 @@
return static_cast<const CallExpression*>(this);
}
-const CastExpression* Expression::AsCast() const {
- assert(IsCast());
- return static_cast<const CastExpression*>(this);
-}
-
const ConstructorExpression* Expression::AsConstructor() const {
assert(IsConstructor());
return static_cast<const ConstructorExpression*>(this);
@@ -141,11 +135,6 @@
return static_cast<CallExpression*>(this);
}
-CastExpression* Expression::AsCast() {
- assert(IsCast());
- return static_cast<CastExpression*>(this);
-}
-
ConstructorExpression* Expression::AsConstructor() {
assert(IsConstructor());
return static_cast<ConstructorExpression*>(this);
diff --git a/src/ast/expression.h b/src/ast/expression.h
index b69e9da..dc8ce58 100644
--- a/src/ast/expression.h
+++ b/src/ast/expression.h
@@ -28,7 +28,6 @@
class BinaryExpression;
class BitcastExpression;
class CallExpression;
-class CastExpression;
class IdentifierExpression;
class ConstructorExpression;
class MemberAccessorExpression;
@@ -70,8 +69,6 @@
const BitcastExpression* AsBitcast() const;
/// @returns the expression as a call
const CallExpression* AsCall() const;
- /// @returns the expression as a cast
- const CastExpression* AsCast() const;
/// @returns the expression as an identifier
const IdentifierExpression* AsIdentifier() const;
/// @returns the expression as an constructor
@@ -89,8 +86,6 @@
BitcastExpression* AsBitcast();
/// @returns the expression as a call
CallExpression* AsCall();
- /// @returns the expression as a cast
- CastExpression* AsCast();
/// @returns the expression as an identifier
IdentifierExpression* AsIdentifier();
/// @returns the expression as an constructor
diff --git a/src/ast/type/type.cc b/src/ast/type/type.cc
index a163014..7565d73 100644
--- a/src/ast/type/type.cc
+++ b/src/ast/type/type.cc
@@ -109,6 +109,10 @@
return false;
}
+bool Type::is_scalar() {
+ return is_float_scalar() || is_integer_scalar() || IsBool();
+}
+
bool Type::is_float_scalar() {
return IsF32();
}
diff --git a/src/ast/type/type.h b/src/ast/type/type.h
index e506c4d..5d0dbe7 100644
--- a/src/ast/type/type.h
+++ b/src/ast/type/type.h
@@ -90,6 +90,8 @@
/// @returns the unwrapped type
Type* UnwrapAliasPtrAlias();
+ /// @returns true if this type is a scalar
+ bool is_scalar();
/// @returns true if this type is a float scalar
bool is_float_scalar();
/// @returns true if this type is a float matrix
diff --git a/src/reader/spirv/function.cc b/src/reader/spirv/function.cc
index bc59df1..963a33d 100644
--- a/src/reader/spirv/function.cc
+++ b/src/reader/spirv/function.cc
@@ -36,7 +36,6 @@
#include "src/ast/call_expression.h"
#include "src/ast/call_statement.h"
#include "src/ast/case_statement.h"
-#include "src/ast/cast_expression.h"
#include "src/ast/continue_statement.h"
#include "src/ast/discard_statement.h"
#include "src/ast/else_statement.h"
@@ -3463,8 +3462,11 @@
return {};
}
- TypedExpression result(expr_type, std::make_unique<ast::CastExpression>(
- expr_type, std::move(arg_expr.expr)));
+ ast::ExpressionList params;
+ params.push_back(std::move(arg_expr.expr));
+ TypedExpression result(expr_type,
+ std::make_unique<ast::TypeConstructorExpression>(
+ expr_type, std::move(params)));
if (requested_type == expr_type) {
return result;
diff --git a/src/reader/spirv/function_conversion_test.cc b/src/reader/spirv/function_conversion_test.cc
index 37525b9..24a6a7a 100644
--- a/src/reader/spirv/function_conversion_test.cc
+++ b/src/reader/spirv/function_conversion_test.cc
@@ -243,9 +243,10 @@
none
__f32
{
- Cast<__f32>(
+ TypeConstructor{
+ __f32
Identifier{x_30}
- )
+ }
}
})"))
<< ToString(fe.ast_body());
@@ -269,11 +270,12 @@
none
__f32
{
- Cast<__f32>(
+ TypeConstructor{
+ __f32
Bitcast<__i32>{
Identifier{x_30}
}
- )
+ }
}
})"))
<< ToString(fe.ast_body());
@@ -297,9 +299,10 @@
none
__vec_2__f32
{
- Cast<__vec_2__f32>(
+ TypeConstructor{
+ __vec_2__f32
Identifier{x_30}
- )
+ }
}
})"))
<< ToString(fe.ast_body());
@@ -323,11 +326,12 @@
none
__vec_2__f32
{
- Cast<__vec_2__f32>(
+ TypeConstructor{
+ __vec_2__f32
Bitcast<__vec_2__i32>{
Identifier{x_30}
}
- )
+ }
}
})"))
<< ToString(fe.ast_body());
@@ -384,11 +388,12 @@
none
__f32
{
- Cast<__f32>(
+ TypeConstructor{
+ __f32
Bitcast<__u32>{
Identifier{x_30}
}
- )
+ }
}
})"))
<< ToString(fe.ast_body());
@@ -412,9 +417,10 @@
none
__f32
{
- Cast<__f32>(
+ TypeConstructor{
+ __f32
Identifier{x_30}
- )
+ }
}
})"))
<< ToString(fe.ast_body());
@@ -438,11 +444,12 @@
none
__vec_2__f32
{
- Cast<__vec_2__f32>(
+ TypeConstructor{
+ __vec_2__f32
Bitcast<__vec_2__u32>{
Identifier{x_30}
}
- )
+ }
}
})"))
<< ToString(fe.ast_body());
@@ -466,9 +473,10 @@
none
__vec_2__f32
{
- Cast<__vec_2__f32>(
+ TypeConstructor{
+ __vec_2__f32
Identifier{x_30}
- )
+ }
}
})"))
<< ToString(fe.ast_body());
@@ -526,9 +534,10 @@
none
__i32
{
- Cast<__i32>(
+ TypeConstructor{
+ __i32
Identifier{x_30}
- )
+ }
}
})"))
<< ToString(fe.ast_body());
@@ -553,9 +562,10 @@
__u32
{
Bitcast<__u32>{
- Cast<__i32>(
+ TypeConstructor{
+ __i32
Identifier{x_30}
- )
+ }
}
}
})"))
@@ -580,9 +590,10 @@
none
__vec_2__i32
{
- Cast<__vec_2__i32>(
+ TypeConstructor{
+ __vec_2__i32
Identifier{x_30}
- )
+ }
}
})"))
<< ToString(fe.ast_body());
@@ -607,9 +618,10 @@
__vec_2__u32
{
Bitcast<__vec_2__u32>{
- Cast<__vec_2__i32>(
+ TypeConstructor{
+ __vec_2__i32
Identifier{x_30}
- )
+ }
}
}
})"))
@@ -669,9 +681,10 @@
__i32
{
Bitcast<__i32>{
- Cast<__u32>(
+ TypeConstructor{
+ __u32
Identifier{x_30}
- )
+ }
}
}
})"))
@@ -696,9 +709,10 @@
none
__u32
{
- Cast<__u32>(
+ TypeConstructor{
+ __u32
Identifier{x_30}
- )
+ }
}
})"))
<< ToString(fe.ast_body());
@@ -723,9 +737,10 @@
__vec_2__i32
{
Bitcast<__vec_2__i32>{
- Cast<__vec_2__u32>(
+ TypeConstructor{
+ __vec_2__u32
Identifier{x_30}
- )
+ }
}
}
})"))
@@ -750,9 +765,10 @@
none
__vec_2__u32
{
- Cast<__vec_2__u32>(
+ TypeConstructor{
+ __vec_2__u32
Identifier{x_30}
- )
+ }
}
})"))
<< ToString(fe.ast_body());
diff --git a/src/reader/wgsl/lexer.cc b/src/reader/wgsl/lexer.cc
index 87b678f..42019fa 100644
--- a/src/reader/wgsl/lexer.cc
+++ b/src/reader/wgsl/lexer.cc
@@ -485,8 +485,6 @@
return {Token::Type::kBuiltin, source, "builtin"};
if (str == "case")
return {Token::Type::kCase, source, "case"};
- if (str == "cast")
- return {Token::Type::kCast, source, "cast"};
if (str == "compute")
return {Token::Type::kCompute, source, "compute"};
if (str == "const")
diff --git a/src/reader/wgsl/lexer_test.cc b/src/reader/wgsl/lexer_test.cc
index c3b456e..81e27e4 100644
--- a/src/reader/wgsl/lexer_test.cc
+++ b/src/reader/wgsl/lexer_test.cc
@@ -420,7 +420,6 @@
TokenData{"break", Token::Type::kBreak},
TokenData{"builtin", Token::Type::kBuiltin},
TokenData{"case", Token::Type::kCase},
- TokenData{"cast", Token::Type::kCast},
TokenData{"compute", Token::Type::kCompute},
TokenData{"const", Token::Type::kConst},
TokenData{"continue", Token::Type::kContinue},
diff --git a/src/reader/wgsl/parser_impl.cc b/src/reader/wgsl/parser_impl.cc
index 1616ea8..26044d4 100644
--- a/src/reader/wgsl/parser_impl.cc
+++ b/src/reader/wgsl/parser_impl.cc
@@ -26,7 +26,6 @@
#include "src/ast/builtin_decoration.h"
#include "src/ast/call_expression.h"
#include "src/ast/case_statement.h"
-#include "src/ast/cast_expression.h"
#include "src/ast/continue_statement.h"
#include "src/ast/decorated_variable.h"
#include "src/ast/discard_statement.h"
@@ -2767,8 +2766,7 @@
// | type_decl PAREN_LEFT argument_expression_list* PAREN_RIGHT
// | const_literal
// | paren_rhs_stmt
-// | CAST LESS_THAN type_decl GREATER_THAN paren_rhs_stmt
-// | AS LESS_THAN type_decl GREATER_THAN paren_rhs_stmt
+// | BITCAST LESS_THAN type_decl GREATER_THAN paren_rhs_stmt
std::unique_ptr<ast::Expression> ParserImpl::primary_expression() {
auto t = peek();
auto source = t.source();
@@ -2790,14 +2788,14 @@
return paren;
}
- if (t.IsCast() || t.IsBitcast()) {
+ if (t.IsBitcast()) {
auto src = t;
next(); // Consume the peek
t = next();
if (!t.IsLessThan()) {
- set_error(t, "missing < for " + src.to_name() + " expression");
+ set_error(t, "missing < for bitcast expression");
return nullptr;
}
@@ -2805,13 +2803,13 @@
if (has_error())
return nullptr;
if (type == nullptr) {
- set_error(peek(), "missing type for " + src.to_name() + " expression");
+ set_error(peek(), "missing type for bitcast expression");
return nullptr;
}
t = next();
if (!t.IsGreaterThan()) {
- set_error(t, "missing > for " + src.to_name() + " expression");
+ set_error(t, "missing > for bitcast expression");
return nullptr;
}
@@ -2823,14 +2821,8 @@
return nullptr;
}
- if (src.IsCast()) {
- return std::make_unique<ast::CastExpression>(source, type,
- std::move(params));
- } else {
- return std::make_unique<ast::BitcastExpression>(source, type,
- std::move(params));
- }
-
+ return std::make_unique<ast::BitcastExpression>(source, type,
+ std::move(params));
} else if (t.IsIdentifier()) {
next(); // Consume the peek
diff --git a/src/reader/wgsl/parser_impl_primary_expression_test.cc b/src/reader/wgsl/parser_impl_primary_expression_test.cc
index bd459e1..49737e4 100644
--- a/src/reader/wgsl/parser_impl_primary_expression_test.cc
+++ b/src/reader/wgsl/parser_impl_primary_expression_test.cc
@@ -16,7 +16,6 @@
#include "src/ast/array_accessor_expression.h"
#include "src/ast/bitcast_expression.h"
#include "src/ast/bool_literal.h"
-#include "src/ast/cast_expression.h"
#include "src/ast/identifier_expression.h"
#include "src/ast/scalar_constructor_expression.h"
#include "src/ast/sint_literal.h"
@@ -170,73 +169,19 @@
TEST_F(ParserImplTest, PrimaryExpression_Cast) {
auto* f32_type = tm()->Get(std::make_unique<ast::type::F32Type>());
- auto* p = parser("cast<f32>(1)");
+ auto* p = parser("f32(1)");
auto e = p->primary_expression();
ASSERT_FALSE(p->has_error()) << p->error();
ASSERT_NE(e, nullptr);
- ASSERT_TRUE(e->IsCast());
+ ASSERT_TRUE(e->IsConstructor());
+ ASSERT_TRUE(e->AsConstructor()->IsTypeConstructor());
- auto* c = e->AsCast();
+ auto* c = e->AsConstructor()->AsTypeConstructor();
ASSERT_EQ(c->type(), f32_type);
+ ASSERT_EQ(c->values().size(), 1u);
- ASSERT_TRUE(c->expr()->IsConstructor());
- ASSERT_TRUE(c->expr()->AsConstructor()->IsScalarConstructor());
-}
-
-TEST_F(ParserImplTest, PrimaryExpression_Cast_MissingGreaterThan) {
- auto* p = parser("cast<f32(1)");
- auto e = p->primary_expression();
- ASSERT_TRUE(p->has_error());
- ASSERT_EQ(e, nullptr);
- EXPECT_EQ(p->error(), "1:9: missing > for cast expression");
-}
-
-TEST_F(ParserImplTest, PrimaryExpression_Cast_MissingType) {
- auto* p = parser("cast<>(1)");
- auto e = p->primary_expression();
- ASSERT_TRUE(p->has_error());
- ASSERT_EQ(e, nullptr);
- EXPECT_EQ(p->error(), "1:6: missing type for cast expression");
-}
-
-TEST_F(ParserImplTest, PrimaryExpression_Cast_InvalidType) {
- auto* p = parser("cast<invalid>(1)");
- auto e = p->primary_expression();
- ASSERT_TRUE(p->has_error());
- ASSERT_EQ(e, nullptr);
- EXPECT_EQ(p->error(), "1:6: unknown type alias 'invalid'");
-}
-
-TEST_F(ParserImplTest, PrimaryExpression_Cast_MissingLeftParen) {
- auto* p = parser("cast<f32>1)");
- auto e = p->primary_expression();
- ASSERT_TRUE(p->has_error());
- ASSERT_EQ(e, nullptr);
- EXPECT_EQ(p->error(), "1:10: expected (");
-}
-
-TEST_F(ParserImplTest, PrimaryExpression_Cast_MissingRightParen) {
- auto* p = parser("cast<f32>(1");
- auto e = p->primary_expression();
- ASSERT_TRUE(p->has_error());
- ASSERT_EQ(e, nullptr);
- EXPECT_EQ(p->error(), "1:12: expected )");
-}
-
-TEST_F(ParserImplTest, PrimaryExpression_Cast_MissingExpression) {
- auto* p = parser("cast<f32>()");
- auto e = p->primary_expression();
- ASSERT_TRUE(p->has_error());
- ASSERT_EQ(e, nullptr);
- EXPECT_EQ(p->error(), "1:11: unable to parse expression");
-}
-
-TEST_F(ParserImplTest, PrimaryExpression_Cast_InvalidExpression) {
- auto* p = parser("cast<f32>(if (a) {})");
- auto e = p->primary_expression();
- ASSERT_TRUE(p->has_error());
- ASSERT_EQ(e, nullptr);
- EXPECT_EQ(p->error(), "1:11: unable to parse expression");
+ ASSERT_TRUE(c->values()[0]->IsConstructor());
+ ASSERT_TRUE(c->values()[0]->AsConstructor()->IsScalarConstructor());
}
TEST_F(ParserImplTest, PrimaryExpression_Bitcast) {
diff --git a/src/reader/wgsl/token.cc b/src/reader/wgsl/token.cc
index f836c0c..76d88e9 100644
--- a/src/reader/wgsl/token.cc
+++ b/src/reader/wgsl/token.cc
@@ -121,8 +121,6 @@
return "builtin";
case Token::Type::kCase:
return "case";
- case Token::Type::kCast:
- return "cast";
case Token::Type::kCompute:
return "compute";
case Token::Type::kConst:
diff --git a/src/reader/wgsl/token.h b/src/reader/wgsl/token.h
index ebd39e6..184d1d9 100644
--- a/src/reader/wgsl/token.h
+++ b/src/reader/wgsl/token.h
@@ -132,8 +132,6 @@
kBuiltin,
/// A 'case'
kCase,
- /// A 'cast'
- kCast,
/// A 'compute'
kCompute,
/// A 'const'
@@ -509,8 +507,6 @@
bool IsBuiltin() const { return type_ == Type::kBuiltin; }
/// @returns true if token is a 'case'
bool IsCase() const { return type_ == Type::kCase; }
- /// @returns true if token is a 'cast'
- bool IsCast() const { return type_ == Type::kCast; }
/// @returns true if token is a 'sampler_comparison'
bool IsComparisonSampler() const { return type_ == Type::kComparisonSampler; }
/// @returns true if token is a 'compute'
diff --git a/src/type_determiner.cc b/src/type_determiner.cc
index dedf1f0..5a412a4 100644
--- a/src/type_determiner.cc
+++ b/src/type_determiner.cc
@@ -26,7 +26,6 @@
#include "src/ast/call_expression.h"
#include "src/ast/call_statement.h"
#include "src/ast/case_statement.h"
-#include "src/ast/cast_expression.h"
#include "src/ast/continue_statement.h"
#include "src/ast/else_statement.h"
#include "src/ast/identifier_expression.h"
@@ -305,9 +304,6 @@
if (expr->IsCall()) {
return DetermineCall(expr->AsCall());
}
- if (expr->IsCast()) {
- return DetermineCast(expr->AsCast());
- }
if (expr->IsConstructor()) {
return DetermineConstructor(expr->AsConstructor());
}
@@ -737,15 +733,6 @@
return true;
}
-bool TypeDeterminer::DetermineCast(ast::CastExpression* expr) {
- if (!DetermineResultType(expr->expr())) {
- return false;
- }
-
- expr->set_result_type(expr->type());
- return true;
-}
-
bool TypeDeterminer::DetermineConstructor(ast::ConstructorExpression* expr) {
if (expr->IsTypeConstructor()) {
auto* ty = expr->AsTypeConstructor();
diff --git a/src/type_determiner.h b/src/type_determiner.h
index 6ba3833..482a439b 100644
--- a/src/type_determiner.h
+++ b/src/type_determiner.h
@@ -30,7 +30,6 @@
class BinaryExpression;
class BitcastExpression;
class CallExpression;
-class CastExpression;
class ConstructorExpression;
class Function;
class IdentifierExpression;
@@ -120,7 +119,6 @@
bool DetermineBinary(ast::BinaryExpression* expr);
bool DetermineBitcast(ast::BitcastExpression* expr);
bool DetermineCall(ast::CallExpression* expr);
- bool DetermineCast(ast::CastExpression* expr);
bool DetermineConstructor(ast::ConstructorExpression* expr);
bool DetermineIdentifier(ast::IdentifierExpression* expr);
bool DetermineIntrinsic(ast::IdentifierExpression* name,
diff --git a/src/type_determiner_test.cc b/src/type_determiner_test.cc
index 9a6bd20..d60b376 100644
--- a/src/type_determiner_test.cc
+++ b/src/type_determiner_test.cc
@@ -29,7 +29,6 @@
#include "src/ast/call_expression.h"
#include "src/ast/call_statement.h"
#include "src/ast/case_statement.h"
-#include "src/ast/cast_expression.h"
#include "src/ast/continue_statement.h"
#include "src/ast/else_statement.h"
#include "src/ast/float_literal.h"
@@ -686,8 +685,11 @@
TEST_F(TypeDeterminerTest, Expr_Cast) {
ast::type::F32Type f32;
- ast::CastExpression cast(&f32,
- std::make_unique<ast::IdentifierExpression>("name"));
+
+ ast::ExpressionList params;
+ params.push_back(std::make_unique<ast::IdentifierExpression>("name"));
+
+ ast::TypeConstructorExpression cast(&f32, std::move(params));
EXPECT_TRUE(td()->DetermineResultType(&cast));
ASSERT_NE(cast.result_type(), nullptr);
diff --git a/src/validator_test.cc b/src/validator_test.cc
index b97b58a..62ada22 100644
--- a/src/validator_test.cc
+++ b/src/validator_test.cc
@@ -24,7 +24,6 @@
#include "src/ast/call_expression.h"
#include "src/ast/call_statement.h"
#include "src/ast/case_statement.h"
-#include "src/ast/cast_expression.h"
#include "src/ast/continue_statement.h"
#include "src/ast/else_statement.h"
#include "src/ast/float_literal.h"
diff --git a/src/writer/hlsl/generator_impl.cc b/src/writer/hlsl/generator_impl.cc
index 68a33ca..6e91894 100644
--- a/src/writer/hlsl/generator_impl.cc
+++ b/src/writer/hlsl/generator_impl.cc
@@ -24,7 +24,6 @@
#include "src/ast/call_expression.h"
#include "src/ast/call_statement.h"
#include "src/ast/case_statement.h"
-#include "src/ast/cast_expression.h"
#include "src/ast/decorated_variable.h"
#include "src/ast/else_statement.h"
#include "src/ast/float_literal.h"
@@ -724,21 +723,6 @@
return true;
}
-bool GeneratorImpl::EmitCast(std::ostream& pre,
- std::ostream& out,
- ast::CastExpression* expr) {
- if (!EmitType(out, expr->type(), "")) {
- return false;
- }
-
- out << "(";
- if (!EmitExpression(pre, out, expr->expr())) {
- return false;
- }
- out << ")";
- return true;
-}
-
bool GeneratorImpl::EmitCase(std::ostream& out, ast::CaseStatement* stmt) {
make_indent(out);
@@ -868,9 +852,6 @@
if (expr->IsCall()) {
return EmitCall(pre, out, expr->AsCall());
}
- if (expr->IsCast()) {
- return EmitCast(pre, out, expr->AsCast());
- }
if (expr->IsConstructor()) {
return EmitConstructor(pre, out, expr->AsConstructor());
}
diff --git a/src/writer/hlsl/generator_impl.h b/src/writer/hlsl/generator_impl.h
index e30c363..1e231a6 100644
--- a/src/writer/hlsl/generator_impl.h
+++ b/src/writer/hlsl/generator_impl.h
@@ -128,14 +128,6 @@
/// @param stmt the statement
/// @returns true if the statment was emitted successfully
bool EmitCase(std::ostream& out, ast::CaseStatement* stmt);
- /// Handles generating a cast expression
- /// @param pre the preamble for the expression stream
- /// @param out the output of the expression stream
- /// @param expr the cast expression
- /// @returns true if the cast was emitted
- bool EmitCast(std::ostream& pre,
- std::ostream& out,
- ast::CastExpression* expr);
/// Handles generating constructor expressions
/// @param pre the preamble for the expression stream
/// @param out the output of the expression stream
diff --git a/src/writer/hlsl/generator_impl_cast_test.cc b/src/writer/hlsl/generator_impl_cast_test.cc
index e646e07..b92b104 100644
--- a/src/writer/hlsl/generator_impl_cast_test.cc
+++ b/src/writer/hlsl/generator_impl_cast_test.cc
@@ -14,11 +14,11 @@
#include <memory>
-#include "src/ast/cast_expression.h"
#include "src/ast/identifier_expression.h"
#include "src/ast/module.h"
#include "src/ast/type/f32_type.h"
#include "src/ast/type/vector_type.h"
+#include "src/ast/type_constructor_expression.h"
#include "src/writer/hlsl/test_helper.h"
namespace tint {
@@ -30,8 +30,11 @@
TEST_F(HlslGeneratorImplTest_Cast, EmitExpression_Cast_Scalar) {
ast::type::F32Type f32;
- auto id = std::make_unique<ast::IdentifierExpression>("id");
- ast::CastExpression cast(&f32, std::move(id));
+
+ ast::ExpressionList params;
+ params.push_back(std::make_unique<ast::IdentifierExpression>("id"));
+
+ ast::TypeConstructorExpression cast(&f32, std::move(params));
ASSERT_TRUE(gen().EmitExpression(pre(), out(), &cast)) << gen().error();
EXPECT_EQ(result(), "float(id)");
@@ -41,8 +44,10 @@
ast::type::F32Type f32;
ast::type::VectorType vec3(&f32, 3);
- auto id = std::make_unique<ast::IdentifierExpression>("id");
- ast::CastExpression cast(&vec3, std::move(id));
+ ast::ExpressionList params;
+ params.push_back(std::make_unique<ast::IdentifierExpression>("id"));
+
+ ast::TypeConstructorExpression cast(&vec3, std::move(params));
ASSERT_TRUE(gen().EmitExpression(pre(), out(), &cast)) << gen().error();
EXPECT_EQ(result(), "vector<float, 3>(id)");
diff --git a/src/writer/msl/generator_impl.cc b/src/writer/msl/generator_impl.cc
index 45773b9..6f26ffa 100644
--- a/src/writer/msl/generator_impl.cc
+++ b/src/writer/msl/generator_impl.cc
@@ -24,7 +24,6 @@
#include "src/ast/call_expression.h"
#include "src/ast/call_statement.h"
#include "src/ast/case_statement.h"
-#include "src/ast/cast_expression.h"
#include "src/ast/continue_statement.h"
#include "src/ast/decorated_variable.h"
#include "src/ast/else_statement.h"
@@ -744,19 +743,6 @@
return true;
}
-bool GeneratorImpl::EmitCast(ast::CastExpression* expr) {
- if (!EmitType(expr->type(), "")) {
- return false;
- }
-
- out_ << "(";
- if (!EmitExpression(expr->expr())) {
- return false;
- }
- out_ << ")";
- return true;
-}
-
bool GeneratorImpl::EmitConstructor(ast::ConstructorExpression* expr) {
if (expr->IsScalarConstructor()) {
return EmitScalarConstructor(expr->AsScalarConstructor());
@@ -992,9 +978,6 @@
if (expr->IsCall()) {
return EmitCall(expr->AsCall());
}
- if (expr->IsCast()) {
- return EmitCast(expr->AsCast());
- }
if (expr->IsConstructor()) {
return EmitConstructor(expr->AsConstructor());
}
diff --git a/src/writer/msl/generator_impl.h b/src/writer/msl/generator_impl.h
index cc458d2..f33a143 100644
--- a/src/writer/msl/generator_impl.h
+++ b/src/writer/msl/generator_impl.h
@@ -98,10 +98,6 @@
/// @param stmt the statement
/// @returns true if the statement was emitted successfully
bool EmitCase(ast::CaseStatement* stmt);
- /// Handles generating a cast expression
- /// @param expr the cast expression
- /// @returns true if the cast was emitted
- bool EmitCast(ast::CastExpression* expr);
/// Handles generating constructor expressions
/// @param expr the constructor expression
/// @returns true if the expression was emitted
diff --git a/src/writer/msl/generator_impl_cast_test.cc b/src/writer/msl/generator_impl_cast_test.cc
index f760335..aea7840 100644
--- a/src/writer/msl/generator_impl_cast_test.cc
+++ b/src/writer/msl/generator_impl_cast_test.cc
@@ -15,11 +15,11 @@
#include <memory>
#include "gtest/gtest.h"
-#include "src/ast/cast_expression.h"
#include "src/ast/identifier_expression.h"
#include "src/ast/module.h"
#include "src/ast/type/f32_type.h"
#include "src/ast/type/vector_type.h"
+#include "src/ast/type_constructor_expression.h"
#include "src/writer/msl/generator_impl.h"
namespace tint {
@@ -31,8 +31,11 @@
TEST_F(MslGeneratorImplTest, EmitExpression_Cast_Scalar) {
ast::type::F32Type f32;
- auto id = std::make_unique<ast::IdentifierExpression>("id");
- ast::CastExpression cast(&f32, std::move(id));
+
+ ast::ExpressionList params;
+ params.push_back(std::make_unique<ast::IdentifierExpression>("id"));
+
+ ast::TypeConstructorExpression cast(&f32, std::move(params));
ast::Module m;
GeneratorImpl g(&m);
@@ -44,8 +47,10 @@
ast::type::F32Type f32;
ast::type::VectorType vec3(&f32, 3);
- auto id = std::make_unique<ast::IdentifierExpression>("id");
- ast::CastExpression cast(&vec3, std::move(id));
+ ast::ExpressionList params;
+ params.push_back(std::make_unique<ast::IdentifierExpression>("id"));
+
+ ast::TypeConstructorExpression cast(&vec3, std::move(params));
ast::Module m;
GeneratorImpl g(&m);
diff --git a/src/writer/spirv/builder.cc b/src/writer/spirv/builder.cc
index b2fcdf1..f879bef 100644
--- a/src/writer/spirv/builder.cc
+++ b/src/writer/spirv/builder.cc
@@ -30,7 +30,6 @@
#include "src/ast/call_expression.h"
#include "src/ast/call_statement.h"
#include "src/ast/case_statement.h"
-#include "src/ast/cast_expression.h"
#include "src/ast/constructor_expression.h"
#include "src/ast/decorated_variable.h"
#include "src/ast/else_statement.h"
@@ -465,9 +464,6 @@
if (expr->IsCall()) {
return GenerateCallExpression(expr->AsCall());
}
- if (expr->IsCast()) {
- return GenerateCastExpression(expr->AsCast());
- }
if (expr->IsConstructor()) {
return GenerateConstructorExpression(expr->AsConstructor(), false);
}
@@ -1054,32 +1050,20 @@
uint32_t Builder::GenerateTypeConstructorExpression(
ast::TypeConstructorExpression* init,
bool is_global_init) {
- auto type_id = GenerateTypeIfNeeded(init->type());
- if (type_id == 0) {
- return 0;
- }
+ auto& values = init->values();
// Generate the zero initializer if there are no values provided.
- if (init->values().empty()) {
+ if (values.empty()) {
ast::NullLiteral nl(init->type()->UnwrapPtrIfNeeded());
return GenerateLiteralIfNeeded(&nl);
}
- auto* result_type = init->type()->UnwrapPtrIfNeeded();
- if (result_type->IsVector()) {
- result_type = result_type->AsVector()->type();
- } else if (result_type->IsArray()) {
- result_type = result_type->AsArray()->type();
- } else if (result_type->IsMatrix()) {
- result_type = result_type->AsMatrix()->type();
- }
-
std::ostringstream out;
out << "__const";
OperandList ops;
bool constructor_is_const = true;
- for (const auto& e : init->values()) {
+ for (const auto& e : values) {
if (!e->IsConstructor()) {
if (is_global_init) {
error_ = "constructor must be a constant expression";
@@ -1089,9 +1073,37 @@
}
}
+ auto* result_type = init->type()->UnwrapAliasPtrAlias();
+
+ bool can_cast_or_copy = result_type->is_scalar();
+ if (result_type->IsVector() && result_type->AsVector()->type()->is_scalar()) {
+ auto* value_type = values[0]->result_type()->UnwrapAliasPtrAlias();
+ can_cast_or_copy =
+ (value_type->IsVector() &&
+ value_type->AsVector()->type()->is_scalar() &&
+ result_type->AsVector()->size() == value_type->AsVector()->size());
+ }
+ if (can_cast_or_copy) {
+ return GenerateCastOrCopy(result_type, values[0].get());
+ }
+
+ auto type_id = GenerateTypeIfNeeded(init->type());
+ if (type_id == 0) {
+ return 0;
+ }
+
bool result_is_constant_composite = constructor_is_const;
bool result_is_spec_composite = false;
- for (const auto& e : init->values()) {
+
+ if (result_type->IsVector()) {
+ result_type = result_type->AsVector()->type();
+ } else if (result_type->IsArray()) {
+ result_type = result_type->AsArray()->type();
+ } else if (result_type->IsMatrix()) {
+ result_type = result_type->AsMatrix()->type();
+ }
+
+ for (const auto& e : values) {
uint32_t id = 0;
if (constructor_is_const) {
id = GenerateConstructorExpression(e->AsConstructor(), is_global_init);
@@ -1104,54 +1116,54 @@
}
auto* value_type = e->result_type()->UnwrapPtrIfNeeded();
+ if (result_type == value_type) {
+ out << "_" << id;
+ ops.push_back(Operand::Int(id));
+ continue;
+ }
+
+ // Both scalars, but not the same type so we need to generate a conversion
+ // of the value.
+ if (value_type->is_scalar() && result_type->is_scalar()) {
+ id = GenerateCastOrCopy(result_type, values[0].get());
+ out << "_" << id;
+ ops.push_back(Operand::Int(id));
+ continue;
+ }
// When handling vectors as the values there a few cases to take into
// consideration:
// 1. Module scoped vec3<f32>(vec2<f32>(1, 2), 3) -> OpSpecConstantOp
- // 2. Function scoped vec3<f32>(vec2<f32>(1, 2), 3) -> OpCompositeExtract
+ // 2. Function scoped vec3<f32>(vec2<f32>(1, 2), 3) -> OpCompositeExtract
// 3. Either array<vec3<f32>, 1>(vec3<f32>(1, 2, 3)) -> use the ID.
+ // -> handled above
+ //
+ // For cases 1 and 2, if the type is different we also may need to insert
+ // a type cast.
if (value_type->IsVector()) {
auto* vec = value_type->AsVector();
auto* vec_type = vec->type();
- // If the value we want is the same as what we have, use it directly.
- // This maps to case 3.
- if (result_type == value_type) {
- out << "_" << id;
- ops.push_back(Operand::Int(id));
- } else if (!is_global_init) {
- // A non-global initializer. Case 2.
- auto value_type_id = GenerateTypeIfNeeded(vec_type);
- if (value_type_id == 0) {
- return 0;
- }
+ auto value_type_id = GenerateTypeIfNeeded(vec_type);
+ if (value_type_id == 0) {
+ return 0;
+ }
- for (uint32_t i = 0; i < vec->size(); ++i) {
- auto extract = result_op();
- auto extract_id = extract.to_i();
+ for (uint32_t i = 0; i < vec->size(); ++i) {
+ auto extract = result_op();
+ auto extract_id = extract.to_i();
+ if (!is_global_init) {
+ // A non-global initializer. Case 2.
push_function_inst(spv::Op::OpCompositeExtract,
{Operand::Int(value_type_id), extract,
Operand::Int(id), Operand::Int(i)});
- out << "_" << extract_id;
- ops.push_back(Operand::Int(extract_id));
-
// We no longer have a constant composite, but have to do a
// composite construction as these calls are inside a function.
result_is_constant_composite = false;
- }
- } else {
- // A global initializer, must use OpSpecConstantOp. Case 1.
- auto value_type_id = GenerateTypeIfNeeded(vec_type);
- if (value_type_id == 0) {
- return 0;
- }
-
- for (uint32_t i = 0; i < vec->size(); ++i) {
- auto extract = result_op();
- auto extract_id = extract.to_i();
-
+ } else {
+ // A global initializer, must use OpSpecConstantOp. Case 1.
auto idx_id = GenerateU32Literal(i);
if (idx_id == 0) {
return 0;
@@ -1161,15 +1173,15 @@
Operand::Int(SpvOpCompositeExtract), Operand::Int(id),
Operand::Int(idx_id)});
- out << "_" << extract_id;
- ops.push_back(Operand::Int(extract_id));
-
result_is_spec_composite = true;
}
+
+ out << "_" << extract_id;
+ ops.push_back(Operand::Int(extract_id));
}
} else {
- out << "_" << id;
- ops.push_back(Operand::Int(id));
+ error_ = "Unhandled type cast value type";
+ return 0;
}
}
@@ -1192,9 +1204,69 @@
} else {
push_function_inst(spv::Op::OpCompositeConstruct, ops);
}
+
return result.to_i();
}
+uint32_t Builder::GenerateCastOrCopy(ast::type::Type* to_type,
+ ast::Expression* from_expr) {
+ auto result = result_op();
+ auto result_id = result.to_i();
+
+ auto result_type_id = GenerateTypeIfNeeded(to_type);
+ if (result_type_id == 0) {
+ return 0;
+ }
+
+ auto val_id = GenerateExpression(from_expr);
+ if (val_id == 0) {
+ return 0;
+ }
+ val_id = GenerateLoadIfNeeded(from_expr->result_type(), val_id);
+
+ auto* from_type = from_expr->result_type()->UnwrapPtrIfNeeded();
+
+ spv::Op op = spv::Op::OpNop;
+ if ((from_type->IsI32() && to_type->IsF32()) ||
+ (from_type->is_signed_integer_vector() && to_type->is_float_vector())) {
+ op = spv::Op::OpConvertSToF;
+ } else if ((from_type->IsU32() && to_type->IsF32()) ||
+ (from_type->is_unsigned_integer_vector() &&
+ to_type->is_float_vector())) {
+ op = spv::Op::OpConvertUToF;
+ } else if ((from_type->IsF32() && to_type->IsI32()) ||
+ (from_type->is_float_vector() &&
+ to_type->is_signed_integer_vector())) {
+ op = spv::Op::OpConvertFToS;
+ } else if ((from_type->IsF32() && to_type->IsU32()) ||
+ (from_type->is_float_vector() &&
+ to_type->is_unsigned_integer_vector())) {
+ op = spv::Op::OpConvertFToU;
+ } else if ((from_type->IsBool() && to_type->IsBool()) ||
+ (from_type->IsU32() && to_type->IsU32()) ||
+ (from_type->IsI32() && to_type->IsI32()) ||
+ (from_type->IsF32() && to_type->IsF32())) {
+ op = spv::Op::OpCopyObject;
+ } else if ((from_type->IsI32() && to_type->IsU32()) ||
+ (from_type->IsU32() && to_type->IsI32()) ||
+ (from_type->is_signed_integer_vector() &&
+ to_type->is_unsigned_integer_vector()) ||
+ (from_type->is_unsigned_integer_vector() &&
+ to_type->is_integer_scalar_or_vector())) {
+ op = spv::Op::OpBitcast;
+ }
+ if (op == spv::Op::OpNop) {
+ error_ = "unable to determine conversion type for cast, from: " +
+ from_type->type_name() + " to: " + to_type->type_name();
+ return 0;
+ }
+
+ push_function_inst(
+ op, {Operand::Int(result_type_id), result, Operand::Int(val_id)});
+
+ return result_id;
+}
+
uint32_t Builder::GenerateLiteralIfNeeded(ast::Literal* lit) {
auto type_id = GenerateTypeIfNeeded(lit->type());
if (type_id == 0) {
@@ -1726,70 +1798,6 @@
return result_id;
}
-uint32_t Builder::GenerateCastExpression(ast::CastExpression* cast) {
- auto result = result_op();
- auto result_id = result.to_i();
-
- auto result_type_id = GenerateTypeIfNeeded(cast->result_type());
- if (result_type_id == 0) {
- return 0;
- }
-
- auto val_id = GenerateExpression(cast->expr());
- if (val_id == 0) {
- return 0;
- }
- val_id = GenerateLoadIfNeeded(cast->expr()->result_type(), val_id);
-
- auto* to_type = cast->result_type()->UnwrapPtrIfNeeded();
- auto* from_type = cast->expr()->result_type()->UnwrapPtrIfNeeded();
-
- spv::Op op = spv::Op::OpNop;
- if ((from_type->IsI32() && to_type->IsF32()) ||
- (from_type->is_signed_integer_vector() && to_type->is_float_vector())) {
- op = spv::Op::OpConvertSToF;
- } else if ((from_type->IsU32() && to_type->IsF32()) ||
- (from_type->is_unsigned_integer_vector() &&
- to_type->is_float_vector())) {
- op = spv::Op::OpConvertUToF;
- } else if ((from_type->IsF32() && to_type->IsI32()) ||
- (from_type->is_float_vector() &&
- to_type->is_signed_integer_vector())) {
- op = spv::Op::OpConvertFToS;
- } else if ((from_type->IsF32() && to_type->IsU32()) ||
- (from_type->is_float_vector() &&
- to_type->is_unsigned_integer_vector())) {
- op = spv::Op::OpConvertFToU;
- } else if ((from_type->IsU32() && to_type->IsU32()) ||
- (from_type->IsI32() && to_type->IsI32()) ||
- (from_type->IsF32() && to_type->IsF32()) ||
- (from_type->is_unsigned_integer_vector() &&
- to_type->is_unsigned_integer_vector()) ||
- (from_type->is_signed_integer_vector() &&
- to_type->is_signed_integer_vector()) ||
- (from_type->is_float_vector() && to_type->is_float_vector())) {
- op = spv::Op::OpCopyObject;
- } else if ((from_type->IsI32() && to_type->IsU32()) ||
- (from_type->IsU32() && to_type->IsI32()) ||
- (from_type->is_signed_integer_vector() &&
- to_type->is_unsigned_integer_vector()) ||
- (from_type->is_unsigned_integer_vector() &&
- to_type->is_integer_scalar_or_vector())) {
- op = spv::Op::OpBitcast;
- }
-
- if (op == spv::Op::OpNop) {
- error_ = "unable to determine conversion type for cast, from: " +
- from_type->type_name() + " to: " + to_type->type_name();
- return 0;
- }
-
- push_function_inst(
- op, {Operand::Int(result_type_id), result, Operand::Int(val_id)});
-
- return result_id;
-}
-
bool Builder::GenerateConditionalBlock(
ast::Expression* cond,
const ast::BlockStatement* true_body,
diff --git a/src/writer/spirv/builder.h b/src/writer/spirv/builder.h
index a0c33d6..ccfce39 100644
--- a/src/writer/spirv/builder.h
+++ b/src/writer/spirv/builder.h
@@ -306,10 +306,12 @@
uint32_t GenerateSampledImage(ast::type::Type* texture_type,
Operand texture_operand,
Operand sampler_operand);
- /// Generates a cast expression
- /// @param expr the expression to generate
+ /// Generates a cast or object copy for the expression result
+ /// @param to_type the type we're casting too
+ /// @param from_expr the expression to cast
/// @returns the expression ID on success or 0 otherwise
- uint32_t GenerateCastExpression(ast::CastExpression* expr);
+ uint32_t GenerateCastOrCopy(ast::type::Type* to_type,
+ ast::Expression* from_expr);
/// Generates a loop statement
/// @param stmt the statement to generate
/// @returns true on successful generation
diff --git a/src/writer/spirv/builder_cast_expression_test.cc b/src/writer/spirv/builder_cast_expression_test.cc
deleted file mode 100644
index 675bb20..0000000
--- a/src/writer/spirv/builder_cast_expression_test.cc
+++ /dev/null
@@ -1,554 +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/ast/cast_expression.h"
-#include "src/ast/float_literal.h"
-#include "src/ast/identifier_expression.h"
-#include "src/ast/module.h"
-#include "src/ast/scalar_constructor_expression.h"
-#include "src/ast/sint_literal.h"
-#include "src/ast/type/f32_type.h"
-#include "src/ast/type/i32_type.h"
-#include "src/ast/type/u32_type.h"
-#include "src/ast/type/vector_type.h"
-#include "src/ast/uint_literal.h"
-#include "src/context.h"
-#include "src/type_determiner.h"
-#include "src/writer/spirv/builder.h"
-#include "src/writer/spirv/spv_dump.h"
-
-namespace tint {
-namespace writer {
-namespace spirv {
-namespace {
-
-using BuilderTest = testing::Test;
-
-TEST_F(BuilderTest, Cast_FloatToU32) {
- ast::type::U32Type u32;
- ast::type::F32Type f32;
-
- ast::CastExpression cast(&u32,
- std::make_unique<ast::ScalarConstructorExpression>(
- std::make_unique<ast::FloatLiteral>(&f32, 2.4)));
-
- Context ctx;
- ast::Module mod;
- TypeDeterminer td(&ctx, &mod);
- ASSERT_TRUE(td.DetermineResultType(&cast)) << td.error();
-
- Builder b(&mod);
- b.push_function(Function{});
- EXPECT_EQ(b.GenerateCastExpression(&cast), 1u);
-
- EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeInt 32 0
-%3 = OpTypeFloat 32
-%4 = OpConstant %3 2.4000001
-)");
- EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
- R"(%1 = OpConvertFToU %2 %4
-)");
-}
-
-TEST_F(BuilderTest, Cast_FloatToI32) {
- ast::type::I32Type i32;
- ast::type::F32Type f32;
-
- ast::CastExpression cast(&i32,
- std::make_unique<ast::ScalarConstructorExpression>(
- std::make_unique<ast::FloatLiteral>(&f32, 2.4)));
-
- Context ctx;
- ast::Module mod;
- TypeDeterminer td(&ctx, &mod);
- ASSERT_TRUE(td.DetermineResultType(&cast)) << td.error();
-
- Builder b(&mod);
- b.push_function(Function{});
- EXPECT_EQ(b.GenerateCastExpression(&cast), 1u);
-
- EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeInt 32 1
-%3 = OpTypeFloat 32
-%4 = OpConstant %3 2.4000001
-)");
- EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
- R"(%1 = OpConvertFToS %2 %4
-)");
-}
-
-TEST_F(BuilderTest, Cast_I32ToFloat) {
- ast::type::I32Type i32;
- ast::type::F32Type f32;
-
- ast::CastExpression cast(&f32,
- std::make_unique<ast::ScalarConstructorExpression>(
- std::make_unique<ast::SintLiteral>(&i32, 2)));
-
- Context ctx;
- ast::Module mod;
- TypeDeterminer td(&ctx, &mod);
- ASSERT_TRUE(td.DetermineResultType(&cast)) << td.error();
-
- Builder b(&mod);
- b.push_function(Function{});
- EXPECT_EQ(b.GenerateCastExpression(&cast), 1u);
-
- EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 32
-%3 = OpTypeInt 32 1
-%4 = OpConstant %3 2
-)");
- EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
- R"(%1 = OpConvertSToF %2 %4
-)");
-}
-
-TEST_F(BuilderTest, Cast_U32ToFloat) {
- ast::type::U32Type u32;
- ast::type::F32Type f32;
-
- ast::CastExpression cast(&f32,
- std::make_unique<ast::ScalarConstructorExpression>(
- std::make_unique<ast::UintLiteral>(&u32, 2)));
-
- Context ctx;
- ast::Module mod;
- TypeDeterminer td(&ctx, &mod);
- ASSERT_TRUE(td.DetermineResultType(&cast)) << td.error();
-
- Builder b(&mod);
- b.push_function(Function{});
- EXPECT_EQ(b.GenerateCastExpression(&cast), 1u);
-
- EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 32
-%3 = OpTypeInt 32 0
-%4 = OpConstant %3 2
-)");
- EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
- R"(%1 = OpConvertUToF %2 %4
-)");
-}
-
-TEST_F(BuilderTest, Cast_WithLoad) {
- ast::type::F32Type f32;
- ast::type::I32Type i32;
-
- // var i : i32 = 1;
- // cast<f32>(i);
- auto var =
- std::make_unique<ast::Variable>("i", ast::StorageClass::kPrivate, &i32);
-
- ast::CastExpression cast(&f32,
- std::make_unique<ast::IdentifierExpression>("i"));
-
- Context ctx;
- ast::Module mod;
- TypeDeterminer td(&ctx, &mod);
- td.RegisterVariableForTesting(var.get());
- ASSERT_TRUE(td.DetermineResultType(&cast)) << td.error();
-
- Builder b(&mod);
- b.push_function(Function{});
- ASSERT_TRUE(b.GenerateGlobalVariable(var.get())) << b.error();
- EXPECT_EQ(b.GenerateCastExpression(&cast), 5u) << b.error();
-
- EXPECT_EQ(DumpInstructions(b.types()), R"(%3 = OpTypeInt 32 1
-%2 = OpTypePointer Private %3
-%4 = OpConstantNull %3
-%1 = OpVariable %2 Private %4
-%6 = OpTypeFloat 32
-)");
- EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
- R"(%7 = OpLoad %3 %1
-%5 = OpConvertSToF %6 %7
-)");
-}
-
-TEST_F(BuilderTest, Cast_WithAlias) {
- ast::type::I32Type i32;
- ast::type::F32Type f32;
-
- // type Int = i32
- // cast<Int>(1.f)
-
- ast::type::AliasType alias("Int", &i32);
-
- ast::CastExpression cast(&alias,
- std::make_unique<ast::ScalarConstructorExpression>(
- std::make_unique<ast::FloatLiteral>(&f32, 2.3)));
-
- Context ctx;
- ast::Module mod;
- TypeDeterminer td(&ctx, &mod);
- ASSERT_TRUE(td.DetermineResultType(&cast)) << td.error();
-
- Builder b(&mod);
- b.push_function(Function{});
- EXPECT_EQ(b.GenerateCastExpression(&cast), 1u);
-
- EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeInt 32 1
-%3 = OpTypeFloat 32
-%4 = OpConstant %3 2.29999995
-)");
- EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
- R"(%1 = OpConvertFToS %2 %4
-)");
-}
-
-TEST_F(BuilderTest, Cast_I32ToU32) {
- ast::type::U32Type u32;
- ast::type::I32Type i32;
-
- ast::CastExpression cast(&u32,
- std::make_unique<ast::ScalarConstructorExpression>(
- std::make_unique<ast::SintLiteral>(&i32, 2)));
-
- Context ctx;
- ast::Module mod;
- TypeDeterminer td(&ctx, &mod);
- ASSERT_TRUE(td.DetermineResultType(&cast)) << td.error();
-
- Builder b(&mod);
- b.push_function(Function{});
- EXPECT_EQ(b.GenerateCastExpression(&cast), 1u);
-
- EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeInt 32 0
-%3 = OpTypeInt 32 1
-%4 = OpConstant %3 2
-)");
- EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
- R"(%1 = OpBitcast %2 %4
-)");
-}
-
-TEST_F(BuilderTest, Cast_U32ToI32) {
- ast::type::U32Type u32;
- ast::type::I32Type i32;
-
- ast::CastExpression cast(&i32,
- std::make_unique<ast::ScalarConstructorExpression>(
- std::make_unique<ast::UintLiteral>(&u32, 2)));
-
- Context ctx;
- ast::Module mod;
- TypeDeterminer td(&ctx, &mod);
- ASSERT_TRUE(td.DetermineResultType(&cast)) << td.error();
-
- Builder b(&mod);
- b.push_function(Function{});
- EXPECT_EQ(b.GenerateCastExpression(&cast), 1u);
-
- EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeInt 32 1
-%3 = OpTypeInt 32 0
-%4 = OpConstant %3 2
-)");
- EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
- R"(%1 = OpBitcast %2 %4
-)");
-}
-
-TEST_F(BuilderTest, Cast_I32ToI32) {
- ast::type::I32Type i32;
-
- ast::CastExpression cast(&i32,
- std::make_unique<ast::ScalarConstructorExpression>(
- std::make_unique<ast::SintLiteral>(&i32, 2)));
-
- Context ctx;
- ast::Module mod;
- TypeDeterminer td(&ctx, &mod);
- ASSERT_TRUE(td.DetermineResultType(&cast)) << td.error();
-
- Builder b(&mod);
- b.push_function(Function{});
- EXPECT_EQ(b.GenerateCastExpression(&cast), 1u);
-
- EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeInt 32 1
-%3 = OpConstant %2 2
-)");
- EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
- R"(%1 = OpCopyObject %2 %3
-)");
-}
-
-TEST_F(BuilderTest, Cast_U32ToU32) {
- ast::type::U32Type u32;
-
- ast::CastExpression cast(&u32,
- std::make_unique<ast::ScalarConstructorExpression>(
- std::make_unique<ast::UintLiteral>(&u32, 2)));
-
- Context ctx;
- ast::Module mod;
- TypeDeterminer td(&ctx, &mod);
- ASSERT_TRUE(td.DetermineResultType(&cast)) << td.error();
-
- Builder b(&mod);
- b.push_function(Function{});
- EXPECT_EQ(b.GenerateCastExpression(&cast), 1u);
-
- EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeInt 32 0
-%3 = OpConstant %2 2
-)");
- EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
- R"(%1 = OpCopyObject %2 %3
-)");
-}
-
-TEST_F(BuilderTest, Cast_F32ToF32) {
- ast::type::F32Type f32;
-
- ast::CastExpression cast(&f32,
- std::make_unique<ast::ScalarConstructorExpression>(
- std::make_unique<ast::FloatLiteral>(&f32, 2.0)));
-
- Context ctx;
- ast::Module mod;
- TypeDeterminer td(&ctx, &mod);
- ASSERT_TRUE(td.DetermineResultType(&cast)) << td.error();
-
- Builder b(&mod);
- b.push_function(Function{});
- EXPECT_EQ(b.GenerateCastExpression(&cast), 1u);
-
- EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 32
-%3 = OpConstant %2 2
-)");
- EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
- R"(%1 = OpCopyObject %2 %3
-)");
-}
-
-TEST_F(BuilderTest, Cast_Vectors_I32_to_F32) {
- ast::type::I32Type i32;
- ast::type::VectorType ivec3(&i32, 3);
- ast::type::F32Type f32;
- ast::type::VectorType fvec3(&f32, 3);
-
- auto var =
- std::make_unique<ast::Variable>("i", ast::StorageClass::kPrivate, &ivec3);
-
- ast::CastExpression cast(&fvec3,
- std::make_unique<ast::IdentifierExpression>("i"));
-
- Context ctx;
- ast::Module mod;
- TypeDeterminer td(&ctx, &mod);
- td.RegisterVariableForTesting(var.get());
- ASSERT_TRUE(td.DetermineResultType(&cast)) << td.error();
-
- Builder b(&mod);
- b.push_function(Function{});
- ASSERT_TRUE(b.GenerateGlobalVariable(var.get())) << b.error();
- EXPECT_EQ(b.GenerateCastExpression(&cast), 6u) << b.error();
-
- EXPECT_EQ(DumpInstructions(b.types()), R"(%4 = OpTypeInt 32 1
-%3 = OpTypeVector %4 3
-%2 = OpTypePointer Private %3
-%5 = OpConstantNull %3
-%1 = OpVariable %2 Private %5
-%8 = OpTypeFloat 32
-%7 = OpTypeVector %8 3
-)");
- EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
- R"(%9 = OpLoad %3 %1
-%6 = OpConvertSToF %7 %9
-)");
-}
-
-TEST_F(BuilderTest, Cast_Vectors_U32_to_F32) {
- ast::type::U32Type u32;
- ast::type::VectorType uvec3(&u32, 3);
- ast::type::F32Type f32;
- ast::type::VectorType fvec3(&f32, 3);
-
- auto var =
- std::make_unique<ast::Variable>("i", ast::StorageClass::kPrivate, &uvec3);
-
- ast::CastExpression cast(&fvec3,
- std::make_unique<ast::IdentifierExpression>("i"));
-
- Context ctx;
- ast::Module mod;
- TypeDeterminer td(&ctx, &mod);
- td.RegisterVariableForTesting(var.get());
- ASSERT_TRUE(td.DetermineResultType(&cast)) << td.error();
-
- Builder b(&mod);
- b.push_function(Function{});
- ASSERT_TRUE(b.GenerateGlobalVariable(var.get())) << b.error();
- EXPECT_EQ(b.GenerateCastExpression(&cast), 6u) << b.error();
-
- EXPECT_EQ(DumpInstructions(b.types()), R"(%4 = OpTypeInt 32 0
-%3 = OpTypeVector %4 3
-%2 = OpTypePointer Private %3
-%5 = OpConstantNull %3
-%1 = OpVariable %2 Private %5
-%8 = OpTypeFloat 32
-%7 = OpTypeVector %8 3
-)");
- EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
- R"(%9 = OpLoad %3 %1
-%6 = OpConvertUToF %7 %9
-)");
-}
-
-TEST_F(BuilderTest, Cast_Vectors_F32_to_I32) {
- ast::type::I32Type i32;
- ast::type::VectorType ivec3(&i32, 3);
- ast::type::F32Type f32;
- ast::type::VectorType fvec3(&f32, 3);
-
- auto var =
- std::make_unique<ast::Variable>("i", ast::StorageClass::kPrivate, &fvec3);
-
- ast::CastExpression cast(&ivec3,
- std::make_unique<ast::IdentifierExpression>("i"));
-
- Context ctx;
- ast::Module mod;
- TypeDeterminer td(&ctx, &mod);
- td.RegisterVariableForTesting(var.get());
- ASSERT_TRUE(td.DetermineResultType(&cast)) << td.error();
-
- Builder b(&mod);
- b.push_function(Function{});
- ASSERT_TRUE(b.GenerateGlobalVariable(var.get())) << b.error();
- EXPECT_EQ(b.GenerateCastExpression(&cast), 6u) << b.error();
-
- EXPECT_EQ(DumpInstructions(b.types()), R"(%4 = OpTypeFloat 32
-%3 = OpTypeVector %4 3
-%2 = OpTypePointer Private %3
-%5 = OpConstantNull %3
-%1 = OpVariable %2 Private %5
-%8 = OpTypeInt 32 1
-%7 = OpTypeVector %8 3
-)");
- EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
- R"(%9 = OpLoad %3 %1
-%6 = OpConvertFToS %7 %9
-)");
-}
-
-TEST_F(BuilderTest, Cast_Vectors_F32_to_U32) {
- ast::type::U32Type u32;
- ast::type::VectorType uvec3(&u32, 3);
- ast::type::F32Type f32;
- ast::type::VectorType fvec3(&f32, 3);
-
- auto var =
- std::make_unique<ast::Variable>("i", ast::StorageClass::kPrivate, &fvec3);
-
- ast::CastExpression cast(&uvec3,
- std::make_unique<ast::IdentifierExpression>("i"));
-
- Context ctx;
- ast::Module mod;
- TypeDeterminer td(&ctx, &mod);
- td.RegisterVariableForTesting(var.get());
- ASSERT_TRUE(td.DetermineResultType(&cast)) << td.error();
-
- Builder b(&mod);
- b.push_function(Function{});
- ASSERT_TRUE(b.GenerateGlobalVariable(var.get())) << b.error();
- EXPECT_EQ(b.GenerateCastExpression(&cast), 6u) << b.error();
-
- EXPECT_EQ(DumpInstructions(b.types()), R"(%4 = OpTypeFloat 32
-%3 = OpTypeVector %4 3
-%2 = OpTypePointer Private %3
-%5 = OpConstantNull %3
-%1 = OpVariable %2 Private %5
-%8 = OpTypeInt 32 0
-%7 = OpTypeVector %8 3
-)");
- EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
- R"(%9 = OpLoad %3 %1
-%6 = OpConvertFToU %7 %9
-)");
-}
-
-TEST_F(BuilderTest, Cast_Vectors_U32_to_U32) {
- ast::type::U32Type u32;
- ast::type::VectorType uvec3(&u32, 3);
-
- auto var =
- std::make_unique<ast::Variable>("i", ast::StorageClass::kPrivate, &uvec3);
-
- ast::CastExpression cast(&uvec3,
- std::make_unique<ast::IdentifierExpression>("i"));
-
- Context ctx;
- ast::Module mod;
- TypeDeterminer td(&ctx, &mod);
- td.RegisterVariableForTesting(var.get());
- ASSERT_TRUE(td.DetermineResultType(&cast)) << td.error();
-
- Builder b(&mod);
- b.push_function(Function{});
- ASSERT_TRUE(b.GenerateGlobalVariable(var.get())) << b.error();
- EXPECT_EQ(b.GenerateCastExpression(&cast), 6u) << b.error();
-
- EXPECT_EQ(DumpInstructions(b.types()), R"(%4 = OpTypeInt 32 0
-%3 = OpTypeVector %4 3
-%2 = OpTypePointer Private %3
-%5 = OpConstantNull %3
-%1 = OpVariable %2 Private %5
-)");
- EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
- R"(%7 = OpLoad %3 %1
-%6 = OpCopyObject %3 %7
-)");
-}
-
-TEST_F(BuilderTest, Cast_Vectors_I32_to_U32) {
- ast::type::U32Type u32;
- ast::type::VectorType uvec3(&u32, 3);
- ast::type::I32Type i32;
- ast::type::VectorType ivec3(&i32, 3);
-
- auto var =
- std::make_unique<ast::Variable>("i", ast::StorageClass::kPrivate, &ivec3);
-
- ast::CastExpression cast(&uvec3,
- std::make_unique<ast::IdentifierExpression>("i"));
-
- Context ctx;
- ast::Module mod;
- TypeDeterminer td(&ctx, &mod);
- td.RegisterVariableForTesting(var.get());
- ASSERT_TRUE(td.DetermineResultType(&cast)) << td.error();
-
- Builder b(&mod);
- b.push_function(Function{});
- ASSERT_TRUE(b.GenerateGlobalVariable(var.get())) << b.error();
- EXPECT_EQ(b.GenerateCastExpression(&cast), 6u) << b.error();
-
- EXPECT_EQ(DumpInstructions(b.types()), R"(%4 = OpTypeInt 32 1
-%3 = OpTypeVector %4 3
-%2 = OpTypePointer Private %3
-%5 = OpConstantNull %3
-%1 = OpVariable %2 Private %5
-%8 = OpTypeInt 32 0
-%7 = OpTypeVector %8 3
-)");
- EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
- R"(%9 = OpLoad %3 %1
-%6 = OpBitcast %7 %9
-)");
-}
-
-} // namespace
-} // namespace spirv
-} // namespace writer
-} // namespace tint
diff --git a/src/writer/spirv/builder_constructor_expression_test.cc b/src/writer/spirv/builder_constructor_expression_test.cc
index 3a16281..f1468db 100644
--- a/src/writer/spirv/builder_constructor_expression_test.cc
+++ b/src/writer/spirv/builder_constructor_expression_test.cc
@@ -18,12 +18,25 @@
#include "spirv/unified1/spirv.h"
#include "spirv/unified1/spirv.hpp11"
#include "src/ast/binary_expression.h"
+#include "src/ast/bool_literal.h"
#include "src/ast/float_literal.h"
#include "src/ast/identifier_expression.h"
+#include "src/ast/member_accessor_expression.h"
#include "src/ast/scalar_constructor_expression.h"
+#include "src/ast/sint_literal.h"
+#include "src/ast/struct.h"
+#include "src/ast/struct_decoration.h"
+#include "src/ast/struct_member.h"
+#include "src/ast/type/array_type.h"
+#include "src/ast/type/bool_type.h"
#include "src/ast/type/f32_type.h"
+#include "src/ast/type/i32_type.h"
+#include "src/ast/type/matrix_type.h"
+#include "src/ast/type/struct_type.h"
+#include "src/ast/type/u32_type.h"
#include "src/ast/type/vector_type.h"
#include "src/ast/type_constructor_expression.h"
+#include "src/ast/uint_literal.h"
#include "src/context.h"
#include "src/type_determiner.h"
#include "src/writer/spirv/builder.h"
@@ -82,31 +95,40 @@
)");
}
-TEST_F(BuilderTest, Constructor_Type_ZeroInit) {
+TEST_F(BuilderTest, Constructor_Type_WithAlias) {
+ ast::type::I32Type i32;
ast::type::F32Type f32;
- ast::type::VectorType vec(&f32, 2);
- ast::ExpressionList vals;
- ast::TypeConstructorExpression t(&vec, std::move(vals));
+ // type Int = i32
+ // cast<Int>(1.f)
+
+ ast::type::AliasType alias("Int", &i32);
+
+ ast::ExpressionList params;
+ params.push_back(std::make_unique<ast::ScalarConstructorExpression>(
+ std::make_unique<ast::FloatLiteral>(&f32, 2.3)));
+
+ ast::TypeConstructorExpression cast(&alias, std::move(params));
Context ctx;
ast::Module mod;
TypeDeterminer td(&ctx, &mod);
- EXPECT_TRUE(td.DetermineResultType(&t)) << td.error();
+ ASSERT_TRUE(td.DetermineResultType(&cast)) << td.error();
Builder b(&mod);
b.push_function(Function{});
+ EXPECT_EQ(b.GenerateExpression(&cast), 1u);
- EXPECT_EQ(b.GenerateConstructorExpression(&t, false), 3u);
- ASSERT_FALSE(b.has_error()) << b.error();
-
- EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 32
-%1 = OpTypeVector %2 2
-%3 = OpConstantNull %1
+ EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeInt 32 1
+%3 = OpTypeFloat 32
+%4 = OpConstant %3 2.29999995
+)");
+ EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
+ R"(%1 = OpConvertFToS %2 %4
)");
}
-TEST_F(BuilderTest, Constructor_Type_NonConstructorParam) {
+TEST_F(BuilderTest, Constructor_Type_IdentifierExpression_Param) {
ast::type::F32Type f32;
ast::type::VectorType vec(&f32, 2);
@@ -130,7 +152,7 @@
b.push_function(Function{});
ASSERT_TRUE(b.GenerateFunctionVariable(var.get())) << b.error();
- EXPECT_EQ(b.GenerateConstructorExpression(&t, false), 8u);
+ EXPECT_EQ(b.GenerateExpression(&t), 8u);
ASSERT_FALSE(b.has_error()) << b.error();
EXPECT_EQ(DumpInstructions(b.types()), R"(%3 = OpTypeFloat 32
@@ -149,81 +171,7 @@
)");
}
-TEST_F(BuilderTest, Constructor_Type_NonConstVector) {
- ast::type::F32Type f32;
- ast::type::VectorType vec2(&f32, 2);
- ast::type::VectorType vec4(&f32, 4);
-
- auto var = std::make_unique<ast::Variable>(
- "ident", ast::StorageClass::kFunction, &vec2);
-
- ast::ExpressionList vals;
- vals.push_back(std::make_unique<ast::ScalarConstructorExpression>(
- std::make_unique<ast::FloatLiteral>(&f32, 1.0f)));
- vals.push_back(std::make_unique<ast::ScalarConstructorExpression>(
- std::make_unique<ast::FloatLiteral>(&f32, 1.0f)));
- vals.push_back(std::make_unique<ast::IdentifierExpression>("ident"));
-
- ast::TypeConstructorExpression t(&vec4, std::move(vals));
-
- Context ctx;
- ast::Module mod;
- TypeDeterminer td(&ctx, &mod);
- td.RegisterVariableForTesting(var.get());
- EXPECT_TRUE(td.DetermineResultType(&t)) << td.error();
-
- Builder b(&mod);
- b.push_function(Function{});
- ASSERT_TRUE(b.GenerateFunctionVariable(var.get())) << b.error();
-
- EXPECT_EQ(b.GenerateConstructorExpression(&t, false), 11u);
- ASSERT_FALSE(b.has_error()) << b.error();
-
- EXPECT_EQ(DumpInstructions(b.types()), R"(%4 = OpTypeFloat 32
-%3 = OpTypeVector %4 2
-%2 = OpTypePointer Function %3
-%5 = OpConstantNull %3
-%6 = OpTypeVector %4 4
-%7 = OpConstant %4 1
-)");
- EXPECT_EQ(DumpInstructions(b.functions()[0].variables()),
- R"(%1 = OpVariable %2 Function %5
-)");
-
- EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
- R"(%8 = OpLoad %3 %1
-%9 = OpCompositeExtract %4 %8 0
-%10 = OpCompositeExtract %4 %8 1
-%11 = OpCompositeConstruct %6 %7 %7 %9 %10
-)");
-}
-
-TEST_F(BuilderTest, Constructor_Type_Dedups) {
- ast::type::F32Type f32;
- ast::type::VectorType vec(&f32, 3);
-
- ast::ExpressionList vals;
- vals.push_back(std::make_unique<ast::ScalarConstructorExpression>(
- std::make_unique<ast::FloatLiteral>(&f32, 1.0f)));
- vals.push_back(std::make_unique<ast::ScalarConstructorExpression>(
- std::make_unique<ast::FloatLiteral>(&f32, 1.0f)));
- vals.push_back(std::make_unique<ast::ScalarConstructorExpression>(
- std::make_unique<ast::FloatLiteral>(&f32, 3.0f)));
-
- ast::TypeConstructorExpression t(&vec, std::move(vals));
-
- Context ctx;
- ast::Module mod;
- TypeDeterminer td(&ctx, &mod);
- EXPECT_TRUE(td.DetermineResultType(&t)) << td.error();
-
- Builder b(&mod);
- EXPECT_EQ(b.GenerateConstructorExpression(&t, true), 5u);
- EXPECT_EQ(b.GenerateConstructorExpression(&t, true), 5u);
- ASSERT_FALSE(b.has_error()) << b.error();
-}
-
-TEST_F(BuilderTest, Constructor_NonConst_Type_Fails) {
+TEST_F(BuilderTest, Constructor_Type_NonConst_Value_Fails) {
ast::type::F32Type f32;
ast::type::VectorType vec(&f32, 2);
auto rel = std::make_unique<ast::BinaryExpression>(
@@ -247,6 +195,1607 @@
EXPECT_EQ(b.error(), R"(constructor must be a constant expression)");
}
+TEST_F(BuilderTest, Constructor_Type_Bool_With_Bool) {
+ ast::type::BoolType bool_type;
+
+ ast::ExpressionList vals;
+ vals.push_back(std::make_unique<ast::ScalarConstructorExpression>(
+ std::make_unique<ast::BoolLiteral>(&bool_type, true)));
+
+ ast::TypeConstructorExpression t(&bool_type, std::move(vals));
+
+ Context ctx;
+ ast::Module mod;
+ TypeDeterminer td(&ctx, &mod);
+ ASSERT_TRUE(td.DetermineResultType(&t)) << td.error();
+
+ Builder b(&mod);
+ b.push_function(Function{});
+
+ EXPECT_EQ(b.GenerateExpression(&t), 1u);
+ ASSERT_FALSE(b.has_error()) << b.error();
+
+ EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeBool
+%3 = OpConstantTrue %2
+)");
+ EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
+ R"(%1 = OpCopyObject %2 %3
+)");
+}
+
+TEST_F(BuilderTest, Constructor_Type_I32_With_I32) {
+ ast::type::I32Type i32;
+
+ ast::ExpressionList params;
+ params.push_back(std::make_unique<ast::ScalarConstructorExpression>(
+ std::make_unique<ast::SintLiteral>(&i32, 2)));
+
+ ast::TypeConstructorExpression cast(&i32, std::move(params));
+
+ Context ctx;
+ ast::Module mod;
+ TypeDeterminer td(&ctx, &mod);
+ ASSERT_TRUE(td.DetermineResultType(&cast)) << td.error();
+
+ Builder b(&mod);
+ b.push_function(Function{});
+ EXPECT_EQ(b.GenerateExpression(&cast), 1u);
+
+ EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeInt 32 1
+%3 = OpConstant %2 2
+)");
+ EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
+ R"(%1 = OpCopyObject %2 %3
+)");
+}
+
+TEST_F(BuilderTest, Constructor_Type_U32_With_U32) {
+ ast::type::U32Type u32;
+
+ ast::ExpressionList params;
+ params.push_back(std::make_unique<ast::ScalarConstructorExpression>(
+ std::make_unique<ast::UintLiteral>(&u32, 2)));
+
+ ast::TypeConstructorExpression cast(&u32, std::move(params));
+
+ Context ctx;
+ ast::Module mod;
+ TypeDeterminer td(&ctx, &mod);
+ ASSERT_TRUE(td.DetermineResultType(&cast)) << td.error();
+
+ Builder b(&mod);
+ b.push_function(Function{});
+ EXPECT_EQ(b.GenerateExpression(&cast), 1u);
+
+ EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeInt 32 0
+%3 = OpConstant %2 2
+)");
+ EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
+ R"(%1 = OpCopyObject %2 %3
+)");
+}
+
+TEST_F(BuilderTest, Constructor_Type_F32_With_F32) {
+ ast::type::F32Type f32;
+
+ ast::ExpressionList params;
+ params.push_back(std::make_unique<ast::ScalarConstructorExpression>(
+ std::make_unique<ast::FloatLiteral>(&f32, 2.0)));
+
+ ast::TypeConstructorExpression cast(&f32, std::move(params));
+
+ Context ctx;
+ ast::Module mod;
+ TypeDeterminer td(&ctx, &mod);
+ ASSERT_TRUE(td.DetermineResultType(&cast)) << td.error();
+
+ Builder b(&mod);
+ b.push_function(Function{});
+ EXPECT_EQ(b.GenerateExpression(&cast), 1u);
+
+ EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 32
+%3 = OpConstant %2 2
+)");
+ EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
+ R"(%1 = OpCopyObject %2 %3
+)");
+}
+
+TEST_F(BuilderTest, Constructor_Type_Vec2_With_F32_F32) {
+ ast::type::F32Type f32;
+ ast::type::VectorType vec(&f32, 2);
+
+ ast::ExpressionList params;
+ params.push_back(std::make_unique<ast::ScalarConstructorExpression>(
+ std::make_unique<ast::FloatLiteral>(&f32, 2.0)));
+ params.push_back(std::make_unique<ast::ScalarConstructorExpression>(
+ std::make_unique<ast::FloatLiteral>(&f32, 2.0)));
+
+ ast::TypeConstructorExpression cast(&vec, std::move(params));
+
+ Context ctx;
+ ast::Module mod;
+ TypeDeterminer td(&ctx, &mod);
+ ASSERT_TRUE(td.DetermineResultType(&cast)) << td.error();
+
+ Builder b(&mod);
+ b.push_function(Function{});
+ EXPECT_EQ(b.GenerateExpression(&cast), 4u);
+
+ EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 32
+%1 = OpTypeVector %2 2
+%3 = OpConstant %2 2
+%4 = OpConstantComposite %1 %3 %3
+)");
+}
+
+TEST_F(BuilderTest, Constructor_Type_Vec3_With_F32_F32_F32) {
+ ast::type::F32Type f32;
+ ast::type::VectorType vec(&f32, 3);
+
+ ast::ExpressionList params;
+ params.push_back(std::make_unique<ast::ScalarConstructorExpression>(
+ std::make_unique<ast::FloatLiteral>(&f32, 2.0)));
+ params.push_back(std::make_unique<ast::ScalarConstructorExpression>(
+ std::make_unique<ast::FloatLiteral>(&f32, 2.0)));
+ params.push_back(std::make_unique<ast::ScalarConstructorExpression>(
+ std::make_unique<ast::FloatLiteral>(&f32, 2.0)));
+
+ ast::TypeConstructorExpression cast(&vec, std::move(params));
+
+ Context ctx;
+ ast::Module mod;
+ TypeDeterminer td(&ctx, &mod);
+ ASSERT_TRUE(td.DetermineResultType(&cast)) << td.error();
+
+ Builder b(&mod);
+ b.push_function(Function{});
+ EXPECT_EQ(b.GenerateExpression(&cast), 4u);
+
+ EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 32
+%1 = OpTypeVector %2 3
+%3 = OpConstant %2 2
+%4 = OpConstantComposite %1 %3 %3 %3
+)");
+}
+
+TEST_F(BuilderTest, Constructor_Type_Vec3_With_F32_Vec2) {
+ ast::type::F32Type f32;
+ ast::type::VectorType vec2(&f32, 2);
+ ast::type::VectorType vec3(&f32, 3);
+
+ ast::ExpressionList vec_params;
+ vec_params.push_back(std::make_unique<ast::ScalarConstructorExpression>(
+ std::make_unique<ast::FloatLiteral>(&f32, 2.0)));
+ vec_params.push_back(std::make_unique<ast::ScalarConstructorExpression>(
+ std::make_unique<ast::FloatLiteral>(&f32, 2.0)));
+
+ ast::ExpressionList params;
+ params.push_back(std::make_unique<ast::ScalarConstructorExpression>(
+ std::make_unique<ast::FloatLiteral>(&f32, 2.0)));
+ params.push_back(std::make_unique<ast::TypeConstructorExpression>(
+ &vec2, std::move(vec_params)));
+
+ ast::TypeConstructorExpression cast(&vec3, std::move(params));
+
+ Context ctx;
+ ast::Module mod;
+ TypeDeterminer td(&ctx, &mod);
+ ASSERT_TRUE(td.DetermineResultType(&cast)) << td.error();
+
+ Builder b(&mod);
+ b.push_function(Function{});
+ EXPECT_EQ(b.GenerateExpression(&cast), 8u);
+
+ EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 32
+%1 = OpTypeVector %2 3
+%3 = OpConstant %2 2
+%4 = OpTypeVector %2 2
+%5 = OpConstantComposite %4 %3 %3
+)");
+ EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
+ R"(%6 = OpCompositeExtract %2 %5 0
+%7 = OpCompositeExtract %2 %5 1
+%8 = OpCompositeConstruct %1 %3 %6 %7
+)");
+}
+
+TEST_F(BuilderTest, Constructor_Type_Vec3_With_Vec2_F32) {
+ ast::type::F32Type f32;
+ ast::type::VectorType vec2(&f32, 2);
+ ast::type::VectorType vec3(&f32, 3);
+
+ ast::ExpressionList vec_params;
+ vec_params.push_back(std::make_unique<ast::ScalarConstructorExpression>(
+ std::make_unique<ast::FloatLiteral>(&f32, 2.0)));
+ vec_params.push_back(std::make_unique<ast::ScalarConstructorExpression>(
+ std::make_unique<ast::FloatLiteral>(&f32, 2.0)));
+
+ ast::ExpressionList params;
+ params.push_back(std::make_unique<ast::TypeConstructorExpression>(
+ &vec2, std::move(vec_params)));
+ params.push_back(std::make_unique<ast::ScalarConstructorExpression>(
+ std::make_unique<ast::FloatLiteral>(&f32, 2.0)));
+
+ ast::TypeConstructorExpression cast(&vec3, std::move(params));
+
+ Context ctx;
+ ast::Module mod;
+ TypeDeterminer td(&ctx, &mod);
+ ASSERT_TRUE(td.DetermineResultType(&cast)) << td.error();
+
+ Builder b(&mod);
+ b.push_function(Function{});
+ EXPECT_EQ(b.GenerateExpression(&cast), 8u);
+
+ EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 32
+%1 = OpTypeVector %2 3
+%3 = OpTypeVector %2 2
+%4 = OpConstant %2 2
+%5 = OpConstantComposite %3 %4 %4
+)");
+ EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
+ R"(%6 = OpCompositeExtract %2 %5 0
+%7 = OpCompositeExtract %2 %5 1
+%8 = OpCompositeConstruct %1 %6 %7 %4
+)");
+}
+
+TEST_F(BuilderTest, Constructor_Type_Vec4_With_F32_F32_F32_F32) {
+ ast::type::F32Type f32;
+ ast::type::VectorType vec(&f32, 4);
+
+ ast::ExpressionList params;
+ params.push_back(std::make_unique<ast::ScalarConstructorExpression>(
+ std::make_unique<ast::FloatLiteral>(&f32, 2.0)));
+ params.push_back(std::make_unique<ast::ScalarConstructorExpression>(
+ std::make_unique<ast::FloatLiteral>(&f32, 2.0)));
+ params.push_back(std::make_unique<ast::ScalarConstructorExpression>(
+ std::make_unique<ast::FloatLiteral>(&f32, 2.0)));
+ params.push_back(std::make_unique<ast::ScalarConstructorExpression>(
+ std::make_unique<ast::FloatLiteral>(&f32, 2.0)));
+
+ ast::TypeConstructorExpression cast(&vec, std::move(params));
+
+ Context ctx;
+ ast::Module mod;
+ TypeDeterminer td(&ctx, &mod);
+ ASSERT_TRUE(td.DetermineResultType(&cast)) << td.error();
+
+ Builder b(&mod);
+ b.push_function(Function{});
+ EXPECT_EQ(b.GenerateExpression(&cast), 4u);
+
+ EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 32
+%1 = OpTypeVector %2 4
+%3 = OpConstant %2 2
+%4 = OpConstantComposite %1 %3 %3 %3 %3
+)");
+}
+
+TEST_F(BuilderTest, Constructor_Type_Vec4_With_F32_F32_Vec2) {
+ ast::type::F32Type f32;
+ ast::type::VectorType vec2(&f32, 2);
+ ast::type::VectorType vec4(&f32, 4);
+
+ ast::ExpressionList vec_params;
+ vec_params.push_back(std::make_unique<ast::ScalarConstructorExpression>(
+ std::make_unique<ast::FloatLiteral>(&f32, 2.0)));
+ vec_params.push_back(std::make_unique<ast::ScalarConstructorExpression>(
+ std::make_unique<ast::FloatLiteral>(&f32, 2.0)));
+
+ ast::ExpressionList params;
+ params.push_back(std::make_unique<ast::ScalarConstructorExpression>(
+ std::make_unique<ast::FloatLiteral>(&f32, 2.0)));
+ params.push_back(std::make_unique<ast::ScalarConstructorExpression>(
+ std::make_unique<ast::FloatLiteral>(&f32, 2.0)));
+ params.push_back(std::make_unique<ast::TypeConstructorExpression>(
+ &vec2, std::move(vec_params)));
+
+ ast::TypeConstructorExpression cast(&vec4, std::move(params));
+
+ Context ctx;
+ ast::Module mod;
+ TypeDeterminer td(&ctx, &mod);
+ ASSERT_TRUE(td.DetermineResultType(&cast)) << td.error();
+
+ Builder b(&mod);
+ b.push_function(Function{});
+ EXPECT_EQ(b.GenerateExpression(&cast), 8u);
+
+ EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 32
+%1 = OpTypeVector %2 4
+%3 = OpConstant %2 2
+%4 = OpTypeVector %2 2
+%5 = OpConstantComposite %4 %3 %3
+)");
+ EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
+ R"(%6 = OpCompositeExtract %2 %5 0
+%7 = OpCompositeExtract %2 %5 1
+%8 = OpCompositeConstruct %1 %3 %3 %6 %7
+)");
+}
+
+TEST_F(BuilderTest, Constructor_Type_Vec4_With_F32_Vec2_F32) {
+ ast::type::F32Type f32;
+ ast::type::VectorType vec2(&f32, 2);
+ ast::type::VectorType vec4(&f32, 4);
+
+ ast::ExpressionList vec_params;
+ vec_params.push_back(std::make_unique<ast::ScalarConstructorExpression>(
+ std::make_unique<ast::FloatLiteral>(&f32, 2.0)));
+ vec_params.push_back(std::make_unique<ast::ScalarConstructorExpression>(
+ std::make_unique<ast::FloatLiteral>(&f32, 2.0)));
+
+ ast::ExpressionList params;
+ params.push_back(std::make_unique<ast::ScalarConstructorExpression>(
+ std::make_unique<ast::FloatLiteral>(&f32, 2.0)));
+ params.push_back(std::make_unique<ast::TypeConstructorExpression>(
+ &vec2, std::move(vec_params)));
+ params.push_back(std::make_unique<ast::ScalarConstructorExpression>(
+ std::make_unique<ast::FloatLiteral>(&f32, 2.0)));
+
+ ast::TypeConstructorExpression cast(&vec4, std::move(params));
+
+ Context ctx;
+ ast::Module mod;
+ TypeDeterminer td(&ctx, &mod);
+ ASSERT_TRUE(td.DetermineResultType(&cast)) << td.error();
+
+ Builder b(&mod);
+ b.push_function(Function{});
+ EXPECT_EQ(b.GenerateExpression(&cast), 8u);
+
+ EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 32
+%1 = OpTypeVector %2 4
+%3 = OpConstant %2 2
+%4 = OpTypeVector %2 2
+%5 = OpConstantComposite %4 %3 %3
+)");
+ EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
+ R"(%6 = OpCompositeExtract %2 %5 0
+%7 = OpCompositeExtract %2 %5 1
+%8 = OpCompositeConstruct %1 %3 %6 %7 %3
+)");
+}
+
+TEST_F(BuilderTest, Constructor_Type_Vec4_With_Vec2_F32_F32) {
+ ast::type::F32Type f32;
+ ast::type::VectorType vec2(&f32, 2);
+ ast::type::VectorType vec4(&f32, 4);
+
+ ast::ExpressionList vec_params;
+ vec_params.push_back(std::make_unique<ast::ScalarConstructorExpression>(
+ std::make_unique<ast::FloatLiteral>(&f32, 2.0)));
+ vec_params.push_back(std::make_unique<ast::ScalarConstructorExpression>(
+ std::make_unique<ast::FloatLiteral>(&f32, 2.0)));
+
+ ast::ExpressionList params;
+ params.push_back(std::make_unique<ast::TypeConstructorExpression>(
+ &vec2, std::move(vec_params)));
+ params.push_back(std::make_unique<ast::ScalarConstructorExpression>(
+ std::make_unique<ast::FloatLiteral>(&f32, 2.0)));
+ params.push_back(std::make_unique<ast::ScalarConstructorExpression>(
+ std::make_unique<ast::FloatLiteral>(&f32, 2.0)));
+
+ ast::TypeConstructorExpression cast(&vec4, std::move(params));
+
+ Context ctx;
+ ast::Module mod;
+ TypeDeterminer td(&ctx, &mod);
+ ASSERT_TRUE(td.DetermineResultType(&cast)) << td.error();
+
+ Builder b(&mod);
+ b.push_function(Function{});
+ EXPECT_EQ(b.GenerateExpression(&cast), 8u);
+
+ EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 32
+%1 = OpTypeVector %2 4
+%3 = OpTypeVector %2 2
+%4 = OpConstant %2 2
+%5 = OpConstantComposite %3 %4 %4
+)");
+ EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
+ R"(%6 = OpCompositeExtract %2 %5 0
+%7 = OpCompositeExtract %2 %5 1
+%8 = OpCompositeConstruct %1 %6 %7 %4 %4
+)");
+}
+
+TEST_F(BuilderTest, Constructor_Type_Vec4_With_Vec2_Vec2) {
+ ast::type::F32Type f32;
+ ast::type::VectorType vec2(&f32, 2);
+ ast::type::VectorType vec4(&f32, 4);
+
+ ast::ExpressionList vec_params;
+ vec_params.push_back(std::make_unique<ast::ScalarConstructorExpression>(
+ std::make_unique<ast::FloatLiteral>(&f32, 2.0)));
+ vec_params.push_back(std::make_unique<ast::ScalarConstructorExpression>(
+ std::make_unique<ast::FloatLiteral>(&f32, 2.0)));
+
+ ast::ExpressionList vec2_params;
+ vec2_params.push_back(std::make_unique<ast::ScalarConstructorExpression>(
+ std::make_unique<ast::FloatLiteral>(&f32, 2.0)));
+ vec2_params.push_back(std::make_unique<ast::ScalarConstructorExpression>(
+ std::make_unique<ast::FloatLiteral>(&f32, 2.0)));
+
+ ast::ExpressionList params;
+ params.push_back(std::make_unique<ast::TypeConstructorExpression>(
+ &vec2, std::move(vec_params)));
+ params.push_back(std::make_unique<ast::TypeConstructorExpression>(
+ &vec2, std::move(vec2_params)));
+
+ ast::TypeConstructorExpression cast(&vec4, std::move(params));
+
+ Context ctx;
+ ast::Module mod;
+ TypeDeterminer td(&ctx, &mod);
+ ASSERT_TRUE(td.DetermineResultType(&cast)) << td.error();
+
+ Builder b(&mod);
+ b.push_function(Function{});
+ EXPECT_EQ(b.GenerateExpression(&cast), 10u);
+
+ EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 32
+%1 = OpTypeVector %2 4
+%3 = OpTypeVector %2 2
+%4 = OpConstant %2 2
+%5 = OpConstantComposite %3 %4 %4
+)");
+ EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
+ R"(%6 = OpCompositeExtract %2 %5 0
+%7 = OpCompositeExtract %2 %5 1
+%8 = OpCompositeExtract %2 %5 0
+%9 = OpCompositeExtract %2 %5 1
+%10 = OpCompositeConstruct %1 %6 %7 %8 %9
+)");
+}
+
+TEST_F(BuilderTest, Constructor_Type_Vec4_With_F32_Vec3) {
+ ast::type::F32Type f32;
+ ast::type::VectorType vec3(&f32, 3);
+ ast::type::VectorType vec4(&f32, 4);
+
+ ast::ExpressionList vec_params;
+ vec_params.push_back(std::make_unique<ast::ScalarConstructorExpression>(
+ std::make_unique<ast::FloatLiteral>(&f32, 2.0)));
+ vec_params.push_back(std::make_unique<ast::ScalarConstructorExpression>(
+ std::make_unique<ast::FloatLiteral>(&f32, 2.0)));
+ vec_params.push_back(std::make_unique<ast::ScalarConstructorExpression>(
+ std::make_unique<ast::FloatLiteral>(&f32, 2.0)));
+
+ ast::ExpressionList params;
+ params.push_back(std::make_unique<ast::ScalarConstructorExpression>(
+ std::make_unique<ast::FloatLiteral>(&f32, 2.0)));
+ params.push_back(std::make_unique<ast::TypeConstructorExpression>(
+ &vec3, std::move(vec_params)));
+
+ ast::TypeConstructorExpression cast(&vec4, std::move(params));
+
+ Context ctx;
+ ast::Module mod;
+ TypeDeterminer td(&ctx, &mod);
+ ASSERT_TRUE(td.DetermineResultType(&cast)) << td.error();
+
+ Builder b(&mod);
+ b.push_function(Function{});
+ EXPECT_EQ(b.GenerateExpression(&cast), 9u);
+
+ EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 32
+%1 = OpTypeVector %2 4
+%3 = OpConstant %2 2
+%4 = OpTypeVector %2 3
+%5 = OpConstantComposite %4 %3 %3 %3
+)");
+ EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
+ R"(%6 = OpCompositeExtract %2 %5 0
+%7 = OpCompositeExtract %2 %5 1
+%8 = OpCompositeExtract %2 %5 2
+%9 = OpCompositeConstruct %1 %3 %6 %7 %8
+)");
+}
+
+TEST_F(BuilderTest, Constructor_Type_Vec4_With_Vec3_F32) {
+ ast::type::F32Type f32;
+ ast::type::VectorType vec3(&f32, 3);
+ ast::type::VectorType vec4(&f32, 4);
+
+ ast::ExpressionList vec_params;
+ vec_params.push_back(std::make_unique<ast::ScalarConstructorExpression>(
+ std::make_unique<ast::FloatLiteral>(&f32, 2.0)));
+ vec_params.push_back(std::make_unique<ast::ScalarConstructorExpression>(
+ std::make_unique<ast::FloatLiteral>(&f32, 2.0)));
+ vec_params.push_back(std::make_unique<ast::ScalarConstructorExpression>(
+ std::make_unique<ast::FloatLiteral>(&f32, 2.0)));
+
+ ast::ExpressionList params;
+ params.push_back(std::make_unique<ast::TypeConstructorExpression>(
+ &vec3, std::move(vec_params)));
+ params.push_back(std::make_unique<ast::ScalarConstructorExpression>(
+ std::make_unique<ast::FloatLiteral>(&f32, 2.0)));
+
+ ast::TypeConstructorExpression cast(&vec4, std::move(params));
+
+ Context ctx;
+ ast::Module mod;
+ TypeDeterminer td(&ctx, &mod);
+ ASSERT_TRUE(td.DetermineResultType(&cast)) << td.error();
+
+ Builder b(&mod);
+ b.push_function(Function{});
+ EXPECT_EQ(b.GenerateExpression(&cast), 9u);
+
+ EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 32
+%1 = OpTypeVector %2 4
+%3 = OpTypeVector %2 3
+%4 = OpConstant %2 2
+%5 = OpConstantComposite %3 %4 %4 %4
+)");
+ EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
+ R"(%6 = OpCompositeExtract %2 %5 0
+%7 = OpCompositeExtract %2 %5 1
+%8 = OpCompositeExtract %2 %5 2
+%9 = OpCompositeConstruct %1 %6 %7 %8 %4
+)");
+}
+
+TEST_F(BuilderTest, Constructor_Type_ModuleScope_Vec3_With_F32_Vec2) {
+ ast::type::F32Type f32;
+ ast::type::VectorType vec2(&f32, 2);
+ ast::type::VectorType vec3(&f32, 3);
+
+ ast::ExpressionList vec_params;
+ vec_params.push_back(std::make_unique<ast::ScalarConstructorExpression>(
+ std::make_unique<ast::FloatLiteral>(&f32, 2.0)));
+ vec_params.push_back(std::make_unique<ast::ScalarConstructorExpression>(
+ std::make_unique<ast::FloatLiteral>(&f32, 2.0)));
+
+ ast::ExpressionList params;
+ params.push_back(std::make_unique<ast::ScalarConstructorExpression>(
+ std::make_unique<ast::FloatLiteral>(&f32, 2.0)));
+ params.push_back(std::make_unique<ast::TypeConstructorExpression>(
+ &vec2, std::move(vec_params)));
+
+ ast::TypeConstructorExpression cast(&vec3, std::move(params));
+
+ Context ctx;
+ ast::Module mod;
+ TypeDeterminer td(&ctx, &mod);
+ ASSERT_TRUE(td.DetermineResultType(&cast)) << td.error();
+
+ Builder b(&mod);
+ b.push_function(Function{});
+ EXPECT_EQ(b.GenerateConstructorExpression(&cast, true), 11u);
+
+ EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 32
+%1 = OpTypeVector %2 3
+%3 = OpConstant %2 2
+%4 = OpTypeVector %2 2
+%5 = OpConstantComposite %4 %3 %3
+%7 = OpTypeInt 32 0
+%8 = OpConstant %7 0
+%6 = OpSpecConstantOp %2 CompositeExtract %5 8
+%10 = OpConstant %7 1
+%9 = OpSpecConstantOp %2 CompositeExtract %5 10
+%11 = OpSpecConstantComposite %1 %3 %6 %9
+)");
+}
+
+TEST_F(BuilderTest, Constructor_Type_ModuleScope_Vec3_With_Vec2_F32) {
+ ast::type::F32Type f32;
+ ast::type::VectorType vec2(&f32, 2);
+ ast::type::VectorType vec3(&f32, 3);
+
+ ast::ExpressionList vec_params;
+ vec_params.push_back(std::make_unique<ast::ScalarConstructorExpression>(
+ std::make_unique<ast::FloatLiteral>(&f32, 2.0)));
+ vec_params.push_back(std::make_unique<ast::ScalarConstructorExpression>(
+ std::make_unique<ast::FloatLiteral>(&f32, 2.0)));
+
+ ast::ExpressionList params;
+ params.push_back(std::make_unique<ast::TypeConstructorExpression>(
+ &vec2, std::move(vec_params)));
+ params.push_back(std::make_unique<ast::ScalarConstructorExpression>(
+ std::make_unique<ast::FloatLiteral>(&f32, 2.0)));
+
+ ast::TypeConstructorExpression cast(&vec3, std::move(params));
+
+ Context ctx;
+ ast::Module mod;
+ TypeDeterminer td(&ctx, &mod);
+ ASSERT_TRUE(td.DetermineResultType(&cast)) << td.error();
+
+ Builder b(&mod);
+ b.push_function(Function{});
+ EXPECT_EQ(b.GenerateConstructorExpression(&cast, true), 11u);
+
+ EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 32
+%1 = OpTypeVector %2 3
+%3 = OpTypeVector %2 2
+%4 = OpConstant %2 2
+%5 = OpConstantComposite %3 %4 %4
+%7 = OpTypeInt 32 0
+%8 = OpConstant %7 0
+%6 = OpSpecConstantOp %2 CompositeExtract %5 8
+%10 = OpConstant %7 1
+%9 = OpSpecConstantOp %2 CompositeExtract %5 10
+%11 = OpSpecConstantComposite %1 %6 %9 %4
+)");
+}
+
+TEST_F(BuilderTest, Constructor_Type_ModuleScope_Vec4_With_F32_F32_Vec2) {
+ ast::type::F32Type f32;
+ ast::type::VectorType vec2(&f32, 2);
+ ast::type::VectorType vec4(&f32, 4);
+
+ ast::ExpressionList vec_params;
+ vec_params.push_back(std::make_unique<ast::ScalarConstructorExpression>(
+ std::make_unique<ast::FloatLiteral>(&f32, 2.0)));
+ vec_params.push_back(std::make_unique<ast::ScalarConstructorExpression>(
+ std::make_unique<ast::FloatLiteral>(&f32, 2.0)));
+
+ ast::ExpressionList params;
+ params.push_back(std::make_unique<ast::ScalarConstructorExpression>(
+ std::make_unique<ast::FloatLiteral>(&f32, 2.0)));
+ params.push_back(std::make_unique<ast::ScalarConstructorExpression>(
+ std::make_unique<ast::FloatLiteral>(&f32, 2.0)));
+ params.push_back(std::make_unique<ast::TypeConstructorExpression>(
+ &vec2, std::move(vec_params)));
+
+ ast::TypeConstructorExpression cast(&vec4, std::move(params));
+
+ Context ctx;
+ ast::Module mod;
+ TypeDeterminer td(&ctx, &mod);
+ ASSERT_TRUE(td.DetermineResultType(&cast)) << td.error();
+
+ Builder b(&mod);
+ b.push_function(Function{});
+ EXPECT_EQ(b.GenerateConstructorExpression(&cast, true), 11u);
+
+ EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 32
+%1 = OpTypeVector %2 4
+%3 = OpConstant %2 2
+%4 = OpTypeVector %2 2
+%5 = OpConstantComposite %4 %3 %3
+%7 = OpTypeInt 32 0
+%8 = OpConstant %7 0
+%6 = OpSpecConstantOp %2 CompositeExtract %5 8
+%10 = OpConstant %7 1
+%9 = OpSpecConstantOp %2 CompositeExtract %5 10
+%11 = OpSpecConstantComposite %1 %3 %3 %6 %9
+)");
+}
+
+TEST_F(BuilderTest, Constructor_Type_ModuleScope_Vec4_With_F32_Vec2_F32) {
+ ast::type::F32Type f32;
+ ast::type::VectorType vec2(&f32, 2);
+ ast::type::VectorType vec4(&f32, 4);
+
+ ast::ExpressionList vec_params;
+ vec_params.push_back(std::make_unique<ast::ScalarConstructorExpression>(
+ std::make_unique<ast::FloatLiteral>(&f32, 2.0)));
+ vec_params.push_back(std::make_unique<ast::ScalarConstructorExpression>(
+ std::make_unique<ast::FloatLiteral>(&f32, 2.0)));
+
+ ast::ExpressionList params;
+ params.push_back(std::make_unique<ast::ScalarConstructorExpression>(
+ std::make_unique<ast::FloatLiteral>(&f32, 2.0)));
+ params.push_back(std::make_unique<ast::TypeConstructorExpression>(
+ &vec2, std::move(vec_params)));
+ params.push_back(std::make_unique<ast::ScalarConstructorExpression>(
+ std::make_unique<ast::FloatLiteral>(&f32, 2.0)));
+
+ ast::TypeConstructorExpression cast(&vec4, std::move(params));
+
+ Context ctx;
+ ast::Module mod;
+ TypeDeterminer td(&ctx, &mod);
+ ASSERT_TRUE(td.DetermineResultType(&cast)) << td.error();
+
+ Builder b(&mod);
+ b.push_function(Function{});
+ EXPECT_EQ(b.GenerateConstructorExpression(&cast, true), 11u);
+
+ EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 32
+%1 = OpTypeVector %2 4
+%3 = OpConstant %2 2
+%4 = OpTypeVector %2 2
+%5 = OpConstantComposite %4 %3 %3
+%7 = OpTypeInt 32 0
+%8 = OpConstant %7 0
+%6 = OpSpecConstantOp %2 CompositeExtract %5 8
+%10 = OpConstant %7 1
+%9 = OpSpecConstantOp %2 CompositeExtract %5 10
+%11 = OpSpecConstantComposite %1 %3 %6 %9 %3
+)");
+}
+
+TEST_F(BuilderTest, Constructor_Type_ModuleScope_Vec4_With_Vec2_F32_F32) {
+ ast::type::F32Type f32;
+ ast::type::VectorType vec2(&f32, 2);
+ ast::type::VectorType vec4(&f32, 4);
+
+ ast::ExpressionList vec_params;
+ vec_params.push_back(std::make_unique<ast::ScalarConstructorExpression>(
+ std::make_unique<ast::FloatLiteral>(&f32, 2.0)));
+ vec_params.push_back(std::make_unique<ast::ScalarConstructorExpression>(
+ std::make_unique<ast::FloatLiteral>(&f32, 2.0)));
+
+ ast::ExpressionList params;
+ params.push_back(std::make_unique<ast::TypeConstructorExpression>(
+ &vec2, std::move(vec_params)));
+ params.push_back(std::make_unique<ast::ScalarConstructorExpression>(
+ std::make_unique<ast::FloatLiteral>(&f32, 2.0)));
+ params.push_back(std::make_unique<ast::ScalarConstructorExpression>(
+ std::make_unique<ast::FloatLiteral>(&f32, 2.0)));
+
+ ast::TypeConstructorExpression cast(&vec4, std::move(params));
+
+ Context ctx;
+ ast::Module mod;
+ TypeDeterminer td(&ctx, &mod);
+ ASSERT_TRUE(td.DetermineResultType(&cast)) << td.error();
+
+ Builder b(&mod);
+ b.push_function(Function{});
+ EXPECT_EQ(b.GenerateConstructorExpression(&cast, true), 11u);
+
+ EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 32
+%1 = OpTypeVector %2 4
+%3 = OpTypeVector %2 2
+%4 = OpConstant %2 2
+%5 = OpConstantComposite %3 %4 %4
+%7 = OpTypeInt 32 0
+%8 = OpConstant %7 0
+%6 = OpSpecConstantOp %2 CompositeExtract %5 8
+%10 = OpConstant %7 1
+%9 = OpSpecConstantOp %2 CompositeExtract %5 10
+%11 = OpSpecConstantComposite %1 %6 %9 %4 %4
+)");
+}
+
+TEST_F(BuilderTest, Constructor_Type_ModuleScope_Vec4_With_Vec2_Vec2) {
+ ast::type::F32Type f32;
+ ast::type::VectorType vec2(&f32, 2);
+ ast::type::VectorType vec4(&f32, 4);
+
+ ast::ExpressionList vec_params;
+ vec_params.push_back(std::make_unique<ast::ScalarConstructorExpression>(
+ std::make_unique<ast::FloatLiteral>(&f32, 2.0)));
+ vec_params.push_back(std::make_unique<ast::ScalarConstructorExpression>(
+ std::make_unique<ast::FloatLiteral>(&f32, 2.0)));
+
+ ast::ExpressionList vec2_params;
+ vec2_params.push_back(std::make_unique<ast::ScalarConstructorExpression>(
+ std::make_unique<ast::FloatLiteral>(&f32, 2.0)));
+ vec2_params.push_back(std::make_unique<ast::ScalarConstructorExpression>(
+ std::make_unique<ast::FloatLiteral>(&f32, 2.0)));
+
+ ast::ExpressionList params;
+ params.push_back(std::make_unique<ast::TypeConstructorExpression>(
+ &vec2, std::move(vec_params)));
+ params.push_back(std::make_unique<ast::TypeConstructorExpression>(
+ &vec2, std::move(vec2_params)));
+
+ ast::TypeConstructorExpression cast(&vec4, std::move(params));
+
+ Context ctx;
+ ast::Module mod;
+ TypeDeterminer td(&ctx, &mod);
+ ASSERT_TRUE(td.DetermineResultType(&cast)) << td.error();
+
+ Builder b(&mod);
+ b.push_function(Function{});
+ EXPECT_EQ(b.GenerateConstructorExpression(&cast, true), 13u);
+
+ EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 32
+%1 = OpTypeVector %2 4
+%3 = OpTypeVector %2 2
+%4 = OpConstant %2 2
+%5 = OpConstantComposite %3 %4 %4
+%7 = OpTypeInt 32 0
+%8 = OpConstant %7 0
+%6 = OpSpecConstantOp %2 CompositeExtract %5 8
+%10 = OpConstant %7 1
+%9 = OpSpecConstantOp %2 CompositeExtract %5 10
+%11 = OpSpecConstantOp %2 CompositeExtract %5 8
+%12 = OpSpecConstantOp %2 CompositeExtract %5 10
+%13 = OpSpecConstantComposite %1 %6 %9 %11 %12
+)");
+}
+
+TEST_F(BuilderTest, Constructor_Type_ModuleScope_Vec4_With_F32_Vec3) {
+ ast::type::F32Type f32;
+ ast::type::VectorType vec3(&f32, 3);
+ ast::type::VectorType vec4(&f32, 4);
+
+ ast::ExpressionList vec_params;
+ vec_params.push_back(std::make_unique<ast::ScalarConstructorExpression>(
+ std::make_unique<ast::FloatLiteral>(&f32, 2.0)));
+ vec_params.push_back(std::make_unique<ast::ScalarConstructorExpression>(
+ std::make_unique<ast::FloatLiteral>(&f32, 2.0)));
+ vec_params.push_back(std::make_unique<ast::ScalarConstructorExpression>(
+ std::make_unique<ast::FloatLiteral>(&f32, 2.0)));
+
+ ast::ExpressionList params;
+ params.push_back(std::make_unique<ast::ScalarConstructorExpression>(
+ std::make_unique<ast::FloatLiteral>(&f32, 2.0)));
+ params.push_back(std::make_unique<ast::TypeConstructorExpression>(
+ &vec3, std::move(vec_params)));
+
+ ast::TypeConstructorExpression cast(&vec4, std::move(params));
+
+ Context ctx;
+ ast::Module mod;
+ TypeDeterminer td(&ctx, &mod);
+ ASSERT_TRUE(td.DetermineResultType(&cast)) << td.error();
+
+ Builder b(&mod);
+ b.push_function(Function{});
+ EXPECT_EQ(b.GenerateConstructorExpression(&cast, true), 13u);
+
+ EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 32
+%1 = OpTypeVector %2 4
+%3 = OpConstant %2 2
+%4 = OpTypeVector %2 3
+%5 = OpConstantComposite %4 %3 %3 %3
+%7 = OpTypeInt 32 0
+%8 = OpConstant %7 0
+%6 = OpSpecConstantOp %2 CompositeExtract %5 8
+%10 = OpConstant %7 1
+%9 = OpSpecConstantOp %2 CompositeExtract %5 10
+%12 = OpConstant %7 2
+%11 = OpSpecConstantOp %2 CompositeExtract %5 12
+%13 = OpSpecConstantComposite %1 %3 %6 %9 %11
+)");
+}
+
+TEST_F(BuilderTest, Constructor_Type_ModuleScope_Vec4_With_Vec3_F32) {
+ ast::type::F32Type f32;
+ ast::type::VectorType vec3(&f32, 3);
+ ast::type::VectorType vec4(&f32, 4);
+
+ ast::ExpressionList vec_params;
+ vec_params.push_back(std::make_unique<ast::ScalarConstructorExpression>(
+ std::make_unique<ast::FloatLiteral>(&f32, 2.0)));
+ vec_params.push_back(std::make_unique<ast::ScalarConstructorExpression>(
+ std::make_unique<ast::FloatLiteral>(&f32, 2.0)));
+ vec_params.push_back(std::make_unique<ast::ScalarConstructorExpression>(
+ std::make_unique<ast::FloatLiteral>(&f32, 2.0)));
+
+ ast::ExpressionList params;
+ params.push_back(std::make_unique<ast::TypeConstructorExpression>(
+ &vec3, std::move(vec_params)));
+ params.push_back(std::make_unique<ast::ScalarConstructorExpression>(
+ std::make_unique<ast::FloatLiteral>(&f32, 2.0)));
+
+ ast::TypeConstructorExpression cast(&vec4, std::move(params));
+
+ Context ctx;
+ ast::Module mod;
+ TypeDeterminer td(&ctx, &mod);
+ ASSERT_TRUE(td.DetermineResultType(&cast)) << td.error();
+
+ Builder b(&mod);
+ b.push_function(Function{});
+ EXPECT_EQ(b.GenerateConstructorExpression(&cast, true), 13u);
+
+ EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 32
+%1 = OpTypeVector %2 4
+%3 = OpTypeVector %2 3
+%4 = OpConstant %2 2
+%5 = OpConstantComposite %3 %4 %4 %4
+%7 = OpTypeInt 32 0
+%8 = OpConstant %7 0
+%6 = OpSpecConstantOp %2 CompositeExtract %5 8
+%10 = OpConstant %7 1
+%9 = OpSpecConstantOp %2 CompositeExtract %5 10
+%12 = OpConstant %7 2
+%11 = OpSpecConstantOp %2 CompositeExtract %5 12
+%13 = OpSpecConstantComposite %1 %6 %9 %11 %4
+)");
+}
+
+TEST_F(BuilderTest, DISABLED_Constructor_Type_Mat2x2_With_Vec2_Vec2) {
+ FAIL();
+}
+
+TEST_F(BuilderTest, DISABLED_Constructor_Type_Mat3x2_With_Vec2_Vec2_Vec2) {
+ FAIL();
+}
+
+TEST_F(BuilderTest, DISABLED_Constructor_Type_Mat4x2_With_Vec2_Vec2_Vec2_Vec2) {
+ FAIL();
+}
+
+TEST_F(BuilderTest, DISABLED_Constructor_Type_Mat2x3_With_Vec3_Vec3) {
+ FAIL();
+}
+
+TEST_F(BuilderTest, DISABLED_Constructor_Type_Mat3x3_With_Vec3_Vec3_Vec3) {
+ FAIL();
+}
+
+TEST_F(BuilderTest, DISABLED_Constructor_Type_Mat4x3_With_Vec3_Vec3_Vec3_Vec3) {
+ FAIL();
+}
+
+TEST_F(BuilderTest, DISABLED_Constructor_Type_Mat2x4_With_Vec4_Vec4) {
+ FAIL();
+}
+
+TEST_F(BuilderTest, DISABLED_Constructor_Type_Mat3x4_With_Vec4_Vec4_Vec4) {
+ FAIL();
+}
+
+TEST_F(BuilderTest, DISABLED_Constructor_Type_Mat4x4_With_Vec4_Vec4_Vec4_Vec4) {
+ FAIL();
+}
+
+TEST_F(BuilderTest,
+ DISABLED_Constructor_Type_ModuleScope_Mat2x2_With_Vec2_Vec2) {
+ FAIL();
+}
+
+TEST_F(BuilderTest,
+ DISABLED_Constructor_Type_ModuleScope_Mat3x2_With_Vec2_Vec2_Vec2) {
+ FAIL();
+}
+
+TEST_F(BuilderTest,
+ DISABLED_Constructor_Type_ModuleScope_Mat4x2_With_Vec2_Vec2_Vec2_Vec2) {
+ FAIL();
+}
+
+TEST_F(BuilderTest,
+ DISABLED_Constructor_Type_ModuleScope_Mat2x3_With_Vec3_Vec3) {
+ FAIL();
+}
+
+TEST_F(BuilderTest,
+ DISABLED_Constructor_Type_ModuleScope_Mat3x3_With_Vec3_Vec3_Vec3) {
+ FAIL();
+}
+
+TEST_F(BuilderTest,
+ DISABLED_Constructor_Type_ModuleScope_Mat4x3_With_Vec3_Vec3_Vec3_Vec3) {
+ FAIL();
+}
+
+TEST_F(BuilderTest,
+ DISABLED_Constructor_Type_ModuleScope_Mat2x4_With_Vec4_Vec4) {
+ FAIL();
+}
+
+TEST_F(BuilderTest,
+ DISABLED_Constructor_Type_ModuleScope_Mat3x4_With_Vec4_Vec4_Vec4) {
+ FAIL();
+}
+
+TEST_F(BuilderTest,
+ DISABLED_Constructor_Type_ModuleScope_Mat4x4_With_Vec4_Vec4_Vec4_Vec4) {
+ FAIL();
+}
+
+TEST_F(BuilderTest, DISABLED_Constructor_Type_Array_5_F32) {
+ FAIL();
+}
+
+TEST_F(BuilderTest, DISABLED_Constructor_Type_Array_5_Vec3) {
+ FAIL();
+}
+
+TEST_F(BuilderTest, DISABLED_Constructor_Type_ModuleScope_Array_5_Vec3) {
+ FAIL();
+}
+
+TEST_F(BuilderTest, DISABLED_Constructor_Type_Struct) {
+ FAIL();
+}
+
+TEST_F(BuilderTest, DISABLED_Constructor_Type_ModuleScope_Struct_With_Vec2) {
+ FAIL();
+}
+
+TEST_F(BuilderTest, Constructor_Type_ZeroInit_F32) {
+ ast::type::F32Type f32;
+
+ ast::ExpressionList vals;
+ ast::TypeConstructorExpression t(&f32, std::move(vals));
+
+ Context ctx;
+ ast::Module mod;
+ TypeDeterminer td(&ctx, &mod);
+ EXPECT_TRUE(td.DetermineResultType(&t)) << td.error();
+
+ Builder b(&mod);
+ b.push_function(Function{});
+
+ EXPECT_EQ(b.GenerateExpression(&t), 2u);
+ ASSERT_FALSE(b.has_error()) << b.error();
+
+ EXPECT_EQ(DumpInstructions(b.types()), R"(%1 = OpTypeFloat 32
+%2 = OpConstantNull %1
+)");
+}
+
+TEST_F(BuilderTest, Constructor_Type_ZeroInit_I32) {
+ ast::type::I32Type i32;
+
+ ast::ExpressionList vals;
+ ast::TypeConstructorExpression t(&i32, std::move(vals));
+
+ Context ctx;
+ ast::Module mod;
+ TypeDeterminer td(&ctx, &mod);
+ EXPECT_TRUE(td.DetermineResultType(&t)) << td.error();
+
+ Builder b(&mod);
+ b.push_function(Function{});
+
+ EXPECT_EQ(b.GenerateExpression(&t), 2u);
+ ASSERT_FALSE(b.has_error()) << b.error();
+
+ EXPECT_EQ(DumpInstructions(b.types()), R"(%1 = OpTypeInt 32 1
+%2 = OpConstantNull %1
+)");
+}
+
+TEST_F(BuilderTest, Constructor_Type_ZeroInit_U32) {
+ ast::type::U32Type u32;
+
+ ast::ExpressionList vals;
+ ast::TypeConstructorExpression t(&u32, std::move(vals));
+
+ Context ctx;
+ ast::Module mod;
+ TypeDeterminer td(&ctx, &mod);
+ EXPECT_TRUE(td.DetermineResultType(&t)) << td.error();
+
+ Builder b(&mod);
+ b.push_function(Function{});
+
+ EXPECT_EQ(b.GenerateExpression(&t), 2u);
+ ASSERT_FALSE(b.has_error()) << b.error();
+
+ EXPECT_EQ(DumpInstructions(b.types()), R"(%1 = OpTypeInt 32 0
+%2 = OpConstantNull %1
+)");
+}
+
+TEST_F(BuilderTest, Constructor_Type_ZeroInit_Bool) {
+ ast::type::BoolType bool_type;
+
+ ast::ExpressionList vals;
+ ast::TypeConstructorExpression t(&bool_type, std::move(vals));
+
+ Context ctx;
+ ast::Module mod;
+ TypeDeterminer td(&ctx, &mod);
+ EXPECT_TRUE(td.DetermineResultType(&t)) << td.error();
+
+ Builder b(&mod);
+ b.push_function(Function{});
+
+ EXPECT_EQ(b.GenerateExpression(&t), 2u);
+ ASSERT_FALSE(b.has_error()) << b.error();
+
+ EXPECT_EQ(DumpInstructions(b.types()), R"(%1 = OpTypeBool
+%2 = OpConstantNull %1
+)");
+}
+
+TEST_F(BuilderTest, Constructor_Type_ZeroInit_Vector) {
+ ast::type::I32Type i32;
+ ast::type::VectorType vec(&i32, 2);
+
+ ast::ExpressionList vals;
+ ast::TypeConstructorExpression t(&vec, std::move(vals));
+
+ Context ctx;
+ ast::Module mod;
+ TypeDeterminer td(&ctx, &mod);
+ EXPECT_TRUE(td.DetermineResultType(&t)) << td.error();
+
+ Builder b(&mod);
+ b.push_function(Function{});
+
+ EXPECT_EQ(b.GenerateExpression(&t), 3u);
+ ASSERT_FALSE(b.has_error()) << b.error();
+
+ EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeInt 32 1
+%1 = OpTypeVector %2 2
+%3 = OpConstantNull %1
+)");
+}
+
+TEST_F(BuilderTest, Constructor_Type_ZeroInit_Matrix) {
+ ast::type::F32Type f32;
+ ast::type::MatrixType mat(&f32, 2, 4);
+
+ ast::ExpressionList vals;
+ ast::TypeConstructorExpression t(&mat, std::move(vals));
+
+ Context ctx;
+ ast::Module mod;
+ TypeDeterminer td(&ctx, &mod);
+ EXPECT_TRUE(td.DetermineResultType(&t)) << td.error();
+
+ Builder b(&mod);
+ b.push_function(Function{});
+
+ EXPECT_EQ(b.GenerateExpression(&t), 4u);
+ ASSERT_FALSE(b.has_error()) << b.error();
+
+ EXPECT_EQ(DumpInstructions(b.types()), R"(%3 = OpTypeFloat 32
+%2 = OpTypeVector %3 2
+%1 = OpTypeMatrix %2 4
+%4 = OpConstantNull %1
+)");
+}
+
+TEST_F(BuilderTest, Constructor_Type_ZeroInit_Array) {
+ ast::type::I32Type i32;
+ ast::type::ArrayType ary(&i32, 2);
+
+ ast::ExpressionList vals;
+ ast::TypeConstructorExpression t(&ary, std::move(vals));
+
+ Context ctx;
+ ast::Module mod;
+ TypeDeterminer td(&ctx, &mod);
+ EXPECT_TRUE(td.DetermineResultType(&t)) << td.error();
+
+ Builder b(&mod);
+ b.push_function(Function{});
+
+ EXPECT_EQ(b.GenerateExpression(&t), 5u);
+ ASSERT_FALSE(b.has_error()) << b.error();
+
+ EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeInt 32 1
+%3 = OpTypeInt 32 0
+%4 = OpConstant %3 2
+%1 = OpTypeArray %2 %4
+%5 = OpConstantNull %1
+)");
+}
+
+TEST_F(BuilderTest, Constructor_Type_ZeroInit_Struct) {
+ ast::type::F32Type f32;
+
+ ast::StructMemberDecorationList decos;
+ ast::StructMemberList members;
+ members.push_back(
+ std::make_unique<ast::StructMember>("a", &f32, std::move(decos)));
+
+ auto s = std::make_unique<ast::Struct>(ast::StructDecoration::kNone,
+ std::move(members));
+ ast::type::StructType s_type(std::move(s));
+ s_type.set_name("my_struct");
+
+ ast::ExpressionList vals;
+ ast::TypeConstructorExpression t(&s_type, std::move(vals));
+
+ Context ctx;
+ ast::Module mod;
+ TypeDeterminer td(&ctx, &mod);
+ EXPECT_TRUE(td.DetermineResultType(&t)) << td.error();
+
+ Builder b(&mod);
+ b.push_function(Function{});
+
+ EXPECT_EQ(b.GenerateExpression(&t), 3u);
+ ASSERT_FALSE(b.has_error()) << b.error();
+
+ EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 32
+%1 = OpTypeStruct %2
+%3 = OpConstantNull %1
+)");
+}
+
+TEST_F(BuilderTest, Constructor_Type_Convert_U32_To_I32) {
+ ast::type::U32Type u32;
+ ast::type::I32Type i32;
+
+ ast::ExpressionList params;
+ params.push_back(std::make_unique<ast::ScalarConstructorExpression>(
+ std::make_unique<ast::UintLiteral>(&u32, 2)));
+
+ ast::TypeConstructorExpression cast(&i32, std::move(params));
+
+ Context ctx;
+ ast::Module mod;
+ TypeDeterminer td(&ctx, &mod);
+ ASSERT_TRUE(td.DetermineResultType(&cast)) << td.error();
+
+ Builder b(&mod);
+ b.push_function(Function{});
+ EXPECT_EQ(b.GenerateExpression(&cast), 1u);
+
+ EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeInt 32 1
+%3 = OpTypeInt 32 0
+%4 = OpConstant %3 2
+)");
+ EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
+ R"(%1 = OpBitcast %2 %4
+)");
+}
+
+TEST_F(BuilderTest, Constructor_Type_Convert_I32_To_U32) {
+ ast::type::U32Type u32;
+ ast::type::I32Type i32;
+
+ ast::ExpressionList params;
+ params.push_back(std::make_unique<ast::ScalarConstructorExpression>(
+ std::make_unique<ast::SintLiteral>(&i32, 2)));
+
+ ast::TypeConstructorExpression cast(&u32, std::move(params));
+
+ Context ctx;
+ ast::Module mod;
+ TypeDeterminer td(&ctx, &mod);
+ ASSERT_TRUE(td.DetermineResultType(&cast)) << td.error();
+
+ Builder b(&mod);
+ b.push_function(Function{});
+ EXPECT_EQ(b.GenerateExpression(&cast), 1u);
+
+ EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeInt 32 0
+%3 = OpTypeInt 32 1
+%4 = OpConstant %3 2
+)");
+ EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
+ R"(%1 = OpBitcast %2 %4
+)");
+}
+
+TEST_F(BuilderTest, Constructor_Type_Convert_F32_To_I32) {
+ ast::type::I32Type i32;
+ ast::type::F32Type f32;
+
+ ast::ExpressionList params;
+ params.push_back(std::make_unique<ast::ScalarConstructorExpression>(
+ std::make_unique<ast::FloatLiteral>(&f32, 2.4)));
+
+ ast::TypeConstructorExpression cast(&i32, std::move(params));
+
+ Context ctx;
+ ast::Module mod;
+ TypeDeterminer td(&ctx, &mod);
+ ASSERT_TRUE(td.DetermineResultType(&cast)) << td.error();
+
+ Builder b(&mod);
+ b.push_function(Function{});
+ EXPECT_EQ(b.GenerateExpression(&cast), 1u);
+
+ EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeInt 32 1
+%3 = OpTypeFloat 32
+%4 = OpConstant %3 2.4000001
+)");
+ EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
+ R"(%1 = OpConvertFToS %2 %4
+)");
+}
+
+TEST_F(BuilderTest, Constructor_Type_Convert_F32_To_U32) {
+ ast::type::U32Type u32;
+ ast::type::F32Type f32;
+
+ ast::ExpressionList params;
+ params.push_back(std::make_unique<ast::ScalarConstructorExpression>(
+ std::make_unique<ast::FloatLiteral>(&f32, 2.4)));
+
+ ast::TypeConstructorExpression cast(&u32, std::move(params));
+
+ Context ctx;
+ ast::Module mod;
+ TypeDeterminer td(&ctx, &mod);
+ ASSERT_TRUE(td.DetermineResultType(&cast)) << td.error();
+
+ Builder b(&mod);
+ b.push_function(Function{});
+ EXPECT_EQ(b.GenerateExpression(&cast), 1u);
+
+ EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeInt 32 0
+%3 = OpTypeFloat 32
+%4 = OpConstant %3 2.4000001
+)");
+ EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
+ R"(%1 = OpConvertFToU %2 %4
+)");
+}
+
+TEST_F(BuilderTest, Constructor_Type_Convert_I32_To_F32) {
+ ast::type::I32Type i32;
+ ast::type::F32Type f32;
+
+ ast::ExpressionList params;
+ params.push_back(std::make_unique<ast::ScalarConstructorExpression>(
+ std::make_unique<ast::SintLiteral>(&i32, 2)));
+
+ ast::TypeConstructorExpression cast(&f32, std::move(params));
+
+ Context ctx;
+ ast::Module mod;
+ TypeDeterminer td(&ctx, &mod);
+ ASSERT_TRUE(td.DetermineResultType(&cast)) << td.error();
+
+ Builder b(&mod);
+ b.push_function(Function{});
+ EXPECT_EQ(b.GenerateExpression(&cast), 1u);
+
+ EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 32
+%3 = OpTypeInt 32 1
+%4 = OpConstant %3 2
+)");
+ EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
+ R"(%1 = OpConvertSToF %2 %4
+)");
+}
+
+TEST_F(BuilderTest, Constructor_Type_Convert_U32_To_F32) {
+ ast::type::U32Type u32;
+ ast::type::F32Type f32;
+
+ ast::ExpressionList params;
+ params.push_back(std::make_unique<ast::ScalarConstructorExpression>(
+ std::make_unique<ast::UintLiteral>(&u32, 2)));
+
+ ast::TypeConstructorExpression cast(&f32, std::move(params));
+
+ Context ctx;
+ ast::Module mod;
+ TypeDeterminer td(&ctx, &mod);
+ ASSERT_TRUE(td.DetermineResultType(&cast)) << td.error();
+
+ Builder b(&mod);
+ b.push_function(Function{});
+ EXPECT_EQ(b.GenerateExpression(&cast), 1u);
+
+ EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 32
+%3 = OpTypeInt 32 0
+%4 = OpConstant %3 2
+)");
+ EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
+ R"(%1 = OpConvertUToF %2 %4
+)");
+}
+
+TEST_F(BuilderTest, Constructor_Type_Convert_Vectors_U32_to_I32) {
+ ast::type::U32Type u32;
+ ast::type::VectorType uvec3(&u32, 3);
+ ast::type::I32Type i32;
+ ast::type::VectorType ivec3(&i32, 3);
+
+ auto var =
+ std::make_unique<ast::Variable>("i", ast::StorageClass::kPrivate, &uvec3);
+
+ ast::ExpressionList params;
+ params.push_back(std::make_unique<ast::IdentifierExpression>("i"));
+
+ ast::TypeConstructorExpression cast(&ivec3, std::move(params));
+
+ Context ctx;
+ ast::Module mod;
+ TypeDeterminer td(&ctx, &mod);
+ td.RegisterVariableForTesting(var.get());
+ ASSERT_TRUE(td.DetermineResultType(&cast)) << td.error();
+
+ Builder b(&mod);
+ b.push_function(Function{});
+ ASSERT_TRUE(b.GenerateGlobalVariable(var.get())) << b.error();
+ EXPECT_EQ(b.GenerateExpression(&cast), 6u) << b.error();
+
+ EXPECT_EQ(DumpInstructions(b.types()), R"(%4 = OpTypeInt 32 0
+%3 = OpTypeVector %4 3
+%2 = OpTypePointer Private %3
+%5 = OpConstantNull %3
+%1 = OpVariable %2 Private %5
+%8 = OpTypeInt 32 1
+%7 = OpTypeVector %8 3
+)");
+ EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
+ R"(%9 = OpLoad %3 %1
+%6 = OpBitcast %7 %9
+)");
+}
+
+TEST_F(BuilderTest, Constructor_Type_Convert_Vectors_F32_to_I32) {
+ ast::type::I32Type i32;
+ ast::type::VectorType ivec3(&i32, 3);
+ ast::type::F32Type f32;
+ ast::type::VectorType fvec3(&f32, 3);
+
+ auto var =
+ std::make_unique<ast::Variable>("i", ast::StorageClass::kPrivate, &fvec3);
+
+ ast::ExpressionList params;
+ params.push_back(std::make_unique<ast::IdentifierExpression>("i"));
+
+ ast::TypeConstructorExpression cast(&ivec3, std::move(params));
+
+ Context ctx;
+ ast::Module mod;
+ TypeDeterminer td(&ctx, &mod);
+ td.RegisterVariableForTesting(var.get());
+ ASSERT_TRUE(td.DetermineResultType(&cast)) << td.error();
+
+ Builder b(&mod);
+ b.push_function(Function{});
+ ASSERT_TRUE(b.GenerateGlobalVariable(var.get())) << b.error();
+ EXPECT_EQ(b.GenerateExpression(&cast), 6u) << b.error();
+
+ EXPECT_EQ(DumpInstructions(b.types()), R"(%4 = OpTypeFloat 32
+%3 = OpTypeVector %4 3
+%2 = OpTypePointer Private %3
+%5 = OpConstantNull %3
+%1 = OpVariable %2 Private %5
+%8 = OpTypeInt 32 1
+%7 = OpTypeVector %8 3
+)");
+ EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
+ R"(%9 = OpLoad %3 %1
+%6 = OpConvertFToS %7 %9
+)");
+}
+
+TEST_F(BuilderTest, Constructor_Type_Convert_Vectors_I32_to_U32) {
+ ast::type::U32Type u32;
+ ast::type::VectorType uvec3(&u32, 3);
+ ast::type::I32Type i32;
+ ast::type::VectorType ivec3(&i32, 3);
+
+ auto var =
+ std::make_unique<ast::Variable>("i", ast::StorageClass::kPrivate, &ivec3);
+
+ ast::ExpressionList params;
+ params.push_back(std::make_unique<ast::IdentifierExpression>("i"));
+
+ ast::TypeConstructorExpression cast(&uvec3, std::move(params));
+
+ Context ctx;
+ ast::Module mod;
+ TypeDeterminer td(&ctx, &mod);
+ td.RegisterVariableForTesting(var.get());
+ ASSERT_TRUE(td.DetermineResultType(&cast)) << td.error();
+
+ Builder b(&mod);
+ b.push_function(Function{});
+ ASSERT_TRUE(b.GenerateGlobalVariable(var.get())) << b.error();
+ EXPECT_EQ(b.GenerateExpression(&cast), 6u) << b.error();
+
+ EXPECT_EQ(DumpInstructions(b.types()), R"(%4 = OpTypeInt 32 1
+%3 = OpTypeVector %4 3
+%2 = OpTypePointer Private %3
+%5 = OpConstantNull %3
+%1 = OpVariable %2 Private %5
+%8 = OpTypeInt 32 0
+%7 = OpTypeVector %8 3
+)");
+ EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
+ R"(%9 = OpLoad %3 %1
+%6 = OpBitcast %7 %9
+)");
+}
+
+TEST_F(BuilderTest, Constructor_Type_Convert_Vectors_F32_to_U32) {
+ ast::type::U32Type u32;
+ ast::type::VectorType uvec3(&u32, 3);
+ ast::type::F32Type f32;
+ ast::type::VectorType fvec3(&f32, 3);
+
+ auto var =
+ std::make_unique<ast::Variable>("i", ast::StorageClass::kPrivate, &fvec3);
+
+ ast::ExpressionList params;
+ params.push_back(std::make_unique<ast::IdentifierExpression>("i"));
+
+ ast::TypeConstructorExpression cast(&uvec3, std::move(params));
+
+ Context ctx;
+ ast::Module mod;
+ TypeDeterminer td(&ctx, &mod);
+ td.RegisterVariableForTesting(var.get());
+ ASSERT_TRUE(td.DetermineResultType(&cast)) << td.error();
+
+ Builder b(&mod);
+ b.push_function(Function{});
+ ASSERT_TRUE(b.GenerateGlobalVariable(var.get())) << b.error();
+ EXPECT_EQ(b.GenerateExpression(&cast), 6u) << b.error();
+
+ EXPECT_EQ(DumpInstructions(b.types()), R"(%4 = OpTypeFloat 32
+%3 = OpTypeVector %4 3
+%2 = OpTypePointer Private %3
+%5 = OpConstantNull %3
+%1 = OpVariable %2 Private %5
+%8 = OpTypeInt 32 0
+%7 = OpTypeVector %8 3
+)");
+ EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
+ R"(%9 = OpLoad %3 %1
+%6 = OpConvertFToU %7 %9
+)");
+}
+
+TEST_F(BuilderTest, Constructor_Type_Convert_Vectors_I32_to_F32) {
+ ast::type::I32Type i32;
+ ast::type::VectorType ivec3(&i32, 3);
+ ast::type::F32Type f32;
+ ast::type::VectorType fvec3(&f32, 3);
+
+ auto var =
+ std::make_unique<ast::Variable>("i", ast::StorageClass::kPrivate, &ivec3);
+
+ ast::ExpressionList params;
+ params.push_back(std::make_unique<ast::IdentifierExpression>("i"));
+
+ ast::TypeConstructorExpression cast(&fvec3, std::move(params));
+
+ Context ctx;
+ ast::Module mod;
+ TypeDeterminer td(&ctx, &mod);
+ td.RegisterVariableForTesting(var.get());
+ ASSERT_TRUE(td.DetermineResultType(&cast)) << td.error();
+
+ Builder b(&mod);
+ b.push_function(Function{});
+ ASSERT_TRUE(b.GenerateGlobalVariable(var.get())) << b.error();
+ EXPECT_EQ(b.GenerateExpression(&cast), 6u) << b.error();
+
+ EXPECT_EQ(DumpInstructions(b.types()), R"(%4 = OpTypeInt 32 1
+%3 = OpTypeVector %4 3
+%2 = OpTypePointer Private %3
+%5 = OpConstantNull %3
+%1 = OpVariable %2 Private %5
+%8 = OpTypeFloat 32
+%7 = OpTypeVector %8 3
+)");
+ EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
+ R"(%9 = OpLoad %3 %1
+%6 = OpConvertSToF %7 %9
+)");
+}
+
+TEST_F(BuilderTest, Constructor_Type_Convert_Vectors_U32_to_F32) {
+ ast::type::U32Type u32;
+ ast::type::VectorType uvec3(&u32, 3);
+ ast::type::F32Type f32;
+ ast::type::VectorType fvec3(&f32, 3);
+
+ auto var =
+ std::make_unique<ast::Variable>("i", ast::StorageClass::kPrivate, &uvec3);
+
+ ast::ExpressionList params;
+ params.push_back(std::make_unique<ast::IdentifierExpression>("i"));
+
+ ast::TypeConstructorExpression cast(&fvec3, std::move(params));
+
+ Context ctx;
+ ast::Module mod;
+ TypeDeterminer td(&ctx, &mod);
+ td.RegisterVariableForTesting(var.get());
+ ASSERT_TRUE(td.DetermineResultType(&cast)) << td.error();
+
+ Builder b(&mod);
+ b.push_function(Function{});
+ ASSERT_TRUE(b.GenerateGlobalVariable(var.get())) << b.error();
+ EXPECT_EQ(b.GenerateExpression(&cast), 6u) << b.error();
+
+ EXPECT_EQ(DumpInstructions(b.types()), R"(%4 = OpTypeInt 32 0
+%3 = OpTypeVector %4 3
+%2 = OpTypePointer Private %3
+%5 = OpConstantNull %3
+%1 = OpVariable %2 Private %5
+%8 = OpTypeFloat 32
+%7 = OpTypeVector %8 3
+)");
+ EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
+ R"(%9 = OpLoad %3 %1
+%6 = OpConvertUToF %7 %9
+)");
+}
+
} // namespace
} // namespace spirv
} // namespace writer
diff --git a/src/writer/wgsl/generator_impl.cc b/src/writer/wgsl/generator_impl.cc
index 4389ae1..e13fe6b 100644
--- a/src/writer/wgsl/generator_impl.cc
+++ b/src/writer/wgsl/generator_impl.cc
@@ -29,7 +29,6 @@
#include "src/ast/call_expression.h"
#include "src/ast/call_statement.h"
#include "src/ast/case_statement.h"
-#include "src/ast/cast_expression.h"
#include "src/ast/constructor_expression.h"
#include "src/ast/continue_statement.h"
#include "src/ast/decorated_variable.h"
@@ -186,9 +185,6 @@
if (expr->IsCall()) {
return EmitCall(expr->AsCall());
}
- if (expr->IsCast()) {
- return EmitCast(expr->AsCast());
- }
if (expr->IsIdentifier()) {
return EmitIdentifier(expr->AsIdentifier());
}
@@ -269,21 +265,6 @@
return true;
}
-bool GeneratorImpl::EmitCast(ast::CastExpression* expr) {
- out_ << "cast<";
- if (!EmitType(expr->type())) {
- return false;
- }
-
- out_ << ">(";
- if (!EmitExpression(expr->expr())) {
- return false;
- }
-
- out_ << ")";
- return true;
-}
-
bool GeneratorImpl::EmitConstructor(ast::ConstructorExpression* expr) {
if (expr->IsScalarConstructor()) {
return EmitScalarConstructor(expr->AsScalarConstructor());
diff --git a/src/writer/wgsl/generator_impl.h b/src/writer/wgsl/generator_impl.h
index 5805f09..0a9e6f4 100644
--- a/src/writer/wgsl/generator_impl.h
+++ b/src/writer/wgsl/generator_impl.h
@@ -98,10 +98,6 @@
/// @param stmt the statement
/// @returns true if the statment was emitted successfully
bool EmitCase(ast::CaseStatement* stmt);
- /// Handles generating a cast expression
- /// @param expr the cast expression
- /// @returns true if the cast was emitted
- bool EmitCast(ast::CastExpression* expr);
/// Handles generating a scalar constructor
/// @param expr the scalar constructor expression
/// @returns true if the scalar constructor is emitted
diff --git a/src/writer/wgsl/generator_impl_cast_test.cc b/src/writer/wgsl/generator_impl_cast_test.cc
index e388337..ee81a66 100644
--- a/src/writer/wgsl/generator_impl_cast_test.cc
+++ b/src/writer/wgsl/generator_impl_cast_test.cc
@@ -15,9 +15,9 @@
#include <memory>
#include "gtest/gtest.h"
-#include "src/ast/cast_expression.h"
#include "src/ast/identifier_expression.h"
#include "src/ast/type/f32_type.h"
+#include "src/ast/type_constructor_expression.h"
#include "src/writer/wgsl/generator_impl.h"
namespace tint {
@@ -29,12 +29,15 @@
TEST_F(WgslGeneratorImplTest, EmitExpression_Cast) {
ast::type::F32Type f32;
- auto id = std::make_unique<ast::IdentifierExpression>("id");
- ast::CastExpression cast(&f32, std::move(id));
+
+ ast::ExpressionList params;
+ params.push_back(std::make_unique<ast::IdentifierExpression>("id"));
+
+ ast::TypeConstructorExpression cast(&f32, std::move(params));
GeneratorImpl g;
ASSERT_TRUE(g.EmitExpression(&cast)) << g.error();
- EXPECT_EQ(g.result(), "cast<f32>(id)");
+ EXPECT_EQ(g.result(), "f32(id)");
}
} // namespace