cgcpu.pas 50 KB

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