1 // Copyright (c) 2016 Google Inc.
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
7 // http://www.apache.org/licenses/LICENSE-2.0
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
15 #include "spirv-tools/libspirv.hpp"
23 #include "source/table.h"
27 Context::Context(spv_target_env env
) : context_(spvContextCreate(env
)) {}
29 Context::Context(Context
&& other
) : context_(other
.context_
) {
30 other
.context_
= nullptr;
33 Context
& Context::operator=(Context
&& other
) {
34 spvContextDestroy(context_
);
35 context_
= other
.context_
;
36 other
.context_
= nullptr;
41 Context::~Context() { spvContextDestroy(context_
); }
43 void Context::SetMessageConsumer(MessageConsumer consumer
) {
44 SetContextMessageConsumer(context_
, std::move(consumer
));
47 spv_context
& Context::CContext() { return context_
; }
49 const spv_context
& Context::CContext() const { return context_
; }
51 // Structs for holding the data members for SpvTools.
52 struct SpirvTools::Impl
{
53 explicit Impl(spv_target_env env
) : context(spvContextCreate(env
)) {
54 // The default consumer in spv_context_t is a null consumer, which provides
55 // equivalent functionality (from the user's perspective) as a real consumer
58 ~Impl() { spvContextDestroy(context
); }
60 spv_context context
; // C interface context object.
63 SpirvTools::SpirvTools(spv_target_env env
) : impl_(new Impl(env
)) {
64 assert(env
!= SPV_ENV_WEBGPU_0
);
67 SpirvTools::~SpirvTools() {}
69 void SpirvTools::SetMessageConsumer(MessageConsumer consumer
) {
70 SetContextMessageConsumer(impl_
->context
, std::move(consumer
));
73 bool SpirvTools::Assemble(const std::string
& text
,
74 std::vector
<uint32_t>* binary
,
75 uint32_t options
) const {
76 return Assemble(text
.data(), text
.size(), binary
, options
);
79 bool SpirvTools::Assemble(const char* text
, const size_t text_size
,
80 std::vector
<uint32_t>* binary
,
81 uint32_t options
) const {
82 spv_binary spvbinary
= nullptr;
83 spv_result_t status
= spvTextToBinaryWithOptions(
84 impl_
->context
, text
, text_size
, options
, &spvbinary
, nullptr);
85 if (status
== SPV_SUCCESS
) {
86 binary
->assign(spvbinary
->code
, spvbinary
->code
+ spvbinary
->wordCount
);
88 spvBinaryDestroy(spvbinary
);
89 return status
== SPV_SUCCESS
;
92 bool SpirvTools::Disassemble(const std::vector
<uint32_t>& binary
,
93 std::string
* text
, uint32_t options
) const {
94 return Disassemble(binary
.data(), binary
.size(), text
, options
);
97 bool SpirvTools::Disassemble(const uint32_t* binary
, const size_t binary_size
,
98 std::string
* text
, uint32_t options
) const {
99 spv_text spvtext
= nullptr;
100 spv_result_t status
= spvBinaryToText(impl_
->context
, binary
, binary_size
,
101 options
, &spvtext
, nullptr);
102 if (status
== SPV_SUCCESS
&&
103 (options
& SPV_BINARY_TO_TEXT_OPTION_PRINT
) == 0) {
105 text
->assign(spvtext
->str
, spvtext
->str
+ spvtext
->length
);
107 spvTextDestroy(spvtext
);
108 return status
== SPV_SUCCESS
;
111 struct CxxParserContext
{
112 const HeaderParser
& header_parser
;
113 const InstructionParser
& instruction_parser
;
116 bool SpirvTools::Parse(const std::vector
<uint32_t>& binary
,
117 const HeaderParser
& header_parser
,
118 const InstructionParser
& instruction_parser
,
119 spv_diagnostic
* diagnostic
) {
120 CxxParserContext parser_context
= {header_parser
, instruction_parser
};
122 spv_parsed_header_fn_t header_fn_wrapper
=
123 [](void* user_data
, spv_endianness_t endianness
, uint32_t magic
,
124 uint32_t version
, uint32_t generator
, uint32_t id_bound
,
126 CxxParserContext
* ctx
= reinterpret_cast<CxxParserContext
*>(user_data
);
127 spv_parsed_header_t header
= {magic
, version
, generator
, id_bound
,
130 return ctx
->header_parser(endianness
, header
);
133 spv_parsed_instruction_fn_t instruction_fn_wrapper
=
134 [](void* user_data
, const spv_parsed_instruction_t
* instruction
) {
135 CxxParserContext
* ctx
= reinterpret_cast<CxxParserContext
*>(user_data
);
136 return ctx
->instruction_parser(*instruction
);
139 spv_result_t status
= spvBinaryParse(
140 impl_
->context
, &parser_context
, binary
.data(), binary
.size(),
141 header_fn_wrapper
, instruction_fn_wrapper
, diagnostic
);
142 return status
== SPV_SUCCESS
;
145 bool SpirvTools::Validate(const std::vector
<uint32_t>& binary
) const {
146 return Validate(binary
.data(), binary
.size());
149 bool SpirvTools::Validate(const uint32_t* binary
,
150 const size_t binary_size
) const {
151 return spvValidateBinary(impl_
->context
, binary
, binary_size
, nullptr) ==
155 bool SpirvTools::Validate(const uint32_t* binary
, const size_t binary_size
,
156 spv_validator_options options
) const {
157 spv_const_binary_t the_binary
{binary
, binary_size
};
158 spv_diagnostic diagnostic
= nullptr;
159 bool valid
= spvValidateWithOptions(impl_
->context
, options
, &the_binary
,
160 &diagnostic
) == SPV_SUCCESS
;
161 if (!valid
&& impl_
->context
->consumer
) {
162 impl_
->context
->consumer
.operator()(
163 SPV_MSG_ERROR
, nullptr, diagnostic
->position
, diagnostic
->error
);
165 spvDiagnosticDestroy(diagnostic
);
169 bool SpirvTools::IsValid() const { return impl_
->context
!= nullptr; }
171 } // namespace spvtools