iced_x86/formatter/
mod.rs

1// SPDX-License-Identifier: MIT
2// Copyright (C) 2018-present iced project and contributors
3
4#[cfg(any(feature = "gas", feature = "intel", feature = "masm", feature = "nasm"))]
5mod enums;
6mod enums_shared;
7#[cfg(feature = "fast_fmt")]
8mod fast;
9#[cfg(any(feature = "gas", feature = "intel", feature = "masm", feature = "nasm"))]
10mod fmt_consts;
11#[cfg(any(feature = "gas", feature = "intel", feature = "masm", feature = "nasm"))]
12mod fmt_opt_provider;
13#[cfg(any(feature = "gas", feature = "intel", feature = "masm", feature = "nasm"))]
14mod fmt_opts;
15#[cfg(any(feature = "gas", feature = "intel", feature = "masm", feature = "nasm"))]
16mod fmt_utils;
17#[cfg(any(feature = "gas", feature = "intel", feature = "masm", feature = "nasm", feature = "fast_fmt"))]
18mod fmt_utils_all;
19#[cfg(feature = "gas")]
20mod gas;
21#[cfg(feature = "intel")]
22mod intel;
23#[cfg(feature = "masm")]
24mod masm;
25#[cfg(feature = "nasm")]
26mod nasm;
27#[cfg(any(feature = "gas", feature = "intel", feature = "masm", feature = "nasm"))]
28mod num_fmt;
29#[cfg(any(feature = "gas", feature = "intel", feature = "masm", feature = "nasm"))]
30mod num_fmt_opts;
31#[cfg(any(feature = "gas", feature = "intel", feature = "masm", feature = "nasm"))]
32mod pseudo_ops;
33mod regs_tbl;
34#[cfg(any(feature = "gas", feature = "intel", feature = "masm", feature = "nasm"))]
35mod regs_tbl_ls;
36#[cfg(any(feature = "gas", feature = "intel", feature = "masm", feature = "nasm"))]
37mod string_output;
38mod strings_data;
39#[cfg(any(feature = "gas", feature = "intel", feature = "masm", feature = "nasm"))]
40mod strings_tbl;
41mod symres;
42#[cfg(test)]
43pub(crate) mod tests;
44
45#[cfg(any(feature = "gas", feature = "intel", feature = "masm", feature = "nasm"))]
46pub use crate::formatter::enums::*;
47pub use crate::formatter::enums_shared::*;
48#[cfg(feature = "fast_fmt")]
49pub use crate::formatter::fast::*;
50#[cfg(any(feature = "gas", feature = "intel", feature = "masm", feature = "nasm"))]
51pub use crate::formatter::fmt_opt_provider::*;
52#[cfg(any(feature = "gas", feature = "intel", feature = "masm", feature = "nasm"))]
53pub use crate::formatter::fmt_opts::*;
54#[cfg(feature = "gas")]
55pub use crate::formatter::gas::*;
56#[cfg(feature = "intel")]
57pub use crate::formatter::intel::*;
58#[cfg(feature = "masm")]
59pub use crate::formatter::masm::*;
60#[cfg(feature = "nasm")]
61pub use crate::formatter::nasm::*;
62#[cfg(any(feature = "gas", feature = "intel", feature = "masm", feature = "nasm"))]
63use crate::formatter::num_fmt::NumberFormatter;
64#[cfg(any(feature = "gas", feature = "intel", feature = "masm", feature = "nasm"))]
65pub use crate::formatter::num_fmt_opts::*;
66pub use crate::formatter::symres::*;
67use crate::*;
68use alloc::string::String;
69use alloc::vec::Vec;
70
71#[cfg(any(feature = "gas", feature = "intel", feature = "masm"))]
72#[allow(deprecated)]
73const REGISTER_ST: Register = Register::DontUse0;
74
75#[cfg(any(feature = "gas", feature = "intel", feature = "masm", feature = "nasm"))]
76fn r_to_r16(reg: Register) -> Register {
77	if Register::EAX <= reg && reg <= Register::R15 {
78		Register::try_from((((reg as u32 - Register::AX as u32) & 0xF) + Register::AX as u32) as usize).unwrap_or(reg)
79	} else {
80		reg
81	}
82}
83
84#[cfg(any(feature = "gas", feature = "intel", feature = "masm", feature = "nasm"))]
85fn r64_to_r32(reg: Register) -> Register {
86	if Register::RAX <= reg && reg <= Register::R15 {
87		Register::try_from((reg as u32 - Register::RAX as u32 + Register::EAX as u32) as usize).unwrap_or(reg)
88	} else {
89		reg
90	}
91}
92
93#[derive(Debug, Default, Clone)]
94#[cfg(any(feature = "gas", feature = "intel", feature = "masm", feature = "nasm"))]
95struct FormatterString {
96	lower: String,
97	upper: String,
98}
99
100#[cfg(any(feature = "gas", feature = "intel", feature = "masm", feature = "nasm"))]
101impl FormatterString {
102	#[must_use]
103	fn new(lower: String) -> Self {
104		debug_assert_eq!(lower.to_lowercase(), lower);
105		Self { upper: lower.to_uppercase(), lower }
106	}
107
108	#[must_use]
109	fn with_strings(strings: Vec<String>) -> Vec<Self> {
110		strings.into_iter().map(FormatterString::new).collect()
111	}
112
113	#[must_use]
114	fn new_str(lower: &str) -> Self {
115		debug_assert_eq!(lower.to_lowercase(), lower);
116		Self { lower: String::from(lower), upper: lower.to_uppercase() }
117	}
118
119	#[must_use]
120	#[inline]
121	fn len(&self) -> usize {
122		self.lower.len()
123	}
124
125	#[cfg(any(feature = "gas", feature = "intel", feature = "nasm"))]
126	#[must_use]
127	#[inline]
128	fn is_default(&self) -> bool {
129		self.lower.is_empty()
130	}
131
132	#[must_use]
133	#[inline]
134	fn get(&self, upper: bool) -> &str {
135		if upper {
136			&self.upper
137		} else {
138			&self.lower
139		}
140	}
141}
142
143/// Used by a [`Formatter`] to write all text. `String` also implements this trait.
144///
145/// The only method that must be implemented is [`write()`], all other methods call it if they're not overridden.
146///
147/// [`Formatter`]: trait.Formatter.html
148/// [`write()`]: #tymethod.write
149#[cfg(any(feature = "gas", feature = "intel", feature = "masm", feature = "nasm"))]
150pub trait FormatterOutput {
151	/// Writes text and text kind
152	///
153	/// # Arguments
154	///
155	/// - `text`: Text
156	/// - `kind`: Text kind
157	fn write(&mut self, text: &str, kind: FormatterTextKind);
158
159	/// Writes a prefix
160	///
161	/// # Arguments
162	///
163	/// - `instruction`: Instruction
164	/// - `text`: Prefix text
165	/// - `prefix`: Prefix
166	#[inline]
167	#[allow(unused_variables)]
168	fn write_prefix(&mut self, instruction: &Instruction, text: &str, prefix: PrefixKind) {
169		self.write(text, FormatterTextKind::Prefix);
170	}
171
172	/// Writes a mnemonic (see [`Instruction::mnemonic()`])
173	///
174	/// [`Instruction::mnemonic()`]: struct.Instruction.html#method.mnemonic
175	///
176	/// - `instruction`: Instruction
177	/// - `text`: Mnemonic text
178	#[inline]
179	#[allow(unused_variables)]
180	fn write_mnemonic(&mut self, instruction: &Instruction, text: &str) {
181		self.write(text, FormatterTextKind::Mnemonic);
182	}
183
184	/// Writes a number
185	///
186	/// # Arguments
187	///
188	/// - `instruction`: Instruction
189	/// - `operand`: Operand number, 0-based. This is a formatter operand and isn't necessarily the same as an instruction operand.
190	/// - `instruction_operand`: Instruction operand number, 0-based, or `None` if it's an operand created by the formatter.
191	/// - `text`: Number text
192	/// - `value`: Value
193	/// - `number_kind`: Number kind
194	/// - `kind`: Text kind
195	#[inline]
196	#[allow(clippy::too_many_arguments)]
197	#[allow(unused_variables)]
198	fn write_number(
199		&mut self, instruction: &Instruction, operand: u32, instruction_operand: Option<u32>, text: &str, value: u64, number_kind: NumberKind,
200		kind: FormatterTextKind,
201	) {
202		self.write(text, kind);
203	}
204
205	/// Writes a decorator
206	///
207	/// # Arguments
208	///
209	/// - `instruction`: Instruction
210	/// - `operand`: Operand number, 0-based. This is a formatter operand and isn't necessarily the same as an instruction operand.
211	/// - `instruction_operand`: Instruction operand number, 0-based, or `None` if it's an operand created by the formatter.
212	/// - `text`: Decorator text
213	/// - `decorator`: Decorator
214	#[inline]
215	#[allow(unused_variables)]
216	fn write_decorator(&mut self, instruction: &Instruction, operand: u32, instruction_operand: Option<u32>, text: &str, decorator: DecoratorKind) {
217		self.write(text, FormatterTextKind::Decorator);
218	}
219
220	/// Writes a register
221	///
222	/// # Arguments
223	///
224	/// - `instruction`: Instruction
225	/// - `operand`: Operand number, 0-based. This is a formatter operand and isn't necessarily the same as an instruction operand.
226	/// - `instruction_operand`: Instruction operand number, 0-based, or `None` if it's an operand created by the formatter.
227	/// - `text`: Register text
228	/// - `register`: Register
229	#[inline]
230	#[allow(unused_variables)]
231	fn write_register(&mut self, instruction: &Instruction, operand: u32, instruction_operand: Option<u32>, text: &str, register: Register) {
232		self.write(text, FormatterTextKind::Register);
233	}
234
235	/// Writes a symbol
236	///
237	/// # Arguments
238	///
239	/// - `instruction`: Instruction
240	/// - `operand`: Operand number, 0-based. This is a formatter operand and isn't necessarily the same as an instruction operand.
241	/// - `instruction_operand`: Instruction operand number, 0-based, or `None` if it's an operand created by the formatter.
242	/// - `address`: Address
243	/// - `symbol`: Symbol
244	#[inline]
245	#[allow(unused_variables)]
246	fn write_symbol(&mut self, instruction: &Instruction, operand: u32, instruction_operand: Option<u32>, address: u64, symbol: &SymbolResult<'_>) {
247		match symbol.text {
248			SymResTextInfo::Text(ref part) => {
249				let s = match &part.text {
250					&SymResString::Str(s) => s,
251					SymResString::String(s) => s.as_str(),
252				};
253				self.write(s, part.color);
254			}
255
256			SymResTextInfo::TextVec(v) => {
257				for part in v {
258					let s = match &part.text {
259						&SymResString::Str(s) => s,
260						SymResString::String(s) => s.as_str(),
261					};
262					self.write(s, part.color);
263				}
264			}
265		}
266	}
267}
268
269#[cfg(any(feature = "gas", feature = "intel", feature = "masm", feature = "nasm"))]
270struct FormatterOutputMethods;
271#[cfg(any(feature = "gas", feature = "intel", feature = "masm", feature = "nasm"))]
272impl FormatterOutputMethods {
273	#[allow(clippy::too_many_arguments)]
274	fn write1(
275		output: &mut dyn FormatterOutput, instruction: &Instruction, operand: u32, instruction_operand: Option<u32>, options: &FormatterOptions,
276		number_formatter: &mut NumberFormatter, number_options: &NumberFormattingOptions<'_>, address: u64, symbol: &SymbolResult<'_>,
277		show_symbol_address: bool,
278	) {
279		FormatterOutputMethods::write2(
280			output,
281			instruction,
282			operand,
283			instruction_operand,
284			options,
285			number_formatter,
286			number_options,
287			address,
288			symbol,
289			show_symbol_address,
290			true,
291			false,
292		);
293	}
294
295	#[allow(clippy::too_many_arguments)]
296	fn write2(
297		output: &mut dyn FormatterOutput, instruction: &Instruction, operand: u32, instruction_operand: Option<u32>, options: &FormatterOptions,
298		number_formatter: &mut NumberFormatter, number_options: &NumberFormattingOptions<'_>, address: u64, symbol: &SymbolResult<'_>,
299		show_symbol_address: bool, write_minus_if_signed: bool, spaces_between_op: bool,
300	) {
301		let mut displ = address.wrapping_sub(symbol.address) as i64;
302		if (symbol.flags & SymbolFlags::SIGNED) != 0 {
303			if write_minus_if_signed {
304				output.write("-", FormatterTextKind::Operator);
305			}
306			displ = displ.wrapping_neg();
307		}
308		output.write_symbol(instruction, operand, instruction_operand, address, symbol);
309		let mut number_kind: NumberKind;
310		if displ != 0 {
311			if spaces_between_op {
312				output.write(" ", FormatterTextKind::Text);
313			}
314			let orig_displ = displ as u64;
315			if displ < 0 {
316				output.write("-", FormatterTextKind::Operator);
317				displ = displ.wrapping_neg();
318				if displ <= i8::MAX as i64 + 1 {
319					number_kind = NumberKind::Int8;
320				} else if displ <= i16::MAX as i64 + 1 {
321					number_kind = NumberKind::Int16;
322				} else if displ <= i32::MAX as i64 + 1 {
323					number_kind = NumberKind::Int32;
324				} else {
325					number_kind = NumberKind::Int64;
326				}
327			} else {
328				output.write("+", FormatterTextKind::Operator);
329				if displ <= i8::MAX as i64 {
330					number_kind = NumberKind::Int8;
331				} else if displ <= i16::MAX as i64 {
332					number_kind = NumberKind::Int16;
333				} else if displ <= i32::MAX as i64 {
334					number_kind = NumberKind::Int32;
335				} else {
336					number_kind = NumberKind::Int64;
337				}
338			}
339			if spaces_between_op {
340				output.write(" ", FormatterTextKind::Text);
341			}
342			let s = number_formatter.format_u64_zeros(options, number_options, displ as u64, false);
343			output.write_number(instruction, operand, instruction_operand, s, orig_displ, number_kind, FormatterTextKind::Number);
344		}
345		if show_symbol_address {
346			output.write(" ", FormatterTextKind::Text);
347			output.write("(", FormatterTextKind::Punctuation);
348			let s = if address <= u16::MAX as u64 {
349				number_kind = NumberKind::UInt16;
350				number_formatter.format_u16_zeros(options, number_options, address as u16, true)
351			} else if address <= u32::MAX as u64 {
352				number_kind = NumberKind::UInt32;
353				number_formatter.format_u32_zeros(options, number_options, address as u32, true)
354			} else {
355				number_kind = NumberKind::UInt64;
356				number_formatter.format_u64_zeros(options, number_options, address, true)
357			};
358			output.write_number(instruction, operand, instruction_operand, s, address, number_kind, FormatterTextKind::Number);
359			output.write(")", FormatterTextKind::Punctuation);
360		}
361	}
362}
363
364/// Formats instructions
365///
366/// This trait is sealed and cannot be implemented by your own types.
367#[cfg(any(feature = "gas", feature = "intel", feature = "masm", feature = "nasm"))]
368pub trait Formatter: private::Sealed {
369	/// Formats the whole instruction: prefixes, mnemonic, operands
370	///
371	/// # Arguments
372	///
373	/// - `instruction`: Instruction
374	/// - `output`: Output, eg. a `String`
375	fn format(&mut self, instruction: &Instruction, output: &mut dyn FormatterOutput);
376
377	/// Gets the formatter options (immutable)
378	#[must_use]
379	fn options(&self) -> &FormatterOptions;
380
381	/// Gets the formatter options (mutable)
382	#[must_use]
383	fn options_mut(&mut self) -> &mut FormatterOptions;
384
385	/// Formats the mnemonic and any prefixes
386	///
387	/// # Arguments
388	///
389	/// - `instruction`: Instruction
390	/// - `output`: Output, eg. a `String`
391	#[inline]
392	fn format_mnemonic(&mut self, instruction: &Instruction, output: &mut dyn FormatterOutput) {
393		self.format_mnemonic_options(instruction, output, FormatMnemonicOptions::NONE);
394	}
395
396	/// Formats the mnemonic and/or any prefixes
397	///
398	/// # Arguments
399	///
400	/// - `instruction`: Instruction
401	/// - `output`: Output, eg. a `String`
402	/// - `options`: Options, see [`FormatMnemonicOptions`]
403	///
404	/// [`FormatMnemonicOptions`]: struct.FormatMnemonicOptions.html
405	fn format_mnemonic_options(&mut self, instruction: &Instruction, output: &mut dyn FormatterOutput, options: u32);
406
407	/// Gets the number of operands that will be formatted. A formatter can add and remove operands
408	///
409	/// # Arguments
410	///
411	/// - `instruction`: Instruction
412	#[must_use]
413	fn operand_count(&mut self, instruction: &Instruction) -> u32;
414
415	/// Returns the operand access but only if it's an operand added by the formatter. If it's an
416	/// operand that is part of [`Instruction`], you should call eg. [`InstructionInfoFactory::info()`].
417	///
418	/// # Arguments
419	///
420	/// - `instruction`: Instruction
421	/// - `operand`: Operand number, 0-based. This is a formatter operand and isn't necessarily the same as an instruction operand. See [`operand_count()`]
422	///
423	/// # Errors
424	///
425	/// This fails if `operand` is invalid.
426	///
427	/// [`Instruction`]: struct.Instruction.html
428	/// [`InstructionInfoFactory::info()`]: struct.InstructionInfoFactory.html#method.info
429	/// [`operand_count()`]: #tymethod.operand_count
430	#[cfg(feature = "instr_info")]
431	fn op_access(&mut self, instruction: &Instruction, operand: u32) -> Result<Option<OpAccess>, IcedError>;
432
433	/// Converts a formatter operand index to an instruction operand index. Returns `None` if it's an operand added by the formatter
434	///
435	/// # Arguments
436	///
437	/// - `instruction`: Instruction
438	/// - `operand`: Operand number, 0-based. This is a formatter operand and isn't necessarily the same as an instruction operand. See [`operand_count()`]
439	///
440	/// # Errors
441	///
442	/// This fails if `operand` is invalid.
443	///
444	/// [`operand_count()`]: #tymethod.operand_count
445	fn get_instruction_operand(&mut self, instruction: &Instruction, operand: u32) -> Result<Option<u32>, IcedError>;
446
447	/// Converts an instruction operand index to a formatter operand index. Returns `None` if the instruction operand isn't used by the formatter
448	///
449	/// # Arguments
450	///
451	/// - `instruction`: Instruction
452	/// - `instruction_operand`: Instruction operand
453	///
454	/// # Errors
455	///
456	/// This fails if `instruction_operand` is invalid.
457	fn get_formatter_operand(&mut self, instruction: &Instruction, instruction_operand: u32) -> Result<Option<u32>, IcedError>;
458
459	/// Formats an operand. This is a formatter operand and not necessarily a real instruction operand.
460	/// A formatter can add and remove operands.
461	///
462	/// # Arguments
463	///
464	/// - `instruction`: Instruction
465	/// - `output`: Output, eg. a `String`
466	/// - `operand`: Operand number, 0-based. This is a formatter operand and isn't necessarily the same as an instruction operand. See [`operand_count()`]
467	///
468	/// # Errors
469	///
470	/// This fails if `operand` is invalid.
471	///
472	/// [`operand_count()`]: #tymethod.operand_count
473	fn format_operand(&mut self, instruction: &Instruction, output: &mut dyn FormatterOutput, operand: u32) -> Result<(), IcedError>;
474
475	/// Formats an operand separator
476	///
477	/// # Arguments
478	///
479	/// - `instruction`: Instruction
480	/// - `output`: Output, eg. a `String`
481	fn format_operand_separator(&mut self, instruction: &Instruction, output: &mut dyn FormatterOutput);
482
483	/// Formats all operands
484	///
485	/// # Arguments
486	///
487	/// - `instruction`: Instruction
488	/// - `output`: Output, eg. a `String`
489	fn format_all_operands(&mut self, instruction: &Instruction, output: &mut dyn FormatterOutput);
490
491	/// Formats a register
492	///
493	/// # Arguments
494	///
495	/// - `register`: Register
496	#[must_use]
497	fn format_register(&mut self, register: Register) -> &str;
498
499	/// Formats a `i8`
500	///
501	/// # Arguments
502	///
503	/// - `value`: Value
504	#[must_use]
505	fn format_i8(&mut self, value: i8) -> &str;
506
507	/// Formats a `i16`
508	///
509	/// # Arguments
510	///
511	/// - `value`: Value
512	#[must_use]
513	fn format_i16(&mut self, value: i16) -> &str;
514
515	/// Formats a `i32`
516	///
517	/// # Arguments
518	///
519	/// - `value`: Value
520	#[must_use]
521	fn format_i32(&mut self, value: i32) -> &str;
522
523	/// Formats a `i64`
524	///
525	/// # Arguments
526	///
527	/// - `value`: Value
528	#[must_use]
529	fn format_i64(&mut self, value: i64) -> &str;
530
531	/// Formats a `u8`
532	///
533	/// # Arguments
534	///
535	/// - `value`: Value
536	#[must_use]
537	fn format_u8(&mut self, value: u8) -> &str;
538
539	/// Formats a `u16`
540	///
541	/// # Arguments
542	///
543	/// - `value`: Value
544	#[must_use]
545	fn format_u16(&mut self, value: u16) -> &str;
546
547	/// Formats a `u32`
548	///
549	/// # Arguments
550	///
551	/// - `value`: Value
552	#[must_use]
553	fn format_u32(&mut self, value: u32) -> &str;
554
555	/// Formats a `u64`
556	///
557	/// # Arguments
558	///
559	/// - `value`: Value
560	#[must_use]
561	fn format_u64(&mut self, value: u64) -> &str;
562
563	/// Formats a `i8`
564	///
565	/// # Arguments
566	///
567	/// - `value`: Value
568	/// - `number_options`: Options
569	#[must_use]
570	fn format_i8_options(&mut self, value: i8, number_options: &NumberFormattingOptions<'_>) -> &str;
571
572	/// Formats a `i16`
573	///
574	/// # Arguments
575	///
576	/// - `value`: Value
577	/// - `number_options`: Options
578	#[must_use]
579	fn format_i16_options(&mut self, value: i16, number_options: &NumberFormattingOptions<'_>) -> &str;
580
581	/// Formats a `i32`
582	///
583	/// # Arguments
584	///
585	/// - `value`: Value
586	/// - `number_options`: Options
587	#[must_use]
588	fn format_i32_options(&mut self, value: i32, number_options: &NumberFormattingOptions<'_>) -> &str;
589
590	/// Formats a `i64`
591	///
592	/// # Arguments
593	///
594	/// - `value`: Value
595	/// - `number_options`: Options
596	#[must_use]
597	fn format_i64_options(&mut self, value: i64, number_options: &NumberFormattingOptions<'_>) -> &str;
598
599	/// Formats a `u8`
600	///
601	/// # Arguments
602	///
603	/// - `value`: Value
604	/// - `number_options`: Options
605	#[must_use]
606	fn format_u8_options(&mut self, value: u8, number_options: &NumberFormattingOptions<'_>) -> &str;
607
608	/// Formats a `u16`
609	///
610	/// # Arguments
611	///
612	/// - `value`: Value
613	/// - `number_options`: Options
614	#[must_use]
615	fn format_u16_options(&mut self, value: u16, number_options: &NumberFormattingOptions<'_>) -> &str;
616
617	/// Formats a `u32`
618	///
619	/// # Arguments
620	///
621	/// - `value`: Value
622	/// - `number_options`: Options
623	#[must_use]
624	fn format_u32_options(&mut self, value: u32, number_options: &NumberFormattingOptions<'_>) -> &str;
625
626	/// Formats a `u64`
627	///
628	/// # Arguments
629	///
630	/// - `value`: Value
631	/// - `number_options`: Options
632	#[must_use]
633	fn format_u64_options(&mut self, value: u64, number_options: &NumberFormattingOptions<'_>) -> &str;
634}
635
636#[cfg(any(feature = "gas", feature = "intel", feature = "masm", feature = "nasm"))]
637mod private {
638	pub trait Sealed {}
639	#[cfg(feature = "gas")]
640	impl Sealed for crate::GasFormatter {}
641	#[cfg(feature = "intel")]
642	impl Sealed for crate::IntelFormatter {}
643	#[cfg(feature = "masm")]
644	impl Sealed for crate::MasmFormatter {}
645	#[cfg(feature = "nasm")]
646	impl Sealed for crate::NasmFormatter {}
647}
648
649#[allow(clippy::manual_map)] // It's wrong
650fn to_owned<'a>(sym_res: Option<SymbolResult<'_>>, vec: &'a mut Vec<SymResTextPart<'a>>) -> Option<SymbolResult<'a>> {
651	match sym_res {
652		None => None,
653		Some(sym_res) => Some(sym_res.to_owned(vec)),
654	}
655}
656
657#[cfg(any(feature = "gas", feature = "intel", feature = "masm", feature = "nasm"))]
658fn get_mnemonic_cc<'a>(options: &FormatterOptions, cc_index: u32, mnemonics: &'a [FormatterString]) -> &'a FormatterString {
659	use crate::iced_constants::IcedConstants;
660	let index = match cc_index {
661		// o
662		0 => {
663			debug_assert_eq!(mnemonics.len(), 1);
664			0
665		}
666		// no
667		1 => {
668			debug_assert_eq!(mnemonics.len(), 1);
669			0
670		}
671		// b, c, nae
672		2 => {
673			debug_assert_eq!(mnemonics.len(), IcedConstants::CC_B_ENUM_COUNT);
674			options.cc_b() as usize
675		}
676		// ae, nb, nc
677		3 => {
678			debug_assert_eq!(mnemonics.len(), IcedConstants::CC_AE_ENUM_COUNT);
679			options.cc_ae() as usize
680		}
681		// e, z
682		4 => {
683			debug_assert_eq!(mnemonics.len(), IcedConstants::CC_E_ENUM_COUNT);
684			options.cc_e() as usize
685		}
686		// ne, nz
687		5 => {
688			debug_assert_eq!(mnemonics.len(), IcedConstants::CC_NE_ENUM_COUNT);
689			options.cc_ne() as usize
690		}
691		// be, na
692		6 => {
693			debug_assert_eq!(mnemonics.len(), IcedConstants::CC_BE_ENUM_COUNT);
694			options.cc_be() as usize
695		}
696		// a, nbe
697		7 => {
698			debug_assert_eq!(mnemonics.len(), IcedConstants::CC_A_ENUM_COUNT);
699			options.cc_a() as usize
700		}
701		// s
702		8 => {
703			debug_assert_eq!(mnemonics.len(), 1);
704			0
705		}
706		// ns
707		9 => {
708			debug_assert_eq!(mnemonics.len(), 1);
709			0
710		}
711		// p, pe
712		10 => {
713			debug_assert_eq!(mnemonics.len(), IcedConstants::CC_P_ENUM_COUNT);
714			options.cc_p() as usize
715		}
716		// np, po
717		11 => {
718			debug_assert_eq!(mnemonics.len(), IcedConstants::CC_NP_ENUM_COUNT);
719			options.cc_np() as usize
720		}
721		// l, nge
722		12 => {
723			debug_assert_eq!(mnemonics.len(), IcedConstants::CC_L_ENUM_COUNT);
724			options.cc_l() as usize
725		}
726		// ge, nl
727		13 => {
728			debug_assert_eq!(mnemonics.len(), IcedConstants::CC_GE_ENUM_COUNT);
729			options.cc_ge() as usize
730		}
731		// le, ng
732		14 => {
733			debug_assert_eq!(mnemonics.len(), IcedConstants::CC_LE_ENUM_COUNT);
734			options.cc_le() as usize
735		}
736		// g, nle
737		15 => {
738			debug_assert_eq!(mnemonics.len(), IcedConstants::CC_G_ENUM_COUNT);
739			options.cc_g() as usize
740		}
741		_ => unreachable!(),
742	};
743	debug_assert!(index < mnemonics.len());
744	&mnemonics[index]
745}