5c67b249ff4e8bd8d3e7a6881c059d2c1883c1ea
[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(llvm_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 }
134
135 #[derive(Copy, Clone, Default, Debug, PartialEq, Serialize, Deserialize)]
136 pub struct InstructionOutput {
137 #[serde(
138 default,
139 skip_serializing_if = "Option::is_none",
140 with = "serde_hex::SerdeHex"
141 )]
142 pub rt: Option<u64>,
143 #[serde(default, flatten, skip_serializing_if = "Option::is_none")]
144 pub overflow: Option<OverflowFlags>,
145 #[serde(default, flatten, skip_serializing_if = "Option::is_none")]
146 pub carry: Option<CarryFlags>,
147 #[serde(default, skip_serializing_if = "Option::is_none")]
148 pub cr0: Option<ConditionRegister>,
149 #[serde(default, skip_serializing_if = "Option::is_none")]
150 pub cr1: Option<ConditionRegister>,
151 #[serde(default, skip_serializing_if = "Option::is_none")]
152 pub cr2: Option<ConditionRegister>,
153 #[serde(default, skip_serializing_if = "Option::is_none")]
154 pub cr3: Option<ConditionRegister>,
155 #[serde(default, skip_serializing_if = "Option::is_none")]
156 pub cr4: Option<ConditionRegister>,
157 #[serde(default, skip_serializing_if = "Option::is_none")]
158 pub cr5: Option<ConditionRegister>,
159 #[serde(default, skip_serializing_if = "Option::is_none")]
160 pub cr6: Option<ConditionRegister>,
161 #[serde(default, skip_serializing_if = "Option::is_none")]
162 pub cr7: Option<ConditionRegister>,
163 }
164
165 #[derive(Debug)]
166 pub struct MissingInstructionInput {
167 pub input: InstructionInputRegister,
168 }
169
170 impl fmt::Display for MissingInstructionInput {
171 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
172 write!(f, "missing instruction input: {}", self.input)
173 }
174 }
175
176 impl std::error::Error for MissingInstructionInput {}
177
178 pub type InstructionResult = Result<InstructionOutput, MissingInstructionInput>;
179
180 #[derive(Copy, Clone, Eq, PartialEq, Hash, Debug, Serialize, Deserialize)]
181 pub enum InstructionInputRegister {
182 #[serde(rename = "ra")]
183 Ra,
184 #[serde(rename = "rb")]
185 Rb,
186 #[serde(rename = "rc")]
187 Rc,
188 #[serde(rename = "carry")]
189 Carry,
190 #[serde(rename = "overflow")]
191 Overflow,
192 #[serde(rename = "immediate_s16")]
193 ImmediateS16,
194 #[serde(rename = "immediate_u16")]
195 ImmediateU16,
196 }
197
198 forward_display_to_serde!(InstructionInputRegister);
199
200 #[derive(Copy, Clone, Default, Debug, Serialize, Deserialize)]
201 pub struct InstructionInput {
202 #[serde(
203 default,
204 skip_serializing_if = "Option::is_none",
205 with = "serde_hex::SerdeHex"
206 )]
207 pub ra: Option<u64>,
208 #[serde(
209 default,
210 skip_serializing_if = "Option::is_none",
211 with = "serde_hex::SerdeHex"
212 )]
213 pub rb: Option<u64>,
214 #[serde(
215 default,
216 skip_serializing_if = "Option::is_none",
217 with = "serde_hex::SerdeHex"
218 )]
219 pub rc: Option<u64>,
220 #[serde(
221 default,
222 skip_serializing_if = "Option::is_none",
223 with = "serde_hex::SerdeHex"
224 )]
225 pub immediate: Option<u64>,
226 #[serde(default, skip_serializing_if = "Option::is_none", flatten)]
227 pub carry: Option<CarryFlags>,
228 #[serde(default, skip_serializing_if = "Option::is_none", flatten)]
229 pub overflow: Option<OverflowFlags>,
230 }
231
232 macro_rules! impl_instr_try_get {
233 (
234 $(
235 $vis:vis fn $fn:ident -> $return_type:ty { .$field:ident else $error_enum:ident }
236 )+
237 ) => {
238 impl InstructionInput {
239 $(
240 $vis fn $fn(self) -> Result<$return_type, MissingInstructionInput> {
241 self.$field.ok_or(MissingInstructionInput {
242 input: InstructionInputRegister::$error_enum,
243 })
244 }
245 )+
246 }
247 };
248 }
249
250 impl_instr_try_get! {
251 pub fn try_get_ra -> u64 {
252 .ra else Ra
253 }
254 pub fn try_get_rb -> u64 {
255 .rb else Rb
256 }
257 pub fn try_get_rc -> u64 {
258 .rc else Rc
259 }
260 pub fn try_get_carry -> CarryFlags {
261 .carry else Carry
262 }
263 pub fn try_get_overflow -> OverflowFlags {
264 .overflow else Overflow
265 }
266 }
267
268 impl InstructionInput {
269 fn try_get_immediate(
270 self,
271 input: InstructionInputRegister,
272 ) -> Result<u64, MissingInstructionInput> {
273 self.immediate.ok_or(MissingInstructionInput { input })
274 }
275 pub fn try_get_immediate_u16(self) -> Result<u16, MissingInstructionInput> {
276 Ok(self.try_get_immediate(InstructionInputRegister::ImmediateU16)? as u16)
277 }
278 pub fn try_get_immediate_s16(self) -> Result<i16, MissingInstructionInput> {
279 Ok(self.try_get_immediate(InstructionInputRegister::ImmediateS16)? as i16)
280 }
281 }
282
283 fn is_false(v: &bool) -> bool {
284 !v
285 }
286
287 #[derive(Copy, Clone, Debug, Serialize, Deserialize)]
288 pub struct TestCase {
289 pub instr: Instr,
290 #[serde(flatten)]
291 pub inputs: InstructionInput,
292 #[serde(default, skip_serializing_if = "Option::is_none")]
293 pub native_outputs: Option<InstructionOutput>,
294 pub model_outputs: InstructionOutput,
295 #[serde(default, skip_serializing_if = "is_false")]
296 pub model_mismatch: bool,
297 }
298
299 #[derive(Clone, Debug, Serialize, Deserialize)]
300 pub struct WholeTest {
301 #[serde(default, skip_serializing_if = "Vec::is_empty")]
302 pub test_cases: Vec<TestCase>,
303 pub any_model_mismatch: bool,
304 }
305
306 instructions! {
307 #[enumerant = AddI]
308 fn addi(Ra, ImmediateS16) -> (Rt) {
309 "addi"
310 }
311
312 #[enumerant = AddIS]
313 fn addis(Ra, ImmediateS16) -> (Rt) {
314 "addis"
315 }
316
317 // add
318 #[enumerant = Add]
319 fn add(Ra, Rb) -> (Rt) {
320 "add"
321 }
322 #[enumerant = AddO]
323 fn addo(Ra, Rb, Overflow) -> (Rt, Overflow) {
324 "addo"
325 }
326 #[enumerant = Add_]
327 fn add_(Ra, Rb, Overflow) -> (Rt, CR0) {
328 "add."
329 }
330 #[enumerant = AddO_]
331 fn addo_(Ra, Rb, Overflow) -> (Rt, Overflow, CR0) {
332 "addo."
333 }
334
335 // addic
336 #[enumerant = AddIC]
337 fn addic(Ra, ImmediateS16) -> (Rt, Carry) {
338 "addic"
339 }
340 #[enumerant = AddIC_]
341 fn addic_(Ra, ImmediateS16, Overflow) -> (Rt, Carry, CR0) {
342 "addic."
343 }
344
345 // subf
346 #[enumerant = SubF]
347 fn subf(Ra, Rb) -> (Rt) {
348 "subf"
349 }
350 #[enumerant = SubFO]
351 fn subfo(Ra, Rb, Overflow) -> (Rt, Overflow) {
352 "subfo"
353 }
354 #[enumerant = SubF_]
355 fn subf_(Ra, Rb, Overflow) -> (Rt, CR0) {
356 "subf."
357 }
358 #[enumerant = SubFO_]
359 fn subfo_(Ra, Rb, Overflow) -> (Rt, Overflow, CR0) {
360 "subfo."
361 }
362
363 // addc
364 #[enumerant = AddC]
365 fn addc(Ra, Rb) -> (Rt, Carry) {
366 "addc"
367 }
368 #[enumerant = AddCO]
369 fn addco(Ra, Rb, Overflow) -> (Rt, Carry, Overflow) {
370 "addco"
371 }
372 #[enumerant = AddC_]
373 fn addc_(Ra, Rb, Overflow) -> (Rt, Carry, CR0) {
374 "addc."
375 }
376 #[enumerant = AddCO_]
377 fn addco_(Ra, Rb, Overflow) -> (Rt, Carry, Overflow, CR0) {
378 "addco."
379 }
380
381 // subfc
382 #[enumerant = SubFC]
383 fn subfc(Ra, Rb) -> (Rt, Carry) {
384 "subfc"
385 }
386 #[enumerant = SubFCO]
387 fn subfco(Ra, Rb, Overflow) -> (Rt, Carry, Overflow) {
388 "subfco"
389 }
390 #[enumerant = SubFC_]
391 fn subfc_(Ra, Rb, Overflow) -> (Rt, Carry, CR0) {
392 "subfc."
393 }
394 #[enumerant = SubFCO_]
395 fn subfco_(Ra, Rb, Overflow) -> (Rt, Carry, Overflow, CR0) {
396 "subfco."
397 }
398
399 // adde
400 #[enumerant = AddE]
401 fn adde(Ra, Rb, Carry) -> (Rt, Carry) {
402 "adde"
403 }
404 #[enumerant = AddEO]
405 fn addeo(Ra, Rb, Overflow, Carry) -> (Rt, Carry, Overflow) {
406 "addeo"
407 }
408 #[enumerant = AddE_]
409 fn adde_(Ra, Rb, Overflow, Carry) -> (Rt, Carry, CR0) {
410 "adde."
411 }
412 #[enumerant = AddEO_]
413 fn addeo_(Ra, Rb, Overflow, Carry) -> (Rt, Carry, Overflow, CR0) {
414 "addeo."
415 }
416
417 // subfe
418 #[enumerant = SubFE]
419 fn subfe(Ra, Rb, Carry) -> (Rt, Carry) {
420 "subfe"
421 }
422 #[enumerant = SubFEO]
423 fn subfeo(Ra, Rb, Overflow, Carry) -> (Rt, Carry, Overflow) {
424 "subfeo"
425 }
426 #[enumerant = SubFE_]
427 fn subfe_(Ra, Rb, Overflow, Carry) -> (Rt, Carry, CR0) {
428 "subfe."
429 }
430 #[enumerant = SubFEO_]
431 fn subfeo_(Ra, Rb, Overflow, Carry) -> (Rt, Carry, Overflow, CR0) {
432 "subfeo."
433 }
434
435 // addme
436 #[enumerant = AddME]
437 fn addme(Ra, Carry) -> (Rt, Carry) {
438 "addme"
439 }
440 #[enumerant = AddMEO]
441 fn addmeo(Ra, Overflow, Carry) -> (Rt, Carry, Overflow) {
442 "addmeo"
443 }
444 #[enumerant = AddME_]
445 fn addme_(Ra, Overflow, Carry) -> (Rt, Carry, CR0) {
446 "addme."
447 }
448 #[enumerant = AddMEO_]
449 fn addmeo_(Ra, Overflow, Carry) -> (Rt, Carry, Overflow, CR0) {
450 "addmeo."
451 }
452
453 // subfme
454 #[enumerant = SubFME]
455 fn subfme(Ra, Carry) -> (Rt, Carry) {
456 "subfme"
457 }
458 #[enumerant = SubFMEO]
459 fn subfmeo(Ra, Overflow, Carry) -> (Rt, Carry, Overflow) {
460 "subfmeo"
461 }
462 #[enumerant = SubFME_]
463 fn subfme_(Ra, Overflow, Carry) -> (Rt, Carry, CR0) {
464 "subfme."
465 }
466 #[enumerant = SubFMEO_]
467 fn subfmeo_(Ra, Overflow, Carry) -> (Rt, Carry, Overflow, CR0) {
468 "subfmeo."
469 }
470
471 // addze
472 #[enumerant = AddZE]
473 fn addze(Ra, Carry) -> (Rt, Carry) {
474 "addze"
475 }
476 #[enumerant = AddZEO]
477 fn addzeo(Ra, Overflow, Carry) -> (Rt, Carry, Overflow) {
478 "addzeo"
479 }
480 #[enumerant = AddZE_]
481 fn addze_(Ra, Overflow, Carry) -> (Rt, Carry, CR0) {
482 "addze."
483 }
484 #[enumerant = AddZEO_]
485 fn addzeo_(Ra, Overflow, Carry) -> (Rt, Carry, Overflow, CR0) {
486 "addzeo."
487 }
488
489 // subfze
490 #[enumerant = SubFZE]
491 fn subfze(Ra, Carry) -> (Rt, Carry) {
492 "subfze"
493 }
494 #[enumerant = SubFZEO]
495 fn subfzeo(Ra, Overflow, Carry) -> (Rt, Carry, Overflow) {
496 "subfzeo"
497 }
498 #[enumerant = SubFZE_]
499 fn subfze_(Ra, Overflow, Carry) -> (Rt, Carry, CR0) {
500 "subfze."
501 }
502 #[enumerant = SubFZEO_]
503 fn subfzeo_(Ra, Overflow, Carry) -> (Rt, Carry, Overflow, CR0) {
504 "subfzeo."
505 }
506
507 #[enumerant = AddEX]
508 fn addex(Ra("r3"), Rb("r4"), Overflow) -> (Rt("r5"), Overflow) {
509 // work around LLVM not supporting addex instruction:
510 "addex" : ".long 0x7CA32154 # addex r5, r3, r4, 0"
511 }
512
513 // neg
514 #[enumerant = Neg]
515 fn neg(Ra) -> (Rt) {
516 "neg"
517 }
518 #[enumerant = NegO]
519 fn nego(Ra, Overflow) -> (Rt, Overflow) {
520 "nego"
521 }
522 #[enumerant = Neg_]
523 fn neg_(Ra, Overflow) -> (Rt, CR0) {
524 "neg."
525 }
526 #[enumerant = NegO_]
527 fn nego_(Ra, Overflow) -> (Rt, Overflow, CR0) {
528 "nego."
529 }
530
531 // divde
532 #[enumerant = DivDE]
533 fn divde(Ra, Rb) -> (Rt) {
534 "divde"
535 }
536 #[enumerant = DivDEO]
537 fn divdeo(Ra, Rb, Overflow) -> (Rt, Overflow) {
538 "divdeo"
539 }
540 #[enumerant = DivDE_]
541 fn divde_(Ra, Rb, Overflow) -> (Rt, CR0) {
542 "divde."
543 }
544 #[enumerant = DivDEO_]
545 fn divdeo_(Ra, Rb, Overflow) -> (Rt, Overflow, CR0) {
546 "divdeo."
547 }
548
549 // divdeu
550 #[enumerant = DivDEU]
551 fn divdeu(Ra, Rb) -> (Rt) {
552 "divdeu"
553 }
554 #[enumerant = DivDEUO]
555 fn divdeuo(Ra, Rb, Overflow) -> (Rt, Overflow) {
556 "divdeuo"
557 }
558 #[enumerant = DivDEU_]
559 fn divdeu_(Ra, Rb, Overflow) -> (Rt, CR0) {
560 "divdeu."
561 }
562 #[enumerant = DivDEUO_]
563 fn divdeuo_(Ra, Rb, Overflow) -> (Rt, Overflow, CR0) {
564 "divdeuo."
565 }
566
567 // divd
568 #[enumerant = DivD]
569 fn divd(Ra, Rb) -> (Rt) {
570 "divd"
571 }
572 #[enumerant = DivDO]
573 fn divdo(Ra, Rb, Overflow) -> (Rt, Overflow) {
574 "divdo"
575 }
576 #[enumerant = DivD_]
577 fn divd_(Ra, Rb, Overflow) -> (Rt, CR0) {
578 "divd."
579 }
580 #[enumerant = DivDO_]
581 fn divdo_(Ra, Rb, Overflow) -> (Rt, Overflow, CR0) {
582 "divdo."
583 }
584
585 // divdu
586 #[enumerant = DivDU]
587 fn divdu(Ra, Rb) -> (Rt) {
588 "divdu"
589 }
590 #[enumerant = DivDUO]
591 fn divduo(Ra, Rb, Overflow) -> (Rt, Overflow) {
592 "divduo"
593 }
594 #[enumerant = DivDU_]
595 fn divdu_(Ra, Rb, Overflow) -> (Rt, CR0) {
596 "divdu."
597 }
598 #[enumerant = DivDUO_]
599 fn divduo_(Ra, Rb, Overflow) -> (Rt, Overflow, CR0) {
600 "divduo."
601 }
602
603 // divwe
604 #[enumerant = DivWE]
605 fn divwe(Ra, Rb) -> (Rt) {
606 "divwe"
607 }
608 #[enumerant = DivWEO]
609 fn divweo(Ra, Rb, Overflow) -> (Rt, Overflow) {
610 "divweo"
611 }
612 #[enumerant = DivWE_]
613 fn divwe_(Ra, Rb, Overflow) -> (Rt, CR0) {
614 "divwe."
615 }
616 #[enumerant = DivWEO_]
617 fn divweo_(Ra, Rb, Overflow) -> (Rt, Overflow, CR0) {
618 "divweo."
619 }
620
621 // divweu
622 #[enumerant = DivWEU]
623 fn divweu(Ra, Rb) -> (Rt) {
624 "divweu"
625 }
626 #[enumerant = DivWEUO]
627 fn divweuo(Ra, Rb, Overflow) -> (Rt, Overflow) {
628 "divweuo"
629 }
630 #[enumerant = DivWEU_]
631 fn divweu_(Ra, Rb, Overflow) -> (Rt, CR0) {
632 "divweu."
633 }
634 #[enumerant = DivWEUO_]
635 fn divweuo_(Ra, Rb, Overflow) -> (Rt, Overflow, CR0) {
636 "divweuo."
637 }
638
639 // divw
640 #[enumerant = DivW]
641 fn divw(Ra, Rb) -> (Rt) {
642 "divw"
643 }
644 #[enumerant = DivWO]
645 fn divwo(Ra, Rb, Overflow) -> (Rt, Overflow) {
646 "divwo"
647 }
648 #[enumerant = DivW_]
649 fn divw_(Ra, Rb, Overflow) -> (Rt, CR0) {
650 "divw."
651 }
652 #[enumerant = DivWO_]
653 fn divwo_(Ra, Rb, Overflow) -> (Rt, Overflow, CR0) {
654 "divwo."
655 }
656
657 // divwu
658 #[enumerant = DivWU]
659 fn divwu(Ra, Rb) -> (Rt) {
660 "divwu"
661 }
662 #[enumerant = DivWUO]
663 fn divwuo(Ra, Rb, Overflow) -> (Rt, Overflow) {
664 "divwuo"
665 }
666 #[enumerant = DivWU_]
667 fn divwu_(Ra, Rb, Overflow) -> (Rt, CR0) {
668 "divwu."
669 }
670 #[enumerant = DivWUO_]
671 fn divwuo_(Ra, Rb, Overflow) -> (Rt, Overflow, CR0) {
672 "divwuo."
673 }
674
675 // mod*
676 #[enumerant = ModSD]
677 fn modsd(Ra, Rb) -> (Rt) {
678 "modsd"
679 }
680 #[enumerant = ModUD]
681 fn modud(Ra, Rb) -> (Rt) {
682 "modud"
683 }
684 #[enumerant = ModSW]
685 fn modsw(Ra, Rb) -> (Rt) {
686 "modsw"
687 }
688 #[enumerant = ModUW]
689 fn moduw(Ra, Rb) -> (Rt) {
690 "moduw"
691 }
692
693 // mullw
694 #[enumerant = MulLW]
695 fn mullw(Ra, Rb) -> (Rt) {
696 "mullw"
697 }
698 #[enumerant = MulLWO]
699 fn mullwo(Ra, Rb, Overflow) -> (Rt, Overflow) {
700 "mullwo"
701 }
702 #[enumerant = MulLW_]
703 fn mullw_(Ra, Rb, Overflow) -> (Rt, CR0) {
704 "mullw."
705 }
706 #[enumerant = MulLWO_]
707 fn mullwo_(Ra, Rb, Overflow) -> (Rt, Overflow, CR0) {
708 "mullwo."
709 }
710
711 // mulhw
712 #[enumerant = MulHW]
713 fn mulhw(Ra, Rb) -> (Rt) {
714 "mulhw"
715 }
716 #[enumerant = MulHW_]
717 fn mulhw_(Ra, Rb, Overflow) -> (Rt, CR0) {
718 "mulhw."
719 }
720
721 // mulhwu
722 #[enumerant = MulHWU]
723 fn mulhwu(Ra, Rb) -> (Rt) {
724 "mulhwu"
725 }
726 #[enumerant = MulHWU_]
727 fn mulhwu_(Ra, Rb, Overflow) -> (Rt, CR0) {
728 "mulhwu."
729 }
730
731 // mulld
732 #[enumerant = MulLD]
733 fn mulld(Ra, Rb) -> (Rt) {
734 "mulld"
735 }
736 #[enumerant = MulLDO]
737 fn mulldo(Ra, Rb, Overflow) -> (Rt, Overflow) {
738 "mulldo"
739 }
740 #[enumerant = MulLD_]
741 fn mulld_(Ra, Rb, Overflow) -> (Rt, CR0) {
742 "mulld."
743 }
744 #[enumerant = MulLDO_]
745 fn mulldo_(Ra, Rb, Overflow) -> (Rt, Overflow, CR0) {
746 "mulldo."
747 }
748
749 // mulhd
750 #[enumerant = MulHD]
751 fn mulhd(Ra, Rb) -> (Rt) {
752 "mulhd"
753 }
754 #[enumerant = MulHD_]
755 fn mulhd_(Ra, Rb, Overflow) -> (Rt, CR0) {
756 "mulhd."
757 }
758
759 // mulhdu
760 #[enumerant = MulHDU]
761 fn mulhdu(Ra, Rb) -> (Rt) {
762 "mulhdu"
763 }
764 #[enumerant = MulHDU_]
765 fn mulhdu_(Ra, Rb, Overflow) -> (Rt, CR0) {
766 "mulhdu."
767 }
768
769 // madd*
770 #[enumerant = MAddHD]
771 fn maddhd(Ra, Rb, Rc) -> (Rt) {
772 "maddhd"
773 }
774 #[enumerant = MAddHDU]
775 fn maddhdu(Ra, Rb, Rc) -> (Rt) {
776 "maddhdu"
777 }
778 #[enumerant = MAddLD]
779 fn maddld(Ra, Rb, Rc) -> (Rt) {
780 "maddld"
781 }
782 }
783
784 // must be after instrs macro call since it uses a macro definition
785 mod python;