Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add debug_printf! and debug_printfln! macros that uses the DebugPrintf extension #768

Merged
merged 33 commits into from
Oct 23, 2021
Merged
Show file tree
Hide file tree
Changes from 10 commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
24fafec
Add a very bad no good prinfln macro
expenses Oct 16, 2021
5656770
Use a better registry identifier
expenses Oct 16, 2021
9931531
Do a little bit of argument count checking
expenses Oct 16, 2021
4f2048d
Use OpLoads to be able to print vectors
expenses Oct 16, 2021
6a21a29
Add an error for string literal expressions
expenses Oct 16, 2021
2ee529e
Revert "Add an error for string literal expressions"
expenses Oct 16, 2021
9311710
Add both printf and printfln, allow for other kinds of expressions by…
expenses Oct 16, 2021
a6c29fe
Tidy up a little
expenses Oct 16, 2021
29481ba
Add a compiletest
expenses Oct 17, 2021
1f68124
Run rustfmt
expenses Oct 17, 2021
d095849
Rename to debug_printf
expenses Oct 18, 2021
2f4f9c9
Parse variables using punctated
expenses Oct 18, 2021
aecdf5b
Handle inner quotes
expenses Oct 18, 2021
564165f
Add tests for function and method calls
expenses Oct 18, 2021
fb6f66c
Escape only quote marks
expenses Oct 18, 2021
0f0d13d
Run rustfmt
expenses Oct 18, 2021
b545f6b
Use a regex to parse types from the format string and assert them wit…
expenses Oct 19, 2021
42978ab
Add extra tests, escape the string correctly while keeping printfln n…
expenses Oct 20, 2021
a0f4615
Use the string debug impl after all
expenses Oct 20, 2021
b4c0d28
Merge remote-tracking branch 'origin/main' into printfln-macro
expenses Oct 20, 2021
c59e3ce
Cargo fmt
expenses Oct 21, 2021
53ae4a1
Merge branch 'printf-macro-type-checking' into printfln-macro
expenses Oct 21, 2021
ffc7505
Cargo fmt again
expenses Oct 21, 2021
81d4103
fmt compiletest
expenses Oct 21, 2021
81ad59e
Merge match branches
expenses Oct 21, 2021
602b691
Improved argument checking
expenses Oct 21, 2021
8c76f59
Filter out captures like %%f
expenses Oct 21, 2021
6fbde8e
Use a peekable character iterator to parse the format string into rus…
expenses Oct 21, 2021
2836b3e
continue on %% to unindent the code
expenses Oct 21, 2021
7155e3b
Finishing touches
expenses Oct 22, 2021
aa6345f
Rustfmt
expenses Oct 22, 2021
41ea76e
Re-bless compile tests
expenses Oct 22, 2021
10575d3
Only last tiny change: Replace impl Iterator with std::str::Chars
expenses Oct 22, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
120 changes: 120 additions & 0 deletions crates/spirv-std/macros/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -350,3 +350,123 @@ fn path_from_ident(ident: Ident) -> syn::Type {
path: syn::Path::from(ident),
})
}

/// 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 <https://github.com/KhronosGroup/Vulkan-ValidationLayers/blob/master/docs/debug_printf.md#debug-printf-format-string> for formatting rules.
#[proc_macro]
pub fn printf(input: TokenStream) -> TokenStream {
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 mut input = syn::parse_macro_input!(input as PrintfInput);
input.format_string.push_str("\\n");
printf_inner(input)
}

struct PrintfInput {
span: proc_macro2::Span,
format_string: String,
variables: Vec<syn::Expr>,
}

impl syn::parse::Parse for PrintfInput {
fn parse(input: syn::parse::ParseStream<'_>) -> syn::parse::Result<Self> {
let span = input.span();

if input.is_empty() {
return Ok(Self {
span,
format_string: Default::default(),
variables: Default::default(),
});
}

Ok(Self {
span,
format_string: input.parse::<syn::LitStr>()?.value(),
variables: {
let mut variables = Vec::new();
while !input.is_empty() {
input.parse::<syn::Token![,]>()?;
variables.push(input.parse()?);
}
variables
expenses marked this conversation as resolved.
Show resolved Hide resolved
},
})
}
}

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;

if number_of_arguments != variables.len() {
return syn::Error::new(
span,
&format!(
"{} % arguments were found, but {} variables were given",
number_of_arguments,
variables.len()
),
)
.to_compile_error()
.into();
}

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() {
let ident = quote::format_ident!("_{}", i);

variable_idents.push_str(&format!("%{} ", ident));

input_registers.push(quote::quote! {
#ident = in(reg) &{#variable},
});

let op_load = format!("%{ident} = OpLoad _ {{{ident}}}", ident = ident);

op_loads.push(quote::quote! {
#op_load,
});
}

let input_registers = input_registers
.into_iter()
.collect::<proc_macro2::TokenStream>();
let op_loads = op_loads.into_iter().collect::<proc_macro2::TokenStream>();

let op_string = format!("%string = OpString \"{}\"", format_string);
expenses marked this conversation as resolved.
Show resolved Hide resolved

let output = quote::quote! {
asm!(
"%void = OpTypeVoid",
#op_string,
"%debug_printf = OpExtInstImport \"NonSemantic.DebugPrintf\"",
#op_loads
concat!("%result = OpExtInst %void %debug_printf 1 %string ", #variable_idents),
#input_registers
)
};

output.into()
}
26 changes: 26 additions & 0 deletions tests/ui/arch/printf.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
// 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);
expenses marked this conversation as resolved.
Show resolved Hide resolved
}
}