fpc/compiler/jvm/rgcpu.pas
Jonas Maebe d0a3b49e6c * fixed memory leak
git-svn-id: branches/jvmbackend@18595 -
2011-08-20 08:13:36 +00:00

359 lines
12 KiB
ObjectPascal

{
Copyright (c) 2010 by Jonas Maebe
This unit implements the JVM specific class for the register
allocator
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
****************************************************************************}
unit rgcpu;
{$i fpcdefs.inc}
interface
uses
aasmbase,aasmcpu,aasmtai,aasmdata,
cgbase,cgutils,
cpubase,
rgobj;
type
tspilltemps = array[tregistertype] of ^Tspill_temp_list;
{ trgcpu }
trgcpu=class(trgobj)
protected
class procedure do_spill_replace_all(list:TAsmList;instr:taicpu;const spilltemps: tspilltemps);
class procedure remove_dummy_load_stores(list: TAsmList; headertai: tai);
public
{ performs the register allocation for *all* register types }
class procedure do_all_register_allocation(list: TAsmList; headertai: tai);
end;
implementation
uses
verbose,cutils,
globtype,globals,
cgobj,
tgobj;
{ trgcpu }
class procedure trgcpu.do_spill_replace_all(list:TAsmList;instr:taicpu;const spilltemps: tspilltemps);
var
l: longint;
reg: tregister;
begin
{ jvm instructions never have more than one memory (virtual register)
operand, so there is no danger of superregister conflicts }
for l:=0 to instr.ops-1 do
if instr.oper[l]^.typ=top_reg then
begin
reg:=instr.oper[l]^.reg;
instr.loadref(l,spilltemps[getregtype(reg)]^[getsupreg(reg)]);
end;
end;
class procedure trgcpu.remove_dummy_load_stores(list: TAsmList; headertai: tai);
type
taitypeset = set of taitype;
function nextskipping(p: tai; const skip: taitypeset): tai;
begin
result:=p;
if not assigned(result) then
exit;
repeat
result:=tai(result.next);
until not assigned(result) or
not(result.typ in skip);
end;
function issimpleregstore(p: tai; var reg: tregister; doubleprecisionok: boolean): boolean;
const
simplestoressp = [a_astore,a_fstore,a_istore];
simplestoresdp = [a_dstore,a_lstore];
begin
result:=
assigned(p) and
(p.typ=ait_instruction) and
((taicpu(p).opcode in simplestoressp) or
(doubleprecisionok and
(taicpu(p).opcode in simplestoresdp))) and
((reg=NR_NO) or
(taicpu(p).oper[0]^.typ=top_reg) and
(taicpu(p).oper[0]^.reg=reg));
if result and
(reg=NR_NO) then
reg:=taicpu(p).oper[0]^.reg;
end;
function issimpleregload(p: tai; var reg: tregister; doubleprecisionok: boolean): boolean;
const
simpleloadssp = [a_aload,a_fload,a_iload];
simpleloadsdp = [a_dload,a_lload];
begin
result:=
assigned(p) and
(p.typ=ait_instruction) and
((taicpu(p).opcode in simpleloadssp) or
(doubleprecisionok and
(taicpu(p).opcode in simpleloadsdp))) and
((reg=NR_NO) or
(taicpu(p).oper[0]^.typ=top_reg) and
(taicpu(p).oper[0]^.reg=reg));
if result and
(reg=NR_NO) then
reg:=taicpu(p).oper[0]^.reg;
end;
function isregallocoftyp(p: tai; typ: TRegAllocType;var reg: tregister): boolean;
begin
result:=
assigned(p) and
(p.typ=ait_regalloc) and
(tai_regalloc(p).ratype=typ);
if result then
if reg=NR_NO then
reg:=tai_regalloc(p).reg
else
result:=tai_regalloc(p).reg=reg;
end;
function regininstruction(p: tai; reg: tregister): boolean;
var
sr: tsuperregister;
i: longint;
begin
result:=false;
if p.typ<>ait_instruction then
exit;
sr:=getsupreg(reg);
for i:=0 to taicpu(p).ops-1 do
case taicpu(p).oper[0]^.typ of
top_reg:
if (getsupreg(taicpu(p).oper[0]^.reg)=sr) then
exit(true);
top_ref:
begin
if (getsupreg(taicpu(p).oper[0]^.ref^.base)=sr) then
exit(true);
if (getsupreg(taicpu(p).oper[0]^.ref^.index)=sr) then
exit(true);
if (getsupreg(taicpu(p).oper[0]^.ref^.indexbase)=sr) then
exit(true);
if (getsupreg(taicpu(p).oper[0]^.ref^.indexbase)=sr) then
exit(true);
end;
end;
end;
function try_remove_store_dealloc_load(var p: tai): boolean;
var
dealloc,
load: tai;
reg: tregister;
begin
result:=false;
{ check for:
store regx
dealloc regx
load regx
and remove. We don't have to check that the load/store
types match, because they have to for this to be
valid JVM code }
dealloc:=nextskipping(p,[ait_comment]);
load:=nextskipping(dealloc,[ait_comment]);
reg:=NR_NO;
if issimpleregstore(p,reg,true) and
isregallocoftyp(dealloc,ra_dealloc,reg) and
issimpleregload(load,reg,true) then
begin
{ remove the whole sequence: the store }
list.remove(p);
p.free;
p:=Tai(load.next);
{ the load }
list.remove(load);
load.free;
result:=true;
end;
end;
var
p,next,nextnext: tai;
reg: tregister;
removedsomething: boolean;
begin
repeat
removedsomething:=false;
p:=headertai;
while assigned(p) do
begin
case p.typ of
ait_regalloc:
begin
reg:=NR_NO;
next:=nextskipping(p,[ait_comment]);
nextnext:=nextskipping(next,[ait_comment,ait_regalloc]);
if assigned(nextnext) then
begin
{ remove
alloc reg
dealloc reg
(can appear after optimisations, necessary to prevent
useless stack slot allocations) }
if isregallocoftyp(p,ra_alloc,reg) and
isregallocoftyp(next,ra_dealloc,reg) and
not regininstruction(nextnext,reg) then
begin
list.remove(p);
p.free;
p:=tai(next.next);
list.remove(next);
next.free;
removedsomething:=true;
continue;
end;
end;
end;
ait_instruction:
begin
if try_remove_store_dealloc_load(p) then
begin
removedsomething:=true;
continue;
end;
{ todo in peephole optimizer:
alloc regx // not double precision
store regx // not double precision
load regy or memy
dealloc regx
load regx
-> change into
load regy or memy
swap // can only handle single precision
and then
swap
<commutative op>
-> remove swap
}
end;
end;
p:=tai(p.next);
end;
until not removedsomething;
end;
class procedure trgcpu.do_all_register_allocation(list: TAsmList; headertai: tai);
var
spill_temps : tspilltemps;
templist : TAsmList;
intrg,
fprg : trgcpu;
p,q : tai;
size : longint;
begin
{ Since there are no actual registers, we simply spill everything. We
use tt_regallocator temps, which are not used by the temp allocator
during code generation, so that we cannot accidentally overwrite
any temporary values }
{ get references to all register allocators }
intrg:=trgcpu(cg.rg[R_INTREGISTER]);
fprg:=trgcpu(cg.rg[R_FPUREGISTER]);
{ determine the live ranges of all registers }
intrg.insert_regalloc_info_all(list);
fprg.insert_regalloc_info_all(list);
{ Don't do the actual allocation when -sr is passed }
if (cs_no_regalloc in current_settings.globalswitches) then
exit;
{ remove some simple useless store/load sequences }
remove_dummy_load_stores(list,headertai);
{ allocate room to store the virtual register -> temp mapping }
spill_temps[R_INTREGISTER]:=allocmem(sizeof(treference)*intrg.maxreg);
spill_temps[R_FPUREGISTER]:=allocmem(sizeof(treference)*fprg.maxreg);
{ List to insert temp allocations into }
templist:=TAsmList.create;
{ allocate/replace all registers }
p:=headertai;
while assigned(p) do
begin
case p.typ of
ait_regalloc:
with Tai_regalloc(p) do
begin
case getregtype(reg) of
R_INTREGISTER:
if getsubreg(reg)=R_SUBD then
size:=4
else
size:=8;
R_ADDRESSREGISTER:
size:=4;
R_FPUREGISTER:
if getsubreg(reg)=R_SUBFS then
size:=4
else
size:=8;
else
internalerror(2010122912);
end;
case ratype of
ra_alloc :
tg.gettemp(templist,
size,1,
tt_regallocator,spill_temps[getregtype(reg)]^[getsupreg(reg)]);
ra_dealloc :
begin
tg.ungettemp(templist,spill_temps[getregtype(reg)]^[getsupreg(reg)]);
{ don't invalidate the temp reference, may still be used one instruction
later }
end;
end;
{ insert the tempallocation/free at the right place }
list.insertlistbefore(p,templist);
{ remove the register allocation info for the register
(p.previous is valid because we just inserted the temp
allocation/free before p) }
q:=Tai(p.previous);
list.remove(p);
p.free;
p:=q;
end;
ait_instruction:
do_spill_replace_all(list,taicpu(p),spill_temps);
end;
p:=Tai(p.next);
end;
freemem(spill_temps[R_INTREGISTER]);
freemem(spill_temps[R_FPUREGISTER]);
templist.free;
end;
end.