Uint8至mm0寄存器

奥韦德

我一直在玩这个演示文稿中的示例(幻灯片41)。

就我而言,它执行alpha混合。

MOVQ mm0, alpha//4 16-b zero-padding α
MOVD mm1, A //move 4 pixels of image A 
MOVD mm2, B //move 4 pixels of image B
PXOR mm3 mm3 //clear mm3 to all zeroes 
//unpack 4 pixels to 4 words
PUNPCKLBW mm1, mm3 // Because B -A could be
PUNPCKLBW mm2, mm3 // negative, need 16 bits
PSUBW mm1, mm2 //(B-A) 
PMULHW mm1, mm0 //(B-A)*fade/256 
PADDW mm1, mm2 //(B-A)*fade + B 
//pack four words back to four bytes
PACKUSWB mm1, mm3

我想用汇编器在c中重写它。

现在,我有这样的事情:

void fade_mmx(SDL_Surface* im1,SDL_Surface* im2,Uint8 alpha, SDL_Surface* imOut)
{
    int pixelsCount = imOut->w * im1->h;
    
    Uint32 *A = (Uint32*) im1->pixels;
    Uint32 *B = (Uint32*) im2->pixels;
    Uint32 *out = (Uint32*) imOut->pixels;
    Uint32 *end = out + pixelsCount;

    __asm__ __volatile__ (
            "\n\t movd  (%0), %%mm0"
            "\n\t movd  (%1), %%mm1"
            "\n\t movd  (%2), %%mm2"
            "\n\t pxor       %%mm3, %%mm3"
            "\n\t punpcklbw  %%mm3, %%mm1"
            "\n\t punpcklbw  %%mm3, %%mm2"
            "\n\t psubw      %%mm2, %%mm1"
            "\n\t pmulhw     %%mm0, %%mm1"
            "\n\t paddw      %%mm2, %%mm1"
            "\n\t packuswb   %%mm3, %%mm1"
    : : "r" (alpha), "r" (A), "r" (B), "r" (out), "r" (end)
    );
    __asm__("emms" : : );
}

编译时收到以下消息:Error: (%dl) is not a valid base/index expression关于汇编器的第一行。我怀疑这是因为alphaUint8,我试图铸造,但后来我得到一个分段错误。在示例中,他们正在谈论4 16-b zero-padding α哪个对我来说不是很清楚。

福兹

您可以在复制到MM reg之前alpha使用标量乘以广播到64位0x0001000100010001ULL另一种选择是将的8位整数零扩展为32位movd,然后pshufw复制它。

您的asm也存在各种安全问题。

#include <SDL/SDL.h>
#include <stdint.h>

void fade_mmx(SDL_Surface* im1,SDL_Surface* im2,Uint8 alpha, SDL_Surface* imOut)
{
    int pixelsCount = imOut->w * im1->h;

    Uint32 *A = (Uint32*) im1->pixels;
    Uint32 *B = (Uint32*) im2->pixels;
    Uint32 *out = (Uint32*) imOut->pixels;
    Uint32 *end = out + pixelsCount;

    Uint64 alphas = (Uint64)alpha * 0x0001000100010001ULL;

    __asm__ __volatile__ (
            "\n\t movd  %0, %%mm0"
            "\n\t movd  %1, %%mm1"
            "\n\t movd  %2, %%mm2"
            "\n\t pxor       %%mm3, %%mm3"
            "\n\t punpcklbw  %%mm3, %%mm1"
            "\n\t punpcklbw  %%mm3, %%mm2"
            "\n\t psubw      %%mm2, %%mm1"
            "\n\t pmulhw     %%mm0, %%mm1"
            "\n\t paddw      %%mm2, %%mm1"
            "\n\t packuswb   %%mm3, %%mm1"
    : // you're probably going to want an "=m"(*something) memory output here
    : "r" (alphas), "m" (*A), "m" (*B), "r" (out), "r" (end)
    : "mm0", "mm1", "mm2", "mm3");
    __asm__("emms" : : );
}

volatile如果编译器知道所有的输入和输出,而不是依赖"memory"破坏者,则asm语句不是必需的(就像这里,没有输出,仅读取作为输入操作数的寄存器和内存。)

对于32位代码,请替换"r"(alphas)"m"(alphas)"rm"(alphas)用来让编译器选择。(但对于32位,使用pshufw绝对要好,而不是让编译器将64位乘法结果存储为2个32位的一半,然后在用movq重新加载时会遇到存储转发停顿。内在的特性将使决策变慢_mm_set1_epi8(alpha)循环外使用的编译器)。

请注意,我还添加了必要的清除程序列表,并用包含要取消引用的指针的寄存器操作数替换为引用了要取消引用的内存的内存操作数,从而使gcc可以推断出要访问的内存

请注意,如果您不解决这些问题,gcc将会感到不满意,并且您的代码行为也将不确定,可能会以神秘且难以调试的方式失败。除非您完全了解自己在做什么,否则不要使用内联汇编。考虑将内在函数用作更安全,可能更有效的替代方法。https://gcc.gnu.org/wiki/DontUseInlineAsm)。

__m128i向量的SSE2使得一次处理4个像素变得很容易,而不是pack通过零填充来浪费2或1浪费您一半的吞吐量。punpckhbw用于补充punpcklbw设置)。MMX已过时,以至于现代CPU的某些指令的MMX版本的吞吐量比等效的128位SSE2 XMM指令的吞吐量低。

本文收集自互联网,转载请注明来源。

如有侵权,请联系[email protected] 删除。

编辑于
0

我来说两句

0条评论
登录后参与评论

相关文章