@@ -148,6 +148,14 @@ pub(super) trait EvalContextExt<'mir, 'tcx: 'mir>:
148148
149149 round_first :: < rustc_apfloat:: ieee:: Single > ( this, left, right, rounding, dest) ?;
150150 }
151+ // Used to implement the _mm_floor_ps, _mm_ceil_ps and _mm_round_ps
152+ // functions. Rounds the elements of `op` according to `rounding`.
153+ "round.ps" => {
154+ let [ op, rounding] =
155+ this. check_shim ( abi, Abi :: C { unwind : false } , link_name, args) ?;
156+
157+ round_all :: < rustc_apfloat:: ieee:: Single > ( this, op, rounding, dest) ?;
158+ }
151159 // Used to implement the _mm_floor_sd, _mm_ceil_sd and _mm_round_sd
152160 // functions. Rounds the first element of `right` according to `rounding`
153161 // and copies the remaining elements from `left`.
@@ -157,6 +165,14 @@ pub(super) trait EvalContextExt<'mir, 'tcx: 'mir>:
157165
158166 round_first :: < rustc_apfloat:: ieee:: Double > ( this, left, right, rounding, dest) ?;
159167 }
168+ // Used to implement the _mm_floor_pd, _mm_ceil_pd and _mm_round_pd
169+ // functions. Rounds the elements of `op` according to `rounding`.
170+ "round.pd" => {
171+ let [ op, rounding] =
172+ this. check_shim ( abi, Abi :: C { unwind : false } , link_name, args) ?;
173+
174+ round_all :: < rustc_apfloat:: ieee:: Double > ( this, op, rounding, dest) ?;
175+ }
160176 // Used to implement the _mm_minpos_epu16 function.
161177 // Find the minimum unsinged 16-bit integer in `op` and
162178 // returns its value and position.
@@ -283,22 +299,7 @@ fn round_first<'tcx, F: rustc_apfloat::Float>(
283299 assert_eq ! ( dest_len, left_len) ;
284300 assert_eq ! ( dest_len, right_len) ;
285301
286- // The fourth bit of `rounding` only affects the SSE status
287- // register, which cannot be accessed from Miri (or from Rust,
288- // for that matter), so we can ignore it.
289- let rounding = match this. read_scalar ( rounding) ?. to_i32 ( ) ? & !0b1000 {
290- // When the third bit is 0, the rounding mode is determined by the
291- // first two bits.
292- 0b000 => rustc_apfloat:: Round :: NearestTiesToEven ,
293- 0b001 => rustc_apfloat:: Round :: TowardNegative ,
294- 0b010 => rustc_apfloat:: Round :: TowardPositive ,
295- 0b011 => rustc_apfloat:: Round :: TowardZero ,
296- // When the third bit is 1, the rounding mode is determined by the
297- // SSE status register. Since we do not support modifying it from
298- // Miri (or Rust), we assume it to be at its default mode (round-to-nearest).
299- 0b100 ..=0b111 => rustc_apfloat:: Round :: NearestTiesToEven ,
300- rounding => throw_unsup_format ! ( "unsupported rounding mode 0x{rounding:02x}" ) ,
301- } ;
302+ let rounding = rounding_from_imm ( this. read_scalar ( rounding) ?. to_i32 ( ) ?) ?;
302303
303304 let op0: F = this. read_scalar ( & this. project_index ( & right, 0 ) ?) ?. to_float ( ) ?;
304305 let res = op0. round_to_integral ( rounding) . value ;
@@ -317,3 +318,50 @@ fn round_first<'tcx, F: rustc_apfloat::Float>(
317318
318319 Ok ( ( ) )
319320}
321+
322+ // Rounds all elements of `op` according to `rounding`.
323+ fn round_all < ' tcx , F : rustc_apfloat:: Float > (
324+ this : & mut crate :: MiriInterpCx < ' _ , ' tcx > ,
325+ op : & OpTy < ' tcx , Provenance > ,
326+ rounding : & OpTy < ' tcx , Provenance > ,
327+ dest : & PlaceTy < ' tcx , Provenance > ,
328+ ) -> InterpResult < ' tcx , ( ) > {
329+ let ( op, op_len) = this. operand_to_simd ( op) ?;
330+ let ( dest, dest_len) = this. place_to_simd ( dest) ?;
331+
332+ assert_eq ! ( dest_len, op_len) ;
333+
334+ let rounding = rounding_from_imm ( this. read_scalar ( rounding) ?. to_i32 ( ) ?) ?;
335+
336+ for i in 0 ..dest_len {
337+ let op: F = this. read_scalar ( & this. project_index ( & op, i) ?) ?. to_float ( ) ?;
338+ let res = op. round_to_integral ( rounding) . value ;
339+ this. write_scalar (
340+ Scalar :: from_uint ( res. to_bits ( ) , Size :: from_bits ( F :: BITS ) ) ,
341+ & this. project_index ( & dest, i) ?,
342+ ) ?;
343+ }
344+
345+ Ok ( ( ) )
346+ }
347+
348+ /// Gets equivalent `rustc_apfloat::Round` from rounding mode immediate of
349+ /// `round.{ss,sd,ps,pd}` intrinsics.
350+ fn rounding_from_imm < ' tcx > ( rounding : i32 ) -> InterpResult < ' tcx , rustc_apfloat:: Round > {
351+ // The fourth bit of `rounding` only affects the SSE status
352+ // register, which cannot be accessed from Miri (or from Rust,
353+ // for that matter), so we can ignore it.
354+ match rounding & !0b1000 {
355+ // When the third bit is 0, the rounding mode is determined by the
356+ // first two bits.
357+ 0b000 => Ok ( rustc_apfloat:: Round :: NearestTiesToEven ) ,
358+ 0b001 => Ok ( rustc_apfloat:: Round :: TowardNegative ) ,
359+ 0b010 => Ok ( rustc_apfloat:: Round :: TowardPositive ) ,
360+ 0b011 => Ok ( rustc_apfloat:: Round :: TowardZero ) ,
361+ // When the third bit is 1, the rounding mode is determined by the
362+ // SSE status register. Since we do not support modifying it from
363+ // Miri (or Rust), we assume it to be at its default mode (round-to-nearest).
364+ 0b100 ..=0b111 => Ok ( rustc_apfloat:: Round :: NearestTiesToEven ) ,
365+ rounding => throw_unsup_format ! ( "unsupported rounding mode 0x{rounding:02x}" ) ,
366+ }
367+ }
0 commit comments