cgcpu.pas 70 KB

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