@@ -566,6 +566,91 @@ impl<'tcx, Tag, Extra> Allocation<Tag, Extra> {
566566 }
567567}
568568
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+
569654/// Relocations
570655#[ derive( Clone , PartialEq , Eq , PartialOrd , Ord , Hash , Debug , RustcEncodable , RustcDecodable ) ]
571656pub struct Relocations < Tag =( ) , Id =AllocId > ( SortedMap < Size , ( Tag , Id ) > ) ;
0 commit comments