1use crate::regs::PhysReg;
43
44use Arg::{Imm, Label, Mem, Named, Reg, Symbol, Through, Xmm};
45use Width::{Byte, Long, Quad, Word};
46
47#[derive(Debug, Clone, Copy, PartialEq, Eq)]
49pub enum Width {
50 Byte,
52 Word,
54 Long,
56 Quad,
58}
59
60impl Width {
61 #[must_use]
63 pub fn index(self) -> usize {
64 match self {
65 Byte => 0,
66 Word => 1,
67 Long => 2,
68 Quad => 3,
69 }
70 }
71}
72
73#[derive(Debug, Clone, Copy, PartialEq, Eq)]
75pub enum Arg {
76 Reg(u8, Width),
78 Xmm(u8),
91 Named(&'static str),
98 Imm,
100 Mem,
102 Symbol,
104 Through,
121 Label,
123}
124
125#[derive(Debug, Clone, Copy, PartialEq, Eq)]
127pub struct Written {
128 pub mnemonic: &'static str,
130 pub args: &'static [Arg],
132}
133
134const fn spell(mnemonic: &'static str, args: &'static [Arg]) -> Written {
136 Written { mnemonic, args }
137}
138
139static CMP_8: [Arg; 2] = [Reg(2, Byte), Reg(1, Byte)];
143static CMP_16: [Arg; 2] = [Reg(2, Word), Reg(1, Word)];
144static CMP_32: [Arg; 2] = [Reg(2, Long), Reg(1, Long)];
145static CMP_64: [Arg; 2] = [Reg(2, Quad), Reg(1, Quad)];
146static SET: [Arg; 1] = [Reg(0, Byte)];
148
149static UCOMI: [Arg; 2] = [Xmm(2), Xmm(1)];
152static UCOMI_BOTH: [Arg; 2] = [Xmm(3), Xmm(2)];
153static SET_SPARE: [Arg; 1] = [Reg(1, Byte)];
156static COMBINE: [Arg; 2] = [Reg(1, Byte), Reg(0, Byte)];
157
158static DIVISOR_8: [Arg; 1] = [Reg(3, Byte)];
161static DIVISOR_16: [Arg; 1] = [Reg(3, Word)];
162static DIVISOR_32: [Arg; 1] = [Reg(3, Long)];
163static DIVISOR_64: [Arg; 1] = [Reg(3, Quad)];
164
165static CLEAR_FOR_QUOTIENT: [Arg; 2] = [Reg(1, Long), Reg(1, Long)];
171static CLEAR_FOR_REMAINDER: [Arg; 2] = [Reg(0, Long), Reg(0, Long)];
172
173static WIDEN_FOR_QUOTIENT: [Arg; 2] = [Reg(2, Byte), Reg(0, Long)];
178static WIDEN_FOR_REMAINDER: [Arg; 2] = [Reg(2, Byte), Reg(1, Long)];
179static HIGH_HALF: [Arg; 2] = [Named("ah"), Reg(0, Byte)];
180
181static TEXT: &[(&str, &[Written])] = &[
191 ("mov_ri_8", &[spell("movb", &[Imm, Reg(0, Byte)])]),
194 ("mov_ri_16", &[spell("movw", &[Imm, Reg(0, Word)])]),
195 ("mov_ri_32", &[spell("movl", &[Imm, Reg(0, Long)])]),
196 ("mov_ri_64", &[spell("movq", &[Imm, Reg(0, Quad)])]),
197 ("add_rr_8", &[spell("addb", &[Reg(2, Byte), Reg(0, Byte)])]),
200 ("add_rr_16", &[spell("addw", &[Reg(2, Word), Reg(0, Word)])]),
201 ("add_rr_32", &[spell("addl", &[Reg(2, Long), Reg(0, Long)])]),
202 ("add_rr_64", &[spell("addq", &[Reg(2, Quad), Reg(0, Quad)])]),
203 ("sub_rr_8", &[spell("subb", &[Reg(2, Byte), Reg(0, Byte)])]),
204 ("sub_rr_16", &[spell("subw", &[Reg(2, Word), Reg(0, Word)])]),
205 ("sub_rr_32", &[spell("subl", &[Reg(2, Long), Reg(0, Long)])]),
206 ("sub_rr_64", &[spell("subq", &[Reg(2, Quad), Reg(0, Quad)])]),
207 ("and_rr_8", &[spell("andb", &[Reg(2, Byte), Reg(0, Byte)])]),
208 ("and_rr_16", &[spell("andw", &[Reg(2, Word), Reg(0, Word)])]),
209 ("and_rr_32", &[spell("andl", &[Reg(2, Long), Reg(0, Long)])]),
210 ("and_rr_64", &[spell("andq", &[Reg(2, Quad), Reg(0, Quad)])]),
211 ("or_rr_8", &[spell("orb", &[Reg(2, Byte), Reg(0, Byte)])]),
212 ("or_rr_16", &[spell("orw", &[Reg(2, Word), Reg(0, Word)])]),
213 ("or_rr_32", &[spell("orl", &[Reg(2, Long), Reg(0, Long)])]),
214 ("or_rr_64", &[spell("orq", &[Reg(2, Quad), Reg(0, Quad)])]),
215 ("xor_rr_8", &[spell("xorb", &[Reg(2, Byte), Reg(0, Byte)])]),
216 ("xor_rr_16", &[spell("xorw", &[Reg(2, Word), Reg(0, Word)])]),
217 ("xor_rr_32", &[spell("xorl", &[Reg(2, Long), Reg(0, Long)])]),
218 ("xor_rr_64", &[spell("xorq", &[Reg(2, Quad), Reg(0, Quad)])]),
219 ("imul_rr_8", &[spell("imull", &[Reg(2, Long), Reg(0, Long)])]),
224 ("imul_rr_16", &[spell("imulw", &[Reg(2, Word), Reg(0, Word)])]),
225 ("imul_rr_32", &[spell("imull", &[Reg(2, Long), Reg(0, Long)])]),
226 ("imul_rr_64", &[spell("imulq", &[Reg(2, Quad), Reg(0, Quad)])]),
227 ("add_ri_8", &[spell("addb", &[Imm, Reg(0, Byte)])]),
229 ("add_ri_16", &[spell("addw", &[Imm, Reg(0, Word)])]),
230 ("add_ri_32", &[spell("addl", &[Imm, Reg(0, Long)])]),
231 ("add_ri_64", &[spell("addq", &[Imm, Reg(0, Quad)])]),
232 ("sub_ri_8", &[spell("subb", &[Imm, Reg(0, Byte)])]),
233 ("sub_ri_16", &[spell("subw", &[Imm, Reg(0, Word)])]),
234 ("sub_ri_32", &[spell("subl", &[Imm, Reg(0, Long)])]),
235 ("sub_ri_64", &[spell("subq", &[Imm, Reg(0, Quad)])]),
236 ("and_ri_8", &[spell("andb", &[Imm, Reg(0, Byte)])]),
237 ("and_ri_16", &[spell("andw", &[Imm, Reg(0, Word)])]),
238 ("and_ri_32", &[spell("andl", &[Imm, Reg(0, Long)])]),
239 ("and_ri_64", &[spell("andq", &[Imm, Reg(0, Quad)])]),
240 ("or_ri_8", &[spell("orb", &[Imm, Reg(0, Byte)])]),
241 ("or_ri_16", &[spell("orw", &[Imm, Reg(0, Word)])]),
242 ("or_ri_32", &[spell("orl", &[Imm, Reg(0, Long)])]),
243 ("or_ri_64", &[spell("orq", &[Imm, Reg(0, Quad)])]),
244 ("xor_ri_8", &[spell("xorb", &[Imm, Reg(0, Byte)])]),
245 ("xor_ri_16", &[spell("xorw", &[Imm, Reg(0, Word)])]),
246 ("xor_ri_32", &[spell("xorl", &[Imm, Reg(0, Long)])]),
247 ("xor_ri_64", &[spell("xorq", &[Imm, Reg(0, Quad)])]),
248 ("imul_ri_8", &[spell("imull", &[Imm, Reg(1, Long), Reg(0, Long)])]),
251 ("imul_ri_16", &[spell("imulw", &[Imm, Reg(1, Word), Reg(0, Word)])]),
252 ("imul_ri_32", &[spell("imull", &[Imm, Reg(1, Long), Reg(0, Long)])]),
253 ("imul_ri_64", &[spell("imulq", &[Imm, Reg(1, Quad), Reg(0, Quad)])]),
254 ("neg_r_8", &[spell("negb", &[Reg(0, Byte)])]),
256 ("neg_r_16", &[spell("negw", &[Reg(0, Word)])]),
257 ("neg_r_32", &[spell("negl", &[Reg(0, Long)])]),
258 ("neg_r_64", &[spell("negq", &[Reg(0, Quad)])]),
259 ("not_r_8", &[spell("notb", &[Reg(0, Byte)])]),
260 ("not_r_16", &[spell("notw", &[Reg(0, Word)])]),
261 ("not_r_32", &[spell("notl", &[Reg(0, Long)])]),
262 ("not_r_64", &[spell("notq", &[Reg(0, Quad)])]),
263 ("idiv_quo_8", &[spell("cbtw", &[]), spell("idivb", &DIVISOR_8)]),
267 ("idiv_quo_16", &[spell("cwtd", &[]), spell("idivw", &DIVISOR_16)]),
268 ("idiv_quo_32", &[spell("cltd", &[]), spell("idivl", &DIVISOR_32)]),
269 ("idiv_quo_64", &[spell("cqto", &[]), spell("idivq", &DIVISOR_64)]),
270 ("idiv_rem_8", &[spell("cbtw", &[]), spell("idivb", &DIVISOR_8), spell("movb", &HIGH_HALF)]),
271 ("idiv_rem_16", &[spell("cwtd", &[]), spell("idivw", &DIVISOR_16)]),
272 ("idiv_rem_32", &[spell("cltd", &[]), spell("idivl", &DIVISOR_32)]),
273 ("idiv_rem_64", &[spell("cqto", &[]), spell("idivq", &DIVISOR_64)]),
274 ("div_quo_8", &[spell("movzbl", &WIDEN_FOR_QUOTIENT), spell("divb", &DIVISOR_8)]),
275 ("div_quo_16", &[spell("xorl", &CLEAR_FOR_QUOTIENT), spell("divw", &DIVISOR_16)]),
276 ("div_quo_32", &[spell("xorl", &CLEAR_FOR_QUOTIENT), spell("divl", &DIVISOR_32)]),
277 ("div_quo_64", &[spell("xorl", &CLEAR_FOR_QUOTIENT), spell("divq", &DIVISOR_64)]),
278 (
279 "div_rem_8",
280 &[
281 spell("movzbl", &WIDEN_FOR_REMAINDER),
282 spell("divb", &DIVISOR_8),
283 spell("movb", &HIGH_HALF),
284 ],
285 ),
286 ("div_rem_16", &[spell("xorl", &CLEAR_FOR_REMAINDER), spell("divw", &DIVISOR_16)]),
287 ("div_rem_32", &[spell("xorl", &CLEAR_FOR_REMAINDER), spell("divl", &DIVISOR_32)]),
288 ("div_rem_64", &[spell("xorl", &CLEAR_FOR_REMAINDER), spell("divq", &DIVISOR_64)]),
289 ("shl_ri_8", &[spell("shlb", &[Imm, Reg(0, Byte)])]),
291 ("shl_ri_16", &[spell("shlw", &[Imm, Reg(0, Word)])]),
292 ("shl_ri_32", &[spell("shll", &[Imm, Reg(0, Long)])]),
293 ("shl_ri_64", &[spell("shlq", &[Imm, Reg(0, Quad)])]),
294 ("shr_ri_8", &[spell("shrb", &[Imm, Reg(0, Byte)])]),
295 ("shr_ri_16", &[spell("shrw", &[Imm, Reg(0, Word)])]),
296 ("shr_ri_32", &[spell("shrl", &[Imm, Reg(0, Long)])]),
297 ("shr_ri_64", &[spell("shrq", &[Imm, Reg(0, Quad)])]),
298 ("sar_ri_8", &[spell("sarb", &[Imm, Reg(0, Byte)])]),
299 ("sar_ri_16", &[spell("sarw", &[Imm, Reg(0, Word)])]),
300 ("sar_ri_32", &[spell("sarl", &[Imm, Reg(0, Long)])]),
301 ("sar_ri_64", &[spell("sarq", &[Imm, Reg(0, Quad)])]),
302 ("shl_rcl_8", &[spell("shlb", &[Reg(2, Byte), Reg(0, Byte)])]),
305 ("shl_rcl_16", &[spell("shlw", &[Reg(2, Byte), Reg(0, Word)])]),
306 ("shl_rcl_32", &[spell("shll", &[Reg(2, Byte), Reg(0, Long)])]),
307 ("shl_rcl_64", &[spell("shlq", &[Reg(2, Byte), Reg(0, Quad)])]),
308 ("shr_rcl_8", &[spell("shrb", &[Reg(2, Byte), Reg(0, Byte)])]),
309 ("shr_rcl_16", &[spell("shrw", &[Reg(2, Byte), Reg(0, Word)])]),
310 ("shr_rcl_32", &[spell("shrl", &[Reg(2, Byte), Reg(0, Long)])]),
311 ("shr_rcl_64", &[spell("shrq", &[Reg(2, Byte), Reg(0, Quad)])]),
312 ("sar_rcl_8", &[spell("sarb", &[Reg(2, Byte), Reg(0, Byte)])]),
313 ("sar_rcl_16", &[spell("sarw", &[Reg(2, Byte), Reg(0, Word)])]),
314 ("sar_rcl_32", &[spell("sarl", &[Reg(2, Byte), Reg(0, Long)])]),
315 ("sar_rcl_64", &[spell("sarq", &[Reg(2, Byte), Reg(0, Quad)])]),
316 ("cmp_set_e_8", &[spell("cmpb", &CMP_8), spell("sete", &SET)]),
320 ("cmp_set_e_16", &[spell("cmpw", &CMP_16), spell("sete", &SET)]),
321 ("cmp_set_e_32", &[spell("cmpl", &CMP_32), spell("sete", &SET)]),
322 ("cmp_set_e_64", &[spell("cmpq", &CMP_64), spell("sete", &SET)]),
323 ("cmp_set_ne_8", &[spell("cmpb", &CMP_8), spell("setne", &SET)]),
324 ("cmp_set_ne_16", &[spell("cmpw", &CMP_16), spell("setne", &SET)]),
325 ("cmp_set_ne_32", &[spell("cmpl", &CMP_32), spell("setne", &SET)]),
326 ("cmp_set_ne_64", &[spell("cmpq", &CMP_64), spell("setne", &SET)]),
327 ("cmp_set_l_8", &[spell("cmpb", &CMP_8), spell("setl", &SET)]),
328 ("cmp_set_l_16", &[spell("cmpw", &CMP_16), spell("setl", &SET)]),
329 ("cmp_set_l_32", &[spell("cmpl", &CMP_32), spell("setl", &SET)]),
330 ("cmp_set_l_64", &[spell("cmpq", &CMP_64), spell("setl", &SET)]),
331 ("cmp_set_le_8", &[spell("cmpb", &CMP_8), spell("setle", &SET)]),
332 ("cmp_set_le_16", &[spell("cmpw", &CMP_16), spell("setle", &SET)]),
333 ("cmp_set_le_32", &[spell("cmpl", &CMP_32), spell("setle", &SET)]),
334 ("cmp_set_le_64", &[spell("cmpq", &CMP_64), spell("setle", &SET)]),
335 ("cmp_set_g_8", &[spell("cmpb", &CMP_8), spell("setg", &SET)]),
336 ("cmp_set_g_16", &[spell("cmpw", &CMP_16), spell("setg", &SET)]),
337 ("cmp_set_g_32", &[spell("cmpl", &CMP_32), spell("setg", &SET)]),
338 ("cmp_set_g_64", &[spell("cmpq", &CMP_64), spell("setg", &SET)]),
339 ("cmp_set_ge_8", &[spell("cmpb", &CMP_8), spell("setge", &SET)]),
340 ("cmp_set_ge_16", &[spell("cmpw", &CMP_16), spell("setge", &SET)]),
341 ("cmp_set_ge_32", &[spell("cmpl", &CMP_32), spell("setge", &SET)]),
342 ("cmp_set_ge_64", &[spell("cmpq", &CMP_64), spell("setge", &SET)]),
343 ("cmp_set_b_8", &[spell("cmpb", &CMP_8), spell("setb", &SET)]),
344 ("cmp_set_b_16", &[spell("cmpw", &CMP_16), spell("setb", &SET)]),
345 ("cmp_set_b_32", &[spell("cmpl", &CMP_32), spell("setb", &SET)]),
346 ("cmp_set_b_64", &[spell("cmpq", &CMP_64), spell("setb", &SET)]),
347 ("cmp_set_be_8", &[spell("cmpb", &CMP_8), spell("setbe", &SET)]),
348 ("cmp_set_be_16", &[spell("cmpw", &CMP_16), spell("setbe", &SET)]),
349 ("cmp_set_be_32", &[spell("cmpl", &CMP_32), spell("setbe", &SET)]),
350 ("cmp_set_be_64", &[spell("cmpq", &CMP_64), spell("setbe", &SET)]),
351 ("cmp_set_a_8", &[spell("cmpb", &CMP_8), spell("seta", &SET)]),
352 ("cmp_set_a_16", &[spell("cmpw", &CMP_16), spell("seta", &SET)]),
353 ("cmp_set_a_32", &[spell("cmpl", &CMP_32), spell("seta", &SET)]),
354 ("cmp_set_a_64", &[spell("cmpq", &CMP_64), spell("seta", &SET)]),
355 ("cmp_set_ae_8", &[spell("cmpb", &CMP_8), spell("setae", &SET)]),
356 ("cmp_set_ae_16", &[spell("cmpw", &CMP_16), spell("setae", &SET)]),
357 ("cmp_set_ae_32", &[spell("cmpl", &CMP_32), spell("setae", &SET)]),
358 ("cmp_set_ae_64", &[spell("cmpq", &CMP_64), spell("setae", &SET)]),
359 ("movzx_8_16", &[spell("movzbw", &[Reg(1, Byte), Reg(0, Word)])]),
363 ("movzx_8_32", &[spell("movzbl", &[Reg(1, Byte), Reg(0, Long)])]),
364 ("movzx_8_64", &[spell("movzbq", &[Reg(1, Byte), Reg(0, Quad)])]),
365 ("movzx_16_32", &[spell("movzwl", &[Reg(1, Word), Reg(0, Long)])]),
366 ("movzx_16_64", &[spell("movzwq", &[Reg(1, Word), Reg(0, Quad)])]),
367 ("mov_32_to_64", &[spell("movl", &[Reg(1, Long), Reg(0, Long)])]),
368 ("movsx_8_16", &[spell("movsbw", &[Reg(1, Byte), Reg(0, Word)])]),
369 ("movsx_8_32", &[spell("movsbl", &[Reg(1, Byte), Reg(0, Long)])]),
370 ("movsx_8_64", &[spell("movsbq", &[Reg(1, Byte), Reg(0, Quad)])]),
371 ("movsx_16_32", &[spell("movswl", &[Reg(1, Word), Reg(0, Long)])]),
372 ("movsx_16_64", &[spell("movswq", &[Reg(1, Word), Reg(0, Quad)])]),
373 ("movsxd_32_64", &[spell("movslq", &[Reg(1, Long), Reg(0, Quad)])]),
374 ("bit_to_8", &[spell("movb", &[Reg(1, Byte), Reg(0, Byte)])]),
379 ("bit_to_16", &[spell("movzbw", &[Reg(1, Byte), Reg(0, Word)])]),
380 ("bit_to_32", &[spell("movzbl", &[Reg(1, Byte), Reg(0, Long)])]),
381 ("bit_to_64", &[spell("movzbq", &[Reg(1, Byte), Reg(0, Quad)])]),
382 ("low_8", &[spell("movb", &[Reg(1, Byte), Reg(0, Byte)])]),
383 ("low_16", &[spell("movw", &[Reg(1, Word), Reg(0, Word)])]),
384 ("low_32", &[spell("movl", &[Reg(1, Long), Reg(0, Long)])]),
385 ("lea_64", &[spell("leaq", &[Mem, Reg(0, Quad)])]),
387 ("mov_rm_8", &[spell("movb", &[Mem, Reg(0, Byte)])]),
390 ("mov_rm_16", &[spell("movw", &[Mem, Reg(0, Word)])]),
391 ("mov_rm_32", &[spell("movl", &[Mem, Reg(0, Long)])]),
392 ("mov_rm_64", &[spell("movq", &[Mem, Reg(0, Quad)])]),
393 ("mov_mr_8", &[spell("movb", &[Reg(0, Byte), Mem])]),
394 ("mov_mr_16", &[spell("movw", &[Reg(0, Word), Mem])]),
395 ("mov_mr_32", &[spell("movl", &[Reg(0, Long), Mem])]),
396 ("mov_mr_64", &[spell("movq", &[Reg(0, Quad), Mem])]),
397 ("ret_val_8", &[]),
400 ("ret_val_16", &[]),
401 ("ret_val_32", &[]),
402 ("ret_val_64", &[]),
403 ("ret_val_f32", &[]),
404 ("ret_val_f64", &[]),
405 ("ret_val2_8", &[]),
406 ("ret_val2_16", &[]),
407 ("ret_val2_32", &[]),
408 ("ret_val2_64", &[]),
409 ("ret_val2_f32", &[]),
410 ("ret_val2_f64", &[]),
411 ("arg_val_8", &[]),
412 ("arg_val_16", &[]),
413 ("arg_val_32", &[]),
414 ("arg_val_64", &[]),
415 ("arg_val_f32", &[]),
416 ("arg_val_f64", &[]),
417 ("br_cond_8", &[]),
418 ("call", &[spell("call", &[Symbol])]),
422 ("call_reg", &[spell("call", &[Through])]),
426 ("test_rr_8", &[spell("testb", &[Reg(0, Byte), Reg(0, Byte)])]),
428 ("jcc_e", &[spell("je", &[Label])]),
429 ("jcc_ne", &[spell("jne", &[Label])]),
430 ("jmp", &[spell("jmp", &[Label])]),
431 ("mov_rr_64", &[spell("movq", &[Reg(1, Quad), Reg(0, Quad)])]),
434 ("push_64", &[spell("pushq", &[Reg(0, Quad)])]),
435 ("pop_64", &[spell("popq", &[Reg(0, Quad)])]),
436 ("ret", &[spell("ret", &[])]),
437 ("movaps_rr", &[spell("movaps", &[Xmm(1), Xmm(0)])]),
438 ("movaps_rm", &[spell("movaps", &[Mem, Xmm(0)])]),
439 ("movaps_mr", &[spell("movaps", &[Xmm(0), Mem])]),
440 ("movss_rm", &[spell("movss", &[Mem, Xmm(0)])]),
441 ("movsd_rm", &[spell("movsd", &[Mem, Xmm(0)])]),
442 ("movss_mr", &[spell("movss", &[Xmm(0), Mem])]),
443 ("movsd_mr", &[spell("movsd", &[Xmm(0), Mem])]),
444 ("addss_rr", &[spell("addss", &[Xmm(2), Xmm(0)])]),
447 ("addsd_rr", &[spell("addsd", &[Xmm(2), Xmm(0)])]),
448 ("subss_rr", &[spell("subss", &[Xmm(2), Xmm(0)])]),
449 ("subsd_rr", &[spell("subsd", &[Xmm(2), Xmm(0)])]),
450 ("mulss_rr", &[spell("mulss", &[Xmm(2), Xmm(0)])]),
451 ("mulsd_rr", &[spell("mulsd", &[Xmm(2), Xmm(0)])]),
452 ("divss_rr", &[spell("divss", &[Xmm(2), Xmm(0)])]),
453 ("divsd_rr", &[spell("divsd", &[Xmm(2), Xmm(0)])]),
454 ("cvtss2sd", &[spell("cvtss2sd", &[Xmm(1), Xmm(0)])]),
463 ("cvtsd2ss", &[spell("cvtsd2ss", &[Xmm(1), Xmm(0)])]),
464 ("cvttss2si_32", &[spell("cvttss2sil", &[Xmm(1), Reg(0, Long)])]),
465 ("cvttss2si_64", &[spell("cvttss2siq", &[Xmm(1), Reg(0, Quad)])]),
466 ("cvttsd2si_32", &[spell("cvttsd2sil", &[Xmm(1), Reg(0, Long)])]),
467 ("cvttsd2si_64", &[spell("cvttsd2siq", &[Xmm(1), Reg(0, Quad)])]),
468 ("cvtsi2ss_32", &[spell("cvtsi2ssl", &[Reg(1, Long), Xmm(0)])]),
469 ("cvtsi2ss_64", &[spell("cvtsi2ssq", &[Reg(1, Quad), Xmm(0)])]),
470 ("cvtsi2sd_32", &[spell("cvtsi2sdl", &[Reg(1, Long), Xmm(0)])]),
471 ("cvtsi2sd_64", &[spell("cvtsi2sdq", &[Reg(1, Quad), Xmm(0)])]),
472 ("movd_to_xmm", &[spell("movd", &[Reg(1, Long), Xmm(0)])]),
473 ("movq_to_xmm", &[spell("movq", &[Reg(1, Quad), Xmm(0)])]),
474 ("movd_from_xmm", &[spell("movd", &[Xmm(1), Reg(0, Long)])]),
475 ("movq_from_xmm", &[spell("movq", &[Xmm(1), Reg(0, Quad)])]),
476 ("ucomiss_set_a", &[spell("ucomiss", &UCOMI), spell("seta", &SET)]),
486 ("ucomiss_set_ae", &[spell("ucomiss", &UCOMI), spell("setae", &SET)]),
487 ("ucomiss_set_b", &[spell("ucomiss", &UCOMI), spell("setb", &SET)]),
488 ("ucomiss_set_be", &[spell("ucomiss", &UCOMI), spell("setbe", &SET)]),
489 ("ucomiss_set_e", &[spell("ucomiss", &UCOMI), spell("sete", &SET)]),
490 ("ucomiss_set_ne", &[spell("ucomiss", &UCOMI), spell("setne", &SET)]),
491 ("ucomiss_set_p", &[spell("ucomiss", &UCOMI), spell("setp", &SET)]),
492 ("ucomiss_set_np", &[spell("ucomiss", &UCOMI), spell("setnp", &SET)]),
493 (
498 "ucomiss_set_e_and_np",
499 &[
500 spell("ucomiss", &UCOMI_BOTH),
501 spell("sete", &SET),
502 spell("setnp", &SET_SPARE),
503 spell("andb", &COMBINE),
504 ],
505 ),
506 (
507 "ucomiss_set_ne_or_p",
508 &[
509 spell("ucomiss", &UCOMI_BOTH),
510 spell("setne", &SET),
511 spell("setp", &SET_SPARE),
512 spell("orb", &COMBINE),
513 ],
514 ),
515 ("ucomisd_set_a", &[spell("ucomisd", &UCOMI), spell("seta", &SET)]),
516 ("ucomisd_set_ae", &[spell("ucomisd", &UCOMI), spell("setae", &SET)]),
517 ("ucomisd_set_b", &[spell("ucomisd", &UCOMI), spell("setb", &SET)]),
518 ("ucomisd_set_be", &[spell("ucomisd", &UCOMI), spell("setbe", &SET)]),
519 ("ucomisd_set_e", &[spell("ucomisd", &UCOMI), spell("sete", &SET)]),
520 ("ucomisd_set_ne", &[spell("ucomisd", &UCOMI), spell("setne", &SET)]),
521 ("ucomisd_set_p", &[spell("ucomisd", &UCOMI), spell("setp", &SET)]),
522 ("ucomisd_set_np", &[spell("ucomisd", &UCOMI), spell("setnp", &SET)]),
523 (
524 "ucomisd_set_e_and_np",
525 &[
526 spell("ucomisd", &UCOMI_BOTH),
527 spell("sete", &SET),
528 spell("setnp", &SET_SPARE),
529 spell("andb", &COMBINE),
530 ],
531 ),
532 (
533 "ucomisd_set_ne_or_p",
534 &[
535 spell("ucomisd", &UCOMI_BOTH),
536 spell("setne", &SET),
537 spell("setp", &SET_SPARE),
538 spell("orb", &COMBINE),
539 ],
540 ),
541];
542
543#[must_use]
550pub fn written(name: &str) -> Option<&'static [Written]> {
551 TEXT.iter().find(|(known, _)| *known == name).map(|&(_, insts)| insts)
552}
553
554static GPR_TEXT: [[&str; 4]; 16] = [
562 ["al", "ax", "eax", "rax"],
563 ["cl", "cx", "ecx", "rcx"],
564 ["dl", "dx", "edx", "rdx"],
565 ["bl", "bx", "ebx", "rbx"],
566 ["spl", "sp", "esp", "rsp"],
567 ["bpl", "bp", "ebp", "rbp"],
568 ["sil", "si", "esi", "rsi"],
569 ["dil", "di", "edi", "rdi"],
570 ["r8b", "r8w", "r8d", "r8"],
571 ["r9b", "r9w", "r9d", "r9"],
572 ["r10b", "r10w", "r10d", "r10"],
573 ["r11b", "r11w", "r11d", "r11"],
574 ["r12b", "r12w", "r12d", "r12"],
575 ["r13b", "r13w", "r13d", "r13"],
576 ["r14b", "r14w", "r14d", "r14"],
577 ["r15b", "r15w", "r15d", "r15"],
578];
579
580#[must_use]
586pub fn gpr_name(reg: PhysReg, width: Width) -> Option<&'static str> {
587 GPR_TEXT.get(usize::from(reg.number())).map(|names| names[width.index()])
588}
589
590#[cfg(test)]
591mod tests {
592 use super::*;
593 use crate::operand::Constraint;
594 use crate::x86_64::insts::{Form, INSTS, form};
595 use crate::x86_64::{GPR, REGS};
596
597 fn named(insts: &[Written]) -> Vec<u8> {
599 let mut at: Vec<u8> = insts
600 .iter()
601 .flat_map(|inst| inst.args)
602 .filter_map(|arg| match *arg {
603 Reg(at, _) | Xmm(at) => Some(at),
604 _ => None,
605 })
606 .collect();
607 at.sort_unstable();
608 at.dedup();
609 at
610 }
611
612 #[test]
613 fn every_opcode_is_written_once_and_in_the_order_it_is_described_in() {
614 let written: Vec<&str> = TEXT.iter().map(|&(name, _)| name).collect();
615 let described: Vec<&str> = INSTS.iter().map(|&(name, _)| name).collect();
616 assert_eq!(written, described);
619 }
620
621 #[test]
628 fn every_argument_names_something_the_instruction_really_has() {
629 for &(name, insts) in TEXT {
630 let form = form(name).expect("every written opcode is a described opcode");
631 let operands = form.operands();
632 let (mut imm, mut mem, mut symbol, mut label) = (false, false, false, false);
633 let mut through = false;
634 for arg in insts.iter().flat_map(|inst| inst.args) {
635 match *arg {
636 Reg(at, _) | Xmm(at) => assert!(
637 usize::from(at) < operands.len(),
638 "{name} names operand {at} and has {} of them",
639 operands.len()
640 ),
641 Named(register) => assert!(
645 REGS.reg_named(register).is_none(),
646 "{name} names {register}, which is a register something could be in"
647 ),
648 Imm => imm = true,
649 Mem => mem = true,
650 Symbol => symbol = true,
651 Label => label = true,
652 Through => through = true,
658 }
659 }
660 assert_eq!(imm, form.takes_imm(), "{name} and its immediate disagree");
661 assert_eq!(mem, form.takes_mem(), "{name} and its addressing mode disagree");
662 assert_eq!(symbol || through, form == Form::Call, "{name} and where it goes disagree");
663 assert!(!(symbol && through), "{name} goes to a name and through a register at once");
664 assert_eq!(
665 label,
666 matches!(form, Form::Jcc | Form::Jmp),
667 "{name} and where it goes disagree"
668 );
669 }
670 }
671
672 #[test]
679 fn an_operand_no_instruction_names_is_one_that_is_not_written() {
680 for &(name, insts) in TEXT {
681 let form = form(name).expect("every written opcode is a described opcode");
682 if insts.is_empty() || matches!(form, Form::DivQuo | Form::DivRem) {
683 continue;
684 }
685 let named = named(insts);
686 let operands = form.operands();
687 for at in 0..operands.len() {
688 let tied = operands.iter().enumerate().any(|(other, operand)| {
689 operand.constraint == Constraint::Reuse(at as u8)
690 && named.contains(&(other as u8))
691 });
692 assert!(
693 named.contains(&(at as u8)) || tied,
694 "{name} has an operand {at} that nothing written for it names"
695 );
696 }
697 }
698 }
699
700 #[test]
701 fn an_opcode_that_is_not_an_instruction_is_written_as_no_instructions() {
702 for name in
703 ["ret_val_32", "ret_val2_64", "arg_val_64", "ret_val_f64", "arg_val_f32", "br_cond_8"]
704 {
705 assert_eq!(written(name), Some([].as_slice()), "{name}");
706 }
707 for &(name, insts) in TEXT {
708 let form = form(name).expect("every written opcode is a described opcode");
709 assert_eq!(
710 insts.is_empty(),
711 matches!(
712 form,
713 Form::RetVal
714 | Form::RetVal2
715 | Form::ArgVal
716 | Form::RetValVec
717 | Form::RetVal2Vec
718 | Form::ArgValVec
719 | Form::BrCond
720 ),
721 "{name} and whether it is an instruction disagree"
722 );
723 }
724 }
725
726 #[test]
727 fn the_widest_spelling_of_a_register_is_the_one_the_register_file_gives_it() {
728 for number in 0..16u8 {
732 let reg = PhysReg::new(number);
733 assert_eq!(gpr_name(reg, Quad), REGS.name(GPR, reg), "register {number}");
734 }
735 assert_eq!(gpr_name(PhysReg::new(16), Quad), None);
736 }
737
738 #[test]
739 fn a_register_is_spelled_by_how_much_of_it_an_instruction_reads() {
740 use crate::x86_64::{R8, RAX, RDI};
741
742 assert_eq!(gpr_name(RAX, Byte), Some("al"));
743 assert_eq!(gpr_name(RAX, Long), Some("eax"));
744 assert_eq!(gpr_name(RDI, Byte), Some("dil"));
747 assert_eq!(gpr_name(RDI, Word), Some("di"));
748 assert_eq!(gpr_name(R8, Long), Some("r8d"));
749 }
750
751 #[test]
752 fn an_opcode_is_written_under_the_name_the_machine_ir_holds() {
753 let add = written("add_rr_32").expect("an opcode this target has");
754 assert_eq!(add, [spell("addl", &[Reg(2, Long), Reg(0, Long)])]);
755 assert_eq!(written("x64.add_rr_32"), None, "the prefix is not part of the opcode");
756 assert_eq!(written("add_rr_128"), None);
757 }
758
759 #[test]
762 fn an_opcode_the_machine_has_no_single_instruction_for_is_written_as_the_ones_it_has() {
763 let compare = written("cmp_set_l_32").expect("an opcode this target has");
764 assert_eq!(compare.iter().map(|inst| inst.mnemonic).collect::<Vec<_>>(), ["cmpl", "setl"]);
765
766 let divide = written("idiv_quo_64").expect("an opcode this target has");
767 assert_eq!(divide.iter().map(|inst| inst.mnemonic).collect::<Vec<_>>(), ["cqto", "idivq"]);
768
769 let remainder = written("div_rem_8").expect("an opcode this target has");
771 assert_eq!(
772 remainder.iter().map(|inst| inst.mnemonic).collect::<Vec<_>>(),
773 ["movzbl", "divb", "movb"]
774 );
775 assert_eq!(remainder[2].args, [Named("ah"), Reg(0, Byte)]);
776 }
777}