2012-03-04 10 views
6

Sto scrivendo un compilatore e devo emettere il codice per le condizioni di ramificazione sui valori float. Ad esempio, per compilare questo tipo di codice:Qual è il modo migliore per eseguire la ramificazione tramite Intel SSE?

if(a <= b){ 
    //1. DO something 
} else { 
    //2. Do something else 
} 

Quando a e b sono variabili float. Devo solo saltare a 2 se la condizione non è vera, altrimenti cadere a 1. Sto considerando qui l'ottimizzazione a livello di compilatore considerando ciò che è in 1 e 2.

Ho bisogno di qualcosa che funzioni con tutti gli operatori di confronto >,> =, <, < =, == e! =

Un modo che ho trovato per fare il confronto è quello di utilizzare CMPLTSD (e altre istruzioni equivalenti per gli altri operatori relazionali). Ma con quello, devo usare un registro SSE soprattutto per il risultato e poi devo spostare il suo valore su un registro generale (eax per esempio) e infine confrontare il valore con 0.

Ho anche visto che il L'istruzione UCOMISD dovrebbe impostare correttamente i flag, ma a quanto pare non funziona come pensavo.

Quindi, qual è il modo migliore per gestire un codice del genere? Ci sono istruzioni migliori della prima soluzione che ho?

Nel migliore dei casi, la soluzione generale a questo problema. Se possibile, mi piacerebbe che il codice si comportasse allo stesso modo di quando si fanno i confronti sugli interi (etichetta cmp a, b; jge). Naturalmente, preferirei le istruzioni più veloci per raggiungere questo obiettivo.

+2

Il modo migliore per farlo * dipende da ciò che si sta facendo *. Come in, cosa c'è dentro il blocco '// DO something'? "Il modo migliore" spesso dipende dall'intera immagine, non dal tentativo di tradurre il codice riga per riga. – jalf

+0

Ho aggiunto dettagli al post per rispondere alle tue due domande. –

+1

Se si desidera effettivamente diramazione, UCOMISD (che in realtà è SSE2) sembra essere la risposta, qual è il problema? Il risultato non ordinato? – harold

risposta

7

I codici di condizione per ucomisd non corrispondono ai codici di confronto numeri interi con segno, ma a quelli senza segno (con "non ordinati" nel contrassegno di parità). È un po 'strano, lo ammetto, ma tutto è chiaramente documentato. Il codice se si vuole realmente ramo potrebbe essere qualcosa di simile per <=:

ucomisd a,b 
    ja else  ; greater 
    jp else  ; unordered 
    ; code for //1 goes here 
    jmp end 
else: 
    ; code for //2 goes here 
end: 

Per <:

jae else ; greater or equal 
jp else ; unordered 

potrei elencarli tutti se si vuole veramente, ma si può solo guardare il codici di condizione per ucomisd e abbinarli a ciò che è necessario saltare.

+0

Questo è davvero strano ... Ma penso che lo avrò con la documentazione. Molte grazie. –

1

Importante: la risposta di @harold è quasi esatta ma presenta un aspetto errato sottile che può far impazzire in un caso limite molto importante in seguito - il trattamento NaN è retrocesso dalla maggior parte delle lingue (come C++).

Come dice @harold correttamente, il risultato di confronto non ordinato viene memorizzato nel flag di parità.

Tuttavia, non confrontato è vero quando qualsiasi operando è NaN come indicato in this stack overflow post. Ciò significa che lo NaN sarà inferiore a, uguale a e superiore a assolutamente ogni numero compresoNaN.

Quindi, se volete la vostra lingua per abbinare C++ 's comportamento di dove qualsiasi confronto con NaN restituisce false, si vuole:

Per <=:

ucomisd xmm0, xmm1 
jbe else_label 

Per <:

ucomisd xmm0, xmm1 
jb else_label 

Confermato nel seguente smontaggio di gcc, dove I return a >= b:

144e:  66 0f 2e c8    ucomisd %xmm0,%xmm1 
1452:  0f 93 c0    setae %al 

Qui utilizza setae che è l'equivalente di modifica registro a jae. Quindi torna immediatamente senza controllare la bandiera di parità.

Perché il suo ja e non jg, la risposta di @ harold è ancora una spiegazione chiara e corretta.

E, naturalmente, non è necessario utilizzare ordinato confrontare, è possibile utilizzare non ordinata confrontare come indicato nella risposta precedente, se si desidera assolutamente ogni numero sia inferiore, superiore, e pari a NaN in il tuo programma/lingua (dove anche NaN < NaN è vero!). E, naturalmente, come puoi vedere, potrebbe essere un po 'più lento poiché richiede controlli aggiuntivi.

Problemi correlati