¿Por qué Intel oculta el núcleo RISC interno en sus procesadores?

89

Comenzando con Pentium Pro (microarquitectura P6), Intel rediseñó sus microprocesadores y usó el núcleo RISC interno bajo las antiguas instrucciones CISC. Desde Pentium Pro, todas las instrucciones CISC se dividen en partes más pequeñas (uops) y luego las ejecuta el núcleo RISC.

Al principio, me quedó claro que Intel decidió ocultar la nueva arquitectura interna y obligar a los programadores a utilizar "shell CISC". Gracias a esta decisión, Intel pudo rediseñar completamente la arquitectura de microprocesadores sin romper la compatibilidad, es razonable.

Sin embargo, no entiendo una cosa, ¿por qué Intel todavía mantiene ocultas las instrucciones RISC internas durante tantos años? ¿Por qué no dejarían que los programadores usen instrucciones RISC como el antiguo conjunto de instrucciones CISC x86?

Si Intel mantiene la compatibilidad con versiones anteriores durante tanto tiempo (todavía tenemos el modo 8086 virtual junto al modo de 64 bits), ¿por qué no nos permiten compilar programas para que omitan las instrucciones CISC y usen el núcleo RISC directamente? Esto abrirá una forma natural de abandonar lentamente el conjunto de instrucciones x86, que está en desuso hoy en día (esta es la razón principal por la que Intel decidió usar el núcleo RISC en el interior, ¿verdad?).

Mirando la nueva serie Intel 'Core i', veo que solo extienden el conjunto de instrucciones CISC agregando AVX, SSE4 y otros.

Mentecato
fuente
1
tenga en cuenta que hay ciertas CPU x86 donde se expone el conjunto de instrucciones RISC interno
phuclv

Respuestas:

90

No, el conjunto de instrucciones x86 ciertamente no está en desuso. Es tan popular como siempre. La razón por la que Intel utiliza internamente un conjunto de microinstrucciones similares a RISC es porque pueden procesarse de manera más eficiente.

Entonces, una CPU x86 funciona con un decodificador bastante resistente en la interfaz, que acepta instrucciones x86 y las convierte a un formato interno optimizado, que el backend puede procesar.

En cuanto a exponer este formato a programas "externos", hay dos puntos:

  • no es un formato estable. Intel puede cambiarlo entre modelos de CPU para adaptarse mejor a la arquitectura específica. Esto les permite maximizar la eficiencia, y esta ventaja se perdería si tuvieran que conformarse con un formato de instrucción fijo y estable para uso interno y externo.
  • simplemente no hay nada que ganar haciéndolo. Con las CPU enormes y complejas de hoy, el decodificador es una parte relativamente pequeña de la CPU. Tener que decodificar las instrucciones x86 lo hace más complejo, pero el resto de la CPU no se ve afectado, por lo que, en general, hay muy poco que ganar, especialmente porque la interfaz x86 todavía tendría que estar allí para ejecutar el código "heredado". . Por lo tanto, ni siquiera guardaría los transistores que se usan actualmente en la interfaz x86.

Esta no es una disposición perfecta, pero el costo es bastante pequeño y es una opción mucho mejor que diseñar la CPU para admitir dos conjuntos de instrucciones completamente diferentes. (En ese caso, probablemente terminarían inventando un tercer conjunto de microoperaciones para uso interno, solo porque se pueden ajustar libremente para adaptarse mejor a la arquitectura interna de la CPU)

jalf
fuente
1
Buenos puntos. RISC es una buena arquitectura central, donde BUENO significa que se ejecuta rápido y se puede implementar correctamente, y x86 ISA, que tiene un historial de arquitectura CISC, es simplemente ahora, un diseño de conjunto de instrucciones con una gran historia y una fabulosa riqueza de software binario disponible para él. , además de ser eficiente para el almacenamiento y procesamiento. No es un shell CISC, es el estándar ISA de facto de la industria.
Warren P
2
@Warren: en la última parte, en realidad no lo creo. Un conjunto de instrucciones CISC bien diseñado es más eficiente en términos de almacenamiento, sí, pero según las pocas pruebas que he visto, la instrucción x86 "promedio" tiene algo así como 4,3 bytes de ancho, que es más de lo que normalmente sería en una arquitectura RISC. x86 pierde mucha eficiencia de almacenamiento porque se ha diseñado y ampliado de forma desordenada a lo largo de los años. Pero como dices, su principal fortaleza es la historia y la enorme cantidad de código binario existente.
jalf
1
No dije que fuera "CISC bien diseñado", solo "gran historia". Las BUENAS partes son las partes de diseño del chip RISC.
Warren P
2
@jalf: a partir de la inspección de los binarios reales, el tamaño de la instrucción en x86 es de aproximadamente 3 bytes cada uno en promedio. Por supuesto, hay instrucciones mucho más largas, pero las más pequeñas tienden a dominar en el uso real.
srking
1
La longitud promedio de las instrucciones no es una buena medida de la densidad del código: el tipo más común de instrucción x86 en el código típico es cargar y almacenar (simplemente mover los datos a donde se pueden procesar y volver a la memoria, los procesadores RISC y aproximadamente la mitad de los CISC tienen muchos registros, por lo que no es necesario hacer tanto. Además, ¿cuánto puede hacer una instrucción (las instrucciones de brazo pueden hacer alrededor de 3 cosas).
ctrl-alt-delor
20

La verdadera respuesta es simple.

El factor principal detrás de la implementación de procesadores RISC fue reducir la complejidad y ganar velocidad. La desventaja de RISC es la densidad de instrucción reducida, lo que significa que el mismo código expresado en formato similar a RISC necesita más instrucciones que el código CISC equivalente.

Este efecto secundario no significa mucho si su CPU funciona a la misma velocidad que la memoria, o al menos si ambas funcionan a velocidades razonablemente similares.

Actualmente, la velocidad de la memoria en comparación con la velocidad de la CPU muestra una gran diferencia en los relojes. Las CPU actuales son a veces cinco veces más rápidas que la memoria principal.

Este estado de la tecnología favorece un código más denso, algo que proporciona CISC.

Puede argumentar que los cachés podrían acelerar las CPU RISC. Pero lo mismo puede decirse de los cpus CISC.

Obtiene una mejora de velocidad mayor utilizando CISC y cachés que RISC y cachés, porque el mismo tamaño de caché tiene más efecto en el código de alta densidad que proporciona CISC.

Otro efecto secundario es que RISC es más difícil en la implementación del compilador. Es más fácil optimizar los compiladores para cpus CISC. etc.

Intel sabe lo que están haciendo.

Esto es tan cierto que ARM tiene un modo de densidad de código más alto llamado Thumb.

Jorge Aldo
fuente
1
Además, un núcleo RISC interno reduce la cantidad de transistores en una CPU CISC. En lugar de cablear cada instrucción CISC, puede usar un microcódigo para ejecutarlas. Esto lleva a reutilizar instrucciones de microcódigo RISC para diferentes instrucciones CISC, por lo que se usa menos área de matriz.
Sil
16

Si Intel mantiene la compatibilidad con versiones anteriores durante tanto tiempo (todavía tenemos el modo 8086 virtual junto al modo de 64 bits), ¿por qué no nos permiten compilar programas para que omitan las instrucciones CISC y usen el núcleo RISC directamente? Esto abrirá una forma natural de abandonar lentamente el conjunto de instrucciones x86, que está en desuso hoy en día (esta es la razón principal por la que Intel decidió usar el núcleo RISC en el interior, ¿verdad?).

Necesita mirar el ángulo comercial de esto. Intel realmente ha intentado alejarse de x86, pero es la gallina de los huevos de oro para la empresa. XScale e Itanium nunca se acercaron al nivel de éxito que tiene su negocio principal x86.

Lo que básicamente estás pidiendo es que Intel se corte las venas a cambio de cálidos comentarios de los desarrolladores. Socavar x86 no les conviene. Cualquier cosa que haga que más desarrolladores no tengan que elegir apuntar a x86 socava x86. Eso, a su vez, los socava.

Mike Thomsen
fuente
6
Sí, cuando Intel intentó hacer esto (Itanium), el mercado simplemente respondió encogiéndose de hombros.
Warren P
Cabe señalar que hubo una variedad de factores mientras Itanium falló, y no solo porque era una nueva arquitectura. Por ejemplo, descargar la programación de la CPU a un compilador que nunca logró su objetivo. Si el Itanium fuera 10 o 100 veces más rápido que las CPU x86, se habría vendido como pan caliente. Pero no fue más rápido.
Katastic Voyage
5

La respuesta es simple. ¡Intel no está desarrollando CPU para desarrolladores ! Los están desarrollando para las personas que toman las decisiones de compra , lo cual, por cierto, es lo que hacen todas las empresas del mundo.

Intel hace mucho tiempo se comprometió a que, (dentro de lo razonable, por supuesto), sus CPU seguirían siendo compatibles con versiones anteriores. La gente quiere saber que, cuando compran una nueva computadora basada en Intel, todos su software actual funcionará exactamente igual que en su computadora anterior. (¡Aunque, con suerte, más rápido!)

Además, Intel sabe exactamente lo importante que es ese compromiso, porque una vez intentaron tomar un camino diferente. Exactamente cuántas personas no se sabe con una CPU Itanium?!?

Puede que no le guste, pero esa decisión, permanecer con el x86, es lo que convirtió a Intel en uno de los nombres comerciales más reconocidos del mundo.

geo
fuente
2
No estoy de acuerdo con la insinuación de que los procesadores Intel no son aptos para desarrolladores. Habiendo programado PowerPC y x86 durante muchos años, he llegado a creer que CISC es mucho más amigable para los programadores. (Ahora trabajo para Intel, pero tomé una decisión sobre este tema antes de ser contratado.)
Jeff
1
@Jeff ¡Esa no era mi intención en absoluto! La pregunta era, ¿por qué Intel no ha abierto el conjunto de instrucciones RISC para que los desarrolladores puedan usarlo? No dije nada acerca de que x86 no sea compatible con desarrolladores. Lo que dije fue que decisiones como esta no se decidieron teniendo en cuenta a los desarrolladores , sino que fueron estrictamente decisiones comerciales.
geo
5

La respuesta de @ jalf cubre la mayoría de las razones, pero hay un detalle interesante que no menciona: el núcleo interno similar a RISC no está diseñado para ejecutar un conjunto de instrucciones como ARM / PPC / MIPS. El impuesto x86 no solo se paga en los decodificadores que consumen mucha energía, sino hasta cierto punto en todo el núcleo. es decir, no se trata solo de la codificación de instrucciones x86; es cada instrucción con una semántica extraña.

Supongamos que Intel creó un modo de funcionamiento en el que el flujo de instrucciones era diferente a x86, con instrucciones que se asignaban más directamente a uops. Supongamos también que cada modelo de CPU tiene su propio ISA para este modo, por lo que todavía son libres de cambiar los componentes internos cuando lo deseen y exponerlos con una cantidad mínima de transistores para la decodificación de instrucciones de este formato alternativo.

Presumiblemente, todavía tendría la misma cantidad de registros, asignados al estado arquitectónico x86, por lo que los sistemas operativos x86 pueden guardarlo / restaurarlo en cambios de contexto sin usar el conjunto de instrucciones específicas de la CPU. Pero si descartamos esa limitación práctica, sí, podríamos tener algunos registros más porque podemos usar los registros temporales ocultos normalmente reservados para el microcódigo 1 .


Si solo tenemos decodificadores alternativos sin cambios en las etapas posteriores de la canalización (unidades de ejecución), este ISA todavía tendría muchas excentricidades x86. No sería una arquitectura RISC muy agradable. Ninguna instrucción por sí sola sería muy compleja, pero algunas de las otras locuras de x86 seguirían ahí.

Por ejemplo: los cambios a la izquierda / derecha dejan el indicador de desbordamiento sin definir, a menos que el recuento de cambios sea uno, en cuyo caso OF = la detección de desbordamiento con signo habitual. Locura similar para rota. Sin embargo, las instrucciones RISC expuestas podrían proporcionar cambios sin banderas y así sucesivamente (permitiendo el uso de solo uno o dos de los múltiples uops que generalmente se incluyen en algunas instrucciones x86 complejas). Así que esto realmente no se sostiene como el principal contraargumento.

Si va a hacer un decodificador completamente nuevo para un RISC ISA, puede hacer que elija partes de las instrucciones x86 para exponerlas como instrucciones RISC. Esto mitiga un poco la especialización x86 del núcleo.


La codificación de la instrucción probablemente no sea de tamaño fijo, ya que las uops individuales pueden contener una gran cantidad de datos. Muchos más datos de los que tienen sentido si todos los insns son del mismo tamaño. Una sola uop microfundida puede agregar un operando inmediato de 32 bits y un operando de memoria que usa un modo de direccionamiento con 2 registros y un desplazamiento de 32 bits. (En SnB y versiones posteriores, solo los modos de direccionamiento de registro único pueden microfusarse con operaciones ALU).

Los uops son muy grandes y no muy similares a las instrucciones ARM de ancho fijo. Un conjunto de instrucciones de 32 bits de ancho fijo solo puede cargar inmediatos de 16 bits a la vez, por lo que cargar una dirección de 32 bits requiere un par carga-media baja-inmediata / carga alta-inmediata. x86 no tiene que hacer eso, lo que ayuda a que no sea terrible con solo 15 registros GP que limitan la capacidad de mantener constantes en los registros. (15 es una gran ayuda sobre 7 registros, pero duplicar nuevamente a 31 ayuda mucho menos, creo que se encontró algo de simulación. RSP generalmente no es de propósito general, por lo que es más como 15 registros GP y una pila).


TL; resumen de DR:

De todos modos, esta respuesta se reduce a "el conjunto de instrucciones x86 es probablemente la mejor manera de programar una CPU que debe poder ejecutar instrucciones x86 rápidamente", pero es de esperar que arroje algo de luz sobre las razones.


Formatos de uop internos en el front-end frente al back-end

Consulte también los modos de micro fusión y direccionamiento para ver un caso de diferencias en lo que pueden representar los formatos uop de front-end y back-end en las CPU Intel.

Nota al pie 1 : Hay algunos registros "ocultos" para su uso como temporales por microcódigo. Estos registros se renombran al igual que los registros arquitectónicos x86, por lo que las instrucciones multi-uop pueden ejecutarse fuera de orden.

por ejemplo, xchg eax, ecxen las CPU de Intel se decodifica como 3 uops ( ¿por qué? ), y nuestra mejor suposición es que estos son uops tipo MOV que lo hacen tmp = eax; ecx=eax ; eax=tmp;. En ese orden, porque mido la latencia de la dirección dst-> src en ~ 1 ciclo, frente a 2 en el otro sentido. Y estos movimientos no son como movinstrucciones regulares ; no parecen ser candidatos para la eliminación de mov de latencia cero.

Consulte también http://blog.stuffedcow.net/2013/05/measuring-rob-capacity/ para una mención de intentar medir experimentalmente el tamaño de PRF y tener que tener en cuenta los registros físicos utilizados para mantener el estado arquitectónico, incluidos los registros ocultos.

En el front-end después de los decodificadores, pero antes de la etapa de emisión / cambio de nombre que cambia el nombre de los registros al archivo de registro físico, el formato interno uop usa números de registro similares a los números de registro x86, pero con espacio para abordar estos registros ocultos.

El formato uop es algo diferente dentro del núcleo fuera de orden (ROB y RS), también conocido como back-end (después de la etapa de emisión / cambio de nombre). Los archivos de registro físico int / FP tienen cada uno 168 entradas en Haswell , por lo que cada campo de registro en un uop debe ser lo suficientemente amplio para abordar esa cantidad.

Dado que el renombrador está en el HW, probablemente sería mejor usarlo, en lugar de enviar instrucciones programadas estáticamente directamente al back-end. Así que podríamos trabajar con un conjunto de registros tan grande como los registros arquitectónicos x86 + temporales de microcódigo, no más que eso.

El back-end está diseñado para funcionar con un renombrador de front-end que evita los peligros WAW / WAR, por lo que no podríamos usarlo como una CPU en orden incluso si quisiéramos. No tiene enclavamientos para detectar esas dependencias; que se maneja por problema / cambio de nombre.

Sería bueno si pudiéramos alimentar uops en el back-end sin el cuello de botella de la etapa de emisión / cambio de nombre (el punto más estrecho en las tuberías modernas de Intel, por ejemplo, 4 de ancho en Skylake frente a 4 ALU + 2 carga + 1 puertos de almacenamiento en el back-end). Pero si hiciste eso, no creo que puedas programar estáticamente el código para evitar la reutilización de registros y pisar un resultado que aún es necesario si un error de caché detuvo una carga durante mucho tiempo.

Por lo tanto, necesitamos enviar uops a la etapa de emisión / cambio de nombre, probablemente solo omitiendo la decodificación, no el caché de uop o IDQ. Luego obtenemos un ejecutivo de OoO normal con una detección de peligros sensata. La tabla de asignación de registros solo está diseñada para cambiar el nombre de 16 + algunos registros enteros en el PRF entero de 168 entradas. No podíamos esperar que el HW cambiara el nombre de un conjunto mayor de registros lógicos en el mismo número de registros físicos; eso requeriría una RAT más grande.

Peter Cordes
fuente
-3

¿Por qué no nos permiten compilar programas para que omitan las instrucciones CISC y usen el núcleo RISC directamente?

Además de las respuestas anteriores, la otra razón es la segmentación del mercado. Se cree que algunas instrucciones se implementan en microcódigo en lugar de en hardware, por lo que permitir que cualquiera ejecute microoperaciones arbitrarias puede socavar las ventas de nuevos cpus con instrucciones CISC "nuevas" de mayor rendimiento.

KOLANICH
fuente
1
No creo que esto tenga sentido. Un RISC puede usar microcódigo, especialmente si estamos hablando de simplemente agregar decodificadores RISC a un frontend x86.
Peter Cordes
2
Eso sigue mal. Las nuevas instrucciones de AES (y las próximas instrucciones SHA) y otras cosas como PCLMULQDQ tienen hardware dedicado. En Haswell, AESENC decodifica en un solo uop ( agner.org/optimize ), por lo que definitivamente no está microcodificado en absoluto. (Los decodificadores solo necesitan activar el secuenciador de ROM de microcódigo para instrucciones que decodifican a más de 4 uops .)
Peter Cordes
1
Tiene razón en que algunas instrucciones nuevas solo usan la funcionalidad existente de una manera que no está disponible con las instrucciones x86. Un buen ejemplo sería BMI2 SHLX , que le permite hacer cambios de conteo variable sin poner el conteo en CL, y sin incurrir en los uops adicionales necesarios para manejar la semántica de la bandera x86 de mala calidad (las banderas no se modifican si el conteo de turnos es cero, por lo que SHL r/m32, clha una dependencia de entrada en FLAGS y decodifica a 3 uops en Skylake. Sin embargo, solo fue 1 uop en Core2 / Nehalem, según las pruebas de Agner Fog).
Peter Cordes
Gracias por tus comentarios.
KOLANICH