blob: 294c07a6b4aaf405b017569f2d00f2b276dc0f3c [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//
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
David Netofcc7d582015-10-27 15:31:10 -04006//
David Neto9fc86582016-09-01 15:33:59 -04007// http://www.apache.org/licenses/LICENSE-2.0
David Netofcc7d582015-10-27 15:31:10 -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.
David Netofcc7d582015-10-27 15:31:10 -040014
15#include "assembly_grammar.h"
16
17#include <algorithm>
David Neto0ca6b592015-10-30 16:06:15 -040018#include <cassert>
David Netofcc7d582015-10-27 15:31:10 -040019#include <cstring>
20
21#include "ext_inst.h"
22#include "opcode.h"
David Neto0ca6b592015-10-30 16:06:15 -040023#include "operand.h"
Lei Zhang04736e72015-11-11 12:14:36 -050024#include "table.h"
David Netofcc7d582015-10-27 15:31:10 -040025
26namespace {
27
28/// @brief Parses a mask expression string for the given operand type.
29///
30/// A mask expression is a sequence of one or more terms separated by '|',
31/// where each term a named enum value for the given type. No whitespace
32/// is permitted.
33///
34/// On success, the value is written to pValue.
35///
36/// @param[in] operandTable operand lookup table
37/// @param[in] type of the operand
38/// @param[in] textValue word of text to be parsed
39/// @param[out] pValue where the resulting value is written
40///
41/// @return result code
42spv_result_t spvTextParseMaskOperand(const spv_operand_table operandTable,
43 const spv_operand_type_t type,
Lei Zhang1a0334e2015-11-02 09:41:20 -050044 const char* textValue, uint32_t* pValue) {
David Netofcc7d582015-10-27 15:31:10 -040045 if (textValue == nullptr) return SPV_ERROR_INVALID_TEXT;
46 size_t text_length = strlen(textValue);
47 if (text_length == 0) return SPV_ERROR_INVALID_TEXT;
Lei Zhang1a0334e2015-11-02 09:41:20 -050048 const char* text_end = textValue + text_length;
David Netofcc7d582015-10-27 15:31:10 -040049
50 // We only support mask expressions in ASCII, so the separator value is a
51 // char.
52 const char separator = '|';
53
54 // Accumulate the result by interpreting one word at a time, scanning
55 // from left to right.
56 uint32_t value = 0;
Lei Zhang1a0334e2015-11-02 09:41:20 -050057 const char* begin = textValue; // The left end of the current word.
58 const char* end = nullptr; // One character past the end of the current word.
David Netofcc7d582015-10-27 15:31:10 -040059 do {
60 end = std::find(begin, text_end, separator);
61
62 spv_operand_desc entry = nullptr;
63 if (spvOperandTableNameLookup(operandTable, type, begin, end - begin,
64 &entry)) {
65 return SPV_ERROR_INVALID_TEXT;
66 }
67 value |= entry->value;
68
69 // Advance to the next word by skipping over the separator.
70 begin = end + 1;
71 } while (end != text_end);
72
73 *pValue = value;
74 return SPV_SUCCESS;
75}
David Neto0ca6b592015-10-30 16:06:15 -040076
David Neto0f166be2015-11-11 01:56:49 -050077// Associates an opcode with its name.
78struct SpecConstantOpcodeEntry {
79 SpvOp opcode;
80 const char* name;
81};
82
83// All the opcodes allowed as the operation for OpSpecConstantOp.
84// The name does not have the usual "Op" prefix. For example opcode SpvOpIAdd
85// is associated with the name "IAdd".
86//
87// clang-format off
88#define CASE(NAME) { SpvOp##NAME, #NAME }
89const SpecConstantOpcodeEntry kOpSpecConstantOpcodes[] = {
90 // Conversion
91 CASE(SConvert),
92 CASE(FConvert),
93 CASE(ConvertFToS),
94 CASE(ConvertSToF),
95 CASE(ConvertFToU),
96 CASE(ConvertUToF),
97 CASE(UConvert),
98 CASE(ConvertPtrToU),
99 CASE(ConvertUToPtr),
David Neto969ce4b2016-01-05 18:22:22 -0500100 CASE(GenericCastToPtr),
David Neto0f166be2015-11-11 01:56:49 -0500101 CASE(PtrCastToGeneric),
102 CASE(Bitcast),
103 CASE(QuantizeToF16),
104 // Arithmetic
105 CASE(SNegate),
106 CASE(Not),
107 CASE(IAdd),
108 CASE(ISub),
109 CASE(IMul),
110 CASE(UDiv),
111 CASE(SDiv),
112 CASE(UMod),
113 CASE(SRem),
114 CASE(SMod),
115 CASE(ShiftRightLogical),
116 CASE(ShiftRightArithmetic),
117 CASE(ShiftLeftLogical),
118 CASE(BitwiseOr),
119 CASE(BitwiseAnd),
David Neto969ce4b2016-01-05 18:22:22 -0500120 CASE(BitwiseXor),
David Neto0f166be2015-11-11 01:56:49 -0500121 CASE(FNegate),
122 CASE(FAdd),
123 CASE(FSub),
124 CASE(FMul),
125 CASE(FDiv),
126 CASE(FRem),
127 CASE(FMod),
128 // Composite
129 CASE(VectorShuffle),
130 CASE(CompositeExtract),
131 CASE(CompositeInsert),
132 // Logical
133 CASE(LogicalOr),
134 CASE(LogicalAnd),
135 CASE(LogicalNot),
136 CASE(LogicalEqual),
137 CASE(LogicalNotEqual),
138 CASE(Select),
139 // Comparison
140 CASE(IEqual),
qining256c56d2016-07-26 17:52:06 -0400141 CASE(INotEqual),
David Neto0f166be2015-11-11 01:56:49 -0500142 CASE(ULessThan),
143 CASE(SLessThan),
144 CASE(UGreaterThan),
145 CASE(SGreaterThan),
146 CASE(ULessThanEqual),
147 CASE(SLessThanEqual),
David Neto0f166be2015-11-11 01:56:49 -0500148 CASE(UGreaterThanEqual),
149 CASE(SGreaterThanEqual),
150 // Memory
151 CASE(AccessChain),
152 CASE(InBoundsAccessChain),
153 CASE(PtrAccessChain),
154 CASE(InBoundsPtrAccessChain),
155};
David Neto969ce4b2016-01-05 18:22:22 -0500156
qining256c56d2016-07-26 17:52:06 -0400157// The 59 is determined by counting the opcodes listed in the spec.
158static_assert(59 == sizeof(kOpSpecConstantOpcodes)/sizeof(kOpSpecConstantOpcodes[0]),
David Neto969ce4b2016-01-05 18:22:22 -0500159 "OpSpecConstantOp opcode table is incomplete");
David Neto0f166be2015-11-11 01:56:49 -0500160#undef CASE
161// clang-format on
162
163const size_t kNumOpSpecConstantOpcodes =
164 sizeof(kOpSpecConstantOpcodes) / sizeof(kOpSpecConstantOpcodes[0]);
165
David Netofcc7d582015-10-27 15:31:10 -0400166} // anonymous namespace
167
168namespace libspirv {
169
170bool AssemblyGrammar::isValid() const {
171 return operandTable_ && opcodeTable_ && extInstTable_;
172}
173
Lei Zhang1a0334e2015-11-02 09:41:20 -0500174spv_result_t AssemblyGrammar::lookupOpcode(const char* name,
175 spv_opcode_desc* desc) const {
David Netofcc7d582015-10-27 15:31:10 -0400176 return spvOpcodeTableNameLookup(opcodeTable_, name, desc);
177}
178
Lei Zhangb36e7042015-10-28 13:40:52 -0400179spv_result_t AssemblyGrammar::lookupOpcode(SpvOp opcode,
Lei Zhang1a0334e2015-11-02 09:41:20 -0500180 spv_opcode_desc* desc) const {
David Netofcc7d582015-10-27 15:31:10 -0400181 return spvOpcodeTableValueLookup(opcodeTable_, opcode, desc);
182}
183
184spv_result_t AssemblyGrammar::lookupOperand(spv_operand_type_t type,
Lei Zhang1a0334e2015-11-02 09:41:20 -0500185 const char* name, size_t name_len,
186 spv_operand_desc* desc) const {
David Netofcc7d582015-10-27 15:31:10 -0400187 return spvOperandTableNameLookup(operandTable_, type, name, name_len, desc);
188}
189
190spv_result_t AssemblyGrammar::lookupOperand(spv_operand_type_t type,
191 uint32_t operand,
Lei Zhang1a0334e2015-11-02 09:41:20 -0500192 spv_operand_desc* desc) const {
David Netofcc7d582015-10-27 15:31:10 -0400193 return spvOperandTableValueLookup(operandTable_, type, operand, desc);
194}
195
David Neto0f166be2015-11-11 01:56:49 -0500196spv_result_t AssemblyGrammar::lookupSpecConstantOpcode(const char* name,
197 SpvOp* opcode) const {
198 const auto* last = kOpSpecConstantOpcodes + kNumOpSpecConstantOpcodes;
199 const auto* found =
200 std::find_if(kOpSpecConstantOpcodes, last,
201 [name](const SpecConstantOpcodeEntry& entry) {
202 return 0 == strcmp(name, entry.name);
203 });
204 if (found == last) return SPV_ERROR_INVALID_LOOKUP;
205 *opcode = found->opcode;
206 return SPV_SUCCESS;
207}
208
David Neto21196942015-11-11 02:45:45 -0500209spv_result_t AssemblyGrammar::lookupSpecConstantOpcode(SpvOp opcode) const {
210 const auto* last = kOpSpecConstantOpcodes + kNumOpSpecConstantOpcodes;
211 const auto* found =
212 std::find_if(kOpSpecConstantOpcodes, last,
213 [opcode](const SpecConstantOpcodeEntry& entry) {
214 return opcode == entry.opcode;
215 });
216 if (found == last) return SPV_ERROR_INVALID_LOOKUP;
217 return SPV_SUCCESS;
218}
219
David Netofcc7d582015-10-27 15:31:10 -0400220spv_result_t AssemblyGrammar::parseMaskOperand(const spv_operand_type_t type,
Lei Zhang1a0334e2015-11-02 09:41:20 -0500221 const char* textValue,
222 uint32_t* pValue) const {
David Netofcc7d582015-10-27 15:31:10 -0400223 return spvTextParseMaskOperand(operandTable_, type, textValue, pValue);
224}
225spv_result_t AssemblyGrammar::lookupExtInst(spv_ext_inst_type_t type,
Lei Zhang1a0334e2015-11-02 09:41:20 -0500226 const char* textValue,
227 spv_ext_inst_desc* extInst) const {
David Netofcc7d582015-10-27 15:31:10 -0400228 return spvExtInstTableNameLookup(extInstTable_, type, textValue, extInst);
229}
230
231spv_result_t AssemblyGrammar::lookupExtInst(spv_ext_inst_type_t type,
232 uint32_t firstWord,
Lei Zhang1a0334e2015-11-02 09:41:20 -0500233 spv_ext_inst_desc* extInst) const {
David Netofcc7d582015-10-27 15:31:10 -0400234 return spvExtInstTableValueLookup(extInstTable_, type, firstWord, extInst);
235}
236
237void AssemblyGrammar::prependOperandTypesForMask(
238 const spv_operand_type_t type, const uint32_t mask,
Lei Zhang1a0334e2015-11-02 09:41:20 -0500239 spv_operand_pattern_t* pattern) const {
David Netofcc7d582015-10-27 15:31:10 -0400240 spvPrependOperandTypesForMask(operandTable_, type, mask, pattern);
241}
242} // namespace libspirv