123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264 |
- // Copyright (c) 2015-2016 The Khronos Group Inc.
- //
- // Licensed under the Apache License, Version 2.0 (the "License");
- // you may not use this file except in compliance with the License.
- // You may obtain a copy of the License at
- //
- // http://www.apache.org/licenses/LICENSE-2.0
- //
- // Unless required by applicable law or agreed to in writing, software
- // distributed under the License is distributed on an "AS IS" BASIS,
- // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- // See the License for the specific language governing permissions and
- // limitations under the License.
- #include "source/assembly_grammar.h"
- #include <algorithm>
- #include <cassert>
- #include <cstring>
- #include "source/ext_inst.h"
- #include "source/opcode.h"
- #include "source/operand.h"
- #include "source/table.h"
- namespace spvtools {
- namespace {
- /// @brief Parses a mask expression string for the given operand type.
- ///
- /// A mask expression is a sequence of one or more terms separated by '|',
- /// where each term a named enum value for the given type. No whitespace
- /// is permitted.
- ///
- /// On success, the value is written to pValue.
- ///
- /// @param[in] operandTable operand lookup table
- /// @param[in] type of the operand
- /// @param[in] textValue word of text to be parsed
- /// @param[out] pValue where the resulting value is written
- ///
- /// @return result code
- spv_result_t spvTextParseMaskOperand(spv_target_env env,
- const spv_operand_table operandTable,
- const spv_operand_type_t type,
- const char* textValue, uint32_t* pValue) {
- if (textValue == nullptr) return SPV_ERROR_INVALID_TEXT;
- size_t text_length = strlen(textValue);
- if (text_length == 0) return SPV_ERROR_INVALID_TEXT;
- const char* text_end = textValue + text_length;
- // We only support mask expressions in ASCII, so the separator value is a
- // char.
- const char separator = '|';
- // Accumulate the result by interpreting one word at a time, scanning
- // from left to right.
- uint32_t value = 0;
- const char* begin = textValue; // The left end of the current word.
- const char* end = nullptr; // One character past the end of the current word.
- do {
- end = std::find(begin, text_end, separator);
- spv_operand_desc entry = nullptr;
- if (spvOperandTableNameLookup(env, operandTable, type, begin, end - begin,
- &entry)) {
- return SPV_ERROR_INVALID_TEXT;
- }
- value |= entry->value;
- // Advance to the next word by skipping over the separator.
- begin = end + 1;
- } while (end != text_end);
- *pValue = value;
- return SPV_SUCCESS;
- }
- // Associates an opcode with its name.
- struct SpecConstantOpcodeEntry {
- SpvOp opcode;
- const char* name;
- };
- // All the opcodes allowed as the operation for OpSpecConstantOp.
- // The name does not have the usual "Op" prefix. For example opcode SpvOpIAdd
- // is associated with the name "IAdd".
- //
- // clang-format off
- #define CASE(NAME) { SpvOp##NAME, #NAME }
- const SpecConstantOpcodeEntry kOpSpecConstantOpcodes[] = {
- // Conversion
- CASE(SConvert),
- CASE(FConvert),
- CASE(ConvertFToS),
- CASE(ConvertSToF),
- CASE(ConvertFToU),
- CASE(ConvertUToF),
- CASE(UConvert),
- CASE(ConvertPtrToU),
- CASE(ConvertUToPtr),
- CASE(GenericCastToPtr),
- CASE(PtrCastToGeneric),
- CASE(Bitcast),
- CASE(QuantizeToF16),
- // Arithmetic
- CASE(SNegate),
- CASE(Not),
- CASE(IAdd),
- CASE(ISub),
- CASE(IMul),
- CASE(UDiv),
- CASE(SDiv),
- CASE(UMod),
- CASE(SRem),
- CASE(SMod),
- CASE(ShiftRightLogical),
- CASE(ShiftRightArithmetic),
- CASE(ShiftLeftLogical),
- CASE(BitwiseOr),
- CASE(BitwiseAnd),
- CASE(BitwiseXor),
- CASE(FNegate),
- CASE(FAdd),
- CASE(FSub),
- CASE(FMul),
- CASE(FDiv),
- CASE(FRem),
- CASE(FMod),
- // Composite
- CASE(VectorShuffle),
- CASE(CompositeExtract),
- CASE(CompositeInsert),
- // Logical
- CASE(LogicalOr),
- CASE(LogicalAnd),
- CASE(LogicalNot),
- CASE(LogicalEqual),
- CASE(LogicalNotEqual),
- CASE(Select),
- // Comparison
- CASE(IEqual),
- CASE(INotEqual),
- CASE(ULessThan),
- CASE(SLessThan),
- CASE(UGreaterThan),
- CASE(SGreaterThan),
- CASE(ULessThanEqual),
- CASE(SLessThanEqual),
- CASE(UGreaterThanEqual),
- CASE(SGreaterThanEqual),
- // Memory
- CASE(AccessChain),
- CASE(InBoundsAccessChain),
- CASE(PtrAccessChain),
- CASE(InBoundsPtrAccessChain),
- };
- // The 59 is determined by counting the opcodes listed in the spec.
- static_assert(59 == sizeof(kOpSpecConstantOpcodes)/sizeof(kOpSpecConstantOpcodes[0]),
- "OpSpecConstantOp opcode table is incomplete");
- #undef CASE
- // clang-format on
- const size_t kNumOpSpecConstantOpcodes =
- sizeof(kOpSpecConstantOpcodes) / sizeof(kOpSpecConstantOpcodes[0]);
- } // namespace
- bool AssemblyGrammar::isValid() const {
- return operandTable_ && opcodeTable_ && extInstTable_;
- }
- CapabilitySet AssemblyGrammar::filterCapsAgainstTargetEnv(
- const SpvCapability* cap_array, uint32_t count) const {
- CapabilitySet cap_set;
- for (uint32_t i = 0; i < count; ++i) {
- spv_operand_desc cap_desc = {};
- if (SPV_SUCCESS == lookupOperand(SPV_OPERAND_TYPE_CAPABILITY,
- static_cast<uint32_t>(cap_array[i]),
- &cap_desc)) {
- // spvOperandTableValueLookup() filters capabilities internally
- // according to the current target environment by itself. So we
- // should be safe to add this capability if the lookup succeeds.
- cap_set.Add(cap_array[i]);
- }
- }
- return cap_set;
- }
- spv_result_t AssemblyGrammar::lookupOpcode(const char* name,
- spv_opcode_desc* desc) const {
- return spvOpcodeTableNameLookup(target_env_, opcodeTable_, name, desc);
- }
- spv_result_t AssemblyGrammar::lookupOpcode(SpvOp opcode,
- spv_opcode_desc* desc) const {
- return spvOpcodeTableValueLookup(target_env_, opcodeTable_, opcode, desc);
- }
- spv_result_t AssemblyGrammar::lookupOperand(spv_operand_type_t type,
- const char* name, size_t name_len,
- spv_operand_desc* desc) const {
- return spvOperandTableNameLookup(target_env_, operandTable_, type, name,
- name_len, desc);
- }
- spv_result_t AssemblyGrammar::lookupOperand(spv_operand_type_t type,
- uint32_t operand,
- spv_operand_desc* desc) const {
- return spvOperandTableValueLookup(target_env_, operandTable_, type, operand,
- desc);
- }
- spv_result_t AssemblyGrammar::lookupSpecConstantOpcode(const char* name,
- SpvOp* opcode) const {
- const auto* last = kOpSpecConstantOpcodes + kNumOpSpecConstantOpcodes;
- const auto* found =
- std::find_if(kOpSpecConstantOpcodes, last,
- [name](const SpecConstantOpcodeEntry& entry) {
- return 0 == strcmp(name, entry.name);
- });
- if (found == last) return SPV_ERROR_INVALID_LOOKUP;
- *opcode = found->opcode;
- return SPV_SUCCESS;
- }
- spv_result_t AssemblyGrammar::lookupSpecConstantOpcode(SpvOp opcode) const {
- const auto* last = kOpSpecConstantOpcodes + kNumOpSpecConstantOpcodes;
- const auto* found =
- std::find_if(kOpSpecConstantOpcodes, last,
- [opcode](const SpecConstantOpcodeEntry& entry) {
- return opcode == entry.opcode;
- });
- if (found == last) return SPV_ERROR_INVALID_LOOKUP;
- return SPV_SUCCESS;
- }
- spv_result_t AssemblyGrammar::parseMaskOperand(const spv_operand_type_t type,
- const char* textValue,
- uint32_t* pValue) const {
- return spvTextParseMaskOperand(target_env_, operandTable_, type, textValue,
- pValue);
- }
- spv_result_t AssemblyGrammar::lookupExtInst(spv_ext_inst_type_t type,
- const char* textValue,
- spv_ext_inst_desc* extInst) const {
- return spvExtInstTableNameLookup(extInstTable_, type, textValue, extInst);
- }
- spv_result_t AssemblyGrammar::lookupExtInst(spv_ext_inst_type_t type,
- uint32_t firstWord,
- spv_ext_inst_desc* extInst) const {
- return spvExtInstTableValueLookup(extInstTable_, type, firstWord, extInst);
- }
- void AssemblyGrammar::pushOperandTypesForMask(
- const spv_operand_type_t type, const uint32_t mask,
- spv_operand_pattern_t* pattern) const {
- spvPushOperandTypesForMask(target_env_, operandTable_, type, mask, pattern);
- }
- } // namespace spvtools
|