如何使用128位C变量和xmm 128位asm?

前端之家收集整理的这篇文章主要介绍了如何使用128位C变量和xmm 128位asm?前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
gcc中,我想通过asm代码做一个128位xor与2 C变量,如何?
asm (
    "movdqa %1,%%xmm1;"
    "movdqa %0,%%xmm0;"
     "pxor %%xmm1,%%xmm0;"
     "movdqa %%xmm0,%0;"

    :"=x"(buff) /* output operand */
    :"x"(bu),"x"(buff)
    :"%xmm0","%xmm1"
    );

但我有一个分段故障错误;
这是objdump输出

movq   -0x80(%rbp),%xmm2

movq   -0x88(%rbp),%xmm3

movdqa %xmm2,%xmm1

movdqa %xmm2,%xmm0

pxor   %xmm1,%xmm0

movdqa %xmm0,%xmm2

movq   %xmm2,-0x78(%rbp)

解决方法

如果变量不是16字节对齐,您将看到segfault问题. The CPU can’t MOVDQA to/from unaligned memory addresses,并将产生一个处理器级别的“GP异常”,提示操作系统删除您的应用程序.

您声明的C变量(堆栈,全局)或在堆上分配通常不会与16字节边界对齐,但偶尔您可能会偶然获得一个对齐的.您可以通过使用__m128或__m128i数据类型来指示编译器确保正确对齐.每个都声明一个正确对齐的128位值.

此外,读取objdump,看起来编译器使用代码将asm序列包装,以使用MOVQ指令将操作数从堆栈复制到xmm2和xmm3寄存器,只有使您的asm代码将值复制到xmm0和xmm1.在xore0进入xmm0之后,包装器将结果复制到xmm2,然后将其复制回堆栈.总体而言,效率并不高. MOVQ每次复制8个字节,and expects (under some circumstances),an 8-byte aligned address.获取未对齐的地址,它可能会失败,就像MOVDQA一样.然而,包装器代码向BP寄存器添加了一个对齐的偏移量(-0x80,-0x88和更高的-0x78),这可能包含或可能不包含一个对齐的值.总而言之,生成代码中没有对齐的保证.

以下确保参数和结果存储在正确对齐的内存位置,并且似乎工作正常:

#include <stdio.h>
#include <emmintrin.h>

void print128(__m128i value) {
    int64_t *v64 = (int64_t*) &value;
    printf("%.16llx %.16llx\n",v64[1],v64[0]);
}

void main() {
    __m128i a = _mm_setr_epi32(0x00ffff00,0x00ffff00,0x10ffff00),/* low dword first! */
            b = _mm_setr_epi32(0x0000ffff,0x0000ffff,0x0000ffff),x;

    asm (
        "movdqa %1,%%xmm0;"      /* xmm0 <- a */
        "movdqa %2,%%xmm1;"      /* xmm1 <- b */
        "pxor %%xmm1,%%xmm0;"    /* xmm0 <- xmm0 xor xmm1 */
        "movdqa %%xmm0,%0;"      /* x <- xmm0 */

        :"=x"(x)          /* output operand,%0 */
        :"x"(a),"x"(b)   /* input operands,%1,%2 */
        :"%xmm0","%xmm1"  /* clobbered registers */
    );

    /* printf the arguments and result as 2 64-bit hex values */
    print128(a);
    print128(b);
    print128(x);
}

编译(gcc,ubuntu 32位)

gcc -msse2 -o app app.c

输出

10ffff0000ffff00 00ffff0000ffff00
0000ffff0000ffff 0000ffff0000ffff
10ff00ff00ff00ff 00ff00ff00ff00ff

在上面的代码中,_mm_setr_epi32用于初始化a和b与128位值,因为编译器可能不支持128个整数文字.

print128写出128位整数的十六进制表示,因为printf可能无法这样做.

以下是较短的,并避免了一些重复的复制.编译器添加隐藏的包装movdqa来使pxor%2,%0神奇地工作,而不必自己加载寄存器:

#include <stdio.h>
#include <emmintrin.h>

void print128(__m128i value) {
    int64_t *px = (int64_t*) &value;
    printf("%.16llx %.16llx\n",px[1],px[0]);
}

void main() {
    __m128i a = _mm_setr_epi32(0x00ffff00,b = _mm_setr_epi32(0x0000ffff,0x0000ffff);

    asm (
        "pxor %2,%0;"    /* a <- b xor a  */

        :"=x"(a)          /* output operand,%2 */
        );

    print128(a);
}

如前所述:

gcc -msse2 -o app app.c

输出

10ff00ff00ff00ff 00ff00ff00ff00ff

或者,如果您想避免内联汇编,可以使用SSE intrinsics instead(PDF).那些内嵌函数/宏封装了类似C语法的MMX / SSE指令. _mm_xor_si128将您的任务减少到一个通话:

#include <stdio.h>
#include <emmintrin.h>

void print128(__m128i value) {
    int64_t *v64 = (int64_t*) &value;
    printf("%.16llx %.16llx\n",v64[0]);
}

void main()
{
    __m128i x = _mm_xor_si128(
        _mm_setr_epi32(0x00ffff00,/* low dword first !*/
        _mm_setr_epi32(0x0000ffff,0x0000ffff));

    print128(x);
}

编译:

gcc -msse2 -o app app.c

输出

10ff00ff00ff00ff 00ff00ff00ff00ff
原文链接:https://www.f2er.com/c/113429.html

猜你在找的C&C++相关文章