cgcpu.pas 81 KB

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