From 07aead8570071c3d728dda8ae0f334906dd6678d Mon Sep 17 00:00:00 2001 From: dan sinclair Date: Tue, 14 Apr 2020 15:03:13 +0000 Subject: [PATCH] [spirv-writer] Adding binary equals generation This CL adds generation for a == operator. Bug: tint:5 Change-Id: Ib27836a42153f3732927234cfa9aed342d0f9ac1 Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/19402 Reviewed-by: Ryan Harrison --- src/writer/spirv/builder.cc | 60 ++++--- .../spirv/builder_binary_expression_test.cc | 162 ++++++++++++++++++ 2 files changed, 198 insertions(+), 24 deletions(-) diff --git a/src/writer/spirv/builder.cc b/src/writer/spirv/builder.cc index 21e8f42fe7..a3e634deab 100644 --- a/src/writer/spirv/builder.cc +++ b/src/writer/spirv/builder.cc @@ -547,38 +547,50 @@ uint32_t Builder::GenerateLiteralIfNeeded(ast::Literal* lit) { } uint32_t Builder::GenerateBinaryExpression(ast::BinaryExpression* expr) { + auto lhs_id = GenerateExpressionAndLoad(expr->lhs()); + if (lhs_id == 0) { + return 0; + } + auto rhs_id = GenerateExpressionAndLoad(expr->rhs()); + if (rhs_id == 0) { + return 0; + } + + auto result = result_op(); + auto result_id = result.to_i(); + + auto lhs_type = expr->lhs()->result_type(); + + auto expr_type = expr->result_type(); + auto type_id = GenerateTypeIfNeeded(expr_type); + if (type_id == 0) { + return 0; + } + + spv::Op op = spv::Op::OpNop; if (expr->IsAdd()) { - auto lhs_id = GenerateExpressionAndLoad(expr->lhs()); - if (lhs_id == 0) { - return 0; - } - auto rhs_id = GenerateExpressionAndLoad(expr->rhs()); - if (rhs_id == 0) { - return 0; - } - - auto result = result_op(); - auto result_id = result.to_i(); - - auto expr_type = expr->result_type(); - auto type_id = GenerateTypeIfNeeded(expr_type); - if (type_id == 0) { - return 0; - } - // This handles int and float and the vectors of those types. Other types // should have been rejected by validation. - spv::Op op = spv::Op::OpIAdd; + op = spv::Op::OpIAdd; if (expr_type->IsF32() || (expr_type->IsVector() && expr_type->AsVector()->type()->IsF32())) { op = spv::Op::OpFAdd; } - push_function_inst(op, {Operand::Int(type_id), result, Operand::Int(lhs_id), - Operand::Int(rhs_id)}); - - return result_id; + } else if (expr->IsEqual()) { + // This handles int and float and the vectors of those types. Other types + // should have been rejected by validation. + op = spv::Op::OpIEqual; + if (lhs_type->IsF32() || + (lhs_type->IsVector() && lhs_type->AsVector()->type()->IsF32())) { + op = spv::Op::OpFOrdEqual; + } + } else { + return 0; } - return 0; + + push_function_inst(op, {Operand::Int(type_id), result, Operand::Int(lhs_id), + Operand::Int(rhs_id)}); + return result_id; } bool Builder::GenerateReturnStatement(ast::ReturnStatement* stmt) { diff --git a/src/writer/spirv/builder_binary_expression_test.cc b/src/writer/spirv/builder_binary_expression_test.cc index 5827ef20af..6b0848f3be 100644 --- a/src/writer/spirv/builder_binary_expression_test.cc +++ b/src/writer/spirv/builder_binary_expression_test.cc @@ -200,6 +200,168 @@ INSTANTIATE_TEST_SUITE_P(BuilderTest, testing::Values(BinaryData{ast::BinaryOp::kAdd, "OpFAdd"})); +using BinaryCompareIntegerTest = testing::TestWithParam; +TEST_P(BinaryCompareIntegerTest, Scalar) { + auto param = GetParam(); + + ast::type::I32Type i32; + + auto lhs = std::make_unique( + std::make_unique(&i32, 3)); + auto rhs = std::make_unique( + std::make_unique(&i32, 4)); + + ast::BinaryExpression expr(param.op, std::move(lhs), std::move(rhs)); + + Context ctx; + TypeDeterminer td(&ctx); + ASSERT_TRUE(td.DetermineResultType(&expr)) << td.error(); + + Builder b; + b.push_function(Function{}); + + ASSERT_EQ(b.GenerateBinaryExpression(&expr), 4) << b.error(); + EXPECT_EQ(DumpInstructions(b.types()), R"(%1 = OpTypeInt 32 1 +%2 = OpConstant %1 3 +%3 = OpConstant %1 4 +%5 = OpTypeBool +)"); + EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), + "%4 = " + param.name + " %5 %2 %3\n"); +} + +TEST_P(BinaryCompareIntegerTest, Vector) { + auto param = GetParam(); + + ast::type::I32Type i32; + ast::type::VectorType vec3(&i32, 3); + + ast::ExpressionList vals; + vals.push_back(std::make_unique( + std::make_unique(&i32, 1))); + vals.push_back(std::make_unique( + std::make_unique(&i32, 1))); + vals.push_back(std::make_unique( + std::make_unique(&i32, 1))); + auto lhs = + std::make_unique(&vec3, std::move(vals)); + + vals.push_back(std::make_unique( + std::make_unique(&i32, 1))); + vals.push_back(std::make_unique( + std::make_unique(&i32, 1))); + vals.push_back(std::make_unique( + std::make_unique(&i32, 1))); + auto rhs = + std::make_unique(&vec3, std::move(vals)); + + Context ctx; + TypeDeterminer td(&ctx); + + ast::BinaryExpression expr(param.op, std::move(lhs), std::move(rhs)); + + ASSERT_TRUE(td.DetermineResultType(&expr)) << td.error(); + + Builder b; + b.push_function(Function{}); + + ASSERT_EQ(b.GenerateBinaryExpression(&expr), 5) << b.error(); + EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeInt 32 1 +%1 = OpTypeVector %2 3 +%3 = OpConstant %2 1 +%4 = OpConstantComposite %1 %3 %3 %3 +%7 = OpTypeBool +%6 = OpTypeVector %7 3 +)"); + EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), + "%5 = " + param.name + " %6 %4 %4\n"); +} +INSTANTIATE_TEST_SUITE_P(BuilderTest, + BinaryCompareIntegerTest, + testing::Values(BinaryData{ast::BinaryOp::kEqual, + "OpIEqual"})); + +using BinaryCompareFloatTest = testing::TestWithParam; +TEST_P(BinaryCompareFloatTest, Scalar) { + auto param = GetParam(); + + ast::type::F32Type f32; + + auto lhs = std::make_unique( + std::make_unique(&f32, 3.2f)); + auto rhs = std::make_unique( + std::make_unique(&f32, 4.5f)); + + ast::BinaryExpression expr(param.op, std::move(lhs), std::move(rhs)); + + Context ctx; + TypeDeterminer td(&ctx); + ASSERT_TRUE(td.DetermineResultType(&expr)) << td.error(); + + Builder b; + b.push_function(Function{}); + + ASSERT_EQ(b.GenerateBinaryExpression(&expr), 4) << b.error(); + EXPECT_EQ(DumpInstructions(b.types()), R"(%1 = OpTypeFloat 32 +%2 = OpConstant %1 3.20000005 +%3 = OpConstant %1 4.5 +%5 = OpTypeBool +)"); + EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), + "%4 = " + param.name + " %5 %2 %3\n"); +} + +TEST_P(BinaryCompareFloatTest, Vector) { + auto param = GetParam(); + + ast::type::F32Type f32; + ast::type::VectorType vec3(&f32, 3); + + ast::ExpressionList vals; + vals.push_back(std::make_unique( + std::make_unique(&f32, 1.f))); + vals.push_back(std::make_unique( + std::make_unique(&f32, 1.f))); + vals.push_back(std::make_unique( + std::make_unique(&f32, 1.f))); + auto lhs = + std::make_unique(&vec3, std::move(vals)); + + vals.push_back(std::make_unique( + std::make_unique(&f32, 1.f))); + vals.push_back(std::make_unique( + std::make_unique(&f32, 1.f))); + vals.push_back(std::make_unique( + std::make_unique(&f32, 1.f))); + auto rhs = + std::make_unique(&vec3, std::move(vals)); + + Context ctx; + TypeDeterminer td(&ctx); + + ast::BinaryExpression expr(param.op, std::move(lhs), std::move(rhs)); + + ASSERT_TRUE(td.DetermineResultType(&expr)) << td.error(); + + Builder b; + b.push_function(Function{}); + + ASSERT_EQ(b.GenerateBinaryExpression(&expr), 5) << b.error(); + EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 32 +%1 = OpTypeVector %2 3 +%3 = OpConstant %2 1 +%4 = OpConstantComposite %1 %3 %3 %3 +%7 = OpTypeBool +%6 = OpTypeVector %7 3 +)"); + EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), + "%5 = " + param.name + " %6 %4 %4\n"); +} +INSTANTIATE_TEST_SUITE_P(BuilderTest, + BinaryCompareFloatTest, + testing::Values(BinaryData{ast::BinaryOp::kEqual, + "OpFOrdEqual"})); + } // namespace } // namespace spirv } // namespace writer