|
4 | 4 |
|
5 | 5 | use either::Either;
|
6 | 6 |
|
| 7 | +use rustc_index::IndexSlice; |
7 | 8 | use rustc_middle::mir;
|
8 |
| -use rustc_middle::mir::interpret::{InterpResult, Scalar}; |
9 | 9 | use rustc_middle::ty::layout::LayoutOf;
|
| 10 | +use rustc_target::abi::{FieldIdx, FIRST_VARIANT}; |
10 | 11 |
|
11 |
| -use super::{ImmTy, InterpCx, Machine, Projectable}; |
| 12 | +use super::{ImmTy, InterpCx, InterpResult, Machine, PlaceTy, Projectable, Scalar}; |
12 | 13 | use crate::util;
|
13 | 14 |
|
14 | 15 | impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
@@ -187,34 +188,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
187 | 188 | }
|
188 | 189 |
|
189 | 190 | Repeat(ref operand, _) => {
|
190 |
| - let src = self.eval_operand(operand, None)?; |
191 |
| - assert!(src.layout.is_sized()); |
192 |
| - let dest = self.force_allocation(&dest)?; |
193 |
| - let length = dest.len(self)?; |
194 |
| - |
195 |
| - if length == 0 { |
196 |
| - // Nothing to copy... but let's still make sure that `dest` as a place is valid. |
197 |
| - self.get_place_alloc_mut(&dest)?; |
198 |
| - } else { |
199 |
| - // Write the src to the first element. |
200 |
| - let first = self.project_index(&dest, 0)?; |
201 |
| - self.copy_op(&src, &first, /*allow_transmute*/ false)?; |
202 |
| - |
203 |
| - // This is performance-sensitive code for big static/const arrays! So we |
204 |
| - // avoid writing each operand individually and instead just make many copies |
205 |
| - // of the first element. |
206 |
| - let elem_size = first.layout.size; |
207 |
| - let first_ptr = first.ptr(); |
208 |
| - let rest_ptr = first_ptr.offset(elem_size, self)?; |
209 |
| - // No alignment requirement since `copy_op` above already checked it. |
210 |
| - self.mem_copy_repeatedly( |
211 |
| - first_ptr, |
212 |
| - rest_ptr, |
213 |
| - elem_size, |
214 |
| - length - 1, |
215 |
| - /*nonoverlapping:*/ true, |
216 |
| - )?; |
217 |
| - } |
| 191 | + self.write_repeat(operand, &dest)?; |
218 | 192 | }
|
219 | 193 |
|
220 | 194 | Len(place) => {
|
@@ -307,6 +281,73 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
307 | 281 | Ok(())
|
308 | 282 | }
|
309 | 283 |
|
| 284 | + /// Writes the aggregate to the destination. |
| 285 | + #[instrument(skip(self), level = "trace")] |
| 286 | + fn write_aggregate( |
| 287 | + &mut self, |
| 288 | + kind: &mir::AggregateKind<'tcx>, |
| 289 | + operands: &IndexSlice<FieldIdx, mir::Operand<'tcx>>, |
| 290 | + dest: &PlaceTy<'tcx, M::Provenance>, |
| 291 | + ) -> InterpResult<'tcx> { |
| 292 | + self.write_uninit(dest)?; // make sure all the padding ends up as uninit |
| 293 | + let (variant_index, variant_dest, active_field_index) = match *kind { |
| 294 | + mir::AggregateKind::Adt(_, variant_index, _, _, active_field_index) => { |
| 295 | + let variant_dest = self.project_downcast(dest, variant_index)?; |
| 296 | + (variant_index, variant_dest, active_field_index) |
| 297 | + } |
| 298 | + _ => (FIRST_VARIANT, dest.clone(), None), |
| 299 | + }; |
| 300 | + if active_field_index.is_some() { |
| 301 | + assert_eq!(operands.len(), 1); |
| 302 | + } |
| 303 | + for (field_index, operand) in operands.iter_enumerated() { |
| 304 | + let field_index = active_field_index.unwrap_or(field_index); |
| 305 | + let field_dest = self.project_field(&variant_dest, field_index.as_usize())?; |
| 306 | + let op = self.eval_operand(operand, Some(field_dest.layout))?; |
| 307 | + self.copy_op(&op, &field_dest, /*allow_transmute*/ false)?; |
| 308 | + } |
| 309 | + self.write_discriminant(variant_index, dest) |
| 310 | + } |
| 311 | + |
| 312 | + /// Repeats `operand` into the destination. `dest` must have array type, and that type |
| 313 | + /// determines how often `operand` is repeated. |
| 314 | + fn write_repeat( |
| 315 | + &mut self, |
| 316 | + operand: &mir::Operand<'tcx>, |
| 317 | + dest: &PlaceTy<'tcx, M::Provenance>, |
| 318 | + ) -> InterpResult<'tcx> { |
| 319 | + let src = self.eval_operand(operand, None)?; |
| 320 | + assert!(src.layout.is_sized()); |
| 321 | + let dest = self.force_allocation(&dest)?; |
| 322 | + let length = dest.len(self)?; |
| 323 | + |
| 324 | + if length == 0 { |
| 325 | + // Nothing to copy... but let's still make sure that `dest` as a place is valid. |
| 326 | + self.get_place_alloc_mut(&dest)?; |
| 327 | + } else { |
| 328 | + // Write the src to the first element. |
| 329 | + let first = self.project_index(&dest, 0)?; |
| 330 | + self.copy_op(&src, &first, /*allow_transmute*/ false)?; |
| 331 | + |
| 332 | + // This is performance-sensitive code for big static/const arrays! So we |
| 333 | + // avoid writing each operand individually and instead just make many copies |
| 334 | + // of the first element. |
| 335 | + let elem_size = first.layout.size; |
| 336 | + let first_ptr = first.ptr(); |
| 337 | + let rest_ptr = first_ptr.offset(elem_size, self)?; |
| 338 | + // No alignment requirement since `copy_op` above already checked it. |
| 339 | + self.mem_copy_repeatedly( |
| 340 | + first_ptr, |
| 341 | + rest_ptr, |
| 342 | + elem_size, |
| 343 | + length - 1, |
| 344 | + /*nonoverlapping:*/ true, |
| 345 | + )?; |
| 346 | + } |
| 347 | + |
| 348 | + Ok(()) |
| 349 | + } |
| 350 | + |
310 | 351 | /// Evaluate the given terminator. Will also adjust the stack frame and statement position accordingly.
|
311 | 352 | fn terminator(&mut self, terminator: &mir::Terminator<'tcx>) -> InterpResult<'tcx> {
|
312 | 353 | info!("{:?}", terminator.kind);
|
|
0 commit comments