cgcpu.pas 107 KB

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