@@ -89,6 +89,73 @@ fp_convert!(__floatunsisf: u32, f32);
89
89
fp_convert ! ( __floatunsidf: u32 , f64 ) ;
90
90
fp_convert ! ( __floatundidf: u64 , f64 ) ;
91
91
92
+ #[ derive( PartialEq , Debug ) ]
93
+ enum Sign {
94
+ Positive ,
95
+ Negative
96
+ }
97
+ macro_rules! fp_fix {
98
+ ( $intrinsic: ident: $fty: ty, $ity: ty) => {
99
+ pub extern "C" fn $intrinsic( f: $fty) -> $ity {
100
+ let fixint_min = <$ity>:: min_value( ) ;
101
+ let fixint_max = <$ity>:: max_value( ) ;
102
+ let fixint_bits = <$ity>:: bits( ) as usize ;
103
+ let fixint_unsigned = fixint_min == 0 ;
104
+
105
+ let sign_bit = <$fty>:: sign_mask( ) ;
106
+ let significand_bits = <$fty>:: significand_bits( ) as usize ;
107
+ let exponent_bias = <$fty>:: exponent_bias( ) as usize ;
108
+ //let exponent_max = <$fty>::exponent_max() as usize;
109
+
110
+ // Break a into sign, exponent, significand
111
+ let a_rep = <$fty>:: repr( f) ;
112
+ let a_abs = a_rep & !sign_bit;
113
+
114
+ // this is used to work around -1 not being available for unsigned
115
+ let sign = if ( a_rep & sign_bit) == 0 { Sign :: Positive } else { Sign :: Negative } ;
116
+ let mut exponent = ( a_abs >> significand_bits) as usize ;
117
+ let significand = ( a_abs & <$fty>:: significand_mask( ) ) | <$fty>:: implicit_bit( ) ;
118
+
119
+ // if < 1 or unsigned & negative
120
+ if exponent < exponent_bias ||
121
+ fixint_unsigned && sign == Sign :: Negative {
122
+ return 0
123
+ }
124
+ exponent -= exponent_bias;
125
+
126
+ // If the value is infinity, saturate.
127
+ // If the value is too large for the integer type, 0.
128
+ if exponent >= ( if fixint_unsigned { fixint_bits} else { fixint_bits -1 } ) {
129
+ return if sign == Sign :: Positive { fixint_max} else { fixint_min}
130
+ }
131
+ // If 0 <= exponent < significand_bits, right shift to get the result.
132
+ // Otherwise, shift left.
133
+ // (sign - 1) will never overflow as negative signs are already returned as 0 for unsigned
134
+ let r = if exponent < significand_bits {
135
+ ( significand >> ( significand_bits - exponent) ) as $ity
136
+ } else {
137
+ ( significand as $ity) << ( exponent - significand_bits)
138
+ } ;
139
+
140
+ if sign == Sign :: Negative {
141
+ ( !r) . wrapping_add( 1 )
142
+ } else {
143
+ r
144
+ }
145
+ }
146
+ }
147
+ }
148
+
149
+ fp_fix ! ( __fixsfsi: f32 , i32 ) ;
150
+ fp_fix ! ( __fixsfdi: f32 , i64 ) ;
151
+ fp_fix ! ( __fixdfsi: f64 , i32 ) ;
152
+ fp_fix ! ( __fixdfdi: f64 , i64 ) ;
153
+
154
+ fp_fix ! ( __fixunssfsi: f32 , u32 ) ;
155
+ fp_fix ! ( __fixunssfdi: f32 , u64 ) ;
156
+ fp_fix ! ( __fixunsdfsi: f64 , u32 ) ;
157
+ fp_fix ! ( __fixunsdfdi: f64 , u64 ) ;
158
+
92
159
// NOTE(cfg) for some reason, on arm*-unknown-linux-gnueabihf, our implementation doesn't
93
160
// match the output of its gcc_s or compiler-rt counterpart. Until we investigate further, we'll
94
161
// just avoid testing against them on those targets. Do note that our implementation gives the
@@ -129,5 +196,47 @@ mod tests {
129
196
-> Option <F64 > {
130
197
Some ( F64 ( f( a. 0 ) ) )
131
198
}
199
+
200
+ fn __fixsfsi( f: extern fn ( f32 ) -> i32 ,
201
+ a: F32 )
202
+ -> Option <I32 > {
203
+ Some ( I32 ( f( a. 0 ) ) )
204
+ }
205
+ fn __fixsfdi( f: extern fn ( f32 ) -> i64 ,
206
+ a: F32 )
207
+ -> Option <I64 > {
208
+ Some ( I64 ( f( a. 0 ) ) )
209
+ }
210
+ fn __fixdfsi( f: extern fn ( f64 ) -> i32 ,
211
+ a: F64 )
212
+ -> Option <I32 > {
213
+ Some ( I32 ( f( a. 0 ) ) )
214
+ }
215
+ fn __fixdfdi( f: extern fn ( f64 ) -> i64 ,
216
+ a: F64 )
217
+ -> Option <I64 > {
218
+ Some ( I64 ( f( a. 0 ) ) )
219
+ }
220
+
221
+ fn __fixunssfsi( f: extern fn ( f32 ) -> u32 ,
222
+ a: F32 )
223
+ -> Option <U32 > {
224
+ Some ( U32 ( f( a. 0 ) ) )
225
+ }
226
+ fn __fixunssfdi( f: extern fn ( f32 ) -> u64 ,
227
+ a: F32 )
228
+ -> Option <U64 > {
229
+ Some ( U64 ( f( a. 0 ) ) )
230
+ }
231
+ fn __fixunsdfsi( f: extern fn ( f64 ) -> u32 ,
232
+ a: F64 )
233
+ -> Option <U32 > {
234
+ Some ( U32 ( f( a. 0 ) ) )
235
+ }
236
+ fn __fixunsdfdi( f: extern fn ( f64 ) -> u64 ,
237
+ a: F64 )
238
+ -> Option <U64 > {
239
+ Some ( U64 ( f( a. 0 ) ) )
240
+ }
132
241
}
133
242
}
0 commit comments