kraid/isa: Handle field restrictions

Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/41841>
This commit is contained in:
Faith Ekstrand 2026-05-30 17:37:19 -04:00 committed by Marge Bot
parent 6f214056ce
commit c64e968bf8
2 changed files with 87 additions and 9 deletions

View file

@ -420,6 +420,7 @@ impl InstrEncSrc {
struct InstrEncFieldSrc {
ident: Ident,
field_type: FieldType,
field_restrict: Option<Rc<FieldRestrict>>,
src_name: String,
src_field: SrcField,
}
@ -428,6 +429,7 @@ impl InstrEncFieldSrc {
fn new(
field_name: &str,
field_type: FieldType,
field_restrict: Option<Rc<FieldRestrict>>,
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<Rc<FieldRestrict>>,
sr_control: SrControl,
enums: &EnumSet,
) -> Option<InstrEncFieldSrc> {
@ -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<Rc<FieldRestrict>>,
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,
));

View file

@ -63,10 +63,53 @@ impl FieldType {
}
}
pub struct FieldRestrict {
values: Vec<LiteralEnum>,
}
impl FieldRestrict {
fn from_xml_attr(
attr: &str,
type_: Option<&FieldType>,
) -> Result<Rc<FieldRestrict>> {
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<Rc<FieldRestrict>>,
pub expr: Box<Expr>,
}
@ -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<u8>,
pub mod_: FieldMod,
pub type_: Option<FieldType>,
pub restrict: Option<Rc<FieldRestrict>>,
pub expr: Option<Box<Expr>>,
}
@ -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,
})
}