Add encoding of flags into tag

Add a `TagFlags` type. You can write enum variants as `Variant(TagFlags,
Content)` and this will encode a u16 into the top 16 bits of the tag
word.
This commit is contained in:
Raph Levien 2021-03-02 09:57:49 -08:00
parent b73eabf4eb
commit 9afa9b86b6
4 changed files with 54 additions and 13 deletions

View file

@ -73,18 +73,31 @@ fn gen_derive_def(name: &str, size: usize, def: &LayoutTypeDef) -> proc_macro2::
let mut args = Vec::new(); let mut args = Vec::new();
let mut field_encoders = proc_macro2::TokenStream::new(); let mut field_encoders = proc_macro2::TokenStream::new();
for (i, (offset, _ty)) in payload.iter().enumerate() { let mut tag_field = None;
for (i, (offset, ty)) in payload.iter().enumerate() {
let field_id = format_ident!("f{}", i); let field_id = format_ident!("f{}", i);
if matches!(ty.ty, GpuType::Scalar(GpuScalar::TagFlags)) {
tag_field = Some(field_id.clone());
} else {
let field_encoder = quote! { let field_encoder = quote! {
#field_id.encode_to(&mut buf[#offset..]); #field_id.encode_to(&mut buf[#offset..]);
}; };
field_encoders.extend(field_encoder); field_encoders.extend(field_encoder);
}
args.push(field_id); args.push(field_id);
} }
let tag = variant_ix as u32; let tag = variant_ix as u32;
let tag_encode = match tag_field {
None => quote! {
buf[0..4].copy_from_slice(&#tag.to_le_bytes());
},
Some(tag_field) => quote! {
buf[0..4].copy_from_slice(&(#tag | ((*#tag_field as u32) << 16)).to_le_bytes());
},
};
let case = quote! { let case = quote! {
#name_id::#variant_id(#(#args),*) => { #name_id::#variant_id(#(#args),*) => {
buf[0..4].copy_from_slice(&#tag.to_le_bytes()); #tag_encode
#field_encoders #field_encoders
} }
}; };
@ -139,12 +152,15 @@ fn gen_derive_scalar_ty(ty: &GpuScalar) -> proc_macro2::TokenStream {
GpuScalar::U8 => quote!(u8), GpuScalar::U8 => quote!(u8),
GpuScalar::U16 => quote!(u16), GpuScalar::U16 => quote!(u16),
GpuScalar::U32 => quote!(u32), GpuScalar::U32 => quote!(u32),
GpuScalar::TagFlags => quote!(u16),
} }
} }
fn gen_encode_field(name: &str, offset: usize, ty: &GpuType) -> proc_macro2::TokenStream { fn gen_encode_field(name: &str, offset: usize, ty: &GpuType) -> proc_macro2::TokenStream {
let name_id = format_ident!("{}", name); let name_id = format_ident!("{}", name);
match ty { match ty {
// encoding of flags into tag word is handled elsewhere
GpuType::Scalar(GpuScalar::TagFlags) => quote! {},
GpuType::Scalar(s) => { GpuType::Scalar(s) => {
let end = offset + s.size(); let end = offset + s.size();
quote! { quote! {

View file

@ -8,7 +8,11 @@ use crate::parse::{GpuScalar, GpuType};
pub fn gen_glsl(module: &LayoutModule) -> String { pub fn gen_glsl(module: &LayoutModule) -> String {
let mut r = String::new(); let mut r = String::new();
writeln!(&mut r, "// SPDX-License-Identifier: Apache-2.0 OR MIT OR Unlicense\n").unwrap(); writeln!(
&mut r,
"// SPDX-License-Identifier: Apache-2.0 OR MIT OR Unlicense\n"
)
.unwrap();
writeln!(&mut r, "// Code auto-generated by piet-gpu-derive\n").unwrap(); writeln!(&mut r, "// Code auto-generated by piet-gpu-derive\n").unwrap();
// Note: GLSL needs definitions before uses. We could do a topological sort here, // Note: GLSL needs definitions before uses. We could do a topological sort here,
// but easiest for now to just require that in spec. // but easiest for now to just require that in spec.
@ -147,8 +151,19 @@ fn gen_enum_read(
} }
writeln!(r, "}}\n").unwrap(); writeln!(r, "}}\n").unwrap();
for (var_name, payload) in variants { for (var_name, payload) in variants {
if payload.len() == 1 { let payload_ix = if payload.len() == 1 {
if let GpuType::InlineStruct(structname) = &payload[0].1.ty { Some(0)
} else if payload.len() == 2 {
if matches!(payload[0].1.ty, GpuType::Scalar(GpuScalar::TagFlags)) {
Some(1)
} else {
None
}
} else {
None
};
if let Some(payload_ix) = payload_ix {
if let GpuType::InlineStruct(structname) = &payload[payload_ix].1.ty {
if is_mem { if is_mem {
writeln!( writeln!(
r, r,
@ -257,6 +272,7 @@ fn gen_extract_scalar(offset: usize, ty: &GpuScalar) -> String {
GpuScalar::F16 | GpuScalar::F32 => extract_fbits(offset, ty.size()), GpuScalar::F16 | GpuScalar::F32 => extract_fbits(offset, ty.size()),
GpuScalar::U8 | GpuScalar::U16 | GpuScalar::U32 => extract_ubits(offset, ty.size()), GpuScalar::U8 | GpuScalar::U16 | GpuScalar::U32 => extract_ubits(offset, ty.size()),
GpuScalar::I8 | GpuScalar::I16 | GpuScalar::I32 => extract_ibits(offset, ty.size()), GpuScalar::I8 | GpuScalar::I16 | GpuScalar::I32 => extract_ibits(offset, ty.size()),
GpuScalar::TagFlags => format!("0 /* TODO */"),
} }
} }
@ -455,6 +471,7 @@ fn gen_pack_bits_scalar(ty: &GpuScalar, offset: usize, inner: &str) -> String {
} }
} }
GpuScalar::I32 => format!("uint({})", inner), GpuScalar::I32 => format!("uint({})", inner),
GpuScalar::TagFlags => format!("0"),
}; };
if shift == 0 { if shift == 0 {
bits bits
@ -473,7 +490,12 @@ fn gen_enum_write(
for (var_name, payload) in variants { for (var_name, payload) in variants {
if payload.is_empty() { if payload.is_empty() {
if is_mem { if is_mem {
writeln!(r, "void {}_{}_write(Alloc a, {}Ref ref) {{", name, var_name, name).unwrap(); writeln!(
r,
"void {}_{}_write(Alloc a, {}Ref ref) {{",
name, var_name, name
)
.unwrap();
writeln!( writeln!(
r, r,
" write_mem(a, ref.offset >> 2, {}_{});", " write_mem(a, ref.offset >> 2, {}_{});",
@ -566,7 +588,7 @@ fn glsl_scalar(s: &GpuScalar) -> &'static str {
match s { match s {
GpuScalar::F16 | GpuScalar::F32 => "float", GpuScalar::F16 | GpuScalar::F32 => "float",
GpuScalar::I8 | GpuScalar::I16 | GpuScalar::I32 => "int", GpuScalar::I8 | GpuScalar::I16 | GpuScalar::I32 => "int",
GpuScalar::U8 | GpuScalar::U16 | GpuScalar::U32 => "uint", GpuScalar::U8 | GpuScalar::U16 | GpuScalar::U32 | GpuScalar::TagFlags => "uint",
} }
} }
@ -574,7 +596,7 @@ fn glsl_vecname(s: &GpuScalar) -> &'static str {
match s { match s {
GpuScalar::F16 | GpuScalar::F32 => "vec", GpuScalar::F16 | GpuScalar::F32 => "vec",
GpuScalar::I8 | GpuScalar::I16 | GpuScalar::I32 => "ivec", GpuScalar::I8 | GpuScalar::I16 | GpuScalar::I32 => "ivec",
GpuScalar::U8 | GpuScalar::U16 | GpuScalar::U32 => "uvec", GpuScalar::U8 | GpuScalar::U16 | GpuScalar::U32 | GpuScalar::TagFlags => "uvec",
} }
} }

View file

@ -240,5 +240,5 @@ impl Size {
} }
fn align_padding(offset: usize, alignment: usize) -> usize { fn align_padding(offset: usize, alignment: usize) -> usize {
offset.wrapping_neg() & (alignment - 1) offset.wrapping_neg() & (alignment.max(1) - 1)
} }

View file

@ -20,6 +20,7 @@ pub enum GpuScalar {
U8, U8,
U16, U16,
U32, U32,
TagFlags,
} }
/// An algebraic datatype. /// An algebraic datatype.
@ -59,6 +60,7 @@ impl GpuScalar {
"u8" => Some(GpuScalar::U8), "u8" => Some(GpuScalar::U8),
"u16" => Some(GpuScalar::U16), "u16" => Some(GpuScalar::U16),
"u32" => Some(GpuScalar::U32), "u32" => Some(GpuScalar::U32),
"TagFlags" => Some(GpuScalar::TagFlags),
_ => None, _ => None,
}) })
} }
@ -72,6 +74,7 @@ impl GpuScalar {
GpuScalar::F32 | GpuScalar::I32 | GpuScalar::U32 => 4, GpuScalar::F32 | GpuScalar::I32 | GpuScalar::U32 => 4,
GpuScalar::I8 | GpuScalar::U8 => 1, GpuScalar::I8 | GpuScalar::U8 => 1,
GpuScalar::F16 | GpuScalar::I16 | GpuScalar::U16 => 2, GpuScalar::F16 | GpuScalar::I16 | GpuScalar::U16 => 2,
GpuScalar::TagFlags => 0,
} }
} }
} }