2010-07-13 8 views
13

Wie werden die von GCC bereitgestellten Multiply-Accumulate-Intrinsics verwendet?Wie die multiplizieren und akkumulieren intrinsics in ARM Cortex-a8?

float32x4_t vmlaq_f32 (float32x4_t , float32x4_t , float32x4_t); 

Kann mir jemand erklären, welche drei Parameter ich an diese Funktion übergeben muss. Ich meine die Quell- und Zielregister und was die Funktion zurückgibt?

Hilfe !!!

+6

Die GCC-Dokumente (und die RealView-Dokumente für die Grundlagen, auf denen die GCC-Grundlagen basieren) sind ziemlich spärlich ... Wenn Sie keine vernünftige Antwort bekommen, würde ich vorschlagen, nur eine zu kompilieren einige Aufrufe und einen Blick auf die Baugruppe, die ausgegeben wird. Das sollte Ihnen eine ziemlich gute Idee geben (auch wenn es ein weniger als idealer Weg ist). –

Antwort

19

sagte einfach die vmla Anweisung macht folgendes:

struct 
{ 
    float val[4]; 
} float32x4_t 


float32x4_t vmla (float32x4_t a, float32x4_t b, float32x4_t c) 
{ 
    float32x4 result; 

    for (int i=0; i<4; i++) 
    { 
    result.val[i] = b.val[i]*c.val[i]+a.val[i]; 
    } 

    return result; 
} 

Und all diese kompiliert in eine Seng Assemblerbefehl :-)

Sie diesen NEON-Assembler intrinsische können unter andere Dinge in typischen 4x4-Matrix-Multiplikationen für 3D-Grafiken wie diese:

float32x4_t transform (float32x4_t * matrix, float32x4_t vector) 
{ 
    /* in a perfect world this code would compile into just four instructions */ 
    float32x4_t result; 

    result = vml (matrix[0], vector); 
    result = vmla (result, matrix[1], vector); 
    result = vmla (result, matrix[2], vector); 
    result = vmla (result, matrix[3], vector); 

    return result; 
} 

Das spart ein paar Zyklen, weil Sie die Ergebnisse nach der Multiplikation nicht hinzufügen müssen. Die Addition wird so oft verwendet, dass sich multiple Akkumulationshsas in diesen Tagen zum Mainstream entwickeln (sogar x86 hat sie in einigen neueren SSE-Befehlssätzen hinzugefügt).

Auch erwähnenswert: Multiply-Akkumulationsoperationen wie diese sind sehr üblich in linearen Algebra und DSP (digitale Signalverarbeitung) Anwendungen. ARM war sehr intelligent und implementierte einen Fast-Path innerhalb des Cortex-A8 NEON-Core. Dieser schnelle Pfad tritt ein, wenn das erste Argument (der Akkumulator) eines VMLA-Befehls das Ergebnis eines vorhergehenden VML- oder VMLA-Befehls ist. Ich könnte ins Detail gehen, aber kurz gesagt läuft eine solche Befehlsreihe vier Mal schneller als eine VML/VADD/VML/VADD-Serie.

Werfen Sie einen Blick auf meine einfache Matrix-multiplizieren: Ich habe genau das getan. Aufgrund dieses schnellen Pfades wird es ungefähr viermal schneller laufen als die Implementierung, die mit VML und ADD anstelle von VMLA geschrieben wurde.

+0

Vielen Dank für eine so detaillierte Antwort. Ihre Antwort erklärt nicht nur die Funktionalität des Befehls, sondern auch die Vor- und Nachteile der Verwendung dieses Befehls. – HaggarTheHorrible

+0

Hallo Nils, ich habe verstanden, wie die Matrixmultiplikation mit den NEON-Befehlen beschleunigt werden kann. Es macht jetzt wirklich süchtig :) Ich möchte die NEON Anweisungen verwenden, um eine Matrix invers zu machen, können Sie mich auf einige gute Dokumente verweisen, die erklären, wie man NEON Anweisungen verwendet, um die umgekehrte Matrix zu machen, oder können Sie mir irgendwelche Ideen geben, wie um das zu tun? Vielen Dank. – HaggarTheHorrible

+1

für Matrix inverse Ich würde eine Google-Suche auf "sse Matrix inverse" tun und portiere den sse-Code zu NEON. Der übliche Weg ist die Berechnung der Inverse für kleine Matrizen (4x4) über Cramers-Regel. –

8

Google für vmlaq_f32, aufgedreht the reference for the RVCT compiler tools. Hier ist, was es sagt:

Vector multiply accumulate: vmla -> Vr[i] := Va[i] + Vb[i] * Vc[i] 
... 
float32x4_t vmlaq_f32 (float32x4_t a, float32x4_t b, float32x4_t c); 

UND

Folgende Typen sind definiert Vektoren darzustellen. NEON Vektordatentypen genannt werden nach dem folgenden Muster: <Typ> < Größe > x < Anzahl der Fahrspuren > _t Zum Beispiel ist ein Vektor int16x4_t vier Bahnen jeweils eine 16-Bit-Ganzzahl enthält. Tabelle E.1 listet die Vektordatentypen auf.

IOW, wird der Rückgabewert der Funktion ein Vektor-4 32-Bit-Schwimmern, und jedes Element des Vektors durch Multiplizieren der entsprechenden Elemente von b und c, und Addieren der Inhalte der a berechnet enthalten sein.

HTH

1
result = vml (matrix[0], vector); 
result = vmla (result, matrix[1], vector); 
result = vmla (result, matrix[2], vector); 
result = vmla (result, matrix[3], vector); 

Diese Sequenz funktioniert jedoch nicht.Das Problem ist, dass x-Komponente ansammelt nur durch die Matrix-Zeilen moduliert X und kann ausgedrückt werden als:

result.x = vector.x * (matrix[0][0] + matrix[1][0] + matrix[2][0] + matrix[3][0]); 

...

Die richtige Reihenfolge wäre:

result = vml (matrix[0], vector.xxxx); 
result = vmla(result, matrix[1], vector.yyyy); 

...

NEON und SSE haben keine eingebaute Auswahl für die Felder (dies würde 8 Bits in Instruktionscodierung pro Vektorregister erfordern). GLSL/HLSL zum Beispiel hat diese Art von Einrichtungen, so dass die meisten GPUs auch haben.

Alternative Art und Weise, dies zu erreichen wäre:

result.x = dp4(vector, matrix[0]); 
result.y = dp4(vector, matrix[1]); 

... // und natürlich wäre die Matrix transponieren für dieses gleiche Ergebnis madd

Die mul, zu erhalten, madd, Die madd-Sequenz wird normalerweise bevorzugt, da sie keine Schreibmaske für die Zielregisterfelder benötigt.

Ansonsten sieht der Code gut aus. =)

Verwandte Themen