cgcpu.pas 82 KB

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