mirror of
https://github.com/KhronosGroup/SPIRV-Tools
synced 2024-11-30 15:00:06 +00:00
1963a2dbda
This CL replaces instances of reset(new ..) with MakeUnique.
794 lines
25 KiB
C++
794 lines
25 KiB
C++
// 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
|