blob: 2fde640539bd8d4af63c68c8d4f35f8461819807 [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
Lei Zhang1ef6b192018-03-14 13:06:18 -040042spv_result_t spvTextParseMaskOperand(spv_target_env env,
43 const spv_operand_table operandTable,
David Netofcc7d582015-10-27 15:31:10 -040044 const spv_operand_type_t type,
Lei Zhang1a0334e2015-11-02 09:41:20 -050045 const char* textValue, uint32_t* pValue) {
David Netofcc7d582015-10-27 15:31:10 -040046 if (textValue == nullptr) return SPV_ERROR_INVALID_TEXT;
47 size_t text_length = strlen(textValue);
48 if (text_length == 0) return SPV_ERROR_INVALID_TEXT;
Lei Zhang1a0334e2015-11-02 09:41:20 -050049 const char* text_end = textValue + text_length;
David Netofcc7d582015-10-27 15:31:10 -040050
51 // We only support mask expressions in ASCII, so the separator value is a
52 // char.
53 const char separator = '|';
54
55 // Accumulate the result by interpreting one word at a time, scanning
56 // from left to right.
57 uint32_t value = 0;
Lei Zhang1a0334e2015-11-02 09:41:20 -050058 const char* begin = textValue; // The left end of the current word.
59 const char* end = nullptr; // One character past the end of the current word.
David Netofcc7d582015-10-27 15:31:10 -040060 do {
61 end = std::find(begin, text_end, separator);
62
63 spv_operand_desc entry = nullptr;
Lei Zhang1ef6b192018-03-14 13:06:18 -040064 if (spvOperandTableNameLookup(env, operandTable, type, begin, end - begin,
David Netofcc7d582015-10-27 15:31:10 -040065 &entry)) {
66 return SPV_ERROR_INVALID_TEXT;
67 }
68 value |= entry->value;
69
70 // Advance to the next word by skipping over the separator.
71 begin = end + 1;
72 } while (end != text_end);
73
74 *pValue = value;
75 return SPV_SUCCESS;
76}
David Neto0ca6b592015-10-30 16:06:15 -040077
David Neto0f166be2015-11-11 01:56:49 -050078// Associates an opcode with its name.
79struct SpecConstantOpcodeEntry {
80 SpvOp opcode;
81 const char* name;
82};
83
84// All the opcodes allowed as the operation for OpSpecConstantOp.
85// The name does not have the usual "Op" prefix. For example opcode SpvOpIAdd
86// is associated with the name "IAdd".
87//
88// clang-format off
89#define CASE(NAME) { SpvOp##NAME, #NAME }
90const SpecConstantOpcodeEntry kOpSpecConstantOpcodes[] = {
91 // Conversion
92 CASE(SConvert),
93 CASE(FConvert),
94 CASE(ConvertFToS),
95 CASE(ConvertSToF),
96 CASE(ConvertFToU),
97 CASE(ConvertUToF),
98 CASE(UConvert),
99 CASE(ConvertPtrToU),
100 CASE(ConvertUToPtr),
David Neto969ce4b2016-01-05 18:22:22 -0500101 CASE(GenericCastToPtr),
David Neto0f166be2015-11-11 01:56:49 -0500102 CASE(PtrCastToGeneric),
103 CASE(Bitcast),
104 CASE(QuantizeToF16),
105 // Arithmetic
106 CASE(SNegate),
107 CASE(Not),
108 CASE(IAdd),
109 CASE(ISub),
110 CASE(IMul),
111 CASE(UDiv),
112 CASE(SDiv),
113 CASE(UMod),
114 CASE(SRem),
115 CASE(SMod),
116 CASE(ShiftRightLogical),
117 CASE(ShiftRightArithmetic),
118 CASE(ShiftLeftLogical),
119 CASE(BitwiseOr),
120 CASE(BitwiseAnd),
David Neto969ce4b2016-01-05 18:22:22 -0500121 CASE(BitwiseXor),
David Neto0f166be2015-11-11 01:56:49 -0500122 CASE(FNegate),
123 CASE(FAdd),
124 CASE(FSub),
125 CASE(FMul),
126 CASE(FDiv),
127 CASE(FRem),
128 CASE(FMod),
129 // Composite
130 CASE(VectorShuffle),
131 CASE(CompositeExtract),
132 CASE(CompositeInsert),
133 // Logical
134 CASE(LogicalOr),
135 CASE(LogicalAnd),
136 CASE(LogicalNot),
137 CASE(LogicalEqual),
138 CASE(LogicalNotEqual),
139 CASE(Select),
140 // Comparison
141 CASE(IEqual),
qining256c56d2016-07-26 17:52:06 -0400142 CASE(INotEqual),
David Neto0f166be2015-11-11 01:56:49 -0500143 CASE(ULessThan),
144 CASE(SLessThan),
145 CASE(UGreaterThan),
146 CASE(SGreaterThan),
147 CASE(ULessThanEqual),
148 CASE(SLessThanEqual),
David Neto0f166be2015-11-11 01:56:49 -0500149 CASE(UGreaterThanEqual),
150 CASE(SGreaterThanEqual),
151 // Memory
152 CASE(AccessChain),
153 CASE(InBoundsAccessChain),
154 CASE(PtrAccessChain),
155 CASE(InBoundsPtrAccessChain),
156};
David Neto969ce4b2016-01-05 18:22:22 -0500157
qining256c56d2016-07-26 17:52:06 -0400158// The 59 is determined by counting the opcodes listed in the spec.
159static_assert(59 == sizeof(kOpSpecConstantOpcodes)/sizeof(kOpSpecConstantOpcodes[0]),
David Neto969ce4b2016-01-05 18:22:22 -0500160 "OpSpecConstantOp opcode table is incomplete");
David Neto0f166be2015-11-11 01:56:49 -0500161#undef CASE
162// clang-format on
163
164const size_t kNumOpSpecConstantOpcodes =
165 sizeof(kOpSpecConstantOpcodes) / sizeof(kOpSpecConstantOpcodes[0]);
166
David Netofcc7d582015-10-27 15:31:10 -0400167} // anonymous namespace
168
169namespace libspirv {
170
171bool AssemblyGrammar::isValid() const {
172 return operandTable_ && opcodeTable_ && extInstTable_;
173}
174
Lei Zhang1ef6b192018-03-14 13:06:18 -0400175CapabilitySet AssemblyGrammar::filterCapsAgainstTargetEnv(
176 const SpvCapability* cap_array, uint32_t count) const {
177 CapabilitySet cap_set;
178 for (uint32_t i = 0; i < count; ++i) {
179 spv_operand_desc cap_desc = {};
180 if (SPV_SUCCESS == lookupOperand(SPV_OPERAND_TYPE_CAPABILITY,
181 static_cast<uint32_t>(cap_array[i]),
182 &cap_desc)) {
183 // spvOperandTableValueLookup() filters capabilities internally
184 // according to the current target environment by itself. So we
185 // should be safe to add this capability if the lookup succeeds.
186 cap_set.Add(cap_array[i]);
187 }
188 }
189 return cap_set;
190}
191
Lei Zhang1a0334e2015-11-02 09:41:20 -0500192spv_result_t AssemblyGrammar::lookupOpcode(const char* name,
193 spv_opcode_desc* desc) const {
Lei Zhang1ef6b192018-03-14 13:06:18 -0400194 return spvOpcodeTableNameLookup(target_env_, opcodeTable_, name, desc);
David Netofcc7d582015-10-27 15:31:10 -0400195}
196
Lei Zhangb36e7042015-10-28 13:40:52 -0400197spv_result_t AssemblyGrammar::lookupOpcode(SpvOp opcode,
Lei Zhang1a0334e2015-11-02 09:41:20 -0500198 spv_opcode_desc* desc) const {
Lei Zhang1ef6b192018-03-14 13:06:18 -0400199 return spvOpcodeTableValueLookup(target_env_, opcodeTable_, opcode, desc);
David Netofcc7d582015-10-27 15:31:10 -0400200}
201
202spv_result_t AssemblyGrammar::lookupOperand(spv_operand_type_t type,
Lei Zhang1a0334e2015-11-02 09:41:20 -0500203 const char* name, size_t name_len,
204 spv_operand_desc* desc) const {
Lei Zhang1ef6b192018-03-14 13:06:18 -0400205 return spvOperandTableNameLookup(target_env_, operandTable_, type, name,
206 name_len, desc);
David Netofcc7d582015-10-27 15:31:10 -0400207}
208
209spv_result_t AssemblyGrammar::lookupOperand(spv_operand_type_t type,
210 uint32_t operand,
Lei Zhang1a0334e2015-11-02 09:41:20 -0500211 spv_operand_desc* desc) const {
Lei Zhang1ef6b192018-03-14 13:06:18 -0400212 return spvOperandTableValueLookup(target_env_, operandTable_, type, operand,
213 desc);
David Netofcc7d582015-10-27 15:31:10 -0400214}
215
David Neto0f166be2015-11-11 01:56:49 -0500216spv_result_t AssemblyGrammar::lookupSpecConstantOpcode(const char* name,
217 SpvOp* opcode) const {
218 const auto* last = kOpSpecConstantOpcodes + kNumOpSpecConstantOpcodes;
219 const auto* found =
220 std::find_if(kOpSpecConstantOpcodes, last,
221 [name](const SpecConstantOpcodeEntry& entry) {
222 return 0 == strcmp(name, entry.name);
223 });
224 if (found == last) return SPV_ERROR_INVALID_LOOKUP;
225 *opcode = found->opcode;
226 return SPV_SUCCESS;
227}
228
David Neto21196942015-11-11 02:45:45 -0500229spv_result_t AssemblyGrammar::lookupSpecConstantOpcode(SpvOp opcode) const {
230 const auto* last = kOpSpecConstantOpcodes + kNumOpSpecConstantOpcodes;
231 const auto* found =
232 std::find_if(kOpSpecConstantOpcodes, last,
233 [opcode](const SpecConstantOpcodeEntry& entry) {
234 return opcode == entry.opcode;
235 });
236 if (found == last) return SPV_ERROR_INVALID_LOOKUP;
237 return SPV_SUCCESS;
238}
239
David Netofcc7d582015-10-27 15:31:10 -0400240spv_result_t AssemblyGrammar::parseMaskOperand(const spv_operand_type_t type,
Lei Zhang1a0334e2015-11-02 09:41:20 -0500241 const char* textValue,
242 uint32_t* pValue) const {
Lei Zhang1ef6b192018-03-14 13:06:18 -0400243 return spvTextParseMaskOperand(target_env_, operandTable_, type, textValue,
244 pValue);
David Netofcc7d582015-10-27 15:31:10 -0400245}
246spv_result_t AssemblyGrammar::lookupExtInst(spv_ext_inst_type_t type,
Lei Zhang1a0334e2015-11-02 09:41:20 -0500247 const char* textValue,
248 spv_ext_inst_desc* extInst) const {
David Netofcc7d582015-10-27 15:31:10 -0400249 return spvExtInstTableNameLookup(extInstTable_, type, textValue, extInst);
250}
251
252spv_result_t AssemblyGrammar::lookupExtInst(spv_ext_inst_type_t type,
253 uint32_t firstWord,
Lei Zhang1a0334e2015-11-02 09:41:20 -0500254 spv_ext_inst_desc* extInst) const {
David Netofcc7d582015-10-27 15:31:10 -0400255 return spvExtInstTableValueLookup(extInstTable_, type, firstWord, extInst);
256}
257
Chris Forbes78338d52017-06-27 16:28:22 -0700258void AssemblyGrammar::pushOperandTypesForMask(
David Netofcc7d582015-10-27 15:31:10 -0400259 const spv_operand_type_t type, const uint32_t mask,
Lei Zhang1a0334e2015-11-02 09:41:20 -0500260 spv_operand_pattern_t* pattern) const {
Lei Zhang1ef6b192018-03-14 13:06:18 -0400261 spvPushOperandTypesForMask(target_env_, operandTable_, type, mask, pattern);
David Netofcc7d582015-10-27 15:31:10 -0400262}
263} // namespace libspirv