@@ -566,6 +566,91 @@ impl<'tcx, Tag, Extra> Allocation<Tag, Extra> {
566
566
}
567
567
}
568
568
569
+ /// Run-length encoding of the undef mask.
570
+ /// Used to copy parts of a mask multiple times to another allocation.
571
+ pub struct AllocationDefinedness {
572
+ ranges : smallvec:: SmallVec :: < [ u64 ; 1 ] > ,
573
+ first : bool ,
574
+ }
575
+
576
+ /// Transferring the definedness mask to other allocations.
577
+ impl < Tag , Extra > Allocation < Tag , Extra > {
578
+ /// Creates a run-length encoding of the undef_mask.
579
+ pub fn compress_defined_range (
580
+ & self ,
581
+ src : Pointer < Tag > ,
582
+ size : Size ,
583
+ ) -> AllocationDefinedness {
584
+ // Since we are copying `size` bytes from `src` to `dest + i * size` (`for i in 0..repeat`),
585
+ // a naive undef mask copying algorithm would repeatedly have to read the undef mask from
586
+ // the source and write it to the destination. Even if we optimized the memory accesses,
587
+ // we'd be doing all of this `repeat` times.
588
+ // Therefor we precompute a compressed version of the undef mask of the source value and
589
+ // then write it back `repeat` times without computing any more information from the source.
590
+
591
+ // a precomputed cache for ranges of defined/undefined bits
592
+ // 0000010010001110 will become
593
+ // [5, 1, 2, 1, 3, 3, 1]
594
+ // where each element toggles the state
595
+
596
+ let mut ranges = smallvec:: SmallVec :: < [ u64 ; 1 ] > :: new ( ) ;
597
+ let first = self . undef_mask . get ( src. offset ) ;
598
+ let mut cur_len = 1 ;
599
+ let mut cur = first;
600
+
601
+ for i in 1 ..size. bytes ( ) {
602
+ // FIXME: optimize to bitshift the current undef block's bits and read the top bit
603
+ if self . undef_mask . get ( src. offset + Size :: from_bytes ( i) ) == cur {
604
+ cur_len += 1 ;
605
+ } else {
606
+ ranges. push ( cur_len) ;
607
+ cur_len = 1 ;
608
+ cur = !cur;
609
+ }
610
+ }
611
+
612
+ ranges. push ( cur_len) ;
613
+
614
+ AllocationDefinedness { ranges, first, }
615
+ }
616
+
617
+ /// Apply multiple instances of the run-length encoding to the undef_mask.
618
+ pub fn mark_compressed_range (
619
+ & mut self ,
620
+ defined : & AllocationDefinedness ,
621
+ dest : Pointer < Tag > ,
622
+ size : Size ,
623
+ repeat : u64 ,
624
+ ) {
625
+ // an optimization where we can just overwrite an entire range of definedness bits if
626
+ // they are going to be uniformly `1` or `0`.
627
+ if defined. ranges . len ( ) <= 1 {
628
+ self . undef_mask . set_range_inbounds (
629
+ dest. offset ,
630
+ dest. offset + size * repeat,
631
+ defined. first ,
632
+ ) ;
633
+ return ;
634
+ }
635
+
636
+ for mut j in 0 ..repeat {
637
+ j *= size. bytes ( ) ;
638
+ j += dest. offset . bytes ( ) ;
639
+ let mut cur = defined. first ;
640
+ for range in & defined. ranges {
641
+ let old_j = j;
642
+ j += range;
643
+ self . undef_mask . set_range_inbounds (
644
+ Size :: from_bytes ( old_j) ,
645
+ Size :: from_bytes ( j) ,
646
+ cur,
647
+ ) ;
648
+ cur = !cur;
649
+ }
650
+ }
651
+ }
652
+ }
653
+
569
654
/// Relocations
570
655
#[ derive( Clone , PartialEq , Eq , PartialOrd , Ord , Hash , Debug , RustcEncodable , RustcDecodable ) ]
571
656
pub struct Relocations < Tag =( ) , Id =AllocId > ( SortedMap < Size , ( Tag , Id ) > ) ;
0 commit comments