内联汇编+指针管理

时间:2015-07-31 18:29:02

标签: c++ inline-assembly avx2

关于在C ++代码中使用内联汇编,我是非常新的。 我想要做的基本上是一种带有模数为32的指针的记忆。

在C ++中,代码使用如下:

void my_memcpy(const std::uint8_t* in,std::uint8_t* out,const std::size_t& sz)
{

       assert((sz%32 == 0));

    for(const std::uint8_t* it = beg; it != (beg+sz);it+=32,out+=32)
    {
      __m256i = _mm256_stream_load_si256(reinterpret_cast<__m256i*>(it));
      _mm256_stream_si256(reinterpret_cast<__m256i*>(out),tmp);

    }            
}

我已经做了一些内联汇编,但每次事先都知道输入选项卡的大小和输出选项卡。

所以我尝试了这个:

void my_memcpy(const std::uint8_t* in,std::uint8_t* out,const std::size_t& sz)
{

     assert((sz%32 == 0));

    __asm__ volatile(

                "mov %1, %%eax \n"
                "mov $0, %%ebx \n"

                "L1: \n"

                "vmovntdqa (%[src],%%ebx), %%ymm0 \n"
                "vmovntdq  %%ymm0, (%[dst],%%ebx) \n"

                "add %%ebx, $32 \n"

                "cmp %%eax, %%ebx \n"
                "jz L1 \n"

                :[dst]"=r"(out)
                :[src]"r"(in),"m"(sz)
                :"memory"
                );

}

G ++告诉我:

Error: unsupported instruction `mov'
Error: `(%rdi,%ebx)' is not a valid base/index expression
Error: `(%rdi,%ebx)' is not a valid base/index expression
Error: operand type mismatch for `add'

所以我尝试了这个:

void my_memcpy(const std::uint8_t* in,std::uint8_t* out,const std::size_t& sz)
{

     assert((sz%32 == 0));
__asm__ volatile(

            "mov %1, %%eax \n"
            "mov $0, %%ebx \n"

            "L1: \n"

            "vmovntdqa %%ebx(%[src]), %%ymm0 \n"
            "vmovntdq  %%ymm0, (%[dst],%%ebx) \n"

            "add %%ebx, $32 \n"

            "cmp %%eax, %%ebx \n"
            "jz L1 \n"

            :[dst]"=r"(out)
            :[src]"r"(in),"m"(sz)
            :"memory"
                );

}

我从G ++获得:

Error: unsupported instruction `mov'
Error: junk `(%rdi)' after register
Error: `(%rdi,%ebx)' is not a valid base/index expression
Error: operand type mismatch for `add'

在每种情况下,我试图找到一个没有成功的解决方案。 我也遇到了这个解决方案:

void my_memcpy(const std::uint8_t* in,std::uint8_t* out,const std::size_t& sz)
{

    __asm__ volatile (
          ".intel_syntax noprefix;"

          "mov eax, [SZ];"
          "mov ebx, 0;"

          "L1 : "

          "vmovntdqa ymm0, [src+ebx];"
          "vmovntdq [dst+ebx], ymm0;"

          "add ebx, 32 \n"

          "cmp ebx, eax \n"
          "jz L1 \n"
                ".att_syntax;"
          : [dst]"=r"(out)
          : [SZ]"m"(sz),[src]"r"(in)
          : "memory");



}

G ++:

undefined reference to `SZ'
undefined reference to `src'
undefined reference to `dst'

这个消息看起来很常见,但我不知道在这种情况下如何修复它。

我知道我的尝试并不严格代表我在C ++中编写的代码。

我想了解我尝试过的错误,以及如何尽可能接近我的C ++函数。

提前感谢。

1 个答案:

答案 0 :(得分:2)

您的第一个示例是最正确的并且有以下错误:

  • 它使用32位寄存器而不是64位。
  • 更改了3个寄存器,这些寄存器未指定为输出或符号。
  • EAX加载了源地址,而不是大小。
  • dst被声明为输出,应该是输入。
  • add指令的参数是错误的方式,在AT&amp; T语法中,目标寄存器是最后一个。
  • 使用非本地标签,如果asm语句重复,则会失败,例如通过内联。

以下表现问题:

  • sz参数通过引用传递。 (也可能会影响调用函数的优化)
  • 然后将其作为内存参数传递给asm,这需要将其写入内存。
  • 然后将其复制到另一个注册表。
  • 使用固定寄存器而不是让编译器选择。

这是一个固定版本,它不比具有内在函数的等效C ++快:

void my_memcpy(const std::uint8_t* in,std::uint8_t* out,const std::size_t sz)
{
     std::size_t count = 0;
     __m256i temp;

     assert((sz%32 == 0));

    __asm__ volatile(

                "1: \n"

                "vmovntdqa (%[src],%[count]), %[temp] \n"
                "vmovntdq  %[temp], (%[dst],%[count]) \n"

                "add $32, %[count] \n"

                "cmp %[sz], %[count] \n"
                "jz 1b \n"

                :[count]"+r"(count), [temp]"=x"(temp)
                :[dst]"r"(out), [src]"r"(in), [sz]"r"(sz)
                :"memory", "cc"
                );

}

源和目标参数是memcpy的另一种可能混淆的方式。

您的英特尔语法版本添加也无法使用正确的语法来引用参数(例如%[dst])。