在我看来,clang ++会错过g ++拾取的汇编程序代码中的错误。或者我错过了一些clang的编译器标志?我是汇编代码的新手。
使用clang ++我编译并链接了我的应用程序错误和警告,但我遇到了令人讨厌的分段错误。切换到g ++,另一方面我得到了这些错误:
GO_F_ImageColourConversion.cpp: Assembler messages:
GO_F_ImageColourConversion.cpp:4679: Error: `(%rsi,%edx,2)' is not a valid base/index expression
GO_F_ImageColourConversion.cpp:4682: Error: `(%rcx,%edx,1)' is not a valid base/index expression
我正在使用这些编译器标志: -DLINUX -g -Wno-deprecated -D_GNU_SOURCE -D_REENTRANT -D__STDC_CONSTANT_MACROS -fPIC -fPIE
我有以下代码(省略不相关的部分):
Ipp8u * pSrc;
Ipp8u * pDst;
int x, y;
asm volatile
(
"movl (%1, %0, 2), %%eax;\n"
"shlw $8, %%ax;\n"
"shrl $8, %%eax;\n"
"movw %%ax, (%2, %0, 1);\n"
: /* no output */
: "r" (x), "r" (pSrc), "r" (pDst)
: "eax", "memory");
}
从这个answer on SO开始,我意识到我有一个32/64位isssue(我正在移植到64位).Ipp8u *是8位但在我的机器上只有4位。
将int更改为uintptr_t x, y;
似乎可以解决问题。为什么clang不会在编译时出错?
答案 0 :(得分:2)
gcc和clang都为我扼杀了你的代码:
6 : error: base register is 64-bit, but index register is not
"movl (%1, %0, 2), %%eax\n"
^
<inline asm>:1:13: note: instantiated into assembly here
movl (%rdi, %edx, 2), %eax
来自clang 3.8 on the godbolt compiler explorer,其中包含一个函数,因此它是可测试的,您无法在问题中提供。你确定你的clang正在构建64位代码吗? (-m64
,而非-m32
或-mx32
)。
在godbolt上提供一个指向你的代码的链接,某些版本的clang默默地错误编译它,否则我只能说“无法重现”。
是的,您的问题是x
是int
,您的问题是在寻址模式下混合寄存器大小。 (%rsi,%edx,2)
无法编码。
使用%q0
来获取%rdx
并不能保证寄存器的高32位中没有垃圾(虽然它不太可能)。相反,您可以使用"r" ((int64_t)x)
到sign-extend x
to 64bits。
为什么你需要内联asm? C版本的编译器输出有多糟糕?
如果您确实想使用内联asm,那么更多更好:
uint32_t asm_tmp = *(uint32_t *)(x*2 + (char*)pSrc); // I think I've reproduced the same pointer math as the addressing mode you used.
asm ( "shlw $8, %w[v]\n\t" // e.g. ax
"shrl $8, %k[v]\n\t" // e.g. eax. potential partial-register slowdown from reading eax after writing ax on older CPUs
: [v] "+&r" (asm_tmp)
);
*(uint16_t *)(x + (char*)pDst) = asm_tmp; // store the low 16
这与clang很好地编译,但是gcc is kinda braindead about generating the address。也许用不同的地址表达式?
您的代码通过以加载开始并以商店结尾来破坏约束的目的。始终让编译器尽可能地处理。如果没有内联asm,你可能会从中获得更好的代码,并且编译器会理解它的作用并且可能会自动向量化或进行其他转换。使用volatile
clobber删除asm语句为"memory"
的需求已经是优化器的一个重大改进:现在它是一个纯函数,编译器知道它只是转换一个寄存器。
另请参阅the end of this answer以获取有关编写内联asm的更多指南。