内联汇编+指针管理
inline assembly + pointer management
我对在 C++ 代码中使用内联汇编非常陌生。
我想做的基本上是一种大小为模数 32 的指针的 memcopy。
在 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 [=11=], %%ebx \n"
"L1: \n"
"vmovntdqa (%[src],%%ebx), %%ymm0 \n"
"vmovntdq %%ymm0, (%[dst],%%ebx) \n"
"add %%ebx, \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 [=13=], %%ebx \n"
"L1: \n"
"vmovntdqa %%ebx(%[src]), %%ymm0 \n"
"vmovntdq %%ymm0, (%[dst],%%ebx) \n"
"add %%ebx, \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++ 函数。
提前致谢。
你的第一个例子是最正确的,但有以下错误:
- 它使用 32 位寄存器而不是 64 位。
- 3 个未指定为输出或破坏的寄存器已更改。
- EAX 加载源地址,而不是大小。
dst
被声明为输出,而它应该是输入。
add
指令的参数是错误的,在 AT&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 , %[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
,这可能会造成混淆。
您的 Intel 语法版本添加也未能使用正确的语法来引用参数(例如 %[dst]
)。
我对在 C++ 代码中使用内联汇编非常陌生。 我想做的基本上是一种大小为模数 32 的指针的 memcopy。
在 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 [=11=], %%ebx \n"
"L1: \n"
"vmovntdqa (%[src],%%ebx), %%ymm0 \n"
"vmovntdq %%ymm0, (%[dst],%%ebx) \n"
"add %%ebx, \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 [=13=], %%ebx \n"
"L1: \n"
"vmovntdqa %%ebx(%[src]), %%ymm0 \n"
"vmovntdq %%ymm0, (%[dst],%%ebx) \n"
"add %%ebx, \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++ 函数。
提前致谢。
你的第一个例子是最正确的,但有以下错误:
- 它使用 32 位寄存器而不是 64 位。
- 3 个未指定为输出或破坏的寄存器已更改。
- EAX 加载源地址,而不是大小。
dst
被声明为输出,而它应该是输入。add
指令的参数是错误的,在 AT&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 , %[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
,这可能会造成混淆。
您的 Intel 语法版本添加也未能使用正确的语法来引用参数(例如 %[dst]
)。