ir/spirv-writer: Emit function declarations
Emit the return type, function type, and the OpFunction instruction. The body is just a label and a hardcoded OpReturn for now and will be emitted properly in a future patch, along with entry point declarations and function parameters. Bug: tint:1906 Change-Id: Id7117da078bccd77a00afb54a63c9c55b13236f9 Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/131600 Reviewed-by: Dan Sinclair <dsinclair@chromium.org> Kokoro: Kokoro <noreply+kokoro@google.com> Commit-Queue: James Price <jrprice@google.com>
This commit is contained in:
parent
0edb5204ab
commit
436fffe2a1
|
@ -1859,6 +1859,7 @@ if (tint_build_unittests) {
|
||||||
|
|
||||||
if (tint_build_ir) {
|
if (tint_build_ir) {
|
||||||
sources += [
|
sources += [
|
||||||
|
"writer/spirv/generator_impl_function_test.cc",
|
||||||
"writer/spirv/generator_impl_ir_test.cc",
|
"writer/spirv/generator_impl_ir_test.cc",
|
||||||
"writer/spirv/generator_impl_type_test.cc",
|
"writer/spirv/generator_impl_type_test.cc",
|
||||||
]
|
]
|
||||||
|
|
|
@ -1227,6 +1227,7 @@ if(TINT_BUILD_TESTS)
|
||||||
|
|
||||||
if(${TINT_BUILD_IR})
|
if(${TINT_BUILD_IR})
|
||||||
list(APPEND TINT_TEST_SRCS
|
list(APPEND TINT_TEST_SRCS
|
||||||
|
writer/spirv/generator_impl_function_test.cc
|
||||||
writer/spirv/generator_impl_ir_test.cc
|
writer/spirv/generator_impl_ir_test.cc
|
||||||
writer/spirv/generator_impl_type_test.cc
|
writer/spirv/generator_impl_type_test.cc
|
||||||
writer/spirv/test_helper_ir.h
|
writer/spirv/test_helper_ir.h
|
||||||
|
|
|
@ -0,0 +1,50 @@
|
||||||
|
// Copyright 2023 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/tint/writer/spirv/test_helper_ir.h"
|
||||||
|
|
||||||
|
namespace tint::writer::spirv {
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
TEST_F(SpvGeneratorImplTest, Function_Empty) {
|
||||||
|
auto* func = CreateFunction();
|
||||||
|
func->name = ir.symbols.Register("foo");
|
||||||
|
func->return_type = ir.types.Get<type::Void>();
|
||||||
|
|
||||||
|
generator_.EmitFunction(func);
|
||||||
|
EXPECT_EQ(DumpModule(generator_.Module()), R"(OpName %1 "foo"
|
||||||
|
%2 = OpTypeVoid
|
||||||
|
%3 = OpTypeFunction %2
|
||||||
|
%1 = OpFunction %2 None %3
|
||||||
|
%4 = OpLabel
|
||||||
|
OpReturn
|
||||||
|
OpFunctionEnd
|
||||||
|
)");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test that we do not emit the same function type more than once.
|
||||||
|
TEST_F(SpvGeneratorImplTest, Function_DeduplicateType) {
|
||||||
|
auto* func = CreateFunction();
|
||||||
|
func->return_type = ir.types.Get<type::Void>();
|
||||||
|
|
||||||
|
generator_.EmitFunction(func);
|
||||||
|
generator_.EmitFunction(func);
|
||||||
|
generator_.EmitFunction(func);
|
||||||
|
EXPECT_EQ(DumpTypes(), R"(%2 = OpTypeVoid
|
||||||
|
%3 = OpTypeFunction %2
|
||||||
|
)");
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
} // namespace tint::writer::spirv
|
|
@ -43,8 +43,10 @@ bool GeneratorImplIr::Generate() {
|
||||||
// TODO(crbug.com/tint/1906): Emit variables.
|
// TODO(crbug.com/tint/1906): Emit variables.
|
||||||
(void)zero_init_workgroup_memory_;
|
(void)zero_init_workgroup_memory_;
|
||||||
|
|
||||||
// TODO(crbug.com/tint/1906): Emit functions.
|
// Emit functions.
|
||||||
(void)ir_;
|
for (auto* func : ir_->functions) {
|
||||||
|
EmitFunction(func);
|
||||||
|
}
|
||||||
|
|
||||||
// Serialize the module into binary SPIR-V.
|
// Serialize the module into binary SPIR-V.
|
||||||
writer_.WriteHeader(module_.IdBound());
|
writer_.WriteHeader(module_.IdBound());
|
||||||
|
@ -79,4 +81,46 @@ uint32_t GeneratorImplIr::Type(const type::Type* ty) {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void GeneratorImplIr::EmitFunction(const ir::Function* func) {
|
||||||
|
// Make an ID for the function.
|
||||||
|
auto id = module_.NextId();
|
||||||
|
|
||||||
|
// Emit the function name.
|
||||||
|
module_.PushDebug(spv::Op::OpName, {id, Operand(func->name.Name())});
|
||||||
|
|
||||||
|
// TODO(jrprice): Emit OpEntryPoint and OpExecutionMode declarations if needed.
|
||||||
|
|
||||||
|
// Get the ID for the return type.
|
||||||
|
auto return_type_id = Type(func->return_type);
|
||||||
|
|
||||||
|
// Get the ID for the function type (creating it if needed).
|
||||||
|
// TODO(jrprice): Add the parameter types when they are supported in the IR.
|
||||||
|
FunctionType function_type{return_type_id, {}};
|
||||||
|
auto function_type_id = function_types_.GetOrCreate(function_type, [&]() {
|
||||||
|
auto func_ty_id = module_.NextId();
|
||||||
|
OperandList operands = {func_ty_id, return_type_id};
|
||||||
|
operands.insert(operands.end(), function_type.param_type_ids.begin(),
|
||||||
|
function_type.param_type_ids.end());
|
||||||
|
module_.PushType(spv::Op::OpTypeFunction, operands);
|
||||||
|
return func_ty_id;
|
||||||
|
});
|
||||||
|
|
||||||
|
// Declare the function.
|
||||||
|
auto decl = Instruction{spv::Op::OpFunction,
|
||||||
|
{return_type_id, id, SpvFunctionControlMaskNone, function_type_id}};
|
||||||
|
|
||||||
|
// Create a function that we will add instructions to.
|
||||||
|
// TODO(jrprice): Add the parameter declarations when they are supported in the IR.
|
||||||
|
auto entry_block = module_.NextId();
|
||||||
|
Function current_function_(decl, entry_block, {});
|
||||||
|
|
||||||
|
// TODO(jrprice): Emit the body of the function.
|
||||||
|
|
||||||
|
// TODO(jrprice): Remove this when we start emitting OpReturn for branches to the terminator.
|
||||||
|
current_function_.push_inst(spv::Op::OpReturn, {});
|
||||||
|
|
||||||
|
// Add the function to the module.
|
||||||
|
module_.PushFunction(current_function_);
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace tint::writer::spirv
|
} // namespace tint::writer::spirv
|
||||||
|
|
|
@ -19,11 +19,13 @@
|
||||||
|
|
||||||
#include "src/tint/diagnostic/diagnostic.h"
|
#include "src/tint/diagnostic/diagnostic.h"
|
||||||
#include "src/tint/utils/hashmap.h"
|
#include "src/tint/utils/hashmap.h"
|
||||||
|
#include "src/tint/utils/vector.h"
|
||||||
#include "src/tint/writer/spirv/binary_writer.h"
|
#include "src/tint/writer/spirv/binary_writer.h"
|
||||||
#include "src/tint/writer/spirv/module.h"
|
#include "src/tint/writer/spirv/module.h"
|
||||||
|
|
||||||
// Forward declarations
|
// Forward declarations
|
||||||
namespace tint::ir {
|
namespace tint::ir {
|
||||||
|
class Function;
|
||||||
class Module;
|
class Module;
|
||||||
} // namespace tint::ir
|
} // namespace tint::ir
|
||||||
namespace tint::type {
|
namespace tint::type {
|
||||||
|
@ -58,15 +60,47 @@ class GeneratorImplIr {
|
||||||
/// @returns the result ID of the type
|
/// @returns the result ID of the type
|
||||||
uint32_t Type(const type::Type* ty);
|
uint32_t Type(const type::Type* ty);
|
||||||
|
|
||||||
|
/// Emit a function.
|
||||||
|
/// @param func the function to emit
|
||||||
|
void EmitFunction(const ir::Function* func);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
const ir::Module* ir_;
|
const ir::Module* ir_;
|
||||||
spirv::Module module_;
|
spirv::Module module_;
|
||||||
BinaryWriter writer_;
|
BinaryWriter writer_;
|
||||||
diag::List diagnostics_;
|
diag::List diagnostics_;
|
||||||
|
|
||||||
|
/// A function type used for an OpTypeFunction declaration.
|
||||||
|
struct FunctionType {
|
||||||
|
uint32_t return_type_id;
|
||||||
|
utils::Vector<uint32_t, 4> param_type_ids;
|
||||||
|
|
||||||
|
/// Hasher provides a hash function for the FunctionType.
|
||||||
|
struct Hasher {
|
||||||
|
/// @param ft the FunctionType to create a hash for
|
||||||
|
/// @return the hash value
|
||||||
|
inline std::size_t operator()(const FunctionType& ft) const {
|
||||||
|
size_t hash = utils::Hash(ft.return_type_id);
|
||||||
|
for (auto& p : ft.param_type_ids) {
|
||||||
|
hash = utils::HashCombine(hash, p);
|
||||||
|
}
|
||||||
|
return hash;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Equality operator for FunctionType.
|
||||||
|
bool operator==(const FunctionType& other) const {
|
||||||
|
return (param_type_ids == other.param_type_ids) &&
|
||||||
|
(return_type_id == other.return_type_id);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
/// The map of types to their result IDs.
|
/// The map of types to their result IDs.
|
||||||
utils::Hashmap<const type::Type*, uint32_t, 8> types_;
|
utils::Hashmap<const type::Type*, uint32_t, 8> types_;
|
||||||
|
|
||||||
|
/// The map of function types to their result IDs.
|
||||||
|
utils::Hashmap<FunctionType, uint32_t, 8, FunctionType::Hasher> function_types_;
|
||||||
|
|
||||||
bool zero_init_workgroup_memory_ = false;
|
bool zero_init_workgroup_memory_ = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -56,9 +56,13 @@ std::string Disassemble(const std::vector<uint32_t>& data) {
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string DumpBuilder(Builder& builder) {
|
std::string DumpBuilder(Builder& builder) {
|
||||||
|
return DumpModule(builder.Module());
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string DumpModule(Module& module) {
|
||||||
BinaryWriter writer;
|
BinaryWriter writer;
|
||||||
writer.WriteHeader(builder.Module().IdBound());
|
writer.WriteHeader(module.IdBound());
|
||||||
writer.WriteModule(&builder.Module());
|
writer.WriteModule(&module);
|
||||||
return Disassemble(writer.result());
|
return Disassemble(writer.result());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -32,6 +32,11 @@ std::string Disassemble(const std::vector<uint32_t>& data);
|
||||||
/// @returns the builder as a SPIR-V disassembly string
|
/// @returns the builder as a SPIR-V disassembly string
|
||||||
std::string DumpBuilder(Builder& builder);
|
std::string DumpBuilder(Builder& builder);
|
||||||
|
|
||||||
|
/// Dumps the given module to a SPIR-V disassembly string
|
||||||
|
/// @param module the module to convert
|
||||||
|
/// @returns the module as a SPIR-V disassembly string
|
||||||
|
std::string DumpModule(Module& module);
|
||||||
|
|
||||||
/// Dumps the given instruction to a SPIR-V disassembly string
|
/// Dumps the given instruction to a SPIR-V disassembly string
|
||||||
/// @param inst the instruction to dump
|
/// @param inst the instruction to dump
|
||||||
/// @returns the instruction as a SPIR-V disassembly string
|
/// @returns the instruction as a SPIR-V disassembly string
|
||||||
|
|
Loading…
Reference in New Issue