cgcpu.pas 50 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450
  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. globtype,symtype,symdef,
  24. cgbase,cgutils,cgobj,
  25. aasmbase,aasmcpu,aasmtai,
  26. parabase,
  27. cpubase,cpuinfo,node,cg64f32,rgcpu;
  28. type
  29. tcgarm = class(tcg)
  30. { true, if the next arithmetic operation should modify the flags }
  31. setflags : boolean;
  32. procedure init_register_allocators;override;
  33. procedure done_register_allocators;override;
  34. procedure a_param_const(list : taasmoutput;size : tcgsize;a : aint;const paraloc : TCGPara);override;
  35. procedure a_param_ref(list : taasmoutput;size : tcgsize;const r : treference;const paraloc : TCGPara);override;
  36. procedure a_paramaddr_ref(list : taasmoutput;const r : treference;const paraloc : TCGPara);override;
  37. procedure a_call_name(list : taasmoutput;const s : string);override;
  38. procedure a_call_reg(list : taasmoutput;reg: tregister); override;
  39. procedure a_op_const_reg(list : taasmoutput; Op: TOpCG; size: TCGSize; a: aint; reg: TRegister); override;
  40. procedure a_op_reg_reg(list : taasmoutput; Op: TOpCG; size: TCGSize; src, dst: TRegister); override;
  41. procedure a_op_const_reg_reg(list: taasmoutput; op: TOpCg;
  42. size: tcgsize; a: aint; src, dst: tregister); override;
  43. procedure a_op_reg_reg_reg(list: taasmoutput; op: TOpCg;
  44. size: tcgsize; src1, src2, dst: tregister); override;
  45. { move instructions }
  46. procedure a_load_const_reg(list : taasmoutput; size: tcgsize; a : aint;reg : tregister);override;
  47. procedure a_load_reg_ref(list : taasmoutput; fromsize, tosize: tcgsize; reg : tregister;const ref : treference);override;
  48. procedure a_load_ref_reg(list : taasmoutput; fromsize, tosize : tcgsize;const Ref : treference;reg : tregister);override;
  49. procedure a_load_reg_reg(list : taasmoutput; fromsize, tosize : tcgsize;reg1,reg2 : tregister);override;
  50. { fpu move instructions }
  51. procedure a_loadfpu_reg_reg(list: taasmoutput; size: tcgsize; reg1, reg2: tregister); override;
  52. procedure a_loadfpu_ref_reg(list: taasmoutput; size: tcgsize; const ref: treference; reg: tregister); override;
  53. procedure a_loadfpu_reg_ref(list: taasmoutput; size: tcgsize; reg: tregister; const ref: treference); override;
  54. { comparison operations }
  55. procedure a_cmp_const_reg_label(list : taasmoutput;size : tcgsize;cmp_op : topcmp;a : aint;reg : tregister;
  56. l : tasmlabel);override;
  57. procedure a_cmp_reg_reg_label(list : taasmoutput;size : tcgsize;cmp_op : topcmp;reg1,reg2 : tregister;l : tasmlabel); override;
  58. procedure a_jmp_name(list : taasmoutput;const s : string); override;
  59. procedure a_jmp_always(list : taasmoutput;l: tasmlabel); override;
  60. procedure a_jmp_flags(list : taasmoutput;const f : TResFlags;l: tasmlabel); override;
  61. procedure g_flags2reg(list: taasmoutput; size: TCgSize; const f: TResFlags; reg: TRegister); override;
  62. procedure g_proc_entry(list : taasmoutput;localsize : longint;nostackframe:boolean);override;
  63. procedure g_proc_exit(list : taasmoutput;parasize : longint;nostackframe:boolean); override;
  64. procedure a_loadaddr_ref_reg(list : taasmoutput;const ref : treference;r : tregister);override;
  65. procedure g_concatcopy(list : taasmoutput;const source,dest : treference;len : aint);override;
  66. procedure g_overflowcheck(list: taasmoutput; const l: tlocation; def: tdef); override;
  67. procedure g_save_standard_registers(list : taasmoutput);override;
  68. procedure g_restore_standard_registers(list : taasmoutput);override;
  69. procedure a_jmp_cond(list : taasmoutput;cond : TOpCmp;l: tasmlabel);
  70. procedure fixref(list : taasmoutput;var ref : treference);
  71. procedure handle_load_store(list:taasmoutput;op: tasmop;oppostfix : toppostfix;reg:tregister;ref: treference);
  72. procedure g_intf_wrapper(list: taasmoutput; procdef: tprocdef; const labelname: string; ioffset: longint);override;
  73. end;
  74. tcg64farm = class(tcg64f32)
  75. procedure a_op64_reg_reg(list : taasmoutput;op:TOpCG;regsrc,regdst : tregister64);override;
  76. procedure a_op64_const_reg(list : taasmoutput;op:TOpCG;value : int64;reg : tregister64);override;
  77. procedure a_op64_const_reg_reg(list: taasmoutput;op:TOpCG;value : int64;regsrc,regdst : tregister64);override;
  78. procedure a_op64_reg_reg_reg(list: taasmoutput;op:TOpCG;regsrc1,regsrc2,regdst : tregister64);override;
  79. end;
  80. const
  81. OpCmp2AsmCond : Array[topcmp] of TAsmCond = (C_NONE,C_EQ,C_GT,
  82. C_LT,C_GE,C_LE,C_NE,C_LS,C_CC,C_CS,C_HI);
  83. function is_shifter_const(d : aint;var imm_shift : byte) : boolean;
  84. function get_fpu_postfix(def : tdef) : toppostfix;
  85. implementation
  86. uses
  87. globals,verbose,systems,cutils,
  88. fmodule,
  89. symconst,symsym,
  90. tgobj,
  91. procinfo,cpupi,
  92. paramgr;
  93. function get_fpu_postfix(def : tdef) : toppostfix;
  94. begin
  95. if def.deftype=floatdef then
  96. begin
  97. case tfloatdef(def).typ of
  98. s32real:
  99. result:=PF_S;
  100. s64real:
  101. result:=PF_D;
  102. s80real:
  103. result:=PF_E;
  104. else
  105. internalerror(200401272);
  106. end;
  107. end
  108. else
  109. internalerror(200401271);
  110. end;
  111. procedure tcgarm.init_register_allocators;
  112. begin
  113. inherited init_register_allocators;
  114. { currently, we save R14 always, so we can use it }
  115. rg[R_INTREGISTER]:=trgintcpu.create(R_INTREGISTER,R_SUBWHOLE,
  116. [RS_R0,RS_R1,RS_R2,RS_R3,RS_R4,RS_R5,RS_R6,RS_R7,RS_R8,
  117. RS_R9,RS_R10,RS_R12,RS_R14],first_int_imreg,[]);
  118. rg[R_FPUREGISTER]:=trgcpu.create(R_FPUREGISTER,R_SUBNONE,
  119. [RS_F0,RS_F1,RS_F2,RS_F3,RS_F4,RS_F5,RS_F6,RS_F7],first_fpu_imreg,[]);
  120. rg[R_MMREGISTER]:=trgcpu.create(R_MMREGISTER,R_SUBNONE,
  121. [RS_S0,RS_S1,RS_R2,RS_R3,RS_R4,RS_S31],first_mm_imreg,[]);
  122. end;
  123. procedure tcgarm.done_register_allocators;
  124. begin
  125. rg[R_INTREGISTER].free;
  126. rg[R_FPUREGISTER].free;
  127. rg[R_MMREGISTER].free;
  128. inherited done_register_allocators;
  129. end;
  130. procedure tcgarm.a_param_const(list : taasmoutput;size : tcgsize;a : aint;const paraloc : TCGPara);
  131. var
  132. ref: treference;
  133. begin
  134. paraloc.check_simple_location;
  135. case paraloc.location^.loc of
  136. LOC_REGISTER,LOC_CREGISTER:
  137. a_load_const_reg(list,size,a,paraloc.location^.register);
  138. LOC_REFERENCE:
  139. begin
  140. reference_reset(ref);
  141. ref.base:=paraloc.location^.reference.index;
  142. ref.offset:=paraloc.location^.reference.offset;
  143. a_load_const_ref(list,size,a,ref);
  144. end;
  145. else
  146. internalerror(2002081101);
  147. end;
  148. end;
  149. procedure tcgarm.a_param_ref(list : taasmoutput;size : tcgsize;const r : treference;const paraloc : TCGPara);
  150. var
  151. ref: treference;
  152. tmpreg: tregister;
  153. begin
  154. paraloc.check_simple_location;
  155. case paraloc.location^.loc of
  156. LOC_REGISTER,LOC_CREGISTER:
  157. a_load_ref_reg(list,size,size,r,paraloc.location^.register);
  158. LOC_REFERENCE:
  159. begin
  160. reference_reset(ref);
  161. ref.base:=paraloc.location^.reference.index;
  162. ref.offset:=paraloc.location^.reference.offset;
  163. tmpreg := getintregister(list,size);
  164. a_load_ref_reg(list,size,size,r,tmpreg);
  165. a_load_reg_ref(list,size,size,tmpreg,ref);
  166. end;
  167. LOC_FPUREGISTER,LOC_CFPUREGISTER:
  168. case size of
  169. OS_F32, OS_F64:
  170. a_loadfpu_ref_reg(list,size,r,paraloc.location^.register);
  171. else
  172. internalerror(2002072801);
  173. end;
  174. else
  175. internalerror(2002081103);
  176. end;
  177. end;
  178. procedure tcgarm.a_paramaddr_ref(list : taasmoutput;const r : treference;const paraloc : TCGPara);
  179. var
  180. ref: treference;
  181. tmpreg: tregister;
  182. begin
  183. paraloc.check_simple_location;
  184. case paraloc.location^.loc of
  185. LOC_REGISTER,LOC_CREGISTER:
  186. a_loadaddr_ref_reg(list,r,paraloc.location^.register);
  187. LOC_REFERENCE:
  188. begin
  189. reference_reset(ref);
  190. ref.base := paraloc.location^.reference.index;
  191. ref.offset := paraloc.location^.reference.offset;
  192. tmpreg := getintregister(list,OS_ADDR);
  193. a_loadaddr_ref_reg(list,r,tmpreg);
  194. a_load_reg_ref(list,OS_ADDR,OS_ADDR,tmpreg,ref);
  195. end;
  196. else
  197. internalerror(2002080701);
  198. end;
  199. end;
  200. procedure tcgarm.a_call_name(list : taasmoutput;const s : string);
  201. begin
  202. list.concat(taicpu.op_sym(A_BL,objectlibrary.newasmsymbol(s,AB_EXTERNAL,AT_FUNCTION)));
  203. {
  204. the compiler does not properly set this flag anymore in pass 1, and
  205. for now we only need it after pass 2 (I hope) (JM)
  206. if not(pi_do_call in current_procinfo.flags) then
  207. internalerror(2003060703);
  208. }
  209. include(current_procinfo.flags,pi_do_call);
  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. {
  218. the compiler does not properly set this flag anymore in pass 1, and
  219. for now we only need it after pass 2 (I hope) (JM)
  220. if not(pi_do_call in current_procinfo.flags) then
  221. internalerror(2003060703);
  222. }
  223. include(current_procinfo.flags,pi_do_call);
  224. end;
  225. procedure tcgarm.a_op_const_reg(list : taasmoutput; Op: TOpCG; size: TCGSize; a: aint; reg: TRegister);
  226. begin
  227. a_op_const_reg_reg(list,op,size,a,reg,reg);
  228. end;
  229. procedure tcgarm.a_op_reg_reg(list : taasmoutput; Op: TOpCG; size: TCGSize; src, dst: TRegister);
  230. begin
  231. case op of
  232. OP_NEG:
  233. list.concat(taicpu.op_reg_reg_const(A_RSB,dst,src,0));
  234. OP_NOT:
  235. begin
  236. list.concat(taicpu.op_reg_reg(A_MVN,dst,src));
  237. case size of
  238. OS_8 :
  239. a_op_const_reg_reg(list,OP_AND,OS_INT,$ff,dst,dst);
  240. OS_16 :
  241. a_op_const_reg_reg(list,OP_AND,OS_INT,$ffff,dst,dst);
  242. end;
  243. end
  244. else
  245. a_op_reg_reg_reg(list,op,OS_32,src,dst,dst);
  246. end;
  247. end;
  248. const
  249. op_reg_reg_opcg2asmop: array[TOpCG] of tasmop =
  250. (A_NONE,A_ADD,A_AND,A_NONE,A_NONE,A_MUL,A_MUL,A_NONE,A_NONE,A_ORR,
  251. A_NONE,A_NONE,A_NONE,A_SUB,A_EOR);
  252. procedure tcgarm.a_op_const_reg_reg(list: taasmoutput; op: TOpCg;
  253. size: tcgsize; a: aint; src, dst: tregister);
  254. var
  255. shift : byte;
  256. tmpreg : tregister;
  257. so : tshifterop;
  258. l1 : longint;
  259. begin
  260. if is_shifter_const(-a,shift) then
  261. case op of
  262. OP_ADD:
  263. begin
  264. op:=OP_SUB;
  265. a:=dword(-a);
  266. end;
  267. OP_SUB:
  268. begin
  269. op:=OP_ADD;
  270. a:=dword(-a);
  271. end
  272. end;
  273. if is_shifter_const(a,shift) and not(op in [OP_IMUL,OP_MUL]) then
  274. case op of
  275. OP_NEG,OP_NOT,
  276. OP_DIV,OP_IDIV:
  277. internalerror(200308281);
  278. OP_SHL:
  279. begin
  280. if a>32 then
  281. internalerror(200308291);
  282. if a<>0 then
  283. begin
  284. shifterop_reset(so);
  285. so.shiftmode:=SM_LSL;
  286. so.shiftimm:=a;
  287. list.concat(taicpu.op_reg_reg_shifterop(A_MOV,dst,src,so));
  288. end
  289. else
  290. list.concat(taicpu.op_reg_reg(A_MOV,dst,src));
  291. end;
  292. OP_SHR:
  293. begin
  294. if a>32 then
  295. internalerror(200308292);
  296. shifterop_reset(so);
  297. if a<>0 then
  298. begin
  299. so.shiftmode:=SM_LSR;
  300. so.shiftimm:=a;
  301. list.concat(taicpu.op_reg_reg_shifterop(A_MOV,dst,src,so));
  302. end
  303. else
  304. list.concat(taicpu.op_reg_reg(A_MOV,dst,src));
  305. end;
  306. OP_SAR:
  307. begin
  308. if a>32 then
  309. internalerror(200308291);
  310. if a<>0 then
  311. begin
  312. shifterop_reset(so);
  313. so.shiftmode:=SM_ASR;
  314. so.shiftimm:=a;
  315. list.concat(taicpu.op_reg_reg_shifterop(A_MOV,dst,src,so));
  316. end
  317. else
  318. list.concat(taicpu.op_reg_reg(A_MOV,dst,src));
  319. end;
  320. else
  321. list.concat(taicpu.op_reg_reg_const(op_reg_reg_opcg2asmop[op],dst,src,a));
  322. end
  323. else
  324. begin
  325. { there could be added some more sophisticated optimizations }
  326. if (op in [OP_MUL,OP_IMUL]) and (a=1) then
  327. a_load_reg_reg(list,size,size,src,dst)
  328. else if (op in [OP_MUL,OP_IMUL]) and (a=0) then
  329. a_load_const_reg(list,size,0,dst)
  330. else if (op in [OP_IMUL]) and (a=-1) then
  331. a_op_reg_reg(list,OP_NEG,size,src,dst)
  332. { we do this here instead in the peephole optimizer because
  333. it saves us a register }
  334. else if (op in [OP_MUL,OP_IMUL]) and ispowerof2(a,l1) then
  335. a_op_const_reg_reg(list,OP_SHL,size,l1,src,dst)
  336. else
  337. begin
  338. tmpreg:=getintregister(list,size);
  339. a_load_const_reg(list,size,a,tmpreg);
  340. a_op_reg_reg_reg(list,op,size,tmpreg,src,dst);
  341. end;
  342. end;
  343. end;
  344. procedure tcgarm.a_op_reg_reg_reg(list: taasmoutput; op: TOpCg;
  345. size: tcgsize; src1, src2, dst: tregister);
  346. var
  347. so : tshifterop;
  348. tmpreg : tregister;
  349. begin
  350. case op of
  351. OP_NEG,OP_NOT,
  352. OP_DIV,OP_IDIV:
  353. internalerror(200308281);
  354. OP_SHL:
  355. begin
  356. shifterop_reset(so);
  357. so.rs:=src1;
  358. so.shiftmode:=SM_LSL;
  359. list.concat(taicpu.op_reg_reg_shifterop(A_MOV,dst,src2,so));
  360. end;
  361. OP_SHR:
  362. begin
  363. shifterop_reset(so);
  364. so.rs:=src1;
  365. so.shiftmode:=SM_LSR;
  366. list.concat(taicpu.op_reg_reg_shifterop(A_MOV,dst,src2,so));
  367. end;
  368. OP_SAR:
  369. begin
  370. shifterop_reset(so);
  371. so.rs:=src1;
  372. so.shiftmode:=SM_ASR;
  373. list.concat(taicpu.op_reg_reg_shifterop(A_MOV,dst,src2,so));
  374. end;
  375. OP_IMUL,
  376. OP_MUL:
  377. begin
  378. { the arm doesn't allow that rd and rm are the same }
  379. if dst=src2 then
  380. begin
  381. if dst<>src1 then
  382. list.concat(taicpu.op_reg_reg_reg(A_MUL,dst,src1,src2))
  383. else
  384. begin
  385. tmpreg:=getintregister(list,size);
  386. a_load_reg_reg(list,size,size,src2,dst);
  387. list.concat(taicpu.op_reg_reg_reg(A_MUL,dst,tmpreg,src1));
  388. end;
  389. end
  390. else
  391. list.concat(taicpu.op_reg_reg_reg(A_MUL,dst,src2,src1));
  392. end;
  393. else
  394. list.concat(setoppostfix(taicpu.op_reg_reg_reg(op_reg_reg_opcg2asmop[op],dst,src2,src1),toppostfix(ord(setflags)*ord(PF_S))));
  395. end;
  396. end;
  397. function rotl(d : dword;b : byte) : dword;
  398. begin
  399. result:=(d shr (32-b)) or (d shl b);
  400. end;
  401. function is_shifter_const(d : aint;var imm_shift : byte) : boolean;
  402. var
  403. i : longint;
  404. begin
  405. for i:=0 to 15 do
  406. begin
  407. if (dword(d) and not(rotl($ff,i*2)))=0 then
  408. begin
  409. imm_shift:=i*2;
  410. result:=true;
  411. exit;
  412. end;
  413. end;
  414. result:=false;
  415. end;
  416. procedure tcgarm.a_load_const_reg(list : taasmoutput; size: tcgsize; a : aint;reg : tregister);
  417. var
  418. imm_shift : byte;
  419. l : tasmlabel;
  420. hr : treference;
  421. begin
  422. if not(size in [OS_8,OS_S8,OS_16,OS_S16,OS_32,OS_S32]) then
  423. internalerror(2002090902);
  424. if is_shifter_const(a,imm_shift) then
  425. list.concat(taicpu.op_reg_const(A_MOV,reg,a))
  426. else if is_shifter_const(not(a),imm_shift) then
  427. list.concat(taicpu.op_reg_const(A_MVN,reg,not(a)))
  428. else
  429. begin
  430. reference_reset(hr);
  431. objectlibrary.getlabel(l);
  432. cg.a_label(current_procinfo.aktlocaldata,l);
  433. hr.symboldata:=current_procinfo.aktlocaldata.last;
  434. current_procinfo.aktlocaldata.concat(tai_const.Create_32bit(longint(a)));
  435. hr.symbol:=l;
  436. list.concat(taicpu.op_reg_ref(A_LDR,reg,hr));
  437. end;
  438. end;
  439. procedure tcgarm.handle_load_store(list:taasmoutput;op: tasmop;oppostfix : toppostfix;reg:tregister;ref: treference);
  440. var
  441. tmpreg : tregister;
  442. tmpref : treference;
  443. l : tasmlabel;
  444. begin
  445. tmpreg:=NR_NO;
  446. { Be sure to have a base register }
  447. if (ref.base=NR_NO) then
  448. begin
  449. if ref.shiftmode<>SM_None then
  450. internalerror(200308294);
  451. ref.base:=ref.index;
  452. ref.index:=NR_NO;
  453. end;
  454. { absolute symbols can't be handled directly, we've to store the symbol reference
  455. in the text segment and access it pc relative
  456. For now, we assume that references where base or index equals to PC are already
  457. relative, all other references are assumed to be absolute and thus they need
  458. to be handled extra.
  459. A proper solution would be to change refoptions to a set and store the information
  460. if the symbol is absolute or relative there.
  461. }
  462. if (assigned(ref.symbol) and
  463. not(is_pc(ref.base)) and
  464. not(is_pc(ref.index))
  465. ) or
  466. (ref.offset<-4095) or
  467. (ref.offset>4095) or
  468. ((oppostfix in [PF_SB,PF_H,PF_SH]) and
  469. ((ref.offset<-255) or
  470. (ref.offset>255)
  471. )
  472. ) or
  473. ((op in [A_LDF,A_STF]) and
  474. ((ref.offset<-1020) or
  475. (ref.offset>1020)
  476. )
  477. ) then
  478. begin
  479. reference_reset(tmpref);
  480. { create consts entry }
  481. objectlibrary.getlabel(l);
  482. cg.a_label(current_procinfo.aktlocaldata,l);
  483. tmpref.symboldata:=current_procinfo.aktlocaldata.last;
  484. if assigned(ref.symbol) then
  485. current_procinfo.aktlocaldata.concat(tai_const.create_sym_offset(ref.symbol,ref.offset))
  486. else
  487. current_procinfo.aktlocaldata.concat(tai_const.Create_32bit(ref.offset));
  488. { load consts entry }
  489. tmpreg:=getintregister(list,OS_INT);
  490. tmpref.symbol:=l;
  491. tmpref.base:=NR_R15;
  492. list.concat(taicpu.op_reg_ref(A_LDR,tmpreg,tmpref));
  493. if (ref.base<>NR_NO) then
  494. begin
  495. if ref.index<>NR_NO then
  496. begin
  497. list.concat(taicpu.op_reg_reg_reg(A_ADD,tmpreg,ref.base,tmpreg));
  498. ref.base:=tmpreg;
  499. end
  500. else
  501. begin
  502. ref.index:=tmpreg;
  503. ref.shiftimm:=0;
  504. ref.signindex:=1;
  505. ref.shiftmode:=SM_None;
  506. end;
  507. end
  508. else
  509. ref.base:=tmpreg;
  510. ref.offset:=0;
  511. ref.symbol:=nil;
  512. end;
  513. if (ref.base<>NR_NO) and (ref.index<>NR_NO) and (ref.offset<>0) then
  514. begin
  515. if tmpreg<>NR_NO then
  516. a_op_const_reg_reg(list,OP_ADD,OS_ADDR,ref.offset,tmpreg,tmpreg)
  517. else
  518. begin
  519. tmpreg:=getintregister(list,OS_ADDR);
  520. a_op_const_reg_reg(list,OP_ADD,OS_ADDR,ref.offset,ref.base,tmpreg);
  521. ref.base:=tmpreg;
  522. end;
  523. ref.offset:=0;
  524. end;
  525. { floating point operations have only limited references
  526. we expect here, that a base is already set }
  527. if (op in [A_LDF,A_STF]) and (ref.index<>NR_NO) then
  528. begin
  529. if ref.shiftmode<>SM_none then
  530. internalerror(200309121);
  531. if tmpreg<>NR_NO then
  532. begin
  533. if ref.base=tmpreg then
  534. begin
  535. if ref.signindex<0 then
  536. list.concat(taicpu.op_reg_reg_reg(A_SUB,tmpreg,tmpreg,ref.index))
  537. else
  538. list.concat(taicpu.op_reg_reg_reg(A_ADD,tmpreg,tmpreg,ref.index));
  539. ref.index:=NR_NO;
  540. end
  541. else
  542. begin
  543. if ref.index<>tmpreg then
  544. internalerror(200403161);
  545. if ref.signindex<0 then
  546. list.concat(taicpu.op_reg_reg_reg(A_SUB,tmpreg,ref.base,tmpreg))
  547. else
  548. list.concat(taicpu.op_reg_reg_reg(A_ADD,tmpreg,ref.base,tmpreg));
  549. ref.base:=tmpreg;
  550. ref.index:=NR_NO;
  551. end;
  552. end
  553. else
  554. begin
  555. tmpreg:=getintregister(list,OS_ADDR);
  556. list.concat(taicpu.op_reg_reg_reg(A_ADD,tmpreg,ref.base,ref.index));
  557. ref.base:=tmpreg;
  558. ref.index:=NR_NO;
  559. end;
  560. end;
  561. list.concat(setoppostfix(taicpu.op_reg_ref(op,reg,ref),oppostfix));
  562. end;
  563. procedure tcgarm.a_load_reg_ref(list : taasmoutput; fromsize, tosize: tcgsize; reg : tregister;const ref : treference);
  564. var
  565. oppostfix:toppostfix;
  566. begin
  567. case ToSize of
  568. { signed integer registers }
  569. OS_8,
  570. OS_S8:
  571. oppostfix:=PF_B;
  572. OS_16,
  573. OS_S16:
  574. oppostfix:=PF_H;
  575. OS_32,
  576. OS_S32:
  577. oppostfix:=PF_None;
  578. else
  579. InternalError(200308295);
  580. end;
  581. handle_load_store(list,A_STR,oppostfix,reg,ref);
  582. end;
  583. procedure tcgarm.a_load_ref_reg(list : taasmoutput; fromsize, tosize : tcgsize;const Ref : treference;reg : tregister);
  584. var
  585. oppostfix:toppostfix;
  586. begin
  587. case FromSize of
  588. { signed integer registers }
  589. OS_8:
  590. oppostfix:=PF_B;
  591. OS_S8:
  592. oppostfix:=PF_SB;
  593. OS_16:
  594. oppostfix:=PF_H;
  595. OS_S16:
  596. oppostfix:=PF_SH;
  597. OS_32,
  598. OS_S32:
  599. oppostfix:=PF_None;
  600. else
  601. InternalError(200308291);
  602. end;
  603. handle_load_store(list,A_LDR,oppostfix,reg,ref);
  604. end;
  605. procedure tcgarm.a_load_reg_reg(list : taasmoutput; fromsize, tosize : tcgsize;reg1,reg2 : tregister);
  606. var
  607. instr: taicpu;
  608. so : tshifterop;
  609. begin
  610. shifterop_reset(so);
  611. if (tcgsize2size[tosize] < tcgsize2size[fromsize]) or
  612. (
  613. (tcgsize2size[tosize] = tcgsize2size[fromsize]) and
  614. (tosize <> fromsize) and
  615. not(fromsize in [OS_32,OS_S32])
  616. ) then
  617. begin
  618. case tosize of
  619. OS_8:
  620. list.concat(taicpu.op_reg_reg_const(A_AND,
  621. reg2,reg1,$ff));
  622. OS_S8:
  623. begin
  624. so.shiftmode:=SM_LSL;
  625. so.shiftimm:=24;
  626. list.concat(taicpu.op_reg_reg_shifterop(A_MOV,reg2,reg1,so));
  627. so.shiftmode:=SM_ASR;
  628. so.shiftimm:=24;
  629. list.concat(taicpu.op_reg_reg_shifterop(A_MOV,reg2,reg2,so));
  630. end;
  631. OS_16:
  632. begin
  633. so.shiftmode:=SM_LSL;
  634. so.shiftimm:=16;
  635. list.concat(taicpu.op_reg_reg_shifterop(A_MOV,reg2,reg1,so));
  636. so.shiftmode:=SM_LSR;
  637. so.shiftimm:=16;
  638. list.concat(taicpu.op_reg_reg_shifterop(A_MOV,reg2,reg2,so));
  639. end;
  640. OS_S16:
  641. begin
  642. so.shiftmode:=SM_LSL;
  643. so.shiftimm:=16;
  644. list.concat(taicpu.op_reg_reg_shifterop(A_MOV,reg2,reg1,so));
  645. so.shiftmode:=SM_ASR;
  646. so.shiftimm:=16;
  647. list.concat(taicpu.op_reg_reg_shifterop(A_MOV,reg2,reg2,so));
  648. end;
  649. OS_32,OS_S32:
  650. begin
  651. instr:=taicpu.op_reg_reg(A_MOV,reg2,reg1);
  652. list.concat(instr);
  653. add_move_instruction(instr);
  654. end;
  655. else internalerror(2002090901);
  656. end;
  657. end
  658. else
  659. begin
  660. if reg1<>reg2 then
  661. begin
  662. { same size, only a register mov required }
  663. instr:=taicpu.op_reg_reg(A_MOV,reg2,reg1);
  664. list.Concat(instr);
  665. { Notify the register allocator that we have written a move instruction so
  666. it can try to eliminate it. }
  667. add_move_instruction(instr);
  668. end;
  669. end;
  670. end;
  671. procedure tcgarm.a_loadfpu_reg_reg(list: taasmoutput; size: tcgsize; reg1, reg2: tregister);
  672. begin
  673. list.concat(setoppostfix(taicpu.op_reg_reg(A_MVF,reg2,reg1),cgsize2fpuoppostfix[size]));
  674. end;
  675. procedure tcgarm.a_loadfpu_ref_reg(list: taasmoutput; size: tcgsize; const ref: treference; reg: tregister);
  676. var
  677. oppostfix:toppostfix;
  678. begin
  679. case size of
  680. OS_F32:
  681. oppostfix:=PF_S;
  682. OS_F64:
  683. oppostfix:=PF_D;
  684. OS_F80:
  685. oppostfix:=PF_E;
  686. else
  687. InternalError(200309021);
  688. end;
  689. handle_load_store(list,A_LDF,oppostfix,reg,ref);
  690. end;
  691. procedure tcgarm.a_loadfpu_reg_ref(list: taasmoutput; size: tcgsize; reg: tregister; const ref: treference);
  692. var
  693. oppostfix:toppostfix;
  694. begin
  695. case size of
  696. OS_F32:
  697. oppostfix:=PF_S;
  698. OS_F64:
  699. oppostfix:=PF_D;
  700. OS_F80:
  701. oppostfix:=PF_E;
  702. else
  703. InternalError(200309021);
  704. end;
  705. handle_load_store(list,A_STF,oppostfix,reg,ref);
  706. end;
  707. { comparison operations }
  708. procedure tcgarm.a_cmp_const_reg_label(list : taasmoutput;size : tcgsize;cmp_op : topcmp;a : aint;reg : tregister;
  709. l : tasmlabel);
  710. var
  711. tmpreg : tregister;
  712. b : byte;
  713. begin
  714. if is_shifter_const(a,b) then
  715. list.concat(taicpu.op_reg_const(A_CMP,reg,a))
  716. { CMN reg,0 and CMN reg,$80000000 are different from CMP reg,$ffffffff
  717. and CMP reg,$7fffffff regarding the flags according to the ARM manual }
  718. else if (a<>$7fffffff) and (a<>-1) and is_shifter_const(-a,b) then
  719. list.concat(taicpu.op_reg_const(A_CMN,reg,-a))
  720. else
  721. begin
  722. tmpreg:=getintregister(list,size);
  723. a_load_const_reg(list,size,a,tmpreg);
  724. list.concat(taicpu.op_reg_reg(A_CMP,reg,tmpreg));
  725. end;
  726. a_jmp_cond(list,cmp_op,l);
  727. end;
  728. procedure tcgarm.a_cmp_reg_reg_label(list : taasmoutput;size : tcgsize;cmp_op : topcmp;reg1,reg2 : tregister;l : tasmlabel);
  729. begin
  730. list.concat(taicpu.op_reg_reg(A_CMP,reg2,reg1));
  731. a_jmp_cond(list,cmp_op,l);
  732. end;
  733. procedure tcgarm.a_jmp_name(list : taasmoutput;const s : string);
  734. begin
  735. list.concat(taicpu.op_sym(A_B,objectlibrary.newasmsymbol(s,AB_EXTERNAL,AT_FUNCTION)));
  736. end;
  737. procedure tcgarm.a_jmp_always(list : taasmoutput;l: tasmlabel);
  738. begin
  739. list.concat(taicpu.op_sym(A_B,objectlibrary.newasmsymbol(l.name,AB_EXTERNAL,AT_FUNCTION)));
  740. end;
  741. procedure tcgarm.a_jmp_flags(list : taasmoutput;const f : TResFlags;l: tasmlabel);
  742. var
  743. ai : taicpu;
  744. begin
  745. ai:=setcondition(taicpu.op_sym(A_B,l),flags_to_cond(f));
  746. ai.is_jmp:=true;
  747. list.concat(ai);
  748. end;
  749. procedure tcgarm.g_flags2reg(list: taasmoutput; size: TCgSize; const f: TResFlags; reg: TRegister);
  750. var
  751. ai : taicpu;
  752. begin
  753. list.concat(setcondition(taicpu.op_reg_const(A_MOV,reg,1),flags_to_cond(f)));
  754. list.concat(setcondition(taicpu.op_reg_const(A_MOV,reg,0),inverse_cond[flags_to_cond(f)]));
  755. end;
  756. procedure tcgarm.g_proc_entry(list : taasmoutput;localsize : longint;nostackframe:boolean);
  757. var
  758. ref : treference;
  759. shift : byte;
  760. firstfloatreg,lastfloatreg,
  761. r : byte;
  762. begin
  763. LocalSize:=align(LocalSize,4);
  764. if not(nostackframe) then
  765. begin
  766. firstfloatreg:=RS_NO;
  767. { save floating point registers? }
  768. for r:=RS_F0 to RS_F7 do
  769. if r in rg[R_FPUREGISTER].used_in_proc-paramanager.get_volatile_registers_fpu(pocall_stdcall) then
  770. begin
  771. if firstfloatreg=RS_NO then
  772. firstfloatreg:=r;
  773. lastfloatreg:=r;
  774. end;
  775. a_reg_alloc(list,NR_STACK_POINTER_REG);
  776. a_reg_alloc(list,NR_FRAME_POINTER_REG);
  777. a_reg_alloc(list,NR_R12);
  778. list.concat(taicpu.op_reg_reg(A_MOV,NR_R12,NR_STACK_POINTER_REG));
  779. { save int registers }
  780. reference_reset(ref);
  781. ref.index:=NR_STACK_POINTER_REG;
  782. ref.addressmode:=AM_PREINDEXED;
  783. list.concat(setoppostfix(taicpu.op_ref_regset(A_STM,ref,
  784. rg[R_INTREGISTER].used_in_proc-paramanager.get_volatile_registers_int(pocall_stdcall)+[RS_R11,RS_R12,RS_R14,RS_R15]),
  785. PF_FD));
  786. list.concat(taicpu.op_reg_reg_const(A_SUB,NR_FRAME_POINTER_REG,NR_R12,4));
  787. { allocate necessary stack size }
  788. { don't use a_op_const_reg_reg here because we don't allow register allocations
  789. in the entry/exit code }
  790. if not(is_shifter_const(localsize,shift)) then
  791. begin
  792. a_load_const_reg(list,OS_ADDR,LocalSize,NR_R12);
  793. list.concat(taicpu.op_reg_reg_reg(A_SUB,NR_STACK_POINTER_REG,NR_STACK_POINTER_REG,NR_R12));
  794. a_reg_dealloc(list,NR_R12);
  795. end
  796. else
  797. begin
  798. a_reg_dealloc(list,NR_R12);
  799. list.concat(taicpu.op_reg_reg_const(A_SUB,NR_STACK_POINTER_REG,NR_STACK_POINTER_REG,LocalSize));
  800. end;
  801. if firstfloatreg<>RS_NO then
  802. begin
  803. reference_reset(ref);
  804. ref.base:=NR_FRAME_POINTER_REG;
  805. ref.offset:=tarmprocinfo(current_procinfo).floatregstart;
  806. list.concat(taicpu.op_reg_const_ref(A_SFM,newreg(R_FPUREGISTER,firstfloatreg,R_SUBWHOLE),
  807. lastfloatreg-firstfloatreg+1,ref));
  808. end;
  809. end;
  810. end;
  811. procedure tcgarm.g_proc_exit(list : taasmoutput;parasize : longint;nostackframe:boolean);
  812. var
  813. ref : treference;
  814. firstfloatreg,lastfloatreg,
  815. r : byte;
  816. begin
  817. if not(nostackframe) then
  818. begin
  819. { restore floating point register }
  820. firstfloatreg:=RS_NO;
  821. { save floating point registers? }
  822. for r:=RS_F0 to RS_F7 do
  823. if r in rg[R_FPUREGISTER].used_in_proc-paramanager.get_volatile_registers_fpu(pocall_stdcall) then
  824. begin
  825. if firstfloatreg=RS_NO then
  826. firstfloatreg:=r;
  827. lastfloatreg:=r;
  828. end;
  829. if firstfloatreg<>RS_NO then
  830. begin
  831. reference_reset(ref);
  832. ref.base:=NR_FRAME_POINTER_REG;
  833. ref.offset:=tarmprocinfo(current_procinfo).floatregstart;
  834. list.concat(taicpu.op_reg_const_ref(A_LFM,newreg(R_FPUREGISTER,firstfloatreg,R_SUBWHOLE),
  835. lastfloatreg-firstfloatreg+1,ref));
  836. end;
  837. if (current_procinfo.framepointer=NR_STACK_POINTER_REG) then
  838. list.concat(taicpu.op_reg_reg(A_MOV,NR_R15,NR_R14))
  839. else
  840. begin
  841. { restore int registers and return }
  842. reference_reset(ref);
  843. ref.index:=NR_FRAME_POINTER_REG;
  844. 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));
  845. end;
  846. end
  847. else
  848. list.concat(taicpu.op_reg_reg(A_MOV,NR_PC,NR_R14));
  849. end;
  850. procedure tcgarm.a_loadaddr_ref_reg(list : taasmoutput;const ref : treference;r : tregister);
  851. var
  852. b : byte;
  853. tmpref : treference;
  854. instr : taicpu;
  855. begin
  856. if ref.addressmode<>AM_OFFSET then
  857. internalerror(200309071);
  858. tmpref:=ref;
  859. { Be sure to have a base register }
  860. if (tmpref.base=NR_NO) then
  861. begin
  862. if tmpref.shiftmode<>SM_None then
  863. internalerror(200308294);
  864. if tmpref.signindex<0 then
  865. internalerror(200312023);
  866. tmpref.base:=tmpref.index;
  867. tmpref.index:=NR_NO;
  868. end;
  869. if assigned(tmpref.symbol) or
  870. not((is_shifter_const(tmpref.offset,b)) or
  871. (is_shifter_const(-tmpref.offset,b))
  872. ) then
  873. fixref(list,tmpref);
  874. { expect a base here }
  875. if tmpref.base=NR_NO then
  876. internalerror(200312022);
  877. if tmpref.index<>NR_NO then
  878. begin
  879. if tmpref.shiftmode<>SM_None then
  880. internalerror(200312021);
  881. if tmpref.signindex<0 then
  882. a_op_reg_reg_reg(list,OP_SUB,OS_ADDR,tmpref.base,tmpref.index,r)
  883. else
  884. a_op_reg_reg_reg(list,OP_ADD,OS_ADDR,tmpref.base,tmpref.index,r);
  885. if tmpref.offset<>0 then
  886. a_op_const_reg_reg(list,OP_ADD,OS_ADDR,tmpref.offset,r,r);
  887. end
  888. else
  889. begin
  890. if tmpref.offset<>0 then
  891. a_op_const_reg_reg(list,OP_ADD,OS_ADDR,tmpref.offset,tmpref.base,r)
  892. else
  893. begin
  894. instr:=taicpu.op_reg_reg(A_MOV,r,tmpref.base);
  895. list.concat(instr);
  896. add_move_instruction(instr);
  897. end;
  898. end;
  899. end;
  900. procedure tcgarm.fixref(list : taasmoutput;var ref : treference);
  901. var
  902. tmpreg : tregister;
  903. tmpref : treference;
  904. l : tasmlabel;
  905. begin
  906. { absolute symbols can't be handled directly, we've to store the symbol reference
  907. in the text segment and access it pc relative
  908. For now, we assume that references where base or index equals to PC are already
  909. relative, all other references are assumed to be absolute and thus they need
  910. to be handled extra.
  911. A proper solution would be to change refoptions to a set and store the information
  912. if the symbol is absolute or relative there.
  913. }
  914. { create consts entry }
  915. reference_reset(tmpref);
  916. objectlibrary.getlabel(l);
  917. cg.a_label(current_procinfo.aktlocaldata,l);
  918. tmpref.symboldata:=current_procinfo.aktlocaldata.last;
  919. if assigned(ref.symbol) then
  920. current_procinfo.aktlocaldata.concat(tai_const.create_sym_offset(ref.symbol,ref.offset))
  921. else
  922. current_procinfo.aktlocaldata.concat(tai_const.Create_32bit(ref.offset));
  923. { load consts entry }
  924. tmpreg:=getintregister(list,OS_INT);
  925. tmpref.symbol:=l;
  926. tmpref.base:=NR_PC;
  927. list.concat(taicpu.op_reg_ref(A_LDR,tmpreg,tmpref));
  928. if (ref.base<>NR_NO) then
  929. begin
  930. if ref.index<>NR_NO then
  931. begin
  932. list.concat(taicpu.op_reg_reg_reg(A_ADD,tmpreg,ref.base,tmpreg));
  933. ref.base:=tmpreg;
  934. end
  935. else
  936. begin
  937. ref.index:=tmpreg;
  938. ref.shiftimm:=0;
  939. ref.signindex:=1;
  940. ref.shiftmode:=SM_None;
  941. end;
  942. end
  943. else
  944. ref.base:=tmpreg;
  945. ref.offset:=0;
  946. ref.symbol:=nil;
  947. end;
  948. procedure tcgarm.g_concatcopy(list : taasmoutput;const source,dest : treference;len : aint);
  949. var
  950. srcref,dstref:treference;
  951. srcreg,destreg,countreg,r:tregister;
  952. helpsize:aword;
  953. copysize:byte;
  954. cgsize:Tcgsize;
  955. procedure genloop(count : aword;size : byte);
  956. const
  957. size2opsize : array[1..4] of tcgsize = (OS_8,OS_16,OS_NO,OS_32);
  958. var
  959. l : tasmlabel;
  960. begin
  961. objectlibrary.getlabel(l);
  962. a_load_const_reg(list,OS_INT,count,countreg);
  963. cg.a_label(list,l);
  964. srcref.addressmode:=AM_POSTINDEXED;
  965. dstref.addressmode:=AM_POSTINDEXED;
  966. srcref.offset:=size;
  967. dstref.offset:=size;
  968. r:=getintregister(list,size2opsize[size]);
  969. a_load_ref_reg(list,size2opsize[size],size2opsize[size],srcref,r);
  970. a_load_reg_ref(list,size2opsize[size],size2opsize[size],r,dstref);
  971. list.concat(setoppostfix(taicpu.op_reg_reg_const(A_SUB,countreg,countreg,1),PF_S));
  972. list.concat(setcondition(taicpu.op_sym(A_B,l),C_NE));
  973. { keep the registers alive }
  974. list.concat(taicpu.op_reg_reg(A_MOV,countreg,countreg));
  975. list.concat(taicpu.op_reg_reg(A_MOV,srcreg,srcreg));
  976. list.concat(taicpu.op_reg_reg(A_MOV,destreg,destreg));
  977. end;
  978. begin
  979. if len=0 then
  980. exit;
  981. helpsize:=12;
  982. dstref:=dest;
  983. srcref:=source;
  984. if cs_littlesize in aktglobalswitches then
  985. helpsize:=8;
  986. if (len<=helpsize) then
  987. begin
  988. copysize:=4;
  989. cgsize:=OS_32;
  990. while len<>0 do
  991. begin
  992. if len<2 then
  993. begin
  994. copysize:=1;
  995. cgsize:=OS_8;
  996. end
  997. else if len<4 then
  998. begin
  999. copysize:=2;
  1000. cgsize:=OS_16;
  1001. end;
  1002. dec(len,copysize);
  1003. r:=getintregister(list,cgsize);
  1004. a_load_ref_reg(list,cgsize,cgsize,srcref,r);
  1005. a_load_reg_ref(list,cgsize,cgsize,r,dstref);
  1006. inc(srcref.offset,copysize);
  1007. inc(dstref.offset,copysize);
  1008. end;
  1009. end
  1010. else
  1011. begin
  1012. destreg:=getintregister(list,OS_ADDR);
  1013. a_loadaddr_ref_reg(list,dest,destreg);
  1014. reference_reset_base(dstref,destreg,0);
  1015. srcreg:=getintregister(list,OS_ADDR);
  1016. a_loadaddr_ref_reg(list,source,srcreg);
  1017. reference_reset_base(srcref,srcreg,0);
  1018. countreg:=getintregister(list,OS_32);
  1019. // if cs_littlesize in aktglobalswitches then
  1020. genloop(len,1);
  1021. {
  1022. else
  1023. begin
  1024. helpsize:=len shr 2;
  1025. len:=len and 3;
  1026. if helpsize>1 then
  1027. begin
  1028. a_load_const_reg(list,OS_INT,helpsize,countreg);
  1029. list.concat(Taicpu.op_none(A_REP,S_NO));
  1030. end;
  1031. if helpsize>0 then
  1032. list.concat(Taicpu.op_none(A_MOVSD,S_NO));
  1033. if len>1 then
  1034. begin
  1035. dec(len,2);
  1036. list.concat(Taicpu.op_none(A_MOVSW,S_NO));
  1037. end;
  1038. if len=1 then
  1039. list.concat(Taicpu.op_none(A_MOVSB,S_NO));
  1040. end;
  1041. }
  1042. end;
  1043. end;
  1044. procedure tcgarm.g_overflowcheck(list: taasmoutput; const l: tlocation; def: tdef);
  1045. begin
  1046. end;
  1047. procedure tcgarm.g_save_standard_registers(list : taasmoutput);
  1048. begin
  1049. { this work is done in g_proc_entry }
  1050. end;
  1051. procedure tcgarm.g_restore_standard_registers(list : taasmoutput);
  1052. begin
  1053. { this work is done in g_proc_exit }
  1054. end;
  1055. procedure tcgarm.a_jmp_cond(list : taasmoutput;cond : TOpCmp;l: tasmlabel);
  1056. var
  1057. ai : taicpu;
  1058. begin
  1059. ai:=Taicpu.Op_sym(A_B,l);
  1060. ai.SetCondition(OpCmp2AsmCond[cond]);
  1061. ai.is_jmp:=true;
  1062. list.concat(ai);
  1063. end;
  1064. procedure tcgarm.g_intf_wrapper(list: taasmoutput; procdef: tprocdef; const labelname: string; ioffset: longint);
  1065. procedure loadvmttor12;
  1066. var
  1067. href : treference;
  1068. begin
  1069. reference_reset_base(href,NR_R0,0);
  1070. cg.a_load_ref_reg(list,OS_ADDR,OS_ADDR,href,NR_R12);
  1071. end;
  1072. procedure op_onr12methodaddr;
  1073. var
  1074. href : treference;
  1075. begin
  1076. if (procdef.extnumber=$ffff) then
  1077. Internalerror(200006139);
  1078. { call/jmp vmtoffs(%eax) ; method offs }
  1079. reference_reset_base(href,NR_R12,procdef._class.vmtmethodoffset(procdef.extnumber));
  1080. cg.a_load_ref_reg(list,OS_ADDR,OS_ADDR,href,NR_R12);
  1081. list.concat(taicpu.op_reg_reg(A_MOV,NR_PC,NR_R12));
  1082. end;
  1083. var
  1084. lab : tasmsymbol;
  1085. make_global : boolean;
  1086. href : treference;
  1087. begin
  1088. if procdef.proctypeoption<>potype_none then
  1089. Internalerror(200006137);
  1090. if not assigned(procdef._class) or
  1091. (procdef.procoptions*[po_classmethod, po_staticmethod,
  1092. po_methodpointer, po_interrupt, po_iocheck]<>[]) then
  1093. Internalerror(200006138);
  1094. if procdef.owner.symtabletype<>objectsymtable then
  1095. Internalerror(200109191);
  1096. make_global:=false;
  1097. if (not current_module.is_unit) or
  1098. (cs_create_smart in aktmoduleswitches) or
  1099. (procdef.owner.defowner.owner.symtabletype=globalsymtable) then
  1100. make_global:=true;
  1101. if make_global then
  1102. list.concat(Tai_symbol.Createname_global(labelname,AT_FUNCTION,0))
  1103. else
  1104. list.concat(Tai_symbol.Createname(labelname,AT_FUNCTION,0));
  1105. { set param1 interface to self }
  1106. g_adjust_self_value(list,procdef,ioffset);
  1107. { case 4 }
  1108. if po_virtualmethod in procdef.procoptions then
  1109. begin
  1110. loadvmttor12;
  1111. op_onr12methodaddr;
  1112. end
  1113. { case 0 }
  1114. else
  1115. list.concat(taicpu.op_sym(A_B,objectlibrary.newasmsymbol(procdef.mangledname,AB_EXTERNAL,AT_FUNCTION)));
  1116. list.concat(Tai_symbol_end.Createname(labelname));
  1117. end;
  1118. procedure tcg64farm.a_op64_reg_reg(list : taasmoutput;op:TOpCG;regsrc,regdst : tregister64);
  1119. var
  1120. tmpreg : tregister;
  1121. begin
  1122. case op of
  1123. OP_NEG:
  1124. begin
  1125. list.concat(setoppostfix(taicpu.op_reg_reg_const(A_RSB,regdst.reglo,regsrc.reglo,0),PF_S));
  1126. list.concat(taicpu.op_reg_reg_const(A_RSC,regdst.reghi,regsrc.reghi,0));
  1127. end;
  1128. OP_NOT:
  1129. begin
  1130. cg.a_op_reg_reg(list,OP_NOT,OS_INT,regsrc.reglo,regdst.reglo);
  1131. cg.a_op_reg_reg(list,OP_NOT,OS_INT,regsrc.reghi,regdst.reghi);
  1132. end;
  1133. else
  1134. a_op64_reg_reg_reg(list,op,regsrc,regdst,regdst);
  1135. end;
  1136. end;
  1137. procedure tcg64farm.a_op64_const_reg(list : taasmoutput;op:TOpCG;value : int64;reg : tregister64);
  1138. begin
  1139. a_op64_const_reg_reg(list,op,value,reg,reg);
  1140. end;
  1141. procedure tcg64farm.a_op64_const_reg_reg(list: taasmoutput;op:TOpCG;value : int64;regsrc,regdst : tregister64);
  1142. var
  1143. tmpreg : tregister;
  1144. b : byte;
  1145. begin
  1146. case op of
  1147. OP_AND,OP_OR,OP_XOR:
  1148. begin
  1149. cg.a_op_const_reg_reg(list,op,OS_32,lo(value),regsrc.reglo,regdst.reglo);
  1150. cg.a_op_const_reg_reg(list,op,OS_32,hi(value),regsrc.reghi,regdst.reghi);
  1151. end;
  1152. OP_ADD:
  1153. begin
  1154. if is_shifter_const(lo(value),b) then
  1155. list.concat(setoppostfix(taicpu.op_reg_reg_const(A_ADD,regdst.reglo,regsrc.reglo,lo(value)),PF_S))
  1156. else
  1157. begin
  1158. tmpreg:=cg.getintregister(list,OS_32);
  1159. cg.a_load_const_reg(list,OS_32,lo(value),tmpreg);
  1160. list.concat(setoppostfix(taicpu.op_reg_reg_reg(A_ADD,regdst.reglo,regsrc.reglo,tmpreg),PF_S));
  1161. end;
  1162. if is_shifter_const(hi(value),b) then
  1163. list.concat(taicpu.op_reg_reg_const(A_ADC,regdst.reghi,regsrc.reghi,hi(value)))
  1164. else
  1165. begin
  1166. tmpreg:=cg.getintregister(list,OS_32);
  1167. cg.a_load_const_reg(list,OS_32,hi(value),tmpreg);
  1168. list.concat(taicpu.op_reg_reg_reg(A_ADC,regdst.reghi,regsrc.reghi,tmpreg));
  1169. end;
  1170. end;
  1171. OP_SUB:
  1172. begin
  1173. if is_shifter_const(lo(value),b) then
  1174. list.concat(setoppostfix(taicpu.op_reg_reg_const(A_SUB,regdst.reglo,regsrc.reglo,lo(value)),PF_S))
  1175. else
  1176. begin
  1177. tmpreg:=cg.getintregister(list,OS_32);
  1178. cg.a_load_const_reg(list,OS_32,lo(value),tmpreg);
  1179. list.concat(setoppostfix(taicpu.op_reg_reg_reg(A_SUB,regdst.reglo,regsrc.reglo,tmpreg),PF_S));
  1180. end;
  1181. if is_shifter_const(hi(value),b) then
  1182. list.concat(taicpu.op_reg_reg_const(A_SBC,regdst.reghi,regsrc.reghi,hi(value)))
  1183. else
  1184. begin
  1185. tmpreg:=cg.getintregister(list,OS_32);
  1186. cg.a_load_const_reg(list,OS_32,hi(value),tmpreg);
  1187. list.concat(taicpu.op_reg_reg_reg(A_SBC,regdst.reghi,regsrc.reghi,tmpreg));
  1188. end;
  1189. end;
  1190. else
  1191. internalerror(2003083101);
  1192. end;
  1193. end;
  1194. procedure tcg64farm.a_op64_reg_reg_reg(list: taasmoutput;op:TOpCG;regsrc1,regsrc2,regdst : tregister64);
  1195. begin
  1196. case op of
  1197. OP_AND,OP_OR,OP_XOR:
  1198. begin
  1199. cg.a_op_reg_reg_reg(list,op,OS_32,regsrc1.reglo,regsrc2.reglo,regdst.reglo);
  1200. cg.a_op_reg_reg_reg(list,op,OS_32,regsrc1.reghi,regsrc2.reghi,regdst.reghi);
  1201. end;
  1202. OP_ADD:
  1203. begin
  1204. list.concat(setoppostfix(taicpu.op_reg_reg_reg(A_ADD,regdst.reglo,regsrc1.reglo,regsrc2.reglo),PF_S));
  1205. list.concat(taicpu.op_reg_reg_reg(A_ADC,regdst.reghi,regsrc1.reghi,regsrc2.reghi));
  1206. end;
  1207. OP_SUB:
  1208. begin
  1209. list.concat(setoppostfix(taicpu.op_reg_reg_reg(A_SUB,regdst.reglo,regsrc2.reglo,regsrc1.reglo),PF_S));
  1210. list.concat(taicpu.op_reg_reg_reg(A_SBC,regdst.reghi,regsrc2.reghi,regsrc1.reghi));
  1211. end;
  1212. else
  1213. internalerror(2003083101);
  1214. end;
  1215. end;
  1216. begin
  1217. cg:=tcgarm.create;
  1218. cg64:=tcg64farm.create;
  1219. end.
  1220. {
  1221. $Log$
  1222. Revision 1.67 2005-01-30 14:43:40 florian
  1223. * fixed compilation of arm compiler
  1224. Revision 1.66 2005/01/04 21:00:48 florian
  1225. * not operator for byte/word fixed
  1226. Revision 1.65 2005/01/04 20:15:05 florian
  1227. * load_reg_reg fixed
  1228. Revision 1.64 2005/01/04 15:36:32 florian
  1229. * implemented nostackframe calling convention directive
  1230. Revision 1.63 2004/11/06 15:18:57 florian
  1231. * fixed OP_SUB for negative constants fitting in the shifter
  1232. Revision 1.62 2004/11/01 17:41:28 florian
  1233. * fixed arm compilation with cgutils
  1234. * ...
  1235. Revision 1.61 2004/10/31 16:47:43 florian
  1236. * fixed ie with pi_do_call
  1237. Revision 1.60 2004/10/31 16:04:30 florian
  1238. * fixed compilation of system unit on arm
  1239. Revision 1.59 2004/10/31 12:37:11 florian
  1240. * another couple of arm fixed
  1241. Revision 1.58 2004/10/24 17:32:53 florian
  1242. * fixed several arm compiler bugs
  1243. Revision 1.57 2004/10/24 11:53:45 peter
  1244. * fixed compilation with removed loadref
  1245. Revision 1.56 2004/10/24 07:54:25 florian
  1246. * fixed compilation of arm compiler
  1247. Revision 1.55 2004/10/11 15:46:45 peter
  1248. * length parameter for copyvaluearray changed to tlocation
  1249. Revision 1.54 2004/07/03 19:29:14 florian
  1250. * fixed problem with cpu interferences
  1251. Revision 1.53 2004/06/20 08:55:31 florian
  1252. * logs truncated
  1253. Revision 1.52 2004/06/16 20:07:10 florian
  1254. * dwarf branch merged
  1255. Revision 1.51.2.1 2004/06/12 17:01:01 florian
  1256. * fixed compilation of arm compiler
  1257. Revision 1.51 2004/03/31 19:13:04 florian
  1258. * concatcopy with len=0 exits now immediatly
  1259. Revision 1.50 2004/03/29 19:19:35 florian
  1260. + arm floating point register saving implemented
  1261. * hopefully stabs generation for MacOSX fixed
  1262. + some defines for arm added
  1263. Revision 1.49 2004/03/14 21:42:24 florian
  1264. * optimized mul code generation
  1265. }