PDA

View Full Version : [asm e c++] Come far ritornare un parametro ? (naked function)


ercand
15-09-2008, 23:17
Salve a tutti, sto cercando di scrivere una classe che sfrutte le sse così da velocizzare il tutto, questa è la classe

class Vector4
{
public:
__forceinline Vector4();
__forceinline Vector4(const Vector4& v);
__forceinline Vector4(const float* vec);

// Operatori unari
__forceinline Vector4 operator - ();

// Operatori binari
Vector4 __cdecl operator + (Vector4& vec);

__m128 vector;
};

questo è il metodo che mi da problemi, somma semplicemente vec con this->vector.
Il metodo è dichiarato come naked per evitare il codice di prolog e epilog che mi rende lentissimo il codice ( con lento intendo che scivere il metodo senza sse è più veloce )

__declspec(naked) Vector4 __cdecl Vector4::operator +(Vector4& vec)
{
__asm
{
// questo per le funzioni naked
mov eax, dword ptr[esp + 12]
mov ecx, dword ptr[esp + 4] // esp+4 primo parametro

// somma
movaps xmm0, xmmword ptr[eax]
movaps xmm1, xmmword ptr[ecx]
addps xmm0, xmm1
}
}

questo è il main per testare la classe

int _tmain(int argc, _TCHAR* argv[])
{
Vector4 v1, v2, v3;

v1 = v2 + v3;

return 0;
}

Quello che non riesco a fare è far si che v1 assuma il risultato di xmm0, ci sto sbattendo la testa da tre giorni e non riesco a venirne fuori, qualcuno potrebbe darmi un indizio su come procedere.

Grazie mille:p

Per i moderatori, mi sono dimenticato di aggiungere il titolo della discussione dopo [asm e c++], se potete modificarlo aggiungete "Come far ritornare un parametro?", grazie:p.

cionci
16-09-2008, 01:27
Naked function...ti vuoi proprio fare male :)

Allora...il problema è che devi ritornare una nuova istanza di Vector4, non devi modificare il vettore contenuto nell'istanza puntata da this.
In pratica devi fare in modo che il risultato della somma venga messo in un nuovo vettore allocato nello stack. Purtroppo non mi ricordo la convenzione per poter ritornare al chiamate una struttura dati complessa (per i dati semplici si ritorna in eax).

Imho se cerchi le prestazioni non ti conviene usare l'operatore + perché questo impone di ritornare prima una nuova istanza di classe che poi mettiamo venga assegnata ad una terza variabile tramite l'operatore uguale.

v = v1 + v2;

Impone l'allocazione di un vettore temporaneo che poi verrà assegnato a v: lo spreco di tempo è notevole, prima per l'accesso al vettore temporaneo e poi per la copia del vettore temporaneo in v.
Imho ti conviene fare così:


Vector4 & add(Vector4 &v);

In questo modo avrai v1.add(v2)) che ti permetterà di portarti dietro il risultato di varie operazioni accumulandolo in v1.
L'implementazione in assembly sarà anche più semplice perché dovrai solo ritornare this in eax.

Potrai anche mettere in sequenza diverse operazioni:

v = v1.add(v2).multiply(v3);

Se avessi bisogno di una copia puoi sempre definire un metodo clone:

Vector4 clone()
{
Vector4 cloned(this);
return cloned;
}

Per questo metodo non ti conviene usare le naked function. In questo modo risolvi automaticamente due problemi in un colpo solo ;)

cionci
16-09-2008, 01:45
Ah...ovviamente servono anche il prologo e l'epilogo, in modo da mettere lo stack nella situazione iniziale per poter fare il ret ;) A meno che tu non modifichi ebp, ma il ret serve sempre.

http://msdn.microsoft.com/en-us/library/4d12973a(VS.80).aspx

ercand
16-09-2008, 14:58
Innanzi tutto grazie per la risposta, e grazie per aver corretto il titolo della discussione:fagiano: .


Imho ti conviene fare così:


Vector4 & add(Vector4 &v);

In questo modo avrai v1.add(v2)) che ti permetterà di portarti dietro il risultato di varie operazioni accumulandolo in v1.
L'implementazione in assembly sarà anche più semplice perché dovrai solo ritornare this in eax.

In questo modo avrai v1.add(v2)) che ti permetterà di portarti dietro il risultato di varie operazioni accumulandolo in v1.
L'implementazione in assembly sarà anche più semplice perché dovrai solo ritornare this in eax.

Potrai anche mettere in sequenza diverse operazioni:

v = v1.add(v2).multiply(v3);

Venedo a quello che mi hai consigliato mi sorge questo dubbio, se faccio questa operazione

v = v1.add(v2)

v assumerà il valore data dalla somma v1+v2, ma anche v1 non assumera lo stesso valore ( visto che il metodo add è chiamato su un'istanza di v1 )?

Grazie:)

cionci
16-09-2008, 15:16
Certo, anche v1 assumerà lo stesso valore. L'equivalente dell'operazione precedente in effetti sarebbe:

v = v1;
v.add(v2);

O in alternativa:

v = v1.clone().add(v2);

Visto che solitamente si applicano varie operazioni ad uno stesso vettore però torna comodo per fare operazioni successive:

v1.add(v2).add(v3);

Un'operazione di questo tipo sarebbe equivalente a:

v1 = v1 + v2 + v3;

operazione che genera ben due variabili temporanee e tre operazioni di copia.

ercand
16-09-2008, 21:09
Quindi mi consigli di mandare a quel paese le funzioni naked?
Visto che ci sono approfitto ulteriormente della tua disponibilità:D ; ho visto che ci sono le funzioni intrinsic a disposizione, io però non voglio utilizzare perchè vorrei capire da solo come sfruttare le sse, le funzioni intrinsic sono per caso dichiarate naked? lo chiedo perche vedendo il codice assembly dentro VS2008 non vedi la parte prolog/epilog ma probabilmente mi sbaglio.

Grazie:)