Que considerações são necessárias para prever a latência das operações em processadores superescalares modernos e como posso calculá-las manualmente?

Quero poder prever, manualmente, por quanto tempo aritmética arbitrária (ou seja, sem ramificação ou memória, embora isso seja bom também) o código de montagem x86-64 levará em conta uma arquitetura específica, levando em conta a reordenação de instruções, a superescalaridade, latências, CPIs etc.

O que / descrever as regras devem ser seguidas para conseguir isso?

Acho que descobri algumas regras preliminares, mas não consegui encontrar nenhuma referência sobre a quebra de nenhum código de exemplo nesse nível de detalhe, então tive que adivinhar algumas. (Por exemplo, o manual de otimização da Intel nemmenciona reordenação de instruções.)

No mínimo, estou procurando (1) confirmação de que cada regra está correta ou uma declaração correta de cada regra e (2) uma lista de quaisquer regras que eu possa ter esquecido.

O maior número possível de instruções é emitido a cada ciclo, iniciando em ordem a partir do ciclo atual e potencialmente tão à frente quanto o tamanho do buffer de reabastecimento.Uma instrução pode ser emitida em um determinado ciclo se:Nenhuma instrução que afeta seus operandos ainda está sendo executada. E:Se for uma instrução de ponto flutuante, todas as instruções de ponto flutuante antes de serem emitidas (instruções de ponto flutuante devem ser reordenadas por instruções estáticas). E:Existe uma unidade funcional disponível para essa instrução nesse ciclo. Cada unidade funcional (?) É canalizada, o que significa que pode aceitar 1 nova instrução por ciclo e o número de unidades funcionais totais é 1 / CPI, para o CPI de uma determinada classe de função (aqui nebuloso: presumivelmente por ex.addps esubps usa a mesma unidade funcional? Como eu determino isso?). E:Menos que a largura superescalar (normalmente4) já foram emitidas várias instruções neste ciclo.Se nenhuma instrução puder ser emitida, o processador simplesmente não emitirá nenhuma - uma condição chamada "paralisação".

Como exemplo, considere o seguinte código de exemplo (que calcula um produto cruzado):

shufps   xmm3, xmm2, 210
shufps   xmm0, xmm1, 201
shufps   xmm2, xmm2, 201
mulps    xmm0, xmm3
shufps   xmm1, xmm1, 210
mulps    xmm1, xmm2
subps    xmm0, xmm1

Minha tentativa de prever a latência para Haswell é algo como isto:

; `mulps`  Haswell latency=5, CPI=0.5
; `shufps` Haswell latency=1, CPI=1
; `subps`  Haswell latency=3, CPI=1

shufps   xmm3, xmm2, 210   ; cycle  1
shufps   xmm0, xmm1, 201   ; cycle  2
shufps   xmm2, xmm2, 201   ; cycle  3
mulps    xmm0, xmm3        ;   (superscalar execution)
shufps   xmm1, xmm1, 210   ; cycle  4
mulps    xmm1, xmm2        ; cycle  5
                           ; cycle  6 (stall `xmm0` and `xmm1`)
                           ; cycle  7 (stall `xmm1`)
                           ; cycle  8 (stall `xmm1`)
subps    xmm0, xmm1        ; cycle  9
                           ; cycle 10 (stall `xmm0`)

questionAnswers(1)

yourAnswerToTheQuestion