mirror of
https://github.com/xenia-project/SPIRV-Tools.git
synced 2024-11-23 11:19:41 +00:00
Add IrBuilder for constructing SPIR-V in-memory representation.
This commit is contained in:
parent
200e897887
commit
8590f9cc81
@ -2,11 +2,13 @@ add_library(SPIRV-Tools-opt
|
||||
basic_block.h
|
||||
function.h
|
||||
instruction.h
|
||||
ir_loader.h
|
||||
module.h
|
||||
reflect.h
|
||||
|
||||
function.cpp
|
||||
instruction.cpp
|
||||
ir_loader.cpp
|
||||
module.cpp
|
||||
)
|
||||
|
||||
|
123
source/opt/ir_loader.cpp
Normal file
123
source/opt/ir_loader.cpp
Normal file
@ -0,0 +1,123 @@
|
||||
// Copyright (c) 2016 Google Inc.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a
|
||||
// copy of this software and/or associated documentation files (the
|
||||
// "Materials"), to deal in the Materials without restriction, including
|
||||
// without limitation the rights to use, copy, modify, merge, publish,
|
||||
// distribute, sublicense, and/or sell copies of the Materials, and to
|
||||
// permit persons to whom the Materials are furnished to do so, subject to
|
||||
// the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included
|
||||
// in all copies or substantial portions of the Materials.
|
||||
//
|
||||
// MODIFICATIONS TO THIS FILE MAY MEAN IT NO LONGER ACCURATELY REFLECTS
|
||||
// KHRONOS STANDARDS. THE UNMODIFIED, NORMATIVE VERSIONS OF KHRONOS
|
||||
// SPECIFICATIONS AND HEADER INFORMATION ARE LOCATED AT
|
||||
// https://www.khronos.org/registry/
|
||||
//
|
||||
// THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
// MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
|
||||
|
||||
#include "ir_loader.h"
|
||||
|
||||
#include <cassert>
|
||||
|
||||
#include "reflect.h"
|
||||
|
||||
namespace spvtools {
|
||||
namespace opt {
|
||||
namespace ir {
|
||||
|
||||
void IrLoader::AddInstruction(const spv_parsed_instruction_t* inst) {
|
||||
const auto opcode = static_cast<SpvOp>(inst->opcode);
|
||||
if (IsDebugLineInst(opcode)) {
|
||||
dbg_line_info_.push_back(Instruction(*inst));
|
||||
return;
|
||||
}
|
||||
|
||||
Instruction spv_inst(*inst, std::move(dbg_line_info_));
|
||||
dbg_line_info_.clear();
|
||||
// Handle function and basic block boundaries first, then normal
|
||||
// instructions.
|
||||
if (opcode == SpvOpFunction) {
|
||||
assert(function_ == nullptr);
|
||||
assert(block_ == nullptr);
|
||||
function_.reset(new Function(std::move(spv_inst)));
|
||||
} else if (opcode == SpvOpFunctionEnd) {
|
||||
assert(function_ != nullptr);
|
||||
assert(block_ == nullptr);
|
||||
module_->AddFunction(std::move(*function_.release()));
|
||||
function_ = nullptr;
|
||||
} else if (opcode == SpvOpLabel) {
|
||||
assert(function_ != nullptr);
|
||||
assert(block_ == nullptr);
|
||||
block_.reset(new BasicBlock(std::move(spv_inst)));
|
||||
} else if (IsTerminatorInst(opcode)) {
|
||||
assert(function_ != nullptr);
|
||||
assert(block_ != nullptr);
|
||||
block_->AddInstruction(std::move(spv_inst));
|
||||
function_->AddBasicBlock(std::move(*block_.release()));
|
||||
block_ = nullptr;
|
||||
} else {
|
||||
if (function_ == nullptr) { // Outside function definition
|
||||
assert(block_ == nullptr);
|
||||
if (opcode == SpvOpCapability) {
|
||||
module_->AddCapability(std::move(spv_inst));
|
||||
} else if (opcode == SpvOpExtension) {
|
||||
module_->AddExtension(std::move(spv_inst));
|
||||
} else if (opcode == SpvOpExtInstImport) {
|
||||
module_->AddExtInstImport(std::move(spv_inst));
|
||||
} else if (opcode == SpvOpMemoryModel) {
|
||||
module_->SetMemoryModel(std::move(spv_inst));
|
||||
} else if (opcode == SpvOpEntryPoint) {
|
||||
module_->AddEntryPoint(std::move(spv_inst));
|
||||
} else if (opcode == SpvOpExecutionMode) {
|
||||
module_->AddExecutionMode(std::move(spv_inst));
|
||||
} else if (IsDebugInst(opcode)) {
|
||||
module_->AddDebugInst(std::move(spv_inst));
|
||||
} else if (IsAnnotationInst(opcode)) {
|
||||
module_->AddAnnotationInst(std::move(spv_inst));
|
||||
} else if (IsTypeInst(opcode)) {
|
||||
module_->AddType(std::move(spv_inst));
|
||||
} else if (IsConstantInst(opcode)) {
|
||||
module_->AddConstant(std::move(spv_inst));
|
||||
} else if (opcode == SpvOpVariable) {
|
||||
module_->AddGlobalVariable(std::move(spv_inst));
|
||||
} else {
|
||||
assert(0 && "unhandled inst type outside function defintion");
|
||||
}
|
||||
} else {
|
||||
if (block_ == nullptr) { // Inside function but outside blocks
|
||||
assert(opcode == SpvOpFunctionParameter);
|
||||
function_->AddParameter(std::move(spv_inst));
|
||||
} else {
|
||||
block_->AddInstruction(std::move(spv_inst));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Resolves internal references among the module, functions, basic blocks, etc.
|
||||
// This function should be called after adding all instructions.
|
||||
//
|
||||
// This concluding call is needed because the whole in memory representation is
|
||||
// designed around rvalues and move semantics, which subject to pointer
|
||||
// invalidation during module construction internally.
|
||||
void IrLoader::EndModule() {
|
||||
for (auto& function : module_->functions()) {
|
||||
for (auto& bb : function.basic_blocks()) {
|
||||
bb.SetParent(&function);
|
||||
}
|
||||
function.SetParent(module_);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace ir
|
||||
} // namespace opt
|
||||
} // namespace spvtools
|
83
source/opt/ir_loader.h
Normal file
83
source/opt/ir_loader.h
Normal file
@ -0,0 +1,83 @@
|
||||
// Copyright (c) 2016 Google Inc.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a
|
||||
// copy of this software and/or associated documentation files (the
|
||||
// "Materials"), to deal in the Materials without restriction, including
|
||||
// without limitation the rights to use, copy, modify, merge, publish,
|
||||
// distribute, sublicense, and/or sell copies of the Materials, and to
|
||||
// permit persons to whom the Materials are furnished to do so, subject to
|
||||
// the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included
|
||||
// in all copies or substantial portions of the Materials.
|
||||
//
|
||||
// MODIFICATIONS TO THIS FILE MAY MEAN IT NO LONGER ACCURATELY REFLECTS
|
||||
// KHRONOS STANDARDS. THE UNMODIFIED, NORMATIVE VERSIONS OF KHRONOS
|
||||
// SPECIFICATIONS AND HEADER INFORMATION ARE LOCATED AT
|
||||
// https://www.khronos.org/registry/
|
||||
//
|
||||
// THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
// MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
|
||||
|
||||
#ifndef LIBSPIRV_OPT_IR_LOADER_H_
|
||||
#define LIBSPIRV_OPT_IR_LOADER_H_
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include "basic_block.h"
|
||||
#include "instruction.h"
|
||||
#include "module.h"
|
||||
#include "spirv-tools/libspirv.h"
|
||||
|
||||
namespace spvtools {
|
||||
namespace opt {
|
||||
namespace ir {
|
||||
|
||||
// Loader class for constructing SPIR-V in-memory IR representation. Methods in
|
||||
// this class are designed to work with the interface for spvBinaryParse() in
|
||||
// libspirv.h so that we can leverage the syntax checks implemented behind it.
|
||||
//
|
||||
// The user is expected to call SetModuleHeader() to fill in the module's
|
||||
// header, and then AddInstruction() for each decoded instruction, and finally
|
||||
// EndModule() to finalize the module. The instructions processed in sequence
|
||||
// by AddInstruction() should comprise a valid SPIR-V module.
|
||||
class IrLoader {
|
||||
public:
|
||||
// Instantiates a builder to construct the given |module| gradually.
|
||||
IrLoader(Module* module) : module_(module) {}
|
||||
|
||||
// Sets the fields in the module's header to the given parameters.
|
||||
void SetModuleHeader(uint32_t magic, uint32_t version, uint32_t generator,
|
||||
uint32_t bound, uint32_t reserved) {
|
||||
module_->SetHeader({magic, version, generator, bound, reserved});
|
||||
}
|
||||
// Adds an instruction to the module. This method will properly capture and
|
||||
// store the data provided in |inst| so that |inst| is no longer needed after
|
||||
// returning.
|
||||
void AddInstruction(const spv_parsed_instruction_t* inst);
|
||||
// Finalizes the module construction. This must be called after the module
|
||||
// header has been set and all instructions have been added.
|
||||
// Resolves internal bookkeeping.
|
||||
void EndModule();
|
||||
|
||||
private:
|
||||
// The module to be built.
|
||||
Module* module_;
|
||||
// The current Function under construction.
|
||||
std::unique_ptr<Function> function_;
|
||||
// The current BasicBlock under construction.
|
||||
std::unique_ptr<BasicBlock> block_;
|
||||
// Line related debug instructions accumulated thus far.
|
||||
std::vector<Instruction> dbg_line_info_;
|
||||
};
|
||||
|
||||
} // namespace ir
|
||||
} // namespace opt
|
||||
} // namespace spvtools
|
||||
|
||||
#endif // LIBSPIRV_OPT_IR_LOADER_H_
|
@ -33,9 +33,9 @@ namespace ir {
|
||||
|
||||
std::vector<Instruction*> Module::types() {
|
||||
std::vector<Instruction*> insts;
|
||||
for (uint32_t i = 0; i < types_and_constants_.size(); ++i) {
|
||||
if (IsTypeInst(types_and_constants_[i].opcode()))
|
||||
insts.push_back(&types_and_constants_[i]);
|
||||
for (uint32_t i = 0; i < types_values_.size(); ++i) {
|
||||
if (IsTypeInst(types_values_[i].opcode()))
|
||||
insts.push_back(&types_values_[i]);
|
||||
}
|
||||
return insts;
|
||||
};
|
||||
@ -43,14 +43,13 @@ std::vector<Instruction*> Module::types() {
|
||||
void Module::ForEachInst(const std::function<void(Instruction*)>& f) {
|
||||
for (auto& i : capabilities_) f(&i);
|
||||
for (auto& i : extensions_) f(&i);
|
||||
for (auto& i : ext_inst_sets_) f(&i);
|
||||
for (auto& i : ext_inst_imports_) f(&i);
|
||||
f(&memory_model_);
|
||||
for (auto& i : entry_points_) f(&i);
|
||||
for (auto& i : execution_modes_) f(&i);
|
||||
for (auto& i : debugs_) f(&i);
|
||||
for (auto& i : annotations_) f(&i);
|
||||
for (auto& i : types_and_constants_) f(&i);
|
||||
for (auto& i : variables_) f(&i);
|
||||
for (auto& i : types_values_) f(&i);
|
||||
for (auto& i : functions_) i.ForEachInst(f);
|
||||
}
|
||||
|
||||
@ -65,14 +64,13 @@ void Module::ToBinary(std::vector<uint32_t>* binary, bool skip_nop) const {
|
||||
// TODO(antiagainst): wow, looks like a duplication of the above.
|
||||
for (const auto& c : capabilities_) c.ToBinary(binary, skip_nop);
|
||||
for (const auto& e : extensions_) e.ToBinary(binary, skip_nop);
|
||||
for (const auto& e : ext_inst_sets_) e.ToBinary(binary, skip_nop);
|
||||
for (const auto& e : ext_inst_imports_) e.ToBinary(binary, skip_nop);
|
||||
memory_model_.ToBinary(binary, skip_nop);
|
||||
for (const auto& e : entry_points_) e.ToBinary(binary, skip_nop);
|
||||
for (const auto& e : execution_modes_) e.ToBinary(binary, skip_nop);
|
||||
for (const auto& d : debugs_) d.ToBinary(binary, skip_nop);
|
||||
for (const auto& a : annotations_) a.ToBinary(binary, skip_nop);
|
||||
for (const auto& t : types_and_constants_) t.ToBinary(binary, skip_nop);
|
||||
for (const auto& v : variables_) v.ToBinary(binary, skip_nop);
|
||||
for (const auto& t : types_values_) t.ToBinary(binary, skip_nop);
|
||||
for (const auto& f : functions_) f.ToBinary(binary, skip_nop);
|
||||
}
|
||||
|
||||
|
@ -28,8 +28,8 @@
|
||||
#define LIBSPIRV_OPT_MODULE_H_
|
||||
|
||||
#include <functional>
|
||||
#include <vector>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include "function.h"
|
||||
#include "instruction.h"
|
||||
@ -61,8 +61,8 @@ class Module {
|
||||
// Appends an extension instruction to this module.
|
||||
void AddExtension(Instruction&& e) { extensions_.push_back(std::move(e)); }
|
||||
// Appends an extended instruction set instruction to this module.
|
||||
void AddExtInstSet(Instruction&& e) {
|
||||
ext_inst_sets_.push_back(std::move(e));
|
||||
void AddExtInstImport(Instruction&& e) {
|
||||
ext_inst_imports_.push_back(std::move(e));
|
||||
}
|
||||
// Appends a memory model instruction to this module.
|
||||
void SetMemoryModel(Instruction&& m) { memory_model_ = std::move(m); }
|
||||
@ -79,15 +79,13 @@ class Module {
|
||||
annotations_.push_back(std::move(a));
|
||||
}
|
||||
// Appends a type-declaration instruction to this module.
|
||||
void AddType(Instruction&& t) {
|
||||
types_and_constants_.push_back(std::move(t));
|
||||
}
|
||||
void AddType(Instruction&& t) { types_values_.push_back(std::move(t)); }
|
||||
// Appends a constant-creation instruction to this module.
|
||||
void AddConstant(Instruction&& c) {
|
||||
types_and_constants_.push_back(std::move(c));
|
||||
void AddConstant(Instruction&& c) { types_values_.push_back(std::move(c)); }
|
||||
// Appends a global variable-declaration instruction to this module.
|
||||
void AddGlobalVariable(Instruction&& v) {
|
||||
types_values_.push_back(std::move(v));
|
||||
}
|
||||
// Appends a variable-declaration instruction to this module.
|
||||
void AddVariable(Instruction&& v) { variables_.push_back(std::move(v)); }
|
||||
// Appends a function to this module.
|
||||
void AddFunction(Function&& f) { functions_.push_back(std::move(f)); }
|
||||
|
||||
@ -115,16 +113,14 @@ class Module {
|
||||
// Section 2.4 of the SPIR-V specification.
|
||||
std::vector<Instruction> capabilities_;
|
||||
std::vector<Instruction> extensions_;
|
||||
std::vector<Instruction> ext_inst_sets_;
|
||||
std::vector<Instruction> ext_inst_imports_;
|
||||
Instruction memory_model_; // A module only has one memory model instruction.
|
||||
std::vector<Instruction> entry_points_;
|
||||
std::vector<Instruction> execution_modes_;
|
||||
std::vector<Instruction> debugs_;
|
||||
std::vector<Instruction> annotations_;
|
||||
// Types and constants may depends on each other; thus they are grouped
|
||||
// together.
|
||||
std::vector<Instruction> types_and_constants_;
|
||||
std::vector<Instruction> variables_;
|
||||
// Type declarations, constants, and global variable declarations.
|
||||
std::vector<Instruction> types_values_;
|
||||
std::vector<Function> functions_;
|
||||
};
|
||||
|
||||
|
@ -49,6 +49,7 @@ function(add_spvtools_unittest)
|
||||
endif()
|
||||
target_include_directories(${ARG_TARGET} PRIVATE
|
||||
${spirv-tools_SOURCE_DIR}
|
||||
${spirv-tools_SOURCE_DIR}/include
|
||||
${SPIRV_HEADER_INCLUDE_DIR}
|
||||
${gtest_SOURCE_DIR}/include
|
||||
${gmock_SOURCE_DIR}/include
|
||||
@ -131,6 +132,7 @@ if (NOT ${SPIRV_SKIP_EXECUTABLES})
|
||||
TARGET UnitSPIRV
|
||||
SRCS ${TEST_SOURCES}
|
||||
LIBS ${SPIRV_TOOLS})
|
||||
add_subdirectory(opt)
|
||||
else()
|
||||
message(STATUS "Did not find googletest, tests will not be built."
|
||||
"To enable tests place googletest in '<spirv-dir>/external/googletest'.")
|
||||
|
30
test/opt/CMakeLists.txt
Normal file
30
test/opt/CMakeLists.txt
Normal file
@ -0,0 +1,30 @@
|
||||
# Copyright (c) 2016 Google Inc.
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining a
|
||||
# copy of this software and/or associated documentation files (the
|
||||
# "Materials"), to deal in the Materials without restriction, including
|
||||
# without limitation the rights to use, copy, modify, merge, publish,
|
||||
# distribute, sublicense, and/or sell copies of the Materials, and to
|
||||
# permit persons to whom the Materials are furnished to do so, subject to
|
||||
# the following conditions:
|
||||
#
|
||||
# The above copyright notice and this permission notice shall be included
|
||||
# in all copies or substantial portions of the Materials.
|
||||
#
|
||||
# MODIFICATIONS TO THIS FILE MAY MEAN IT NO LONGER ACCURATELY REFLECTS
|
||||
# KHRONOS STANDARDS. THE UNMODIFIED, NORMATIVE VERSIONS OF KHRONOS
|
||||
# SPECIFICATIONS AND HEADER INFORMATION ARE LOCATED AT
|
||||
# https://www.khronos.org/registry/
|
||||
#
|
||||
# THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
# IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
# CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
# TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
# MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
|
||||
|
||||
add_spvtools_unittest(TARGET ir_loader
|
||||
SRCS test_ir_loader.cpp opt_test_common.cpp
|
||||
LIBS SPIRV-Tools-opt ${SPIRV_TOOLS}
|
||||
)
|
116
test/opt/opt_test_common.cpp
Normal file
116
test/opt/opt_test_common.cpp
Normal file
@ -0,0 +1,116 @@
|
||||
// Copyright (c) 2016 Google Inc.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a
|
||||
// copy of this software and/or associated documentation files (the
|
||||
// "Materials"), to deal in the Materials without restriction, including
|
||||
// without limitation the rights to use, copy, modify, merge, publish,
|
||||
// distribute, sublicense, and/or sell copies of the Materials, and to
|
||||
// permit persons to whom the Materials are furnished to do so, subject to
|
||||
// the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included
|
||||
// in all copies or substantial portions of the Materials.
|
||||
//
|
||||
// MODIFICATIONS TO THIS FILE MAY MEAN IT NO LONGER ACCURATELY REFLECTS
|
||||
// KHRONOS STANDARDS. THE UNMODIFIED, NORMATIVE VERSIONS OF KHRONOS
|
||||
// SPECIFICATIONS AND HEADER INFORMATION ARE LOCATED AT
|
||||
// https://www.khronos.org/registry/
|
||||
//
|
||||
// THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
// MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
|
||||
|
||||
#include "opt_test_common.h"
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include "source/opt/ir_loader.h"
|
||||
#include "spirv-tools/libspirv.h"
|
||||
|
||||
namespace spvtools {
|
||||
namespace opt {
|
||||
|
||||
namespace {
|
||||
|
||||
// Sets the module header. Meets the interface requirement of spvBinaryParse().
|
||||
spv_result_t SetSpvHeader(void* builder, spv_endianness_t, uint32_t magic,
|
||||
uint32_t version, uint32_t generator,
|
||||
uint32_t id_bound, uint32_t reserved) {
|
||||
reinterpret_cast<ir::IrLoader*>(builder)->SetModuleHeader(
|
||||
magic, version, generator, id_bound, reserved);
|
||||
return SPV_SUCCESS;
|
||||
};
|
||||
|
||||
// Processes a parsed instruction. Meets the interface requirement of
|
||||
// spvBinaryParse().
|
||||
spv_result_t SetSpvInst(void* builder, const spv_parsed_instruction_t* inst) {
|
||||
reinterpret_cast<ir::IrLoader*>(builder)->AddInstruction(inst);
|
||||
return SPV_SUCCESS;
|
||||
};
|
||||
|
||||
} // annoymous namespace
|
||||
|
||||
// Assembles the given assembly |text| and returns the binary.
|
||||
std::vector<uint32_t> Assemble(const std::string& text) {
|
||||
spv_context context = spvContextCreate(SPV_ENV_UNIVERSAL_1_1);
|
||||
spv_binary binary = nullptr;
|
||||
spv_diagnostic diagnostic = nullptr;
|
||||
|
||||
spv_result_t status =
|
||||
spvTextToBinary(context, text.data(), text.size(), &binary, &diagnostic);
|
||||
EXPECT_EQ(SPV_SUCCESS, status) << "assemble text to binary failed";
|
||||
std::vector<uint32_t> result(binary->code, binary->code + binary->wordCount);
|
||||
|
||||
spvDiagnosticDestroy(diagnostic);
|
||||
spvBinaryDestroy(binary);
|
||||
spvContextDestroy(context);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// Disassembles the given SPIR-V |binary| and returns the assembly.
|
||||
std::string Disassemble(const std::vector<uint32_t>& binary) {
|
||||
spv_context context = spvContextCreate(SPV_ENV_UNIVERSAL_1_1);
|
||||
spv_text text = nullptr;
|
||||
spv_diagnostic diagnostic = nullptr;
|
||||
|
||||
spv_result_t status =
|
||||
spvBinaryToText(context, binary.data(), binary.size(),
|
||||
SPV_BINARY_TO_TEXT_OPTION_NO_HEADER, &text, &diagnostic);
|
||||
EXPECT_EQ(SPV_SUCCESS, status) << "disassemble binary to text failed";
|
||||
std::string result(text->str, text->str + text->length);
|
||||
|
||||
spvDiagnosticDestroy(diagnostic);
|
||||
spvTextDestroy(text);
|
||||
spvContextDestroy(context);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// Builds and returns a Module for the given SPIR-V |binary|.
|
||||
std::unique_ptr<ir::Module> BuildModule(const std::vector<uint32_t>& binary) {
|
||||
spv_context context = spvContextCreate(SPV_ENV_UNIVERSAL_1_1);
|
||||
spv_diagnostic diagnostic = nullptr;
|
||||
|
||||
std::unique_ptr<ir::Module> module(new ir::Module);
|
||||
ir::IrLoader builder(module.get());
|
||||
|
||||
spv_result_t status =
|
||||
spvBinaryParse(context, &builder, binary.data(), binary.size(),
|
||||
SetSpvHeader, SetSpvInst, &diagnostic);
|
||||
EXPECT_EQ(SPV_SUCCESS, status) << "build ir::Module from binary failed";
|
||||
|
||||
spvDiagnosticDestroy(diagnostic);
|
||||
spvContextDestroy(context);
|
||||
|
||||
builder.EndModule();
|
||||
|
||||
return module;
|
||||
}
|
||||
|
||||
} // namespace opt
|
||||
} // namespace spvtools
|
54
test/opt/opt_test_common.h
Normal file
54
test/opt/opt_test_common.h
Normal file
@ -0,0 +1,54 @@
|
||||
// Copyright (c) 2016 Google Inc.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a
|
||||
// copy of this software and/or associated documentation files (the
|
||||
// "Materials"), to deal in the Materials without restriction, including
|
||||
// without limitation the rights to use, copy, modify, merge, publish,
|
||||
// distribute, sublicense, and/or sell copies of the Materials, and to
|
||||
// permit persons to whom the Materials are furnished to do so, subject to
|
||||
// the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included
|
||||
// in all copies or substantial portions of the Materials.
|
||||
//
|
||||
// MODIFICATIONS TO THIS FILE MAY MEAN IT NO LONGER ACCURATELY REFLECTS
|
||||
// KHRONOS STANDARDS. THE UNMODIFIED, NORMATIVE VERSIONS OF KHRONOS
|
||||
// SPECIFICATIONS AND HEADER INFORMATION ARE LOCATED AT
|
||||
// https://www.khronos.org/registry/
|
||||
//
|
||||
// THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
// MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
|
||||
|
||||
#ifndef LIBSPIRV_TEST_OPT_OPT_TEST_COMMON_H_
|
||||
#define LIBSPIRV_TEST_OPT_OPT_TEST_COMMON_H_
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "source/opt/module.h"
|
||||
|
||||
namespace spvtools {
|
||||
namespace opt {
|
||||
|
||||
// TODO(antiagainst): expand and export these functions as the C++ interface in
|
||||
// libspirv.hpp.
|
||||
|
||||
// Assembles the given assembly |text| and returns the binary.
|
||||
std::vector<uint32_t> Assemble(const std::string& text);
|
||||
|
||||
// Disassembles the given SPIR-V |binary| and returns the assembly.
|
||||
std::string Disassemble(const std::vector<uint32_t>& binary);
|
||||
|
||||
// Builds and returns a Module for the given SPIR-V |binary|.
|
||||
std::unique_ptr<ir::Module> BuildModule(const std::vector<uint32_t>& binary);
|
||||
|
||||
} // namespace opt
|
||||
} // namespace spvtools
|
||||
|
||||
#endif // LIBSPIRV_TEST_OPT_OPT_TEST_COMMON_H_
|
193
test/opt/test_ir_loader.cpp
Normal file
193
test/opt/test_ir_loader.cpp
Normal file
@ -0,0 +1,193 @@
|
||||
// Copyright (c) 2016 Google Inc.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a
|
||||
// copy of this software and/or associated documentation files (the
|
||||
// "Materials"), to deal in the Materials without restriction, including
|
||||
// without limitation the rights to use, copy, modify, merge, publish,
|
||||
// distribute, sublicense, and/or sell copies of the Materials, and to
|
||||
// permit persons to whom the Materials are furnished to do so, subject to
|
||||
// the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included
|
||||
// in all copies or substantial portions of the Materials.
|
||||
//
|
||||
// MODIFICATIONS TO THIS FILE MAY MEAN IT NO LONGER ACCURATELY REFLECTS
|
||||
// KHRONOS STANDARDS. THE UNMODIFIED, NORMATIVE VERSIONS OF KHRONOS
|
||||
// SPECIFICATIONS AND HEADER INFORMATION ARE LOCATED AT
|
||||
// https://www.khronos.org/registry/
|
||||
//
|
||||
// THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
// MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include "opt_test_common.h"
|
||||
|
||||
namespace {
|
||||
|
||||
using namespace spvtools::opt;
|
||||
|
||||
TEST(IrBuilder, RoundTrip) {
|
||||
// #version 310 es
|
||||
// int add(int a, int b) { return a + b; }
|
||||
// void main() { add(1, 2); }
|
||||
const std::string text =
|
||||
"OpCapability Shader\n"
|
||||
"%1 = OpExtInstImport \"GLSL.std.450\"\n"
|
||||
"OpMemoryModel Logical GLSL450\n"
|
||||
"OpEntryPoint Vertex %2 \"main\"\n"
|
||||
"OpSource ESSL 310\n"
|
||||
"OpSourceExtension \"GL_GOOGLE_cpp_style_line_directive\"\n"
|
||||
"OpSourceExtension \"GL_GOOGLE_include_directive\"\n"
|
||||
"OpName %2 \"main\"\n"
|
||||
"OpName %3 \"add(i1;i1;\"\n"
|
||||
"OpName %4 \"a\"\n"
|
||||
"OpName %5 \"b\"\n"
|
||||
"OpName %6 \"param\"\n"
|
||||
"OpName %7 \"param\"\n"
|
||||
"%8 = OpTypeVoid\n"
|
||||
"%9 = OpTypeFunction %8\n"
|
||||
"%10 = OpTypeInt 32 1\n"
|
||||
"%11 = OpTypePointer Function %10\n"
|
||||
"%12 = OpTypeFunction %10 %11 %11\n"
|
||||
"%13 = OpConstant %10 1\n"
|
||||
"%14 = OpConstant %10 2\n"
|
||||
"%2 = OpFunction %8 None %9\n"
|
||||
"%15 = OpLabel\n"
|
||||
"%6 = OpVariable %11 Function\n"
|
||||
"%7 = OpVariable %11 Function\n"
|
||||
"OpStore %6 %13\n"
|
||||
"OpStore %7 %14\n"
|
||||
"%16 = OpFunctionCall %10 %3 %6 %7\n"
|
||||
"OpReturn\n"
|
||||
"OpFunctionEnd\n"
|
||||
"%3 = OpFunction %10 None %12\n"
|
||||
"%4 = OpFunctionParameter %11\n"
|
||||
"%5 = OpFunctionParameter %11\n"
|
||||
"%17 = OpLabel\n"
|
||||
"%18 = OpLoad %10 %4\n"
|
||||
"%19 = OpLoad %10 %5\n"
|
||||
"%20 = OpIAdd %10 %18 %19\n"
|
||||
"OpReturnValue %20\n"
|
||||
"OpFunctionEnd\n";
|
||||
|
||||
std::unique_ptr<ir::Module> module = BuildModule(Assemble(text));
|
||||
std::vector<uint32_t> binary;
|
||||
module->ToBinary(&binary, /* skip_nop = */ false);
|
||||
|
||||
EXPECT_EQ(text, Disassemble(binary));
|
||||
}
|
||||
|
||||
TEST(IrBuilder, KeepLineDebugInfo) {
|
||||
// #version 310 es
|
||||
// void main() {}
|
||||
const std::string text =
|
||||
"OpCapability Shader\n"
|
||||
"%1 = OpExtInstImport \"GLSL.std.450\"\n"
|
||||
"OpMemoryModel Logical GLSL450\n"
|
||||
"OpEntryPoint Vertex %2 \"main\"\n"
|
||||
"%3 = OpString \"minimal.vert\"\n"
|
||||
"OpSource ESSL 310\n"
|
||||
"OpName %2 \"main\"\n"
|
||||
"OpLine %3 10 10\n"
|
||||
"%4 = OpTypeVoid\n"
|
||||
"OpLine %3 100 100\n"
|
||||
"%5 = OpTypeFunction %4\n"
|
||||
"%2 = OpFunction %4 None %5\n"
|
||||
"OpLine %3 1 1\n"
|
||||
"OpNoLine\n"
|
||||
"OpLine %3 2 2\n"
|
||||
"OpLine %3 3 3\n"
|
||||
"%6 = OpLabel\n"
|
||||
"OpLine %3 4 4\n"
|
||||
"OpNoLine\n"
|
||||
"OpReturn\n"
|
||||
"OpFunctionEnd\n";
|
||||
|
||||
std::unique_ptr<ir::Module> module = BuildModule(Assemble(text));
|
||||
std::vector<uint32_t> binary;
|
||||
module->ToBinary(&binary, /* skip_nop = */ false);
|
||||
|
||||
EXPECT_EQ(text, Disassemble(binary));
|
||||
}
|
||||
|
||||
TEST(IrBuilder, LocalGlobalVariables) {
|
||||
// #version 310 es
|
||||
//
|
||||
// float gv1 = 10.;
|
||||
// float gv2 = 100.;
|
||||
//
|
||||
// float f() {
|
||||
// float lv1 = gv1 + gv2;
|
||||
// float lv2 = gv1 * gv2;
|
||||
// return lv1 / lv2;
|
||||
// }
|
||||
//
|
||||
// void main() {
|
||||
// float lv1 = gv1 - gv2;
|
||||
// }
|
||||
const std::string text =
|
||||
"OpCapability Shader\n"
|
||||
"%1 = OpExtInstImport \"GLSL.std.450\"\n"
|
||||
"OpMemoryModel Logical GLSL450\n"
|
||||
"OpEntryPoint Vertex %2 \"main\"\n"
|
||||
"OpSource ESSL 310\n"
|
||||
"OpName %2 \"main\"\n"
|
||||
"OpName %3 \"f(\"\n"
|
||||
"OpName %4 \"gv1\"\n"
|
||||
"OpName %5 \"gv2\"\n"
|
||||
"OpName %6 \"lv1\"\n"
|
||||
"OpName %7 \"lv2\"\n"
|
||||
"OpName %8 \"lv1\"\n"
|
||||
"%9 = OpTypeVoid\n"
|
||||
"%10 = OpTypeFunction %9\n"
|
||||
"%11 = OpTypeFloat 32\n"
|
||||
"%12 = OpTypeFunction %11\n"
|
||||
"%13 = OpTypePointer Private %11\n"
|
||||
"%4 = OpVariable %13 Private\n"
|
||||
"%14 = OpConstant %11 10\n"
|
||||
"%5 = OpVariable %13 Private\n"
|
||||
"%15 = OpConstant %11 100\n"
|
||||
"%16 = OpTypePointer Function %11\n"
|
||||
"%2 = OpFunction %9 None %10\n"
|
||||
"%17 = OpLabel\n"
|
||||
"%8 = OpVariable %16 Function\n"
|
||||
"OpStore %4 %14\n"
|
||||
"OpStore %5 %15\n"
|
||||
"%18 = OpLoad %11 %4\n"
|
||||
"%19 = OpLoad %11 %5\n"
|
||||
"%20 = OpFSub %11 %18 %19\n"
|
||||
"OpStore %8 %20\n"
|
||||
"OpReturn\n"
|
||||
"OpFunctionEnd\n"
|
||||
"%3 = OpFunction %11 None %12\n"
|
||||
"%21 = OpLabel\n"
|
||||
"%6 = OpVariable %16 Function\n"
|
||||
"%7 = OpVariable %16 Function\n"
|
||||
"%22 = OpLoad %11 %4\n"
|
||||
"%23 = OpLoad %11 %5\n"
|
||||
"%24 = OpFAdd %11 %22 %23\n"
|
||||
"OpStore %6 %24\n"
|
||||
"%25 = OpLoad %11 %4\n"
|
||||
"%26 = OpLoad %11 %5\n"
|
||||
"%27 = OpFMul %11 %25 %26\n"
|
||||
"OpStore %7 %27\n"
|
||||
"%28 = OpLoad %11 %6\n"
|
||||
"%29 = OpLoad %11 %7\n"
|
||||
"%30 = OpFDiv %11 %28 %29\n"
|
||||
"OpReturnValue %30\n"
|
||||
"OpFunctionEnd\n";
|
||||
|
||||
std::unique_ptr<ir::Module> module = BuildModule(Assemble(text));
|
||||
std::vector<uint32_t> binary;
|
||||
module->ToBinary(&binary, /* skip_nop = */ false);
|
||||
|
||||
EXPECT_EQ(text, Disassemble(binary));
|
||||
}
|
||||
|
||||
} // anonymous namespace
|
Loading…
Reference in New Issue
Block a user