cgcpu.pas 63 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728
  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. 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. { [#xxx] isn't a valid address operand }
  540. ((ref.base=NR_NO) and (ref.index=NR_NO)) or
  541. (ref.offset<-4095) or
  542. (ref.offset>4095) or
  543. ((oppostfix in [PF_SB,PF_H,PF_SH]) and
  544. ((ref.offset<-255) or
  545. (ref.offset>255)
  546. )
  547. ) or
  548. ((op in [A_LDF,A_STF]) and
  549. ((ref.offset<-1020) or
  550. (ref.offset>1020) or
  551. { the usual pc relative symbol handling assumes possible offsets of +/- 4095 }
  552. assigned(ref.symbol)
  553. )
  554. ) then
  555. begin
  556. reference_reset(tmpref);
  557. { load symbol }
  558. tmpreg:=getintregister(list,OS_INT);
  559. if assigned(ref.symbol) then
  560. begin
  561. objectlibrary.getlabel(l);
  562. cg.a_label(current_procinfo.aktlocaldata,l);
  563. tmpref.symboldata:=current_procinfo.aktlocaldata.last;
  564. current_procinfo.aktlocaldata.concat(tai_const.create_sym_offset(ref.symbol,ref.offset));
  565. { load consts entry }
  566. tmpref.symbol:=l;
  567. tmpref.base:=NR_R15;
  568. list.concat(taicpu.op_reg_ref(A_LDR,tmpreg,tmpref));
  569. end
  570. else
  571. a_load_const_reg(list,OS_ADDR,ref.offset,tmpreg);
  572. if (ref.base<>NR_NO) then
  573. begin
  574. if ref.index<>NR_NO then
  575. begin
  576. list.concat(taicpu.op_reg_reg_reg(A_ADD,tmpreg,ref.base,tmpreg));
  577. ref.base:=tmpreg;
  578. end
  579. else
  580. begin
  581. ref.index:=tmpreg;
  582. ref.shiftimm:=0;
  583. ref.signindex:=1;
  584. ref.shiftmode:=SM_None;
  585. end;
  586. end
  587. else
  588. ref.base:=tmpreg;
  589. ref.offset:=0;
  590. ref.symbol:=nil;
  591. end;
  592. if (ref.base<>NR_NO) and (ref.index<>NR_NO) and (ref.offset<>0) then
  593. begin
  594. if tmpreg<>NR_NO then
  595. a_op_const_reg_reg(list,OP_ADD,OS_ADDR,ref.offset,tmpreg,tmpreg)
  596. else
  597. begin
  598. tmpreg:=getintregister(list,OS_ADDR);
  599. a_op_const_reg_reg(list,OP_ADD,OS_ADDR,ref.offset,ref.base,tmpreg);
  600. ref.base:=tmpreg;
  601. end;
  602. ref.offset:=0;
  603. end;
  604. { floating point operations have only limited references
  605. we expect here, that a base is already set }
  606. if (op in [A_LDF,A_STF]) and (ref.index<>NR_NO) then
  607. begin
  608. if ref.shiftmode<>SM_none then
  609. internalerror(200309121);
  610. if tmpreg<>NR_NO then
  611. begin
  612. if ref.base=tmpreg then
  613. begin
  614. if ref.signindex<0 then
  615. list.concat(taicpu.op_reg_reg_reg(A_SUB,tmpreg,tmpreg,ref.index))
  616. else
  617. list.concat(taicpu.op_reg_reg_reg(A_ADD,tmpreg,tmpreg,ref.index));
  618. ref.index:=NR_NO;
  619. end
  620. else
  621. begin
  622. if ref.index<>tmpreg then
  623. internalerror(200403161);
  624. if ref.signindex<0 then
  625. list.concat(taicpu.op_reg_reg_reg(A_SUB,tmpreg,ref.base,tmpreg))
  626. else
  627. list.concat(taicpu.op_reg_reg_reg(A_ADD,tmpreg,ref.base,tmpreg));
  628. ref.base:=tmpreg;
  629. ref.index:=NR_NO;
  630. end;
  631. end
  632. else
  633. begin
  634. tmpreg:=getintregister(list,OS_ADDR);
  635. list.concat(taicpu.op_reg_reg_reg(A_ADD,tmpreg,ref.base,ref.index));
  636. ref.base:=tmpreg;
  637. ref.index:=NR_NO;
  638. end;
  639. end;
  640. list.concat(setoppostfix(taicpu.op_reg_ref(op,reg,ref),oppostfix));
  641. end;
  642. procedure tcgarm.a_load_reg_ref(list : taasmoutput; fromsize, tosize: tcgsize; reg : tregister;const ref : treference);
  643. var
  644. oppostfix:toppostfix;
  645. begin
  646. case ToSize of
  647. { signed integer registers }
  648. OS_8,
  649. OS_S8:
  650. oppostfix:=PF_B;
  651. OS_16,
  652. OS_S16:
  653. oppostfix:=PF_H;
  654. OS_32,
  655. OS_S32:
  656. oppostfix:=PF_None;
  657. else
  658. InternalError(200308295);
  659. end;
  660. handle_load_store(list,A_STR,oppostfix,reg,ref);
  661. end;
  662. procedure tcgarm.a_load_ref_reg(list : taasmoutput; fromsize, tosize : tcgsize;const Ref : treference;reg : tregister);
  663. var
  664. oppostfix:toppostfix;
  665. begin
  666. case FromSize of
  667. { signed integer registers }
  668. OS_8:
  669. oppostfix:=PF_B;
  670. OS_S8:
  671. oppostfix:=PF_SB;
  672. OS_16:
  673. oppostfix:=PF_H;
  674. OS_S16:
  675. oppostfix:=PF_SH;
  676. OS_32,
  677. OS_S32:
  678. oppostfix:=PF_None;
  679. else
  680. InternalError(200308291);
  681. end;
  682. handle_load_store(list,A_LDR,oppostfix,reg,ref);
  683. end;
  684. procedure tcgarm.a_load_reg_reg(list : taasmoutput; fromsize, tosize : tcgsize;reg1,reg2 : tregister);
  685. var
  686. instr: taicpu;
  687. so : tshifterop;
  688. begin
  689. shifterop_reset(so);
  690. if (tcgsize2size[tosize] < tcgsize2size[fromsize]) or
  691. (
  692. (tcgsize2size[tosize] = tcgsize2size[fromsize]) and
  693. (tosize <> fromsize) and
  694. not(fromsize in [OS_32,OS_S32])
  695. ) then
  696. begin
  697. case tosize of
  698. OS_8:
  699. list.concat(taicpu.op_reg_reg_const(A_AND,
  700. reg2,reg1,$ff));
  701. OS_S8:
  702. begin
  703. so.shiftmode:=SM_LSL;
  704. so.shiftimm:=24;
  705. list.concat(taicpu.op_reg_reg_shifterop(A_MOV,reg2,reg1,so));
  706. so.shiftmode:=SM_ASR;
  707. so.shiftimm:=24;
  708. list.concat(taicpu.op_reg_reg_shifterop(A_MOV,reg2,reg2,so));
  709. end;
  710. OS_16:
  711. begin
  712. so.shiftmode:=SM_LSL;
  713. so.shiftimm:=16;
  714. list.concat(taicpu.op_reg_reg_shifterop(A_MOV,reg2,reg1,so));
  715. so.shiftmode:=SM_LSR;
  716. so.shiftimm:=16;
  717. list.concat(taicpu.op_reg_reg_shifterop(A_MOV,reg2,reg2,so));
  718. end;
  719. OS_S16:
  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_ASR;
  725. so.shiftimm:=16;
  726. list.concat(taicpu.op_reg_reg_shifterop(A_MOV,reg2,reg2,so));
  727. end;
  728. OS_32,OS_S32:
  729. begin
  730. instr:=taicpu.op_reg_reg(A_MOV,reg2,reg1);
  731. list.concat(instr);
  732. add_move_instruction(instr);
  733. end;
  734. else internalerror(2002090901);
  735. end;
  736. end
  737. else
  738. begin
  739. if reg1<>reg2 then
  740. begin
  741. { same size, only a register mov required }
  742. instr:=taicpu.op_reg_reg(A_MOV,reg2,reg1);
  743. list.Concat(instr);
  744. { Notify the register allocator that we have written a move instruction so
  745. it can try to eliminate it. }
  746. add_move_instruction(instr);
  747. end;
  748. end;
  749. end;
  750. procedure tcgarm.a_paramfpu_ref(list : taasmoutput;size : tcgsize;const ref : treference;const paraloc : TCGPara);
  751. var
  752. href,href2 : treference;
  753. hloc : pcgparalocation;
  754. begin
  755. href:=ref;
  756. hloc:=paraloc.location;
  757. while assigned(hloc) do
  758. begin
  759. case hloc^.loc of
  760. LOC_FPUREGISTER,LOC_CFPUREGISTER:
  761. a_loadfpu_ref_reg(list,size,ref,hloc^.register);
  762. LOC_REGISTER :
  763. a_load_ref_reg(list,hloc^.size,hloc^.size,href,hloc^.register);
  764. LOC_REFERENCE :
  765. begin
  766. reference_reset_base(href2,hloc^.reference.index,hloc^.reference.offset);
  767. a_load_ref_ref(list,hloc^.size,hloc^.size,href,href2);
  768. end;
  769. else
  770. internalerror(200408241);
  771. end;
  772. inc(href.offset,tcgsize2size[hloc^.size]);
  773. hloc:=hloc^.next;
  774. end;
  775. end;
  776. procedure tcgarm.a_loadfpu_reg_reg(list: taasmoutput; size: tcgsize; reg1, reg2: tregister);
  777. begin
  778. list.concat(setoppostfix(taicpu.op_reg_reg(A_MVF,reg2,reg1),cgsize2fpuoppostfix[size]));
  779. end;
  780. procedure tcgarm.a_loadfpu_ref_reg(list: taasmoutput; size: tcgsize; const ref: treference; reg: tregister);
  781. var
  782. oppostfix:toppostfix;
  783. begin
  784. case size of
  785. OS_F32:
  786. oppostfix:=PF_S;
  787. OS_F64:
  788. oppostfix:=PF_D;
  789. OS_F80:
  790. oppostfix:=PF_E;
  791. else
  792. InternalError(200309021);
  793. end;
  794. handle_load_store(list,A_LDF,oppostfix,reg,ref);
  795. end;
  796. procedure tcgarm.a_loadfpu_reg_ref(list: taasmoutput; size: tcgsize; reg: tregister; const ref: treference);
  797. var
  798. oppostfix:toppostfix;
  799. begin
  800. case size of
  801. OS_F32:
  802. oppostfix:=PF_S;
  803. OS_F64:
  804. oppostfix:=PF_D;
  805. OS_F80:
  806. oppostfix:=PF_E;
  807. else
  808. InternalError(200309021);
  809. end;
  810. handle_load_store(list,A_STF,oppostfix,reg,ref);
  811. end;
  812. { comparison operations }
  813. procedure tcgarm.a_cmp_const_reg_label(list : taasmoutput;size : tcgsize;cmp_op : topcmp;a : aint;reg : tregister;
  814. l : tasmlabel);
  815. var
  816. tmpreg : tregister;
  817. b : byte;
  818. begin
  819. if is_shifter_const(a,b) then
  820. list.concat(taicpu.op_reg_const(A_CMP,reg,a))
  821. { CMN reg,0 and CMN reg,$80000000 are different from CMP reg,$ffffffff
  822. and CMP reg,$7fffffff regarding the flags according to the ARM manual }
  823. else if (a<>$7fffffff) and (a<>-1) and is_shifter_const(-a,b) then
  824. list.concat(taicpu.op_reg_const(A_CMN,reg,-a))
  825. else
  826. begin
  827. tmpreg:=getintregister(list,size);
  828. a_load_const_reg(list,size,a,tmpreg);
  829. list.concat(taicpu.op_reg_reg(A_CMP,reg,tmpreg));
  830. end;
  831. a_jmp_cond(list,cmp_op,l);
  832. end;
  833. procedure tcgarm.a_cmp_reg_reg_label(list : taasmoutput;size : tcgsize;cmp_op : topcmp;reg1,reg2 : tregister;l : tasmlabel);
  834. begin
  835. list.concat(taicpu.op_reg_reg(A_CMP,reg2,reg1));
  836. a_jmp_cond(list,cmp_op,l);
  837. end;
  838. procedure tcgarm.a_jmp_name(list : taasmoutput;const s : string);
  839. begin
  840. list.concat(taicpu.op_sym(A_B,objectlibrary.newasmsymbol(s,AB_EXTERNAL,AT_FUNCTION)));
  841. end;
  842. procedure tcgarm.a_jmp_always(list : taasmoutput;l: tasmlabel);
  843. begin
  844. list.concat(taicpu.op_sym(A_B,objectlibrary.newasmsymbol(l.name,AB_EXTERNAL,AT_FUNCTION)));
  845. end;
  846. procedure tcgarm.a_jmp_flags(list : taasmoutput;const f : TResFlags;l: tasmlabel);
  847. var
  848. ai : taicpu;
  849. begin
  850. ai:=setcondition(taicpu.op_sym(A_B,l),flags_to_cond(f));
  851. ai.is_jmp:=true;
  852. list.concat(ai);
  853. end;
  854. procedure tcgarm.g_flags2reg(list: taasmoutput; size: TCgSize; const f: TResFlags; reg: TRegister);
  855. var
  856. ai : taicpu;
  857. begin
  858. list.concat(setcondition(taicpu.op_reg_const(A_MOV,reg,1),flags_to_cond(f)));
  859. list.concat(setcondition(taicpu.op_reg_const(A_MOV,reg,0),inverse_cond(flags_to_cond(f))));
  860. end;
  861. procedure tcgarm.g_proc_entry(list : taasmoutput;localsize : longint;nostackframe:boolean);
  862. var
  863. ref : treference;
  864. shift : byte;
  865. firstfloatreg,lastfloatreg,
  866. r : byte;
  867. begin
  868. LocalSize:=align(LocalSize,4);
  869. if not(nostackframe) then
  870. begin
  871. firstfloatreg:=RS_NO;
  872. { save floating point registers? }
  873. for r:=RS_F0 to RS_F7 do
  874. if r in rg[R_FPUREGISTER].used_in_proc-paramanager.get_volatile_registers_fpu(pocall_stdcall) then
  875. begin
  876. if firstfloatreg=RS_NO then
  877. firstfloatreg:=r;
  878. lastfloatreg:=r;
  879. end;
  880. a_reg_alloc(list,NR_STACK_POINTER_REG);
  881. a_reg_alloc(list,NR_FRAME_POINTER_REG);
  882. a_reg_alloc(list,NR_R12);
  883. list.concat(taicpu.op_reg_reg(A_MOV,NR_R12,NR_STACK_POINTER_REG));
  884. { save int registers }
  885. reference_reset(ref);
  886. ref.index:=NR_STACK_POINTER_REG;
  887. ref.addressmode:=AM_PREINDEXED;
  888. list.concat(setoppostfix(taicpu.op_ref_regset(A_STM,ref,
  889. rg[R_INTREGISTER].used_in_proc-paramanager.get_volatile_registers_int(pocall_stdcall)+[RS_R11,RS_R12,RS_R14,RS_R15]),
  890. PF_FD));
  891. list.concat(taicpu.op_reg_reg_const(A_SUB,NR_FRAME_POINTER_REG,NR_R12,4));
  892. { allocate necessary stack size }
  893. { don't use a_op_const_reg_reg here because we don't allow register allocations
  894. in the entry/exit code }
  895. if not(is_shifter_const(localsize,shift)) then
  896. begin
  897. a_load_const_reg(list,OS_ADDR,LocalSize,NR_R12);
  898. list.concat(taicpu.op_reg_reg_reg(A_SUB,NR_STACK_POINTER_REG,NR_STACK_POINTER_REG,NR_R12));
  899. a_reg_dealloc(list,NR_R12);
  900. end
  901. else
  902. begin
  903. a_reg_dealloc(list,NR_R12);
  904. list.concat(taicpu.op_reg_reg_const(A_SUB,NR_STACK_POINTER_REG,NR_STACK_POINTER_REG,LocalSize));
  905. end;
  906. if firstfloatreg<>RS_NO then
  907. begin
  908. reference_reset(ref);
  909. if not(is_shifter_const(-tarmprocinfo(current_procinfo).floatregstart,shift)) then
  910. begin
  911. a_load_const_reg(list,OS_ADDR,-tarmprocinfo(current_procinfo).floatregstart,NR_R12);
  912. list.concat(taicpu.op_reg_reg_reg(A_SUB,NR_R12,NR_FRAME_POINTER_REG,NR_R12));
  913. ref.base:=NR_R12;
  914. end
  915. else
  916. begin
  917. ref.base:=NR_FRAME_POINTER_REG;
  918. ref.offset:=tarmprocinfo(current_procinfo).floatregstart;
  919. end;
  920. list.concat(taicpu.op_reg_const_ref(A_SFM,newreg(R_FPUREGISTER,firstfloatreg,R_SUBWHOLE),
  921. lastfloatreg-firstfloatreg+1,ref));
  922. end;
  923. end;
  924. end;
  925. procedure tcgarm.g_proc_exit(list : taasmoutput;parasize : longint;nostackframe:boolean);
  926. var
  927. ref : treference;
  928. firstfloatreg,lastfloatreg,
  929. r : byte;
  930. shift : byte;
  931. begin
  932. if not(nostackframe) then
  933. begin
  934. { restore floating point register }
  935. firstfloatreg:=RS_NO;
  936. { save floating point registers? }
  937. for r:=RS_F0 to RS_F7 do
  938. if r in rg[R_FPUREGISTER].used_in_proc-paramanager.get_volatile_registers_fpu(pocall_stdcall) then
  939. begin
  940. if firstfloatreg=RS_NO then
  941. firstfloatreg:=r;
  942. lastfloatreg:=r;
  943. end;
  944. if firstfloatreg<>RS_NO then
  945. begin
  946. reference_reset(ref);
  947. if not(is_shifter_const(-tarmprocinfo(current_procinfo).floatregstart,shift)) then
  948. begin
  949. a_load_const_reg(list,OS_ADDR,-tarmprocinfo(current_procinfo).floatregstart,NR_R12);
  950. list.concat(taicpu.op_reg_reg_reg(A_SUB,NR_R12,NR_FRAME_POINTER_REG,NR_R12));
  951. ref.base:=NR_R12;
  952. end
  953. else
  954. begin
  955. ref.base:=NR_FRAME_POINTER_REG;
  956. ref.offset:=tarmprocinfo(current_procinfo).floatregstart;
  957. end;
  958. list.concat(taicpu.op_reg_const_ref(A_LFM,newreg(R_FPUREGISTER,firstfloatreg,R_SUBWHOLE),
  959. lastfloatreg-firstfloatreg+1,ref));
  960. end;
  961. if (current_procinfo.framepointer=NR_STACK_POINTER_REG) then
  962. list.concat(taicpu.op_reg_reg(A_MOV,NR_R15,NR_R14))
  963. else
  964. begin
  965. { restore int registers and return }
  966. reference_reset(ref);
  967. ref.index:=NR_FRAME_POINTER_REG;
  968. 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));
  969. end;
  970. end
  971. else
  972. list.concat(taicpu.op_reg_reg(A_MOV,NR_PC,NR_R14));
  973. end;
  974. procedure tcgarm.a_loadaddr_ref_reg(list : taasmoutput;const ref : treference;r : tregister);
  975. var
  976. b : byte;
  977. tmpref : treference;
  978. instr : taicpu;
  979. begin
  980. if ref.addressmode<>AM_OFFSET then
  981. internalerror(200309071);
  982. tmpref:=ref;
  983. { Be sure to have a base register }
  984. if (tmpref.base=NR_NO) then
  985. begin
  986. if tmpref.shiftmode<>SM_None then
  987. internalerror(200308294);
  988. if tmpref.signindex<0 then
  989. internalerror(200312023);
  990. tmpref.base:=tmpref.index;
  991. tmpref.index:=NR_NO;
  992. end;
  993. if assigned(tmpref.symbol) or
  994. not((is_shifter_const(tmpref.offset,b)) or
  995. (is_shifter_const(-tmpref.offset,b))
  996. ) then
  997. fixref(list,tmpref);
  998. { expect a base here if there is an index }
  999. if (tmpref.base=NR_NO) and (tmpref.index<>NR_NO) then
  1000. internalerror(200312022);
  1001. if tmpref.index<>NR_NO then
  1002. begin
  1003. if tmpref.shiftmode<>SM_None then
  1004. internalerror(200312021);
  1005. if tmpref.signindex<0 then
  1006. a_op_reg_reg_reg(list,OP_SUB,OS_ADDR,tmpref.base,tmpref.index,r)
  1007. else
  1008. a_op_reg_reg_reg(list,OP_ADD,OS_ADDR,tmpref.base,tmpref.index,r);
  1009. if tmpref.offset<>0 then
  1010. a_op_const_reg_reg(list,OP_ADD,OS_ADDR,tmpref.offset,r,r);
  1011. end
  1012. else
  1013. begin
  1014. if tmpref.offset<>0 then
  1015. begin
  1016. if tmpref.base<>NR_NO then
  1017. a_op_const_reg_reg(list,OP_ADD,OS_ADDR,tmpref.offset,tmpref.base,r)
  1018. else
  1019. a_load_const_reg(list,OS_ADDR,tmpref.offset,r);
  1020. end
  1021. else
  1022. begin
  1023. instr:=taicpu.op_reg_reg(A_MOV,r,tmpref.base);
  1024. list.concat(instr);
  1025. add_move_instruction(instr);
  1026. end;
  1027. end;
  1028. end;
  1029. procedure tcgarm.fixref(list : taasmoutput;var ref : treference);
  1030. var
  1031. tmpreg : tregister;
  1032. tmpref : treference;
  1033. l : tasmlabel;
  1034. begin
  1035. { absolute symbols can't be handled directly, we've to store the symbol reference
  1036. in the text segment and access it pc relative
  1037. For now, we assume that references where base or index equals to PC are already
  1038. relative, all other references are assumed to be absolute and thus they need
  1039. to be handled extra.
  1040. A proper solution would be to change refoptions to a set and store the information
  1041. if the symbol is absolute or relative there.
  1042. }
  1043. { create consts entry }
  1044. reference_reset(tmpref);
  1045. objectlibrary.getlabel(l);
  1046. cg.a_label(current_procinfo.aktlocaldata,l);
  1047. tmpref.symboldata:=current_procinfo.aktlocaldata.last;
  1048. if assigned(ref.symbol) then
  1049. current_procinfo.aktlocaldata.concat(tai_const.create_sym_offset(ref.symbol,ref.offset))
  1050. else
  1051. current_procinfo.aktlocaldata.concat(tai_const.Create_32bit(ref.offset));
  1052. { load consts entry }
  1053. tmpreg:=getintregister(list,OS_INT);
  1054. tmpref.symbol:=l;
  1055. tmpref.base:=NR_PC;
  1056. list.concat(taicpu.op_reg_ref(A_LDR,tmpreg,tmpref));
  1057. if (ref.base<>NR_NO) then
  1058. begin
  1059. if ref.index<>NR_NO then
  1060. begin
  1061. list.concat(taicpu.op_reg_reg_reg(A_ADD,tmpreg,ref.base,tmpreg));
  1062. ref.base:=tmpreg;
  1063. end
  1064. else
  1065. begin
  1066. ref.index:=tmpreg;
  1067. ref.shiftimm:=0;
  1068. ref.signindex:=1;
  1069. ref.shiftmode:=SM_None;
  1070. end;
  1071. end
  1072. else
  1073. ref.base:=tmpreg;
  1074. ref.offset:=0;
  1075. ref.symbol:=nil;
  1076. end;
  1077. procedure tcgarm.g_concatcopy_move(list : taasmoutput;const source,dest : treference;len : aint);
  1078. var
  1079. paraloc1,paraloc2,paraloc3 : TCGPara;
  1080. begin
  1081. paraloc1.init;
  1082. paraloc2.init;
  1083. paraloc3.init;
  1084. paramanager.getintparaloc(pocall_default,1,paraloc1);
  1085. paramanager.getintparaloc(pocall_default,2,paraloc2);
  1086. paramanager.getintparaloc(pocall_default,3,paraloc3);
  1087. paramanager.allocparaloc(list,paraloc3);
  1088. a_param_const(list,OS_INT,len,paraloc3);
  1089. paramanager.allocparaloc(list,paraloc2);
  1090. a_paramaddr_ref(list,dest,paraloc2);
  1091. paramanager.allocparaloc(list,paraloc2);
  1092. a_paramaddr_ref(list,source,paraloc1);
  1093. paramanager.freeparaloc(list,paraloc3);
  1094. paramanager.freeparaloc(list,paraloc2);
  1095. paramanager.freeparaloc(list,paraloc1);
  1096. alloccpuregisters(list,R_INTREGISTER,paramanager.get_volatile_registers_int(pocall_default));
  1097. alloccpuregisters(list,R_FPUREGISTER,paramanager.get_volatile_registers_fpu(pocall_default));
  1098. a_call_name(list,'FPC_MOVE');
  1099. dealloccpuregisters(list,R_FPUREGISTER,paramanager.get_volatile_registers_fpu(pocall_default));
  1100. dealloccpuregisters(list,R_INTREGISTER,paramanager.get_volatile_registers_int(pocall_default));
  1101. paraloc3.done;
  1102. paraloc2.done;
  1103. paraloc1.done;
  1104. end;
  1105. procedure tcgarm.g_concatcopy_internal(list : taasmoutput;const source,dest : treference;len : aint;aligned : boolean);
  1106. var
  1107. srcref,dstref:treference;
  1108. srcreg,destreg,countreg,r:tregister;
  1109. helpsize:aword;
  1110. copysize:byte;
  1111. cgsize:Tcgsize;
  1112. procedure genloop(count : aword;size : byte);
  1113. const
  1114. size2opsize : array[1..4] of tcgsize = (OS_8,OS_16,OS_NO,OS_32);
  1115. var
  1116. l : tasmlabel;
  1117. begin
  1118. objectlibrary.getlabel(l);
  1119. a_load_const_reg(list,OS_INT,count,countreg);
  1120. cg.a_label(list,l);
  1121. srcref.addressmode:=AM_POSTINDEXED;
  1122. dstref.addressmode:=AM_POSTINDEXED;
  1123. srcref.offset:=size;
  1124. dstref.offset:=size;
  1125. r:=getintregister(list,size2opsize[size]);
  1126. a_load_ref_reg(list,size2opsize[size],size2opsize[size],srcref,r);
  1127. list.concat(setoppostfix(taicpu.op_reg_reg_const(A_SUB,countreg,countreg,1),PF_S));
  1128. a_load_reg_ref(list,size2opsize[size],size2opsize[size],r,dstref);
  1129. list.concat(setcondition(taicpu.op_sym(A_B,l),C_NE));
  1130. { keep the registers alive }
  1131. list.concat(taicpu.op_reg_reg(A_MOV,countreg,countreg));
  1132. list.concat(taicpu.op_reg_reg(A_MOV,srcreg,srcreg));
  1133. list.concat(taicpu.op_reg_reg(A_MOV,destreg,destreg));
  1134. end;
  1135. begin
  1136. if len=0 then
  1137. exit;
  1138. helpsize:=12;
  1139. dstref:=dest;
  1140. srcref:=source;
  1141. if cs_littlesize in aktglobalswitches then
  1142. helpsize:=8;
  1143. if (len<=helpsize) and aligned then
  1144. begin
  1145. copysize:=4;
  1146. cgsize:=OS_32;
  1147. while len<>0 do
  1148. begin
  1149. if len<2 then
  1150. begin
  1151. copysize:=1;
  1152. cgsize:=OS_8;
  1153. end
  1154. else if len<4 then
  1155. begin
  1156. copysize:=2;
  1157. cgsize:=OS_16;
  1158. end;
  1159. dec(len,copysize);
  1160. r:=getintregister(list,cgsize);
  1161. a_load_ref_reg(list,cgsize,cgsize,srcref,r);
  1162. a_load_reg_ref(list,cgsize,cgsize,r,dstref);
  1163. inc(srcref.offset,copysize);
  1164. inc(dstref.offset,copysize);
  1165. end;
  1166. end
  1167. else
  1168. begin
  1169. destreg:=getintregister(list,OS_ADDR);
  1170. a_loadaddr_ref_reg(list,dest,destreg);
  1171. reference_reset_base(dstref,destreg,0);
  1172. srcreg:=getintregister(list,OS_ADDR);
  1173. a_loadaddr_ref_reg(list,source,srcreg);
  1174. reference_reset_base(srcref,srcreg,0);
  1175. countreg:=getintregister(list,OS_32);
  1176. // if cs_littlesize in aktglobalswitches then
  1177. genloop(len,1);
  1178. {
  1179. else
  1180. begin
  1181. helpsize:=len shr 2;
  1182. len:=len and 3;
  1183. if helpsize>1 then
  1184. begin
  1185. a_load_const_reg(list,OS_INT,helpsize,countreg);
  1186. list.concat(Taicpu.op_none(A_REP,S_NO));
  1187. end;
  1188. if helpsize>0 then
  1189. list.concat(Taicpu.op_none(A_MOVSD,S_NO));
  1190. if len>1 then
  1191. begin
  1192. dec(len,2);
  1193. list.concat(Taicpu.op_none(A_MOVSW,S_NO));
  1194. end;
  1195. if len=1 then
  1196. list.concat(Taicpu.op_none(A_MOVSB,S_NO));
  1197. end;
  1198. }
  1199. end;
  1200. end;
  1201. procedure tcgarm.g_concatcopy_unaligned(list : taasmoutput;const source,dest : treference;len : aint);
  1202. begin
  1203. g_concatcopy_internal(list,source,dest,len,false);
  1204. end;
  1205. procedure tcgarm.g_concatcopy(list : taasmoutput;const source,dest : treference;len : aint);
  1206. begin
  1207. g_concatcopy_internal(list,source,dest,len,true);
  1208. end;
  1209. procedure tcgarm.g_overflowCheck(list : taasmoutput;const l : tlocation;def : tdef);
  1210. var
  1211. ovloc : tlocation;
  1212. begin
  1213. ovloc.loc:=LOC_VOID;
  1214. g_overflowCheck_loc(list,l,def,ovloc);
  1215. end;
  1216. procedure tcgarm.g_overflowCheck_loc(List:TAasmOutput;const Loc:TLocation;def:TDef;ovloc : tlocation);
  1217. var
  1218. hl : tasmlabel;
  1219. ai:TAiCpu;
  1220. hflags : tresflags;
  1221. begin
  1222. if not(cs_check_overflow in aktlocalswitches) then
  1223. exit;
  1224. objectlibrary.getlabel(hl);
  1225. case ovloc.loc of
  1226. LOC_VOID:
  1227. begin
  1228. ai:=taicpu.op_sym(A_B,hl);
  1229. ai.is_jmp:=true;
  1230. if not((def.deftype=pointerdef) or
  1231. ((def.deftype=orddef) and
  1232. (torddef(def).typ in [u64bit,u16bit,u32bit,u8bit,uchar,bool8bit,bool16bit,bool32bit]))) then
  1233. ai.SetCondition(C_VC)
  1234. else
  1235. ai.SetCondition(C_CC);
  1236. list.concat(ai);
  1237. end;
  1238. LOC_FLAGS:
  1239. begin
  1240. hflags:=ovloc.resflags;
  1241. inverse_flags(hflags);
  1242. cg.a_jmp_flags(list,hflags,hl);
  1243. end;
  1244. else
  1245. internalerror(200409281);
  1246. end;
  1247. a_call_name(list,'FPC_OVERFLOW');
  1248. a_label(list,hl);
  1249. end;
  1250. procedure tcgarm.g_save_standard_registers(list : taasmoutput);
  1251. begin
  1252. { this work is done in g_proc_entry }
  1253. end;
  1254. procedure tcgarm.g_restore_standard_registers(list : taasmoutput);
  1255. begin
  1256. { this work is done in g_proc_exit }
  1257. end;
  1258. procedure tcgarm.a_jmp_cond(list : taasmoutput;cond : TOpCmp;l: tasmlabel);
  1259. var
  1260. ai : taicpu;
  1261. begin
  1262. ai:=Taicpu.Op_sym(A_B,l);
  1263. ai.SetCondition(OpCmp2AsmCond[cond]);
  1264. ai.is_jmp:=true;
  1265. list.concat(ai);
  1266. end;
  1267. procedure tcgarm.g_intf_wrapper(list: taasmoutput; procdef: tprocdef; const labelname: string; ioffset: longint);
  1268. procedure loadvmttor12;
  1269. var
  1270. href : treference;
  1271. begin
  1272. reference_reset_base(href,NR_R0,0);
  1273. cg.a_load_ref_reg(list,OS_ADDR,OS_ADDR,href,NR_R12);
  1274. end;
  1275. procedure op_onr12methodaddr;
  1276. var
  1277. href : treference;
  1278. begin
  1279. if (procdef.extnumber=$ffff) then
  1280. Internalerror(200006139);
  1281. { call/jmp vmtoffs(%eax) ; method offs }
  1282. reference_reset_base(href,NR_R12,procdef._class.vmtmethodoffset(procdef.extnumber));
  1283. cg.a_load_ref_reg(list,OS_ADDR,OS_ADDR,href,NR_R12);
  1284. list.concat(taicpu.op_reg_reg(A_MOV,NR_PC,NR_R12));
  1285. end;
  1286. var
  1287. lab : tasmsymbol;
  1288. make_global : boolean;
  1289. href : treference;
  1290. begin
  1291. if not(procdef.proctypeoption in [potype_function,potype_procedure]) then
  1292. Internalerror(200006137);
  1293. if not assigned(procdef._class) or
  1294. (procdef.procoptions*[po_classmethod, po_staticmethod,
  1295. po_methodpointer, po_interrupt, po_iocheck]<>[]) then
  1296. Internalerror(200006138);
  1297. if procdef.owner.symtabletype<>objectsymtable then
  1298. Internalerror(200109191);
  1299. make_global:=false;
  1300. if (not current_module.is_unit) or
  1301. (cs_create_smart in aktmoduleswitches) or
  1302. (procdef.owner.defowner.owner.symtabletype=globalsymtable) then
  1303. make_global:=true;
  1304. if make_global then
  1305. list.concat(Tai_symbol.Createname_global(labelname,AT_FUNCTION,0))
  1306. else
  1307. list.concat(Tai_symbol.Createname(labelname,AT_FUNCTION,0));
  1308. { set param1 interface to self }
  1309. g_adjust_self_value(list,procdef,ioffset);
  1310. { case 4 }
  1311. if po_virtualmethod in procdef.procoptions then
  1312. begin
  1313. loadvmttor12;
  1314. op_onr12methodaddr;
  1315. end
  1316. { case 0 }
  1317. else
  1318. list.concat(taicpu.op_sym(A_B,objectlibrary.newasmsymbol(procdef.mangledname,AB_EXTERNAL,AT_FUNCTION)));
  1319. list.concat(Tai_symbol_end.Createname(labelname));
  1320. end;
  1321. procedure tcg64farm.a_op64_reg_reg(list : taasmoutput;op:TOpCG;size : tcgsize;regsrc,regdst : tregister64);
  1322. var
  1323. tmpreg : tregister;
  1324. begin
  1325. case op of
  1326. OP_NEG:
  1327. begin
  1328. list.concat(setoppostfix(taicpu.op_reg_reg_const(A_RSB,regdst.reglo,regsrc.reglo,0),PF_S));
  1329. list.concat(taicpu.op_reg_reg_const(A_RSC,regdst.reghi,regsrc.reghi,0));
  1330. end;
  1331. OP_NOT:
  1332. begin
  1333. cg.a_op_reg_reg(list,OP_NOT,OS_INT,regsrc.reglo,regdst.reglo);
  1334. cg.a_op_reg_reg(list,OP_NOT,OS_INT,regsrc.reghi,regdst.reghi);
  1335. end;
  1336. else
  1337. a_op64_reg_reg_reg(list,op,size,regsrc,regdst,regdst);
  1338. end;
  1339. end;
  1340. procedure tcg64farm.a_op64_const_reg(list : taasmoutput;op:TOpCG;size : tcgsize;value : int64;reg : tregister64);
  1341. begin
  1342. a_op64_const_reg_reg(list,op,size,value,reg,reg);
  1343. end;
  1344. procedure tcg64farm.a_op64_const_reg_reg(list: taasmoutput;op:TOpCG;size : tcgsize;value : int64;regsrc,regdst : tregister64);
  1345. var
  1346. ovloc : tlocation;
  1347. begin
  1348. a_op64_const_reg_reg_checkoverflow(list,op,size,value,regsrc,regdst,false,ovloc);
  1349. end;
  1350. procedure tcg64farm.a_op64_reg_reg_reg(list: taasmoutput;op:TOpCG;size : tcgsize;regsrc1,regsrc2,regdst : tregister64);
  1351. var
  1352. ovloc : tlocation;
  1353. begin
  1354. a_op64_reg_reg_reg_checkoverflow(list,op,size,regsrc1,regsrc2,regdst,false,ovloc);
  1355. end;
  1356. procedure tcg64farm.a_op64_const_reg_reg_checkoverflow(list: taasmoutput;op:TOpCG;size : tcgsize;value : int64;regsrc,regdst : tregister64;setflags : boolean;var ovloc : tlocation);
  1357. var
  1358. tmpreg : tregister;
  1359. b : byte;
  1360. begin
  1361. ovloc.loc:=LOC_VOID;
  1362. case op of
  1363. OP_NEG,
  1364. OP_NOT :
  1365. internalerror(200306017);
  1366. end;
  1367. if (setflags or tcgarm(cg).cgsetflags) and (op in [OP_ADD,OP_SUB]) then
  1368. begin
  1369. case op of
  1370. OP_ADD:
  1371. begin
  1372. if is_shifter_const(lo(value),b) then
  1373. list.concat(setoppostfix(taicpu.op_reg_reg_const(A_ADD,regdst.reglo,regsrc.reglo,lo(value)),PF_S))
  1374. else
  1375. begin
  1376. tmpreg:=cg.getintregister(list,OS_32);
  1377. cg.a_load_const_reg(list,OS_32,lo(value),tmpreg);
  1378. list.concat(setoppostfix(taicpu.op_reg_reg_reg(A_ADD,regdst.reglo,regsrc.reglo,tmpreg),PF_S));
  1379. end;
  1380. if is_shifter_const(hi(value),b) then
  1381. list.concat(setoppostfix(taicpu.op_reg_reg_const(A_ADC,regdst.reghi,regsrc.reghi,hi(value)),PF_S))
  1382. else
  1383. begin
  1384. tmpreg:=cg.getintregister(list,OS_32);
  1385. cg.a_load_const_reg(list,OS_32,hi(value),tmpreg);
  1386. list.concat(setoppostfix(taicpu.op_reg_reg_reg(A_ADC,regdst.reghi,regsrc.reghi,tmpreg),PF_S));
  1387. end;
  1388. end;
  1389. OP_SUB:
  1390. begin
  1391. if is_shifter_const(lo(value),b) then
  1392. list.concat(setoppostfix(taicpu.op_reg_reg_const(A_SUB,regdst.reglo,regsrc.reglo,lo(value)),PF_S))
  1393. else
  1394. begin
  1395. tmpreg:=cg.getintregister(list,OS_32);
  1396. cg.a_load_const_reg(list,OS_32,lo(value),tmpreg);
  1397. list.concat(setoppostfix(taicpu.op_reg_reg_reg(A_SUB,regdst.reglo,regsrc.reglo,tmpreg),PF_S));
  1398. end;
  1399. if is_shifter_const(hi(value),b) then
  1400. list.concat(setoppostfix(taicpu.op_reg_reg_const(A_SBC,regdst.reghi,regsrc.reghi,hi(value)),PF_S))
  1401. else
  1402. begin
  1403. tmpreg:=cg.getintregister(list,OS_32);
  1404. cg.a_load_const_reg(list,OS_32,hi(value),tmpreg);
  1405. list.concat(setoppostfix(taicpu.op_reg_reg_reg(A_SBC,regdst.reghi,regsrc.reghi,tmpreg),PF_S));
  1406. end;
  1407. end;
  1408. else
  1409. internalerror(200502131);
  1410. end;
  1411. if size=OS_64 then
  1412. begin
  1413. { the arm has an weired opinion how flags for SUB/ADD are handled }
  1414. ovloc.loc:=LOC_FLAGS;
  1415. case op of
  1416. OP_ADD:
  1417. ovloc.resflags:=F_CS;
  1418. OP_SUB:
  1419. ovloc.resflags:=F_CC;
  1420. end;
  1421. end;
  1422. end
  1423. else
  1424. begin
  1425. case op of
  1426. OP_AND,OP_OR,OP_XOR:
  1427. begin
  1428. cg.a_op_const_reg_reg(list,op,OS_32,lo(value),regsrc.reglo,regdst.reglo);
  1429. cg.a_op_const_reg_reg(list,op,OS_32,hi(value),regsrc.reghi,regdst.reghi);
  1430. end;
  1431. OP_ADD:
  1432. begin
  1433. if is_shifter_const(lo(value),b) then
  1434. list.concat(setoppostfix(taicpu.op_reg_reg_const(A_ADD,regdst.reglo,regsrc.reglo,lo(value)),PF_S))
  1435. else
  1436. begin
  1437. tmpreg:=cg.getintregister(list,OS_32);
  1438. cg.a_load_const_reg(list,OS_32,lo(value),tmpreg);
  1439. list.concat(setoppostfix(taicpu.op_reg_reg_reg(A_ADD,regdst.reglo,regsrc.reglo,tmpreg),PF_S));
  1440. end;
  1441. if is_shifter_const(hi(value),b) then
  1442. list.concat(taicpu.op_reg_reg_const(A_ADC,regdst.reghi,regsrc.reghi,hi(value)))
  1443. else
  1444. begin
  1445. tmpreg:=cg.getintregister(list,OS_32);
  1446. cg.a_load_const_reg(list,OS_32,hi(value),tmpreg);
  1447. list.concat(taicpu.op_reg_reg_reg(A_ADC,regdst.reghi,regsrc.reghi,tmpreg));
  1448. end;
  1449. end;
  1450. OP_SUB:
  1451. begin
  1452. if is_shifter_const(lo(value),b) then
  1453. list.concat(setoppostfix(taicpu.op_reg_reg_const(A_SUB,regdst.reglo,regsrc.reglo,lo(value)),PF_S))
  1454. else
  1455. begin
  1456. tmpreg:=cg.getintregister(list,OS_32);
  1457. cg.a_load_const_reg(list,OS_32,lo(value),tmpreg);
  1458. list.concat(setoppostfix(taicpu.op_reg_reg_reg(A_SUB,regdst.reglo,regsrc.reglo,tmpreg),PF_S));
  1459. end;
  1460. if is_shifter_const(hi(value),b) then
  1461. list.concat(taicpu.op_reg_reg_const(A_SBC,regdst.reghi,regsrc.reghi,hi(value)))
  1462. else
  1463. begin
  1464. tmpreg:=cg.getintregister(list,OS_32);
  1465. cg.a_load_const_reg(list,OS_32,hi(value),tmpreg);
  1466. list.concat(taicpu.op_reg_reg_reg(A_SBC,regdst.reghi,regsrc.reghi,tmpreg));
  1467. end;
  1468. end;
  1469. else
  1470. internalerror(2003083101);
  1471. end;
  1472. end;
  1473. end;
  1474. procedure tcg64farm.a_op64_reg_reg_reg_checkoverflow(list: taasmoutput;op:TOpCG;size : tcgsize;regsrc1,regsrc2,regdst : tregister64;setflags : boolean;var ovloc : tlocation);
  1475. var
  1476. op1,op2:TAsmOp;
  1477. begin
  1478. ovloc.loc:=LOC_VOID;
  1479. case op of
  1480. OP_NEG,
  1481. OP_NOT :
  1482. internalerror(200306017);
  1483. end;
  1484. if (setflags or tcgarm(cg).cgsetflags) and (op in [OP_ADD,OP_SUB]) then
  1485. begin
  1486. case op of
  1487. OP_ADD:
  1488. begin
  1489. list.concat(setoppostfix(taicpu.op_reg_reg_reg(A_ADD,regdst.reglo,regsrc1.reglo,regsrc2.reglo),PF_S));
  1490. list.concat(setoppostfix(taicpu.op_reg_reg_reg(A_ADC,regdst.reghi,regsrc1.reghi,regsrc2.reghi),PF_S));
  1491. end;
  1492. OP_SUB:
  1493. begin
  1494. list.concat(setoppostfix(taicpu.op_reg_reg_reg(A_SUB,regdst.reglo,regsrc2.reglo,regsrc1.reglo),PF_S));
  1495. list.concat(setoppostfix(taicpu.op_reg_reg_reg(A_SBC,regdst.reghi,regsrc2.reghi,regsrc1.reghi),PF_S));
  1496. end;
  1497. else
  1498. internalerror(2003083101);
  1499. end;
  1500. if size=OS_64 then
  1501. begin
  1502. { the arm has an weired opinion how flags for SUB/ADD are handled }
  1503. ovloc.loc:=LOC_FLAGS;
  1504. case op of
  1505. OP_ADD:
  1506. ovloc.resflags:=F_CC;
  1507. OP_SUB:
  1508. ovloc.resflags:=F_CS;
  1509. end;
  1510. end;
  1511. end
  1512. else
  1513. begin
  1514. case op of
  1515. OP_AND,OP_OR,OP_XOR:
  1516. begin
  1517. cg.a_op_reg_reg_reg(list,op,OS_32,regsrc1.reglo,regsrc2.reglo,regdst.reglo);
  1518. cg.a_op_reg_reg_reg(list,op,OS_32,regsrc1.reghi,regsrc2.reghi,regdst.reghi);
  1519. end;
  1520. OP_ADD:
  1521. begin
  1522. list.concat(setoppostfix(taicpu.op_reg_reg_reg(A_ADD,regdst.reglo,regsrc1.reglo,regsrc2.reglo),PF_S));
  1523. list.concat(taicpu.op_reg_reg_reg(A_ADC,regdst.reghi,regsrc1.reghi,regsrc2.reghi));
  1524. end;
  1525. OP_SUB:
  1526. begin
  1527. list.concat(setoppostfix(taicpu.op_reg_reg_reg(A_SUB,regdst.reglo,regsrc2.reglo,regsrc1.reglo),PF_S));
  1528. list.concat(taicpu.op_reg_reg_reg(A_SBC,regdst.reghi,regsrc2.reghi,regsrc1.reghi));
  1529. end;
  1530. else
  1531. internalerror(2003083101);
  1532. end;
  1533. end;
  1534. end;
  1535. begin
  1536. cg:=tcgarm.create;
  1537. cg64:=tcg64farm.create;
  1538. end.