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