cgcpu.pas 82 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166
  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. case ToSize of
  691. { signed integer registers }
  692. OS_8,
  693. OS_S8:
  694. oppostfix:=PF_B;
  695. OS_16,
  696. OS_S16:
  697. oppostfix:=PF_H;
  698. OS_32,
  699. OS_S32:
  700. oppostfix:=PF_None;
  701. else
  702. InternalError(200308295);
  703. end;
  704. if ref.alignment<>0 then
  705. begin
  706. if target_info.endian=endian_big then
  707. dir:=-1
  708. else
  709. dir:=1;
  710. case FromSize of
  711. OS_16,OS_S16:
  712. begin
  713. shifterop_reset(so);so.shiftmode:=SM_LSR;so.shiftimm:=8;
  714. tmpreg:=getintregister(list,OS_INT);
  715. usedtmpref:=ref;
  716. if target_info.endian=endian_big then
  717. inc(usedtmpref.offset,1);
  718. usedtmpref:=a_internal_load_reg_ref(list,OS_8,OS_8,reg,usedtmpref);
  719. inc(usedtmpref.offset,dir);
  720. list.concat(taicpu.op_reg_reg_shifterop(A_MOV,tmpreg,reg,so));
  721. a_internal_load_reg_ref(list,OS_8,OS_8,tmpreg,usedtmpref);
  722. end;
  723. OS_32,OS_S32:
  724. begin
  725. shifterop_reset(so);so.shiftmode:=SM_LSR;so.shiftimm:=8;
  726. tmpreg:=getintregister(list,OS_INT);
  727. usedtmpref:=ref;
  728. if target_info.endian=endian_big then
  729. inc(usedtmpref.offset,3);
  730. usedtmpref:=a_internal_load_reg_ref(list,OS_8,OS_8,reg,usedtmpref);
  731. list.concat(taicpu.op_reg_reg_shifterop(A_MOV,tmpreg,reg,so));
  732. inc(usedtmpref.offset,dir);
  733. a_internal_load_reg_ref(list,OS_8,OS_8,tmpreg,usedtmpref);
  734. list.concat(taicpu.op_reg_reg_shifterop(A_MOV,tmpreg,tmpreg,so));
  735. inc(usedtmpref.offset,dir);
  736. a_internal_load_reg_ref(list,OS_8,OS_8,tmpreg,usedtmpref);
  737. list.concat(taicpu.op_reg_reg_shifterop(A_MOV,tmpreg,tmpreg,so));
  738. inc(usedtmpref.offset,dir);
  739. a_internal_load_reg_ref(list,OS_8,OS_8,tmpreg,usedtmpref);
  740. end
  741. else
  742. handle_load_store(list,A_STR,oppostfix,reg,ref);
  743. end;
  744. end
  745. else
  746. handle_load_store(list,A_STR,oppostfix,reg,ref);
  747. end;
  748. procedure tcgarm.a_load_ref_reg(list : TAsmList; fromsize, tosize : tcgsize;const Ref : treference;reg : tregister);
  749. var
  750. oppostfix:toppostfix;
  751. usedtmpref: treference;
  752. tmpreg,tmpreg2,tmpreg3 : tregister;
  753. so : tshifterop;
  754. dir : integer;
  755. begin
  756. case FromSize of
  757. { signed integer registers }
  758. OS_8:
  759. oppostfix:=PF_B;
  760. OS_S8:
  761. oppostfix:=PF_SB;
  762. OS_16:
  763. oppostfix:=PF_H;
  764. OS_S16:
  765. oppostfix:=PF_SH;
  766. OS_32,
  767. OS_S32:
  768. oppostfix:=PF_None;
  769. else
  770. InternalError(200308297);
  771. end;
  772. if Ref.alignment<>0 then
  773. begin
  774. if target_info.endian=endian_big then
  775. dir:=-1
  776. else
  777. dir:=1;
  778. case FromSize of
  779. OS_16,OS_S16:
  780. begin
  781. { only complicated references need an extra loadaddr }
  782. if assigned(ref.symbol) or
  783. (ref.index<>NR_NO) or
  784. (ref.offset<-4095) or
  785. (ref.offset>4094) or
  786. { sometimes the compiler reused registers }
  787. (reg=ref.index) or
  788. (reg=ref.base) then
  789. begin
  790. tmpreg3:=getintregister(list,OS_INT);
  791. a_loadaddr_ref_reg(list,ref,tmpreg3);
  792. reference_reset_base(usedtmpref,tmpreg3,0);
  793. end
  794. else
  795. usedtmpref:=ref;
  796. if target_info.endian=endian_big then
  797. inc(usedtmpref.offset,1);
  798. shifterop_reset(so);so.shiftmode:=SM_LSL;so.shiftimm:=8;
  799. tmpreg:=getintregister(list,OS_INT);
  800. a_internal_load_ref_reg(list,OS_8,OS_8,usedtmpref,tmpreg);
  801. inc(usedtmpref.offset,dir);
  802. tmpreg2:=getintregister(list,OS_INT);
  803. if FromSize=OS_16 then
  804. a_internal_load_ref_reg(list,OS_8,OS_8,usedtmpref,tmpreg2)
  805. else
  806. a_internal_load_ref_reg(list,OS_S8,OS_S8,usedtmpref,tmpreg2);
  807. list.concat(taicpu.op_reg_reg_reg_shifterop(A_ORR,reg,tmpreg,tmpreg2,so));
  808. end;
  809. OS_32,OS_S32:
  810. begin
  811. tmpreg:=getintregister(list,OS_INT);
  812. tmpreg2:=getintregister(list,OS_INT);
  813. { only complicated references need an extra loadaddr }
  814. if assigned(ref.symbol) or
  815. (ref.index<>NR_NO) or
  816. (ref.offset<-4095) or
  817. (ref.offset>4092) or
  818. { sometimes the compiler reused registers }
  819. (reg=ref.index) or
  820. (reg=ref.base) then
  821. begin
  822. tmpreg3:=getintregister(list,OS_INT);
  823. a_loadaddr_ref_reg(list,ref,tmpreg3);
  824. reference_reset_base(usedtmpref,tmpreg3,0);
  825. end
  826. else
  827. usedtmpref:=ref;
  828. if target_info.endian=endian_big then
  829. inc(usedtmpref.offset,3);
  830. shifterop_reset(so);so.shiftmode:=SM_LSL;so.shiftimm:=8;
  831. a_internal_load_ref_reg(list,OS_8,OS_8,usedtmpref,reg);
  832. inc(usedtmpref.offset,dir);
  833. a_internal_load_ref_reg(list,OS_8,OS_8,usedtmpref,tmpreg);
  834. list.concat(taicpu.op_reg_reg_reg_shifterop(A_ORR,tmpreg2,reg,tmpreg,so));
  835. inc(usedtmpref.offset,dir);
  836. a_internal_load_ref_reg(list,OS_8,OS_8,usedtmpref,reg);
  837. so.shiftimm:=16;
  838. list.concat(taicpu.op_reg_reg_reg_shifterop(A_ORR,tmpreg,tmpreg2,reg,so));
  839. inc(usedtmpref.offset,dir);
  840. a_internal_load_ref_reg(list,OS_8,OS_8,usedtmpref,tmpreg2);
  841. so.shiftimm:=24;
  842. list.concat(taicpu.op_reg_reg_reg_shifterop(A_ORR,reg,tmpreg,tmpreg2,so));
  843. end
  844. else
  845. handle_load_store(list,A_LDR,oppostfix,reg,ref);
  846. end;
  847. end
  848. else
  849. handle_load_store(list,A_LDR,oppostfix,reg,ref);
  850. if (fromsize=OS_S8) and (tosize = OS_16) then
  851. a_load_reg_reg(list,OS_16,OS_32,reg,reg);
  852. end;
  853. function tcgarm.a_internal_load_reg_ref(list : TAsmList; fromsize, tosize: tcgsize; reg : tregister;const ref : treference):treference;
  854. var
  855. oppostfix:toppostfix;
  856. begin
  857. case ToSize of
  858. { signed integer registers }
  859. OS_8,
  860. OS_S8:
  861. oppostfix:=PF_B;
  862. OS_16,
  863. OS_S16:
  864. oppostfix:=PF_H;
  865. OS_32,
  866. OS_S32:
  867. oppostfix:=PF_None;
  868. else
  869. InternalError(2003082910);
  870. end;
  871. result:=handle_load_store(list,A_STR,oppostfix,reg,ref);
  872. end;
  873. function tcgarm.a_internal_load_ref_reg(list : TAsmList; fromsize, tosize : tcgsize;const Ref : treference;reg : tregister):treference;
  874. var
  875. oppostfix:toppostfix;
  876. begin
  877. case FromSize of
  878. { signed integer registers }
  879. OS_8:
  880. oppostfix:=PF_B;
  881. OS_S8:
  882. oppostfix:=PF_SB;
  883. OS_16:
  884. oppostfix:=PF_H;
  885. OS_S16:
  886. oppostfix:=PF_SH;
  887. OS_32,
  888. OS_S32:
  889. oppostfix:=PF_None;
  890. else
  891. InternalError(200308291);
  892. end;
  893. result:=handle_load_store(list,A_LDR,oppostfix,reg,ref);
  894. end;
  895. procedure tcgarm.a_load_reg_reg(list : TAsmList; fromsize, tosize : tcgsize;reg1,reg2 : tregister);
  896. var
  897. so : tshifterop;
  898. procedure do_shift(shiftmode : tshiftmode; shiftimm : byte; reg : tregister);
  899. begin
  900. so.shiftmode:=shiftmode;
  901. so.shiftimm:=shiftimm;
  902. list.concat(taicpu.op_reg_reg_shifterop(A_MOV,reg2,reg,so));
  903. end;
  904. var
  905. instr: taicpu;
  906. conv_done: boolean;
  907. begin
  908. if (tcgsize2size[fromsize]>32) or (tcgsize2size[tosize]>32) then
  909. internalerror(2002090901);
  910. conv_done:=false;
  911. if tosize<>fromsize then
  912. begin
  913. shifterop_reset(so);
  914. conv_done:=true;
  915. if tcgsize2size[tosize]<=tcgsize2size[fromsize] then
  916. fromsize:=tosize;
  917. case fromsize of
  918. OS_8:
  919. list.concat(taicpu.op_reg_reg_const(A_AND,reg2,reg1,$ff));
  920. OS_S8:
  921. begin
  922. do_shift(SM_LSL,24,reg1);
  923. if tosize=OS_16 then
  924. begin
  925. do_shift(SM_ASR,8,reg2);
  926. do_shift(SM_LSR,16,reg2);
  927. end
  928. else
  929. do_shift(SM_ASR,24,reg2);
  930. end;
  931. OS_16:
  932. begin
  933. do_shift(SM_LSL,16,reg1);
  934. do_shift(SM_LSR,16,reg2);
  935. end;
  936. OS_S16:
  937. begin
  938. do_shift(SM_LSL,16,reg1);
  939. do_shift(SM_ASR,16,reg2)
  940. end;
  941. else
  942. conv_done:=false;
  943. end;
  944. end;
  945. if not conv_done and (reg1<>reg2) then
  946. begin
  947. { same size, only a register mov required }
  948. instr:=taicpu.op_reg_reg(A_MOV,reg2,reg1);
  949. list.Concat(instr);
  950. { Notify the register allocator that we have written a move instruction so
  951. it can try to eliminate it. }
  952. add_move_instruction(instr);
  953. end;
  954. end;
  955. procedure tcgarm.a_paramfpu_ref(list : TAsmList;size : tcgsize;const ref : treference;const paraloc : TCGPara);
  956. var
  957. href,href2 : treference;
  958. hloc : pcgparalocation;
  959. begin
  960. href:=ref;
  961. hloc:=paraloc.location;
  962. while assigned(hloc) do
  963. begin
  964. case hloc^.loc of
  965. LOC_FPUREGISTER,LOC_CFPUREGISTER:
  966. a_loadfpu_ref_reg(list,size,size,ref,hloc^.register);
  967. LOC_REGISTER :
  968. case hloc^.size of
  969. OS_F32:
  970. a_load_ref_reg(list,OS_32,OS_32,href,hloc^.register);
  971. OS_64,
  972. OS_F64:
  973. cg64.a_param64_ref(list,href,paraloc);
  974. else
  975. a_load_ref_reg(list,hloc^.size,hloc^.size,href,hloc^.register);
  976. end;
  977. LOC_REFERENCE :
  978. begin
  979. reference_reset_base(href2,hloc^.reference.index,hloc^.reference.offset);
  980. { concatcopy should choose the best way to copy the data }
  981. g_concatcopy(list,href,href2,tcgsize2size[size]);
  982. end;
  983. else
  984. internalerror(200408241);
  985. end;
  986. inc(href.offset,tcgsize2size[hloc^.size]);
  987. hloc:=hloc^.next;
  988. end;
  989. end;
  990. procedure tcgarm.a_loadfpu_reg_reg(list: TAsmList; fromsize,tosize: tcgsize; reg1, reg2: tregister);
  991. begin
  992. list.concat(setoppostfix(taicpu.op_reg_reg(A_MVF,reg2,reg1),cgsize2fpuoppostfix[tosize]));
  993. end;
  994. procedure tcgarm.a_loadfpu_ref_reg(list: TAsmList; fromsize,tosize: tcgsize; const ref: treference; reg: tregister);
  995. var
  996. oppostfix:toppostfix;
  997. begin
  998. case tosize of
  999. OS_32,
  1000. OS_F32:
  1001. oppostfix:=PF_S;
  1002. OS_64,
  1003. OS_F64:
  1004. oppostfix:=PF_D;
  1005. OS_F80:
  1006. oppostfix:=PF_E;
  1007. else
  1008. InternalError(200309021);
  1009. end;
  1010. handle_load_store(list,A_LDF,oppostfix,reg,ref);
  1011. end;
  1012. procedure tcgarm.a_loadfpu_reg_ref(list: TAsmList; fromsize, tosize: tcgsize; reg: tregister; const ref: treference);
  1013. var
  1014. oppostfix:toppostfix;
  1015. begin
  1016. case tosize of
  1017. OS_F32:
  1018. oppostfix:=PF_S;
  1019. OS_F64:
  1020. oppostfix:=PF_D;
  1021. OS_F80:
  1022. oppostfix:=PF_E;
  1023. else
  1024. InternalError(200309022);
  1025. end;
  1026. handle_load_store(list,A_STF,oppostfix,reg,ref);
  1027. end;
  1028. { comparison operations }
  1029. procedure tcgarm.a_cmp_const_reg_label(list : TAsmList;size : tcgsize;cmp_op : topcmp;a : aint;reg : tregister;
  1030. l : tasmlabel);
  1031. var
  1032. tmpreg : tregister;
  1033. b : byte;
  1034. begin
  1035. if is_shifter_const(a,b) then
  1036. list.concat(taicpu.op_reg_const(A_CMP,reg,a))
  1037. { CMN reg,0 and CMN reg,$80000000 are different from CMP reg,$ffffffff
  1038. and CMP reg,$7fffffff regarding the flags according to the ARM manual }
  1039. else if (a<>$7fffffff) and (a<>-1) and is_shifter_const(-a,b) then
  1040. list.concat(taicpu.op_reg_const(A_CMN,reg,-a))
  1041. else
  1042. begin
  1043. tmpreg:=getintregister(list,size);
  1044. a_load_const_reg(list,size,a,tmpreg);
  1045. list.concat(taicpu.op_reg_reg(A_CMP,reg,tmpreg));
  1046. end;
  1047. a_jmp_cond(list,cmp_op,l);
  1048. end;
  1049. procedure tcgarm.a_cmp_reg_reg_label(list : TAsmList;size : tcgsize;cmp_op : topcmp;reg1,reg2 : tregister;l : tasmlabel);
  1050. begin
  1051. list.concat(taicpu.op_reg_reg(A_CMP,reg2,reg1));
  1052. a_jmp_cond(list,cmp_op,l);
  1053. end;
  1054. procedure tcgarm.a_jmp_name(list : TAsmList;const s : string);
  1055. var
  1056. ai : taicpu;
  1057. begin
  1058. ai:=taicpu.op_sym(A_B,current_asmdata.RefAsmSymbol(s));
  1059. ai.is_jmp:=true;
  1060. list.concat(ai);
  1061. end;
  1062. procedure tcgarm.a_jmp_always(list : TAsmList;l: tasmlabel);
  1063. var
  1064. ai : taicpu;
  1065. begin
  1066. ai:=taicpu.op_sym(A_B,l);
  1067. ai.is_jmp:=true;
  1068. list.concat(ai);
  1069. end;
  1070. procedure tcgarm.a_jmp_flags(list : TAsmList;const f : TResFlags;l: tasmlabel);
  1071. var
  1072. ai : taicpu;
  1073. begin
  1074. ai:=setcondition(taicpu.op_sym(A_B,l),flags_to_cond(f));
  1075. ai.is_jmp:=true;
  1076. list.concat(ai);
  1077. end;
  1078. procedure tcgarm.g_flags2reg(list: TAsmList; size: TCgSize; const f: TResFlags; reg: TRegister);
  1079. begin
  1080. list.concat(setcondition(taicpu.op_reg_const(A_MOV,reg,1),flags_to_cond(f)));
  1081. list.concat(setcondition(taicpu.op_reg_const(A_MOV,reg,0),inverse_cond(flags_to_cond(f))));
  1082. end;
  1083. procedure tcgarm.g_proc_entry(list : TAsmList;localsize : longint;nostackframe:boolean);
  1084. var
  1085. ref : treference;
  1086. shift : byte;
  1087. firstfloatreg,lastfloatreg,
  1088. r : byte;
  1089. regs : tcpuregisterset;
  1090. begin
  1091. LocalSize:=align(LocalSize,4);
  1092. if not(nostackframe) then
  1093. begin
  1094. firstfloatreg:=RS_NO;
  1095. { save floating point registers? }
  1096. for r:=RS_F0 to RS_F7 do
  1097. if r in rg[R_FPUREGISTER].used_in_proc-paramanager.get_volatile_registers_fpu(pocall_stdcall) then
  1098. begin
  1099. if firstfloatreg=RS_NO then
  1100. firstfloatreg:=r;
  1101. lastfloatreg:=r;
  1102. end;
  1103. a_reg_alloc(list,NR_STACK_POINTER_REG);
  1104. if current_procinfo.framepointer<>NR_STACK_POINTER_REG then
  1105. begin
  1106. a_reg_alloc(list,NR_FRAME_POINTER_REG);
  1107. a_reg_alloc(list,NR_R12);
  1108. list.concat(taicpu.op_reg_reg(A_MOV,NR_R12,NR_STACK_POINTER_REG));
  1109. end;
  1110. { save int registers }
  1111. reference_reset(ref);
  1112. ref.index:=NR_STACK_POINTER_REG;
  1113. ref.addressmode:=AM_PREINDEXED;
  1114. regs:=rg[R_INTREGISTER].used_in_proc-paramanager.get_volatile_registers_int(pocall_stdcall);
  1115. if current_procinfo.framepointer<>NR_STACK_POINTER_REG then
  1116. regs:=regs+[RS_R11,RS_R12,RS_R14,RS_R15]
  1117. else
  1118. if (regs<>[]) or (pi_do_call in current_procinfo.flags) then
  1119. include(regs,RS_R14);
  1120. if regs<>[] then
  1121. list.concat(setoppostfix(taicpu.op_ref_regset(A_STM,ref,regs),PF_FD));
  1122. if current_procinfo.framepointer<>NR_STACK_POINTER_REG then
  1123. list.concat(taicpu.op_reg_reg_const(A_SUB,NR_FRAME_POINTER_REG,NR_R12,4));
  1124. { allocate necessary stack size
  1125. not necessary according to Yury Sidorov
  1126. { don't use a_op_const_reg_reg here because we don't allow register allocations
  1127. in the entry/exit code }
  1128. if (target_info.system in [system_arm_wince]) and
  1129. (localsize>=winstackpagesize) then
  1130. begin
  1131. if localsize div winstackpagesize<=5 then
  1132. begin
  1133. if is_shifter_const(localsize,shift) then
  1134. list.concat(Taicpu.op_reg_reg_const(A_SUB,NR_STACK_POINTER_REG,NR_STACK_POINTER_REG,localsize))
  1135. else
  1136. begin
  1137. a_load_const_reg(list,OS_ADDR,localsize,NR_R12);
  1138. list.concat(taicpu.op_reg_reg_reg(A_SUB,NR_STACK_POINTER_REG,NR_STACK_POINTER_REG,NR_R12));
  1139. end;
  1140. for i:=1 to localsize div winstackpagesize do
  1141. begin
  1142. if localsize-i*winstackpagesize<4096 then
  1143. reference_reset_base(href,NR_STACK_POINTER_REG,-(localsize-i*winstackpagesize))
  1144. else
  1145. begin
  1146. a_load_const_reg(list,OS_ADDR,-(localsize-i*winstackpagesize),NR_R12);
  1147. reference_reset_base(href,NR_STACK_POINTER_REG,0);
  1148. href.index:=NR_R12;
  1149. end;
  1150. { the data stored doesn't matter }
  1151. list.concat(Taicpu.op_reg_ref(A_STR,NR_R0,href));
  1152. end;
  1153. a_reg_dealloc(list,NR_R12);
  1154. reference_reset_base(href,NR_STACK_POINTER_REG,0);
  1155. { the data stored doesn't matter }
  1156. list.concat(Taicpu.op_reg_ref(A_STR,NR_R0,href));
  1157. end
  1158. else
  1159. begin
  1160. current_asmdata.getjumplabel(again);
  1161. list.concat(Taicpu.op_reg_const(A_MOV,NR_R12,localsize div winstackpagesize));
  1162. a_label(list,again);
  1163. { always shifterop }
  1164. list.concat(Taicpu.op_reg_reg_const(A_SUB,NR_STACK_POINTER_REG,NR_STACK_POINTER_REG,winstackpagesize));
  1165. reference_reset_base(href,NR_STACK_POINTER_REG,0);
  1166. { the data stored doesn't matter }
  1167. list.concat(Taicpu.op_reg_ref(A_STR,NR_R0,href));
  1168. list.concat(Taicpu.op_reg_reg_const(A_SUB,NR_R12,NR_R12,1));
  1169. a_jmp_cond(list,OC_NE,again);
  1170. if is_shifter_const(localsize mod winstackpagesize,shift) then
  1171. list.concat(Taicpu.op_reg_reg_const(A_SUB,NR_STACK_POINTER_REG,NR_STACK_POINTER_REG,localsize mod winstackpagesize))
  1172. else
  1173. begin
  1174. a_load_const_reg(list,OS_ADDR,localsize mod winstackpagesize,NR_R12);
  1175. list.concat(taicpu.op_reg_reg_reg(A_SUB,NR_STACK_POINTER_REG,NR_STACK_POINTER_REG,NR_R12));
  1176. end;
  1177. a_reg_dealloc(list,NR_R12);
  1178. reference_reset_base(href,NR_STACK_POINTER_REG,0);
  1179. { the data stored doesn't matter }
  1180. list.concat(Taicpu.op_reg_ref(A_STR,NR_R0,href));
  1181. end
  1182. end
  1183. else
  1184. }
  1185. if LocalSize<>0 then
  1186. if not(is_shifter_const(localsize,shift)) then
  1187. begin
  1188. if current_procinfo.framepointer=NR_STACK_POINTER_REG then
  1189. a_reg_alloc(list,NR_R12);
  1190. a_load_const_reg(list,OS_ADDR,LocalSize,NR_R12);
  1191. list.concat(taicpu.op_reg_reg_reg(A_SUB,NR_STACK_POINTER_REG,NR_STACK_POINTER_REG,NR_R12));
  1192. a_reg_dealloc(list,NR_R12);
  1193. end
  1194. else
  1195. begin
  1196. a_reg_dealloc(list,NR_R12);
  1197. list.concat(taicpu.op_reg_reg_const(A_SUB,NR_STACK_POINTER_REG,NR_STACK_POINTER_REG,LocalSize));
  1198. end;
  1199. if firstfloatreg<>RS_NO then
  1200. begin
  1201. reference_reset(ref);
  1202. if tg.direction*tarmprocinfo(current_procinfo).floatregstart>=1023 then
  1203. begin
  1204. a_load_const_reg(list,OS_ADDR,-tarmprocinfo(current_procinfo).floatregstart,NR_R12);
  1205. list.concat(taicpu.op_reg_reg_reg(A_SUB,NR_R12,current_procinfo.framepointer,NR_R12));
  1206. ref.base:=NR_R12;
  1207. end
  1208. else
  1209. begin
  1210. ref.base:=current_procinfo.framepointer;
  1211. ref.offset:=tarmprocinfo(current_procinfo).floatregstart;
  1212. end;
  1213. list.concat(taicpu.op_reg_const_ref(A_SFM,newreg(R_FPUREGISTER,firstfloatreg,R_SUBWHOLE),
  1214. lastfloatreg-firstfloatreg+1,ref));
  1215. end;
  1216. end;
  1217. end;
  1218. procedure tcgarm.g_proc_exit(list : TAsmList;parasize : longint;nostackframe:boolean);
  1219. var
  1220. ref : treference;
  1221. firstfloatreg,lastfloatreg,
  1222. r : byte;
  1223. shift : byte;
  1224. regs : tcpuregisterset;
  1225. LocalSize : longint;
  1226. begin
  1227. if not(nostackframe) then
  1228. begin
  1229. { restore floating point register }
  1230. firstfloatreg:=RS_NO;
  1231. { save floating point registers? }
  1232. for r:=RS_F0 to RS_F7 do
  1233. if r in rg[R_FPUREGISTER].used_in_proc-paramanager.get_volatile_registers_fpu(pocall_stdcall) then
  1234. begin
  1235. if firstfloatreg=RS_NO then
  1236. firstfloatreg:=r;
  1237. lastfloatreg:=r;
  1238. end;
  1239. if firstfloatreg<>RS_NO then
  1240. begin
  1241. reference_reset(ref);
  1242. if tg.direction*tarmprocinfo(current_procinfo).floatregstart>=1023 then
  1243. begin
  1244. a_load_const_reg(list,OS_ADDR,-tarmprocinfo(current_procinfo).floatregstart,NR_R12);
  1245. list.concat(taicpu.op_reg_reg_reg(A_SUB,NR_R12,current_procinfo.framepointer,NR_R12));
  1246. ref.base:=NR_R12;
  1247. end
  1248. else
  1249. begin
  1250. ref.base:=current_procinfo.framepointer;
  1251. ref.offset:=tarmprocinfo(current_procinfo).floatregstart;
  1252. end;
  1253. list.concat(taicpu.op_reg_const_ref(A_LFM,newreg(R_FPUREGISTER,firstfloatreg,R_SUBWHOLE),
  1254. lastfloatreg-firstfloatreg+1,ref));
  1255. end;
  1256. if (current_procinfo.framepointer=NR_STACK_POINTER_REG) then
  1257. begin
  1258. LocalSize:=current_procinfo.calc_stackframe_size;
  1259. if LocalSize<>0 then
  1260. if not(is_shifter_const(LocalSize,shift)) then
  1261. begin
  1262. a_reg_alloc(list,NR_R12);
  1263. a_load_const_reg(list,OS_ADDR,LocalSize,NR_R12);
  1264. list.concat(taicpu.op_reg_reg_reg(A_ADD,NR_STACK_POINTER_REG,NR_STACK_POINTER_REG,NR_R12));
  1265. a_reg_dealloc(list,NR_R12);
  1266. end
  1267. else
  1268. begin
  1269. list.concat(taicpu.op_reg_reg_const(A_ADD,NR_STACK_POINTER_REG,NR_STACK_POINTER_REG,LocalSize));
  1270. end;
  1271. regs:=rg[R_INTREGISTER].used_in_proc-paramanager.get_volatile_registers_int(pocall_stdcall);
  1272. if (pi_do_call in current_procinfo.flags) or (regs<>[]) then
  1273. begin
  1274. exclude(regs,RS_R14);
  1275. include(regs,RS_R15);
  1276. end;
  1277. if regs=[] then
  1278. list.concat(taicpu.op_reg_reg(A_MOV,NR_R15,NR_R14))
  1279. else
  1280. begin
  1281. reference_reset(ref);
  1282. ref.index:=NR_STACK_POINTER_REG;
  1283. ref.addressmode:=AM_PREINDEXED;
  1284. list.concat(setoppostfix(taicpu.op_ref_regset(A_LDM,ref,regs),PF_FD));
  1285. end;
  1286. end
  1287. else
  1288. begin
  1289. { restore int registers and return }
  1290. reference_reset(ref);
  1291. ref.index:=NR_FRAME_POINTER_REG;
  1292. 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));
  1293. end;
  1294. end
  1295. else
  1296. list.concat(taicpu.op_reg_reg(A_MOV,NR_PC,NR_R14));
  1297. end;
  1298. procedure tcgarm.a_loadaddr_ref_reg(list : TAsmList;const ref : treference;r : tregister);
  1299. var
  1300. b : byte;
  1301. tmpref : treference;
  1302. instr : taicpu;
  1303. begin
  1304. if ref.addressmode<>AM_OFFSET then
  1305. internalerror(200309071);
  1306. tmpref:=ref;
  1307. { Be sure to have a base register }
  1308. if (tmpref.base=NR_NO) then
  1309. begin
  1310. if tmpref.shiftmode<>SM_None then
  1311. internalerror(200308294);
  1312. if tmpref.signindex<0 then
  1313. internalerror(200312023);
  1314. tmpref.base:=tmpref.index;
  1315. tmpref.index:=NR_NO;
  1316. end;
  1317. if assigned(tmpref.symbol) or
  1318. not((is_shifter_const(tmpref.offset,b)) or
  1319. (is_shifter_const(-tmpref.offset,b))
  1320. ) then
  1321. fixref(list,tmpref);
  1322. { expect a base here if there is an index }
  1323. if (tmpref.base=NR_NO) and (tmpref.index<>NR_NO) then
  1324. internalerror(200312022);
  1325. if tmpref.index<>NR_NO then
  1326. begin
  1327. if tmpref.shiftmode<>SM_None then
  1328. internalerror(200312021);
  1329. if tmpref.signindex<0 then
  1330. a_op_reg_reg_reg(list,OP_SUB,OS_ADDR,tmpref.base,tmpref.index,r)
  1331. else
  1332. a_op_reg_reg_reg(list,OP_ADD,OS_ADDR,tmpref.base,tmpref.index,r);
  1333. if tmpref.offset<>0 then
  1334. a_op_const_reg_reg(list,OP_ADD,OS_ADDR,tmpref.offset,r,r);
  1335. end
  1336. else
  1337. begin
  1338. if tmpref.base=NR_NO then
  1339. a_load_const_reg(list,OS_ADDR,tmpref.offset,r)
  1340. else
  1341. if tmpref.offset<>0 then
  1342. a_op_const_reg_reg(list,OP_ADD,OS_ADDR,tmpref.offset,tmpref.base,r)
  1343. else
  1344. begin
  1345. instr:=taicpu.op_reg_reg(A_MOV,r,tmpref.base);
  1346. list.concat(instr);
  1347. add_move_instruction(instr);
  1348. end;
  1349. end;
  1350. end;
  1351. procedure tcgarm.fixref(list : TAsmList;var ref : treference);
  1352. var
  1353. tmpreg : tregister;
  1354. tmpref : treference;
  1355. l : tasmlabel;
  1356. begin
  1357. { absolute symbols can't be handled directly, we've to store the symbol reference
  1358. in the text segment and access it pc relative
  1359. For now, we assume that references where base or index equals to PC are already
  1360. relative, all other references are assumed to be absolute and thus they need
  1361. to be handled extra.
  1362. A proper solution would be to change refoptions to a set and store the information
  1363. if the symbol is absolute or relative there.
  1364. }
  1365. { create consts entry }
  1366. reference_reset(tmpref);
  1367. current_asmdata.getjumplabel(l);
  1368. cg.a_label(current_procinfo.aktlocaldata,l);
  1369. tmpref.symboldata:=current_procinfo.aktlocaldata.last;
  1370. if assigned(ref.symbol) then
  1371. current_procinfo.aktlocaldata.concat(tai_const.create_sym_offset(ref.symbol,ref.offset))
  1372. else
  1373. current_procinfo.aktlocaldata.concat(tai_const.Create_32bit(ref.offset));
  1374. { load consts entry }
  1375. tmpreg:=getintregister(list,OS_INT);
  1376. tmpref.symbol:=l;
  1377. tmpref.base:=NR_PC;
  1378. list.concat(taicpu.op_reg_ref(A_LDR,tmpreg,tmpref));
  1379. if (ref.base<>NR_NO) then
  1380. begin
  1381. if ref.index<>NR_NO then
  1382. begin
  1383. list.concat(taicpu.op_reg_reg_reg(A_ADD,tmpreg,ref.base,tmpreg));
  1384. ref.base:=tmpreg;
  1385. end
  1386. else
  1387. if ref.base<>NR_PC then
  1388. begin
  1389. ref.index:=tmpreg;
  1390. ref.shiftimm:=0;
  1391. ref.signindex:=1;
  1392. ref.shiftmode:=SM_None;
  1393. end
  1394. else
  1395. ref.base:=tmpreg;
  1396. end
  1397. else
  1398. ref.base:=tmpreg;
  1399. ref.offset:=0;
  1400. ref.symbol:=nil;
  1401. end;
  1402. procedure tcgarm.g_concatcopy_move(list : TAsmList;const source,dest : treference;len : aint);
  1403. var
  1404. paraloc1,paraloc2,paraloc3 : TCGPara;
  1405. begin
  1406. paraloc1.init;
  1407. paraloc2.init;
  1408. paraloc3.init;
  1409. paramanager.getintparaloc(pocall_default,1,paraloc1);
  1410. paramanager.getintparaloc(pocall_default,2,paraloc2);
  1411. paramanager.getintparaloc(pocall_default,3,paraloc3);
  1412. paramanager.allocparaloc(list,paraloc3);
  1413. a_param_const(list,OS_INT,len,paraloc3);
  1414. paramanager.allocparaloc(list,paraloc2);
  1415. a_paramaddr_ref(list,dest,paraloc2);
  1416. paramanager.allocparaloc(list,paraloc2);
  1417. a_paramaddr_ref(list,source,paraloc1);
  1418. paramanager.freeparaloc(list,paraloc3);
  1419. paramanager.freeparaloc(list,paraloc2);
  1420. paramanager.freeparaloc(list,paraloc1);
  1421. alloccpuregisters(list,R_INTREGISTER,paramanager.get_volatile_registers_int(pocall_default));
  1422. alloccpuregisters(list,R_FPUREGISTER,paramanager.get_volatile_registers_fpu(pocall_default));
  1423. a_call_name(list,'FPC_MOVE');
  1424. dealloccpuregisters(list,R_FPUREGISTER,paramanager.get_volatile_registers_fpu(pocall_default));
  1425. dealloccpuregisters(list,R_INTREGISTER,paramanager.get_volatile_registers_int(pocall_default));
  1426. paraloc3.done;
  1427. paraloc2.done;
  1428. paraloc1.done;
  1429. end;
  1430. procedure tcgarm.g_concatcopy_internal(list : TAsmList;const source,dest : treference;len : aint;aligned : boolean);
  1431. const
  1432. 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}
  1433. var
  1434. srcref,dstref,usedtmpref,usedtmpref2:treference;
  1435. srcreg,destreg,countreg,r,tmpreg:tregister;
  1436. helpsize:aint;
  1437. copysize:byte;
  1438. cgsize:Tcgsize;
  1439. tmpregisters:array[1..maxtmpreg] of tregister;
  1440. tmpregi,tmpregi2:byte;
  1441. { will never be called with count<=4 }
  1442. procedure genloop(count : aword;size : byte);
  1443. const
  1444. size2opsize : array[1..4] of tcgsize = (OS_8,OS_16,OS_NO,OS_32);
  1445. var
  1446. l : tasmlabel;
  1447. begin
  1448. current_asmdata.getjumplabel(l);
  1449. if count<size then size:=1;
  1450. a_load_const_reg(list,OS_INT,count div size,countreg);
  1451. cg.a_label(list,l);
  1452. srcref.addressmode:=AM_POSTINDEXED;
  1453. dstref.addressmode:=AM_POSTINDEXED;
  1454. srcref.offset:=size;
  1455. dstref.offset:=size;
  1456. r:=getintregister(list,size2opsize[size]);
  1457. a_load_ref_reg(list,size2opsize[size],size2opsize[size],srcref,r);
  1458. list.concat(setoppostfix(taicpu.op_reg_reg_const(A_SUB,countreg,countreg,1),PF_S));
  1459. a_load_reg_ref(list,size2opsize[size],size2opsize[size],r,dstref);
  1460. a_jmp_flags(list,F_NE,l);
  1461. srcref.offset:=1;
  1462. dstref.offset:=1;
  1463. case count mod size of
  1464. 1:
  1465. begin
  1466. a_load_ref_reg(list,OS_8,OS_8,srcref,r);
  1467. a_load_reg_ref(list,OS_8,OS_8,r,dstref);
  1468. end;
  1469. 2:
  1470. if aligned then
  1471. begin
  1472. a_load_ref_reg(list,OS_16,OS_16,srcref,r);
  1473. a_load_reg_ref(list,OS_16,OS_16,r,dstref);
  1474. end
  1475. else
  1476. begin
  1477. a_load_ref_reg(list,OS_8,OS_8,srcref,r);
  1478. a_load_reg_ref(list,OS_8,OS_8,r,dstref);
  1479. a_load_ref_reg(list,OS_8,OS_8,srcref,r);
  1480. a_load_reg_ref(list,OS_8,OS_8,r,dstref);
  1481. end;
  1482. 3:
  1483. if aligned then
  1484. begin
  1485. srcref.offset:=2;
  1486. dstref.offset:=2;
  1487. a_load_ref_reg(list,OS_16,OS_16,srcref,r);
  1488. a_load_reg_ref(list,OS_16,OS_16,r,dstref);
  1489. a_load_ref_reg(list,OS_8,OS_8,srcref,r);
  1490. a_load_reg_ref(list,OS_8,OS_8,r,dstref);
  1491. end
  1492. else
  1493. begin
  1494. a_load_ref_reg(list,OS_8,OS_8,srcref,r);
  1495. a_load_reg_ref(list,OS_8,OS_8,r,dstref);
  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. a_load_ref_reg(list,OS_8,OS_8,srcref,r);
  1499. a_load_reg_ref(list,OS_8,OS_8,r,dstref);
  1500. end;
  1501. end;
  1502. { keep the registers alive }
  1503. list.concat(taicpu.op_reg_reg(A_MOV,countreg,countreg));
  1504. list.concat(taicpu.op_reg_reg(A_MOV,srcreg,srcreg));
  1505. list.concat(taicpu.op_reg_reg(A_MOV,destreg,destreg));
  1506. end;
  1507. begin
  1508. if len=0 then
  1509. exit;
  1510. helpsize:=12+maxtmpreg*4;//52 with maxtmpreg=10
  1511. dstref:=dest;
  1512. srcref:=source;
  1513. if cs_opt_size in current_settings.optimizerswitches then
  1514. helpsize:=8;
  1515. if (len<=helpsize) and aligned then
  1516. begin
  1517. tmpregi:=0;
  1518. srcreg:=getintregister(list,OS_ADDR);
  1519. { explicit pc relative addressing, could be
  1520. e.g. a floating point constant }
  1521. if source.base=NR_PC then
  1522. begin
  1523. { ... then we don't need a loadaddr }
  1524. srcref:=source;
  1525. end
  1526. else
  1527. begin
  1528. a_loadaddr_ref_reg(list,source,srcreg);
  1529. reference_reset_base(srcref,srcreg,0);
  1530. end;
  1531. while (len div 4 <> 0) and (tmpregi<maxtmpreg) do
  1532. begin
  1533. inc(tmpregi);
  1534. tmpregisters[tmpregi]:=getintregister(list,OS_32);
  1535. a_load_ref_reg(list,OS_32,OS_32,srcref,tmpregisters[tmpregi]);
  1536. inc(srcref.offset,4);
  1537. dec(len,4);
  1538. end;
  1539. destreg:=getintregister(list,OS_ADDR);
  1540. a_loadaddr_ref_reg(list,dest,destreg);
  1541. reference_reset_base(dstref,destreg,0);
  1542. tmpregi2:=1;
  1543. while (tmpregi2<=tmpregi) do
  1544. begin
  1545. a_load_reg_ref(list,OS_32,OS_32,tmpregisters[tmpregi2],dstref);
  1546. inc(dstref.offset,4);
  1547. inc(tmpregi2);
  1548. end;
  1549. copysize:=4;
  1550. cgsize:=OS_32;
  1551. while len<>0 do
  1552. begin
  1553. if len<2 then
  1554. begin
  1555. copysize:=1;
  1556. cgsize:=OS_8;
  1557. end
  1558. else if len<4 then
  1559. begin
  1560. copysize:=2;
  1561. cgsize:=OS_16;
  1562. end;
  1563. dec(len,copysize);
  1564. r:=getintregister(list,cgsize);
  1565. a_load_ref_reg(list,cgsize,cgsize,srcref,r);
  1566. a_load_reg_ref(list,cgsize,cgsize,r,dstref);
  1567. inc(srcref.offset,copysize);
  1568. inc(dstref.offset,copysize);
  1569. end;{end of while}
  1570. end
  1571. else
  1572. begin
  1573. cgsize:=OS_32;
  1574. if (len<=4) then{len<=4 and not aligned}
  1575. begin
  1576. r:=getintregister(list,cgsize);
  1577. usedtmpref:=a_internal_load_ref_reg(list,OS_8,OS_8,srcref,r);
  1578. if Len=1 then
  1579. a_load_reg_ref(list,OS_8,OS_8,r,dstref)
  1580. else
  1581. begin
  1582. tmpreg:=getintregister(list,cgsize);
  1583. usedtmpref2:=a_internal_load_reg_ref(list,OS_8,OS_8,r,dstref);
  1584. inc(usedtmpref.offset,1);
  1585. a_load_ref_reg(list,OS_8,OS_8,usedtmpref,tmpreg);
  1586. inc(usedtmpref2.offset,1);
  1587. a_load_reg_ref(list,OS_8,OS_8,tmpreg,usedtmpref2);
  1588. if len>2 then
  1589. begin
  1590. inc(usedtmpref.offset,1);
  1591. a_load_ref_reg(list,OS_8,OS_8,usedtmpref,tmpreg);
  1592. inc(usedtmpref2.offset,1);
  1593. a_load_reg_ref(list,OS_8,OS_8,tmpreg,usedtmpref2);
  1594. if len>3 then
  1595. begin
  1596. inc(usedtmpref.offset,1);
  1597. a_load_ref_reg(list,OS_8,OS_8,usedtmpref,tmpreg);
  1598. inc(usedtmpref2.offset,1);
  1599. a_load_reg_ref(list,OS_8,OS_8,tmpreg,usedtmpref2);
  1600. end;
  1601. end;
  1602. end;
  1603. end{end of if len<=4}
  1604. else
  1605. begin{unaligned & 4<len<helpsize **or** aligned/unaligned & len>helpsize}
  1606. destreg:=getintregister(list,OS_ADDR);
  1607. a_loadaddr_ref_reg(list,dest,destreg);
  1608. reference_reset_base(dstref,destreg,0);
  1609. srcreg:=getintregister(list,OS_ADDR);
  1610. a_loadaddr_ref_reg(list,source,srcreg);
  1611. reference_reset_base(srcref,srcreg,0);
  1612. countreg:=getintregister(list,OS_32);
  1613. // if cs_opt_size in current_settings.optimizerswitches then
  1614. { roozbeh : it seems loading 1 byte is faster becouse of caching/fetching(?) }
  1615. {if aligned then
  1616. genloop(len,4)
  1617. else}
  1618. genloop(len,1);
  1619. end;
  1620. end;
  1621. end;
  1622. procedure tcgarm.g_concatcopy_unaligned(list : TAsmList;const source,dest : treference;len : aint);
  1623. begin
  1624. g_concatcopy_internal(list,source,dest,len,false);
  1625. end;
  1626. procedure tcgarm.g_concatcopy(list : TAsmList;const source,dest : treference;len : aint);
  1627. begin
  1628. if (source.alignment in [1..3]) or
  1629. (dest.alignment in [1..3]) then
  1630. g_concatcopy_internal(list,source,dest,len,false)
  1631. else
  1632. g_concatcopy_internal(list,source,dest,len,true);
  1633. end;
  1634. procedure tcgarm.g_overflowCheck(list : TAsmList;const l : tlocation;def : tdef);
  1635. var
  1636. ovloc : tlocation;
  1637. begin
  1638. ovloc.loc:=LOC_VOID;
  1639. g_overflowCheck_loc(list,l,def,ovloc);
  1640. end;
  1641. procedure tcgarm.g_overflowCheck_loc(List:TAsmList;const Loc:TLocation;def:TDef;ovloc : tlocation);
  1642. var
  1643. hl : tasmlabel;
  1644. ai:TAiCpu;
  1645. hflags : tresflags;
  1646. begin
  1647. if not(cs_check_overflow in current_settings.localswitches) then
  1648. exit;
  1649. current_asmdata.getjumplabel(hl);
  1650. case ovloc.loc of
  1651. LOC_VOID:
  1652. begin
  1653. ai:=taicpu.op_sym(A_B,hl);
  1654. ai.is_jmp:=true;
  1655. if not((def.typ=pointerdef) or
  1656. ((def.typ=orddef) and
  1657. (torddef(def).ordtype in [u64bit,u16bit,u32bit,u8bit,uchar,bool8bit,bool16bit,bool32bit]))) then
  1658. ai.SetCondition(C_VC)
  1659. else
  1660. if TAiCpu(List.Last).opcode in [A_RSB,A_RSC,A_SBC,A_SUB] then
  1661. ai.SetCondition(C_CS)
  1662. else
  1663. ai.SetCondition(C_CC);
  1664. list.concat(ai);
  1665. end;
  1666. LOC_FLAGS:
  1667. begin
  1668. hflags:=ovloc.resflags;
  1669. inverse_flags(hflags);
  1670. cg.a_jmp_flags(list,hflags,hl);
  1671. end;
  1672. else
  1673. internalerror(200409281);
  1674. end;
  1675. a_call_name(list,'FPC_OVERFLOW');
  1676. a_label(list,hl);
  1677. end;
  1678. procedure tcgarm.g_save_registers(list : TAsmList);
  1679. begin
  1680. { this work is done in g_proc_entry }
  1681. end;
  1682. procedure tcgarm.g_restore_registers(list : TAsmList);
  1683. begin
  1684. { this work is done in g_proc_exit }
  1685. end;
  1686. procedure tcgarm.a_jmp_cond(list : TAsmList;cond : TOpCmp;l: tasmlabel);
  1687. var
  1688. ai : taicpu;
  1689. begin
  1690. ai:=Taicpu.Op_sym(A_B,l);
  1691. ai.SetCondition(OpCmp2AsmCond[cond]);
  1692. ai.is_jmp:=true;
  1693. list.concat(ai);
  1694. end;
  1695. procedure tcgarm.g_intf_wrapper(list: TAsmList; procdef: tprocdef; const labelname: string; ioffset: longint);
  1696. procedure loadvmttor12;
  1697. var
  1698. href : treference;
  1699. begin
  1700. reference_reset_base(href,NR_R0,0);
  1701. cg.a_load_ref_reg(list,OS_ADDR,OS_ADDR,href,NR_R12);
  1702. end;
  1703. procedure op_onr12methodaddr;
  1704. var
  1705. href : treference;
  1706. begin
  1707. if (procdef.extnumber=$ffff) then
  1708. Internalerror(200006139);
  1709. { call/jmp vmtoffs(%eax) ; method offs }
  1710. reference_reset_base(href,NR_R12,procdef._class.vmtmethodoffset(procdef.extnumber));
  1711. cg.a_load_ref_reg(list,OS_ADDR,OS_ADDR,href,NR_R12);
  1712. list.concat(taicpu.op_reg_reg(A_MOV,NR_PC,NR_R12));
  1713. end;
  1714. var
  1715. make_global : boolean;
  1716. begin
  1717. if not(procdef.proctypeoption in [potype_function,potype_procedure]) then
  1718. Internalerror(200006137);
  1719. if not assigned(procdef._class) or
  1720. (procdef.procoptions*[po_classmethod, po_staticmethod,
  1721. po_methodpointer, po_interrupt, po_iocheck]<>[]) then
  1722. Internalerror(200006138);
  1723. if procdef.owner.symtabletype<>ObjectSymtable then
  1724. Internalerror(200109191);
  1725. make_global:=false;
  1726. if (not current_module.is_unit) or
  1727. create_smartlink or
  1728. (procdef.owner.defowner.owner.symtabletype=globalsymtable) then
  1729. make_global:=true;
  1730. if make_global then
  1731. list.concat(Tai_symbol.Createname_global(labelname,AT_FUNCTION,0))
  1732. else
  1733. list.concat(Tai_symbol.Createname(labelname,AT_FUNCTION,0));
  1734. { set param1 interface to self }
  1735. g_adjust_self_value(list,procdef,ioffset);
  1736. { case 4 }
  1737. if po_virtualmethod in procdef.procoptions then
  1738. begin
  1739. loadvmttor12;
  1740. op_onr12methodaddr;
  1741. end
  1742. { case 0 }
  1743. else
  1744. list.concat(taicpu.op_sym(A_B,current_asmdata.RefAsmSymbol(procdef.mangledname)));
  1745. list.concat(Tai_symbol_end.Createname(labelname));
  1746. end;
  1747. procedure tcg64farm.a_op64_reg_reg(list : TAsmList;op:TOpCG;size : tcgsize;regsrc,regdst : tregister64);
  1748. begin
  1749. case op of
  1750. OP_NEG:
  1751. begin
  1752. list.concat(setoppostfix(taicpu.op_reg_reg_const(A_RSB,regdst.reglo,regsrc.reglo,0),PF_S));
  1753. list.concat(taicpu.op_reg_reg_const(A_RSC,regdst.reghi,regsrc.reghi,0));
  1754. end;
  1755. OP_NOT:
  1756. begin
  1757. cg.a_op_reg_reg(list,OP_NOT,OS_INT,regsrc.reglo,regdst.reglo);
  1758. cg.a_op_reg_reg(list,OP_NOT,OS_INT,regsrc.reghi,regdst.reghi);
  1759. end;
  1760. else
  1761. a_op64_reg_reg_reg(list,op,size,regsrc,regdst,regdst);
  1762. end;
  1763. end;
  1764. procedure tcg64farm.a_op64_const_reg(list : TAsmList;op:TOpCG;size : tcgsize;value : int64;reg : tregister64);
  1765. begin
  1766. a_op64_const_reg_reg(list,op,size,value,reg,reg);
  1767. end;
  1768. procedure tcg64farm.a_op64_const_reg_reg(list: TAsmList;op:TOpCG;size : tcgsize;value : int64;regsrc,regdst : tregister64);
  1769. var
  1770. ovloc : tlocation;
  1771. begin
  1772. a_op64_const_reg_reg_checkoverflow(list,op,size,value,regsrc,regdst,false,ovloc);
  1773. end;
  1774. procedure tcg64farm.a_op64_reg_reg_reg(list: TAsmList;op:TOpCG;size : tcgsize;regsrc1,regsrc2,regdst : tregister64);
  1775. var
  1776. ovloc : tlocation;
  1777. begin
  1778. a_op64_reg_reg_reg_checkoverflow(list,op,size,regsrc1,regsrc2,regdst,false,ovloc);
  1779. end;
  1780. procedure tcg64farm.a_op64_const_reg_reg_checkoverflow(list: TAsmList;op:TOpCG;size : tcgsize;value : int64;regsrc,regdst : tregister64;setflags : boolean;var ovloc : tlocation);
  1781. var
  1782. tmpreg : tregister;
  1783. b : byte;
  1784. begin
  1785. ovloc.loc:=LOC_VOID;
  1786. case op of
  1787. OP_NEG,
  1788. OP_NOT :
  1789. internalerror(200306017);
  1790. end;
  1791. if (setflags or tcgarm(cg).cgsetflags) and (op in [OP_ADD,OP_SUB]) then
  1792. begin
  1793. case op of
  1794. OP_ADD:
  1795. begin
  1796. if is_shifter_const(lo(value),b) then
  1797. list.concat(setoppostfix(taicpu.op_reg_reg_const(A_ADD,regdst.reglo,regsrc.reglo,lo(value)),PF_S))
  1798. else
  1799. begin
  1800. tmpreg:=cg.getintregister(list,OS_32);
  1801. cg.a_load_const_reg(list,OS_32,lo(value),tmpreg);
  1802. list.concat(setoppostfix(taicpu.op_reg_reg_reg(A_ADD,regdst.reglo,regsrc.reglo,tmpreg),PF_S));
  1803. end;
  1804. if is_shifter_const(hi(value),b) then
  1805. list.concat(setoppostfix(taicpu.op_reg_reg_const(A_ADC,regdst.reghi,regsrc.reghi,hi(value)),PF_S))
  1806. else
  1807. begin
  1808. tmpreg:=cg.getintregister(list,OS_32);
  1809. cg.a_load_const_reg(list,OS_32,hi(value),tmpreg);
  1810. list.concat(setoppostfix(taicpu.op_reg_reg_reg(A_ADC,regdst.reghi,regsrc.reghi,tmpreg),PF_S));
  1811. end;
  1812. end;
  1813. OP_SUB:
  1814. begin
  1815. if is_shifter_const(lo(value),b) then
  1816. list.concat(setoppostfix(taicpu.op_reg_reg_const(A_SUB,regdst.reglo,regsrc.reglo,lo(value)),PF_S))
  1817. else
  1818. begin
  1819. tmpreg:=cg.getintregister(list,OS_32);
  1820. cg.a_load_const_reg(list,OS_32,lo(value),tmpreg);
  1821. list.concat(setoppostfix(taicpu.op_reg_reg_reg(A_SUB,regdst.reglo,regsrc.reglo,tmpreg),PF_S));
  1822. end;
  1823. if is_shifter_const(hi(value),b) then
  1824. list.concat(setoppostfix(taicpu.op_reg_reg_const(A_SBC,regdst.reghi,regsrc.reghi,aint(hi(value))),PF_S))
  1825. else
  1826. begin
  1827. tmpreg:=cg.getintregister(list,OS_32);
  1828. cg.a_load_const_reg(list,OS_32,hi(value),tmpreg);
  1829. list.concat(setoppostfix(taicpu.op_reg_reg_reg(A_SBC,regdst.reghi,regsrc.reghi,tmpreg),PF_S));
  1830. end;
  1831. end;
  1832. else
  1833. internalerror(200502131);
  1834. end;
  1835. if size=OS_64 then
  1836. begin
  1837. { the arm has an weired opinion how flags for SUB/ADD are handled }
  1838. ovloc.loc:=LOC_FLAGS;
  1839. case op of
  1840. OP_ADD:
  1841. ovloc.resflags:=F_CS;
  1842. OP_SUB:
  1843. ovloc.resflags:=F_CC;
  1844. end;
  1845. end;
  1846. end
  1847. else
  1848. begin
  1849. case op of
  1850. OP_AND,OP_OR,OP_XOR:
  1851. begin
  1852. cg.a_op_const_reg_reg(list,op,OS_32,aint(lo(value)),regsrc.reglo,regdst.reglo);
  1853. cg.a_op_const_reg_reg(list,op,OS_32,aint(hi(value)),regsrc.reghi,regdst.reghi);
  1854. end;
  1855. OP_ADD:
  1856. begin
  1857. if is_shifter_const(aint(lo(value)),b) then
  1858. list.concat(setoppostfix(taicpu.op_reg_reg_const(A_ADD,regdst.reglo,regsrc.reglo,aint(lo(value))),PF_S))
  1859. else
  1860. begin
  1861. tmpreg:=cg.getintregister(list,OS_32);
  1862. cg.a_load_const_reg(list,OS_32,aint(lo(value)),tmpreg);
  1863. list.concat(setoppostfix(taicpu.op_reg_reg_reg(A_ADD,regdst.reglo,regsrc.reglo,tmpreg),PF_S));
  1864. end;
  1865. if is_shifter_const(aint(hi(value)),b) then
  1866. list.concat(taicpu.op_reg_reg_const(A_ADC,regdst.reghi,regsrc.reghi,aint(hi(value))))
  1867. else
  1868. begin
  1869. tmpreg:=cg.getintregister(list,OS_32);
  1870. cg.a_load_const_reg(list,OS_32,aint(hi(value)),tmpreg);
  1871. list.concat(taicpu.op_reg_reg_reg(A_ADC,regdst.reghi,regsrc.reghi,tmpreg));
  1872. end;
  1873. end;
  1874. OP_SUB:
  1875. begin
  1876. if is_shifter_const(aint(lo(value)),b) then
  1877. list.concat(setoppostfix(taicpu.op_reg_reg_const(A_SUB,regdst.reglo,regsrc.reglo,aint(lo(value))),PF_S))
  1878. else
  1879. begin
  1880. tmpreg:=cg.getintregister(list,OS_32);
  1881. cg.a_load_const_reg(list,OS_32,aint(lo(value)),tmpreg);
  1882. list.concat(setoppostfix(taicpu.op_reg_reg_reg(A_SUB,regdst.reglo,regsrc.reglo,tmpreg),PF_S));
  1883. end;
  1884. if is_shifter_const(aint(hi(value)),b) then
  1885. list.concat(taicpu.op_reg_reg_const(A_SBC,regdst.reghi,regsrc.reghi,aint(hi(value))))
  1886. else
  1887. begin
  1888. tmpreg:=cg.getintregister(list,OS_32);
  1889. cg.a_load_const_reg(list,OS_32,hi(value),tmpreg);
  1890. list.concat(taicpu.op_reg_reg_reg(A_SBC,regdst.reghi,regsrc.reghi,tmpreg));
  1891. end;
  1892. end;
  1893. else
  1894. internalerror(2003083101);
  1895. end;
  1896. end;
  1897. end;
  1898. procedure tcg64farm.a_op64_reg_reg_reg_checkoverflow(list: TAsmList;op:TOpCG;size : tcgsize;regsrc1,regsrc2,regdst : tregister64;setflags : boolean;var ovloc : tlocation);
  1899. begin
  1900. ovloc.loc:=LOC_VOID;
  1901. case op of
  1902. OP_NEG,
  1903. OP_NOT :
  1904. internalerror(200306017);
  1905. end;
  1906. if (setflags or tcgarm(cg).cgsetflags) and (op in [OP_ADD,OP_SUB]) then
  1907. begin
  1908. case op of
  1909. OP_ADD:
  1910. begin
  1911. list.concat(setoppostfix(taicpu.op_reg_reg_reg(A_ADD,regdst.reglo,regsrc1.reglo,regsrc2.reglo),PF_S));
  1912. list.concat(setoppostfix(taicpu.op_reg_reg_reg(A_ADC,regdst.reghi,regsrc1.reghi,regsrc2.reghi),PF_S));
  1913. end;
  1914. OP_SUB:
  1915. begin
  1916. list.concat(setoppostfix(taicpu.op_reg_reg_reg(A_SUB,regdst.reglo,regsrc2.reglo,regsrc1.reglo),PF_S));
  1917. list.concat(setoppostfix(taicpu.op_reg_reg_reg(A_SBC,regdst.reghi,regsrc2.reghi,regsrc1.reghi),PF_S));
  1918. end;
  1919. else
  1920. internalerror(2003083101);
  1921. end;
  1922. if size=OS_64 then
  1923. begin
  1924. { the arm has an weired opinion how flags for SUB/ADD are handled }
  1925. ovloc.loc:=LOC_FLAGS;
  1926. case op of
  1927. OP_ADD:
  1928. ovloc.resflags:=F_CS;
  1929. OP_SUB:
  1930. ovloc.resflags:=F_CC;
  1931. end;
  1932. end;
  1933. end
  1934. else
  1935. begin
  1936. case op of
  1937. OP_AND,OP_OR,OP_XOR:
  1938. begin
  1939. cg.a_op_reg_reg_reg(list,op,OS_32,regsrc1.reglo,regsrc2.reglo,regdst.reglo);
  1940. cg.a_op_reg_reg_reg(list,op,OS_32,regsrc1.reghi,regsrc2.reghi,regdst.reghi);
  1941. end;
  1942. OP_ADD:
  1943. begin
  1944. list.concat(setoppostfix(taicpu.op_reg_reg_reg(A_ADD,regdst.reglo,regsrc1.reglo,regsrc2.reglo),PF_S));
  1945. list.concat(taicpu.op_reg_reg_reg(A_ADC,regdst.reghi,regsrc1.reghi,regsrc2.reghi));
  1946. end;
  1947. OP_SUB:
  1948. begin
  1949. list.concat(setoppostfix(taicpu.op_reg_reg_reg(A_SUB,regdst.reglo,regsrc2.reglo,regsrc1.reglo),PF_S));
  1950. list.concat(taicpu.op_reg_reg_reg(A_SBC,regdst.reghi,regsrc2.reghi,regsrc1.reghi));
  1951. end;
  1952. else
  1953. internalerror(2003083101);
  1954. end;
  1955. end;
  1956. end;
  1957. begin
  1958. cg:=tcgarm.create;
  1959. cg64:=tcg64farm.create;
  1960. end.