Design: Aritmética com transporte

Criado em 28 mar. 2017  ·  7Comentários  ·  Fonte: WebAssembly/design

(Esta é uma versão expandida do problema (https://github.com/WebAssembly/spec/issues/446))

A aritmética de precisão múltipla requer manuseio especial. Isso está disponível de alguma forma em todas as ISAs, mas não está disponível atualmente no webasm.

Existem basicamente três maneiras de fazer isso (parece-me), nenhuma das quais é especialmente palatável no contexto do design atual:

Opção 1. Adicione um registrador de flags especial, junto com instruções que fazem aritmética com aquele registrador.

Esta é a abordagem tradicional no hardware convencional.

Você recebe instruções como

adicionar

que adicionará dois números e o valor do sinalizador de transporte e definirá o sinalizador de transporte no resultado.

Isso não é agradável porque adiciona um registro especial.

Opção 2.
Suporta uma forma de aritmética de 60 bits com 4 bits para sinalizadores.

Opção 3.
Suporta aritmética multi-palavra: a adição leva 3 argumentos e produz 2 saídas.

Essa abordagem causará menos danos ao ISA existente e à arquitetura de registro. No entanto, isso será difícil de mapear para o hardware existente de forma eficiente (nem todos os ISAs de hardware suportam o carregamento do registro de sinalizadores diretamente.

Seja como for, a aritmética de precisão múltipla é bastante importante e muito difícil de emular sem algum suporte de hardware simples.

Comentários muito úteis

Houve algum progresso nesta questão? Carregar e emprestar são necessários para implementar a criptografia moderna (por exemplo, SIDH) de forma eficiente. A adição de grande número sem ADDC é vários fatores mais lenta do que com. O mesmo se aplica à subtração e à multiplicação.

Todos 7 comentários

Parece-me que para a opção 3 existem otimizações plausíveis que tornariam isso prático. Suponha que {i32,i64}.addc receba três entradas, op2 no topo, op1 abaixo, carry na base e produza duas saídas, result no topo e carry abaixo. Por uma questão de argumento, suponha que o carry seja sempre do mesmo tipo que os outros operandos. Defina addc apenas para usar o bit baixo do carry e para que o carry restante após a operação seja zero ou um. As coisas agora estão razoavelmente configuradas para uma adição de várias palavras, digamos. Em um loop adequadamente desenrolado, um compilador JIT/Wasm realmente deve ser capaz de ver que é o transporte que está sendo propagado e gerar um bom código. (E se o loop não for desenrolado, a sobrecarga do loop diluirá a extração/inserção de transporte de qualquer maneira.) Acho que o código livre de ramificação do pior caso para extração de transporte deve ser mov rd, 0; adc rd, 0 ; para inserção, algo como and rc, 1; add rc, ~0 onde rc é um registrador que contém um valor a ser tratado como um carry.

No ARM, consumir um carry é separado de produzir um carry: ADC consome, ADC.S consome e produz, ADD.S apenas produz. Queremos todas essas variantes? E sobre o transbordamento?

(Pode haver uma quarta opção, onde adicionamos uma operação de operação e ramificação na condição que produz um resultado e ramifica para um rótulo ou não, por exemplo, i32.addc op1 op2 carry L ramifica para L no conjunto de transporte e cai no carry clear, e de qualquer forma deixa um resultado na pilha, mas parece mais difícil de usar em geral do que as três opções que você sugeriu.)

Existe alguém disposto a defender esta proposta? Precisaríamos de semântica proposta, codificação binária e gostaria de pelo menos um mínimo de casos de uso e uma implementação com números de desempenho para esses casos de uso (compare o MVP WebAssembly atual, com essa adição proposta e o código nativo).

Em princípio, eu estaria disposto a defender isso.
No entanto, mudanças pessoais significam que tenho recursos limitados pelo menos nos próximos meses.
———
Frank McCabe
Arquiteto de Software Sênior
Telefone: 650-740 6673 | E-mail: [email protected] [email protected]
Lógica de inicialização | 450 Lambert Ave, Palo Alto, CA 94306 | instartlogic. com http://instartlogic.com/

Em 11 de maio de 2017, às 10h14, JF Bastien [email protected] escreveu:

Existe alguém disposto a defender esta proposta? Precisaríamos de semântica proposta, codificação binária e gostaria de pelo menos um mínimo de casos de uso e uma implementação com números de desempenho para esses casos de uso (compare o MVP WebAssembly atual, com essa adição proposta e o código nativo).


Você está recebendo isso porque foi o autor do tópico.
Responda a este e-mail diretamente, visualize-o no GitHub https://github.com/WebAssembly/design/issues/1021#issuecomment-300856161 ou silencie o tópico https://github.com/notifications/unsubscribe-auth/ADfCzd9le4ufXm6DSsArpfXCYsGdV7UIks5r40H5gaJpZM4MrKma .

Provavelmente terei tempo para me dedicar a isso, embora não muito até junho ou algo assim, e depois no outono. IMO essa funcionalidade é bastante importante, e acho que o sinalizador de estouro é tão importante quanto o sinalizador de transporte, embora com diferentes casos de uso (fixnum das linguagens dinâmicas -> transição bignum).

Discuti isso com algumas pessoas da Mozilla hoje. Resumindo:

  • Provavelmente queremos instruções dedicadas aqui porque emular o comportamento será mais lento e geralmente não queremos fazer correspondência de padrões mágicos para reconhecer a emulação e transformá-la em código de máquina eficiente nos bastidores
  • Nós nos preocupamos com carry/borrow e overflow, com certeza; outras bandeiras a definir
  • Nós nos preocupamos em somar e subtrair com certeza; multiplicar, dividir, girar (girar através de transporte é comum, mas é útil para Wasm?) TBD
  • O caso comum é que só nos preocupamos com um sinalizador de cada vez e provavelmente é adequado para cobrir esse caso, não uma situação geral de "capturar sinalizadores A, B e C"
  • Para carry, uma instrução que sempre consome um carry-in e sempre produz um carry-out é suficiente; variantes que consomem mas não produzem ou vice-versa não são necessárias, e não tê-las provavelmente não afetará a saída de um bom compilador
  • Queremos motivar este trabalho com dados de boas bibliotecas MP existentes (como Gnu MP); isso pode ser fatos (a biblioteca X tem/não tem sub-rotinas de montador ou usa intrínsecos para fazer uso de sinalizadores; ela usa instruções A e B) ou dados de desempenho (a biblioteca Y pode usar sub-rotinas de montador ou emular em C; a diferença de perf é N% ) ou casos de uso (aritmética bignum geral, criptografia, o que mais vier à mente)
  • Podemos querer esperar com a proposta de instruções específicas até começarmos a discutir instruções de produção de valores múltiplos em geral, por exemplo, retornos de valores múltiplos

Houve algum progresso nesta questão? Carregar e emprestar são necessários para implementar a criptografia moderna (por exemplo, SIDH) de forma eficiente. A adição de grande número sem ADDC é vários fatores mais lenta do que com. O mesmo se aplica à subtração e à multiplicação.

Acho que estamos pelo menos esperando que o multi-valor seja concluído para que possamos expressar facilmente uma operação com mais de um resultado. O valor múltiplo está "quase lá".

Esta página foi útil?
0 / 5 - 0 avaliações

Questões relacionadas

Artur-A picture Artur-A  ·  3Comentários

cretz picture cretz  ·  5Comentários

beriberikix picture beriberikix  ·  7Comentários

thysultan picture thysultan  ·  4Comentários

jfbastien picture jfbastien  ·  6Comentários