2015-05-15 4 views
11

Ecco un SSCCE:Perché questa cura Auto-Vectorizer riguarda i costruttori/i distruttori?

class Vec final { 
    public: 
     float data[4]; 

     inline Vec(void) {} 
     inline ~Vec(void) {} 
}; 
Vec operator*(float const& scalar, Vec const& vec) { 
    Vec result; 
    #if 1 
     for (int k=0;k<4;++k) result.data[k]=scalar*vec.data[k]; 
    #else 
     float const*__restrict src = vec.data; 
     float  *__restrict dst = result.data; 
     for (int k=0;k<4;++k) dst[k]=scalar*src[k]; 
    #endif 
    return result; 
} 

int main(int /*argc*/, char* /*argv*/[]) { 
    Vec vec; 
    Vec scaledf = 2.0f * vec; 
    return 0; 
} 

Quando si compila, MSVC 2013 mi informa (/Qvec-report:2) che

main.cpp (11): informazioni C5002: ciclo non Vectorized a causa di motivi '1200'

Ciò significa che "[l] oop contiene dipendenze dei dati trasportate dal ciclo".

ho notato che commentando sia il costruttore o il distruttore per Vec (edit: o inadempiente, ad esempio Vec()=default;) fa sì che vettorizzare successo. La mia domanda: perché?


Nota: Alternare la #if sarà anche farlo funzionare. Il __restrict è importante.
Nota: la modifica da a float const scalar causa la vettorizzazione di report 1303 (la vettorizzazione non sarebbe una vincita), ho il sospetto che il riferimento possa essere passato direttamente in un registro SSE mentre il pass-by-value necessita di un'altra copia.

+0

Cosa succede se si predefinisce ('Vec() = default;') invece il costruttore e il distruttore? Il modo in cui li hai definiti in questo momento li rende non banali, forse l'ottimizzatore non gli piace per qualche motivo. – Praetorian

+0

@Praetorian L'impostazione predefinita di almeno uno di essi provoca il successo della vettorizzazione. – imallett

+1

Sembra (per me) come se il codice per il tipo di destinazione fosse sufficientemente complesso, non è abbastanza "intelligente" abbastanza da garantire che non si abbia aliasing (cioè, non può provare che 'src' e' dst' necessariamente si riferisce a oggetti distinti). –

risposta

1

Perché si dichiara un distruttore non virtuale vuoto inline ~Vec(void) {} con un costruttore predefinito vuoto inline Vec(void) {}?

Come risultato il compilatore non genera il costruttore di copie predefinito. Quindi il codice return result; non può essere compilato senza di esso perché questo richiede di copiare il risultato in un oggetto restituito temporaneo (che potrebbe non essere quello che vuoi).

Definire un costruttore di copia oppure non definire affatto il costruttore e il distruttore vuoto.

+0

Il costruttore/distruttore vuoto sono a causa della giocosità di questo esempio di giocattolo.Inoltre, deve essere generato un costruttore di copie dal momento che compila bene. In ogni caso, aggiungendo 'inline Vec (Vec const & other) = default; non ha alcun effetto – imallett