cgcpu.pas 90 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363
  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. stackmisalignment: pint;
  1194. begin
  1195. LocalSize:=align(LocalSize,4);
  1196. { call instruction does not put anything on the stack }
  1197. stackmisalignment:=0;
  1198. if not(nostackframe) then
  1199. begin
  1200. firstfloatreg:=RS_NO;
  1201. { save floating point registers? }
  1202. for r:=RS_F0 to RS_F7 do
  1203. if r in rg[R_FPUREGISTER].used_in_proc-paramanager.get_volatile_registers_fpu(pocall_stdcall) then
  1204. begin
  1205. if firstfloatreg=RS_NO then
  1206. firstfloatreg:=r;
  1207. lastfloatreg:=r;
  1208. inc(stackmisalignment,12);
  1209. end;
  1210. a_reg_alloc(list,NR_STACK_POINTER_REG);
  1211. if current_procinfo.framepointer<>NR_STACK_POINTER_REG then
  1212. begin
  1213. a_reg_alloc(list,NR_FRAME_POINTER_REG);
  1214. a_reg_alloc(list,NR_R12);
  1215. list.concat(taicpu.op_reg_reg(A_MOV,NR_R12,NR_STACK_POINTER_REG));
  1216. end;
  1217. { save int registers }
  1218. reference_reset(ref,4);
  1219. ref.index:=NR_STACK_POINTER_REG;
  1220. ref.addressmode:=AM_PREINDEXED;
  1221. regs:=rg[R_INTREGISTER].used_in_proc-paramanager.get_volatile_registers_int(pocall_stdcall);
  1222. if current_procinfo.framepointer<>NR_STACK_POINTER_REG then
  1223. regs:=regs+[RS_R11,RS_R12,RS_R14,RS_R15]
  1224. else
  1225. if (regs<>[]) or (pi_do_call in current_procinfo.flags) then
  1226. include(regs,RS_R14);
  1227. if regs<>[] then
  1228. begin
  1229. for r:=RS_R0 to RS_R15 do
  1230. if (r in regs) then
  1231. inc(stackmisalignment,4);
  1232. list.concat(setoppostfix(taicpu.op_ref_regset(A_STM,ref,regs),PF_FD));
  1233. end;
  1234. if current_procinfo.framepointer<>NR_STACK_POINTER_REG then
  1235. list.concat(taicpu.op_reg_reg_const(A_SUB,NR_FRAME_POINTER_REG,NR_R12,4));
  1236. stackmisalignment:=stackmisalignment mod current_settings.alignment.localalignmax;
  1237. if (LocalSize<>0) or
  1238. ((stackmisalignment<>0) and
  1239. ((pi_do_call in current_procinfo.flags) or
  1240. (po_assembler in current_procinfo.procdef.procoptions))) then
  1241. begin
  1242. localsize:=align(localsize+stackmisalignment,current_settings.alignment.localalignmax)-stackmisalignment;
  1243. if not(is_shifter_const(localsize,shift)) then
  1244. begin
  1245. if current_procinfo.framepointer=NR_STACK_POINTER_REG then
  1246. a_reg_alloc(list,NR_R12);
  1247. a_load_const_reg(list,OS_ADDR,LocalSize,NR_R12);
  1248. list.concat(taicpu.op_reg_reg_reg(A_SUB,NR_STACK_POINTER_REG,NR_STACK_POINTER_REG,NR_R12));
  1249. a_reg_dealloc(list,NR_R12);
  1250. end
  1251. else
  1252. begin
  1253. a_reg_dealloc(list,NR_R12);
  1254. list.concat(taicpu.op_reg_reg_const(A_SUB,NR_STACK_POINTER_REG,NR_STACK_POINTER_REG,LocalSize));
  1255. end;
  1256. end;
  1257. if firstfloatreg<>RS_NO then
  1258. begin
  1259. reference_reset(ref,4);
  1260. if tg.direction*tarmprocinfo(current_procinfo).floatregstart>=1023 then
  1261. begin
  1262. a_load_const_reg(list,OS_ADDR,-tarmprocinfo(current_procinfo).floatregstart,NR_R12);
  1263. list.concat(taicpu.op_reg_reg_reg(A_SUB,NR_R12,current_procinfo.framepointer,NR_R12));
  1264. ref.base:=NR_R12;
  1265. end
  1266. else
  1267. begin
  1268. ref.base:=current_procinfo.framepointer;
  1269. ref.offset:=tarmprocinfo(current_procinfo).floatregstart;
  1270. end;
  1271. list.concat(taicpu.op_reg_const_ref(A_SFM,newreg(R_FPUREGISTER,firstfloatreg,R_SUBWHOLE),
  1272. lastfloatreg-firstfloatreg+1,ref));
  1273. end;
  1274. end;
  1275. end;
  1276. procedure tcgarm.g_proc_exit(list : TAsmList;parasize : longint;nostackframe:boolean);
  1277. var
  1278. ref : treference;
  1279. firstfloatreg,lastfloatreg,
  1280. r : byte;
  1281. shift : byte;
  1282. regs : tcpuregisterset;
  1283. LocalSize : longint;
  1284. stackmisalignment: pint;
  1285. begin
  1286. if not(nostackframe) then
  1287. begin
  1288. stackmisalignment:=0;
  1289. { restore floating point register }
  1290. firstfloatreg:=RS_NO;
  1291. { save floating point registers? }
  1292. for r:=RS_F0 to RS_F7 do
  1293. if r in rg[R_FPUREGISTER].used_in_proc-paramanager.get_volatile_registers_fpu(pocall_stdcall) then
  1294. begin
  1295. if firstfloatreg=RS_NO then
  1296. firstfloatreg:=r;
  1297. lastfloatreg:=r;
  1298. { floating point register space is already included in
  1299. localsize below by calc_stackframe_size
  1300. inc(stackmisalignment,12);
  1301. }
  1302. end;
  1303. if firstfloatreg<>RS_NO then
  1304. begin
  1305. reference_reset(ref,4);
  1306. if tg.direction*tarmprocinfo(current_procinfo).floatregstart>=1023 then
  1307. begin
  1308. a_load_const_reg(list,OS_ADDR,-tarmprocinfo(current_procinfo).floatregstart,NR_R12);
  1309. list.concat(taicpu.op_reg_reg_reg(A_SUB,NR_R12,current_procinfo.framepointer,NR_R12));
  1310. ref.base:=NR_R12;
  1311. end
  1312. else
  1313. begin
  1314. ref.base:=current_procinfo.framepointer;
  1315. ref.offset:=tarmprocinfo(current_procinfo).floatregstart;
  1316. end;
  1317. list.concat(taicpu.op_reg_const_ref(A_LFM,newreg(R_FPUREGISTER,firstfloatreg,R_SUBWHOLE),
  1318. lastfloatreg-firstfloatreg+1,ref));
  1319. end;
  1320. regs:=rg[R_INTREGISTER].used_in_proc-paramanager.get_volatile_registers_int(pocall_stdcall);
  1321. if (pi_do_call in current_procinfo.flags) or (regs<>[]) then
  1322. begin
  1323. exclude(regs,RS_R14);
  1324. include(regs,RS_R15);
  1325. end;
  1326. if (current_procinfo.framepointer<>NR_STACK_POINTER_REG) then
  1327. regs:=regs+[RS_R11,RS_R13,RS_R15];
  1328. for r:=RS_R0 to RS_R15 do
  1329. if (r in regs) then
  1330. inc(stackmisalignment,4);
  1331. stackmisalignment:=stackmisalignment mod current_settings.alignment.localalignmax;
  1332. if (current_procinfo.framepointer=NR_STACK_POINTER_REG) then
  1333. begin
  1334. LocalSize:=current_procinfo.calc_stackframe_size;
  1335. if (LocalSize<>0) or
  1336. ((stackmisalignment<>0) and
  1337. ((pi_do_call in current_procinfo.flags) or
  1338. (po_assembler in current_procinfo.procdef.procoptions))) then
  1339. begin
  1340. localsize:=align(localsize+stackmisalignment,current_settings.alignment.localalignmax)-stackmisalignment;
  1341. if not(is_shifter_const(LocalSize,shift)) then
  1342. begin
  1343. a_reg_alloc(list,NR_R12);
  1344. a_load_const_reg(list,OS_ADDR,LocalSize,NR_R12);
  1345. list.concat(taicpu.op_reg_reg_reg(A_ADD,NR_STACK_POINTER_REG,NR_STACK_POINTER_REG,NR_R12));
  1346. a_reg_dealloc(list,NR_R12);
  1347. end
  1348. else
  1349. begin
  1350. list.concat(taicpu.op_reg_reg_const(A_ADD,NR_STACK_POINTER_REG,NR_STACK_POINTER_REG,LocalSize));
  1351. end;
  1352. end;
  1353. if regs=[] then
  1354. list.concat(taicpu.op_reg_reg(A_MOV,NR_R15,NR_R14))
  1355. else
  1356. begin
  1357. reference_reset(ref,4);
  1358. ref.index:=NR_STACK_POINTER_REG;
  1359. ref.addressmode:=AM_PREINDEXED;
  1360. list.concat(setoppostfix(taicpu.op_ref_regset(A_LDM,ref,regs),PF_FD));
  1361. end;
  1362. end
  1363. else
  1364. begin
  1365. { restore int registers and return }
  1366. reference_reset(ref,4);
  1367. ref.index:=NR_FRAME_POINTER_REG;
  1368. list.concat(setoppostfix(taicpu.op_ref_regset(A_LDM,ref,regs),PF_EA));
  1369. end;
  1370. end
  1371. else
  1372. list.concat(taicpu.op_reg_reg(A_MOV,NR_PC,NR_R14));
  1373. end;
  1374. procedure tcgarm.a_loadaddr_ref_reg(list : TAsmList;const ref : treference;r : tregister);
  1375. var
  1376. b : byte;
  1377. tmpref : treference;
  1378. instr : taicpu;
  1379. begin
  1380. if ref.addressmode<>AM_OFFSET then
  1381. internalerror(200309071);
  1382. tmpref:=ref;
  1383. { Be sure to have a base register }
  1384. if (tmpref.base=NR_NO) then
  1385. begin
  1386. if tmpref.shiftmode<>SM_None then
  1387. internalerror(200308294);
  1388. if tmpref.signindex<0 then
  1389. internalerror(200312023);
  1390. tmpref.base:=tmpref.index;
  1391. tmpref.index:=NR_NO;
  1392. end;
  1393. if assigned(tmpref.symbol) or
  1394. not((is_shifter_const(tmpref.offset,b)) or
  1395. (is_shifter_const(-tmpref.offset,b))
  1396. ) then
  1397. fixref(list,tmpref);
  1398. { expect a base here if there is an index }
  1399. if (tmpref.base=NR_NO) and (tmpref.index<>NR_NO) then
  1400. internalerror(200312022);
  1401. if tmpref.index<>NR_NO then
  1402. begin
  1403. if tmpref.shiftmode<>SM_None then
  1404. internalerror(200312021);
  1405. if tmpref.signindex<0 then
  1406. a_op_reg_reg_reg(list,OP_SUB,OS_ADDR,tmpref.base,tmpref.index,r)
  1407. else
  1408. a_op_reg_reg_reg(list,OP_ADD,OS_ADDR,tmpref.base,tmpref.index,r);
  1409. if tmpref.offset<>0 then
  1410. a_op_const_reg_reg(list,OP_ADD,OS_ADDR,tmpref.offset,r,r);
  1411. end
  1412. else
  1413. begin
  1414. if tmpref.base=NR_NO then
  1415. a_load_const_reg(list,OS_ADDR,tmpref.offset,r)
  1416. else
  1417. if tmpref.offset<>0 then
  1418. a_op_const_reg_reg(list,OP_ADD,OS_ADDR,tmpref.offset,tmpref.base,r)
  1419. else
  1420. begin
  1421. instr:=taicpu.op_reg_reg(A_MOV,r,tmpref.base);
  1422. list.concat(instr);
  1423. add_move_instruction(instr);
  1424. end;
  1425. end;
  1426. end;
  1427. procedure tcgarm.fixref(list : TAsmList;var ref : treference);
  1428. var
  1429. tmpreg : tregister;
  1430. tmpref : treference;
  1431. l : tasmlabel;
  1432. begin
  1433. { absolute symbols can't be handled directly, we've to store the symbol reference
  1434. in the text segment and access it pc relative
  1435. For now, we assume that references where base or index equals to PC are already
  1436. relative, all other references are assumed to be absolute and thus they need
  1437. to be handled extra.
  1438. A proper solution would be to change refoptions to a set and store the information
  1439. if the symbol is absolute or relative there.
  1440. }
  1441. { create consts entry }
  1442. reference_reset(tmpref,4);
  1443. current_asmdata.getjumplabel(l);
  1444. cg.a_label(current_procinfo.aktlocaldata,l);
  1445. tmpref.symboldata:=current_procinfo.aktlocaldata.last;
  1446. if assigned(ref.symbol) then
  1447. current_procinfo.aktlocaldata.concat(tai_const.create_sym_offset(ref.symbol,ref.offset))
  1448. else
  1449. current_procinfo.aktlocaldata.concat(tai_const.Create_32bit(ref.offset));
  1450. { load consts entry }
  1451. tmpreg:=getintregister(list,OS_INT);
  1452. tmpref.symbol:=l;
  1453. tmpref.base:=NR_PC;
  1454. list.concat(taicpu.op_reg_ref(A_LDR,tmpreg,tmpref));
  1455. if (ref.base<>NR_NO) then
  1456. begin
  1457. if ref.index<>NR_NO then
  1458. begin
  1459. list.concat(taicpu.op_reg_reg_reg(A_ADD,tmpreg,ref.base,tmpreg));
  1460. ref.base:=tmpreg;
  1461. end
  1462. else
  1463. if ref.base<>NR_PC then
  1464. begin
  1465. ref.index:=tmpreg;
  1466. ref.shiftimm:=0;
  1467. ref.signindex:=1;
  1468. ref.shiftmode:=SM_None;
  1469. end
  1470. else
  1471. ref.base:=tmpreg;
  1472. end
  1473. else
  1474. ref.base:=tmpreg;
  1475. ref.offset:=0;
  1476. ref.symbol:=nil;
  1477. end;
  1478. procedure tcgarm.g_concatcopy_move(list : TAsmList;const source,dest : treference;len : aint);
  1479. var
  1480. paraloc1,paraloc2,paraloc3 : TCGPara;
  1481. begin
  1482. paraloc1.init;
  1483. paraloc2.init;
  1484. paraloc3.init;
  1485. paramanager.getintparaloc(pocall_default,1,paraloc1);
  1486. paramanager.getintparaloc(pocall_default,2,paraloc2);
  1487. paramanager.getintparaloc(pocall_default,3,paraloc3);
  1488. paramanager.allocparaloc(list,paraloc3);
  1489. a_param_const(list,OS_INT,len,paraloc3);
  1490. paramanager.allocparaloc(list,paraloc2);
  1491. a_paramaddr_ref(list,dest,paraloc2);
  1492. paramanager.allocparaloc(list,paraloc2);
  1493. a_paramaddr_ref(list,source,paraloc1);
  1494. paramanager.freeparaloc(list,paraloc3);
  1495. paramanager.freeparaloc(list,paraloc2);
  1496. paramanager.freeparaloc(list,paraloc1);
  1497. alloccpuregisters(list,R_INTREGISTER,paramanager.get_volatile_registers_int(pocall_default));
  1498. alloccpuregisters(list,R_FPUREGISTER,paramanager.get_volatile_registers_fpu(pocall_default));
  1499. a_call_name(list,'FPC_MOVE',false);
  1500. dealloccpuregisters(list,R_FPUREGISTER,paramanager.get_volatile_registers_fpu(pocall_default));
  1501. dealloccpuregisters(list,R_INTREGISTER,paramanager.get_volatile_registers_int(pocall_default));
  1502. paraloc3.done;
  1503. paraloc2.done;
  1504. paraloc1.done;
  1505. end;
  1506. procedure tcgarm.g_concatcopy_internal(list : TAsmList;const source,dest : treference;len : aint;aligned : boolean);
  1507. const
  1508. 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}
  1509. var
  1510. srcref,dstref,usedtmpref,usedtmpref2:treference;
  1511. srcreg,destreg,countreg,r,tmpreg:tregister;
  1512. helpsize:aint;
  1513. copysize:byte;
  1514. cgsize:Tcgsize;
  1515. tmpregisters:array[1..maxtmpreg] of tregister;
  1516. tmpregi,tmpregi2:byte;
  1517. { will never be called with count<=4 }
  1518. procedure genloop(count : aword;size : byte);
  1519. const
  1520. size2opsize : array[1..4] of tcgsize = (OS_8,OS_16,OS_NO,OS_32);
  1521. var
  1522. l : tasmlabel;
  1523. begin
  1524. current_asmdata.getjumplabel(l);
  1525. if count<size then size:=1;
  1526. a_load_const_reg(list,OS_INT,count div size,countreg);
  1527. cg.a_label(list,l);
  1528. srcref.addressmode:=AM_POSTINDEXED;
  1529. dstref.addressmode:=AM_POSTINDEXED;
  1530. srcref.offset:=size;
  1531. dstref.offset:=size;
  1532. r:=getintregister(list,size2opsize[size]);
  1533. a_load_ref_reg(list,size2opsize[size],size2opsize[size],srcref,r);
  1534. list.concat(setoppostfix(taicpu.op_reg_reg_const(A_SUB,countreg,countreg,1),PF_S));
  1535. a_load_reg_ref(list,size2opsize[size],size2opsize[size],r,dstref);
  1536. a_jmp_flags(list,F_NE,l);
  1537. srcref.offset:=1;
  1538. dstref.offset:=1;
  1539. case count mod size of
  1540. 1:
  1541. begin
  1542. a_load_ref_reg(list,OS_8,OS_8,srcref,r);
  1543. a_load_reg_ref(list,OS_8,OS_8,r,dstref);
  1544. end;
  1545. 2:
  1546. if aligned then
  1547. begin
  1548. a_load_ref_reg(list,OS_16,OS_16,srcref,r);
  1549. a_load_reg_ref(list,OS_16,OS_16,r,dstref);
  1550. end
  1551. else
  1552. begin
  1553. a_load_ref_reg(list,OS_8,OS_8,srcref,r);
  1554. a_load_reg_ref(list,OS_8,OS_8,r,dstref);
  1555. a_load_ref_reg(list,OS_8,OS_8,srcref,r);
  1556. a_load_reg_ref(list,OS_8,OS_8,r,dstref);
  1557. end;
  1558. 3:
  1559. if aligned then
  1560. begin
  1561. srcref.offset:=2;
  1562. dstref.offset:=2;
  1563. a_load_ref_reg(list,OS_16,OS_16,srcref,r);
  1564. a_load_reg_ref(list,OS_16,OS_16,r,dstref);
  1565. a_load_ref_reg(list,OS_8,OS_8,srcref,r);
  1566. a_load_reg_ref(list,OS_8,OS_8,r,dstref);
  1567. end
  1568. else
  1569. begin
  1570. a_load_ref_reg(list,OS_8,OS_8,srcref,r);
  1571. a_load_reg_ref(list,OS_8,OS_8,r,dstref);
  1572. a_load_ref_reg(list,OS_8,OS_8,srcref,r);
  1573. a_load_reg_ref(list,OS_8,OS_8,r,dstref);
  1574. a_load_ref_reg(list,OS_8,OS_8,srcref,r);
  1575. a_load_reg_ref(list,OS_8,OS_8,r,dstref);
  1576. end;
  1577. end;
  1578. { keep the registers alive }
  1579. list.concat(taicpu.op_reg_reg(A_MOV,countreg,countreg));
  1580. list.concat(taicpu.op_reg_reg(A_MOV,srcreg,srcreg));
  1581. list.concat(taicpu.op_reg_reg(A_MOV,destreg,destreg));
  1582. end;
  1583. begin
  1584. if len=0 then
  1585. exit;
  1586. helpsize:=12+maxtmpreg*4;//52 with maxtmpreg=10
  1587. dstref:=dest;
  1588. srcref:=source;
  1589. if cs_opt_size in current_settings.optimizerswitches then
  1590. helpsize:=8;
  1591. if (len<=helpsize) and aligned then
  1592. begin
  1593. tmpregi:=0;
  1594. srcreg:=getintregister(list,OS_ADDR);
  1595. { explicit pc relative addressing, could be
  1596. e.g. a floating point constant }
  1597. if source.base=NR_PC then
  1598. begin
  1599. { ... then we don't need a loadaddr }
  1600. srcref:=source;
  1601. end
  1602. else
  1603. begin
  1604. a_loadaddr_ref_reg(list,source,srcreg);
  1605. reference_reset_base(srcref,srcreg,0,source.alignment);
  1606. end;
  1607. while (len div 4 <> 0) and (tmpregi<maxtmpreg) do
  1608. begin
  1609. inc(tmpregi);
  1610. tmpregisters[tmpregi]:=getintregister(list,OS_32);
  1611. a_load_ref_reg(list,OS_32,OS_32,srcref,tmpregisters[tmpregi]);
  1612. inc(srcref.offset,4);
  1613. dec(len,4);
  1614. end;
  1615. destreg:=getintregister(list,OS_ADDR);
  1616. a_loadaddr_ref_reg(list,dest,destreg);
  1617. reference_reset_base(dstref,destreg,0,dest.alignment);
  1618. tmpregi2:=1;
  1619. while (tmpregi2<=tmpregi) do
  1620. begin
  1621. a_load_reg_ref(list,OS_32,OS_32,tmpregisters[tmpregi2],dstref);
  1622. inc(dstref.offset,4);
  1623. inc(tmpregi2);
  1624. end;
  1625. copysize:=4;
  1626. cgsize:=OS_32;
  1627. while len<>0 do
  1628. begin
  1629. if len<2 then
  1630. begin
  1631. copysize:=1;
  1632. cgsize:=OS_8;
  1633. end
  1634. else if len<4 then
  1635. begin
  1636. copysize:=2;
  1637. cgsize:=OS_16;
  1638. end;
  1639. dec(len,copysize);
  1640. r:=getintregister(list,cgsize);
  1641. a_load_ref_reg(list,cgsize,cgsize,srcref,r);
  1642. a_load_reg_ref(list,cgsize,cgsize,r,dstref);
  1643. inc(srcref.offset,copysize);
  1644. inc(dstref.offset,copysize);
  1645. end;{end of while}
  1646. end
  1647. else
  1648. begin
  1649. cgsize:=OS_32;
  1650. if (len<=4) then{len<=4 and not aligned}
  1651. begin
  1652. r:=getintregister(list,cgsize);
  1653. usedtmpref:=a_internal_load_ref_reg(list,OS_8,OS_8,srcref,r);
  1654. if Len=1 then
  1655. a_load_reg_ref(list,OS_8,OS_8,r,dstref)
  1656. else
  1657. begin
  1658. tmpreg:=getintregister(list,cgsize);
  1659. usedtmpref2:=a_internal_load_reg_ref(list,OS_8,OS_8,r,dstref);
  1660. inc(usedtmpref.offset,1);
  1661. a_load_ref_reg(list,OS_8,OS_8,usedtmpref,tmpreg);
  1662. inc(usedtmpref2.offset,1);
  1663. a_load_reg_ref(list,OS_8,OS_8,tmpreg,usedtmpref2);
  1664. if len>2 then
  1665. begin
  1666. inc(usedtmpref.offset,1);
  1667. a_load_ref_reg(list,OS_8,OS_8,usedtmpref,tmpreg);
  1668. inc(usedtmpref2.offset,1);
  1669. a_load_reg_ref(list,OS_8,OS_8,tmpreg,usedtmpref2);
  1670. if len>3 then
  1671. begin
  1672. inc(usedtmpref.offset,1);
  1673. a_load_ref_reg(list,OS_8,OS_8,usedtmpref,tmpreg);
  1674. inc(usedtmpref2.offset,1);
  1675. a_load_reg_ref(list,OS_8,OS_8,tmpreg,usedtmpref2);
  1676. end;
  1677. end;
  1678. end;
  1679. end{end of if len<=4}
  1680. else
  1681. begin{unaligned & 4<len<helpsize **or** aligned/unaligned & len>helpsize}
  1682. destreg:=getintregister(list,OS_ADDR);
  1683. a_loadaddr_ref_reg(list,dest,destreg);
  1684. reference_reset_base(dstref,destreg,0,dest.alignment);
  1685. srcreg:=getintregister(list,OS_ADDR);
  1686. a_loadaddr_ref_reg(list,source,srcreg);
  1687. reference_reset_base(srcref,srcreg,0,source.alignment);
  1688. countreg:=getintregister(list,OS_32);
  1689. // if cs_opt_size in current_settings.optimizerswitches then
  1690. { roozbeh : it seems loading 1 byte is faster becouse of caching/fetching(?) }
  1691. {if aligned then
  1692. genloop(len,4)
  1693. else}
  1694. genloop(len,1);
  1695. end;
  1696. end;
  1697. end;
  1698. procedure tcgarm.g_concatcopy_unaligned(list : TAsmList;const source,dest : treference;len : aint);
  1699. begin
  1700. g_concatcopy_internal(list,source,dest,len,false);
  1701. end;
  1702. procedure tcgarm.g_concatcopy(list : TAsmList;const source,dest : treference;len : aint);
  1703. begin
  1704. if (source.alignment in [1..3]) or
  1705. (dest.alignment in [1..3]) then
  1706. g_concatcopy_internal(list,source,dest,len,false)
  1707. else
  1708. g_concatcopy_internal(list,source,dest,len,true);
  1709. end;
  1710. procedure tcgarm.g_overflowCheck(list : TAsmList;const l : tlocation;def : tdef);
  1711. var
  1712. ovloc : tlocation;
  1713. begin
  1714. ovloc.loc:=LOC_VOID;
  1715. g_overflowCheck_loc(list,l,def,ovloc);
  1716. end;
  1717. procedure tcgarm.g_overflowCheck_loc(List:TAsmList;const Loc:TLocation;def:TDef;ovloc : tlocation);
  1718. var
  1719. hl : tasmlabel;
  1720. ai:TAiCpu;
  1721. hflags : tresflags;
  1722. begin
  1723. if not(cs_check_overflow in current_settings.localswitches) then
  1724. exit;
  1725. current_asmdata.getjumplabel(hl);
  1726. case ovloc.loc of
  1727. LOC_VOID:
  1728. begin
  1729. ai:=taicpu.op_sym(A_B,hl);
  1730. ai.is_jmp:=true;
  1731. if not((def.typ=pointerdef) or
  1732. ((def.typ=orddef) and
  1733. (torddef(def).ordtype in [u64bit,u16bit,u32bit,u8bit,uchar,pasbool]))) then
  1734. ai.SetCondition(C_VC)
  1735. else
  1736. if TAiCpu(List.Last).opcode in [A_RSB,A_RSC,A_SBC,A_SUB] then
  1737. ai.SetCondition(C_CS)
  1738. else
  1739. ai.SetCondition(C_CC);
  1740. list.concat(ai);
  1741. end;
  1742. LOC_FLAGS:
  1743. begin
  1744. hflags:=ovloc.resflags;
  1745. inverse_flags(hflags);
  1746. cg.a_jmp_flags(list,hflags,hl);
  1747. end;
  1748. else
  1749. internalerror(200409281);
  1750. end;
  1751. a_call_name(list,'FPC_OVERFLOW',false);
  1752. a_label(list,hl);
  1753. end;
  1754. procedure tcgarm.g_save_registers(list : TAsmList);
  1755. begin
  1756. { this work is done in g_proc_entry }
  1757. end;
  1758. procedure tcgarm.g_restore_registers(list : TAsmList);
  1759. begin
  1760. { this work is done in g_proc_exit }
  1761. end;
  1762. procedure tcgarm.a_jmp_cond(list : TAsmList;cond : TOpCmp;l: tasmlabel);
  1763. var
  1764. ai : taicpu;
  1765. begin
  1766. ai:=Taicpu.Op_sym(A_B,l);
  1767. ai.SetCondition(OpCmp2AsmCond[cond]);
  1768. ai.is_jmp:=true;
  1769. list.concat(ai);
  1770. end;
  1771. procedure tcgarm.g_adjust_self_value(list:TAsmList;procdef: tprocdef;ioffset: aint);
  1772. var
  1773. hsym : tsym;
  1774. href : treference;
  1775. paraloc : Pcgparalocation;
  1776. shift : byte;
  1777. begin
  1778. { calculate the parameter info for the procdef }
  1779. if not procdef.has_paraloc_info then
  1780. begin
  1781. procdef.requiredargarea:=paramanager.create_paraloc_info(procdef,callerside);
  1782. procdef.has_paraloc_info:=true;
  1783. end;
  1784. hsym:=tsym(procdef.parast.Find('self'));
  1785. if not(assigned(hsym) and
  1786. (hsym.typ=paravarsym)) then
  1787. internalerror(200305251);
  1788. paraloc:=tparavarsym(hsym).paraloc[callerside].location;
  1789. while paraloc<>nil do
  1790. with paraloc^ do
  1791. begin
  1792. case loc of
  1793. LOC_REGISTER:
  1794. begin
  1795. if is_shifter_const(ioffset,shift) then
  1796. a_op_const_reg(list,OP_SUB,size,ioffset,register)
  1797. else
  1798. begin
  1799. a_load_const_reg(list,OS_ADDR,ioffset,NR_R12);
  1800. a_op_reg_reg(list,OP_SUB,size,NR_R12,register);
  1801. end;
  1802. end;
  1803. LOC_REFERENCE:
  1804. begin
  1805. { offset in the wrapper needs to be adjusted for the stored
  1806. return address }
  1807. reference_reset_base(href,reference.index,reference.offset+sizeof(aint),sizeof(pint));
  1808. if is_shifter_const(ioffset,shift) then
  1809. a_op_const_ref(list,OP_SUB,size,ioffset,href)
  1810. else
  1811. begin
  1812. a_load_const_reg(list,OS_ADDR,ioffset,NR_R12);
  1813. a_op_reg_ref(list,OP_SUB,size,NR_R12,href);
  1814. end;
  1815. end
  1816. else
  1817. internalerror(200309189);
  1818. end;
  1819. paraloc:=next;
  1820. end;
  1821. end;
  1822. procedure tcgarm.g_stackpointer_alloc(list: TAsmList; size: longint);
  1823. begin
  1824. internalerror(200807237);
  1825. end;
  1826. procedure tcgarm.g_intf_wrapper(list: TAsmList; procdef: tprocdef; const labelname: string; ioffset: longint);
  1827. procedure loadvmttor12;
  1828. var
  1829. href : treference;
  1830. begin
  1831. reference_reset_base(href,NR_R0,0,sizeof(pint));
  1832. cg.a_load_ref_reg(list,OS_ADDR,OS_ADDR,href,NR_R12);
  1833. end;
  1834. procedure op_onr12methodaddr;
  1835. var
  1836. href : treference;
  1837. begin
  1838. if (procdef.extnumber=$ffff) then
  1839. Internalerror(200006139);
  1840. { call/jmp vmtoffs(%eax) ; method offs }
  1841. reference_reset_base(href,NR_R12,procdef._class.vmtmethodoffset(procdef.extnumber),sizeof(pint));
  1842. cg.a_load_ref_reg(list,OS_ADDR,OS_ADDR,href,NR_R12);
  1843. list.concat(taicpu.op_reg_reg(A_MOV,NR_PC,NR_R12));
  1844. end;
  1845. var
  1846. make_global : boolean;
  1847. begin
  1848. if not(procdef.proctypeoption in [potype_function,potype_procedure]) then
  1849. Internalerror(200006137);
  1850. if not assigned(procdef._class) or
  1851. (procdef.procoptions*[po_classmethod, po_staticmethod,
  1852. po_methodpointer, po_interrupt, po_iocheck]<>[]) then
  1853. Internalerror(200006138);
  1854. if procdef.owner.symtabletype<>ObjectSymtable then
  1855. Internalerror(200109191);
  1856. make_global:=false;
  1857. if (not current_module.is_unit) or
  1858. create_smartlink or
  1859. (procdef.owner.defowner.owner.symtabletype=globalsymtable) then
  1860. make_global:=true;
  1861. if make_global then
  1862. list.concat(Tai_symbol.Createname_global(labelname,AT_FUNCTION,0))
  1863. else
  1864. list.concat(Tai_symbol.Createname(labelname,AT_FUNCTION,0));
  1865. { the wrapper might need aktlocaldata for the additional data to
  1866. load the constant }
  1867. current_procinfo:=cprocinfo.create(nil);
  1868. { set param1 interface to self }
  1869. g_adjust_self_value(list,procdef,ioffset);
  1870. { case 4 }
  1871. if po_virtualmethod in procdef.procoptions then
  1872. begin
  1873. loadvmttor12;
  1874. op_onr12methodaddr;
  1875. end
  1876. { case 0 }
  1877. else
  1878. list.concat(taicpu.op_sym(A_B,current_asmdata.RefAsmSymbol(procdef.mangledname)));
  1879. list.concatlist(current_procinfo.aktlocaldata);
  1880. current_procinfo.Free;
  1881. current_procinfo:=nil;
  1882. list.concat(Tai_symbol_end.Createname(labelname));
  1883. end;
  1884. procedure tcgarm.maybeadjustresult(list: TAsmList; op: TOpCg; size: tcgsize; dst: tregister);
  1885. const
  1886. overflowops = [OP_MUL,OP_SHL,OP_ADD,OP_SUB,OP_NOT,OP_NEG];
  1887. begin
  1888. if (op in overflowops) and
  1889. (size in [OS_8,OS_S8,OS_16,OS_S16]) then
  1890. a_load_reg_reg(list,OS_32,size,dst,dst);
  1891. end;
  1892. function tcgarm.get_darwin_call_stub(const s: string; weak: boolean): tasmsymbol;
  1893. var
  1894. stubname: string;
  1895. l1: tasmsymbol;
  1896. href: treference;
  1897. begin
  1898. stubname := 'L'+s+'$stub';
  1899. result := current_asmdata.getasmsymbol(stubname);
  1900. if assigned(result) then
  1901. exit;
  1902. if current_asmdata.asmlists[al_imports]=nil then
  1903. current_asmdata.asmlists[al_imports]:=TAsmList.create;
  1904. current_asmdata.asmlists[al_imports].concat(Tai_section.create(sec_stub,'',0));
  1905. current_asmdata.asmlists[al_imports].concat(Tai_align.Create(4));
  1906. result := current_asmdata.RefAsmSymbol(stubname);
  1907. current_asmdata.asmlists[al_imports].concat(Tai_symbol.Create(result,0));
  1908. { register as a weak symbol if necessary }
  1909. if weak then
  1910. current_asmdata.weakrefasmsymbol(s);
  1911. current_asmdata.asmlists[al_imports].concat(tai_directive.create(asd_indirect_symbol,s));
  1912. if not(cs_create_pic in current_settings.moduleswitches) then
  1913. begin
  1914. l1 := current_asmdata.RefAsmSymbol('L'+s+'$slp');
  1915. reference_reset_symbol(href,l1,0,sizeof(pint));
  1916. href.refaddr:=addr_full;
  1917. current_asmdata.asmlists[al_imports].concat(taicpu.op_reg_ref(A_LDR,NR_R12,href));
  1918. reference_reset_base(href,NR_R12,0,sizeof(pint));
  1919. current_asmdata.asmlists[al_imports].concat(taicpu.op_reg_ref(A_LDR,NR_R15,href));
  1920. current_asmdata.asmlists[al_imports].concat(Tai_symbol.Create(l1,0));
  1921. l1 := current_asmdata.RefAsmSymbol('L'+s+'$lazy_ptr');
  1922. current_asmdata.asmlists[al_imports].concat(tai_const.create_sym(l1));
  1923. end
  1924. else
  1925. internalerror(2008100401);
  1926. current_asmdata.asmlists[al_imports].concat(tai_directive.create(asd_lazy_symbol_pointer,''));
  1927. current_asmdata.asmlists[al_imports].concat(Tai_symbol.Create(l1,0));
  1928. current_asmdata.asmlists[al_imports].concat(tai_directive.create(asd_indirect_symbol,s));
  1929. current_asmdata.asmlists[al_imports].concat(tai_const.createname('dyld_stub_binding_helper',0));
  1930. end;
  1931. procedure tcg64farm.a_op64_reg_reg(list : TAsmList;op:TOpCG;size : tcgsize;regsrc,regdst : tregister64);
  1932. begin
  1933. case op of
  1934. OP_NEG:
  1935. begin
  1936. list.concat(setoppostfix(taicpu.op_reg_reg_const(A_RSB,regdst.reglo,regsrc.reglo,0),PF_S));
  1937. list.concat(taicpu.op_reg_reg_const(A_RSC,regdst.reghi,regsrc.reghi,0));
  1938. end;
  1939. OP_NOT:
  1940. begin
  1941. cg.a_op_reg_reg(list,OP_NOT,OS_INT,regsrc.reglo,regdst.reglo);
  1942. cg.a_op_reg_reg(list,OP_NOT,OS_INT,regsrc.reghi,regdst.reghi);
  1943. end;
  1944. else
  1945. a_op64_reg_reg_reg(list,op,size,regsrc,regdst,regdst);
  1946. end;
  1947. end;
  1948. procedure tcg64farm.a_op64_const_reg(list : TAsmList;op:TOpCG;size : tcgsize;value : int64;reg : tregister64);
  1949. begin
  1950. a_op64_const_reg_reg(list,op,size,value,reg,reg);
  1951. end;
  1952. procedure tcg64farm.a_op64_const_reg_reg(list: TAsmList;op:TOpCG;size : tcgsize;value : int64;regsrc,regdst : tregister64);
  1953. var
  1954. ovloc : tlocation;
  1955. begin
  1956. a_op64_const_reg_reg_checkoverflow(list,op,size,value,regsrc,regdst,false,ovloc);
  1957. end;
  1958. procedure tcg64farm.a_op64_reg_reg_reg(list: TAsmList;op:TOpCG;size : tcgsize;regsrc1,regsrc2,regdst : tregister64);
  1959. var
  1960. ovloc : tlocation;
  1961. begin
  1962. a_op64_reg_reg_reg_checkoverflow(list,op,size,regsrc1,regsrc2,regdst,false,ovloc);
  1963. end;
  1964. procedure tcg64farm.a_op64_const_reg_reg_checkoverflow(list: TAsmList;op:TOpCG;size : tcgsize;value : int64;regsrc,regdst : tregister64;setflags : boolean;var ovloc : tlocation);
  1965. var
  1966. tmpreg : tregister;
  1967. b : byte;
  1968. begin
  1969. ovloc.loc:=LOC_VOID;
  1970. case op of
  1971. OP_NEG,
  1972. OP_NOT :
  1973. internalerror(200306017);
  1974. end;
  1975. if (setflags or tcgarm(cg).cgsetflags) and (op in [OP_ADD,OP_SUB]) then
  1976. begin
  1977. case op of
  1978. OP_ADD:
  1979. begin
  1980. if is_shifter_const(lo(value),b) then
  1981. list.concat(setoppostfix(taicpu.op_reg_reg_const(A_ADD,regdst.reglo,regsrc.reglo,lo(value)),PF_S))
  1982. else
  1983. begin
  1984. tmpreg:=cg.getintregister(list,OS_32);
  1985. cg.a_load_const_reg(list,OS_32,lo(value),tmpreg);
  1986. list.concat(setoppostfix(taicpu.op_reg_reg_reg(A_ADD,regdst.reglo,regsrc.reglo,tmpreg),PF_S));
  1987. end;
  1988. if is_shifter_const(hi(value),b) then
  1989. list.concat(setoppostfix(taicpu.op_reg_reg_const(A_ADC,regdst.reghi,regsrc.reghi,hi(value)),PF_S))
  1990. else
  1991. begin
  1992. tmpreg:=cg.getintregister(list,OS_32);
  1993. cg.a_load_const_reg(list,OS_32,hi(value),tmpreg);
  1994. list.concat(setoppostfix(taicpu.op_reg_reg_reg(A_ADC,regdst.reghi,regsrc.reghi,tmpreg),PF_S));
  1995. end;
  1996. end;
  1997. OP_SUB:
  1998. begin
  1999. if is_shifter_const(lo(value),b) then
  2000. list.concat(setoppostfix(taicpu.op_reg_reg_const(A_SUB,regdst.reglo,regsrc.reglo,lo(value)),PF_S))
  2001. else
  2002. begin
  2003. tmpreg:=cg.getintregister(list,OS_32);
  2004. cg.a_load_const_reg(list,OS_32,lo(value),tmpreg);
  2005. list.concat(setoppostfix(taicpu.op_reg_reg_reg(A_SUB,regdst.reglo,regsrc.reglo,tmpreg),PF_S));
  2006. end;
  2007. if is_shifter_const(hi(value),b) then
  2008. list.concat(setoppostfix(taicpu.op_reg_reg_const(A_SBC,regdst.reghi,regsrc.reghi,aint(hi(value))),PF_S))
  2009. else
  2010. begin
  2011. tmpreg:=cg.getintregister(list,OS_32);
  2012. cg.a_load_const_reg(list,OS_32,hi(value),tmpreg);
  2013. list.concat(setoppostfix(taicpu.op_reg_reg_reg(A_SBC,regdst.reghi,regsrc.reghi,tmpreg),PF_S));
  2014. end;
  2015. end;
  2016. else
  2017. internalerror(200502131);
  2018. end;
  2019. if size=OS_64 then
  2020. begin
  2021. { the arm has an weired opinion how flags for SUB/ADD are handled }
  2022. ovloc.loc:=LOC_FLAGS;
  2023. case op of
  2024. OP_ADD:
  2025. ovloc.resflags:=F_CS;
  2026. OP_SUB:
  2027. ovloc.resflags:=F_CC;
  2028. end;
  2029. end;
  2030. end
  2031. else
  2032. begin
  2033. case op of
  2034. OP_AND,OP_OR,OP_XOR:
  2035. begin
  2036. cg.a_op_const_reg_reg(list,op,OS_32,aint(lo(value)),regsrc.reglo,regdst.reglo);
  2037. cg.a_op_const_reg_reg(list,op,OS_32,aint(hi(value)),regsrc.reghi,regdst.reghi);
  2038. end;
  2039. OP_ADD:
  2040. begin
  2041. if is_shifter_const(aint(lo(value)),b) then
  2042. list.concat(setoppostfix(taicpu.op_reg_reg_const(A_ADD,regdst.reglo,regsrc.reglo,aint(lo(value))),PF_S))
  2043. else
  2044. begin
  2045. tmpreg:=cg.getintregister(list,OS_32);
  2046. cg.a_load_const_reg(list,OS_32,aint(lo(value)),tmpreg);
  2047. list.concat(setoppostfix(taicpu.op_reg_reg_reg(A_ADD,regdst.reglo,regsrc.reglo,tmpreg),PF_S));
  2048. end;
  2049. if is_shifter_const(aint(hi(value)),b) then
  2050. list.concat(taicpu.op_reg_reg_const(A_ADC,regdst.reghi,regsrc.reghi,aint(hi(value))))
  2051. else
  2052. begin
  2053. tmpreg:=cg.getintregister(list,OS_32);
  2054. cg.a_load_const_reg(list,OS_32,aint(hi(value)),tmpreg);
  2055. list.concat(taicpu.op_reg_reg_reg(A_ADC,regdst.reghi,regsrc.reghi,tmpreg));
  2056. end;
  2057. end;
  2058. OP_SUB:
  2059. begin
  2060. if is_shifter_const(aint(lo(value)),b) then
  2061. list.concat(setoppostfix(taicpu.op_reg_reg_const(A_SUB,regdst.reglo,regsrc.reglo,aint(lo(value))),PF_S))
  2062. else
  2063. begin
  2064. tmpreg:=cg.getintregister(list,OS_32);
  2065. cg.a_load_const_reg(list,OS_32,aint(lo(value)),tmpreg);
  2066. list.concat(setoppostfix(taicpu.op_reg_reg_reg(A_SUB,regdst.reglo,regsrc.reglo,tmpreg),PF_S));
  2067. end;
  2068. if is_shifter_const(aint(hi(value)),b) then
  2069. list.concat(taicpu.op_reg_reg_const(A_SBC,regdst.reghi,regsrc.reghi,aint(hi(value))))
  2070. else
  2071. begin
  2072. tmpreg:=cg.getintregister(list,OS_32);
  2073. cg.a_load_const_reg(list,OS_32,hi(value),tmpreg);
  2074. list.concat(taicpu.op_reg_reg_reg(A_SBC,regdst.reghi,regsrc.reghi,tmpreg));
  2075. end;
  2076. end;
  2077. else
  2078. internalerror(2003083101);
  2079. end;
  2080. end;
  2081. end;
  2082. procedure tcg64farm.a_op64_reg_reg_reg_checkoverflow(list: TAsmList;op:TOpCG;size : tcgsize;regsrc1,regsrc2,regdst : tregister64;setflags : boolean;var ovloc : tlocation);
  2083. begin
  2084. ovloc.loc:=LOC_VOID;
  2085. case op of
  2086. OP_NEG,
  2087. OP_NOT :
  2088. internalerror(200306017);
  2089. end;
  2090. if (setflags or tcgarm(cg).cgsetflags) and (op in [OP_ADD,OP_SUB]) then
  2091. begin
  2092. case op of
  2093. OP_ADD:
  2094. begin
  2095. list.concat(setoppostfix(taicpu.op_reg_reg_reg(A_ADD,regdst.reglo,regsrc1.reglo,regsrc2.reglo),PF_S));
  2096. list.concat(setoppostfix(taicpu.op_reg_reg_reg(A_ADC,regdst.reghi,regsrc1.reghi,regsrc2.reghi),PF_S));
  2097. end;
  2098. OP_SUB:
  2099. begin
  2100. list.concat(setoppostfix(taicpu.op_reg_reg_reg(A_SUB,regdst.reglo,regsrc2.reglo,regsrc1.reglo),PF_S));
  2101. list.concat(setoppostfix(taicpu.op_reg_reg_reg(A_SBC,regdst.reghi,regsrc2.reghi,regsrc1.reghi),PF_S));
  2102. end;
  2103. else
  2104. internalerror(2003083101);
  2105. end;
  2106. if size=OS_64 then
  2107. begin
  2108. { the arm has an weired opinion how flags for SUB/ADD are handled }
  2109. ovloc.loc:=LOC_FLAGS;
  2110. case op of
  2111. OP_ADD:
  2112. ovloc.resflags:=F_CS;
  2113. OP_SUB:
  2114. ovloc.resflags:=F_CC;
  2115. end;
  2116. end;
  2117. end
  2118. else
  2119. begin
  2120. case op of
  2121. OP_AND,OP_OR,OP_XOR:
  2122. begin
  2123. cg.a_op_reg_reg_reg(list,op,OS_32,regsrc1.reglo,regsrc2.reglo,regdst.reglo);
  2124. cg.a_op_reg_reg_reg(list,op,OS_32,regsrc1.reghi,regsrc2.reghi,regdst.reghi);
  2125. end;
  2126. OP_ADD:
  2127. begin
  2128. list.concat(setoppostfix(taicpu.op_reg_reg_reg(A_ADD,regdst.reglo,regsrc1.reglo,regsrc2.reglo),PF_S));
  2129. list.concat(taicpu.op_reg_reg_reg(A_ADC,regdst.reghi,regsrc1.reghi,regsrc2.reghi));
  2130. end;
  2131. OP_SUB:
  2132. begin
  2133. list.concat(setoppostfix(taicpu.op_reg_reg_reg(A_SUB,regdst.reglo,regsrc2.reglo,regsrc1.reglo),PF_S));
  2134. list.concat(taicpu.op_reg_reg_reg(A_SBC,regdst.reghi,regsrc2.reghi,regsrc1.reghi));
  2135. end;
  2136. else
  2137. internalerror(2003083101);
  2138. end;
  2139. end;
  2140. end;
  2141. begin
  2142. cg:=tcgarm.create;
  2143. cg64:=tcg64farm.create;
  2144. end.