需要注意的是,您需要更具體地瞭解您如何編譯內容,並可能提供最少的示例。我知道這可能不是最好的答案,但我認爲它夠好。它變長了,但這是因爲代碼。
下面的工作的底線是它應該是安全的離開編譯器並使用適當的編譯器標誌。在底部,我舉了一個例子說明如何使用本地寄存器變量,但它可能不會很有用(它很容易被忽略)。你可以使用全局寄存器變量,但它不會產生任何好結果,並且不鼓勵。
我的設置是Intel(R) Core(TM) i7-4770 CPU
,gcc version 4.9.2
和clang version 3.5.0
。以下代碼確實將avx_scalar
存儲在xmm
寄存器中,其中-O1
及以上。沒有什麼或-O0
他們沒有。要生成彙編代碼爲:
[clang++|g++] -march=native -S -Ox ./sse.cpp
,
其中x
是優化級別。
有趣的是,與-march=archive
這兩個編譯器決定使用SSE4.1版本超過傳統SSE在任何情況下我測試,即使我在代碼本身中使用傳統的SSE內在函數。這很好。
我還測試了使用smmintrin.h
這是SSE4.1頭。沒有國旗gcc使用傳統的SSE和鐺無法與error: "SSE4.1 instruction set not enabled"
編譯。通過xmmintrin.h
這是傳統的SSE頭文件,這兩個編譯器在出現標誌的情況下生成AVX版本,而在遺漏的時候編譯器生成AVX版本。
測試代碼avx.cpp
:
Revelvant部分g++ -march=native -S -O2 ./avx.cpp
extern "C"
{
#include <smmintrin.h>
}
const float scalar = 3.14;
const __m128 avx_scalar = _mm_set1_ps(scalar);
__m128 vector;
__m128 its_me(){
__m128 ret;
__m128 result;
for(int i = 0; i < 1000; ++i)
{
vector = _mm_set_ps(i*1,i*2,i*3,i*4);
result = _mm_mul_ps(vector, avx_scalar);
ret = _mm_add_ps(ret, result);
}
return ret;
}
:
.LFB639:
.cfi_startproc
vmovaps _ZL10avx_scalar(%rip), %xmm5
xorl %edx, %edx
.p2align 4,,10
.p2align 3
.L2:
leal (%rdx,%rdx), %ecx
vxorps %xmm2, %xmm2, %xmm2
vxorps %xmm1, %xmm1, %xmm1
vxorps %xmm3, %xmm3, %xmm3
leal 0(,%rdx,4), %eax
vcvtsi2ss %ecx, %xmm3, %xmm3
vxorps %xmm4, %xmm4, %xmm4
vcvtsi2ss %eax, %xmm2, %xmm2
leal (%rcx,%rdx), %eax
vcvtsi2ss %edx, %xmm4, %xmm4
addl $1, %edx
vcvtsi2ss %eax, %xmm1, %xmm1
vunpcklps %xmm4, %xmm3, %xmm3
vunpcklps %xmm1, %xmm2, %xmm1
vmovlhps %xmm3, %xmm1, %xmm1
vmulps %xmm5, %xmm1, %xmm2
vaddps %xmm2, %xmm0, %xmm0
cmpl $1000, %edx
jne .L2
vmovaps %xmm1, vector(%rip)
ret
.cfi_endproc
而且clang++ -march=native -S -O2 ./avx.cpp
:
# BB#0:
xorl %eax, %eax
movl $4, %ecx
movl $2, %edx
vmovaps _ZL10avx_scalar(%rip), %xmm1
xorl %esi, %esi
# implicit-def: XMM0
.align 16, 0x90
.LBB0_1: # =>This Inner Loop Header: Depth=1
leal -2(%rdx), %r8d
leal -4(%rcx), %edi
vmovd %edi, %xmm2
vpinsrd $1, %eax, %xmm2, %xmm2
vpinsrd $2, %r8d, %xmm2, %xmm2
vpinsrd $3, %esi, %xmm2, %xmm2
vcvtdq2ps %xmm2, %xmm2
vmulps %xmm1, %xmm2, %xmm2
vaddps %xmm2, %xmm0, %xmm0
leal 1(%rsi), %r8d
leal 3(%rax), %edi
vmovd %ecx, %xmm2
vpinsrd $1, %edi, %xmm2, %xmm2
vpinsrd $2, %edx, %xmm2, %xmm2
vpinsrd $3, %r8d, %xmm2, %xmm2
vcvtdq2ps %xmm2, %xmm2
vmulps %xmm1, %xmm2, %xmm3
vaddps %xmm3, %xmm0, %xmm0
addl $2, %esi
addl $6, %eax
addl $8, %ecx
addl $4, %edx
cmpl $1000, %esi # imm = 0x3E8
jne .LBB0_1
# BB#2:
vmovaps %xmm2, vector(%rip)
retq
爲了記錄,您可以手動把本地變量到寄存器,但鐺完全忽略與-01
和above.I GCC鼓勵尋找xmm13
在輸出g++ -march=native -S -Ox ./avx.cpp
與下面的代碼不同x
值(假設你有你的CPU至少13個XMM寄存器):
extern "C"
{
#include <xmmintrin.h>
}
const float scalar = 3.14;
__m128 its_me(){
__m128 vector;
register __m128 avx_scalar asm ("xmm13") = _mm_set1_ps(scalar); // that's how you do it in gcc.
//const __m128 avx_scalar = _mm_set1_ps(scalar);
__m128 ret;
__m128 result;
for(int i = 0; i < 1000; ++i)
{
vector = _mm_set_ps(i*1,i*2,i*3,i*4);
result = _mm_mul_ps(vector, avx_scalar);
ret = _mm_add_ps(ret, result);
}
return ret;
}
您應該使用內置向量支持和/或內在函數。另外,如果你想用-masm = intel的intel語法進行編譯,不要試圖繞過編譯器的後面。至於保留一個寄存器,這也可能是一個壞主意,但gcc允許全局寄存器變量。 – Jester 2015-02-23 17:20:24
如http://stackoverflow.com/a/9080351/1133179幫助中所述,Umm沒有聲明'const __mm128'變量? – luk32 2015-02-23 17:22:00
@Jester -masm = intel打破了一些提升依賴關係,試過之前。 – Marandil 2015-02-23 21:38:47