Coverage Report

Created: 2024-09-11 07:09

/src/spirv-tools/source/libspirv.cpp
Line
Count
Source (jump to first uncovered line)
1
// Copyright (c) 2016 Google Inc.
2
//
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
6
//
7
//     http://www.apache.org/licenses/LICENSE-2.0
8
//
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.
14
15
#include "spirv-tools/libspirv.hpp"
16
17
#include <cassert>
18
#include <iostream>
19
#include <string>
20
#include <utility>
21
#include <vector>
22
23
#include "source/table.h"
24
25
namespace spvtools {
26
27
0
Context::Context(spv_target_env env) : context_(spvContextCreate(env)) {}
28
29
0
Context::Context(Context&& other) : context_(other.context_) {
30
0
  other.context_ = nullptr;
31
0
}
32
33
0
Context& Context::operator=(Context&& other) {
34
0
  spvContextDestroy(context_);
35
0
  context_ = other.context_;
36
0
  other.context_ = nullptr;
37
38
0
  return *this;
39
0
}
40
41
0
Context::~Context() { spvContextDestroy(context_); }
42
43
0
void Context::SetMessageConsumer(MessageConsumer consumer) {
44
0
  SetContextMessageConsumer(context_, std::move(consumer));
45
0
}
46
47
0
spv_context& Context::CContext() { return context_; }
48
49
0
const spv_context& Context::CContext() const { return context_; }
50
51
// Structs for holding the data members for SpvTools.
52
struct SpirvTools::Impl {
53
31.3k
  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
56
    // does nothing.
57
31.3k
  }
58
31.3k
  ~Impl() { spvContextDestroy(context); }
59
60
  spv_context context;  // C interface context object.
61
};
62
63
31.3k
SpirvTools::SpirvTools(spv_target_env env) : impl_(new Impl(env)) {
64
31.3k
  assert(env != SPV_ENV_WEBGPU_0);
65
31.3k
}
66
67
31.3k
SpirvTools::~SpirvTools() {}
68
69
31.3k
void SpirvTools::SetMessageConsumer(MessageConsumer consumer) {
70
31.3k
  SetContextMessageConsumer(impl_->context, std::move(consumer));
71
31.3k
}
72
73
bool SpirvTools::Assemble(const std::string& text,
74
                          std::vector<uint32_t>* binary,
75
0
                          uint32_t options) const {
76
0
  return Assemble(text.data(), text.size(), binary, options);
77
0
}
78
79
bool SpirvTools::Assemble(const char* text, const size_t text_size,
80
                          std::vector<uint32_t>* binary,
81
0
                          uint32_t options) const {
82
0
  spv_binary spvbinary = nullptr;
83
0
  spv_result_t status = spvTextToBinaryWithOptions(
84
0
      impl_->context, text, text_size, options, &spvbinary, nullptr);
85
0
  if (status == SPV_SUCCESS) {
86
0
    binary->assign(spvbinary->code, spvbinary->code + spvbinary->wordCount);
87
0
  }
88
0
  spvBinaryDestroy(spvbinary);
89
0
  return status == SPV_SUCCESS;
90
0
}
91
92
bool SpirvTools::Disassemble(const std::vector<uint32_t>& binary,
93
0
                             std::string* text, uint32_t options) const {
94
0
  return Disassemble(binary.data(), binary.size(), text, options);
95
0
}
96
97
bool SpirvTools::Disassemble(const uint32_t* binary, const size_t binary_size,
98
0
                             std::string* text, uint32_t options) const {
99
0
  spv_text spvtext = nullptr;
100
0
  spv_result_t status = spvBinaryToText(impl_->context, binary, binary_size,
101
0
                                        options, &spvtext, nullptr);
102
0
  if (status == SPV_SUCCESS &&
103
0
      (options & SPV_BINARY_TO_TEXT_OPTION_PRINT) == 0) {
104
0
    assert(spvtext);
105
0
    text->assign(spvtext->str, spvtext->str + spvtext->length);
106
0
  }
107
0
  spvTextDestroy(spvtext);
108
0
  return status == SPV_SUCCESS;
109
0
}
110
111
struct CxxParserContext {
112
  const HeaderParser& header_parser;
113
  const InstructionParser& instruction_parser;
114
};
115
116
bool SpirvTools::Parse(const std::vector<uint32_t>& binary,
117
                       const HeaderParser& header_parser,
118
                       const InstructionParser& instruction_parser,
119
0
                       spv_diagnostic* diagnostic) {
120
0
  CxxParserContext parser_context = {header_parser, instruction_parser};
121
122
0
  spv_parsed_header_fn_t header_fn_wrapper =
123
0
      [](void* user_data, spv_endianness_t endianness, uint32_t magic,
124
0
         uint32_t version, uint32_t generator, uint32_t id_bound,
125
0
         uint32_t reserved) {
126
0
        CxxParserContext* ctx = reinterpret_cast<CxxParserContext*>(user_data);
127
0
        spv_parsed_header_t header = {magic, version, generator, id_bound,
128
0
                                      reserved};
129
130
0
        return ctx->header_parser(endianness, header);
131
0
      };
132
133
0
  spv_parsed_instruction_fn_t instruction_fn_wrapper =
134
0
      [](void* user_data, const spv_parsed_instruction_t* instruction) {
135
0
        CxxParserContext* ctx = reinterpret_cast<CxxParserContext*>(user_data);
136
0
        return ctx->instruction_parser(*instruction);
137
0
      };
138
139
0
  spv_result_t status = spvBinaryParse(
140
0
      impl_->context, &parser_context, binary.data(), binary.size(),
141
0
      header_fn_wrapper, instruction_fn_wrapper, diagnostic);
142
0
  return status == SPV_SUCCESS;
143
0
}
144
145
10.2k
bool SpirvTools::Validate(const std::vector<uint32_t>& binary) const {
146
10.2k
  return Validate(binary.data(), binary.size());
147
10.2k
}
148
149
bool SpirvTools::Validate(const uint32_t* binary,
150
10.2k
                          const size_t binary_size) const {
151
10.2k
  return spvValidateBinary(impl_->context, binary, binary_size, nullptr) ==
152
10.2k
         SPV_SUCCESS;
153
10.2k
}
154
155
bool SpirvTools::Validate(const uint32_t* binary, const size_t binary_size,
156
21.1k
                          spv_validator_options options) const {
157
21.1k
  spv_const_binary_t the_binary{binary, binary_size};
158
21.1k
  spv_diagnostic diagnostic = nullptr;
159
21.1k
  bool valid = spvValidateWithOptions(impl_->context, options, &the_binary,
160
21.1k
                                      &diagnostic) == SPV_SUCCESS;
161
21.1k
  if (!valid && impl_->context->consumer) {
162
10.3k
    impl_->context->consumer.operator()(
163
10.3k
        SPV_MSG_ERROR, nullptr, diagnostic->position, diagnostic->error);
164
10.3k
  }
165
21.1k
  spvDiagnosticDestroy(diagnostic);
166
21.1k
  return valid;
167
21.1k
}
168
169
0
bool SpirvTools::IsValid() const { return impl_->context != nullptr; }
170
171
}  // namespace spvtools