cgcpu.pas 48 KB

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