cgcpu.pas 63 KB

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