需要注意的是,您需要更具体地了解您如何编译内容,并可能提供最少的示例。我知道这可能不是最好的答案,但我认为它够好。它变长了,但这是因为代码。
下面的工作的底线是它应该是安全的离开编译器并使用适当的编译器标志。在底部,我举了一个例子说明如何使用本地寄存器变量,但它可能不会很有用(它很容易被忽略)。你可以使用全局寄存器变量,但它不会产生任何好结果,并且不鼓励。
我的设置是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