asm中的寄存器数组

时间:2018-02-25 19:06:36

标签: c gcc x86 sse inline-assembly

如何在asm()中定义指向XMM寄存器的指针? 就像在循环中访问数组元素一样,如何使用计数器访问asm中的寄存器? 我尝试在以下代码中执行此操作:

float *f=(float*)_aligned_malloc(64,16);
for(int i=0;i<4;i++)
    asm volatile
        (
        "movaps (%1),%%xmm%0"
        :
        :"r"(i),"r"(f+4*i)
        :"%xmm%0"
        );

但是编译器给了我这个错误:

unknown register name '%xmm%0' in 'asm'

2 个答案:

答案 0 :(得分:3)

与使用汇编程序宏或实际手动展开相比,这听起来像是一个可怕的想法。如果gcc决定不完全展开循环,你的代码将完全破解,因为它只能用于编译时常量索引。

此外,没有办法告诉编译器你将结果放在哪个寄存器中,所以这基本上没用了。我只是回答使用GNU C inline-asm语法时的愚蠢行为,不是因为这个答案在任何项目中都可能有用。

也就是说,您可以使用"i"约束和a c operand modifier将此格式设置为裸号格式,例如1而不是$1

void *_aligned_malloc(int, int);
void foo()
{
    float *f=(float*)_aligned_malloc(64,16);
    for(int i=0;i<4;i++) {
        asm volatile (
        "movaps %[input],%%xmm%c[regnum]"
        :
        // only compiles with optimization enabled.
        :[regnum] "i"(i), [input] "m"(f[4*i])
        :"%xmm0", "%xmm1", "%xmm2", "%xmm3"
        );
    }
}

gcc和clang,-O3,能够完全展开并为每次迭代生成i一个可以匹配"i"约束的编译时常量。 This compiles on Godbolt

# gcc7.3 -O3
foo():
    subq    $8, %rsp
    movl    $16, %esi
    movl    $64, %edi
    call    _aligned_malloc(int, int)       # from a dummy prototype so it compiles
    movaps (%rax),%xmm0
    movaps 16(%rax),%xmm1          # compiler can use addressing modes because I switched to an "m" constraint
    movaps 32(%rax),%xmm2
    movaps 48(%rax),%xmm3
    vzeroupper                     # XMM clobbers also include YMM, and I guess gcc assumes you might have dirtied the upper lanes.
    addq    $8, %rsp
    ret

请注意,我只告诉编译器读取每组4的第一个float

ICC -O3即使catastrophic error: Cannot match asm operand constraint也说-O3。当然,在禁用优化的情况下,gcc和clang会遇到同样的问题。例如,gcc -O0会说:

<source>: In function 'void foo()':
<source>:11:10: warning: asm operand 0 probably doesn't match constraints
         );
          ^
<source>:11:10: error: impossible constraint in 'asm'
Compiler returned: 1

因为没有优化,i不是编译时常量,不能匹配"i"(立即)约束。

显然你不能使用"r"约束;如果编译器选择%xmm%eax,那将填充asm模板eax

无论如何,这是无用的,因为你不能使用目的地寄存器。您所能做的就是告诉编译器所有可能的目标寄存器都被破坏了。在一个asm语句中写入被破坏的寄存器是不安全的,然后假设该值仍然存在于稍后的asm语句中。

与所有其他体系结构一样,x86无法使用运行时值索引体系结构寄存器。注册号必须硬编码到指令流中。

(有些微控制器,比如AVR,有内存映射寄存器,所以你可以通过索引寄存器文件别名的内存来索引它们。但这种情况很少见,而且x86不会这样做。它会干扰掉 - 按照与自修改代码类似的方式执行顺序执行.BTW,SMC(或分支到16个不同版本的指令之一)是运行时索引寄存器文件的唯一选项。)

答案 1 :(得分:2)

你不能 - 没有办法索引寄存器文件。

如果要按顺序使用多个寄存器,则需要展开循环并明确命名每个寄存器。