Aqui está um arquivo C simples com uma definição de enumeração e uma main
função:
enum days {MON, TUE, WED, THU};
int main() {
enum days d;
d = WED;
return 0;
}
Transpila para o seguinte LLVM IR:
define dso_local i32 @main() #0 {
%1 = alloca i32, align 4
%2 = alloca i32, align 4
store i32 0, i32* %1, align 4
store i32 2, i32* %2, align 4
ret i32 0
}
%2
é evidentemente a d
variável, que recebe 2 atribuídos a ela. A que %1
corresponde se zero é retornado diretamente?
c
llvm
llvm-codegen
macleginn
fonte
fonte
clang-9 -S -emit-llvm simple.c
main
( godbolt.org/z/kEtS-s ). O link mostra como o assembly é mapeado para a fontemain
, a variável extra misteriosa desaparecerá. Curiosamente, ele também desaparece se você omitirreturn
completamente a declaração (o que é legalmain
em C e equivalente areturn 0;
).main
comoint main(int argc, char **argv)
vêargc
eargv
copia na pilha, mas a variável zero misteriosa ainda está lá além delas.Respostas:
Esse
%1
registro foi gerado pelo clang para manipular várias instruções de retorno em uma função . Imagine que você tivesse uma função para calcular o fatorial de um número inteiro. Em vez de escrever assimVocê provavelmente faria isso
Por quê? Porque Clang irá inserir a
result
variável que contém o valor de retorno para você. Yay. Esse é o propósito exato disso%1
. Veja no ir uma versão ligeiramente modificada do seu código.Código modificado,
IR,
Agora você vê isso
%1
se tornando útil, hein? Como os outros apontaram, para funções com apenas uma instrução de retorno, essa variável provavelmente será removida por um dos passes otimizados do llvm.fonte
Por que isso importa - qual é o problema real?
Eu acho que a resposta mais profunda que você está procurando pode ser: a arquitetura do LLVM é baseada em frontends bastante simples e em muitas passagens. Os frontends precisam gerar o código correto, mas não precisa ser um bom código. Eles podem fazer a coisa mais simples que funciona.
Nesse caso, o Clang gera algumas instruções que acabam não sendo usadas para nada. Isso geralmente não é um problema, porque alguma parte do LLVM se livra de instruções supérfluas. Clang confia que isso aconteça. Clang não precisa evitar emitir código morto; sua implementação pode se concentrar na correção, simplicidade, testabilidade etc.
fonte
Porque o Clang é feito com análise de sintaxe, mas o LLVM nem começou com a otimização.
O front-end do Clang gerou IR (Representação Intermediária) e não código de máquina. Essas variáveis são SSAs (atribuições estáticas únicas); eles ainda não foram vinculados a registros e, na verdade, após a otimização, nunca serão porque são redundantes.
Esse código é uma representação literal da fonte. É o que chama a atenção do LLVM para otimização. Basicamente, o LLVM começa com isso e otimiza a partir daí. De fato, para a versão 10 e x86_64, o llc -O2 acabará gerando:
fonte