소스 검색

* fixed ABI compliance for parameter passing and function returning on all
x86-64 platforms (except for win64, which uses another ABI and which
already complied to it) + test
* fixed returning records containing 1 single or double field on darwin/i386,
these have to be returned via ST0 instead of as a regular record
* added support for LOC_FPUREGISTER and LOC_MMREGISTER in several places
where they can now occur due to the previous two changes
* made a few internalerrors unique

git-svn-id: trunk@15368 -

Jonas Maebe 15 년 전
부모
커밋
15e9c54b44

+ 7 - 0
.gitattributes

@@ -8479,30 +8479,35 @@ tests/test/cg/obj/darwin/arm/ctest.o -text
 tests/test/cg/obj/darwin/arm/tcext3.o -text
 tests/test/cg/obj/darwin/arm/tcext4.o -text
 tests/test/cg/obj/darwin/arm/tcext5.o -text
+tests/test/cg/obj/darwin/arm/tcext6.o -text
 tests/test/cg/obj/darwin/i386/cpptcl1.o -text
 tests/test/cg/obj/darwin/i386/cpptcl2.o -text
 tests/test/cg/obj/darwin/i386/ctest.o -text
 tests/test/cg/obj/darwin/i386/tcext3.o -text
 tests/test/cg/obj/darwin/i386/tcext4.o -text
 tests/test/cg/obj/darwin/i386/tcext5.o -text
+tests/test/cg/obj/darwin/i386/tcext6.o -text
 tests/test/cg/obj/darwin/powerpc/cpptcl1.o -text
 tests/test/cg/obj/darwin/powerpc/cpptcl2.o -text
 tests/test/cg/obj/darwin/powerpc/ctest.o -text
 tests/test/cg/obj/darwin/powerpc/tcext3.o -text
 tests/test/cg/obj/darwin/powerpc/tcext4.o -text
 tests/test/cg/obj/darwin/powerpc/tcext5.o -text
+tests/test/cg/obj/darwin/powerpc/tcext6.o -text
 tests/test/cg/obj/darwin/powerpc64/cpptcl1.o -text
 tests/test/cg/obj/darwin/powerpc64/cpptcl2.o -text
 tests/test/cg/obj/darwin/powerpc64/ctest.o -text
 tests/test/cg/obj/darwin/powerpc64/tcext3.o -text
 tests/test/cg/obj/darwin/powerpc64/tcext4.o -text
 tests/test/cg/obj/darwin/powerpc64/tcext5.o -text
+tests/test/cg/obj/darwin/powerpc64/tcext6.o -text
 tests/test/cg/obj/darwin/x86_64/cpptcl1.o -text
 tests/test/cg/obj/darwin/x86_64/cpptcl2.o -text
 tests/test/cg/obj/darwin/x86_64/ctest.o -text
 tests/test/cg/obj/darwin/x86_64/tcext3.o -text
 tests/test/cg/obj/darwin/x86_64/tcext4.o -text
 tests/test/cg/obj/darwin/x86_64/tcext5.o -text
+tests/test/cg/obj/darwin/x86_64/tcext6.o -text
 tests/test/cg/obj/freebsd/i386/ctest.o -text
 tests/test/cg/obj/freebsd/i386/tcext3.o -text
 tests/test/cg/obj/freebsd/i386/tcext4.o -text
@@ -8573,6 +8578,7 @@ tests/test/cg/obj/stdint.h svneol=native#text/plain
 tests/test/cg/obj/tcext3.c -text
 tests/test/cg/obj/tcext4.c -text
 tests/test/cg/obj/tcext5.c -text
+tests/test/cg/obj/tcext6.c svneol=native#text/plain
 tests/test/cg/obj/win32/i386/cpptcl1.o -text
 tests/test/cg/obj/win32/i386/ctest.o -text
 tests/test/cg/obj/win32/i386/tcext3.o -text
@@ -8620,6 +8626,7 @@ tests/test/cg/tcalext.pp svneol=native#text/plain
 tests/test/cg/tcalext3.pp svneol=native#text/plain
 tests/test/cg/tcalext4.pp svneol=native#text/plain
 tests/test/cg/tcalext5.pp svneol=native#text/plain
+tests/test/cg/tcalext6.pp svneol=native#text/plain
 tests/test/cg/tcalfun1.pp svneol=native#text/plain
 tests/test/cg/tcalfun2.pp svneol=native#text/plain
 tests/test/cg/tcalfun3.pp svneol=native#text/plain

+ 56 - 7
compiler/cgobj.pas

@@ -897,7 +897,9 @@ implementation
               begin
                  reference_reset_base(ref,cgpara.location^.reference.index,cgpara.location^.reference.offset,cgpara.alignment);
                  a_load_reg_ref(list,size,cgpara.location^.size,r,ref);
-              end
+              end;
+            LOC_MMREGISTER,LOC_CMMREGISTER:
+              a_loadmm_intreg_reg(list,size,cgpara.location^.size,r,cgpara.location^.register,mms_movescalar);
             else
               internalerror(2002071004);
          end;
@@ -919,7 +921,7 @@ implementation
                  a_load_const_ref(list,cgpara.location^.size,a,ref);
               end
             else
-              internalerror(2002071004);
+              internalerror(2010053109);
          end;
       end;
 
@@ -1046,9 +1048,23 @@ implementation
                      { use concatcopy, because the parameter can be larger than }
                      { what the OS_* constants can handle                       }
                      g_concatcopy(list,tmpref,ref,sizeleft);
+                end;
+              LOC_MMREGISTER,LOC_CMMREGISTER:
+                begin
+                   case location^.size of
+                     OS_F32,
+                     OS_F64,
+                     OS_F128:
+                       a_loadmm_ref_reg(list,location^.size,location^.size,tmpref,location^.register,mms_movescalar);
+                     OS_M8..OS_M128,
+                     OS_MS8..OS_MS128:
+                       a_loadmm_ref_reg(list,location^.size,location^.size,tmpref,location^.register,nil);
+                     else
+                       internalerror(2010053101);
+                   end;
                 end
               else
-                internalerror(2002071004);
+                internalerror(2010053111);
             end;
             inc(tmpref.offset,tcgsize2size[location^.size]);
             dec(sizeleft,tcgsize2size[location^.size]);
@@ -1106,7 +1122,19 @@ implementation
                a_load_reg_ref(list,paraloc.size,paraloc.size,paraloc.register,ref);
              end;
            LOC_MMREGISTER :
-             cg.a_loadmm_reg_ref(list,paraloc.size,paraloc.size,paraloc.register,ref,mms_movescalar);
+             begin
+               case paraloc.size of
+                 OS_F32,
+                 OS_F64,
+                 OS_F128:
+                   a_loadmm_reg_ref(list,paraloc.size,paraloc.size,paraloc.register,ref,mms_movescalar);
+                 OS_M8..OS_M128,
+                 OS_MS8..OS_MS128:
+                   a_loadmm_reg_ref(list,paraloc.size,paraloc.size,paraloc.register,ref,nil);
+                 else
+                   internalerror(2010053102);
+               end;
+             end;
            LOC_FPUREGISTER :
              cg.a_loadfpu_reg_ref(list,paraloc.size,paraloc.size,paraloc.register,ref);
            LOC_REFERENCE :
@@ -1115,7 +1143,7 @@ implementation
                { use concatcopy, because it can also be a float which fails when
                  load_ref_ref is used. Don't copy data when the references are equal }
                if not((href.base=ref.base) and (href.offset=ref.offset)) then
-                 cg.g_concatcopy(list,href,ref,sizeleft);
+                 g_concatcopy(list,href,ref,sizeleft);
              end;
            else
              internalerror(2002081302);
@@ -1140,7 +1168,28 @@ implementation
                end;
              end;
            LOC_MMREGISTER :
-             a_loadmm_reg_reg(list,paraloc.size,regsize,paraloc.register,reg,mms_movescalar);
+             begin
+               case getregtype(reg) of
+                 R_INTREGISTER:
+                   a_loadmm_reg_intreg(list,paraloc.size,regsize,paraloc.register,reg,mms_movescalar);
+                 R_MMREGISTER:
+                   begin
+                     case paraloc.size of
+                       OS_F32,
+                       OS_F64,
+                       OS_F128:
+                        a_loadmm_reg_reg(list,paraloc.size,regsize,paraloc.register,reg,mms_movescalar);
+                       OS_M8..OS_M128,
+                       OS_MS8..OS_MS128:
+                         a_loadmm_reg_reg(list,paraloc.size,paraloc.size,paraloc.register,reg,nil);
+                       else
+                         internalerror(2010053102);
+                     end;
+                   end;
+                 else
+                   internalerror(2010053104);
+               end;
+             end;
            LOC_FPUREGISTER :
              a_loadfpu_reg_reg(list,paraloc.size,regsize,paraloc.register,reg);
            LOC_REFERENCE :
@@ -2742,7 +2791,7 @@ implementation
                 tg.Ungettemp(list,ref);
               end;
             else
-              internalerror(2002071004);
+              internalerror(2010053112);
          end;
       end;
 

+ 11 - 0
compiler/i386/cpupara.pas

@@ -62,6 +62,7 @@ unit cpupara;
     uses
        cutils,
        systems,verbose,
+       symtable,
        defutil;
 
       const
@@ -316,6 +317,7 @@ unit cpupara;
       var
         retcgsize  : tcgsize;
         paraloc : pcgparalocation;
+        sym: tfieldvarsym;
       begin
         result.init;
         result.alignment:=get_para_align(p.proccalloption);
@@ -329,6 +331,15 @@ unit cpupara;
             paraloc^.loc:=LOC_VOID;
             exit;
           end;
+        { on darwin/i386, if a record has only one field and that field is a
+          single or double, it has to be returned like a single/double }
+        if (target_info.system=system_i386_darwin) and
+           ((def.typ=recorddef) or
+            is_object(def)) and
+           tabstractrecordsymtable(tabstractrecorddef(def).symtable).has_single_field(sym) and
+           (sym.vardef.typ=floatdef) and
+           (tfloatdef(sym.vardef).floattype in [s32real,s64real]) then
+          def:=sym.vardef;
         { Constructors return self instead of a boolean }
         if (p.proctypeoption=potype_constructor) then
           begin

+ 14 - 3
compiler/ncgmem.pas

@@ -366,7 +366,9 @@ implementation
                LOC_CREFERENCE:
                  ;
                LOC_REGISTER,
-               LOC_CREGISTER:
+               LOC_CREGISTER,
+               LOC_MMREGISTER,
+               LOC_FPUREGISTER:
                  begin
                    // in case the result is not something that can be put
                    // into an integer register (e.g.
@@ -374,7 +376,8 @@ implementation
                    // a function returning a value > sizeof(intreg))
                    // -> force to memory
                    if not tstoreddef(left.resultdef).is_intregable or
-                      not tstoreddef(resultdef).is_intregable then
+                      not tstoreddef(resultdef).is_intregable or
+                      (location.loc in [LOC_MMREGISTER,LOC_FPUREGISTER]) then
                      location_force_mem(current_asmdata.CurrAsmList,location)
                    else
                      begin
@@ -804,7 +807,15 @@ implementation
               location.reference.alignment:=sizeof(pint);
            end
          else
-           location_copy(location,left.location);
+           begin
+              { may happen in case of function results }
+              case left.location.loc of
+                LOC_REGISTER,
+                LOC_MMREGISTER:
+                  location_force_mem(current_asmdata.CurrAsmList,left.location);
+              end;
+             location_copy(location,left.location);
+           end;
 
          { location must be memory }
          if not(location.loc in [LOC_REFERENCE,LOC_CREFERENCE]) then

+ 32 - 1
compiler/ncgutil.pas

@@ -814,6 +814,24 @@ implementation
                      begin
                        cg.a_loadfpu_reg_reg(list,l.size,cgpara.location^.size,l.register,cgpara.location^.register);
                      end;
+                   { can happen if a record with only 1 "single field" is
+                     returned in a floating point register and then is directly
+                     passed to a regcall parameter }
+                   LOC_REGISTER:
+                     begin
+                       tmploc:=l;
+                       location_force_mem(list,tmploc);
+                       case l.size of
+                         OS_F32:
+                           tmploc.size:=OS_32;
+                         OS_F64:
+                           tmploc.size:=OS_64;
+                         else
+                           internalerror(2010053116);
+                       end;
+                       cg.a_load_loc_cgpara(list,tmploc,cgpara);
+                       location_freetemp(list,tmploc);
+                     end
                    else
                      internalerror(2010053003);
                  end;
@@ -971,7 +989,9 @@ implementation
 
           This doesn't depend on emulator settings, emulator settings should
           be handled by cpupara }
-        if vardef.typ=floatdef then
+        if (vardef.typ=floatdef) or
+           { some ABIs return certain records in an fpu register }
+           (l.loc in [LOC_FPUREGISTER,LOC_CFPUREGISTER]) then
           begin
             gen_loadfpu_loc_cgpara(list,l,cgpara,vardef.size);
             exit;
@@ -1008,6 +1028,17 @@ implementation
                     cg.a_load_loc_cgpara(list,l,cgpara);
                 end;
             end;
+          LOC_MMREGISTER,
+          LOC_CMMREGISTER:
+            begin
+              case l.size of
+                OS_F32,
+                OS_F64:
+                  cg.a_loadmm_loc_cgpara(list,l,cgpara,mms_movescalar);
+                else
+                  cg.a_loadmm_loc_cgpara(list,l,cgpara,nil);
+              end;
+            end;
 {$ifdef SUPPORT_MMX}
           LOC_MMXREGISTER,
           LOC_CMMXREGISTER:

+ 1 - 1
compiler/ppu.pas

@@ -43,7 +43,7 @@ type
 {$endif Test_Double_checksum}
 
 const
-  CurrentPPUVersion = 118;
+  CurrentPPUVersion = 119;
 
 { buffer sizes }
   maxentrysize = 1024;

+ 22 - 0
compiler/symtable.pas

@@ -90,6 +90,7 @@ interface
           procedure addalignmentpadding;
           procedure insertdef(def:TDefEntry);override;
           function is_packed: boolean;
+          function has_single_field(out sym:tfieldvarsym): boolean;
         protected
           _datasize       : aint;
           { size in bits of the data in case of bitpacked record. Only important during construction, }
@@ -1003,6 +1004,27 @@ implementation
       end;
 
 
+    function tabstractrecordsymtable.has_single_field(out sym: tfieldvarsym): boolean;
+      var
+        i: longint;
+      begin
+        result:=false;
+        for i:=0 to SymList.Count-1 do
+          begin
+            if tsym(symlist[i]).typ=fieldvarsym then
+              begin
+                if result then
+                  begin
+                    result:=false;
+                    exit;
+                  end;
+                result:=true;
+                sym:=tfieldvarsym(symlist[i])
+              end;
+          end;
+      end;
+
+
     procedure tabstractrecordsymtable.setdatasize(val: aint);
       begin
         _datasize:=val;

+ 26 - 8
compiler/x86_64/cgcpu.pas

@@ -203,32 +203,50 @@ unit cgcpu;
 
 
     procedure tcgx86_64.a_loadmm_intreg_reg(list: TAsmList; fromsize, tosize : tcgsize; intreg, mmreg: tregister; shuffle: pmmshuffle);
+      var
+        opc: tasmop;
       begin
         { this code can only be used to transfer raw data, not to perform
           conversions }
-        if (tosize<>OS_F64) then
+        if (tcgsize2size[fromsize]<>tcgsize2size[tosize]) or
+           not(tosize in [OS_F32,OS_F64,OS_M64]) then
           internalerror(2009112505);
-        if not(fromsize in [OS_64,OS_S64]) then
-          internalerror(2009112506);
+        case fromsize of
+          OS_32,OS_S32:
+            opc:=A_MOVD;
+          OS_64,OS_S64:
+            opc:=A_MOVQ;
+          else
+            internalerror(2009112506);
+        end;
         if assigned(shuffle) and
            not shufflescalar(shuffle) then
           internalerror(2009112517);
-        list.concat(taicpu.op_reg_reg(A_MOVD,S_NO,intreg,mmreg));
+        list.concat(taicpu.op_reg_reg(opc,S_NO,intreg,mmreg));
       end;
 
 
     procedure tcgx86_64.a_loadmm_reg_intreg(list: TAsmList; fromsize, tosize : tcgsize; mmreg, intreg: tregister;shuffle : pmmshuffle);
+      var
+        opc: tasmop;
       begin
         { this code can only be used to transfer raw data, not to perform
           conversions }
-        if (fromsize<>OS_F64) then
+        if (tcgsize2size[fromsize]<>tcgsize2size[tosize]) or
+           not (fromsize in [OS_F32,OS_F64,OS_M64]) then
           internalerror(2009112507);
-        if not(tosize in [OS_64,OS_S64]) then
-          internalerror(2009112408);
+        case tosize of
+          OS_32,OS_S32:
+            opc:=A_MOVD;
+          OS_64,OS_S64:
+            opc:=A_MOVQ;
+          else
+            internalerror(2009112408);
+        end;
         if assigned(shuffle) and
            not shufflescalar(shuffle) then
           internalerror(2009112515);
-        list.concat(taicpu.op_reg_reg(A_MOVD,S_NO,mmreg,intreg));
+        list.concat(taicpu.op_reg_reg(opc,S_NO,mmreg,intreg));
       end;
 
 

파일 크기가 너무 크기때문에 변경 상태를 표시하지 않습니다.
+ 643 - 227
compiler/x86_64/cpupara.pas


+ 20 - 1
compiler/x86_64/nx64cal.pas

@@ -26,11 +26,14 @@ unit nx64cal;
 interface
 
     uses
+      symdef,
       ncal,ncgcal;
 
     type
        tx8664callnode = class(tcgcallnode)
+        protected
          procedure extra_call_code;override;
+         procedure set_result_location(realresdef: tstoreddef);override;
        end;
 
 
@@ -39,7 +42,7 @@ implementation
     uses
       globtype,
       systems,
-      cpubase,
+      cpubase,cgbase,cgutils,cgobj,
       aasmtai,aasmdata,aasmcpu;
 
     procedure tx8664callnode.extra_call_code;
@@ -58,6 +61,22 @@ implementation
       end;
 
 
+    procedure tx8664callnode.set_result_location(realresdef: tstoreddef);
+      begin
+        { avoid useless "movq %xmm0,%rax" and "movq %rax,%xmm0" instructions
+          (which moreover for some reason are not supported by the Darwin
+           x86-64 assembler) }
+        if assigned(retloc.location) and
+           not assigned(retloc.location^.next) and
+           (retloc.location^.loc in [LOC_MMREGISTER,LOC_CMMREGISTER]) then
+          begin
+            location_reset(location,LOC_MMREGISTER,retloc.location^.size);
+            location.register:=cg.getmmregister(current_asmdata.CurrAsmList,retloc.location^.size);
+          end
+        else
+          inherited
+      end;
+
 begin
    ccallnode:=tx8664callnode;
 end.

+ 3 - 1
tests/Makefile

@@ -1,5 +1,5 @@
 #
-# Don't edit, this file is generated by FPCMake Version 2.0.0 [2010/05/17]
+# Don't edit, this file is generated by FPCMake Version 2.0.0 [2010/06/03]
 #
 default: allexectests
 MAKEFILETARGETS=i386-linux i386-go32v2 i386-win32 i386-os2 i386-freebsd i386-beos i386-haiku i386-netbsd i386-solaris i386-qnx i386-netware i386-openbsd i386-wdosx i386-darwin i386-emx i386-watcom i386-netwlibc i386-wince i386-embedded i386-symbian i386-nativent m68k-linux m68k-freebsd m68k-netbsd m68k-amiga m68k-atari m68k-openbsd m68k-palmos m68k-embedded powerpc-linux powerpc-netbsd powerpc-amiga powerpc-macos powerpc-darwin powerpc-morphos powerpc-embedded sparc-linux sparc-netbsd sparc-solaris sparc-embedded x86_64-linux x86_64-freebsd x86_64-solaris x86_64-darwin x86_64-win64 x86_64-embedded arm-linux arm-palmos arm-darwin arm-wince arm-gba arm-nds arm-embedded arm-symbian powerpc64-linux powerpc64-darwin powerpc64-embedded avr-embedded armeb-linux armeb-embedded mipsel-linux
@@ -1509,6 +1509,7 @@ ifneq ($(TEST_ABI),)
 	-$(COPY) test/cg/obj/$(TEST_OS_TARGET)/$(TEST_CPU_TARGET)-$(TEST_ABI)/tcext3.o test/cg
 	-$(COPY) test/cg/obj/$(TEST_OS_TARGET)/$(TEST_CPU_TARGET)-$(TEST_ABI)/tcext4.o test/cg
 	-$(COPY) test/cg/obj/$(TEST_OS_TARGET)/$(TEST_CPU_TARGET)-$(TEST_ABI)/tcext5.o test/cg
+	-$(COPY) test/cg/obj/$(TEST_OS_TARGET)/$(TEST_CPU_TARGET)-$(TEST_ABI)/tcext6.o test/cg
 	-$(COPY) test/cg/obj/$(TEST_OS_TARGET)/$(TEST_CPU_TARGET)-$(TEST_ABI)/cpptcl1.o test/cg
 	-$(COPY) test/cg/obj/$(TEST_OS_TARGET)/$(TEST_CPU_TARGET)-$(TEST_ABI)/cpptcl2.o test/cg
 else
@@ -1516,6 +1517,7 @@ else
 	-$(COPY) test/cg/obj/$(TEST_OS_TARGET)/$(TEST_CPU_TARGET)/tcext3.o test/cg
 	-$(COPY) test/cg/obj/$(TEST_OS_TARGET)/$(TEST_CPU_TARGET)/tcext4.o test/cg
 	-$(COPY) test/cg/obj/$(TEST_OS_TARGET)/$(TEST_CPU_TARGET)/tcext5.o test/cg
+	-$(COPY) test/cg/obj/$(TEST_OS_TARGET)/$(TEST_CPU_TARGET)/tcext6.o test/cg
 	-$(COPY) test/cg/obj/$(TEST_OS_TARGET)/$(TEST_CPU_TARGET)/cpptcl1.o test/cg
 	-$(COPY) test/cg/obj/$(TEST_OS_TARGET)/$(TEST_CPU_TARGET)/cpptcl2.o test/cg
 endif

+ 2 - 0
tests/Makefile.fpc

@@ -184,6 +184,7 @@ ifneq ($(TEST_ABI),)
         -$(COPY) test/cg/obj/$(TEST_OS_TARGET)/$(TEST_CPU_TARGET)-$(TEST_ABI)/tcext3.o test/cg
         -$(COPY) test/cg/obj/$(TEST_OS_TARGET)/$(TEST_CPU_TARGET)-$(TEST_ABI)/tcext4.o test/cg
         -$(COPY) test/cg/obj/$(TEST_OS_TARGET)/$(TEST_CPU_TARGET)-$(TEST_ABI)/tcext5.o test/cg
+        -$(COPY) test/cg/obj/$(TEST_OS_TARGET)/$(TEST_CPU_TARGET)-$(TEST_ABI)/tcext6.o test/cg
         -$(COPY) test/cg/obj/$(TEST_OS_TARGET)/$(TEST_CPU_TARGET)-$(TEST_ABI)/cpptcl1.o test/cg
         -$(COPY) test/cg/obj/$(TEST_OS_TARGET)/$(TEST_CPU_TARGET)-$(TEST_ABI)/cpptcl2.o test/cg
 else
@@ -191,6 +192,7 @@ else
         -$(COPY) test/cg/obj/$(TEST_OS_TARGET)/$(TEST_CPU_TARGET)/tcext3.o test/cg
         -$(COPY) test/cg/obj/$(TEST_OS_TARGET)/$(TEST_CPU_TARGET)/tcext4.o test/cg
         -$(COPY) test/cg/obj/$(TEST_OS_TARGET)/$(TEST_CPU_TARGET)/tcext5.o test/cg
+        -$(COPY) test/cg/obj/$(TEST_OS_TARGET)/$(TEST_CPU_TARGET)/tcext6.o test/cg
         -$(COPY) test/cg/obj/$(TEST_OS_TARGET)/$(TEST_CPU_TARGET)/cpptcl1.o test/cg
         -$(COPY) test/cg/obj/$(TEST_OS_TARGET)/$(TEST_CPU_TARGET)/cpptcl2.o test/cg
 endif

BIN
tests/test/cg/obj/darwin/arm/tcext6.o


BIN
tests/test/cg/obj/darwin/i386/tcext6.o


BIN
tests/test/cg/obj/darwin/powerpc/tcext6.o


BIN
tests/test/cg/obj/darwin/powerpc64/tcext6.o


BIN
tests/test/cg/obj/darwin/x86_64/tcext6.o


+ 246 - 0
tests/test/cg/obj/tcext6.c

@@ -0,0 +1,246 @@
+#include <stdint.h>
+
+struct struct1 {
+  float v;
+  };
+
+struct struct2 {
+  double v;
+  };
+
+
+struct struct3 {
+  float v1;
+  float v2;
+  };
+
+struct struct4 {
+  double v1;
+  float v2;
+  };
+
+struct struct5 {
+  double v1;
+  double v2;
+  };
+
+struct struct6 {
+  double v1;
+  float v2;
+  float v3;
+  };
+
+struct struct7 {
+  float v1;
+  int32_t v2;
+  double v3;
+  };
+
+struct struct8 {
+  union {
+    float v1;
+    double d;
+    };
+  };
+
+struct struct9 {
+  int64_t v1;
+  float v2;
+  };
+
+struct struct10 {
+  int64_t v1;
+  int16_t v2;
+  float v3;
+  };
+
+struct struct11 {
+  int64_t v1;
+  double v2;
+  };
+
+struct struct12 {
+  int64_t v1;
+  float v2;
+  float v3;
+  };
+
+struct struct13 {
+  double v1;
+  int64_t v2;
+  };
+
+struct struct14 {
+  double v1;
+  int32_t v2;
+  int16_t v3;
+  };
+
+struct struct15 {
+  double v1;
+  int32_t v2;
+  float v3;
+  };
+
+struct struct16 {
+  float v1;
+  float v2;
+  float v3;
+  float v4;
+  };
+
+struct struct17 {
+  float v1;
+  double v2;
+  };
+
+struct struct31 {
+  long double v1;
+  float v2;
+  };
+
+float pass1(struct struct1 s) {
+  return s.v;
+}
+
+double pass2(struct struct2 s) {
+  return s.v;
+}
+
+float pass3(struct struct3 s) {
+  return s.v1 + s.v2;
+}
+
+double pass4(struct struct4 s) {
+  return s.v1 + s.v2;
+}
+
+double pass5(struct struct5 s) {
+  return s.v1 + s.v2;
+}
+
+double pass6(struct struct6 s) {
+  return s.v1 + s.v2;
+}
+
+double pass7(struct struct7 s) {
+  return s.v1 + s.v2 + s.v3;
+}
+
+double pass8(struct struct8 s) {
+  return s.d;
+}
+
+int64_t pass9(struct struct9 s) {
+  return s.v1 + (int64_t)s.v2;
+}
+
+int64_t pass10(struct struct10 s) {
+  return s.v1 + s.v2 + (int64_t)s.v3;
+}
+
+int64_t pass11(struct struct11 s) {
+  return s.v1 + (int64_t)s.v2;
+}
+
+int64_t pass12(struct struct12 s) {
+  return s.v1 + (int64_t)s.v2 + (int64_t)s.v3;
+}
+
+int64_t pass13(struct struct13 s) {
+  return (int64_t)s.v1 + s.v2;
+}
+
+int64_t pass14(struct struct14 s) {
+  return (int64_t)s.v1 + s.v2 + s.v3;
+}
+
+int64_t pass15(struct struct15 s) {
+  return (int64_t)s.v1 + s.v2 + (int64_t)s.v3;
+}
+
+float pass16(struct struct16 s) {
+  return s.v1 + s.v2 + s.v3 + s.v4;
+}
+
+float pass17(struct struct17 s) {
+  return s.v1 + s.v2;
+}
+
+long double pass31(struct struct31 s) {
+  return s.v1 + s.v2;
+}
+
+
+
+struct struct1 pass1a(char b, struct struct1 s) {
+  return s;
+}
+
+struct struct2 pass2a(char b, struct struct2 s) {
+  return s;
+}
+
+struct struct3 pass3a(char b, struct struct3 s) {
+  return s;
+}
+
+struct struct4 pass4a(char b, struct struct4 s) {
+  return s;
+}
+
+struct struct5 pass5a(char b, struct struct5 s) {
+  return s;
+}
+
+struct struct6 pass6a(char b, struct struct6 s) {
+  return s;
+}
+
+struct struct7 pass7a(char b, struct struct7 s) {
+  return s;
+}
+
+struct struct8 pass8a(char b, struct struct8 s) {
+  return s;
+}
+
+struct struct9 pass9a(char b, struct struct9 s) {
+  return s;
+}
+
+struct struct10 pass10a(char b, struct struct10 s) {
+  return s;
+}
+
+struct struct11 pass11a(char b, struct struct11 s) {
+  return s;
+}
+
+struct struct12 pass12a(char b, struct struct12 s) {
+  return s;
+}
+
+struct struct13 pass13a(char b, struct struct13 s) {
+  return s;
+}
+
+struct struct14 pass14a(char b, struct struct14 s) {
+  return s;
+}
+
+struct struct15 pass15a(char b, struct struct15 s) {
+  return s;
+}
+
+struct struct16 pass16a(char b, struct struct16 s) {
+  return s;
+}
+
+struct struct17 pass17a(char b, struct struct17 s) {
+  return s;
+}
+
+struct struct31 pass31a(char b, struct struct31 s) {
+  return s;
+}

+ 462 - 0
tests/test/cg/tcalext6.pp

@@ -0,0 +1,462 @@
+{ Tests passing of different records by value to C methods. 
+ One type of these records has one field which is a simple array of bytes,
+ the other consists of a few fields of atomic size.
+ 
+ Note that it does not only test a single field of these records, but all
+ by comparing the sum of the field values with the sum returned by the
+ C function.
+}
+program calext6;
+{$MODE DELPHI}
+
+{ requires libgcc for the C functions }
+{$ifdef FPUSOFT}
+  {$define NO_FLOAT}
+{$endif}
+
+type
+  int8_t = shortint;
+  pint8_t = ^int8_t;
+  int16_t = smallint;
+  int32_t = longint;
+  int64_t = int64;
+
+var
+  success : boolean;
+
+{$packrecords c}
+
+type
+  struct1 = record
+    v : single;
+  end;
+
+  struct2 = record
+    v : double;
+  end;
+
+  struct3 = record
+    v1 : single;
+    v2 : single;
+  end;
+
+  struct4 = record
+    v1 : double;
+    v2 : single;
+  end;
+
+  struct5 = record
+    v1 : double;
+    v2 : double;
+  end;
+
+  struct6 = record
+    v1 : double;
+    v2 : single;
+    v3 : single;
+  end;
+  
+  struct7 = record
+    v1 : single;
+    v2 : int32_t;
+    v3 : double;
+  end;
+
+  struct8 = record
+    case byte of
+      0: (v1: single);
+      1: (d: double);
+  end;
+
+  struct9 = record
+    v1 : int64_t;
+    v2 : single;
+  end;
+
+  struct10 = record
+    v1 : int64_t;
+    v2 : int16_t;
+    v3 : single;
+  end;
+
+  struct11 = record
+    v1 : int64_t;
+    v2 : double;
+  end;
+
+  struct12 = record
+    v1 : int64_t;
+    v2 : single;
+    v3 : single;
+  end;
+
+  struct13 = record
+    v1 : double;
+    v2 : int64_t;
+  end;
+
+  struct14 = record
+    v1 : double;
+    v2 : int32_t;
+    v3 : int16_t;
+  end;
+  
+  struct15 = record 
+    v1 : double;
+    v2 : int32_t;
+    v3 : single;
+  end;
+
+  struct16 = record
+    v1 : single;
+    v2 : single;
+    v3 : single;
+    v4 : single;
+  end;
+
+  struct17 = record
+    v1 : single;
+    v2 : double;
+  end;
+
+  struct31 = record
+    v1 : cextended;
+    v2 : single;
+  end;
+
+procedure fill(var mem; size : integer);
+var
+  i : Integer;
+  p : pint8_t;
+begin
+  p := @mem;
+  for i := 0 to size-1 do begin
+    p^ := random(255)+1;
+    inc(p);
+  end;
+end;
+
+procedure verify(val1, val2 : int64_t; nr : Integer); overload;
+begin
+  success := success and (val1 = val2);
+  Write('Testing test ', nr , ', was ', val1, ', should be ', val2, '...');
+  if (val1 = val2) then
+    WriteLn('Success.')
+  else
+    WriteLn('Failed');
+end;
+
+procedure verify(val1, val2 : double; nr : Integer); overload;
+begin
+  success := success and (val1 = val2);
+  Write('Testing test ', nr , ', was ', val1, ', should be ', val2, '...');
+  if (val1 = val2) then
+    WriteLn('Success.')
+  else
+    WriteLn('Failed');
+end;
+
+procedure verify(val1, val2 : cextended; nr : Integer); overload;
+begin
+  success := success and (val1 = val2);
+  Write('Testing test ', nr , ', was ', val1, ', should be ', val2, '...');
+  if (val1 = val2) then
+    WriteLn('Success.')
+  else
+    WriteLn('Failed');
+end;
+
+function check1(s : struct1) : single;
+begin
+  result := s.v;
+end;
+
+function check2(s : struct2) : double;
+begin
+  result := s.v;
+end;
+
+function check3(s : struct3) : single;
+begin
+  result := s.v1 + s.v2;
+end;
+
+function check4(s : struct4) : double;
+begin
+  result := s.v1 + s.v2;
+end;
+
+function check5(s : struct5) : double;
+begin
+  result := s.v1 + s.v2;
+end;
+
+function check6(s : struct6) : double;
+begin
+  result := s.v1 + s.v2;
+end;
+
+function check7(s : struct7) : double;
+begin
+  result := s.v1 + s.v2 + s.v3;
+end;
+
+function check8(s : struct8) : double;
+begin
+  result := s.d;
+end;
+
+function check9(s : struct9) : int64_t;
+begin
+  result := s.v1 + trunc(s.v2);
+end;
+
+function check10(s : struct10) : int64_t;
+begin
+  result := s.v1 + s.v2 + trunc(s.v3);
+end;
+
+function check11(s : struct11) : int64_t;
+begin
+  result := s.v1 + trunc(s.v2);
+end;
+
+function check12(s : struct12) : int64_t;
+begin
+  result := s.v1 + trunc(s.v2) + trunc(s.v3);
+end;
+
+function check13(s : struct13) : int64_t;
+begin
+  result := trunc(s.v1) + s.v2 ;
+end;
+
+function check14(s : struct14) : int64_t;
+begin
+  result := trunc(s.v1) + s.v2 + s.v3;
+end;
+
+function check15(s : struct15) : int64_t;
+begin
+  result := trunc(s.v1) + s.v2 + trunc(s.v3);
+end;
+
+function check16(s : struct16) : single;
+begin
+  result := s.v1 + s.v2 + s.v3 + s.v4;
+end;
+
+function check17(s : struct17) : double;
+begin
+  result := s.v1 + s.v2;
+end;
+
+function check31(s : struct31) : cextended;
+begin
+  result := s.v1 + s.v2;
+end;
+
+
+{$L tcext6.o}
+function pass1(s : struct1; b: byte) : single; cdecl; external;
+function pass2(s : struct2; b: byte) : double; cdecl; external;
+function pass3(s : struct3; b: byte) : single; cdecl; external;
+function pass4(s : struct4; b: byte) : double; cdecl; external;
+function pass5(s : struct5; b: byte) : double; cdecl; external;
+function pass6(s : struct6; b: byte) : double; cdecl; external;
+function pass61(d1,d2,d3,d4,d5: double; s : struct6; b: byte) : double; cdecl; external;
+function pass7(s : struct7; b: byte) : double; cdecl; external;
+function pass8(s : struct8; b: byte) : double; cdecl; external;
+function pass9(s : struct9; b: byte) : int64_t; cdecl; external;
+function pass10(s : struct10; b: byte) : int64_t; cdecl; external;
+function pass11(s : struct11; b: byte) : int64_t; cdecl; external;
+function pass12(s : struct12; b: byte) : int64_t; cdecl; external;
+function pass13(s : struct13; b: byte) : int64_t; cdecl; external;
+function pass14(s : struct14; b: byte) : int64_t; cdecl; external;
+function pass15(s : struct15; b: byte) : int64_t; cdecl; external;
+function pass16(s : struct16; b: byte) : single; cdecl; external;
+function pass17(s : struct17; b: byte) : single; cdecl; external;
+{$ifdef FPC_HAS_TYPE_EXTENDED}
+function pass31(s : struct31; b: byte) : cextended; cdecl; external;
+{$endif}
+
+function pass1a(b: byte; s : struct1) : struct1; cdecl; external;
+function pass2a(b: byte; s : struct2) : struct2; cdecl; external;
+function pass3a(b: byte; s : struct3) : struct3; cdecl; external;
+function pass4a(b: byte; s : struct4) : struct4; cdecl; external;
+function pass5a(b: byte; s : struct5) : struct5; cdecl; external;
+function pass6a(b: byte; s : struct6) : struct6; cdecl; external;
+function pass7a(b: byte; s : struct7) : struct7; cdecl; external;
+function pass8a(b: byte; s : struct8) : struct8; cdecl; external;
+function pass9a(b: byte; s : struct9) : struct9; cdecl; external;
+function pass10a(b: byte; s : struct10) : struct10; cdecl; external;
+function pass11a(b: byte; s : struct11) : struct11; cdecl; external;
+function pass12a(b: byte; s : struct12) : struct12; cdecl; external;
+function pass13a(b: byte; s : struct13) : struct13; cdecl; external;
+function pass14a(b: byte; s : struct14) : struct14; cdecl; external;
+function pass15a(b: byte; s : struct15) : struct15; cdecl; external;
+function pass16a(b: byte; s : struct16) : struct16; cdecl; external;
+function pass17a(b: byte; s : struct17) : struct17; cdecl; external;
+{$ifdef FPC_HAS_TYPE_EXTENDED}
+function pass31a(b: byte; s : struct31) : struct31; cdecl; external;
+{$endif}
+
+procedure dotest;
+var
+  s1 : struct1;
+  s2 : struct2;
+  s3 : struct3;
+  s4 : struct4;
+  s5 : struct5;
+  s6 : struct6;
+  s7 : struct7;
+  s8 : struct8;
+  s9 : struct9;
+  s10 : struct10;
+  s11 : struct11;
+  s12 : struct12;
+  s13 : struct13;
+  s14 : struct14;
+  s15 : struct15;
+  s16 : struct16;
+  s17 : struct17;
+  s31 : struct31;
+
+begin
+  success := true;
+
+{$ifndef NO_FLOAT}
+  s1.v:=2.0;
+
+  s2.v:=3.0;
+  
+  s3.v1:=4.5;
+  s3.v2:=5.125;
+  
+  s4.v1:=6.175;
+  s4.v2:=7.5;
+  
+  s5.v1:=8.075;
+  s5.v2:=9.000125;
+  
+  s6.v1:=10.25;
+  s6.v2:=11.5;
+  s6.v3:=12.125;
+  
+  s7.v1:=13.5;
+  s7.v2:=14;
+  s7.v3:=15.0625;
+  
+  s8.d:=16.000575;
+  
+  s9.v1:=$123456789012345;
+  s9.v2:=17.0;
+  
+  s10.v1:=$234567890123456;
+  s10.v2:=-12399;
+  s10.v3:=18.0;
+  
+  s11.v1:=$345678901234567;
+  s11.v2:=19.0;
+  
+  s12.v1:=$456789012345678;
+  s12.v2:=20.0;
+  s12.v3:=21.0;
+  
+  s13.v1:=22.0;
+  s13.v2:=$567890123456789;
+  
+  s14.v1:=23.0;
+  s14.v2:=$19283774;
+  s14.v3:=12356;
+  
+  s15.v1:=24.0;
+  s15.v2:=$28195647;
+  s15.v3:=25.0;
+  
+  s16.v1:=26.5;
+  s16.v2:=27.75;
+  s16.v3:=28.25;
+  s16.v4:=29.125;
+
+  s17.v1:=31.25;
+  s17.v2:=32.125;
+  
+  s31.v1:=32.625;
+  s31.v2:=33.5;
+
+  verify(pass1(s1,1), check1(s1), 1);
+  verify(pass2(s2,2), check2(s2), 2);
+  verify(pass3(s3,3), check3(s3), 3);
+  verify(pass4(s4,4), check4(s4), 4);
+  verify(pass5(s5,5), check5(s5), 5);
+  verify(pass6(s6,6), check6(s6), 6);
+  verify(pass7(s7,7), check7(s7), 7);
+  verify(pass8(s8,8), check8(s8), 8);
+  verify(pass9(s9,9), check9(s9), 9);
+  verify(pass10(s10,10), check10(s10), 10);
+  verify(pass11(s11,11), check11(s11), 11);
+  verify(pass12(s12,12), check12(s12), 12);
+  verify(pass13(s13,13), check13(s13), 13);
+  verify(pass14(s14,14), check14(s14), 14);
+  verify(pass15(s15,15), check15(s15), 15);
+  verify(pass16(s16,16), check16(s16), 16);
+  verify(pass17(s17,17), check17(s17), 17);
+{$ifdef FPC_HAS_TYPE_EXTENDED}
+  verify(pass31(s31,31), check31(s31), 31);
+{$endif}
+
+  verify(check1(pass1a(1,s1)), check1(s1), 41);
+  verify(check2(pass2a(2,s2)), check2(s2), 42);
+  verify(check3(pass3a(3,s3)), check3(s3), 43);
+  verify(check4(pass4a(4,s4)), check4(s4), 44);
+  verify(check5(pass5a(5,s5)), check5(s5), 45);
+  verify(check6(pass6a(6,s6)), check6(s6), 46);
+  verify(check7(pass7a(7,s7)), check7(s7), 47);
+  verify(check8(pass8a(8,s8)), check8(s8), 48);
+  verify(check9(pass9a(9,s9)), check9(s9), 49);
+  verify(check10(pass10a(10,s10)), check10(s10), 50);
+  verify(check11(pass11a(11,s11)), check11(s11), 51);
+  verify(check12(pass12a(12,s12)), check12(s12), 52);
+  verify(check13(pass13a(13,s13)), check13(s13), 53);
+  verify(check14(pass14a(14,s14)), check14(s14), 54);
+  verify(check15(pass15a(15,s15)), check15(s15), 55);
+  verify(check16(pass16a(16,s16)), check16(s16), 56);
+  verify(check17(pass17a(17,s17)), check17(s17), 57);
+{$ifdef FPC_HAS_TYPE_EXTENDED}
+  verify(check31(pass31a(31,s31)), check31(s31), 71);
+{$endif}
+
+  verify(pass1a(1,s1).v, s1.v, 81);
+  verify(pass2a(2,s2).v, s2.v, 82);
+  verify(pass3a(3,s3).v1, s3.v1, 83);
+  verify(pass3a(3,s3).v2, s3.v2, 103);
+  verify(pass4a(4,s4).v1, s4.v1, 84);
+  verify(pass5a(5,s5).v1, s5.v1, 85);
+  verify(pass6a(6,s6).v1, s6.v1, 86);
+  verify(pass7a(7,s7).v1, s7.v1, 87);
+  verify(pass7a(7,s7).v2, s7.v2, 107);
+  verify(pass8a(8,s8).d, s8.d, 88);
+  verify(pass9a(9,s9).v1, s9.v1, 89);
+  verify(pass10a(10,s10).v1, s10.v1, 90);
+  verify(pass10a(10,s10).v2, s10.v2, 90);
+  verify(pass11a(11,s11).v1, s11.v1, 91);
+  verify(pass12a(12,s12).v1, s12.v1, 92);
+  verify(pass13a(13,s13).v1, s13.v1, 93);
+  verify(pass14a(14,s14).v1, s14.v1, 94);
+  verify(pass15a(15,s15).v1, s15.v1, 95);
+  verify(pass16a(16,s16).v1, s16.v1, 96);
+  verify(pass17a(17,s17).v1, s17.v1, 97);
+{$ifdef FPC_HAS_TYPE_EXTENDED}
+  verify(pass31a(31,s31).v1, s31.v1, 101);
+{$endif}
+
+{$endif ndef nofloat}
+
+  if (not success) then
+    halt(1);
+end;
+
+begin
+  dotest;
+end.

이 변경점에서 너무 많은 파일들이 변경되어 몇몇 파일들은 표시되지 않았습니다.