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