cgcpu.pas 87 KB

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