@@ -167,6 +167,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
167167 // This is a "bitwise" operation, so there's no NaN non-determinism.
168168 this. write_scalar ( Scalar :: from_f64 ( f. abs ( ) ) , dest) ?;
169169 }
170+
170171 "floorf32" | "ceilf32" | "truncf32" | "roundf32" | "rintf32" => {
171172 let [ f] = check_arg_count ( args) ?;
172173 let f = this. read_scalar ( f) ?. to_f32 ( ) ?;
@@ -182,6 +183,22 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
182183 let res = this. adjust_nan ( res, & [ f] ) ;
183184 this. write_scalar ( res, dest) ?;
184185 }
186+ "floorf64" | "ceilf64" | "truncf64" | "roundf64" | "rintf64" => {
187+ let [ f] = check_arg_count ( args) ?;
188+ let f = this. read_scalar ( f) ?. to_f64 ( ) ?;
189+ let mode = match intrinsic_name {
190+ "floorf64" => Round :: TowardNegative ,
191+ "ceilf64" => Round :: TowardPositive ,
192+ "truncf64" => Round :: TowardZero ,
193+ "roundf64" => Round :: NearestTiesToAway ,
194+ "rintf64" => Round :: NearestTiesToEven ,
195+ _ => bug ! ( ) ,
196+ } ;
197+ let res = f. round_to_integral ( mode) . value ;
198+ let res = this. adjust_nan ( res, & [ f] ) ;
199+ this. write_scalar ( res, dest) ?;
200+ }
201+
185202 #[ rustfmt:: skip]
186203 | "sinf32"
187204 | "cosf32"
@@ -211,22 +228,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
211228 let res = this. adjust_nan ( res, & [ f] ) ;
212229 this. write_scalar ( res, dest) ?;
213230 }
214-
215- "floorf64" | "ceilf64" | "truncf64" | "roundf64" | "rintf64" => {
216- let [ f] = check_arg_count ( args) ?;
217- let f = this. read_scalar ( f) ?. to_f64 ( ) ?;
218- let mode = match intrinsic_name {
219- "floorf64" => Round :: TowardNegative ,
220- "ceilf64" => Round :: TowardPositive ,
221- "truncf64" => Round :: TowardZero ,
222- "roundf64" => Round :: NearestTiesToAway ,
223- "rintf64" => Round :: NearestTiesToEven ,
224- _ => bug ! ( ) ,
225- } ;
226- let res = f. round_to_integral ( mode) . value ;
227- let res = this. adjust_nan ( res, & [ f] ) ;
228- this. write_scalar ( res, dest) ?;
229- }
230231 #[ rustfmt:: skip]
231232 | "sinf64"
232233 | "cosf64"
@@ -256,84 +257,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
256257 let res = this. adjust_nan ( res, & [ f] ) ;
257258 this. write_scalar ( res, dest) ?;
258259 }
259- #[ rustfmt:: skip]
260- | "fadd_algebraic"
261- | "fsub_algebraic"
262- | "fmul_algebraic"
263- | "fdiv_algebraic"
264- | "frem_algebraic"
265- => {
266- let [ a, b] = check_arg_count ( args) ?;
267- let a = this. read_immediate ( a) ?;
268- let b = this. read_immediate ( b) ?;
269- let op = match intrinsic_name {
270- "fadd_algebraic" => mir:: BinOp :: Add ,
271- "fsub_algebraic" => mir:: BinOp :: Sub ,
272- "fmul_algebraic" => mir:: BinOp :: Mul ,
273- "fdiv_algebraic" => mir:: BinOp :: Div ,
274- "frem_algebraic" => mir:: BinOp :: Rem ,
275- _ => bug ! ( ) ,
276- } ;
277- let res = this. wrapping_binary_op ( op, & a, & b) ?;
278- // `wrapping_binary_op` already called `generate_nan` if necessary.
279- this. write_immediate ( * res, dest) ?;
280- }
281-
282- #[ rustfmt:: skip]
283- | "fadd_fast"
284- | "fsub_fast"
285- | "fmul_fast"
286- | "fdiv_fast"
287- | "frem_fast"
288- => {
289- let [ a, b] = check_arg_count ( args) ?;
290- let a = this. read_immediate ( a) ?;
291- let b = this. read_immediate ( b) ?;
292- let op = match intrinsic_name {
293- "fadd_fast" => mir:: BinOp :: Add ,
294- "fsub_fast" => mir:: BinOp :: Sub ,
295- "fmul_fast" => mir:: BinOp :: Mul ,
296- "fdiv_fast" => mir:: BinOp :: Div ,
297- "frem_fast" => mir:: BinOp :: Rem ,
298- _ => bug ! ( ) ,
299- } ;
300- let float_finite = |x : & ImmTy < ' tcx , _ > | -> InterpResult < ' tcx , bool > {
301- let ty:: Float ( fty) = x. layout . ty . kind ( ) else {
302- bug ! ( "float_finite: non-float input type {}" , x. layout. ty)
303- } ;
304- Ok ( match fty {
305- FloatTy :: F16 => unimplemented ! ( "f16_f128" ) ,
306- FloatTy :: F32 => x. to_scalar ( ) . to_f32 ( ) ?. is_finite ( ) ,
307- FloatTy :: F64 => x. to_scalar ( ) . to_f64 ( ) ?. is_finite ( ) ,
308- FloatTy :: F128 => unimplemented ! ( "f16_f128" ) ,
309- } )
310- } ;
311- match ( float_finite ( & a) ?, float_finite ( & b) ?) {
312- ( false , false ) => throw_ub_format ! (
313- "`{intrinsic_name}` intrinsic called with non-finite value as both parameters" ,
314- ) ,
315- ( false , _) => throw_ub_format ! (
316- "`{intrinsic_name}` intrinsic called with non-finite value as first parameter" ,
317- ) ,
318- ( _, false ) => throw_ub_format ! (
319- "`{intrinsic_name}` intrinsic called with non-finite value as second parameter" ,
320- ) ,
321- _ => { }
322- }
323- let res = this. wrapping_binary_op ( op, & a, & b) ?;
324- if !float_finite ( & res) ? {
325- throw_ub_format ! ( "`{intrinsic_name}` intrinsic produced non-finite value as result" ) ;
326- }
327- // This cannot be a NaN so we also don't have to apply any non-determinism.
328- // (Also, `wrapping_binary_op` already called `generate_nan` if needed.)
329- this. write_immediate ( * res, dest) ?;
330- }
331260
332- #[ rustfmt:: skip]
333- | "minnumf32"
334- | "maxnumf32"
335- | "copysignf32"
336- => {
261+ "minnumf32" | "maxnumf32" | "copysignf32" => {
337262 let [ a, b] = check_arg_count ( args) ?;
338263 let a = this. read_scalar ( a) ?. to_f32 ( ) ?;
339264 let b = this. read_scalar ( b) ?. to_f32 ( ) ?;
@@ -345,12 +270,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
345270 } ;
346271 this. write_scalar ( Scalar :: from_f32 ( res) , dest) ?;
347272 }
348-
349- #[ rustfmt:: skip]
350- | "minnumf64"
351- | "maxnumf64"
352- | "copysignf64"
353- => {
273+ "minnumf64" | "maxnumf64" | "copysignf64" => {
354274 let [ a, b] = check_arg_count ( args) ?;
355275 let a = this. read_scalar ( a) ?. to_f64 ( ) ?;
356276 let b = this. read_scalar ( b) ?. to_f64 ( ) ?;
@@ -373,7 +293,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
373293 let res = this. adjust_nan ( res, & [ a, b, c] ) ;
374294 this. write_scalar ( res, dest) ?;
375295 }
376-
377296 "fmaf64" => {
378297 let [ a, b, c] = check_arg_count ( args) ?;
379298 let a = this. read_scalar ( a) ?. to_f64 ( ) ?;
@@ -394,7 +313,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
394313 let res = this. adjust_nan ( res, & [ f1, f2] ) ;
395314 this. write_scalar ( res, dest) ?;
396315 }
397-
398316 "powf64" => {
399317 let [ f1, f2] = check_arg_count ( args) ?;
400318 let f1 = this. read_scalar ( f1) ?. to_f64 ( ) ?;
@@ -414,7 +332,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
414332 let res = this. adjust_nan ( res, & [ f] ) ;
415333 this. write_scalar ( res, dest) ?;
416334 }
417-
418335 "powif64" => {
419336 let [ f, i] = check_arg_count ( args) ?;
420337 let f = this. read_scalar ( f) ?. to_f64 ( ) ?;
@@ -425,6 +342,79 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
425342 this. write_scalar ( res, dest) ?;
426343 }
427344
345+ #[ rustfmt:: skip]
346+ | "fadd_algebraic"
347+ | "fsub_algebraic"
348+ | "fmul_algebraic"
349+ | "fdiv_algebraic"
350+ | "frem_algebraic"
351+ => {
352+ let [ a, b] = check_arg_count ( args) ?;
353+ let a = this. read_immediate ( a) ?;
354+ let b = this. read_immediate ( b) ?;
355+ let op = match intrinsic_name {
356+ "fadd_algebraic" => mir:: BinOp :: Add ,
357+ "fsub_algebraic" => mir:: BinOp :: Sub ,
358+ "fmul_algebraic" => mir:: BinOp :: Mul ,
359+ "fdiv_algebraic" => mir:: BinOp :: Div ,
360+ "frem_algebraic" => mir:: BinOp :: Rem ,
361+ _ => bug ! ( ) ,
362+ } ;
363+ let res = this. wrapping_binary_op ( op, & a, & b) ?;
364+ // `wrapping_binary_op` already called `generate_nan` if necessary.
365+ this. write_immediate ( * res, dest) ?;
366+ }
367+
368+ #[ rustfmt:: skip]
369+ | "fadd_fast"
370+ | "fsub_fast"
371+ | "fmul_fast"
372+ | "fdiv_fast"
373+ | "frem_fast"
374+ => {
375+ let [ a, b] = check_arg_count ( args) ?;
376+ let a = this. read_immediate ( a) ?;
377+ let b = this. read_immediate ( b) ?;
378+ let op = match intrinsic_name {
379+ "fadd_fast" => mir:: BinOp :: Add ,
380+ "fsub_fast" => mir:: BinOp :: Sub ,
381+ "fmul_fast" => mir:: BinOp :: Mul ,
382+ "fdiv_fast" => mir:: BinOp :: Div ,
383+ "frem_fast" => mir:: BinOp :: Rem ,
384+ _ => bug ! ( ) ,
385+ } ;
386+ let float_finite = |x : & ImmTy < ' tcx , _ > | -> InterpResult < ' tcx , bool > {
387+ let ty:: Float ( fty) = x. layout . ty . kind ( ) else {
388+ bug ! ( "float_finite: non-float input type {}" , x. layout. ty)
389+ } ;
390+ Ok ( match fty {
391+ FloatTy :: F16 => unimplemented ! ( "f16_f128" ) ,
392+ FloatTy :: F32 => x. to_scalar ( ) . to_f32 ( ) ?. is_finite ( ) ,
393+ FloatTy :: F64 => x. to_scalar ( ) . to_f64 ( ) ?. is_finite ( ) ,
394+ FloatTy :: F128 => unimplemented ! ( "f16_f128" ) ,
395+ } )
396+ } ;
397+ match ( float_finite ( & a) ?, float_finite ( & b) ?) {
398+ ( false , false ) => throw_ub_format ! (
399+ "`{intrinsic_name}` intrinsic called with non-finite value as both parameters" ,
400+ ) ,
401+ ( false , _) => throw_ub_format ! (
402+ "`{intrinsic_name}` intrinsic called with non-finite value as first parameter" ,
403+ ) ,
404+ ( _, false ) => throw_ub_format ! (
405+ "`{intrinsic_name}` intrinsic called with non-finite value as second parameter" ,
406+ ) ,
407+ _ => { }
408+ }
409+ let res = this. wrapping_binary_op ( op, & a, & b) ?;
410+ if !float_finite ( & res) ? {
411+ throw_ub_format ! ( "`{intrinsic_name}` intrinsic produced non-finite value as result" ) ;
412+ }
413+ // This cannot be a NaN so we also don't have to apply any non-determinism.
414+ // (Also, `wrapping_binary_op` already called `generate_nan` if needed.)
415+ this. write_immediate ( * res, dest) ?;
416+ }
417+
428418 "float_to_int_unchecked" => {
429419 let [ val] = check_arg_count ( args) ?;
430420 let val = this. read_immediate ( val) ?;
0 commit comments