xref: /aosp_15_r20/external/mesa3d/src/etnaviv/isa/parser.rs (revision 6104692788411f58d303aa86923a9ff6ecaded22)
1 // Copyright © 2024 Igalia S.L.
2 // SPDX-License-Identifier: MIT
3 
4 use crate::util::EtnaAsmResultExt;
5 
6 use etnaviv_isa_proc::IsaParser;
7 use isa_bindings::*;
8 use pest::iterators::Pair;
9 use pest::Parser;
10 use std::fs;
11 use std::str::FromStr;
12 
13 #[derive(IsaParser)]
14 #[isa = "etnaviv.xml"]
15 #[static_rules_file = "static_rules.pest"]
16 struct Isa;
17 
get_child_rule(item: Pair<Rule>) -> Rule18 fn get_child_rule(item: Pair<Rule>) -> Rule {
19     item.into_inner().next().unwrap().as_rule()
20 }
21 
parse_pair<T: FromStr>(item: Pair<Rule>) -> T where T::Err: std::fmt::Debug,22 fn parse_pair<T: FromStr>(item: Pair<Rule>) -> T
23 where
24     T::Err: std::fmt::Debug,
25 {
26     item.as_str().parse::<T>().unwrap()
27 }
28 
fill_swizzle(item: Pair<Rule>) -> u3229 fn fill_swizzle(item: Pair<Rule>) -> u32 {
30     assert!(item.as_rule() == Rule::SrcSwizzle);
31 
32     item.into_inner()
33         .map(|comp| match comp.as_rule() {
34             Rule::Swiz => match comp.as_str() {
35                 "x" => 0,
36                 "y" => 1,
37                 "z" => 2,
38                 "w" => 3,
39                 _ => panic!("Unexpected swizzle {:?}", comp.as_str()),
40             },
41             _ => panic!("Unexpected rule {:?}", comp.as_rule()),
42         })
43         .enumerate()
44         .fold(0, |acc, (index, swiz_index)| {
45             acc | swiz_index << (2 * index)
46         })
47 }
48 
fill_destination(pair: Pair<Rule>, dest: &mut etna_inst_dst)49 fn fill_destination(pair: Pair<Rule>, dest: &mut etna_inst_dst) {
50     dest.set_use(1);
51 
52     for item in pair.into_inner() {
53         match item.as_rule() {
54             Rule::RegAddressingMode => {
55                 let rule = get_child_rule(item);
56                 dest.set_amode(isa_reg_addressing_mode::from_rule(rule));
57             }
58             Rule::Register => {
59                 dest.set_reg(parse_pair(item));
60             }
61             Rule::Wrmask => {
62                 let rule = get_child_rule(item);
63                 dest.set_write_mask(isa_wrmask::from_rule(rule));
64             }
65             _ => panic!("Unexpected rule {:?}", item.as_rule()),
66         }
67     }
68 }
69 
fill_mem_destination(pair: Pair<Rule>, dest: &mut etna_inst_dst)70 fn fill_mem_destination(pair: Pair<Rule>, dest: &mut etna_inst_dst) {
71     dest.set_use(1);
72 
73     for item in pair.into_inner() {
74         match item.as_rule() {
75             Rule::Wrmask => {
76                 let rule = get_child_rule(item);
77                 dest.set_write_mask(isa_wrmask::from_rule(rule));
78             }
79             _ => panic!("Unexpected rule {:?}", item.as_rule()),
80         }
81     }
82 }
83 
fill_tex(pair: Pair<Rule>, tex: &mut etna_inst_tex)84 fn fill_tex(pair: Pair<Rule>, tex: &mut etna_inst_tex) {
85     for item in pair.into_inner() {
86         match item.as_rule() {
87             Rule::Register => {
88                 let r = parse_pair(item);
89                 tex.set_id(r)
90             }
91             Rule::SrcSwizzle => {
92                 let bytes = fill_swizzle(item);
93                 tex.set_swiz(bytes);
94             }
95             _ => panic!("Unexpected rule {:?}", item.as_rule()),
96         }
97     }
98 }
99 
fill_source(pair: Pair<Rule>, src: &mut etna_inst_src, dual_16_mode: bool)100 fn fill_source(pair: Pair<Rule>, src: &mut etna_inst_src, dual_16_mode: bool) {
101     src.set_use(1);
102 
103     for item in pair.into_inner() {
104         match item.as_rule() {
105             Rule::Absolute => unsafe {
106                 src.__bindgen_anon_1.__bindgen_anon_1.set_abs(1);
107             },
108             Rule::Negate => unsafe {
109                 src.__bindgen_anon_1.__bindgen_anon_1.set_neg(1);
110             },
111             Rule::RegGroup => {
112                 let rule = get_child_rule(item);
113                 src.set_rgroup(isa_reg_group::from_rule(rule));
114             }
115             Rule::RegAddressingMode => {
116                 let rule = get_child_rule(item);
117                 unsafe {
118                     src.__bindgen_anon_1
119                         .__bindgen_anon_1
120                         .set_amode(isa_reg_addressing_mode::from_rule(rule));
121                 }
122             }
123             Rule::Register => {
124                 let r = parse_pair(item);
125                 unsafe {
126                     src.__bindgen_anon_1.__bindgen_anon_1.set_reg(r);
127                 }
128             }
129             Rule::Immediate_Minus_Nan => {
130                 src.set_rgroup(isa_reg_group::ISA_REG_GROUP_IMMED);
131 
132                 let imm_struct = unsafe { &mut src.__bindgen_anon_1.__bindgen_anon_2 };
133 
134                 imm_struct.set_imm_type(0);
135                 imm_struct.set_imm_val(0xfffff);
136             }
137             Rule::Immediate_float => {
138                 let value: f32 = parse_pair(item);
139                 let bits = value.to_bits();
140 
141                 assert!((bits & 0xfff) == 0); /* 12 lsb cut off */
142                 src.set_rgroup(isa_reg_group::ISA_REG_GROUP_IMMED);
143 
144                 let imm_type = if dual_16_mode { 3 } else { 0 };
145                 let imm_struct = unsafe { &mut src.__bindgen_anon_1.__bindgen_anon_2 };
146 
147                 imm_struct.set_imm_type(imm_type);
148                 imm_struct.set_imm_val(bits >> 12);
149             }
150             i_type @ (Rule::Immediate_int | Rule::Immediate_uint) => {
151                 let value = if i_type == Rule::Immediate_int {
152                     parse_pair::<i32>(item) as u32
153                 } else {
154                     parse_pair::<u32>(item)
155                 };
156 
157                 src.set_rgroup(isa_reg_group::ISA_REG_GROUP_IMMED);
158 
159                 let imm_struct = unsafe { &mut src.__bindgen_anon_1.__bindgen_anon_2 };
160                 imm_struct.set_imm_type(1);
161                 imm_struct.set_imm_val(value);
162             }
163             Rule::SrcSwizzle => {
164                 let bytes = fill_swizzle(item);
165                 unsafe {
166                     src.__bindgen_anon_1.__bindgen_anon_1.set_swiz(bytes);
167                 }
168             }
169             _ => panic!("Unexpected rule {:?}", item.as_rule()),
170         }
171     }
172 }
173 
process(input: Pair<Rule>, dual_16_mode: bool) -> Option<etna_inst>174 fn process(input: Pair<Rule>, dual_16_mode: bool) -> Option<etna_inst> {
175     // The assembler and disassembler are both using the
176     // 'full' form of the ISA which contains void's and
177     // use the HW ordering of instruction src arguments.
178 
179     if input.as_rule() == Rule::EOI {
180         return None;
181     }
182 
183     // Create instruction with sane defaults.
184     let mut instr = etna_inst::default();
185     instr.dst.set_write_mask(isa_wrmask::ISA_WRMASK_XYZW);
186 
187     instr.opcode = isa_opc::from_rule(input.as_rule());
188     let mut src_index = 0;
189 
190     for p in input.into_inner() {
191         match p.as_rule() {
192             Rule::Dst_full => {
193                 instr.set_dst_full(1);
194             }
195             Rule::Sat => {
196                 instr.set_sat(1);
197             }
198             Rule::Cond => {
199                 let rule = get_child_rule(p);
200                 instr.set_cond(isa_cond::from_rule(rule));
201             }
202             Rule::Skphp => {
203                 instr.set_skphp(1);
204             }
205             Rule::Pmode => {
206                 instr.set_pmode(1);
207             }
208             Rule::Denorm => {
209                 instr.set_denorm(1);
210             }
211             Rule::Local => {
212                 instr.set_local(1);
213             }
214             Rule::Left_shift => {
215                 let item = p.into_inner().next().unwrap();
216                 let amount = parse_pair(item);
217                 instr.set_left_shift(amount);
218             }
219             Rule::Type => {
220                 let rule = get_child_rule(p);
221                 instr.type_ = isa_type::from_rule(rule);
222             }
223             Rule::Thread => {
224                 let rule = get_child_rule(p);
225                 instr.set_thread(isa_thread::from_rule(rule));
226             }
227             Rule::Rounding => {
228                 let rule = get_child_rule(p);
229                 instr.rounding = isa_rounding::from_rule(rule);
230             }
231             Rule::DestVoid => {
232                 // Nothing to do
233             }
234             Rule::DstRegister => {
235                 fill_destination(p, &mut instr.dst);
236             }
237             Rule::DstMemAddr => {
238                 fill_mem_destination(p, &mut instr.dst);
239             }
240             Rule::SrcVoid => {
241                 // Nothing to do
242             }
243             Rule::SrcRegister => {
244                 fill_source(p, &mut instr.src[src_index], dual_16_mode);
245                 src_index += 1;
246             }
247             Rule::TexSrc => {
248                 fill_tex(p, &mut instr.tex);
249             }
250             Rule::Target => {
251                 let target = parse_pair(p);
252                 instr.imm = target;
253             }
254             _ => panic!("Unexpected rule {:?}", p.as_rule()),
255         }
256     }
257 
258     Some(instr)
259 }
260 
parse(rule: Rule, content: &str, dual_16_mode: bool, asm_result: &mut etna_asm_result)261 fn parse(rule: Rule, content: &str, dual_16_mode: bool, asm_result: &mut etna_asm_result) {
262     let result = Isa::parse(rule, content);
263 
264     match result {
265         Ok(program) => {
266             for line in program {
267                 if let Some(result) = process(line, dual_16_mode) {
268                     asm_result.append_instruction(result);
269                 }
270             }
271 
272             asm_result.success = true;
273         }
274         Err(e) => {
275             asm_result.set_error(&format!("{}", e));
276             asm_result.success = false;
277         }
278     }
279 }
280 
asm_process_str(string: &str, dual_16_mode: bool, asm_result: &mut etna_asm_result)281 pub fn asm_process_str(string: &str, dual_16_mode: bool, asm_result: &mut etna_asm_result) {
282     parse(Rule::instruction, string, dual_16_mode, asm_result)
283 }
284 
asm_process_file(file: &str, dual_16_mode: bool, asm_result: &mut etna_asm_result)285 pub fn asm_process_file(file: &str, dual_16_mode: bool, asm_result: &mut etna_asm_result) {
286     let content = fs::read_to_string(file).expect("cannot read file");
287 
288     parse(Rule::instructions, &content, dual_16_mode, asm_result)
289 }
290