Domanda

Sono la copia di elementi di un array ad un altro in C ++. Ho trovato le istruzioni rep movs in x86 che sembra copiare una matrice a ESI ad un array a EDI di dimensioni ECX. Tuttavia, né il for né loop while mi provarono compilati in un'istruzione rep movs in VS 2008 (su un processore Intel Xeon x64). Come posso scrivere un codice che andranno compilati a questa istruzione?

È stato utile?

Soluzione

Se avete bisogno di esattamente che l'istruzione - uso built-in assembler e scrivere che l'istruzione manualmente. Non si può fare affidamento sul compilatore di produrre qualsiasi codice macchina specifico - anche se emette in una compilation si può decidere di emettere qualche altro equivalente durante la compilazione successiva.

Altri suggerimenti

Onestamente, non si dovrebbe. REP è una specie di holdover obsolete nel set di istruzioni, e in realtà piuttosto lento poiché deve chiamare una subroutine microprogramma all'interno della CPU, che ha una ROM ricerca latenza ed è nonpipelined pure.

In quasi ogni applicazione, vi accorgerete che il compilatore memcpy() intrinseco sia più facile da usare e funziona più velocemente.

Sotto MSVC ci sono la __movsxxx & __stosxxx intrinseci che genererà un'istruzione REP prefissato.

c'è anche un 'trucco' per forzare memset intrinseca alias REP STOS sotto VC9 +, come le intrinseche uscite non più, a causa della SSE2 ramificazione nel CRT. questo è meglio che __stosxxx a causa del fatto che il compilatore può ottimizzare per le costanti e l'ordine correttamente.

#define memset(mem,fill,size) memset((DWORD*)mem,((fill) << 24|(fill) << 16|(fill) << 8|(fill)),size)
__forceinline void memset(DWORD* pStart, unsigned long dwFill, size_t nSize)
{
    //credits to Nepharius for finding this
    DWORD* pLast = pStart + (nSize >> 2);
    while(pStart < pLast)
        *pStart++ = dwFill;

    if((nSize &= 3) == 0)
        return;

    if(nSize == 3)
    {
        (((WORD*)pStart))[0]   = WORD(dwFill);
        (((BYTE*)pStart))[2]   = BYTE(dwFill);
    }
    else if(nSize == 2)
        (((WORD*)pStart))[0]   = WORD(dwFill);
    else
        (((BYTE*)pStart))[0]   = BYTE(dwFill);
}

naturalmente REP non è sempre la cosa migliore da utilizzare, imo tuo modo meglio usare memcpy, sarà diramazione a uno SSE2 o REPS MOV in base al sistema (sotto msvc), a meno che non ti senti come scrivere su misura per il montaggio aree 'calde' ...

REP e gli amici è stato bello una volta, quando la CPU x86 è stato un singolo-gasdotto industriale CISC-processore.

Ma questo è cambiato. Oggigiorno quando gli incontri processore qualsiasi istruzione, la prima che fa è tradurlo in un formato più semplice (VLIW-come micro-op) e programmi per un esecuzione futuro (questo è parte di out-of-order -Esecuzione, parte della programmazione tra i diversi core della CPU logici, può essere utilizzato per semplificare scrittura post-write-sequenze in single-scrive, et.c.). Questo macchinario funziona bene per le istruzioni che si traduce in un paio di VLIW-come codici operativi, ma non machine-code che si traduce in cicli. codice macchina Loop-tradotto probabilmente causare la pipeline di esecuzione per stallo.

Piuttosto che spendere centinaia di migliaia di transistori in costruendo CPU-circuiti per la gestione loop porzioni delle micro-op nella conduttura esecuzione, semplicemente gestirlo in una sorta di legacy-mode scadente che si arresta stutterly conduttura, e chiedere programmatori moderni per scrivere il proprio dannati loop!

Pertanto è raramente usato quando le macchine scrivere codice. Se si verifica REP in un binario eseguibile, la sua, probabilmente una catena di montaggio muppet umano che non sapeva meglio, o un cracker che aveva davvero bisogno i pochi byte è salvato per usarlo al posto di un ciclo vero e proprio, che lo ha scritto.

(comunque. Prendete tutto quello che ho appena scritto con un grano di sale. Forse questo non è più vero. Io non sono al 100% al passo con la struttura interna di CPU x86 più, ho avuto in altri hobby ..)

Io uso il rappresentante * prefisso varianti con CMPS *, MOV *, SCAS * e stos * istruzioni varianti di generare codice inline che riduce al minimo la dimensione del codice, consente di evitare chiamate inutili / salta e quindi tiene giù il lavoro svolto dai cache. L'alternativa è di impostare i parametri e chiamare un memset o da qualche altra memcpy che può essere nel complesso più veloce se voglio copiare un centinaio di byte o più, ma se è solo una questione di 10-20 byte utilizzando rep è più veloce (o almeno era l'ultima volta che ho misurato).

Dato che il mio compilatore permette di specificare e l'utilizzo delle funzioni di assemblaggio in linea e comprende il loro utilizzo registro / modifica nelle attività di ottimizzazione è possibile per me di utilizzare loro quando le circostanze sono di destra.

Una nota storica - non avendo alcuna conoscenza nelle strategie del produttore - ci fu un tempo in cui i "movs rep *" (ecc) istruzioni erano molto lento. Penso che sia stato intorno al periodo del Pentium / Pentium MMX. Un mio collega (che aveva un quadro più chiaro di me) ha detto che i produttori hanno diminuito l'area del chip (<=> un minor numero di transistor / più microcodice) assegnati al trattamento rep e lo ha utilizzato per fare altri, istruzioni più utilizzate più velocemente.

Nei quindici anni o giù di lì da quando è diventato rappresentante relativamente parlando più veloce ancora una volta che suggerirebbe più transistor / meno microcodice.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top