I recently noticed a difference between the way GCC and LLVM treat
sign extension for parameters and return values on x86-64. I could
not find a clear answer in the x86-64 ABI [1] concerning whether
parameters should be sign extended by the caller or callee and
similarly whether return values should be sign extended by the caller
or callee.
Consider a simple 'signed char' division routine:
signed char sdiv(signed char x, signed char y)
{
return x / y;
}
On my Fedora 16 Linux host GCC 4.6.2 produces:
sdiv:
.LFB11:
.cfi_startproc
movsbl %dil, %eax
movsbl %sil, %esi
movl %eax, %edx
sarl $31, %edx
idivl %esi
ret
where as clang 2.9 produces:
sdiv: # @sdiv
.Leh_func_begin0:
# BB#0:
movl %edi, %eax
cltd
idivl %esi
movsbl %al, %eax
ret
GCC assumes the parameters have *not* been sign extended and assumes
it is the receivers job to extend the return value. LLVM assumes the
parameters *have* been sign extended and that the receiver expects a
sign extended result.
The LLVM model implies the the caller always has to sign extend for
signed promotion to argument registers and that the callee always has
to sign extend for signed promotion to return value registers. The
GCC model seems more reasonable and efficient to me because whoever is
actually using the values gets to choose whether a sign extension is
done (or not done at all).
Could someone explain the LLVM implementation to me?
[1] http://www.x86-64.org/documentation/abi.pdf
Sorry about the delayed response; I was sort of expecting someone else
to respond. It looks like a rather nasty issue, and deserves some
attention.
LLVM has traditionally assumed that all integer argument and return
types narrower than int are promoted to int on all architectures.
Nobody has actually noticed any issues with this before now, as far as
I know.
If gcc has decided to assume no sign/zero-extension on x86-64, we need
to follow their lead, at least on Linux. Please file at
http://llvm.org/bugs/ ; an executable testcase to go with this would
be nice, so we can compare various compilers and different platforms.
(clang 2.9 relatively old, but I don't think anything has changed here
since it was released.)
-Eli
FYI, this is vaguely related:
http://nondot.org/~sabre/LLVMNotes/ExtendedIntegerResults.txt
It was brought up by people that cared about 16-bit targets but where int was 32-bit. I don't think that anyone actively cares about this at the moment, but it would be nice to clean this up someday.
-Chris
LLVM has traditionally assumed that all integer argument and return
types narrower than int are promoted to int on all architectures.
Nobody has actually noticed any issues with this before now, as far as
I know.
The only reason that I noticed was that Python ctypes started misbehaving
when we went to build/test it on OS X Lion (http://bugs.python.org/issue13370).
After investigating the failure I found this. Python uses libffi and
libffi implements
the GCC ABI. So I would expect any project using libffi with clang to
have problems.
If gcc has decided to assume no sign/zero-extension on x86-64, we need
to follow their lead, at least on Linux. Please file at
http://llvm.org/bugs/ ; an executable testcase to go with this would
be nice, so we can compare various compilers and different platforms.
Will do. Thanks.
-- Meador
Hi Meador,
Have you filed a bugzilla report? What's the PR number?
Evan