cgcpu.pas 62 KB

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