mirror of
https://gitlab.com/freepascal.org/fpc/source.git
synced 2025-09-28 03:41:07 +02:00
* optimized spilling writing when the reg operand can be
replaced by reference
This commit is contained in:
parent
044ec56b56
commit
c853d10cc2
@ -105,388 +105,6 @@ implementation
|
||||
Trgcpu
|
||||
******************************************************************************}
|
||||
|
||||
{$ifdef OLDRGX86}
|
||||
function trgx86.instr_spill_register(list:Taasmoutput;
|
||||
instr:taicpu;
|
||||
const r:Tsuperregisterset;
|
||||
const spilltemplist:Tspill_temp_list): boolean;
|
||||
{
|
||||
Spill the registers in r in this instruction. Returns true if any help
|
||||
registers are used. This procedure has become one big hack party, because
|
||||
of the huge amount of situations you can have. The irregularity of the i386
|
||||
instruction set doesn't help either. (DM)
|
||||
}
|
||||
var i:byte;
|
||||
supreg:Tsuperregister;
|
||||
subreg:Tsubregister;
|
||||
helpreg:Tregister;
|
||||
helpins:Taicpu;
|
||||
op:Tasmop;
|
||||
hopsize:Topsize;
|
||||
pos:Tai;
|
||||
|
||||
begin
|
||||
{Situation examples are in intel notation, so operand order:
|
||||
mov eax , ebx
|
||||
^^^ ^^^
|
||||
oper[1] oper[0]
|
||||
(DM)}
|
||||
result:=false;
|
||||
with taicpu(instr) do
|
||||
begin
|
||||
case ops of
|
||||
0:
|
||||
;
|
||||
1:
|
||||
begin
|
||||
if (oper[0]^.typ=top_reg) and
|
||||
(getregtype(oper[0]^.reg)=regtype) then
|
||||
begin
|
||||
supreg:=getsupreg(oper[0]^.reg);
|
||||
if supregset_in(r,supreg) then
|
||||
begin
|
||||
{Situation example:
|
||||
push r20d ; r20d must be spilled into [ebp-12]
|
||||
|
||||
Change into:
|
||||
push [ebp-12] ; Replace register by reference }
|
||||
{ hopsize:=reg2opsize(oper[0].reg);}
|
||||
oper[0]^.typ:=top_ref;
|
||||
new(oper[0]^.ref);
|
||||
oper[0]^.ref^:=spilltemplist[supreg];
|
||||
{ oper[0]^.ref^.size:=hopsize;}
|
||||
end;
|
||||
end;
|
||||
if oper[0]^.typ=top_ref then
|
||||
begin
|
||||
supreg:=getsupreg(oper[0]^.ref^.base);
|
||||
if supregset_in(r,supreg) then
|
||||
begin
|
||||
{Situation example:
|
||||
push [r21d+4*r22d] ; r21d must be spilled into [ebp-12]
|
||||
|
||||
Change into:
|
||||
|
||||
mov r23d,[ebp-12] ; Use a help register
|
||||
push [r23d+4*r22d] ; Replace register by helpregister }
|
||||
subreg:=getsubreg(oper[0]^.ref^.base);
|
||||
if oper[0]^.ref^.index=NR_NO then
|
||||
pos:=Tai(previous)
|
||||
else
|
||||
pos:=get_insert_pos(Tai(previous),getsupreg(oper[0]^.ref^.index),RS_INVALID,RS_INVALID);
|
||||
getregisterinline(list,pos,subreg,helpreg);
|
||||
result:=true;
|
||||
helpins:=Taicpu.op_ref_reg(A_MOV,reg2opsize(oper[0]^.ref^.base),spilltemplist[supreg],helpreg);
|
||||
if pos=nil then
|
||||
list.insertafter(helpins,list.first)
|
||||
else
|
||||
list.insertafter(helpins,pos.next);
|
||||
ungetregisterinline(list,helpins,helpreg);
|
||||
forward_allocation(Tai(helpins.next),instr);
|
||||
oper[0]^.ref^.base:=helpreg;
|
||||
end;
|
||||
supreg:=getsupreg(oper[0]^.ref^.index);
|
||||
if supregset_in(r,supreg) then
|
||||
begin
|
||||
{Situation example:
|
||||
push [r21d+4*r22d] ; r22d must be spilled into [ebp-12]
|
||||
|
||||
Change into:
|
||||
|
||||
mov r23d,[ebp-12] ; Use a help register
|
||||
push [r21d+4*r23d] ; Replace register by helpregister }
|
||||
subreg:=getsubreg(oper[0]^.ref^.index);
|
||||
if oper[0]^.ref^.base=NR_NO then
|
||||
pos:=Tai(instr.previous)
|
||||
else
|
||||
pos:=get_insert_pos(Tai(instr.previous),getsupreg(oper[0]^.ref^.base),RS_INVALID,RS_INVALID);
|
||||
getregisterinline(list,pos,subreg,helpreg);
|
||||
result:=true;
|
||||
helpins:=Taicpu.op_ref_reg(A_MOV,reg2opsize(oper[0]^.ref^.index),spilltemplist[supreg],helpreg);
|
||||
if pos=nil then
|
||||
list.insertafter(helpins,list.first)
|
||||
else
|
||||
list.insertafter(helpins,pos.next);
|
||||
ungetregisterinline(list,helpins,helpreg);
|
||||
forward_allocation(Tai(helpins.next),instr);
|
||||
oper[0]^.ref^.index:=helpreg;
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
2,
|
||||
3 :
|
||||
begin
|
||||
{ Opcodes with 3 registers are shrd/shld, where the 3rd operand is const or CL,
|
||||
that doesn't need spilling }
|
||||
|
||||
{ First spill the registers from the references. This is
|
||||
required because the reference can be moved from this instruction
|
||||
to a MOV instruction when spilling of the register operand is done }
|
||||
for i:=0 to 1 do
|
||||
if oper[i]^.typ=top_ref then
|
||||
begin
|
||||
supreg:=getsupreg(oper[i]^.ref^.base);
|
||||
if supregset_in(r,supreg) then
|
||||
begin
|
||||
{Situation example:
|
||||
add r20d,[r21d+4*r22d] ; r21d must be spilled into [ebp-12]
|
||||
|
||||
Change into:
|
||||
|
||||
mov r23d,[ebp-12] ; Use a help register
|
||||
add r20d,[r23d+4*r22d] ; Replace register by helpregister }
|
||||
subreg:=getsubreg(oper[i]^.ref^.base);
|
||||
if i=1 then
|
||||
pos:=get_insert_pos(Tai(instr.previous),getsupreg(oper[i]^.ref^.index),getsupreg(oper[0]^.reg),RS_INVALID)
|
||||
else
|
||||
pos:=get_insert_pos(Tai(instr.previous),getsupreg(oper[i]^.ref^.index),RS_INVALID,RS_INVALID);
|
||||
getregisterinline(list,pos,subreg,helpreg);
|
||||
result:=true;
|
||||
helpins:=Taicpu.op_ref_reg(A_MOV,reg2opsize(oper[i]^.ref^.base),spilltemplist[supreg],helpreg);
|
||||
if pos=nil then
|
||||
list.insertafter(helpins,list.first)
|
||||
else
|
||||
list.insertafter(helpins,pos.next);
|
||||
oper[i]^.ref^.base:=helpreg;
|
||||
ungetregisterinline(list,helpins,helpreg);
|
||||
forward_allocation(Tai(helpins.next),instr);
|
||||
end;
|
||||
supreg:=getsupreg(oper[i]^.ref^.index);
|
||||
if supregset_in(r,supreg) then
|
||||
begin
|
||||
{Situation example:
|
||||
add r20d,[r21d+4*r22d] ; r22d must be spilled into [ebp-12]
|
||||
|
||||
Change into:
|
||||
|
||||
mov r23d,[ebp-12] ; Use a help register
|
||||
add r20d,[r21d+4*r23d] ; Replace register by helpregister }
|
||||
subreg:=getsubreg(oper[i]^.ref^.index);
|
||||
if i=1 then
|
||||
pos:=get_insert_pos(Tai(instr.previous),getsupreg(oper[i]^.ref^.base),
|
||||
getsupreg(oper[0]^.reg),RS_INVALID)
|
||||
else
|
||||
pos:=get_insert_pos(Tai(instr.previous),getsupreg(oper[i]^.ref^.base),RS_INVALID,RS_INVALID);
|
||||
getregisterinline(list,pos,subreg,helpreg);
|
||||
result:=true;
|
||||
helpins:=Taicpu.op_ref_reg(A_MOV,reg2opsize(oper[i]^.ref^.index),spilltemplist[supreg],helpreg);
|
||||
if pos=nil then
|
||||
list.insertafter(helpins,list.first)
|
||||
else
|
||||
list.insertafter(helpins,pos.next);
|
||||
oper[i]^.ref^.index:=helpreg;
|
||||
ungetregisterinline(list,helpins,helpreg);
|
||||
forward_allocation(Tai(helpins.next),instr);
|
||||
end;
|
||||
end;
|
||||
if (oper[0]^.typ=top_reg) and
|
||||
(getregtype(oper[0]^.reg)=regtype) then
|
||||
begin
|
||||
supreg:=getsupreg(oper[0]^.reg);
|
||||
subreg:=getsubreg(oper[0]^.reg);
|
||||
if supregset_in(r,supreg) then
|
||||
if oper[1]^.typ=top_ref then
|
||||
begin
|
||||
{Situation example:
|
||||
add [r20d],r21d ; r21d must be spilled into [ebp-12]
|
||||
|
||||
Change into:
|
||||
|
||||
mov r22d,[ebp-12] ; Use a help register
|
||||
add [r20d],r22d ; Replace register by helpregister }
|
||||
pos:=get_insert_pos(Tai(instr.previous),getsupreg(oper[0]^.reg),
|
||||
getsupreg(oper[1]^.ref^.base),getsupreg(oper[1]^.ref^.index));
|
||||
getregisterinline(list,pos,subreg,helpreg);
|
||||
result:=true;
|
||||
helpins:=Taicpu.op_ref_reg(A_MOV,reg2opsize(oper[0]^.reg),spilltemplist[supreg],helpreg);
|
||||
if pos=nil then
|
||||
list.insertafter(helpins,list.first)
|
||||
else
|
||||
list.insertafter(helpins,pos.next);
|
||||
oper[0]^.reg:=helpreg;
|
||||
ungetregisterinline(list,helpins,helpreg);
|
||||
forward_allocation(Tai(helpins.next),instr);
|
||||
end
|
||||
else
|
||||
begin
|
||||
{Situation example:
|
||||
add r20d,r21d ; r21d must be spilled into [ebp-12]
|
||||
|
||||
Change into:
|
||||
|
||||
add r20d,[ebp-12] ; Replace register by reference }
|
||||
oper[0]^.typ:=top_ref;
|
||||
new(oper[0]^.ref);
|
||||
oper[0]^.ref^:=spilltemplist[supreg];
|
||||
end;
|
||||
end;
|
||||
if (oper[1]^.typ=top_reg) and
|
||||
(getregtype(oper[1]^.reg)=regtype) then
|
||||
begin
|
||||
supreg:=getsupreg(oper[1]^.reg);
|
||||
subreg:=getsubreg(oper[1]^.reg);
|
||||
if supregset_in(r,supreg) then
|
||||
begin
|
||||
if oper[0]^.typ=top_ref then
|
||||
begin
|
||||
{Situation example:
|
||||
add r20d,[r21d] ; r20d must be spilled into [ebp-12]
|
||||
|
||||
Change into:
|
||||
|
||||
mov r22d,[r21d] ; Use a help register
|
||||
add [ebp-12],r22d ; Replace register by helpregister }
|
||||
pos:=get_insert_pos(Tai(instr.previous),getsupreg(oper[0]^.ref^.base),
|
||||
getsupreg(oper[0]^.ref^.index),RS_INVALID);
|
||||
getregisterinline(list,pos,subreg,helpreg);
|
||||
result:=true;
|
||||
op:=A_MOV;
|
||||
hopsize:=opsize; {Save old value...}
|
||||
if (opcode=A_MOVZX) or (opcode=A_MOVSX) or (opcode=A_LEA) then
|
||||
begin
|
||||
{Because 'movzx memory,register' does not exist...}
|
||||
op:=opcode;
|
||||
opcode:=A_MOV;
|
||||
opsize:=reg2opsize(oper[1]^.reg);
|
||||
end;
|
||||
helpins:=Taicpu.op_ref_reg(op,hopsize,oper[0]^.ref^,helpreg);
|
||||
if pos=nil then
|
||||
list.insertafter(helpins,list.first)
|
||||
else
|
||||
list.insertafter(helpins,pos.next);
|
||||
dispose(oper[0]^.ref);
|
||||
oper[0]^.typ:=top_reg;
|
||||
oper[0]^.reg:=helpreg;
|
||||
oper[1]^.typ:=top_ref;
|
||||
new(oper[1]^.ref);
|
||||
oper[1]^.ref^:=spilltemplist[supreg];
|
||||
ungetregisterinline(list,helpins,helpreg);
|
||||
forward_allocation(Tai(helpins.next),instr);
|
||||
end
|
||||
else
|
||||
begin
|
||||
{Situation example:
|
||||
add r20d,r21d ; r20d must be spilled into [ebp-12]
|
||||
|
||||
Change into:
|
||||
|
||||
add [ebp-12],r21d ; Replace register by reference }
|
||||
if (opcode=A_MOVZX) or (opcode=A_MOVSX) then
|
||||
begin
|
||||
{Because 'movzx memory,register' does not exist...}
|
||||
result:=true;
|
||||
op:=opcode;
|
||||
hopsize:=opsize;
|
||||
opcode:=A_MOV;
|
||||
opsize:=reg2opsize(oper[1]^.reg);
|
||||
pos:=get_insert_pos(Tai(instr.previous),getsupreg(oper[0]^.reg),RS_INVALID,RS_INVALID);
|
||||
getregisterinline(list,pos,subreg,helpreg);
|
||||
helpins:=Taicpu.op_reg_reg(op,hopsize,oper[0]^.reg,helpreg);
|
||||
if pos=nil then
|
||||
list.insertafter(helpins,list.first)
|
||||
else
|
||||
list.insertafter(helpins,pos.next);
|
||||
oper[0]^.reg:=helpreg;
|
||||
ungetregisterinline(list,helpins,helpreg);
|
||||
forward_allocation(Tai(helpins.next),instr);
|
||||
end;
|
||||
oper[1]^.typ:=top_ref;
|
||||
new(oper[1]^.ref);
|
||||
oper[1]^.ref^:=spilltemplist[supreg];
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
|
||||
{ The i386 instruction set never gets boring...
|
||||
some opcodes do not support a memory location as destination }
|
||||
if (oper[1]^.typ=top_ref) and
|
||||
(
|
||||
(oper[0]^.typ=top_const) or
|
||||
((oper[0]^.typ=top_reg) and
|
||||
(getregtype(oper[0]^.reg)=regtype))
|
||||
) then
|
||||
begin
|
||||
case opcode of
|
||||
A_SHLD,A_SHRD,
|
||||
A_IMUL :
|
||||
begin
|
||||
{Yikes! We just changed the destination register into
|
||||
a memory location above here.
|
||||
|
||||
Situation examples:
|
||||
|
||||
imul [ebp-12],r21d ; We need a help register
|
||||
imul [ebp-12],<const> ; We need a help register
|
||||
|
||||
Change into:
|
||||
|
||||
mov r22d,[ebp-12] ; Use a help instruction (only for IMUL)
|
||||
imul r22d,r21d ; Replace reference by helpregister
|
||||
mov [ebp-12],r22d ; Use another help instruction}
|
||||
getregisterinline(list,Tai(previous),subreg,helpreg);
|
||||
result:=true;
|
||||
{First help instruction.}
|
||||
helpins:=Taicpu.op_ref_reg(A_MOV,opsize,oper[1]^.ref^,helpreg);
|
||||
if previous=nil then
|
||||
list.insert(helpins)
|
||||
else
|
||||
list.insertafter(helpins,previous);
|
||||
{Second help instruction.}
|
||||
helpins:=Taicpu.op_reg_ref(A_MOV,opsize,helpreg,oper[1]^.ref^);
|
||||
dispose(oper[1]^.ref);
|
||||
oper[1]^.typ:=top_reg;
|
||||
oper[1]^.reg:=helpreg;
|
||||
list.insertafter(helpins,instr);
|
||||
ungetregisterinline(list,instr,helpreg);
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
|
||||
{ The i386 instruction set never gets boring...
|
||||
some opcodes do not support a memory location as source }
|
||||
if (oper[0]^.typ=top_ref) and
|
||||
(oper[1]^.typ=top_reg) and
|
||||
(getregtype(oper[1]^.reg)=regtype) then
|
||||
begin
|
||||
case opcode of
|
||||
A_BT,A_BTS,
|
||||
A_BTC,A_BTR :
|
||||
begin
|
||||
{Yikes! We just changed the source register into
|
||||
a memory location above here.
|
||||
|
||||
Situation example:
|
||||
|
||||
bt r21d,[ebp-12] ; We need a help register
|
||||
|
||||
Change into:
|
||||
|
||||
mov r22d,[ebp-12] ; Use a help instruction (only for IMUL)
|
||||
bt r21d,r22d ; Replace reference by helpregister}
|
||||
getregisterinline(list,Tai(previous),subreg,helpreg);
|
||||
result:=true;
|
||||
{First help instruction.}
|
||||
helpins:=Taicpu.op_ref_reg(A_MOV,opsize,oper[0]^.ref^,helpreg);
|
||||
if previous=nil then
|
||||
list.insert(helpins)
|
||||
else
|
||||
list.insertafter(helpins,previous);
|
||||
dispose(oper[0]^.ref);
|
||||
oper[0]^.typ:=top_reg;
|
||||
oper[0]^.reg:=helpreg;
|
||||
ungetregisterinline(list,helpins,helpreg);
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
else
|
||||
internalerror(200409202);
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
{$endif OLDRGX86}
|
||||
|
||||
|
||||
function trgx86.get_spill_subreg(r : tregister) : tsubregister;
|
||||
begin
|
||||
result:=getsubreg(r);
|
||||
@ -494,8 +112,80 @@ implementation
|
||||
|
||||
|
||||
function trgx86.do_spill_replace(list:Taasmoutput;instr:taicpu;orgreg:tsuperregister;const spilltemp:treference):boolean;
|
||||
var
|
||||
replaceoper : longint;
|
||||
begin
|
||||
result:=false;
|
||||
with instr do
|
||||
begin
|
||||
replaceoper:=-1;
|
||||
case ops of
|
||||
1 :
|
||||
begin
|
||||
if (oper[0]^.typ=top_reg) then
|
||||
begin
|
||||
if getsupreg(oper[0]^.reg)<>orgreg then
|
||||
internalerror(200410101);
|
||||
replaceoper:=0;
|
||||
end;
|
||||
end;
|
||||
2,3 :
|
||||
begin
|
||||
{ We can handle opcodes with 2 and 3 operands the same way. The opcodes
|
||||
with 3 registers are shrd/shld, where the 3rd operand is const or CL,
|
||||
that doesn't need spilling }
|
||||
if (oper[0]^.typ=top_reg) and
|
||||
(oper[1]^.typ=top_reg) and
|
||||
(getsupreg(oper[0]^.reg)<>getsupreg(oper[1]^.reg)) then
|
||||
begin
|
||||
{ One of the arguments shall be able to be replaced }
|
||||
if (getregtype(oper[0]^.reg)=regtype) and
|
||||
(getsupreg(oper[0]^.reg)=orgreg) then
|
||||
replaceoper:=0
|
||||
else
|
||||
if (getregtype(oper[0]^.reg)=regtype) and
|
||||
(getsupreg(oper[1]^.reg)=orgreg) then
|
||||
replaceoper:=1
|
||||
else
|
||||
internalerror(200410101);
|
||||
case replaceoper of
|
||||
0 :
|
||||
begin
|
||||
{ Some instructions don't allow memory references
|
||||
for source }
|
||||
case instr.opcode of
|
||||
A_BT,
|
||||
A_BTS,
|
||||
A_BTC,
|
||||
A_BTR :
|
||||
replaceoper:=-1;
|
||||
end;
|
||||
end;
|
||||
1 :
|
||||
begin
|
||||
{ Some instructions don't allow memory references
|
||||
for destination }
|
||||
case instr.opcode of
|
||||
A_SHLD,
|
||||
A_SHRD,
|
||||
A_IMUL :
|
||||
replaceoper:=-1;
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
|
||||
{ Replace register with spill reference }
|
||||
if replaceoper<>-1 then
|
||||
begin
|
||||
oper[replaceoper]^.typ:=top_ref;
|
||||
new(oper[replaceoper]^.ref);
|
||||
oper[replaceoper]^.ref^:=spilltemp;
|
||||
result:=true;
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
|
||||
|
||||
@ -625,7 +315,11 @@ implementation
|
||||
end.
|
||||
{
|
||||
$Log$
|
||||
Revision 1.8 2004-10-05 20:41:02 peter
|
||||
Revision 1.9 2004-10-10 16:30:26 peter
|
||||
* optimized spilling writing when the reg operand can be
|
||||
replaced by reference
|
||||
|
||||
Revision 1.8 2004/10/05 20:41:02 peter
|
||||
* more spilling rewrites
|
||||
|
||||
Revision 1.7 2004/10/04 20:46:22 peter
|
||||
|
Loading…
Reference in New Issue
Block a user