@@ -48,111 +48,100 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
48
48
}
49
49
50
50
impl < ' a , ' mir , ' tcx , M : Machine < ' mir , ' tcx > > EvalContext < ' a , ' mir , ' tcx , M > {
51
- /// Returns the result of the specified operation and whether it overflowed.
52
- pub fn binary_op (
51
+ fn binary_char_op (
53
52
& self ,
54
53
bin_op : mir:: BinOp ,
55
- ValTy { value : left , layout : left_layout } : ValTy < ' tcx > ,
56
- ValTy { value : right , layout : right_layout } : ValTy < ' tcx > ,
54
+ l : char ,
55
+ r : char ,
57
56
) -> EvalResult < ' tcx , ( Scalar , bool ) > {
58
57
use rustc:: mir:: BinOp :: * ;
59
58
60
- let left = left. to_scalar ( ) ?;
61
- let right = right. to_scalar ( ) ?;
59
+ let res = match bin_op {
60
+ Eq => l == r,
61
+ Ne => l != r,
62
+ Lt => l < r,
63
+ Le => l <= r,
64
+ Gt => l > r,
65
+ Ge => l >= r,
66
+ _ => bug ! ( "Invalid operation on char: {:?}" , bin_op) ,
67
+ } ;
68
+ return Ok ( ( Scalar :: from_bool ( res) , false ) ) ;
69
+ }
62
70
63
- trace ! ( "Running binary op {:?}: {:?} ({:?}), {:?} ({:?})" ,
64
- bin_op, left, left_layout. ty. sty, right, right_layout. ty. sty) ;
71
+ fn binary_bool_op (
72
+ & self ,
73
+ bin_op : mir:: BinOp ,
74
+ l : bool ,
75
+ r : bool ,
76
+ ) -> EvalResult < ' tcx , ( Scalar , bool ) > {
77
+ use rustc:: mir:: BinOp :: * ;
65
78
66
- // Handle non-integer operations
67
- if let ty:: Char = left_layout. ty . sty {
68
- assert_eq ! ( right_layout. ty. sty, ty:: Char ) ;
69
- let l = left. to_char ( ) ?;
70
- let r = right. to_char ( ) ?;
71
- let res = match bin_op {
72
- Eq => l == r,
73
- Ne => l != r,
74
- Lt => l < r,
75
- Le => l <= r,
76
- Gt => l > r,
77
- Ge => l >= r,
78
- _ => bug ! ( "Invalid operation on char: {:?}" , bin_op) ,
79
- } ;
80
- return Ok ( ( Scalar :: from_bool ( res) , false ) ) ;
81
- }
82
- if let ty:: Bool = left_layout. ty . sty {
83
- assert_eq ! ( right_layout. ty. sty, ty:: Bool ) ;
84
- let l = left. to_bool ( ) ?;
85
- let r = right. to_bool ( ) ?;
86
- let res = match bin_op {
87
- Eq => l == r,
88
- Ne => l != r,
89
- Lt => l < r,
90
- Le => l <= r,
91
- Gt => l > r,
92
- Ge => l >= r,
93
- BitAnd => l & r,
94
- BitOr => l | r,
95
- BitXor => l ^ r,
96
- _ => bug ! ( "Invalid operation on bool: {:?}" , bin_op) ,
97
- } ;
98
- return Ok ( ( Scalar :: from_bool ( res) , false ) ) ;
99
- }
100
- if let ty:: Float ( fty) = left_layout. ty . sty {
101
- let l = left. to_bits ( left_layout. size ) ?;
102
- let r = right. to_bits ( right_layout. size ) ?;
103
- assert_eq ! ( right_layout. ty. sty, ty:: Float ( fty) ) ;
104
- macro_rules! float_math {
105
- ( $ty: path, $size: expr) => { {
106
- let l = <$ty>:: from_bits( l) ;
107
- let r = <$ty>:: from_bits( r) ;
108
- let bitify = |res: :: rustc_apfloat:: StatusAnd <$ty>| Scalar :: Bits {
109
- bits: res. value. to_bits( ) ,
110
- size: $size,
111
- } ;
112
- let val = match bin_op {
113
- Eq => Scalar :: from_bool( l == r) ,
114
- Ne => Scalar :: from_bool( l != r) ,
115
- Lt => Scalar :: from_bool( l < r) ,
116
- Le => Scalar :: from_bool( l <= r) ,
117
- Gt => Scalar :: from_bool( l > r) ,
118
- Ge => Scalar :: from_bool( l >= r) ,
119
- Add => bitify( l + r) ,
120
- Sub => bitify( l - r) ,
121
- Mul => bitify( l * r) ,
122
- Div => bitify( l / r) ,
123
- Rem => bitify( l % r) ,
124
- _ => bug!( "invalid float op: `{:?}`" , bin_op) ,
125
- } ;
126
- return Ok ( ( val, false ) ) ;
127
- } } ;
128
- }
129
- match fty {
130
- FloatTy :: F32 => float_math ! ( Single , 4 ) ,
131
- FloatTy :: F64 => float_math ! ( Double , 8 ) ,
132
- }
133
- }
134
- // Only integers left
135
- #[ inline]
136
- fn is_ptr < ' tcx > ( ty : ty:: Ty < ' tcx > ) -> bool {
137
- match ty. sty {
138
- ty:: RawPtr ( ..) | ty:: Ref ( ..) | ty:: FnPtr ( ..) => true ,
139
- _ => false ,
140
- }
79
+ let res = match bin_op {
80
+ Eq => l == r,
81
+ Ne => l != r,
82
+ Lt => l < r,
83
+ Le => l <= r,
84
+ Gt => l > r,
85
+ Ge => l >= r,
86
+ BitAnd => l & r,
87
+ BitOr => l | r,
88
+ BitXor => l ^ r,
89
+ _ => bug ! ( "Invalid operation on bool: {:?}" , bin_op) ,
90
+ } ;
91
+ return Ok ( ( Scalar :: from_bool ( res) , false ) ) ;
92
+ }
93
+
94
+ fn binary_float_op (
95
+ & self ,
96
+ bin_op : mir:: BinOp ,
97
+ fty : FloatTy ,
98
+ // passing in raw bits
99
+ l : u128 ,
100
+ r : u128 ,
101
+ ) -> EvalResult < ' tcx , ( Scalar , bool ) > {
102
+ use rustc:: mir:: BinOp :: * ;
103
+
104
+ macro_rules! float_math {
105
+ ( $ty: path, $size: expr) => { {
106
+ let l = <$ty>:: from_bits( l) ;
107
+ let r = <$ty>:: from_bits( r) ;
108
+ let bitify = |res: :: rustc_apfloat:: StatusAnd <$ty>| Scalar :: Bits {
109
+ bits: res. value. to_bits( ) ,
110
+ size: $size,
111
+ } ;
112
+ let val = match bin_op {
113
+ Eq => Scalar :: from_bool( l == r) ,
114
+ Ne => Scalar :: from_bool( l != r) ,
115
+ Lt => Scalar :: from_bool( l < r) ,
116
+ Le => Scalar :: from_bool( l <= r) ,
117
+ Gt => Scalar :: from_bool( l > r) ,
118
+ Ge => Scalar :: from_bool( l >= r) ,
119
+ Add => bitify( l + r) ,
120
+ Sub => bitify( l - r) ,
121
+ Mul => bitify( l * r) ,
122
+ Div => bitify( l / r) ,
123
+ Rem => bitify( l % r) ,
124
+ _ => bug!( "invalid float op: `{:?}`" , bin_op) ,
125
+ } ;
126
+ return Ok ( ( val, false ) ) ;
127
+ } } ;
141
128
}
142
- assert ! ( left_layout. ty. is_integral( ) || is_ptr( left_layout. ty) ) ;
143
- assert ! ( right_layout. ty. is_integral( ) || is_ptr( right_layout. ty) ) ;
144
-
145
- // Handle operations that support pointers
146
- if let Some ( handled) =
147
- M :: try_ptr_op ( self , bin_op, left, left_layout, right, right_layout) ?
148
- {
149
- return Ok ( handled) ;
129
+ match fty {
130
+ FloatTy :: F32 => float_math ! ( Single , 4 ) ,
131
+ FloatTy :: F64 => float_math ! ( Double , 8 ) ,
150
132
}
133
+ }
151
134
152
- // From now on, everything must be bytes, no pointer values
153
- // (this is independent of the type)
154
- let l = left. to_bits ( left_layout. size ) ?;
155
- let r = right. to_bits ( right_layout. size ) ?;
135
+ fn binary_int_op (
136
+ & self ,
137
+ bin_op : mir:: BinOp ,
138
+ // passing in raw bits
139
+ l : u128 ,
140
+ left_layout : TyLayout < ' tcx > ,
141
+ r : u128 ,
142
+ right_layout : TyLayout < ' tcx > ,
143
+ ) -> EvalResult < ' tcx , ( Scalar , bool ) > {
144
+ use rustc:: mir:: BinOp :: * ;
156
145
157
146
// Shift ops can have an RHS with a different numeric type.
158
147
if bin_op == Shl || bin_op == Shr {
@@ -189,11 +178,11 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
189
178
// For the remaining ops, the types must be the same on both sides
190
179
if left_layout. ty != right_layout. ty {
191
180
let msg = format ! (
192
- "unimplemented binary op {:?}: {:?} ({:?}), {:?} ({:?})" ,
181
+ "unimplemented asymmetric binary op {:?}: {:?} ({:?}), {:?} ({:?})" ,
193
182
bin_op,
194
- left ,
183
+ l ,
195
184
left_layout. ty,
196
- right ,
185
+ r ,
197
186
right_layout. ty
198
187
) ;
199
188
return err ! ( Unimplemented ( msg) ) ;
@@ -289,11 +278,10 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
289
278
290
279
_ => {
291
280
let msg = format ! (
292
- "unimplemented binary op {:?}: {:?} ({:?}) , {:?} ({:?})" ,
281
+ "unimplemented binary op {:?}: {:?}, {:?} (both {:?})" ,
293
282
bin_op,
294
- left,
295
- left_layout. ty,
296
- right,
283
+ l,
284
+ r,
297
285
right_layout. ty,
298
286
) ;
299
287
return err ! ( Unimplemented ( msg) ) ;
@@ -303,6 +291,65 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
303
291
Ok ( ( val, false ) )
304
292
}
305
293
294
+ /// Returns the result of the specified operation and whether it overflowed.
295
+ pub fn binary_op (
296
+ & self ,
297
+ bin_op : mir:: BinOp ,
298
+ ValTy { value : left, layout : left_layout } : ValTy < ' tcx > ,
299
+ ValTy { value : right, layout : right_layout } : ValTy < ' tcx > ,
300
+ ) -> EvalResult < ' tcx , ( Scalar , bool ) > {
301
+ let left = left. to_scalar ( ) ?;
302
+ let right = right. to_scalar ( ) ?;
303
+
304
+ trace ! ( "Running binary op {:?}: {:?} ({:?}), {:?} ({:?})" ,
305
+ bin_op, left, left_layout. ty. sty, right, right_layout. ty. sty) ;
306
+
307
+ match left_layout. ty . sty {
308
+ ty:: Char => {
309
+ assert_eq ! ( left_layout. ty, right_layout. ty) ;
310
+ let l = left. to_char ( ) ?;
311
+ let r = right. to_char ( ) ?;
312
+ self . binary_char_op ( bin_op, l, r)
313
+ }
314
+ ty:: Bool => {
315
+ assert_eq ! ( left_layout. ty, right_layout. ty) ;
316
+ let l = left. to_bool ( ) ?;
317
+ let r = right. to_bool ( ) ?;
318
+ self . binary_bool_op ( bin_op, l, r)
319
+ }
320
+ ty:: Float ( fty) => {
321
+ assert_eq ! ( left_layout. ty, right_layout. ty) ;
322
+ let l = left. to_bits ( left_layout. size ) ?;
323
+ let r = right. to_bits ( right_layout. size ) ?;
324
+ self . binary_float_op ( bin_op, fty, l, r)
325
+ }
326
+ _ => {
327
+ // Must be integer(-like) types
328
+ #[ inline]
329
+ fn is_ptr < ' tcx > ( ty : ty:: Ty < ' tcx > ) -> bool {
330
+ match ty. sty {
331
+ ty:: RawPtr ( ..) | ty:: Ref ( ..) | ty:: FnPtr ( ..) => true ,
332
+ _ => false ,
333
+ }
334
+ }
335
+ assert ! ( left_layout. ty. is_integral( ) || is_ptr( left_layout. ty) ) ;
336
+ assert ! ( right_layout. ty. is_integral( ) || is_ptr( right_layout. ty) ) ;
337
+
338
+ // Handle operations that support pointer values
339
+ if let Some ( handled) =
340
+ M :: try_ptr_op ( self , bin_op, left, left_layout, right, right_layout) ?
341
+ {
342
+ return Ok ( handled) ;
343
+ }
344
+
345
+ // Everything else only works with "proper" bits
346
+ let l = left. to_bits ( left_layout. size ) ?;
347
+ let r = right. to_bits ( right_layout. size ) ?;
348
+ self . binary_int_op ( bin_op, l, left_layout, r, right_layout)
349
+ }
350
+ }
351
+ }
352
+
306
353
pub fn unary_op (
307
354
& self ,
308
355
un_op : mir:: UnOp ,
0 commit comments