Arquitetura P6 - Deixando de lado a renomeação de registros, os registros de usuários limitados resultam em mais operações gastas em derramamento/carregamento?

StackOverflow https://stackoverflow.com/questions/2460198

Pergunta

Estou estudando design JIT em relação à implementação de VM em linguagens dinâmicas.Não tenho feito muita Assembleia desde os dias 8086/8088, só um pouco aqui ou ali, então seja gentil se eu estiver indisposto.

Pelo que entendi, a arquitetura x86 (IA-32) ainda tem hoje o mesmo conjunto básico de registros limitados de sempre, mas a contagem de registros internos cresceu tremendamente, mas esses registros internos geralmente não estão disponíveis e são usados ​​com renomeação de registros para obter pipeline paralelo de código que de outra forma não poderia ser paralelizado.Eu entendo essa otimização muito bem, mas meu sentimento é que, embora essas otimizações ajudem no rendimento geral e para algoritmos paralelos, o conjunto limitado de registros com o qual ainda estamos presos resulta em mais sobrecarga de registro, de modo que se o x86 tivesse o dobro ou o quádruplo dos registros disponível para nós, pode haver significativamente menos opcodes push/pop em um fluxo de instruções típico?Ou existem outras otimizações de processador que também otimizam isso e que eu não conheço?Basicamente, se eu tiver uma unidade de código que tenha 4 registros para trabalhar com números inteiros, mas minha unidade tiver uma dúzia de variáveis, tenho potencialmente um push/pop para cada 2 ou mais instruções.

Alguma referência a estudos, ou melhor ainda, experiências pessoais?

EDITAR:x86_64 possui 16 registros, que é o dobro do x86-32, obrigado pela correção e informação.

Foi útil?

Solução

Além de renomear registros para ocultar bolhas devido a latências de instruções, a maioria das arquiteturas x86 são inteligentes o suficiente para contar pushes e pops e renomeá-los também em registros.Lembre-se de que o decodificador de instruções no x86 na verdade executa uma espécie de compilação JIT, transformando o fluxo de instruções do x86 em um pequeno programa de microcódigo armazenado no cache de rastreamento.Parte desse processo inclui interceptar cargas de pilha de pequenos deslocamentos e também transformá-las em registros.Assim, algo como (o evidentemente bobo e puramente por exemplo):

lwz eax,[ebp]
lwz ebx,[ebp+4]
add eax,[edx+0]
push eax 
lwz eax,[ebp+8]
add eax,ebx
pop ebx
add eax,ebx

cozinha em algo como (fingir que os registros internos são nomeados por exemplo r0..r16):

lw r3, edx
lw r1, ebp
lw r2, ebp+4 ; the constant '4' is usually stored as an immediate operand
add r1,r2
or r4,r1,r1 ;; move r1 to r4
lw r1, ebp+8
add r1,r2
or r2,r4,r4
add r1,r2

É claro que um decodificador magicamente inteligente (diferente daquele que realmente se encaixa na contagem de transistores) colapsaria alguns dos movimentos desnecessários lá, mas o que quero dizer é que push/pop e armazena/carrega para esp+(some small number) são na verdade transformados em registros de sombra.

Outras dicas

Dois pontos:

(1) x86-64 dobra o número de registros para 16

(2) em CPUs x86 modernas, uma instrução que usa um local de memória que já está no cache L1 é aproximadamente tão rápido quanto a mesma operação com um operando de registro, então você quase pode pensar em L1 como "memória de registro"

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top