summaryrefslogtreecommitdiff
path: root/compiler/js/rgcpu.pas
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/js/rgcpu.pas')
-rw-r--r--compiler/js/rgcpu.pas358
1 files changed, 358 insertions, 0 deletions
diff --git a/compiler/js/rgcpu.pas b/compiler/js/rgcpu.pas
new file mode 100644
index 0000000000..879a752bc1
--- /dev/null
+++ b/compiler/js/rgcpu.pas
@@ -0,0 +1,358 @@
+{
+ 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.