Estoy tratando de vectorizar algunos cálculos simples para acelerar la arquitectura SIMD. Sin embargo, también quiero ponerlos como función en línea porque las llamadas a funciones y los códigos no vectorizados también requieren tiempo de cálculo. Sin embargo, no siempre puedo lograrlos al mismo tiempo. De hecho, la mayoría de mis funciones en línea no se auto-vectorizan. Aquí hay un código de prueba simple que funciona:
inline void add1(double *v, int Length) {
for(int i=0; i < Length; i++) v[i] += 1;
}
void call_add1(double v[], int L) {
add1(v, L);
}
int main(){return 0;}
En Mac OS X 10.12.3, compílelo:
clang++ -O3 -Rpass=loop-vectorize -Rpass-analysis=loop-vectorize -std=c++11 -ffast-math test.cpp
test.cpp:2:5: remark: vectorized loop (vectorization width: 2, interleaved count: 2) [-Rpass=loop-vectorize]
for(int i=0; i < Length; i++) v[i] += 1;
^
Sin embargo, algo muy similar (solo mover argumentos en call_add1) no funciona:
inline void add1(double *v, int Length) {
for(int i=0; i < Length; i++) v[i] += 1;
}
void call_add1() {
double v[20]={0,1,3,4,5,6,7,8,9,10,1,2,3,4,5,6,7,8,9};
int L=20;
add1(v, L);
}
int main(){ return 0;}
Compilar con el mismo comando no produce resultados. ¿Por qué pasó esto? ¿Cómo puedo asegurarme de que los bucles en las funciones en línea siempre se auto-vectorizan? Quiero vectorizar muchos bucles de funciones, así que espero que la solución no sea demasiado compleja.
3 respuestas
Compilar su código con -fsave-optimization-record
muestra que el ciclo se desenrolló y luego se eliminó.
--- !Passed
Pass: loop-unroll
Name: FullyUnrolled
DebugLoc: { File: main.cpp, Line: 2, Column: 5 }
Function: _Z9call_add1v
Args:
- String: 'completely unrolled loop with '
- UnrollCount: '20'
- String: ' iterations'
...
--- !Passed
Pass: gvn
Name: LoadElim
DebugLoc: { File: main.cpp, Line: 2, Column: 40 }
Function: _Z9call_add1v
Args:
- String: 'load of type '
- Type: double
- String: ' eliminated'
- String: ' in favor of '
- InfavorOfValue: '0.000000e+00'
Si coloca 4000 elementos en la matriz, excederá el umbral del optimizador y el sonido metálico permitirá la vectorización.
Parece que el compilador simplemente desenrollaría y optimizaría el ciclo, cuando v
se especifica explícitamente. Lo cual es una cosa buena : el código que no tiene que ejecutarse es el más rápido.
Para verificar que es una optimización, puede intentar hacer que algunas de las variables sean volátiles (ejemplo en vivo).
Eso es porque para el compilador del segundo caso sabe que no hay efectos secundarios y optimiza todo https://godbolt.org/ g / CnojEi clang 4.0.0 con -O3
solo hojas:
call_add1():
rep ret
main:
xor eax, eax
ret
Y no obtienes marketing sobre la magia del bucle.
En el primer caso, el compilador produce algún cuerpo para la función, porque la función modifica el argumento. Si compiló esto como un archivo objeto. Podría vincular a esta función y funcionaría. Supongo que si los parámetros fueran constantes, entonces tal vez la función también quedaría con el cuerpo vacío.
Cuando imprime el contenido, los programas no son idénticos, pero ambos usan instrucciones vectorizadas: https://godbolt.org/ g / KF1kNt
Preguntas relacionadas
Nuevas preguntas
c++
C ++ es un lenguaje de programación de propósito general. Originalmente fue diseñado como una extensión de C, y tiene una sintaxis similar, pero ahora es un lenguaje completamente diferente. Use esta etiqueta para preguntas sobre el código (que se compilará) con un compilador de C ++. Utilice una etiqueta específica de la versión para preguntas relacionadas con una revisión estándar específica [C ++ 11], [C ++ 14], [C ++ 17] o [C ++ 20] etc.