cgcpu.pas 75 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000
  1. {
  2. Copyright (c) 2003 by Florian Klaempfl
  3. Member of the Free Pascal development team
  4. This unit implements the code generator for the ARM
  5. This program is free software; you can redistribute it and/or modify
  6. it under the terms of the GNU General Public License as published by
  7. the Free Software Foundation; either version 2 of the License, or
  8. (at your option) any later version.
  9. This program is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. GNU General Public License for more details.
  13. You should have received a copy of the GNU General Public License
  14. along with this program; if not, write to the Free Software
  15. Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  16. ****************************************************************************
  17. }
  18. unit cgcpu;
  19. {$i fpcdefs.inc}
  20. interface
  21. uses
  22. globtype,symtype,symdef,
  23. cgbase,cgutils,cgobj,
  24. aasmbase,aasmcpu,aasmtai,aasmdata,
  25. parabase,
  26. cpubase,cpuinfo,node,cg64f32,rgcpu;
  27. type
  28. tcgarm = class(tcg)
  29. { true, if the next arithmetic operation should modify the flags }
  30. cgsetflags : boolean;
  31. procedure init_register_allocators;override;
  32. procedure done_register_allocators;override;
  33. procedure a_param_const(list : TAsmList;size : tcgsize;a : aint;const paraloc : TCGPara);override;
  34. procedure a_param_ref(list : TAsmList;size : tcgsize;const r : treference;const paraloc : TCGPara);override;
  35. procedure a_paramaddr_ref(list : TAsmList;const r : treference;const paraloc : TCGPara);override;
  36. procedure a_call_name(list : TAsmList;const s : string);override;
  37. procedure a_call_reg(list : TAsmList;reg: tregister);override;
  38. procedure a_call_ref(list : TAsmList;ref: treference);override;
  39. procedure a_op_const_reg(list : TAsmList; Op: TOpCG; size: TCGSize; a: aint; reg: TRegister); override;
  40. procedure a_op_reg_reg(list : TAsmList; Op: TOpCG; size: TCGSize; src, dst: TRegister); override;
  41. procedure a_op_const_reg_reg(list: TAsmList; op: TOpCg;
  42. size: tcgsize; a: aint; src, dst: tregister); override;
  43. procedure a_op_reg_reg_reg(list: TAsmList; op: TOpCg;
  44. size: tcgsize; src1, src2, dst: tregister); override;
  45. procedure a_op_const_reg_reg_checkoverflow(list: TAsmList; op: TOpCg; size: tcgsize; a: aint; src, dst: tregister;setflags : boolean;var ovloc : tlocation);override;
  46. procedure a_op_reg_reg_reg_checkoverflow(list: TAsmList; op: TOpCg; size: tcgsize; src1, src2, dst: tregister;setflags : boolean;var ovloc : tlocation);override;
  47. { move instructions }
  48. procedure a_load_const_reg(list : TAsmList; size: tcgsize; a : aint;reg : tregister);override;
  49. procedure a_load_reg_ref(list : TAsmList; fromsize, tosize: tcgsize; reg : tregister;const ref : treference);override;
  50. procedure a_load_ref_reg(list : TAsmList; fromsize, tosize : tcgsize;const Ref : treference;reg : tregister);override;
  51. procedure a_load_reg_reg(list : TAsmList; fromsize, tosize : tcgsize;reg1,reg2 : tregister);override;
  52. function a_internal_load_reg_ref(list : TAsmList; fromsize, tosize: tcgsize; reg : tregister;const ref : treference):treference;
  53. function a_internal_load_ref_reg(list : TAsmList; fromsize, tosize : tcgsize;const Ref : treference;reg : tregister):treference;
  54. { fpu move instructions }
  55. procedure a_loadfpu_reg_reg(list: TAsmList; size: tcgsize; reg1, reg2: tregister); override;
  56. procedure a_loadfpu_ref_reg(list: TAsmList; size: tcgsize; const ref: treference; reg: tregister); override;
  57. procedure a_loadfpu_reg_ref(list: TAsmList; size: tcgsize; reg: tregister; const ref: treference); override;
  58. procedure a_paramfpu_ref(list : TAsmList;size : tcgsize;const ref : treference;const paraloc : TCGPara);override;
  59. { comparison operations }
  60. procedure a_cmp_const_reg_label(list : TAsmList;size : tcgsize;cmp_op : topcmp;a : aint;reg : tregister;
  61. l : tasmlabel);override;
  62. procedure a_cmp_reg_reg_label(list : TAsmList;size : tcgsize;cmp_op : topcmp;reg1,reg2 : tregister;l : tasmlabel); override;
  63. procedure a_jmp_name(list : TAsmList;const s : string); override;
  64. procedure a_jmp_always(list : TAsmList;l: tasmlabel); override;
  65. procedure a_jmp_flags(list : TAsmList;const f : TResFlags;l: tasmlabel); override;
  66. procedure g_flags2reg(list: TAsmList; size: TCgSize; const f: TResFlags; reg: TRegister); override;
  67. procedure g_proc_entry(list : TAsmList;localsize : longint;nostackframe:boolean);override;
  68. procedure g_proc_exit(list : TAsmList;parasize : longint;nostackframe:boolean); override;
  69. procedure a_loadaddr_ref_reg(list : TAsmList;const ref : treference;r : tregister);override;
  70. procedure g_concatcopy(list : TAsmList;const source,dest : treference;len : aint);override;
  71. procedure g_concatcopy_unaligned(list : TAsmList;const source,dest : treference;len : aint);override;
  72. procedure g_concatcopy_move(list : TAsmList;const source,dest : treference;len : aint);
  73. procedure g_concatcopy_internal(list : TAsmList;const source,dest : treference;len : aint;aligned : boolean);
  74. procedure g_overflowcheck(list: TAsmList; const l: tlocation; def: tdef); override;
  75. procedure g_overflowCheck_loc(List:TAsmList;const Loc:TLocation;def:TDef;ovloc : tlocation);override;
  76. procedure g_save_standard_registers(list : TAsmList);override;
  77. procedure g_restore_standard_registers(list : TAsmList);override;
  78. procedure a_jmp_cond(list : TAsmList;cond : TOpCmp;l: tasmlabel);
  79. procedure fixref(list : TAsmList;var ref : treference);
  80. function handle_load_store(list:TAsmList;op: tasmop;oppostfix : toppostfix;reg:tregister;ref: treference):treference;
  81. procedure g_intf_wrapper(list: TAsmList; procdef: tprocdef; const labelname: string; ioffset: longint);override;
  82. end;
  83. tcg64farm = class(tcg64f32)
  84. procedure a_op64_reg_reg(list : TAsmList;op:TOpCG;size : tcgsize;regsrc,regdst : tregister64);override;
  85. procedure a_op64_const_reg(list : TAsmList;op:TOpCG;size : tcgsize;value : int64;reg : tregister64);override;
  86. procedure a_op64_const_reg_reg(list: TAsmList;op:TOpCG;size : tcgsize;value : int64;regsrc,regdst : tregister64);override;
  87. procedure a_op64_reg_reg_reg(list: TAsmList;op:TOpCG;size : tcgsize;regsrc1,regsrc2,regdst : tregister64);override;
  88. procedure a_op64_const_reg_reg_checkoverflow(list: TAsmList;op:TOpCG;size : tcgsize;value : int64;regsrc,regdst : tregister64;setflags : boolean;var ovloc : tlocation);override;
  89. procedure a_op64_reg_reg_reg_checkoverflow(list: TAsmList;op:TOpCG;size : tcgsize;regsrc1,regsrc2,regdst : tregister64;setflags : boolean;var ovloc : tlocation);override;
  90. end;
  91. const
  92. OpCmp2AsmCond : Array[topcmp] of TAsmCond = (C_NONE,C_EQ,C_GT,
  93. C_LT,C_GE,C_LE,C_NE,C_LS,C_CC,C_CS,C_HI);
  94. function get_fpu_postfix(def : tdef) : toppostfix;
  95. implementation
  96. uses
  97. globals,verbose,systems,cutils,
  98. fmodule,
  99. symconst,symsym,
  100. tgobj,
  101. procinfo,cpupi,
  102. paramgr;
  103. function get_fpu_postfix(def : tdef) : toppostfix;
  104. begin
  105. if def.deftype=floatdef then
  106. begin
  107. case tfloatdef(def).typ of
  108. s32real:
  109. result:=PF_S;
  110. s64real:
  111. result:=PF_D;
  112. s80real:
  113. result:=PF_E;
  114. else
  115. internalerror(200401272);
  116. end;
  117. end
  118. else
  119. internalerror(200401271);
  120. end;
  121. procedure tcgarm.init_register_allocators;
  122. begin
  123. inherited init_register_allocators;
  124. { currently, we save R14 always, so we can use it }
  125. rg[R_INTREGISTER]:=trgintcpu.create(R_INTREGISTER,R_SUBWHOLE,
  126. [RS_R0,RS_R1,RS_R2,RS_R3,RS_R4,RS_R5,RS_R6,RS_R7,RS_R8,
  127. RS_R9,RS_R10,RS_R12,RS_R14],first_int_imreg,[]);
  128. rg[R_FPUREGISTER]:=trgcpu.create(R_FPUREGISTER,R_SUBNONE,
  129. [RS_F0,RS_F1,RS_F2,RS_F3,RS_F4,RS_F5,RS_F6,RS_F7],first_fpu_imreg,[]);
  130. rg[R_MMREGISTER]:=trgcpu.create(R_MMREGISTER,R_SUBNONE,
  131. [RS_S0,RS_S1,RS_R2,RS_R3,RS_R4,RS_S31],first_mm_imreg,[]);
  132. end;
  133. procedure tcgarm.done_register_allocators;
  134. begin
  135. rg[R_INTREGISTER].free;
  136. rg[R_FPUREGISTER].free;
  137. rg[R_MMREGISTER].free;
  138. inherited done_register_allocators;
  139. end;
  140. procedure tcgarm.a_param_const(list : TAsmList;size : tcgsize;a : aint;const paraloc : TCGPara);
  141. var
  142. ref: treference;
  143. begin
  144. paraloc.check_simple_location;
  145. case paraloc.location^.loc of
  146. LOC_REGISTER,LOC_CREGISTER:
  147. a_load_const_reg(list,size,a,paraloc.location^.register);
  148. LOC_REFERENCE:
  149. begin
  150. reference_reset(ref);
  151. ref.base:=paraloc.location^.reference.index;
  152. ref.offset:=paraloc.location^.reference.offset;
  153. a_load_const_ref(list,size,a,ref);
  154. end;
  155. else
  156. internalerror(2002081101);
  157. end;
  158. end;
  159. procedure tcgarm.a_param_ref(list : TAsmList;size : tcgsize;const r : treference;const paraloc : TCGPara);
  160. var
  161. tmpref, ref: treference;
  162. location: pcgparalocation;
  163. sizeleft: aint;
  164. begin
  165. location := paraloc.location;
  166. tmpref := r;
  167. sizeleft := paraloc.intsize;
  168. while assigned(location) do
  169. begin
  170. case location^.loc of
  171. LOC_REGISTER,LOC_CREGISTER:
  172. a_load_ref_reg(list,location^.size,location^.size,tmpref,location^.register);
  173. LOC_REFERENCE:
  174. begin
  175. reference_reset_base(ref,location^.reference.index,location^.reference.offset);
  176. { doubles in softemu mode have a strange order of registers and references }
  177. if location^.size=OS_32 then
  178. g_concatcopy(list,tmpref,ref,4)
  179. else
  180. begin
  181. g_concatcopy(list,tmpref,ref,sizeleft);
  182. if assigned(location^.next) then
  183. internalerror(2005010710);
  184. end;
  185. end;
  186. LOC_FPUREGISTER,LOC_CFPUREGISTER:
  187. case location^.size of
  188. OS_F32, OS_F64:
  189. a_loadfpu_ref_reg(list,location^.size,tmpref,location^.register);
  190. else
  191. internalerror(2002072801);
  192. end;
  193. LOC_VOID:
  194. begin
  195. // nothing to do
  196. end;
  197. else
  198. internalerror(2002081103);
  199. end;
  200. inc(tmpref.offset,tcgsize2size[location^.size]);
  201. dec(sizeleft,tcgsize2size[location^.size]);
  202. location := location^.next;
  203. end;
  204. end;
  205. procedure tcgarm.a_paramaddr_ref(list : TAsmList;const r : treference;const paraloc : TCGPara);
  206. var
  207. ref: treference;
  208. tmpreg: tregister;
  209. begin
  210. paraloc.check_simple_location;
  211. case paraloc.location^.loc of
  212. LOC_REGISTER,LOC_CREGISTER:
  213. a_loadaddr_ref_reg(list,r,paraloc.location^.register);
  214. LOC_REFERENCE:
  215. begin
  216. reference_reset(ref);
  217. ref.base := paraloc.location^.reference.index;
  218. ref.offset := paraloc.location^.reference.offset;
  219. tmpreg := getintregister(list,OS_ADDR);
  220. a_loadaddr_ref_reg(list,r,tmpreg);
  221. a_load_reg_ref(list,OS_ADDR,OS_ADDR,tmpreg,ref);
  222. end;
  223. else
  224. internalerror(2002080701);
  225. end;
  226. end;
  227. procedure tcgarm.a_call_name(list : TAsmList;const s : string);
  228. begin
  229. list.concat(taicpu.op_sym(A_BL,current_asmdata.RefAsmSymbol(s)));
  230. {
  231. the compiler does not properly set this flag anymore in pass 1, and
  232. for now we only need it after pass 2 (I hope) (JM)
  233. if not(pi_do_call in current_procinfo.flags) then
  234. internalerror(2003060703);
  235. }
  236. include(current_procinfo.flags,pi_do_call);
  237. end;
  238. procedure tcgarm.a_call_reg(list : TAsmList;reg: tregister);
  239. var
  240. r : tregister;
  241. begin
  242. list.concat(taicpu.op_reg_reg(A_MOV,NR_R14,NR_PC));
  243. list.concat(taicpu.op_reg_reg(A_MOV,NR_PC,reg));
  244. {
  245. the compiler does not properly set this flag anymore in pass 1, and
  246. for now we only need it after pass 2 (I hope) (JM)
  247. if not(pi_do_call in current_procinfo.flags) then
  248. internalerror(2003060703);
  249. }
  250. include(current_procinfo.flags,pi_do_call);
  251. end;
  252. procedure tcgarm.a_call_ref(list : TAsmList;ref: treference);
  253. begin
  254. a_reg_alloc(list,NR_R12);
  255. a_load_ref_reg(list,OS_ADDR,OS_ADDR,ref,NR_R12);
  256. list.concat(taicpu.op_reg_reg(A_MOV,NR_R14,NR_PC));
  257. list.concat(taicpu.op_reg_reg(A_MOV,NR_PC,NR_R12));
  258. a_reg_dealloc(list,NR_R12);
  259. include(current_procinfo.flags,pi_do_call);
  260. end;
  261. procedure tcgarm.a_op_const_reg(list : TAsmList; Op: TOpCG; size: TCGSize; a: aint; reg: TRegister);
  262. begin
  263. a_op_const_reg_reg(list,op,size,a,reg,reg);
  264. end;
  265. procedure tcgarm.a_op_reg_reg(list : TAsmList; Op: TOpCG; size: TCGSize; src, dst: TRegister);
  266. begin
  267. case op of
  268. OP_NEG:
  269. list.concat(taicpu.op_reg_reg_const(A_RSB,dst,src,0));
  270. OP_NOT:
  271. begin
  272. list.concat(taicpu.op_reg_reg(A_MVN,dst,src));
  273. case size of
  274. OS_8 :
  275. a_op_const_reg_reg(list,OP_AND,OS_INT,$ff,dst,dst);
  276. OS_16 :
  277. a_op_const_reg_reg(list,OP_AND,OS_INT,$ffff,dst,dst);
  278. end;
  279. end
  280. else
  281. a_op_reg_reg_reg(list,op,OS_32,src,dst,dst);
  282. end;
  283. end;
  284. const
  285. op_reg_reg_opcg2asmop: array[TOpCG] of tasmop =
  286. (A_NONE,A_MOV,A_ADD,A_AND,A_NONE,A_NONE,A_MUL,A_MUL,A_NONE,A_NONE,A_ORR,
  287. A_NONE,A_NONE,A_NONE,A_SUB,A_EOR);
  288. procedure tcgarm.a_op_const_reg_reg(list: TAsmList; op: TOpCg;
  289. size: tcgsize; a: aint; src, dst: tregister);
  290. var
  291. ovloc : tlocation;
  292. begin
  293. a_op_const_reg_reg_checkoverflow(list,op,size,a,src,dst,false,ovloc);
  294. end;
  295. procedure tcgarm.a_op_reg_reg_reg(list: TAsmList; op: TOpCg;
  296. size: tcgsize; src1, src2, dst: tregister);
  297. var
  298. ovloc : tlocation;
  299. begin
  300. a_op_reg_reg_reg_checkoverflow(list,op,size,src1,src2,dst,false,ovloc);
  301. end;
  302. procedure tcgarm.a_op_const_reg_reg_checkoverflow(list: TAsmList; op: TOpCg; size: tcgsize; a: aint; src, dst: tregister;setflags : boolean;var ovloc : tlocation);
  303. var
  304. shift : byte;
  305. tmpreg : tregister;
  306. so : tshifterop;
  307. l1 : longint;
  308. begin
  309. ovloc.loc:=LOC_VOID;
  310. if is_shifter_const(-a,shift) then
  311. case op of
  312. OP_ADD:
  313. begin
  314. op:=OP_SUB;
  315. a:=dword(-a);
  316. end;
  317. OP_SUB:
  318. begin
  319. op:=OP_ADD;
  320. a:=dword(-a);
  321. end
  322. end;
  323. if is_shifter_const(a,shift) and not(op in [OP_IMUL,OP_MUL]) then
  324. case op of
  325. OP_NEG,OP_NOT,
  326. OP_DIV,OP_IDIV:
  327. internalerror(200308281);
  328. OP_SHL:
  329. begin
  330. if a>32 then
  331. internalerror(200308291);
  332. if a<>0 then
  333. begin
  334. shifterop_reset(so);
  335. so.shiftmode:=SM_LSL;
  336. so.shiftimm:=a;
  337. list.concat(taicpu.op_reg_reg_shifterop(A_MOV,dst,src,so));
  338. end
  339. else
  340. list.concat(taicpu.op_reg_reg(A_MOV,dst,src));
  341. end;
  342. OP_SHR:
  343. begin
  344. if a>32 then
  345. internalerror(200308292);
  346. shifterop_reset(so);
  347. if a<>0 then
  348. begin
  349. so.shiftmode:=SM_LSR;
  350. so.shiftimm:=a;
  351. list.concat(taicpu.op_reg_reg_shifterop(A_MOV,dst,src,so));
  352. end
  353. else
  354. list.concat(taicpu.op_reg_reg(A_MOV,dst,src));
  355. end;
  356. OP_SAR:
  357. begin
  358. if a>32 then
  359. internalerror(200308291);
  360. if a<>0 then
  361. begin
  362. shifterop_reset(so);
  363. so.shiftmode:=SM_ASR;
  364. so.shiftimm:=a;
  365. list.concat(taicpu.op_reg_reg_shifterop(A_MOV,dst,src,so));
  366. end
  367. else
  368. list.concat(taicpu.op_reg_reg(A_MOV,dst,src));
  369. end;
  370. else
  371. list.concat(setoppostfix(
  372. taicpu.op_reg_reg_const(op_reg_reg_opcg2asmop[op],dst,src,a),toppostfix(ord(cgsetflags or setflags)*ord(PF_S))
  373. ));
  374. if (cgsetflags or setflags) and (size in [OS_8,OS_16,OS_32]) then
  375. begin
  376. ovloc.loc:=LOC_FLAGS;
  377. case op of
  378. OP_ADD:
  379. ovloc.resflags:=F_CS;
  380. OP_SUB:
  381. ovloc.resflags:=F_CC;
  382. end;
  383. end;
  384. end
  385. else
  386. begin
  387. { there could be added some more sophisticated optimizations }
  388. if (op in [OP_MUL,OP_IMUL]) and (a=1) then
  389. a_load_reg_reg(list,size,size,src,dst)
  390. else if (op in [OP_MUL,OP_IMUL]) and (a=0) then
  391. a_load_const_reg(list,size,0,dst)
  392. else if (op in [OP_IMUL]) and (a=-1) then
  393. a_op_reg_reg(list,OP_NEG,size,src,dst)
  394. { we do this here instead in the peephole optimizer because
  395. it saves us a register }
  396. else if (op in [OP_MUL,OP_IMUL]) and ispowerof2(a,l1) and not(cgsetflags or setflags) then
  397. a_op_const_reg_reg(list,OP_SHL,size,l1,src,dst)
  398. { for example : b=a*5 -> b=a*4+a with add instruction and shl }
  399. else if (op in [OP_MUL,OP_IMUL]) and ispowerof2(a-1,l1) and not(cgsetflags or setflags) then
  400. begin
  401. if l1>32 then{roozbeh does this ever happen?}
  402. internalerror(200308291);
  403. shifterop_reset(so);
  404. so.shiftmode:=SM_LSL;
  405. so.shiftimm:=l1;
  406. list.concat(taicpu.op_reg_reg_reg_shifterop(A_ADD,dst,src,src,so));
  407. end
  408. else
  409. begin
  410. tmpreg:=getintregister(list,size);
  411. a_load_const_reg(list,size,a,tmpreg);
  412. a_op_reg_reg_reg_checkoverflow(list,op,size,tmpreg,src,dst,setflags,ovloc);
  413. end;
  414. end;
  415. end;
  416. procedure tcgarm.a_op_reg_reg_reg_checkoverflow(list: TAsmList; op: TOpCg; size: tcgsize; src1, src2, dst: tregister;setflags : boolean;var ovloc : tlocation);
  417. var
  418. so : tshifterop;
  419. tmpreg,overflowreg : tregister;
  420. asmop : tasmop;
  421. begin
  422. ovloc.loc:=LOC_VOID;
  423. case op of
  424. OP_NEG,OP_NOT,
  425. OP_DIV,OP_IDIV:
  426. internalerror(200308281);
  427. OP_SHL:
  428. begin
  429. shifterop_reset(so);
  430. so.rs:=src1;
  431. so.shiftmode:=SM_LSL;
  432. list.concat(taicpu.op_reg_reg_shifterop(A_MOV,dst,src2,so));
  433. end;
  434. OP_SHR:
  435. begin
  436. shifterop_reset(so);
  437. so.rs:=src1;
  438. so.shiftmode:=SM_LSR;
  439. list.concat(taicpu.op_reg_reg_shifterop(A_MOV,dst,src2,so));
  440. end;
  441. OP_SAR:
  442. begin
  443. shifterop_reset(so);
  444. so.rs:=src1;
  445. so.shiftmode:=SM_ASR;
  446. list.concat(taicpu.op_reg_reg_shifterop(A_MOV,dst,src2,so));
  447. end;
  448. OP_IMUL,
  449. OP_MUL:
  450. begin
  451. if cgsetflags or setflags then
  452. begin
  453. overflowreg:=getintregister(list,size);
  454. if op=OP_IMUL then
  455. asmop:=A_SMULL
  456. else
  457. asmop:=A_UMULL;
  458. { the arm doesn't allow that rd and rm are the same }
  459. if dst=src2 then
  460. begin
  461. if dst<>src1 then
  462. list.concat(taicpu.op_reg_reg_reg_reg(asmop,dst,overflowreg,src1,src2))
  463. else
  464. begin
  465. tmpreg:=getintregister(list,size);
  466. a_load_reg_reg(list,size,size,src2,dst);
  467. list.concat(taicpu.op_reg_reg_reg_reg(asmop,dst,overflowreg,tmpreg,src1));
  468. end;
  469. end
  470. else
  471. list.concat(taicpu.op_reg_reg_reg_reg(asmop,dst,overflowreg,src2,src1));
  472. if op=OP_IMUL then
  473. begin
  474. shifterop_reset(so);
  475. so.shiftmode:=SM_ASR;
  476. so.shiftimm:=31;
  477. list.concat(taicpu.op_reg_reg_shifterop(A_CMP,overflowreg,dst,so));
  478. end
  479. else
  480. list.concat(taicpu.op_reg_const(A_CMP,overflowreg,0));
  481. ovloc.loc:=LOC_FLAGS;
  482. ovloc.resflags:=F_NE;
  483. end
  484. else
  485. begin
  486. { the arm doesn't allow that rd and rm are the same }
  487. if dst=src2 then
  488. begin
  489. if dst<>src1 then
  490. list.concat(taicpu.op_reg_reg_reg(A_MUL,dst,src1,src2))
  491. else
  492. begin
  493. tmpreg:=getintregister(list,size);
  494. a_load_reg_reg(list,size,size,src2,dst);
  495. list.concat(taicpu.op_reg_reg_reg(A_MUL,dst,tmpreg,src1));
  496. end;
  497. end
  498. else
  499. list.concat(taicpu.op_reg_reg_reg(A_MUL,dst,src2,src1));
  500. end;
  501. end;
  502. else
  503. list.concat(setoppostfix(
  504. taicpu.op_reg_reg_reg(op_reg_reg_opcg2asmop[op],dst,src2,src1),toppostfix(ord(cgsetflags or setflags)*ord(PF_S))
  505. ));
  506. end;
  507. end;
  508. procedure tcgarm.a_load_const_reg(list : TAsmList; size: tcgsize; a : aint;reg : tregister);
  509. var
  510. imm_shift : byte;
  511. l : tasmlabel;
  512. hr : treference;
  513. tmpreg : tregister;
  514. begin
  515. if not(size in [OS_8,OS_S8,OS_16,OS_S16,OS_32,OS_S32]) then
  516. internalerror(2002090902);
  517. if is_shifter_const(a,imm_shift) then
  518. list.concat(taicpu.op_reg_const(A_MOV,reg,a))
  519. else if is_shifter_const(not(a),imm_shift) then
  520. list.concat(taicpu.op_reg_const(A_MVN,reg,not(a)))
  521. { loading of constants with mov and orr }
  522. {else [if (is_shifter_const(a-byte(a),imm_shift)) then
  523. begin
  524. }{ roozbeh:why using tmpreg later causes error in compiling of system.pp,and also those other similars}
  525. {list.concat(taicpu.op_reg_const(A_MOV,reg,a-byte(a)));
  526. list.concat(taicpu.op_reg_reg_const(A_ORR,reg,reg,byte(a)));
  527. end
  528. else if (is_shifter_const(a-word(a),imm_shift)) and (is_shifter_const(word(a),imm_shift)) then
  529. begin
  530. list.concat(taicpu.op_reg_const(A_MOV,reg,a-word(a)));
  531. list.concat(taicpu.op_reg_reg_const(A_ORR,reg,reg,word(a)));
  532. end
  533. else if (is_shifter_const(a-(longint(a) shl 8) shr 8,imm_shift)) and (is_shifter_const((longint(a) shl 8) shr 8,imm_shift)) then
  534. begin
  535. list.concat(taicpu.op_reg_const(A_MOV,reg,a-(longint(a) shl 8)shr 8));
  536. list.concat(taicpu.op_reg_reg_const(A_ORR,reg,reg,(longint(a) shl 8)shr 8));
  537. end}
  538. else
  539. begin
  540. reference_reset(hr);
  541. current_asmdata.getjumplabel(l);
  542. cg.a_label(current_procinfo.aktlocaldata,l);
  543. hr.symboldata:=current_procinfo.aktlocaldata.last;
  544. current_procinfo.aktlocaldata.concat(tai_const.Create_32bit(longint(a)));
  545. hr.symbol:=l;
  546. list.concat(taicpu.op_reg_ref(A_LDR,reg,hr));
  547. end;
  548. end;
  549. function tcgarm.handle_load_store(list:TAsmList;op: tasmop;oppostfix : toppostfix;reg:tregister;ref: treference):treference;
  550. var
  551. tmpreg,tmpreg2 : tregister;
  552. tmpref : treference;
  553. l : tasmlabel;
  554. so : tshifterop;
  555. begin
  556. tmpreg:=NR_NO;
  557. { Be sure to have a base register }
  558. if (ref.base=NR_NO) then
  559. begin
  560. if ref.shiftmode<>SM_None then
  561. internalerror(200308294);
  562. ref.base:=ref.index;
  563. ref.index:=NR_NO;
  564. end;
  565. { absolute symbols can't be handled directly, we've to store the symbol reference
  566. in the text segment and access it pc relative
  567. For now, we assume that references where base or index equals to PC are already
  568. relative, all other references are assumed to be absolute and thus they need
  569. to be handled extra.
  570. A proper solution would be to change refoptions to a set and store the information
  571. if the symbol is absolute or relative there.
  572. }
  573. if (assigned(ref.symbol) and
  574. not(is_pc(ref.base)) and
  575. not(is_pc(ref.index))
  576. ) or
  577. { [#xxx] isn't a valid address operand }
  578. ((ref.base=NR_NO) and (ref.index=NR_NO)) or
  579. (ref.offset<-4095) or
  580. (ref.offset>4095) or
  581. ((oppostfix in [PF_SB,PF_H,PF_SH]) and
  582. ((ref.offset<-255) or
  583. (ref.offset>255)
  584. )
  585. ) or
  586. ((op in [A_LDF,A_STF]) and
  587. ((ref.offset<-1020) or
  588. (ref.offset>1020) or
  589. { the usual pc relative symbol handling assumes possible offsets of +/- 4095 }
  590. assigned(ref.symbol)
  591. )
  592. ) then
  593. begin
  594. reference_reset(tmpref);
  595. { load symbol }
  596. tmpreg:=getintregister(list,OS_INT);
  597. if assigned(ref.symbol) then
  598. begin
  599. current_asmdata.getjumplabel(l);
  600. cg.a_label(current_procinfo.aktlocaldata,l);
  601. tmpref.symboldata:=current_procinfo.aktlocaldata.last;
  602. current_procinfo.aktlocaldata.concat(tai_const.create_sym_offset(ref.symbol,ref.offset));
  603. { load consts entry }
  604. tmpref.symbol:=l;
  605. tmpref.base:=NR_R15;
  606. list.concat(taicpu.op_reg_ref(A_LDR,tmpreg,tmpref));
  607. end
  608. else
  609. a_load_const_reg(list,OS_ADDR,ref.offset,tmpreg);
  610. if (ref.base<>NR_NO) then
  611. begin
  612. if ref.index<>NR_NO then
  613. begin
  614. list.concat(taicpu.op_reg_reg_reg(A_ADD,tmpreg,ref.base,tmpreg));
  615. ref.base:=tmpreg;
  616. end
  617. else
  618. begin
  619. ref.index:=tmpreg;
  620. ref.shiftimm:=0;
  621. ref.signindex:=1;
  622. ref.shiftmode:=SM_None;
  623. end;
  624. end
  625. else
  626. ref.base:=tmpreg;
  627. ref.offset:=0;
  628. ref.symbol:=nil;
  629. end;
  630. if (ref.base<>NR_NO) and (ref.index<>NR_NO) and (ref.offset<>0) then
  631. begin
  632. if tmpreg<>NR_NO then
  633. a_op_const_reg_reg(list,OP_ADD,OS_ADDR,ref.offset,tmpreg,tmpreg)
  634. else
  635. begin
  636. tmpreg:=getintregister(list,OS_ADDR);
  637. a_op_const_reg_reg(list,OP_ADD,OS_ADDR,ref.offset,ref.base,tmpreg);
  638. ref.base:=tmpreg;
  639. end;
  640. ref.offset:=0;
  641. end;
  642. { floating point operations have only limited references
  643. we expect here, that a base is already set }
  644. if (op in [A_LDF,A_STF]) and (ref.index<>NR_NO) then
  645. begin
  646. if ref.shiftmode<>SM_none then
  647. internalerror(200309121);
  648. if tmpreg<>NR_NO then
  649. begin
  650. if ref.base=tmpreg then
  651. begin
  652. if ref.signindex<0 then
  653. list.concat(taicpu.op_reg_reg_reg(A_SUB,tmpreg,tmpreg,ref.index))
  654. else
  655. list.concat(taicpu.op_reg_reg_reg(A_ADD,tmpreg,tmpreg,ref.index));
  656. ref.index:=NR_NO;
  657. end
  658. else
  659. begin
  660. if ref.index<>tmpreg then
  661. internalerror(200403161);
  662. if ref.signindex<0 then
  663. list.concat(taicpu.op_reg_reg_reg(A_SUB,tmpreg,ref.base,tmpreg))
  664. else
  665. list.concat(taicpu.op_reg_reg_reg(A_ADD,tmpreg,ref.base,tmpreg));
  666. ref.base:=tmpreg;
  667. ref.index:=NR_NO;
  668. end;
  669. end
  670. else
  671. begin
  672. tmpreg:=getintregister(list,OS_ADDR);
  673. list.concat(taicpu.op_reg_reg_reg(A_ADD,tmpreg,ref.base,ref.index));
  674. ref.base:=tmpreg;
  675. ref.index:=NR_NO;
  676. end;
  677. end;
  678. list.concat(setoppostfix(taicpu.op_reg_ref(op,reg,ref),oppostfix));
  679. Result := ref;
  680. end;
  681. procedure tcgarm.a_load_reg_ref(list : TAsmList; fromsize, tosize: tcgsize; reg : tregister;const ref : treference);
  682. var
  683. oppostfix:toppostfix;
  684. usedtmpref,usedtmpref2: treference;
  685. tmpreg,tmpreg2 : tregister;
  686. so : tshifterop;
  687. begin
  688. case ToSize of
  689. { signed integer registers }
  690. OS_8,
  691. OS_S8:
  692. oppostfix:=PF_B;
  693. OS_16,
  694. OS_S16:
  695. oppostfix:=PF_H;
  696. OS_32,
  697. OS_S32:
  698. oppostfix:=PF_None;
  699. else
  700. InternalError(200308295);
  701. end;
  702. if ref.alignment<>0 then
  703. begin
  704. case FromSize of
  705. OS_16,OS_S16:
  706. begin
  707. shifterop_reset(so);so.shiftmode:=SM_LSR;so.shiftimm:=8;
  708. tmpreg:=getintregister(list,OS_INT);
  709. usedtmpref:=a_internal_load_reg_ref(list,OS_8,OS_8,reg,Ref);
  710. inc(usedtmpref.offset);
  711. list.concat(taicpu.op_reg_reg_shifterop(A_MOV,tmpreg,reg,so));
  712. a_internal_load_reg_ref(list,OS_8,OS_8,tmpreg,usedtmpref);
  713. end;
  714. OS_32,OS_S32:
  715. begin
  716. shifterop_reset(so);so.shiftmode:=SM_LSR;so.shiftimm:=8;
  717. tmpreg:=getintregister(list,OS_INT);
  718. usedtmpref:=a_internal_load_reg_ref(list,OS_8,OS_8,reg,Ref);
  719. list.concat(taicpu.op_reg_reg_shifterop(A_MOV,tmpreg,reg,so));
  720. inc(usedtmpref.offset);
  721. a_internal_load_reg_ref(list,OS_8,OS_8,tmpreg,usedtmpref);
  722. list.concat(taicpu.op_reg_reg_shifterop(A_MOV,tmpreg,tmpreg,so));
  723. inc(usedtmpref.offset);
  724. a_internal_load_reg_ref(list,OS_8,OS_8,tmpreg,usedtmpref);
  725. list.concat(taicpu.op_reg_reg_shifterop(A_MOV,tmpreg,tmpreg,so));
  726. inc(usedtmpref.offset);
  727. a_internal_load_reg_ref(list,OS_8,OS_8,tmpreg,usedtmpref);
  728. end
  729. else
  730. handle_load_store(list,A_STR,oppostfix,reg,ref);
  731. end;
  732. end
  733. else
  734. handle_load_store(list,A_STR,oppostfix,reg,ref);
  735. end;
  736. procedure tcgarm.a_load_ref_reg(list : TAsmList; fromsize, tosize : tcgsize;const Ref : treference;reg : tregister);
  737. var
  738. oppostfix:toppostfix;
  739. usedtmpref,usedtmpref2: treference;
  740. tmpreg,tmpreg2,tmpreg3 : tregister;
  741. so : tshifterop;
  742. begin
  743. case FromSize of
  744. { signed integer registers }
  745. OS_8:
  746. oppostfix:=PF_B;
  747. OS_S8:
  748. oppostfix:=PF_SB;
  749. OS_16:
  750. oppostfix:=PF_H;
  751. OS_S16:
  752. oppostfix:=PF_SH;
  753. OS_32,
  754. OS_S32:
  755. oppostfix:=PF_None;
  756. else
  757. InternalError(200308291);
  758. end;
  759. if Ref.alignment<>0 then
  760. begin
  761. case FromSize of
  762. OS_16,OS_S16:
  763. begin
  764. a_loadaddr_ref_reg(list,ref,reg);
  765. reference_reset_base(usedtmpref,reg,0);
  766. shifterop_reset(so);so.shiftmode:=SM_LSL;so.shiftimm:=8;
  767. tmpreg:=getintregister(list,OS_INT);
  768. a_internal_load_ref_reg(list,OS_8,OS_8,usedtmpref,tmpreg);
  769. inc(usedtmpref.offset);
  770. tmpreg2:=getintregister(list,OS_INT);
  771. if FromSize=OS_16 then
  772. a_internal_load_ref_reg(list,OS_8,OS_8,usedtmpref,tmpreg2)
  773. else
  774. a_internal_load_ref_reg(list,OS_S8,OS_S8,usedtmpref,tmpreg2);
  775. list.concat(taicpu.op_reg_reg_reg_shifterop(A_ORR,reg,tmpreg,tmpreg2,so));
  776. end;
  777. OS_32,OS_S32:
  778. begin
  779. tmpreg:=getintregister(list,OS_INT);
  780. tmpreg2:=getintregister(list,OS_INT);
  781. tmpreg3:=getintregister(list,OS_INT);
  782. shifterop_reset(so);so.shiftmode:=SM_LSL;so.shiftimm:=8;
  783. a_loadaddr_ref_reg(list,ref,tmpreg3);
  784. reference_reset_base(usedtmpref,tmpreg3,0);
  785. a_internal_load_ref_reg(list,OS_8,OS_8,usedtmpref,reg);
  786. inc(usedtmpref.offset);
  787. a_internal_load_ref_reg(list,OS_8,OS_8,usedtmpref,tmpreg);
  788. list.concat(taicpu.op_reg_reg_reg_shifterop(A_ORR,tmpreg2,reg,tmpreg,so));
  789. inc(usedtmpref.offset);
  790. a_internal_load_ref_reg(list,OS_8,OS_8,usedtmpref,reg);
  791. so.shiftimm:=16;
  792. list.concat(taicpu.op_reg_reg_reg_shifterop(A_ORR,tmpreg,tmpreg2,reg,so));
  793. inc(usedtmpref.offset);
  794. a_internal_load_ref_reg(list,OS_8,OS_8,usedtmpref,tmpreg2);
  795. so.shiftimm:=24;
  796. list.concat(taicpu.op_reg_reg_reg_shifterop(A_ORR,reg,tmpreg,tmpreg2,so));
  797. end
  798. else
  799. handle_load_store(list,A_LDR,oppostfix,reg,ref);
  800. end;
  801. end
  802. else
  803. handle_load_store(list,A_LDR,oppostfix,reg,ref);
  804. end;
  805. function tcgarm.a_internal_load_reg_ref(list : TAsmList; fromsize, tosize: tcgsize; reg : tregister;const ref : treference):treference;
  806. var
  807. oppostfix:toppostfix;
  808. begin
  809. case ToSize of
  810. { signed integer registers }
  811. OS_8,
  812. OS_S8:
  813. oppostfix:=PF_B;
  814. OS_16,
  815. OS_S16:
  816. oppostfix:=PF_H;
  817. OS_32,
  818. OS_S32:
  819. oppostfix:=PF_None;
  820. else
  821. InternalError(2003082910);
  822. end;
  823. result:=handle_load_store(list,A_STR,oppostfix,reg,ref);
  824. end;
  825. function tcgarm.a_internal_load_ref_reg(list : TAsmList; fromsize, tosize : tcgsize;const Ref : treference;reg : tregister):treference;
  826. var
  827. oppostfix:toppostfix;
  828. begin
  829. case FromSize of
  830. { signed integer registers }
  831. OS_8:
  832. oppostfix:=PF_B;
  833. OS_S8:
  834. oppostfix:=PF_SB;
  835. OS_16:
  836. oppostfix:=PF_H;
  837. OS_S16:
  838. oppostfix:=PF_SH;
  839. OS_32,
  840. OS_S32:
  841. oppostfix:=PF_None;
  842. else
  843. InternalError(200308291);
  844. end;
  845. result:=handle_load_store(list,A_LDR,oppostfix,reg,ref);
  846. end;
  847. procedure tcgarm.a_load_reg_reg(list : TAsmList; fromsize, tosize : tcgsize;reg1,reg2 : tregister);
  848. var
  849. instr: taicpu;
  850. so : tshifterop;
  851. begin
  852. shifterop_reset(so);
  853. if (tcgsize2size[tosize] < tcgsize2size[fromsize]) or
  854. (
  855. (tcgsize2size[tosize] = tcgsize2size[fromsize]) and
  856. (tosize <> fromsize) and
  857. not(fromsize in [OS_32,OS_S32])
  858. ) then
  859. begin
  860. case tosize of
  861. OS_8:
  862. list.concat(taicpu.op_reg_reg_const(A_AND,
  863. reg2,reg1,$ff));
  864. OS_S8:
  865. begin
  866. so.shiftmode:=SM_LSL;
  867. so.shiftimm:=24;
  868. list.concat(taicpu.op_reg_reg_shifterop(A_MOV,reg2,reg1,so));
  869. so.shiftmode:=SM_ASR;
  870. so.shiftimm:=24;
  871. list.concat(taicpu.op_reg_reg_shifterop(A_MOV,reg2,reg2,so));
  872. end;
  873. OS_16:
  874. begin
  875. so.shiftmode:=SM_LSL;
  876. so.shiftimm:=16;
  877. list.concat(taicpu.op_reg_reg_shifterop(A_MOV,reg2,reg1,so));
  878. so.shiftmode:=SM_LSR;
  879. so.shiftimm:=16;
  880. list.concat(taicpu.op_reg_reg_shifterop(A_MOV,reg2,reg2,so));
  881. end;
  882. OS_S16:
  883. begin
  884. so.shiftmode:=SM_LSL;
  885. so.shiftimm:=16;
  886. list.concat(taicpu.op_reg_reg_shifterop(A_MOV,reg2,reg1,so));
  887. so.shiftmode:=SM_ASR;
  888. so.shiftimm:=16;
  889. list.concat(taicpu.op_reg_reg_shifterop(A_MOV,reg2,reg2,so));
  890. end;
  891. OS_32,OS_S32:
  892. begin
  893. instr:=taicpu.op_reg_reg(A_MOV,reg2,reg1);
  894. list.concat(instr);
  895. add_move_instruction(instr);
  896. end;
  897. else internalerror(2002090901);
  898. end;
  899. end
  900. else
  901. begin
  902. if reg1<>reg2 then
  903. begin
  904. { same size, only a register mov required }
  905. instr:=taicpu.op_reg_reg(A_MOV,reg2,reg1);
  906. list.Concat(instr);
  907. { Notify the register allocator that we have written a move instruction so
  908. it can try to eliminate it. }
  909. add_move_instruction(instr);
  910. end;
  911. end;
  912. end;
  913. procedure tcgarm.a_paramfpu_ref(list : TAsmList;size : tcgsize;const ref : treference;const paraloc : TCGPara);
  914. var
  915. href,href2 : treference;
  916. hloc : pcgparalocation;
  917. begin
  918. href:=ref;
  919. hloc:=paraloc.location;
  920. while assigned(hloc) do
  921. begin
  922. case hloc^.loc of
  923. LOC_FPUREGISTER,LOC_CFPUREGISTER:
  924. a_loadfpu_ref_reg(list,size,ref,hloc^.register);
  925. LOC_REGISTER :
  926. a_load_ref_reg(list,hloc^.size,hloc^.size,href,hloc^.register);
  927. LOC_REFERENCE :
  928. begin
  929. reference_reset_base(href2,hloc^.reference.index,hloc^.reference.offset);
  930. a_load_ref_ref(list,hloc^.size,hloc^.size,href,href2);
  931. end;
  932. else
  933. internalerror(200408241);
  934. end;
  935. inc(href.offset,tcgsize2size[hloc^.size]);
  936. hloc:=hloc^.next;
  937. end;
  938. end;
  939. procedure tcgarm.a_loadfpu_reg_reg(list: TAsmList; size: tcgsize; reg1, reg2: tregister);
  940. begin
  941. list.concat(setoppostfix(taicpu.op_reg_reg(A_MVF,reg2,reg1),cgsize2fpuoppostfix[size]));
  942. end;
  943. procedure tcgarm.a_loadfpu_ref_reg(list: TAsmList; size: tcgsize; const ref: treference; reg: tregister);
  944. var
  945. oppostfix:toppostfix;
  946. begin
  947. case size of
  948. OS_F32:
  949. oppostfix:=PF_S;
  950. OS_F64:
  951. oppostfix:=PF_D;
  952. OS_F80:
  953. oppostfix:=PF_E;
  954. else
  955. InternalError(200309021);
  956. end;
  957. handle_load_store(list,A_LDF,oppostfix,reg,ref);
  958. end;
  959. procedure tcgarm.a_loadfpu_reg_ref(list: TAsmList; size: tcgsize; reg: tregister; const ref: treference);
  960. var
  961. oppostfix:toppostfix;
  962. begin
  963. case size of
  964. OS_F32:
  965. oppostfix:=PF_S;
  966. OS_F64:
  967. oppostfix:=PF_D;
  968. OS_F80:
  969. oppostfix:=PF_E;
  970. else
  971. InternalError(200309022);
  972. end;
  973. handle_load_store(list,A_STF,oppostfix,reg,ref);
  974. end;
  975. { comparison operations }
  976. procedure tcgarm.a_cmp_const_reg_label(list : TAsmList;size : tcgsize;cmp_op : topcmp;a : aint;reg : tregister;
  977. l : tasmlabel);
  978. var
  979. tmpreg : tregister;
  980. b : byte;
  981. begin
  982. if is_shifter_const(a,b) then
  983. list.concat(taicpu.op_reg_const(A_CMP,reg,a))
  984. { CMN reg,0 and CMN reg,$80000000 are different from CMP reg,$ffffffff
  985. and CMP reg,$7fffffff regarding the flags according to the ARM manual }
  986. else if (a<>$7fffffff) and (a<>-1) and is_shifter_const(-a,b) then
  987. list.concat(taicpu.op_reg_const(A_CMN,reg,-a))
  988. else
  989. begin
  990. tmpreg:=getintregister(list,size);
  991. a_load_const_reg(list,size,a,tmpreg);
  992. list.concat(taicpu.op_reg_reg(A_CMP,reg,tmpreg));
  993. end;
  994. a_jmp_cond(list,cmp_op,l);
  995. end;
  996. procedure tcgarm.a_cmp_reg_reg_label(list : TAsmList;size : tcgsize;cmp_op : topcmp;reg1,reg2 : tregister;l : tasmlabel);
  997. begin
  998. list.concat(taicpu.op_reg_reg(A_CMP,reg2,reg1));
  999. a_jmp_cond(list,cmp_op,l);
  1000. end;
  1001. procedure tcgarm.a_jmp_name(list : TAsmList;const s : string);
  1002. begin
  1003. list.concat(taicpu.op_sym(A_B,current_asmdata.RefAsmSymbol(s)));
  1004. end;
  1005. procedure tcgarm.a_jmp_always(list : TAsmList;l: tasmlabel);
  1006. begin
  1007. list.concat(taicpu.op_sym(A_B,l));
  1008. end;
  1009. procedure tcgarm.a_jmp_flags(list : TAsmList;const f : TResFlags;l: tasmlabel);
  1010. var
  1011. ai : taicpu;
  1012. begin
  1013. ai:=setcondition(taicpu.op_sym(A_B,l),flags_to_cond(f));
  1014. ai.is_jmp:=true;
  1015. list.concat(ai);
  1016. end;
  1017. procedure tcgarm.g_flags2reg(list: TAsmList; size: TCgSize; const f: TResFlags; reg: TRegister);
  1018. var
  1019. ai : taicpu;
  1020. begin
  1021. list.concat(setcondition(taicpu.op_reg_const(A_MOV,reg,1),flags_to_cond(f)));
  1022. list.concat(setcondition(taicpu.op_reg_const(A_MOV,reg,0),inverse_cond(flags_to_cond(f))));
  1023. end;
  1024. procedure tcgarm.g_proc_entry(list : TAsmList;localsize : longint;nostackframe:boolean);
  1025. var
  1026. ref : treference;
  1027. shift : byte;
  1028. firstfloatreg,lastfloatreg,
  1029. r : byte;
  1030. begin
  1031. LocalSize:=align(LocalSize,4);
  1032. if not(nostackframe) then
  1033. begin
  1034. firstfloatreg:=RS_NO;
  1035. { save floating point registers? }
  1036. for r:=RS_F0 to RS_F7 do
  1037. if r in rg[R_FPUREGISTER].used_in_proc-paramanager.get_volatile_registers_fpu(pocall_stdcall) then
  1038. begin
  1039. if firstfloatreg=RS_NO then
  1040. firstfloatreg:=r;
  1041. lastfloatreg:=r;
  1042. end;
  1043. a_reg_alloc(list,NR_STACK_POINTER_REG);
  1044. a_reg_alloc(list,NR_FRAME_POINTER_REG);
  1045. a_reg_alloc(list,NR_R12);
  1046. list.concat(taicpu.op_reg_reg(A_MOV,NR_R12,NR_STACK_POINTER_REG));
  1047. { save int registers }
  1048. reference_reset(ref);
  1049. ref.index:=NR_STACK_POINTER_REG;
  1050. ref.addressmode:=AM_PREINDEXED;
  1051. list.concat(setoppostfix(taicpu.op_ref_regset(A_STM,ref,
  1052. rg[R_INTREGISTER].used_in_proc-paramanager.get_volatile_registers_int(pocall_stdcall)+[RS_R11,RS_R12,RS_R14,RS_R15]),
  1053. PF_FD));
  1054. list.concat(taicpu.op_reg_reg_const(A_SUB,NR_FRAME_POINTER_REG,NR_R12,4));
  1055. { allocate necessary stack size }
  1056. { don't use a_op_const_reg_reg here because we don't allow register allocations
  1057. in the entry/exit code }
  1058. if not(is_shifter_const(localsize,shift)) then
  1059. begin
  1060. a_load_const_reg(list,OS_ADDR,LocalSize,NR_R12);
  1061. list.concat(taicpu.op_reg_reg_reg(A_SUB,NR_STACK_POINTER_REG,NR_STACK_POINTER_REG,NR_R12));
  1062. a_reg_dealloc(list,NR_R12);
  1063. end
  1064. else
  1065. begin
  1066. a_reg_dealloc(list,NR_R12);
  1067. list.concat(taicpu.op_reg_reg_const(A_SUB,NR_STACK_POINTER_REG,NR_STACK_POINTER_REG,LocalSize));
  1068. end;
  1069. if firstfloatreg<>RS_NO then
  1070. begin
  1071. reference_reset(ref);
  1072. if tarmprocinfo(current_procinfo).floatregstart<=-1023 then
  1073. begin
  1074. a_load_const_reg(list,OS_ADDR,-tarmprocinfo(current_procinfo).floatregstart,NR_R12);
  1075. list.concat(taicpu.op_reg_reg_reg(A_SUB,NR_R12,NR_FRAME_POINTER_REG,NR_R12));
  1076. ref.base:=NR_R12;
  1077. end
  1078. else
  1079. begin
  1080. ref.base:=NR_FRAME_POINTER_REG;
  1081. ref.offset:=tarmprocinfo(current_procinfo).floatregstart;
  1082. end;
  1083. list.concat(taicpu.op_reg_const_ref(A_SFM,newreg(R_FPUREGISTER,firstfloatreg,R_SUBWHOLE),
  1084. lastfloatreg-firstfloatreg+1,ref));
  1085. end;
  1086. end;
  1087. end;
  1088. procedure tcgarm.g_proc_exit(list : TAsmList;parasize : longint;nostackframe:boolean);
  1089. var
  1090. ref : treference;
  1091. firstfloatreg,lastfloatreg,
  1092. r : byte;
  1093. shift : byte;
  1094. begin
  1095. if not(nostackframe) then
  1096. begin
  1097. { restore floating point register }
  1098. firstfloatreg:=RS_NO;
  1099. { save floating point registers? }
  1100. for r:=RS_F0 to RS_F7 do
  1101. if r in rg[R_FPUREGISTER].used_in_proc-paramanager.get_volatile_registers_fpu(pocall_stdcall) then
  1102. begin
  1103. if firstfloatreg=RS_NO then
  1104. firstfloatreg:=r;
  1105. lastfloatreg:=r;
  1106. end;
  1107. if firstfloatreg<>RS_NO then
  1108. begin
  1109. reference_reset(ref);
  1110. if tarmprocinfo(current_procinfo).floatregstart<=-1023 then
  1111. begin
  1112. a_load_const_reg(list,OS_ADDR,-tarmprocinfo(current_procinfo).floatregstart,NR_R12);
  1113. list.concat(taicpu.op_reg_reg_reg(A_SUB,NR_R12,NR_FRAME_POINTER_REG,NR_R12));
  1114. ref.base:=NR_R12;
  1115. end
  1116. else
  1117. begin
  1118. ref.base:=NR_FRAME_POINTER_REG;
  1119. ref.offset:=tarmprocinfo(current_procinfo).floatregstart;
  1120. end;
  1121. list.concat(taicpu.op_reg_const_ref(A_LFM,newreg(R_FPUREGISTER,firstfloatreg,R_SUBWHOLE),
  1122. lastfloatreg-firstfloatreg+1,ref));
  1123. end;
  1124. if (current_procinfo.framepointer=NR_STACK_POINTER_REG) then
  1125. list.concat(taicpu.op_reg_reg(A_MOV,NR_R15,NR_R14))
  1126. else
  1127. begin
  1128. { restore int registers and return }
  1129. reference_reset(ref);
  1130. ref.index:=NR_FRAME_POINTER_REG;
  1131. 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));
  1132. end;
  1133. end
  1134. else
  1135. list.concat(taicpu.op_reg_reg(A_MOV,NR_PC,NR_R14));
  1136. end;
  1137. procedure tcgarm.a_loadaddr_ref_reg(list : TAsmList;const ref : treference;r : tregister);
  1138. var
  1139. b : byte;
  1140. tmpref : treference;
  1141. instr : taicpu;
  1142. begin
  1143. if ref.addressmode<>AM_OFFSET then
  1144. internalerror(200309071);
  1145. tmpref:=ref;
  1146. { Be sure to have a base register }
  1147. if (tmpref.base=NR_NO) then
  1148. begin
  1149. if tmpref.shiftmode<>SM_None then
  1150. internalerror(200308294);
  1151. if tmpref.signindex<0 then
  1152. internalerror(200312023);
  1153. tmpref.base:=tmpref.index;
  1154. tmpref.index:=NR_NO;
  1155. end;
  1156. if assigned(tmpref.symbol) or
  1157. not((is_shifter_const(tmpref.offset,b)) or
  1158. (is_shifter_const(-tmpref.offset,b))
  1159. ) then
  1160. fixref(list,tmpref);
  1161. { expect a base here if there is an index }
  1162. if (tmpref.base=NR_NO) and (tmpref.index<>NR_NO) then
  1163. internalerror(200312022);
  1164. if tmpref.index<>NR_NO then
  1165. begin
  1166. if tmpref.shiftmode<>SM_None then
  1167. internalerror(200312021);
  1168. if tmpref.signindex<0 then
  1169. a_op_reg_reg_reg(list,OP_SUB,OS_ADDR,tmpref.base,tmpref.index,r)
  1170. else
  1171. a_op_reg_reg_reg(list,OP_ADD,OS_ADDR,tmpref.base,tmpref.index,r);
  1172. if tmpref.offset<>0 then
  1173. a_op_const_reg_reg(list,OP_ADD,OS_ADDR,tmpref.offset,r,r);
  1174. end
  1175. else
  1176. begin
  1177. if tmpref.offset<>0 then
  1178. begin
  1179. if tmpref.base<>NR_NO then
  1180. a_op_const_reg_reg(list,OP_ADD,OS_ADDR,tmpref.offset,tmpref.base,r)
  1181. else
  1182. a_load_const_reg(list,OS_ADDR,tmpref.offset,r);
  1183. end
  1184. else
  1185. begin
  1186. instr:=taicpu.op_reg_reg(A_MOV,r,tmpref.base);
  1187. list.concat(instr);
  1188. add_move_instruction(instr);
  1189. end;
  1190. end;
  1191. end;
  1192. procedure tcgarm.fixref(list : TAsmList;var ref : treference);
  1193. var
  1194. tmpreg : tregister;
  1195. tmpref : treference;
  1196. l : tasmlabel;
  1197. begin
  1198. { absolute symbols can't be handled directly, we've to store the symbol reference
  1199. in the text segment and access it pc relative
  1200. For now, we assume that references where base or index equals to PC are already
  1201. relative, all other references are assumed to be absolute and thus they need
  1202. to be handled extra.
  1203. A proper solution would be to change refoptions to a set and store the information
  1204. if the symbol is absolute or relative there.
  1205. }
  1206. { create consts entry }
  1207. reference_reset(tmpref);
  1208. current_asmdata.getjumplabel(l);
  1209. cg.a_label(current_procinfo.aktlocaldata,l);
  1210. tmpref.symboldata:=current_procinfo.aktlocaldata.last;
  1211. if assigned(ref.symbol) then
  1212. current_procinfo.aktlocaldata.concat(tai_const.create_sym_offset(ref.symbol,ref.offset))
  1213. else
  1214. current_procinfo.aktlocaldata.concat(tai_const.Create_32bit(ref.offset));
  1215. { load consts entry }
  1216. tmpreg:=getintregister(list,OS_INT);
  1217. tmpref.symbol:=l;
  1218. tmpref.base:=NR_PC;
  1219. list.concat(taicpu.op_reg_ref(A_LDR,tmpreg,tmpref));
  1220. if (ref.base<>NR_NO) then
  1221. begin
  1222. if ref.index<>NR_NO then
  1223. begin
  1224. list.concat(taicpu.op_reg_reg_reg(A_ADD,tmpreg,ref.base,tmpreg));
  1225. ref.base:=tmpreg;
  1226. end
  1227. else
  1228. begin
  1229. ref.index:=tmpreg;
  1230. ref.shiftimm:=0;
  1231. ref.signindex:=1;
  1232. ref.shiftmode:=SM_None;
  1233. end;
  1234. end
  1235. else
  1236. ref.base:=tmpreg;
  1237. ref.offset:=0;
  1238. ref.symbol:=nil;
  1239. end;
  1240. procedure tcgarm.g_concatcopy_move(list : TAsmList;const source,dest : treference;len : aint);
  1241. var
  1242. paraloc1,paraloc2,paraloc3 : TCGPara;
  1243. begin
  1244. paraloc1.init;
  1245. paraloc2.init;
  1246. paraloc3.init;
  1247. paramanager.getintparaloc(pocall_default,1,paraloc1);
  1248. paramanager.getintparaloc(pocall_default,2,paraloc2);
  1249. paramanager.getintparaloc(pocall_default,3,paraloc3);
  1250. paramanager.allocparaloc(list,paraloc3);
  1251. a_param_const(list,OS_INT,len,paraloc3);
  1252. paramanager.allocparaloc(list,paraloc2);
  1253. a_paramaddr_ref(list,dest,paraloc2);
  1254. paramanager.allocparaloc(list,paraloc2);
  1255. a_paramaddr_ref(list,source,paraloc1);
  1256. paramanager.freeparaloc(list,paraloc3);
  1257. paramanager.freeparaloc(list,paraloc2);
  1258. paramanager.freeparaloc(list,paraloc1);
  1259. alloccpuregisters(list,R_INTREGISTER,paramanager.get_volatile_registers_int(pocall_default));
  1260. alloccpuregisters(list,R_FPUREGISTER,paramanager.get_volatile_registers_fpu(pocall_default));
  1261. a_call_name(list,'FPC_MOVE');
  1262. dealloccpuregisters(list,R_FPUREGISTER,paramanager.get_volatile_registers_fpu(pocall_default));
  1263. dealloccpuregisters(list,R_INTREGISTER,paramanager.get_volatile_registers_int(pocall_default));
  1264. paraloc3.done;
  1265. paraloc2.done;
  1266. paraloc1.done;
  1267. end;
  1268. procedure tcgarm.g_concatcopy_internal(list : TAsmList;const source,dest : treference;len : aint;aligned : boolean);
  1269. const
  1270. maxtmpreg=10;{roozbeh: can be reduced to 8 or lower if might conflick with reserved ones,also +2 is used becouse of regs required for referencing}
  1271. var
  1272. srcref,dstref,usedtmpref,usedtmpref2:treference;
  1273. srcreg,destreg,countreg,r,tmpreg,tmpreg2:tregister;
  1274. helpsize:aword;
  1275. copysize:byte;
  1276. cgsize:Tcgsize;
  1277. so:tshifterop;
  1278. tmpregisters:array[1..maxtmpreg]of tregister;
  1279. tmpregi,tmpregi2:byte;
  1280. { will never be called with count<=4 }
  1281. procedure genloop(count : aword;size : byte);
  1282. const
  1283. size2opsize : array[1..4] of tcgsize = (OS_8,OS_16,OS_NO,OS_32);
  1284. var
  1285. l : tasmlabel;
  1286. begin
  1287. current_asmdata.getjumplabel(l);
  1288. if count<size then size:=1;
  1289. a_load_const_reg(list,OS_INT,count div size,countreg);
  1290. cg.a_label(list,l);
  1291. srcref.addressmode:=AM_POSTINDEXED;
  1292. dstref.addressmode:=AM_POSTINDEXED;
  1293. srcref.offset:=size;
  1294. dstref.offset:=size;
  1295. r:=getintregister(list,size2opsize[size]);
  1296. a_load_ref_reg(list,size2opsize[size],size2opsize[size],srcref,r);
  1297. list.concat(setoppostfix(taicpu.op_reg_reg_const(A_SUB,countreg,countreg,1),PF_S));
  1298. a_load_reg_ref(list,size2opsize[size],size2opsize[size],r,dstref);
  1299. list.concat(setcondition(taicpu.op_sym(A_B,l),C_NE));
  1300. srcref.offset:=1;
  1301. dstref.offset:=1;
  1302. case count mod size of
  1303. 1:
  1304. begin
  1305. a_load_ref_reg(list,OS_8,OS_8,srcref,r);
  1306. a_load_reg_ref(list,OS_8,OS_8,r,dstref);
  1307. end;
  1308. 2:
  1309. if aligned then
  1310. begin
  1311. a_load_ref_reg(list,OS_16,OS_16,srcref,r);
  1312. a_load_reg_ref(list,OS_16,OS_16,r,dstref);
  1313. end
  1314. else
  1315. begin
  1316. a_load_ref_reg(list,OS_8,OS_8,srcref,r);
  1317. a_load_reg_ref(list,OS_8,OS_8,r,dstref);
  1318. a_load_ref_reg(list,OS_8,OS_8,srcref,r);
  1319. a_load_reg_ref(list,OS_8,OS_8,r,dstref);
  1320. end;
  1321. 3:
  1322. if aligned then
  1323. begin
  1324. srcref.offset:=2;
  1325. dstref.offset:=2;
  1326. a_load_ref_reg(list,OS_16,OS_16,srcref,r);
  1327. a_load_reg_ref(list,OS_16,OS_16,r,dstref);
  1328. a_load_ref_reg(list,OS_8,OS_8,srcref,r);
  1329. a_load_reg_ref(list,OS_8,OS_8,r,dstref);
  1330. end
  1331. else
  1332. begin
  1333. a_load_ref_reg(list,OS_8,OS_8,srcref,r);
  1334. a_load_reg_ref(list,OS_8,OS_8,r,dstref);
  1335. a_load_ref_reg(list,OS_8,OS_8,srcref,r);
  1336. a_load_reg_ref(list,OS_8,OS_8,r,dstref);
  1337. a_load_ref_reg(list,OS_8,OS_8,srcref,r);
  1338. a_load_reg_ref(list,OS_8,OS_8,r,dstref);
  1339. end;
  1340. end;
  1341. { keep the registers alive }
  1342. list.concat(taicpu.op_reg_reg(A_MOV,countreg,countreg));
  1343. list.concat(taicpu.op_reg_reg(A_MOV,srcreg,srcreg));
  1344. list.concat(taicpu.op_reg_reg(A_MOV,destreg,destreg));
  1345. end;
  1346. begin
  1347. if len=0 then
  1348. exit;
  1349. helpsize:=12+maxtmpreg*4;//52 with maxtmpreg=10
  1350. dstref:=dest;
  1351. srcref:=source;
  1352. if cs_opt_size in aktoptimizerswitches then
  1353. helpsize:=8;
  1354. if (len<=helpsize) and aligned then
  1355. begin
  1356. tmpregi:=0;
  1357. srcreg:=getintregister(list,OS_ADDR);
  1358. { explicit pc relative addressing, could be
  1359. e.g. a floating point constant }
  1360. if source.base=NR_PC then
  1361. begin
  1362. { ... then we don't need a loadaddr }
  1363. srcref:=source;
  1364. end
  1365. else
  1366. begin
  1367. a_loadaddr_ref_reg(list,source,srcreg);
  1368. reference_reset_base(srcref,srcreg,0);
  1369. end;
  1370. while (len div 4 <> 0) and (tmpregi<=maxtmpreg) do
  1371. begin
  1372. inc(tmpregi);
  1373. tmpregisters[tmpregi]:=getintregister(list,OS_32);
  1374. a_load_ref_reg(list,OS_32,OS_32,srcref,tmpregisters[tmpregi]);
  1375. inc(srcref.offset,4);
  1376. dec(len,4);
  1377. end;
  1378. destreg:=getintregister(list,OS_ADDR);
  1379. a_loadaddr_ref_reg(list,dest,destreg);
  1380. reference_reset_base(dstref,destreg,0);
  1381. tmpregi2:=1;
  1382. while (tmpregi2<=tmpregi) do
  1383. begin
  1384. a_load_reg_ref(list,OS_32,OS_32,tmpregisters[tmpregi2],dstref);
  1385. inc(dstref.offset,4);
  1386. inc(tmpregi2);
  1387. end;
  1388. copysize:=4;
  1389. cgsize:=OS_32;
  1390. while len<>0 do
  1391. begin
  1392. if len<2 then
  1393. begin
  1394. copysize:=1;
  1395. cgsize:=OS_8;
  1396. end
  1397. else if len<4 then
  1398. begin
  1399. copysize:=2;
  1400. cgsize:=OS_16;
  1401. end;
  1402. dec(len,copysize);
  1403. r:=getintregister(list,cgsize);
  1404. a_load_ref_reg(list,cgsize,cgsize,srcref,r);
  1405. a_load_reg_ref(list,cgsize,cgsize,r,dstref);
  1406. inc(srcref.offset,copysize);
  1407. inc(dstref.offset,copysize);
  1408. end;{end of while}
  1409. end
  1410. else
  1411. begin
  1412. cgsize:=OS_32;
  1413. if (len<=4) then{len<=4 and not aligned}
  1414. begin
  1415. r:=getintregister(list,cgsize);
  1416. usedtmpref:=a_internal_load_ref_reg(list,OS_8,OS_8,srcref,r);
  1417. if Len=1 then
  1418. a_load_reg_ref(list,OS_8,OS_8,r,dstref)
  1419. else
  1420. begin
  1421. tmpreg:=getintregister(list,cgsize);
  1422. usedtmpref2:=a_internal_load_reg_ref(list,OS_8,OS_8,r,dstref);
  1423. inc(usedtmpref.offset,1);
  1424. a_load_ref_reg(list,OS_8,OS_8,usedtmpref,tmpreg);
  1425. inc(usedtmpref2.offset,1);
  1426. a_load_reg_ref(list,OS_8,OS_8,tmpreg,usedtmpref2);
  1427. if len>2 then
  1428. begin
  1429. inc(usedtmpref.offset,1);
  1430. a_load_ref_reg(list,OS_8,OS_8,usedtmpref,tmpreg);
  1431. inc(usedtmpref2.offset,1);
  1432. a_load_reg_ref(list,OS_8,OS_8,tmpreg,usedtmpref2);
  1433. if len>3 then
  1434. begin
  1435. inc(usedtmpref.offset,1);
  1436. a_load_ref_reg(list,OS_8,OS_8,usedtmpref,tmpreg);
  1437. inc(usedtmpref2.offset,1);
  1438. a_load_reg_ref(list,OS_8,OS_8,tmpreg,usedtmpref2);
  1439. end;
  1440. end;
  1441. end;
  1442. end{end of if len<=4}
  1443. else
  1444. begin{unaligned & 4<len<helpsize **or** aligned/unaligned & len>helpsize}
  1445. destreg:=getintregister(list,OS_ADDR);
  1446. a_loadaddr_ref_reg(list,dest,destreg);
  1447. reference_reset_base(dstref,destreg,0);
  1448. srcreg:=getintregister(list,OS_ADDR);
  1449. a_loadaddr_ref_reg(list,source,srcreg);
  1450. reference_reset_base(srcref,srcreg,0);
  1451. countreg:=getintregister(list,OS_32);
  1452. // if cs_opt_size in aktoptimizerswitches then
  1453. { roozbeh : it seems loading 1 byte is faster becouse of caching/fetching(?) }
  1454. {if aligned then
  1455. genloop(len,4)
  1456. else}
  1457. genloop(len,1);
  1458. end;
  1459. end;
  1460. end;
  1461. procedure tcgarm.g_concatcopy_unaligned(list : TAsmList;const source,dest : treference;len : aint);
  1462. begin
  1463. g_concatcopy_internal(list,source,dest,len,false);
  1464. end;
  1465. procedure tcgarm.g_concatcopy(list : TAsmList;const source,dest : treference;len : aint);
  1466. begin
  1467. if (source.alignment in [1..3]) or
  1468. (dest.alignment in [1..3]) then
  1469. g_concatcopy_internal(list,source,dest,len,false)
  1470. else
  1471. g_concatcopy_internal(list,source,dest,len,true);
  1472. end;
  1473. procedure tcgarm.g_overflowCheck(list : TAsmList;const l : tlocation;def : tdef);
  1474. var
  1475. ovloc : tlocation;
  1476. begin
  1477. ovloc.loc:=LOC_VOID;
  1478. g_overflowCheck_loc(list,l,def,ovloc);
  1479. end;
  1480. procedure tcgarm.g_overflowCheck_loc(List:TAsmList;const Loc:TLocation;def:TDef;ovloc : tlocation);
  1481. var
  1482. hl : tasmlabel;
  1483. ai:TAiCpu;
  1484. hflags : tresflags;
  1485. begin
  1486. if not(cs_check_overflow in aktlocalswitches) then
  1487. exit;
  1488. current_asmdata.getjumplabel(hl);
  1489. case ovloc.loc of
  1490. LOC_VOID:
  1491. begin
  1492. ai:=taicpu.op_sym(A_B,hl);
  1493. ai.is_jmp:=true;
  1494. if not((def.deftype=pointerdef) or
  1495. ((def.deftype=orddef) and
  1496. (torddef(def).typ in [u64bit,u16bit,u32bit,u8bit,uchar,bool8bit,bool16bit,bool32bit]))) then
  1497. ai.SetCondition(C_VC)
  1498. else
  1499. if TAiCpu(List.Last).opcode in [A_RSB,A_RSC,A_SBC,A_SUB] then
  1500. ai.SetCondition(C_CS)
  1501. else
  1502. ai.SetCondition(C_CC);
  1503. list.concat(ai);
  1504. end;
  1505. LOC_FLAGS:
  1506. begin
  1507. hflags:=ovloc.resflags;
  1508. if not (hflags in [F_CS,F_CC]) then
  1509. inverse_flags(hflags);
  1510. cg.a_jmp_flags(list,hflags,hl);
  1511. end;
  1512. else
  1513. internalerror(200409281);
  1514. end;
  1515. a_call_name(list,'FPC_OVERFLOW');
  1516. a_label(list,hl);
  1517. end;
  1518. procedure tcgarm.g_save_standard_registers(list : TAsmList);
  1519. begin
  1520. { this work is done in g_proc_entry }
  1521. end;
  1522. procedure tcgarm.g_restore_standard_registers(list : TAsmList);
  1523. begin
  1524. { this work is done in g_proc_exit }
  1525. end;
  1526. procedure tcgarm.a_jmp_cond(list : TAsmList;cond : TOpCmp;l: tasmlabel);
  1527. var
  1528. ai : taicpu;
  1529. begin
  1530. ai:=Taicpu.Op_sym(A_B,l);
  1531. ai.SetCondition(OpCmp2AsmCond[cond]);
  1532. ai.is_jmp:=true;
  1533. list.concat(ai);
  1534. end;
  1535. procedure tcgarm.g_intf_wrapper(list: TAsmList; procdef: tprocdef; const labelname: string; ioffset: longint);
  1536. procedure loadvmttor12;
  1537. var
  1538. href : treference;
  1539. begin
  1540. reference_reset_base(href,NR_R0,0);
  1541. cg.a_load_ref_reg(list,OS_ADDR,OS_ADDR,href,NR_R12);
  1542. end;
  1543. procedure op_onr12methodaddr;
  1544. var
  1545. href : treference;
  1546. begin
  1547. if (procdef.extnumber=$ffff) then
  1548. Internalerror(200006139);
  1549. { call/jmp vmtoffs(%eax) ; method offs }
  1550. reference_reset_base(href,NR_R12,procdef._class.vmtmethodoffset(procdef.extnumber));
  1551. cg.a_load_ref_reg(list,OS_ADDR,OS_ADDR,href,NR_R12);
  1552. list.concat(taicpu.op_reg_reg(A_MOV,NR_PC,NR_R12));
  1553. end;
  1554. var
  1555. lab : tasmsymbol;
  1556. make_global : boolean;
  1557. href : treference;
  1558. begin
  1559. if not(procdef.proctypeoption in [potype_function,potype_procedure]) then
  1560. Internalerror(200006137);
  1561. if not assigned(procdef._class) or
  1562. (procdef.procoptions*[po_classmethod, po_staticmethod,
  1563. po_methodpointer, po_interrupt, po_iocheck]<>[]) then
  1564. Internalerror(200006138);
  1565. if procdef.owner.symtabletype<>objectsymtable then
  1566. Internalerror(200109191);
  1567. make_global:=false;
  1568. if (not current_module.is_unit) or
  1569. (cs_create_smart in aktmoduleswitches) or
  1570. (procdef.owner.defowner.owner.symtabletype=globalsymtable) then
  1571. make_global:=true;
  1572. if make_global then
  1573. list.concat(Tai_symbol.Createname_global(labelname,AT_FUNCTION,0))
  1574. else
  1575. list.concat(Tai_symbol.Createname(labelname,AT_FUNCTION,0));
  1576. { set param1 interface to self }
  1577. g_adjust_self_value(list,procdef,ioffset);
  1578. { case 4 }
  1579. if po_virtualmethod in procdef.procoptions then
  1580. begin
  1581. loadvmttor12;
  1582. op_onr12methodaddr;
  1583. end
  1584. { case 0 }
  1585. else
  1586. list.concat(taicpu.op_sym(A_B,current_asmdata.RefAsmSymbol(procdef.mangledname)));
  1587. list.concat(Tai_symbol_end.Createname(labelname));
  1588. end;
  1589. procedure tcg64farm.a_op64_reg_reg(list : TAsmList;op:TOpCG;size : tcgsize;regsrc,regdst : tregister64);
  1590. var
  1591. tmpreg : tregister;
  1592. begin
  1593. case op of
  1594. OP_NEG:
  1595. begin
  1596. list.concat(setoppostfix(taicpu.op_reg_reg_const(A_RSB,regdst.reglo,regsrc.reglo,0),PF_S));
  1597. list.concat(taicpu.op_reg_reg_const(A_RSC,regdst.reghi,regsrc.reghi,0));
  1598. end;
  1599. OP_NOT:
  1600. begin
  1601. cg.a_op_reg_reg(list,OP_NOT,OS_INT,regsrc.reglo,regdst.reglo);
  1602. cg.a_op_reg_reg(list,OP_NOT,OS_INT,regsrc.reghi,regdst.reghi);
  1603. end;
  1604. else
  1605. a_op64_reg_reg_reg(list,op,size,regsrc,regdst,regdst);
  1606. end;
  1607. end;
  1608. procedure tcg64farm.a_op64_const_reg(list : TAsmList;op:TOpCG;size : tcgsize;value : int64;reg : tregister64);
  1609. begin
  1610. a_op64_const_reg_reg(list,op,size,value,reg,reg);
  1611. end;
  1612. procedure tcg64farm.a_op64_const_reg_reg(list: TAsmList;op:TOpCG;size : tcgsize;value : int64;regsrc,regdst : tregister64);
  1613. var
  1614. ovloc : tlocation;
  1615. begin
  1616. a_op64_const_reg_reg_checkoverflow(list,op,size,value,regsrc,regdst,false,ovloc);
  1617. end;
  1618. procedure tcg64farm.a_op64_reg_reg_reg(list: TAsmList;op:TOpCG;size : tcgsize;regsrc1,regsrc2,regdst : tregister64);
  1619. var
  1620. ovloc : tlocation;
  1621. begin
  1622. a_op64_reg_reg_reg_checkoverflow(list,op,size,regsrc1,regsrc2,regdst,false,ovloc);
  1623. end;
  1624. procedure tcg64farm.a_op64_const_reg_reg_checkoverflow(list: TAsmList;op:TOpCG;size : tcgsize;value : int64;regsrc,regdst : tregister64;setflags : boolean;var ovloc : tlocation);
  1625. var
  1626. tmpreg : tregister;
  1627. b : byte;
  1628. begin
  1629. ovloc.loc:=LOC_VOID;
  1630. case op of
  1631. OP_NEG,
  1632. OP_NOT :
  1633. internalerror(200306017);
  1634. end;
  1635. if (setflags or tcgarm(cg).cgsetflags) and (op in [OP_ADD,OP_SUB]) then
  1636. begin
  1637. case op of
  1638. OP_ADD:
  1639. begin
  1640. if is_shifter_const(lo(value),b) then
  1641. list.concat(setoppostfix(taicpu.op_reg_reg_const(A_ADD,regdst.reglo,regsrc.reglo,lo(value)),PF_S))
  1642. else
  1643. begin
  1644. tmpreg:=cg.getintregister(list,OS_32);
  1645. cg.a_load_const_reg(list,OS_32,lo(value),tmpreg);
  1646. list.concat(setoppostfix(taicpu.op_reg_reg_reg(A_ADD,regdst.reglo,regsrc.reglo,tmpreg),PF_S));
  1647. end;
  1648. if is_shifter_const(hi(value),b) then
  1649. list.concat(setoppostfix(taicpu.op_reg_reg_const(A_ADC,regdst.reghi,regsrc.reghi,hi(value)),PF_S))
  1650. else
  1651. begin
  1652. tmpreg:=cg.getintregister(list,OS_32);
  1653. cg.a_load_const_reg(list,OS_32,hi(value),tmpreg);
  1654. list.concat(setoppostfix(taicpu.op_reg_reg_reg(A_ADC,regdst.reghi,regsrc.reghi,tmpreg),PF_S));
  1655. end;
  1656. end;
  1657. OP_SUB:
  1658. begin
  1659. if is_shifter_const(lo(value),b) then
  1660. list.concat(setoppostfix(taicpu.op_reg_reg_const(A_SUB,regdst.reglo,regsrc.reglo,lo(value)),PF_S))
  1661. else
  1662. begin
  1663. tmpreg:=cg.getintregister(list,OS_32);
  1664. cg.a_load_const_reg(list,OS_32,lo(value),tmpreg);
  1665. list.concat(setoppostfix(taicpu.op_reg_reg_reg(A_SUB,regdst.reglo,regsrc.reglo,tmpreg),PF_S));
  1666. end;
  1667. if is_shifter_const(hi(value),b) then
  1668. list.concat(setoppostfix(taicpu.op_reg_reg_const(A_SBC,regdst.reghi,regsrc.reghi,hi(value)),PF_S))
  1669. else
  1670. begin
  1671. tmpreg:=cg.getintregister(list,OS_32);
  1672. cg.a_load_const_reg(list,OS_32,hi(value),tmpreg);
  1673. list.concat(setoppostfix(taicpu.op_reg_reg_reg(A_SBC,regdst.reghi,regsrc.reghi,tmpreg),PF_S));
  1674. end;
  1675. end;
  1676. else
  1677. internalerror(200502131);
  1678. end;
  1679. if size=OS_64 then
  1680. begin
  1681. { the arm has an weired opinion how flags for SUB/ADD are handled }
  1682. ovloc.loc:=LOC_FLAGS;
  1683. case op of
  1684. OP_ADD:
  1685. ovloc.resflags:=F_CS;
  1686. OP_SUB:
  1687. ovloc.resflags:=F_CC;
  1688. end;
  1689. end;
  1690. end
  1691. else
  1692. begin
  1693. case op of
  1694. OP_AND,OP_OR,OP_XOR:
  1695. begin
  1696. cg.a_op_const_reg_reg(list,op,OS_32,lo(value),regsrc.reglo,regdst.reglo);
  1697. cg.a_op_const_reg_reg(list,op,OS_32,hi(value),regsrc.reghi,regdst.reghi);
  1698. end;
  1699. OP_ADD:
  1700. begin
  1701. if is_shifter_const(lo(value),b) then
  1702. list.concat(setoppostfix(taicpu.op_reg_reg_const(A_ADD,regdst.reglo,regsrc.reglo,lo(value)),PF_S))
  1703. else
  1704. begin
  1705. tmpreg:=cg.getintregister(list,OS_32);
  1706. cg.a_load_const_reg(list,OS_32,lo(value),tmpreg);
  1707. list.concat(setoppostfix(taicpu.op_reg_reg_reg(A_ADD,regdst.reglo,regsrc.reglo,tmpreg),PF_S));
  1708. end;
  1709. if is_shifter_const(hi(value),b) then
  1710. list.concat(taicpu.op_reg_reg_const(A_ADC,regdst.reghi,regsrc.reghi,hi(value)))
  1711. else
  1712. begin
  1713. tmpreg:=cg.getintregister(list,OS_32);
  1714. cg.a_load_const_reg(list,OS_32,hi(value),tmpreg);
  1715. list.concat(taicpu.op_reg_reg_reg(A_ADC,regdst.reghi,regsrc.reghi,tmpreg));
  1716. end;
  1717. end;
  1718. OP_SUB:
  1719. begin
  1720. if is_shifter_const(lo(value),b) then
  1721. list.concat(setoppostfix(taicpu.op_reg_reg_const(A_SUB,regdst.reglo,regsrc.reglo,lo(value)),PF_S))
  1722. else
  1723. begin
  1724. tmpreg:=cg.getintregister(list,OS_32);
  1725. cg.a_load_const_reg(list,OS_32,lo(value),tmpreg);
  1726. list.concat(setoppostfix(taicpu.op_reg_reg_reg(A_SUB,regdst.reglo,regsrc.reglo,tmpreg),PF_S));
  1727. end;
  1728. if is_shifter_const(hi(value),b) then
  1729. list.concat(taicpu.op_reg_reg_const(A_SBC,regdst.reghi,regsrc.reghi,hi(value)))
  1730. else
  1731. begin
  1732. tmpreg:=cg.getintregister(list,OS_32);
  1733. cg.a_load_const_reg(list,OS_32,hi(value),tmpreg);
  1734. list.concat(taicpu.op_reg_reg_reg(A_SBC,regdst.reghi,regsrc.reghi,tmpreg));
  1735. end;
  1736. end;
  1737. else
  1738. internalerror(2003083101);
  1739. end;
  1740. end;
  1741. end;
  1742. procedure tcg64farm.a_op64_reg_reg_reg_checkoverflow(list: TAsmList;op:TOpCG;size : tcgsize;regsrc1,regsrc2,regdst : tregister64;setflags : boolean;var ovloc : tlocation);
  1743. var
  1744. op1,op2:TAsmOp;
  1745. begin
  1746. ovloc.loc:=LOC_VOID;
  1747. case op of
  1748. OP_NEG,
  1749. OP_NOT :
  1750. internalerror(200306017);
  1751. end;
  1752. if (setflags or tcgarm(cg).cgsetflags) and (op in [OP_ADD,OP_SUB]) then
  1753. begin
  1754. case op of
  1755. OP_ADD:
  1756. begin
  1757. list.concat(setoppostfix(taicpu.op_reg_reg_reg(A_ADD,regdst.reglo,regsrc1.reglo,regsrc2.reglo),PF_S));
  1758. list.concat(setoppostfix(taicpu.op_reg_reg_reg(A_ADC,regdst.reghi,regsrc1.reghi,regsrc2.reghi),PF_S));
  1759. end;
  1760. OP_SUB:
  1761. begin
  1762. list.concat(setoppostfix(taicpu.op_reg_reg_reg(A_SUB,regdst.reglo,regsrc2.reglo,regsrc1.reglo),PF_S));
  1763. list.concat(setoppostfix(taicpu.op_reg_reg_reg(A_SBC,regdst.reghi,regsrc2.reghi,regsrc1.reghi),PF_S));
  1764. end;
  1765. else
  1766. internalerror(2003083101);
  1767. end;
  1768. if size=OS_64 then
  1769. begin
  1770. { the arm has an weired opinion how flags for SUB/ADD are handled }
  1771. ovloc.loc:=LOC_FLAGS;
  1772. case op of
  1773. OP_ADD:
  1774. ovloc.resflags:=F_CC;
  1775. OP_SUB:
  1776. ovloc.resflags:=F_CS;
  1777. end;
  1778. end;
  1779. end
  1780. else
  1781. begin
  1782. case op of
  1783. OP_AND,OP_OR,OP_XOR:
  1784. begin
  1785. cg.a_op_reg_reg_reg(list,op,OS_32,regsrc1.reglo,regsrc2.reglo,regdst.reglo);
  1786. cg.a_op_reg_reg_reg(list,op,OS_32,regsrc1.reghi,regsrc2.reghi,regdst.reghi);
  1787. end;
  1788. OP_ADD:
  1789. begin
  1790. list.concat(setoppostfix(taicpu.op_reg_reg_reg(A_ADD,regdst.reglo,regsrc1.reglo,regsrc2.reglo),PF_S));
  1791. list.concat(taicpu.op_reg_reg_reg(A_ADC,regdst.reghi,regsrc1.reghi,regsrc2.reghi));
  1792. end;
  1793. OP_SUB:
  1794. begin
  1795. list.concat(setoppostfix(taicpu.op_reg_reg_reg(A_SUB,regdst.reglo,regsrc2.reglo,regsrc1.reglo),PF_S));
  1796. list.concat(taicpu.op_reg_reg_reg(A_SBC,regdst.reghi,regsrc2.reghi,regsrc1.reghi));
  1797. end;
  1798. else
  1799. internalerror(2003083101);
  1800. end;
  1801. end;
  1802. end;
  1803. begin
  1804. cg:=tcgarm.create;
  1805. cg64:=tcg64farm.create;
  1806. end.