From 24fafecd982de26874821c9c907d358b699381e7 Mon Sep 17 00:00:00 2001 From: Ashley Ruglys Date: Sat, 16 Oct 2021 06:45:11 -0700 Subject: [PATCH 01/31] Add a very bad no good prinfln macro --- crates/spirv-std/macros/src/lib.rs | 63 ++++++++++++++++++++++++++++++ 1 file changed, 63 insertions(+) diff --git a/crates/spirv-std/macros/src/lib.rs b/crates/spirv-std/macros/src/lib.rs index cf5e21d639..53410f737b 100644 --- a/crates/spirv-std/macros/src/lib.rs +++ b/crates/spirv-std/macros/src/lib.rs @@ -350,3 +350,66 @@ fn path_from_ident(ident: Ident) -> syn::Type { path: syn::Path::from(ident), }) } + +#[derive(Default)] +struct PrintfInput { + string: String, + expressions: Vec, +} + +impl syn::parse::Parse for PrintfInput { + fn parse(input: syn::parse::ParseStream<'_>) -> syn::parse::Result { + if input.is_empty() { + return Ok(Self::default()); + } + + Ok(Self { + string: input.parse::()?.value(), + expressions: { + let mut expressions = Vec::new(); + while !input.is_empty() { + input.parse::()?; + expressions.push(input.parse()?); + } + expressions + }, + }) + } +} + +#[proc_macro] +pub fn printfln(input: TokenStream) -> TokenStream { + let input = syn::parse_macro_input!(input as PrintfInput); + + let PrintfInput { + string, + expressions, + } = input; + + let mut input_string = String::new(); + let mut registers = Vec::new(); + + for (i, expression) in expressions.into_iter().enumerate() { + input_string.push_str(&format!(" {{n{}}}", i)); + + let ident = quote::format_ident!("n{}", i); + + registers.push(quote::quote! { + #ident = in(reg) #expression, + }); + } + + let registers = registers.into_iter().collect::(); + + let output = quote::quote! { + asm!( + "%void = OpTypeVoid", + concat!("%string = OpString \"", #string, "\\n\""), + "%debug_printf = OpExtInstImport \"NonSemantic.DebugPrintf\"", + concat!("%result = OpExtInst %void %debug_printf 1 %string", #input_string), + #registers + ) + }; + + output.into() +} From 56567708b9482aca4da70d6c8d8edb2f3fcffd1e Mon Sep 17 00:00:00 2001 From: Ashley Ruglys Date: Sat, 16 Oct 2021 07:01:09 -0700 Subject: [PATCH 02/31] Use a better registry identifier --- crates/spirv-std/macros/src/lib.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/crates/spirv-std/macros/src/lib.rs b/crates/spirv-std/macros/src/lib.rs index 53410f737b..7679a3065e 100644 --- a/crates/spirv-std/macros/src/lib.rs +++ b/crates/spirv-std/macros/src/lib.rs @@ -390,9 +390,9 @@ pub fn printfln(input: TokenStream) -> TokenStream { let mut registers = Vec::new(); for (i, expression) in expressions.into_iter().enumerate() { - input_string.push_str(&format!(" {{n{}}}", i)); + let ident = quote::format_ident!("_{}", i); - let ident = quote::format_ident!("n{}", i); + input_string.push_str(&format!(" {{{}}}", ident)); registers.push(quote::quote! { #ident = in(reg) #expression, From 99315314f3d6b96602fe0125d11ec1a2db83f5f0 Mon Sep 17 00:00:00 2001 From: Ashley Ruglys Date: Sat, 16 Oct 2021 07:22:24 -0700 Subject: [PATCH 03/31] Do a little bit of argument count checking --- crates/spirv-std/macros/src/lib.rs | 27 +++++++++++++++++++++++++-- 1 file changed, 25 insertions(+), 2 deletions(-) diff --git a/crates/spirv-std/macros/src/lib.rs b/crates/spirv-std/macros/src/lib.rs index 7679a3065e..1461e87864 100644 --- a/crates/spirv-std/macros/src/lib.rs +++ b/crates/spirv-std/macros/src/lib.rs @@ -351,19 +351,26 @@ fn path_from_ident(ident: Ident) -> syn::Type { }) } -#[derive(Default)] struct PrintfInput { + span: proc_macro2::Span, string: String, expressions: Vec, } impl syn::parse::Parse for PrintfInput { fn parse(input: syn::parse::ParseStream<'_>) -> syn::parse::Result { + let span = input.span(); + if input.is_empty() { - return Ok(Self::default()); + return Ok(Self { + span, + string: Default::default(), + expressions: Default::default(), + }); } Ok(Self { + span, string: input.parse::()?.value(), expressions: { let mut expressions = Vec::new(); @@ -384,8 +391,24 @@ pub fn printfln(input: TokenStream) -> TokenStream { let PrintfInput { string, expressions, + span, } = input; + let number_of_arguments = string.matches('%').count() - string.matches("%%").count() * 2; + + if number_of_arguments != expressions.len() { + return syn::Error::new( + span, + &format!( + "{} % arguments were found, but {} expressions were given", + number_of_arguments, + expressions.len() + ), + ) + .to_compile_error() + .into(); + } + let mut input_string = String::new(); let mut registers = Vec::new(); From 4f2048d108d8b04da48e4f1a5c022a339b6ea0ae Mon Sep 17 00:00:00 2001 From: Ashley Ruglys Date: Sat, 16 Oct 2021 08:21:33 -0700 Subject: [PATCH 04/31] Use OpLoads to be able to print vectors --- crates/spirv-std/macros/src/lib.rs | 27 ++++++++++++++++++++++++--- 1 file changed, 24 insertions(+), 3 deletions(-) diff --git a/crates/spirv-std/macros/src/lib.rs b/crates/spirv-std/macros/src/lib.rs index 1461e87864..b5ba926acf 100644 --- a/crates/spirv-std/macros/src/lib.rs +++ b/crates/spirv-std/macros/src/lib.rs @@ -384,6 +384,16 @@ impl syn::parse::Parse for PrintfInput { } } +/// Print a formatted string with a newline using the debug printf extension. +/// +/// Examples: +/// +/// ```rust,ignore +/// printfln!("uv: %v2f", uv); +/// printfln!("pos.x: %f, pos.z: %f, int: %i", pos.x, pos.z, int); +/// ``` +/// +/// See for formatting rules. #[proc_macro] pub fn printfln(input: TokenStream) -> TokenStream { let input = syn::parse_macro_input!(input as PrintfInput); @@ -411,24 +421,35 @@ pub fn printfln(input: TokenStream) -> TokenStream { let mut input_string = String::new(); let mut registers = Vec::new(); + let mut op_loads = Vec::new(); for (i, expression) in expressions.into_iter().enumerate() { let ident = quote::format_ident!("_{}", i); - input_string.push_str(&format!(" {{{}}}", ident)); + input_string.push_str(&format!(" %{}", ident)); registers.push(quote::quote! { - #ident = in(reg) #expression, + #ident = in(reg) &#expression, + }); + + let op_load = format!("%{ident} = OpLoad _ {{{ident}}}", ident = ident); + + op_loads.push(quote::quote! { + #op_load, }); } let registers = registers.into_iter().collect::(); + let op_loads = op_loads.into_iter().collect::(); + + let op_string = format!("%string = OpString \"{}\\n\"", string); let output = quote::quote! { asm!( "%void = OpTypeVoid", - concat!("%string = OpString \"", #string, "\\n\""), + #op_string, "%debug_printf = OpExtInstImport \"NonSemantic.DebugPrintf\"", + #op_loads concat!("%result = OpExtInst %void %debug_printf 1 %string", #input_string), #registers ) From 6a21a292e230ec1092c55fe09704a1cd40d9ba12 Mon Sep 17 00:00:00 2001 From: Ashley Ruglys Date: Sat, 16 Oct 2021 08:29:32 -0700 Subject: [PATCH 05/31] Add an error for string literal expressions --- crates/spirv-std/macros/src/lib.rs | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/crates/spirv-std/macros/src/lib.rs b/crates/spirv-std/macros/src/lib.rs index b5ba926acf..6f7d87e91f 100644 --- a/crates/spirv-std/macros/src/lib.rs +++ b/crates/spirv-std/macros/src/lib.rs @@ -376,7 +376,17 @@ impl syn::parse::Parse for PrintfInput { let mut expressions = Vec::new(); while !input.is_empty() { input.parse::()?; - expressions.push(input.parse()?); + + let expr = input.parse()?; + + if let syn::Expr::Lit(syn::ExprLit { lit: syn::Lit::Str(lit_str), ..}) = expr { + return Err(syn::Error::new( + lit_str.span(), + "String literals should be part of the format string.", + )) + } + + expressions.push(expr); } expressions }, From 2ee529e11dcc7d0693ec970887c10af0ad73085b Mon Sep 17 00:00:00 2001 From: Ashley Ruglys Date: Sat, 16 Oct 2021 08:48:28 -0700 Subject: [PATCH 06/31] Revert "Add an error for string literal expressions" This reverts commit 6a21a292e230ec1092c55fe09704a1cd40d9ba12. --- crates/spirv-std/macros/src/lib.rs | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/crates/spirv-std/macros/src/lib.rs b/crates/spirv-std/macros/src/lib.rs index 6f7d87e91f..b5ba926acf 100644 --- a/crates/spirv-std/macros/src/lib.rs +++ b/crates/spirv-std/macros/src/lib.rs @@ -376,17 +376,7 @@ impl syn::parse::Parse for PrintfInput { let mut expressions = Vec::new(); while !input.is_empty() { input.parse::()?; - - let expr = input.parse()?; - - if let syn::Expr::Lit(syn::ExprLit { lit: syn::Lit::Str(lit_str), ..}) = expr { - return Err(syn::Error::new( - lit_str.span(), - "String literals should be part of the format string.", - )) - } - - expressions.push(expr); + expressions.push(input.parse()?); } expressions }, From 9311710ebce4d8471546e49096363dbe653b3346 Mon Sep 17 00:00:00 2001 From: Ashley Ruglys Date: Sat, 16 Oct 2021 10:13:11 -0700 Subject: [PATCH 07/31] Add both printf and printfln, allow for other kinds of expressions by blocking the in(reg) --- crates/spirv-std/macros/src/lib.rs | 113 ++++++++++++++++++----------- 1 file changed, 70 insertions(+), 43 deletions(-) diff --git a/crates/spirv-std/macros/src/lib.rs b/crates/spirv-std/macros/src/lib.rs index b5ba926acf..66501c9c80 100644 --- a/crates/spirv-std/macros/src/lib.rs +++ b/crates/spirv-std/macros/src/lib.rs @@ -351,10 +351,49 @@ fn path_from_ident(ident: Ident) -> syn::Type { }) } +/// Print a formatted string with a newline using the debug printf extension. +/// +/// Examples: +/// +/// ```rust,ignore +/// printfln!("uv: %v2f", uv); +/// printfln!("pos.x: %f, pos.z: %f, int: %i", pos.x, pos.z, int); +/// ``` +/// +/// See for formatting rules. +#[proc_macro] +pub fn printf(input: TokenStream) -> TokenStream { + let input = syn::parse_macro_input!(input as PrintfInput); + + let PrintfInput { + format_string, + variables, + span, + } = input; + + printf_inner(format_string, variables, span) +} + +/// Similar to `printf` but appends a newline to the format string. +#[proc_macro] +pub fn printfln(input: TokenStream) -> TokenStream { + let input = syn::parse_macro_input!(input as PrintfInput); + + let PrintfInput { + mut format_string, + variables, + span, + } = input; + + format_string.push_str("\\n"); + + printf_inner(format_string, variables, span) +} + struct PrintfInput { span: proc_macro2::Span, - string: String, - expressions: Vec, + format_string: String, + variables: Vec, } impl syn::parse::Parse for PrintfInput { @@ -364,72 +403,58 @@ impl syn::parse::Parse for PrintfInput { if input.is_empty() { return Ok(Self { span, - string: Default::default(), - expressions: Default::default(), + format_string: Default::default(), + variables: Default::default(), }); } Ok(Self { span, - string: input.parse::()?.value(), - expressions: { - let mut expressions = Vec::new(); + format_string: input.parse::()?.value(), + variables: { + let mut variables = Vec::new(); while !input.is_empty() { input.parse::()?; - expressions.push(input.parse()?); + variables.push(input.parse()?); } - expressions + variables }, }) } } -/// Print a formatted string with a newline using the debug printf extension. -/// -/// Examples: -/// -/// ```rust,ignore -/// printfln!("uv: %v2f", uv); -/// printfln!("pos.x: %f, pos.z: %f, int: %i", pos.x, pos.z, int); -/// ``` -/// -/// See for formatting rules. -#[proc_macro] -pub fn printfln(input: TokenStream) -> TokenStream { - let input = syn::parse_macro_input!(input as PrintfInput); - - let PrintfInput { - string, - expressions, - span, - } = input; - - let number_of_arguments = string.matches('%').count() - string.matches("%%").count() * 2; +fn printf_inner( + format_string: String, + variables: Vec, + span: proc_macro2::Span, +) -> TokenStream { + let number_of_arguments = + format_string.matches('%').count() - format_string.matches("%%").count() * 2; - if number_of_arguments != expressions.len() { + if number_of_arguments != variables.len() { return syn::Error::new( span, &format!( - "{} % arguments were found, but {} expressions were given", + "{} % arguments were found, but {} variables were given", number_of_arguments, - expressions.len() + variables.len() ), ) .to_compile_error() .into(); } - let mut input_string = String::new(); - let mut registers = Vec::new(); + let mut variable_idents = String::new(); + let mut input_registers = Vec::new(); let mut op_loads = Vec::new(); - for (i, expression) in expressions.into_iter().enumerate() { + for (i, variable) in variables.into_iter().enumerate() { let ident = quote::format_ident!("_{}", i); - input_string.push_str(&format!(" %{}", ident)); + variable_idents.push_str(&format!("%{} ", ident)); - registers.push(quote::quote! { - #ident = in(reg) &#expression, + input_registers.push(quote::quote! { + #ident = in(reg) &{#variable}, }); let op_load = format!("%{ident} = OpLoad _ {{{ident}}}", ident = ident); @@ -439,10 +464,12 @@ pub fn printfln(input: TokenStream) -> TokenStream { }); } - let registers = registers.into_iter().collect::(); + let input_registers = input_registers + .into_iter() + .collect::(); let op_loads = op_loads.into_iter().collect::(); - let op_string = format!("%string = OpString \"{}\\n\"", string); + let op_string = format!("%string = OpString \"{}\"", format_string); let output = quote::quote! { asm!( @@ -450,8 +477,8 @@ pub fn printfln(input: TokenStream) -> TokenStream { #op_string, "%debug_printf = OpExtInstImport \"NonSemantic.DebugPrintf\"", #op_loads - concat!("%result = OpExtInst %void %debug_printf 1 %string", #input_string), - #registers + concat!("%result = OpExtInst %void %debug_printf 1 %string ", #variable_idents), + #input_registers ) }; From a6c29fecfa26019f7e2920ab0dcce9c019bf0749 Mon Sep 17 00:00:00 2001 From: Ashley Ruglys Date: Sat, 16 Oct 2021 11:05:23 -0700 Subject: [PATCH 08/31] Tidy up a little --- crates/spirv-std/macros/src/lib.rs | 36 +++++++++--------------------- 1 file changed, 11 insertions(+), 25 deletions(-) diff --git a/crates/spirv-std/macros/src/lib.rs b/crates/spirv-std/macros/src/lib.rs index 66501c9c80..bcb6dea7b9 100644 --- a/crates/spirv-std/macros/src/lib.rs +++ b/crates/spirv-std/macros/src/lib.rs @@ -363,31 +363,15 @@ fn path_from_ident(ident: Ident) -> syn::Type { /// See for formatting rules. #[proc_macro] pub fn printf(input: TokenStream) -> TokenStream { - let input = syn::parse_macro_input!(input as PrintfInput); - - let PrintfInput { - format_string, - variables, - span, - } = input; - - printf_inner(format_string, variables, span) + printf_inner(syn::parse_macro_input!(input as PrintfInput)) } /// Similar to `printf` but appends a newline to the format string. #[proc_macro] pub fn printfln(input: TokenStream) -> TokenStream { - let input = syn::parse_macro_input!(input as PrintfInput); - - let PrintfInput { - mut format_string, - variables, - span, - } = input; - - format_string.push_str("\\n"); - - printf_inner(format_string, variables, span) + let mut input = syn::parse_macro_input!(input as PrintfInput); + input.format_string.push_str("\\n"); + printf_inner(input) } struct PrintfInput { @@ -423,11 +407,13 @@ impl syn::parse::Parse for PrintfInput { } } -fn printf_inner( - format_string: String, - variables: Vec, - span: proc_macro2::Span, -) -> TokenStream { +fn printf_inner(input: PrintfInput) -> TokenStream { + let PrintfInput { + format_string, + variables, + span, + } = input; + let number_of_arguments = format_string.matches('%').count() - format_string.matches("%%").count() * 2; From 29481bacd5d373508dace3d5092ed7b6e09258fc Mon Sep 17 00:00:00 2001 From: Ashley Ruglys Date: Sun, 17 Oct 2021 10:49:03 -0700 Subject: [PATCH 09/31] Add a compiletest --- tests/ui/arch/printf.rs | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 tests/ui/arch/printf.rs diff --git a/tests/ui/arch/printf.rs b/tests/ui/arch/printf.rs new file mode 100644 index 0000000000..6b340e6fc4 --- /dev/null +++ b/tests/ui/arch/printf.rs @@ -0,0 +1,23 @@ +// build-pass +// compile-flags: -Ctarget-feature=+ext:SPV_KHR_non_semantic_info + +use spirv_std::{macros::{printf, printfln}, glam::Vec2}; + +#[spirv(fragment)] +pub fn main() { + unsafe { + printf!(); + printfln!(); + printfln!("Hello World"); + } + + let vec = Vec2::new(1.52, 25.1); + + unsafe { + printfln!("%v2f", vec); + printfln!("%v2f", { vec * 2.0 }); + printfln!("%v2f", vec * 3.0); + printfln!("%% %v2f %%", vec * 4.0); + printfln!("%u %i %f 🐉", 11_u32, -11_i32, 11.0_f32); + } +} From 1f681246036bc9dac123f367f8c1e4b164e947a4 Mon Sep 17 00:00:00 2001 From: Ashley Ruglys Date: Sun, 17 Oct 2021 10:54:06 -0700 Subject: [PATCH 10/31] Run rustfmt --- tests/ui/arch/printf.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/tests/ui/arch/printf.rs b/tests/ui/arch/printf.rs index 6b340e6fc4..bbd3f3a981 100644 --- a/tests/ui/arch/printf.rs +++ b/tests/ui/arch/printf.rs @@ -1,7 +1,10 @@ // build-pass // compile-flags: -Ctarget-feature=+ext:SPV_KHR_non_semantic_info -use spirv_std::{macros::{printf, printfln}, glam::Vec2}; +use spirv_std::{ + glam::Vec2, + macros::{printf, printfln}, +}; #[spirv(fragment)] pub fn main() { From d095849a679f024e00e3027cec4fef9e1cb06dc6 Mon Sep 17 00:00:00 2001 From: Ashley Ruglys Date: Mon, 18 Oct 2021 03:54:50 -0700 Subject: [PATCH 11/31] Rename to debug_printf --- crates/spirv-std/macros/src/lib.rs | 24 ++++++++++++------------ tests/ui/arch/debug_printf.rs | 26 ++++++++++++++++++++++++++ tests/ui/arch/printf.rs | 26 -------------------------- 3 files changed, 38 insertions(+), 38 deletions(-) create mode 100644 tests/ui/arch/debug_printf.rs delete mode 100644 tests/ui/arch/printf.rs diff --git a/crates/spirv-std/macros/src/lib.rs b/crates/spirv-std/macros/src/lib.rs index bcb6dea7b9..4bd6ec5b88 100644 --- a/crates/spirv-std/macros/src/lib.rs +++ b/crates/spirv-std/macros/src/lib.rs @@ -356,31 +356,31 @@ fn path_from_ident(ident: Ident) -> syn::Type { /// Examples: /// /// ```rust,ignore -/// printfln!("uv: %v2f", uv); -/// printfln!("pos.x: %f, pos.z: %f, int: %i", pos.x, pos.z, int); +/// debug_printfln!("uv: %v2f", uv); +/// debug_printfln!("pos.x: %f, pos.z: %f, int: %i", pos.x, pos.z, int); /// ``` /// /// See for formatting rules. #[proc_macro] -pub fn printf(input: TokenStream) -> TokenStream { - printf_inner(syn::parse_macro_input!(input as PrintfInput)) +pub fn debug_printf(input: TokenStream) -> TokenStream { + debug_printf_inner(syn::parse_macro_input!(input as DebugPrintfInput)) } -/// Similar to `printf` but appends a newline to the format string. +/// Similar to `debug_printf` but appends a newline to the format string. #[proc_macro] -pub fn printfln(input: TokenStream) -> TokenStream { - let mut input = syn::parse_macro_input!(input as PrintfInput); +pub fn debug_printfln(input: TokenStream) -> TokenStream { + let mut input = syn::parse_macro_input!(input as DebugPrintfInput); input.format_string.push_str("\\n"); - printf_inner(input) + debug_printf_inner(input) } -struct PrintfInput { +struct DebugPrintfInput { span: proc_macro2::Span, format_string: String, variables: Vec, } -impl syn::parse::Parse for PrintfInput { +impl syn::parse::Parse for DebugPrintfInput { fn parse(input: syn::parse::ParseStream<'_>) -> syn::parse::Result { let span = input.span(); @@ -407,8 +407,8 @@ impl syn::parse::Parse for PrintfInput { } } -fn printf_inner(input: PrintfInput) -> TokenStream { - let PrintfInput { +fn debug_printf_inner(input: DebugPrintfInput) -> TokenStream { + let DebugPrintfInput { format_string, variables, span, diff --git a/tests/ui/arch/debug_printf.rs b/tests/ui/arch/debug_printf.rs new file mode 100644 index 0000000000..364111ee1d --- /dev/null +++ b/tests/ui/arch/debug_printf.rs @@ -0,0 +1,26 @@ +// build-pass +// compile-flags: -Ctarget-feature=+ext:SPV_KHR_non_semantic_info + +use spirv_std::{ + glam::Vec2, + macros::{debug_printf, debug_printfln}, +}; + +#[spirv(fragment)] +pub fn main() { + unsafe { + debug_printf!(); + debug_printfln!(); + debug_printfln!("Hello World"); + } + + let vec = Vec2::new(1.52, 25.1); + + unsafe { + debug_printfln!("%v2f", vec); + debug_printfln!("%v2f", { vec * 2.0 }); + debug_printfln!("%v2f", vec * 3.0); + debug_printfln!("%% %v2f %%", vec * 4.0); + debug_printfln!("%u %i %f 🐉", 11_u32, -11_i32, 11.0_f32); + } +} diff --git a/tests/ui/arch/printf.rs b/tests/ui/arch/printf.rs deleted file mode 100644 index bbd3f3a981..0000000000 --- a/tests/ui/arch/printf.rs +++ /dev/null @@ -1,26 +0,0 @@ -// build-pass -// compile-flags: -Ctarget-feature=+ext:SPV_KHR_non_semantic_info - -use spirv_std::{ - glam::Vec2, - macros::{printf, printfln}, -}; - -#[spirv(fragment)] -pub fn main() { - unsafe { - printf!(); - printfln!(); - printfln!("Hello World"); - } - - let vec = Vec2::new(1.52, 25.1); - - unsafe { - printfln!("%v2f", vec); - printfln!("%v2f", { vec * 2.0 }); - printfln!("%v2f", vec * 3.0); - printfln!("%% %v2f %%", vec * 4.0); - printfln!("%u %i %f 🐉", 11_u32, -11_i32, 11.0_f32); - } -} From 2f4f9c9162f8053155d850c07dfb9407f8f87e4d Mon Sep 17 00:00:00 2001 From: Ashley Ruglys Date: Mon, 18 Oct 2021 04:04:30 -0700 Subject: [PATCH 12/31] Parse variables using punctated --- crates/spirv-std/macros/src/lib.rs | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/crates/spirv-std/macros/src/lib.rs b/crates/spirv-std/macros/src/lib.rs index 4bd6ec5b88..f05f31fadc 100644 --- a/crates/spirv-std/macros/src/lib.rs +++ b/crates/spirv-std/macros/src/lib.rs @@ -392,17 +392,16 @@ impl syn::parse::Parse for DebugPrintfInput { }); } + let format_string = input.parse::()?; + if !input.is_empty() { + input.parse::()?; + } + let variables = syn::punctuated::Punctuated::::parse_terminated(input)?; + Ok(Self { span, - format_string: input.parse::()?.value(), - variables: { - let mut variables = Vec::new(); - while !input.is_empty() { - input.parse::()?; - variables.push(input.parse()?); - } - variables - }, + format_string: format_string.value(), + variables: variables.into_iter().collect(), }) } } From aecdf5bc6c3d7768b788842adc6ed9ff1aae2bcb Mon Sep 17 00:00:00 2001 From: Ashley Ruglys Date: Mon, 18 Oct 2021 04:11:59 -0700 Subject: [PATCH 13/31] Handle inner quotes --- crates/spirv-std/macros/src/lib.rs | 2 +- tests/ui/arch/debug_printf.rs | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/crates/spirv-std/macros/src/lib.rs b/crates/spirv-std/macros/src/lib.rs index f05f31fadc..b3f592bd73 100644 --- a/crates/spirv-std/macros/src/lib.rs +++ b/crates/spirv-std/macros/src/lib.rs @@ -454,7 +454,7 @@ fn debug_printf_inner(input: DebugPrintfInput) -> TokenStream { .collect::(); let op_loads = op_loads.into_iter().collect::(); - let op_string = format!("%string = OpString \"{}\"", format_string); + let op_string = format!("%string = OpString {:?}", format_string); let output = quote::quote! { asm!( diff --git a/tests/ui/arch/debug_printf.rs b/tests/ui/arch/debug_printf.rs index 364111ee1d..c1dbe2a7d6 100644 --- a/tests/ui/arch/debug_printf.rs +++ b/tests/ui/arch/debug_printf.rs @@ -12,6 +12,8 @@ pub fn main() { debug_printf!(); debug_printfln!(); debug_printfln!("Hello World"); + debug_printfln!("Hello World",); + debug_printfln!(r#"Hello "World""#); } let vec = Vec2::new(1.52, 25.1); From 564165f5123c41c52290628ad0d54f0603501fa3 Mon Sep 17 00:00:00 2001 From: Ashley Ruglys Date: Mon, 18 Oct 2021 04:20:27 -0700 Subject: [PATCH 14/31] Add tests for function and method calls --- tests/ui/arch/debug_printf.rs | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/tests/ui/arch/debug_printf.rs b/tests/ui/arch/debug_printf.rs index c1dbe2a7d6..fa5f5a6ef7 100644 --- a/tests/ui/arch/debug_printf.rs +++ b/tests/ui/arch/debug_printf.rs @@ -6,6 +6,21 @@ use spirv_std::{ macros::{debug_printf, debug_printfln}, }; + +fn func(a: f32, b: f32) -> f32 { + a * b + 1.0 +} + +struct Struct { + a: f32 +} + +impl Struct { + fn method(&self, b: f32, c: f32) -> f32 { + self.a * b + c + } +} + #[spirv(fragment)] pub fn main() { unsafe { @@ -24,5 +39,7 @@ pub fn main() { debug_printfln!("%v2f", vec * 3.0); debug_printfln!("%% %v2f %%", vec * 4.0); debug_printfln!("%u %i %f 🐉", 11_u32, -11_i32, 11.0_f32); + debug_printfln!("%f", func(33.0, 44.0)); + debug_printfln!("%f", Struct { a: 33.0 }.method(44.0, 55.0)); } } From fb6f66cc8d81d04a630caec2de8882c6011571f0 Mon Sep 17 00:00:00 2001 From: Ashley Ruglys Date: Mon, 18 Oct 2021 04:30:28 -0700 Subject: [PATCH 15/31] Escape only quote marks --- crates/spirv-std/macros/src/lib.rs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/crates/spirv-std/macros/src/lib.rs b/crates/spirv-std/macros/src/lib.rs index b3f592bd73..c01426ff8d 100644 --- a/crates/spirv-std/macros/src/lib.rs +++ b/crates/spirv-std/macros/src/lib.rs @@ -408,7 +408,7 @@ impl syn::parse::Parse for DebugPrintfInput { fn debug_printf_inner(input: DebugPrintfInput) -> TokenStream { let DebugPrintfInput { - format_string, + mut format_string, variables, span, } = input; @@ -454,7 +454,11 @@ fn debug_printf_inner(input: DebugPrintfInput) -> TokenStream { .collect::(); let op_loads = op_loads.into_iter().collect::(); - let op_string = format!("%string = OpString {:?}", format_string); + // Escape any inner quote marks. We can't use something like `String::escape_debug` + // as this escapes the newlines too. + format_string = format_string.replace('"', r#"\""#); + + let op_string = format!("%string = OpString \"{}\"", format_string); let output = quote::quote! { asm!( From 0f0d13d40a7f0d71f175b125935f6036fa99fd39 Mon Sep 17 00:00:00 2001 From: Ashley Date: Mon, 18 Oct 2021 13:39:24 +0200 Subject: [PATCH 16/31] Run rustfmt --- crates/spirv-std/macros/src/lib.rs | 3 ++- tests/ui/arch/debug_printf.rs | 3 +-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/crates/spirv-std/macros/src/lib.rs b/crates/spirv-std/macros/src/lib.rs index c01426ff8d..97a2ff365a 100644 --- a/crates/spirv-std/macros/src/lib.rs +++ b/crates/spirv-std/macros/src/lib.rs @@ -396,7 +396,8 @@ impl syn::parse::Parse for DebugPrintfInput { if !input.is_empty() { input.parse::()?; } - let variables = syn::punctuated::Punctuated::::parse_terminated(input)?; + let variables = + syn::punctuated::Punctuated::::parse_terminated(input)?; Ok(Self { span, diff --git a/tests/ui/arch/debug_printf.rs b/tests/ui/arch/debug_printf.rs index fa5f5a6ef7..425201688c 100644 --- a/tests/ui/arch/debug_printf.rs +++ b/tests/ui/arch/debug_printf.rs @@ -6,13 +6,12 @@ use spirv_std::{ macros::{debug_printf, debug_printfln}, }; - fn func(a: f32, b: f32) -> f32 { a * b + 1.0 } struct Struct { - a: f32 + a: f32, } impl Struct { From b545f6bf8778092e57b0682ce3dbd22b1c888f18 Mon Sep 17 00:00:00 2001 From: Ashley Ruglys Date: Tue, 19 Oct 2021 01:10:50 -0700 Subject: [PATCH 17/31] Use a regex to parse types from the format string and assert them with functions --- Cargo.lock | 1 + crates/spirv-std/macros/Cargo.toml | 1 + crates/spirv-std/macros/src/lib.rs | 44 ++++++++++++++++++++++++++++-- crates/spirv-std/src/lib.rs | 10 +++++++ tests/ui/arch/debug_printf.rs | 8 ++++-- 5 files changed, 59 insertions(+), 5 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 679cbd8625..91efcffe9a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2259,6 +2259,7 @@ dependencies = [ "heck", "proc-macro2", "quote", + "regex", "spirv-types", "syn", ] diff --git a/crates/spirv-std/macros/Cargo.toml b/crates/spirv-std/macros/Cargo.toml index 5338df7e02..cfd91478bb 100644 --- a/crates/spirv-std/macros/Cargo.toml +++ b/crates/spirv-std/macros/Cargo.toml @@ -16,3 +16,4 @@ heck = "0.3.2" proc-macro2 = "1.0.24" quote = "1.0.8" syn = { version = "1.0.58", features=["full"] } +regex = "1.5.4" diff --git a/crates/spirv-std/macros/src/lib.rs b/crates/spirv-std/macros/src/lib.rs index 97a2ff365a..f3347e33bf 100644 --- a/crates/spirv-std/macros/src/lib.rs +++ b/crates/spirv-std/macros/src/lib.rs @@ -430,17 +430,57 @@ fn debug_printf_inner(input: DebugPrintfInput) -> TokenStream { .into(); } + let specifiers = "d|i|o|u|x|X|a|A|e|E|f|F|g|G|ul|lu|lx"; + + let regex = regex::Regex::new(&format!(r"%\d*\.?\d*(v(2|3|4)({specifiers})|{specifiers})", specifiers=specifiers)).unwrap(); + + fn map_specifier_to_type(specifier: &str) -> proc_macro2::TokenStream { + match specifier { + "d" => quote::quote! { i32 }, + "i" => quote::quote! { i32 }, + "o" => quote::quote! { u32 }, + "u" => quote::quote! { u32 }, + "x" => quote::quote! { u32 }, + "X" => quote::quote! { u32 }, + "a" => quote::quote! { f32 }, + "A" => quote::quote! { f32 }, + "e" => quote::quote! { f32 }, + "E" => quote::quote! { f32 }, + "f" => quote::quote! { f32 }, + "F" => quote::quote! { f32 }, + "g" => quote::quote! { f32 }, + "G" => quote::quote! { f32 }, + "ul" => quote::quote! { u64 }, + "lu" => quote::quote! { u64 }, + "lx" => quote::quote! { u64 }, + _ => unreachable!() + } + } + + let assert_fns = regex.captures_iter(&format_string).map(|captures| { + let specifier = &captures[1][0..1]; + + if specifier == "v" { + let count = &captures[2].parse::().unwrap(); + let ty = map_specifier_to_type(&captures[3][0..1]); + quote::quote! { spirv_std::debug_printf_assert_is_vector::<#ty, _, #count> } + } else { + let ty = map_specifier_to_type(specifier); + quote::quote! { spirv_std::debug_printf_assert_is_type::<#ty> } + } + }); + let mut variable_idents = String::new(); let mut input_registers = Vec::new(); let mut op_loads = Vec::new(); - for (i, variable) in variables.into_iter().enumerate() { + for (i, (variable, assert_fn)) in variables.into_iter().zip(assert_fns).enumerate() { let ident = quote::format_ident!("_{}", i); variable_idents.push_str(&format!("%{} ", ident)); input_registers.push(quote::quote! { - #ident = in(reg) &{#variable}, + #ident = in(reg) &#assert_fn(#variable), }); let op_load = format!("%{ident} = OpLoad _ {{{ident}}}", ident = ident); diff --git a/crates/spirv-std/src/lib.rs b/crates/spirv-std/src/lib.rs index fb65ba3656..a795b297c7 100644 --- a/crates/spirv-std/src/lib.rs +++ b/crates/spirv-std/src/lib.rs @@ -130,3 +130,13 @@ extern "C" fn rust_eh_personality() {} #[doc(hidden)] /// [spirv_types] pub fn workaround_rustdoc_ice_84738() {} + +#[doc(hidden)] +pub fn debug_printf_assert_is_type(ty: T) -> T { + ty +} + +#[doc(hidden)] +pub fn debug_printf_assert_is_vector, const SIZE: usize>(vec: V) -> V { + vec +} diff --git a/tests/ui/arch/debug_printf.rs b/tests/ui/arch/debug_printf.rs index 425201688c..abd02bba81 100644 --- a/tests/ui/arch/debug_printf.rs +++ b/tests/ui/arch/debug_printf.rs @@ -2,7 +2,7 @@ // compile-flags: -Ctarget-feature=+ext:SPV_KHR_non_semantic_info use spirv_std::{ - glam::Vec2, + glam::{Vec2, Vec3, Vec4, UVec2, IVec2}, macros::{debug_printf, debug_printfln}, }; @@ -34,11 +34,13 @@ pub fn main() { unsafe { debug_printfln!("%v2f", vec); - debug_printfln!("%v2f", { vec * 2.0 }); - debug_printfln!("%v2f", vec * 3.0); + debug_printfln!("%1v2f", { vec * 2.0 }); + debug_printfln!("%1.2v2f", vec * 3.0); debug_printfln!("%% %v2f %%", vec * 4.0); debug_printfln!("%u %i %f 🐉", 11_u32, -11_i32, 11.0_f32); debug_printfln!("%f", func(33.0, 44.0)); debug_printfln!("%f", Struct { a: 33.0 }.method(44.0, 55.0)); + debug_printfln!("%v3f %v4f", Vec3::new(1.0, 1.0, 1.0), Vec4::splat(5.0)); + debug_printfln!("%v2u %v2i", UVec2::new(1, 1), IVec2::splat(-5)); } } From 42978abea12df546551d5b02038b669aab7c637a Mon Sep 17 00:00:00 2001 From: Ashley Ruglys Date: Wed, 20 Oct 2021 03:52:41 -0700 Subject: [PATCH 18/31] Add extra tests, escape the string correctly while keeping printfln newlines --- crates/spirv-std/macros/src/lib.rs | 20 +++++++++----------- tests/ui/arch/debug_printf.rs | 5 +++++ 2 files changed, 14 insertions(+), 11 deletions(-) diff --git a/crates/spirv-std/macros/src/lib.rs b/crates/spirv-std/macros/src/lib.rs index 97a2ff365a..03f73ccc41 100644 --- a/crates/spirv-std/macros/src/lib.rs +++ b/crates/spirv-std/macros/src/lib.rs @@ -363,15 +363,13 @@ fn path_from_ident(ident: Ident) -> syn::Type { /// See for formatting rules. #[proc_macro] pub fn debug_printf(input: TokenStream) -> TokenStream { - debug_printf_inner(syn::parse_macro_input!(input as DebugPrintfInput)) + debug_printf_inner(syn::parse_macro_input!(input as DebugPrintfInput), false) } /// Similar to `debug_printf` but appends a newline to the format string. #[proc_macro] pub fn debug_printfln(input: TokenStream) -> TokenStream { - let mut input = syn::parse_macro_input!(input as DebugPrintfInput); - input.format_string.push_str("\\n"); - debug_printf_inner(input) + debug_printf_inner(syn::parse_macro_input!(input as DebugPrintfInput), true) } struct DebugPrintfInput { @@ -407,9 +405,9 @@ impl syn::parse::Parse for DebugPrintfInput { } } -fn debug_printf_inner(input: DebugPrintfInput) -> TokenStream { +fn debug_printf_inner(input: DebugPrintfInput, append_newline: bool) -> TokenStream { let DebugPrintfInput { - mut format_string, + format_string, variables, span, } = input; @@ -455,11 +453,11 @@ fn debug_printf_inner(input: DebugPrintfInput) -> TokenStream { .collect::(); let op_loads = op_loads.into_iter().collect::(); - // Escape any inner quote marks. We can't use something like `String::escape_debug` - // as this escapes the newlines too. - format_string = format_string.replace('"', r#"\""#); - - let op_string = format!("%string = OpString \"{}\"", format_string); + let op_string = format!( + "%string = OpString \"{}{}\"", + format_string.escape_debug(), + if append_newline { "\\n" } else { "" } + ); let output = quote::quote! { asm!( diff --git a/tests/ui/arch/debug_printf.rs b/tests/ui/arch/debug_printf.rs index 425201688c..e83800e8f7 100644 --- a/tests/ui/arch/debug_printf.rs +++ b/tests/ui/arch/debug_printf.rs @@ -28,6 +28,11 @@ pub fn main() { debug_printfln!("Hello World"); debug_printfln!("Hello World",); debug_printfln!(r#"Hello "World""#); + debug_printfln!( + r#"Hello "World" +"# + ); + debug_printfln!("Hello \"World\"\n\n"); } let vec = Vec2::new(1.52, 25.1); From a0f461537a469a0a1adc628fed41bd4e5b394b0e Mon Sep 17 00:00:00 2001 From: Ashley Ruglys Date: Wed, 20 Oct 2021 08:55:01 -0700 Subject: [PATCH 19/31] Use the string debug impl after all --- crates/spirv-std/macros/src/lib.rs | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/crates/spirv-std/macros/src/lib.rs b/crates/spirv-std/macros/src/lib.rs index 03f73ccc41..c94c838bb0 100644 --- a/crates/spirv-std/macros/src/lib.rs +++ b/crates/spirv-std/macros/src/lib.rs @@ -363,13 +363,15 @@ fn path_from_ident(ident: Ident) -> syn::Type { /// See for formatting rules. #[proc_macro] pub fn debug_printf(input: TokenStream) -> TokenStream { - debug_printf_inner(syn::parse_macro_input!(input as DebugPrintfInput), false) + debug_printf_inner(syn::parse_macro_input!(input as DebugPrintfInput)) } /// Similar to `debug_printf` but appends a newline to the format string. #[proc_macro] pub fn debug_printfln(input: TokenStream) -> TokenStream { - debug_printf_inner(syn::parse_macro_input!(input as DebugPrintfInput), true) + let mut input = syn::parse_macro_input!(input as DebugPrintfInput); + input.format_string.push_str("\n"); + debug_printf_inner(input) } struct DebugPrintfInput { @@ -405,7 +407,7 @@ impl syn::parse::Parse for DebugPrintfInput { } } -fn debug_printf_inner(input: DebugPrintfInput, append_newline: bool) -> TokenStream { +fn debug_printf_inner(input: DebugPrintfInput) -> TokenStream { let DebugPrintfInput { format_string, variables, @@ -453,11 +455,7 @@ fn debug_printf_inner(input: DebugPrintfInput, append_newline: bool) -> TokenStr .collect::(); let op_loads = op_loads.into_iter().collect::(); - let op_string = format!( - "%string = OpString \"{}{}\"", - format_string.escape_debug(), - if append_newline { "\\n" } else { "" } - ); + let op_string = format!("%string = OpString {:?}", format_string); let output = quote::quote! { asm!( From c59e3cec70534ee0b801bf14ab03b9d9ce1a349f Mon Sep 17 00:00:00 2001 From: Ashley Ruglys Date: Thu, 21 Oct 2021 01:09:41 -0700 Subject: [PATCH 20/31] Cargo fmt --- crates/spirv-std/macros/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/spirv-std/macros/src/lib.rs b/crates/spirv-std/macros/src/lib.rs index c94c838bb0..dad0a6c4ee 100644 --- a/crates/spirv-std/macros/src/lib.rs +++ b/crates/spirv-std/macros/src/lib.rs @@ -370,7 +370,7 @@ pub fn debug_printf(input: TokenStream) -> TokenStream { #[proc_macro] pub fn debug_printfln(input: TokenStream) -> TokenStream { let mut input = syn::parse_macro_input!(input as DebugPrintfInput); - input.format_string.push_str("\n"); + input.format_string.push('\n'); debug_printf_inner(input) } From ffc7505a8367475c93c7d4c4c47288f89ce2f8a8 Mon Sep 17 00:00:00 2001 From: Ashley Ruglys Date: Thu, 21 Oct 2021 01:49:24 -0700 Subject: [PATCH 21/31] Cargo fmt again --- crates/spirv-std/macros/src/lib.rs | 8 ++++++-- crates/spirv-std/src/lib.rs | 8 +++++++- 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/crates/spirv-std/macros/src/lib.rs b/crates/spirv-std/macros/src/lib.rs index 02954e50e2..e4b032c00b 100644 --- a/crates/spirv-std/macros/src/lib.rs +++ b/crates/spirv-std/macros/src/lib.rs @@ -432,7 +432,11 @@ fn debug_printf_inner(input: DebugPrintfInput) -> TokenStream { let specifiers = "d|i|o|u|x|X|a|A|e|E|f|F|g|G|ul|lu|lx"; - let regex = regex::Regex::new(&format!(r"%\d*\.?\d*(v(2|3|4)({specifiers})|{specifiers})", specifiers=specifiers)).unwrap(); + let regex = regex::Regex::new(&format!( + r"%\d*\.?\d*(v(2|3|4)({specifiers})|{specifiers})", + specifiers = specifiers + )) + .unwrap(); fn map_specifier_to_type(specifier: &str) -> proc_macro2::TokenStream { match specifier { @@ -453,7 +457,7 @@ fn debug_printf_inner(input: DebugPrintfInput) -> TokenStream { "ul" => quote::quote! { u64 }, "lu" => quote::quote! { u64 }, "lx" => quote::quote! { u64 }, - _ => unreachable!() + _ => unreachable!(), } } diff --git a/crates/spirv-std/src/lib.rs b/crates/spirv-std/src/lib.rs index a795b297c7..ae38c54ef8 100644 --- a/crates/spirv-std/src/lib.rs +++ b/crates/spirv-std/src/lib.rs @@ -137,6 +137,12 @@ pub fn debug_printf_assert_is_type(ty: T) -> T { } #[doc(hidden)] -pub fn debug_printf_assert_is_vector, const SIZE: usize>(vec: V) -> V { +pub fn debug_printf_assert_is_vector< + TY: crate::scalar::Scalar, + V: crate::vector::Vector, + const SIZE: usize, +>( + vec: V, +) -> V { vec } From 81d4103f9c7c7fa488befcd779f9447666a547e3 Mon Sep 17 00:00:00 2001 From: Ashley Ruglys Date: Thu, 21 Oct 2021 01:53:41 -0700 Subject: [PATCH 22/31] fmt compiletest --- tests/ui/arch/debug_printf.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/ui/arch/debug_printf.rs b/tests/ui/arch/debug_printf.rs index eb6dc6f943..b3c241a129 100644 --- a/tests/ui/arch/debug_printf.rs +++ b/tests/ui/arch/debug_printf.rs @@ -2,7 +2,7 @@ // compile-flags: -Ctarget-feature=+ext:SPV_KHR_non_semantic_info use spirv_std::{ - glam::{Vec2, Vec3, Vec4, UVec2, IVec2}, + glam::{IVec2, UVec2, Vec2, Vec3, Vec4}, macros::{debug_printf, debug_printfln}, }; From 81ad59e406b61aa206bc846eb0fb639ecc033e15 Mon Sep 17 00:00:00 2001 From: Ashley Ruglys Date: Thu, 21 Oct 2021 04:48:15 -0700 Subject: [PATCH 23/31] Merge match branches --- crates/spirv-std/macros/src/lib.rs | 21 ++++----------------- 1 file changed, 4 insertions(+), 17 deletions(-) diff --git a/crates/spirv-std/macros/src/lib.rs b/crates/spirv-std/macros/src/lib.rs index e4b032c00b..406f4559fc 100644 --- a/crates/spirv-std/macros/src/lib.rs +++ b/crates/spirv-std/macros/src/lib.rs @@ -440,23 +440,10 @@ fn debug_printf_inner(input: DebugPrintfInput) -> TokenStream { fn map_specifier_to_type(specifier: &str) -> proc_macro2::TokenStream { match specifier { - "d" => quote::quote! { i32 }, - "i" => quote::quote! { i32 }, - "o" => quote::quote! { u32 }, - "u" => quote::quote! { u32 }, - "x" => quote::quote! { u32 }, - "X" => quote::quote! { u32 }, - "a" => quote::quote! { f32 }, - "A" => quote::quote! { f32 }, - "e" => quote::quote! { f32 }, - "E" => quote::quote! { f32 }, - "f" => quote::quote! { f32 }, - "F" => quote::quote! { f32 }, - "g" => quote::quote! { f32 }, - "G" => quote::quote! { f32 }, - "ul" => quote::quote! { u64 }, - "lu" => quote::quote! { u64 }, - "lx" => quote::quote! { u64 }, + "d" | "i" => quote::quote! { i32 }, + "o" | "u" | "x" | "X" => quote::quote! { u32 }, + "a" | "A" | "e" | "E" | "f" | "F" | "g" | "G" => quote::quote! { f32 }, + "ul" | "lu" | "lx" => quote::quote! { u64 }, _ => unreachable!(), } } From 602b6910b01bbb9069180cb57fdfdf5aae8ea151 Mon Sep 17 00:00:00 2001 From: Ashley Ruglys Date: Thu, 21 Oct 2021 05:15:20 -0700 Subject: [PATCH 24/31] Improved argument checking --- crates/spirv-std/macros/src/lib.rs | 21 ++++--- tests/ui/arch/debug_printf_type_checking.rs | 18 ++++++ .../ui/arch/debug_printf_type_checking.stderr | 59 +++++++++++++++++++ 3 files changed, 87 insertions(+), 11 deletions(-) create mode 100644 tests/ui/arch/debug_printf_type_checking.rs create mode 100644 tests/ui/arch/debug_printf_type_checking.stderr diff --git a/crates/spirv-std/macros/src/lib.rs b/crates/spirv-std/macros/src/lib.rs index 406f4559fc..96c7192e3b 100644 --- a/crates/spirv-std/macros/src/lib.rs +++ b/crates/spirv-std/macros/src/lib.rs @@ -414,14 +414,21 @@ fn debug_printf_inner(input: DebugPrintfInput) -> TokenStream { span, } = input; - let number_of_arguments = - format_string.matches('%').count() - format_string.matches("%%").count() * 2; + let specifiers = "d|i|o|u|x|X|a|A|e|E|f|F|g|G|ul|lu|lx"; + + let regex = regex::Regex::new(&format!( + r"%\d*\.?\d*(v(2|3|4)({specifiers})|{specifiers})", + specifiers = specifiers + )) + .unwrap(); + + let number_of_arguments = regex.captures_iter(&format_string).count(); if number_of_arguments != variables.len() { return syn::Error::new( span, &format!( - "{} % arguments were found, but {} variables were given", + "{} valid % arguments were found, but {} variables were given", number_of_arguments, variables.len() ), @@ -430,14 +437,6 @@ fn debug_printf_inner(input: DebugPrintfInput) -> TokenStream { .into(); } - let specifiers = "d|i|o|u|x|X|a|A|e|E|f|F|g|G|ul|lu|lx"; - - let regex = regex::Regex::new(&format!( - r"%\d*\.?\d*(v(2|3|4)({specifiers})|{specifiers})", - specifiers = specifiers - )) - .unwrap(); - fn map_specifier_to_type(specifier: &str) -> proc_macro2::TokenStream { match specifier { "d" | "i" => quote::quote! { i32 }, diff --git a/tests/ui/arch/debug_printf_type_checking.rs b/tests/ui/arch/debug_printf_type_checking.rs new file mode 100644 index 0000000000..48be332f6f --- /dev/null +++ b/tests/ui/arch/debug_printf_type_checking.rs @@ -0,0 +1,18 @@ +// build-fail +// compile-flags: -Ctarget-feature=+ext:SPV_KHR_non_semantic_info + +use spirv_std::{ + macros::debug_printf, + glam::Vec2, +}; + +#[spirv(fragment)] +pub fn main() { + unsafe { + debug_printf!("%r", 11_i32); + debug_printf!("%f", 11_u32); + debug_printf!("%u", 11.0_f32); + debug_printf!("%v2f", 11.0); + debug_printf!("%f", Vec2::splat(33.3)); + } +} diff --git a/tests/ui/arch/debug_printf_type_checking.stderr b/tests/ui/arch/debug_printf_type_checking.stderr new file mode 100644 index 0000000000..8f7b46d92f --- /dev/null +++ b/tests/ui/arch/debug_printf_type_checking.stderr @@ -0,0 +1,59 @@ +error: 0 valid % arguments were found, but 1 variables were given + --> $DIR/debug_printf_type_checking.rs:12:23 + | +12 | debug_printf!("%r", 11_i32); + | ^^^^ + +error[E0308]: mismatched types + --> $DIR/debug_printf_type_checking.rs:13:29 + | +13 | debug_printf!("%f", 11_u32); + | ^^^^^^ expected `f32`, found `u32` + | +help: change the type of the numeric literal from `u32` to `f32` + | +13 | debug_printf!("%f", 11_f32); + | ~~~ + +error[E0308]: mismatched types + --> $DIR/debug_printf_type_checking.rs:14:29 + | +14 | debug_printf!("%u", 11.0_f32); + | ^^^^^^^^ expected `u32`, found `f32` + | +help: change the type of the numeric literal from `f32` to `u32` + | +14 | debug_printf!("%u", 11u32); + | ~~~ + +error[E0277]: the trait bound `{float}: Vector` is not satisfied + --> $DIR/debug_printf_type_checking.rs:15:31 + | +15 | debug_printf!("%v2f", 11.0); + | ----------------------^^^^-- + | | | + | | the trait `Vector` is not implemented for `{float}` + | required by a bound introduced by this call + | + = help: the following implementations were found: + > + > + > + > + and 13 others +note: required by a bound in `debug_printf_assert_is_vector` + --> C:/Users/Ashley/Desktop/rust-gpu/crates/spirv-std/src/lib.rs:142:8 + | +142 | V: crate::vector::Vector, + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `debug_printf_assert_is_vector` + +error[E0308]: mismatched types + --> $DIR/debug_printf_type_checking.rs:16:29 + | +16 | debug_printf!("%f", Vec2::splat(33.3)); + | ^^^^^^^^^^^^^^^^^ expected `f32`, found struct `Vec2` + +error: aborting due to 5 previous errors + +Some errors have detailed explanations: E0277, E0308. +For more information about an error, try `rustc --explain E0277`. From 8c76f59fbe72acae2ea2c783f125efedc3b8e9bd Mon Sep 17 00:00:00 2001 From: Ashley Ruglys Date: Thu, 21 Oct 2021 05:22:56 -0700 Subject: [PATCH 25/31] Filter out captures like %%f --- crates/spirv-std/macros/src/lib.rs | 35 ++++++++++++++++++------------ tests/ui/arch/debug_printf.rs | 1 + 2 files changed, 22 insertions(+), 14 deletions(-) diff --git a/crates/spirv-std/macros/src/lib.rs b/crates/spirv-std/macros/src/lib.rs index 96c7192e3b..84d6b783eb 100644 --- a/crates/spirv-std/macros/src/lib.rs +++ b/crates/spirv-std/macros/src/lib.rs @@ -417,12 +417,16 @@ fn debug_printf_inner(input: DebugPrintfInput) -> TokenStream { let specifiers = "d|i|o|u|x|X|a|A|e|E|f|F|g|G|ul|lu|lx"; let regex = regex::Regex::new(&format!( - r"%\d*\.?\d*(v(2|3|4)({specifiers})|{specifiers})", + r"(%+)\d*\.?\d*(v(2|3|4)({specifiers})|{specifiers})", specifiers = specifiers )) .unwrap(); - let number_of_arguments = regex.captures_iter(&format_string).count(); + let number_of_arguments = regex + .captures_iter(&format_string) + // Filter out captures with an even number of `%`s, as pairs of them are escaped. + .filter(|captures| captures[1].len() % 2 == 1) + .count(); if number_of_arguments != variables.len() { return syn::Error::new( @@ -447,18 +451,21 @@ fn debug_printf_inner(input: DebugPrintfInput) -> TokenStream { } } - let assert_fns = regex.captures_iter(&format_string).map(|captures| { - let specifier = &captures[1][0..1]; - - if specifier == "v" { - let count = &captures[2].parse::().unwrap(); - let ty = map_specifier_to_type(&captures[3][0..1]); - quote::quote! { spirv_std::debug_printf_assert_is_vector::<#ty, _, #count> } - } else { - let ty = map_specifier_to_type(specifier); - quote::quote! { spirv_std::debug_printf_assert_is_type::<#ty> } - } - }); + let assert_fns = regex + .captures_iter(&format_string) + .filter(|captures| captures[1].len() % 2 == 1) + .map(|captures| { + let specifier = &captures[2][0..1]; + + if specifier == "v" { + let count = &captures[3].parse::().unwrap(); + let ty = map_specifier_to_type(&captures[4][0..1]); + quote::quote! { spirv_std::debug_printf_assert_is_vector::<#ty, _, #count> } + } else { + let ty = map_specifier_to_type(specifier); + quote::quote! { spirv_std::debug_printf_assert_is_type::<#ty> } + } + }); let mut variable_idents = String::new(); let mut input_registers = Vec::new(); diff --git a/tests/ui/arch/debug_printf.rs b/tests/ui/arch/debug_printf.rs index b3c241a129..d296f12473 100644 --- a/tests/ui/arch/debug_printf.rs +++ b/tests/ui/arch/debug_printf.rs @@ -33,6 +33,7 @@ pub fn main() { "# ); debug_printfln!("Hello \"World\"\n\n"); + debug_printfln!("%%r %%f %%%%f %%%%%u", 77); } let vec = Vec2::new(1.52, 25.1); From 6fbde8e7666adb6cac9f78b9752db327991868bc Mon Sep 17 00:00:00 2001 From: Ashley Ruglys Date: Thu, 21 Oct 2021 08:46:37 -0700 Subject: [PATCH 26/31] Use a peekable character iterator to parse the format string into rust types --- Cargo.lock | 1 - crates/spirv-std/macros/Cargo.toml | 1 - crates/spirv-std/macros/src/lib.rs | 182 ++++++++++++++---- tests/ui/arch/debug_printf_type_checking.rs | 9 + .../ui/arch/debug_printf_type_checking.stderr | 80 ++++++-- 5 files changed, 220 insertions(+), 53 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 91efcffe9a..679cbd8625 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2259,7 +2259,6 @@ dependencies = [ "heck", "proc-macro2", "quote", - "regex", "spirv-types", "syn", ] diff --git a/crates/spirv-std/macros/Cargo.toml b/crates/spirv-std/macros/Cargo.toml index cfd91478bb..5338df7e02 100644 --- a/crates/spirv-std/macros/Cargo.toml +++ b/crates/spirv-std/macros/Cargo.toml @@ -16,4 +16,3 @@ heck = "0.3.2" proc-macro2 = "1.0.24" quote = "1.0.8" syn = { version = "1.0.58", features=["full"] } -regex = "1.5.4" diff --git a/crates/spirv-std/macros/src/lib.rs b/crates/spirv-std/macros/src/lib.rs index 84d6b783eb..72c0fe95ef 100644 --- a/crates/spirv-std/macros/src/lib.rs +++ b/crates/spirv-std/macros/src/lib.rs @@ -407,6 +407,20 @@ impl syn::parse::Parse for DebugPrintfInput { } } +fn parsing_error(message: &str, span: proc_macro2::Span) -> TokenStream { + syn::Error::new(span, message).to_compile_error().into() +} + +enum FormatType { + Scalar { + ty: proc_macro2::TokenStream, + }, + Vector { + ty: proc_macro2::TokenStream, + width: usize, + }, +} + fn debug_printf_inner(input: DebugPrintfInput) -> TokenStream { let DebugPrintfInput { format_string, @@ -414,26 +428,135 @@ fn debug_printf_inner(input: DebugPrintfInput) -> TokenStream { span, } = input; - let specifiers = "d|i|o|u|x|X|a|A|e|E|f|F|g|G|ul|lu|lx"; + fn map_specifier_to_type( + specifier: char, + chars: &mut std::iter::Peekable>, + ) -> Option { + Some(match specifier { + 'd' | 'i' => quote::quote! { i32 }, + 'o' | 'x' | 'X' => quote::quote! { u32 }, + 'a' | 'A' | 'e' | 'E' | 'f' | 'F' | 'g' | 'G' => quote::quote! { f32 }, + 'u' => { + if matches!(chars.peek(), Some('l')) { + chars.next(); + quote::quote! { u64 } + } else { + quote::quote! { u32 } + } + } + 'l' => { + if matches!(chars.peek(), Some('u' | 'x')) { + chars.next(); + quote::quote! { u64 } + } else { + return None; + } + } + _ => return None, + }) + } - let regex = regex::Regex::new(&format!( - r"(%+)\d*\.?\d*(v(2|3|4)({specifiers})|{specifiers})", - specifiers = specifiers - )) - .unwrap(); + let mut chars = format_string.chars().peekable(); + let mut format_arguments = Vec::new(); + + while let Some(ch) = chars.next() { + if ch == '%' { + match chars.next() { + None => return parsing_error("Unterminated format specifier", span), + Some('%') => {} + Some(mut ch) => { + let mut has_precision = false; + + while matches!(ch, '0'..='9') { + ch = + match chars.next() { + Some(ch) => ch, + None => return parsing_error( + "Unterminated format specifier: missing type after precision", + span, + ), + }; + + has_precision = true; + } - let number_of_arguments = regex - .captures_iter(&format_string) - // Filter out captures with an even number of `%`s, as pairs of them are escaped. - .filter(|captures| captures[1].len() % 2 == 1) - .count(); + if has_precision && ch == '.' { + ch = match chars.next() { + Some(ch) => ch, + None => { + return parsing_error( + "Unterminated format specifier: missing type after decimal point", + span, + ) + } + }; + + while matches!(ch, '0'..='9') { + ch = match chars.next() { + Some(ch) => ch, + None => { + return parsing_error("Unterminated format specifier: missing type after fraction precision", span) + } + }; + } + } - if number_of_arguments != variables.len() { + if ch == 'v' { + let width = match chars.next() { + Some('2') => 2, + Some('3') => 3, + Some('4') => 4, + Some(ch) => { + return parsing_error( + &format!("Invalid width for vector: {}", ch), + span, + ) + } + None => { + return parsing_error("Missing vector dimensions specifier", span) + } + }; + + ch = match chars.next() { + Some(ch) => ch, + None => return parsing_error("Missing vector type specifier", span), + }; + + let ty = match map_specifier_to_type(ch, &mut chars) { + Some(ty) => ty, + _ => { + return parsing_error( + &format!("Unrecognised vector type specifier: '{}'", ch), + span, + ) + } + }; + + format_arguments.push(FormatType::Vector { ty, width }); + } else { + let ty = match map_specifier_to_type(ch, &mut chars) { + Some(ty) => ty, + _ => { + return parsing_error( + &format!("Unrecognised format specifier: '{}'", ch), + span, + ) + } + }; + + format_arguments.push(FormatType::Scalar { ty }); + } + } + } + } + } + + if format_arguments.len() != variables.len() { return syn::Error::new( span, &format!( - "{} valid % arguments were found, but {} variables were given", - number_of_arguments, + "{} % arguments were found, but {} variables were given", + format_arguments.len(), variables.len() ), ) @@ -441,31 +564,14 @@ fn debug_printf_inner(input: DebugPrintfInput) -> TokenStream { .into(); } - fn map_specifier_to_type(specifier: &str) -> proc_macro2::TokenStream { - match specifier { - "d" | "i" => quote::quote! { i32 }, - "o" | "u" | "x" | "X" => quote::quote! { u32 }, - "a" | "A" | "e" | "E" | "f" | "F" | "g" | "G" => quote::quote! { f32 }, - "ul" | "lu" | "lx" => quote::quote! { u64 }, - _ => unreachable!(), + let assert_fns = format_arguments.iter().map(|ty| match ty { + FormatType::Scalar { ty } => { + quote::quote! { spirv_std::debug_printf_assert_is_type::<#ty> } } - } - - let assert_fns = regex - .captures_iter(&format_string) - .filter(|captures| captures[1].len() % 2 == 1) - .map(|captures| { - let specifier = &captures[2][0..1]; - - if specifier == "v" { - let count = &captures[3].parse::().unwrap(); - let ty = map_specifier_to_type(&captures[4][0..1]); - quote::quote! { spirv_std::debug_printf_assert_is_vector::<#ty, _, #count> } - } else { - let ty = map_specifier_to_type(specifier); - quote::quote! { spirv_std::debug_printf_assert_is_type::<#ty> } - } - }); + FormatType::Vector { ty, width } => { + quote::quote! { spirv_std::debug_printf_assert_is_vector::<#ty, _, #width> } + } + }); let mut variable_idents = String::new(); let mut input_registers = Vec::new(); diff --git a/tests/ui/arch/debug_printf_type_checking.rs b/tests/ui/arch/debug_printf_type_checking.rs index 48be332f6f..878327e21f 100644 --- a/tests/ui/arch/debug_printf_type_checking.rs +++ b/tests/ui/arch/debug_printf_type_checking.rs @@ -9,6 +9,15 @@ use spirv_std::{ #[spirv(fragment)] pub fn main() { unsafe { + debug_printf!("%1"); + debug_printf!("%1."); + debug_printf!("%."); + debug_printf!("%.1"); + debug_printf!("%1.1"); + debug_printf!("%1.1v"); + debug_printf!("%1.1v5"); + debug_printf!("%1.1v2"); + debug_printf!("%1.1v2r"); debug_printf!("%r", 11_i32); debug_printf!("%f", 11_u32); debug_printf!("%u", 11.0_f32); diff --git a/tests/ui/arch/debug_printf_type_checking.stderr b/tests/ui/arch/debug_printf_type_checking.stderr index 8f7b46d92f..58fc2bc8b7 100644 --- a/tests/ui/arch/debug_printf_type_checking.stderr +++ b/tests/ui/arch/debug_printf_type_checking.stderr @@ -1,35 +1,89 @@ -error: 0 valid % arguments were found, but 1 variables were given +error: Unterminated format specifier: missing type after precision --> $DIR/debug_printf_type_checking.rs:12:23 | -12 | debug_printf!("%r", 11_i32); +12 | debug_printf!("%1"); + | ^^^^ + +error: Unterminated format specifier: missing type after decimal point + --> $DIR/debug_printf_type_checking.rs:13:23 + | +13 | debug_printf!("%1."); + | ^^^^^ + +error: Unrecognised format specifier: '.' + --> $DIR/debug_printf_type_checking.rs:14:23 + | +14 | debug_printf!("%."); + | ^^^^ + +error: Unrecognised format specifier: '.' + --> $DIR/debug_printf_type_checking.rs:15:23 + | +15 | debug_printf!("%.1"); + | ^^^^^ + +error: Unterminated format specifier: missing type after fraction precision + --> $DIR/debug_printf_type_checking.rs:16:23 + | +16 | debug_printf!("%1.1"); + | ^^^^^^ + +error: Missing vector dimensions specifier + --> $DIR/debug_printf_type_checking.rs:17:23 + | +17 | debug_printf!("%1.1v"); + | ^^^^^^^ + +error: Invalid width for vector: 5 + --> $DIR/debug_printf_type_checking.rs:18:23 + | +18 | debug_printf!("%1.1v5"); + | ^^^^^^^^ + +error: Missing vector type specifier + --> $DIR/debug_printf_type_checking.rs:19:23 + | +19 | debug_printf!("%1.1v2"); + | ^^^^^^^^ + +error: Unrecognised vector type specifier: 'r' + --> $DIR/debug_printf_type_checking.rs:20:23 + | +20 | debug_printf!("%1.1v2r"); + | ^^^^^^^^^ + +error: Unrecognised format specifier: 'r' + --> $DIR/debug_printf_type_checking.rs:21:23 + | +21 | debug_printf!("%r", 11_i32); | ^^^^ error[E0308]: mismatched types - --> $DIR/debug_printf_type_checking.rs:13:29 + --> $DIR/debug_printf_type_checking.rs:22:29 | -13 | debug_printf!("%f", 11_u32); +22 | debug_printf!("%f", 11_u32); | ^^^^^^ expected `f32`, found `u32` | help: change the type of the numeric literal from `u32` to `f32` | -13 | debug_printf!("%f", 11_f32); +22 | debug_printf!("%f", 11_f32); | ~~~ error[E0308]: mismatched types - --> $DIR/debug_printf_type_checking.rs:14:29 + --> $DIR/debug_printf_type_checking.rs:23:29 | -14 | debug_printf!("%u", 11.0_f32); +23 | debug_printf!("%u", 11.0_f32); | ^^^^^^^^ expected `u32`, found `f32` | help: change the type of the numeric literal from `f32` to `u32` | -14 | debug_printf!("%u", 11u32); +23 | debug_printf!("%u", 11u32); | ~~~ error[E0277]: the trait bound `{float}: Vector` is not satisfied - --> $DIR/debug_printf_type_checking.rs:15:31 + --> $DIR/debug_printf_type_checking.rs:24:31 | -15 | debug_printf!("%v2f", 11.0); +24 | debug_printf!("%v2f", 11.0); | ----------------------^^^^-- | | | | | the trait `Vector` is not implemented for `{float}` @@ -48,12 +102,12 @@ note: required by a bound in `debug_printf_assert_is_vector` | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `debug_printf_assert_is_vector` error[E0308]: mismatched types - --> $DIR/debug_printf_type_checking.rs:16:29 + --> $DIR/debug_printf_type_checking.rs:25:29 | -16 | debug_printf!("%f", Vec2::splat(33.3)); +25 | debug_printf!("%f", Vec2::splat(33.3)); | ^^^^^^^^^^^^^^^^^ expected `f32`, found struct `Vec2` -error: aborting due to 5 previous errors +error: aborting due to 14 previous errors Some errors have detailed explanations: E0277, E0308. For more information about an error, try `rustc --explain E0277`. From 2836b3ef8fbc70aab3e17d9feac827ab91edc2ad Mon Sep 17 00:00:00 2001 From: Ashley Ruglys Date: Thu, 21 Oct 2021 09:00:02 -0700 Subject: [PATCH 27/31] continue on %% to unindent the code --- crates/spirv-std/macros/src/lib.rs | 159 ++++++++++++++--------------- 1 file changed, 78 insertions(+), 81 deletions(-) diff --git a/crates/spirv-std/macros/src/lib.rs b/crates/spirv-std/macros/src/lib.rs index 72c0fe95ef..f3ffdcbe28 100644 --- a/crates/spirv-std/macros/src/lib.rs +++ b/crates/spirv-std/macros/src/lib.rs @@ -459,95 +459,92 @@ fn debug_printf_inner(input: DebugPrintfInput) -> TokenStream { let mut chars = format_string.chars().peekable(); let mut format_arguments = Vec::new(); - while let Some(ch) = chars.next() { + while let Some(mut ch) = chars.next() { if ch == '%' { - match chars.next() { + ch = match chars.next() { + Some('%') => continue, None => return parsing_error("Unterminated format specifier", span), - Some('%') => {} - Some(mut ch) => { - let mut has_precision = false; - - while matches!(ch, '0'..='9') { - ch = - match chars.next() { - Some(ch) => ch, - None => return parsing_error( - "Unterminated format specifier: missing type after precision", - span, - ), - }; - - has_precision = true; + Some(ch) => ch, + }; + + let mut has_precision = false; + + while matches!(ch, '0'..='9') { + ch = match chars.next() { + Some(ch) => ch, + None => { + return parsing_error( + "Unterminated format specifier: missing type after precision", + span, + ) } + }; - if has_precision && ch == '.' { - ch = match chars.next() { - Some(ch) => ch, - None => { - return parsing_error( - "Unterminated format specifier: missing type after decimal point", - span, - ) - } - }; - - while matches!(ch, '0'..='9') { - ch = match chars.next() { - Some(ch) => ch, - None => { - return parsing_error("Unterminated format specifier: missing type after fraction precision", span) - } - }; - } - } + has_precision = true; + } - if ch == 'v' { - let width = match chars.next() { - Some('2') => 2, - Some('3') => 3, - Some('4') => 4, - Some(ch) => { - return parsing_error( - &format!("Invalid width for vector: {}", ch), - span, - ) - } - None => { - return parsing_error("Missing vector dimensions specifier", span) - } - }; - - ch = match chars.next() { - Some(ch) => ch, - None => return parsing_error("Missing vector type specifier", span), - }; - - let ty = match map_specifier_to_type(ch, &mut chars) { - Some(ty) => ty, - _ => { - return parsing_error( - &format!("Unrecognised vector type specifier: '{}'", ch), - span, - ) - } - }; - - format_arguments.push(FormatType::Vector { ty, width }); - } else { - let ty = match map_specifier_to_type(ch, &mut chars) { - Some(ty) => ty, - _ => { - return parsing_error( - &format!("Unrecognised format specifier: '{}'", ch), - span, - ) - } - }; - - format_arguments.push(FormatType::Scalar { ty }); + if has_precision && ch == '.' { + ch = match chars.next() { + Some(ch) => ch, + None => { + return parsing_error( + "Unterminated format specifier: missing type after decimal point", + span, + ) } + }; + + while matches!(ch, '0'..='9') { + ch = match chars.next() { + Some(ch) => ch, + None => return parsing_error( + "Unterminated format specifier: missing type after fraction precision", + span, + ), + }; } } + + if ch == 'v' { + let width = match chars.next() { + Some('2') => 2, + Some('3') => 3, + Some('4') => 4, + Some(ch) => { + return parsing_error(&format!("Invalid width for vector: {}", ch), span) + } + None => return parsing_error("Missing vector dimensions specifier", span), + }; + + ch = match chars.next() { + Some(ch) => ch, + None => return parsing_error("Missing vector type specifier", span), + }; + + let ty = match map_specifier_to_type(ch, &mut chars) { + Some(ty) => ty, + _ => { + return parsing_error( + &format!("Unrecognised vector type specifier: '{}'", ch), + span, + ) + } + }; + + format_arguments.push(FormatType::Vector { ty, width }); + } else { + let ty = match map_specifier_to_type(ch, &mut chars) { + Some(ty) => ty, + _ => { + return parsing_error( + &format!("Unrecognised format specifier: '{}'", ch), + span, + ) + } + }; + + format_arguments.push(FormatType::Scalar { ty }); + } } } From 7155e3b044a2d55e8f7003ab1e415729ad417859 Mon Sep 17 00:00:00 2001 From: Ashley Ruglys Date: Fri, 22 Oct 2021 03:15:46 -0700 Subject: [PATCH 28/31] Finishing touches --- crates/spirv-std/macros/src/lib.rs | 31 +++++----- tests/ui/arch/debug_printf_type_checking.rs | 1 + .../ui/arch/debug_printf_type_checking.stderr | 62 +++++++++---------- 3 files changed, 49 insertions(+), 45 deletions(-) diff --git a/crates/spirv-std/macros/src/lib.rs b/crates/spirv-std/macros/src/lib.rs index f3ffdcbe28..27a1ea3960 100644 --- a/crates/spirv-std/macros/src/lib.rs +++ b/crates/spirv-std/macros/src/lib.rs @@ -430,14 +430,16 @@ fn debug_printf_inner(input: DebugPrintfInput) -> TokenStream { fn map_specifier_to_type( specifier: char, - chars: &mut std::iter::Peekable>, + chars: &mut impl Iterator, ) -> Option { + let mut peekable = chars.peekable(); + Some(match specifier { 'd' | 'i' => quote::quote! { i32 }, 'o' | 'x' | 'X' => quote::quote! { u32 }, 'a' | 'A' | 'e' | 'E' | 'f' | 'F' | 'g' | 'G' => quote::quote! { f32 }, 'u' => { - if matches!(chars.peek(), Some('l')) { + if matches!(peekable.peek(), Some('l')) { chars.next(); quote::quote! { u64 } } else { @@ -445,7 +447,7 @@ fn debug_printf_inner(input: DebugPrintfInput) -> TokenStream { } } 'l' => { - if matches!(chars.peek(), Some('u' | 'x')) { + if matches!(peekable.peek(), Some('u' | 'x')) { chars.next(); quote::quote! { u64 } } else { @@ -456,7 +458,7 @@ fn debug_printf_inner(input: DebugPrintfInput) -> TokenStream { }) } - let mut chars = format_string.chars().peekable(); + let mut chars = format_string.chars(); let mut format_arguments = Vec::new(); while let Some(mut ch) = chars.next() { @@ -561,24 +563,25 @@ fn debug_printf_inner(input: DebugPrintfInput) -> TokenStream { .into(); } - let assert_fns = format_arguments.iter().map(|ty| match ty { - FormatType::Scalar { ty } => { - quote::quote! { spirv_std::debug_printf_assert_is_type::<#ty> } - } - FormatType::Vector { ty, width } => { - quote::quote! { spirv_std::debug_printf_assert_is_vector::<#ty, _, #width> } - } - }); - let mut variable_idents = String::new(); let mut input_registers = Vec::new(); let mut op_loads = Vec::new(); - for (i, (variable, assert_fn)) in variables.into_iter().zip(assert_fns).enumerate() { + for (i, (variable, format_argument)) in variables.into_iter().zip(format_arguments).enumerate() + { let ident = quote::format_ident!("_{}", i); variable_idents.push_str(&format!("%{} ", ident)); + let assert_fn = match format_argument { + FormatType::Scalar { ty } => { + quote::quote! { spirv_std::debug_printf_assert_is_type::<#ty> } + } + FormatType::Vector { ty, width } => { + quote::quote! { spirv_std::debug_printf_assert_is_vector::<#ty, _, #width> } + } + }; + input_registers.push(quote::quote! { #ident = in(reg) &#assert_fn(#variable), }); diff --git a/tests/ui/arch/debug_printf_type_checking.rs b/tests/ui/arch/debug_printf_type_checking.rs index 878327e21f..1582de6f3b 100644 --- a/tests/ui/arch/debug_printf_type_checking.rs +++ b/tests/ui/arch/debug_printf_type_checking.rs @@ -1,4 +1,5 @@ // build-fail +// normalize-stderr-test "\S*/crates/spirv-std/src/" -> "$$SPIRV_STD_SRC/" // compile-flags: -Ctarget-feature=+ext:SPV_KHR_non_semantic_info use spirv_std::{ diff --git a/tests/ui/arch/debug_printf_type_checking.stderr b/tests/ui/arch/debug_printf_type_checking.stderr index 58fc2bc8b7..4920ced8e8 100644 --- a/tests/ui/arch/debug_printf_type_checking.stderr +++ b/tests/ui/arch/debug_printf_type_checking.stderr @@ -1,89 +1,89 @@ error: Unterminated format specifier: missing type after precision - --> $DIR/debug_printf_type_checking.rs:12:23 + --> $DIR/debug_printf_type_checking.rs:13:23 | -12 | debug_printf!("%1"); +13 | debug_printf!("%1"); | ^^^^ error: Unterminated format specifier: missing type after decimal point - --> $DIR/debug_printf_type_checking.rs:13:23 + --> $DIR/debug_printf_type_checking.rs:14:23 | -13 | debug_printf!("%1."); +14 | debug_printf!("%1."); | ^^^^^ error: Unrecognised format specifier: '.' - --> $DIR/debug_printf_type_checking.rs:14:23 + --> $DIR/debug_printf_type_checking.rs:15:23 | -14 | debug_printf!("%."); +15 | debug_printf!("%."); | ^^^^ error: Unrecognised format specifier: '.' - --> $DIR/debug_printf_type_checking.rs:15:23 + --> $DIR/debug_printf_type_checking.rs:16:23 | -15 | debug_printf!("%.1"); +16 | debug_printf!("%.1"); | ^^^^^ error: Unterminated format specifier: missing type after fraction precision - --> $DIR/debug_printf_type_checking.rs:16:23 + --> $DIR/debug_printf_type_checking.rs:17:23 | -16 | debug_printf!("%1.1"); +17 | debug_printf!("%1.1"); | ^^^^^^ error: Missing vector dimensions specifier - --> $DIR/debug_printf_type_checking.rs:17:23 + --> $DIR/debug_printf_type_checking.rs:18:23 | -17 | debug_printf!("%1.1v"); +18 | debug_printf!("%1.1v"); | ^^^^^^^ error: Invalid width for vector: 5 - --> $DIR/debug_printf_type_checking.rs:18:23 + --> $DIR/debug_printf_type_checking.rs:19:23 | -18 | debug_printf!("%1.1v5"); +19 | debug_printf!("%1.1v5"); | ^^^^^^^^ error: Missing vector type specifier - --> $DIR/debug_printf_type_checking.rs:19:23 + --> $DIR/debug_printf_type_checking.rs:20:23 | -19 | debug_printf!("%1.1v2"); +20 | debug_printf!("%1.1v2"); | ^^^^^^^^ error: Unrecognised vector type specifier: 'r' - --> $DIR/debug_printf_type_checking.rs:20:23 + --> $DIR/debug_printf_type_checking.rs:21:23 | -20 | debug_printf!("%1.1v2r"); +21 | debug_printf!("%1.1v2r"); | ^^^^^^^^^ error: Unrecognised format specifier: 'r' - --> $DIR/debug_printf_type_checking.rs:21:23 + --> $DIR/debug_printf_type_checking.rs:22:23 | -21 | debug_printf!("%r", 11_i32); +22 | debug_printf!("%r", 11_i32); | ^^^^ error[E0308]: mismatched types - --> $DIR/debug_printf_type_checking.rs:22:29 + --> $DIR/debug_printf_type_checking.rs:23:29 | -22 | debug_printf!("%f", 11_u32); +23 | debug_printf!("%f", 11_u32); | ^^^^^^ expected `f32`, found `u32` | help: change the type of the numeric literal from `u32` to `f32` | -22 | debug_printf!("%f", 11_f32); +23 | debug_printf!("%f", 11_f32); | ~~~ error[E0308]: mismatched types - --> $DIR/debug_printf_type_checking.rs:23:29 + --> $DIR/debug_printf_type_checking.rs:24:29 | -23 | debug_printf!("%u", 11.0_f32); +24 | debug_printf!("%u", 11.0_f32); | ^^^^^^^^ expected `u32`, found `f32` | help: change the type of the numeric literal from `f32` to `u32` | -23 | debug_printf!("%u", 11u32); +24 | debug_printf!("%u", 11u32); | ~~~ error[E0277]: the trait bound `{float}: Vector` is not satisfied - --> $DIR/debug_printf_type_checking.rs:24:31 + --> $DIR/debug_printf_type_checking.rs:25:31 | -24 | debug_printf!("%v2f", 11.0); +25 | debug_printf!("%v2f", 11.0); | ----------------------^^^^-- | | | | | the trait `Vector` is not implemented for `{float}` @@ -96,15 +96,15 @@ error[E0277]: the trait bound `{float}: Vector` is not satisfied > and 13 others note: required by a bound in `debug_printf_assert_is_vector` - --> C:/Users/Ashley/Desktop/rust-gpu/crates/spirv-std/src/lib.rs:142:8 + --> $SPIRV_STD_SRC/lib.rs:142:8 | 142 | V: crate::vector::Vector, | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `debug_printf_assert_is_vector` error[E0308]: mismatched types - --> $DIR/debug_printf_type_checking.rs:25:29 + --> $DIR/debug_printf_type_checking.rs:26:29 | -25 | debug_printf!("%f", Vec2::splat(33.3)); +26 | debug_printf!("%f", Vec2::splat(33.3)); | ^^^^^^^^^^^^^^^^^ expected `f32`, found struct `Vec2` error: aborting due to 14 previous errors From aa6345f8be4bac7e50b8f5820f2ec51756bbd6cd Mon Sep 17 00:00:00 2001 From: Ashley Ruglys Date: Fri, 22 Oct 2021 03:48:11 -0700 Subject: [PATCH 29/31] Rustfmt --- tests/ui/arch/debug_printf_type_checking.rs | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/tests/ui/arch/debug_printf_type_checking.rs b/tests/ui/arch/debug_printf_type_checking.rs index 1582de6f3b..c41c7924b9 100644 --- a/tests/ui/arch/debug_printf_type_checking.rs +++ b/tests/ui/arch/debug_printf_type_checking.rs @@ -2,10 +2,7 @@ // normalize-stderr-test "\S*/crates/spirv-std/src/" -> "$$SPIRV_STD_SRC/" // compile-flags: -Ctarget-feature=+ext:SPV_KHR_non_semantic_info -use spirv_std::{ - macros::debug_printf, - glam::Vec2, -}; +use spirv_std::{glam::Vec2, macros::debug_printf}; #[spirv(fragment)] pub fn main() { From 41ea76ece48706aa649ce90b33ad08c49597fc29 Mon Sep 17 00:00:00 2001 From: Ashley Ruglys Date: Fri, 22 Oct 2021 04:17:47 -0700 Subject: [PATCH 30/31] Re-bless compile tests --- .../ui/arch/debug_printf_type_checking.stderr | 60 +++++++++---------- 1 file changed, 30 insertions(+), 30 deletions(-) diff --git a/tests/ui/arch/debug_printf_type_checking.stderr b/tests/ui/arch/debug_printf_type_checking.stderr index 4920ced8e8..2e21dc300f 100644 --- a/tests/ui/arch/debug_printf_type_checking.stderr +++ b/tests/ui/arch/debug_printf_type_checking.stderr @@ -1,89 +1,89 @@ error: Unterminated format specifier: missing type after precision - --> $DIR/debug_printf_type_checking.rs:13:23 + --> $DIR/debug_printf_type_checking.rs:10:23 | -13 | debug_printf!("%1"); +10 | debug_printf!("%1"); | ^^^^ error: Unterminated format specifier: missing type after decimal point - --> $DIR/debug_printf_type_checking.rs:14:23 + --> $DIR/debug_printf_type_checking.rs:11:23 | -14 | debug_printf!("%1."); +11 | debug_printf!("%1."); | ^^^^^ error: Unrecognised format specifier: '.' - --> $DIR/debug_printf_type_checking.rs:15:23 + --> $DIR/debug_printf_type_checking.rs:12:23 | -15 | debug_printf!("%."); +12 | debug_printf!("%."); | ^^^^ error: Unrecognised format specifier: '.' - --> $DIR/debug_printf_type_checking.rs:16:23 + --> $DIR/debug_printf_type_checking.rs:13:23 | -16 | debug_printf!("%.1"); +13 | debug_printf!("%.1"); | ^^^^^ error: Unterminated format specifier: missing type after fraction precision - --> $DIR/debug_printf_type_checking.rs:17:23 + --> $DIR/debug_printf_type_checking.rs:14:23 | -17 | debug_printf!("%1.1"); +14 | debug_printf!("%1.1"); | ^^^^^^ error: Missing vector dimensions specifier - --> $DIR/debug_printf_type_checking.rs:18:23 + --> $DIR/debug_printf_type_checking.rs:15:23 | -18 | debug_printf!("%1.1v"); +15 | debug_printf!("%1.1v"); | ^^^^^^^ error: Invalid width for vector: 5 - --> $DIR/debug_printf_type_checking.rs:19:23 + --> $DIR/debug_printf_type_checking.rs:16:23 | -19 | debug_printf!("%1.1v5"); +16 | debug_printf!("%1.1v5"); | ^^^^^^^^ error: Missing vector type specifier - --> $DIR/debug_printf_type_checking.rs:20:23 + --> $DIR/debug_printf_type_checking.rs:17:23 | -20 | debug_printf!("%1.1v2"); +17 | debug_printf!("%1.1v2"); | ^^^^^^^^ error: Unrecognised vector type specifier: 'r' - --> $DIR/debug_printf_type_checking.rs:21:23 + --> $DIR/debug_printf_type_checking.rs:18:23 | -21 | debug_printf!("%1.1v2r"); +18 | debug_printf!("%1.1v2r"); | ^^^^^^^^^ error: Unrecognised format specifier: 'r' - --> $DIR/debug_printf_type_checking.rs:22:23 + --> $DIR/debug_printf_type_checking.rs:19:23 | -22 | debug_printf!("%r", 11_i32); +19 | debug_printf!("%r", 11_i32); | ^^^^ error[E0308]: mismatched types - --> $DIR/debug_printf_type_checking.rs:23:29 + --> $DIR/debug_printf_type_checking.rs:20:29 | -23 | debug_printf!("%f", 11_u32); +20 | debug_printf!("%f", 11_u32); | ^^^^^^ expected `f32`, found `u32` | help: change the type of the numeric literal from `u32` to `f32` | -23 | debug_printf!("%f", 11_f32); +20 | debug_printf!("%f", 11_f32); | ~~~ error[E0308]: mismatched types - --> $DIR/debug_printf_type_checking.rs:24:29 + --> $DIR/debug_printf_type_checking.rs:21:29 | -24 | debug_printf!("%u", 11.0_f32); +21 | debug_printf!("%u", 11.0_f32); | ^^^^^^^^ expected `u32`, found `f32` | help: change the type of the numeric literal from `f32` to `u32` | -24 | debug_printf!("%u", 11u32); +21 | debug_printf!("%u", 11u32); | ~~~ error[E0277]: the trait bound `{float}: Vector` is not satisfied - --> $DIR/debug_printf_type_checking.rs:25:31 + --> $DIR/debug_printf_type_checking.rs:22:31 | -25 | debug_printf!("%v2f", 11.0); +22 | debug_printf!("%v2f", 11.0); | ----------------------^^^^-- | | | | | the trait `Vector` is not implemented for `{float}` @@ -102,9 +102,9 @@ note: required by a bound in `debug_printf_assert_is_vector` | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `debug_printf_assert_is_vector` error[E0308]: mismatched types - --> $DIR/debug_printf_type_checking.rs:26:29 + --> $DIR/debug_printf_type_checking.rs:23:29 | -26 | debug_printf!("%f", Vec2::splat(33.3)); +23 | debug_printf!("%f", Vec2::splat(33.3)); | ^^^^^^^^^^^^^^^^^ expected `f32`, found struct `Vec2` error: aborting due to 14 previous errors From 10575d34662d72a8503119709586035cf5ab624d Mon Sep 17 00:00:00 2001 From: Ashley Ruglys Date: Fri, 22 Oct 2021 12:40:25 -0700 Subject: [PATCH 31/31] Only last tiny change: Replace impl Iterator with std::str::Chars --- crates/spirv-std/macros/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/spirv-std/macros/src/lib.rs b/crates/spirv-std/macros/src/lib.rs index 27a1ea3960..0efba5dfe8 100644 --- a/crates/spirv-std/macros/src/lib.rs +++ b/crates/spirv-std/macros/src/lib.rs @@ -430,7 +430,7 @@ fn debug_printf_inner(input: DebugPrintfInput) -> TokenStream { fn map_specifier_to_type( specifier: char, - chars: &mut impl Iterator, + chars: &mut std::str::Chars<'_>, ) -> Option { let mut peekable = chars.peekable();