|
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