mirror of
https://github.com/encounter/dawn-cmake.git
synced 2025-06-07 07:03:42 +00:00
[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/fail_stream_test.cc
|
||||||
reader/spirv/function_decl_test.cc
|
reader/spirv/function_decl_test.cc
|
||||||
reader/spirv/function_var_test.cc
|
reader/spirv/function_var_test.cc
|
||||||
|
reader/spirv/function_memory_test.cc
|
||||||
reader/spirv/namer_test.cc
|
reader/spirv/namer_test.cc
|
||||||
reader/spirv/parser_impl_convert_member_decoration_test.cc
|
reader/spirv/parser_impl_convert_member_decoration_test.cc
|
||||||
reader/spirv/parser_impl_convert_type_test.cc
|
reader/spirv/parser_impl_convert_type_test.cc
|
||||||
|
@ -20,9 +20,8 @@
|
|||||||
#include "source/opt/function.h"
|
#include "source/opt/function.h"
|
||||||
#include "source/opt/instruction.h"
|
#include "source/opt/instruction.h"
|
||||||
#include "source/opt/module.h"
|
#include "source/opt/module.h"
|
||||||
#include "src/ast/bool_literal.h"
|
#include "src/ast/assignment_statement.h"
|
||||||
#include "src/ast/float_literal.h"
|
#include "src/ast/identifier_expression.h"
|
||||||
#include "src/ast/int_literal.h"
|
|
||||||
#include "src/ast/scalar_constructor_expression.h"
|
#include "src/ast/scalar_constructor_expression.h"
|
||||||
#include "src/ast/uint_literal.h"
|
#include "src/ast/uint_literal.h"
|
||||||
#include "src/ast/variable.h"
|
#include "src/ast/variable.h"
|
||||||
@ -61,9 +60,7 @@ bool FunctionEmitter::Emit() {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Start populating the body.
|
if (!EmitBody()) {
|
||||||
|
|
||||||
if (!EmitFunctionVariables()) {
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -134,6 +131,16 @@ ast::type::Type* FunctionEmitter::GetVariableStoreType(
|
|||||||
return parser_impl_.ConvertType(var_store_type_id);
|
return parser_impl_.ConvertType(var_store_type_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool FunctionEmitter::EmitBody() {
|
||||||
|
if (!EmitFunctionVariables()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!EmitFunctionBodyStatements()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return success();
|
||||||
|
}
|
||||||
|
|
||||||
bool FunctionEmitter::EmitFunctionVariables() {
|
bool FunctionEmitter::EmitFunctionVariables() {
|
||||||
if (failed()) {
|
if (failed()) {
|
||||||
return false;
|
return false;
|
||||||
@ -171,10 +178,66 @@ std::unique_ptr<ast::Expression> FunctionEmitter::MakeExpression(uint32_t id) {
|
|||||||
if (spirv_constant) {
|
if (spirv_constant) {
|
||||||
return parser_impl_.MakeConstantExpression(id);
|
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;
|
Fail() << "unhandled expression for ID " << id;
|
||||||
return nullptr;
|
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 spirv
|
||||||
} // namespace reader
|
} // namespace reader
|
||||||
} // namespace tint
|
} // namespace tint
|
||||||
|
@ -18,8 +18,10 @@
|
|||||||
#include <memory>
|
#include <memory>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
|
#include "source/opt/basic_block.h"
|
||||||
#include "source/opt/constants.h"
|
#include "source/opt/constants.h"
|
||||||
#include "source/opt/function.h"
|
#include "source/opt/function.h"
|
||||||
|
#include "source/opt/instruction.h"
|
||||||
#include "source/opt/ir_context.h"
|
#include "source/opt/ir_context.h"
|
||||||
#include "source/opt/type_manager.h"
|
#include "source/opt/type_manager.h"
|
||||||
#include "src/ast/expression.h"
|
#include "src/ast/expression.h"
|
||||||
@ -65,10 +67,29 @@ class FunctionEmitter {
|
|||||||
/// @returns true if emission has not yet failed.
|
/// @returns true if emission has not yet failed.
|
||||||
bool EmitFunctionDeclaration();
|
bool EmitFunctionDeclaration();
|
||||||
|
|
||||||
|
/// Emits the function body, populating |ast_body_|
|
||||||
|
/// @returns false if emission failed.
|
||||||
|
bool EmitBody();
|
||||||
|
|
||||||
/// Emits declarations of function variables.
|
/// Emits declarations of function variables.
|
||||||
/// @returns false if emission failed.
|
/// @returns false if emission failed.
|
||||||
bool EmitFunctionVariables();
|
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
|
/// Makes an expression
|
||||||
/// @param id the SPIR-V ID of the value
|
/// @param id the SPIR-V ID of the value
|
||||||
/// @returns true if emission has not yet failed.
|
/// @returns true if emission has not yet failed.
|
||||||
|
154
src/reader/spirv/function_memory_test.cc
Normal file
154
src/reader/spirv/function_memory_test.cc
Normal file
@ -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…
x
Reference in New Issue
Block a user