cgcpu.pas 50 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439
  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;const funcretparaloc:tparalocation);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;const funcretparaloc:tparalocation);
  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.44 2004-02-04 22:01:13 peter
  1118. * first try to get cpupara working for x86_64
  1119. Revision 1.43 2004/01/29 17:09:32 florian
  1120. * handling of floating point references fixed
  1121. Revision 1.42 2004/01/28 15:36:47 florian
  1122. * fixed another couple of arm bugs
  1123. Revision 1.41 2004/01/27 15:04:06 florian
  1124. * fixed code generation for math inl. nodes
  1125. * more code generator improvements
  1126. Revision 1.40 2004/01/26 19:05:56 florian
  1127. * fixed several arm issues
  1128. Revision 1.39 2004/01/24 20:19:46 florian
  1129. * fixed some spilling stuff
  1130. + not(<int64>) implemented
  1131. + small set comparisations implemented
  1132. Revision 1.38 2004/01/24 01:33:20 florian
  1133. * fixref fixed if index, base and offset were given
  1134. Revision 1.37 2004/01/22 20:13:18 florian
  1135. * fixed several issues with flags
  1136. Revision 1.36 2004/01/22 02:22:47 florian
  1137. * op_const_reg_reg with OP_SAR fixed
  1138. Revision 1.35 2004/01/22 01:47:15 florian
  1139. * improved register usage
  1140. + implemented second_cmp64bit
  1141. Revision 1.34 2004/01/21 19:01:03 florian
  1142. * fixed handling of max. distance of pc relative symbols
  1143. Revision 1.33 2004/01/21 15:41:56 florian
  1144. * fixed register allocator problems with concatcopy
  1145. Revision 1.32 2004/01/21 14:22:00 florian
  1146. + reintroduce implemented
  1147. Revision 1.31 2004/01/21 01:22:35 florian
  1148. * fixed a_cmp_const_reg_label
  1149. * fixed volatile register handling which was broken by my last patch
  1150. Revision 1.30 2004/01/20 23:18:00 florian
  1151. * fixed a_call_reg
  1152. + implemented paramgr.get_volative_registers
  1153. Revision 1.29 2003/12/26 14:02:30 peter
  1154. * sparc updates
  1155. * use registertype in spill_register
  1156. Revision 1.28 2003/12/18 17:06:21 florian
  1157. * arm compiler compilation fixed
  1158. Revision 1.27 2003/12/08 17:43:57 florian
  1159. * fixed ldm/stm arm assembler reading
  1160. * fixed a_load_reg_reg with OS_8 on ARM
  1161. * non supported calling conventions cause only a warning now
  1162. Revision 1.26 2003/12/03 17:39:05 florian
  1163. * fixed several arm calling conventions issues
  1164. * fixed reference reading in the assembler reader
  1165. * fixed a_loadaddr_ref_reg
  1166. Revision 1.25 2003/11/30 19:35:29 florian
  1167. * fixed several arm related problems
  1168. Revision 1.24 2003/11/24 15:17:37 florian
  1169. * changed some types to prevend range check errors
  1170. Revision 1.23 2003/11/21 16:29:26 florian
  1171. * fixed reading of reg. sets in the arm assembler reader
  1172. Revision 1.22 2003/11/07 15:58:32 florian
  1173. * Florian's culmutative nr. 1; contains:
  1174. - invalid calling conventions for a certain cpu are rejected
  1175. - arm softfloat calling conventions
  1176. - -Sp for cpu dependend code generation
  1177. - several arm fixes
  1178. - remaining code for value open array paras on heap
  1179. Revision 1.21 2003/11/02 14:30:03 florian
  1180. * fixed ARM for new reg. allocation scheme
  1181. Revision 1.20 2003/10/11 16:06:42 florian
  1182. * fixed some MMX<->SSE
  1183. * started to fix ppc, needs an overhaul
  1184. + stabs info improve for spilling, not sure if it works correctly/completly
  1185. - MMX_SUPPORT removed from Makefile.fpc
  1186. Revision 1.19 2003/09/11 11:55:00 florian
  1187. * improved arm code generation
  1188. * move some protected and private field around
  1189. * the temp. register for register parameters/arguments are now released
  1190. before the move to the parameter register is done. This improves
  1191. the code in a lot of cases.
  1192. Revision 1.18 2003/09/09 12:53:40 florian
  1193. * some assembling problems fixed
  1194. * improved loadaddr_ref_reg
  1195. Revision 1.17 2003/09/06 16:45:51 florian
  1196. * fixed exit code (no preindexed addressing mode in LDM)
  1197. Revision 1.16 2003/09/06 11:21:50 florian
  1198. * fixed stm and ldm to be usable with preindex operand
  1199. Revision 1.15 2003/09/05 23:57:01 florian
  1200. * arm is working again as before the new register naming scheme was implemented
  1201. Revision 1.14 2003/09/04 21:07:03 florian
  1202. * ARM compiler compiles again
  1203. Revision 1.13 2003/09/04 00:15:29 florian
  1204. * first bunch of adaptions of arm compiler for new register type
  1205. Revision 1.12 2003/09/03 19:10:30 florian
  1206. * initial revision of new register naming
  1207. Revision 1.11 2003/09/03 11:18:37 florian
  1208. * fixed arm concatcopy
  1209. + arm support in the common compiler sources added
  1210. * moved some generic cg code around
  1211. + tfputype added
  1212. * ...
  1213. Revision 1.10 2003/09/01 15:11:16 florian
  1214. * fixed reference handling
  1215. * fixed operand postfix for floating point instructions
  1216. * fixed wrong shifter constant handling
  1217. Revision 1.9 2003/09/01 09:54:57 florian
  1218. * results of work on arm port last weekend
  1219. Revision 1.8 2003/08/29 21:36:28 florian
  1220. * fixed procedure entry/exit code
  1221. * started to fix reference handling
  1222. Revision 1.7 2003/08/28 13:26:10 florian
  1223. * another couple of arm fixes
  1224. Revision 1.6 2003/08/28 00:05:29 florian
  1225. * today's arm patches
  1226. Revision 1.5 2003/08/25 23:20:38 florian
  1227. + started to implement FPU support for the ARM
  1228. * fixed a lot of other things
  1229. Revision 1.4 2003/08/24 12:27:26 florian
  1230. * continued to work on the arm port
  1231. Revision 1.3 2003/08/21 03:14:00 florian
  1232. * arm compiler can be compiled; far from being working
  1233. Revision 1.2 2003/08/20 15:50:12 florian
  1234. * more arm stuff
  1235. Revision 1.1 2003/07/21 16:35:30 florian
  1236. * very basic stuff for the arm
  1237. }