cgcpu.pas 91 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384
  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; fromsize, tosize: tcgsize; reg1, reg2: tregister); override;
  56. procedure a_loadfpu_ref_reg(list: TAsmList; fromsize, tosize: tcgsize; const ref: treference; reg: tregister); override;
  57. procedure a_loadfpu_reg_ref(list: TAsmList; fromsize, tosize: 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_registers(list : TAsmList);override;
  77. procedure g_restore_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. procedure g_adjust_self_value(list:TAsmList;procdef: tprocdef;ioffset: aint); override;
  83. procedure g_stackpointer_alloc(list : TAsmList;size : longint);override;
  84. private
  85. { clear out potential overflow bits from 8 or 16 bit operations }
  86. { the upper 24/16 bits of a register after an operation }
  87. procedure maybeadjustresult(list: TAsmList; op: TOpCg; size: tcgsize; dst: tregister);
  88. function get_darwin_call_stub(const s: string): tasmsymbol;
  89. end;
  90. tcg64farm = class(tcg64f32)
  91. procedure a_op64_reg_reg(list : TAsmList;op:TOpCG;size : tcgsize;regsrc,regdst : tregister64);override;
  92. procedure a_op64_const_reg(list : TAsmList;op:TOpCG;size : tcgsize;value : int64;reg : tregister64);override;
  93. procedure a_op64_const_reg_reg(list: TAsmList;op:TOpCG;size : tcgsize;value : int64;regsrc,regdst : tregister64);override;
  94. procedure a_op64_reg_reg_reg(list: TAsmList;op:TOpCG;size : tcgsize;regsrc1,regsrc2,regdst : tregister64);override;
  95. procedure a_op64_const_reg_reg_checkoverflow(list: TAsmList;op:TOpCG;size : tcgsize;value : int64;regsrc,regdst : tregister64;setflags : boolean;var ovloc : tlocation);override;
  96. procedure a_op64_reg_reg_reg_checkoverflow(list: TAsmList;op:TOpCG;size : tcgsize;regsrc1,regsrc2,regdst : tregister64;setflags : boolean;var ovloc : tlocation);override;
  97. end;
  98. const
  99. OpCmp2AsmCond : Array[topcmp] of TAsmCond = (C_NONE,C_EQ,C_GT,
  100. C_LT,C_GE,C_LE,C_NE,C_LS,C_CC,C_CS,C_HI);
  101. winstackpagesize = 4096;
  102. function get_fpu_postfix(def : tdef) : toppostfix;
  103. implementation
  104. uses
  105. globals,verbose,systems,cutils,
  106. fmodule,
  107. symconst,symsym,
  108. tgobj,
  109. procinfo,cpupi,
  110. paramgr;
  111. function get_fpu_postfix(def : tdef) : toppostfix;
  112. begin
  113. if def.typ=floatdef then
  114. begin
  115. case tfloatdef(def).floattype of
  116. s32real:
  117. result:=PF_S;
  118. s64real:
  119. result:=PF_D;
  120. s80real:
  121. result:=PF_E;
  122. else
  123. internalerror(200401272);
  124. end;
  125. end
  126. else
  127. internalerror(200401271);
  128. end;
  129. procedure tcgarm.init_register_allocators;
  130. begin
  131. inherited init_register_allocators;
  132. { currently, we save R14 always, so we can use it }
  133. if (target_info.system<>system_arm_darwin) then
  134. rg[R_INTREGISTER]:=trgintcpu.create(R_INTREGISTER,R_SUBWHOLE,
  135. [RS_R0,RS_R1,RS_R2,RS_R3,RS_R4,RS_R5,RS_R6,RS_R7,RS_R8,
  136. RS_R9,RS_R10,RS_R12,RS_R14],first_int_imreg,[])
  137. else
  138. { r9 is not available on Darwin according to the llvm code generator }
  139. rg[R_INTREGISTER]:=trgintcpu.create(R_INTREGISTER,R_SUBWHOLE,
  140. [RS_R0,RS_R1,RS_R2,RS_R3,RS_R4,RS_R5,RS_R6,RS_R7,RS_R8,
  141. RS_R10,RS_R12,RS_R14],first_int_imreg,[]);
  142. rg[R_FPUREGISTER]:=trgcpu.create(R_FPUREGISTER,R_SUBNONE,
  143. [RS_F0,RS_F1,RS_F2,RS_F3,RS_F4,RS_F5,RS_F6,RS_F7],first_fpu_imreg,[]);
  144. rg[R_MMREGISTER]:=trgcpu.create(R_MMREGISTER,R_SUBNONE,
  145. [RS_S0,RS_S1,RS_R2,RS_R3,RS_R4,RS_S31],first_mm_imreg,[]);
  146. end;
  147. procedure tcgarm.done_register_allocators;
  148. begin
  149. rg[R_INTREGISTER].free;
  150. rg[R_FPUREGISTER].free;
  151. rg[R_MMREGISTER].free;
  152. inherited done_register_allocators;
  153. end;
  154. procedure tcgarm.a_param_const(list : TAsmList;size : tcgsize;a : aint;const paraloc : TCGPara);
  155. var
  156. ref: treference;
  157. begin
  158. paraloc.check_simple_location;
  159. case paraloc.location^.loc of
  160. LOC_REGISTER,LOC_CREGISTER:
  161. a_load_const_reg(list,size,a,paraloc.location^.register);
  162. LOC_REFERENCE:
  163. begin
  164. reference_reset(ref);
  165. ref.base:=paraloc.location^.reference.index;
  166. ref.offset:=paraloc.location^.reference.offset;
  167. a_load_const_ref(list,size,a,ref);
  168. end;
  169. else
  170. internalerror(2002081101);
  171. end;
  172. end;
  173. procedure tcgarm.a_param_ref(list : TAsmList;size : tcgsize;const r : treference;const paraloc : TCGPara);
  174. var
  175. tmpref, ref: treference;
  176. location: pcgparalocation;
  177. sizeleft: aint;
  178. begin
  179. location := paraloc.location;
  180. tmpref := r;
  181. sizeleft := paraloc.intsize;
  182. while assigned(location) do
  183. begin
  184. case location^.loc of
  185. LOC_REGISTER,LOC_CREGISTER:
  186. a_load_ref_reg(list,location^.size,location^.size,tmpref,location^.register);
  187. LOC_REFERENCE:
  188. begin
  189. reference_reset_base(ref,location^.reference.index,location^.reference.offset);
  190. { doubles in softemu mode have a strange order of registers and references }
  191. if location^.size=OS_32 then
  192. g_concatcopy(list,tmpref,ref,4)
  193. else
  194. begin
  195. g_concatcopy(list,tmpref,ref,sizeleft);
  196. if assigned(location^.next) then
  197. internalerror(2005010710);
  198. end;
  199. end;
  200. LOC_FPUREGISTER,LOC_CFPUREGISTER:
  201. case location^.size of
  202. OS_F32, OS_F64:
  203. a_loadfpu_ref_reg(list,location^.size,location^.size,tmpref,location^.register);
  204. else
  205. internalerror(2002072801);
  206. end;
  207. LOC_VOID:
  208. begin
  209. // nothing to do
  210. end;
  211. else
  212. internalerror(2002081103);
  213. end;
  214. inc(tmpref.offset,tcgsize2size[location^.size]);
  215. dec(sizeleft,tcgsize2size[location^.size]);
  216. location := location^.next;
  217. end;
  218. end;
  219. procedure tcgarm.a_paramaddr_ref(list : TAsmList;const r : treference;const paraloc : TCGPara);
  220. var
  221. ref: treference;
  222. tmpreg: tregister;
  223. begin
  224. paraloc.check_simple_location;
  225. case paraloc.location^.loc of
  226. LOC_REGISTER,LOC_CREGISTER:
  227. a_loadaddr_ref_reg(list,r,paraloc.location^.register);
  228. LOC_REFERENCE:
  229. begin
  230. reference_reset(ref);
  231. ref.base := paraloc.location^.reference.index;
  232. ref.offset := paraloc.location^.reference.offset;
  233. tmpreg := getintregister(list,OS_ADDR);
  234. a_loadaddr_ref_reg(list,r,tmpreg);
  235. a_load_reg_ref(list,OS_ADDR,OS_ADDR,tmpreg,ref);
  236. end;
  237. else
  238. internalerror(2002080701);
  239. end;
  240. end;
  241. procedure tcgarm.a_call_name(list : TAsmList;const s : string);
  242. begin
  243. if target_info.system<>system_arm_darwin then
  244. list.concat(taicpu.op_sym(A_BL,current_asmdata.RefAsmSymbol(s)))
  245. else
  246. list.concat(taicpu.op_sym(A_BL,get_darwin_call_stub(s)));
  247. {
  248. the compiler does not properly set this flag anymore in pass 1, and
  249. for now we only need it after pass 2 (I hope) (JM)
  250. if not(pi_do_call in current_procinfo.flags) then
  251. internalerror(2003060703);
  252. }
  253. include(current_procinfo.flags,pi_do_call);
  254. end;
  255. procedure tcgarm.a_call_reg(list : TAsmList;reg: tregister);
  256. begin
  257. list.concat(taicpu.op_reg_reg(A_MOV,NR_R14,NR_PC));
  258. list.concat(taicpu.op_reg_reg(A_MOV,NR_PC,reg));
  259. {
  260. the compiler does not properly set this flag anymore in pass 1, and
  261. for now we only need it after pass 2 (I hope) (JM)
  262. if not(pi_do_call in current_procinfo.flags) then
  263. internalerror(2003060703);
  264. }
  265. include(current_procinfo.flags,pi_do_call);
  266. end;
  267. procedure tcgarm.a_call_ref(list : TAsmList;ref: treference);
  268. begin
  269. a_reg_alloc(list,NR_R12);
  270. a_load_ref_reg(list,OS_ADDR,OS_ADDR,ref,NR_R12);
  271. list.concat(taicpu.op_reg_reg(A_MOV,NR_R14,NR_PC));
  272. list.concat(taicpu.op_reg_reg(A_MOV,NR_PC,NR_R12));
  273. a_reg_dealloc(list,NR_R12);
  274. include(current_procinfo.flags,pi_do_call);
  275. end;
  276. procedure tcgarm.a_op_const_reg(list : TAsmList; Op: TOpCG; size: TCGSize; a: aint; reg: TRegister);
  277. begin
  278. a_op_const_reg_reg(list,op,size,a,reg,reg);
  279. end;
  280. procedure tcgarm.a_op_reg_reg(list : TAsmList; Op: TOpCG; size: TCGSize; src, dst: TRegister);
  281. begin
  282. case op of
  283. OP_NEG:
  284. list.concat(taicpu.op_reg_reg_const(A_RSB,dst,src,0));
  285. OP_NOT:
  286. begin
  287. list.concat(taicpu.op_reg_reg(A_MVN,dst,src));
  288. case size of
  289. OS_8 :
  290. a_op_const_reg_reg(list,OP_AND,OS_INT,$ff,dst,dst);
  291. OS_16 :
  292. a_op_const_reg_reg(list,OP_AND,OS_INT,$ffff,dst,dst);
  293. end;
  294. end
  295. else
  296. a_op_reg_reg_reg(list,op,OS_32,src,dst,dst);
  297. end;
  298. end;
  299. const
  300. op_reg_reg_opcg2asmop: array[TOpCG] of tasmop =
  301. (A_NONE,A_MOV,A_ADD,A_AND,A_NONE,A_NONE,A_MUL,A_MUL,A_NONE,A_NONE,A_ORR,
  302. A_NONE,A_NONE,A_NONE,A_SUB,A_EOR,A_NONE,A_NONE);
  303. procedure tcgarm.a_op_const_reg_reg(list: TAsmList; op: TOpCg;
  304. size: tcgsize; a: aint; src, dst: tregister);
  305. var
  306. ovloc : tlocation;
  307. begin
  308. a_op_const_reg_reg_checkoverflow(list,op,size,a,src,dst,false,ovloc);
  309. end;
  310. procedure tcgarm.a_op_reg_reg_reg(list: TAsmList; op: TOpCg;
  311. size: tcgsize; src1, src2, dst: tregister);
  312. var
  313. ovloc : tlocation;
  314. begin
  315. a_op_reg_reg_reg_checkoverflow(list,op,size,src1,src2,dst,false,ovloc);
  316. end;
  317. procedure tcgarm.a_op_const_reg_reg_checkoverflow(list: TAsmList; op: TOpCg; size: tcgsize; a: aint; src, dst: tregister;setflags : boolean;var ovloc : tlocation);
  318. var
  319. shift : byte;
  320. tmpreg : tregister;
  321. so : tshifterop;
  322. l1 : longint;
  323. begin
  324. ovloc.loc:=LOC_VOID;
  325. if {$ifopt R+}(a<>-2147483648) and{$endif} is_shifter_const(-a,shift) then
  326. case op of
  327. OP_ADD:
  328. begin
  329. op:=OP_SUB;
  330. a:=aint(dword(-a));
  331. end;
  332. OP_SUB:
  333. begin
  334. op:=OP_ADD;
  335. a:=aint(dword(-a));
  336. end
  337. end;
  338. if is_shifter_const(a,shift) and not(op in [OP_IMUL,OP_MUL]) then
  339. case op of
  340. OP_NEG,OP_NOT,
  341. OP_DIV,OP_IDIV:
  342. internalerror(200308281);
  343. OP_SHL:
  344. begin
  345. if a>32 then
  346. internalerror(200308294);
  347. if a<>0 then
  348. begin
  349. shifterop_reset(so);
  350. so.shiftmode:=SM_LSL;
  351. so.shiftimm:=a;
  352. list.concat(taicpu.op_reg_reg_shifterop(A_MOV,dst,src,so));
  353. end
  354. else
  355. list.concat(taicpu.op_reg_reg(A_MOV,dst,src));
  356. end;
  357. OP_ROL:
  358. begin
  359. if a>32 then
  360. internalerror(200308294);
  361. if a<>0 then
  362. begin
  363. shifterop_reset(so);
  364. so.shiftmode:=SM_ROR;
  365. so.shiftimm:=32-a;
  366. list.concat(taicpu.op_reg_reg_shifterop(A_MOV,dst,src,so));
  367. end
  368. else
  369. list.concat(taicpu.op_reg_reg(A_MOV,dst,src));
  370. end;
  371. OP_ROR:
  372. begin
  373. if a>32 then
  374. internalerror(200308294);
  375. if a<>0 then
  376. begin
  377. shifterop_reset(so);
  378. so.shiftmode:=SM_ROR;
  379. so.shiftimm:=a;
  380. list.concat(taicpu.op_reg_reg_shifterop(A_MOV,dst,src,so));
  381. end
  382. else
  383. list.concat(taicpu.op_reg_reg(A_MOV,dst,src));
  384. end;
  385. OP_SHR:
  386. begin
  387. if a>32 then
  388. internalerror(200308292);
  389. shifterop_reset(so);
  390. if a<>0 then
  391. begin
  392. so.shiftmode:=SM_LSR;
  393. so.shiftimm:=a;
  394. list.concat(taicpu.op_reg_reg_shifterop(A_MOV,dst,src,so));
  395. end
  396. else
  397. list.concat(taicpu.op_reg_reg(A_MOV,dst,src));
  398. end;
  399. OP_SAR:
  400. begin
  401. if a>32 then
  402. internalerror(200308295);
  403. if a<>0 then
  404. begin
  405. shifterop_reset(so);
  406. so.shiftmode:=SM_ASR;
  407. so.shiftimm:=a;
  408. list.concat(taicpu.op_reg_reg_shifterop(A_MOV,dst,src,so));
  409. end
  410. else
  411. list.concat(taicpu.op_reg_reg(A_MOV,dst,src));
  412. end;
  413. else
  414. list.concat(setoppostfix(
  415. taicpu.op_reg_reg_const(op_reg_reg_opcg2asmop[op],dst,src,a),toppostfix(ord(cgsetflags or setflags)*ord(PF_S))
  416. ));
  417. if (cgsetflags or setflags) and (size in [OS_8,OS_16,OS_32]) then
  418. begin
  419. ovloc.loc:=LOC_FLAGS;
  420. case op of
  421. OP_ADD:
  422. ovloc.resflags:=F_CS;
  423. OP_SUB:
  424. ovloc.resflags:=F_CC;
  425. end;
  426. end;
  427. end
  428. else
  429. begin
  430. { there could be added some more sophisticated optimizations }
  431. if (op in [OP_MUL,OP_IMUL]) and (a=1) then
  432. a_load_reg_reg(list,size,size,src,dst)
  433. else if (op in [OP_MUL,OP_IMUL]) and (a=0) then
  434. a_load_const_reg(list,size,0,dst)
  435. else if (op in [OP_IMUL]) and (a=-1) then
  436. a_op_reg_reg(list,OP_NEG,size,src,dst)
  437. { we do this here instead in the peephole optimizer because
  438. it saves us a register }
  439. else if (op in [OP_MUL,OP_IMUL]) and ispowerof2(a,l1) and not(cgsetflags or setflags) then
  440. a_op_const_reg_reg(list,OP_SHL,size,l1,src,dst)
  441. { for example : b=a*5 -> b=a*4+a with add instruction and shl }
  442. else if (op in [OP_MUL,OP_IMUL]) and ispowerof2(a-1,l1) and not(cgsetflags or setflags) then
  443. begin
  444. if l1>32 then{roozbeh does this ever happen?}
  445. internalerror(200308296);
  446. shifterop_reset(so);
  447. so.shiftmode:=SM_LSL;
  448. so.shiftimm:=l1;
  449. list.concat(taicpu.op_reg_reg_reg_shifterop(A_ADD,dst,src,src,so));
  450. end
  451. else
  452. begin
  453. tmpreg:=getintregister(list,size);
  454. a_load_const_reg(list,size,a,tmpreg);
  455. a_op_reg_reg_reg_checkoverflow(list,op,size,tmpreg,src,dst,setflags,ovloc);
  456. end;
  457. end;
  458. maybeadjustresult(list,op,size,dst);
  459. end;
  460. procedure tcgarm.a_op_reg_reg_reg_checkoverflow(list: TAsmList; op: TOpCg; size: tcgsize; src1, src2, dst: tregister;setflags : boolean;var ovloc : tlocation);
  461. var
  462. so : tshifterop;
  463. tmpreg,overflowreg : tregister;
  464. asmop : tasmop;
  465. begin
  466. ovloc.loc:=LOC_VOID;
  467. case op of
  468. OP_NEG,OP_NOT,
  469. OP_DIV,OP_IDIV:
  470. internalerror(200308281);
  471. OP_SHL:
  472. begin
  473. shifterop_reset(so);
  474. so.rs:=src1;
  475. so.shiftmode:=SM_LSL;
  476. list.concat(taicpu.op_reg_reg_shifterop(A_MOV,dst,src2,so));
  477. end;
  478. OP_SHR:
  479. begin
  480. shifterop_reset(so);
  481. so.rs:=src1;
  482. so.shiftmode:=SM_LSR;
  483. list.concat(taicpu.op_reg_reg_shifterop(A_MOV,dst,src2,so));
  484. end;
  485. OP_SAR:
  486. begin
  487. shifterop_reset(so);
  488. so.rs:=src1;
  489. so.shiftmode:=SM_ASR;
  490. list.concat(taicpu.op_reg_reg_shifterop(A_MOV,dst,src2,so));
  491. end;
  492. OP_ROL:
  493. begin
  494. if not(size in [OS_32,OS_S32]) then
  495. internalerror(2008072801);
  496. { simulate ROL by ror'ing 32-value }
  497. tmpreg:=getintregister(list,OS_32);
  498. list.concat(taicpu.op_reg_const(A_MOV,tmpreg,32));
  499. list.concat(taicpu.op_reg_reg_reg(A_SUB,src1,tmpreg,src1));
  500. shifterop_reset(so);
  501. so.rs:=src1;
  502. so.shiftmode:=SM_ROR;
  503. list.concat(taicpu.op_reg_reg_shifterop(A_MOV,dst,src2,so));
  504. end;
  505. OP_ROR:
  506. begin
  507. if not(size in [OS_32,OS_S32]) then
  508. internalerror(2008072802);
  509. shifterop_reset(so);
  510. so.rs:=src1;
  511. so.shiftmode:=SM_ROR;
  512. list.concat(taicpu.op_reg_reg_shifterop(A_MOV,dst,src2,so));
  513. end;
  514. OP_IMUL,
  515. OP_MUL:
  516. begin
  517. if cgsetflags or setflags then
  518. begin
  519. overflowreg:=getintregister(list,size);
  520. if op=OP_IMUL then
  521. asmop:=A_SMULL
  522. else
  523. asmop:=A_UMULL;
  524. { the arm doesn't allow that rd and rm are the same }
  525. if dst=src2 then
  526. begin
  527. if dst<>src1 then
  528. list.concat(taicpu.op_reg_reg_reg_reg(asmop,dst,overflowreg,src1,src2))
  529. else
  530. begin
  531. tmpreg:=getintregister(list,size);
  532. a_load_reg_reg(list,size,size,src2,dst);
  533. list.concat(taicpu.op_reg_reg_reg_reg(asmop,dst,overflowreg,tmpreg,src1));
  534. end;
  535. end
  536. else
  537. list.concat(taicpu.op_reg_reg_reg_reg(asmop,dst,overflowreg,src2,src1));
  538. if op=OP_IMUL then
  539. begin
  540. shifterop_reset(so);
  541. so.shiftmode:=SM_ASR;
  542. so.shiftimm:=31;
  543. list.concat(taicpu.op_reg_reg_shifterop(A_CMP,overflowreg,dst,so));
  544. end
  545. else
  546. list.concat(taicpu.op_reg_const(A_CMP,overflowreg,0));
  547. ovloc.loc:=LOC_FLAGS;
  548. ovloc.resflags:=F_NE;
  549. end
  550. else
  551. begin
  552. { the arm doesn't allow that rd and rm are the same }
  553. if dst=src2 then
  554. begin
  555. if dst<>src1 then
  556. list.concat(taicpu.op_reg_reg_reg(A_MUL,dst,src1,src2))
  557. else
  558. begin
  559. tmpreg:=getintregister(list,size);
  560. a_load_reg_reg(list,size,size,src2,dst);
  561. list.concat(taicpu.op_reg_reg_reg(A_MUL,dst,tmpreg,src1));
  562. end;
  563. end
  564. else
  565. list.concat(taicpu.op_reg_reg_reg(A_MUL,dst,src2,src1));
  566. end;
  567. end;
  568. else
  569. list.concat(setoppostfix(
  570. taicpu.op_reg_reg_reg(op_reg_reg_opcg2asmop[op],dst,src2,src1),toppostfix(ord(cgsetflags or setflags)*ord(PF_S))
  571. ));
  572. end;
  573. maybeadjustresult(list,op,size,dst);
  574. end;
  575. procedure tcgarm.a_load_const_reg(list : TAsmList; size: tcgsize; a : aint;reg : tregister);
  576. var
  577. imm_shift : byte;
  578. l : tasmlabel;
  579. hr : treference;
  580. begin
  581. if not(size in [OS_8,OS_S8,OS_16,OS_S16,OS_32,OS_S32]) then
  582. internalerror(2002090902);
  583. if is_shifter_const(a,imm_shift) then
  584. list.concat(taicpu.op_reg_const(A_MOV,reg,a))
  585. else if is_shifter_const(not(a),imm_shift) then
  586. list.concat(taicpu.op_reg_const(A_MVN,reg,not(a)))
  587. { loading of constants with mov and orr }
  588. else if (is_shifter_const(a-byte(a),imm_shift)) then
  589. begin
  590. list.concat(taicpu.op_reg_const(A_MOV,reg,a-byte(a)));
  591. list.concat(taicpu.op_reg_reg_const(A_ORR,reg,reg,byte(a)));
  592. end
  593. else if (is_shifter_const(a-word(a),imm_shift)) and (is_shifter_const(word(a),imm_shift)) then
  594. begin
  595. list.concat(taicpu.op_reg_const(A_MOV,reg,a-word(a)));
  596. list.concat(taicpu.op_reg_reg_const(A_ORR,reg,reg,word(a)));
  597. end
  598. else if (is_shifter_const(a-(dword(a) shl 8) shr 8,imm_shift)) and (is_shifter_const((dword(a) shl 8) shr 8,imm_shift)) then
  599. begin
  600. list.concat(taicpu.op_reg_const(A_MOV,reg,a-(dword(a) shl 8) shr 8));
  601. list.concat(taicpu.op_reg_reg_const(A_ORR,reg,reg,(dword(a) shl 8) shr 8));
  602. end
  603. else
  604. begin
  605. reference_reset(hr);
  606. current_asmdata.getjumplabel(l);
  607. cg.a_label(current_procinfo.aktlocaldata,l);
  608. hr.symboldata:=current_procinfo.aktlocaldata.last;
  609. current_procinfo.aktlocaldata.concat(tai_const.Create_32bit(longint(a)));
  610. hr.symbol:=l;
  611. list.concat(taicpu.op_reg_ref(A_LDR,reg,hr));
  612. end;
  613. end;
  614. function tcgarm.handle_load_store(list:TAsmList;op: tasmop;oppostfix : toppostfix;reg:tregister;ref: treference):treference;
  615. var
  616. tmpreg : tregister;
  617. tmpref : treference;
  618. l : tasmlabel;
  619. begin
  620. tmpreg:=NR_NO;
  621. { Be sure to have a base register }
  622. if (ref.base=NR_NO) then
  623. begin
  624. if ref.shiftmode<>SM_None then
  625. internalerror(200308294);
  626. ref.base:=ref.index;
  627. ref.index:=NR_NO;
  628. end;
  629. { absolute symbols can't be handled directly, we've to store the symbol reference
  630. in the text segment and access it pc relative
  631. For now, we assume that references where base or index equals to PC are already
  632. relative, all other references are assumed to be absolute and thus they need
  633. to be handled extra.
  634. A proper solution would be to change refoptions to a set and store the information
  635. if the symbol is absolute or relative there.
  636. }
  637. if (assigned(ref.symbol) and
  638. not(is_pc(ref.base)) and
  639. not(is_pc(ref.index))
  640. ) or
  641. { [#xxx] isn't a valid address operand }
  642. ((ref.base=NR_NO) and (ref.index=NR_NO)) or
  643. (ref.offset<-4095) or
  644. (ref.offset>4095) or
  645. ((oppostfix in [PF_SB,PF_H,PF_SH]) and
  646. ((ref.offset<-255) or
  647. (ref.offset>255)
  648. )
  649. ) or
  650. ((op in [A_LDF,A_STF]) and
  651. ((ref.offset<-1020) or
  652. (ref.offset>1020) or
  653. { the usual pc relative symbol handling assumes possible offsets of +/- 4095 }
  654. assigned(ref.symbol)
  655. )
  656. ) then
  657. begin
  658. reference_reset(tmpref);
  659. { load symbol }
  660. tmpreg:=getintregister(list,OS_INT);
  661. if assigned(ref.symbol) then
  662. begin
  663. current_asmdata.getjumplabel(l);
  664. cg.a_label(current_procinfo.aktlocaldata,l);
  665. tmpref.symboldata:=current_procinfo.aktlocaldata.last;
  666. current_procinfo.aktlocaldata.concat(tai_const.create_sym_offset(ref.symbol,ref.offset));
  667. { load consts entry }
  668. tmpref.symbol:=l;
  669. tmpref.base:=NR_R15;
  670. list.concat(taicpu.op_reg_ref(A_LDR,tmpreg,tmpref));
  671. { in case of LDF/STF, we got rid of the NR_R15 }
  672. if is_pc(ref.base) then
  673. ref.base:=NR_NO;
  674. if is_pc(ref.index) then
  675. ref.index:=NR_NO;
  676. end
  677. else
  678. a_load_const_reg(list,OS_ADDR,ref.offset,tmpreg);
  679. if (ref.base<>NR_NO) then
  680. begin
  681. if ref.index<>NR_NO then
  682. begin
  683. list.concat(taicpu.op_reg_reg_reg(A_ADD,tmpreg,ref.base,tmpreg));
  684. ref.base:=tmpreg;
  685. end
  686. else
  687. begin
  688. ref.index:=tmpreg;
  689. ref.shiftimm:=0;
  690. ref.signindex:=1;
  691. ref.shiftmode:=SM_None;
  692. end;
  693. end
  694. else
  695. ref.base:=tmpreg;
  696. ref.offset:=0;
  697. ref.symbol:=nil;
  698. end;
  699. if (ref.base<>NR_NO) and (ref.index<>NR_NO) and (ref.offset<>0) then
  700. begin
  701. if tmpreg<>NR_NO then
  702. a_op_const_reg_reg(list,OP_ADD,OS_ADDR,ref.offset,tmpreg,tmpreg)
  703. else
  704. begin
  705. tmpreg:=getintregister(list,OS_ADDR);
  706. a_op_const_reg_reg(list,OP_ADD,OS_ADDR,ref.offset,ref.base,tmpreg);
  707. ref.base:=tmpreg;
  708. end;
  709. ref.offset:=0;
  710. end;
  711. { floating point operations have only limited references
  712. we expect here, that a base is already set }
  713. if (op in [A_LDF,A_STF]) and (ref.index<>NR_NO) then
  714. begin
  715. if ref.shiftmode<>SM_none then
  716. internalerror(200309121);
  717. if tmpreg<>NR_NO then
  718. begin
  719. if ref.base=tmpreg then
  720. begin
  721. if ref.signindex<0 then
  722. list.concat(taicpu.op_reg_reg_reg(A_SUB,tmpreg,tmpreg,ref.index))
  723. else
  724. list.concat(taicpu.op_reg_reg_reg(A_ADD,tmpreg,tmpreg,ref.index));
  725. ref.index:=NR_NO;
  726. end
  727. else
  728. begin
  729. if ref.index<>tmpreg then
  730. internalerror(200403161);
  731. if ref.signindex<0 then
  732. list.concat(taicpu.op_reg_reg_reg(A_SUB,tmpreg,ref.base,tmpreg))
  733. else
  734. list.concat(taicpu.op_reg_reg_reg(A_ADD,tmpreg,ref.base,tmpreg));
  735. ref.base:=tmpreg;
  736. ref.index:=NR_NO;
  737. end;
  738. end
  739. else
  740. begin
  741. tmpreg:=getintregister(list,OS_ADDR);
  742. list.concat(taicpu.op_reg_reg_reg(A_ADD,tmpreg,ref.base,ref.index));
  743. ref.base:=tmpreg;
  744. ref.index:=NR_NO;
  745. end;
  746. end;
  747. list.concat(setoppostfix(taicpu.op_reg_ref(op,reg,ref),oppostfix));
  748. Result := ref;
  749. end;
  750. procedure tcgarm.a_load_reg_ref(list : TAsmList; fromsize, tosize: tcgsize; reg : tregister;const ref : treference);
  751. var
  752. oppostfix:toppostfix;
  753. usedtmpref: treference;
  754. tmpreg : tregister;
  755. so : tshifterop;
  756. dir : integer;
  757. begin
  758. if (TCGSize2Size[FromSize] >= TCGSize2Size[ToSize]) then
  759. FromSize := ToSize;
  760. case ToSize of
  761. { signed integer registers }
  762. OS_8,
  763. OS_S8:
  764. oppostfix:=PF_B;
  765. OS_16,
  766. OS_S16:
  767. oppostfix:=PF_H;
  768. OS_32,
  769. OS_S32:
  770. oppostfix:=PF_None;
  771. else
  772. InternalError(200308295);
  773. end;
  774. if (ref.alignment in [1,2]) and (ref.alignment<tcgsize2size[tosize]) then
  775. begin
  776. if target_info.endian=endian_big then
  777. dir:=-1
  778. else
  779. dir:=1;
  780. case FromSize of
  781. OS_16,OS_S16:
  782. begin
  783. shifterop_reset(so);so.shiftmode:=SM_LSR;so.shiftimm:=8;
  784. tmpreg:=getintregister(list,OS_INT);
  785. usedtmpref:=ref;
  786. if target_info.endian=endian_big then
  787. inc(usedtmpref.offset,1);
  788. usedtmpref:=a_internal_load_reg_ref(list,OS_8,OS_8,reg,usedtmpref);
  789. inc(usedtmpref.offset,dir);
  790. list.concat(taicpu.op_reg_reg_shifterop(A_MOV,tmpreg,reg,so));
  791. a_internal_load_reg_ref(list,OS_8,OS_8,tmpreg,usedtmpref);
  792. end;
  793. OS_32,OS_S32:
  794. begin
  795. tmpreg:=getintregister(list,OS_INT);
  796. usedtmpref:=ref;
  797. shifterop_reset(so);so.shiftmode:=SM_LSR;
  798. if ref.alignment=2 then
  799. begin
  800. so.shiftimm:=16;
  801. if target_info.endian=endian_big then
  802. inc(usedtmpref.offset,2);
  803. usedtmpref:=a_internal_load_reg_ref(list,OS_16,OS_16,reg,usedtmpref);
  804. list.concat(taicpu.op_reg_reg_shifterop(A_MOV,tmpreg,reg,so));
  805. inc(usedtmpref.offset,dir*2);
  806. a_internal_load_reg_ref(list,OS_16,OS_16,tmpreg,usedtmpref);
  807. end
  808. else
  809. begin
  810. so.shiftimm:=8;
  811. if target_info.endian=endian_big then
  812. inc(usedtmpref.offset,3);
  813. usedtmpref:=a_internal_load_reg_ref(list,OS_8,OS_8,reg,usedtmpref);
  814. list.concat(taicpu.op_reg_reg_shifterop(A_MOV,tmpreg,reg,so));
  815. inc(usedtmpref.offset,dir);
  816. a_internal_load_reg_ref(list,OS_8,OS_8,tmpreg,usedtmpref);
  817. list.concat(taicpu.op_reg_reg_shifterop(A_MOV,tmpreg,tmpreg,so));
  818. inc(usedtmpref.offset,dir);
  819. a_internal_load_reg_ref(list,OS_8,OS_8,tmpreg,usedtmpref);
  820. list.concat(taicpu.op_reg_reg_shifterop(A_MOV,tmpreg,tmpreg,so));
  821. inc(usedtmpref.offset,dir);
  822. a_internal_load_reg_ref(list,OS_8,OS_8,tmpreg,usedtmpref);
  823. end;
  824. end
  825. else
  826. handle_load_store(list,A_STR,oppostfix,reg,ref);
  827. end;
  828. end
  829. else
  830. handle_load_store(list,A_STR,oppostfix,reg,ref);
  831. end;
  832. procedure tcgarm.a_load_ref_reg(list : TAsmList; fromsize, tosize : tcgsize;const Ref : treference;reg : tregister);
  833. var
  834. oppostfix:toppostfix;
  835. usedtmpref: treference;
  836. tmpreg,tmpreg2 : tregister;
  837. so : tshifterop;
  838. dir : integer;
  839. begin
  840. if (TCGSize2Size[FromSize] >= TCGSize2Size[ToSize]) then
  841. FromSize := ToSize;
  842. case FromSize of
  843. { signed integer registers }
  844. OS_8:
  845. oppostfix:=PF_B;
  846. OS_S8:
  847. oppostfix:=PF_SB;
  848. OS_16:
  849. oppostfix:=PF_H;
  850. OS_S16:
  851. oppostfix:=PF_SH;
  852. OS_32,
  853. OS_S32:
  854. oppostfix:=PF_None;
  855. else
  856. InternalError(200308297);
  857. end;
  858. if (ref.alignment in [1,2]) and (ref.alignment<tcgsize2size[fromsize]) then
  859. begin
  860. if target_info.endian=endian_big then
  861. dir:=-1
  862. else
  863. dir:=1;
  864. case FromSize of
  865. OS_16,OS_S16:
  866. begin
  867. { only complicated references need an extra loadaddr }
  868. if assigned(ref.symbol) or
  869. (ref.index<>NR_NO) or
  870. (ref.offset<-4095) or
  871. (ref.offset>4094) or
  872. { sometimes the compiler reused registers }
  873. (reg=ref.index) or
  874. (reg=ref.base) then
  875. begin
  876. tmpreg2:=getintregister(list,OS_INT);
  877. a_loadaddr_ref_reg(list,ref,tmpreg2);
  878. reference_reset_base(usedtmpref,tmpreg2,0);
  879. end
  880. else
  881. usedtmpref:=ref;
  882. if target_info.endian=endian_big then
  883. inc(usedtmpref.offset,1);
  884. shifterop_reset(so);so.shiftmode:=SM_LSL;so.shiftimm:=8;
  885. tmpreg:=getintregister(list,OS_INT);
  886. a_internal_load_ref_reg(list,OS_8,OS_8,usedtmpref,reg);
  887. inc(usedtmpref.offset,dir);
  888. if FromSize=OS_16 then
  889. a_internal_load_ref_reg(list,OS_8,OS_8,usedtmpref,tmpreg)
  890. else
  891. a_internal_load_ref_reg(list,OS_S8,OS_S8,usedtmpref,tmpreg);
  892. list.concat(taicpu.op_reg_reg_reg_shifterop(A_ORR,reg,reg,tmpreg,so));
  893. end;
  894. OS_32,OS_S32:
  895. begin
  896. tmpreg:=getintregister(list,OS_INT);
  897. { only complicated references need an extra loadaddr }
  898. if assigned(ref.symbol) or
  899. (ref.index<>NR_NO) or
  900. (ref.offset<-4095) or
  901. (ref.offset>4092) or
  902. { sometimes the compiler reused registers }
  903. (reg=ref.index) or
  904. (reg=ref.base) then
  905. begin
  906. tmpreg2:=getintregister(list,OS_INT);
  907. a_loadaddr_ref_reg(list,ref,tmpreg2);
  908. reference_reset_base(usedtmpref,tmpreg2,0);
  909. end
  910. else
  911. usedtmpref:=ref;
  912. shifterop_reset(so);so.shiftmode:=SM_LSL;
  913. if ref.alignment=2 then
  914. begin
  915. if target_info.endian=endian_big then
  916. inc(usedtmpref.offset,2);
  917. a_internal_load_ref_reg(list,OS_16,OS_16,usedtmpref,reg);
  918. inc(usedtmpref.offset,dir*2);
  919. a_internal_load_ref_reg(list,OS_16,OS_16,usedtmpref,tmpreg);
  920. so.shiftimm:=16;
  921. list.concat(taicpu.op_reg_reg_reg_shifterop(A_ORR,reg,reg,tmpreg,so));
  922. end
  923. else
  924. begin
  925. if target_info.endian=endian_big then
  926. inc(usedtmpref.offset,3);
  927. a_internal_load_ref_reg(list,OS_8,OS_8,usedtmpref,reg);
  928. inc(usedtmpref.offset,dir);
  929. a_internal_load_ref_reg(list,OS_8,OS_8,usedtmpref,tmpreg);
  930. so.shiftimm:=8;
  931. list.concat(taicpu.op_reg_reg_reg_shifterop(A_ORR,reg,reg,tmpreg,so));
  932. inc(usedtmpref.offset,dir);
  933. a_internal_load_ref_reg(list,OS_8,OS_8,usedtmpref,tmpreg);
  934. so.shiftimm:=16;
  935. list.concat(taicpu.op_reg_reg_reg_shifterop(A_ORR,reg,reg,tmpreg,so));
  936. inc(usedtmpref.offset,dir);
  937. a_internal_load_ref_reg(list,OS_8,OS_8,usedtmpref,tmpreg);
  938. so.shiftimm:=24;
  939. list.concat(taicpu.op_reg_reg_reg_shifterop(A_ORR,reg,reg,tmpreg,so));
  940. end;
  941. end
  942. else
  943. handle_load_store(list,A_LDR,oppostfix,reg,ref);
  944. end;
  945. end
  946. else
  947. handle_load_store(list,A_LDR,oppostfix,reg,ref);
  948. if (fromsize=OS_S8) and (tosize = OS_16) then
  949. a_load_reg_reg(list,OS_16,OS_32,reg,reg);
  950. end;
  951. function tcgarm.a_internal_load_reg_ref(list : TAsmList; fromsize, tosize: tcgsize; reg : tregister;const ref : treference):treference;
  952. var
  953. oppostfix:toppostfix;
  954. begin
  955. case ToSize of
  956. { signed integer registers }
  957. OS_8,
  958. OS_S8:
  959. oppostfix:=PF_B;
  960. OS_16,
  961. OS_S16:
  962. oppostfix:=PF_H;
  963. OS_32,
  964. OS_S32:
  965. oppostfix:=PF_None;
  966. else
  967. InternalError(2003082910);
  968. end;
  969. result:=handle_load_store(list,A_STR,oppostfix,reg,ref);
  970. end;
  971. function tcgarm.a_internal_load_ref_reg(list : TAsmList; fromsize, tosize : tcgsize;const Ref : treference;reg : tregister):treference;
  972. var
  973. oppostfix:toppostfix;
  974. begin
  975. case FromSize of
  976. { signed integer registers }
  977. OS_8:
  978. oppostfix:=PF_B;
  979. OS_S8:
  980. oppostfix:=PF_SB;
  981. OS_16:
  982. oppostfix:=PF_H;
  983. OS_S16:
  984. oppostfix:=PF_SH;
  985. OS_32,
  986. OS_S32:
  987. oppostfix:=PF_None;
  988. else
  989. InternalError(200308291);
  990. end;
  991. result:=handle_load_store(list,A_LDR,oppostfix,reg,ref);
  992. end;
  993. procedure tcgarm.a_load_reg_reg(list : TAsmList; fromsize, tosize : tcgsize;reg1,reg2 : tregister);
  994. var
  995. so : tshifterop;
  996. procedure do_shift(shiftmode : tshiftmode; shiftimm : byte; reg : tregister);
  997. begin
  998. so.shiftmode:=shiftmode;
  999. so.shiftimm:=shiftimm;
  1000. list.concat(taicpu.op_reg_reg_shifterop(A_MOV,reg2,reg,so));
  1001. end;
  1002. var
  1003. instr: taicpu;
  1004. conv_done: boolean;
  1005. begin
  1006. if (tcgsize2size[fromsize]>32) or (tcgsize2size[tosize]>32) or (fromsize=OS_NO) or (tosize=OS_NO) then
  1007. internalerror(2002090901);
  1008. conv_done:=false;
  1009. if tosize<>fromsize then
  1010. begin
  1011. shifterop_reset(so);
  1012. conv_done:=true;
  1013. if tcgsize2size[tosize]<=tcgsize2size[fromsize] then
  1014. fromsize:=tosize;
  1015. case fromsize of
  1016. OS_8:
  1017. list.concat(taicpu.op_reg_reg_const(A_AND,reg2,reg1,$ff));
  1018. OS_S8:
  1019. begin
  1020. do_shift(SM_LSL,24,reg1);
  1021. if tosize=OS_16 then
  1022. begin
  1023. do_shift(SM_ASR,8,reg2);
  1024. do_shift(SM_LSR,16,reg2);
  1025. end
  1026. else
  1027. do_shift(SM_ASR,24,reg2);
  1028. end;
  1029. OS_16:
  1030. begin
  1031. do_shift(SM_LSL,16,reg1);
  1032. do_shift(SM_LSR,16,reg2);
  1033. end;
  1034. OS_S16:
  1035. begin
  1036. do_shift(SM_LSL,16,reg1);
  1037. do_shift(SM_ASR,16,reg2)
  1038. end;
  1039. else
  1040. conv_done:=false;
  1041. end;
  1042. end;
  1043. if not conv_done and (reg1<>reg2) then
  1044. begin
  1045. { same size, only a register mov required }
  1046. instr:=taicpu.op_reg_reg(A_MOV,reg2,reg1);
  1047. list.Concat(instr);
  1048. { Notify the register allocator that we have written a move instruction so
  1049. it can try to eliminate it. }
  1050. add_move_instruction(instr);
  1051. end;
  1052. end;
  1053. procedure tcgarm.a_paramfpu_ref(list : TAsmList;size : tcgsize;const ref : treference;const paraloc : TCGPara);
  1054. var
  1055. href,href2 : treference;
  1056. hloc : pcgparalocation;
  1057. begin
  1058. href:=ref;
  1059. hloc:=paraloc.location;
  1060. while assigned(hloc) do
  1061. begin
  1062. case hloc^.loc of
  1063. LOC_FPUREGISTER,LOC_CFPUREGISTER:
  1064. a_loadfpu_ref_reg(list,size,size,ref,hloc^.register);
  1065. LOC_REGISTER :
  1066. case hloc^.size of
  1067. OS_F32:
  1068. a_load_ref_reg(list,OS_32,OS_32,href,hloc^.register);
  1069. OS_64,
  1070. OS_F64:
  1071. cg64.a_param64_ref(list,href,paraloc);
  1072. else
  1073. a_load_ref_reg(list,hloc^.size,hloc^.size,href,hloc^.register);
  1074. end;
  1075. LOC_REFERENCE :
  1076. begin
  1077. reference_reset_base(href2,hloc^.reference.index,hloc^.reference.offset);
  1078. { concatcopy should choose the best way to copy the data }
  1079. g_concatcopy(list,href,href2,tcgsize2size[size]);
  1080. end;
  1081. else
  1082. internalerror(200408241);
  1083. end;
  1084. inc(href.offset,tcgsize2size[hloc^.size]);
  1085. hloc:=hloc^.next;
  1086. end;
  1087. end;
  1088. procedure tcgarm.a_loadfpu_reg_reg(list: TAsmList; fromsize,tosize: tcgsize; reg1, reg2: tregister);
  1089. begin
  1090. list.concat(setoppostfix(taicpu.op_reg_reg(A_MVF,reg2,reg1),cgsize2fpuoppostfix[tosize]));
  1091. end;
  1092. procedure tcgarm.a_loadfpu_ref_reg(list: TAsmList; fromsize,tosize: tcgsize; const ref: treference; reg: tregister);
  1093. var
  1094. oppostfix:toppostfix;
  1095. begin
  1096. case fromsize of
  1097. OS_32,
  1098. OS_F32:
  1099. oppostfix:=PF_S;
  1100. OS_64,
  1101. OS_F64:
  1102. oppostfix:=PF_D;
  1103. OS_F80:
  1104. oppostfix:=PF_E;
  1105. else
  1106. InternalError(200309021);
  1107. end;
  1108. handle_load_store(list,A_LDF,oppostfix,reg,ref);
  1109. if fromsize<>tosize then
  1110. a_loadfpu_reg_reg(list,fromsize,tosize,reg,reg);
  1111. end;
  1112. procedure tcgarm.a_loadfpu_reg_ref(list: TAsmList; fromsize, tosize: tcgsize; reg: tregister; const ref: treference);
  1113. var
  1114. oppostfix:toppostfix;
  1115. begin
  1116. case tosize of
  1117. OS_F32:
  1118. oppostfix:=PF_S;
  1119. OS_F64:
  1120. oppostfix:=PF_D;
  1121. OS_F80:
  1122. oppostfix:=PF_E;
  1123. else
  1124. InternalError(200309022);
  1125. end;
  1126. handle_load_store(list,A_STF,oppostfix,reg,ref);
  1127. end;
  1128. { comparison operations }
  1129. procedure tcgarm.a_cmp_const_reg_label(list : TAsmList;size : tcgsize;cmp_op : topcmp;a : aint;reg : tregister;
  1130. l : tasmlabel);
  1131. var
  1132. tmpreg : tregister;
  1133. b : byte;
  1134. begin
  1135. if is_shifter_const(a,b) then
  1136. list.concat(taicpu.op_reg_const(A_CMP,reg,a))
  1137. { CMN reg,0 and CMN reg,$80000000 are different from CMP reg,$ffffffff
  1138. and CMP reg,$7fffffff regarding the flags according to the ARM manual }
  1139. else if (a<>$7fffffff) and (a<>-1) and is_shifter_const(-a,b) then
  1140. list.concat(taicpu.op_reg_const(A_CMN,reg,-a))
  1141. else
  1142. begin
  1143. tmpreg:=getintregister(list,size);
  1144. a_load_const_reg(list,size,a,tmpreg);
  1145. list.concat(taicpu.op_reg_reg(A_CMP,reg,tmpreg));
  1146. end;
  1147. a_jmp_cond(list,cmp_op,l);
  1148. end;
  1149. procedure tcgarm.a_cmp_reg_reg_label(list : TAsmList;size : tcgsize;cmp_op : topcmp;reg1,reg2 : tregister;l : tasmlabel);
  1150. begin
  1151. list.concat(taicpu.op_reg_reg(A_CMP,reg2,reg1));
  1152. a_jmp_cond(list,cmp_op,l);
  1153. end;
  1154. procedure tcgarm.a_jmp_name(list : TAsmList;const s : string);
  1155. var
  1156. ai : taicpu;
  1157. begin
  1158. ai:=taicpu.op_sym(A_B,current_asmdata.RefAsmSymbol(s));
  1159. ai.is_jmp:=true;
  1160. list.concat(ai);
  1161. end;
  1162. procedure tcgarm.a_jmp_always(list : TAsmList;l: tasmlabel);
  1163. var
  1164. ai : taicpu;
  1165. begin
  1166. ai:=taicpu.op_sym(A_B,l);
  1167. ai.is_jmp:=true;
  1168. list.concat(ai);
  1169. end;
  1170. procedure tcgarm.a_jmp_flags(list : TAsmList;const f : TResFlags;l: tasmlabel);
  1171. var
  1172. ai : taicpu;
  1173. begin
  1174. ai:=setcondition(taicpu.op_sym(A_B,l),flags_to_cond(f));
  1175. ai.is_jmp:=true;
  1176. list.concat(ai);
  1177. end;
  1178. procedure tcgarm.g_flags2reg(list: TAsmList; size: TCgSize; const f: TResFlags; reg: TRegister);
  1179. begin
  1180. list.concat(setcondition(taicpu.op_reg_const(A_MOV,reg,1),flags_to_cond(f)));
  1181. list.concat(setcondition(taicpu.op_reg_const(A_MOV,reg,0),inverse_cond(flags_to_cond(f))));
  1182. end;
  1183. procedure tcgarm.g_proc_entry(list : TAsmList;localsize : longint;nostackframe:boolean);
  1184. var
  1185. ref : treference;
  1186. shift : byte;
  1187. firstfloatreg,lastfloatreg,
  1188. r : byte;
  1189. regs : tcpuregisterset;
  1190. begin
  1191. LocalSize:=align(LocalSize,4);
  1192. if not(nostackframe) then
  1193. begin
  1194. firstfloatreg:=RS_NO;
  1195. { save floating point registers? }
  1196. for r:=RS_F0 to RS_F7 do
  1197. if r in rg[R_FPUREGISTER].used_in_proc-paramanager.get_volatile_registers_fpu(pocall_stdcall) then
  1198. begin
  1199. if firstfloatreg=RS_NO then
  1200. firstfloatreg:=r;
  1201. lastfloatreg:=r;
  1202. end;
  1203. a_reg_alloc(list,NR_STACK_POINTER_REG);
  1204. if current_procinfo.framepointer<>NR_STACK_POINTER_REG then
  1205. begin
  1206. a_reg_alloc(list,NR_FRAME_POINTER_REG);
  1207. a_reg_alloc(list,NR_R12);
  1208. list.concat(taicpu.op_reg_reg(A_MOV,NR_R12,NR_STACK_POINTER_REG));
  1209. end;
  1210. { save int registers }
  1211. reference_reset(ref);
  1212. ref.index:=NR_STACK_POINTER_REG;
  1213. ref.addressmode:=AM_PREINDEXED;
  1214. regs:=rg[R_INTREGISTER].used_in_proc-paramanager.get_volatile_registers_int(pocall_stdcall);
  1215. if current_procinfo.framepointer<>NR_STACK_POINTER_REG then
  1216. regs:=regs+[RS_R11,RS_R12,RS_R14,RS_R15]
  1217. else
  1218. if (regs<>[]) or (pi_do_call in current_procinfo.flags) then
  1219. include(regs,RS_R14);
  1220. if regs<>[] then
  1221. list.concat(setoppostfix(taicpu.op_ref_regset(A_STM,ref,regs),PF_FD));
  1222. if current_procinfo.framepointer<>NR_STACK_POINTER_REG then
  1223. list.concat(taicpu.op_reg_reg_const(A_SUB,NR_FRAME_POINTER_REG,NR_R12,4));
  1224. (* allocate necessary stack size
  1225. not necessary according to Yury Sidorov
  1226. { don't use a_op_const_reg_reg here because we don't allow register allocations
  1227. in the entry/exit code }
  1228. if (target_info.system in [system_arm_wince]) and
  1229. (localsize>=winstackpagesize) then
  1230. begin
  1231. if localsize div winstackpagesize<=5 then
  1232. begin
  1233. if is_shifter_const(localsize,shift) then
  1234. list.concat(Taicpu.op_reg_reg_const(A_SUB,NR_STACK_POINTER_REG,NR_STACK_POINTER_REG,localsize))
  1235. else
  1236. begin
  1237. a_load_const_reg(list,OS_ADDR,localsize,NR_R12);
  1238. list.concat(taicpu.op_reg_reg_reg(A_SUB,NR_STACK_POINTER_REG,NR_STACK_POINTER_REG,NR_R12));
  1239. end;
  1240. for i:=1 to localsize div winstackpagesize do
  1241. begin
  1242. if localsize-i*winstackpagesize<4096 then
  1243. reference_reset_base(href,NR_STACK_POINTER_REG,-(localsize-i*winstackpagesize))
  1244. else
  1245. begin
  1246. a_load_const_reg(list,OS_ADDR,-(localsize-i*winstackpagesize),NR_R12);
  1247. reference_reset_base(href,NR_STACK_POINTER_REG,0);
  1248. href.index:=NR_R12;
  1249. end;
  1250. { the data stored doesn't matter }
  1251. list.concat(Taicpu.op_reg_ref(A_STR,NR_R0,href));
  1252. end;
  1253. a_reg_dealloc(list,NR_R12);
  1254. reference_reset_base(href,NR_STACK_POINTER_REG,0);
  1255. { the data stored doesn't matter }
  1256. list.concat(Taicpu.op_reg_ref(A_STR,NR_R0,href));
  1257. end
  1258. else
  1259. begin
  1260. current_asmdata.getjumplabel(again);
  1261. list.concat(Taicpu.op_reg_const(A_MOV,NR_R12,localsize div winstackpagesize));
  1262. a_label(list,again);
  1263. { always shifterop }
  1264. list.concat(Taicpu.op_reg_reg_const(A_SUB,NR_STACK_POINTER_REG,NR_STACK_POINTER_REG,winstackpagesize));
  1265. reference_reset_base(href,NR_STACK_POINTER_REG,0);
  1266. { the data stored doesn't matter }
  1267. list.concat(Taicpu.op_reg_ref(A_STR,NR_R0,href));
  1268. list.concat(Taicpu.op_reg_reg_const(A_SUB,NR_R12,NR_R12,1));
  1269. a_jmp_cond(list,OC_NE,again);
  1270. if is_shifter_const(localsize mod winstackpagesize,shift) then
  1271. list.concat(Taicpu.op_reg_reg_const(A_SUB,NR_STACK_POINTER_REG,NR_STACK_POINTER_REG,localsize mod winstackpagesize))
  1272. else
  1273. begin
  1274. a_load_const_reg(list,OS_ADDR,localsize mod winstackpagesize,NR_R12);
  1275. list.concat(taicpu.op_reg_reg_reg(A_SUB,NR_STACK_POINTER_REG,NR_STACK_POINTER_REG,NR_R12));
  1276. end;
  1277. a_reg_dealloc(list,NR_R12);
  1278. reference_reset_base(href,NR_STACK_POINTER_REG,0);
  1279. { the data stored doesn't matter }
  1280. list.concat(Taicpu.op_reg_ref(A_STR,NR_R0,href));
  1281. end
  1282. end
  1283. else
  1284. *)
  1285. if LocalSize<>0 then
  1286. if not(is_shifter_const(localsize,shift)) then
  1287. begin
  1288. if current_procinfo.framepointer=NR_STACK_POINTER_REG then
  1289. a_reg_alloc(list,NR_R12);
  1290. a_load_const_reg(list,OS_ADDR,LocalSize,NR_R12);
  1291. list.concat(taicpu.op_reg_reg_reg(A_SUB,NR_STACK_POINTER_REG,NR_STACK_POINTER_REG,NR_R12));
  1292. a_reg_dealloc(list,NR_R12);
  1293. end
  1294. else
  1295. begin
  1296. a_reg_dealloc(list,NR_R12);
  1297. list.concat(taicpu.op_reg_reg_const(A_SUB,NR_STACK_POINTER_REG,NR_STACK_POINTER_REG,LocalSize));
  1298. end;
  1299. if firstfloatreg<>RS_NO then
  1300. begin
  1301. reference_reset(ref);
  1302. if tg.direction*tarmprocinfo(current_procinfo).floatregstart>=1023 then
  1303. begin
  1304. a_load_const_reg(list,OS_ADDR,-tarmprocinfo(current_procinfo).floatregstart,NR_R12);
  1305. list.concat(taicpu.op_reg_reg_reg(A_SUB,NR_R12,current_procinfo.framepointer,NR_R12));
  1306. ref.base:=NR_R12;
  1307. end
  1308. else
  1309. begin
  1310. ref.base:=current_procinfo.framepointer;
  1311. ref.offset:=tarmprocinfo(current_procinfo).floatregstart;
  1312. end;
  1313. list.concat(taicpu.op_reg_const_ref(A_SFM,newreg(R_FPUREGISTER,firstfloatreg,R_SUBWHOLE),
  1314. lastfloatreg-firstfloatreg+1,ref));
  1315. end;
  1316. end;
  1317. end;
  1318. procedure tcgarm.g_proc_exit(list : TAsmList;parasize : longint;nostackframe:boolean);
  1319. var
  1320. ref : treference;
  1321. firstfloatreg,lastfloatreg,
  1322. r : byte;
  1323. shift : byte;
  1324. regs : tcpuregisterset;
  1325. LocalSize : longint;
  1326. begin
  1327. if not(nostackframe) then
  1328. begin
  1329. { restore floating point register }
  1330. firstfloatreg:=RS_NO;
  1331. { save floating point registers? }
  1332. for r:=RS_F0 to RS_F7 do
  1333. if r in rg[R_FPUREGISTER].used_in_proc-paramanager.get_volatile_registers_fpu(pocall_stdcall) then
  1334. begin
  1335. if firstfloatreg=RS_NO then
  1336. firstfloatreg:=r;
  1337. lastfloatreg:=r;
  1338. end;
  1339. if firstfloatreg<>RS_NO then
  1340. begin
  1341. reference_reset(ref);
  1342. if tg.direction*tarmprocinfo(current_procinfo).floatregstart>=1023 then
  1343. begin
  1344. a_load_const_reg(list,OS_ADDR,-tarmprocinfo(current_procinfo).floatregstart,NR_R12);
  1345. list.concat(taicpu.op_reg_reg_reg(A_SUB,NR_R12,current_procinfo.framepointer,NR_R12));
  1346. ref.base:=NR_R12;
  1347. end
  1348. else
  1349. begin
  1350. ref.base:=current_procinfo.framepointer;
  1351. ref.offset:=tarmprocinfo(current_procinfo).floatregstart;
  1352. end;
  1353. list.concat(taicpu.op_reg_const_ref(A_LFM,newreg(R_FPUREGISTER,firstfloatreg,R_SUBWHOLE),
  1354. lastfloatreg-firstfloatreg+1,ref));
  1355. end;
  1356. if (current_procinfo.framepointer=NR_STACK_POINTER_REG) then
  1357. begin
  1358. LocalSize:=current_procinfo.calc_stackframe_size;
  1359. if LocalSize<>0 then
  1360. if not(is_shifter_const(LocalSize,shift)) then
  1361. begin
  1362. a_reg_alloc(list,NR_R12);
  1363. a_load_const_reg(list,OS_ADDR,LocalSize,NR_R12);
  1364. list.concat(taicpu.op_reg_reg_reg(A_ADD,NR_STACK_POINTER_REG,NR_STACK_POINTER_REG,NR_R12));
  1365. a_reg_dealloc(list,NR_R12);
  1366. end
  1367. else
  1368. begin
  1369. list.concat(taicpu.op_reg_reg_const(A_ADD,NR_STACK_POINTER_REG,NR_STACK_POINTER_REG,LocalSize));
  1370. end;
  1371. regs:=rg[R_INTREGISTER].used_in_proc-paramanager.get_volatile_registers_int(pocall_stdcall);
  1372. if (pi_do_call in current_procinfo.flags) or (regs<>[]) then
  1373. begin
  1374. exclude(regs,RS_R14);
  1375. include(regs,RS_R15);
  1376. end;
  1377. if regs=[] then
  1378. list.concat(taicpu.op_reg_reg(A_MOV,NR_R15,NR_R14))
  1379. else
  1380. begin
  1381. reference_reset(ref);
  1382. ref.index:=NR_STACK_POINTER_REG;
  1383. ref.addressmode:=AM_PREINDEXED;
  1384. list.concat(setoppostfix(taicpu.op_ref_regset(A_LDM,ref,regs),PF_FD));
  1385. end;
  1386. end
  1387. else
  1388. begin
  1389. { restore int registers and return }
  1390. reference_reset(ref);
  1391. ref.index:=NR_FRAME_POINTER_REG;
  1392. 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));
  1393. end;
  1394. end
  1395. else
  1396. list.concat(taicpu.op_reg_reg(A_MOV,NR_PC,NR_R14));
  1397. end;
  1398. procedure tcgarm.a_loadaddr_ref_reg(list : TAsmList;const ref : treference;r : tregister);
  1399. var
  1400. b : byte;
  1401. tmpref : treference;
  1402. instr : taicpu;
  1403. begin
  1404. if ref.addressmode<>AM_OFFSET then
  1405. internalerror(200309071);
  1406. tmpref:=ref;
  1407. { Be sure to have a base register }
  1408. if (tmpref.base=NR_NO) then
  1409. begin
  1410. if tmpref.shiftmode<>SM_None then
  1411. internalerror(200308294);
  1412. if tmpref.signindex<0 then
  1413. internalerror(200312023);
  1414. tmpref.base:=tmpref.index;
  1415. tmpref.index:=NR_NO;
  1416. end;
  1417. if assigned(tmpref.symbol) or
  1418. not((is_shifter_const(tmpref.offset,b)) or
  1419. (is_shifter_const(-tmpref.offset,b))
  1420. ) then
  1421. fixref(list,tmpref);
  1422. { expect a base here if there is an index }
  1423. if (tmpref.base=NR_NO) and (tmpref.index<>NR_NO) then
  1424. internalerror(200312022);
  1425. if tmpref.index<>NR_NO then
  1426. begin
  1427. if tmpref.shiftmode<>SM_None then
  1428. internalerror(200312021);
  1429. if tmpref.signindex<0 then
  1430. a_op_reg_reg_reg(list,OP_SUB,OS_ADDR,tmpref.base,tmpref.index,r)
  1431. else
  1432. a_op_reg_reg_reg(list,OP_ADD,OS_ADDR,tmpref.base,tmpref.index,r);
  1433. if tmpref.offset<>0 then
  1434. a_op_const_reg_reg(list,OP_ADD,OS_ADDR,tmpref.offset,r,r);
  1435. end
  1436. else
  1437. begin
  1438. if tmpref.base=NR_NO then
  1439. a_load_const_reg(list,OS_ADDR,tmpref.offset,r)
  1440. else
  1441. if tmpref.offset<>0 then
  1442. a_op_const_reg_reg(list,OP_ADD,OS_ADDR,tmpref.offset,tmpref.base,r)
  1443. else
  1444. begin
  1445. instr:=taicpu.op_reg_reg(A_MOV,r,tmpref.base);
  1446. list.concat(instr);
  1447. add_move_instruction(instr);
  1448. end;
  1449. end;
  1450. end;
  1451. procedure tcgarm.fixref(list : TAsmList;var ref : treference);
  1452. var
  1453. tmpreg : tregister;
  1454. tmpref : treference;
  1455. l : tasmlabel;
  1456. begin
  1457. { absolute symbols can't be handled directly, we've to store the symbol reference
  1458. in the text segment and access it pc relative
  1459. For now, we assume that references where base or index equals to PC are already
  1460. relative, all other references are assumed to be absolute and thus they need
  1461. to be handled extra.
  1462. A proper solution would be to change refoptions to a set and store the information
  1463. if the symbol is absolute or relative there.
  1464. }
  1465. { create consts entry }
  1466. reference_reset(tmpref);
  1467. current_asmdata.getjumplabel(l);
  1468. cg.a_label(current_procinfo.aktlocaldata,l);
  1469. tmpref.symboldata:=current_procinfo.aktlocaldata.last;
  1470. if assigned(ref.symbol) then
  1471. current_procinfo.aktlocaldata.concat(tai_const.create_sym_offset(ref.symbol,ref.offset))
  1472. else
  1473. current_procinfo.aktlocaldata.concat(tai_const.Create_32bit(ref.offset));
  1474. { load consts entry }
  1475. tmpreg:=getintregister(list,OS_INT);
  1476. tmpref.symbol:=l;
  1477. tmpref.base:=NR_PC;
  1478. list.concat(taicpu.op_reg_ref(A_LDR,tmpreg,tmpref));
  1479. if (ref.base<>NR_NO) then
  1480. begin
  1481. if ref.index<>NR_NO then
  1482. begin
  1483. list.concat(taicpu.op_reg_reg_reg(A_ADD,tmpreg,ref.base,tmpreg));
  1484. ref.base:=tmpreg;
  1485. end
  1486. else
  1487. if ref.base<>NR_PC then
  1488. begin
  1489. ref.index:=tmpreg;
  1490. ref.shiftimm:=0;
  1491. ref.signindex:=1;
  1492. ref.shiftmode:=SM_None;
  1493. end
  1494. else
  1495. ref.base:=tmpreg;
  1496. end
  1497. else
  1498. ref.base:=tmpreg;
  1499. ref.offset:=0;
  1500. ref.symbol:=nil;
  1501. end;
  1502. procedure tcgarm.g_concatcopy_move(list : TAsmList;const source,dest : treference;len : aint);
  1503. var
  1504. paraloc1,paraloc2,paraloc3 : TCGPara;
  1505. begin
  1506. paraloc1.init;
  1507. paraloc2.init;
  1508. paraloc3.init;
  1509. paramanager.getintparaloc(pocall_default,1,paraloc1);
  1510. paramanager.getintparaloc(pocall_default,2,paraloc2);
  1511. paramanager.getintparaloc(pocall_default,3,paraloc3);
  1512. paramanager.allocparaloc(list,paraloc3);
  1513. a_param_const(list,OS_INT,len,paraloc3);
  1514. paramanager.allocparaloc(list,paraloc2);
  1515. a_paramaddr_ref(list,dest,paraloc2);
  1516. paramanager.allocparaloc(list,paraloc2);
  1517. a_paramaddr_ref(list,source,paraloc1);
  1518. paramanager.freeparaloc(list,paraloc3);
  1519. paramanager.freeparaloc(list,paraloc2);
  1520. paramanager.freeparaloc(list,paraloc1);
  1521. alloccpuregisters(list,R_INTREGISTER,paramanager.get_volatile_registers_int(pocall_default));
  1522. alloccpuregisters(list,R_FPUREGISTER,paramanager.get_volatile_registers_fpu(pocall_default));
  1523. a_call_name(list,'FPC_MOVE');
  1524. dealloccpuregisters(list,R_FPUREGISTER,paramanager.get_volatile_registers_fpu(pocall_default));
  1525. dealloccpuregisters(list,R_INTREGISTER,paramanager.get_volatile_registers_int(pocall_default));
  1526. paraloc3.done;
  1527. paraloc2.done;
  1528. paraloc1.done;
  1529. end;
  1530. procedure tcgarm.g_concatcopy_internal(list : TAsmList;const source,dest : treference;len : aint;aligned : boolean);
  1531. const
  1532. 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}
  1533. var
  1534. srcref,dstref,usedtmpref,usedtmpref2:treference;
  1535. srcreg,destreg,countreg,r,tmpreg:tregister;
  1536. helpsize:aint;
  1537. copysize:byte;
  1538. cgsize:Tcgsize;
  1539. tmpregisters:array[1..maxtmpreg] of tregister;
  1540. tmpregi,tmpregi2:byte;
  1541. { will never be called with count<=4 }
  1542. procedure genloop(count : aword;size : byte);
  1543. const
  1544. size2opsize : array[1..4] of tcgsize = (OS_8,OS_16,OS_NO,OS_32);
  1545. var
  1546. l : tasmlabel;
  1547. begin
  1548. current_asmdata.getjumplabel(l);
  1549. if count<size then size:=1;
  1550. a_load_const_reg(list,OS_INT,count div size,countreg);
  1551. cg.a_label(list,l);
  1552. srcref.addressmode:=AM_POSTINDEXED;
  1553. dstref.addressmode:=AM_POSTINDEXED;
  1554. srcref.offset:=size;
  1555. dstref.offset:=size;
  1556. r:=getintregister(list,size2opsize[size]);
  1557. a_load_ref_reg(list,size2opsize[size],size2opsize[size],srcref,r);
  1558. list.concat(setoppostfix(taicpu.op_reg_reg_const(A_SUB,countreg,countreg,1),PF_S));
  1559. a_load_reg_ref(list,size2opsize[size],size2opsize[size],r,dstref);
  1560. a_jmp_flags(list,F_NE,l);
  1561. srcref.offset:=1;
  1562. dstref.offset:=1;
  1563. case count mod size of
  1564. 1:
  1565. begin
  1566. a_load_ref_reg(list,OS_8,OS_8,srcref,r);
  1567. a_load_reg_ref(list,OS_8,OS_8,r,dstref);
  1568. end;
  1569. 2:
  1570. if aligned then
  1571. begin
  1572. a_load_ref_reg(list,OS_16,OS_16,srcref,r);
  1573. a_load_reg_ref(list,OS_16,OS_16,r,dstref);
  1574. end
  1575. else
  1576. begin
  1577. a_load_ref_reg(list,OS_8,OS_8,srcref,r);
  1578. a_load_reg_ref(list,OS_8,OS_8,r,dstref);
  1579. a_load_ref_reg(list,OS_8,OS_8,srcref,r);
  1580. a_load_reg_ref(list,OS_8,OS_8,r,dstref);
  1581. end;
  1582. 3:
  1583. if aligned then
  1584. begin
  1585. srcref.offset:=2;
  1586. dstref.offset:=2;
  1587. a_load_ref_reg(list,OS_16,OS_16,srcref,r);
  1588. a_load_reg_ref(list,OS_16,OS_16,r,dstref);
  1589. a_load_ref_reg(list,OS_8,OS_8,srcref,r);
  1590. a_load_reg_ref(list,OS_8,OS_8,r,dstref);
  1591. end
  1592. else
  1593. begin
  1594. a_load_ref_reg(list,OS_8,OS_8,srcref,r);
  1595. a_load_reg_ref(list,OS_8,OS_8,r,dstref);
  1596. a_load_ref_reg(list,OS_8,OS_8,srcref,r);
  1597. a_load_reg_ref(list,OS_8,OS_8,r,dstref);
  1598. a_load_ref_reg(list,OS_8,OS_8,srcref,r);
  1599. a_load_reg_ref(list,OS_8,OS_8,r,dstref);
  1600. end;
  1601. end;
  1602. { keep the registers alive }
  1603. list.concat(taicpu.op_reg_reg(A_MOV,countreg,countreg));
  1604. list.concat(taicpu.op_reg_reg(A_MOV,srcreg,srcreg));
  1605. list.concat(taicpu.op_reg_reg(A_MOV,destreg,destreg));
  1606. end;
  1607. begin
  1608. if len=0 then
  1609. exit;
  1610. helpsize:=12+maxtmpreg*4;//52 with maxtmpreg=10
  1611. dstref:=dest;
  1612. srcref:=source;
  1613. if cs_opt_size in current_settings.optimizerswitches then
  1614. helpsize:=8;
  1615. if (len<=helpsize) and aligned then
  1616. begin
  1617. tmpregi:=0;
  1618. srcreg:=getintregister(list,OS_ADDR);
  1619. { explicit pc relative addressing, could be
  1620. e.g. a floating point constant }
  1621. if source.base=NR_PC then
  1622. begin
  1623. { ... then we don't need a loadaddr }
  1624. srcref:=source;
  1625. end
  1626. else
  1627. begin
  1628. a_loadaddr_ref_reg(list,source,srcreg);
  1629. reference_reset_base(srcref,srcreg,0);
  1630. end;
  1631. while (len div 4 <> 0) and (tmpregi<maxtmpreg) do
  1632. begin
  1633. inc(tmpregi);
  1634. tmpregisters[tmpregi]:=getintregister(list,OS_32);
  1635. a_load_ref_reg(list,OS_32,OS_32,srcref,tmpregisters[tmpregi]);
  1636. inc(srcref.offset,4);
  1637. dec(len,4);
  1638. end;
  1639. destreg:=getintregister(list,OS_ADDR);
  1640. a_loadaddr_ref_reg(list,dest,destreg);
  1641. reference_reset_base(dstref,destreg,0);
  1642. tmpregi2:=1;
  1643. while (tmpregi2<=tmpregi) do
  1644. begin
  1645. a_load_reg_ref(list,OS_32,OS_32,tmpregisters[tmpregi2],dstref);
  1646. inc(dstref.offset,4);
  1647. inc(tmpregi2);
  1648. end;
  1649. copysize:=4;
  1650. cgsize:=OS_32;
  1651. while len<>0 do
  1652. begin
  1653. if len<2 then
  1654. begin
  1655. copysize:=1;
  1656. cgsize:=OS_8;
  1657. end
  1658. else if len<4 then
  1659. begin
  1660. copysize:=2;
  1661. cgsize:=OS_16;
  1662. end;
  1663. dec(len,copysize);
  1664. r:=getintregister(list,cgsize);
  1665. a_load_ref_reg(list,cgsize,cgsize,srcref,r);
  1666. a_load_reg_ref(list,cgsize,cgsize,r,dstref);
  1667. inc(srcref.offset,copysize);
  1668. inc(dstref.offset,copysize);
  1669. end;{end of while}
  1670. end
  1671. else
  1672. begin
  1673. cgsize:=OS_32;
  1674. if (len<=4) then{len<=4 and not aligned}
  1675. begin
  1676. r:=getintregister(list,cgsize);
  1677. usedtmpref:=a_internal_load_ref_reg(list,OS_8,OS_8,srcref,r);
  1678. if Len=1 then
  1679. a_load_reg_ref(list,OS_8,OS_8,r,dstref)
  1680. else
  1681. begin
  1682. tmpreg:=getintregister(list,cgsize);
  1683. usedtmpref2:=a_internal_load_reg_ref(list,OS_8,OS_8,r,dstref);
  1684. inc(usedtmpref.offset,1);
  1685. a_load_ref_reg(list,OS_8,OS_8,usedtmpref,tmpreg);
  1686. inc(usedtmpref2.offset,1);
  1687. a_load_reg_ref(list,OS_8,OS_8,tmpreg,usedtmpref2);
  1688. if len>2 then
  1689. begin
  1690. inc(usedtmpref.offset,1);
  1691. a_load_ref_reg(list,OS_8,OS_8,usedtmpref,tmpreg);
  1692. inc(usedtmpref2.offset,1);
  1693. a_load_reg_ref(list,OS_8,OS_8,tmpreg,usedtmpref2);
  1694. if len>3 then
  1695. begin
  1696. inc(usedtmpref.offset,1);
  1697. a_load_ref_reg(list,OS_8,OS_8,usedtmpref,tmpreg);
  1698. inc(usedtmpref2.offset,1);
  1699. a_load_reg_ref(list,OS_8,OS_8,tmpreg,usedtmpref2);
  1700. end;
  1701. end;
  1702. end;
  1703. end{end of if len<=4}
  1704. else
  1705. begin{unaligned & 4<len<helpsize **or** aligned/unaligned & len>helpsize}
  1706. destreg:=getintregister(list,OS_ADDR);
  1707. a_loadaddr_ref_reg(list,dest,destreg);
  1708. reference_reset_base(dstref,destreg,0);
  1709. srcreg:=getintregister(list,OS_ADDR);
  1710. a_loadaddr_ref_reg(list,source,srcreg);
  1711. reference_reset_base(srcref,srcreg,0);
  1712. countreg:=getintregister(list,OS_32);
  1713. // if cs_opt_size in current_settings.optimizerswitches then
  1714. { roozbeh : it seems loading 1 byte is faster becouse of caching/fetching(?) }
  1715. {if aligned then
  1716. genloop(len,4)
  1717. else}
  1718. genloop(len,1);
  1719. end;
  1720. end;
  1721. end;
  1722. procedure tcgarm.g_concatcopy_unaligned(list : TAsmList;const source,dest : treference;len : aint);
  1723. begin
  1724. g_concatcopy_internal(list,source,dest,len,false);
  1725. end;
  1726. procedure tcgarm.g_concatcopy(list : TAsmList;const source,dest : treference;len : aint);
  1727. begin
  1728. if (source.alignment in [1..3]) or
  1729. (dest.alignment in [1..3]) then
  1730. g_concatcopy_internal(list,source,dest,len,false)
  1731. else
  1732. g_concatcopy_internal(list,source,dest,len,true);
  1733. end;
  1734. procedure tcgarm.g_overflowCheck(list : TAsmList;const l : tlocation;def : tdef);
  1735. var
  1736. ovloc : tlocation;
  1737. begin
  1738. ovloc.loc:=LOC_VOID;
  1739. g_overflowCheck_loc(list,l,def,ovloc);
  1740. end;
  1741. procedure tcgarm.g_overflowCheck_loc(List:TAsmList;const Loc:TLocation;def:TDef;ovloc : tlocation);
  1742. var
  1743. hl : tasmlabel;
  1744. ai:TAiCpu;
  1745. hflags : tresflags;
  1746. begin
  1747. if not(cs_check_overflow in current_settings.localswitches) then
  1748. exit;
  1749. current_asmdata.getjumplabel(hl);
  1750. case ovloc.loc of
  1751. LOC_VOID:
  1752. begin
  1753. ai:=taicpu.op_sym(A_B,hl);
  1754. ai.is_jmp:=true;
  1755. if not((def.typ=pointerdef) or
  1756. ((def.typ=orddef) and
  1757. (torddef(def).ordtype in [u64bit,u16bit,u32bit,u8bit,uchar,pasbool]))) then
  1758. ai.SetCondition(C_VC)
  1759. else
  1760. if TAiCpu(List.Last).opcode in [A_RSB,A_RSC,A_SBC,A_SUB] then
  1761. ai.SetCondition(C_CS)
  1762. else
  1763. ai.SetCondition(C_CC);
  1764. list.concat(ai);
  1765. end;
  1766. LOC_FLAGS:
  1767. begin
  1768. hflags:=ovloc.resflags;
  1769. inverse_flags(hflags);
  1770. cg.a_jmp_flags(list,hflags,hl);
  1771. end;
  1772. else
  1773. internalerror(200409281);
  1774. end;
  1775. a_call_name(list,'FPC_OVERFLOW');
  1776. a_label(list,hl);
  1777. end;
  1778. procedure tcgarm.g_save_registers(list : TAsmList);
  1779. begin
  1780. { this work is done in g_proc_entry }
  1781. end;
  1782. procedure tcgarm.g_restore_registers(list : TAsmList);
  1783. begin
  1784. { this work is done in g_proc_exit }
  1785. end;
  1786. procedure tcgarm.a_jmp_cond(list : TAsmList;cond : TOpCmp;l: tasmlabel);
  1787. var
  1788. ai : taicpu;
  1789. begin
  1790. ai:=Taicpu.Op_sym(A_B,l);
  1791. ai.SetCondition(OpCmp2AsmCond[cond]);
  1792. ai.is_jmp:=true;
  1793. list.concat(ai);
  1794. end;
  1795. procedure tcgarm.g_adjust_self_value(list:TAsmList;procdef: tprocdef;ioffset: aint);
  1796. var
  1797. hsym : tsym;
  1798. href : treference;
  1799. paraloc : Pcgparalocation;
  1800. shift : byte;
  1801. begin
  1802. { calculate the parameter info for the procdef }
  1803. if not procdef.has_paraloc_info then
  1804. begin
  1805. procdef.requiredargarea:=paramanager.create_paraloc_info(procdef,callerside);
  1806. procdef.has_paraloc_info:=true;
  1807. end;
  1808. hsym:=tsym(procdef.parast.Find('self'));
  1809. if not(assigned(hsym) and
  1810. (hsym.typ=paravarsym)) then
  1811. internalerror(200305251);
  1812. paraloc:=tparavarsym(hsym).paraloc[callerside].location;
  1813. while paraloc<>nil do
  1814. with paraloc^ do
  1815. begin
  1816. case loc of
  1817. LOC_REGISTER:
  1818. begin
  1819. if is_shifter_const(ioffset,shift) then
  1820. a_op_const_reg(list,OP_SUB,size,ioffset,register)
  1821. else
  1822. begin
  1823. a_load_const_reg(list,OS_ADDR,ioffset,NR_R12);
  1824. a_op_reg_reg(list,OP_SUB,size,NR_R12,register);
  1825. end;
  1826. end;
  1827. LOC_REFERENCE:
  1828. begin
  1829. { offset in the wrapper needs to be adjusted for the stored
  1830. return address }
  1831. reference_reset_base(href,reference.index,reference.offset+sizeof(aint));
  1832. if is_shifter_const(ioffset,shift) then
  1833. a_op_const_ref(list,OP_SUB,size,ioffset,href)
  1834. else
  1835. begin
  1836. a_load_const_reg(list,OS_ADDR,ioffset,NR_R12);
  1837. a_op_reg_ref(list,OP_SUB,size,NR_R12,href);
  1838. end;
  1839. end
  1840. else
  1841. internalerror(200309189);
  1842. end;
  1843. paraloc:=next;
  1844. end;
  1845. end;
  1846. procedure tcgarm.g_stackpointer_alloc(list: TAsmList; size: longint);
  1847. begin
  1848. internalerror(200807237);
  1849. end;
  1850. procedure tcgarm.g_intf_wrapper(list: TAsmList; procdef: tprocdef; const labelname: string; ioffset: longint);
  1851. procedure loadvmttor12;
  1852. var
  1853. href : treference;
  1854. begin
  1855. reference_reset_base(href,NR_R0,0);
  1856. cg.a_load_ref_reg(list,OS_ADDR,OS_ADDR,href,NR_R12);
  1857. end;
  1858. procedure op_onr12methodaddr;
  1859. var
  1860. href : treference;
  1861. begin
  1862. if (procdef.extnumber=$ffff) then
  1863. Internalerror(200006139);
  1864. { call/jmp vmtoffs(%eax) ; method offs }
  1865. reference_reset_base(href,NR_R12,procdef._class.vmtmethodoffset(procdef.extnumber));
  1866. cg.a_load_ref_reg(list,OS_ADDR,OS_ADDR,href,NR_R12);
  1867. list.concat(taicpu.op_reg_reg(A_MOV,NR_PC,NR_R12));
  1868. end;
  1869. var
  1870. make_global : boolean;
  1871. begin
  1872. if not(procdef.proctypeoption in [potype_function,potype_procedure]) then
  1873. Internalerror(200006137);
  1874. if not assigned(procdef._class) or
  1875. (procdef.procoptions*[po_classmethod, po_staticmethod,
  1876. po_methodpointer, po_interrupt, po_iocheck]<>[]) then
  1877. Internalerror(200006138);
  1878. if procdef.owner.symtabletype<>ObjectSymtable then
  1879. Internalerror(200109191);
  1880. make_global:=false;
  1881. if (not current_module.is_unit) or
  1882. create_smartlink or
  1883. (procdef.owner.defowner.owner.symtabletype=globalsymtable) then
  1884. make_global:=true;
  1885. if make_global then
  1886. list.concat(Tai_symbol.Createname_global(labelname,AT_FUNCTION,0))
  1887. else
  1888. list.concat(Tai_symbol.Createname(labelname,AT_FUNCTION,0));
  1889. { the wrapper might need aktlocaldata for the additional data to
  1890. load the constant }
  1891. current_procinfo:=cprocinfo.create(nil);
  1892. { set param1 interface to self }
  1893. g_adjust_self_value(list,procdef,ioffset);
  1894. { case 4 }
  1895. if po_virtualmethod in procdef.procoptions then
  1896. begin
  1897. loadvmttor12;
  1898. op_onr12methodaddr;
  1899. end
  1900. { case 0 }
  1901. else
  1902. list.concat(taicpu.op_sym(A_B,current_asmdata.RefAsmSymbol(procdef.mangledname)));
  1903. list.concatlist(current_procinfo.aktlocaldata);
  1904. current_procinfo.Free;
  1905. current_procinfo:=nil;
  1906. list.concat(Tai_symbol_end.Createname(labelname));
  1907. end;
  1908. procedure tcgarm.maybeadjustresult(list: TAsmList; op: TOpCg; size: tcgsize; dst: tregister);
  1909. const
  1910. overflowops = [OP_MUL,OP_SHL,OP_ADD,OP_SUB,OP_NOT,OP_NEG];
  1911. begin
  1912. if (op in overflowops) and
  1913. (size in [OS_8,OS_S8,OS_16,OS_S16]) then
  1914. a_load_reg_reg(list,OS_32,size,dst,dst);
  1915. end;
  1916. function tcgarm.get_darwin_call_stub(const s: string): tasmsymbol;
  1917. var
  1918. stubname: string;
  1919. l1: tasmsymbol;
  1920. href: treference;
  1921. begin
  1922. stubname := 'L'+s+'$stub';
  1923. result := current_asmdata.getasmsymbol(stubname);
  1924. if assigned(result) then
  1925. exit;
  1926. if current_asmdata.asmlists[al_imports]=nil then
  1927. current_asmdata.asmlists[al_imports]:=TAsmList.create;
  1928. current_asmdata.asmlists[al_imports].concat(Tai_section.create(sec_stub,'',0));
  1929. current_asmdata.asmlists[al_imports].concat(Tai_align.Create(4));
  1930. result := current_asmdata.RefAsmSymbol(stubname);
  1931. current_asmdata.asmlists[al_imports].concat(Tai_symbol.Create(result,0));
  1932. current_asmdata.asmlists[al_imports].concat(tai_directive.create(asd_indirect_symbol,s));
  1933. if not(cs_create_pic in current_settings.moduleswitches) then
  1934. begin
  1935. l1 := current_asmdata.RefAsmSymbol('L'+s+'$slp');
  1936. reference_reset_symbol(href,l1,0);
  1937. href.refaddr:=addr_full;
  1938. current_asmdata.asmlists[al_imports].concat(taicpu.op_reg_ref(A_LDR,NR_R12,href));
  1939. reference_reset_base(href,NR_R12,0);
  1940. current_asmdata.asmlists[al_imports].concat(taicpu.op_reg_ref(A_LDR,NR_R15,href));
  1941. current_asmdata.asmlists[al_imports].concat(Tai_symbol.Create(l1,0));
  1942. l1 := current_asmdata.RefAsmSymbol('L'+s+'$lazy_ptr');
  1943. current_asmdata.asmlists[al_imports].concat(tai_const.create_sym(l1));
  1944. end
  1945. else
  1946. internalerror(2008100401);
  1947. current_asmdata.asmlists[al_imports].concat(tai_directive.create(asd_lazy_symbol_pointer,''));
  1948. current_asmdata.asmlists[al_imports].concat(Tai_symbol.Create(l1,0));
  1949. current_asmdata.asmlists[al_imports].concat(tai_directive.create(asd_indirect_symbol,s));
  1950. current_asmdata.asmlists[al_imports].concat(tai_const.createname('dyld_stub_binding_helper',0));
  1951. end;
  1952. procedure tcg64farm.a_op64_reg_reg(list : TAsmList;op:TOpCG;size : tcgsize;regsrc,regdst : tregister64);
  1953. begin
  1954. case op of
  1955. OP_NEG:
  1956. begin
  1957. list.concat(setoppostfix(taicpu.op_reg_reg_const(A_RSB,regdst.reglo,regsrc.reglo,0),PF_S));
  1958. list.concat(taicpu.op_reg_reg_const(A_RSC,regdst.reghi,regsrc.reghi,0));
  1959. end;
  1960. OP_NOT:
  1961. begin
  1962. cg.a_op_reg_reg(list,OP_NOT,OS_INT,regsrc.reglo,regdst.reglo);
  1963. cg.a_op_reg_reg(list,OP_NOT,OS_INT,regsrc.reghi,regdst.reghi);
  1964. end;
  1965. else
  1966. a_op64_reg_reg_reg(list,op,size,regsrc,regdst,regdst);
  1967. end;
  1968. end;
  1969. procedure tcg64farm.a_op64_const_reg(list : TAsmList;op:TOpCG;size : tcgsize;value : int64;reg : tregister64);
  1970. begin
  1971. a_op64_const_reg_reg(list,op,size,value,reg,reg);
  1972. end;
  1973. procedure tcg64farm.a_op64_const_reg_reg(list: TAsmList;op:TOpCG;size : tcgsize;value : int64;regsrc,regdst : tregister64);
  1974. var
  1975. ovloc : tlocation;
  1976. begin
  1977. a_op64_const_reg_reg_checkoverflow(list,op,size,value,regsrc,regdst,false,ovloc);
  1978. end;
  1979. procedure tcg64farm.a_op64_reg_reg_reg(list: TAsmList;op:TOpCG;size : tcgsize;regsrc1,regsrc2,regdst : tregister64);
  1980. var
  1981. ovloc : tlocation;
  1982. begin
  1983. a_op64_reg_reg_reg_checkoverflow(list,op,size,regsrc1,regsrc2,regdst,false,ovloc);
  1984. end;
  1985. procedure tcg64farm.a_op64_const_reg_reg_checkoverflow(list: TAsmList;op:TOpCG;size : tcgsize;value : int64;regsrc,regdst : tregister64;setflags : boolean;var ovloc : tlocation);
  1986. var
  1987. tmpreg : tregister;
  1988. b : byte;
  1989. begin
  1990. ovloc.loc:=LOC_VOID;
  1991. case op of
  1992. OP_NEG,
  1993. OP_NOT :
  1994. internalerror(200306017);
  1995. end;
  1996. if (setflags or tcgarm(cg).cgsetflags) and (op in [OP_ADD,OP_SUB]) then
  1997. begin
  1998. case op of
  1999. OP_ADD:
  2000. begin
  2001. if is_shifter_const(lo(value),b) then
  2002. list.concat(setoppostfix(taicpu.op_reg_reg_const(A_ADD,regdst.reglo,regsrc.reglo,lo(value)),PF_S))
  2003. else
  2004. begin
  2005. tmpreg:=cg.getintregister(list,OS_32);
  2006. cg.a_load_const_reg(list,OS_32,lo(value),tmpreg);
  2007. list.concat(setoppostfix(taicpu.op_reg_reg_reg(A_ADD,regdst.reglo,regsrc.reglo,tmpreg),PF_S));
  2008. end;
  2009. if is_shifter_const(hi(value),b) then
  2010. list.concat(setoppostfix(taicpu.op_reg_reg_const(A_ADC,regdst.reghi,regsrc.reghi,hi(value)),PF_S))
  2011. else
  2012. begin
  2013. tmpreg:=cg.getintregister(list,OS_32);
  2014. cg.a_load_const_reg(list,OS_32,hi(value),tmpreg);
  2015. list.concat(setoppostfix(taicpu.op_reg_reg_reg(A_ADC,regdst.reghi,regsrc.reghi,tmpreg),PF_S));
  2016. end;
  2017. end;
  2018. OP_SUB:
  2019. begin
  2020. if is_shifter_const(lo(value),b) then
  2021. list.concat(setoppostfix(taicpu.op_reg_reg_const(A_SUB,regdst.reglo,regsrc.reglo,lo(value)),PF_S))
  2022. else
  2023. begin
  2024. tmpreg:=cg.getintregister(list,OS_32);
  2025. cg.a_load_const_reg(list,OS_32,lo(value),tmpreg);
  2026. list.concat(setoppostfix(taicpu.op_reg_reg_reg(A_SUB,regdst.reglo,regsrc.reglo,tmpreg),PF_S));
  2027. end;
  2028. if is_shifter_const(hi(value),b) then
  2029. list.concat(setoppostfix(taicpu.op_reg_reg_const(A_SBC,regdst.reghi,regsrc.reghi,aint(hi(value))),PF_S))
  2030. else
  2031. begin
  2032. tmpreg:=cg.getintregister(list,OS_32);
  2033. cg.a_load_const_reg(list,OS_32,hi(value),tmpreg);
  2034. list.concat(setoppostfix(taicpu.op_reg_reg_reg(A_SBC,regdst.reghi,regsrc.reghi,tmpreg),PF_S));
  2035. end;
  2036. end;
  2037. else
  2038. internalerror(200502131);
  2039. end;
  2040. if size=OS_64 then
  2041. begin
  2042. { the arm has an weired opinion how flags for SUB/ADD are handled }
  2043. ovloc.loc:=LOC_FLAGS;
  2044. case op of
  2045. OP_ADD:
  2046. ovloc.resflags:=F_CS;
  2047. OP_SUB:
  2048. ovloc.resflags:=F_CC;
  2049. end;
  2050. end;
  2051. end
  2052. else
  2053. begin
  2054. case op of
  2055. OP_AND,OP_OR,OP_XOR:
  2056. begin
  2057. cg.a_op_const_reg_reg(list,op,OS_32,aint(lo(value)),regsrc.reglo,regdst.reglo);
  2058. cg.a_op_const_reg_reg(list,op,OS_32,aint(hi(value)),regsrc.reghi,regdst.reghi);
  2059. end;
  2060. OP_ADD:
  2061. begin
  2062. if is_shifter_const(aint(lo(value)),b) then
  2063. list.concat(setoppostfix(taicpu.op_reg_reg_const(A_ADD,regdst.reglo,regsrc.reglo,aint(lo(value))),PF_S))
  2064. else
  2065. begin
  2066. tmpreg:=cg.getintregister(list,OS_32);
  2067. cg.a_load_const_reg(list,OS_32,aint(lo(value)),tmpreg);
  2068. list.concat(setoppostfix(taicpu.op_reg_reg_reg(A_ADD,regdst.reglo,regsrc.reglo,tmpreg),PF_S));
  2069. end;
  2070. if is_shifter_const(aint(hi(value)),b) then
  2071. list.concat(taicpu.op_reg_reg_const(A_ADC,regdst.reghi,regsrc.reghi,aint(hi(value))))
  2072. else
  2073. begin
  2074. tmpreg:=cg.getintregister(list,OS_32);
  2075. cg.a_load_const_reg(list,OS_32,aint(hi(value)),tmpreg);
  2076. list.concat(taicpu.op_reg_reg_reg(A_ADC,regdst.reghi,regsrc.reghi,tmpreg));
  2077. end;
  2078. end;
  2079. OP_SUB:
  2080. begin
  2081. if is_shifter_const(aint(lo(value)),b) then
  2082. list.concat(setoppostfix(taicpu.op_reg_reg_const(A_SUB,regdst.reglo,regsrc.reglo,aint(lo(value))),PF_S))
  2083. else
  2084. begin
  2085. tmpreg:=cg.getintregister(list,OS_32);
  2086. cg.a_load_const_reg(list,OS_32,aint(lo(value)),tmpreg);
  2087. list.concat(setoppostfix(taicpu.op_reg_reg_reg(A_SUB,regdst.reglo,regsrc.reglo,tmpreg),PF_S));
  2088. end;
  2089. if is_shifter_const(aint(hi(value)),b) then
  2090. list.concat(taicpu.op_reg_reg_const(A_SBC,regdst.reghi,regsrc.reghi,aint(hi(value))))
  2091. else
  2092. begin
  2093. tmpreg:=cg.getintregister(list,OS_32);
  2094. cg.a_load_const_reg(list,OS_32,hi(value),tmpreg);
  2095. list.concat(taicpu.op_reg_reg_reg(A_SBC,regdst.reghi,regsrc.reghi,tmpreg));
  2096. end;
  2097. end;
  2098. else
  2099. internalerror(2003083101);
  2100. end;
  2101. end;
  2102. end;
  2103. procedure tcg64farm.a_op64_reg_reg_reg_checkoverflow(list: TAsmList;op:TOpCG;size : tcgsize;regsrc1,regsrc2,regdst : tregister64;setflags : boolean;var ovloc : tlocation);
  2104. begin
  2105. ovloc.loc:=LOC_VOID;
  2106. case op of
  2107. OP_NEG,
  2108. OP_NOT :
  2109. internalerror(200306017);
  2110. end;
  2111. if (setflags or tcgarm(cg).cgsetflags) and (op in [OP_ADD,OP_SUB]) then
  2112. begin
  2113. case op of
  2114. OP_ADD:
  2115. begin
  2116. list.concat(setoppostfix(taicpu.op_reg_reg_reg(A_ADD,regdst.reglo,regsrc1.reglo,regsrc2.reglo),PF_S));
  2117. list.concat(setoppostfix(taicpu.op_reg_reg_reg(A_ADC,regdst.reghi,regsrc1.reghi,regsrc2.reghi),PF_S));
  2118. end;
  2119. OP_SUB:
  2120. begin
  2121. list.concat(setoppostfix(taicpu.op_reg_reg_reg(A_SUB,regdst.reglo,regsrc2.reglo,regsrc1.reglo),PF_S));
  2122. list.concat(setoppostfix(taicpu.op_reg_reg_reg(A_SBC,regdst.reghi,regsrc2.reghi,regsrc1.reghi),PF_S));
  2123. end;
  2124. else
  2125. internalerror(2003083101);
  2126. end;
  2127. if size=OS_64 then
  2128. begin
  2129. { the arm has an weired opinion how flags for SUB/ADD are handled }
  2130. ovloc.loc:=LOC_FLAGS;
  2131. case op of
  2132. OP_ADD:
  2133. ovloc.resflags:=F_CS;
  2134. OP_SUB:
  2135. ovloc.resflags:=F_CC;
  2136. end;
  2137. end;
  2138. end
  2139. else
  2140. begin
  2141. case op of
  2142. OP_AND,OP_OR,OP_XOR:
  2143. begin
  2144. cg.a_op_reg_reg_reg(list,op,OS_32,regsrc1.reglo,regsrc2.reglo,regdst.reglo);
  2145. cg.a_op_reg_reg_reg(list,op,OS_32,regsrc1.reghi,regsrc2.reghi,regdst.reghi);
  2146. end;
  2147. OP_ADD:
  2148. begin
  2149. list.concat(setoppostfix(taicpu.op_reg_reg_reg(A_ADD,regdst.reglo,regsrc1.reglo,regsrc2.reglo),PF_S));
  2150. list.concat(taicpu.op_reg_reg_reg(A_ADC,regdst.reghi,regsrc1.reghi,regsrc2.reghi));
  2151. end;
  2152. OP_SUB:
  2153. begin
  2154. list.concat(setoppostfix(taicpu.op_reg_reg_reg(A_SUB,regdst.reglo,regsrc2.reglo,regsrc1.reglo),PF_S));
  2155. list.concat(taicpu.op_reg_reg_reg(A_SBC,regdst.reghi,regsrc2.reghi,regsrc1.reghi));
  2156. end;
  2157. else
  2158. internalerror(2003083101);
  2159. end;
  2160. end;
  2161. end;
  2162. begin
  2163. cg:=tcgarm.create;
  2164. cg64:=tcg64farm.create;
  2165. end.