dynasm\arch\aarch64/
debug.rs

1use super::ast::Modifier;
2use super::aarch64data::{Opdata, Matcher, Command, Relocation, SpecialComm};
3use crate::common::Size;
4
5use std::fmt::Write;
6
7
8#[cfg(feature = "dynasm_opmap")]
9pub fn create_opmap() -> String {
10    let mut s = String::new();
11
12    let mut mnemnonics: Vec<_> = super::aarch64data::mnemnonics().cloned().collect();
13    mnemnonics.sort();
14
15    for mnemnonic in mnemnonics {
16        // get the data for this mnemnonic
17        let data = super::aarch64data::get_mnemonic_data(mnemnonic).unwrap();
18        // format the data for the opmap docs
19        let formats = data.into_iter()
20            .map(|x| format_opdata(mnemnonic, x))
21            .flat_map(|x| x)
22            .map(|x| x.replace(">>> ", ""))
23            .collect::<Vec<_>>();
24
25        // push mnemnonic name as title
26        write!(s, "### {}\n```insref\n{}\n```\n", mnemnonic, formats.join("\n")).unwrap();
27    }
28    s
29}
30
31
32#[cfg(feature = "dynasm_extract")]
33pub fn extract_opmap() -> String {
34    let mut buf = Vec::new();
35
36    let mut mnemnonics: Vec<_> = super::aarch64data::mnemnonics().cloned().collect();
37    mnemnonics.sort();
38
39    for mnemnonic in mnemnonics {
40        // get the data for this mnemnonic
41        let data = super::aarch64data::get_mnemonic_data(mnemnonic).unwrap();
42
43        buf.extend(
44            data.into_iter()
45            .map(|x| extract_opdata(mnemnonic, x))
46            .flat_map(|x| x)
47        );
48    }
49
50    buf.join("\n")
51}
52
53
54pub fn format_opdata_list(name: &str, data: &[Opdata]) -> String {
55    let mut forms = Vec::new();
56
57    for data in data {
58        forms.extend(format_opdata(name, data));
59    }
60
61    forms.join("\n")
62}
63
64pub fn format_opdata(name: &str, data: &Opdata) -> Vec<String> {
65
66    let has_simd_full_width = data.matchers.iter().any(|m| match m {
67        Matcher::V(_) | Matcher::RegList(_, _) => true,
68        _ => false
69    });
70
71    let form_count = 1 + has_simd_full_width as u8;
72    let mut forms = Vec::new();
73
74    for i in 0 .. form_count {
75        let mut buf = format!(">>> {}", name);
76
77        let (constraints, names) = match constraints_and_names(data) {
78            Ok(o) => o,
79            Err(e) => panic!("Encountered a faulty op listing for {}: {}", name, e)
80        };
81
82        let mut first = true;
83        let mut after_dot = false;
84        let mut end_count = 0;
85        let mut names = &names[..];
86
87        for matcher in data.matchers {
88            if let Matcher::End = matcher {
89                end_count += 1;
90                buf.push_str(" {");
91                continue;
92            } else if let Matcher::Dot = matcher {
93                after_dot = true;
94                buf.push('.');
95                continue;
96            }
97
98            if first {
99                if !after_dot {
100                    buf.push(' ');
101                    first = false;
102                }
103                after_dot = false;
104            } else {
105                buf.push_str(", ");
106            }
107
108            let (arg_names, rest) = names.split_at(matcher.flatarg_count());
109            names = rest;
110
111            match matcher {
112                Matcher::Dot => (),
113                Matcher::Lit(s) => write!(buf, "{}", s).unwrap(),
114                Matcher::LitInt(v) => write!(buf, "{}", v).unwrap(),
115                Matcher::LitFloat(v) => write!(buf, "{}", v).unwrap(),
116                Matcher::Ident => write!(buf, "{}", arg_names[0]).unwrap(),
117                Matcher::Cond => write!(buf, "<cond>").unwrap(),
118                Matcher::Imm => write!(buf, "#{}", arg_names[0]).unwrap(),
119                Matcher::W =>   write!(buf, "W{}", arg_names[0]).unwrap(),
120                Matcher::X =>   write!(buf, "X{}", arg_names[0]).unwrap(),
121                Matcher::WSP => write!(buf, "W{}|WSP", arg_names[0]).unwrap(),
122                Matcher::XSP => write!(buf, "X{}|SP", arg_names[0]).unwrap(),
123                Matcher::B =>   write!(buf, "B{}", arg_names[0]).unwrap(),
124                Matcher::H =>   write!(buf, "H{}", arg_names[0]).unwrap(),
125                Matcher::S =>   write!(buf, "S{}", arg_names[0]).unwrap(),
126                Matcher::D =>   write!(buf, "D{}", arg_names[0]).unwrap(),
127                Matcher::Q =>   write!(buf, "Q{}", arg_names[0]).unwrap(),
128                Matcher::V(s) => {
129                    let width = if i == 0 { 16 } else { 8 };
130                    write!(buf, "V{}.{}{}", arg_names[0], size_to_string(*s), width / s.in_bytes()).unwrap();
131                },
132                Matcher::VStatic(s, c) => write!(buf, "V{}.{}{}", arg_names[0], size_to_string(*s), c).unwrap(),
133                Matcher::VElement(s) => write!(buf, "V{}.{}[{}]", arg_names[0], size_to_string(*s), arg_names[1]).unwrap(),
134                Matcher::VElementStatic(s, element) => write!(buf, "V{}.{}[{}]", arg_names[0], size_to_string(*s), element).unwrap(),
135                Matcher::VStaticElement(s, c) => write!(buf, "V{}.{}{}[{}]", arg_names[0], size_to_string(*s), c, arg_names[1]).unwrap(),
136                Matcher::RegList(a, s) => {
137                    let width = if i == 0 { 16 } else { 8 };
138                    write!(buf, "{{V{}.{}{} * {}}}", arg_names[0], size_to_string(*s), width / s.in_bytes(), a).unwrap();
139                },
140                Matcher::RegListStatic(a, s, c) => write!(buf, "{{V{}.{}{} * {}}}", arg_names[0], size_to_string(*s), c, a).unwrap(),
141                Matcher::RegListElement(a, s) =>   write!(buf, "{{V{}.{} * {}}}[{}]", arg_names[0], size_to_string(*s), a, arg_names[1]).unwrap(),
142                Matcher::Offset => buf.push_str(&arg_names[0]),
143                Matcher::RefBase =>   write!(buf, "[X{}|SP]", arg_names[0]).unwrap(),
144                Matcher::RefOffset => write!(buf, "[X{}|SP {{, #{} }} ]", arg_names[0], arg_names[1]).unwrap(),
145                Matcher::RefPre =>    write!(buf, "[X{}|SP, #{}]!", arg_names[0], arg_names[1]).unwrap(),
146                Matcher::RefIndex =>  write!(buf, "[X{}|SP, W{}|X{} {{ , UXTW|LSL|SXTW|SXTX {{ #{} }} }} ]", arg_names[0], arg_names[1], arg_names[1], arg_names[3]).unwrap(),
147                Matcher::LitMod(m) => {
148                    buf.push_str(m.as_str());
149                    if !m.expr_required() {
150                        write!(buf, " {{ #{} }}", arg_names[0]).unwrap();
151                    } else {
152                        write!(buf, " #{}", arg_names[0]).unwrap();
153                    }
154                },
155                Matcher::Mod(mods) => {
156                    let mut required = false;
157                    let mut unsigned_extends = String::new();
158                    let mut signed_extends   = String::new();
159                    let mut rest = Vec::new();
160                    for m in *mods {
161                        required = required || m.expr_required();
162                        match m {
163                            Modifier::LSL | Modifier::LSR | Modifier::ASR | Modifier::ROR | Modifier::MSL => rest.push(m.as_str()),
164                            Modifier::SXTX | Modifier::SXTW | Modifier::SXTH | Modifier::SXTB => signed_extends.push(m.as_str().chars().nth(3).unwrap()),
165                            Modifier::UXTX | Modifier::UXTW | Modifier::UXTH | Modifier::UXTB => unsigned_extends.push(m.as_str().chars().nth(3).unwrap()),
166                        }
167                    }
168                    if !unsigned_extends.is_empty() {
169                        if unsigned_extends.len() > 1 {
170                            unsigned_extends = format!("UXT[{}]", unsigned_extends);
171                        } else {
172                            unsigned_extends = format!("UXT{}", unsigned_extends);
173                        }
174                        rest.push(&unsigned_extends);
175                    }
176                    if !signed_extends.is_empty() {
177                        if signed_extends.len() > 1 {
178                            signed_extends = format!("SXT[{}]", signed_extends);
179                        } else {
180                            signed_extends = format!("SXT{}", signed_extends);
181                        }
182                        rest.push(&signed_extends);
183                    }
184                    buf.push_str(&rest.join("|"));
185
186                    if !required {
187                        write!(buf, " {{ #{} }}", arg_names[1]).unwrap();
188                    } else {
189                        write!(buf, " #{}", arg_names[1]).unwrap();
190                    }
191                },
192                Matcher::End => ()
193            }
194
195        }
196
197        for _ in 0 .. end_count {
198            buf.push_str(" }");
199        }
200
201        if let Some(c) = constraints {
202            let mut len = c.len() + buf.len();
203            while len < 100 {
204                buf.push(' ');
205                len += 1;
206            }
207            buf.push_str(&c);
208        }
209
210        forms.push(buf);
211    }
212
213    forms
214}
215
216pub fn size_to_string(size: Size) -> &'static str {
217    match size {
218        Size::BYTE => "B",
219        Size::B_2 => "H",
220        Size::B_4 => "S",
221        Size::B_8 => "D",
222        Size::B_16 => "Q",
223        _ => unimplemented!()
224    }
225}
226
227fn constraints_and_names(opdata: &Opdata) -> Result<(Option<String>, Vec<String>), &'static str> {
228    let data = group_opdata(opdata)?;
229    let constraints = format_constraints(&data);
230    let names = data.into_iter().map(|a| a.name.unwrap_or_else(|| "?".into())).collect();
231    Ok((constraints, names))
232}
233
234fn group_opdata(opdata: &Opdata) -> Result<Vec<ArgWithCommands>, &'static str> {
235    let args = flatten_matchers(opdata.matchers);
236    let (max_cursor, commands) = group_commands(opdata.commands);
237
238    if args.len() != max_cursor {
239        return Err("arg / command count mismatch");
240    }
241
242    let mut args: Vec<_> = args.into_iter().map(|(arg, can_be_default)| ArgWithCommands {
243        arg,
244        can_be_default,
245        commands: Vec::new(),
246        name: None
247    }).collect();
248
249    for (command, idx) in commands {
250        args[idx].commands.push(command);
251    }
252
253    // validate the commands - argtypes
254    check_command_sanity(&args)?;
255
256    name_args(&mut args);
257
258    Ok(args)
259}
260
261
262#[derive(Clone, Copy, PartialEq, Eq, Hash)]
263enum FlatArgTy {
264    Direct,
265    Immediate,
266    Modifier,
267    JumpTarget,
268    Lit
269}
270
271struct ArgWithCommands {
272    pub arg: FlatArgTy,
273    pub can_be_default: bool,
274    pub commands: Vec<Command>,
275    pub name: Option<String>,
276}
277
278/// Take a matcher array and return a vector of the types of flat arg each should produce
279fn flatten_matchers(matchers: &[Matcher]) -> Vec<(FlatArgTy, bool)> {
280    let mut args = Vec::new();
281    let mut default = false;
282
283    for matcher in matchers {
284        match matcher {
285            Matcher::Dot
286            | Matcher::Lit(_)
287            | Matcher::LitInt(_)
288            | Matcher::LitFloat(_) => (),
289            Matcher::Ident
290            | Matcher::Cond
291            | Matcher::Imm => args.push((FlatArgTy::Immediate, default)),
292            Matcher::W
293            | Matcher::X
294            | Matcher::WSP
295            | Matcher::XSP
296            | Matcher::B
297            | Matcher::H
298            | Matcher::S
299            | Matcher::D
300            | Matcher::Q => args.push((FlatArgTy::Direct, default)),
301            Matcher::V(_)
302            | Matcher::VStatic(_, _)
303            | Matcher::VElementStatic(_, _)
304            | Matcher::RegList(_, _)
305            | Matcher::RegListStatic(_, _, _) => args.push((FlatArgTy::Direct, default)),
306            Matcher::VElement(_)
307            | Matcher::VStaticElement(_, _)
308            | Matcher::RegListElement(_, _) => {
309                args.push((FlatArgTy::Direct, default));
310                args.push((FlatArgTy::Immediate, default));
311            },
312            Matcher::Offset => args.push((FlatArgTy::JumpTarget, default)),
313            Matcher::RefBase => args.push((FlatArgTy::Direct, default)),
314            Matcher::RefOffset => {
315                args.push((FlatArgTy::Direct, default));
316                args.push((FlatArgTy::Immediate, true));
317            },
318            Matcher::RefPre => {
319                args.push((FlatArgTy::Direct, default));
320                args.push((FlatArgTy::Immediate, default));
321            },
322            Matcher::RefIndex => {
323                args.push((FlatArgTy::Direct, default));
324                args.push((FlatArgTy::Direct, default));
325                args.push((FlatArgTy::Modifier, true));
326                args.push((FlatArgTy::Immediate, true));
327            },
328            Matcher::LitMod(_) => {
329                args.push((FlatArgTy::Immediate, true));
330            },
331            Matcher::Mod(_) => {
332                args.push((FlatArgTy::Modifier, default));
333                args.push((FlatArgTy::Immediate, true));
334            },
335            Matcher::End => default = true,
336        }
337    }
338    args
339}
340
341/// Take a commands slice and calculate the expected amount of args / a vec of command, argidx
342fn group_commands(commands: &[Command]) -> (usize, Vec<(Command, usize)>) {
343    let mut cursor = 0;
344    let mut command_idx = Vec::new();
345
346    for command in commands {
347        match command {
348            Command::A => {
349                cursor += 1;
350                continue;
351            },
352            Command::C => {
353                cursor -= 1;
354                continue;
355            },
356            Command::Rwidth(_) => {
357                continue;
358            },
359            _ => ()
360        }
361
362        command_idx.push((*command, cursor));
363        match command {
364            Command::R(_)
365            | Command::REven(_)
366            | Command::R4(_)
367            | Command::RNoZr(_)
368            | Command::RNext
369            | Command::Ubits(_, _)
370            | Command::Uscaled(_, _, _)
371            | Command::Ulist(_, _)
372            | Command::Urange(_, _, _)
373            | Command::Usubone(_, _)
374            | Command::Usubzero(_, _)
375            | Command::Usubmod(_, _)
376            | Command::Usum(_, _)
377            | Command::Ufields(_)
378            | Command::Sbits(_, _)
379            | Command::Sscaled(_, _,_)
380            | Command::Special(_, _)
381            | Command::Rotates(_)
382            | Command::ExtendsW(_)
383            | Command::ExtendsX(_)
384            | Command::Cond(_)
385            | Command::CondInv(_)
386            | Command::LitList(_, _)
387            | Command::Offset(_) => cursor += 1,
388            _ => ()
389        }
390    }
391
392    (cursor, command_idx)
393}
394
395/// checks if the commands for each arg type make sense
396fn check_command_sanity(args: &[ArgWithCommands]) -> Result<(), &'static str> {
397    for arg in args {
398        if arg.commands.is_empty() {
399            return Err("Arg with no commands")
400        }
401
402        for command in &arg.commands {
403            let check = match command {
404                Command::R(_)
405                | Command::REven(_)
406                | Command::R4(_)
407                | Command::RNoZr(_)
408                | Command::RNext => arg.arg == FlatArgTy::Direct,
409                Command::Ubits(_, _)
410                | Command::Uscaled(_, _, _)
411                | Command::Ulist(_, _)
412                | Command::Urange(_, _, _)
413                | Command::Usubone(_, _, )
414                | Command::Usubzero(_, _, )
415                | Command::Usubmod(_, _, )
416                | Command::Usum(_, _)
417                | Command::Ufields(_)
418                | Command::Sbits(_, _)
419                | Command::Sscaled(_, _,_)
420                | Command::CUbits(_)
421                | Command::CUsum(_)
422                | Command::CSscaled(_, _)
423                | Command::CUrange(_, _)
424                | Command::Uslice(_, _, _)
425                | Command::Sslice(_, _, _)
426                | Command::Special(_, _) => arg.arg == FlatArgTy::Immediate,
427                Command::Cond(_)
428                | Command::CondInv(_)
429                | Command::LitList(_, _) => arg.arg == FlatArgTy::Lit || arg.arg == FlatArgTy::Immediate,
430                Command::Offset(_) => arg.arg == FlatArgTy::JumpTarget,
431                Command::Rotates(_)
432                | Command::ExtendsW(_)
433                | Command::ExtendsX(_) => arg.arg == FlatArgTy::Modifier,
434                Command::A
435                | Command::C
436                | Command::Rwidth(_) => unreachable!()
437            };
438
439            if !check {
440                return Err("command / argtype mismatch");
441            }
442
443            let check = match command {
444                Command::R(_)
445                | Command::Ubits(_, _)
446                | Command::Uscaled(_, _, _)
447                | Command::Uslice(_, _, _)
448                | Command::Urange(_, _, _)
449                | Command::Ulist(_, _)
450                | Command::Ufields(_)
451                | Command::Sbits(_, _)
452                | Command::Sscaled(_, _, _)
453                | Command::Sslice(_, _, _)
454                | Command::CUbits(_)
455                | Command::CUsum(_)
456                | Command::CSscaled(_, _)
457                | Command::Rotates(_)
458                | Command::ExtendsW(_)
459                | Command::ExtendsX(_) => true,
460                Command::R4(_)
461                | Command::RNoZr(_)
462                | Command::REven(_)
463                | Command::RNext
464                | Command::Usubone(_, _)
465                | Command::Usubzero(_, _)
466                | Command::Usubmod(_, _)
467                | Command::Usum(_, _)
468                | Command::CUrange(_, _)
469                | Command::Special(_, _)
470                | Command::Cond(_)
471                | Command::CondInv(_)
472                | Command::LitList(_, _)
473                | Command::Offset(_) => !arg.can_be_default,
474                Command::A
475                | Command::C
476                | Command::Rwidth(_) => unreachable!()
477            };
478
479            if !check {
480                return Err("default mismatch");
481            }
482        }
483    }
484
485    Ok(())
486}
487
488/// assign names to the args being used
489fn name_args(args: &mut [ArgWithCommands]) {
490    // iirc no op uses more than 4 unconstrained literals / immediates
491    let reg_name_list = ["n", "m", "a", "b"];
492    let mut reg_name_idx = 0;
493    let imm_name_list = ["", "1", "2", "3"];
494    let mut imm_name_idx = 0;
495
496    for arg in args {
497        match arg.arg {
498            FlatArgTy::Direct => {
499                match &arg.commands[0] {
500                    Command::R(_)
501                    | Command::REven(_)
502                    | Command::RNoZr(_)
503                    | Command::R4(_) => {
504                        arg.name = Some(reg_name_list[reg_name_idx].to_string());
505                        reg_name_idx += 1;
506                    },
507                    Command::RNext => {
508                        arg.name = Some(format!("{}+1", reg_name_list[reg_name_idx - 1]));
509                    },
510                    _ => unreachable!()
511                }
512            },
513            FlatArgTy::Immediate => {
514                match &arg.commands[0] {
515                    Command::Cond(_)
516                    | Command::CondInv(_) => arg.name = None,
517                    Command::LitList(_, name) => arg.name = Some(name.trim_end_matches('S').to_lowercase()),
518                    Command::Ubits(_, _)
519                    | Command::Uscaled(_, _, _)
520                    | Command::Ulist(_, _)
521                    | Command::Urange(_, _, _)
522                    | Command::Usubone(_, _)
523                    | Command::Usubzero(_, _)
524                    | Command::Usubmod(_, _)
525                    | Command::Usum(_, _)
526                    | Command::Ufields(_)
527                    | Command::CUbits(_)
528                    | Command::CUsum(_)
529                    | Command::CUrange(_, _)
530                    | Command::Uslice(_, _, _) => {
531                        arg.name = Some(format!("uimm{}", imm_name_list[imm_name_idx]));
532                        imm_name_idx += 1;
533                    },
534                    Command::Sbits(_, _)
535                    | Command::Sscaled(_, _,_)
536                    | Command::CSscaled(_, _)
537                    | Command::Sslice(_, _, _) => {
538                        arg.name = Some(format!("simm{}", imm_name_list[imm_name_idx]));
539                        imm_name_idx += 1;
540                    },
541                    Command::Special(_, _) => {
542                        arg.name = Some(format!("imm{}", imm_name_list[imm_name_idx]));
543                        imm_name_idx += 1;
544                    },
545                    _ => unreachable!()
546                }
547            },
548            FlatArgTy::Modifier => arg.name = None,
549            FlatArgTy::JumpTarget => match &arg.commands[0] {
550                Command::Offset(_) => arg.name = Some("<offset>".to_string()),
551                _ => unreachable!()
552            },
553            FlatArgTy::Lit => match &arg.commands[0] {
554                Command::Cond(_)
555                | Command::CondInv(_) => arg.name = None,
556                Command::LitList(_, name) => arg.name = Some(name.trim_end_matches('S').to_lowercase()),
557                _ => unreachable!()
558            }
559        }
560    }
561}
562
563fn format_constraints(args: &[ArgWithCommands]) -> Option<String> {
564    let mut constraints = String::new();
565    let mut prevname = "?";
566
567    for arg in args {
568        if let Some(ref name) = arg.name {
569            emit_constraints(name, prevname, &arg.commands, &mut constraints);
570            prevname = name;
571        }
572    }
573
574    if constraints.is_empty() {
575        None
576    } else {
577        let len = constraints.len();
578        Some(format!(" ({})", &constraints[0 .. len - 2]))
579    }
580}
581
582fn emit_constraints(name: &str, prevname: &str, commands: &[Command], buf: &mut String) {
583    for command in commands {
584        match command {
585            Command::R4(_) => write!(buf, "{} is 0-15", name),
586            Command::RNoZr(_) => write!(buf, "{} is 0-30", name),
587            Command::REven(_) => write!(buf, "{} is even", name),
588            Command::Ubits(_, bits)
589            | Command::CUbits(bits) => write!(buf, "#{} <= {}", name, (1u32 << bits) - 1),
590            Command::Uscaled(_, bits, scale) => write!(buf, "#{} <= {}, #{} = {} * N", name, (1u32 << (bits + scale)) - 1, name, 1u32 << scale),
591            Command::Ulist(_, list) => {
592                let numbers = list.iter().map(|n| n.to_string()).collect::<Vec<_>>().join(", ");
593                write!(buf, "#{} = [{}]", name, numbers)
594            },
595            Command::Urange(_, min, max)
596            | Command::CUrange(min, max) => write!(buf, "{} <= #{} <= {}", min, name, max),
597            Command::Usubone(_, bits) => write!(buf, "1 <= #{} <= {}", name, (1u32 << bits)),
598            Command::Usubzero(_, bits) => write!(buf, "0 <= #{} <= {}", name, (1u32 << bits) - 1),
599            Command::Usubmod(_, bits) => write!(buf, "0 <= #{} <= {}", name, (1u32 << bits) - 1),
600            Command::Usum(_, bits)
601            | Command::CUsum(bits) => write!(buf, "1 <= #{} <= {} - {}", name, 1u32 << bits, prevname),
602            Command::Ufields(fields) => write!(buf, "#{} <= {}", name, (1u32 << fields.len()) - 1),
603            Command::Sbits(_, bits) => write!(buf, "-{} <= #{} <= {}", 1u32 << (bits - 1), name, (1u32 << (bits - 1)) - 1),
604            Command::Sscaled(_, bits, scale)
605            | Command::CSscaled(bits, scale) => write!(buf, "-{} <= #{} <= {}, #{} = {} * N", 1u32 << (bits + scale - 1), name, (1u32 << (bits + scale - 1)) - 1, name, 1u32 << scale),
606            Command::Special(_, SpecialComm::WIDE_IMMEDIATE_W)
607            | Command::Special(_, SpecialComm::WIDE_IMMEDIATE_X)
608            | Command::Special(_, SpecialComm::INVERTED_WIDE_IMMEDIATE_W)
609            | Command::Special(_, SpecialComm::INVERTED_WIDE_IMMEDIATE_X) => write!(buf, "#{} is a wide immediate", name),
610            Command::Special(_, SpecialComm::LOGICAL_IMMEDIATE_W)
611            | Command::Special(_, SpecialComm::LOGICAL_IMMEDIATE_X) => write!(buf, "#{} is a logical immediate", name),
612            Command::Special(_, SpecialComm::FLOAT_IMMEDIATE)
613            | Command::Special(_, SpecialComm::SPLIT_FLOAT_IMMEDIATE) => write!(buf, "#{} is a floating point immediate", name),
614            Command::Special(_, SpecialComm::STRETCHED_IMMEDIATE) => write!(buf, "#{} is a stretched immediate", name),
615            Command::Offset(Relocation::B) => write!(buf, "offset is 26 bit, 4-byte aligned"),
616            Command::Offset(Relocation::BCOND) => write!(buf, "offset is 19 bit, 4-byte aligned"),
617            Command::Offset(Relocation::ADR) => write!(buf, "offset is 21 bit"),
618            Command::Offset(Relocation::ADRP) => write!(buf, "offset is 21 bit, 4K-page aligned"),
619            Command::Offset(Relocation::TBZ) => write!(buf, "offset is 14 bit, 4-byte aligned"),
620            Command::Offset(Relocation::LITERAL32) => write!(buf, "offset is 32 bits"),
621            Command::Offset(Relocation::LITERAL64) => write!(buf, "offset is 64 bits"),
622            _ => continue
623        }.unwrap();
624
625        write!(buf, ", ").unwrap();
626        break;
627    }
628}
629
630#[cfg(feature = "dynasm_extract")]
631pub fn extract_opdata(name: &str, data: &Opdata) -> Vec<String> {
632
633    let has_simd_full_width = data.matchers.iter().any(|m| match m {
634        Matcher::V(_) | Matcher::RegList(_, _) => true,
635        _ => false
636    });
637
638    let form_count = 1 + has_simd_full_width as u8;
639    let mut forms = Vec::new();
640
641    for i in 0 .. form_count {
642        let mut buf = format!("\"{}", name);
643
644        let mut first = true;
645        let mut after_dot = false;
646        let mut end_count = 0;
647        let mut arg_idx = 0;
648
649        let grouped = group_opdata(data).unwrap();
650        let mut constraints = extract_constraints(&grouped);
651
652        for matcher in data.matchers {
653            if let Matcher::End = matcher {
654                end_count += 1;
655                buf.push_str(" <");
656                continue;
657            } else if let Matcher::Dot = matcher {
658                after_dot = true;
659                buf.push('.');
660                continue;
661            }
662
663            if first {
664                if !after_dot {
665                    buf.push(' ');
666                    first = false;
667                }
668                after_dot = false;
669            } else {
670                buf.push_str(", ");
671            }
672
673            match matcher {
674                Matcher::Dot => (),
675                Matcher::Lit(s) => write!(buf, "{}", s).unwrap(),
676                Matcher::LitInt(v) => write!(buf, "{}", v).unwrap(),
677                Matcher::LitFloat(v) => write!(buf, "{:.5}", v).unwrap(),
678                Matcher::Ident
679                | Matcher::Cond => write!(buf, "<Ident,{}>", arg_idx).unwrap(),
680                Matcher::Imm => write!(buf, "<Imm,{}>", arg_idx).unwrap(),
681                Matcher::W =>   write!(buf, "<W,{}>", arg_idx).unwrap(),
682                Matcher::X =>   write!(buf, "<X,{}>", arg_idx).unwrap(),
683                Matcher::WSP => write!(buf, "<WSP,{}>", arg_idx).unwrap(),
684                Matcher::XSP => write!(buf, "<XSP,{}>", arg_idx).unwrap(),
685                Matcher::B =>   write!(buf, "<B,{}>", arg_idx).unwrap(),
686                Matcher::H =>   write!(buf, "<H,{}>", arg_idx).unwrap(),
687                Matcher::S =>   write!(buf, "<S,{}>", arg_idx).unwrap(),
688                Matcher::D =>   write!(buf, "<D,{}>", arg_idx).unwrap(),
689                Matcher::Q =>   write!(buf, "<Q,{}>", arg_idx).unwrap(),
690                Matcher::V(s) => {
691                    let width = if i == 0 { 16 } else { 8 };
692                    write!(buf, "<V,{}>.{}{}", arg_idx, size_to_string(*s), width / s.in_bytes()).unwrap();
693                },
694                Matcher::VStatic(s, c) => write!(buf, "<V,{}>.{}{}", arg_idx, size_to_string(*s), c).unwrap(),
695                Matcher::VElement(s) => write!(buf, "<V,{}>.{}[<Imm,{}>]", arg_idx, size_to_string(*s), arg_idx + 1).unwrap(),
696                Matcher::VElementStatic(s, element) => write!(buf, "<V,{}>.{}[{}]", arg_idx, size_to_string(*s), element).unwrap(),
697                Matcher::VStaticElement(s, c) => write!(buf, "<V,{}>.{}{}[<Imm,{}>]", arg_idx, size_to_string(*s), c, arg_idx + 1).unwrap(),
698                Matcher::RegList(a, s) => {
699                    let width = if i == 0 { 16 } else { 8 };
700                    write!(buf, "{{<V,{}>.{}{} * {}}}", arg_idx, size_to_string(*s), width / s.in_bytes(), a).unwrap();
701                },
702                Matcher::RegListStatic(a, s, c) => write!(buf, "{{<V,{}>.{}{} * {}}}", arg_idx, size_to_string(*s), c, a).unwrap(),
703                Matcher::RegListElement(a, s) =>   write!(buf, "{{<V,{}>.{} * {}}}[<Imm,{}>]", arg_idx, size_to_string(*s), a, arg_idx + 1).unwrap(),
704                Matcher::Offset => write!(buf, "<Off,{}>", arg_idx).unwrap(),
705                Matcher::RefBase =>   write!(buf, "[<XSP,{}>]", arg_idx).unwrap(),
706                Matcher::RefOffset => write!(buf, "[<XSP,{}> <, <Imm,{}> > ]", arg_idx, arg_idx + 1).unwrap(),
707                Matcher::RefPre =>    write!(buf, "[<XSP,{}>, <Imm,{}>]!", arg_idx, arg_idx + 1).unwrap(),
708                Matcher::RefIndex => {
709                    constraints.push(format!("{}: ModWX()", arg_idx + 2));
710                    write!(buf, "[<XSP,{}>, <WX,{}> < , <Mod,{}> < <Imm,{}> > > ]", arg_idx, arg_idx + 1, arg_idx + 2, arg_idx + 3).unwrap();
711                },
712                Matcher::LitMod(m) => {
713                    buf.push_str(m.as_str());
714                    if !m.expr_required() {
715                        write!(buf, " {{ <Imm,{}> }}", arg_idx).unwrap();
716                    } else {
717                        write!(buf, " <Imm,{}>", arg_idx).unwrap();
718                    }
719                },
720                Matcher::Mod(mods) => {
721                    let mut required = false;
722                    let mut options = Vec::new();
723                    for m in *mods {
724                        required = required || m.expr_required();
725                        options.push(format!("\"{}\"", m.as_str()));
726                    }
727
728                    constraints.push(format!("{}: List({})", arg_idx, options.join(", ")));
729
730                    if !required {
731                        write!(buf, "<Mod,{}> < <Imm,{}> >", arg_idx, arg_idx + 1).unwrap();
732                    } else {
733                        write!(buf, "<Mod,{}> <Imm,{}>", arg_idx, arg_idx + 1).unwrap();
734                    }
735                },
736                Matcher::End => ()
737            }
738
739            arg_idx += matcher.flatarg_count();
740        }
741
742        for _ in 0 .. end_count {
743            buf.push_str(" >");
744        }
745
746        write!(buf, "\"\t {{{}}}", constraints.join(", ")).unwrap();
747
748        forms.push(buf);
749    }
750
751    forms
752}
753
754#[cfg(feature = "dynasm_extract")]
755fn extract_constraints(args: &[ArgWithCommands]) -> Vec<String> {
756    use super::aarch64data::{COND_MAP, SPECIAL_IDENT_MAP};
757
758    let mut constraints = Vec::new();
759    for (i, arg) in args.iter().enumerate() {
760        for command in &arg.commands {
761            let constraint = match command {
762                Command::R(_) => format!("R(32)"),
763                Command::REven(_) => format!("R(32, 2)"),
764                Command::RNoZr(_) => format!("R(31)"),
765                Command::R4(_) => format!("R(16)"),
766                Command::RNext => format!("RNext()"),
767                Command::Ubits(_, bits)
768                | Command::CUbits(bits) => format!("Range(0, {}, 1)", 1u32 << bits),
769                Command::Uscaled(_, bits, scale) => format!("Range(0, {}, {})", 1u32 << (bits + scale), 1u32 << scale),
770                Command::Ulist(_, list) => {
771                    let numbers = list.iter().map(|n| n.to_string()).collect::<Vec<_>>().join(", ");
772                    format!("List({})", numbers)
773                },
774                Command::Urange(_, min, max)
775                | Command::CUrange(min, max) => format!("Range({}, {}+1, 1)", min, max),
776                Command::Usubone(_, bits) => format!("Range(1, {}+1, 1)", 1u32 << bits),
777                Command::Usubzero(_, bits) => format!("Range(0, {}, 1)",  1u32 << bits),
778                Command::Usubmod(_, bits) => format!("Range(0, {}, 1)", 1u32 << bits),
779                Command::Usum(_, bits)
780                | Command::CUsum(bits) => format!("Range2(1, {}+1, 1)", 1u32 << bits),
781                Command::Ufields(fields) => format!("Range(0, {}, 1)", 1u32 << fields.len()),
782                Command::Sbits(_, bits) => format!("Range(-{}, {}, 1)", 1u32 << (bits - 1), 1u32 << (bits - 1)),
783                Command::Sscaled(_, bits, scale)
784                | Command::CSscaled(bits, scale) => format!("Range(-{}, {}, {})", 1u32 << (bits + scale - 1), 1u32 << (bits + scale - 1), 1u32 << scale),
785                Command::Special(_, SpecialComm::WIDE_IMMEDIATE_W) => format!("Special('wide_w')"),
786                | Command::Special(_, SpecialComm::WIDE_IMMEDIATE_X) => format!("Special('wide_x')"),
787                | Command::Special(_, SpecialComm::INVERTED_WIDE_IMMEDIATE_W) => format!("Special('inverted_w')"),
788                | Command::Special(_, SpecialComm::INVERTED_WIDE_IMMEDIATE_X) => format!("Special('inverted_x')"),
789                Command::Special(_, SpecialComm::LOGICAL_IMMEDIATE_W) => format!("Special('logical_w')"),
790                | Command::Special(_, SpecialComm::LOGICAL_IMMEDIATE_X) => format!("Special('logical_x')"),
791                Command::Special(_, SpecialComm::FLOAT_IMMEDIATE)
792                | Command::Special(_, SpecialComm::SPLIT_FLOAT_IMMEDIATE) => format!("Special('float')"),
793                Command::Special(_, SpecialComm::STRETCHED_IMMEDIATE) => format!("Special('stretched')"),
794                Command::Offset(Relocation::B) => format!("Range(-{}, {}, {})", 1<<27, 1<<27, 4),
795                Command::Offset(Relocation::BCOND) => format!("Range(-{}, {}, {})", 1<<18, 1<<18, 4),
796                Command::Offset(Relocation::ADR) => format!("Range(-{}, {}, {})", 1<<20, 1<<20, 1),
797                Command::Offset(Relocation::ADRP) => format!("Range(-{}, {}, {})", 1u64<<32, 1u64<<32, 4096),
798                Command::Offset(Relocation::TBZ) => format!("Range(-{}, {}, {})", 1<<15, 1<<15, 4),
799                Command::Offset(Relocation::LITERAL32) => format!("Range(-{}, {}, {})", 1<<31, 1<<31, 1),
800                Command::Offset(Relocation::LITERAL64) => format!("Range(-{}, {}, {})", 1u64<<63, 1u64<<63, 1),
801                Command::Cond(_) => {
802                    let keys: Vec<_> = COND_MAP.keys().map(|k| format!("\"{}\"", k)).collect();
803                    format!("List({})", keys.join(", "))
804                },
805                Command::CondInv(_) => {
806                    let keys: Vec<_> = COND_MAP.iter().filter_map(|(k, v)| if *v < 14 { Some(format!("\"{}\"", k)) } else { None }).collect();
807                    format!("List({})", keys.join(", "))
808                },
809                Command::LitList(_, name) => {
810                    let keys: Vec<_> = SPECIAL_IDENT_MAP[name].keys().map(|k| format!("\"{}\"", k)).collect();
811                    format!("List({})", keys.join(", "))
812                }
813                _ => continue
814            };
815            constraints.push(format!("{}: {}", i, constraint));
816
817            break;
818        }
819    }
820    constraints
821}