cgcpu.pas 53 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522
  1. {
  2. $Id$
  3. Copyright (c) 2003 by Florian Klaempfl
  4. Member of the Free Pascal development team
  5. This unit implements the code generator for the ARM
  6. This program is free software; you can redistribute it and/or modify
  7. it under the terms of the GNU General Public License as published by
  8. the Free Software Foundation; either version 2 of the License, or
  9. (at your option) any later version.
  10. This program is distributed in the hope that it will be useful,
  11. but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. GNU General Public License for more details.
  14. You should have received a copy of the GNU General Public License
  15. along with this program; if not, write to the Free Software
  16. Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  17. ****************************************************************************
  18. }
  19. unit cgcpu;
  20. {$i fpcdefs.inc}
  21. interface
  22. uses
  23. symtype,
  24. cgbase,cgobj,
  25. aasmbase,aasmcpu,aasmtai,
  26. cpubase,cpuinfo,node,cg64f32,rgcpu;
  27. type
  28. tcgarm = class(tcg)
  29. { true, if the next arithmetic operation should modify the flags }
  30. setflags : boolean;
  31. procedure init_register_allocators;override;
  32. procedure done_register_allocators;override;
  33. procedure a_param_const(list : taasmoutput;size : tcgsize;a : aword;const locpara : tparalocation);override;
  34. procedure a_param_ref(list : taasmoutput;size : tcgsize;const r : treference;const locpara : tparalocation);override;
  35. procedure a_paramaddr_ref(list : taasmoutput;const r : treference;const locpara : tparalocation);override;
  36. procedure a_call_name(list : taasmoutput;const s : string);override;
  37. procedure a_call_reg(list : taasmoutput;reg: tregister); override;
  38. procedure a_op_const_reg(list : taasmoutput; Op: TOpCG; size: TCGSize; a: AWord; reg: TRegister); override;
  39. procedure a_op_reg_reg(list : taasmoutput; Op: TOpCG; size: TCGSize; src, dst: TRegister); override;
  40. procedure a_op_const_reg_reg(list: taasmoutput; op: TOpCg;
  41. size: tcgsize; a: aword; src, dst: tregister); override;
  42. procedure a_op_reg_reg_reg(list: taasmoutput; op: TOpCg;
  43. size: tcgsize; src1, src2, dst: tregister); override;
  44. { move instructions }
  45. procedure a_load_const_reg(list : taasmoutput; size: tcgsize; a : aword;reg : tregister);override;
  46. procedure a_load_reg_ref(list : taasmoutput; fromsize, tosize: tcgsize; reg : tregister;const ref : treference);override;
  47. procedure a_load_ref_reg(list : taasmoutput; fromsize, tosize : tcgsize;const Ref : treference;reg : tregister);override;
  48. procedure a_load_reg_reg(list : taasmoutput; fromsize, tosize : tcgsize;reg1,reg2 : tregister);override;
  49. { fpu move instructions }
  50. procedure a_loadfpu_reg_reg(list: taasmoutput; size: tcgsize; reg1, reg2: tregister); override;
  51. procedure a_loadfpu_ref_reg(list: taasmoutput; size: tcgsize; const ref: treference; reg: tregister); override;
  52. procedure a_loadfpu_reg_ref(list: taasmoutput; size: tcgsize; reg: tregister; const ref: treference); override;
  53. { comparison operations }
  54. procedure a_cmp_const_reg_label(list : taasmoutput;size : tcgsize;cmp_op : topcmp;a : aword;reg : tregister;
  55. l : tasmlabel);override;
  56. procedure a_cmp_reg_reg_label(list : taasmoutput;size : tcgsize;cmp_op : topcmp;reg1,reg2 : tregister;l : tasmlabel); override;
  57. procedure a_jmp_name(list : taasmoutput;const s : string); override;
  58. procedure a_jmp_always(list : taasmoutput;l: tasmlabel); override;
  59. procedure a_jmp_flags(list : taasmoutput;const f : TResFlags;l: tasmlabel); override;
  60. procedure g_flags2reg(list: taasmoutput; size: TCgSize; const f: TResFlags; reg: TRegister); override;
  61. procedure g_copyvaluepara_openarray(list : taasmoutput;const ref, lenref:treference;elesize:aword);override;
  62. procedure g_stackframe_entry(list : taasmoutput;localsize : longint);override;
  63. procedure g_return_from_proc(list : taasmoutput;parasize : aword); override;
  64. procedure g_restore_frame_pointer(list : taasmoutput);override;
  65. procedure a_loadaddr_ref_reg(list : taasmoutput;const ref : treference;r : tregister);override;
  66. procedure g_concatcopy(list : taasmoutput;const source,dest : treference;len : aword; delsource,loadref : boolean);override;
  67. procedure g_overflowcheck(list: taasmoutput; const l: tlocation; def: tdef); override;
  68. procedure g_save_standard_registers(list : taasmoutput);override;
  69. procedure g_restore_standard_registers(list : taasmoutput);override;
  70. procedure g_save_all_registers(list : taasmoutput);override;
  71. procedure g_restore_all_registers(list : taasmoutput;const funcretparaloc:tparalocation);override;
  72. procedure a_jmp_cond(list : taasmoutput;cond : TOpCmp;l: tasmlabel);
  73. procedure fixref(list : taasmoutput;var ref : treference);
  74. procedure handle_load_store(list:taasmoutput;op: tasmop;oppostfix : toppostfix;reg:tregister;ref: treference);
  75. end;
  76. tcg64farm = class(tcg64f32)
  77. procedure a_op64_reg_reg(list : taasmoutput;op:TOpCG;regsrc,regdst : tregister64);override;
  78. procedure a_op64_const_reg(list : taasmoutput;op:TOpCG;value : qword;reg : tregister64);override;
  79. procedure a_op64_const_reg_reg(list: taasmoutput;op:TOpCG;value : qword;regsrc,regdst : tregister64);override;
  80. procedure a_op64_reg_reg_reg(list: taasmoutput;op:TOpCG;regsrc1,regsrc2,regdst : tregister64);override;
  81. end;
  82. const
  83. OpCmp2AsmCond : Array[topcmp] of TAsmCond = (C_NONE,C_EQ,C_GT,
  84. C_LT,C_GE,C_LE,C_NE,C_LS,C_CC,C_CS,C_HI);
  85. function is_shifter_const(d : dword;var imm_shift : byte) : boolean;
  86. function get_fpu_postfix(def : tdef) : toppostfix;
  87. implementation
  88. uses
  89. globtype,globals,verbose,systems,cutils,
  90. symconst,symdef,symsym,
  91. tgobj,
  92. procinfo,cpupi,
  93. cgutils,
  94. paramgr;
  95. function get_fpu_postfix(def : tdef) : toppostfix;
  96. begin
  97. if def.deftype=floatdef then
  98. begin
  99. case tfloatdef(def).typ of
  100. s32real:
  101. result:=PF_S;
  102. s64real:
  103. result:=PF_D;
  104. s80real:
  105. result:=PF_E;
  106. else
  107. internalerror(200401272);
  108. end;
  109. end
  110. else
  111. internalerror(200401271);
  112. end;
  113. procedure tcgarm.init_register_allocators;
  114. begin
  115. inherited init_register_allocators;
  116. { currently, we save R14 always, so we can use it }
  117. rg[R_INTREGISTER]:=trgcpu.create(R_INTREGISTER,R_SUBWHOLE,
  118. [RS_R0,RS_R1,RS_R2,RS_R3,RS_R4,RS_R5,RS_R6,RS_R7,RS_R8,
  119. RS_R9,RS_R10,RS_R12,RS_R14],first_int_imreg,[]);
  120. rg[R_FPUREGISTER]:=trgcpu.create(R_FPUREGISTER,R_SUBNONE,
  121. [RS_F0,RS_F1,RS_F2,RS_F3,RS_F4,RS_F5,RS_F6,RS_F7],first_fpu_imreg,[]);
  122. rg[R_MMREGISTER]:=trgcpu.create(R_MMREGISTER,R_SUBNONE,
  123. [RS_S0,RS_S1,RS_R2,RS_R3,RS_R4,RS_S31],first_mm_imreg,[]);
  124. end;
  125. procedure tcgarm.done_register_allocators;
  126. begin
  127. rg[R_INTREGISTER].free;
  128. rg[R_FPUREGISTER].free;
  129. rg[R_MMREGISTER].free;
  130. inherited done_register_allocators;
  131. end;
  132. procedure tcgarm.a_param_const(list : taasmoutput;size : tcgsize;a : aword;const locpara : tparalocation);
  133. var
  134. ref: treference;
  135. begin
  136. case locpara.loc of
  137. LOC_REGISTER,LOC_CREGISTER:
  138. a_load_const_reg(list,size,a,locpara.register);
  139. LOC_REFERENCE:
  140. begin
  141. reference_reset(ref);
  142. ref.base:=locpara.reference.index;
  143. ref.offset:=locpara.reference.offset;
  144. a_load_const_ref(list,size,a,ref);
  145. end;
  146. else
  147. internalerror(2002081101);
  148. end;
  149. if locpara.alignment<>0 then
  150. internalerror(2002081102);
  151. end;
  152. procedure tcgarm.a_param_ref(list : taasmoutput;size : tcgsize;const r : treference;const locpara : tparalocation);
  153. var
  154. ref: treference;
  155. tmpreg: tregister;
  156. begin
  157. case locpara.loc of
  158. LOC_REGISTER,LOC_CREGISTER:
  159. a_load_ref_reg(list,size,size,r,locpara.register);
  160. LOC_REFERENCE:
  161. begin
  162. reference_reset(ref);
  163. ref.base:=locpara.reference.index;
  164. ref.offset:=locpara.reference.offset;
  165. tmpreg := getintregister(list,size);
  166. a_load_ref_reg(list,size,size,r,tmpreg);
  167. a_load_reg_ref(list,size,size,tmpreg,ref);
  168. ungetregister(list,tmpreg);
  169. end;
  170. LOC_FPUREGISTER,LOC_CFPUREGISTER:
  171. case size of
  172. OS_F32, OS_F64:
  173. a_loadfpu_ref_reg(list,size,r,locpara.register);
  174. else
  175. internalerror(2002072801);
  176. end;
  177. else
  178. internalerror(2002081103);
  179. end;
  180. if locpara.alignment<>0 then
  181. internalerror(2002081104);
  182. end;
  183. procedure tcgarm.a_paramaddr_ref(list : taasmoutput;const r : treference;const locpara : tparalocation);
  184. var
  185. ref: treference;
  186. tmpreg: tregister;
  187. begin
  188. case locpara.loc of
  189. LOC_REGISTER,LOC_CREGISTER:
  190. a_loadaddr_ref_reg(list,r,locpara.register);
  191. LOC_REFERENCE:
  192. begin
  193. reference_reset(ref);
  194. ref.base := locpara.reference.index;
  195. ref.offset := locpara.reference.offset;
  196. tmpreg := getintregister(list,OS_ADDR);
  197. a_loadaddr_ref_reg(list,r,tmpreg);
  198. a_load_reg_ref(list,OS_ADDR,OS_ADDR,tmpreg,ref);
  199. ungetregister(list,tmpreg);
  200. end;
  201. else
  202. internalerror(2002080701);
  203. end;
  204. end;
  205. procedure tcgarm.a_call_name(list : taasmoutput;const s : string);
  206. begin
  207. list.concat(taicpu.op_sym(A_BL,objectlibrary.newasmsymbol(s,AB_EXTERNAL,AT_FUNCTION)));
  208. if not(pi_do_call in current_procinfo.flags) then
  209. internalerror(2003060703);
  210. end;
  211. procedure tcgarm.a_call_reg(list : taasmoutput;reg: tregister);
  212. var
  213. r : tregister;
  214. begin
  215. list.concat(taicpu.op_reg_reg(A_MOV,NR_R14,NR_PC));
  216. list.concat(taicpu.op_reg_reg(A_MOV,NR_PC,reg));
  217. if not(pi_do_call in current_procinfo.flags) then
  218. internalerror(2003060704);
  219. end;
  220. procedure tcgarm.a_op_const_reg(list : taasmoutput; Op: TOpCG; size: TCGSize; a: AWord; reg: TRegister);
  221. begin
  222. a_op_const_reg_reg(list,op,size,a,reg,reg);
  223. end;
  224. procedure tcgarm.a_op_reg_reg(list : taasmoutput; Op: TOpCG; size: TCGSize; src, dst: TRegister);
  225. begin
  226. case op of
  227. OP_NEG:
  228. list.concat(taicpu.op_reg_reg_const(A_RSB,dst,src,0));
  229. OP_NOT:
  230. list.concat(taicpu.op_reg_reg(A_MVN,dst,src));
  231. else
  232. a_op_reg_reg_reg(list,op,OS_32,src,dst,dst);
  233. end;
  234. end;
  235. const
  236. op_reg_reg_opcg2asmop: array[TOpCG] of tasmop =
  237. (A_NONE,A_ADD,A_AND,A_NONE,A_NONE,A_MUL,A_MUL,A_NONE,A_NONE,A_ORR,
  238. A_NONE,A_NONE,A_NONE,A_SUB,A_EOR);
  239. procedure tcgarm.a_op_const_reg_reg(list: taasmoutput; op: TOpCg;
  240. size: tcgsize; a: aword; src, dst: tregister);
  241. var
  242. shift : byte;
  243. tmpreg : tregister;
  244. so : tshifterop;
  245. l1 : longint;
  246. begin
  247. if is_shifter_const(dword(-a),shift) then
  248. case op of
  249. OP_ADD:
  250. begin
  251. op:=OP_SUB;
  252. a:=dword(-a);
  253. end;
  254. OP_SUB:
  255. begin
  256. op:=OP_SUB;
  257. a:=dword(-a);
  258. end
  259. end;
  260. if is_shifter_const(a,shift) and not(op in [OP_IMUL,OP_MUL]) then
  261. case op of
  262. OP_NEG,OP_NOT,
  263. OP_DIV,OP_IDIV:
  264. internalerror(200308281);
  265. OP_SHL:
  266. begin
  267. if a>32 then
  268. internalerror(200308291);
  269. if a<>0 then
  270. begin
  271. shifterop_reset(so);
  272. so.shiftmode:=SM_LSL;
  273. so.shiftimm:=a;
  274. list.concat(taicpu.op_reg_reg_shifterop(A_MOV,dst,src,so));
  275. end
  276. else
  277. list.concat(taicpu.op_reg_reg(A_MOV,dst,src));
  278. end;
  279. OP_SHR:
  280. begin
  281. if a>32 then
  282. internalerror(200308292);
  283. shifterop_reset(so);
  284. if a<>0 then
  285. begin
  286. so.shiftmode:=SM_LSR;
  287. so.shiftimm:=a;
  288. list.concat(taicpu.op_reg_reg_shifterop(A_MOV,dst,src,so));
  289. end
  290. else
  291. list.concat(taicpu.op_reg_reg(A_MOV,dst,src));
  292. end;
  293. OP_SAR:
  294. begin
  295. if a>32 then
  296. internalerror(200308291);
  297. if a<>0 then
  298. begin
  299. shifterop_reset(so);
  300. so.shiftmode:=SM_ASR;
  301. so.shiftimm:=a;
  302. list.concat(taicpu.op_reg_reg_shifterop(A_MOV,dst,src,so));
  303. end
  304. else
  305. list.concat(taicpu.op_reg_reg(A_MOV,dst,src));
  306. end;
  307. else
  308. list.concat(taicpu.op_reg_reg_const(op_reg_reg_opcg2asmop[op],dst,src,a));
  309. end
  310. else
  311. begin
  312. { there could be added some more sophisticated optimizations }
  313. if (op in [OP_MUL,OP_IMUL]) and (a=1) then
  314. a_load_reg_reg(list,size,size,src,dst)
  315. else if (op in [OP_MUL,OP_IMUL]) and (a=0) then
  316. a_load_const_reg(list,size,0,dst)
  317. else if (op in [OP_IMUL]) and (a=-1) then
  318. a_op_reg_reg(list,OP_NEG,size,src,dst)
  319. { we do this here instead in the peephole optimizer because
  320. it saves us a register }
  321. else if (op in [OP_MUL,OP_IMUL]) and ispowerof2(a,l1) then
  322. a_op_const_reg_reg(list,OP_SHL,size,l1,src,dst)
  323. else
  324. begin
  325. tmpreg:=getintregister(list,size);
  326. a_load_const_reg(list,size,a,tmpreg);
  327. a_op_reg_reg_reg(list,op,size,tmpreg,src,dst);
  328. ungetregister(list,tmpreg);
  329. end;
  330. end;
  331. end;
  332. procedure tcgarm.a_op_reg_reg_reg(list: taasmoutput; op: TOpCg;
  333. size: tcgsize; src1, src2, dst: tregister);
  334. var
  335. so : tshifterop;
  336. tmpreg : tregister;
  337. begin
  338. case op of
  339. OP_NEG,OP_NOT,
  340. OP_DIV,OP_IDIV:
  341. internalerror(200308281);
  342. OP_SHL:
  343. begin
  344. shifterop_reset(so);
  345. so.rs:=src1;
  346. so.shiftmode:=SM_LSL;
  347. list.concat(taicpu.op_reg_reg_shifterop(A_MOV,dst,src2,so));
  348. end;
  349. OP_SHR:
  350. begin
  351. shifterop_reset(so);
  352. so.rs:=src1;
  353. so.shiftmode:=SM_LSR;
  354. list.concat(taicpu.op_reg_reg_shifterop(A_MOV,dst,src2,so));
  355. end;
  356. OP_SAR:
  357. begin
  358. shifterop_reset(so);
  359. so.rs:=src1;
  360. so.shiftmode:=SM_ASR;
  361. list.concat(taicpu.op_reg_reg_shifterop(A_MOV,dst,src2,so));
  362. end;
  363. OP_IMUL,
  364. OP_MUL:
  365. begin
  366. { the arm doesn't allow that rd and rm are the same }
  367. if dst=src2 then
  368. begin
  369. if dst<>src1 then
  370. list.concat(taicpu.op_reg_reg_reg(A_MUL,dst,src1,src2))
  371. else
  372. begin
  373. tmpreg:=getintregister(list,size);
  374. a_load_reg_reg(list,size,size,src2,dst);
  375. ungetregister(list,tmpreg);
  376. list.concat(taicpu.op_reg_reg_reg(A_MUL,dst,tmpreg,src1));
  377. end;
  378. end
  379. else
  380. list.concat(taicpu.op_reg_reg_reg(A_MUL,dst,src2,src1));
  381. end;
  382. else
  383. list.concat(setoppostfix(taicpu.op_reg_reg_reg(op_reg_reg_opcg2asmop[op],dst,src2,src1),toppostfix(ord(setflags)*ord(PF_S))));
  384. end;
  385. end;
  386. function rotl(d : dword;b : byte) : dword;
  387. begin
  388. result:=(d shr (32-b)) or (d shl b);
  389. end;
  390. function is_shifter_const(d : dword;var imm_shift : byte) : boolean;
  391. var
  392. i : longint;
  393. begin
  394. for i:=0 to 15 do
  395. begin
  396. if (d and not(rotl($ff,i*2)))=0 then
  397. begin
  398. imm_shift:=i*2;
  399. result:=true;
  400. exit;
  401. end;
  402. end;
  403. result:=false;
  404. end;
  405. procedure tcgarm.a_load_const_reg(list : taasmoutput; size: tcgsize; a : aword;reg : tregister);
  406. var
  407. imm_shift : byte;
  408. l : tasmlabel;
  409. hr : treference;
  410. begin
  411. if not(size in [OS_8,OS_S8,OS_16,OS_S16,OS_32,OS_S32]) then
  412. internalerror(2002090902);
  413. if is_shifter_const(dword(a),imm_shift) then
  414. list.concat(taicpu.op_reg_const(A_MOV,reg,a))
  415. else if is_shifter_const(dword(not(a)),imm_shift) then
  416. list.concat(taicpu.op_reg_const(A_MVN,reg,not(a)))
  417. else
  418. begin
  419. reference_reset(hr);
  420. objectlibrary.getlabel(l);
  421. cg.a_label(current_procinfo.aktlocaldata,l);
  422. hr.symboldata:=current_procinfo.aktlocaldata.last;
  423. current_procinfo.aktlocaldata.concat(tai_const.Create_32bit(longint(a)));
  424. hr.symbol:=l;
  425. list.concat(taicpu.op_reg_ref(A_LDR,reg,hr));
  426. end;
  427. end;
  428. procedure tcgarm.handle_load_store(list:taasmoutput;op: tasmop;oppostfix : toppostfix;reg:tregister;ref: treference);
  429. var
  430. tmpreg : tregister;
  431. tmpref : treference;
  432. l : tasmlabel;
  433. begin
  434. tmpreg:=NR_NO;
  435. { Be sure to have a base register }
  436. if (ref.base=NR_NO) then
  437. begin
  438. if ref.shiftmode<>SM_None then
  439. internalerror(200308294);
  440. ref.base:=ref.index;
  441. ref.index:=NR_NO;
  442. end;
  443. { absolute symbols can't be handled directly, we've to store the symbol reference
  444. in the text segment and access it pc relative
  445. For now, we assume that references where base or index equals to PC are already
  446. relative, all other references are assumed to be absolute and thus they need
  447. to be handled extra.
  448. A proper solution would be to change refoptions to a set and store the information
  449. if the symbol is absolute or relative there.
  450. }
  451. if (assigned(ref.symbol) and
  452. not(is_pc(ref.base)) and
  453. not(is_pc(ref.index))
  454. ) or
  455. (ref.offset<-4095) or
  456. (ref.offset>4095) or
  457. ((oppostfix in [PF_SB,PF_H,PF_SH]) and
  458. ((ref.offset<-255) or
  459. (ref.offset>255)
  460. )
  461. ) or
  462. ((op in [A_LDF,A_STF]) and
  463. ((ref.offset<-1020) or
  464. (ref.offset>1020)
  465. )
  466. ) then
  467. begin
  468. reference_reset(tmpref);
  469. { create consts entry }
  470. objectlibrary.getlabel(l);
  471. cg.a_label(current_procinfo.aktlocaldata,l);
  472. tmpref.symboldata:=current_procinfo.aktlocaldata.last;
  473. if assigned(ref.symbol) then
  474. current_procinfo.aktlocaldata.concat(tai_const_symbol.Create_offset(ref.symbol,ref.offset))
  475. else
  476. current_procinfo.aktlocaldata.concat(tai_const.Create_32bit(ref.offset));
  477. { load consts entry }
  478. tmpreg:=getintregister(list,OS_INT);
  479. tmpref.symbol:=l;
  480. tmpref.base:=NR_R15;
  481. list.concat(taicpu.op_reg_ref(A_LDR,tmpreg,tmpref));
  482. if (ref.base<>NR_NO) then
  483. begin
  484. if ref.index<>NR_NO then
  485. begin
  486. list.concat(taicpu.op_reg_reg_reg(A_ADD,tmpreg,ref.base,tmpreg));
  487. ref.base:=tmpreg;
  488. end
  489. else
  490. begin
  491. ref.index:=tmpreg;
  492. ref.shiftimm:=0;
  493. ref.signindex:=1;
  494. ref.shiftmode:=SM_None;
  495. end;
  496. end
  497. else
  498. ref.base:=tmpreg;
  499. ref.offset:=0;
  500. ref.symbol:=nil;
  501. end;
  502. if (ref.base<>NR_NO) and (ref.index<>NR_NO) and (ref.offset<>0) then
  503. begin
  504. if tmpreg<>NR_NO then
  505. a_op_const_reg_reg(list,OP_ADD,OS_ADDR,ref.offset,tmpreg,tmpreg)
  506. else
  507. begin
  508. tmpreg:=getintregister(list,OS_ADDR);
  509. a_op_const_reg_reg(list,OP_ADD,OS_ADDR,ref.offset,ref.base,tmpreg);
  510. ref.base:=tmpreg;
  511. end;
  512. ref.offset:=0;
  513. end;
  514. { floating point operations have only limited references
  515. we expect here, that a base is already set }
  516. if (op in [A_LDF,A_STF]) and (ref.index<>NR_NO) then
  517. begin
  518. if ref.shiftmode<>SM_none then
  519. internalerror(200309121);
  520. if tmpreg<>NR_NO then
  521. begin
  522. if ref.base=tmpreg then
  523. begin
  524. if ref.signindex<0 then
  525. list.concat(taicpu.op_reg_reg_reg(A_SUB,tmpreg,tmpreg,ref.index))
  526. else
  527. list.concat(taicpu.op_reg_reg_reg(A_ADD,tmpreg,tmpreg,ref.index));
  528. ref.index:=NR_NO;
  529. end
  530. else
  531. begin
  532. if ref.index<>tmpreg then
  533. internalerror(200403161);
  534. if ref.signindex<0 then
  535. list.concat(taicpu.op_reg_reg_reg(A_SUB,tmpreg,ref.base,tmpreg))
  536. else
  537. list.concat(taicpu.op_reg_reg_reg(A_ADD,tmpreg,ref.base,tmpreg));
  538. ref.base:=tmpreg;
  539. ref.index:=NR_NO;
  540. end;
  541. end
  542. else
  543. begin
  544. tmpreg:=getintregister(list,OS_ADDR);
  545. list.concat(taicpu.op_reg_reg_reg(A_ADD,tmpreg,ref.base,ref.index));
  546. ref.base:=tmpreg;
  547. ref.index:=NR_NO;
  548. end;
  549. end;
  550. list.concat(setoppostfix(taicpu.op_reg_ref(op,reg,ref),oppostfix));
  551. if (tmpreg<>NR_NO) then
  552. ungetregister(list,tmpreg);
  553. end;
  554. procedure tcgarm.a_load_reg_ref(list : taasmoutput; fromsize, tosize: tcgsize; reg : tregister;const ref : treference);
  555. var
  556. oppostfix:toppostfix;
  557. begin
  558. case ToSize of
  559. { signed integer registers }
  560. OS_8,
  561. OS_S8:
  562. oppostfix:=PF_B;
  563. OS_16,
  564. OS_S16:
  565. oppostfix:=PF_H;
  566. OS_32,
  567. OS_S32:
  568. oppostfix:=PF_None;
  569. else
  570. InternalError(200308295);
  571. end;
  572. handle_load_store(list,A_STR,oppostfix,reg,ref);
  573. end;
  574. procedure tcgarm.a_load_ref_reg(list : taasmoutput; fromsize, tosize : tcgsize;const Ref : treference;reg : tregister);
  575. var
  576. oppostfix:toppostfix;
  577. begin
  578. case FromSize of
  579. { signed integer registers }
  580. OS_8:
  581. oppostfix:=PF_B;
  582. OS_S8:
  583. oppostfix:=PF_SB;
  584. OS_16:
  585. oppostfix:=PF_H;
  586. OS_S16:
  587. oppostfix:=PF_SH;
  588. OS_32,
  589. OS_S32:
  590. oppostfix:=PF_None;
  591. else
  592. InternalError(200308291);
  593. end;
  594. handle_load_store(list,A_LDR,oppostfix,reg,ref);
  595. end;
  596. procedure tcgarm.a_load_reg_reg(list : taasmoutput; fromsize, tosize : tcgsize;reg1,reg2 : tregister);
  597. var
  598. instr: taicpu;
  599. so : tshifterop;
  600. begin
  601. shifterop_reset(so);
  602. if (reg1<>reg2) or
  603. (tcgsize2size[tosize] < tcgsize2size[fromsize]) or
  604. ((tcgsize2size[tosize] = tcgsize2size[fromsize]) and
  605. (tosize <> fromsize) and
  606. not(fromsize in [OS_32,OS_S32])) then
  607. begin
  608. case tosize of
  609. OS_8:
  610. list.concat(taicpu.op_reg_reg_const(A_AND,
  611. reg2,reg1,$ff));
  612. OS_S8:
  613. begin
  614. so.shiftmode:=SM_LSL;
  615. so.shiftimm:=24;
  616. list.concat(taicpu.op_reg_reg_shifterop(A_MOV,reg2,reg1,so));
  617. so.shiftmode:=SM_ASR;
  618. so.shiftimm:=24;
  619. list.concat(taicpu.op_reg_reg_shifterop(A_MOV,reg2,reg2,so));
  620. end;
  621. OS_16:
  622. begin
  623. so.shiftmode:=SM_LSL;
  624. so.shiftimm:=16;
  625. list.concat(taicpu.op_reg_reg_shifterop(A_MOV,reg2,reg1,so));
  626. so.shiftmode:=SM_LSR;
  627. so.shiftimm:=16;
  628. list.concat(taicpu.op_reg_reg_shifterop(A_MOV,reg2,reg2,so));
  629. end;
  630. OS_S16:
  631. begin
  632. so.shiftmode:=SM_LSL;
  633. so.shiftimm:=16;
  634. list.concat(taicpu.op_reg_reg_shifterop(A_MOV,reg2,reg1,so));
  635. so.shiftmode:=SM_ASR;
  636. so.shiftimm:=16;
  637. list.concat(taicpu.op_reg_reg_shifterop(A_MOV,reg2,reg2,so));
  638. end;
  639. OS_32,OS_S32:
  640. begin
  641. instr:=taicpu.op_reg_reg(A_MOV,reg2,reg1);
  642. list.concat(instr);
  643. add_move_instruction(instr);
  644. end;
  645. else internalerror(2002090901);
  646. end;
  647. end;
  648. end;
  649. procedure tcgarm.a_loadfpu_reg_reg(list: taasmoutput; size: tcgsize; reg1, reg2: tregister);
  650. begin
  651. list.concat(setoppostfix(taicpu.op_reg_reg(A_MVF,reg2,reg1),cgsize2fpuoppostfix[size]));
  652. end;
  653. procedure tcgarm.a_loadfpu_ref_reg(list: taasmoutput; size: tcgsize; const ref: treference; reg: tregister);
  654. var
  655. oppostfix:toppostfix;
  656. begin
  657. case size of
  658. OS_F32:
  659. oppostfix:=PF_S;
  660. OS_F64:
  661. oppostfix:=PF_D;
  662. OS_F80:
  663. oppostfix:=PF_E;
  664. else
  665. InternalError(200309021);
  666. end;
  667. handle_load_store(list,A_LDF,oppostfix,reg,ref);
  668. end;
  669. procedure tcgarm.a_loadfpu_reg_ref(list: taasmoutput; size: tcgsize; reg: tregister; const ref: treference);
  670. var
  671. oppostfix:toppostfix;
  672. begin
  673. case size of
  674. OS_F32:
  675. oppostfix:=PF_S;
  676. OS_F64:
  677. oppostfix:=PF_D;
  678. OS_F80:
  679. oppostfix:=PF_E;
  680. else
  681. InternalError(200309021);
  682. end;
  683. handle_load_store(list,A_STF,oppostfix,reg,ref);
  684. end;
  685. { comparison operations }
  686. procedure tcgarm.a_cmp_const_reg_label(list : taasmoutput;size : tcgsize;cmp_op : topcmp;a : aword;reg : tregister;
  687. l : tasmlabel);
  688. var
  689. tmpreg : tregister;
  690. b : byte;
  691. begin
  692. if is_shifter_const(a,b) then
  693. list.concat(taicpu.op_reg_const(A_CMP,reg,a))
  694. { CMN reg,0 and CMN reg,$80000000 are different from CMP reg,$ffffffff
  695. and CMP reg,$7fffffff regarding the flags according to the ARM manual }
  696. else if is_shifter_const(-a,b) and (a<>$7fffffff) and (a<>$ffffffff) then
  697. list.concat(taicpu.op_reg_const(A_CMN,reg,-a))
  698. else
  699. begin
  700. tmpreg:=getintregister(list,size);
  701. a_load_const_reg(list,size,a,tmpreg);
  702. list.concat(taicpu.op_reg_reg(A_CMP,reg,tmpreg));
  703. ungetregister(list,tmpreg);
  704. end;
  705. a_jmp_cond(list,cmp_op,l);
  706. end;
  707. procedure tcgarm.a_cmp_reg_reg_label(list : taasmoutput;size : tcgsize;cmp_op : topcmp;reg1,reg2 : tregister;l : tasmlabel);
  708. begin
  709. list.concat(taicpu.op_reg_reg(A_CMP,reg2,reg1));
  710. a_jmp_cond(list,cmp_op,l);
  711. end;
  712. procedure tcgarm.a_jmp_name(list : taasmoutput;const s : string);
  713. begin
  714. list.concat(taicpu.op_sym(A_B,objectlibrary.newasmsymbol(s,AB_EXTERNAL,AT_FUNCTION)));
  715. end;
  716. procedure tcgarm.a_jmp_always(list : taasmoutput;l: tasmlabel);
  717. begin
  718. list.concat(taicpu.op_sym(A_B,objectlibrary.newasmsymbol(l.name,AB_EXTERNAL,AT_FUNCTION)));
  719. end;
  720. procedure tcgarm.a_jmp_flags(list : taasmoutput;const f : TResFlags;l: tasmlabel);
  721. var
  722. ai : taicpu;
  723. begin
  724. ai:=setcondition(taicpu.op_sym(A_B,l),flags_to_cond(f));
  725. ai.is_jmp:=true;
  726. list.concat(ai);
  727. end;
  728. procedure tcgarm.g_flags2reg(list: taasmoutput; size: TCgSize; const f: TResFlags; reg: TRegister);
  729. var
  730. ai : taicpu;
  731. begin
  732. list.concat(setcondition(taicpu.op_reg_const(A_MOV,reg,1),flags_to_cond(f)));
  733. list.concat(setcondition(taicpu.op_reg_const(A_MOV,reg,0),inverse_cond[flags_to_cond(f)]));
  734. end;
  735. procedure tcgarm.g_copyvaluepara_openarray(list : taasmoutput;const ref, lenref:treference;elesize:aword);
  736. begin
  737. end;
  738. procedure tcgarm.g_stackframe_entry(list : taasmoutput;localsize : longint);
  739. var
  740. ref : treference;
  741. shift : byte;
  742. firstfloatreg,lastfloatreg,
  743. r : byte;
  744. begin
  745. LocalSize:=align(LocalSize,4);
  746. firstfloatreg:=RS_NO;
  747. { save floating point registers? }
  748. for r:=RS_F0 to RS_F7 do
  749. if r in rg[R_FPUREGISTER].used_in_proc-paramanager.get_volatile_registers_fpu(pocall_stdcall) then
  750. begin
  751. if firstfloatreg=RS_NO then
  752. firstfloatreg:=r;
  753. lastfloatreg:=r;
  754. end;
  755. a_reg_alloc(list,NR_STACK_POINTER_REG);
  756. a_reg_alloc(list,NR_FRAME_POINTER_REG);
  757. a_reg_alloc(list,NR_R12);
  758. list.concat(taicpu.op_reg_reg(A_MOV,NR_R12,NR_STACK_POINTER_REG));
  759. { save int registers }
  760. reference_reset(ref);
  761. ref.index:=NR_STACK_POINTER_REG;
  762. ref.addressmode:=AM_PREINDEXED;
  763. list.concat(setoppostfix(taicpu.op_ref_regset(A_STM,ref,
  764. rg[R_INTREGISTER].used_in_proc-paramanager.get_volatile_registers_int(pocall_stdcall)+[RS_R11,RS_R12,RS_R14,RS_R15]),
  765. PF_FD));
  766. list.concat(taicpu.op_reg_reg_const(A_SUB,NR_FRAME_POINTER_REG,NR_R12,4));
  767. { allocate necessary stack size }
  768. { don't use a_op_const_reg_reg here because we don't allow register allocations
  769. in the entry/exit code }
  770. if not(is_shifter_const(localsize,shift)) then
  771. begin
  772. a_load_const_reg(list,OS_ADDR,LocalSize,NR_R12);
  773. list.concat(taicpu.op_reg_reg_reg(A_SUB,NR_STACK_POINTER_REG,NR_STACK_POINTER_REG,NR_R12));
  774. a_reg_dealloc(list,NR_R12);
  775. end
  776. else
  777. begin
  778. a_reg_dealloc(list,NR_R12);
  779. list.concat(taicpu.op_reg_reg_const(A_SUB,NR_STACK_POINTER_REG,NR_STACK_POINTER_REG,LocalSize));
  780. end;
  781. if firstfloatreg<>RS_NO then
  782. begin
  783. reference_reset(ref);
  784. ref.base:=NR_FRAME_POINTER_REG;
  785. ref.offset:=tarmprocinfo(current_procinfo).floatregstart;
  786. list.concat(taicpu.op_reg_const_ref(A_SFM,newreg(R_FPUREGISTER,firstfloatreg,R_SUBWHOLE),
  787. lastfloatreg-firstfloatreg+1,ref));
  788. end;
  789. end;
  790. procedure tcgarm.g_return_from_proc(list : taasmoutput;parasize : aword);
  791. var
  792. ref : treference;
  793. firstfloatreg,lastfloatreg,
  794. r : byte;
  795. begin
  796. { restore floating point register }
  797. firstfloatreg:=RS_NO;
  798. { save floating point registers? }
  799. for r:=RS_F0 to RS_F7 do
  800. if r in rg[R_FPUREGISTER].used_in_proc-paramanager.get_volatile_registers_fpu(pocall_stdcall) then
  801. begin
  802. if firstfloatreg=RS_NO then
  803. firstfloatreg:=r;
  804. lastfloatreg:=r;
  805. end;
  806. if firstfloatreg<>RS_NO then
  807. begin
  808. reference_reset(ref);
  809. ref.base:=NR_FRAME_POINTER_REG;
  810. ref.offset:=tarmprocinfo(current_procinfo).floatregstart;
  811. list.concat(taicpu.op_reg_const_ref(A_LFM,newreg(R_FPUREGISTER,firstfloatreg,R_SUBWHOLE),
  812. lastfloatreg-firstfloatreg+1,ref));
  813. end;
  814. if (current_procinfo.framepointer=NR_STACK_POINTER_REG) then
  815. list.concat(taicpu.op_reg_reg(A_MOV,NR_R15,NR_R14))
  816. else
  817. begin
  818. { restore int registers and return }
  819. reference_reset(ref);
  820. ref.index:=NR_FRAME_POINTER_REG;
  821. list.concat(setoppostfix(taicpu.op_ref_regset(A_LDM,ref,rg[R_INTREGISTER].used_in_proc-paramanager.get_volatile_registers_int(pocall_stdcall)+[RS_R11,RS_R13,RS_R15]),PF_EA));
  822. end;
  823. end;
  824. procedure tcgarm.g_restore_frame_pointer(list : taasmoutput);
  825. begin
  826. { the frame pointer on the ARM is restored while the ret is executed }
  827. end;
  828. procedure tcgarm.a_loadaddr_ref_reg(list : taasmoutput;const ref : treference;r : tregister);
  829. var
  830. b : byte;
  831. tmpref : treference;
  832. instr : taicpu;
  833. begin
  834. if ref.addressmode<>AM_OFFSET then
  835. internalerror(200309071);
  836. tmpref:=ref;
  837. { Be sure to have a base register }
  838. if (tmpref.base=NR_NO) then
  839. begin
  840. if tmpref.shiftmode<>SM_None then
  841. internalerror(200308294);
  842. if tmpref.signindex<0 then
  843. internalerror(200312023);
  844. tmpref.base:=tmpref.index;
  845. tmpref.index:=NR_NO;
  846. end;
  847. if assigned(tmpref.symbol) or
  848. not((is_shifter_const(dword(tmpref.offset),b)) or
  849. (is_shifter_const(dword(-tmpref.offset),b))
  850. ) then
  851. fixref(list,tmpref);
  852. { expect a base here }
  853. if tmpref.base=NR_NO then
  854. internalerror(200312022);
  855. if tmpref.index<>NR_NO then
  856. begin
  857. if tmpref.shiftmode<>SM_None then
  858. internalerror(200312021);
  859. if tmpref.signindex<0 then
  860. a_op_reg_reg_reg(list,OP_SUB,OS_ADDR,tmpref.base,tmpref.index,r)
  861. else
  862. a_op_reg_reg_reg(list,OP_ADD,OS_ADDR,tmpref.base,tmpref.index,r);
  863. if tmpref.offset<>0 then
  864. a_op_const_reg_reg(list,OP_ADD,OS_ADDR,tmpref.offset,r,r);
  865. end
  866. else
  867. begin
  868. if tmpref.offset<>0 then
  869. a_op_const_reg_reg(list,OP_ADD,OS_ADDR,tmpref.offset,tmpref.base,r)
  870. else
  871. begin
  872. instr:=taicpu.op_reg_reg(A_MOV,r,tmpref.base);
  873. list.concat(instr);
  874. add_move_instruction(instr);
  875. end;
  876. end;
  877. reference_release(list,tmpref);
  878. end;
  879. procedure tcgarm.fixref(list : taasmoutput;var ref : treference);
  880. var
  881. tmpreg : tregister;
  882. tmpref : treference;
  883. l : tasmlabel;
  884. begin
  885. { absolute symbols can't be handled directly, we've to store the symbol reference
  886. in the text segment and access it pc relative
  887. For now, we assume that references where base or index equals to PC are already
  888. relative, all other references are assumed to be absolute and thus they need
  889. to be handled extra.
  890. A proper solution would be to change refoptions to a set and store the information
  891. if the symbol is absolute or relative there.
  892. }
  893. { create consts entry }
  894. reference_reset(tmpref);
  895. objectlibrary.getlabel(l);
  896. cg.a_label(current_procinfo.aktlocaldata,l);
  897. tmpref.symboldata:=current_procinfo.aktlocaldata.last;
  898. if assigned(ref.symbol) then
  899. current_procinfo.aktlocaldata.concat(tai_const_symbol.Create_offset(ref.symbol,ref.offset))
  900. else
  901. current_procinfo.aktlocaldata.concat(tai_const.Create_32bit(ref.offset));
  902. { load consts entry }
  903. tmpreg:=getintregister(list,OS_INT);
  904. tmpref.symbol:=l;
  905. tmpref.base:=NR_PC;
  906. list.concat(taicpu.op_reg_ref(A_LDR,tmpreg,tmpref));
  907. if (ref.base<>NR_NO) then
  908. begin
  909. if ref.index<>NR_NO then
  910. begin
  911. list.concat(taicpu.op_reg_reg_reg(A_ADD,tmpreg,ref.base,tmpreg));
  912. ref.base:=tmpreg;
  913. end
  914. else
  915. begin
  916. ref.index:=tmpreg;
  917. ref.shiftimm:=0;
  918. ref.signindex:=1;
  919. ref.shiftmode:=SM_None;
  920. end;
  921. end
  922. else
  923. ref.base:=tmpreg;
  924. ref.offset:=0;
  925. ref.symbol:=nil;
  926. end;
  927. procedure tcgarm.g_concatcopy(list : taasmoutput;const source,dest : treference;len : aword; delsource,loadref : boolean);
  928. var
  929. srcref,dstref:treference;
  930. srcreg,destreg,countreg,r:tregister;
  931. helpsize:aword;
  932. copysize:byte;
  933. cgsize:Tcgsize;
  934. procedure genloop(count : aword;size : byte);
  935. const
  936. size2opsize : array[1..4] of tcgsize = (OS_8,OS_16,OS_NO,OS_32);
  937. var
  938. l : tasmlabel;
  939. begin
  940. objectlibrary.getlabel(l);
  941. a_load_const_reg(list,OS_INT,count,countreg);
  942. cg.a_label(list,l);
  943. srcref.addressmode:=AM_POSTINDEXED;
  944. dstref.addressmode:=AM_POSTINDEXED;
  945. srcref.offset:=size;
  946. dstref.offset:=size;
  947. r:=getintregister(list,size2opsize[size]);
  948. a_load_ref_reg(list,size2opsize[size],size2opsize[size],srcref,r);
  949. a_load_reg_ref(list,size2opsize[size],size2opsize[size],r,dstref);
  950. ungetregister(list,r);
  951. list.concat(setoppostfix(taicpu.op_reg_reg_const(A_SUB,countreg,countreg,1),PF_S));
  952. list.concat(setcondition(taicpu.op_sym(A_B,l),C_NE));
  953. { keep the registers alive }
  954. list.concat(taicpu.op_reg_reg(A_MOV,countreg,countreg));
  955. list.concat(taicpu.op_reg_reg(A_MOV,srcreg,srcreg));
  956. list.concat(taicpu.op_reg_reg(A_MOV,destreg,destreg));
  957. end;
  958. begin
  959. if len=0 then
  960. exit;
  961. helpsize:=12;
  962. dstref:=dest;
  963. srcref:=source;
  964. if cs_littlesize in aktglobalswitches then
  965. helpsize:=8;
  966. if not loadref and (len<=helpsize) then
  967. begin
  968. copysize:=4;
  969. cgsize:=OS_32;
  970. while len<>0 do
  971. begin
  972. if len<2 then
  973. begin
  974. copysize:=1;
  975. cgsize:=OS_8;
  976. end
  977. else if len<4 then
  978. begin
  979. copysize:=2;
  980. cgsize:=OS_16;
  981. end;
  982. dec(len,copysize);
  983. r:=getintregister(list,cgsize);
  984. a_load_ref_reg(list,cgsize,cgsize,srcref,r);
  985. if (len=0) and delsource then
  986. reference_release(list,source);
  987. a_load_reg_ref(list,cgsize,cgsize,r,dstref);
  988. inc(srcref.offset,copysize);
  989. inc(dstref.offset,copysize);
  990. ungetregister(list,r);
  991. end;
  992. end
  993. else
  994. begin
  995. destreg:=getintregister(list,OS_ADDR);
  996. a_loadaddr_ref_reg(list,dest,destreg);
  997. reference_reset_base(dstref,destreg,0);
  998. srcreg:=getintregister(list,OS_ADDR);
  999. if loadref then
  1000. a_load_ref_reg(list,OS_ADDR,OS_ADDR,source,srcreg)
  1001. else
  1002. a_loadaddr_ref_reg(list,source,srcreg);
  1003. reference_reset_base(srcref,srcreg,0);
  1004. if delsource then
  1005. reference_release(list,source);
  1006. countreg:=getintregister(list,OS_32);
  1007. // if cs_littlesize in aktglobalswitches then
  1008. genloop(len,1);
  1009. {
  1010. else
  1011. begin
  1012. helpsize:=len shr 2;
  1013. len:=len and 3;
  1014. if helpsize>1 then
  1015. begin
  1016. a_load_const_reg(list,OS_INT,helpsize,countreg);
  1017. list.concat(Taicpu.op_none(A_REP,S_NO));
  1018. end;
  1019. if helpsize>0 then
  1020. list.concat(Taicpu.op_none(A_MOVSD,S_NO));
  1021. if len>1 then
  1022. begin
  1023. dec(len,2);
  1024. list.concat(Taicpu.op_none(A_MOVSW,S_NO));
  1025. end;
  1026. if len=1 then
  1027. list.concat(Taicpu.op_none(A_MOVSB,S_NO));
  1028. end;
  1029. }
  1030. ungetregister(list,countreg);
  1031. ungetregister(list,srcreg);
  1032. ungetregister(list,destreg);
  1033. end;
  1034. if delsource then
  1035. tg.ungetiftemp(list,source);
  1036. end;
  1037. procedure tcgarm.g_overflowcheck(list: taasmoutput; const l: tlocation; def: tdef);
  1038. begin
  1039. end;
  1040. procedure tcgarm.g_save_standard_registers(list : taasmoutput);
  1041. begin
  1042. { we support only ARM standard calling conventions so this procedure has no use on the ARM }
  1043. end;
  1044. procedure tcgarm.g_restore_standard_registers(list : taasmoutput);
  1045. begin
  1046. { we support only ARM standard calling conventions so this procedure has no use on the ARM }
  1047. end;
  1048. procedure tcgarm.g_save_all_registers(list : taasmoutput);
  1049. begin
  1050. { we support only ARM standard calling conventions so this procedure has no use on the ARM }
  1051. end;
  1052. procedure tcgarm.g_restore_all_registers(list : taasmoutput;const funcretparaloc:tparalocation);
  1053. begin
  1054. { we support only ARM standard calling conventions so this procedure has no use on the ARM }
  1055. end;
  1056. procedure tcgarm.a_jmp_cond(list : taasmoutput;cond : TOpCmp;l: tasmlabel);
  1057. var
  1058. ai : taicpu;
  1059. begin
  1060. ai:=Taicpu.Op_sym(A_B,l);
  1061. ai.SetCondition(OpCmp2AsmCond[cond]);
  1062. ai.is_jmp:=true;
  1063. list.concat(ai);
  1064. end;
  1065. procedure tcg64farm.a_op64_reg_reg(list : taasmoutput;op:TOpCG;regsrc,regdst : tregister64);
  1066. var
  1067. tmpreg : tregister;
  1068. begin
  1069. case op of
  1070. OP_NEG:
  1071. begin
  1072. list.concat(setoppostfix(taicpu.op_reg_reg_const(A_RSB,regdst.reglo,regsrc.reglo,0),PF_S));
  1073. list.concat(taicpu.op_reg_reg_const(A_RSC,regdst.reghi,regsrc.reghi,0));
  1074. end;
  1075. OP_NOT:
  1076. begin
  1077. cg.a_op_reg_reg(list,OP_NOT,OS_INT,regsrc.reglo,regdst.reglo);
  1078. cg.a_op_reg_reg(list,OP_NOT,OS_INT,regsrc.reghi,regdst.reghi);
  1079. end;
  1080. else
  1081. a_op64_reg_reg_reg(list,op,regsrc,regdst,regdst);
  1082. end;
  1083. end;
  1084. procedure tcg64farm.a_op64_const_reg(list : taasmoutput;op:TOpCG;value : qword;reg : tregister64);
  1085. begin
  1086. a_op64_const_reg_reg(list,op,value,reg,reg);
  1087. end;
  1088. procedure tcg64farm.a_op64_const_reg_reg(list: taasmoutput;op:TOpCG;value : qword;regsrc,regdst : tregister64);
  1089. var
  1090. tmpreg : tregister;
  1091. b : byte;
  1092. begin
  1093. case op of
  1094. OP_AND,OP_OR,OP_XOR:
  1095. begin
  1096. cg.a_op_const_reg_reg(list,op,OS_32,lo(value),regsrc.reglo,regdst.reglo);
  1097. cg.a_op_const_reg_reg(list,op,OS_32,hi(value),regsrc.reghi,regdst.reghi);
  1098. end;
  1099. OP_ADD:
  1100. begin
  1101. if is_shifter_const(lo(value),b) then
  1102. list.concat(setoppostfix(taicpu.op_reg_reg_const(A_ADD,regdst.reglo,regsrc.reglo,lo(value)),PF_S))
  1103. else
  1104. begin
  1105. tmpreg:=cg.getintregister(list,OS_32);
  1106. cg.a_load_const_reg(list,OS_32,lo(value),tmpreg);
  1107. list.concat(setoppostfix(taicpu.op_reg_reg_reg(A_ADD,regdst.reglo,regsrc.reglo,tmpreg),PF_S));
  1108. cg.ungetregister(list,tmpreg);
  1109. end;
  1110. if is_shifter_const(hi(value),b) then
  1111. list.concat(taicpu.op_reg_reg_const(A_ADC,regdst.reghi,regsrc.reghi,hi(value)))
  1112. else
  1113. begin
  1114. tmpreg:=cg.getintregister(list,OS_32);
  1115. cg.a_load_const_reg(list,OS_32,hi(value),tmpreg);
  1116. list.concat(taicpu.op_reg_reg_reg(A_ADC,regdst.reghi,regsrc.reghi,tmpreg));
  1117. cg.ungetregister(list,tmpreg);
  1118. end;
  1119. end;
  1120. OP_SUB:
  1121. begin
  1122. if is_shifter_const(lo(value),b) then
  1123. list.concat(setoppostfix(taicpu.op_reg_reg_const(A_SUB,regdst.reglo,regsrc.reglo,lo(value)),PF_S))
  1124. else
  1125. begin
  1126. tmpreg:=cg.getintregister(list,OS_32);
  1127. cg.a_load_const_reg(list,OS_32,lo(value),tmpreg);
  1128. list.concat(setoppostfix(taicpu.op_reg_reg_reg(A_SUB,regdst.reglo,regsrc.reglo,tmpreg),PF_S));
  1129. cg.ungetregister(list,tmpreg);
  1130. end;
  1131. if is_shifter_const(hi(value),b) then
  1132. list.concat(taicpu.op_reg_reg_const(A_SBC,regdst.reghi,regsrc.reghi,hi(value)))
  1133. else
  1134. begin
  1135. tmpreg:=cg.getintregister(list,OS_32);
  1136. cg.a_load_const_reg(list,OS_32,hi(value),tmpreg);
  1137. list.concat(taicpu.op_reg_reg_reg(A_SBC,regdst.reghi,regsrc.reghi,tmpreg));
  1138. cg.ungetregister(list,tmpreg);
  1139. end;
  1140. end;
  1141. else
  1142. internalerror(2003083101);
  1143. end;
  1144. end;
  1145. procedure tcg64farm.a_op64_reg_reg_reg(list: taasmoutput;op:TOpCG;regsrc1,regsrc2,regdst : tregister64);
  1146. begin
  1147. case op of
  1148. OP_AND,OP_OR,OP_XOR:
  1149. begin
  1150. cg.a_op_reg_reg_reg(list,op,OS_32,regsrc1.reglo,regsrc2.reglo,regdst.reglo);
  1151. cg.a_op_reg_reg_reg(list,op,OS_32,regsrc1.reghi,regsrc2.reghi,regdst.reghi);
  1152. end;
  1153. OP_ADD:
  1154. begin
  1155. list.concat(setoppostfix(taicpu.op_reg_reg_reg(A_ADD,regdst.reglo,regsrc1.reglo,regsrc2.reglo),PF_S));
  1156. list.concat(taicpu.op_reg_reg_reg(A_ADC,regdst.reghi,regsrc1.reghi,regsrc2.reghi));
  1157. end;
  1158. OP_SUB:
  1159. begin
  1160. list.concat(setoppostfix(taicpu.op_reg_reg_reg(A_SUB,regdst.reglo,regsrc2.reglo,regsrc1.reglo),PF_S));
  1161. list.concat(taicpu.op_reg_reg_reg(A_SBC,regdst.reghi,regsrc2.reghi,regsrc1.reghi));
  1162. end;
  1163. else
  1164. internalerror(2003083101);
  1165. end;
  1166. end;
  1167. begin
  1168. cg:=tcgarm.create;
  1169. cg64:=tcg64farm.create;
  1170. end.
  1171. {
  1172. $Log$
  1173. Revision 1.51 2004-03-31 19:13:04 florian
  1174. * concatcopy with len=0 exits now immediatly
  1175. Revision 1.50 2004/03/29 19:19:35 florian
  1176. + arm floating point register saving implemented
  1177. * hopefully stabs generation for MacOSX fixed
  1178. + some defines for arm added
  1179. Revision 1.49 2004/03/14 21:42:24 florian
  1180. * optimized mul code generation
  1181. Revision 1.48 2004/03/14 16:15:40 florian
  1182. * spilling problem fixed
  1183. * handling of floating point memory references fixed
  1184. Revision 1.47 2004/03/10 22:35:40 florian
  1185. + fixed code generation for cmn
  1186. Revision 1.46 2004/03/06 20:35:19 florian
  1187. * fixed arm compilation
  1188. * cleaned up code generation for exported linux procedures
  1189. Revision 1.45 2004/03/02 00:36:33 olle
  1190. * big transformation of Tai_[const_]Symbol.Create[data]name*
  1191. Revision 1.44 2004/02/04 22:01:13 peter
  1192. * first try to get cpupara working for x86_64
  1193. Revision 1.43 2004/01/29 17:09:32 florian
  1194. * handling of floating point references fixed
  1195. Revision 1.42 2004/01/28 15:36:47 florian
  1196. * fixed another couple of arm bugs
  1197. Revision 1.41 2004/01/27 15:04:06 florian
  1198. * fixed code generation for math inl. nodes
  1199. * more code generator improvements
  1200. Revision 1.40 2004/01/26 19:05:56 florian
  1201. * fixed several arm issues
  1202. Revision 1.39 2004/01/24 20:19:46 florian
  1203. * fixed some spilling stuff
  1204. + not(<int64>) implemented
  1205. + small set comparisations implemented
  1206. Revision 1.38 2004/01/24 01:33:20 florian
  1207. * fixref fixed if index, base and offset were given
  1208. Revision 1.37 2004/01/22 20:13:18 florian
  1209. * fixed several issues with flags
  1210. Revision 1.36 2004/01/22 02:22:47 florian
  1211. * op_const_reg_reg with OP_SAR fixed
  1212. Revision 1.35 2004/01/22 01:47:15 florian
  1213. * improved register usage
  1214. + implemented second_cmp64bit
  1215. Revision 1.34 2004/01/21 19:01:03 florian
  1216. * fixed handling of max. distance of pc relative symbols
  1217. Revision 1.33 2004/01/21 15:41:56 florian
  1218. * fixed register allocator problems with concatcopy
  1219. Revision 1.32 2004/01/21 14:22:00 florian
  1220. + reintroduce implemented
  1221. Revision 1.31 2004/01/21 01:22:35 florian
  1222. * fixed a_cmp_const_reg_label
  1223. * fixed volatile register handling which was broken by my last patch
  1224. Revision 1.30 2004/01/20 23:18:00 florian
  1225. * fixed a_call_reg
  1226. + implemented paramgr.get_volative_registers
  1227. Revision 1.29 2003/12/26 14:02:30 peter
  1228. * sparc updates
  1229. * use registertype in spill_register
  1230. Revision 1.28 2003/12/18 17:06:21 florian
  1231. * arm compiler compilation fixed
  1232. Revision 1.27 2003/12/08 17:43:57 florian
  1233. * fixed ldm/stm arm assembler reading
  1234. * fixed a_load_reg_reg with OS_8 on ARM
  1235. * non supported calling conventions cause only a warning now
  1236. Revision 1.26 2003/12/03 17:39:05 florian
  1237. * fixed several arm calling conventions issues
  1238. * fixed reference reading in the assembler reader
  1239. * fixed a_loadaddr_ref_reg
  1240. Revision 1.25 2003/11/30 19:35:29 florian
  1241. * fixed several arm related problems
  1242. Revision 1.24 2003/11/24 15:17:37 florian
  1243. * changed some types to prevend range check errors
  1244. Revision 1.23 2003/11/21 16:29:26 florian
  1245. * fixed reading of reg. sets in the arm assembler reader
  1246. Revision 1.22 2003/11/07 15:58:32 florian
  1247. * Florian's culmutative nr. 1; contains:
  1248. - invalid calling conventions for a certain cpu are rejected
  1249. - arm softfloat calling conventions
  1250. - -Sp for cpu dependend code generation
  1251. - several arm fixes
  1252. - remaining code for value open array paras on heap
  1253. Revision 1.21 2003/11/02 14:30:03 florian
  1254. * fixed ARM for new reg. allocation scheme
  1255. Revision 1.20 2003/10/11 16:06:42 florian
  1256. * fixed some MMX<->SSE
  1257. * started to fix ppc, needs an overhaul
  1258. + stabs info improve for spilling, not sure if it works correctly/completly
  1259. - MMX_SUPPORT removed from Makefile.fpc
  1260. Revision 1.19 2003/09/11 11:55:00 florian
  1261. * improved arm code generation
  1262. * move some protected and private field around
  1263. * the temp. register for register parameters/arguments are now released
  1264. before the move to the parameter register is done. This improves
  1265. the code in a lot of cases.
  1266. Revision 1.18 2003/09/09 12:53:40 florian
  1267. * some assembling problems fixed
  1268. * improved loadaddr_ref_reg
  1269. Revision 1.17 2003/09/06 16:45:51 florian
  1270. * fixed exit code (no preindexed addressing mode in LDM)
  1271. Revision 1.16 2003/09/06 11:21:50 florian
  1272. * fixed stm and ldm to be usable with preindex operand
  1273. Revision 1.15 2003/09/05 23:57:01 florian
  1274. * arm is working again as before the new register naming scheme was implemented
  1275. Revision 1.14 2003/09/04 21:07:03 florian
  1276. * ARM compiler compiles again
  1277. Revision 1.13 2003/09/04 00:15:29 florian
  1278. * first bunch of adaptions of arm compiler for new register type
  1279. Revision 1.12 2003/09/03 19:10:30 florian
  1280. * initial revision of new register naming
  1281. Revision 1.11 2003/09/03 11:18:37 florian
  1282. * fixed arm concatcopy
  1283. + arm support in the common compiler sources added
  1284. * moved some generic cg code around
  1285. + tfputype added
  1286. * ...
  1287. Revision 1.10 2003/09/01 15:11:16 florian
  1288. * fixed reference handling
  1289. * fixed operand postfix for floating point instructions
  1290. * fixed wrong shifter constant handling
  1291. Revision 1.9 2003/09/01 09:54:57 florian
  1292. * results of work on arm port last weekend
  1293. Revision 1.8 2003/08/29 21:36:28 florian
  1294. * fixed procedure entry/exit code
  1295. * started to fix reference handling
  1296. Revision 1.7 2003/08/28 13:26:10 florian
  1297. * another couple of arm fixes
  1298. Revision 1.6 2003/08/28 00:05:29 florian
  1299. * today's arm patches
  1300. Revision 1.5 2003/08/25 23:20:38 florian
  1301. + started to implement FPU support for the ARM
  1302. * fixed a lot of other things
  1303. Revision 1.4 2003/08/24 12:27:26 florian
  1304. * continued to work on the arm port
  1305. Revision 1.3 2003/08/21 03:14:00 florian
  1306. * arm compiler can be compiled; far from being working
  1307. Revision 1.2 2003/08/20 15:50:12 florian
  1308. * more arm stuff
  1309. Revision 1.1 2003/07/21 16:35:30 florian
  1310. * very basic stuff for the arm
  1311. }