mirror of
https://gitlab.com/freepascal.org/fpc/source.git
synced 2025-04-14 21:59:47 +02:00
* refactor function result handling
* rename methodpointerinit/done to callinitblock/callcleanupblock * moved checks in callnode to separate functions * funcretnode is now always a simple node instead of a block of statements * funcret and methodpointer are generated/optimized only in pass_1 so a conversion from calln to loadn is much easier * function result assignments are much more often optimized to use the assignment destination location instead of using a temp git-svn-id: trunk@8558 -
This commit is contained in:
parent
399a2a86fa
commit
e0cf015159
@ -94,12 +94,12 @@ interface
|
||||
|
||||
ttempcreatenode = class;
|
||||
|
||||
ttempinfoflag = (ti_may_be_in_reg,ti_valid,ti_nextref_set_hookoncopy_nil,ti_is_inlined_result,
|
||||
ttempinfoflag = (ti_may_be_in_reg,ti_valid,ti_nextref_set_hookoncopy_nil,ti_is_funcret,
|
||||
ti_addr_taken);
|
||||
ttempinfoflags = set of ttempinfoflag;
|
||||
|
||||
const
|
||||
tempinfostoreflags = [ti_may_be_in_reg,ti_is_inlined_result,ti_addr_taken];
|
||||
tempinfostoreflags = [ti_may_be_in_reg,ti_is_funcret,ti_addr_taken];
|
||||
|
||||
type
|
||||
{ to allow access to the location by temp references even after the temp has }
|
||||
@ -133,7 +133,7 @@ type
|
||||
{ to it and *not* generate a ttempdeletenode }
|
||||
constructor create(_typedef: tdef; _size: aint; _temptype: ttemptype;allowreg:boolean); virtual;
|
||||
constructor create_withnode(_typedef: tdef; _size: aint; _temptype: ttemptype; allowreg:boolean; withnode: tnode); virtual;
|
||||
constructor create_inlined_result(_typedef: tdef; _size: aint; _temptype: ttemptype; allowreg:boolean); virtual;
|
||||
constructor create_funcret(_typedef: tdef; _size: aint; _temptype: ttemptype; allowreg:boolean); virtual;
|
||||
constructor ppuload(t:tnodetype;ppufile:tcompilerppufile);override;
|
||||
procedure ppuwrite(ppufile:tcompilerppufile);override;
|
||||
procedure buildderefimpl;override;
|
||||
@ -742,10 +742,10 @@ implementation
|
||||
end;
|
||||
|
||||
|
||||
constructor ttempcreatenode.create_inlined_result(_typedef: tdef; _size: aint; _temptype: ttemptype; allowreg:boolean);
|
||||
constructor ttempcreatenode.create_funcret(_typedef: tdef; _size: aint; _temptype: ttemptype; allowreg:boolean);
|
||||
begin
|
||||
self.create(_typedef,_size,_temptype,allowreg);
|
||||
include(tempinfo^.flags,ti_is_inlined_result);
|
||||
include(tempinfo^.flags,ti_is_funcret);
|
||||
end;
|
||||
|
||||
|
||||
|
2244
compiler/ncal.pas
2244
compiler/ncal.pas
File diff suppressed because it is too large
Load Diff
@ -1,4 +1,4 @@
|
||||
{
|
||||
{
|
||||
Copyright (c) 1998-2002 by Florian Klaempfl
|
||||
|
||||
Generate assembler for call nodes
|
||||
@ -45,13 +45,13 @@ interface
|
||||
|
||||
tcgcallnode = class(tcallnode)
|
||||
private
|
||||
procedure handle_return_value;
|
||||
procedure release_unused_return_value;
|
||||
procedure release_para_temps;
|
||||
procedure pushparas;
|
||||
procedure freeparas;
|
||||
protected
|
||||
framepointer_paraloc : tcgpara;
|
||||
refcountedtemp : treference;
|
||||
procedure handle_return_value;
|
||||
{# This routine is used to push the current frame pointer
|
||||
on the stack. This is used in nested routines where the
|
||||
value of the frame pointer is always pushed as an extra
|
||||
@ -509,190 +509,159 @@ implementation
|
||||
var
|
||||
cgsize : tcgsize;
|
||||
retloc : tlocation;
|
||||
hregister : tregister;
|
||||
tempnode : tnode;
|
||||
begin
|
||||
cgsize:=procdefinition.funcretloc[callerside].size;
|
||||
|
||||
{ structured results are easy to handle....
|
||||
needed also when result_no_used !! }
|
||||
{ Check that the return location is set when the result is passed in
|
||||
a parameter }
|
||||
if (procdefinition.proctypeoption<>potype_constructor) and
|
||||
paramanager.ret_in_param(resultdef,procdefinition.proccalloption) then
|
||||
begin
|
||||
{ Location should be setup by the funcret para }
|
||||
if location.loc<>LOC_REFERENCE then
|
||||
internalerror(200304241);
|
||||
end
|
||||
else
|
||||
{ ansi/widestrings must be registered, so we can dispose them }
|
||||
if resultdef.needs_inittable then
|
||||
begin
|
||||
if procdefinition.funcretloc[callerside].loc<>LOC_REGISTER then
|
||||
internalerror(200409261);
|
||||
internalerror(200304241);
|
||||
exit;
|
||||
end;
|
||||
|
||||
retloc:=procdefinition.funcretloc[callerside];
|
||||
{$ifndef cpu64bit}
|
||||
if cgsize in [OS_64,OS_S64] then
|
||||
begin
|
||||
{ the function result registers are already allocated }
|
||||
if getsupreg(retloc.register64.reglo)<first_int_imreg then
|
||||
cg.ungetcpuregister(current_asmdata.CurrAsmList,retloc.register64.reglo);
|
||||
retloc.register64.reglo:=cg.getintregister(current_asmdata.CurrAsmList,OS_32);
|
||||
cg.a_load_reg_reg(current_asmdata.CurrAsmList,OS_32,OS_32,procdefinition.funcretloc[callerside].register64.reglo,retloc.register64.reglo);
|
||||
if getsupreg(retloc.register64.reghi)<first_int_imreg then
|
||||
cg.ungetcpuregister(current_asmdata.CurrAsmList,retloc.register64.reghi);
|
||||
retloc.register64.reghi:=cg.getintregister(current_asmdata.CurrAsmList,OS_32);
|
||||
cg.a_load_reg_reg(current_asmdata.CurrAsmList,OS_32,OS_32,procdefinition.funcretloc[callerside].register64.reghi,retloc.register64.reghi);
|
||||
end
|
||||
else
|
||||
{$endif cpu64bit}
|
||||
begin
|
||||
{ the FUNCTION_RESULT_REG is already allocated }
|
||||
if getsupreg(retloc.register)<first_int_imreg then
|
||||
cg.ungetcpuregister(current_asmdata.CurrAsmList,retloc.register);
|
||||
|
||||
{ reg_ref could generate two instrcutions and allocate a register so we've to
|
||||
save the result first before releasing it }
|
||||
retloc.register:=cg.getaddressregister(current_asmdata.CurrAsmList);
|
||||
cg.a_load_reg_reg(current_asmdata.CurrAsmList,OS_ADDR,OS_ADDR,procdefinition.funcretloc[callerside].register,retloc.register);
|
||||
end;
|
||||
|
||||
if not assigned(funcretnode) then
|
||||
begin
|
||||
location_reset(location,LOC_REFERENCE,cgsize);
|
||||
location.reference:=refcountedtemp;
|
||||
end
|
||||
else
|
||||
begin
|
||||
{ in case of a regular funcretnode with ret_in_param, the }
|
||||
{ original funcretnode isn't touched -> make sure it's }
|
||||
{ the same here (not sure if it's necessary) }
|
||||
tempnode := funcretnode.getcopy;
|
||||
tempnode.pass_generate_code;
|
||||
location := tempnode.location;
|
||||
tempnode.free;
|
||||
cg.g_decrrefcount(current_asmdata.CurrAsmList,resultdef,location.reference);
|
||||
end;
|
||||
{$ifndef cpu64bit}
|
||||
if cgsize in [OS_64,OS_S64] then
|
||||
cg64.a_load64_reg_ref(current_asmdata.CurrAsmList,retloc.register64,location.reference)
|
||||
else
|
||||
{$endif}
|
||||
cg.a_load_reg_ref(current_asmdata.CurrAsmList,cgsize,cgsize,retloc.register,location.reference);
|
||||
end
|
||||
else
|
||||
{ normal (ordinal,float,pointer) result value }
|
||||
begin
|
||||
{ we have only to handle the result if it is used }
|
||||
if (cnf_return_value_used in callnodeflags) then
|
||||
begin
|
||||
location.loc:=procdefinition.funcretloc[callerside].loc;
|
||||
case procdefinition.funcretloc[callerside].loc of
|
||||
LOC_FPUREGISTER:
|
||||
begin
|
||||
location_reset(location,LOC_FPUREGISTER,cgsize);
|
||||
location.register:=procdefinition.funcretloc[callerside].register;
|
||||
{ Load normal (ordinal,float,pointer) result value from accumulator }
|
||||
cgsize:=procdefinition.funcretloc[callerside].size;
|
||||
case procdefinition.funcretloc[callerside].loc of
|
||||
LOC_FPUREGISTER:
|
||||
begin
|
||||
location_reset(location,LOC_FPUREGISTER,cgsize);
|
||||
location.register:=procdefinition.funcretloc[callerside].register;
|
||||
{$ifdef x86}
|
||||
tcgx86(cg).inc_fpu_stack;
|
||||
tcgx86(cg).inc_fpu_stack;
|
||||
{$else x86}
|
||||
if getsupreg(procdefinition.funcretloc[callerside].register)<first_fpu_imreg then
|
||||
cg.ungetcpuregister(current_asmdata.CurrAsmList,procdefinition.funcretloc[callerside].register);
|
||||
hregister:=cg.getfpuregister(current_asmdata.CurrAsmList,location.size);
|
||||
cg.a_loadfpu_reg_reg(current_asmdata.CurrAsmList,location.size,location.size,location.register,hregister);
|
||||
location.register:=hregister;
|
||||
if getsupreg(procdefinition.funcretloc[callerside].register)<first_fpu_imreg then
|
||||
cg.ungetcpuregister(current_asmdata.CurrAsmList,procdefinition.funcretloc[callerside].register);
|
||||
hregister:=cg.getfpuregister(current_asmdata.CurrAsmList,location.size);
|
||||
cg.a_loadfpu_reg_reg(current_asmdata.CurrAsmList,location.size,location.size,location.register,hregister);
|
||||
location.register:=hregister;
|
||||
{$endif x86}
|
||||
end;
|
||||
end;
|
||||
|
||||
LOC_REGISTER:
|
||||
begin
|
||||
if cgsize<>OS_NO then
|
||||
begin
|
||||
location_reset(location,LOC_REGISTER,cgsize);
|
||||
LOC_REGISTER:
|
||||
begin
|
||||
if cgsize<>OS_NO then
|
||||
begin
|
||||
location_reset(location,LOC_REGISTER,cgsize);
|
||||
{$ifndef cpu64bit}
|
||||
if cgsize in [OS_64,OS_S64] then
|
||||
begin
|
||||
retloc:=procdefinition.funcretloc[callerside];
|
||||
if retloc.loc<>LOC_REGISTER then
|
||||
internalerror(200409141);
|
||||
{ the function result registers are already allocated }
|
||||
if getsupreg(retloc.register64.reglo)<first_int_imreg then
|
||||
cg.ungetcpuregister(current_asmdata.CurrAsmList,retloc.register64.reglo);
|
||||
location.register64.reglo:=cg.getintregister(current_asmdata.CurrAsmList,OS_32);
|
||||
cg.a_load_reg_reg(current_asmdata.CurrAsmList,OS_32,OS_32,retloc.register64.reglo,location.register64.reglo);
|
||||
if getsupreg(retloc.register64.reghi)<first_int_imreg then
|
||||
cg.ungetcpuregister(current_asmdata.CurrAsmList,retloc.register64.reghi);
|
||||
location.register64.reghi:=cg.getintregister(current_asmdata.CurrAsmList,OS_32);
|
||||
cg.a_load_reg_reg(current_asmdata.CurrAsmList,OS_32,OS_32,retloc.register64.reghi,location.register64.reghi);
|
||||
end
|
||||
else
|
||||
if cgsize in [OS_64,OS_S64] then
|
||||
begin
|
||||
retloc:=procdefinition.funcretloc[callerside];
|
||||
if retloc.loc<>LOC_REGISTER then
|
||||
internalerror(200409141);
|
||||
{ the function result registers are already allocated }
|
||||
if getsupreg(retloc.register64.reglo)<first_int_imreg then
|
||||
cg.ungetcpuregister(current_asmdata.CurrAsmList,retloc.register64.reglo);
|
||||
location.register64.reglo:=cg.getintregister(current_asmdata.CurrAsmList,OS_32);
|
||||
cg.a_load_reg_reg(current_asmdata.CurrAsmList,OS_32,OS_32,retloc.register64.reglo,location.register64.reglo);
|
||||
if getsupreg(retloc.register64.reghi)<first_int_imreg then
|
||||
cg.ungetcpuregister(current_asmdata.CurrAsmList,retloc.register64.reghi);
|
||||
location.register64.reghi:=cg.getintregister(current_asmdata.CurrAsmList,OS_32);
|
||||
cg.a_load_reg_reg(current_asmdata.CurrAsmList,OS_32,OS_32,retloc.register64.reghi,location.register64.reghi);
|
||||
end
|
||||
else
|
||||
{$endif cpu64bit}
|
||||
begin
|
||||
{ change register size after the unget because the
|
||||
getregister was done for the full register
|
||||
def_cgsize(resultdef) is used here because
|
||||
it could be a constructor call }
|
||||
if getsupreg(procdefinition.funcretloc[callerside].register)<first_int_imreg then
|
||||
cg.ungetcpuregister(current_asmdata.CurrAsmList,procdefinition.funcretloc[callerside].register);
|
||||
location.register:=cg.getintregister(current_asmdata.CurrAsmList,def_cgsize(resultdef));
|
||||
cg.a_load_reg_reg(current_asmdata.CurrAsmList,cgsize,def_cgsize(resultdef),procdefinition.funcretloc[callerside].register,location.register);
|
||||
end;
|
||||
begin
|
||||
{ change register size after the unget because the
|
||||
getregister was done for the full register
|
||||
def_cgsize(resultdef) is used here because
|
||||
it could be a constructor call }
|
||||
if getsupreg(procdefinition.funcretloc[callerside].register)<first_int_imreg then
|
||||
cg.ungetcpuregister(current_asmdata.CurrAsmList,procdefinition.funcretloc[callerside].register);
|
||||
location.register:=cg.getintregister(current_asmdata.CurrAsmList,def_cgsize(resultdef));
|
||||
cg.a_load_reg_reg(current_asmdata.CurrAsmList,cgsize,def_cgsize(resultdef),procdefinition.funcretloc[callerside].register,location.register);
|
||||
end;
|
||||
{$ifdef arm}
|
||||
if (resultdef.typ=floatdef) and (current_settings.fputype in [fpu_fpa,fpu_fpa10,fpu_fpa11]) then
|
||||
begin
|
||||
location_force_mem(current_asmdata.CurrAsmList,location);
|
||||
end;
|
||||
if (resultdef.typ=floatdef) and (current_settings.fputype in [fpu_fpa,fpu_fpa10,fpu_fpa11]) then
|
||||
begin
|
||||
location_force_mem(current_asmdata.CurrAsmList,location);
|
||||
end;
|
||||
{$endif arm}
|
||||
end
|
||||
else
|
||||
begin
|
||||
if resultdef.size>0 then
|
||||
internalerror(200305131);
|
||||
end;
|
||||
end;
|
||||
|
||||
LOC_MMREGISTER:
|
||||
begin
|
||||
location_reset(location,LOC_MMREGISTER,cgsize);
|
||||
if getsupreg(procdefinition.funcretloc[callerside].register)<first_mm_imreg then
|
||||
cg.ungetcpuregister(current_asmdata.CurrAsmList,procdefinition.funcretloc[callerside].register);
|
||||
location.register:=cg.getmmregister(current_asmdata.CurrAsmList,cgsize);
|
||||
cg.a_loadmm_reg_reg(current_asmdata.CurrAsmList,cgsize,cgsize,procdefinition.funcretloc[callerside].register,location.register,mms_movescalar);
|
||||
end;
|
||||
|
||||
else
|
||||
internalerror(200405023);
|
||||
end
|
||||
else
|
||||
begin
|
||||
if resultdef.size>0 then
|
||||
internalerror(200305131);
|
||||
end;
|
||||
end
|
||||
else
|
||||
begin
|
||||
{$ifdef x86}
|
||||
{ release FPU stack }
|
||||
if procdefinition.funcretloc[callerside].loc=LOC_FPUREGISTER then
|
||||
emit_reg(A_FSTP,S_NO,NR_FPU_RESULT_REG);
|
||||
{$endif x86}
|
||||
if cgsize<>OS_NO then
|
||||
location_free(current_asmdata.CurrAsmList,procdefinition.funcretloc[callerside]);
|
||||
location_reset(location,LOC_VOID,OS_NO);
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
|
||||
LOC_MMREGISTER:
|
||||
begin
|
||||
location_reset(location,LOC_MMREGISTER,cgsize);
|
||||
if getsupreg(procdefinition.funcretloc[callerside].register)<first_mm_imreg then
|
||||
cg.ungetcpuregister(current_asmdata.CurrAsmList,procdefinition.funcretloc[callerside].register);
|
||||
location.register:=cg.getmmregister(current_asmdata.CurrAsmList,cgsize);
|
||||
cg.a_loadmm_reg_reg(current_asmdata.CurrAsmList,cgsize,cgsize,procdefinition.funcretloc[callerside].register,location.register,mms_movescalar);
|
||||
end;
|
||||
|
||||
else
|
||||
internalerror(200405023);
|
||||
end;
|
||||
|
||||
{ copy value to the final location if this was already provided to the
|
||||
callnode. This must be done after the call node, because the location can
|
||||
also be used as parameter and may not be finalized yet }
|
||||
if assigned(funcretnode) then
|
||||
begin
|
||||
funcretnode.pass_generate_code;
|
||||
{ Decrease refcount for refcounted types, this can be skipped when
|
||||
we have used a temp, because then it is already done from tempcreatenode.
|
||||
Also no finalize is needed, because there is no risk of exceptions from the
|
||||
function since this is code is only executed after the function call has returned }
|
||||
if funcretnode.resultdef.needs_inittable and
|
||||
(funcretnode.nodetype<>temprefn) then
|
||||
cg.g_decrrefcount(current_asmdata.CurrAsmList,funcretnode.resultdef,funcretnode.location.reference);
|
||||
|
||||
case location.loc of
|
||||
LOC_REGISTER :
|
||||
{$ifndef cpu64bit}
|
||||
if cgsize in [OS_64,OS_S64] then
|
||||
cg64.a_load64_reg_loc(current_asmdata.CurrAsmList,location.register64,funcretnode.location)
|
||||
else
|
||||
{$endif}
|
||||
cg.a_load_reg_loc(current_asmdata.CurrAsmList,cgsize,location.register,funcretnode.location);
|
||||
else
|
||||
internalerror(200709085);
|
||||
end;
|
||||
location := funcretnode.location;
|
||||
end;
|
||||
end;
|
||||
|
||||
|
||||
procedure tcgcallnode.release_unused_return_value;
|
||||
begin
|
||||
{ When the result is not used we need to finalize the result and
|
||||
can release the temp }
|
||||
can release the temp. This need to be after the callcleanupblock
|
||||
tree is generated, because that converts the temp from persistent to normal }
|
||||
if not(cnf_return_value_used in callnodeflags) then
|
||||
begin
|
||||
if location.loc=LOC_REFERENCE then
|
||||
begin
|
||||
if resultdef.needs_inittable then
|
||||
cg.g_finalize(current_asmdata.CurrAsmList,resultdef,location.reference);
|
||||
tg.ungetiftemp(current_asmdata.CurrAsmList,location.reference)
|
||||
end;
|
||||
case location.loc of
|
||||
LOC_REFERENCE :
|
||||
begin
|
||||
if resultdef.needs_inittable then
|
||||
cg.g_finalize(current_asmdata.CurrAsmList,resultdef,location.reference);
|
||||
tg.ungetiftemp(current_asmdata.CurrAsmList,location.reference);
|
||||
end;
|
||||
{$ifdef x86}
|
||||
LOC_FPUREGISTER :
|
||||
begin
|
||||
{ release FPU stack }
|
||||
emit_reg(A_FSTP,S_NO,NR_FPU_RESULT_REG);
|
||||
tcgx86(cg).dec_fpu_stack;
|
||||
end;
|
||||
{$endif x86}
|
||||
end;
|
||||
if procdefinition.funcretloc[callerside].size<>OS_NO then
|
||||
location_free(current_asmdata.CurrAsmList,procdefinition.funcretloc[callerside]);
|
||||
location_reset(location,LOC_VOID,OS_NO);
|
||||
end;
|
||||
end;
|
||||
|
||||
|
||||
procedure tcgcallnode.release_para_temps;
|
||||
var
|
||||
hp : tnode;
|
||||
hp,
|
||||
hp2 : tnode;
|
||||
ppn : tcallparanode;
|
||||
begin
|
||||
{ Release temps from parameters }
|
||||
@ -714,7 +683,13 @@ implementation
|
||||
begin
|
||||
while assigned(hp) do
|
||||
begin
|
||||
location_freetemp(current_asmdata.CurrAsmList,tarrayconstructornode(hp).left.location);
|
||||
hp2:=tarrayconstructornode(hp).left;
|
||||
{ ignore typeconvs and addrn inserted by arrayconstructn for
|
||||
passing a shortstring }
|
||||
if (hp2.nodetype=typeconvn) and
|
||||
(tunarynode(hp2).left.nodetype=addrn) then
|
||||
hp2:=tunarynode(tunarynode(hp2).left).left;
|
||||
location_freetemp(current_asmdata.CurrAsmList,hp2.location);
|
||||
hp:=tarrayconstructornode(hp).right;
|
||||
end;
|
||||
end;
|
||||
@ -864,19 +839,8 @@ implementation
|
||||
not procdefinition.has_paraloc_info then
|
||||
internalerror(200305264);
|
||||
|
||||
if assigned(methodpointerinit) then
|
||||
secondpass(methodpointerinit);
|
||||
|
||||
if resultdef.needs_inittable and
|
||||
not paramanager.ret_in_param(resultdef,procdefinition.proccalloption) and
|
||||
not assigned(funcretnode) then
|
||||
begin
|
||||
tg.gettemptyped(current_asmdata.CurrAsmList,resultdef,tt_normal,refcountedtemp);
|
||||
{ finalize instead of only decrref, because if the called }
|
||||
{ function throws an exception this temp will be decrref'd }
|
||||
{ again (tw7100) }
|
||||
cg.g_finalize(current_asmdata.CurrAsmList,resultdef,refcountedtemp);
|
||||
end;
|
||||
if assigned(callinitblock) then
|
||||
secondpass(callinitblock);
|
||||
|
||||
regs_to_save_int:=paramanager.get_volatile_registers_int(procdefinition.proccalloption);
|
||||
regs_to_save_fpu:=paramanager.get_volatile_registers_fpu(procdefinition.proccalloption);
|
||||
@ -1120,6 +1084,18 @@ implementation
|
||||
else
|
||||
location_reset(location,LOC_VOID,OS_NO);
|
||||
|
||||
{ convert persistent temps for parameters and function result to normal temps }
|
||||
if assigned(callcleanupblock) then
|
||||
secondpass(callcleanupblock);
|
||||
|
||||
{ release temps and finalize unused return values, must be
|
||||
after the callcleanupblock because that converts temps
|
||||
from persistent to normal }
|
||||
release_unused_return_value;
|
||||
|
||||
{ release temps of paras }
|
||||
release_para_temps;
|
||||
|
||||
{ perhaps i/o check ? }
|
||||
if (cs_check_io in current_settings.localswitches) and
|
||||
(po_iocheck in procdefinition.procoptions) and
|
||||
@ -1132,13 +1108,6 @@ implementation
|
||||
cg.a_call_name(current_asmdata.CurrAsmList,'FPC_IOCHECK');
|
||||
cg.deallocallcpuregisters(current_asmdata.CurrAsmList);
|
||||
end;
|
||||
|
||||
{ release temps of paras }
|
||||
release_para_temps;
|
||||
|
||||
|
||||
if assigned(methodpointerdone) then
|
||||
secondpass(methodpointerdone);
|
||||
end;
|
||||
|
||||
|
||||
|
@ -2542,7 +2542,7 @@ implementation
|
||||
if (ti_valid in ttemprefnode(n).tempinfo^.flags) and
|
||||
(ttemprefnode(n).tempinfo^.location.loc in [LOC_CREGISTER,LOC_CFPUREGISTER,LOC_CMMXREGISTER,LOC_CMMREGISTER]) and
|
||||
(ttemprefnode(n).tempinfo^.location.register = rr^.old) and
|
||||
(not(ti_is_inlined_result in ttemprefnode(n).tempinfo^.flags) or
|
||||
(not(ti_is_funcret in ttemprefnode(n).tempinfo^.flags) or
|
||||
not(fc_exit in flowcontrol)) then
|
||||
begin
|
||||
{$ifndef cpu64bit}
|
||||
|
@ -1696,7 +1696,7 @@ implementation
|
||||
if (tcallnode(left).symtableprocentry.owner.symtabletype=ObjectSymtable) then
|
||||
begin
|
||||
if assigned(tcallnode(left).methodpointer) then
|
||||
tloadnode(hp).set_mp(tcallnode(left).get_load_methodpointer)
|
||||
tloadnode(hp).set_mp(tcallnode(left).methodpointer.getcopy)
|
||||
else
|
||||
tloadnode(hp).set_mp(load_self_node);
|
||||
end;
|
||||
|
@ -679,10 +679,7 @@ implementation
|
||||
is pushed as a parameter. Using the final destination of left directly
|
||||
save a temp allocation and copy of data (PFV) }
|
||||
oldassignmentnode:=aktassignmentnode;
|
||||
if right.nodetype=addn then
|
||||
aktassignmentnode:=self
|
||||
else
|
||||
aktassignmentnode:=nil;
|
||||
aktassignmentnode:=self;
|
||||
firstpass(right);
|
||||
aktassignmentnode:=oldassignmentnode;
|
||||
if nf_assign_done_in_right in flags then
|
||||
@ -695,66 +692,11 @@ implementation
|
||||
if codegenerror then
|
||||
exit;
|
||||
|
||||
{ if right is a function call for which the address of the result }
|
||||
{ is allocated by the caller and passed to the function via an }
|
||||
{ invisible function result, try to pass the x in "x:=f(...)" as }
|
||||
{ that function result instead. Condition: x cannot be accessible }
|
||||
{ from within f. This is the case if x is a temp, or x is a local }
|
||||
{ variable or value parameter of the current block and its address }
|
||||
{ is not passed to f. One problem: what if someone takes the }
|
||||
{ address of x, puts it in a pointer variable/field and then }
|
||||
{ accesses it that way from within the function? This is solved }
|
||||
{ (in a conservative way) using the ti_addr_taken/addr_taken flags }
|
||||
if (cs_opt_level1 in current_settings.optimizerswitches) and
|
||||
(right.nodetype = calln) and
|
||||
(right.resultdef=left.resultdef) and
|
||||
{ left must be a temp, since otherwise as soon as you modify the }
|
||||
{ result, the current left node is modified and that one may }
|
||||
{ still be an argument to the function or even accessed in the }
|
||||
{ function }
|
||||
(
|
||||
(
|
||||
(((left.nodetype = temprefn) and
|
||||
not(ti_addr_taken in ttemprefnode(left).tempinfo^.flags) and
|
||||
not(ti_may_be_in_reg in ttemprefnode(left).tempinfo^.flags)) or
|
||||
((left.nodetype = loadn) and
|
||||
{ nested procedures may access the current procedure's locals }
|
||||
(tcallnode(right).procdefinition.parast.symtablelevel=normal_function_level) and
|
||||
{ must be a local variable or a value para }
|
||||
((tloadnode(left).symtableentry.typ = localvarsym) or
|
||||
((tloadnode(left).symtableentry.typ = paravarsym) and
|
||||
(tparavarsym(tloadnode(left).symtableentry).varspez = vs_value)
|
||||
)
|
||||
) and
|
||||
{ the address may not have been taken of the variable/parameter, because }
|
||||
{ otherwise it's possible that the called function can access it via a }
|
||||
{ global variable or other stored state }
|
||||
not(tabstractvarsym(tloadnode(left).symtableentry).addr_taken) and
|
||||
(tabstractvarsym(tloadnode(left).symtableentry).varregable in [vr_none,vr_addr])
|
||||
)
|
||||
) and
|
||||
paramanager.ret_in_param(right.resultdef,tcallnode(right).procdefinition.proccalloption)
|
||||
) or
|
||||
{ there's special support for ansi/widestrings in the callnode }
|
||||
is_ansistring(right.resultdef) or
|
||||
is_widestring(right.resultdef)
|
||||
) then
|
||||
begin
|
||||
if assigned(tcallnode(right).funcretnode) then
|
||||
internalerror(2007080201);
|
||||
tcallnode(right).funcretnode := left;
|
||||
result := right;
|
||||
left := nil;
|
||||
right := nil;
|
||||
exit;
|
||||
end;
|
||||
|
||||
{ assignment to refcounted variable -> inc/decref }
|
||||
if (not is_class(left.resultdef) and
|
||||
left.resultdef.needs_inittable) then
|
||||
include(current_procinfo.flags,pi_do_call);
|
||||
|
||||
|
||||
if (is_shortstring(left.resultdef)) then
|
||||
begin
|
||||
if right.resultdef.typ=stringdef then
|
||||
|
@ -121,9 +121,9 @@ implementation
|
||||
calln:
|
||||
begin
|
||||
{ not in one statement, won't work because of b- }
|
||||
result := foreachnode(tcallnode(n).methodpointerinit,f,arg) or result;
|
||||
result := foreachnode(tcallnode(n).callinitblock,f,arg) or result;
|
||||
result := foreachnode(tcallnode(n).methodpointer,f,arg) or result;
|
||||
result := foreachnode(tcallnode(n).methodpointerdone,f,arg) or result;
|
||||
result := foreachnode(tcallnode(n).callcleanupblock,f,arg) or result;
|
||||
end;
|
||||
ifn, whilerepeatn, forn, tryexceptn, tryfinallyn:
|
||||
begin
|
||||
@ -169,9 +169,9 @@ implementation
|
||||
end;
|
||||
calln:
|
||||
begin
|
||||
result := foreachnodestatic(procmethod,tcallnode(n).methodpointerinit,f,arg) or result;
|
||||
result := foreachnodestatic(procmethod,tcallnode(n).callinitblock,f,arg) or result;
|
||||
result := foreachnodestatic(procmethod,tcallnode(n).methodpointer,f,arg) or result;
|
||||
result := foreachnodestatic(procmethod,tcallnode(n).methodpointerdone,f,arg) or result;
|
||||
result := foreachnodestatic(procmethod,tcallnode(n).callcleanupblock,f,arg) or result;
|
||||
end;
|
||||
ifn, whilerepeatn, forn, tryexceptn, tryfinallyn:
|
||||
begin
|
||||
@ -267,7 +267,7 @@ implementation
|
||||
method without a self pointer }
|
||||
if assigned(tcallnode(p1).methodpointer) and
|
||||
(tcallnode(p1).methodpointer.nodetype<>typen) then
|
||||
tloadnode(p2).set_mp(tcallnode(p1).get_load_methodpointer);
|
||||
tloadnode(p2).set_mp(tcallnode(p1).methodpointer.getcopy);
|
||||
end;
|
||||
typecheckpass(p2);
|
||||
p1.free;
|
||||
|
@ -144,10 +144,10 @@ unit opttail;
|
||||
oldnodetree:=n;
|
||||
n:=internalstatements(nodes);
|
||||
|
||||
if assigned(usedcallnode.methodpointerinit) then
|
||||
if assigned(usedcallnode.callinitblock) then
|
||||
begin
|
||||
addstatement(nodes,usedcallnode.methodpointerinit);
|
||||
usedcallnode.methodpointerinit:=nil;
|
||||
addstatement(nodes,usedcallnode.callinitblock);
|
||||
usedcallnode.callinitblock:=nil;
|
||||
end;
|
||||
|
||||
addstatement(nodes,calcnodes);
|
||||
@ -156,13 +156,13 @@ unit opttail;
|
||||
{ create goto }
|
||||
addstatement(nodes,cgotonode.create(labelnode));
|
||||
|
||||
if assigned(usedcallnode.methodpointerdone) then
|
||||
if assigned(usedcallnode.callcleanupblock) then
|
||||
begin
|
||||
{ methodpointerdone should contain only temp. node clean up }
|
||||
checktreenodetypes(usedcallnode.methodpointerdone,
|
||||
{ callcleanupblock should contain only temp. node clean up }
|
||||
checktreenodetypes(usedcallnode.callcleanupblock,
|
||||
[tempdeleten,blockn,statementn,temprefn,nothingn]);
|
||||
addstatement(nodes,usedcallnode.methodpointerdone);
|
||||
usedcallnode.methodpointerdone:=nil;
|
||||
addstatement(nodes,usedcallnode.callcleanupblock);
|
||||
usedcallnode.callcleanupblock:=nil;
|
||||
end;
|
||||
|
||||
oldnodetree.free;
|
||||
|
@ -1079,7 +1079,7 @@ implementation
|
||||
begin
|
||||
hp2:=cloadnode.create_procvar(tprocsym(tcallnode(hp).symtableprocentry),currprocdef,tcallnode(hp).symtableproc);
|
||||
if (po_methodpointer in pv.procoptions) then
|
||||
tloadnode(hp2).set_mp(tcallnode(hp).get_load_methodpointer);
|
||||
tloadnode(hp2).set_mp(tcallnode(hp).methodpointer.getcopy);
|
||||
hp.destroy;
|
||||
{ replace the old callnode with the new loadnode }
|
||||
hpp^:=hp2;
|
||||
|
Loading…
Reference in New Issue
Block a user