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