cgcpu.pas 92 KB

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