Xeon-Phi Knights 랜딩 코어는 exp2
명령어 vexp2pd
(내장형 _mm512_exp2a23_pd
)을 가지고 있습니다. 인텔 C++ 컴파일러는 컴파일러와 함께 제공되는 SVML (Short Vector Math Library)을 사용하여 exp
함수를 벡터화 할 수 있습니다. 특히, fx __svml_exp8
을 호출합니다.은 SVML의 함수 호출을 오버라이드합니다.
그러나 디버거를 거치면 은 vexp2pd
명령어를 사용하고 있지 않습니다. 이는 많은 FMA 작업과 관련된 복잡한 기능입니다. 나는 vexp2pd
이 exp
보다 덜 정확하다는 것을 이해합니다. 그러나 -fp-model fast=1
(기본값) 또는 fp-model fast=2
을 사용하면 컴파일러가이 명령어를 사용하지만 예상하지는 않습니다.
두 가지 질문이 있습니다.
- 컴파일러를 사용하여
vexp2pd
을 얻는 방법이 있습니까? __svml_exp8
에 대한 호출을 안전하게 재정의하려면 어떻게해야합니까?
두 번째 질문에 대해서는 이것이 지금까지 내가 한 것입니다.
//exp(x) = exp2(log2(e)*x)
extern "C" __m512d __svml_exp8(__m512d x) {
return _mm512_exp2a23_pd(_mm512_mul_pd(_mm512_set1_pd(M_LOG2E), x));
}
이 안전한가요? 예를 들어 더 나은 솔루션이 있습니까? 기능을 인라인하는 사람? 아래의 테스트 코드에서 오버 라이드하지 않은 경우보다 약 3 배 빠릅니다.
//https://godbolt.org/g/adI11c
//icpc -O3 -xMIC-AVX512 foo.cpp
#include <math.h>
#include <stdio.h>
#include <x86intrin.h>
extern "C" __m512d __svml_exp8(__m512d x) {
//exp(x) = exp2(log2(e)*x)
return _mm512_exp2a23_pd(_mm512_mul_pd(_mm512_set1_pd(M_LOG2E), x));
}
void foo(double * __restrict x, double * __restrict y) {
__assume_aligned(x, 64);
__assume_aligned(y, 64);
for(int i=0; i<1024; i++) y[i] = exp(x[i]);
}
int main(void) {
double x[1024], y[1024];
for(int i=0; i<1024; i++) x[i] = 1.0*i;
for(int r=0; r<1000000; r++) foo(x,y);
double sum=0;
//for(int i=0; i<1024; i++) sum+=y[i];
for(int i=0; i<8; i++) printf("%f ", y[i]); puts("");
//printf("%lf",sum);
}
'vexp2pd'를 사용하여 30 비트 정밀도를 버리도록 컴파일러에게 요청합니다. 그것은 빠른 수학으로도 그렇게하지 않을 것입니다. – Mysticial
@Mysticial 컴파일러에서'vrcp28pd' (실제로는 [https://godbolt.org/g/Wya9Ic])를 볼 수 있습니다. 그래서 빠른 상호를 사용한다면 왜 빠른 'exp'가 아니겠습니까? 그 코드를 보면서 상호 코드를 살펴보면 뉴턴이나 다른 것의 반복을하는 것처럼 보일 수도 있습니다 (그렇지 않으면 모든 FMA와 관련이 있습니다).그것은 왜 그것이 빠른 상호가 아닌 빠른'exp'를 사용하는지 설명 할 수 있습니다. –
나는'vfixupimmpd'에 대해 들어 본 적이 없다. 이상한 지시. 본질 가이드에 따르면 AVXVL이 필요하지만 AVXVL이없는 KNL 용으로 생성합니다. –