错误:使用索引寻址和 Clang 的指令的操作数无效
Error: invalid operand for instruction using indexed addressing and Clang
我正在使用Clang捕获编译问题。GCC可以很好地编译程序。该程序使用索引寻址。
错误是:
$ clang++ -g2 -O1 test.cxx -c
test.cxx:19:10: error: invalid operand for instruction
"movq (%[idx],%[in]), %[x] ;n"
^
<inline asm>:5:23: note: instantiated into assembly here
movq (%rbx,%rsi), -8(%rsp) ;
^~~~~~~~
test.cxx:20:10: error: invalid operand for instruction
"movq (%[idx],%[out]), %[y] ;n"
^
<inline asm>:6:23: note: instantiated into assembly here
movq (%rbx,%rdi), -16(%rsp) ;
^~~~~~~~~
test.cxx:21:10: error: invalid operand for instruction
"cmovnzq %[x], %[y] ;n" // copy in to out if NZ
^
<inline asm>:7:20: note: instantiated into assembly here
cmovnzq -8(%rsp), -16(%rsp) ;
^~~~~~~~~
test.cxx:22:10: error: invalid operand for instruction
"movq %[y], (%[idx],%[out]) ;n"
^
<inline asm>:8:21: note: instantiated into assembly here
movq -16(%rsp), (%rbx,%rdi) ;
^~~~~~~~~~~
4 errors generated.
如何解决问题?(或者我如何告诉 Clang 停止定义__GNUC__
以使其远离 GCC 代码路径)。
$ cat test.cxx
#include <iostream>
#include <algorithm>
#include <cstring>
#include <cstdint>
void test_cmov(uint8_t in[96], uint8_t out[96], uint64_t flag)
{
#if defined(__GNUC__)
const uint32_t iter = 96/sizeof(uint64_t);
uint64_t* optr = reinterpret_cast<uint64_t*>(out);
uint64_t* iptr = reinterpret_cast<uint64_t*>(in);
uint64_t idx=0, x, y;
__asm__ __volatile__ (
".att_syntax ;n"
"cmpq $0, %[flag] ;n" // compare, set ZERO flag
"movq %[iter], %%rcx ;n" // load iteration count
"1: ;n"
"movq (%[idx],%[in]), %[x] ;n"
"movq (%[idx],%[out]), %[y] ;n"
"cmovnzq %[x], %[y] ;n" // copy in to out if NZ
"movq %[y], (%[idx],%[out]) ;n"
"leaq 8(%[idx]), %[idx] ;n" // increment index
"loopnz 1b ;n" // does not affect flags
: [out] "+D" (optr), [in] "+S" (iptr), [idx] "+b" (idx),
[x] "=g" (x), [y] "=g" (y)
: [flag] "g" (flag), [iter] "I" (iter)
: "rcx", "cc"
);
#else
if (flag)
std::memcpy(out, in, 96);
#endif
}
int main(int argc, char*argv[])
{
uint8_t in[96], out[96];
uint64_t flag = (argc >=2 && argv[1][0] == 'y');
std::memset(in, 0x00, 96);
std::memset(out, 0x00, 96);
std::memcpy(in, argv[0], std::min(96ul, std::strlen(argv[0])));
test_cmov(in, out, flag);
std::cout << (const char*)out << std::endl;
return 0;
}
$ gcc --version
gcc (GCC) 8.3.1 20190223 (Red Hat 8.3.1-2)
...
$ clang --version
clang version 7.0.1 (Fedora 7.0.1-6.fc29)
Target: x86_64-unknown-linux-gnu
...
$ lsb_release -a
LSB Version: :core-4.1-amd64:core-4.1-noarch
Distributor ID: Fedora
Description: Fedora release 29 (Twenty Nine)
Release: 29
Codename: TwentyNine
您使用了"=g"
约束,让编译器为%[x]
和%[y]
选择一个mem操作数。
请改用"=r"
。
您的模板使用movq (%[idx],%[in]), %[x]
,如果%[x]
是内存,显然无法组装,因为 x86 不支持任何指令的 2 个显式内存操作数。
这里与 gcc 的区别在于,如果可以选择,它喜欢选择内存操作数。 (这是一个优化器错误,IMO,但不是正确性问题。 您的内联 asm 有问题,只碰巧与 GCC 一起使用,因为它为[x] "=g" (x)
) 选择一个寄存器
如果您阅读错误消息,这一点很明显:
<inline asm>:5:23: note: instantiated into assembly here
movq (%rbx,%rsi), -8(%rsp)
...
cmovnzq -8(%rsp), -16(%rsp)
显然,这些不是有效的指示。
如果您关心 clang,通常避免为内联 asm 选择内存操作数,除非它在正常情况下肯定会有所帮助。
当你在内联 asm 中编写整个循环时,你肯定希望让编译器溢出其他内容以释放寄存器,如果某些循环临时需要的话。 或者真的任何时候你在同一个内联 asm 块中多次使用和操作数。 GCC 不会看这个,也不会知道选择内存的成本。 (而且 clang 只是愚蠢,即使有很多免费注册也会选择内存。
相关文章:
- 使用C++库在Android项目中修改gradle中的cmake参数,用于插入指令的测试
- 无法编译 rtmidi 测试 cmidiin.cpp 文件, 非法指令
- 奇怪的结构&GCC&clang(void*返回类型)
- C++:对不存在的命名空间使用命名空间指令
- 数据成员SFINAE的C++17测试:gcc vs clang
- 当我编译webrtc服务器时,Windows上只支持clang-cl
- 为什么在Windows上的VS 2019和Clang 9中"size_t"在没有标题的情况下工作
- 我可以将一个用clang c++11编译的对象与另一个用c++17编译的对象链接起来吗
- Clang bug?使用指针作为模板参数
- clang整洁10忽略了我的NOLINT命令
- 如何防止clang格式在流运算符调用之间添加换行符<<
- 在clang++预处理器中确定gcc工具链版本
- 为什么 Clang 不允许"and"作为函数名称?
- 带有 -stdlib=libc++ 的 clang++ 9.0.1 找不到<optional>
- clang格式:宏的缩进
- CLANG 编译器 说:变量"PTR"可能未初始化
- 错误:使用索引寻址和 Clang 的指令的操作数无效
- Clang在GCC没有的地方产生非法指令
- 使用clang-format缩进预处理器指令
- 为什么GCC或Clang在使用快速数学时不优化到1指令的倒数