| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358 | {    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.
 |