mirror of
https://gitlab.com/freepascal.org/fpc/source.git
synced 2025-11-22 03:19:46 +01: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_formal_para;virtual;
|
||||||
procedure push_copyout_para;virtual;abstract;
|
procedure push_copyout_para;virtual;abstract;
|
||||||
function maybe_push_unused_para:boolean;virtual;
|
function maybe_push_unused_para:boolean;virtual;
|
||||||
|
|
||||||
|
procedure secondcallparan_do_secondpass;
|
||||||
|
procedure secondcallparan_after_secondpass;
|
||||||
public
|
public
|
||||||
tempcgpara : tcgpara;
|
tempcgpara : tcgpara;
|
||||||
|
|
||||||
@ -317,9 +320,128 @@ implementation
|
|||||||
end;
|
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
|
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
|
begin
|
||||||
if not(assigned(parasym)) then
|
if not(assigned(parasym)) then
|
||||||
internalerror(200304242);
|
internalerror(200304242);
|
||||||
@ -328,116 +450,8 @@ implementation
|
|||||||
a parameter }
|
a parameter }
|
||||||
if (left.nodetype<>nothingn) then
|
if (left.nodetype<>nothingn) then
|
||||||
begin
|
begin
|
||||||
if assigned(fparainit) then
|
secondcallparan_do_secondpass;
|
||||||
secondpass(fparainit);
|
secondcallparan_after_secondpass;
|
||||||
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);
|
|
||||||
end;
|
end;
|
||||||
|
|
||||||
{ next parameter }
|
{ next parameter }
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user