From ad4bf42b7e2779aa5f59d017e76071d3ec6e4242 Mon Sep 17 00:00:00 2001 From: Matthias Fauconneau Date: Thu, 23 Sep 2021 11:26:02 +0200 Subject: [PATCH] Simplify extensions. Add Debug PrintF --- autogen/src/header.rs | 62 ++-------- autogen/src/main.rs | 112 ++++++++++-------- autogen/src/structs.rs | 2 + autogen/src/table.rs | 22 +--- .../autogen_nonsemantic_debugprintf.rs | 11 ++ rspirv/tests/spirv_blobs.rs | 3 +- spirv/autogen_spirv.rs | 23 +++- 7 files changed, 110 insertions(+), 125 deletions(-) create mode 100644 rspirv/grammar/autogen_nonsemantic_debugprintf.rs diff --git a/autogen/src/header.rs b/autogen/src/header.rs index fbbc1cac..e5079655 100644 --- a/autogen/src/header.rs +++ b/autogen/src/header.rs @@ -6,12 +6,6 @@ use proc_macro2::TokenStream; use quote::quote; use std::collections::BTreeMap; -static GLSL_STD_450_SPEC_LINK: &str = "\ -https://www.khronos.org/registry/spir-v/specs/unified1/GLSL.std.450.html"; - -static OPENCL_STD_SPEC_LINK: &str = "\ -https://www.khronos.org/registry/spir-v/specs/unified1/OpenCL.ExtendedInstructionSet.100.html"; - /// Returns the markdown string containing a link to the spec for the given /// operand `kind`. fn get_spec_link(kind: &str) -> String { @@ -304,48 +298,10 @@ pub fn gen_spirv_header(grammar: &structs::Grammar) -> TokenStream { } } -/// Returns the GLSL.std.450 extended instruction opcodes. -pub fn gen_glsl_std_450_opcodes(grammar: &structs::ExtInstSetGrammar) -> TokenStream { - // Get the instruction table. - let opcodes = grammar.instructions.iter().map(|inst| { - // Omit the "Op" prefix. - let opname = as_ident(&inst.opname); - let opcode = inst.opcode; - quote! { #opname = #opcode } - }); - - let from_prim_list = grammar - .instructions - .iter() - .map(|inst| { - let opname = as_ident(&inst.opname); - let opcode = inst.opcode; - quote! { #opcode => GLOp::#opname } - }) - .collect::>(); - - let comment = format!( - "[GLSL.std.450]({}) extended instruction opcode", - GLSL_STD_450_SPEC_LINK - ); - let attribute = value_enum_attribute(); - let from_prim_impl = from_primitive_impl(&from_prim_list, &as_ident("GLOp")); - - quote! { - #[doc = #comment] - #attribute - #[allow(clippy::upper_case_acronyms)] - pub enum GLOp { - #(#opcodes),* - } - - #from_prim_impl - } -} - -/// Returns the OpenCL.std extended instruction opcodes. -pub fn gen_opencl_std_opcodes(grammar: &structs::ExtInstSetGrammar) -> TokenStream { - // Get the instruction table. +/// Returns extended instruction opcodes +pub fn gen_opcodes(op: &str, grammar: &structs::ExtInstSetGrammar, comment: &str) -> TokenStream { + let op = as_ident(op); + // Get the instruction table let opcodes = grammar.instructions.iter().map(|inst| { // Omit the "Op" prefix. let opname = as_ident(&inst.opname); @@ -359,22 +315,18 @@ pub fn gen_opencl_std_opcodes(grammar: &structs::ExtInstSetGrammar) -> TokenStre .map(|inst| { let opname = as_ident(&inst.opname); let opcode = inst.opcode; - quote! { #opcode => CLOp::#opname } + quote! { #opcode => #op::#opname } }) .collect::>(); - let comment = format!( - "[OpenCL.std]({}) extended instruction opcode", - OPENCL_STD_SPEC_LINK - ); let attribute = value_enum_attribute(); - let from_prim_impl = from_primitive_impl(&from_prim_list, &as_ident("CLOp")); + let from_prim_impl = from_primitive_impl(&from_prim_list, &op); quote! { #[doc = #comment] #attribute #[allow(clippy::upper_case_acronyms)] - pub enum CLOp { + pub enum #op { #(#opcodes),* } diff --git a/autogen/src/main.rs b/autogen/src/main.rs index 8054de43..2eba5efb 100644 --- a/autogen/src/main.rs +++ b/autogen/src/main.rs @@ -9,8 +9,9 @@ mod table; mod utils; use std::{ - env, fs, - io::{Read, Write}, + env, + fs, + io::Write, path::{Path, PathBuf}, process, }; @@ -61,65 +62,82 @@ fn main() { panic!("SPIRV-Headers missing - please checkout using git submodule"); } - let mut contents = String::new(); - - { - let path = autogen_src_dir - .join("external/SPIRV-Headers/include/spirv/unified1/spirv.core.grammar.json"); - let mut file = fs::File::open(path).unwrap(); - file.read_to_string(&mut contents).unwrap(); - } - let grammar: structs::Grammar = { - let mut original = serde_json::from_str(&contents).unwrap(); + let mut original = + serde_json::from_str( + &std::str::from_utf8( + &fs::read(autogen_src_dir.join( + "external/SPIRV-Headers/include/spirv/unified1/spirv.core.grammar.json", + )) + .unwrap(), + ) + .unwrap(), + ) + .unwrap(); map_reserved_instructions(&mut original); original }; - // For GLSLstd450 extended instruction set. - { - let path = autogen_src_dir.join( - "external/SPIRV-Headers/include/spirv/unified1/extinst.glsl.std.450.grammar.json", - ); - let mut file = fs::File::open(path).unwrap(); - contents.clear(); - file.read_to_string(&mut contents).unwrap(); - } - let gl_grammar: structs::ExtInstSetGrammar = serde_json::from_str(&contents).unwrap(); - - // For OpenCL extended instruction set. - { - let path = autogen_src_dir.join( - "external/SPIRV-Headers/include/spirv/unified1/extinst.opencl.std.100.grammar.json", - ); - let mut file = fs::File::open(path).unwrap(); - contents.clear(); - file.read_to_string(&mut contents).unwrap(); - } - let cl_grammar: structs::ExtInstSetGrammar = serde_json::from_str(&contents).unwrap(); + let extended_instruction_sets = [ + ("GLSL.std.450", "GLOp", "https://www.khronos.org/registry/spir-v/specs/unified1/GLSL.std.450.html"), + ("OpenCL.std.100", "CLOp", "https://www.khronos.org/registry/spir-v/specs/unified1/OpenCL.ExtendedInstructionSet.100.html"), + ("NonSemantic.DebugPrintF", "DebugPrintFOp", "https://github.com/KhronosGroup/Vulkan-ValidationLayers/blob/master/docs/debug_printf.md"), + ]; + let extended_instruction_sets = extended_instruction_sets.map(|(ext, op, url)| { + let grammar: structs::ExtInstSetGrammar = serde_json::from_str( + &std::str::from_utf8( + &fs::read(autogen_src_dir.join(format!( + "external/SPIRV-Headers/include/spirv/unified1/extinst.{}.grammar.json", + ext.to_lowercase() + ))) + .unwrap(), + ) + .unwrap(), + ) + .unwrap(); + (ext, op, url, grammar) + }); - // Path to the generated SPIR-V header file. + // SPIR-V header write_formatted(&autogen_src_dir.join("../spirv/autogen_spirv.rs"), { let core = header::gen_spirv_header(&grammar); - let gl = header::gen_glsl_std_450_opcodes(&gl_grammar); - let cl = header::gen_opencl_std_opcodes(&cl_grammar); - format!("{}\n{}\n{}", core, gl, cl) + let extended_instruction_sets = + extended_instruction_sets + .iter() + .map(|(ext, op, url, grammar)| { + header::gen_opcodes( + op, + &grammar, + &format!("[{}]({}) extended instruction opcode", ext, url), + ) + .to_string() + }); + format!( + "{}\n{}", + core, + extended_instruction_sets.collect::>().join("\n") + ) }); - // Path to the generated instruction table. + // Instruction table write_formatted( &autogen_src_dir.join("../rspirv/grammar/autogen_table.rs"), table::gen_grammar_inst_table_operand_kinds(&grammar), ); - // Path to the generated GLSLstd450 extended instruction set header. - write_formatted( - &autogen_src_dir.join("../rspirv/grammar/autogen_glsl_std_450.rs"), - table::gen_glsl_std_450_inst_table(&gl_grammar), - ); - write_formatted( - &autogen_src_dir.join("../rspirv/grammar/autogen_opencl_std_100.rs"), - table::gen_opencl_std_100_inst_table(&cl_grammar), - ); + // Extended instruction sets + for (ext, _, _, grammar) in extended_instruction_sets { + write_formatted( + &autogen_src_dir.join(format!( + "../rspirv/grammar/autogen_{}.rs", + ext.replace(".", "_").to_lowercase() + )), + table::gen_instruction_table( + &grammar.instructions, + &format!("{}_INSTRUCTION_TABLE", ext.replace(".", "_").to_uppercase()), + true, + ), + ); + } // Path to the generated operands kind in data representation. write_formatted( diff --git a/autogen/src/structs.rs b/autogen/src/structs.rs index 138a895b..36683e6f 100644 --- a/autogen/src/structs.rs +++ b/autogen/src/structs.rs @@ -65,7 +65,9 @@ pub struct Grammar { #[derive(Debug, Deserialize)] pub struct ExtInstSetGrammar { + #[serde(default)] pub copyright: Vec, + #[serde(default)] pub version: u32, pub revision: u32, pub instructions: Vec, diff --git a/autogen/src/table.rs b/autogen/src/table.rs index 58659ab3..c3d60a77 100644 --- a/autogen/src/table.rs +++ b/autogen/src/table.rs @@ -19,7 +19,7 @@ fn convert_quantifier(quantifier: structs::Quantifier) -> Ident { /// `grammar` is expected to be an array of SPIR-V instructions. /// `name` is the name of the generated table. /// `is_ext` indicates whether the grammar is for an extended instruction set. -fn gen_instruction_table( +pub(crate) fn gen_instruction_table( grammar: &[structs::Instruction], name: &str, is_ext: bool, @@ -82,23 +82,3 @@ pub fn gen_grammar_inst_table_operand_kinds(grammar: &structs::Grammar) -> Token #table } } - -/// Writes the generated instruction table for GLSLstd450 extended instruction -/// set from `grammar` to the file with the given `filename`. -pub fn gen_glsl_std_450_inst_table(grammar: &structs::ExtInstSetGrammar) -> TokenStream { - gen_instruction_table( - &grammar.instructions, - "GLSL_STD_450_INSTRUCTION_TABLE", - true, - ) -} - -/// Writes the generated instruction table for OpenCLstd100 extended instruction -/// set from `grammar` to the file with the given `filename`. -pub fn gen_opencl_std_100_inst_table(grammar: &structs::ExtInstSetGrammar) -> TokenStream { - gen_instruction_table( - &grammar.instructions, - "OPENCL_STD_100_INSTRUCTION_TABLE", - true, - ) -} diff --git a/rspirv/grammar/autogen_nonsemantic_debugprintf.rs b/rspirv/grammar/autogen_nonsemantic_debugprintf.rs new file mode 100644 index 00000000..bdb6f387 --- /dev/null +++ b/rspirv/grammar/autogen_nonsemantic_debugprintf.rs @@ -0,0 +1,11 @@ +// AUTOMATICALLY GENERATED from the SPIR-V JSON grammar: +// external/spirv.core.grammar.json. +// DO NOT MODIFY! + +static NONSEMANTIC_DEBUGPRINTF_INSTRUCTION_TABLE: &[ExtendedInstruction<'static>] = &[ext_inst!( + DebugPrintf, + 1u32, + [], + [], + [(IdRef, One), (IdRef, ZeroOrMore)] +)]; diff --git a/rspirv/tests/spirv_blobs.rs b/rspirv/tests/spirv_blobs.rs index f1f25647..40a13096 100644 --- a/rspirv/tests/spirv_blobs.rs +++ b/rspirv/tests/spirv_blobs.rs @@ -1,6 +1,7 @@ use rspirv::{ binary::{Assemble as _, Disassemble as _}, - dr, lift, + dr, + lift, }; use std::path::PathBuf; diff --git a/spirv/autogen_spirv.rs b/spirv/autogen_spirv.rs index e3256485..d208ab85 100644 --- a/spirv/autogen_spirv.rs +++ b/spirv/autogen_spirv.rs @@ -3989,7 +3989,7 @@ impl num_traits::FromPrimitive for GLOp { Self::from_i64(n as i64) } } -#[doc = "[OpenCL.std](https://www.khronos.org/registry/spir-v/specs/unified1/OpenCL.ExtendedInstructionSet.100.html) extended instruction opcode"] +#[doc = "[OpenCL.std.100](https://www.khronos.org/registry/spir-v/specs/unified1/OpenCL.ExtendedInstructionSet.100.html) extended instruction opcode"] #[repr(u32)] #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] #[cfg_attr(feature = "serialize", derive(serde::Serialize))] @@ -4332,3 +4332,24 @@ impl num_traits::FromPrimitive for CLOp { Self::from_i64(n as i64) } } +#[doc = "[NonSemantic.DebugPrintF](https://github.com/KhronosGroup/Vulkan-ValidationLayers/blob/master/docs/debug_printf.md) extended instruction opcode"] +#[repr(u32)] +#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] +#[cfg_attr(feature = "serialize", derive(serde::Serialize))] +#[cfg_attr(feature = "deserialize", derive(serde::Deserialize))] +#[allow(clippy::upper_case_acronyms)] +pub enum DebugPrintFOp { + DebugPrintf = 1u32, +} +impl num_traits::FromPrimitive for DebugPrintFOp { + #[allow(trivial_numeric_casts)] + fn from_i64(n: i64) -> Option { + Some(match n as u32 { + 1u32 => DebugPrintFOp::DebugPrintf, + _ => return None, + }) + } + fn from_u64(n: u64) -> Option { + Self::from_i64(n as i64) + } +}