mirror of
https://gitlab.com/freepascal.org/fpc/source.git
synced 2025-04-05 01:38:03 +02:00
* 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.
This commit is contained in:
parent
b2f5f6ac7d
commit
e237da95d2
@ -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 }
|
||||
|
Loading…
Reference in New Issue
Block a user