blob: 1573306971b5c4cc34ffa36403ae5c271a2d6fb8 [file] [log] [blame]
Dejan Mircevskib6fe02f2016-01-07 13:44:22 -05001// Copyright (c) 2015-2016 The Khronos Group Inc.
Andrew Woloszyn71fc0552015-09-24 10:26:51 -04002//
David Neto9fc86582016-09-01 15:33:59 -04003// 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
Andrew Woloszyn71fc0552015-09-24 10:26:51 -04006//
David Neto9fc86582016-09-01 15:33:59 -04007// http://www.apache.org/licenses/LICENSE-2.0
Andrew Woloszyn71fc0552015-09-24 10:26:51 -04008//
David Neto9fc86582016-09-01 15:33:59 -04009// 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.
Andrew Woloszyn71fc0552015-09-24 10:26:51 -040014
David Neto9f79d782015-10-27 16:27:05 -040015#ifndef LIBSPIRV_TEXT_HANDLER_H_
16#define LIBSPIRV_TEXT_HANDLER_H_
Andrew Woloszyn71fc0552015-09-24 10:26:51 -040017
David Neto62741202015-10-13 15:51:12 -040018#include <iomanip>
David Neto62741202015-10-13 15:51:12 -040019#include <sstream>
20#include <type_traits>
Andrew Woloszyn71fc0552015-09-24 10:26:51 -040021#include <unordered_map>
22
23#include "diagnostic.h"
David Netob5dc8fc2015-10-06 16:22:00 -040024#include "instruction.h"
Lei Zhang755f97f2016-09-02 18:06:18 -040025#include "message.h"
David Neto5a703352016-02-17 14:44:00 -050026#include "spirv-tools/libspirv.h"
David Neto78e677b2015-10-05 13:28:46 -040027#include "text.h"
Andrew Woloszyn71fc0552015-09-24 10:26:51 -040028
dan sinclair3dad1cd2018-07-07 09:38:00 -040029namespace spvtools {
30
Andrew Woloszyn71fc0552015-09-24 10:26:51 -040031// Structures
32
Andrew Woloszyn71fc0552015-09-24 10:26:51 -040033// This is a lattice for tracking types.
34enum class IdTypeClass {
Lei Zhang1a0334e2015-11-02 09:41:20 -050035 kBottom = 0, // We have no information yet.
Andrew Woloszyn71fc0552015-09-24 10:26:51 -040036 kScalarIntegerType,
37 kScalarFloatType,
38 kOtherType
39};
40
Andrew Woloszyn71fc0552015-09-24 10:26:51 -040041// Contains ID type information that needs to be tracked across all Ids.
42// Bitwidth is only valid when type_class is kScalarIntegerType or
43// kScalarFloatType.
44struct IdType {
45 uint32_t bitwidth; // Safe to assume that we will not have > 2^32 bits.
Lei Zhang1a0334e2015-11-02 09:41:20 -050046 bool isSigned; // This is only significant if type_class is integral.
Andrew Woloszyn71fc0552015-09-24 10:26:51 -040047 IdTypeClass type_class;
48};
49
Andrew Woloszyn157e41b2015-10-16 15:11:00 -040050// Default equality operator for IdType. Tests if all members are the same.
Lei Zhang1a0334e2015-11-02 09:41:20 -050051inline bool operator==(const IdType& first, const IdType& second) {
Andrew Woloszyn157e41b2015-10-16 15:11:00 -040052 return (first.bitwidth == second.bitwidth) &&
53 (first.isSigned == second.isSigned) &&
54 (first.type_class == second.type_class);
55}
56
57// Tests whether any member of the IdTypes do not match.
Lei Zhang1a0334e2015-11-02 09:41:20 -050058inline bool operator!=(const IdType& first, const IdType& second) {
Andrew Woloszyn157e41b2015-10-16 15:11:00 -040059 return !(first == second);
60}
61
David Neto78e677b2015-10-05 13:28:46 -040062// A value representing an unknown type.
63extern const IdType kUnknownType;
64
Andrew Woloszyn537e7762015-09-29 11:28:34 -040065// Returns true if the type is a scalar integer type.
66inline bool isScalarIntegral(const IdType& type) {
67 return type.type_class == IdTypeClass::kScalarIntegerType;
68}
69
70// Returns true if the type is a scalar floating point type.
71inline bool isScalarFloating(const IdType& type) {
72 return type.type_class == IdTypeClass::kScalarFloatType;
73}
74
David Neto78e677b2015-10-05 13:28:46 -040075// Returns the number of bits in the type.
76// This is only valid for bottom, scalar integer, and scalar floating
77// classes. For bottom, assume 32 bits.
78inline int assumedBitWidth(const IdType& type) {
Lei Zhang1a0334e2015-11-02 09:41:20 -050079 switch (type.type_class) {
David Neto78e677b2015-10-05 13:28:46 -040080 case IdTypeClass::kBottom:
81 return 32;
82 case IdTypeClass::kScalarIntegerType:
83 case IdTypeClass::kScalarFloatType:
84 return type.bitwidth;
85 default:
86 break;
87 }
88 // We don't care about this case.
89 return 0;
90}
91
David Neto9e545d72015-11-06 18:08:49 -050092// A templated class with a static member function Clamp, where Clamp
93// sets a referenced value of type T to 0 if T is an unsigned
94// integer type, and returns true if it modified the referenced
95// value.
96template <typename T, typename = void>
97class ClampToZeroIfUnsignedType {
98 public:
99 // The default specialization does not clamp the value.
100 static bool Clamp(T*) { return false; }
101};
102
103// The specialization of ClampToZeroIfUnsignedType for unsigned integer
104// types.
105template <typename T>
106class ClampToZeroIfUnsignedType<
107 T, typename std::enable_if<std::is_unsigned<T>::value>::type> {
108 public:
109 static bool Clamp(T* value_pointer) {
110 if (*value_pointer) {
111 *value_pointer = 0;
112 return true;
113 }
114 return false;
115 }
116};
117
Andrew Woloszyn71fc0552015-09-24 10:26:51 -0400118// Encapsulates the data used during the assembly of a SPIR-V module.
119class AssemblyContext {
120 public:
dan sinclair3dad1cd2018-07-07 09:38:00 -0400121 AssemblyContext(spv_text text, const MessageConsumer& consumer,
Andrey Tuganovb173d1c2017-04-11 19:46:15 -0400122 std::set<uint32_t>&& ids_to_preserve = std::set<uint32_t>())
Diego Novillod2938e42017-11-08 12:40:02 -0500123 : current_position_({}),
124 consumer_(consumer),
125 text_(text),
126 bound_(1),
127 next_id_(1),
128 ids_to_preserve_(std::move(ids_to_preserve)) {}
Andrew Woloszyn71fc0552015-09-24 10:26:51 -0400129
130 // Assigns a new integer value to the given text ID, or returns the previously
131 // assigned integer value if the ID has been seen before.
Lei Zhang1a0334e2015-11-02 09:41:20 -0500132 uint32_t spvNamedIdAssignOrGet(const char* textValue);
Andrew Woloszyn71fc0552015-09-24 10:26:51 -0400133
134 // Returns the largest largest numeric ID that has been assigned.
135 uint32_t getBound() const;
136
137 // Advances position to point to the next word in the input stream.
138 // Returns SPV_SUCCESS on success.
139 spv_result_t advance();
140
Lei Zhang6032b982016-03-15 16:52:40 -0400141 // Sets word to the next word in the input text. Fills next_position with
Andrew Woloszyn71fc0552015-09-24 10:26:51 -0400142 // the next location past the end of the word.
Lei Zhang6032b982016-03-15 16:52:40 -0400143 spv_result_t getWord(std::string* word, spv_position next_position);
Andrew Woloszyn71fc0552015-09-24 10:26:51 -0400144
Andrew Woloszyn71fc0552015-09-24 10:26:51 -0400145 // Returns true if the next word in the input is the start of a new Opcode.
146 bool startsWithOp();
147
148 // Returns true if the next word in the input is the start of a new
149 // instruction.
150 bool isStartOfNewInst();
151
152 // Returns a diagnostic object initialized with current position in the input
David Netoac508b02015-10-09 15:48:09 -0400153 // stream, and for the given error code. Any data written to this object will
154 // show up in pDiagnsotic on destruction.
155 DiagnosticStream diagnostic(spv_result_t error) {
dan sinclairf80696e2018-06-19 16:02:44 -0400156 return DiagnosticStream(current_position_, consumer_, "", error);
David Netoac508b02015-10-09 15:48:09 -0400157 }
158
159 // Returns a diagnostic object with the default assembly error code.
Andrew Woloszyn71fc0552015-09-24 10:26:51 -0400160 DiagnosticStream diagnostic() {
David Netoac508b02015-10-09 15:48:09 -0400161 // The default failure for assembly is invalid text.
162 return diagnostic(SPV_ERROR_INVALID_TEXT);
Andrew Woloszyn71fc0552015-09-24 10:26:51 -0400163 }
164
Lei Zhangacf72872015-11-13 11:00:10 -0500165 // Returns then next character in the input stream.
Andrew Woloszyn71fc0552015-09-24 10:26:51 -0400166 char peek() const;
167
168 // Returns true if there is more text in the input stream.
169 bool hasText() const;
170
171 // Seeks the input stream forward by 'size' characters.
172 void seekForward(uint32_t size);
173
174 // Sets the current position in the input stream to the given position.
Lei Zhang1a0334e2015-11-02 09:41:20 -0500175 void setPosition(const spv_position_t& newPosition) {
Andrew Woloszyn71fc0552015-09-24 10:26:51 -0400176 current_position_ = newPosition;
177 }
178
179 // Returns the current position in the input stream.
Lei Zhang1a0334e2015-11-02 09:41:20 -0500180 const spv_position_t& position() const { return current_position_; }
Andrew Woloszyn71fc0552015-09-24 10:26:51 -0400181
182 // Appends the given 32-bit value to the given instruction.
David Neto78e677b2015-10-05 13:28:46 -0400183 // Returns SPV_SUCCESS if the value could be correctly inserted in the
Andrew Woloszyn71fc0552015-09-24 10:26:51 -0400184 // instruction.
Lei Zhang1a0334e2015-11-02 09:41:20 -0500185 spv_result_t binaryEncodeU32(const uint32_t value, spv_instruction_t* pInst);
David Neto78e677b2015-10-05 13:28:46 -0400186
Andrew Woloszyn71fc0552015-09-24 10:26:51 -0400187 // Appends the given string to the given instruction.
David Neto78e677b2015-10-05 13:28:46 -0400188 // Returns SPV_SUCCESS if the value could be correctly inserted in the
Andrew Woloszyn71fc0552015-09-24 10:26:51 -0400189 // instruction.
Lei Zhang1a0334e2015-11-02 09:41:20 -0500190 spv_result_t binaryEncodeString(const char* value, spv_instruction_t* pInst);
Andrew Woloszyn71fc0552015-09-24 10:26:51 -0400191
David Neto78e677b2015-10-05 13:28:46 -0400192 // Appends the given numeric literal to the given instruction.
193 // Validates and respects the bitwidth supplied in the IdType argument.
194 // If the type is of class kBottom the value will be encoded as a
195 // 32-bit integer.
196 // Returns SPV_SUCCESS if the value could be correctly added to the
David Neto51013d12015-10-14 11:31:51 -0400197 // instruction. Returns the given error code on failure, and emits
Lei Zhangacf72872015-11-13 11:00:10 -0500198 // a diagnostic if that error code is not SPV_FAILED_MATCH.
Lei Zhang1a0334e2015-11-02 09:41:20 -0500199 spv_result_t binaryEncodeNumericLiteral(const char* numeric_literal,
David Neto51013d12015-10-14 11:31:51 -0400200 spv_result_t error_code,
Lei Zhang1a0334e2015-11-02 09:41:20 -0500201 const IdType& type,
202 spv_instruction_t* pInst);
David Neto78e677b2015-10-05 13:28:46 -0400203
Andrew Woloszyn537e7762015-09-29 11:28:34 -0400204 // Returns the IdType associated with this type-generating value.
205 // If the type has not been previously recorded with recordTypeDefinition,
David Neto78e677b2015-10-05 13:28:46 -0400206 // kUnknownType will be returned.
Andrew Woloszyn537e7762015-09-29 11:28:34 -0400207 IdType getTypeOfTypeGeneratingValue(uint32_t value) const;
208
209 // Returns the IdType that represents the return value of this Value
210 // generating instruction.
211 // If the value has not been recorded with recordTypeIdForValue, or the type
David Neto78e677b2015-10-05 13:28:46 -0400212 // could not be determined kUnknownType will be returned.
Andrew Woloszyn537e7762015-09-29 11:28:34 -0400213 IdType getTypeOfValueInstruction(uint32_t value) const;
214
215 // Tracks the type-defining instruction. The result of the tracking can
216 // later be queried using getValueType.
217 // pInst is expected to be completely filled in by the time this instruction
218 // is called.
219 // Returns SPV_SUCCESS on success, or SPV_ERROR_INVALID_VALUE on error.
220 spv_result_t recordTypeDefinition(const spv_instruction_t* pInst);
221
222 // Tracks the relationship between the value and its type.
223 spv_result_t recordTypeIdForValue(uint32_t value, uint32_t type);
224
David Neto2ae4a682015-11-09 18:55:42 -0500225 // Records the given Id as being the import of the given extended instruction
226 // type.
227 spv_result_t recordIdAsExtInstImport(uint32_t id, spv_ext_inst_type_t type);
228
229 // Returns the extended instruction type corresponding to the import with
230 // the given Id, if it exists. Returns SPV_EXT_INST_TYPE_NONE if the
231 // id is not the id for an extended instruction type.
232 spv_ext_inst_type_t getExtInstTypeForId(uint32_t id) const;
233
Andrey Tuganovb173d1c2017-04-11 19:46:15 -0400234 // Returns a set consisting of each ID generated by spvNamedIdAssignOrGet from
235 // a numeric ID text representation. For example, generated from "%12" but not
236 // from "%foo".
237 std::set<uint32_t> GetNumericIds() const;
238
Andrew Woloszyn71fc0552015-09-24 10:26:51 -0400239 private:
Andrew Woloszyn71fc0552015-09-24 10:26:51 -0400240 // Maps ID names to their corresponding numerical ids.
241 using spv_named_id_table = std::unordered_map<std::string, uint32_t>;
242 // Maps type-defining IDs to their IdType.
243 using spv_id_to_type_map = std::unordered_map<uint32_t, IdType>;
244 // Maps Ids to the id of their type.
245 using spv_id_to_type_id = std::unordered_map<uint32_t, uint32_t>;
246
247 spv_named_id_table named_ids_;
248 spv_id_to_type_map types_;
249 spv_id_to_type_id value_types_;
David Neto2ae4a682015-11-09 18:55:42 -0500250 // Maps an extended instruction import Id to the extended instruction type.
251 std::unordered_map<uint32_t, spv_ext_inst_type_t> import_id_to_ext_inst_type_;
Andrew Woloszyn71fc0552015-09-24 10:26:51 -0400252 spv_position_t current_position_;
dan sinclair3dad1cd2018-07-07 09:38:00 -0400253 MessageConsumer consumer_;
Andrew Woloszyn71fc0552015-09-24 10:26:51 -0400254 spv_text text_;
255 uint32_t bound_;
Andrey Tuganovb173d1c2017-04-11 19:46:15 -0400256 uint32_t next_id_;
257 std::set<uint32_t> ids_to_preserve_;
Andrew Woloszyn71fc0552015-09-24 10:26:51 -0400258};
dan sinclair3dad1cd2018-07-07 09:38:00 -0400259
260} // namespace spvtools
261
David Neto9f79d782015-10-27 16:27:05 -0400262#endif // _LIBSPIRV_TEXT_HANDLER_H_