@@ -5,10 +5,17 @@ use rustc_span::{sym, Symbol};
55use  rustc_target:: abi:: { Endian ,  HasDataLayout } ; 
66
77use  crate :: helpers:: { 
8-     bool_to_simd_element,  check_arg_count,  round_to_next_multiple_of,  simd_element_to_bool, 
8+     bool_to_simd_element,  check_arg_count,  round_to_next_multiple_of,  simd_element_to_bool,  ToHost , 
9+     ToSoft , 
910} ; 
1011use  crate :: * ; 
1112
13+ #[ derive( Copy ,  Clone ) ]  
14+ pub ( crate )  enum  MinMax  { 
15+     Min , 
16+     Max , 
17+ } 
18+ 
1219impl < ' mir ,  ' tcx :  ' mir >  EvalContextExt < ' mir ,  ' tcx >  for  crate :: MiriInterpCx < ' mir ,  ' tcx >  { } 
1320pub  trait  EvalContextExt < ' mir ,  ' tcx :  ' mir > :  crate :: MiriInterpCxExt < ' mir ,  ' tcx >  { 
1421    /// Calls the simd intrinsic `intrinsic`; the `simd_` prefix has already been removed. 
@@ -67,13 +74,17 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
6774                    let  op = this. read_immediate ( & this. project_index ( & op,  i) ?) ?; 
6875                    let  dest = this. project_index ( & dest,  i) ?; 
6976                    let  val = match  which { 
70-                         Op :: MirOp ( mir_op)  => this. wrapping_unary_op ( mir_op,  & op) ?. to_scalar ( ) , 
77+                         Op :: MirOp ( mir_op)  => { 
78+                             // This already does NaN adjustments 
79+                             this. wrapping_unary_op ( mir_op,  & op) ?. to_scalar ( ) 
80+                         } 
7181                        Op :: Abs  => { 
7282                            // Works for f32 and f64. 
7383                            let  ty:: Float ( float_ty)  = op. layout . ty . kind ( )  else  { 
7484                                span_bug ! ( this. cur_span( ) ,  "{} operand is not a float" ,  intrinsic_name) 
7585                            } ; 
7686                            let  op = op. to_scalar ( ) ; 
87+                             // "Bitwise" operation, no NaN adjustments 
7788                            match  float_ty { 
7889                                FloatTy :: F32  => Scalar :: from_f32 ( op. to_f32 ( ) ?. abs ( ) ) , 
7990                                FloatTy :: F64  => Scalar :: from_f64 ( op. to_f64 ( ) ?. abs ( ) ) , 
@@ -86,14 +97,16 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
8697                            // FIXME using host floats 
8798                            match  float_ty { 
8899                                FloatTy :: F32  => { 
89-                                     let  f = f32:: from_bits ( op. to_scalar ( ) . to_u32 ( ) ?) ; 
90-                                     let  res = f. sqrt ( ) ; 
91-                                     Scalar :: from_u32 ( res. to_bits ( ) ) 
100+                                     let  f = op. to_scalar ( ) . to_f32 ( ) ?; 
101+                                     let  res = f. to_host ( ) . sqrt ( ) . to_soft ( ) ; 
102+                                     let  res = this. adjust_nan ( res,  & [ f] ) ; 
103+                                     Scalar :: from ( res) 
92104                                } 
93105                                FloatTy :: F64  => { 
94-                                     let  f = f64:: from_bits ( op. to_scalar ( ) . to_u64 ( ) ?) ; 
95-                                     let  res = f. sqrt ( ) ; 
96-                                     Scalar :: from_u64 ( res. to_bits ( ) ) 
106+                                     let  f = op. to_scalar ( ) . to_f64 ( ) ?; 
107+                                     let  res = f. to_host ( ) . sqrt ( ) . to_soft ( ) ; 
108+                                     let  res = this. adjust_nan ( res,  & [ f] ) ; 
109+                                     Scalar :: from ( res) 
97110                                } 
98111                            } 
99112                        } 
@@ -105,11 +118,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
105118                                FloatTy :: F32  => { 
106119                                    let  f = op. to_scalar ( ) . to_f32 ( ) ?; 
107120                                    let  res = f. round_to_integral ( rounding) . value ; 
121+                                     let  res = this. adjust_nan ( res,  & [ f] ) ; 
108122                                    Scalar :: from_f32 ( res) 
109123                                } 
110124                                FloatTy :: F64  => { 
111125                                    let  f = op. to_scalar ( ) . to_f64 ( ) ?; 
112126                                    let  res = f. round_to_integral ( rounding) . value ; 
127+                                     let  res = this. adjust_nan ( res,  & [ f] ) ; 
113128                                    Scalar :: from_f64 ( res) 
114129                                } 
115130                            } 
@@ -157,8 +172,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
157172                enum  Op  { 
158173                    MirOp ( BinOp ) , 
159174                    SaturatingOp ( BinOp ) , 
160-                     FMax , 
161-                     FMin , 
175+                     FMinMax ( MinMax ) , 
162176                    WrappingOffset , 
163177                } 
164178                let  which = match  intrinsic_name { 
@@ -178,8 +192,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
178192                    "le"  => Op :: MirOp ( BinOp :: Le ) , 
179193                    "gt"  => Op :: MirOp ( BinOp :: Gt ) , 
180194                    "ge"  => Op :: MirOp ( BinOp :: Ge ) , 
181-                     "fmax"  => Op :: FMax , 
182-                     "fmin"  => Op :: FMin , 
195+                     "fmax"  => Op :: FMinMax ( MinMax :: Max ) , 
196+                     "fmin"  => Op :: FMinMax ( MinMax :: Min ) , 
183197                    "saturating_add"  => Op :: SaturatingOp ( BinOp :: Add ) , 
184198                    "saturating_sub"  => Op :: SaturatingOp ( BinOp :: Sub ) , 
185199                    "arith_offset"  => Op :: WrappingOffset , 
@@ -192,6 +206,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
192206                    let  dest = this. project_index ( & dest,  i) ?; 
193207                    let  val = match  which { 
194208                        Op :: MirOp ( mir_op)  => { 
209+                             // This does NaN adjustments. 
195210                            let  ( val,  overflowed)  = this. overflowing_binary_op ( mir_op,  & left,  & right) ?; 
196211                            if  matches ! ( mir_op,  BinOp :: Shl  | BinOp :: Shr )  { 
197212                                // Shifts have extra UB as SIMD operations that the MIR binop does not have. 
@@ -225,11 +240,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
225240                            let  offset_ptr = ptr. wrapping_signed_offset ( offset_bytes,  this) ; 
226241                            Scalar :: from_maybe_pointer ( offset_ptr,  this) 
227242                        } 
228-                         Op :: FMax  => { 
229-                             fmax_op ( & left,  & right) ?
230-                         } 
231-                         Op :: FMin  => { 
232-                             fmin_op ( & left,  & right) ?
243+                         Op :: FMinMax ( op)  => { 
244+                             this. fminmax_op ( op,  & left,  & right) ?
233245                        } 
234246                    } ; 
235247                    this. write_scalar ( val,  & dest) ?; 
@@ -259,18 +271,20 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
259271                    } ; 
260272                    let  val = match  float_ty { 
261273                        FloatTy :: F32  => { 
262-                             let  a = f32:: from_bits ( a. to_u32 ( ) ?) ; 
263-                             let  b = f32:: from_bits ( b. to_u32 ( ) ?) ; 
264-                             let  c = f32:: from_bits ( c. to_u32 ( ) ?) ; 
265-                             let  res = a. mul_add ( b,  c) ; 
266-                             Scalar :: from_u32 ( res. to_bits ( ) ) 
274+                             let  a = a. to_f32 ( ) ?; 
275+                             let  b = b. to_f32 ( ) ?; 
276+                             let  c = c. to_f32 ( ) ?; 
277+                             let  res = a. to_host ( ) . mul_add ( b. to_host ( ) ,  c. to_host ( ) ) . to_soft ( ) ; 
278+                             let  res = this. adjust_nan ( res,  & [ a,  b,  c] ) ; 
279+                             Scalar :: from ( res) 
267280                        } 
268281                        FloatTy :: F64  => { 
269-                             let  a = f64:: from_bits ( a. to_u64 ( ) ?) ; 
270-                             let  b = f64:: from_bits ( b. to_u64 ( ) ?) ; 
271-                             let  c = f64:: from_bits ( c. to_u64 ( ) ?) ; 
272-                             let  res = a. mul_add ( b,  c) ; 
273-                             Scalar :: from_u64 ( res. to_bits ( ) ) 
282+                             let  a = a. to_f64 ( ) ?; 
283+                             let  b = b. to_f64 ( ) ?; 
284+                             let  c = c. to_f64 ( ) ?; 
285+                             let  res = a. to_host ( ) . mul_add ( b. to_host ( ) ,  c. to_host ( ) ) . to_soft ( ) ; 
286+                             let  res = this. adjust_nan ( res,  & [ a,  b,  c] ) ; 
287+                             Scalar :: from ( res) 
274288                        } 
275289                    } ; 
276290                    this. write_scalar ( val,  & dest) ?; 
@@ -295,17 +309,16 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
295309                enum  Op  { 
296310                    MirOp ( BinOp ) , 
297311                    MirOpBool ( BinOp ) , 
298-                     Max , 
299-                     Min , 
312+                     MinMax ( MinMax ) , 
300313                } 
301314                let  which = match  intrinsic_name { 
302315                    "reduce_and"  => Op :: MirOp ( BinOp :: BitAnd ) , 
303316                    "reduce_or"  => Op :: MirOp ( BinOp :: BitOr ) , 
304317                    "reduce_xor"  => Op :: MirOp ( BinOp :: BitXor ) , 
305318                    "reduce_any"  => Op :: MirOpBool ( BinOp :: BitOr ) , 
306319                    "reduce_all"  => Op :: MirOpBool ( BinOp :: BitAnd ) , 
307-                     "reduce_max"  => Op :: Max , 
308-                     "reduce_min"  => Op :: Min , 
320+                     "reduce_max"  => Op :: MinMax ( MinMax :: Max ) , 
321+                     "reduce_min"  => Op :: MinMax ( MinMax :: Min ) , 
309322                    _ => unreachable ! ( ) , 
310323                } ; 
311324
@@ -325,24 +338,16 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
325338                            let  op = imm_from_bool ( simd_element_to_bool ( op) ?) ; 
326339                            this. wrapping_binary_op ( mir_op,  & res,  & op) ?
327340                        } 
328-                         Op :: Max  => { 
329-                             if  matches ! ( res. layout. ty. kind( ) ,  ty:: Float ( _) )  { 
330-                                 ImmTy :: from_scalar ( fmax_op ( & res,  & op) ?,  res. layout ) 
331-                             }  else  { 
332-                                 // Just boring integers, so NaNs to worry about 
333-                                 if  this. wrapping_binary_op ( BinOp :: Ge ,  & res,  & op) ?. to_scalar ( ) . to_bool ( ) ? { 
334-                                     res
335-                                 }  else  { 
336-                                     op
337-                                 } 
338-                             } 
339-                         } 
340-                         Op :: Min  => { 
341+                         Op :: MinMax ( mmop)  => { 
341342                            if  matches ! ( res. layout. ty. kind( ) ,  ty:: Float ( _) )  { 
342-                                 ImmTy :: from_scalar ( fmin_op ( & res,  & op) ?,  res. layout ) 
343+                                 ImmTy :: from_scalar ( this . fminmax_op ( mmop ,   & res,  & op) ?,  res. layout ) 
343344                            }  else  { 
344345                                // Just boring integers, so NaNs to worry about 
345-                                 if  this. wrapping_binary_op ( BinOp :: Le ,  & res,  & op) ?. to_scalar ( ) . to_bool ( ) ? { 
346+                                 let  mirop = match  mmop { 
347+                                     MinMax :: Min  => BinOp :: Le , 
348+                                     MinMax :: Max  => BinOp :: Ge , 
349+                                 } ; 
350+                                 if  this. wrapping_binary_op ( mirop,  & res,  & op) ?. to_scalar ( ) . to_bool ( ) ? { 
346351                                    res
347352                                }  else  { 
348353                                    op
@@ -709,6 +714,43 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
709714        } 
710715        Ok ( ( ) ) 
711716    } 
717+ 
718+     fn  fminmax_op ( 
719+         & self , 
720+         op :  MinMax , 
721+         left :  & ImmTy < ' tcx ,  Provenance > , 
722+         right :  & ImmTy < ' tcx ,  Provenance > , 
723+     )  -> InterpResult < ' tcx ,  Scalar < Provenance > >  { 
724+         let  this = self . eval_context_ref ( ) ; 
725+         assert_eq ! ( left. layout. ty,  right. layout. ty) ; 
726+         let  ty:: Float ( float_ty)  = left. layout . ty . kind ( )  else  { 
727+             bug ! ( "fmax operand is not a float" ) 
728+         } ; 
729+         let  left = left. to_scalar ( ) ; 
730+         let  right = right. to_scalar ( ) ; 
731+         Ok ( match  float_ty { 
732+             FloatTy :: F32  => { 
733+                 let  left = left. to_f32 ( ) ?; 
734+                 let  right = right. to_f32 ( ) ?; 
735+                 let  res = match  op { 
736+                     MinMax :: Min  => left. min ( right) , 
737+                     MinMax :: Max  => left. max ( right) , 
738+                 } ; 
739+                 let  res = this. adjust_nan ( res,  & [ left,  right] ) ; 
740+                 Scalar :: from_f32 ( res) 
741+             } 
742+             FloatTy :: F64  => { 
743+                 let  left = left. to_f64 ( ) ?; 
744+                 let  right = right. to_f64 ( ) ?; 
745+                 let  res = match  op { 
746+                     MinMax :: Min  => left. min ( right) , 
747+                     MinMax :: Max  => left. max ( right) , 
748+                 } ; 
749+                 let  res = this. adjust_nan ( res,  & [ left,  right] ) ; 
750+                 Scalar :: from_f64 ( res) 
751+             } 
752+         } ) 
753+     } 
712754} 
713755
714756fn  simd_bitmask_index ( idx :  u32 ,  vec_len :  u32 ,  endianness :  Endian )  -> u32  { 
@@ -719,31 +761,3 @@ fn simd_bitmask_index(idx: u32, vec_len: u32, endianness: Endian) -> u32 {
719761        Endian :: Big  => vec_len - 1  - idx,  // reverse order of bits 
720762    } 
721763} 
722- 
723- fn  fmax_op < ' tcx > ( 
724-     left :  & ImmTy < ' tcx ,  Provenance > , 
725-     right :  & ImmTy < ' tcx ,  Provenance > , 
726- )  -> InterpResult < ' tcx ,  Scalar < Provenance > >  { 
727-     assert_eq ! ( left. layout. ty,  right. layout. ty) ; 
728-     let  ty:: Float ( float_ty)  = left. layout . ty . kind ( )  else  {  bug ! ( "fmax operand is not a float" )  } ; 
729-     let  left = left. to_scalar ( ) ; 
730-     let  right = right. to_scalar ( ) ; 
731-     Ok ( match  float_ty { 
732-         FloatTy :: F32  => Scalar :: from_f32 ( left. to_f32 ( ) ?. max ( right. to_f32 ( ) ?) ) , 
733-         FloatTy :: F64  => Scalar :: from_f64 ( left. to_f64 ( ) ?. max ( right. to_f64 ( ) ?) ) , 
734-     } ) 
735- } 
736- 
737- fn  fmin_op < ' tcx > ( 
738-     left :  & ImmTy < ' tcx ,  Provenance > , 
739-     right :  & ImmTy < ' tcx ,  Provenance > , 
740- )  -> InterpResult < ' tcx ,  Scalar < Provenance > >  { 
741-     assert_eq ! ( left. layout. ty,  right. layout. ty) ; 
742-     let  ty:: Float ( float_ty)  = left. layout . ty . kind ( )  else  {  bug ! ( "fmin operand is not a float" )  } ; 
743-     let  left = left. to_scalar ( ) ; 
744-     let  right = right. to_scalar ( ) ; 
745-     Ok ( match  float_ty { 
746-         FloatTy :: F32  => Scalar :: from_f32 ( left. to_f32 ( ) ?. min ( right. to_f32 ( ) ?) ) , 
747-         FloatTy :: F64  => Scalar :: from_f64 ( left. to_f64 ( ) ?. min ( right. to_f64 ( ) ?) ) , 
748-     } ) 
749- } 
0 commit comments