PageRenderTime 41ms CodeModel.GetById 29ms app.highlight 5ms RepoModel.GetById 0ms app.codeStats 1ms

/compiler/arm/cgcpu.pas

https://github.com/slibre/freepascal
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