cgcpu.pas 75 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115
  1. {
  2. Copyright (c) 2008 by Florian Klaempfl
  3. Member of the Free Pascal development team
  4. This unit implements the code generator for the AVR
  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. { tcgavr }
  29. tcgavr = class(tcg)
  30. { true, if the next arithmetic operation should modify the flags }
  31. cgsetflags : boolean;
  32. procedure init_register_allocators;override;
  33. procedure done_register_allocators;override;
  34. function getintregister(list:TAsmList;size:Tcgsize):Tregister;override;
  35. function getaddressregister(list:TAsmList):TRegister;override;
  36. procedure a_load_const_cgpara(list : TAsmList;size : tcgsize;a : tcgint;const paraloc : TCGPara);override;
  37. procedure a_load_ref_cgpara(list : TAsmList;size : tcgsize;const r : treference;const paraloc : TCGPara);override;
  38. procedure a_loadaddr_ref_cgpara(list : TAsmList;const r : treference;const paraloc : TCGPara);override;
  39. procedure a_load_reg_cgpara(list : TAsmList; size : tcgsize;r : tregister; const cgpara : tcgpara);override;
  40. procedure a_call_name(list : TAsmList;const s : string; weak: boolean);override;
  41. procedure a_call_reg(list : TAsmList;reg: tregister);override;
  42. procedure a_op_const_reg(list : TAsmList; Op: TOpCG; size: TCGSize; a: tcgint; reg: TRegister); override;
  43. procedure a_op_reg_reg(list: TAsmList; Op: TOpCG; size: TCGSize; src, dst : TRegister); override;
  44. procedure a_op_reg_reg_reg(list: TAsmList; op: TOpCg; size: tcgsize; src1, src2, dst: tregister); override;
  45. procedure a_op_const_reg_reg(list : TAsmList;op : TOpCg;size : tcgsize; a : tcgint;src,dst : tregister); override;
  46. { move instructions }
  47. procedure a_load_const_reg(list : TAsmList; size: tcgsize; a : tcgint;reg : tregister);override;
  48. procedure a_load_reg_ref(list : TAsmList; fromsize, tosize: tcgsize; reg : tregister;const ref : treference);override;
  49. procedure a_load_ref_reg(list : TAsmList; fromsize, tosize : tcgsize;const Ref : treference;reg : tregister);override;
  50. procedure a_load_reg_reg(list : TAsmList; fromsize, tosize : tcgsize;reg1,reg2 : tregister);override;
  51. { fpu move instructions }
  52. procedure a_loadfpu_reg_reg(list: TAsmList; fromsize, tosize: tcgsize; reg1, reg2: tregister); override;
  53. procedure a_loadfpu_ref_reg(list: TAsmList; fromsize, tosize: tcgsize; const ref: treference; reg: tregister); override;
  54. procedure a_loadfpu_reg_ref(list: TAsmList; fromsize, tosize: tcgsize; reg: tregister; const ref: treference); override;
  55. { comparison operations }
  56. procedure a_cmp_const_reg_label(list : TAsmList;size : tcgsize;cmp_op : topcmp;a : tcgint;reg : tregister;
  57. l : tasmlabel);override;
  58. procedure a_cmp_reg_reg_label(list : TAsmList;size : tcgsize;cmp_op : topcmp;reg1,reg2 : tregister;l : tasmlabel); override;
  59. procedure a_jmp_name(list : TAsmList;const s : string); override;
  60. procedure a_jmp_always(list : TAsmList;l: tasmlabel); override;
  61. procedure a_jmp_flags(list : TAsmList;const f : TResFlags;l: tasmlabel); override;
  62. procedure g_flags2reg(list: TAsmList; size: TCgSize; const f: TResFlags; reg: TRegister); override;
  63. procedure g_proc_entry(list : TAsmList;localsize : longint;nostackframe:boolean);override;
  64. procedure g_proc_exit(list : TAsmList;parasize : longint;nostackframe:boolean); override;
  65. procedure a_loadaddr_ref_reg(list : TAsmList;const ref : treference;r : tregister);override;
  66. procedure g_concatcopy(list : TAsmList;const source,dest : treference;len : tcgint);override;
  67. procedure g_concatcopy_move(list : TAsmList;const source,dest : treference;len : tcgint);
  68. procedure g_overflowcheck(list: TAsmList; const l: tlocation; def: tdef); override;
  69. procedure g_save_registers(list : TAsmList);override;
  70. procedure g_restore_registers(list : TAsmList);override;
  71. procedure a_jmp_cond(list : TAsmList;cond : TOpCmp;l: tasmlabel);
  72. procedure fixref(list : TAsmList;var ref : treference);
  73. function normalize_ref(list : TAsmList;ref : treference;
  74. tmpreg : tregister) : treference;
  75. procedure emit_mov(list: TAsmList;reg2: tregister; reg1: tregister);
  76. procedure a_adjust_sp(list: TAsmList; value: longint);
  77. function GetLoad(const ref : treference) : tasmop;
  78. function GetStore(const ref: treference): tasmop;
  79. protected
  80. procedure a_op_reg_reg_internal(list: TAsmList; Op: TOpCG; size: TCGSize; src, srchi, dst, dsthi: TRegister);
  81. procedure a_op_const_reg_internal(list : TAsmList; Op: TOpCG; size: TCGSize; a: tcgint; reg, reghi: TRegister);
  82. procedure maybegetcpuregister(list : tasmlist; reg : tregister);
  83. end;
  84. tcg64favr = class(tcg64f32)
  85. procedure a_op64_reg_reg(list : TAsmList;op:TOpCG;size : tcgsize;regsrc,regdst : tregister64);override;
  86. procedure a_op64_const_reg(list : TAsmList;op:TOpCG;size : tcgsize;value : int64;reg : tregister64);override;
  87. end;
  88. procedure create_codegen;
  89. const
  90. TOpCG2AsmOp: Array[topcg] of TAsmOp = (A_NONE,A_MOV,A_ADD,A_AND,A_NONE,
  91. A_NONE,A_MULS,A_MUL,A_NEG,A_COM,A_OR,
  92. A_ASR,A_LSL,A_LSR,A_SUB,A_EOR,A_ROL,A_ROR);
  93. implementation
  94. uses
  95. globals,verbose,systems,cutils,
  96. fmodule,
  97. symconst,symsym,symtable,
  98. tgobj,rgobj,
  99. procinfo,cpupi,
  100. paramgr;
  101. procedure tcgavr.init_register_allocators;
  102. begin
  103. inherited init_register_allocators;
  104. rg[R_INTREGISTER]:=trgintcpu.create(R_INTREGISTER,R_SUBWHOLE,
  105. [RS_R18,RS_R19,RS_R20,RS_R21,RS_R22,RS_R23,RS_R24,RS_R25,
  106. RS_R2,RS_R3,RS_R4,RS_R5,RS_R6,RS_R7,RS_R8,RS_R9,
  107. RS_R10,RS_R11,RS_R12,RS_R13,RS_R14,RS_R15,RS_R16,RS_R17],first_int_imreg,[]);
  108. end;
  109. procedure tcgavr.done_register_allocators;
  110. begin
  111. rg[R_INTREGISTER].free;
  112. // rg[R_ADDRESSREGISTER].free;
  113. inherited done_register_allocators;
  114. end;
  115. function tcgavr.getintregister(list: TAsmList; size: Tcgsize): Tregister;
  116. var
  117. tmp1,tmp2,tmp3 : TRegister;
  118. begin
  119. case size of
  120. OS_8,OS_S8:
  121. Result:=inherited getintregister(list, size);
  122. OS_16,OS_S16:
  123. begin
  124. Result:=inherited getintregister(list, OS_8);
  125. { ensure that the high register can be retrieved by
  126. GetNextReg
  127. }
  128. if inherited getintregister(list, OS_8)<>GetNextReg(Result) then
  129. internalerror(2011021331);
  130. end;
  131. OS_32,OS_S32:
  132. begin
  133. Result:=inherited getintregister(list, OS_8);
  134. tmp1:=inherited getintregister(list, OS_8);
  135. { ensure that the high register can be retrieved by
  136. GetNextReg
  137. }
  138. if tmp1<>GetNextReg(Result) then
  139. internalerror(2011021332);
  140. tmp2:=inherited getintregister(list, OS_8);
  141. { ensure that the upper register can be retrieved by
  142. GetNextReg
  143. }
  144. if tmp2<>GetNextReg(tmp1) then
  145. internalerror(2011021333);
  146. tmp3:=inherited getintregister(list, OS_8);
  147. { ensure that the upper register can be retrieved by
  148. GetNextReg
  149. }
  150. if tmp3<>GetNextReg(tmp2) then
  151. internalerror(2011021334);
  152. end;
  153. else
  154. internalerror(2011021330);
  155. end;
  156. end;
  157. function tcgavr.getaddressregister(list: TAsmList): TRegister;
  158. begin
  159. Result:=getintregister(list,OS_ADDR);
  160. end;
  161. procedure tcgavr.a_load_reg_cgpara(list : TAsmList;size : tcgsize;r : tregister;const cgpara : tcgpara);
  162. procedure load_para_loc(r : TRegister;paraloc : PCGParaLocation);
  163. var
  164. ref : treference;
  165. begin
  166. paramanager.allocparaloc(list,paraloc);
  167. case paraloc^.loc of
  168. LOC_REGISTER,LOC_CREGISTER:
  169. a_load_reg_reg(list,paraloc^.size,paraloc^.size,r,paraloc^.register);
  170. LOC_REFERENCE,LOC_CREFERENCE:
  171. begin
  172. reference_reset_base(ref,paraloc^.reference.index,paraloc^.reference.offset,2);
  173. a_load_reg_ref(list,paraloc^.size,paraloc^.size,r,ref);
  174. end;
  175. else
  176. internalerror(2002071004);
  177. end;
  178. end;
  179. var
  180. i, i2 : longint;
  181. hp : PCGParaLocation;
  182. begin
  183. { if use_push(cgpara) then
  184. begin
  185. if tcgsize2size[cgpara.Size] > 2 then
  186. begin
  187. if tcgsize2size[cgpara.Size] <> 4 then
  188. internalerror(2013031101);
  189. if cgpara.location^.Next = nil then
  190. begin
  191. if tcgsize2size[cgpara.location^.size] <> 4 then
  192. internalerror(2013031101);
  193. end
  194. else
  195. begin
  196. if tcgsize2size[cgpara.location^.size] <> 2 then
  197. internalerror(2013031101);
  198. if tcgsize2size[cgpara.location^.Next^.size] <> 2 then
  199. internalerror(2013031101);
  200. if cgpara.location^.Next^.Next <> nil then
  201. internalerror(2013031101);
  202. end;
  203. if tcgsize2size[cgpara.size]>cgpara.alignment then
  204. pushsize:=cgpara.size
  205. else
  206. pushsize:=int_cgsize(cgpara.alignment);
  207. pushsize2 := int_cgsize(tcgsize2size[pushsize] - 2);
  208. list.concat(taicpu.op_reg(A_PUSH,TCgsize2opsize[pushsize2],makeregsize(list,GetNextReg(r),pushsize2)));
  209. list.concat(taicpu.op_reg(A_PUSH,S_W,makeregsize(list,r,OS_16)));
  210. end
  211. else
  212. begin
  213. cgpara.check_simple_location;
  214. if tcgsize2size[cgpara.location^.size]>cgpara.alignment then
  215. pushsize:=cgpara.location^.size
  216. else
  217. pushsize:=int_cgsize(cgpara.alignment);
  218. list.concat(taicpu.op_reg(A_PUSH,TCgsize2opsize[pushsize],makeregsize(list,r,pushsize)));
  219. end;
  220. end
  221. else }
  222. begin
  223. if not(tcgsize2size[cgpara.Size] in [1..4]) then
  224. internalerror(2014011101);
  225. hp:=cgpara.location;
  226. i:=0;
  227. while i<tcgsize2size[cgpara.Size] do
  228. begin
  229. if not(assigned(hp)) then
  230. internalerror(2014011102);
  231. inc(i, tcgsize2size[hp^.Size]);
  232. if hp^.Loc=LOC_REGISTER then
  233. begin
  234. load_para_loc(r,hp);
  235. hp:=hp^.Next;
  236. r:=GetNextReg(r);
  237. end
  238. else
  239. begin
  240. load_para_loc(r,hp);
  241. for i2:=1 to tcgsize2size[hp^.Size] do
  242. r:=GetNextReg(r);
  243. hp:=hp^.Next;
  244. end;
  245. end;
  246. if assigned(hp) then
  247. internalerror(2014011103);
  248. end;
  249. end;
  250. procedure tcgavr.a_load_const_cgpara(list : TAsmList;size : tcgsize;a : tcgint;const paraloc : TCGPara);
  251. var
  252. i : longint;
  253. hp : PCGParaLocation;
  254. begin
  255. if not(tcgsize2size[paraloc.Size] in [1..4]) then
  256. internalerror(2014011101);
  257. hp:=paraloc.location;
  258. for i:=1 to tcgsize2size[paraloc.Size] do
  259. begin
  260. if not(assigned(hp)) then
  261. internalerror(2014011105);
  262. case hp^.loc of
  263. LOC_REGISTER,LOC_CREGISTER:
  264. begin
  265. if (tcgsize2size[hp^.size]<>1) or
  266. (hp^.shiftval<>0) then
  267. internalerror(2015041101);
  268. a_load_const_reg(list,hp^.size,(a shr (8*(i-1))) and $ff,hp^.register);
  269. hp:=hp^.Next;
  270. end;
  271. LOC_REFERENCE,LOC_CREFERENCE:
  272. list.concat(taicpu.op_const(A_PUSH,(a shr (8*(i-1))) and $ff));
  273. else
  274. internalerror(2002071004);
  275. end;
  276. end;
  277. end;
  278. procedure tcgavr.a_load_ref_cgpara(list : TAsmList;size : tcgsize;const r : treference;const paraloc : TCGPara);
  279. var
  280. tmpref, ref: treference;
  281. location: pcgparalocation;
  282. sizeleft: tcgint;
  283. begin
  284. location := paraloc.location;
  285. tmpref := r;
  286. sizeleft := paraloc.intsize;
  287. while assigned(location) do
  288. begin
  289. paramanager.allocparaloc(list,location);
  290. case location^.loc of
  291. LOC_REGISTER,LOC_CREGISTER:
  292. a_load_ref_reg(list,location^.size,location^.size,tmpref,location^.register);
  293. LOC_REFERENCE:
  294. begin
  295. reference_reset_base(ref,location^.reference.index,location^.reference.offset,paraloc.alignment);
  296. { doubles in softemu mode have a strange order of registers and references }
  297. if location^.size=OS_32 then
  298. g_concatcopy(list,tmpref,ref,4)
  299. else
  300. begin
  301. g_concatcopy(list,tmpref,ref,sizeleft);
  302. if assigned(location^.next) then
  303. internalerror(2005010710);
  304. end;
  305. end;
  306. LOC_VOID:
  307. begin
  308. // nothing to do
  309. end;
  310. else
  311. internalerror(2002081103);
  312. end;
  313. inc(tmpref.offset,tcgsize2size[location^.size]);
  314. dec(sizeleft,tcgsize2size[location^.size]);
  315. location := location^.next;
  316. end;
  317. end;
  318. procedure tcgavr.a_loadaddr_ref_cgpara(list : TAsmList;const r : treference;const paraloc : TCGPara);
  319. var
  320. tmpreg: tregister;
  321. begin
  322. tmpreg:=getaddressregister(list);
  323. a_loadaddr_ref_reg(list,r,tmpreg);
  324. a_load_reg_cgpara(list,OS_ADDR,tmpreg,paraloc);
  325. end;
  326. procedure tcgavr.a_call_name(list : TAsmList;const s : string; weak: boolean);
  327. begin
  328. if CPUAVR_HAS_JMP_CALL in cpu_capabilities[current_settings.cputype] then
  329. list.concat(taicpu.op_sym(A_CALL,current_asmdata.RefAsmSymbol(s)))
  330. else
  331. list.concat(taicpu.op_sym(A_RCALL,current_asmdata.RefAsmSymbol(s)));
  332. include(current_procinfo.flags,pi_do_call);
  333. end;
  334. procedure tcgavr.a_call_reg(list : TAsmList;reg: tregister);
  335. begin
  336. a_reg_alloc(list,NR_ZLO);
  337. a_reg_alloc(list,NR_ZHI);
  338. list.concat(taicpu.op_reg_reg(A_MOV,NR_ZLO,reg));
  339. list.concat(taicpu.op_reg_reg(A_MOV,NR_ZHI,GetHigh(reg)));
  340. list.concat(taicpu.op_none(A_ICALL));
  341. a_reg_dealloc(list,NR_ZLO);
  342. a_reg_dealloc(list,NR_ZHI);
  343. include(current_procinfo.flags,pi_do_call);
  344. end;
  345. procedure tcgavr.a_op_const_reg(list : TAsmList; Op: TOpCG; size: TCGSize; a: tcgint; reg: TRegister);
  346. begin
  347. if not(size in [OS_S8,OS_8,OS_S16,OS_16,OS_S32,OS_32]) then
  348. internalerror(2012102403);
  349. a_op_const_reg_internal(list,Op,size,a,reg,NR_NO);
  350. end;
  351. procedure tcgavr.a_op_reg_reg(list: TAsmList; Op: TOpCG; size: TCGSize; src, dst : TRegister);
  352. begin
  353. if not(size in [OS_S8,OS_8,OS_S16,OS_16,OS_S32,OS_32]) then
  354. internalerror(2012102401);
  355. a_op_reg_reg_internal(list,Op,size,src,NR_NO,dst,NR_NO);
  356. end;
  357. procedure tcgavr.a_op_reg_reg_reg(list: TAsmList; op: TOpCg; size: tcgsize; src1, src2, dst: tregister);
  358. begin
  359. if (op in [OP_MUL,OP_IMUL]) and (size in [OS_16,OS_S16]) then
  360. begin
  361. getcpuregister(list,NR_R0);
  362. getcpuregister(list,NR_R1);
  363. list.concat(taicpu.op_reg_reg(A_MUL,src1,src2));
  364. emit_mov(list,dst,NR_R0);
  365. emit_mov(list,GetNextReg(dst),NR_R1);
  366. list.concat(taicpu.op_reg_reg(A_MUL,GetNextReg(src1),src2));
  367. list.concat(taicpu.op_reg_reg(A_ADD,GetNextReg(dst),NR_R0));
  368. list.concat(taicpu.op_reg_reg(A_MUL,src1,GetNextReg(src2)));
  369. list.concat(taicpu.op_reg_reg(A_ADD,GetNextReg(dst),NR_R0));
  370. ungetcpuregister(list,NR_R0);
  371. list.concat(taicpu.op_reg(A_CLR,NR_R1));
  372. ungetcpuregister(list,NR_R1);
  373. end
  374. else
  375. inherited a_op_reg_reg_reg(list,op,size,src1,src2,dst);
  376. end;
  377. procedure tcgavr.a_op_const_reg_reg(list: TAsmList; op: TOpCg; size: tcgsize; a: tcgint; src, dst: tregister);
  378. begin
  379. if (op in [OP_MUL,OP_IMUL]) and (size in [OS_16,OS_S16]) and (a in [2,4,8]) then
  380. begin
  381. emit_mov(list,dst,src);
  382. emit_mov(list,GetNextReg(dst),GetNextReg(src));
  383. a:=a shr 1;
  384. while a>0 do
  385. begin
  386. list.concat(taicpu.op_reg(A_LSL,dst));
  387. list.concat(taicpu.op_reg(A_ROL,GetNextReg(dst)));
  388. a:=a shr 1;
  389. end;
  390. end
  391. else
  392. inherited a_op_const_reg_reg(list,op,size,a,src,dst);
  393. end;
  394. procedure tcgavr.a_op_reg_reg_internal(list : TAsmList; Op: TOpCG; size: TCGSize; src, srchi, dst, dsthi: TRegister);
  395. var
  396. countreg,
  397. tmpreg: tregister;
  398. i : integer;
  399. instr : taicpu;
  400. paraloc1,paraloc2,paraloc3 : TCGPara;
  401. l1,l2 : tasmlabel;
  402. pd : tprocdef;
  403. procedure NextSrcDst;
  404. begin
  405. if i=5 then
  406. begin
  407. dst:=dsthi;
  408. src:=srchi;
  409. end
  410. else
  411. begin
  412. dst:=GetNextReg(dst);
  413. src:=GetNextReg(src);
  414. end;
  415. end;
  416. { iterates TmpReg through all registers of dst }
  417. procedure NextTmp;
  418. begin
  419. if i=5 then
  420. tmpreg:=dsthi
  421. else
  422. tmpreg:=GetNextReg(tmpreg);
  423. end;
  424. begin
  425. case op of
  426. OP_ADD:
  427. begin
  428. list.concat(taicpu.op_reg_reg(A_ADD,dst,src));
  429. if size in [OS_S16,OS_16,OS_S32,OS_32,OS_S64,OS_64] then
  430. begin
  431. for i:=2 to tcgsize2size[size] do
  432. begin
  433. NextSrcDst;
  434. list.concat(taicpu.op_reg_reg(A_ADC,dst,src));
  435. end;
  436. end;
  437. end;
  438. OP_SUB:
  439. begin
  440. list.concat(taicpu.op_reg_reg(A_SUB,dst,src));
  441. if size in [OS_S16,OS_16,OS_S32,OS_32,OS_S64,OS_64] then
  442. begin
  443. for i:=2 to tcgsize2size[size] do
  444. begin
  445. NextSrcDst;
  446. list.concat(taicpu.op_reg_reg(A_SBC,dst,src));
  447. end;
  448. end;
  449. end;
  450. OP_NEG:
  451. begin
  452. if src<>dst then
  453. begin
  454. if size in [OS_S64,OS_64] then
  455. begin
  456. a_load_reg_reg(list,OS_32,OS_32,src,dst);
  457. a_load_reg_reg(list,OS_32,OS_32,srchi,dsthi);
  458. end
  459. else
  460. a_load_reg_reg(list,size,size,src,dst);
  461. end;
  462. if size in [OS_S16,OS_16,OS_S32,OS_32,OS_S64,OS_64] then
  463. begin
  464. tmpreg:=GetNextReg(dst);
  465. for i:=2 to tcgsize2size[size] do
  466. begin
  467. list.concat(taicpu.op_reg(A_COM,tmpreg));
  468. NextTmp;
  469. end;
  470. list.concat(taicpu.op_reg(A_NEG,dst));
  471. tmpreg:=GetNextReg(dst);
  472. for i:=2 to tcgsize2size[size] do
  473. begin
  474. list.concat(taicpu.op_reg_const(A_SBCI,tmpreg,-1));
  475. NextTmp;
  476. end;
  477. end;
  478. end;
  479. OP_NOT:
  480. begin
  481. for i:=1 to tcgsize2size[size] do
  482. begin
  483. if src<>dst then
  484. a_load_reg_reg(list,OS_8,OS_8,src,dst);
  485. list.concat(taicpu.op_reg(A_COM,dst));
  486. NextSrcDst;
  487. end;
  488. end;
  489. OP_MUL,OP_IMUL:
  490. begin
  491. if size in [OS_8,OS_S8] then
  492. begin
  493. cg.a_reg_alloc(list,NR_R0);
  494. cg.a_reg_alloc(list,NR_R1);
  495. list.concat(taicpu.op_reg_reg(topcg2asmop[op],dst,src));
  496. list.concat(taicpu.op_reg(A_CLR,NR_R1));
  497. cg.a_reg_dealloc(list,NR_R1);
  498. list.concat(taicpu.op_reg_reg(A_MOV,dst,NR_R0));
  499. cg.a_reg_dealloc(list,NR_R0);
  500. end
  501. else if size=OS_16 then
  502. begin
  503. tmpreg:=getintregister(list,OS_16);
  504. emit_mov(list,tmpreg,dst);
  505. emit_mov(list,GetNextReg(tmpreg),GetNextReg(dst));
  506. list.concat(taicpu.op_reg_reg(A_MUL,tmpreg,src));
  507. emit_mov(list,dst,NR_R0);
  508. emit_mov(list,GetNextReg(dst),NR_R1);
  509. list.concat(taicpu.op_reg_reg(A_MUL,GetNextReg(tmpreg),src));
  510. list.concat(taicpu.op_reg_reg(A_ADD,GetNextReg(dst),NR_R0));
  511. list.concat(taicpu.op_reg_reg(A_MUL,tmpreg,GetNextReg(src)));
  512. list.concat(taicpu.op_reg_reg(A_ADD,GetNextReg(dst),NR_R0));
  513. list.concat(taicpu.op_reg(A_CLR,NR_R1));
  514. { keep code for muls with overflow checking
  515. pd:=search_system_proc('fpc_mul_word');
  516. paraloc1.init;
  517. paraloc2.init;
  518. paraloc3.init;
  519. paramanager.getintparaloc(list,pd,1,paraloc1);
  520. paramanager.getintparaloc(list,pd,2,paraloc2);
  521. paramanager.getintparaloc(list,pd,3,paraloc3);
  522. a_load_const_cgpara(list,OS_8,0,paraloc3);
  523. a_load_reg_cgpara(list,OS_16,src,paraloc2);
  524. a_load_reg_cgpara(list,OS_16,dst,paraloc1);
  525. paramanager.freecgpara(list,paraloc3);
  526. paramanager.freecgpara(list,paraloc2);
  527. paramanager.freecgpara(list,paraloc1);
  528. alloccpuregisters(list,R_INTREGISTER,paramanager.get_volatile_registers_int(pocall_default));
  529. a_call_name(list,'FPC_MUL_WORD',false);
  530. dealloccpuregisters(list,R_INTREGISTER,paramanager.get_volatile_registers_int(pocall_default));
  531. cg.a_reg_alloc(list,NR_R24);
  532. cg.a_reg_alloc(list,NR_R25);
  533. cg.a_load_reg_reg(list,OS_8,OS_8,NR_R24,dst);
  534. cg.a_reg_dealloc(list,NR_R24);
  535. cg.a_load_reg_reg(list,OS_8,OS_8,NR_R25,GetNextReg(dst));
  536. cg.a_reg_dealloc(list,NR_R25);
  537. paraloc3.done;
  538. paraloc2.done;
  539. paraloc1.done;
  540. }
  541. end
  542. else
  543. internalerror(2011022002);
  544. end;
  545. OP_DIV,OP_IDIV:
  546. { special stuff, needs separate handling inside code }
  547. { generator }
  548. internalerror(2011022001);
  549. OP_SHR,OP_SHL,OP_SAR,OP_ROL,OP_ROR:
  550. begin
  551. current_asmdata.getjumplabel(l1);
  552. current_asmdata.getjumplabel(l2);
  553. countreg:=getintregister(list,OS_8);
  554. a_load_reg_reg(list,size,OS_8,src,countreg);
  555. list.concat(taicpu.op_reg(A_TST,countreg));
  556. a_jmp_flags(list,F_EQ,l2);
  557. cg.a_label(list,l1);
  558. case op of
  559. OP_SHR:
  560. list.concat(taicpu.op_reg(A_LSR,GetOffsetReg64(dst,dsthi,tcgsize2size[size]-1)));
  561. OP_SHL:
  562. list.concat(taicpu.op_reg(A_LSL,dst));
  563. OP_SAR:
  564. list.concat(taicpu.op_reg(A_ASR,GetOffsetReg64(dst,dsthi,tcgsize2size[size]-1)));
  565. OP_ROR:
  566. begin
  567. { load carry? }
  568. if not(size in [OS_8,OS_S8]) then
  569. begin
  570. list.concat(taicpu.op_none(A_CLC));
  571. list.concat(taicpu.op_reg_const(A_SBRC,src,0));
  572. list.concat(taicpu.op_none(A_SEC));
  573. end;
  574. list.concat(taicpu.op_reg(A_ROR,GetOffsetReg64(dst,dsthi,tcgsize2size[size]-1)));
  575. end;
  576. OP_ROL:
  577. begin
  578. { load carry? }
  579. if not(size in [OS_8,OS_S8]) then
  580. begin
  581. list.concat(taicpu.op_none(A_CLC));
  582. list.concat(taicpu.op_reg_const(A_SBRC,GetOffsetReg64(dst,dsthi,tcgsize2size[size]-1),7));
  583. list.concat(taicpu.op_none(A_SEC));
  584. end;
  585. list.concat(taicpu.op_reg(A_ROL,dst))
  586. end;
  587. else
  588. internalerror(2011030901);
  589. end;
  590. if size in [OS_S16,OS_16,OS_S32,OS_32,OS_S64,OS_64] then
  591. begin
  592. for i:=2 to tcgsize2size[size] do
  593. begin
  594. case op of
  595. OP_ROR,
  596. OP_SHR:
  597. list.concat(taicpu.op_reg(A_ROR,GetOffsetReg64(dst,dsthi,tcgsize2size[size]-i)));
  598. OP_ROL,
  599. OP_SHL:
  600. list.concat(taicpu.op_reg(A_ROL,GetOffsetReg64(dst,dsthi,i-1)));
  601. OP_SAR:
  602. list.concat(taicpu.op_reg(A_ROR,GetOffsetReg64(dst,dsthi,tcgsize2size[size]-i)));
  603. else
  604. internalerror(2011030902);
  605. end;
  606. end;
  607. end;
  608. list.concat(taicpu.op_reg(A_DEC,countreg));
  609. a_jmp_flags(list,F_NE,l1);
  610. // keep registers alive
  611. list.concat(taicpu.op_reg_reg(A_MOV,countreg,countreg));
  612. cg.a_label(list,l2);
  613. end;
  614. OP_AND,OP_OR,OP_XOR:
  615. begin
  616. for i:=1 to tcgsize2size[size] do
  617. begin
  618. list.concat(taicpu.op_reg_reg(topcg2asmop[op],dst,src));
  619. NextSrcDst;
  620. end;
  621. end;
  622. else
  623. internalerror(2011022004);
  624. end;
  625. end;
  626. procedure tcgavr.a_op_const_reg_internal(list: TAsmList; Op: TOpCG;
  627. size: TCGSize; a: tcgint; reg, reghi: TRegister);
  628. var
  629. mask : qword;
  630. shift : byte;
  631. i : byte;
  632. tmpreg : tregister;
  633. tmpreg64 : tregister64;
  634. procedure NextReg;
  635. begin
  636. if i=5 then
  637. reg:=reghi
  638. else
  639. reg:=GetNextReg(reg);
  640. end;
  641. var
  642. curvalue : byte;
  643. begin
  644. optimize_op_const(size,op,a);
  645. mask:=$ff;
  646. shift:=0;
  647. case op of
  648. OP_NONE:
  649. begin
  650. { Opcode is optimized away }
  651. end;
  652. OP_MOVE:
  653. begin
  654. { Optimized, replaced with a simple load }
  655. a_load_const_reg(list,size,a,reg);
  656. end;
  657. OP_OR:
  658. begin
  659. for i:=1 to tcgsize2size[size] do
  660. begin
  661. list.concat(taicpu.op_reg_const(A_ORI,reg,(qword(a) and mask) shr shift));
  662. NextReg;
  663. mask:=mask shl 8;
  664. inc(shift,8);
  665. end;
  666. end;
  667. OP_AND:
  668. begin
  669. for i:=1 to tcgsize2size[size] do
  670. begin
  671. list.concat(taicpu.op_reg_const(A_ANDI,reg,(qword(a) and mask) shr shift));
  672. NextReg;
  673. mask:=mask shl 8;
  674. inc(shift,8);
  675. end;
  676. end;
  677. OP_SUB:
  678. begin
  679. list.concat(taicpu.op_reg_const(A_SUBI,reg,a and mask));
  680. if size in [OS_S16,OS_16,OS_S32,OS_32,OS_S64,OS_64] then
  681. begin
  682. for i:=2 to tcgsize2size[size] do
  683. begin
  684. NextReg;
  685. mask:=mask shl 8;
  686. inc(shift,8);
  687. curvalue:=(qword(a) and mask) shr shift;
  688. { decrease pressure on upper half of registers by using SBC ...,R1 instead
  689. of SBCI ...,0 }
  690. if curvalue=0 then
  691. list.concat(taicpu.op_reg_reg(A_SBC,reg,NR_R1))
  692. else
  693. list.concat(taicpu.op_reg_const(A_SBCI,reg,curvalue));
  694. end;
  695. end;
  696. end;
  697. OP_ADD:
  698. begin
  699. curvalue:=a and mask;
  700. if curvalue=0 then
  701. list.concat(taicpu.op_reg_reg(A_ADD,reg,NR_R1))
  702. else
  703. begin
  704. tmpreg:=getintregister(list,OS_8);
  705. a_load_const_reg(list,OS_8,curvalue,tmpreg);
  706. list.concat(taicpu.op_reg_reg(A_ADD,reg,tmpreg));
  707. end;
  708. if size in [OS_S16,OS_16,OS_S32,OS_32,OS_S64,OS_64] then
  709. begin
  710. for i:=2 to tcgsize2size[size] do
  711. begin
  712. NextReg;
  713. mask:=mask shl 8;
  714. inc(shift,8);
  715. curvalue:=(qword(a) and mask) shr shift;
  716. { decrease pressure on upper half of registers by using ADC ...,R1 instead
  717. of ADD ...,0 }
  718. if curvalue=0 then
  719. list.concat(taicpu.op_reg_reg(A_ADC,reg,NR_R1))
  720. else
  721. begin
  722. tmpreg:=getintregister(list,OS_8);
  723. a_load_const_reg(list,OS_8,curvalue,tmpreg);
  724. list.concat(taicpu.op_reg_reg(A_ADC,reg,tmpreg));
  725. end;
  726. end;
  727. end;
  728. end;
  729. else
  730. begin
  731. if size in [OS_64,OS_S64] then
  732. begin
  733. tmpreg64.reglo:=getintregister(list,OS_32);
  734. tmpreg64.reghi:=getintregister(list,OS_32);
  735. cg64.a_load64_const_reg(list,a,tmpreg64);
  736. cg64.a_op64_reg_reg(list,op,size,tmpreg64,joinreg64(reg,reghi));
  737. end
  738. else
  739. begin
  740. {$if 0}
  741. { code not working yet }
  742. if (op=OP_SAR) and (a=31) and (size in [OS_32,OS_S32]) then
  743. begin
  744. tmpreg:=reg;
  745. for i:=1 to 4 do
  746. begin
  747. list.concat(taicpu.op_reg_reg(A_MOV,tmpreg,NR_R1));
  748. tmpreg:=GetNextReg(tmpreg);
  749. end;
  750. end
  751. else
  752. {$endif}
  753. begin
  754. tmpreg:=getintregister(list,size);
  755. a_load_const_reg(list,size,a,tmpreg);
  756. a_op_reg_reg(list,op,size,tmpreg,reg);
  757. end;
  758. end;
  759. end;
  760. end;
  761. end;
  762. procedure tcgavr.a_load_const_reg(list : TAsmList; size: tcgsize; a : tcgint;reg : tregister);
  763. var
  764. mask : qword;
  765. shift : byte;
  766. i : byte;
  767. begin
  768. mask:=$ff;
  769. shift:=0;
  770. for i:=1 to tcgsize2size[size] do
  771. begin
  772. if ((qword(a) and mask) shr shift)=0 then
  773. emit_mov(list,reg,NR_R1)
  774. else
  775. list.concat(taicpu.op_reg_const(A_LDI,reg,(qword(a) and mask) shr shift));
  776. mask:=mask shl 8;
  777. inc(shift,8);
  778. reg:=GetNextReg(reg);
  779. end;
  780. end;
  781. procedure tcgavr.maybegetcpuregister(list:tasmlist;reg : tregister);
  782. begin
  783. { allocate the register only, if a cpu register is passed }
  784. if getsupreg(reg)<first_int_imreg then
  785. getcpuregister(list,reg);
  786. end;
  787. function tcgavr.normalize_ref(list:TAsmList;ref: treference;tmpreg : tregister) : treference;
  788. var
  789. tmpref : treference;
  790. l : tasmlabel;
  791. begin
  792. Result:=ref;
  793. if ref.addressmode<>AM_UNCHANGED then
  794. internalerror(2011021701);
  795. { Be sure to have a base register }
  796. if (ref.base=NR_NO) then
  797. begin
  798. { only symbol+offset? }
  799. if ref.index=NR_NO then
  800. exit;
  801. ref.base:=ref.index;
  802. ref.index:=NR_NO;
  803. end;
  804. { can we take advantage of adiw/sbiw? }
  805. if (current_settings.cputype>=cpu_avr2) and not(assigned(ref.symbol)) and (ref.offset<>0) and (ref.offset>=-63) and (ref.offset<=63) and
  806. ((tmpreg=NR_R24) or (tmpreg=NR_R26) or (tmpreg=NR_R28) or (tmpreg=NR_R30)) and (ref.base<>NR_NO) then
  807. begin
  808. maybegetcpuregister(list,tmpreg);
  809. emit_mov(list,tmpreg,ref.base);
  810. maybegetcpuregister(list,GetNextReg(tmpreg));
  811. emit_mov(list,GetNextReg(tmpreg),GetNextReg(ref.base));
  812. if ref.index<>NR_NO then
  813. begin
  814. list.concat(taicpu.op_reg_reg(A_ADD,tmpreg,ref.index));
  815. list.concat(taicpu.op_reg_reg(A_ADC,GetNextReg(tmpreg),GetNextReg(ref.index)));
  816. end;
  817. if ref.offset>0 then
  818. list.concat(taicpu.op_reg_const(A_ADIW,tmpreg,ref.offset))
  819. else
  820. list.concat(taicpu.op_reg_const(A_SBIW,tmpreg,-ref.offset));
  821. ref.offset:=0;
  822. ref.base:=tmpreg;
  823. ref.index:=NR_NO;
  824. end
  825. else if assigned(ref.symbol) or (ref.offset<>0) then
  826. begin
  827. reference_reset(tmpref,0);
  828. tmpref.symbol:=ref.symbol;
  829. tmpref.offset:=ref.offset;
  830. if assigned(ref.symbol) and (ref.symbol.typ in [AT_FUNCTION,AT_LABEL]) then
  831. tmpref.refaddr:=addr_lo8_gs
  832. else
  833. tmpref.refaddr:=addr_lo8;
  834. maybegetcpuregister(list,tmpreg);
  835. list.concat(taicpu.op_reg_ref(A_LDI,tmpreg,tmpref));
  836. if assigned(ref.symbol) and (ref.symbol.typ in [AT_FUNCTION,AT_LABEL]) then
  837. tmpref.refaddr:=addr_hi8_gs
  838. else
  839. tmpref.refaddr:=addr_hi8;
  840. maybegetcpuregister(list,GetNextReg(tmpreg));
  841. list.concat(taicpu.op_reg_ref(A_LDI,GetNextReg(tmpreg),tmpref));
  842. if (ref.base<>NR_NO) then
  843. begin
  844. list.concat(taicpu.op_reg_reg(A_ADD,tmpreg,ref.base));
  845. list.concat(taicpu.op_reg_reg(A_ADC,GetNextReg(tmpreg),GetNextReg(ref.base)));
  846. end;
  847. if (ref.index<>NR_NO) then
  848. begin
  849. list.concat(taicpu.op_reg_reg(A_ADD,tmpreg,ref.index));
  850. list.concat(taicpu.op_reg_reg(A_ADC,GetNextReg(tmpreg),GetNextReg(ref.index)));
  851. end;
  852. ref.symbol:=nil;
  853. ref.offset:=0;
  854. ref.base:=tmpreg;
  855. ref.index:=NR_NO;
  856. end
  857. else if (ref.base<>NR_NO) and (ref.index<>NR_NO) then
  858. begin
  859. maybegetcpuregister(list,tmpreg);
  860. emit_mov(list,tmpreg,ref.base);
  861. maybegetcpuregister(list,GetNextReg(tmpreg));
  862. emit_mov(list,GetNextReg(tmpreg),GetNextReg(ref.base));
  863. list.concat(taicpu.op_reg_reg(A_ADD,tmpreg,ref.index));
  864. list.concat(taicpu.op_reg_reg(A_ADC,GetNextReg(tmpreg),GetNextReg(ref.index)));
  865. ref.base:=tmpreg;
  866. ref.index:=NR_NO;
  867. end
  868. else if (ref.base<>NR_NO) then
  869. begin
  870. maybegetcpuregister(list,tmpreg);
  871. emit_mov(list,tmpreg,ref.base);
  872. maybegetcpuregister(list,GetNextReg(tmpreg));
  873. emit_mov(list,GetNextReg(tmpreg),GetNextReg(ref.base));
  874. ref.base:=tmpreg;
  875. ref.index:=NR_NO;
  876. end
  877. else if (ref.index<>NR_NO) then
  878. begin
  879. maybegetcpuregister(list,tmpreg);
  880. emit_mov(list,tmpreg,ref.index);
  881. maybegetcpuregister(list,GetNextReg(tmpreg));
  882. emit_mov(list,GetNextReg(tmpreg),GetNextReg(ref.index));
  883. ref.base:=tmpreg;
  884. ref.index:=NR_NO;
  885. end;
  886. Result:=ref;
  887. end;
  888. procedure tcgavr.a_load_reg_ref(list : TAsmList; fromsize, tosize: tcgsize; reg : tregister;const ref : treference);
  889. var
  890. href : treference;
  891. conv_done: boolean;
  892. tmpreg : tregister;
  893. i : integer;
  894. QuickRef : Boolean;
  895. begin
  896. QuickRef:=false;
  897. href:=Ref;
  898. { ensure, href.base contains a valid register if there is any register used }
  899. if href.base=NR_NO then
  900. begin
  901. href.base:=href.index;
  902. href.index:=NR_NO;
  903. end;
  904. { try to use std/sts }
  905. if not((href.Base=NR_NO) and (href.Index=NR_NO)) then
  906. begin
  907. if not((href.addressmode=AM_UNCHANGED) and
  908. (href.symbol=nil) and
  909. (href.Index=NR_NO) and
  910. (href.Offset in [0..64-tcgsize2size[fromsize]])) then
  911. href:=normalize_ref(list,href,NR_R30)
  912. else
  913. begin
  914. if (href.base<>NR_R28) and (href.base<>NR_R30) then
  915. begin
  916. maybegetcpuregister(list,NR_R30);
  917. emit_mov(list,NR_R30,href.base);
  918. maybegetcpuregister(list,NR_R31);
  919. emit_mov(list,NR_R31,GetNextReg(href.base));
  920. href.base:=NR_R30;
  921. end;
  922. QuickRef:=true;
  923. end;
  924. end
  925. else
  926. QuickRef:=true;
  927. if (tcgsize2size[fromsize]>32) or (tcgsize2size[tosize]>32) or (fromsize=OS_NO) or (tosize=OS_NO) then
  928. internalerror(2011021307);
  929. conv_done:=false;
  930. if tosize<>fromsize then
  931. begin
  932. conv_done:=true;
  933. if tcgsize2size[tosize]<=tcgsize2size[fromsize] then
  934. fromsize:=tosize;
  935. case fromsize of
  936. OS_8:
  937. begin
  938. if not(QuickRef) and (tcgsize2size[tosize]>1) then
  939. href.addressmode:=AM_POSTINCREMENT;
  940. list.concat(taicpu.op_ref_reg(GetStore(href),href,reg));
  941. for i:=2 to tcgsize2size[tosize] do
  942. begin
  943. if QuickRef then
  944. inc(href.offset);
  945. if not(QuickRef) and (i<tcgsize2size[fromsize]) then
  946. href.addressmode:=AM_POSTINCREMENT
  947. else
  948. href.addressmode:=AM_UNCHANGED;
  949. list.concat(taicpu.op_ref_reg(GetStore(href),href,NR_R1));
  950. end;
  951. end;
  952. OS_S8:
  953. begin
  954. if not(QuickRef) and (tcgsize2size[tosize]>1) then
  955. href.addressmode:=AM_POSTINCREMENT;
  956. list.concat(taicpu.op_ref_reg(GetStore(href),href,reg));
  957. if tcgsize2size[tosize]>1 then
  958. begin
  959. tmpreg:=getintregister(list,OS_8);
  960. emit_mov(list,tmpreg,NR_R1);
  961. list.concat(taicpu.op_reg_const(A_SBRC,reg,7));
  962. list.concat(taicpu.op_reg(A_COM,tmpreg));
  963. for i:=2 to tcgsize2size[tosize] do
  964. begin
  965. if QuickRef then
  966. inc(href.offset);
  967. if not(QuickRef) and (i<tcgsize2size[fromsize]) then
  968. href.addressmode:=AM_POSTINCREMENT
  969. else
  970. href.addressmode:=AM_UNCHANGED;
  971. list.concat(taicpu.op_ref_reg(GetStore(href),href,tmpreg));
  972. end;
  973. end;
  974. end;
  975. OS_16:
  976. begin
  977. if not(QuickRef) and (tcgsize2size[tosize]>1) then
  978. href.addressmode:=AM_POSTINCREMENT;
  979. list.concat(taicpu.op_ref_reg(GetStore(href),href,reg));
  980. if QuickRef then
  981. inc(href.offset)
  982. else if not(QuickRef) and (tcgsize2size[fromsize]>2) then
  983. href.addressmode:=AM_POSTINCREMENT
  984. else
  985. href.addressmode:=AM_UNCHANGED;
  986. reg:=GetNextReg(reg);
  987. list.concat(taicpu.op_ref_reg(GetStore(href),href,reg));
  988. for i:=3 to tcgsize2size[tosize] do
  989. begin
  990. if QuickRef then
  991. inc(href.offset);
  992. if not(QuickRef) and (i<tcgsize2size[fromsize]) then
  993. href.addressmode:=AM_POSTINCREMENT
  994. else
  995. href.addressmode:=AM_UNCHANGED;
  996. list.concat(taicpu.op_ref_reg(GetStore(href),href,NR_R1));
  997. end;
  998. end;
  999. OS_S16:
  1000. begin
  1001. if not(QuickRef) and (tcgsize2size[tosize]>1) then
  1002. href.addressmode:=AM_POSTINCREMENT;
  1003. list.concat(taicpu.op_ref_reg(GetStore(href),href,reg));
  1004. if QuickRef then
  1005. inc(href.offset)
  1006. else if not(QuickRef) and (tcgsize2size[fromsize]>2) then
  1007. href.addressmode:=AM_POSTINCREMENT
  1008. else
  1009. href.addressmode:=AM_UNCHANGED;
  1010. reg:=GetNextReg(reg);
  1011. list.concat(taicpu.op_ref_reg(GetStore(href),href,reg));
  1012. if tcgsize2size[tosize]>2 then
  1013. begin
  1014. tmpreg:=getintregister(list,OS_8);
  1015. emit_mov(list,tmpreg,NR_R1);
  1016. list.concat(taicpu.op_reg_const(A_SBRC,reg,7));
  1017. list.concat(taicpu.op_reg(A_COM,tmpreg));
  1018. for i:=3 to tcgsize2size[tosize] do
  1019. begin
  1020. if QuickRef then
  1021. inc(href.offset);
  1022. if not(QuickRef) and (i<tcgsize2size[fromsize]) then
  1023. href.addressmode:=AM_POSTINCREMENT
  1024. else
  1025. href.addressmode:=AM_UNCHANGED;
  1026. list.concat(taicpu.op_ref_reg(GetStore(href),href,tmpreg));
  1027. end;
  1028. end;
  1029. end;
  1030. else
  1031. conv_done:=false;
  1032. end;
  1033. end;
  1034. if not conv_done then
  1035. begin
  1036. for i:=1 to tcgsize2size[fromsize] do
  1037. begin
  1038. if not(QuickRef) and (i<tcgsize2size[fromsize]) then
  1039. href.addressmode:=AM_POSTINCREMENT
  1040. else
  1041. href.addressmode:=AM_UNCHANGED;
  1042. list.concat(taicpu.op_ref_reg(GetStore(href),href,reg));
  1043. if QuickRef then
  1044. inc(href.offset);
  1045. reg:=GetNextReg(reg);
  1046. end;
  1047. end;
  1048. if not(QuickRef) then
  1049. begin
  1050. ungetcpuregister(list,href.base);
  1051. ungetcpuregister(list,GetNextReg(href.base));
  1052. end;
  1053. end;
  1054. procedure tcgavr.a_load_ref_reg(list : TAsmList; fromsize, tosize : tcgsize;
  1055. const Ref : treference;reg : tregister);
  1056. var
  1057. href : treference;
  1058. conv_done: boolean;
  1059. tmpreg : tregister;
  1060. i : integer;
  1061. QuickRef : boolean;
  1062. begin
  1063. QuickRef:=false;
  1064. href:=Ref;
  1065. { ensure, href.base contains a valid register if there is any register used }
  1066. if href.base=NR_NO then
  1067. begin
  1068. href.base:=href.index;
  1069. href.index:=NR_NO;
  1070. end;
  1071. { try to use ldd/lds }
  1072. if not((href.Base=NR_NO) and (href.Index=NR_NO)) then
  1073. begin
  1074. if not((href.addressmode=AM_UNCHANGED) and
  1075. (href.symbol=nil) and
  1076. (href.Index=NR_NO) and
  1077. (href.Offset in [0..64-tcgsize2size[fromsize]])) then
  1078. href:=normalize_ref(list,href,NR_R30)
  1079. else
  1080. begin
  1081. if (href.base<>NR_R28) and (href.base<>NR_R30) then
  1082. begin
  1083. maybegetcpuregister(list,NR_R30);
  1084. emit_mov(list,NR_R30,href.base);
  1085. maybegetcpuregister(list,NR_R31);
  1086. emit_mov(list,NR_R31,GetNextReg(href.base));
  1087. href.base:=NR_R30;
  1088. end;
  1089. QuickRef:=true;
  1090. end;
  1091. end
  1092. else
  1093. QuickRef:=true;
  1094. if (tcgsize2size[fromsize]>32) or (tcgsize2size[tosize]>32) or (fromsize=OS_NO) or (tosize=OS_NO) then
  1095. internalerror(2011021307);
  1096. conv_done:=false;
  1097. if tosize<>fromsize then
  1098. begin
  1099. conv_done:=true;
  1100. if tcgsize2size[tosize]<=tcgsize2size[fromsize] then
  1101. fromsize:=tosize;
  1102. case fromsize of
  1103. OS_8:
  1104. begin
  1105. list.concat(taicpu.op_reg_ref(GetLoad(href),reg,href));
  1106. for i:=2 to tcgsize2size[tosize] do
  1107. begin
  1108. reg:=GetNextReg(reg);
  1109. emit_mov(list,reg,NR_R1);
  1110. end;
  1111. end;
  1112. OS_S8:
  1113. begin
  1114. list.concat(taicpu.op_reg_ref(GetLoad(href),reg,href));
  1115. tmpreg:=reg;
  1116. if tcgsize2size[tosize]>1 then
  1117. begin
  1118. reg:=GetNextReg(reg);
  1119. emit_mov(list,reg,NR_R1);
  1120. list.concat(taicpu.op_reg_const(A_SBRC,tmpreg,7));
  1121. list.concat(taicpu.op_reg(A_COM,reg));
  1122. tmpreg:=reg;
  1123. for i:=3 to tcgsize2size[tosize] do
  1124. begin
  1125. reg:=GetNextReg(reg);
  1126. emit_mov(list,reg,tmpreg);
  1127. end;
  1128. end;
  1129. end;
  1130. OS_16:
  1131. begin
  1132. if not(QuickRef) then
  1133. href.addressmode:=AM_POSTINCREMENT;
  1134. list.concat(taicpu.op_reg_ref(GetLoad(href),reg,href));
  1135. if QuickRef then
  1136. inc(href.offset);
  1137. href.addressmode:=AM_UNCHANGED;
  1138. reg:=GetNextReg(reg);
  1139. list.concat(taicpu.op_reg_ref(GetLoad(href),reg,href));
  1140. for i:=3 to tcgsize2size[tosize] do
  1141. begin
  1142. reg:=GetNextReg(reg);
  1143. emit_mov(list,reg,NR_R1);
  1144. end;
  1145. end;
  1146. OS_S16:
  1147. begin
  1148. if not(QuickRef) then
  1149. href.addressmode:=AM_POSTINCREMENT;
  1150. list.concat(taicpu.op_reg_ref(GetLoad(href),reg,href));
  1151. if QuickRef then
  1152. inc(href.offset);
  1153. href.addressmode:=AM_UNCHANGED;
  1154. reg:=GetNextReg(reg);
  1155. list.concat(taicpu.op_reg_ref(GetLoad(href),reg,href));
  1156. tmpreg:=reg;
  1157. reg:=GetNextReg(reg);
  1158. emit_mov(list,reg,NR_R1);
  1159. list.concat(taicpu.op_reg_const(A_SBRC,tmpreg,7));
  1160. list.concat(taicpu.op_reg(A_COM,reg));
  1161. tmpreg:=reg;
  1162. for i:=4 to tcgsize2size[tosize] do
  1163. begin
  1164. reg:=GetNextReg(reg);
  1165. emit_mov(list,reg,tmpreg);
  1166. end;
  1167. end;
  1168. else
  1169. conv_done:=false;
  1170. end;
  1171. end;
  1172. if not conv_done then
  1173. begin
  1174. for i:=1 to tcgsize2size[fromsize] do
  1175. begin
  1176. if not(QuickRef) and (i<tcgsize2size[fromsize]) then
  1177. href.addressmode:=AM_POSTINCREMENT
  1178. else
  1179. href.addressmode:=AM_UNCHANGED;
  1180. list.concat(taicpu.op_reg_ref(GetLoad(href),reg,href));
  1181. if QuickRef then
  1182. inc(href.offset);
  1183. reg:=GetNextReg(reg);
  1184. end;
  1185. end;
  1186. if not(QuickRef) then
  1187. begin
  1188. ungetcpuregister(list,href.base);
  1189. ungetcpuregister(list,GetNextReg(href.base));
  1190. end;
  1191. end;
  1192. procedure tcgavr.a_load_reg_reg(list : TAsmList; fromsize, tosize : tcgsize;reg1,reg2 : tregister);
  1193. var
  1194. conv_done: boolean;
  1195. tmpreg : tregister;
  1196. i : integer;
  1197. begin
  1198. if (tcgsize2size[fromsize]>32) or (tcgsize2size[tosize]>32) or (fromsize=OS_NO) or (tosize=OS_NO) then
  1199. internalerror(2011021310);
  1200. conv_done:=false;
  1201. if tosize<>fromsize then
  1202. begin
  1203. conv_done:=true;
  1204. if tcgsize2size[tosize]<=tcgsize2size[fromsize] then
  1205. fromsize:=tosize;
  1206. case fromsize of
  1207. OS_8:
  1208. begin
  1209. emit_mov(list,reg2,reg1);
  1210. for i:=2 to tcgsize2size[tosize] do
  1211. begin
  1212. reg2:=GetNextReg(reg2);
  1213. emit_mov(list,reg2,NR_R1);
  1214. end;
  1215. end;
  1216. OS_S8:
  1217. begin
  1218. emit_mov(list,reg2,reg1);
  1219. if tcgsize2size[tosize]>1 then
  1220. begin
  1221. reg2:=GetNextReg(reg2);
  1222. emit_mov(list,reg2,NR_R1);
  1223. list.concat(taicpu.op_reg_const(A_SBRC,reg1,7));
  1224. list.concat(taicpu.op_reg(A_COM,reg2));
  1225. tmpreg:=reg2;
  1226. for i:=3 to tcgsize2size[tosize] do
  1227. begin
  1228. reg2:=GetNextReg(reg2);
  1229. emit_mov(list,reg2,tmpreg);
  1230. end;
  1231. end;
  1232. end;
  1233. OS_16:
  1234. begin
  1235. emit_mov(list,reg2,reg1);
  1236. reg1:=GetNextReg(reg1);
  1237. reg2:=GetNextReg(reg2);
  1238. emit_mov(list,reg2,reg1);
  1239. for i:=3 to tcgsize2size[tosize] do
  1240. begin
  1241. reg2:=GetNextReg(reg2);
  1242. emit_mov(list,reg2,NR_R1);
  1243. end;
  1244. end;
  1245. OS_S16:
  1246. begin
  1247. emit_mov(list,reg2,reg1);
  1248. reg1:=GetNextReg(reg1);
  1249. reg2:=GetNextReg(reg2);
  1250. emit_mov(list,reg2,reg1);
  1251. if tcgsize2size[tosize]>2 then
  1252. begin
  1253. reg2:=GetNextReg(reg2);
  1254. emit_mov(list,reg2,NR_R1);
  1255. list.concat(taicpu.op_reg_const(A_SBRC,reg1,7));
  1256. list.concat(taicpu.op_reg(A_COM,reg2));
  1257. tmpreg:=reg2;
  1258. for i:=4 to tcgsize2size[tosize] do
  1259. begin
  1260. reg2:=GetNextReg(reg2);
  1261. emit_mov(list,reg2,tmpreg);
  1262. end;
  1263. end;
  1264. end;
  1265. else
  1266. conv_done:=false;
  1267. end;
  1268. end;
  1269. if not conv_done and (reg1<>reg2) then
  1270. begin
  1271. for i:=1 to tcgsize2size[fromsize] do
  1272. begin
  1273. emit_mov(list,reg2,reg1);
  1274. reg1:=GetNextReg(reg1);
  1275. reg2:=GetNextReg(reg2);
  1276. end;
  1277. end;
  1278. end;
  1279. procedure tcgavr.a_loadfpu_reg_reg(list: TAsmList; fromsize,tosize: tcgsize; reg1, reg2: tregister);
  1280. begin
  1281. internalerror(2012010702);
  1282. end;
  1283. procedure tcgavr.a_loadfpu_ref_reg(list: TAsmList; fromsize,tosize: tcgsize; const ref: treference; reg: tregister);
  1284. begin
  1285. internalerror(2012010703);
  1286. end;
  1287. procedure tcgavr.a_loadfpu_reg_ref(list: TAsmList; fromsize, tosize: tcgsize; reg: tregister; const ref: treference);
  1288. begin
  1289. internalerror(2012010704);
  1290. end;
  1291. { comparison operations }
  1292. procedure tcgavr.a_cmp_const_reg_label(list : TAsmList;size : tcgsize;
  1293. cmp_op : topcmp;a : tcgint;reg : tregister;l : tasmlabel);
  1294. var
  1295. swapped : boolean;
  1296. tmpreg : tregister;
  1297. i : byte;
  1298. begin
  1299. if a=0 then
  1300. begin
  1301. swapped:=false;
  1302. { swap parameters? }
  1303. case cmp_op of
  1304. OC_GT:
  1305. begin
  1306. swapped:=true;
  1307. cmp_op:=OC_LT;
  1308. end;
  1309. OC_LTE:
  1310. begin
  1311. swapped:=true;
  1312. cmp_op:=OC_GTE;
  1313. end;
  1314. OC_BE:
  1315. begin
  1316. swapped:=true;
  1317. cmp_op:=OC_AE;
  1318. end;
  1319. OC_A:
  1320. begin
  1321. swapped:=true;
  1322. cmp_op:=OC_B;
  1323. end;
  1324. end;
  1325. if swapped then
  1326. list.concat(taicpu.op_reg_reg(A_CP,reg,NR_R1))
  1327. else
  1328. list.concat(taicpu.op_reg_reg(A_CP,NR_R1,reg));
  1329. for i:=2 to tcgsize2size[size] do
  1330. begin
  1331. reg:=GetNextReg(reg);
  1332. if swapped then
  1333. list.concat(taicpu.op_reg_reg(A_CPC,reg,NR_R1))
  1334. else
  1335. list.concat(taicpu.op_reg_reg(A_CPC,NR_R1,reg));
  1336. end;
  1337. a_jmp_cond(list,cmp_op,l);
  1338. end
  1339. else
  1340. inherited a_cmp_const_reg_label(list,size,cmp_op,a,reg,l);
  1341. end;
  1342. procedure tcgavr.a_cmp_reg_reg_label(list : TAsmList;size : tcgsize;
  1343. cmp_op : topcmp;reg1,reg2 : tregister;l : tasmlabel);
  1344. var
  1345. swapped : boolean;
  1346. tmpreg : tregister;
  1347. i : byte;
  1348. begin
  1349. swapped:=false;
  1350. { swap parameters? }
  1351. case cmp_op of
  1352. OC_GT:
  1353. begin
  1354. swapped:=true;
  1355. cmp_op:=OC_LT;
  1356. end;
  1357. OC_LTE:
  1358. begin
  1359. swapped:=true;
  1360. cmp_op:=OC_GTE;
  1361. end;
  1362. OC_BE:
  1363. begin
  1364. swapped:=true;
  1365. cmp_op:=OC_AE;
  1366. end;
  1367. OC_A:
  1368. begin
  1369. swapped:=true;
  1370. cmp_op:=OC_B;
  1371. end;
  1372. end;
  1373. if swapped then
  1374. begin
  1375. tmpreg:=reg1;
  1376. reg1:=reg2;
  1377. reg2:=tmpreg;
  1378. end;
  1379. list.concat(taicpu.op_reg_reg(A_CP,reg2,reg1));
  1380. for i:=2 to tcgsize2size[size] do
  1381. begin
  1382. reg1:=GetNextReg(reg1);
  1383. reg2:=GetNextReg(reg2);
  1384. list.concat(taicpu.op_reg_reg(A_CPC,reg2,reg1));
  1385. end;
  1386. a_jmp_cond(list,cmp_op,l);
  1387. end;
  1388. procedure tcgavr.a_jmp_name(list : TAsmList;const s : string);
  1389. var
  1390. ai : taicpu;
  1391. begin
  1392. if CPUAVR_HAS_JMP_CALL in cpu_capabilities[current_settings.cputype] then
  1393. ai:=taicpu.op_sym(A_JMP,current_asmdata.RefAsmSymbol(s))
  1394. else
  1395. ai:=taicpu.op_sym(A_RJMP,current_asmdata.RefAsmSymbol(s));
  1396. ai.is_jmp:=true;
  1397. list.concat(ai);
  1398. end;
  1399. procedure tcgavr.a_jmp_always(list : TAsmList;l: tasmlabel);
  1400. var
  1401. ai : taicpu;
  1402. begin
  1403. if CPUAVR_HAS_JMP_CALL in cpu_capabilities[current_settings.cputype] then
  1404. ai:=taicpu.op_sym(A_JMP,l)
  1405. else
  1406. ai:=taicpu.op_sym(A_RJMP,l);
  1407. ai.is_jmp:=true;
  1408. list.concat(ai);
  1409. end;
  1410. procedure tcgavr.a_jmp_flags(list : TAsmList;const f : TResFlags;l: tasmlabel);
  1411. var
  1412. ai : taicpu;
  1413. begin
  1414. ai:=setcondition(taicpu.op_sym(A_BRxx,l),flags_to_cond(f));
  1415. ai.is_jmp:=true;
  1416. list.concat(ai);
  1417. end;
  1418. procedure tcgavr.g_flags2reg(list: TAsmList; size: TCgSize; const f: TResFlags; reg: TRegister);
  1419. var
  1420. l : TAsmLabel;
  1421. tmpflags : TResFlags;
  1422. begin
  1423. current_asmdata.getjumplabel(l);
  1424. {
  1425. if flags_to_cond(f) then
  1426. begin
  1427. tmpflags:=f;
  1428. inverse_flags(tmpflags);
  1429. emit_mov(reg,NR_R1);
  1430. a_jmp_flags(list,tmpflags,l);
  1431. list.concat(taicpu.op_reg_const(A_LDI,reg,1));
  1432. end
  1433. else
  1434. }
  1435. begin
  1436. list.concat(taicpu.op_reg_const(A_LDI,reg,1));
  1437. a_jmp_flags(list,f,l);
  1438. emit_mov(list,reg,NR_R1);
  1439. end;
  1440. cg.a_label(list,l);
  1441. end;
  1442. procedure tcgavr.a_adjust_sp(list : TAsmList; value : longint);
  1443. var
  1444. i : integer;
  1445. begin
  1446. case value of
  1447. 0:
  1448. ;
  1449. {-14..-1:
  1450. begin
  1451. if ((-value) mod 2)<>0 then
  1452. list.concat(taicpu.op_reg(A_PUSH,NR_R0));
  1453. for i:=1 to (-value) div 2 do
  1454. list.concat(taicpu.op_const(A_RCALL,0));
  1455. end;
  1456. 1..7:
  1457. begin
  1458. for i:=1 to value do
  1459. list.concat(taicpu.op_reg(A_POP,NR_R0));
  1460. end;}
  1461. else
  1462. begin
  1463. list.concat(taicpu.op_reg_const(A_SUBI,NR_R28,lo(word(-value))));
  1464. list.concat(taicpu.op_reg_const(A_SBCI,NR_R29,hi(word(-value))));
  1465. // get SREG
  1466. list.concat(taicpu.op_reg_const(A_IN,NR_R0,NIO_SREG));
  1467. // block interrupts
  1468. list.concat(taicpu.op_none(A_CLI));
  1469. // write high SP
  1470. list.concat(taicpu.op_const_reg(A_OUT,NIO_SP_HI,NR_R29));
  1471. // release interrupts
  1472. list.concat(taicpu.op_const_reg(A_OUT,NIO_SREG,NR_R0));
  1473. // write low SP
  1474. list.concat(taicpu.op_const_reg(A_OUT,NIO_SP_LO,NR_R28));
  1475. end;
  1476. end;
  1477. end;
  1478. function tcgavr.GetLoad(const ref: treference) : tasmop;
  1479. begin
  1480. if (ref.base=NR_NO) and (ref.index=NR_NO) then
  1481. result:=A_LDS
  1482. else if (ref.base<>NR_NO) and (ref.offset<>0) then
  1483. result:=A_LDD
  1484. else
  1485. result:=A_LD;
  1486. end;
  1487. function tcgavr.GetStore(const ref: treference) : tasmop;
  1488. begin
  1489. if (ref.base=NR_NO) and (ref.index=NR_NO) then
  1490. result:=A_STS
  1491. else if (ref.base<>NR_NO) and (ref.offset<>0) then
  1492. result:=A_STD
  1493. else
  1494. result:=A_ST;
  1495. end;
  1496. procedure tcgavr.g_proc_entry(list : TAsmList;localsize : longint;nostackframe:boolean);
  1497. var
  1498. regs : tcpuregisterset;
  1499. reg : tsuperregister;
  1500. begin
  1501. if not(nostackframe) then
  1502. begin
  1503. { check if the framepointer is actually used, this is done here because
  1504. we have to know the size of the locals (must be 0), avr does not know
  1505. an sp based stack }
  1506. if not(current_procinfo.procdef.stack_tainting_parameter(calleeside)) and
  1507. (localsize=0) then
  1508. current_procinfo.framepointer:=NR_NO;
  1509. { save int registers,
  1510. but only if the procedure returns }
  1511. if not(po_noreturn in current_procinfo.procdef.procoptions) then
  1512. regs:=rg[R_INTREGISTER].used_in_proc-paramanager.get_volatile_registers_int(pocall_stdcall)
  1513. else
  1514. regs:=[];
  1515. { if the framepointer is potentially used, save it always because we need a proper stack frame,
  1516. even if the procedure never returns, the procedure could be e.g. a nested one accessing
  1517. an outer stackframe }
  1518. if current_procinfo.framepointer<>NR_NO then
  1519. regs:=regs+[RS_R28,RS_R29];
  1520. for reg:=RS_R31 downto RS_R0 do
  1521. if reg in regs then
  1522. list.concat(taicpu.op_reg(A_PUSH,newreg(R_INTREGISTER,reg,R_SUBWHOLE)));
  1523. if current_procinfo.framepointer<>NR_NO then
  1524. begin
  1525. list.concat(taicpu.op_reg_const(A_IN,NR_R28,NIO_SP_LO));
  1526. list.concat(taicpu.op_reg_const(A_IN,NR_R29,NIO_SP_HI));
  1527. a_adjust_sp(list,-localsize);
  1528. end;
  1529. end;
  1530. end;
  1531. procedure tcgavr.g_proc_exit(list : TAsmList;parasize : longint;nostackframe:boolean);
  1532. var
  1533. regs : tcpuregisterset;
  1534. reg : TSuperRegister;
  1535. LocalSize : longint;
  1536. begin
  1537. { every byte counts for avr, so if a subroutine is marked as non-returning, we do
  1538. not generate any exit code, so we really trust the noreturn directive
  1539. }
  1540. if po_noreturn in current_procinfo.procdef.procoptions then
  1541. exit;
  1542. if not(nostackframe) then
  1543. begin
  1544. regs:=rg[R_INTREGISTER].used_in_proc-paramanager.get_volatile_registers_int(pocall_stdcall);
  1545. if current_procinfo.framepointer<>NR_NO then
  1546. begin
  1547. regs:=regs+[RS_R28,RS_R29];
  1548. LocalSize:=current_procinfo.calc_stackframe_size;
  1549. a_adjust_sp(list,LocalSize);
  1550. end;
  1551. for reg:=RS_R0 to RS_R31 do
  1552. if reg in regs then
  1553. list.concat(taicpu.op_reg(A_POP,newreg(R_INTREGISTER,reg,R_SUBWHOLE)));
  1554. end;
  1555. list.concat(taicpu.op_none(A_RET));
  1556. end;
  1557. procedure tcgavr.a_loadaddr_ref_reg(list : TAsmList;const ref : treference;r : tregister);
  1558. var
  1559. tmpref : treference;
  1560. begin
  1561. if ref.addressmode<>AM_UNCHANGED then
  1562. internalerror(2011021701);
  1563. if assigned(ref.symbol) or (ref.offset<>0) then
  1564. begin
  1565. reference_reset(tmpref,0);
  1566. tmpref.symbol:=ref.symbol;
  1567. tmpref.offset:=ref.offset;
  1568. if assigned(ref.symbol) and (ref.symbol.typ in [AT_FUNCTION,AT_LABEL]) then
  1569. tmpref.refaddr:=addr_lo8_gs
  1570. else
  1571. tmpref.refaddr:=addr_lo8;
  1572. list.concat(taicpu.op_reg_ref(A_LDI,r,tmpref));
  1573. if assigned(ref.symbol) and (ref.symbol.typ in [AT_FUNCTION,AT_LABEL]) then
  1574. tmpref.refaddr:=addr_hi8_gs
  1575. else
  1576. tmpref.refaddr:=addr_hi8;
  1577. list.concat(taicpu.op_reg_ref(A_LDI,GetNextReg(r),tmpref));
  1578. if (ref.base<>NR_NO) then
  1579. begin
  1580. list.concat(taicpu.op_reg_reg(A_ADD,r,ref.base));
  1581. list.concat(taicpu.op_reg_reg(A_ADC,GetNextReg(r),GetNextReg(ref.base)));
  1582. end;
  1583. if (ref.index<>NR_NO) then
  1584. begin
  1585. list.concat(taicpu.op_reg_reg(A_ADD,r,ref.index));
  1586. list.concat(taicpu.op_reg_reg(A_ADC,GetNextReg(r),GetNextReg(ref.index)));
  1587. end;
  1588. end
  1589. else if (ref.base<>NR_NO)then
  1590. begin
  1591. emit_mov(list,r,ref.base);
  1592. emit_mov(list,GetNextReg(r),GetNextReg(ref.base));
  1593. if (ref.index<>NR_NO) then
  1594. begin
  1595. list.concat(taicpu.op_reg_reg(A_ADD,r,ref.index));
  1596. list.concat(taicpu.op_reg_reg(A_ADC,GetNextReg(r),GetNextReg(ref.index)));
  1597. end;
  1598. end
  1599. else if (ref.index<>NR_NO) then
  1600. begin
  1601. emit_mov(list,r,ref.index);
  1602. emit_mov(list,GetNextReg(r),GetNextReg(ref.index));
  1603. end;
  1604. end;
  1605. procedure tcgavr.fixref(list : TAsmList;var ref : treference);
  1606. begin
  1607. internalerror(2011021320);
  1608. end;
  1609. procedure tcgavr.g_concatcopy_move(list : TAsmList;const source,dest : treference;len : tcgint);
  1610. var
  1611. paraloc1,paraloc2,paraloc3 : TCGPara;
  1612. pd : tprocdef;
  1613. begin
  1614. pd:=search_system_proc('MOVE');
  1615. paraloc1.init;
  1616. paraloc2.init;
  1617. paraloc3.init;
  1618. paramanager.getintparaloc(list,pd,1,paraloc1);
  1619. paramanager.getintparaloc(list,pd,2,paraloc2);
  1620. paramanager.getintparaloc(list,pd,3,paraloc3);
  1621. a_load_const_cgpara(list,OS_SINT,len,paraloc3);
  1622. a_loadaddr_ref_cgpara(list,dest,paraloc2);
  1623. a_loadaddr_ref_cgpara(list,source,paraloc1);
  1624. paramanager.freecgpara(list,paraloc3);
  1625. paramanager.freecgpara(list,paraloc2);
  1626. paramanager.freecgpara(list,paraloc1);
  1627. alloccpuregisters(list,R_INTREGISTER,paramanager.get_volatile_registers_int(pocall_default));
  1628. a_call_name_static(list,'FPC_MOVE');
  1629. dealloccpuregisters(list,R_INTREGISTER,paramanager.get_volatile_registers_int(pocall_default));
  1630. paraloc3.done;
  1631. paraloc2.done;
  1632. paraloc1.done;
  1633. end;
  1634. procedure tcgavr.g_concatcopy(list : TAsmList;const source,dest : treference;len : tcgint);
  1635. var
  1636. countreg,tmpreg : tregister;
  1637. srcref,dstref : treference;
  1638. copysize,countregsize : tcgsize;
  1639. l : TAsmLabel;
  1640. i : longint;
  1641. SrcQuickRef, DestQuickRef : Boolean;
  1642. begin
  1643. if len>16 then
  1644. begin
  1645. current_asmdata.getjumplabel(l);
  1646. reference_reset(srcref,0);
  1647. reference_reset(dstref,0);
  1648. srcref.base:=NR_R30;
  1649. srcref.addressmode:=AM_POSTINCREMENT;
  1650. dstref.base:=NR_R26;
  1651. dstref.addressmode:=AM_POSTINCREMENT;
  1652. copysize:=OS_8;
  1653. if len<256 then
  1654. countregsize:=OS_8
  1655. else if len<65536 then
  1656. countregsize:=OS_16
  1657. else
  1658. internalerror(2011022007);
  1659. countreg:=getintregister(list,countregsize);
  1660. a_load_const_reg(list,countregsize,len,countreg);
  1661. a_loadaddr_ref_reg(list,source,NR_R30);
  1662. tmpreg:=getaddressregister(list);
  1663. a_loadaddr_ref_reg(list,dest,tmpreg);
  1664. { X is used for spilling code so we can load it
  1665. only by a push/pop sequence, this can be
  1666. optimized later on by the peephole optimizer
  1667. }
  1668. list.concat(taicpu.op_reg(A_PUSH,tmpreg));
  1669. list.concat(taicpu.op_reg(A_PUSH,GetNextReg(tmpreg)));
  1670. list.concat(taicpu.op_reg(A_POP,NR_R27));
  1671. list.concat(taicpu.op_reg(A_POP,NR_R26));
  1672. cg.a_label(list,l);
  1673. list.concat(taicpu.op_reg_ref(GetLoad(srcref),NR_R0,srcref));
  1674. list.concat(taicpu.op_ref_reg(GetStore(dstref),dstref,NR_R0));
  1675. list.concat(taicpu.op_reg(A_DEC,countreg));
  1676. a_jmp_flags(list,F_NE,l);
  1677. // keep registers alive
  1678. list.concat(taicpu.op_reg_reg(A_MOV,countreg,countreg));
  1679. end
  1680. else
  1681. begin
  1682. SrcQuickRef:=false;
  1683. DestQuickRef:=false;
  1684. if not((source.addressmode=AM_UNCHANGED) and
  1685. (source.symbol=nil) and
  1686. ((source.base=NR_R28) or
  1687. (source.base=NR_R30)) and
  1688. (source.Index=NR_NO) and
  1689. (source.Offset in [0..64-len])) and
  1690. not((source.Base=NR_NO) and (source.Index=NR_NO)) then
  1691. srcref:=normalize_ref(list,source,NR_R30)
  1692. else
  1693. begin
  1694. SrcQuickRef:=true;
  1695. srcref:=source;
  1696. end;
  1697. if not((dest.addressmode=AM_UNCHANGED) and
  1698. (dest.symbol=nil) and
  1699. ((dest.base=NR_R28) or
  1700. (dest.base=NR_R30)) and
  1701. (dest.Index=NR_No) and
  1702. (dest.Offset in [0..64-len])) and
  1703. not((dest.Base=NR_NO) and (dest.Index=NR_NO)) then
  1704. begin
  1705. if not(SrcQuickRef) then
  1706. begin
  1707. tmpreg:=getaddressregister(list);
  1708. dstref:=normalize_ref(list,dest,tmpreg);
  1709. { X is used for spilling code so we can load it
  1710. only by a push/pop sequence, this can be
  1711. optimized later on by the peephole optimizer
  1712. }
  1713. list.concat(taicpu.op_reg(A_PUSH,tmpreg));
  1714. list.concat(taicpu.op_reg(A_PUSH,GetNextReg(tmpreg)));
  1715. list.concat(taicpu.op_reg(A_POP,NR_R27));
  1716. list.concat(taicpu.op_reg(A_POP,NR_R26));
  1717. dstref.base:=NR_R26;
  1718. end
  1719. else
  1720. dstref:=normalize_ref(list,dest,NR_R30);
  1721. end
  1722. else
  1723. begin
  1724. DestQuickRef:=true;
  1725. dstref:=dest;
  1726. end;
  1727. for i:=1 to len do
  1728. begin
  1729. if not(SrcQuickRef) and (i<len) then
  1730. srcref.addressmode:=AM_POSTINCREMENT
  1731. else
  1732. srcref.addressmode:=AM_UNCHANGED;
  1733. if not(DestQuickRef) and (i<len) then
  1734. dstref.addressmode:=AM_POSTINCREMENT
  1735. else
  1736. dstref.addressmode:=AM_UNCHANGED;
  1737. list.concat(taicpu.op_reg_ref(GetLoad(srcref),NR_R0,srcref));
  1738. list.concat(taicpu.op_ref_reg(GetStore(dstref),dstref,NR_R0));
  1739. if SrcQuickRef then
  1740. inc(srcref.offset);
  1741. if DestQuickRef then
  1742. inc(dstref.offset);
  1743. end;
  1744. if not(SrcQuickRef) then
  1745. begin
  1746. ungetcpuregister(list,srcref.base);
  1747. ungetcpuregister(list,GetNextReg(srcref.base));
  1748. end;
  1749. end;
  1750. end;
  1751. procedure tcgavr.g_overflowCheck(list : TAsmList;const l : tlocation;def : tdef);
  1752. var
  1753. hl : tasmlabel;
  1754. ai : taicpu;
  1755. cond : TAsmCond;
  1756. begin
  1757. if not(cs_check_overflow in current_settings.localswitches) then
  1758. exit;
  1759. current_asmdata.getjumplabel(hl);
  1760. if not ((def.typ=pointerdef) or
  1761. ((def.typ=orddef) and
  1762. (torddef(def).ordtype in [u64bit,u16bit,u32bit,u8bit,uchar,
  1763. pasbool8,pasbool16,pasbool32,pasbool64]))) then
  1764. cond:=C_VC
  1765. else
  1766. cond:=C_CC;
  1767. ai:=Taicpu.Op_Sym(A_BRxx,hl);
  1768. ai.SetCondition(cond);
  1769. ai.is_jmp:=true;
  1770. list.concat(ai);
  1771. a_call_name(list,'FPC_OVERFLOW',false);
  1772. a_label(list,hl);
  1773. end;
  1774. procedure tcgavr.g_save_registers(list: TAsmList);
  1775. begin
  1776. { this is done by the entry code }
  1777. end;
  1778. procedure tcgavr.g_restore_registers(list: TAsmList);
  1779. begin
  1780. { this is done by the exit code }
  1781. end;
  1782. procedure tcgavr.a_jmp_cond(list : TAsmList;cond : TOpCmp;l: tasmlabel);
  1783. var
  1784. ai1,ai2 : taicpu;
  1785. hl : TAsmLabel;
  1786. begin
  1787. ai1:=Taicpu.Op_sym(A_BRxx,l);
  1788. ai1.is_jmp:=true;
  1789. hl:=nil;
  1790. case cond of
  1791. OC_EQ:
  1792. ai1.SetCondition(C_EQ);
  1793. OC_GT:
  1794. begin
  1795. { emulate GT }
  1796. current_asmdata.getjumplabel(hl);
  1797. ai2:=Taicpu.Op_Sym(A_BRxx,hl);
  1798. ai2.SetCondition(C_EQ);
  1799. ai2.is_jmp:=true;
  1800. list.concat(ai2);
  1801. ai1.SetCondition(C_GE);
  1802. end;
  1803. OC_LT:
  1804. ai1.SetCondition(C_LT);
  1805. OC_GTE:
  1806. ai1.SetCondition(C_GE);
  1807. OC_LTE:
  1808. begin
  1809. { emulate LTE }
  1810. ai2:=Taicpu.Op_Sym(A_BRxx,l);
  1811. ai2.SetCondition(C_EQ);
  1812. ai2.is_jmp:=true;
  1813. list.concat(ai2);
  1814. ai1.SetCondition(C_LT);
  1815. end;
  1816. OC_NE:
  1817. ai1.SetCondition(C_NE);
  1818. OC_BE:
  1819. begin
  1820. { emulate BE }
  1821. ai2:=Taicpu.Op_Sym(A_BRxx,l);
  1822. ai2.SetCondition(C_EQ);
  1823. ai2.is_jmp:=true;
  1824. list.concat(ai2);
  1825. ai1.SetCondition(C_LO);
  1826. end;
  1827. OC_B:
  1828. ai1.SetCondition(C_LO);
  1829. OC_AE:
  1830. ai1.SetCondition(C_SH);
  1831. OC_A:
  1832. begin
  1833. { emulate A (unsigned GT) }
  1834. current_asmdata.getjumplabel(hl);
  1835. ai2:=Taicpu.Op_Sym(A_BRxx,hl);
  1836. ai2.SetCondition(C_EQ);
  1837. ai2.is_jmp:=true;
  1838. list.concat(ai2);
  1839. ai1.SetCondition(C_SH);
  1840. end;
  1841. else
  1842. internalerror(2011082501);
  1843. end;
  1844. list.concat(ai1);
  1845. if assigned(hl) then
  1846. a_label(list,hl);
  1847. end;
  1848. procedure tcgavr.emit_mov(list: TAsmList;reg2: tregister; reg1: tregister);
  1849. var
  1850. instr: taicpu;
  1851. begin
  1852. instr:=taicpu.op_reg_reg(A_MOV,reg2,reg1);
  1853. list.Concat(instr);
  1854. { Notify the register allocator that we have written a move instruction so
  1855. it can try to eliminate it. }
  1856. add_move_instruction(instr);
  1857. end;
  1858. procedure tcg64favr.a_op64_reg_reg(list : TAsmList;op:TOpCG;size : tcgsize;regsrc,regdst : tregister64);
  1859. begin
  1860. if not(size in [OS_S64,OS_64]) then
  1861. internalerror(2012102402);
  1862. tcgavr(cg).a_op_reg_reg_internal(list,Op,size,regsrc.reglo,regsrc.reghi,regdst.reglo,regdst.reghi);
  1863. end;
  1864. procedure tcg64favr.a_op64_const_reg(list : TAsmList;op:TOpCG;size : tcgsize;value : int64;reg : tregister64);
  1865. begin
  1866. tcgavr(cg).a_op_const_reg_internal(list,Op,size,value,reg.reglo,reg.reghi);
  1867. end;
  1868. procedure create_codegen;
  1869. begin
  1870. cg:=tcgavr.create;
  1871. cg64:=tcg64favr.create;
  1872. end;
  1873. end.