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

View File

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