cgcpu.pas 40 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154
  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,cginfo;
  27. type
  28. tcgarm = class(tcg)
  29. procedure a_param_const(list : taasmoutput;size : tcgsize;a : aword;const locpara : tparalocation);override;
  30. procedure a_param_ref(list : taasmoutput;size : tcgsize;const r : treference;const locpara : tparalocation);override;
  31. procedure a_paramaddr_ref(list : taasmoutput;const r : treference;const locpara : tparalocation);override;
  32. procedure a_call_name(list : taasmoutput;const s : string);override;
  33. procedure a_call_reg(list : taasmoutput;reg: tregister); override;
  34. procedure a_call_ref(list : taasmoutput;const ref : treference);override;
  35. procedure a_op_const_reg(list : taasmoutput; Op: TOpCG; size: TCGSize; a: AWord; reg: TRegister); override;
  36. procedure a_op_reg_reg(list : taasmoutput; Op: TOpCG; size: TCGSize; src, dst: TRegister); override;
  37. procedure a_op_const_reg_reg(list: taasmoutput; op: TOpCg;
  38. size: tcgsize; a: aword; src, dst: tregister); override;
  39. procedure a_op_reg_reg_reg(list: taasmoutput; op: TOpCg;
  40. size: tcgsize; src1, src2, dst: tregister); override;
  41. { move instructions }
  42. procedure a_load_const_reg(list : taasmoutput; size: tcgsize; a : aword;reg : tregister);override;
  43. procedure a_load_reg_ref(list : taasmoutput; fromsize, tosize: tcgsize; reg : tregister;const ref : treference);override;
  44. procedure a_load_ref_reg(list : taasmoutput; fromsize, tosize : tcgsize;const Ref : treference;reg : tregister);override;
  45. procedure a_load_reg_reg(list : taasmoutput; fromsize, tosize : tcgsize;reg1,reg2 : tregister);override;
  46. { fpu move instructions }
  47. procedure a_loadfpu_reg_reg(list: taasmoutput; size: tcgsize; reg1, reg2: tregister); override;
  48. procedure a_loadfpu_ref_reg(list: taasmoutput; size: tcgsize; const ref: treference; reg: tregister); override;
  49. procedure a_loadfpu_reg_ref(list: taasmoutput; size: tcgsize; reg: tregister; const ref: treference); override;
  50. { comparison operations }
  51. procedure a_cmp_const_reg_label(list : taasmoutput;size : tcgsize;cmp_op : topcmp;a : aword;reg : tregister;
  52. l : tasmlabel);override;
  53. procedure a_cmp_reg_reg_label(list : taasmoutput;size : tcgsize;cmp_op : topcmp;reg1,reg2 : tregister;l : tasmlabel); override;
  54. procedure a_jmp_always(list : taasmoutput;l: tasmlabel); override;
  55. procedure a_jmp_flags(list : taasmoutput;const f : TResFlags;l: tasmlabel); override;
  56. procedure g_flags2reg(list: taasmoutput; size: TCgSize; const f: TResFlags; reg: TRegister); override;
  57. procedure g_copyvaluepara_openarray(list : taasmoutput;const ref, lenref:treference;elesize:integer);override;
  58. procedure g_stackframe_entry(list : taasmoutput;localsize : longint);override;
  59. procedure g_return_from_proc(list : taasmoutput;parasize : aword); override;
  60. procedure g_restore_frame_pointer(list : taasmoutput);override;
  61. procedure a_loadaddr_ref_reg(list : taasmoutput;const ref : treference;r : tregister);override;
  62. procedure g_concatcopy(list : taasmoutput;const source,dest : treference;len : aword; delsource,loadref : boolean);override;
  63. procedure g_overflowcheck(list: taasmoutput; const l: tlocation; def: tdef); override;
  64. procedure g_save_standard_registers(list : taasmoutput; usedinproc : tsuperregisterset);override;
  65. procedure g_restore_standard_registers(list : taasmoutput; usedinproc : tsuperregisterset);override;
  66. procedure g_save_all_registers(list : taasmoutput);override;
  67. procedure g_restore_all_registers(list : taasmoutput;accused,acchiused:boolean);override;
  68. procedure a_jmp_cond(list : taasmoutput;cond : TOpCmp;l: tasmlabel);
  69. procedure fixref(list : taasmoutput;var ref : treference);
  70. procedure handle_load_store(list:taasmoutput;op: tasmop;oppostfix : toppostfix;reg:tregister;ref: treference);
  71. end;
  72. tcg64farm = class(tcg64f32)
  73. procedure a_op64_reg_reg(list : taasmoutput;op:TOpCG;regsrc,regdst : tregister64);override;
  74. procedure a_op64_const_reg(list : taasmoutput;op:TOpCG;value : qword;reg : tregister64);override;
  75. procedure a_op64_const_reg_reg(list: taasmoutput;op:TOpCG;value : qword;regsrc,regdst : tregister64);override;
  76. procedure a_op64_reg_reg_reg(list: taasmoutput;op:TOpCG;regsrc1,regsrc2,regdst : tregister64);override;
  77. end;
  78. const
  79. OpCmp2AsmCond : Array[topcmp] of TAsmCond = (C_NONE,C_EQ,C_GT,
  80. C_LT,C_GE,C_LE,C_NE,C_LE,C_LT,C_GE,C_GT);
  81. function is_shifter_const(d : dword;var imm_shift : byte) : boolean;
  82. implementation
  83. uses
  84. globtype,globals,verbose,systems,cutils,symconst,symdef,symsym,rgobj,tgobj,cpupi;
  85. procedure tcgarm.a_param_const(list : taasmoutput;size : tcgsize;a : aword;const locpara : tparalocation);
  86. var
  87. ref: treference;
  88. begin
  89. case locpara.loc of
  90. LOC_REGISTER,LOC_CREGISTER:
  91. a_load_const_reg(list,size,a,locpara.register);
  92. LOC_REFERENCE:
  93. begin
  94. reference_reset(ref);
  95. ref.base:=locpara.reference.index;
  96. ref.offset:=locpara.reference.offset;
  97. a_load_const_ref(list,size,a,ref);
  98. end;
  99. else
  100. internalerror(2002081101);
  101. end;
  102. if locpara.sp_fixup<>0 then
  103. internalerror(2002081102);
  104. end;
  105. procedure tcgarm.a_param_ref(list : taasmoutput;size : tcgsize;const r : treference;const locpara : tparalocation);
  106. var
  107. ref: treference;
  108. tmpreg: tregister;
  109. begin
  110. case locpara.loc of
  111. LOC_REGISTER,LOC_CREGISTER:
  112. a_load_ref_reg(list,size,size,r,locpara.register);
  113. LOC_REFERENCE:
  114. begin
  115. reference_reset(ref);
  116. ref.base:=locpara.reference.index;
  117. ref.offset:=locpara.reference.offset;
  118. tmpreg := rg.getregisterint(list,size);
  119. a_load_ref_reg(list,size,size,r,tmpreg);
  120. a_load_reg_ref(list,size,size,tmpreg,ref);
  121. rg.ungetregisterint(list,tmpreg);
  122. end;
  123. LOC_FPUREGISTER,LOC_CFPUREGISTER:
  124. case size of
  125. OS_F32, OS_F64:
  126. a_loadfpu_ref_reg(list,size,r,locpara.register);
  127. else
  128. internalerror(2002072801);
  129. end;
  130. else
  131. internalerror(2002081103);
  132. end;
  133. if locpara.sp_fixup<>0 then
  134. internalerror(2002081104);
  135. end;
  136. procedure tcgarm.a_paramaddr_ref(list : taasmoutput;const r : treference;const locpara : tparalocation);
  137. var
  138. ref: treference;
  139. tmpreg: tregister;
  140. begin
  141. case locpara.loc of
  142. LOC_REGISTER,LOC_CREGISTER:
  143. a_loadaddr_ref_reg(list,r,locpara.register);
  144. LOC_REFERENCE:
  145. begin
  146. reference_reset(ref);
  147. ref.base := locpara.reference.index;
  148. ref.offset := locpara.reference.offset;
  149. tmpreg := rg.getregisterint(list,OS_ADDR);
  150. a_loadaddr_ref_reg(list,r,tmpreg);
  151. a_load_reg_ref(list,OS_ADDR,OS_ADDR,tmpreg,ref);
  152. rg.ungetregisterint(list,tmpreg);
  153. end;
  154. else
  155. internalerror(2002080701);
  156. end;
  157. end;
  158. procedure tcgarm.a_call_name(list : taasmoutput;const s : string);
  159. begin
  160. list.concat(taicpu.op_sym(A_BL,objectlibrary.newasmsymbol(s)));
  161. if not(pi_do_call in current_procinfo.flags) then
  162. internalerror(2003060703);
  163. end;
  164. procedure tcgarm.a_call_reg(list : taasmoutput;reg: tregister);
  165. var
  166. r : tregister;
  167. begin
  168. list.concat(taicpu.op_reg_reg(A_MOV,NR_PC,reg));
  169. if not(pi_do_call in current_procinfo.flags) then
  170. internalerror(2003060704);
  171. end;
  172. procedure tcgarm.a_call_ref(list : taasmoutput;const ref : treference);
  173. var
  174. r : tregister;
  175. begin
  176. a_load_ref_reg(list,OS_ADDR,OS_ADDR,ref,NR_PC);
  177. if not(pi_do_call in current_procinfo.flags) then
  178. internalerror(2003060705);
  179. end;
  180. procedure tcgarm.a_op_const_reg(list : taasmoutput; Op: TOpCG; size: TCGSize; a: AWord; reg: TRegister);
  181. begin
  182. a_op_const_reg_reg(list,op,size,a,reg,reg);
  183. end;
  184. procedure tcgarm.a_op_reg_reg(list : taasmoutput; Op: TOpCG; size: TCGSize; src, dst: TRegister);
  185. begin
  186. case op of
  187. OP_NEG:
  188. list.concat(taicpu.op_reg_reg_const(A_RSB,dst,src,0));
  189. OP_NOT:
  190. list.concat(taicpu.op_reg_reg(A_MVN,dst,src));
  191. else
  192. a_op_reg_reg_reg(list,op,OS_32,src,dst,dst);
  193. end;
  194. end;
  195. const
  196. op_reg_reg_opcg2asmop: array[TOpCG] of tasmop =
  197. (A_NONE,A_ADD,A_AND,A_NONE,A_NONE,A_MUL,A_MUL,A_NONE,A_NONE,A_ORR,
  198. A_NONE,A_NONE,A_NONE,A_SUB,A_EOR);
  199. procedure tcgarm.a_op_const_reg_reg(list: taasmoutput; op: TOpCg;
  200. size: tcgsize; a: aword; src, dst: tregister);
  201. var
  202. shift : byte;
  203. tmpreg : tregister;
  204. so : tshifterop;
  205. begin
  206. if is_shifter_const(a,shift) and (not(op in [OP_IMUL,OP_MUL])) then
  207. case op of
  208. OP_NEG,OP_NOT,
  209. OP_DIV,OP_IDIV:
  210. internalerror(200308281);
  211. OP_SHL:
  212. begin
  213. if a>32 then
  214. internalerror(200308291);
  215. shifterop_reset(so);
  216. so.shiftmode:=SM_LSL;
  217. so.shiftimm:=a;
  218. list.concat(taicpu.op_reg_reg_shifterop(A_MOV,dst,src,so));
  219. end;
  220. OP_SHR:
  221. begin
  222. if a>32 then
  223. internalerror(200308292);
  224. shifterop_reset(so);
  225. so.shiftmode:=SM_LSR;
  226. so.shiftimm:=a;
  227. list.concat(taicpu.op_reg_reg_shifterop(A_MOV,dst,src,so));
  228. end;
  229. OP_SAR:
  230. begin
  231. if a>32 then
  232. internalerror(200308291);
  233. shifterop_reset(so);
  234. so.shiftmode:=SM_LSL;
  235. so.shiftimm:=a;
  236. list.concat(taicpu.op_reg_reg_shifterop(A_MOV,dst,src,so));
  237. end;
  238. else
  239. list.concat(taicpu.op_reg_reg_const(op_reg_reg_opcg2asmop[op],dst,src,a));
  240. end
  241. else
  242. begin
  243. { there could be added some more sophisticated optimizations }
  244. if (op in [OP_MUL,OP_IMUL]) and (a=1) then
  245. a_load_reg_reg(list,size,size,src,dst)
  246. else if (op in [OP_MUL,OP_IMUL]) and (a=0) then
  247. a_load_const_reg(list,size,0,dst)
  248. else if (op in [OP_IMUL]) and (a=-1) then
  249. a_op_reg_reg(list,OP_NEG,size,src,dst)
  250. else
  251. begin
  252. tmpreg := rg.getregisterint(list,size);
  253. a_load_const_reg(list,size,a,tmpreg);
  254. a_op_reg_reg_reg(list,op,size,tmpreg,src,dst);
  255. rg.ungetregisterint(list,tmpreg);
  256. end;
  257. end;
  258. end;
  259. procedure tcgarm.a_op_reg_reg_reg(list: taasmoutput; op: TOpCg;
  260. size: tcgsize; src1, src2, dst: tregister);
  261. var
  262. so : tshifterop;
  263. tmpreg : tregister;
  264. begin
  265. case op of
  266. OP_NEG,OP_NOT,
  267. OP_DIV,OP_IDIV:
  268. internalerror(200308281);
  269. OP_SHL:
  270. begin
  271. shifterop_reset(so);
  272. so.rs:=src1;
  273. so.shiftmode:=SM_LSL;
  274. list.concat(taicpu.op_reg_reg_shifterop(A_MOV,dst,src2,so));
  275. end;
  276. OP_SHR:
  277. begin
  278. shifterop_reset(so);
  279. so.rs:=src1;
  280. so.shiftmode:=SM_LSR;
  281. list.concat(taicpu.op_reg_reg_shifterop(A_MOV,dst,src2,so));
  282. end;
  283. OP_SAR:
  284. begin
  285. shifterop_reset(so);
  286. so.rs:=src1;
  287. so.shiftmode:=SM_ASR;
  288. list.concat(taicpu.op_reg_reg_shifterop(A_MOV,dst,src2,so));
  289. end;
  290. OP_IMUL,
  291. OP_MUL:
  292. begin
  293. { the arm doesn't allow that rd and rm are the same }
  294. if dst=src2 then
  295. begin
  296. if src1<>src2 then
  297. list.concat(taicpu.op_reg_reg_reg(A_MUL,dst,src1,src2))
  298. else
  299. begin
  300. writeln('Warning: Fix MUL');
  301. list.concat(taicpu.op_reg_reg_reg(A_MUL,dst,src2,src1));
  302. end;
  303. end
  304. else
  305. list.concat(taicpu.op_reg_reg_reg(A_MUL,dst,src2,src1));
  306. end;
  307. else
  308. list.concat(taicpu.op_reg_reg_reg(op_reg_reg_opcg2asmop[op],dst,src2,src1));
  309. end;
  310. end;
  311. function rotl(d : dword;b : byte) : dword;
  312. begin
  313. result:=(d shr (32-b)) or (d shl b);
  314. end;
  315. function is_shifter_const(d : dword;var imm_shift : byte) : boolean;
  316. var
  317. i : longint;
  318. begin
  319. for i:=0 to 15 do
  320. begin
  321. if (d and not(rotl($ff,i*2)))=0 then
  322. begin
  323. imm_shift:=i*2;
  324. result:=true;
  325. exit;
  326. end;
  327. end;
  328. result:=false;
  329. end;
  330. procedure tcgarm.a_load_const_reg(list : taasmoutput; size: tcgsize; a : aword;reg : tregister);
  331. var
  332. imm_shift : byte;
  333. l : tasmlabel;
  334. hr : treference;
  335. begin
  336. if not(size in [OS_8,OS_S8,OS_16,OS_S16,OS_32,OS_S32]) then
  337. internalerror(2002090902);
  338. if is_shifter_const(a,imm_shift) then
  339. list.concat(taicpu.op_reg_const(A_MOV,reg,a))
  340. else if is_shifter_const(not(a),imm_shift) then
  341. list.concat(taicpu.op_reg_const(A_MVN,reg,not(a)))
  342. else
  343. begin
  344. objectlibrary.getdatalabel(l);
  345. current_procinfo.aktlocaldata.concat(tai_symbol.Create(l,0));
  346. current_procinfo.aktlocaldata.concat(tai_const.Create_32bit(a));
  347. reference_reset(hr);
  348. hr.symbol:=l;
  349. list.concat(taicpu.op_reg_ref(A_LDR,reg,hr));
  350. end;
  351. end;
  352. procedure tcgarm.handle_load_store(list:taasmoutput;op: tasmop;oppostfix : toppostfix;reg:tregister;ref: treference);
  353. var
  354. tmpreg : tregister;
  355. tmpref : treference;
  356. l : tasmlabel;
  357. begin
  358. tmpreg:=NR_NO;
  359. { Be sure to have a base register }
  360. if (ref.base=NR_NO) then
  361. begin
  362. if ref.shiftmode<>SM_None then
  363. internalerror(200308294);
  364. ref.base:=ref.index;
  365. ref.index:=NR_NO;
  366. end;
  367. { absolute symbols can't be handled directly, we've to store the symbol reference
  368. in the text segment and access it pc relative
  369. For now, we assume that references where base or index equals to PC are already
  370. relative, all other references are assumed to be absolute and thus they need
  371. to be handled extra.
  372. A proper solution would be to change refoptions to a set and store the information
  373. if the symbol is absolute or relative there.
  374. }
  375. if (assigned(ref.symbol) and
  376. not(is_pc(ref.base)) and
  377. not(is_pc(ref.index))
  378. ) or
  379. (ref.offset<-4095) or
  380. (ref.offset>4095) then
  381. begin
  382. { check consts distance }
  383. { create consts entry }
  384. objectlibrary.getdatalabel(l);
  385. current_procinfo.aktlocaldata.concat(Tai_symbol.Create(l,0));
  386. if assigned(ref.symbol) then
  387. current_procinfo.aktlocaldata.concat(tai_const_symbol.Create_offset(ref.symbol,ref.offset))
  388. else
  389. current_procinfo.aktlocaldata.concat(tai_const.Create_32bit(ref.offset));
  390. { load consts entry }
  391. tmpreg:=rg.getregisterint(list,OS_INT);
  392. reference_reset(tmpref);
  393. tmpref.symbol:=l;
  394. tmpref.base:=NR_R15;
  395. list.concat(taicpu.op_reg_ref(A_LDR,tmpreg,tmpref));
  396. if (ref.base<>NR_NO) then
  397. begin
  398. if ref.index<>NR_NO then
  399. begin
  400. list.concat(taicpu.op_reg_reg_reg(A_ADD,tmpreg,ref.base,tmpreg));
  401. rg.ungetregister(list,ref.base);
  402. ref.base:=tmpreg;
  403. end
  404. else
  405. begin
  406. ref.index:=tmpreg;
  407. ref.shiftimm:=0;
  408. ref.signindex:=1;
  409. ref.shiftmode:=SM_None;
  410. end;
  411. end
  412. else
  413. ref.base:=tmpreg;
  414. ref.offset:=0;
  415. ref.symbol:=nil;
  416. end;
  417. list.concat(setoppostfix(taicpu.op_reg_ref(op,reg,ref),oppostfix));
  418. if (tmpreg<>NR_NO) then
  419. rg.ungetregisterint(list,tmpreg);
  420. end;
  421. procedure tcgarm.a_load_reg_ref(list : taasmoutput; fromsize, tosize: tcgsize; reg : tregister;const ref : treference);
  422. var
  423. oppostfix:toppostfix;
  424. begin
  425. case ToSize of
  426. { signed integer registers }
  427. OS_8,
  428. OS_S8:
  429. oppostfix:=PF_B;
  430. OS_16,
  431. OS_S16:
  432. oppostfix:=PF_H;
  433. OS_32,
  434. OS_S32:
  435. oppostfix:=PF_None;
  436. else
  437. InternalError(200308295);
  438. end;
  439. handle_load_store(list,A_STR,oppostfix,reg,ref);
  440. end;
  441. procedure tcgarm.a_load_ref_reg(list : taasmoutput; fromsize, tosize : tcgsize;const Ref : treference;reg : tregister);
  442. var
  443. oppostfix:toppostfix;
  444. begin
  445. case FromSize of
  446. { signed integer registers }
  447. OS_8:
  448. oppostfix:=PF_B;
  449. OS_S8:
  450. oppostfix:=PF_SB;
  451. OS_16:
  452. oppostfix:=PF_H;
  453. OS_S16:
  454. oppostfix:=PF_SH;
  455. OS_32,
  456. OS_S32:
  457. oppostfix:=PF_None;
  458. else
  459. InternalError(200308291);
  460. end;
  461. handle_load_store(list,A_LDR,oppostfix,reg,ref);
  462. end;
  463. procedure tcgarm.a_load_reg_reg(list : taasmoutput; fromsize, tosize : tcgsize;reg1,reg2 : tregister);
  464. var
  465. instr: taicpu;
  466. so : tshifterop;
  467. begin
  468. shifterop_reset(so);
  469. if (reg1<>reg2) or
  470. (tcgsize2size[tosize] < tcgsize2size[fromsize]) or
  471. ((tcgsize2size[tosize] = tcgsize2size[fromsize]) and
  472. (tosize <> fromsize) and
  473. not(fromsize in [OS_32,OS_S32])) then
  474. begin
  475. case tosize of
  476. OS_8:
  477. instr := taicpu.op_reg_reg_const(A_AND,
  478. reg2,reg1,$ff);
  479. OS_S8:
  480. begin
  481. so.shiftmode:=SM_LSL;
  482. so.shiftimm:=24;
  483. list.concat(taicpu.op_reg_reg_shifterop(A_MOV,reg2,reg1,so));
  484. so.shiftmode:=SM_ASR;
  485. so.shiftimm:=24;
  486. list.concat(taicpu.op_reg_reg_shifterop(A_MOV,reg2,reg2,so));
  487. end;
  488. OS_16:
  489. begin
  490. so.shiftmode:=SM_LSL;
  491. so.shiftimm:=16;
  492. list.concat(taicpu.op_reg_reg_shifterop(A_MOV,reg2,reg1,so));
  493. so.shiftmode:=SM_LSR;
  494. so.shiftimm:=16;
  495. list.concat(taicpu.op_reg_reg_shifterop(A_MOV,reg2,reg2,so));
  496. end;
  497. OS_S16:
  498. begin
  499. so.shiftmode:=SM_LSL;
  500. so.shiftimm:=16;
  501. list.concat(taicpu.op_reg_reg_shifterop(A_MOV,reg2,reg1,so));
  502. so.shiftmode:=SM_ASR;
  503. so.shiftimm:=16;
  504. list.concat(taicpu.op_reg_reg_shifterop(A_MOV,reg2,reg2,so));
  505. end;
  506. OS_32,OS_S32:
  507. begin
  508. instr:=taicpu.op_reg_reg(A_MOV,reg2,reg1);
  509. rg.add_move_instruction(instr);
  510. list.concat(instr);
  511. end;
  512. else internalerror(2002090901);
  513. end;
  514. end;
  515. end;
  516. procedure tcgarm.a_loadfpu_reg_reg(list: taasmoutput; size: tcgsize; reg1, reg2: tregister);
  517. begin
  518. list.concat(setoppostfix(taicpu.op_reg_reg(A_MVF,reg2,reg1),cgsize2fpuoppostfix[size]));
  519. end;
  520. procedure tcgarm.a_loadfpu_ref_reg(list: taasmoutput; size: tcgsize; const ref: treference; reg: tregister);
  521. var
  522. oppostfix:toppostfix;
  523. begin
  524. case size of
  525. OS_F32:
  526. oppostfix:=PF_S;
  527. OS_F64:
  528. oppostfix:=PF_D;
  529. OS_F80:
  530. oppostfix:=PF_E;
  531. else
  532. InternalError(200309021);
  533. end;
  534. handle_load_store(list,A_LDF,oppostfix,reg,ref);
  535. end;
  536. procedure tcgarm.a_loadfpu_reg_ref(list: taasmoutput; size: tcgsize; reg: tregister; const ref: treference);
  537. var
  538. oppostfix:toppostfix;
  539. begin
  540. case size of
  541. OS_F32:
  542. oppostfix:=PF_S;
  543. OS_F64:
  544. oppostfix:=PF_D;
  545. OS_F80:
  546. oppostfix:=PF_E;
  547. else
  548. InternalError(200309021);
  549. end;
  550. handle_load_store(list,A_STF,oppostfix,reg,ref);
  551. end;
  552. { comparison operations }
  553. procedure tcgarm.a_cmp_const_reg_label(list : taasmoutput;size : tcgsize;cmp_op : topcmp;a : aword;reg : tregister;
  554. l : tasmlabel);
  555. var
  556. tmpreg : tregister;
  557. b : byte;
  558. begin
  559. if is_shifter_const(a,b) then
  560. list.concat(taicpu.op_reg_const(A_CMN,reg,a))
  561. { CMN reg,0 and CMN reg,$80000000 are different from CMP reg,$ffffffff
  562. and CMP reg,$7fffffff regarding the flags according to the ARM manual }
  563. else if is_shifter_const(not(a),b) and (a<>$7fffffff) and (a<>$ffffffff) then
  564. list.concat(taicpu.op_reg_const(A_CMN,reg,not(a)))
  565. else
  566. begin
  567. tmpreg:=rg.getregisterint(list,size);
  568. a_load_const_reg(list,size,a,tmpreg);
  569. list.concat(taicpu.op_reg_reg(A_CMP,reg,tmpreg));
  570. rg.ungetregisterint(list,tmpreg);
  571. end;
  572. a_jmp_cond(list,cmp_op,l);
  573. end;
  574. procedure tcgarm.a_cmp_reg_reg_label(list : taasmoutput;size : tcgsize;cmp_op : topcmp;reg1,reg2 : tregister;l : tasmlabel);
  575. begin
  576. list.concat(taicpu.op_reg_reg(A_CMP,reg2,reg1));
  577. a_jmp_cond(list,cmp_op,l);
  578. end;
  579. procedure tcgarm.a_jmp_always(list : taasmoutput;l: tasmlabel);
  580. begin
  581. list.concat(taicpu.op_sym(A_B,objectlibrary.newasmsymbol(l.name)));
  582. end;
  583. procedure tcgarm.a_jmp_flags(list : taasmoutput;const f : TResFlags;l: tasmlabel);
  584. var
  585. ai : taicpu;
  586. begin
  587. ai:=setcondition(taicpu.op_sym(A_B,l),flags_to_cond(f));
  588. ai.is_jmp:=true;
  589. list.concat(ai);
  590. end;
  591. procedure tcgarm.g_flags2reg(list: taasmoutput; size: TCgSize; const f: TResFlags; reg: TRegister);
  592. var
  593. ai : taicpu;
  594. begin
  595. list.concat(setcondition(taicpu.op_reg_const(A_MOV,reg,1),flags_to_cond(f)));
  596. list.concat(setcondition(taicpu.op_reg_const(A_MOV,reg,0),inverse_cond[flags_to_cond(f)]));
  597. end;
  598. procedure tcgarm.g_copyvaluepara_openarray(list : taasmoutput;const ref, lenref:treference;elesize:integer);
  599. begin
  600. end;
  601. procedure tcgarm.g_stackframe_entry(list : taasmoutput;localsize : longint);
  602. var
  603. ref : treference;
  604. begin
  605. LocalSize:=align(LocalSize,4);
  606. a_reg_alloc(list,NR_STACK_POINTER_REG);
  607. a_reg_alloc(list,NR_FRAME_POINTER_REG);
  608. a_reg_alloc(list,NR_R12);
  609. list.concat(taicpu.op_reg_reg(A_MOV,NR_R12,NR_STACK_POINTER_REG));
  610. { save int registers }
  611. reference_reset(ref);
  612. ref.index:=NR_STACK_POINTER_REG;
  613. ref.addressmode:=AM_PREINDEXED;
  614. list.concat(setoppostfix(taicpu.op_ref_regset(A_STM,ref,rg.used_in_proc_int-[RS_R0..RS_R3]+[RS_R11,RS_R12,RS_R15]),PF_FD));
  615. list.concat(taicpu.op_reg_reg_const(A_SUB,NR_FRAME_POINTER_REG,NR_R12,4));
  616. a_reg_alloc(list,NR_R12);
  617. { allocate necessary stack size }
  618. list.concat(taicpu.op_reg_reg_const(A_SUB,NR_STACK_POINTER_REG,NR_STACK_POINTER_REG,LocalSize));
  619. end;
  620. procedure tcgarm.g_return_from_proc(list : taasmoutput;parasize : aword);
  621. var
  622. ref : treference;
  623. begin
  624. if (current_procinfo.framepointer=NR_STACK_POINTER_REG) then
  625. list.concat(taicpu.op_reg_reg(A_MOV,NR_R15,NR_R14))
  626. else
  627. begin
  628. { restore int registers and return }
  629. reference_reset(ref);
  630. ref.index:=NR_FRAME_POINTER_REG;
  631. - list.concat(setoppostfix(taicpu.op_ref_regset(A_LDM,ref,rg.used_in_proc_int-[RS_R0..RS_R3]+[RS_R11,RS_R13,RS_R15]),PF_EA));
  632. end;
  633. end;
  634. procedure tcgarm.g_restore_frame_pointer(list : taasmoutput);
  635. begin
  636. { the frame pointer on the ARM is restored while the ret is executed }
  637. end;
  638. procedure tcgarm.a_loadaddr_ref_reg(list : taasmoutput;const ref : treference;r : tregister);
  639. var
  640. b : byte;
  641. tmpref : treference;
  642. begin
  643. tmpref:=ref;
  644. { Be sure to have a base register }
  645. if (tmpref.base=NR_NO) then
  646. begin
  647. if tmpref.shiftmode<>SM_None then
  648. internalerror(200308294);
  649. tmpref.base:=tmpref.index;
  650. tmpref.index:=NR_NO;
  651. end;
  652. if assigned(tmpref.symbol) or
  653. not(is_shifter_const(tmpref.offset,b)) or
  654. ((tmpref.base<>NR_NO) and (tmpref.index<>NR_NO)) then
  655. fixref(list,tmpref);
  656. if ref.index<>NR_NO then
  657. begin
  658. end
  659. { else
  660. list.concat(taicpu.op_reg_reg(A_MOV,r,));
  661. ref.signindex<0 then }
  662. end;
  663. procedure tcgarm.fixref(list : taasmoutput;var ref : treference);
  664. var
  665. tmpreg : tregister;
  666. tmpref : treference;
  667. l : tasmlabel;
  668. begin
  669. { absolute symbols can't be handled directly, we've to store the symbol reference
  670. in the text segment and access it pc relative
  671. For now, we assume that references where base or index equals to PC are already
  672. relative, all other references are assumed to be absolute and thus they need
  673. to be handled extra.
  674. A proper solution would be to change refoptions to a set and store the information
  675. if the symbol is absolute or relative there.
  676. }
  677. { check consts distance }
  678. {!!!!!}
  679. { create consts entry }
  680. objectlibrary.getdatalabel(l);
  681. current_procinfo.aktlocaldata.concat(Tai_symbol.Create(l,0));
  682. if assigned(ref.symbol) then
  683. current_procinfo.aktlocaldata.concat(tai_const_symbol.Create_offset(ref.symbol,ref.offset))
  684. else
  685. current_procinfo.aktlocaldata.concat(tai_const.Create_32bit(ref.offset));
  686. { load consts entry }
  687. tmpreg:=rg.getregisterint(list,OS_INT);
  688. reference_reset(tmpref);
  689. tmpref.symbol:=l;
  690. tmpref.base:=NR_PC;
  691. list.concat(taicpu.op_reg_ref(A_LDR,tmpreg,tmpref));
  692. if (ref.base<>NR_NO) then
  693. begin
  694. if ref.index<>NR_NO then
  695. begin
  696. list.concat(taicpu.op_reg_reg_reg(A_ADD,tmpreg,ref.base,tmpreg));
  697. rg.ungetregisterint(list,ref.base);
  698. ref.base:=tmpreg;
  699. end
  700. else
  701. begin
  702. ref.index:=tmpreg;
  703. ref.shiftimm:=0;
  704. ref.signindex:=1;
  705. ref.shiftmode:=SM_None;
  706. end;
  707. end
  708. else
  709. ref.base:=tmpreg;
  710. ref.offset:=0;
  711. ref.symbol:=nil;
  712. end;
  713. procedure tcgarm.g_concatcopy(list : taasmoutput;const source,dest : treference;len : aword; delsource,loadref : boolean);
  714. var
  715. srcref,dstref:treference;
  716. srcreg,destreg,countreg,r:tregister;
  717. helpsize:aword;
  718. copysize:byte;
  719. cgsize:Tcgsize;
  720. procedure genloop(count : aword;size : byte);
  721. const
  722. size2opsize : array[1..4] of tcgsize = (OS_8,OS_16,OS_NO,OS_32);
  723. var
  724. l : tasmlabel;
  725. begin
  726. objectlibrary.getdatalabel(l);
  727. a_load_const_reg(list,OS_INT,count,countreg);
  728. list.concat(Tai_symbol.Create(l,0));
  729. srcref.addressmode:=AM_POSTINDEXED;
  730. dstref.addressmode:=AM_POSTINDEXED;
  731. srcref.offset:=size;
  732. dstref.offset:=size;
  733. r:=rg.getregisterint(list,size2opsize[size]);
  734. a_load_ref_reg(list,size2opsize[size],size2opsize[size],srcref,r);
  735. a_load_reg_ref(list,size2opsize[size],size2opsize[size],r,dstref);
  736. rg.ungetregisterint(list,r);
  737. list.concat(setoppostfix(taicpu.op_reg_reg_const(A_SUB,countreg,countreg,1),PF_S));
  738. list.concat(setcondition(taicpu.op_sym(A_B,l),C_NE));
  739. end;
  740. begin
  741. helpsize:=12;
  742. dstref:=dest;
  743. srcref:=source;
  744. if cs_littlesize in aktglobalswitches then
  745. helpsize:=8;
  746. if not loadref and (len<=helpsize) then
  747. begin
  748. copysize:=4;
  749. cgsize:=OS_32;
  750. while len<>0 do
  751. begin
  752. if len<2 then
  753. begin
  754. copysize:=1;
  755. cgsize:=OS_8;
  756. end
  757. else if len<4 then
  758. begin
  759. copysize:=2;
  760. cgsize:=OS_16;
  761. end;
  762. dec(len,copysize);
  763. r:=rg.getregisterint(list,cgsize);
  764. a_load_ref_reg(list,cgsize,cgsize,srcref,r);
  765. if (len=0) and delsource then
  766. reference_release(list,source);
  767. a_load_reg_ref(list,cgsize,cgsize,r,dstref);
  768. inc(srcref.offset,copysize);
  769. inc(dstref.offset,copysize);
  770. rg.ungetregisterint(list,r);
  771. end;
  772. end
  773. else
  774. begin
  775. destreg:=rg.getregisterint(list,OS_ADDR);
  776. a_loadaddr_ref_reg(list,dest,destreg);
  777. srcreg:=rg.getregisterint(list,OS_ADDR);
  778. if loadref then
  779. a_load_ref_reg(list,OS_ADDR,OS_ADDR,source,srcreg)
  780. else
  781. begin
  782. a_loadaddr_ref_reg(list,source,srcreg);
  783. if delsource then
  784. begin
  785. srcref:=source;
  786. reference_release(list,srcref);
  787. end;
  788. end;
  789. countreg:=rg.getregisterint(list,OS_32);
  790. // if cs_littlesize in aktglobalswitches then
  791. genloop(len,1);
  792. {
  793. else
  794. begin
  795. helpsize:=len shr 2;
  796. len:=len and 3;
  797. if helpsize>1 then
  798. begin
  799. a_load_const_reg(list,OS_INT,helpsize,countreg);
  800. list.concat(Taicpu.op_none(A_REP,S_NO));
  801. end;
  802. if helpsize>0 then
  803. list.concat(Taicpu.op_none(A_MOVSD,S_NO));
  804. if len>1 then
  805. begin
  806. dec(len,2);
  807. list.concat(Taicpu.op_none(A_MOVSW,S_NO));
  808. end;
  809. if len=1 then
  810. list.concat(Taicpu.op_none(A_MOVSB,S_NO));
  811. end;
  812. }
  813. rg.ungetregisterint(list,countreg);
  814. rg.ungetregisterint(list,srcreg);
  815. rg.ungetregisterint(list,destreg);
  816. end;
  817. if delsource then
  818. tg.ungetiftemp(list,source);
  819. end;
  820. procedure tcgarm.g_overflowcheck(list: taasmoutput; const l: tlocation; def: tdef);
  821. begin
  822. end;
  823. procedure tcgarm.g_save_standard_registers(list : taasmoutput; usedinproc : tsuperregisterset);
  824. begin
  825. { we support only ARM standard calling conventions so this procedure has no use on the ARM }
  826. end;
  827. procedure tcgarm.g_restore_standard_registers(list : taasmoutput; usedinproc : tsuperregisterset);
  828. begin
  829. { we support only ARM standard calling conventions so this procedure has no use on the ARM }
  830. end;
  831. procedure tcgarm.g_save_all_registers(list : taasmoutput);
  832. begin
  833. { we support only ARM standard calling conventions so this procedure has no use on the ARM }
  834. end;
  835. procedure tcgarm.g_restore_all_registers(list : taasmoutput;accused,acchiused:boolean);
  836. begin
  837. { we support only ARM standard calling conventions so this procedure has no use on the ARM }
  838. end;
  839. procedure tcgarm.a_jmp_cond(list : taasmoutput;cond : TOpCmp;l: tasmlabel);
  840. var
  841. ai : taicpu;
  842. begin
  843. ai:=Taicpu.Op_sym(A_B,l);
  844. ai.SetCondition(OpCmp2AsmCond[cond]);
  845. ai.is_jmp:=true;
  846. list.concat(ai);
  847. end;
  848. procedure tcg64farm.a_op64_reg_reg(list : taasmoutput;op:TOpCG;regsrc,regdst : tregister64);
  849. var
  850. tmpreg : tregister;
  851. begin
  852. case op of
  853. OP_NEG:
  854. begin
  855. list.concat(setoppostfix(taicpu.op_reg_reg_const(A_RSB,regdst.reglo,regsrc.reglo,0),PF_S));
  856. list.concat(taicpu.op_reg_reg_const(A_RSC,regdst.reghi,regsrc.reghi,0));
  857. end;
  858. else
  859. a_op64_reg_reg_reg(list,op,regsrc,regdst,regdst);
  860. end;
  861. end;
  862. procedure tcg64farm.a_op64_const_reg(list : taasmoutput;op:TOpCG;value : qword;reg : tregister64);
  863. begin
  864. a_op64_const_reg_reg(list,op,value,reg,reg);
  865. end;
  866. procedure tcg64farm.a_op64_const_reg_reg(list: taasmoutput;op:TOpCG;value : qword;regsrc,regdst : tregister64);
  867. var
  868. tmpreg : tregister;
  869. b : byte;
  870. begin
  871. case op of
  872. OP_AND,OP_OR,OP_XOR:
  873. begin
  874. cg.a_op_const_reg_reg(list,op,OS_32,lo(value),regsrc.reglo,regdst.reglo);
  875. cg.a_op_const_reg_reg(list,op,OS_32,hi(value),regsrc.reghi,regdst.reghi);
  876. end;
  877. OP_ADD:
  878. begin
  879. if is_shifter_const(lo(value),b) then
  880. list.concat(setoppostfix(taicpu.op_reg_reg_const(A_ADD,regdst.reglo,regsrc.reglo,lo(value)),PF_S))
  881. else
  882. begin
  883. tmpreg:=rg.getregisterint(list,OS_32);
  884. cg.a_load_const_reg(list,OS_32,lo(value),tmpreg);
  885. list.concat(setoppostfix(taicpu.op_reg_reg_reg(A_ADD,regdst.reglo,regsrc.reglo,tmpreg),PF_S));
  886. rg.ungetregisterint(list,tmpreg);
  887. end;
  888. if is_shifter_const(hi(value),b) then
  889. list.concat(taicpu.op_reg_reg_const(A_ADC,regdst.reghi,regsrc.reghi,hi(value)))
  890. else
  891. begin
  892. tmpreg:=rg.getregisterint(list,OS_32);
  893. cg.a_load_const_reg(list,OS_32,hi(value),tmpreg);
  894. list.concat(taicpu.op_reg_reg_reg(A_ADC,regdst.reghi,regsrc.reghi,tmpreg));
  895. rg.ungetregisterint(list,tmpreg);
  896. end;
  897. end;
  898. OP_SUB:
  899. begin
  900. if is_shifter_const(lo(value),b) then
  901. list.concat(setoppostfix(taicpu.op_reg_reg_const(A_SUB,regdst.reglo,regsrc.reglo,lo(value)),PF_S))
  902. else
  903. begin
  904. tmpreg:=rg.getregisterint(list,OS_32);
  905. cg.a_load_const_reg(list,OS_32,lo(value),tmpreg);
  906. list.concat(setoppostfix(taicpu.op_reg_reg_reg(A_SUB,regdst.reglo,regsrc.reglo,tmpreg),PF_S));
  907. rg.ungetregisterint(list,tmpreg);
  908. end;
  909. if is_shifter_const(hi(value),b) then
  910. list.concat(taicpu.op_reg_reg_const(A_SBC,regdst.reghi,regsrc.reghi,hi(value)))
  911. else
  912. begin
  913. tmpreg:=rg.getregisterint(list,OS_32);
  914. cg.a_load_const_reg(list,OS_32,hi(value),tmpreg);
  915. list.concat(taicpu.op_reg_reg_reg(A_SBC,regdst.reghi,regsrc.reghi,tmpreg));
  916. rg.ungetregisterint(list,tmpreg);
  917. end;
  918. end;
  919. else
  920. internalerror(2003083101);
  921. end;
  922. end;
  923. procedure tcg64farm.a_op64_reg_reg_reg(list: taasmoutput;op:TOpCG;regsrc1,regsrc2,regdst : tregister64);
  924. begin
  925. case op of
  926. OP_AND,OP_OR,OP_XOR:
  927. begin
  928. cg.a_op_reg_reg_reg(list,op,OS_32,regsrc1.reglo,regsrc2.reglo,regdst.reglo);
  929. cg.a_op_reg_reg_reg(list,op,OS_32,regsrc1.reghi,regsrc2.reghi,regdst.reghi);
  930. end;
  931. OP_ADD:
  932. begin
  933. list.concat(setoppostfix(taicpu.op_reg_reg_reg(A_ADD,regdst.reglo,regsrc1.reglo,regsrc2.reglo),PF_S));
  934. list.concat(taicpu.op_reg_reg_reg(A_ADC,regdst.reghi,regsrc1.reghi,regsrc2.reghi));
  935. end;
  936. OP_SUB:
  937. begin
  938. list.concat(setoppostfix(taicpu.op_reg_reg_reg(A_SUB,regdst.reglo,regsrc2.reglo,regsrc1.reglo),PF_S));
  939. list.concat(taicpu.op_reg_reg_reg(A_SBC,regdst.reghi,regsrc2.reghi,regsrc1.reghi));
  940. end;
  941. else
  942. internalerror(2003083101);
  943. end;
  944. end;
  945. begin
  946. cg:=tcgarm.create;
  947. cg64:=tcg64farm.create;
  948. end.
  949. {
  950. $Log$
  951. Revision 1.17 2003-09-06 16:45:51 florian
  952. * fixed exit code (no preindexed addressing mode in LDM)
  953. Revision 1.16 2003/09/06 11:21:50 florian
  954. * fixed stm and ldm to be usable with preindex operand
  955. Revision 1.15 2003/09/05 23:57:01 florian
  956. * arm is working again as before the new register naming scheme was implemented
  957. Revision 1.14 2003/09/04 21:07:03 florian
  958. * ARM compiler compiles again
  959. Revision 1.13 2003/09/04 00:15:29 florian
  960. * first bunch of adaptions of arm compiler for new register type
  961. Revision 1.12 2003/09/03 19:10:30 florian
  962. * initial revision of new register naming
  963. Revision 1.11 2003/09/03 11:18:37 florian
  964. * fixed arm concatcopy
  965. + arm support in the common compiler sources added
  966. * moved some generic cg code around
  967. + tfputype added
  968. * ...
  969. Revision 1.10 2003/09/01 15:11:16 florian
  970. * fixed reference handling
  971. * fixed operand postfix for floating point instructions
  972. * fixed wrong shifter constant handling
  973. Revision 1.9 2003/09/01 09:54:57 florian
  974. * results of work on arm port last weekend
  975. Revision 1.8 2003/08/29 21:36:28 florian
  976. * fixed procedure entry/exit code
  977. * started to fix reference handling
  978. Revision 1.7 2003/08/28 13:26:10 florian
  979. * another couple of arm fixes
  980. Revision 1.6 2003/08/28 00:05:29 florian
  981. * today's arm patches
  982. Revision 1.5 2003/08/25 23:20:38 florian
  983. + started to implement FPU support for the ARM
  984. * fixed a lot of other things
  985. Revision 1.4 2003/08/24 12:27:26 florian
  986. * continued to work on the arm port
  987. Revision 1.3 2003/08/21 03:14:00 florian
  988. * arm compiler can be compiled; far from being working
  989. Revision 1.2 2003/08/20 15:50:12 florian
  990. * more arm stuff
  991. Revision 1.1 2003/07/21 16:35:30 florian
  992. * very basic stuff for the arm
  993. }