core/stdarch/crates/core_arch/src/x86/
adx.rs

1#[cfg(test)]
2use stdarch_test::assert_instr;
3
4#[allow(improper_ctypes)]
5unsafe extern "unadjusted" {
6    #[link_name = "llvm.x86.addcarry.32"]
7    fn llvm_addcarry_u32(a: u8, b: u32, c: u32) -> (u8, u32);
8    #[link_name = "llvm.x86.addcarryx.u32"]
9    fn llvm_addcarryx_u32(a: u8, b: u32, c: u32, d: *mut u32) -> u8;
10    #[link_name = "llvm.x86.subborrow.32"]
11    fn llvm_subborrow_u32(a: u8, b: u32, c: u32) -> (u8, u32);
12}
13
14/// Adds unsigned 32-bit integers `a` and `b` with unsigned 8-bit carry-in `c_in`
15/// (carry or overflow flag), and store the unsigned 32-bit result in `out`, and the carry-out
16/// is returned (carry or overflow flag).
17///
18/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_addcarry_u32)
19#[inline]
20#[cfg_attr(test, assert_instr(adc))]
21#[stable(feature = "simd_x86_adx", since = "1.33.0")]
22pub unsafe fn _addcarry_u32(c_in: u8, a: u32, b: u32, out: &mut u32) -> u8 {
23    let (a, b) = llvm_addcarry_u32(c_in, a, b);
24    *out = b;
25    a
26}
27
28/// Adds unsigned 32-bit integers `a` and `b` with unsigned 8-bit carry-in `c_in`
29/// (carry or overflow flag), and store the unsigned 32-bit result in `out`, and
30/// the carry-out is returned (carry or overflow flag).
31///
32/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_addcarryx_u32)
33#[inline]
34#[target_feature(enable = "adx")]
35#[cfg_attr(test, assert_instr(adc))]
36#[stable(feature = "simd_x86_adx", since = "1.33.0")]
37pub unsafe fn _addcarryx_u32(c_in: u8, a: u32, b: u32, out: &mut u32) -> u8 {
38    llvm_addcarryx_u32(c_in, a, b, out as *mut _)
39}
40
41/// Adds unsigned 32-bit integers `a` and `b` with unsigned 8-bit carry-in `c_in`
42/// (carry or overflow flag), and store the unsigned 32-bit result in `out`, and
43/// the carry-out is returned (carry or overflow flag).
44///
45/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_subborrow_u32)
46#[inline]
47#[cfg_attr(test, assert_instr(sbb))]
48#[stable(feature = "simd_x86_adx", since = "1.33.0")]
49pub unsafe fn _subborrow_u32(c_in: u8, a: u32, b: u32, out: &mut u32) -> u8 {
50    let (a, b) = llvm_subborrow_u32(c_in, a, b);
51    *out = b;
52    a
53}
54
55#[cfg(test)]
56mod tests {
57    use stdarch_test::simd_test;
58
59    use crate::core_arch::x86::*;
60
61    #[test]
62    fn test_addcarry_u32() {
63        unsafe {
64            let a = u32::MAX;
65            let mut out = 0;
66
67            let r = _addcarry_u32(0, a, 1, &mut out);
68            assert_eq!(r, 1);
69            assert_eq!(out, 0);
70
71            let r = _addcarry_u32(0, a, 0, &mut out);
72            assert_eq!(r, 0);
73            assert_eq!(out, a);
74
75            let r = _addcarry_u32(1, a, 1, &mut out);
76            assert_eq!(r, 1);
77            assert_eq!(out, 1);
78
79            let r = _addcarry_u32(1, a, 0, &mut out);
80            assert_eq!(r, 1);
81            assert_eq!(out, 0);
82
83            let r = _addcarry_u32(0, 3, 4, &mut out);
84            assert_eq!(r, 0);
85            assert_eq!(out, 7);
86
87            let r = _addcarry_u32(1, 3, 4, &mut out);
88            assert_eq!(r, 0);
89            assert_eq!(out, 8);
90        }
91    }
92
93    #[simd_test(enable = "adx")]
94    unsafe fn test_addcarryx_u32() {
95        let a = u32::MAX;
96        let mut out = 0;
97
98        let r = _addcarryx_u32(0, a, 1, &mut out);
99        assert_eq!(r, 1);
100        assert_eq!(out, 0);
101
102        let r = _addcarryx_u32(0, a, 0, &mut out);
103        assert_eq!(r, 0);
104        assert_eq!(out, a);
105
106        let r = _addcarryx_u32(1, a, 1, &mut out);
107        assert_eq!(r, 1);
108        assert_eq!(out, 1);
109
110        let r = _addcarryx_u32(1, a, 0, &mut out);
111        assert_eq!(r, 1);
112        assert_eq!(out, 0);
113
114        let r = _addcarryx_u32(0, 3, 4, &mut out);
115        assert_eq!(r, 0);
116        assert_eq!(out, 7);
117
118        let r = _addcarryx_u32(1, 3, 4, &mut out);
119        assert_eq!(r, 0);
120        assert_eq!(out, 8);
121    }
122
123    #[simd_test(enable = "adx")]
124    unsafe fn test_addcarryx_u32_2() {
125        unsafe fn add_1_2_3() -> u32 {
126            let mut out = 0;
127            _addcarryx_u32(1, 2, 3, &mut out);
128            out
129        }
130        assert_eq!(6, add_1_2_3());
131    }
132
133    #[test]
134    fn test_subborrow_u32() {
135        unsafe {
136            let a = u32::MAX;
137            let mut out = 0;
138
139            let r = _subborrow_u32(0, 0, 1, &mut out);
140            assert_eq!(r, 1);
141            assert_eq!(out, a);
142
143            let r = _subborrow_u32(0, 0, 0, &mut out);
144            assert_eq!(r, 0);
145            assert_eq!(out, 0);
146
147            let r = _subborrow_u32(1, 0, 1, &mut out);
148            assert_eq!(r, 1);
149            assert_eq!(out, a - 1);
150
151            let r = _subborrow_u32(1, 0, 0, &mut out);
152            assert_eq!(r, 1);
153            assert_eq!(out, a);
154
155            let r = _subborrow_u32(0, 7, 3, &mut out);
156            assert_eq!(r, 0);
157            assert_eq!(out, 4);
158
159            let r = _subborrow_u32(1, 7, 3, &mut out);
160            assert_eq!(r, 0);
161            assert_eq!(out, 3);
162        }
163    }
164}