diff --git a/compiler/llvm/llvmdef.pas b/compiler/llvm/llvmdef.pas index 34d3d99af2..f5e995f6c6 100644 --- a/compiler/llvm/llvmdef.pas +++ b/compiler/llvm/llvmdef.pas @@ -742,11 +742,16 @@ implementation register (-> paranr_result is smaller than paranr_self for that platform in symconst) } {$ifdef aarch64} - if not first then + if not first and + not is_managed_type(hp.vardef) then internalerror(2015101404); {$endif aarch64} if withattributes then - if first then + if first +{$ifdef aarch64} + and not is_managed_type(hp.vardef) +{$endif aarch64} + then encodedstr:=encodedstr+' sret noalias nocapture' else encodedstr:=encodedstr+' noalias nocapture'; diff --git a/compiler/llvm/llvmpara.pas b/compiler/llvm/llvmpara.pas index 64fe80d464..44cba6426a 100644 --- a/compiler/llvm/llvmpara.pas +++ b/compiler/llvm/llvmpara.pas @@ -148,7 +148,12 @@ unit llvmpara; paralocs } while assigned(paraloc) do begin - if vo_is_funcret in parasym.varoptions then + if (vo_is_funcret in parasym.varoptions) + {$ifdef aarch64} + { see AArch64's tcpuparamanager.create_paraloc_info_intern() } + and not is_managed_type(parasym.vardef) + {$endif aarch64} + then paraloc^.retvalloc:=true; { ordinal parameters must be passed as a single paraloc } if (cgpara.def.typ in [orddef,enumdef,floatdef]) and diff --git a/compiler/pparautl.pas b/compiler/pparautl.pas index 73f4ef3e4b..b61173d50c 100644 --- a/compiler/pparautl.pas +++ b/compiler/pparautl.pas @@ -105,6 +105,9 @@ implementation paranr:=paranr_result_leftright else {$endif} + if is_managed_type(pd.returndef) then + paranr:=paranr_result_managed + else paranr:=paranr_result; { Generate result variable accessing function result } vs:=cparavarsym.create('$result',paranr,vs_var,pd.returndef,[vo_is_funcret,vo_is_hidden_para]); diff --git a/compiler/symconst.pas b/compiler/symconst.pas index 9c91944020..08951b97ca 100644 --- a/compiler/symconst.pas +++ b/compiler/symconst.pas @@ -124,10 +124,10 @@ const paranr_blockselfpara = 1; paranr_parentfp_delphi_cc_leftright = 2; {$if defined(aarch64) and defined(llvm)} - { for AArch64 on LLVM, the "sret" parameter - must always be the first -> give it a higher number; can't do it for other - platforms, because that would change the register assignment/parameter order - and the current one is presumably Delphi-compatible } + { for AArch64 on LLVM, the "sret" parameter must always be the first + (it gets passed in a dedicated register, so it won't shift the register + assignments) -> give it a lower number; can't do it for other platforms, + because that would change the register assignment/parameter order } paranr_result = 2; paranr_parentfp = 3; paranr_self = 4; @@ -136,12 +136,19 @@ const paranr_self = 3; paranr_result = 4; {$endif} - paranr_vmt = 5; + { pointers to managed result parameters must always be passed in the same way as the first regular + parameter, regardless of ABI conventions, because the RTL expects the two following declarations + to be handled in the same way: + function f: com_interface; + procedure p(out o: obj); + } + paranr_result_managed = 5; + paranr_vmt = 6; { the implicit parameters for Objective-C methods need to come after the hidden result parameter } - paranr_objc_self = 5; - paranr_objc_cmd = 6; + paranr_objc_self = 7; + paranr_objc_cmd = 8; { Required to support variations of syscalls on Amiga-likes } paranr_syscall_lib_first = 9; { for basefirst on MorphOS/ppc and AmigaOS4/ppc }