* fix parameter alignment on x86_64 when more than 6 parameters are involved (aka the stack is used)

+ added test
This commit is contained in:
Sven Barth 2023-08-03 22:34:28 +02:00
parent ec0b830bba
commit 82dd70e72f
5 changed files with 123 additions and 4 deletions

View File

@ -1650,10 +1650,11 @@ unit cpupara;
locidx,
i,j,
varalign,
procparaalign,
paraalign : longint;
use_ms_abi : boolean;
begin
paraalign:=get_para_align(p.proccalloption);
procparaalign:=get_para_align(p.proccalloption);
use_ms_abi:=x86_64_use_ms_abi(p.proccalloption);
{ Register parameters are assigned from left to right }
for i:=0 to paras.count-1 do
@ -1695,6 +1696,7 @@ unit cpupara;
paralen:=sizeof(pint);
paradef:=cpointerdef.getreusable_no_free(paradef);
paralocdef:=paradef;
paraalign:=procparaalign;
loc[0].def:=paralocdef;
loc[1].def:=nil;
for j:=2 to high(loc) do
@ -1707,7 +1709,7 @@ unit cpupara;
begin
getvalueparaloc(p.proccalloption,hp.varspez,paralocdef,loc);
paralen:=push_size(hp.varspez,paralocdef,p.proccalloption);
paraalign:=max(paraalign,paradef.alignment);
paraalign:=max(procparaalign,paradef.alignment);
if p.proccalloption = pocall_vectorcall then
begin
{ TODO: Can this set of instructions be put into 'defutil' without it relying on the argument classification? [Kit] }
@ -1990,7 +1992,7 @@ unit cpupara;
else
paraloc^.reference.index:=NR_FRAME_POINTER_REG;
varalign:=used_align(size_2_align(paralen),paraalign,paraalign);
paraloc^.reference.offset:=parasize;
paraloc^.reference.offset:=align(parasize,varalign);
parasize:=align(parasize+paralen,varalign);
paralen:=0;
end;

View File

@ -240,7 +240,7 @@ endif
.PHONY: create_c_objects delete_c_objects copyfiles test_c_objects
C_SOURCE_DIR=test/cg/obj
C_SOURCES=ctest.c tcext3.c tcext4.c tcext5.c tcext6.c
C_SOURCES=ctest.c tcext3.c tcext4.c tcext5.c tcext6.c tcext7.c
CPP_SOURCES=cpptcl1.cpp cpptcl2.cpp
TASM_SOURCES=ttasm1.asm
ifneq ($(TEST_ABI),)

Binary file not shown.

View File

@ -0,0 +1,46 @@
struct CTest
{
unsigned long a;
unsigned long b;
unsigned long c;
unsigned long d;
} __attribute__((aligned(16)));
int TestFunc(unsigned long arg1, unsigned long arg2, unsigned long arg3, unsigned long arg4,
unsigned long arg5, unsigned long arg6, unsigned long arg7, struct CTest arg8,
unsigned long arg9, struct CTest arg10)
{
if (arg1 != 1)
return 1;
if (arg2 != 2)
return 2;
if (arg3 != 3)
return 3;
if (arg4 != 4)
return 4;
if (arg5 != 5)
return 5;
if (arg6 != 6)
return 6;
if (arg7 != 7)
return 7;
if (arg8.a != 801)
return 801;
if (arg8.b != 802)
return 802;
if (arg8.c != 803)
return 803;
if (arg8.d != 804)
return 804;
if (arg9 != 9)
return 9;
if (arg10.a != 1001)
return 1001;
if (arg10.b != 1002)
return 1002;
if (arg10.c != 1003)
return 1003;
if (arg10.d != 1004)
return 1004;
return 0;
}

71
tests/test/cg/tcalext7.pp Normal file
View File

@ -0,0 +1,71 @@
{ %CPU=x86_64 }
{ %TARGET=linux }
program tcalext7;
{$mode objfpc}{$H+}
{$L tcext7.o}
type
TTest = record
a, b: Int64;
case Boolean of
True: (c, d: Int64);
{ to enforce 16-Byte alignment }
False: (e: Extended);
end;
function TestFunc(aArg1, aArg2, aArg3, aArg4, aArg5, aArg6, aArg7: Int64; aArg8: TTest; aArg9: Int64; aArg10: TTest): LongInt; cdecl; external name 'TestFunc';
function MakeTest(aArg1, aArg2, aArg3, aArg4: Int64): TTest;
begin
Result.a := aArg1;
Result.b := aArg2;
Result.c := aArg3;
Result.d := aArg4;
end;
procedure Test(aArg1, aArg2, aArg3, aArg4, aArg5, aArg6, aArg7: Int64; aArg8: TTest; aArg9: Int64; aArg10: TTest);
begin
if aArg1 <> 1 then
Halt(1);
if aArg2 <> 2 then
Halt(2);
if aArg3 <> 3 then
Halt(3);
if aArg4 <> 4 then
Halt(4);
if aArg5 <> 5 then
Halt(5);
if aArg6 <> 6 then
Halt(6);
if aArg7 <> 7 then
Halt(7);
if aArg8.a <> 801 then
Halt(801);
if aArg8.b <> 802 then
Halt(802);
if aArg8.c <> 803 then
Halt(803);
if aArg8.d <> 804 then
Halt(804);
if aArg9 <> 9 then
Halt(9);
if aArg10.a <> 1001 then
Halt(1001);
if aArg10.b <> 1002 then
Halt(1002);
if aArg10.c <> 1003 then
Halt(1003);
if aArg10.d <> 1004 then
Halt(1004);
end;
var
res: LongInt;
begin
Test(1, 2, 3, 4, 5, 6, 7, MakeTest(801, 802, 803, 804), 9, MakeTest(1001, 1002, 1003, 1004));
res := TestFunc(1, 2, 3, 4, 5, 6, 7, MakeTest(801, 802, 803, 804), 9, MakeTest(1001, 1002, 1003, 1004));
if res <> 0 then
Halt(res + 10000);
end.