mirror of
https://gitlab.com/freepascal.org/fpc/source.git
synced 2025-08-12 05:45:59 +02:00
Solves #39296: x86-64 parameter zero/sign extension
This commit is contained in:
parent
b4f939a4ab
commit
bc84f780ee
@ -176,15 +176,13 @@ unit cpupara;
|
|||||||
if size<=4 then
|
if size<=4 then
|
||||||
begin
|
begin
|
||||||
cl.typ:=X86_64_INTEGERSI_CLASS;
|
cl.typ:=X86_64_INTEGERSI_CLASS;
|
||||||
{ gcc/clang sign/zero-extend all values to 32 bits, except for
|
{ The ABI does not require any sign/zero extension for parameters,
|
||||||
_Bool (= Pascal boolean), which is only zero-extended to 8 bits
|
except for _Bool (= Pascal boolean) to 8 bits. However, some
|
||||||
as per the x86-64 ABI -> do the same
|
compilers (clang) extend them to 32 bits anyway and rely on it
|
||||||
|
-> also do it for compatibility when calling such code }
|
||||||
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 }
|
|
||||||
if not assigned(cl.def) or
|
if not assigned(cl.def) or
|
||||||
not(cl.def.typ=orddef) or
|
(cl.def.typ<>orddef) or
|
||||||
not(torddef(cl.def).ordtype in [uchar,u8bit,s8bit,pasbool1]) then
|
(torddef(cl.def).ordtype<>pasbool1) then
|
||||||
cl.def:=u32inttype;
|
cl.def:=u32inttype;
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
@ -1489,7 +1487,20 @@ unit cpupara;
|
|||||||
end
|
end
|
||||||
else if result.intsize in [1,2,4] then
|
else if result.intsize in [1,2,4] then
|
||||||
begin
|
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
|
end
|
||||||
else
|
else
|
||||||
begin
|
begin
|
||||||
@ -1785,6 +1796,30 @@ unit cpupara;
|
|||||||
end
|
end
|
||||||
else
|
else
|
||||||
begin
|
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);
|
paraloc^.size:=def_cgsize(paraloc^.def);
|
||||||
{ s64comp is pushed in an int register }
|
{ s64comp is pushed in an int register }
|
||||||
if paraloc^.size=OS_C64 then
|
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