Muitas vezes nos dizem que o hardware não se importa em qual idioma o programa está escrito, pois apenas vê o código binário compilado, mas essa não é a verdade. Por exemplo, considere o humilde Z80; suas extensões ao conjunto de instruções 8080 incluem instruções como CPIR, que são úteis para verificar seqüências de caracteres no estilo C (terminação NULL), por exemplo, para executar strlen()
. Os designers devem ter identificado que a execução de programas em C (ao contrário de Pascal, onde o comprimento de uma string está no cabeçalho) era algo para o qual o design provavelmente seria usado. Outro exemplo clássico é o Lisp Machine .
Que outros exemplos existem? Por exemplo, instruções, número e tipo de registros , modos de endereçamento, que fazem um determinado processador favorecer as convenções de um idioma específico? Estou particularmente interessado em revisões da mesma família.
sizeof(int)
seja igual a 1 deve exigir que o tipochar
seja assinado (já que umint
deve poder manter todos os valores do tipochar
). Eu escrevi código para uma máquina ondechar
eint
são números inteiros assinados de 16 bits; as maiores dificuldades são que não se pode usar uniões para conversão de tipos, e o armazenamento eficiente de um grande número de bytes requer empacotamento e descompactação manuais. Essas questões são menores em comparação com a possibilidade em C de que sizeof (int) == sizeof (long), desde que ... #unsigned int
valores. O C99 melhorou essa situação, mas antes do C99 não havia uma maneira segura garantida de comparar um valor potencialmente negativo a um valor do tipounsigned int
(seria necessário testar se o número era negativo antes de fazer a comparação).Respostas:
As respostas existentes se concentram nas mudanças do ISA . Também há outras alterações de hardware. Por exemplo, o C ++ geralmente usa vtables para chamadas virtuais. Começando com o Pentium M , a Intel possui um componente "preditor de ramificação indireta" que acelera as chamadas de função virtual.
fonte
O conjunto de instruções Intel 8086 inclui uma variação de "ret", que adiciona um valor ao ponteiro da pilha após a inserção do endereço de retorno. Isso é útil para muitas implementações do Pascal, nas quais o chamador de uma função envia argumentos para a pilha antes de fazer uma chamada de função e os expande posteriormente. Se uma rotina aceitar, por exemplo, parâmetros de quatro bytes, ela poderá terminar com "RET 0004" para limpar a pilha. Na ausência de tal instrução, uma convenção de chamada provavelmente exigiria que o código localizasse o endereço de retorno em um registro, atualizasse o ponteiro da pilha e depois pulasse para esse registro.
Curiosamente, a maioria dos códigos (incluindo rotinas do SO) no Macintosh original usava a convenção de chamada Pascal, apesar da falta de uma instrução facilitadora no 68000. O uso dessa convenção de chamada economizou 2-4 bytes de código em um site de chamada típico, mas exigia um extra 4-6 bytes de código no site de retorno de todas as funções que utilizaram parâmetros.
fonte
ENTER
contrapartida para issoRET n
... #ENTER
existia no original 8086; veio com processadores posteriores. Porém, traz um ponto interessante: os modos de endereçamento baseados em BP são claramente projetados em torno do uso de parâmetros empilhados e locais acessados via ponteiro de quadro. Acho essa convenção interessante de várias maneiras, especialmente considerando que (1) o código puro da linguagem assembly é mais apto a usar valores em registradores do que a pilha, mas (2) as vantagens de abordar [BP + nn] sobre [SP + nn] o endereçamento é mais significativo para programas em linguagem assembly que acessam coisas na pilha do que ... #Um exemplo é o MIPS, que possui ambos
add
eaddu
para interceptar e ignorar o estouro, respectivamente. (Tambémsub
esubu
.) Precisava do primeiro tipo de instrução para idiomas como Ada (eu acho - eu nunca usei o Ada) que lida com estouros de forma explícita e o segundo tipo para idiomas como C que ignoram estouros.Se bem me lembro, a CPU real possui alguns circuitos adicionais na ALU para controlar os estouros. Se o único idioma com o qual as pessoas se importavam era o C, não seria necessário.
fonte
nmemb*size+offset
bytes e precisar garantir que não haja um estouro.addu
esubu
(as que não verificam se há estouros) foram as que foram adicionadas para deixar C feliz. Claro, eu realmente não sei - nós apenas o abordamos vagamente em palestras e eu certamente não sou especialista em arquitetura: p.A série Burroughs 5000 foi projetada para oferecer suporte eficiente à ALGOL, e o iAPX-432 da Intel foi projetado para executar com eficiência o Ada. O Inmos Transputer tinha seu próprio idioma, Occam. Eu acho que o processador Parallax "Propeller" foi projetado para ser programado usando sua própria variante do BASIC.
Não é um idioma, mas o conjunto de instruções do VAX-11 possui uma única instrução para carregar um contexto de processo, que foi projetado após uma solicitação da equipe de design do VMS. Não me lembro dos detalhes, mas o ISTR levou tantas instruções para implementar que colocou um limite superior sério no número de processos que eles poderiam agendar.
fonte
Uma coisa que ninguém parece ter mencionado até agora é que os avanços na otimização do compilador (onde a linguagem base é irrelevante) levaram a mudança dos conjuntos de instruções CISC (que foram amplamente projetados para serem codificados por humanos) para os conjuntos de instruções RISC (que eram amplamente projetado para ser codificado por compiladores.)
fonte
A família Motorola 68000 introduziu algum modo de endereço de incremento automático que tornou a cópia de dados por meio da CPU muito eficiente e compacta.
[Exemplo atualizado]
este foi um código c ++ que influenciou 68000 assembler
implementado no assembler convencional (pseudocódigo, esqueci os comandos 68000 assembler)
com o novo modo de endereço, tornou-se algo semelhante a
apenas duas instruções por loop em vez de 4.
fonte
O mainframe da série Z da IBM é o descendente do IBM 360 a partir da década de 1960.
Houve várias instruções específicas para acelerar os programas COBOL e Fortran. O exemplo clássico é o
BXLE
- "Ramificação no Índice Baixo ou Igual", que é a maior parte de umfor
loop Fortran ou um COBOLPERFORM VARYING x from 1 by 1 until x > n
encapsulado em uma única instrução.Há também uma família inteira de instruções decimais compactadas para suportar a aritmética decimal de ponto fixo comum nos programas COBOL.
fonte
DO
loop FORTRAN .Os primeiros processadores Intel tinham os seguintes recursos, muitos deles agora obsoletos no modo de 64 bits:
O sinalizador de sinal, encontrado no registro de status de muitas CPUs, existe para executar facilmente aritmética assinada E não assinada.
O conjunto de instruções do SSE 4.1 apresenta instruções para o processamento de cadeias, contadas e terminadas com zero (PCMPESTR, etc.)
Além disso, eu poderia imaginar que vários recursos no nível do sistema foram projetados para oferecer suporte à segurança do código compilado (verificação de limite de segmento, portas de chamada com cópia de parâmetros etc.)
fonte
Alguns processadores ARM, principalmente aqueles em dispositivos móveis, incluem (d) extensão Jazelle, que é intérprete de JVM de hardware; interpreta diretamente o bytecode Java. A JVM com reconhecimento de Jazelle pode usar o hardware para acelerar a execução e eliminar grande parte do JIT, mas o fallback para a VM do software ainda é garantido se o bytecode não puder ser interpretado no chip.
Os processadores com essa unidade incluem a instrução BXJ, que coloca o processador no "modo Jazelle" especial ou, se a ativação da unidade falhou, ela é interpretada como uma instrução de ramificação normal. A unidade reutiliza os registros do ARM para manter o estado da JVM.
O sucessor da tecnologia Jazelle é o ThumbEE
fonte
Tanto quanto sei, isso era mais comum no passado.
Há uma sessão de perguntas em que James Gosling disse que havia pessoas tentando criar hardware que pudesse lidar melhor com o bytecode da JVM, mas essas pessoas descobririam uma maneira de fazê-lo com o intel x86 "genérico" comum (talvez compilando o bytecode de alguma maneira inteligente).
Ele mencionou que há vantagem em usar o popular chip genérico (como o da Intel) porque ele possui uma grande corporação que lança enormes somas de dinheiro no produto.
Vale a pena conferir o vídeo. Ele fala sobre isso aos 19 ou 20 minutos.
fonte
Eu fiz uma pesquisa rápida na página e parece que ninguém mencionou CPUs desenvolvidas especificamente para executar o Forth . A linguagem de programação Forth é baseada em pilha, compacta e usada em sistemas de controle.
fonte
A CPU Intel iAPX foi projetada especificamente para idiomas OO. Não deu muito certo, no entanto.
fonte
O 68000 possuía o MOVEM, que era mais adequado para inserir vários registros na pilha em uma única instrução, o que muitos idiomas esperavam.
Se você viu o MOVEM (MOVE Multiple) precedendo o JSR (Jump SubRotine) em todo o código, geralmente sabia que estava lidando com o código C em conformidade.
O MOVEM permitiu o incremento automático do registro de destino, permitindo que cada uso continue empilhando no destino ou removendo da pilha no caso de decremento automático.
http://68k.hax.com/MOVEM
fonte
A arquitetura AVR da Atmel foi totalmente projetada desde o início para ser adequada para programação em C. Por exemplo, esta nota de aplicação é mais detalhada.
Na IMO, isso está intimamente relacionado à excelente resposta do rockets4kids , com PIC16-s iniciais sendo desenvolvidos para programação direta de montadores (40 instruções no total), com famílias mais tarde mirando C.
fonte
Quando o coprocessador numérico 8087 foi projetado, era bastante comum que os idiomas realizassem todas as matemáticas de ponto flutuante usando o tipo de maior precisão e arredondassem o resultado para menor precisão ao atribuí-lo a uma variável de menor precisão. No padrão C original, por exemplo, a sequência:
promoveria
a
eb
paradouble
, adicioná-los, promoverc
adouble
, adicioná-lo, e depois armazenar o resultado arredondado parafloat
. Embora em muitos casos fosse mais rápido para um compilador gerar código que executasse operações diretamente no tipofloat
, era mais simples ter um conjunto de rotinas de ponto flutuante que operariam apenas no tipodouble
, além de rotinas para converter em / fromfloat
, do que ter conjuntos separados de rotinas para lidar com operações emfloat
edouble
. O 8087 foi projetado em torno dessa abordagem da aritmética, executando todas as operações aritméticas usando um tipo de ponto flutuante de 80 bits [80 bits provavelmente foi escolhido porque:Em muitos processadores de 16 e 32 bits, é mais rápido trabalhar com uma mantissa de 64 bits e um expoente separado do que trabalhar com valor que divide um byte entre a mantissa e o expoente.
É muito difícil realizar cálculos precisos com a precisão total dos tipos numéricos que se está usando; se alguém está tentando, por exemplo, calcular algo como log10 (x), é mais fácil e rápido calcular um resultado com precisão de até 100ulp de um tipo de 80 bits do que calcular um resultado com precisão de 1ulp de 64 bits tipo, e arredondar o resultado anterior para a precisão de 64 bits produzirá um valor de 64 bits mais preciso que o último.
Infelizmente, versões futuras da linguagem mudaram a semântica de como os tipos de ponto flutuante deveriam funcionar; enquanto a semântica do 8087 teria sido muito boa se as linguagens as suportassem consistentemente, se as funções f1 (), f2 () etc. retornassem tipo
float
, muitos autores do compilador se encarregariam de criarlong double
um alias para o tipo duplo de 64 bits em vez do tipo de 80 bits do compilador (e não fornece outros meios de criar variáveis de 80 bits) e avaliar arbitrariamente algo como:de qualquer uma das seguintes maneiras:
Observe que, se f3 e f4 retornam os mesmos valores que f1 e f2, respectivamente, a expressão original deve retornar claramente zero, mas muitas dessas expressões podem não retornar. Isso levou as pessoas a condenar a "precisão extra" do 8087, embora a última formulação geralmente fosse superior à terceira e - com código que usasse o tipo duplo estendido adequadamente - raramente seria inferior.
Nos anos seguintes, a Intel respondeu à tendência da linguagem (lamentável IMHO) de forçar resultados intermediários a serem arredondados para a precisão dos operandos, projetando seus processadores posteriores de modo a favorecer esse comportamento, em detrimento do código que se beneficiaria do uso de alto desempenho. precisão em cálculos intermediários.
fonte
## How the stack changed the processor
e## How floating point changed the processor
) para que as pessoas possam ter a mentalidade correta ao lê-la e são menos propensas a pensar que você estava distraído ao responder ou reposicionar o mesmas respostas (semelhantes).