|
9 | 9 | // except according to those terms. |
10 | 10 |
|
11 | 11 | use rustc::mir; |
12 | | -use rustc::ty::{self, layout::{self, TyLayout}}; |
| 12 | +use rustc::ty::{self, layout::TyLayout}; |
13 | 13 | use syntax::ast::FloatTy; |
14 | 14 | use rustc_apfloat::ieee::{Double, Single}; |
15 | 15 | use rustc_apfloat::Float; |
@@ -60,32 +60,102 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> { |
60 | 60 | let left = left.to_scalar()?; |
61 | 61 | let right = right.to_scalar()?; |
62 | 62 |
|
63 | | - let left_kind = match left_layout.abi { |
64 | | - layout::Abi::Scalar(ref scalar) => scalar.value, |
65 | | - _ => return err!(TypeNotPrimitive(left_layout.ty)), |
66 | | - }; |
67 | | - let right_kind = match right_layout.abi { |
68 | | - layout::Abi::Scalar(ref scalar) => scalar.value, |
69 | | - _ => return err!(TypeNotPrimitive(right_layout.ty)), |
70 | | - }; |
71 | 63 | trace!("Running binary op {:?}: {:?} ({:?}), {:?} ({:?})", |
72 | | - bin_op, left, left_kind, right, right_kind); |
| 64 | + bin_op, left, left_layout.ty.sty, right, right_layout.ty.sty); |
73 | 65 |
|
74 | | - // I: Handle operations that support pointers |
75 | | - if !left_kind.is_float() && !right_kind.is_float() { |
76 | | - if let Some(handled) = |
77 | | - M::try_ptr_op(self, bin_op, left, left_layout, right, right_layout)? |
78 | | - { |
79 | | - return Ok(handled); |
| 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), |
80 | 132 | } |
81 | 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 | + } |
| 141 | + } |
| 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); |
| 150 | + } |
82 | 151 |
|
83 | | - // II: From now on, everything must be bytes, no pointers |
| 152 | + // From now on, everything must be bytes, no pointer values |
| 153 | + // (this is independent of the type) |
84 | 154 | let l = left.to_bits(left_layout.size)?; |
85 | 155 | let r = right.to_bits(right_layout.size)?; |
86 | 156 |
|
87 | | - // These ops can have an RHS with a different numeric type. |
88 | | - if right_kind.is_int() && (bin_op == Shl || bin_op == Shr) { |
| 157 | + // Shift ops can have an RHS with a different numeric type. |
| 158 | + if bin_op == Shl || bin_op == Shr { |
89 | 159 | let signed = left_layout.abi.is_signed(); |
90 | 160 | let mut oflo = (r as u32 as u128) != r; |
91 | 161 | let mut r = r as u32; |
@@ -116,18 +186,20 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> { |
116 | 186 | }, oflo)); |
117 | 187 | } |
118 | 188 |
|
119 | | - if left_kind != right_kind { |
| 189 | + // For the remaining ops, the types must be the same on both sides |
| 190 | + if left_layout.ty != right_layout.ty { |
120 | 191 | let msg = format!( |
121 | 192 | "unimplemented binary op {:?}: {:?} ({:?}), {:?} ({:?})", |
122 | 193 | bin_op, |
123 | 194 | left, |
124 | | - left_kind, |
| 195 | + left_layout.ty, |
125 | 196 | right, |
126 | | - right_kind |
| 197 | + right_layout.ty |
127 | 198 | ); |
128 | 199 | return err!(Unimplemented(msg)); |
129 | 200 | } |
130 | 201 |
|
| 202 | + // Operations that need special treatment for signed integers |
131 | 203 | if left_layout.abi.is_signed() { |
132 | 204 | let op: Option<fn(&i128, &i128) -> bool> = match bin_op { |
133 | 205 | Lt => Some(i128::lt), |
@@ -180,38 +252,6 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> { |
180 | 252 | } |
181 | 253 | } |
182 | 254 |
|
183 | | - if let ty::Float(fty) = left_layout.ty.sty { |
184 | | - macro_rules! float_math { |
185 | | - ($ty:path, $size:expr) => {{ |
186 | | - let l = <$ty>::from_bits(l); |
187 | | - let r = <$ty>::from_bits(r); |
188 | | - let bitify = |res: ::rustc_apfloat::StatusAnd<$ty>| Scalar::Bits { |
189 | | - bits: res.value.to_bits(), |
190 | | - size: $size, |
191 | | - }; |
192 | | - let val = match bin_op { |
193 | | - Eq => Scalar::from_bool(l == r), |
194 | | - Ne => Scalar::from_bool(l != r), |
195 | | - Lt => Scalar::from_bool(l < r), |
196 | | - Le => Scalar::from_bool(l <= r), |
197 | | - Gt => Scalar::from_bool(l > r), |
198 | | - Ge => Scalar::from_bool(l >= r), |
199 | | - Add => bitify(l + r), |
200 | | - Sub => bitify(l - r), |
201 | | - Mul => bitify(l * r), |
202 | | - Div => bitify(l / r), |
203 | | - Rem => bitify(l % r), |
204 | | - _ => bug!("invalid float op: `{:?}`", bin_op), |
205 | | - }; |
206 | | - return Ok((val, false)); |
207 | | - }}; |
208 | | - } |
209 | | - match fty { |
210 | | - FloatTy::F32 => float_math!(Single, 4), |
211 | | - FloatTy::F64 => float_math!(Double, 8), |
212 | | - } |
213 | | - } |
214 | | - |
215 | 255 | let size = left_layout.size.bytes() as u8; |
216 | 256 |
|
217 | 257 | // only ints left |
|
0 commit comments