Considere o seguinte código:
void f1(bool ok) {
if (ok) [[likely]] {
// ...
} else [[unlikely]] {
// ...
}
}
void f2(bool ok) {
if (ok) [[likely]] {
// ...
} else {
// ...
}
}
void f3(bool ok) {
if (ok) {
// ...
} else [[unlikely]] {
// ...
}
}
f1
,f2
, e sãof3
equivalentes do ponto de vista do compilador?
Basicamente sim, é redundante, exceto por um caso que o MSVC não lida corretamente. Se você aplicar apenas um dos atributos ao branch true de uma
if
declaração, todos os compiladores funcionam como esperado e não requerem um atributo oposto noelse
branch.Falta de documentação
O padrão C++ em [dcl.attr.likelihood] não fornece nenhuma orientação de uso clara para este caso, nem nenhum dos manuais do compilador.
O Clang tem este exemplo :
Um exemplo em que ambos
[[unlikely]]
e[[likely]]
são usados (de forma não contraditória ou não ignorada) não existe na documentação.O GCC parece não conter nenhuma documentação em Atributos de Declaração e Atributos de Rótulo , mas seria de se esperar que funcionasse de forma semelhante ao Clang.
A documentação do MSVC também é vaga e apenas explica que os atributos são dicas de otimização, mas não diz muito sobre esses casos extremos de uso.
Saída do compilador
Se você inverter
[[likely]]
e[[unlikely]]
no seu código, então é possível obter alguma divergência do compilador paraf3
( https://godbolt.org/z/dffYv1E7r ):O GCC e o Clang são tendenciosos
f = 0
e saltam parat = 0
, mas o MSVC faz o inesperado:Esta saída é tendenciosa para
t = 0
mesmo quef = 0
seja provável. Talvez o bug do MSVC aqui seja que[[likely]]
os[[unlikely]]
atributos emelse
branches são ignorados completamente, e apenas os atributos após a condição da declaração if importam. Eu relatei isso em https://developercommunity.visualstudio.com/t/likely-and-unlikely-attributes-a/10845089Nota: o fato de que o GCC emite um código ligeiramente pior que o Clang e o MSVC no exemplo é um Bug 47253 do GCC conhecido . A saída ainda é equivalente em comportamento ao Clang.