blob: 448d9dcfb487e7b547c4138410ac30ac5462590f [file] [log] [blame]
David Netofcc7d582015-10-27 15:31:10 -04001// Copyright (c) 2015 The Khronos Group Inc.
2//
3// Permission is hereby granted, free of charge, to any person obtaining a
4// copy of this software and/or associated documentation files (the
5// "Materials"), to deal in the Materials without restriction, including
6// without limitation the rights to use, copy, modify, merge, publish,
7// distribute, sublicense, and/or sell copies of the Materials, and to
8// permit persons to whom the Materials are furnished to do so, subject to
9// the following conditions:
10//
11// The above copyright notice and this permission notice shall be included
12// in all copies or substantial portions of the Materials.
13//
14// MODIFICATIONS TO THIS FILE MAY MEAN IT NO LONGER ACCURATELY REFLECTS
15// KHRONOS STANDARDS. THE UNMODIFIED, NORMATIVE VERSIONS OF KHRONOS
16// SPECIFICATIONS AND HEADER INFORMATION ARE LOCATED AT
17// https://www.khronos.org/registry/
18//
19// THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
20// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
21// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
22// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
23// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
24// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
25// MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
26
27#include "assembly_grammar.h"
28
29#include <algorithm>
David Neto0ca6b592015-10-30 16:06:15 -040030#include <cassert>
David Netofcc7d582015-10-27 15:31:10 -040031#include <cstring>
32
33#include "ext_inst.h"
34#include "opcode.h"
David Neto0ca6b592015-10-30 16:06:15 -040035#include "operand.h"
Lei Zhang04736e72015-11-11 12:14:36 -050036#include "table.h"
David Netofcc7d582015-10-27 15:31:10 -040037
38namespace {
39
40/// @brief Parses a mask expression string for the given operand type.
41///
42/// A mask expression is a sequence of one or more terms separated by '|',
43/// where each term a named enum value for the given type. No whitespace
44/// is permitted.
45///
46/// On success, the value is written to pValue.
47///
48/// @param[in] operandTable operand lookup table
49/// @param[in] type of the operand
50/// @param[in] textValue word of text to be parsed
51/// @param[out] pValue where the resulting value is written
52///
53/// @return result code
54spv_result_t spvTextParseMaskOperand(const spv_operand_table operandTable,
55 const spv_operand_type_t type,
Lei Zhang1a0334e2015-11-02 09:41:20 -050056 const char* textValue, uint32_t* pValue) {
David Netofcc7d582015-10-27 15:31:10 -040057 if (textValue == nullptr) return SPV_ERROR_INVALID_TEXT;
58 size_t text_length = strlen(textValue);
59 if (text_length == 0) return SPV_ERROR_INVALID_TEXT;
Lei Zhang1a0334e2015-11-02 09:41:20 -050060 const char* text_end = textValue + text_length;
David Netofcc7d582015-10-27 15:31:10 -040061
62 // We only support mask expressions in ASCII, so the separator value is a
63 // char.
64 const char separator = '|';
65
66 // Accumulate the result by interpreting one word at a time, scanning
67 // from left to right.
68 uint32_t value = 0;
Lei Zhang1a0334e2015-11-02 09:41:20 -050069 const char* begin = textValue; // The left end of the current word.
70 const char* end = nullptr; // One character past the end of the current word.
David Netofcc7d582015-10-27 15:31:10 -040071 do {
72 end = std::find(begin, text_end, separator);
73
74 spv_operand_desc entry = nullptr;
75 if (spvOperandTableNameLookup(operandTable, type, begin, end - begin,
76 &entry)) {
77 return SPV_ERROR_INVALID_TEXT;
78 }
79 value |= entry->value;
80
81 // Advance to the next word by skipping over the separator.
82 begin = end + 1;
83 } while (end != text_end);
84
85 *pValue = value;
86 return SPV_SUCCESS;
87}
David Neto0ca6b592015-10-30 16:06:15 -040088
89// Returns the operand table.
90spv_operand_table GetDefaultOperandTable() {
91 spv_operand_table result = nullptr;
92 spvOperandTableGet(&result);
93 assert(result);
94 return result;
95}
96
97// Returns the opcode table.
98spv_opcode_table GetDefaultOpcodeTable() {
99 spv_opcode_table result = nullptr;
100 spvOpcodeTableGet(&result);
101 assert(result);
102 return result;
103}
104
105// Returns the extended instruction table.
106spv_ext_inst_table GetDefaultExtInstTable() {
107 spv_ext_inst_table result = nullptr;
108 spvExtInstTableGet(&result);
109 assert(result);
110 return result;
111}
112
David Neto0f166be2015-11-11 01:56:49 -0500113// Associates an opcode with its name.
114struct SpecConstantOpcodeEntry {
115 SpvOp opcode;
116 const char* name;
117};
118
119// All the opcodes allowed as the operation for OpSpecConstantOp.
120// The name does not have the usual "Op" prefix. For example opcode SpvOpIAdd
121// is associated with the name "IAdd".
122//
123// clang-format off
124#define CASE(NAME) { SpvOp##NAME, #NAME }
125const SpecConstantOpcodeEntry kOpSpecConstantOpcodes[] = {
126 // Conversion
127 CASE(SConvert),
128 CASE(FConvert),
129 CASE(ConvertFToS),
130 CASE(ConvertSToF),
131 CASE(ConvertFToU),
132 CASE(ConvertUToF),
133 CASE(UConvert),
134 CASE(ConvertPtrToU),
135 CASE(ConvertUToPtr),
136 CASE(PtrCastToGeneric),
137 CASE(Bitcast),
138 CASE(QuantizeToF16),
139 // Arithmetic
140 CASE(SNegate),
141 CASE(Not),
142 CASE(IAdd),
143 CASE(ISub),
144 CASE(IMul),
145 CASE(UDiv),
146 CASE(SDiv),
147 CASE(UMod),
148 CASE(SRem),
149 CASE(SMod),
150 CASE(ShiftRightLogical),
151 CASE(ShiftRightArithmetic),
152 CASE(ShiftLeftLogical),
153 CASE(BitwiseOr),
154 CASE(BitwiseAnd),
155 CASE(FNegate),
156 CASE(FAdd),
157 CASE(FSub),
158 CASE(FMul),
159 CASE(FDiv),
160 CASE(FRem),
161 CASE(FMod),
162 // Composite
163 CASE(VectorShuffle),
164 CASE(CompositeExtract),
165 CASE(CompositeInsert),
166 // Logical
167 CASE(LogicalOr),
168 CASE(LogicalAnd),
169 CASE(LogicalNot),
170 CASE(LogicalEqual),
171 CASE(LogicalNotEqual),
172 CASE(Select),
173 // Comparison
174 CASE(IEqual),
175 CASE(ULessThan),
176 CASE(SLessThan),
177 CASE(UGreaterThan),
178 CASE(SGreaterThan),
179 CASE(ULessThanEqual),
180 CASE(SLessThanEqual),
181 CASE(SLessThanEqual),
182 CASE(UGreaterThanEqual),
183 CASE(SGreaterThanEqual),
184 // Memory
185 CASE(AccessChain),
186 CASE(InBoundsAccessChain),
187 CASE(PtrAccessChain),
188 CASE(InBoundsPtrAccessChain),
189};
190#undef CASE
191// clang-format on
192
193const size_t kNumOpSpecConstantOpcodes =
194 sizeof(kOpSpecConstantOpcodes) / sizeof(kOpSpecConstantOpcodes[0]);
195
David Netofcc7d582015-10-27 15:31:10 -0400196} // anonymous namespace
197
198namespace libspirv {
199
David Neto0ca6b592015-10-30 16:06:15 -0400200AssemblyGrammar::AssemblyGrammar()
201 : AssemblyGrammar(GetDefaultOperandTable(), GetDefaultOpcodeTable(),
202 GetDefaultExtInstTable()) {
203 assert(isValid());
204}
205
David Netofcc7d582015-10-27 15:31:10 -0400206bool AssemblyGrammar::isValid() const {
207 return operandTable_ && opcodeTable_ && extInstTable_;
208}
209
Lei Zhang1a0334e2015-11-02 09:41:20 -0500210spv_result_t AssemblyGrammar::lookupOpcode(const char* name,
211 spv_opcode_desc* desc) const {
David Netofcc7d582015-10-27 15:31:10 -0400212 return spvOpcodeTableNameLookup(opcodeTable_, name, desc);
213}
214
Lei Zhangb36e7042015-10-28 13:40:52 -0400215spv_result_t AssemblyGrammar::lookupOpcode(SpvOp opcode,
Lei Zhang1a0334e2015-11-02 09:41:20 -0500216 spv_opcode_desc* desc) const {
David Netofcc7d582015-10-27 15:31:10 -0400217 return spvOpcodeTableValueLookup(opcodeTable_, opcode, desc);
218}
219
220spv_result_t AssemblyGrammar::lookupOperand(spv_operand_type_t type,
Lei Zhang1a0334e2015-11-02 09:41:20 -0500221 const char* name, size_t name_len,
222 spv_operand_desc* desc) const {
David Netofcc7d582015-10-27 15:31:10 -0400223 return spvOperandTableNameLookup(operandTable_, type, name, name_len, desc);
224}
225
226spv_result_t AssemblyGrammar::lookupOperand(spv_operand_type_t type,
227 uint32_t operand,
Lei Zhang1a0334e2015-11-02 09:41:20 -0500228 spv_operand_desc* desc) const {
David Netofcc7d582015-10-27 15:31:10 -0400229 return spvOperandTableValueLookup(operandTable_, type, operand, desc);
230}
231
David Neto0f166be2015-11-11 01:56:49 -0500232spv_result_t AssemblyGrammar::lookupSpecConstantOpcode(const char* name,
233 SpvOp* opcode) const {
234 const auto* last = kOpSpecConstantOpcodes + kNumOpSpecConstantOpcodes;
235 const auto* found =
236 std::find_if(kOpSpecConstantOpcodes, last,
237 [name](const SpecConstantOpcodeEntry& entry) {
238 return 0 == strcmp(name, entry.name);
239 });
240 if (found == last) return SPV_ERROR_INVALID_LOOKUP;
241 *opcode = found->opcode;
242 return SPV_SUCCESS;
243}
244
David Neto21196942015-11-11 02:45:45 -0500245spv_result_t AssemblyGrammar::lookupSpecConstantOpcode(SpvOp opcode) const {
246 const auto* last = kOpSpecConstantOpcodes + kNumOpSpecConstantOpcodes;
247 const auto* found =
248 std::find_if(kOpSpecConstantOpcodes, last,
249 [opcode](const SpecConstantOpcodeEntry& entry) {
250 return opcode == entry.opcode;
251 });
252 if (found == last) return SPV_ERROR_INVALID_LOOKUP;
253 return SPV_SUCCESS;
254}
255
David Netofcc7d582015-10-27 15:31:10 -0400256spv_result_t AssemblyGrammar::parseMaskOperand(const spv_operand_type_t type,
Lei Zhang1a0334e2015-11-02 09:41:20 -0500257 const char* textValue,
258 uint32_t* pValue) const {
David Netofcc7d582015-10-27 15:31:10 -0400259 return spvTextParseMaskOperand(operandTable_, type, textValue, pValue);
260}
261spv_result_t AssemblyGrammar::lookupExtInst(spv_ext_inst_type_t type,
Lei Zhang1a0334e2015-11-02 09:41:20 -0500262 const char* textValue,
263 spv_ext_inst_desc* extInst) const {
David Netofcc7d582015-10-27 15:31:10 -0400264 return spvExtInstTableNameLookup(extInstTable_, type, textValue, extInst);
265}
266
267spv_result_t AssemblyGrammar::lookupExtInst(spv_ext_inst_type_t type,
268 uint32_t firstWord,
Lei Zhang1a0334e2015-11-02 09:41:20 -0500269 spv_ext_inst_desc* extInst) const {
David Netofcc7d582015-10-27 15:31:10 -0400270 return spvExtInstTableValueLookup(extInstTable_, type, firstWord, extInst);
271}
272
273void AssemblyGrammar::prependOperandTypesForMask(
274 const spv_operand_type_t type, const uint32_t mask,
Lei Zhang1a0334e2015-11-02 09:41:20 -0500275 spv_operand_pattern_t* pattern) const {
David Netofcc7d582015-10-27 15:31:10 -0400276 spvPrependOperandTypesForMask(operandTable_, type, mask, pattern);
277}
278} // namespace libspirv