* a_call_ref functionality cannot be implemented efficiently at code generator level, because references need specific preparations at earlier points. Moved this support to tcgcallnode and its x86 descendants, and got rid of all ifdef's around.

+ x86 targets now directly call procedure variables located in references.
- a_call_ref method removed from tcg and thlcgobj.

git-svn-id: trunk@26666 -
This commit is contained in:
sergei 2014-02-03 13:28:56 +00:00
parent 0d3f36eebf
commit 9c1f917e3a
10 changed files with 108 additions and 123 deletions

View File

@ -47,7 +47,6 @@ unit cgcpu;
procedure a_call_name(list : TAsmList;const s : string; weak: boolean);override; procedure a_call_name(list : TAsmList;const s : string; weak: boolean);override;
procedure a_call_reg(list : TAsmList;reg: tregister);override; procedure a_call_reg(list : TAsmList;reg: tregister);override;
procedure a_call_ref(list : TAsmList;ref: treference);override;
{ move instructions } { move instructions }
procedure a_load_reg_ref(list : TAsmList; fromsize, tosize: tcgsize; reg : tregister;const ref : treference);override; procedure a_load_reg_ref(list : TAsmList; fromsize, tosize: tcgsize; reg : tregister;const ref : treference);override;
@ -681,16 +680,6 @@ unit cgcpu;
end; end;
procedure tbasecgarm.a_call_ref(list : TAsmList;ref: treference);
begin
a_reg_alloc(list,NR_R12);
a_load_ref_reg(list,OS_ADDR,OS_ADDR,ref,NR_R12);
a_call_reg(list,NR_R12);
a_reg_dealloc(list,NR_R12);
include(current_procinfo.flags,pi_do_call);
end;
procedure tcgarm.a_op_const_reg(list : TAsmList; Op: TOpCG; size: TCGSize; a: tcgint; reg: TRegister); procedure tcgarm.a_op_const_reg(list : TAsmList; Op: TOpCG; size: TCGSize; a: tcgint; reg: TRegister);
begin begin
a_op_const_reg_reg(list,op,size,a,reg,reg); a_op_const_reg_reg(list,op,size,a,reg,reg);

View File

@ -54,7 +54,6 @@ unit cgcpu;
procedure a_call_name(list : TAsmList;const s : string; weak: boolean);override; procedure a_call_name(list : TAsmList;const s : string; weak: boolean);override;
procedure a_call_reg(list : TAsmList;reg: tregister);override; procedure a_call_reg(list : TAsmList;reg: tregister);override;
procedure a_call_ref(list : TAsmList;ref: treference);override;
procedure a_op_const_reg(list : TAsmList; Op: TOpCG; size: TCGSize; a: tcgint; reg: TRegister); override; procedure a_op_const_reg(list : TAsmList; Op: TOpCG; size: TCGSize; a: tcgint; reg: TRegister); override;
procedure a_op_reg_reg(list: TAsmList; Op: TOpCG; size: TCGSize; src, dst : TRegister); override; procedure a_op_reg_reg(list: TAsmList; Op: TOpCG; size: TCGSize; src, dst : TRegister); override;
@ -406,19 +405,6 @@ unit cgcpu;
end; end;
procedure tcgavr.a_call_ref(list : TAsmList;ref: treference);
begin
a_reg_alloc(list,NR_ZLO);
a_reg_alloc(list,NR_ZHI);
a_load_ref_reg(list,OS_ADDR,OS_ADDR,ref,NR_ZLO);
list.concat(taicpu.op_none(A_ICALL));
a_reg_dealloc(list,NR_ZLO);
a_reg_dealloc(list,NR_ZHI);
include(current_procinfo.flags,pi_do_call);
end;
procedure tcgavr.a_op_const_reg(list : TAsmList; Op: TOpCG; size: TCGSize; a: tcgint; reg: TRegister); procedure tcgavr.a_op_const_reg(list : TAsmList; Op: TOpCG; size: TCGSize; a: tcgint; reg: TRegister);
begin begin
if not(size in [OS_S8,OS_8,OS_S16,OS_16,OS_S32,OS_32]) then if not(size in [OS_S8,OS_8,OS_S16,OS_16,OS_S32,OS_32]) then

View File

@ -227,7 +227,6 @@ unit cgobj;
} }
procedure a_call_name(list : TAsmList;const s : string; weak: boolean);virtual; abstract; procedure a_call_name(list : TAsmList;const s : string; weak: boolean);virtual; abstract;
procedure a_call_reg(list : TAsmList;reg : tregister);virtual; abstract; procedure a_call_reg(list : TAsmList;reg : tregister);virtual; abstract;
procedure a_call_ref(list : TAsmList;ref : treference);virtual;
{ same as a_call_name, might be overridden on certain architectures to emit { same as a_call_name, might be overridden on certain architectures to emit
static calls without usage of a got trampoline } static calls without usage of a got trampoline }
procedure a_call_name_static(list : TAsmList;const s : string);virtual; procedure a_call_name_static(list : TAsmList;const s : string);virtual;
@ -2413,16 +2412,6 @@ implementation
end; end;
procedure tcg.a_call_ref(list : TAsmList;ref: treference);
var
tempreg : TRegister;
begin
tempreg := getintregister(list, OS_ADDR);
a_load_ref_reg(list,OS_ADDR,OS_ADDR,ref,tempreg);
a_call_reg(list,tempreg);
end;
function tcg.g_indirect_sym_load(list:TAsmList;const symname: string; const flags: tindsymflags): tregister; function tcg.g_indirect_sym_load(list:TAsmList;const symname: string; const flags: tindsymflags): tregister;
var var
l: tasmsymbol; l: tasmsymbol;

View File

@ -151,7 +151,6 @@ unit hlcg2ll;
function a_call_name(list : TAsmList;pd : tprocdef;const s : TSymStr; forceresdef: tdef; weak: boolean): tcgpara;override; function a_call_name(list : TAsmList;pd : tprocdef;const s : TSymStr; forceresdef: tdef; weak: boolean): tcgpara;override;
procedure a_call_reg(list : TAsmList;pd : tabstractprocdef;reg : tregister);override; procedure a_call_reg(list : TAsmList;pd : tabstractprocdef;reg : tregister);override;
procedure a_call_ref(list : TAsmList;pd : tabstractprocdef;const ref : treference);override;
{ same as a_call_name, might be overridden on certain architectures to emit { same as a_call_name, might be overridden on certain architectures to emit
static calls without usage of a got trampoline } static calls without usage of a got trampoline }
function a_call_name_static(list : TAsmList;pd : tprocdef;const s : TSymStr; forceresdef: tdef): tcgpara;override; function a_call_name_static(list : TAsmList;pd : tprocdef;const s : TSymStr; forceresdef: tdef): tcgpara;override;
@ -462,11 +461,6 @@ implementation
cg.a_call_reg(list,reg); cg.a_call_reg(list,reg);
end; end;
procedure thlcg2ll.a_call_ref(list: TAsmList; pd: tabstractprocdef; const ref: treference);
begin
cg.a_call_ref(list,ref);
end;
function thlcg2ll.a_call_name_static(list: TAsmList; pd: tprocdef; const s: TSymStr; forceresdef: tdef): tcgpara; function thlcg2ll.a_call_name_static(list: TAsmList; pd: tprocdef; const s: TSymStr; forceresdef: tdef): tcgpara;
begin begin
cg.a_call_name_static(list,s); cg.a_call_name_static(list,s);

View File

@ -194,7 +194,6 @@ unit hlcgobj;
} }
function a_call_name(list : TAsmList;pd : tprocdef;const s : TSymStr; forceresdef: tdef; weak: boolean): tcgpara;virtual;abstract; function a_call_name(list : TAsmList;pd : tprocdef;const s : TSymStr; forceresdef: tdef; weak: boolean): tcgpara;virtual;abstract;
procedure a_call_reg(list : TAsmList;pd : tabstractprocdef;reg : tregister);virtual;abstract; procedure a_call_reg(list : TAsmList;pd : tabstractprocdef;reg : tregister);virtual;abstract;
procedure a_call_ref(list : TAsmList;pd : tabstractprocdef;const ref : treference);virtual;
{ same as a_call_name, might be overridden on certain architectures to emit { same as a_call_name, might be overridden on certain architectures to emit
static calls without usage of a got trampoline } static calls without usage of a got trampoline }
function a_call_name_static(list : TAsmList;pd : tprocdef;const s : TSymStr; forceresdef: tdef): tcgpara;virtual; function a_call_name_static(list : TAsmList;pd : tprocdef;const s : TSymStr; forceresdef: tdef): tcgpara;virtual;
@ -975,22 +974,6 @@ implementation
end; end;
end; end;
procedure thlcgobj.a_call_ref(list: TAsmList; pd: tabstractprocdef; const ref: treference);
var
reg: tregister;
size: tdef;
begin
{ the loaded data is always a pointer to a procdef. A procvardef is
implicitly a pointer already, but a procdef isn't -> create one }
if pd.typ=procvardef then
size:=pd
else
size:=getpointerdef(pd);
reg:=getaddressregister(list,size);
a_load_ref_reg(list,size,size,ref,reg);
a_call_reg(list,pd,reg);
end;
function thlcgobj.a_call_name_static(list: TAsmList; pd: tprocdef; const s: TSymStr; forceresdef: tdef): tcgpara; function thlcgobj.a_call_name_static(list: TAsmList; pd: tprocdef; const s: TSymStr; forceresdef: tdef): tcgpara;
begin begin
result:=a_call_name(list,pd,s,forceresdef,false); result:=a_call_name(list,pd,s,forceresdef,false);

View File

@ -49,8 +49,6 @@ unit cgcpu;
procedure a_call_name_static_far(list : TAsmList;const s : string); procedure a_call_name_static_far(list : TAsmList;const s : string);
procedure a_call_reg(list : TAsmList;reg : tregister);override; procedure a_call_reg(list : TAsmList;reg : tregister);override;
procedure a_call_reg_far(list : TAsmList;reg : tregister); procedure a_call_reg_far(list : TAsmList;reg : tregister);
procedure a_call_ref(list : TAsmList;ref : treference);override;
procedure a_call_ref_far(list : TAsmList;ref : treference);
procedure a_op_const_reg(list : TAsmList; Op: TOpCG; size: TCGSize; a: tcgint; reg: TRegister); override; procedure a_op_const_reg(list : TAsmList; Op: TOpCG; size: TCGSize; a: tcgint; reg: TRegister); override;
procedure a_op_const_ref(list : TAsmList; Op: TOpCG; size: TCGSize; a: tcgint; const ref: TReference); override; procedure a_op_const_ref(list : TAsmList; Op: TOpCG; size: TCGSize; a: tcgint; const ref: TReference); override;
@ -254,27 +252,12 @@ unit cgcpu;
a_load_reg_ref(list,OS_32,OS_32,reg,href); a_load_reg_ref(list,OS_32,OS_32,reg,href);
cg.getcpuregister(list,NR_BX); cg.getcpuregister(list,NR_BX);
cg.getcpuregister(list,NR_SI); cg.getcpuregister(list,NR_SI);
a_call_ref_far(list,href); href.refaddr:=addr_far_ref;
list.concat(taicpu.op_ref(A_CALL,S_NO,href));
tg.ungettemp(list,href); tg.ungettemp(list,href);
end; end;
procedure tcg8086.a_call_ref(list: TAsmList; ref: treference);
begin
if current_settings.x86memorymodel in x86_far_code_models then
a_call_ref_far(list,ref)
else
a_call_ref_near(list,ref);
end;
procedure tcg8086.a_call_ref_far(list: TAsmList; ref: treference);
begin
ref.refaddr:=addr_far_ref;
list.concat(taicpu.op_ref(A_CALL,S_NO,ref));
end;
procedure tcg8086.a_op_const_reg(list: TAsmList; Op: TOpCG; size: TCGSize; procedure tcg8086.a_op_const_reg(list: TAsmList; Op: TOpCG; size: TCGSize;
a: tcgint; reg: TRegister); a: tcgint; reg: TRegister);
var var

View File

@ -28,13 +28,15 @@ interface
{ $define AnsiStrRef} { $define AnsiStrRef}
uses uses
nx86cal; nx86cal,cgutils;
type type
ti8086callnode = class(tx86callnode) ti8086callnode = class(tx86callnode)
protected protected
procedure pop_parasize(pop_size:longint);override; procedure pop_parasize(pop_size:longint);override;
procedure extra_interrupt_code;override; procedure extra_interrupt_code;override;
procedure extra_call_ref_code(var ref: treference);override;
procedure do_call_ref(ref: treference);override;
end; end;
@ -43,11 +45,11 @@ implementation
uses uses
globtype,systems, globtype,systems,
cutils,verbose,globals, cutils,verbose,globals,
cgbase,cgutils, cgbase,
cpubase,paramgr, cpubase,paramgr,
aasmtai,aasmdata,aasmcpu, aasmtai,aasmdata,aasmcpu,
ncal,nbas,nmem,nld,ncnv, ncal,nbas,nmem,nld,ncnv,
cga,cgobj,cpuinfo; cga,cgobj,cgx86,cpuinfo;
{***************************************************************************** {*****************************************************************************
@ -92,6 +94,33 @@ implementation
end; end;
procedure ti8086callnode.extra_call_ref_code(var ref: treference);
begin
if ref.base<>NR_NO then
begin
cg.getcpuregister(current_asmdata.CurrAsmList,NR_BX);
cg.a_load_reg_reg(current_asmdata.CurrAsmList,OS_16,OS_16,ref.base,NR_BX);
ref.base:=NR_BX;
cg.ungetcpuregister(current_asmdata.CurrAsmList,NR_BX);
end;
if ref.index<>NR_NO then
begin
cg.getcpuregister(current_asmdata.CurrAsmList,NR_SI);
cg.a_load_reg_reg(current_asmdata.CurrAsmList,OS_16,OS_16,ref.index,NR_SI);
ref.index:=NR_SI;
cg.ungetcpuregister(current_asmdata.CurrAsmList,NR_SI);
end;
end;
procedure ti8086callnode.do_call_ref(ref: treference);
begin
if current_settings.x86memorymodel in x86_far_code_models then
ref.refaddr:=addr_far_ref;
current_asmdata.CurrAsmList.concat(taicpu.op_ref(A_CALL,S_NO,ref));
end;
begin begin
ccallnode:=ti8086callnode; ccallnode:=ti8086callnode;
end. end.

View File

@ -87,6 +87,14 @@ interface
LOC_REFERENCE, this method will be called to perform the necessary LOC_REFERENCE, this method will be called to perform the necessary
cleanups. By default it does not do anything } cleanups. By default it does not do anything }
procedure do_release_unused_return_value;virtual; procedure do_release_unused_return_value;virtual;
{ Override the following three methods to support calls to address in
'ref' without loading it into register (only x86 targets probably).
If can_call_ref returns true, it should do required simplification
on ref. }
function can_call_ref(var ref: treference):boolean;virtual;
procedure extra_call_ref_code(var ref: treference);virtual;
procedure do_call_ref(ref: treference);virtual;
public public
procedure pass_generate_code;override; procedure pass_generate_code;override;
destructor destroy;override; destructor destroy;override;
@ -415,6 +423,24 @@ implementation
end; end;
function tcgcallnode.can_call_ref(var ref: treference): boolean;
begin
result:=false;
end;
procedure tcgcallnode.extra_call_ref_code(var ref: treference);
begin
{ no action by default }
end;
procedure tcgcallnode.do_call_ref(ref: treference);
begin
InternalError(2014012901);
end;
procedure tcgcallnode.set_result_location(realresdef: tstoreddef); procedure tcgcallnode.set_result_location(realresdef: tstoreddef);
begin begin
if realresdef.is_intregable or if realresdef.is_intregable or
@ -757,6 +783,7 @@ implementation
pd : tprocdef; pd : tprocdef;
proc_addr_size: TCgSize; proc_addr_size: TCgSize;
proc_addr_voidptrdef: tdef; proc_addr_voidptrdef: tdef;
callref: boolean;
{$ifdef vtentry} {$ifdef vtentry}
sym : tasmsymbol; sym : tasmsymbol;
{$endif vtentry} {$endif vtentry}
@ -884,10 +911,14 @@ implementation
tobjectdef(tprocdef(procdefinition).struct).register_vmt_call(tprocdef(procdefinition).extnumber); tobjectdef(tprocdef(procdefinition).struct).register_vmt_call(tprocdef(procdefinition).extnumber);
reference_reset_base(href,vmtreg,vmtoffset,proc_addr_voidptrdef.alignment); reference_reset_base(href,vmtreg,vmtoffset,proc_addr_voidptrdef.alignment);
{$ifndef x86} pvreg:=NR_NO;
pvreg:=cg.getintregister(current_asmdata.CurrAsmList,proc_addr_size);
cg.a_load_ref_reg(current_asmdata.CurrAsmList,proc_addr_size,proc_addr_size,href,pvreg); callref:=can_call_ref(href);
{$endif not x86} if not callref then
begin
pvreg:=cg.getintregister(current_asmdata.CurrAsmList,proc_addr_size);
cg.a_load_ref_reg(current_asmdata.CurrAsmList,proc_addr_size,proc_addr_size,href,pvreg);
end;
{ Load parameters that are in temporary registers in the { Load parameters that are in temporary registers in the
correct parameter register } correct parameter register }
@ -899,22 +930,9 @@ implementation
freeparas; freeparas;
end; end;
{$ifdef i8086} if callref then
if href.base<>NR_NO then extra_call_ref_code(href);
begin
cg.getcpuregister(current_asmdata.CurrAsmList,NR_BX);
cg.a_load_reg_reg(current_asmdata.CurrAsmList,OS_16,OS_16,href.base,NR_BX);
href.base:=NR_BX;
cg.ungetcpuregister(current_asmdata.CurrAsmList,NR_BX);
end;
if href.index<>NR_NO then
begin
cg.getcpuregister(current_asmdata.CurrAsmList,NR_SI);
cg.a_load_reg_reg(current_asmdata.CurrAsmList,OS_16,OS_16,href.base,NR_SI);
href.index:=NR_SI;
cg.ungetcpuregister(current_asmdata.CurrAsmList,NR_SI);
end;
{$endif i8086}
cg.alloccpuregisters(current_asmdata.CurrAsmList,R_INTREGISTER,regs_to_save_int); cg.alloccpuregisters(current_asmdata.CurrAsmList,R_INTREGISTER,regs_to_save_int);
if cg.uses_registers(R_ADDRESSREGISTER) then if cg.uses_registers(R_ADDRESSREGISTER) then
cg.alloccpuregisters(current_asmdata.CurrAsmList,R_ADDRESSREGISTER,regs_to_save_address); cg.alloccpuregisters(current_asmdata.CurrAsmList,R_ADDRESSREGISTER,regs_to_save_address);
@ -925,11 +943,11 @@ implementation
{ call method } { call method }
extra_call_code; extra_call_code;
{$ifdef x86} if callref then
hlcg.a_call_ref(current_asmdata.CurrAsmList,tabstractprocdef(procdefinition),href); do_call_ref(href)
{$else x86} else
hlcg.a_call_reg(current_asmdata.CurrAsmList,tabstractprocdef(procdefinition),pvreg); hlcg.a_call_reg(current_asmdata.CurrAsmList,tabstractprocdef(procdefinition),pvreg);
{$endif x86}
extra_post_call_code; extra_post_call_code;
end end
else else
@ -977,12 +995,18 @@ implementation
{ now procedure variable case } { now procedure variable case }
begin begin
secondpass(right); secondpass(right);
callref:=false;
pvreg:=cg.getintregister(current_asmdata.CurrAsmList,proc_addr_size); pvreg:=cg.getintregister(current_asmdata.CurrAsmList,proc_addr_size);
{ Only load OS_ADDR from the reference (when converting to hlcg: { Only load OS_ADDR from the reference (when converting to hlcg:
watch out with procedure of object) } watch out with procedure of object) }
if right.location.loc in [LOC_REFERENCE,LOC_CREFERENCE] then if right.location.loc in [LOC_REFERENCE,LOC_CREFERENCE] then
cg.a_load_ref_reg(current_asmdata.CurrAsmList,proc_addr_size,proc_addr_size,right.location.reference,pvreg) begin
href:=right.location.reference;
callref:=can_call_ref(href);
if not callref then
cg.a_load_ref_reg(current_asmdata.CurrAsmList,proc_addr_size,proc_addr_size,right.location.reference,pvreg)
end
else if right.location.loc in [LOC_REGISTER,LOC_CREGISTER] then else if right.location.loc in [LOC_REGISTER,LOC_CREGISTER] then
begin begin
{ in case left is a method pointer and we are on a big endian target, then { in case left is a method pointer and we are on a big endian target, then
@ -1005,6 +1029,9 @@ implementation
freeparas; freeparas;
end; end;
if callref then
extra_call_ref_code(href);
cg.alloccpuregisters(current_asmdata.CurrAsmList,R_INTREGISTER,regs_to_save_int); cg.alloccpuregisters(current_asmdata.CurrAsmList,R_INTREGISTER,regs_to_save_int);
if cg.uses_registers(R_ADDRESSREGISTER) then if cg.uses_registers(R_ADDRESSREGISTER) then
cg.alloccpuregisters(current_asmdata.CurrAsmList,R_ADDRESSREGISTER,regs_to_save_address); cg.alloccpuregisters(current_asmdata.CurrAsmList,R_ADDRESSREGISTER,regs_to_save_address);
@ -1018,7 +1045,11 @@ implementation
if (po_interrupt in procdefinition.procoptions) then if (po_interrupt in procdefinition.procoptions) then
extra_interrupt_code; extra_interrupt_code;
extra_call_code; extra_call_code;
hlcg.a_call_reg(current_asmdata.CurrAsmList,tabstractprocdef(procdefinition),pvreg);
if callref then
do_call_ref(href)
else
hlcg.a_call_reg(current_asmdata.CurrAsmList,procdefinition,pvreg);
extra_post_call_code; extra_post_call_code;
end; end;

View File

@ -61,8 +61,6 @@ unit cgx86;
procedure a_call_name_static_near(list : TAsmList;const s : string); procedure a_call_name_static_near(list : TAsmList;const s : string);
procedure a_call_reg(list : TAsmList;reg : tregister);override; procedure a_call_reg(list : TAsmList;reg : tregister);override;
procedure a_call_reg_near(list : TAsmList;reg : tregister); procedure a_call_reg_near(list : TAsmList;reg : tregister);
procedure a_call_ref(list : TAsmList;ref : treference);override;
procedure a_call_ref_near(list : TAsmList;ref : treference);
procedure a_op_const_reg(list : TAsmList; Op: TOpCG; size: TCGSize; a: tcgint; reg: TRegister); override; procedure a_op_const_reg(list : TAsmList; Op: TOpCG; size: TCGSize; a: tcgint; reg: TRegister); override;
procedure a_op_const_ref(list : TAsmList; Op: TOpCG; size: TCGSize; a: tcgint; const ref: TReference); override; procedure a_op_const_ref(list : TAsmList; Op: TOpCG; size: TCGSize; a: tcgint; const ref: TReference); override;
@ -850,18 +848,6 @@ unit cgx86;
end; end;
procedure tcgx86.a_call_ref(list : TAsmList;ref : treference);
begin
a_call_ref_near(list,ref);
end;
procedure tcgx86.a_call_ref_near(list: TAsmList; ref: treference);
begin
list.concat(taicpu.op_ref(A_CALL,S_NO,ref));
end;
{********************** load instructions ********************} {********************** load instructions ********************}
procedure tcgx86.a_load_const_reg(list : TAsmList; tosize: TCGSize; a : tcgint; reg : TRegister); procedure tcgx86.a_load_const_reg(list : TAsmList; tosize: TCGSize; a : tcgint; reg : TRegister);

View File

@ -29,6 +29,7 @@ interface
uses uses
symdef, symdef,
cgutils,
ncgcal; ncgcal;
type type
@ -39,6 +40,8 @@ interface
protected protected
procedure do_release_unused_return_value;override; procedure do_release_unused_return_value;override;
procedure set_result_location(realresdef: tstoreddef);override; procedure set_result_location(realresdef: tstoreddef);override;
function can_call_ref(var ref: treference):boolean;override;
procedure do_call_ref(ref: treference);override;
end; end;
@ -46,7 +49,7 @@ implementation
uses uses
cgobj, cgobj,
cgbase,cgutils,cpubase,cgx86,cga; cgbase,cpubase,cgx86,cga,aasmdata,aasmcpu;
{***************************************************************************** {*****************************************************************************
@ -81,4 +84,16 @@ implementation
end; end;
function tx86callnode.can_call_ref(var ref: treference): boolean;
begin
tcgx86(cg).make_simple_ref(current_asmdata.CurrAsmList,ref);
result:=true;
end;
procedure tx86callnode.do_call_ref(ref: treference);
begin
current_asmdata.CurrAsmList.concat(taicpu.op_ref(A_CALL,S_NO,ref));
end;
end. end.