Coverage Report

Created: 2025-06-13 06:37

/src/spirv-tools/source/text_handler.h
Line
Count
Source (jump to first uncovered line)
1
// Copyright (c) 2015-2016 The Khronos Group 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
#ifndef SOURCE_TEXT_HANDLER_H_
16
#define SOURCE_TEXT_HANDLER_H_
17
18
#include <iomanip>
19
#include <set>
20
#include <sstream>
21
#include <string>
22
#include <type_traits>
23
#include <unordered_map>
24
#include <utility>
25
26
#include "source/diagnostic.h"
27
#include "source/instruction.h"
28
#include "source/text.h"
29
#include "spirv-tools/libspirv.h"
30
31
namespace spvtools {
32
33
// Structures
34
35
// This is a lattice for tracking types.
36
enum class IdTypeClass {
37
  kBottom = 0,  // We have no information yet.
38
  kScalarIntegerType,
39
  kScalarFloatType,
40
  kOtherType
41
};
42
43
// Contains ID type information that needs to be tracked across all Ids.
44
// Bitwidth is only valid when type_class is kScalarIntegerType or
45
// kScalarFloatType.
46
struct IdType {
47
  uint32_t bitwidth;  // Safe to assume that we will not have > 2^32 bits.
48
  bool isSigned;      // This is only significant if type_class is integral.
49
  IdTypeClass type_class;
50
  spv_fp_encoding_t encoding;
51
};
52
53
// Default equality operator for IdType. Tests if all members are the same.
54
0
inline bool operator==(const IdType& first, const IdType& second) {
55
0
  return (first.bitwidth == second.bitwidth) &&
56
0
         (first.isSigned == second.isSigned) &&
57
0
         (first.type_class == second.type_class);
58
0
}
59
60
// Tests whether any member of the IdTypes do not match.
61
0
inline bool operator!=(const IdType& first, const IdType& second) {
62
0
  return !(first == second);
63
0
}
64
65
// A value representing an unknown type.
66
extern const IdType kUnknownType;
67
68
// Returns true if the type is a scalar integer type.
69
7.27k
inline bool isScalarIntegral(const IdType& type) {
70
7.27k
  return type.type_class == IdTypeClass::kScalarIntegerType;
71
7.27k
}
72
73
// Returns true if the type is a scalar floating point type.
74
124k
inline bool isScalarFloating(const IdType& type) {
75
124k
  return type.type_class == IdTypeClass::kScalarFloatType;
76
124k
}
77
78
// Returns the number of bits in the type.
79
// This is only valid for bottom, scalar integer, and scalar floating
80
// classes.  For bottom, assume 32 bits.
81
10.5M
inline int assumedBitWidth(const IdType& type) {
82
10.5M
  switch (type.type_class) {
83
10.5M
    case IdTypeClass::kBottom:
84
10.5M
      return 32;
85
0
    case IdTypeClass::kScalarIntegerType:
86
0
    case IdTypeClass::kScalarFloatType:
87
0
      return type.bitwidth;
88
0
    default:
89
0
      break;
90
10.5M
  }
91
  // We don't care about this case.
92
0
  return 0;
93
10.5M
}
94
95
// A templated class with a static member function Clamp, where Clamp
96
// sets a referenced value of type T to 0 if T is an unsigned
97
// integer type, and returns true if it modified the referenced
98
// value.
99
template <typename T, typename = void>
100
class ClampToZeroIfUnsignedType {
101
 public:
102
  // The default specialization does not clamp the value.
103
  static bool Clamp(T*) { return false; }
104
};
105
106
// The specialization of ClampToZeroIfUnsignedType for unsigned integer
107
// types.
108
template <typename T>
109
class ClampToZeroIfUnsignedType<
110
    T, typename std::enable_if<std::is_unsigned<T>::value>::type> {
111
 public:
112
  static bool Clamp(T* value_pointer) {
113
    if (*value_pointer) {
114
      *value_pointer = 0;
115
      return true;
116
    }
117
    return false;
118
  }
119
};
120
121
// Encapsulates the data used during the assembly of a SPIR-V module.
122
class AssemblyContext {
123
 public:
124
  AssemblyContext(spv_text text, const MessageConsumer& consumer,
125
                  std::set<uint32_t>&& ids_to_preserve = std::set<uint32_t>())
126
29.8k
      : current_position_({}),
127
29.8k
        consumer_(consumer),
128
29.8k
        text_(text),
129
29.8k
        bound_(1),
130
29.8k
        next_id_(1),
131
29.8k
        ids_to_preserve_(std::move(ids_to_preserve)) {}
132
133
  // Assigns a new integer value to the given text ID, or returns the previously
134
  // assigned integer value if the ID has been seen before.
135
  uint32_t spvNamedIdAssignOrGet(const char* textValue);
136
137
  // Returns the largest largest numeric ID that has been assigned.
138
  uint32_t getBound() const;
139
140
  // Advances position to point to the next word in the input stream.
141
  // Returns SPV_SUCCESS on success.
142
  spv_result_t advance();
143
144
  // Sets word to the next word in the input text. Fills next_position with
145
  // the next location past the end of the word.  Returns an error if the
146
  // context is invalid or has no more text. Otherwise returns SPV_SUCCESS.
147
  // Assumes the next part of the input is not whitespace.
148
  //
149
  // A word ends at the next comment or whitespace.  However, double-quoted
150
  // strings remain intact, and a backslash always escapes the next character.
151
  // The input stream may end before a matching double-quote, or immediately
152
  // after a backslash. Both such cases still count as success.
153
  spv_result_t getWord(std::string* word, spv_position next_position);
154
155
  // Returns true if the next word in the input is the start of a new Opcode.
156
  bool startsWithOp();
157
158
  // Returns true if the next word in the input is the start of a new
159
  // instruction.
160
  bool isStartOfNewInst();
161
162
  // Returns a diagnostic object initialized with current position in the input
163
  // stream, and for the given error code. Any data written to this object will
164
  // show up in pDiagnsotic on destruction.
165
628k
  DiagnosticStream diagnostic(spv_result_t error) {
166
628k
    return DiagnosticStream(current_position_, consumer_, "", error);
167
628k
  }
168
169
  // Returns a diagnostic object with the default assembly error code.
170
184k
  DiagnosticStream diagnostic() {
171
    // The default failure for assembly is invalid text.
172
184k
    return diagnostic(SPV_ERROR_INVALID_TEXT);
173
184k
  }
174
175
  // Returns then next character in the input stream.
176
  char peek() const;
177
178
  // Returns true if there is more text in the input stream.
179
  bool hasText() const;
180
181
  // Seeks the input stream forward by 'size' characters.
182
  void seekForward(uint32_t size);
183
184
  // Sets the current position in the input stream to the given position.
185
13.7M
  void setPosition(const spv_position_t& newPosition) {
186
13.7M
    current_position_ = newPosition;
187
13.7M
  }
188
189
  // Returns the current position in the input stream.
190
1.22M
  const spv_position_t& position() const { return current_position_; }
191
192
  // Appends the given 32-bit value to the given instruction.
193
  // Returns SPV_SUCCESS if the value could be correctly inserted in the
194
  // instruction.
195
  spv_result_t binaryEncodeU32(const uint32_t value, spv_instruction_t* pInst);
196
197
  // Appends the given string to the given instruction.
198
  // Returns SPV_SUCCESS if the value could be correctly inserted in the
199
  // instruction.
200
  spv_result_t binaryEncodeString(const char* value, spv_instruction_t* pInst);
201
202
  // Appends the given numeric literal to the given instruction.
203
  // Validates and respects the bitwidth supplied in the IdType argument.
204
  // If the type is of class kBottom the value will be encoded as a
205
  // 32-bit integer.
206
  // Returns SPV_SUCCESS if the value could be correctly added to the
207
  // instruction.  Returns the given error code on failure, and emits
208
  // a diagnostic if that error code is not SPV_FAILED_MATCH.
209
  spv_result_t binaryEncodeNumericLiteral(const char* numeric_literal,
210
                                          spv_result_t error_code,
211
                                          const IdType& type,
212
                                          spv_instruction_t* pInst);
213
214
  // Returns the IdType associated with this type-generating value.
215
  // If the type has not been previously recorded with recordTypeDefinition,
216
  // kUnknownType  will be returned.
217
  IdType getTypeOfTypeGeneratingValue(uint32_t value) const;
218
219
  // Returns the IdType that represents the return value of this Value
220
  // generating instruction.
221
  // If the value has not been recorded with recordTypeIdForValue, or the type
222
  // could not be determined kUnknownType will be returned.
223
  IdType getTypeOfValueInstruction(uint32_t value) const;
224
225
  // Tracks the type-defining instruction. The result of the tracking can
226
  // later be queried using getValueType.
227
  // pInst is expected to be completely filled in by the time this instruction
228
  // is called.
229
  // Returns SPV_SUCCESS on success, or SPV_ERROR_INVALID_VALUE on error.
230
  spv_result_t recordTypeDefinition(const spv_instruction_t* pInst);
231
232
  // Tracks the relationship between the value and its type.
233
  spv_result_t recordTypeIdForValue(uint32_t value, uint32_t type);
234
235
  // Records the given Id as being the import of the given extended instruction
236
  // type.
237
  spv_result_t recordIdAsExtInstImport(uint32_t id, spv_ext_inst_type_t type);
238
239
  // Returns the extended instruction type corresponding to the import with
240
  // the given Id, if it exists.  Returns SPV_EXT_INST_TYPE_NONE if the
241
  // id is not the id for an extended instruction type.
242
  spv_ext_inst_type_t getExtInstTypeForId(uint32_t id) const;
243
244
  // Returns a set consisting of each ID generated by spvNamedIdAssignOrGet from
245
  // a numeric ID text representation. For example, generated from "%12" but not
246
  // from "%foo".
247
  std::set<uint32_t> GetNumericIds() const;
248
249
 private:
250
  // Maps ID names to their corresponding numerical ids.
251
  using spv_named_id_table = std::unordered_map<std::string, uint32_t>;
252
  // Maps type-defining IDs to their IdType.
253
  using spv_id_to_type_map = std::unordered_map<uint32_t, IdType>;
254
  // Maps Ids to the id of their type.
255
  using spv_id_to_type_id = std::unordered_map<uint32_t, uint32_t>;
256
257
  spv_named_id_table named_ids_;
258
  spv_id_to_type_map types_;
259
  spv_id_to_type_id value_types_;
260
  // Maps an extended instruction import Id to the extended instruction type.
261
  std::unordered_map<uint32_t, spv_ext_inst_type_t> import_id_to_ext_inst_type_;
262
  spv_position_t current_position_;
263
  MessageConsumer consumer_;
264
  spv_text text_;
265
  uint32_t bound_;
266
  uint32_t next_id_;
267
  std::set<uint32_t> ids_to_preserve_;
268
};
269
270
}  // namespace spvtools
271
272
#endif  // SOURCE_TEXT_HANDLER_H_