1use crate::int::udiv::*;
2
3macro_rules! sdivmod {
4 (
5 $unsigned_fn:ident, // name of the unsigned division function
6 $signed_fn:ident, // name of the signed division function
7 $uX:ident, // unsigned integer type for the inputs and outputs of `$unsigned_name`
8 $iX:ident, // signed integer type for the inputs and outputs of `$signed_name`
9 $($attr:tt),* // attributes
10 ) => {
11 intrinsics! {
12 #[avr_skip]
13 $(
14 #[$attr]
15 )*
16 /// Returns `n / d` and sets `*rem = n % d`
17 pub extern "C" fn $signed_fn(a: $iX, b: $iX, rem: &mut $iX) -> $iX {
18 let a_neg = a < 0;
19 let b_neg = b < 0;
20 let mut a = a;
21 let mut b = b;
22 if a_neg {
23 a = a.wrapping_neg();
24 }
25 if b_neg {
26 b = b.wrapping_neg();
27 }
28 let mut r = *rem as $uX;
29 let t = $unsigned_fn(a as $uX, b as $uX, Some(&mut r)) as $iX;
30 let mut r = r as $iX;
31 if a_neg {
32 r = r.wrapping_neg();
33 }
34 *rem = r;
35 if a_neg != b_neg {
36 t.wrapping_neg()
37 } else {
38 t
39 }
40 }
41 }
42 }
43}
44
45macro_rules! sdiv {
46 (
47 $unsigned_fn:ident, // name of the unsigned division function
48 $signed_fn:ident, // name of the signed division function
49 $uX:ident, // unsigned integer type for the inputs and outputs of `$unsigned_name`
50 $iX:ident, // signed integer type for the inputs and outputs of `$signed_name`
51 $($attr:tt),* // attributes
52 ) => {
53 intrinsics! {
54 #[avr_skip]
55 $(
56 #[$attr]
57 )*
58 /// Returns `n / d`
59 pub extern "C" fn $signed_fn(a: $iX, b: $iX) -> $iX {
60 let a_neg = a < 0;
61 let b_neg = b < 0;
62 let mut a = a;
63 let mut b = b;
64 if a_neg {
65 a = a.wrapping_neg();
66 }
67 if b_neg {
68 b = b.wrapping_neg();
69 }
70 let t = $unsigned_fn(a as $uX, b as $uX) as $iX;
71 if a_neg != b_neg {
72 t.wrapping_neg()
73 } else {
74 t
75 }
76 }
77 }
78 }
79}
80
81macro_rules! smod {
82 (
83 $unsigned_fn:ident, // name of the unsigned division function
84 $signed_fn:ident, // name of the signed division function
85 $uX:ident, // unsigned integer type for the inputs and outputs of `$unsigned_name`
86 $iX:ident, // signed integer type for the inputs and outputs of `$signed_name`
87 $($attr:tt),* // attributes
88 ) => {
89 intrinsics! {
90 #[avr_skip]
91 $(
92 #[$attr]
93 )*
94 /// Returns `n % d`
95 pub extern "C" fn $signed_fn(a: $iX, b: $iX) -> $iX {
96 let a_neg = a < 0;
97 let b_neg = b < 0;
98 let mut a = a;
99 let mut b = b;
100 if a_neg {
101 a = a.wrapping_neg();
102 }
103 if b_neg {
104 b = b.wrapping_neg();
105 }
106 let r = $unsigned_fn(a as $uX, b as $uX) as $iX;
107 if a_neg {
108 r.wrapping_neg()
109 } else {
110 r
111 }
112 }
113 }
114 }
115}
116
117sdivmod!(
118 __udivmodsi4,
119 __divmodsi4,
120 u32,
121 i32,
122 maybe_use_optimized_c_shim
123);
124// The `#[arm_aeabi_alias = __aeabi_idiv]` attribute cannot be made to work with `intrinsics!` in macros
125intrinsics! {
126 #[maybe_use_optimized_c_shim]
127 #[arm_aeabi_alias = __aeabi_idiv]
128 /// Returns `n / d`
129 pub extern "C" fn __divsi3(a: i32, b: i32) -> i32 {
130 let a_neg = a < 0;
131 let b_neg = b < 0;
132 let mut a = a;
133 let mut b = b;
134 if a_neg {
135 a = a.wrapping_neg();
136 }
137 if b_neg {
138 b = b.wrapping_neg();
139 }
140 let t = __udivsi3(a as u32, b as u32) as i32;
141 if a_neg != b_neg {
142 t.wrapping_neg()
143 } else {
144 t
145 }
146 }
147}
148smod!(__umodsi3, __modsi3, u32, i32, maybe_use_optimized_c_shim);
149
150sdivmod!(
151 __udivmoddi4,
152 __divmoddi4,
153 u64,
154 i64,
155 maybe_use_optimized_c_shim
156);
157sdiv!(__udivdi3, __divdi3, u64, i64, maybe_use_optimized_c_shim);
158smod!(__umoddi3, __moddi3, u64, i64, maybe_use_optimized_c_shim);
159
160// LLVM does not currently have a `__divmodti4` function, but GCC does
161sdivmod!(
162 __udivmodti4,
163 __divmodti4,
164 u128,
165 i128,
166 maybe_use_optimized_c_shim
167);
168sdiv!(__udivti3, __divti3, u128, i128, win64_128bit_abi_hack);
169smod!(__umodti3, __modti3, u128, i128, win64_128bit_abi_hack);
170