|
@@ -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,127 +320,138 @@ implementation
|
|
|
end;
|
|
|
|
|
|
|
|
|
- procedure tcgcallparanode.secondcallparan;
|
|
|
- var
|
|
|
- pushaddr: boolean;
|
|
|
+ procedure tcgcallparanode.secondcallparan_do_secondpass;
|
|
|
begin
|
|
|
- if not(assigned(parasym)) then
|
|
|
- internalerror(200304242);
|
|
|
+ if assigned(fparainit) then
|
|
|
+ secondpass(fparainit);
|
|
|
+ secondpass(left);
|
|
|
+ end;
|
|
|
|
|
|
- { Skip nothingn nodes which are used after disabling
|
|
|
- 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);
|
|
|
+ procedure tcgcallparanode.secondcallparan_after_secondpass;
|
|
|
+ var
|
|
|
+ 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);
|
|
|
+ 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
|
|
|
+ { 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
|
|
|
- { 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
|
|
|
+ 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
|
|
|
- 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;
|
|
|
+ { 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);
|
|
|
|
|
|
- { 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);
|
|
|
+ { Skip nothingn nodes which are used after disabling
|
|
|
+ a parameter }
|
|
|
+ if (left.nodetype<>nothingn) then
|
|
|
+ begin
|
|
|
+ secondcallparan_do_secondpass;
|
|
|
+ secondcallparan_after_secondpass;
|
|
|
end;
|
|
|
|
|
|
{ next parameter }
|