* optimization in tcg386.g_intf_wrapper: use the much more efficient case 1

for virtual methods, that use the register calling convention, but have at
  least one free register (i.e. not used as a parameter and not required to be
  preserved by the function)

git-svn-id: trunk@25830 -
This commit is contained in:
nickysn 2013-10-19 17:40:38 +00:00
parent bfd31e7516
commit 378afb69b2

View File

@ -30,7 +30,7 @@ unit cgcpu;
cgbase,cgobj,cg64f32,cgx86, cgbase,cgobj,cg64f32,cgx86,
aasmbase,aasmtai,aasmdata,aasmcpu, aasmbase,aasmtai,aasmdata,aasmcpu,
cpubase,parabase,cgutils, cpubase,parabase,cgutils,
symconst,symdef symconst,symdef,symsym
; ;
type type
@ -616,17 +616,17 @@ unit cgcpu;
possible calling conventions: possible calling conventions:
default stdcall cdecl pascal register default stdcall cdecl pascal register
default(0): OK OK OK OK OK default(0): OK OK OK OK OK
virtual(1): OK OK OK OK OK(2) virtual(1): OK OK OK OK OK(2 or 1)
(0): (0):
set self parameter to correct value set self parameter to correct value
jmp mangledname jmp mangledname
(1): The wrapper code use %eax to reach the virtual method address (1): The wrapper code use %ecx to reach the virtual method address
set self to correct value set self to correct value
move self,%eax move self,%eax
mov 0(%eax),%eax ; load vmt mov 0(%eax),%ecx ; load vmt
jmp vmtoffs(%eax) ; method offs jmp vmtoffs(%ecx) ; method offs
(2): Virtual use values pushed on stack to reach the method address (2): Virtual use values pushed on stack to reach the method address
so the following code be generated: so the following code be generated:
@ -642,6 +642,27 @@ unit cgcpu;
} }
{ returns whether ECX is used as a parameter }
function is_ecx_used: boolean;
var
i: Integer;
hp: tparavarsym;
paraloc: PCGParaLocation;
begin
for i:=0 to procdef.paras.count-1 do
begin
hp:=tparavarsym(procdef.paras[i]);
paraloc:=hp.paraloc[calleeside].Location;
while paraloc<>nil do
begin
if (paraloc^.Loc=LOC_REGISTER) and (getsupreg(paraloc^.register)=RS_ECX) then
exit(true);
paraloc:=paraloc^.Next;
end;
end;
Result:=false;
end;
procedure getselftoeax(offs: longint); procedure getselftoeax(offs: longint);
var var
href : treference; href : treference;
@ -660,23 +681,23 @@ unit cgcpu;
end; end;
end; end;
procedure loadvmttoeax; procedure loadvmtto(reg: tregister);
var var
href : treference; href : treference;
begin begin
{ mov 0(%eax),%eax ; load vmt} { mov 0(%eax),%reg ; load vmt}
reference_reset_base(href,NR_EAX,0,4); reference_reset_base(href,NR_EAX,0,4);
cg.a_load_ref_reg(list,OS_ADDR,OS_ADDR,href,NR_EAX); cg.a_load_ref_reg(list,OS_ADDR,OS_ADDR,href,reg);
end; end;
procedure op_oneaxmethodaddr(op: TAsmOp); procedure op_onregmethodaddr(op: TAsmOp; reg: tregister);
var var
href : treference; href : treference;
begin begin
if (procdef.extnumber=$ffff) then if (procdef.extnumber=$ffff) then
Internalerror(200006139); Internalerror(200006139);
{ call/jmp vmtoffs(%eax) ; method offs } { call/jmp vmtoffs(%reg) ; method offs }
reference_reset_base(href,NR_EAX,tobjectdef(procdef.struct).vmtmethodoffset(procdef.extnumber),4); reference_reset_base(href,reg,tobjectdef(procdef.struct).vmtmethodoffset(procdef.extnumber),4);
list.concat(taicpu.op_ref(op,S_L,href)); list.concat(taicpu.op_ref(op,S_L,href));
end; end;
@ -724,13 +745,13 @@ unit cgcpu;
if (po_virtualmethod in procdef.procoptions) and if (po_virtualmethod in procdef.procoptions) and
not is_objectpascal_helper(procdef.struct) then not is_objectpascal_helper(procdef.struct) then
begin begin
if (procdef.proccalloption=pocall_register) then if (procdef.proccalloption=pocall_register) and is_ecx_used then
begin begin
{ case 2 } { case 2 }
list.concat(taicpu.op_reg(A_PUSH,S_L,NR_EBX)); { allocate space for address} list.concat(taicpu.op_reg(A_PUSH,S_L,NR_EBX)); { allocate space for address}
list.concat(taicpu.op_reg(A_PUSH,S_L,NR_EAX)); list.concat(taicpu.op_reg(A_PUSH,S_L,NR_EAX));
getselftoeax(8); getselftoeax(8);
loadvmttoeax; loadvmtto(NR_EAX);
loadmethodoffstoeax; loadmethodoffstoeax;
{ mov %eax,4(%esp) } { mov %eax,4(%esp) }
reference_reset_base(href,NR_ESP,4,4); reference_reset_base(href,NR_ESP,4,4);
@ -744,8 +765,8 @@ unit cgcpu;
begin begin
{ case 1 } { case 1 }
getselftoeax(0); getselftoeax(0);
loadvmttoeax; loadvmtto(NR_ECX);
op_oneaxmethodaddr(A_JMP); op_onregmethodaddr(A_JMP,NR_ECX);
end; end;
end end
{ case 0 } { case 0 }