!24 回退 'Pull Request !23 : spirv-tools/headers update to vulkan-sdk-1.3.275.0'

Merge pull request !24 from openharmony_ci/revert-merge-23-master
This commit is contained in:
openharmony_ci 2024-04-30 02:33:17 +00:00 committed by Gitee
commit 86aeb7d7b9
No known key found for this signature in database
GPG Key ID: 173E9B9CA92EEF8F
784 changed files with 26960 additions and 49719 deletions

3
.gitignore vendored
View File

@ -4,7 +4,6 @@
compile_commands.json compile_commands.json
/build*/ /build*/
/buildtools/ /buildtools/
/external/abseil_cpp/
/external/googletest /external/googletest
/external/SPIRV-Headers /external/SPIRV-Headers
/external/spirv-headers /external/spirv-headers
@ -21,7 +20,7 @@ bazel-bin
bazel-genfiles bazel-genfiles
bazel-out bazel-out
bazel-spirv-tools bazel-spirv-tools
bazel-SPIRV-Tools bazel-spirv-tools
bazel-testlogs bazel-testlogs
# Vim # Vim

View File

@ -71,7 +71,6 @@ SPVTOOLS_SRC_FILES := \
source/val/validate_primitives.cpp \ source/val/validate_primitives.cpp \
source/val/validate_ray_query.cpp \ source/val/validate_ray_query.cpp \
source/val/validate_ray_tracing.cpp \ source/val/validate_ray_tracing.cpp \
source/val/validate_ray_tracing_reorder.cpp \
source/val/validate_scopes.cpp \ source/val/validate_scopes.cpp \
source/val/validate_small_type_uses.cpp \ source/val/validate_small_type_uses.cpp \
source/val/validate_type.cpp source/val/validate_type.cpp
@ -79,7 +78,6 @@ SPVTOOLS_SRC_FILES := \
SPVTOOLS_OPT_SRC_FILES := \ SPVTOOLS_OPT_SRC_FILES := \
source/opt/aggressive_dead_code_elim_pass.cpp \ source/opt/aggressive_dead_code_elim_pass.cpp \
source/opt/amd_ext_to_khr.cpp \ source/opt/amd_ext_to_khr.cpp \
source/opt/analyze_live_input_pass.cpp \
source/opt/basic_block.cpp \ source/opt/basic_block.cpp \
source/opt/block_merge_pass.cpp \ source/opt/block_merge_pass.cpp \
source/opt/block_merge_util.cpp \ source/opt/block_merge_util.cpp \
@ -111,9 +109,8 @@ SPVTOOLS_OPT_SRC_FILES := \
source/opt/eliminate_dead_constant_pass.cpp \ source/opt/eliminate_dead_constant_pass.cpp \
source/opt/eliminate_dead_functions_pass.cpp \ source/opt/eliminate_dead_functions_pass.cpp \
source/opt/eliminate_dead_functions_util.cpp \ source/opt/eliminate_dead_functions_util.cpp \
source/opt/eliminate_dead_io_components_pass.cpp \ source/opt/eliminate_dead_input_components_pass.cpp \
source/opt/eliminate_dead_members_pass.cpp \ source/opt/eliminate_dead_members_pass.cpp \
source/opt/eliminate_dead_output_stores_pass.cpp \
source/opt/feature_manager.cpp \ source/opt/feature_manager.cpp \
source/opt/fix_func_call_arguments.cpp \ source/opt/fix_func_call_arguments.cpp \
source/opt/fix_storage_class.cpp \ source/opt/fix_storage_class.cpp \
@ -136,11 +133,9 @@ SPVTOOLS_OPT_SRC_FILES := \
source/opt/instrument_pass.cpp \ source/opt/instrument_pass.cpp \
source/opt/interface_var_sroa.cpp \ source/opt/interface_var_sroa.cpp \
source/opt/interp_fixup_pass.cpp \ source/opt/interp_fixup_pass.cpp \
source/opt/invocation_interlock_placement_pass.cpp \
source/opt/ir_context.cpp \ source/opt/ir_context.cpp \
source/opt/ir_loader.cpp \ source/opt/ir_loader.cpp \
source/opt/licm_pass.cpp \ source/opt/licm_pass.cpp \
source/opt/liveness.cpp \
source/opt/local_access_chain_convert_pass.cpp \ source/opt/local_access_chain_convert_pass.cpp \
source/opt/local_redundancy_elimination.cpp \ source/opt/local_redundancy_elimination.cpp \
source/opt/local_single_block_elim_pass.cpp \ source/opt/local_single_block_elim_pass.cpp \
@ -183,8 +178,6 @@ SPVTOOLS_OPT_SRC_FILES := \
source/opt/strip_debug_info_pass.cpp \ source/opt/strip_debug_info_pass.cpp \
source/opt/strip_nonsemantic_info_pass.cpp \ source/opt/strip_nonsemantic_info_pass.cpp \
source/opt/struct_cfg_analysis.cpp \ source/opt/struct_cfg_analysis.cpp \
source/opt/switch_descriptorset_pass.cpp \
source/opt/trim_capabilities_pass.cpp \
source/opt/type_manager.cpp \ source/opt/type_manager.cpp \
source/opt/types.cpp \ source/opt/types.cpp \
source/opt/unify_const_pass.cpp \ source/opt/unify_const_pass.cpp \
@ -224,8 +217,7 @@ $(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
@ -299,8 +291,7 @@ $(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.
@ -343,7 +334,7 @@ LOCAL_C_INCLUDES := \
$(SPVTOOLS_OUT_PATH) $(SPVTOOLS_OUT_PATH)
LOCAL_EXPORT_C_INCLUDES := \ LOCAL_EXPORT_C_INCLUDES := \
$(LOCAL_PATH)/include $(LOCAL_PATH)/include
LOCAL_CXXFLAGS:=-std=c++17 -fno-exceptions -fno-rtti -Werror LOCAL_CXXFLAGS:=-std=c++11 -fno-exceptions -fno-rtti -Werror
LOCAL_SRC_FILES:= $(SPVTOOLS_SRC_FILES) LOCAL_SRC_FILES:= $(SPVTOOLS_SRC_FILES)
include $(BUILD_STATIC_LIBRARY) include $(BUILD_STATIC_LIBRARY)
@ -354,7 +345,7 @@ LOCAL_C_INCLUDES := \
$(LOCAL_PATH)/source \ $(LOCAL_PATH)/source \
$(SPVHEADERS_LOCAL_PATH)/include \ $(SPVHEADERS_LOCAL_PATH)/include \
$(SPVTOOLS_OUT_PATH) $(SPVTOOLS_OUT_PATH)
LOCAL_CXXFLAGS:=-std=c++17 -fno-exceptions -fno-rtti -Werror LOCAL_CXXFLAGS:=-std=c++11 -fno-exceptions -fno-rtti -Werror
LOCAL_STATIC_LIBRARIES:=SPIRV-Tools LOCAL_STATIC_LIBRARIES:=SPIRV-Tools
LOCAL_SRC_FILES:= $(SPVTOOLS_OPT_SRC_FILES) LOCAL_SRC_FILES:= $(SPVTOOLS_OPT_SRC_FILES)
include $(BUILD_STATIC_LIBRARY) include $(BUILD_STATIC_LIBRARY)

View File

@ -1,24 +1,27 @@
load( load(
":build_defs.bzl", ":build_defs.bzl",
"CLDEBUGINFO100_GRAMMAR_JSON_FILE",
"COMMON_COPTS", "COMMON_COPTS",
"DEBUGINFO_GRAMMAR_JSON_FILE", "DEBUGINFO_GRAMMAR_JSON_FILE",
"CLDEBUGINFO100_GRAMMAR_JSON_FILE",
"SHDEBUGINFO100_GRAMMAR_JSON_FILE", "SHDEBUGINFO100_GRAMMAR_JSON_FILE",
"TEST_COPTS", "TEST_COPTS",
"base_test",
"generate_core_tables", "generate_core_tables",
"generate_enum_string_mapping", "generate_enum_string_mapping",
"generate_extinst_lang_headers", "generate_extinst_lang_headers",
"generate_glsl_tables", "generate_glsl_tables",
"generate_opencl_tables", "generate_opencl_tables",
"generate_vendor_tables", "generate_vendor_tables",
"incompatible_with", "link_test",
"lint_test",
"opt_test",
"reduce_test",
"util_test",
"val_test",
) )
package( package(
default_visibility = ["//visibility:private"], default_visibility = ["//visibility:private"],
features = [
"layering_check",
],
) )
licenses(["notice"]) licenses(["notice"])
@ -38,50 +41,35 @@ py_binary(
srcs = ["utils/generate_language_headers.py"], srcs = ["utils/generate_language_headers.py"],
) )
generate_core_tables(version = "unified1") generate_core_tables("unified1")
generate_enum_string_mapping(version = "unified1") generate_enum_string_mapping("unified1")
generate_opencl_tables(version = "unified1") generate_opencl_tables("unified1")
generate_glsl_tables(version = "unified1") generate_glsl_tables("unified1")
generate_vendor_tables(extension = "spv-amd-shader-explicit-vertex-parameter") generate_vendor_tables("spv-amd-shader-explicit-vertex-parameter")
generate_vendor_tables(extension = "spv-amd-shader-trinary-minmax") generate_vendor_tables("spv-amd-shader-trinary-minmax")
generate_vendor_tables(extension = "spv-amd-gcn-shader") generate_vendor_tables("spv-amd-gcn-shader")
generate_vendor_tables(extension = "spv-amd-shader-ballot") generate_vendor_tables("spv-amd-shader-ballot")
generate_vendor_tables(extension = "debuginfo") generate_vendor_tables("debuginfo")
generate_vendor_tables(extension = "nonsemantic.clspvreflection") generate_vendor_tables("opencl.debuginfo.100", "CLDEBUG100_")
generate_vendor_tables( generate_vendor_tables("nonsemantic.shader.debuginfo.100", "SHDEBUG100_")
extension = "opencl.debuginfo.100",
operand_kind_prefix = "CLDEBUG100_",
)
generate_vendor_tables( generate_vendor_tables("nonsemantic.clspvreflection")
extension = "nonsemantic.shader.debuginfo.100",
operand_kind_prefix = "SHDEBUG100_",
)
generate_extinst_lang_headers( generate_extinst_lang_headers("DebugInfo", DEBUGINFO_GRAMMAR_JSON_FILE)
name = "DebugInfo",
grammar = DEBUGINFO_GRAMMAR_JSON_FILE,
)
generate_extinst_lang_headers( generate_extinst_lang_headers("OpenCLDebugInfo100", CLDEBUGINFO100_GRAMMAR_JSON_FILE)
name = "OpenCLDebugInfo100",
grammar = CLDEBUGINFO100_GRAMMAR_JSON_FILE,
)
generate_extinst_lang_headers( generate_extinst_lang_headers("NonSemanticShaderDebugInfo100", SHDEBUGINFO100_GRAMMAR_JSON_FILE)
name = "NonSemanticShaderDebugInfo100",
grammar = SHDEBUGINFO100_GRAMMAR_JSON_FILE,
)
py_binary( py_binary(
name = "generate_registry_tables", name = "generate_registry_tables",
@ -89,12 +77,12 @@ py_binary(
) )
genrule( genrule(
name = "generators_inc", name = "gen_registry_tables",
srcs = ["@spirv_headers//:spirv_xml_registry"], srcs = ["@spirv_headers//:spirv_xml_registry"],
outs = ["generators.inc"], outs = ["generators.inc"],
cmd = "$(location :generate_registry_tables) --xml=$(location @spirv_headers//:spirv_xml_registry) --generator-output=$(location generators.inc)", cmd = "$(location generate_registry_tables) --xml=$(location @spirv_headers//:spirv_xml_registry) --generator-output=$(location generators.inc)",
cmd_bat = "$(location :generate_registry_tables) --xml=$(location @spirv_headers//:spirv_xml_registry) --generator-output=$(location generators.inc)", cmd_bat = "$(location //:generate_registry_tables) --xml=$(location @spirv_headers//:spirv_xml_registry) --generator-output=$(location generators.inc)",
tools = [":generate_registry_tables"], exec_tools = [":generate_registry_tables"],
) )
py_binary( py_binary(
@ -103,103 +91,120 @@ py_binary(
) )
genrule( genrule(
name = "build_version_inc", name = "gen_build_version",
srcs = ["CHANGES"], srcs = ["CHANGES"],
outs = ["build-version.inc"], outs = ["build-version.inc"],
cmd = "SOURCE_DATE_EPOCH=0 $(location :update_build_version) $(location CHANGES) $(location build-version.inc)", cmd = "SOURCE_DATE_EPOCH=0 $(location update_build_version) $(location CHANGES) $(location build-version.inc)",
cmd_bat = "set SOURCE_DATE_EPOCH=0 && $(location :update_build_version) $(location CHANGES) $(location build-version.inc)", cmd_bat = "set SOURCE_DATE_EPOCH=0 && $(location //:update_build_version) $(location CHANGES) $(location build-version.inc)",
local = True, exec_tools = [":update_build_version"],
tools = [":update_build_version"],
) )
# Libraries # Libraries
cc_library( cc_library(
name = "spirv_tools", name = "generated_headers",
hdrs = [ hdrs = [
"include/spirv-tools/libspirv.h", ":gen_build_version",
"include/spirv-tools/libspirv.hpp",
],
copts = COMMON_COPTS,
includes = ["include"],
linkstatic = 1,
visibility = ["//visibility:public"],
deps = [
":spirv_tools_internal",
],
)
cc_library(
name = "spirv_tools_internal",
srcs = glob([
"source/*.cpp",
"source/util/*.cpp",
"source/val/*.cpp",
]) + [
":build_version_inc",
":gen_core_tables_unified1", ":gen_core_tables_unified1",
":gen_enum_string_mapping", ":gen_enum_string_mapping",
":gen_extinst_lang_headers_DebugInfo", ":gen_extinst_lang_headers_DebugInfo",
":gen_extinst_lang_headers_NonSemanticShaderDebugInfo100",
":gen_extinst_lang_headers_OpenCLDebugInfo100", ":gen_extinst_lang_headers_OpenCLDebugInfo100",
":gen_extinst_lang_headers_NonSemanticShaderDebugInfo100",
":gen_glsl_tables_unified1", ":gen_glsl_tables_unified1",
":gen_opencl_tables_unified1", ":gen_opencl_tables_unified1",
":gen_registry_tables",
":gen_vendor_tables_debuginfo", ":gen_vendor_tables_debuginfo",
":gen_vendor_tables_nonsemantic_clspvreflection", ":gen_vendor_tables_nonsemantic_clspvreflection",
":gen_vendor_tables_nonsemantic_shader_debuginfo_100",
":gen_vendor_tables_opencl_debuginfo_100", ":gen_vendor_tables_opencl_debuginfo_100",
":gen_vendor_tables_nonsemantic_shader_debuginfo_100",
":gen_vendor_tables_spv_amd_gcn_shader", ":gen_vendor_tables_spv_amd_gcn_shader",
":gen_vendor_tables_spv_amd_shader_ballot", ":gen_vendor_tables_spv_amd_shader_ballot",
":gen_vendor_tables_spv_amd_shader_explicit_vertex_parameter", ":gen_vendor_tables_spv_amd_shader_explicit_vertex_parameter",
":gen_vendor_tables_spv_amd_shader_trinary_minmax", ":gen_vendor_tables_spv_amd_shader_trinary_minmax",
":generators_inc",
], ],
hdrs = [ copts = COMMON_COPTS,
)
cc_library(
name = "spirv_tools_headers",
hdrs = glob([
"include/spirv-tools/libspirv.h", "include/spirv-tools/libspirv.h",
"include/spirv-tools/libspirv.hpp", "include/spirv-tools/libspirv.hpp",
":gen_extinst_lang_headers_DebugInfo",
":gen_extinst_lang_headers_NonSemanticShaderDebugInfo100",
":gen_extinst_lang_headers_OpenCLDebugInfo100",
] + glob([
"source/*.h", "source/*.h",
"source/util/*.h", "source/util/*.h",
"source/val/*.h", "source/val/*.h",
]), ]),
copts = COMMON_COPTS, copts = COMMON_COPTS,
includes = ["include"], includes = ["source"],
deps = [ deps = [
"@spirv_headers//:spirv_common_headers", "@spirv_headers//:spirv_c_headers",
"@spirv_headers//:spirv_cpp11_headers",
], ],
) )
cc_library(
name = "spirv_tools",
srcs = glob([
"source/*.cpp",
"source/util/*.cpp",
"source/val/*.cpp",
]),
hdrs = [
"include/spirv-tools/libspirv.h",
"include/spirv-tools/libspirv.hpp",
],
copts = COMMON_COPTS + select({
"@bazel_tools//src/conditions:windows": [""],
"//conditions:default": ["-Wno-implicit-fallthrough"],
}),
includes = ["include"],
linkstatic = 1,
visibility = ["//visibility:public"],
deps = [
":generated_headers",
":spirv_tools_headers",
"@spirv_headers//:spirv_c_headers",
"@spirv_headers//:spirv_common_headers",
],
)
cc_library(
name = "spirv_tools_comp",
srcs = glob([
"source/comp/*.cpp",
"source/comp/*.h",
]),
copts = COMMON_COPTS,
linkstatic = 1,
visibility = ["//visibility:public"],
deps = [
":generated_headers",
":spirv_tools",
":spirv_tools_headers",
"@spirv_headers//:spirv_common_headers",
],
)
cc_library(
name = "spirv_tools_opt_headers",
hdrs = glob(["source/opt/*.h"]),
copts = COMMON_COPTS,
)
cc_library( cc_library(
name = "spirv_tools_opt", name = "spirv_tools_opt",
srcs = glob(["source/opt/*.cpp"]),
hdrs = [ hdrs = [
"include/spirv-tools/instrument.hpp", "include/spirv-tools/instrument.hpp",
"include/spirv-tools/optimizer.hpp", "include/spirv-tools/optimizer.hpp",
], ],
copts = COMMON_COPTS, copts = COMMON_COPTS,
includes = ["include"],
linkstatic = 1, linkstatic = 1,
visibility = ["//visibility:public"], visibility = ["//visibility:public"],
deps = [ deps = [
":spirv_tools", ":spirv_tools",
":spirv_tools_opt_internal", ":spirv_tools_headers",
], ":spirv_tools_opt_headers",
)
cc_library(
name = "spirv_tools_opt_internal",
srcs = glob(["source/opt/*.cpp"]) + [
":gen_vendor_tables_spv_amd_shader_ballot",
],
hdrs = glob(["source/opt/*.h"]) + [
"include/spirv-tools/instrument.hpp",
"include/spirv-tools/optimizer.hpp",
],
copts = COMMON_COPTS,
deps = [
":spirv_tools_internal",
"@spirv_headers//:spirv_common_headers", "@spirv_headers//:spirv_common_headers",
], ],
) )
@ -209,9 +214,11 @@ cc_library(
srcs = glob(["source/reduce/*.cpp"]), srcs = glob(["source/reduce/*.cpp"]),
hdrs = glob(["source/reduce/*.h"]), hdrs = glob(["source/reduce/*.h"]),
copts = COMMON_COPTS, copts = COMMON_COPTS,
linkstatic = 1,
visibility = ["//visibility:public"],
deps = [ deps = [
":spirv_tools_internal", ":spirv_tools",
":spirv_tools_opt_internal", ":spirv_tools_opt",
], ],
) )
@ -223,38 +230,21 @@ cc_library(
linkstatic = 1, linkstatic = 1,
visibility = ["//visibility:public"], visibility = ["//visibility:public"],
deps = [ deps = [
":spirv_tools_internal", ":spirv_tools",
":spirv_tools_opt_internal", ":spirv_tools_opt",
],
)
cc_library(
name = "spirv_tools_lint_internal",
srcs = glob([
"source/lint/*.cpp",
"source/lint/*.h",
]),
hdrs = ["include/spirv-tools/linter.hpp"] + glob([
"source/lint/*.h",
]),
copts = COMMON_COPTS,
includes = ["include"],
deps = [
":spirv_tools_internal",
":spirv_tools_opt_internal",
], ],
) )
cc_library( cc_library(
name = "spirv_tools_lint", name = "spirv_tools_lint",
srcs = glob(["source/lint/*.cpp", "source/lint/*.h"]),
hdrs = ["include/spirv-tools/linter.hpp"], hdrs = ["include/spirv-tools/linter.hpp"],
copts = COMMON_COPTS, copts = COMMON_COPTS,
includes = ["include"],
linkstatic = 1, linkstatic = 1,
visibility = ["//visibility:public"], visibility = ["//visibility:public"],
deps = [ deps = [
":spirv_tools", ":spirv_tools",
":spirv_tools_lint_internal", ":spirv_tools_opt",
], ],
) )
@ -263,28 +253,23 @@ cc_library(
srcs = glob(["tools/util/*.cpp"]), srcs = glob(["tools/util/*.cpp"]),
hdrs = glob(["tools/util/*.h"]), hdrs = glob(["tools/util/*.h"]),
copts = COMMON_COPTS, copts = COMMON_COPTS,
linkstatic = 1,
visibility = ["//visibility:public"],
deps = [":spirv_tools"], deps = [":spirv_tools"],
) )
cc_library(
name = "tools_io",
hdrs = ["tools/io.h"],
copts = COMMON_COPTS,
)
# Tools # Tools
cc_binary( cc_binary(
name = "spirv-as", name = "spirv-as",
srcs = [ srcs = [
"tools/as/as.cpp", "tools/as/as.cpp",
"tools/io.h",
], ],
copts = COMMON_COPTS, copts = COMMON_COPTS,
visibility = ["//visibility:public"], visibility = ["//visibility:public"],
deps = [ deps = [
":spirv_tools_internal", ":spirv_tools",
":tools_io",
":tools_util",
], ],
) )
@ -292,44 +277,25 @@ cc_binary(
name = "spirv-dis", name = "spirv-dis",
srcs = [ srcs = [
"tools/dis/dis.cpp", "tools/dis/dis.cpp",
"tools/io.h",
], ],
copts = COMMON_COPTS, copts = COMMON_COPTS,
visibility = ["//visibility:public"], visibility = ["//visibility:public"],
deps = [ deps = [
":spirv_tools", ":spirv_tools",
":tools_io",
":tools_util",
],
)
cc_binary(
name = "spirv-objdump",
srcs = [
"tools/objdump/extract_source.cpp",
"tools/objdump/extract_source.h",
"tools/objdump/objdump.cpp",
],
copts = COMMON_COPTS,
visibility = ["//visibility:public"],
deps = [
":spirv_tools_internal",
":spirv_tools_opt_internal",
":tools_io",
":tools_util",
"@spirv_headers//:spirv_cpp_headers",
], ],
) )
cc_binary( cc_binary(
name = "spirv-val", name = "spirv-val",
srcs = [ srcs = [
"tools/io.h",
"tools/val/val.cpp", "tools/val/val.cpp",
], ],
copts = COMMON_COPTS, copts = COMMON_COPTS,
visibility = ["//visibility:public"], visibility = ["//visibility:public"],
deps = [ deps = [
":spirv_tools_internal", ":spirv_tools",
":tools_io",
":tools_util", ":tools_util",
], ],
) )
@ -337,14 +303,14 @@ cc_binary(
cc_binary( cc_binary(
name = "spirv-opt", name = "spirv-opt",
srcs = [ srcs = [
"tools/io.h",
"tools/opt/opt.cpp", "tools/opt/opt.cpp",
], ],
copts = COMMON_COPTS, copts = COMMON_COPTS,
visibility = ["//visibility:public"], visibility = ["//visibility:public"],
deps = [ deps = [
":spirv_tools_internal", ":spirv_tools",
":spirv_tools_opt_internal", ":spirv_tools_opt",
":tools_io",
":tools_util", ":tools_util",
], ],
) )
@ -352,15 +318,15 @@ cc_binary(
cc_binary( cc_binary(
name = "spirv-reduce", name = "spirv-reduce",
srcs = [ srcs = [
"tools/io.h",
"tools/reduce/reduce.cpp", "tools/reduce/reduce.cpp",
], ],
copts = COMMON_COPTS, copts = COMMON_COPTS,
visibility = ["//visibility:public"], visibility = ["//visibility:public"],
deps = [ deps = [
":spirv_tools_internal", ":spirv_tools",
":spirv_tools_opt_internal", ":spirv_tools_opt",
":spirv_tools_reduce", ":spirv_tools_reduce",
":tools_io",
":tools_util", ":tools_util",
], ],
) )
@ -368,29 +334,28 @@ cc_binary(
cc_binary( cc_binary(
name = "spirv-link", name = "spirv-link",
srcs = [ srcs = [
"tools/io.h",
"tools/link/linker.cpp", "tools/link/linker.cpp",
], ],
copts = COMMON_COPTS, copts = COMMON_COPTS,
visibility = ["//visibility:public"], visibility = ["//visibility:public"],
deps = [ deps = [
":spirv_tools_internal", ":spirv_tools",
":spirv_tools_link", ":spirv_tools_link",
":tools_io",
":tools_util",
], ],
) )
cc_binary( cc_binary(
name = "spirv-lint", name = "spirv-lint",
srcs = [ srcs = [
"tools/io.h",
"tools/lint/lint.cpp", "tools/lint/lint.cpp",
], ],
copts = COMMON_COPTS, copts = COMMON_COPTS,
visibility = ["//visibility:public"], visibility = ["//visibility:public"],
deps = [ deps = [
":spirv_tools",
":spirv_tools_lint", ":spirv_tools_lint",
":spirv_tools_opt_internal",
":tools_io",
":tools_util", ":tools_util",
], ],
) )
@ -401,143 +366,50 @@ cc_binary(
"tools/cfg/bin_to_dot.cpp", "tools/cfg/bin_to_dot.cpp",
"tools/cfg/bin_to_dot.h", "tools/cfg/bin_to_dot.h",
"tools/cfg/cfg.cpp", "tools/cfg/cfg.cpp",
"tools/io.h",
], ],
copts = COMMON_COPTS, copts = COMMON_COPTS,
visibility = ["//visibility:public"], visibility = ["//visibility:public"],
deps = [ deps = [":spirv_tools"],
":spirv_tools_internal",
":tools_io",
":tools_util",
],
) )
# Unit tests # Unit tests
cc_library( cc_library(
name = "test_lib", name = "test_common",
testonly = 1, testonly = 1,
srcs = [ srcs = [
"test/unit_spirv.cpp",
],
hdrs = [
"test/test_fixture.h", "test/test_fixture.h",
"test/unit_spirv.cpp",
"test/unit_spirv.h", "test/unit_spirv.h",
], ],
compatible_with = [],
copts = TEST_COPTS, copts = TEST_COPTS,
deps = [ includes = ["test"],
":spirv_tools_internal",
"@com_google_googletest//:gtest",
],
)
# PCH (precompiled header) tests only work when using CMake and MSVC on Windows,
# so they will be skipped in the Bazel builds.
[cc_test(
name = "base_{testcase}_test".format(testcase = f[len("test/"):-len("_test.cpp")]),
size = "small",
srcs = [f],
copts = TEST_COPTS + ["-DTESTING"],
linkstatic = 1,
target_compatible_with = {
"test/timer_test.cpp": incompatible_with(["@bazel_tools//src/conditions:windows"]),
}.get(f, []),
deps = [
"tools_util",
":spirv_tools_internal",
":test_lib",
"@com_google_googletest//:gtest",
"@com_google_googletest//:gtest_main",
],
) for f in glob(
[
"test/*_test.cpp",
"test/tools/*_test.cpp",
],
exclude = [
"test/cpp_interface_test.cpp",
"test/pch_test.cpp",
],
)]
cc_test(
name = "base_cpp_interface_test",
size = "small",
srcs = ["test/cpp_interface_test.cpp"],
linkstatic = 1,
deps = [
":spirv_tools_opt_internal",
"@com_google_googletest//:gtest",
"@com_google_googletest//:gtest_main",
"@spirv_headers//:spirv_cpp11_headers",
],
)
cc_test(
name = "base_ilist_test",
size = "small",
srcs = ["test/util/ilist_test.cpp"],
copts = TEST_COPTS,
linkstatic = 1,
deps = [
":spirv_tools_internal",
"@com_google_googletest//:gtest",
"@com_google_googletest//:gtest_main",
],
)
cc_library(
name = "link_test_lib",
testonly = 1,
hdrs = ["test/link/linker_fixture.h"],
copts = TEST_COPTS,
deps = [
":spirv_tools_internal",
":spirv_tools_link",
":test_lib",
"@com_google_effcee//:effcee",
"@com_googlesource_code_re2//:re2",
],
)
[cc_test(
name = "link_{testcase}_test".format(testcase = f[len("test/link/"):-len("_test.cpp")]),
size = "small",
srcs = [f],
copts = TEST_COPTS,
linkstatic = 1,
deps = [
":link_test_lib",
"@com_google_googletest//:gtest",
"@com_google_googletest//:gtest_main",
],
) for f in glob(
["test/link/*_test.cpp"],
)]
[cc_test(
name = "lint_{testcase}_test".format(testcase = f[len("test/lint/"):-len("_test.cpp")]),
size = "small",
srcs = [f],
copts = TEST_COPTS,
linkstatic = 1, linkstatic = 1,
deps = [ deps = [
":spirv_tools", ":spirv_tools",
":spirv_tools_lint_internal",
":spirv_tools_opt_internal",
"@com_google_googletest//:gtest", "@com_google_googletest//:gtest",
"@com_google_googletest//:gtest_main",
], ],
) for f in glob( )
["test/lint/*_test.cpp"],
)]
cc_library( cc_library(
name = "opt_test_lib", name = "link_test_common",
testonly = 1, testonly = 1,
srcs = [ srcs = ["test/link/linker_fixture.h"],
"test/opt/pass_utils.cpp", compatible_with = [],
copts = TEST_COPTS,
linkstatic = 1,
deps = [
":spirv_tools_link",
":test_common",
], ],
)
cc_library(
name = "opt_test_common",
testonly = 1,
srcs = ["test/opt/pass_utils.cpp"],
hdrs = [ hdrs = [
"test/opt/assembly_builder.h", "test/opt/assembly_builder.h",
"test/opt/function_utils.h", "test/opt/function_utils.h",
@ -545,181 +417,143 @@ cc_library(
"test/opt/pass_fixture.h", "test/opt/pass_fixture.h",
"test/opt/pass_utils.h", "test/opt/pass_utils.h",
], ],
compatible_with = [],
copts = TEST_COPTS, copts = TEST_COPTS,
linkstatic = 1,
deps = [ deps = [
":spirv_tools_internal", ":spirv_tools_opt",
":spirv_tools_opt_internal", ":test_common",
"@com_google_effcee//:effcee",
"@com_google_googletest//:gtest",
], ],
) )
[cc_test(
name = "opt_{testcase}_test".format(testcase = f[len("test/opt/"):-len("_test.cpp")]),
size = "small",
srcs = [f],
copts = TEST_COPTS,
linkstatic = 1,
deps = [
":opt_test_lib",
":spirv_tools_internal",
":spirv_tools_opt_internal",
":test_lib",
"@com_google_effcee//:effcee",
"@com_google_googletest//:gtest",
"@com_google_googletest//:gtest_main",
],
) for f in glob(["test/opt/*_test.cpp"])]
[cc_test(
name = "opt_dom_tree_{testcase}_test".format(testcase = f[len("test/opt/dominator_tree/"):-len(".cpp")]),
size = "small",
srcs = [f],
copts = TEST_COPTS,
linkstatic = 1,
deps = [
":opt_test_lib",
":spirv_tools_opt_internal",
"@com_google_googletest//:gtest",
"@com_google_googletest//:gtest_main",
],
) for f in glob(
["test/opt/dominator_tree/*.cpp"],
exclude = ["test/opt/dominator_tree/pch_test_opt_dom.cpp"],
)]
[cc_test(
name = "opt_loop_{testcase}_test".format(testcase = f[len("test/opt/loop_optimizations/"):-len(".cpp")]),
size = "small",
srcs = [f],
copts = TEST_COPTS,
linkstatic = 1,
deps = [
":opt_test_lib",
":spirv_tools",
":spirv_tools_opt_internal",
"@com_google_effcee//:effcee",
"@com_google_googletest//:gtest",
"@com_google_googletest//:gtest_main",
],
) for f in glob(
["test/opt/loop_optimizations/*.cpp"],
exclude = ["test/opt/loop_optimizations/pch_test_opt_loop.cpp"],
)]
cc_library( cc_library(
name = "reduce_test_lib", name = "reduce_test_common",
testonly = 1, testonly = 1,
srcs = [ srcs = [
"test/reduce/reduce_test_util.cpp", "test/reduce/reduce_test_util.cpp",
"tools/io.h",
], ],
hdrs = ["test/reduce/reduce_test_util.h"], hdrs = ["test/reduce/reduce_test_util.h"],
compatible_with = [],
copts = TEST_COPTS, copts = TEST_COPTS,
linkstatic = 1,
deps = [ deps = [
":spirv_tools",
":spirv_tools_opt_internal",
":spirv_tools_reduce", ":spirv_tools_reduce",
":test_lib", ":test_common",
":tools_io",
"@com_google_googletest//:gtest",
], ],
) )
[cc_test(
name = "reduce_{testcase}_test".format(testcase = f[len("test/reduce/"):-len("_test.cpp")]),
size = "small",
srcs = [f],
copts = TEST_COPTS,
linkstatic = 1,
deps = [
":reduce_test_lib",
":spirv_tools_internal",
":spirv_tools_opt_internal",
":spirv_tools_reduce",
"@com_google_googletest//:gtest_main",
],
) for f in glob(["test/reduce/*_test.cpp"])]
[cc_test(
name = "util_{testcase}_test".format(testcase = f[len("test/util/"):-len("_test.cpp")]),
size = "small",
srcs = [f],
copts = TEST_COPTS,
linkstatic = 1,
deps = [
":spirv_tools_internal",
"@com_google_googletest//:gtest",
"@com_google_googletest//:gtest_main",
],
) for f in glob(["test/util/*_test.cpp"])]
cc_library( cc_library(
name = "val_test_lib", name = "val_test_common",
testonly = 1, testonly = 1,
srcs = [ srcs = [
"test/val/val_code_generator.cpp", "test/val/val_code_generator.cpp",
"test/val/val_fixtures.h",
], ],
hdrs = [ hdrs = [
"test/val/val_code_generator.h", "test/val/val_code_generator.h",
"test/val/val_fixtures.h",
], ],
copts = TEST_COPTS, compatible_with = [],
deps = [
":spirv_tools_internal",
":test_lib",
],
)
[cc_test(
name = "val_{testcase}_test".format(testcase = f[len("test/val/val_"):-len("_test.cpp")]),
size = "small",
srcs = [f],
copts = TEST_COPTS, copts = TEST_COPTS,
linkstatic = 1, linkstatic = 1,
deps = [ deps = [":test_common"],
":spirv_tools_internal", )
":test_lib",
":val_test_lib", # PCH (precompiled header) tests only work when using CMake and MSVC on Windows,
"@com_google_googletest//:gtest", # so they will be skipped in the Bazel builds.
"@com_google_googletest//:gtest_main",
], [base_test(
name = f[5:-4], # strip test/, .cpp
srcs = [f],
) for f in glob( ) for f in glob(
["test/val/val_*_test.cpp"], ["test/*.cpp"],
exclude = [ exclude = [
"test/val/val_capability_test.cpp", "test/cpp_interface_test.cpp", # has its own base_test below.
"test/val/val_limits_test.cpp", "test/log_test.cpp", # has its own base_test below.
"test/pch_test.cpp", # pch tests are skipped.
"test/timer_test.cpp", # has its own base_test below.
], ],
)] )]
cc_test( # This test uses unistd.h and does not run on Windows.
name = "val_capability_test", base_test(
size = "large", name = "timer_test",
timeout = "long", srcs = select({
srcs = ["test/val/val_capability_test.cpp"], "@bazel_tools//src/conditions:windows": [],
copts = TEST_COPTS + ["-O3"], "//conditions:default": ["test/timer_test.cpp"],
linkstatic = 1, }),
deps = [
":spirv_tools_internal",
":test_lib",
":val_test_lib",
"@com_google_googletest//:gtest",
"@com_google_googletest//:gtest_main",
],
) )
cc_test( base_test(
name = "val_limits_test", name = "cpp_interface_test",
size = "large", srcs = ["test/cpp_interface_test.cpp"],
timeout = "long", deps = [":spirv_tools_opt"],
srcs = ["test/val/val_limits_test.cpp"],
copts = TEST_COPTS + [
"-O3",
],
linkstatic = 1,
deps = [
":test_lib",
":val_test_lib",
"@com_google_googletest//:gtest",
"@com_google_googletest//:gtest_main",
],
) )
base_test(
name = "log_test",
srcs = ["test/log_test.cpp"],
deps = [":spirv_tools_opt"],
)
[link_test(
name = f[10:-4], # strip test/link/, .cpp
srcs = [f],
) for f in glob(
["test/link/*.cpp"],
)]
[lint_test(
name = f[10:-4], # strip test/lint/, .cpp
srcs = [f],
) for f in glob(
["test/lint/*.cpp"],
)]
[opt_test(
name = f[9:-4], # strip test/opt/, .cpp
srcs = [f],
) for f in glob(
["test/opt/*.cpp"],
# pch tests are skipped.
exclude = ["test/opt/pch_test_opt.cpp"],
)]
[opt_test(
name = "dom_tree_" + f[24:-4], # strip test/opt/dominator_tree/, .cpp
srcs = [f],
) for f in glob(
["test/opt/dominator_tree/*.cpp"],
# pch tests are skipped.
exclude = ["test/opt/dominator_tree/pch_test_opt_dom.cpp"],
)]
[opt_test(
name = "loop_" + f[28:-4], # strip test/opt/loop_optimizations/, .cpp
srcs = [f],
) for f in glob(
["test/opt/loop_optimizations/*.cpp"],
# pch tests are skipped.
exclude = ["test/opt/loop_optimizations/pch_test_opt_loop.cpp"],
)]
[reduce_test(
name = f[12:-4], # strip test/reduce/, .cpp
srcs = [f],
) for f in glob(["test/reduce/*.cpp"])]
[util_test(
name = f[10:-4], # strip test/util/, .cpp
srcs = [f],
) for f in glob(["test/util/*.cpp"])]
[val_test(
name = f[9:-4], # strip test/val/, .cpp
srcs = [f],
) for f in glob(
["test/val/*.cpp"],
exclude = [
"test/val/pch_test_val.cpp", # pch tests are skipped.
],
)]

1024
BUILD.gn

File diff suppressed because it is too large Load Diff

145
CHANGES
View File

@ -1,150 +1,5 @@
Revision history for SPIRV-Tools Revision history for SPIRV-Tools
v2023.6 2023-12-18
- General
- update_build_version.py produce deterministic header. (#5426)
- Support missing git in update_build_version.py (#5473)
- Optimizer
- Add ComputeDerivativeGroup*NV capabilities to trim capabilities pass. (#5430)
- Do not crash when tryingto fold unsupported spec constant (#5496)
- instrument: Fix handling of gl_InvocationID (#5493)
- Fix nullptr argument in MarkInsertChain (#5465)
- opt: support 64-bit OpAccessChain index in FixStorageClass (#5446)
- opt: add StorageImageReadWithoutFormat to cap trim (#5475)
- opt: add PhysicalStorageBufferAddresses to trim (#5476)
- Fix array size calculation (#5463
- Validator
- spirv-val: Loosen restriction on base type of DebugTypePointer and DebugTypeQualifier (#5479)
- spirv-val: Add WorkgroupMemoryExplicitLayoutKHR check for Block (#5461)
v2023.5 2023-10-15
- General
- Support 2 Intel extensions (#5357)
- SPV_QCOM_image_processing support (#5223)
- Optimizer
- opt: fix StorageInputOutput16 trimming. (#5359)
- opt: add StoragePushConstant16 to trim pass (#5366)
- opt: enable StorageUniform16 (#5371)
- opt: add bitmask support for capability trimming (#5372)
- opt: Add SwitchDescriptorSetPass (#5375)
- opt: add FragmentShader*InterlockEXT to capability trim pass (#5390)
- opt: add Int64 capability to trim pass (#5398)
- opt: add Float64 capability to trim pass (#5428)
- opt: add raytracing/rayquery to trim pass (#5397)
- opt: add ImageMSArray capability to trim pass. (#5395)
- Add SPV_KHR_physical_storage_buffer to allowlists (#5402)
- Add SPV_EXT_fragment_shader_interlock to allow lists (#5393)
- Make sure that fragment shader interlock instructions are not removed by DCE (#5400)
- instrument: Use Import linkage for instrumentation functions (#5355)
- Add a new legalization pass to dedupe invocation interlock instructions (#5409)
- instrument: Ensure linking works even of nothing is changed (#5419)
- Validator
- Move token version/cap/ext checks from parsing to validation (#5370)
- val: re-add ImageMSArray validation (#5394)
- Linker
- linker: Add --use-highest-version option
v2023.4 2023-07-17
- General
- Set cmake_policy CMP0128 (#5341)
- Add python3 requirement for the script (#5326)
- Add support for LiteralFloat type (#5323)
- SPV_KHR_cooperative_matrix (#5286)
- Allow OpTypeBool in UniformConstant (#5237)
- Allow physical storage buffer pointer in IO (#5251)
- Remove const zero image operands (#5232)
- Optimizer
- Enable vector constant folding (#4913) (#5272)
- Fold negation of integer vectors (#5269)
- Add folding rule for OpTranspose (#5241)
- Add SPV_NV_bindless_texture to spirv optimizations (#5231)
- Fix incorrect half float conversion (#5349)
- Add SPV_EXT_shader_atomic_float_add to allow lists (#5348)
- Instrument
- instrument: Cast gl_VertexIndex and InstanceIndex to uint (#5319)
- instrument: Fix buffer address length calculations (#5257)
- instrument: Reduce number of inst_bindless_stream_write_6 calls (#5327)
- Validator
- Validate GroupNonUniform instructions (#5296)
- spirv-val: Label SPV_KHR_cooperative_matrix VUID (#5301)
- Validate layouts for PhysicalStorageBuffer pointers (#5291)
- spirv-val: Remove VUID from 1.3.251 spec (#5244)
- Diff
- spirv-diff: Update test expectations (#5264)
- spirv-diff: Leave undefined ids unpaired. (#5262)
- spirv-diff: Properly match SPV_KHR_ray_query types. (#5259)
- diff: Don't give up entry point matching too early. (#5224)
v2023.3 2023-05-15
- General
- Update spirv_headers to include SPV_KHR_ray_tracing_position_fetch (#5205)
- spirv-tools: Add support for QNX (#5211)
- build: set std=c++17 for BUILD.gn (#5162)
- Optimizer
- Run ADCE when the printf extension is used. (#5215)
- Don't convert struct members to half (#5201)
- Apply scalar replacement on vars with Pointer decorations (#5208)
- opt: Fix null deref in OpMatrixTimesVector and OpVectorTimesMatrix (#5199)
- instrument: Add set and binding to bindless error records (#5204)
- instrument: Change descriptor state storage format (#5178)
- Fix LICMPass (#5087)
- Add Vulkan memory model to allow lists (#5173)
- Do not remove control barrier after spv1.3 (#5174)
- Validator
- spirv-val: Label Interface Location/Component VUIDs (#5221)
- Add support for SPV_EXT_shader_tile_image (#5188)
- Fix vector OpConstantComposite type validation (#5191)
- spirv-val: Label new Vulkan VUID 07951 (#5154)
- Fuzz
- Do not define GOOGLE_PROTOBUF_INTERNAL_DONATE_STEAL_INLINE if it is already defined. (#5200)
v2023.2 2023-03-10
- General
- build: move from c++11 to c++17 (#4983)
- tools: refactorize tools flags parsing. (#5111)
- Add C interface for Optimizer (#5030)
- libspirv.cpp: adds c++ api for spvBinaryParse (#5109)
- build: change the way we set cxx version for bazel. (#5114)
- Optimizer
- Fix null pointer in FoldInsertWithConstants. (#5093)
- Fix removal of dependent non-semantic instructions (#5122)
- Remove duplicate lists of constant and type opcodes (#5106)
- opt: fix spirv ABI on Linux again. (#5113)
- Validator
- Validate decoration of structs with RuntimeArray (#5094)
- Validate operand type before operating on it (#5092)
- spirv-val: Conditional Branch without an exit is invalid in loop header (#5069)
- spirv-val: Initial SPV_EXT_mesh_shader builtins (#5080)
v2023.1 2023-01-17
- General
- Renamed "master" to "main" (issue#5051)
- Validate version 5 of clspv reflection (#5050)
- Remove testing support for VS2015 (#5027)
- Fix undef behaviour in hex float parsing (#5025)
- Require C++11 *or later* (#5020)
- Instrument
- Instrument: Fix bindless checking for BufferDeviceAddress (#5049)
- Optimizer
- Optimize allocation of spvtools::opt::Instruction::operands_ (#5024)
- spirv-opt: Fix OpCompositeInsert with Null Constant (#5008)
- spirv-opt: Handle null CompositeInsert (#4998)
- Add option to ADCE to remove output variables from interface. (#4994)
- Add support for tesc, tese and geom to EliminateDead*Components (#4990)
- Add pass to eliminate dead output components (#4982)
- spirv-opt: Add const folding for CompositeInsert (#4943)
- Add passes to eliminate dead output stores (#4970)
- Prevent eliminating case constructs in block merging (#4976)
- Validator
- Fix layout validation (#5015)
- Fix use of invalid analysis (#5013)
- Fix infinite loop in validator (#5006)
- Add validation support for SPV_NV_shader_invocation_reorder. (#4979)
- Only validate full layout in Vulkan environments (#4972)
- spirv-val: Label new Vulkan OpPtrAccessChain VUs (#4975)
- spirv-val: Add OpPtrAccessChain Base checks (#4965)
v2022.4 2022-10-12 v2022.4 2022-10-12
- General - General
- Support Narrow Types in BitCast Folding Rule (#4941) - Support Narrow Types in BitCast Folding Rule (#4941)

View File

@ -1,4 +1,4 @@
# Copyright (c) 2015-2023 The Khronos Group Inc. # Copyright (c) 2015-2016 The Khronos Group Inc.
# #
# Licensed under the Apache License, Version 2.0 (the "License"); # Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License. # you may not use this file except in compliance with the License.
@ -12,38 +12,26 @@
# See the License for the specific language governing permissions and # See the License for the specific language governing permissions and
# limitations under the License. # limitations under the License.
cmake_minimum_required(VERSION 3.17.2) cmake_minimum_required(VERSION 2.8.12)
if (POLICY CMP0048)
project(spirv-tools) cmake_policy(SET CMP0048 NEW)
endif()
# Avoid a bug in CMake 3.22.1. By default it will set -std=c++11 for if (POLICY CMP0054)
# targets in test/*, when those tests need -std=c++17. # Avoid dereferencing variables or interpret keywords that have been
# https://github.com/KhronosGroup/SPIRV-Tools/issues/5340 # quoted or bracketed.
# The bug is fixed in CMake 3.22.2 # https://cmake.org/cmake/help/v3.1/policy/CMP0054.html
if (${CMAKE_VERSION} VERSION_GREATER_EQUAL "3.22.1") cmake_policy(SET CMP0054 NEW)
if (${CMAKE_VERSION} VERSION_LESS "3.22.2")
cmake_policy(SET CMP0128 NEW)
endif()
endif() endif()
set_property(GLOBAL PROPERTY USE_FOLDERS ON) set_property(GLOBAL PROPERTY USE_FOLDERS ON)
project(spirv-tools)
enable_testing() enable_testing()
set(SPIRV_TOOLS "SPIRV-Tools") set(SPIRV_TOOLS "SPIRV-Tools")
include(GNUInstallDirs) include(GNUInstallDirs)
set(CMAKE_POSITION_INDEPENDENT_CODE ON) set(CMAKE_POSITION_INDEPENDENT_CODE ON)
set(CMAKE_CXX_STANDARD 11)
# Require at least C++17
if(NOT CMAKE_CXX_STANDARD)
set(CMAKE_CXX_STANDARD 17)
endif()
if(${CMAKE_CXX_STANDARD} LESS 17)
message(FATAL_ERROR "SPIRV-Tools requires C++17 or later, but is configured for C++${CMAKE_CXX_STANDARD})")
endif()
set(CMAKE_CXX_EXTENSIONS OFF)
option(ENABLE_RTTI "Enables RTTI" OFF) option(ENABLE_RTTI "Enables RTTI" OFF)
option(SPIRV_ALLOW_TIMERS "Allow timers via clock_gettime on supported platforms" ON) option(SPIRV_ALLOW_TIMERS "Allow timers via clock_gettime on supported platforms" ON)
@ -63,8 +51,6 @@ elseif("${CMAKE_SYSTEM_NAME}" STREQUAL "iOS")
add_definitions(-DSPIRV_IOS) add_definitions(-DSPIRV_IOS)
elseif("${CMAKE_SYSTEM_NAME}" STREQUAL "tvOS") elseif("${CMAKE_SYSTEM_NAME}" STREQUAL "tvOS")
add_definitions(-DSPIRV_TVOS) add_definitions(-DSPIRV_TVOS)
elseif("${CMAKE_SYSTEM_NAME}" STREQUAL "visionOS")
add_definitions(-DSPIRV_VISIONOS)
elseif("${CMAKE_SYSTEM_NAME}" STREQUAL "Android") elseif("${CMAKE_SYSTEM_NAME}" STREQUAL "Android")
add_definitions(-DSPIRV_ANDROID) add_definitions(-DSPIRV_ANDROID)
set(SPIRV_TIMER_ENABLED ${SPIRV_ALLOW_TIMERS}) set(SPIRV_TIMER_ENABLED ${SPIRV_ALLOW_TIMERS})
@ -76,8 +62,6 @@ elseif("${CMAKE_SYSTEM_NAME}" STREQUAL "Fuchsia")
add_definitions(-DSPIRV_FUCHSIA) add_definitions(-DSPIRV_FUCHSIA)
elseif("${CMAKE_SYSTEM_NAME}" STREQUAL "GNU") elseif("${CMAKE_SYSTEM_NAME}" STREQUAL "GNU")
add_definitions(-DSPIRV_GNU) add_definitions(-DSPIRV_GNU)
elseif("${CMAKE_SYSTEM_NAME}" STREQUAL "QNX")
add_definitions(-DSPIRV_QNX)
else() else()
message(FATAL_ERROR "Your platform '${CMAKE_SYSTEM_NAME}' is not supported!") message(FATAL_ERROR "Your platform '${CMAKE_SYSTEM_NAME}' is not supported!")
endif() endif()
@ -204,9 +188,10 @@ function(spvtools_default_compile_options TARGET)
target_compile_options(${TARGET} PRIVATE ${SPIRV_WARNINGS}) target_compile_options(${TARGET} PRIVATE ${SPIRV_WARNINGS})
if (${COMPILER_IS_LIKE_GNU}) if (${COMPILER_IS_LIKE_GNU})
target_compile_options(${TARGET} PRIVATE -std=c++11 -fno-exceptions)
target_compile_options(${TARGET} PRIVATE target_compile_options(${TARGET} PRIVATE
-Wall -Wextra -Wno-long-long -Wshadow -Wundef -Wconversion -Wall -Wextra -Wno-long-long -Wshadow -Wundef -Wconversion
-Wno-sign-conversion -fno-exceptions) -Wno-sign-conversion)
if(NOT ENABLE_RTTI) if(NOT ENABLE_RTTI)
add_compile_options(-fno-rtti) add_compile_options(-fno-rtti)
@ -215,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" OR "${CMAKE_CXX_COMPILER_ID}" STREQUAL "AppleClang") if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang")
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 "")
@ -243,7 +228,7 @@ function(spvtools_default_compile_options TARGET)
# For MinGW cross compile, statically link to the C++ runtime. # For MinGW cross compile, statically link to the C++ runtime.
# But it still depends on MSVCRT.dll. # But it still depends on MSVCRT.dll.
if (${CMAKE_SYSTEM_NAME} MATCHES "Windows") if (${CMAKE_SYSTEM_NAME} MATCHES "Windows")
if (NOT MSVC) if (${CMAKE_CXX_COMPILER_ID} MATCHES "GNU")
set_target_properties(${TARGET} PROPERTIES set_target_properties(${TARGET} PROPERTIES
LINK_FLAGS -static -static-libgcc -static-libstdc++) LINK_FLAGS -static -static-libgcc -static-libstdc++)
endif() endif()
@ -262,7 +247,7 @@ if(NOT COMMAND find_host_program)
endif() endif()
# Tests require Python3 # Tests require Python3
find_host_package(Python3 REQUIRED) find_host_package(PythonInterp 3 REQUIRED)
# Check for symbol exports on Linux. # Check for symbol exports on Linux.
# At the moment, this check will fail on the OSX build machines for the Android NDK. # At the moment, this check will fail on the OSX build machines for the Android NDK.
@ -271,7 +256,7 @@ if("${CMAKE_SYSTEM_NAME}" STREQUAL "Linux")
macro(spvtools_check_symbol_exports TARGET) macro(spvtools_check_symbol_exports TARGET)
if (NOT "${SPIRV_SKIP_TESTS}") if (NOT "${SPIRV_SKIP_TESTS}")
add_test(NAME spirv-tools-symbol-exports-${TARGET} add_test(NAME spirv-tools-symbol-exports-${TARGET}
COMMAND Python3::Interpreter COMMAND ${PYTHON_EXECUTABLE}
${spirv-tools_SOURCE_DIR}/utils/check_symbol_exports.py "$<TARGET_FILE:${TARGET}>") ${spirv-tools_SOURCE_DIR}/utils/check_symbol_exports.py "$<TARGET_FILE:${TARGET}>")
endif() endif()
endmacro() endmacro()
@ -284,7 +269,7 @@ else()
endif() endif()
if(ENABLE_SPIRV_TOOLS_INSTALL) if(ENABLE_SPIRV_TOOLS_INSTALL)
if(WIN32 AND NOT MINGW) if(WIN32)
macro(spvtools_config_package_dir TARGET PATH) macro(spvtools_config_package_dir TARGET PATH)
set(${PATH} ${TARGET}/cmake) set(${PATH} ${TARGET}/cmake)
endmacro() endmacro()
@ -304,23 +289,15 @@ if(ENABLE_SPIRV_TOOLS_INSTALL)
endmacro() endmacro()
endif() endif()
# Currently iOS and Android are very similar. # Defaults to OFF if the user didn't set it.
# They both have their own packaging (APP/APK). option(SPIRV_SKIP_EXECUTABLES
# Which makes regular executables/testing problematic. "Skip building the executable and tests along with the library"
# ${SPIRV_SKIP_EXECUTABLES})
# Currently the only deliverables for these platforms are option(SPIRV_SKIP_TESTS
# libraries (either STATIC or SHARED). "Skip building tests along with the library" ${SPIRV_SKIP_TESTS})
# if ("${SPIRV_SKIP_EXECUTABLES}")
# Furthermore testing is equally problematic.
if (IOS OR ANDROID)
set(SPIRV_SKIP_EXECUTABLES ON)
endif()
option(SPIRV_SKIP_EXECUTABLES "Skip building the executable and tests along with the library")
if (SPIRV_SKIP_EXECUTABLES)
set(SPIRV_SKIP_TESTS ON) set(SPIRV_SKIP_TESTS ON)
endif() endif()
option(SPIRV_SKIP_TESTS "Skip building tests along with the library")
# Defaults to ON. The checks can be time consuming. # Defaults to ON. The checks can be time consuming.
# Turn off if they take too long. # Turn off if they take too long.
@ -378,7 +355,7 @@ endif(ENABLE_SPIRV_TOOLS_INSTALL)
if (NOT "${SPIRV_SKIP_TESTS}") if (NOT "${SPIRV_SKIP_TESTS}")
add_test(NAME spirv-tools-copyrights add_test(NAME spirv-tools-copyrights
COMMAND Python3::Interpreter utils/check_copyright.py COMMAND ${PYTHON_EXECUTABLE} utils/check_copyright.py
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}) WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR})
endif() endif()

View File

@ -2,8 +2,9 @@
## For users: Reporting bugs and requesting features ## For users: Reporting bugs and requesting features
We organize known future work in GitHub projects. See We organize known future work in GitHub projects. See [Tracking SPIRV-Tools work
[Tracking SPIRV-Tools work with GitHub projects](https://github.com/KhronosGroup/SPIRV-Tools/blob/main/docs/projects.md) with GitHub
projects](https://github.com/KhronosGroup/SPIRV-Tools/blob/master/docs/projects.md)
for more. for more.
To report a new bug or request a new feature, please file a GitHub issue. Please To report a new bug or request a new feature, please file a GitHub issue. Please
@ -35,9 +36,9 @@ create a new issue, as with bugs. In the issue provide
## For developers: Contributing a patch ## For developers: Contributing a patch
Before we can use your code, you must sign the Before we can use your code, you must sign the [Khronos Open Source Contributor
[Khronos Open Source Contributor License Agreement](https://cla-assistant.io/KhronosGroup/SPIRV-Tools) License Agreement](https://cla-assistant.io/KhronosGroup/SPIRV-Tools) (CLA),
(CLA), which you can do online. The CLA is necessary mainly because you own the which you can do online. The CLA is necessary mainly because you own the
copyright to your changes, even after your contribution becomes part of our copyright to your changes, even after your contribution becomes part of our
codebase, so we need your permission to use and distribute your code. We also codebase, so we need your permission to use and distribute your code. We also
need to be sure of various other things -- for instance that you'll tell us if need to be sure of various other things -- for instance that you'll tell us if
@ -46,20 +47,20 @@ sign the CLA until after you've submitted your code for review and a member has
approved it, but you must do it before we can put your code into our codebase. approved it, but you must do it before we can put your code into our codebase.
See See
[README.md](https://github.com/KhronosGroup/SPIRV-Tools/blob/main/README.md) [README.md](https://github.com/KhronosGroup/SPIRV-Tools/blob/master/README.md)
for instruction on how to get, build, and test the source. Once you have made for instruction on how to get, build, and test the source. Once you have made
your changes: your changes:
* Ensure the code follows the * Ensure the code follows the [Google C++ Style
[Google C++ Style Guide](https://google.github.io/styleguide/cppguide.html). Guide](https://google.github.io/styleguide/cppguide.html). Running
Running `clang-format -style=file -i [modified-files]` can help. `clang-format -style=file -i [modified-files]` can help.
* Create a pull request (PR) with your patch. * Create a pull request (PR) with your patch.
* Make sure the PR description clearly identified the problem, explains the * Make sure the PR description clearly identified the problem, explains the
solution, and references the issue if applicable. solution, and references the issue if applicable.
* If your patch completely fixes bug 1234, the commit message should say * If your patch completely fixes bug 1234, the commit message should say
`Fixes https://github.com/KhronosGroup/SPIRV-Tools/issues/1234` When you do `Fixes https://github.com/KhronosGroup/SPIRV-Tools/issues/1234`
this, the issue will be closed automatically when the commit goes into When you do this, the issue will be closed automatically when the commit
main. Also, this helps us update the [CHANGES](CHANGES) file. goes into master. Also, this helps us update the [CHANGES](CHANGES) file.
* Watch the continuous builds to make sure they pass. * Watch the continuous builds to make sure they pass.
* Request a code review. * Request a code review.
@ -81,8 +82,8 @@ Instructions for this are given below.
The formal code reviews are done on GitHub. Reviewers are to look for all of the The formal code reviews are done on GitHub. Reviewers are to look for all of the
usual things: usual things:
* Coding style follows the * Coding style follows the [Google C++ Style
[Google C++ Style Guide](https://google.github.io/styleguide/cppguide.html) Guide](https://google.github.io/styleguide/cppguide.html)
* Identify potential functional problems. * Identify potential functional problems.
* Identify code duplication. * Identify code duplication.
* Ensure the unit tests have enough coverage. * Ensure the unit tests have enough coverage.
@ -101,49 +102,84 @@ should pay particular attention to:
updated. For example, a new instruction is added, but the def-use manager is updated. For example, a new instruction is added, but the def-use manager is
not updated. Later on, it is possible that the def-use manager will be used, not updated. Later on, it is possible that the def-use manager will be used,
and give wrong results. and give wrong results.
* If a pass gets the id of a type from the type manager, make sure the type is
not a struct or array. It there are two structs that look the same, the type
manager can return the wrong one.
## For maintainers: Merging a PR ## For maintainers: Merging a PR
We intend to maintain a linear history on the GitHub main branch, and the We intend to maintain a linear history on the GitHub master branch, and the
build and its tests should pass at each commit in that history. A linear build and its tests should pass at each commit in that history. A linear
always-working history is easier to understand and to bisect in case we want to always-working history is easier to understand and to bisect in case we want to
find which commit introduced a bug. The find which commit introduced a bug.
[Squash and Merge](https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/incorporating-changes-from-a-pull-request/about-pull-request-merges#squash-and-merge-your-commits)
button on the GitHub web interface. All other ways of merging on the web
interface have been disabled.
Before merging, we generally require: ### Initial merge setup
1. All tests except for the smoke test pass. See The following steps should be done exactly once (when you are about to merge a
[failing smoke test](#failing-smoke-test). PR for the first time):
1. The PR is approved by at least one of the maintainers. If the PR modifies
different parts of the code, then multiple reviewers might be necessary.
The squash-and-merge button will turn green when these requirements are met. * It is assumed that upstream points to
Maintainers have the to power to merge even if the button is not green, but that [git@github.com](mailto:git@github.com):KhronosGroup/SPIRV-Tools.git or
is discouraged. https://github.com/KhronosGroup/SPIRV-Tools.git.
### Failing smoke test * Find out the local name for the main github repo in your git configuration.
For example, in this configuration, it is labeled `upstream`.
The purpose of the smoke test is to let us know if ```
[shaderc](https://github.com/google/shaderc) fails to build with the change. If git remote -v
it fails, the maintainer needs to determine if the reason for the failure is a [ ... ]
problem in the current PR or if another repository needs to be changed. Most of upstream https://github.com/KhronosGroup/SPIRV-Tools.git (fetch)
the time [Glslang](https://github.com/KhronosGroup/glslang) needs to be updated upstream https://github.com/KhronosGroup/SPIRV-Tools.git (push)
to account for the change in SPIR-V Tools. ```
The PR can still be merged if the problem is not with that PR. * Make sure that the `upstream` remote is set to fetch from the `refs/pull`
namespace:
## For maintainers: Running tests ```
git config --get-all remote.upstream.fetch
+refs/heads/*:refs/remotes/upstream/*
+refs/pull/*/head:refs/remotes/upstream/pr/*
```
For security reasons, not all tests will run automatically. When they do not, a * If the line `+refs/pull/*/head:refs/remotes/upstream/pr/*` is not present in
maintainer will have to start the tests. your configuration, you can add it with the command:
If the Github actions tests do not run on a PR, they can be initiated by closing ```
and reopening the PR. git config --local --add remote.upstream.fetch '+refs/pull/*/head:refs/remotes/upstream/pr/*'
```
If the kokoro tests are not run, they can be run by adding the label ### Merge workflow
`kokoro:run` to the PR.
The following steps should be done for every PR that you intend to merge:
* Make sure your local copy of the master branch is up to date:
```
git checkout master
git pull
```
* Fetch all pull requests refs:
```
git fetch upstream
```
* Checkout the particular pull request you are going to review:
```
git checkout pr/1048
```
* Rebase the PR on top of the master branch. If there are conflicts, send it
back to the author and ask them to rebase. During the interactive rebase be
sure to squash all of the commits down to a single commit.
```
git rebase -i master
```
* **Build and test the PR.**
* If all of the tests pass, push the commit `git push upstream HEAD:master`
* Close the PR and add a comment saying it was push using the commit that you
just pushed. See https://github.com/KhronosGroup/SPIRV-Tools/pull/935 as an
example.

21
DEPS
View File

@ -3,32 +3,19 @@ use_relative_paths = True
vars = { vars = {
'github': 'https://github.com', 'github': 'https://github.com',
'abseil_revision': '79ca5d7aad63973c83a4962a66ab07cd623131ea', 'effcee_revision': '35912e1b7778ec2ddcff7e7188177761539e59e0',
'googletest_revision': 'd9bb8412d60b993365abb53f00b6dad9b2c01b62',
'effcee_revision': '19b4aa87af25cb4ee779a071409732f34bfc305c', 're2_revision': 'd2836d1b1c34c4e330a85a1006201db474bf2c8a',
'spirv_headers_revision': '85a1ed200d50660786c1a88d9166e871123cce39',
'googletest_revision': 'b10fad38c4026a29ea6561ab15fc4818170d1c10',
# Use protobufs before they gained the dependency on abseil
'protobuf_revision': 'v21.12',
're2_revision': '7e0c1a9e2417e70e5f0efc323267ac71d1fa0685',
'spirv_headers_revision': '1c6bb2743599e6eb6f37b2969acc0aef812e32e3',
} }
deps = { deps = {
'external/abseil_cpp':
Var('github') + '/abseil/abseil-cpp.git@' + Var('abseil_revision'),
'external/effcee': 'external/effcee':
Var('github') + '/google/effcee.git@' + Var('effcee_revision'), Var('github') + '/google/effcee.git@' + Var('effcee_revision'),
'external/googletest': 'external/googletest':
Var('github') + '/google/googletest.git@' + Var('googletest_revision'), Var('github') + '/google/googletest.git@' + Var('googletest_revision'),
'external/protobuf':
Var('github') + '/protocolbuffers/protobuf.git@' + Var('protobuf_revision'),
'external/re2': 'external/re2':
Var('github') + '/google/re2.git@' + Var('re2_revision'), Var('github') + '/google/re2.git@' + Var('re2_revision'),

0
OAT.xml Executable file → Normal file
View File

View File

@ -18,8 +18,6 @@ See http://dev.chromium.org/developers/how-tos/depottools/presubmit-scripts
for more details about the presubmit API built into depot_tools. for more details about the presubmit API built into depot_tools.
""" """
USE_PYTHON3 = True
LINT_FILTERS = [ LINT_FILTERS = [
"-build/storage_class", "-build/storage_class",
"-readability/casting", "-readability/casting",

2
README.OpenSource Executable file → Normal file
View File

@ -3,7 +3,7 @@
"Name": "spirv-tools", "Name": "spirv-tools",
"License": "Apache-2.0", "License": "Apache-2.0",
"License File": "LICENSE", "License File": "LICENSE",
"Version Number": "sdk-1.3.275.0", "Version Number": "v2022.4",
"Owner": "zhangleiyu1@huawei.com", "Owner": "zhangleiyu1@huawei.com",
"Upstream URL": "https://github.com/KhronosGroup/SPIRV-Tools.git", "Upstream URL": "https://github.com/KhronosGroup/SPIRV-Tools.git",
"Description": "The SPIR-V Tools project provides an API and commands for processing SPIR-V modules." "Description": "The SPIR-V Tools project provides an API and commands for processing SPIR-V modules."

View File

@ -1,7 +1,4 @@
# SPIR-V Tools # SPIR-V Tools
[![OpenSSF Scorecard](https://api.securityscorecards.dev/projects/github.com/KhronosGroup/SPIRV-Tools/badge)](https://securityscorecards.dev/viewer/?uri=github.com/KhronosGroup/SPIRV-Tools)
NEWS 2023-01-11: Development occurs on the `main` branch.
## Overview ## Overview
@ -26,7 +23,7 @@ headers, and XML registry.
<img alt="Linux" src="kokoro/img/linux.png" width="20px" height="20px" hspace="2px"/>[![Linux Build Status](https://storage.googleapis.com/spirv-tools/badges/build_status_linux_clang_release.svg)](https://storage.googleapis.com/spirv-tools/badges/build_link_linux_clang_release.html) <img alt="Linux" src="kokoro/img/linux.png" width="20px" height="20px" hspace="2px"/>[![Linux Build Status](https://storage.googleapis.com/spirv-tools/badges/build_status_linux_clang_release.svg)](https://storage.googleapis.com/spirv-tools/badges/build_link_linux_clang_release.html)
<img alt="MacOS" src="kokoro/img/macos.png" width="20px" height="20px" hspace="2px"/>[![MacOS Build Status](https://storage.googleapis.com/spirv-tools/badges/build_status_macos_clang_release.svg)](https://storage.googleapis.com/spirv-tools/badges/build_link_macos_clang_release.html) <img alt="MacOS" src="kokoro/img/macos.png" width="20px" height="20px" hspace="2px"/>[![MacOS Build Status](https://storage.googleapis.com/spirv-tools/badges/build_status_macos_clang_release.svg)](https://storage.googleapis.com/spirv-tools/badges/build_link_macos_clang_release.html)
<img alt="Windows" src="kokoro/img/windows.png" width="20px" height="20px" hspace="2px"/>[![Windows Build Status](https://storage.googleapis.com/spirv-tools/badges/build_status_windows_release.svg)](https://storage.googleapis.com/spirv-tools/badges/build_link_windows_vs2019_release.html) <img alt="Windows" src="kokoro/img/windows.png" width="20px" height="20px" hspace="2px"/>[![Windows Build Status](https://storage.googleapis.com/spirv-tools/badges/build_status_windows_release.svg)](https://storage.googleapis.com/spirv-tools/badges/build_link_windows_vs2017_release.html)
[More downloads](docs/downloads.md) [More downloads](docs/downloads.md)
@ -99,10 +96,10 @@ and in-progress work.
*Note*: The validator checks some Universal Limits, from section 2.17 of the SPIR-V spec. *Note*: The validator checks some Universal Limits, from section 2.17 of the SPIR-V spec.
The validator will fail on a module that exceeds those minimum upper bound limits. The validator will fail on a module that exceeds those minimum upper bound limits.
The validator has been parameterized to allow larger values, for use when targeting It is [future work](https://github.com/KhronosGroup/SPIRV-Tools/projects/1#card-1052403)
a more-than-minimally-capable SPIR-V consumer. to parameterize the validator to allow larger
limits accepted by a more than minimally capable SPIR-V consumer.
See [`tools/val/val.cpp`](tools/val/val.cpp) or run `spirv-val --help` for the command-line help.
### Optimizer ### Optimizer
@ -274,7 +271,7 @@ Contributions via merge request are welcome. Changes should:
`clang-format version 5.0.0` for SPIRV-Tools. Settings are defined by `clang-format version 5.0.0` for SPIRV-Tools. Settings are defined by
the included [.clang-format](.clang-format) file. the included [.clang-format](.clang-format) file.
We intend to maintain a linear history on the GitHub `main` branch. We intend to maintain a linear history on the GitHub `master` branch.
### Getting the source ### Getting the source
@ -293,18 +290,16 @@ For some kinds of development, you may need the latest sources from the third-pa
git clone https://github.com/google/googletest.git spirv-tools/external/googletest git clone https://github.com/google/googletest.git spirv-tools/external/googletest
git clone https://github.com/google/effcee.git spirv-tools/external/effcee git clone https://github.com/google/effcee.git spirv-tools/external/effcee
git clone https://github.com/google/re2.git spirv-tools/external/re2 git clone https://github.com/google/re2.git spirv-tools/external/re2
git clone https://github.com/abseil/abseil-cpp.git spirv-tools/external/abseil_cpp
#### Dependency on Effcee #### Dependency on Effcee
Some tests depend on the [Effcee][effcee] library for stateful matching. Some tests depend on the [Effcee][effcee] library for stateful matching.
Effcee itself depends on [RE2][re2], and RE2 depends on [Abseil][abseil-cpp]. Effcee itself depends on [RE2][re2].
* If SPIRV-Tools is configured as part of a larger project that already uses * If SPIRV-Tools is configured as part of a larger project that already uses
Effcee, then that project should include Effcee before SPIRV-Tools. Effcee, then that project should include Effcee before SPIRV-Tools.
* Otherwise, SPIRV-Tools expects Effcee sources to appear in `external/effcee`, * Otherwise, SPIRV-Tools expects Effcee sources to appear in `external/effcee`
RE2 sources to appear in `external/re2`, and Abseil sources to appear in and RE2 sources to appear in `external/re2`.
`external/abseil_cpp`.
### Source code organization ### Source code organization
@ -316,9 +311,6 @@ Effcee itself depends on [RE2][re2], and RE2 depends on [Abseil][abseil-cpp].
* `external/re2`: Location of [RE2][re2] sources, if the `re2` library is not already * `external/re2`: Location of [RE2][re2] sources, if the `re2` library is not already
configured by an enclosing project. configured by an enclosing project.
(The Effcee project already requires RE2.) (The Effcee project already requires RE2.)
* `external/abseil_cpp`: Location of [Abseil][abseil-cpp] sources, if Abseil is
not already configured by an enclosing project.
(The RE2 project already requires Abseil.)
* `include/`: API clients should add this directory to the include search path * `include/`: API clients should add this directory to the include search path
* `external/spirv-headers`: Intended location for * `external/spirv-headers`: Intended location for
[SPIR-V headers][spirv-headers], not provided [SPIR-V headers][spirv-headers], not provided
@ -386,11 +378,10 @@ fuzzer tests.
### Build using Bazel ### Build using Bazel
You can also use [Bazel](https://bazel.build/) to build the project. You can also use [Bazel](https://bazel.build/) to build the project.
```sh ```sh
cd <spirv-dir>
bazel build :all bazel build :all
``` ```
### Build a node.js package using Emscripten ### Build a node.js package using Emscripten
The SPIRV-Tools core library can be built to a WebAssembly [node.js](https://nodejs.org) The SPIRV-Tools core library can be built to a WebAssembly [node.js](https://nodejs.org)
@ -441,13 +432,10 @@ On MacOS
- AppleClang 11.0 - AppleClang 11.0
On Windows On Windows
- Visual Studio 2015
- Visual Studio 2017 - Visual Studio 2017
- Visual Studio 2019
- Visual Studio 2022
Note: Visual Studio 2017 has incomplete c++17 support. We might stop Other compilers or later versions may work, but they are not tested.
testing it soon. Other compilers or later versions may work, but they are not
tested.
### CMake options ### CMake options
@ -479,12 +467,12 @@ iterator debugging.
### Android ndk-build ### Android ndk-build
SPIR-V Tools supports building static libraries `libSPIRV-Tools.a` and SPIR-V Tools supports building static libraries `libSPIRV-Tools.a` and
`libSPIRV-Tools-opt.a` for Android. Using the Android NDK r25c or later: `libSPIRV-Tools-opt.a` for Android:
``` ```
cd <spirv-dir> cd <spirv-dir>
export ANDROID_NDK=/path/to/your/ndk # NDK r25c or later export ANDROID_NDK=/path/to/your/ndk
mkdir build && cd build mkdir build && cd build
mkdir libs mkdir libs
@ -508,7 +496,7 @@ The script requires Chromium's
### Usage ### Usage
The internals of the library use C++17 features, and are exposed via both a C The internals of the library use C++11 features, and are exposed via both a C
and C++ API. and C++ API.
In order to use the library from an application, the include path should point In order to use the library from an application, the include path should point
@ -730,16 +718,10 @@ Use `bazel test :all` to run all tests. This will run tests in parallel by defau
To run a single test target, specify `:my_test_target` instead of `:all`. Test target To run a single test target, specify `:my_test_target` instead of `:all`. Test target
names get printed when you run `bazel test :all`. For example, you can run names get printed when you run `bazel test :all`. For example, you can run
`opt_def_use_test` with: `opt_def_use_test` with:
on linux:
```shell ```shell
bazel test --cxxopt=-std=c++17 :opt_def_use_test bazel test :opt_def_use_test
``` ```
on windows:
```shell
bazel test --cxxopt=/std:c++17 :opt_def_use_test
```
## Future Work ## Future Work
<a name="future"></a> <a name="future"></a>
@ -797,7 +779,6 @@ limitations under the License.
[googletest-issue-610]: https://github.com/google/googletest/issues/610 [googletest-issue-610]: https://github.com/google/googletest/issues/610
[effcee]: https://github.com/google/effcee [effcee]: https://github.com/google/effcee
[re2]: https://github.com/google/re2 [re2]: https://github.com/google/re2
[abseil-cpp]: https://github.com/abseil/abseil-cpp
[CMake]: https://cmake.org/ [CMake]: https://cmake.org/
[cpp-style-guide]: https://google.github.io/styleguide/cppguide.html [cpp-style-guide]: https://google.github.io/styleguide/cppguide.html
[clang-sanitizers]: http://clang.llvm.org/docs/UsersManual.html#controlling-code-generation [clang-sanitizers]: http://clang.llvm.org/docs/UsersManual.html#controlling-code-generation

View File

@ -1,13 +0,0 @@
# Security Policy
## Supported Versions
Security updates are applied only to the latest release.
## Reporting a Vulnerability
If you have discovered a security vulnerability in this project, please report it privately. **Do not disclose it as a public issue.** This gives us time to work with you to fix the issue before public exposure, reducing the chance that the exploit will be used before a patch is released.
Please disclose it at [security advisory](https://github.com/KhronosGroup/SPIRV-Tools/security/advisories/new).
This project is maintained by a team of volunteers on a reasonable-effort basis. As such, please give us at least 90 days to work on a fix before public exposure.

View File

@ -1,11 +1,3 @@
load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")
http_archive(
name = "bazel_skylib",
strip_prefix = "bazel-skylib-main",
urls = ["https://github.com/bazelbuild/bazel-skylib/archive/main.zip"],
)
local_repository( local_repository(
name = "spirv_headers", name = "spirv_headers",
path = "external/spirv-headers", path = "external/spirv-headers",
@ -25,8 +17,3 @@ local_repository(
name = "com_google_effcee", name = "com_google_effcee",
path = "external/effcee", path = "external/effcee",
) )
local_repository(
name = "com_google_absl",
path = "external/abseil_cpp",
)

View File

@ -5,7 +5,7 @@ LOCAL_CPP_EXTENSION := .cc .cpp .cxx
LOCAL_SRC_FILES:=test.cpp LOCAL_SRC_FILES:=test.cpp
LOCAL_MODULE:=spirvtools_test LOCAL_MODULE:=spirvtools_test
LOCAL_LDLIBS:=-landroid LOCAL_LDLIBS:=-landroid
LOCAL_CXXFLAGS:=-std=c++17 -fno-exceptions -fno-rtti -Werror LOCAL_CXXFLAGS:=-std=c++11 -fno-exceptions -fno-rtti -Werror
LOCAL_STATIC_LIBRARIES=SPIRV-Tools SPIRV-Tools-opt LOCAL_STATIC_LIBRARIES=SPIRV-Tools SPIRV-Tools-opt
include $(BUILD_SHARED_LIBRARY) include $(BUILD_SHARED_LIBRARY)

View File

@ -1,5 +1,5 @@
APP_ABI := all APP_ABI := all
APP_BUILD_SCRIPT := Android.mk APP_BUILD_SCRIPT := Android.mk
APP_STL := c++_static APP_STL := c++_static
APP_PLATFORM := android-24 APP_PLATFORM := android-9
NDK_TOOLCHAIN_VERSION := 4.9 NDK_TOOLCHAIN_VERSION := 4.9

View File

@ -1,21 +1,20 @@
"""Constants and macros for spirv-tools BUILD."""
COMMON_COPTS = [ COMMON_COPTS = [
"-DSPIRV_CHECK_CONTEXT", "-DSPIRV_CHECK_CONTEXT",
"-DSPIRV_COLOR_TERMINAL", "-DSPIRV_COLOR_TERMINAL",
] + select({ ] + select({
"@platforms//os:windows": [], "@bazel_tools//src/conditions:windows": [""],
"//conditions:default": [ "//conditions:default": [
"-DSPIRV_LINUX", "-DSPIRV_LINUX",
"-DSPIRV_TIMER_ENABLED", "-DSPIRV_TIMER_ENABLED",
"-fvisibility=hidden",
"-fno-exceptions",
"-fno-rtti",
"-Wall", "-Wall",
"-Wextra", "-Wextra",
"-Wnon-virtual-dtor", "-Wnon-virtual-dtor",
"-Wno-missing-field-initializers", "-Wno-missing-field-initializers",
"-Werror", "-Werror",
"-std=c++11",
"-fvisibility=hidden",
"-fno-exceptions",
"-fno-rtti",
"-Wno-long-long", "-Wno-long-long",
"-Wshadow", "-Wshadow",
"-Wundef", "-Wundef",
@ -24,211 +23,324 @@ COMMON_COPTS = [
], ],
}) })
TEST_COPTS = COMMON_COPTS + [ TEST_COPTS = COMMON_COPTS + select({
] + select({ "@bazel_tools//src/conditions:windows": [
"@platforms//os:windows": [
# Disable C4503 "decorated name length exceeded" warning, # Disable C4503 "decorated name length exceeded" warning,
# triggered by some heavily templated types. # triggered by some heavily templated types.
# We don't care much about that in test code. # We don't care much about that in test code.
# Important to do since we have warnings-as-errors. # Important to do since we have warnings-as-errors.
"/wd4503", "/wd4503"
], ],
"//conditions:default": [ "//conditions:default": [
"-Wno-undef", "-Wno-undef",
"-Wno-self-assign", "-Wno-self-assign",
"-Wno-shadow", "-Wno-shadow",
"-Wno-unused-parameter", "-Wno-unused-parameter"
], ],
}) })
def incompatible_with(incompatible_constraints):
return select(_merge_dicts([{"//conditions:default": []}, {
constraint: ["@platforms//:incompatible"]
for constraint in incompatible_constraints
}]))
DEBUGINFO_GRAMMAR_JSON_FILE = "@spirv_headers//:spirv_ext_inst_debuginfo_grammar_unified1" DEBUGINFO_GRAMMAR_JSON_FILE = "@spirv_headers//:spirv_ext_inst_debuginfo_grammar_unified1"
CLDEBUGINFO100_GRAMMAR_JSON_FILE = "@spirv_headers//:spirv_ext_inst_opencl_debuginfo_100_grammar_unified1" CLDEBUGINFO100_GRAMMAR_JSON_FILE = "@spirv_headers//:spirv_ext_inst_opencl_debuginfo_100_grammar_unified1"
SHDEBUGINFO100_GRAMMAR_JSON_FILE = "@spirv_headers//:spirv_ext_inst_nonsemantic_shader_debuginfo_100_grammar_unified1" SHDEBUGINFO100_GRAMMAR_JSON_FILE = "@spirv_headers//:spirv_ext_inst_nonsemantic_shader_debuginfo_100_grammar_unified1"
def _merge_dicts(dicts): def generate_core_tables(version = None):
merged = {}
for d in dicts:
merged.update(d)
return merged
def generate_core_tables(version):
if not version: if not version:
fail("Must specify version", "version") fail("Must specify version", "version")
grammars = [
grammars = dict( "@spirv_headers//:spirv_core_grammar_" + version,
core_grammar = "@spirv_headers//:spirv_core_grammar_{}".format(version), DEBUGINFO_GRAMMAR_JSON_FILE,
debuginfo_grammar = DEBUGINFO_GRAMMAR_JSON_FILE, CLDEBUGINFO100_GRAMMAR_JSON_FILE,
cldebuginfo_grammar = CLDEBUGINFO100_GRAMMAR_JSON_FILE, ]
) outs = [
"core.insts-{}.inc".format(version),
outs = dict( "operand.kinds-{}.inc".format(version),
core_insts_output = "core.insts-{}.inc".format(version), ]
operand_kinds_output = "operand.kinds-{}.inc".format(version), fmtargs = grammars + outs
)
cmd = (
"$(location :generate_grammar_tables)" +
" --spirv-core-grammar=$(location {core_grammar})" +
" --extinst-debuginfo-grammar=$(location {debuginfo_grammar})" +
" --extinst-cldebuginfo100-grammar=$(location {cldebuginfo_grammar})" +
" --core-insts-output=$(location {core_insts_output})" +
" --operand-kinds-output=$(location {operand_kinds_output})" +
" --output-language=c++"
).format(**_merge_dicts([grammars, outs]))
native.genrule( native.genrule(
name = "gen_core_tables_" + version, name = "gen_core_tables_" + version,
srcs = grammars.values(), srcs = grammars,
outs = outs.values(), outs = outs,
cmd = cmd, cmd = (
cmd_bat = cmd, "$(location :generate_grammar_tables) " +
tools = [":generate_grammar_tables"], "--spirv-core-grammar=$(location {0}) " +
"--extinst-debuginfo-grammar=$(location {1}) " +
"--extinst-cldebuginfo100-grammar=$(location {2}) " +
"--core-insts-output=$(location {3}) " +
"--operand-kinds-output=$(location {4})"
).format(*fmtargs),
cmd_bat = (
"$(location :generate_grammar_tables) " +
"--spirv-core-grammar=$(location {0}) " +
"--extinst-debuginfo-grammar=$(location {1}) " +
"--extinst-cldebuginfo100-grammar=$(location {2}) " +
"--core-insts-output=$(location {3}) " +
"--operand-kinds-output=$(location {4})"
).format(*fmtargs),
exec_tools = [":generate_grammar_tables"],
visibility = ["//visibility:private"], visibility = ["//visibility:private"],
) )
def generate_enum_string_mapping(version): def generate_enum_string_mapping(version = None):
if not version: if not version:
fail("Must specify version", "version") fail("Must specify version", "version")
grammars = [
grammars = dict( "@spirv_headers//:spirv_core_grammar_" + version,
core_grammar = "@spirv_headers//:spirv_core_grammar_{}".format(version), DEBUGINFO_GRAMMAR_JSON_FILE,
debuginfo_grammar = DEBUGINFO_GRAMMAR_JSON_FILE, CLDEBUGINFO100_GRAMMAR_JSON_FILE,
cldebuginfo_grammar = CLDEBUGINFO100_GRAMMAR_JSON_FILE, ]
) outs = [
"extension_enum.inc",
outs = dict( "enum_string_mapping.inc",
extension_enum_ouput = "extension_enum.inc", ]
enum_string_mapping_output = "enum_string_mapping.inc", fmtargs = grammars + outs
)
cmd = (
"$(location :generate_grammar_tables)" +
" --spirv-core-grammar=$(location {core_grammar})" +
" --extinst-debuginfo-grammar=$(location {debuginfo_grammar})" +
" --extinst-cldebuginfo100-grammar=$(location {cldebuginfo_grammar})" +
" --extension-enum-output=$(location {extension_enum_ouput})" +
" --enum-string-mapping-output=$(location {enum_string_mapping_output})" +
" --output-language=c++"
).format(**_merge_dicts([grammars, outs]))
native.genrule( native.genrule(
name = "gen_enum_string_mapping", name = "gen_enum_string_mapping",
srcs = grammars.values(), srcs = grammars,
outs = outs.values(), outs = outs,
cmd = cmd, cmd = (
cmd_bat = cmd, "$(location :generate_grammar_tables) " +
tools = [":generate_grammar_tables"], "--spirv-core-grammar=$(location {0}) " +
"--extinst-debuginfo-grammar=$(location {1}) " +
"--extinst-cldebuginfo100-grammar=$(location {2}) " +
"--extension-enum-output=$(location {3}) " +
"--enum-string-mapping-output=$(location {4})"
).format(*fmtargs),
cmd_bat = (
"$(location :generate_grammar_tables) " +
"--spirv-core-grammar=$(location {0}) " +
"--extinst-debuginfo-grammar=$(location {1}) " +
"--extinst-cldebuginfo100-grammar=$(location {2}) " +
"--extension-enum-output=$(location {3}) " +
"--enum-string-mapping-output=$(location {4})"
).format(*fmtargs),
exec_tools = [":generate_grammar_tables"],
visibility = ["//visibility:private"], visibility = ["//visibility:private"],
) )
def generate_opencl_tables(version): def generate_opencl_tables(version = None):
if not version: if not version:
fail("Must specify version", "version") fail("Must specify version", "version")
grammars = [
grammars = dict( "@spirv_headers//:spirv_opencl_grammar_" + version,
opencl_grammar = "@spirv_headers//:spirv_opencl_grammar_{}".format(version), ]
) outs = ["opencl.std.insts.inc"]
fmtargs = grammars + outs
outs = dict(
opencl_insts_output = "opencl.std.insts.inc",
)
cmd = (
"$(location :generate_grammar_tables)" +
" --extinst-opencl-grammar=$(location {opencl_grammar})" +
" --opencl-insts-output=$(location {opencl_insts_output})"
).format(**_merge_dicts([grammars, outs]))
native.genrule( native.genrule(
name = "gen_opencl_tables_" + version, name = "gen_opencl_tables_" + version,
srcs = grammars.values(), srcs = grammars,
outs = outs.values(), outs = outs,
cmd = cmd, cmd = (
cmd_bat = cmd, "$(location :generate_grammar_tables) " +
tools = [":generate_grammar_tables"], "--extinst-opencl-grammar=$(location {0}) " +
"--opencl-insts-output=$(location {1})"
).format(*fmtargs),
cmd_bat = (
"$(location :generate_grammar_tables) " +
"--extinst-opencl-grammar=$(location {0}) " +
"--opencl-insts-output=$(location {1})"
).format(*fmtargs),
exec_tools = [":generate_grammar_tables"],
visibility = ["//visibility:private"], visibility = ["//visibility:private"],
) )
def generate_glsl_tables(version): def generate_glsl_tables(version = None):
if not version: if not version:
fail("Must specify version", "version") fail("Must specify version", "version")
grammars = [
grammars = dict( "@spirv_headers//:spirv_glsl_grammar_" + version,
gsls_grammar = "@spirv_headers//:spirv_glsl_grammar_{}".format(version), ]
) outs = ["glsl.std.450.insts.inc"]
outs = dict( fmtargs = grammars + outs
gsls_insts_outs = "glsl.std.450.insts.inc",
)
cmd = (
"$(location :generate_grammar_tables)" +
" --extinst-glsl-grammar=$(location {gsls_grammar})" +
" --glsl-insts-output=$(location {gsls_insts_outs})" +
" --output-language=c++"
).format(**_merge_dicts([grammars, outs]))
native.genrule( native.genrule(
name = "gen_glsl_tables_" + version, name = "gen_glsl_tables_" + version,
srcs = grammars.values(), srcs = grammars,
outs = outs.values(), outs = outs,
cmd = cmd, cmd = (
cmd_bat = cmd, "$(location :generate_grammar_tables) " +
tools = [":generate_grammar_tables"], "--extinst-glsl-grammar=$(location {0}) " +
"--glsl-insts-output=$(location {1})"
).format(*fmtargs),
cmd_bat = (
"$(location :generate_grammar_tables) " +
"--extinst-glsl-grammar=$(location {0}) " +
"--glsl-insts-output=$(location {1})"
).format(*fmtargs),
exec_tools = [":generate_grammar_tables"],
visibility = ["//visibility:private"], visibility = ["//visibility:private"],
) )
def generate_vendor_tables(extension, operand_kind_prefix = ""): def generate_vendor_tables(extension, operand_kind_prefix = ""):
if not extension: if not extension:
fail("Must specify extension", "extension") fail("Must specify extension", "extension")
extension_rule = extension.replace("-", "_").replace(".", "_") extension_rule = extension.replace("-", "_").replace(".", "_")
grammars = dict( grammars = ["@spirv_headers//:spirv_ext_inst_{}_grammar_unified1".format(extension_rule)]
vendor_grammar = "@spirv_headers//:spirv_ext_inst_{}_grammar_unified1".format(extension_rule), outs = ["{}.insts.inc".format(extension)]
) prefices = [operand_kind_prefix]
outs = dict( fmtargs = grammars + outs + prefices
vendor_insts_output = "{}.insts.inc".format(extension),
)
cmd = (
"$(location :generate_grammar_tables)" +
" --extinst-vendor-grammar=$(location {vendor_grammar})" +
" --vendor-insts-output=$(location {vendor_insts_output})" +
" --vendor-operand-kind-prefix={operand_kind_prefix}"
).format(operand_kind_prefix = operand_kind_prefix, **_merge_dicts([grammars, outs]))
native.genrule( native.genrule(
name = "gen_vendor_tables_" + extension_rule, name = "gen_vendor_tables_" + extension_rule,
srcs = grammars.values(), srcs = grammars,
outs = outs.values(), outs = outs,
cmd = cmd, cmd = (
cmd_bat = cmd, "$(location :generate_grammar_tables) " +
tools = [":generate_grammar_tables"], "--extinst-vendor-grammar=$(location {0}) " +
"--vendor-insts-output=$(location {1}) " +
"--vendor-operand-kind-prefix={2}"
).format(*fmtargs),
cmd_bat = (
"$(location :generate_grammar_tables) " +
"--extinst-vendor-grammar=$(location {0}) " +
"--vendor-insts-output=$(location {1}) " +
"--vendor-operand-kind-prefix={2}"
).format(*fmtargs),
exec_tools = [":generate_grammar_tables"],
visibility = ["//visibility:private"], visibility = ["//visibility:private"],
) )
def generate_extinst_lang_headers(name, grammar = None): def generate_extinst_lang_headers(name, grammar = None):
if not grammar: if not grammar:
fail("Must specify grammar", "grammar") fail("Must specify grammar", "grammar")
outs = dict( outs = [name + ".h"]
extinst_output_path = name + ".h", fmtargs = outs
)
cmd = (
"$(location :generate_language_headers)" +
" --extinst-grammar=$<" +
" --extinst-output-path=$(location {extinst_output_path})"
).format(**outs)
native.genrule( native.genrule(
name = "gen_extinst_lang_headers_{}".format(name), name = "gen_extinst_lang_headers_" + name,
srcs = [grammar], srcs = [grammar],
outs = outs.values(), outs = outs,
cmd = cmd, cmd = (
cmd_bat = cmd, "$(location :generate_language_headers) " +
tools = [":generate_language_headers"], "--extinst-grammar=$< " +
"--extinst-output-path=$(location {0})"
).format(*fmtargs),
cmd_bat = (
"$(location :generate_language_headers) " +
"--extinst-grammar=$< " +
"--extinst-output-path=$(location {0})"
).format(*fmtargs),
exec_tools = [":generate_language_headers"],
visibility = ["//visibility:private"], visibility = ["//visibility:private"],
) )
def base_test(name, srcs, deps = []):
if srcs == []:
return
if name[-5:] != "_test":
name = name + "_test"
native.cc_test(
name = "base_" + name,
srcs = srcs,
compatible_with = [],
copts = TEST_COPTS,
size = "large",
deps = [
":test_common",
"@com_google_googletest//:gtest_main",
"@com_google_googletest//:gtest",
"@com_google_effcee//:effcee",
] + deps,
)
def lint_test(name, srcs, deps = []):
if name[-5:] != "_test":
name = name + "_test"
native.cc_test(
name = "lint_" + name,
srcs = srcs,
compatible_with = [],
copts = TEST_COPTS,
size = "large",
deps = [
":spirv_tools_lint",
"@com_google_googletest//:gtest_main",
"@com_google_googletest//:gtest",
"@com_google_effcee//:effcee",
] + deps,
)
def link_test(name, srcs, deps = []):
if name[-5:] != "_test":
name = name + "_test"
native.cc_test(
name = "link_" + name,
srcs = srcs,
compatible_with = [],
copts = TEST_COPTS,
size = "large",
deps = [
":link_test_common",
"@com_google_googletest//:gtest_main",
"@com_google_googletest//:gtest",
"@com_google_effcee//:effcee",
] + deps,
)
def opt_test(name, srcs, deps = []):
if name[-5:] != "_test":
name = name + "_test"
native.cc_test(
name = "opt_" + name,
srcs = srcs,
compatible_with = [],
copts = TEST_COPTS,
size = "large",
deps = [
":opt_test_common",
"@com_google_googletest//:gtest_main",
"@com_google_googletest//:gtest",
"@com_google_effcee//:effcee",
] + deps,
)
def reduce_test(name, srcs, deps = []):
if name[-5:] != "_test":
name = name + "_test"
native.cc_test(
name = "reduce_" + name,
srcs = srcs,
compatible_with = [],
copts = TEST_COPTS,
size = "large",
deps = [
":reduce_test_common",
":spirv_tools_reduce",
"@com_google_googletest//:gtest_main",
"@com_google_googletest//:gtest",
"@com_google_effcee//:effcee",
] + deps,
)
def util_test(name, srcs, deps = []):
if name[-5:] != "_test":
name = name + "_test"
native.cc_test(
name = "util_" + name,
srcs = srcs,
compatible_with = [],
copts = TEST_COPTS,
size = "large",
deps = [
":opt_test_common",
"@com_google_googletest//:gtest_main",
"@com_google_googletest//:gtest",
"@com_google_effcee//:effcee",
] + deps,
)
def val_test(name, srcs = [], copts = [], deps = [], **kwargs):
if name[-5:] != "_test":
name = name + "_test"
if name[:4] != "val_":
name = "val_" + name
native.cc_test(
name = name,
srcs = srcs,
compatible_with = [],
copts = TEST_COPTS + copts,
size = "large",
deps = [
":val_test_common",
"@com_google_googletest//:gtest_main",
"@com_google_googletest//:gtest",
"@com_google_effcee//:effcee",
] + deps,
**kwargs
)

0
docker-compose.yml Executable file → Normal file
View File

View File

@ -2,7 +2,7 @@
## Latest builds ## Latest builds
Download the latest builds of the [main](https://github.com/KhronosGroup/SPIRV-Tools/tree/main) branch. Download the latest builds of the [master](https://github.com/KhronosGroup/SPIRV-Tools/tree/master) branch.
### Release build ### Release build
| Windows | Linux | MacOS | | Windows | Linux | MacOS |

View File

@ -34,7 +34,7 @@ through the project workflow:
ones. ones.
* They determine if the work for a card has been completed. * They determine if the work for a card has been completed.
* Normally they are the person (or persons) who can approve and merge a pull * Normally they are the person (or persons) who can approve and merge a pull
request into the `main` branch. request into the `master` branch.
Our projects organize cards into the following columns: Our projects organize cards into the following columns:
* `Ideas`: Work which could be done, captured either as Cards or Notes. * `Ideas`: Work which could be done, captured either as Cards or Notes.
@ -51,7 +51,7 @@ Our projects organize cards into the following columns:
claimed by someone. claimed by someone.
* `Done`: Issues which have been resolved, by completing their work. * `Done`: Issues which have been resolved, by completing their work.
* The changes have been applied to the repository, typically by being pushed * The changes have been applied to the repository, typically by being pushed
into the `main` branch. into the `master` branch.
* Other kinds of work could update repository settings, for example. * Other kinds of work could update repository settings, for example.
* `Rejected ideas`: Work which has been considered, but which we don't want * `Rejected ideas`: Work which has been considered, but which we don't want
implemented. implemented.

View File

@ -30,7 +30,11 @@ if (DEFINED SPIRV-Headers_SOURCE_DIR)
# This allows flexible position of the SPIRV-Headers repo. # This allows flexible position of the SPIRV-Headers repo.
set(SPIRV_HEADER_DIR ${SPIRV-Headers_SOURCE_DIR}) set(SPIRV_HEADER_DIR ${SPIRV-Headers_SOURCE_DIR})
else() else()
set(SPIRV_HEADER_DIR ${CMAKE_CURRENT_SOURCE_DIR}/spirv-headers) if (IS_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/SPIRV-Headers)
set(SPIRV_HEADER_DIR ${CMAKE_CURRENT_SOURCE_DIR}/SPIRV-Headers)
else()
set(SPIRV_HEADER_DIR ${CMAKE_CURRENT_SOURCE_DIR}/spirv-headers)
endif()
endif() endif()
if (IS_DIRECTORY ${SPIRV_HEADER_DIR}) if (IS_DIRECTORY ${SPIRV_HEADER_DIR})
@ -41,6 +45,8 @@ if (IS_DIRECTORY ${SPIRV_HEADER_DIR})
# Do this so enclosing projects can use SPIRV-Headers_SOURCE_DIR to find # Do this so enclosing projects can use SPIRV-Headers_SOURCE_DIR to find
# headers to include. # headers to include.
if (NOT DEFINED SPIRV-Headers_SOURCE_DIR) if (NOT DEFINED SPIRV-Headers_SOURCE_DIR)
set(SPIRV_HEADERS_SKIP_INSTALL ON)
set(SPIRV_HEADERS_SKIP_EXAMPLES ON)
add_subdirectory(${SPIRV_HEADER_DIR}) add_subdirectory(${SPIRV_HEADER_DIR})
endif() endif()
else() else()
@ -54,9 +60,7 @@ if (NOT ${SPIRV_SKIP_TESTS})
if (TARGET gmock) if (TARGET gmock)
message(STATUS "Google Mock already configured") message(STATUS "Google Mock already configured")
else() else()
if (NOT GMOCK_DIR) set(GMOCK_DIR ${CMAKE_CURRENT_SOURCE_DIR}/googletest)
set(GMOCK_DIR ${CMAKE_CURRENT_SOURCE_DIR}/googletest)
endif()
if(EXISTS ${GMOCK_DIR}) if(EXISTS ${GMOCK_DIR})
if(MSVC) if(MSVC)
# Our tests use ::testing::Combine. Work around a compiler # Our tests use ::testing::Combine. Work around a compiler
@ -73,7 +77,7 @@ if (NOT ${SPIRV_SKIP_TESTS})
# gtest requires special defines for building as a shared # gtest requires special defines for building as a shared
# library, simply always build as static. # library, simply always build as static.
push_variable(BUILD_SHARED_LIBS 0) push_variable(BUILD_SHARED_LIBS 0)
add_subdirectory(${GMOCK_DIR} ${CMAKE_CURRENT_BINARY_DIR}/googletest EXCLUDE_FROM_ALL) add_subdirectory(${GMOCK_DIR} EXCLUDE_FROM_ALL)
pop_variable(BUILD_SHARED_LIBS) pop_variable(BUILD_SHARED_LIBS)
endif() endif()
endif() endif()
@ -91,22 +95,10 @@ if (NOT ${SPIRV_SKIP_TESTS})
# Find Effcee and RE2, for testing. # Find Effcee and RE2, for testing.
# RE2 depends on Abseil. We set absl_SOURCE_DIR if it is not already set, so
# that effcee can find abseil.
if(NOT TARGET absl::base)
if (NOT absl_SOURCE_DIR)
if (EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/abseil_cpp)
set(absl_SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/abseil_cpp" CACHE STRING "Abseil source dir" )
endif()
endif()
endif()
# First find RE2, since Effcee depends on it. # First find RE2, since Effcee depends on it.
# If already configured, then use that. Otherwise, prefer to find it under 're2' # If already configured, then use that. Otherwise, prefer to find it under 're2'
# in this directory. # in this directory.
if (NOT TARGET re2) if (NOT TARGET re2)
# If we are configuring RE2, then turn off its testing. It takes a long time and # If we are configuring RE2, then turn off its testing. It takes a long time and
# does not add much value for us. If an enclosing project configured RE2, then it # does not add much value for us. If an enclosing project configured RE2, then it
# has already chosen whether to enable RE2 testing. # has already chosen whether to enable RE2 testing.
@ -164,7 +156,7 @@ if(SPIRV_BUILD_FUZZER)
if(NOT TARGET protobuf::libprotobuf OR NOT TARGET protobuf::protoc) if(NOT TARGET protobuf::libprotobuf OR NOT TARGET protobuf::protoc)
set(SPIRV_TOOLS_PROTOBUF_DIR ${CMAKE_CURRENT_SOURCE_DIR}/protobuf) set(SPIRV_TOOLS_PROTOBUF_DIR ${CMAKE_CURRENT_SOURCE_DIR}/protobuf/cmake)
if (NOT IS_DIRECTORY ${SPIRV_TOOLS_PROTOBUF_DIR}) if (NOT IS_DIRECTORY ${SPIRV_TOOLS_PROTOBUF_DIR})
message( message(
FATAL_ERROR FATAL_ERROR

View File

@ -36,25 +36,16 @@ namespace spvtools {
// generated by InstrumentPass::GenDebugStreamWrite. This method is utilized // generated by InstrumentPass::GenDebugStreamWrite. This method is utilized
// by InstBindlessCheckPass, InstBuffAddrCheckPass, and InstDebugPrintfPass. // by InstBindlessCheckPass, InstBuffAddrCheckPass, and InstDebugPrintfPass.
// //
// The 1st member of the debug output buffer contains a set of flags // The first member of the debug output buffer contains the next available word
// controlling the behavior of instrumentation code.
static const int kDebugOutputFlagsOffset = 0;
// Values stored at kDebugOutputFlagsOffset
enum kInstFlags : unsigned int {
kInstBufferOOBEnable = 0x1,
};
// The 2nd member of the debug output buffer contains the next available word
// in the data stream to be written. Shaders will atomically read and update // in the data stream to be written. Shaders will atomically read and update
// this value so as not to overwrite each others records. This value must be // this value so as not to overwrite each others records. This value must be
// initialized to zero // initialized to zero
static const int kDebugOutputSizeOffset = 1; static const int kDebugOutputSizeOffset = 0;
// The 3rd member of the output buffer is the start of the stream of records // The second member of the output buffer is the start of the stream of records
// written by the instrumented shaders. Each record represents a validation // written by the instrumented shaders. Each record represents a validation
// error. The format of the records is documented below. // error. The format of the records is documented below.
static const int kDebugOutputDataOffset = 2; static const int kDebugOutputDataOffset = 1;
// Common Stream Record Offsets // Common Stream Record Offsets
// //
@ -73,14 +64,196 @@ static const int kInstCommonOutShaderId = 1;
// which generated the validation error. // which generated the validation error.
static const int kInstCommonOutInstructionIdx = 2; static const int kInstCommonOutInstructionIdx = 2;
// This is the stage which generated the validation error. This word is used
// to determine the contents of the next two words in the record.
// 0:Vert, 1:TessCtrl, 2:TessEval, 3:Geom, 4:Frag, 5:Compute
static const int kInstCommonOutStageIdx = 3;
static const int kInstCommonOutCnt = 4;
// Stage-specific Stream Record Offsets
//
// Each stage will contain different values in the next set of words of the
// record used to identify which instantiation of the shader generated the
// validation error.
//
// Vertex Shader Output Record Offsets
static const int kInstVertOutVertexIndex = kInstCommonOutCnt;
static const int kInstVertOutInstanceIndex = kInstCommonOutCnt + 1;
static const int kInstVertOutUnused = kInstCommonOutCnt + 2;
// Frag Shader Output Record Offsets
static const int kInstFragOutFragCoordX = kInstCommonOutCnt;
static const int kInstFragOutFragCoordY = kInstCommonOutCnt + 1;
static const int kInstFragOutUnused = kInstCommonOutCnt + 2;
// Compute Shader Output Record Offsets
static const int kInstCompOutGlobalInvocationIdX = kInstCommonOutCnt;
static const int kInstCompOutGlobalInvocationIdY = kInstCommonOutCnt + 1;
static const int kInstCompOutGlobalInvocationIdZ = kInstCommonOutCnt + 2;
// Tessellation Control Shader Output Record Offsets
static const int kInstTessCtlOutInvocationId = kInstCommonOutCnt;
static const int kInstTessCtlOutPrimitiveId = kInstCommonOutCnt + 1;
static const int kInstTessCtlOutUnused = kInstCommonOutCnt + 2;
// Tessellation Eval Shader Output Record Offsets
static const int kInstTessEvalOutPrimitiveId = kInstCommonOutCnt;
static const int kInstTessEvalOutTessCoordU = kInstCommonOutCnt + 1;
static const int kInstTessEvalOutTessCoordV = kInstCommonOutCnt + 2;
// Geometry Shader Output Record Offsets
static const int kInstGeomOutPrimitiveId = kInstCommonOutCnt;
static const int kInstGeomOutInvocationId = kInstCommonOutCnt + 1;
static const int kInstGeomOutUnused = kInstCommonOutCnt + 2;
// Ray Tracing Shader Output Record Offsets
static const int kInstRayTracingOutLaunchIdX = kInstCommonOutCnt;
static const int kInstRayTracingOutLaunchIdY = kInstCommonOutCnt + 1;
static const int kInstRayTracingOutLaunchIdZ = kInstCommonOutCnt + 2;
// Mesh Shader Output Record Offsets
static const int kInstMeshOutGlobalInvocationIdX = kInstCommonOutCnt;
static const int kInstMeshOutGlobalInvocationIdY = kInstCommonOutCnt + 1;
static const int kInstMeshOutGlobalInvocationIdZ = kInstCommonOutCnt + 2;
// Task Shader Output Record Offsets
static const int kInstTaskOutGlobalInvocationIdX = kInstCommonOutCnt;
static const int kInstTaskOutGlobalInvocationIdY = kInstCommonOutCnt + 1;
static const int kInstTaskOutGlobalInvocationIdZ = kInstCommonOutCnt + 2;
// Size of Common and Stage-specific Members
static const int kInstStageOutCnt = kInstCommonOutCnt + 3;
// Validation Error Code Offset
//
// This identifies the validation error. It also helps to identify
// how many words follow in the record and their meaning.
static const int kInstValidationOutError = kInstStageOutCnt;
// Validation-specific Output Record Offsets
//
// Each different validation will generate a potentially different
// number of words at the end of the record giving more specifics
// about the validation error.
//
// A bindless bounds error will output the index and the bound.
static const int kInstBindlessBoundsOutDescIndex = kInstStageOutCnt + 1;
static const int kInstBindlessBoundsOutDescBound = kInstStageOutCnt + 2;
static const int kInstBindlessBoundsOutUnused = kInstStageOutCnt + 3;
static const int kInstBindlessBoundsOutCnt = kInstStageOutCnt + 4;
// A descriptor uninitialized error will output the index.
static const int kInstBindlessUninitOutDescIndex = kInstStageOutCnt + 1;
static const int kInstBindlessUninitOutUnused = kInstStageOutCnt + 2;
static const int kInstBindlessUninitOutUnused2 = kInstStageOutCnt + 3;
static const int kInstBindlessUninitOutCnt = kInstStageOutCnt + 4;
// A buffer out-of-bounds error will output the descriptor
// index, the buffer offset and the buffer size
static const int kInstBindlessBuffOOBOutDescIndex = kInstStageOutCnt + 1;
static const int kInstBindlessBuffOOBOutBuffOff = kInstStageOutCnt + 2;
static const int kInstBindlessBuffOOBOutBuffSize = kInstStageOutCnt + 3;
static const int kInstBindlessBuffOOBOutCnt = kInstStageOutCnt + 4;
// A buffer address unalloc error will output the 64-bit pointer in
// two 32-bit pieces, lower bits first.
static const int kInstBuffAddrUnallocOutDescPtrLo = kInstStageOutCnt + 1;
static const int kInstBuffAddrUnallocOutDescPtrHi = kInstStageOutCnt + 2;
static const int kInstBuffAddrUnallocOutCnt = kInstStageOutCnt + 3;
// Maximum Output Record Member Count
static const int kInstMaxOutCnt = kInstStageOutCnt + 4;
// Validation Error Codes
//
// These are the possible validation error codes.
static const int kInstErrorBindlessBounds = 0;
static const int kInstErrorBindlessUninit = 1;
static const int kInstErrorBuffAddrUnallocRef = 2;
// Deleted: static const int kInstErrorBindlessBuffOOB = 3;
// This comment will will remain for 2 releases to allow
// for the transition of all builds. Buffer OOB is
// generating the following four differentiated codes instead:
static const int kInstErrorBuffOOBUniform = 4;
static const int kInstErrorBuffOOBStorage = 5;
static const int kInstErrorBuffOOBUniformTexel = 6;
static const int kInstErrorBuffOOBStorageTexel = 7;
static const int kInstErrorMax = kInstErrorBuffOOBStorageTexel;
// Direct Input Buffer Offsets
//
// The following values provide member offsets into the input buffers
// consumed by InstrumentPass::GenDebugDirectRead(). This method is utilized
// by InstBindlessCheckPass.
//
// The only object in an input buffer is a runtime array of unsigned
// integers. Each validation will have its own formatting of this array.
static const int kDebugInputDataOffset = 0;
// Debug Buffer Bindings // Debug Buffer Bindings
// //
// These are the bindings for the different buffers which are // These are the bindings for the different buffers which are
// read or written by the instrumentation passes. // read or written by the instrumentation passes.
// //
// This is the output buffer written by InstBindlessCheckPass,
// InstBuffAddrCheckPass, and possibly other future validations.
static const int kDebugOutputBindingStream = 0;
// The binding for the input buffer read by InstBindlessCheckPass.
static const int kDebugInputBindingBindless = 1;
// The binding for the input buffer read by InstBuffAddrCheckPass.
static const int kDebugInputBindingBuffAddr = 2;
// This is the output buffer written by InstDebugPrintfPass. // This is the output buffer written by InstDebugPrintfPass.
static const int kDebugOutputPrintfStream = 3; static const int kDebugOutputPrintfStream = 3;
// Bindless Validation Input Buffer Format
//
// An input buffer for bindless validation consists of a single array of
// unsigned integers we will call Data[]. This array is formatted as follows.
//
// At offset kDebugInputBindlessInitOffset in Data[] is a single uint which
// gives an offset to the start of the bindless initialization data. More
// specifically, if the following value is zero, we know that the descriptor at
// (set = s, binding = b, index = i) is not initialized; if the value is
// non-zero, and the descriptor points to a buffer, the value is the length of
// the buffer in bytes and can be used to check for out-of-bounds buffer
// references:
// Data[ i + Data[ b + Data[ s + Data[ kDebugInputBindlessInitOffset ] ] ] ]
static const int kDebugInputBindlessInitOffset = 0;
// At offset kDebugInputBindlessOffsetLengths is some number of uints which
// provide the bindless length data. More specifically, the number of
// descriptors at (set=s, binding=b) is:
// Data[ Data[ s + kDebugInputBindlessOffsetLengths ] + b ]
static const int kDebugInputBindlessOffsetLengths = 1;
// Buffer Device Address Input Buffer Format
//
// An input buffer for buffer device address validation consists of a single
// array of unsigned 64-bit integers we will call Data[]. This array is
// formatted as follows:
//
// At offset kDebugInputBuffAddrPtrOffset is a list of sorted valid buffer
// addresses. The list is terminated with the address 0xffffffffffffffff.
// If 0x0 is not a valid buffer address, this address is inserted at the
// start of the list.
//
static const int kDebugInputBuffAddrPtrOffset = 1;
//
// At offset kDebugInputBuffAddrLengthOffset in Data[] is a single uint64 which
// gives an offset to the start of the buffer length data. More
// specifically, for a buffer whose pointer is located at input buffer offset
// i, the length is located at:
//
// Data[ i - kDebugInputBuffAddrPtrOffset
// + Data[ kDebugInputBuffAddrLengthOffset ] ]
//
// The length associated with the 0xffffffffffffffff address is zero. If
// not a valid buffer, the length associated with the 0x0 address is zero.
static const int kDebugInputBuffAddrLengthOffset = 0;
} // namespace spvtools } // namespace spvtools
#endif // INCLUDE_SPIRV_TOOLS_INSTRUMENT_HPP_ #endif // INCLUDE_SPIRV_TOOLS_INSTRUMENT_HPP_

View File

@ -143,7 +143,6 @@ typedef enum spv_operand_type_t {
// may be larger than 32, which would require such a typed literal value to // may be larger than 32, which would require such a typed literal value to
// occupy multiple SPIR-V words. // occupy multiple SPIR-V words.
SPV_OPERAND_TYPE_TYPED_LITERAL_NUMBER, SPV_OPERAND_TYPE_TYPED_LITERAL_NUMBER,
SPV_OPERAND_TYPE_LITERAL_FLOAT, // Always 32-bit float.
// Set 3: The literal string operand type. // Set 3: The literal string operand type.
SPV_OPERAND_TYPE_LITERAL_STRING, SPV_OPERAND_TYPE_LITERAL_STRING,
@ -286,22 +285,6 @@ typedef enum spv_operand_type_t {
// An optional packed vector format // An optional packed vector format
SPV_OPERAND_TYPE_OPTIONAL_PACKED_VECTOR_FORMAT, SPV_OPERAND_TYPE_OPTIONAL_PACKED_VECTOR_FORMAT,
// Concrete operand types for cooperative matrix.
SPV_OPERAND_TYPE_COOPERATIVE_MATRIX_OPERANDS,
// An optional cooperative matrix operands
SPV_OPERAND_TYPE_OPTIONAL_COOPERATIVE_MATRIX_OPERANDS,
SPV_OPERAND_TYPE_COOPERATIVE_MATRIX_LAYOUT,
SPV_OPERAND_TYPE_COOPERATIVE_MATRIX_USE,
// Enum type from SPV_INTEL_global_variable_fpga_decorations
SPV_OPERAND_TYPE_INITIALIZATION_MODE_QUALIFIER,
// Enum type from SPV_INTEL_global_variable_host_access
SPV_OPERAND_TYPE_HOST_ACCESS_QUALIFIER,
// Enum type from SPV_INTEL_cache_controls
SPV_OPERAND_TYPE_LOAD_CACHE_CONTROL,
// Enum type from SPV_INTEL_cache_controls
SPV_OPERAND_TYPE_STORE_CACHE_CONTROL,
// This is a sentinel value, and does not represent an operand type. // This is a sentinel value, and does not represent an operand type.
// It should come last. // It should come last.
SPV_OPERAND_TYPE_NUM_OPERAND_TYPES, SPV_OPERAND_TYPE_NUM_OPERAND_TYPES,
@ -419,19 +402,6 @@ typedef struct spv_parsed_instruction_t {
uint16_t num_operands; uint16_t num_operands;
} spv_parsed_instruction_t; } spv_parsed_instruction_t;
typedef struct spv_parsed_header_t {
// The magic number of the SPIR-V module.
uint32_t magic;
// Version number.
uint32_t version;
// Generator's magic number.
uint32_t generator;
// IDs bound for this module (0 < id < bound).
uint32_t bound;
// reserved.
uint32_t reserved;
} spv_parsed_header_t;
typedef struct spv_const_binary_t { typedef struct spv_const_binary_t {
const uint32_t* code; const uint32_t* code;
const size_t wordCount; const size_t wordCount;
@ -471,8 +441,6 @@ typedef struct spv_reducer_options_t spv_reducer_options_t;
typedef struct spv_fuzzer_options_t spv_fuzzer_options_t; typedef struct spv_fuzzer_options_t spv_fuzzer_options_t;
typedef struct spv_optimizer_t spv_optimizer_t;
// Type Definitions // Type Definitions
typedef spv_const_binary_t* spv_const_binary; typedef spv_const_binary_t* spv_const_binary;
@ -932,63 +900,6 @@ SPIRV_TOOLS_EXPORT spv_result_t spvBinaryParse(
const size_t num_words, spv_parsed_header_fn_t parse_header, const size_t num_words, spv_parsed_header_fn_t parse_header,
spv_parsed_instruction_fn_t parse_instruction, spv_diagnostic* diagnostic); spv_parsed_instruction_fn_t parse_instruction, spv_diagnostic* diagnostic);
// The optimizer interface.
// A pointer to a function that accepts a log message from an optimizer.
typedef void (*spv_message_consumer)(
spv_message_level_t, const char*, const spv_position_t*, const char*);
// Creates and returns an optimizer object. This object must be passed to
// optimizer APIs below and is valid until passed to spvOptimizerDestroy.
SPIRV_TOOLS_EXPORT spv_optimizer_t* spvOptimizerCreate(spv_target_env env);
// Destroys the given optimizer object.
SPIRV_TOOLS_EXPORT void spvOptimizerDestroy(spv_optimizer_t* optimizer);
// Sets an spv_message_consumer on an optimizer object.
SPIRV_TOOLS_EXPORT void spvOptimizerSetMessageConsumer(
spv_optimizer_t* optimizer, spv_message_consumer consumer);
// Registers passes that attempt to legalize the generated code.
SPIRV_TOOLS_EXPORT void spvOptimizerRegisterLegalizationPasses(
spv_optimizer_t* optimizer);
// Registers passes that attempt to improve performance of generated code.
SPIRV_TOOLS_EXPORT void spvOptimizerRegisterPerformancePasses(
spv_optimizer_t* optimizer);
// Registers passes that attempt to improve the size of generated code.
SPIRV_TOOLS_EXPORT void spvOptimizerRegisterSizePasses(
spv_optimizer_t* optimizer);
// Registers a pass specified by a flag in an optimizer object.
SPIRV_TOOLS_EXPORT bool spvOptimizerRegisterPassFromFlag(
spv_optimizer_t* optimizer, const char* flag);
// Registers passes specified by length number of flags in an optimizer object.
SPIRV_TOOLS_EXPORT bool spvOptimizerRegisterPassesFromFlags(
spv_optimizer_t* optimizer, const char** flags, const size_t flag_count);
// Optimizes the SPIR-V code of size |word_count| pointed to by |binary| and
// returns an optimized spv_binary in |optimized_binary|.
//
// Returns SPV_SUCCESS on successful optimization, whether or not the module is
// modified. Returns an SPV_ERROR_* if the module fails to validate or if
// errors occur when processing using any of the registered passes. In that
// case, no further passes are executed and the |optimized_binary| contents may
// be invalid.
//
// By default, the binary is validated before any transforms are performed,
// and optionally after each transform. Validation uses SPIR-V spec rules
// for the SPIR-V version named in the binary's header (at word offset 1).
// Additionally, if the target environment is a client API (such as
// Vulkan 1.1), then validate for that client API version, to the extent
// that it is verifiable from data in the binary itself, or from the
// validator options set on the optimizer options.
SPIRV_TOOLS_EXPORT spv_result_t spvOptimizerRun(
spv_optimizer_t* optimizer, const uint32_t* binary, const size_t word_count,
spv_binary* optimized_binary, const spv_optimizer_options options);
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif

View File

@ -31,11 +31,6 @@ using MessageConsumer = std::function<void(
const spv_position_t& /* position */, const char* /* message */ const spv_position_t& /* position */, const char* /* message */
)>; )>;
using HeaderParser = std::function<spv_result_t(
const spv_endianness_t endianess, const spv_parsed_header_t& instruction)>;
using InstructionParser =
std::function<spv_result_t(const spv_parsed_instruction_t& instruction)>;
// C++ RAII wrapper around the C context object spv_context. // C++ RAII wrapper around the C context object spv_context.
class Context { class Context {
public: public:
@ -341,23 +336,6 @@ class SpirvTools {
std::string* text, std::string* text,
uint32_t options = kDefaultDisassembleOption) const; uint32_t options = kDefaultDisassembleOption) const;
// Parses a SPIR-V binary, specified as counted sequence of 32-bit words.
// Parsing feedback is provided via two callbacks provided as std::function.
// In a valid parse the parsed-header callback is called once, and
// then the parsed-instruction callback is called once for each instruction
// in the stream.
// Returns true on successful parsing.
// If diagnostic is non-null, a diagnostic is emitted on failed parsing.
// If diagnostic is null the context's message consumer
// will be used to emit any errors. If a callback returns anything other than
// SPV_SUCCESS, then that status code is returned, no further callbacks are
// issued, and no additional diagnostics are emitted.
// This is a wrapper around the C API spvBinaryParse.
bool Parse(const std::vector<uint32_t>& binary,
const HeaderParser& header_parser,
const InstructionParser& instruction_parser,
spv_diagnostic* diagnostic = nullptr);
// Validates the given SPIR-V |binary|. Returns true if no issues are found. // Validates the given SPIR-V |binary|. Returns true if no issues are found.
// Otherwise, returns false and communicates issues via the message consumer // Otherwise, returns false and communicates issues via the message consumer
// registered. // registered.

View File

@ -26,6 +26,11 @@ namespace spvtools {
class LinkerOptions { class LinkerOptions {
public: public:
LinkerOptions()
: create_library_(false),
verify_ids_(false),
allow_partial_linkage_(false) {}
// Returns whether a library or an executable should be produced by the // Returns whether a library or an executable should be produced by the
// linking phase. // linking phase.
// //
@ -58,16 +63,10 @@ class LinkerOptions {
allow_partial_linkage_ = allow_partial_linkage; allow_partial_linkage_ = allow_partial_linkage;
} }
bool GetUseHighestVersion() const { return use_highest_version_; }
void SetUseHighestVersion(bool use_highest_vers) {
use_highest_version_ = use_highest_vers;
}
private: private:
bool create_library_{false}; bool create_library_;
bool verify_ids_{false}; bool verify_ids_;
bool allow_partial_linkage_{false}; bool allow_partial_linkage_;
bool use_highest_version_{false};
}; };
// Links one or more SPIR-V modules into a new SPIR-V module. That is, combine // Links one or more SPIR-V modules into a new SPIR-V module. That is, combine

View File

@ -19,7 +19,6 @@
#include <ostream> #include <ostream>
#include <string> #include <string>
#include <unordered_map> #include <unordered_map>
#include <unordered_set>
#include <utility> #include <utility>
#include <vector> #include <vector>
@ -97,24 +96,12 @@ class Optimizer {
// Registers passes that attempt to improve performance of generated code. // Registers passes that attempt to improve performance of generated code.
// This sequence of passes is subject to constant review and will change // This sequence of passes is subject to constant review and will change
// from time to time. // from time to time.
//
// If |preserve_interface| is true, all non-io variables in the entry point
// interface are considered live and are not eliminated.
// |preserve_interface| should be true if HLSL is generated
// from the SPIR-V bytecode.
Optimizer& RegisterPerformancePasses(); Optimizer& RegisterPerformancePasses();
Optimizer& RegisterPerformancePasses(bool preserve_interface);
// Registers passes that attempt to improve the size of generated code. // Registers passes that attempt to improve the size of generated code.
// This sequence of passes is subject to constant review and will change // This sequence of passes is subject to constant review and will change
// from time to time. // from time to time.
//
// If |preserve_interface| is true, all non-io variables in the entry point
// interface are considered live and are not eliminated.
// |preserve_interface| should be true if HLSL is generated
// from the SPIR-V bytecode.
Optimizer& RegisterSizePasses(); Optimizer& RegisterSizePasses();
Optimizer& RegisterSizePasses(bool preserve_interface);
// Registers passes that attempt to legalize the generated code. // Registers passes that attempt to legalize the generated code.
// //
@ -124,13 +111,7 @@ class Optimizer {
// //
// This sequence of passes is subject to constant review and will change // This sequence of passes is subject to constant review and will change
// from time to time. // from time to time.
//
// If |preserve_interface| is true, all non-io variables in the entry point
// interface are considered live and are not eliminated.
// |preserve_interface| should be true if HLSL is generated
// from the SPIR-V bytecode.
Optimizer& RegisterLegalizationPasses(); Optimizer& RegisterLegalizationPasses();
Optimizer& RegisterLegalizationPasses(bool preserve_interface);
// Register passes specified in the list of |flags|. Each flag must be a // Register passes specified in the list of |flags|. Each flag must be a
// string of a form accepted by Optimizer::FlagHasValidForm(). // string of a form accepted by Optimizer::FlagHasValidForm().
@ -539,14 +520,8 @@ Optimizer::PassToken CreateDeadInsertElimPass();
// interface are considered live and are not eliminated. This mode is needed // interface are considered live and are not eliminated. This mode is needed
// by GPU-Assisted validation instrumentation, where a change in the interface // by GPU-Assisted validation instrumentation, where a change in the interface
// is not allowed. // is not allowed.
//
// If |remove_outputs| is true, allow outputs to be removed from the interface.
// This is only safe if the caller knows that there is no corresponding input
// variable in the following shader. It is false by default.
Optimizer::PassToken CreateAggressiveDCEPass(); Optimizer::PassToken CreateAggressiveDCEPass();
Optimizer::PassToken CreateAggressiveDCEPass(bool preserve_interface); Optimizer::PassToken CreateAggressiveDCEPass(bool preserve_interface);
Optimizer::PassToken CreateAggressiveDCEPass(bool preserve_interface,
bool remove_outputs);
// Creates a remove-unused-interface-variables pass. // Creates a remove-unused-interface-variables pass.
// Removes variables referenced on the |OpEntryPoint| instruction that are not // Removes variables referenced on the |OpEntryPoint| instruction that are not
@ -766,9 +741,19 @@ Optimizer::PassToken CreateCombineAccessChainsPass();
// potentially de-optimizing the instrument code, for example, inlining // potentially de-optimizing the instrument code, for example, inlining
// the debug record output function throughout the module. // the debug record output function throughout the module.
// //
// The instrumentation will write |shader_id| in each output record // The instrumentation will read and write buffers in debug
// descriptor set |desc_set|. It will write |shader_id| in each output record
// to identify the shader module which generated the record. // to identify the shader module which generated the record.
Optimizer::PassToken CreateInstBindlessCheckPass(uint32_t shader_id); // |desc_length_enable| controls instrumentation of runtime descriptor array
// references, |desc_init_enable| controls instrumentation of descriptor
// initialization checking, and |buff_oob_enable| controls instrumentation
// of storage and uniform buffer bounds checking, all of which require input
// buffer support. |texbuff_oob_enable| controls instrumentation of texel
// buffers, which does not require input buffer support.
Optimizer::PassToken CreateInstBindlessCheckPass(
uint32_t desc_set, uint32_t shader_id, bool desc_length_enable = false,
bool desc_init_enable = false, bool buff_oob_enable = false,
bool texbuff_oob_enable = false);
// Create a pass to instrument physical buffer address checking // Create a pass to instrument physical buffer address checking
// This pass instruments all physical buffer address references to check that // This pass instruments all physical buffer address references to check that
@ -789,7 +774,8 @@ Optimizer::PassToken CreateInstBindlessCheckPass(uint32_t shader_id);
// The instrumentation will read and write buffers in debug // The instrumentation will read and write buffers in debug
// descriptor set |desc_set|. It will write |shader_id| in each output record // descriptor set |desc_set|. It will write |shader_id| in each output record
// to identify the shader module which generated the record. // to identify the shader module which generated the record.
Optimizer::PassToken CreateInstBuffAddrCheckPass(uint32_t shader_id); Optimizer::PassToken CreateInstBuffAddrCheckPass(uint32_t desc_set,
uint32_t shader_id);
// Create a pass to instrument OpDebugPrintf instructions. // Create a pass to instrument OpDebugPrintf instructions.
// This pass replaces all OpDebugPrintf instructions with instructions to write // This pass replaces all OpDebugPrintf instructions with instructions to write
@ -901,59 +887,12 @@ Optimizer::PassToken CreateAmdExtToKhrPass();
Optimizer::PassToken CreateInterpolateFixupPass(); Optimizer::PassToken CreateInterpolateFixupPass();
// Removes unused components from composite input variables. Current // Removes unused components from composite input variables. Current
// implementation just removes trailing unused components from input arrays // implementation just removes trailing unused components from input arrays.
// and structs. The pass performs best after maximizing dead code removal. // The pass performs best after maximizing dead code removal. A subsequent dead
// A subsequent dead code elimination pass would be beneficial in removing // code elimination pass would be beneficial in removing newly unused component
// newly unused component types. // types.
//
// WARNING: This pass can only be safely applied standalone to vertex shaders
// as it can otherwise cause interface incompatibilities with the preceding
// shader in the pipeline. If applied to non-vertex shaders, the user should
// follow by applying EliminateDeadOutputStores and
// EliminateDeadOutputComponents to the preceding shader.
Optimizer::PassToken CreateEliminateDeadInputComponentsPass(); Optimizer::PassToken CreateEliminateDeadInputComponentsPass();
// Removes unused components from composite output variables. Current
// implementation just removes trailing unused components from output arrays
// and structs. The pass performs best after eliminating dead output stores.
// A subsequent dead code elimination pass would be beneficial in removing
// newly unused component types. Currently only supports vertex and fragment
// shaders.
//
// WARNING: This pass cannot be safely applied standalone as it can cause
// interface incompatibility with the following shader in the pipeline. The
// user should first apply EliminateDeadInputComponents to the following
// shader, then apply EliminateDeadOutputStores to this shader.
Optimizer::PassToken CreateEliminateDeadOutputComponentsPass();
// Removes unused components from composite input variables. This safe
// version will not cause interface incompatibilities since it only changes
// vertex shaders. The current implementation just removes trailing unused
// components from input structs and input arrays. The pass performs best
// after maximizing dead code removal. A subsequent dead code elimination
// pass would be beneficial in removing newly unused component types.
Optimizer::PassToken CreateEliminateDeadInputComponentsSafePass();
// Analyzes shader and populates |live_locs| and |live_builtins|. Best results
// will be obtained if shader has all dead code eliminated first. |live_locs|
// and |live_builtins| are subsequently used when calling
// CreateEliminateDeadOutputStoresPass on the preceding shader. Currently only
// supports tesc, tese, geom, and frag shaders.
Optimizer::PassToken CreateAnalyzeLiveInputPass(
std::unordered_set<uint32_t>* live_locs,
std::unordered_set<uint32_t>* live_builtins);
// Removes stores to output locations not listed in |live_locs| or
// |live_builtins|. Best results are obtained if constant propagation is
// performed first. A subsequent call to ADCE will eliminate any dead code
// created by the removal of the stores. A subsequent call to
// CreateEliminateDeadOutputComponentsPass will eliminate any dead output
// components created by the elimination of the stores. Currently only supports
// vert, tesc, tese, and geom shaders.
Optimizer::PassToken CreateEliminateDeadOutputStoresPass(
std::unordered_set<uint32_t>* live_locs,
std::unordered_set<uint32_t>* live_builtins);
// Creates a convert-to-sampled-image pass to convert images and/or // Creates a convert-to-sampled-image pass to convert images and/or
// samplers with given pairs of descriptor set and binding to sampled image. // samplers with given pairs of descriptor set and binding to sampled image.
// If a pair of an image and a sampler have the same pair of descriptor set and // If a pair of an image and a sampler have the same pair of descriptor set and
@ -978,28 +917,6 @@ Optimizer::PassToken CreateRemoveDontInlinePass();
// object, currently the pass would remove accesschain pointer argument passed // object, currently the pass would remove accesschain pointer argument passed
// to the function // to the function
Optimizer::PassToken CreateFixFuncCallArgumentsPass(); Optimizer::PassToken CreateFixFuncCallArgumentsPass();
// Creates a trim-capabilities pass.
// This pass removes unused capabilities for a given module, and if possible,
// associated extensions.
// See `trim_capabilities.h` for the list of supported capabilities.
//
// If the module contains unsupported capabilities, this pass will ignore them.
// This should be fine in most cases, but could yield to incorrect results if
// the unknown capability interacts with one of the trimmed capabilities.
Optimizer::PassToken CreateTrimCapabilitiesPass();
// Creates a switch-descriptorset pass.
// This pass changes any DescriptorSet decorations with the value |ds_from| to
// use the new value |ds_to|.
Optimizer::PassToken CreateSwitchDescriptorSetPass(uint32_t ds_from,
uint32_t ds_to);
// Creates an invocation interlock placement pass.
// This pass ensures that an entry point will have at most one
// OpBeginInterlockInvocationEXT and one OpEndInterlockInvocationEXT, in that
// order.
Optimizer::PassToken CreateInvocationInterlockPlacementPass();
} // namespace spvtools } // namespace spvtools
#endif // INCLUDE_SPIRV_TOOLS_OPTIMIZER_HPP_ #endif // INCLUDE_SPIRV_TOOLS_OPTIMIZER_HPP_

View File

@ -23,11 +23,6 @@ set -x
BUILD_ROOT=$PWD BUILD_ROOT=$PWD
SRC=$PWD/github/SPIRV-Tools SRC=$PWD/github/SPIRV-Tools
# This is required to run any git command in the docker since owner will
# have changed between the clone environment, and the docker container.
# Marking the root of the repo as safe for ownership changes.
git config --global --add safe.directory $SRC
# Get clang-format-5.0.0. # Get clang-format-5.0.0.
# Once kokoro upgrades the Ubuntu VMs, we can use 'apt-get install clang-format' # Once kokoro upgrades the Ubuntu VMs, we can use 'apt-get install clang-format'
curl -L http://releases.llvm.org/5.0.0/clang+llvm-5.0.0-linux-x86_64-ubuntu14.04.tar.xz -o clang-llvm.tar.xz curl -L http://releases.llvm.org/5.0.0/clang+llvm-5.0.0-linux-x86_64-ubuntu14.04.tar.xz -o clang-llvm.tar.xz

View File

@ -22,3 +22,4 @@ set -x
SCRIPT_DIR=`dirname "$BASH_SOURCE"` SCRIPT_DIR=`dirname "$BASH_SOURCE"`
source $SCRIPT_DIR/../scripts/macos/build.sh Debug source $SCRIPT_DIR/../scripts/macos/build.sh Debug

View File

@ -24,22 +24,21 @@ CC=clang
CXX=clang++ CXX=clang++
SRC=$PWD/github/SPIRV-Tools SRC=$PWD/github/SPIRV-Tools
# This is required to run any git command in the docker since owner will
# have changed between the clone environment, and the docker container.
# Marking the root of the repo as safe for ownership changes.
git config --global --add safe.directory $SRC
cd $SRC cd $SRC
/usr/bin/python3 utils/git-sync-deps --treeless git clone --depth=1 https://github.com/KhronosGroup/SPIRV-Headers external/spirv-headers
git clone https://github.com/google/googletest external/googletest
cd external && cd googletest && git reset --hard 1fb1bb23bb8418dc73a5a9a82bbed31dc610fec7 && cd .. && cd ..
git clone --depth=1 https://github.com/google/effcee external/effcee
git clone --depth=1 https://github.com/google/re2 external/re2
# Get bazel 5.0.0 # Get bazel 5.0.0
gsutil cp gs://bazel/5.0.0/release/bazel-5.0.0-darwin-x86_64 . gsutil cp gs://bazel/5.0.0/release/bazel-5.0.0-darwin-x86_64 .
chmod +x bazel-5.0.0-darwin-x86_64 chmod +x bazel-5.0.0-darwin-x86_64
echo $(date): Build everything... echo $(date): Build everything...
./bazel-5.0.0-darwin-x86_64 build --cxxopt=-std=c++17 :all ./bazel-5.0.0-darwin-x86_64 build :all
echo $(date): Build completed. echo $(date): Build completed.
echo $(date): Starting bazel test... echo $(date): Starting bazel test...
./bazel-5.0.0-darwin-x86_64 test --cxxopt=-std=c++17 :all ./bazel-5.0.0-darwin-x86_64 test :all
echo $(date): Bazel test completed. echo $(date): Bazel test completed.

View File

@ -22,3 +22,4 @@ set -x
SCRIPT_DIR=`dirname "$BASH_SOURCE"` SCRIPT_DIR=`dirname "$BASH_SOURCE"`
source $SCRIPT_DIR/../scripts/macos/build.sh RelWithDebInfo source $SCRIPT_DIR/../scripts/macos/build.sh RelWithDebInfo

View File

@ -20,11 +20,6 @@ set -e
# Display commands being run. # Display commands being run.
set -x set -x
# This is required to run any git command in the docker since owner will
# have changed between the clone environment, and the docker container.
# Marking the root of the repo as safe for ownership changes.
git config --global --add safe.directory $ROOT_DIR
. /bin/using.sh # Declare the bash `using` function for configuring toolchains. . /bin/using.sh # Declare the bash `using` function for configuring toolchains.
if [ $COMPILER = "clang" ]; then if [ $COMPILER = "clang" ]; then
@ -35,6 +30,14 @@ fi
cd $ROOT_DIR cd $ROOT_DIR
function clone_if_missing() {
url=$1
dir=$2
if [[ ! -d "$dir" ]]; then
git clone ${@:3} "$url" "$dir"
fi
}
function clean_dir() { function clean_dir() {
dir=$1 dir=$1
if [[ -d "$dir" ]]; then if [[ -d "$dir" ]]; then
@ -43,10 +46,12 @@ function clean_dir() {
mkdir "$dir" mkdir "$dir"
} }
if [ $TOOL != "cmake-smoketest" ]; then clone_if_missing https://github.com/KhronosGroup/SPIRV-Headers external/spirv-headers --depth=1
# Get source for dependencies, as specified in the DEPS file clone_if_missing https://github.com/google/googletest external/googletest
/usr/bin/python3 utils/git-sync-deps --treeless pushd external/googletest; git reset --hard 1fb1bb23bb8418dc73a5a9a82bbed31dc610fec7; popd
fi clone_if_missing https://github.com/google/effcee external/effcee --depth=1
clone_if_missing https://github.com/google/re2 external/re2 --depth=1
clone_if_missing https://github.com/protocolbuffers/protobuf external/protobuf --branch v3.13.0.1
if [ $TOOL = "cmake" ]; then if [ $TOOL = "cmake" ]; then
using cmake-3.17.2 using cmake-3.17.2
@ -131,7 +136,6 @@ elif [ $TOOL = "cmake-smoketest" ]; then
git clone https://github.com/KhronosGroup/SPIRV-Headers.git spirv-headers git clone https://github.com/KhronosGroup/SPIRV-Headers.git spirv-headers
git clone https://github.com/google/re2 git clone https://github.com/google/re2
git clone https://github.com/google/effcee git clone https://github.com/google/effcee
git clone https://github.com/abseil/abseil-cpp abseil_cpp
cd $SHADERC_DIR cd $SHADERC_DIR
mkdir build mkdir build
@ -142,7 +146,7 @@ elif [ $TOOL = "cmake-smoketest" ]; then
cmake -GNinja -DRE2_BUILD_TESTING=OFF -DCMAKE_BUILD_TYPE="Release" .. cmake -GNinja -DRE2_BUILD_TESTING=OFF -DCMAKE_BUILD_TYPE="Release" ..
echo $(date): Build glslang... echo $(date): Build glslang...
ninja glslang-standalone ninja glslangValidator
echo $(date): Build everything... echo $(date): Build everything...
ninja ninja
@ -156,7 +160,7 @@ elif [ $TOOL = "cmake-smoketest" ]; then
echo $(date): ctest completed. echo $(date): ctest completed.
elif [ $TOOL = "cmake-android-ndk" ]; then elif [ $TOOL = "cmake-android-ndk" ]; then
using cmake-3.17.2 using cmake-3.17.2
using ndk-r25c using ndk-r21d
using ninja-1.10.0 using ninja-1.10.0
clean_dir "$ROOT_DIR/build" clean_dir "$ROOT_DIR/build"
@ -164,7 +168,7 @@ elif [ $TOOL = "cmake-android-ndk" ]; then
echo $(date): Starting build... echo $(date): Starting build...
cmake -DCMAKE_BUILD_TYPE=Release \ cmake -DCMAKE_BUILD_TYPE=Release \
-DANDROID_NATIVE_API_LEVEL=android-24 \ -DANDROID_NATIVE_API_LEVEL=android-16 \
-DANDROID_ABI="armeabi-v7a with NEON" \ -DANDROID_ABI="armeabi-v7a with NEON" \
-DSPIRV_SKIP_TESTS=ON \ -DSPIRV_SKIP_TESTS=ON \
-DCMAKE_TOOLCHAIN_FILE="$ANDROID_NDK_HOME/build/cmake/android.toolchain.cmake" \ -DCMAKE_TOOLCHAIN_FILE="$ANDROID_NDK_HOME/build/cmake/android.toolchain.cmake" \
@ -176,7 +180,7 @@ elif [ $TOOL = "cmake-android-ndk" ]; then
ninja ninja
echo $(date): Build completed. echo $(date): Build completed.
elif [ $TOOL = "android-ndk-build" ]; then elif [ $TOOL = "android-ndk-build" ]; then
using ndk-r25c using ndk-r21d
clean_dir "$ROOT_DIR/build" clean_dir "$ROOT_DIR/build"
cd "$ROOT_DIR/build" cd "$ROOT_DIR/build"
@ -194,10 +198,10 @@ elif [ $TOOL = "bazel" ]; then
using bazel-5.0.0 using bazel-5.0.0
echo $(date): Build everything... echo $(date): Build everything...
bazel build --cxxopt=-std=c++17 :all bazel build :all
echo $(date): Build completed. echo $(date): Build completed.
echo $(date): Starting bazel test... echo $(date): Starting bazel test...
bazel test --cxxopt=-std=c++17 :all bazel test :all
echo $(date): Bazel test completed. echo $(date): Bazel test completed.
fi fi

View File

@ -26,18 +26,6 @@ COMPILER=$2
TOOL=$3 TOOL=$3
BUILD_SHA=${KOKORO_GITHUB_COMMIT:-$KOKORO_GITHUB_PULL_REQUEST_COMMIT} BUILD_SHA=${KOKORO_GITHUB_COMMIT:-$KOKORO_GITHUB_PULL_REQUEST_COMMIT}
# chown the given directory to the current user, if it exists.
# Docker creates files with the root user - this can upset the Kokoro artifact copier.
function chown_dir() {
dir=$1
if [[ -d "$dir" ]]; then
sudo chown -R "$(id -u):$(id -g)" "$dir"
fi
}
set +e
# Allow build failures
# "--privileged" is required to run ptrace in the asan builds. # "--privileged" is required to run ptrace in the asan builds.
docker run --rm -i \ docker run --rm -i \
--privileged \ --privileged \
@ -53,11 +41,16 @@ docker run --rm -i \
--env BUILD_SHA="${BUILD_SHA}" \ --env BUILD_SHA="${BUILD_SHA}" \
--entrypoint "${SCRIPT_DIR}/build-docker.sh" \ --entrypoint "${SCRIPT_DIR}/build-docker.sh" \
"gcr.io/shaderc-build/radial-build:latest" "gcr.io/shaderc-build/radial-build:latest"
RESULT=$?
# This is important. If the permissions are not fixed, kokoro will fail
# to pull build artifacts, and put the build in tool-failure state, which # chown the given directory to the current user, if it exists.
# blocks the logs. # Docker creates files with the root user - this can upset the Kokoro artifact copier.
function chown_dir() {
dir=$1
if [[ -d "$dir" ]]; then
sudo chown -R "$(id -u):$(id -g)" "$dir"
fi
}
chown_dir "${ROOT_DIR}/build" chown_dir "${ROOT_DIR}/build"
chown_dir "${ROOT_DIR}/external" chown_dir "${ROOT_DIR}/external"
exit $RESULT

View File

@ -24,11 +24,6 @@ BUILD_ROOT=$PWD
SRC=$PWD/github/SPIRV-Tools SRC=$PWD/github/SPIRV-Tools
BUILD_TYPE=$1 BUILD_TYPE=$1
# This is required to run any git command in the docker since owner will
# have changed between the clone environment, and the docker container.
# Marking the root of the repo as safe for ownership changes.
git config --global --add safe.directory $SRC
# Get NINJA. # Get NINJA.
wget -q https://github.com/ninja-build/ninja/releases/download/v1.8.2/ninja-mac.zip wget -q https://github.com/ninja-build/ninja/releases/download/v1.8.2/ninja-mac.zip
unzip -q ninja-mac.zip unzip -q ninja-mac.zip
@ -36,16 +31,23 @@ chmod +x ninja
export PATH="$PWD:$PATH" export PATH="$PWD:$PATH"
cd $SRC cd $SRC
python3 utils/git-sync-deps --treeless git clone --depth=1 https://github.com/KhronosGroup/SPIRV-Headers external/spirv-headers
git clone https://github.com/google/googletest external/googletest
cd external && cd googletest && git reset --hard 1fb1bb23bb8418dc73a5a9a82bbed31dc610fec7 && cd .. && cd ..
git clone --depth=1 https://github.com/google/effcee external/effcee
git clone --depth=1 https://github.com/google/re2 external/re2
git clone --depth=1 --branch v3.13.0.1 https://github.com/protocolbuffers/protobuf external/protobuf
mkdir build && cd $SRC/build mkdir build && cd $SRC/build
# Invoke the build. # Invoke the build.
BUILD_SHA=${KOKORO_GITHUB_COMMIT:-$KOKORO_GITHUB_PULL_REQUEST_COMMIT} BUILD_SHA=${KOKORO_GITHUB_COMMIT:-$KOKORO_GITHUB_PULL_REQUEST_COMMIT}
echo $(date): Starting build... echo $(date): Starting build...
# We need Python 3. At the moment python3.7 is the newest Python on Kokoro.
cmake \ cmake \
-GNinja \ -GNinja \
-DCMAKE_INSTALL_PREFIX=$KOKORO_ARTIFACTS_DIR/install \ -DCMAKE_INSTALL_PREFIX=$KOKORO_ARTIFACTS_DIR/install \
-DPYTHON_EXECUTABLE:FILEPATH=/usr/local/bin/python3.7 \
-DCMAKE_C_COMPILER=clang \ -DCMAKE_C_COMPILER=clang \
-DCMAKE_CXX_COMPILER=clang++ \ -DCMAKE_CXX_COMPILER=clang++ \
-DCMAKE_BUILD_TYPE=$BUILD_TYPE \ -DCMAKE_BUILD_TYPE=$BUILD_TYPE \

View File

@ -24,23 +24,26 @@ set VS_VERSION=%2
:: Force usage of python 3.6 :: Force usage of python 3.6
set PATH=C:\python36;"C:\Program Files\cmake-3.23.1-windows-x86_64\bin";%PATH% set PATH=C:\python36;"C:\Program Files\cmake-3.23.1-windows-x86_64\bin";%PATH%
cd %SRC%
git clone --depth=1 https://github.com/KhronosGroup/SPIRV-Headers external/spirv-headers
git clone https://github.com/google/googletest external/googletest
cd external && cd googletest && git reset --hard 1fb1bb23bb8418dc73a5a9a82bbed31dc610fec7 && cd .. && cd ..
git clone --depth=1 https://github.com/google/effcee external/effcee
git clone --depth=1 https://github.com/google/re2 external/re2
git clone --depth=1 --branch v3.13.0.1 https://github.com/protocolbuffers/protobuf external/protobuf
:: ######################################### :: #########################################
:: set up msvc build env :: set up msvc build env
:: ######################################### :: #########################################
if %VS_VERSION% == 2017 ( if %VS_VERSION% == 2017 (
call "C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Auxiliary\Build\vcvarsall.bat" x64 call "C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Auxiliary\Build\vcvarsall.bat" x64
echo "Using VS 2017..." echo "Using VS 2017..."
) else if %VS_VERSION% == 2015 (
:: RE2 does not support VS2017, we we must disable tests. call "C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat" x64
set BUILD_TESTS=NO echo "Using VS 2015..."
) else if %VS_VERSION% == 2019 (
call "C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Auxiliary\Build\vcvarsall.bat" x64
echo "Using VS 2019..."
) )
cd %SRC% cd %SRC%
python utils/git-sync-deps --treeless
mkdir build mkdir build
cd build cd build
@ -59,10 +62,6 @@ set CMAKE_FLAGS=-DCMAKE_INSTALL_PREFIX=%KOKORO_ARTIFACTS_DIR%\install -GNinja -D
:: Build spirv-fuzz :: Build spirv-fuzz
set CMAKE_FLAGS=%CMAKE_FLAGS% -DSPIRV_BUILD_FUZZER=ON set CMAKE_FLAGS=%CMAKE_FLAGS% -DSPIRV_BUILD_FUZZER=ON
if "%BUILD_TESTS%" == "NO" (
set CMAKE_FLAGS=-DSPIRV_SKIP_TESTS=ON %CMAKE_FLAGS%
)
cmake %CMAKE_FLAGS% .. cmake %CMAKE_FLAGS% ..
if %ERRORLEVEL% NEQ 0 exit /b %ERRORLEVEL% if %ERRORLEVEL% NEQ 0 exit /b %ERRORLEVEL%
@ -78,12 +77,10 @@ setlocal ENABLEDELAYEDEXPANSION
:: ################################################ :: ################################################
:: Run the tests :: Run the tests
:: ################################################ :: ################################################
if "%BUILD_TESTS%" NEQ "NO" ( echo "Running Tests... %DATE% %TIME%"
echo "Running Tests... %DATE% %TIME%" ctest -C %BUILD_TYPE% --output-on-failure --timeout 300
ctest -C %BUILD_TYPE% --output-on-failure --timeout 300 if !ERRORLEVEL! NEQ 0 exit /b !ERRORLEVEL!
if !ERRORLEVEL! NEQ 0 exit /b !ERRORLEVEL! echo "Tests Completed %DATE% %TIME%"
echo "Tests Completed %DATE% %TIME%"
)
:: ################################################ :: ################################################
:: Install and package. :: Install and package.

View File

@ -1,4 +1,4 @@
:: Copyright (c) 2023 Google LLC :: Copyright (c) 2018 Google LLC.
:: ::
:: Licensed under the Apache License, Version 2.0 (the "License"); :: Licensed under the Apache License, Version 2.0 (the "License");
:: you may not use this file except in compliance with the License. :: you may not use this file except in compliance with the License.
@ -20,5 +20,5 @@
set SCRIPT_DIR=%~dp0 set SCRIPT_DIR=%~dp0
:: Call with correct parameter :: Call with correct parameter
call %SCRIPT_DIR%\..\scripts\windows\build.bat RelWithDebInfo 2019 call %SCRIPT_DIR%\..\scripts\windows\build.bat RelWithDebInfo 2013

View File

@ -1,4 +1,4 @@
# Copyright (c) 2023 Google LLC. # Copyright (c) 2018 Google LLC.
# #
# Licensed under the Apache License, Version 2.0 (the "License"); # Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License. # you may not use this file except in compliance with the License.
@ -13,10 +13,4 @@
# limitations under the License. # limitations under the License.
# Continuous build configuration. # Continuous build configuration.
build_file: "SPIRV-Tools/kokoro/windows-msvc-2019-release/build.bat" build_file: "SPIRV-Tools/kokoro/windows-msvc-2013-release/build.bat"
action {
define_artifacts {
regex: "install.zip"
}
}

View File

@ -1,4 +1,4 @@
# Copyright (c) 2023 Google LLC. # Copyright (c) 2018 Google LLC.
# #
# Licensed under the Apache License, Version 2.0 (the "License"); # Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License. # you may not use this file except in compliance with the License.
@ -13,4 +13,4 @@
# limitations under the License. # limitations under the License.
# Presubmit build configuration. # Presubmit build configuration.
build_file: "SPIRV-Tools/kokoro/windows-msvc-2019-release/build.bat" build_file: "SPIRV-Tools/kokoro/windows-msvc-2013-release/build.bat"

View File

@ -0,0 +1,59 @@
:: Copyright (c) 2019 Google LLC.
::
:: Licensed under the Apache License, Version 2.0 (the "License");
:: you may not use this file except in compliance with the License.
:: You may obtain a copy of the License at
::
:: http://www.apache.org/licenses/LICENSE-2.0
::
:: Unless required by applicable law or agreed to in writing, software
:: distributed under the License is distributed on an "AS IS" BASIS,
:: WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
:: See the License for the specific language governing permissions and
:: limitations under the License.
::
:: Windows Build Script.
@echo on
set SRC=%cd%\github\SPIRV-Tools
:: Force usage of python 3.6
set PATH=C:\python36;%PATH%
:: Get dependencies
cd %SRC%
git clone --depth=1 https://github.com/KhronosGroup/SPIRV-Headers external/spirv-headers
git clone https://github.com/google/googletest external/googletest
cd external && cd googletest && git reset --hard 1fb1bb23bb8418dc73a5a9a82bbed31dc610fec7 && cd .. && cd ..
git clone --depth=1 https://github.com/google/effcee external/effcee
git clone --depth=1 https://github.com/google/re2 external/re2
:: REM Install Bazel.
wget -q https://github.com/bazelbuild/bazel/releases/download/5.0.0/bazel-5.0.0-windows-x86_64.zip
unzip -q bazel-5.0.0-windows-x86_64.zip
:: Set up MSVC
call "C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat" x64
set BAZEL_VS=C:\Program Files (x86)\Microsoft Visual Studio 14.0
set BAZEL_VC=C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC
set BAZEL_PYTHON=c:\tools\python2\python.exe
:: #########################################
:: Start building.
:: #########################################
echo "Build everything... %DATE% %TIME%"
bazel.exe build :all
if %ERRORLEVEL% NEQ 0 exit /b %ERRORLEVEL%
echo "Build Completed %DATE% %TIME%"
:: ##############
:: Run the tests
:: ##############
echo "Running Tests... %DATE% %TIME%"
bazel.exe test :all
if %ERRORLEVEL% NEQ 0 exit /b %ERRORLEVEL%
echo "Tests Completed %DATE% %TIME%"
exit /b 0

View File

@ -0,0 +1,16 @@
# Copyright (c) 2019 Google LLC.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# Continuous build configuration.
build_file: "SPIRV-Tools/kokoro/windows-msvc-2015-release-bazel/build.bat"

View File

@ -0,0 +1,16 @@
# Copyright (c) 2019 Google LLC.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# Presubmit build configuration.
build_file: "SPIRV-Tools/kokoro/windows-msvc-2015-release-bazel/build.bat"

View File

@ -0,0 +1,24 @@
:: Copyright (c) 2018 Google LLC.
::
:: Licensed under the Apache License, Version 2.0 (the "License");
:: you may not use this file except in compliance with the License.
:: You may obtain a copy of the License at
::
:: http://www.apache.org/licenses/LICENSE-2.0
::
:: Unless required by applicable law or agreed to in writing, software
:: distributed under the License is distributed on an "AS IS" BASIS,
:: WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
:: See the License for the specific language governing permissions and
:: limitations under the License.
::
:: Windows Build Script.
@echo on
:: Find out the directory of the common build script.
set SCRIPT_DIR=%~dp0
:: Call with correct parameter
call %SCRIPT_DIR%\..\scripts\windows\build.bat RelWithDebInfo 2015

View File

@ -0,0 +1,16 @@
# Copyright (c) 2018 Google LLC.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# Continuous build configuration.
build_file: "SPIRV-Tools/kokoro/windows-msvc-2015-release/build.bat"

View File

@ -0,0 +1,16 @@
# Copyright (c) 2018 Google LLC.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# Presubmit build configuration.
build_file: "SPIRV-Tools/kokoro/windows-msvc-2015-release/build.bat"

View File

@ -1,4 +1,4 @@
:: Copyright (c) 2023 Google LLC :: Copyright (c) 2018 Google LLC.
:: ::
:: Licensed under the Apache License, Version 2.0 (the "License"); :: Licensed under the Apache License, Version 2.0 (the "License");
:: you may not use this file except in compliance with the License. :: you may not use this file except in compliance with the License.
@ -20,4 +20,4 @@
set SCRIPT_DIR=%~dp0 set SCRIPT_DIR=%~dp0
:: Call with correct parameter :: Call with correct parameter
call %SCRIPT_DIR%\..\scripts\windows\build.bat Debug 2019 call %SCRIPT_DIR%\..\scripts\windows\build.bat Debug 2017

View File

@ -1,4 +1,4 @@
# Copyright (c) 2023 Google LLC # Copyright (c) 2018 Google LLC.
# #
# Licensed under the Apache License, Version 2.0 (the "License"); # Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License. # you may not use this file except in compliance with the License.
@ -13,7 +13,7 @@
# limitations under the License. # limitations under the License.
# Continuous build configuration. # Continuous build configuration.
build_file: "SPIRV-Tools/kokoro/windows-msvc-2019-debug/build.bat" build_file: "SPIRV-Tools/kokoro/windows-msvc-2017-debug/build.bat"
action { action {
define_artifacts { define_artifacts {

View File

@ -1,4 +1,4 @@
# Copyright (c) 2023 Google LLC # Copyright (c) 2018 Google LLC.
# #
# Licensed under the Apache License, Version 2.0 (the "License"); # Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License. # you may not use this file except in compliance with the License.
@ -13,4 +13,4 @@
# limitations under the License. # limitations under the License.
# Presubmit build configuration. # Presubmit build configuration.
build_file: "SPIRV-Tools/kokoro/windows-msvc-2019-debug/build.bat" build_file: "SPIRV-Tools/kokoro/windows-msvc-2017-debug/build.bat"

0
read.me Executable file → Normal file
View File

View File

@ -31,13 +31,12 @@ macro(spvtools_core_tables CONFIG_VERSION)
set(GRAMMAR_INSTS_INC_FILE "${spirv-tools_BINARY_DIR}/core.insts-${CONFIG_VERSION}.inc") set(GRAMMAR_INSTS_INC_FILE "${spirv-tools_BINARY_DIR}/core.insts-${CONFIG_VERSION}.inc")
set(GRAMMAR_KINDS_INC_FILE "${spirv-tools_BINARY_DIR}/operand.kinds-${CONFIG_VERSION}.inc") set(GRAMMAR_KINDS_INC_FILE "${spirv-tools_BINARY_DIR}/operand.kinds-${CONFIG_VERSION}.inc")
add_custom_command(OUTPUT ${GRAMMAR_INSTS_INC_FILE} ${GRAMMAR_KINDS_INC_FILE} add_custom_command(OUTPUT ${GRAMMAR_INSTS_INC_FILE} ${GRAMMAR_KINDS_INC_FILE}
COMMAND Python3::Interpreter ${GRAMMAR_PROCESSING_SCRIPT} COMMAND ${PYTHON_EXECUTABLE} ${GRAMMAR_PROCESSING_SCRIPT}
--spirv-core-grammar=${GRAMMAR_JSON_FILE} --spirv-core-grammar=${GRAMMAR_JSON_FILE}
--extinst-debuginfo-grammar=${DEBUGINFO_GRAMMAR_JSON_FILE} --extinst-debuginfo-grammar=${DEBUGINFO_GRAMMAR_JSON_FILE}
--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}
@ -53,13 +52,12 @@ macro(spvtools_enum_string_mapping CONFIG_VERSION)
set(GRAMMAR_ENUM_STRING_MAPPING_INC_FILE "${spirv-tools_BINARY_DIR}/enum_string_mapping.inc") set(GRAMMAR_ENUM_STRING_MAPPING_INC_FILE "${spirv-tools_BINARY_DIR}/enum_string_mapping.inc")
add_custom_command(OUTPUT ${GRAMMAR_EXTENSION_ENUM_INC_FILE} add_custom_command(OUTPUT ${GRAMMAR_EXTENSION_ENUM_INC_FILE}
${GRAMMAR_ENUM_STRING_MAPPING_INC_FILE} ${GRAMMAR_ENUM_STRING_MAPPING_INC_FILE}
COMMAND Python3::Interpreter ${GRAMMAR_PROCESSING_SCRIPT} COMMAND ${PYTHON_EXECUTABLE} ${GRAMMAR_PROCESSING_SCRIPT}
--spirv-core-grammar=${GRAMMAR_JSON_FILE} --spirv-core-grammar=${GRAMMAR_JSON_FILE}
--extinst-debuginfo-grammar=${DEBUGINFO_GRAMMAR_JSON_FILE} --extinst-debuginfo-grammar=${DEBUGINFO_GRAMMAR_JSON_FILE}
--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}
@ -75,7 +73,7 @@ macro(spvtools_vimsyntax CONFIG_VERSION CLVERSION)
set(OPENCL_GRAMMAR_JSON_FILE "${SPIRV_HEADER_INCLUDE_DIR}/spirv/${CONFIG_VERSION}/extinst.opencl.std.100.grammar.json") set(OPENCL_GRAMMAR_JSON_FILE "${SPIRV_HEADER_INCLUDE_DIR}/spirv/${CONFIG_VERSION}/extinst.opencl.std.100.grammar.json")
set(VIMSYNTAX_FILE "${spirv-tools_BINARY_DIR}/spvasm.vim") set(VIMSYNTAX_FILE "${spirv-tools_BINARY_DIR}/spvasm.vim")
add_custom_command(OUTPUT ${VIMSYNTAX_FILE} add_custom_command(OUTPUT ${VIMSYNTAX_FILE}
COMMAND Python3::Interpreter ${VIMSYNTAX_PROCESSING_SCRIPT} COMMAND ${PYTHON_EXECUTABLE} ${VIMSYNTAX_PROCESSING_SCRIPT}
--spirv-core-grammar=${GRAMMAR_JSON_FILE} --spirv-core-grammar=${GRAMMAR_JSON_FILE}
--extinst-debuginfo-grammar=${DEBUGINFO_GRAMMAR_JSON_FILE} --extinst-debuginfo-grammar=${DEBUGINFO_GRAMMAR_JSON_FILE}
--extinst-glsl-grammar=${GLSL_GRAMMAR_JSON_FILE} --extinst-glsl-grammar=${GLSL_GRAMMAR_JSON_FILE}
@ -91,10 +89,9 @@ macro(spvtools_glsl_tables CONFIG_VERSION)
set(GLSL_GRAMMAR_JSON_FILE "${SPIRV_HEADER_INCLUDE_DIR}/spirv/${CONFIG_VERSION}/extinst.glsl.std.450.grammar.json") set(GLSL_GRAMMAR_JSON_FILE "${SPIRV_HEADER_INCLUDE_DIR}/spirv/${CONFIG_VERSION}/extinst.glsl.std.450.grammar.json")
set(GRAMMAR_INC_FILE "${spirv-tools_BINARY_DIR}/glsl.std.450.insts.inc") set(GRAMMAR_INC_FILE "${spirv-tools_BINARY_DIR}/glsl.std.450.insts.inc")
add_custom_command(OUTPUT ${GRAMMAR_INC_FILE} add_custom_command(OUTPUT ${GRAMMAR_INC_FILE}
COMMAND Python3::Interpreter ${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})
@ -105,7 +102,7 @@ macro(spvtools_opencl_tables CONFIG_VERSION)
set(OPENCL_GRAMMAR_JSON_FILE "${SPIRV_HEADER_INCLUDE_DIR}/spirv/${CONFIG_VERSION}/extinst.opencl.std.100.grammar.json") set(OPENCL_GRAMMAR_JSON_FILE "${SPIRV_HEADER_INCLUDE_DIR}/spirv/${CONFIG_VERSION}/extinst.opencl.std.100.grammar.json")
set(GRAMMAR_INC_FILE "${spirv-tools_BINARY_DIR}/opencl.std.insts.inc") set(GRAMMAR_INC_FILE "${spirv-tools_BINARY_DIR}/opencl.std.insts.inc")
add_custom_command(OUTPUT ${GRAMMAR_INC_FILE} add_custom_command(OUTPUT ${GRAMMAR_INC_FILE}
COMMAND Python3::Interpreter ${GRAMMAR_PROCESSING_SCRIPT} COMMAND ${PYTHON_EXECUTABLE} ${GRAMMAR_PROCESSING_SCRIPT}
--extinst-opencl-grammar=${OPENCL_GRAMMAR_JSON_FILE} --extinst-opencl-grammar=${OPENCL_GRAMMAR_JSON_FILE}
--opencl-insts-output=${GRAMMAR_INC_FILE} --opencl-insts-output=${GRAMMAR_INC_FILE}
DEPENDS ${GRAMMAR_PROCESSING_SCRIPT} ${CORE_GRAMMAR_JSON_FILE} ${OPENCL_GRAMMAR_JSON_FILE} DEPENDS ${GRAMMAR_PROCESSING_SCRIPT} ${CORE_GRAMMAR_JSON_FILE} ${OPENCL_GRAMMAR_JSON_FILE}
@ -120,7 +117,7 @@ macro(spvtools_vendor_tables VENDOR_TABLE SHORT_NAME OPERAND_KIND_PREFIX)
set(GRAMMAR_FILE "${spirv-tools_SOURCE_DIR}/source/extinst.${VENDOR_TABLE}.grammar.json") set(GRAMMAR_FILE "${spirv-tools_SOURCE_DIR}/source/extinst.${VENDOR_TABLE}.grammar.json")
endif() endif()
add_custom_command(OUTPUT ${INSTS_FILE} add_custom_command(OUTPUT ${INSTS_FILE}
COMMAND Python3::Interpreter ${GRAMMAR_PROCESSING_SCRIPT} COMMAND ${PYTHON_EXECUTABLE} ${GRAMMAR_PROCESSING_SCRIPT}
--extinst-vendor-grammar=${GRAMMAR_FILE} --extinst-vendor-grammar=${GRAMMAR_FILE}
--vendor-insts-output=${INSTS_FILE} --vendor-insts-output=${INSTS_FILE}
--vendor-operand-kind-prefix=${OPERAND_KIND_PREFIX} --vendor-operand-kind-prefix=${OPERAND_KIND_PREFIX}
@ -134,7 +131,7 @@ endmacro(spvtools_vendor_tables)
macro(spvtools_extinst_lang_headers NAME GRAMMAR_FILE) macro(spvtools_extinst_lang_headers NAME GRAMMAR_FILE)
set(OUT_H ${spirv-tools_BINARY_DIR}/${NAME}.h) set(OUT_H ${spirv-tools_BINARY_DIR}/${NAME}.h)
add_custom_command(OUTPUT ${OUT_H} add_custom_command(OUTPUT ${OUT_H}
COMMAND Python3::Interpreter ${LANG_HEADER_PROCESSING_SCRIPT} COMMAND ${PYTHON_EXECUTABLE} ${LANG_HEADER_PROCESSING_SCRIPT}
--extinst-grammar=${GRAMMAR_FILE} --extinst-grammar=${GRAMMAR_FILE}
--extinst-output-path=${OUT_H} --extinst-output-path=${OUT_H}
DEPENDS ${LANG_HEADER_PROCESSING_SCRIPT} ${GRAMMAR_FILE} DEPENDS ${LANG_HEADER_PROCESSING_SCRIPT} ${GRAMMAR_FILE}
@ -168,7 +165,7 @@ set_property(TARGET spirv-tools-vimsyntax PROPERTY FOLDER "SPIRV-Tools utilities
set(GENERATOR_INC_FILE ${spirv-tools_BINARY_DIR}/generators.inc) set(GENERATOR_INC_FILE ${spirv-tools_BINARY_DIR}/generators.inc)
set(SPIRV_XML_REGISTRY_FILE ${SPIRV_HEADER_INCLUDE_DIR}/spirv/spir-v.xml) set(SPIRV_XML_REGISTRY_FILE ${SPIRV_HEADER_INCLUDE_DIR}/spirv/spir-v.xml)
add_custom_command(OUTPUT ${GENERATOR_INC_FILE} add_custom_command(OUTPUT ${GENERATOR_INC_FILE}
COMMAND Python3::Interpreter ${XML_REGISTRY_PROCESSING_SCRIPT} COMMAND ${PYTHON_EXECUTABLE} ${XML_REGISTRY_PROCESSING_SCRIPT}
--xml=${SPIRV_XML_REGISTRY_FILE} --xml=${SPIRV_XML_REGISTRY_FILE}
--generator-output=${GENERATOR_INC_FILE} --generator-output=${GENERATOR_INC_FILE}
DEPENDS ${XML_REGISTRY_PROCESSING_SCRIPT} ${SPIRV_XML_REGISTRY_FILE} DEPENDS ${XML_REGISTRY_PROCESSING_SCRIPT} ${SPIRV_XML_REGISTRY_FILE}
@ -198,7 +195,7 @@ set(SPIRV_TOOLS_BUILD_VERSION_INC_GENERATOR
set(SPIRV_TOOLS_CHANGES_FILE set(SPIRV_TOOLS_CHANGES_FILE
${spirv-tools_SOURCE_DIR}/CHANGES) ${spirv-tools_SOURCE_DIR}/CHANGES)
add_custom_command(OUTPUT ${SPIRV_TOOLS_BUILD_VERSION_INC} add_custom_command(OUTPUT ${SPIRV_TOOLS_BUILD_VERSION_INC}
COMMAND Python3::Interpreter COMMAND ${PYTHON_EXECUTABLE}
${SPIRV_TOOLS_BUILD_VERSION_INC_GENERATOR} ${SPIRV_TOOLS_BUILD_VERSION_INC_GENERATOR}
${SPIRV_TOOLS_CHANGES_FILE} ${SPIRV_TOOLS_BUILD_VERSION_INC} ${SPIRV_TOOLS_CHANGES_FILE} ${SPIRV_TOOLS_BUILD_VERSION_INC}
DEPENDS ${SPIRV_TOOLS_BUILD_VERSION_INC_GENERATOR} DEPENDS ${SPIRV_TOOLS_BUILD_VERSION_INC_GENERATOR}
@ -328,7 +325,6 @@ set(SPIRV_SOURCES
${CMAKE_CURRENT_SOURCE_DIR}/val/validate_primitives.cpp ${CMAKE_CURRENT_SOURCE_DIR}/val/validate_primitives.cpp
${CMAKE_CURRENT_SOURCE_DIR}/val/validate_ray_query.cpp ${CMAKE_CURRENT_SOURCE_DIR}/val/validate_ray_query.cpp
${CMAKE_CURRENT_SOURCE_DIR}/val/validate_ray_tracing.cpp ${CMAKE_CURRENT_SOURCE_DIR}/val/validate_ray_tracing.cpp
${CMAKE_CURRENT_SOURCE_DIR}/val/validate_ray_tracing_reorder.cpp
${CMAKE_CURRENT_SOURCE_DIR}/val/validate_scopes.cpp ${CMAKE_CURRENT_SOURCE_DIR}/val/validate_scopes.cpp
${CMAKE_CURRENT_SOURCE_DIR}/val/validate_small_type_uses.cpp ${CMAKE_CURRENT_SOURCE_DIR}/val/validate_small_type_uses.cpp
${CMAKE_CURRENT_SOURCE_DIR}/val/validate_type.cpp ${CMAKE_CURRENT_SOURCE_DIR}/val/validate_type.cpp
@ -418,8 +414,17 @@ if("${CMAKE_SYSTEM_NAME}" STREQUAL "Linux")
endif() endif()
endif() endif()
if (ANDROID)
foreach(target ${SPIRV_TOOLS_TARGETS})
target_link_libraries(${target} PRIVATE android log)
endforeach()
endif()
if(ENABLE_SPIRV_TOOLS_INSTALL) if(ENABLE_SPIRV_TOOLS_INSTALL)
install(TARGETS ${SPIRV_TOOLS_TARGETS} EXPORT ${SPIRV_TOOLS}Targets) install(TARGETS ${SPIRV_TOOLS_TARGETS} EXPORT ${SPIRV_TOOLS}Targets
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR})
export(EXPORT ${SPIRV_TOOLS}Targets FILE ${SPIRV_TOOLS}Target.cmake) export(EXPORT ${SPIRV_TOOLS}Targets FILE ${SPIRV_TOOLS}Target.cmake)
spvtools_config_package_dir(${SPIRV_TOOLS} PACKAGE_DIR) spvtools_config_package_dir(${SPIRV_TOOLS} PACKAGE_DIR)

View File

@ -21,7 +21,6 @@
#include "source/ext_inst.h" #include "source/ext_inst.h"
#include "source/opcode.h" #include "source/opcode.h"
#include "source/operand.h" #include "source/operand.h"
#include "source/spirv_target_env.h"
#include "source/table.h" #include "source/table.h"
namespace spvtools { namespace spvtools {
@ -79,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 {
spv::Op opcode; SpvOp 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 // The name does not have the usual "Op" prefix. For example opcode SpvOpIAdd
// spv::Op::IAdd is associated with the name "IAdd". // is associated with the name "IAdd".
// //
// clang-format off // clang-format off
#define CASE(NAME) { spv::Op::Op##NAME, #NAME } #define CASE(NAME) { SpvOp##NAME, #NAME }
const SpecConstantOpcodeEntry kOpSpecConstantOpcodes[] = { const SpecConstantOpcodeEntry kOpSpecConstantOpcodes[] = {
// Conversion // Conversion
CASE(SConvert), CASE(SConvert),
@ -155,12 +154,11 @@ const SpecConstantOpcodeEntry kOpSpecConstantOpcodes[] = {
CASE(InBoundsAccessChain), CASE(InBoundsAccessChain),
CASE(PtrAccessChain), CASE(PtrAccessChain),
CASE(InBoundsPtrAccessChain), CASE(InBoundsPtrAccessChain),
CASE(CooperativeMatrixLengthNV), CASE(CooperativeMatrixLengthNV)
CASE(CooperativeMatrixLengthKHR)
}; };
// The 60 is determined by counting the opcodes listed in the spec. // The 60 is determined by counting the opcodes listed in the spec.
static_assert(61 == sizeof(kOpSpecConstantOpcodes)/sizeof(kOpSpecConstantOpcodes[0]), static_assert(60 == sizeof(kOpSpecConstantOpcodes)/sizeof(kOpSpecConstantOpcodes[0]),
"OpSpecConstantOp opcode table is incomplete"); "OpSpecConstantOp opcode table is incomplete");
#undef CASE #undef CASE
// clang-format on // clang-format on
@ -175,20 +173,17 @@ bool AssemblyGrammar::isValid() const {
} }
CapabilitySet AssemblyGrammar::filterCapsAgainstTargetEnv( CapabilitySet AssemblyGrammar::filterCapsAgainstTargetEnv(
const spv::Capability* cap_array, uint32_t count) const { const SpvCapability* cap_array, uint32_t count) const {
CapabilitySet cap_set; CapabilitySet cap_set;
const auto version = spvVersionForTargetEnv(target_env_);
for (uint32_t i = 0; i < count; ++i) { for (uint32_t i = 0; i < count; ++i) {
spv_operand_desc entry = {}; spv_operand_desc cap_desc = {};
if (SPV_SUCCESS == lookupOperand(SPV_OPERAND_TYPE_CAPABILITY, if (SPV_SUCCESS == lookupOperand(SPV_OPERAND_TYPE_CAPABILITY,
static_cast<uint32_t>(cap_array[i]), static_cast<uint32_t>(cap_array[i]),
&entry)) { &cap_desc)) {
// This token is visible in this environment if it's in an appropriate // spvOperandTableValueLookup() filters capabilities internally
// core version, or it is enabled by a capability or an extension. // according to the current target environment by itself. So we
if ((version >= entry->minVersion && version <= entry->lastVersion) || // should be safe to add this capability if the lookup succeeds.
entry->numExtensions > 0u || entry->numCapabilities > 0u) { cap_set.Add(cap_array[i]);
cap_set.insert(cap_array[i]);
}
} }
} }
return cap_set; return cap_set;
@ -199,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(spv::Op opcode, spv_result_t AssemblyGrammar::lookupOpcode(SpvOp 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);
} }
@ -219,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,
spv::Op* opcode) const { SpvOp* 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,
@ -231,7 +226,7 @@ spv_result_t AssemblyGrammar::lookupSpecConstantOpcode(const char* name,
return SPV_SUCCESS; return SPV_SUCCESS;
} }
spv_result_t AssemblyGrammar::lookupSpecConstantOpcode(spv::Op opcode) const { spv_result_t AssemblyGrammar::lookupSpecConstantOpcode(SpvOp 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,

View File

@ -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 spv::Capability* cap_array, CapabilitySet filterCapsAgainstTargetEnv(const SpvCapability* 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(spv::Op opcode, spv_opcode_desc* desc) const; spv_result_t lookupOpcode(SpvOp 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,12 +82,11 @@ 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, spv_result_t lookupSpecConstantOpcode(const char* name, SpvOp* opcode) const;
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(spv::Op opcode) const; spv_result_t lookupSpecConstantOpcode(SpvOp opcode) const;
// Parses a mask expression string for the given operand type. // Parses a mask expression string for the given operand type.
// //

View File

@ -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, spv::Op opcode, spv_result_t exhaustedInputDiagnostic(size_t inst_offset, SpvOp 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<spv::Op>(inst.opcode), &opcode_desc)) if (grammar_.lookupOpcode(static_cast<SpvOp>(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 spv::Op opcode = static_cast<spv::Op>(inst->opcode); const SpvOp opcode = static_cast<SpvOp>(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 == spv::Op::OpExtInst && parsed_operand.offset == 3) { if (opcode == SpvOpExtInst && 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(spv::Op::OpExtInst == opcode); assert(SpvOpExtInst == 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(spv::Op::OpSpecConstantOp == opcode); assert(SpvOpSpecConstantOp == opcode);
if (word > static_cast<uint32_t>(spv::Op::Max) || if (word > static_cast<uint32_t>(SpvOp::SpvOpMax) ||
grammar_.lookupSpecConstantOpcode(spv::Op(word))) { grammar_.lookupSpecConstantOpcode(SpvOp(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(spv::Op(word), &opcode_entry)) { if (grammar_.lookupOpcode(SpvOp(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";
} }
@ -546,17 +546,10 @@ spv_result_t Parser::parseOperand(size_t inst_offset,
parsed_operand.number_bit_width = 32; parsed_operand.number_bit_width = 32;
break; break;
case SPV_OPERAND_TYPE_LITERAL_FLOAT:
// These are regular single-word literal float operands.
parsed_operand.type = SPV_OPERAND_TYPE_LITERAL_FLOAT;
parsed_operand.number_kind = SPV_NUMBER_FLOATING;
parsed_operand.number_bit_width = 32;
break;
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 == spv::Op::OpSwitch) { if (opcode == SpvOpSwitch) {
// 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);
@ -582,8 +575,7 @@ spv_result_t Parser::parseOperand(size_t inst_offset,
<< " is not a scalar integer"; << " is not a scalar integer";
} }
} else { } else {
assert(opcode == spv::Op::OpConstant || assert(opcode == SpvOpConstant || opcode == SpvOpSpecConstant);
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);
@ -615,7 +607,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 (spv::Op::OpExtInstImport == opcode) { if (SpvOpExtInstImport == 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.
@ -633,6 +625,7 @@ spv_result_t Parser::parseOperand(size_t inst_offset,
} break; } break;
case SPV_OPERAND_TYPE_CAPABILITY: case SPV_OPERAND_TYPE_CAPABILITY:
case SPV_OPERAND_TYPE_SOURCE_LANGUAGE:
case SPV_OPERAND_TYPE_EXECUTION_MODEL: case SPV_OPERAND_TYPE_EXECUTION_MODEL:
case SPV_OPERAND_TYPE_ADDRESSING_MODEL: case SPV_OPERAND_TYPE_ADDRESSING_MODEL:
case SPV_OPERAND_TYPE_MEMORY_MODEL: case SPV_OPERAND_TYPE_MEMORY_MODEL:
@ -689,21 +682,6 @@ spv_result_t Parser::parseOperand(size_t inst_offset,
spvPushOperandTypes(entry->operandTypes, expected_operands); spvPushOperandTypes(entry->operandTypes, expected_operands);
} break; } break;
case SPV_OPERAND_TYPE_SOURCE_LANGUAGE: {
spv_operand_desc entry;
if (grammar_.lookupOperand(type, word, &entry)) {
return diagnostic()
<< "Invalid " << spvOperandTypeStr(parsed_operand.type)
<< " operand: " << word
<< ", if you are creating a new source language please use "
"value 0 "
"(Unknown) and when ready, add your source language to "
"SPRIV-Headers";
}
// Prepare to accept operands to this operand, if needed.
spvPushOperandTypes(entry->operandTypes, expected_operands);
} break;
case SPV_OPERAND_TYPE_FP_FAST_MATH_MODE: case SPV_OPERAND_TYPE_FP_FAST_MATH_MODE:
case SPV_OPERAND_TYPE_FUNCTION_CONTROL: case SPV_OPERAND_TYPE_FUNCTION_CONTROL:
case SPV_OPERAND_TYPE_LOOP_CONTROL: case SPV_OPERAND_TYPE_LOOP_CONTROL:
@ -712,9 +690,7 @@ spv_result_t Parser::parseOperand(size_t inst_offset,
case SPV_OPERAND_TYPE_OPTIONAL_MEMORY_ACCESS: case SPV_OPERAND_TYPE_OPTIONAL_MEMORY_ACCESS:
case SPV_OPERAND_TYPE_SELECTION_CONTROL: case SPV_OPERAND_TYPE_SELECTION_CONTROL:
case SPV_OPERAND_TYPE_CLDEBUG100_DEBUG_INFO_FLAGS: case SPV_OPERAND_TYPE_CLDEBUG100_DEBUG_INFO_FLAGS:
case SPV_OPERAND_TYPE_DEBUG_INFO_FLAGS: case SPV_OPERAND_TYPE_DEBUG_INFO_FLAGS: {
case SPV_OPERAND_TYPE_COOPERATIVE_MATRIX_OPERANDS:
case SPV_OPERAND_TYPE_OPTIONAL_COOPERATIVE_MATRIX_OPERANDS: {
// This operand is a mask. // This operand is a mask.
// Map an optional operand type to its corresponding concrete type. // Map an optional operand type to its corresponding concrete type.
@ -722,8 +698,6 @@ spv_result_t Parser::parseOperand(size_t inst_offset,
parsed_operand.type = SPV_OPERAND_TYPE_IMAGE; parsed_operand.type = SPV_OPERAND_TYPE_IMAGE;
else if (type == SPV_OPERAND_TYPE_OPTIONAL_MEMORY_ACCESS) else if (type == SPV_OPERAND_TYPE_OPTIONAL_MEMORY_ACCESS)
parsed_operand.type = SPV_OPERAND_TYPE_MEMORY_ACCESS; parsed_operand.type = SPV_OPERAND_TYPE_MEMORY_ACCESS;
if (type == SPV_OPERAND_TYPE_OPTIONAL_COOPERATIVE_MATRIX_OPERANDS)
parsed_operand.type = SPV_OPERAND_TYPE_COOPERATIVE_MATRIX_OPERANDS;
// Check validity of set mask bits. Also prepare for operands for those // Check validity of set mask bits. Also prepare for operands for those
// masks if they have any. To get operand order correct, scan from // masks if they have any. To get operand order correct, scan from
@ -815,14 +789,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 spv::Op opcode = static_cast<spv::Op>(inst->opcode); const SpvOp opcode = static_cast<SpvOp>(inst->opcode);
if (spvOpcodeGeneratesType(opcode)) { if (spvOpcodeGeneratesType(opcode)) {
NumberType info = {SPV_NUMBER_NONE, 0}; NumberType info = {SPV_NUMBER_NONE, 0};
if (spv::Op::OpTypeInt == opcode) { if (SpvOpTypeInt == 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 (spv::Op::OpTypeFloat == opcode) { } else if (SpvOpTypeFloat == 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);
} }

View File

@ -275,16 +275,10 @@ std::vector<std::pair<BB*, BB*>> CFA<BB>::CalculateDominators(
std::vector<std::pair<bb_ptr, bb_ptr>> out; std::vector<std::pair<bb_ptr, bb_ptr>> out;
for (auto idom : idoms) { for (auto idom : idoms) {
// At this point if there is no dominator for the node, just make it
// reflexive.
auto dominator = std::get<1>(idom).dominator;
if (dominator == undefined_dom) {
dominator = std::get<1>(idom).postorder_index;
}
// NOTE: performing a const cast for convenient usage with // NOTE: performing a const cast for convenient usage with
// UpdateImmediateDominators // UpdateImmediateDominators
out.push_back({const_cast<BB*>(std::get<0>(idom)), out.push_back({const_cast<BB*>(std::get<0>(idom)),
const_cast<BB*>(postorder[dominator])}); const_cast<BB*>(postorder[std::get<1>(idom).dominator])});
} }
// Sort by postorder index to generate a deterministic ordering of edges. // Sort by postorder index to generate a deterministic ordering of edges.

View File

@ -39,7 +39,10 @@ set_property(TARGET SPIRV-Tools-diff PROPERTY FOLDER "SPIRV-Tools libraries")
spvtools_check_symbol_exports(SPIRV-Tools-diff) spvtools_check_symbol_exports(SPIRV-Tools-diff)
if(ENABLE_SPIRV_TOOLS_INSTALL) if(ENABLE_SPIRV_TOOLS_INSTALL)
install(TARGETS SPIRV-Tools-diff EXPORT SPIRV-Tools-diffTargets) install(TARGETS SPIRV-Tools-diff EXPORT SPIRV-Tools-diffTargets
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR})
export(EXPORT SPIRV-Tools-diffTargets FILE SPIRV-Tools-diffTargets.cmake) export(EXPORT SPIRV-Tools-diffTargets FILE SPIRV-Tools-diffTargets.cmake)
spvtools_config_package_dir(SPIRV-Tools-diff PACKAGE_DIR) spvtools_config_package_dir(SPIRV-Tools-diff PACKAGE_DIR)

File diff suppressed because it is too large Load Diff

View File

@ -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<spv::Op>(inst.opcode); auto opcode = static_cast<SpvOp>(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 == spv::Op::OpName) { if (comment_ && opcode == SpvOpName) {
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<spv::Op>(inst.opcode); auto opcode = static_cast<SpvOp>(inst.opcode);
if (comment_ && opcode == spv::Op::OpFunction) { if (comment_ && opcode == SpvOpFunction) {
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,14 +351,13 @@ 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(spv::Op(word), &opcode_desc)) if (grammar_.lookupOpcode(SpvOp(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;
} break; } break;
case SPV_OPERAND_TYPE_LITERAL_INTEGER: case SPV_OPERAND_TYPE_LITERAL_INTEGER:
case SPV_OPERAND_TYPE_TYPED_LITERAL_NUMBER: case SPV_OPERAND_TYPE_TYPED_LITERAL_NUMBER: {
case SPV_OPERAND_TYPE_LITERAL_FLOAT: {
SetRed(); SetRed();
EmitNumericLiteral(&stream_, inst, operand); EmitNumericLiteral(&stream_, inst, operand);
ResetColor(); ResetColor();

View File

@ -1,4 +1,4 @@
// Copyright (c) 2023 Google Inc. // Copyright (c) 2016 Google Inc.
// //
// Licensed under the Apache License, Version 2.0 (the "License"); // Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License. // you may not use this file except in compliance with the License.
@ -12,457 +12,196 @@
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // limitations under the License.
#include <algorithm>
#include <cassert>
#include <cstdint>
#include <functional>
#include <initializer_list>
#include <limits>
#include <type_traits>
#include <vector>
#ifndef SOURCE_ENUM_SET_H_ #ifndef SOURCE_ENUM_SET_H_
#define SOURCE_ENUM_SET_H_ #define SOURCE_ENUM_SET_H_
#include <cstdint>
#include <functional>
#include <memory>
#include <set>
#include <utility>
#include "source/latest_version_spirv_header.h" #include "source/latest_version_spirv_header.h"
#include "source/util/make_unique.h"
namespace spvtools { namespace spvtools {
// This container is optimized to store and retrieve unsigned enum values. // A set of values of a 32-bit enum type.
// The base model for this implementation is an open-addressing hashtable with // It is fast and compact for the common case, where enum values
// linear probing. For small enums (max index < 64), all operations are O(1). // are at most 63. But it can represent enums with larger values,
// // as may appear in extensions.
// - Enums are stored in buckets (64 contiguous values max per bucket) template <typename EnumType>
// - Buckets ranges don't overlap, but don't have to be contiguous.
// - Enums are packed into 64-bits buckets, using 1 bit per enum value.
//
// Example:
// - MyEnum { A = 0, B = 1, C = 64, D = 65 }
// - 2 buckets are required:
// - bucket 0, storing values in the range [ 0; 64[
// - bucket 1, storing values in the range [64; 128[
//
// - Buckets are stored in a sorted vector (sorted by bucket range).
// - Retrieval is done by computing the theoretical bucket index using the enum
// value, and
// doing a linear scan from this position.
// - Insertion is done by retrieving the bucket and either:
// - inserting a new bucket in the sorted vector when no buckets has a
// compatible range.
// - setting the corresponding bit in the bucket.
// This means insertion in the middle/beginning can cause a memmove when no
// bucket is available. In our case, this happens at most 23 times for the
// largest enum we have (Opcodes).
template <typename T>
class EnumSet { class EnumSet {
private: private:
using BucketType = uint64_t; // The ForEach method will call the functor on enum values in
using ElementType = std::underlying_type_t<T>; // enum value order (lowest to highest). To make that easier, use
static_assert(std::is_enum_v<T>, "EnumSets only works with enums."); // an ordered set for the overflow values.
static_assert(std::is_signed_v<ElementType> == false, using OverflowSetType = std::set<uint32_t>;
"EnumSet doesn't supports signed enums.");
// Each bucket can hold up to `kBucketSize` distinct, contiguous enum values.
// The first value a bucket can hold must be aligned on `kBucketSize`.
struct Bucket {
// bit mask to store `kBucketSize` enums.
BucketType data;
// 1st enum this bucket can represent.
T start;
friend bool operator==(const Bucket& lhs, const Bucket& rhs) {
return lhs.start == rhs.start && lhs.data == rhs.data;
}
};
// How many distinct values can a bucket hold? 1 bit per value.
static constexpr size_t kBucketSize = sizeof(BucketType) * 8ULL;
public: public:
class Iterator { // Construct an empty set.
public: EnumSet() {}
typedef Iterator self_type; // Construct an set with just the given enum value.
typedef T value_type; explicit EnumSet(EnumType c) { Add(c); }
typedef T& reference; // Construct an set from an initializer list of enum values.
typedef T* pointer; EnumSet(std::initializer_list<EnumType> cs) {
typedef std::forward_iterator_tag iterator_category; for (auto c : cs) Add(c);
typedef size_t difference_type;
Iterator(const Iterator& other)
: set_(other.set_),
bucketIndex_(other.bucketIndex_),
bucketOffset_(other.bucketOffset_) {}
Iterator& operator++() {
do {
if (bucketIndex_ >= set_->buckets_.size()) {
bucketIndex_ = set_->buckets_.size();
bucketOffset_ = 0;
break;
}
if (bucketOffset_ + 1 == kBucketSize) {
bucketOffset_ = 0;
++bucketIndex_;
} else {
++bucketOffset_;
}
} while (bucketIndex_ < set_->buckets_.size() &&
!set_->HasEnumAt(bucketIndex_, bucketOffset_));
return *this;
}
Iterator operator++(int) {
Iterator old = *this;
operator++();
return old;
}
T operator*() const {
assert(set_->HasEnumAt(bucketIndex_, bucketOffset_) &&
"operator*() called on an invalid iterator.");
return GetValueFromBucket(set_->buckets_[bucketIndex_], bucketOffset_);
}
bool operator!=(const Iterator& other) const {
return set_ != other.set_ || bucketOffset_ != other.bucketOffset_ ||
bucketIndex_ != other.bucketIndex_;
}
bool operator==(const Iterator& other) const {
return !(operator!=(other));
}
Iterator& operator=(const Iterator& other) {
set_ = other.set_;
bucketIndex_ = other.bucketIndex_;
bucketOffset_ = other.bucketOffset_;
return *this;
}
private:
Iterator(const EnumSet* set, size_t bucketIndex, ElementType bucketOffset)
: set_(set), bucketIndex_(bucketIndex), bucketOffset_(bucketOffset) {}
private:
const EnumSet* set_ = nullptr;
// Index of the bucket in the vector.
size_t bucketIndex_ = 0;
// Offset in bits in the current bucket.
ElementType bucketOffset_ = 0;
friend class EnumSet;
};
// Required to allow the use of std::inserter.
using value_type = T;
using const_iterator = Iterator;
using iterator = Iterator;
public:
iterator cbegin() const noexcept {
auto it = iterator(this, /* bucketIndex= */ 0, /* bucketOffset= */ 0);
if (buckets_.size() == 0) {
return it;
}
// The iterator has the logic to find the next valid bit. If the value 0
// is not stored, use it to find the next valid bit.
if (!HasEnumAt(it.bucketIndex_, it.bucketOffset_)) {
++it;
}
return it;
} }
EnumSet(uint32_t count, const EnumType* ptr) {
iterator begin() const noexcept { return cbegin(); } for (uint32_t i = 0; i < count; ++i) Add(ptr[i]);
iterator cend() const noexcept {
return iterator(this, buckets_.size(), /* bucketOffset= */ 0);
} }
// Copy constructor.
iterator end() const noexcept { return cend(); } EnumSet(const EnumSet& other) { *this = other; }
// Move constructor. The moved-from set is emptied.
// Creates an empty set. EnumSet(EnumSet&& other) {
EnumSet() : buckets_(0), size_(0) {} mask_ = other.mask_;
overflow_ = std::move(other.overflow_);
// Creates a set and store `value` in it. other.mask_ = 0;
EnumSet(T value) : EnumSet() { insert(value); } other.overflow_.reset(nullptr);
// Creates a set and stores each `values` in it.
EnumSet(std::initializer_list<T> values) : EnumSet() {
for (auto item : values) {
insert(item);
}
} }
// Assignment operator.
// Creates a set, and insert `count` enum values pointed by `array` in it.
EnumSet(ElementType count, const T* array) : EnumSet() {
for (ElementType i = 0; i < count; i++) {
insert(array[i]);
}
}
// Creates a set initialized with the content of the range [begin; end[.
template <class InputIt>
EnumSet(InputIt begin, InputIt end) : EnumSet() {
for (; begin != end; ++begin) {
insert(*begin);
}
}
// Copies the EnumSet `other` into a new EnumSet.
EnumSet(const EnumSet& other)
: buckets_(other.buckets_), size_(other.size_) {}
// Moves the EnumSet `other` into a new EnumSet.
EnumSet(EnumSet&& other)
: buckets_(std::move(other.buckets_)), size_(other.size_) {}
// Deep-copies the EnumSet `other` into this EnumSet.
EnumSet& operator=(const EnumSet& other) { EnumSet& operator=(const EnumSet& other) {
buckets_ = other.buckets_; if (&other != this) {
size_ = other.size_; mask_ = other.mask_;
overflow_.reset(other.overflow_ ? new OverflowSetType(*other.overflow_)
: nullptr);
}
return *this; return *this;
} }
// Matches std::unordered_set::insert behavior. friend bool operator==(const EnumSet& a, const EnumSet& b) {
std::pair<iterator, bool> insert(const T& value) { if (a.mask_ != b.mask_) {
const size_t index = FindBucketForValue(value);
const ElementType offset = ComputeBucketOffset(value);
if (index >= buckets_.size() ||
buckets_[index].start != ComputeBucketStart(value)) {
size_ += 1;
InsertBucketFor(index, value);
return std::make_pair(Iterator(this, index, offset), true);
}
auto& bucket = buckets_[index];
const auto mask = ComputeMaskForValue(value);
if (bucket.data & mask) {
return std::make_pair(Iterator(this, index, offset), false);
}
size_ += 1;
bucket.data |= ComputeMaskForValue(value);
return std::make_pair(Iterator(this, index, offset), true);
}
// Inserts `value` in the set if possible.
// Similar to `std::unordered_set::insert`, except the hint is ignored.
// Returns an iterator to the inserted element, or the element preventing
// insertion.
iterator insert(const_iterator, const T& value) {
return insert(value).first;
}
// Inserts `value` in the set if possible.
// Similar to `std::unordered_set::insert`, except the hint is ignored.
// Returns an iterator to the inserted element, or the element preventing
// insertion.
iterator insert(const_iterator, T&& value) { return insert(value).first; }
// Inserts all the values in the range [`first`; `last[.
// Similar to `std::unordered_set::insert`.
template <class InputIt>
void insert(InputIt first, InputIt last) {
for (auto it = first; it != last; ++it) {
insert(*it);
}
}
// Removes the value `value` into the set.
// Similar to `std::unordered_set::erase`.
// Returns the number of erased elements.
size_t erase(const T& value) {
const size_t index = FindBucketForValue(value);
if (index >= buckets_.size() ||
buckets_[index].start != ComputeBucketStart(value)) {
return 0;
}
auto& bucket = buckets_[index];
const auto mask = ComputeMaskForValue(value);
if (!(bucket.data & mask)) {
return 0;
}
size_ -= 1;
bucket.data &= ~mask;
if (bucket.data == 0) {
buckets_.erase(buckets_.cbegin() + index);
}
return 1;
}
// Returns true if `value` is present in the set.
bool contains(T value) const {
const size_t index = FindBucketForValue(value);
if (index >= buckets_.size() ||
buckets_[index].start != ComputeBucketStart(value)) {
return false; return false;
} }
auto& bucket = buckets_[index];
return bucket.data & ComputeMaskForValue(value);
}
// Returns the 1 if `value` is present in the set, `0` otherwise. if (a.overflow_ == nullptr && b.overflow_ == nullptr) {
inline size_t count(T value) const { return contains(value) ? 1 : 0; }
// Returns true if the set is holds no values.
inline bool empty() const { return size_ == 0; }
// Returns the number of enums stored in this set.
size_t size() const { return size_; }
// Returns true if this set contains at least one value contained in `in_set`.
// Note: If `in_set` is empty, this function returns true.
bool HasAnyOf(const EnumSet<T>& in_set) const {
if (in_set.empty()) {
return true; return true;
} }
auto lhs = buckets_.cbegin(); if (a.overflow_ == nullptr || b.overflow_ == nullptr) {
auto rhs = in_set.buckets_.cbegin(); return false;
}
while (lhs != buckets_.cend() && rhs != in_set.buckets_.cend()) { return *a.overflow_ == *b.overflow_;
if (lhs->start == rhs->start) { }
if (lhs->data & rhs->data) {
// At least 1 bit is shared. Early return.
return true;
}
lhs++; friend bool operator!=(const EnumSet& a, const EnumSet& b) {
rhs++; return !(a == b);
continue; }
}
// LHS bucket is smaller than the current RHS bucket. Catching up on RHS. // Adds the given enum value to the set. This has no effect if the
if (lhs->start < rhs->start) { // enum value is already in the set.
lhs++; void Add(EnumType c) { AddWord(ToWord(c)); }
continue;
}
// Otherwise, RHS needs to catch up on LHS. // Removes the given enum value from the set. This has no effect if the
rhs++; // enum value is not in the set.
void Remove(EnumType c) { RemoveWord(ToWord(c)); }
// Returns true if this enum value is in the set.
bool Contains(EnumType c) const { return ContainsWord(ToWord(c)); }
// Applies f to each enum in the set, in order from smallest enum
// value to largest.
void ForEach(std::function<void(EnumType)> f) const {
for (uint32_t i = 0; i < 64; ++i) {
if (mask_ & AsMask(i)) f(static_cast<EnumType>(i));
}
if (overflow_) {
for (uint32_t c : *overflow_) f(static_cast<EnumType>(c));
}
}
// Returns true if the set is empty.
bool IsEmpty() const {
if (mask_) return false;
if (overflow_ && !overflow_->empty()) return false;
return true;
}
// Returns true if the set contains ANY of the elements of |in_set|,
// or if |in_set| is empty.
bool HasAnyOf(const EnumSet<EnumType>& in_set) const {
if (in_set.IsEmpty()) return true;
if (mask_ & in_set.mask_) return true;
if (!overflow_ || !in_set.overflow_) return false;
for (uint32_t item : *in_set.overflow_) {
if (overflow_->find(item) != overflow_->end()) return true;
} }
return false; return false;
} }
private: private:
// Returns the index of the last bucket in which `value` could be stored. // Adds the given enum value (as a 32-bit word) to the set. This has no
static constexpr inline size_t ComputeLargestPossibleBucketIndexFor(T value) { // effect if the enum value is already in the set.
return static_cast<size_t>(value) / kBucketSize; void AddWord(uint32_t word) {
} if (auto new_bits = AsMask(word)) {
mask_ |= new_bits;
// Returns the smallest enum value that could be contained in the same bucket } else {
// as `value`. Overflow().insert(word);
static constexpr inline T ComputeBucketStart(T value) {
return static_cast<T>(kBucketSize *
ComputeLargestPossibleBucketIndexFor(value));
}
// Returns the index of the bit that corresponds to `value` in the bucket.
static constexpr inline ElementType ComputeBucketOffset(T value) {
return static_cast<ElementType>(value) % kBucketSize;
}
// Returns the bitmask used to represent the enum `value` in its bucket.
static constexpr inline BucketType ComputeMaskForValue(T value) {
return 1ULL << ComputeBucketOffset(value);
}
// Returns the `enum` stored in `bucket` at `offset`.
// `offset` is the bit-offset in the bucket storage.
static constexpr inline T GetValueFromBucket(const Bucket& bucket,
BucketType offset) {
return static_cast<T>(static_cast<ElementType>(bucket.start) + offset);
}
// For a given enum `value`, finds the bucket index that could contain this
// value. If no such bucket is found, the index at which the new bucket should
// be inserted is returned.
size_t FindBucketForValue(T value) const {
// Set is empty, insert at 0.
if (buckets_.size() == 0) {
return 0;
} }
}
const T wanted_start = ComputeBucketStart(value); // Removes the given enum value (as a 32-bit word) from the set. This has no
assert(buckets_.size() > 0 && // effect if the enum value is not in the set.
"Size must not be 0 here. Has the code above changed?"); void RemoveWord(uint32_t word) {
size_t index = std::min(buckets_.size() - 1, if (auto new_bits = AsMask(word)) {
ComputeLargestPossibleBucketIndexFor(value)); mask_ &= ~new_bits;
} else {
// This loops behaves like std::upper_bound with a reverse iterator. auto itr = Overflow().find(word);
// Buckets are sorted. 3 main cases: if (itr != Overflow().end()) Overflow().erase(itr);
// - The bucket matches
// => returns the bucket index.
// - The found bucket is larger
// => scans left until it finds the correct bucket, or insertion point.
// - The found bucket is smaller
// => We are at the end, so we return past-end index for insertion.
for (; buckets_[index].start >= wanted_start; index--) {
if (index == 0) {
return 0;
}
} }
return index + 1;
} }
// Creates a new bucket to store `value` and inserts it at `index`. // Returns true if the enum represented as a 32-bit word is in the set.
// If the `index` is past the end, the bucket is inserted at the end of the bool ContainsWord(uint32_t word) const {
// vector. // We shouldn't call Overflow() since this is a const method.
void InsertBucketFor(size_t index, T value) { if (auto bits = AsMask(word)) {
const T bucket_start = ComputeBucketStart(value); return (mask_ & bits) != 0;
Bucket bucket = {1ULL << ComputeBucketOffset(value), bucket_start}; } else if (auto overflow = overflow_.get()) {
auto it = buckets_.emplace(buckets_.begin() + index, std::move(bucket)); return overflow->find(word) != overflow->end();
#if defined(NDEBUG)
(void)it; // Silencing unused variable warning.
#else
assert(std::next(it) == buckets_.end() ||
std::next(it)->start > bucket_start);
assert(it == buckets_.begin() || std::prev(it)->start < bucket_start);
#endif
}
// Returns true if the bucket at `bucketIndex/ stores the enum at
// `bucketOffset`, false otherwise.
bool HasEnumAt(size_t bucketIndex, BucketType bucketOffset) const {
assert(bucketIndex < buckets_.size());
assert(bucketOffset < kBucketSize);
return buckets_[bucketIndex].data & (1ULL << bucketOffset);
}
// Returns true if `lhs` and `rhs` hold the exact same values.
friend bool operator==(const EnumSet& lhs, const EnumSet& rhs) {
if (lhs.size_ != rhs.size_) {
return false;
} }
// The word is large, but the set doesn't have large members, so
// it doesn't have an overflow set.
return false;
}
if (lhs.buckets_.size() != rhs.buckets_.size()) { // Returns the enum value as a uint32_t.
return false; uint32_t ToWord(EnumType value) const {
static_assert(sizeof(EnumType) <= sizeof(uint32_t),
"EnumType must statically castable to uint32_t");
return static_cast<uint32_t>(value);
}
// Determines whether the given enum value can be represented
// as a bit in a uint64_t mask. If so, then returns that mask bit.
// Otherwise, returns 0.
uint64_t AsMask(uint32_t word) const {
if (word > 63) return 0;
return uint64_t(1) << word;
}
// Ensures that overflow_set_ references a set. A new empty set is
// allocated if one doesn't exist yet. Returns overflow_set_.
OverflowSetType& Overflow() {
if (overflow_.get() == nullptr) {
overflow_ = MakeUnique<OverflowSetType>();
} }
return lhs.buckets_ == rhs.buckets_; return *overflow_;
} }
// Returns true if `lhs` and `rhs` hold at least 1 different value. // Enums with values up to 63 are stored as bits in this mask.
friend bool operator!=(const EnumSet& lhs, const EnumSet& rhs) { uint64_t mask_ = 0;
return !(lhs == rhs); // Enums with values larger than 63 are stored in this set.
} // This set should normally be empty or very small.
std::unique_ptr<OverflowSetType> overflow_ = {};
// Storage for the buckets.
std::vector<Bucket> buckets_;
// How many enums is this set storing.
size_t size_ = 0;
}; };
// A set of spv::Capability. // A set of SpvCapability, optimized for small capability values.
using CapabilitySet = EnumSet<spv::Capability>; using CapabilitySet = EnumSet<SpvCapability>;
} // namespace spvtools } // namespace spvtools

View File

@ -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(spv::Capability capability); const char* CapabilityToString(SpvCapability capability);
} // namespace spvtools } // namespace spvtools

View File

@ -24,9 +24,7 @@
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 != static_cast<uint16_t>(spv::Op::OpExtension)) { if (inst->opcode != SpvOpExtension) return "ERROR_not_op_extension";
return "ERROR_not_op_extension";
}
assert(inst->num_operands == 1); assert(inst->num_operands == 1);
@ -40,9 +38,8 @@ std::string GetExtensionString(const spv_parsed_instruction_t* inst) {
std::string ExtensionSetToString(const ExtensionSet& extensions) { std::string ExtensionSetToString(const ExtensionSet& extensions) {
std::stringstream ss; std::stringstream ss;
for (auto extension : extensions) { extensions.ForEach(
ss << ExtensionToString(extension) << " "; [&ss](Extension ext) { ss << ExtensionToString(ext) << " "; });
}
return ss.str(); return ss.str();
} }

View File

@ -15,7 +15,6 @@
#ifndef SOURCE_EXTENSIONS_H_ #ifndef SOURCE_EXTENSIONS_H_
#define SOURCE_EXTENSIONS_H_ #define SOURCE_EXTENSIONS_H_
#include <cstdint>
#include <string> #include <string>
#include "source/enum_set.h" #include "source/enum_set.h"
@ -24,7 +23,7 @@
namespace spvtools { namespace spvtools {
// The known SPIR-V extensions. // The known SPIR-V extensions.
enum Extension : uint32_t { enum Extension {
#include "extension_enum.inc" #include "extension_enum.inc"
}; };

View File

@ -470,7 +470,10 @@ if(SPIRV_BUILD_FUZZER)
spvtools_check_symbol_exports(SPIRV-Tools-fuzz) spvtools_check_symbol_exports(SPIRV-Tools-fuzz)
if(ENABLE_SPIRV_TOOLS_INSTALL) if(ENABLE_SPIRV_TOOLS_INSTALL)
install(TARGETS SPIRV-Tools-fuzz EXPORT SPIRV-Tools-fuzzTargets) install(TARGETS SPIRV-Tools-fuzz EXPORT SPIRV-Tools-fuzzTargets
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR})
export(EXPORT SPIRV-Tools-fuzzTargets FILE SPIRV-Tools-fuzzTarget.cmake) export(EXPORT SPIRV-Tools-fuzzTargets FILE SPIRV-Tools-fuzzTarget.cmake)
spvtools_config_package_dir(SPIRV-Tools-fuzz PACKAGE_DIR) spvtools_config_package_dir(SPIRV-Tools-fuzz PACKAGE_DIR)

View File

@ -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() != spv::Op::OpVariable) { if (type_or_value.opcode() != SpvOpVariable) {
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() != spv::Op::OpVariable) { if (type_or_value.opcode() != SpvOpVariable) {
continue; continue;
} }
if (replay_result.transformation_context->GetFactManager() if (replay_result.transformation_context->GetFactManager()

View File

@ -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() != spv::Op::OpFunctionCall) { if (instruction.opcode() != SpvOpFunctionCall) {
continue; continue;
} }
// Get the id of the function being called. // Get the id of the function being called.

View File

@ -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() == spv::Op::OpConstant); assert(constant_instruction.opcode() == SpvOpConstant);
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() == spv::Op::OpConstant && assert(constant_inst->opcode() == SpvOpConstant &&
"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,9 +175,8 @@ bool ConstantUniformFacts::MaybeAddFact(
return false; return false;
} }
assert(spv::Op::OpVariable == uniform_variable->opcode()); assert(SpvOpVariable == uniform_variable->opcode());
assert(spv::StorageClass::Uniform == assert(SpvStorageClassUniform == uniform_variable->GetSingleWordInOperand(0));
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());
@ -185,7 +184,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() !=
spv::StorageClass::Uniform) { SpvStorageClassUniform) {
return false; return false;
} }
auto should_be_uniform_pointer_instruction = auto should_be_uniform_pointer_instruction =

View File

@ -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(uint32_t(operation.opcode)); hash.push_back(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,8 +104,7 @@ bool DataSynonymAndIdEquationFacts::MaybeAddFact(
} }
// Now add the fact. // Now add the fact.
AddEquationFactRecursive(lhs_dd, static_cast<spv::Op>(fact.opcode()), AddEquationFactRecursive(lhs_dd, static_cast<SpvOp>(fact.opcode()), rhs_dds);
rhs_dds);
return true; return true;
} }
@ -120,7 +119,7 @@ DataSynonymAndIdEquationFacts::GetEquations(
} }
void DataSynonymAndIdEquationFacts::AddEquationFactRecursive( void DataSynonymAndIdEquationFacts::AddEquationFactRecursive(
const protobufs::DataDescriptor& lhs_dd, spv::Op opcode, const protobufs::DataDescriptor& lhs_dd, SpvOp 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.");
@ -156,21 +155,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 spv::Op::OpConvertSToF: case SpvOpConvertSToF:
case spv::Op::OpConvertUToF: case SpvOpConvertUToF:
ComputeConversionDataSynonymFacts(*rhs_dds[0]); ComputeConversionDataSynonymFacts(*rhs_dds[0]);
break; break;
case spv::Op::OpBitcast: { case SpvOpBitcast: {
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 spv::Op::OpIAdd: { case SpvOpIAdd: {
// 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 == spv::Op::OpISub) { if (equation.opcode == SpvOpISub) {
// 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"
@ -180,7 +179,7 @@ void DataSynonymAndIdEquationFacts::AddEquationFactRecursive(
} }
} }
for (const auto& equation : GetEquations(rhs_dds[1])) { for (const auto& equation : GetEquations(rhs_dds[1])) {
if (equation.opcode == spv::Op::OpISub) { if (equation.opcode == SpvOpISub) {
// 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)"
@ -191,10 +190,10 @@ void DataSynonymAndIdEquationFacts::AddEquationFactRecursive(
} }
break; break;
} }
case spv::Op::OpISub: { case SpvOpISub: {
// 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 == spv::Op::OpIAdd) { if (equation.opcode == SpvOpIAdd) {
// 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"
@ -208,34 +207,34 @@ void DataSynonymAndIdEquationFacts::AddEquationFactRecursive(
} }
} }
if (equation.opcode == spv::Op::OpISub) { if (equation.opcode == SpvOpISub) {
// 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, spv::Op::OpSNegate, AddEquationFactRecursive(lhs_dd, SpvOpSNegate,
{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 == spv::Op::OpIAdd) { if (equation.opcode == SpvOpIAdd) {
// 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, spv::Op::OpSNegate, AddEquationFactRecursive(lhs_dd, SpvOpSNegate,
{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, spv::Op::OpSNegate, AddEquationFactRecursive(lhs_dd, SpvOpSNegate,
{equation.operands[0]}); {equation.operands[0]});
} }
} }
if (equation.opcode == spv::Op::OpISub) { if (equation.opcode == SpvOpISub) {
// 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)"
@ -246,8 +245,8 @@ void DataSynonymAndIdEquationFacts::AddEquationFactRecursive(
} }
break; break;
} }
case spv::Op::OpLogicalNot: case SpvOpLogicalNot:
case spv::Op::OpSNegate: { case SpvOpSNegate: {
// 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) {
@ -322,9 +321,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 == spv::Op::OpConvertSToF) { if (equation.opcode == SpvOpConvertSToF) {
convert_s_to_f_lhs.push_back(*dd_it); convert_s_to_f_lhs.push_back(*dd_it);
} else if (equation.opcode == spv::Op::OpConvertUToF) { } else if (equation.opcode == SpvOpConvertUToF) {
convert_u_to_f_lhs.push_back(*dd_it); convert_u_to_f_lhs.push_back(*dd_it);
} }
} }
@ -809,9 +808,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() ==
spv::Op::OpTypeVoid || SpvOpTypeVoid ||
ir_context_->get_def_use_mgr()->GetDef(end_type_id_2)->opcode() == ir_context_->get_def_use_mgr()->GetDef(end_type_id_2)->opcode() ==
spv::Op::OpTypeVoid) { SpvOpTypeVoid) {
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.

View File

@ -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 {
spv::Op opcode; SpvOp 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, spv::Op opcode, const protobufs::DataDescriptor& lhs_dd, SpvOp 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.

View File

@ -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 << " " << fact.opcode(); stream << " " << static_cast<SpvOp>(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, spv::Op opcode, void FactManager::AddFactIdEquation(uint32_t lhs_id, SpvOp 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(uint32_t(opcode)); fact.set_opcode(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);
} }

View File

@ -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, spv::Op opcode, void AddFactIdEquation(uint32_t lhs_id, SpvOp 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

View File

@ -36,9 +36,8 @@ 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() == spv::Op::OpCapability); assert(capability.opcode() == SpvOpCapability);
if (spv::Capability(capability.GetSingleWordInOperand(0)) == if (capability.GetSingleWordInOperand(0) == SpvCapabilityShader) {
spv::Capability::Shader) {
found_capability_shader = true; found_capability_shader = true;
break; break;
} }
@ -52,8 +51,7 @@ 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 (spv::ExecutionModel(entry_point.GetSingleWordInOperand(0)) == if (entry_point.GetSingleWordInOperand(0) == SpvExecutionModelFragment) {
spv::ExecutionModel::Fragment) {
fragment_entry_point = &entry_point; fragment_entry_point = &entry_point;
break; break;
} }
@ -83,9 +81,8 @@ 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() == spv::Op::OpVariable && if (inst.opcode() == SpvOpVariable &&
spv::StorageClass(inst.GetSingleWordInOperand(0)) == inst.GetSingleWordInOperand(0) == SpvStorageClassOutput) {
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; "
@ -147,11 +144,10 @@ 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( MakeIdUseDescriptor(constant_id,
constant_id, MakeInstructionDescriptor(greater_than_instruction,
MakeInstructionDescriptor(greater_than_instruction, SpvOpFOrdGreaterThan, 0),
spv::Op::OpFOrdGreaterThan, 0), in_operand_index),
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());
} }
@ -208,21 +204,20 @@ 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>( auto label = MakeUnique<opt::Instruction>(ir_context.get(), SpvOpLabel, 0,
ir_context.get(), spv::Op::OpLabel, 0, new_exit_block_id, 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( new_exit_block->AddInstruction(MakeUnique<opt::Instruction>(
MakeUnique<opt::Instruction>(ir_context.get(), spv::Op::OpReturn, 0, 0, ir_context.get(), SpvOpReturn, 0, 0, opt::Instruction::OperandList()));
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>( auto label = MakeUnique<opt::Instruction>(ir_context.get(), SpvOpLabel, 0,
ir_context.get(), spv::Op::OpLabel, 0, ir_context->TakeNextId(), 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
@ -234,7 +229,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(), spv::Op::OpCompositeConstruct, vec4_id, ir_context.get(), SpvOpCompositeConstruct, 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));
@ -246,7 +241,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(), spv::Op::OpStore, 0, 0, op_store_operands)); ir_context.get(), SpvOpStore, 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
@ -318,7 +313,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(), spv::Op::OpFOrdGreaterThan, ir_context.get(), SpvOpFOrdGreaterThan,
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));
@ -349,9 +344,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(MakeUnique<opt::Instruction>( new_entry_block->AddInstruction(
ir_context.get(), spv::Op::OpBranchConditional, 0, 0, MakeUnique<opt::Instruction>(ir_context.get(), SpvOpBranchConditional,
op_branch_conditional_operands)); 0, 0, 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());

View File

@ -131,15 +131,14 @@ 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, spv::Op, uint32_t>> std::vector<std::tuple<uint32_t, SpvOp, uint32_t>> base_opcode_skip_triples;
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<spv::Op, uint32_t> skip_count; std::map<SpvOp, 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
@ -152,7 +151,7 @@ void FuzzerPass::ForEachInstructionWithInstructionDescriptor(
base = inst_it->result_id(); base = inst_it->result_id();
skip_count.clear(); skip_count.clear();
} }
const spv::Op opcode = inst_it->opcode(); const SpvOp 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,
@ -331,7 +330,7 @@ uint32_t FuzzerPass::FindOrCreateStructType(
} }
uint32_t FuzzerPass::FindOrCreatePointerType(uint32_t base_type_id, uint32_t FuzzerPass::FindOrCreatePointerType(uint32_t base_type_id,
spv::StorageClass storage_class) { SpvStorageClass 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(
@ -346,7 +345,7 @@ uint32_t FuzzerPass::FindOrCreatePointerType(uint32_t base_type_id,
} }
uint32_t FuzzerPass::FindOrCreatePointerToIntegerType( uint32_t FuzzerPass::FindOrCreatePointerToIntegerType(
uint32_t width, bool is_signed, spv::StorageClass storage_class) { uint32_t width, bool is_signed, SpvStorageClass storage_class) {
return FindOrCreatePointerType(FindOrCreateIntegerType(width, is_signed), return FindOrCreatePointerType(FindOrCreateIntegerType(width, is_signed),
storage_class); storage_class);
} }
@ -433,7 +432,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() == spv::Op::OpUndef && inst.type_id() == type_id) { if (inst.opcode() == SpvOpUndef && inst.type_id() == type_id) {
return inst.result_id(); return inst.result_id();
} }
} }
@ -465,7 +464,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(
spv::StorageClass storage_class) const { SpvStorageClass 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;
@ -481,23 +480,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 spv::Op::OpTypeBool: case SpvOpTypeBool:
case spv::Op::OpTypeFloat: case SpvOpTypeFloat:
case spv::Op::OpTypeInt: case SpvOpTypeInt:
case spv::Op::OpTypeMatrix: case SpvOpTypeMatrix:
case spv::Op::OpTypeVector: case SpvOpTypeVector:
// 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 spv::Op::OpTypeArray: case SpvOpTypeArray:
// 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 spv::Op::OpTypeStruct: { case SpvOpTypeStruct: {
// 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(),
@ -516,12 +515,11 @@ FuzzerPass::GetAvailableBasicTypesAndPointers(
} }
break; break;
} }
case spv::Op::OpTypePointer: { case SpvOpTypePointer: {
// 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 (spv::StorageClass(inst.GetSingleWordInOperand(0)) == if (inst.GetSingleWordInOperand(0) == storage_class &&
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
@ -543,22 +541,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 spv::Op::OpTypeBool: case SpvOpTypeBool:
return FindOrCreateBoolConstant(false, is_irrelevant); return FindOrCreateBoolConstant(false, is_irrelevant);
case spv::Op::OpTypeFloat: { case SpvOpTypeFloat: {
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 spv::Op::OpTypeInt: { case SpvOpTypeInt: {
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 spv::Op::OpTypeArray: { case SpvOpTypeArray: {
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());
@ -568,8 +566,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 spv::Op::OpTypeMatrix: case SpvOpTypeMatrix:
case spv::Op::OpTypeVector: { case SpvOpTypeVector: {
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(
@ -578,7 +576,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 spv::Op::OpTypeStruct: { case SpvOpTypeStruct: {
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 "
@ -648,7 +646,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() == spv::Op::OpBranch && if (maybe_preheader->terminator()->opcode() == SpvOpBranch &&
!maybe_preheader->IsLoopHeader()) { !maybe_preheader->IsLoopHeader()) {
return maybe_preheader; return maybe_preheader;
} }
@ -685,8 +683,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() == spv::Op::OpPhi || while (non_phi_or_var_inst->opcode() == SpvOpPhi ||
non_phi_or_var_inst->opcode() == spv::Op::OpVariable) { non_phi_or_var_inst->opcode() == SpvOpVariable) {
non_phi_or_var_inst = non_phi_or_var_inst->NextNode(); non_phi_or_var_inst = non_phi_or_var_inst->NextNode();
} }
@ -708,7 +706,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() ==
spv::StorageClass::Function && SpvStorageClassFunction &&
"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);
@ -717,7 +715,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() != spv::Op::OpVariable) { if (instruction.opcode() != SpvOpVariable) {
continue; continue;
} }
// The existing OpVariable must have type |pointer_type_id|. // The existing OpVariable must have type |pointer_type_id|.
@ -751,16 +749,15 @@ 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() == (pointer_type->AsPointer()->storage_class() == SpvStorageClassPrivate ||
spv::StorageClass::Private ||
pointer_type->AsPointer()->storage_class() == pointer_type->AsPointer()->storage_class() ==
spv::StorageClass::Workgroup) && SpvStorageClassWorkgroup) &&
"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() != spv::Op::OpVariable) { if (instruction.opcode() != SpvOpVariable) {
continue; continue;
} }
// The existing OpVariable must have type |pointer_type_id|. // The existing OpVariable must have type |pointer_type_id|.
@ -784,13 +781,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 == spv::StorageClass::Workgroup) { if (storage_class == SpvStorageClassWorkgroup) {
ApplyTransformation(TransformationAddGlobalVariable( ApplyTransformation(TransformationAddGlobalVariable(
result_id, pointer_type_id, spv::StorageClass::Workgroup, 0, result_id, pointer_type_id, SpvStorageClassWorkgroup, 0,
pointee_value_is_irrelevant)); pointee_value_is_irrelevant));
} else { } else {
ApplyTransformation(TransformationAddGlobalVariable( ApplyTransformation(TransformationAddGlobalVariable(
result_id, pointer_type_id, spv::StorageClass::Private, result_id, pointer_type_id, SpvStorageClassPrivate,
FindOrCreateZeroConstant(pointee_type_id, pointee_value_is_irrelevant), FindOrCreateZeroConstant(pointee_type_id, pointee_value_is_irrelevant),
pointee_value_is_irrelevant)); pointee_value_is_irrelevant));
} }

View File

@ -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,
spv::StorageClass storage_class); SpvStorageClass 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,
spv::StorageClass storage_class); SpvStorageClass 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(spv::StorageClass storage_class) const; GetAvailableBasicTypesAndPointers(SpvStorageClass 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

View File

@ -34,16 +34,15 @@ 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( assert(inst_it->opcode() ==
inst_it->opcode() == instruction_descriptor.target_instruction_opcode() &&
spv::Op(instruction_descriptor.target_instruction_opcode()) && "The opcode of the instruction we might insert before must be "
"The opcode of the instruction we might insert before must be " "the same as the opcode in the descriptor for the instruction");
"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( if (!fuzzerutil::CanInsertOpcodeBeforeInstruction(SpvOpAccessChain,
spv::Op::OpAccessChain, inst_it)) { inst_it)) {
return; return;
} }
@ -65,8 +64,8 @@ void FuzzerPassAddAccessChains::Apply() {
return false; return false;
} }
switch (instruction->opcode()) { switch (instruction->opcode()) {
case spv::Op::OpConstantNull: case SpvOpConstantNull:
case spv::Op::OpUndef: case SpvOpUndef:
// 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
@ -79,7 +78,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() == spv::Op::OpTypePointer; ->opcode() == SpvOpTypePointer;
}); });
// At this point, |relevant_instructions| contains all the pointers // At this point, |relevant_instructions| contains all the pointers
@ -113,14 +112,14 @@ void FuzzerPassAddAccessChains::Apply() {
} }
uint32_t bound; uint32_t bound;
switch (subobject_type->opcode()) { switch (subobject_type->opcode()) {
case spv::Op::OpTypeArray: case SpvOpTypeArray:
bound = fuzzerutil::GetArraySize(*subobject_type, GetIRContext()); bound = fuzzerutil::GetArraySize(*subobject_type, GetIRContext());
break; break;
case spv::Op::OpTypeMatrix: case SpvOpTypeMatrix:
case spv::Op::OpTypeVector: case SpvOpTypeVector:
bound = subobject_type->GetSingleWordInOperand(1); bound = subobject_type->GetSingleWordInOperand(1);
break; break;
case spv::Op::OpTypeStruct: case SpvOpTypeStruct:
bound = fuzzerutil::GetNumberOfStructMembers(*subobject_type); bound = fuzzerutil::GetNumberOfStructMembers(*subobject_type);
break; break;
default: default:
@ -141,9 +140,9 @@ void FuzzerPassAddAccessChains::Apply() {
GetFuzzerContext()->GetRandomIndexForAccessChain(bound); GetFuzzerContext()->GetRandomIndexForAccessChain(bound);
switch (subobject_type->opcode()) { switch (subobject_type->opcode()) {
case spv::Op::OpTypeArray: case SpvOpTypeArray:
case spv::Op::OpTypeMatrix: case SpvOpTypeMatrix:
case spv::Op::OpTypeVector: { case SpvOpTypeVector: {
// The index will be clamped // The index will be clamped
bool is_signed = GetFuzzerContext()->ChooseEven(); bool is_signed = GetFuzzerContext()->ChooseEven();
@ -165,7 +164,7 @@ void FuzzerPassAddAccessChains::Apply() {
subobject_type_id = subobject_type->GetSingleWordInOperand(0); subobject_type_id = subobject_type->GetSingleWordInOperand(0);
} break; } break;
case spv::Op::OpTypeStruct: case SpvOpTypeStruct:
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 =
@ -179,7 +178,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<spv::StorageClass>( static_cast<SpvStorageClass>(
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(

View File

@ -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( if (!fuzzerutil::CanInsertOpcodeBeforeInstruction(SpvOpCompositeExtract,
spv::Op::OpCompositeExtract, inst_it)) { 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 spv::Op::OpTypeArray: case SpvOpTypeArray:
number_of_members = number_of_members =
fuzzerutil::GetArraySize(*type_inst, GetIRContext()); fuzzerutil::GetArraySize(*type_inst, GetIRContext());
break; break;
case spv::Op::OpTypeVector: case SpvOpTypeVector:
case spv::Op::OpTypeMatrix: case SpvOpTypeMatrix:
number_of_members = type_inst->GetSingleWordInOperand(1); number_of_members = type_inst->GetSingleWordInOperand(1);
break; break;
case spv::Op::OpTypeStruct: case SpvOpTypeStruct:
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 spv::Op::OpTypeArray: case SpvOpTypeArray:
case spv::Op::OpTypeVector: case SpvOpTypeVector:
case spv::Op::OpTypeMatrix: case SpvOpTypeMatrix:
type_id = type_inst->GetSingleWordInOperand(0); type_id = type_inst->GetSingleWordInOperand(0);
break; break;
case spv::Op::OpTypeStruct: case SpvOpTypeStruct:
type_id = type_inst->GetSingleWordInOperand(indices.back()); type_id = type_inst->GetSingleWordInOperand(indices.back());
break; break;
default: default:

View File

@ -36,11 +36,10 @@ 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( assert(instruction_iterator->opcode() ==
instruction_iterator->opcode() == instruction_descriptor.target_instruction_opcode() &&
spv::Op(instruction_descriptor.target_instruction_opcode()) && "The opcode of the instruction we might insert before must be "
"The opcode of the instruction we might insert before must be " "the same as the opcode in the descriptor for the instruction");
"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.
@ -52,7 +51,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(
spv::Op::OpCompositeInsert, instruction_iterator)) { SpvOpCompositeInsert, instruction_iterator)) {
return; return;
} }

View File

@ -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 spv::Op::OpTypeArray: case SpvOpTypeArray:
case spv::Op::OpTypeBool: case SpvOpTypeBool:
case spv::Op::OpTypeFloat: case SpvOpTypeFloat:
case spv::Op::OpTypeInt: case SpvOpTypeInt:
case spv::Op::OpTypeMatrix: case SpvOpTypeMatrix:
case spv::Op::OpTypeVector: case SpvOpTypeVector:
candidates.push_back(inst.result_id()); candidates.push_back(inst.result_id());
break; break;
case spv::Op::OpTypeStruct: { case SpvOpTypeStruct: {
if (!fuzzerutil::MembersHaveBuiltInDecoration(GetIRContext(), if (!fuzzerutil::MembersHaveBuiltInDecoration(GetIRContext(),
inst.result_id()) && inst.result_id()) &&
!fuzzerutil::HasBlockOrBufferBlockDecoration(GetIRContext(), !fuzzerutil::HasBlockOrBufferBlockDecoration(GetIRContext(),

View File

@ -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(spv::Op::OpCopyMemory, if (!fuzzerutil::CanInsertOpcodeBeforeInstruction(SpvOpCopyMemory,
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()
? spv::StorageClass::Private ? SpvStorageClassPrivate
: spv::StorageClass::Function; : SpvStorageClassFunction;
auto pointee_type_id = fuzzerutil::GetPointeeTypeIdFromPointerType( auto pointee_type_id = fuzzerutil::GetPointeeTypeIdFromPointerType(
GetIRContext(), inst->type_id()); GetIRContext(), inst->type_id());

View File

@ -29,14 +29,12 @@ 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(
spv::Capability::Float64) && SpvCapabilityFloat64) &&
ir_context->get_feature_mgr()->HasCapability( ir_context->get_feature_mgr()->HasCapability(SpvCapabilityInt64);
spv::Capability::Int64);
case 16: case 16:
return ir_context->get_feature_mgr()->HasCapability( return ir_context->get_feature_mgr()->HasCapability(
spv::Capability::Float16) && SpvCapabilityFloat16) &&
ir_context->get_feature_mgr()->HasCapability( ir_context->get_feature_mgr()->HasCapability(SpvCapabilityInt16);
spv::Capability::Int16);
default: default:
return false; return false;
} }
@ -68,8 +66,7 @@ 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(spv::Op::OpIAdd, if (!fuzzerutil::CanInsertOpcodeBeforeInstruction(SpvOpIAdd, inst_it)) {
inst_it)) {
return; return;
} }
@ -81,7 +78,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() != spv::Op::OpUndef && instruction->opcode() != SpvOpUndef &&
!GetTransformationContext() !GetTransformationContext()
->GetFactManager() ->GetFactManager()
->IdIsIrrelevant(instruction->result_id()); ->IdIsIrrelevant(instruction->result_id());
@ -89,16 +86,15 @@ 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<spv::Op> candidate_opcodes = { std::vector<SpvOp> candidate_opcodes = {
spv::Op::OpIAdd, spv::Op::OpISub, spv::Op::OpLogicalNot, SpvOpIAdd, SpvOpISub, SpvOpLogicalNot, SpvOpSNegate,
spv::Op::OpSNegate, spv::Op::OpConvertUToF, spv::Op::OpConvertSToF, SpvOpConvertUToF, SpvOpConvertSToF, SpvOpBitcast};
spv::Op::OpBitcast};
do { do {
auto opcode = auto opcode =
GetFuzzerContext()->RemoveAtRandomIndex(&candidate_opcodes); GetFuzzerContext()->RemoveAtRandomIndex(&candidate_opcodes);
switch (opcode) { switch (opcode) {
case spv::Op::OpConvertSToF: case SpvOpConvertSToF:
case spv::Op::OpConvertUToF: { case SpvOpConvertUToF: {
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)) {
@ -148,7 +144,7 @@ void FuzzerPassAddEquationInstructions::Apply() {
{operand->result_id()}, instruction_descriptor)); {operand->result_id()}, instruction_descriptor));
return; return;
} }
case spv::Op::OpBitcast: { case SpvOpBitcast: {
const auto candidate_instructions = const auto candidate_instructions =
GetNumericalInstructions(available_instructions); GetNumericalInstructions(available_instructions);
@ -201,8 +197,8 @@ void FuzzerPassAddEquationInstructions::Apply() {
return; return;
} }
} break; } break;
case spv::Op::OpIAdd: case SpvOpIAdd:
case spv::Op::OpISub: { case SpvOpISub: {
// 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 =
@ -255,7 +251,7 @@ void FuzzerPassAddEquationInstructions::Apply() {
} }
break; break;
} }
case spv::Op::OpLogicalNot: { case SpvOpLogicalNot: {
// 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 =
@ -272,7 +268,7 @@ void FuzzerPassAddEquationInstructions::Apply() {
} }
break; break;
} }
case spv::Op::OpSNegate: { case SpvOpSNegate: {
// 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);

View File

@ -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( if (!fuzzerutil::CanInsertOpcodeBeforeInstruction(SpvOpFunctionCall,
spv::Op::OpFunctionCall, inst_it)) { 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() != spv::Op::OpVariable || if (inst->opcode() != SpvOpVariable ||
inst->opcode() != spv::Op::OpFunctionParameter) { inst->opcode() != SpvOpFunctionParameter) {
// 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 == spv::StorageClass::Function) { if (storage_class == SpvStorageClassFunction) {
// 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 == spv::StorageClass::Private || assert((storage_class == SpvStorageClassPrivate ||
storage_class == spv::StorageClass::Workgroup) && storage_class == SpvStorageClassWorkgroup) &&
"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 == spv::StorageClass::Private storage_class == SpvStorageClassPrivate
? FindOrCreateZeroConstant(pointee_type_id, false) ? FindOrCreateZeroConstant(pointee_type_id, false)
: 0, : 0,
true)); true));

View File

@ -29,17 +29,16 @@ FuzzerPassAddGlobalVariables::FuzzerPassAddGlobalVariables(
transformations, ignore_inapplicable_transformations) {} transformations, ignore_inapplicable_transformations) {}
void FuzzerPassAddGlobalVariables::Apply() { void FuzzerPassAddGlobalVariables::Apply() {
spv::StorageClass variable_storage_class = spv::StorageClass::Private; SpvStorageClass variable_storage_class = SpvStorageClassPrivate;
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 (spv::ExecutionModel(entry_point.GetSingleWordInOperand(0)) == if (entry_point.GetSingleWordInOperand(0) == SpvExecutionModelGLCompute) {
spv::ExecutionModel::GLCompute) {
variable_storage_class = variable_storage_class =
GetFuzzerContext()->ChoosePercentage( GetFuzzerContext()->ChoosePercentage(
GetFuzzerContext()->GetChanceOfChoosingWorkgroupStorageClass()) GetFuzzerContext()->GetChanceOfChoosingWorkgroupStorageClass())
? spv::StorageClass::Workgroup ? SpvStorageClassWorkgroup
: spv::StorageClass::Private; : SpvStorageClassPrivate;
break; break;
} }
} }
@ -88,7 +87,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 == spv::StorageClass::Private variable_storage_class == SpvStorageClassPrivate
? FindOrCreateZeroConstant(basic_type, false) ? FindOrCreateZeroConstant(basic_type, false)
: 0, : 0,
true)); true));

View File

@ -34,11 +34,10 @@ 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( assert(inst_it->opcode() ==
inst_it->opcode() == instruction_descriptor.target_instruction_opcode() &&
spv::Op(instruction_descriptor.target_instruction_opcode()) && "The opcode of the instruction we might insert before must be "
"The opcode of the instruction we might insert before must be " "the same as the opcode in the descriptor for the instruction");
"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(
@ -48,11 +47,10 @@ 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(spv::Op::OpLoad, if (!fuzzerutil::CanInsertOpcodeBeforeInstruction(SpvOpLoad, inst_it)) {
inst_it)) {
return; return;
} }
if (!fuzzerutil::CanInsertOpcodeBeforeInstruction(spv::Op::OpAtomicLoad, if (!fuzzerutil::CanInsertOpcodeBeforeInstruction(SpvOpAtomicLoad,
inst_it)) { inst_it)) {
return; return;
} }
@ -66,8 +64,8 @@ void FuzzerPassAddLoads::Apply() {
return false; return false;
} }
switch (instruction->opcode()) { switch (instruction->opcode()) {
case spv::Op::OpConstantNull: case SpvOpConstantNull:
case spv::Op::OpUndef: case SpvOpUndef:
// 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.
@ -77,7 +75,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() == spv::Op::OpTypePointer; ->opcode() == SpvOpTypePointer;
}); });
// At this point, |relevant_instructions| contains all the pointers // At this point, |relevant_instructions| contains all the pointers
@ -94,25 +92,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<spv::StorageClass>( auto storage_class = static_cast<SpvStorageClass>(
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 spv::StorageClass::StorageBuffer: case SpvStorageClassStorageBuffer:
case spv::StorageClass::PhysicalStorageBuffer: case SpvStorageClassPhysicalStorageBuffer:
case spv::StorageClass::Workgroup: case SpvStorageClassWorkgroup:
case spv::StorageClass::CrossWorkgroup: case SpvStorageClassCrossWorkgroup:
case spv::StorageClass::AtomicCounter: case SpvStorageClassAtomicCounter:
case spv::StorageClass::Image: case SpvStorageClassImage:
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(
{uint32_t(spv::Scope::Invocation)}, {SpvScopeInvocation},
FindOrCreateIntegerType(32, GetFuzzerContext()->ChooseEven()), FindOrCreateIntegerType(32, GetFuzzerContext()->ChooseEven()),
false); false);

View File

@ -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(spv::StorageClass::Function); GetAvailableBasicTypesAndPointers(SpvStorageClassFunction);
// 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, spv::StorageClass::Function, basic_type)); pointer_type, SpvStorageClassFunction, 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.

View File

@ -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() == spv::Op::OpFunction || if (pair.second->opcode() == SpvOpFunction ||
pair.second->opcode() == spv::Op::OpUndef) { pair.second->opcode() == SpvOpUndef) {
continue; continue;
} }

View File

@ -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 spv::StorageClass::Function: { case SpvStorageClassFunction: {
// 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 spv::StorageClass::Private: case SpvStorageClassPrivate:
case spv::StorageClass::Workgroup: { case SpvStorageClassWorkgroup: {
// 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 =

View File

@ -34,11 +34,10 @@ 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( assert(inst_it->opcode() ==
inst_it->opcode() == instruction_descriptor.target_instruction_opcode() &&
spv::Op(instruction_descriptor.target_instruction_opcode()) && "The opcode of the instruction we might insert before must be "
"The opcode of the instruction we might insert before must be " "the same as the opcode in the descriptor for the instruction");
"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(
@ -48,12 +47,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(spv::Op::OpStore, if (!fuzzerutil::CanInsertOpcodeBeforeInstruction(SpvOpStore,
inst_it)) { inst_it)) {
return; return;
} }
if (!fuzzerutil::CanInsertOpcodeBeforeInstruction( if (!fuzzerutil::CanInsertOpcodeBeforeInstruction(SpvOpAtomicStore,
spv::Op::OpAtomicStore, inst_it)) { inst_it)) {
return; return;
} }
@ -68,7 +67,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() != spv::Op::OpTypePointer) { if (type_inst->opcode() != SpvOpTypePointer) {
// Not a pointer. // Not a pointer.
return false; return false;
} }
@ -77,8 +76,8 @@ void FuzzerPassAddStores::Apply() {
return false; return false;
} }
switch (instruction->opcode()) { switch (instruction->opcode()) {
case spv::Op::OpConstantNull: case SpvOpConstantNull:
case spv::Op::OpUndef: case SpvOpUndef:
// 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.
@ -127,24 +126,24 @@ void FuzzerPassAddStores::Apply() {
uint32_t memory_semantics_id = 0; uint32_t memory_semantics_id = 0;
auto storage_class = auto storage_class =
static_cast<spv::StorageClass>(GetIRContext() static_cast<SpvStorageClass>(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 spv::StorageClass::StorageBuffer: case SpvStorageClassStorageBuffer:
case spv::StorageClass::PhysicalStorageBuffer: case SpvStorageClassPhysicalStorageBuffer:
case spv::StorageClass::Workgroup: case SpvStorageClassWorkgroup:
case spv::StorageClass::CrossWorkgroup: case SpvStorageClassCrossWorkgroup:
case spv::StorageClass::AtomicCounter: case SpvStorageClassAtomicCounter:
case spv::StorageClass::Image: case SpvStorageClassImage:
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(
{uint32_t(spv::Scope::Invocation)}, {SpvScopeInvocation},
FindOrCreateIntegerType(32, GetFuzzerContext()->ChooseEven()), FindOrCreateIntegerType(32, GetFuzzerContext()->ChooseEven()),
false); false);

View File

@ -44,8 +44,7 @@ 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(spv::Op::OpIAdd, if (!fuzzerutil::CanInsertOpcodeBeforeInstruction(SpvOpIAdd, inst_it)) {
inst_it)) {
return; return;
} }

View File

@ -35,11 +35,10 @@ 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( assert(instruction_iterator->opcode() ==
instruction_iterator->opcode() == instruction_descriptor.target_instruction_opcode() &&
spv::Op(instruction_descriptor.target_instruction_opcode()) && "The opcode of the instruction we might insert before must be "
"The opcode of the instruction we might insert before must be " "the same as the opcode in the descriptor for the instruction");
"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(
@ -50,7 +49,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(
spv::Op::OpVectorShuffle, instruction_iterator)) { SpvOpVectorShuffle, instruction_iterator)) {
return; return;
} }

View File

@ -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() == spv::Op::OpBranchConditional && if (instruction->opcode() == SpvOpBranchConditional &&
GetFuzzerContext()->ChoosePercentage( GetFuzzerContext()->ChoosePercentage(
GetFuzzerContext()->GetChanceOfAdjustingBranchWeights())) { GetFuzzerContext()->GetChanceOfAdjustingBranchWeights())) {
ApplyTransformation(TransformationAdjustBranchWeights( ApplyTransformation(TransformationAdjustBranchWeights(

View File

@ -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<spv::FunctionControlMask> basic_function_control_masks = { std::vector<uint32_t> basic_function_control_masks = {
spv::FunctionControlMask::MaskNone, spv::FunctionControlMask::Inline, SpvFunctionControlMaskNone, SpvFunctionControlInlineMask,
spv::FunctionControlMask::DontInline}; SpvFunctionControlDontInlineMask};
uint32_t new_function_control_mask = uint32_t new_function_control_mask =
uint32_t(basic_function_control_masks[GetFuzzerContext()->RandomIndex( 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 :
{spv::FunctionControlMask::Pure, spv::FunctionControlMask::Const}) { {SpvFunctionControlPureMask, SpvFunctionControlConstMask}) {
if ((existing_function_control_mask & uint32_t(mask_bit)) && if ((existing_function_control_mask & mask_bit) &&
GetFuzzerContext()->ChooseEven()) { GetFuzzerContext()->ChooseEven()) {
new_function_control_mask |= uint32_t(mask_bit); new_function_control_mask |= mask_bit;
} }
} }

View File

@ -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() != spv::Op::OpLoopMerge) { if (merge_inst->opcode() != SpvOpLoopMerge) {
continue; continue;
} }
@ -48,10 +48,9 @@ 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 = { std::vector<uint32_t> basic_masks = {SpvLoopControlMaskNone,
uint32_t(spv::LoopControlMask::MaskNone), SpvLoopControlUnrollMask,
uint32_t(spv::LoopControlMask::Unroll), SpvLoopControlDontUnrollMask};
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)];
@ -59,20 +58,19 @@ 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 : {spv::LoopControlMask::DependencyInfinite, for (auto mask_bit :
spv::LoopControlMask::DependencyLength, {SpvLoopControlDependencyInfiniteMask,
spv::LoopControlMask::MinIterations, SpvLoopControlDependencyLengthMask,
spv::LoopControlMask::MaxIterations, SpvLoopControlMinIterationsMask, SpvLoopControlMaxIterationsMask,
spv::LoopControlMask::IterationMultiple}) { SpvLoopControlIterationMultipleMask}) {
if ((existing_mask & uint32_t(mask_bit)) && if ((existing_mask & mask_bit) && GetFuzzerContext()->ChooseEven()) {
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 |= uint32_t(mask_bit); new_mask |= mask_bit;
} }
} }
@ -83,14 +81,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 & uint32_t(spv::LoopControlMask::DontUnroll))) { if (!(new_mask & SpvLoopControlDontUnrollMask)) {
// 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 |= uint32_t(spv::LoopControlMask::PeelCount); new_mask |= SpvLoopControlPeelCountMask;
// 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();
@ -99,7 +97,7 @@ void FuzzerPassAdjustLoopControls::Apply() {
if (TransformationSetLoopControl::PartialCountIsSupported( if (TransformationSetLoopControl::PartialCountIsSupported(
GetIRContext()) && GetIRContext()) &&
GetFuzzerContext()->ChooseEven()) { GetFuzzerContext()->ChooseEven()) {
new_mask |= uint32_t(spv::LoopControlMask::PartialCount); new_mask |= SpvLoopControlPartialCountMask;
partial_count = partial_count =
GetFuzzerContext()->GetRandomLoopControlPartialCount(); GetFuzzerContext()->GetRandomLoopControlPartialCount();
} }

View File

@ -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 spv::Op::OpCopyMemory: case SpvOpCopyMemory:
case spv::Op::OpCopyMemorySized: case SpvOpCopyMemorySized:
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,26 +75,24 @@ 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>(spv::MemoryAccessMask::MaskNone); : static_cast<uint32_t>(SpvMemoryAccessMaskNone);
// 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 = bool add_volatile = !(existing_mask & SpvMemoryAccessVolatileMask) &&
!(existing_mask & uint32_t(spv::MemoryAccessMask::Volatile)) && GetFuzzerContext()->ChooseEven();
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 | (existing_mask | (add_volatile ? SpvMemoryAccessVolatileMask
(add_volatile ? uint32_t(spv::MemoryAccessMask::Volatile) : SpvMemoryAccessMaskNone)) ^
: uint32_t(spv::MemoryAccessMask::MaskNone))) ^ (toggle_nontemporal ? SpvMemoryAccessNontemporalMask
(toggle_nontemporal ? uint32_t(spv::MemoryAccessMask::Nontemporal) : SpvMemoryAccessMaskNone);
: 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);

View File

@ -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() != spv::Op::OpSelectionMerge) { if (merge_inst->opcode() != SpvOpSelectionMerge) {
continue; continue;
} }
@ -48,14 +48,13 @@ 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 : {spv::SelectionControlMask::MaskNone, for (auto control :
spv::SelectionControlMask::Flatten, {SpvSelectionControlMaskNone, SpvSelectionControlFlattenMask,
spv::SelectionControlMask::DontFlatten}) { SpvSelectionControlDontFlattenMask}) {
if (control == if (control == merge_inst->GetSingleWordOperand(1)) {
spv::SelectionControlMask(merge_inst->GetSingleWordOperand(1))) {
continue; continue;
} }
choices.push_back(uint32_t(control)); choices.push_back(control);
} }
// Apply the transformation and add it to the output transformation // Apply the transformation and add it to the output transformation

View File

@ -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( !fuzzerutil::CanInsertOpcodeBeforeInstruction(SpvOpCompositeExtract,
spv::Op::OpCompositeExtract, use_inst) && use_inst) &&
use_inst->opcode() != spv::Op::OpPhi) { use_inst->opcode() != SpvOpPhi) {
// 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() != spv::Op::OpPhi) { if (use_inst->opcode() != SpvOpPhi) {
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(
spv::Op opcode, uint32_t use_in_operand_index, SpvOp 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 =

View File

@ -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(spv::Op opcode, bool DataDescriptorsHaveCompatibleTypes(SpvOp 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);

View File

@ -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(
spv::Op::OpCompositeConstruct, inst_it)) { SpvOpCompositeConstruct, 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 spv::Op::OpTypeArray: case SpvOpTypeArray:
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 spv::Op::OpTypeMatrix: case SpvOpTypeMatrix:
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 spv::Op::OpTypeStruct: case SpvOpTypeStruct:
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 spv::Op::OpTypeVector: case SpvOpTypeVector:
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() == spv::Op::OpTypeArray && assert(array_type_instruction.opcode() == SpvOpTypeArray &&
"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() == spv::Op::OpTypeMatrix && assert(matrix_type_instruction.opcode() == SpvOpTypeMatrix &&
"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() == spv::Op::OpTypeStruct && assert(struct_type_instruction.opcode() == SpvOpTypeStruct &&
"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() == spv::Op::OpTypeVector && assert(vector_type_instruction.opcode() == SpvOpTypeVector &&
"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,

View File

@ -35,11 +35,10 @@ 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( assert(inst_it->opcode() ==
inst_it->opcode() == instruction_descriptor.target_instruction_opcode() &&
spv::Op(instruction_descriptor.target_instruction_opcode()) && "The opcode of the instruction we might insert before must be "
"The opcode of the instruction we might insert before must be " "the same as the opcode in the descriptor for the instruction");
"the same as the opcode in the descriptor for the instruction");
if (GetTransformationContext()->GetFactManager()->BlockIsDead( if (GetTransformationContext()->GetFactManager()->BlockIsDead(
block->id())) { block->id())) {
@ -49,7 +48,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(spv::Op::OpCopyObject, if (!fuzzerutil::CanInsertOpcodeBeforeInstruction(SpvOpCopyObject,
inst_it)) { inst_it)) {
return; return;
} }

View File

@ -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<spv::Capability>(capability_inst.GetSingleWordInOperand(0)); static_cast<SpvCapability>(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.
} }
spv::StorageClass FuzzerPassDonateModules::AdaptStorageClass( SpvStorageClass FuzzerPassDonateModules::AdaptStorageClass(
spv::StorageClass donor_storage_class) { SpvStorageClass donor_storage_class) {
switch (donor_storage_class) { switch (donor_storage_class) {
case spv::StorageClass::Function: case SpvStorageClassFunction:
case spv::StorageClass::Private: case SpvStorageClassPrivate:
case spv::StorageClass::Workgroup: case SpvStorageClassWorkgroup:
// We leave these alone // We leave these alone
return donor_storage_class; return donor_storage_class;
case spv::StorageClass::Input: case SpvStorageClassInput:
case spv::StorageClass::Output: case SpvStorageClassOutput:
case spv::StorageClass::Uniform: case SpvStorageClassUniform:
case spv::StorageClass::UniformConstant: case SpvStorageClassUniformConstant:
case spv::StorageClass::PushConstant: case SpvStorageClassPushConstant:
case spv::StorageClass::Image: case SpvStorageClassImage:
case spv::StorageClass::StorageBuffer: case SpvStorageClassStorageBuffer:
// We change these to Private // We change these to Private
return spv::StorageClass::Private; return SpvStorageClassPrivate;
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 spv::StorageClass::Max; return SpvStorageClassMax;
} }
} }
@ -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 spv::Op::OpTypeImage: case SpvOpTypeImage:
case spv::Op::OpTypeSampledImage: case SpvOpTypeSampledImage:
case spv::Op::OpTypeSampler: case SpvOpTypeSampler:
// 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 spv::Op::OpTypeVoid: { case SpvOpTypeVoid: {
// 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 spv::Op::OpTypeBool: { case SpvOpTypeBool: {
// 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 spv::Op::OpTypeInt: { case SpvOpTypeInt: {
// 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 spv::Op::OpTypeFloat: { case SpvOpTypeFloat: {
// Similar to spv::Op::OpTypeInt. // Similar to SpvOpTypeInt.
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 spv::Op::OpTypeVector: { case SpvOpTypeVector: {
// 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 spv::Op::OpTypeMatrix: { case SpvOpTypeMatrix: {
// Similar to spv::Op::OpTypeVector. // Similar to SpvOpTypeVector.
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 spv::Op::OpTypeArray: { case SpvOpTypeArray: {
// 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 spv::Op::OpTypeRuntimeArray: { case SpvOpTypeRuntimeArray: {
// 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 spv::Op::OpTypeStruct: { case SpvOpTypeStruct: {
// Similar to spv::Op::OpTypeArray. // Similar to SpvOpTypeArray.
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 spv::Op::OpTypePointer: { case SpvOpTypePointer: {
// Similar to spv::Op::OpTypeArray. // Similar to SpvOpTypeArray.
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<spv::StorageClass>( AdaptStorageClass(static_cast<SpvStorageClass>(
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 spv::Op::OpTypeFunction: { case SpvOpTypeFunction: {
// 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,11 +425,10 @@ void FuzzerPassDonateModules::HandleTypeOrValue(
argument_type_ids)); argument_type_ids));
} }
} break; } break;
case spv::Op::OpSpecConstantOp: { case SpvOpSpecConstantOp: {
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 = auto opcode = static_cast<SpvOp>(type_or_value.GetSingleWordInOperand(0));
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.
@ -448,20 +447,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 spv::Op::OpSpecConstantTrue: case SpvOpSpecConstantTrue:
case spv::Op::OpSpecConstantFalse: case SpvOpSpecConstantFalse:
case spv::Op::OpConstantTrue: case SpvOpConstantTrue:
case spv::Op::OpConstantFalse: { case SpvOpConstantFalse: {
// 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() == spv::Op::OpConstantTrue || auto value = type_or_value.opcode() == SpvOpConstantTrue ||
type_or_value.opcode() == spv::Op::OpSpecConstantTrue; type_or_value.opcode() == SpvOpSpecConstantTrue;
ApplyTransformation( ApplyTransformation(
TransformationAddConstantBoolean(new_result_id, value, false)); TransformationAddConstantBoolean(new_result_id, value, false));
} break; } break;
case spv::Op::OpSpecConstant: case SpvOpSpecConstant:
case spv::Op::OpConstant: { case SpvOpConstant: {
// 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();
@ -473,8 +472,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 spv::Op::OpSpecConstantComposite: case SpvOpSpecConstantComposite:
case spv::Op::OpConstantComposite: { case SpvOpConstantComposite: {
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.");
@ -496,7 +495,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 spv::Op::OpConstantNull: { case SpvOpConstantNull: {
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.
@ -510,7 +509,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 spv::Op::OpVariable: { case SpvOpVariable: {
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.
@ -537,11 +536,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;
spv::StorageClass storage_class = SpvStorageClass storage_class =
static_cast<spv::StorageClass>(type_or_value.GetSingleWordInOperand( static_cast<SpvStorageClass>(type_or_value.GetSingleWordInOperand(
0)) == spv::StorageClass::Workgroup 0)) == SpvStorageClassWorkgroup
? spv::StorageClass::Workgroup ? SpvStorageClassWorkgroup
: spv::StorageClass::Private; : SpvStorageClassPrivate;
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
@ -552,7 +551,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 == spv::StorageClass::Workgroup initializer_id = storage_class == SpvStorageClassWorkgroup
? 0 ? 0
: FindOrCreateZeroConstant( : FindOrCreateZeroConstant(
fuzzerutil::GetPointeeTypeIdFromPointerType( fuzzerutil::GetPointeeTypeIdFromPointerType(
@ -567,7 +566,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 spv::Op::OpUndef: { case SpvOpUndef: {
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.
@ -639,7 +638,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() == spv::Op::OpArrayLength) { if (instruction->opcode() == SpvOpArrayLength) {
// 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);
@ -683,70 +682,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 spv::Op::OpAtomicLoad: case SpvOpAtomicLoad:
case spv::Op::OpAtomicStore: case SpvOpAtomicStore:
case spv::Op::OpAtomicExchange: case SpvOpAtomicExchange:
case spv::Op::OpAtomicCompareExchange: case SpvOpAtomicCompareExchange:
case spv::Op::OpAtomicCompareExchangeWeak: case SpvOpAtomicCompareExchangeWeak:
case spv::Op::OpAtomicIIncrement: case SpvOpAtomicIIncrement:
case spv::Op::OpAtomicIDecrement: case SpvOpAtomicIDecrement:
case spv::Op::OpAtomicIAdd: case SpvOpAtomicIAdd:
case spv::Op::OpAtomicISub: case SpvOpAtomicISub:
case spv::Op::OpAtomicSMin: case SpvOpAtomicSMin:
case spv::Op::OpAtomicUMin: case SpvOpAtomicUMin:
case spv::Op::OpAtomicSMax: case SpvOpAtomicSMax:
case spv::Op::OpAtomicUMax: case SpvOpAtomicUMax:
case spv::Op::OpAtomicAnd: case SpvOpAtomicAnd:
case spv::Op::OpAtomicOr: case SpvOpAtomicOr:
case spv::Op::OpAtomicXor: case SpvOpAtomicXor:
// 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 spv::Op::OpImageSampleImplicitLod: case SpvOpImageSampleImplicitLod:
case spv::Op::OpImageSampleExplicitLod: case SpvOpImageSampleExplicitLod:
case spv::Op::OpImageSampleDrefImplicitLod: case SpvOpImageSampleDrefImplicitLod:
case spv::Op::OpImageSampleDrefExplicitLod: case SpvOpImageSampleDrefExplicitLod:
case spv::Op::OpImageSampleProjImplicitLod: case SpvOpImageSampleProjImplicitLod:
case spv::Op::OpImageSampleProjExplicitLod: case SpvOpImageSampleProjExplicitLod:
case spv::Op::OpImageSampleProjDrefImplicitLod: case SpvOpImageSampleProjDrefImplicitLod:
case spv::Op::OpImageSampleProjDrefExplicitLod: case SpvOpImageSampleProjDrefExplicitLod:
case spv::Op::OpImageFetch: case SpvOpImageFetch:
case spv::Op::OpImageGather: case SpvOpImageGather:
case spv::Op::OpImageDrefGather: case SpvOpImageDrefGather:
case spv::Op::OpImageRead: case SpvOpImageRead:
case spv::Op::OpImageWrite: case SpvOpImageWrite:
case spv::Op::OpImageSparseSampleImplicitLod: case SpvOpImageSparseSampleImplicitLod:
case spv::Op::OpImageSparseSampleExplicitLod: case SpvOpImageSparseSampleExplicitLod:
case spv::Op::OpImageSparseSampleDrefImplicitLod: case SpvOpImageSparseSampleDrefImplicitLod:
case spv::Op::OpImageSparseSampleDrefExplicitLod: case SpvOpImageSparseSampleDrefExplicitLod:
case spv::Op::OpImageSparseSampleProjImplicitLod: case SpvOpImageSparseSampleProjImplicitLod:
case spv::Op::OpImageSparseSampleProjExplicitLod: case SpvOpImageSparseSampleProjExplicitLod:
case spv::Op::OpImageSparseSampleProjDrefImplicitLod: case SpvOpImageSparseSampleProjDrefImplicitLod:
case spv::Op::OpImageSparseSampleProjDrefExplicitLod: case SpvOpImageSparseSampleProjDrefExplicitLod:
case spv::Op::OpImageSparseFetch: case SpvOpImageSparseFetch:
case spv::Op::OpImageSparseGather: case SpvOpImageSparseGather:
case spv::Op::OpImageSparseDrefGather: case SpvOpImageSparseDrefGather:
case spv::Op::OpImageSparseRead: case SpvOpImageSparseRead:
case spv::Op::OpImageSampleFootprintNV: case SpvOpImageSampleFootprintNV:
case spv::Op::OpImage: case SpvOpImage:
case spv::Op::OpImageQueryFormat: case SpvOpImageQueryFormat:
case spv::Op::OpImageQueryLevels: case SpvOpImageQueryLevels:
case spv::Op::OpImageQueryLod: case SpvOpImageQueryLod:
case spv::Op::OpImageQueryOrder: case SpvOpImageQueryOrder:
case spv::Op::OpImageQuerySamples: case SpvOpImageQuerySamples:
case spv::Op::OpImageQuerySize: case SpvOpImageQuerySize:
case spv::Op::OpImageQuerySizeLod: case SpvOpImageQuerySizeLod:
case spv::Op::OpSampledImage: case SpvOpSampledImage:
// 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 spv::Op::OpLoad: case SpvOpLoad:
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 spv::Op::OpTypeImage: case SpvOpTypeImage:
case spv::Op::OpTypeSampledImage: case SpvOpTypeSampledImage:
case spv::Op::OpTypeSampler: case SpvOpTypeSampler:
// Again, we ignore instructions that relate to accessing images. // Again, we ignore instructions that relate to accessing images.
return false; return false;
default: default:
@ -784,13 +783,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 spv::Op::OpTypeArray: case SpvOpTypeArray:
case spv::Op::OpTypeBool: case SpvOpTypeBool:
case spv::Op::OpTypeFloat: case SpvOpTypeFloat:
case spv::Op::OpTypeInt: case SpvOpTypeInt:
case spv::Op::OpTypeMatrix: case SpvOpTypeMatrix:
case spv::Op::OpTypeStruct: case SpvOpTypeStruct:
case spv::Op::OpTypeVector: case SpvOpTypeVector:
return true; return true;
default: default:
return false; return false;
@ -801,7 +800,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() == spv::Op::OpArrayLength && assert(instruction.opcode() == SpvOpArrayLength &&
"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));
@ -810,12 +809,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() == spv::Op::OpTypePointer && assert(pointer_to_struct_instruction->opcode() == SpvOpTypePointer &&
"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() == spv::Op::OpTypeStruct && assert(donated_struct_type_instruction->opcode() == SpvOpTypeStruct &&
"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 &&
@ -826,7 +825,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() == spv::Op::OpTypeArray && assert(fixed_size_array_type_instruction->opcode() == SpvOpTypeArray &&
"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);
@ -838,8 +837,7 @@ void FuzzerPassDonateModules::HandleOpArrayLength(
} }
donated_instructions->push_back(MakeInstructionMessage( donated_instructions->push_back(MakeInstructionMessage(
spv::Op::OpCopyObject, SpvOpCopyObject, original_id_to_donated_id->at(instruction.type_id()),
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}}})));
} }
@ -894,7 +892,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(
spv::Op::OpCopyObject, remapped_type_id, SpvOpCopyObject, 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}}})));
} }
@ -928,8 +926,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() == spv::Op::OpLabel || ->opcode() == SpvOpLabel ||
instruction.opcode() == spv::Op::OpPhi) && instruction.opcode() == SpvOpPhi) &&
"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()});
@ -944,7 +942,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() == spv::Op::OpVariable && if (instruction.opcode() == SpvOpVariable &&
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(
@ -1019,7 +1017,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() != spv::Op::OpPhi) { if (inst.opcode() != SpvOpPhi) {
break; break;
} }
@ -1072,8 +1070,7 @@ 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, 32, false, SpvStorageClassFunction); // Needed for adding loop limiters
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,
@ -1110,8 +1107,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 spv::Op::OpAccessChain: case SpvOpAccessChain:
case spv::Op::OpInBoundsAccessChain: { case SpvOpInBoundsAccessChain: {
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()));
@ -1121,8 +1118,7 @@ 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 && assert(pointer_type && pointer_type->opcode() == SpvOpTypePointer &&
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 =
@ -1142,8 +1138,7 @@ 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() == if (should_be_composite_type->opcode() == SpvOpTypeRuntimeArray) {
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
@ -1153,7 +1148,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() == spv::Op::OpTypeArray && assert(fixed_size_array_type->opcode() == SpvOpTypeArray &&
"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.
@ -1168,12 +1163,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() == spv::Op::OpTypeInt); assert(index_type_inst->opcode() == SpvOpTypeInt);
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() != spv::Op::OpConstant) { if (index_inst->opcode() != SpvOpConstant) {
// 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.
@ -1199,7 +1194,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() != spv::Op::OpTypeVoid && if (function_return_type_inst->opcode() != SpvOpTypeVoid &&
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()),

View File

@ -45,8 +45,7 @@ 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 spv::StorageClass AdaptStorageClass( static SpvStorageClass AdaptStorageClass(SpvStorageClass donor_storage_class);
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

View File

@ -40,8 +40,8 @@ void FuzzerPassExpandVectorReductions::Apply() {
} }
// |instruction| must be OpAny or OpAll. // |instruction| must be OpAny or OpAll.
if (instruction.opcode() != spv::Op::OpAny && if (instruction.opcode() != SpvOpAny &&
instruction.opcode() != spv::Op::OpAll) { instruction.opcode() != SpvOpAll) {
continue; continue;
} }

View File

@ -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() == spv::Op::OpSelectionMerge && block.GetMergeInst()->opcode() == SpvOpSelectionMerge &&
block.terminator()->opcode() == spv::Op::OpBranchConditional && block.terminator()->opcode() == SpvOpBranchConditional &&
!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 spv::Op::OpTypeBool: case SpvOpTypeBool:
case spv::Op::OpTypeInt: case SpvOpTypeInt:
case spv::Op::OpTypeFloat: case SpvOpTypeFloat:
case spv::Op::OpTypePointer: case SpvOpTypePointer:
case spv::Op::OpTypeVector: case SpvOpTypeVector:
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 spv::Op::OpTypeVector: { case SpvOpTypeVector: {
uint32_t dimension = uint32_t dimension =
type_instruction->GetSingleWordInOperand(1); type_instruction->GetSingleWordInOperand(1);
switch (dimension) { switch (dimension) {

View File

@ -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() != spv::Op::OpBranch) && function_call_block->terminator()->opcode() != SpvOpBranch) &&
!MaybeApplyTransformation(TransformationSplitBlock( !MaybeApplyTransformation(TransformationSplitBlock(
MakeInstructionDescriptor(GetIRContext(), MakeInstructionDescriptor(GetIRContext(),
function_call_instruction->NextNode()), function_call_instruction->NextNode()),

View File

@ -47,20 +47,18 @@ void FuzzerPassMakeVectorOperationsDynamic::Apply() {
} }
// Make sure |instruction| has only one indexing operand. // Make sure |instruction| has only one indexing operand.
assert( assert(instruction.NumInOperands() ==
instruction.NumInOperands() == (instruction.opcode() == SpvOpCompositeExtract ? 2 : 3) &&
(instruction.opcode() == spv::Op::OpCompositeExtract ? 2 : 3) && "FuzzerPassMakeVectorOperationsDynamic: the composite "
"FuzzerPassMakeVectorOperationsDynamic: the composite " "instruction must have "
"instruction must have " "only one indexing operand.");
"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() == spv::Op::OpCompositeExtract ? 1 instruction.opcode() == SpvOpCompositeExtract ? 1 : 2)},
: 2)},
32, GetFuzzerContext()->ChooseEven(), false))); 32, GetFuzzerContext()->ChooseEven(), false)));
} }
} }

Some files were not shown because too many files have changed in this diff Show More