cgcpu.pas 72 KB

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