Roll external/abseil_cpp/ 8f739d18b..917bfee46 (2 commits) (#5887)
[KhronosGroup/SPIRV-Tools.git] / source / assembly_grammar.cpp
blob0092d01a50038afb4318af3350d466d0ac918569
1 // Copyright (c) 2015-2016 The Khronos Group Inc.
2 //
3 // 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
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // 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.
15 #include "source/assembly_grammar.h"
17 #include <algorithm>
18 #include <cassert>
19 #include <cstring>
21 #include "source/ext_inst.h"
22 #include "source/opcode.h"
23 #include "source/operand.h"
24 #include "source/spirv_target_env.h"
25 #include "source/table.h"
27 namespace spvtools {
28 namespace {
30 /// @brief Parses a mask expression string for the given operand type.
31 ///
32 /// A mask expression is a sequence of one or more terms separated by '|',
33 /// where each term a named enum value for the given type. No whitespace
34 /// is permitted.
35 ///
36 /// On success, the value is written to pValue.
37 ///
38 /// @param[in] operandTable operand lookup table
39 /// @param[in] type of the operand
40 /// @param[in] textValue word of text to be parsed
41 /// @param[out] pValue where the resulting value is written
42 ///
43 /// @return result code
44 spv_result_t spvTextParseMaskOperand(spv_target_env env,
45 const spv_operand_table operandTable,
46 const spv_operand_type_t type,
47 const char* textValue, uint32_t* pValue) {
48 if (textValue == nullptr) return SPV_ERROR_INVALID_TEXT;
49 size_t text_length = strlen(textValue);
50 if (text_length == 0) return SPV_ERROR_INVALID_TEXT;
51 const char* text_end = textValue + text_length;
53 // We only support mask expressions in ASCII, so the separator value is a
54 // char.
55 const char separator = '|';
57 // Accumulate the result by interpreting one word at a time, scanning
58 // from left to right.
59 uint32_t value = 0;
60 const char* begin = textValue; // The left end of the current word.
61 const char* end = nullptr; // One character past the end of the current word.
62 do {
63 end = std::find(begin, text_end, separator);
65 spv_operand_desc entry = nullptr;
66 if (auto error = spvOperandTableNameLookup(env, operandTable, type, begin,
67 end - begin, &entry)) {
68 return error;
70 value |= entry->value;
72 // Advance to the next word by skipping over the separator.
73 begin = end + 1;
74 } while (end != text_end);
76 *pValue = value;
77 return SPV_SUCCESS;
80 // Associates an opcode with its name.
81 struct SpecConstantOpcodeEntry {
82 spv::Op opcode;
83 const char* name;
86 // All the opcodes allowed as the operation for OpSpecConstantOp.
87 // The name does not have the usual "Op" prefix. For example opcode
88 // spv::Op::IAdd is associated with the name "IAdd".
90 // clang-format off
91 #define CASE(NAME) { spv::Op::Op##NAME, #NAME }
92 const SpecConstantOpcodeEntry kOpSpecConstantOpcodes[] = {
93 // Conversion
94 CASE(SConvert),
95 CASE(FConvert),
96 CASE(ConvertFToS),
97 CASE(ConvertSToF),
98 CASE(ConvertFToU),
99 CASE(ConvertUToF),
100 CASE(UConvert),
101 CASE(ConvertPtrToU),
102 CASE(ConvertUToPtr),
103 CASE(GenericCastToPtr),
104 CASE(PtrCastToGeneric),
105 CASE(Bitcast),
106 CASE(QuantizeToF16),
107 // Arithmetic
108 CASE(SNegate),
109 CASE(Not),
110 CASE(IAdd),
111 CASE(ISub),
112 CASE(IMul),
113 CASE(UDiv),
114 CASE(SDiv),
115 CASE(UMod),
116 CASE(SRem),
117 CASE(SMod),
118 CASE(ShiftRightLogical),
119 CASE(ShiftRightArithmetic),
120 CASE(ShiftLeftLogical),
121 CASE(BitwiseOr),
122 CASE(BitwiseAnd),
123 CASE(BitwiseXor),
124 CASE(FNegate),
125 CASE(FAdd),
126 CASE(FSub),
127 CASE(FMul),
128 CASE(FDiv),
129 CASE(FRem),
130 CASE(FMod),
131 // Composite
132 CASE(VectorShuffle),
133 CASE(CompositeExtract),
134 CASE(CompositeInsert),
135 // Logical
136 CASE(LogicalOr),
137 CASE(LogicalAnd),
138 CASE(LogicalNot),
139 CASE(LogicalEqual),
140 CASE(LogicalNotEqual),
141 CASE(Select),
142 // Comparison
143 CASE(IEqual),
144 CASE(INotEqual),
145 CASE(ULessThan),
146 CASE(SLessThan),
147 CASE(UGreaterThan),
148 CASE(SGreaterThan),
149 CASE(ULessThanEqual),
150 CASE(SLessThanEqual),
151 CASE(UGreaterThanEqual),
152 CASE(SGreaterThanEqual),
153 // Memory
154 CASE(AccessChain),
155 CASE(InBoundsAccessChain),
156 CASE(PtrAccessChain),
157 CASE(InBoundsPtrAccessChain),
158 CASE(CooperativeMatrixLengthNV),
159 CASE(CooperativeMatrixLengthKHR)
162 // The 60 is determined by counting the opcodes listed in the spec.
163 static_assert(61 == sizeof(kOpSpecConstantOpcodes)/sizeof(kOpSpecConstantOpcodes[0]),
164 "OpSpecConstantOp opcode table is incomplete");
165 #undef CASE
166 // clang-format on
168 const size_t kNumOpSpecConstantOpcodes =
169 sizeof(kOpSpecConstantOpcodes) / sizeof(kOpSpecConstantOpcodes[0]);
171 } // namespace
173 bool AssemblyGrammar::isValid() const {
174 return operandTable_ && opcodeTable_ && extInstTable_;
177 CapabilitySet AssemblyGrammar::filterCapsAgainstTargetEnv(
178 const spv::Capability* cap_array, uint32_t count) const {
179 CapabilitySet cap_set;
180 const auto version = spvVersionForTargetEnv(target_env_);
181 for (uint32_t i = 0; i < count; ++i) {
182 spv_operand_desc entry = {};
183 if (SPV_SUCCESS == lookupOperand(SPV_OPERAND_TYPE_CAPABILITY,
184 static_cast<uint32_t>(cap_array[i]),
185 &entry)) {
186 // This token is visible in this environment if it's in an appropriate
187 // core version, or it is enabled by a capability or an extension.
188 if ((version >= entry->minVersion && version <= entry->lastVersion) ||
189 entry->numExtensions > 0u || entry->numCapabilities > 0u) {
190 cap_set.insert(cap_array[i]);
194 return cap_set;
197 spv_result_t AssemblyGrammar::lookupOpcode(const char* name,
198 spv_opcode_desc* desc) const {
199 return spvOpcodeTableNameLookup(target_env_, opcodeTable_, name, desc);
202 spv_result_t AssemblyGrammar::lookupOpcode(spv::Op opcode,
203 spv_opcode_desc* desc) const {
204 return spvOpcodeTableValueLookup(target_env_, opcodeTable_, opcode, desc);
207 spv_result_t AssemblyGrammar::lookupOperand(spv_operand_type_t type,
208 const char* name, size_t name_len,
209 spv_operand_desc* desc) const {
210 return spvOperandTableNameLookup(target_env_, operandTable_, type, name,
211 name_len, desc);
214 spv_result_t AssemblyGrammar::lookupOperand(spv_operand_type_t type,
215 uint32_t operand,
216 spv_operand_desc* desc) const {
217 return spvOperandTableValueLookup(target_env_, operandTable_, type, operand,
218 desc);
221 spv_result_t AssemblyGrammar::lookupSpecConstantOpcode(const char* name,
222 spv::Op* opcode) const {
223 const auto* last = kOpSpecConstantOpcodes + kNumOpSpecConstantOpcodes;
224 const auto* found =
225 std::find_if(kOpSpecConstantOpcodes, last,
226 [name](const SpecConstantOpcodeEntry& entry) {
227 return 0 == strcmp(name, entry.name);
229 if (found == last) return SPV_ERROR_INVALID_LOOKUP;
230 *opcode = found->opcode;
231 return SPV_SUCCESS;
234 spv_result_t AssemblyGrammar::lookupSpecConstantOpcode(spv::Op opcode) const {
235 const auto* last = kOpSpecConstantOpcodes + kNumOpSpecConstantOpcodes;
236 const auto* found =
237 std::find_if(kOpSpecConstantOpcodes, last,
238 [opcode](const SpecConstantOpcodeEntry& entry) {
239 return opcode == entry.opcode;
241 if (found == last) return SPV_ERROR_INVALID_LOOKUP;
242 return SPV_SUCCESS;
245 spv_result_t AssemblyGrammar::parseMaskOperand(const spv_operand_type_t type,
246 const char* textValue,
247 uint32_t* pValue) const {
248 return spvTextParseMaskOperand(target_env_, operandTable_, type, textValue,
249 pValue);
251 spv_result_t AssemblyGrammar::lookupExtInst(spv_ext_inst_type_t type,
252 const char* textValue,
253 spv_ext_inst_desc* extInst) const {
254 return spvExtInstTableNameLookup(extInstTable_, type, textValue, extInst);
257 spv_result_t AssemblyGrammar::lookupExtInst(spv_ext_inst_type_t type,
258 uint32_t firstWord,
259 spv_ext_inst_desc* extInst) const {
260 return spvExtInstTableValueLookup(extInstTable_, type, firstWord, extInst);
263 void AssemblyGrammar::pushOperandTypesForMask(
264 const spv_operand_type_t type, const uint32_t mask,
265 spv_operand_pattern_t* pattern) const {
266 spvPushOperandTypesForMask(target_env_, operandTable_, type, mask, pattern);
269 } // namespace spvtools