cgcpu.pas 84 KB

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