cgcpu.pas 51 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463
  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. begin
  246. if is_shifter_const(dword(-a),shift) then
  247. case op of
  248. OP_ADD:
  249. begin
  250. op:=OP_SUB;
  251. a:=dword(-a);
  252. end;
  253. OP_SUB:
  254. begin
  255. op:=OP_SUB;
  256. a:=dword(-a);
  257. end
  258. end;
  259. if is_shifter_const(a,shift) and not(op in [OP_IMUL,OP_MUL]) then
  260. case op of
  261. OP_NEG,OP_NOT,
  262. OP_DIV,OP_IDIV:
  263. internalerror(200308281);
  264. OP_SHL:
  265. begin
  266. if a>32 then
  267. internalerror(200308291);
  268. if a<>0 then
  269. begin
  270. shifterop_reset(so);
  271. so.shiftmode:=SM_LSL;
  272. so.shiftimm:=a;
  273. list.concat(taicpu.op_reg_reg_shifterop(A_MOV,dst,src,so));
  274. end
  275. else
  276. list.concat(taicpu.op_reg_reg(A_MOV,dst,src));
  277. end;
  278. OP_SHR:
  279. begin
  280. if a>32 then
  281. internalerror(200308292);
  282. shifterop_reset(so);
  283. if a<>0 then
  284. begin
  285. so.shiftmode:=SM_LSR;
  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_SAR:
  293. begin
  294. if a>32 then
  295. internalerror(200308291);
  296. if a<>0 then
  297. begin
  298. shifterop_reset(so);
  299. so.shiftmode:=SM_ASR;
  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. else
  307. list.concat(taicpu.op_reg_reg_const(op_reg_reg_opcg2asmop[op],dst,src,a));
  308. end
  309. else
  310. begin
  311. { there could be added some more sophisticated optimizations }
  312. if (op in [OP_MUL,OP_IMUL]) and (a=1) then
  313. a_load_reg_reg(list,size,size,src,dst)
  314. else if (op in [OP_MUL,OP_IMUL]) and (a=0) then
  315. a_load_const_reg(list,size,0,dst)
  316. else if (op in [OP_IMUL]) and (a=-1) then
  317. a_op_reg_reg(list,OP_NEG,size,src,dst)
  318. else
  319. begin
  320. tmpreg:=getintregister(list,size);
  321. a_load_const_reg(list,size,a,tmpreg);
  322. a_op_reg_reg_reg(list,op,size,tmpreg,src,dst);
  323. ungetregister(list,tmpreg);
  324. end;
  325. end;
  326. end;
  327. procedure tcgarm.a_op_reg_reg_reg(list: taasmoutput; op: TOpCg;
  328. size: tcgsize; src1, src2, dst: tregister);
  329. var
  330. so : tshifterop;
  331. tmpreg : tregister;
  332. begin
  333. case op of
  334. OP_NEG,OP_NOT,
  335. OP_DIV,OP_IDIV:
  336. internalerror(200308281);
  337. OP_SHL:
  338. begin
  339. shifterop_reset(so);
  340. so.rs:=src1;
  341. so.shiftmode:=SM_LSL;
  342. list.concat(taicpu.op_reg_reg_shifterop(A_MOV,dst,src2,so));
  343. end;
  344. OP_SHR:
  345. begin
  346. shifterop_reset(so);
  347. so.rs:=src1;
  348. so.shiftmode:=SM_LSR;
  349. list.concat(taicpu.op_reg_reg_shifterop(A_MOV,dst,src2,so));
  350. end;
  351. OP_SAR:
  352. begin
  353. shifterop_reset(so);
  354. so.rs:=src1;
  355. so.shiftmode:=SM_ASR;
  356. list.concat(taicpu.op_reg_reg_shifterop(A_MOV,dst,src2,so));
  357. end;
  358. OP_IMUL,
  359. OP_MUL:
  360. begin
  361. { the arm doesn't allow that rd and rm are the same }
  362. if dst=src2 then
  363. begin
  364. if dst<>src1 then
  365. list.concat(taicpu.op_reg_reg_reg(A_MUL,dst,src1,src2))
  366. else
  367. begin
  368. tmpreg:=getintregister(list,size);
  369. a_load_reg_reg(list,size,size,src2,dst);
  370. ungetregister(list,tmpreg);
  371. list.concat(taicpu.op_reg_reg_reg(A_MUL,dst,tmpreg,src1));
  372. end;
  373. end
  374. else
  375. list.concat(taicpu.op_reg_reg_reg(A_MUL,dst,src2,src1));
  376. end;
  377. else
  378. list.concat(setoppostfix(taicpu.op_reg_reg_reg(op_reg_reg_opcg2asmop[op],dst,src2,src1),toppostfix(ord(setflags)*ord(PF_S))));
  379. end;
  380. end;
  381. function rotl(d : dword;b : byte) : dword;
  382. begin
  383. result:=(d shr (32-b)) or (d shl b);
  384. end;
  385. function is_shifter_const(d : dword;var imm_shift : byte) : boolean;
  386. var
  387. i : longint;
  388. begin
  389. for i:=0 to 15 do
  390. begin
  391. if (d and not(rotl($ff,i*2)))=0 then
  392. begin
  393. imm_shift:=i*2;
  394. result:=true;
  395. exit;
  396. end;
  397. end;
  398. result:=false;
  399. end;
  400. procedure tcgarm.a_load_const_reg(list : taasmoutput; size: tcgsize; a : aword;reg : tregister);
  401. var
  402. imm_shift : byte;
  403. l : tasmlabel;
  404. hr : treference;
  405. begin
  406. if not(size in [OS_8,OS_S8,OS_16,OS_S16,OS_32,OS_S32]) then
  407. internalerror(2002090902);
  408. if is_shifter_const(dword(a),imm_shift) then
  409. list.concat(taicpu.op_reg_const(A_MOV,reg,a))
  410. else if is_shifter_const(dword(not(a)),imm_shift) then
  411. list.concat(taicpu.op_reg_const(A_MVN,reg,not(a)))
  412. else
  413. begin
  414. reference_reset(hr);
  415. objectlibrary.getlabel(l);
  416. cg.a_label(current_procinfo.aktlocaldata,l);
  417. hr.symboldata:=current_procinfo.aktlocaldata.last;
  418. current_procinfo.aktlocaldata.concat(tai_const.Create_32bit(longint(a)));
  419. hr.symbol:=l;
  420. list.concat(taicpu.op_reg_ref(A_LDR,reg,hr));
  421. end;
  422. end;
  423. procedure tcgarm.handle_load_store(list:taasmoutput;op: tasmop;oppostfix : toppostfix;reg:tregister;ref: treference);
  424. var
  425. tmpreg : tregister;
  426. tmpref : treference;
  427. l : tasmlabel;
  428. begin
  429. tmpreg:=NR_NO;
  430. { Be sure to have a base register }
  431. if (ref.base=NR_NO) then
  432. begin
  433. if ref.shiftmode<>SM_None then
  434. internalerror(200308294);
  435. ref.base:=ref.index;
  436. ref.index:=NR_NO;
  437. end;
  438. { absolute symbols can't be handled directly, we've to store the symbol reference
  439. in the text segment and access it pc relative
  440. For now, we assume that references where base or index equals to PC are already
  441. relative, all other references are assumed to be absolute and thus they need
  442. to be handled extra.
  443. A proper solution would be to change refoptions to a set and store the information
  444. if the symbol is absolute or relative there.
  445. }
  446. if (assigned(ref.symbol) and
  447. not(is_pc(ref.base)) and
  448. not(is_pc(ref.index))
  449. ) or
  450. (ref.offset<-4095) or
  451. (ref.offset>4095) or
  452. ((oppostfix in [PF_SB,PF_H,PF_SH]) and
  453. ((ref.offset<-255) or
  454. (ref.offset>255)
  455. )
  456. ) or
  457. ((op in [A_LDF,A_STF]) and
  458. ((ref.offset<-1020) or
  459. (ref.offset>1020)
  460. )
  461. ) then
  462. begin
  463. reference_reset(tmpref);
  464. { create consts entry }
  465. objectlibrary.getlabel(l);
  466. cg.a_label(current_procinfo.aktlocaldata,l);
  467. tmpref.symboldata:=current_procinfo.aktlocaldata.last;
  468. if assigned(ref.symbol) then
  469. current_procinfo.aktlocaldata.concat(tai_const_symbol.Create_offset(ref.symbol,ref.offset))
  470. else
  471. current_procinfo.aktlocaldata.concat(tai_const.Create_32bit(ref.offset));
  472. { load consts entry }
  473. tmpreg:=getintregister(list,OS_INT);
  474. tmpref.symbol:=l;
  475. tmpref.base:=NR_R15;
  476. list.concat(taicpu.op_reg_ref(A_LDR,tmpreg,tmpref));
  477. if (ref.base<>NR_NO) then
  478. begin
  479. if ref.index<>NR_NO then
  480. begin
  481. list.concat(taicpu.op_reg_reg_reg(A_ADD,tmpreg,ref.base,tmpreg));
  482. ref.base:=tmpreg;
  483. end
  484. else
  485. begin
  486. ref.index:=tmpreg;
  487. ref.shiftimm:=0;
  488. ref.signindex:=1;
  489. ref.shiftmode:=SM_None;
  490. end;
  491. end
  492. else
  493. ref.base:=tmpreg;
  494. ref.offset:=0;
  495. ref.symbol:=nil;
  496. end;
  497. if (ref.base<>NR_NO) and (ref.index<>NR_NO) and (ref.offset<>0) then
  498. begin
  499. if tmpreg<>NR_NO then
  500. a_op_const_reg_reg(list,OP_ADD,OS_ADDR,ref.offset,tmpreg,tmpreg)
  501. else
  502. begin
  503. tmpreg:=getintregister(list,OS_ADDR);
  504. a_op_const_reg_reg(list,OP_ADD,OS_ADDR,ref.offset,ref.base,tmpreg);
  505. ref.base:=tmpreg;
  506. end;
  507. ref.offset:=0;
  508. end;
  509. { floating point operations have only limited references
  510. we expect here, that a base is already set }
  511. if (op in [A_LDF,A_STF]) and (ref.index<>NR_NO) then
  512. begin
  513. if ref.shiftmode<>SM_none then
  514. internalerror(200309121);
  515. if tmpreg<>NR_NO then
  516. begin
  517. if ref.base=tmpreg then
  518. begin
  519. if ref.signindex<0 then
  520. list.concat(taicpu.op_reg_reg_reg(A_SUB,tmpreg,tmpreg,ref.index))
  521. else
  522. list.concat(taicpu.op_reg_reg_reg(A_ADD,tmpreg,tmpreg,ref.index));
  523. ref.index:=NR_NO;
  524. end
  525. else
  526. begin
  527. if ref.index<>tmpreg then
  528. internalerror(200403161);
  529. if ref.signindex<0 then
  530. list.concat(taicpu.op_reg_reg_reg(A_SUB,tmpreg,ref.base,tmpreg))
  531. else
  532. list.concat(taicpu.op_reg_reg_reg(A_ADD,tmpreg,ref.base,tmpreg));
  533. ref.base:=tmpreg;
  534. ref.index:=NR_NO;
  535. end;
  536. end
  537. else
  538. begin
  539. tmpreg:=getintregister(list,OS_ADDR);
  540. list.concat(taicpu.op_reg_reg_reg(A_ADD,tmpreg,ref.base,ref.index));
  541. ref.base:=tmpreg;
  542. ref.index:=NR_NO;
  543. end;
  544. end;
  545. list.concat(setoppostfix(taicpu.op_reg_ref(op,reg,ref),oppostfix));
  546. if (tmpreg<>NR_NO) then
  547. ungetregister(list,tmpreg);
  548. end;
  549. procedure tcgarm.a_load_reg_ref(list : taasmoutput; fromsize, tosize: tcgsize; reg : tregister;const ref : treference);
  550. var
  551. oppostfix:toppostfix;
  552. begin
  553. case ToSize of
  554. { signed integer registers }
  555. OS_8,
  556. OS_S8:
  557. oppostfix:=PF_B;
  558. OS_16,
  559. OS_S16:
  560. oppostfix:=PF_H;
  561. OS_32,
  562. OS_S32:
  563. oppostfix:=PF_None;
  564. else
  565. InternalError(200308295);
  566. end;
  567. handle_load_store(list,A_STR,oppostfix,reg,ref);
  568. end;
  569. procedure tcgarm.a_load_ref_reg(list : taasmoutput; fromsize, tosize : tcgsize;const Ref : treference;reg : tregister);
  570. var
  571. oppostfix:toppostfix;
  572. begin
  573. case FromSize of
  574. { signed integer registers }
  575. OS_8:
  576. oppostfix:=PF_B;
  577. OS_S8:
  578. oppostfix:=PF_SB;
  579. OS_16:
  580. oppostfix:=PF_H;
  581. OS_S16:
  582. oppostfix:=PF_SH;
  583. OS_32,
  584. OS_S32:
  585. oppostfix:=PF_None;
  586. else
  587. InternalError(200308291);
  588. end;
  589. handle_load_store(list,A_LDR,oppostfix,reg,ref);
  590. end;
  591. procedure tcgarm.a_load_reg_reg(list : taasmoutput; fromsize, tosize : tcgsize;reg1,reg2 : tregister);
  592. var
  593. instr: taicpu;
  594. so : tshifterop;
  595. begin
  596. shifterop_reset(so);
  597. if (reg1<>reg2) or
  598. (tcgsize2size[tosize] < tcgsize2size[fromsize]) or
  599. ((tcgsize2size[tosize] = tcgsize2size[fromsize]) and
  600. (tosize <> fromsize) and
  601. not(fromsize in [OS_32,OS_S32])) then
  602. begin
  603. case tosize of
  604. OS_8:
  605. list.concat(taicpu.op_reg_reg_const(A_AND,
  606. reg2,reg1,$ff));
  607. OS_S8:
  608. begin
  609. so.shiftmode:=SM_LSL;
  610. so.shiftimm:=24;
  611. list.concat(taicpu.op_reg_reg_shifterop(A_MOV,reg2,reg1,so));
  612. so.shiftmode:=SM_ASR;
  613. so.shiftimm:=24;
  614. list.concat(taicpu.op_reg_reg_shifterop(A_MOV,reg2,reg2,so));
  615. end;
  616. OS_16:
  617. begin
  618. so.shiftmode:=SM_LSL;
  619. so.shiftimm:=16;
  620. list.concat(taicpu.op_reg_reg_shifterop(A_MOV,reg2,reg1,so));
  621. so.shiftmode:=SM_LSR;
  622. so.shiftimm:=16;
  623. list.concat(taicpu.op_reg_reg_shifterop(A_MOV,reg2,reg2,so));
  624. end;
  625. OS_S16:
  626. begin
  627. so.shiftmode:=SM_LSL;
  628. so.shiftimm:=16;
  629. list.concat(taicpu.op_reg_reg_shifterop(A_MOV,reg2,reg1,so));
  630. so.shiftmode:=SM_ASR;
  631. so.shiftimm:=16;
  632. list.concat(taicpu.op_reg_reg_shifterop(A_MOV,reg2,reg2,so));
  633. end;
  634. OS_32,OS_S32:
  635. begin
  636. instr:=taicpu.op_reg_reg(A_MOV,reg2,reg1);
  637. list.concat(instr);
  638. add_move_instruction(instr);
  639. end;
  640. else internalerror(2002090901);
  641. end;
  642. end;
  643. end;
  644. procedure tcgarm.a_loadfpu_reg_reg(list: taasmoutput; size: tcgsize; reg1, reg2: tregister);
  645. begin
  646. list.concat(setoppostfix(taicpu.op_reg_reg(A_MVF,reg2,reg1),cgsize2fpuoppostfix[size]));
  647. end;
  648. procedure tcgarm.a_loadfpu_ref_reg(list: taasmoutput; size: tcgsize; const ref: treference; reg: tregister);
  649. var
  650. oppostfix:toppostfix;
  651. begin
  652. case size of
  653. OS_F32:
  654. oppostfix:=PF_S;
  655. OS_F64:
  656. oppostfix:=PF_D;
  657. OS_F80:
  658. oppostfix:=PF_E;
  659. else
  660. InternalError(200309021);
  661. end;
  662. handle_load_store(list,A_LDF,oppostfix,reg,ref);
  663. end;
  664. procedure tcgarm.a_loadfpu_reg_ref(list: taasmoutput; size: tcgsize; reg: tregister; const ref: treference);
  665. var
  666. oppostfix:toppostfix;
  667. begin
  668. case size of
  669. OS_F32:
  670. oppostfix:=PF_S;
  671. OS_F64:
  672. oppostfix:=PF_D;
  673. OS_F80:
  674. oppostfix:=PF_E;
  675. else
  676. InternalError(200309021);
  677. end;
  678. handle_load_store(list,A_STF,oppostfix,reg,ref);
  679. end;
  680. { comparison operations }
  681. procedure tcgarm.a_cmp_const_reg_label(list : taasmoutput;size : tcgsize;cmp_op : topcmp;a : aword;reg : tregister;
  682. l : tasmlabel);
  683. var
  684. tmpreg : tregister;
  685. b : byte;
  686. begin
  687. if is_shifter_const(a,b) then
  688. list.concat(taicpu.op_reg_const(A_CMP,reg,a))
  689. { CMN reg,0 and CMN reg,$80000000 are different from CMP reg,$ffffffff
  690. and CMP reg,$7fffffff regarding the flags according to the ARM manual }
  691. else if is_shifter_const(-a,b) and (a<>$7fffffff) and (a<>$ffffffff) then
  692. list.concat(taicpu.op_reg_const(A_CMN,reg,-a))
  693. else
  694. begin
  695. tmpreg:=getintregister(list,size);
  696. a_load_const_reg(list,size,a,tmpreg);
  697. list.concat(taicpu.op_reg_reg(A_CMP,reg,tmpreg));
  698. ungetregister(list,tmpreg);
  699. end;
  700. a_jmp_cond(list,cmp_op,l);
  701. end;
  702. procedure tcgarm.a_cmp_reg_reg_label(list : taasmoutput;size : tcgsize;cmp_op : topcmp;reg1,reg2 : tregister;l : tasmlabel);
  703. begin
  704. list.concat(taicpu.op_reg_reg(A_CMP,reg2,reg1));
  705. a_jmp_cond(list,cmp_op,l);
  706. end;
  707. procedure tcgarm.a_jmp_name(list : taasmoutput;const s : string);
  708. begin
  709. list.concat(taicpu.op_sym(A_B,objectlibrary.newasmsymbol(s,AB_EXTERNAL,AT_FUNCTION)));
  710. end;
  711. procedure tcgarm.a_jmp_always(list : taasmoutput;l: tasmlabel);
  712. begin
  713. list.concat(taicpu.op_sym(A_B,objectlibrary.newasmsymbol(l.name,AB_EXTERNAL,AT_FUNCTION)));
  714. end;
  715. procedure tcgarm.a_jmp_flags(list : taasmoutput;const f : TResFlags;l: tasmlabel);
  716. var
  717. ai : taicpu;
  718. begin
  719. ai:=setcondition(taicpu.op_sym(A_B,l),flags_to_cond(f));
  720. ai.is_jmp:=true;
  721. list.concat(ai);
  722. end;
  723. procedure tcgarm.g_flags2reg(list: taasmoutput; size: TCgSize; const f: TResFlags; reg: TRegister);
  724. var
  725. ai : taicpu;
  726. begin
  727. list.concat(setcondition(taicpu.op_reg_const(A_MOV,reg,1),flags_to_cond(f)));
  728. list.concat(setcondition(taicpu.op_reg_const(A_MOV,reg,0),inverse_cond[flags_to_cond(f)]));
  729. end;
  730. procedure tcgarm.g_copyvaluepara_openarray(list : taasmoutput;const ref, lenref:treference;elesize:aword);
  731. begin
  732. end;
  733. procedure tcgarm.g_stackframe_entry(list : taasmoutput;localsize : longint);
  734. var
  735. ref : treference;
  736. shift : byte;
  737. begin
  738. LocalSize:=align(LocalSize,4);
  739. a_reg_alloc(list,NR_STACK_POINTER_REG);
  740. a_reg_alloc(list,NR_FRAME_POINTER_REG);
  741. a_reg_alloc(list,NR_R12);
  742. list.concat(taicpu.op_reg_reg(A_MOV,NR_R12,NR_STACK_POINTER_REG));
  743. { save int registers }
  744. reference_reset(ref);
  745. ref.index:=NR_STACK_POINTER_REG;
  746. ref.addressmode:=AM_PREINDEXED;
  747. list.concat(setoppostfix(taicpu.op_ref_regset(A_STM,ref,rg[R_INTREGISTER].used_in_proc-paramanager.get_volatile_registers_int(pocall_stdcall)+[RS_R11,RS_R12,RS_R14,RS_R15]),PF_FD));
  748. list.concat(taicpu.op_reg_reg_const(A_SUB,NR_FRAME_POINTER_REG,NR_R12,4));
  749. { allocate necessary stack size }
  750. { don't use a_op_const_reg_reg here because we don't allow register allocations
  751. in the entry/exit code }
  752. if not(is_shifter_const(localsize,shift)) then
  753. begin
  754. a_load_const_reg(list,OS_ADDR,LocalSize,NR_R12);
  755. list.concat(taicpu.op_reg_reg_reg(A_SUB,NR_STACK_POINTER_REG,NR_STACK_POINTER_REG,NR_R12));
  756. a_reg_dealloc(list,NR_R12);
  757. end
  758. else
  759. begin
  760. a_reg_dealloc(list,NR_R12);
  761. list.concat(taicpu.op_reg_reg_const(A_SUB,NR_STACK_POINTER_REG,NR_STACK_POINTER_REG,LocalSize));
  762. end;
  763. end;
  764. procedure tcgarm.g_return_from_proc(list : taasmoutput;parasize : aword);
  765. var
  766. ref : treference;
  767. begin
  768. if (current_procinfo.framepointer=NR_STACK_POINTER_REG) then
  769. list.concat(taicpu.op_reg_reg(A_MOV,NR_R15,NR_R14))
  770. else
  771. begin
  772. { restore int registers and return }
  773. reference_reset(ref);
  774. ref.index:=NR_FRAME_POINTER_REG;
  775. 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));
  776. end;
  777. end;
  778. procedure tcgarm.g_restore_frame_pointer(list : taasmoutput);
  779. begin
  780. { the frame pointer on the ARM is restored while the ret is executed }
  781. end;
  782. procedure tcgarm.a_loadaddr_ref_reg(list : taasmoutput;const ref : treference;r : tregister);
  783. var
  784. b : byte;
  785. tmpref : treference;
  786. instr : taicpu;
  787. begin
  788. if ref.addressmode<>AM_OFFSET then
  789. internalerror(200309071);
  790. tmpref:=ref;
  791. { Be sure to have a base register }
  792. if (tmpref.base=NR_NO) then
  793. begin
  794. if tmpref.shiftmode<>SM_None then
  795. internalerror(200308294);
  796. if tmpref.signindex<0 then
  797. internalerror(200312023);
  798. tmpref.base:=tmpref.index;
  799. tmpref.index:=NR_NO;
  800. end;
  801. if assigned(tmpref.symbol) or
  802. not((is_shifter_const(dword(tmpref.offset),b)) or
  803. (is_shifter_const(dword(-tmpref.offset),b))
  804. ) then
  805. fixref(list,tmpref);
  806. { expect a base here }
  807. if tmpref.base=NR_NO then
  808. internalerror(200312022);
  809. if tmpref.index<>NR_NO then
  810. begin
  811. if tmpref.shiftmode<>SM_None then
  812. internalerror(200312021);
  813. if tmpref.signindex<0 then
  814. a_op_reg_reg_reg(list,OP_SUB,OS_ADDR,tmpref.base,tmpref.index,r)
  815. else
  816. a_op_reg_reg_reg(list,OP_ADD,OS_ADDR,tmpref.base,tmpref.index,r);
  817. if tmpref.offset<>0 then
  818. a_op_const_reg_reg(list,OP_ADD,OS_ADDR,tmpref.offset,r,r);
  819. end
  820. else
  821. begin
  822. if tmpref.offset<>0 then
  823. a_op_const_reg_reg(list,OP_ADD,OS_ADDR,tmpref.offset,tmpref.base,r)
  824. else
  825. begin
  826. instr:=taicpu.op_reg_reg(A_MOV,r,tmpref.base);
  827. list.concat(instr);
  828. add_move_instruction(instr);
  829. end;
  830. end;
  831. reference_release(list,tmpref);
  832. end;
  833. procedure tcgarm.fixref(list : taasmoutput;var ref : treference);
  834. var
  835. tmpreg : tregister;
  836. tmpref : treference;
  837. l : tasmlabel;
  838. begin
  839. { absolute symbols can't be handled directly, we've to store the symbol reference
  840. in the text segment and access it pc relative
  841. For now, we assume that references where base or index equals to PC are already
  842. relative, all other references are assumed to be absolute and thus they need
  843. to be handled extra.
  844. A proper solution would be to change refoptions to a set and store the information
  845. if the symbol is absolute or relative there.
  846. }
  847. { create consts entry }
  848. reference_reset(tmpref);
  849. objectlibrary.getlabel(l);
  850. cg.a_label(current_procinfo.aktlocaldata,l);
  851. tmpref.symboldata:=current_procinfo.aktlocaldata.last;
  852. if assigned(ref.symbol) then
  853. current_procinfo.aktlocaldata.concat(tai_const_symbol.Create_offset(ref.symbol,ref.offset))
  854. else
  855. current_procinfo.aktlocaldata.concat(tai_const.Create_32bit(ref.offset));
  856. { load consts entry }
  857. tmpreg:=getintregister(list,OS_INT);
  858. tmpref.symbol:=l;
  859. tmpref.base:=NR_PC;
  860. list.concat(taicpu.op_reg_ref(A_LDR,tmpreg,tmpref));
  861. if (ref.base<>NR_NO) then
  862. begin
  863. if ref.index<>NR_NO then
  864. begin
  865. list.concat(taicpu.op_reg_reg_reg(A_ADD,tmpreg,ref.base,tmpreg));
  866. ref.base:=tmpreg;
  867. end
  868. else
  869. begin
  870. ref.index:=tmpreg;
  871. ref.shiftimm:=0;
  872. ref.signindex:=1;
  873. ref.shiftmode:=SM_None;
  874. end;
  875. end
  876. else
  877. ref.base:=tmpreg;
  878. ref.offset:=0;
  879. ref.symbol:=nil;
  880. end;
  881. procedure tcgarm.g_concatcopy(list : taasmoutput;const source,dest : treference;len : aword; delsource,loadref : boolean);
  882. var
  883. srcref,dstref:treference;
  884. srcreg,destreg,countreg,r:tregister;
  885. helpsize:aword;
  886. copysize:byte;
  887. cgsize:Tcgsize;
  888. procedure genloop(count : aword;size : byte);
  889. const
  890. size2opsize : array[1..4] of tcgsize = (OS_8,OS_16,OS_NO,OS_32);
  891. var
  892. l : tasmlabel;
  893. begin
  894. objectlibrary.getlabel(l);
  895. a_load_const_reg(list,OS_INT,count,countreg);
  896. cg.a_label(list,l);
  897. srcref.addressmode:=AM_POSTINDEXED;
  898. dstref.addressmode:=AM_POSTINDEXED;
  899. srcref.offset:=size;
  900. dstref.offset:=size;
  901. r:=getintregister(list,size2opsize[size]);
  902. a_load_ref_reg(list,size2opsize[size],size2opsize[size],srcref,r);
  903. a_load_reg_ref(list,size2opsize[size],size2opsize[size],r,dstref);
  904. ungetregister(list,r);
  905. list.concat(setoppostfix(taicpu.op_reg_reg_const(A_SUB,countreg,countreg,1),PF_S));
  906. list.concat(setcondition(taicpu.op_sym(A_B,l),C_NE));
  907. { keep the registers alive }
  908. list.concat(taicpu.op_reg_reg(A_MOV,countreg,countreg));
  909. list.concat(taicpu.op_reg_reg(A_MOV,srcreg,srcreg));
  910. list.concat(taicpu.op_reg_reg(A_MOV,destreg,destreg));
  911. end;
  912. begin
  913. helpsize:=12;
  914. dstref:=dest;
  915. srcref:=source;
  916. if cs_littlesize in aktglobalswitches then
  917. helpsize:=8;
  918. if not loadref and (len<=helpsize) then
  919. begin
  920. copysize:=4;
  921. cgsize:=OS_32;
  922. while len<>0 do
  923. begin
  924. if len<2 then
  925. begin
  926. copysize:=1;
  927. cgsize:=OS_8;
  928. end
  929. else if len<4 then
  930. begin
  931. copysize:=2;
  932. cgsize:=OS_16;
  933. end;
  934. dec(len,copysize);
  935. r:=getintregister(list,cgsize);
  936. a_load_ref_reg(list,cgsize,cgsize,srcref,r);
  937. if (len=0) and delsource then
  938. reference_release(list,source);
  939. a_load_reg_ref(list,cgsize,cgsize,r,dstref);
  940. inc(srcref.offset,copysize);
  941. inc(dstref.offset,copysize);
  942. ungetregister(list,r);
  943. end;
  944. end
  945. else
  946. begin
  947. destreg:=getintregister(list,OS_ADDR);
  948. a_loadaddr_ref_reg(list,dest,destreg);
  949. reference_reset_base(dstref,destreg,0);
  950. srcreg:=getintregister(list,OS_ADDR);
  951. if loadref then
  952. a_load_ref_reg(list,OS_ADDR,OS_ADDR,source,srcreg)
  953. else
  954. a_loadaddr_ref_reg(list,source,srcreg);
  955. reference_reset_base(srcref,srcreg,0);
  956. if delsource then
  957. reference_release(list,source);
  958. countreg:=getintregister(list,OS_32);
  959. // if cs_littlesize in aktglobalswitches then
  960. genloop(len,1);
  961. {
  962. else
  963. begin
  964. helpsize:=len shr 2;
  965. len:=len and 3;
  966. if helpsize>1 then
  967. begin
  968. a_load_const_reg(list,OS_INT,helpsize,countreg);
  969. list.concat(Taicpu.op_none(A_REP,S_NO));
  970. end;
  971. if helpsize>0 then
  972. list.concat(Taicpu.op_none(A_MOVSD,S_NO));
  973. if len>1 then
  974. begin
  975. dec(len,2);
  976. list.concat(Taicpu.op_none(A_MOVSW,S_NO));
  977. end;
  978. if len=1 then
  979. list.concat(Taicpu.op_none(A_MOVSB,S_NO));
  980. end;
  981. }
  982. ungetregister(list,countreg);
  983. ungetregister(list,srcreg);
  984. ungetregister(list,destreg);
  985. end;
  986. if delsource then
  987. tg.ungetiftemp(list,source);
  988. end;
  989. procedure tcgarm.g_overflowcheck(list: taasmoutput; const l: tlocation; def: tdef);
  990. begin
  991. end;
  992. procedure tcgarm.g_save_standard_registers(list : taasmoutput);
  993. begin
  994. { we support only ARM standard calling conventions so this procedure has no use on the ARM }
  995. end;
  996. procedure tcgarm.g_restore_standard_registers(list : taasmoutput);
  997. begin
  998. { we support only ARM standard calling conventions so this procedure has no use on the ARM }
  999. end;
  1000. procedure tcgarm.g_save_all_registers(list : taasmoutput);
  1001. begin
  1002. { we support only ARM standard calling conventions so this procedure has no use on the ARM }
  1003. end;
  1004. procedure tcgarm.g_restore_all_registers(list : taasmoutput;const funcretparaloc:tparalocation);
  1005. begin
  1006. { we support only ARM standard calling conventions so this procedure has no use on the ARM }
  1007. end;
  1008. procedure tcgarm.a_jmp_cond(list : taasmoutput;cond : TOpCmp;l: tasmlabel);
  1009. var
  1010. ai : taicpu;
  1011. begin
  1012. ai:=Taicpu.Op_sym(A_B,l);
  1013. ai.SetCondition(OpCmp2AsmCond[cond]);
  1014. ai.is_jmp:=true;
  1015. list.concat(ai);
  1016. end;
  1017. procedure tcg64farm.a_op64_reg_reg(list : taasmoutput;op:TOpCG;regsrc,regdst : tregister64);
  1018. var
  1019. tmpreg : tregister;
  1020. begin
  1021. case op of
  1022. OP_NEG:
  1023. begin
  1024. list.concat(setoppostfix(taicpu.op_reg_reg_const(A_RSB,regdst.reglo,regsrc.reglo,0),PF_S));
  1025. list.concat(taicpu.op_reg_reg_const(A_RSC,regdst.reghi,regsrc.reghi,0));
  1026. end;
  1027. OP_NOT:
  1028. begin
  1029. cg.a_op_reg_reg(list,OP_NOT,OS_INT,regsrc.reglo,regdst.reglo);
  1030. cg.a_op_reg_reg(list,OP_NOT,OS_INT,regsrc.reghi,regdst.reghi);
  1031. end;
  1032. else
  1033. a_op64_reg_reg_reg(list,op,regsrc,regdst,regdst);
  1034. end;
  1035. end;
  1036. procedure tcg64farm.a_op64_const_reg(list : taasmoutput;op:TOpCG;value : qword;reg : tregister64);
  1037. begin
  1038. a_op64_const_reg_reg(list,op,value,reg,reg);
  1039. end;
  1040. procedure tcg64farm.a_op64_const_reg_reg(list: taasmoutput;op:TOpCG;value : qword;regsrc,regdst : tregister64);
  1041. var
  1042. tmpreg : tregister;
  1043. b : byte;
  1044. begin
  1045. case op of
  1046. OP_AND,OP_OR,OP_XOR:
  1047. begin
  1048. cg.a_op_const_reg_reg(list,op,OS_32,lo(value),regsrc.reglo,regdst.reglo);
  1049. cg.a_op_const_reg_reg(list,op,OS_32,hi(value),regsrc.reghi,regdst.reghi);
  1050. end;
  1051. OP_ADD:
  1052. begin
  1053. if is_shifter_const(lo(value),b) then
  1054. list.concat(setoppostfix(taicpu.op_reg_reg_const(A_ADD,regdst.reglo,regsrc.reglo,lo(value)),PF_S))
  1055. else
  1056. begin
  1057. tmpreg:=cg.getintregister(list,OS_32);
  1058. cg.a_load_const_reg(list,OS_32,lo(value),tmpreg);
  1059. list.concat(setoppostfix(taicpu.op_reg_reg_reg(A_ADD,regdst.reglo,regsrc.reglo,tmpreg),PF_S));
  1060. cg.ungetregister(list,tmpreg);
  1061. end;
  1062. if is_shifter_const(hi(value),b) then
  1063. list.concat(taicpu.op_reg_reg_const(A_ADC,regdst.reghi,regsrc.reghi,hi(value)))
  1064. else
  1065. begin
  1066. tmpreg:=cg.getintregister(list,OS_32);
  1067. cg.a_load_const_reg(list,OS_32,hi(value),tmpreg);
  1068. list.concat(taicpu.op_reg_reg_reg(A_ADC,regdst.reghi,regsrc.reghi,tmpreg));
  1069. cg.ungetregister(list,tmpreg);
  1070. end;
  1071. end;
  1072. OP_SUB:
  1073. begin
  1074. if is_shifter_const(lo(value),b) then
  1075. list.concat(setoppostfix(taicpu.op_reg_reg_const(A_SUB,regdst.reglo,regsrc.reglo,lo(value)),PF_S))
  1076. else
  1077. begin
  1078. tmpreg:=cg.getintregister(list,OS_32);
  1079. cg.a_load_const_reg(list,OS_32,lo(value),tmpreg);
  1080. list.concat(setoppostfix(taicpu.op_reg_reg_reg(A_SUB,regdst.reglo,regsrc.reglo,tmpreg),PF_S));
  1081. cg.ungetregister(list,tmpreg);
  1082. end;
  1083. if is_shifter_const(hi(value),b) then
  1084. list.concat(taicpu.op_reg_reg_const(A_SBC,regdst.reghi,regsrc.reghi,hi(value)))
  1085. else
  1086. begin
  1087. tmpreg:=cg.getintregister(list,OS_32);
  1088. cg.a_load_const_reg(list,OS_32,hi(value),tmpreg);
  1089. list.concat(taicpu.op_reg_reg_reg(A_SBC,regdst.reghi,regsrc.reghi,tmpreg));
  1090. cg.ungetregister(list,tmpreg);
  1091. end;
  1092. end;
  1093. else
  1094. internalerror(2003083101);
  1095. end;
  1096. end;
  1097. procedure tcg64farm.a_op64_reg_reg_reg(list: taasmoutput;op:TOpCG;regsrc1,regsrc2,regdst : tregister64);
  1098. begin
  1099. case op of
  1100. OP_AND,OP_OR,OP_XOR:
  1101. begin
  1102. cg.a_op_reg_reg_reg(list,op,OS_32,regsrc1.reglo,regsrc2.reglo,regdst.reglo);
  1103. cg.a_op_reg_reg_reg(list,op,OS_32,regsrc1.reghi,regsrc2.reghi,regdst.reghi);
  1104. end;
  1105. OP_ADD:
  1106. begin
  1107. list.concat(setoppostfix(taicpu.op_reg_reg_reg(A_ADD,regdst.reglo,regsrc1.reglo,regsrc2.reglo),PF_S));
  1108. list.concat(taicpu.op_reg_reg_reg(A_ADC,regdst.reghi,regsrc1.reghi,regsrc2.reghi));
  1109. end;
  1110. OP_SUB:
  1111. begin
  1112. list.concat(setoppostfix(taicpu.op_reg_reg_reg(A_SUB,regdst.reglo,regsrc2.reglo,regsrc1.reglo),PF_S));
  1113. list.concat(taicpu.op_reg_reg_reg(A_SBC,regdst.reghi,regsrc2.reghi,regsrc1.reghi));
  1114. end;
  1115. else
  1116. internalerror(2003083101);
  1117. end;
  1118. end;
  1119. begin
  1120. cg:=tcgarm.create;
  1121. cg64:=tcg64farm.create;
  1122. end.
  1123. {
  1124. $Log$
  1125. Revision 1.48 2004-03-14 16:15:40 florian
  1126. * spilling problem fixed
  1127. * handling of floating point memory references fixed
  1128. Revision 1.47 2004/03/10 22:35:40 florian
  1129. + fixed code generation for cmn
  1130. Revision 1.46 2004/03/06 20:35:19 florian
  1131. * fixed arm compilation
  1132. * cleaned up code generation for exported linux procedures
  1133. Revision 1.45 2004/03/02 00:36:33 olle
  1134. * big transformation of Tai_[const_]Symbol.Create[data]name*
  1135. Revision 1.44 2004/02/04 22:01:13 peter
  1136. * first try to get cpupara working for x86_64
  1137. Revision 1.43 2004/01/29 17:09:32 florian
  1138. * handling of floating point references fixed
  1139. Revision 1.42 2004/01/28 15:36:47 florian
  1140. * fixed another couple of arm bugs
  1141. Revision 1.41 2004/01/27 15:04:06 florian
  1142. * fixed code generation for math inl. nodes
  1143. * more code generator improvements
  1144. Revision 1.40 2004/01/26 19:05:56 florian
  1145. * fixed several arm issues
  1146. Revision 1.39 2004/01/24 20:19:46 florian
  1147. * fixed some spilling stuff
  1148. + not(<int64>) implemented
  1149. + small set comparisations implemented
  1150. Revision 1.38 2004/01/24 01:33:20 florian
  1151. * fixref fixed if index, base and offset were given
  1152. Revision 1.37 2004/01/22 20:13:18 florian
  1153. * fixed several issues with flags
  1154. Revision 1.36 2004/01/22 02:22:47 florian
  1155. * op_const_reg_reg with OP_SAR fixed
  1156. Revision 1.35 2004/01/22 01:47:15 florian
  1157. * improved register usage
  1158. + implemented second_cmp64bit
  1159. Revision 1.34 2004/01/21 19:01:03 florian
  1160. * fixed handling of max. distance of pc relative symbols
  1161. Revision 1.33 2004/01/21 15:41:56 florian
  1162. * fixed register allocator problems with concatcopy
  1163. Revision 1.32 2004/01/21 14:22:00 florian
  1164. + reintroduce implemented
  1165. Revision 1.31 2004/01/21 01:22:35 florian
  1166. * fixed a_cmp_const_reg_label
  1167. * fixed volatile register handling which was broken by my last patch
  1168. Revision 1.30 2004/01/20 23:18:00 florian
  1169. * fixed a_call_reg
  1170. + implemented paramgr.get_volative_registers
  1171. Revision 1.29 2003/12/26 14:02:30 peter
  1172. * sparc updates
  1173. * use registertype in spill_register
  1174. Revision 1.28 2003/12/18 17:06:21 florian
  1175. * arm compiler compilation fixed
  1176. Revision 1.27 2003/12/08 17:43:57 florian
  1177. * fixed ldm/stm arm assembler reading
  1178. * fixed a_load_reg_reg with OS_8 on ARM
  1179. * non supported calling conventions cause only a warning now
  1180. Revision 1.26 2003/12/03 17:39:05 florian
  1181. * fixed several arm calling conventions issues
  1182. * fixed reference reading in the assembler reader
  1183. * fixed a_loadaddr_ref_reg
  1184. Revision 1.25 2003/11/30 19:35:29 florian
  1185. * fixed several arm related problems
  1186. Revision 1.24 2003/11/24 15:17:37 florian
  1187. * changed some types to prevend range check errors
  1188. Revision 1.23 2003/11/21 16:29:26 florian
  1189. * fixed reading of reg. sets in the arm assembler reader
  1190. Revision 1.22 2003/11/07 15:58:32 florian
  1191. * Florian's culmutative nr. 1; contains:
  1192. - invalid calling conventions for a certain cpu are rejected
  1193. - arm softfloat calling conventions
  1194. - -Sp for cpu dependend code generation
  1195. - several arm fixes
  1196. - remaining code for value open array paras on heap
  1197. Revision 1.21 2003/11/02 14:30:03 florian
  1198. * fixed ARM for new reg. allocation scheme
  1199. Revision 1.20 2003/10/11 16:06:42 florian
  1200. * fixed some MMX<->SSE
  1201. * started to fix ppc, needs an overhaul
  1202. + stabs info improve for spilling, not sure if it works correctly/completly
  1203. - MMX_SUPPORT removed from Makefile.fpc
  1204. Revision 1.19 2003/09/11 11:55:00 florian
  1205. * improved arm code generation
  1206. * move some protected and private field around
  1207. * the temp. register for register parameters/arguments are now released
  1208. before the move to the parameter register is done. This improves
  1209. the code in a lot of cases.
  1210. Revision 1.18 2003/09/09 12:53:40 florian
  1211. * some assembling problems fixed
  1212. * improved loadaddr_ref_reg
  1213. Revision 1.17 2003/09/06 16:45:51 florian
  1214. * fixed exit code (no preindexed addressing mode in LDM)
  1215. Revision 1.16 2003/09/06 11:21:50 florian
  1216. * fixed stm and ldm to be usable with preindex operand
  1217. Revision 1.15 2003/09/05 23:57:01 florian
  1218. * arm is working again as before the new register naming scheme was implemented
  1219. Revision 1.14 2003/09/04 21:07:03 florian
  1220. * ARM compiler compiles again
  1221. Revision 1.13 2003/09/04 00:15:29 florian
  1222. * first bunch of adaptions of arm compiler for new register type
  1223. Revision 1.12 2003/09/03 19:10:30 florian
  1224. * initial revision of new register naming
  1225. Revision 1.11 2003/09/03 11:18:37 florian
  1226. * fixed arm concatcopy
  1227. + arm support in the common compiler sources added
  1228. * moved some generic cg code around
  1229. + tfputype added
  1230. * ...
  1231. Revision 1.10 2003/09/01 15:11:16 florian
  1232. * fixed reference handling
  1233. * fixed operand postfix for floating point instructions
  1234. * fixed wrong shifter constant handling
  1235. Revision 1.9 2003/09/01 09:54:57 florian
  1236. * results of work on arm port last weekend
  1237. Revision 1.8 2003/08/29 21:36:28 florian
  1238. * fixed procedure entry/exit code
  1239. * started to fix reference handling
  1240. Revision 1.7 2003/08/28 13:26:10 florian
  1241. * another couple of arm fixes
  1242. Revision 1.6 2003/08/28 00:05:29 florian
  1243. * today's arm patches
  1244. Revision 1.5 2003/08/25 23:20:38 florian
  1245. + started to implement FPU support for the ARM
  1246. * fixed a lot of other things
  1247. Revision 1.4 2003/08/24 12:27:26 florian
  1248. * continued to work on the arm port
  1249. Revision 1.3 2003/08/21 03:14:00 florian
  1250. * arm compiler can be compiled; far from being working
  1251. Revision 1.2 2003/08/20 15:50:12 florian
  1252. * more arm stuff
  1253. Revision 1.1 2003/07/21 16:35:30 florian
  1254. * very basic stuff for the arm
  1255. }