2
0

cgcpu.pas 85 KB

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