cgcpu.pas 88 KB

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