add cdtbcd, cbcdtd, and addg6s
[power-instruction-analyzer.git] / src / lib.rs
1 // SPDX-License-Identifier: LGPL-2.1-or-later
2 // See Notices.txt for copyright information
3
4 #![cfg_attr(feature = "native_instrs", feature(asm))]
5
6 #[cfg(all(feature = "native_instrs", not(target_arch = "powerpc64")))]
7 compile_error!("native_instrs feature requires target_arch to be powerpc64");
8
9 pub mod instr_models;
10 mod serde_hex;
11
12 use power_instruction_analyzer_proc_macro::instructions;
13 use serde::{Deserialize, Serialize};
14 use serde_plain::forward_display_to_serde;
15 use std::{cmp::Ordering, fmt};
16
17 // powerpc bit numbers count from MSB to LSB
18 const fn get_xer_bit_mask(powerpc_bit_num: usize) -> u64 {
19 (1 << 63) >> powerpc_bit_num
20 }
21
22 macro_rules! xer_subset {
23 (
24 $struct_vis:vis struct $struct_name:ident {
25 $(
26 #[bit($powerpc_bit_num:expr, $mask_name:ident)]
27 $field_vis:vis $field_name:ident: bool,
28 )+
29 }
30 ) => {
31 #[derive(Default, Copy, Clone, Debug, PartialEq, Serialize, Deserialize)]
32 $struct_vis struct $struct_name {
33 $(
34 $field_vis $field_name: bool,
35 )+
36 }
37
38 impl $struct_name {
39 $(
40 $field_vis const $mask_name: u64 = get_xer_bit_mask($powerpc_bit_num);
41 )+
42 $struct_vis const XER_MASK: u64 = $(Self::$mask_name)|+;
43 pub const fn from_xer(xer: u64) -> Self {
44 Self {
45 $(
46 $field_name: (xer & Self::$mask_name) != 0,
47 )+
48 }
49 }
50 pub const fn to_xer(self) -> u64 {
51 let mut retval = 0u64;
52 $(
53 if self.$field_name {
54 retval |= Self::$mask_name;
55 }
56 )+
57 retval
58 }
59 }
60 };
61 }
62
63 xer_subset! {
64 pub struct OverflowFlags {
65 #[bit(32, XER_SO_MASK)]
66 pub so: bool,
67 #[bit(33, XER_OV_MASK)]
68 pub ov: bool,
69 #[bit(44, XER_OV32_MASK)]
70 pub ov32: bool,
71 }
72 }
73
74 impl OverflowFlags {
75 pub const fn from_overflow(overflow: bool) -> Self {
76 Self {
77 so: overflow,
78 ov: overflow,
79 ov32: overflow,
80 }
81 }
82 }
83
84 xer_subset! {
85 pub struct CarryFlags {
86 #[bit(34, XER_CA_MASK)]
87 pub ca: bool,
88 #[bit(45, XER_CA32_MASK)]
89 pub ca32: bool,
90 }
91 }
92
93 #[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize)]
94 pub struct ConditionRegister {
95 pub lt: bool,
96 pub gt: bool,
97 pub eq: bool,
98 pub so: bool,
99 }
100
101 impl ConditionRegister {
102 pub const fn from_4_bits(bits: u8) -> Self {
103 // assert bits is 4-bits long
104 // can switch to using assert! once rustc feature const_panic is stabilized
105 [0; 0x10][bits as usize];
106
107 Self {
108 lt: (bits & 8) != 0,
109 gt: (bits & 4) != 0,
110 eq: (bits & 2) != 0,
111 so: (bits & 1) != 0,
112 }
113 }
114 pub const CR_FIELD_COUNT: usize = 8;
115 pub const fn from_cr_field(cr: u32, field_index: usize) -> Self {
116 // assert field_index is less than CR_FIELD_COUNT
117 // can switch to using assert! once rustc feature const_panic is stabilized
118 [0; Self::CR_FIELD_COUNT][field_index];
119
120 let reversed_field_index = Self::CR_FIELD_COUNT - field_index - 1;
121 let bits = (cr >> (4 * reversed_field_index)) & 0xF;
122 Self::from_4_bits(bits as u8)
123 }
124 pub fn from_signed_int<T: Ord + Default>(value: T, so: bool) -> Self {
125 let ordering = value.cmp(&T::default());
126 Self {
127 lt: ordering == Ordering::Less,
128 gt: ordering == Ordering::Greater,
129 eq: ordering == Ordering::Equal,
130 so,
131 }
132 }
133 pub fn from_ordering(ordering: Ordering, so: bool) -> Self {
134 Self {
135 lt: ordering == Ordering::Less,
136 gt: ordering == Ordering::Greater,
137 eq: ordering == Ordering::Equal,
138 so,
139 }
140 }
141 }
142
143 #[derive(Copy, Clone, Default, Debug, PartialEq, Serialize, Deserialize)]
144 pub struct InstructionOutput {
145 #[serde(
146 default,
147 skip_serializing_if = "Option::is_none",
148 with = "serde_hex::SerdeHex"
149 )]
150 pub rt: Option<u64>,
151 #[serde(default, flatten, skip_serializing_if = "Option::is_none")]
152 pub overflow: Option<OverflowFlags>,
153 #[serde(default, flatten, skip_serializing_if = "Option::is_none")]
154 pub carry: Option<CarryFlags>,
155 #[serde(default, skip_serializing_if = "Option::is_none")]
156 pub cr0: Option<ConditionRegister>,
157 #[serde(default, skip_serializing_if = "Option::is_none")]
158 pub cr1: Option<ConditionRegister>,
159 #[serde(default, skip_serializing_if = "Option::is_none")]
160 pub cr2: Option<ConditionRegister>,
161 #[serde(default, skip_serializing_if = "Option::is_none")]
162 pub cr3: Option<ConditionRegister>,
163 #[serde(default, skip_serializing_if = "Option::is_none")]
164 pub cr4: Option<ConditionRegister>,
165 #[serde(default, skip_serializing_if = "Option::is_none")]
166 pub cr5: Option<ConditionRegister>,
167 #[serde(default, skip_serializing_if = "Option::is_none")]
168 pub cr6: Option<ConditionRegister>,
169 #[serde(default, skip_serializing_if = "Option::is_none")]
170 pub cr7: Option<ConditionRegister>,
171 }
172
173 #[derive(Debug)]
174 pub struct MissingInstructionInput {
175 pub input: InstructionInputRegister,
176 }
177
178 impl fmt::Display for MissingInstructionInput {
179 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
180 write!(f, "missing instruction input: {}", self.input)
181 }
182 }
183
184 impl std::error::Error for MissingInstructionInput {}
185
186 pub type InstructionResult = Result<InstructionOutput, MissingInstructionInput>;
187
188 #[derive(Copy, Clone, Eq, PartialEq, Hash, Debug, Serialize, Deserialize)]
189 pub enum InstructionInputRegister {
190 #[serde(rename = "ra")]
191 Ra,
192 #[serde(rename = "rb")]
193 Rb,
194 #[serde(rename = "rc")]
195 Rc,
196 #[serde(rename = "carry")]
197 Carry,
198 #[serde(rename = "overflow")]
199 Overflow,
200 #[serde(rename = "immediate_s16")]
201 ImmediateS16,
202 #[serde(rename = "immediate_u16")]
203 ImmediateU16,
204 }
205
206 forward_display_to_serde!(InstructionInputRegister);
207
208 #[derive(Copy, Clone, Default, Debug, Serialize, Deserialize)]
209 pub struct InstructionInput {
210 #[serde(
211 default,
212 skip_serializing_if = "Option::is_none",
213 with = "serde_hex::SerdeHex"
214 )]
215 pub ra: Option<u64>,
216 #[serde(
217 default,
218 skip_serializing_if = "Option::is_none",
219 with = "serde_hex::SerdeHex"
220 )]
221 pub rb: Option<u64>,
222 #[serde(
223 default,
224 skip_serializing_if = "Option::is_none",
225 with = "serde_hex::SerdeHex"
226 )]
227 pub rc: Option<u64>,
228 #[serde(
229 default,
230 skip_serializing_if = "Option::is_none",
231 with = "serde_hex::SerdeHex"
232 )]
233 pub immediate: Option<u64>,
234 #[serde(default, skip_serializing_if = "Option::is_none", flatten)]
235 pub carry: Option<CarryFlags>,
236 #[serde(default, skip_serializing_if = "Option::is_none", flatten)]
237 pub overflow: Option<OverflowFlags>,
238 }
239
240 macro_rules! impl_instr_try_get {
241 (
242 $(
243 $vis:vis fn $fn:ident -> $return_type:ty { .$field:ident else $error_enum:ident }
244 )+
245 ) => {
246 impl InstructionInput {
247 $(
248 $vis fn $fn(self) -> Result<$return_type, MissingInstructionInput> {
249 self.$field.ok_or(MissingInstructionInput {
250 input: InstructionInputRegister::$error_enum,
251 })
252 }
253 )+
254 }
255 };
256 }
257
258 impl_instr_try_get! {
259 pub fn try_get_ra -> u64 {
260 .ra else Ra
261 }
262 pub fn try_get_rb -> u64 {
263 .rb else Rb
264 }
265 pub fn try_get_rc -> u64 {
266 .rc else Rc
267 }
268 pub fn try_get_carry -> CarryFlags {
269 .carry else Carry
270 }
271 pub fn try_get_overflow -> OverflowFlags {
272 .overflow else Overflow
273 }
274 }
275
276 impl InstructionInput {
277 fn try_get_immediate(
278 self,
279 input: InstructionInputRegister,
280 ) -> Result<u64, MissingInstructionInput> {
281 self.immediate.ok_or(MissingInstructionInput { input })
282 }
283 pub fn try_get_immediate_u16(self) -> Result<u16, MissingInstructionInput> {
284 Ok(self.try_get_immediate(InstructionInputRegister::ImmediateU16)? as u16)
285 }
286 pub fn try_get_immediate_s16(self) -> Result<i16, MissingInstructionInput> {
287 Ok(self.try_get_immediate(InstructionInputRegister::ImmediateS16)? as i16)
288 }
289 }
290
291 fn is_false(v: &bool) -> bool {
292 !v
293 }
294
295 #[derive(Copy, Clone, Debug, Serialize, Deserialize)]
296 pub struct TestCase {
297 pub instr: Instr,
298 #[serde(flatten)]
299 pub inputs: InstructionInput,
300 #[serde(default, skip_serializing_if = "Option::is_none")]
301 pub native_outputs: Option<InstructionOutput>,
302 pub model_outputs: InstructionOutput,
303 #[serde(default, skip_serializing_if = "is_false")]
304 pub model_mismatch: bool,
305 }
306
307 #[derive(Clone, Debug, Serialize, Deserialize)]
308 pub struct WholeTest {
309 #[serde(default, skip_serializing_if = "Vec::is_empty")]
310 pub test_cases: Vec<TestCase>,
311 pub any_model_mismatch: bool,
312 }
313
314 instructions! {
315 #[enumerant = AddI]
316 fn addi(Ra, ImmediateS16) -> (Rt) {
317 "addi"
318 }
319
320 #[enumerant = AddIS]
321 fn addis(Ra, ImmediateS16) -> (Rt) {
322 "addis"
323 }
324
325 // add
326 #[enumerant = Add]
327 fn add(Ra, Rb) -> (Rt) {
328 "add"
329 }
330 #[enumerant = AddO]
331 fn addo(Ra, Rb, Overflow) -> (Rt, Overflow) {
332 "addo"
333 }
334 #[enumerant = Add_]
335 fn add_(Ra, Rb, Overflow) -> (Rt, CR0) {
336 "add."
337 }
338 #[enumerant = AddO_]
339 fn addo_(Ra, Rb, Overflow) -> (Rt, Overflow, CR0) {
340 "addo."
341 }
342
343 // addic
344 #[enumerant = AddIC]
345 fn addic(Ra, ImmediateS16) -> (Rt, Carry) {
346 "addic"
347 }
348 #[enumerant = AddIC_]
349 fn addic_(Ra, ImmediateS16, Overflow) -> (Rt, Carry, CR0) {
350 "addic."
351 }
352
353 // subf
354 #[enumerant = SubF]
355 fn subf(Ra, Rb) -> (Rt) {
356 "subf"
357 }
358 #[enumerant = SubFO]
359 fn subfo(Ra, Rb, Overflow) -> (Rt, Overflow) {
360 "subfo"
361 }
362 #[enumerant = SubF_]
363 fn subf_(Ra, Rb, Overflow) -> (Rt, CR0) {
364 "subf."
365 }
366 #[enumerant = SubFO_]
367 fn subfo_(Ra, Rb, Overflow) -> (Rt, Overflow, CR0) {
368 "subfo."
369 }
370
371 #[enumerant = SubFIC]
372 fn subfic(Ra, ImmediateS16) -> (Rt, Carry) {
373 "subfic"
374 }
375
376 // addc
377 #[enumerant = AddC]
378 fn addc(Ra, Rb) -> (Rt, Carry) {
379 "addc"
380 }
381 #[enumerant = AddCO]
382 fn addco(Ra, Rb, Overflow) -> (Rt, Carry, Overflow) {
383 "addco"
384 }
385 #[enumerant = AddC_]
386 fn addc_(Ra, Rb, Overflow) -> (Rt, Carry, CR0) {
387 "addc."
388 }
389 #[enumerant = AddCO_]
390 fn addco_(Ra, Rb, Overflow) -> (Rt, Carry, Overflow, CR0) {
391 "addco."
392 }
393
394 // subfc
395 #[enumerant = SubFC]
396 fn subfc(Ra, Rb) -> (Rt, Carry) {
397 "subfc"
398 }
399 #[enumerant = SubFCO]
400 fn subfco(Ra, Rb, Overflow) -> (Rt, Carry, Overflow) {
401 "subfco"
402 }
403 #[enumerant = SubFC_]
404 fn subfc_(Ra, Rb, Overflow) -> (Rt, Carry, CR0) {
405 "subfc."
406 }
407 #[enumerant = SubFCO_]
408 fn subfco_(Ra, Rb, Overflow) -> (Rt, Carry, Overflow, CR0) {
409 "subfco."
410 }
411
412 // adde
413 #[enumerant = AddE]
414 fn adde(Ra, Rb, Carry) -> (Rt, Carry) {
415 "adde"
416 }
417 #[enumerant = AddEO]
418 fn addeo(Ra, Rb, Overflow, Carry) -> (Rt, Carry, Overflow) {
419 "addeo"
420 }
421 #[enumerant = AddE_]
422 fn adde_(Ra, Rb, Overflow, Carry) -> (Rt, Carry, CR0) {
423 "adde."
424 }
425 #[enumerant = AddEO_]
426 fn addeo_(Ra, Rb, Overflow, Carry) -> (Rt, Carry, Overflow, CR0) {
427 "addeo."
428 }
429
430 // subfe
431 #[enumerant = SubFE]
432 fn subfe(Ra, Rb, Carry) -> (Rt, Carry) {
433 "subfe"
434 }
435 #[enumerant = SubFEO]
436 fn subfeo(Ra, Rb, Overflow, Carry) -> (Rt, Carry, Overflow) {
437 "subfeo"
438 }
439 #[enumerant = SubFE_]
440 fn subfe_(Ra, Rb, Overflow, Carry) -> (Rt, Carry, CR0) {
441 "subfe."
442 }
443 #[enumerant = SubFEO_]
444 fn subfeo_(Ra, Rb, Overflow, Carry) -> (Rt, Carry, Overflow, CR0) {
445 "subfeo."
446 }
447
448 // addme
449 #[enumerant = AddME]
450 fn addme(Ra, Carry) -> (Rt, Carry) {
451 "addme"
452 }
453 #[enumerant = AddMEO]
454 fn addmeo(Ra, Overflow, Carry) -> (Rt, Carry, Overflow) {
455 "addmeo"
456 }
457 #[enumerant = AddME_]
458 fn addme_(Ra, Overflow, Carry) -> (Rt, Carry, CR0) {
459 "addme."
460 }
461 #[enumerant = AddMEO_]
462 fn addmeo_(Ra, Overflow, Carry) -> (Rt, Carry, Overflow, CR0) {
463 "addmeo."
464 }
465
466 // subfme
467 #[enumerant = SubFME]
468 fn subfme(Ra, Carry) -> (Rt, Carry) {
469 "subfme"
470 }
471 #[enumerant = SubFMEO]
472 fn subfmeo(Ra, Overflow, Carry) -> (Rt, Carry, Overflow) {
473 "subfmeo"
474 }
475 #[enumerant = SubFME_]
476 fn subfme_(Ra, Overflow, Carry) -> (Rt, Carry, CR0) {
477 "subfme."
478 }
479 #[enumerant = SubFMEO_]
480 fn subfmeo_(Ra, Overflow, Carry) -> (Rt, Carry, Overflow, CR0) {
481 "subfmeo."
482 }
483
484 // addze
485 #[enumerant = AddZE]
486 fn addze(Ra, Carry) -> (Rt, Carry) {
487 "addze"
488 }
489 #[enumerant = AddZEO]
490 fn addzeo(Ra, Overflow, Carry) -> (Rt, Carry, Overflow) {
491 "addzeo"
492 }
493 #[enumerant = AddZE_]
494 fn addze_(Ra, Overflow, Carry) -> (Rt, Carry, CR0) {
495 "addze."
496 }
497 #[enumerant = AddZEO_]
498 fn addzeo_(Ra, Overflow, Carry) -> (Rt, Carry, Overflow, CR0) {
499 "addzeo."
500 }
501
502 // subfze
503 #[enumerant = SubFZE]
504 fn subfze(Ra, Carry) -> (Rt, Carry) {
505 "subfze"
506 }
507 #[enumerant = SubFZEO]
508 fn subfzeo(Ra, Overflow, Carry) -> (Rt, Carry, Overflow) {
509 "subfzeo"
510 }
511 #[enumerant = SubFZE_]
512 fn subfze_(Ra, Overflow, Carry) -> (Rt, Carry, CR0) {
513 "subfze."
514 }
515 #[enumerant = SubFZEO_]
516 fn subfzeo_(Ra, Overflow, Carry) -> (Rt, Carry, Overflow, CR0) {
517 "subfzeo."
518 }
519
520 #[enumerant = AddEX]
521 fn addex(Ra("r3"), Rb("r4"), Overflow) -> (Rt("r5"), Overflow) {
522 // work around LLVM not supporting addex instruction:
523 "addex" : ".long 0x7CA32154 # addex r5, r3, r4, 0"
524 }
525
526 // neg
527 #[enumerant = Neg]
528 fn neg(Ra) -> (Rt) {
529 "neg"
530 }
531 #[enumerant = NegO]
532 fn nego(Ra, Overflow) -> (Rt, Overflow) {
533 "nego"
534 }
535 #[enumerant = Neg_]
536 fn neg_(Ra, Overflow) -> (Rt, CR0) {
537 "neg."
538 }
539 #[enumerant = NegO_]
540 fn nego_(Ra, Overflow) -> (Rt, Overflow, CR0) {
541 "nego."
542 }
543
544 // divde
545 #[enumerant = DivDE]
546 fn divde(Ra, Rb) -> (Rt) {
547 "divde"
548 }
549 #[enumerant = DivDEO]
550 fn divdeo(Ra, Rb, Overflow) -> (Rt, Overflow) {
551 "divdeo"
552 }
553 #[enumerant = DivDE_]
554 fn divde_(Ra, Rb, Overflow) -> (Rt, CR0) {
555 "divde."
556 }
557 #[enumerant = DivDEO_]
558 fn divdeo_(Ra, Rb, Overflow) -> (Rt, Overflow, CR0) {
559 "divdeo."
560 }
561
562 // divdeu
563 #[enumerant = DivDEU]
564 fn divdeu(Ra, Rb) -> (Rt) {
565 "divdeu"
566 }
567 #[enumerant = DivDEUO]
568 fn divdeuo(Ra, Rb, Overflow) -> (Rt, Overflow) {
569 "divdeuo"
570 }
571 #[enumerant = DivDEU_]
572 fn divdeu_(Ra, Rb, Overflow) -> (Rt, CR0) {
573 "divdeu."
574 }
575 #[enumerant = DivDEUO_]
576 fn divdeuo_(Ra, Rb, Overflow) -> (Rt, Overflow, CR0) {
577 "divdeuo."
578 }
579
580 // divd
581 #[enumerant = DivD]
582 fn divd(Ra, Rb) -> (Rt) {
583 "divd"
584 }
585 #[enumerant = DivDO]
586 fn divdo(Ra, Rb, Overflow) -> (Rt, Overflow) {
587 "divdo"
588 }
589 #[enumerant = DivD_]
590 fn divd_(Ra, Rb, Overflow) -> (Rt, CR0) {
591 "divd."
592 }
593 #[enumerant = DivDO_]
594 fn divdo_(Ra, Rb, Overflow) -> (Rt, Overflow, CR0) {
595 "divdo."
596 }
597
598 // divdu
599 #[enumerant = DivDU]
600 fn divdu(Ra, Rb) -> (Rt) {
601 "divdu"
602 }
603 #[enumerant = DivDUO]
604 fn divduo(Ra, Rb, Overflow) -> (Rt, Overflow) {
605 "divduo"
606 }
607 #[enumerant = DivDU_]
608 fn divdu_(Ra, Rb, Overflow) -> (Rt, CR0) {
609 "divdu."
610 }
611 #[enumerant = DivDUO_]
612 fn divduo_(Ra, Rb, Overflow) -> (Rt, Overflow, CR0) {
613 "divduo."
614 }
615
616 // divwe
617 #[enumerant = DivWE]
618 fn divwe(Ra, Rb) -> (Rt) {
619 "divwe"
620 }
621 #[enumerant = DivWEO]
622 fn divweo(Ra, Rb, Overflow) -> (Rt, Overflow) {
623 "divweo"
624 }
625 #[enumerant = DivWE_]
626 fn divwe_(Ra, Rb, Overflow) -> (Rt, CR0) {
627 "divwe."
628 }
629 #[enumerant = DivWEO_]
630 fn divweo_(Ra, Rb, Overflow) -> (Rt, Overflow, CR0) {
631 "divweo."
632 }
633
634 // divweu
635 #[enumerant = DivWEU]
636 fn divweu(Ra, Rb) -> (Rt) {
637 "divweu"
638 }
639 #[enumerant = DivWEUO]
640 fn divweuo(Ra, Rb, Overflow) -> (Rt, Overflow) {
641 "divweuo"
642 }
643 #[enumerant = DivWEU_]
644 fn divweu_(Ra, Rb, Overflow) -> (Rt, CR0) {
645 "divweu."
646 }
647 #[enumerant = DivWEUO_]
648 fn divweuo_(Ra, Rb, Overflow) -> (Rt, Overflow, CR0) {
649 "divweuo."
650 }
651
652 // divw
653 #[enumerant = DivW]
654 fn divw(Ra, Rb) -> (Rt) {
655 "divw"
656 }
657 #[enumerant = DivWO]
658 fn divwo(Ra, Rb, Overflow) -> (Rt, Overflow) {
659 "divwo"
660 }
661 #[enumerant = DivW_]
662 fn divw_(Ra, Rb, Overflow) -> (Rt, CR0) {
663 "divw."
664 }
665 #[enumerant = DivWO_]
666 fn divwo_(Ra, Rb, Overflow) -> (Rt, Overflow, CR0) {
667 "divwo."
668 }
669
670 // divwu
671 #[enumerant = DivWU]
672 fn divwu(Ra, Rb) -> (Rt) {
673 "divwu"
674 }
675 #[enumerant = DivWUO]
676 fn divwuo(Ra, Rb, Overflow) -> (Rt, Overflow) {
677 "divwuo"
678 }
679 #[enumerant = DivWU_]
680 fn divwu_(Ra, Rb, Overflow) -> (Rt, CR0) {
681 "divwu."
682 }
683 #[enumerant = DivWUO_]
684 fn divwuo_(Ra, Rb, Overflow) -> (Rt, Overflow, CR0) {
685 "divwuo."
686 }
687
688 // mod*
689 #[enumerant = ModSD]
690 fn modsd(Ra, Rb) -> (Rt) {
691 "modsd"
692 }
693 #[enumerant = ModUD]
694 fn modud(Ra, Rb) -> (Rt) {
695 "modud"
696 }
697 #[enumerant = ModSW]
698 fn modsw(Ra, Rb) -> (Rt) {
699 "modsw"
700 }
701 #[enumerant = ModUW]
702 fn moduw(Ra, Rb) -> (Rt) {
703 "moduw"
704 }
705
706 #[enumerant = MulLI]
707 fn mulli(Ra, ImmediateS16) -> (Rt) {
708 "mulli"
709 }
710
711 // mullw
712 #[enumerant = MulLW]
713 fn mullw(Ra, Rb) -> (Rt) {
714 "mullw"
715 }
716 #[enumerant = MulLWO]
717 fn mullwo(Ra, Rb, Overflow) -> (Rt, Overflow) {
718 "mullwo"
719 }
720 #[enumerant = MulLW_]
721 fn mullw_(Ra, Rb, Overflow) -> (Rt, CR0) {
722 "mullw."
723 }
724 #[enumerant = MulLWO_]
725 fn mullwo_(Ra, Rb, Overflow) -> (Rt, Overflow, CR0) {
726 "mullwo."
727 }
728
729 // mulhw
730 #[enumerant = MulHW]
731 fn mulhw(Ra, Rb) -> (Rt) {
732 "mulhw"
733 }
734 #[enumerant = MulHW_]
735 fn mulhw_(Ra, Rb, Overflow) -> (Rt, CR0) {
736 "mulhw."
737 }
738
739 // mulhwu
740 #[enumerant = MulHWU]
741 fn mulhwu(Ra, Rb) -> (Rt) {
742 "mulhwu"
743 }
744 #[enumerant = MulHWU_]
745 fn mulhwu_(Ra, Rb, Overflow) -> (Rt, CR0) {
746 "mulhwu."
747 }
748
749 // mulld
750 #[enumerant = MulLD]
751 fn mulld(Ra, Rb) -> (Rt) {
752 "mulld"
753 }
754 #[enumerant = MulLDO]
755 fn mulldo(Ra, Rb, Overflow) -> (Rt, Overflow) {
756 "mulldo"
757 }
758 #[enumerant = MulLD_]
759 fn mulld_(Ra, Rb, Overflow) -> (Rt, CR0) {
760 "mulld."
761 }
762 #[enumerant = MulLDO_]
763 fn mulldo_(Ra, Rb, Overflow) -> (Rt, Overflow, CR0) {
764 "mulldo."
765 }
766
767 // mulhd
768 #[enumerant = MulHD]
769 fn mulhd(Ra, Rb) -> (Rt) {
770 "mulhd"
771 }
772 #[enumerant = MulHD_]
773 fn mulhd_(Ra, Rb, Overflow) -> (Rt, CR0) {
774 "mulhd."
775 }
776
777 // mulhdu
778 #[enumerant = MulHDU]
779 fn mulhdu(Ra, Rb) -> (Rt) {
780 "mulhdu"
781 }
782 #[enumerant = MulHDU_]
783 fn mulhdu_(Ra, Rb, Overflow) -> (Rt, CR0) {
784 "mulhdu."
785 }
786
787 // madd*
788 #[enumerant = MAddHD]
789 fn maddhd(Ra, Rb, Rc) -> (Rt) {
790 "maddhd"
791 }
792 #[enumerant = MAddHDU]
793 fn maddhdu(Ra, Rb, Rc) -> (Rt) {
794 "maddhdu"
795 }
796 #[enumerant = MAddLD]
797 fn maddld(Ra, Rb, Rc) -> (Rt) {
798 "maddld"
799 }
800
801 // cmpi
802 #[enumerant = CmpDI]
803 fn cmpdi(Ra, ImmediateS16, Overflow) -> (CR0) {
804 "cmpdi"
805 }
806 #[enumerant = CmpWI]
807 fn cmpwi(Ra, ImmediateS16, Overflow) -> (CR0) {
808 "cmpwi"
809 }
810
811 // cmpli
812 #[enumerant = CmpLDI]
813 fn cmpldi(Ra, ImmediateU16, Overflow) -> (CR0) {
814 "cmpldi"
815 }
816 #[enumerant = CmpLWI]
817 fn cmplwi(Ra, ImmediateU16, Overflow) -> (CR0) {
818 "cmplwi"
819 }
820
821 // cmp
822 #[enumerant = CmpD]
823 fn cmpd(Ra, Rb, Overflow) -> (CR0) {
824 "cmpd"
825 }
826 #[enumerant = CmpW]
827 fn cmpw(Ra, Rb, Overflow) -> (CR0) {
828 "cmpw"
829 }
830
831 // cmpl
832 #[enumerant = CmpLD]
833 fn cmpld(Ra, Rb, Overflow) -> (CR0) {
834 "cmpld"
835 }
836 #[enumerant = CmpLW]
837 fn cmplw(Ra, Rb, Overflow) -> (CR0) {
838 "cmplw"
839 }
840
841 // cmprb 0, 0, ..., ...
842 #[enumerant = CmpRB0]
843 fn cmprb_0(Ra("r3"), Rb("r4")) -> (CR0) {
844 "cmprb_0" : "cmprb 0, 0, 3, 4"
845 }
846
847 #[enumerant = CDTBcd]
848 fn cdtbcd(Ra("r3")) -> (Rt("r4")) {
849 // work around LLVM not supporting cdtbcd instruction:
850 "cdtbcd" : ".long 0x7C640234 # cdtbcd r4, r3"
851 }
852
853 #[enumerant = CBcdTD]
854 fn cbcdtd(Ra("r3")) -> (Rt("r4")) {
855 // work around LLVM not supporting cbcdtd instruction:
856 "cbcdtd" : ".long 0x7C640274 # cbcdtd r4, r3"
857 }
858
859 #[enumerant = AddG6s]
860 fn addg6s(Ra("r3"), Rb("r4")) -> (Rt("r5")) {
861 // work around LLVM not supporting addg6s instruction:
862 "addg6s" : ".long 0x7CA32094 # addg6s r5, r3, r4"
863 }
864 }
865
866 // must be after instrs macro call since it uses a macro definition
867 mod python;