1
1
use rustc_apfloat:: { Float , Round } ;
2
2
use rustc_middle:: ty:: layout:: { HasParamEnv , LayoutOf } ;
3
3
use rustc_middle:: { mir, ty, ty:: FloatTy } ;
4
+ use rustc_span:: { sym, Symbol } ;
4
5
use rustc_target:: abi:: { Endian , HasDataLayout } ;
5
6
6
7
use crate :: * ;
@@ -25,7 +26,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
25
26
| "floor"
26
27
| "round"
27
28
| "trunc"
28
- | "fsqrt" => {
29
+ | "fsqrt"
30
+ | "ctlz"
31
+ | "cttz"
32
+ | "bswap"
33
+ | "bitreverse"
34
+ => {
29
35
let [ op] = check_arg_count ( args) ?;
30
36
let ( op, op_len) = this. operand_to_simd ( op) ?;
31
37
let ( dest, dest_len) = this. place_to_simd ( dest) ?;
@@ -38,6 +44,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
38
44
Abs ,
39
45
Sqrt ,
40
46
Round ( rustc_apfloat:: Round ) ,
47
+ Numeric ( Symbol ) ,
41
48
}
42
49
let which = match intrinsic_name {
43
50
"neg" => Op :: MirOp ( mir:: UnOp :: Neg ) ,
@@ -47,6 +54,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
47
54
"floor" => Op :: Round ( rustc_apfloat:: Round :: TowardNegative ) ,
48
55
"round" => Op :: Round ( rustc_apfloat:: Round :: NearestTiesToAway ) ,
49
56
"trunc" => Op :: Round ( rustc_apfloat:: Round :: TowardZero ) ,
57
+ "ctlz" => Op :: Numeric ( sym:: ctlz) ,
58
+ "cttz" => Op :: Numeric ( sym:: cttz) ,
59
+ "bswap" => Op :: Numeric ( sym:: bswap) ,
60
+ "bitreverse" => Op :: Numeric ( sym:: bitreverse) ,
50
61
_ => unreachable ! ( ) ,
51
62
} ;
52
63
@@ -101,6 +112,20 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
101
112
}
102
113
}
103
114
}
115
+ Op :: Numeric ( name) => {
116
+ assert ! ( op. layout. ty. is_integral( ) ) ;
117
+ let size = op. layout . size ;
118
+ let bits = op. to_scalar ( ) . to_bits ( size) . unwrap ( ) ;
119
+ let extra = 128u128 . checked_sub ( u128:: from ( size. bits ( ) ) ) . unwrap ( ) ;
120
+ let bits_out = match name {
121
+ sym:: ctlz => u128:: from ( bits. leading_zeros ( ) ) . checked_sub ( extra) . unwrap ( ) ,
122
+ sym:: cttz => u128:: from ( ( bits << extra) . trailing_zeros ( ) ) . checked_sub ( extra) . unwrap ( ) ,
123
+ sym:: bswap => ( bits << extra) . swap_bytes ( ) ,
124
+ sym:: bitreverse => ( bits << extra) . reverse_bits ( ) ,
125
+ _ => unreachable ! ( ) ,
126
+ } ;
127
+ Scalar :: from_uint ( bits_out, size)
128
+ }
104
129
} ;
105
130
this. write_scalar ( val, & dest) ?;
106
131
}
@@ -126,7 +151,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
126
151
| "fmin"
127
152
| "saturating_add"
128
153
| "saturating_sub"
129
- | "arith_offset" => {
154
+ | "arith_offset"
155
+ => {
130
156
use mir:: BinOp ;
131
157
132
158
let [ left, right] = check_arg_count ( args) ?;
@@ -386,16 +412,25 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
386
412
let ( dest, dest_len) = this. place_to_simd ( dest) ?;
387
413
let bitmask_len = dest_len. max ( 8 ) ;
388
414
389
- assert ! ( mask. layout. ty. is_integral( ) ) ;
390
415
assert ! ( bitmask_len <= 64 ) ;
391
416
assert_eq ! ( bitmask_len, mask. layout. size. bits( ) ) ;
392
417
assert_eq ! ( dest_len, yes_len) ;
393
418
assert_eq ! ( dest_len, no_len) ;
394
419
let dest_len = u32:: try_from ( dest_len) . unwrap ( ) ;
395
420
let bitmask_len = u32:: try_from ( bitmask_len) . unwrap ( ) ;
396
421
397
- let mask: u64 =
398
- this. read_scalar ( mask) ?. to_bits ( mask. layout . size ) ?. try_into ( ) . unwrap ( ) ;
422
+ // The mask can be a single integer or an array.
423
+ let mask: u64 = match mask. layout . ty . kind ( ) {
424
+ ty:: Int ( ..) | ty:: Uint ( ..) =>
425
+ this. read_scalar ( mask) ?. to_bits ( mask. layout . size ) ?. try_into ( ) . unwrap ( ) ,
426
+ ty:: Array ( elem, _) if matches ! ( elem. kind( ) , ty:: Uint ( ty:: UintTy :: U8 ) ) => {
427
+ let mask_ty = this. machine . layouts . uint ( mask. layout . size ) . unwrap ( ) ;
428
+ let mask = mask. transmute ( mask_ty, this) ?;
429
+ this. read_scalar ( & mask) ?. to_bits ( mask_ty. size ) ?. try_into ( ) . unwrap ( )
430
+ }
431
+ _ => bug ! ( "simd_select_bitmask: invalid mask type {}" , mask. layout. ty) ,
432
+ } ;
433
+
399
434
for i in 0 ..dest_len {
400
435
let mask = mask
401
436
& 1u64
0 commit comments