mirror of
https://gitlab.com/freepascal.org/fpc/source.git
synced 2025-04-09 17:48:46 +02:00
Solves #39296: x86-64 parameter zero/sign extension
This commit is contained in:
parent
a77f5221f3
commit
a73ee4f403
@ -176,15 +176,13 @@ unit cpupara;
|
||||
if size<=4 then
|
||||
begin
|
||||
cl.typ:=X86_64_INTEGERSI_CLASS;
|
||||
{ gcc/clang sign/zero-extend all values to 32 bits, except for
|
||||
_Bool (= Pascal boolean), which is only zero-extended to 8 bits
|
||||
as per the x86-64 ABI -> do the same
|
||||
|
||||
some testing showed, that this is not true for 8 bit values:
|
||||
in case of an 8 bit value, it is not zero/sign extended }
|
||||
{ The ABI does not require any sign/zero extension for parameters,
|
||||
except for _Bool (= Pascal boolean) to 8 bits. However, some
|
||||
compilers (clang) extend them to 32 bits anyway and rely on it
|
||||
-> also do it for compatibility when calling such code }
|
||||
if not assigned(cl.def) or
|
||||
not(cl.def.typ=orddef) or
|
||||
not(torddef(cl.def).ordtype in [uchar,u8bit,s8bit,pasbool1]) then
|
||||
(cl.def.typ<>orddef) or
|
||||
(torddef(cl.def).ordtype<>pasbool1) then
|
||||
cl.def:=u32inttype;
|
||||
end
|
||||
else
|
||||
@ -1489,7 +1487,20 @@ unit cpupara;
|
||||
end
|
||||
else if result.intsize in [1,2,4] then
|
||||
begin
|
||||
paraloc^.size:=def_cgsize(paraloc^.def);
|
||||
{ The ABI does not require sign/zero-extended function
|
||||
results, but older versions of clang did so and
|
||||
on Darwin current versions of clang keep doing so
|
||||
for backward compatibility. On other platforms, it
|
||||
doesn't and hence we don't either }
|
||||
if (i=0) and
|
||||
not(target_info.system in systems_darwin) and
|
||||
(result.intsize in [1,2]) then
|
||||
begin
|
||||
paraloc^.size:=int_cgsize(result.intsize);
|
||||
paraloc^.def:=cgsize_orddef(paraloc^.size);
|
||||
end
|
||||
else
|
||||
paraloc^.size:=def_cgsize(paraloc^.def);
|
||||
end
|
||||
else
|
||||
begin
|
||||
@ -1785,6 +1796,30 @@ unit cpupara;
|
||||
end
|
||||
else
|
||||
begin
|
||||
{ some compilers sign/zero-extend on the callerside,
|
||||
others don't. To be compatible with both, FPC
|
||||
extends on the callerside, and assumes no
|
||||
extension has been performed on the calleeside.
|
||||
This is less efficient, but the alternative is
|
||||
occasional crashes when calling code generated
|
||||
by certain other compilers, or being called from
|
||||
code generated by other compilers.
|
||||
|
||||
Exception: Darwin, since everyone there needs to
|
||||
be compatible with the system compiler clang
|
||||
(which extends on the caller side).
|
||||
|
||||
Not for LLVM, since there the zero/signext
|
||||
attributes by definition only apply to the
|
||||
caller side }
|
||||
{$ifndef LLVM}
|
||||
if not(target_info.system in systems_darwin) and
|
||||
(side=calleeside) and
|
||||
(hp.paraloc[side].intsize in [1,2]) then
|
||||
begin
|
||||
paraloc^.def:=hp.paraloc[side].def
|
||||
end;
|
||||
{$endif not LLVM}
|
||||
paraloc^.size:=def_cgsize(paraloc^.def);
|
||||
{ s64comp is pushed in an int register }
|
||||
if paraloc^.size=OS_C64 then
|
||||
|
26
tests/webtbs/tw39296.pp
Normal file
26
tests/webtbs/tw39296.pp
Normal file
@ -0,0 +1,26 @@
|
||||
{ %cpu=x86_64 }
|
||||
{ %skiptarget=win64 }
|
||||
|
||||
function bytepara(b: byte; s: shortint): boolean; assembler; nostackframe;
|
||||
asm
|
||||
xorl %eax, %eax
|
||||
cmpl $5, %edi
|
||||
seteb %al
|
||||
cmpl $-3, %esi
|
||||
seteb %dl
|
||||
andb %dl, %al
|
||||
end;
|
||||
|
||||
var
|
||||
b1: byte;
|
||||
s1: shortint;
|
||||
begin
|
||||
b1:=5;
|
||||
s1:=-3;
|
||||
asm
|
||||
movl $0x12345678, %edi
|
||||
movl $0xabcdef01, %esi
|
||||
end ['rsi', 'rdi'];
|
||||
if not bytepara(b1,s1) then
|
||||
halt(1);
|
||||
end.
|
Loading…
Reference in New Issue
Block a user