cgcpu.pas 71 KB

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