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