[spirv-reader] Emit stores
Bug: tint:3 Change-Id: Ibda57e58ac13abb650eb0f3e01adbd40b439a82b Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/19120 Reviewed-by: dan sinclair <dsinclair@google.com>
This commit is contained in:
parent
7456f4258a
commit
a1a86007c9
|
@ -330,6 +330,7 @@ if(${TINT_BUILD_SPV_READER})
|
|||
reader/spirv/fail_stream_test.cc
|
||||
reader/spirv/function_decl_test.cc
|
||||
reader/spirv/function_var_test.cc
|
||||
reader/spirv/function_memory_test.cc
|
||||
reader/spirv/namer_test.cc
|
||||
reader/spirv/parser_impl_convert_member_decoration_test.cc
|
||||
reader/spirv/parser_impl_convert_type_test.cc
|
||||
|
|
|
@ -20,9 +20,8 @@
|
|||
#include "source/opt/function.h"
|
||||
#include "source/opt/instruction.h"
|
||||
#include "source/opt/module.h"
|
||||
#include "src/ast/bool_literal.h"
|
||||
#include "src/ast/float_literal.h"
|
||||
#include "src/ast/int_literal.h"
|
||||
#include "src/ast/assignment_statement.h"
|
||||
#include "src/ast/identifier_expression.h"
|
||||
#include "src/ast/scalar_constructor_expression.h"
|
||||
#include "src/ast/uint_literal.h"
|
||||
#include "src/ast/variable.h"
|
||||
|
@ -61,9 +60,7 @@ bool FunctionEmitter::Emit() {
|
|||
return false;
|
||||
}
|
||||
|
||||
// Start populating the body.
|
||||
|
||||
if (!EmitFunctionVariables()) {
|
||||
if (!EmitBody()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -134,6 +131,16 @@ ast::type::Type* FunctionEmitter::GetVariableStoreType(
|
|||
return parser_impl_.ConvertType(var_store_type_id);
|
||||
}
|
||||
|
||||
bool FunctionEmitter::EmitBody() {
|
||||
if (!EmitFunctionVariables()) {
|
||||
return false;
|
||||
}
|
||||
if (!EmitFunctionBodyStatements()) {
|
||||
return false;
|
||||
}
|
||||
return success();
|
||||
}
|
||||
|
||||
bool FunctionEmitter::EmitFunctionVariables() {
|
||||
if (failed()) {
|
||||
return false;
|
||||
|
@ -171,10 +178,66 @@ std::unique_ptr<ast::Expression> FunctionEmitter::MakeExpression(uint32_t id) {
|
|||
if (spirv_constant) {
|
||||
return parser_impl_.MakeConstantExpression(id);
|
||||
}
|
||||
const auto* inst = def_use_mgr_->GetDef(id);
|
||||
if (inst == nullptr) {
|
||||
Fail() << "ID " << id << " does not have a defining SPIR-V instruction";
|
||||
return nullptr;
|
||||
}
|
||||
switch (inst->opcode()) {
|
||||
case SpvOpVariable:
|
||||
// This is not a declaration, but a use of an identifier.
|
||||
return std::make_unique<ast::IdentifierExpression>(namer_.Name(id));
|
||||
default:
|
||||
break;
|
||||
}
|
||||
Fail() << "unhandled expression for ID " << id;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool FunctionEmitter::EmitFunctionBodyStatements() {
|
||||
// TODO(dneto): For now, emit only regular statements in the entry block.
|
||||
// We'll use assignments as markers in the tests, to be able to tell where
|
||||
// code is placed in control flow. First prove that we can emit assignments.
|
||||
return EmitStatementsInBasicBlock(*function_.entry());
|
||||
}
|
||||
|
||||
bool FunctionEmitter::EmitStatementsInBasicBlock(
|
||||
const spvtools::opt::BasicBlock& bb) {
|
||||
const auto* terminator = bb.terminator();
|
||||
const auto* merge = bb.GetMergeInst(); // Might be nullptr
|
||||
// Emit regular statements.
|
||||
for (auto& inst : bb) {
|
||||
if (&inst == terminator || &inst == merge || inst.opcode() == SpvOpLabel ||
|
||||
inst.opcode() == SpvOpVariable) {
|
||||
continue;
|
||||
}
|
||||
if (!EmitStatement(inst)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
// TODO(dneto): Handle the terminator
|
||||
return true;
|
||||
}
|
||||
|
||||
bool FunctionEmitter::EmitStatement(const spvtools::opt::Instruction& inst) {
|
||||
switch (inst.opcode()) {
|
||||
case SpvOpStore: {
|
||||
// TODO(dneto): Order of evaluation?
|
||||
auto lhs = MakeExpression(inst.GetSingleWordInOperand(0));
|
||||
auto rhs = MakeExpression(inst.GetSingleWordInOperand(1));
|
||||
ast_body_.emplace_back(std::make_unique<ast::AssignmentStatement>(
|
||||
std::move(lhs), std::move(rhs)));
|
||||
return success();
|
||||
}
|
||||
case SpvOpFunctionCall:
|
||||
// TODO(dneto): Fill this out. Make this pass, for existing tests
|
||||
return success();
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return Fail() << "unhandled instruction with opcode " << inst.opcode();
|
||||
}
|
||||
|
||||
} // namespace spirv
|
||||
} // namespace reader
|
||||
} // namespace tint
|
||||
|
|
|
@ -18,8 +18,10 @@
|
|||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
#include "source/opt/basic_block.h"
|
||||
#include "source/opt/constants.h"
|
||||
#include "source/opt/function.h"
|
||||
#include "source/opt/instruction.h"
|
||||
#include "source/opt/ir_context.h"
|
||||
#include "source/opt/type_manager.h"
|
||||
#include "src/ast/expression.h"
|
||||
|
@ -65,10 +67,29 @@ class FunctionEmitter {
|
|||
/// @returns true if emission has not yet failed.
|
||||
bool EmitFunctionDeclaration();
|
||||
|
||||
/// Emits the function body, populating |ast_body_|
|
||||
/// @returns false if emission failed.
|
||||
bool EmitBody();
|
||||
|
||||
/// Emits declarations of function variables.
|
||||
/// @returns false if emission failed.
|
||||
bool EmitFunctionVariables();
|
||||
|
||||
/// Emits statements in the body.
|
||||
/// @returns false if emission failed.
|
||||
bool EmitFunctionBodyStatements();
|
||||
|
||||
/// Emits a basic block
|
||||
/// @param bb internal representation of the basic block
|
||||
/// @returns false if emission failed.
|
||||
bool EmitStatementsInBasicBlock(const spvtools::opt::BasicBlock& bb);
|
||||
|
||||
/// Emits a normal instruction: not a terminator, label, or variable
|
||||
/// declaration.
|
||||
/// @param inst the instruction
|
||||
/// @returns false if emission failed.
|
||||
bool EmitStatement(const spvtools::opt::Instruction& inst);
|
||||
|
||||
/// Makes an expression
|
||||
/// @param id the SPIR-V ID of the value
|
||||
/// @returns true if emission has not yet failed.
|
||||
|
|
|
@ -0,0 +1,154 @@
|
|||
// 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/reader/spirv/function.h"
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "gmock/gmock.h"
|
||||
#include "src/reader/spirv/parser_impl.h"
|
||||
#include "src/reader/spirv/parser_impl_test_helper.h"
|
||||
#include "src/reader/spirv/spirv_tools_helpers_test.h"
|
||||
|
||||
namespace tint {
|
||||
namespace reader {
|
||||
namespace spirv {
|
||||
namespace {
|
||||
|
||||
using ::testing::HasSubstr;
|
||||
|
||||
TEST_F(SpvParserTest, EmitFunctionVariables_StoreBoolConst) {
|
||||
auto p = parser(test::Assemble(R"(
|
||||
%void = OpTypeVoid
|
||||
%voidfn = OpTypeFunction %void
|
||||
%ty = OpTypeBool
|
||||
%true = OpConstantTrue %ty
|
||||
%false = OpConstantFalse %ty
|
||||
%null = OpConstantNull %ty
|
||||
%ptr_ty = OpTypePointer Function %ty
|
||||
%100 = OpFunction %void None %voidfn
|
||||
%entry = OpLabel
|
||||
%1 = OpVariable %ptr_ty Function
|
||||
OpStore %1 %true
|
||||
OpStore %1 %false
|
||||
OpStore %1 %null
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)"));
|
||||
ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
|
||||
FunctionEmitter fe(p, *spirv_function(100));
|
||||
EXPECT_TRUE(fe.EmitBody()) << p->error();
|
||||
EXPECT_THAT(ToString(fe.ast_body()), HasSubstr(R"(Assignment{
|
||||
Identifier{x_1}
|
||||
ScalarConstructor{true}
|
||||
}
|
||||
Assignment{
|
||||
Identifier{x_1}
|
||||
ScalarConstructor{false}
|
||||
}
|
||||
Assignment{
|
||||
Identifier{x_1}
|
||||
ScalarConstructor{false}
|
||||
})"));
|
||||
}
|
||||
|
||||
TEST_F(SpvParserTest, EmitFunctionVariables_StoreUintConst) {
|
||||
auto p = parser(test::Assemble(R"(
|
||||
%void = OpTypeVoid
|
||||
%voidfn = OpTypeFunction %void
|
||||
%ty = OpTypeInt 32 0
|
||||
%val = OpConstant %ty 42
|
||||
%null = OpConstantNull %ty
|
||||
%ptr_ty = OpTypePointer Function %ty
|
||||
%100 = OpFunction %void None %voidfn
|
||||
%entry = OpLabel
|
||||
%1 = OpVariable %ptr_ty Function
|
||||
OpStore %1 %val
|
||||
OpStore %1 %null
|
||||
OpReturn
|
||||
)"));
|
||||
ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
|
||||
FunctionEmitter fe(p, *spirv_function(100));
|
||||
EXPECT_TRUE(fe.EmitBody());
|
||||
EXPECT_THAT(ToString(fe.ast_body()), HasSubstr(R"(Assignment{
|
||||
Identifier{x_1}
|
||||
ScalarConstructor{42}
|
||||
}
|
||||
Assignment{
|
||||
Identifier{x_1}
|
||||
ScalarConstructor{0}
|
||||
})"));
|
||||
}
|
||||
|
||||
TEST_F(SpvParserTest, EmitFunctionVariables_StoreIntConst) {
|
||||
auto p = parser(test::Assemble(R"(
|
||||
%void = OpTypeVoid
|
||||
%voidfn = OpTypeFunction %void
|
||||
%ty = OpTypeInt 32 1
|
||||
%val = OpConstant %ty 42
|
||||
%null = OpConstantNull %ty
|
||||
%ptr_ty = OpTypePointer Function %ty
|
||||
%100 = OpFunction %void None %voidfn
|
||||
%entry = OpLabel
|
||||
%1 = OpVariable %ptr_ty Function
|
||||
OpStore %1 %val
|
||||
OpStore %1 %null
|
||||
OpReturn
|
||||
)"));
|
||||
ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
|
||||
FunctionEmitter fe(p, *spirv_function(100));
|
||||
EXPECT_TRUE(fe.EmitBody());
|
||||
EXPECT_THAT(ToString(fe.ast_body()), HasSubstr(R"(Assignment{
|
||||
Identifier{x_1}
|
||||
ScalarConstructor{42}
|
||||
}
|
||||
Assignment{
|
||||
Identifier{x_1}
|
||||
ScalarConstructor{0}
|
||||
})"));
|
||||
}
|
||||
|
||||
TEST_F(SpvParserTest, EmitFunctionVariables_StoreFloatConst) {
|
||||
auto p = parser(test::Assemble(R"(
|
||||
%void = OpTypeVoid
|
||||
%voidfn = OpTypeFunction %void
|
||||
%ty = OpTypeFloat 32
|
||||
%val = OpConstant %ty 42
|
||||
%null = OpConstantNull %ty
|
||||
%ptr_ty = OpTypePointer Function %ty
|
||||
%100 = OpFunction %void None %voidfn
|
||||
%entry = OpLabel
|
||||
%1 = OpVariable %ptr_ty Function
|
||||
OpStore %1 %val
|
||||
OpStore %1 %null
|
||||
OpReturn
|
||||
)"));
|
||||
ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
|
||||
FunctionEmitter fe(p, *spirv_function(100));
|
||||
EXPECT_TRUE(fe.EmitBody());
|
||||
EXPECT_THAT(ToString(fe.ast_body()), HasSubstr(R"(Assignment{
|
||||
Identifier{x_1}
|
||||
ScalarConstructor{42.000000}
|
||||
}
|
||||
Assignment{
|
||||
Identifier{x_1}
|
||||
ScalarConstructor{0.000000}
|
||||
})"));
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace spirv
|
||||
} // namespace reader
|
||||
} // namespace tint
|
Loading…
Reference in New Issue