/compiler/arm/cgcpu.pas

https://github.com/slibre/freepascal · Pascal · 4152 lines · 3511 code · 343 blank · 298 comment · 422 complexity · 4ffa7e926bb091829f38cfbc8d1d4d75 MD5 · raw file

Large files are truncated click here to view the full file

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