Por que a Intel oculta o núcleo RISC interno em seus processadores?

90

Começando com o Pentium Pro (microarquitetura P6), a Intel redesenhou seus microprocessadores e usou o núcleo RISC interno de acordo com as antigas instruções CISC. Desde o Pentium Pro, todas as instruções CISC são divididas em partes menores (uops) e depois executadas pelo núcleo RISC.

No início, ficou claro para mim que a Intel decidiu ocultar uma nova arquitetura interna e forçar os programadores a usar o "shell CISC". Graças a esta decisão, a Intel pode redesenhar totalmente a arquitetura dos microprocessadores sem quebrar a compatibilidade, é razoável.

No entanto, eu não entendo uma coisa, por que a Intel ainda mantém um conjunto de instruções RISC interno escondido por tantos anos? Por que eles não permitem que os programadores usem instruções RISC como o antigo conjunto de instruções CISC x86?

Se a Intel mantém a compatibilidade com versões anteriores por tanto tempo (ainda temos o modo 8086 virtual próximo ao modo de 64 bits), por que eles não nos permitem compilar programas para que eles ignorem as instruções CISC e usem o núcleo RISC diretamente? Isso abrirá um caminho natural para abandonar lentamente o conjunto de instruções x86, que está obsoleto hoje em dia (esta é a principal razão pela qual a Intel decidiu usar o núcleo RISC dentro, certo?).

Olhando para a nova série Intel 'Core i', vejo que eles apenas estendem o conjunto de instruções CISC adicionando AVX, SSE4 e outros.

Pateta
fonte
1
observe que existem certas CPUs x86 onde o conjunto de instruções RISC interno é exposto
phuclv

Respostas:

93

Não, o conjunto de instruções x86 certamente não está obsoleto. É tão popular como sempre. O motivo pelo qual a Intel usa um conjunto de microinstruções semelhantes a RISC internamente é porque eles podem ser processados ​​com mais eficiência.

Portanto, uma CPU x86 funciona tendo um decodificador bem pesado no front-end, que aceita instruções x86 e as converte em um formato interno otimizado, que o back-end pode processar.

Quanto à exposição desse formato a programas "externos", existem dois pontos:

  • não é um formato estável. A Intel pode alterá-lo entre os modelos de CPU para melhor se adequar à arquitetura específica. Isso permite que eles maximizem a eficiência e essa vantagem seria perdida se eles tivessem que se estabelecer em um formato de instrução fixo e estável para uso interno e externo.
  • simplesmente não há nada a ganhar fazendo isso. Com as enormes e complexas CPUs de hoje, o decodificador é uma parte relativamente pequena da CPU. Ter que decodificar instruções x86 torna isso mais complexo, mas o resto da CPU não é afetado, então, no geral, há muito pouco a ser ganho, especialmente porque o frontend x86 ainda teria que estar lá, a fim de executar o código "legado" . Portanto, você nem mesmo salvaria os transistores usados ​​atualmente no frontend x86.

Este não é um arranjo exatamente perfeito, mas o custo é bastante pequeno e é uma escolha muito melhor do que projetar a CPU para suportar dois conjuntos de instruções completamente diferentes. (Nesse caso, eles provavelmente acabariam inventando um terceiro conjunto de micro-operações para uso interno, só porque eles podem ser ajustados livremente para melhor se adequar à arquitetura interna da CPU)

Jalf
fonte
1
Bons pontos. RISC é uma boa arquitetura central, onde GOOD significa execução rápida e possível de implementar corretamente, e x86 ISA, que tem uma história arquitetônica CISC, é apenas agora, um layout de conjunto de instruções com uma enorme história e fabulosa riqueza de software binário disponível para ele , além de ser eficiente para armazenamento e processamento. Não é um shell CISC, é o ISA padrão de fato da indústria.
Warren P
2
@ Warren: na última parte, acho que não. Um conjunto de instruções CISC bem projetado é mais eficiente em termos de armazenamento, sim, mas a partir dos poucos testes que vi, a instrução x86 "média" tem cerca de 4,3 bytes de largura, o que é mais do que normalmente seria uma arquitetura RISC. O x86 perde muita eficiência de armazenamento porque foi projetado e ampliado de maneira tão aleatória ao longo dos anos. Mas como você disse, seu principal ponto forte é a história e a enorme quantidade de código binário existente.
jalf
1
Eu não disse que era "CISC bem projetado", apenas "história enorme". As peças BOAS são as peças de design do chip RISC.
Warren P
2
@jalf - Da inspeção dos binários reais, o tamanho da instrução no x86 é de cerca de 3 bytes cada, em média. Existem instruções muito mais longas, é claro, mas as menores tendem a dominar o uso real.
srking
1
O comprimento médio da instrução não é uma boa medida da densidade do código: o tipo mais comum de instrução x86 no código típico é carregar e armazenar (apenas movendo os dados para onde eles podem ser processados ​​e de volta para a memória, os processadores RISC e cerca de ½ do CISC têm muitos registradores, então não é necessário fazer tanto. Também quanto uma instrução pode fazer (instruções de armar podem fazer cerca de 3 coisas).
ctrl-alt-delor
20

A verdadeira resposta é simples.

O principal fator por trás da implementação dos processadores RISC foi reduzir a complexidade e ganhar velocidade. A desvantagem do RISC é a densidade de instrução reduzida, o que significa que o mesmo código expresso em formato semelhante ao RISC precisa de mais instruções do que o código CISC equivalente.

Este efeito colateral não significa muito se sua CPU funcionar na mesma velocidade que a memória, ou pelo menos se ambos rodarem em velocidades razoavelmente semelhantes.

Atualmente a velocidade da memória em comparação com a velocidade do CPU mostra uma grande diferença nos clocks. As CPUs atuais às vezes são cinco vezes ou mais mais rápidas do que a memória principal.

Esse estado da tecnologia favorece um código mais denso, algo que o CISC oferece.

Você pode argumentar que os caches podem acelerar CPUs RISC. Mas o mesmo pode ser dito sobre cpus CISC.

Você obtém uma melhoria de velocidade maior usando CISC e caches do que RISC e caches, porque o mesmo tamanho de cache tem mais efeito no código de alta densidade que o CISC fornece.

Outro efeito colateral é que o RISC é mais difícil na implementação do compilador. É mais fácil otimizar compiladores para cpus CISC. etc.

A Intel sabe o que está fazendo.

Isso é tão verdade que o ARM tem um modo de densidade de código mais alto chamado Thumb.

Jorge Aldo
fonte
1
Além disso, um núcleo RISC interno reduz a contagem de transistores em uma CPU CISC. Em vez de conectar todas as instruções CISC, você pode usar o microcódigo para executá-las. Isso leva à reutilização das instruções do microcódigo RISC para diferentes instruções CISC, portanto, usando menos área do molde.
Sil
16

Se a Intel mantém a compatibilidade com versões anteriores por tanto tempo (ainda temos o modo 8086 virtual próximo ao modo de 64 bits), por que eles não nos permitem compilar programas para que ignorem as instruções CISC e usem o núcleo RISC diretamente? Isso abrirá um caminho natural para abandonar lentamente o conjunto de instruções x86, que está obsoleto hoje em dia (esta é a principal razão pela qual a Intel decidiu usar o núcleo RISC dentro, certo?).

Você precisa olhar para o ângulo de negócios disso. A Intel, na verdade, tentou deixar o x86, mas é a galinha dos ovos de ouro para a empresa. O XScale e o Itanium nunca chegaram nem perto do nível de sucesso que seu principal negócio x86 tem.

O que você está basicamente pedindo é que a Intel corte seus pulsos em troca de fuzzies calorosos dos desenvolvedores. Minar o x86 não é do interesse deles. Qualquer coisa que faça com que mais desenvolvedores não tenham que escolher como alvo o x86 prejudica o x86. Isso, por sua vez, os enfraquece.

Mike Thomsen
fonte
6
Sim, quando a Intel tentou fazer isso (Itanium), o mercado simplesmente respondeu com um encolher de ombros.
Warren P
Deve-se observar que houve uma variedade de fatores durante a falha do Itanium, e não apenas porque era uma nova arquitetura. Por exemplo, descarregar o agendamento da CPU para um compilador que nunca atingiu seu objetivo. Se o Itanium fosse 10x ou 100x mais rápido do que CPUs x86, ele teria vendido como bolos quentes. Mas não foi mais rápido.
Katastic Voyage
5

A resposta é simples. A Intel não está desenvolvendo CPUs para desenvolvedores ! Eles estão desenvolvendo-os para as pessoas que fazem a compra decisões de , o que, aliás, é o que todas as empresas no mundo fazem!

A Intel há muito tempo se comprometeu a que, (dentro do razoável, é claro), suas CPUs permaneceriam compatíveis com as versões anteriores. As pessoas querem saber que, quando compram um novo computador baseado em Intel, tudo seus softwares atuais rodarão exatamente da mesma forma que em seus computadores antigos. (Embora, esperançosamente, mais rápido!)

Além disso, a Intel sabe exatamente o quão importante é esse compromisso, porque uma vez eles tentaram seguir um caminho diferente. Exatamente quantas pessoas você conhece com uma CPU Itanium?!?

Você pode não gostar, mas aquela decisão, de ficar com o x86, é o que tornou a Intel um dos nomes de negócios mais reconhecidos do mundo!

geo
fonte
2
Não concordo com a insinuação de que os processadores Intel não são amigáveis ​​ao desenvolvedor. Tendo programado PowerPC e x86 por muitos anos, passei a acreditar que o CISC é muito mais amigável ao programador. (Eu trabalho para a Intel agora, mas me decidi sobre esse assunto antes de ser contratado.)
Jeff Hammond
1
@Jeff Essa não foi minha intenção! A questão era: por que a Intel não abriu o conjunto de instruções RISC para que os desenvolvedores possam usá-lo. Eu não disse nada sobre o x86 não ser amigável ao desenvolvedor. O que eu disse foi que decisões como essa não foram decididas com os desenvolvedores em mente , mas sim decisões estritamente de negócios.
geo
5

A resposta de @jalf cobre a maioria dos motivos, mas há um detalhe interessante que ele não menciona: o núcleo interno semelhante ao RISC não foi projetado para executar um conjunto de instruções como ARM / PPC / MIPS. O imposto x86 não é pago apenas nos decodificadores que consomem muita energia, mas até certo ponto em todo o núcleo. ou seja, não é apenas a codificação da instrução x86; é cada instrução com uma semântica estranha.

Vamos fingir que a Intel criou um modo operacional em que o fluxo de instruções era diferente de x86, com instruções mapeadas mais diretamente para uops. Vamos também fingir que cada modelo de CPU tem seu próprio ISA para este modo, então eles ainda estão livres para alterar os internos quando quiserem e expô-los com uma quantidade mínima de transistores para decodificação de instruções deste formato alternativo.

Presumivelmente, você ainda teria apenas o mesmo número de registros, mapeados para o estado arquitetônico x86, de modo que os sistemas operacionais x86 podem salvá-lo / restaurá-lo em alternâncias de contexto sem usar o conjunto de instruções específico da CPU. Mas se descartarmos essa limitação prática, sim, poderíamos ter mais alguns registros porque podemos usar os registros temporários ocultos normalmente reservados para o microcódigo 1 .


Se apenas tivermos decodificadores alternativos sem alterações nos estágios posteriores do pipeline (unidades de execução), este ISA ainda terá muitas excentricidades x86. Não seria uma arquitetura RISC muito boa. Nenhuma instrução seria muito complexa, mas algumas das outras loucuras do x86 ainda estariam lá.

Por exemplo: os deslocamentos para a esquerda / direita deixam o sinalizador de estouro indefinido, a menos que a contagem de deslocamento seja um, caso em que OF = a detecção usual de estouro com sinal. Loucura semelhante para gira. No entanto, as instruções RISC expostas podem fornecer mudanças sem sinalizador e assim por diante (permitindo o uso de apenas um ou dois dos vários uops que geralmente entram em algumas instruções x86 complexas). Portanto, isso realmente não se sustenta como o principal contra-argumento.

Se você for fazer um decodificador totalmente novo para um ISA RISC, poderá fazer com que ele selecione partes das instruções x86 para serem expostas como instruções RISC. Isso atenua um pouco a especialização x86 do núcleo.


A codificação da instrução provavelmente não seria de tamanho fixo, uma vez que uops individuais podem conter muitos dados. Muito mais dados do que faz sentido se todos os insns forem do mesmo tamanho. Um único uop micro-fundido pode adicionar um operando imediato de 32 bits e um operando de memória que usa um modo de endereçamento com 2 registradores e um deslocamento de 32 bits. (No SnB e posterior, apenas os modos de endereçamento de registro único podem microfundir com operações de ALU).

uops são muito grandes e não muito semelhantes às instruções ARM de largura fixa. Um conjunto de instruções de 32 bits de largura fixa só pode carregar imediatos de 16 bits por vez, portanto, o carregamento de um endereço de 32 bits requer um par de carga imediata baixa-metade / carga alta-imediata. O x86 não precisa fazer isso, o que o ajuda a não ser terrível, com apenas 15 registros GP limitando a capacidade de manter constantes nos registros. (15 é uma grande ajuda sobre 7 registros, mas dobrar novamente para 31 ajuda muito menos, eu acho que alguma simulação encontrada. RSP geralmente não é de uso geral, então é mais como 15 registros GP e uma pilha.)


TL; Resumo DR:

De qualquer forma, essa resposta se resume a "o conjunto de instruções x86 é provavelmente a melhor maneira de programar uma CPU que deve ser capaz de executar instruções x86 rapidamente", mas espero que esclareça as razões.


Formatos uop internos no front-end vs. back-end

Veja também Micro fusão e modos de endereçamento para um caso de diferenças no que os formatos uop front-end vs. back-end podem representar nas CPUs Intel.

Nota de rodapé 1 : Existem alguns registros "ocultos" para uso como temporários por microcódigo. Esses registradores são renomeados da mesma forma que os registradores de arquitetura x86, de modo que as instruções multi-uop podem ser executadas fora de ordem.

por exemplo, xchg eax, ecxem CPUs da Intel decodifica como 3 uops ( por quê? ), e nosso melhor palpite é que esses uops do tipo MOV o fazem tmp = eax; ecx=eax ; eax=tmp;. Nessa ordem, porque eu meço a latência da direção dst-> src em ~ 1 ciclo, vs. 2 para o outro lado. E esses movimentos não são normaismov instruções ; eles não parecem ser candidatos para eliminação de movimento de latência zero.

Veja também http://blog.stuffedcow.net/2013/05/measuring-rob-capacity/ para uma menção de tentar medir experimentalmente o tamanho do PRF e ter que levar em conta os registros físicos usados ​​para manter o estado arquitetônico, incluindo registros ocultos.

No front-end após os decodificadores, mas antes do estágio de emissão / renomeação que renomeia os registros no arquivo de registro físico, o formato uop interno usa números de registro semelhantes aos números de registro x86, mas com espaço para lidar com esses registros ocultos.

O formato uop é um pouco diferente dentro do núcleo fora de ordem (ROB e RS), também conhecido como back-end (após o estágio de emissão / renomeação). Cada um dos arquivos de registro físico int / FP tem 168 entradas em Haswell , então cada campo de registro em um uop precisa ser largo o suficiente para lidar com esse número.

Como o renomeador está no HW, provavelmente seria melhor usá-lo, em vez de alimentar instruções programadas estaticamente diretamente no back-end. Portanto, trabalharíamos com um conjunto de registros tão grande quanto os registros de arquitetura x86 + temporários de microcódigo, não mais do que isso.

O back-end foi projetado para funcionar com um renomeador de front-end que evita os riscos WAW / WAR, portanto, não poderíamos usá-lo como uma CPU em ordem, mesmo se quiséssemos. Ele não tem intertravamentos para detectar essas dependências; que é tratado por emitir / renomear.

Seria ótimo se pudéssemos alimentar uops no back-end sem o gargalo do estágio de edição / renomeação (o ponto mais estreito nos pipelines modernos da Intel, por exemplo, 4-wide no Skylake vs. 4 ALU + 2 load + 1 store ports em o back-end). Mas se você fez isso, não acho que você pode agendar código estaticamente para evitar a reutilização de registro e pisar em um resultado que ainda é necessário se uma falha de cache paralisar uma carga por um longo tempo.

Portanto, praticamente precisamos alimentar o uops para o estágio de emissão / renomeação, provavelmente ignorando a decodificação, não o cache uop ou IDQ. Então, obtemos exec normal OoO com detecção sã de perigo. A tabela de alocação de registro é projetada apenas para renomear 16 + alguns registros inteiros no PRF inteiro de 168 entradas. Não podemos esperar que o HW renomeie um conjunto maior de registros lógicos no mesmo número de registros físicos; isso exigiria um RAT maior.

Peter Cordes
fonte
-3

Por que eles não nos permitem compilar programas para que eles ignorem as instruções CISC e usem o núcleo RISC diretamente?

Além das respostas anteriores, o outro motivo é a segmentação de mercado. Acredita-se que algumas instruções sejam implementadas em microcódigo em vez de hardware, portanto, permitir que qualquer pessoa execute microoperações arbitrárias pode prejudicar a venda de novos cpus com "novas" instruções CISC de maior desempenho.

KOLANICH
fonte
1
Eu não acho que isso faça sentido. Um RISC pode usar microcódigo, especialmente se estamos falando apenas de adicionar decodificadores RISC a um frontend x86.
Peter Cordes
2
Isso ainda está errado. As novas instruções do AES (e as próximas instruções SHA) e outras coisas como PCLMULQDQ têm hardware dedicado. Em Haswell, AESENC decodifica para um único uop ( agner.org/optimize ), então definitivamente não é microcodificado. (Os decodificadores só precisam ativar o sequenciador de microcódigo ROM para instruções que decodificam para mais de 4 uops .)
Peter Cordes
1
Você está certo ao dizer que algumas novas instruções apenas usam a funcionalidade existente de uma forma que não está disponível com as instruções x86. Um bom exemplo seria BMI2 SHLX , que permite fazer mudanças de contagem variável sem colocar a contagem em CL, e sem incorrer no UOPs extras necessários para lidar com a semântica bandeira x86 de baixa qualidade (bandeiras são não modificada se a contagem de mudança é zero, por isso SHL r/m32, cltem uma dependência de entrada em FLAGS e decodifica para 3 uops no Skylake. No entanto, foi apenas 1 uop no Core2 / Nehalem, de acordo com os testes de Agner Fog.)
Peter Cordes
Obrigado por seus comentários.
KOLANICH