1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121
//! mulx /// Unsigned multiply without affecting flags. pub trait Mulx: crate::marker::Sized { /// Unsigned multiply without affecting flags. /// /// Unsigned multiplication of `x` with `y` returning a pair `(lo, hi)` /// with the low half and the high half of the result. /// /// # Instructions /// /// - [`MULX`](http://www.felixcloutier.com/x86/MULX.html): /// - Description: Unsigned multiply without affecting flags. /// - Architecture: x86. /// - Instruction set: BMI2. /// - Registers: 32/64 bit. /// /// # Example /// /// ``` /// # use bitintr::*; /// { // 8-bit /// let a: u8 = 128; /// let b: u8 = 128; /// let (lo, hi): (u8, u8) = a.mulx(b); /// // result = 16384 = 0b0100_0000_0000_0000u16 /// // ^~hi~~~~~ ^~lo~~~~~ /// assert_eq!(lo, 0b0000_0000); /// assert_eq!(hi, 0b0100_0000); /// } /// { // 16-bit /// let a: u16 = 65_500; /// let b: u16 = 65_500; /// let (lo, hi): (u16, u16) = a.mulx(b); /// // result = 4290250000 = 0b1111_1111_1011_1000_0000_0101_0001_0000u32 /// // ^~hi~~~~~~~~~~~~~~~ ^~lo~~~~~~~~~~~~~~~ /// assert_eq!(lo, 0b0000_0101_0001_0000); /// assert_eq!(hi, 0b1111_1111_1011_1000); /// } /// { // 32-bit /// let a: u32 = 4_294_967_200; /// let b: u32 = 2; /// let (lo, hi): (u32, u32) = a.mulx(b); /// // result = 8589934400 /// // = 0b0001_1111_1111_1111_1111_1111_1111_0100_0000u64 /// // ^~hi ^~lo~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ /// assert_eq!(lo, 0b1111_1111_1111_1111_1111_1111_0100_0000u32); /// assert_eq!(hi, 0b0001u32); /// } /// { // 64-bit /// let a: u64 = 9_223_372_036_854_775_800; /// let b: u64 = 100; /// let (lo, hi): (u64, u64) = a.mulx(b); /// // result = 922337203685477580000 /// // = 0b00110001_11111111_11111111_11111111_11111111_11111111_11111111_11111100_11100000u128 /// // ^~hi~~~~ ^~lo~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ /// assert_eq!(lo, 0b11111111_11111111_11111111_11111111_11111111_11111111_11111100_11100000u64); /// assert_eq!(hi, 0b00110001u64); /// } /// { // 8-bit /// let a: i8 = 128u8 as i8; /// let b: i8 = 128u8 as i8; /// let (lo, hi): (i8, i8) = a.mulx(b); /// // result = _____ = 0b0100_0000_0000_0000u16 /// // ^~hi~~~~~ ^~lo~~~~~ /// assert_eq!(lo, 0b0000_0000); /// assert_eq!(hi, 0b0100_0000); /// } /// { // 16-bit /// let a: i16 = 65_500u16 as i16; /// let b: i16 = 65_500u16 as i16; /// let (lo, hi): (i16, i16) = a.mulx(b); /// // result = 4290250000 = 0b1111_1111_1011_1000_0000_0101_0001_0000u32 /// // ^~hi~~~~~~~~~~~~~~~ ^~lo~~~~~~~~~~~~~~~ /// assert_eq!(lo, 0b0000_0101_0001_0000u16 as i16); /// assert_eq!(hi, 0b1111_1111_1011_1000u16 as i16); /// } /// ``` fn mulx(self, y: Self) -> (Self, Self); } macro_rules! impl_umulx { ($id:ident, $id_l:ident) => { #[allow(clippy::use_self)] impl Mulx for $id { #[inline] fn mulx(self, y: Self) -> (Self, Self) { const BIT_WIDTH: $id_l = (crate::mem::size_of::<$id>() * 8) as $id_l; let x = self; let result: $id_l = (x as $id_l) * (y as $id_l); let hi = (result >> BIT_WIDTH) as Self; (result as Self, hi) } } }; } impl_umulx!(u8, u16); impl_umulx!(u16, u32); impl_umulx!(u32, u64); impl_umulx!(u64, u128); macro_rules! impl_smulx { ($id:ident, $uid:ident) => { impl Mulx for $id { #[inline] fn mulx(self, y: Self) -> (Self, Self) { let ux = self as $uid; let uy = y as $uid; let (rx, ry) = ux.mulx(uy); (rx as _, ry as _) } } }; } impl_smulx!(i8, u8); impl_smulx!(i16, u16); impl_smulx!(i32, u32); impl_smulx!(i64, u64);