compiler_builtins/int/
sdiv.rs

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            $(
13                #[$attr]
14            )*
15            /// Returns `n / d` and sets `*rem = n % d`
16            pub extern "C" fn $signed_fn(a: $iX, b: $iX, rem: &mut $iX) -> $iX {
17                let a_neg = a < 0;
18                let b_neg = b < 0;
19                let mut a = a;
20                let mut b = b;
21
22                if a_neg {
23                    a = a.wrapping_neg();
24                }
25                if b_neg {
26                    b = b.wrapping_neg();
27                }
28
29                let mut r = *rem as $uX;
30                let t = $unsigned_fn(a as $uX, b as $uX, Some(&mut r)) as $iX;
31                let mut r = r as $iX;
32
33                if a_neg {
34                    r = r.wrapping_neg();
35                }
36                *rem = r;
37                if a_neg != b_neg {
38                    t.wrapping_neg()
39                } else {
40                    t
41                }
42            }
43        }
44    }
45}
46
47macro_rules! sdiv {
48    (
49        $unsigned_fn:ident, // name of the unsigned division function
50        $signed_fn:ident, // name of the signed division function
51        $uX:ident, // unsigned integer type for the inputs and outputs of `$unsigned_name`
52        $iX:ident, // signed integer type for the inputs and outputs of `$signed_name`
53        $($attr:tt),* // attributes
54    ) => {
55        intrinsics! {
56            $(
57                #[$attr]
58            )*
59            /// Returns `n / d`
60            pub extern "C" fn $signed_fn(a: $iX, b: $iX) -> $iX {
61                let a_neg = a < 0;
62                let b_neg = b < 0;
63                let mut a = a;
64                let mut b = b;
65                if a_neg {
66                    a = a.wrapping_neg();
67                }
68                if b_neg {
69                    b = b.wrapping_neg();
70                }
71                let t = $unsigned_fn(a as $uX, b as $uX) as $iX;
72                if a_neg != b_neg {
73                    t.wrapping_neg()
74                } else {
75                    t
76                }
77            }
78        }
79    }
80}
81
82macro_rules! smod {
83    (
84        $unsigned_fn:ident, // name of the unsigned division function
85        $signed_fn:ident, // name of the signed division function
86        $uX:ident, // unsigned integer type for the inputs and outputs of `$unsigned_name`
87        $iX:ident, // signed integer type for the inputs and outputs of `$signed_name`
88        $($attr:tt),* // attributes
89    ) => {
90        intrinsics! {
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
117#[cfg(not(target_arch = "avr"))]
118sdivmod!(
119    __udivmodsi4,
120    __divmodsi4,
121    u32,
122    i32,
123    maybe_use_optimized_c_shim
124);
125
126#[cfg(target_arch = "avr")]
127intrinsics! {
128    /// Returns `a / b` and `a % b` packed together.
129    ///
130    /// Ideally we'd use `-> (u32, u32)` or some kind of a packed struct, but
131    /// both force a stack allocation, while our result has to be in R18:R26.
132    pub extern "C" fn __divmodsi4(a: i32, b: i32) -> u64 {
133        let a_neg = a < 0;
134        let b_neg = b < 0;
135        let mut a = a;
136        let mut b = b;
137
138        if a_neg {
139            a = a.wrapping_neg();
140        }
141        if b_neg {
142            b = b.wrapping_neg();
143        }
144
145        let tr = __udivmodsi4(a as u32, b as u32);
146        let mut t = tr as u32 as i32;
147        let mut r = (tr >> 32) as u32 as i32;
148
149        if a_neg {
150            r = r.wrapping_neg();
151        }
152        if a_neg != b_neg {
153            t = t.wrapping_neg();
154        }
155
156        ((r as u32 as u64) << 32) | (t as u32 as u64)
157    }
158}
159
160// The `#[arm_aeabi_alias = __aeabi_idiv]` attribute cannot be made to work with `intrinsics!` in macros
161intrinsics! {
162    #[maybe_use_optimized_c_shim]
163    #[arm_aeabi_alias = __aeabi_idiv]
164    /// Returns `n / d`
165    pub extern "C" fn __divsi3(a: i32, b: i32) -> i32 {
166        let a_neg = a < 0;
167        let b_neg = b < 0;
168        let mut a = a;
169        let mut b = b;
170        if a_neg {
171            a = a.wrapping_neg();
172        }
173        if b_neg {
174            b = b.wrapping_neg();
175        }
176        let t = __udivsi3(a as u32, b as u32) as i32;
177        if a_neg != b_neg {
178            t.wrapping_neg()
179        } else {
180            t
181        }
182    }
183}
184smod!(__umodsi3, __modsi3, u32, i32, maybe_use_optimized_c_shim);
185
186sdivmod!(
187    __udivmoddi4,
188    __divmoddi4,
189    u64,
190    i64,
191    maybe_use_optimized_c_shim
192);
193sdiv!(__udivdi3, __divdi3, u64, i64, maybe_use_optimized_c_shim);
194smod!(__umoddi3, __moddi3, u64, i64, maybe_use_optimized_c_shim);
195
196// LLVM does not currently have a `__divmodti4` function, but GCC does
197sdivmod!(
198    __udivmodti4,
199    __divmodti4,
200    u128,
201    i128,
202    maybe_use_optimized_c_shim
203);
204sdiv!(__udivti3, __divti3, u128, i128,);
205smod!(__umodti3, __modti3, u128, i128,);