/compiler/arm/cgcpu.pas
Pascal | 4152 lines | 3511 code | 343 blank | 298 comment | 422 complexity | 4ffa7e926bb091829f38cfbc8d1d4d75 MD5 | raw file
Possible License(s): LGPL-2.0, LGPL-2.1, LGPL-3.0
Large files files are truncated, but you can click here to view the full file
1{ 2 3 Copyright (c) 2003 by Florian Klaempfl 4 Member of the Free Pascal development team 5 6 This unit implements the code generator for the ARM 7 8 This program is free software; you can redistribute it and/or modify 9 it under the terms of the GNU General Public License as published by 10 the Free Software Foundation; either version 2 of the License, or 11 (at your option) any later version. 12 13 This program is distributed in the hope that it will be useful, 14 but WITHOUT ANY WARRANTY; without even the implied warranty of 15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 GNU General Public License for more details. 17 18 You should have received a copy of the GNU General Public License 19 along with this program; if not, write to the Free Software 20 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 21 22 **************************************************************************** 23} 24unit cgcpu; 25 26{$i fpcdefs.inc} 27 28 interface 29 30 uses 31 globtype,symtype,symdef, 32 cgbase,cgutils,cgobj, 33 aasmbase,aasmcpu,aasmtai,aasmdata, 34 parabase, 35 cpubase,cpuinfo,cg64f32,rgcpu; 36 37 38 type 39 tcgarm = class(tcg) 40 { true, if the next arithmetic operation should modify the flags } 41 cgsetflags : boolean; 42 43 procedure a_load_const_cgpara(list : TAsmList;size : tcgsize;a : tcgint;const paraloc : TCGPara);override; 44 procedure a_load_ref_cgpara(list : TAsmList;size : tcgsize;const r : treference;const paraloc : TCGPara);override; 45 procedure a_loadaddr_ref_cgpara(list : TAsmList;const r : treference;const paraloc : TCGPara);override; 46 47 procedure a_call_name(list : TAsmList;const s : string; weak: boolean);override; 48 procedure a_call_reg(list : TAsmList;reg: tregister);override; 49 procedure a_call_ref(list : TAsmList;ref: treference);override; 50 51 procedure a_op_const_reg(list : TAsmList; Op: TOpCG; size: TCGSize; a: tcgint; reg: TRegister); override; 52 procedure a_op_reg_reg(list : TAsmList; Op: TOpCG; size: TCGSize; src, dst: TRegister); override; 53 54 procedure a_op_const_reg_reg(list: TAsmList; op: TOpCg; 55 size: tcgsize; a: tcgint; src, dst: tregister); override; 56 procedure a_op_reg_reg_reg(list: TAsmList; op: TOpCg; 57 size: tcgsize; src1, src2, dst: tregister); override; 58 procedure a_op_const_reg_reg_checkoverflow(list: TAsmList; op: TOpCg; size: tcgsize; a: tcgint; src, dst: tregister;setflags : boolean;var ovloc : tlocation);override; 59 procedure a_op_reg_reg_reg_checkoverflow(list: TAsmList; op: TOpCg; size: tcgsize; src1, src2, dst: tregister;setflags : boolean;var ovloc : tlocation);override; 60 61 { move instructions } 62 procedure a_load_reg_ref(list : TAsmList; fromsize, tosize: tcgsize; reg : tregister;const ref : treference);override; 63 procedure a_load_reg_reg(list : TAsmList; fromsize, tosize : tcgsize;reg1,reg2 : tregister);override; 64 function a_internal_load_reg_ref(list : TAsmList; fromsize, tosize: tcgsize; reg : tregister;const ref : treference):treference; 65 function a_internal_load_ref_reg(list : TAsmList; fromsize, tosize : tcgsize;const Ref : treference;reg : tregister):treference; 66 67 { fpu move instructions } 68 procedure a_loadfpu_reg_reg(list: TAsmList; fromsize, tosize: tcgsize; reg1, reg2: tregister); override; 69 procedure a_loadfpu_ref_reg(list: TAsmList; fromsize, tosize: tcgsize; const ref: treference; reg: tregister); override; 70 procedure a_loadfpu_reg_ref(list: TAsmList; fromsize, tosize: tcgsize; reg: tregister; const ref: treference); override; 71 72 procedure a_loadfpu_ref_cgpara(list : TAsmList;size : tcgsize;const ref : treference;const paraloc : TCGPara);override; 73 { comparison operations } 74 procedure a_cmp_const_reg_label(list : TAsmList;size : tcgsize;cmp_op : topcmp;a : tcgint;reg : tregister; 75 l : tasmlabel);override; 76 procedure a_cmp_reg_reg_label(list : TAsmList;size : tcgsize;cmp_op : topcmp;reg1,reg2 : tregister;l : tasmlabel); override; 77 78 procedure a_jmp_name(list : TAsmList;const s : string); override; 79 procedure a_jmp_always(list : TAsmList;l: tasmlabel); override; 80 procedure a_jmp_flags(list : TAsmList;const f : TResFlags;l: tasmlabel); override; 81 82 procedure g_flags2reg(list: TAsmList; size: TCgSize; const f: TResFlags; reg: TRegister); override; 83 84 procedure g_proc_entry(list : TAsmList;localsize : longint;nostackframe:boolean);override; 85 procedure g_proc_exit(list : TAsmList;parasize : longint;nostackframe:boolean); override; 86 87 procedure a_loadaddr_ref_reg(list : TAsmList;const ref : treference;r : tregister);override; 88 89 procedure g_concatcopy(list : TAsmList;const source,dest : treference;len : tcgint);override; 90 procedure g_concatcopy_unaligned(list : TAsmList;const source,dest : treference;len : tcgint);override; 91 procedure g_concatcopy_move(list : TAsmList;const source,dest : treference;len : tcgint); 92 procedure g_concatcopy_internal(list : TAsmList;const source,dest : treference;len : tcgint;aligned : boolean); 93 94 procedure g_overflowcheck(list: TAsmList; const l: tlocation; def: tdef); override; 95 procedure g_overflowCheck_loc(List:TAsmList;const Loc:TLocation;def:TDef;ovloc : tlocation);override; 96 97 procedure g_save_registers(list : TAsmList);override; 98 procedure g_restore_registers(list : TAsmList);override; 99 100 procedure a_jmp_cond(list : TAsmList;cond : TOpCmp;l: tasmlabel); 101 procedure fixref(list : TAsmList;var ref : treference); 102 function handle_load_store(list:TAsmList;op: tasmop;oppostfix : toppostfix;reg:tregister;ref: treference):treference; virtual; 103 104 procedure g_intf_wrapper(list: TAsmList; procdef: tprocdef; const labelname: string; ioffset: longint);override; 105 procedure g_adjust_self_value(list:TAsmList;procdef: tprocdef;ioffset: tcgint); override; 106 procedure g_stackpointer_alloc(list : TAsmList;size : longint);override; 107 108 procedure a_loadmm_reg_reg(list: TAsmList; fromsize, tosize : tcgsize;reg1, reg2: tregister;shuffle : pmmshuffle); override; 109 procedure a_loadmm_ref_reg(list: TAsmList; fromsize, tosize : tcgsize;const ref: treference; reg: tregister;shuffle : pmmshuffle); override; 110 procedure a_loadmm_reg_ref(list: TAsmList; fromsize, tosize : tcgsize;reg: tregister; const ref: treference;shuffle : pmmshuffle); override; 111 procedure a_loadmm_intreg_reg(list: TAsmList; fromsize, tosize : tcgsize;intreg, mmreg: tregister; shuffle: pmmshuffle); override; 112 procedure a_loadmm_reg_intreg(list: TAsmList; fromsize, tosize : tcgsize;mmreg, intreg: tregister; shuffle : pmmshuffle); override; 113 114 procedure a_opmm_reg_reg(list: TAsmList; Op: TOpCG; size : tcgsize;src,dst: tregister;shuffle : pmmshuffle); override; 115 { Transform unsupported methods into Internal errors } 116 procedure a_bit_scan_reg_reg(list: TAsmList; reverse: boolean; size: TCGSize; src, dst: TRegister); override; 117 118 { try to generate optimized 32 Bit multiplication, returns true if successful generated } 119 function try_optimized_mul32_const_reg_reg(list: TAsmList; a: tcgint; src, dst: tregister) : boolean; 120 121 { clear out potential overflow bits from 8 or 16 bit operations } 122 { the upper 24/16 bits of a register after an operation } 123 procedure maybeadjustresult(list: TAsmList; op: TOpCg; size: tcgsize; dst: tregister); 124 function get_darwin_call_stub(const s: string; weak: boolean): tasmsymbol; 125 end; 126 127 tarmcgarm = class(tcgarm) 128 procedure init_register_allocators;override; 129 procedure done_register_allocators;override; 130 131 procedure a_load_const_reg(list : TAsmList; size: tcgsize; a : tcgint;reg : tregister);override; 132 procedure a_load_ref_reg(list : TAsmList; fromsize, tosize : tcgsize;const Ref : treference;reg : tregister);override; 133 end; 134 135 tcg64farm = class(tcg64f32) 136 procedure a_op64_reg_reg(list : TAsmList;op:TOpCG;size : tcgsize;regsrc,regdst : tregister64);override; 137 procedure a_op64_const_reg(list : TAsmList;op:TOpCG;size : tcgsize;value : int64;reg : tregister64);override; 138 procedure a_op64_const_reg_reg(list: TAsmList;op:TOpCG;size : tcgsize;value : int64;regsrc,regdst : tregister64);override; 139 procedure a_op64_reg_reg_reg(list: TAsmList;op:TOpCG;size : tcgsize;regsrc1,regsrc2,regdst : tregister64);override; 140 procedure a_op64_const_reg_reg_checkoverflow(list: TAsmList;op:TOpCG;size : tcgsize;value : int64;regsrc,regdst : tregister64;setflags : boolean;var ovloc : tlocation);override; 141 procedure a_op64_reg_reg_reg_checkoverflow(list: TAsmList;op:TOpCG;size : tcgsize;regsrc1,regsrc2,regdst : tregister64;setflags : boolean;var ovloc : tlocation);override; 142 procedure a_loadmm_intreg64_reg(list: TAsmList; mmsize: tcgsize; intreg: tregister64; mmreg: tregister);override; 143 procedure a_loadmm_reg_intreg64(list: TAsmList; mmsize: tcgsize; mmreg: tregister; intreg: tregister64);override; 144 end; 145 146 Tthumb2cgarm = class(tcgarm) 147 procedure init_register_allocators;override; 148 procedure done_register_allocators;override; 149 150 procedure a_call_reg(list : TAsmList;reg: tregister);override; 151 152 procedure a_load_const_reg(list : TAsmList; size: tcgsize; a : tcgint;reg : tregister);override; 153 procedure a_load_ref_reg(list : TAsmList; fromsize, tosize : tcgsize;const Ref : treference;reg : tregister);override; 154 155 procedure a_op_const_reg_reg_checkoverflow(list: TAsmList; op: TOpCg; size: tcgsize; a: tcgint; src, dst: tregister;setflags : boolean;var ovloc : tlocation);override; 156 procedure a_op_reg_reg_reg_checkoverflow(list: TAsmList; op: TOpCg; size: tcgsize; src1, src2, dst: tregister;setflags : boolean;var ovloc : tlocation);override; 157 158 procedure g_flags2reg(list: TAsmList; size: TCgSize; const f: TResFlags; reg: TRegister); override; 159 160 procedure g_proc_entry(list : TAsmList;localsize : longint;nostackframe:boolean);override; 161 procedure g_proc_exit(list : TAsmList;parasize : longint;nostackframe:boolean); override; 162 163 function handle_load_store(list:TAsmList;op: tasmop;oppostfix : toppostfix;reg:tregister;ref: treference):treference; override; 164 165 procedure a_loadmm_reg_reg(list: TAsmList; fromsize, tosize : tcgsize;reg1, reg2: tregister;shuffle : pmmshuffle); override; 166 procedure a_loadmm_ref_reg(list: TAsmList; fromsize, tosize : tcgsize;const ref: treference; reg: tregister;shuffle : pmmshuffle); override; 167 procedure a_loadmm_reg_ref(list: TAsmList; fromsize, tosize : tcgsize;reg: tregister; const ref: treference;shuffle : pmmshuffle); override; 168 procedure a_loadmm_intreg_reg(list: TAsmList; fromsize, tosize : tcgsize;intreg, mmreg: tregister; shuffle: pmmshuffle); override; 169 procedure a_loadmm_reg_intreg(list: TAsmList; fromsize, tosize : tcgsize;mmreg, intreg: tregister; shuffle : pmmshuffle); override; 170 end; 171 172 tthumb2cg64farm = class(tcg64farm) 173 procedure a_op64_reg_reg(list : TAsmList;op:TOpCG;size : tcgsize;regsrc,regdst : tregister64);override; 174 end; 175 176 const 177 OpCmp2AsmCond : Array[topcmp] of TAsmCond = (C_NONE,C_EQ,C_GT, 178 C_LT,C_GE,C_LE,C_NE,C_LS,C_CC,C_CS,C_HI); 179 180 winstackpagesize = 4096; 181 182 function get_fpu_postfix(def : tdef) : toppostfix; 183 procedure create_codegen; 184 185 implementation 186 187 188 uses 189 globals,verbose,systems,cutils, 190 aopt,aoptcpu, 191 fmodule, 192 symconst,symsym,symtable, 193 tgobj, 194 procinfo,cpupi, 195 paramgr; 196 197 198 function get_fpu_postfix(def : tdef) : toppostfix; 199 begin 200 if def.typ=floatdef then 201 begin 202 case tfloatdef(def).floattype of 203 s32real: 204 result:=PF_S; 205 s64real: 206 result:=PF_D; 207 s80real: 208 result:=PF_E; 209 else 210 internalerror(200401272); 211 end; 212 end 213 else 214 internalerror(200401271); 215 end; 216 217 218 procedure tarmcgarm.init_register_allocators; 219 begin 220 inherited init_register_allocators; 221 { currently, we always save R14, so we can use it } 222 if (target_info.system<>system_arm_darwin) then 223 begin 224 if assigned(current_procinfo) and (current_procinfo.framepointer<>NR_R11) then 225 rg[R_INTREGISTER]:=trgintcpu.create(R_INTREGISTER,R_SUBWHOLE, 226 [RS_R0,RS_R1,RS_R2,RS_R3,RS_R12,RS_R4,RS_R5,RS_R6,RS_R7,RS_R8, 227 RS_R9,RS_R10,RS_R11,RS_R14],first_int_imreg,[]) 228 else 229 rg[R_INTREGISTER]:=trgintcpu.create(R_INTREGISTER,R_SUBWHOLE, 230 [RS_R0,RS_R1,RS_R2,RS_R3,RS_R12,RS_R4,RS_R5,RS_R6,RS_R7,RS_R8, 231 RS_R9,RS_R10,RS_R14],first_int_imreg,[]) 232 end 233 else 234 { r7 is not available on Darwin, it's used as frame pointer (always, 235 for backtrace support -- also in gcc/clang -> R11 can be used). 236 r9 is volatile } 237 rg[R_INTREGISTER]:=trgintcpu.create(R_INTREGISTER,R_SUBWHOLE, 238 [RS_R0,RS_R1,RS_R2,RS_R3,RS_R9,RS_R12,RS_R4,RS_R5,RS_R6,RS_R8, 239 RS_R10,RS_R11,RS_R14],first_int_imreg,[]); 240 rg[R_FPUREGISTER]:=trgcpu.create(R_FPUREGISTER,R_SUBNONE, 241 [RS_F0,RS_F1,RS_F2,RS_F3,RS_F4,RS_F5,RS_F6,RS_F7],first_fpu_imreg,[]); 242 { The register allocator currently cannot deal with multiple 243 non-overlapping subregs per register, so we can only use 244 half the single precision registers for now (as sub registers of the 245 double precision ones). } 246 if current_settings.fputype=fpu_vfpv3 then 247 rg[R_MMREGISTER]:=trgcpu.create(R_MMREGISTER,R_SUBFD, 248 [RS_D0,RS_D1,RS_D2,RS_D3,RS_D4,RS_D5,RS_D6,RS_D7, 249 RS_D16,RS_D17,RS_D18,RS_D19,RS_D20,RS_D21,RS_D22,RS_D23,RS_D24,RS_D25,RS_D26,RS_D27,RS_D28,RS_D29,RS_D30,RS_D31, 250 RS_D8,RS_D9,RS_D10,RS_D11,RS_D12,RS_D13,RS_D14,RS_D15 251 ],first_mm_imreg,[]) 252 else 253 rg[R_MMREGISTER]:=trgcpu.create(R_MMREGISTER,R_SUBFD, 254 [RS_D0,RS_D1,RS_D2,RS_D3,RS_D4,RS_D5,RS_D6,RS_D7,RS_D8,RS_D9,RS_D10,RS_D11,RS_D12,RS_D13,RS_D14,RS_D15],first_mm_imreg,[]); 255 end; 256 257 258 procedure tarmcgarm.done_register_allocators; 259 begin 260 rg[R_INTREGISTER].free; 261 rg[R_FPUREGISTER].free; 262 rg[R_MMREGISTER].free; 263 inherited done_register_allocators; 264 end; 265 266 267 procedure tarmcgarm.a_load_const_reg(list : TAsmList; size: tcgsize; a : tcgint;reg : tregister); 268 var 269 imm_shift : byte; 270 l : tasmlabel; 271 hr : treference; 272 imm1, imm2: DWord; 273 begin 274 if not(size in [OS_8,OS_S8,OS_16,OS_S16,OS_32,OS_S32]) then 275 internalerror(2002090902); 276 if is_shifter_const(a,imm_shift) then 277 list.concat(taicpu.op_reg_const(A_MOV,reg,a)) 278 else if is_shifter_const(not(a),imm_shift) then 279 list.concat(taicpu.op_reg_const(A_MVN,reg,not(a))) 280 { loading of constants with mov and orr } 281 else if (split_into_shifter_const(a,imm1, imm2)) then 282 begin 283 list.concat(taicpu.op_reg_const(A_MOV,reg, imm1)); 284 list.concat(taicpu.op_reg_reg_const(A_ORR,reg,reg, imm2)); 285 end 286 { loading of constants with mvn and bic } 287 else if (split_into_shifter_const(not(a), imm1, imm2)) then 288 begin 289 list.concat(taicpu.op_reg_const(A_MVN,reg, imm1)); 290 list.concat(taicpu.op_reg_reg_const(A_BIC,reg,reg, imm2)); 291 end 292 else 293 begin 294 reference_reset(hr,4); 295 296 current_asmdata.getjumplabel(l); 297 cg.a_label(current_procinfo.aktlocaldata,l); 298 hr.symboldata:=current_procinfo.aktlocaldata.last; 299 current_procinfo.aktlocaldata.concat(tai_const.Create_32bit(longint(a))); 300 301 hr.symbol:=l; 302 hr.base:=NR_PC; 303 list.concat(taicpu.op_reg_ref(A_LDR,reg,hr)); 304 end; 305 end; 306 307 308 procedure tarmcgarm.a_load_ref_reg(list : TAsmList; fromsize, tosize : tcgsize;const Ref : treference;reg : tregister); 309 var 310 oppostfix:toppostfix; 311 usedtmpref: treference; 312 tmpreg,tmpreg2 : tregister; 313 so : tshifterop; 314 dir : integer; 315 begin 316 if (TCGSize2Size[FromSize] >= TCGSize2Size[ToSize]) then 317 FromSize := ToSize; 318 case FromSize of 319 { signed integer registers } 320 OS_8: 321 oppostfix:=PF_B; 322 OS_S8: 323 oppostfix:=PF_SB; 324 OS_16: 325 oppostfix:=PF_H; 326 OS_S16: 327 oppostfix:=PF_SH; 328 OS_32, 329 OS_S32: 330 oppostfix:=PF_None; 331 else 332 InternalError(200308297); 333 end; 334 if (ref.alignment in [1,2]) and (ref.alignment<tcgsize2size[fromsize]) then 335 begin 336 if target_info.endian=endian_big then 337 dir:=-1 338 else 339 dir:=1; 340 case FromSize of 341 OS_16,OS_S16: 342 begin 343 { only complicated references need an extra loadaddr } 344 if assigned(ref.symbol) or 345 (ref.index<>NR_NO) or 346 (ref.offset<-4095) or 347 (ref.offset>4094) or 348 { sometimes the compiler reused registers } 349 (reg=ref.index) or 350 (reg=ref.base) then 351 begin 352 tmpreg2:=getintregister(list,OS_INT); 353 a_loadaddr_ref_reg(list,ref,tmpreg2); 354 reference_reset_base(usedtmpref,tmpreg2,0,ref.alignment); 355 end 356 else 357 usedtmpref:=ref; 358 359 if target_info.endian=endian_big then 360 inc(usedtmpref.offset,1); 361 shifterop_reset(so);so.shiftmode:=SM_LSL;so.shiftimm:=8; 362 tmpreg:=getintregister(list,OS_INT); 363 a_internal_load_ref_reg(list,OS_8,OS_8,usedtmpref,reg); 364 inc(usedtmpref.offset,dir); 365 if FromSize=OS_16 then 366 a_internal_load_ref_reg(list,OS_8,OS_8,usedtmpref,tmpreg) 367 else 368 a_internal_load_ref_reg(list,OS_S8,OS_S8,usedtmpref,tmpreg); 369 list.concat(taicpu.op_reg_reg_reg_shifterop(A_ORR,reg,reg,tmpreg,so)); 370 end; 371 OS_32,OS_S32: 372 begin 373 tmpreg:=getintregister(list,OS_INT); 374 375 { only complicated references need an extra loadaddr } 376 if assigned(ref.symbol) or 377 (ref.index<>NR_NO) or 378 (ref.offset<-4095) or 379 (ref.offset>4092) or 380 { sometimes the compiler reused registers } 381 (reg=ref.index) or 382 (reg=ref.base) then 383 begin 384 tmpreg2:=getintregister(list,OS_INT); 385 a_loadaddr_ref_reg(list,ref,tmpreg2); 386 reference_reset_base(usedtmpref,tmpreg2,0,ref.alignment); 387 end 388 else 389 usedtmpref:=ref; 390 391 shifterop_reset(so);so.shiftmode:=SM_LSL; 392 if ref.alignment=2 then 393 begin 394 if target_info.endian=endian_big then 395 inc(usedtmpref.offset,2); 396 a_internal_load_ref_reg(list,OS_16,OS_16,usedtmpref,reg); 397 inc(usedtmpref.offset,dir*2); 398 a_internal_load_ref_reg(list,OS_16,OS_16,usedtmpref,tmpreg); 399 so.shiftimm:=16; 400 list.concat(taicpu.op_reg_reg_reg_shifterop(A_ORR,reg,reg,tmpreg,so)); 401 end 402 else 403 begin 404 tmpreg2:=getintregister(list,OS_INT); 405 if target_info.endian=endian_big then 406 inc(usedtmpref.offset,3); 407 a_internal_load_ref_reg(list,OS_8,OS_8,usedtmpref,reg); 408 409 inc(usedtmpref.offset,dir); 410 a_internal_load_ref_reg(list,OS_8,OS_8,usedtmpref,tmpreg); 411 412 inc(usedtmpref.offset,dir); 413 a_internal_load_ref_reg(list,OS_8,OS_8,usedtmpref,tmpreg2); 414 415 so.shiftimm:=8; 416 list.concat(taicpu.op_reg_reg_reg_shifterop(A_ORR,reg,reg,tmpreg,so)); 417 418 inc(usedtmpref.offset,dir); 419 a_internal_load_ref_reg(list,OS_8,OS_8,usedtmpref,tmpreg); 420 421 so.shiftimm:=16; 422 list.concat(taicpu.op_reg_reg_reg_shifterop(A_ORR,reg,reg,tmpreg2,so)); 423 424 so.shiftimm:=24; 425 list.concat(taicpu.op_reg_reg_reg_shifterop(A_ORR,reg,reg,tmpreg,so)); 426 end; 427 end 428 else 429 handle_load_store(list,A_LDR,oppostfix,reg,ref); 430 end; 431 end 432 else 433 handle_load_store(list,A_LDR,oppostfix,reg,ref); 434 435 if (fromsize=OS_S8) and (tosize = OS_16) then 436 a_load_reg_reg(list,OS_16,OS_32,reg,reg); 437 end; 438 439 440 procedure tcgarm.a_load_const_cgpara(list : TAsmList;size : tcgsize;a : tcgint;const paraloc : TCGPara); 441 var 442 ref: treference; 443 begin 444 paraloc.check_simple_location; 445 paramanager.allocparaloc(list,paraloc.location); 446 case paraloc.location^.loc of 447 LOC_REGISTER,LOC_CREGISTER: 448 a_load_const_reg(list,size,a,paraloc.location^.register); 449 LOC_REFERENCE: 450 begin 451 reference_reset(ref,paraloc.alignment); 452 ref.base:=paraloc.location^.reference.index; 453 ref.offset:=paraloc.location^.reference.offset; 454 a_load_const_ref(list,size,a,ref); 455 end; 456 else 457 internalerror(2002081101); 458 end; 459 end; 460 461 462 procedure tcgarm.a_load_ref_cgpara(list : TAsmList;size : tcgsize;const r : treference;const paraloc : TCGPara); 463 var 464 tmpref, ref: treference; 465 location: pcgparalocation; 466 sizeleft: aint; 467 begin 468 location := paraloc.location; 469 tmpref := r; 470 sizeleft := paraloc.intsize; 471 while assigned(location) do 472 begin 473 paramanager.allocparaloc(list,location); 474 case location^.loc of 475 LOC_REGISTER,LOC_CREGISTER: 476 a_load_ref_reg(list,location^.size,location^.size,tmpref,location^.register); 477 LOC_REFERENCE: 478 begin 479 reference_reset_base(ref,location^.reference.index,location^.reference.offset,paraloc.alignment); 480 { doubles in softemu mode have a strange order of registers and references } 481 if location^.size=OS_32 then 482 g_concatcopy(list,tmpref,ref,4) 483 else 484 begin 485 g_concatcopy(list,tmpref,ref,sizeleft); 486 if assigned(location^.next) then 487 internalerror(2005010710); 488 end; 489 end; 490 LOC_FPUREGISTER,LOC_CFPUREGISTER: 491 case location^.size of 492 OS_F32, OS_F64: 493 a_loadfpu_ref_reg(list,location^.size,location^.size,tmpref,location^.register); 494 else 495 internalerror(2002072801); 496 end; 497 LOC_VOID: 498 begin 499 // nothing to do 500 end; 501 else 502 internalerror(2002081103); 503 end; 504 inc(tmpref.offset,tcgsize2size[location^.size]); 505 dec(sizeleft,tcgsize2size[location^.size]); 506 location := location^.next; 507 end; 508 end; 509 510 511 procedure tcgarm.a_loadaddr_ref_cgpara(list : TAsmList;const r : treference;const paraloc : TCGPara); 512 var 513 ref: treference; 514 tmpreg: tregister; 515 begin 516 paraloc.check_simple_location; 517 paramanager.allocparaloc(list,paraloc.location); 518 case paraloc.location^.loc of 519 LOC_REGISTER,LOC_CREGISTER: 520 a_loadaddr_ref_reg(list,r,paraloc.location^.register); 521 LOC_REFERENCE: 522 begin 523 reference_reset(ref,paraloc.alignment); 524 ref.base := paraloc.location^.reference.index; 525 ref.offset := paraloc.location^.reference.offset; 526 tmpreg := getintregister(list,OS_ADDR); 527 a_loadaddr_ref_reg(list,r,tmpreg); 528 a_load_reg_ref(list,OS_ADDR,OS_ADDR,tmpreg,ref); 529 end; 530 else 531 internalerror(2002080701); 532 end; 533 end; 534 535 536 procedure tcgarm.a_call_name(list : TAsmList;const s : string; weak: boolean); 537 var 538 branchopcode: tasmop; 539 begin 540 { check not really correct: should only be used for non-Thumb cpus } 541 if CPUARM_HAS_BLX_LABEL in cpu_capabilities[current_settings.cputype] then 542 branchopcode:=A_BLX 543 else 544 branchopcode:=A_BL; 545 if target_info.system<>system_arm_darwin then 546 if not weak then 547 list.concat(taicpu.op_sym(branchopcode,current_asmdata.RefAsmSymbol(s))) 548 else 549 list.concat(taicpu.op_sym(branchopcode,current_asmdata.WeakRefAsmSymbol(s))) 550 else 551 list.concat(taicpu.op_sym(branchopcode,get_darwin_call_stub(s,weak))); 552{ 553 the compiler does not properly set this flag anymore in pass 1, and 554 for now we only need it after pass 2 (I hope) (JM) 555 if not(pi_do_call in current_procinfo.flags) then 556 internalerror(2003060703); 557} 558 include(current_procinfo.flags,pi_do_call); 559 end; 560 561 562 procedure tcgarm.a_call_reg(list : TAsmList;reg: tregister); 563 begin 564 { check not really correct: should only be used for non-Thumb cpus } 565 if not(CPUARM_HAS_BLX in cpu_capabilities[current_settings.cputype]) then 566 begin 567 list.concat(taicpu.op_reg_reg(A_MOV,NR_R14,NR_PC)); 568 list.concat(taicpu.op_reg_reg(A_MOV,NR_PC,reg)); 569 end 570 else 571 list.concat(taicpu.op_reg(A_BLX, reg)); 572{ 573 the compiler does not properly set this flag anymore in pass 1, and 574 for now we only need it after pass 2 (I hope) (JM) 575 if not(pi_do_call in current_procinfo.flags) then 576 internalerror(2003060703); 577} 578 include(current_procinfo.flags,pi_do_call); 579 end; 580 581 582 procedure tcgarm.a_call_ref(list : TAsmList;ref: treference); 583 begin 584 a_reg_alloc(list,NR_R12); 585 a_load_ref_reg(list,OS_ADDR,OS_ADDR,ref,NR_R12); 586 a_call_reg(list,NR_R12); 587 a_reg_dealloc(list,NR_R12); 588 include(current_procinfo.flags,pi_do_call); 589 end; 590 591 592 procedure tcgarm.a_op_const_reg(list : TAsmList; Op: TOpCG; size: TCGSize; a: tcgint; reg: TRegister); 593 begin 594 a_op_const_reg_reg(list,op,size,a,reg,reg); 595 end; 596 597 598 procedure tcgarm.a_op_reg_reg(list : TAsmList; Op: TOpCG; size: TCGSize; src, dst: TRegister); 599 var 600 so : tshifterop; 601 begin 602 if op = OP_NEG then 603 list.concat(taicpu.op_reg_reg_const(A_RSB,dst,src,0)) 604 else if op = OP_NOT then 605 begin 606 if size in [OS_8, OS_16, OS_S8, OS_S16] then 607 begin 608 shifterop_reset(so); 609 so.shiftmode:=SM_LSL; 610 if size in [OS_8, OS_S8] then 611 so.shiftimm:=24 612 else 613 so.shiftimm:=16; 614 list.concat(taicpu.op_reg_reg_shifterop(A_MVN,dst,src,so)); 615 {Using a shift here allows this to be folded into another instruction} 616 if size in [OS_S8, OS_S16] then 617 so.shiftmode:=SM_ASR 618 else 619 so.shiftmode:=SM_LSR; 620 list.concat(taicpu.op_reg_reg_shifterop(A_MOV,dst,dst,so)); 621 end 622 else 623 list.concat(taicpu.op_reg_reg(A_MVN,dst,src)); 624 end 625 else 626 a_op_reg_reg_reg(list,op,OS_32,src,dst,dst); 627 end; 628 629 630 const 631 op_reg_reg_opcg2asmop: array[TOpCG] of tasmop = 632 (A_NONE,A_MOV,A_ADD,A_AND,A_NONE,A_NONE,A_MUL,A_MUL,A_NONE,A_NONE,A_ORR, 633 A_NONE,A_NONE,A_NONE,A_SUB,A_EOR,A_NONE,A_NONE); 634 635 636 procedure tcgarm.a_op_const_reg_reg(list: TAsmList; op: TOpCg; 637 size: tcgsize; a: tcgint; src, dst: tregister); 638 var 639 ovloc : tlocation; 640 begin 641 a_op_const_reg_reg_checkoverflow(list,op,size,a,src,dst,false,ovloc); 642 end; 643 644 645 procedure tcgarm.a_op_reg_reg_reg(list: TAsmList; op: TOpCg; 646 size: tcgsize; src1, src2, dst: tregister); 647 var 648 ovloc : tlocation; 649 begin 650 a_op_reg_reg_reg_checkoverflow(list,op,size,src1,src2,dst,false,ovloc); 651 end; 652 653 function opshift2shiftmode(op: TOpCg): tshiftmode; 654 begin 655 case op of 656 OP_SHL: Result:=SM_LSL; 657 OP_SHR: Result:=SM_LSR; 658 OP_ROR: Result:=SM_ROR; 659 OP_ROL: Result:=SM_ROR; 660 OP_SAR: Result:=SM_ASR; 661 else internalerror(2012070501); 662 end 663 end; 664 665 666 function tcgarm.try_optimized_mul32_const_reg_reg(list: TAsmList; a: tcgint; src, dst: tregister) : boolean; 667 var 668 multiplier : dword; 669 power : longint; 670 shifterop : tshifterop; 671 bitsset : byte; 672 negative : boolean; 673 first : boolean; 674 b, 675 cycles : byte; 676 maxeffort : byte; 677 begin 678 result:=true; 679 cycles:=0; 680 negative:=a<0; 681 shifterop.rs:=NR_NO; 682 shifterop.shiftmode:=SM_LSL; 683 if negative then 684 inc(cycles); 685 multiplier:=dword(abs(a)); 686 bitsset:=popcnt(multiplier and $fffffffe); 687 688 { heuristics to estimate how much instructions are reasonable to replace the mul, 689 this is currently based on XScale timings } 690 { in the simplest case, we need a mov to load the constant and a mul to carry out the 691 actual multiplication, this requires min. 1+4 cycles 692 693 because the first shift imm. might cause a stall and because we need more instructions 694 when replacing the mul we generate max. 3 instructions to replace this mul } 695 maxeffort:=3; 696 697 { if the constant is not a shifter op, we need either some mov/mvn/bic/or sequence or 698 a ldr, so generating one more operation to replace this is beneficial } 699 if not(is_shifter_const(dword(a),b)) and not(is_shifter_const(not(dword(a)),b)) then 700 inc(maxeffort); 701 702 { if the upper 5 bits are all set or clear, mul is one cycle faster } 703 if ((dword(a) and $f8000000)=0) or ((dword(a) and $f8000000)=$f8000000) then 704 dec(maxeffort); 705 706 { if the upper 17 bits are all set or clear, mul is another cycle faster } 707 if ((dword(a) and $ffff8000)=0) or ((dword(a) and $ffff8000)=$ffff8000) then 708 dec(maxeffort); 709 710 { most simple cases } 711 if a=1 then 712 a_load_reg_reg(list,OS_32,OS_32,src,dst) 713 else if a=0 then 714 a_load_const_reg(list,OS_32,0,dst) 715 else if a=-1 then 716 a_op_reg_reg(list,OP_NEG,OS_32,src,dst) 717 { add up ? 718 719 basically, one add is needed for each bit being set in the constant factor 720 however, the least significant bit is for free, it can be hidden in the initial 721 instruction 722 } 723 else if (bitsset+cycles<=maxeffort) and 724 (bitsset<=popcnt(dword(nextpowerof2(multiplier,power)-multiplier) and $fffffffe)) then 725 begin 726 first:=true; 727 while multiplier<>0 do 728 begin 729 shifterop.shiftimm:=BsrDWord(multiplier); 730 if odd(multiplier) then 731 begin 732 list.concat(taicpu.op_reg_reg_reg_shifterop(A_ADD,dst,src,src,shifterop)); 733 dec(multiplier); 734 end 735 else 736 if first then 737 list.concat(taicpu.op_reg_reg_shifterop(A_MOV,dst,src,shifterop)) 738 else 739 list.concat(taicpu.op_reg_reg_reg_shifterop(A_ADD,dst,dst,src,shifterop)); 740 first:=false; 741 dec(multiplier,1 shl shifterop.shiftimm); 742 end; 743 if negative then 744 list.concat(taicpu.op_reg_reg_const(A_RSB,dst,dst,0)); 745 end 746 { subtract from the next greater power of two? } 747 else if popcnt(dword(nextpowerof2(multiplier,power)-multiplier) and $fffffffe)+cycles+1<=maxeffort then 748 begin 749 first:=true; 750 while multiplier<>0 do 751 begin 752 if first then 753 begin 754 multiplier:=(1 shl power)-multiplier; 755 shifterop.shiftimm:=power; 756 end 757 else 758 shifterop.shiftimm:=BsrDWord(multiplier); 759 760 if odd(multiplier) then 761 begin 762 list.concat(taicpu.op_reg_reg_reg_shifterop(A_RSB,dst,src,src,shifterop)); 763 dec(multiplier); 764 end 765 else 766 if first then 767 list.concat(taicpu.op_reg_reg_shifterop(A_MOV,dst,src,shifterop)) 768 else 769 begin 770 list.concat(taicpu.op_reg_reg_reg_shifterop(A_SUB,dst,dst,src,shifterop)); 771 dec(multiplier,1 shl shifterop.shiftimm); 772 end; 773 first:=false; 774 end; 775 if negative then 776 list.concat(taicpu.op_reg_reg_const(A_RSB,dst,dst,0)); 777 end 778 else 779 result:=false; 780 end; 781 782 783 procedure tcgarm.a_op_const_reg_reg_checkoverflow(list: TAsmList; op: TOpCg; size: tcgsize; a: tcgint; src, dst: tregister;setflags : boolean;var ovloc : tlocation); 784 var 785 shift : byte; 786 tmpreg : tregister; 787 so : tshifterop; 788 l1 : longint; 789 imm1, imm2: DWord; 790 791 792 begin 793 ovloc.loc:=LOC_VOID; 794 if {$ifopt R+}(a<>-2147483648) and{$endif} not setflags and is_shifter_const(-a,shift) then 795 case op of 796 OP_ADD: 797 begin 798 op:=OP_SUB; 799 a:=aint(dword(-a)); 800 end; 801 OP_SUB: 802 begin 803 op:=OP_ADD; 804 a:=aint(dword(-a)); 805 end 806 end; 807 808 if is_shifter_const(a,shift) and not(op in [OP_IMUL,OP_MUL]) then 809 case op of 810 OP_NEG,OP_NOT: 811 internalerror(200308281); 812 OP_SHL, 813 OP_SHR, 814 OP_ROL, 815 OP_ROR, 816 OP_SAR: 817 begin 818 if a>32 then 819 internalerror(200308294); 820 if a<>0 then 821 begin 822 shifterop_reset(so); 823 so.shiftmode:=opshift2shiftmode(op); 824 if op = OP_ROL then 825 so.shiftimm:=32-a 826 else 827 so.shiftimm:=a; 828 list.concat(taicpu.op_reg_reg_shifterop(A_MOV,dst,src,so)); 829 end 830 else 831 list.concat(taicpu.op_reg_reg(A_MOV,dst,src)); 832 end; 833 else 834 {if (op in [OP_SUB, OP_ADD]) and 835 ((a < 0) or 836 (a > 4095)) then 837 begin 838 tmpreg:=getintregister(list,size); 839 list.concat(taicpu.op_reg_const(A_MOVT, tmpreg, (a shr 16) and $FFFF)); 840 list.concat(taicpu.op_reg_const(A_MOV, tmpreg, a and $FFFF)); 841 list.concat(setoppostfix(taicpu.op_reg_reg_reg(op_reg_reg_opcg2asmop[op],dst,src,tmpreg),toppostfix(ord(cgsetflags or setflags)*ord(PF_S)) 842 )); 843 end 844 else} 845 begin 846 if cgsetflags or setflags then 847 a_reg_alloc(list,NR_DEFAULTFLAGS); 848 list.concat(setoppostfix( 849 taicpu.op_reg_reg_const(op_reg_reg_opcg2asmop[op],dst,src,a),toppostfix(ord(cgsetflags or setflags)*ord(PF_S)))); 850 end; 851 if (cgsetflags or setflags) and (size in [OS_8,OS_16,OS_32]) then 852 begin 853 ovloc.loc:=LOC_FLAGS; 854 case op of 855 OP_ADD: 856 ovloc.resflags:=F_CS; 857 OP_SUB: 858 ovloc.resflags:=F_CC; 859 end; 860 end; 861 end 862 else 863 begin 864 { there could be added some more sophisticated optimizations } 865 if (op in [OP_MUL,OP_IMUL,OP_DIV,OP_IDIV]) and (a=1) then 866 a_load_reg_reg(list,size,size,src,dst) 867 else if (op in [OP_MUL,OP_IMUL]) and (a=0) then 868 a_load_const_reg(list,size,0,dst) 869 else if (op in [OP_IMUL,OP_IDIV]) and (a=-1) then 870 a_op_reg_reg(list,OP_NEG,size,src,dst) 871 { we do this here instead in the peephole optimizer because 872 it saves us a register } 873 else if (op in [OP_MUL,OP_IMUL]) and ispowerof2(a,l1) and not(cgsetflags or setflags) then 874 a_op_const_reg_reg(list,OP_SHL,size,l1,src,dst) 875 { for example : b=a*5 -> b=a*4+a with add instruction and shl } 876 else if (op in [OP_MUL,OP_IMUL]) and ispowerof2(a-1,l1) and not(cgsetflags or setflags) then 877 begin 878 if l1>32 then{roozbeh does this ever happen?} 879 internalerror(200308296); 880 shifterop_reset(so); 881 so.shiftmode:=SM_LSL; 882 so.shiftimm:=l1; 883 list.concat(taicpu.op_reg_reg_reg_shifterop(A_ADD,dst,src,src,so)); 884 end 885 { for example : b=a*7 -> b=a*8-a with rsb instruction and shl } 886 else if (op in [OP_MUL,OP_IMUL]) and ispowerof2(a+1,l1) and not(cgsetflags or setflags) then 887 begin 888 if l1>32 then{does this ever happen?} 889 internalerror(201205181); 890 shifterop_reset(so); 891 so.shiftmode:=SM_LSL; 892 so.shiftimm:=l1; 893 list.concat(taicpu.op_reg_reg_reg_shifterop(A_RSB,dst,src,src,so)); 894 end 895 else if (op in [OP_MUL,OP_IMUL]) and not(cgsetflags or setflags) and try_optimized_mul32_const_reg_reg(list,a,src,dst) then 896 begin 897 { nothing to do on success } 898 end 899 { x := y and 0; just clears a register, this sometimes gets generated on 64bit ops. 900 Just using mov x, #0 might allow some easier optimizations down the line. } 901 else if (op = OP_AND) and (dword(a)=0) then 902 list.concat(taicpu.op_reg_const(A_MOV,dst,0)) 903 { x := y AND $FFFFFFFF just copies the register, so use mov for better optimizations } 904 else if (op = OP_AND) and (not(dword(a))=0) then 905 list.concat(taicpu.op_reg_reg(A_MOV,dst,src)) 906 { BIC clears the specified bits, while AND keeps them, using BIC allows to use a 907 broader range of shifterconstants.} 908 else if (op = OP_AND) and is_shifter_const(not(dword(a)),shift) then 909 list.concat(taicpu.op_reg_reg_const(A_BIC,dst,src,not(dword(a)))) 910 else if (op = OP_AND) and split_into_shifter_const(not(dword(a)), imm1, imm2) then 911 begin 912 list.concat(taicpu.op_reg_reg_const(A_BIC,dst,src,imm1)); 913 list.concat(taicpu.op_reg_reg_const(A_BIC,dst,dst,imm2)); 914 end 915 else if (op in [OP_ADD, OP_SUB, OP_OR]) and 916 not(cgsetflags or setflags) and 917 split_into_shifter_const(a, imm1, imm2) then 918 begin 919 list.concat(taicpu.op_reg_reg_const(op_reg_reg_opcg2asmop[op],dst,src,imm1)); 920 list.concat(taicpu.op_reg_reg_const(op_reg_reg_opcg2asmop[op],dst,dst,imm2)); 921 end 922 else 923 begin 924 tmpreg:=getintregister(list,size); 925 a_load_const_reg(list,size,a,tmpreg); 926 a_op_reg_reg_reg_checkoverflow(list,op,size,tmpreg,src,dst,setflags,ovloc); 927 end; 928 end; 929 maybeadjustresult(list,op,size,dst); 930 end; 931 932 933 procedure tcgarm.a_op_reg_reg_reg_checkoverflow(list: TAsmList; op: TOpCg; size: tcgsize; src1, src2, dst: tregister;setflags : boolean;var ovloc : tlocation); 934 var 935 so : tshifterop; 936 tmpreg,overflowreg : tregister; 937 asmop : tasmop; 938 begin 939 ovloc.loc:=LOC_VOID; 940 case op of 941 OP_NEG,OP_NOT, 942 OP_DIV,OP_IDIV: 943 internalerror(200308281); 944 OP_SHL, 945 OP_SHR, 946 OP_SAR, 947 OP_ROR: 948 begin 949 if (op = OP_ROR) and not(size in [OS_32,OS_S32]) then 950 internalerror(2008072801); 951 shifterop_reset(so); 952 so.rs:=src1; 953 so.shiftmode:=opshift2shiftmode(op); 954 list.concat(taicpu.op_reg_reg_shifterop(A_MOV,dst,src2,so)); 955 end; 956 OP_ROL: 957 begin 958 if not(size in [OS_32,OS_S32]) then 959 internalerror(2008072801); 960 { simulate ROL by ror'ing 32-value } 961 tmpreg:=getintregister(list,OS_32); 962 list.concat(taicpu.op_reg_reg_const(A_RSB,tmpreg,src1, 32)); 963 shifterop_reset(so); 964 so.rs:=tmpreg; 965 so.shiftmode:=SM_ROR; 966 list.concat(taicpu.op_reg_reg_shifterop(A_MOV,dst,src2,so)); 967 end; 968 OP_IMUL, 969 OP_MUL: 970 begin 971 if cgsetflags or setflags then 972 begin 973 overflowreg:=getintregister(list,size); 974 if op=OP_IMUL then 975 asmop:=A_SMULL 976 else 977 asmop:=A_UMULL; 978 { the arm doesn't allow that rd and rm are the same } 979 if dst=src2 then 980 begin 981 if dst<>src1 then 982 list.concat(taicpu.op_reg_reg_reg_reg(asmop,dst,overflowreg,src1,src2)) 983 else 984 begin 985 tmpreg:=getintregister(list,size); 986 a_load_reg_reg(list,size,size,src2,dst); 987 list.concat(taicpu.op_reg_reg_reg_reg(asmop,dst,overflowreg,tmpreg,src1)); 988 end; 989 end 990 else 991 list.concat(taicpu.op_reg_reg_reg_reg(asmop,dst,overflowreg,src2,src1)); 992 a_reg_alloc(list,NR_DEFAULTFLAGS); 993 if op=OP_IMUL then 994 begin 995 shifterop_reset(so); 996 so.shiftmode:=SM_ASR; 997 so.shiftimm:=31; 998 list.concat(taicpu.op_reg_reg_shifterop(A_CMP,overflowreg,dst,so)); 999 end 1000 else 1001 list.concat(taicpu.op_reg_const(A_CMP,overflowreg,0)); 1002 1003 ovloc.loc:=LOC_FLAGS; 1004 ovloc.resflags:=F_NE; 1005 end 1006 else 1007 begin 1008 { the arm doesn't allow that rd and rm are the same } 1009 if dst=src2 then 1010 begin 1011 if dst<>src1 then 1012 list.concat(taicpu.op_reg_reg_reg(A_MUL,dst,src1,src2)) 1013 else 1014 begin 1015 tmpreg:=getintregister(list,size); 1016 a_load_reg_reg(list,size,size,src2,dst); 1017 list.concat(taicpu.op_reg_reg_reg(A_MUL,dst,tmpreg,src1)); 1018 end; 1019 end 1020 else 1021 list.concat(taicpu.op_reg_reg_reg(A_MUL,dst,src2,src1)); 1022 end; 1023 end; 1024 else 1025 begin 1026 if cgsetflags or setflags then 1027 a_reg_alloc(list,NR_DEFAULTFLAGS); 1028 list.concat(setoppostfix( 1029 taicpu.op_reg_reg_reg(op_reg_reg_opcg2asmop[op],dst,src2,src1),toppostfix(ord(cgsetflags or setflags)*ord(PF_S)))); 1030 end; 1031 end; 1032 maybeadjustresult(list,op,size,dst); 1033 end; 1034 1035 1036 function tcgarm.handle_load_store(list:TAsmList;op: tasmop;oppostfix : toppostfix;reg:tregister;ref: treference):treference; 1037 var 1038 tmpreg : tregister; 1039 tmpref : treference; 1040 l : tasmlabel; 1041 begin 1042 tmpreg:=NR_NO; 1043 1044 { Be sure to have a base register } 1045 if (ref.base=NR_NO) then 1046 begin 1047 if ref.shiftmode<>SM_None then 1048 internalerror(200308294); 1049 ref.base:=ref.index; 1050 ref.index:=NR_NO; 1051 end; 1052 1053 { absolute symbols can't be handled directly, we've to store the symbol reference 1054 in the text segment and access it pc relative 1055 1056 For now, we assume that references where base or index equals to PC are already 1057 relative, all other references are assumed to be absolute and thus they need 1058 to be handled extra. 1059 1060 A proper solution would be to change refoptions to a set and store the information 1061 if the symbol is absolute or relative there. 1062 } 1063 1064 if (assigned(ref.symbol) and 1065 not(is_pc(ref.base)) and 1066 not(is_pc(ref.index)) 1067 ) or 1068 { [#xxx] isn't a valid address operand } 1069 ((ref.base=NR_NO) and (ref.index=NR_NO)) or 1070 (ref.offset<-4095) or 1071 (ref.offset>4095) or 1072 ((oppostfix in [PF_SB,PF_H,PF_SH]) and 1073 ((ref.offset<-255) or 1074 (ref.offset>255) 1075 ) 1076 ) or 1077 ((op in [A_LDF,A_STF,A_FLDS,A_FLDD,A_FSTS,A_FSTD]) and 1078 ((ref.offset<-1020) or 1079 (ref.offset>1020) or 1080 ((abs(ref.offset) mod 4)<>0) 1081 ) 1082 ) then 1083 begin 1084 fixref(list,ref); 1085 end; 1086 1087 { fold if there is base, index and offset, however, don't fold 1088 for vfp memory instructions because we later fold the index } 1089 if not(op in [A_FLDS,A_FLDD,A_FSTS,A_FSTD]) and 1090 (ref.base<>NR_NO) and (ref.index<>NR_NO) and (ref.offset<>0) then 1091 begin 1092 if tmpreg<>NR_NO then 1093 a_op_const_reg_reg(list,OP_ADD,OS_ADDR,ref.offset,tmpreg,tmpreg) 1094 else 1095 begin 1096 tmpreg:=getintregister(list,OS_ADDR); 1097 a_op_const_reg_reg(list,OP_ADD,OS_ADDR,ref.offset,ref.base,tmpreg); 1098 ref.base:=tmpreg; 1099 end; 1100 ref.offset:=0; 1101 end; 1102 1103 { floating point operations have only limited references 1104 we expect here, that a base is already set } 1105 if (op in [A_LDF,A_STF,A_FLDS,A_FLDD,A_FSTS,A_FSTD]) and (ref.index<>NR_NO) then 1106 begin 1107 if ref.shiftmode<>SM_none then 1108 internalerror(200309121); 1109 if tmpreg<>NR_NO then 1110 begin 1111 if ref.base=tmpreg then 1112 begin 1113 if ref.signindex<0 then 1114 list.concat(taicpu.op_reg_reg_reg(A_SUB,tmpreg,tmpreg,ref.index)) 1115 else 1116 list.concat(taicpu.op_reg_reg_reg(A_ADD,tmpreg,tmpreg,ref.index)); 1117 ref.index:=NR_NO; 1118 end 1119 else 1120 begin 1121 if ref.index<>tmpreg then 1122 internalerror(200403161); 1123 if ref.signindex<0 then 1124 list.concat(taicpu.op_reg_reg_reg(A_SUB,tmpreg,ref.base,tmpreg)) 1125 else 1126 list.concat(taicpu.op_reg_reg_reg(A_ADD,tmpreg,ref.base,tmpreg)); 1127 ref.base:=tmpreg; 1128 ref.index:=NR_NO; 1129 end; 1130 end 1131 else 1132 begin 1133 tmpreg:=getintregister(list,OS_ADDR); 1134 list.concat(taicpu.op_reg_reg_reg(A_ADD,tmpreg,ref.base,ref.index)); 1135 ref.base:=tmpreg; 1136 ref.index:=NR_NO; 1137 end; 1138 end; 1139 list.concat(setoppostfix(taicpu.op_reg_ref(op,reg,ref),oppostfix)); 1140 Result := ref; 1141 end; 1142 1143 1144 procedure tcgarm.a_load_reg_ref(list : TAsmList; fromsize, tosize: tcgsize; reg : tregister;const ref : treference); 1145 var 1146 oppostfix:toppostfix; 1147 usedtmpref: treference; 1148 tmpreg : tregister; 1149 so : tshifterop; 1150 dir : integer; 1151 begin 1152 if (TCGSize2Size[FromSize] >= TCGSize2Size[ToSize]) then 1153 FromSize := ToSize; 1154 case ToSize of 1155 { signed integer registers } 1156 OS_8, 1157 OS_S8: 1158 oppostfix:=PF_B; 1159 OS_16, 1160 OS_S16: 1161 oppostfix:=PF_H; 1162 OS_32, 1163 OS_S32, 1164 { for vfp value stored in integer register } 1165 OS_F32: 1166 oppostfix:=PF_None; 1167 else 1168 Inter…
Large files files are truncated, but you can click here to view the full file