cgcpu.pas 115 KB

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