@@ -148,6 +148,14 @@ pub(super) trait EvalContextExt<'mir, 'tcx: 'mir>:
148
148
149
149
round_first :: < rustc_apfloat:: ieee:: Single > ( this, left, right, rounding, dest) ?;
150
150
}
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
+ }
151
159
// Used to implement the _mm_floor_sd, _mm_ceil_sd and _mm_round_sd
152
160
// functions. Rounds the first element of `right` according to `rounding`
153
161
// and copies the remaining elements from `left`.
@@ -157,6 +165,14 @@ pub(super) trait EvalContextExt<'mir, 'tcx: 'mir>:
157
165
158
166
round_first :: < rustc_apfloat:: ieee:: Double > ( this, left, right, rounding, dest) ?;
159
167
}
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
+ }
160
176
// Used to implement the _mm_minpos_epu16 function.
161
177
// Find the minimum unsinged 16-bit integer in `op` and
162
178
// returns its value and position.
@@ -283,22 +299,7 @@ fn round_first<'tcx, F: rustc_apfloat::Float>(
283
299
assert_eq ! ( dest_len, left_len) ;
284
300
assert_eq ! ( dest_len, right_len) ;
285
301
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 ( ) ?) ?;
302
303
303
304
let op0: F = this. read_scalar ( & this. project_index ( & right, 0 ) ?) ?. to_float ( ) ?;
304
305
let res = op0. round_to_integral ( rounding) . value ;
@@ -317,3 +318,50 @@ fn round_first<'tcx, F: rustc_apfloat::Float>(
317
318
318
319
Ok ( ( ) )
319
320
}
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