diff --git a/compiler/arm/cpupara.pas b/compiler/arm/cpupara.pas index 60b41dac6e..1fdc985c18 100644 --- a/compiler/arm/cpupara.pas +++ b/compiler/arm/cpupara.pas @@ -45,6 +45,8 @@ unit cpupara; function create_varargs_paraloc_info(p : tabstractprocdef; side: tcallercallee; varargspara:tvarargsparalist):longint;override; function get_funcretloc(p : tabstractprocdef; side: tcallercallee; forcetempdef: tdef): tcgpara;override; private + function usemmpararegs(calloption: tproccalloption; variadic: boolean): boolean; + function getparaloc(calloption : tproccalloption; p : tdef; isvariadic: boolean) : tcgloc; procedure init_values(p: tabstractprocdef; side: tcallercallee; var curintreg, curfloatreg, curmmreg: tsuperregister; var cur_stack_offset: aword; var sparesinglereg: tregister); @@ -131,7 +133,9 @@ unit cpupara; end; - function getparaloc(calloption : tproccalloption; p : tdef; isvariadic: boolean) : tcgloc; + function tcpuparamanager.getparaloc(calloption : tproccalloption; p : tdef; isvariadic: boolean) : tcgloc; + var + basedef: tdef; begin { Later, the LOC_REFERENCE is in most cases changed into LOC_REGISTER if push_addr_param for the def is true @@ -161,7 +165,11 @@ unit cpupara; classrefdef: getparaloc:=LOC_REGISTER; recorddef: - getparaloc:=LOC_REGISTER; + if usemmpararegs(calloption,isvariadic) and + is_hfa(p,basedef) then + getparaloc:=LOC_MMREGISTER + else + getparaloc:=LOC_REGISTER; objectdef: getparaloc:=LOC_REGISTER; stringdef: @@ -176,6 +184,9 @@ unit cpupara; arraydef: if is_dynamic_array(p) then getparaloc:=LOC_REGISTER + else if usemmpararegs(calloption,isvariadic) and + is_hfa(p,basedef) then + getparaloc:=LOC_MMREGISTER else getparaloc:=LOC_REFERENCE; setdef: @@ -229,12 +240,19 @@ unit cpupara; var i: longint; sym: tsym; + basedef: tdef; begin if handle_common_ret_in_param(def,pd,result) then exit; case def.typ of recorddef: begin + if usemmpararegs(pd.proccalloption,is_c_variadic(pd)) and + is_hfa(def,basedef) then + begin + result:=false; + exit; + end; result:=def.size>4; if not result and (target_info.abi in [abi_default,abi_armeb]) then @@ -327,11 +345,13 @@ unit cpupara; var nextintreg,nextfloatreg,nextmmreg : tsuperregister; - paradef : tdef; + paradef, + hfabasedef : tdef; paraloc : pcgparalocation; stack_offset : aword; hp : tparavarsym; loc : tcgloc; + hfabasesize : tcgsize; paracgsize : tcgsize; paralen : longint; i : integer; @@ -359,6 +379,31 @@ unit cpupara; end; + procedure updatemmregs(paradef, basedef: tdef); + var + regsavailable, + regsneeded: longint; + basesize: asizeint; + begin + basesize:=basedef.size; + regsneeded:=paradef.size div basesize; + regsavailable:=ord(RS_D7)-ord(nextmmreg)+1; + case basesize of + 4: + regsavailable:=regsavailable*2+ord(sparesinglereg<>NR_NO); + 8: + ; + else + internalerror(2019022301); + end; + if regsavailableNR_NO)) then begin paraloc^.loc:=LOC_MMREGISTER; @@ -642,35 +707,53 @@ unit cpupara; function tcpuparamanager.get_funcretloc(p : tabstractprocdef; side: tcallercallee; forcetempdef: tdef): tcgpara; var - paraloc : pcgparalocation; + paraloc: pcgparalocation; retcgsize : tcgsize; + basedef: tdef; + i: longint; + mmreg: tregister; begin if set_common_funcretloc_info(p,forcetempdef,retcgsize,result) then exit; paraloc:=result.add_location; { Return in FPU register? } - if result.def.typ=floatdef then + basedef:=nil; + if (result.def.typ=floatdef) or + is_hfa(result.def,basedef) then begin - if (target_info.abi=abi_eabihf) or (p.proccalloption=pocall_hardfloat) then + if usemmpararegs(p.proccalloption,is_c_variadic(p)) then begin - paraloc^.loc:=LOC_MMREGISTER; + if assigned(basedef) then + begin + for i:=2 to result.def.size div basedef.size do + result.add_location; + retcgsize:=def_cgsize(basedef); + end + else + basedef:=result.def; case retcgsize of OS_64, OS_F64: begin - paraloc^.register:=NR_MM_RESULT_REG; + mmreg:=NR_MM_RESULT_REG end; OS_32, OS_F32: begin - paraloc^.register:=NR_S0; + mmreg:=NR_S0; end; else internalerror(2012032501); end; - paraloc^.size:=retcgsize; - paraloc^.def:=result.def; + repeat + paraloc^.loc:=LOC_MMREGISTER; + paraloc^.register:=mmreg; + inc(mmreg); + paraloc^.size:=retcgsize; + paraloc^.def:=basedef; + paraloc:=paraloc^.next; + until not assigned(paraloc); end else if (p.proccalloption in [pocall_softfloat]) or (cs_fp_emulation in current_settings.moduleswitches) or @@ -764,6 +847,14 @@ unit cpupara; end; + function tcpuparamanager.usemmpararegs(calloption: tproccalloption; variadic: boolean): boolean; + begin + result:= + ((target_info.abi=abi_eabihf) or (calloption=pocall_hardfloat)) and + (not variadic); + end; + + function tcpuparamanager.create_paraloc_info(p : tabstractprocdef; side: tcallercallee):longint; var cur_stack_offset: aword;