https://gcc.gnu.org/bugzilla/show_bug.cgi?id=104547
Bug ID: 104547 Summary: std::vector::resize(v.size() - n) produces poor code Product: gcc Version: 11.2.1 Status: UNCONFIRMED Keywords: missed-optimization Severity: normal Priority: P3 Component: tree-optimization Assignee: unassigned at gcc dot gnu.org Reporter: redi at gcc dot gnu.org Target Milestone: --- The codegen for this is pretty bad: #include <vector> void shrink(std::vector<int>& v, unsigned n) { v.resize(v.size() - n); } _Z6shrinkRSt6vectorIiSaIiEEj: .LFB865: .cfi_startproc movq 8(%rdi), %rdx movq (%rdi), %rcx movl %esi, %esi movq %rdx, %rax subq %rcx, %rax sarq $2, %rax movq %rax, %r8 subq %rsi, %r8 jb .L3 cmpq %rax, %r8 jnb .L1 leaq (%rcx,%r8,4), %rax cmpq %rax, %rdx je .L1 movq %rax, 8(%rdi) .L1: ret .L3: pushq %rax .cfi_def_cfa_offset 16 movl $.LC0, %edi call _ZSt20__throw_length_errorPKc .cfi_endproc Telling the compiler that v.size() - n doesn't wrap doesn't help at all: #include <vector> void shrink(std::vector<int>& v, unsigned n) { if (v.size() < n) __builtin_unreachable(); v.resize(v.size() - n); } Why do we still have the call to __throw_length_error() there? It's unreachable, because we're only shrinking, not growing. This is better: void shrink_pop(std::vector<int>& v, unsigned n) { while (n--) v.pop_back(); } _Z10shrink_popRSt6vectorIiSaIiEEj: .LFB866: .cfi_startproc testl %esi, %esi je .L10 movq 8(%rdi), %rax movl %esi, %esi negq %rsi leaq (%rax,%rsi,4), %rdx .p2align 4,,10 .p2align 3 .L12: subq $4, %rax movq %rax, 8(%rdi) cmpq %rax, %rdx jne .L12 .L10: ret .cfi_endproc And this: void shrink_min(std::vector<int>& v, unsigned n) { v.resize(std::min<std::size_t>(v.size(), n)); } _Z10shrink_minRSt6vectorIiSaIiEEj: .LFB867: .cfi_startproc movq 8(%rdi), %rdx movq (%rdi), %rcx movl %esi, %esi movq %rdx, %rax subq %rcx, %rax sarq $2, %rax cmpq %rax, %rsi jb .L54 .L52: ret .p2align 4,,10 .p2align 3 .L54: leaq (%rcx,%rsi,4), %rax cmpq %rax, %rdx je .L52 movq %rax, 8(%rdi) ret .cfi_endproc