cgcpu.pas 84 KB

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