diff --git a/src/panfrost/compiler/kraid/proc/isa/encoder.rs b/src/panfrost/compiler/kraid/proc/isa/encoder.rs index c550dec3d7f..c407d462124 100644 --- a/src/panfrost/compiler/kraid/proc/isa/encoder.rs +++ b/src/panfrost/compiler/kraid/proc/isa/encoder.rs @@ -420,6 +420,7 @@ impl InstrEncSrc { struct InstrEncFieldSrc { ident: Ident, field_type: FieldType, + field_restrict: Option>, src_name: String, src_field: SrcField, } @@ -428,6 +429,7 @@ impl InstrEncFieldSrc { fn new( field_name: &str, field_type: FieldType, + field_restrict: Option>, src_name: &str, src_field: SrcField, ) -> InstrEncFieldSrc { @@ -436,6 +438,7 @@ impl InstrEncFieldSrc { InstrEncFieldSrc { ident, field_type, + field_restrict, src_name, src_field, } @@ -459,6 +462,15 @@ impl InstrEncFieldSrc { }); } + if let Some(restrict) = &self.field_restrict { + let err = format!("Unsupported {f_ident} value"); + ts.extend(quote! { + if !#restrict.contains(&#f_ident) { + return Err(#err.into()); + } + }); + } + if matches!(&self.field_type, FieldType::Enum(_)) { ts.extend(quote! { let #f_ident = #f_ident.try_encode(arch)?; @@ -509,6 +521,7 @@ impl InstrEncSources { instr_name: &str, field_name: &str, field_type: &FieldType, + field_restrict: &Option>, sr_control: SrControl, enums: &EnumSet, ) -> Option { @@ -529,6 +542,7 @@ impl InstrEncSources { Some(InstrEncFieldSrc::new( field_name, field_type.clone(), + field_restrict.clone(), &src.name, src_field, )) @@ -539,6 +553,7 @@ impl InstrEncSources { instr_name: &str, field_name: &str, field_type: &FieldType, + field_restrict: &Option>, sr_control: SrControl, enums: &EnumSet, ) -> InstrEncFieldSrc { @@ -557,6 +572,7 @@ impl InstrEncSources { return InstrEncFieldSrc::new( field_name, field_type.clone(), + field_restrict.clone(), &src.name, src_field, ); @@ -574,6 +590,7 @@ impl InstrEncSources { InstrEncFieldSrc::new( field_name, field_type.clone(), + field_restrict.clone(), &src.name, src_field, ) @@ -648,11 +665,11 @@ impl InstrEncVariant { continue; } - let (field_name, field_type) = match field { + let (field_name, field_type, restrict) = match field { InstrField::Virtual(f) => { // Virtual fields are always sources since they're used to // calculate computed physical fields. - (&f.name, &f.type_) + (&f.name, &f.type_, &f.restrict) } InstrField::Physical(f) => { // Physical fields only show up as sources if we can't @@ -660,27 +677,28 @@ impl InstrEncVariant { if f.expr.is_some() { continue; } - (&f.name, f.type_.as_ref().unwrap()) + (&f.name, f.type_.as_ref().unwrap(), &f.restrict) } InstrField::Reserved(_) => continue, }; - fields.push((i, field_name, field_type)); + fields.push((i, field_name, field_type, restrict)); } // Add the sources and destinations first - for (i, field_name, field_type) in fields.iter().cloned() { + for (i, field_name, field_type, restrict) in fields.iter().cloned() { field_srcs[i] = srcs.add_src_for_src_dst_field( &instr.name, field_name, &field_type, + restrict, sr_control, enums, ); } // Add all the other sources - for (i, field_name, field_type) in fields.iter().cloned() { + for (i, field_name, field_type, restrict) in fields.iter().cloned() { if field_srcs[i].is_some() { continue; } @@ -689,6 +707,7 @@ impl InstrEncVariant { &instr.name, field_name, &field_type, + restrict, sr_control, enums, )); diff --git a/src/panfrost/compiler/kraid/proc/isa/instr.rs b/src/panfrost/compiler/kraid/proc/isa/instr.rs index 2440553bd38..b1222902f1b 100644 --- a/src/panfrost/compiler/kraid/proc/isa/instr.rs +++ b/src/panfrost/compiler/kraid/proc/isa/instr.rs @@ -63,10 +63,53 @@ impl FieldType { } } +pub struct FieldRestrict { + values: Vec, +} + +impl FieldRestrict { + fn from_xml_attr( + attr: &str, + type_: Option<&FieldType>, + ) -> Result> { + let Some(FieldType::Enum(e)) = type_ else { + return Err(err("restrict= requires an enum type")); + }; + + let mut values = Vec::new(); + for v_name in attr.split(' ') { + if v_name.trim().is_empty() { + continue; + } + + let Some(v) = e.get_value(v_name) else { + return Err(err("Invalid enum value in restrict")); + }; + values.push(LiteralEnum { + enum_type: e.clone(), + value_name: v.name.clone(), + value_ident: v.ident.clone(), + }); + } + Ok(Rc::new(FieldRestrict { values })) + } +} + +impl ToTokens for FieldRestrict { + fn to_tokens(&self, ts: &mut TokenStream2) { + let mut values_ts = TokenStream2::new(); + for i in &self.values { + values_ts.extend(quote! { #i, }); + } + ts.extend(quote! { [#values_ts] }); + } +} + pub struct VirtualField { pub name: String, pub ident: Ident, pub type_: FieldType, + pub restrict: Option>, pub expr: Box, } @@ -86,13 +129,20 @@ impl VirtualField { let snake_name = to_snake_case(&name); let ident = Ident::new(&snake_name, Span::call_site()); - let type_ = xml + let type_name = xml .attrs .get("type") .ok_or(err("Instruction virtual has no type"))?; + let type_ = FieldType::from_name(type_name, 32, enums)?; + + let restrict = if let Some(res_attr) = xml.attrs.get("restrict") { + Some(FieldRestrict::from_xml_attr(res_attr, Some(&type_))?) + } else { + None + }; let expr = if let Some(exact) = xml.attrs.get("exact") { - Box::new(Expr::literal(Some(type_), exact, enums)?) + Box::new(Expr::literal(Some(type_name), exact, enums)?) } else { let mut children = xml.children; if children.len() != 1 { @@ -105,7 +155,8 @@ impl VirtualField { Ok(VirtualField { name, ident, - type_: FieldType::from_name(type_, 32, enums)?, + type_, + restrict, expr, }) } @@ -152,6 +203,7 @@ pub struct PhysicalField { pub bits: Range, pub mod_: FieldMod, pub type_: Option, + pub restrict: Option>, pub expr: Option>, } @@ -188,6 +240,12 @@ impl PhysicalField { None => None, }; + let restrict = if let Some(res_attr) = xml.attrs.get("restrict") { + Some(FieldRestrict::from_xml_attr(res_attr, type_.as_ref())?) + } else { + None + }; + let mut expr = if let Some(exact) = xml.attrs.get("exact") { Some(Box::new(Expr::literal( type_name.map(String::as_str), @@ -224,6 +282,7 @@ impl PhysicalField { bits, mod_, type_, + restrict, expr, }) }