Em 32 bits, tínhamos 8 registradores de "uso geral". Com 64 bits, a quantidade dobra, mas parece independente da própria mudança de 64 bits.
Agora, se os registradores são tão rápidos (sem acesso à memória), por que não existem mais naturalmente? Os construtores de CPU não deveriam trabalhar tantos registros quanto possível na CPU? Qual é a restrição lógica para a razão de termos apenas a quantia que temos?
88
Respostas:
Há muitos motivos pelos quais você não tem apenas um grande número de registros:
Atualmente, temos muitos registradores - eles apenas não estão programados explicitamente. Temos "renomeação de registro". Enquanto você acessa apenas um pequeno conjunto (8-32 registradores), eles na verdade são apoiados por um conjunto muito maior (por exemplo, 64-256). A CPU então rastreia a visibilidade de cada registro e os aloca para o conjunto renomeado. Por exemplo, você pode carregar, modificar e, em seguida, armazenar em um registro muitas vezes seguidas e ter cada uma dessas operações realmente executada de forma independente, dependendo das falhas de cache etc. No ARM:
Os núcleos do Cortex A9 registram a renomeação, então a primeira carga para "r0" na verdade vai para um registro virtual renomeado - vamos chamá-lo de "v0". O carregamento, incremento e armazenamento acontecem na "v0". Enquanto isso, também executamos um carregamento / modificação / armazenamento em r0 novamente, mas isso será renomeado para "v1" porque esta é uma sequência totalmente independente usando r0. Digamos que a carga do ponteiro em "r4" parou devido a uma falha no cache. Tudo bem - não precisamos esperar que "r0" esteja pronto. Por ser renomeado, podemos executar a próxima sequência com "v1" (também mapeado para r0) - e talvez seja um acerto de cache e acabamos de ter uma grande vitória de desempenho.
Eu acho que o x86 é até um número gigantesco de registros renomeados atualmente (estimativa 256). Isso significaria ter 8 bits vezes 2 para cada instrução apenas para dizer qual é a origem e o destino. Isso aumentaria enormemente o número de fios necessários ao longo do núcleo e seu tamanho. Portanto, há um ponto ideal em torno de 16-32 registradores que a maioria dos designers se conformaram, e para designs de CPU fora de ordem, a renomeação de registradores é a maneira de mitigar isso.
Editar : A importância da execução fora de ordem e renomeação de registro neste. Depois de ter OOO, o número de registros não importa muito, porque eles são apenas "marcas temporárias" e são renomeados para o conjunto de registros virtuais muito maior. Você não quer que o número seja muito pequeno, porque fica difícil escrever pequenas sequências de código. Este é um problema para x86-32, porque os 8 registros limitados significam que muitos temporários acabam passando pela pilha, e o núcleo precisa de lógica extra para encaminhar leituras / gravações para a memória. Se você não tem OOO, geralmente está falando de um núcleo pequeno; nesse caso, um grande conjunto de registros é um benefício de baixo custo / desempenho.
Portanto, há um ponto ideal natural para o tamanho do banco de registradores que atinge o máximo em cerca de 32 registradores arquitetados para a maioria das classes de CPU. x86-32 tem 8 registros e é definitivamente muito pequeno. ARM foi com 16 registros e é um bom compromisso. 32 registros é um pouco demais - você acaba não precisando dos últimos 10 ou mais.
Nada disso afeta os registros extras que você obtém para SSE e outros coprocessadores de ponto flutuante vetorial. Eles fazem sentido como um conjunto extra porque são executados independentemente do núcleo inteiro e não aumentam a complexidade da CPU exponencialmente.
fonte
Nós Não ter mais deles
Como quase todas as instruções devem selecionar 1, 2 ou 3 registros arquitetonicamente visíveis, expandir o número deles aumentaria o tamanho do código em vários bits em cada instrução e, assim, reduziria a densidade do código. Também aumenta a quantidade de contexto que deve ser salvo como estado de thread e parcialmente salvo no registro de ativação de uma função . Essas operações ocorrem com freqüência. Os intertravamentos do pipeline devem verificar um placar para cada registro e isso tem tempo quadrático e complexidade espacial. E talvez o maior motivo seja simplesmente a compatibilidade com o conjunto de instruções já definido.
Mas acontece que, graças à renomeação de registros , realmente temos muitos registros disponíveis e nem mesmo precisamos salvá-los. A CPU, na verdade, possui muitos conjuntos de registros e alterna automaticamente entre eles conforme o código é executado. Ele faz isso apenas para obter mais registros.
Exemplo:
Em uma arquitetura que tem apenas r0-r7, o código a seguir pode ser reescrito automaticamente pela CPU como algo como:
Nesse caso, r10 é um registro oculto que é substituído por r1 temporariamente. A CPU pode dizer que o valor de r1 nunca é usado novamente após o primeiro armazenamento. Isso permite que o primeiro carregamento seja atrasado (mesmo um acerto de cache no chip geralmente leva vários ciclos) sem exigir o atraso do segundo carregamento ou do segundo armazenamento.
fonte
Eles adicionam registros o tempo todo, mas geralmente estão vinculados a instruções para fins especiais (por exemplo, SIMD, SSE2, etc.) ou exigem a compilação para uma arquitetura de CPU específica, o que diminui a portabilidade. As instruções existentes geralmente funcionam em registros específicos e não poderiam tirar proveito de outros registros se eles estivessem disponíveis. Conjunto de instruções legado e tudo.
fonte
Para adicionar informações interessantes aqui, você notará que ter 8 registradores do mesmo tamanho permite que os opcodes mantenham consistência com a notação hexadecimal. Por exemplo, a instrução
push ax
é opcode 0x50 em x86 e vai até 0x57 para o último registro di. Em seguida, a instruçãopop ax
começa em 0x58 e vai até 0x5Fpop di
para completar a primeira base-16. A consistência hexadecimal é mantida com 8 registros por tamanho.fonte