1 // Copyright (c) 2015-2016 The Khronos Group 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 #ifndef SOURCE_TEXT_HANDLER_H_
16 #define SOURCE_TEXT_HANDLER_H_
22 #include <type_traits>
23 #include <unordered_map>
26 #include "source/diagnostic.h"
27 #include "source/instruction.h"
28 #include "source/text.h"
29 #include "spirv-tools/libspirv.h"
35 // This is a lattice for tracking types.
36 enum class IdTypeClass
{
37 kBottom
= 0, // We have no information yet.
43 // Contains ID type information that needs to be tracked across all Ids.
44 // Bitwidth is only valid when type_class is kScalarIntegerType or
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
;
52 // Default equality operator for IdType. Tests if all members are the same.
53 inline bool operator==(const IdType
& first
, const IdType
& second
) {
54 return (first
.bitwidth
== second
.bitwidth
) &&
55 (first
.isSigned
== second
.isSigned
) &&
56 (first
.type_class
== second
.type_class
);
59 // Tests whether any member of the IdTypes do not match.
60 inline bool operator!=(const IdType
& first
, const IdType
& second
) {
61 return !(first
== second
);
64 // A value representing an unknown type.
65 extern const IdType kUnknownType
;
67 // Returns true if the type is a scalar integer type.
68 inline bool isScalarIntegral(const IdType
& type
) {
69 return type
.type_class
== IdTypeClass::kScalarIntegerType
;
72 // Returns true if the type is a scalar floating point type.
73 inline bool isScalarFloating(const IdType
& type
) {
74 return type
.type_class
== IdTypeClass::kScalarFloatType
;
77 // Returns the number of bits in the type.
78 // This is only valid for bottom, scalar integer, and scalar floating
79 // classes. For bottom, assume 32 bits.
80 inline int assumedBitWidth(const IdType
& type
) {
81 switch (type
.type_class
) {
82 case IdTypeClass::kBottom
:
84 case IdTypeClass::kScalarIntegerType
:
85 case IdTypeClass::kScalarFloatType
:
90 // We don't care about this case.
94 // A templated class with a static member function Clamp, where Clamp
95 // sets a referenced value of type T to 0 if T is an unsigned
96 // integer type, and returns true if it modified the referenced
98 template <typename T
, typename
= void>
99 class ClampToZeroIfUnsignedType
{
101 // The default specialization does not clamp the value.
102 static bool Clamp(T
*) { return false; }
105 // The specialization of ClampToZeroIfUnsignedType for unsigned integer
107 template <typename T
>
108 class ClampToZeroIfUnsignedType
<
109 T
, typename
std::enable_if
<std::is_unsigned
<T
>::value
>::type
> {
111 static bool Clamp(T
* value_pointer
) {
112 if (*value_pointer
) {
120 // Encapsulates the data used during the assembly of a SPIR-V module.
121 class AssemblyContext
{
123 AssemblyContext(spv_text text
, const MessageConsumer
& consumer
,
124 std::set
<uint32_t>&& ids_to_preserve
= std::set
<uint32_t>())
125 : current_position_({}),
130 ids_to_preserve_(std::move(ids_to_preserve
)) {}
132 // Assigns a new integer value to the given text ID, or returns the previously
133 // assigned integer value if the ID has been seen before.
134 uint32_t spvNamedIdAssignOrGet(const char* textValue
);
136 // Returns the largest largest numeric ID that has been assigned.
137 uint32_t getBound() const;
139 // Advances position to point to the next word in the input stream.
140 // Returns SPV_SUCCESS on success.
141 spv_result_t
advance();
143 // Sets word to the next word in the input text. Fills next_position with
144 // the next location past the end of the word.
145 spv_result_t
getWord(std::string
* word
, spv_position next_position
);
147 // Returns true if the next word in the input is the start of a new Opcode.
150 // Returns true if the next word in the input is the start of a new
152 bool isStartOfNewInst();
154 // Returns a diagnostic object initialized with current position in the input
155 // stream, and for the given error code. Any data written to this object will
156 // show up in pDiagnsotic on destruction.
157 DiagnosticStream
diagnostic(spv_result_t error
) {
158 return DiagnosticStream(current_position_
, consumer_
, "", error
);
161 // Returns a diagnostic object with the default assembly error code.
162 DiagnosticStream
diagnostic() {
163 // The default failure for assembly is invalid text.
164 return diagnostic(SPV_ERROR_INVALID_TEXT
);
167 // Returns then next character in the input stream.
170 // Returns true if there is more text in the input stream.
171 bool hasText() const;
173 // Seeks the input stream forward by 'size' characters.
174 void seekForward(uint32_t size
);
176 // Sets the current position in the input stream to the given position.
177 void setPosition(const spv_position_t
& newPosition
) {
178 current_position_
= newPosition
;
181 // Returns the current position in the input stream.
182 const spv_position_t
& position() const { return current_position_
; }
184 // Appends the given 32-bit value to the given instruction.
185 // Returns SPV_SUCCESS if the value could be correctly inserted in the
187 spv_result_t
binaryEncodeU32(const uint32_t value
, spv_instruction_t
* pInst
);
189 // Appends the given string to the given instruction.
190 // Returns SPV_SUCCESS if the value could be correctly inserted in the
192 spv_result_t
binaryEncodeString(const char* value
, spv_instruction_t
* pInst
);
194 // Appends the given numeric literal to the given instruction.
195 // Validates and respects the bitwidth supplied in the IdType argument.
196 // If the type is of class kBottom the value will be encoded as a
198 // Returns SPV_SUCCESS if the value could be correctly added to the
199 // instruction. Returns the given error code on failure, and emits
200 // a diagnostic if that error code is not SPV_FAILED_MATCH.
201 spv_result_t
binaryEncodeNumericLiteral(const char* numeric_literal
,
202 spv_result_t error_code
,
204 spv_instruction_t
* pInst
);
206 // Returns the IdType associated with this type-generating value.
207 // If the type has not been previously recorded with recordTypeDefinition,
208 // kUnknownType will be returned.
209 IdType
getTypeOfTypeGeneratingValue(uint32_t value
) const;
211 // Returns the IdType that represents the return value of this Value
212 // generating instruction.
213 // If the value has not been recorded with recordTypeIdForValue, or the type
214 // could not be determined kUnknownType will be returned.
215 IdType
getTypeOfValueInstruction(uint32_t value
) const;
217 // Tracks the type-defining instruction. The result of the tracking can
218 // later be queried using getValueType.
219 // pInst is expected to be completely filled in by the time this instruction
221 // Returns SPV_SUCCESS on success, or SPV_ERROR_INVALID_VALUE on error.
222 spv_result_t
recordTypeDefinition(const spv_instruction_t
* pInst
);
224 // Tracks the relationship between the value and its type.
225 spv_result_t
recordTypeIdForValue(uint32_t value
, uint32_t type
);
227 // Records the given Id as being the import of the given extended instruction
229 spv_result_t
recordIdAsExtInstImport(uint32_t id
, spv_ext_inst_type_t type
);
231 // Returns the extended instruction type corresponding to the import with
232 // the given Id, if it exists. Returns SPV_EXT_INST_TYPE_NONE if the
233 // id is not the id for an extended instruction type.
234 spv_ext_inst_type_t
getExtInstTypeForId(uint32_t id
) const;
236 // Returns a set consisting of each ID generated by spvNamedIdAssignOrGet from
237 // a numeric ID text representation. For example, generated from "%12" but not
239 std::set
<uint32_t> GetNumericIds() const;
242 // Maps ID names to their corresponding numerical ids.
243 using spv_named_id_table
= std::unordered_map
<std::string
, uint32_t>;
244 // Maps type-defining IDs to their IdType.
245 using spv_id_to_type_map
= std::unordered_map
<uint32_t, IdType
>;
246 // Maps Ids to the id of their type.
247 using spv_id_to_type_id
= std::unordered_map
<uint32_t, uint32_t>;
249 spv_named_id_table named_ids_
;
250 spv_id_to_type_map types_
;
251 spv_id_to_type_id value_types_
;
252 // Maps an extended instruction import Id to the extended instruction type.
253 std::unordered_map
<uint32_t, spv_ext_inst_type_t
> import_id_to_ext_inst_type_
;
254 spv_position_t current_position_
;
255 MessageConsumer consumer_
;
259 std::set
<uint32_t> ids_to_preserve_
;
262 } // namespace spvtools
264 #endif // SOURCE_TEXT_HANDLER_H_