mirror of
https://github.com/KhronosGroup/SPIRV-Tools
synced 2024-11-21 19:20:07 +00:00
Switch SPIRV-Tools to use spirv.hpp11 internally (#4981)
Fixes #4960 * Switches to using enum classes with an underlying type to avoid undefined behaviour
This commit is contained in:
parent
c8e1588cfa
commit
d35a78db57
@ -220,7 +220,8 @@ $(1)/opencl.std.insts.inc \
|
||||
--core-insts-output=$(1)/core.insts-unified1.inc \
|
||||
--glsl-insts-output=$(1)/glsl.std.450.insts.inc \
|
||||
--opencl-insts-output=$(1)/opencl.std.insts.inc \
|
||||
--operand-kinds-output=$(1)/operand.kinds-unified1.inc
|
||||
--operand-kinds-output=$(1)/operand.kinds-unified1.inc \
|
||||
--output-language=c++
|
||||
@echo "[$(TARGET_ARCH_ABI)] Grammar (from unified1) : instructions & operands <= grammar JSON files"
|
||||
$(LOCAL_PATH)/source/opcode.cpp: $(1)/core.insts-unified1.inc
|
||||
$(LOCAL_PATH)/source/operand.cpp: $(1)/operand.kinds-unified1.inc
|
||||
@ -294,7 +295,8 @@ $(1)/extension_enum.inc $(1)/enum_string_mapping.inc: \
|
||||
--extinst-debuginfo-grammar=$(SPV_DEBUGINFO_GRAMMAR) \
|
||||
--extinst-cldebuginfo100-grammar=$(SPV_CLDEBUGINFO100_GRAMMAR) \
|
||||
--extension-enum-output=$(1)/extension_enum.inc \
|
||||
--enum-string-mapping-output=$(1)/enum_string_mapping.inc
|
||||
--enum-string-mapping-output=$(1)/enum_string_mapping.inc \
|
||||
--output-language=c++
|
||||
@echo "[$(TARGET_ARCH_ABI)] Generate enum<->string mapping <= grammar JSON files"
|
||||
# Generated header extension_enum.inc is transitively included by table.h, which is
|
||||
# used pervasively. Capture the pervasive dependency.
|
||||
|
@ -137,7 +137,7 @@ cc_library(
|
||||
copts = COMMON_COPTS,
|
||||
includes = ["source"],
|
||||
deps = [
|
||||
"@spirv_headers//:spirv_c_headers",
|
||||
"@spirv_headers//:spirv_cpp11_headers",
|
||||
],
|
||||
)
|
||||
|
||||
@ -162,7 +162,7 @@ cc_library(
|
||||
deps = [
|
||||
":generated_headers",
|
||||
":spirv_tools_headers",
|
||||
"@spirv_headers//:spirv_c_headers",
|
||||
"@spirv_headers//:spirv_cpp11_headers",
|
||||
"@spirv_headers//:spirv_common_headers",
|
||||
],
|
||||
)
|
||||
|
6
BUILD.gn
6
BUILD.gn
@ -69,6 +69,8 @@ template("spvtools_core_tables") {
|
||||
rebase_path(cldebuginfo100_insts_file, root_build_dir),
|
||||
"--operand-kinds-output",
|
||||
rebase_path(operand_kinds_file, root_build_dir),
|
||||
"--output-language",
|
||||
"c++"
|
||||
]
|
||||
}
|
||||
}
|
||||
@ -101,6 +103,8 @@ template("spvtools_core_enums") {
|
||||
rebase_path(extension_enum_file, root_build_dir),
|
||||
"--enum-string-mapping-output",
|
||||
rebase_path(extension_map_file, root_build_dir),
|
||||
"--output-language",
|
||||
"c++"
|
||||
]
|
||||
inputs = [
|
||||
core_json_file,
|
||||
@ -142,6 +146,8 @@ template("spvtools_glsl_tables") {
|
||||
rebase_path(glsl_json_file, root_build_dir),
|
||||
"--glsl-insts-output",
|
||||
rebase_path(glsl_insts_file, root_build_dir),
|
||||
"--output-language",
|
||||
"c++"
|
||||
]
|
||||
inputs = [
|
||||
core_json_file,
|
||||
|
@ -200,7 +200,7 @@ function(spvtools_default_compile_options TARGET)
|
||||
if(NOT "${SPIRV_PERF}" STREQUAL "")
|
||||
target_compile_options(${TARGET} PRIVATE -fno-omit-frame-pointer)
|
||||
endif()
|
||||
if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang")
|
||||
if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang" OR "${CMAKE_CXX_COMPILER_ID}" STREQUAL "AppleClang")
|
||||
set(SPIRV_USE_SANITIZER "" CACHE STRING
|
||||
"Use the clang sanitizer [address|memory|thread|...]")
|
||||
if(NOT "${SPIRV_USE_SANITIZER}" STREQUAL "")
|
||||
|
2
DEPS
2
DEPS
@ -6,7 +6,7 @@ vars = {
|
||||
'effcee_revision': '35912e1b7778ec2ddcff7e7188177761539e59e0',
|
||||
'googletest_revision': 'd9bb8412d60b993365abb53f00b6dad9b2c01b62',
|
||||
're2_revision': 'd2836d1b1c34c4e330a85a1006201db474bf2c8a',
|
||||
'spirv_headers_revision': '85a1ed200d50660786c1a88d9166e871123cce39',
|
||||
'spirv_headers_revision': '47f2465ee3e78ec5ec38f00b2c405d9475797228',
|
||||
}
|
||||
|
||||
deps = {
|
||||
|
@ -66,7 +66,8 @@ def generate_core_tables(version = None):
|
||||
"--extinst-debuginfo-grammar=$(location {1}) " +
|
||||
"--extinst-cldebuginfo100-grammar=$(location {2}) " +
|
||||
"--core-insts-output=$(location {3}) " +
|
||||
"--operand-kinds-output=$(location {4})"
|
||||
"--operand-kinds-output=$(location {4}) " +
|
||||
"--output-language=c++"
|
||||
).format(*fmtargs),
|
||||
cmd_bat = (
|
||||
"$(location :generate_grammar_tables) " +
|
||||
@ -74,7 +75,8 @@ def generate_core_tables(version = None):
|
||||
"--extinst-debuginfo-grammar=$(location {1}) " +
|
||||
"--extinst-cldebuginfo100-grammar=$(location {2}) " +
|
||||
"--core-insts-output=$(location {3}) " +
|
||||
"--operand-kinds-output=$(location {4})"
|
||||
"--operand-kinds-output=$(location {4}) " +
|
||||
"--output-language=c++"
|
||||
).format(*fmtargs),
|
||||
exec_tools = [":generate_grammar_tables"],
|
||||
visibility = ["//visibility:private"],
|
||||
@ -103,7 +105,8 @@ def generate_enum_string_mapping(version = None):
|
||||
"--extinst-debuginfo-grammar=$(location {1}) " +
|
||||
"--extinst-cldebuginfo100-grammar=$(location {2}) " +
|
||||
"--extension-enum-output=$(location {3}) " +
|
||||
"--enum-string-mapping-output=$(location {4})"
|
||||
"--enum-string-mapping-output=$(location {4}) " +
|
||||
"--output-language=c++"
|
||||
).format(*fmtargs),
|
||||
cmd_bat = (
|
||||
"$(location :generate_grammar_tables) " +
|
||||
@ -111,7 +114,8 @@ def generate_enum_string_mapping(version = None):
|
||||
"--extinst-debuginfo-grammar=$(location {1}) " +
|
||||
"--extinst-cldebuginfo100-grammar=$(location {2}) " +
|
||||
"--extension-enum-output=$(location {3}) " +
|
||||
"--enum-string-mapping-output=$(location {4})"
|
||||
"--enum-string-mapping-output=$(location {4}) " +
|
||||
"--output-language=c++"
|
||||
).format(*fmtargs),
|
||||
exec_tools = [":generate_grammar_tables"],
|
||||
visibility = ["//visibility:private"],
|
||||
@ -158,12 +162,14 @@ def generate_glsl_tables(version = None):
|
||||
cmd = (
|
||||
"$(location :generate_grammar_tables) " +
|
||||
"--extinst-glsl-grammar=$(location {0}) " +
|
||||
"--glsl-insts-output=$(location {1})"
|
||||
"--glsl-insts-output=$(location {1}) " +
|
||||
"--output-language=c++"
|
||||
).format(*fmtargs),
|
||||
cmd_bat = (
|
||||
"$(location :generate_grammar_tables) " +
|
||||
"--extinst-glsl-grammar=$(location {0}) " +
|
||||
"--glsl-insts-output=$(location {1})"
|
||||
"--glsl-insts-output=$(location {1}) " +
|
||||
"--output-language=c++"
|
||||
).format(*fmtargs),
|
||||
exec_tools = [":generate_grammar_tables"],
|
||||
visibility = ["//visibility:private"],
|
||||
|
@ -37,6 +37,7 @@ macro(spvtools_core_tables CONFIG_VERSION)
|
||||
--extinst-cldebuginfo100-grammar=${CLDEBUGINFO100_GRAMMAR_JSON_FILE}
|
||||
--core-insts-output=${GRAMMAR_INSTS_INC_FILE}
|
||||
--operand-kinds-output=${GRAMMAR_KINDS_INC_FILE}
|
||||
--output-language=c++
|
||||
DEPENDS ${GRAMMAR_PROCESSING_SCRIPT}
|
||||
${GRAMMAR_JSON_FILE}
|
||||
${DEBUGINFO_GRAMMAR_JSON_FILE}
|
||||
@ -58,6 +59,7 @@ macro(spvtools_enum_string_mapping CONFIG_VERSION)
|
||||
--extinst-cldebuginfo100-grammar=${CLDEBUGINFO100_GRAMMAR_JSON_FILE}
|
||||
--extension-enum-output=${GRAMMAR_EXTENSION_ENUM_INC_FILE}
|
||||
--enum-string-mapping-output=${GRAMMAR_ENUM_STRING_MAPPING_INC_FILE}
|
||||
--output-language=c++
|
||||
DEPENDS ${GRAMMAR_PROCESSING_SCRIPT}
|
||||
${GRAMMAR_JSON_FILE}
|
||||
${DEBUGINFO_GRAMMAR_JSON_FILE}
|
||||
@ -92,6 +94,7 @@ macro(spvtools_glsl_tables CONFIG_VERSION)
|
||||
COMMAND ${PYTHON_EXECUTABLE} ${GRAMMAR_PROCESSING_SCRIPT}
|
||||
--extinst-glsl-grammar=${GLSL_GRAMMAR_JSON_FILE}
|
||||
--glsl-insts-output=${GRAMMAR_INC_FILE}
|
||||
--output-language=c++
|
||||
DEPENDS ${GRAMMAR_PROCESSING_SCRIPT} ${CORE_GRAMMAR_JSON_FILE} ${GLSL_GRAMMAR_JSON_FILE}
|
||||
COMMENT "Generate info tables for GLSL extended instructions and operands v${CONFIG_VERSION}.")
|
||||
list(APPEND EXTINST_CPP_DEPENDS ${GRAMMAR_INC_FILE})
|
||||
|
@ -78,16 +78,16 @@ spv_result_t spvTextParseMaskOperand(spv_target_env env,
|
||||
|
||||
// Associates an opcode with its name.
|
||||
struct SpecConstantOpcodeEntry {
|
||||
SpvOp opcode;
|
||||
spv::Op 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".
|
||||
// The name does not have the usual "Op" prefix. For example opcode
|
||||
// spv::Op::IAdd is associated with the name "IAdd".
|
||||
//
|
||||
// clang-format off
|
||||
#define CASE(NAME) { SpvOp##NAME, #NAME }
|
||||
#define CASE(NAME) { spv::Op::Op##NAME, #NAME }
|
||||
const SpecConstantOpcodeEntry kOpSpecConstantOpcodes[] = {
|
||||
// Conversion
|
||||
CASE(SConvert),
|
||||
@ -173,7 +173,7 @@ bool AssemblyGrammar::isValid() const {
|
||||
}
|
||||
|
||||
CapabilitySet AssemblyGrammar::filterCapsAgainstTargetEnv(
|
||||
const SpvCapability* cap_array, uint32_t count) const {
|
||||
const spv::Capability* cap_array, uint32_t count) const {
|
||||
CapabilitySet cap_set;
|
||||
for (uint32_t i = 0; i < count; ++i) {
|
||||
spv_operand_desc cap_desc = {};
|
||||
@ -194,7 +194,7 @@ spv_result_t AssemblyGrammar::lookupOpcode(const char* name,
|
||||
return spvOpcodeTableNameLookup(target_env_, opcodeTable_, name, desc);
|
||||
}
|
||||
|
||||
spv_result_t AssemblyGrammar::lookupOpcode(SpvOp opcode,
|
||||
spv_result_t AssemblyGrammar::lookupOpcode(spv::Op opcode,
|
||||
spv_opcode_desc* desc) const {
|
||||
return spvOpcodeTableValueLookup(target_env_, opcodeTable_, opcode, desc);
|
||||
}
|
||||
@ -214,7 +214,7 @@ spv_result_t AssemblyGrammar::lookupOperand(spv_operand_type_t type,
|
||||
}
|
||||
|
||||
spv_result_t AssemblyGrammar::lookupSpecConstantOpcode(const char* name,
|
||||
SpvOp* opcode) const {
|
||||
spv::Op* opcode) const {
|
||||
const auto* last = kOpSpecConstantOpcodes + kNumOpSpecConstantOpcodes;
|
||||
const auto* found =
|
||||
std::find_if(kOpSpecConstantOpcodes, last,
|
||||
@ -226,7 +226,7 @@ spv_result_t AssemblyGrammar::lookupSpecConstantOpcode(const char* name,
|
||||
return SPV_SUCCESS;
|
||||
}
|
||||
|
||||
spv_result_t AssemblyGrammar::lookupSpecConstantOpcode(SpvOp opcode) const {
|
||||
spv_result_t AssemblyGrammar::lookupSpecConstantOpcode(spv::Op opcode) const {
|
||||
const auto* last = kOpSpecConstantOpcodes + kNumOpSpecConstantOpcodes;
|
||||
const auto* found =
|
||||
std::find_if(kOpSpecConstantOpcodes, last,
|
||||
|
@ -41,7 +41,7 @@ class AssemblyGrammar {
|
||||
|
||||
// Removes capabilities not available in the current target environment and
|
||||
// returns the rest.
|
||||
CapabilitySet filterCapsAgainstTargetEnv(const SpvCapability* cap_array,
|
||||
CapabilitySet filterCapsAgainstTargetEnv(const spv::Capability* cap_array,
|
||||
uint32_t count) const;
|
||||
|
||||
// Fills in the desc parameter with the information about the opcode
|
||||
@ -52,7 +52,7 @@ class AssemblyGrammar {
|
||||
// Fills in the desc parameter with the information about the opcode
|
||||
// of the valid. Returns SPV_SUCCESS if the opcode was found, and
|
||||
// SPV_ERROR_INVALID_LOOKUP if the opcode does not exist.
|
||||
spv_result_t lookupOpcode(SpvOp opcode, spv_opcode_desc* desc) const;
|
||||
spv_result_t lookupOpcode(spv::Op opcode, spv_opcode_desc* desc) const;
|
||||
|
||||
// Fills in the desc parameter with the information about the given
|
||||
// operand. Returns SPV_SUCCESS if the operand was found, and
|
||||
@ -82,11 +82,12 @@ class AssemblyGrammar {
|
||||
// the integer add opcode for OpSpecConstantOp. On success, returns
|
||||
// SPV_SUCCESS and sends the discovered operation code through the opcode
|
||||
// parameter. On failure, returns SPV_ERROR_INVALID_LOOKUP.
|
||||
spv_result_t lookupSpecConstantOpcode(const char* name, SpvOp* opcode) const;
|
||||
spv_result_t lookupSpecConstantOpcode(const char* name,
|
||||
spv::Op* opcode) const;
|
||||
|
||||
// Returns SPV_SUCCESS if the given opcode is valid as the opcode operand
|
||||
// to OpSpecConstantOp.
|
||||
spv_result_t lookupSpecConstantOpcode(SpvOp opcode) const;
|
||||
spv_result_t lookupSpecConstantOpcode(spv::Op opcode) const;
|
||||
|
||||
// Parses a mask expression string for the given operand type.
|
||||
//
|
||||
|
@ -156,7 +156,7 @@ class Parser {
|
||||
// Issues a diagnostic describing an exhaustion of input condition when
|
||||
// trying to decode an instruction operand, and returns
|
||||
// SPV_ERROR_INVALID_BINARY.
|
||||
spv_result_t exhaustedInputDiagnostic(size_t inst_offset, SpvOp opcode,
|
||||
spv_result_t exhaustedInputDiagnostic(size_t inst_offset, spv::Op opcode,
|
||||
spv_operand_type_t type) {
|
||||
return diagnostic() << "End of input reached while decoding Op"
|
||||
<< spvOpcodeString(opcode) << " starting at word "
|
||||
@ -318,7 +318,7 @@ spv_result_t Parser::parseInstruction() {
|
||||
<< inst_word_count;
|
||||
}
|
||||
spv_opcode_desc opcode_desc;
|
||||
if (grammar_.lookupOpcode(static_cast<SpvOp>(inst.opcode), &opcode_desc))
|
||||
if (grammar_.lookupOpcode(static_cast<spv::Op>(inst.opcode), &opcode_desc))
|
||||
return diagnostic() << "Invalid opcode: " << inst.opcode;
|
||||
|
||||
// Advance past the opcode word. But remember the of the start
|
||||
@ -418,7 +418,7 @@ spv_result_t Parser::parseOperand(size_t inst_offset,
|
||||
std::vector<uint32_t>* words,
|
||||
std::vector<spv_parsed_operand_t>* operands,
|
||||
spv_operand_pattern_t* expected_operands) {
|
||||
const SpvOp opcode = static_cast<SpvOp>(inst->opcode);
|
||||
const spv::Op opcode = static_cast<spv::Op>(inst->opcode);
|
||||
// We'll fill in this result as we go along.
|
||||
spv_parsed_operand_t parsed_operand;
|
||||
parsed_operand.offset = uint16_t(_.word_index - inst_offset);
|
||||
@ -473,7 +473,7 @@ spv_result_t Parser::parseOperand(size_t inst_offset,
|
||||
if (!word) return diagnostic(SPV_ERROR_INVALID_ID) << "Id is 0";
|
||||
parsed_operand.type = SPV_OPERAND_TYPE_ID;
|
||||
|
||||
if (opcode == SpvOpExtInst && parsed_operand.offset == 3) {
|
||||
if (opcode == spv::Op::OpExtInst && parsed_operand.offset == 3) {
|
||||
// The current word is the extended instruction set Id.
|
||||
// Set the extended instruction set type for the current instruction.
|
||||
auto ext_inst_type_iter = _.import_id_to_ext_inst_type.find(word);
|
||||
@ -494,7 +494,7 @@ spv_result_t Parser::parseOperand(size_t inst_offset,
|
||||
break;
|
||||
|
||||
case SPV_OPERAND_TYPE_EXTENSION_INSTRUCTION_NUMBER: {
|
||||
assert(SpvOpExtInst == opcode);
|
||||
assert(spv::Op::OpExtInst == opcode);
|
||||
assert(inst->ext_inst_type != SPV_EXT_INST_TYPE_NONE);
|
||||
spv_ext_inst_desc ext_inst;
|
||||
if (grammar_.lookupExtInst(inst->ext_inst_type, word, &ext_inst) ==
|
||||
@ -516,14 +516,14 @@ spv_result_t Parser::parseOperand(size_t inst_offset,
|
||||
} break;
|
||||
|
||||
case SPV_OPERAND_TYPE_SPEC_CONSTANT_OP_NUMBER: {
|
||||
assert(SpvOpSpecConstantOp == opcode);
|
||||
if (word > static_cast<uint32_t>(SpvOp::SpvOpMax) ||
|
||||
grammar_.lookupSpecConstantOpcode(SpvOp(word))) {
|
||||
assert(spv::Op::OpSpecConstantOp == opcode);
|
||||
if (word > static_cast<uint32_t>(spv::Op::Max) ||
|
||||
grammar_.lookupSpecConstantOpcode(spv::Op(word))) {
|
||||
return diagnostic()
|
||||
<< "Invalid " << spvOperandTypeStr(type) << ": " << word;
|
||||
}
|
||||
spv_opcode_desc opcode_entry = nullptr;
|
||||
if (grammar_.lookupOpcode(SpvOp(word), &opcode_entry)) {
|
||||
if (grammar_.lookupOpcode(spv::Op(word), &opcode_entry)) {
|
||||
return diagnostic(SPV_ERROR_INTERNAL)
|
||||
<< "OpSpecConstant opcode table out of sync";
|
||||
}
|
||||
@ -549,7 +549,7 @@ spv_result_t Parser::parseOperand(size_t inst_offset,
|
||||
case SPV_OPERAND_TYPE_TYPED_LITERAL_NUMBER:
|
||||
case SPV_OPERAND_TYPE_OPTIONAL_TYPED_LITERAL_INTEGER:
|
||||
parsed_operand.type = SPV_OPERAND_TYPE_TYPED_LITERAL_NUMBER;
|
||||
if (opcode == SpvOpSwitch) {
|
||||
if (opcode == spv::Op::OpSwitch) {
|
||||
// The literal operands have the same type as the value
|
||||
// referenced by the selector Id.
|
||||
const uint32_t selector_id = peekAt(inst_offset + 1);
|
||||
@ -575,7 +575,8 @@ spv_result_t Parser::parseOperand(size_t inst_offset,
|
||||
<< " is not a scalar integer";
|
||||
}
|
||||
} else {
|
||||
assert(opcode == SpvOpConstant || opcode == SpvOpSpecConstant);
|
||||
assert(opcode == spv::Op::OpConstant ||
|
||||
opcode == spv::Op::OpSpecConstant);
|
||||
// The literal number type is determined by the type Id for the
|
||||
// constant.
|
||||
assert(inst->type_id);
|
||||
@ -607,7 +608,7 @@ spv_result_t Parser::parseOperand(size_t inst_offset,
|
||||
parsed_operand.num_words = uint16_t(string_num_words);
|
||||
parsed_operand.type = SPV_OPERAND_TYPE_LITERAL_STRING;
|
||||
|
||||
if (SpvOpExtInstImport == opcode) {
|
||||
if (spv::Op::OpExtInstImport == opcode) {
|
||||
// Record the extended instruction type for the ID for this import.
|
||||
// There is only one string literal argument to OpExtInstImport,
|
||||
// so it's sufficient to guard this just on the opcode.
|
||||
@ -789,14 +790,14 @@ spv_result_t Parser::setNumericTypeInfoForType(
|
||||
|
||||
void Parser::recordNumberType(size_t inst_offset,
|
||||
const spv_parsed_instruction_t* inst) {
|
||||
const SpvOp opcode = static_cast<SpvOp>(inst->opcode);
|
||||
const spv::Op opcode = static_cast<spv::Op>(inst->opcode);
|
||||
if (spvOpcodeGeneratesType(opcode)) {
|
||||
NumberType info = {SPV_NUMBER_NONE, 0};
|
||||
if (SpvOpTypeInt == opcode) {
|
||||
if (spv::Op::OpTypeInt == opcode) {
|
||||
const bool is_signed = peekAt(inst_offset + 3) != 0;
|
||||
info.type = is_signed ? SPV_NUMBER_SIGNED_INT : SPV_NUMBER_UNSIGNED_INT;
|
||||
info.bit_width = peekAt(inst_offset + 2);
|
||||
} else if (SpvOpTypeFloat == opcode) {
|
||||
} else if (spv::Op::OpTypeFloat == opcode) {
|
||||
info.type = SPV_NUMBER_FLOATING;
|
||||
info.bit_width = peekAt(inst_offset + 2);
|
||||
}
|
||||
|
@ -44,8 +44,8 @@ using IdGroup = std::vector<uint32_t>;
|
||||
// different implementations produce identical results.
|
||||
using IdGroupMapByName = std::map<std::string, IdGroup>;
|
||||
using IdGroupMapByTypeId = std::map<uint32_t, IdGroup>;
|
||||
using IdGroupMapByOp = std::map<SpvOp, IdGroup>;
|
||||
using IdGroupMapByStorageClass = std::map<SpvStorageClass, IdGroup>;
|
||||
using IdGroupMapByOp = std::map<spv::Op, IdGroup>;
|
||||
using IdGroupMapByStorageClass = std::map<spv::StorageClass, IdGroup>;
|
||||
|
||||
// A set of potential id mappings that haven't been resolved yet. Any id in src
|
||||
// may map in any id in dst. Note that ids are added in the same order as they
|
||||
@ -301,10 +301,10 @@ class Differ {
|
||||
// Get various properties from an id. These Helper functions are passed to
|
||||
// `GroupIds` and `GroupIdsAndMatch` below (as the `get_group` argument).
|
||||
uint32_t GroupIdsHelperGetTypeId(const IdInstructions& id_to, uint32_t id);
|
||||
SpvStorageClass GroupIdsHelperGetTypePointerStorageClass(
|
||||
spv::StorageClass GroupIdsHelperGetTypePointerStorageClass(
|
||||
const IdInstructions& id_to, uint32_t id);
|
||||
SpvOp GroupIdsHelperGetTypePointerTypeOp(const IdInstructions& id_to,
|
||||
uint32_t id);
|
||||
spv::Op GroupIdsHelperGetTypePointerTypeOp(const IdInstructions& id_to,
|
||||
uint32_t id);
|
||||
|
||||
// Given a list of ids, groups them based on some value. The `get_group`
|
||||
// function extracts a piece of information corresponding to each id, and the
|
||||
@ -414,8 +414,8 @@ class Differ {
|
||||
// Helper functions to retrieve information pertaining to an id
|
||||
const opt::Instruction* GetInst(const IdInstructions& id_to, uint32_t id);
|
||||
uint32_t GetConstantUint(const IdInstructions& id_to, uint32_t constant_id);
|
||||
SpvExecutionModel GetExecutionModel(const opt::Module* module,
|
||||
uint32_t entry_point_id);
|
||||
spv::ExecutionModel GetExecutionModel(const opt::Module* module,
|
||||
uint32_t entry_point_id);
|
||||
bool HasName(const IdInstructions& id_to, uint32_t id);
|
||||
// Get the OpName associated with an id
|
||||
std::string GetName(const IdInstructions& id_to, uint32_t id, bool* has_name);
|
||||
@ -424,20 +424,21 @@ class Differ {
|
||||
// string, and this improves diff between SPIR-V from those tools and others.
|
||||
std::string GetSanitizedName(const IdInstructions& id_to, uint32_t id);
|
||||
uint32_t GetVarTypeId(const IdInstructions& id_to, uint32_t var_id,
|
||||
SpvStorageClass* storage_class);
|
||||
spv::StorageClass* storage_class);
|
||||
bool GetDecorationValue(const IdInstructions& id_to, uint32_t id,
|
||||
SpvDecoration decoration, uint32_t* decoration_value);
|
||||
spv::Decoration decoration,
|
||||
uint32_t* decoration_value);
|
||||
const opt::Instruction* GetForwardPointerInst(const IdInstructions& id_to,
|
||||
uint32_t id);
|
||||
bool IsIntType(const IdInstructions& id_to, uint32_t type_id);
|
||||
bool IsFloatType(const IdInstructions& id_to, uint32_t type_id);
|
||||
bool IsConstantUint(const IdInstructions& id_to, uint32_t id);
|
||||
bool IsVariable(const IdInstructions& id_to, uint32_t pointer_id);
|
||||
bool IsOp(const IdInstructions& id_to, uint32_t id, SpvOp opcode);
|
||||
bool IsOp(const IdInstructions& id_to, uint32_t id, spv::Op opcode);
|
||||
bool IsPerVertexType(const IdInstructions& id_to, uint32_t type_id);
|
||||
bool IsPerVertexVariable(const IdInstructions& id_to, uint32_t type_id);
|
||||
SpvStorageClass GetPerVertexStorageClass(const opt::Module* module,
|
||||
uint32_t type_id);
|
||||
spv::StorageClass GetPerVertexStorageClass(const opt::Module* module,
|
||||
uint32_t type_id);
|
||||
spv_ext_inst_type_t GetExtInstType(const IdInstructions& id_to,
|
||||
uint32_t set_id);
|
||||
spv_number_kind_t GetNumberKind(const IdInstructions& id_to,
|
||||
@ -561,19 +562,19 @@ void IdInstructions::MapIdsToInfos(
|
||||
uint32_t id_operand = 0;
|
||||
|
||||
switch (inst.opcode()) {
|
||||
case SpvOpName:
|
||||
case spv::Op::OpName:
|
||||
info_map = &name_map_;
|
||||
break;
|
||||
case SpvOpMemberName:
|
||||
case spv::Op::OpMemberName:
|
||||
info_map = &name_map_;
|
||||
break;
|
||||
case SpvOpDecorate:
|
||||
case spv::Op::OpDecorate:
|
||||
info_map = &decoration_map_;
|
||||
break;
|
||||
case SpvOpMemberDecorate:
|
||||
case spv::Op::OpMemberDecorate:
|
||||
info_map = &decoration_map_;
|
||||
break;
|
||||
case SpvOpTypeForwardPointer: {
|
||||
case spv::Op::OpTypeForwardPointer: {
|
||||
uint32_t id = inst.GetSingleWordOperand(0);
|
||||
assert(id != 0);
|
||||
|
||||
@ -731,10 +732,10 @@ int Differ::ComparePreambleInstructions(const opt::Instruction* a,
|
||||
// Instead of comparing OpExecutionMode entry point ids as ids, compare them
|
||||
// through their corresponding execution model. This simplifies traversing
|
||||
// the sorted list of instructions between src and dst modules.
|
||||
if (a->opcode() == SpvOpExecutionMode) {
|
||||
const SpvExecutionModel src_model =
|
||||
if (a->opcode() == spv::Op::OpExecutionMode) {
|
||||
const spv::ExecutionModel src_model =
|
||||
GetExecutionModel(src_inst_module, a->GetSingleWordOperand(0));
|
||||
const SpvExecutionModel dst_model =
|
||||
const spv::ExecutionModel dst_model =
|
||||
GetExecutionModel(dst_inst_module, b->GetSingleWordOperand(0));
|
||||
|
||||
if (src_model < dst_model) {
|
||||
@ -818,17 +819,17 @@ uint32_t Differ::GroupIdsHelperGetTypeId(const IdInstructions& id_to,
|
||||
return GetInst(id_to, id)->type_id();
|
||||
}
|
||||
|
||||
SpvStorageClass Differ::GroupIdsHelperGetTypePointerStorageClass(
|
||||
spv::StorageClass Differ::GroupIdsHelperGetTypePointerStorageClass(
|
||||
const IdInstructions& id_to, uint32_t id) {
|
||||
const opt::Instruction* inst = GetInst(id_to, id);
|
||||
assert(inst && inst->opcode() == SpvOpTypePointer);
|
||||
return SpvStorageClass(inst->GetSingleWordInOperand(0));
|
||||
assert(inst && inst->opcode() == spv::Op::OpTypePointer);
|
||||
return spv::StorageClass(inst->GetSingleWordInOperand(0));
|
||||
}
|
||||
|
||||
SpvOp Differ::GroupIdsHelperGetTypePointerTypeOp(const IdInstructions& id_to,
|
||||
uint32_t id) {
|
||||
spv::Op Differ::GroupIdsHelperGetTypePointerTypeOp(const IdInstructions& id_to,
|
||||
uint32_t id) {
|
||||
const opt::Instruction* inst = GetInst(id_to, id);
|
||||
assert(inst && inst->opcode() == SpvOpTypePointer);
|
||||
assert(inst && inst->opcode() == spv::Op::OpTypePointer);
|
||||
|
||||
const uint32_t type_id = inst->GetSingleWordInOperand(1);
|
||||
const opt::Instruction* type_inst = GetInst(id_to, type_id);
|
||||
@ -1020,7 +1021,7 @@ bool Differ::DoInstructionsMatchFuzzy(const opt::Instruction* src_inst,
|
||||
}
|
||||
// For external instructions, make sure the set and opcode of the external
|
||||
// instruction matches too.
|
||||
if (src_inst->opcode() == SpvOpExtInst) {
|
||||
if (src_inst->opcode() == spv::Op::OpExtInst) {
|
||||
if (!DoOperandsMatch(src_inst, dst_inst, 0, 2)) {
|
||||
return false;
|
||||
}
|
||||
@ -1064,26 +1065,26 @@ bool Differ::DoDebugAndAnnotationInstructionsMatch(
|
||||
}
|
||||
|
||||
switch (src_inst->opcode()) {
|
||||
case SpvOpString:
|
||||
case SpvOpSourceExtension:
|
||||
case SpvOpModuleProcessed:
|
||||
case spv::Op::OpString:
|
||||
case spv::Op::OpSourceExtension:
|
||||
case spv::Op::OpModuleProcessed:
|
||||
return DoesOperandMatch(src_inst->GetOperand(0), dst_inst->GetOperand(0));
|
||||
case SpvOpSource:
|
||||
case spv::Op::OpSource:
|
||||
return DoOperandsMatch(src_inst, dst_inst, 0, 2);
|
||||
case SpvOpSourceContinued:
|
||||
case spv::Op::OpSourceContinued:
|
||||
return true;
|
||||
case SpvOpName:
|
||||
case spv::Op::OpName:
|
||||
return DoOperandsMatch(src_inst, dst_inst, 0, 1);
|
||||
case SpvOpMemberName:
|
||||
case spv::Op::OpMemberName:
|
||||
return DoOperandsMatch(src_inst, dst_inst, 0, 2);
|
||||
case SpvOpDecorate:
|
||||
case spv::Op::OpDecorate:
|
||||
return DoOperandsMatch(src_inst, dst_inst, 0, 2);
|
||||
case SpvOpMemberDecorate:
|
||||
case spv::Op::OpMemberDecorate:
|
||||
return DoOperandsMatch(src_inst, dst_inst, 0, 3);
|
||||
case SpvOpExtInst:
|
||||
case SpvOpDecorationGroup:
|
||||
case SpvOpGroupDecorate:
|
||||
case SpvOpGroupMemberDecorate:
|
||||
case spv::Op::OpExtInst:
|
||||
case spv::Op::OpDecorationGroup:
|
||||
case spv::Op::OpGroupDecorate:
|
||||
case spv::Op::OpGroupMemberDecorate:
|
||||
return false;
|
||||
default:
|
||||
return false;
|
||||
@ -1095,9 +1096,9 @@ bool Differ::AreVariablesMatchable(uint32_t src_id, uint32_t dst_id,
|
||||
// Variables must match by their built-in decorations.
|
||||
uint32_t src_built_in_decoration = 0, dst_built_in_decoration = 0;
|
||||
const bool src_is_built_in = GetDecorationValue(
|
||||
src_id_to_, src_id, SpvDecorationBuiltIn, &src_built_in_decoration);
|
||||
src_id_to_, src_id, spv::Decoration::BuiltIn, &src_built_in_decoration);
|
||||
const bool dst_is_built_in = GetDecorationValue(
|
||||
dst_id_to_, dst_id, SpvDecorationBuiltIn, &dst_built_in_decoration);
|
||||
dst_id_to_, dst_id, spv::Decoration::BuiltIn, &dst_built_in_decoration);
|
||||
|
||||
if (src_is_built_in != dst_is_built_in) {
|
||||
return false;
|
||||
@ -1107,7 +1108,7 @@ bool Differ::AreVariablesMatchable(uint32_t src_id, uint32_t dst_id,
|
||||
}
|
||||
|
||||
// Check their types and storage classes.
|
||||
SpvStorageClass src_storage_class, dst_storage_class;
|
||||
spv::StorageClass src_storage_class, dst_storage_class;
|
||||
const uint32_t src_type_id =
|
||||
GetVarTypeId(src_id_to_, src_id, &src_storage_class);
|
||||
const uint32_t dst_type_id =
|
||||
@ -1127,12 +1128,14 @@ bool Differ::AreVariablesMatchable(uint32_t src_id, uint32_t dst_id,
|
||||
// Allow one of the two to be Private while the other is Input or
|
||||
// Output, this allows matching in/out variables that have been turned
|
||||
// global as part of linking two stages (as done in ANGLE).
|
||||
const bool src_is_io = src_storage_class == SpvStorageClassInput ||
|
||||
src_storage_class == SpvStorageClassOutput;
|
||||
const bool dst_is_io = dst_storage_class == SpvStorageClassInput ||
|
||||
dst_storage_class == SpvStorageClassOutput;
|
||||
const bool src_is_private = src_storage_class == SpvStorageClassPrivate;
|
||||
const bool dst_is_private = dst_storage_class == SpvStorageClassPrivate;
|
||||
const bool src_is_io = src_storage_class == spv::StorageClass::Input ||
|
||||
src_storage_class == spv::StorageClass::Output;
|
||||
const bool dst_is_io = dst_storage_class == spv::StorageClass::Input ||
|
||||
dst_storage_class == spv::StorageClass::Output;
|
||||
const bool src_is_private =
|
||||
src_storage_class == spv::StorageClass::Private;
|
||||
const bool dst_is_private =
|
||||
dst_storage_class == spv::StorageClass::Private;
|
||||
|
||||
if (!((src_is_io && dst_is_private) || (src_is_private && dst_is_io))) {
|
||||
return false;
|
||||
@ -1277,16 +1280,16 @@ bool Differ::MatchOpSpecConstant(const opt::Instruction* src_inst,
|
||||
// Otherwise, match them by SpecId.
|
||||
uint32_t src_spec_id, dst_spec_id;
|
||||
|
||||
if (GetDecorationValue(src_id_to_, src_id, SpvDecorationSpecId,
|
||||
if (GetDecorationValue(src_id_to_, src_id, spv::Decoration::SpecId,
|
||||
&src_spec_id) &&
|
||||
GetDecorationValue(dst_id_to_, dst_id, SpvDecorationSpecId,
|
||||
GetDecorationValue(dst_id_to_, dst_id, spv::Decoration::SpecId,
|
||||
&dst_spec_id)) {
|
||||
return src_spec_id == dst_spec_id;
|
||||
}
|
||||
|
||||
// There is no SpecId decoration, while not practical, still valid.
|
||||
// SpecConstantOp don't have SpecId and can be matched by operands
|
||||
if (src_inst->opcode() == SpvOpSpecConstantOp) {
|
||||
if (src_inst->opcode() == spv::Op::OpSpecConstantOp) {
|
||||
if (src_inst->NumInOperandWords() == dst_inst->NumInOperandWords()) {
|
||||
return DoOperandsMatch(src_inst, dst_inst, 0,
|
||||
src_inst->NumInOperandWords());
|
||||
@ -1327,13 +1330,13 @@ bool Differ::MatchOpVariable(const opt::Instruction* src_inst,
|
||||
// built-in decorations.
|
||||
uint32_t src_built_in_decoration;
|
||||
const bool src_is_built_in = GetDecorationValue(
|
||||
src_id_to_, src_id, SpvDecorationBuiltIn, &src_built_in_decoration);
|
||||
src_id_to_, src_id, spv::Decoration::BuiltIn, &src_built_in_decoration);
|
||||
|
||||
if (src_is_built_in && AreVariablesMatchable(src_id, dst_id, flexibility)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
SpvStorageClass src_storage_class, dst_storage_class;
|
||||
spv::StorageClass src_storage_class, dst_storage_class;
|
||||
GetVarTypeId(src_id_to_, src_id, &src_storage_class);
|
||||
GetVarTypeId(dst_id_to_, dst_id, &dst_storage_class);
|
||||
|
||||
@ -1348,13 +1351,13 @@ bool Differ::MatchOpVariable(const opt::Instruction* src_inst,
|
||||
uint32_t src_binding = 0, dst_binding = 0;
|
||||
|
||||
const bool src_has_set = GetDecorationValue(
|
||||
src_id_to_, src_id, SpvDecorationDescriptorSet, &src_set);
|
||||
src_id_to_, src_id, spv::Decoration::DescriptorSet, &src_set);
|
||||
const bool dst_has_set = GetDecorationValue(
|
||||
dst_id_to_, dst_id, SpvDecorationDescriptorSet, &dst_set);
|
||||
const bool src_has_binding =
|
||||
GetDecorationValue(src_id_to_, src_id, SpvDecorationBinding, &src_set);
|
||||
const bool dst_has_binding =
|
||||
GetDecorationValue(dst_id_to_, dst_id, SpvDecorationBinding, &dst_set);
|
||||
dst_id_to_, dst_id, spv::Decoration::DescriptorSet, &dst_set);
|
||||
const bool src_has_binding = GetDecorationValue(
|
||||
src_id_to_, src_id, spv::Decoration::Binding, &src_set);
|
||||
const bool dst_has_binding = GetDecorationValue(
|
||||
dst_id_to_, dst_id, spv::Decoration::Binding, &dst_set);
|
||||
|
||||
if (src_has_set && dst_has_set && src_has_binding && dst_has_binding) {
|
||||
return src_set == dst_set && src_binding == dst_binding;
|
||||
@ -1367,9 +1370,9 @@ bool Differ::MatchOpVariable(const opt::Instruction* src_inst,
|
||||
uint32_t src_location, dst_location;
|
||||
|
||||
const bool src_has_location = GetDecorationValue(
|
||||
src_id_to_, src_id, SpvDecorationLocation, &src_location);
|
||||
src_id_to_, src_id, spv::Decoration::Location, &src_location);
|
||||
const bool dst_has_location = GetDecorationValue(
|
||||
dst_id_to_, dst_id, SpvDecorationLocation, &dst_location);
|
||||
dst_id_to_, dst_id, spv::Decoration::Location, &dst_location);
|
||||
|
||||
if (src_has_location && dst_has_location) {
|
||||
return src_location == dst_location;
|
||||
@ -1384,25 +1387,25 @@ bool Differ::MatchPerVertexType(uint32_t src_type_id, uint32_t dst_type_id) {
|
||||
// For gl_PerVertex, find the type pointer of this type (array) and make sure
|
||||
// the storage classes of src and dst match; geometry and tessellation shaders
|
||||
// have two instances of gl_PerVertex.
|
||||
SpvStorageClass src_storage_class =
|
||||
spv::StorageClass src_storage_class =
|
||||
GetPerVertexStorageClass(src_, src_type_id);
|
||||
SpvStorageClass dst_storage_class =
|
||||
spv::StorageClass dst_storage_class =
|
||||
GetPerVertexStorageClass(dst_, dst_type_id);
|
||||
|
||||
assert(src_storage_class == SpvStorageClassInput ||
|
||||
src_storage_class == SpvStorageClassOutput);
|
||||
assert(dst_storage_class == SpvStorageClassInput ||
|
||||
dst_storage_class == SpvStorageClassOutput);
|
||||
assert(src_storage_class == spv::StorageClass::Input ||
|
||||
src_storage_class == spv::StorageClass::Output);
|
||||
assert(dst_storage_class == spv::StorageClass::Input ||
|
||||
dst_storage_class == spv::StorageClass::Output);
|
||||
|
||||
return src_storage_class == dst_storage_class;
|
||||
}
|
||||
|
||||
bool Differ::MatchPerVertexVariable(const opt::Instruction* src_inst,
|
||||
const opt::Instruction* dst_inst) {
|
||||
SpvStorageClass src_storage_class =
|
||||
SpvStorageClass(src_inst->GetSingleWordInOperand(0));
|
||||
SpvStorageClass dst_storage_class =
|
||||
SpvStorageClass(dst_inst->GetSingleWordInOperand(0));
|
||||
spv::StorageClass src_storage_class =
|
||||
spv::StorageClass(src_inst->GetSingleWordInOperand(0));
|
||||
spv::StorageClass dst_storage_class =
|
||||
spv::StorageClass(dst_inst->GetSingleWordInOperand(0));
|
||||
|
||||
return src_storage_class == dst_storage_class;
|
||||
}
|
||||
@ -1479,7 +1482,7 @@ InstructionList Differ::GetFunctionHeader(const opt::Function& function) {
|
||||
InstructionList body;
|
||||
function.WhileEachInst(
|
||||
[&body](const opt::Instruction* inst) {
|
||||
if (inst->opcode() == SpvOpLabel) {
|
||||
if (inst->opcode() == spv::Op::OpLabel) {
|
||||
return false;
|
||||
}
|
||||
body.push_back(inst);
|
||||
@ -1694,12 +1697,12 @@ void Differ::MatchVariablesUsedByMatchedInstructions(
|
||||
default:
|
||||
// TODO: match functions based on OpFunctionCall?
|
||||
break;
|
||||
case SpvOpAccessChain:
|
||||
case SpvOpInBoundsAccessChain:
|
||||
case SpvOpPtrAccessChain:
|
||||
case SpvOpInBoundsPtrAccessChain:
|
||||
case SpvOpLoad:
|
||||
case SpvOpStore:
|
||||
case spv::Op::OpAccessChain:
|
||||
case spv::Op::OpInBoundsAccessChain:
|
||||
case spv::Op::OpPtrAccessChain:
|
||||
case spv::Op::OpInBoundsPtrAccessChain:
|
||||
case spv::Op::OpLoad:
|
||||
case spv::Op::OpStore:
|
||||
const uint32_t src_pointer_id = src_inst->GetSingleWordInOperand(0);
|
||||
const uint32_t dst_pointer_id = dst_inst->GetSingleWordInOperand(0);
|
||||
if (IsVariable(src_id_to_, src_pointer_id) &&
|
||||
@ -1727,23 +1730,24 @@ const opt::Instruction* Differ::GetInst(const IdInstructions& id_to,
|
||||
uint32_t Differ::GetConstantUint(const IdInstructions& id_to,
|
||||
uint32_t constant_id) {
|
||||
const opt::Instruction* constant_inst = GetInst(id_to, constant_id);
|
||||
assert(constant_inst->opcode() == SpvOpConstant);
|
||||
assert(GetInst(id_to, constant_inst->type_id())->opcode() == SpvOpTypeInt);
|
||||
assert(constant_inst->opcode() == spv::Op::OpConstant);
|
||||
assert(GetInst(id_to, constant_inst->type_id())->opcode() ==
|
||||
spv::Op::OpTypeInt);
|
||||
|
||||
return constant_inst->GetSingleWordInOperand(0);
|
||||
}
|
||||
|
||||
SpvExecutionModel Differ::GetExecutionModel(const opt::Module* module,
|
||||
uint32_t entry_point_id) {
|
||||
spv::ExecutionModel Differ::GetExecutionModel(const opt::Module* module,
|
||||
uint32_t entry_point_id) {
|
||||
for (const opt::Instruction& inst : module->entry_points()) {
|
||||
assert(inst.opcode() == SpvOpEntryPoint);
|
||||
assert(inst.opcode() == spv::Op::OpEntryPoint);
|
||||
if (inst.GetSingleWordOperand(1) == entry_point_id) {
|
||||
return SpvExecutionModel(inst.GetSingleWordOperand(0));
|
||||
return spv::ExecutionModel(inst.GetSingleWordOperand(0));
|
||||
}
|
||||
}
|
||||
|
||||
assert(false && "Unreachable");
|
||||
return SpvExecutionModel(0xFFF);
|
||||
return spv::ExecutionModel(0xFFF);
|
||||
}
|
||||
|
||||
bool Differ::HasName(const IdInstructions& id_to, uint32_t id) {
|
||||
@ -1751,7 +1755,7 @@ bool Differ::HasName(const IdInstructions& id_to, uint32_t id) {
|
||||
assert(id < id_to.name_map_.size());
|
||||
|
||||
for (const opt::Instruction* inst : id_to.name_map_[id]) {
|
||||
if (inst->opcode() == SpvOpName) {
|
||||
if (inst->opcode() == spv::Op::OpName) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@ -1765,7 +1769,7 @@ std::string Differ::GetName(const IdInstructions& id_to, uint32_t id,
|
||||
assert(id < id_to.name_map_.size());
|
||||
|
||||
for (const opt::Instruction* inst : id_to.name_map_[id]) {
|
||||
if (inst->opcode() == SpvOpName) {
|
||||
if (inst->opcode() == spv::Op::OpName) {
|
||||
*has_name = true;
|
||||
return inst->GetOperand(1).AsString();
|
||||
}
|
||||
@ -1788,11 +1792,11 @@ std::string Differ::GetSanitizedName(const IdInstructions& id_to, uint32_t id) {
|
||||
}
|
||||
|
||||
uint32_t Differ::GetVarTypeId(const IdInstructions& id_to, uint32_t var_id,
|
||||
SpvStorageClass* storage_class) {
|
||||
spv::StorageClass* storage_class) {
|
||||
const opt::Instruction* var_inst = GetInst(id_to, var_id);
|
||||
assert(var_inst->opcode() == SpvOpVariable);
|
||||
assert(var_inst->opcode() == spv::Op::OpVariable);
|
||||
|
||||
*storage_class = SpvStorageClass(var_inst->GetSingleWordInOperand(0));
|
||||
*storage_class = spv::StorageClass(var_inst->GetSingleWordInOperand(0));
|
||||
|
||||
// Get the type pointer from the variable.
|
||||
const uint32_t type_pointer_id = var_inst->type_id();
|
||||
@ -1803,15 +1807,15 @@ uint32_t Differ::GetVarTypeId(const IdInstructions& id_to, uint32_t var_id,
|
||||
}
|
||||
|
||||
bool Differ::GetDecorationValue(const IdInstructions& id_to, uint32_t id,
|
||||
SpvDecoration decoration,
|
||||
spv::Decoration decoration,
|
||||
uint32_t* decoration_value) {
|
||||
assert(id != 0);
|
||||
assert(id < id_to.decoration_map_.size());
|
||||
|
||||
for (const opt::Instruction* inst : id_to.decoration_map_[id]) {
|
||||
if (inst->opcode() == SpvOpDecorate &&
|
||||
if (inst->opcode() == spv::Op::OpDecorate &&
|
||||
inst->GetSingleWordOperand(0) == id &&
|
||||
inst->GetSingleWordOperand(1) == decoration) {
|
||||
spv::Decoration(inst->GetSingleWordOperand(1)) == decoration) {
|
||||
*decoration_value = inst->GetSingleWordOperand(2);
|
||||
return true;
|
||||
}
|
||||
@ -1828,28 +1832,28 @@ const opt::Instruction* Differ::GetForwardPointerInst(
|
||||
}
|
||||
|
||||
bool Differ::IsIntType(const IdInstructions& id_to, uint32_t type_id) {
|
||||
return IsOp(id_to, type_id, SpvOpTypeInt);
|
||||
return IsOp(id_to, type_id, spv::Op::OpTypeInt);
|
||||
}
|
||||
|
||||
bool Differ::IsFloatType(const IdInstructions& id_to, uint32_t type_id) {
|
||||
return IsOp(id_to, type_id, SpvOpTypeFloat);
|
||||
return IsOp(id_to, type_id, spv::Op::OpTypeFloat);
|
||||
}
|
||||
|
||||
bool Differ::IsConstantUint(const IdInstructions& id_to, uint32_t id) {
|
||||
const opt::Instruction* constant_inst = GetInst(id_to, id);
|
||||
if (constant_inst->opcode() != SpvOpConstant) {
|
||||
if (constant_inst->opcode() != spv::Op::OpConstant) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const opt::Instruction* type_inst = GetInst(id_to, constant_inst->type_id());
|
||||
return type_inst->opcode() == SpvOpTypeInt;
|
||||
return type_inst->opcode() == spv::Op::OpTypeInt;
|
||||
}
|
||||
|
||||
bool Differ::IsVariable(const IdInstructions& id_to, uint32_t pointer_id) {
|
||||
return IsOp(id_to, pointer_id, SpvOpVariable);
|
||||
return IsOp(id_to, pointer_id, spv::Op::OpVariable);
|
||||
}
|
||||
|
||||
bool Differ::IsOp(const IdInstructions& id_to, uint32_t id, SpvOp op) {
|
||||
bool Differ::IsOp(const IdInstructions& id_to, uint32_t id, spv::Op op) {
|
||||
return GetInst(id_to, id)->opcode() == op;
|
||||
}
|
||||
|
||||
@ -1858,17 +1862,18 @@ bool Differ::IsPerVertexType(const IdInstructions& id_to, uint32_t type_id) {
|
||||
assert(type_id < id_to.decoration_map_.size());
|
||||
|
||||
for (const opt::Instruction* inst : id_to.decoration_map_[type_id]) {
|
||||
if (inst->opcode() == SpvOpMemberDecorate &&
|
||||
if (inst->opcode() == spv::Op::OpMemberDecorate &&
|
||||
inst->GetSingleWordOperand(0) == type_id &&
|
||||
inst->GetSingleWordOperand(2) == SpvDecorationBuiltIn) {
|
||||
SpvBuiltIn built_in = SpvBuiltIn(inst->GetSingleWordOperand(3));
|
||||
spv::Decoration(inst->GetSingleWordOperand(2)) ==
|
||||
spv::Decoration::BuiltIn) {
|
||||
spv::BuiltIn built_in = spv::BuiltIn(inst->GetSingleWordOperand(3));
|
||||
|
||||
// Only gl_PerVertex can have, and it can only have, the following
|
||||
// built-in decorations.
|
||||
return built_in == SpvBuiltInPosition ||
|
||||
built_in == SpvBuiltInPointSize ||
|
||||
built_in == SpvBuiltInClipDistance ||
|
||||
built_in == SpvBuiltInCullDistance;
|
||||
return built_in == spv::BuiltIn::Position ||
|
||||
built_in == spv::BuiltIn::PointSize ||
|
||||
built_in == spv::BuiltIn::ClipDistance ||
|
||||
built_in == spv::BuiltIn::CullDistance;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1877,12 +1882,12 @@ bool Differ::IsPerVertexType(const IdInstructions& id_to, uint32_t type_id) {
|
||||
|
||||
bool Differ::IsPerVertexVariable(const IdInstructions& id_to, uint32_t var_id) {
|
||||
// Get the type from the type pointer.
|
||||
SpvStorageClass storage_class;
|
||||
spv::StorageClass storage_class;
|
||||
uint32_t type_id = GetVarTypeId(id_to, var_id, &storage_class);
|
||||
const opt::Instruction* type_inst = GetInst(id_to, type_id);
|
||||
|
||||
// If array, get the element type.
|
||||
if (type_inst->opcode() == SpvOpTypeArray) {
|
||||
if (type_inst->opcode() == spv::Op::OpTypeArray) {
|
||||
type_id = type_inst->GetSingleWordInOperand(0);
|
||||
}
|
||||
|
||||
@ -1890,21 +1895,21 @@ bool Differ::IsPerVertexVariable(const IdInstructions& id_to, uint32_t var_id) {
|
||||
return IsPerVertexType(id_to, type_id);
|
||||
}
|
||||
|
||||
SpvStorageClass Differ::GetPerVertexStorageClass(const opt::Module* module,
|
||||
uint32_t type_id) {
|
||||
spv::StorageClass Differ::GetPerVertexStorageClass(const opt::Module* module,
|
||||
uint32_t type_id) {
|
||||
for (const opt::Instruction& inst : module->types_values()) {
|
||||
switch (inst.opcode()) {
|
||||
case SpvOpTypeArray:
|
||||
case spv::Op::OpTypeArray:
|
||||
// The gl_PerVertex instance could be an array, look for a variable of
|
||||
// the array type instead.
|
||||
if (inst.GetSingleWordInOperand(0) == type_id) {
|
||||
type_id = inst.result_id();
|
||||
}
|
||||
break;
|
||||
case SpvOpTypePointer:
|
||||
case spv::Op::OpTypePointer:
|
||||
// Find the storage class of the pointer to this type.
|
||||
if (inst.GetSingleWordInOperand(1) == type_id) {
|
||||
return SpvStorageClass(inst.GetSingleWordInOperand(0));
|
||||
return spv::StorageClass(inst.GetSingleWordInOperand(0));
|
||||
}
|
||||
break;
|
||||
default:
|
||||
@ -1915,7 +1920,7 @@ SpvStorageClass Differ::GetPerVertexStorageClass(const opt::Module* module,
|
||||
// gl_PerVertex is declared, but is unused. Return either of Input or Output
|
||||
// classes just so it matches one in the other module. This should be highly
|
||||
// unlikely, perhaps except for ancient GS-used-to-emulate-CS scenarios.
|
||||
return SpvStorageClassOutput;
|
||||
return spv::StorageClass::Output;
|
||||
}
|
||||
|
||||
spv_ext_inst_type_t Differ::GetExtInstType(const IdInstructions& id_to,
|
||||
@ -1941,9 +1946,9 @@ spv_number_kind_t Differ::GetNumberKind(const IdInstructions& id_to,
|
||||
case SPV_OPERAND_TYPE_TYPED_LITERAL_NUMBER:
|
||||
case SPV_OPERAND_TYPE_OPTIONAL_TYPED_LITERAL_INTEGER:
|
||||
switch (inst.opcode()) {
|
||||
case SpvOpSwitch:
|
||||
case SpvOpConstant:
|
||||
case SpvOpSpecConstant:
|
||||
case spv::Op::OpSwitch:
|
||||
case spv::Op::OpConstant:
|
||||
case spv::Op::OpSpecConstant:
|
||||
// Same kind of number as the selector (OpSwitch) or the type
|
||||
// (Op*Constant).
|
||||
return GetTypeNumberKind(id_to, inst.GetSingleWordOperand(0),
|
||||
@ -1969,12 +1974,12 @@ spv_number_kind_t Differ::GetTypeNumberKind(const IdInstructions& id_to,
|
||||
}
|
||||
|
||||
switch (type_inst->opcode()) {
|
||||
case SpvOpTypeInt:
|
||||
case spv::Op::OpTypeInt:
|
||||
*number_bit_width = type_inst->GetSingleWordOperand(1);
|
||||
return type_inst->GetSingleWordOperand(2) == 0 ? SPV_NUMBER_UNSIGNED_INT
|
||||
: SPV_NUMBER_SIGNED_INT;
|
||||
break;
|
||||
case SpvOpTypeFloat:
|
||||
case spv::Op::OpTypeFloat:
|
||||
*number_bit_width = type_inst->GetSingleWordOperand(1);
|
||||
return SPV_NUMBER_FLOATING;
|
||||
default:
|
||||
@ -2092,7 +2097,7 @@ void Differ::MatchTypeForwardPointers() {
|
||||
return inst.GetSingleWordOperand(0);
|
||||
};
|
||||
auto accept_type_forward_pointer_ops = [](const opt::Instruction& inst) {
|
||||
return inst.opcode() == SpvOpTypeForwardPointer;
|
||||
return inst.opcode() == spv::Op::OpTypeForwardPointer;
|
||||
};
|
||||
|
||||
PoolPotentialIds(src_->types_values(), potential_id_map.src_ids, true,
|
||||
@ -2116,17 +2121,17 @@ void Differ::MatchTypeForwardPointers() {
|
||||
// - If leftover is unique, match
|
||||
|
||||
// Group forwarded pointers by storage class first and loop over them.
|
||||
GroupIdsAndMatch<SpvStorageClass>(
|
||||
potential_id_map.src_ids, potential_id_map.dst_ids, SpvStorageClassMax,
|
||||
&Differ::GroupIdsHelperGetTypePointerStorageClass,
|
||||
GroupIdsAndMatch<spv::StorageClass>(
|
||||
potential_id_map.src_ids, potential_id_map.dst_ids,
|
||||
spv::StorageClass::Max, &Differ::GroupIdsHelperGetTypePointerStorageClass,
|
||||
[this](const IdGroup& src_group_by_storage_class,
|
||||
const IdGroup& dst_group_by_storage_class) {
|
||||
|
||||
// Group them further by the type they are pointing to and loop over
|
||||
// them.
|
||||
GroupIdsAndMatch<SpvOp>(
|
||||
src_group_by_storage_class, dst_group_by_storage_class, SpvOpMax,
|
||||
&Differ::GroupIdsHelperGetTypePointerTypeOp,
|
||||
GroupIdsAndMatch<spv::Op>(
|
||||
src_group_by_storage_class, dst_group_by_storage_class,
|
||||
spv::Op::Max, &Differ::GroupIdsHelperGetTypePointerTypeOp,
|
||||
[this](const IdGroup& src_group_by_type_op,
|
||||
const IdGroup& dst_group_by_type_op) {
|
||||
|
||||
@ -2182,8 +2187,8 @@ void Differ::MatchTypeIds() {
|
||||
MatchIds(potential_id_map, [this, flexibility](
|
||||
const opt::Instruction* src_inst,
|
||||
const opt::Instruction* dst_inst) {
|
||||
const SpvOp src_op = src_inst->opcode();
|
||||
const SpvOp dst_op = dst_inst->opcode();
|
||||
const spv::Op src_op = src_inst->opcode();
|
||||
const spv::Op dst_op = dst_inst->opcode();
|
||||
|
||||
// Don't match if the opcode is not the same.
|
||||
if (src_op != dst_op) {
|
||||
@ -2191,26 +2196,26 @@ void Differ::MatchTypeIds() {
|
||||
}
|
||||
|
||||
switch (src_op) {
|
||||
case SpvOpTypeVoid:
|
||||
case SpvOpTypeBool:
|
||||
case SpvOpTypeSampler:
|
||||
case spv::Op::OpTypeVoid:
|
||||
case spv::Op::OpTypeBool:
|
||||
case spv::Op::OpTypeSampler:
|
||||
// void, bool and sampler are unique, match them.
|
||||
return true;
|
||||
case SpvOpTypeInt:
|
||||
case SpvOpTypeFloat:
|
||||
case SpvOpTypeVector:
|
||||
case SpvOpTypeMatrix:
|
||||
case SpvOpTypeSampledImage:
|
||||
case SpvOpTypeRuntimeArray:
|
||||
case SpvOpTypePointer:
|
||||
case spv::Op::OpTypeInt:
|
||||
case spv::Op::OpTypeFloat:
|
||||
case spv::Op::OpTypeVector:
|
||||
case spv::Op::OpTypeMatrix:
|
||||
case spv::Op::OpTypeSampledImage:
|
||||
case spv::Op::OpTypeRuntimeArray:
|
||||
case spv::Op::OpTypePointer:
|
||||
// Match these instructions when all operands match.
|
||||
assert(src_inst->NumInOperandWords() ==
|
||||
dst_inst->NumInOperandWords());
|
||||
return DoOperandsMatch(src_inst, dst_inst, 0,
|
||||
src_inst->NumInOperandWords());
|
||||
|
||||
case SpvOpTypeFunction:
|
||||
case SpvOpTypeImage:
|
||||
case spv::Op::OpTypeFunction:
|
||||
case spv::Op::OpTypeImage:
|
||||
// Match function types only if they have the same number of operands,
|
||||
// and they all match.
|
||||
// Match image types similarly, expecting the optional final parameter
|
||||
@ -2221,7 +2226,7 @@ void Differ::MatchTypeIds() {
|
||||
return DoOperandsMatch(src_inst, dst_inst, 0,
|
||||
src_inst->NumInOperandWords());
|
||||
|
||||
case SpvOpTypeArray:
|
||||
case spv::Op::OpTypeArray:
|
||||
// Match arrays only if the element type and length match. The length
|
||||
// is an id of a constant, so the actual constant it's defining is
|
||||
// compared instead.
|
||||
@ -2238,7 +2243,7 @@ void Differ::MatchTypeIds() {
|
||||
// example if a spec contant is used).
|
||||
return DoOperandsMatch(src_inst, dst_inst, 1, 1);
|
||||
|
||||
case SpvOpTypeStruct:
|
||||
case spv::Op::OpTypeStruct:
|
||||
return MatchOpTypeStruct(src_inst, dst_inst, flexibility);
|
||||
|
||||
default:
|
||||
@ -2270,8 +2275,8 @@ void Differ::MatchConstants() {
|
||||
MatchIds(potential_id_map, [this, flexibility](
|
||||
const opt::Instruction* src_inst,
|
||||
const opt::Instruction* dst_inst) {
|
||||
const SpvOp src_op = src_inst->opcode();
|
||||
const SpvOp dst_op = dst_inst->opcode();
|
||||
const spv::Op src_op = src_inst->opcode();
|
||||
const spv::Op dst_op = dst_inst->opcode();
|
||||
|
||||
// Don't match if the opcode is not the same.
|
||||
if (src_op != dst_op) {
|
||||
@ -2279,14 +2284,14 @@ void Differ::MatchConstants() {
|
||||
}
|
||||
|
||||
switch (src_op) {
|
||||
case SpvOpConstantTrue:
|
||||
case SpvOpConstantFalse:
|
||||
case spv::Op::OpConstantTrue:
|
||||
case spv::Op::OpConstantFalse:
|
||||
// true and false are unique, match them.
|
||||
return true;
|
||||
case SpvOpConstant:
|
||||
case spv::Op::OpConstant:
|
||||
return MatchOpConstant(src_inst, dst_inst, flexibility);
|
||||
case SpvOpConstantComposite:
|
||||
case SpvOpSpecConstantComposite:
|
||||
case spv::Op::OpConstantComposite:
|
||||
case spv::Op::OpSpecConstantComposite:
|
||||
// Composite constants must match in type and value.
|
||||
//
|
||||
// TODO: match OpConstantNull with OpConstantComposite with all zeros
|
||||
@ -2299,7 +2304,7 @@ void Differ::MatchConstants() {
|
||||
dst_inst->GetOperand(0)) &&
|
||||
DoOperandsMatch(src_inst, dst_inst, 0,
|
||||
src_inst->NumInOperandWords());
|
||||
case SpvOpConstantSampler:
|
||||
case spv::Op::OpConstantSampler:
|
||||
// Match sampler constants exactly.
|
||||
// TODO: Allow flexibility in parameters to better diff shaders where
|
||||
// the sampler param has changed.
|
||||
@ -2307,15 +2312,15 @@ void Differ::MatchConstants() {
|
||||
dst_inst->NumInOperandWords());
|
||||
return DoOperandsMatch(src_inst, dst_inst, 0,
|
||||
src_inst->NumInOperandWords());
|
||||
case SpvOpConstantNull:
|
||||
case spv::Op::OpConstantNull:
|
||||
// Match null constants as long as the type matches.
|
||||
return DoesOperandMatch(src_inst->GetOperand(0),
|
||||
dst_inst->GetOperand(0));
|
||||
|
||||
case SpvOpSpecConstantTrue:
|
||||
case SpvOpSpecConstantFalse:
|
||||
case SpvOpSpecConstant:
|
||||
case SpvOpSpecConstantOp:
|
||||
case spv::Op::OpSpecConstantTrue:
|
||||
case spv::Op::OpSpecConstantFalse:
|
||||
case spv::Op::OpSpecConstant:
|
||||
case spv::Op::OpSpecConstantOp:
|
||||
// Match spec constants by name if available, then by the SpecId
|
||||
// decoration.
|
||||
return MatchOpSpecConstant(src_inst, dst_inst);
|
||||
@ -2334,7 +2339,7 @@ void Differ::MatchVariableIds() {
|
||||
return inst.result_id();
|
||||
};
|
||||
auto accept_type_ops = [](const opt::Instruction& inst) {
|
||||
return inst.opcode() == SpvOpVariable;
|
||||
return inst.opcode() == spv::Op::OpVariable;
|
||||
};
|
||||
|
||||
PoolPotentialIds(src_->types_values(), potential_id_map.src_ids, true,
|
||||
@ -2350,8 +2355,8 @@ void Differ::MatchVariableIds() {
|
||||
MatchIds(potential_id_map,
|
||||
[this, flexibility](const opt::Instruction* src_inst,
|
||||
const opt::Instruction* dst_inst) {
|
||||
assert(src_inst->opcode() == SpvOpVariable);
|
||||
assert(dst_inst->opcode() == SpvOpVariable);
|
||||
assert(src_inst->opcode() == spv::Op::OpVariable);
|
||||
assert(dst_inst->opcode() == spv::Op::OpVariable);
|
||||
|
||||
return MatchOpVariable(src_inst, dst_inst, flexibility);
|
||||
});
|
||||
@ -2597,7 +2602,7 @@ void Differ::ToParsedInstruction(
|
||||
parsed_inst->num_words = static_cast<uint16_t>(inst_binary.size());
|
||||
parsed_inst->opcode = static_cast<uint16_t>(inst.opcode());
|
||||
parsed_inst->ext_inst_type =
|
||||
inst.opcode() == SpvOpExtInst
|
||||
inst.opcode() == spv::Op::OpExtInst
|
||||
? GetExtInstType(id_to, original_inst.GetSingleWordInOperand(0))
|
||||
: SPV_EXT_INST_TYPE_NONE;
|
||||
parsed_inst->type_id =
|
||||
|
@ -244,7 +244,7 @@ void InstructionDisassembler::EmitHeaderSchema(uint32_t schema) {
|
||||
|
||||
void InstructionDisassembler::EmitInstruction(
|
||||
const spv_parsed_instruction_t& inst, size_t inst_byte_offset) {
|
||||
auto opcode = static_cast<SpvOp>(inst.opcode);
|
||||
auto opcode = static_cast<spv::Op>(inst.opcode);
|
||||
|
||||
if (inst.result_id) {
|
||||
SetBlue();
|
||||
@ -268,7 +268,7 @@ void InstructionDisassembler::EmitInstruction(
|
||||
EmitOperand(inst, i);
|
||||
}
|
||||
|
||||
if (comment_ && opcode == SpvOpName) {
|
||||
if (comment_ && opcode == spv::Op::OpName) {
|
||||
const spv_parsed_operand_t& operand = inst.operands[0];
|
||||
const uint32_t word = inst.words[operand.offset];
|
||||
stream_ << " ; id %" << word;
|
||||
@ -290,8 +290,8 @@ void InstructionDisassembler::EmitInstruction(
|
||||
void InstructionDisassembler::EmitSectionComment(
|
||||
const spv_parsed_instruction_t& inst, bool& inserted_decoration_space,
|
||||
bool& inserted_debug_space, bool& inserted_type_space) {
|
||||
auto opcode = static_cast<SpvOp>(inst.opcode);
|
||||
if (comment_ && opcode == SpvOpFunction) {
|
||||
auto opcode = static_cast<spv::Op>(inst.opcode);
|
||||
if (comment_ && opcode == spv::Op::OpFunction) {
|
||||
stream_ << std::endl;
|
||||
stream_ << std::string(indent_, ' ');
|
||||
stream_ << "; Function " << name_mapper_(inst.result_id) << std::endl;
|
||||
@ -351,7 +351,7 @@ void InstructionDisassembler::EmitOperand(const spv_parsed_instruction_t& inst,
|
||||
} break;
|
||||
case SPV_OPERAND_TYPE_SPEC_CONSTANT_OP_NUMBER: {
|
||||
spv_opcode_desc opcode_desc;
|
||||
if (grammar_.lookupOpcode(SpvOp(word), &opcode_desc))
|
||||
if (grammar_.lookupOpcode(spv::Op(word), &opcode_desc))
|
||||
assert(false && "should have caught this earlier");
|
||||
SetRed();
|
||||
stream_ << opcode_desc->name;
|
||||
|
@ -200,8 +200,8 @@ class EnumSet {
|
||||
std::unique_ptr<OverflowSetType> overflow_ = {};
|
||||
};
|
||||
|
||||
// A set of SpvCapability, optimized for small capability values.
|
||||
using CapabilitySet = EnumSet<SpvCapability>;
|
||||
// A set of spv::Capability, optimized for small capability values.
|
||||
using CapabilitySet = EnumSet<spv::Capability>;
|
||||
|
||||
} // namespace spvtools
|
||||
|
||||
|
@ -29,7 +29,7 @@ bool GetExtensionFromString(const char* str, Extension* extension);
|
||||
const char* ExtensionToString(Extension extension);
|
||||
|
||||
// Returns text string corresponding to |capability|.
|
||||
const char* CapabilityToString(SpvCapability capability);
|
||||
const char* CapabilityToString(spv::Capability capability);
|
||||
|
||||
} // namespace spvtools
|
||||
|
||||
|
@ -24,7 +24,9 @@
|
||||
namespace spvtools {
|
||||
|
||||
std::string GetExtensionString(const spv_parsed_instruction_t* inst) {
|
||||
if (inst->opcode != SpvOpExtension) return "ERROR_not_op_extension";
|
||||
if (inst->opcode != static_cast<uint16_t>(spv::Op::OpExtension)) {
|
||||
return "ERROR_not_op_extension";
|
||||
}
|
||||
|
||||
assert(inst->num_operands == 1);
|
||||
|
||||
|
@ -130,7 +130,7 @@ bool AddedFunctionReducer::InterestingnessFunctionForReducingAddedFunction(
|
||||
binary_under_reduction.size());
|
||||
assert(ir_context != nullptr && "The binary should be parsable.");
|
||||
for (auto& type_or_value : ir_context->module()->types_values()) {
|
||||
if (type_or_value.opcode() != SpvOpVariable) {
|
||||
if (type_or_value.opcode() != spv::Op::OpVariable) {
|
||||
continue;
|
||||
}
|
||||
if (irrelevant_pointee_global_variables.count(type_or_value.result_id())) {
|
||||
@ -202,7 +202,7 @@ void AddedFunctionReducer::ReplayPrefixAndAddFunction(
|
||||
auto* ir_context = replay_result.transformed_module.get();
|
||||
|
||||
for (auto& type_or_value : ir_context->module()->types_values()) {
|
||||
if (type_or_value.opcode() != SpvOpVariable) {
|
||||
if (type_or_value.opcode() != spv::Op::OpVariable) {
|
||||
continue;
|
||||
}
|
||||
if (replay_result.transformation_context->GetFactManager()
|
||||
|
@ -54,7 +54,7 @@ void CallGraph::BuildGraphAndGetDepthOfFunctionCalls(
|
||||
// Consider every function call instruction in every block.
|
||||
for (auto& block : function) {
|
||||
for (auto& instruction : block) {
|
||||
if (instruction.opcode() != SpvOpFunctionCall) {
|
||||
if (instruction.opcode() != spv::Op::OpFunctionCall) {
|
||||
continue;
|
||||
}
|
||||
// Get the id of the function being called.
|
||||
|
@ -63,7 +63,7 @@ std::vector<uint32_t> ConstantUniformFacts::GetConstantWords(
|
||||
bool ConstantUniformFacts::DataMatches(
|
||||
const opt::Instruction& constant_instruction,
|
||||
const protobufs::FactConstantUniform& constant_uniform_fact) {
|
||||
assert(constant_instruction.opcode() == SpvOpConstant);
|
||||
assert(constant_instruction.opcode() == spv::Op::OpConstant);
|
||||
std::vector<uint32_t> data_in_constant;
|
||||
for (uint32_t i = 0; i < constant_instruction.NumInOperands(); i++) {
|
||||
data_in_constant.push_back(constant_instruction.GetSingleWordInOperand(i));
|
||||
@ -95,7 +95,7 @@ ConstantUniformFacts::GetUniformDescriptorsForConstant(
|
||||
uint32_t constant_id) const {
|
||||
std::vector<protobufs::UniformBufferElementDescriptor> result;
|
||||
auto constant_inst = ir_context_->get_def_use_mgr()->GetDef(constant_id);
|
||||
assert(constant_inst->opcode() == SpvOpConstant &&
|
||||
assert(constant_inst->opcode() == spv::Op::OpConstant &&
|
||||
"The given id must be that of a constant");
|
||||
auto type_id = constant_inst->type_id();
|
||||
for (auto& fact_and_type_id : facts_and_type_ids_) {
|
||||
@ -175,8 +175,9 @@ bool ConstantUniformFacts::MaybeAddFact(
|
||||
return false;
|
||||
}
|
||||
|
||||
assert(SpvOpVariable == uniform_variable->opcode());
|
||||
assert(SpvStorageClassUniform == uniform_variable->GetSingleWordInOperand(0));
|
||||
assert(spv::Op::OpVariable == uniform_variable->opcode());
|
||||
assert(spv::StorageClass::Uniform ==
|
||||
spv::StorageClass(uniform_variable->GetSingleWordInOperand(0)));
|
||||
|
||||
auto should_be_uniform_pointer_type =
|
||||
ir_context_->get_type_mgr()->GetType(uniform_variable->type_id());
|
||||
@ -184,7 +185,7 @@ bool ConstantUniformFacts::MaybeAddFact(
|
||||
return false;
|
||||
}
|
||||
if (should_be_uniform_pointer_type->AsPointer()->storage_class() !=
|
||||
SpvStorageClassUniform) {
|
||||
spv::StorageClass::Uniform) {
|
||||
return false;
|
||||
}
|
||||
auto should_be_uniform_pointer_instruction =
|
||||
|
@ -23,7 +23,7 @@ namespace fact_manager {
|
||||
size_t DataSynonymAndIdEquationFacts::OperationHash::operator()(
|
||||
const Operation& operation) const {
|
||||
std::u32string hash;
|
||||
hash.push_back(operation.opcode);
|
||||
hash.push_back(uint32_t(operation.opcode));
|
||||
for (auto operand : operation.operands) {
|
||||
hash.push_back(static_cast<uint32_t>(DataDescriptorHash()(operand)));
|
||||
}
|
||||
@ -104,7 +104,8 @@ bool DataSynonymAndIdEquationFacts::MaybeAddFact(
|
||||
}
|
||||
|
||||
// Now add the fact.
|
||||
AddEquationFactRecursive(lhs_dd, static_cast<SpvOp>(fact.opcode()), rhs_dds);
|
||||
AddEquationFactRecursive(lhs_dd, static_cast<spv::Op>(fact.opcode()),
|
||||
rhs_dds);
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -119,7 +120,7 @@ DataSynonymAndIdEquationFacts::GetEquations(
|
||||
}
|
||||
|
||||
void DataSynonymAndIdEquationFacts::AddEquationFactRecursive(
|
||||
const protobufs::DataDescriptor& lhs_dd, SpvOp opcode,
|
||||
const protobufs::DataDescriptor& lhs_dd, spv::Op opcode,
|
||||
const std::vector<const protobufs::DataDescriptor*>& rhs_dds) {
|
||||
assert(synonymous_.Exists(lhs_dd) &&
|
||||
"The LHS must be known to the equivalence relation.");
|
||||
@ -155,21 +156,21 @@ void DataSynonymAndIdEquationFacts::AddEquationFactRecursive(
|
||||
// Now try to work out corollaries implied by the new equation and existing
|
||||
// facts.
|
||||
switch (opcode) {
|
||||
case SpvOpConvertSToF:
|
||||
case SpvOpConvertUToF:
|
||||
case spv::Op::OpConvertSToF:
|
||||
case spv::Op::OpConvertUToF:
|
||||
ComputeConversionDataSynonymFacts(*rhs_dds[0]);
|
||||
break;
|
||||
case SpvOpBitcast: {
|
||||
case spv::Op::OpBitcast: {
|
||||
assert(DataDescriptorsAreWellFormedAndComparable(lhs_dd, *rhs_dds[0]) &&
|
||||
"Operands of OpBitcast equation fact must have compatible types");
|
||||
if (!synonymous_.IsEquivalent(lhs_dd, *rhs_dds[0])) {
|
||||
AddDataSynonymFactRecursive(lhs_dd, *rhs_dds[0]);
|
||||
}
|
||||
} break;
|
||||
case SpvOpIAdd: {
|
||||
case spv::Op::OpIAdd: {
|
||||
// Equation form: "a = b + c"
|
||||
for (const auto& equation : GetEquations(rhs_dds[0])) {
|
||||
if (equation.opcode == SpvOpISub) {
|
||||
if (equation.opcode == spv::Op::OpISub) {
|
||||
// Equation form: "a = (d - e) + c"
|
||||
if (synonymous_.IsEquivalent(*equation.operands[1], *rhs_dds[1])) {
|
||||
// Equation form: "a = (d - c) + c"
|
||||
@ -179,7 +180,7 @@ void DataSynonymAndIdEquationFacts::AddEquationFactRecursive(
|
||||
}
|
||||
}
|
||||
for (const auto& equation : GetEquations(rhs_dds[1])) {
|
||||
if (equation.opcode == SpvOpISub) {
|
||||
if (equation.opcode == spv::Op::OpISub) {
|
||||
// Equation form: "a = b + (d - e)"
|
||||
if (synonymous_.IsEquivalent(*equation.operands[1], *rhs_dds[0])) {
|
||||
// Equation form: "a = b + (d - b)"
|
||||
@ -190,10 +191,10 @@ void DataSynonymAndIdEquationFacts::AddEquationFactRecursive(
|
||||
}
|
||||
break;
|
||||
}
|
||||
case SpvOpISub: {
|
||||
case spv::Op::OpISub: {
|
||||
// Equation form: "a = b - c"
|
||||
for (const auto& equation : GetEquations(rhs_dds[0])) {
|
||||
if (equation.opcode == SpvOpIAdd) {
|
||||
if (equation.opcode == spv::Op::OpIAdd) {
|
||||
// Equation form: "a = (d + e) - c"
|
||||
if (synonymous_.IsEquivalent(*equation.operands[0], *rhs_dds[1])) {
|
||||
// Equation form: "a = (c + e) - c"
|
||||
@ -207,34 +208,34 @@ void DataSynonymAndIdEquationFacts::AddEquationFactRecursive(
|
||||
}
|
||||
}
|
||||
|
||||
if (equation.opcode == SpvOpISub) {
|
||||
if (equation.opcode == spv::Op::OpISub) {
|
||||
// Equation form: "a = (d - e) - c"
|
||||
if (synonymous_.IsEquivalent(*equation.operands[0], *rhs_dds[1])) {
|
||||
// Equation form: "a = (c - e) - c"
|
||||
// We can thus infer "a = -e"
|
||||
AddEquationFactRecursive(lhs_dd, SpvOpSNegate,
|
||||
AddEquationFactRecursive(lhs_dd, spv::Op::OpSNegate,
|
||||
{equation.operands[1]});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (const auto& equation : GetEquations(rhs_dds[1])) {
|
||||
if (equation.opcode == SpvOpIAdd) {
|
||||
if (equation.opcode == spv::Op::OpIAdd) {
|
||||
// Equation form: "a = b - (d + e)"
|
||||
if (synonymous_.IsEquivalent(*equation.operands[0], *rhs_dds[0])) {
|
||||
// Equation form: "a = b - (b + e)"
|
||||
// We can thus infer "a = -e"
|
||||
AddEquationFactRecursive(lhs_dd, SpvOpSNegate,
|
||||
AddEquationFactRecursive(lhs_dd, spv::Op::OpSNegate,
|
||||
{equation.operands[1]});
|
||||
}
|
||||
if (synonymous_.IsEquivalent(*equation.operands[1], *rhs_dds[0])) {
|
||||
// Equation form: "a = b - (d + b)"
|
||||
// We can thus infer "a = -d"
|
||||
AddEquationFactRecursive(lhs_dd, SpvOpSNegate,
|
||||
AddEquationFactRecursive(lhs_dd, spv::Op::OpSNegate,
|
||||
{equation.operands[0]});
|
||||
}
|
||||
}
|
||||
if (equation.opcode == SpvOpISub) {
|
||||
if (equation.opcode == spv::Op::OpISub) {
|
||||
// Equation form: "a = b - (d - e)"
|
||||
if (synonymous_.IsEquivalent(*equation.operands[0], *rhs_dds[0])) {
|
||||
// Equation form: "a = b - (b - e)"
|
||||
@ -245,8 +246,8 @@ void DataSynonymAndIdEquationFacts::AddEquationFactRecursive(
|
||||
}
|
||||
break;
|
||||
}
|
||||
case SpvOpLogicalNot:
|
||||
case SpvOpSNegate: {
|
||||
case spv::Op::OpLogicalNot:
|
||||
case spv::Op::OpSNegate: {
|
||||
// Equation form: "a = !b" or "a = -b"
|
||||
for (const auto& equation : GetEquations(rhs_dds[0])) {
|
||||
if (equation.opcode == opcode) {
|
||||
@ -321,9 +322,9 @@ void DataSynonymAndIdEquationFacts::ComputeConversionDataSynonymFacts(
|
||||
|
||||
for (const auto& equation : fact.second) {
|
||||
if (synonymous_.IsEquivalent(*equation.operands[0], dd)) {
|
||||
if (equation.opcode == SpvOpConvertSToF) {
|
||||
if (equation.opcode == spv::Op::OpConvertSToF) {
|
||||
convert_s_to_f_lhs.push_back(*dd_it);
|
||||
} else if (equation.opcode == SpvOpConvertUToF) {
|
||||
} else if (equation.opcode == spv::Op::OpConvertUToF) {
|
||||
convert_u_to_f_lhs.push_back(*dd_it);
|
||||
}
|
||||
}
|
||||
@ -808,9 +809,9 @@ bool DataSynonymAndIdEquationFacts::DataDescriptorsAreWellFormedAndComparable(
|
||||
}
|
||||
// Neither end type is allowed to be void.
|
||||
if (ir_context_->get_def_use_mgr()->GetDef(end_type_id_1)->opcode() ==
|
||||
SpvOpTypeVoid ||
|
||||
spv::Op::OpTypeVoid ||
|
||||
ir_context_->get_def_use_mgr()->GetDef(end_type_id_2)->opcode() ==
|
||||
SpvOpTypeVoid) {
|
||||
spv::Op::OpTypeVoid) {
|
||||
return false;
|
||||
}
|
||||
// If the end types are the same, the data descriptors are comparable.
|
||||
|
@ -79,7 +79,7 @@ class DataSynonymAndIdEquationFacts {
|
||||
// This helper struct represents the right hand side of an equation as an
|
||||
// operator applied to a number of data descriptor operands.
|
||||
struct Operation {
|
||||
SpvOp opcode;
|
||||
spv::Op opcode;
|
||||
std::vector<const protobufs::DataDescriptor*> operands;
|
||||
};
|
||||
|
||||
@ -144,7 +144,7 @@ class DataSynonymAndIdEquationFacts {
|
||||
// corollaries, in the form of data synonym or equation facts, that follow
|
||||
// from this and other known facts.
|
||||
void AddEquationFactRecursive(
|
||||
const protobufs::DataDescriptor& lhs_dd, SpvOp opcode,
|
||||
const protobufs::DataDescriptor& lhs_dd, spv::Op opcode,
|
||||
const std::vector<const protobufs::DataDescriptor*>& rhs_dds);
|
||||
|
||||
// Returns true if and only if |dd.object()| still exists in the module.
|
||||
|
@ -64,7 +64,7 @@ std::string ToString(const protobufs::FactDataSynonym& fact) {
|
||||
std::string ToString(const protobufs::FactIdEquation& fact) {
|
||||
std::stringstream stream;
|
||||
stream << fact.lhs_id();
|
||||
stream << " " << static_cast<SpvOp>(fact.opcode());
|
||||
stream << " " << fact.opcode();
|
||||
for (auto rhs_id : fact.rhs_id()) {
|
||||
stream << " " << rhs_id;
|
||||
}
|
||||
@ -255,11 +255,11 @@ void FactManager::AddFactIdIsIrrelevant(uint32_t result_id) {
|
||||
assert(success && "|result_id| is invalid");
|
||||
}
|
||||
|
||||
void FactManager::AddFactIdEquation(uint32_t lhs_id, SpvOp opcode,
|
||||
void FactManager::AddFactIdEquation(uint32_t lhs_id, spv::Op opcode,
|
||||
const std::vector<uint32_t>& rhs_id) {
|
||||
protobufs::FactIdEquation fact;
|
||||
fact.set_lhs_id(lhs_id);
|
||||
fact.set_opcode(opcode);
|
||||
fact.set_opcode(uint32_t(opcode));
|
||||
for (auto an_rhs_id : rhs_id) {
|
||||
fact.add_rhs_id(an_rhs_id);
|
||||
}
|
||||
|
@ -83,7 +83,7 @@ class FactManager {
|
||||
// |lhs_id| = |opcode| |rhs_id[0]| ... |rhs_id[N-1]|
|
||||
//
|
||||
// Neither |lhs_id| nor any of |rhs_id| may be irrelevant.
|
||||
void AddFactIdEquation(uint32_t lhs_id, SpvOp opcode,
|
||||
void AddFactIdEquation(uint32_t lhs_id, spv::Op opcode,
|
||||
const std::vector<uint32_t>& rhs_id);
|
||||
|
||||
// Inspects all known facts and adds corollary facts; e.g. if we know that
|
||||
|
@ -36,8 +36,9 @@ opt::Function* FindFragmentShaderEntryPoint(opt::IRContext* ir_context,
|
||||
// Check that this is a fragment shader
|
||||
bool found_capability_shader = false;
|
||||
for (auto& capability : ir_context->capabilities()) {
|
||||
assert(capability.opcode() == SpvOpCapability);
|
||||
if (capability.GetSingleWordInOperand(0) == SpvCapabilityShader) {
|
||||
assert(capability.opcode() == spv::Op::OpCapability);
|
||||
if (spv::Capability(capability.GetSingleWordInOperand(0)) ==
|
||||
spv::Capability::Shader) {
|
||||
found_capability_shader = true;
|
||||
break;
|
||||
}
|
||||
@ -51,7 +52,8 @@ opt::Function* FindFragmentShaderEntryPoint(opt::IRContext* ir_context,
|
||||
|
||||
opt::Instruction* fragment_entry_point = nullptr;
|
||||
for (auto& entry_point : ir_context->module()->entry_points()) {
|
||||
if (entry_point.GetSingleWordInOperand(0) == SpvExecutionModelFragment) {
|
||||
if (spv::ExecutionModel(entry_point.GetSingleWordInOperand(0)) ==
|
||||
spv::ExecutionModel::Fragment) {
|
||||
fragment_entry_point = &entry_point;
|
||||
break;
|
||||
}
|
||||
@ -81,8 +83,9 @@ opt::Instruction* FindVec4OutputVariable(opt::IRContext* ir_context,
|
||||
MessageConsumer message_consumer) {
|
||||
opt::Instruction* output_variable = nullptr;
|
||||
for (auto& inst : ir_context->types_values()) {
|
||||
if (inst.opcode() == SpvOpVariable &&
|
||||
inst.GetSingleWordInOperand(0) == SpvStorageClassOutput) {
|
||||
if (inst.opcode() == spv::Op::OpVariable &&
|
||||
spv::StorageClass(inst.GetSingleWordInOperand(0)) ==
|
||||
spv::StorageClass::Output) {
|
||||
if (output_variable != nullptr) {
|
||||
message_consumer(SPV_MSG_ERROR, nullptr, {},
|
||||
"Only one output variable can be handled at present; "
|
||||
@ -144,10 +147,11 @@ MakeConstantUniformReplacement(opt::IRContext* ir_context,
|
||||
uint32_t greater_than_instruction,
|
||||
uint32_t in_operand_index) {
|
||||
return MakeUnique<TransformationReplaceConstantWithUniform>(
|
||||
MakeIdUseDescriptor(constant_id,
|
||||
MakeInstructionDescriptor(greater_than_instruction,
|
||||
SpvOpFOrdGreaterThan, 0),
|
||||
in_operand_index),
|
||||
MakeIdUseDescriptor(
|
||||
constant_id,
|
||||
MakeInstructionDescriptor(greater_than_instruction,
|
||||
spv::Op::OpFOrdGreaterThan, 0),
|
||||
in_operand_index),
|
||||
fact_manager.GetUniformDescriptorsForConstant(constant_id)[0],
|
||||
ir_context->TakeNextId(), ir_context->TakeNextId());
|
||||
}
|
||||
@ -204,20 +208,21 @@ bool ForceRenderRed(
|
||||
// Make the new exit block
|
||||
auto new_exit_block_id = ir_context->TakeNextId();
|
||||
{
|
||||
auto label = MakeUnique<opt::Instruction>(ir_context.get(), SpvOpLabel, 0,
|
||||
new_exit_block_id,
|
||||
opt::Instruction::OperandList());
|
||||
auto label = MakeUnique<opt::Instruction>(
|
||||
ir_context.get(), spv::Op::OpLabel, 0, new_exit_block_id,
|
||||
opt::Instruction::OperandList());
|
||||
auto new_exit_block = MakeUnique<opt::BasicBlock>(std::move(label));
|
||||
new_exit_block->AddInstruction(MakeUnique<opt::Instruction>(
|
||||
ir_context.get(), SpvOpReturn, 0, 0, opt::Instruction::OperandList()));
|
||||
new_exit_block->AddInstruction(
|
||||
MakeUnique<opt::Instruction>(ir_context.get(), spv::Op::OpReturn, 0, 0,
|
||||
opt::Instruction::OperandList()));
|
||||
entry_point_function->AddBasicBlock(std::move(new_exit_block));
|
||||
}
|
||||
|
||||
// Make the new entry block
|
||||
{
|
||||
auto label = MakeUnique<opt::Instruction>(ir_context.get(), SpvOpLabel, 0,
|
||||
ir_context->TakeNextId(),
|
||||
opt::Instruction::OperandList());
|
||||
auto label = MakeUnique<opt::Instruction>(
|
||||
ir_context.get(), spv::Op::OpLabel, 0, ir_context->TakeNextId(),
|
||||
opt::Instruction::OperandList());
|
||||
auto new_entry_block = MakeUnique<opt::BasicBlock>(std::move(label));
|
||||
|
||||
// Make an instruction to construct vec4(1.0, 0.0, 0.0, 1.0), representing
|
||||
@ -229,7 +234,7 @@ bool ForceRenderRed(
|
||||
auto temp_vec4 = opt::analysis::Vector(float_type, 4);
|
||||
auto vec4_id = ir_context->get_type_mgr()->GetId(&temp_vec4);
|
||||
auto red = MakeUnique<opt::Instruction>(
|
||||
ir_context.get(), SpvOpCompositeConstruct, vec4_id,
|
||||
ir_context.get(), spv::Op::OpCompositeConstruct, vec4_id,
|
||||
ir_context->TakeNextId(), op_composite_construct_operands);
|
||||
auto red_id = red->result_id();
|
||||
new_entry_block->AddInstruction(std::move(red));
|
||||
@ -241,7 +246,7 @@ bool ForceRenderRed(
|
||||
opt::Instruction::OperandList op_store_operands = {variable_to_store_into,
|
||||
value_to_be_stored};
|
||||
new_entry_block->AddInstruction(MakeUnique<opt::Instruction>(
|
||||
ir_context.get(), SpvOpStore, 0, 0, op_store_operands));
|
||||
ir_context.get(), spv::Op::OpStore, 0, 0, op_store_operands));
|
||||
|
||||
// We are going to attempt to construct 'false' as an expression of the form
|
||||
// 'literal1 > literal2'. If we succeed, we will later replace each literal
|
||||
@ -313,7 +318,7 @@ bool ForceRenderRed(
|
||||
{SPV_OPERAND_TYPE_ID, {smaller_constant}},
|
||||
{SPV_OPERAND_TYPE_ID, {larger_constant}}};
|
||||
new_entry_block->AddInstruction(MakeUnique<opt::Instruction>(
|
||||
ir_context.get(), SpvOpFOrdGreaterThan,
|
||||
ir_context.get(), spv::Op::OpFOrdGreaterThan,
|
||||
ir_context->get_type_mgr()->GetId(registered_bool_type),
|
||||
id_guaranteed_to_be_false, greater_than_operands));
|
||||
|
||||
@ -344,9 +349,9 @@ bool ForceRenderRed(
|
||||
opt::Operand else_block = {SPV_OPERAND_TYPE_ID, {new_exit_block_id}};
|
||||
opt::Instruction::OperandList op_branch_conditional_operands = {
|
||||
false_condition, then_block, else_block};
|
||||
new_entry_block->AddInstruction(
|
||||
MakeUnique<opt::Instruction>(ir_context.get(), SpvOpBranchConditional,
|
||||
0, 0, op_branch_conditional_operands));
|
||||
new_entry_block->AddInstruction(MakeUnique<opt::Instruction>(
|
||||
ir_context.get(), spv::Op::OpBranchConditional, 0, 0,
|
||||
op_branch_conditional_operands));
|
||||
|
||||
entry_point_function->InsertBasicBlockBefore(
|
||||
std::move(new_entry_block), entry_point_function->entry().get());
|
||||
|
@ -131,14 +131,15 @@ void FuzzerPass::ForEachInstructionWithInstructionDescriptor(
|
||||
// should skip when searching from 'base' for the desired instruction.
|
||||
// (An instruction that has a result id is represented by its own opcode,
|
||||
// itself as 'base', and a skip-count of 0.)
|
||||
std::vector<std::tuple<uint32_t, SpvOp, uint32_t>> base_opcode_skip_triples;
|
||||
std::vector<std::tuple<uint32_t, spv::Op, uint32_t>>
|
||||
base_opcode_skip_triples;
|
||||
|
||||
// The initial base instruction is the block label.
|
||||
uint32_t base = block->id();
|
||||
|
||||
// Counts the number of times we have seen each opcode since we reset the
|
||||
// base instruction.
|
||||
std::map<SpvOp, uint32_t> skip_count;
|
||||
std::map<spv::Op, uint32_t> skip_count;
|
||||
|
||||
// Consider every instruction in the block. The label is excluded: it is
|
||||
// only necessary to consider it as a base in case the first instruction
|
||||
@ -151,7 +152,7 @@ void FuzzerPass::ForEachInstructionWithInstructionDescriptor(
|
||||
base = inst_it->result_id();
|
||||
skip_count.clear();
|
||||
}
|
||||
const SpvOp opcode = inst_it->opcode();
|
||||
const spv::Op opcode = inst_it->opcode();
|
||||
|
||||
// Invoke the provided function, which might apply a transformation.
|
||||
action(block, inst_it,
|
||||
@ -330,7 +331,7 @@ uint32_t FuzzerPass::FindOrCreateStructType(
|
||||
}
|
||||
|
||||
uint32_t FuzzerPass::FindOrCreatePointerType(uint32_t base_type_id,
|
||||
SpvStorageClass storage_class) {
|
||||
spv::StorageClass storage_class) {
|
||||
// We do not use the type manager here, due to problems related to isomorphic
|
||||
// but distinct structs not being regarded as different.
|
||||
auto existing_id = fuzzerutil::MaybeGetPointerType(
|
||||
@ -345,7 +346,7 @@ uint32_t FuzzerPass::FindOrCreatePointerType(uint32_t base_type_id,
|
||||
}
|
||||
|
||||
uint32_t FuzzerPass::FindOrCreatePointerToIntegerType(
|
||||
uint32_t width, bool is_signed, SpvStorageClass storage_class) {
|
||||
uint32_t width, bool is_signed, spv::StorageClass storage_class) {
|
||||
return FindOrCreatePointerType(FindOrCreateIntegerType(width, is_signed),
|
||||
storage_class);
|
||||
}
|
||||
@ -432,7 +433,7 @@ uint32_t FuzzerPass::FindOrCreateCompositeConstant(
|
||||
|
||||
uint32_t FuzzerPass::FindOrCreateGlobalUndef(uint32_t type_id) {
|
||||
for (auto& inst : GetIRContext()->types_values()) {
|
||||
if (inst.opcode() == SpvOpUndef && inst.type_id() == type_id) {
|
||||
if (inst.opcode() == spv::Op::OpUndef && inst.type_id() == type_id) {
|
||||
return inst.result_id();
|
||||
}
|
||||
}
|
||||
@ -464,7 +465,7 @@ uint32_t FuzzerPass::FindOrCreateNullConstant(uint32_t type_id) {
|
||||
|
||||
std::pair<std::vector<uint32_t>, std::map<uint32_t, std::vector<uint32_t>>>
|
||||
FuzzerPass::GetAvailableBasicTypesAndPointers(
|
||||
SpvStorageClass storage_class) const {
|
||||
spv::StorageClass storage_class) const {
|
||||
// Records all of the basic types available in the module.
|
||||
std::set<uint32_t> basic_types;
|
||||
|
||||
@ -480,23 +481,23 @@ FuzzerPass::GetAvailableBasicTypesAndPointers(
|
||||
// For pointer types with basic pointee types, associate the pointer type
|
||||
// with the basic type.
|
||||
switch (inst.opcode()) {
|
||||
case SpvOpTypeBool:
|
||||
case SpvOpTypeFloat:
|
||||
case SpvOpTypeInt:
|
||||
case SpvOpTypeMatrix:
|
||||
case SpvOpTypeVector:
|
||||
case spv::Op::OpTypeBool:
|
||||
case spv::Op::OpTypeFloat:
|
||||
case spv::Op::OpTypeInt:
|
||||
case spv::Op::OpTypeMatrix:
|
||||
case spv::Op::OpTypeVector:
|
||||
// These are all basic types.
|
||||
basic_types.insert(inst.result_id());
|
||||
basic_type_to_pointers.insert({inst.result_id(), {}});
|
||||
break;
|
||||
case SpvOpTypeArray:
|
||||
case spv::Op::OpTypeArray:
|
||||
// An array type is basic if its base type is basic.
|
||||
if (basic_types.count(inst.GetSingleWordInOperand(0))) {
|
||||
basic_types.insert(inst.result_id());
|
||||
basic_type_to_pointers.insert({inst.result_id(), {}});
|
||||
}
|
||||
break;
|
||||
case SpvOpTypeStruct: {
|
||||
case spv::Op::OpTypeStruct: {
|
||||
// A struct type is basic if it does not have the Block/BufferBlock
|
||||
// decoration, and if all of its members are basic.
|
||||
if (!fuzzerutil::HasBlockOrBufferBlockDecoration(GetIRContext(),
|
||||
@ -515,11 +516,12 @@ FuzzerPass::GetAvailableBasicTypesAndPointers(
|
||||
}
|
||||
break;
|
||||
}
|
||||
case SpvOpTypePointer: {
|
||||
case spv::Op::OpTypePointer: {
|
||||
// We are interested in the pointer if its pointee type is basic and it
|
||||
// has the right storage class.
|
||||
auto pointee_type = inst.GetSingleWordInOperand(1);
|
||||
if (inst.GetSingleWordInOperand(0) == storage_class &&
|
||||
if (spv::StorageClass(inst.GetSingleWordInOperand(0)) ==
|
||||
storage_class &&
|
||||
basic_types.count(pointee_type)) {
|
||||
// The pointer has the desired storage class, and its pointee type is
|
||||
// a basic type, so we are interested in it. Associate it with its
|
||||
@ -541,22 +543,22 @@ uint32_t FuzzerPass::FindOrCreateZeroConstant(
|
||||
GetIRContext()->get_def_use_mgr()->GetDef(scalar_or_composite_type_id);
|
||||
assert(type_instruction && "The type instruction must exist.");
|
||||
switch (type_instruction->opcode()) {
|
||||
case SpvOpTypeBool:
|
||||
case spv::Op::OpTypeBool:
|
||||
return FindOrCreateBoolConstant(false, is_irrelevant);
|
||||
case SpvOpTypeFloat: {
|
||||
case spv::Op::OpTypeFloat: {
|
||||
auto width = type_instruction->GetSingleWordInOperand(0);
|
||||
auto num_words = (width + 32 - 1) / 32;
|
||||
return FindOrCreateFloatConstant(std::vector<uint32_t>(num_words, 0),
|
||||
width, is_irrelevant);
|
||||
}
|
||||
case SpvOpTypeInt: {
|
||||
case spv::Op::OpTypeInt: {
|
||||
auto width = type_instruction->GetSingleWordInOperand(0);
|
||||
auto num_words = (width + 32 - 1) / 32;
|
||||
return FindOrCreateIntegerConstant(
|
||||
std::vector<uint32_t>(num_words, 0), width,
|
||||
type_instruction->GetSingleWordInOperand(1), is_irrelevant);
|
||||
}
|
||||
case SpvOpTypeArray: {
|
||||
case spv::Op::OpTypeArray: {
|
||||
auto component_type_id = type_instruction->GetSingleWordInOperand(0);
|
||||
auto num_components =
|
||||
fuzzerutil::GetArraySize(*type_instruction, GetIRContext());
|
||||
@ -566,8 +568,8 @@ uint32_t FuzzerPass::FindOrCreateZeroConstant(
|
||||
FindOrCreateZeroConstant(component_type_id, is_irrelevant)),
|
||||
scalar_or_composite_type_id, is_irrelevant);
|
||||
}
|
||||
case SpvOpTypeMatrix:
|
||||
case SpvOpTypeVector: {
|
||||
case spv::Op::OpTypeMatrix:
|
||||
case spv::Op::OpTypeVector: {
|
||||
auto component_type_id = type_instruction->GetSingleWordInOperand(0);
|
||||
auto num_components = type_instruction->GetSingleWordInOperand(1);
|
||||
return FindOrCreateCompositeConstant(
|
||||
@ -576,7 +578,7 @@ uint32_t FuzzerPass::FindOrCreateZeroConstant(
|
||||
FindOrCreateZeroConstant(component_type_id, is_irrelevant)),
|
||||
scalar_or_composite_type_id, is_irrelevant);
|
||||
}
|
||||
case SpvOpTypeStruct: {
|
||||
case spv::Op::OpTypeStruct: {
|
||||
assert(!fuzzerutil::HasBlockOrBufferBlockDecoration(
|
||||
GetIRContext(), scalar_or_composite_type_id) &&
|
||||
"We do not construct constants of struct types decorated with "
|
||||
@ -646,7 +648,7 @@ opt::BasicBlock* FuzzerPass::GetOrCreateSimpleLoopPreheader(
|
||||
|
||||
// |maybe_preheader| is a preheader if it branches unconditionally to
|
||||
// the header. We also require it not to be a loop header.
|
||||
if (maybe_preheader->terminator()->opcode() == SpvOpBranch &&
|
||||
if (maybe_preheader->terminator()->opcode() == spv::Op::OpBranch &&
|
||||
!maybe_preheader->IsLoopHeader()) {
|
||||
return maybe_preheader;
|
||||
}
|
||||
@ -683,8 +685,8 @@ opt::BasicBlock* FuzzerPass::SplitBlockAfterOpPhiOrOpVariable(
|
||||
|
||||
// Find the first non-OpPhi and non-OpVariable instruction.
|
||||
auto non_phi_or_var_inst = &*block->begin();
|
||||
while (non_phi_or_var_inst->opcode() == SpvOpPhi ||
|
||||
non_phi_or_var_inst->opcode() == SpvOpVariable) {
|
||||
while (non_phi_or_var_inst->opcode() == spv::Op::OpPhi ||
|
||||
non_phi_or_var_inst->opcode() == spv::Op::OpVariable) {
|
||||
non_phi_or_var_inst = non_phi_or_var_inst->NextNode();
|
||||
}
|
||||
|
||||
@ -706,7 +708,7 @@ uint32_t FuzzerPass::FindOrCreateLocalVariable(
|
||||
(void)pointer_type;
|
||||
assert(pointer_type && pointer_type->AsPointer() &&
|
||||
pointer_type->AsPointer()->storage_class() ==
|
||||
SpvStorageClassFunction &&
|
||||
spv::StorageClass::Function &&
|
||||
"The pointer_type_id must refer to a defined pointer type with "
|
||||
"storage class Function");
|
||||
auto function = fuzzerutil::FindFunction(GetIRContext(), function_id);
|
||||
@ -715,7 +717,7 @@ uint32_t FuzzerPass::FindOrCreateLocalVariable(
|
||||
// First we try to find a suitable existing variable.
|
||||
// All of the local variable declarations are located in the first block.
|
||||
for (auto& instruction : *function->begin()) {
|
||||
if (instruction.opcode() != SpvOpVariable) {
|
||||
if (instruction.opcode() != spv::Op::OpVariable) {
|
||||
continue;
|
||||
}
|
||||
// The existing OpVariable must have type |pointer_type_id|.
|
||||
@ -749,15 +751,16 @@ uint32_t FuzzerPass::FindOrCreateGlobalVariable(
|
||||
(void)pointer_type;
|
||||
assert(
|
||||
pointer_type && pointer_type->AsPointer() &&
|
||||
(pointer_type->AsPointer()->storage_class() == SpvStorageClassPrivate ||
|
||||
(pointer_type->AsPointer()->storage_class() ==
|
||||
spv::StorageClass::Private ||
|
||||
pointer_type->AsPointer()->storage_class() ==
|
||||
SpvStorageClassWorkgroup) &&
|
||||
spv::StorageClass::Workgroup) &&
|
||||
"The pointer_type_id must refer to a defined pointer type with storage "
|
||||
"class Private or Workgroup");
|
||||
|
||||
// First we try to find a suitable existing variable.
|
||||
for (auto& instruction : GetIRContext()->module()->types_values()) {
|
||||
if (instruction.opcode() != SpvOpVariable) {
|
||||
if (instruction.opcode() != spv::Op::OpVariable) {
|
||||
continue;
|
||||
}
|
||||
// The existing OpVariable must have type |pointer_type_id|.
|
||||
@ -781,13 +784,13 @@ uint32_t FuzzerPass::FindOrCreateGlobalVariable(
|
||||
uint32_t result_id = GetFuzzerContext()->GetFreshId();
|
||||
|
||||
// A variable with storage class Workgroup shouldn't have an initializer.
|
||||
if (storage_class == SpvStorageClassWorkgroup) {
|
||||
if (storage_class == spv::StorageClass::Workgroup) {
|
||||
ApplyTransformation(TransformationAddGlobalVariable(
|
||||
result_id, pointer_type_id, SpvStorageClassWorkgroup, 0,
|
||||
result_id, pointer_type_id, spv::StorageClass::Workgroup, 0,
|
||||
pointee_value_is_irrelevant));
|
||||
} else {
|
||||
ApplyTransformation(TransformationAddGlobalVariable(
|
||||
result_id, pointer_type_id, SpvStorageClassPrivate,
|
||||
result_id, pointer_type_id, spv::StorageClass::Private,
|
||||
FindOrCreateZeroConstant(pointee_type_id, pointee_value_is_irrelevant),
|
||||
pointee_value_is_irrelevant));
|
||||
}
|
||||
|
@ -159,14 +159,14 @@ class FuzzerPass {
|
||||
// already exist) and storage class |storage_class|. A transformation is
|
||||
// applied to add the pointer if it does not already exist.
|
||||
uint32_t FindOrCreatePointerType(uint32_t base_type_id,
|
||||
SpvStorageClass storage_class);
|
||||
spv::StorageClass storage_class);
|
||||
|
||||
// Returns the id of an OpTypePointer instruction, with a integer base
|
||||
// type of width and signedness specified by |width| and |is_signed|,
|
||||
// respectively. If the pointer type or required integer base type do not
|
||||
// exist, transformations are applied to add them.
|
||||
uint32_t FindOrCreatePointerToIntegerType(uint32_t width, bool is_signed,
|
||||
SpvStorageClass storage_class);
|
||||
spv::StorageClass storage_class);
|
||||
|
||||
// Returns the id of an OpConstant instruction, with a integer type of
|
||||
// width and signedness specified by |width| and |is_signed|, respectively,
|
||||
@ -239,7 +239,7 @@ class FuzzerPass {
|
||||
// storage class, and the sequence will have multiple elements if there are
|
||||
// repeated pointer declarations for the same basic type and storage class.
|
||||
std::pair<std::vector<uint32_t>, std::map<uint32_t, std::vector<uint32_t>>>
|
||||
GetAvailableBasicTypesAndPointers(SpvStorageClass storage_class) const;
|
||||
GetAvailableBasicTypesAndPointers(spv::StorageClass storage_class) const;
|
||||
|
||||
// Given a type id, |scalar_or_composite_type_id|, which must correspond to
|
||||
// some scalar or composite type, returns the result id of an instruction
|
||||
|
@ -34,15 +34,16 @@ void FuzzerPassAddAccessChains::Apply() {
|
||||
opt::BasicBlock::iterator inst_it,
|
||||
const protobufs::InstructionDescriptor& instruction_descriptor)
|
||||
-> void {
|
||||
assert(inst_it->opcode() ==
|
||||
instruction_descriptor.target_instruction_opcode() &&
|
||||
"The opcode of the instruction we might insert before must be "
|
||||
"the same as the opcode in the descriptor for the instruction");
|
||||
assert(
|
||||
inst_it->opcode() ==
|
||||
spv::Op(instruction_descriptor.target_instruction_opcode()) &&
|
||||
"The opcode of the instruction we might insert before must be "
|
||||
"the same as the opcode in the descriptor for the instruction");
|
||||
|
||||
// Check whether it is legitimate to insert an access chain
|
||||
// instruction before this instruction.
|
||||
if (!fuzzerutil::CanInsertOpcodeBeforeInstruction(SpvOpAccessChain,
|
||||
inst_it)) {
|
||||
if (!fuzzerutil::CanInsertOpcodeBeforeInstruction(
|
||||
spv::Op::OpAccessChain, inst_it)) {
|
||||
return;
|
||||
}
|
||||
|
||||
@ -64,8 +65,8 @@ void FuzzerPassAddAccessChains::Apply() {
|
||||
return false;
|
||||
}
|
||||
switch (instruction->opcode()) {
|
||||
case SpvOpConstantNull:
|
||||
case SpvOpUndef:
|
||||
case spv::Op::OpConstantNull:
|
||||
case spv::Op::OpUndef:
|
||||
// Do not allow making an access chain from a null or
|
||||
// undefined pointer. (We can eliminate these cases
|
||||
// before actually checking that the instruction is a
|
||||
@ -78,7 +79,7 @@ void FuzzerPassAddAccessChains::Apply() {
|
||||
// make an access chain from it.
|
||||
return context->get_def_use_mgr()
|
||||
->GetDef(instruction->type_id())
|
||||
->opcode() == SpvOpTypePointer;
|
||||
->opcode() == spv::Op::OpTypePointer;
|
||||
});
|
||||
|
||||
// At this point, |relevant_instructions| contains all the pointers
|
||||
@ -112,14 +113,14 @@ void FuzzerPassAddAccessChains::Apply() {
|
||||
}
|
||||
uint32_t bound;
|
||||
switch (subobject_type->opcode()) {
|
||||
case SpvOpTypeArray:
|
||||
case spv::Op::OpTypeArray:
|
||||
bound = fuzzerutil::GetArraySize(*subobject_type, GetIRContext());
|
||||
break;
|
||||
case SpvOpTypeMatrix:
|
||||
case SpvOpTypeVector:
|
||||
case spv::Op::OpTypeMatrix:
|
||||
case spv::Op::OpTypeVector:
|
||||
bound = subobject_type->GetSingleWordInOperand(1);
|
||||
break;
|
||||
case SpvOpTypeStruct:
|
||||
case spv::Op::OpTypeStruct:
|
||||
bound = fuzzerutil::GetNumberOfStructMembers(*subobject_type);
|
||||
break;
|
||||
default:
|
||||
@ -140,9 +141,9 @@ void FuzzerPassAddAccessChains::Apply() {
|
||||
GetFuzzerContext()->GetRandomIndexForAccessChain(bound);
|
||||
|
||||
switch (subobject_type->opcode()) {
|
||||
case SpvOpTypeArray:
|
||||
case SpvOpTypeMatrix:
|
||||
case SpvOpTypeVector: {
|
||||
case spv::Op::OpTypeArray:
|
||||
case spv::Op::OpTypeMatrix:
|
||||
case spv::Op::OpTypeVector: {
|
||||
// The index will be clamped
|
||||
|
||||
bool is_signed = GetFuzzerContext()->ChooseEven();
|
||||
@ -164,7 +165,7 @@ void FuzzerPassAddAccessChains::Apply() {
|
||||
subobject_type_id = subobject_type->GetSingleWordInOperand(0);
|
||||
|
||||
} break;
|
||||
case SpvOpTypeStruct:
|
||||
case spv::Op::OpTypeStruct:
|
||||
index_ids.push_back(FindOrCreateIntegerConstant(
|
||||
{index_value}, 32, GetFuzzerContext()->ChooseEven(), false));
|
||||
subobject_type_id =
|
||||
@ -178,7 +179,7 @@ void FuzzerPassAddAccessChains::Apply() {
|
||||
// pointer suitable for the access chain's result type exists, so we
|
||||
// create one if it does not.
|
||||
FindOrCreatePointerType(subobject_type_id,
|
||||
static_cast<SpvStorageClass>(
|
||||
static_cast<spv::StorageClass>(
|
||||
pointer_type->GetSingleWordInOperand(0)));
|
||||
// Apply the transformation to add an access chain.
|
||||
ApplyTransformation(TransformationAccessChain(
|
||||
|
@ -53,8 +53,8 @@ void FuzzerPassAddCompositeExtract::Apply() {
|
||||
opt::Function* /*unused*/, opt::BasicBlock* /*unused*/,
|
||||
opt::BasicBlock::iterator inst_it,
|
||||
const protobufs::InstructionDescriptor& instruction_descriptor) {
|
||||
if (!fuzzerutil::CanInsertOpcodeBeforeInstruction(SpvOpCompositeExtract,
|
||||
inst_it)) {
|
||||
if (!fuzzerutil::CanInsertOpcodeBeforeInstruction(
|
||||
spv::Op::OpCompositeExtract, inst_it)) {
|
||||
return;
|
||||
}
|
||||
|
||||
@ -97,15 +97,15 @@ void FuzzerPassAddCompositeExtract::Apply() {
|
||||
assert(type_inst && "Composite instruction has invalid type id");
|
||||
|
||||
switch (type_inst->opcode()) {
|
||||
case SpvOpTypeArray:
|
||||
case spv::Op::OpTypeArray:
|
||||
number_of_members =
|
||||
fuzzerutil::GetArraySize(*type_inst, GetIRContext());
|
||||
break;
|
||||
case SpvOpTypeVector:
|
||||
case SpvOpTypeMatrix:
|
||||
case spv::Op::OpTypeVector:
|
||||
case spv::Op::OpTypeMatrix:
|
||||
number_of_members = type_inst->GetSingleWordInOperand(1);
|
||||
break;
|
||||
case SpvOpTypeStruct:
|
||||
case spv::Op::OpTypeStruct:
|
||||
number_of_members = type_inst->NumInOperands();
|
||||
break;
|
||||
default:
|
||||
@ -122,12 +122,12 @@ void FuzzerPassAddCompositeExtract::Apply() {
|
||||
number_of_members));
|
||||
|
||||
switch (type_inst->opcode()) {
|
||||
case SpvOpTypeArray:
|
||||
case SpvOpTypeVector:
|
||||
case SpvOpTypeMatrix:
|
||||
case spv::Op::OpTypeArray:
|
||||
case spv::Op::OpTypeVector:
|
||||
case spv::Op::OpTypeMatrix:
|
||||
type_id = type_inst->GetSingleWordInOperand(0);
|
||||
break;
|
||||
case SpvOpTypeStruct:
|
||||
case spv::Op::OpTypeStruct:
|
||||
type_id = type_inst->GetSingleWordInOperand(indices.back());
|
||||
break;
|
||||
default:
|
||||
|
@ -36,10 +36,11 @@ void FuzzerPassAddCompositeInserts::Apply() {
|
||||
opt::BasicBlock::iterator instruction_iterator,
|
||||
const protobufs::InstructionDescriptor& instruction_descriptor)
|
||||
-> void {
|
||||
assert(instruction_iterator->opcode() ==
|
||||
instruction_descriptor.target_instruction_opcode() &&
|
||||
"The opcode of the instruction we might insert before must be "
|
||||
"the same as the opcode in the descriptor for the instruction");
|
||||
assert(
|
||||
instruction_iterator->opcode() ==
|
||||
spv::Op(instruction_descriptor.target_instruction_opcode()) &&
|
||||
"The opcode of the instruction we might insert before must be "
|
||||
"the same as the opcode in the descriptor for the instruction");
|
||||
|
||||
// Randomly decide whether to try adding an OpCompositeInsert
|
||||
// instruction.
|
||||
@ -51,7 +52,7 @@ void FuzzerPassAddCompositeInserts::Apply() {
|
||||
// It must be possible to insert an OpCompositeInsert instruction
|
||||
// before |instruction_iterator|.
|
||||
if (!fuzzerutil::CanInsertOpcodeBeforeInstruction(
|
||||
SpvOpCompositeInsert, instruction_iterator)) {
|
||||
spv::Op::OpCompositeInsert, instruction_iterator)) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -114,15 +114,15 @@ uint32_t FuzzerPassAddCompositeTypes::ChooseScalarOrCompositeType() {
|
||||
std::vector<uint32_t> candidates;
|
||||
for (auto& inst : GetIRContext()->types_values()) {
|
||||
switch (inst.opcode()) {
|
||||
case SpvOpTypeArray:
|
||||
case SpvOpTypeBool:
|
||||
case SpvOpTypeFloat:
|
||||
case SpvOpTypeInt:
|
||||
case SpvOpTypeMatrix:
|
||||
case SpvOpTypeVector:
|
||||
case spv::Op::OpTypeArray:
|
||||
case spv::Op::OpTypeBool:
|
||||
case spv::Op::OpTypeFloat:
|
||||
case spv::Op::OpTypeInt:
|
||||
case spv::Op::OpTypeMatrix:
|
||||
case spv::Op::OpTypeVector:
|
||||
candidates.push_back(inst.result_id());
|
||||
break;
|
||||
case SpvOpTypeStruct: {
|
||||
case spv::Op::OpTypeStruct: {
|
||||
if (!fuzzerutil::MembersHaveBuiltInDecoration(GetIRContext(),
|
||||
inst.result_id()) &&
|
||||
!fuzzerutil::HasBlockOrBufferBlockDecoration(GetIRContext(),
|
||||
|
@ -36,7 +36,7 @@ void FuzzerPassAddCopyMemory::Apply() {
|
||||
opt::BasicBlock::iterator inst_it,
|
||||
const protobufs::InstructionDescriptor& instruction_descriptor) {
|
||||
// Check that we can insert an OpCopyMemory before this instruction.
|
||||
if (!fuzzerutil::CanInsertOpcodeBeforeInstruction(SpvOpCopyMemory,
|
||||
if (!fuzzerutil::CanInsertOpcodeBeforeInstruction(spv::Op::OpCopyMemory,
|
||||
inst_it)) {
|
||||
return;
|
||||
}
|
||||
@ -61,8 +61,8 @@ void FuzzerPassAddCopyMemory::Apply() {
|
||||
|
||||
// Decide whether to create global or local variable.
|
||||
auto storage_class = GetFuzzerContext()->ChooseEven()
|
||||
? SpvStorageClassPrivate
|
||||
: SpvStorageClassFunction;
|
||||
? spv::StorageClass::Private
|
||||
: spv::StorageClass::Function;
|
||||
|
||||
auto pointee_type_id = fuzzerutil::GetPointeeTypeIdFromPointerType(
|
||||
GetIRContext(), inst->type_id());
|
||||
|
@ -29,12 +29,14 @@ bool IsBitWidthSupported(opt::IRContext* ir_context, uint32_t bit_width) {
|
||||
return true;
|
||||
case 64:
|
||||
return ir_context->get_feature_mgr()->HasCapability(
|
||||
SpvCapabilityFloat64) &&
|
||||
ir_context->get_feature_mgr()->HasCapability(SpvCapabilityInt64);
|
||||
spv::Capability::Float64) &&
|
||||
ir_context->get_feature_mgr()->HasCapability(
|
||||
spv::Capability::Int64);
|
||||
case 16:
|
||||
return ir_context->get_feature_mgr()->HasCapability(
|
||||
SpvCapabilityFloat16) &&
|
||||
ir_context->get_feature_mgr()->HasCapability(SpvCapabilityInt16);
|
||||
spv::Capability::Float16) &&
|
||||
ir_context->get_feature_mgr()->HasCapability(
|
||||
spv::Capability::Int16);
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
@ -66,7 +68,8 @@ void FuzzerPassAddEquationInstructions::Apply() {
|
||||
// as an example opcode for this check, to be representative of *some*
|
||||
// opcode that defines an equation, even though we may choose a
|
||||
// different opcode below.
|
||||
if (!fuzzerutil::CanInsertOpcodeBeforeInstruction(SpvOpIAdd, inst_it)) {
|
||||
if (!fuzzerutil::CanInsertOpcodeBeforeInstruction(spv::Op::OpIAdd,
|
||||
inst_it)) {
|
||||
return;
|
||||
}
|
||||
|
||||
@ -78,7 +81,7 @@ void FuzzerPassAddEquationInstructions::Apply() {
|
||||
[this](opt::IRContext* /*unused*/,
|
||||
opt::Instruction* instruction) -> bool {
|
||||
return instruction->result_id() && instruction->type_id() &&
|
||||
instruction->opcode() != SpvOpUndef &&
|
||||
instruction->opcode() != spv::Op::OpUndef &&
|
||||
!GetTransformationContext()
|
||||
->GetFactManager()
|
||||
->IdIsIrrelevant(instruction->result_id());
|
||||
@ -86,15 +89,16 @@ void FuzzerPassAddEquationInstructions::Apply() {
|
||||
|
||||
// Try the opcodes for which we know how to make ids at random until
|
||||
// something works.
|
||||
std::vector<SpvOp> candidate_opcodes = {
|
||||
SpvOpIAdd, SpvOpISub, SpvOpLogicalNot, SpvOpSNegate,
|
||||
SpvOpConvertUToF, SpvOpConvertSToF, SpvOpBitcast};
|
||||
std::vector<spv::Op> candidate_opcodes = {
|
||||
spv::Op::OpIAdd, spv::Op::OpISub, spv::Op::OpLogicalNot,
|
||||
spv::Op::OpSNegate, spv::Op::OpConvertUToF, spv::Op::OpConvertSToF,
|
||||
spv::Op::OpBitcast};
|
||||
do {
|
||||
auto opcode =
|
||||
GetFuzzerContext()->RemoveAtRandomIndex(&candidate_opcodes);
|
||||
switch (opcode) {
|
||||
case SpvOpConvertSToF:
|
||||
case SpvOpConvertUToF: {
|
||||
case spv::Op::OpConvertSToF:
|
||||
case spv::Op::OpConvertUToF: {
|
||||
std::vector<const opt::Instruction*> candidate_instructions;
|
||||
for (const auto* inst :
|
||||
GetIntegerInstructions(available_instructions)) {
|
||||
@ -144,7 +148,7 @@ void FuzzerPassAddEquationInstructions::Apply() {
|
||||
{operand->result_id()}, instruction_descriptor));
|
||||
return;
|
||||
}
|
||||
case SpvOpBitcast: {
|
||||
case spv::Op::OpBitcast: {
|
||||
const auto candidate_instructions =
|
||||
GetNumericalInstructions(available_instructions);
|
||||
|
||||
@ -197,8 +201,8 @@ void FuzzerPassAddEquationInstructions::Apply() {
|
||||
return;
|
||||
}
|
||||
} break;
|
||||
case SpvOpIAdd:
|
||||
case SpvOpISub: {
|
||||
case spv::Op::OpIAdd:
|
||||
case spv::Op::OpISub: {
|
||||
// Instructions of integer (scalar or vector) result type are
|
||||
// suitable for these opcodes.
|
||||
auto integer_instructions =
|
||||
@ -251,7 +255,7 @@ void FuzzerPassAddEquationInstructions::Apply() {
|
||||
}
|
||||
break;
|
||||
}
|
||||
case SpvOpLogicalNot: {
|
||||
case spv::Op::OpLogicalNot: {
|
||||
// Choose any available instruction of boolean scalar/vector
|
||||
// result type and equate its negation with a fresh id.
|
||||
auto boolean_instructions =
|
||||
@ -268,7 +272,7 @@ void FuzzerPassAddEquationInstructions::Apply() {
|
||||
}
|
||||
break;
|
||||
}
|
||||
case SpvOpSNegate: {
|
||||
case spv::Op::OpSNegate: {
|
||||
// Similar to OpLogicalNot, but for signed integer negation.
|
||||
auto integer_instructions =
|
||||
GetIntegerInstructions(available_instructions);
|
||||
|
@ -39,8 +39,8 @@ void FuzzerPassAddFunctionCalls::Apply() {
|
||||
-> void {
|
||||
// Check whether it is legitimate to insert a function call before the
|
||||
// instruction.
|
||||
if (!fuzzerutil::CanInsertOpcodeBeforeInstruction(SpvOpFunctionCall,
|
||||
inst_it)) {
|
||||
if (!fuzzerutil::CanInsertOpcodeBeforeInstruction(
|
||||
spv::Op::OpFunctionCall, inst_it)) {
|
||||
return;
|
||||
}
|
||||
|
||||
@ -112,8 +112,8 @@ std::vector<uint32_t> FuzzerPassAddFunctionCalls::ChooseFunctionCallArguments(
|
||||
auto available_pointers = FindAvailableInstructions(
|
||||
caller_function, caller_block, caller_inst_it,
|
||||
[this, caller_block](opt::IRContext* /*unused*/, opt::Instruction* inst) {
|
||||
if (inst->opcode() != SpvOpVariable ||
|
||||
inst->opcode() != SpvOpFunctionParameter) {
|
||||
if (inst->opcode() != spv::Op::OpVariable ||
|
||||
inst->opcode() != spv::Op::OpFunctionParameter) {
|
||||
// Function parameters and variables are the only
|
||||
// kinds of pointer that can be used as actual
|
||||
// parameters.
|
||||
@ -172,15 +172,15 @@ std::vector<uint32_t> FuzzerPassAddFunctionCalls::ChooseFunctionCallArguments(
|
||||
auto storage_class = param_type->AsPointer()->storage_class();
|
||||
auto pointee_type_id = fuzzerutil::GetPointeeTypeIdFromPointerType(
|
||||
GetIRContext(), param->type_id());
|
||||
if (storage_class == SpvStorageClassFunction) {
|
||||
if (storage_class == spv::StorageClass::Function) {
|
||||
// Add a new zero-initialized local variable to the current
|
||||
// function, noting that its pointee value is irrelevant.
|
||||
ApplyTransformation(TransformationAddLocalVariable(
|
||||
fresh_variable_id, param->type_id(), caller_function->result_id(),
|
||||
FindOrCreateZeroConstant(pointee_type_id, false), true));
|
||||
} else {
|
||||
assert((storage_class == SpvStorageClassPrivate ||
|
||||
storage_class == SpvStorageClassWorkgroup) &&
|
||||
assert((storage_class == spv::StorageClass::Private ||
|
||||
storage_class == spv::StorageClass::Workgroup) &&
|
||||
"Only Function, Private and Workgroup storage classes are "
|
||||
"supported at present.");
|
||||
// Add a new global variable to the module, zero-initializing it if
|
||||
@ -188,7 +188,7 @@ std::vector<uint32_t> FuzzerPassAddFunctionCalls::ChooseFunctionCallArguments(
|
||||
// irrelevant.
|
||||
ApplyTransformation(TransformationAddGlobalVariable(
|
||||
fresh_variable_id, param->type_id(), storage_class,
|
||||
storage_class == SpvStorageClassPrivate
|
||||
storage_class == spv::StorageClass::Private
|
||||
? FindOrCreateZeroConstant(pointee_type_id, false)
|
||||
: 0,
|
||||
true));
|
||||
|
@ -29,16 +29,17 @@ FuzzerPassAddGlobalVariables::FuzzerPassAddGlobalVariables(
|
||||
transformations, ignore_inapplicable_transformations) {}
|
||||
|
||||
void FuzzerPassAddGlobalVariables::Apply() {
|
||||
SpvStorageClass variable_storage_class = SpvStorageClassPrivate;
|
||||
spv::StorageClass variable_storage_class = spv::StorageClass::Private;
|
||||
for (auto& entry_point : GetIRContext()->module()->entry_points()) {
|
||||
// If the execution model of some entry point is GLCompute,
|
||||
// then the variable storage class may be Workgroup.
|
||||
if (entry_point.GetSingleWordInOperand(0) == SpvExecutionModelGLCompute) {
|
||||
if (spv::ExecutionModel(entry_point.GetSingleWordInOperand(0)) ==
|
||||
spv::ExecutionModel::GLCompute) {
|
||||
variable_storage_class =
|
||||
GetFuzzerContext()->ChoosePercentage(
|
||||
GetFuzzerContext()->GetChanceOfChoosingWorkgroupStorageClass())
|
||||
? SpvStorageClassWorkgroup
|
||||
: SpvStorageClassPrivate;
|
||||
? spv::StorageClass::Workgroup
|
||||
: spv::StorageClass::Private;
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -87,7 +88,7 @@ void FuzzerPassAddGlobalVariables::Apply() {
|
||||
ApplyTransformation(TransformationAddGlobalVariable(
|
||||
GetFuzzerContext()->GetFreshId(), pointer_type_id,
|
||||
variable_storage_class,
|
||||
variable_storage_class == SpvStorageClassPrivate
|
||||
variable_storage_class == spv::StorageClass::Private
|
||||
? FindOrCreateZeroConstant(basic_type, false)
|
||||
: 0,
|
||||
true));
|
||||
|
@ -34,10 +34,11 @@ void FuzzerPassAddLoads::Apply() {
|
||||
opt::BasicBlock::iterator inst_it,
|
||||
const protobufs::InstructionDescriptor& instruction_descriptor)
|
||||
-> void {
|
||||
assert(inst_it->opcode() ==
|
||||
instruction_descriptor.target_instruction_opcode() &&
|
||||
"The opcode of the instruction we might insert before must be "
|
||||
"the same as the opcode in the descriptor for the instruction");
|
||||
assert(
|
||||
inst_it->opcode() ==
|
||||
spv::Op(instruction_descriptor.target_instruction_opcode()) &&
|
||||
"The opcode of the instruction we might insert before must be "
|
||||
"the same as the opcode in the descriptor for the instruction");
|
||||
|
||||
// Randomly decide whether to try inserting a load here.
|
||||
if (!GetFuzzerContext()->ChoosePercentage(
|
||||
@ -47,10 +48,11 @@ void FuzzerPassAddLoads::Apply() {
|
||||
|
||||
// Check whether it is legitimate to insert a load or atomic load before
|
||||
// this instruction.
|
||||
if (!fuzzerutil::CanInsertOpcodeBeforeInstruction(SpvOpLoad, inst_it)) {
|
||||
if (!fuzzerutil::CanInsertOpcodeBeforeInstruction(spv::Op::OpLoad,
|
||||
inst_it)) {
|
||||
return;
|
||||
}
|
||||
if (!fuzzerutil::CanInsertOpcodeBeforeInstruction(SpvOpAtomicLoad,
|
||||
if (!fuzzerutil::CanInsertOpcodeBeforeInstruction(spv::Op::OpAtomicLoad,
|
||||
inst_it)) {
|
||||
return;
|
||||
}
|
||||
@ -64,8 +66,8 @@ void FuzzerPassAddLoads::Apply() {
|
||||
return false;
|
||||
}
|
||||
switch (instruction->opcode()) {
|
||||
case SpvOpConstantNull:
|
||||
case SpvOpUndef:
|
||||
case spv::Op::OpConstantNull:
|
||||
case spv::Op::OpUndef:
|
||||
// Do not allow loading from a null or undefined pointer;
|
||||
// this might be OK if the block is dead, but for now we
|
||||
// conservatively avoid it.
|
||||
@ -75,7 +77,7 @@ void FuzzerPassAddLoads::Apply() {
|
||||
}
|
||||
return context->get_def_use_mgr()
|
||||
->GetDef(instruction->type_id())
|
||||
->opcode() == SpvOpTypePointer;
|
||||
->opcode() == spv::Op::OpTypePointer;
|
||||
});
|
||||
|
||||
// At this point, |relevant_instructions| contains all the pointers
|
||||
@ -92,25 +94,25 @@ void FuzzerPassAddLoads::Apply() {
|
||||
uint32_t memory_scope_id = 0;
|
||||
uint32_t memory_semantics_id = 0;
|
||||
|
||||
auto storage_class = static_cast<SpvStorageClass>(
|
||||
auto storage_class = static_cast<spv::StorageClass>(
|
||||
GetIRContext()
|
||||
->get_def_use_mgr()
|
||||
->GetDef(chosen_instruction->type_id())
|
||||
->GetSingleWordInOperand(0));
|
||||
|
||||
switch (storage_class) {
|
||||
case SpvStorageClassStorageBuffer:
|
||||
case SpvStorageClassPhysicalStorageBuffer:
|
||||
case SpvStorageClassWorkgroup:
|
||||
case SpvStorageClassCrossWorkgroup:
|
||||
case SpvStorageClassAtomicCounter:
|
||||
case SpvStorageClassImage:
|
||||
case spv::StorageClass::StorageBuffer:
|
||||
case spv::StorageClass::PhysicalStorageBuffer:
|
||||
case spv::StorageClass::Workgroup:
|
||||
case spv::StorageClass::CrossWorkgroup:
|
||||
case spv::StorageClass::AtomicCounter:
|
||||
case spv::StorageClass::Image:
|
||||
if (GetFuzzerContext()->ChoosePercentage(
|
||||
GetFuzzerContext()->GetChanceOfAddingAtomicLoad())) {
|
||||
is_atomic_load = true;
|
||||
|
||||
memory_scope_id = FindOrCreateConstant(
|
||||
{SpvScopeInvocation},
|
||||
{uint32_t(spv::Scope::Invocation)},
|
||||
FindOrCreateIntegerType(32, GetFuzzerContext()->ChooseEven()),
|
||||
false);
|
||||
|
||||
|
@ -31,7 +31,7 @@ FuzzerPassAddLocalVariables::FuzzerPassAddLocalVariables(
|
||||
|
||||
void FuzzerPassAddLocalVariables::Apply() {
|
||||
auto basic_type_ids_and_pointers =
|
||||
GetAvailableBasicTypesAndPointers(SpvStorageClassFunction);
|
||||
GetAvailableBasicTypesAndPointers(spv::StorageClass::Function);
|
||||
|
||||
// These are the basic types that are available to this fuzzer pass.
|
||||
auto& basic_types = basic_type_ids_and_pointers.first;
|
||||
@ -64,7 +64,7 @@ void FuzzerPassAddLocalVariables::Apply() {
|
||||
// use it.
|
||||
pointer_type = GetFuzzerContext()->GetFreshId();
|
||||
ApplyTransformation(TransformationAddTypePointer(
|
||||
pointer_type, SpvStorageClassFunction, basic_type));
|
||||
pointer_type, spv::StorageClass::Function, basic_type));
|
||||
available_pointers_to_basic_type.push_back(pointer_type);
|
||||
} else {
|
||||
// There is - grab one.
|
||||
|
@ -176,8 +176,8 @@ FuzzerPassAddOpPhiSynonyms::GetIdEquivalenceClasses() {
|
||||
// - OpFunction does not yield a value;
|
||||
// - OpUndef yields an undefined value at each use, so it should never be a
|
||||
// synonym of another id.
|
||||
if (pair.second->opcode() == SpvOpFunction ||
|
||||
pair.second->opcode() == SpvOpUndef) {
|
||||
if (pair.second->opcode() == spv::Op::OpFunction ||
|
||||
pair.second->opcode() == spv::Op::OpUndef) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -79,7 +79,7 @@ void FuzzerPassAddParameters::Apply() {
|
||||
auto storage_class = fuzzerutil::GetStorageClassFromPointerType(
|
||||
GetIRContext(), current_type_id);
|
||||
switch (storage_class) {
|
||||
case SpvStorageClassFunction: {
|
||||
case spv::StorageClass::Function: {
|
||||
// In every caller find or create a local variable that has the
|
||||
// selected type.
|
||||
for (auto* instr :
|
||||
@ -91,8 +91,8 @@ void FuzzerPassAddParameters::Apply() {
|
||||
call_parameter_ids[instr->result_id()] = variable_id;
|
||||
}
|
||||
} break;
|
||||
case SpvStorageClassPrivate:
|
||||
case SpvStorageClassWorkgroup: {
|
||||
case spv::StorageClass::Private:
|
||||
case spv::StorageClass::Workgroup: {
|
||||
// If there exists at least one caller, find or create a global
|
||||
// variable that has the selected type.
|
||||
std::vector<opt::Instruction*> callers =
|
||||
|
@ -34,10 +34,11 @@ void FuzzerPassAddStores::Apply() {
|
||||
opt::BasicBlock::iterator inst_it,
|
||||
const protobufs::InstructionDescriptor& instruction_descriptor)
|
||||
-> void {
|
||||
assert(inst_it->opcode() ==
|
||||
instruction_descriptor.target_instruction_opcode() &&
|
||||
"The opcode of the instruction we might insert before must be "
|
||||
"the same as the opcode in the descriptor for the instruction");
|
||||
assert(
|
||||
inst_it->opcode() ==
|
||||
spv::Op(instruction_descriptor.target_instruction_opcode()) &&
|
||||
"The opcode of the instruction we might insert before must be "
|
||||
"the same as the opcode in the descriptor for the instruction");
|
||||
|
||||
// Randomly decide whether to try inserting a store here.
|
||||
if (!GetFuzzerContext()->ChoosePercentage(
|
||||
@ -47,12 +48,12 @@ void FuzzerPassAddStores::Apply() {
|
||||
|
||||
// Check whether it is legitimate to insert a store before this
|
||||
// instruction.
|
||||
if (!fuzzerutil::CanInsertOpcodeBeforeInstruction(SpvOpStore,
|
||||
if (!fuzzerutil::CanInsertOpcodeBeforeInstruction(spv::Op::OpStore,
|
||||
inst_it)) {
|
||||
return;
|
||||
}
|
||||
if (!fuzzerutil::CanInsertOpcodeBeforeInstruction(SpvOpAtomicStore,
|
||||
inst_it)) {
|
||||
if (!fuzzerutil::CanInsertOpcodeBeforeInstruction(
|
||||
spv::Op::OpAtomicStore, inst_it)) {
|
||||
return;
|
||||
}
|
||||
|
||||
@ -67,7 +68,7 @@ void FuzzerPassAddStores::Apply() {
|
||||
}
|
||||
auto type_inst = context->get_def_use_mgr()->GetDef(
|
||||
instruction->type_id());
|
||||
if (type_inst->opcode() != SpvOpTypePointer) {
|
||||
if (type_inst->opcode() != spv::Op::OpTypePointer) {
|
||||
// Not a pointer.
|
||||
return false;
|
||||
}
|
||||
@ -76,8 +77,8 @@ void FuzzerPassAddStores::Apply() {
|
||||
return false;
|
||||
}
|
||||
switch (instruction->opcode()) {
|
||||
case SpvOpConstantNull:
|
||||
case SpvOpUndef:
|
||||
case spv::Op::OpConstantNull:
|
||||
case spv::Op::OpUndef:
|
||||
// Do not allow storing to a null or undefined pointer;
|
||||
// this might be OK if the block is dead, but for now we
|
||||
// conservatively avoid it.
|
||||
@ -126,24 +127,24 @@ void FuzzerPassAddStores::Apply() {
|
||||
uint32_t memory_semantics_id = 0;
|
||||
|
||||
auto storage_class =
|
||||
static_cast<SpvStorageClass>(GetIRContext()
|
||||
->get_def_use_mgr()
|
||||
->GetDef(pointer->type_id())
|
||||
->GetSingleWordInOperand(0));
|
||||
static_cast<spv::StorageClass>(GetIRContext()
|
||||
->get_def_use_mgr()
|
||||
->GetDef(pointer->type_id())
|
||||
->GetSingleWordInOperand(0));
|
||||
|
||||
switch (storage_class) {
|
||||
case SpvStorageClassStorageBuffer:
|
||||
case SpvStorageClassPhysicalStorageBuffer:
|
||||
case SpvStorageClassWorkgroup:
|
||||
case SpvStorageClassCrossWorkgroup:
|
||||
case SpvStorageClassAtomicCounter:
|
||||
case SpvStorageClassImage:
|
||||
case spv::StorageClass::StorageBuffer:
|
||||
case spv::StorageClass::PhysicalStorageBuffer:
|
||||
case spv::StorageClass::Workgroup:
|
||||
case spv::StorageClass::CrossWorkgroup:
|
||||
case spv::StorageClass::AtomicCounter:
|
||||
case spv::StorageClass::Image:
|
||||
if (GetFuzzerContext()->ChoosePercentage(
|
||||
GetFuzzerContext()->GetChanceOfAddingAtomicStore())) {
|
||||
is_atomic_store = true;
|
||||
|
||||
memory_scope_id = FindOrCreateConstant(
|
||||
{SpvScopeInvocation},
|
||||
{uint32_t(spv::Scope::Invocation)},
|
||||
FindOrCreateIntegerType(32, GetFuzzerContext()->ChooseEven()),
|
||||
false);
|
||||
|
||||
|
@ -44,7 +44,8 @@ void FuzzerPassAddSynonyms::Apply() {
|
||||
// Skip |inst_it| if we can't insert anything above it. OpIAdd is just
|
||||
// a representative of some instruction that might be produced by the
|
||||
// transformation.
|
||||
if (!fuzzerutil::CanInsertOpcodeBeforeInstruction(SpvOpIAdd, inst_it)) {
|
||||
if (!fuzzerutil::CanInsertOpcodeBeforeInstruction(spv::Op::OpIAdd,
|
||||
inst_it)) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -35,10 +35,11 @@ void FuzzerPassAddVectorShuffleInstructions::Apply() {
|
||||
opt::BasicBlock::iterator instruction_iterator,
|
||||
const protobufs::InstructionDescriptor& instruction_descriptor)
|
||||
-> void {
|
||||
assert(instruction_iterator->opcode() ==
|
||||
instruction_descriptor.target_instruction_opcode() &&
|
||||
"The opcode of the instruction we might insert before must be "
|
||||
"the same as the opcode in the descriptor for the instruction");
|
||||
assert(
|
||||
instruction_iterator->opcode() ==
|
||||
spv::Op(instruction_descriptor.target_instruction_opcode()) &&
|
||||
"The opcode of the instruction we might insert before must be "
|
||||
"the same as the opcode in the descriptor for the instruction");
|
||||
|
||||
// Randomly decide whether to try adding an OpVectorShuffle instruction.
|
||||
if (!GetFuzzerContext()->ChoosePercentage(
|
||||
@ -49,7 +50,7 @@ void FuzzerPassAddVectorShuffleInstructions::Apply() {
|
||||
// It must be valid to insert an OpVectorShuffle instruction
|
||||
// before |instruction_iterator|.
|
||||
if (!fuzzerutil::CanInsertOpcodeBeforeInstruction(
|
||||
SpvOpVectorShuffle, instruction_iterator)) {
|
||||
spv::Op::OpVectorShuffle, instruction_iterator)) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -33,7 +33,7 @@ void FuzzerPassAdjustBranchWeights::Apply() {
|
||||
// For all OpBranchConditional instructions,
|
||||
// randomly applies the transformation.
|
||||
GetIRContext()->module()->ForEachInst([this](opt::Instruction* instruction) {
|
||||
if (instruction->opcode() == SpvOpBranchConditional &&
|
||||
if (instruction->opcode() == spv::Op::OpBranchConditional &&
|
||||
GetFuzzerContext()->ChoosePercentage(
|
||||
GetFuzzerContext()->GetChanceOfAdjustingBranchWeights())) {
|
||||
ApplyTransformation(TransformationAdjustBranchWeights(
|
||||
|
@ -40,21 +40,21 @@ void FuzzerPassAdjustFunctionControls::Apply() {
|
||||
// For the new mask, we first randomly select one of three basic masks:
|
||||
// None, Inline or DontInline. These are always valid (and are mutually
|
||||
// exclusive).
|
||||
std::vector<uint32_t> basic_function_control_masks = {
|
||||
SpvFunctionControlMaskNone, SpvFunctionControlInlineMask,
|
||||
SpvFunctionControlDontInlineMask};
|
||||
std::vector<spv::FunctionControlMask> basic_function_control_masks = {
|
||||
spv::FunctionControlMask::MaskNone, spv::FunctionControlMask::Inline,
|
||||
spv::FunctionControlMask::DontInline};
|
||||
uint32_t new_function_control_mask =
|
||||
basic_function_control_masks[GetFuzzerContext()->RandomIndex(
|
||||
basic_function_control_masks)];
|
||||
uint32_t(basic_function_control_masks[GetFuzzerContext()->RandomIndex(
|
||||
basic_function_control_masks)]);
|
||||
|
||||
// We now consider the Pure and Const mask bits. If these are already
|
||||
// set on the function then it's OK to keep them, but also interesting
|
||||
// to consider dropping them, so we decide randomly in each case.
|
||||
for (auto mask_bit :
|
||||
{SpvFunctionControlPureMask, SpvFunctionControlConstMask}) {
|
||||
if ((existing_function_control_mask & mask_bit) &&
|
||||
{spv::FunctionControlMask::Pure, spv::FunctionControlMask::Const}) {
|
||||
if ((existing_function_control_mask & uint32_t(mask_bit)) &&
|
||||
GetFuzzerContext()->ChooseEven()) {
|
||||
new_function_control_mask |= mask_bit;
|
||||
new_function_control_mask |= uint32_t(mask_bit);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -34,7 +34,7 @@ void FuzzerPassAdjustLoopControls::Apply() {
|
||||
for (auto& block : function) {
|
||||
if (auto merge_inst = block.GetMergeInst()) {
|
||||
// Ignore the instruction if it is not a loop merge.
|
||||
if (merge_inst->opcode() != SpvOpLoopMerge) {
|
||||
if (merge_inst->opcode() != spv::Op::OpLoopMerge) {
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -48,9 +48,10 @@ void FuzzerPassAdjustLoopControls::Apply() {
|
||||
TransformationSetLoopControl::kLoopControlMaskInOperandIndex);
|
||||
|
||||
// First, set the new mask to one of None, Unroll or DontUnroll.
|
||||
std::vector<uint32_t> basic_masks = {SpvLoopControlMaskNone,
|
||||
SpvLoopControlUnrollMask,
|
||||
SpvLoopControlDontUnrollMask};
|
||||
std::vector<uint32_t> basic_masks = {
|
||||
uint32_t(spv::LoopControlMask::MaskNone),
|
||||
uint32_t(spv::LoopControlMask::Unroll),
|
||||
uint32_t(spv::LoopControlMask::DontUnroll)};
|
||||
uint32_t new_mask =
|
||||
basic_masks[GetFuzzerContext()->RandomIndex(basic_masks)];
|
||||
|
||||
@ -58,19 +59,20 @@ void FuzzerPassAdjustLoopControls::Apply() {
|
||||
// does, check which of these were present in the existing mask and
|
||||
// randomly decide whether to keep them. They are just hints, so
|
||||
// removing them should not change the semantics of the module.
|
||||
for (auto mask_bit :
|
||||
{SpvLoopControlDependencyInfiniteMask,
|
||||
SpvLoopControlDependencyLengthMask,
|
||||
SpvLoopControlMinIterationsMask, SpvLoopControlMaxIterationsMask,
|
||||
SpvLoopControlIterationMultipleMask}) {
|
||||
if ((existing_mask & mask_bit) && GetFuzzerContext()->ChooseEven()) {
|
||||
for (auto mask_bit : {spv::LoopControlMask::DependencyInfinite,
|
||||
spv::LoopControlMask::DependencyLength,
|
||||
spv::LoopControlMask::MinIterations,
|
||||
spv::LoopControlMask::MaxIterations,
|
||||
spv::LoopControlMask::IterationMultiple}) {
|
||||
if ((existing_mask & uint32_t(mask_bit)) &&
|
||||
GetFuzzerContext()->ChooseEven()) {
|
||||
// The mask bits we are considering are not available in all SPIR-V
|
||||
// versions. However, we only include a mask bit if it was present
|
||||
// in the original loop control mask, and we work under the
|
||||
// assumption that we are transforming a valid module, thus we don't
|
||||
// need to actually check whether the SPIR-V version being used
|
||||
// supports these loop control mask bits.
|
||||
new_mask |= mask_bit;
|
||||
new_mask |= uint32_t(mask_bit);
|
||||
}
|
||||
}
|
||||
|
||||
@ -81,14 +83,14 @@ void FuzzerPassAdjustLoopControls::Apply() {
|
||||
|
||||
// PeelCount and PartialCount are not compatible with DontUnroll, so
|
||||
// we check whether DontUnroll is set.
|
||||
if (!(new_mask & SpvLoopControlDontUnrollMask)) {
|
||||
if (!(new_mask & uint32_t(spv::LoopControlMask::DontUnroll))) {
|
||||
// If PeelCount is supported by this SPIR-V version, randomly choose
|
||||
// whether to set it. If it was set in the original mask and is not
|
||||
// selected for setting here, that amounts to dropping it.
|
||||
if (TransformationSetLoopControl::PeelCountIsSupported(
|
||||
GetIRContext()) &&
|
||||
GetFuzzerContext()->ChooseEven()) {
|
||||
new_mask |= SpvLoopControlPeelCountMask;
|
||||
new_mask |= uint32_t(spv::LoopControlMask::PeelCount);
|
||||
// The peel count is chosen randomly - if PeelCount was already set
|
||||
// this will overwrite whatever peel count was previously used.
|
||||
peel_count = GetFuzzerContext()->GetRandomLoopControlPeelCount();
|
||||
@ -97,7 +99,7 @@ void FuzzerPassAdjustLoopControls::Apply() {
|
||||
if (TransformationSetLoopControl::PartialCountIsSupported(
|
||||
GetIRContext()) &&
|
||||
GetFuzzerContext()->ChooseEven()) {
|
||||
new_mask |= SpvLoopControlPartialCountMask;
|
||||
new_mask |= uint32_t(spv::LoopControlMask::PartialCount);
|
||||
partial_count =
|
||||
GetFuzzerContext()->GetRandomLoopControlPartialCount();
|
||||
}
|
||||
|
@ -47,8 +47,8 @@ void FuzzerPassAdjustMemoryOperandsMasks::Apply() {
|
||||
// From SPIR-V 1.4 onwards, OpCopyMemory and OpCopyMemorySized have a
|
||||
// second mask.
|
||||
switch (inst_it->opcode()) {
|
||||
case SpvOpCopyMemory:
|
||||
case SpvOpCopyMemorySized:
|
||||
case spv::Op::OpCopyMemory:
|
||||
case spv::Op::OpCopyMemorySized:
|
||||
if (TransformationSetMemoryOperandsMask::
|
||||
MultipleMemoryOperandMasksAreSupported(GetIRContext())) {
|
||||
indices_of_available_masks_to_adjust.push_back(1);
|
||||
@ -75,24 +75,26 @@ void FuzzerPassAdjustMemoryOperandsMasks::Apply() {
|
||||
existing_mask_in_operand_index < inst_it->NumInOperands()
|
||||
? inst_it->GetSingleWordInOperand(
|
||||
existing_mask_in_operand_index)
|
||||
: static_cast<uint32_t>(SpvMemoryAccessMaskNone);
|
||||
: static_cast<uint32_t>(spv::MemoryAccessMask::MaskNone);
|
||||
|
||||
// There are two things we can do to a mask:
|
||||
// - add Volatile if not already present
|
||||
// - toggle Nontemporal
|
||||
// The following ensures that we do at least one of these
|
||||
bool add_volatile = !(existing_mask & SpvMemoryAccessVolatileMask) &&
|
||||
GetFuzzerContext()->ChooseEven();
|
||||
bool add_volatile =
|
||||
!(existing_mask & uint32_t(spv::MemoryAccessMask::Volatile)) &&
|
||||
GetFuzzerContext()->ChooseEven();
|
||||
bool toggle_nontemporal =
|
||||
!add_volatile || GetFuzzerContext()->ChooseEven();
|
||||
|
||||
// These bitwise operations use '|' to add Volatile if desired, and
|
||||
// '^' to toggle Nontemporal if desired.
|
||||
uint32_t new_mask =
|
||||
(existing_mask | (add_volatile ? SpvMemoryAccessVolatileMask
|
||||
: SpvMemoryAccessMaskNone)) ^
|
||||
(toggle_nontemporal ? SpvMemoryAccessNontemporalMask
|
||||
: SpvMemoryAccessMaskNone);
|
||||
(existing_mask |
|
||||
(add_volatile ? uint32_t(spv::MemoryAccessMask::Volatile)
|
||||
: uint32_t(spv::MemoryAccessMask::MaskNone))) ^
|
||||
(toggle_nontemporal ? uint32_t(spv::MemoryAccessMask::Nontemporal)
|
||||
: uint32_t(spv::MemoryAccessMask::MaskNone));
|
||||
|
||||
TransformationSetMemoryOperandsMask transformation(
|
||||
MakeInstructionDescriptor(block, inst_it), new_mask, mask_index);
|
||||
|
@ -34,7 +34,7 @@ void FuzzerPassAdjustSelectionControls::Apply() {
|
||||
for (auto& block : function) {
|
||||
if (auto merge_inst = block.GetMergeInst()) {
|
||||
// Ignore the instruction if it is not a selection merge.
|
||||
if (merge_inst->opcode() != SpvOpSelectionMerge) {
|
||||
if (merge_inst->opcode() != spv::Op::OpSelectionMerge) {
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -48,13 +48,14 @@ void FuzzerPassAdjustSelectionControls::Apply() {
|
||||
// The choices to change the selection control to are the set of valid
|
||||
// controls, minus the current control.
|
||||
std::vector<uint32_t> choices;
|
||||
for (auto control :
|
||||
{SpvSelectionControlMaskNone, SpvSelectionControlFlattenMask,
|
||||
SpvSelectionControlDontFlattenMask}) {
|
||||
if (control == merge_inst->GetSingleWordOperand(1)) {
|
||||
for (auto control : {spv::SelectionControlMask::MaskNone,
|
||||
spv::SelectionControlMask::Flatten,
|
||||
spv::SelectionControlMask::DontFlatten}) {
|
||||
if (control ==
|
||||
spv::SelectionControlMask(merge_inst->GetSingleWordOperand(1))) {
|
||||
continue;
|
||||
}
|
||||
choices.push_back(control);
|
||||
choices.push_back(uint32_t(control));
|
||||
}
|
||||
|
||||
// Apply the transformation and add it to the output transformation
|
||||
|
@ -107,9 +107,9 @@ void FuzzerPassApplyIdSynonyms::Apply() {
|
||||
// which case we need to be able to add an extract instruction to get
|
||||
// that element out.
|
||||
if (synonym_to_try->index_size() > 0 &&
|
||||
!fuzzerutil::CanInsertOpcodeBeforeInstruction(SpvOpCompositeExtract,
|
||||
use_inst) &&
|
||||
use_inst->opcode() != SpvOpPhi) {
|
||||
!fuzzerutil::CanInsertOpcodeBeforeInstruction(
|
||||
spv::Op::OpCompositeExtract, use_inst) &&
|
||||
use_inst->opcode() != spv::Op::OpPhi) {
|
||||
// We cannot insert an extract before this instruction, so this
|
||||
// synonym is no good.
|
||||
continue;
|
||||
@ -132,7 +132,7 @@ void FuzzerPassApplyIdSynonyms::Apply() {
|
||||
id_with_which_to_replace_use = GetFuzzerContext()->GetFreshId();
|
||||
opt::Instruction* instruction_to_insert_before = nullptr;
|
||||
|
||||
if (use_inst->opcode() != SpvOpPhi) {
|
||||
if (use_inst->opcode() != spv::Op::OpPhi) {
|
||||
instruction_to_insert_before = use_inst;
|
||||
} else {
|
||||
auto parent_block_id =
|
||||
@ -182,7 +182,7 @@ void FuzzerPassApplyIdSynonyms::Apply() {
|
||||
}
|
||||
|
||||
bool FuzzerPassApplyIdSynonyms::DataDescriptorsHaveCompatibleTypes(
|
||||
SpvOp opcode, uint32_t use_in_operand_index,
|
||||
spv::Op opcode, uint32_t use_in_operand_index,
|
||||
const protobufs::DataDescriptor& dd1,
|
||||
const protobufs::DataDescriptor& dd2) {
|
||||
auto base_object_type_id_1 =
|
||||
|
@ -38,7 +38,7 @@ class FuzzerPassApplyIdSynonyms : public FuzzerPass {
|
||||
// with respect to the type. Concretely, returns true if |dd1| and |dd2| have
|
||||
// the same type or both |dd1| and |dd2| are either a numerical or a vector
|
||||
// type of integral components with possibly different signedness.
|
||||
bool DataDescriptorsHaveCompatibleTypes(SpvOp opcode,
|
||||
bool DataDescriptorsHaveCompatibleTypes(spv::Op opcode,
|
||||
uint32_t use_in_operand_index,
|
||||
const protobufs::DataDescriptor& dd1,
|
||||
const protobufs::DataDescriptor& dd2);
|
||||
|
@ -81,7 +81,7 @@ void FuzzerPassConstructComposites::Apply() {
|
||||
// Check whether it is legitimate to insert a composite construction
|
||||
// before the instruction.
|
||||
if (!fuzzerutil::CanInsertOpcodeBeforeInstruction(
|
||||
SpvOpCompositeConstruct, inst_it)) {
|
||||
spv::Op::OpCompositeConstruct, inst_it)) {
|
||||
return;
|
||||
}
|
||||
|
||||
@ -121,19 +121,19 @@ void FuzzerPassConstructComposites::Apply() {
|
||||
auto composite_type_inst =
|
||||
GetIRContext()->get_def_use_mgr()->GetDef(chosen_composite_type);
|
||||
switch (composite_type_inst->opcode()) {
|
||||
case SpvOpTypeArray:
|
||||
case spv::Op::OpTypeArray:
|
||||
constructor_arguments = FindComponentsToConstructArray(
|
||||
*composite_type_inst, type_id_to_available_instructions);
|
||||
break;
|
||||
case SpvOpTypeMatrix:
|
||||
case spv::Op::OpTypeMatrix:
|
||||
constructor_arguments = FindComponentsToConstructMatrix(
|
||||
*composite_type_inst, type_id_to_available_instructions);
|
||||
break;
|
||||
case SpvOpTypeStruct:
|
||||
case spv::Op::OpTypeStruct:
|
||||
constructor_arguments = FindComponentsToConstructStruct(
|
||||
*composite_type_inst, type_id_to_available_instructions);
|
||||
break;
|
||||
case SpvOpTypeVector:
|
||||
case spv::Op::OpTypeVector:
|
||||
constructor_arguments = FindComponentsToConstructVector(
|
||||
*composite_type_inst, type_id_to_available_instructions);
|
||||
break;
|
||||
@ -156,7 +156,7 @@ std::vector<uint32_t>
|
||||
FuzzerPassConstructComposites::FindComponentsToConstructArray(
|
||||
const opt::Instruction& array_type_instruction,
|
||||
const TypeIdToInstructions& type_id_to_available_instructions) {
|
||||
assert(array_type_instruction.opcode() == SpvOpTypeArray &&
|
||||
assert(array_type_instruction.opcode() == spv::Op::OpTypeArray &&
|
||||
"Precondition: instruction must be an array type.");
|
||||
|
||||
// Get the element type for the array.
|
||||
@ -191,7 +191,7 @@ std::vector<uint32_t>
|
||||
FuzzerPassConstructComposites::FindComponentsToConstructMatrix(
|
||||
const opt::Instruction& matrix_type_instruction,
|
||||
const TypeIdToInstructions& type_id_to_available_instructions) {
|
||||
assert(matrix_type_instruction.opcode() == SpvOpTypeMatrix &&
|
||||
assert(matrix_type_instruction.opcode() == spv::Op::OpTypeMatrix &&
|
||||
"Precondition: instruction must be a matrix type.");
|
||||
|
||||
// Get the element type for the matrix.
|
||||
@ -221,7 +221,7 @@ std::vector<uint32_t>
|
||||
FuzzerPassConstructComposites::FindComponentsToConstructStruct(
|
||||
const opt::Instruction& struct_type_instruction,
|
||||
const TypeIdToInstructions& type_id_to_available_instructions) {
|
||||
assert(struct_type_instruction.opcode() == SpvOpTypeStruct &&
|
||||
assert(struct_type_instruction.opcode() == spv::Op::OpTypeStruct &&
|
||||
"Precondition: instruction must be a struct type.");
|
||||
std::vector<uint32_t> result;
|
||||
// Consider the type of each field of the struct.
|
||||
@ -251,7 +251,7 @@ std::vector<uint32_t>
|
||||
FuzzerPassConstructComposites::FindComponentsToConstructVector(
|
||||
const opt::Instruction& vector_type_instruction,
|
||||
const TypeIdToInstructions& type_id_to_available_instructions) {
|
||||
assert(vector_type_instruction.opcode() == SpvOpTypeVector &&
|
||||
assert(vector_type_instruction.opcode() == spv::Op::OpTypeVector &&
|
||||
"Precondition: instruction must be a vector type.");
|
||||
|
||||
// Get details of the type underlying the vector, and the width of the vector,
|
||||
|
@ -35,10 +35,11 @@ void FuzzerPassCopyObjects::Apply() {
|
||||
opt::BasicBlock::iterator inst_it,
|
||||
const protobufs::InstructionDescriptor& instruction_descriptor)
|
||||
-> void {
|
||||
assert(inst_it->opcode() ==
|
||||
instruction_descriptor.target_instruction_opcode() &&
|
||||
"The opcode of the instruction we might insert before must be "
|
||||
"the same as the opcode in the descriptor for the instruction");
|
||||
assert(
|
||||
inst_it->opcode() ==
|
||||
spv::Op(instruction_descriptor.target_instruction_opcode()) &&
|
||||
"The opcode of the instruction we might insert before must be "
|
||||
"the same as the opcode in the descriptor for the instruction");
|
||||
|
||||
if (GetTransformationContext()->GetFactManager()->BlockIsDead(
|
||||
block->id())) {
|
||||
@ -48,7 +49,7 @@ void FuzzerPassCopyObjects::Apply() {
|
||||
|
||||
// Check whether it is legitimate to insert a copy before this
|
||||
// instruction.
|
||||
if (!fuzzerutil::CanInsertOpcodeBeforeInstruction(SpvOpCopyObject,
|
||||
if (!fuzzerutil::CanInsertOpcodeBeforeInstruction(spv::Op::OpCopyObject,
|
||||
inst_it)) {
|
||||
return;
|
||||
}
|
||||
|
@ -88,7 +88,7 @@ void FuzzerPassDonateModules::DonateSingleModule(
|
||||
// module.
|
||||
for (const auto& capability_inst : donor_ir_context->capabilities()) {
|
||||
auto capability =
|
||||
static_cast<SpvCapability>(capability_inst.GetSingleWordInOperand(0));
|
||||
static_cast<spv::Capability>(capability_inst.GetSingleWordInOperand(0));
|
||||
if (!GetIRContext()->get_feature_mgr()->HasCapability(capability)) {
|
||||
return;
|
||||
}
|
||||
@ -122,27 +122,27 @@ void FuzzerPassDonateModules::DonateSingleModule(
|
||||
// kinds of decoration.
|
||||
}
|
||||
|
||||
SpvStorageClass FuzzerPassDonateModules::AdaptStorageClass(
|
||||
SpvStorageClass donor_storage_class) {
|
||||
spv::StorageClass FuzzerPassDonateModules::AdaptStorageClass(
|
||||
spv::StorageClass donor_storage_class) {
|
||||
switch (donor_storage_class) {
|
||||
case SpvStorageClassFunction:
|
||||
case SpvStorageClassPrivate:
|
||||
case SpvStorageClassWorkgroup:
|
||||
case spv::StorageClass::Function:
|
||||
case spv::StorageClass::Private:
|
||||
case spv::StorageClass::Workgroup:
|
||||
// We leave these alone
|
||||
return donor_storage_class;
|
||||
case SpvStorageClassInput:
|
||||
case SpvStorageClassOutput:
|
||||
case SpvStorageClassUniform:
|
||||
case SpvStorageClassUniformConstant:
|
||||
case SpvStorageClassPushConstant:
|
||||
case SpvStorageClassImage:
|
||||
case SpvStorageClassStorageBuffer:
|
||||
case spv::StorageClass::Input:
|
||||
case spv::StorageClass::Output:
|
||||
case spv::StorageClass::Uniform:
|
||||
case spv::StorageClass::UniformConstant:
|
||||
case spv::StorageClass::PushConstant:
|
||||
case spv::StorageClass::Image:
|
||||
case spv::StorageClass::StorageBuffer:
|
||||
// We change these to Private
|
||||
return SpvStorageClassPrivate;
|
||||
return spv::StorageClass::Private;
|
||||
default:
|
||||
// Handle other cases on demand.
|
||||
assert(false && "Currently unsupported storage class.");
|
||||
return SpvStorageClassMax;
|
||||
return spv::StorageClass::Max;
|
||||
}
|
||||
}
|
||||
|
||||
@ -200,14 +200,14 @@ void FuzzerPassDonateModules::HandleTypeOrValue(
|
||||
// that its component types will have been considered previously, and that
|
||||
// |original_id_to_donated_id| will already contain an entry for them.
|
||||
switch (type_or_value.opcode()) {
|
||||
case SpvOpTypeImage:
|
||||
case SpvOpTypeSampledImage:
|
||||
case SpvOpTypeSampler:
|
||||
case spv::Op::OpTypeImage:
|
||||
case spv::Op::OpTypeSampledImage:
|
||||
case spv::Op::OpTypeSampler:
|
||||
// We do not donate types and variables that relate to images and
|
||||
// samplers, so we skip these types and subsequently skip anything that
|
||||
// depends on them.
|
||||
return;
|
||||
case SpvOpTypeVoid: {
|
||||
case spv::Op::OpTypeVoid: {
|
||||
// Void has to exist already in order for us to have an entry point.
|
||||
// Get the existing id of void.
|
||||
opt::analysis::Void void_type;
|
||||
@ -216,7 +216,7 @@ void FuzzerPassDonateModules::HandleTypeOrValue(
|
||||
"The module being transformed will always have 'void' type "
|
||||
"declared.");
|
||||
} break;
|
||||
case SpvOpTypeBool: {
|
||||
case spv::Op::OpTypeBool: {
|
||||
// Bool cannot be declared multiple times, so use its existing id if
|
||||
// present, or add a declaration of Bool with a fresh id if not.
|
||||
opt::analysis::Bool bool_type;
|
||||
@ -228,7 +228,7 @@ void FuzzerPassDonateModules::HandleTypeOrValue(
|
||||
ApplyTransformation(TransformationAddTypeBoolean(new_result_id));
|
||||
}
|
||||
} break;
|
||||
case SpvOpTypeInt: {
|
||||
case spv::Op::OpTypeInt: {
|
||||
// Int cannot be declared multiple times with the same width and
|
||||
// signedness, so check whether an existing identical Int type is
|
||||
// present and use its id if so. Otherwise add a declaration of the
|
||||
@ -246,8 +246,8 @@ void FuzzerPassDonateModules::HandleTypeOrValue(
|
||||
TransformationAddTypeInt(new_result_id, width, is_signed));
|
||||
}
|
||||
} break;
|
||||
case SpvOpTypeFloat: {
|
||||
// Similar to SpvOpTypeInt.
|
||||
case spv::Op::OpTypeFloat: {
|
||||
// Similar to spv::Op::OpTypeInt.
|
||||
const uint32_t width = type_or_value.GetSingleWordInOperand(0);
|
||||
opt::analysis::Float float_type(width);
|
||||
auto float_type_id = GetIRContext()->get_type_mgr()->GetId(&float_type);
|
||||
@ -258,7 +258,7 @@ void FuzzerPassDonateModules::HandleTypeOrValue(
|
||||
ApplyTransformation(TransformationAddTypeFloat(new_result_id, width));
|
||||
}
|
||||
} break;
|
||||
case SpvOpTypeVector: {
|
||||
case spv::Op::OpTypeVector: {
|
||||
// It is not legal to have two Vector type declarations with identical
|
||||
// element types and element counts, so check whether an existing
|
||||
// identical Vector type is present and use its id if so. Otherwise add
|
||||
@ -282,8 +282,8 @@ void FuzzerPassDonateModules::HandleTypeOrValue(
|
||||
new_result_id, component_type_id, component_count));
|
||||
}
|
||||
} break;
|
||||
case SpvOpTypeMatrix: {
|
||||
// Similar to SpvOpTypeVector.
|
||||
case spv::Op::OpTypeMatrix: {
|
||||
// Similar to spv::Op::OpTypeVector.
|
||||
uint32_t column_type_id = original_id_to_donated_id->at(
|
||||
type_or_value.GetSingleWordInOperand(0));
|
||||
auto column_type =
|
||||
@ -302,7 +302,7 @@ void FuzzerPassDonateModules::HandleTypeOrValue(
|
||||
}
|
||||
|
||||
} break;
|
||||
case SpvOpTypeArray: {
|
||||
case spv::Op::OpTypeArray: {
|
||||
// It is OK to have multiple structurally identical array types, so
|
||||
// we go ahead and add a remapped version of the type declared by the
|
||||
// donor.
|
||||
@ -318,7 +318,7 @@ void FuzzerPassDonateModules::HandleTypeOrValue(
|
||||
original_id_to_donated_id->at(
|
||||
type_or_value.GetSingleWordInOperand(1))));
|
||||
} break;
|
||||
case SpvOpTypeRuntimeArray: {
|
||||
case spv::Op::OpTypeRuntimeArray: {
|
||||
// A runtime array is allowed as the final member of an SSBO. During
|
||||
// donation we turn runtime arrays into fixed-size arrays. For dead
|
||||
// code donations this is OK because the array is never indexed into at
|
||||
@ -341,8 +341,8 @@ void FuzzerPassDonateModules::HandleTypeOrValue(
|
||||
{GetFuzzerContext()->GetRandomSizeForNewArray()}, 32, false,
|
||||
false)));
|
||||
} break;
|
||||
case SpvOpTypeStruct: {
|
||||
// Similar to SpvOpTypeArray.
|
||||
case spv::Op::OpTypeStruct: {
|
||||
// Similar to spv::Op::OpTypeArray.
|
||||
std::vector<uint32_t> member_type_ids;
|
||||
for (uint32_t i = 0; i < type_or_value.NumInOperands(); i++) {
|
||||
auto component_type_id = type_or_value.GetSingleWordInOperand(i);
|
||||
@ -358,8 +358,8 @@ void FuzzerPassDonateModules::HandleTypeOrValue(
|
||||
ApplyTransformation(
|
||||
TransformationAddTypeStruct(new_result_id, member_type_ids));
|
||||
} break;
|
||||
case SpvOpTypePointer: {
|
||||
// Similar to SpvOpTypeArray.
|
||||
case spv::Op::OpTypePointer: {
|
||||
// Similar to spv::Op::OpTypeArray.
|
||||
uint32_t pointee_type_id = type_or_value.GetSingleWordInOperand(1);
|
||||
if (!original_id_to_donated_id->count(pointee_type_id)) {
|
||||
// We did not donate the pointee type for this pointer type, so we
|
||||
@ -369,11 +369,11 @@ void FuzzerPassDonateModules::HandleTypeOrValue(
|
||||
new_result_id = GetFuzzerContext()->GetFreshId();
|
||||
ApplyTransformation(TransformationAddTypePointer(
|
||||
new_result_id,
|
||||
AdaptStorageClass(static_cast<SpvStorageClass>(
|
||||
AdaptStorageClass(static_cast<spv::StorageClass>(
|
||||
type_or_value.GetSingleWordInOperand(0))),
|
||||
original_id_to_donated_id->at(pointee_type_id)));
|
||||
} break;
|
||||
case SpvOpTypeFunction: {
|
||||
case spv::Op::OpTypeFunction: {
|
||||
// It is not OK to have multiple function types that use identical ids
|
||||
// for their return and parameter types. We thus go through all
|
||||
// existing function types to look for a match. We do not use the
|
||||
@ -425,10 +425,11 @@ void FuzzerPassDonateModules::HandleTypeOrValue(
|
||||
argument_type_ids));
|
||||
}
|
||||
} break;
|
||||
case SpvOpSpecConstantOp: {
|
||||
case spv::Op::OpSpecConstantOp: {
|
||||
new_result_id = GetFuzzerContext()->GetFreshId();
|
||||
auto type_id = original_id_to_donated_id->at(type_or_value.type_id());
|
||||
auto opcode = static_cast<SpvOp>(type_or_value.GetSingleWordInOperand(0));
|
||||
auto opcode =
|
||||
static_cast<spv::Op>(type_or_value.GetSingleWordInOperand(0));
|
||||
|
||||
// Make sure we take into account |original_id_to_donated_id| when
|
||||
// computing operands for OpSpecConstantOp.
|
||||
@ -447,20 +448,20 @@ void FuzzerPassDonateModules::HandleTypeOrValue(
|
||||
ApplyTransformation(TransformationAddSpecConstantOp(
|
||||
new_result_id, type_id, opcode, std::move(operands)));
|
||||
} break;
|
||||
case SpvOpSpecConstantTrue:
|
||||
case SpvOpSpecConstantFalse:
|
||||
case SpvOpConstantTrue:
|
||||
case SpvOpConstantFalse: {
|
||||
case spv::Op::OpSpecConstantTrue:
|
||||
case spv::Op::OpSpecConstantFalse:
|
||||
case spv::Op::OpConstantTrue:
|
||||
case spv::Op::OpConstantFalse: {
|
||||
// It is OK to have duplicate definitions of True and False, so add
|
||||
// these to the module, using a remapped Bool type.
|
||||
new_result_id = GetFuzzerContext()->GetFreshId();
|
||||
auto value = type_or_value.opcode() == SpvOpConstantTrue ||
|
||||
type_or_value.opcode() == SpvOpSpecConstantTrue;
|
||||
auto value = type_or_value.opcode() == spv::Op::OpConstantTrue ||
|
||||
type_or_value.opcode() == spv::Op::OpSpecConstantTrue;
|
||||
ApplyTransformation(
|
||||
TransformationAddConstantBoolean(new_result_id, value, false));
|
||||
} break;
|
||||
case SpvOpSpecConstant:
|
||||
case SpvOpConstant: {
|
||||
case spv::Op::OpSpecConstant:
|
||||
case spv::Op::OpConstant: {
|
||||
// It is OK to have duplicate constant definitions, so add this to the
|
||||
// module using a remapped result type.
|
||||
new_result_id = GetFuzzerContext()->GetFreshId();
|
||||
@ -472,8 +473,8 @@ void FuzzerPassDonateModules::HandleTypeOrValue(
|
||||
new_result_id, original_id_to_donated_id->at(type_or_value.type_id()),
|
||||
data_words, false));
|
||||
} break;
|
||||
case SpvOpSpecConstantComposite:
|
||||
case SpvOpConstantComposite: {
|
||||
case spv::Op::OpSpecConstantComposite:
|
||||
case spv::Op::OpConstantComposite: {
|
||||
assert(original_id_to_donated_id->count(type_or_value.type_id()) &&
|
||||
"Composite types for which it is possible to create a constant "
|
||||
"should have been donated.");
|
||||
@ -495,7 +496,7 @@ void FuzzerPassDonateModules::HandleTypeOrValue(
|
||||
new_result_id, original_id_to_donated_id->at(type_or_value.type_id()),
|
||||
constituent_ids, false));
|
||||
} break;
|
||||
case SpvOpConstantNull: {
|
||||
case spv::Op::OpConstantNull: {
|
||||
if (!original_id_to_donated_id->count(type_or_value.type_id())) {
|
||||
// We did not donate the type associated with this null constant, so
|
||||
// we cannot donate the null constant.
|
||||
@ -509,7 +510,7 @@ void FuzzerPassDonateModules::HandleTypeOrValue(
|
||||
new_result_id,
|
||||
original_id_to_donated_id->at(type_or_value.type_id())));
|
||||
} break;
|
||||
case SpvOpVariable: {
|
||||
case spv::Op::OpVariable: {
|
||||
if (!original_id_to_donated_id->count(type_or_value.type_id())) {
|
||||
// We did not donate the pointer type associated with this variable,
|
||||
// so we cannot donate the variable.
|
||||
@ -536,11 +537,11 @@ void FuzzerPassDonateModules::HandleTypeOrValue(
|
||||
uint32_t remapped_pointer_type =
|
||||
original_id_to_donated_id->at(type_or_value.type_id());
|
||||
uint32_t initializer_id;
|
||||
SpvStorageClass storage_class =
|
||||
static_cast<SpvStorageClass>(type_or_value.GetSingleWordInOperand(
|
||||
0)) == SpvStorageClassWorkgroup
|
||||
? SpvStorageClassWorkgroup
|
||||
: SpvStorageClassPrivate;
|
||||
spv::StorageClass storage_class =
|
||||
static_cast<spv::StorageClass>(type_or_value.GetSingleWordInOperand(
|
||||
0)) == spv::StorageClass::Workgroup
|
||||
? spv::StorageClass::Workgroup
|
||||
: spv::StorageClass::Private;
|
||||
if (type_or_value.NumInOperands() == 1) {
|
||||
// The variable did not have an initializer. Initialize it to zero
|
||||
// if it has Private storage class (to limit problems associated with
|
||||
@ -551,7 +552,7 @@ void FuzzerPassDonateModules::HandleTypeOrValue(
|
||||
// could initialize Workgroup variables at the start of an entry
|
||||
// point, and should do so if their uninitialized nature proves
|
||||
// problematic.
|
||||
initializer_id = storage_class == SpvStorageClassWorkgroup
|
||||
initializer_id = storage_class == spv::StorageClass::Workgroup
|
||||
? 0
|
||||
: FindOrCreateZeroConstant(
|
||||
fuzzerutil::GetPointeeTypeIdFromPointerType(
|
||||
@ -566,7 +567,7 @@ void FuzzerPassDonateModules::HandleTypeOrValue(
|
||||
TransformationAddGlobalVariable(new_result_id, remapped_pointer_type,
|
||||
storage_class, initializer_id, true));
|
||||
} break;
|
||||
case SpvOpUndef: {
|
||||
case spv::Op::OpUndef: {
|
||||
if (!original_id_to_donated_id->count(type_or_value.type_id())) {
|
||||
// We did not donate the type associated with this undef, so we cannot
|
||||
// donate the undef.
|
||||
@ -638,7 +639,7 @@ void FuzzerPassDonateModules::HandleFunctions(
|
||||
[this, &donated_instructions, donor_ir_context,
|
||||
&original_id_to_donated_id,
|
||||
&skipped_instructions](const opt::Instruction* instruction) {
|
||||
if (instruction->opcode() == SpvOpArrayLength) {
|
||||
if (instruction->opcode() == spv::Op::OpArrayLength) {
|
||||
// We treat OpArrayLength specially.
|
||||
HandleOpArrayLength(*instruction, original_id_to_donated_id,
|
||||
&donated_instructions);
|
||||
@ -682,70 +683,70 @@ bool FuzzerPassDonateModules::CanDonateInstruction(
|
||||
// Now consider instructions we specifically want to skip because we do not
|
||||
// yet support them.
|
||||
switch (instruction.opcode()) {
|
||||
case SpvOpAtomicLoad:
|
||||
case SpvOpAtomicStore:
|
||||
case SpvOpAtomicExchange:
|
||||
case SpvOpAtomicCompareExchange:
|
||||
case SpvOpAtomicCompareExchangeWeak:
|
||||
case SpvOpAtomicIIncrement:
|
||||
case SpvOpAtomicIDecrement:
|
||||
case SpvOpAtomicIAdd:
|
||||
case SpvOpAtomicISub:
|
||||
case SpvOpAtomicSMin:
|
||||
case SpvOpAtomicUMin:
|
||||
case SpvOpAtomicSMax:
|
||||
case SpvOpAtomicUMax:
|
||||
case SpvOpAtomicAnd:
|
||||
case SpvOpAtomicOr:
|
||||
case SpvOpAtomicXor:
|
||||
case spv::Op::OpAtomicLoad:
|
||||
case spv::Op::OpAtomicStore:
|
||||
case spv::Op::OpAtomicExchange:
|
||||
case spv::Op::OpAtomicCompareExchange:
|
||||
case spv::Op::OpAtomicCompareExchangeWeak:
|
||||
case spv::Op::OpAtomicIIncrement:
|
||||
case spv::Op::OpAtomicIDecrement:
|
||||
case spv::Op::OpAtomicIAdd:
|
||||
case spv::Op::OpAtomicISub:
|
||||
case spv::Op::OpAtomicSMin:
|
||||
case spv::Op::OpAtomicUMin:
|
||||
case spv::Op::OpAtomicSMax:
|
||||
case spv::Op::OpAtomicUMax:
|
||||
case spv::Op::OpAtomicAnd:
|
||||
case spv::Op::OpAtomicOr:
|
||||
case spv::Op::OpAtomicXor:
|
||||
// We conservatively ignore all atomic instructions at present.
|
||||
// TODO(https://github.com/KhronosGroup/SPIRV-Tools/issues/3276): Consider
|
||||
// being less conservative here.
|
||||
case SpvOpImageSampleImplicitLod:
|
||||
case SpvOpImageSampleExplicitLod:
|
||||
case SpvOpImageSampleDrefImplicitLod:
|
||||
case SpvOpImageSampleDrefExplicitLod:
|
||||
case SpvOpImageSampleProjImplicitLod:
|
||||
case SpvOpImageSampleProjExplicitLod:
|
||||
case SpvOpImageSampleProjDrefImplicitLod:
|
||||
case SpvOpImageSampleProjDrefExplicitLod:
|
||||
case SpvOpImageFetch:
|
||||
case SpvOpImageGather:
|
||||
case SpvOpImageDrefGather:
|
||||
case SpvOpImageRead:
|
||||
case SpvOpImageWrite:
|
||||
case SpvOpImageSparseSampleImplicitLod:
|
||||
case SpvOpImageSparseSampleExplicitLod:
|
||||
case SpvOpImageSparseSampleDrefImplicitLod:
|
||||
case SpvOpImageSparseSampleDrefExplicitLod:
|
||||
case SpvOpImageSparseSampleProjImplicitLod:
|
||||
case SpvOpImageSparseSampleProjExplicitLod:
|
||||
case SpvOpImageSparseSampleProjDrefImplicitLod:
|
||||
case SpvOpImageSparseSampleProjDrefExplicitLod:
|
||||
case SpvOpImageSparseFetch:
|
||||
case SpvOpImageSparseGather:
|
||||
case SpvOpImageSparseDrefGather:
|
||||
case SpvOpImageSparseRead:
|
||||
case SpvOpImageSampleFootprintNV:
|
||||
case SpvOpImage:
|
||||
case SpvOpImageQueryFormat:
|
||||
case SpvOpImageQueryLevels:
|
||||
case SpvOpImageQueryLod:
|
||||
case SpvOpImageQueryOrder:
|
||||
case SpvOpImageQuerySamples:
|
||||
case SpvOpImageQuerySize:
|
||||
case SpvOpImageQuerySizeLod:
|
||||
case SpvOpSampledImage:
|
||||
case spv::Op::OpImageSampleImplicitLod:
|
||||
case spv::Op::OpImageSampleExplicitLod:
|
||||
case spv::Op::OpImageSampleDrefImplicitLod:
|
||||
case spv::Op::OpImageSampleDrefExplicitLod:
|
||||
case spv::Op::OpImageSampleProjImplicitLod:
|
||||
case spv::Op::OpImageSampleProjExplicitLod:
|
||||
case spv::Op::OpImageSampleProjDrefImplicitLod:
|
||||
case spv::Op::OpImageSampleProjDrefExplicitLod:
|
||||
case spv::Op::OpImageFetch:
|
||||
case spv::Op::OpImageGather:
|
||||
case spv::Op::OpImageDrefGather:
|
||||
case spv::Op::OpImageRead:
|
||||
case spv::Op::OpImageWrite:
|
||||
case spv::Op::OpImageSparseSampleImplicitLod:
|
||||
case spv::Op::OpImageSparseSampleExplicitLod:
|
||||
case spv::Op::OpImageSparseSampleDrefImplicitLod:
|
||||
case spv::Op::OpImageSparseSampleDrefExplicitLod:
|
||||
case spv::Op::OpImageSparseSampleProjImplicitLod:
|
||||
case spv::Op::OpImageSparseSampleProjExplicitLod:
|
||||
case spv::Op::OpImageSparseSampleProjDrefImplicitLod:
|
||||
case spv::Op::OpImageSparseSampleProjDrefExplicitLod:
|
||||
case spv::Op::OpImageSparseFetch:
|
||||
case spv::Op::OpImageSparseGather:
|
||||
case spv::Op::OpImageSparseDrefGather:
|
||||
case spv::Op::OpImageSparseRead:
|
||||
case spv::Op::OpImageSampleFootprintNV:
|
||||
case spv::Op::OpImage:
|
||||
case spv::Op::OpImageQueryFormat:
|
||||
case spv::Op::OpImageQueryLevels:
|
||||
case spv::Op::OpImageQueryLod:
|
||||
case spv::Op::OpImageQueryOrder:
|
||||
case spv::Op::OpImageQuerySamples:
|
||||
case spv::Op::OpImageQuerySize:
|
||||
case spv::Op::OpImageQuerySizeLod:
|
||||
case spv::Op::OpSampledImage:
|
||||
// We ignore all instructions related to accessing images, since we do not
|
||||
// donate images.
|
||||
return false;
|
||||
case SpvOpLoad:
|
||||
case spv::Op::OpLoad:
|
||||
switch (donor_ir_context->get_def_use_mgr()
|
||||
->GetDef(instruction.type_id())
|
||||
->opcode()) {
|
||||
case SpvOpTypeImage:
|
||||
case SpvOpTypeSampledImage:
|
||||
case SpvOpTypeSampler:
|
||||
case spv::Op::OpTypeImage:
|
||||
case spv::Op::OpTypeSampledImage:
|
||||
case spv::Op::OpTypeSampler:
|
||||
// Again, we ignore instructions that relate to accessing images.
|
||||
return false;
|
||||
default:
|
||||
@ -783,13 +784,13 @@ bool FuzzerPassDonateModules::CanDonateInstruction(
|
||||
bool FuzzerPassDonateModules::IsBasicType(
|
||||
const opt::Instruction& instruction) const {
|
||||
switch (instruction.opcode()) {
|
||||
case SpvOpTypeArray:
|
||||
case SpvOpTypeBool:
|
||||
case SpvOpTypeFloat:
|
||||
case SpvOpTypeInt:
|
||||
case SpvOpTypeMatrix:
|
||||
case SpvOpTypeStruct:
|
||||
case SpvOpTypeVector:
|
||||
case spv::Op::OpTypeArray:
|
||||
case spv::Op::OpTypeBool:
|
||||
case spv::Op::OpTypeFloat:
|
||||
case spv::Op::OpTypeInt:
|
||||
case spv::Op::OpTypeMatrix:
|
||||
case spv::Op::OpTypeStruct:
|
||||
case spv::Op::OpTypeVector:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
@ -800,7 +801,7 @@ void FuzzerPassDonateModules::HandleOpArrayLength(
|
||||
const opt::Instruction& instruction,
|
||||
std::map<uint32_t, uint32_t>* original_id_to_donated_id,
|
||||
std::vector<protobufs::Instruction>* donated_instructions) const {
|
||||
assert(instruction.opcode() == SpvOpArrayLength &&
|
||||
assert(instruction.opcode() == spv::Op::OpArrayLength &&
|
||||
"Precondition: instruction must be OpArrayLength.");
|
||||
uint32_t donated_variable_id =
|
||||
original_id_to_donated_id->at(instruction.GetSingleWordInOperand(0));
|
||||
@ -809,12 +810,12 @@ void FuzzerPassDonateModules::HandleOpArrayLength(
|
||||
auto pointer_to_struct_instruction =
|
||||
GetIRContext()->get_def_use_mgr()->GetDef(
|
||||
donated_variable_instruction->type_id());
|
||||
assert(pointer_to_struct_instruction->opcode() == SpvOpTypePointer &&
|
||||
assert(pointer_to_struct_instruction->opcode() == spv::Op::OpTypePointer &&
|
||||
"Type of variable must be pointer.");
|
||||
auto donated_struct_type_instruction =
|
||||
GetIRContext()->get_def_use_mgr()->GetDef(
|
||||
pointer_to_struct_instruction->GetSingleWordInOperand(1));
|
||||
assert(donated_struct_type_instruction->opcode() == SpvOpTypeStruct &&
|
||||
assert(donated_struct_type_instruction->opcode() == spv::Op::OpTypeStruct &&
|
||||
"Pointee type of pointer used by OpArrayLength must be struct.");
|
||||
assert(donated_struct_type_instruction->NumInOperands() ==
|
||||
instruction.GetSingleWordInOperand(1) + 1 &&
|
||||
@ -825,7 +826,7 @@ void FuzzerPassDonateModules::HandleOpArrayLength(
|
||||
donated_struct_type_instruction->NumInOperands() - 1);
|
||||
auto fixed_size_array_type_instruction =
|
||||
GetIRContext()->get_def_use_mgr()->GetDef(fixed_size_array_type_id);
|
||||
assert(fixed_size_array_type_instruction->opcode() == SpvOpTypeArray &&
|
||||
assert(fixed_size_array_type_instruction->opcode() == spv::Op::OpTypeArray &&
|
||||
"The donated array type must be fixed-size.");
|
||||
auto array_size_id =
|
||||
fixed_size_array_type_instruction->GetSingleWordInOperand(1);
|
||||
@ -837,7 +838,8 @@ void FuzzerPassDonateModules::HandleOpArrayLength(
|
||||
}
|
||||
|
||||
donated_instructions->push_back(MakeInstructionMessage(
|
||||
SpvOpCopyObject, original_id_to_donated_id->at(instruction.type_id()),
|
||||
spv::Op::OpCopyObject,
|
||||
original_id_to_donated_id->at(instruction.type_id()),
|
||||
original_id_to_donated_id->at(instruction.result_id()),
|
||||
opt::Instruction::OperandList({{SPV_OPERAND_TYPE_ID, {array_size_id}}})));
|
||||
}
|
||||
@ -892,7 +894,7 @@ void FuzzerPassDonateModules::HandleDifficultInstruction(
|
||||
// more interesting value later.
|
||||
auto zero_constant = FindOrCreateZeroConstant(remapped_type_id, true);
|
||||
donated_instructions->push_back(MakeInstructionMessage(
|
||||
SpvOpCopyObject, remapped_type_id,
|
||||
spv::Op::OpCopyObject, remapped_type_id,
|
||||
original_id_to_donated_id->at(instruction.result_id()),
|
||||
opt::Instruction::OperandList({{SPV_OPERAND_TYPE_ID, {zero_constant}}})));
|
||||
}
|
||||
@ -926,8 +928,8 @@ void FuzzerPassDonateModules::PrepareInstructionForDonation(
|
||||
(void)(donor_ir_context);
|
||||
assert((donor_ir_context->get_def_use_mgr()
|
||||
->GetDef(operand_id)
|
||||
->opcode() == SpvOpLabel ||
|
||||
instruction.opcode() == SpvOpPhi) &&
|
||||
->opcode() == spv::Op::OpLabel ||
|
||||
instruction.opcode() == spv::Op::OpPhi) &&
|
||||
"Unsupported forward reference.");
|
||||
original_id_to_donated_id->insert(
|
||||
{operand_id, GetFuzzerContext()->GetFreshId()});
|
||||
@ -942,7 +944,7 @@ void FuzzerPassDonateModules::PrepareInstructionForDonation(
|
||||
input_operands.push_back({in_operand.type, operand_data});
|
||||
}
|
||||
|
||||
if (instruction.opcode() == SpvOpVariable &&
|
||||
if (instruction.opcode() == spv::Op::OpVariable &&
|
||||
instruction.NumInOperands() == 1) {
|
||||
// This is an uninitialized local variable. Initialize it to zero.
|
||||
input_operands.push_back(
|
||||
@ -1017,7 +1019,7 @@ bool FuzzerPassDonateModules::CreateLoopLimiterInfo(
|
||||
|
||||
// Adjust OpPhi instructions in the |merge_block|.
|
||||
for (const auto& inst : *merge_block) {
|
||||
if (inst.opcode() != SpvOpPhi) {
|
||||
if (inst.opcode() != spv::Op::OpPhi) {
|
||||
break;
|
||||
}
|
||||
|
||||
@ -1070,7 +1072,8 @@ bool FuzzerPassDonateModules::MaybeAddLivesafeFunction(
|
||||
// live-safe. Add them if not already present.
|
||||
FindOrCreateBoolType(); // Needed for comparisons
|
||||
FindOrCreatePointerToIntegerType(
|
||||
32, false, SpvStorageClassFunction); // Needed for adding loop limiters
|
||||
32, false,
|
||||
spv::StorageClass::Function); // Needed for adding loop limiters
|
||||
FindOrCreateIntegerConstant({0}, 32, false,
|
||||
false); // Needed for initializing loop limiters
|
||||
FindOrCreateIntegerConstant({1}, 32, false,
|
||||
@ -1107,8 +1110,8 @@ bool FuzzerPassDonateModules::MaybeAddLivesafeFunction(
|
||||
for (auto& block : function_to_donate) {
|
||||
for (auto& inst : block) {
|
||||
switch (inst.opcode()) {
|
||||
case SpvOpAccessChain:
|
||||
case SpvOpInBoundsAccessChain: {
|
||||
case spv::Op::OpAccessChain:
|
||||
case spv::Op::OpInBoundsAccessChain: {
|
||||
protobufs::AccessChainClampingInfo clamping_info;
|
||||
clamping_info.set_access_chain_id(
|
||||
original_id_to_donated_id.at(inst.result_id()));
|
||||
@ -1118,7 +1121,8 @@ bool FuzzerPassDonateModules::MaybeAddLivesafeFunction(
|
||||
assert(base_object && "The base object must exist.");
|
||||
auto pointer_type = donor_ir_context->get_def_use_mgr()->GetDef(
|
||||
base_object->type_id());
|
||||
assert(pointer_type && pointer_type->opcode() == SpvOpTypePointer &&
|
||||
assert(pointer_type &&
|
||||
pointer_type->opcode() == spv::Op::OpTypePointer &&
|
||||
"The base object must have pointer type.");
|
||||
|
||||
auto should_be_composite_type =
|
||||
@ -1138,7 +1142,8 @@ bool FuzzerPassDonateModules::MaybeAddLivesafeFunction(
|
||||
|
||||
// Get the bound for the component being indexed into.
|
||||
uint32_t bound;
|
||||
if (should_be_composite_type->opcode() == SpvOpTypeRuntimeArray) {
|
||||
if (should_be_composite_type->opcode() ==
|
||||
spv::Op::OpTypeRuntimeArray) {
|
||||
// The donor is indexing into a runtime array. We do not
|
||||
// donate runtime arrays. Instead, we donate a corresponding
|
||||
// fixed-size array for every runtime array. We should thus
|
||||
@ -1148,7 +1153,7 @@ bool FuzzerPassDonateModules::MaybeAddLivesafeFunction(
|
||||
GetIRContext()->get_def_use_mgr()->GetDef(
|
||||
original_id_to_donated_id.at(
|
||||
should_be_composite_type->result_id()));
|
||||
assert(fixed_size_array_type->opcode() == SpvOpTypeArray &&
|
||||
assert(fixed_size_array_type->opcode() == spv::Op::OpTypeArray &&
|
||||
"A runtime array type in the donor should have been "
|
||||
"replaced by a fixed-sized array in the recipient.");
|
||||
// The size of this fixed-size array is a suitable bound.
|
||||
@ -1163,12 +1168,12 @@ bool FuzzerPassDonateModules::MaybeAddLivesafeFunction(
|
||||
donor_ir_context->get_def_use_mgr()->GetDef(index_id);
|
||||
auto index_type_inst = donor_ir_context->get_def_use_mgr()->GetDef(
|
||||
index_inst->type_id());
|
||||
assert(index_type_inst->opcode() == SpvOpTypeInt);
|
||||
assert(index_type_inst->opcode() == spv::Op::OpTypeInt);
|
||||
opt::analysis::Integer* index_int_type =
|
||||
donor_ir_context->get_type_mgr()
|
||||
->GetType(index_type_inst->result_id())
|
||||
->AsInteger();
|
||||
if (index_inst->opcode() != SpvOpConstant) {
|
||||
if (index_inst->opcode() != spv::Op::OpConstant) {
|
||||
// We will have to clamp this index, so we need a constant
|
||||
// whose value is one less than the bound, to compare
|
||||
// against and to use as the clamped value.
|
||||
@ -1194,7 +1199,7 @@ bool FuzzerPassDonateModules::MaybeAddLivesafeFunction(
|
||||
uint32_t kill_unreachable_return_value_id = 0;
|
||||
auto function_return_type_inst =
|
||||
donor_ir_context->get_def_use_mgr()->GetDef(function_to_donate.type_id());
|
||||
if (function_return_type_inst->opcode() != SpvOpTypeVoid &&
|
||||
if (function_return_type_inst->opcode() != spv::Op::OpTypeVoid &&
|
||||
fuzzerutil::FunctionContainsOpKillOrUnreachable(function_to_donate)) {
|
||||
kill_unreachable_return_value_id = FindOrCreateZeroConstant(
|
||||
original_id_to_donated_id.at(function_return_type_inst->result_id()),
|
||||
|
@ -45,7 +45,8 @@ class FuzzerPassDonateModules : public FuzzerPass {
|
||||
private:
|
||||
// Adapts a storage class coming from a donor module so that it will work
|
||||
// in a recipient module, e.g. by changing Uniform to Private.
|
||||
static SpvStorageClass AdaptStorageClass(SpvStorageClass donor_storage_class);
|
||||
static spv::StorageClass AdaptStorageClass(
|
||||
spv::StorageClass donor_storage_class);
|
||||
|
||||
// Identifies all external instruction set imports in |donor_ir_context| and
|
||||
// populates |original_id_to_donated_id| with a mapping from the donor's id
|
||||
|
@ -40,8 +40,8 @@ void FuzzerPassExpandVectorReductions::Apply() {
|
||||
}
|
||||
|
||||
// |instruction| must be OpAny or OpAll.
|
||||
if (instruction.opcode() != SpvOpAny &&
|
||||
instruction.opcode() != SpvOpAll) {
|
||||
if (instruction.opcode() != spv::Op::OpAny &&
|
||||
instruction.opcode() != spv::Op::OpAll) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -48,8 +48,8 @@ void FuzzerPassFlattenConditionalBranches::Apply() {
|
||||
// Only consider this block if it is the header of a conditional, with a
|
||||
// non-irrelevant condition.
|
||||
if (block.GetMergeInst() &&
|
||||
block.GetMergeInst()->opcode() == SpvOpSelectionMerge &&
|
||||
block.terminator()->opcode() == SpvOpBranchConditional &&
|
||||
block.GetMergeInst()->opcode() == spv::Op::OpSelectionMerge &&
|
||||
block.terminator()->opcode() == spv::Op::OpBranchConditional &&
|
||||
!GetTransformationContext()->GetFactManager()->IdIsIrrelevant(
|
||||
block.terminator()->GetSingleWordInOperand(0))) {
|
||||
selection_headers.emplace_back(&block);
|
||||
@ -94,11 +94,11 @@ void FuzzerPassFlattenConditionalBranches::Apply() {
|
||||
->get_def_use_mgr()
|
||||
->GetDef(phi_instruction->type_id())
|
||||
->opcode()) {
|
||||
case SpvOpTypeBool:
|
||||
case SpvOpTypeInt:
|
||||
case SpvOpTypeFloat:
|
||||
case SpvOpTypePointer:
|
||||
case SpvOpTypeVector:
|
||||
case spv::Op::OpTypeBool:
|
||||
case spv::Op::OpTypeInt:
|
||||
case spv::Op::OpTypeFloat:
|
||||
case spv::Op::OpTypePointer:
|
||||
case spv::Op::OpTypeVector:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
@ -143,7 +143,7 @@ void FuzzerPassFlattenConditionalBranches::Apply() {
|
||||
GetIRContext()->get_def_use_mgr()->GetDef(
|
||||
phi_instruction->type_id());
|
||||
switch (type_instruction->opcode()) {
|
||||
case SpvOpTypeVector: {
|
||||
case spv::Op::OpTypeVector: {
|
||||
uint32_t dimension =
|
||||
type_instruction->GetSingleWordInOperand(1);
|
||||
switch (dimension) {
|
||||
|
@ -64,7 +64,7 @@ void FuzzerPassInlineFunctions::Apply() {
|
||||
auto* function_call_block =
|
||||
GetIRContext()->get_instr_block(function_call_instruction);
|
||||
if ((function_call_instruction != &*--function_call_block->tail() ||
|
||||
function_call_block->terminator()->opcode() != SpvOpBranch) &&
|
||||
function_call_block->terminator()->opcode() != spv::Op::OpBranch) &&
|
||||
!MaybeApplyTransformation(TransformationSplitBlock(
|
||||
MakeInstructionDescriptor(GetIRContext(),
|
||||
function_call_instruction->NextNode()),
|
||||
|
@ -47,18 +47,20 @@ void FuzzerPassMakeVectorOperationsDynamic::Apply() {
|
||||
}
|
||||
|
||||
// Make sure |instruction| has only one indexing operand.
|
||||
assert(instruction.NumInOperands() ==
|
||||
(instruction.opcode() == SpvOpCompositeExtract ? 2 : 3) &&
|
||||
"FuzzerPassMakeVectorOperationsDynamic: the composite "
|
||||
"instruction must have "
|
||||
"only one indexing operand.");
|
||||
assert(
|
||||
instruction.NumInOperands() ==
|
||||
(instruction.opcode() == spv::Op::OpCompositeExtract ? 2 : 3) &&
|
||||
"FuzzerPassMakeVectorOperationsDynamic: the composite "
|
||||
"instruction must have "
|
||||
"only one indexing operand.");
|
||||
|
||||
// Applies the make vector operation dynamic transformation.
|
||||
ApplyTransformation(TransformationMakeVectorOperationDynamic(
|
||||
instruction.result_id(),
|
||||
FindOrCreateIntegerConstant(
|
||||
{instruction.GetSingleWordInOperand(
|
||||
instruction.opcode() == SpvOpCompositeExtract ? 1 : 2)},
|
||||
instruction.opcode() == spv::Op::OpCompositeExtract ? 1
|
||||
: 2)},
|
||||
32, GetFuzzerContext()->ChooseEven(), false)));
|
||||
}
|
||||
}
|
||||
|
@ -64,11 +64,11 @@ void FuzzerPassMergeFunctionReturns::Apply() {
|
||||
[this, function](
|
||||
opt::BasicBlock* /*unused*/, opt::BasicBlock::iterator inst_it,
|
||||
const protobufs::InstructionDescriptor& instruction_descriptor) {
|
||||
const SpvOp opcode = inst_it->opcode();
|
||||
const spv::Op opcode = inst_it->opcode();
|
||||
switch (opcode) {
|
||||
case SpvOpKill:
|
||||
case SpvOpUnreachable:
|
||||
case SpvOpTerminateInvocation: {
|
||||
case spv::Op::OpKill:
|
||||
case spv::Op::OpUnreachable:
|
||||
case spv::Op::OpTerminateInvocation: {
|
||||
// This is an early termination instruction - we need to wrap it
|
||||
// so that it becomes a return.
|
||||
if (TransformationWrapEarlyTerminatorInFunction::
|
||||
@ -85,7 +85,7 @@ void FuzzerPassMergeFunctionReturns::Apply() {
|
||||
GetIRContext()->get_def_use_mgr()->GetDef(
|
||||
function->type_id());
|
||||
uint32_t returned_value_id;
|
||||
if (function_return_type->opcode() == SpvOpTypeVoid) {
|
||||
if (function_return_type->opcode() == spv::Op::OpTypeVoid) {
|
||||
// No value is needed.
|
||||
returned_value_id = 0;
|
||||
} else if (fuzzerutil::CanCreateConstant(
|
||||
@ -130,7 +130,7 @@ void FuzzerPassMergeFunctionReturns::Apply() {
|
||||
|
||||
// If the entry block does not branch unconditionally to another block,
|
||||
// split it.
|
||||
if (function->entry()->terminator()->opcode() != SpvOpBranch) {
|
||||
if (function->entry()->terminator()->opcode() != spv::Op::OpBranch) {
|
||||
SplitBlockAfterOpPhiOrOpVariable(function->entry()->id());
|
||||
}
|
||||
|
||||
@ -149,9 +149,9 @@ void FuzzerPassMergeFunctionReturns::Apply() {
|
||||
if (GetIRContext()
|
||||
->get_instr_block(merge_block)
|
||||
->WhileEachInst([](opt::Instruction* inst) {
|
||||
return inst->opcode() == SpvOpLabel ||
|
||||
inst->opcode() == SpvOpPhi ||
|
||||
inst->opcode() == SpvOpBranch;
|
||||
return inst->opcode() == spv::Op::OpLabel ||
|
||||
inst->opcode() == spv::Op::OpPhi ||
|
||||
inst->opcode() == spv::Op::OpBranch;
|
||||
})) {
|
||||
actual_merge_blocks.emplace_back(merge_block);
|
||||
continue;
|
||||
@ -324,7 +324,8 @@ FuzzerPassMergeFunctionReturns::GetInfoNeededForMergeBlocks(
|
||||
|
||||
bool FuzzerPassMergeFunctionReturns::IsEarlyTerminatorWrapper(
|
||||
const opt::Function& function) const {
|
||||
for (SpvOp opcode : {SpvOpKill, SpvOpUnreachable, SpvOpTerminateInvocation}) {
|
||||
for (spv::Op opcode : {spv::Op::OpKill, spv::Op::OpUnreachable,
|
||||
spv::Op::OpTerminateInvocation}) {
|
||||
if (TransformationWrapEarlyTerminatorInFunction::MaybeGetWrapperFunction(
|
||||
GetIRContext(), opcode) == &function) {
|
||||
return true;
|
||||
|
@ -39,7 +39,8 @@ void FuzzerPassMutatePointers::Apply() {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!fuzzerutil::CanInsertOpcodeBeforeInstruction(SpvOpLoad, inst_it)) {
|
||||
if (!fuzzerutil::CanInsertOpcodeBeforeInstruction(spv::Op::OpLoad,
|
||||
inst_it)) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -37,21 +37,21 @@ FuzzerPassObfuscateConstants::FuzzerPassObfuscateConstants(
|
||||
|
||||
void FuzzerPassObfuscateConstants::ObfuscateBoolConstantViaConstantPair(
|
||||
uint32_t depth, const protobufs::IdUseDescriptor& bool_constant_use,
|
||||
const std::vector<SpvOp>& greater_than_opcodes,
|
||||
const std::vector<SpvOp>& less_than_opcodes, uint32_t constant_id_1,
|
||||
const std::vector<spv::Op>& greater_than_opcodes,
|
||||
const std::vector<spv::Op>& less_than_opcodes, uint32_t constant_id_1,
|
||||
uint32_t constant_id_2, bool first_constant_is_larger) {
|
||||
auto bool_constant_opcode = GetIRContext()
|
||||
->get_def_use_mgr()
|
||||
->GetDef(bool_constant_use.id_of_interest())
|
||||
->opcode();
|
||||
assert((bool_constant_opcode == SpvOpConstantFalse ||
|
||||
bool_constant_opcode == SpvOpConstantTrue) &&
|
||||
assert((bool_constant_opcode == spv::Op::OpConstantFalse ||
|
||||
bool_constant_opcode == spv::Op::OpConstantTrue) &&
|
||||
"Precondition: this must be a usage of a boolean constant.");
|
||||
|
||||
// Pick an opcode at random. First randomly decide whether to generate
|
||||
// a 'greater than' or 'less than' kind of opcode, and then select a
|
||||
// random opcode from the resulting subset.
|
||||
SpvOp comparison_opcode;
|
||||
spv::Op comparison_opcode;
|
||||
if (GetFuzzerContext()->ChooseEven()) {
|
||||
comparison_opcode = greater_than_opcodes[GetFuzzerContext()->RandomIndex(
|
||||
greater_than_opcodes)];
|
||||
@ -68,9 +68,9 @@ void FuzzerPassObfuscateConstants::ObfuscateBoolConstantViaConstantPair(
|
||||
comparison_opcode) != greater_than_opcodes.end();
|
||||
uint32_t lhs_id;
|
||||
uint32_t rhs_id;
|
||||
if ((bool_constant_opcode == SpvOpConstantTrue &&
|
||||
if ((bool_constant_opcode == spv::Op::OpConstantTrue &&
|
||||
first_constant_is_larger == is_greater_than_opcode) ||
|
||||
(bool_constant_opcode == SpvOpConstantFalse &&
|
||||
(bool_constant_opcode == spv::Op::OpConstantFalse &&
|
||||
first_constant_is_larger != is_greater_than_opcode)) {
|
||||
lhs_id = constant_id_1;
|
||||
rhs_id = constant_id_2;
|
||||
@ -147,12 +147,12 @@ void FuzzerPassObfuscateConstants::ObfuscateBoolConstantViaFloatConstantPair(
|
||||
first_constant_is_larger =
|
||||
float_constant_1->GetDouble() > float_constant_2->GetDouble();
|
||||
}
|
||||
std::vector<SpvOp> greater_than_opcodes{
|
||||
SpvOpFOrdGreaterThan, SpvOpFOrdGreaterThanEqual, SpvOpFUnordGreaterThan,
|
||||
SpvOpFUnordGreaterThanEqual};
|
||||
std::vector<SpvOp> less_than_opcodes{
|
||||
SpvOpFOrdGreaterThan, SpvOpFOrdGreaterThanEqual, SpvOpFUnordGreaterThan,
|
||||
SpvOpFUnordGreaterThanEqual};
|
||||
std::vector<spv::Op> greater_than_opcodes{
|
||||
spv::Op::OpFOrdGreaterThan, spv::Op::OpFOrdGreaterThanEqual,
|
||||
spv::Op::OpFUnordGreaterThan, spv::Op::OpFUnordGreaterThanEqual};
|
||||
std::vector<spv::Op> less_than_opcodes{
|
||||
spv::Op::OpFOrdGreaterThan, spv::Op::OpFOrdGreaterThanEqual,
|
||||
spv::Op::OpFUnordGreaterThan, spv::Op::OpFUnordGreaterThanEqual};
|
||||
|
||||
ObfuscateBoolConstantViaConstantPair(
|
||||
depth, bool_constant_use, greater_than_opcodes, less_than_opcodes,
|
||||
@ -190,9 +190,10 @@ void FuzzerPassObfuscateConstants::
|
||||
first_constant_is_larger =
|
||||
signed_int_constant_1->GetS64() > signed_int_constant_2->GetS64();
|
||||
}
|
||||
std::vector<SpvOp> greater_than_opcodes{SpvOpSGreaterThan,
|
||||
SpvOpSGreaterThanEqual};
|
||||
std::vector<SpvOp> less_than_opcodes{SpvOpSLessThan, SpvOpSLessThanEqual};
|
||||
std::vector<spv::Op> greater_than_opcodes{spv::Op::OpSGreaterThan,
|
||||
spv::Op::OpSGreaterThanEqual};
|
||||
std::vector<spv::Op> less_than_opcodes{spv::Op::OpSLessThan,
|
||||
spv::Op::OpSLessThanEqual};
|
||||
|
||||
ObfuscateBoolConstantViaConstantPair(
|
||||
depth, bool_constant_use, greater_than_opcodes, less_than_opcodes,
|
||||
@ -232,9 +233,10 @@ void FuzzerPassObfuscateConstants::
|
||||
first_constant_is_larger =
|
||||
unsigned_int_constant_1->GetU64() > unsigned_int_constant_2->GetU64();
|
||||
}
|
||||
std::vector<SpvOp> greater_than_opcodes{SpvOpUGreaterThan,
|
||||
SpvOpUGreaterThanEqual};
|
||||
std::vector<SpvOp> less_than_opcodes{SpvOpULessThan, SpvOpULessThanEqual};
|
||||
std::vector<spv::Op> greater_than_opcodes{spv::Op::OpUGreaterThan,
|
||||
spv::Op::OpUGreaterThanEqual};
|
||||
std::vector<spv::Op> less_than_opcodes{spv::Op::OpULessThan,
|
||||
spv::Op::OpULessThanEqual};
|
||||
|
||||
ObfuscateBoolConstantViaConstantPair(
|
||||
depth, bool_constant_use, greater_than_opcodes, less_than_opcodes,
|
||||
@ -379,7 +381,7 @@ void FuzzerPassObfuscateConstants::ObfuscateScalarConstant(
|
||||
uniform_descriptor.index());
|
||||
assert(element_type_id && "Type of uniform variable is invalid");
|
||||
|
||||
FindOrCreatePointerType(element_type_id, SpvStorageClassUniform);
|
||||
FindOrCreatePointerType(element_type_id, spv::StorageClass::Uniform);
|
||||
|
||||
// Create, apply and record a transformation to replace the constant use with
|
||||
// the result of a load from the chosen uniform.
|
||||
@ -394,11 +396,11 @@ void FuzzerPassObfuscateConstants::ObfuscateConstant(
|
||||
->get_def_use_mgr()
|
||||
->GetDef(constant_use.id_of_interest())
|
||||
->opcode()) {
|
||||
case SpvOpConstantTrue:
|
||||
case SpvOpConstantFalse:
|
||||
case spv::Op::OpConstantTrue:
|
||||
case spv::Op::OpConstantFalse:
|
||||
ObfuscateBoolConstant(depth, constant_use);
|
||||
break;
|
||||
case SpvOpConstant:
|
||||
case spv::Op::OpConstant:
|
||||
ObfuscateScalarConstant(depth, constant_use);
|
||||
break;
|
||||
default:
|
||||
@ -410,7 +412,7 @@ void FuzzerPassObfuscateConstants::ObfuscateConstant(
|
||||
void FuzzerPassObfuscateConstants::MaybeAddConstantIdUse(
|
||||
const opt::Instruction& inst, uint32_t in_operand_index,
|
||||
uint32_t base_instruction_result_id,
|
||||
const std::map<SpvOp, uint32_t>& skipped_opcode_count,
|
||||
const std::map<spv::Op, uint32_t>& skipped_opcode_count,
|
||||
std::vector<protobufs::IdUseDescriptor>* constant_uses) {
|
||||
if (inst.GetInOperand(in_operand_index).type != SPV_OPERAND_TYPE_ID) {
|
||||
// The operand is not an id, so it cannot be a constant id.
|
||||
@ -420,15 +422,15 @@ void FuzzerPassObfuscateConstants::MaybeAddConstantIdUse(
|
||||
auto operand_definition =
|
||||
GetIRContext()->get_def_use_mgr()->GetDef(operand_id);
|
||||
switch (operand_definition->opcode()) {
|
||||
case SpvOpConstantFalse:
|
||||
case SpvOpConstantTrue:
|
||||
case SpvOpConstant: {
|
||||
case spv::Op::OpConstantFalse:
|
||||
case spv::Op::OpConstantTrue:
|
||||
case spv::Op::OpConstant: {
|
||||
// The operand is a constant id, so make an id use descriptor and record
|
||||
// it.
|
||||
protobufs::IdUseDescriptor id_use_descriptor;
|
||||
id_use_descriptor.set_id_of_interest(operand_id);
|
||||
id_use_descriptor.mutable_enclosing_instruction()
|
||||
->set_target_instruction_opcode(inst.opcode());
|
||||
->set_target_instruction_opcode(uint32_t(inst.opcode()));
|
||||
id_use_descriptor.mutable_enclosing_instruction()
|
||||
->set_base_instruction_result_id(base_instruction_result_id);
|
||||
id_use_descriptor.mutable_enclosing_instruction()
|
||||
@ -461,7 +463,7 @@ void FuzzerPassObfuscateConstants::Apply() {
|
||||
// opcode need to be skipped in order to find the instruction of interest
|
||||
// from the base instruction. We maintain a mapping that records a skip
|
||||
// count for each relevant opcode.
|
||||
std::map<SpvOp, uint32_t> skipped_opcode_count;
|
||||
std::map<spv::Op, uint32_t> skipped_opcode_count;
|
||||
|
||||
// Go through each instruction in the block.
|
||||
for (auto& inst : block) {
|
||||
@ -478,7 +480,7 @@ void FuzzerPassObfuscateConstants::Apply() {
|
||||
// The instruction must not be an OpVariable, the only id that an
|
||||
// OpVariable uses is an initializer id, which has to remain
|
||||
// constant.
|
||||
if (inst.opcode() != SpvOpVariable) {
|
||||
if (inst.opcode() != spv::Op::OpVariable) {
|
||||
// Consider each operand of the instruction, and add a constant id
|
||||
// use for the operand if relevant.
|
||||
for (uint32_t in_operand_index = 0;
|
||||
|
@ -85,8 +85,8 @@ class FuzzerPassObfuscateConstants : public FuzzerPass {
|
||||
// (similar for |less_than_opcodes|).
|
||||
void ObfuscateBoolConstantViaConstantPair(
|
||||
uint32_t depth, const protobufs::IdUseDescriptor& bool_constant_use,
|
||||
const std::vector<SpvOp>& greater_than_opcodes,
|
||||
const std::vector<SpvOp>& less_than_opcodes, uint32_t constant_id_1,
|
||||
const std::vector<spv::Op>& greater_than_opcodes,
|
||||
const std::vector<spv::Op>& less_than_opcodes, uint32_t constant_id_1,
|
||||
uint32_t constant_id_2, bool first_constant_is_larger);
|
||||
|
||||
// A helper method to determine whether input operand |in_operand_index| of
|
||||
@ -96,7 +96,7 @@ class FuzzerPassObfuscateConstants : public FuzzerPass {
|
||||
void MaybeAddConstantIdUse(
|
||||
const opt::Instruction& inst, uint32_t in_operand_index,
|
||||
uint32_t base_instruction_result_id,
|
||||
const std::map<SpvOp, uint32_t>& skipped_opcode_count,
|
||||
const std::map<spv::Op, uint32_t>& skipped_opcode_count,
|
||||
std::vector<protobufs::IdUseDescriptor>* constant_uses);
|
||||
|
||||
// Returns a vector of unique words that denote constants. Every such constant
|
||||
|
@ -137,12 +137,12 @@ FuzzerPassOutlineFunctions::MaybeGetEntryBlockSuitableForOutlining(
|
||||
"The entry block cannot be a loop header at this point.");
|
||||
|
||||
// If the entry block starts with OpPhi or OpVariable, try to split it.
|
||||
if (entry_block->begin()->opcode() == SpvOpPhi ||
|
||||
entry_block->begin()->opcode() == SpvOpVariable) {
|
||||
if (entry_block->begin()->opcode() == spv::Op::OpPhi ||
|
||||
entry_block->begin()->opcode() == spv::Op::OpVariable) {
|
||||
// Find the first non-OpPhi and non-OpVariable instruction.
|
||||
auto non_phi_or_var_inst = &*entry_block->begin();
|
||||
while (non_phi_or_var_inst->opcode() == SpvOpPhi ||
|
||||
non_phi_or_var_inst->opcode() == SpvOpVariable) {
|
||||
while (non_phi_or_var_inst->opcode() == spv::Op::OpPhi ||
|
||||
non_phi_or_var_inst->opcode() == spv::Op::OpVariable) {
|
||||
non_phi_or_var_inst = non_phi_or_var_inst->NextNode();
|
||||
}
|
||||
|
||||
@ -175,7 +175,7 @@ FuzzerPassOutlineFunctions::MaybeGetExitBlockSuitableForOutlining(
|
||||
|
||||
// Find the first non-OpPhi instruction, after which to split.
|
||||
auto split_before = &*exit_block->begin();
|
||||
while (split_before->opcode() == SpvOpPhi) {
|
||||
while (split_before->opcode() == spv::Op::OpPhi) {
|
||||
split_before = split_before->NextNode();
|
||||
}
|
||||
|
||||
|
@ -47,7 +47,7 @@ void FuzzerPassPermuteFunctionVariables::Apply() {
|
||||
|
||||
std::vector<opt::Instruction*> variables;
|
||||
for (auto& instruction : *first_block) {
|
||||
if (instruction.opcode() == SpvOpVariable) {
|
||||
if (instruction.opcode() == spv::Op::OpVariable) {
|
||||
variables.push_back(&instruction);
|
||||
}
|
||||
}
|
||||
|
@ -40,7 +40,7 @@ void FuzzerPassPermutePhiOperands::Apply() {
|
||||
const protobufs::InstructionDescriptor& /*unused*/) {
|
||||
const auto& inst = *inst_it;
|
||||
|
||||
if (inst.opcode() != SpvOpPhi) {
|
||||
if (inst.opcode() != spv::Op::OpPhi) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -35,10 +35,11 @@ void FuzzerPassPushIdsThroughVariables::Apply() {
|
||||
opt::BasicBlock::iterator instruction_iterator,
|
||||
const protobufs::InstructionDescriptor& instruction_descriptor)
|
||||
-> void {
|
||||
assert(instruction_iterator->opcode() ==
|
||||
instruction_descriptor.target_instruction_opcode() &&
|
||||
"The opcode of the instruction we might insert before must be "
|
||||
"the same as the opcode in the descriptor for the instruction");
|
||||
assert(
|
||||
instruction_iterator->opcode() ==
|
||||
spv::Op(instruction_descriptor.target_instruction_opcode()) &&
|
||||
"The opcode of the instruction we might insert before must be "
|
||||
"the same as the opcode in the descriptor for the instruction");
|
||||
|
||||
// Randomly decide whether to try pushing an id through a variable.
|
||||
if (!GetFuzzerContext()->ChoosePercentage(
|
||||
@ -55,16 +56,16 @@ void FuzzerPassPushIdsThroughVariables::Apply() {
|
||||
// It must be valid to insert OpStore and OpLoad instructions
|
||||
// before the instruction to insert before.
|
||||
if (!fuzzerutil::CanInsertOpcodeBeforeInstruction(
|
||||
SpvOpStore, instruction_iterator) ||
|
||||
spv::Op::OpStore, instruction_iterator) ||
|
||||
!fuzzerutil::CanInsertOpcodeBeforeInstruction(
|
||||
SpvOpLoad, instruction_iterator)) {
|
||||
spv::Op::OpLoad, instruction_iterator)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Randomly decides whether a global or local variable will be added.
|
||||
auto variable_storage_class = GetFuzzerContext()->ChooseEven()
|
||||
? SpvStorageClassPrivate
|
||||
: SpvStorageClassFunction;
|
||||
? spv::StorageClass::Private
|
||||
: spv::StorageClass::Function;
|
||||
|
||||
// Gets the available basic and pointer types.
|
||||
auto basic_type_ids_and_pointers =
|
||||
@ -127,13 +128,13 @@ void FuzzerPassPushIdsThroughVariables::Apply() {
|
||||
GetIRContext()->get_def_use_mgr()->GetDef(basic_type_id);
|
||||
assert(type_inst);
|
||||
switch (type_inst->opcode()) {
|
||||
case SpvOpTypeBool:
|
||||
case SpvOpTypeFloat:
|
||||
case SpvOpTypeInt:
|
||||
case SpvOpTypeArray:
|
||||
case SpvOpTypeMatrix:
|
||||
case SpvOpTypeVector:
|
||||
case SpvOpTypeStruct:
|
||||
case spv::Op::OpTypeBool:
|
||||
case spv::Op::OpTypeFloat:
|
||||
case spv::Op::OpTypeInt:
|
||||
case spv::Op::OpTypeArray:
|
||||
case spv::Op::OpTypeMatrix:
|
||||
case spv::Op::OpTypeVector:
|
||||
case spv::Op::OpTypeStruct:
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
@ -150,7 +151,8 @@ void FuzzerPassPushIdsThroughVariables::Apply() {
|
||||
value_instructions)]
|
||||
->result_id(),
|
||||
GetFuzzerContext()->GetFreshId(), GetFuzzerContext()->GetFreshId(),
|
||||
variable_storage_class, initializer_id, instruction_descriptor));
|
||||
uint32_t(variable_storage_class), initializer_id,
|
||||
instruction_descriptor));
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -38,13 +38,13 @@ void FuzzerPassReplaceBranchesFromDeadBlocksWithExits::Apply() {
|
||||
// to be executed with the Fragment execution model. We conservatively only
|
||||
// allow OpKill if every entry point in the module has the Fragment execution
|
||||
// model.
|
||||
auto fragment_execution_model_guaranteed =
|
||||
std::all_of(GetIRContext()->module()->entry_points().begin(),
|
||||
GetIRContext()->module()->entry_points().end(),
|
||||
[](const opt::Instruction& entry_point) -> bool {
|
||||
return entry_point.GetSingleWordInOperand(0) ==
|
||||
SpvExecutionModelFragment;
|
||||
});
|
||||
auto fragment_execution_model_guaranteed = std::all_of(
|
||||
GetIRContext()->module()->entry_points().begin(),
|
||||
GetIRContext()->module()->entry_points().end(),
|
||||
[](const opt::Instruction& entry_point) -> bool {
|
||||
return spv::ExecutionModel(entry_point.GetSingleWordInOperand(0)) ==
|
||||
spv::ExecutionModel::Fragment;
|
||||
});
|
||||
|
||||
// Transformations of this type can disable one another. To avoid ordering
|
||||
// bias, we therefore build a set of candidate transformations to apply, and
|
||||
@ -71,20 +71,20 @@ void FuzzerPassReplaceBranchesFromDeadBlocksWithExits::Apply() {
|
||||
// Whether we can use OpKill depends on the execution model, and which of
|
||||
// OpReturn and OpReturnValue we can use depends on the return type of the
|
||||
// enclosing function.
|
||||
std::vector<SpvOp> opcodes = {SpvOpUnreachable};
|
||||
std::vector<spv::Op> opcodes = {spv::Op::OpUnreachable};
|
||||
if (fragment_execution_model_guaranteed) {
|
||||
opcodes.emplace_back(SpvOpKill);
|
||||
opcodes.emplace_back(spv::Op::OpKill);
|
||||
}
|
||||
auto function_return_type =
|
||||
GetIRContext()->get_type_mgr()->GetType(function.type_id());
|
||||
if (function_return_type->AsVoid()) {
|
||||
opcodes.emplace_back(SpvOpReturn);
|
||||
opcodes.emplace_back(spv::Op::OpReturn);
|
||||
} else if (fuzzerutil::CanCreateConstant(GetIRContext(),
|
||||
function.type_id())) {
|
||||
// For simplicity we only allow OpReturnValue if the function return
|
||||
// type is a type for which we can create a constant. This allows us a
|
||||
// zero of the given type as a default return value.
|
||||
opcodes.emplace_back(SpvOpReturnValue);
|
||||
opcodes.emplace_back(spv::Op::OpReturnValue);
|
||||
}
|
||||
// Choose one of the available terminator opcodes at random and create a
|
||||
// candidate transformation.
|
||||
@ -92,7 +92,7 @@ void FuzzerPassReplaceBranchesFromDeadBlocksWithExits::Apply() {
|
||||
candidate_transformations.emplace_back(
|
||||
TransformationReplaceBranchFromDeadBlockWithExit(
|
||||
block.id(), opcode,
|
||||
opcode == SpvOpReturnValue
|
||||
opcode == spv::Op::OpReturnValue
|
||||
? FindOrCreateZeroConstant(function.type_id(), true)
|
||||
: 0));
|
||||
}
|
||||
|
@ -41,7 +41,7 @@ void FuzzerPassReplaceCopyMemoriesWithLoadsStores::Apply() {
|
||||
}
|
||||
|
||||
// The instruction must be OpCopyMemory.
|
||||
if (instruction->opcode() != SpvOpCopyMemory) {
|
||||
if (instruction->opcode() != spv::Op::OpCopyMemory) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -40,7 +40,7 @@ void FuzzerPassReplaceCopyObjectsWithStoresLoads::Apply() {
|
||||
return;
|
||||
}
|
||||
// The instruction must be OpCopyObject.
|
||||
if (instruction->opcode() != SpvOpCopyObject) {
|
||||
if (instruction->opcode() != spv::Op::OpCopyObject) {
|
||||
return;
|
||||
}
|
||||
// The opcode of the type_id instruction cannot be a OpTypePointer,
|
||||
@ -48,21 +48,22 @@ void FuzzerPassReplaceCopyObjectsWithStoresLoads::Apply() {
|
||||
if (GetIRContext()
|
||||
->get_def_use_mgr()
|
||||
->GetDef(instruction->type_id())
|
||||
->opcode() == SpvOpTypePointer) {
|
||||
->opcode() == spv::Op::OpTypePointer) {
|
||||
return;
|
||||
}
|
||||
// It must be valid to insert OpStore and OpLoad instructions
|
||||
// before the instruction OpCopyObject.
|
||||
if (!fuzzerutil::CanInsertOpcodeBeforeInstruction(SpvOpStore,
|
||||
if (!fuzzerutil::CanInsertOpcodeBeforeInstruction(spv::Op::OpStore,
|
||||
instruction) ||
|
||||
!fuzzerutil::CanInsertOpcodeBeforeInstruction(SpvOpLoad, instruction)) {
|
||||
!fuzzerutil::CanInsertOpcodeBeforeInstruction(spv::Op::OpLoad,
|
||||
instruction)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Randomly decides whether a global or local variable will be added.
|
||||
auto variable_storage_class = GetFuzzerContext()->ChooseEven()
|
||||
? SpvStorageClassPrivate
|
||||
: SpvStorageClassFunction;
|
||||
? spv::StorageClass::Private
|
||||
: spv::StorageClass::Function;
|
||||
|
||||
// Find or create a constant to initialize the variable from. The type of
|
||||
// |instruction| must be such that the function FindOrCreateConstant can be
|
||||
@ -79,7 +80,7 @@ void FuzzerPassReplaceCopyObjectsWithStoresLoads::Apply() {
|
||||
// Apply the transformation replacing OpCopyObject with Store and Load.
|
||||
ApplyTransformation(TransformationReplaceCopyObjectWithStoreLoad(
|
||||
instruction->result_id(), GetFuzzerContext()->GetFreshId(),
|
||||
variable_storage_class, variable_initializer_id));
|
||||
uint32_t(variable_storage_class), variable_initializer_id));
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -73,7 +73,7 @@ void FuzzerPassReplaceIrrelevantIds::Apply() {
|
||||
// we cannot use these as replacements.
|
||||
for (const auto& pair : GetIRContext()->get_def_use_mgr()->id_to_defs()) {
|
||||
uint32_t type_id = pair.second->type_id();
|
||||
if (pair.second->opcode() != SpvOpFunction && type_id &&
|
||||
if (pair.second->opcode() != spv::Op::OpFunction && type_id &&
|
||||
types_to_ids.count(type_id)) {
|
||||
types_to_ids[type_id].push_back(pair.first);
|
||||
}
|
||||
|
@ -50,9 +50,9 @@ void FuzzerPassReplaceLoadsStoresWithCopyMemories::Apply() {
|
||||
std::unordered_map<uint32_t, opt::Instruction*> current_op_loads;
|
||||
for (auto& instruction : block) {
|
||||
// Add a potential OpLoad instruction.
|
||||
if (instruction.opcode() == SpvOpLoad) {
|
||||
if (instruction.opcode() == spv::Op::OpLoad) {
|
||||
current_op_loads[instruction.result_id()] = &instruction;
|
||||
} else if (instruction.opcode() == SpvOpStore) {
|
||||
} else if (instruction.opcode() == spv::Op::OpStore) {
|
||||
if (current_op_loads.find(instruction.GetSingleWordOperand(1)) !=
|
||||
current_op_loads.end()) {
|
||||
// We have found the matching OpLoad instruction to the current
|
||||
@ -73,7 +73,7 @@ void FuzzerPassReplaceLoadsStoresWithCopyMemories::Apply() {
|
||||
opt::Instruction* source_id =
|
||||
GetIRContext()->get_def_use_mgr()->GetDef(
|
||||
it->second->GetSingleWordOperand(2));
|
||||
SpvStorageClass storage_class =
|
||||
spv::StorageClass storage_class =
|
||||
fuzzerutil::GetStorageClassFromPointerType(
|
||||
GetIRContext(), source_id->type_id());
|
||||
if (!TransformationReplaceLoadStoreWithCopyMemory::
|
||||
|
@ -50,7 +50,7 @@ void FuzzerPassReplaceOpPhiIdsFromDeadPredecessors::Apply() {
|
||||
block->id(), [this, &function, block, &transformations](
|
||||
opt::Instruction* instruction, uint32_t) {
|
||||
// Only consider OpPhi instructions.
|
||||
if (instruction->opcode() != SpvOpPhi) {
|
||||
if (instruction->opcode() != spv::Op::OpPhi) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -52,7 +52,7 @@ void FuzzerPassReplaceOpSelectsWithConditionalBranches::Apply() {
|
||||
|
||||
for (auto& instruction : block) {
|
||||
// We only care about OpSelect instructions.
|
||||
if (instruction.opcode() != SpvOpSelect) {
|
||||
if (instruction.opcode() != spv::Op::OpSelect) {
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -69,7 +69,7 @@ void FuzzerPassReplaceOpSelectsWithConditionalBranches::Apply() {
|
||||
->get_def_use_mgr()
|
||||
->GetDef(fuzzerutil::GetTypeId(
|
||||
GetIRContext(), instruction.GetSingleWordInOperand(0)))
|
||||
->opcode() != SpvOpTypeBool) {
|
||||
->opcode() != spv::Op::OpTypeBool) {
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -136,7 +136,7 @@ void FuzzerPassReplaceOpSelectsWithConditionalBranches::Apply() {
|
||||
|
||||
bool FuzzerPassReplaceOpSelectsWithConditionalBranches::
|
||||
InstructionNeedsSplitBefore(opt::Instruction* instruction) {
|
||||
assert(instruction && instruction->opcode() == SpvOpSelect &&
|
||||
assert(instruction && instruction->opcode() == spv::Op::OpSelect &&
|
||||
"The instruction must be OpSelect.");
|
||||
|
||||
auto block = GetIRContext()->get_instr_block(instruction);
|
||||
@ -163,7 +163,7 @@ bool FuzzerPassReplaceOpSelectsWithConditionalBranches::
|
||||
auto predecessor = GetIRContext()->get_instr_block(
|
||||
GetIRContext()->cfg()->preds(block->id())[0]);
|
||||
return predecessor->MergeBlockIdIfAny() ||
|
||||
predecessor->terminator()->opcode() != SpvOpBranch;
|
||||
predecessor->terminator()->opcode() != spv::Op::OpBranch;
|
||||
}
|
||||
|
||||
} // namespace fuzz
|
||||
|
@ -72,7 +72,8 @@ void FuzzerPassReplaceParameterWithGlobal::Apply() {
|
||||
assert(replaced_param && "Unable to find a parameter to replace");
|
||||
|
||||
// Make sure type id for the global variable exists in the module.
|
||||
FindOrCreatePointerType(replaced_param->type_id(), SpvStorageClassPrivate);
|
||||
FindOrCreatePointerType(replaced_param->type_id(),
|
||||
spv::StorageClass::Private);
|
||||
|
||||
// Make sure initializer for the global variable exists in the module.
|
||||
FindOrCreateZeroConstant(replaced_param->type_id(), false);
|
||||
|
@ -65,7 +65,7 @@ void FuzzerPassSplitBlocks::Apply() {
|
||||
|
||||
// Counts the number of times we have seen each opcode since we reset the
|
||||
// base instruction.
|
||||
std::map<SpvOp, uint32_t> skip_count;
|
||||
std::map<spv::Op, uint32_t> skip_count;
|
||||
|
||||
// Consider every instruction in the block. The label is excluded: it is
|
||||
// only necessary to consider it as a base in case the first instruction
|
||||
@ -78,7 +78,7 @@ void FuzzerPassSplitBlocks::Apply() {
|
||||
base = inst.result_id();
|
||||
skip_count.clear();
|
||||
}
|
||||
const SpvOp opcode = inst.opcode();
|
||||
const spv::Op opcode = inst.opcode();
|
||||
instruction_descriptors.emplace_back(MakeInstructionDescriptor(
|
||||
base, opcode, skip_count.count(opcode) ? skip_count.at(opcode) : 0));
|
||||
if (!inst.HasResultId()) {
|
||||
|
@ -39,7 +39,7 @@ void FuzzerPassSwapBranchConditionalOperands::Apply() {
|
||||
const protobufs::InstructionDescriptor& instruction_descriptor) {
|
||||
const auto& inst = *inst_it;
|
||||
|
||||
if (inst.opcode() != SpvOpBranchConditional) {
|
||||
if (inst.opcode() != spv::Op::OpBranchConditional) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -36,8 +36,9 @@ void FuzzerPassToggleAccessChainInstruction::Apply() {
|
||||
// probabilistically applied.
|
||||
context->module()->ForEachInst([this,
|
||||
context](opt::Instruction* instruction) {
|
||||
SpvOp opcode = instruction->opcode();
|
||||
if ((opcode == SpvOpAccessChain || opcode == SpvOpInBoundsAccessChain) &&
|
||||
spv::Op opcode = instruction->opcode();
|
||||
if ((opcode == spv::Op::OpAccessChain ||
|
||||
opcode == spv::Op::OpInBoundsAccessChain) &&
|
||||
GetFuzzerContext()->ChoosePercentage(
|
||||
GetFuzzerContext()->GetChanceOfTogglingAccessChainInstruction())) {
|
||||
auto instructionDescriptor =
|
||||
|
@ -52,7 +52,7 @@ void FuzzerPassWrapVectorSynonym::Apply() {
|
||||
// It must be valid to insert an OpCompositeConstruct instruction
|
||||
// before |instruction_iterator|.
|
||||
if (!fuzzerutil::CanInsertOpcodeBeforeInstruction(
|
||||
SpvOpCompositeConstruct, instruction_iterator)) {
|
||||
spv::Op::OpCompositeConstruct, instruction_iterator)) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -111,7 +111,7 @@ opt::BasicBlock::iterator GetIteratorForInstruction(
|
||||
// Determines whether it is OK to insert an instruction with opcode |opcode|
|
||||
// before |instruction_in_block|.
|
||||
bool CanInsertOpcodeBeforeInstruction(
|
||||
SpvOp opcode, const opt::BasicBlock::iterator& instruction_in_block);
|
||||
spv::Op opcode, const opt::BasicBlock::iterator& instruction_in_block);
|
||||
|
||||
// Determines whether it is OK to make a synonym of |inst|.
|
||||
// |transformation_context| is used to verify that the result id of |inst|
|
||||
@ -170,8 +170,8 @@ uint32_t GetBoundForCompositeIndex(const opt::Instruction& composite_type_inst,
|
||||
opt::IRContext* ir_context);
|
||||
|
||||
// Returns memory semantics mask for specific storage class.
|
||||
SpvMemorySemanticsMask GetMemorySemanticsForStorageClass(
|
||||
SpvStorageClass storage_class);
|
||||
spv::MemorySemanticsMask GetMemorySemanticsForStorageClass(
|
||||
spv::StorageClass storage_class);
|
||||
|
||||
// Returns true if and only if |context| is valid, according to the validator
|
||||
// instantiated with |validator_options|. |consumer| is used for error
|
||||
@ -258,18 +258,18 @@ uint32_t GetPointeeTypeIdFromPointerType(opt::IRContext* context,
|
||||
|
||||
// Given |pointer_type_inst|, which must be an OpTypePointer instruction,
|
||||
// returns the associated storage class.
|
||||
SpvStorageClass GetStorageClassFromPointerType(
|
||||
spv::StorageClass GetStorageClassFromPointerType(
|
||||
opt::Instruction* pointer_type_inst);
|
||||
|
||||
// Given |pointer_type_id|, which must be the id of a pointer type, returns the
|
||||
// associated storage class.
|
||||
SpvStorageClass GetStorageClassFromPointerType(opt::IRContext* context,
|
||||
uint32_t pointer_type_id);
|
||||
spv::StorageClass GetStorageClassFromPointerType(opt::IRContext* context,
|
||||
uint32_t pointer_type_id);
|
||||
|
||||
// Returns the id of a pointer with pointee type |pointee_type_id| and storage
|
||||
// class |storage_class|, if it exists, and 0 otherwise.
|
||||
uint32_t MaybeGetPointerType(opt::IRContext* context, uint32_t pointee_type_id,
|
||||
SpvStorageClass storage_class);
|
||||
spv::StorageClass storage_class);
|
||||
|
||||
// Given an instruction |inst| and an operand absolute index |absolute_index|,
|
||||
// returns the index of the operand restricted to the input operands.
|
||||
@ -309,7 +309,7 @@ void AddVariableIdToEntryPointInterfaces(opt::IRContext* context, uint32_t id);
|
||||
// Returns a pointer to the new global variable instruction.
|
||||
opt::Instruction* AddGlobalVariable(opt::IRContext* context, uint32_t result_id,
|
||||
uint32_t type_id,
|
||||
SpvStorageClass storage_class,
|
||||
spv::StorageClass storage_class,
|
||||
uint32_t initializer_id);
|
||||
|
||||
// Adds an instruction to the start of |function_id|, of the form:
|
||||
@ -541,7 +541,7 @@ MapToRepeatedUInt32Pair(const std::map<uint32_t, uint32_t>& data);
|
||||
// opcode |opcode| can be inserted, or nullptr if there is no such instruction.
|
||||
opt::Instruction* GetLastInsertBeforeInstruction(opt::IRContext* ir_context,
|
||||
uint32_t block_id,
|
||||
SpvOp opcode);
|
||||
spv::Op opcode);
|
||||
|
||||
// Checks whether various conditions hold related to the acceptability of
|
||||
// replacing the id use at |use_in_operand_index| of |use_instruction| with a
|
||||
@ -608,14 +608,14 @@ opt::Module::iterator GetFunctionIterator(opt::IRContext* ir_context,
|
||||
// behaviour depending on the signedness of the operand at
|
||||
// |use_in_operand_index|.
|
||||
// Assumes that the operand must be the id of an integer scalar or vector.
|
||||
bool IsAgnosticToSignednessOfOperand(SpvOp opcode,
|
||||
bool IsAgnosticToSignednessOfOperand(spv::Op opcode,
|
||||
uint32_t use_in_operand_index);
|
||||
|
||||
// Returns true if |type_id_1| and |type_id_2| represent compatible types
|
||||
// given the context of the instruction with |opcode| (i.e. we can replace
|
||||
// an operand of |opcode| of the first type with an id of the second type
|
||||
// and vice-versa).
|
||||
bool TypesAreCompatible(opt::IRContext* ir_context, SpvOp opcode,
|
||||
bool TypesAreCompatible(opt::IRContext* ir_context, spv::Op opcode,
|
||||
uint32_t use_in_operand_index, uint32_t type_id_1,
|
||||
uint32_t type_id_2);
|
||||
|
||||
|
@ -40,8 +40,9 @@ opt::Instruction* FindInstruction(
|
||||
"The skipped instruction count should only be incremented "
|
||||
"after the instruction base has been found.");
|
||||
}
|
||||
if (found_base && instruction.opcode() ==
|
||||
instruction_descriptor.target_instruction_opcode()) {
|
||||
if (found_base &&
|
||||
instruction.opcode() ==
|
||||
spv::Op(instruction_descriptor.target_instruction_opcode())) {
|
||||
if (num_ignored == instruction_descriptor.num_opcodes_to_ignore()) {
|
||||
return &instruction;
|
||||
}
|
||||
@ -52,11 +53,11 @@ opt::Instruction* FindInstruction(
|
||||
}
|
||||
|
||||
protobufs::InstructionDescriptor MakeInstructionDescriptor(
|
||||
uint32_t base_instruction_result_id, SpvOp target_instruction_opcode,
|
||||
uint32_t base_instruction_result_id, spv::Op target_instruction_opcode,
|
||||
uint32_t num_opcodes_to_ignore) {
|
||||
protobufs::InstructionDescriptor result;
|
||||
result.set_base_instruction_result_id(base_instruction_result_id);
|
||||
result.set_target_instruction_opcode(target_instruction_opcode);
|
||||
result.set_target_instruction_opcode(uint32_t(target_instruction_opcode));
|
||||
result.set_num_opcodes_to_ignore(num_opcodes_to_ignore);
|
||||
return result;
|
||||
}
|
||||
@ -64,7 +65,7 @@ protobufs::InstructionDescriptor MakeInstructionDescriptor(
|
||||
protobufs::InstructionDescriptor MakeInstructionDescriptor(
|
||||
const opt::BasicBlock& block,
|
||||
const opt::BasicBlock::const_iterator& inst_it) {
|
||||
const SpvOp opcode =
|
||||
const spv::Op opcode =
|
||||
inst_it->opcode(); // The opcode of the instruction being described.
|
||||
uint32_t skip_count = 0; // The number of these opcodes we have skipped when
|
||||
// searching backwards.
|
||||
|
@ -32,7 +32,7 @@ opt::Instruction* FindInstruction(
|
||||
// components. See the protobuf definition for details of what these
|
||||
// components mean.
|
||||
protobufs::InstructionDescriptor MakeInstructionDescriptor(
|
||||
uint32_t base_instruction_result_id, SpvOp target_instruction_opcode,
|
||||
uint32_t base_instruction_result_id, spv::Op target_instruction_opcode,
|
||||
uint32_t num_opcodes_to_ignore);
|
||||
|
||||
// Returns an instruction descriptor that describing the instruction at
|
||||
|
@ -20,10 +20,10 @@ namespace spvtools {
|
||||
namespace fuzz {
|
||||
|
||||
protobufs::Instruction MakeInstructionMessage(
|
||||
SpvOp opcode, uint32_t result_type_id, uint32_t result_id,
|
||||
spv::Op opcode, uint32_t result_type_id, uint32_t result_id,
|
||||
const opt::Instruction::OperandList& input_operands) {
|
||||
protobufs::Instruction result;
|
||||
result.set_opcode(opcode);
|
||||
result.set_opcode(uint32_t(opcode));
|
||||
result.set_result_type_id(result_type_id);
|
||||
result.set_result_id(result_id);
|
||||
for (auto& operand : input_operands) {
|
||||
@ -71,7 +71,7 @@ std::unique_ptr<opt::Instruction> InstructionFromMessage(
|
||||
}
|
||||
// Create and return the instruction.
|
||||
return MakeUnique<opt::Instruction>(
|
||||
ir_context, static_cast<SpvOp>(instruction_message.opcode()),
|
||||
ir_context, static_cast<spv::Op>(instruction_message.opcode()),
|
||||
instruction_message.result_type_id(), instruction_message.result_id(),
|
||||
in_operands);
|
||||
}
|
||||
|
@ -26,7 +26,7 @@ namespace fuzz {
|
||||
|
||||
// Creates an Instruction protobuf message from its component parts.
|
||||
protobufs::Instruction MakeInstructionMessage(
|
||||
SpvOp opcode, uint32_t result_type_id, uint32_t result_id,
|
||||
spv::Op opcode, uint32_t result_type_id, uint32_t result_id,
|
||||
const opt::Instruction::OperandList& input_operands);
|
||||
|
||||
// Creates an Instruction protobuf message from a parsed instruction.
|
||||
|
@ -63,7 +63,7 @@ bool TransformationAccessChain::IsApplicable(
|
||||
}
|
||||
// The type must indeed be a pointer.
|
||||
auto pointer_type = ir_context->get_def_use_mgr()->GetDef(pointer->type_id());
|
||||
if (pointer_type->opcode() != SpvOpTypePointer) {
|
||||
if (pointer_type->opcode() != spv::Op::OpTypePointer) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -75,7 +75,7 @@ bool TransformationAccessChain::IsApplicable(
|
||||
return false;
|
||||
}
|
||||
if (!fuzzerutil::CanInsertOpcodeBeforeInstruction(
|
||||
SpvOpAccessChain, instruction_to_insert_before)) {
|
||||
spv::Op::OpAccessChain, instruction_to_insert_before)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -83,8 +83,8 @@ bool TransformationAccessChain::IsApplicable(
|
||||
// we do not want to allow accessing such pointers. This might be acceptable
|
||||
// in dead blocks, but we conservatively avoid it.
|
||||
switch (pointer->opcode()) {
|
||||
case SpvOpConstantNull:
|
||||
case SpvOpUndef:
|
||||
case spv::Op::OpConstantNull:
|
||||
case spv::Op::OpUndef:
|
||||
assert(
|
||||
false &&
|
||||
"Access chains should not be created from null/undefined pointers");
|
||||
@ -117,7 +117,7 @@ bool TransformationAccessChain::IsApplicable(
|
||||
|
||||
// Check whether the object is a struct.
|
||||
if (ir_context->get_def_use_mgr()->GetDef(subobject_type_id)->opcode() ==
|
||||
SpvOpTypeStruct) {
|
||||
spv::Op::OpTypeStruct) {
|
||||
// It is a struct: we need to retrieve the integer value.
|
||||
|
||||
bool successful;
|
||||
@ -202,7 +202,7 @@ bool TransformationAccessChain::IsApplicable(
|
||||
// associated with pointers to isomorphic structs being regarded as the same.
|
||||
return fuzzerutil::MaybeGetPointerType(
|
||||
ir_context, subobject_type_id,
|
||||
static_cast<SpvStorageClass>(
|
||||
static_cast<spv::StorageClass>(
|
||||
pointer_type->GetSingleWordInOperand(0))) != 0;
|
||||
}
|
||||
|
||||
@ -243,7 +243,7 @@ void TransformationAccessChain::Apply(
|
||||
|
||||
// Check whether the object is a struct.
|
||||
if (ir_context->get_def_use_mgr()->GetDef(subobject_type_id)->opcode() ==
|
||||
SpvOpTypeStruct) {
|
||||
spv::Op::OpTypeStruct) {
|
||||
// It is a struct: we need to retrieve the integer value.
|
||||
|
||||
index_value =
|
||||
@ -290,7 +290,8 @@ void TransformationAccessChain::Apply(
|
||||
// %fresh_ids.first = OpULessThanEqual %bool %int_id %bound_minus_one.
|
||||
fuzzerutil::UpdateModuleIdBound(ir_context, fresh_ids.first());
|
||||
auto comparison_instruction = MakeUnique<opt::Instruction>(
|
||||
ir_context, SpvOpULessThanEqual, bool_type_id, fresh_ids.first(),
|
||||
ir_context, spv::Op::OpULessThanEqual, bool_type_id,
|
||||
fresh_ids.first(),
|
||||
opt::Instruction::OperandList(
|
||||
{{SPV_OPERAND_TYPE_ID, {index_instruction->result_id()}},
|
||||
{SPV_OPERAND_TYPE_ID, {bound_minus_one_id}}}));
|
||||
@ -306,7 +307,7 @@ void TransformationAccessChain::Apply(
|
||||
// %bound_minus_one
|
||||
fuzzerutil::UpdateModuleIdBound(ir_context, fresh_ids.second());
|
||||
auto select_instruction = MakeUnique<opt::Instruction>(
|
||||
ir_context, SpvOpSelect, int_type_inst->result_id(),
|
||||
ir_context, spv::Op::OpSelect, int_type_inst->result_id(),
|
||||
fresh_ids.second(),
|
||||
opt::Instruction::OperandList(
|
||||
{{SPV_OPERAND_TYPE_ID, {fresh_ids.first()}},
|
||||
@ -334,13 +335,14 @@ void TransformationAccessChain::Apply(
|
||||
// of the original pointer.
|
||||
uint32_t result_type = fuzzerutil::MaybeGetPointerType(
|
||||
ir_context, subobject_type_id,
|
||||
static_cast<SpvStorageClass>(pointer_type->GetSingleWordInOperand(0)));
|
||||
static_cast<spv::StorageClass>(pointer_type->GetSingleWordInOperand(0)));
|
||||
|
||||
// Add the access chain instruction to the module, and update the module's
|
||||
// id bound.
|
||||
fuzzerutil::UpdateModuleIdBound(ir_context, message_.fresh_id());
|
||||
auto access_chain_instruction = MakeUnique<opt::Instruction>(
|
||||
ir_context, SpvOpAccessChain, result_type, message_.fresh_id(), operands);
|
||||
auto access_chain_instruction =
|
||||
MakeUnique<opt::Instruction>(ir_context, spv::Op::OpAccessChain,
|
||||
result_type, message_.fresh_id(), operands);
|
||||
auto access_chain_instruction_ptr = access_chain_instruction.get();
|
||||
instruction_to_insert_before->InsertBefore(
|
||||
std::move(access_chain_instruction));
|
||||
@ -367,7 +369,7 @@ std::pair<bool, uint32_t> TransformationAccessChain::GetStructIndexValue(
|
||||
opt::IRContext* ir_context, uint32_t index_id,
|
||||
uint32_t object_type_id) const {
|
||||
assert(ir_context->get_def_use_mgr()->GetDef(object_type_id)->opcode() ==
|
||||
SpvOpTypeStruct &&
|
||||
spv::Op::OpTypeStruct &&
|
||||
"Precondition: the type must be a struct type.");
|
||||
if (!ValidIndexToComposite(ir_context, index_id, object_type_id)) {
|
||||
return {false, 0};
|
||||
@ -408,14 +410,14 @@ bool TransformationAccessChain::ValidIndexToComposite(
|
||||
// The index type must be 32-bit integer.
|
||||
auto index_type =
|
||||
ir_context->get_def_use_mgr()->GetDef(index_instruction->type_id());
|
||||
if (index_type->opcode() != SpvOpTypeInt ||
|
||||
if (index_type->opcode() != spv::Op::OpTypeInt ||
|
||||
index_type->GetSingleWordInOperand(0) != 32) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// If the object being traversed is a struct, the id must correspond to an
|
||||
// in-bound constant.
|
||||
if (object_type_def->opcode() == SpvOpTypeStruct) {
|
||||
if (object_type_def->opcode() == spv::Op::OpTypeStruct) {
|
||||
if (!spvOpcodeIsConstant(index_instruction->opcode())) {
|
||||
return false;
|
||||
}
|
||||
|
@ -87,10 +87,10 @@ void TransformationAddBitInstructionSynonym::Apply(
|
||||
// synonym fact. The helper function should take care of invalidating
|
||||
// analyses before adding facts.
|
||||
switch (bit_instruction->opcode()) {
|
||||
case SpvOpBitwiseOr:
|
||||
case SpvOpBitwiseXor:
|
||||
case SpvOpBitwiseAnd:
|
||||
case SpvOpNot:
|
||||
case spv::Op::OpBitwiseOr:
|
||||
case spv::Op::OpBitwiseXor:
|
||||
case spv::Op::OpBitwiseAnd:
|
||||
case spv::Op::OpNot:
|
||||
AddOpBitwiseOrOpNotSynonym(ir_context, transformation_context,
|
||||
bit_instruction);
|
||||
break;
|
||||
@ -106,10 +106,10 @@ bool TransformationAddBitInstructionSynonym::IsInstructionSupported(
|
||||
// Right now we only support certain operations. When this issue is addressed
|
||||
// the following conditional can use the function |spvOpcodeIsBit|.
|
||||
// |instruction| must be defined and must be a supported bit instruction.
|
||||
if (!instruction || (instruction->opcode() != SpvOpBitwiseOr &&
|
||||
instruction->opcode() != SpvOpBitwiseXor &&
|
||||
instruction->opcode() != SpvOpBitwiseAnd &&
|
||||
instruction->opcode() != SpvOpNot)) {
|
||||
if (!instruction || (instruction->opcode() != spv::Op::OpBitwiseOr &&
|
||||
instruction->opcode() != spv::Op::OpBitwiseXor &&
|
||||
instruction->opcode() != spv::Op::OpBitwiseAnd &&
|
||||
instruction->opcode() != spv::Op::OpNot)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -119,7 +119,7 @@ bool TransformationAddBitInstructionSynonym::IsInstructionSupported(
|
||||
return false;
|
||||
}
|
||||
|
||||
if (instruction->opcode() == SpvOpNot) {
|
||||
if (instruction->opcode() == spv::Op::OpNot) {
|
||||
auto operand = instruction->GetInOperand(0).words[0];
|
||||
auto operand_inst = ir_context->get_def_use_mgr()->GetDef(operand);
|
||||
auto operand_type =
|
||||
@ -171,10 +171,10 @@ uint32_t TransformationAddBitInstructionSynonym::GetRequiredFreshIdCount(
|
||||
// TODO(https://github.com/KhronosGroup/SPIRV-Tools/issues/3557):
|
||||
// Right now, only certain operations are supported.
|
||||
switch (bit_instruction->opcode()) {
|
||||
case SpvOpBitwiseOr:
|
||||
case SpvOpBitwiseXor:
|
||||
case SpvOpBitwiseAnd:
|
||||
case SpvOpNot:
|
||||
case spv::Op::OpBitwiseOr:
|
||||
case spv::Op::OpBitwiseXor:
|
||||
case spv::Op::OpBitwiseAnd:
|
||||
case spv::Op::OpNot:
|
||||
return (2 + bit_instruction->NumInOperands()) *
|
||||
ir_context->get_type_mgr()
|
||||
->GetType(bit_instruction->type_id())
|
||||
@ -220,7 +220,7 @@ void TransformationAddBitInstructionSynonym::AddOpBitwiseOrOpNotSynonym(
|
||||
for (auto operand = bit_instruction->begin() + 2;
|
||||
operand != bit_instruction->end(); operand++) {
|
||||
auto bit_extract =
|
||||
opt::Instruction(ir_context, SpvOpBitFieldUExtract,
|
||||
opt::Instruction(ir_context, spv::Op::OpBitFieldUExtract,
|
||||
bit_instruction->type_id(), *fresh_id++,
|
||||
{{SPV_OPERAND_TYPE_ID, operand->words},
|
||||
{SPV_OPERAND_TYPE_ID, {offset}},
|
||||
@ -246,12 +246,13 @@ void TransformationAddBitInstructionSynonym::AddOpBitwiseOrOpNotSynonym(
|
||||
// first two bits of the result.
|
||||
uint32_t offset = fuzzerutil::MaybeGetIntegerConstant(
|
||||
ir_context, *transformation_context, {1}, 32, false, false);
|
||||
auto bit_insert = opt::Instruction(
|
||||
ir_context, SpvOpBitFieldInsert, bit_instruction->type_id(), *fresh_id++,
|
||||
{{SPV_OPERAND_TYPE_ID, {extracted_bit_instructions[0]}},
|
||||
{SPV_OPERAND_TYPE_ID, {extracted_bit_instructions[1]}},
|
||||
{SPV_OPERAND_TYPE_ID, {offset}},
|
||||
{SPV_OPERAND_TYPE_ID, {count}}});
|
||||
auto bit_insert =
|
||||
opt::Instruction(ir_context, spv::Op::OpBitFieldInsert,
|
||||
bit_instruction->type_id(), *fresh_id++,
|
||||
{{SPV_OPERAND_TYPE_ID, {extracted_bit_instructions[0]}},
|
||||
{SPV_OPERAND_TYPE_ID, {extracted_bit_instructions[1]}},
|
||||
{SPV_OPERAND_TYPE_ID, {offset}},
|
||||
{SPV_OPERAND_TYPE_ID, {count}}});
|
||||
bit_instruction->InsertBefore(MakeUnique<opt::Instruction>(bit_insert));
|
||||
fuzzerutil::UpdateModuleIdBound(ir_context, bit_insert.result_id());
|
||||
|
||||
@ -260,7 +261,7 @@ void TransformationAddBitInstructionSynonym::AddOpBitwiseOrOpNotSynonym(
|
||||
offset = fuzzerutil::MaybeGetIntegerConstant(
|
||||
ir_context, *transformation_context, {i}, 32, false, false);
|
||||
bit_insert = opt::Instruction(
|
||||
ir_context, SpvOpBitFieldInsert, bit_instruction->type_id(),
|
||||
ir_context, spv::Op::OpBitFieldInsert, bit_instruction->type_id(),
|
||||
*fresh_id++,
|
||||
{{SPV_OPERAND_TYPE_ID, {bit_insert.result_id()}},
|
||||
{SPV_OPERAND_TYPE_ID, {extracted_bit_instructions[i]}},
|
||||
|
@ -43,7 +43,8 @@ void TransformationAddConstantBoolean::Apply(
|
||||
// Add the boolean constant to the module, ensuring the module's id bound is
|
||||
// high enough.
|
||||
auto new_instruction = MakeUnique<opt::Instruction>(
|
||||
ir_context, message_.is_true() ? SpvOpConstantTrue : SpvOpConstantFalse,
|
||||
ir_context,
|
||||
message_.is_true() ? spv::Op::OpConstantTrue : spv::Op::OpConstantFalse,
|
||||
fuzzerutil::MaybeGetBoolType(ir_context), message_.fresh_id(),
|
||||
opt::Instruction::OperandList());
|
||||
auto new_instruction_ptr = new_instruction.get();
|
||||
|
@ -53,7 +53,7 @@ bool TransformationAddConstantComposite::IsApplicable(
|
||||
// struct - whether its decorations are OK.
|
||||
std::vector<uint32_t> constituent_type_ids;
|
||||
switch (composite_type_instruction->opcode()) {
|
||||
case SpvOpTypeArray:
|
||||
case spv::Op::OpTypeArray:
|
||||
for (uint32_t index = 0;
|
||||
index <
|
||||
fuzzerutil::GetArraySize(*composite_type_instruction, ir_context);
|
||||
@ -62,8 +62,8 @@ bool TransformationAddConstantComposite::IsApplicable(
|
||||
composite_type_instruction->GetSingleWordInOperand(0));
|
||||
}
|
||||
break;
|
||||
case SpvOpTypeMatrix:
|
||||
case SpvOpTypeVector:
|
||||
case spv::Op::OpTypeMatrix:
|
||||
case spv::Op::OpTypeVector:
|
||||
for (uint32_t index = 0;
|
||||
index < composite_type_instruction->GetSingleWordInOperand(1);
|
||||
index++) {
|
||||
@ -71,7 +71,7 @@ bool TransformationAddConstantComposite::IsApplicable(
|
||||
composite_type_instruction->GetSingleWordInOperand(0));
|
||||
}
|
||||
break;
|
||||
case SpvOpTypeStruct:
|
||||
case spv::Op::OpTypeStruct:
|
||||
// We do not create constants of structs decorated with Block nor
|
||||
// BufferBlock. The SPIR-V spec does not explicitly disallow this, but it
|
||||
// seems like a strange thing to do, so we disallow it to avoid triggering
|
||||
@ -120,7 +120,7 @@ void TransformationAddConstantComposite::Apply(
|
||||
in_operands.push_back({SPV_OPERAND_TYPE_ID, {constituent_id}});
|
||||
}
|
||||
auto new_instruction = MakeUnique<opt::Instruction>(
|
||||
ir_context, SpvOpConstantComposite, message_.type_id(),
|
||||
ir_context, spv::Op::OpConstantComposite, message_.type_id(),
|
||||
message_.fresh_id(), in_operands);
|
||||
auto new_instruction_ptr = new_instruction.get();
|
||||
ir_context->module()->AddGlobalValue(std::move(new_instruction));
|
||||
|
@ -48,8 +48,8 @@ bool TransformationAddConstantNull::IsApplicable(
|
||||
void TransformationAddConstantNull::Apply(
|
||||
opt::IRContext* ir_context, TransformationContext* /*unused*/) const {
|
||||
auto new_instruction = MakeUnique<opt::Instruction>(
|
||||
ir_context, SpvOpConstantNull, message_.type_id(), message_.fresh_id(),
|
||||
opt::Instruction::OperandList());
|
||||
ir_context, spv::Op::OpConstantNull, message_.type_id(),
|
||||
message_.fresh_id(), opt::Instruction::OperandList());
|
||||
auto new_instruction_ptr = new_instruction.get();
|
||||
ir_context->module()->AddGlobalValue(std::move(new_instruction));
|
||||
fuzzerutil::UpdateModuleIdBound(ir_context, message_.fresh_id());
|
||||
|
@ -65,7 +65,7 @@ void TransformationAddConstantScalar::Apply(
|
||||
opt::IRContext* ir_context,
|
||||
TransformationContext* transformation_context) const {
|
||||
auto new_instruction = MakeUnique<opt::Instruction>(
|
||||
ir_context, SpvOpConstant, message_.type_id(), message_.fresh_id(),
|
||||
ir_context, spv::Op::OpConstant, message_.type_id(), message_.fresh_id(),
|
||||
opt::Instruction::OperandList(
|
||||
{{SPV_OPERAND_TYPE_LITERAL_INTEGER,
|
||||
std::vector<uint32_t>(message_.word().begin(),
|
||||
|
@ -27,12 +27,12 @@ TransformationAddCopyMemory::TransformationAddCopyMemory(
|
||||
|
||||
TransformationAddCopyMemory::TransformationAddCopyMemory(
|
||||
const protobufs::InstructionDescriptor& instruction_descriptor,
|
||||
uint32_t fresh_id, uint32_t source_id, SpvStorageClass storage_class,
|
||||
uint32_t fresh_id, uint32_t source_id, spv::StorageClass storage_class,
|
||||
uint32_t initializer_id) {
|
||||
*message_.mutable_instruction_descriptor() = instruction_descriptor;
|
||||
message_.set_fresh_id(fresh_id);
|
||||
message_.set_source_id(source_id);
|
||||
message_.set_storage_class(storage_class);
|
||||
message_.set_storage_class(uint32_t(storage_class));
|
||||
message_.set_initializer_id(initializer_id);
|
||||
}
|
||||
|
||||
@ -53,7 +53,8 @@ bool TransformationAddCopyMemory::IsApplicable(
|
||||
// Check that we can insert OpCopyMemory before |instruction_descriptor|.
|
||||
auto iter = fuzzerutil::GetIteratorForInstruction(
|
||||
ir_context->get_instr_block(inst), inst);
|
||||
if (!fuzzerutil::CanInsertOpcodeBeforeInstruction(SpvOpCopyMemory, iter)) {
|
||||
if (!fuzzerutil::CanInsertOpcodeBeforeInstruction(spv::Op::OpCopyMemory,
|
||||
iter)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -65,8 +66,10 @@ bool TransformationAddCopyMemory::IsApplicable(
|
||||
}
|
||||
|
||||
// |storage_class| is either Function or Private.
|
||||
if (message_.storage_class() != SpvStorageClassFunction &&
|
||||
message_.storage_class() != SpvStorageClassPrivate) {
|
||||
if (spv::StorageClass(message_.storage_class()) !=
|
||||
spv::StorageClass::Function &&
|
||||
spv::StorageClass(message_.storage_class()) !=
|
||||
spv::StorageClass::Private) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -76,7 +79,7 @@ bool TransformationAddCopyMemory::IsApplicable(
|
||||
// OpTypePointer with |message_.storage_class| exists.
|
||||
if (!fuzzerutil::MaybeGetPointerType(
|
||||
ir_context, pointee_type_id,
|
||||
static_cast<SpvStorageClass>(message_.storage_class()))) {
|
||||
static_cast<spv::StorageClass>(message_.storage_class()))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -103,20 +106,20 @@ void TransformationAddCopyMemory::Apply(
|
||||
ir_context->get_instr_block(insert_before_inst);
|
||||
|
||||
// Add global or local variable to copy memory into.
|
||||
auto storage_class = static_cast<SpvStorageClass>(message_.storage_class());
|
||||
auto storage_class = static_cast<spv::StorageClass>(message_.storage_class());
|
||||
auto type_id = fuzzerutil::MaybeGetPointerType(
|
||||
ir_context,
|
||||
fuzzerutil::GetPointeeTypeIdFromPointerType(
|
||||
ir_context, fuzzerutil::GetTypeId(ir_context, message_.source_id())),
|
||||
storage_class);
|
||||
|
||||
if (storage_class == SpvStorageClassPrivate) {
|
||||
if (storage_class == spv::StorageClass::Private) {
|
||||
opt::Instruction* new_global =
|
||||
fuzzerutil::AddGlobalVariable(ir_context, message_.fresh_id(), type_id,
|
||||
storage_class, message_.initializer_id());
|
||||
ir_context->get_def_use_mgr()->AnalyzeInstDefUse(new_global);
|
||||
} else {
|
||||
assert(storage_class == SpvStorageClassFunction &&
|
||||
assert(storage_class == spv::StorageClass::Function &&
|
||||
"Storage class can be either Private or Function");
|
||||
opt::Function* enclosing_function = enclosing_block->GetParent();
|
||||
opt::Instruction* new_local = fuzzerutil::AddLocalVariable(
|
||||
@ -130,7 +133,7 @@ void TransformationAddCopyMemory::Apply(
|
||||
enclosing_block, insert_before_inst);
|
||||
|
||||
auto new_instruction = MakeUnique<opt::Instruction>(
|
||||
ir_context, SpvOpCopyMemory, 0, 0,
|
||||
ir_context, spv::Op::OpCopyMemory, 0, 0,
|
||||
opt::Instruction::OperandList{
|
||||
{SPV_OPERAND_TYPE_ID, {message_.fresh_id()}},
|
||||
{SPV_OPERAND_TYPE_ID, {message_.source_id()}}});
|
||||
@ -160,7 +163,8 @@ protobufs::Transformation TransformationAddCopyMemory::ToMessage() const {
|
||||
bool TransformationAddCopyMemory::IsInstructionSupported(
|
||||
opt::IRContext* ir_context, opt::Instruction* inst) {
|
||||
if (!inst->result_id() || !inst->type_id() ||
|
||||
inst->opcode() == SpvOpConstantNull || inst->opcode() == SpvOpUndef) {
|
||||
inst->opcode() == spv::Op::OpConstantNull ||
|
||||
inst->opcode() == spv::Op::OpUndef) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -30,7 +30,7 @@ class TransformationAddCopyMemory : public Transformation {
|
||||
|
||||
TransformationAddCopyMemory(
|
||||
const protobufs::InstructionDescriptor& instruction_descriptor,
|
||||
uint32_t fresh_id, uint32_t source_id, SpvStorageClass storage_class,
|
||||
uint32_t fresh_id, uint32_t source_id, spv::StorageClass storage_class,
|
||||
uint32_t initializer_id);
|
||||
|
||||
// - |instruction_descriptor| must point to a valid instruction in the module.
|
||||
|
@ -61,7 +61,7 @@ bool TransformationAddDeadBlock::IsApplicable(
|
||||
}
|
||||
|
||||
// It must end with OpBranch.
|
||||
if (existing_block->terminator()->opcode() != SpvOpBranch) {
|
||||
if (existing_block->terminator()->opcode() != spv::Op::OpBranch) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -122,27 +122,27 @@ void TransformationAddDeadBlock::Apply(
|
||||
auto enclosing_function = existing_block->GetParent();
|
||||
std::unique_ptr<opt::BasicBlock> new_block =
|
||||
MakeUnique<opt::BasicBlock>(MakeUnique<opt::Instruction>(
|
||||
ir_context, SpvOpLabel, 0, message_.fresh_id(),
|
||||
ir_context, spv::Op::OpLabel, 0, message_.fresh_id(),
|
||||
opt::Instruction::OperandList()));
|
||||
new_block->AddInstruction(MakeUnique<opt::Instruction>(
|
||||
ir_context, SpvOpBranch, 0, 0,
|
||||
ir_context, spv::Op::OpBranch, 0, 0,
|
||||
opt::Instruction::OperandList(
|
||||
{{SPV_OPERAND_TYPE_ID, {successor_block_id}}})));
|
||||
|
||||
// Turn the original block into a selection merge, with its original successor
|
||||
// as the merge block.
|
||||
existing_block->terminator()->InsertBefore(MakeUnique<opt::Instruction>(
|
||||
ir_context, SpvOpSelectionMerge, 0, 0,
|
||||
ir_context, spv::Op::OpSelectionMerge, 0, 0,
|
||||
opt::Instruction::OperandList(
|
||||
{{SPV_OPERAND_TYPE_ID, {successor_block_id}},
|
||||
{SPV_OPERAND_TYPE_SELECTION_CONTROL,
|
||||
{SpvSelectionControlMaskNone}}})));
|
||||
{uint32_t(spv::SelectionControlMask::MaskNone)}}})));
|
||||
|
||||
// Change the original block's terminator to be a conditional branch on the
|
||||
// given boolean, with the original successor and the new successor as branch
|
||||
// targets, and such that at runtime control will always transfer to the
|
||||
// original successor.
|
||||
existing_block->terminator()->SetOpcode(SpvOpBranchConditional);
|
||||
existing_block->terminator()->SetOpcode(spv::Op::OpBranchConditional);
|
||||
existing_block->terminator()->SetInOperands(
|
||||
{{SPV_OPERAND_TYPE_ID, {bool_id}},
|
||||
{SPV_OPERAND_TYPE_ID,
|
||||
|
@ -142,7 +142,7 @@ bool TransformationAddDeadBreak::IsApplicable(
|
||||
}
|
||||
|
||||
// Check that |message_.from_block| ends with an unconditional branch.
|
||||
if (bb_from->terminator()->opcode() != SpvOpBranch) {
|
||||
if (bb_from->terminator()->opcode() != spv::Op::OpBranch) {
|
||||
// The block associated with the id does not end with an unconditional
|
||||
// branch.
|
||||
return false;
|
||||
|
@ -55,7 +55,7 @@ bool TransformationAddDeadContinue::IsApplicable(
|
||||
}
|
||||
|
||||
// Check that |message_.from_block| ends with an unconditional branch.
|
||||
if (bb_from->terminator()->opcode() != SpvOpBranch) {
|
||||
if (bb_from->terminator()->opcode() != spv::Op::OpBranch) {
|
||||
// The block associated with the id does not end with an unconditional
|
||||
// branch.
|
||||
return false;
|
||||
|
@ -28,17 +28,17 @@ TransformationAddEarlyTerminatorWrapper::
|
||||
TransformationAddEarlyTerminatorWrapper::
|
||||
TransformationAddEarlyTerminatorWrapper(uint32_t function_fresh_id,
|
||||
uint32_t label_fresh_id,
|
||||
SpvOp opcode) {
|
||||
spv::Op opcode) {
|
||||
message_.set_function_fresh_id(function_fresh_id);
|
||||
message_.set_label_fresh_id(label_fresh_id);
|
||||
message_.set_opcode(opcode);
|
||||
message_.set_opcode(uint32_t(opcode));
|
||||
}
|
||||
|
||||
bool TransformationAddEarlyTerminatorWrapper::IsApplicable(
|
||||
opt::IRContext* ir_context, const TransformationContext& /*unused*/) const {
|
||||
assert((message_.opcode() == SpvOpKill ||
|
||||
message_.opcode() == SpvOpUnreachable ||
|
||||
message_.opcode() == SpvOpTerminateInvocation) &&
|
||||
assert((spv::Op(message_.opcode()) == spv::Op::OpKill ||
|
||||
spv::Op(message_.opcode()) == spv::Op::OpUnreachable ||
|
||||
spv::Op(message_.opcode()) == spv::Op::OpTerminateInvocation) &&
|
||||
"Invalid opcode.");
|
||||
|
||||
if (!fuzzerutil::IsFreshId(ir_context, message_.function_fresh_id())) {
|
||||
@ -66,26 +66,29 @@ void TransformationAddEarlyTerminatorWrapper::Apply(
|
||||
// %label_fresh_id = OpLabel
|
||||
// OpKill|Unreachable|TerminateInvocation
|
||||
auto basic_block = MakeUnique<opt::BasicBlock>(MakeUnique<opt::Instruction>(
|
||||
ir_context, SpvOpLabel, 0, message_.label_fresh_id(),
|
||||
ir_context, spv::Op::OpLabel, 0, message_.label_fresh_id(),
|
||||
opt::Instruction::OperandList()));
|
||||
basic_block->AddInstruction(MakeUnique<opt::Instruction>(
|
||||
ir_context, static_cast<SpvOp>(message_.opcode()), 0, 0,
|
||||
ir_context, static_cast<spv::Op>(message_.opcode()), 0, 0,
|
||||
opt::Instruction::OperandList()));
|
||||
|
||||
// Create a zero-argument void function.
|
||||
auto void_type_id = fuzzerutil::MaybeGetVoidType(ir_context);
|
||||
auto function = MakeUnique<opt::Function>(MakeUnique<opt::Instruction>(
|
||||
ir_context, SpvOpFunction, void_type_id, message_.function_fresh_id(),
|
||||
ir_context, spv::Op::OpFunction, void_type_id,
|
||||
message_.function_fresh_id(),
|
||||
opt::Instruction::OperandList(
|
||||
{{SPV_OPERAND_TYPE_FUNCTION_CONTROL, {SpvFunctionControlMaskNone}},
|
||||
{{SPV_OPERAND_TYPE_FUNCTION_CONTROL,
|
||||
{uint32_t(spv::FunctionControlMask::MaskNone)}},
|
||||
{SPV_OPERAND_TYPE_TYPE_ID,
|
||||
{fuzzerutil::FindFunctionType(ir_context, {void_type_id})}}})));
|
||||
|
||||
// Add the basic block to the function as the sole block, and add the function
|
||||
// to the module.
|
||||
function->AddBasicBlock(std::move(basic_block));
|
||||
function->SetFunctionEnd(MakeUnique<opt::Instruction>(
|
||||
ir_context, SpvOpFunctionEnd, 0, 0, opt::Instruction::OperandList()));
|
||||
function->SetFunctionEnd(
|
||||
MakeUnique<opt::Instruction>(ir_context, spv::Op::OpFunctionEnd, 0, 0,
|
||||
opt::Instruction::OperandList()));
|
||||
ir_context->module()->AddFunction(std::move(function));
|
||||
|
||||
ir_context->InvalidateAnalysesExceptFor(opt::IRContext::kAnalysisNone);
|
||||
|
@ -30,7 +30,7 @@ class TransformationAddEarlyTerminatorWrapper : public Transformation {
|
||||
|
||||
TransformationAddEarlyTerminatorWrapper(uint32_t function_fresh_id,
|
||||
uint32_t label_fresh_id,
|
||||
SpvOp opcode);
|
||||
spv::Op opcode);
|
||||
|
||||
// - |message_.function_fresh_id| and |message_.label_fresh_id| must be fresh
|
||||
// and distinct.
|
||||
|
@ -178,7 +178,7 @@ void TransformationAddFunction::Apply(
|
||||
}
|
||||
ir_context->InvalidateAnalysesExceptFor(opt::IRContext::kAnalysisNone);
|
||||
|
||||
assert(message_.instruction(0).opcode() == SpvOpFunction &&
|
||||
assert(spv::Op(message_.instruction(0).opcode()) == spv::Op::OpFunction &&
|
||||
"The first instruction of an 'add function' transformation must be "
|
||||
"OpFunction.");
|
||||
|
||||
@ -189,7 +189,7 @@ void TransformationAddFunction::Apply(
|
||||
} else {
|
||||
// Inform the fact manager that all blocks in the function are dead.
|
||||
for (auto& inst : message_.instruction()) {
|
||||
if (inst.opcode() == SpvOpLabel) {
|
||||
if (spv::Op(inst.opcode()) == spv::Op::OpLabel) {
|
||||
transformation_context->GetFactManager()->AddFactBlockIsDead(
|
||||
inst.result_id());
|
||||
}
|
||||
@ -202,16 +202,16 @@ void TransformationAddFunction::Apply(
|
||||
// parameters to other functions knowing that it is OK if they get
|
||||
// over-written.
|
||||
for (auto& instruction : message_.instruction()) {
|
||||
switch (instruction.opcode()) {
|
||||
case SpvOpFunctionParameter:
|
||||
switch (spv::Op(instruction.opcode())) {
|
||||
case spv::Op::OpFunctionParameter:
|
||||
if (ir_context->get_def_use_mgr()
|
||||
->GetDef(instruction.result_type_id())
|
||||
->opcode() == SpvOpTypePointer) {
|
||||
->opcode() == spv::Op::OpTypePointer) {
|
||||
transformation_context->GetFactManager()
|
||||
->AddFactValueOfPointeeIsIrrelevant(instruction.result_id());
|
||||
}
|
||||
break;
|
||||
case SpvOpVariable:
|
||||
case spv::Op::OpVariable:
|
||||
transformation_context->GetFactManager()
|
||||
->AddFactValueOfPointeeIsIrrelevant(instruction.result_id());
|
||||
break;
|
||||
@ -239,7 +239,7 @@ bool TransformationAddFunction::TryToAddFunction(
|
||||
|
||||
// A function must start with OpFunction.
|
||||
auto function_begin = message_.instruction(0);
|
||||
if (function_begin.opcode() != SpvOpFunction) {
|
||||
if (spv::Op(function_begin.opcode()) != spv::Op::OpFunction) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -256,8 +256,8 @@ bool TransformationAddFunction::TryToAddFunction(
|
||||
// Iterate through all function parameter instructions, adding parameters to
|
||||
// the new function.
|
||||
while (instruction_index < num_instructions &&
|
||||
message_.instruction(instruction_index).opcode() ==
|
||||
SpvOpFunctionParameter) {
|
||||
spv::Op(message_.instruction(instruction_index).opcode()) ==
|
||||
spv::Op::OpFunctionParameter) {
|
||||
new_function->AddParameter(InstructionFromMessage(
|
||||
ir_context, message_.instruction(instruction_index)));
|
||||
instruction_index++;
|
||||
@ -265,16 +265,19 @@ bool TransformationAddFunction::TryToAddFunction(
|
||||
|
||||
// After the parameters, there needs to be a label.
|
||||
if (instruction_index == num_instructions ||
|
||||
message_.instruction(instruction_index).opcode() != SpvOpLabel) {
|
||||
spv::Op(message_.instruction(instruction_index).opcode()) !=
|
||||
spv::Op::OpLabel) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Iterate through the instructions block by block until the end of the
|
||||
// function is reached.
|
||||
while (instruction_index < num_instructions &&
|
||||
message_.instruction(instruction_index).opcode() != SpvOpFunctionEnd) {
|
||||
spv::Op(message_.instruction(instruction_index).opcode()) !=
|
||||
spv::Op::OpFunctionEnd) {
|
||||
// Invariant: we should always be at a label instruction at this point.
|
||||
assert(message_.instruction(instruction_index).opcode() == SpvOpLabel);
|
||||
assert(spv::Op(message_.instruction(instruction_index).opcode()) ==
|
||||
spv::Op::OpLabel);
|
||||
|
||||
// Make a basic block using the label instruction.
|
||||
std::unique_ptr<opt::BasicBlock> block =
|
||||
@ -285,9 +288,10 @@ bool TransformationAddFunction::TryToAddFunction(
|
||||
// of the function, adding each such instruction to the block.
|
||||
instruction_index++;
|
||||
while (instruction_index < num_instructions &&
|
||||
message_.instruction(instruction_index).opcode() !=
|
||||
SpvOpFunctionEnd &&
|
||||
message_.instruction(instruction_index).opcode() != SpvOpLabel) {
|
||||
spv::Op(message_.instruction(instruction_index).opcode()) !=
|
||||
spv::Op::OpFunctionEnd &&
|
||||
spv::Op(message_.instruction(instruction_index).opcode()) !=
|
||||
spv::Op::OpLabel) {
|
||||
block->AddInstruction(InstructionFromMessage(
|
||||
ir_context, message_.instruction(instruction_index)));
|
||||
instruction_index++;
|
||||
@ -298,7 +302,8 @@ bool TransformationAddFunction::TryToAddFunction(
|
||||
// Having considered all the blocks, we should be at the last instruction and
|
||||
// it needs to be OpFunctionEnd.
|
||||
if (instruction_index != num_instructions - 1 ||
|
||||
message_.instruction(instruction_index).opcode() != SpvOpFunctionEnd) {
|
||||
spv::Op(message_.instruction(instruction_index).opcode()) !=
|
||||
spv::Op::OpFunctionEnd) {
|
||||
return false;
|
||||
}
|
||||
// Set the function's final instruction, add the function to the module and
|
||||
@ -339,20 +344,20 @@ bool TransformationAddFunction::TryToMakeFunctionLivesafe(
|
||||
for (auto& block : *added_function) {
|
||||
for (auto& inst : block) {
|
||||
switch (inst.opcode()) {
|
||||
case SpvOpKill:
|
||||
case SpvOpUnreachable:
|
||||
case spv::Op::OpKill:
|
||||
case spv::Op::OpUnreachable:
|
||||
if (!TryToTurnKillOrUnreachableIntoReturn(ir_context, added_function,
|
||||
&inst)) {
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
case SpvOpAccessChain:
|
||||
case SpvOpInBoundsAccessChain:
|
||||
case spv::Op::OpAccessChain:
|
||||
case spv::Op::OpInBoundsAccessChain:
|
||||
if (!TryToClampAccessChainIndices(ir_context, &inst)) {
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
case SpvOpFunctionCall:
|
||||
case spv::Op::OpFunctionCall:
|
||||
// A livesafe function my only call other livesafe functions.
|
||||
if (!transformation_context.GetFactManager()->FunctionIsLivesafe(
|
||||
inst.GetSingleWordInOperand(0))) {
|
||||
@ -404,7 +409,7 @@ bool TransformationAddFunction::TryToAddLoopLimiters(
|
||||
auto loop_limit_constant_id_instr =
|
||||
ir_context->get_def_use_mgr()->GetDef(message_.loop_limit_constant_id());
|
||||
if (!loop_limit_constant_id_instr ||
|
||||
loop_limit_constant_id_instr->opcode() != SpvOpConstant) {
|
||||
loop_limit_constant_id_instr->opcode() != spv::Op::OpConstant) {
|
||||
// The loop limit constant id instruction must exist and have an
|
||||
// appropriate opcode.
|
||||
return false;
|
||||
@ -412,7 +417,7 @@ bool TransformationAddFunction::TryToAddLoopLimiters(
|
||||
|
||||
auto loop_limit_type = ir_context->get_def_use_mgr()->GetDef(
|
||||
loop_limit_constant_id_instr->type_id());
|
||||
if (loop_limit_type->opcode() != SpvOpTypeInt ||
|
||||
if (loop_limit_type->opcode() != spv::Op::OpTypeInt ||
|
||||
loop_limit_type->GetSingleWordInOperand(0) != 32) {
|
||||
// The type of the loop limit constant must be 32-bit integer. It
|
||||
// doesn't actually matter whether the integer is signed or not.
|
||||
@ -457,7 +462,7 @@ bool TransformationAddFunction::TryToAddLoopLimiters(
|
||||
|
||||
// Look for pointer-to-unsigned int type.
|
||||
opt::analysis::Pointer pointer_to_unsigned_int_type(
|
||||
registered_unsigned_int_type, SpvStorageClassFunction);
|
||||
registered_unsigned_int_type, spv::StorageClass::Function);
|
||||
uint32_t pointer_to_unsigned_int_type_id =
|
||||
ir_context->get_type_mgr()->GetId(&pointer_to_unsigned_int_type);
|
||||
if (!pointer_to_unsigned_int_type_id) {
|
||||
@ -477,13 +482,13 @@ bool TransformationAddFunction::TryToAddLoopLimiters(
|
||||
|
||||
// Declare the loop limiter variable at the start of the function's entry
|
||||
// block, via an instruction of the form:
|
||||
// %loop_limiter_var = SpvOpVariable %ptr_to_uint Function %zero
|
||||
// %loop_limiter_var = spv::Op::OpVariable %ptr_to_uint Function %zero
|
||||
added_function->begin()->begin()->InsertBefore(MakeUnique<opt::Instruction>(
|
||||
ir_context, SpvOpVariable, pointer_to_unsigned_int_type_id,
|
||||
ir_context, spv::Op::OpVariable, pointer_to_unsigned_int_type_id,
|
||||
message_.loop_limiter_variable_id(),
|
||||
opt::Instruction::OperandList(
|
||||
{{SPV_OPERAND_TYPE_STORAGE_CLASS, {SpvStorageClassFunction}},
|
||||
{SPV_OPERAND_TYPE_ID, {zero_id}}})));
|
||||
opt::Instruction::OperandList({{SPV_OPERAND_TYPE_STORAGE_CLASS,
|
||||
{uint32_t(spv::StorageClass::Function)}},
|
||||
{SPV_OPERAND_TYPE_ID, {zero_id}}})));
|
||||
// Update the module's id bound since we have added the loop limiter
|
||||
// variable id.
|
||||
fuzzerutil::UpdateModuleIdBound(ir_context,
|
||||
@ -589,10 +594,11 @@ bool TransformationAddFunction::TryToAddLoopLimiters(
|
||||
auto back_edge_block = ir_context->cfg()->block(back_edge_block_id);
|
||||
auto back_edge_block_terminator = back_edge_block->terminator();
|
||||
bool compare_using_greater_than_equal;
|
||||
if (back_edge_block_terminator->opcode() == SpvOpBranch) {
|
||||
if (back_edge_block_terminator->opcode() == spv::Op::OpBranch) {
|
||||
compare_using_greater_than_equal = true;
|
||||
} else {
|
||||
assert(back_edge_block_terminator->opcode() == SpvOpBranchConditional);
|
||||
assert(back_edge_block_terminator->opcode() ==
|
||||
spv::Op::OpBranchConditional);
|
||||
assert(((back_edge_block_terminator->GetSingleWordInOperand(1) ==
|
||||
loop_header->id() &&
|
||||
back_edge_block_terminator->GetSingleWordInOperand(2) ==
|
||||
@ -613,7 +619,7 @@ bool TransformationAddFunction::TryToAddLoopLimiters(
|
||||
// Add a load from the loop limiter variable, of the form:
|
||||
// %t1 = OpLoad %uint32 %loop_limiter
|
||||
new_instructions.push_back(MakeUnique<opt::Instruction>(
|
||||
ir_context, SpvOpLoad, unsigned_int_type_id,
|
||||
ir_context, spv::Op::OpLoad, unsigned_int_type_id,
|
||||
loop_limiter_info.load_id(),
|
||||
opt::Instruction::OperandList(
|
||||
{{SPV_OPERAND_TYPE_ID, {message_.loop_limiter_variable_id()}}})));
|
||||
@ -621,7 +627,7 @@ bool TransformationAddFunction::TryToAddLoopLimiters(
|
||||
// Increment the loaded value:
|
||||
// %t2 = OpIAdd %uint32 %t1 %one
|
||||
new_instructions.push_back(MakeUnique<opt::Instruction>(
|
||||
ir_context, SpvOpIAdd, unsigned_int_type_id,
|
||||
ir_context, spv::Op::OpIAdd, unsigned_int_type_id,
|
||||
loop_limiter_info.increment_id(),
|
||||
opt::Instruction::OperandList(
|
||||
{{SPV_OPERAND_TYPE_ID, {loop_limiter_info.load_id()}},
|
||||
@ -630,7 +636,7 @@ bool TransformationAddFunction::TryToAddLoopLimiters(
|
||||
// Store the incremented value back to the loop limiter variable:
|
||||
// OpStore %loop_limiter %t2
|
||||
new_instructions.push_back(MakeUnique<opt::Instruction>(
|
||||
ir_context, SpvOpStore, 0, 0,
|
||||
ir_context, spv::Op::OpStore, 0, 0,
|
||||
opt::Instruction::OperandList(
|
||||
{{SPV_OPERAND_TYPE_ID, {message_.loop_limiter_variable_id()}},
|
||||
{SPV_OPERAND_TYPE_ID, {loop_limiter_info.increment_id()}}})));
|
||||
@ -641,17 +647,18 @@ bool TransformationAddFunction::TryToAddLoopLimiters(
|
||||
// %t3 = OpULessThan %bool %t1 %loop_limit
|
||||
new_instructions.push_back(MakeUnique<opt::Instruction>(
|
||||
ir_context,
|
||||
compare_using_greater_than_equal ? SpvOpUGreaterThanEqual
|
||||
: SpvOpULessThan,
|
||||
compare_using_greater_than_equal ? spv::Op::OpUGreaterThanEqual
|
||||
: spv::Op::OpULessThan,
|
||||
bool_type_id, loop_limiter_info.compare_id(),
|
||||
opt::Instruction::OperandList(
|
||||
{{SPV_OPERAND_TYPE_ID, {loop_limiter_info.load_id()}},
|
||||
{SPV_OPERAND_TYPE_ID, {message_.loop_limit_constant_id()}}})));
|
||||
|
||||
if (back_edge_block_terminator->opcode() == SpvOpBranchConditional) {
|
||||
if (back_edge_block_terminator->opcode() == spv::Op::OpBranchConditional) {
|
||||
new_instructions.push_back(MakeUnique<opt::Instruction>(
|
||||
ir_context,
|
||||
compare_using_greater_than_equal ? SpvOpLogicalOr : SpvOpLogicalAnd,
|
||||
compare_using_greater_than_equal ? spv::Op::OpLogicalOr
|
||||
: spv::Op::OpLogicalAnd,
|
||||
bool_type_id, loop_limiter_info.logical_op_id(),
|
||||
opt::Instruction::OperandList(
|
||||
{{SPV_OPERAND_TYPE_ID,
|
||||
@ -669,11 +676,11 @@ bool TransformationAddFunction::TryToAddLoopLimiters(
|
||||
back_edge_block_terminator->InsertBefore(std::move(new_instructions));
|
||||
}
|
||||
|
||||
if (back_edge_block_terminator->opcode() == SpvOpBranchConditional) {
|
||||
if (back_edge_block_terminator->opcode() == spv::Op::OpBranchConditional) {
|
||||
back_edge_block_terminator->SetInOperand(
|
||||
0, {loop_limiter_info.logical_op_id()});
|
||||
} else {
|
||||
assert(back_edge_block_terminator->opcode() == SpvOpBranch &&
|
||||
assert(back_edge_block_terminator->opcode() == spv::Op::OpBranch &&
|
||||
"Back-edge terminator must be OpBranch or OpBranchConditional");
|
||||
|
||||
// Check that, if the merge block starts with OpPhi instructions, suitable
|
||||
@ -689,7 +696,7 @@ bool TransformationAddFunction::TryToAddLoopLimiters(
|
||||
// Augment OpPhi instructions at the loop merge with the given ids.
|
||||
uint32_t phi_index = 0;
|
||||
for (auto& inst : *merge_block) {
|
||||
if (inst.opcode() != SpvOpPhi) {
|
||||
if (inst.opcode() != spv::Op::OpPhi) {
|
||||
break;
|
||||
}
|
||||
assert(phi_index <
|
||||
@ -702,7 +709,7 @@ bool TransformationAddFunction::TryToAddLoopLimiters(
|
||||
}
|
||||
|
||||
// Add the new edge, by changing OpBranch to OpBranchConditional.
|
||||
back_edge_block_terminator->SetOpcode(SpvOpBranchConditional);
|
||||
back_edge_block_terminator->SetOpcode(spv::Op::OpBranchConditional);
|
||||
back_edge_block_terminator->SetInOperands(opt::Instruction::OperandList(
|
||||
{{SPV_OPERAND_TYPE_ID, {loop_limiter_info.compare_id()}},
|
||||
{SPV_OPERAND_TYPE_ID, {loop_header->MergeBlockId()}},
|
||||
@ -724,18 +731,18 @@ bool TransformationAddFunction::TryToAddLoopLimiters(
|
||||
bool TransformationAddFunction::TryToTurnKillOrUnreachableIntoReturn(
|
||||
opt::IRContext* ir_context, opt::Function* added_function,
|
||||
opt::Instruction* kill_or_unreachable_inst) const {
|
||||
assert((kill_or_unreachable_inst->opcode() == SpvOpKill ||
|
||||
kill_or_unreachable_inst->opcode() == SpvOpUnreachable) &&
|
||||
assert((kill_or_unreachable_inst->opcode() == spv::Op::OpKill ||
|
||||
kill_or_unreachable_inst->opcode() == spv::Op::OpUnreachable) &&
|
||||
"Precondition: instruction must be OpKill or OpUnreachable.");
|
||||
|
||||
// Get the function's return type.
|
||||
auto function_return_type_inst =
|
||||
ir_context->get_def_use_mgr()->GetDef(added_function->type_id());
|
||||
|
||||
if (function_return_type_inst->opcode() == SpvOpTypeVoid) {
|
||||
if (function_return_type_inst->opcode() == spv::Op::OpTypeVoid) {
|
||||
// The function has void return type, so change this instruction to
|
||||
// OpReturn.
|
||||
kill_or_unreachable_inst->SetOpcode(SpvOpReturn);
|
||||
kill_or_unreachable_inst->SetOpcode(spv::Op::OpReturn);
|
||||
} else {
|
||||
// The function has non-void return type, so change this instruction
|
||||
// to OpReturnValue, using the value id provided with the
|
||||
@ -749,7 +756,7 @@ bool TransformationAddFunction::TryToTurnKillOrUnreachableIntoReturn(
|
||||
->type_id() != function_return_type_inst->result_id()) {
|
||||
return false;
|
||||
}
|
||||
kill_or_unreachable_inst->SetOpcode(SpvOpReturnValue);
|
||||
kill_or_unreachable_inst->SetOpcode(spv::Op::OpReturnValue);
|
||||
kill_or_unreachable_inst->SetInOperands(
|
||||
{{SPV_OPERAND_TYPE_ID, {message_.kill_unreachable_return_value_id()}}});
|
||||
}
|
||||
@ -758,8 +765,8 @@ bool TransformationAddFunction::TryToTurnKillOrUnreachableIntoReturn(
|
||||
|
||||
bool TransformationAddFunction::TryToClampAccessChainIndices(
|
||||
opt::IRContext* ir_context, opt::Instruction* access_chain_inst) const {
|
||||
assert((access_chain_inst->opcode() == SpvOpAccessChain ||
|
||||
access_chain_inst->opcode() == SpvOpInBoundsAccessChain) &&
|
||||
assert((access_chain_inst->opcode() == spv::Op::OpAccessChain ||
|
||||
access_chain_inst->opcode() == spv::Op::OpInBoundsAccessChain) &&
|
||||
"Precondition: instruction must be OpAccessChain or "
|
||||
"OpInBoundsAccessChain.");
|
||||
|
||||
@ -793,7 +800,7 @@ bool TransformationAddFunction::TryToClampAccessChainIndices(
|
||||
assert(base_object && "The base object must exist.");
|
||||
auto pointer_type =
|
||||
ir_context->get_def_use_mgr()->GetDef(base_object->type_id());
|
||||
assert(pointer_type && pointer_type->opcode() == SpvOpTypePointer &&
|
||||
assert(pointer_type && pointer_type->opcode() == spv::Op::OpTypePointer &&
|
||||
"The base object must have pointer type.");
|
||||
auto should_be_composite_type = ir_context->get_def_use_mgr()->GetDef(
|
||||
pointer_type->GetSingleWordInOperand(1));
|
||||
@ -824,18 +831,18 @@ bool TransformationAddFunction::TryToClampAccessChainIndices(
|
||||
auto index_inst = ir_context->get_def_use_mgr()->GetDef(index_id);
|
||||
auto index_type_inst =
|
||||
ir_context->get_def_use_mgr()->GetDef(index_inst->type_id());
|
||||
assert(index_type_inst->opcode() == SpvOpTypeInt);
|
||||
assert(index_type_inst->opcode() == spv::Op::OpTypeInt);
|
||||
assert(index_type_inst->GetSingleWordInOperand(0) == 32);
|
||||
opt::analysis::Integer* index_int_type =
|
||||
ir_context->get_type_mgr()
|
||||
->GetType(index_type_inst->result_id())
|
||||
->AsInteger();
|
||||
|
||||
if (index_inst->opcode() != SpvOpConstant ||
|
||||
if (index_inst->opcode() != spv::Op::OpConstant ||
|
||||
index_inst->GetSingleWordInOperand(0) >= bound) {
|
||||
// The index is either non-constant or an out-of-bounds constant, so we
|
||||
// need to clamp it.
|
||||
assert(should_be_composite_type->opcode() != SpvOpTypeStruct &&
|
||||
assert(should_be_composite_type->opcode() != spv::Op::OpTypeStruct &&
|
||||
"Access chain indices into structures are required to be "
|
||||
"constants.");
|
||||
opt::analysis::IntConstant bound_minus_one(index_int_type, {bound - 1});
|
||||
@ -866,7 +873,7 @@ bool TransformationAddFunction::TryToClampAccessChainIndices(
|
||||
// Compare the index with the bound via an instruction of the form:
|
||||
// %t1 = OpULessThanEqual %bool %index %bound_minus_one
|
||||
new_instructions.push_back(MakeUnique<opt::Instruction>(
|
||||
ir_context, SpvOpULessThanEqual, bool_type_id, compare_id,
|
||||
ir_context, spv::Op::OpULessThanEqual, bool_type_id, compare_id,
|
||||
opt::Instruction::OperandList(
|
||||
{{SPV_OPERAND_TYPE_ID, {index_inst->result_id()}},
|
||||
{SPV_OPERAND_TYPE_ID, {bound_minus_one_id}}})));
|
||||
@ -874,7 +881,8 @@ bool TransformationAddFunction::TryToClampAccessChainIndices(
|
||||
// Select the index if in-bounds, otherwise one less than the bound:
|
||||
// %t2 = OpSelect %int_type %t1 %index %bound_minus_one
|
||||
new_instructions.push_back(MakeUnique<opt::Instruction>(
|
||||
ir_context, SpvOpSelect, index_type_inst->result_id(), select_id,
|
||||
ir_context, spv::Op::OpSelect, index_type_inst->result_id(),
|
||||
select_id,
|
||||
opt::Instruction::OperandList(
|
||||
{{SPV_OPERAND_TYPE_ID, {compare_id}},
|
||||
{SPV_OPERAND_TYPE_ID, {index_inst->result_id()}},
|
||||
@ -899,20 +907,20 @@ opt::Instruction* TransformationAddFunction::FollowCompositeIndex(
|
||||
uint32_t index_id) {
|
||||
uint32_t sub_object_type_id;
|
||||
switch (composite_type_inst.opcode()) {
|
||||
case SpvOpTypeArray:
|
||||
case SpvOpTypeRuntimeArray:
|
||||
case spv::Op::OpTypeArray:
|
||||
case spv::Op::OpTypeRuntimeArray:
|
||||
sub_object_type_id = composite_type_inst.GetSingleWordInOperand(0);
|
||||
break;
|
||||
case SpvOpTypeMatrix:
|
||||
case SpvOpTypeVector:
|
||||
case spv::Op::OpTypeMatrix:
|
||||
case spv::Op::OpTypeVector:
|
||||
sub_object_type_id = composite_type_inst.GetSingleWordInOperand(0);
|
||||
break;
|
||||
case SpvOpTypeStruct: {
|
||||
case spv::Op::OpTypeStruct: {
|
||||
auto index_inst = ir_context->get_def_use_mgr()->GetDef(index_id);
|
||||
assert(index_inst->opcode() == SpvOpConstant);
|
||||
assert(index_inst->opcode() == spv::Op::OpConstant);
|
||||
assert(ir_context->get_def_use_mgr()
|
||||
->GetDef(index_inst->type_id())
|
||||
->opcode() == SpvOpTypeInt);
|
||||
->opcode() == spv::Op::OpTypeInt);
|
||||
assert(ir_context->get_def_use_mgr()
|
||||
->GetDef(index_inst->type_id())
|
||||
->GetSingleWordInOperand(0) == 32);
|
||||
|
@ -39,14 +39,14 @@ bool TransformationAddGlobalUndef::IsApplicable(
|
||||
auto type = ir_context->get_def_use_mgr()->GetDef(message_.type_id());
|
||||
// The type must exist, and must not be a function or pointer type.
|
||||
return type != nullptr && opt::IsTypeInst(type->opcode()) &&
|
||||
type->opcode() != SpvOpTypeFunction &&
|
||||
type->opcode() != SpvOpTypePointer;
|
||||
type->opcode() != spv::Op::OpTypeFunction &&
|
||||
type->opcode() != spv::Op::OpTypePointer;
|
||||
}
|
||||
|
||||
void TransformationAddGlobalUndef::Apply(
|
||||
opt::IRContext* ir_context, TransformationContext* /*unused*/) const {
|
||||
auto new_instruction = MakeUnique<opt::Instruction>(
|
||||
ir_context, SpvOpUndef, message_.type_id(), message_.fresh_id(),
|
||||
ir_context, spv::Op::OpUndef, message_.type_id(), message_.fresh_id(),
|
||||
opt::Instruction::OperandList());
|
||||
auto new_instruction_ptr = new_instruction.get();
|
||||
ir_context->module()->AddGlobalValue(std::move(new_instruction));
|
||||
|
@ -24,11 +24,11 @@ TransformationAddGlobalVariable::TransformationAddGlobalVariable(
|
||||
: message_(std::move(message)) {}
|
||||
|
||||
TransformationAddGlobalVariable::TransformationAddGlobalVariable(
|
||||
uint32_t fresh_id, uint32_t type_id, SpvStorageClass storage_class,
|
||||
uint32_t fresh_id, uint32_t type_id, spv::StorageClass storage_class,
|
||||
uint32_t initializer_id, bool value_is_irrelevant) {
|
||||
message_.set_fresh_id(fresh_id);
|
||||
message_.set_type_id(type_id);
|
||||
message_.set_storage_class(storage_class);
|
||||
message_.set_storage_class(uint32_t(storage_class));
|
||||
message_.set_initializer_id(initializer_id);
|
||||
message_.set_value_is_irrelevant(value_is_irrelevant);
|
||||
}
|
||||
@ -41,10 +41,10 @@ bool TransformationAddGlobalVariable::IsApplicable(
|
||||
}
|
||||
|
||||
// The storage class must be Private or Workgroup.
|
||||
auto storage_class = static_cast<SpvStorageClass>(message_.storage_class());
|
||||
auto storage_class = static_cast<spv::StorageClass>(message_.storage_class());
|
||||
switch (storage_class) {
|
||||
case SpvStorageClassPrivate:
|
||||
case SpvStorageClassWorkgroup:
|
||||
case spv::StorageClass::Private:
|
||||
case spv::StorageClass::Workgroup:
|
||||
break;
|
||||
default:
|
||||
assert(false && "Unsupported storage class.");
|
||||
@ -66,7 +66,7 @@ bool TransformationAddGlobalVariable::IsApplicable(
|
||||
}
|
||||
if (message_.initializer_id()) {
|
||||
// An initializer is not allowed if the storage class is Workgroup.
|
||||
if (storage_class == SpvStorageClassWorkgroup) {
|
||||
if (storage_class == spv::StorageClass::Workgroup) {
|
||||
assert(false &&
|
||||
"By construction this transformation should not have an "
|
||||
"initializer when Workgroup storage class is used.");
|
||||
@ -95,7 +95,7 @@ void TransformationAddGlobalVariable::Apply(
|
||||
TransformationContext* transformation_context) const {
|
||||
opt::Instruction* new_instruction = fuzzerutil::AddGlobalVariable(
|
||||
ir_context, message_.fresh_id(), message_.type_id(),
|
||||
static_cast<SpvStorageClass>(message_.storage_class()),
|
||||
static_cast<spv::StorageClass>(message_.storage_class()),
|
||||
message_.initializer_id());
|
||||
|
||||
// Inform the def-use manager about the new instruction.
|
||||
|
@ -29,7 +29,7 @@ class TransformationAddGlobalVariable : public Transformation {
|
||||
protobufs::TransformationAddGlobalVariable message);
|
||||
|
||||
TransformationAddGlobalVariable(uint32_t fresh_id, uint32_t type_id,
|
||||
SpvStorageClass storage_class,
|
||||
spv::StorageClass storage_class,
|
||||
uint32_t initializer_id,
|
||||
bool value_is_irrelevant);
|
||||
|
||||
|
@ -73,7 +73,7 @@ bool TransformationAddImageSampleUnusedComponents::IsApplicable(
|
||||
// It must be an OpCompositeConstruct instruction such that it can be checked
|
||||
// that the original components are present.
|
||||
if (coordinate_with_unused_components_instruction->opcode() !=
|
||||
SpvOpCompositeConstruct) {
|
||||
spv::Op::OpCompositeConstruct) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -43,8 +43,10 @@ bool TransformationAddLocalVariable::IsApplicable(
|
||||
// function storage class.
|
||||
auto type_instruction =
|
||||
ir_context->get_def_use_mgr()->GetDef(message_.type_id());
|
||||
if (!type_instruction || type_instruction->opcode() != SpvOpTypePointer ||
|
||||
type_instruction->GetSingleWordInOperand(0) != SpvStorageClassFunction) {
|
||||
if (!type_instruction ||
|
||||
type_instruction->opcode() != spv::Op::OpTypePointer ||
|
||||
spv::StorageClass(type_instruction->GetSingleWordInOperand(0)) !=
|
||||
spv::StorageClass::Function) {
|
||||
return false;
|
||||
}
|
||||
// The initializer must...
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user