|
@@ -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
|
|
|
|
- _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
|
|
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;
|
|
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
|