[llvm-bugs] [Bug 35046] New: gcc/clang calling convension mismatch
via llvm-bugs
llvm-bugs at lists.llvm.org
Mon Oct 23 16:29:19 PDT 2017
https://bugs.llvm.org/show_bug.cgi?id=35046
Bug ID: 35046
Summary: gcc/clang calling convension mismatch
Product: clang
Version: unspecified
Hardware: PC
OS: Linux
Status: NEW
Severity: enhancement
Priority: P
Component: -New Bugs
Assignee: unassignedclangbugs at nondot.org
Reporter: vanyacpp at gmail.com
CC: llvm-bugs at lists.llvm.org
Recently I have discovered that empty arguments are passed differently by gcc
and by clang.
struct empty
{};
void f(empty, empty, empty);
int main()
{
f(empty{}, empty{}, empty{});
}
GCC pushed 0 to stack for each empty struct while clang does nothing.
main(GCC):
sub rsp, 16
xor eax, eax
push rax
push rax
push rax
call f(empty, empty, empty)
xor eax, eax
add rsp, 40
ret
main(clang):
push rax
call f(empty, empty, empty)
xor eax, eax
pop rcx
ret
I would say that I like the code generated by clang more. As the struct is
empty no value needs to be passed. In a case the callee needs to take the
address of the argument it can allocate the argument in its own frame as the
argument is passed by value.
As the code generated differs I wondered if I can construct an example where
parameters get wrong values because of this. Turned out it wasn't very
difficult.
The following program
struct empty
{};
struct big
{
int a;
int b;
int c;
int d;
int e;
};
void print_7th(empty, empty, empty, empty, empty, empty, big seventh)
{
std::cout << seventh.a
<< ' ' << seventh.b
<< ' ' << seventh.c
<< ' ' << seventh.d
<< ' ' << seventh.e << std::endl;
}
int main()
{
empty e;
print_7th(e, e, e, e, e, e, big{1, 2, 3, 4, 5});
}
prints different output when print_7th and main are compiled with different
compilers:
./gcc-to-gcc
1 2 3 4 5
./clang-to-gcc
5 32767 0 0 635911936
./gcc-to-clang
192 0 -1204279016 32765 1
./clang-to-clang
1 2 3 4 5
Another easy way to see that compilers pass arguments differently is compiling
this code:
int sum(empty, empty, empty, empty, empty, empty, big seventh)
{
return seventh.a + seventh.b + seventh.c + seventh.d + seventh.e;
}
GCC generates:
sum:
mov eax, DWORD PTR [rsp+60]
add eax, DWORD PTR [rsp+56]
add eax, DWORD PTR [rsp+64]
add eax, DWORD PTR [rsp+68]
add eax, DWORD PTR [rsp+72]
ret
while clang generates:
sum:
mov eax, dword ptr [rsp + 12]
add eax, dword ptr [rsp + 8]
add eax, dword ptr [rsp + 16]
add eax, dword ptr [rsp + 20]
add eax, dword ptr [rsp + 24]
ret
I don't know which compiler is right in this case and which conform to SysV ABI
better. I would prefer GCC to adopt clang behavior as it is more efficient.
Because if we have two popular major compilers that both are widely used and
are incompatible with each other and we have to break compatibility of one of
them it's better to choose the better alternative. Also using empty struct as
parameters is common in C++ code, and it's great to make them free.
I have already reported this issue against gcc:
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=82693 I report this issue here
too, to let clang developers know about the issue too.
--
You are receiving this mail because:
You are on the CC list for the bug.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/llvm-bugs/attachments/20171023/34096a1b/attachment.html>
More information about the llvm-bugs
mailing list