我有一个AVX内核我写的做复杂的共轭乘法:
__attribute__((noinline))
static __attribute__((target("avx"))) void asm_vcmulcc(
cfloat* __restrict__ cc, const cfloat* __restrict__ aa, const cfloat* __restrict__ bb, ssize_t size) {
ssize_t iters = size/4;
ssize_t rem = size-iters*4;
__asm__(
".section .rodata # constant section\n\t"
".align 32 # 32 byte alignment\n\t"
"LC%=:\n\t"
" .long 0x80000000\n\t"
" .long 0x80000000\n\t"
" .long 0x80000000\n\t"
" .long 0x80000000\n\t"
" .long 0x80000000\n\t"
" .long 0x80000000\n\t"
" .long 0x80000000\n\t"
" .long 0x80000000\n\t"
""
".text\n\t"
" vmovaps LC%=(%%rip), %%ymm4\n\t"
" xorl %%eax, %%eax\n\t"
""
".p2align 4\n\t"
"LOOP%=:\n\t"
" vmovups (%[bb],%%rax,1), %%ymm3\n\t"
" vmovups (%[aa],%%rax,1), %%ymm1\n\t"
" vpermilps $0xa0, %%ymm1, %%ymm2\n\t"
" vpermilps $0xf5, %%ymm1, %%ymm0\n\t"
" vmulps %%ymm3, %%ymm2, %%ymm2\n\t"
" vxorps %%ymm4, %%ymm0, %%ymm0\n\t"
" vpermilps $0xb1, %%ymm3, %%ymm3\n\t"
" vmulps %%ymm3, %%ymm0, %%ymm0\n\t"
" vaddsubps %%ymm0, %%ymm2, %%ymm0\n\t"
" vmovups %%ymm0, (%[cc],%%rax,1)\n\t"
" addq $32, %%rax\n\t"
" cmpq %[bytes], %%rax\n\t"
" jl LOOP%=\n\t"
:
: [aa] "r" (aa), [bb] "r" (bb), [cc] "r" (cc), [bytes] "r" (iters*4*sizeof(cfloat))
: "ymm0", "ymm1", "ymm2", "ymm3", "ymm4", "rax", "memory"
);
if (rem > 0) {
aa += iters*4;
bb += iters*4;
cc += iters*4;
for (ssize_t ii=0; ii < rem; ii++) {
cc[ii] = conj(aa[ii])*bb[ii];
}
}
}
适用于英特尔编译器,gcc&gt; = 5,但gcc&lt; 5个错误输出(这是g ++ 4.8.5):
> g++ -std=c++0x -I. -c -mavx lib.cc -O3 -o lib.o
lib.cc: In function ‘void avx_vcmulcc(prelude::{anonymous}::cfloat*, const cfloat*, const cfloat*, int)’:
lib.cc:80:6: error: unknown register name ‘ymm4’ in ‘asm’
);
^
lib.cc:80:6: error: unknown register name ‘ymm3’ in ‘asm’
lib.cc:80:6: error: unknown register name ‘ymm2’ in ‘asm’
lib.cc:80:6: error: unknown register name ‘ymm1’ in ‘asm’
lib.cc:80:6: error: unknown register name ‘ymm0’ in ‘asm’
有或没有-mavx选项。显然,允许编译器发出AVX,但是不会让它通过unmolested?是否有一个隐藏的选项来抑制这个?
答案 0 :(得分:2)
您需要指定XMM寄存器,因为从编译器的角度来看,这些是被破坏的寄存器,因为编译器对YMM寄存器一无所知。您应该添加一个编译器条件并在支持它们的编译器上使用YMM寄存器,因为理论上可以使用XMM寄存器而不会干扰仅YMM寄存器部分(使用SSE2指令),未来的GCC版本可能会使用该信息(虽然这似乎不太可能)。 this document on transition penalities中提到了这一点。更多详情请见Intel Advanced Vector Extensions Programming Reference。
请注意,您可以将.long
数组定义为具有used
属性的静态数组,并从内联程序集引用该数组。如果内联汇编语句被编译器复制或多次使用,这将避免重复常量。 (或者,您可以为数组使用m
输入操作数,并删除数组上的used
属性,这也有利于它在大内存模型中正常工作。)