cgcpu.pas 81 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253
  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. emit_mov(list,NR_ZLO,reg);
  338. a_reg_alloc(list,NR_ZHI);
  339. emit_mov(list,NR_ZHI,GetHigh(reg));
  340. list.concat(taicpu.op_none(A_ICALL));
  341. a_reg_dealloc(list,NR_ZHI);
  342. a_reg_dealloc(list,NR_ZLO);
  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]) and
  360. (CPUAVR_HAS_MUL in cpu_capabilities[current_settings.cputype]) then
  361. begin
  362. getcpuregister(list,NR_R0);
  363. getcpuregister(list,NR_R1);
  364. list.concat(taicpu.op_reg_reg(A_MUL,src1,src2));
  365. emit_mov(list,dst,NR_R0);
  366. emit_mov(list,GetNextReg(dst),NR_R1);
  367. list.concat(taicpu.op_reg_reg(A_MUL,GetNextReg(src1),src2));
  368. list.concat(taicpu.op_reg_reg(A_ADD,GetNextReg(dst),NR_R0));
  369. list.concat(taicpu.op_reg_reg(A_MUL,src1,GetNextReg(src2)));
  370. list.concat(taicpu.op_reg_reg(A_ADD,GetNextReg(dst),NR_R0));
  371. ungetcpuregister(list,NR_R0);
  372. list.concat(taicpu.op_reg(A_CLR,NR_R1));
  373. ungetcpuregister(list,NR_R1);
  374. end
  375. else
  376. inherited a_op_reg_reg_reg(list,op,size,src1,src2,dst);
  377. end;
  378. procedure tcgavr.a_op_const_reg_reg(list: TAsmList; op: TOpCg; size: tcgsize; a: tcgint; src, dst: tregister);
  379. begin
  380. if (op in [OP_MUL,OP_IMUL]) and (size in [OS_16,OS_S16]) and (a in [2,4,8]) then
  381. begin
  382. emit_mov(list,dst,src);
  383. emit_mov(list,GetNextReg(dst),GetNextReg(src));
  384. a:=a shr 1;
  385. while a>0 do
  386. begin
  387. list.concat(taicpu.op_reg(A_LSL,dst));
  388. list.concat(taicpu.op_reg(A_ROL,GetNextReg(dst)));
  389. a:=a shr 1;
  390. end;
  391. end
  392. else
  393. inherited a_op_const_reg_reg(list,op,size,a,src,dst);
  394. end;
  395. procedure tcgavr.a_op_reg_reg_internal(list : TAsmList; Op: TOpCG; size: TCGSize; src, srchi, dst, dsthi: TRegister);
  396. var
  397. countreg,
  398. tmpreg: tregister;
  399. i : integer;
  400. instr : taicpu;
  401. paraloc1,paraloc2,paraloc3 : TCGPara;
  402. l1,l2 : tasmlabel;
  403. pd : tprocdef;
  404. procedure NextSrcDst;
  405. begin
  406. if i=5 then
  407. begin
  408. dst:=dsthi;
  409. src:=srchi;
  410. end
  411. else
  412. begin
  413. dst:=GetNextReg(dst);
  414. src:=GetNextReg(src);
  415. end;
  416. end;
  417. { iterates TmpReg through all registers of dst }
  418. procedure NextTmp;
  419. begin
  420. if i=5 then
  421. tmpreg:=dsthi
  422. else
  423. tmpreg:=GetNextReg(tmpreg);
  424. end;
  425. begin
  426. case op of
  427. OP_ADD:
  428. begin
  429. list.concat(taicpu.op_reg_reg(A_ADD,dst,src));
  430. if size in [OS_S16,OS_16,OS_S32,OS_32,OS_S64,OS_64] then
  431. begin
  432. for i:=2 to tcgsize2size[size] do
  433. begin
  434. NextSrcDst;
  435. list.concat(taicpu.op_reg_reg(A_ADC,dst,src));
  436. end;
  437. end;
  438. end;
  439. OP_SUB:
  440. begin
  441. list.concat(taicpu.op_reg_reg(A_SUB,dst,src));
  442. if size in [OS_S16,OS_16,OS_S32,OS_32,OS_S64,OS_64] then
  443. begin
  444. for i:=2 to tcgsize2size[size] do
  445. begin
  446. NextSrcDst;
  447. list.concat(taicpu.op_reg_reg(A_SBC,dst,src));
  448. end;
  449. end;
  450. end;
  451. OP_NEG:
  452. begin
  453. if src<>dst then
  454. begin
  455. if size in [OS_S64,OS_64] then
  456. begin
  457. a_load_reg_reg(list,OS_32,OS_32,src,dst);
  458. a_load_reg_reg(list,OS_32,OS_32,srchi,dsthi);
  459. end
  460. else
  461. a_load_reg_reg(list,size,size,src,dst);
  462. end;
  463. if size in [OS_S16,OS_16,OS_S32,OS_32,OS_S64,OS_64] then
  464. begin
  465. tmpreg:=GetNextReg(dst);
  466. for i:=2 to tcgsize2size[size] do
  467. begin
  468. list.concat(taicpu.op_reg(A_COM,tmpreg));
  469. NextTmp;
  470. end;
  471. list.concat(taicpu.op_reg(A_NEG,dst));
  472. tmpreg:=GetNextReg(dst);
  473. for i:=2 to tcgsize2size[size] do
  474. begin
  475. list.concat(taicpu.op_reg_const(A_SBCI,tmpreg,-1));
  476. NextTmp;
  477. end;
  478. end;
  479. end;
  480. OP_NOT:
  481. begin
  482. for i:=1 to tcgsize2size[size] do
  483. begin
  484. if src<>dst then
  485. a_load_reg_reg(list,OS_8,OS_8,src,dst);
  486. list.concat(taicpu.op_reg(A_COM,dst));
  487. NextSrcDst;
  488. end;
  489. end;
  490. OP_MUL,OP_IMUL:
  491. begin
  492. if size in [OS_8,OS_S8] then
  493. begin
  494. if CPUAVR_HAS_MUL in cpu_capabilities[current_settings.cputype] then
  495. begin
  496. cg.a_reg_alloc(list,NR_R0);
  497. cg.a_reg_alloc(list,NR_R1);
  498. list.concat(taicpu.op_reg_reg(topcg2asmop[op],dst,src));
  499. list.concat(taicpu.op_reg(A_CLR,NR_R1));
  500. cg.a_reg_dealloc(list,NR_R1);
  501. list.concat(taicpu.op_reg_reg(A_MOV,dst,NR_R0));
  502. cg.a_reg_dealloc(list,NR_R0);
  503. end
  504. else
  505. internalerror(2015061001);
  506. end
  507. else if size=OS_16 then
  508. begin
  509. if CPUAVR_HAS_MUL in cpu_capabilities[current_settings.cputype] then
  510. begin
  511. tmpreg:=getintregister(list,OS_16);
  512. emit_mov(list,tmpreg,dst);
  513. emit_mov(list,GetNextReg(tmpreg),GetNextReg(dst));
  514. list.concat(taicpu.op_reg_reg(A_MUL,tmpreg,src));
  515. emit_mov(list,dst,NR_R0);
  516. emit_mov(list,GetNextReg(dst),NR_R1);
  517. list.concat(taicpu.op_reg_reg(A_MUL,GetNextReg(tmpreg),src));
  518. list.concat(taicpu.op_reg_reg(A_ADD,GetNextReg(dst),NR_R0));
  519. list.concat(taicpu.op_reg_reg(A_MUL,tmpreg,GetNextReg(src)));
  520. list.concat(taicpu.op_reg_reg(A_ADD,GetNextReg(dst),NR_R0));
  521. list.concat(taicpu.op_reg(A_CLR,NR_R1));
  522. end
  523. else
  524. begin
  525. { keep code for muls with overflow checking }
  526. pd:=search_system_proc('fpc_mul_word');
  527. paraloc1.init;
  528. paraloc2.init;
  529. paraloc3.init;
  530. paramanager.getintparaloc(list,pd,1,paraloc1);
  531. paramanager.getintparaloc(list,pd,2,paraloc2);
  532. paramanager.getintparaloc(list,pd,3,paraloc3);
  533. a_load_const_cgpara(list,OS_8,0,paraloc3);
  534. a_load_reg_cgpara(list,OS_16,src,paraloc2);
  535. a_load_reg_cgpara(list,OS_16,dst,paraloc1);
  536. paramanager.freecgpara(list,paraloc3);
  537. paramanager.freecgpara(list,paraloc2);
  538. paramanager.freecgpara(list,paraloc1);
  539. alloccpuregisters(list,R_INTREGISTER,paramanager.get_volatile_registers_int(pocall_default));
  540. a_call_name(list,'FPC_MUL_WORD',false);
  541. dealloccpuregisters(list,R_INTREGISTER,paramanager.get_volatile_registers_int(pocall_default));
  542. cg.a_reg_alloc(list,NR_R24);
  543. cg.a_reg_alloc(list,NR_R25);
  544. cg.a_load_reg_reg(list,OS_8,OS_8,NR_R24,dst);
  545. cg.a_reg_dealloc(list,NR_R24);
  546. cg.a_load_reg_reg(list,OS_8,OS_8,NR_R25,GetNextReg(dst));
  547. cg.a_reg_dealloc(list,NR_R25);
  548. paraloc3.done;
  549. paraloc2.done;
  550. paraloc1.done;
  551. end;
  552. end
  553. else
  554. internalerror(2011022002);
  555. end;
  556. OP_DIV,OP_IDIV:
  557. { special stuff, needs separate handling inside code }
  558. { generator }
  559. internalerror(2011022001);
  560. OP_SHR,OP_SHL,OP_SAR,OP_ROL,OP_ROR:
  561. begin
  562. current_asmdata.getjumplabel(l1);
  563. current_asmdata.getjumplabel(l2);
  564. countreg:=getintregister(list,OS_8);
  565. a_load_reg_reg(list,size,OS_8,src,countreg);
  566. list.concat(taicpu.op_reg(A_TST,countreg));
  567. a_jmp_flags(list,F_EQ,l2);
  568. cg.a_label(list,l1);
  569. case op of
  570. OP_SHR:
  571. list.concat(taicpu.op_reg(A_LSR,GetOffsetReg64(dst,dsthi,tcgsize2size[size]-1)));
  572. OP_SHL:
  573. list.concat(taicpu.op_reg(A_LSL,dst));
  574. OP_SAR:
  575. list.concat(taicpu.op_reg(A_ASR,GetOffsetReg64(dst,dsthi,tcgsize2size[size]-1)));
  576. OP_ROR:
  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,src,0));
  583. list.concat(taicpu.op_none(A_SEC));
  584. end;
  585. list.concat(taicpu.op_reg(A_ROR,GetOffsetReg64(dst,dsthi,tcgsize2size[size]-1)));
  586. end;
  587. OP_ROL:
  588. begin
  589. { load carry? }
  590. if not(size in [OS_8,OS_S8]) then
  591. begin
  592. list.concat(taicpu.op_none(A_CLC));
  593. list.concat(taicpu.op_reg_const(A_SBRC,GetOffsetReg64(dst,dsthi,tcgsize2size[size]-1),7));
  594. list.concat(taicpu.op_none(A_SEC));
  595. end;
  596. list.concat(taicpu.op_reg(A_ROL,dst))
  597. end;
  598. else
  599. internalerror(2011030901);
  600. end;
  601. if size in [OS_S16,OS_16,OS_S32,OS_32,OS_S64,OS_64] then
  602. begin
  603. for i:=2 to tcgsize2size[size] do
  604. begin
  605. case op of
  606. OP_ROR,
  607. OP_SHR:
  608. list.concat(taicpu.op_reg(A_ROR,GetOffsetReg64(dst,dsthi,tcgsize2size[size]-i)));
  609. OP_ROL,
  610. OP_SHL:
  611. list.concat(taicpu.op_reg(A_ROL,GetOffsetReg64(dst,dsthi,i-1)));
  612. OP_SAR:
  613. list.concat(taicpu.op_reg(A_ROR,GetOffsetReg64(dst,dsthi,tcgsize2size[size]-i)));
  614. else
  615. internalerror(2011030902);
  616. end;
  617. end;
  618. end;
  619. list.concat(taicpu.op_reg(A_DEC,countreg));
  620. a_jmp_flags(list,F_NE,l1);
  621. // keep registers alive
  622. list.concat(taicpu.op_reg_reg(A_MOV,countreg,countreg));
  623. cg.a_label(list,l2);
  624. end;
  625. OP_AND,OP_OR,OP_XOR:
  626. begin
  627. for i:=1 to tcgsize2size[size] do
  628. begin
  629. list.concat(taicpu.op_reg_reg(topcg2asmop[op],dst,src));
  630. NextSrcDst;
  631. end;
  632. end;
  633. else
  634. internalerror(2011022004);
  635. end;
  636. end;
  637. procedure tcgavr.a_op_const_reg_internal(list: TAsmList; Op: TOpCG;
  638. size: TCGSize; a: tcgint; reg, reghi: TRegister);
  639. var
  640. mask : qword;
  641. shift : byte;
  642. i,j : byte;
  643. tmpreg : tregister;
  644. tmpreg64 : tregister64;
  645. procedure NextReg;
  646. begin
  647. if i=5 then
  648. reg:=reghi
  649. else
  650. reg:=GetNextReg(reg);
  651. end;
  652. var
  653. curvalue : byte;
  654. begin
  655. optimize_op_const(size,op,a);
  656. mask:=$ff;
  657. shift:=0;
  658. case op of
  659. OP_NONE:
  660. begin
  661. { Opcode is optimized away }
  662. end;
  663. OP_MOVE:
  664. begin
  665. { Optimized, replaced with a simple load }
  666. a_load_const_reg(list,size,a,reg);
  667. end;
  668. OP_OR:
  669. begin
  670. for i:=1 to tcgsize2size[size] do
  671. begin
  672. list.concat(taicpu.op_reg_const(A_ORI,reg,(qword(a) and mask) shr shift));
  673. NextReg;
  674. mask:=mask shl 8;
  675. inc(shift,8);
  676. end;
  677. end;
  678. OP_AND:
  679. begin
  680. for i:=1 to tcgsize2size[size] do
  681. begin
  682. list.concat(taicpu.op_reg_const(A_ANDI,reg,(qword(a) and mask) shr shift));
  683. NextReg;
  684. mask:=mask shl 8;
  685. inc(shift,8);
  686. end;
  687. end;
  688. OP_SUB:
  689. begin
  690. list.concat(taicpu.op_reg_const(A_SUBI,reg,a and mask));
  691. if size in [OS_S16,OS_16,OS_S32,OS_32,OS_S64,OS_64] then
  692. begin
  693. for i:=2 to tcgsize2size[size] do
  694. begin
  695. NextReg;
  696. mask:=mask shl 8;
  697. inc(shift,8);
  698. curvalue:=(qword(a) and mask) shr shift;
  699. { decrease pressure on upper half of registers by using SBC ...,R1 instead
  700. of SBCI ...,0 }
  701. if curvalue=0 then
  702. list.concat(taicpu.op_reg_reg(A_SBC,reg,NR_R1))
  703. else
  704. list.concat(taicpu.op_reg_const(A_SBCI,reg,curvalue));
  705. end;
  706. end;
  707. end;
  708. OP_SHR,OP_SHL,OP_SAR,OP_ROL,OP_ROR:
  709. begin
  710. if a*tcgsize2size[size]<=8 then
  711. begin
  712. for j:=1 to a do
  713. begin
  714. case op of
  715. OP_SHR:
  716. list.concat(taicpu.op_reg(A_LSR,GetOffsetReg64(reg,reghi,tcgsize2size[size]-1)));
  717. OP_SHL:
  718. list.concat(taicpu.op_reg(A_LSL,reg));
  719. OP_SAR:
  720. list.concat(taicpu.op_reg(A_ASR,GetOffsetReg64(reg,reghi,tcgsize2size[size]-1)));
  721. OP_ROR:
  722. begin
  723. { load carry? }
  724. if not(size in [OS_8,OS_S8]) then
  725. begin
  726. list.concat(taicpu.op_none(A_CLC));
  727. list.concat(taicpu.op_reg_const(A_SBRC,reg,0));
  728. list.concat(taicpu.op_none(A_SEC));
  729. end;
  730. list.concat(taicpu.op_reg(A_ROR,GetOffsetReg64(reg,reghi,tcgsize2size[size]-1)));
  731. end;
  732. OP_ROL:
  733. begin
  734. { load carry? }
  735. if not(size in [OS_8,OS_S8]) then
  736. begin
  737. list.concat(taicpu.op_none(A_CLC));
  738. list.concat(taicpu.op_reg_const(A_SBRC,GetOffsetReg64(reg,reghi,tcgsize2size[size]-1),7));
  739. list.concat(taicpu.op_none(A_SEC));
  740. end;
  741. list.concat(taicpu.op_reg(A_ROL,reg))
  742. end;
  743. else
  744. internalerror(2011030901);
  745. end;
  746. if size in [OS_S16,OS_16,OS_S32,OS_32,OS_S64,OS_64] then
  747. begin
  748. for i:=2 to tcgsize2size[size] do
  749. begin
  750. case op of
  751. OP_ROR,
  752. OP_SHR:
  753. list.concat(taicpu.op_reg(A_ROR,GetOffsetReg64(reg,reghi,tcgsize2size[size]-i)));
  754. OP_ROL,
  755. OP_SHL:
  756. list.concat(taicpu.op_reg(A_ROL,GetOffsetReg64(reg,reghi,i-1)));
  757. OP_SAR:
  758. list.concat(taicpu.op_reg(A_ROR,GetOffsetReg64(reg,reghi,tcgsize2size[size]-i)));
  759. else
  760. internalerror(2011030902);
  761. end;
  762. end;
  763. end;
  764. end;
  765. end
  766. else
  767. begin
  768. tmpreg:=getintregister(list,size);
  769. a_load_const_reg(list,size,a,tmpreg);
  770. a_op_reg_reg(list,op,size,tmpreg,reg);
  771. end;
  772. end;
  773. OP_ADD:
  774. begin
  775. curvalue:=a and mask;
  776. if curvalue=0 then
  777. list.concat(taicpu.op_reg_reg(A_ADD,reg,NR_R1))
  778. else
  779. begin
  780. tmpreg:=getintregister(list,OS_8);
  781. a_load_const_reg(list,OS_8,curvalue,tmpreg);
  782. list.concat(taicpu.op_reg_reg(A_ADD,reg,tmpreg));
  783. end;
  784. if size in [OS_S16,OS_16,OS_S32,OS_32,OS_S64,OS_64] then
  785. begin
  786. for i:=2 to tcgsize2size[size] do
  787. begin
  788. NextReg;
  789. mask:=mask shl 8;
  790. inc(shift,8);
  791. curvalue:=(qword(a) and mask) shr shift;
  792. { decrease pressure on upper half of registers by using ADC ...,R1 instead
  793. of ADD ...,0 }
  794. if curvalue=0 then
  795. list.concat(taicpu.op_reg_reg(A_ADC,reg,NR_R1))
  796. else
  797. begin
  798. tmpreg:=getintregister(list,OS_8);
  799. a_load_const_reg(list,OS_8,curvalue,tmpreg);
  800. list.concat(taicpu.op_reg_reg(A_ADC,reg,tmpreg));
  801. end;
  802. end;
  803. end;
  804. end;
  805. else
  806. begin
  807. if size in [OS_64,OS_S64] then
  808. begin
  809. tmpreg64.reglo:=getintregister(list,OS_32);
  810. tmpreg64.reghi:=getintregister(list,OS_32);
  811. cg64.a_load64_const_reg(list,a,tmpreg64);
  812. cg64.a_op64_reg_reg(list,op,size,tmpreg64,joinreg64(reg,reghi));
  813. end
  814. else
  815. begin
  816. {$if 0}
  817. { code not working yet }
  818. if (op=OP_SAR) and (a=31) and (size in [OS_32,OS_S32]) then
  819. begin
  820. tmpreg:=reg;
  821. for i:=1 to 4 do
  822. begin
  823. list.concat(taicpu.op_reg_reg(A_MOV,tmpreg,NR_R1));
  824. tmpreg:=GetNextReg(tmpreg);
  825. end;
  826. end
  827. else
  828. {$endif}
  829. begin
  830. tmpreg:=getintregister(list,size);
  831. a_load_const_reg(list,size,a,tmpreg);
  832. a_op_reg_reg(list,op,size,tmpreg,reg);
  833. end;
  834. end;
  835. end;
  836. end;
  837. end;
  838. procedure tcgavr.a_load_const_reg(list : TAsmList; size: tcgsize; a : tcgint;reg : tregister);
  839. var
  840. mask : qword;
  841. shift : byte;
  842. i : byte;
  843. begin
  844. mask:=$ff;
  845. shift:=0;
  846. for i:=1 to tcgsize2size[size] do
  847. begin
  848. if ((qword(a) and mask) shr shift)=0 then
  849. emit_mov(list,reg,NR_R1)
  850. else
  851. list.concat(taicpu.op_reg_const(A_LDI,reg,(qword(a) and mask) shr shift));
  852. mask:=mask shl 8;
  853. inc(shift,8);
  854. reg:=GetNextReg(reg);
  855. end;
  856. end;
  857. procedure tcgavr.maybegetcpuregister(list:tasmlist;reg : tregister);
  858. begin
  859. { allocate the register only, if a cpu register is passed }
  860. if getsupreg(reg)<first_int_imreg then
  861. getcpuregister(list,reg);
  862. end;
  863. function tcgavr.normalize_ref(list:TAsmList;ref: treference;tmpreg : tregister) : treference;
  864. var
  865. tmpref : treference;
  866. l : tasmlabel;
  867. begin
  868. Result:=ref;
  869. if ref.addressmode<>AM_UNCHANGED then
  870. internalerror(2011021701);
  871. { Be sure to have a base register }
  872. if (ref.base=NR_NO) then
  873. begin
  874. { only symbol+offset? }
  875. if ref.index=NR_NO then
  876. exit;
  877. ref.base:=ref.index;
  878. ref.index:=NR_NO;
  879. end;
  880. { can we take advantage of adiw/sbiw? }
  881. if (current_settings.cputype>=cpu_avr2) and not(assigned(ref.symbol)) and (ref.offset<>0) and (ref.offset>=-63) and (ref.offset<=63) and
  882. ((tmpreg=NR_R24) or (tmpreg=NR_R26) or (tmpreg=NR_R28) or (tmpreg=NR_R30)) and (ref.base<>NR_NO) then
  883. begin
  884. maybegetcpuregister(list,tmpreg);
  885. emit_mov(list,tmpreg,ref.base);
  886. maybegetcpuregister(list,GetNextReg(tmpreg));
  887. emit_mov(list,GetNextReg(tmpreg),GetNextReg(ref.base));
  888. if ref.index<>NR_NO then
  889. begin
  890. list.concat(taicpu.op_reg_reg(A_ADD,tmpreg,ref.index));
  891. list.concat(taicpu.op_reg_reg(A_ADC,GetNextReg(tmpreg),GetNextReg(ref.index)));
  892. end;
  893. if ref.offset>0 then
  894. list.concat(taicpu.op_reg_const(A_ADIW,tmpreg,ref.offset))
  895. else
  896. list.concat(taicpu.op_reg_const(A_SBIW,tmpreg,-ref.offset));
  897. ref.offset:=0;
  898. ref.base:=tmpreg;
  899. ref.index:=NR_NO;
  900. end
  901. else if assigned(ref.symbol) or (ref.offset<>0) then
  902. begin
  903. reference_reset(tmpref,0);
  904. tmpref.symbol:=ref.symbol;
  905. tmpref.offset:=ref.offset;
  906. if assigned(ref.symbol) and (ref.symbol.typ in [AT_FUNCTION,AT_LABEL]) then
  907. tmpref.refaddr:=addr_lo8_gs
  908. else
  909. tmpref.refaddr:=addr_lo8;
  910. maybegetcpuregister(list,tmpreg);
  911. list.concat(taicpu.op_reg_ref(A_LDI,tmpreg,tmpref));
  912. if assigned(ref.symbol) and (ref.symbol.typ in [AT_FUNCTION,AT_LABEL]) then
  913. tmpref.refaddr:=addr_hi8_gs
  914. else
  915. tmpref.refaddr:=addr_hi8;
  916. maybegetcpuregister(list,GetNextReg(tmpreg));
  917. list.concat(taicpu.op_reg_ref(A_LDI,GetNextReg(tmpreg),tmpref));
  918. if (ref.base<>NR_NO) then
  919. begin
  920. list.concat(taicpu.op_reg_reg(A_ADD,tmpreg,ref.base));
  921. list.concat(taicpu.op_reg_reg(A_ADC,GetNextReg(tmpreg),GetNextReg(ref.base)));
  922. end;
  923. if (ref.index<>NR_NO) then
  924. begin
  925. list.concat(taicpu.op_reg_reg(A_ADD,tmpreg,ref.index));
  926. list.concat(taicpu.op_reg_reg(A_ADC,GetNextReg(tmpreg),GetNextReg(ref.index)));
  927. end;
  928. ref.symbol:=nil;
  929. ref.offset:=0;
  930. ref.base:=tmpreg;
  931. ref.index:=NR_NO;
  932. end
  933. else if (ref.base<>NR_NO) and (ref.index<>NR_NO) then
  934. begin
  935. maybegetcpuregister(list,tmpreg);
  936. emit_mov(list,tmpreg,ref.base);
  937. maybegetcpuregister(list,GetNextReg(tmpreg));
  938. emit_mov(list,GetNextReg(tmpreg),GetNextReg(ref.base));
  939. list.concat(taicpu.op_reg_reg(A_ADD,tmpreg,ref.index));
  940. list.concat(taicpu.op_reg_reg(A_ADC,GetNextReg(tmpreg),GetNextReg(ref.index)));
  941. ref.base:=tmpreg;
  942. ref.index:=NR_NO;
  943. end
  944. else if (ref.base<>NR_NO) then
  945. begin
  946. maybegetcpuregister(list,tmpreg);
  947. emit_mov(list,tmpreg,ref.base);
  948. maybegetcpuregister(list,GetNextReg(tmpreg));
  949. emit_mov(list,GetNextReg(tmpreg),GetNextReg(ref.base));
  950. ref.base:=tmpreg;
  951. ref.index:=NR_NO;
  952. end
  953. else if (ref.index<>NR_NO) then
  954. begin
  955. maybegetcpuregister(list,tmpreg);
  956. emit_mov(list,tmpreg,ref.index);
  957. maybegetcpuregister(list,GetNextReg(tmpreg));
  958. emit_mov(list,GetNextReg(tmpreg),GetNextReg(ref.index));
  959. ref.base:=tmpreg;
  960. ref.index:=NR_NO;
  961. end;
  962. Result:=ref;
  963. end;
  964. procedure tcgavr.a_load_reg_ref(list : TAsmList; fromsize, tosize: tcgsize; reg : tregister;const ref : treference);
  965. var
  966. href : treference;
  967. conv_done: boolean;
  968. tmpreg : tregister;
  969. i : integer;
  970. QuickRef : Boolean;
  971. begin
  972. QuickRef:=false;
  973. href:=Ref;
  974. { ensure, href.base contains a valid register if there is any register used }
  975. if href.base=NR_NO then
  976. begin
  977. href.base:=href.index;
  978. href.index:=NR_NO;
  979. end;
  980. { try to use std/sts }
  981. if not((href.Base=NR_NO) and (href.Index=NR_NO)) then
  982. begin
  983. if not((href.addressmode=AM_UNCHANGED) and
  984. (href.symbol=nil) and
  985. (href.Index=NR_NO) and
  986. (href.Offset in [0..64-tcgsize2size[fromsize]])) then
  987. href:=normalize_ref(list,href,NR_R30)
  988. else
  989. begin
  990. if (href.base<>NR_R28) and (href.base<>NR_R30) then
  991. begin
  992. maybegetcpuregister(list,NR_R30);
  993. emit_mov(list,NR_R30,href.base);
  994. maybegetcpuregister(list,NR_R31);
  995. emit_mov(list,NR_R31,GetNextReg(href.base));
  996. href.base:=NR_R30;
  997. end;
  998. QuickRef:=true;
  999. end;
  1000. end
  1001. else
  1002. QuickRef:=true;
  1003. if (tcgsize2size[fromsize]>32) or (tcgsize2size[tosize]>32) or (fromsize=OS_NO) or (tosize=OS_NO) then
  1004. internalerror(2011021307);
  1005. conv_done:=false;
  1006. if tosize<>fromsize then
  1007. begin
  1008. conv_done:=true;
  1009. if tcgsize2size[tosize]<=tcgsize2size[fromsize] then
  1010. fromsize:=tosize;
  1011. case fromsize of
  1012. OS_8:
  1013. begin
  1014. if not(QuickRef) and (tcgsize2size[tosize]>1) then
  1015. href.addressmode:=AM_POSTINCREMENT;
  1016. list.concat(taicpu.op_ref_reg(GetStore(href),href,reg));
  1017. for i:=2 to tcgsize2size[tosize] do
  1018. begin
  1019. if QuickRef then
  1020. inc(href.offset);
  1021. if not(QuickRef) and (i<tcgsize2size[fromsize]) then
  1022. href.addressmode:=AM_POSTINCREMENT
  1023. else
  1024. href.addressmode:=AM_UNCHANGED;
  1025. list.concat(taicpu.op_ref_reg(GetStore(href),href,NR_R1));
  1026. end;
  1027. end;
  1028. OS_S8:
  1029. begin
  1030. if not(QuickRef) and (tcgsize2size[tosize]>1) then
  1031. href.addressmode:=AM_POSTINCREMENT;
  1032. list.concat(taicpu.op_ref_reg(GetStore(href),href,reg));
  1033. if tcgsize2size[tosize]>1 then
  1034. begin
  1035. tmpreg:=getintregister(list,OS_8);
  1036. emit_mov(list,tmpreg,NR_R1);
  1037. list.concat(taicpu.op_reg_const(A_SBRC,reg,7));
  1038. list.concat(taicpu.op_reg(A_COM,tmpreg));
  1039. for i:=2 to tcgsize2size[tosize] do
  1040. begin
  1041. if QuickRef then
  1042. inc(href.offset);
  1043. if not(QuickRef) and (i<tcgsize2size[fromsize]) then
  1044. href.addressmode:=AM_POSTINCREMENT
  1045. else
  1046. href.addressmode:=AM_UNCHANGED;
  1047. list.concat(taicpu.op_ref_reg(GetStore(href),href,tmpreg));
  1048. end;
  1049. end;
  1050. end;
  1051. OS_16:
  1052. begin
  1053. if not(QuickRef) and (tcgsize2size[tosize]>1) then
  1054. href.addressmode:=AM_POSTINCREMENT;
  1055. list.concat(taicpu.op_ref_reg(GetStore(href),href,reg));
  1056. if QuickRef then
  1057. inc(href.offset)
  1058. else if not(QuickRef) and (tcgsize2size[fromsize]>2) then
  1059. href.addressmode:=AM_POSTINCREMENT
  1060. else
  1061. href.addressmode:=AM_UNCHANGED;
  1062. reg:=GetNextReg(reg);
  1063. list.concat(taicpu.op_ref_reg(GetStore(href),href,reg));
  1064. for i:=3 to tcgsize2size[tosize] do
  1065. begin
  1066. if QuickRef then
  1067. inc(href.offset);
  1068. if not(QuickRef) and (i<tcgsize2size[fromsize]) then
  1069. href.addressmode:=AM_POSTINCREMENT
  1070. else
  1071. href.addressmode:=AM_UNCHANGED;
  1072. list.concat(taicpu.op_ref_reg(GetStore(href),href,NR_R1));
  1073. end;
  1074. end;
  1075. OS_S16:
  1076. begin
  1077. if not(QuickRef) and (tcgsize2size[tosize]>1) then
  1078. href.addressmode:=AM_POSTINCREMENT;
  1079. list.concat(taicpu.op_ref_reg(GetStore(href),href,reg));
  1080. if QuickRef then
  1081. inc(href.offset)
  1082. else if not(QuickRef) and (tcgsize2size[fromsize]>2) then
  1083. href.addressmode:=AM_POSTINCREMENT
  1084. else
  1085. href.addressmode:=AM_UNCHANGED;
  1086. reg:=GetNextReg(reg);
  1087. list.concat(taicpu.op_ref_reg(GetStore(href),href,reg));
  1088. if tcgsize2size[tosize]>2 then
  1089. begin
  1090. tmpreg:=getintregister(list,OS_8);
  1091. emit_mov(list,tmpreg,NR_R1);
  1092. list.concat(taicpu.op_reg_const(A_SBRC,reg,7));
  1093. list.concat(taicpu.op_reg(A_COM,tmpreg));
  1094. for i:=3 to tcgsize2size[tosize] do
  1095. begin
  1096. if QuickRef then
  1097. inc(href.offset);
  1098. if not(QuickRef) and (i<tcgsize2size[fromsize]) then
  1099. href.addressmode:=AM_POSTINCREMENT
  1100. else
  1101. href.addressmode:=AM_UNCHANGED;
  1102. list.concat(taicpu.op_ref_reg(GetStore(href),href,tmpreg));
  1103. end;
  1104. end;
  1105. end;
  1106. else
  1107. conv_done:=false;
  1108. end;
  1109. end;
  1110. if not conv_done then
  1111. begin
  1112. for i:=1 to tcgsize2size[fromsize] do
  1113. begin
  1114. if not(QuickRef) and (i<tcgsize2size[fromsize]) then
  1115. href.addressmode:=AM_POSTINCREMENT
  1116. else
  1117. href.addressmode:=AM_UNCHANGED;
  1118. list.concat(taicpu.op_ref_reg(GetStore(href),href,reg));
  1119. if QuickRef then
  1120. inc(href.offset);
  1121. reg:=GetNextReg(reg);
  1122. end;
  1123. end;
  1124. if not(QuickRef) then
  1125. begin
  1126. ungetcpuregister(list,href.base);
  1127. ungetcpuregister(list,GetNextReg(href.base));
  1128. end;
  1129. end;
  1130. procedure tcgavr.a_load_ref_reg(list : TAsmList; fromsize, tosize : tcgsize;
  1131. const Ref : treference;reg : tregister);
  1132. var
  1133. href : treference;
  1134. conv_done: boolean;
  1135. tmpreg : tregister;
  1136. i : integer;
  1137. QuickRef : boolean;
  1138. begin
  1139. QuickRef:=false;
  1140. href:=Ref;
  1141. { ensure, href.base contains a valid register if there is any register used }
  1142. if href.base=NR_NO then
  1143. begin
  1144. href.base:=href.index;
  1145. href.index:=NR_NO;
  1146. end;
  1147. { try to use ldd/lds }
  1148. if not((href.Base=NR_NO) and (href.Index=NR_NO)) then
  1149. begin
  1150. if not((href.addressmode=AM_UNCHANGED) and
  1151. (href.symbol=nil) and
  1152. (href.Index=NR_NO) and
  1153. (href.Offset in [0..64-tcgsize2size[fromsize]])) then
  1154. href:=normalize_ref(list,href,NR_R30)
  1155. else
  1156. begin
  1157. if (href.base<>NR_R28) and (href.base<>NR_R30) then
  1158. begin
  1159. maybegetcpuregister(list,NR_R30);
  1160. emit_mov(list,NR_R30,href.base);
  1161. maybegetcpuregister(list,NR_R31);
  1162. emit_mov(list,NR_R31,GetNextReg(href.base));
  1163. href.base:=NR_R30;
  1164. end;
  1165. QuickRef:=true;
  1166. end;
  1167. end
  1168. else
  1169. QuickRef:=true;
  1170. if (tcgsize2size[fromsize]>32) or (tcgsize2size[tosize]>32) or (fromsize=OS_NO) or (tosize=OS_NO) then
  1171. internalerror(2011021307);
  1172. conv_done:=false;
  1173. if tosize<>fromsize then
  1174. begin
  1175. conv_done:=true;
  1176. if tcgsize2size[tosize]<=tcgsize2size[fromsize] then
  1177. fromsize:=tosize;
  1178. case fromsize of
  1179. OS_8:
  1180. begin
  1181. list.concat(taicpu.op_reg_ref(GetLoad(href),reg,href));
  1182. for i:=2 to tcgsize2size[tosize] do
  1183. begin
  1184. reg:=GetNextReg(reg);
  1185. emit_mov(list,reg,NR_R1);
  1186. end;
  1187. end;
  1188. OS_S8:
  1189. begin
  1190. list.concat(taicpu.op_reg_ref(GetLoad(href),reg,href));
  1191. tmpreg:=reg;
  1192. if tcgsize2size[tosize]>1 then
  1193. begin
  1194. reg:=GetNextReg(reg);
  1195. emit_mov(list,reg,NR_R1);
  1196. list.concat(taicpu.op_reg_const(A_SBRC,tmpreg,7));
  1197. list.concat(taicpu.op_reg(A_COM,reg));
  1198. tmpreg:=reg;
  1199. for i:=3 to tcgsize2size[tosize] do
  1200. begin
  1201. reg:=GetNextReg(reg);
  1202. emit_mov(list,reg,tmpreg);
  1203. end;
  1204. end;
  1205. end;
  1206. OS_16:
  1207. begin
  1208. if not(QuickRef) then
  1209. href.addressmode:=AM_POSTINCREMENT;
  1210. list.concat(taicpu.op_reg_ref(GetLoad(href),reg,href));
  1211. if QuickRef then
  1212. inc(href.offset);
  1213. href.addressmode:=AM_UNCHANGED;
  1214. reg:=GetNextReg(reg);
  1215. list.concat(taicpu.op_reg_ref(GetLoad(href),reg,href));
  1216. for i:=3 to tcgsize2size[tosize] do
  1217. begin
  1218. reg:=GetNextReg(reg);
  1219. emit_mov(list,reg,NR_R1);
  1220. end;
  1221. end;
  1222. OS_S16:
  1223. begin
  1224. if not(QuickRef) then
  1225. href.addressmode:=AM_POSTINCREMENT;
  1226. list.concat(taicpu.op_reg_ref(GetLoad(href),reg,href));
  1227. if QuickRef then
  1228. inc(href.offset);
  1229. href.addressmode:=AM_UNCHANGED;
  1230. reg:=GetNextReg(reg);
  1231. list.concat(taicpu.op_reg_ref(GetLoad(href),reg,href));
  1232. tmpreg:=reg;
  1233. reg:=GetNextReg(reg);
  1234. emit_mov(list,reg,NR_R1);
  1235. list.concat(taicpu.op_reg_const(A_SBRC,tmpreg,7));
  1236. list.concat(taicpu.op_reg(A_COM,reg));
  1237. tmpreg:=reg;
  1238. for i:=4 to tcgsize2size[tosize] do
  1239. begin
  1240. reg:=GetNextReg(reg);
  1241. emit_mov(list,reg,tmpreg);
  1242. end;
  1243. end;
  1244. else
  1245. conv_done:=false;
  1246. end;
  1247. end;
  1248. if not conv_done then
  1249. begin
  1250. for i:=1 to tcgsize2size[fromsize] do
  1251. begin
  1252. if not(QuickRef) and (i<tcgsize2size[fromsize]) then
  1253. href.addressmode:=AM_POSTINCREMENT
  1254. else
  1255. href.addressmode:=AM_UNCHANGED;
  1256. list.concat(taicpu.op_reg_ref(GetLoad(href),reg,href));
  1257. if QuickRef then
  1258. inc(href.offset);
  1259. reg:=GetNextReg(reg);
  1260. end;
  1261. end;
  1262. if not(QuickRef) then
  1263. begin
  1264. ungetcpuregister(list,href.base);
  1265. ungetcpuregister(list,GetNextReg(href.base));
  1266. end;
  1267. end;
  1268. procedure tcgavr.a_load_reg_reg(list : TAsmList; fromsize, tosize : tcgsize;reg1,reg2 : tregister);
  1269. var
  1270. conv_done: boolean;
  1271. tmpreg : tregister;
  1272. i : integer;
  1273. begin
  1274. if (tcgsize2size[fromsize]>32) or (tcgsize2size[tosize]>32) or (fromsize=OS_NO) or (tosize=OS_NO) then
  1275. internalerror(2011021310);
  1276. conv_done:=false;
  1277. if tosize<>fromsize then
  1278. begin
  1279. conv_done:=true;
  1280. if tcgsize2size[tosize]<=tcgsize2size[fromsize] then
  1281. fromsize:=tosize;
  1282. case fromsize of
  1283. OS_8:
  1284. begin
  1285. emit_mov(list,reg2,reg1);
  1286. for i:=2 to tcgsize2size[tosize] do
  1287. begin
  1288. reg2:=GetNextReg(reg2);
  1289. emit_mov(list,reg2,NR_R1);
  1290. end;
  1291. end;
  1292. OS_S8:
  1293. begin
  1294. emit_mov(list,reg2,reg1);
  1295. if tcgsize2size[tosize]>1 then
  1296. begin
  1297. reg2:=GetNextReg(reg2);
  1298. emit_mov(list,reg2,NR_R1);
  1299. list.concat(taicpu.op_reg_const(A_SBRC,reg1,7));
  1300. list.concat(taicpu.op_reg(A_COM,reg2));
  1301. tmpreg:=reg2;
  1302. for i:=3 to tcgsize2size[tosize] do
  1303. begin
  1304. reg2:=GetNextReg(reg2);
  1305. emit_mov(list,reg2,tmpreg);
  1306. end;
  1307. end;
  1308. end;
  1309. OS_16:
  1310. begin
  1311. emit_mov(list,reg2,reg1);
  1312. reg1:=GetNextReg(reg1);
  1313. reg2:=GetNextReg(reg2);
  1314. emit_mov(list,reg2,reg1);
  1315. for i:=3 to tcgsize2size[tosize] do
  1316. begin
  1317. reg2:=GetNextReg(reg2);
  1318. emit_mov(list,reg2,NR_R1);
  1319. end;
  1320. end;
  1321. OS_S16:
  1322. begin
  1323. emit_mov(list,reg2,reg1);
  1324. reg1:=GetNextReg(reg1);
  1325. reg2:=GetNextReg(reg2);
  1326. emit_mov(list,reg2,reg1);
  1327. if tcgsize2size[tosize]>2 then
  1328. begin
  1329. reg2:=GetNextReg(reg2);
  1330. emit_mov(list,reg2,NR_R1);
  1331. list.concat(taicpu.op_reg_const(A_SBRC,reg1,7));
  1332. list.concat(taicpu.op_reg(A_COM,reg2));
  1333. tmpreg:=reg2;
  1334. for i:=4 to tcgsize2size[tosize] do
  1335. begin
  1336. reg2:=GetNextReg(reg2);
  1337. emit_mov(list,reg2,tmpreg);
  1338. end;
  1339. end;
  1340. end;
  1341. else
  1342. conv_done:=false;
  1343. end;
  1344. end;
  1345. if not conv_done and (reg1<>reg2) then
  1346. begin
  1347. for i:=1 to tcgsize2size[fromsize] do
  1348. begin
  1349. emit_mov(list,reg2,reg1);
  1350. reg1:=GetNextReg(reg1);
  1351. reg2:=GetNextReg(reg2);
  1352. end;
  1353. end;
  1354. end;
  1355. procedure tcgavr.a_loadfpu_reg_reg(list: TAsmList; fromsize,tosize: tcgsize; reg1, reg2: tregister);
  1356. begin
  1357. internalerror(2012010702);
  1358. end;
  1359. procedure tcgavr.a_loadfpu_ref_reg(list: TAsmList; fromsize,tosize: tcgsize; const ref: treference; reg: tregister);
  1360. begin
  1361. internalerror(2012010703);
  1362. end;
  1363. procedure tcgavr.a_loadfpu_reg_ref(list: TAsmList; fromsize, tosize: tcgsize; reg: tregister; const ref: treference);
  1364. begin
  1365. internalerror(2012010704);
  1366. end;
  1367. { comparison operations }
  1368. procedure tcgavr.a_cmp_const_reg_label(list : TAsmList;size : tcgsize;
  1369. cmp_op : topcmp;a : tcgint;reg : tregister;l : tasmlabel);
  1370. var
  1371. swapped : boolean;
  1372. tmpreg : tregister;
  1373. i : byte;
  1374. begin
  1375. if a=0 then
  1376. begin
  1377. swapped:=false;
  1378. { swap parameters? }
  1379. case cmp_op of
  1380. OC_GT:
  1381. begin
  1382. swapped:=true;
  1383. cmp_op:=OC_LT;
  1384. end;
  1385. OC_LTE:
  1386. begin
  1387. swapped:=true;
  1388. cmp_op:=OC_GTE;
  1389. end;
  1390. OC_BE:
  1391. begin
  1392. swapped:=true;
  1393. cmp_op:=OC_AE;
  1394. end;
  1395. OC_A:
  1396. begin
  1397. swapped:=true;
  1398. cmp_op:=OC_B;
  1399. end;
  1400. end;
  1401. if swapped then
  1402. list.concat(taicpu.op_reg_reg(A_CP,reg,NR_R1))
  1403. else
  1404. list.concat(taicpu.op_reg_reg(A_CP,NR_R1,reg));
  1405. for i:=2 to tcgsize2size[size] do
  1406. begin
  1407. reg:=GetNextReg(reg);
  1408. if swapped then
  1409. list.concat(taicpu.op_reg_reg(A_CPC,reg,NR_R1))
  1410. else
  1411. list.concat(taicpu.op_reg_reg(A_CPC,NR_R1,reg));
  1412. end;
  1413. a_jmp_cond(list,cmp_op,l);
  1414. end
  1415. else
  1416. inherited a_cmp_const_reg_label(list,size,cmp_op,a,reg,l);
  1417. end;
  1418. procedure tcgavr.a_cmp_reg_reg_label(list : TAsmList;size : tcgsize;
  1419. cmp_op : topcmp;reg1,reg2 : tregister;l : tasmlabel);
  1420. var
  1421. swapped : boolean;
  1422. tmpreg : tregister;
  1423. i : byte;
  1424. begin
  1425. swapped:=false;
  1426. { swap parameters? }
  1427. case cmp_op of
  1428. OC_GT:
  1429. begin
  1430. swapped:=true;
  1431. cmp_op:=OC_LT;
  1432. end;
  1433. OC_LTE:
  1434. begin
  1435. swapped:=true;
  1436. cmp_op:=OC_GTE;
  1437. end;
  1438. OC_BE:
  1439. begin
  1440. swapped:=true;
  1441. cmp_op:=OC_AE;
  1442. end;
  1443. OC_A:
  1444. begin
  1445. swapped:=true;
  1446. cmp_op:=OC_B;
  1447. end;
  1448. end;
  1449. if swapped then
  1450. begin
  1451. tmpreg:=reg1;
  1452. reg1:=reg2;
  1453. reg2:=tmpreg;
  1454. end;
  1455. list.concat(taicpu.op_reg_reg(A_CP,reg2,reg1));
  1456. for i:=2 to tcgsize2size[size] do
  1457. begin
  1458. reg1:=GetNextReg(reg1);
  1459. reg2:=GetNextReg(reg2);
  1460. list.concat(taicpu.op_reg_reg(A_CPC,reg2,reg1));
  1461. end;
  1462. a_jmp_cond(list,cmp_op,l);
  1463. end;
  1464. procedure tcgavr.a_jmp_name(list : TAsmList;const s : string);
  1465. var
  1466. ai : taicpu;
  1467. begin
  1468. if CPUAVR_HAS_JMP_CALL in cpu_capabilities[current_settings.cputype] then
  1469. ai:=taicpu.op_sym(A_JMP,current_asmdata.RefAsmSymbol(s))
  1470. else
  1471. ai:=taicpu.op_sym(A_RJMP,current_asmdata.RefAsmSymbol(s));
  1472. ai.is_jmp:=true;
  1473. list.concat(ai);
  1474. end;
  1475. procedure tcgavr.a_jmp_always(list : TAsmList;l: tasmlabel);
  1476. var
  1477. ai : taicpu;
  1478. begin
  1479. if CPUAVR_HAS_JMP_CALL in cpu_capabilities[current_settings.cputype] then
  1480. ai:=taicpu.op_sym(A_JMP,l)
  1481. else
  1482. ai:=taicpu.op_sym(A_RJMP,l);
  1483. ai.is_jmp:=true;
  1484. list.concat(ai);
  1485. end;
  1486. procedure tcgavr.a_jmp_flags(list : TAsmList;const f : TResFlags;l: tasmlabel);
  1487. var
  1488. ai : taicpu;
  1489. begin
  1490. ai:=setcondition(taicpu.op_sym(A_BRxx,l),flags_to_cond(f));
  1491. ai.is_jmp:=true;
  1492. list.concat(ai);
  1493. end;
  1494. procedure tcgavr.g_flags2reg(list: TAsmList; size: TCgSize; const f: TResFlags; reg: TRegister);
  1495. var
  1496. l : TAsmLabel;
  1497. tmpflags : TResFlags;
  1498. begin
  1499. current_asmdata.getjumplabel(l);
  1500. {
  1501. if flags_to_cond(f) then
  1502. begin
  1503. tmpflags:=f;
  1504. inverse_flags(tmpflags);
  1505. emit_mov(reg,NR_R1);
  1506. a_jmp_flags(list,tmpflags,l);
  1507. list.concat(taicpu.op_reg_const(A_LDI,reg,1));
  1508. end
  1509. else
  1510. }
  1511. begin
  1512. list.concat(taicpu.op_reg_const(A_LDI,reg,1));
  1513. a_jmp_flags(list,f,l);
  1514. emit_mov(list,reg,NR_R1);
  1515. end;
  1516. cg.a_label(list,l);
  1517. end;
  1518. procedure tcgavr.a_adjust_sp(list : TAsmList; value : longint);
  1519. var
  1520. i : integer;
  1521. begin
  1522. case value of
  1523. 0:
  1524. ;
  1525. {-14..-1:
  1526. begin
  1527. if ((-value) mod 2)<>0 then
  1528. list.concat(taicpu.op_reg(A_PUSH,NR_R0));
  1529. for i:=1 to (-value) div 2 do
  1530. list.concat(taicpu.op_const(A_RCALL,0));
  1531. end;
  1532. 1..7:
  1533. begin
  1534. for i:=1 to value do
  1535. list.concat(taicpu.op_reg(A_POP,NR_R0));
  1536. end;}
  1537. else
  1538. begin
  1539. list.concat(taicpu.op_reg_const(A_SUBI,NR_R28,lo(word(-value))));
  1540. list.concat(taicpu.op_reg_const(A_SBCI,NR_R29,hi(word(-value))));
  1541. // get SREG
  1542. list.concat(taicpu.op_reg_const(A_IN,NR_R0,NIO_SREG));
  1543. // block interrupts
  1544. list.concat(taicpu.op_none(A_CLI));
  1545. // write high SP
  1546. list.concat(taicpu.op_const_reg(A_OUT,NIO_SP_HI,NR_R29));
  1547. // release interrupts
  1548. list.concat(taicpu.op_const_reg(A_OUT,NIO_SREG,NR_R0));
  1549. // write low SP
  1550. list.concat(taicpu.op_const_reg(A_OUT,NIO_SP_LO,NR_R28));
  1551. end;
  1552. end;
  1553. end;
  1554. function tcgavr.GetLoad(const ref: treference) : tasmop;
  1555. begin
  1556. if (ref.base=NR_NO) and (ref.index=NR_NO) then
  1557. result:=A_LDS
  1558. else if (ref.base<>NR_NO) and (ref.offset<>0) then
  1559. result:=A_LDD
  1560. else
  1561. result:=A_LD;
  1562. end;
  1563. function tcgavr.GetStore(const ref: treference) : tasmop;
  1564. begin
  1565. if (ref.base=NR_NO) and (ref.index=NR_NO) then
  1566. result:=A_STS
  1567. else if (ref.base<>NR_NO) and (ref.offset<>0) then
  1568. result:=A_STD
  1569. else
  1570. result:=A_ST;
  1571. end;
  1572. procedure tcgavr.g_proc_entry(list : TAsmList;localsize : longint;nostackframe:boolean);
  1573. var
  1574. regs : tcpuregisterset;
  1575. reg : tsuperregister;
  1576. begin
  1577. if po_interrupt in current_procinfo.procdef.procoptions then
  1578. begin
  1579. { check if the framepointer is actually used, this is done here because
  1580. we have to know the size of the locals (must be 0), avr does not know
  1581. an sp based stack }
  1582. if not(current_procinfo.procdef.stack_tainting_parameter(calleeside)) and
  1583. (localsize=0) then
  1584. current_procinfo.framepointer:=NR_NO;
  1585. { save int registers,
  1586. but only if the procedure returns }
  1587. if not(po_noreturn in current_procinfo.procdef.procoptions) then
  1588. regs:=rg[R_INTREGISTER].used_in_proc
  1589. else
  1590. regs:=[];
  1591. { if the framepointer is potentially used, save it always because we need a proper stack frame,
  1592. even if the procedure never returns, the procedure could be e.g. a nested one accessing
  1593. an outer stackframe }
  1594. if current_procinfo.framepointer<>NR_NO then
  1595. regs:=regs+[RS_R28,RS_R29];
  1596. regs:=regs+[RS_R0];
  1597. for reg:=RS_R31 downto RS_R0 do
  1598. if reg in regs then
  1599. list.concat(taicpu.op_reg(A_PUSH,newreg(R_INTREGISTER,reg,R_SUBWHOLE)));
  1600. { Save SREG }
  1601. list.concat(taicpu.op_reg_const(A_IN, NR_R0, $3F));
  1602. list.concat(taicpu.op_reg(A_PUSH, NR_R0));
  1603. if current_procinfo.framepointer<>NR_NO then
  1604. begin
  1605. list.concat(taicpu.op_reg_const(A_IN,NR_R28,NIO_SP_LO));
  1606. list.concat(taicpu.op_reg_const(A_IN,NR_R29,NIO_SP_HI));
  1607. a_adjust_sp(list,-localsize);
  1608. end;
  1609. end
  1610. else if not(nostackframe) then
  1611. begin
  1612. { check if the framepointer is actually used, this is done here because
  1613. we have to know the size of the locals (must be 0), avr does not know
  1614. an sp based stack }
  1615. if not(current_procinfo.procdef.stack_tainting_parameter(calleeside)) and
  1616. (localsize=0) then
  1617. current_procinfo.framepointer:=NR_NO;
  1618. { save int registers,
  1619. but only if the procedure returns }
  1620. if not(po_noreturn in current_procinfo.procdef.procoptions) then
  1621. regs:=rg[R_INTREGISTER].used_in_proc-paramanager.get_volatile_registers_int(pocall_stdcall)
  1622. else
  1623. regs:=[];
  1624. { if the framepointer is potentially used, save it always because we need a proper stack frame,
  1625. even if the procedure never returns, the procedure could be e.g. a nested one accessing
  1626. an outer stackframe }
  1627. if current_procinfo.framepointer<>NR_NO then
  1628. regs:=regs+[RS_R28,RS_R29];
  1629. for reg:=RS_R31 downto RS_R0 do
  1630. if reg in regs then
  1631. list.concat(taicpu.op_reg(A_PUSH,newreg(R_INTREGISTER,reg,R_SUBWHOLE)));
  1632. if current_procinfo.framepointer<>NR_NO then
  1633. begin
  1634. list.concat(taicpu.op_reg_const(A_IN,NR_R28,NIO_SP_LO));
  1635. list.concat(taicpu.op_reg_const(A_IN,NR_R29,NIO_SP_HI));
  1636. a_adjust_sp(list,-localsize);
  1637. end;
  1638. end;
  1639. end;
  1640. procedure tcgavr.g_proc_exit(list : TAsmList;parasize : longint;nostackframe:boolean);
  1641. var
  1642. regs : tcpuregisterset;
  1643. reg : TSuperRegister;
  1644. LocalSize : longint;
  1645. begin
  1646. { every byte counts for avr, so if a subroutine is marked as non-returning, we do
  1647. not generate any exit code, so we really trust the noreturn directive
  1648. }
  1649. if po_noreturn in current_procinfo.procdef.procoptions then
  1650. exit;
  1651. if po_interrupt in current_procinfo.procdef.procoptions then
  1652. begin
  1653. regs:=rg[R_INTREGISTER].used_in_proc;
  1654. if current_procinfo.framepointer<>NR_NO then
  1655. begin
  1656. regs:=regs+[RS_R28,RS_R29];
  1657. LocalSize:=current_procinfo.calc_stackframe_size;
  1658. a_adjust_sp(list,LocalSize);
  1659. end;
  1660. { Reload SREG }
  1661. regs:=regs+[RS_R0];
  1662. list.concat(taicpu.op_reg(A_POP, NR_R0));
  1663. list.concat(taicpu.op_const_reg(A_OUT, $3F, NR_R0));
  1664. for reg:=RS_R0 to RS_R31 do
  1665. if reg in regs then
  1666. list.concat(taicpu.op_reg(A_POP,newreg(R_INTREGISTER,reg,R_SUBWHOLE)));
  1667. list.concat(taicpu.op_none(A_RETI));
  1668. end
  1669. else if not(nostackframe) then
  1670. begin
  1671. regs:=rg[R_INTREGISTER].used_in_proc-paramanager.get_volatile_registers_int(pocall_stdcall);
  1672. if current_procinfo.framepointer<>NR_NO then
  1673. begin
  1674. regs:=regs+[RS_R28,RS_R29];
  1675. LocalSize:=current_procinfo.calc_stackframe_size;
  1676. a_adjust_sp(list,LocalSize);
  1677. end;
  1678. for reg:=RS_R0 to RS_R31 do
  1679. if reg in regs then
  1680. list.concat(taicpu.op_reg(A_POP,newreg(R_INTREGISTER,reg,R_SUBWHOLE)));
  1681. list.concat(taicpu.op_none(A_RET));
  1682. end
  1683. else
  1684. list.concat(taicpu.op_none(A_RET));
  1685. end;
  1686. procedure tcgavr.a_loadaddr_ref_reg(list : TAsmList;const ref : treference;r : tregister);
  1687. var
  1688. tmpref : treference;
  1689. begin
  1690. if ref.addressmode<>AM_UNCHANGED then
  1691. internalerror(2011021701);
  1692. if assigned(ref.symbol) or (ref.offset<>0) then
  1693. begin
  1694. reference_reset(tmpref,0);
  1695. tmpref.symbol:=ref.symbol;
  1696. tmpref.offset:=ref.offset;
  1697. if assigned(ref.symbol) and (ref.symbol.typ in [AT_FUNCTION,AT_LABEL]) then
  1698. tmpref.refaddr:=addr_lo8_gs
  1699. else
  1700. tmpref.refaddr:=addr_lo8;
  1701. list.concat(taicpu.op_reg_ref(A_LDI,r,tmpref));
  1702. if assigned(ref.symbol) and (ref.symbol.typ in [AT_FUNCTION,AT_LABEL]) then
  1703. tmpref.refaddr:=addr_hi8_gs
  1704. else
  1705. tmpref.refaddr:=addr_hi8;
  1706. list.concat(taicpu.op_reg_ref(A_LDI,GetNextReg(r),tmpref));
  1707. if (ref.base<>NR_NO) then
  1708. begin
  1709. list.concat(taicpu.op_reg_reg(A_ADD,r,ref.base));
  1710. list.concat(taicpu.op_reg_reg(A_ADC,GetNextReg(r),GetNextReg(ref.base)));
  1711. end;
  1712. if (ref.index<>NR_NO) then
  1713. begin
  1714. list.concat(taicpu.op_reg_reg(A_ADD,r,ref.index));
  1715. list.concat(taicpu.op_reg_reg(A_ADC,GetNextReg(r),GetNextReg(ref.index)));
  1716. end;
  1717. end
  1718. else if (ref.base<>NR_NO)then
  1719. begin
  1720. emit_mov(list,r,ref.base);
  1721. emit_mov(list,GetNextReg(r),GetNextReg(ref.base));
  1722. if (ref.index<>NR_NO) then
  1723. begin
  1724. list.concat(taicpu.op_reg_reg(A_ADD,r,ref.index));
  1725. list.concat(taicpu.op_reg_reg(A_ADC,GetNextReg(r),GetNextReg(ref.index)));
  1726. end;
  1727. end
  1728. else if (ref.index<>NR_NO) then
  1729. begin
  1730. emit_mov(list,r,ref.index);
  1731. emit_mov(list,GetNextReg(r),GetNextReg(ref.index));
  1732. end;
  1733. end;
  1734. procedure tcgavr.fixref(list : TAsmList;var ref : treference);
  1735. begin
  1736. internalerror(2011021320);
  1737. end;
  1738. procedure tcgavr.g_concatcopy_move(list : TAsmList;const source,dest : treference;len : tcgint);
  1739. var
  1740. paraloc1,paraloc2,paraloc3 : TCGPara;
  1741. pd : tprocdef;
  1742. begin
  1743. pd:=search_system_proc('MOVE');
  1744. paraloc1.init;
  1745. paraloc2.init;
  1746. paraloc3.init;
  1747. paramanager.getintparaloc(list,pd,1,paraloc1);
  1748. paramanager.getintparaloc(list,pd,2,paraloc2);
  1749. paramanager.getintparaloc(list,pd,3,paraloc3);
  1750. a_load_const_cgpara(list,OS_SINT,len,paraloc3);
  1751. a_loadaddr_ref_cgpara(list,dest,paraloc2);
  1752. a_loadaddr_ref_cgpara(list,source,paraloc1);
  1753. paramanager.freecgpara(list,paraloc3);
  1754. paramanager.freecgpara(list,paraloc2);
  1755. paramanager.freecgpara(list,paraloc1);
  1756. alloccpuregisters(list,R_INTREGISTER,paramanager.get_volatile_registers_int(pocall_default));
  1757. a_call_name_static(list,'FPC_MOVE');
  1758. dealloccpuregisters(list,R_INTREGISTER,paramanager.get_volatile_registers_int(pocall_default));
  1759. paraloc3.done;
  1760. paraloc2.done;
  1761. paraloc1.done;
  1762. end;
  1763. procedure tcgavr.g_concatcopy(list : TAsmList;const source,dest : treference;len : tcgint);
  1764. var
  1765. countreg,tmpreg : tregister;
  1766. srcref,dstref : treference;
  1767. copysize,countregsize : tcgsize;
  1768. l : TAsmLabel;
  1769. i : longint;
  1770. SrcQuickRef, DestQuickRef : Boolean;
  1771. begin
  1772. if len>16 then
  1773. begin
  1774. current_asmdata.getjumplabel(l);
  1775. reference_reset(srcref,0);
  1776. reference_reset(dstref,0);
  1777. srcref.base:=NR_R30;
  1778. srcref.addressmode:=AM_POSTINCREMENT;
  1779. dstref.base:=NR_R26;
  1780. dstref.addressmode:=AM_POSTINCREMENT;
  1781. copysize:=OS_8;
  1782. if len<256 then
  1783. countregsize:=OS_8
  1784. else if len<65536 then
  1785. countregsize:=OS_16
  1786. else
  1787. internalerror(2011022007);
  1788. countreg:=getintregister(list,countregsize);
  1789. a_load_const_reg(list,countregsize,len,countreg);
  1790. a_loadaddr_ref_reg(list,source,NR_R30);
  1791. tmpreg:=getaddressregister(list);
  1792. a_loadaddr_ref_reg(list,dest,tmpreg);
  1793. { X is used for spilling code so we can load it
  1794. only by a push/pop sequence, this can be
  1795. optimized later on by the peephole optimizer
  1796. }
  1797. list.concat(taicpu.op_reg(A_PUSH,tmpreg));
  1798. list.concat(taicpu.op_reg(A_PUSH,GetNextReg(tmpreg)));
  1799. list.concat(taicpu.op_reg(A_POP,NR_R27));
  1800. list.concat(taicpu.op_reg(A_POP,NR_R26));
  1801. cg.a_label(list,l);
  1802. list.concat(taicpu.op_reg_ref(GetLoad(srcref),NR_R0,srcref));
  1803. list.concat(taicpu.op_ref_reg(GetStore(dstref),dstref,NR_R0));
  1804. list.concat(taicpu.op_reg(A_DEC,countreg));
  1805. a_jmp_flags(list,F_NE,l);
  1806. // keep registers alive
  1807. list.concat(taicpu.op_reg_reg(A_MOV,countreg,countreg));
  1808. end
  1809. else
  1810. begin
  1811. SrcQuickRef:=false;
  1812. DestQuickRef:=false;
  1813. if not((source.addressmode=AM_UNCHANGED) and
  1814. (source.symbol=nil) and
  1815. ((source.base=NR_R28) or
  1816. (source.base=NR_R30)) and
  1817. (source.Index=NR_NO) and
  1818. (source.Offset in [0..64-len])) and
  1819. not((source.Base=NR_NO) and (source.Index=NR_NO)) then
  1820. srcref:=normalize_ref(list,source,NR_R30)
  1821. else
  1822. begin
  1823. SrcQuickRef:=true;
  1824. srcref:=source;
  1825. end;
  1826. if not((dest.addressmode=AM_UNCHANGED) and
  1827. (dest.symbol=nil) and
  1828. ((dest.base=NR_R28) or
  1829. (dest.base=NR_R30)) and
  1830. (dest.Index=NR_No) and
  1831. (dest.Offset in [0..64-len])) and
  1832. not((dest.Base=NR_NO) and (dest.Index=NR_NO)) then
  1833. begin
  1834. if not(SrcQuickRef) then
  1835. begin
  1836. tmpreg:=getaddressregister(list);
  1837. dstref:=normalize_ref(list,dest,tmpreg);
  1838. { X is used for spilling code so we can load it
  1839. only by a push/pop sequence, this can be
  1840. optimized later on by the peephole optimizer
  1841. }
  1842. list.concat(taicpu.op_reg(A_PUSH,tmpreg));
  1843. list.concat(taicpu.op_reg(A_PUSH,GetNextReg(tmpreg)));
  1844. list.concat(taicpu.op_reg(A_POP,NR_R27));
  1845. list.concat(taicpu.op_reg(A_POP,NR_R26));
  1846. dstref.base:=NR_R26;
  1847. end
  1848. else
  1849. dstref:=normalize_ref(list,dest,NR_R30);
  1850. end
  1851. else
  1852. begin
  1853. DestQuickRef:=true;
  1854. dstref:=dest;
  1855. end;
  1856. for i:=1 to len do
  1857. begin
  1858. if not(SrcQuickRef) and (i<len) then
  1859. srcref.addressmode:=AM_POSTINCREMENT
  1860. else
  1861. srcref.addressmode:=AM_UNCHANGED;
  1862. if not(DestQuickRef) and (i<len) then
  1863. dstref.addressmode:=AM_POSTINCREMENT
  1864. else
  1865. dstref.addressmode:=AM_UNCHANGED;
  1866. list.concat(taicpu.op_reg_ref(GetLoad(srcref),NR_R0,srcref));
  1867. list.concat(taicpu.op_ref_reg(GetStore(dstref),dstref,NR_R0));
  1868. if SrcQuickRef then
  1869. inc(srcref.offset);
  1870. if DestQuickRef then
  1871. inc(dstref.offset);
  1872. end;
  1873. if not(SrcQuickRef) then
  1874. begin
  1875. ungetcpuregister(list,srcref.base);
  1876. ungetcpuregister(list,GetNextReg(srcref.base));
  1877. end;
  1878. end;
  1879. end;
  1880. procedure tcgavr.g_overflowCheck(list : TAsmList;const l : tlocation;def : tdef);
  1881. var
  1882. hl : tasmlabel;
  1883. ai : taicpu;
  1884. cond : TAsmCond;
  1885. begin
  1886. if not(cs_check_overflow in current_settings.localswitches) then
  1887. exit;
  1888. current_asmdata.getjumplabel(hl);
  1889. if not ((def.typ=pointerdef) or
  1890. ((def.typ=orddef) and
  1891. (torddef(def).ordtype in [u64bit,u16bit,u32bit,u8bit,uchar,
  1892. pasbool8,pasbool16,pasbool32,pasbool64]))) then
  1893. cond:=C_VC
  1894. else
  1895. cond:=C_CC;
  1896. ai:=Taicpu.Op_Sym(A_BRxx,hl);
  1897. ai.SetCondition(cond);
  1898. ai.is_jmp:=true;
  1899. list.concat(ai);
  1900. a_call_name(list,'FPC_OVERFLOW',false);
  1901. a_label(list,hl);
  1902. end;
  1903. procedure tcgavr.g_save_registers(list: TAsmList);
  1904. begin
  1905. { this is done by the entry code }
  1906. end;
  1907. procedure tcgavr.g_restore_registers(list: TAsmList);
  1908. begin
  1909. { this is done by the exit code }
  1910. end;
  1911. procedure tcgavr.a_jmp_cond(list : TAsmList;cond : TOpCmp;l: tasmlabel);
  1912. var
  1913. ai1,ai2 : taicpu;
  1914. hl : TAsmLabel;
  1915. begin
  1916. ai1:=Taicpu.Op_sym(A_BRxx,l);
  1917. ai1.is_jmp:=true;
  1918. hl:=nil;
  1919. case cond of
  1920. OC_EQ:
  1921. ai1.SetCondition(C_EQ);
  1922. OC_GT:
  1923. begin
  1924. { emulate GT }
  1925. current_asmdata.getjumplabel(hl);
  1926. ai2:=Taicpu.Op_Sym(A_BRxx,hl);
  1927. ai2.SetCondition(C_EQ);
  1928. ai2.is_jmp:=true;
  1929. list.concat(ai2);
  1930. ai1.SetCondition(C_GE);
  1931. end;
  1932. OC_LT:
  1933. ai1.SetCondition(C_LT);
  1934. OC_GTE:
  1935. ai1.SetCondition(C_GE);
  1936. OC_LTE:
  1937. begin
  1938. { emulate LTE }
  1939. ai2:=Taicpu.Op_Sym(A_BRxx,l);
  1940. ai2.SetCondition(C_EQ);
  1941. ai2.is_jmp:=true;
  1942. list.concat(ai2);
  1943. ai1.SetCondition(C_LT);
  1944. end;
  1945. OC_NE:
  1946. ai1.SetCondition(C_NE);
  1947. OC_BE:
  1948. begin
  1949. { emulate BE }
  1950. ai2:=Taicpu.Op_Sym(A_BRxx,l);
  1951. ai2.SetCondition(C_EQ);
  1952. ai2.is_jmp:=true;
  1953. list.concat(ai2);
  1954. ai1.SetCondition(C_LO);
  1955. end;
  1956. OC_B:
  1957. ai1.SetCondition(C_LO);
  1958. OC_AE:
  1959. ai1.SetCondition(C_SH);
  1960. OC_A:
  1961. begin
  1962. { emulate A (unsigned GT) }
  1963. current_asmdata.getjumplabel(hl);
  1964. ai2:=Taicpu.Op_Sym(A_BRxx,hl);
  1965. ai2.SetCondition(C_EQ);
  1966. ai2.is_jmp:=true;
  1967. list.concat(ai2);
  1968. ai1.SetCondition(C_SH);
  1969. end;
  1970. else
  1971. internalerror(2011082501);
  1972. end;
  1973. list.concat(ai1);
  1974. if assigned(hl) then
  1975. a_label(list,hl);
  1976. end;
  1977. procedure tcgavr.emit_mov(list: TAsmList;reg2: tregister; reg1: tregister);
  1978. var
  1979. instr: taicpu;
  1980. begin
  1981. instr:=taicpu.op_reg_reg(A_MOV,reg2,reg1);
  1982. list.Concat(instr);
  1983. { Notify the register allocator that we have written a move instruction so
  1984. it can try to eliminate it. }
  1985. add_move_instruction(instr);
  1986. end;
  1987. procedure tcg64favr.a_op64_reg_reg(list : TAsmList;op:TOpCG;size : tcgsize;regsrc,regdst : tregister64);
  1988. begin
  1989. if not(size in [OS_S64,OS_64]) then
  1990. internalerror(2012102402);
  1991. tcgavr(cg).a_op_reg_reg_internal(list,Op,size,regsrc.reglo,regsrc.reghi,regdst.reglo,regdst.reghi);
  1992. end;
  1993. procedure tcg64favr.a_op64_const_reg(list : TAsmList;op:TOpCG;size : tcgsize;value : int64;reg : tregister64);
  1994. begin
  1995. tcgavr(cg).a_op_const_reg_internal(list,Op,size,value,reg.reglo,reg.reghi);
  1996. end;
  1997. procedure create_codegen;
  1998. begin
  1999. cg:=tcgavr.create;
  2000. cg64:=tcg64favr.create;
  2001. end;
  2002. end.