Skip to content

Conversation

rluvaton
Copy link

@rluvaton rluvaton commented Sep 20, 2025

I noticed that this was not inlined when trying to push and probably the reason why the compiler lose the information about the capacity (fixes #82801) - is there a way I can test that to make sure the issue is fixed?

The reason is due to LLVM not marking the condition for capacity as dead code, opened an issue:

I noticed that this was not inlined when trying to `push` and probably the reason why the compiler lose the information about the capacity (fixes rust-lang#82801)

BTW The original PR that added it (rust-lang#91352) wrote:
> [...] I tried lots of minor variations on this, e.g. different inlining
attributes. This was the best one I could find. [...]

I never contributed to Rust so I did not know how to test that it actually fixes the problem, but I'm fairly certain it is.

Consider the very basic example (Godbolt rustc 1.90.0 `-C opt-level=3 -C target-feature=+avx2 -C codegen-units=1`) 
```rust
#[no_mangle]
fn extend_offsets(offsets: &[usize]) -> Vec::<usize> {
    let mut intermediate = Vec::<usize>::with_capacity(offsets.len());

    for &offset in offsets {
        intermediate.push(offset)
    }

    intermediate
}
```

it does not inline `grow_one` which make it not use SIMD.

If however we are using [`push_within_capacity`](rust-lang#100486):

```rust
#![feature(vec_push_within_capacity)]

#[no_mangle]
fn extend_offsets(offsets: &[usize]) -> Vec::<usize> {
    let mut intermediate = Vec::<usize>::with_capacity(offsets.len());

    for &offset in offsets {
        intermediate.push_within_capacity(offset).unwrap()
    }

    intermediate
}
```

it will use SIMD
@rustbot rustbot added S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. T-libs Relevant to the library team, which will review and decide on the PR/issue. labels Sep 20, 2025
@rustbot
Copy link
Collaborator

rustbot commented Sep 20, 2025

r? @tgross35

rustbot has assigned @tgross35.
They will have a look at your PR within the next two weeks and either review your PR or reassign to another reviewer.

Use r? to explicitly pick a reviewer

@saethlin
Copy link
Member

@bors try @rust-timer queue

@rust-timer

This comment has been minimized.

@rust-bors

This comment has been minimized.

rust-bors bot added a commit that referenced this pull request Sep 20, 2025
perf: change `RawVec` `grow_one` from `#[inline(never)]` to `#[inline]`
@rustbot rustbot added the S-waiting-on-perf Status: Waiting on a perf run to be completed. label Sep 20, 2025
@rust-log-analyzer
Copy link
Collaborator

The job aarch64-gnu-llvm-20-1 failed! Check out the build log: (web) (plain enhanced) (plain)

Click to see the possible cause of the failure (guessed by this bot)

---- [codegen] tests/codegen-llvm/vec-len-invariant.rs stdout ----
------FileCheck stdout------------------------------

------FileCheck stderr------------------------------
/checkout/tests/codegen-llvm/vec-len-invariant.rs:12:12: error: CHECK: expected string not found in input
 // CHECK: call {{.*}}grow_one
           ^
/checkout/obj/build/aarch64-unknown-linux-gnu/test/codegen-llvm/vec-len-invariant/vec-len-invariant.ll:123:19: note: scanning from here
 %len.i = load i64, ptr %0, align 8, !alias.scope !6, !noundef !3
                  ^
/checkout/obj/build/aarch64-unknown-linux-gnu/test/codegen-llvm/vec-len-invariant/vec-len-invariant.ll:157:6: note: possible intended match here
; call alloc::raw_vec::finish_grow
     ^

Input file: /checkout/obj/build/aarch64-unknown-linux-gnu/test/codegen-llvm/vec-len-invariant/vec-len-invariant.ll
Check file: /checkout/tests/codegen-llvm/vec-len-invariant.rs

-dump-input=help explains the following input dump.

Input was:
<<<<<<
            .
            .
            .
           23:  %2 = getelementptr inbounds nuw i8, ptr %current_memory, i64 8 
           24:  %3 = load i64, ptr %2, align 8, !range !2, !noundef !3 
           25:  %.not = icmp eq i64 %3, 0 
           26:  br i1 %.not, label %bb5, label %bb1 
           27:  
           28: bb1: ; preds = %start 
           29:  %ptr = load ptr, ptr %current_memory, align 8, !nonnull !3, !noundef !3 
           30:  %4 = getelementptr inbounds nuw i8, ptr %current_memory, i64 16 
           31:  %5 = load i64, ptr %4, align 8, !noundef !3 
           32:  store i64 %3, ptr %_9, align 8 
           33:  store i64 %0, ptr %_12, align 8 
           34:  %_14 = icmp eq i64 %3, %0 
           35:  br i1 %_14, label %bb2, label %bb3, !prof !4 
           36:  
           37: bb5: ; preds = %start 
           38:  %6 = icmp eq i64 %1, 0 
           39:  br i1 %6, label %bb2.i.i, label %bb4.i.i 
           40:  
           41: bb2.i.i: ; preds = %bb5 
           42:  %_19.i.i = getelementptr i8, ptr null, i64 %0 
           43:  br label %bb7 
           44:  
           45: bb4.i.i: ; preds = %bb5 
           46: ; call __rustc::__rust_no_alloc_shim_is_unstable_v2 
           47:  tail call void @_RNvCsluNeYmp3Xm3_7___rustc35___rust_no_alloc_shim_is_unstable_v2() #11 
           48: ; call __rustc::__rust_alloc 
           49:  %7 = tail call noundef ptr @_RNvCsluNeYmp3Xm3_7___rustc12___rust_alloc(i64 noundef %1, i64 noundef range(i64 1, -9223372036854775807) %0) #11 
           50:  br label %bb7 
           51:  
           52: bb3: ; preds = %bb1 
           53:  call void @llvm.lifetime.start.p0(i64 48, ptr nonnull %_16) 
           54:  store ptr null, ptr %_16, align 8 
           55: ; call core::panicking::assert_failed 
           56:  call void @_ZN4core9panicking13assert_failed17hc671a3ed0aea6677E(i8 noundef 0, ptr noalias noundef nonnull readonly align 8 dereferenceable(8) %_9, ptr noalias noundef nonnull readonly align 8 dereferenceable(8) %_12, ptr noalias noundef nonnull align 8 dereferenceable(48) %_16, ptr noalias noundef nonnull readonly align 8 dereferenceable(24) @alloc_60b3217ab254a473df4c758b54d2e808) #12 
           57:  unreachable 
           58:  
           59: bb2: ; preds = %bb1 
           60:  %_6.not.i.i = icmp ult i64 %1, %5 
           61:  br i1 %_6.not.i.i, label %bb2.i.i13, label %bb1.i.i, !prof !5 
           62:  
           63: bb2.i.i13: ; preds = %bb2 
           64:  call void @llvm.lifetime.start.p0(i64 48, ptr nonnull %_12.i.i) 
           65:  store ptr @alloc_04056f6d76887c0653320aca2f1cbe49, ptr %_12.i.i, align 8 
           66:  %8 = getelementptr inbounds nuw i8, ptr %_12.i.i, i64 8 
           67:  store i64 1, ptr %8, align 8 
           68:  %9 = getelementptr inbounds nuw i8, ptr %_12.i.i, i64 16 
           69:  store ptr null, ptr %9, align 8 
           70:  %10 = getelementptr inbounds nuw i8, ptr %_12.i.i, i64 32 
           71:  store ptr inttoptr (i64 8 to ptr), ptr %10, align 8 
           72:  %11 = getelementptr inbounds nuw i8, ptr %_12.i.i, i64 40 
           73:  store i64 0, ptr %11, align 8 
           74: ; call core::panicking::panic_fmt 
           75:  call void @_ZN4core9panicking9panic_fmt17hc0fa719bc544a225E(ptr noalias noundef nonnull readonly align 8 dereferenceable(48) %_12.i.i, ptr noalias noundef nonnull readonly align 8 dereferenceable(24) @alloc_f8c5c844aa69054ab9d96ab1c41933fc) #12 
           76:  unreachable 
           77:  
           78: bb1.i.i: ; preds = %bb2 
           79:  %12 = icmp eq i64 %5, 0 
           80:  br i1 %12, label %bb4.i.i12, label %bb5.i.i 
           81:  
           82: bb4.i.i12: ; preds = %bb1.i.i 
           83:  %13 = icmp eq i64 %1, 0 
           84:  br i1 %13, label %bb2.i.i.i, label %bb4.i.i.i 
           85:  
           86: bb2.i.i.i: ; preds = %bb4.i.i12 
           87:  %_19.i.i.i = getelementptr i8, ptr null, i64 %0 
           88:  br label %bb7 
           89:  
           90: bb4.i.i.i: ; preds = %bb4.i.i12 
           91: ; call __rustc::__rust_no_alloc_shim_is_unstable_v2 
           92:  tail call void @_RNvCsluNeYmp3Xm3_7___rustc35___rust_no_alloc_shim_is_unstable_v2() #11 
           93: ; call __rustc::__rust_alloc 
           94:  %14 = tail call noundef ptr @_RNvCsluNeYmp3Xm3_7___rustc12___rust_alloc(i64 noundef %1, i64 noundef range(i64 1, -9223372036854775807) %0) #11 
           95:  br label %bb7 
           96:  
           97: bb5.i.i: ; preds = %bb1.i.i 
           98: ; call __rustc::__rust_realloc 
           99:  %15 = tail call noundef ptr @_RNvCsluNeYmp3Xm3_7___rustc14___rust_realloc(ptr noundef nonnull %ptr, i64 noundef %5, i64 noundef range(i64 1, -9223372036854775807) %0, i64 noundef %1) #11 
          100:  br label %bb7 
          101:  
          102: bb7: ; preds = %bb5.i.i, %bb4.i.i.i, %bb2.i.i.i, %bb4.i.i, %bb2.i.i 
          103:  %_0.sroa.0.0.i.i11.pn = phi ptr [ %_19.i.i, %bb2.i.i ], [ %7, %bb4.i.i ], [ %15, %bb5.i.i ], [ %_19.i.i.i, %bb2.i.i.i ], [ %14, %bb4.i.i.i ] 
          104:  %16 = icmp eq ptr %_0.sroa.0.0.i.i11.pn, null 
          105:  %17 = inttoptr i64 %0 to ptr 
          106:  %spec.select = select i1 %16, ptr %17, ptr %_0.sroa.0.0.i.i11.pn 
          107:  %spec.select4 = zext i1 %16 to i64 
          108:  %18 = getelementptr inbounds nuw i8, ptr %_0, i64 8 
          109:  store ptr %spec.select, ptr %18, align 8 
          110:  %19 = getelementptr inbounds nuw i8, ptr %_0, i64 16 
          111:  store i64 %1, ptr %19, align 8 
          112:  store i64 %spec.select4, ptr %_0, align 8 
          113:  ret void 
          114: } 
          115:  
          116: ; Function Attrs: uwtable 
          117: define void @should_load_once(ptr noalias nocapture noundef align 8 dereferenceable(24) %v) unnamed_addr #1 personality ptr @rust_eh_personality { 
          118: start: 
          119:  %_29.i.i = alloca [24 x i8], align 8 
          120:  %self5.i.i = alloca [24 x i8], align 8 
          121:  tail call void @llvm.experimental.noalias.scope.decl(metadata !6) 
          122:  %0 = getelementptr inbounds nuw i8, ptr %v, i64 16 
          123:  %len.i = load i64, ptr %0, align 8, !alias.scope !6, !noundef !3 
check:12'0                       X~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ error: no match found
          124:  %1 = getelementptr inbounds nuw i8, ptr %v, i64 8 
check:12'0     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
          125:  %self1.i = load i64, ptr %1, align 8, !range !9, !alias.scope !6, !noundef !3 
check:12'0     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
          126:  %_4.i = icmp eq i64 %len.i, %self1.i 
check:12'0     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
          127:  br i1 %_4.i, label %bb1.i, label %start.bb3_crit_edge.i 
check:12'0     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
          128:  
check:12'0     ~
          129: start.bb3_crit_edge.i: ; preds = %start 
check:12'0     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
          130:  %_24.pre.i = load ptr, ptr %v, align 8, !alias.scope !6 
check:12'0     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
          131:  br label %"_ZN5alloc3vec16Vec$LT$T$C$A$GT$8push_mut17h2c3392560117356eE.exit" 
check:12'0     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
          132:  
check:12'0     ~
          133: bb1.i: ; preds = %start 
check:12'0     ~~~~~~~~~~~~~~~~~~~~~~~~
          134:  tail call void @llvm.experimental.noalias.scope.decl(metadata !10) 
check:12'0     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
          135:  %2 = shl nuw i64 %len.i, 1 
check:12'0     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
          136:  %3 = tail call i64 @llvm.umax.i64(i64 %2, i64 8) 
check:12'0     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
          137:  %_26.i.i.i = icmp slt i64 %3, 0 
check:12'0     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
          138:  br i1 %_26.i.i.i, label %bb12.i, label %bb25.i.i, !prof !13 
check:12'0     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
          139:  
check:12'0     ~
          140: bb25.i.i: ; preds = %bb1.i 
check:12'0     ~~~~~~~~~~~~~~~~~~~~~~~~~~~
          141:  call void @llvm.lifetime.start.p0(i64 24, ptr nonnull %self5.i.i), !noalias !14 
check:12'0     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
          142:  call void @llvm.lifetime.start.p0(i64 24, ptr nonnull %_29.i.i), !noalias !14 
check:12'0     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
          143:  %4 = icmp eq i64 %len.i, 0 
check:12'0     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
          144:  br i1 %4, label %"_ZN5alloc7raw_vec20RawVecInner$LT$A$GT$14current_memory17h84d95bdf5b34909dE.exit.i.i", label %bb4.i.i.i 
check:12'0     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
          145:  
check:12'0     ~
          146: bb4.i.i.i: ; preds = %bb25.i.i 
check:12'0     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
          147:  %self.val.i.i = load ptr, ptr %v, align 8, !alias.scope !14, !nonnull !3, !noundef !3 
check:12'0     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
          148:  store ptr %self.val.i.i, ptr %_29.i.i, align 8, !alias.scope !15, !noalias !14 
check:12'0     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
          149:  %_15.sroa.5.0._0.sroa_idx.i.i.i = getelementptr inbounds nuw i8, ptr %_29.i.i, i64 16 
check:12'0     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
          150:  store i64 %len.i, ptr %_15.sroa.5.0._0.sroa_idx.i.i.i, align 8, !alias.scope !15, !noalias !14 
check:12'0     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
          151:  br label %"_ZN5alloc7raw_vec20RawVecInner$LT$A$GT$14current_memory17h84d95bdf5b34909dE.exit.i.i" 
check:12'0     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
          152:  
check:12'0     ~
          153: "_ZN5alloc7raw_vec20RawVecInner$LT$A$GT$14current_memory17h84d95bdf5b34909dE.exit.i.i": ; preds = %bb4.i.i.i, %bb25.i.i 
check:12'0     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
          154:  %.sink.i.i.i = phi i64 [ 1, %bb4.i.i.i ], [ 0, %bb25.i.i ] 
check:12'0     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
          155:  %5 = getelementptr inbounds nuw i8, ptr %_29.i.i, i64 8 
check:12'0     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
          156:  store i64 %.sink.i.i.i, ptr %5, align 8, !alias.scope !15, !noalias !14 
check:12'0     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
          157: ; call alloc::raw_vec::finish_grow 
check:12'0     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
check:12'1          ?                              possible intended match
          158:  call fastcc void @_ZN5alloc7raw_vec11finish_grow17h598902a8a8510760E(ptr noalias noundef align 8 dereferenceable(24) %self5.i.i, i64 noundef 1, i64 noundef %3, ptr noalias noundef readonly align 8 dereferenceable(24) %_29.i.i), !noalias !14 
check:12'0     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
          159:  call void @llvm.lifetime.end.p0(i64 24, ptr nonnull %_29.i.i), !noalias !14 
check:12'0     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
          160:  %_56.i.i = load i64, ptr %self5.i.i, align 8, !range !18, !noalias !14, !noundef !3 
check:12'0     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
          161:  %6 = trunc nuw i64 %_56.i.i to i1 
check:12'0     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
          162:  %7 = getelementptr inbounds nuw i8, ptr %self5.i.i, i64 8 
check:12'0     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
          163:  br i1 %6, label %bb26.i.i, label %"_ZN5alloc7raw_vec20RawVecInner$LT$A$GT$14grow_amortized17h6d61f7b4f2838582E.exit.i" 
check:12'0     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
          164:  
check:12'0     ~
          165: bb26.i.i: ; preds = %"_ZN5alloc7raw_vec20RawVecInner$LT$A$GT$14current_memory17h84d95bdf5b34909dE.exit.i.i" 
check:12'0     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
          166:  %e.0.i.i = load i64, ptr %7, align 8, !range !2, !noalias !14, !noundef !3 
check:12'0     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
          167:  %8 = getelementptr inbounds nuw i8, ptr %self5.i.i, i64 16 
check:12'0     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
          168:  %e.1.i.i = load i64, ptr %8, align 8, !noalias !14 
check:12'0     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
          169:  call void @llvm.lifetime.end.p0(i64 24, ptr nonnull %self5.i.i), !noalias !14 
check:12'0     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
          170:  br label %bb12.i 
check:12'0     ~~~~~~~~~~~~~~~~~~
          171:  
check:12'0     ~
          172: "_ZN5alloc7raw_vec20RawVecInner$LT$A$GT$14grow_amortized17h6d61f7b4f2838582E.exit.i": ; preds = %"_ZN5alloc7raw_vec20RawVecInner$LT$A$GT$14current_memory17h84d95bdf5b34909dE.exit.i.i" 
check:12'0     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
          173:  %v.013.i.i = load ptr, ptr %7, align 8, !noalias !14, !nonnull !3, !noundef !3 
check:12'0     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
          174:  call void @llvm.lifetime.end.p0(i64 24, ptr nonnull %self5.i.i), !noalias !14 
check:12'0     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
          175:  store ptr %v.013.i.i, ptr %v, align 8, !alias.scope !14 
check:12'0     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
          176:  store i64 %3, ptr %1, align 8, !alias.scope !14 
check:12'0     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
          177:  br label %"_ZN5alloc3vec16Vec$LT$T$C$A$GT$8push_mut17h2c3392560117356eE.exit" 
check:12'0     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
          178:  
check:12'0     ~
          179: bb12.i: ; preds = %bb26.i.i, %bb1.i 
check:12'0     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
          180:  %_0.sroa.6.0.i.ph.i = phi i64 [ undef, %bb1.i ], [ %e.1.i.i, %bb26.i.i ] 
check:12'0     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
          181:  %_0.sroa.0.0.i.ph.i = phi i64 [ 0, %bb1.i ], [ %e.0.i.i, %bb26.i.i ] 
check:12'0     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
          182: ; call alloc::raw_vec::handle_error 
check:12'0     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
          183:  tail call void @_ZN5alloc7raw_vec12handle_error17h3a1325aef5fdff61E(i64 noundef %_0.sroa.0.0.i.ph.i, i64 %_0.sroa.6.0.i.ph.i, ptr noalias noundef nonnull readonly align 8 dereferenceable(24) @alloc_39d7e98511a1d7398aea42ce8d330a58) #12, !noalias !6 
check:12'0     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
          184:  unreachable 
check:12'0     ~~~~~~~~~~~~~
          185:  
check:12'0     ~
          186: "_ZN5alloc3vec16Vec$LT$T$C$A$GT$8push_mut17h2c3392560117356eE.exit": ; preds = %start.bb3_crit_edge.i, %"_ZN5alloc7raw_vec20RawVecInner$LT$A$GT$14grow_amortized17h6d61f7b4f2838582E.exit.i" 
check:12'0     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
          187:  %_24.i = phi ptr [ %_24.pre.i, %start.bb3_crit_edge.i ], [ %v.013.i.i, %"_ZN5alloc7raw_vec20RawVecInner$LT$A$GT$14grow_amortized17h6d61f7b4f2838582E.exit.i" ] 
check:12'0     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
          188:  %9 = getelementptr inbounds nuw i8, ptr %_24.i, i64 %len.i 
check:12'0     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
          189:  store i8 1, ptr %9, align 1, !noalias !6 
check:12'0     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
          190:  %_12.0.i = add i64 %len.i, 1 
check:12'0     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
          191:  store i64 %_12.0.i, ptr %0, align 8, !alias.scope !6 
check:12'0     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
          192:  ret void 
check:12'0     ~~~~~~~~~~
          193: } 
check:12'0     ~~
          194:  
check:12'0     ~
          195: ; Function Attrs: nounwind uwtable 
check:12'0     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
          196: declare noundef range(i32 0, 10) i32 @rust_eh_personality(i32 noundef, i32 noundef, i64 noundef, ptr noundef, ptr noundef) unnamed_addr #2 
check:12'0     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
          197:  
check:12'0     ~
          198: ; Function Attrs: mustprogress nocallback nofree nosync nounwind willreturn memory(argmem: readwrite) 
check:12'0     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
          199: declare void @llvm.lifetime.start.p0(i64 immarg, ptr nocapture) #3 
check:12'0     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
          200:  
check:12'0     ~
          201: ; Function Attrs: mustprogress nocallback nofree nosync nounwind willreturn memory(argmem: readwrite) 
check:12'0     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
          202: declare void @llvm.lifetime.end.p0(i64 immarg, ptr nocapture) #3 
check:12'0     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
          203:  
check:12'0     ~
          204: ; core::panicking::panic_fmt 
check:12'0     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
          205: ; Function Attrs: cold noinline noreturn uwtable 
check:12'0     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
          206: declare void @_ZN4core9panicking9panic_fmt17hc0fa719bc544a225E(ptr noalias noundef readonly align 8 dereferenceable(48), ptr noalias noundef readonly align 8 dereferenceable(24)) unnamed_addr #4 
check:12'0     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
          207:  
check:12'0     ~
          208: ; alloc::raw_vec::handle_error 
check:12'0     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
          209: ; Function Attrs: cold minsize noreturn optsize uwtable 
check:12'0     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
          210: declare void @_ZN5alloc7raw_vec12handle_error17h3a1325aef5fdff61E(i64 noundef range(i64 0, -9223372036854775807), i64, ptr noalias noundef readonly align 8 dereferenceable(24)) unnamed_addr #5 
check:12'0     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
          211:  
check:12'0     ~
          212: ; __rustc::__rust_no_alloc_shim_is_unstable_v2 
check:12'0     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
          213: ; Function Attrs: nounwind uwtable 
check:12'0     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
          214: declare void @_RNvCsluNeYmp3Xm3_7___rustc35___rust_no_alloc_shim_is_unstable_v2() unnamed_addr #2 
check:12'0     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
          215:  
check:12'0     ~
          216: ; __rustc::__rust_alloc 
check:12'0     ~~~~~~~~~~~~~~~~~~~~~~~~
          217: ; Function Attrs: nounwind allockind("alloc,uninitialized,aligned") allocsize(0) uwtable 
check:12'0     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
          218: declare noalias noundef ptr @_RNvCsluNeYmp3Xm3_7___rustc12___rust_alloc(i64 noundef, i64 allocalign noundef) unnamed_addr #6 
check:12'0     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
          219:  
check:12'0     ~
          220: ; __rustc::__rust_realloc 
check:12'0     ~~~~~~~~~~~~~~~~~~~~~~~~~~
          221: ; Function Attrs: nounwind allockind("realloc,aligned") allocsize(3) uwtable 
check:12'0     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
          222: declare noalias noundef ptr @_RNvCsluNeYmp3Xm3_7___rustc14___rust_realloc(ptr allocptr noundef, i64 noundef, i64 allocalign noundef, i64 noundef) unnamed_addr #7 
check:12'0     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
          223:  
check:12'0     ~
          224: ; core::panicking::assert_failed 
check:12'0     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
          225: ; Function Attrs: cold minsize noinline noreturn optsize uwtable 
check:12'0     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
          226: declare void @_ZN4core9panicking13assert_failed17hc671a3ed0aea6677E(i8 noundef range(i8 0, 3), ptr noalias noundef readonly align 8 dereferenceable(8), ptr noalias noundef readonly align 8 dereferenceable(8), ptr noalias noundef align 8 dereferenceable(48), ptr noalias noundef readonly align 8 dereferenceable(24)) unnamed_addr #8 
check:12'0     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
          227:  
check:12'0     ~
          228: ; Function Attrs: nocallback nofree nosync nounwind willreturn memory(inaccessiblemem: readwrite) 
check:12'0     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
          229: declare void @llvm.experimental.noalias.scope.decl(metadata) #9 
check:12'0     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
          230:  
check:12'0     ~
          231: ; Function Attrs: nocallback nofree nosync nounwind speculatable willreturn memory(none) 
check:12'0     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
          232: declare i64 @llvm.umax.i64(i64, i64) #10 
check:12'0     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
          233:  
check:12'0     ~
          234: attributes #0 = { cold uwtable "frame-pointer"="non-leaf" "probe-stack"="inline-asm" "target-cpu"="generic" "target-features"="+v8a,+outline-atomics" } 
check:12'0     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
          235: attributes #1 = { uwtable "frame-pointer"="non-leaf" "probe-stack"="inline-asm" "target-cpu"="generic" "target-features"="+v8a,+outline-atomics" } 
check:12'0     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
          236: attributes #2 = { nounwind uwtable "frame-pointer"="non-leaf" "probe-stack"="inline-asm" "target-cpu"="generic" "target-features"="+v8a,+outline-atomics" } 
check:12'0     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
          237: attributes #3 = { mustprogress nocallback nofree nosync nounwind willreturn memory(argmem: readwrite) } 
check:12'0     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
          238: attributes #4 = { cold noinline noreturn uwtable "frame-pointer"="non-leaf" "probe-stack"="inline-asm" "target-cpu"="generic" "target-features"="+v8a,+outline-atomics" } 
check:12'0     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
          239: attributes #5 = { cold minsize noreturn optsize uwtable "frame-pointer"="non-leaf" "probe-stack"="inline-asm" "target-cpu"="generic" "target-features"="+v8a,+outline-atomics" } 
check:12'0     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
          240: attributes #6 = { nounwind allockind("alloc,uninitialized,aligned") allocsize(0) uwtable "alloc-family"="__rust_alloc" "alloc-variant-zeroed"="_RNvCsluNeYmp3Xm3_7___rustc19___rust_alloc_zeroed" "frame-pointer"="non-leaf" "probe-stack"="inline-asm" "target-cpu"="generic" "target-features"="+v8a,+outline-atomics" } 
check:12'0     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
          241: attributes #7 = { nounwind allockind("realloc,aligned") allocsize(3) uwtable "alloc-family"="__rust_alloc" "frame-pointer"="non-leaf" "probe-stack"="inline-asm" "target-cpu"="generic" "target-features"="+v8a,+outline-atomics" } 
check:12'0     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
          242: attributes #8 = { cold minsize noinline noreturn optsize uwtable "frame-pointer"="non-leaf" "probe-stack"="inline-asm" "target-cpu"="generic" "target-features"="+v8a,+outline-atomics" } 
check:12'0     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
          243: attributes #9 = { nocallback nofree nosync nounwind willreturn memory(inaccessiblemem: readwrite) } 
check:12'0     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
          244: attributes #10 = { nocallback nofree nosync nounwind speculatable willreturn memory(none) } 
check:12'0     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
          245: attributes #11 = { nounwind } 
check:12'0     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
          246: attributes #12 = { noreturn } 
check:12'0     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
          247:  
check:12'0     ~
          248: !llvm.module.flags = !{!0} 
check:12'0     ~~~~~~~~~~~~~~~~~~~~~~~~~~~
          249: !llvm.ident = !{!1} 
check:12'0     ~~~~~~~~~~~~~~~~~~~~
          250:  
check:12'0     ~
          251: !0 = !{i32 8, !"PIC Level", i32 2} 
check:12'0     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
          252: !1 = !{!"rustc version 1.92.0-nightly (ac01e0523 2025-09-20)"} 
check:12'0     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
          253: !2 = !{i64 0, i64 -9223372036854775807} 
check:12'0     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
          254: !3 = !{} 
check:12'0     ~~~~~~~~~
          255: !4 = !{!"branch_weights", !"expected", i32 2000, i32 1} 
check:12'0     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
          256: !5 = !{!"branch_weights", !"expected", i32 1, i32 2000} 
check:12'0     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
          257: !6 = !{!7} 
check:12'0     ~~~~~~~~~~~
            .
            .
            .
>>>>>>

------------------------------------------

error: verification with 'FileCheck' failed
status: exit status: 1
command: "/usr/lib/llvm-20/bin/FileCheck" "--input-file" "/checkout/obj/build/aarch64-unknown-linux-gnu/test/codegen-llvm/vec-len-invariant/vec-len-invariant.ll" "/checkout/tests/codegen-llvm/vec-len-invariant.rs" "--check-prefix=CHECK" "--allow-unused-prefixes" "--dump-input-context" "100"
stdout: none
--- stderr -------------------------------
/checkout/tests/codegen-llvm/vec-len-invariant.rs:12:12: error: CHECK: expected string not found in input
 // CHECK: call {{.*}}grow_one
           ^
/checkout/obj/build/aarch64-unknown-linux-gnu/test/codegen-llvm/vec-len-invariant/vec-len-invariant.ll:123:19: note: scanning from here
 %len.i = load i64, ptr %0, align 8, !alias.scope !6, !noundef !3
                  ^
/checkout/obj/build/aarch64-unknown-linux-gnu/test/codegen-llvm/vec-len-invariant/vec-len-invariant.ll:157:6: note: possible intended match here
; call alloc::raw_vec::finish_grow
     ^

Input file: /checkout/obj/build/aarch64-unknown-linux-gnu/test/codegen-llvm/vec-len-invariant/vec-len-invariant.ll
Check file: /checkout/tests/codegen-llvm/vec-len-invariant.rs

-dump-input=help explains the following input dump.

Input was:
<<<<<<
            .
            .
            .
           23:  %2 = getelementptr inbounds nuw i8, ptr %current_memory, i64 8 
           24:  %3 = load i64, ptr %2, align 8, !range !2, !noundef !3 
           25:  %.not = icmp eq i64 %3, 0 
           26:  br i1 %.not, label %bb5, label %bb1 
           27:  
           28: bb1: ; preds = %start 
           29:  %ptr = load ptr, ptr %current_memory, align 8, !nonnull !3, !noundef !3 
           30:  %4 = getelementptr inbounds nuw i8, ptr %current_memory, i64 16 
           31:  %5 = load i64, ptr %4, align 8, !noundef !3 
           32:  store i64 %3, ptr %_9, align 8 
           33:  store i64 %0, ptr %_12, align 8 
           34:  %_14 = icmp eq i64 %3, %0 
           35:  br i1 %_14, label %bb2, label %bb3, !prof !4 
           36:  
           37: bb5: ; preds = %start 
           38:  %6 = icmp eq i64 %1, 0 
           39:  br i1 %6, label %bb2.i.i, label %bb4.i.i 
           40:  
           41: bb2.i.i: ; preds = %bb5 
           42:  %_19.i.i = getelementptr i8, ptr null, i64 %0 
           43:  br label %bb7 
           44:  
           45: bb4.i.i: ; preds = %bb5 
           46: ; call __rustc::__rust_no_alloc_shim_is_unstable_v2 
           47:  tail call void @_RNvCsluNeYmp3Xm3_7___rustc35___rust_no_alloc_shim_is_unstable_v2() #11 
           48: ; call __rustc::__rust_alloc 
           49:  %7 = tail call noundef ptr @_RNvCsluNeYmp3Xm3_7___rustc12___rust_alloc(i64 noundef %1, i64 noundef range(i64 1, -9223372036854775807) %0) #11 
           50:  br label %bb7 
           51:  
           52: bb3: ; preds = %bb1 
           53:  call void @llvm.lifetime.start.p0(i64 48, ptr nonnull %_16) 
           54:  store ptr null, ptr %_16, align 8 
           55: ; call core::panicking::assert_failed 
           56:  call void @_ZN4core9panicking13assert_failed17hc671a3ed0aea6677E(i8 noundef 0, ptr noalias noundef nonnull readonly align 8 dereferenceable(8) %_9, ptr noalias noundef nonnull readonly align 8 dereferenceable(8) %_12, ptr noalias noundef nonnull align 8 dereferenceable(48) %_16, ptr noalias noundef nonnull readonly align 8 dereferenceable(24) @alloc_60b3217ab254a473df4c758b54d2e808) #12 
           57:  unreachable 
           58:  
           59: bb2: ; preds = %bb1 
           60:  %_6.not.i.i = icmp ult i64 %1, %5 
           61:  br i1 %_6.not.i.i, label %bb2.i.i13, label %bb1.i.i, !prof !5 
           62:  
           63: bb2.i.i13: ; preds = %bb2 
           64:  call void @llvm.lifetime.start.p0(i64 48, ptr nonnull %_12.i.i) 
           65:  store ptr @alloc_04056f6d76887c0653320aca2f1cbe49, ptr %_12.i.i, align 8 
           66:  %8 = getelementptr inbounds nuw i8, ptr %_12.i.i, i64 8 
           67:  store i64 1, ptr %8, align 8 
           68:  %9 = getelementptr inbounds nuw i8, ptr %_12.i.i, i64 16 
           69:  store ptr null, ptr %9, align 8 
           70:  %10 = getelementptr inbounds nuw i8, ptr %_12.i.i, i64 32 
           71:  store ptr inttoptr (i64 8 to ptr), ptr %10, align 8 
           72:  %11 = getelementptr inbounds nuw i8, ptr %_12.i.i, i64 40 
           73:  store i64 0, ptr %11, align 8 
           74: ; call core::panicking::panic_fmt 
           75:  call void @_ZN4core9panicking9panic_fmt17hc0fa719bc544a225E(ptr noalias noundef nonnull readonly align 8 dereferenceable(48) %_12.i.i, ptr noalias noundef nonnull readonly align 8 dereferenceable(24) @alloc_f8c5c844aa69054ab9d96ab1c41933fc) #12 
           76:  unreachable 
           77:  
           78: bb1.i.i: ; preds = %bb2 
           79:  %12 = icmp eq i64 %5, 0 
           80:  br i1 %12, label %bb4.i.i12, label %bb5.i.i 
           81:  
           82: bb4.i.i12: ; preds = %bb1.i.i 
           83:  %13 = icmp eq i64 %1, 0 
           84:  br i1 %13, label %bb2.i.i.i, label %bb4.i.i.i 
           85:  
           86: bb2.i.i.i: ; preds = %bb4.i.i12 
           87:  %_19.i.i.i = getelementptr i8, ptr null, i64 %0 
           88:  br label %bb7 
           89:  
           90: bb4.i.i.i: ; preds = %bb4.i.i12 
           91: ; call __rustc::__rust_no_alloc_shim_is_unstable_v2 
           92:  tail call void @_RNvCsluNeYmp3Xm3_7___rustc35___rust_no_alloc_shim_is_unstable_v2() #11 
           93: ; call __rustc::__rust_alloc 
           94:  %14 = tail call noundef ptr @_RNvCsluNeYmp3Xm3_7___rustc12___rust_alloc(i64 noundef %1, i64 noundef range(i64 1, -9223372036854775807) %0) #11 

@rust-bors
Copy link

rust-bors bot commented Sep 20, 2025

☀️ Try build successful (CI)
Build commit: 2b1a9e5 (2b1a9e56c785e5abe128db3331df10395fb85de5, parent: 9f2ef0f14d6028c5108643cafa6e2c617834594b)

@rust-timer

This comment has been minimized.

@tgross35
Copy link
Contributor

and probably the reason why the compiler lose the information about the capacity (fixes #82801) - is there a way I can test that to make sure the issue is fixed?

The way to do this would be a codegen test. I think you could add a new function at tests/codegen-llvm/vec-len-invariant.rs (the failing test here) based on the top post of #82801 that has a CHECK-NOT: handle_error to ensure that the function doesn't contain a call to alloc::raw_vec::handle_error. Please make sure the test actually fails without the fix here.

You should also add another function that doesn't have the capacity information and passes with CHECK: handle_error, to make sure the test gets flagged if handle_error is renamed or something.

(not sure how familiar you are with filecheck but CHECK: foo means there has to be a line in the LLVM IR containing "foo", CHECK-NOT: foo means no lines can contain "foo". Some more at https://llvm.org/docs/CommandGuide/FileCheck.html)

BTW The original PR that added it (#91352) wrote:

[...] I tried lots of minor variations on this, e.g. different inlining
attributes. This was the best one I could find. [...]

@nnethercote it's been forever so I doubt it, but any idea what metrics you were going for here?

@rust-timer
Copy link
Collaborator

Finished benchmarking commit (2b1a9e5): comparison URL.

Overall result: ❌✅ regressions and improvements - please read the text below

Benchmarking this pull request means it may be perf-sensitive – we'll automatically label it not fit for rolling up. You can override this, but we strongly advise not to, due to possible changes in compiler perf.

Next Steps: If you can justify the regressions found in this try perf run, please do so in sufficient writing along with @rustbot label: +perf-regression-triaged. If not, please fix the regressions and do another perf run. If its results are neutral or positive, the label will be automatically removed.

@bors rollup=never
@rustbot label: -S-waiting-on-perf +perf-regression

Instruction count

Our most reliable metric. Used to determine the overall result above. However, even this metric can be noisy.

mean range count
Regressions ❌
(primary)
1.0% [0.1%, 3.8%] 40
Regressions ❌
(secondary)
0.5% [0.2%, 1.8%] 29
Improvements ✅
(primary)
-0.3% [-0.6%, -0.1%] 56
Improvements ✅
(secondary)
-0.4% [-2.0%, -0.1%] 80
All ❌✅ (primary) 0.3% [-0.6%, 3.8%] 96

Max RSS (memory usage)

Results (primary 3.4%, secondary -3.0%)

A less reliable metric. May be of interest, but not used to determine the overall result above.

mean range count
Regressions ❌
(primary)
4.7% [2.0%, 9.9%] 4
Regressions ❌
(secondary)
- - 0
Improvements ✅
(primary)
-1.8% [-1.8%, -1.8%] 1
Improvements ✅
(secondary)
-3.0% [-3.0%, -3.0%] 1
All ❌✅ (primary) 3.4% [-1.8%, 9.9%] 5

Cycles

Results (primary 2.6%, secondary 1.9%)

A less reliable metric. May be of interest, but not used to determine the overall result above.

mean range count
Regressions ❌
(primary)
2.6% [1.3%, 4.4%] 13
Regressions ❌
(secondary)
1.9% [1.7%, 2.2%] 2
Improvements ✅
(primary)
- - 0
Improvements ✅
(secondary)
- - 0
All ❌✅ (primary) 2.6% [1.3%, 4.4%] 13

Binary size

Results (primary 0.1%, secondary 0.2%)

A less reliable metric. May be of interest, but not used to determine the overall result above.

mean range count
Regressions ❌
(primary)
0.4% [0.0%, 1.2%] 40
Regressions ❌
(secondary)
0.3% [0.0%, 0.7%] 43
Improvements ✅
(primary)
-0.2% [-0.3%, -0.0%] 34
Improvements ✅
(secondary)
-0.3% [-0.3%, -0.3%] 3
All ❌✅ (primary) 0.1% [-0.3%, 1.2%] 74

Bootstrap: 471.07s -> 478.071s (1.49%)
Artifact size: 389.99 MiB -> 390.06 MiB (0.02%)

@rustbot rustbot added perf-regression Performance regression. and removed S-waiting-on-perf Status: Waiting on a perf run to be completed. labels Sep 20, 2025
@rluvaton
Copy link
Author

Debugging locally for the last 3 hours, the problem for not optimizing into SIMD is not because of the grow_one, the grow_one should never be called in our case, but instead the compiler don't understand that if len == self.buf.capacity() inside push_mut will never be taken.

@rluvaton
Copy link
Author

How do you help the optimizer in this case

@tgross35
Copy link
Contributor

I haven't dug into it but you may be able to play with using assert_unchecked (aka assume) in some places. We have this once at

// Make it more obvious that a subsequent Vec::reserve(capacity) will not allocate.
hint::assert_unchecked(!this.needs_to_grow(0, capacity, elem_layout));
, see #126793. Note that there's a bit of a fine line to balance, overuse of assert_unchecked can make compile times worse.

The usual process here usually involves playing with the implementations and looking at the result of --emit=llvm-ir or do that on godbolt (under "add new"). Probably no need to look at the actual asm since an error condition removal should be platform-agnostic and happen at the LLVM IR level.

If you're getting really deep into things, godbolt also has "add new"->"opt pipeline" for looking at optimizations done by each LLVM pass one at a time. Can be helpful for looking at things more incrementally, rather than just the coarse diff between -Copt-level=1 and -Copt-level=2 output.

@rluvaton rluvaton marked this pull request as draft September 21, 2025 00:31
@rustbot rustbot added S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. and removed S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. labels Sep 21, 2025
@rluvaton
Copy link
Author

So I found the problem.

LLVM does not eliminate dead code in some cases:
consider this example:

const COUNT: usize = 10000;

#[no_mangle]
pub fn run() -> usize {
    let mut inter = 0;
    let mut my_cap = COUNT;

    for _ in 0..COUNT {
        let len = inter;

        if len == my_cap {
            something(len);
        }

        inter += 1;
    }

    return inter;
}

#[inline(never)]
fn something(len: usize) {
    std::hint::black_box(len as i128);
}

pub fn main() {
    std::hint::black_box(run());
}

it will eliminate:

if len == my_cap {
  something(len);
}

but if you change the code of the if to modify my_cap it will not remove that:

if len == my_cap {
    something(len);
	my_cap += 1;
}

it will not eliminate the if.

looking at Rust MIR, the if exists in both cases, but in LLVM IR it does not exists - meaning that LLVM have the problem.

will try to look inside LLVM (Ugh, CPP)

@rluvaton rluvaton changed the title perf: change RawVec grow_one from #[inline(never)] to #[inline] Fix using SIMD for basic loop iteration with sufficient capacity Sep 21, 2025
@rluvaton
Copy link
Author

rluvaton commented Sep 21, 2025

I tried for a looong time, gave up and opened an issue to LLVM:

@rluvaton rluvaton closed this Sep 21, 2025
@rustbot rustbot removed the S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. label Sep 21, 2025
@rluvaton rluvaton deleted the patch-1 branch September 21, 2025 20:06
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
perf-regression Performance regression. T-libs Relevant to the library team, which will review and decide on the PR/issue.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

The compiler loses vector capacity information
6 participants