xref: /aosp_15_r20/external/mesa3d/src/etnaviv/isa/isa.rs (revision 6104692788411f58d303aa86923a9ff6ecaded22)
1*61046927SAndroid Build Coastguard Worker // Copyright © 2024 Igalia S.L.
2*61046927SAndroid Build Coastguard Worker // SPDX-License-Identifier: MIT
3*61046927SAndroid Build Coastguard Worker 
4*61046927SAndroid Build Coastguard Worker use indexmap::IndexMap;
5*61046927SAndroid Build Coastguard Worker use roxmltree::Document;
6*61046927SAndroid Build Coastguard Worker use std::collections::HashMap;
7*61046927SAndroid Build Coastguard Worker 
8*61046927SAndroid Build Coastguard Worker /// A structure representing a bitset.
9*61046927SAndroid Build Coastguard Worker #[derive(Debug)]
10*61046927SAndroid Build Coastguard Worker pub struct Bitset<'a> {
11*61046927SAndroid Build Coastguard Worker     pub name: &'a str,
12*61046927SAndroid Build Coastguard Worker     pub displayname: Option<&'a str>,
13*61046927SAndroid Build Coastguard Worker     pub extends: Option<&'a str>,
14*61046927SAndroid Build Coastguard Worker     pub meta: HashMap<&'a str, &'a str>,
15*61046927SAndroid Build Coastguard Worker }
16*61046927SAndroid Build Coastguard Worker 
17*61046927SAndroid Build Coastguard Worker /// A structure representing a value in a bitset enum.
18*61046927SAndroid Build Coastguard Worker #[derive(Debug)]
19*61046927SAndroid Build Coastguard Worker pub struct BitSetEnumValue<'a> {
20*61046927SAndroid Build Coastguard Worker     pub display: &'a str,
21*61046927SAndroid Build Coastguard Worker     pub name: Option<&'a str>,
22*61046927SAndroid Build Coastguard Worker }
23*61046927SAndroid Build Coastguard Worker 
24*61046927SAndroid Build Coastguard Worker /// A structure representing a bitset enum.
25*61046927SAndroid Build Coastguard Worker #[derive(Debug)]
26*61046927SAndroid Build Coastguard Worker pub struct BitSetEnum<'a> {
27*61046927SAndroid Build Coastguard Worker     pub name: &'a str,
28*61046927SAndroid Build Coastguard Worker     pub values: Vec<BitSetEnumValue<'a>>,
29*61046927SAndroid Build Coastguard Worker }
30*61046927SAndroid Build Coastguard Worker 
31*61046927SAndroid Build Coastguard Worker /// A structure representing a bitset template.
32*61046927SAndroid Build Coastguard Worker #[derive(Debug)]
33*61046927SAndroid Build Coastguard Worker pub struct BitsetTemplate<'a> {
34*61046927SAndroid Build Coastguard Worker     pub display: &'a str,
35*61046927SAndroid Build Coastguard Worker }
36*61046927SAndroid Build Coastguard Worker 
37*61046927SAndroid Build Coastguard Worker /// A structure representing an Instruction Set Architecture (ISA),
38*61046927SAndroid Build Coastguard Worker /// containing bitsets and enums.
39*61046927SAndroid Build Coastguard Worker pub struct ISA<'a> {
40*61046927SAndroid Build Coastguard Worker     pub bitsets: IndexMap<&'a str, Bitset<'a>>,
41*61046927SAndroid Build Coastguard Worker     pub enums: IndexMap<&'a str, BitSetEnum<'a>>,
42*61046927SAndroid Build Coastguard Worker     pub templates: IndexMap<&'a str, BitsetTemplate<'a>>,
43*61046927SAndroid Build Coastguard Worker }
44*61046927SAndroid Build Coastguard Worker 
45*61046927SAndroid Build Coastguard Worker impl<'a> ISA<'a> {
46*61046927SAndroid Build Coastguard Worker     /// Creates a new `ISA` by loading bitsets and enums from a parsed XML document.
new(doc: &'a Document) -> Self47*61046927SAndroid Build Coastguard Worker     pub fn new(doc: &'a Document) -> Self {
48*61046927SAndroid Build Coastguard Worker         let mut isa = ISA {
49*61046927SAndroid Build Coastguard Worker             bitsets: IndexMap::new(),
50*61046927SAndroid Build Coastguard Worker             enums: IndexMap::new(),
51*61046927SAndroid Build Coastguard Worker             templates: IndexMap::new(),
52*61046927SAndroid Build Coastguard Worker         };
53*61046927SAndroid Build Coastguard Worker 
54*61046927SAndroid Build Coastguard Worker         isa.load_from_document(doc);
55*61046927SAndroid Build Coastguard Worker         isa
56*61046927SAndroid Build Coastguard Worker     }
57*61046927SAndroid Build Coastguard Worker 
58*61046927SAndroid Build Coastguard Worker     /// Collects metadata for a given bitset by walking the `extends` chain in reverse order.
collect_meta(&self, name: &'a str) -> HashMap<&'a str, &'a str>59*61046927SAndroid Build Coastguard Worker     pub fn collect_meta(&self, name: &'a str) -> HashMap<&'a str, &'a str> {
60*61046927SAndroid Build Coastguard Worker         let mut meta = HashMap::new();
61*61046927SAndroid Build Coastguard Worker         let mut chain = Vec::new();
62*61046927SAndroid Build Coastguard Worker         let mut current = Some(name);
63*61046927SAndroid Build Coastguard Worker 
64*61046927SAndroid Build Coastguard Worker         // Gather the chain of bitsets
65*61046927SAndroid Build Coastguard Worker         while let Some(item) = current {
66*61046927SAndroid Build Coastguard Worker             if let Some(bitset) = self.bitsets.get(item) {
67*61046927SAndroid Build Coastguard Worker                 chain.push(bitset);
68*61046927SAndroid Build Coastguard Worker                 current = bitset.extends;
69*61046927SAndroid Build Coastguard Worker             } else {
70*61046927SAndroid Build Coastguard Worker                 current = None;
71*61046927SAndroid Build Coastguard Worker             }
72*61046927SAndroid Build Coastguard Worker         }
73*61046927SAndroid Build Coastguard Worker 
74*61046927SAndroid Build Coastguard Worker         // Collect metadata in reverse order so children's metadata overwrites their parent's.
75*61046927SAndroid Build Coastguard Worker         for bitset in chain.into_iter().rev() {
76*61046927SAndroid Build Coastguard Worker             meta.extend(&bitset.meta);
77*61046927SAndroid Build Coastguard Worker         }
78*61046927SAndroid Build Coastguard Worker 
79*61046927SAndroid Build Coastguard Worker         meta
80*61046927SAndroid Build Coastguard Worker     }
81*61046927SAndroid Build Coastguard Worker 
82*61046927SAndroid Build Coastguard Worker     /// Loads bitsets and enums from a parsed XML document into the `ISA`.
load_from_document(&mut self, doc: &'a Document)83*61046927SAndroid Build Coastguard Worker     fn load_from_document(&mut self, doc: &'a Document) {
84*61046927SAndroid Build Coastguard Worker         doc.descendants()
85*61046927SAndroid Build Coastguard Worker             .filter(|node| node.is_element() && node.has_tag_name("template"))
86*61046927SAndroid Build Coastguard Worker             .for_each(|value| {
87*61046927SAndroid Build Coastguard Worker                 let name = value.attribute("name").unwrap();
88*61046927SAndroid Build Coastguard Worker                 let display = value.text().unwrap();
89*61046927SAndroid Build Coastguard Worker 
90*61046927SAndroid Build Coastguard Worker                 self.templates.insert(name, BitsetTemplate { display });
91*61046927SAndroid Build Coastguard Worker             });
92*61046927SAndroid Build Coastguard Worker 
93*61046927SAndroid Build Coastguard Worker         doc.descendants()
94*61046927SAndroid Build Coastguard Worker             .filter(|node| node.is_element() && node.has_tag_name("enum"))
95*61046927SAndroid Build Coastguard Worker             .for_each(|node| {
96*61046927SAndroid Build Coastguard Worker                 let values = node
97*61046927SAndroid Build Coastguard Worker                     .children()
98*61046927SAndroid Build Coastguard Worker                     .filter(|node| node.is_element() && node.has_tag_name("value"))
99*61046927SAndroid Build Coastguard Worker                     .map(|value| {
100*61046927SAndroid Build Coastguard Worker                         let display = value.attribute("display").unwrap();
101*61046927SAndroid Build Coastguard Worker                         let name = value.attribute("name");
102*61046927SAndroid Build Coastguard Worker 
103*61046927SAndroid Build Coastguard Worker                         BitSetEnumValue { display, name }
104*61046927SAndroid Build Coastguard Worker                     })
105*61046927SAndroid Build Coastguard Worker                     .collect();
106*61046927SAndroid Build Coastguard Worker 
107*61046927SAndroid Build Coastguard Worker                 let name = node.attribute("name").unwrap();
108*61046927SAndroid Build Coastguard Worker 
109*61046927SAndroid Build Coastguard Worker                 self.enums.insert(name, BitSetEnum { name, values });
110*61046927SAndroid Build Coastguard Worker             });
111*61046927SAndroid Build Coastguard Worker 
112*61046927SAndroid Build Coastguard Worker         doc.descendants()
113*61046927SAndroid Build Coastguard Worker             .filter(|node| node.is_element() && node.has_tag_name("bitset"))
114*61046927SAndroid Build Coastguard Worker             .for_each(|node| {
115*61046927SAndroid Build Coastguard Worker                 let name = node.attribute("name").unwrap();
116*61046927SAndroid Build Coastguard Worker                 let displayname = node.attribute("displayname");
117*61046927SAndroid Build Coastguard Worker                 let extends = node.attribute("extends");
118*61046927SAndroid Build Coastguard Worker                 let meta_nodes = node
119*61046927SAndroid Build Coastguard Worker                     .children()
120*61046927SAndroid Build Coastguard Worker                     .filter(|child| child.is_element() && child.has_tag_name("meta"));
121*61046927SAndroid Build Coastguard Worker 
122*61046927SAndroid Build Coastguard Worker                 // We can have multiple <meta> tags, which we need to combine.
123*61046927SAndroid Build Coastguard Worker                 let combined_meta: HashMap<_, _> = meta_nodes
124*61046927SAndroid Build Coastguard Worker                     .flat_map(|m| m.attributes())
125*61046927SAndroid Build Coastguard Worker                     .map(|attr| (attr.name(), attr.value()))
126*61046927SAndroid Build Coastguard Worker                     .collect();
127*61046927SAndroid Build Coastguard Worker 
128*61046927SAndroid Build Coastguard Worker                 self.bitsets.insert(
129*61046927SAndroid Build Coastguard Worker                     name,
130*61046927SAndroid Build Coastguard Worker                     Bitset {
131*61046927SAndroid Build Coastguard Worker                         name,
132*61046927SAndroid Build Coastguard Worker                         displayname,
133*61046927SAndroid Build Coastguard Worker                         extends,
134*61046927SAndroid Build Coastguard Worker                         meta: combined_meta,
135*61046927SAndroid Build Coastguard Worker                     },
136*61046927SAndroid Build Coastguard Worker                 );
137*61046927SAndroid Build Coastguard Worker             });
138*61046927SAndroid Build Coastguard Worker     }
139*61046927SAndroid Build Coastguard Worker }
140*61046927SAndroid Build Coastguard Worker 
141*61046927SAndroid Build Coastguard Worker #[cfg(test)]
142*61046927SAndroid Build Coastguard Worker mod tests {
143*61046927SAndroid Build Coastguard Worker     use super::*;
144*61046927SAndroid Build Coastguard Worker 
145*61046927SAndroid Build Coastguard Worker     #[test]
test_collect_meta()146*61046927SAndroid Build Coastguard Worker     fn test_collect_meta() {
147*61046927SAndroid Build Coastguard Worker         let mut isa = ISA {
148*61046927SAndroid Build Coastguard Worker             bitsets: IndexMap::new(),
149*61046927SAndroid Build Coastguard Worker             enums: IndexMap::new(),
150*61046927SAndroid Build Coastguard Worker             templates: IndexMap::new(),
151*61046927SAndroid Build Coastguard Worker         };
152*61046927SAndroid Build Coastguard Worker         isa.bitsets.insert(
153*61046927SAndroid Build Coastguard Worker             "bitset1",
154*61046927SAndroid Build Coastguard Worker             Bitset {
155*61046927SAndroid Build Coastguard Worker                 name: "bitset1",
156*61046927SAndroid Build Coastguard Worker                 extends: None,
157*61046927SAndroid Build Coastguard Worker                 meta: HashMap::from([("key1", "value1")]),
158*61046927SAndroid Build Coastguard Worker             },
159*61046927SAndroid Build Coastguard Worker         );
160*61046927SAndroid Build Coastguard Worker         isa.bitsets.insert(
161*61046927SAndroid Build Coastguard Worker             "bitset2",
162*61046927SAndroid Build Coastguard Worker             Bitset {
163*61046927SAndroid Build Coastguard Worker                 name: "bitset2",
164*61046927SAndroid Build Coastguard Worker                 extends: Some("bitset1"),
165*61046927SAndroid Build Coastguard Worker                 meta: HashMap::from([("key2", "value2")]),
166*61046927SAndroid Build Coastguard Worker             },
167*61046927SAndroid Build Coastguard Worker         );
168*61046927SAndroid Build Coastguard Worker         isa.bitsets.insert(
169*61046927SAndroid Build Coastguard Worker             "bitset3",
170*61046927SAndroid Build Coastguard Worker             Bitset {
171*61046927SAndroid Build Coastguard Worker                 name: "bitset3",
172*61046927SAndroid Build Coastguard Worker                 extends: Some("bitset2"),
173*61046927SAndroid Build Coastguard Worker                 meta: HashMap::from([("key3", "value3")]),
174*61046927SAndroid Build Coastguard Worker             },
175*61046927SAndroid Build Coastguard Worker         );
176*61046927SAndroid Build Coastguard Worker 
177*61046927SAndroid Build Coastguard Worker         let meta = isa.collect_meta("bitset3");
178*61046927SAndroid Build Coastguard Worker         assert_eq!(meta.get("key1"), Some(&"value1"));
179*61046927SAndroid Build Coastguard Worker         assert_eq!(meta.get("key2"), Some(&"value2"));
180*61046927SAndroid Build Coastguard Worker         assert_eq!(meta.get("key3"), Some(&"value3"));
181*61046927SAndroid Build Coastguard Worker     }
182*61046927SAndroid Build Coastguard Worker 
183*61046927SAndroid Build Coastguard Worker     #[test]
test_load_from_document()184*61046927SAndroid Build Coastguard Worker     fn test_load_from_document() {
185*61046927SAndroid Build Coastguard Worker         let xml_data = r#"
186*61046927SAndroid Build Coastguard Worker         <isa>
187*61046927SAndroid Build Coastguard Worker             <bitset name="bitset1">
188*61046927SAndroid Build Coastguard Worker                 <meta key1="value1"/>
189*61046927SAndroid Build Coastguard Worker                 <meta key2="value2"/>
190*61046927SAndroid Build Coastguard Worker             </bitset>
191*61046927SAndroid Build Coastguard Worker             <bitset name="bitset2" extends="bitset1"/>
192*61046927SAndroid Build Coastguard Worker             <enum name="enum1">
193*61046927SAndroid Build Coastguard Worker                 <value display="val1" val="0"/>
194*61046927SAndroid Build Coastguard Worker                 <value display="val2" val="1"/>
195*61046927SAndroid Build Coastguard Worker             </enum>
196*61046927SAndroid Build Coastguard Worker         </isa>
197*61046927SAndroid Build Coastguard Worker         "#;
198*61046927SAndroid Build Coastguard Worker 
199*61046927SAndroid Build Coastguard Worker         let doc = Document::parse(xml_data).unwrap();
200*61046927SAndroid Build Coastguard Worker         let isa = ISA::new(&doc);
201*61046927SAndroid Build Coastguard Worker 
202*61046927SAndroid Build Coastguard Worker         let bitset1 = isa.bitsets.get(&"bitset1").unwrap();
203*61046927SAndroid Build Coastguard Worker         assert_eq!(bitset1.name, "bitset1");
204*61046927SAndroid Build Coastguard Worker         assert_eq!(bitset1.meta.get("key1"), Some(&"value1"));
205*61046927SAndroid Build Coastguard Worker         assert_eq!(bitset1.meta.get("key2"), Some(&"value2"));
206*61046927SAndroid Build Coastguard Worker 
207*61046927SAndroid Build Coastguard Worker         let bitset2 = isa.bitsets.get(&"bitset2").unwrap();
208*61046927SAndroid Build Coastguard Worker         assert_eq!(bitset2.name, "bitset2");
209*61046927SAndroid Build Coastguard Worker         assert_eq!(bitset2.extends, Some("bitset1"));
210*61046927SAndroid Build Coastguard Worker 
211*61046927SAndroid Build Coastguard Worker         let enum1 = isa.enums.get(&"enum1").unwrap();
212*61046927SAndroid Build Coastguard Worker         assert_eq!(enum1.name, "enum1");
213*61046927SAndroid Build Coastguard Worker         assert_eq!(enum1.values.len(), 2);
214*61046927SAndroid Build Coastguard Worker         assert_eq!(enum1.values[0].display, "val1");
215*61046927SAndroid Build Coastguard Worker         assert_eq!(enum1.values[1].display, "val2");
216*61046927SAndroid Build Coastguard Worker     }
217*61046927SAndroid Build Coastguard Worker }
218