1 // Copyright (c) 2015-2016 The Khronos Group Inc.
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
7 // http://www.apache.org/licenses/LICENSE-2.0
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"
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"
30 /// @brief Parses a mask expression string for the given operand type.
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
36 /// On success, the value is written to pValue.
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
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
55 const char separator
= '|';
57 // Accumulate the result by interpreting one word at a time, scanning
58 // from left to right.
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.
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
)) {
70 value
|= entry
->value
;
72 // Advance to the next word by skipping over the separator.
74 } while (end
!= text_end
);
80 // Associates an opcode with its name.
81 struct SpecConstantOpcodeEntry
{
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".
91 #define CASE(NAME) { spv::Op::Op##NAME, #NAME }
92 const SpecConstantOpcodeEntry kOpSpecConstantOpcodes
[] = {
103 CASE(GenericCastToPtr
),
104 CASE(PtrCastToGeneric
),
118 CASE(ShiftRightLogical
),
119 CASE(ShiftRightArithmetic
),
120 CASE(ShiftLeftLogical
),
133 CASE(CompositeExtract
),
134 CASE(CompositeInsert
),
140 CASE(LogicalNotEqual
),
149 CASE(ULessThanEqual
),
150 CASE(SLessThanEqual
),
151 CASE(UGreaterThanEqual
),
152 CASE(SGreaterThanEqual
),
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");
168 const size_t kNumOpSpecConstantOpcodes
=
169 sizeof(kOpSpecConstantOpcodes
) / sizeof(kOpSpecConstantOpcodes
[0]);
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
]),
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
]);
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
,
214 spv_result_t
AssemblyGrammar::lookupOperand(spv_operand_type_t type
,
216 spv_operand_desc
* desc
) const {
217 return spvOperandTableValueLookup(target_env_
, operandTable_
, type
, operand
,
221 spv_result_t
AssemblyGrammar::lookupSpecConstantOpcode(const char* name
,
222 spv::Op
* opcode
) const {
223 const auto* last
= kOpSpecConstantOpcodes
+ kNumOpSpecConstantOpcodes
;
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
;
234 spv_result_t
AssemblyGrammar::lookupSpecConstantOpcode(spv::Op opcode
) const {
235 const auto* last
= kOpSpecConstantOpcodes
+ kNumOpSpecConstantOpcodes
;
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
;
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
,
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
,
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