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 let data = super::aarch64data::get_mnemonic_data(mnemnonic).unwrap();
18 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 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 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 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
278fn 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
341fn 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
395fn 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
488fn name_args(args: &mut [ArgWithCommands]) {
490 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}