| // Copyright (c) 2018 Google LLC | |
| // | |
| // 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. | |
| // MARK-V is a compression format for SPIR-V binaries. It strips away | |
| // non-essential information (such as result IDs which can be regenerated) and | |
| // uses various bit reduction techniques to reduce the size of the binary. | |
| #include "source/comp/markv_codec.h" | |
| #include "source/comp/markv_logger.h" | |
| #include "source/latest_version_glsl_std_450_header.h" | |
| #include "source/latest_version_opencl_std_header.h" | |
| #include "source/opcode.h" | |
| #include "source/util/make_unique.h" | |
| namespace spvtools { | |
| namespace comp { | |
| namespace { | |
| // Custom hash function used to produce short descriptors. | |
| uint32_t ShortHashU32Array(const std::vector<uint32_t>& words) { | |
| // The hash function is a sum of hashes of each word seeded by word index. | |
| // Knuth's multiplicative hash is used to hash the words. | |
| const uint32_t kKnuthMulHash = 2654435761; | |
| uint32_t val = 0; | |
| for (uint32_t i = 0; i < words.size(); ++i) { | |
| val += (words[i] + i + 123) * kKnuthMulHash; | |
| } | |
| return 1 + val % ((1 << MarkvCodec::kShortDescriptorNumBits) - 1); | |
| } | |
| // Returns a set of mtf rank codecs based on a plausible hand-coded | |
| // distribution. | |
| std::map<uint64_t, std::unique_ptr<HuffmanCodec<uint32_t>>> | |
| GetMtfHuffmanCodecs() { | |
| std::map<uint64_t, std::unique_ptr<HuffmanCodec<uint32_t>>> codecs; | |
| std::unique_ptr<HuffmanCodec<uint32_t>> codec; | |
| codec = MakeUnique<HuffmanCodec<uint32_t>>(std::map<uint32_t, uint32_t>({ | |
| {0, 5}, | |
| {1, 40}, | |
| {2, 10}, | |
| {3, 5}, | |
| {4, 5}, | |
| {5, 5}, | |
| {6, 3}, | |
| {7, 3}, | |
| {8, 3}, | |
| {9, 3}, | |
| {MarkvCodec::kMtfRankEncodedByValueSignal, 10}, | |
| })); | |
| codecs.emplace(kMtfAll, std::move(codec)); | |
| codec = MakeUnique<HuffmanCodec<uint32_t>>(std::map<uint32_t, uint32_t>({ | |
| {1, 50}, | |
| {2, 20}, | |
| {3, 5}, | |
| {4, 5}, | |
| {5, 2}, | |
| {6, 1}, | |
| {7, 1}, | |
| {8, 1}, | |
| {9, 1}, | |
| {MarkvCodec::kMtfRankEncodedByValueSignal, 10}, | |
| })); | |
| codecs.emplace(kMtfGenericNonZeroRank, std::move(codec)); | |
| return codecs; | |
| } | |
| } // namespace | |
| const uint32_t MarkvCodec::kMarkvMagicNumber = 0x07230303; | |
| const uint32_t MarkvCodec::kMtfSmallestRankEncodedByValue = 10; | |
| const uint32_t MarkvCodec::kMtfRankEncodedByValueSignal = | |
| std::numeric_limits<uint32_t>::max(); | |
| const uint32_t MarkvCodec::kShortDescriptorNumBits = 8; | |
| const size_t MarkvCodec::kByteBreakAfterInstIfLessThanUntilNextByte = 8; | |
| MarkvCodec::MarkvCodec(spv_const_context context, | |
| spv_validator_options validator_options, | |
| const MarkvModel* model) | |
| : validator_options_(validator_options), | |
| grammar_(context), | |
| model_(model), | |
| short_id_descriptors_(ShortHashU32Array), | |
| mtf_huffman_codecs_(GetMtfHuffmanCodecs()), | |
| context_(context) {} | |
| MarkvCodec::~MarkvCodec() { spvValidatorOptionsDestroy(validator_options_); } | |
| MarkvCodec::MarkvHeader::MarkvHeader() | |
| : magic_number(MarkvCodec::kMarkvMagicNumber), | |
| markv_version(MarkvCodec::GetMarkvVersion()) {} | |
| // Defines and returns current MARK-V version. | |
| // static | |
| uint32_t MarkvCodec::GetMarkvVersion() { | |
| const uint32_t kVersionMajor = 1; | |
| const uint32_t kVersionMinor = 4; | |
| return kVersionMinor | (kVersionMajor << 16); | |
| } | |
| size_t MarkvCodec::GetNumBitsToNextByte(size_t bit_pos) const { | |
| return (8 - (bit_pos % 8)) % 8; | |
| } | |
| // Returns true if the opcode has a fixed number of operands. May return a | |
| // false negative. | |
| bool MarkvCodec::OpcodeHasFixedNumberOfOperands(SpvOp opcode) const { | |
| switch (opcode) { | |
| // TODO(atgoo@github.com) This is not a complete list. | |
| case SpvOpNop: | |
| case SpvOpName: | |
| case SpvOpUndef: | |
| case SpvOpSizeOf: | |
| case SpvOpLine: | |
| case SpvOpNoLine: | |
| case SpvOpDecorationGroup: | |
| case SpvOpExtension: | |
| case SpvOpExtInstImport: | |
| case SpvOpMemoryModel: | |
| case SpvOpCapability: | |
| case SpvOpTypeVoid: | |
| case SpvOpTypeBool: | |
| case SpvOpTypeInt: | |
| case SpvOpTypeFloat: | |
| case SpvOpTypeVector: | |
| case SpvOpTypeMatrix: | |
| case SpvOpTypeSampler: | |
| case SpvOpTypeSampledImage: | |
| case SpvOpTypeArray: | |
| case SpvOpTypePointer: | |
| case SpvOpConstantTrue: | |
| case SpvOpConstantFalse: | |
| case SpvOpLabel: | |
| case SpvOpBranch: | |
| case SpvOpFunction: | |
| case SpvOpFunctionParameter: | |
| case SpvOpFunctionEnd: | |
| case SpvOpBitcast: | |
| case SpvOpCopyObject: | |
| case SpvOpTranspose: | |
| case SpvOpSNegate: | |
| case SpvOpFNegate: | |
| case SpvOpIAdd: | |
| case SpvOpFAdd: | |
| case SpvOpISub: | |
| case SpvOpFSub: | |
| case SpvOpIMul: | |
| case SpvOpFMul: | |
| case SpvOpUDiv: | |
| case SpvOpSDiv: | |
| case SpvOpFDiv: | |
| case SpvOpUMod: | |
| case SpvOpSRem: | |
| case SpvOpSMod: | |
| case SpvOpFRem: | |
| case SpvOpFMod: | |
| case SpvOpVectorTimesScalar: | |
| case SpvOpMatrixTimesScalar: | |
| case SpvOpVectorTimesMatrix: | |
| case SpvOpMatrixTimesVector: | |
| case SpvOpMatrixTimesMatrix: | |
| case SpvOpOuterProduct: | |
| case SpvOpDot: | |
| return true; | |
| default: | |
| break; | |
| } | |
| return false; | |
| } | |
| void MarkvCodec::ProcessCurInstruction() { | |
| instructions_.emplace_back(new val::Instruction(&inst_)); | |
| const SpvOp opcode = SpvOp(inst_.opcode); | |
| if (inst_.result_id) { | |
| id_to_def_instruction_.emplace(inst_.result_id, instructions_.back().get()); | |
| // Collect ids local to the current function. | |
| if (cur_function_id_) { | |
| ids_local_to_cur_function_.push_back(inst_.result_id); | |
| } | |
| // Starting new function. | |
| if (opcode == SpvOpFunction) { | |
| cur_function_id_ = inst_.result_id; | |
| cur_function_return_type_ = inst_.type_id; | |
| if (model_->id_fallback_strategy() == | |
| MarkvModel::IdFallbackStrategy::kRuleBased) { | |
| multi_mtf_.Insert(GetMtfFunctionWithReturnType(inst_.type_id), | |
| inst_.result_id); | |
| } | |
| // Store function parameter types in a queue, so that we know which types | |
| // to expect in the following OpFunctionParameter instructions. | |
| const val::Instruction* def_inst = FindDef(inst_.words[4]); | |
| assert(def_inst); | |
| assert(def_inst->opcode() == SpvOpTypeFunction); | |
| for (uint32_t i = 3; i < def_inst->words().size(); ++i) { | |
| remaining_function_parameter_types_.push_back(def_inst->word(i)); | |
| } | |
| } | |
| } | |
| // Remove local ids from MTFs if function end. | |
| if (opcode == SpvOpFunctionEnd) { | |
| cur_function_id_ = 0; | |
| for (uint32_t id : ids_local_to_cur_function_) multi_mtf_.RemoveFromAll(id); | |
| ids_local_to_cur_function_.clear(); | |
| assert(remaining_function_parameter_types_.empty()); | |
| } | |
| if (!inst_.result_id) return; | |
| { | |
| // Save the result ID to type ID mapping. | |
| // In the grammar, type ID always appears before result ID. | |
| // A regular value maps to its type. Some instructions (e.g. OpLabel) | |
| // have no type Id, and will map to 0. The result Id for a | |
| // type-generating instruction (e.g. OpTypeInt) maps to itself. | |
| auto insertion_result = id_to_type_id_.emplace( | |
| inst_.result_id, spvOpcodeGeneratesType(SpvOp(inst_.opcode)) | |
| ? inst_.result_id | |
| : inst_.type_id); | |
| (void)insertion_result; | |
| assert(insertion_result.second); | |
| } | |
| // Add result_id to MTFs. | |
| if (model_->id_fallback_strategy() == | |
| MarkvModel::IdFallbackStrategy::kRuleBased) { | |
| switch (opcode) { | |
| case SpvOpTypeFloat: | |
| case SpvOpTypeInt: | |
| case SpvOpTypeBool: | |
| case SpvOpTypeVector: | |
| case SpvOpTypePointer: | |
| case SpvOpExtInstImport: | |
| case SpvOpTypeSampledImage: | |
| case SpvOpTypeImage: | |
| case SpvOpTypeSampler: | |
| multi_mtf_.Insert(GetMtfIdGeneratedByOpcode(opcode), inst_.result_id); | |
| break; | |
| default: | |
| break; | |
| } | |
| if (spvOpcodeIsComposite(opcode)) { | |
| multi_mtf_.Insert(kMtfTypeComposite, inst_.result_id); | |
| } | |
| if (opcode == SpvOpLabel) { | |
| multi_mtf_.InsertOrPromote(kMtfLabel, inst_.result_id); | |
| } | |
| if (opcode == SpvOpTypeInt) { | |
| multi_mtf_.Insert(kMtfTypeScalar, inst_.result_id); | |
| multi_mtf_.Insert(kMtfTypeIntScalarOrVector, inst_.result_id); | |
| } | |
| if (opcode == SpvOpTypeFloat) { | |
| multi_mtf_.Insert(kMtfTypeScalar, inst_.result_id); | |
| multi_mtf_.Insert(kMtfTypeFloatScalarOrVector, inst_.result_id); | |
| } | |
| if (opcode == SpvOpTypeBool) { | |
| multi_mtf_.Insert(kMtfTypeScalar, inst_.result_id); | |
| multi_mtf_.Insert(kMtfTypeBoolScalarOrVector, inst_.result_id); | |
| } | |
| if (opcode == SpvOpTypeVector) { | |
| const uint32_t component_type_id = inst_.words[2]; | |
| const uint32_t size = inst_.words[3]; | |
| if (multi_mtf_.HasValue(GetMtfIdGeneratedByOpcode(SpvOpTypeFloat), | |
| component_type_id)) { | |
| multi_mtf_.Insert(kMtfTypeFloatScalarOrVector, inst_.result_id); | |
| } else if (multi_mtf_.HasValue(GetMtfIdGeneratedByOpcode(SpvOpTypeInt), | |
| component_type_id)) { | |
| multi_mtf_.Insert(kMtfTypeIntScalarOrVector, inst_.result_id); | |
| } else if (multi_mtf_.HasValue(GetMtfIdGeneratedByOpcode(SpvOpTypeBool), | |
| component_type_id)) { | |
| multi_mtf_.Insert(kMtfTypeBoolScalarOrVector, inst_.result_id); | |
| } | |
| multi_mtf_.Insert(GetMtfTypeVectorOfSize(size), inst_.result_id); | |
| } | |
| if (inst_.opcode == SpvOpTypeFunction) { | |
| const uint32_t return_type = inst_.words[2]; | |
| multi_mtf_.Insert(kMtfTypeReturnedByFunction, return_type); | |
| multi_mtf_.Insert(GetMtfFunctionTypeWithReturnType(return_type), | |
| inst_.result_id); | |
| } | |
| if (inst_.type_id) { | |
| const val::Instruction* type_inst = FindDef(inst_.type_id); | |
| assert(type_inst); | |
| multi_mtf_.Insert(kMtfObject, inst_.result_id); | |
| multi_mtf_.Insert(GetMtfIdOfType(inst_.type_id), inst_.result_id); | |
| if (multi_mtf_.HasValue(kMtfTypeFloatScalarOrVector, inst_.type_id)) { | |
| multi_mtf_.Insert(kMtfFloatScalarOrVector, inst_.result_id); | |
| } | |
| if (multi_mtf_.HasValue(kMtfTypeIntScalarOrVector, inst_.type_id)) | |
| multi_mtf_.Insert(kMtfIntScalarOrVector, inst_.result_id); | |
| if (multi_mtf_.HasValue(kMtfTypeBoolScalarOrVector, inst_.type_id)) | |
| multi_mtf_.Insert(kMtfBoolScalarOrVector, inst_.result_id); | |
| if (multi_mtf_.HasValue(kMtfTypeComposite, inst_.type_id)) | |
| multi_mtf_.Insert(kMtfComposite, inst_.result_id); | |
| switch (type_inst->opcode()) { | |
| case SpvOpTypeInt: | |
| case SpvOpTypeBool: | |
| case SpvOpTypePointer: | |
| case SpvOpTypeVector: | |
| case SpvOpTypeImage: | |
| case SpvOpTypeSampledImage: | |
| case SpvOpTypeSampler: | |
| multi_mtf_.Insert( | |
| GetMtfIdWithTypeGeneratedByOpcode(type_inst->opcode()), | |
| inst_.result_id); | |
| break; | |
| default: | |
| break; | |
| } | |
| if (type_inst->opcode() == SpvOpTypeVector) { | |
| const uint32_t component_type = type_inst->word(2); | |
| multi_mtf_.Insert(GetMtfVectorOfComponentType(component_type), | |
| inst_.result_id); | |
| } | |
| if (type_inst->opcode() == SpvOpTypePointer) { | |
| assert(type_inst->operands().size() > 2); | |
| assert(type_inst->words().size() > type_inst->operands()[2].offset); | |
| const uint32_t data_type = | |
| type_inst->word(type_inst->operands()[2].offset); | |
| multi_mtf_.Insert(GetMtfPointerToType(data_type), inst_.result_id); | |
| if (multi_mtf_.HasValue(kMtfTypeComposite, data_type)) | |
| multi_mtf_.Insert(kMtfTypePointerToComposite, inst_.result_id); | |
| } | |
| } | |
| if (spvOpcodeGeneratesType(opcode)) { | |
| if (opcode != SpvOpTypeFunction) { | |
| multi_mtf_.Insert(kMtfTypeNonFunction, inst_.result_id); | |
| } | |
| } | |
| } | |
| if (model_->AnyDescriptorHasCodingScheme()) { | |
| const uint32_t long_descriptor = | |
| long_id_descriptors_.ProcessInstruction(inst_); | |
| if (model_->DescriptorHasCodingScheme(long_descriptor)) | |
| multi_mtf_.Insert(GetMtfLongIdDescriptor(long_descriptor), | |
| inst_.result_id); | |
| } | |
| if (model_->id_fallback_strategy() == | |
| MarkvModel::IdFallbackStrategy::kShortDescriptor) { | |
| const uint32_t short_descriptor = | |
| short_id_descriptors_.ProcessInstruction(inst_); | |
| multi_mtf_.Insert(GetMtfShortIdDescriptor(short_descriptor), | |
| inst_.result_id); | |
| } | |
| } | |
| uint64_t MarkvCodec::GetRuleBasedMtf() { | |
| // This function is only called for id operands (but not result ids). | |
| assert(spvIsIdType(operand_.type) || | |
| operand_.type == SPV_OPERAND_TYPE_OPTIONAL_ID); | |
| assert(operand_.type != SPV_OPERAND_TYPE_RESULT_ID); | |
| const SpvOp opcode = static_cast<SpvOp>(inst_.opcode); | |
| // All operand slots which expect label id. | |
| if ((inst_.opcode == SpvOpLoopMerge && operand_index_ <= 1) || | |
| (inst_.opcode == SpvOpSelectionMerge && operand_index_ == 0) || | |
| (inst_.opcode == SpvOpBranch && operand_index_ == 0) || | |
| (inst_.opcode == SpvOpBranchConditional && | |
| (operand_index_ == 1 || operand_index_ == 2)) || | |
| (inst_.opcode == SpvOpPhi && operand_index_ >= 3 && | |
| operand_index_ % 2 == 1) || | |
| (inst_.opcode == SpvOpSwitch && operand_index_ > 0)) { | |
| return kMtfLabel; | |
| } | |
| switch (opcode) { | |
| case SpvOpFAdd: | |
| case SpvOpFSub: | |
| case SpvOpFMul: | |
| case SpvOpFDiv: | |
| case SpvOpFRem: | |
| case SpvOpFMod: | |
| case SpvOpFNegate: { | |
| if (operand_index_ == 0) return kMtfTypeFloatScalarOrVector; | |
| return GetMtfIdOfType(inst_.type_id); | |
| } | |
| case SpvOpISub: | |
| case SpvOpIAdd: | |
| case SpvOpIMul: | |
| case SpvOpSDiv: | |
| case SpvOpUDiv: | |
| case SpvOpSMod: | |
| case SpvOpUMod: | |
| case SpvOpSRem: | |
| case SpvOpSNegate: { | |
| if (operand_index_ == 0) return kMtfTypeIntScalarOrVector; | |
| return kMtfIntScalarOrVector; | |
| } | |
| // TODO(atgoo@github.com) Add OpConvertFToU and other opcodes. | |
| case SpvOpFOrdEqual: | |
| case SpvOpFUnordEqual: | |
| case SpvOpFOrdNotEqual: | |
| case SpvOpFUnordNotEqual: | |
| case SpvOpFOrdLessThan: | |
| case SpvOpFUnordLessThan: | |
| case SpvOpFOrdGreaterThan: | |
| case SpvOpFUnordGreaterThan: | |
| case SpvOpFOrdLessThanEqual: | |
| case SpvOpFUnordLessThanEqual: | |
| case SpvOpFOrdGreaterThanEqual: | |
| case SpvOpFUnordGreaterThanEqual: { | |
| if (operand_index_ == 0) return kMtfTypeBoolScalarOrVector; | |
| if (operand_index_ == 2) return kMtfFloatScalarOrVector; | |
| if (operand_index_ == 3) { | |
| const uint32_t first_operand_id = GetInstWords()[3]; | |
| const uint32_t first_operand_type = id_to_type_id_.at(first_operand_id); | |
| return GetMtfIdOfType(first_operand_type); | |
| } | |
| break; | |
| } | |
| case SpvOpVectorShuffle: { | |
| if (operand_index_ == 0) { | |
| assert(inst_.num_operands > 4); | |
| return GetMtfTypeVectorOfSize(inst_.num_operands - 4); | |
| } | |
| assert(inst_.type_id); | |
| if (operand_index_ == 2 || operand_index_ == 3) | |
| return GetMtfVectorOfComponentType( | |
| GetVectorComponentType(inst_.type_id)); | |
| break; | |
| } | |
| case SpvOpVectorTimesScalar: { | |
| if (operand_index_ == 0) { | |
| // TODO(atgoo@github.com) Could be narrowed to vector of floats. | |
| return GetMtfIdGeneratedByOpcode(SpvOpTypeVector); | |
| } | |
| assert(inst_.type_id); | |
| if (operand_index_ == 2) return GetMtfIdOfType(inst_.type_id); | |
| if (operand_index_ == 3) | |
| return GetMtfIdOfType(GetVectorComponentType(inst_.type_id)); | |
| break; | |
| } | |
| case SpvOpDot: { | |
| if (operand_index_ == 0) return GetMtfIdGeneratedByOpcode(SpvOpTypeFloat); | |
| assert(inst_.type_id); | |
| if (operand_index_ == 2) | |
| return GetMtfVectorOfComponentType(inst_.type_id); | |
| if (operand_index_ == 3) { | |
| const uint32_t vector_id = GetInstWords()[3]; | |
| const uint32_t vector_type = id_to_type_id_.at(vector_id); | |
| return GetMtfIdOfType(vector_type); | |
| } | |
| break; | |
| } | |
| case SpvOpTypeVector: { | |
| if (operand_index_ == 1) { | |
| return kMtfTypeScalar; | |
| } | |
| break; | |
| } | |
| case SpvOpTypeMatrix: { | |
| if (operand_index_ == 1) { | |
| return GetMtfIdGeneratedByOpcode(SpvOpTypeVector); | |
| } | |
| break; | |
| } | |
| case SpvOpTypePointer: { | |
| if (operand_index_ == 2) { | |
| return kMtfTypeNonFunction; | |
| } | |
| break; | |
| } | |
| case SpvOpTypeStruct: { | |
| if (operand_index_ >= 1) { | |
| return kMtfTypeNonFunction; | |
| } | |
| break; | |
| } | |
| case SpvOpTypeFunction: { | |
| if (operand_index_ == 1) { | |
| return kMtfTypeNonFunction; | |
| } | |
| if (operand_index_ >= 2) { | |
| return kMtfTypeNonFunction; | |
| } | |
| break; | |
| } | |
| case SpvOpLoad: { | |
| if (operand_index_ == 0) return kMtfTypeNonFunction; | |
| if (operand_index_ == 2) { | |
| assert(inst_.type_id); | |
| return GetMtfPointerToType(inst_.type_id); | |
| } | |
| break; | |
| } | |
| case SpvOpStore: { | |
| if (operand_index_ == 0) | |
| return GetMtfIdWithTypeGeneratedByOpcode(SpvOpTypePointer); | |
| if (operand_index_ == 1) { | |
| const uint32_t pointer_id = GetInstWords()[1]; | |
| const uint32_t pointer_type = id_to_type_id_.at(pointer_id); | |
| const val::Instruction* pointer_inst = FindDef(pointer_type); | |
| assert(pointer_inst); | |
| assert(pointer_inst->opcode() == SpvOpTypePointer); | |
| const uint32_t data_type = | |
| pointer_inst->word(pointer_inst->operands()[2].offset); | |
| return GetMtfIdOfType(data_type); | |
| } | |
| break; | |
| } | |
| case SpvOpVariable: { | |
| if (operand_index_ == 0) | |
| return GetMtfIdGeneratedByOpcode(SpvOpTypePointer); | |
| break; | |
| } | |
| case SpvOpAccessChain: { | |
| if (operand_index_ == 0) | |
| return GetMtfIdGeneratedByOpcode(SpvOpTypePointer); | |
| if (operand_index_ == 2) return kMtfTypePointerToComposite; | |
| if (operand_index_ >= 3) | |
| return GetMtfIdWithTypeGeneratedByOpcode(SpvOpTypeInt); | |
| break; | |
| } | |
| case SpvOpCompositeConstruct: { | |
| if (operand_index_ == 0) return kMtfTypeComposite; | |
| if (operand_index_ >= 2) { | |
| const uint32_t composite_type = GetInstWords()[1]; | |
| if (multi_mtf_.HasValue(kMtfTypeFloatScalarOrVector, composite_type)) | |
| return kMtfFloatScalarOrVector; | |
| if (multi_mtf_.HasValue(kMtfTypeIntScalarOrVector, composite_type)) | |
| return kMtfIntScalarOrVector; | |
| if (multi_mtf_.HasValue(kMtfTypeBoolScalarOrVector, composite_type)) | |
| return kMtfBoolScalarOrVector; | |
| } | |
| break; | |
| } | |
| case SpvOpCompositeExtract: { | |
| if (operand_index_ == 2) return kMtfComposite; | |
| break; | |
| } | |
| case SpvOpConstantComposite: { | |
| if (operand_index_ == 0) return kMtfTypeComposite; | |
| if (operand_index_ >= 2) { | |
| const val::Instruction* composite_type_inst = FindDef(inst_.type_id); | |
| assert(composite_type_inst); | |
| if (composite_type_inst->opcode() == SpvOpTypeVector) { | |
| return GetMtfIdOfType(composite_type_inst->word(2)); | |
| } | |
| } | |
| break; | |
| } | |
| case SpvOpExtInst: { | |
| if (operand_index_ == 2) | |
| return GetMtfIdGeneratedByOpcode(SpvOpExtInstImport); | |
| if (operand_index_ >= 4) { | |
| const uint32_t return_type = GetInstWords()[1]; | |
| const uint32_t ext_inst_type = inst_.ext_inst_type; | |
| const uint32_t ext_inst_index = GetInstWords()[4]; | |
| // TODO(atgoo@github.com) The list of extended instructions is | |
| // incomplete. Only common instructions and low-hanging fruits listed. | |
| if (ext_inst_type == SPV_EXT_INST_TYPE_GLSL_STD_450) { | |
| switch (ext_inst_index) { | |
| case GLSLstd450FAbs: | |
| case GLSLstd450FClamp: | |
| case GLSLstd450FMax: | |
| case GLSLstd450FMin: | |
| case GLSLstd450FMix: | |
| case GLSLstd450Step: | |
| case GLSLstd450SmoothStep: | |
| case GLSLstd450Fma: | |
| case GLSLstd450Pow: | |
| case GLSLstd450Exp: | |
| case GLSLstd450Exp2: | |
| case GLSLstd450Log: | |
| case GLSLstd450Log2: | |
| case GLSLstd450Sqrt: | |
| case GLSLstd450InverseSqrt: | |
| case GLSLstd450Fract: | |
| case GLSLstd450Floor: | |
| case GLSLstd450Ceil: | |
| case GLSLstd450Radians: | |
| case GLSLstd450Degrees: | |
| case GLSLstd450Sin: | |
| case GLSLstd450Cos: | |
| case GLSLstd450Tan: | |
| case GLSLstd450Sinh: | |
| case GLSLstd450Cosh: | |
| case GLSLstd450Tanh: | |
| case GLSLstd450Asin: | |
| case GLSLstd450Acos: | |
| case GLSLstd450Atan: | |
| case GLSLstd450Atan2: | |
| case GLSLstd450Asinh: | |
| case GLSLstd450Acosh: | |
| case GLSLstd450Atanh: | |
| case GLSLstd450MatrixInverse: | |
| case GLSLstd450Cross: | |
| case GLSLstd450Normalize: | |
| case GLSLstd450Reflect: | |
| case GLSLstd450FaceForward: | |
| return GetMtfIdOfType(return_type); | |
| case GLSLstd450Length: | |
| case GLSLstd450Distance: | |
| case GLSLstd450Refract: | |
| return kMtfFloatScalarOrVector; | |
| default: | |
| break; | |
| } | |
| } else if (ext_inst_type == SPV_EXT_INST_TYPE_OPENCL_STD) { | |
| switch (ext_inst_index) { | |
| case OpenCLLIB::Fabs: | |
| case OpenCLLIB::FClamp: | |
| case OpenCLLIB::Fmax: | |
| case OpenCLLIB::Fmin: | |
| case OpenCLLIB::Step: | |
| case OpenCLLIB::Smoothstep: | |
| case OpenCLLIB::Fma: | |
| case OpenCLLIB::Pow: | |
| case OpenCLLIB::Exp: | |
| case OpenCLLIB::Exp2: | |
| case OpenCLLIB::Log: | |
| case OpenCLLIB::Log2: | |
| case OpenCLLIB::Sqrt: | |
| case OpenCLLIB::Rsqrt: | |
| case OpenCLLIB::Fract: | |
| case OpenCLLIB::Floor: | |
| case OpenCLLIB::Ceil: | |
| case OpenCLLIB::Radians: | |
| case OpenCLLIB::Degrees: | |
| case OpenCLLIB::Sin: | |
| case OpenCLLIB::Cos: | |
| case OpenCLLIB::Tan: | |
| case OpenCLLIB::Sinh: | |
| case OpenCLLIB::Cosh: | |
| case OpenCLLIB::Tanh: | |
| case OpenCLLIB::Asin: | |
| case OpenCLLIB::Acos: | |
| case OpenCLLIB::Atan: | |
| case OpenCLLIB::Atan2: | |
| case OpenCLLIB::Asinh: | |
| case OpenCLLIB::Acosh: | |
| case OpenCLLIB::Atanh: | |
| case OpenCLLIB::Cross: | |
| case OpenCLLIB::Normalize: | |
| return GetMtfIdOfType(return_type); | |
| case OpenCLLIB::Length: | |
| case OpenCLLIB::Distance: | |
| return kMtfFloatScalarOrVector; | |
| default: | |
| break; | |
| } | |
| } | |
| } | |
| break; | |
| } | |
| case SpvOpFunction: { | |
| if (operand_index_ == 0) return kMtfTypeReturnedByFunction; | |
| if (operand_index_ == 3) { | |
| const uint32_t return_type = GetInstWords()[1]; | |
| return GetMtfFunctionTypeWithReturnType(return_type); | |
| } | |
| break; | |
| } | |
| case SpvOpFunctionCall: { | |
| if (operand_index_ == 0) return kMtfTypeReturnedByFunction; | |
| if (operand_index_ == 2) { | |
| const uint32_t return_type = GetInstWords()[1]; | |
| return GetMtfFunctionWithReturnType(return_type); | |
| } | |
| if (operand_index_ >= 3) { | |
| const uint32_t function_id = GetInstWords()[3]; | |
| const val::Instruction* function_inst = FindDef(function_id); | |
| if (!function_inst) return kMtfObject; | |
| assert(function_inst->opcode() == SpvOpFunction); | |
| const uint32_t function_type_id = function_inst->word(4); | |
| const val::Instruction* function_type_inst = FindDef(function_type_id); | |
| assert(function_type_inst); | |
| assert(function_type_inst->opcode() == SpvOpTypeFunction); | |
| const uint32_t argument_type = function_type_inst->word(operand_index_); | |
| return GetMtfIdOfType(argument_type); | |
| } | |
| break; | |
| } | |
| case SpvOpReturnValue: { | |
| if (operand_index_ == 0) return GetMtfIdOfType(cur_function_return_type_); | |
| break; | |
| } | |
| case SpvOpBranchConditional: { | |
| if (operand_index_ == 0) | |
| return GetMtfIdWithTypeGeneratedByOpcode(SpvOpTypeBool); | |
| break; | |
| } | |
| case SpvOpSampledImage: { | |
| if (operand_index_ == 0) | |
| return GetMtfIdGeneratedByOpcode(SpvOpTypeSampledImage); | |
| if (operand_index_ == 2) | |
| return GetMtfIdWithTypeGeneratedByOpcode(SpvOpTypeImage); | |
| if (operand_index_ == 3) | |
| return GetMtfIdWithTypeGeneratedByOpcode(SpvOpTypeSampler); | |
| break; | |
| } | |
| case SpvOpImageSampleImplicitLod: { | |
| if (operand_index_ == 0) | |
| return GetMtfIdGeneratedByOpcode(SpvOpTypeVector); | |
| if (operand_index_ == 2) | |
| return GetMtfIdWithTypeGeneratedByOpcode(SpvOpTypeSampledImage); | |
| if (operand_index_ == 3) | |
| return GetMtfIdWithTypeGeneratedByOpcode(SpvOpTypeVector); | |
| break; | |
| } | |
| default: | |
| break; | |
| } | |
| return kMtfNone; | |
| } | |
| } // namespace comp | |
| } // namespace spvtools |