1 { 2 Copyright (c) 1998-2009 by Florian Klaempfl and David Zhang 3 4 This unit implements the register allocator for MIPS(EL) 5 6 This program is free software; you can redistribute it and/or modify 7 it under the terms of the GNU General Public License as published by 8 the Free Software Foundation; either version 2 of the License, or 9 (at your option) any later version. 10 11 This program is distributed in the hope that it will be useful, 12 but WITHOUT ANY WARRANTY; without even the implied warranty of 13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 GNU General Public License for more details. 15 16 You should have received a copy of the GNU General Public License 17 along with this program; if not, write to the Free Software 18 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 19 20 **************************************************************************** 21 } 22 23 unit rgcpu; 24 25 {$i fpcdefs.inc} 26 27 interface 28 29 uses 30 aasmbase,aasmsym,aasmcpu,aasmtai,aasmdata, 31 cgbase,cgutils, 32 cpubase, 33 rgobj; 34 35 type 36 trgcpu=class(trgobj) get_spill_subregnull37 function get_spill_subreg(r : tregister) : tsubregister;override; 38 procedure do_spill_read(list: TAsmList; pos: tai; const spilltemp: treference; tempreg: tregister; orgsupreg: tsuperregister); override; 39 procedure do_spill_written(list: TAsmList; pos: tai; const spilltemp: treference; tempreg: tregister; orgsupreg: tsuperregister); override; do_spill_replacenull40 function do_spill_replace(list: TAsmList; instr: tai_cpu_abstract_sym; orgreg: tsuperregister; const spilltemp: treference): boolean; override; 41 end; 42 43 trgintcpu=class(trgcpu) 44 procedure add_cpu_interferences(p:tai);override; 45 end; 46 47 implementation 48 49 uses 50 globtype, 51 verbose,cutils, 52 cgobj; 53 54 trgcpu.get_spill_subregnull55 function trgcpu.get_spill_subreg(r : tregister) : tsubregister; 56 begin 57 if getregtype(r)=R_FPUREGISTER then 58 result:=getsubreg(r) 59 else 60 result:=defaultsub; 61 end; 62 63 64 procedure trgcpu.do_spill_read(list: TAsmList; pos: tai; const spilltemp: treference; tempreg: tregister; orgsupreg: tsuperregister); 65 var 66 helpins : tai; 67 tmpref : treference; 68 helplist : tasmlist; 69 hreg : tregister; 70 begin 71 if abs(spilltemp.offset)>32767 then 72 begin 73 helplist:=tasmlist.create; 74 75 if getregtype(tempreg)=R_INTREGISTER then 76 hreg:=tempreg 77 else 78 hreg:=cg.getintregister(helplist,OS_ADDR); 79 80 helplist.concat(taicpu.op_reg_const(A_LUI,hreg,spilltemp.offset shr 16)); 81 helplist.concat(taicpu.op_reg_reg_const(A_ORI,hreg,hreg,spilltemp.offset and $FFFF)); 82 helplist.concat(taicpu.op_reg_reg_reg(A_ADDU,hreg,hreg,spilltemp.base)); 83 84 reference_reset_base(tmpref,hreg,0,spilltemp.temppos,sizeof(aint),[]); 85 86 helpins:=spilling_create_load(tmpref,tempreg); 87 helplist.concat(helpins); 88 list.insertlistafter(pos,helplist); 89 helplist.free; 90 end 91 else 92 inherited; 93 end; 94 95 96 procedure trgcpu.do_spill_written(list: TAsmList; pos: tai; const spilltemp: treference; tempreg: tregister; orgsupreg: tsuperregister); 97 var 98 tmpref : treference; 99 helplist : tasmlist; 100 hreg : tregister; 101 begin 102 if abs(spilltemp.offset)>32767 then 103 begin 104 helplist:=tasmlist.create; 105 106 if getregtype(tempreg)=R_INTREGISTER then 107 hreg:=getregisterinline(helplist,[R_SUBWHOLE]) 108 else 109 hreg:=cg.getintregister(helplist,OS_ADDR); 110 111 helplist.concat(taicpu.op_reg_const(A_LUI,hreg,spilltemp.offset shr 16)); 112 helplist.concat(taicpu.op_reg_reg_const(A_ORI,hreg,hreg,spilltemp.offset and $FFFF)); 113 helplist.concat(taicpu.op_reg_reg_reg(A_ADDU,hreg,hreg,spilltemp.base)); 114 115 reference_reset_base(tmpref,hreg,0,spilltemp.temppos,sizeof(aint),[]); 116 117 helplist.concat(spilling_create_store(tempreg,tmpref)); 118 if getregtype(tempreg)=R_INTREGISTER then 119 ungetregisterinline(helplist,hreg); 120 121 list.insertlistafter(pos,helplist); 122 helplist.free; 123 end 124 else 125 inherited; 126 end; 127 128 trgcpu.do_spill_replacenull129 function trgcpu.do_spill_replace(list: TAsmList; instr: tai_cpu_abstract_sym; orgreg: tsuperregister; const spilltemp: treference): boolean; 130 begin 131 result:=false; 132 { Replace 'move orgreg,src' with 'sw src,spilltemp' 133 and 'move dst,orgreg' with 'lw dst,spilltemp' } 134 135 if (not (instr.opcode in [A_MOVE,A_MOV_S,A_MOV_D,A_MTC1])) or (abs(spilltemp.offset)>32767) then 136 exit; 137 if (instr.ops<>2) or 138 (instr.oper[0]^.typ<>top_reg) or 139 (instr.oper[1]^.typ<>top_reg) then 140 InternalError(2013061001); 141 if (getregtype(instr.oper[0]^.reg)<>regtype) or 142 (getregtype(instr.oper[1]^.reg)<>regtype) then 143 begin 144 if (instr.opcode=A_MTC1) then 145 begin 146 { TODO: MTC1 src,orgreg ==> SW src,0/4(spilltemp) (endian-dependent!!) } 147 if (regtype=R_FPUREGISTER) then 148 exit; 149 end 150 else 151 InternalError(2013061003); 152 end; 153 if get_alias(getsupreg(instr.oper[1]^.reg))=orgreg then 154 begin 155 case instr.opcode of 156 A_MOVE: instr.opcode:=A_LW; 157 A_MOV_S: instr.opcode:=A_LWC1; 158 A_MOV_D: instr.opcode:=A_LDC1; 159 else 160 InternalError(2013061004); 161 end; 162 end 163 else if get_alias(getsupreg(instr.oper[0]^.reg))=orgreg then 164 begin 165 case instr.opcode of 166 A_MOVE: instr.opcode:=A_SW; 167 A_MOV_S: instr.opcode:=A_SWC1; 168 A_MOV_D: instr.opcode:=A_SDC1; 169 A_MTC1: 170 begin 171 if (getregtype(instr.oper[0]^.reg)<>R_INTREGISTER) then 172 InternalError(2013061006); 173 instr.opcode:=A_LWC1; 174 end 175 else 176 InternalError(2013061005); 177 end; 178 instr.oper[0]^:=instr.oper[1]^; 179 end 180 else 181 InternalError(2013061002); 182 instr.oper[1]^.typ:=top_ref; 183 new(instr.oper[1]^.ref); 184 instr.oper[1]^.ref^:=spilltemp; 185 result:=true; 186 end; 187 188 189 procedure trgintcpu.add_cpu_interferences(p: tai); 190 var 191 supreg: tsuperregister; 192 begin 193 if p.typ<>ait_instruction then 194 exit; 195 if (taicpu(p).ops>=1) and (taicpu(p).oper[0]^.typ=top_reg) and 196 (getregtype(taicpu(p).oper[0]^.reg)=regtype) and 197 (taicpu(p).spilling_get_operation_type(0) in [operand_write,operand_readwrite]) then 198 begin 199 { prevent merging registers with frame/stack pointer, $zero and $at 200 if an instruction writes to the register } 201 supreg:=getsupreg(taicpu(p).oper[0]^.reg); 202 add_edge(supreg,RS_STACK_POINTER_REG); 203 add_edge(supreg,RS_FRAME_POINTER_REG); 204 add_edge(supreg,RS_R0); 205 add_edge(supreg,RS_R1); 206 end; 207 end; 208 209 210 end. 211