Este código c++ é
#include<cmath>
double f1(double a){
return std::cos(a);
}
double f2(double a){
return std::cos(a) + std::sin(a);
}
é compilado no seguinte assembly ( https://godbolt.org/z/Y578h1TKx )
f1(double):
jmp cos
f2(double):
sub rsp, 24
lea rdi, [rsp+8]
mov rsi, rsp
call sincos
movsd xmm0, QWORD PTR [rsp+8]
addsd xmm0, QWORD PTR [rsp]
add rsp, 24
ret
Isso significa que o gcc conhece as funções padrão da glibc e tem técnicas de otimização para casos específicos que as utilizam?
Ao compilar o GCC em si, você especifica um triplo de destino que inclui informações sobre a plataforma e (talvez indiretamente) a implementação da biblioteca padrão C usada no destino para o qual o GCC compilado será compilado.
Por exemplo
x86_64-linux-gnu
, oux86_64-unknown-linux-gnu
é um alvo triplo típico para um alvo que executa Linux em um processador x86-64 com glibc como implementação de biblioteca padrão C.Da mesma forma
x86_64-linux-musl
, oux86_64-unknown-linux-musl
seria um alvo semelhante que usa a implementação da biblioteca padrão musl C.Além disso, há
-m
opções de compilador (por exemplo-mglibc
, ,-mmusl
, ...) para alterar a implementação da biblioteca padrão C de destino assumida.Dessa forma, o GCC sabe se o destino suporta ou não a
sincos
função não padrão e, se suportar, ele pode reescrever chamadas parastd::cos
estd::sin
, que têm semânticas que são sempre conhecidas porque são especificadas pelos padrões C++ e C, para uma chamada parasincos
da maneira que você está vendo.Por exemplo, se você compilar com
-muclibc
para um destino Linux usando a implementação da biblioteca padrão C uclibc, o GCC assumirá que elasincos
não está presente e não reescreverá parasincos
. (Embora eu ache que o uclibc realmente suporta sincos.)Com a configuração padrão (ou seja, sem nenhum sinalizador
-std=c*
ou-ansi
), não há problema em o compilador reescrever para asincos
função não padrão, mesmo quesincos
não seja um nome reservado por nenhum padrão e, portanto, possa ser usado para uma finalidade diferente pelo usuário, porque as opções padrão do GCC assumem extensões GNU (ou seja,-std=gnu++XX
em vez de-std=c++XX
), não conformidade estrita com os padrões.Infelizmente, o GCC ainda realiza essa transformação mesmo em modo de conformidade padrão estrito, onde isso não deveria acontecer. Veja o relatório de bug aqui .