Я улавливаю проблемы компиляции с использованием 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