From abd472e45aea3a6d7358e3bfdca8dd8418fdb730 Mon Sep 17 00:00:00 2001 From: dan sinclair Date: Fri, 1 May 2020 19:05:55 +0000 Subject: [PATCH] [spirv-writer] Add start of cast support. This CL starts support for the cast expression. It adds the i32 to f32 conversion path. Bug: tint:5 Change-Id: Id1eafc38592060c4b5b91964302d79a847e2edaf Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/20628 Reviewed-by: David Neto --- BUILD.gn | 1 + src/CMakeLists.txt | 1 + src/type_determiner.cc | 4 + src/writer/spirv/builder.cc | 42 ++++++++++ src/writer/spirv/builder.h | 4 + .../spirv/builder_cast_expression_test.cc | 76 +++++++++++++++++++ 6 files changed, 128 insertions(+) create mode 100644 src/writer/spirv/builder_cast_expression_test.cc diff --git a/BUILD.gn b/BUILD.gn index 23074761cf..80be5fcbd8 100644 --- a/BUILD.gn +++ b/BUILD.gn @@ -686,6 +686,7 @@ source_set("tint_unittests_spv_writer_src") { "src/writer/spirv/builder_assign_test.cc", "src/writer/spirv/builder_binary_expression_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_entry_point_test.cc", "src/writer/spirv/builder_function_test.cc", diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index a47d8291a0..61bc317f5e 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -431,6 +431,7 @@ if(${TINT_BUILD_SPV_WRITER}) writer/spirv/builder_assign_test.cc writer/spirv/builder_binary_expression_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_entry_point_test.cc writer/spirv/builder_function_test.cc diff --git a/src/type_determiner.cc b/src/type_determiner.cc index 6a1f1d185b..31e66bdec2 100644 --- a/src/type_determiner.cc +++ b/src/type_determiner.cc @@ -359,6 +359,10 @@ bool TypeDeterminer::DetermineCall(ast::CallExpression* expr) { } bool TypeDeterminer::DetermineCast(ast::CastExpression* expr) { + if (!DetermineResultType(expr->expr())) { + return false; + } + expr->set_result_type(expr->type()); return true; } diff --git a/src/writer/spirv/builder.cc b/src/writer/spirv/builder.cc index 8cd55d8739..680abd3f41 100644 --- a/src/writer/spirv/builder.cc +++ b/src/writer/spirv/builder.cc @@ -25,6 +25,7 @@ #include "src/ast/bool_literal.h" #include "src/ast/builtin_decoration.h" #include "src/ast/call_expression.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" @@ -297,6 +298,9 @@ uint32_t Builder::GenerateExpression(ast::Expression* expr) { if (expr->IsCall()) { return GenerateCallExpression(expr->AsCall()); } + if (expr->IsCast()) { + return GenerateCastExpression(expr->AsCast()); + } if (expr->IsConstructor()) { return GenerateConstructorExpression(expr->AsConstructor(), false); } @@ -1145,6 +1149,44 @@ uint32_t Builder::GenerateCallExpression(ast::CallExpression* expr) { 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; + } + + 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()) { + op = spv::Op::OpConvertSToF; + } else if (from_type->IsU32() && to_type->IsF32()) { + op = spv::Op::OpConvertUToF; + } else if (from_type->IsF32() && to_type->IsI32()) { + op = spv::Op::OpConvertFToS; + } else if (from_type->IsF32() && to_type->IsU32()) { + op = spv::Op::OpConvertFToU; + } + if (op == spv::Op::OpNop) { + error_ = "unable to determine conversion type for cast"; + 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::StatementList& true_body, diff --git a/src/writer/spirv/builder.h b/src/writer/spirv/builder.h index f3a40d2f09..87f8b24ea9 100644 --- a/src/writer/spirv/builder.h +++ b/src/writer/spirv/builder.h @@ -279,6 +279,10 @@ class Builder { /// @param expr the expression to generate /// @returns the expression ID on success or 0 otherwise uint32_t GenerateCallExpression(ast::CallExpression* expr); + /// Generates a cast expression + /// @param expr the expression to generate + /// @returns the expression ID on success or 0 otherwise + uint32_t GenerateCastExpression(ast::CastExpression* 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 new file mode 100644 index 0000000000..0af27a284a --- /dev/null +++ b/src/writer/spirv/builder_cast_expression_test.cc @@ -0,0 +1,76 @@ +// 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/int_literal.h" +#include "src/ast/module.h" +#include "src/ast/scalar_constructor_expression.h" +#include "src/ast/type/f32_type.h" +#include "src/ast/type/i32_type.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, DISABLED_Cast_FloatToU32) {} + +TEST_F(BuilderTest, DISABLED_Cast_FloatToI32) {} + +TEST_F(BuilderTest, Cast_I32ToFloat) { + ast::type::I32Type i32; + ast::type::F32Type f32; + + ast::CastExpression cast(&f32, + std::make_unique( + std::make_unique(&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, DISABLED_Cast_U32ToFloat) {} + +TEST_F(BuilderTest, DISABLED_Cast_WithLoad) {} + +TEST_F(BuilderTest, DISABLED_Cast_WithAlias) {} + +// TODO(dsinclair): Are here i32 -> u32 and u32->i32 casts? + +} // namespace +} // namespace spirv +} // namespace writer +} // namespace tint