C代码中的SSE2指令

C代码中的SSE2指令,c,gcc,assembly,sse,C,Gcc,Assembly,Sse,我正在尝试对c代码进行反向工程,但我不能真正理解汇编的这一部分。我知道这是SSE扩展的一部分。然而,有些东西确实与我在x86指令中所习惯的有所不同 static int sad16_sse2(void *v, uint8_t *blk2, uint8_t *blk1, int stride, int h) { int ret; __asm__ volatile( "pxor %%xmm6, %%xmm6 \n\t" ASMAL

我正在尝试对c代码进行反向工程,但我不能真正理解汇编的这一部分。我知道这是SSE扩展的一部分。然而,有些东西确实与我在x86指令中所习惯的有所不同

static int sad16_sse2(void *v, uint8_t *blk2, uint8_t *blk1, int stride, int h)
{
    int ret;
    __asm__ volatile(
        "pxor %%xmm6, %%xmm6            \n\t"
        ASMALIGN(4)
        "1:                             \n\t"
        "movdqu (%1), %%xmm0            \n\t"
        "movdqu (%1, %3), %%xmm1        \n\t"
        "psadbw (%2), %%xmm0            \n\t"
        "psadbw (%2, %3), %%xmm1        \n\t"
        "paddw %%xmm0, %%xmm6           \n\t"
        "paddw %%xmm1, %%xmm6           \n\t"
        "lea (%1,%3,2), %1              \n\t"
        "lea (%2,%3,2), %2              \n\t"
        "sub $2, %0                     \n\t"
        " jg 1b                         \n\t"
        : "+r" (h), "+r" (blk1), "+r" (blk2)
        : "r" ((x86_reg)stride)
    );
    __asm__ volatile(
        "movhlps %%xmm6, %%xmm0         \n\t"
        "paddw   %%xmm0, %%xmm6         \n\t"
        "movd    %%xmm6, %0             \n\t"
        : "=r"(ret)
    );
    return ret;
}

什么是%1、%2和%3?(%1、%2、%3)是什么意思?还有,“+r”、“-r”、“=r”是什么意思?

你会想看看这个


百分号是指令操作数。

内联汇编程序的工作原理与宏预处理器类似。只有一个前导百分比的操作数将按输入参数在参数列表中出现的顺序替换为输入参数,在这种情况下:

%0    h                output, register, r/w
%1    blk1             output, register, r/w
%2    blk2             output, register, r/w
%3    (x86_reg)stride  input, register, read only
参数是正常的C表达式。它们可以通过“约束”进一步指定,在这种情况下,“r”表示值应该在寄存器中,而不是“m”,后者是内存操作数。约束修饰符“=r”使其成为仅写操作数,“+r”是读写操作数,“r”和正常读操作数

在第一个冒号之后显示输出操作数,在第二个冒号之后显示输入操作数,在可选的第三个冒号之后显示闭合寄存器

因此指令序列计算
blk1
blk2
的每个字节的绝对差值之和。这在16字节块中发生,因此如果
stride
为16,则块是连续的,否则会有孔。每个指令出现两次,因为完成了一些最小的循环展开,
h
参数是要处理的32字节块的数量。第二个asm块似乎没有用,因为
psadbw
指令只在目标寄存器的低位16位求和。(是否省略了一些代码?

此代码使用两个不相连的内联汇编块是无效的;它可能会工作,但不能保证一定会工作,因为编译器在输入第二个
\u asm\uuu
块之前,可能会选择使用第二个
\uu asm\uu
块的“非声明输入”(regs
%xmm0
/
%xmm6
)执行某些操作。有关如何解决此问题的详细信息,请参阅。