diff --git a/Android.mk b/Android.mk index f010225b57..f0a0022d60 100644 --- a/Android.mk +++ b/Android.mk @@ -199,44 +199,49 @@ SPVTOOLS_OPT_SRC_FILES := \ source/opt/wrap_opkill.cpp # Locations of grammar files. -# -SPV_COREUNIFIED1_GRAMMAR=$(SPVHEADERS_LOCAL_PATH)/include/spirv/unified1/spirv.core.grammar.json -SPV_DEBUGINFO_GRAMMAR=$(SPVHEADERS_LOCAL_PATH)/include/spirv/unified1/extinst.debuginfo.grammar.json -SPV_CLDEBUGINFO100_GRAMMAR=$(SPVHEADERS_LOCAL_PATH)/include/spirv/unified1/extinst.opencl.debuginfo.100.grammar.json -SPV_VKDEBUGINFO100_GRAMMAR=$(SPVHEADERS_LOCAL_PATH)/include/spirv/unified1/extinst.nonsemantic.shader.debuginfo.100.grammar.json +GRAMMAR_DIR=$(SPVHEADERS_LOCAL_PATH)/include/spirv/unified1 define gen_spvtools_grammar_tables +# $1 is the output directory, which is unique per ABI. +# Rules for creating grammar tables. They are statically compiled +# into the SPIRV-Tools code. $(call generate-file-dir,$(1)/core_tables_body.inc) $(1)/core_tables_body.inc \ $(1)/core_tables_header.inc \ : \ - $(LOCAL_PATH)/utils/generate_grammar_tables.py \ - $(SPV_COREUNIFIED1_GRAMMAR) \ - $(SPV_DEBUGINFO_GRAMMAR) \ - $(SPV_CLDEBUGINFO100_GRAMMAR) - @$(HOST_PYTHON) $(LOCAL_PATH)/utils/ggt.py \ - --spirv-core-grammar=$(SPV_COREUNIFIED1_GRAMMAR) \ - --extinst-debuginfo-grammar=$(SPV_DEBUGINFO_GRAMMAR) \ - --extinst-cldebuginfo100-grammar=$(SPV_CLDEBUGINFO100_GRAMMAR) \ - --core-tables-body-output=$(1)/core_tables_body.inc \ - --core-tables-header-output=$(1)/core_tables_header.inc - @echo "[$(TARGET_ARCH_ABI)] Grammar from unified1) : instructions & operands <= grammar JSON files" + $(LOCAL_PATH)/utils/ggt.py \ + $(GRAMMAR_DIR)/extinst.debuginfo.grammar.json \ + $(GRAMMAR_DIR)/extinst.glsl.std.450.grammar.json \ + $(GRAMMAR_DIR)/extinst.nonsemantic.clspvreflection.grammar.json \ + $(GRAMMAR_DIR)/extinst.nonsemantic.shader.debuginfo.100.grammar.json \ + $(GRAMMAR_DIR)/extinst.nonsemantic.vkspreflection.grammar.json \ + $(GRAMMAR_DIR)/extinst.opencl.debuginfo.100.grammar.json \ + $(GRAMMAR_DIR)/extinst.opencl.std.100.grammar.json \ + $(GRAMMAR_DIR)/extinst.spv-amd-gcn-shader.grammar.json \ + $(GRAMMAR_DIR)/extinst.spv-amd-shader-ballot.grammar.json \ + $(GRAMMAR_DIR)/extinst.spv-amd-shader-explicit-vertex-parameter.grammar.json \ + $(GRAMMAR_DIR)/extinst.spv-amd-shader-trinary-minmax.grammar.json \ + $(GRAMMAR_DIR)/spirv.core.grammar.json + @$(HOST_PYTHON) $(LOCAL_PATH)/utils/ggt.py \ + --core-tables-body-output=$(1)/core_tables_body.inc \ + --core-tables-header-output=$(1)/core_tables_header.inc \ + --spirv-core-grammar=$(GRAMMAR_DIR)/spirv.core.grammar.json \ + --extinst=,$(GRAMMAR_DIR)/extinst.debuginfo.grammar.json \ + --extinst=,$(GRAMMAR_DIR)/extinst.glsl.std.450.grammar.json \ + --extinst=,$(GRAMMAR_DIR)/extinst.nonsemantic.clspvreflection.grammar.json \ + --extinst=SHDEBUG100_,$(GRAMMAR_DIR)/extinst.nonsemantic.shader.debuginfo.100.grammar.json \ + --extinst=,$(GRAMMAR_DIR)/extinst.nonsemantic.vkspreflection.grammar.json \ + --extinst=CLDEBUG100_,$(GRAMMAR_DIR)/extinst.opencl.debuginfo.100.grammar.json \ + --extinst=,$(GRAMMAR_DIR)/extinst.opencl.std.100.grammar.json \ + --extinst=,$(GRAMMAR_DIR)/extinst.spv-amd-gcn-shader.grammar.json \ + --extinst=,$(GRAMMAR_DIR)/extinst.spv-amd-shader-ballot.grammar.json \ + --extinst=,$(GRAMMAR_DIR)/extinst.spv-amd-shader-explicit-vertex-parameter.grammar.json \ + --extinst=,$(GRAMMAR_DIR)/extinst.spv-amd-shader-trinary-minmax.grammar.json + @echo "[$(TARGET_ARCH_ABI)] Grammar tables <= grammar JSON files" # Make all source files depend on the generated core tables $(foreach F,$(SPVTOOLS_SRC_FILES) $(SPVTOOLS_OPT_SRC_FILES),$(LOCAL_PATH)/$F ) \ : $(1)/core_tables_body.inc \ $(1)/core_tables_header.inc -$(LOCAL_PATH)/source/ext_inst.cpp: \ - $(1)/glsl.std.450.insts.inc \ - $(1)/opencl.std.100.insts.inc \ - $(1)/debuginfo.insts.inc \ - $(1)/opencl.debuginfo.100.insts.inc \ - $(1)/nonsemantic.shader.debuginfo.100.insts.inc \ - $(1)/spv-amd-gcn-shader.insts.inc \ - $(1)/spv-amd-shader-ballot.insts.inc \ - $(1)/spv-amd-shader-explicit-vertex-parameter.insts.inc \ - $(1)/spv-amd-shader-trinary-minmax.insts.inc -$(LOCAL_PATH)/source/opt/amd_ext_to_khr.cpp: \ - $(1)/spv-amd-shader-ballot.insts.inc endef $(eval $(call gen_spvtools_grammar_tables,$(SPVTOOLS_OUT_PATH))) @@ -257,36 +262,13 @@ $(1)/$(2).h : \ $(foreach F,$(SPVTOOLS_SRC_FILES) $(SPVTOOLS_OPT_SRC_FILES),$(LOCAL_PATH)/$F ) \ : $(1)/$(2).h endef -# We generate language-specific headers for DebugInfo and OpenCL.DebugInfo.100 -$(eval $(call gen_spvtools_lang_headers,$(SPVTOOLS_OUT_PATH),DebugInfo,$(SPV_DEBUGINFO_GRAMMAR))) -$(eval $(call gen_spvtools_lang_headers,$(SPVTOOLS_OUT_PATH),OpenCLDebugInfo100,$(SPV_CLDEBUGINFO100_GRAMMAR))) -$(eval $(call gen_spvtools_lang_headers,$(SPVTOOLS_OUT_PATH),NonSemanticShaderDebugInfo100,$(SPV_VKDEBUGINFO100_GRAMMAR))) -define gen_spvtools_vendor_tables -$(call generate-file-dir,$(1)/$(2).insts.inc) -$(1)/$(2).insts.inc : \ - $(LOCAL_PATH)/utils/generate_grammar_tables.py \ - $(SPVHEADERS_LOCAL_PATH)/include/spirv/unified1/extinst.$(2).grammar.json - @$(HOST_PYTHON) $(LOCAL_PATH)/utils/generate_grammar_tables.py \ - --extinst-vendor-grammar=$(SPVHEADERS_LOCAL_PATH)/include/spirv/unified1/extinst.$(2).grammar.json \ - --vendor-insts-output=$(1)/$(2).insts.inc \ - --vendor-operand-kind-prefix=$(3) - @echo "[$(TARGET_ARCH_ABI)] Extended instruction set: $(2) tables <= grammar" -$(LOCAL_PATH)/source/ext_inst.cpp: $(1)/$(2).insts.inc -endef -# Vendor and debug extended instruction sets, with grammars from SPIRV-Headers source tree. -$(eval $(call gen_spvtools_vendor_tables,$(SPVTOOLS_OUT_PATH),glsl.std.450,"")) -$(eval $(call gen_spvtools_vendor_tables,$(SPVTOOLS_OUT_PATH),opencl.std.100,"")) -$(eval $(call gen_spvtools_vendor_tables,$(SPVTOOLS_OUT_PATH),debuginfo,"")) -$(eval $(call gen_spvtools_vendor_tables,$(SPVTOOLS_OUT_PATH),opencl.debuginfo.100,"CLDEBUG100_")) -$(eval $(call gen_spvtools_vendor_tables,$(SPVTOOLS_OUT_PATH),nonsemantic.shader.debuginfo.100,"SHDEBUG100_")) -$(eval $(call gen_spvtools_vendor_tables,$(SPVTOOLS_OUT_PATH),spv-amd-gcn-shader,"")) -$(eval $(call gen_spvtools_vendor_tables,$(SPVTOOLS_OUT_PATH),spv-amd-shader-ballot,"")) -$(eval $(call gen_spvtools_vendor_tables,$(SPVTOOLS_OUT_PATH),spv-amd-shader-explicit-vertex-parameter,"")) -$(eval $(call gen_spvtools_vendor_tables,$(SPVTOOLS_OUT_PATH),spv-amd-shader-trinary-minmax,"")) -$(eval $(call gen_spvtools_vendor_tables,$(SPVTOOLS_OUT_PATH),nonsemantic.clspvreflection,"")) -$(eval $(call gen_spvtools_vendor_tables,$(SPVTOOLS_OUT_PATH),nonsemantic.vkspreflection,"")) +# Generate C++ headers for some extended instruction sets. +$(eval $(call gen_spvtools_lang_headers,$(SPVTOOLS_OUT_PATH),DebugInfo,$(GRAMMAR_DIR)/extinst.debuginfo.grammar.json)) +$(eval $(call gen_spvtools_lang_headers,$(SPVTOOLS_OUT_PATH),OpenCLDebugInfo100,$(GRAMMAR_DIR)/extinst.opencl.debuginfo.100.grammar.json)) +$(eval $(call gen_spvtools_lang_headers,$(SPVTOOLS_OUT_PATH),NonSemanticShaderDebugInfo100,$(GRAMMAR_DIR)/extinst.nonsemantic.shader.debuginfo.100.grammar.json)) + define gen_spvtools_build_version_inc $(call generate-file-dir,$(1)/dummy_filename) diff --git a/BUILD.bazel b/BUILD.bazel index e5fa2049b4..1986176048 100644 --- a/BUILD.bazel +++ b/BUILD.bazel @@ -5,9 +5,9 @@ load( "DEBUGINFO_GRAMMAR_JSON_FILE", "SHDEBUGINFO100_GRAMMAR_JSON_FILE", "TEST_COPTS", - "generate_compressed_tables", + "create_grammar_tables_target", + "ExtInst", "generate_extinst_lang_headers", - "generate_vendor_tables", "incompatible_with", ) @@ -54,40 +54,23 @@ py_binary( srcs = ["utils/generate_language_headers.py"], ) -generate_compressed_tables() - -generate_vendor_tables( - extension = "glsl.std.450", - target = "spirv_glsl_grammar_unified1" -) - -generate_vendor_tables( - extension = "opencl.std.100", - target = "spirv_opencl_grammar_unified1" -) - -generate_vendor_tables(extension = "spv-amd-shader-explicit-vertex-parameter") - -generate_vendor_tables(extension = "spv-amd-shader-trinary-minmax") - -generate_vendor_tables(extension = "spv-amd-gcn-shader") - -generate_vendor_tables(extension = "spv-amd-shader-ballot") - -generate_vendor_tables(extension = "debuginfo") - -generate_vendor_tables(extension = "nonsemantic.clspvreflection") - -generate_vendor_tables(extension = "nonsemantic.vkspreflection") - -generate_vendor_tables( - extension = "opencl.debuginfo.100", - operand_kind_prefix = "CLDEBUG100_", -) - -generate_vendor_tables( - extension = "nonsemantic.shader.debuginfo.100", - operand_kind_prefix = "SHDEBUG100_", +create_grammar_tables_target( + name="core", # unused + extinsts = [ + ExtInst("glsl.std.450", target="spirv_glsl_grammar_unified1"), + ExtInst("opencl.std.100", target="spirv_opencl_grammar_unified1"), + ExtInst("opencl.debuginfo.100", prefix="CLDEBUG100_"), + ExtInst("nonsemantic.shader.debuginfo.100", prefix="SHDEBUG100_"), + ] + [ExtInst(e) for e in [ + "spv-amd-shader-explicit-vertex-parameter", + "spv-amd-shader-trinary-minmax", + "spv-amd-gcn-shader", + "spv-amd-shader-ballot", + "debuginfo", + "nonsemantic.clspvreflection", + "nonsemantic.vkspreflection", + ] + ] ) generate_extinst_lang_headers( @@ -162,17 +145,6 @@ cc_library( ":gen_extinst_lang_headers_DebugInfo", ":gen_extinst_lang_headers_NonSemanticShaderDebugInfo100", ":gen_extinst_lang_headers_OpenCLDebugInfo100", - ":gen_vendor_tables_spirv_glsl_grammar_unified1", - ":gen_vendor_tables_spirv_opencl_grammar_unified1", - ":gen_vendor_tables_debuginfo", - ":gen_vendor_tables_nonsemantic_clspvreflection", - ":gen_vendor_tables_nonsemantic_vkspreflection", - ":gen_vendor_tables_nonsemantic_shader_debuginfo_100", - ":gen_vendor_tables_opencl_debuginfo_100", - ":gen_vendor_tables_spv_amd_gcn_shader", - ":gen_vendor_tables_spv_amd_shader_ballot", - ":gen_vendor_tables_spv_amd_shader_explicit_vertex_parameter", - ":gen_vendor_tables_spv_amd_shader_trinary_minmax", ":generators_inc", ], hdrs = [ @@ -210,9 +182,7 @@ cc_library( cc_library( name = "spirv_tools_opt_internal", - srcs = glob(["source/opt/*.cpp"]) + [ - ":gen_vendor_tables_spv_amd_shader_ballot", - ], + srcs = glob(["source/opt/*.cpp"]), hdrs = glob(["source/opt/*.h"]) + [ "include/spirv-tools/optimizer.hpp", ], diff --git a/BUILD.gn b/BUILD.gn index 26083ce9c1..0f73cb1ae6 100644 --- a/BUILD.gn +++ b/BUILD.gn @@ -36,24 +36,41 @@ spirv_is_winuwp = is_win && target_os == "winuwp" action("spvtools_core_tables") { script = "utils/ggt.py" - core_json_file = - "${spirv_headers}/include/spirv/unified1/spirv.core.grammar.json" - debuginfo_insts_file = - "${spirv_headers}/include/spirv/unified1/extinst.debuginfo.grammar.json" - cldebuginfo100_insts_file = "${spirv_headers}/include/spirv/unified1/extinst.opencl.debuginfo.100.grammar.json" - core_tables_body_file = "${target_gen_dir}/core_tables_body.inc" core_tables_header_file = "${target_gen_dir}/core_tables_header.inc" + # Extended instruction set grammar files + grammar_dir = "${spirv_headers}/include/spirv/unified1" + f0=rebase_path("${grammar_dir}/extinst.debuginfo.grammar.json", root_build_dir) + f1=rebase_path("${grammar_dir}/extinst.glsl.std.450.grammar.json", root_build_dir) + f2=rebase_path("${grammar_dir}/extinst.nonsemantic.clspvreflection.grammar.json", root_build_dir) + f3=rebase_path("${grammar_dir}/extinst.nonsemantic.shader.debuginfo.100.grammar.json", root_build_dir) + f4=rebase_path("${grammar_dir}/extinst.nonsemantic.vkspreflection.grammar.json", root_build_dir) + f5=rebase_path("${grammar_dir}/extinst.opencl.debuginfo.100.grammar.json", root_build_dir) + f6=rebase_path("${grammar_dir}/extinst.opencl.std.100.grammar.json", root_build_dir) + f7=rebase_path("${grammar_dir}/extinst.spv-amd-gcn-shader.grammar.json", root_build_dir) + f8=rebase_path("${grammar_dir}/extinst.spv-amd-shader-ballot.grammar.json", root_build_dir) + f9=rebase_path("${grammar_dir}/extinst.spv-amd-shader-explicit-vertex-parameter.grammar.json", root_build_dir) + f10=rebase_path("${grammar_dir}/extinst.spv-amd-shader-trinary-minmax.grammar.json", root_build_dir) + sources = [ - cldebuginfo100_insts_file, - core_json_file, - debuginfo_insts_file, "utils/Table/__init__.py", "utils/Table/Context.py", "utils/Table/IndexRange.py", "utils/Table/Operand.py", "utils/Table/StringList.py", + "${grammar_dir}/extinst.debuginfo.grammar.json", + "${grammar_dir}/extinst.glsl.std.450.grammar.json", + "${grammar_dir}/extinst.nonsemantic.clspvreflection.grammar.json", + "${grammar_dir}/extinst.nonsemantic.shader.debuginfo.100.grammar.json", + "${grammar_dir}/extinst.nonsemantic.vkspreflection.grammar.json", + "${grammar_dir}/extinst.opencl.debuginfo.100.grammar.json", + "${grammar_dir}/extinst.opencl.std.100.grammar.json", + "${grammar_dir}/extinst.spv-amd-gcn-shader.grammar.json", + "${grammar_dir}/extinst.spv-amd-shader-ballot.grammar.json", + "${grammar_dir}/extinst.spv-amd-shader-explicit-vertex-parameter.grammar.json", + "${grammar_dir}/extinst.spv-amd-shader-trinary-minmax.grammar.json", + "${grammar_dir}/spirv.core.grammar.json", ] outputs = [ core_tables_body_file, @@ -61,11 +78,18 @@ action("spvtools_core_tables") { ] args = [ "--spirv-core-grammar", - rebase_path(core_json_file, root_build_dir), - "--extinst-debuginfo-grammar", - rebase_path(debuginfo_insts_file, root_build_dir), - "--extinst-cldebuginfo100-grammar", - rebase_path(cldebuginfo100_insts_file, root_build_dir), + rebase_path("${grammar_dir}/spirv.core.grammar.json", root_build_dir), + "--extinst=,${f0}", + "--extinst=,${f1}", + "--extinst=,${f2}", + "--extinst=SHDEBUG100_,${f3}", + "--extinst=,${f4}", + "--extinst=CLDEBUG100_,${f5}", + "--extinst=,${f6}", + "--extinst=,${f7}", + "--extinst=,${f8}", + "--extinst=,${f9}", + "--extinst=,${f10}", "--core-tables-body-output", rebase_path(core_tables_body_file, root_build_dir), "--core-tables-header-output", @@ -93,30 +117,6 @@ template("spvtools_language_header") { } } -template("spvtools_vendor_table") { - assert(defined(invoker.name), "Need name in $target_name generation.") - - action("spvtools_vendor_tables_" + target_name) { - script = "utils/generate_grammar_tables.py" - - name = invoker.name - extinst_vendor_grammar = - "${spirv_headers}/include/spirv/unified1/extinst.${name}.grammar.json" - extinst_file = "${target_gen_dir}/${name}.insts.inc" - - args = [ - "--extinst-vendor-grammar", - rebase_path(extinst_vendor_grammar, root_build_dir), - "--vendor-insts-output", - rebase_path(extinst_file, root_build_dir), - "--vendor-operand-kind-prefix", - invoker.operand_kind_prefix, - ] - inputs = [ extinst_vendor_grammar ] - outputs = [ extinst_file ] - } -} - action("spvtools_generators_inc") { script = "utils/generate_registry_tables.py" @@ -161,60 +161,6 @@ spvtools_language_header("vkdebuginfo100") { grammar_file = "${spirv_headers}/include/spirv/unified1/extinst.nonsemantic.shader.debuginfo.100.grammar.json" } -spvtools_vendor_tables = [ - [ - "glsl.std.450", - "...nil...", - ], - [ - "opencl.std.100", - "...nil...", - ], - [ - "spv-amd-shader-explicit-vertex-parameter", - "...nil...", - ], - [ - "spv-amd-shader-trinary-minmax", - "...nil...", - ], - [ - "spv-amd-gcn-shader", - "...nil...", - ], - [ - "spv-amd-shader-ballot", - "...nil...", - ], - [ - "debuginfo", - "...nil...", - ], - [ - "opencl.debuginfo.100", - "CLDEBUG100_", - ], - [ - "nonsemantic.clspvreflection", - "...nil...", - ], - [ - "nonsemantic.vkspreflection", - "...nil...", - ], - [ - "nonsemantic.shader.debuginfo.100", - "SHDEBUG100_", - ], -] - -foreach(table_def, spvtools_vendor_tables) { - spvtools_vendor_table(table_def[0]) { - name = table_def[0] - operand_kind_prefix = table_def[1] - } -} - config("spvtools_public_config") { include_dirs = [ "include" ] } @@ -284,10 +230,6 @@ static_library("spvtools") { ":spvtools_language_header_debuginfo", ":spvtools_language_header_vkdebuginfo100", ] - foreach(table_def, spvtools_vendor_tables) { - target_name = table_def[0] - deps += [ ":spvtools_vendor_tables_$target_name" ] - } sources = [ "source/assembly_grammar.cpp", @@ -696,7 +638,6 @@ static_library("spvtools_opt") { deps = [ ":spvtools", ":spvtools_language_header_debuginfo", - ":spvtools_vendor_tables_spv-amd-shader-ballot", ] public_deps = [ ":spvtools_headers", diff --git a/build_defs.bzl b/build_defs.bzl index 9cfee91349..1f7cacded7 100644 --- a/build_defs.bzl +++ b/build_defs.bzl @@ -58,65 +58,70 @@ def _merge_dicts(dicts): merged.update(d) return merged -# TODO(b/413743565): Remove after legacy grammars removed. -def generate_core_tables(version): - if not version: - fail("Must specify version", "version") - grammars = dict( - core_grammar = "@spirv_headers//:spirv_core_grammar_{}".format(version), - debuginfo_grammar = DEBUGINFO_GRAMMAR_JSON_FILE, - cldebuginfo_grammar = CLDEBUGINFO100_GRAMMAR_JSON_FILE, - ) - - outs = dict( - core_insts_output = "core.insts-{}.inc".format(version), - operand_kinds_output = "operand.kinds-{}.inc".format(version), - ) - - 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})" - ).format(**_merge_dicts([grammars, outs])) - - native.genrule( - name = "gen_core_tables_" + version, - srcs = grammars.values(), - outs = outs.values(), - cmd = cmd, - cmd_bat = cmd, - tools = [":generate_grammar_tables"], - visibility = ["//visibility:private"], - ) - -def generate_compressed_tables(): +def ExtInst(name, target = "", prefix =""): + """ + Returns a dictionary specifying the info needed to + process an extended instruction set. + + Args: + name: The extension name; forms part of the .json grammar file. + target: if non-empty, the name of the bazel target in spirv-headers + that names the JSON grammar file for the extended instrution set. + If empty, the target name is derived from 'name'. + prefix: The optional prefix for names of operand enums. + + Returns a dictionary with keys 'name', 'target', 'prefix' and the + corresponding values. + """ + return {'name':name, 'target':target, 'prefix':prefix} + + +def _extinst_grammar_target(e): + """ + Args: e, as returned from extinst + Returns the SPIRV-Headers target for the given extended instruction set spec. + """ + target = e['target'] + name = e['name'] + if len(target) > 0: + return "@spirv_headers//:{}".format(target) + name_part = name.replace("-", "_").replace(".", "_") + return "@spirv_headers//:spirv_ext_inst_{}_grammar_unified1".format(name_part) + + +def create_grammar_tables_target(name, extinsts): + """ + Creates a ":gen_compressed_tables" target for SPIR-V instruction + set grammar tables. + + Args: + name: unused. Required by convention. + extinsts: list of extended instruction specs. + Each spec is a dictionary, as returned from 'extinst'. + """ grammars = dict( core_grammar = SPIRV_CORE_GRAMMAR_JSON_FILE, - debuginfo_grammar = DEBUGINFO_GRAMMAR_JSON_FILE, - cldebuginfo_grammar = CLDEBUGINFO100_GRAMMAR_JSON_FILE, ) - outs = dict( core_tables_header_output = "core_tables_header.inc", core_tables_body_output = "core_tables_body.inc", ) + extinst_args = [] + for e in extinsts: + extinst_args.append('--extinst={},$(location {})'.format(e['prefix'],_extinst_grammar_target(e))) cmd = ( "$(location :ggt)" + " --spirv-core-grammar=$(location {core_grammar})" + - " --extinst-debuginfo-grammar=$(location {debuginfo_grammar})" + - " --extinst-cldebuginfo100-grammar=$(location {cldebuginfo_grammar})" + " --core-tables-body-output=$(location {core_tables_body_output})" + - " --core-tables-header-output=$(location {core_tables_header_output})" + " --core-tables-header-output=$(location {core_tables_header_output})" + + " " + " ".join(extinst_args) ).format(**_merge_dicts([grammars, outs])) native.genrule( name = "gen_compressed_tables", - srcs = grammars.values(), + srcs = grammars.values() + [_extinst_grammar_target(e) for e in extinsts], outs = outs.values(), cmd = cmd, cmd_bat = cmd, @@ -124,41 +129,16 @@ def generate_compressed_tables(): visibility = ["//visibility:private"], ) -def generate_vendor_tables(extension, target = "", operand_kind_prefix = ""): - if not extension: - fail("Must specify extension", "extension") - - if target == "": - extension_rule = extension.replace("-", "_").replace(".", "_") - grammars = dict( - vendor_grammar = "@spirv_headers//:spirv_ext_inst_{}_grammar_unified1".format(extension_rule), - ) - else: - grammars = dict( - vendor_grammar = "@spirv_headers//:{}".format(target), - ) - extension_rule = target - outs = dict( - 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( - name = "gen_vendor_tables_" + extension_rule, - srcs = grammars.values(), - outs = outs.values(), - cmd = cmd, - cmd_bat = cmd, - tools = [":generate_grammar_tables"], - visibility = ["//visibility:private"], - ) - def generate_extinst_lang_headers(name, grammar = None): + """ + Creates a :gen_extinst_lang_headers_* target for a C++ header + the enums in a SPIR-V extended instruction set. + + Args: + name: the basename of the emitted header file. + grammar: the path to the JSON grammar file for the extended + instruction set. + """ if not grammar: fail("Must specify grammar", "grammar") outs = dict( diff --git a/include/spirv-tools/libspirv.h b/include/spirv-tools/libspirv.h index bcc8332dc0..941a442871 100644 --- a/include/spirv-tools/libspirv.h +++ b/include/spirv-tools/libspirv.h @@ -327,6 +327,18 @@ typedef enum spv_operand_type_t { SPV_OPERAND_TYPE_COOPERATIVE_VECTOR_MATRIX_LAYOUT, SPV_OPERAND_TYPE_COMPONENT_TYPE, + // From nonesmantic.clspvreflection + SPV_OPERAND_TYPE_KERNEL_PROPERTY_FLAGS, + + // From nonesmantic.shader.debuginfo.100 + SPV_OPERAND_TYPE_SHDEBUG100_BUILD_IDENTIFIER_FLAGS, + SPV_OPERAND_TYPE_SHDEBUG100_DEBUG_BASE_TYPE_ATTRIBUTE_ENCODING, + SPV_OPERAND_TYPE_SHDEBUG100_DEBUG_COMPOSITE_TYPE, + SPV_OPERAND_TYPE_SHDEBUG100_DEBUG_IMPORTED_ENTITY, + SPV_OPERAND_TYPE_SHDEBUG100_DEBUG_INFO_FLAGS, + SPV_OPERAND_TYPE_SHDEBUG100_DEBUG_OPERATION, + SPV_OPERAND_TYPE_SHDEBUG100_DEBUG_TYPE_QUALIFIER, + // This is a sentinel value, and does not represent an operand type. // It should come last. SPV_OPERAND_TYPE_NUM_OPERAND_TYPES, diff --git a/source/CMakeLists.txt b/source/CMakeLists.txt index 7ea4542129..2cacf4ee26 100644 --- a/source/CMakeLists.txt +++ b/source/CMakeLists.txt @@ -19,25 +19,52 @@ set(LANG_HEADER_PROCESSING_SCRIPT "${spirv-tools_SOURCE_DIR}/utils/generate_lang set(GGT_SCRIPT "${spirv-tools_SOURCE_DIR}/utils/ggt.py") # Pull in grammar files that have migrated to SPIRV-Headers -set(SPIRV_CORE_GRAMMAR_JSON_FILE "${SPIRV_HEADER_INCLUDE_DIR}/spirv/unified1/spirv.core.grammar.json") -set(DEBUGINFO_GRAMMAR_JSON_FILE "${SPIRV_HEADER_INCLUDE_DIR}/spirv/unified1/extinst.debuginfo.grammar.json") -set(CLDEBUGINFO100_GRAMMAR_JSON_FILE "${SPIRV_HEADER_INCLUDE_DIR}/spirv/unified1/extinst.opencl.debuginfo.100.grammar.json") -set(VKDEBUGINFO100_GRAMMAR_JSON_FILE "${SPIRV_HEADER_INCLUDE_DIR}/spirv/unified1/extinst.nonsemantic.shader.debuginfo.100.grammar.json") +set(GRAMMAR_DIR "${SPIRV_HEADER_INCLUDE_DIR}/spirv/unified1") +set(SPIRV_CORE_GRAMMAR_JSON_FILE "${GRAMMAR_DIR}/spirv.core.grammar.json") +set(EI_debuginfo "${GRAMMAR_DIR}/extinst.debuginfo.grammar.json") +set(EI_cldebuginfo "${GRAMMAR_DIR}/extinst.opencl.debuginfo.100.grammar.json") +set(EI_glsl "${GRAMMAR_DIR}/extinst.glsl.std.450.grammar.json") +set(EI_opencl "${GRAMMAR_DIR}/extinst.opencl.std.100.grammar.json") +set(EI_amd_evp "${GRAMMAR_DIR}/extinst.spv-amd-shader-explicit-vertex-parameter.grammar.json") +set(EI_amd_trimm "${GRAMMAR_DIR}/extinst.spv-amd-shader-trinary-minmax.grammar.json") +set(EI_amd_gcn "${GRAMMAR_DIR}/extinst.spv-amd-gcn-shader.grammar.json") +set(EI_amd_ballot "${GRAMMAR_DIR}/extinst.spv-amd-shader-ballot.grammar.json") +set(EI_ns_debuginfo "${GRAMMAR_DIR}/extinst.nonsemantic.shader.debuginfo.100.grammar.json") +set(EI_ns_clspvreflect "${GRAMMAR_DIR}/extinst.nonsemantic.clspvreflection.grammar.json") +set(EI_ns_vkspreflect "${GRAMMAR_DIR}/extinst.nonsemantic.vkspreflection.grammar.json") set(CORE_TABLES_BODY_INC_FILE ${spirv-tools_BINARY_DIR}/core_tables_body.inc) set(CORE_TABLES_HEADER_INC_FILE ${spirv-tools_BINARY_DIR}/core_tables_header.inc) add_custom_command(OUTPUT ${CORE_TABLES_BODY_INC_FILE} ${CORE_TABLES_HEADER_INC_FILE} COMMAND Python3::Interpreter ${GGT_SCRIPT} - --spirv-core-grammar=${SPIRV_CORE_GRAMMAR_JSON_FILE} - --extinst-debuginfo-grammar=${DEBUGINFO_GRAMMAR_JSON_FILE} - --extinst-cldebuginfo100-grammar=${CLDEBUGINFO100_GRAMMAR_JSON_FILE} --core-tables-body-output=${CORE_TABLES_BODY_INC_FILE} --core-tables-header-output=${CORE_TABLES_HEADER_INC_FILE} + --spirv-core-grammar=${SPIRV_CORE_GRAMMAR_JSON_FILE} + --extinst=,${EI_glsl} + --extinst=,${EI_opencl} + --extinst=CLDEBUG100_,${EI_cldebuginfo} + --extinst=SHDEBUG100_,${EI_ns_debuginfo} + --extinst=,${EI_amd_evp} + --extinst=,${EI_amd_trimm} + --extinst=,${EI_amd_gcn} + --extinst=,${EI_amd_ballot} + --extinst=,${EI_debuginfo} + --extinst=,${EI_ns_clspvreflect} + --extinst=,${EI_ns_vkspreflect} DEPENDS ${GGT_SCRIPT} ${SPIRV_CORE_GRAMMAR_JSON_FILE} - ${DEBUGINFO_GRAMMAR_JSON_FILE} - ${CLDEBUGINFO100_GRAMMAR_JSON_FILE} - COMMENT "Generate core tables") + ${EI_glsl} + ${EI_opencl} + ${EI_cldebuginfo} + ${EI_ns_debuginfo} + ${EI_amd_evp} + ${EI_amd_trimm} + ${EI_amd_gcn} + ${EI_amd_ballot} + ${EI_debuginfo} + ${EI_ns_clspvreflect} + ${EI_ns_vkspreflect} + COMMENT "Generate grammar tables") add_custom_target(spirv-tools-tables DEPENDS ${CORE_TABLES_BODY_INC_FILE} ${CORE_TABLES_HEADER_INC_FILE}) macro(spvtools_vimsyntax CONFIG_VERSION CLVERSION) @@ -48,33 +75,15 @@ macro(spvtools_vimsyntax CONFIG_VERSION CLVERSION) add_custom_command(OUTPUT ${VIMSYNTAX_FILE} COMMAND Python3::Interpreter ${VIMSYNTAX_PROCESSING_SCRIPT} --spirv-core-grammar=${GRAMMAR_JSON_FILE} - --extinst-debuginfo-grammar=${DEBUGINFO_GRAMMAR_JSON_FILE} + --extinst-debuginfo-grammar=${EI_debuginfo} --extinst-glsl-grammar=${GLSL_GRAMMAR_JSON_FILE} --extinst-opencl-grammar=${OPENCL_GRAMMAR_JSON_FILE} >${VIMSYNTAX_FILE} DEPENDS ${VIMSYNTAX_PROCESSING_SCRIPT} ${GRAMMAR_JSON_FILE} - ${GLSL_GRAMMAR_JSON_FILE} ${OPENCL_GRAMMAR_JSON_FILE} ${DEBUGINFO_GRAMMAR_JSON_FILE} + ${GLSL_GRAMMAR_JSON_FILE} ${OPENCL_GRAMMAR_JSON_FILE} ${EI_debuinfo} COMMENT "Generate spvasm.vim: Vim syntax file for SPIR-V assembly.") endmacro(spvtools_vimsyntax) -macro(spvtools_vendor_tables VENDOR_TABLE SHORT_NAME OPERAND_KIND_PREFIX) - set(INSTS_FILE "${spirv-tools_BINARY_DIR}/${VENDOR_TABLE}.insts.inc") - set(GRAMMAR_FILE "${SPIRV_HEADER_INCLUDE_DIR}/spirv/unified1/extinst.${VENDOR_TABLE}.grammar.json") - if(NOT EXISTS ${GRAMMAR_FILE}) - set(GRAMMAR_FILE "${spirv-tools_SOURCE_DIR}/source/extinst.${VENDOR_TABLE}.grammar.json") - endif() - add_custom_command(OUTPUT ${INSTS_FILE} - COMMAND Python3::Interpreter ${GRAMMAR_PROCESSING_SCRIPT} - --extinst-vendor-grammar=${GRAMMAR_FILE} - --vendor-insts-output=${INSTS_FILE} - --vendor-operand-kind-prefix=${OPERAND_KIND_PREFIX} - DEPENDS ${GRAMMAR_PROCESSING_SCRIPT} ${GRAMMAR_FILE} - COMMENT "Generate extended instruction tables for ${VENDOR_TABLE}.") - add_custom_target(spv-tools-${SHORT_NAME} DEPENDS ${INSTS_FILE}) - set_property(TARGET spv-tools-${SHORT_NAME} PROPERTY FOLDER "SPIRV-Tools build") - list(APPEND EXTINST_CPP_DEPENDS spv-tools-${SHORT_NAME}) -endmacro(spvtools_vendor_tables) - macro(spvtools_extinst_lang_headers NAME GRAMMAR_FILE) set(OUT_H ${spirv-tools_BINARY_DIR}/${NAME}.h) add_custom_command(OUTPUT ${OUT_H} @@ -88,20 +97,9 @@ macro(spvtools_extinst_lang_headers NAME GRAMMAR_FILE) list(APPEND EXTINST_CPP_DEPENDS spirv-tools-header-${NAME}) endmacro(spvtools_extinst_lang_headers) -spvtools_vendor_tables("glsl.std.450" "glsl" "") -spvtools_vendor_tables("opencl.std.100" "opencl" "") -spvtools_vendor_tables("spv-amd-shader-explicit-vertex-parameter" "spv-amd-sevp" "") -spvtools_vendor_tables("spv-amd-shader-trinary-minmax" "spv-amd-stm" "") -spvtools_vendor_tables("spv-amd-gcn-shader" "spv-amd-gs" "") -spvtools_vendor_tables("spv-amd-shader-ballot" "spv-amd-sb" "") -spvtools_vendor_tables("debuginfo" "debuginfo" "") -spvtools_vendor_tables("opencl.debuginfo.100" "cldi100" "CLDEBUG100_") -spvtools_vendor_tables("nonsemantic.shader.debuginfo.100" "shdi100" "SHDEBUG100_") -spvtools_vendor_tables("nonsemantic.clspvreflection" "clspvreflection" "") -spvtools_vendor_tables("nonsemantic.vkspreflection" "vkspreflection" "") -spvtools_extinst_lang_headers("DebugInfo" ${DEBUGINFO_GRAMMAR_JSON_FILE}) -spvtools_extinst_lang_headers("OpenCLDebugInfo100" ${CLDEBUGINFO100_GRAMMAR_JSON_FILE}) -spvtools_extinst_lang_headers("NonSemanticShaderDebugInfo100" ${VKDEBUGINFO100_GRAMMAR_JSON_FILE}) +spvtools_extinst_lang_headers("DebugInfo" ${EI_debuginfo}) +spvtools_extinst_lang_headers("OpenCLDebugInfo100" ${EI_cldebuginfo}) +spvtools_extinst_lang_headers("NonSemanticShaderDebugInfo100" ${EI_ns_debuginfo}) spvtools_vimsyntax("unified1" "1.0") add_custom_target(spirv-tools-vimsyntax DEPENDS ${VIMSYNTAX_FILE}) diff --git a/source/assembly_grammar.cpp b/source/assembly_grammar.cpp index 5fd9532294..4886ee6783 100644 --- a/source/assembly_grammar.cpp +++ b/source/assembly_grammar.cpp @@ -168,8 +168,6 @@ const size_t kNumOpSpecConstantOpcodes = } // namespace -bool AssemblyGrammar::isValid() const { return extInstTable_; } - CapabilitySet AssemblyGrammar::filterCapsAgainstTargetEnv( const spv::Capability* cap_array, uint32_t count) const { CapabilitySet cap_set; @@ -229,17 +227,6 @@ spv_result_t AssemblyGrammar::parseMaskOperand(const spv_operand_type_t type, uint32_t* pValue) const { return spvTextParseMaskOperand(type, textValue, pValue); } -spv_result_t AssemblyGrammar::lookupExtInst(spv_ext_inst_type_t type, - const char* textValue, - spv_ext_inst_desc* extInst) const { - return spvExtInstTableNameLookup(extInstTable_, type, textValue, extInst); -} - -spv_result_t AssemblyGrammar::lookupExtInst(spv_ext_inst_type_t type, - uint32_t firstWord, - spv_ext_inst_desc* extInst) const { - return spvExtInstTableValueLookup(extInstTable_, type, firstWord, extInst); -} void AssemblyGrammar::pushOperandTypesForMask( const spv_operand_type_t type, const uint32_t mask, diff --git a/source/assembly_grammar.h b/source/assembly_grammar.h index cf875501bf..08e10e7a79 100644 --- a/source/assembly_grammar.h +++ b/source/assembly_grammar.h @@ -29,11 +29,7 @@ namespace spvtools { class AssemblyGrammar { public: explicit AssemblyGrammar(const spv_const_context context) - : target_env_(context->target_env), - extInstTable_(context->ext_inst_table) {} - - // Returns true if the internal tables have been initialized with valid data. - bool isValid() const; + : target_env_(context->target_env) {} // Returns the SPIR-V target environment. spv_target_env target_env() const { return target_env_; } @@ -80,18 +76,6 @@ class AssemblyGrammar { spv_result_t parseMaskOperand(const spv_operand_type_t type, const char* textValue, uint32_t* pValue) const; - // Writes the extended operand with the given type and text to the *extInst - // parameter. - // Returns SPV_SUCCESS if the value could be found. - spv_result_t lookupExtInst(spv_ext_inst_type_t type, const char* textValue, - spv_ext_inst_desc* extInst) const; - - // Writes the extended operand with the given type and first encoded word - // to the *extInst parameter. - // Returns SPV_SUCCESS if the value could be found. - spv_result_t lookupExtInst(spv_ext_inst_type_t type, uint32_t firstWord, - spv_ext_inst_desc* extInst) const; - // Inserts the operands expected after the given typed mask onto the end // of the given pattern. // @@ -108,7 +92,6 @@ class AssemblyGrammar { private: const spv_target_env target_env_; - const spv_ext_inst_table extInstTable_; }; } // namespace spvtools diff --git a/source/binary.cpp b/source/binary.cpp index a4e9cf4c16..745faea66b 100644 --- a/source/binary.cpp +++ b/source/binary.cpp @@ -496,11 +496,12 @@ spv_result_t Parser::parseOperand(size_t inst_offset, case SPV_OPERAND_TYPE_EXTENSION_INSTRUCTION_NUMBER: { assert(spvIsExtendedInstruction(opcode)); assert(inst->ext_inst_type != SPV_EXT_INST_TYPE_NONE); - spv_ext_inst_desc ext_inst; - if (grammar_.lookupExtInst(inst->ext_inst_type, word, &ext_inst) == + + const spvtools::ExtInstDesc* desc = nullptr; + if (spvtools::LookupExtInst(inst->ext_inst_type, word, &desc) == SPV_SUCCESS) { // if we know about this ext inst, push the expected operands - spvPushOperandTypes(ext_inst->operandTypes, expected_operands); + spvPushOperandTypes(desc->operands(), expected_operands); } else { // if we don't know this extended instruction and the set isn't // non-semantic, we cannot process further diff --git a/source/diff/diff.cpp b/source/diff/diff.cpp index 4217b5f771..7fd21f3524 100644 --- a/source/diff/diff.cpp +++ b/source/diff/diff.cpp @@ -2798,20 +2798,7 @@ spv_result_t Differ::Output() { src_id_to_.inst_map_.resize(id_map_.SrcToDstMap().IdBound(), nullptr); dst_id_to_.inst_map_.resize(id_map_.DstToSrcMap().IdBound(), nullptr); - const spv_target_env target_env = SPV_ENV_UNIVERSAL_1_6; - spv_ext_inst_table ext_inst_table; - spv_result_t result; - - result = spvExtInstTableGet(&ext_inst_table, target_env); - if (result != SPV_SUCCESS) return result; - - spv_context_t context{ - target_env, - ext_inst_table, - }; - - const AssemblyGrammar grammar(&context); - if (!grammar.isValid()) return SPV_ERROR_INVALID_TABLE; + spv_context_t context{SPV_ENV_UNIVERSAL_1_6, nullptr}; uint32_t disassembly_options = SPV_BINARY_TO_TEXT_OPTION_PRINT; if (options_.indent) { @@ -2819,7 +2806,7 @@ spv_result_t Differ::Output() { } NameMapper name_mapper = GetTrivialNameMapper(); - disassemble::InstructionDisassembler dis(grammar, out_, disassembly_options, + disassemble::InstructionDisassembler dis(out_, disassembly_options, name_mapper); if (!options_.no_header) { diff --git a/source/disassemble.cpp b/source/disassemble.cpp index 2d6f11803f..eb72672085 100644 --- a/source/disassemble.cpp +++ b/source/disassemble.cpp @@ -31,7 +31,6 @@ #include #include -#include "source/assembly_grammar.h" #include "source/binary.h" #include "source/diagnostic.h" #include "source/ext_inst.h" @@ -116,8 +115,7 @@ struct ControlFlowGraph { // representation. class Disassembler { public: - Disassembler(const AssemblyGrammar& grammar, uint32_t options, - NameMapper name_mapper) + Disassembler(uint32_t options, NameMapper name_mapper) : print_(spvIsInBitfield(SPV_BINARY_TO_TEXT_OPTION_PRINT, options)), nested_indent_( spvIsInBitfield(SPV_BINARY_TO_TEXT_OPTION_NESTED_INDENT, options)), @@ -125,7 +123,7 @@ class Disassembler { spvIsInBitfield(SPV_BINARY_TO_TEXT_OPTION_REORDER_BLOCKS, options)), text_(), out_(print_ ? out_stream() : out_stream(text_)), - instruction_disassembler_(grammar, out_.get(), options, name_mapper), + instruction_disassembler_(out_.get(), options, name_mapper), header_(!spvIsInBitfield(SPV_BINARY_TO_TEXT_OPTION_NO_HEADER, options)), byte_offset_(0) {} @@ -625,12 +623,10 @@ constexpr uint32_t kCommentColumn = 50; } // namespace namespace disassemble { -InstructionDisassembler::InstructionDisassembler(const AssemblyGrammar& grammar, - std::ostream& stream, +InstructionDisassembler::InstructionDisassembler(std::ostream& stream, uint32_t options, NameMapper name_mapper) - : grammar_(grammar), - stream_(stream), + : stream_(stream), print_(spvIsInBitfield(SPV_BINARY_TO_TEXT_OPTION_PRINT, options)), color_(spvIsInBitfield(SPV_BINARY_TO_TEXT_OPTION_COLOR, options)), indent_(spvIsInBitfield(SPV_BINARY_TO_TEXT_OPTION_INDENT, options) @@ -871,11 +867,10 @@ void InstructionDisassembler::EmitOperand(std::ostream& stream, stream << "%" << name_mapper_(word); break; case SPV_OPERAND_TYPE_EXTENSION_INSTRUCTION_NUMBER: { - spv_ext_inst_desc ext_inst; SetRed(stream); - if (grammar_.lookupExtInst(inst.ext_inst_type, word, &ext_inst) == - SPV_SUCCESS) { - stream << ext_inst->name; + const ExtInstDesc* desc = nullptr; + if (LookupExtInst(inst.ext_inst_type, word, &desc) == SPV_SUCCESS) { + stream << desc->name().data(); } else { if (!spvExtInstIsNonSemantic(inst.ext_inst_type)) { assert(false && "should have caught this earlier"); @@ -1043,11 +1038,6 @@ std::string spvInstructionBinaryToText(const spv_target_env env, const size_t wordCount, const uint32_t options) { spv_context context = spvContextCreate(env); - const AssemblyGrammar grammar(context); - if (!grammar.isValid()) { - spvContextDestroy(context); - return ""; - } // Generate friendly names for Ids if requested. std::unique_ptr friendly_mapper; @@ -1058,7 +1048,7 @@ std::string spvInstructionBinaryToText(const spv_target_env env, } // Now disassemble! - Disassembler disassembler(grammar, options, name_mapper); + Disassembler disassembler(options, name_mapper); WrappedDisassembler wrapped(&disassembler, instCode, instWordCount); spvBinaryParse(context, &wrapped, code, wordCount, DisassembleTargetHeader, DisassembleTargetInstruction, nullptr); @@ -1087,9 +1077,6 @@ spv_result_t spvBinaryToText(const spv_const_context context, spvtools::UseDiagnosticAsMessageConsumer(&hijack_context, pDiagnostic); } - const spvtools::AssemblyGrammar grammar(&hijack_context); - if (!grammar.isValid()) return SPV_ERROR_INVALID_TABLE; - // Generate friendly names for Ids if requested. std::unique_ptr friendly_mapper; spvtools::NameMapper name_mapper = spvtools::GetTrivialNameMapper(); @@ -1100,7 +1087,7 @@ spv_result_t spvBinaryToText(const spv_const_context context, } // Now disassemble! - spvtools::Disassembler disassembler(grammar, options, name_mapper); + spvtools::Disassembler disassembler(options, name_mapper); if (auto error = spvBinaryParse(&hijack_context, &disassembler, code, wordCount, spvtools::DisassembleHeader, diff --git a/source/disassemble.h b/source/disassemble.h index b6d13c647b..08c37381f3 100644 --- a/source/disassemble.h +++ b/source/disassemble.h @@ -37,7 +37,6 @@ std::string spvInstructionBinaryToText(const spv_target_env env, const size_t word_count, const uint32_t options); -class AssemblyGrammar; namespace disassemble { // Shared code with other tools (than the disassembler) that might need to @@ -45,8 +44,8 @@ namespace disassemble { // binary for an instruction to its assembly representation. class InstructionDisassembler { public: - InstructionDisassembler(const AssemblyGrammar& grammar, std::ostream& stream, - uint32_t options, NameMapper name_mapper); + InstructionDisassembler(std::ostream& stream, uint32_t options, + NameMapper name_mapper); // Emits the assembly header for the module. void EmitHeaderSpirv(); @@ -104,7 +103,6 @@ class InstructionDisassembler { // |id_comments_|. void GenerateCommentForDecoratedId(const spv_parsed_instruction_t& inst); - const spvtools::AssemblyGrammar& grammar_; std::ostream& stream_; const bool print_; // Should we also print to the standard output stream? const bool color_; // Should we print in colour? diff --git a/source/ext_inst.cpp b/source/ext_inst.cpp index cbda87bf27..c8fe8bb476 100644 --- a/source/ext_inst.cpp +++ b/source/ext_inst.cpp @@ -17,97 +17,7 @@ #include // DebugInfo extended instruction set. -// See https://www.khronos.org/registry/spir-v/specs/1.0/DebugInfo.html -// TODO(dneto): DebugInfo.h should probably move to SPIRV-Headers. -#include "DebugInfo.h" -#include "debuginfo.insts.inc" -#include "glsl.std.450.insts.inc" -#include "nonsemantic.clspvreflection.insts.inc" -#include "nonsemantic.shader.debuginfo.100.insts.inc" -#include "nonsemantic.vkspreflection.insts.inc" -#include "opencl.debuginfo.100.insts.inc" -#include "opencl.std.100.insts.inc" -#include "source/latest_version_glsl_std_450_header.h" -#include "source/latest_version_opencl_std_header.h" -#include "source/macro.h" -#include "source/spirv_definition.h" -#include "spirv-tools/libspirv.h" -#include "spv-amd-gcn-shader.insts.inc" -#include "spv-amd-shader-ballot.insts.inc" -#include "spv-amd-shader-explicit-vertex-parameter.insts.inc" -#include "spv-amd-shader-trinary-minmax.insts.inc" - -static const spv_ext_inst_group_t kGroups_1_0[] = { - {SPV_EXT_INST_TYPE_GLSL_STD_450, ARRAY_SIZE(glsl_std_450_entries), - glsl_std_450_entries}, - {SPV_EXT_INST_TYPE_OPENCL_STD, ARRAY_SIZE(opencl_std_100_entries), - opencl_std_100_entries}, - {SPV_EXT_INST_TYPE_SPV_AMD_SHADER_EXPLICIT_VERTEX_PARAMETER, - ARRAY_SIZE(spv_amd_shader_explicit_vertex_parameter_entries), - spv_amd_shader_explicit_vertex_parameter_entries}, - {SPV_EXT_INST_TYPE_SPV_AMD_SHADER_TRINARY_MINMAX, - ARRAY_SIZE(spv_amd_shader_trinary_minmax_entries), - spv_amd_shader_trinary_minmax_entries}, - {SPV_EXT_INST_TYPE_SPV_AMD_GCN_SHADER, - ARRAY_SIZE(spv_amd_gcn_shader_entries), spv_amd_gcn_shader_entries}, - {SPV_EXT_INST_TYPE_SPV_AMD_SHADER_BALLOT, - ARRAY_SIZE(spv_amd_shader_ballot_entries), spv_amd_shader_ballot_entries}, - {SPV_EXT_INST_TYPE_DEBUGINFO, ARRAY_SIZE(debuginfo_entries), - debuginfo_entries}, - {SPV_EXT_INST_TYPE_OPENCL_DEBUGINFO_100, - ARRAY_SIZE(opencl_debuginfo_100_entries), opencl_debuginfo_100_entries}, - {SPV_EXT_INST_TYPE_NONSEMANTIC_SHADER_DEBUGINFO_100, - ARRAY_SIZE(nonsemantic_shader_debuginfo_100_entries), - nonsemantic_shader_debuginfo_100_entries}, - {SPV_EXT_INST_TYPE_NONSEMANTIC_CLSPVREFLECTION, - ARRAY_SIZE(nonsemantic_clspvreflection_entries), - nonsemantic_clspvreflection_entries}, - {SPV_EXT_INST_TYPE_NONSEMANTIC_VKSPREFLECTION, - ARRAY_SIZE(nonsemantic_vkspreflection_entries), - nonsemantic_vkspreflection_entries}, -}; - -static const spv_ext_inst_table_t kTable_1_0 = {ARRAY_SIZE(kGroups_1_0), - kGroups_1_0}; - -spv_result_t spvExtInstTableGet(spv_ext_inst_table* pExtInstTable, - spv_target_env env) { - if (!pExtInstTable) return SPV_ERROR_INVALID_POINTER; - - switch (env) { - // The extended instruction sets are all version 1.0 so far. - case SPV_ENV_UNIVERSAL_1_0: - case SPV_ENV_VULKAN_1_0: - case SPV_ENV_UNIVERSAL_1_1: - case SPV_ENV_UNIVERSAL_1_2: - case SPV_ENV_OPENCL_1_2: - case SPV_ENV_OPENCL_EMBEDDED_1_2: - case SPV_ENV_OPENCL_2_0: - case SPV_ENV_OPENCL_EMBEDDED_2_0: - case SPV_ENV_OPENCL_2_1: - case SPV_ENV_OPENCL_EMBEDDED_2_1: - case SPV_ENV_OPENCL_2_2: - case SPV_ENV_OPENCL_EMBEDDED_2_2: - case SPV_ENV_OPENGL_4_0: - case SPV_ENV_OPENGL_4_1: - case SPV_ENV_OPENGL_4_2: - case SPV_ENV_OPENGL_4_3: - case SPV_ENV_OPENGL_4_5: - case SPV_ENV_UNIVERSAL_1_3: - case SPV_ENV_VULKAN_1_1: - case SPV_ENV_VULKAN_1_1_SPIRV_1_4: - case SPV_ENV_UNIVERSAL_1_4: - case SPV_ENV_UNIVERSAL_1_5: - case SPV_ENV_VULKAN_1_2: - case SPV_ENV_UNIVERSAL_1_6: - case SPV_ENV_VULKAN_1_3: - case SPV_ENV_VULKAN_1_4: - *pExtInstTable = &kTable_1_0; - return SPV_SUCCESS; - default: - return SPV_ERROR_INVALID_TABLE; - } -} +// #include "DebugInfo.h" spv_ext_inst_type_t spvExtInstImportTypeGet(const char* name) { // The names are specified by the respective extension instruction @@ -171,47 +81,3 @@ bool spvExtInstIsDebugInfo(const spv_ext_inst_type_t type) { } return false; } - -spv_result_t spvExtInstTableNameLookup(const spv_ext_inst_table table, - const spv_ext_inst_type_t type, - const char* name, - spv_ext_inst_desc* pEntry) { - if (!table) return SPV_ERROR_INVALID_TABLE; - if (!pEntry) return SPV_ERROR_INVALID_POINTER; - - for (uint32_t groupIndex = 0; groupIndex < table->count; groupIndex++) { - const auto& group = table->groups[groupIndex]; - if (type != group.type) continue; - for (uint32_t index = 0; index < group.count; index++) { - const auto& entry = group.entries[index]; - if (!strcmp(name, entry.name)) { - *pEntry = &entry; - return SPV_SUCCESS; - } - } - } - - return SPV_ERROR_INVALID_LOOKUP; -} - -spv_result_t spvExtInstTableValueLookup(const spv_ext_inst_table table, - const spv_ext_inst_type_t type, - const uint32_t value, - spv_ext_inst_desc* pEntry) { - if (!table) return SPV_ERROR_INVALID_TABLE; - if (!pEntry) return SPV_ERROR_INVALID_POINTER; - - for (uint32_t groupIndex = 0; groupIndex < table->count; groupIndex++) { - const auto& group = table->groups[groupIndex]; - if (type != group.type) continue; - for (uint32_t index = 0; index < group.count; index++) { - const auto& entry = group.entries[index]; - if (value == entry.ext_inst) { - *pEntry = &entry; - return SPV_SUCCESS; - } - } - } - - return SPV_ERROR_INVALID_LOOKUP; -} diff --git a/source/ext_inst.h b/source/ext_inst.h index 4027f4c3c8..3c3150b49b 100644 --- a/source/ext_inst.h +++ b/source/ext_inst.h @@ -27,20 +27,4 @@ bool spvExtInstIsNonSemantic(const spv_ext_inst_type_t type); // Returns true if the extended instruction set is debug info bool spvExtInstIsDebugInfo(const spv_ext_inst_type_t type); -// Finds the named extended instruction of the given type in the given extended -// instruction table. On success, returns SPV_SUCCESS and writes a handle of -// the instruction entry into *entry. -spv_result_t spvExtInstTableNameLookup(const spv_ext_inst_table table, - const spv_ext_inst_type_t type, - const char* name, - spv_ext_inst_desc* entry); - -// Finds the extended instruction of the given type in the given extended -// instruction table by value. On success, returns SPV_SUCCESS and writes a -// handle of the instruction entry into *entry. -spv_result_t spvExtInstTableValueLookup(const spv_ext_inst_table table, - const spv_ext_inst_type_t type, - const uint32_t value, - spv_ext_inst_desc* pEntry); - #endif // SOURCE_EXT_INST_H_ diff --git a/source/operand.cpp b/source/operand.cpp index c071de060b..0acdac71e6 100644 --- a/source/operand.cpp +++ b/source/operand.cpp @@ -204,6 +204,24 @@ const char* spvOperandTypeStr(spv_operand_type_t type) { case SPV_OPERAND_TYPE_COMPONENT_TYPE: return "component type"; + case SPV_OPERAND_TYPE_KERNEL_PROPERTY_FLAGS: + return "kernel property flags"; + case SPV_OPERAND_TYPE_SHDEBUG100_BUILD_IDENTIFIER_FLAGS: + return "NonSemantic.Shader.DebugInfo.100 debug build identifier flags"; + case SPV_OPERAND_TYPE_SHDEBUG100_DEBUG_BASE_TYPE_ATTRIBUTE_ENCODING: + return "NonSemantic.Shader.DebugInfo.100 debug base type attribute " + "encoding"; + case SPV_OPERAND_TYPE_SHDEBUG100_DEBUG_COMPOSITE_TYPE: + return "NonSemantic.Shader.DebugInfo.100 debug composite type"; + case SPV_OPERAND_TYPE_SHDEBUG100_DEBUG_IMPORTED_ENTITY: + return "NonSemantic.Shader.DebugInfo.100 debug imported entity"; + case SPV_OPERAND_TYPE_SHDEBUG100_DEBUG_INFO_FLAGS: + return "NonSemantic.Shader.DebugInfo.100 debug info flags"; + case SPV_OPERAND_TYPE_SHDEBUG100_DEBUG_OPERATION: + return "NonSemantic.Shader.DebugInfo.100 debug operation"; + case SPV_OPERAND_TYPE_SHDEBUG100_DEBUG_TYPE_QUALIFIER: + return "NonSemantic.Shader.DebugInfo.100 debug type qualifier"; + case SPV_OPERAND_TYPE_NONE: return "NONE"; default: @@ -317,6 +335,14 @@ bool spvOperandIsConcrete(spv_operand_type_t type) { case SPV_OPERAND_TYPE_TENSOR_CLAMP_MODE: case SPV_OPERAND_TYPE_COOPERATIVE_VECTOR_MATRIX_LAYOUT: case SPV_OPERAND_TYPE_COMPONENT_TYPE: + case SPV_OPERAND_TYPE_KERNEL_PROPERTY_FLAGS: + case SPV_OPERAND_TYPE_SHDEBUG100_BUILD_IDENTIFIER_FLAGS: + case SPV_OPERAND_TYPE_SHDEBUG100_DEBUG_BASE_TYPE_ATTRIBUTE_ENCODING: + case SPV_OPERAND_TYPE_SHDEBUG100_DEBUG_COMPOSITE_TYPE: + case SPV_OPERAND_TYPE_SHDEBUG100_DEBUG_IMPORTED_ENTITY: + case SPV_OPERAND_TYPE_SHDEBUG100_DEBUG_INFO_FLAGS: + case SPV_OPERAND_TYPE_SHDEBUG100_DEBUG_OPERATION: + case SPV_OPERAND_TYPE_SHDEBUG100_DEBUG_TYPE_QUALIFIER: return true; default: break; diff --git a/source/operand.h b/source/operand.h index 54a6e6775d..c85ba27737 100644 --- a/source/operand.h +++ b/source/operand.h @@ -49,12 +49,6 @@ bool spvOperandIsOptional(spv_operand_type_t type); // operand. bool spvOperandIsVariable(spv_operand_type_t type); -// Append a list of operand types to the end of the pattern vector. -// The types parameter specifies the source array of types, ending with -// SPV_OPERAND_TYPE_NONE. -void spvPushOperandTypes(const spv_operand_type_t* types, - spv_operand_pattern_t* pattern); - // Append a list of operand types to the end of the pattern vector. // The types parameter specifies the source span of types. void spvPushOperandTypes( diff --git a/source/opt/amd_ext_to_khr.cpp b/source/opt/amd_ext_to_khr.cpp index a314567f8c..085751b883 100644 --- a/source/opt/amd_ext_to_khr.cpp +++ b/source/opt/amd_ext_to_khr.cpp @@ -19,7 +19,6 @@ #include "ir_builder.h" #include "source/opt/ir_context.h" -#include "spv-amd-shader-ballot.insts.inc" #include "type_manager.h" namespace spvtools { diff --git a/source/opt/trim_capabilities_pass.cpp b/source/opt/trim_capabilities_pass.cpp index 6337019641..cc0e331bb9 100644 --- a/source/opt/trim_capabilities_pass.cpp +++ b/source/opt/trim_capabilities_pass.cpp @@ -598,9 +598,8 @@ void TrimCapabilitiesPass::addInstructionRequirementsForExtInst( spv_ext_inst_type_t instructionSet = spvExtInstImportTypeGet(extInstSet.AsString().c_str()); - spv_ext_inst_desc desc = {}; - auto result = - context()->grammar().lookupExtInst(instructionSet, extInstruction, &desc); + const ExtInstDesc* desc = nullptr; + auto result = LookupExtInst(instructionSet, extInstruction, &desc); if (result != SPV_SUCCESS) { return; } diff --git a/source/opt/trim_capabilities_pass.h b/source/opt/trim_capabilities_pass.h index 511d996e9a..d2369b15eb 100644 --- a/source/opt/trim_capabilities_pass.h +++ b/source/opt/trim_capabilities_pass.h @@ -131,32 +131,9 @@ class TrimCapabilitiesPass : public Pass { private: // Inserts every capability listed by `descriptor` this pass supports into // `output`. - // TODO(b/413723831): After extended instruction sets are converted to use - // descriptors, change this back into a template to collapse all three - // implementations. - void addSupportedCapabilitiesToSet( - const spv_ext_inst_desc_t* const descriptor, - CapabilitySet* output) const { - const uint32_t capabilityCount = descriptor->numCapabilities; - for (uint32_t i = 0; i < capabilityCount; ++i) { - const auto capability = descriptor->capabilities[i]; - if (supportedCapabilities_.contains(capability)) { - output->insert(capability); - } - } - } - void addSupportedCapabilitiesToSet( - const spvtools::InstructionDesc* const descriptor, - CapabilitySet* output) const { - for (auto capability : descriptor->capabilities()) { - if (supportedCapabilities_.contains(capability)) { - output->insert(capability); - } - } - } - void addSupportedCapabilitiesToSet( - const spvtools::OperandDesc* const descriptor, - CapabilitySet* output) const { + template + void addSupportedCapabilitiesToSet(const Descriptor* const descriptor, + CapabilitySet* output) const { for (auto capability : descriptor->capabilities()) { if (supportedCapabilities_.contains(capability)) { output->insert(capability); diff --git a/source/table.cpp b/source/table.cpp index 0b9e2f5249..3f313730aa 100644 --- a/source/table.cpp +++ b/source/table.cpp @@ -49,12 +49,7 @@ spv_context spvContextCreate(spv_target_env env) { return nullptr; } - spv_ext_inst_table ext_inst_table = nullptr; - - spvExtInstTableGet(&ext_inst_table, env); - - return new spv_context_t{env, ext_inst_table, - nullptr /* a null default consumer */}; + return new spv_context_t{env, nullptr /* a null default consumer */}; } void spvContextDestroy(spv_context context) { delete context; } diff --git a/source/table.h b/source/table.h index 6fef99c545..e61a4d49f9 100644 --- a/source/table.h +++ b/source/table.h @@ -22,54 +22,9 @@ // NOTE: Instruction and operand tables have moved to table2.{h|cpp}, // where they are represented more compactly. -// TODO(dneto): Move the remaining tables to the new scheme. - -// Define the static tables that describe the grammatical structure -// of SPIR-V instructions and their operands. These tables are populated -// by reading the grammar files from SPIRV-Headers. -// -// Most clients access these tables indirectly via an spv_context_t object. -// -// The overall structure among containers (i.e. skipping scalar data members) -// is as follows: -// -// An spv_context_t: -// - points to spv_ext_inst_table_t = array of spv_ext_inst_group_t -// -// An spv_ext_inst_group_t has: -// - array of spv_ext_inst_desc_t -// -// An spv_ext_inst_desc_t has: -// - a name string -// - array of spv::Capability -// - array of spv_operand_type_t - -typedef struct spv_ext_inst_desc_t { - const char* name; - const uint32_t ext_inst; - const uint32_t numCapabilities; - const spv::Capability* capabilities; - const spv_operand_type_t operandTypes[40]; // vksp needs at least 40 -} spv_ext_inst_desc_t; - -typedef struct spv_ext_inst_group_t { - const spv_ext_inst_type_t type; - const uint32_t count; - const spv_ext_inst_desc_t* entries; -} spv_ext_inst_group_t; - -typedef struct spv_ext_inst_table_t { - const uint32_t count; - const spv_ext_inst_group_t* groups; -} spv_ext_inst_table_t; - -typedef const spv_ext_inst_desc_t* spv_ext_inst_desc; - -typedef const spv_ext_inst_table_t* spv_ext_inst_table; struct spv_context_t { const spv_target_env target_env; - const spv_ext_inst_table ext_inst_table; spvtools::MessageConsumer consumer; }; @@ -80,7 +35,4 @@ namespace spvtools { void SetContextMessageConsumer(spv_context context, MessageConsumer consumer); } // namespace spvtools -// Populates *table with entries for env. -spv_result_t spvExtInstTableGet(spv_ext_inst_table* table, spv_target_env env); - #endif // SOURCE_TABLE_H_ diff --git a/source/table2.cpp b/source/table2.cpp index baf6a99f10..b68aeade49 100644 --- a/source/table2.cpp +++ b/source/table2.cpp @@ -80,9 +80,9 @@ struct NameValue { // Array of operand types, referenced by IndexRanges elsewhere. // Contains all sequences of operand types used in the grammar. -// Maps an operand kind to a NameValue entries for that kind. +// Maps an operand kind to NameValue entries for that kind. // The result is an IndexRange into kOperandNames, and are sorted -// are sorted by string name within that span. +// by string name within that span. IndexRange OperandNameRangeForKind(spv_operand_type_t type); // Maps an operand kind to possible operands for that kind. @@ -90,6 +90,16 @@ IndexRange OperandNameRangeForKind(spv_operand_type_t type); // are sorted by value within that span. IndexRange OperandByValueRangeForKind(spv_operand_type_t type); +// Maps an extended instruction set kind to NameValue entries for that kind. +// The result is an IndexRange into kExtIntNames, and are sorted +// by string name within that span. +IndexRange ExtInstNameRangeForKind(spv_ext_inst_type_t type); + +// Maps an extended instruction set kind to possible operands for that kind. +// The result is an IndexRange into kExtInstByValue, and the instructions +// are sorted by opcode value within that span. +IndexRange ExtInstByValueRangeForKind(spv_ext_inst_type_t type); + // Returns the name of an extension, as an index into kStrings IndexRange ExtensionToIndexRange(Extension extension); @@ -136,6 +146,16 @@ utils::Span InstructionDesc::extensions() const { return extensions_range.apply(kExtensionSpans); } +utils::Span ExtInstDesc::operands() const { + return operands_range.apply(kOperandSpans); +} +utils::Span ExtInstDesc::name() const { + return name_range.apply(kStrings); +} +utils::Span ExtInstDesc::capabilities() const { + return capabilities_range.apply(kCapabilitySpans); +} + spv_result_t LookupOpcode(spv::Op opcode, const InstructionDesc** desc) { // Metaphor: Look for the needle in the haystack. const InstructionDesc needle(opcode); @@ -263,6 +283,58 @@ spv_result_t LookupOperand(spv_operand_type_t type, const char* name, return SPV_ERROR_INVALID_LOOKUP; } +spv_result_t LookupExtInst(spv_ext_inst_type_t type, const char* name, + const ExtInstDesc** desc) { + auto ir = ExtInstNameRangeForKind(type); + if (ir.empty()) { + return SPV_ERROR_INVALID_LOOKUP; + } + + auto span = ir.apply(kExtInstNames.data()); + + // The comparison function knows to use 'name' string to compare against + // when the value is kSentinel. + const auto kSentinel = uint32_t(-1); + const NameValue needle{{}, kSentinel}; + auto less = [&](const NameValue& lhs, const NameValue& rhs) { + const char* lhs_chars = lhs.value == kSentinel ? name : getChars(lhs.name); + const char* rhs_chars = rhs.value == kSentinel ? name : getChars(rhs.name); + return std::strcmp(lhs_chars, rhs_chars) < 0; + }; + + auto where = std::lower_bound(span.begin(), span.end(), needle, less); + if (where != span.end() && std::strcmp(getChars(where->name), name) == 0) { + return LookupExtInst(type, where->value, desc); + } + return SPV_ERROR_INVALID_LOOKUP; +} + +// Finds the extended instruction description by opcode value. +// On success, returns SPV_SUCCESS and updates *desc. +spv_result_t LookupExtInst(spv_ext_inst_type_t type, uint32_t value, + const ExtInstDesc** desc) { + auto ir = ExtInstByValueRangeForKind(type); + if (ir.empty()) { + return SPV_ERROR_INVALID_LOOKUP; + } + + auto span = ir.apply(kExtInstByValue.data()); + + // Metaphor: Look for the needle in the haystack. + // The operand value is the first member. + const ExtInstDesc needle(value); + auto where = + std::lower_bound(span.begin(), span.end(), needle, + [&](const ExtInstDesc& lhs, const ExtInstDesc& rhs) { + return lhs.value < rhs.value; + }); + if (where != span.end() && where->value == value) { + *desc = &*where; + return SPV_SUCCESS; + } + return SPV_ERROR_INVALID_LOOKUP; +} + const char* ExtensionToString(Extension extension) { return getChars(ExtensionToIndexRange(extension)); } diff --git a/source/table2.h b/source/table2.h index 2ea62606bd..e3731c4329 100644 --- a/source/table2.h +++ b/source/table2.h @@ -40,6 +40,7 @@ // // An OperandDesc describes an operand. // An InstructionDesc desribes an instruction. +// An ExtInstDesc describes an extended intruction. // // Both OperandDesc and InstructionDesc have members: // - a name string @@ -51,13 +52,18 @@ // - a lastVersion // // An OperandDesc also has: -// - a uint32_t value. +// - a uint32_t value. // // An InstructionDesc also has: -// - a spv::Op opcode -// - a bool hasResult -// - a bool hasType -// - a printing class +// - a spv::Op opcode +// - a bool hasResult +// - a bool hasType +// - a printing class +// +// An ExtInstDesc has: +// - a name +// - array of spv::Capability (as an enum) +// - array of spv_operand_type_t (as an enum) // // The arrays are represented by spans into a global static array, with one // array for each of: @@ -180,6 +186,27 @@ struct InstructionDesc { InstructionDesc(InstructionDesc&&) = delete; }; +// Describes an extended instruction +struct ExtInstDesc { + const uint32_t value; + const IndexRange operands_range; // Indexes kOperandSpans + const IndexRange name_range; // Indexes kStrings + const IndexRange capabilities_range; // Indexes kCapbilitySpans + // Returns the span of elements in the global grammar tables corresponding + // to the privately-stored index ranges + utils::Span operands() const; + utils::Span name() const; + utils::Span capabilities() const; + + constexpr ExtInstDesc(uint32_t v, IndexRange o, IndexRange n, IndexRange c) + : value(v), operands_range(o), name_range(n), capabilities_range(c) {} + + constexpr ExtInstDesc(uint32_t v) : value(v) {} + + ExtInstDesc(const ExtInstDesc&) = delete; + ExtInstDesc(ExtInstDesc&&) = delete; +}; + // Finds the instruction description by opcode name. The name should not // have the "Op" prefix. On success, returns SPV_SUCCESS and updates *desc. spv_result_t LookupOpcode(const char* name, const InstructionDesc** desc); @@ -214,6 +241,15 @@ spv_result_t LookupOperand(spv_operand_type_t type, const char* name, spv_result_t LookupOperand(spv_operand_type_t type, uint32_t operand, const OperandDesc** desc); +// Finds the extended instruction description by opcode name. +// On success, returns SPV_SUCCESS and updates *desc. +spv_result_t LookupExtInst(spv_ext_inst_type_t type, const char* name, + const ExtInstDesc** desc); +// Finds the extended instruction description by opcode value. +// On success, returns SPV_SUCCESS and updates *desc. +spv_result_t LookupExtInst(spv_ext_inst_type_t type, uint32_t value, + const ExtInstDesc** desc); + // Finds Extension enum corresponding to |str|. Returns false if not found. bool GetExtensionFromString(const char* str, Extension* extension); diff --git a/source/text.cpp b/source/text.cpp index bacfe29b78..79f9c3ce9a 100644 --- a/source/text.cpp +++ b/source/text.cpp @@ -242,14 +242,14 @@ spv_result_t spvTextEncodeOperand(const spvtools::AssemblyGrammar& grammar, case SPV_OPERAND_TYPE_EXTENSION_INSTRUCTION_NUMBER: { // The assembler accepts the symbolic name for an extended instruction, // and emits its corresponding number. - spv_ext_inst_desc extInst; - if (grammar.lookupExtInst(pInst->extInstType, textValue, &extInst) == + const spvtools::ExtInstDesc* desc = nullptr; + if (spvtools::LookupExtInst(pInst->extInstType, textValue, &desc) == SPV_SUCCESS) { // if we know about this extended instruction, push the numeric value - spvInstructionAddWord(pInst, extInst->ext_inst); + spvInstructionAddWord(pInst, desc->value); // Prepare to parse the operands for the extended instructions. - spvPushOperandTypes(extInst->operandTypes, pExpectedOperands); + spvPushOperandTypes(desc->operands(), pExpectedOperands); } else { // if we don't know this extended instruction and the set isn't // non-semantic, we cannot process further @@ -861,10 +861,6 @@ spv_result_t GetNumericIds(const spvtools::AssemblyGrammar& grammar, if (!text->str) return context.diagnostic() << "Missing assembly text."; - if (!grammar.isValid()) { - return SPV_ERROR_INVALID_TABLE; - } - // Skip past whitespace and comments. context.advance(); @@ -910,10 +906,6 @@ spv_result_t spvTextToBinaryInternal(const spvtools::AssemblyGrammar& grammar, spvtools::AssemblyContext context(text, consumer, std::move(ids_to_preserve)); if (!text->str) return context.diagnostic() << "Missing assembly text."; - - if (!grammar.isValid()) { - return SPV_ERROR_INVALID_TABLE; - } if (!pBinary) return SPV_ERROR_INVALID_POINTER; std::vector instructions; diff --git a/source/val/instruction.h b/source/val/instruction.h index 59e8af13b1..6b424891bf 100644 --- a/source/val/instruction.h +++ b/source/val/instruction.h @@ -24,6 +24,7 @@ #include "source/ext_inst.h" #include "source/opcode.h" #include "source/table.h" +#include "source/table2.h" #include "spirv-tools/libspirv.h" namespace spvtools { @@ -83,9 +84,7 @@ class Instruction { const spv_parsed_instruction_t& c_inst() const { return inst_; } /// Provides direct access to instructions spv_ext_inst_type_t object. - const spv_ext_inst_type_t& ext_inst_type() const { - return inst_.ext_inst_type; - } + spv_ext_inst_type_t ext_inst_type() const { return inst_.ext_inst_type; } bool IsNonSemantic() const { return spvIsExtendedInstruction(opcode()) && @@ -113,7 +112,7 @@ class Instruction { private: const std::vector words_; const std::vector operands_; - spv_parsed_instruction_t inst_; + const spv_parsed_instruction_t inst_; size_t line_num_ = 0; /// The function in which this instruction was declared diff --git a/source/val/validate_extensions.cpp b/source/val/validate_extensions.cpp index e0bc2f6361..58aaf5272a 100644 --- a/source/val/validate_extensions.cpp +++ b/source/val/validate_extensions.cpp @@ -35,16 +35,15 @@ namespace spvtools { namespace val { namespace { -std::string ReflectionInstructionName(ValidationState_t& _, - const Instruction* inst) { - spv_ext_inst_desc desc = nullptr; - if (_.grammar().lookupExtInst(SPV_EXT_INST_TYPE_NONSEMANTIC_CLSPVREFLECTION, - inst->word(4), &desc) != SPV_SUCCESS || +std::string ReflectionInstructionName(const Instruction* inst) { + const ExtInstDesc* desc = nullptr; + if (LookupExtInst(SPV_EXT_INST_TYPE_NONSEMANTIC_CLSPVREFLECTION, + inst->word(4), &desc) != SPV_SUCCESS || !desc) { return std::string("Unknown ExtInst"); } std::ostringstream ss; - ss << desc->name; + ss << desc->name().data(); return ss.str(); } @@ -189,18 +188,17 @@ spv_result_t ValidateDebugInfoOperand( if (DoesDebugInfoOperandMatchExpectation(_, expectation, inst, word_index)) return SPV_SUCCESS; - spv_ext_inst_desc desc = nullptr; - if (_.grammar().lookupExtInst(inst->ext_inst_type(), expected_debug_inst, - &desc) != SPV_SUCCESS || + const ExtInstDesc* desc = nullptr; + if (LookupExtInst(inst->ext_inst_type(), expected_debug_inst, &desc) != + SPV_SUCCESS || !desc) { return _.diag(SPV_ERROR_INVALID_DATA, inst) << ext_inst_name() << ": " << "expected operand " << debug_inst_name << " is invalid"; } return _.diag(SPV_ERROR_INVALID_DATA, inst) - << ext_inst_name() << ": " - << "expected operand " << debug_inst_name << " must be a result id of " - << desc->name; + << ext_inst_name() << ": " << "expected operand " << debug_inst_name + << " must be a result id of " << desc->name().data(); } #define CHECK_DEBUG_OPERAND(NAME, debug_opcode, index) \ @@ -285,7 +283,7 @@ spv_result_t ValidateOperandDebugType( spv_result_t ValidateClspvReflectionKernel(ValidationState_t& _, const Instruction* inst, uint32_t version) { - const auto inst_name = ReflectionInstructionName(_, inst); + const auto inst_name = ReflectionInstructionName(inst); const auto kernel_id = inst->GetOperandAs(4); const auto kernel = _.FindDef(kernel_id); if (kernel->opcode() != spv::Op::OpFunction) { @@ -930,7 +928,7 @@ spv_result_t ValidateClspvReflectionInstruction(ValidationState_t& _, } if (version < required_version) { return _.diag(SPV_ERROR_INVALID_ID, inst) - << ReflectionInstructionName(_, inst) << " requires version " + << ReflectionInstructionName(inst) << " requires version " << required_version << ", but parsed version is " << version; } @@ -1101,9 +1099,8 @@ spv_result_t ValidateExtInst(ValidationState_t& _, const Instruction* inst) { spv_ext_inst_type_t(inst->ext_inst_type()); auto ext_inst_name = [&_, ext_inst_set, ext_inst_type, ext_inst_index]() { - spv_ext_inst_desc desc = nullptr; - if (_.grammar().lookupExtInst(ext_inst_type, ext_inst_index, &desc) != - SPV_SUCCESS || + const ExtInstDesc* desc = nullptr; + if (LookupExtInst(ext_inst_type, ext_inst_index, &desc) != SPV_SUCCESS || !desc) { return std::string("Unknown ExtInst"); } @@ -1114,7 +1111,7 @@ spv_result_t ValidateExtInst(ValidationState_t& _, const Instruction* inst) { std::ostringstream ss; ss << import_inst->GetOperandAs(1); ss << " "; - ss << desc->name; + ss << desc->name().data(); return ss.str(); }; diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index a07dc22c59..68ce4efc0a 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -108,6 +108,7 @@ set(TEST_SOURCES ext_inst.glsl_test.cpp ext_inst.non_semantic_test.cpp ext_inst.opencl_test.cpp + ext_inst_lookup_test.cpp fix_word_test.cpp generator_magic_number_test.cpp hex_float_test.cpp diff --git a/test/ext_inst_lookup_test.cpp b/test/ext_inst_lookup_test.cpp new file mode 100644 index 0000000000..a580c7c6c9 --- /dev/null +++ b/test/ext_inst_lookup_test.cpp @@ -0,0 +1,87 @@ +// Copyright 2025 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. + +#include +#include + +#include "gmock/gmock.h" +#include "source/spirv_target_env.h" +#include "source/table2.h" +#include "test/unit_spirv.h" + +using ::testing::ContainerEq; +using ::testing::ValuesIn; + +namespace spvtools { +namespace { + +struct ExtInstLookupCase { + spv_ext_inst_type_t type; + std::string name; + uint32_t value; + bool expect_pass = true; +}; + +std::ostream& operator<<(std::ostream& os, const ExtInstLookupCase& eilc) { + os << "EILC(" << static_cast(eilc.type) << ", '" << eilc.name << "', " + << eilc.value << ", expect pass? " << eilc.expect_pass << ")"; + return os; +} + +using ExtInstLookupTest = ::testing::TestWithParam; + +TEST_P(ExtInstLookupTest, ExtInstLookup_ByName) { + const ExtInstDesc* desc = nullptr; + auto status = LookupExtInst(GetParam().type, GetParam().name.data(), &desc); + if (GetParam().expect_pass) { + EXPECT_EQ(status, SPV_SUCCESS); + ASSERT_NE(desc, nullptr); + EXPECT_EQ(static_cast(desc->value), GetParam().value); + } else { + EXPECT_NE(status, SPV_SUCCESS); + EXPECT_EQ(desc, nullptr); + } +} + +TEST_P(ExtInstLookupTest, ExtInstLookup_ByValue_Success) { + const ExtInstDesc* desc = nullptr; + if (GetParam().expect_pass) { + auto status = LookupExtInst(GetParam().type, GetParam().value, &desc); + EXPECT_EQ(status, SPV_SUCCESS); + ASSERT_NE(desc, nullptr); + EXPECT_EQ(desc->value, GetParam().value); + EXPECT_EQ(std::string(desc->name().data()), GetParam().name); + } +} + +INSTANTIATE_TEST_SUITE_P(Samples, ExtInstLookupTest, + ValuesIn(std::vector{ + {SPV_EXT_INST_TYPE_GLSL_STD_450, "FMix", 46}, + {SPV_EXT_INST_TYPE_OPENCL_STD, "s_mul24", 169}, + {SPV_EXT_INST_TYPE_OPENCL_STD, "mix", 99}, + })); + +TEST(ExtInstLookupSingleTest, ExtInstLookup_Value_Fails) { + // This list may need adjusting over time. + std::array bad_values = {{99999, 37737, 110101}}; + for (auto bad_value : bad_values) { + const ExtInstDesc* desc = nullptr; + auto status = LookupExtInst(SPV_EXT_INST_TYPE_OPENCL_STD, bad_value, &desc); + EXPECT_NE(status, SPV_SUCCESS); + ASSERT_EQ(desc, nullptr); + } +} + +} // namespace +} // namespace spvtools diff --git a/tools/cfg/bin_to_dot.cpp b/tools/cfg/bin_to_dot.cpp index 40a7dc4d12..85fa1e6a3a 100644 --- a/tools/cfg/bin_to_dot.cpp +++ b/tools/cfg/bin_to_dot.cpp @@ -172,7 +172,6 @@ spv_result_t BinaryToDot(const spv_const_context context, const uint32_t* words, // diagnostics. These are programmer errors, not user errors. if (!diagnostic) return SPV_ERROR_INVALID_DIAGNOSTIC; const spvtools::AssemblyGrammar grammar(context); - if (!grammar.isValid()) return SPV_ERROR_INVALID_TABLE; spvtools::FriendlyNameMapper friendly_mapper(context, words, num_words); DotConverter converter(friendly_mapper.GetNameMapper(), out); diff --git a/utils/ggt.py b/utils/ggt.py index e4a9b3e517..2c87c91c03 100755 --- a/utils/ggt.py +++ b/utils/ggt.py @@ -21,7 +21,7 @@ import os.path import re import sys -from typing import Dict, List, Tuple +from typing import Dict, List, Tuple, Any # Find modules relative to the directory containing this script. # This is needed for hermetic Bazel builds, where the Table files are bundled @@ -36,15 +36,53 @@ # core or KHR grammar files. Get this list from the SPIR-V registry web page. # NOTE: Only put things on this list if it is not in those grammar files. EXTENSIONS_FROM_SPIRV_REGISTRY_AND_NOT_FROM_GRAMMARS = """ -SPV_AMD_gcn_shader SPV_AMD_gpu_shader_half_float SPV_AMD_gpu_shader_int16 -SPV_AMD_shader_trinary_minmax SPV_KHR_non_semantic_info SPV_EXT_relaxed_printf_string_address_space """ -MODE='new' +class ExtInst(): + """ + An extended instruction set. + + Properties: + prefix: the string prefix for operand enums. Often an empty string. + file: the location of the JSON grammar file + name: the name, can be used as an identifier + enum_name: the enum name, e.g. SPV_EXT_INST_OPENCL_STD + grammar: the JSON object for the grammar, loaded from the file. + """ + def __init__(self,spec: str): + matches = re.fullmatch('^([^,]*),(.*)',spec) + if matches is None: + raise Exception("Invalid prefix and path: {}".format(spec)) + self.prefix = matches[1] + if self.prefix is None: + self.prefix = "" + self.file = matches[2] + matches = re.match('.*extinst\\.(.*)\\.grammar.json', self.file) + if matches is None: + raise Exception("Invalid grammar file name: {}".format(self.file)) + self.name = matches[1].replace('-','_').replace('.','_') + + self.enum_name = 'SPV_EXT_INST_TYPE_{}'.format(self.name).upper() + if self.enum_name == "SPV_EXT_INST_TYPE_OPENCL_STD_100": + # Live with an old decision, by adjusting this name. + self.enum_name = "SPV_EXT_INST_TYPE_OPENCL_STD" + + self.load() + + def load(self): + """ + Populates self.grammar from the file. + Applies the self.prefix to operand enums + """ + with open(self.file) as json_file: + self.grammar = json.loads(json_file.read()) + if len(self.prefix) > 0: + prefix_operand_kind_names(self.prefix, self.grammar) + def convert_min_required_version(version): # (version: str | None) -> str """Converts the minimal required SPIR-V version encoded in the grammar to @@ -439,7 +477,6 @@ def ShouldEmit(operand_kind_json: Dict[str,any]): parts.append(" }\n return IR(0,0);\n}\n") self.body_decls.extend(parts) - def ComputeInstructionTables(self, insts) -> None: """ Creates declarations for instruction tables. @@ -448,8 +485,7 @@ def ComputeInstructionTables(self, insts) -> None: Params: insts: an array of instructions objects using the JSON schema """ - self.header_ignore_decls.append( -""" + self.header_ignore_decls.append(""" // Describes an Instruction struct InstructionDesc { const spv::Op value; @@ -559,6 +595,118 @@ def ComputeInstructionTables(self, insts) -> None: self.body_decls.extend(parts) + def ComputeExtendedInstructions(self, extinsts) -> None: + """ + Generates tables for extended instructions + + Args: + self + extinsts: a list of extinst objects + """ + + """ + ExtInstDesc { + value: uint32_t + name: IndexRange + operands: IndexRange + capabilities: IndexRange + } + + The definitions are: + - kExtInstByValue: a 1-dimensional array of all operand descriptions + sorted first by extended instruction enum, then by operand value. + + - ExtInstByValueRangeForKind: a function mapping from extinst enum to + the index range into kExtInstByValue. + + - kExtInstNames: a 1-dimensional array of all extinst name-value pairs, + sorted first by extinst enum, then by operand name. + Each entry is represented by an index range into the string table. + + - kExtInstNamesRangeByKind: a mapping from operand kind to the index + range into kOperandNames. + This has mappings for both concrete and corresponding optional operand kinds. + """ + + # Create kExtInstByValue + by_value: List[List[Any]] = [] + by_value_by_kind: Dict[str,IndexRange] = {} + for e in extinsts: + insts_in_set = [] + for inst in sorted(e.grammar['instructions'], key = lambda inst: inst['opcode']): + operands = [convert_operand_kind(o) for o in inst.get('operands',[])] + inst_parts = [ + inst['opcode'], + self.context.AddStringList('operand', operands), + self.context.AddString(inst['opname']), + self.context.AddStringList('capability', inst.get('capabilities',[])), + ] + inst_parts = [str(x) for x in inst_parts] + insts_in_set.append(' {{{}}}, // {} in {}'.format( + ','.join(inst_parts), inst['opname'], e.name)) + by_value_by_kind[e.enum_name] = IndexRange(len(by_value), len(insts_in_set)) + by_value.extend(insts_in_set) + + parts: List[str] = [] + parts.append("""// Extended instruction descriptions, ordered by (extinst enum, opcode value). +// The fields in order are: +// enum value +// operands, an IndexRange into kOperandSpans +// name, a character-counting IndexRange into kStrings +// capabilities, an IndexRange into kCapabilitySpans""") + parts.append("static const std::array kExtInstByValue{{{{".format(len(by_value))) + parts.extend(by_value) + parts.append('}};\n') + self.body_decls.extend(parts) + + # Create kExtInstByValueRangeForKind + parts = [] + parts.append("""// Maps an extended instruction enum to possible names for operands of that kind. +// The result is an IndexRange into kOperandNames, and the names +// are sorted by name within that span. +// An optional variant of a kind maps to the details for the corresponding +// concrete operand kind.""") + parts = ["IndexRange ExtInstByValueRangeForKind(spv_ext_inst_type_t type) {\n switch(type) {"] + for name, ir in by_value_by_kind.items(): + parts.append(" case {}: return {};".format(name, ir)) + parts.append(" default: break;"); + parts.append(" }\n return IR(0,0);\n}\n") + self.body_decls.extend(parts) + + # Create kExtInstNames + parts = [] + by_name: List[List[Any]] = [] + by_name_by_kind: Dict[str,IndexRange] = {} + for e in extinsts: + # Sort by name within a set + insts_by_name = sorted(e.grammar['instructions'], key = lambda i: i['opname']) + insts_in_set = [] + for inst in insts_by_name: + insts_in_set.append( + ' {{{}, {}}}, // {} in {}'.format( + str(self.context.AddString(inst['opname'])), + inst['opcode'], + inst['opname'], + e.name)) + by_name_by_kind[e.enum_name] = IndexRange(len(by_name), len(insts_in_set)) + by_name.extend(insts_in_set) + parts.append("static const std::array kExtInstNames{{{{".format(len(by_name))) + parts.extend(by_name) + parts.append('}};\n') + self.body_decls.extend(parts) + + # Create kExtInstNameRangeByKind + parts = [] + parts.append("""// Maps an extended instruction kind to possible names for instructions of that kind. +// The result is an IndexRange into kExtInstNames, and the names +// are sorted by name within that span.""") + parts = ["IndexRange ExtInstNameRangeForKind(spv_ext_inst_type_t type) {\n switch(type) {"] + for name, ir in by_name_by_kind.items(): + parts.append(" case {}: return {};".format(name, str(ir))) + parts.append(" default: break;"); + parts.append(" }\n return IR(0,0);\n}\n") + self.body_decls.extend(parts) + def ComputeLeafTables(self) -> None: """ Generates the tables that the instruction and operand tables point to. @@ -749,22 +897,10 @@ def main(): type=str, required=False, help='input JSON grammar file for core SPIR-V ' 'instructions') - parser.add_argument('--extinst-debuginfo-grammar', metavar='', - type=str, required=False, default=None, - help='input JSON grammar file for DebugInfo extended ' - 'instruction set') - parser.add_argument('--extinst-cldebuginfo100-grammar', metavar='', - type=str, required=False, default=None, - help='input JSON grammar file for OpenCL.DebugInfo.100 ' - 'extended instruction set') - parser.add_argument('--extinst-glsl-grammar', metavar='', - type=str, required=False, default=None, - help='input JSON grammar file for GLSL extended ' - 'instruction set') - parser.add_argument('--extinst-opencl-grammar', metavar='', - type=str, required=False, default=None, - help='input JSON grammar file for OpenCL extended ' - 'instruction set') + parser.add_argument('--extinst', metavar='', + type=str, action='append', required=False, default=None, + help='extended instruction info: an enum prefix, then a comma, then' + ' the file location of the JSON grammar') parser.add_argument('--core-tables-body-output', metavar='', type=str, required=False, default=None, @@ -773,118 +909,53 @@ def main(): type=str, required=False, default=None, help='output file for core SPIR-V grammar tables to be included in .h') - # TODO: remove unused options - parser.add_argument('--core-insts-output', metavar='', - type=str, required=False, default=None, - help='output file for core SPIR-V instructions') - parser.add_argument('--glsl-insts-output', metavar='', - type=str, required=False, default=None, - help='output file for GLSL extended instruction set') - parser.add_argument('--opencl-insts-output', metavar='', - type=str, required=False, default=None, - help='output file for OpenCL extended instruction set') - parser.add_argument('--operand-kinds-output', metavar='', - type=str, required=False, default=None, - help='output file for operand kinds') - parser.add_argument('--extension-enum-output', metavar='', - type=str, required=False, default=None, - help='output file for extension enumeration') - parser.add_argument('--enum-string-mapping-output', metavar='', - type=str, required=False, default=None, - help='output file for enum-string mappings') - parser.add_argument('--extinst-vendor-grammar', metavar='', - type=str, required=False, default=None, - help='input JSON grammar file for vendor extended ' - 'instruction set'), - parser.add_argument('--vendor-insts-output', metavar='', - type=str, required=False, default=None, - help='output file for vendor extended instruction set') - parser.add_argument('--vendor-operand-kind-prefix', metavar='', - type=str, required=False, default=None, - help='prefix for operand kinds (to disambiguate operand type enums)') args = parser.parse_args() - - # The GN build system needs this because it doesn't handle quoting - # empty string arguments well. - if args.vendor_operand_kind_prefix == "...nil...": - args.vendor_operand_kind_prefix = "" - - if (args.core_insts_output is None) != \ - (args.operand_kinds_output is None): - print('error: --core-insts-output and --operand-kinds-output ' - 'should be specified together.') - exit(1) - if args.operand_kinds_output and not (args.spirv_core_grammar and - args.extinst_debuginfo_grammar and - args.extinst_cldebuginfo100_grammar): - print('error: --operand-kinds-output requires --spirv-core-grammar ' - 'and --extinst-debuginfo-grammar ' - 'and --extinst-cldebuginfo100-grammar') - exit(1) - if (args.glsl_insts_output is None) != \ - (args.extinst_glsl_grammar is None): - print('error: --glsl-insts-output and --extinst-glsl-grammar ' - 'should be specified together.') - exit(1) - if (args.opencl_insts_output is None) != \ - (args.extinst_opencl_grammar is None): - print('error: --opencl-insts-output and --extinst-opencl-grammar ' - 'should be specified together.') + if args.spirv_core_grammar is None: + print('error: missing --spirv-core-grammar ') exit(1) - if (args.vendor_insts_output is None) != \ - (args.extinst_vendor_grammar is None): - print('error: --vendor-insts-output and ' - '--extinst-vendor-grammar should be specified together.') + if (args.core_tables_body_output is None) and (args.core_tables_header_output is None): + print('error: need at least one of --core-tables-body-output --core-tables-header-output ') exit(1) - if all([args.core_insts_output is None, - args.core_tables_body_output is None, - args.core_tables_header_output is None, - args.glsl_insts_output is None, - args.opencl_insts_output is None, - args.vendor_insts_output is None, - args.extension_enum_output is None, - args.enum_string_mapping_output is None]): - print('error: at least one output should be specified.') + if len(args.extinst) < 1: + print('error: missing --extinst ') exit(1) - if args.spirv_core_grammar is not None: - # Populate instructions, extensions, operand_kinds list of json objects - with open(args.spirv_core_grammar) as json_file: - core_grammar = json.loads(json_file.read()) - with open(args.extinst_debuginfo_grammar) as debuginfo_json_file: - debuginfo_grammar = json.loads(debuginfo_json_file.read()) - with open(args.extinst_cldebuginfo100_grammar) as cldebuginfo100_json_file: - cldebuginfo100_grammar = json.loads(cldebuginfo100_json_file.read()) - prefix_operand_kind_names("CLDEBUG100_", cldebuginfo100_grammar) - instructions = [] - instructions.extend(core_grammar['instructions']) - instructions.extend(debuginfo_grammar['instructions']) - instructions.extend(cldebuginfo100_grammar['instructions']) - operand_kinds = [] - operand_kinds.extend(core_grammar['operand_kinds']) - operand_kinds.extend(debuginfo_grammar['operand_kinds']) - operand_kinds.extend(cldebuginfo100_grammar['operand_kinds']) - - extensions = get_extension_list(instructions, operand_kinds) - operand_kinds = precondition_operand_kinds(operand_kinds) - - printing_class: List[str] = [e['tag'] for e in core_grammar['instruction_printing_class']] - - g = Grammar(extensions, operand_kinds, printing_class) - - g.ComputeOperandTables() - g.ComputeInstructionTables(core_grammar['instructions']) - g.ComputeLeafTables() - - if args.core_tables_body_output is not None: - make_path_to_file(args.core_tables_body_output) - with open(args.core_tables_body_output, 'w') as f: - f.write('\n'.join(g.body_decls)) - if args.core_tables_header_output is not None: - make_path_to_file(args.core_tables_header_output) - with open(args.core_tables_header_output, 'w') as f: - f.write('\n'.join(g.header_decls)) + # Load the JSON grammar files. + extinsts = sorted([ExtInst(e) for e in args.extinst], key = lambda e: e.name) + with open(args.spirv_core_grammar) as json_file: + core_grammar = json.loads(json_file.read()) + printing_class: List[str] = [e['tag'] for e in core_grammar['instruction_printing_class']] + + # Collect all operand kinds and instructions, so we can generate + # extension lists, capability lists, and alias lists. + # Make a copy to avoid polluting the instruction list. + instructions = [x for x in core_grammar['instructions']] + operand_kinds = [x for x in core_grammar['operand_kinds']] + for e in extinsts: + instructions.extend(e.grammar.get('instructions',[])) + operand_kinds.extend(e.grammar.get('operand_kinds',[])) + + extensions = get_extension_list(instructions, operand_kinds) + # TODO(dneto): I think preconditioning is no longer necessary now that + # aliases are explicitly represented. + operand_kinds = precondition_operand_kinds(operand_kinds) + + g = Grammar(extensions, operand_kinds, printing_class) + g.ComputeOperandTables() + g.ComputeInstructionTables(core_grammar['instructions']) + g.ComputeExtendedInstructions(extinsts) + g.ComputeLeafTables() + + if args.core_tables_body_output is not None: + make_path_to_file(args.core_tables_body_output) + with open(args.core_tables_body_output, 'w') as f: + f.write('\n'.join(g.body_decls)) + if args.core_tables_header_output is not None: + make_path_to_file(args.core_tables_header_output) + with open(args.core_tables_header_output, 'w') as f: + f.write('\n'.join(g.header_decls)) + exit(0) if __name__ == '__main__':