¿Cómo han influido los idiomas en el diseño de la CPU? [cerrado]

44

Somos a menudo que al hardware no le importa en qué idioma está escrito un programa, solo ve el código binario compilado, sin embargo esto no es toda la verdad. Por ejemplo, consideremos el humilde Z80; sus extensiones al conjunto de instrucciones 8080 incluyen instrucciones como CPIR, que es útil para escanear cadenas de estilo C (terminadas en NULL), por ejemplo, para realizar strlen() . Los diseñadores deben haber identificado que ejecutar programas en C (a diferencia de Pascal, donde la longitud de una cadena está en el encabezado) era algo para lo que era probable que se usara su diseño. Otro ejemplo clásico es la Lisp Machine .

¿Qué otros ejemplos hay? P.ej. ¿Instrucciones, número y tipo de registros , modos de direccionamiento, que hacen que un procesador particular favorezca las convenciones de un idioma en particular? Estoy particularmente interesado en las revisiones de la misma familia.

    
pregunta Gaius 30.07.2012 - 22:34

15 respuestas

20

Las respuestas existentes se enfocan en los cambios de ISA . También hay otros cambios de hardware. Por ejemplo, C ++ comúnmente usa vtables para llamadas virtuales. Comenzando con el Pentium M , Intel tiene un componente de "predictor de rama indirecta" que acelera las llamadas a funciones virtuales.

    
respondido por el MSalters 31.07.2012 - 14:04
14

El conjunto de instrucciones de Intel 8086 incluye una variación de "ret" que agrega un valor al puntero de la pila después de que muestra la dirección de retorno. Esto es útil para muchas implementaciones de Pascal en las que el llamador de una función insertará argumentos en la pila antes de realizar una llamada de función, y los sacará después. Si una rutina aceptara por ej. El valor de cuatro bytes de parámetros, podría terminar con "RET 0004" para limpiar la pila. En ausencia de tal instrucción, tal convención de llamada probablemente habría requerido que el código extraiga la dirección de retorno a un registro, actualice el puntero de la pila y luego salte a ese registro.

Curiosamente, la mayoría del código (incluidas las rutinas del sistema operativo) en el Macintosh original usaba la convención de llamadas de Pascal a pesar de la falta de una instrucción de facilitación en el 68000. El uso de esta convención de llamadas guardaba de 2 a 4 bytes de código en un sitio de llamadas típico, pero requirió un adicional de 4-6 bytes de código en el sitio de retorno de cada función que tomó parámetros.

    
respondido por el supercat 31.07.2012 - 01:21
10

Un ejemplo es MIPS, que tiene add y addu para atrapar e ignorar el desbordamiento respectivamente. (También sub y subu ). Necesitaba el primer tipo de instrucción para idiomas como Ada (creo, aunque en realidad nunca he usado Ada), que se ocupa de los desbordamientos explícitamente y el segundo tipo para idiomas como C que ignorar los desbordamientos.

Si recuerdo correctamente, la CPU real tiene algunos circuitos adicionales en la ALU para realizar un seguimiento de los desbordamientos. Si el único idioma que le importara a la gente era C, no lo necesitaría.

    
respondido por el Tikhon Jelvis 30.07.2012 - 22:45
8

La serie Burroughs 5000 fue diseñada para soportar de manera eficiente ALGOL, y el iAPX-432 de Intel fue diseñado para ejecutar Ada de manera eficiente. El Inmos Transputer tenía su propio idioma, Occam. Creo que el procesador Parallax "Propeller" fue diseñado para ser programado usando su propia variante de BASIC.

No es un idioma, pero el conjunto de instrucciones VAX-11 tiene una sola instrucción para cargar un contexto de proceso, que se diseñó después de una solicitud del equipo de diseño de VMS. No recuerdo los detalles, pero ISTR tomó tantas instrucciones para implementar que puso un límite superior serio en la cantidad de procesos que podrían programar.

    
respondido por el TMN 30.07.2012 - 22:48
7

Una cosa que nadie parece haber mencionado hasta ahora es que los avances en la optimización del compilador (donde el lenguaje base es en gran medida irrelevante) condujeron al cambio de los conjuntos de instrucciones CISC (que fueron diseñados en gran parte para ser codificados por humanos) a los conjuntos de instrucciones RISC ( que fueron diseñados en gran parte para ser codificados por compiladores.)

    
respondido por el rockets4kids 04.08.2012 - 17:52
5

La familia Motorola 68000 presentó algunos autoincrement adressmode que realizó la copia de datos a través del cpu Muy eficiente y compacto.

[Ejemplo actualizado]

este fue un código c ++ que influyó en el ensamblador 68000

while(someCondition)
    destination[destinationOffset++] = source[sourceOffset++]

implementado en ensamblador convencional (pseudocódigo, olvidé los comandos del ensamblador 68000)

adressRegister1 = source
adressRegister2 = destination
while(someCondition) {
    move akku,(adressRegister1)
    move (adressRegister2), akku
    increment(adressRegister1, 1)
    increment(adressRegister2, 1)
}

con la nueva dirección de acceso se convirtió en algo similar a

adressRegister1 = source
adressRegister2 = destination
while(someCondition) {
    move akku,(adressRegister1++)
    move (adressRegister2++), akku
}

solo dos instrucciones por bucle en lugar de 4.

    
respondido por el k3b 31.07.2012 - 13:27
5

El mainframe de la serie Z de IBM, es el descendiente de IBM 360 de la década de 1960.

Hubo varias instrucciones que se pusieron específicamente para acelerar los programas COBOL y Fortran. El ejemplo clásico es el BXLE - "Rama en el índice bajo o igual", que es la mayoría de un bucle Fortran for o un COBOL PERFORM VARYING x from 1 by 1 until x > n encapsulado en una sola instrucción.

También hay toda una familia de instrucciones decimales empaquetadas para admitir la aritmética decimal de punto fijo común en los programas COBOL.

    
respondido por el James Anderson 31.07.2012 - 08:23
3

Las primeras CPU de Intel tenían las siguientes características, muchas de ellas ahora obsoletas en modo de 64 bits:

  • instrucciones ENTER, LEAVE y RET nn [manuales tempranos explicados explícitamente que se introdujeron para lenguajes estructurados en bloques, por ejemplo, Pascal, que admite procedimientos anidados]
  • instrucciones para acelerar la aritmética BCD (AAA, AAM, etc.); también soporte BCD en x87
  • Instrucciones de JCXZ y LOOP para implementar bucles contados
  • INTO, para generar una trampa en el desbordamiento aritmético (por ejemplo, en Ada)
  • XLAT para búsquedas de tablas
  • LIMITADO para verificar los límites de la matriz

El indicador de signo, que se encuentra en el registro de estado de muchas CPU, existe para realizar fácilmente la aritmética firmada y sin firmar.

El conjunto de instrucciones

SSE 4.1 presenta instrucciones para el procesamiento de cadenas, tanto contadas como terminadas en cero (PCMPESTR, etc.)

Además, puedo imaginar que se diseñaron varias funciones de nivel de sistema para admitir seguridad del código compilado (verificación de límite de segmento, puertas de llamadas con copia de parámetros, etc.)

    
respondido por el zvrba 01.08.2012 - 17:41
3

Algunos procesadores ARM, principalmente aquellos en dispositivos móviles, incluyen (d) la extensión Jazelle, que es un intérprete de JVM de hardware; Se interpreta directamente el código de bytes de Java. La JVM compatible con Jazelle puede usar el hardware para acelerar la ejecución y eliminar gran parte de JIT, pero el respaldo al software VM todavía está asegurado si el código de bytes no se puede interpretar en un chip.

Los procesadores con dicha unidad incluyen la instrucción BXJ, que coloca al procesador en el "modo Jazelle" especial o, si la activación de la unidad ha fallado, se interpreta como una instrucción de derivación normal. La unidad reutiliza los registros ARM para mantener el estado JVM.

El sucesor de la tecnología Jazelle es ThumbEE

    
respondido por el usoban 05.08.2012 - 10:23
2

Por lo que sé, esto era más común en el pasado.

Hay una sesión de preguntas en la que James Gosling dijo que había personas que intentaban hacer hardware eso podría lidiar mejor con el código de bytes JVM, pero entonces estas personas encontrarían una manera de hacerlo con la inteligencia "genérica" común x86 (tal vez compilando el código de bytes de alguna manera inteligente).

Mencionó que hay una ventaja en el uso del chip genérico popular (como el de Intel) porque tiene una gran corporación que arroja enormes sumas de dinero al producto.

Vale la pena ver el video. Habla de esto en el minuto 19 o 20.

    
respondido por el Pedro Henrique A. Oliveira 02.08.2012 - 21:36
2

Hice una búsqueda rápida en la página y parece que nadie ha mencionado los CPU desarrollados específicamente para ejecutar Forth . El lenguaje de programación de Forth se basa en la pila, es compacto y se usa en los sistemas de control.

    
respondido por el Paddy3118 09.08.2012 - 08:30
2

La CPU Intel iAPX se diseñó específicamente para los idiomas OO. Sin embargo, no funcionó.

  

El iAPX 432 ( intel Advanced Processor architecture ) fue el primer diseño de microprocesador de 32 bits de Intel, introducido en 1981 como un conjunto de tres circuitos integrados. Fue pensado para ser el diseño principal de Intel para la década de 1980, implementando muchas funciones avanzadas de administración de memoria y multitarea. Por lo tanto, el diseño fue referido como un Micromainframe ...

     

El iAPX 432 fue "diseñado para ser programado completamente en lenguajes de alto nivel" , con Ada es principal y admite programación orientada a objetos y recolección de basura directamente en hardware y microcódigo . El soporte directo para varias estructuras de datos también tenía la intención de permitir que los sistemas operativos modernos para iAPX 432 se implementen usando mucho menos código de programa que para los procesadores ordinarios. Estas propiedades y características dieron como resultado un diseño de hardware y microcódigo que era mucho más complejo que la mayoría de los procesadores de la era, especialmente los microprocesadores.

     

Utilizando la tecnología de semiconductores de su época, los ingenieros de Intel no pudieron traducir el diseño en una primera implementación muy eficiente. Junto con la falta de optimización en un compilador de Ada prematuro, esto contribuyó a que los sistemas informáticos fueran bastante lentos pero caros, y llevaran a cabo comparaciones típicas en aproximadamente 1/4 de la velocidad del nuevo chip 80286 en la misma frecuencia de reloj (a principios de 1982). p>      

Esta brecha de rendimiento inicial en el perfil bastante bajo y la línea 8086 de bajo precio fue probablemente la razón principal por la que el plan de Intel para reemplazar este último (más tarde conocido como x86) con el iAPX 432 falló. Aunque los ingenieros vieron formas de mejorar el diseño de la próxima generación, la arquitectura de capacidades de iAPX 432 había comenzado a considerarse más como una sobrecarga de implementación en lugar de un soporte de simplificación que se pretendía que fuera.

     

El proyecto iAPX 432 fue un error comercial para Intel ...

    
respondido por el just-passing-by 05.08.2012 - 05:29
1

El 68000 tenía MOVEM que era más adecuado para insertar múltiples registros en la pila en una sola instrucción que es lo que muchos idiomas esperaban.

Si vio MOVEM (MOVE Multiple) que precede a JSR (Jump SubRoutine) en todo el código, entonces en general sabía que estaba tratando con el código que cumple con C.

MOVEM permitió el incremento automático del registro de destino permitiendo que cada uso continúe apilando en el destino, o eliminando de la pila en el caso de decremento automático.

enlace

    
respondido por el Myztry 04.08.2012 - 19:09
1

La arquitectura AVR de Atmel está totalmente diseñada desde el principio para que sea adecuada para la programación en C. Por ejemplo, esta nota de la aplicación elabora más.

En la OMI, esto está estrechamente relacionado con la excelente respuesta , y los primeros PIC16-s se están desarrollando para uso directo. Programación de ensambladores (40 instrucciones en total), con familias posteriores dirigidas a C.

    
respondido por el Vorac 27.09.2013 - 10:46
1

Cuando se diseñó el coprocesador numérico 8087, era bastante común que los idiomas realizaran todos los cálculos de punto flotante utilizando el tipo de mayor precisión, y solo redondeaban el resultado a una precisión más baja al asignarlo a una variable de menor precisión. En el estándar C original, por ejemplo, la secuencia:

float a = 16777216, b = 0.125, c = -16777216;
float d = a+b+c;

promovería a y b a double , agregarlos, promover c a double , agregarlo y luego almacenar el resultado redondeado a float . Aunque en muchos casos hubiera sido más rápido para un compilador generar código que realizaría operaciones directamente en el tipo float , era más simple tener un conjunto de rutinas de punto flotante que operaría solo en el tipo double , junto con con rutinas para convertir a / desde float , que tener conjuntos separados de rutinas para manejar operaciones en float y double . El 8087 se diseñó alrededor de esa aproximación a la aritmética, realizando todas las operaciones aritméticas utilizando un tipo de punto flotante de 80 bits [probablemente se eligió 80 bits porque:

  1. En muchos procesadores de 16 y 32 bits, es más rápido trabajar con una mantisa de 64 bits y un exponente separado que trabajar con un valor que divide un byte entre la mantisa y el exponente.

  2. Es muy difícil realizar cálculos que sean precisos con la precisión total de los tipos numéricos que se utilizan; si uno está tratando de, por ejemplo, calcular algo como log10 (x), es más fácil y más rápido calcular un resultado que es preciso dentro de 100 pulg de un tipo de 80 bits que calcular un resultado que es preciso dentro de 1 pulso de un tipo de 64 bits, y redondeando el anterior el resultado a una precisión de 64 bits producirá un valor de 64 bits que es más preciso que el último.

Lamentablemente, las versiones futuras del lenguaje cambiaron la semántica de cómo deberían funcionar los tipos de punto flotante; mientras que la semántica 8087 hubiera sido muy agradable si los lenguajes los hubieran apoyado de manera consistente, si las funciones f1 (), f2 (), etc. devolvieran el tipo float , muchos autores del compilador se encargarían de hacer de long double un alias el tipo doble de 64 bits en lugar del tipo de 80 bits del compilador (y no proporciona ningún otro medio para crear variables de 80 bits), y para evaluar arbitrariamente algo como:

double f = f1()*f2() - f3()*f4();

de cualquiera de las siguientes maneras:

double f = (float)(f1()*f2()) - (extended_double)f3()*f4();
double f = (extended_double)f1()*f2() - (float)(f3()*f4());
double f = (float)(f1()*f2()) - (float)(f3()*f4());
double f = (extended_double)f1()*f2() - (extended_double)f3()*f4();

Tenga en cuenta que si f3 y f4 devuelven los mismos valores que f1 y f2, respectivamente, la expresión original debería devolver cero, pero muchas de las últimas expresiones pueden no hacerlo. Esto condujo a la gente a condenar la "precisión extra" del 8087, aunque la última formulación generalmente sería superior a la tercera y, con el código que usaba el tipo doble extendido, rara vez sería inferior.

En los años intermedios, Intel ha respondido a la tendencia del lenguaje (IMHO desafortunado) de forzar los resultados intermedios para redondearlos a la precisión de los operandos mediante el diseño de sus procesadores posteriores para favorecer ese comportamiento, en detrimento del código que beneficiaría de usar una mayor precisión en cálculos intermedios.

    
respondido por el supercat 03.11.2014 - 20:17

Lea otras preguntas en las etiquetas