#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/spirv_target_env.h"
#include "source/table.h"
namespace spvtools {
namespace {
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;
const char separator = '|';
uint32_t value = 0;
const char* begin = textValue;
const char* end = nullptr;
do {
end = std::find(begin, text_end, separator);
spv_operand_desc entry = nullptr;
if (auto error = spvOperandTableNameLookup(env, operandTable, type, begin,
end - begin, &entry)) {
return error;
}
value |= entry->value;
begin = end + 1;
} while (end != text_end);
*pValue = value;
return SPV_SUCCESS;
}
struct SpecConstantOpcodeEntry {
spv::Op opcode;
const char* name;
};
#define CASE(NAME) { spv::Op::Op##NAME, #NAME }
const SpecConstantOpcodeEntry kOpSpecConstantOpcodes[] = {
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),
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),
CASE(VectorShuffle),
CASE(CompositeExtract),
CASE(CompositeInsert),
CASE(LogicalOr),
CASE(LogicalAnd),
CASE(LogicalNot),
CASE(LogicalEqual),
CASE(LogicalNotEqual),
CASE(Select),
CASE(IEqual),
CASE(INotEqual),
CASE(ULessThan),
CASE(SLessThan),
CASE(UGreaterThan),
CASE(SGreaterThan),
CASE(ULessThanEqual),
CASE(SLessThanEqual),
CASE(UGreaterThanEqual),
CASE(SGreaterThanEqual),
CASE(AccessChain),
CASE(InBoundsAccessChain),
CASE(PtrAccessChain),
CASE(InBoundsPtrAccessChain),
CASE(CooperativeMatrixLengthNV),
CASE(CooperativeMatrixLengthKHR)
};
static_assert(61 == sizeof(kOpSpecConstantOpcodes)/sizeof(kOpSpecConstantOpcodes[0]),
"OpSpecConstantOp opcode table is incomplete");
#undef CASE
const size_t kNumOpSpecConstantOpcodes =
sizeof(kOpSpecConstantOpcodes) / sizeof(kOpSpecConstantOpcodes[0]);
}
bool AssemblyGrammar::isValid() const {
return operandTable_ && opcodeTable_ && extInstTable_;
}
CapabilitySet AssemblyGrammar::filterCapsAgainstTargetEnv(
const spv::Capability* cap_array, uint32_t count) const {
CapabilitySet cap_set;
const auto version = spvVersionForTargetEnv(target_env_);
for (uint32_t i = 0; i < count; ++i) {
spv_operand_desc entry = {};
if (SPV_SUCCESS == lookupOperand(SPV_OPERAND_TYPE_CAPABILITY,
static_cast<uint32_t>(cap_array[i]),
&entry)) {
if ((version >= entry->minVersion && version <= entry->lastVersion) ||
entry->numExtensions > 0u || entry->numCapabilities > 0u) {
cap_set.insert(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(spv::Op 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,
spv::Op* 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(spv::Op 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);
}
}