Skip to content

Commit 202aea5

Browse files
committed
Speed up compilation of large constant arrays
This is a different approach to rust-lang#51672 as suggested by @oli-obk. Rather than write each repeated value one-by-one, we write the first one and then copy its value directly into the remaining memory.
1 parent 0cf0691 commit 202aea5

File tree

2 files changed

+30
-8
lines changed

2 files changed

+30
-8
lines changed

src/librustc_mir/interpret/eval_context.rs

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -591,10 +591,14 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M
591591

592592
let (dest, dest_align) = self.force_allocation(dest)?.to_ptr_align();
593593

594-
// FIXME: speed up repeat filling
595-
for i in 0..length {
596-
let elem_dest = dest.ptr_offset(elem_size * i as u64, &self)?;
597-
self.write_value_to_ptr(value, elem_dest, dest_align, elem_ty)?;
594+
if length > 0 {
595+
//write the first value
596+
self.write_value_to_ptr(value, dest, dest_align, elem_ty)?;
597+
598+
if length > 1 {
599+
let rest = dest.ptr_offset(elem_size * 1 as u64, &self)?;
600+
self.memory.copy_repeatedly(dest, dest_align, rest, dest_align, elem_size, length - 1, false)?;
601+
}
598602
}
599603
}
600604

src/librustc_mir/interpret/memory.rs

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -594,6 +594,19 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> {
594594
dest_align: Align,
595595
size: Size,
596596
nonoverlapping: bool,
597+
) -> EvalResult<'tcx> {
598+
self.copy_repeatedly(src, src_align, dest, dest_align, size, 1, nonoverlapping)
599+
}
600+
601+
pub fn copy_repeatedly(
602+
&mut self,
603+
src: Scalar,
604+
src_align: Align,
605+
dest: Scalar,
606+
dest_align: Align,
607+
size: Size,
608+
length: u64,
609+
nonoverlapping: bool,
597610
) -> EvalResult<'tcx> {
598611
// Empty accesses don't need to be valid pointers, but they should still be aligned
599612
self.check_align(src, src_align)?;
@@ -617,7 +630,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> {
617630
.collect();
618631

619632
let src_bytes = self.get_bytes_unchecked(src, size, src_align)?.as_ptr();
620-
let dest_bytes = self.get_bytes_mut(dest, size, dest_align)?.as_mut_ptr();
633+
let dest_bytes = self.get_bytes_mut(dest, size * length, dest_align)?.as_mut_ptr();
621634

622635
// SAFE: The above indexing would have panicked if there weren't at least `size` bytes
623636
// behind `src` and `dest`. Also, we use the overlapping-safe `ptr::copy` if `src` and
@@ -634,13 +647,18 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> {
634647
));
635648
}
636649
}
637-
ptr::copy(src_bytes, dest_bytes, size.bytes() as usize);
650+
651+
for i in 0..length {
652+
ptr::copy(src_bytes, dest_bytes.offset((size.bytes() * i) as isize), size.bytes() as usize);
653+
}
638654
} else {
639-
ptr::copy_nonoverlapping(src_bytes, dest_bytes, size.bytes() as usize);
655+
for i in 0..length {
656+
ptr::copy_nonoverlapping(src_bytes, dest_bytes.offset((size.bytes() * i) as isize), size.bytes() as usize);
657+
}
640658
}
641659
}
642660

643-
self.copy_undef_mask(src, dest, size)?;
661+
self.copy_undef_mask(src, dest, size * length)?;
644662
// copy back the relocations
645663
self.get_mut(dest.alloc_id)?.relocations.insert_presorted(relocations);
646664

0 commit comments

Comments
 (0)