From 15e9c54b442fb11c1a2863ffb06c7ee052d322bd Mon Sep 17 00:00:00 2001 From: Jonas Maebe Date: Thu, 3 Jun 2010 20:08:50 +0000 Subject: [PATCH] * 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 - --- .gitattributes | 7 + compiler/cgobj.pas | 63 +- compiler/i386/cpupara.pas | 11 + compiler/ncgmem.pas | 17 +- compiler/ncgutil.pas | 33 +- compiler/ppu.pas | 2 +- compiler/symtable.pas | 22 + compiler/x86_64/cgcpu.pas | 34 +- compiler/x86_64/cpupara.pas | 990 ++++++++++++++------ compiler/x86_64/nx64cal.pas | 21 +- tests/Makefile | 4 +- tests/Makefile.fpc | 2 + tests/test/cg/obj/darwin/arm/tcext6.o | Bin 0 -> 14716 bytes tests/test/cg/obj/darwin/i386/tcext6.o | Bin 0 -> 11616 bytes tests/test/cg/obj/darwin/powerpc/tcext6.o | Bin 0 -> 13728 bytes tests/test/cg/obj/darwin/powerpc64/tcext6.o | Bin 0 -> 14868 bytes tests/test/cg/obj/darwin/x86_64/tcext6.o | Bin 0 -> 17448 bytes tests/test/cg/obj/tcext6.c | 246 +++++ tests/test/cg/tcalext6.pp | 462 +++++++++ 19 files changed, 1619 insertions(+), 295 deletions(-) create mode 100644 tests/test/cg/obj/darwin/arm/tcext6.o create mode 100644 tests/test/cg/obj/darwin/i386/tcext6.o create mode 100644 tests/test/cg/obj/darwin/powerpc/tcext6.o create mode 100644 tests/test/cg/obj/darwin/powerpc64/tcext6.o create mode 100644 tests/test/cg/obj/darwin/x86_64/tcext6.o create mode 100644 tests/test/cg/obj/tcext6.c create mode 100644 tests/test/cg/tcalext6.pp diff --git a/.gitattributes b/.gitattributes index ed08906df9..0687e1894b 100644 --- a/.gitattributes +++ b/.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 diff --git a/compiler/cgobj.pas b/compiler/cgobj.pas index 392435a701..e52b793744 100644 --- a/compiler/cgobj.pas +++ b/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; diff --git a/compiler/i386/cpupara.pas b/compiler/i386/cpupara.pas index 236722ba43..111b06d300 100644 --- a/compiler/i386/cpupara.pas +++ b/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 diff --git a/compiler/ncgmem.pas b/compiler/ncgmem.pas index d8e0f7d65c..dd7c9c22e4 100644 --- a/compiler/ncgmem.pas +++ b/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 diff --git a/compiler/ncgutil.pas b/compiler/ncgutil.pas index bc92fbb082..900b9be8e8 100644 --- a/compiler/ncgutil.pas +++ b/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: diff --git a/compiler/ppu.pas b/compiler/ppu.pas index f76cd828e3..11fefe8e30 100644 --- a/compiler/ppu.pas +++ b/compiler/ppu.pas @@ -43,7 +43,7 @@ type {$endif Test_Double_checksum} const - CurrentPPUVersion = 118; + CurrentPPUVersion = 119; { buffer sizes } maxentrysize = 1024; diff --git a/compiler/symtable.pas b/compiler/symtable.pas index b724c4406c..a6f567a7c0 100644 --- a/compiler/symtable.pas +++ b/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; diff --git a/compiler/x86_64/cgcpu.pas b/compiler/x86_64/cgcpu.pas index 8c4b848a5e..fc55bf2277 100644 --- a/compiler/x86_64/cgcpu.pas +++ b/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; diff --git a/compiler/x86_64/cpupara.pas b/compiler/x86_64/cpupara.pas index 2b7070878b..8e9c8833de 100644 --- a/compiler/x86_64/cpupara.pas +++ b/compiler/x86_64/cpupara.pas @@ -56,7 +56,8 @@ unit cpupara; uses cutils,verbose, systems, - defutil; + defutil, + symtable; const paraintsupregs : array[0..5] of tsuperregister = (RS_RDI,RS_RSI,RS_RDX,RS_RCX,RS_R8,RS_R9); @@ -65,181 +66,552 @@ unit cpupara; paraintsupregs_winx64 : array[0..3] of tsuperregister = (RS_RCX,RS_RDX,RS_R8,RS_R9); parammsupregs_winx64 : array[0..3] of tsuperregister = (RS_XMM0,RS_XMM1,RS_XMM2,RS_XMM3); +{ + The argument classification code largely comes from libffi: - function structure_in_registers(varspez:tvarspez;size:longint):boolean; + ffi64.c - Copyright (c) 2002, 2007 Bo Thorsen + Copyright (c) 2008 Red Hat, Inc. + + x86-64 Foreign Function Interface + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the + ``Software''), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to + the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + DEALINGS IN THE SOFTWARE. + ----------------------------------------------------------------------- *) +} + + const + MAX_PARA_CLASSES = 4; + + type + tx64paraclass = ( + X86_64_NO_CLASS, + X86_64_INTEGER_CLASS,X86_64_INTEGERSI_CLASS, + X86_64_SSE_CLASS,X86_64_SSESF_CLASS,X86_64_SSEDF_CLASS,X86_64_SSEUP_CLASS, + X86_64_X87_CLASS,X86_64_X87UP_CLASS, + X86_64_COMPLEX_X87_CLASS, + X86_64_MEMORY_CLASS + ); + tx64paraclasses = array[0..MAX_PARA_CLASSES-1] of tx64paraclass; + + { Win64-specific helper } + function aggregate_in_registers_win64(varspez:tvarspez;size:longint):boolean; begin - if (target_info.system=system_x86_64_win64) then -{ TODO: Temporary hack: vs_const parameters are always passed by reference for win64} - result:=(varspez=vs_value) and (size in [1,2,4,8]) + { TODO: Temporary hack: vs_const parameters are always passed by reference for win64} + result:=(varspez=vs_value) and (size in [1,2,4,8]) + end; + + (* x86-64 register passing implementation. See x86-64 ABI for details. Goal + of this code is to classify each 8bytes of incoming argument by the register + class and assign registers accordingly. *) + + (* Return the union class of CLASS1 and CLASS2. + See the x86-64 PS ABI for details. *) + + function merge_classes(class1, class2: tx64paraclass): tx64paraclass; + begin + (* Rule #1: If both classes are equal, this is the resulting class. *) + if (class1=class2) then + exit(class1); + + (* Rule #2: If one of the classes is NO_CLASS, the resulting class is + the other class. *) + if (class1=X86_64_NO_CLASS) then + exit(class2); + if (class2=X86_64_NO_CLASS) then + exit(class1); + + (* Rule #3: If one of the classes is MEMORY, the result is MEMORY. *) + if (class1=X86_64_MEMORY_CLASS) or + (class2=X86_64_MEMORY_CLASS) then + exit(X86_64_MEMORY_CLASS); + + (* Rule #4: If one of the classes is INTEGER, the result is INTEGER. *) + { 32 bit } + if ((class1=X86_64_INTEGERSI_CLASS) and + (class2=X86_64_SSESF_CLASS)) or + ((class2=X86_64_INTEGERSI_CLASS) and + (class1=X86_64_SSESF_CLASS)) then + exit(X86_64_INTEGERSI_CLASS); + { 64 bit } + if (class1 in [X86_64_INTEGER_CLASS,X86_64_INTEGERSI_CLASS]) or + (class2 in [X86_64_INTEGER_CLASS,X86_64_INTEGERSI_CLASS]) then + exit(X86_64_INTEGER_CLASS); + + (* Rule #5: If one of the classes is X87, X87UP, or COMPLEX_X87 class, + MEMORY is used. *) + if (class1 in [X86_64_X87_CLASS,X86_64_X87UP_CLASS,X86_64_COMPLEX_X87_CLASS]) or + (class2 in [X86_64_X87_CLASS,X86_64_X87UP_CLASS,X86_64_COMPLEX_X87_CLASS]) then + exit(X86_64_MEMORY_CLASS); + + (* Rule #6: Otherwise class SSE is used. *) + result:=X86_64_SSE_CLASS; + end; + + (* Classify the argument of type TYPE and mode MODE. + CLASSES will be filled by the register class used to pass each word + of the operand. The number of words is returned. In case the parameter + should be passed in memory, 0 is returned. As a special case for zero + sized containers, classes[0] will be NO_CLASS and 1 is returned. + + real_size contains either def.size, or a value derived from + def.bitpackedsize and the field offset denoting the number of bytes + spanned by a bitpacked field + + See the x86-64 PS ABI for details. + *) + function classify_as_integer_argument(real_size: aint; var classes: tx64paraclasses; byte_offset: aint): longint; + var + size: aint; + begin + size:=byte_offset+real_size; + if size<=4 then + classes[0]:=X86_64_INTEGERSI_CLASS else - result:=(size<=16); + classes[0]:=X86_64_INTEGER_CLASS; + if size<=8 then + result:=1 + else + begin + if size<=12 then + classes[1]:=X86_64_INTEGERSI_CLASS + else if (size<=16) then + classes[1]:=X86_64_INTEGER_CLASS + else + internalerror(2010021401); + result:=2; + end end; - procedure getvalueparaloc(varspez:tvarspez;p : tdef;var loc1,loc2:tcgloc); + function classify_argument(def: tdef; varspez: tvarspez; real_size: aint; var classes: tx64paraclasses; byte_offset: aint): longint; forward; + + function init_aggregate_classification(def: tdef; varspez: tvarspez; out words: longint; out classes: tx64paraclasses): longint; + var + i: longint; begin - loc1:=LOC_INVALID; - loc2:=LOC_INVALID; - case p.typ of - orddef: - begin - loc1:=LOC_REGISTER; - { TODO: 128bit also needs lochigh} - end; - floatdef: - begin - case tfloatdef(p).floattype of - s80real, - sc80real: - loc1:=LOC_REFERENCE; - s32real, - s64real : - loc1:=LOC_MMREGISTER; - s64currency, - s64comp : - loc1:=LOC_REGISTER; - s128real: - begin - loc1:=LOC_MMREGISTER; - loc2:=LOC_MMREGISTER; - { TODO: float 128bit needs SSEUP lochigh} - end; - end; - end; - recorddef: - begin - if structure_in_registers(varspez,p.size) then - begin - loc1:=LOC_REGISTER; - if p.size>8 then - loc2:=LOC_REGISTER; - end - else - loc1:=LOC_REFERENCE; - end; - objectdef: - begin - if is_object(p) then - begin - if structure_in_registers(varspez,p.size) then - loc1:=LOC_REGISTER - else - loc1:=LOC_REFERENCE; - end - else - loc1:=LOC_REGISTER; - end; - arraydef: - begin - if not(is_special_array(p)) and - (target_info.system=system_x86_64_win64) and - structure_in_registers(varspez,p.size) then - begin - loc1:=LOC_REGISTER; - if p.size>8 then - loc2:=LOC_REGISTER; - end - else - loc1:=LOC_REFERENCE; - end; - variantdef: - { linux abi } - if target_info.system<>system_x86_64_win64 then - loc1:=LOC_REGISTER - else - loc1:=LOC_REFERENCE; - stringdef: - if is_shortstring(p) or is_longstring(p) then - begin - { handle long and shortstrings like arrays } - if structure_in_registers(varspez,p.size) then - begin - loc1:=LOC_REGISTER; - if p.size>8 then - loc2:=LOC_REGISTER; - end - else - loc1:=LOC_REFERENCE; - end - else - loc1:=LOC_REGISTER; - setdef: - if is_smallset(p) then - loc1:=LOC_REGISTER - else - loc1:=LOC_REFERENCE; - procvardef: - begin - if (po_methodpointer in tprocvardef(p).procoptions) then - begin - { This is a record of 16 bytes } - if structure_in_registers(varspez,p.size) then - begin - loc1:=LOC_REGISTER; - loc2:=LOC_REGISTER; - end - else - loc1:=LOC_REFERENCE; - end - else - loc1:=LOC_REGISTER; - end; - else - begin - { default for pointers,enums,etc } - loc1:=LOC_REGISTER; - end; + words:=0; + { win64 follows a different convention here } + if (target_info.system=system_x86_64_win64) then + begin + if aggregate_in_registers_win64(varspez,def.size) then + begin + classes[0]:=X86_64_INTEGER_CLASS; + result:=1; + end + else + result:=0; + exit; + end; + + (* If the struct is larger than 32 bytes, pass it on the stack. *) + if def.size > 32 then + exit(0); + + words:=(def.size+7) div 8; + + (* Zero sized arrays or structures are NO_CLASS. We return 0 to + signal memory class, so handle it as special case. *) + if (words=0) then + begin + classes[0]:=X86_64_NO_CLASS; + exit(1); + end; + + { we'll be merging the classes elements with the subclasses + elements, so initialise them first } + for i:=low(classes) to high(classes) do + classes[i]:=X86_64_NO_CLASS; + result:=words; + end; + + + function classify_aggregate_element(def: tdef; varspez: tvarspez; real_size: aint; var classes: tx64paraclasses; new_byte_offset: aint): longint; + var + subclasses: tx64paraclasses; + i, + pos: longint; + begin + result:=classify_argument(def,varspez,real_size,subclasses,new_byte_offset mod 8); + if (result=0) then + exit; + pos:=new_byte_offset div 8; + if result-1+pos>high(classes) then + internalerror(2010053108); + for i:=0 to result-1 do + begin + classes[i+pos] := + merge_classes(subclasses[i],classes[i+pos]); + end; + end; + + + function finalize_aggregate_classification(def: tdef; words: longint; var classes: tx64paraclasses): longint; + var + i: longint; + begin + if (words>2) then + begin + (* When size > 16 bytes, if the first one isn't + X86_64_SSE_CLASS or any other ones aren't + X86_64_SSEUP_CLASS, everything should be passed in + memory. *) + if (classes[0]<>X86_64_SSE_CLASS) then + exit(0); + + for i:=1 to words-1 do + if (classes[i]<>X86_64_SSEUP_CLASS) then + exit(0); + end; + + (* Final merger cleanup. *) + (* The first one must never be X86_64_SSEUP_CLASS or + X86_64_X87UP_CLASS. *) + if (classes[0]=X86_64_SSEUP_CLASS) or + (classes[0]=X86_64_X87UP_CLASS) then + internalerror(2010021402); + for i:=0 to words-1 do + begin + (* If one class is MEMORY, everything should be passed in + memory. *) + if (classes[i]=X86_64_MEMORY_CLASS) then + exit(0); + + (* The X86_64_SSEUP_CLASS should be always preceded by + X86_64_SSE_CLASS or X86_64_SSEUP_CLASS. *) + if (classes[i]=X86_64_SSEUP_CLASS) and + (classes[i-1]<>X86_64_SSE_CLASS) and + (classes[i-1]<>X86_64_SSEUP_CLASS) then + classes[i]:=X86_64_SSE_CLASS; + + (* If X86_64_X87UP_CLASS isn't preceded by X86_64_X87_CLASS, + everything should be passed in memory. *) + if (classes[i]=X86_64_X87UP_CLASS) and + (classes[i-1]<>X86_64_X87_CLASS) then + exit(0); + end; + + { FIXME: in case a record contains empty padding space, e.g. a + "single" field followed by a "double", then we have a problem + because the cgpara helpers cannot figure out that they should + skip 4 bytes after storing the single (LOC_MMREGISTER with size + OS_F32) to memory before storing the double -> for now scale + such locations always up to 64 bits, although this loads/stores + some superfluous data } + { 1) the first part is 32 bit while there is still a second part } + if (classes[1]<>X86_64_NO_CLASS) then + case classes[0] of + X86_64_INTEGERSI_CLASS: + classes[0]:=X86_64_INTEGER_CLASS; + X86_64_SSESF_CLASS: + classes[0]:=X86_64_SSE_CLASS; + end; + { 2) the second part is 32 bit, but the total size is > 12 bytes } + if (def.size>12) then + case classes[1] of + X86_64_INTEGERSI_CLASS: + classes[1]:=X86_64_INTEGER_CLASS; + X86_64_SSESF_CLASS: + classes[1]:=X86_64_SSE_CLASS; + end; + + result:=words; + end; + + + function classify_record(def: tdef; varspez: tvarspez; var classes: tx64paraclasses; byte_offset: aint): longint; + var + vs: tfieldvarsym; + size, + new_byte_offset: aint; + i, + words, + num: longint; + begin + result:=init_aggregate_classification(def,varspez,words,classes); + if (words=0) then + exit; + + (* Merge the fields of the structure. *) + for i:=0 to tabstractrecorddef(def).symtable.symlist.count-1 do + begin + if tsym(tabstractrecorddef(def).symtable.symlist[i]).typ<>fieldvarsym then + continue; + vs:=tfieldvarsym(tabstractrecorddef(def).symtable.symlist[i]); + num:=-1; + if not tabstractrecordsymtable(tabstractrecorddef(def).symtable).is_packed then + begin + new_byte_offset:=byte_offset+vs.fieldoffset; + size:=vs.vardef.size; + end + else + begin + new_byte_offset:=byte_offset+vs.fieldoffset div 8; + if (vs.vardef.typ in [orddef,enumdef]) then + { calculate the number of bytes spanned by + this bitpacked field } + size:=((vs.fieldoffset+vs.vardef.packedbitsize+7) div 8)-(vs.fieldoffset div 8) + else + size:=vs.vardef.size + end; + num:=classify_aggregate_element(vs.vardef,varspez,size,classes,new_byte_offset); + if (num=0) then + exit(0); + end; + + result:=finalize_aggregate_classification(def,words,classes); + end; + + + function classify_normal_array(def: tarraydef; varspez: tvarspez; var classes: tx64paraclasses; byte_offset: aint): longint; + var + i, elecount: aword; + size, + elesize, + new_byte_offset, + bitoffset: aint; + words, + num: longint; + isbitpacked: boolean; + begin + result:=init_aggregate_classification(def,varspez,words,classes); + if (words=0) then + exit; + + isbitpacked:=is_packed_array(def); + if not isbitpacked then + begin + elesize:=def.elesize; + size:=elesize; + end + else + begin + elesize:=def.elepackedbitsize; + bitoffset:=0; + end; + + (* Merge the elements of the array. *) + i:=0; + elecount:=def.elecount; + repeat + if not isbitpacked then + begin + { size does not change } + new_byte_offset:=byte_offset+i*elesize; + end + else + begin + { calculate the number of bytes spanned by this bitpacked + element } + size:=((bitoffset+elesize+7) div 8)-(bitoffset div 8); + new_byte_offset:=byte_offset+(elesize*i) div 8; + { bit offset of next element } + inc(bitoffset,elesize); + end; + num:=classify_aggregate_element(def.elementdef,varspez,size,classes,new_byte_offset); + if (num=0) then + exit(0); + inc(i); + until (i=elecount); + + result:=finalize_aggregate_classification(def,words,classes); + end; + + + function classify_argument(def: tdef; varspez: tvarspez; real_size: aint; var classes: tx64paraclasses; byte_offset: aint): longint; + begin + case def.typ of + orddef, + enumdef, + pointerdef, + classrefdef: + result:=classify_as_integer_argument(real_size,classes,byte_offset); + formaldef: + result:=classify_as_integer_argument(voidpointertype.size,classes,byte_offset); + floatdef: + begin + case tfloatdef(def).floattype of + s32real: + begin + if byte_offset=0 then + classes[0]:=X86_64_SSESF_CLASS + else + { if we have e.g. a record with two successive "single" + fields, we need a 64 bit rather than a 32 bit load } + classes[0]:=X86_64_SSE_CLASS; + result:=1; + end; + s64real: + begin + classes[0]:=X86_64_SSEDF_CLASS; + result:=1; + end; + s80real, + sc80real: + begin + classes[0]:=X86_64_X87_CLASS; + classes[1]:=X86_64_X87UP_CLASS; + result:=2; + end; + s64comp, + s64currency: + begin + classes[0]:=X86_64_INTEGER_CLASS; + result:=1; + end; + s128real: + begin + classes[0]:=X86_64_SSE_CLASS; + classes[1]:=X86_64_SSEUP_CLASS; + result:=2; + end; + else + internalerror(2010060301); + end; + end; + recorddef: + result:=classify_record(def,varspez,classes,byte_offset); + objectdef: + begin + if is_object(def) then + { pass by reference, like ppc and i386 } + result:=0 + else + { all kinds of pointer types: class, objcclass, interface, ... } + result:=classify_as_integer_argument(voidpointertype.size,classes,byte_offset); + end; + setdef: + begin + if is_smallset(def) then + result:=classify_as_integer_argument(def.size,classes,byte_offset) + else + result:=0; + end; + stringdef: + begin + if (tstringdef(def).stringtype in [st_shortstring,st_longstring]) then + result:=0 + else + result:=classify_as_integer_argument(def.size,classes,byte_offset); + end; + arraydef: + begin + { a dynamic array is treated like a pointer } + if is_dynamic_array(def) then + result:=classify_as_integer_argument(voidpointertype.size,classes,byte_offset) + { other special arrays are passed on the stack } + else if is_open_array(def) or + is_array_of_const(def) then + result:=0 + else + { normal array } + result:=classify_normal_array(tarraydef(def),varspez,classes,byte_offset); + end; + { the file record is definitely too big } + filedef: + result:=0; + procvardef: + begin + if (po_methodpointer in tprocvardef(def).procoptions) then + begin + { treat as TMethod record } + def:=search_system_type('TMETHOD').typedef; + result:=classify_argument(def,varspez,def.size,classes,byte_offset); + end + else + { pointer } + result:=classify_as_integer_argument(def.size,classes,byte_offset); + end; + variantdef: + begin + { same as tvardata record } + def:=search_system_type('TVARDATA').typedef; + result:=classify_argument(def,varspez,def.size,classes,byte_offset); + end; + else + internalerror(2010021405); + end; + end; + + + procedure getvalueparaloc(varspez:tvarspez;def:tdef;var loc1,loc2:tx64paraclass); + var + size: aint; + i: longint; + classes: tx64paraclasses; + numclasses: longint; + begin + { init the classes array, because even if classify_argument inits only + one element we copy both to loc1/loc2 in case "1" is returned } + for i:=low(classes) to high(classes) do + classes[i]:=X86_64_NO_CLASS; + { def.size internalerrors for open arrays and dynamic arrays, since + their size cannot be determined at compile-time. + classify_argument does not look at the realsize argument for arrays + cases, but we obviously do have to pass something... } + if is_special_array(def) then + size:=-1 + else + size:=def.size; + numclasses:=classify_argument(def,varspez,size,classes,0); + case numclasses of + 0: + begin + loc1:=X86_64_MEMORY_CLASS; + loc2:=X86_64_NO_CLASS; + end; + 1,2: + begin + { If the class is X87, X87UP or COMPLEX_X87, it is passed in memory } + if classes[0] in [X86_64_X87_CLASS,X86_64_X87UP_CLASS,X86_64_COMPLEX_X87_CLASS] then + classes[0]:=X86_64_MEMORY_CLASS; + if classes[1] in [X86_64_X87_CLASS,X86_64_X87UP_CLASS,X86_64_COMPLEX_X87_CLASS] then + classes[1]:=X86_64_MEMORY_CLASS; + loc1:=classes[0]; + loc2:=classes[1]; + end + else + { 4 can only happen for _m256 vectors, not yet supported } + internalerror(2010021501); end; end; function tx86_64paramanager.ret_in_param(def : tdef;calloption : tproccalloption) : boolean; var - l,loc1,loc2 : tcgloc; - i : longint; + classes: tx64paraclasses; + numclasses: longint; begin - case target_info.system of - system_x86_64_win64: - result:=(calloption=pocall_safecall) or - (def.size>8) or not(def.size in [1,2,4,8]) + if ((target_info.system=system_x86_64_win64) and + (calloption=pocall_safecall)) then + exit(true); + case def.typ of + { for records it depends on their contents and size } + recorddef, + { make sure we handle 'procedure of object' correctly } + procvardef: + begin + numclasses:=classify_argument(def,vs_value,def.size,classes,0); + result:=(numclasses=0); + end; else - { return method pointers in LOC_REGISTER like records of the same size; - this is SysV only } - if (def.typ=procvardef) and - (po_methodpointer in tprocvardef(def).procoptions) then - result:=false - { handle objectdefs by the default code because they have no equivalence in C } - else if (def.typ in [recorddef {,arraydef }]) and (def.size<=16) then - begin - case def.typ of - recorddef: - begin - l:=LOC_MMREGISTER; - for i:=0 to tabstractrecorddef(def).symtable.SymList.count-1 do - begin - getvalueparaloc(vs_value,tfieldvarsym(tabstractrecorddef(def).symtable.SymList[i]).vardef,loc1,loc2); - case loc1 of - LOC_REGISTER: - if l<>LOC_REFERENCE then - l:=LOC_REGISTER; - LOC_MMREGISTER: - ; - else - l:=LOC_REFERENCE; - end; - end; - end; - arraydef: - begin - getvalueparaloc(vs_value,tarraydef(def).elementdef,l,loc2); - if not(l in [LOC_MMREGISTER,LOC_REGISTER]) then - l:=LOC_REFERENCE; - end; - end; - result:=l=LOC_REFERENCE; - end - else - result:=inherited ret_in_param(def,calloption); + result:=inherited ret_in_param(def,calloption); end; end; @@ -267,6 +639,9 @@ unit cpupara; { true if a parameter is too large to copy and only the address is pushed } function tx86_64paramanager.push_addr_param(varspez:tvarspez;def : tdef;calloption : tproccalloption) : boolean; + var + classes: tx64paraclasses; + numclasses: longint; begin result:=false; { var,out always require address } @@ -277,51 +652,55 @@ unit cpupara; end; { Only vs_const, vs_value here } case def.typ of - variantdef, formaldef : result:=true; recorddef : begin - { Win ABI depends on size to pass it in a register or not } - if (target_info.system=system_x86_64_win64) then - result:=not structure_in_registers(varspez,def.size) { MetroWerks Pascal: const records always passed by reference (for Mac OS X interfaces) } - else if (calloption=pocall_mwpascal) and - (varspez=vs_const) then + if (calloption=pocall_mwpascal) and + (varspez=vs_const) then result:=true + { Win ABI depends on size to pass it in a register or not } + else if (target_info.system=system_x86_64_win64) then + result:=not aggregate_in_registers_win64(varspez,def.size) else - { linux ABI always passes it as value parameter } + { SysV ABI always passes it as value parameter } result:=false; end; arraydef : begin { cdecl array of const need to be ignored and therefor be puhsed as value parameter with length 0 } - if (calloption in [pocall_cdecl,pocall_cppdecl]) and - (is_array_of_const(def) or - is_dynamic_array(def)) then + if ((calloption in [pocall_cdecl,pocall_cppdecl]) and + is_array_of_const(def)) or + is_dynamic_array(def) then result:=false else - result:=true; + { pass all arrays by reference to be compatible with C (passing + an array by value (= copying it on the stack) does not exist, + because an array is the same as a pointer there } + result:=true end; objectdef : begin + { don't treat objects like records, because we only know wheter + or not they'll have a VMT after the entire object is parsed + -> if they are used as function result from one of their own + methods, their size can still change after we've determined + whether this function result should be returned by reference or + by value } if is_object(def) then - result:=not structure_in_registers(varspez,def.size); - end; - stringdef : - begin - if (tstringdef(def).stringtype in [st_shortstring,st_longstring]) then - result:=not structure_in_registers(varspez,def.size); - end; - procvardef : - begin - if (po_methodpointer in tprocvardef(def).procoptions) then - result:=not structure_in_registers(varspez,def.size); + result:=true; end; + variantdef, + stringdef, + procvardef, setdef : - result:=not is_smallset(def); + begin + numclasses:=classify_argument(def,vs_value,def.size,classes,0); + result:=numclasses=0; + end; end; end; @@ -405,7 +784,15 @@ unit cpupara; function tx86_64paramanager.get_funcretloc(p : tabstractprocdef; side: tcallercallee; def: tdef): tcgpara; + const + intretregs: array[0..1] of tregister = (NR_FUNCTION_RETURN_REG,NR_FUNCTION_RETURN_REG_HIGH); + mmretregs: array[0..1] of tregister = (NR_MM_RESULT_REG,NR_MM_RESULT_REG_HIGH); var + classes: tx64paraclasses; + i, + numclasses: longint; + intretregidx, + mmretregidx: longint; retcgsize : tcgsize; paraloc : pcgparalocation; begin @@ -442,22 +829,24 @@ unit cpupara; exit; end; - paraloc:=result.add_location; - { Return in FPU register? } + { Return in FPU register? -> don't use classify_argument(), because + currency and comp need special treatment here (they are integer class + when passing as parameter, but LOC_FPUREGISTER as function result) } if def.typ=floatdef then begin + paraloc:=result.add_location; case tfloatdef(def).floattype of s32real: begin paraloc^.loc:=LOC_MMREGISTER; paraloc^.register:=newreg(R_MMREGISTER,RS_MM_RESULT_REG,R_SUBMMS); - paraloc^.size:=retcgsize; + paraloc^.size:=OS_F32; end; s64real: begin paraloc^.loc:=LOC_MMREGISTER; paraloc^.register:=newreg(R_MMREGISTER,RS_MM_RESULT_REG,R_SUBMMD); - paraloc^.size:=retcgsize; + paraloc^.size:=OS_F64; end; { the first two only exist on targets with an x87, on others they are replace by int64 } @@ -477,47 +866,67 @@ unit cpupara; else { Return in register } begin - paraloc^.loc:=LOC_REGISTER; - if retcgsize=OS_NO then + numclasses:=classify_argument(def,vs_value,def.size,classes,0); + { this would mean a memory return } + if (numclasses=0) then + internalerror(2010021502); + { this would mean an _m256 vector (valid, but not yet supported) } + if (numclasses>2) then + internalerror(2010021503); + intretregidx:=0; + mmretregidx:=0; + for i:=0 to numclasses-1 do begin - case def.size of - 0..4: - begin - paraloc^.size:=OS_32; - paraloc^.register:=newreg(R_INTREGISTER,RS_FUNCTION_RESULT_REG,R_SUBD); - end; - 5..8: - begin - paraloc^.size:=OS_64; - paraloc^.register:=newreg(R_INTREGISTER,RS_FUNCTION_RESULT_REG,R_SUBQ); - end; - 9..16: - begin - paraloc^.size:=OS_64; - paraloc^.register:=newreg(R_INTREGISTER,RS_FUNCTION_RESULT_REG,R_SUBWHOLE); - paraloc:=result.add_location; - paraloc^.size:=OS_64; - paraloc^.loc:=LOC_REGISTER; - paraloc^.register:=newreg(R_INTREGISTER,RS_RDX,R_SUBWHOLE); - end; - end; - end - else if retcgsize in [OS_128,OS_S128] then - begin - paraloc^.size:=OS_64; - paraloc^.register:=newreg(R_INTREGISTER,RS_FUNCTION_RESULT_REG,R_SUBWHOLE); paraloc:=result.add_location; - paraloc^.size:=OS_64; - paraloc^.loc:=LOC_REGISTER; - paraloc^.register:=newreg(R_INTREGISTER,RS_RDX,R_SUBWHOLE); - end - else - begin - paraloc^.size:=retcgsize; - if side=callerside then - paraloc^.register:=newreg(R_INTREGISTER,RS_FUNCTION_RESULT_REG,cgsize2subreg(R_INTREGISTER,retcgsize)) - else - paraloc^.register:=newreg(R_INTREGISTER,RS_FUNCTION_RETURN_REG,cgsize2subreg(R_INTREGISTER,retcgsize)); + case classes[i] of + X86_64_INTEGERSI_CLASS, + X86_64_INTEGER_CLASS: + begin + paraloc^.loc:=LOC_REGISTER; + paraloc^.register:=intretregs[intretregidx]; + if classes[i]=X86_64_INTEGER_CLASS then + paraloc^.size:=OS_64 + else if result.intsize in [1,2,4] then + paraloc^.size:=retcgsize + else + paraloc^.size:=OS_32; + setsubreg(paraloc^.register,cgsize2subreg(R_INTREGISTER,paraloc^.size)); + inc(intretregidx); + end; + X86_64_SSE_CLASS, + X86_64_SSEUP_CLASS, + X86_64_SSESF_CLASS, + X86_64_SSEDF_CLASS: + begin + paraloc^.loc:=LOC_MMREGISTER; + paraloc^.register:=mmretregs[mmretregidx]; + case classes[i] of + X86_64_SSESF_CLASS: + begin + setsubreg(paraloc^.register,R_SUBMMS); + paraloc^.size:=OS_F32; + end; + X86_64_SSEDF_CLASS: + begin + setsubreg(paraloc^.register,R_SUBMMD); + paraloc^.size:=OS_F64; + end; + else + paraloc^.size:=OS_M64; + end; + inc(mmretregidx); + end; + X86_64_NO_CLASS: + begin + { empty record/array } + if (i<>0) or + (numclasses<>1) then + internalerror(2010060302); + paraloc^.loc:=LOC_VOID; + end; + else + internalerror(2010021504); + end; end; end; end; @@ -531,7 +940,9 @@ unit cpupara; subreg : tsubregister; pushaddr : boolean; paracgsize : tcgsize; - loc : array[1..2] of tcgloc; + loc : array[1..2] of tx64paraclass; + needintloc, + needmmloc, paralen, locidx, i, @@ -546,8 +957,8 @@ unit cpupara; pushaddr:=push_addr_param(hp.varspez,hp.vardef,p.proccalloption); if pushaddr then begin - loc[1]:=LOC_REGISTER; - loc[2]:=LOC_INVALID; + loc[1]:=X86_64_INTEGER_CLASS; + loc[2]:=X86_64_NO_CLASS; paracgsize:=OS_ADDR; paralen:=sizeof(aint); end @@ -563,12 +974,17 @@ unit cpupara; (target_info.system = system_x86_64_win64) and (hp.vardef.typ = floatdef) then begin - loc[1] := LOC_REGISTER; - loc[2] := LOC_INVALID; - if paracgsize = OS_F64 then - paracgsize := OS_64 + loc[2]:=X86_64_NO_CLASS; + if paracgsize=OS_F64 then + begin + loc[1]:=X86_64_INTEGER_CLASS; + paracgsize:=OS_64 + end else - paracgsize := OS_32; + begin + loc[1]:=X86_64_INTEGERSI_CLASS; + paracgsize:=OS_32; + end; end; hp.paraloc[side].reset; @@ -577,42 +993,60 @@ unit cpupara; hp.paraloc[side].Alignment:=paraalign; if paralen>0 then begin + { Enough registers free? } + needintloc:=0; + needmmloc:=0; + for locidx:=low(loc) to high(loc) do + case loc[locidx] of + X86_64_INTEGER_CLASS, + X86_64_INTEGERSI_CLASS: + inc(needintloc); + X86_64_SSE_CLASS, + X86_64_SSESF_CLASS, + X86_64_SSEDF_CLASS, + X86_64_SSEUP_CLASS: + inc(needmmloc); + end; + { the "-1" is because we can also use the current register } + if ((target_info.system=system_x86_64_win64) and + ((intparareg+needintloc-1 > high(paraintsupregs_winx64)) or + (mmparareg+needmmloc-1 > high(parammsupregs_winx64)))) or + ((target_info.system<>system_x86_64_win64) and + ((intparareg+needintloc-1 > high(paraintsupregs)) or + (mmparareg+needmmloc-1 > high(parammsupregs)))) then + begin + { If there are no registers available for any + eightbyte of an argument, the whole argument is + passed on the stack. } + loc[low(loc)]:=X86_64_MEMORY_CLASS; + for locidx:=succ(low(loc)) to high(loc) do + loc[locidx]:=X86_64_NO_CLASS; + end; + locidx:=1; while (paralen>0) do begin if locidx>2 then internalerror(200501283); - { Enough registers free? } - case loc[locidx] of - LOC_REGISTER : - begin - { winx64 uses different registers } - if ((target_info.system=system_x86_64_win64) and - (intparareg>high(paraintsupregs_winx64))) or - ((target_info.system<>system_x86_64_win64) and - (intparareg>high(paraintsupregs))) then - loc[locidx]:=LOC_REFERENCE; - end; - LOC_MMREGISTER : - begin - { winx64 uses different registers } - if ((target_info.system=system_x86_64_win64) and - (mmparareg>high(parammsupregs_winx64))) or - ((target_info.system<>system_x86_64_win64) and - (mmparareg>high(parammsupregs))) then - loc[locidx]:=LOC_REFERENCE; - end; - end; { Allocate } case loc[locidx] of - LOC_REGISTER : + X86_64_INTEGER_CLASS, + X86_64_INTEGERSI_CLASS: begin paraloc:=hp.paraloc[side].add_location; paraloc^.loc:=LOC_REGISTER; - if (paracgsize=OS_NO) or (loc[2]<>LOC_INVALID) then + if (paracgsize=OS_NO) or (loc[2]<>X86_64_NO_CLASS) then begin - paraloc^.size:=OS_INT; - subreg:=R_SUBWHOLE; + if loc[locidx]=X86_64_INTEGER_CLASS then + begin + paraloc^.size:=OS_INT; + subreg:=R_SUBWHOLE; + end + else + begin + paraloc^.size:=OS_32; + subreg:=R_SUBD; + end; end else begin @@ -636,18 +1070,30 @@ unit cpupara; inc(intparareg); dec(paralen,tcgsize2size[paraloc^.size]); end; - LOC_MMREGISTER : + X86_64_SSE_CLASS, + X86_64_SSESF_CLASS, + X86_64_SSEDF_CLASS, + X86_64_SSEUP_CLASS: begin paraloc:=hp.paraloc[side].add_location; paraloc^.loc:=LOC_MMREGISTER; - case paracgsize of - OS_F32: - subreg:=R_SUBMMS; - OS_F64: - subreg:=R_SUBMMD; + case loc[locidx] of + X86_64_SSESF_CLASS: + begin + subreg:=R_SUBMMS; + paraloc^.size:=OS_F32; + end; + X86_64_SSEDF_CLASS: + begin + subreg:=R_SUBMMD; + paraloc^.size:=OS_F64; + end; else - subreg:=R_SUBMMWHOLE; + begin + subreg:=R_SUBMMWHOLE; + paraloc^.size:=OS_M64; + end; end; { winx64 uses different registers } @@ -655,10 +1101,6 @@ unit cpupara; paraloc^.register:=newreg(R_MMREGISTER,parammsupregs_winx64[mmparareg],subreg) else paraloc^.register:=newreg(R_MMREGISTER,parammsupregs[mmparareg],subreg); - if paracgsize=OS_F128 then - paraloc^.size:=OS_F64 - else - paraloc^.size:=paracgsize; { matching int register must be skipped } if target_info.system=system_x86_64_win64 then @@ -667,7 +1109,7 @@ unit cpupara; inc(mmparareg); dec(paralen,tcgsize2size[paraloc^.size]); end; - LOC_REFERENCE : + X86_64_MEMORY_CLASS : begin paraloc:=hp.paraloc[side].add_location; paraloc^.loc:=LOC_REFERENCE; @@ -695,9 +1137,11 @@ unit cpupara; parasize:=align(parasize+paralen,varalign); paralen:=0; end; + else + internalerror(2010053113); end; if (locidx<2) and - (loc[locidx+1]<>LOC_INVALID) then + (loc[locidx+1]<>X86_64_NO_CLASS) then inc(locidx); end; end diff --git a/compiler/x86_64/nx64cal.pas b/compiler/x86_64/nx64cal.pas index 58fd78c7a8..1217282463 100644 --- a/compiler/x86_64/nx64cal.pas +++ b/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. diff --git a/tests/Makefile b/tests/Makefile index 887c4fe031..f13f517e6d 100644 --- a/tests/Makefile +++ b/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 diff --git a/tests/Makefile.fpc b/tests/Makefile.fpc index ebdf293c1f..cbb2ac3c38 100644 --- a/tests/Makefile.fpc +++ b/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 diff --git a/tests/test/cg/obj/darwin/arm/tcext6.o b/tests/test/cg/obj/darwin/arm/tcext6.o new file mode 100644 index 0000000000000000000000000000000000000000..fed0ac0a235d38f24203f8727d9063ecb9aa5892 GIT binary patch literal 14716 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 literal 0 HcmV?d00001 diff --git a/tests/test/cg/obj/darwin/i386/tcext6.o b/tests/test/cg/obj/darwin/i386/tcext6.o new file mode 100644 index 0000000000000000000000000000000000000000..378a5f6d9982b38c8991cf4481237b8b286b84c2 GIT binary patch literal 11616 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 k2_tU>Oldij-8fajdw2K6V9?EeoL! zB9a9bn{k0sjpW83Nhx+6gBgD$a%x%}6D((#4rE-LHtv)ef0WMH9*ym|nlYKUwqp7_ z_nx=I_|<2x5z*E7h454O`H1X;L=iwP+a(Mx zy%zSO?Klxj3d-*)=GE7CH}`fkGFN^5y06r&b4#ww%r*LC5iKb~ZBCMGw-GivT4P+_X$)<|AIhn+-$HJFM;njp7{Y;^QAwPSX>F14}X1@z+( z(W15~*y!HgF_DcMZi9_kL_+#3zVHeydSjJU3+kU?Lk`-555mOUI&Z zj1pbhhAfW>Y%J9Cg*ASib|Sa&{b+0LZtiSsD>IFk?zx36Xvu<&2qeyl)HSwo&Csx~ ziW|_nkf@{vG34DJ#!vPLkh$_8_~)1Ml*P-hT>SKVb1$AvtPb~{T}_okbEtAOLj6fZ z`6aY{BS{hA3^C{2YRW%7hw>-kXgmEosj~kN)x2_2+pGC#8ZDZHuWf=K0Y9(*B<1(N zLj`9}QUv|TAN@V_bl-jty{Y(1IM$IhkCA^zrFA6X_>Q38b?Enc^t%E5j=yq<>XLJ4 z{i;Ys(aNt8m95DyIr9Wj8zrfK4iyZzv7?rJEW+H6GHKCoAE$owxnT-p&4;goiDJ+F zdU^N7k$y!E=JIi#C-kix{I%#?CHhu#{~;>B|0Jz-=ePRe7a57BYkL#-&+kpdhI0~Y z{w*gFN4X-qm*+kSTRg^>V3*gxRDA4)&)x9(IMz^tf+dNJFFF!FU+<22)xEo(&CS{M zXESo(zlPUB^~K-r`>*!zjuA1^YZyKj{CD{ni{t1ku8&VX}T)x~@Kt{w^{1o`3GSg*{V?J+sa| zzkc-`Ey8@)id=V@^K9Jt$98y~$R4lJdmQ^d{Ve1;slNExcJ!qM`OZg z`@f*tfjP7e=SbbaMp|FCk;>0B5uLe@9PZ!BdLs69=I8U@9gWoWkCr#|k2bXQk0v{? z-#)u$l$`$2NEYf@nlnDN&*8iJ;(uK5#zV(3IiH^kwU1(+*~eKt=-e}6qUVFF!_Num ztmpIU+~hhsUc81A@Z-jveI?-w>v~;(22p<%**oS}>vQRHKA|7MyyYQI`G`{i`-h## z?$wlsvnhY~Mk?q>Uk2upJ1M-30Q;NdHF4<6LrJCl#PQ ziS|8c-;4GGXfHy03EIohzOsxip6BO8VjjI#R!&(ckE~dYat6JYh+Okp!Z+i!-MeY+ zj%39VZ_bYwh|G()6sbg8rsDUB2;bz&;};cYdeLL*kj2oRHb=Ka^xeFR2&a594!_S9 zUBON-IAw-2shz*OI>y%_}G2$a}DV4>$*yV`sGKuV0zdlh$Jk4qcBs-W`MI6H{ndSJ_8(& z@+;Um4o;onOlBv@{kamSWeS|3G0tTB*U1G(`aD^GoVqbPlX3>H%*k-3z-gEQX9_V4 zO(BM%Da0@|G}fQVVi@Ka)?9wx!*Ot4Fr3=7b25C=eB83tSHE#bq#{zXqWCF~H+OY+ z>3d;pbK#bzyWx~C^X1o4fv(og_~sUgwKR5;ueH59T3X*t)-|B)wJd*E%a+dW2, z(qeAo)BZ`z_Pe#EC0sinwLi5Sf7_P!%@KX$c1t-u?Oqp_6*M+e)tY7p$CsVpn4R%0 zw(%fZnl+AK;|pL2>TP?nm3y7QWfPtn?>re+(e<5HJ_ zIum^gYbw5wj#06ExR9cjf_g2e6`DHROTA94`nN45g{k3zX1XqxLk}NxtnX^Qd8Ug9nwy2Nq4doiff^GSSxtto?9`S)g_blUbZRst}kTFmorE6{&s}tNUCg zvrgf+9O*?4Gw%cQk<{4B)B|ABGls6*NnwbxPIhgVuSNny@EbAzk17Nl=b3ZEH zOfm0KeJ&F$P9D`sFdt-QA1ZQE%ue;7Fqy@vqxulc6U=-N73C@BcJ;8!1j{!9hq++B z&&-EWu|361svo#ausD6Ru-$@L%=`hEhf~ZyRfmMhEI-0vVG@HkGV>6a@1&T0>IpD; z)iH}xNb4~$lPG+Sd|ByQ3GQr|R()tCMeat)p=7tpW*Xn67?PG?;>7n&&FkfWm z(`eY|8yMPY7Sq#ekd3awfI;Id(T9UK`0t@6QiBYvf!VAE%o`wrXJkM>ef388SM>sG zV_UH%=a0UxV$FD;m^YM+>!5m-wH`sQpuxGSje{{` zD{H;#(E|2tuG8u)YYiF=2h!dHt*2P)tVavjv(a8xZ?M*z(1Hf%v-b0lZ?o1L9xY(c zrXzI@TD}~kk&G@`J z&sy7!24}(kGHC5$t@9o&V9&;UU%ks(SP!hhd9lA4@)&Eq>(K)CY|_c6-?3C5$DG_AhA;?{~S z?OolC?cKL`ceb`~u4rrQ>bk9YQ*&o?dkg`BC8hA)WQJPcWQTpuwayH6waN-$_VXwl zUX3aYeJ1&w8^bq+tB?}f*~;gH!(3D-`lqGZ%0lSeEH%~^9BadJn?_aHOvzZHZqD>g zX9G86R%Nrl@&KC(`BSDW@WM(}WpjPzT=a8V2^y=iZ_X^qT$zb7uG#X=VM_XL-V#iO zTBF-HDE0aDX@pTCj)b2o?CI((Y-?>Q+#HJ)c5L}}b7x0vaU;K~ERHvJe!I0jT2!cC zUZJ?Lb7McNAloX>Ms@WC zD=!=WoFB0)7dctEQrcNM&pFRsaC)3o7p$^u{Bs7K=kA9S{NDTIf|Z}`yf?x9a&438 zaQAvHSPAZ@m4le^*l;AlF z0^}6$lxC)1~pl)A`erhK${)j=JQdD4a?spF-suhWrNL zIgrnj2849T*T)6-()m%DCR=6LrYnUEzPDXHTj0d5EAlnu)0NK51WK@v7*O2!D!n5uM z04GS}yMYSwo8<{Xep#N7oJfsZo+y*wtT+hr%Zh{KOlmxJ59+?By8uD{N702OHaY+& zNxnWVxECrYkgLfM6u_~>I|PzbqH%Unra+CM)&SPR?hxz%a3VB*3F*uzX~;>mqmSAy z`iAspyj{#~V8~F10I|S~-BWl%aDP#mx==wu(_aV*&K5EN=Q?TR7F2d<%McXAcNJ|J zfPzEmWVi{QHssTQubLi1a$+;C$2!r8XsQ!IbDr1*-~?!VCpaT=8VtDsFz%A$C=8~P z2T^I3JOnws|p^PW%l*LR*2vZVrrv!i#lQc4Xhs=~fP{^GU01Bl~2`VULrUZgQG9{3l zg^ZgLot2m=2}jV3)1B8FBquB5sR(?yO-BNP!X1djS<-+%)cN|j;9htylHJ1p#iV_z z0~tsZjrPZkih=yOjFvK5!>EK&8>3~69%fX^Xo%5rMjtRL0}A9Y!WS02Rx*mB%Xn|p zki7&R)R5f-PH4z}0`F_cj)GYlvZvsU8nUZkTtoI1>|=;;3V<)_+D3-IVOY%2S*!^f z#u%1p_mu!{r*@#IQ`mtqfOa_!Prvk;ZRp9AzBJ)>u0XRcX9b*YDC; zy9^!ESo;ipsIhh$o~yC;8orb9Qf(7v2?>^Gc4#|N8~sHUO%DO_78%;8o04d(c&V+M18)p>(C!dBQ|4zX2XFvr+>#9*FLYtUexQ|nEG^{o1Gq`*_* zE0+Sh_HCB}`}Q4{0z3D;BL((u&yoVWw>LA$UKo`r1h*w#DVQw(m&4FbUDjNe#zuAf4H2Sq z%o7BABa3IQsS6#pOklstPxo$a;C_ujdae7d`slhB9Dmd7TFXWmm+&aZWUQA@~a}}ioDLqz;8r;BJv+Zo)P&&k>V$SuN&+yAbtY) zu&&GEC$K=u;>Z8FDf`8b{~x6+e*8~KS^W5SNLl>&ZOh)kN(h1;WIuf^~Zs) zlX{NNIfFT0Cm9zF1D}_A9?O>vRuSM~sUHF^mimLhBL;KIO)I4S6!51~UkCgrW79?D z9(>q?pZ8$>Z5w*{9~bn~#fV}fmKsrF#4;mFjaY6(nGq}S|18vRYVGaX6mK;(c+wk- zQE7^gHHrDC*vAvnP{jkDk)|v@@G$FY+}3<+EnC_gi`8#!jK`@He_-Y+d2(urhoP2u zf@+C}qLz4+YKf<#mUyIUiKIh)u?NhAJw`^(z5>q D5F^E( literal 0 HcmV?d00001 diff --git a/tests/test/cg/obj/darwin/powerpc64/tcext6.o b/tests/test/cg/obj/darwin/powerpc64/tcext6.o new file mode 100644 index 0000000000000000000000000000000000000000..daf4019a36e9185ac636d1b694232d048d3d45f2 GIT binary patch literal 14868 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 MY3Vl2MSLXtA0(YgBLDyZ literal 0 HcmV?d00001 diff --git a/tests/test/cg/obj/darwin/x86_64/tcext6.o b/tests/test/cg/obj/darwin/x86_64/tcext6.o new file mode 100644 index 0000000000000000000000000000000000000000..988134537550a0093749a5516729120b582bc603 GIT binary patch literal 17448 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 literal 0 HcmV?d00001 diff --git a/tests/test/cg/obj/tcext6.c b/tests/test/cg/obj/tcext6.c new file mode 100644 index 0000000000..848248f702 --- /dev/null +++ b/tests/test/cg/obj/tcext6.c @@ -0,0 +1,246 @@ +#include + +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; +} diff --git a/tests/test/cg/tcalext6.pp b/tests/test/cg/tcalext6.pp new file mode 100644 index 0000000000..1a8f0bf22e --- /dev/null +++ b/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.