1
1
use log:: trace;
2
2
3
3
use rustc_middle:: { mir, ty:: Ty } ;
4
+ use rustc_target:: abi:: Size ;
4
5
5
6
use crate :: * ;
6
7
@@ -11,8 +12,6 @@ pub trait EvalContextExt<'tcx> {
11
12
left : & ImmTy < ' tcx , Tag > ,
12
13
right : & ImmTy < ' tcx , Tag > ,
13
14
) -> InterpResult < ' tcx , ( Scalar < Tag > , bool , Ty < ' tcx > ) > ;
14
-
15
- fn ptr_eq ( & self , left : Scalar < Tag > , right : Scalar < Tag > ) -> InterpResult < ' tcx , bool > ;
16
15
}
17
16
18
17
impl < ' mir , ' tcx > EvalContextExt < ' tcx > for super :: MiriEvalContext < ' mir , ' tcx > {
@@ -27,23 +26,8 @@ impl<'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'mir, 'tcx> {
27
26
trace ! ( "ptr_op: {:?} {:?} {:?}" , * left, bin_op, * right) ;
28
27
29
28
Ok ( match bin_op {
30
- Eq | Ne => {
31
- // This supports fat pointers.
32
- #[ rustfmt:: skip]
33
- let eq = match ( * * left, * * right) {
34
- ( Immediate :: Scalar ( left) , Immediate :: Scalar ( right) ) => {
35
- self . ptr_eq ( left. check_init ( ) ?, right. check_init ( ) ?) ?
36
- }
37
- ( Immediate :: ScalarPair ( left1, left2) , Immediate :: ScalarPair ( right1, right2) ) => {
38
- self . ptr_eq ( left1. check_init ( ) ?, right1. check_init ( ) ?) ?
39
- && self . ptr_eq ( left2. check_init ( ) ?, right2. check_init ( ) ?) ?
40
- }
41
- _ => bug ! ( "Type system should not allow comparing Scalar with ScalarPair" ) ,
42
- } ;
43
- ( Scalar :: from_bool ( if bin_op == Eq { eq } else { !eq } ) , false , self . tcx . types . bool )
44
- }
45
-
46
- Lt | Le | Gt | Ge => {
29
+ Eq | Ne | Lt | Le | Gt | Ge => {
30
+ assert_eq ! ( left. layout. abi, right. layout. abi) ; // types an differ, e.g. fn ptrs with different `for`
47
31
let size = self . pointer_size ( ) ;
48
32
// Just compare the bits. ScalarPairs are compared lexicographically.
49
33
// We thus always compare pairs and simply fill scalars up with 0.
@@ -58,35 +42,49 @@ impl<'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'mir, 'tcx> {
58
42
( r1. check_init ( ) ?. to_bits ( size) ?, r2. check_init ( ) ?. to_bits ( size) ?) ,
59
43
} ;
60
44
let res = match bin_op {
45
+ Eq => left == right,
46
+ Ne => left != right,
61
47
Lt => left < right,
62
48
Le => left <= right,
63
49
Gt => left > right,
64
50
Ge => left >= right,
65
- _ => bug ! ( "We already established it has to be one of these operators." ) ,
51
+ _ => bug ! ( ) ,
66
52
} ;
67
53
( Scalar :: from_bool ( res) , false , self . tcx . types . bool )
68
54
}
69
55
70
56
Offset => {
57
+ assert ! ( left. layout. ty. is_unsafe_ptr( ) ) ;
58
+ let ptr = self . scalar_to_ptr ( left. to_scalar ( ) ?) ?;
59
+ let offset = right. to_scalar ( ) ?. to_machine_isize ( self ) ?;
60
+
71
61
let pointee_ty =
72
62
left. layout . ty . builtin_deref ( true ) . expect ( "Offset called on non-ptr type" ) . ty ;
73
- let ptr = self . ptr_offset_inbounds (
74
- self . scalar_to_ptr ( left. to_scalar ( ) ?) ?,
75
- pointee_ty,
76
- right. to_scalar ( ) ?. to_machine_isize ( self ) ?,
77
- ) ?;
63
+ let ptr = self . ptr_offset_inbounds ( ptr, pointee_ty, offset) ?;
78
64
( Scalar :: from_maybe_pointer ( ptr, self ) , false , left. layout . ty )
79
65
}
80
66
81
- _ => bug ! ( "Invalid operator on pointers: {:?}" , bin_op) ,
82
- } )
83
- }
67
+ // Some more operations are possible with atomics.
68
+ // The return value always has the provenance of the *left* operand.
69
+ Add | Sub | BitOr | BitAnd | BitXor => {
70
+ assert ! ( left. layout. ty. is_unsafe_ptr( ) ) ;
71
+ assert ! ( right. layout. ty. is_unsafe_ptr( ) ) ;
72
+ let ptr = self . scalar_to_ptr ( left. to_scalar ( ) ?) ?;
73
+ // We do the actual operation with usize-typed scalars.
74
+ let left = ImmTy :: from_uint ( ptr. addr ( ) . bytes ( ) , self . machine . layouts . usize ) ;
75
+ let right = ImmTy :: from_uint (
76
+ right. to_scalar ( ) ?. to_machine_usize ( self ) ?,
77
+ self . machine . layouts . usize ,
78
+ ) ;
79
+ let ( result, overflowing, _ty) =
80
+ self . overflowing_binary_op ( bin_op, & left, & right) ?;
81
+ // Construct a new pointer with the provenance of `ptr` (the LHS).
82
+ let result_ptr =
83
+ Pointer :: new ( ptr. provenance , Size :: from_bytes ( result. to_machine_usize ( self ) ?) ) ;
84
+ ( Scalar :: from_maybe_pointer ( result_ptr, self ) , overflowing, left. layout . ty )
85
+ }
84
86
85
- fn ptr_eq ( & self , left : Scalar < Tag > , right : Scalar < Tag > ) -> InterpResult < ' tcx , bool > {
86
- let size = self . pointer_size ( ) ;
87
- // Just compare the integers.
88
- let left = left. to_bits ( size) ?;
89
- let right = right. to_bits ( size) ?;
90
- Ok ( left == right)
87
+ _ => span_bug ! ( self . cur_span( ) , "Invalid operator on pointers: {:?}" , bin_op) ,
88
+ } )
91
89
}
92
90
}
0 commit comments