blob: 11f9bc381575cb8e5ffcab7f90f03d355cfe33f1 [file] [log] [blame]
Dejan Mircevskib6fe02f2016-01-07 13:44:22 -05001// Copyright (c) 2015-2016 The Khronos Group Inc.
David Netofcc7d582015-10-27 15:31:10 -04002//
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
David Neto0f166be2015-11-11 01:56:49 -050089// Associates an opcode with its name.
90struct SpecConstantOpcodeEntry {
91 SpvOp opcode;
92 const char* name;
93};
94
95// All the opcodes allowed as the operation for OpSpecConstantOp.
96// The name does not have the usual "Op" prefix. For example opcode SpvOpIAdd
97// is associated with the name "IAdd".
98//
99// clang-format off
100#define CASE(NAME) { SpvOp##NAME, #NAME }
101const SpecConstantOpcodeEntry kOpSpecConstantOpcodes[] = {
102 // Conversion
103 CASE(SConvert),
104 CASE(FConvert),
105 CASE(ConvertFToS),
106 CASE(ConvertSToF),
107 CASE(ConvertFToU),
108 CASE(ConvertUToF),
109 CASE(UConvert),
110 CASE(ConvertPtrToU),
111 CASE(ConvertUToPtr),
David Neto969ce4b2016-01-05 18:22:22 -0500112 CASE(GenericCastToPtr),
David Neto0f166be2015-11-11 01:56:49 -0500113 CASE(PtrCastToGeneric),
114 CASE(Bitcast),
115 CASE(QuantizeToF16),
116 // Arithmetic
117 CASE(SNegate),
118 CASE(Not),
119 CASE(IAdd),
120 CASE(ISub),
121 CASE(IMul),
122 CASE(UDiv),
123 CASE(SDiv),
124 CASE(UMod),
125 CASE(SRem),
126 CASE(SMod),
127 CASE(ShiftRightLogical),
128 CASE(ShiftRightArithmetic),
129 CASE(ShiftLeftLogical),
130 CASE(BitwiseOr),
131 CASE(BitwiseAnd),
David Neto969ce4b2016-01-05 18:22:22 -0500132 CASE(BitwiseXor),
David Neto0f166be2015-11-11 01:56:49 -0500133 CASE(FNegate),
134 CASE(FAdd),
135 CASE(FSub),
136 CASE(FMul),
137 CASE(FDiv),
138 CASE(FRem),
139 CASE(FMod),
140 // Composite
141 CASE(VectorShuffle),
142 CASE(CompositeExtract),
143 CASE(CompositeInsert),
144 // Logical
145 CASE(LogicalOr),
146 CASE(LogicalAnd),
147 CASE(LogicalNot),
148 CASE(LogicalEqual),
149 CASE(LogicalNotEqual),
150 CASE(Select),
151 // Comparison
152 CASE(IEqual),
qining256c56d2016-07-26 17:52:06 -0400153 CASE(INotEqual),
David Neto0f166be2015-11-11 01:56:49 -0500154 CASE(ULessThan),
155 CASE(SLessThan),
156 CASE(UGreaterThan),
157 CASE(SGreaterThan),
158 CASE(ULessThanEqual),
159 CASE(SLessThanEqual),
David Neto0f166be2015-11-11 01:56:49 -0500160 CASE(UGreaterThanEqual),
161 CASE(SGreaterThanEqual),
162 // Memory
163 CASE(AccessChain),
164 CASE(InBoundsAccessChain),
165 CASE(PtrAccessChain),
166 CASE(InBoundsPtrAccessChain),
167};
David Neto969ce4b2016-01-05 18:22:22 -0500168
qining256c56d2016-07-26 17:52:06 -0400169// The 59 is determined by counting the opcodes listed in the spec.
170static_assert(59 == sizeof(kOpSpecConstantOpcodes)/sizeof(kOpSpecConstantOpcodes[0]),
David Neto969ce4b2016-01-05 18:22:22 -0500171 "OpSpecConstantOp opcode table is incomplete");
David Neto0f166be2015-11-11 01:56:49 -0500172#undef CASE
173// clang-format on
174
175const size_t kNumOpSpecConstantOpcodes =
176 sizeof(kOpSpecConstantOpcodes) / sizeof(kOpSpecConstantOpcodes[0]);
177
David Netofcc7d582015-10-27 15:31:10 -0400178} // anonymous namespace
179
180namespace libspirv {
181
182bool AssemblyGrammar::isValid() const {
183 return operandTable_ && opcodeTable_ && extInstTable_;
184}
185
Lei Zhang1a0334e2015-11-02 09:41:20 -0500186spv_result_t AssemblyGrammar::lookupOpcode(const char* name,
187 spv_opcode_desc* desc) const {
David Netofcc7d582015-10-27 15:31:10 -0400188 return spvOpcodeTableNameLookup(opcodeTable_, name, desc);
189}
190
Lei Zhangb36e7042015-10-28 13:40:52 -0400191spv_result_t AssemblyGrammar::lookupOpcode(SpvOp opcode,
Lei Zhang1a0334e2015-11-02 09:41:20 -0500192 spv_opcode_desc* desc) const {
David Netofcc7d582015-10-27 15:31:10 -0400193 return spvOpcodeTableValueLookup(opcodeTable_, opcode, desc);
194}
195
196spv_result_t AssemblyGrammar::lookupOperand(spv_operand_type_t type,
Lei Zhang1a0334e2015-11-02 09:41:20 -0500197 const char* name, size_t name_len,
198 spv_operand_desc* desc) const {
David Netofcc7d582015-10-27 15:31:10 -0400199 return spvOperandTableNameLookup(operandTable_, type, name, name_len, desc);
200}
201
202spv_result_t AssemblyGrammar::lookupOperand(spv_operand_type_t type,
203 uint32_t operand,
Lei Zhang1a0334e2015-11-02 09:41:20 -0500204 spv_operand_desc* desc) const {
David Netofcc7d582015-10-27 15:31:10 -0400205 return spvOperandTableValueLookup(operandTable_, type, operand, desc);
206}
207
David Neto0f166be2015-11-11 01:56:49 -0500208spv_result_t AssemblyGrammar::lookupSpecConstantOpcode(const char* name,
209 SpvOp* opcode) const {
210 const auto* last = kOpSpecConstantOpcodes + kNumOpSpecConstantOpcodes;
211 const auto* found =
212 std::find_if(kOpSpecConstantOpcodes, last,
213 [name](const SpecConstantOpcodeEntry& entry) {
214 return 0 == strcmp(name, entry.name);
215 });
216 if (found == last) return SPV_ERROR_INVALID_LOOKUP;
217 *opcode = found->opcode;
218 return SPV_SUCCESS;
219}
220
David Neto21196942015-11-11 02:45:45 -0500221spv_result_t AssemblyGrammar::lookupSpecConstantOpcode(SpvOp opcode) const {
222 const auto* last = kOpSpecConstantOpcodes + kNumOpSpecConstantOpcodes;
223 const auto* found =
224 std::find_if(kOpSpecConstantOpcodes, last,
225 [opcode](const SpecConstantOpcodeEntry& entry) {
226 return opcode == entry.opcode;
227 });
228 if (found == last) return SPV_ERROR_INVALID_LOOKUP;
229 return SPV_SUCCESS;
230}
231
David Netofcc7d582015-10-27 15:31:10 -0400232spv_result_t AssemblyGrammar::parseMaskOperand(const spv_operand_type_t type,
Lei Zhang1a0334e2015-11-02 09:41:20 -0500233 const char* textValue,
234 uint32_t* pValue) const {
David Netofcc7d582015-10-27 15:31:10 -0400235 return spvTextParseMaskOperand(operandTable_, type, textValue, pValue);
236}
237spv_result_t AssemblyGrammar::lookupExtInst(spv_ext_inst_type_t type,
Lei Zhang1a0334e2015-11-02 09:41:20 -0500238 const char* textValue,
239 spv_ext_inst_desc* extInst) const {
David Netofcc7d582015-10-27 15:31:10 -0400240 return spvExtInstTableNameLookup(extInstTable_, type, textValue, extInst);
241}
242
243spv_result_t AssemblyGrammar::lookupExtInst(spv_ext_inst_type_t type,
244 uint32_t firstWord,
Lei Zhang1a0334e2015-11-02 09:41:20 -0500245 spv_ext_inst_desc* extInst) const {
David Netofcc7d582015-10-27 15:31:10 -0400246 return spvExtInstTableValueLookup(extInstTable_, type, firstWord, extInst);
247}
248
249void AssemblyGrammar::prependOperandTypesForMask(
250 const spv_operand_type_t type, const uint32_t mask,
Lei Zhang1a0334e2015-11-02 09:41:20 -0500251 spv_operand_pattern_t* pattern) const {
David Netofcc7d582015-10-27 15:31:10 -0400252 spvPrependOperandTypesForMask(operandTable_, type, mask, pattern);
253}
254} // namespace libspirv