cgcpu.pas 87 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276
  1. {
  2. Copyright (c) 2003 by Florian Klaempfl
  3. Member of the Free Pascal development team
  4. This unit implements the code generator for the ARM
  5. This program is free software; you can redistribute it and/or modify
  6. it under the terms of the GNU General Public License as published by
  7. the Free Software Foundation; either version 2 of the License, or
  8. (at your option) any later version.
  9. This program is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. GNU General Public License for more details.
  13. You should have received a copy of the GNU General Public License
  14. along with this program; if not, write to the Free Software
  15. Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  16. ****************************************************************************
  17. }
  18. unit cgcpu;
  19. {$i fpcdefs.inc}
  20. interface
  21. uses
  22. globtype,symtype,symdef,
  23. cgbase,cgutils,cgobj,
  24. aasmbase,aasmcpu,aasmtai,aasmdata,
  25. parabase,
  26. cpubase,cpuinfo,node,cg64f32,rgcpu;
  27. type
  28. tcgarm = class(tcg)
  29. { true, if the next arithmetic operation should modify the flags }
  30. cgsetflags : boolean;
  31. procedure init_register_allocators;override;
  32. procedure done_register_allocators;override;
  33. procedure a_param_const(list : TAsmList;size : tcgsize;a : aint;const paraloc : TCGPara);override;
  34. procedure a_param_ref(list : TAsmList;size : tcgsize;const r : treference;const paraloc : TCGPara);override;
  35. procedure a_paramaddr_ref(list : TAsmList;const r : treference;const paraloc : TCGPara);override;
  36. procedure a_call_name(list : TAsmList;const s : string);override;
  37. procedure a_call_reg(list : TAsmList;reg: tregister);override;
  38. procedure a_call_ref(list : TAsmList;ref: treference);override;
  39. procedure a_op_const_reg(list : TAsmList; Op: TOpCG; size: TCGSize; a: aint; reg: TRegister); override;
  40. procedure a_op_reg_reg(list : TAsmList; Op: TOpCG; size: TCGSize; src, dst: TRegister); override;
  41. procedure a_op_const_reg_reg(list: TAsmList; op: TOpCg;
  42. size: tcgsize; a: aint; src, dst: tregister); override;
  43. procedure a_op_reg_reg_reg(list: TAsmList; op: TOpCg;
  44. size: tcgsize; src1, src2, dst: tregister); override;
  45. procedure a_op_const_reg_reg_checkoverflow(list: TAsmList; op: TOpCg; size: tcgsize; a: aint; src, dst: tregister;setflags : boolean;var ovloc : tlocation);override;
  46. procedure a_op_reg_reg_reg_checkoverflow(list: TAsmList; op: TOpCg; size: tcgsize; src1, src2, dst: tregister;setflags : boolean;var ovloc : tlocation);override;
  47. { move instructions }
  48. procedure a_load_const_reg(list : TAsmList; size: tcgsize; a : aint;reg : tregister);override;
  49. procedure a_load_reg_ref(list : TAsmList; fromsize, tosize: tcgsize; reg : tregister;const ref : treference);override;
  50. procedure a_load_ref_reg(list : TAsmList; fromsize, tosize : tcgsize;const Ref : treference;reg : tregister);override;
  51. procedure a_load_reg_reg(list : TAsmList; fromsize, tosize : tcgsize;reg1,reg2 : tregister);override;
  52. function a_internal_load_reg_ref(list : TAsmList; fromsize, tosize: tcgsize; reg : tregister;const ref : treference):treference;
  53. function a_internal_load_ref_reg(list : TAsmList; fromsize, tosize : tcgsize;const Ref : treference;reg : tregister):treference;
  54. { fpu move instructions }
  55. procedure a_loadfpu_reg_reg(list: TAsmList; fromsize, tosize: tcgsize; reg1, reg2: tregister); override;
  56. procedure a_loadfpu_ref_reg(list: TAsmList; fromsize, tosize: tcgsize; const ref: treference; reg: tregister); override;
  57. procedure a_loadfpu_reg_ref(list: TAsmList; fromsize, tosize: tcgsize; reg: tregister; const ref: treference); override;
  58. procedure a_paramfpu_ref(list : TAsmList;size : tcgsize;const ref : treference;const paraloc : TCGPara);override;
  59. { comparison operations }
  60. procedure a_cmp_const_reg_label(list : TAsmList;size : tcgsize;cmp_op : topcmp;a : aint;reg : tregister;
  61. l : tasmlabel);override;
  62. procedure a_cmp_reg_reg_label(list : TAsmList;size : tcgsize;cmp_op : topcmp;reg1,reg2 : tregister;l : tasmlabel); override;
  63. procedure a_jmp_name(list : TAsmList;const s : string); override;
  64. procedure a_jmp_always(list : TAsmList;l: tasmlabel); override;
  65. procedure a_jmp_flags(list : TAsmList;const f : TResFlags;l: tasmlabel); override;
  66. procedure g_flags2reg(list: TAsmList; size: TCgSize; const f: TResFlags; reg: TRegister); override;
  67. procedure g_proc_entry(list : TAsmList;localsize : longint;nostackframe:boolean);override;
  68. procedure g_proc_exit(list : TAsmList;parasize : longint;nostackframe:boolean); override;
  69. procedure a_loadaddr_ref_reg(list : TAsmList;const ref : treference;r : tregister);override;
  70. procedure g_concatcopy(list : TAsmList;const source,dest : treference;len : aint);override;
  71. procedure g_concatcopy_unaligned(list : TAsmList;const source,dest : treference;len : aint);override;
  72. procedure g_concatcopy_move(list : TAsmList;const source,dest : treference;len : aint);
  73. procedure g_concatcopy_internal(list : TAsmList;const source,dest : treference;len : aint;aligned : boolean);
  74. procedure g_overflowcheck(list: TAsmList; const l: tlocation; def: tdef); override;
  75. procedure g_overflowCheck_loc(List:TAsmList;const Loc:TLocation;def:TDef;ovloc : tlocation);override;
  76. procedure g_save_registers(list : TAsmList);override;
  77. procedure g_restore_registers(list : TAsmList);override;
  78. procedure a_jmp_cond(list : TAsmList;cond : TOpCmp;l: tasmlabel);
  79. procedure fixref(list : TAsmList;var ref : treference);
  80. function handle_load_store(list:TAsmList;op: tasmop;oppostfix : toppostfix;reg:tregister;ref: treference):treference;
  81. procedure g_intf_wrapper(list: TAsmList; procdef: tprocdef; const labelname: string; ioffset: longint);override;
  82. procedure g_adjust_self_value(list:TAsmList;procdef: tprocdef;ioffset: aint); override;
  83. 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. if (TCGSize2Size[FromSize] >= TCGSize2Size[ToSize]) then
  698. FromSize := ToSize;
  699. case ToSize of
  700. { signed integer registers }
  701. OS_8,
  702. OS_S8:
  703. oppostfix:=PF_B;
  704. OS_16,
  705. OS_S16:
  706. oppostfix:=PF_H;
  707. OS_32,
  708. OS_S32:
  709. oppostfix:=PF_None;
  710. else
  711. InternalError(200308295);
  712. end;
  713. if (ref.alignment in [1,2]) and (ref.alignment<tcgsize2size[tosize]) then
  714. begin
  715. if target_info.endian=endian_big then
  716. dir:=-1
  717. else
  718. dir:=1;
  719. case FromSize of
  720. OS_16,OS_S16:
  721. begin
  722. shifterop_reset(so);so.shiftmode:=SM_LSR;so.shiftimm:=8;
  723. tmpreg:=getintregister(list,OS_INT);
  724. usedtmpref:=ref;
  725. if target_info.endian=endian_big then
  726. inc(usedtmpref.offset,1);
  727. usedtmpref:=a_internal_load_reg_ref(list,OS_8,OS_8,reg,usedtmpref);
  728. inc(usedtmpref.offset,dir);
  729. list.concat(taicpu.op_reg_reg_shifterop(A_MOV,tmpreg,reg,so));
  730. a_internal_load_reg_ref(list,OS_8,OS_8,tmpreg,usedtmpref);
  731. end;
  732. OS_32,OS_S32:
  733. begin
  734. tmpreg:=getintregister(list,OS_INT);
  735. usedtmpref:=ref;
  736. shifterop_reset(so);so.shiftmode:=SM_LSR;
  737. if ref.alignment=2 then
  738. begin
  739. so.shiftimm:=16;
  740. if target_info.endian=endian_big then
  741. inc(usedtmpref.offset,2);
  742. usedtmpref:=a_internal_load_reg_ref(list,OS_16,OS_16,reg,usedtmpref);
  743. list.concat(taicpu.op_reg_reg_shifterop(A_MOV,tmpreg,reg,so));
  744. inc(usedtmpref.offset,dir*2);
  745. a_internal_load_reg_ref(list,OS_16,OS_16,tmpreg,usedtmpref);
  746. end
  747. else
  748. begin
  749. so.shiftimm:=8;
  750. if target_info.endian=endian_big then
  751. inc(usedtmpref.offset,3);
  752. usedtmpref:=a_internal_load_reg_ref(list,OS_8,OS_8,reg,usedtmpref);
  753. list.concat(taicpu.op_reg_reg_shifterop(A_MOV,tmpreg,reg,so));
  754. inc(usedtmpref.offset,dir);
  755. a_internal_load_reg_ref(list,OS_8,OS_8,tmpreg,usedtmpref);
  756. list.concat(taicpu.op_reg_reg_shifterop(A_MOV,tmpreg,tmpreg,so));
  757. inc(usedtmpref.offset,dir);
  758. a_internal_load_reg_ref(list,OS_8,OS_8,tmpreg,usedtmpref);
  759. list.concat(taicpu.op_reg_reg_shifterop(A_MOV,tmpreg,tmpreg,so));
  760. inc(usedtmpref.offset,dir);
  761. a_internal_load_reg_ref(list,OS_8,OS_8,tmpreg,usedtmpref);
  762. end;
  763. end
  764. else
  765. handle_load_store(list,A_STR,oppostfix,reg,ref);
  766. end;
  767. end
  768. else
  769. handle_load_store(list,A_STR,oppostfix,reg,ref);
  770. end;
  771. procedure tcgarm.a_load_ref_reg(list : TAsmList; fromsize, tosize : tcgsize;const Ref : treference;reg : tregister);
  772. var
  773. oppostfix:toppostfix;
  774. usedtmpref: treference;
  775. tmpreg,tmpreg2 : tregister;
  776. so : tshifterop;
  777. dir : integer;
  778. begin
  779. if (TCGSize2Size[FromSize] >= TCGSize2Size[ToSize]) then
  780. FromSize := ToSize;
  781. case FromSize of
  782. { signed integer registers }
  783. OS_8:
  784. oppostfix:=PF_B;
  785. OS_S8:
  786. oppostfix:=PF_SB;
  787. OS_16:
  788. oppostfix:=PF_H;
  789. OS_S16:
  790. oppostfix:=PF_SH;
  791. OS_32,
  792. OS_S32:
  793. oppostfix:=PF_None;
  794. else
  795. InternalError(200308297);
  796. end;
  797. if (ref.alignment in [1,2]) and (ref.alignment<tcgsize2size[fromsize]) then
  798. begin
  799. if target_info.endian=endian_big then
  800. dir:=-1
  801. else
  802. dir:=1;
  803. case FromSize of
  804. OS_16,OS_S16:
  805. begin
  806. { only complicated references need an extra loadaddr }
  807. if assigned(ref.symbol) or
  808. (ref.index<>NR_NO) or
  809. (ref.offset<-4095) or
  810. (ref.offset>4094) or
  811. { sometimes the compiler reused registers }
  812. (reg=ref.index) or
  813. (reg=ref.base) then
  814. begin
  815. tmpreg2:=getintregister(list,OS_INT);
  816. a_loadaddr_ref_reg(list,ref,tmpreg2);
  817. reference_reset_base(usedtmpref,tmpreg2,0);
  818. end
  819. else
  820. usedtmpref:=ref;
  821. if target_info.endian=endian_big then
  822. inc(usedtmpref.offset,1);
  823. shifterop_reset(so);so.shiftmode:=SM_LSL;so.shiftimm:=8;
  824. tmpreg:=getintregister(list,OS_INT);
  825. a_internal_load_ref_reg(list,OS_8,OS_8,usedtmpref,reg);
  826. inc(usedtmpref.offset,dir);
  827. if FromSize=OS_16 then
  828. a_internal_load_ref_reg(list,OS_8,OS_8,usedtmpref,tmpreg)
  829. else
  830. a_internal_load_ref_reg(list,OS_S8,OS_S8,usedtmpref,tmpreg);
  831. list.concat(taicpu.op_reg_reg_reg_shifterop(A_ORR,reg,reg,tmpreg,so));
  832. end;
  833. OS_32,OS_S32:
  834. begin
  835. tmpreg:=getintregister(list,OS_INT);
  836. { only complicated references need an extra loadaddr }
  837. if assigned(ref.symbol) or
  838. (ref.index<>NR_NO) or
  839. (ref.offset<-4095) or
  840. (ref.offset>4092) or
  841. { sometimes the compiler reused registers }
  842. (reg=ref.index) or
  843. (reg=ref.base) then
  844. begin
  845. tmpreg2:=getintregister(list,OS_INT);
  846. a_loadaddr_ref_reg(list,ref,tmpreg2);
  847. reference_reset_base(usedtmpref,tmpreg2,0);
  848. end
  849. else
  850. usedtmpref:=ref;
  851. shifterop_reset(so);so.shiftmode:=SM_LSL;
  852. if ref.alignment=2 then
  853. begin
  854. if target_info.endian=endian_big then
  855. inc(usedtmpref.offset,2);
  856. a_internal_load_ref_reg(list,OS_16,OS_16,usedtmpref,reg);
  857. inc(usedtmpref.offset,dir*2);
  858. a_internal_load_ref_reg(list,OS_16,OS_16,usedtmpref,tmpreg);
  859. so.shiftimm:=16;
  860. list.concat(taicpu.op_reg_reg_reg_shifterop(A_ORR,reg,reg,tmpreg,so));
  861. end
  862. else
  863. begin
  864. if target_info.endian=endian_big then
  865. inc(usedtmpref.offset,3);
  866. a_internal_load_ref_reg(list,OS_8,OS_8,usedtmpref,reg);
  867. inc(usedtmpref.offset,dir);
  868. a_internal_load_ref_reg(list,OS_8,OS_8,usedtmpref,tmpreg);
  869. so.shiftimm:=8;
  870. list.concat(taicpu.op_reg_reg_reg_shifterop(A_ORR,reg,reg,tmpreg,so));
  871. inc(usedtmpref.offset,dir);
  872. a_internal_load_ref_reg(list,OS_8,OS_8,usedtmpref,tmpreg);
  873. so.shiftimm:=16;
  874. list.concat(taicpu.op_reg_reg_reg_shifterop(A_ORR,reg,reg,tmpreg,so));
  875. inc(usedtmpref.offset,dir);
  876. a_internal_load_ref_reg(list,OS_8,OS_8,usedtmpref,tmpreg);
  877. so.shiftimm:=24;
  878. list.concat(taicpu.op_reg_reg_reg_shifterop(A_ORR,reg,reg,tmpreg,so));
  879. end;
  880. end
  881. else
  882. handle_load_store(list,A_LDR,oppostfix,reg,ref);
  883. end;
  884. end
  885. else
  886. handle_load_store(list,A_LDR,oppostfix,reg,ref);
  887. if (fromsize=OS_S8) and (tosize = OS_16) then
  888. a_load_reg_reg(list,OS_16,OS_32,reg,reg);
  889. end;
  890. function tcgarm.a_internal_load_reg_ref(list : TAsmList; fromsize, tosize: tcgsize; reg : tregister;const ref : treference):treference;
  891. var
  892. oppostfix:toppostfix;
  893. begin
  894. case ToSize of
  895. { signed integer registers }
  896. OS_8,
  897. OS_S8:
  898. oppostfix:=PF_B;
  899. OS_16,
  900. OS_S16:
  901. oppostfix:=PF_H;
  902. OS_32,
  903. OS_S32:
  904. oppostfix:=PF_None;
  905. else
  906. InternalError(2003082910);
  907. end;
  908. result:=handle_load_store(list,A_STR,oppostfix,reg,ref);
  909. end;
  910. function tcgarm.a_internal_load_ref_reg(list : TAsmList; fromsize, tosize : tcgsize;const Ref : treference;reg : tregister):treference;
  911. var
  912. oppostfix:toppostfix;
  913. begin
  914. case FromSize of
  915. { signed integer registers }
  916. OS_8:
  917. oppostfix:=PF_B;
  918. OS_S8:
  919. oppostfix:=PF_SB;
  920. OS_16:
  921. oppostfix:=PF_H;
  922. OS_S16:
  923. oppostfix:=PF_SH;
  924. OS_32,
  925. OS_S32:
  926. oppostfix:=PF_None;
  927. else
  928. InternalError(200308291);
  929. end;
  930. result:=handle_load_store(list,A_LDR,oppostfix,reg,ref);
  931. end;
  932. procedure tcgarm.a_load_reg_reg(list : TAsmList; fromsize, tosize : tcgsize;reg1,reg2 : tregister);
  933. var
  934. so : tshifterop;
  935. procedure do_shift(shiftmode : tshiftmode; shiftimm : byte; reg : tregister);
  936. begin
  937. so.shiftmode:=shiftmode;
  938. so.shiftimm:=shiftimm;
  939. list.concat(taicpu.op_reg_reg_shifterop(A_MOV,reg2,reg,so));
  940. end;
  941. var
  942. instr: taicpu;
  943. conv_done: boolean;
  944. begin
  945. if (tcgsize2size[fromsize]>32) or (tcgsize2size[tosize]>32) or (fromsize=OS_NO) or (tosize=OS_NO) then
  946. internalerror(2002090901);
  947. conv_done:=false;
  948. if tosize<>fromsize then
  949. begin
  950. shifterop_reset(so);
  951. conv_done:=true;
  952. if tcgsize2size[tosize]<=tcgsize2size[fromsize] then
  953. fromsize:=tosize;
  954. case fromsize of
  955. OS_8:
  956. list.concat(taicpu.op_reg_reg_const(A_AND,reg2,reg1,$ff));
  957. OS_S8:
  958. begin
  959. do_shift(SM_LSL,24,reg1);
  960. if tosize=OS_16 then
  961. begin
  962. do_shift(SM_ASR,8,reg2);
  963. do_shift(SM_LSR,16,reg2);
  964. end
  965. else
  966. do_shift(SM_ASR,24,reg2);
  967. end;
  968. OS_16:
  969. begin
  970. do_shift(SM_LSL,16,reg1);
  971. do_shift(SM_LSR,16,reg2);
  972. end;
  973. OS_S16:
  974. begin
  975. do_shift(SM_LSL,16,reg1);
  976. do_shift(SM_ASR,16,reg2)
  977. end;
  978. else
  979. conv_done:=false;
  980. end;
  981. end;
  982. if not conv_done and (reg1<>reg2) then
  983. begin
  984. { same size, only a register mov required }
  985. instr:=taicpu.op_reg_reg(A_MOV,reg2,reg1);
  986. list.Concat(instr);
  987. { Notify the register allocator that we have written a move instruction so
  988. it can try to eliminate it. }
  989. add_move_instruction(instr);
  990. end;
  991. end;
  992. procedure tcgarm.a_paramfpu_ref(list : TAsmList;size : tcgsize;const ref : treference;const paraloc : TCGPara);
  993. var
  994. href,href2 : treference;
  995. hloc : pcgparalocation;
  996. begin
  997. href:=ref;
  998. hloc:=paraloc.location;
  999. while assigned(hloc) do
  1000. begin
  1001. case hloc^.loc of
  1002. LOC_FPUREGISTER,LOC_CFPUREGISTER:
  1003. a_loadfpu_ref_reg(list,size,size,ref,hloc^.register);
  1004. LOC_REGISTER :
  1005. case hloc^.size of
  1006. OS_F32:
  1007. a_load_ref_reg(list,OS_32,OS_32,href,hloc^.register);
  1008. OS_64,
  1009. OS_F64:
  1010. cg64.a_param64_ref(list,href,paraloc);
  1011. else
  1012. a_load_ref_reg(list,hloc^.size,hloc^.size,href,hloc^.register);
  1013. end;
  1014. LOC_REFERENCE :
  1015. begin
  1016. reference_reset_base(href2,hloc^.reference.index,hloc^.reference.offset);
  1017. { concatcopy should choose the best way to copy the data }
  1018. g_concatcopy(list,href,href2,tcgsize2size[size]);
  1019. end;
  1020. else
  1021. internalerror(200408241);
  1022. end;
  1023. inc(href.offset,tcgsize2size[hloc^.size]);
  1024. hloc:=hloc^.next;
  1025. end;
  1026. end;
  1027. procedure tcgarm.a_loadfpu_reg_reg(list: TAsmList; fromsize,tosize: tcgsize; reg1, reg2: tregister);
  1028. begin
  1029. list.concat(setoppostfix(taicpu.op_reg_reg(A_MVF,reg2,reg1),cgsize2fpuoppostfix[tosize]));
  1030. end;
  1031. procedure tcgarm.a_loadfpu_ref_reg(list: TAsmList; fromsize,tosize: tcgsize; const ref: treference; reg: tregister);
  1032. var
  1033. oppostfix:toppostfix;
  1034. begin
  1035. case fromsize of
  1036. OS_32,
  1037. OS_F32:
  1038. oppostfix:=PF_S;
  1039. OS_64,
  1040. OS_F64:
  1041. oppostfix:=PF_D;
  1042. OS_F80:
  1043. oppostfix:=PF_E;
  1044. else
  1045. InternalError(200309021);
  1046. end;
  1047. handle_load_store(list,A_LDF,oppostfix,reg,ref);
  1048. if fromsize<>tosize then
  1049. a_loadfpu_reg_reg(list,fromsize,tosize,reg,reg);
  1050. end;
  1051. procedure tcgarm.a_loadfpu_reg_ref(list: TAsmList; fromsize, tosize: tcgsize; reg: tregister; const ref: treference);
  1052. var
  1053. oppostfix:toppostfix;
  1054. begin
  1055. case tosize of
  1056. OS_F32:
  1057. oppostfix:=PF_S;
  1058. OS_F64:
  1059. oppostfix:=PF_D;
  1060. OS_F80:
  1061. oppostfix:=PF_E;
  1062. else
  1063. InternalError(200309022);
  1064. end;
  1065. handle_load_store(list,A_STF,oppostfix,reg,ref);
  1066. end;
  1067. { comparison operations }
  1068. procedure tcgarm.a_cmp_const_reg_label(list : TAsmList;size : tcgsize;cmp_op : topcmp;a : aint;reg : tregister;
  1069. l : tasmlabel);
  1070. var
  1071. tmpreg : tregister;
  1072. b : byte;
  1073. begin
  1074. if is_shifter_const(a,b) then
  1075. list.concat(taicpu.op_reg_const(A_CMP,reg,a))
  1076. { CMN reg,0 and CMN reg,$80000000 are different from CMP reg,$ffffffff
  1077. and CMP reg,$7fffffff regarding the flags according to the ARM manual }
  1078. else if (a<>$7fffffff) and (a<>-1) and is_shifter_const(-a,b) then
  1079. list.concat(taicpu.op_reg_const(A_CMN,reg,-a))
  1080. else
  1081. begin
  1082. tmpreg:=getintregister(list,size);
  1083. a_load_const_reg(list,size,a,tmpreg);
  1084. list.concat(taicpu.op_reg_reg(A_CMP,reg,tmpreg));
  1085. end;
  1086. a_jmp_cond(list,cmp_op,l);
  1087. end;
  1088. procedure tcgarm.a_cmp_reg_reg_label(list : TAsmList;size : tcgsize;cmp_op : topcmp;reg1,reg2 : tregister;l : tasmlabel);
  1089. begin
  1090. list.concat(taicpu.op_reg_reg(A_CMP,reg2,reg1));
  1091. a_jmp_cond(list,cmp_op,l);
  1092. end;
  1093. procedure tcgarm.a_jmp_name(list : TAsmList;const s : string);
  1094. var
  1095. ai : taicpu;
  1096. begin
  1097. ai:=taicpu.op_sym(A_B,current_asmdata.RefAsmSymbol(s));
  1098. ai.is_jmp:=true;
  1099. list.concat(ai);
  1100. end;
  1101. procedure tcgarm.a_jmp_always(list : TAsmList;l: tasmlabel);
  1102. var
  1103. ai : taicpu;
  1104. begin
  1105. ai:=taicpu.op_sym(A_B,l);
  1106. ai.is_jmp:=true;
  1107. list.concat(ai);
  1108. end;
  1109. procedure tcgarm.a_jmp_flags(list : TAsmList;const f : TResFlags;l: tasmlabel);
  1110. var
  1111. ai : taicpu;
  1112. begin
  1113. ai:=setcondition(taicpu.op_sym(A_B,l),flags_to_cond(f));
  1114. ai.is_jmp:=true;
  1115. list.concat(ai);
  1116. end;
  1117. procedure tcgarm.g_flags2reg(list: TAsmList; size: TCgSize; const f: TResFlags; reg: TRegister);
  1118. begin
  1119. list.concat(setcondition(taicpu.op_reg_const(A_MOV,reg,1),flags_to_cond(f)));
  1120. list.concat(setcondition(taicpu.op_reg_const(A_MOV,reg,0),inverse_cond(flags_to_cond(f))));
  1121. end;
  1122. procedure tcgarm.g_proc_entry(list : TAsmList;localsize : longint;nostackframe:boolean);
  1123. var
  1124. ref : treference;
  1125. shift : byte;
  1126. firstfloatreg,lastfloatreg,
  1127. r : byte;
  1128. regs : tcpuregisterset;
  1129. begin
  1130. LocalSize:=align(LocalSize,4);
  1131. if not(nostackframe) then
  1132. begin
  1133. firstfloatreg:=RS_NO;
  1134. { save floating point registers? }
  1135. for r:=RS_F0 to RS_F7 do
  1136. if r in rg[R_FPUREGISTER].used_in_proc-paramanager.get_volatile_registers_fpu(pocall_stdcall) then
  1137. begin
  1138. if firstfloatreg=RS_NO then
  1139. firstfloatreg:=r;
  1140. lastfloatreg:=r;
  1141. end;
  1142. a_reg_alloc(list,NR_STACK_POINTER_REG);
  1143. if current_procinfo.framepointer<>NR_STACK_POINTER_REG then
  1144. begin
  1145. a_reg_alloc(list,NR_FRAME_POINTER_REG);
  1146. a_reg_alloc(list,NR_R12);
  1147. list.concat(taicpu.op_reg_reg(A_MOV,NR_R12,NR_STACK_POINTER_REG));
  1148. end;
  1149. { save int registers }
  1150. reference_reset(ref);
  1151. ref.index:=NR_STACK_POINTER_REG;
  1152. ref.addressmode:=AM_PREINDEXED;
  1153. regs:=rg[R_INTREGISTER].used_in_proc-paramanager.get_volatile_registers_int(pocall_stdcall);
  1154. if current_procinfo.framepointer<>NR_STACK_POINTER_REG then
  1155. regs:=regs+[RS_R11,RS_R12,RS_R14,RS_R15]
  1156. else
  1157. if (regs<>[]) or (pi_do_call in current_procinfo.flags) then
  1158. include(regs,RS_R14);
  1159. if regs<>[] then
  1160. list.concat(setoppostfix(taicpu.op_ref_regset(A_STM,ref,regs),PF_FD));
  1161. if current_procinfo.framepointer<>NR_STACK_POINTER_REG then
  1162. list.concat(taicpu.op_reg_reg_const(A_SUB,NR_FRAME_POINTER_REG,NR_R12,4));
  1163. (* allocate necessary stack size
  1164. not necessary according to Yury Sidorov
  1165. { don't use a_op_const_reg_reg here because we don't allow register allocations
  1166. in the entry/exit code }
  1167. if (target_info.system in [system_arm_wince]) and
  1168. (localsize>=winstackpagesize) then
  1169. begin
  1170. if localsize div winstackpagesize<=5 then
  1171. begin
  1172. if is_shifter_const(localsize,shift) then
  1173. list.concat(Taicpu.op_reg_reg_const(A_SUB,NR_STACK_POINTER_REG,NR_STACK_POINTER_REG,localsize))
  1174. else
  1175. begin
  1176. a_load_const_reg(list,OS_ADDR,localsize,NR_R12);
  1177. list.concat(taicpu.op_reg_reg_reg(A_SUB,NR_STACK_POINTER_REG,NR_STACK_POINTER_REG,NR_R12));
  1178. end;
  1179. for i:=1 to localsize div winstackpagesize do
  1180. begin
  1181. if localsize-i*winstackpagesize<4096 then
  1182. reference_reset_base(href,NR_STACK_POINTER_REG,-(localsize-i*winstackpagesize))
  1183. else
  1184. begin
  1185. a_load_const_reg(list,OS_ADDR,-(localsize-i*winstackpagesize),NR_R12);
  1186. reference_reset_base(href,NR_STACK_POINTER_REG,0);
  1187. href.index:=NR_R12;
  1188. end;
  1189. { the data stored doesn't matter }
  1190. list.concat(Taicpu.op_reg_ref(A_STR,NR_R0,href));
  1191. end;
  1192. a_reg_dealloc(list,NR_R12);
  1193. reference_reset_base(href,NR_STACK_POINTER_REG,0);
  1194. { the data stored doesn't matter }
  1195. list.concat(Taicpu.op_reg_ref(A_STR,NR_R0,href));
  1196. end
  1197. else
  1198. begin
  1199. current_asmdata.getjumplabel(again);
  1200. list.concat(Taicpu.op_reg_const(A_MOV,NR_R12,localsize div winstackpagesize));
  1201. a_label(list,again);
  1202. { always shifterop }
  1203. list.concat(Taicpu.op_reg_reg_const(A_SUB,NR_STACK_POINTER_REG,NR_STACK_POINTER_REG,winstackpagesize));
  1204. reference_reset_base(href,NR_STACK_POINTER_REG,0);
  1205. { the data stored doesn't matter }
  1206. list.concat(Taicpu.op_reg_ref(A_STR,NR_R0,href));
  1207. list.concat(Taicpu.op_reg_reg_const(A_SUB,NR_R12,NR_R12,1));
  1208. a_jmp_cond(list,OC_NE,again);
  1209. if is_shifter_const(localsize mod winstackpagesize,shift) then
  1210. list.concat(Taicpu.op_reg_reg_const(A_SUB,NR_STACK_POINTER_REG,NR_STACK_POINTER_REG,localsize mod winstackpagesize))
  1211. else
  1212. begin
  1213. a_load_const_reg(list,OS_ADDR,localsize mod winstackpagesize,NR_R12);
  1214. list.concat(taicpu.op_reg_reg_reg(A_SUB,NR_STACK_POINTER_REG,NR_STACK_POINTER_REG,NR_R12));
  1215. end;
  1216. a_reg_dealloc(list,NR_R12);
  1217. reference_reset_base(href,NR_STACK_POINTER_REG,0);
  1218. { the data stored doesn't matter }
  1219. list.concat(Taicpu.op_reg_ref(A_STR,NR_R0,href));
  1220. end
  1221. end
  1222. else
  1223. *)
  1224. if LocalSize<>0 then
  1225. if not(is_shifter_const(localsize,shift)) then
  1226. begin
  1227. if current_procinfo.framepointer=NR_STACK_POINTER_REG then
  1228. a_reg_alloc(list,NR_R12);
  1229. a_load_const_reg(list,OS_ADDR,LocalSize,NR_R12);
  1230. list.concat(taicpu.op_reg_reg_reg(A_SUB,NR_STACK_POINTER_REG,NR_STACK_POINTER_REG,NR_R12));
  1231. a_reg_dealloc(list,NR_R12);
  1232. end
  1233. else
  1234. begin
  1235. a_reg_dealloc(list,NR_R12);
  1236. list.concat(taicpu.op_reg_reg_const(A_SUB,NR_STACK_POINTER_REG,NR_STACK_POINTER_REG,LocalSize));
  1237. end;
  1238. if firstfloatreg<>RS_NO then
  1239. begin
  1240. reference_reset(ref);
  1241. if tg.direction*tarmprocinfo(current_procinfo).floatregstart>=1023 then
  1242. begin
  1243. a_load_const_reg(list,OS_ADDR,-tarmprocinfo(current_procinfo).floatregstart,NR_R12);
  1244. list.concat(taicpu.op_reg_reg_reg(A_SUB,NR_R12,current_procinfo.framepointer,NR_R12));
  1245. ref.base:=NR_R12;
  1246. end
  1247. else
  1248. begin
  1249. ref.base:=current_procinfo.framepointer;
  1250. ref.offset:=tarmprocinfo(current_procinfo).floatregstart;
  1251. end;
  1252. list.concat(taicpu.op_reg_const_ref(A_SFM,newreg(R_FPUREGISTER,firstfloatreg,R_SUBWHOLE),
  1253. lastfloatreg-firstfloatreg+1,ref));
  1254. end;
  1255. end;
  1256. end;
  1257. procedure tcgarm.g_proc_exit(list : TAsmList;parasize : longint;nostackframe:boolean);
  1258. var
  1259. ref : treference;
  1260. firstfloatreg,lastfloatreg,
  1261. r : byte;
  1262. shift : byte;
  1263. regs : tcpuregisterset;
  1264. LocalSize : longint;
  1265. begin
  1266. if not(nostackframe) then
  1267. begin
  1268. { restore floating point register }
  1269. firstfloatreg:=RS_NO;
  1270. { save floating point registers? }
  1271. for r:=RS_F0 to RS_F7 do
  1272. if r in rg[R_FPUREGISTER].used_in_proc-paramanager.get_volatile_registers_fpu(pocall_stdcall) then
  1273. begin
  1274. if firstfloatreg=RS_NO then
  1275. firstfloatreg:=r;
  1276. lastfloatreg:=r;
  1277. end;
  1278. if firstfloatreg<>RS_NO then
  1279. begin
  1280. reference_reset(ref);
  1281. if tg.direction*tarmprocinfo(current_procinfo).floatregstart>=1023 then
  1282. begin
  1283. a_load_const_reg(list,OS_ADDR,-tarmprocinfo(current_procinfo).floatregstart,NR_R12);
  1284. list.concat(taicpu.op_reg_reg_reg(A_SUB,NR_R12,current_procinfo.framepointer,NR_R12));
  1285. ref.base:=NR_R12;
  1286. end
  1287. else
  1288. begin
  1289. ref.base:=current_procinfo.framepointer;
  1290. ref.offset:=tarmprocinfo(current_procinfo).floatregstart;
  1291. end;
  1292. list.concat(taicpu.op_reg_const_ref(A_LFM,newreg(R_FPUREGISTER,firstfloatreg,R_SUBWHOLE),
  1293. lastfloatreg-firstfloatreg+1,ref));
  1294. end;
  1295. if (current_procinfo.framepointer=NR_STACK_POINTER_REG) then
  1296. begin
  1297. LocalSize:=current_procinfo.calc_stackframe_size;
  1298. if LocalSize<>0 then
  1299. if not(is_shifter_const(LocalSize,shift)) then
  1300. begin
  1301. a_reg_alloc(list,NR_R12);
  1302. a_load_const_reg(list,OS_ADDR,LocalSize,NR_R12);
  1303. list.concat(taicpu.op_reg_reg_reg(A_ADD,NR_STACK_POINTER_REG,NR_STACK_POINTER_REG,NR_R12));
  1304. a_reg_dealloc(list,NR_R12);
  1305. end
  1306. else
  1307. begin
  1308. list.concat(taicpu.op_reg_reg_const(A_ADD,NR_STACK_POINTER_REG,NR_STACK_POINTER_REG,LocalSize));
  1309. end;
  1310. regs:=rg[R_INTREGISTER].used_in_proc-paramanager.get_volatile_registers_int(pocall_stdcall);
  1311. if (pi_do_call in current_procinfo.flags) or (regs<>[]) then
  1312. begin
  1313. exclude(regs,RS_R14);
  1314. include(regs,RS_R15);
  1315. end;
  1316. if regs=[] then
  1317. list.concat(taicpu.op_reg_reg(A_MOV,NR_R15,NR_R14))
  1318. else
  1319. begin
  1320. reference_reset(ref);
  1321. ref.index:=NR_STACK_POINTER_REG;
  1322. ref.addressmode:=AM_PREINDEXED;
  1323. list.concat(setoppostfix(taicpu.op_ref_regset(A_LDM,ref,regs),PF_FD));
  1324. end;
  1325. end
  1326. else
  1327. begin
  1328. { restore int registers and return }
  1329. reference_reset(ref);
  1330. ref.index:=NR_FRAME_POINTER_REG;
  1331. 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));
  1332. end;
  1333. end
  1334. else
  1335. list.concat(taicpu.op_reg_reg(A_MOV,NR_PC,NR_R14));
  1336. end;
  1337. procedure tcgarm.a_loadaddr_ref_reg(list : TAsmList;const ref : treference;r : tregister);
  1338. var
  1339. b : byte;
  1340. tmpref : treference;
  1341. instr : taicpu;
  1342. begin
  1343. if ref.addressmode<>AM_OFFSET then
  1344. internalerror(200309071);
  1345. tmpref:=ref;
  1346. { Be sure to have a base register }
  1347. if (tmpref.base=NR_NO) then
  1348. begin
  1349. if tmpref.shiftmode<>SM_None then
  1350. internalerror(200308294);
  1351. if tmpref.signindex<0 then
  1352. internalerror(200312023);
  1353. tmpref.base:=tmpref.index;
  1354. tmpref.index:=NR_NO;
  1355. end;
  1356. if assigned(tmpref.symbol) or
  1357. not((is_shifter_const(tmpref.offset,b)) or
  1358. (is_shifter_const(-tmpref.offset,b))
  1359. ) then
  1360. fixref(list,tmpref);
  1361. { expect a base here if there is an index }
  1362. if (tmpref.base=NR_NO) and (tmpref.index<>NR_NO) then
  1363. internalerror(200312022);
  1364. if tmpref.index<>NR_NO then
  1365. begin
  1366. if tmpref.shiftmode<>SM_None then
  1367. internalerror(200312021);
  1368. if tmpref.signindex<0 then
  1369. a_op_reg_reg_reg(list,OP_SUB,OS_ADDR,tmpref.base,tmpref.index,r)
  1370. else
  1371. a_op_reg_reg_reg(list,OP_ADD,OS_ADDR,tmpref.base,tmpref.index,r);
  1372. if tmpref.offset<>0 then
  1373. a_op_const_reg_reg(list,OP_ADD,OS_ADDR,tmpref.offset,r,r);
  1374. end
  1375. else
  1376. begin
  1377. if tmpref.base=NR_NO then
  1378. a_load_const_reg(list,OS_ADDR,tmpref.offset,r)
  1379. else
  1380. if tmpref.offset<>0 then
  1381. a_op_const_reg_reg(list,OP_ADD,OS_ADDR,tmpref.offset,tmpref.base,r)
  1382. else
  1383. begin
  1384. instr:=taicpu.op_reg_reg(A_MOV,r,tmpref.base);
  1385. list.concat(instr);
  1386. add_move_instruction(instr);
  1387. end;
  1388. end;
  1389. end;
  1390. procedure tcgarm.fixref(list : TAsmList;var ref : treference);
  1391. var
  1392. tmpreg : tregister;
  1393. tmpref : treference;
  1394. l : tasmlabel;
  1395. begin
  1396. { absolute symbols can't be handled directly, we've to store the symbol reference
  1397. in the text segment and access it pc relative
  1398. For now, we assume that references where base or index equals to PC are already
  1399. relative, all other references are assumed to be absolute and thus they need
  1400. to be handled extra.
  1401. A proper solution would be to change refoptions to a set and store the information
  1402. if the symbol is absolute or relative there.
  1403. }
  1404. { create consts entry }
  1405. reference_reset(tmpref);
  1406. current_asmdata.getjumplabel(l);
  1407. cg.a_label(current_procinfo.aktlocaldata,l);
  1408. tmpref.symboldata:=current_procinfo.aktlocaldata.last;
  1409. if assigned(ref.symbol) then
  1410. current_procinfo.aktlocaldata.concat(tai_const.create_sym_offset(ref.symbol,ref.offset))
  1411. else
  1412. current_procinfo.aktlocaldata.concat(tai_const.Create_32bit(ref.offset));
  1413. { load consts entry }
  1414. tmpreg:=getintregister(list,OS_INT);
  1415. tmpref.symbol:=l;
  1416. tmpref.base:=NR_PC;
  1417. list.concat(taicpu.op_reg_ref(A_LDR,tmpreg,tmpref));
  1418. if (ref.base<>NR_NO) then
  1419. begin
  1420. if ref.index<>NR_NO then
  1421. begin
  1422. list.concat(taicpu.op_reg_reg_reg(A_ADD,tmpreg,ref.base,tmpreg));
  1423. ref.base:=tmpreg;
  1424. end
  1425. else
  1426. if ref.base<>NR_PC then
  1427. begin
  1428. ref.index:=tmpreg;
  1429. ref.shiftimm:=0;
  1430. ref.signindex:=1;
  1431. ref.shiftmode:=SM_None;
  1432. end
  1433. else
  1434. ref.base:=tmpreg;
  1435. end
  1436. else
  1437. ref.base:=tmpreg;
  1438. ref.offset:=0;
  1439. ref.symbol:=nil;
  1440. end;
  1441. procedure tcgarm.g_concatcopy_move(list : TAsmList;const source,dest : treference;len : aint);
  1442. var
  1443. paraloc1,paraloc2,paraloc3 : TCGPara;
  1444. begin
  1445. paraloc1.init;
  1446. paraloc2.init;
  1447. paraloc3.init;
  1448. paramanager.getintparaloc(pocall_default,1,paraloc1);
  1449. paramanager.getintparaloc(pocall_default,2,paraloc2);
  1450. paramanager.getintparaloc(pocall_default,3,paraloc3);
  1451. paramanager.allocparaloc(list,paraloc3);
  1452. a_param_const(list,OS_INT,len,paraloc3);
  1453. paramanager.allocparaloc(list,paraloc2);
  1454. a_paramaddr_ref(list,dest,paraloc2);
  1455. paramanager.allocparaloc(list,paraloc2);
  1456. a_paramaddr_ref(list,source,paraloc1);
  1457. paramanager.freeparaloc(list,paraloc3);
  1458. paramanager.freeparaloc(list,paraloc2);
  1459. paramanager.freeparaloc(list,paraloc1);
  1460. alloccpuregisters(list,R_INTREGISTER,paramanager.get_volatile_registers_int(pocall_default));
  1461. alloccpuregisters(list,R_FPUREGISTER,paramanager.get_volatile_registers_fpu(pocall_default));
  1462. a_call_name(list,'FPC_MOVE');
  1463. dealloccpuregisters(list,R_FPUREGISTER,paramanager.get_volatile_registers_fpu(pocall_default));
  1464. dealloccpuregisters(list,R_INTREGISTER,paramanager.get_volatile_registers_int(pocall_default));
  1465. paraloc3.done;
  1466. paraloc2.done;
  1467. paraloc1.done;
  1468. end;
  1469. procedure tcgarm.g_concatcopy_internal(list : TAsmList;const source,dest : treference;len : aint;aligned : boolean);
  1470. const
  1471. 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}
  1472. var
  1473. srcref,dstref,usedtmpref,usedtmpref2:treference;
  1474. srcreg,destreg,countreg,r,tmpreg:tregister;
  1475. helpsize:aint;
  1476. copysize:byte;
  1477. cgsize:Tcgsize;
  1478. tmpregisters:array[1..maxtmpreg] of tregister;
  1479. tmpregi,tmpregi2:byte;
  1480. { will never be called with count<=4 }
  1481. procedure genloop(count : aword;size : byte);
  1482. const
  1483. size2opsize : array[1..4] of tcgsize = (OS_8,OS_16,OS_NO,OS_32);
  1484. var
  1485. l : tasmlabel;
  1486. begin
  1487. current_asmdata.getjumplabel(l);
  1488. if count<size then size:=1;
  1489. a_load_const_reg(list,OS_INT,count div size,countreg);
  1490. cg.a_label(list,l);
  1491. srcref.addressmode:=AM_POSTINDEXED;
  1492. dstref.addressmode:=AM_POSTINDEXED;
  1493. srcref.offset:=size;
  1494. dstref.offset:=size;
  1495. r:=getintregister(list,size2opsize[size]);
  1496. a_load_ref_reg(list,size2opsize[size],size2opsize[size],srcref,r);
  1497. list.concat(setoppostfix(taicpu.op_reg_reg_const(A_SUB,countreg,countreg,1),PF_S));
  1498. a_load_reg_ref(list,size2opsize[size],size2opsize[size],r,dstref);
  1499. a_jmp_flags(list,F_NE,l);
  1500. srcref.offset:=1;
  1501. dstref.offset:=1;
  1502. case count mod size of
  1503. 1:
  1504. begin
  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. end;
  1508. 2:
  1509. if aligned then
  1510. begin
  1511. a_load_ref_reg(list,OS_16,OS_16,srcref,r);
  1512. a_load_reg_ref(list,OS_16,OS_16,r,dstref);
  1513. end
  1514. else
  1515. begin
  1516. a_load_ref_reg(list,OS_8,OS_8,srcref,r);
  1517. a_load_reg_ref(list,OS_8,OS_8,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. 3:
  1522. if aligned then
  1523. begin
  1524. srcref.offset:=2;
  1525. dstref.offset:=2;
  1526. a_load_ref_reg(list,OS_16,OS_16,srcref,r);
  1527. a_load_reg_ref(list,OS_16,OS_16,r,dstref);
  1528. a_load_ref_reg(list,OS_8,OS_8,srcref,r);
  1529. a_load_reg_ref(list,OS_8,OS_8,r,dstref);
  1530. end
  1531. else
  1532. begin
  1533. a_load_ref_reg(list,OS_8,OS_8,srcref,r);
  1534. a_load_reg_ref(list,OS_8,OS_8,r,dstref);
  1535. a_load_ref_reg(list,OS_8,OS_8,srcref,r);
  1536. a_load_reg_ref(list,OS_8,OS_8,r,dstref);
  1537. a_load_ref_reg(list,OS_8,OS_8,srcref,r);
  1538. a_load_reg_ref(list,OS_8,OS_8,r,dstref);
  1539. end;
  1540. end;
  1541. { keep the registers alive }
  1542. list.concat(taicpu.op_reg_reg(A_MOV,countreg,countreg));
  1543. list.concat(taicpu.op_reg_reg(A_MOV,srcreg,srcreg));
  1544. list.concat(taicpu.op_reg_reg(A_MOV,destreg,destreg));
  1545. end;
  1546. begin
  1547. if len=0 then
  1548. exit;
  1549. helpsize:=12+maxtmpreg*4;//52 with maxtmpreg=10
  1550. dstref:=dest;
  1551. srcref:=source;
  1552. if cs_opt_size in current_settings.optimizerswitches then
  1553. helpsize:=8;
  1554. if (len<=helpsize) and aligned then
  1555. begin
  1556. tmpregi:=0;
  1557. srcreg:=getintregister(list,OS_ADDR);
  1558. { explicit pc relative addressing, could be
  1559. e.g. a floating point constant }
  1560. if source.base=NR_PC then
  1561. begin
  1562. { ... then we don't need a loadaddr }
  1563. srcref:=source;
  1564. end
  1565. else
  1566. begin
  1567. a_loadaddr_ref_reg(list,source,srcreg);
  1568. reference_reset_base(srcref,srcreg,0);
  1569. end;
  1570. while (len div 4 <> 0) and (tmpregi<maxtmpreg) do
  1571. begin
  1572. inc(tmpregi);
  1573. tmpregisters[tmpregi]:=getintregister(list,OS_32);
  1574. a_load_ref_reg(list,OS_32,OS_32,srcref,tmpregisters[tmpregi]);
  1575. inc(srcref.offset,4);
  1576. dec(len,4);
  1577. end;
  1578. destreg:=getintregister(list,OS_ADDR);
  1579. a_loadaddr_ref_reg(list,dest,destreg);
  1580. reference_reset_base(dstref,destreg,0);
  1581. tmpregi2:=1;
  1582. while (tmpregi2<=tmpregi) do
  1583. begin
  1584. a_load_reg_ref(list,OS_32,OS_32,tmpregisters[tmpregi2],dstref);
  1585. inc(dstref.offset,4);
  1586. inc(tmpregi2);
  1587. end;
  1588. copysize:=4;
  1589. cgsize:=OS_32;
  1590. while len<>0 do
  1591. begin
  1592. if len<2 then
  1593. begin
  1594. copysize:=1;
  1595. cgsize:=OS_8;
  1596. end
  1597. else if len<4 then
  1598. begin
  1599. copysize:=2;
  1600. cgsize:=OS_16;
  1601. end;
  1602. dec(len,copysize);
  1603. r:=getintregister(list,cgsize);
  1604. a_load_ref_reg(list,cgsize,cgsize,srcref,r);
  1605. a_load_reg_ref(list,cgsize,cgsize,r,dstref);
  1606. inc(srcref.offset,copysize);
  1607. inc(dstref.offset,copysize);
  1608. end;{end of while}
  1609. end
  1610. else
  1611. begin
  1612. cgsize:=OS_32;
  1613. if (len<=4) then{len<=4 and not aligned}
  1614. begin
  1615. r:=getintregister(list,cgsize);
  1616. usedtmpref:=a_internal_load_ref_reg(list,OS_8,OS_8,srcref,r);
  1617. if Len=1 then
  1618. a_load_reg_ref(list,OS_8,OS_8,r,dstref)
  1619. else
  1620. begin
  1621. tmpreg:=getintregister(list,cgsize);
  1622. usedtmpref2:=a_internal_load_reg_ref(list,OS_8,OS_8,r,dstref);
  1623. inc(usedtmpref.offset,1);
  1624. a_load_ref_reg(list,OS_8,OS_8,usedtmpref,tmpreg);
  1625. inc(usedtmpref2.offset,1);
  1626. a_load_reg_ref(list,OS_8,OS_8,tmpreg,usedtmpref2);
  1627. if len>2 then
  1628. begin
  1629. inc(usedtmpref.offset,1);
  1630. a_load_ref_reg(list,OS_8,OS_8,usedtmpref,tmpreg);
  1631. inc(usedtmpref2.offset,1);
  1632. a_load_reg_ref(list,OS_8,OS_8,tmpreg,usedtmpref2);
  1633. if len>3 then
  1634. begin
  1635. inc(usedtmpref.offset,1);
  1636. a_load_ref_reg(list,OS_8,OS_8,usedtmpref,tmpreg);
  1637. inc(usedtmpref2.offset,1);
  1638. a_load_reg_ref(list,OS_8,OS_8,tmpreg,usedtmpref2);
  1639. end;
  1640. end;
  1641. end;
  1642. end{end of if len<=4}
  1643. else
  1644. begin{unaligned & 4<len<helpsize **or** aligned/unaligned & len>helpsize}
  1645. destreg:=getintregister(list,OS_ADDR);
  1646. a_loadaddr_ref_reg(list,dest,destreg);
  1647. reference_reset_base(dstref,destreg,0);
  1648. srcreg:=getintregister(list,OS_ADDR);
  1649. a_loadaddr_ref_reg(list,source,srcreg);
  1650. reference_reset_base(srcref,srcreg,0);
  1651. countreg:=getintregister(list,OS_32);
  1652. // if cs_opt_size in current_settings.optimizerswitches then
  1653. { roozbeh : it seems loading 1 byte is faster becouse of caching/fetching(?) }
  1654. {if aligned then
  1655. genloop(len,4)
  1656. else}
  1657. genloop(len,1);
  1658. end;
  1659. end;
  1660. end;
  1661. procedure tcgarm.g_concatcopy_unaligned(list : TAsmList;const source,dest : treference;len : aint);
  1662. begin
  1663. g_concatcopy_internal(list,source,dest,len,false);
  1664. end;
  1665. procedure tcgarm.g_concatcopy(list : TAsmList;const source,dest : treference;len : aint);
  1666. begin
  1667. if (source.alignment in [1..3]) or
  1668. (dest.alignment in [1..3]) then
  1669. g_concatcopy_internal(list,source,dest,len,false)
  1670. else
  1671. g_concatcopy_internal(list,source,dest,len,true);
  1672. end;
  1673. procedure tcgarm.g_overflowCheck(list : TAsmList;const l : tlocation;def : tdef);
  1674. var
  1675. ovloc : tlocation;
  1676. begin
  1677. ovloc.loc:=LOC_VOID;
  1678. g_overflowCheck_loc(list,l,def,ovloc);
  1679. end;
  1680. procedure tcgarm.g_overflowCheck_loc(List:TAsmList;const Loc:TLocation;def:TDef;ovloc : tlocation);
  1681. var
  1682. hl : tasmlabel;
  1683. ai:TAiCpu;
  1684. hflags : tresflags;
  1685. begin
  1686. if not(cs_check_overflow in current_settings.localswitches) then
  1687. exit;
  1688. current_asmdata.getjumplabel(hl);
  1689. case ovloc.loc of
  1690. LOC_VOID:
  1691. begin
  1692. ai:=taicpu.op_sym(A_B,hl);
  1693. ai.is_jmp:=true;
  1694. if not((def.typ=pointerdef) or
  1695. ((def.typ=orddef) and
  1696. (torddef(def).ordtype in [u64bit,u16bit,u32bit,u8bit,uchar,pasbool]))) then
  1697. ai.SetCondition(C_VC)
  1698. else
  1699. if TAiCpu(List.Last).opcode in [A_RSB,A_RSC,A_SBC,A_SUB] then
  1700. ai.SetCondition(C_CS)
  1701. else
  1702. ai.SetCondition(C_CC);
  1703. list.concat(ai);
  1704. end;
  1705. LOC_FLAGS:
  1706. begin
  1707. hflags:=ovloc.resflags;
  1708. inverse_flags(hflags);
  1709. cg.a_jmp_flags(list,hflags,hl);
  1710. end;
  1711. else
  1712. internalerror(200409281);
  1713. end;
  1714. a_call_name(list,'FPC_OVERFLOW');
  1715. a_label(list,hl);
  1716. end;
  1717. procedure tcgarm.g_save_registers(list : TAsmList);
  1718. begin
  1719. { this work is done in g_proc_entry }
  1720. end;
  1721. procedure tcgarm.g_restore_registers(list : TAsmList);
  1722. begin
  1723. { this work is done in g_proc_exit }
  1724. end;
  1725. procedure tcgarm.a_jmp_cond(list : TAsmList;cond : TOpCmp;l: tasmlabel);
  1726. var
  1727. ai : taicpu;
  1728. begin
  1729. ai:=Taicpu.Op_sym(A_B,l);
  1730. ai.SetCondition(OpCmp2AsmCond[cond]);
  1731. ai.is_jmp:=true;
  1732. list.concat(ai);
  1733. end;
  1734. procedure tcgarm.g_adjust_self_value(list:TAsmList;procdef: tprocdef;ioffset: aint);
  1735. var
  1736. hsym : tsym;
  1737. href : treference;
  1738. paraloc : Pcgparalocation;
  1739. shift : byte;
  1740. begin
  1741. { calculate the parameter info for the procdef }
  1742. if not procdef.has_paraloc_info then
  1743. begin
  1744. procdef.requiredargarea:=paramanager.create_paraloc_info(procdef,callerside);
  1745. procdef.has_paraloc_info:=true;
  1746. end;
  1747. hsym:=tsym(procdef.parast.Find('self'));
  1748. if not(assigned(hsym) and
  1749. (hsym.typ=paravarsym)) then
  1750. internalerror(200305251);
  1751. paraloc:=tparavarsym(hsym).paraloc[callerside].location;
  1752. while paraloc<>nil do
  1753. with paraloc^ do
  1754. begin
  1755. case loc of
  1756. LOC_REGISTER:
  1757. begin
  1758. if is_shifter_const(ioffset,shift) then
  1759. a_op_const_reg(list,OP_SUB,size,ioffset,register)
  1760. else
  1761. begin
  1762. a_load_const_reg(list,OS_ADDR,ioffset,NR_R12);
  1763. a_op_reg_reg(list,OP_SUB,size,NR_R12,register);
  1764. end;
  1765. end;
  1766. LOC_REFERENCE:
  1767. begin
  1768. { offset in the wrapper needs to be adjusted for the stored
  1769. return address }
  1770. reference_reset_base(href,reference.index,reference.offset+sizeof(aint));
  1771. if is_shifter_const(ioffset,shift) then
  1772. a_op_const_ref(list,OP_SUB,size,ioffset,href)
  1773. else
  1774. begin
  1775. a_load_const_reg(list,OS_ADDR,ioffset,NR_R12);
  1776. a_op_reg_ref(list,OP_SUB,size,NR_R12,href);
  1777. end;
  1778. end
  1779. else
  1780. internalerror(200309189);
  1781. end;
  1782. paraloc:=next;
  1783. end;
  1784. end;
  1785. procedure tcgarm.g_intf_wrapper(list: TAsmList; procdef: tprocdef; const labelname: string; ioffset: longint);
  1786. procedure loadvmttor12;
  1787. var
  1788. href : treference;
  1789. begin
  1790. reference_reset_base(href,NR_R0,0);
  1791. cg.a_load_ref_reg(list,OS_ADDR,OS_ADDR,href,NR_R12);
  1792. end;
  1793. procedure op_onr12methodaddr;
  1794. var
  1795. href : treference;
  1796. begin
  1797. if (procdef.extnumber=$ffff) then
  1798. Internalerror(200006139);
  1799. { call/jmp vmtoffs(%eax) ; method offs }
  1800. reference_reset_base(href,NR_R12,procdef._class.vmtmethodoffset(procdef.extnumber));
  1801. cg.a_load_ref_reg(list,OS_ADDR,OS_ADDR,href,NR_R12);
  1802. list.concat(taicpu.op_reg_reg(A_MOV,NR_PC,NR_R12));
  1803. end;
  1804. var
  1805. make_global : boolean;
  1806. begin
  1807. if not(procdef.proctypeoption in [potype_function,potype_procedure]) then
  1808. Internalerror(200006137);
  1809. if not assigned(procdef._class) or
  1810. (procdef.procoptions*[po_classmethod, po_staticmethod,
  1811. po_methodpointer, po_interrupt, po_iocheck]<>[]) then
  1812. Internalerror(200006138);
  1813. if procdef.owner.symtabletype<>ObjectSymtable then
  1814. Internalerror(200109191);
  1815. make_global:=false;
  1816. if (not current_module.is_unit) or
  1817. create_smartlink or
  1818. (procdef.owner.defowner.owner.symtabletype=globalsymtable) then
  1819. make_global:=true;
  1820. if make_global then
  1821. list.concat(Tai_symbol.Createname_global(labelname,AT_FUNCTION,0))
  1822. else
  1823. list.concat(Tai_symbol.Createname(labelname,AT_FUNCTION,0));
  1824. { the wrapper might need aktlocaldata for the additional data to
  1825. load the constant }
  1826. current_procinfo:=cprocinfo.create(nil);
  1827. { set param1 interface to self }
  1828. g_adjust_self_value(list,procdef,ioffset);
  1829. { case 4 }
  1830. if po_virtualmethod in procdef.procoptions then
  1831. begin
  1832. loadvmttor12;
  1833. op_onr12methodaddr;
  1834. end
  1835. { case 0 }
  1836. else
  1837. list.concat(taicpu.op_sym(A_B,current_asmdata.RefAsmSymbol(procdef.mangledname)));
  1838. list.concatlist(current_procinfo.aktlocaldata);
  1839. current_procinfo.Free;
  1840. current_procinfo:=nil;
  1841. list.concat(Tai_symbol_end.Createname(labelname));
  1842. end;
  1843. procedure tcgarm.maybeadjustresult(list: TAsmList; op: TOpCg; size: tcgsize; dst: tregister);
  1844. const
  1845. overflowops = [OP_MUL,OP_SHL,OP_ADD,OP_SUB,OP_NOT,OP_NEG];
  1846. begin
  1847. if (op in overflowops) and
  1848. (size in [OS_8,OS_S8,OS_16,OS_S16]) then
  1849. a_load_reg_reg(list,OS_32,size,dst,dst);
  1850. end;
  1851. procedure tcg64farm.a_op64_reg_reg(list : TAsmList;op:TOpCG;size : tcgsize;regsrc,regdst : tregister64);
  1852. begin
  1853. case op of
  1854. OP_NEG:
  1855. begin
  1856. list.concat(setoppostfix(taicpu.op_reg_reg_const(A_RSB,regdst.reglo,regsrc.reglo,0),PF_S));
  1857. list.concat(taicpu.op_reg_reg_const(A_RSC,regdst.reghi,regsrc.reghi,0));
  1858. end;
  1859. OP_NOT:
  1860. begin
  1861. cg.a_op_reg_reg(list,OP_NOT,OS_INT,regsrc.reglo,regdst.reglo);
  1862. cg.a_op_reg_reg(list,OP_NOT,OS_INT,regsrc.reghi,regdst.reghi);
  1863. end;
  1864. else
  1865. a_op64_reg_reg_reg(list,op,size,regsrc,regdst,regdst);
  1866. end;
  1867. end;
  1868. procedure tcg64farm.a_op64_const_reg(list : TAsmList;op:TOpCG;size : tcgsize;value : int64;reg : tregister64);
  1869. begin
  1870. a_op64_const_reg_reg(list,op,size,value,reg,reg);
  1871. end;
  1872. procedure tcg64farm.a_op64_const_reg_reg(list: TAsmList;op:TOpCG;size : tcgsize;value : int64;regsrc,regdst : tregister64);
  1873. var
  1874. ovloc : tlocation;
  1875. begin
  1876. a_op64_const_reg_reg_checkoverflow(list,op,size,value,regsrc,regdst,false,ovloc);
  1877. end;
  1878. procedure tcg64farm.a_op64_reg_reg_reg(list: TAsmList;op:TOpCG;size : tcgsize;regsrc1,regsrc2,regdst : tregister64);
  1879. var
  1880. ovloc : tlocation;
  1881. begin
  1882. a_op64_reg_reg_reg_checkoverflow(list,op,size,regsrc1,regsrc2,regdst,false,ovloc);
  1883. end;
  1884. procedure tcg64farm.a_op64_const_reg_reg_checkoverflow(list: TAsmList;op:TOpCG;size : tcgsize;value : int64;regsrc,regdst : tregister64;setflags : boolean;var ovloc : tlocation);
  1885. var
  1886. tmpreg : tregister;
  1887. b : byte;
  1888. begin
  1889. ovloc.loc:=LOC_VOID;
  1890. case op of
  1891. OP_NEG,
  1892. OP_NOT :
  1893. internalerror(200306017);
  1894. end;
  1895. if (setflags or tcgarm(cg).cgsetflags) and (op in [OP_ADD,OP_SUB]) then
  1896. begin
  1897. case op of
  1898. OP_ADD:
  1899. begin
  1900. if is_shifter_const(lo(value),b) then
  1901. list.concat(setoppostfix(taicpu.op_reg_reg_const(A_ADD,regdst.reglo,regsrc.reglo,lo(value)),PF_S))
  1902. else
  1903. begin
  1904. tmpreg:=cg.getintregister(list,OS_32);
  1905. cg.a_load_const_reg(list,OS_32,lo(value),tmpreg);
  1906. list.concat(setoppostfix(taicpu.op_reg_reg_reg(A_ADD,regdst.reglo,regsrc.reglo,tmpreg),PF_S));
  1907. end;
  1908. if is_shifter_const(hi(value),b) then
  1909. list.concat(setoppostfix(taicpu.op_reg_reg_const(A_ADC,regdst.reghi,regsrc.reghi,hi(value)),PF_S))
  1910. else
  1911. begin
  1912. tmpreg:=cg.getintregister(list,OS_32);
  1913. cg.a_load_const_reg(list,OS_32,hi(value),tmpreg);
  1914. list.concat(setoppostfix(taicpu.op_reg_reg_reg(A_ADC,regdst.reghi,regsrc.reghi,tmpreg),PF_S));
  1915. end;
  1916. end;
  1917. OP_SUB:
  1918. begin
  1919. if is_shifter_const(lo(value),b) then
  1920. list.concat(setoppostfix(taicpu.op_reg_reg_const(A_SUB,regdst.reglo,regsrc.reglo,lo(value)),PF_S))
  1921. else
  1922. begin
  1923. tmpreg:=cg.getintregister(list,OS_32);
  1924. cg.a_load_const_reg(list,OS_32,lo(value),tmpreg);
  1925. list.concat(setoppostfix(taicpu.op_reg_reg_reg(A_SUB,regdst.reglo,regsrc.reglo,tmpreg),PF_S));
  1926. end;
  1927. if is_shifter_const(hi(value),b) then
  1928. list.concat(setoppostfix(taicpu.op_reg_reg_const(A_SBC,regdst.reghi,regsrc.reghi,aint(hi(value))),PF_S))
  1929. else
  1930. begin
  1931. tmpreg:=cg.getintregister(list,OS_32);
  1932. cg.a_load_const_reg(list,OS_32,hi(value),tmpreg);
  1933. list.concat(setoppostfix(taicpu.op_reg_reg_reg(A_SBC,regdst.reghi,regsrc.reghi,tmpreg),PF_S));
  1934. end;
  1935. end;
  1936. else
  1937. internalerror(200502131);
  1938. end;
  1939. if size=OS_64 then
  1940. begin
  1941. { the arm has an weired opinion how flags for SUB/ADD are handled }
  1942. ovloc.loc:=LOC_FLAGS;
  1943. case op of
  1944. OP_ADD:
  1945. ovloc.resflags:=F_CS;
  1946. OP_SUB:
  1947. ovloc.resflags:=F_CC;
  1948. end;
  1949. end;
  1950. end
  1951. else
  1952. begin
  1953. case op of
  1954. OP_AND,OP_OR,OP_XOR:
  1955. begin
  1956. cg.a_op_const_reg_reg(list,op,OS_32,aint(lo(value)),regsrc.reglo,regdst.reglo);
  1957. cg.a_op_const_reg_reg(list,op,OS_32,aint(hi(value)),regsrc.reghi,regdst.reghi);
  1958. end;
  1959. OP_ADD:
  1960. begin
  1961. if is_shifter_const(aint(lo(value)),b) then
  1962. list.concat(setoppostfix(taicpu.op_reg_reg_const(A_ADD,regdst.reglo,regsrc.reglo,aint(lo(value))),PF_S))
  1963. else
  1964. begin
  1965. tmpreg:=cg.getintregister(list,OS_32);
  1966. cg.a_load_const_reg(list,OS_32,aint(lo(value)),tmpreg);
  1967. list.concat(setoppostfix(taicpu.op_reg_reg_reg(A_ADD,regdst.reglo,regsrc.reglo,tmpreg),PF_S));
  1968. end;
  1969. if is_shifter_const(aint(hi(value)),b) then
  1970. list.concat(taicpu.op_reg_reg_const(A_ADC,regdst.reghi,regsrc.reghi,aint(hi(value))))
  1971. else
  1972. begin
  1973. tmpreg:=cg.getintregister(list,OS_32);
  1974. cg.a_load_const_reg(list,OS_32,aint(hi(value)),tmpreg);
  1975. list.concat(taicpu.op_reg_reg_reg(A_ADC,regdst.reghi,regsrc.reghi,tmpreg));
  1976. end;
  1977. end;
  1978. OP_SUB:
  1979. begin
  1980. if is_shifter_const(aint(lo(value)),b) then
  1981. list.concat(setoppostfix(taicpu.op_reg_reg_const(A_SUB,regdst.reglo,regsrc.reglo,aint(lo(value))),PF_S))
  1982. else
  1983. begin
  1984. tmpreg:=cg.getintregister(list,OS_32);
  1985. cg.a_load_const_reg(list,OS_32,aint(lo(value)),tmpreg);
  1986. list.concat(setoppostfix(taicpu.op_reg_reg_reg(A_SUB,regdst.reglo,regsrc.reglo,tmpreg),PF_S));
  1987. end;
  1988. if is_shifter_const(aint(hi(value)),b) then
  1989. list.concat(taicpu.op_reg_reg_const(A_SBC,regdst.reghi,regsrc.reghi,aint(hi(value))))
  1990. else
  1991. begin
  1992. tmpreg:=cg.getintregister(list,OS_32);
  1993. cg.a_load_const_reg(list,OS_32,hi(value),tmpreg);
  1994. list.concat(taicpu.op_reg_reg_reg(A_SBC,regdst.reghi,regsrc.reghi,tmpreg));
  1995. end;
  1996. end;
  1997. else
  1998. internalerror(2003083101);
  1999. end;
  2000. end;
  2001. end;
  2002. procedure tcg64farm.a_op64_reg_reg_reg_checkoverflow(list: TAsmList;op:TOpCG;size : tcgsize;regsrc1,regsrc2,regdst : tregister64;setflags : boolean;var ovloc : tlocation);
  2003. begin
  2004. ovloc.loc:=LOC_VOID;
  2005. case op of
  2006. OP_NEG,
  2007. OP_NOT :
  2008. internalerror(200306017);
  2009. end;
  2010. if (setflags or tcgarm(cg).cgsetflags) and (op in [OP_ADD,OP_SUB]) then
  2011. begin
  2012. case op of
  2013. OP_ADD:
  2014. begin
  2015. list.concat(setoppostfix(taicpu.op_reg_reg_reg(A_ADD,regdst.reglo,regsrc1.reglo,regsrc2.reglo),PF_S));
  2016. list.concat(setoppostfix(taicpu.op_reg_reg_reg(A_ADC,regdst.reghi,regsrc1.reghi,regsrc2.reghi),PF_S));
  2017. end;
  2018. OP_SUB:
  2019. begin
  2020. list.concat(setoppostfix(taicpu.op_reg_reg_reg(A_SUB,regdst.reglo,regsrc2.reglo,regsrc1.reglo),PF_S));
  2021. list.concat(setoppostfix(taicpu.op_reg_reg_reg(A_SBC,regdst.reghi,regsrc2.reghi,regsrc1.reghi),PF_S));
  2022. end;
  2023. else
  2024. internalerror(2003083101);
  2025. end;
  2026. if size=OS_64 then
  2027. begin
  2028. { the arm has an weired opinion how flags for SUB/ADD are handled }
  2029. ovloc.loc:=LOC_FLAGS;
  2030. case op of
  2031. OP_ADD:
  2032. ovloc.resflags:=F_CS;
  2033. OP_SUB:
  2034. ovloc.resflags:=F_CC;
  2035. end;
  2036. end;
  2037. end
  2038. else
  2039. begin
  2040. case op of
  2041. OP_AND,OP_OR,OP_XOR:
  2042. begin
  2043. cg.a_op_reg_reg_reg(list,op,OS_32,regsrc1.reglo,regsrc2.reglo,regdst.reglo);
  2044. cg.a_op_reg_reg_reg(list,op,OS_32,regsrc1.reghi,regsrc2.reghi,regdst.reghi);
  2045. end;
  2046. OP_ADD:
  2047. begin
  2048. list.concat(setoppostfix(taicpu.op_reg_reg_reg(A_ADD,regdst.reglo,regsrc1.reglo,regsrc2.reglo),PF_S));
  2049. list.concat(taicpu.op_reg_reg_reg(A_ADC,regdst.reghi,regsrc1.reghi,regsrc2.reghi));
  2050. end;
  2051. OP_SUB:
  2052. begin
  2053. list.concat(setoppostfix(taicpu.op_reg_reg_reg(A_SUB,regdst.reglo,regsrc2.reglo,regsrc1.reglo),PF_S));
  2054. list.concat(taicpu.op_reg_reg_reg(A_SBC,regdst.reghi,regsrc2.reghi,regsrc1.reghi));
  2055. end;
  2056. else
  2057. internalerror(2003083101);
  2058. end;
  2059. end;
  2060. end;
  2061. begin
  2062. cg:=tcgarm.create;
  2063. cg64:=tcg64farm.create;
  2064. end.