1 | #[cfg (test)] |
2 | use stdarch_test::assert_instr; |
3 | |
4 | #[allow (improper_ctypes)] |
5 | unsafe extern "unadjusted" { |
6 | #[link_name = "llvm.x86.addcarry.64" ] |
7 | unsafefn llvm_addcarry_u64(a: u8, b: u64, c: u64) -> (u8, u64); |
8 | #[link_name = "llvm.x86.addcarryx.u64" ] |
9 | unsafefn llvm_addcarryx_u64(a: u8, b: u64, c: u64, d: *mut u64) -> u8; |
10 | #[link_name = "llvm.x86.subborrow.64" ] |
11 | unsafefn llvm_subborrow_u64(a: u8, b: u64, c: u64) -> (u8, u64); |
12 | } |
13 | |
14 | /// Adds unsigned 64-bit integers `a` and `b` with unsigned 8-bit carry-in `c_in` |
15 | /// (carry or overflow flag), and store the unsigned 64-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_u64) |
19 | #[inline ] |
20 | #[cfg_attr (test, assert_instr(adc))] |
21 | #[stable (feature = "simd_x86_adx" , since = "1.33.0" )] |
22 | pub unsafe fn _addcarry_u64(c_in: u8, a: u64, b: u64, out: &mut u64) -> u8 { |
23 | let (a: u8, b: u64) = llvm_addcarry_u64(a:c_in, b:a, c:b); |
24 | *out = b; |
25 | a |
26 | } |
27 | |
28 | /// Adds unsigned 64-bit integers `a` and `b` with unsigned 8-bit carry-in `c_in` |
29 | /// (carry or overflow flag), and store the unsigned 64-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_u64) |
33 | #[inline ] |
34 | #[target_feature (enable = "adx" )] |
35 | #[cfg_attr (test, assert_instr(adc))] |
36 | #[stable (feature = "simd_x86_adx" , since = "1.33.0" )] |
37 | pub unsafe fn _addcarryx_u64(c_in: u8, a: u64, b: u64, out: &mut u64) -> u8 { |
38 | llvm_addcarryx_u64(a:c_in, b:a, c:b, d:out as *mut _) |
39 | } |
40 | |
41 | /// Adds unsigned 64-bit integers `a` and `b` with unsigned 8-bit carry-in `c_in`. |
42 | /// (carry or overflow flag), and store the unsigned 64-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_u64) |
46 | #[inline ] |
47 | #[cfg_attr (test, assert_instr(sbb))] |
48 | #[stable (feature = "simd_x86_adx" , since = "1.33.0" )] |
49 | pub unsafe fn _subborrow_u64(c_in: u8, a: u64, b: u64, out: &mut u64) -> u8 { |
50 | let (a: u8, b: u64) = llvm_subborrow_u64(a:c_in, b:a, c:b); |
51 | *out = b; |
52 | a |
53 | } |
54 | |
55 | #[cfg (test)] |
56 | mod tests { |
57 | use stdarch_test::simd_test; |
58 | |
59 | use crate::core_arch::x86_64::*; |
60 | |
61 | #[test ] |
62 | fn test_addcarry_u64() { |
63 | unsafe { |
64 | let a = u64::MAX; |
65 | let mut out = 0; |
66 | |
67 | let r = _addcarry_u64(0, a, 1, &mut out); |
68 | assert_eq!(r, 1); |
69 | assert_eq!(out, 0); |
70 | |
71 | let r = _addcarry_u64(0, a, 0, &mut out); |
72 | assert_eq!(r, 0); |
73 | assert_eq!(out, a); |
74 | |
75 | let r = _addcarry_u64(1, a, 1, &mut out); |
76 | assert_eq!(r, 1); |
77 | assert_eq!(out, 1); |
78 | |
79 | let r = _addcarry_u64(1, a, 0, &mut out); |
80 | assert_eq!(r, 1); |
81 | assert_eq!(out, 0); |
82 | |
83 | let r = _addcarry_u64(0, 3, 4, &mut out); |
84 | assert_eq!(r, 0); |
85 | assert_eq!(out, 7); |
86 | |
87 | let r = _addcarry_u64(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_u64() { |
95 | let a = u64::MAX; |
96 | let mut out = 0; |
97 | |
98 | let r = _addcarry_u64(0, a, 1, &mut out); |
99 | assert_eq!(r, 1); |
100 | assert_eq!(out, 0); |
101 | |
102 | let r = _addcarry_u64(0, a, 0, &mut out); |
103 | assert_eq!(r, 0); |
104 | assert_eq!(out, a); |
105 | |
106 | let r = _addcarry_u64(1, a, 1, &mut out); |
107 | assert_eq!(r, 1); |
108 | assert_eq!(out, 1); |
109 | |
110 | let r = _addcarry_u64(1, a, 0, &mut out); |
111 | assert_eq!(r, 1); |
112 | assert_eq!(out, 0); |
113 | |
114 | let r = _addcarry_u64(0, 3, 4, &mut out); |
115 | assert_eq!(r, 0); |
116 | assert_eq!(out, 7); |
117 | |
118 | let r = _addcarry_u64(1, 3, 4, &mut out); |
119 | assert_eq!(r, 0); |
120 | assert_eq!(out, 8); |
121 | } |
122 | |
123 | #[test ] |
124 | fn test_subborrow_u64() { |
125 | unsafe { |
126 | let a = u64::MAX; |
127 | let mut out = 0; |
128 | |
129 | let r = _subborrow_u64(0, 0, 1, &mut out); |
130 | assert_eq!(r, 1); |
131 | assert_eq!(out, a); |
132 | |
133 | let r = _subborrow_u64(0, 0, 0, &mut out); |
134 | assert_eq!(r, 0); |
135 | assert_eq!(out, 0); |
136 | |
137 | let r = _subborrow_u64(1, 0, 1, &mut out); |
138 | assert_eq!(r, 1); |
139 | assert_eq!(out, a - 1); |
140 | |
141 | let r = _subborrow_u64(1, 0, 0, &mut out); |
142 | assert_eq!(r, 1); |
143 | assert_eq!(out, a); |
144 | |
145 | let r = _subborrow_u64(0, 7, 3, &mut out); |
146 | assert_eq!(r, 0); |
147 | assert_eq!(out, 4); |
148 | |
149 | let r = _subborrow_u64(1, 7, 3, &mut out); |
150 | assert_eq!(r, 0); |
151 | assert_eq!(out, 3); |
152 | } |
153 | } |
154 | } |
155 | |