From e237da95d2b16fe25ef196674215cb341b983188 Mon Sep 17 00:00:00 2001 From: Nikolay Nikolov <nickysn@gmail.com> Date: Tue, 25 Feb 2025 07:21:13 +0200 Subject: [PATCH] * most of tcgcallparanode.secondcallparan's code was moved into two new methods: secondcallparan_do_secondpass and secondcallparan_after_secondpass. These are protected methods, meant to be called in secondcallparan's descendants, to provide alternative parameter handling algorithms (needed for WebAssembly). No functional changes. --- compiler/ncgcal.pas | 238 +++++++++++++++++++++++--------------------- 1 file changed, 126 insertions(+), 112 deletions(-) diff --git a/compiler/ncgcal.pas b/compiler/ncgcal.pas index bf40111498..1150afc817 100644 --- a/compiler/ncgcal.pas +++ b/compiler/ncgcal.pas @@ -40,6 +40,9 @@ interface procedure push_formal_para;virtual; procedure push_copyout_para;virtual;abstract; function maybe_push_unused_para:boolean;virtual; + + procedure secondcallparan_do_secondpass; + procedure secondcallparan_after_secondpass; public tempcgpara : tcgpara; @@ -317,9 +320,128 @@ implementation end; - procedure tcgcallparanode.secondcallparan; + procedure tcgcallparanode.secondcallparan_do_secondpass; + begin + if assigned(fparainit) then + secondpass(fparainit); + secondpass(left); + end; + + + procedure tcgcallparanode.secondcallparan_after_secondpass; var - pushaddr: boolean; + pushaddr: boolean; + begin + hlcg.maybe_change_load_node_reg(current_asmdata.CurrAsmList,left,true); + + paramanager.createtempparaloc(current_asmdata.CurrAsmList,aktcallnode.procdefinition.proccalloption,parasym,not followed_by_stack_tainting_call_cached,tempcgpara); + + { handle varargs first, because parasym is not valid } + if (cpf_varargs_para in callparaflags) then + begin + if paramanager.push_addr_param(vs_value,left.resultdef, + aktcallnode.procdefinition.proccalloption) then + push_addr_para + else + push_value_para; + end + { hidden parameters } + else if (vo_is_hidden_para in parasym.varoptions) then + begin + { don't push a node that already generated a pointer type + by address for implicit hidden parameters } + pushaddr:=(vo_is_funcret in parasym.varoptions) or + { pass "this" in C++ classes explicitly as pointer + because push_addr_param might not be true for them } + (is_cppclass(parasym.vardef) and (vo_is_self in parasym.varoptions)) or + ( + ( + not(left.resultdef.typ in [pointerdef,classrefdef]) or + ( + { allow pointerdefs (as self) to be passed as addr + param if the method is part of a type helper which + extends a pointer type } + (vo_is_self in parasym.varoptions) and + (aktcallnode.procdefinition.owner.symtabletype=objectsymtable) and + (is_objectpascal_helper(tdef(aktcallnode.procdefinition.owner.defowner))) and + (tobjectdef(aktcallnode.procdefinition.owner.defowner).extendeddef.typ=pointerdef) + ) + ) and + paramanager.push_addr_param(parasym.varspez,parasym.vardef, + aktcallnode.procdefinition.proccalloption)); + + if pushaddr then + begin + { objects or advanced records could be located in registers if they are the result of a type case, see e.g. webtbs\tw26075.pp } + if not(left.location.loc in [LOC_CREFERENCE,LOC_REFERENCE]) then + hlcg.location_force_mem(current_asmdata.CurrAsmList,left.location,left.resultdef); + push_addr_para + end + else + push_value_para; + end + { formal def } + else if (parasym.vardef.typ=formaldef) then + push_formal_para + { Normal parameter } + else if paramanager.push_copyout_param(parasym.varspez,parasym.vardef, + aktcallnode.procdefinition.proccalloption) then + push_copyout_para + else + begin + { don't push a node that already generated a pointer type + by address for implicit hidden parameters } + if (not( + (vo_is_hidden_para in parasym.varoptions) and + (left.resultdef.typ in [pointerdef,classrefdef]) + ) and + paramanager.push_addr_param(parasym.varspez,parasym.vardef, + aktcallnode.procdefinition.proccalloption)) and + { dyn. arrays passed to an array of const must be passed by value, see tests/webtbs/tw4219.pp } + not( + is_array_of_const(parasym.vardef) and + is_dynamic_array(left.resultdef) + ) then + begin + { Passing a var parameter to a var parameter, we can + just push the address transparently } + if (left.nodetype=loadn) and + (tloadnode(left).is_addr_param_load) then + begin + if (left.location.reference.index<>NR_NO) or + (left.location.reference.offset<>0) then + internalerror(200410107); + hlcg.a_load_reg_cgpara(current_asmdata.CurrAsmList,cpointerdef.getreusable(left.resultdef),left.location.reference.base,tempcgpara) + end + else + begin + { Force to be in memory } + if not(left.location.loc in [LOC_CREFERENCE,LOC_REFERENCE]) then + hlcg.location_force_mem(current_asmdata.CurrAsmList,left.location,left.resultdef); + push_addr_para; + end; + end + else + push_value_para; + end; + + { update return location in callnode when this is the function + result } + if assigned(parasym) and + ( + { for type helper/record constructor check that it is self parameter } + ( + (vo_is_self in parasym.varoptions) and + (aktcallnode.procdefinition.proctypeoption=potype_constructor) and + (parasym.vardef.typ<>objectdef) + ) or + (vo_is_funcret in parasym.varoptions) + ) then + location_copy(aktcallnode.location,left.location); + end; + + + procedure tcgcallparanode.secondcallparan; begin if not(assigned(parasym)) then internalerror(200304242); @@ -328,116 +450,8 @@ implementation a parameter } if (left.nodetype<>nothingn) then begin - if assigned(fparainit) then - secondpass(fparainit); - secondpass(left); - - hlcg.maybe_change_load_node_reg(current_asmdata.CurrAsmList,left,true); - - paramanager.createtempparaloc(current_asmdata.CurrAsmList,aktcallnode.procdefinition.proccalloption,parasym,not followed_by_stack_tainting_call_cached,tempcgpara); - - { handle varargs first, because parasym is not valid } - if (cpf_varargs_para in callparaflags) then - begin - if paramanager.push_addr_param(vs_value,left.resultdef, - aktcallnode.procdefinition.proccalloption) then - push_addr_para - else - push_value_para; - end - { hidden parameters } - else if (vo_is_hidden_para in parasym.varoptions) then - begin - { don't push a node that already generated a pointer type - by address for implicit hidden parameters } - pushaddr:=(vo_is_funcret in parasym.varoptions) or - { pass "this" in C++ classes explicitly as pointer - because push_addr_param might not be true for them } - (is_cppclass(parasym.vardef) and (vo_is_self in parasym.varoptions)) or - ( - ( - not(left.resultdef.typ in [pointerdef,classrefdef]) or - ( - { allow pointerdefs (as self) to be passed as addr - param if the method is part of a type helper which - extends a pointer type } - (vo_is_self in parasym.varoptions) and - (aktcallnode.procdefinition.owner.symtabletype=objectsymtable) and - (is_objectpascal_helper(tdef(aktcallnode.procdefinition.owner.defowner))) and - (tobjectdef(aktcallnode.procdefinition.owner.defowner).extendeddef.typ=pointerdef) - ) - ) and - paramanager.push_addr_param(parasym.varspez,parasym.vardef, - aktcallnode.procdefinition.proccalloption)); - - if pushaddr then - begin - { objects or advanced records could be located in registers if they are the result of a type case, see e.g. webtbs\tw26075.pp } - if not(left.location.loc in [LOC_CREFERENCE,LOC_REFERENCE]) then - hlcg.location_force_mem(current_asmdata.CurrAsmList,left.location,left.resultdef); - push_addr_para - end - else - push_value_para; - end - { formal def } - else if (parasym.vardef.typ=formaldef) then - push_formal_para - { Normal parameter } - else if paramanager.push_copyout_param(parasym.varspez,parasym.vardef, - aktcallnode.procdefinition.proccalloption) then - push_copyout_para - else - begin - { don't push a node that already generated a pointer type - by address for implicit hidden parameters } - if (not( - (vo_is_hidden_para in parasym.varoptions) and - (left.resultdef.typ in [pointerdef,classrefdef]) - ) and - paramanager.push_addr_param(parasym.varspez,parasym.vardef, - aktcallnode.procdefinition.proccalloption)) and - { dyn. arrays passed to an array of const must be passed by value, see tests/webtbs/tw4219.pp } - not( - is_array_of_const(parasym.vardef) and - is_dynamic_array(left.resultdef) - ) then - begin - { Passing a var parameter to a var parameter, we can - just push the address transparently } - if (left.nodetype=loadn) and - (tloadnode(left).is_addr_param_load) then - begin - if (left.location.reference.index<>NR_NO) or - (left.location.reference.offset<>0) then - internalerror(200410107); - hlcg.a_load_reg_cgpara(current_asmdata.CurrAsmList,cpointerdef.getreusable(left.resultdef),left.location.reference.base,tempcgpara) - end - else - begin - { Force to be in memory } - if not(left.location.loc in [LOC_CREFERENCE,LOC_REFERENCE]) then - hlcg.location_force_mem(current_asmdata.CurrAsmList,left.location,left.resultdef); - push_addr_para; - end; - end - else - push_value_para; - end; - - { update return location in callnode when this is the function - result } - if assigned(parasym) and - ( - { for type helper/record constructor check that it is self parameter } - ( - (vo_is_self in parasym.varoptions) and - (aktcallnode.procdefinition.proctypeoption=potype_constructor) and - (parasym.vardef.typ<>objectdef) - ) or - (vo_is_funcret in parasym.varoptions) - ) then - location_copy(aktcallnode.location,left.location); + secondcallparan_do_secondpass; + secondcallparan_after_secondpass; end; { next parameter }