Quando compilato con GCC 5.2 utilizzando -std=c99
, -O3
, e -mavx2
, il seguente esempio di codice auto-vettorizza (assembly here):Come auto-vettorizzare le scritture stride con GCC?
#include <stdint.h>
void test(uint32_t *restrict a,
uint32_t *restrict b) {
uint32_t *a_aligned = __builtin_assume_aligned(a, 32);
uint32_t *b_aligned = __builtin_assume_aligned(b, 32);
for (int i = 0; i < (1L << 10); i += 2) {
a_aligned[i] = 42 * b_aligned[i];
a_aligned[i+1] = 3 * a_aligned[i+1];
}
}
Ma il seguente codice di esempio non auto-vectorize (assembly here):
#include <stdint.h>
void test(uint32_t *restrict a,
uint32_t *restrict b) {
uint32_t *a_aligned = __builtin_assume_aligned(a, 32);
uint32_t *b_aligned = __builtin_assume_aligned(b, 32);
for (int i = 0; i < (1L << 10); i += 2) {
a_aligned[i] = 42 * b_aligned[i];
a_aligned[i+1] = a_aligned[i+1];
}
}
L'unica differenza tra i campioni è il fattore di scala su a_aligned[i+1]
.
Questo è stato anche il caso per GCC 4.8, 4.9 e 5.1. L'aggiunta della dichiarazione volatile
a a_aligned
inibisce completamente l'auto-vettorizzazione. Il primo campione viene eseguito costantemente più velocemente del secondo per noi, con un aumento della velocità più pronunciato per i tipi più piccoli (ad esempio uint8_t
anziché uint32_t
).
C'è un modo per rendere auto-vectorize il secondo codice con GCC?
Quindi l'unica differenza è il fattore di scala (3 rispetto a nulla)? Prova ad aggiungere 1 come fattore di scala in modo esplicito. Se lo risolve, è un bug del compilatore. – Jeff
Oppure prova a commentare la frase 'a_aligned [i + 1] = a_aligned [i + 1]', o riscrivila come 'a_aligned [i + 1] * = 1'. Il compilatore potrebbe non sapere cosa fare con il tuo no-op self assignment se non quello di fare esattamente quello che hai detto di fare con esso. –
@Jeff In effetti, l'unica differenza è il fattore di scala. L'aggiunta di un esplicito 1 non rende il secondo esempio di codice auto-vectorize ([assembly here] (https://goo.gl/dnjSaQ)). –