@@ -48,111 +48,100 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
4848}
4949
5050impl < ' 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 (
5352 & self ,
5453 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 ,
5756 ) -> EvalResult < ' tcx , ( Scalar , bool ) > {
5857 use rustc:: mir:: BinOp :: * ;
5958
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+ }
6270
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 :: * ;
6578
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+ } } ;
141128 }
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 ) ,
150132 }
133+ }
151134
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 :: * ;
156145
157146 // Shift ops can have an RHS with a different numeric type.
158147 if bin_op == Shl || bin_op == Shr {
@@ -189,11 +178,11 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
189178 // For the remaining ops, the types must be the same on both sides
190179 if left_layout. ty != right_layout. ty {
191180 let msg = format ! (
192- "unimplemented binary op {:?}: {:?} ({:?}), {:?} ({:?})" ,
181+ "unimplemented asymmetric binary op {:?}: {:?} ({:?}), {:?} ({:?})" ,
193182 bin_op,
194- left ,
183+ l ,
195184 left_layout. ty,
196- right ,
185+ r ,
197186 right_layout. ty
198187 ) ;
199188 return err ! ( Unimplemented ( msg) ) ;
@@ -289,11 +278,10 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
289278
290279 _ => {
291280 let msg = format ! (
292- "unimplemented binary op {:?}: {:?} ({:?}) , {:?} ({:?})" ,
281+ "unimplemented binary op {:?}: {:?}, {:?} (both {:?})" ,
293282 bin_op,
294- left,
295- left_layout. ty,
296- right,
283+ l,
284+ r,
297285 right_layout. ty,
298286 ) ;
299287 return err ! ( Unimplemented ( msg) ) ;
@@ -303,6 +291,65 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
303291 Ok ( ( val, false ) )
304292 }
305293
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+
306353 pub fn unary_op (
307354 & self ,
308355 un_op : mir:: UnOp ,
0 commit comments