Browse Source

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

Sven Barth 2 years ago
parent
commit
82dd70e72f

+ 5 - 3
compiler/x86_64/cpupara.pas

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

+ 1 - 1
tests/Makefile.fpc

@@ -240,7 +240,7 @@ endif
 .PHONY: create_c_objects delete_c_objects copyfiles test_c_objects
 .PHONY: create_c_objects delete_c_objects copyfiles test_c_objects
 
 
 C_SOURCE_DIR=test/cg/obj
 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
 CPP_SOURCES=cpptcl1.cpp cpptcl2.cpp
 TASM_SOURCES=ttasm1.asm
 TASM_SOURCES=ttasm1.asm
 ifneq ($(TEST_ABI),)
 ifneq ($(TEST_ABI),)

BIN
tests/test/cg/obj/linux/x86_64/tcext7.o


+ 46 - 0
tests/test/cg/obj/tcext7.c

@@ -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 - 0
tests/test/cg/tcalext7.pp

@@ -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.