@@ -162,10 +162,20 @@ pub struct MachBuffer<I: VCodeInst> {
162162 /// Latest branches, to facilitate in-place editing for better fallthrough
163163 /// behavior and empty-block removal.
164164 latest_branches : SmallVec < [ MachBranch ; 4 ] > ,
165- /// All labels at the current offset (emission tail). For correctness, this
166- /// *must* be complete, because we rely on it to update labels when we
167- /// truncate branches.
165+ /// All labels at the current offset (emission tail). This is lazily
166+ /// cleared: it is actually accurate as long as the current offset is
167+ /// `labels_at_tail_off`, but if `cur_offset()` has grown larger, it should
168+ /// be considered as empty.
169+ ///
170+ /// For correctness, this *must* be complete (i.e., the vector must contain
171+ /// all labels whose offsets are resolved to the current tail), because we
172+ /// rely on it to update labels when we truncate branches.
168173 labels_at_tail : SmallVec < [ MachLabel ; 4 ] > ,
174+ /// The last offset at which `labels_at_tail` is valid. It is conceptually
175+ /// always describing the tail of the buffer, but we do not clear
176+ /// `labels_at_tail` eagerly when the tail grows, rather we lazily clear it
177+ /// when the offset has grown past this (`labels_at_tail_off`) point.
178+ labels_at_tail_off : CodeOffset ,
169179}
170180
171181/// A `MachBuffer` once emission is completed: holds generated code and records,
@@ -226,6 +236,7 @@ impl<I: VCodeInst> MachBuffer<I> {
226236 island_worst_case_size : 0 ,
227237 latest_branches : SmallVec :: new ( ) ,
228238 labels_at_tail : SmallVec :: new ( ) ,
239+ labels_at_tail_off : 0 ,
229240 }
230241 }
231242
@@ -238,7 +249,6 @@ impl<I: VCodeInst> MachBuffer<I> {
238249 pub fn put1 ( & mut self , value : u8 ) {
239250 trace ! ( "MachBuffer: put byte @ {}: {:x}" , self . cur_offset( ) , value) ;
240251 self . data . push ( value) ;
241- self . labels_at_tail . clear ( ) ;
242252 }
243253
244254 /// Add 2 bytes.
@@ -250,7 +260,6 @@ impl<I: VCodeInst> MachBuffer<I> {
250260 ) ;
251261 let bytes = value. to_le_bytes ( ) ;
252262 self . data . extend_from_slice ( & bytes[ ..] ) ;
253- self . labels_at_tail . clear ( ) ;
254263 }
255264
256265 /// Add 4 bytes.
@@ -262,7 +271,6 @@ impl<I: VCodeInst> MachBuffer<I> {
262271 ) ;
263272 let bytes = value. to_le_bytes ( ) ;
264273 self . data . extend_from_slice ( & bytes[ ..] ) ;
265- self . labels_at_tail . clear ( ) ;
266274 }
267275
268276 /// Add 8 bytes.
@@ -274,7 +282,6 @@ impl<I: VCodeInst> MachBuffer<I> {
274282 ) ;
275283 let bytes = value. to_le_bytes ( ) ;
276284 self . data . extend_from_slice ( & bytes[ ..] ) ;
277- self . labels_at_tail . clear ( ) ;
278285 }
279286
280287 /// Add a slice of bytes.
@@ -285,7 +292,6 @@ impl<I: VCodeInst> MachBuffer<I> {
285292 data. len( )
286293 ) ;
287294 self . data . extend_from_slice ( data) ;
288- self . labels_at_tail . clear ( ) ;
289295 }
290296
291297 /// Reserve appended space and return a mutable slice referring to it.
@@ -294,7 +300,6 @@ impl<I: VCodeInst> MachBuffer<I> {
294300 let off = self . data . len ( ) ;
295301 let new_len = self . data . len ( ) + len;
296302 self . data . resize ( new_len, 0 ) ;
297- self . labels_at_tail . clear ( ) ;
298303 & mut self . data [ off..]
299304 }
300305
@@ -335,10 +340,21 @@ impl<I: VCodeInst> MachBuffer<I> {
335340 ) ;
336341 let offset = self . cur_offset ( ) ;
337342 self . label_offsets [ label. 0 as usize ] = offset;
343+ self . lazily_clear_labels_at_tail ( ) ;
338344 self . labels_at_tail . push ( label) ;
339345 self . optimize_branches ( ) ;
340346 }
341347
348+ /// Lazily clear `labels_at_tail` if the tail offset has moved beyond the
349+ /// offset that it applies to.
350+ fn lazily_clear_labels_at_tail ( & mut self ) {
351+ let offset = self . cur_offset ( ) ;
352+ if offset > self . labels_at_tail_off {
353+ self . labels_at_tail_off = offset;
354+ self . labels_at_tail . clear ( ) ;
355+ }
356+ }
357+
342358 /// Resolve a label to an offset, if known. May return `UNKNOWN_LABEL_OFFSET`.
343359 fn resolve_label_offset ( & self , label : MachLabel ) -> CodeOffset {
344360 let alias = self . label_aliases [ label. 0 as usize ] ;
@@ -396,6 +412,7 @@ impl<I: VCodeInst> MachBuffer<I> {
396412 debug_assert ! ( end > start) ;
397413 assert ! ( !self . fixup_records. is_empty( ) ) ;
398414 let fixup = self . fixup_records . len ( ) - 1 ;
415+ self . lazily_clear_labels_at_tail ( ) ;
399416 self . latest_branches . push ( MachBranch {
400417 start,
401418 end,
@@ -421,6 +438,7 @@ impl<I: VCodeInst> MachBuffer<I> {
421438 assert ! ( !self . fixup_records. is_empty( ) ) ;
422439 let fixup = self . fixup_records . len ( ) - 1 ;
423440 let inverted = Some ( SmallVec :: from ( inverted) ) ;
441+ self . lazily_clear_labels_at_tail ( ) ;
424442 self . latest_branches . push ( MachBranch {
425443 start,
426444 end,
@@ -432,11 +450,13 @@ impl<I: VCodeInst> MachBuffer<I> {
432450 }
433451
434452 fn truncate_last_branch ( & mut self ) {
453+ self . lazily_clear_labels_at_tail ( ) ;
435454 let b = self . latest_branches . pop ( ) . unwrap ( ) ;
436455 assert ! ( b. end == self . cur_offset( ) ) ;
437456 self . data . truncate ( b. start as usize ) ;
438457 self . fixup_records . truncate ( b. fixup ) ;
439458 let cur_off = self . cur_offset ( ) ;
459+ self . labels_at_tail_off = cur_off;
440460 trace ! (
441461 "truncate_last_branch: truncated {:?}; off now {}" ,
442462 b,
@@ -450,12 +470,18 @@ impl<I: VCodeInst> MachBuffer<I> {
450470 }
451471
452472 fn optimize_branches ( & mut self ) {
473+ self . lazily_clear_labels_at_tail ( ) ;
453474 trace ! (
454475 "enter optimize_branches:\n b = {:?}\n l = {:?}\n f = {:?}" ,
455476 self . latest_branches,
456477 self . labels_at_tail,
457478 self . fixup_records
458479 ) ;
480+
481+ // We continue to munch on branches at the tail of the buffer until no
482+ // more rules apply. Note that the loop only continues if a branch is
483+ // actually truncated (or if labels are redirected away from a branch),
484+ // so this always makes progress.
459485 while let Some ( b) = self . latest_branches . last ( ) {
460486 let cur_off = self . cur_offset ( ) ;
461487 trace ! ( "optimize_branches: last branch {:?} at off {}" , b, cur_off) ;
@@ -962,9 +988,10 @@ struct MachBranch {
962988 fixup : usize ,
963989 inverted : Option < SmallVec < [ u8 ; 8 ] > > ,
964990 /// All labels pointing to the start of this branch. For correctness, this
965- /// *must* be complete: we rely on being able to redirect all labels that
966- /// could jump to this branch before removing it, if it is otherwise
967- /// unreachable.
991+ /// *must* be complete (i.e., must contain all labels whose resolved offsets
992+ /// are at the start of this branch): we rely on being able to redirect all
993+ /// labels that could jump to this branch before removing it, if it is
994+ /// otherwise unreachable.
968995 labels_at_this_branch : SmallVec < [ MachLabel ; 4 ] > ,
969996}
970997
0 commit comments