Rollup merge of #129751 - RalfJung:interpret-visit-field-order, r=compiler-errors

interpret/visitor: make memory order iteration slightly more efficient

Finally I know enough about RPIT to write this iterator signature correctly. :D

This means memory-order iteration now needs an allocation, but it avoids quadratic complexity (where it has to do a linear scan n times to find the n-th field in memory order), so that seems like a win overall. The changed code only affects Miri; the rustc changes are NOPs.
This commit is contained in:
Matthias Krüger 2024-08-31 10:08:58 +02:00 committed by GitHub
commit a59c1a4291
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 15 additions and 17 deletions

View File

@ -25,14 +25,15 @@ fn read_discriminant(&mut self, v: &Self::V) -> InterpResult<'tcx, VariantIdx> {
} }
/// This function provides the chance to reorder the order in which fields are visited for /// This function provides the chance to reorder the order in which fields are visited for
/// `FieldsShape::Aggregate`: The order of fields will be /// `FieldsShape::Aggregate`.
/// `(0..num_fields).map(aggregate_field_order)`.
/// ///
/// The default means we iterate in source declaration order; alternative this can do an inverse /// The default means we iterate in source declaration order; alternatively this can do some
/// lookup in `memory_index` to use memory field order instead. /// work with `memory_index` to iterate in memory order.
#[inline(always)] #[inline(always)]
fn aggregate_field_order(_memory_index: &IndexVec<FieldIdx, u32>, idx: usize) -> usize { fn aggregate_field_iter(
idx memory_index: &IndexVec<FieldIdx, u32>,
) -> impl Iterator<Item = FieldIdx> + 'static {
memory_index.indices()
} }
// Recursive actions, ready to be overloaded. // Recursive actions, ready to be overloaded.
@ -172,9 +173,9 @@ fn walk_value(&mut self, v: &Self::V) -> InterpResult<'tcx> {
&FieldsShape::Union(fields) => { &FieldsShape::Union(fields) => {
self.visit_union(v, fields)?; self.visit_union(v, fields)?;
} }
FieldsShape::Arbitrary { offsets, memory_index } => { FieldsShape::Arbitrary { memory_index, .. } => {
for idx in 0..offsets.len() { for idx in Self::aggregate_field_iter(memory_index) {
let idx = Self::aggregate_field_order(memory_index, idx); let idx = idx.as_usize();
let field = self.ecx().project_field(v, idx)?; let field = self.ecx().project_field(v, idx)?;
self.visit_field(v, idx, &field)?; self.visit_field(v, idx, &field)?;
} }

View File

@ -630,14 +630,11 @@ fn ecx(&self) -> &MiriInterpCx<'tcx> {
self.ecx self.ecx
} }
fn aggregate_field_order(memory_index: &IndexVec<FieldIdx, u32>, idx: usize) -> usize { fn aggregate_field_iter(
// We need to do an *inverse* lookup: find the field that has position `idx` in memory order. memory_index: &IndexVec<FieldIdx, u32>,
for (src_field, &mem_pos) in memory_index.iter_enumerated() { ) -> impl Iterator<Item = FieldIdx> + 'static {
if mem_pos as usize == idx { let inverse_memory_index = memory_index.invert_bijective_mapping();
return src_field.as_usize(); inverse_memory_index.into_iter()
}
}
panic!("invalid `memory_index`, could not find {}-th field in memory order", idx);
} }
// Hook to detect `UnsafeCell`. // Hook to detect `UnsafeCell`.