blob: a437fb3cbbc979d4f1cc23fb679dc8b6ed8828d0 [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"
David Netofcc7d582015-10-27 15:31:10 -040036
37namespace {
38
39/// @brief Parses a mask expression string for the given operand type.
40///
41/// A mask expression is a sequence of one or more terms separated by '|',
42/// where each term a named enum value for the given type. No whitespace
43/// is permitted.
44///
45/// On success, the value is written to pValue.
46///
47/// @param[in] operandTable operand lookup table
48/// @param[in] type of the operand
49/// @param[in] textValue word of text to be parsed
50/// @param[out] pValue where the resulting value is written
51///
52/// @return result code
53spv_result_t spvTextParseMaskOperand(const spv_operand_table operandTable,
54 const spv_operand_type_t type,
Lei Zhang1a0334e2015-11-02 09:41:20 -050055 const char* textValue, uint32_t* pValue) {
David Netofcc7d582015-10-27 15:31:10 -040056 if (textValue == nullptr) return SPV_ERROR_INVALID_TEXT;
57 size_t text_length = strlen(textValue);
58 if (text_length == 0) return SPV_ERROR_INVALID_TEXT;
Lei Zhang1a0334e2015-11-02 09:41:20 -050059 const char* text_end = textValue + text_length;
David Netofcc7d582015-10-27 15:31:10 -040060
61 // We only support mask expressions in ASCII, so the separator value is a
62 // char.
63 const char separator = '|';
64
65 // Accumulate the result by interpreting one word at a time, scanning
66 // from left to right.
67 uint32_t value = 0;
Lei Zhang1a0334e2015-11-02 09:41:20 -050068 const char* begin = textValue; // The left end of the current word.
69 const char* end = nullptr; // One character past the end of the current word.
David Netofcc7d582015-10-27 15:31:10 -040070 do {
71 end = std::find(begin, text_end, separator);
72
73 spv_operand_desc entry = nullptr;
74 if (spvOperandTableNameLookup(operandTable, type, begin, end - begin,
75 &entry)) {
76 return SPV_ERROR_INVALID_TEXT;
77 }
78 value |= entry->value;
79
80 // Advance to the next word by skipping over the separator.
81 begin = end + 1;
82 } while (end != text_end);
83
84 *pValue = value;
85 return SPV_SUCCESS;
86}
David Neto0ca6b592015-10-30 16:06:15 -040087
88// Returns the operand table.
89spv_operand_table GetDefaultOperandTable() {
90 spv_operand_table result = nullptr;
91 spvOperandTableGet(&result);
92 assert(result);
93 return result;
94}
95
96// Returns the opcode table.
97spv_opcode_table GetDefaultOpcodeTable() {
98 spv_opcode_table result = nullptr;
99 spvOpcodeTableGet(&result);
100 assert(result);
101 return result;
102}
103
104// Returns the extended instruction table.
105spv_ext_inst_table GetDefaultExtInstTable() {
106 spv_ext_inst_table result = nullptr;
107 spvExtInstTableGet(&result);
108 assert(result);
109 return result;
110}
111
David Neto0f166be2015-11-11 01:56:49 -0500112// Associates an opcode with its name.
113struct SpecConstantOpcodeEntry {
114 SpvOp opcode;
115 const char* name;
116};
117
118// All the opcodes allowed as the operation for OpSpecConstantOp.
119// The name does not have the usual "Op" prefix. For example opcode SpvOpIAdd
120// is associated with the name "IAdd".
121//
122// clang-format off
123#define CASE(NAME) { SpvOp##NAME, #NAME }
124const SpecConstantOpcodeEntry kOpSpecConstantOpcodes[] = {
125 // Conversion
126 CASE(SConvert),
127 CASE(FConvert),
128 CASE(ConvertFToS),
129 CASE(ConvertSToF),
130 CASE(ConvertFToU),
131 CASE(ConvertUToF),
132 CASE(UConvert),
133 CASE(ConvertPtrToU),
134 CASE(ConvertUToPtr),
135 CASE(PtrCastToGeneric),
136 CASE(Bitcast),
137 CASE(QuantizeToF16),
138 // Arithmetic
139 CASE(SNegate),
140 CASE(Not),
141 CASE(IAdd),
142 CASE(ISub),
143 CASE(IMul),
144 CASE(UDiv),
145 CASE(SDiv),
146 CASE(UMod),
147 CASE(SRem),
148 CASE(SMod),
149 CASE(ShiftRightLogical),
150 CASE(ShiftRightArithmetic),
151 CASE(ShiftLeftLogical),
152 CASE(BitwiseOr),
153 CASE(BitwiseAnd),
154 CASE(FNegate),
155 CASE(FAdd),
156 CASE(FSub),
157 CASE(FMul),
158 CASE(FDiv),
159 CASE(FRem),
160 CASE(FMod),
161 // Composite
162 CASE(VectorShuffle),
163 CASE(CompositeExtract),
164 CASE(CompositeInsert),
165 // Logical
166 CASE(LogicalOr),
167 CASE(LogicalAnd),
168 CASE(LogicalNot),
169 CASE(LogicalEqual),
170 CASE(LogicalNotEqual),
171 CASE(Select),
172 // Comparison
173 CASE(IEqual),
174 CASE(ULessThan),
175 CASE(SLessThan),
176 CASE(UGreaterThan),
177 CASE(SGreaterThan),
178 CASE(ULessThanEqual),
179 CASE(SLessThanEqual),
180 CASE(SLessThanEqual),
181 CASE(UGreaterThanEqual),
182 CASE(SGreaterThanEqual),
183 // Memory
184 CASE(AccessChain),
185 CASE(InBoundsAccessChain),
186 CASE(PtrAccessChain),
187 CASE(InBoundsPtrAccessChain),
188};
189#undef CASE
190// clang-format on
191
192const size_t kNumOpSpecConstantOpcodes =
193 sizeof(kOpSpecConstantOpcodes) / sizeof(kOpSpecConstantOpcodes[0]);
194
David Netofcc7d582015-10-27 15:31:10 -0400195} // anonymous namespace
196
197namespace libspirv {
198
David Neto0ca6b592015-10-30 16:06:15 -0400199AssemblyGrammar::AssemblyGrammar()
200 : AssemblyGrammar(GetDefaultOperandTable(), GetDefaultOpcodeTable(),
201 GetDefaultExtInstTable()) {
202 assert(isValid());
203}
204
David Netofcc7d582015-10-27 15:31:10 -0400205bool AssemblyGrammar::isValid() const {
206 return operandTable_ && opcodeTable_ && extInstTable_;
207}
208
Lei Zhang1a0334e2015-11-02 09:41:20 -0500209spv_result_t AssemblyGrammar::lookupOpcode(const char* name,
210 spv_opcode_desc* desc) const {
David Netofcc7d582015-10-27 15:31:10 -0400211 return spvOpcodeTableNameLookup(opcodeTable_, name, desc);
212}
213
Lei Zhangb36e7042015-10-28 13:40:52 -0400214spv_result_t AssemblyGrammar::lookupOpcode(SpvOp opcode,
Lei Zhang1a0334e2015-11-02 09:41:20 -0500215 spv_opcode_desc* desc) const {
David Netofcc7d582015-10-27 15:31:10 -0400216 return spvOpcodeTableValueLookup(opcodeTable_, opcode, desc);
217}
218
219spv_result_t AssemblyGrammar::lookupOperand(spv_operand_type_t type,
Lei Zhang1a0334e2015-11-02 09:41:20 -0500220 const char* name, size_t name_len,
221 spv_operand_desc* desc) const {
David Netofcc7d582015-10-27 15:31:10 -0400222 return spvOperandTableNameLookup(operandTable_, type, name, name_len, desc);
223}
224
225spv_result_t AssemblyGrammar::lookupOperand(spv_operand_type_t type,
226 uint32_t operand,
Lei Zhang1a0334e2015-11-02 09:41:20 -0500227 spv_operand_desc* desc) const {
David Netofcc7d582015-10-27 15:31:10 -0400228 return spvOperandTableValueLookup(operandTable_, type, operand, desc);
229}
230
David Neto0f166be2015-11-11 01:56:49 -0500231spv_result_t AssemblyGrammar::lookupSpecConstantOpcode(const char* name,
232 SpvOp* opcode) const {
233 const auto* last = kOpSpecConstantOpcodes + kNumOpSpecConstantOpcodes;
234 const auto* found =
235 std::find_if(kOpSpecConstantOpcodes, last,
236 [name](const SpecConstantOpcodeEntry& entry) {
237 return 0 == strcmp(name, entry.name);
238 });
239 if (found == last) return SPV_ERROR_INVALID_LOOKUP;
240 *opcode = found->opcode;
241 return SPV_SUCCESS;
242}
243
David Neto21196942015-11-11 02:45:45 -0500244spv_result_t AssemblyGrammar::lookupSpecConstantOpcode(SpvOp opcode) const {
245 const auto* last = kOpSpecConstantOpcodes + kNumOpSpecConstantOpcodes;
246 const auto* found =
247 std::find_if(kOpSpecConstantOpcodes, last,
248 [opcode](const SpecConstantOpcodeEntry& entry) {
249 return opcode == entry.opcode;
250 });
251 if (found == last) return SPV_ERROR_INVALID_LOOKUP;
252 return SPV_SUCCESS;
253}
254
David Netofcc7d582015-10-27 15:31:10 -0400255spv_result_t AssemblyGrammar::parseMaskOperand(const spv_operand_type_t type,
Lei Zhang1a0334e2015-11-02 09:41:20 -0500256 const char* textValue,
257 uint32_t* pValue) const {
David Netofcc7d582015-10-27 15:31:10 -0400258 return spvTextParseMaskOperand(operandTable_, type, textValue, pValue);
259}
260spv_result_t AssemblyGrammar::lookupExtInst(spv_ext_inst_type_t type,
Lei Zhang1a0334e2015-11-02 09:41:20 -0500261 const char* textValue,
262 spv_ext_inst_desc* extInst) const {
David Netofcc7d582015-10-27 15:31:10 -0400263 return spvExtInstTableNameLookup(extInstTable_, type, textValue, extInst);
264}
265
266spv_result_t AssemblyGrammar::lookupExtInst(spv_ext_inst_type_t type,
267 uint32_t firstWord,
Lei Zhang1a0334e2015-11-02 09:41:20 -0500268 spv_ext_inst_desc* extInst) const {
David Netofcc7d582015-10-27 15:31:10 -0400269 return spvExtInstTableValueLookup(extInstTable_, type, firstWord, extInst);
270}
271
272void AssemblyGrammar::prependOperandTypesForMask(
273 const spv_operand_type_t type, const uint32_t mask,
Lei Zhang1a0334e2015-11-02 09:41:20 -0500274 spv_operand_pattern_t* pattern) const {
David Netofcc7d582015-10-27 15:31:10 -0400275 spvPrependOperandTypesForMask(operandTable_, type, mask, pattern);
276}
277} // namespace libspirv