cgcpu.pas 115 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105
  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_OR:
  904. begin
  905. for i:=1 to tcgsize2size[size] do
  906. begin
  907. if ((qword(a) and mask) shr shift)<>0 then
  908. list.concat(taicpu.op_reg_const(A_ORI,reg,(qword(a) and mask) shr shift));
  909. { check if we are not in the last iteration to avoid an internalerror in GetNextReg }
  910. if i<tcgsize2size[size] then
  911. NextRegPostInc;
  912. mask:=mask shl 8;
  913. inc(shift,8);
  914. end;
  915. end;
  916. OP_AND:
  917. begin
  918. for i:=1 to tcgsize2size[size] do
  919. begin
  920. if ((qword(a) and mask) shr shift)=0 then
  921. list.concat(taicpu.op_reg_reg(A_MOV,reg,GetDefaultZeroReg))
  922. else if ((qword(a) and mask) shr shift)<>$ff then
  923. begin
  924. getcpuregister(list,NR_R26);
  925. list.concat(taicpu.op_reg_const(A_LDI,NR_R26,(qword(a) and mask) shr shift));
  926. list.concat(taicpu.op_reg_reg(A_AND,reg,NR_R26));
  927. ungetcpuregister(list,NR_R26);
  928. end;
  929. { check if we are not in the last iteration to avoid an internalerror in GetNextReg }
  930. if i<tcgsize2size[size] then
  931. NextRegPostInc;
  932. mask:=mask shl 8;
  933. inc(shift,8);
  934. end;
  935. end;
  936. OP_SUB:
  937. begin
  938. if ((a and mask)=1) and (tcgsize2size[size]=1) then
  939. list.concat(taicpu.op_reg(A_DEC,reg))
  940. else
  941. begin
  942. getcpuregister(list,NR_R26);
  943. list.concat(taicpu.op_reg_const(A_LDI,NR_R26,a and mask));
  944. list.concat(taicpu.op_reg_reg(A_SUB,reg,NR_R26));
  945. ungetcpuregister(list,NR_R26);
  946. end;
  947. if size in [OS_S16,OS_16,OS_S32,OS_32,OS_S64,OS_64] then
  948. begin
  949. for i:=2 to tcgsize2size[size] do
  950. begin
  951. NextRegPreInc;
  952. mask:=mask shl 8;
  953. inc(shift,8);
  954. curvalue:=(qword(a) and mask) shr shift;
  955. { decrease pressure on upper half of registers by using SBC ...,R1 instead
  956. of SBCI ...,0 }
  957. if curvalue=0 then
  958. list.concat(taicpu.op_reg_reg(A_SBC,reg,GetDefaultZeroReg))
  959. else
  960. list.concat(taicpu.op_reg_const(A_SBCI,reg,curvalue));
  961. end;
  962. end;
  963. end;
  964. OP_SHR,OP_SHL,OP_SAR,OP_ROL,OP_ROR:
  965. begin
  966. if (op=OP_SAR) and (a>=(tcgsize2size[size]*8-1)) then
  967. begin
  968. current_asmdata.getjumplabel(l1);
  969. cg.a_reg_alloc(list,NR_DEFAULTFLAGS);
  970. list.concat(taicpu.op_reg(A_TST,GetOffsetReg64(reg,reghi,tcgsize2size[size]-1)));
  971. a_load_const_reg(list,OS_8,0,GetOffsetReg64(reg,reghi,tcgsize2size[size]-1));
  972. a_jmp_flags(list,F_PL,l1);
  973. list.concat(taicpu.op_reg(A_DEC,GetOffsetReg64(reg,reghi,tcgsize2size[size]-1)));
  974. cg.a_label(list,l1);
  975. for i:=2 to tcgsize2size[size] do
  976. a_load_reg_reg(list,OS_8,OS_8,GetOffsetReg64(reg,reghi,tcgsize2size[size]-1),GetOffsetReg64(reg,reghi,tcgsize2size[size]-i));
  977. end
  978. else if (op=OP_SHR) and (a=(tcgsize2size[size]*8-1)) then
  979. begin
  980. current_asmdata.getjumplabel(l1);
  981. cg.a_reg_alloc(list,NR_DEFAULTFLAGS);
  982. list.concat(taicpu.op_reg(A_TST,GetOffsetReg64(reg,reghi,tcgsize2size[size]-1)));
  983. a_load_const_reg(list,OS_8,0,GetOffsetReg64(reg,reghi,0));
  984. a_jmp_flags(list,F_PL,l1);
  985. list.concat(taicpu.op_reg(A_INC,GetOffsetReg64(reg,reghi,0)));
  986. cg.a_label(list,l1);
  987. for i:=1 to tcgsize2size[size]-1 do
  988. a_load_const_reg(list,OS_8,0,GetOffsetReg64(reg,reghi,i));
  989. end
  990. else if a*tcgsize2size[size]<=8 then
  991. begin
  992. for j:=1 to a do
  993. begin
  994. case op of
  995. OP_SHR:
  996. list.concat(taicpu.op_reg(A_LSR,GetOffsetReg64(reg,reghi,tcgsize2size[size]-1)));
  997. OP_SHL:
  998. list.concat(taicpu.op_reg(A_LSL,reg));
  999. OP_SAR:
  1000. list.concat(taicpu.op_reg(A_ASR,GetOffsetReg64(reg,reghi,tcgsize2size[size]-1)));
  1001. OP_ROR:
  1002. begin
  1003. { load carry? }
  1004. if not(size in [OS_8,OS_S8]) then
  1005. begin
  1006. list.concat(taicpu.op_none(A_CLC));
  1007. list.concat(taicpu.op_reg_const(A_SBRC,reg,0));
  1008. list.concat(taicpu.op_none(A_SEC));
  1009. end;
  1010. list.concat(taicpu.op_reg(A_ROR,GetOffsetReg64(reg,reghi,tcgsize2size[size]-1)));
  1011. end;
  1012. OP_ROL:
  1013. begin
  1014. { load carry? }
  1015. if not(size in [OS_8,OS_S8]) then
  1016. begin
  1017. list.concat(taicpu.op_none(A_CLC));
  1018. list.concat(taicpu.op_reg_const(A_SBRC,GetOffsetReg64(reg,reghi,tcgsize2size[size]-1),7));
  1019. list.concat(taicpu.op_none(A_SEC));
  1020. end;
  1021. list.concat(taicpu.op_reg(A_ROL,reg))
  1022. end;
  1023. else
  1024. internalerror(2011030903);
  1025. end;
  1026. if size in [OS_S16,OS_16,OS_S32,OS_32,OS_S64,OS_64] then
  1027. begin
  1028. for i:=2 to tcgsize2size[size] do
  1029. begin
  1030. case op of
  1031. OP_ROR,
  1032. OP_SHR:
  1033. list.concat(taicpu.op_reg(A_ROR,GetOffsetReg64(reg,reghi,tcgsize2size[size]-i)));
  1034. OP_ROL,
  1035. OP_SHL:
  1036. list.concat(taicpu.op_reg(A_ROL,GetOffsetReg64(reg,reghi,i-1)));
  1037. OP_SAR:
  1038. list.concat(taicpu.op_reg(A_ROR,GetOffsetReg64(reg,reghi,tcgsize2size[size]-i)));
  1039. else
  1040. internalerror(2011030904);
  1041. end;
  1042. end;
  1043. end;
  1044. end;
  1045. end
  1046. else
  1047. begin
  1048. tmpreg:=getintregister(list,size);
  1049. a_load_const_reg(list,size,a,tmpreg);
  1050. a_op_reg_reg(list,op,size,tmpreg,reg);
  1051. end;
  1052. end;
  1053. OP_ADD:
  1054. begin
  1055. curvalue:=a and mask;
  1056. if tcgsize2size[size]>1 then
  1057. cg.a_reg_alloc(list, NR_DEFAULTFLAGS);
  1058. if curvalue=0 then
  1059. list.concat(taicpu.op_reg_reg(A_ADD,reg,GetDefaultZeroReg))
  1060. else if (curvalue=1) and (tcgsize2size[size]=1) then
  1061. list.concat(taicpu.op_reg(A_INC,reg))
  1062. else
  1063. begin
  1064. tmpreg:=getintregister(list,OS_8);
  1065. a_load_const_reg(list,OS_8,curvalue,tmpreg);
  1066. list.concat(taicpu.op_reg_reg(A_ADD,reg,tmpreg));
  1067. end;
  1068. if size in [OS_S16,OS_16,OS_S32,OS_32,OS_S64,OS_64] then
  1069. begin
  1070. for i:=2 to tcgsize2size[size] do
  1071. begin
  1072. NextRegPreInc;
  1073. mask:=mask shl 8;
  1074. inc(shift,8);
  1075. curvalue:=(qword(a) and mask) shr shift;
  1076. { decrease pressure on upper half of registers by using ADC ...,R1 instead
  1077. of ADD ...,0 }
  1078. if curvalue=0 then
  1079. list.concat(taicpu.op_reg_reg(A_ADC,reg,GetDefaultZeroReg))
  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_ADC,reg,tmpreg));
  1085. end;
  1086. end;
  1087. end;
  1088. if tcgsize2size[size]>1 then
  1089. cg.a_reg_dealloc(list, NR_DEFAULTFLAGS);
  1090. end;
  1091. else
  1092. begin
  1093. if size in [OS_64,OS_S64] then
  1094. begin
  1095. tmpreg64.reglo:=getintregister(list,OS_32);
  1096. tmpreg64.reghi:=getintregister(list,OS_32);
  1097. cg64.a_load64_const_reg(list,a,tmpreg64);
  1098. cg64.a_op64_reg_reg(list,op,size,tmpreg64,joinreg64(reg,reghi));
  1099. end
  1100. else
  1101. begin
  1102. {$if 0}
  1103. { code not working yet }
  1104. if (op=OP_SAR) and (a=31) and (size in [OS_32,OS_S32]) then
  1105. begin
  1106. tmpreg:=reg;
  1107. for i:=1 to 4 do
  1108. begin
  1109. list.concat(taicpu.op_reg_reg(A_MOV,tmpreg,GetDefaultZeroReg));
  1110. tmpreg:=GetNextReg(tmpreg);
  1111. end;
  1112. end
  1113. else
  1114. {$endif}
  1115. begin
  1116. tmpreg:=getintregister(list,size);
  1117. a_load_const_reg(list,size,a,tmpreg);
  1118. a_op_reg_reg(list,op,size,tmpreg,reg);
  1119. end;
  1120. end;
  1121. end;
  1122. end;
  1123. end;
  1124. procedure tcgavr.a_load_const_reg(list : TAsmList; size: tcgsize; a : tcgint;reg : tregister);
  1125. var
  1126. mask : qword;
  1127. shift : byte;
  1128. i : byte;
  1129. begin
  1130. mask:=$ff;
  1131. shift:=0;
  1132. for i:=1 to tcgsize2size[size] do
  1133. begin
  1134. if ((qword(a) and mask) shr shift)=0 then
  1135. emit_mov(list,reg,GetDefaultZeroReg)
  1136. else
  1137. begin
  1138. getcpuregister(list,NR_R26);
  1139. list.concat(taicpu.op_reg_const(A_LDI,NR_R26,(qword(a) and mask) shr shift));
  1140. a_load_reg_reg(list,OS_8,OS_8,NR_R26,reg);
  1141. ungetcpuregister(list,NR_R26);
  1142. end;
  1143. mask:=mask shl 8;
  1144. inc(shift,8);
  1145. { check if we are not in the last iteration to avoid an internalerror in GetNextReg }
  1146. if i<tcgsize2size[size] then
  1147. reg:=GetNextReg(reg);
  1148. end;
  1149. end;
  1150. procedure tcgavr.maybegetcpuregister(list:tasmlist;reg : tregister);
  1151. begin
  1152. { allocate the register only, if a cpu register is passed }
  1153. if getsupreg(reg)<first_int_imreg then
  1154. getcpuregister(list,reg);
  1155. end;
  1156. { Returns true if dataspace address falls in I/O register range }
  1157. function tcgavr.addr_is_io_register(const addr: integer): boolean;
  1158. begin
  1159. result := (not(current_settings.cputype in [cpu_avrxmega3,cpu_avrtiny]) and (addr>31)) or
  1160. ((current_settings.cputype in [cpu_avrxmega3,cpu_avrtiny]) and (addr>=0)) and
  1161. (addr<cpuinfo.embedded_controllers[current_settings.controllertype].srambase);
  1162. end;
  1163. function tcgavr.normalize_ref(list:TAsmList;ref: treference;tmpreg : tregister) : treference;
  1164. var
  1165. tmpref : treference;
  1166. begin
  1167. Result:=ref;
  1168. if ref.addressmode<>AM_UNCHANGED then
  1169. internalerror(2011021705);
  1170. { Be sure to have a base register }
  1171. if (ref.base=NR_NO) then
  1172. begin
  1173. ref.base:=ref.index;
  1174. ref.index:=NR_NO;
  1175. end;
  1176. { can we take advantage of adiw/sbiw? }
  1177. 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
  1178. ((tmpreg=NR_R24) or (tmpreg=NR_R26) or (tmpreg=NR_R28) or (tmpreg=NR_R30)) and (ref.base<>NR_NO) then
  1179. begin
  1180. maybegetcpuregister(list,tmpreg);
  1181. emit_mov(list,tmpreg,ref.base);
  1182. maybegetcpuregister(list,GetNextReg(tmpreg));
  1183. emit_mov(list,GetNextReg(tmpreg),GetNextReg(ref.base));
  1184. if ref.index<>NR_NO then
  1185. begin
  1186. cg.a_reg_alloc(list, NR_DEFAULTFLAGS);
  1187. list.concat(taicpu.op_reg_reg(A_ADD,tmpreg,ref.index));
  1188. list.concat(taicpu.op_reg_reg(A_ADC,GetNextReg(tmpreg),GetNextReg(ref.index)));
  1189. cg.a_reg_dealloc(list, NR_DEFAULTFLAGS);
  1190. end;
  1191. if ref.offset>0 then
  1192. list.concat(taicpu.op_reg_const(A_ADIW,tmpreg,ref.offset))
  1193. else
  1194. list.concat(taicpu.op_reg_const(A_SBIW,tmpreg,-ref.offset));
  1195. ref.offset:=0;
  1196. ref.base:=tmpreg;
  1197. ref.index:=NR_NO;
  1198. end
  1199. else if assigned(ref.symbol) or (ref.offset<>0) then
  1200. begin
  1201. reference_reset(tmpref,0,[]);
  1202. tmpref.symbol:=ref.symbol;
  1203. tmpref.offset:=ref.offset;
  1204. if assigned(ref.symbol) and (ref.symbol.typ in [AT_FUNCTION,AT_LABEL]) then
  1205. tmpref.refaddr:=addr_lo8_gs
  1206. else
  1207. tmpref.refaddr:=addr_lo8;
  1208. maybegetcpuregister(list,tmpreg);
  1209. list.concat(taicpu.op_reg_ref(A_LDI,tmpreg,tmpref));
  1210. if assigned(ref.symbol) and (ref.symbol.typ in [AT_FUNCTION,AT_LABEL]) then
  1211. tmpref.refaddr:=addr_hi8_gs
  1212. else
  1213. tmpref.refaddr:=addr_hi8;
  1214. maybegetcpuregister(list,GetNextReg(tmpreg));
  1215. list.concat(taicpu.op_reg_ref(A_LDI,GetNextReg(tmpreg),tmpref));
  1216. if (ref.base<>NR_NO) then
  1217. begin
  1218. cg.a_reg_alloc(list, NR_DEFAULTFLAGS);
  1219. list.concat(taicpu.op_reg_reg(A_ADD,tmpreg,ref.base));
  1220. list.concat(taicpu.op_reg_reg(A_ADC,GetNextReg(tmpreg),GetNextReg(ref.base)));
  1221. cg.a_reg_dealloc(list, NR_DEFAULTFLAGS);
  1222. end;
  1223. if (ref.index<>NR_NO) then
  1224. begin
  1225. cg.a_reg_alloc(list, NR_DEFAULTFLAGS);
  1226. list.concat(taicpu.op_reg_reg(A_ADD,tmpreg,ref.index));
  1227. list.concat(taicpu.op_reg_reg(A_ADC,GetNextReg(tmpreg),GetNextReg(ref.index)));
  1228. cg.a_reg_dealloc(list, NR_DEFAULTFLAGS);
  1229. end;
  1230. ref.symbol:=nil;
  1231. ref.offset:=0;
  1232. ref.base:=tmpreg;
  1233. ref.index:=NR_NO;
  1234. end
  1235. else if (ref.base<>NR_NO) and (ref.index<>NR_NO) then
  1236. begin
  1237. maybegetcpuregister(list,tmpreg);
  1238. emit_mov(list,tmpreg,ref.base);
  1239. maybegetcpuregister(list,GetNextReg(tmpreg));
  1240. emit_mov(list,GetNextReg(tmpreg),GetNextReg(ref.base));
  1241. cg.a_reg_alloc(list, NR_DEFAULTFLAGS);
  1242. list.concat(taicpu.op_reg_reg(A_ADD,tmpreg,ref.index));
  1243. list.concat(taicpu.op_reg_reg(A_ADC,GetNextReg(tmpreg),GetNextReg(ref.index)));
  1244. cg.a_reg_dealloc(list, NR_DEFAULTFLAGS);
  1245. ref.base:=tmpreg;
  1246. ref.index:=NR_NO;
  1247. end
  1248. else if (ref.base<>NR_NO) then
  1249. begin
  1250. maybegetcpuregister(list,tmpreg);
  1251. emit_mov(list,tmpreg,ref.base);
  1252. maybegetcpuregister(list,GetNextReg(tmpreg));
  1253. emit_mov(list,GetNextReg(tmpreg),GetNextReg(ref.base));
  1254. ref.base:=tmpreg;
  1255. ref.index:=NR_NO;
  1256. end
  1257. else if (ref.index<>NR_NO) then
  1258. begin
  1259. maybegetcpuregister(list,tmpreg);
  1260. emit_mov(list,tmpreg,ref.index);
  1261. maybegetcpuregister(list,GetNextReg(tmpreg));
  1262. emit_mov(list,GetNextReg(tmpreg),GetNextReg(ref.index));
  1263. ref.base:=tmpreg;
  1264. ref.index:=NR_NO;
  1265. end
  1266. else
  1267. Internalerror(2020011901);
  1268. Result:=ref;
  1269. end;
  1270. procedure tcgavr.a_load_reg_ref(list : TAsmList; fromsize, tosize: tcgsize; reg : tregister;const ref : treference);
  1271. var
  1272. href : treference;
  1273. conv_done: boolean;
  1274. tmpreg : tregister;
  1275. i : integer;
  1276. QuickRef,ungetcpuregister_z: Boolean;
  1277. begin
  1278. QuickRef:=false;
  1279. ungetcpuregister_z:=false;
  1280. href:=Ref;
  1281. { ensure, href.base contains a valid register if there is any register used }
  1282. if href.base=NR_NO then
  1283. begin
  1284. href.base:=href.index;
  1285. href.index:=NR_NO;
  1286. end;
  1287. { try to use std/sts }
  1288. if not((href.Base=NR_NO) and (href.Index=NR_NO)) then
  1289. begin
  1290. if not((href.addressmode=AM_UNCHANGED) and
  1291. (href.symbol=nil) and
  1292. (href.Index=NR_NO) and
  1293. (href.Offset in [0..64-tcgsize2size[fromsize]])) or
  1294. (CPUAVR_16_REGS in cpu_capabilities[current_settings.cputype]) then
  1295. begin
  1296. href:=normalize_ref(list,href,NR_R30);
  1297. getcpuregister(list,NR_R30);
  1298. getcpuregister(list,NR_R31);
  1299. ungetcpuregister_z:=true;
  1300. end
  1301. else
  1302. begin
  1303. if (href.base<>NR_R28) and (href.base<>NR_R30) then
  1304. begin
  1305. getcpuregister(list,NR_R30);
  1306. emit_mov(list,NR_R30,href.base);
  1307. getcpuregister(list,NR_R31);
  1308. emit_mov(list,NR_R31,GetNextReg(href.base));
  1309. href.base:=NR_R30;
  1310. ungetcpuregister_z:=true;
  1311. end;
  1312. QuickRef:=true;
  1313. end;
  1314. end
  1315. else
  1316. QuickRef:=true;
  1317. if (tcgsize2size[fromsize]>32) or (tcgsize2size[tosize]>32) or (fromsize=OS_NO) or (tosize=OS_NO) then
  1318. internalerror(2011021303);
  1319. conv_done:=false;
  1320. if tosize<>fromsize then
  1321. begin
  1322. conv_done:=true;
  1323. if tcgsize2size[tosize]<=tcgsize2size[fromsize] then
  1324. fromsize:=tosize;
  1325. case fromsize of
  1326. OS_8:
  1327. begin
  1328. if not(QuickRef) and (tcgsize2size[tosize]>1) then
  1329. href.addressmode:=AM_POSTINCREMENT;
  1330. list.concat(taicpu.op_ref_reg(GetStore(href),href,reg));
  1331. for i:=2 to tcgsize2size[tosize] do
  1332. begin
  1333. if QuickRef then
  1334. inc(href.offset);
  1335. if not(QuickRef) and (i<tcgsize2size[fromsize]) then
  1336. href.addressmode:=AM_POSTINCREMENT
  1337. else
  1338. href.addressmode:=AM_UNCHANGED;
  1339. list.concat(taicpu.op_ref_reg(GetStore(href),href,GetDefaultZeroReg));
  1340. end;
  1341. end;
  1342. OS_S8:
  1343. begin
  1344. if not(QuickRef) and (tcgsize2size[tosize]>1) then
  1345. href.addressmode:=AM_POSTINCREMENT;
  1346. list.concat(taicpu.op_ref_reg(GetStore(href),href,reg));
  1347. if tcgsize2size[tosize]>1 then
  1348. begin
  1349. tmpreg:=getintregister(list,OS_8);
  1350. emit_mov(list,tmpreg,GetDefaultZeroReg);
  1351. list.concat(taicpu.op_reg_const(A_SBRC,reg,7));
  1352. list.concat(taicpu.op_reg(A_COM,tmpreg));
  1353. for i:=2 to tcgsize2size[tosize] do
  1354. begin
  1355. if QuickRef then
  1356. inc(href.offset);
  1357. if not(QuickRef) and (i<tcgsize2size[fromsize]) then
  1358. href.addressmode:=AM_POSTINCREMENT
  1359. else
  1360. href.addressmode:=AM_UNCHANGED;
  1361. list.concat(taicpu.op_ref_reg(GetStore(href),href,tmpreg));
  1362. end;
  1363. end;
  1364. end;
  1365. OS_16:
  1366. begin
  1367. if not(QuickRef) and (tcgsize2size[tosize]>1) then
  1368. href.addressmode:=AM_POSTINCREMENT;
  1369. list.concat(taicpu.op_ref_reg(GetStore(href),href,reg));
  1370. if QuickRef then
  1371. inc(href.offset)
  1372. else if not(QuickRef) and (tcgsize2size[fromsize]>2) then
  1373. href.addressmode:=AM_POSTINCREMENT
  1374. else
  1375. href.addressmode:=AM_UNCHANGED;
  1376. reg:=GetNextReg(reg);
  1377. list.concat(taicpu.op_ref_reg(GetStore(href),href,reg));
  1378. for i:=3 to tcgsize2size[tosize] do
  1379. begin
  1380. if QuickRef then
  1381. inc(href.offset);
  1382. if not(QuickRef) and (i<tcgsize2size[fromsize]) then
  1383. href.addressmode:=AM_POSTINCREMENT
  1384. else
  1385. href.addressmode:=AM_UNCHANGED;
  1386. list.concat(taicpu.op_ref_reg(GetStore(href),href,GetDefaultZeroReg));
  1387. end;
  1388. end;
  1389. OS_S16:
  1390. begin
  1391. if not(QuickRef) and (tcgsize2size[tosize]>1) then
  1392. href.addressmode:=AM_POSTINCREMENT;
  1393. list.concat(taicpu.op_ref_reg(GetStore(href),href,reg));
  1394. if QuickRef then
  1395. inc(href.offset)
  1396. else if not(QuickRef) and (tcgsize2size[fromsize]>2) then
  1397. href.addressmode:=AM_POSTINCREMENT
  1398. else
  1399. href.addressmode:=AM_UNCHANGED;
  1400. reg:=GetNextReg(reg);
  1401. list.concat(taicpu.op_ref_reg(GetStore(href),href,reg));
  1402. if tcgsize2size[tosize]>2 then
  1403. begin
  1404. tmpreg:=getintregister(list,OS_8);
  1405. emit_mov(list,tmpreg,GetDefaultZeroReg);
  1406. list.concat(taicpu.op_reg_const(A_SBRC,reg,7));
  1407. list.concat(taicpu.op_reg(A_COM,tmpreg));
  1408. for i:=3 to tcgsize2size[tosize] do
  1409. begin
  1410. if QuickRef then
  1411. inc(href.offset);
  1412. if not(QuickRef) and (i<tcgsize2size[fromsize]) then
  1413. href.addressmode:=AM_POSTINCREMENT
  1414. else
  1415. href.addressmode:=AM_UNCHANGED;
  1416. list.concat(taicpu.op_ref_reg(GetStore(href),href,tmpreg));
  1417. end;
  1418. end;
  1419. end;
  1420. else
  1421. conv_done:=false;
  1422. end;
  1423. end;
  1424. if not conv_done then
  1425. begin
  1426. { Write to 16 bit ioreg, first high byte then low byte
  1427. sequence required for 16 bit timer registers
  1428. See e.g. atmega328p manual para 15.3 Accessing 16 bit registers
  1429. Avrxmega3: write low byte first then high byte
  1430. See e.g. megaAVR-0 family data sheet 7.5.6 Accessing 16-bit registers }
  1431. if (current_settings.cputype <> cpu_avrxmega3) and
  1432. (fromsize in [OS_16, OS_S16]) and QuickRef and addr_is_io_register(href.offset) then
  1433. begin
  1434. tmpreg:=GetNextReg(reg);
  1435. href.addressmode:=AM_UNCHANGED;
  1436. inc(href.offset);
  1437. list.concat(taicpu.op_ref_reg(GetStore(href),href,tmpreg));
  1438. dec(href.offset);
  1439. list.concat(taicpu.op_ref_reg(GetStore(href),href,reg));
  1440. end
  1441. else
  1442. begin
  1443. for i:=1 to tcgsize2size[fromsize] do
  1444. begin
  1445. if not(QuickRef) and (i<tcgsize2size[fromsize]) then
  1446. href.addressmode:=AM_POSTINCREMENT
  1447. else
  1448. href.addressmode:=AM_UNCHANGED;
  1449. list.concat(taicpu.op_ref_reg(GetStore(href),href,reg));
  1450. if QuickRef then
  1451. inc(href.offset);
  1452. { check if we are not in the last iteration to avoid an internalerror in GetNextReg }
  1453. if i<tcgsize2size[fromsize] then
  1454. reg:=GetNextReg(reg);
  1455. end;
  1456. end;
  1457. end;
  1458. if not(QuickRef) or ungetcpuregister_z then
  1459. begin
  1460. ungetcpuregister(list,href.base);
  1461. ungetcpuregister(list,GetNextReg(href.base));
  1462. end;
  1463. end;
  1464. procedure tcgavr.a_load_ref_reg(list : TAsmList; fromsize, tosize : tcgsize;
  1465. const Ref : treference;reg : tregister);
  1466. var
  1467. href : treference;
  1468. conv_done: boolean;
  1469. tmpreg : tregister;
  1470. i : integer;
  1471. QuickRef,ungetcpuregister_z: boolean;
  1472. begin
  1473. QuickRef:=false;
  1474. ungetcpuregister_z:=false;
  1475. href:=Ref;
  1476. { ensure, href.base contains a valid register if there is any register used }
  1477. if href.base=NR_NO then
  1478. begin
  1479. href.base:=href.index;
  1480. href.index:=NR_NO;
  1481. end;
  1482. { try to use ldd/lds }
  1483. if not((href.Base=NR_NO) and (href.Index=NR_NO)) then
  1484. begin
  1485. if not((href.addressmode=AM_UNCHANGED) and
  1486. (href.symbol=nil) and
  1487. (href.Index=NR_NO) and
  1488. (href.Offset in [0..64-tcgsize2size[fromsize]])) or
  1489. (CPUAVR_16_REGS in cpu_capabilities[current_settings.cputype]) then
  1490. begin
  1491. href:=normalize_ref(list,href,NR_R30);
  1492. getcpuregister(list,NR_R30);
  1493. getcpuregister(list,NR_R31);
  1494. ungetcpuregister_z:=true;
  1495. end
  1496. else
  1497. begin
  1498. if (href.base<>NR_R28) and (href.base<>NR_R30) then
  1499. begin
  1500. getcpuregister(list,NR_R30);
  1501. emit_mov(list,NR_R30,href.base);
  1502. getcpuregister(list,NR_R31);
  1503. emit_mov(list,NR_R31,GetNextReg(href.base));
  1504. href.base:=NR_R30;
  1505. ungetcpuregister_z:=true;
  1506. end;
  1507. QuickRef:=true;
  1508. end;
  1509. end
  1510. else
  1511. QuickRef:=true;
  1512. if (tcgsize2size[fromsize]>32) or (tcgsize2size[tosize]>32) or (fromsize=OS_NO) or (tosize=OS_NO) then
  1513. internalerror(2011021304);
  1514. conv_done:=false;
  1515. if tosize<>fromsize then
  1516. begin
  1517. conv_done:=true;
  1518. if tcgsize2size[tosize]<=tcgsize2size[fromsize] then
  1519. fromsize:=tosize;
  1520. case fromsize of
  1521. OS_8:
  1522. begin
  1523. list.concat(taicpu.op_reg_ref(GetLoad(href),reg,href));
  1524. for i:=2 to tcgsize2size[tosize] do
  1525. begin
  1526. reg:=GetNextReg(reg);
  1527. emit_mov(list,reg,GetDefaultZeroReg);
  1528. end;
  1529. end;
  1530. OS_S8:
  1531. begin
  1532. list.concat(taicpu.op_reg_ref(GetLoad(href),reg,href));
  1533. tmpreg:=reg;
  1534. if tcgsize2size[tosize]>1 then
  1535. begin
  1536. reg:=GetNextReg(reg);
  1537. emit_mov(list,reg,GetDefaultZeroReg);
  1538. list.concat(taicpu.op_reg_const(A_SBRC,tmpreg,7));
  1539. list.concat(taicpu.op_reg(A_COM,reg));
  1540. tmpreg:=reg;
  1541. for i:=3 to tcgsize2size[tosize] do
  1542. begin
  1543. reg:=GetNextReg(reg);
  1544. emit_mov(list,reg,tmpreg);
  1545. end;
  1546. end;
  1547. end;
  1548. OS_16:
  1549. begin
  1550. if not(QuickRef) then
  1551. href.addressmode:=AM_POSTINCREMENT;
  1552. list.concat(taicpu.op_reg_ref(GetLoad(href),reg,href));
  1553. if QuickRef then
  1554. inc(href.offset);
  1555. href.addressmode:=AM_UNCHANGED;
  1556. reg:=GetNextReg(reg);
  1557. list.concat(taicpu.op_reg_ref(GetLoad(href),reg,href));
  1558. for i:=3 to tcgsize2size[tosize] do
  1559. begin
  1560. reg:=GetNextReg(reg);
  1561. emit_mov(list,reg,GetDefaultZeroReg);
  1562. end;
  1563. end;
  1564. OS_S16:
  1565. begin
  1566. if not(QuickRef) then
  1567. href.addressmode:=AM_POSTINCREMENT;
  1568. list.concat(taicpu.op_reg_ref(GetLoad(href),reg,href));
  1569. if QuickRef then
  1570. inc(href.offset);
  1571. href.addressmode:=AM_UNCHANGED;
  1572. reg:=GetNextReg(reg);
  1573. list.concat(taicpu.op_reg_ref(GetLoad(href),reg,href));
  1574. tmpreg:=reg;
  1575. reg:=GetNextReg(reg);
  1576. emit_mov(list,reg,GetDefaultZeroReg);
  1577. list.concat(taicpu.op_reg_const(A_SBRC,tmpreg,7));
  1578. list.concat(taicpu.op_reg(A_COM,reg));
  1579. tmpreg:=reg;
  1580. for i:=4 to tcgsize2size[tosize] do
  1581. begin
  1582. reg:=GetNextReg(reg);
  1583. emit_mov(list,reg,tmpreg);
  1584. end;
  1585. end;
  1586. else
  1587. conv_done:=false;
  1588. end;
  1589. end;
  1590. if not conv_done then
  1591. begin
  1592. for i:=1 to tcgsize2size[fromsize] do
  1593. begin
  1594. if not(QuickRef) and (i<tcgsize2size[fromsize]) then
  1595. href.addressmode:=AM_POSTINCREMENT
  1596. else
  1597. href.addressmode:=AM_UNCHANGED;
  1598. list.concat(taicpu.op_reg_ref(GetLoad(href),reg,href));
  1599. if QuickRef then
  1600. inc(href.offset);
  1601. { check if we are not in the last iteration to avoid an internalerror in GetNextReg }
  1602. if i<tcgsize2size[fromsize] then
  1603. reg:=GetNextReg(reg);
  1604. end;
  1605. end;
  1606. if ungetcpuregister_z then
  1607. begin
  1608. ungetcpuregister(list,href.base);
  1609. ungetcpuregister(list,GetNextReg(href.base));
  1610. end;
  1611. end;
  1612. procedure tcgavr.a_load_reg_reg(list : TAsmList; fromsize, tosize : tcgsize;reg1,reg2 : tregister);
  1613. var
  1614. conv_done: boolean;
  1615. tmpreg : tregister;
  1616. i : integer;
  1617. begin
  1618. if (tcgsize2size[fromsize]>32) or (tcgsize2size[tosize]>32) or (fromsize=OS_NO) or (tosize=OS_NO) then
  1619. internalerror(2011021310);
  1620. conv_done:=false;
  1621. if tosize<>fromsize then
  1622. begin
  1623. conv_done:=true;
  1624. if tcgsize2size[tosize]<=tcgsize2size[fromsize] then
  1625. fromsize:=tosize;
  1626. case fromsize of
  1627. OS_8:
  1628. begin
  1629. emit_mov(list,reg2,reg1);
  1630. for i:=2 to tcgsize2size[tosize] do
  1631. begin
  1632. reg2:=GetNextReg(reg2);
  1633. emit_mov(list,reg2,GetDefaultZeroReg);
  1634. end;
  1635. end;
  1636. OS_S8:
  1637. begin
  1638. emit_mov(list,reg2,reg1);
  1639. if tcgsize2size[tosize]>1 then
  1640. begin
  1641. reg2:=GetNextReg(reg2);
  1642. emit_mov(list,reg2,GetDefaultZeroReg);
  1643. list.concat(taicpu.op_reg_const(A_SBRC,reg1,7));
  1644. list.concat(taicpu.op_reg(A_COM,reg2));
  1645. tmpreg:=reg2;
  1646. for i:=3 to tcgsize2size[tosize] do
  1647. begin
  1648. reg2:=GetNextReg(reg2);
  1649. emit_mov(list,reg2,tmpreg);
  1650. end;
  1651. end;
  1652. end;
  1653. OS_16:
  1654. begin
  1655. emit_mov(list,reg2,reg1);
  1656. reg1:=GetNextReg(reg1);
  1657. reg2:=GetNextReg(reg2);
  1658. emit_mov(list,reg2,reg1);
  1659. for i:=3 to tcgsize2size[tosize] do
  1660. begin
  1661. reg2:=GetNextReg(reg2);
  1662. emit_mov(list,reg2,GetDefaultZeroReg);
  1663. end;
  1664. end;
  1665. OS_S16:
  1666. begin
  1667. emit_mov(list,reg2,reg1);
  1668. reg1:=GetNextReg(reg1);
  1669. reg2:=GetNextReg(reg2);
  1670. emit_mov(list,reg2,reg1);
  1671. if tcgsize2size[tosize]>2 then
  1672. begin
  1673. reg2:=GetNextReg(reg2);
  1674. emit_mov(list,reg2,GetDefaultZeroReg);
  1675. list.concat(taicpu.op_reg_const(A_SBRC,reg1,7));
  1676. list.concat(taicpu.op_reg(A_COM,reg2));
  1677. tmpreg:=reg2;
  1678. for i:=4 to tcgsize2size[tosize] do
  1679. begin
  1680. reg2:=GetNextReg(reg2);
  1681. emit_mov(list,reg2,tmpreg);
  1682. end;
  1683. end;
  1684. end;
  1685. else
  1686. conv_done:=false;
  1687. end;
  1688. end;
  1689. if not conv_done and (reg1<>reg2) then
  1690. begin
  1691. for i:=1 to tcgsize2size[fromsize] do
  1692. begin
  1693. emit_mov(list,reg2,reg1);
  1694. { check if we are not in the last iteration to avoid an internalerror in GetNextReg }
  1695. if i<tcgsize2size[fromsize] then
  1696. begin
  1697. reg1:=GetNextReg(reg1);
  1698. reg2:=GetNextReg(reg2);
  1699. end;
  1700. end;
  1701. end;
  1702. end;
  1703. procedure tcgavr.a_loadfpu_reg_reg(list: TAsmList; fromsize,tosize: tcgsize; reg1, reg2: tregister);
  1704. begin
  1705. internalerror(2012010702);
  1706. end;
  1707. procedure tcgavr.a_loadfpu_ref_reg(list: TAsmList; fromsize,tosize: tcgsize; const ref: treference; reg: tregister);
  1708. begin
  1709. internalerror(2012010703);
  1710. end;
  1711. procedure tcgavr.a_loadfpu_reg_ref(list: TAsmList; fromsize, tosize: tcgsize; reg: tregister; const ref: treference);
  1712. begin
  1713. internalerror(2012010704);
  1714. end;
  1715. { comparison operations }
  1716. procedure tcgavr.a_cmp_const_reg_label(list : TAsmList;size : tcgsize;
  1717. cmp_op : topcmp;a : tcgint;reg : tregister;l : tasmlabel);
  1718. var
  1719. swapped : boolean;
  1720. i : byte;
  1721. begin
  1722. if a=0 then
  1723. begin
  1724. swapped:=false;
  1725. { swap parameters? }
  1726. case cmp_op of
  1727. OC_GT:
  1728. begin
  1729. swapped:=true;
  1730. cmp_op:=OC_LT;
  1731. end;
  1732. OC_LTE:
  1733. begin
  1734. swapped:=true;
  1735. cmp_op:=OC_GTE;
  1736. end;
  1737. OC_BE:
  1738. begin
  1739. swapped:=true;
  1740. cmp_op:=OC_AE;
  1741. end;
  1742. OC_A:
  1743. begin
  1744. swapped:=true;
  1745. cmp_op:=OC_B;
  1746. end;
  1747. end;
  1748. cg.a_reg_alloc(list,NR_DEFAULTFLAGS);
  1749. { If doing a signed test for x<0, we can simply test the sign bit
  1750. of the most significant byte }
  1751. if (cmp_op in [OC_LT,OC_GTE]) and
  1752. (not swapped) then
  1753. begin
  1754. for i:=2 to tcgsize2size[size] do
  1755. reg:=GetNextReg(reg);
  1756. list.concat(taicpu.op_reg_reg(A_CP,reg,GetDefaultZeroReg));
  1757. end
  1758. else
  1759. begin
  1760. if swapped then
  1761. list.concat(taicpu.op_reg_reg(A_CP,GetDefaultZeroReg,reg))
  1762. else
  1763. list.concat(taicpu.op_reg_reg(A_CP,reg,GetDefaultZeroReg));
  1764. for i:=2 to tcgsize2size[size] do
  1765. begin
  1766. reg:=GetNextReg(reg);
  1767. if swapped then
  1768. list.concat(taicpu.op_reg_reg(A_CPC,GetDefaultZeroReg,reg))
  1769. else
  1770. list.concat(taicpu.op_reg_reg(A_CPC,reg,GetDefaultZeroReg));
  1771. end;
  1772. end;
  1773. a_jmp_cond(list,cmp_op,l);
  1774. cg.a_reg_dealloc(list,NR_DEFAULTFLAGS);
  1775. end
  1776. else
  1777. inherited a_cmp_const_reg_label(list,size,cmp_op,a,reg,l);
  1778. end;
  1779. procedure tcgavr.a_cmp_reg_reg_label(list : TAsmList;size : tcgsize;
  1780. cmp_op : topcmp;reg1,reg2 : tregister;l : tasmlabel);
  1781. var
  1782. swapped : boolean;
  1783. tmpreg : tregister;
  1784. i : byte;
  1785. begin
  1786. swapped:=false;
  1787. { swap parameters? }
  1788. case cmp_op of
  1789. OC_GT:
  1790. begin
  1791. swapped:=true;
  1792. cmp_op:=OC_LT;
  1793. end;
  1794. OC_LTE:
  1795. begin
  1796. swapped:=true;
  1797. cmp_op:=OC_GTE;
  1798. end;
  1799. OC_BE:
  1800. begin
  1801. swapped:=true;
  1802. cmp_op:=OC_AE;
  1803. end;
  1804. OC_A:
  1805. begin
  1806. swapped:=true;
  1807. cmp_op:=OC_B;
  1808. end;
  1809. end;
  1810. if swapped then
  1811. begin
  1812. tmpreg:=reg1;
  1813. reg1:=reg2;
  1814. reg2:=tmpreg;
  1815. end;
  1816. cg.a_reg_alloc(list,NR_DEFAULTFLAGS);
  1817. list.concat(taicpu.op_reg_reg(A_CP,reg2,reg1));
  1818. for i:=2 to tcgsize2size[size] do
  1819. begin
  1820. reg1:=GetNextReg(reg1);
  1821. reg2:=GetNextReg(reg2);
  1822. list.concat(taicpu.op_reg_reg(A_CPC,reg2,reg1));
  1823. end;
  1824. a_jmp_cond(list,cmp_op,l);
  1825. cg.a_reg_dealloc(list,NR_DEFAULTFLAGS);
  1826. end;
  1827. procedure tcgavr.a_jmp_name(list : TAsmList;const s : string);
  1828. var
  1829. ai : taicpu;
  1830. begin
  1831. if CPUAVR_HAS_JMP_CALL in cpu_capabilities[current_settings.cputype] then
  1832. ai:=taicpu.op_sym(A_JMP,current_asmdata.RefAsmSymbol(s,AT_FUNCTION))
  1833. else
  1834. ai:=taicpu.op_sym(A_RJMP,current_asmdata.RefAsmSymbol(s,AT_FUNCTION));
  1835. ai.is_jmp:=true;
  1836. list.concat(ai);
  1837. end;
  1838. procedure tcgavr.a_jmp_always(list : TAsmList;l: tasmlabel);
  1839. var
  1840. ai : taicpu;
  1841. begin
  1842. if CPUAVR_HAS_JMP_CALL in cpu_capabilities[current_settings.cputype] then
  1843. ai:=taicpu.op_sym(A_JMP,l)
  1844. else
  1845. ai:=taicpu.op_sym(A_RJMP,l);
  1846. ai.is_jmp:=true;
  1847. list.concat(ai);
  1848. end;
  1849. procedure tcgavr.a_jmp_flags(list : TAsmList;const f : TResFlags;l: tasmlabel);
  1850. var
  1851. ai : taicpu;
  1852. begin
  1853. ai:=setcondition(taicpu.op_sym(A_BRxx,l),flags_to_cond(f));
  1854. ai.is_jmp:=true;
  1855. list.concat(ai);
  1856. end;
  1857. procedure tcgavr.g_flags2reg(list: TAsmList; size: TCgSize; const f: TResFlags; reg: TRegister);
  1858. var
  1859. l : TAsmLabel;
  1860. //tmpflags : TResFlags;
  1861. i: Integer;
  1862. hreg: TRegister;
  1863. begin
  1864. current_asmdata.getjumplabel(l);
  1865. {
  1866. if flags_to_cond(f) then
  1867. begin
  1868. tmpflags:=f;
  1869. inverse_flags(tmpflags);
  1870. emit_mov(reg,GetDefaultZeroReg);
  1871. a_jmp_flags(list,tmpflags,l);
  1872. list.concat(taicpu.op_reg_const(A_LDI,reg,1));
  1873. end
  1874. else
  1875. }
  1876. begin
  1877. list.concat(taicpu.op_reg_const(A_LDI,reg,1));
  1878. hreg:=reg;
  1879. for i:=2 to tcgsize2size[size] do
  1880. begin
  1881. hreg:=GetNextReg(hreg);
  1882. emit_mov(list,hreg,GetDefaultZeroReg);
  1883. end;
  1884. a_jmp_flags(list,f,l);
  1885. emit_mov(list,reg,GetDefaultZeroReg);
  1886. end;
  1887. cg.a_label(list,l);
  1888. end;
  1889. procedure tcgavr.a_adjust_sp(list : TAsmList; value : longint);
  1890. {var
  1891. i : integer; }
  1892. begin
  1893. case value of
  1894. 0:
  1895. ;
  1896. {-14..-1:
  1897. begin
  1898. if ((-value) mod 2)<>0 then
  1899. list.concat(taicpu.op_reg(A_PUSH,GetDefaultTmpReg));
  1900. for i:=1 to (-value) div 2 do
  1901. list.concat(taicpu.op_const(A_RCALL,0));
  1902. end;
  1903. 1..7:
  1904. begin
  1905. for i:=1 to value do
  1906. list.concat(taicpu.op_reg(A_POP,GetDefaultTmpReg));
  1907. end;}
  1908. else
  1909. begin
  1910. list.concat(taicpu.op_reg_const(A_SUBI,NR_R28,lo(word(-value))));
  1911. list.concat(taicpu.op_reg_const(A_SBCI,NR_R29,hi(word(-value))));
  1912. // get SREG
  1913. list.concat(taicpu.op_reg_const(A_IN,GetDefaultTmpReg,NIO_SREG));
  1914. // block interrupts
  1915. list.concat(taicpu.op_none(A_CLI));
  1916. // write high SP
  1917. list.concat(taicpu.op_const_reg(A_OUT,NIO_SP_HI,NR_R29));
  1918. // release interrupts
  1919. list.concat(taicpu.op_const_reg(A_OUT,NIO_SREG,GetDefaultTmpReg));
  1920. // write low SP
  1921. list.concat(taicpu.op_const_reg(A_OUT,NIO_SP_LO,NR_R28));
  1922. end;
  1923. end;
  1924. end;
  1925. function tcgavr.GetLoad(const ref: treference) : tasmop;
  1926. begin
  1927. if (ref.base=NR_NO) and (ref.index=NR_NO) then
  1928. result:=A_LDS
  1929. else if (ref.base<>NR_NO) and (ref.offset<>0) then
  1930. result:=A_LDD
  1931. else
  1932. result:=A_LD;
  1933. end;
  1934. function tcgavr.GetStore(const ref: treference) : tasmop;
  1935. begin
  1936. if (ref.base=NR_NO) and (ref.index=NR_NO) then
  1937. result:=A_STS
  1938. else if (ref.base<>NR_NO) and (ref.offset<>0) then
  1939. result:=A_STD
  1940. else
  1941. result:=A_ST;
  1942. end;
  1943. procedure tcgavr.gen_multiply(list: TAsmList; op: topcg; size: TCgSize; src2, src1, dst: tregister; check_overflow: boolean; var ovloc: tlocation);
  1944. procedure perform_r1_check(overflow_label: TAsmLabel; other_reg: TRegister=NR_R1);
  1945. var
  1946. ai: taicpu;
  1947. begin
  1948. if check_overflow then
  1949. begin
  1950. list.concat(taicpu.op_reg_reg(A_OR,NR_R1,other_reg));
  1951. ai:=Taicpu.Op_Sym(A_BRxx,overflow_label);
  1952. ai.SetCondition(C_NE);
  1953. ai.is_jmp:=true;
  1954. list.concat(ai);
  1955. end;
  1956. end;
  1957. procedure perform_ovf_check(overflow_label: TAsmLabel);
  1958. var
  1959. ai: taicpu;
  1960. begin
  1961. if check_overflow then
  1962. begin
  1963. ai:=Taicpu.Op_Sym(A_BRxx,overflow_label);
  1964. ai.SetCondition(C_CS);
  1965. ai.is_jmp:=true;
  1966. list.concat(ai);
  1967. end;
  1968. end;
  1969. var
  1970. pd: tprocdef;
  1971. paraloc1, paraloc2: tcgpara;
  1972. ai: taicpu;
  1973. hl, no_overflow: TAsmLabel;
  1974. name: String;
  1975. begin
  1976. ovloc.loc:=LOC_VOID;
  1977. if size in [OS_8,OS_S8] then
  1978. begin
  1979. if (CPUAVR_HAS_MUL in cpu_capabilities[current_settings.cputype]) and
  1980. (op=OP_MUL) then
  1981. begin
  1982. cg.a_reg_alloc(list,NR_R0);
  1983. cg.a_reg_alloc(list,NR_R1);
  1984. list.concat(taicpu.op_reg_reg(topcg2asmop[op],src1,src2));
  1985. // Check overflow
  1986. if check_overflow then
  1987. begin
  1988. current_asmdata.getjumplabel(hl);
  1989. list.concat(taicpu.op_reg_reg(A_AND,NR_R1,NR_R1));
  1990. { Clear carry as it's not affected by any of the instructions }
  1991. list.concat(taicpu.op_none(A_CLC));
  1992. ai:=Taicpu.Op_Sym(A_BRxx,hl);
  1993. ai.SetCondition(C_EQ);
  1994. ai.is_jmp:=true;
  1995. list.concat(ai);
  1996. list.concat(taicpu.op_reg(A_CLR,NR_R1));
  1997. list.concat(taicpu.op_none(A_SEC));
  1998. a_label(list,hl);
  1999. ovloc.loc:=LOC_FLAGS;
  2000. end
  2001. else
  2002. list.concat(taicpu.op_reg(A_CLR,NR_R1));
  2003. cg.a_reg_dealloc(list,NR_R1);
  2004. list.concat(taicpu.op_reg_reg(A_MOV,dst,NR_R0));
  2005. cg.a_reg_dealloc(list,NR_R0);
  2006. end
  2007. else if (CPUAVR_HAS_MUL in cpu_capabilities[current_settings.cputype]) and
  2008. (op=OP_IMUL) then
  2009. begin
  2010. cg.a_reg_alloc(list,NR_R0);
  2011. cg.a_reg_alloc(list,NR_R1);
  2012. list.concat(taicpu.op_reg_reg(A_MULS,src1,src2));
  2013. list.concat(taicpu.op_reg_reg(A_MOV,dst,NR_R0));
  2014. // Check overflow
  2015. if check_overflow then
  2016. begin
  2017. current_asmdata.getjumplabel(no_overflow);
  2018. list.concat(taicpu.op_reg_const(A_SBRC,NR_R0,7));
  2019. list.concat(taicpu.op_reg(A_INC,NR_R1));
  2020. list.concat(taicpu.op_reg(A_TST,NR_R1));
  2021. ai:=Taicpu.Op_Sym(A_BRxx,no_overflow);
  2022. ai.SetCondition(C_EQ);
  2023. ai.is_jmp:=true;
  2024. list.concat(ai);
  2025. list.concat(taicpu.op_reg(A_CLR,NR_R1));
  2026. a_call_name(list,'FPC_OVERFLOW',false);
  2027. a_label(list,no_overflow);
  2028. ovloc.loc:=LOC_VOID;
  2029. end
  2030. else
  2031. list.concat(taicpu.op_reg(A_CLR,NR_R1));
  2032. cg.a_reg_dealloc(list,NR_R1);
  2033. cg.a_reg_dealloc(list,NR_R0);
  2034. end
  2035. else
  2036. begin
  2037. if size=OS_8 then
  2038. name:='fpc_mul_byte'
  2039. else
  2040. name:='fpc_mul_shortint';
  2041. if check_overflow then
  2042. name:=name+'_checkoverflow';
  2043. pd:=search_system_proc(name);
  2044. paraloc1.init;
  2045. paraloc2.init;
  2046. paramanager.getcgtempparaloc(list,pd,1,paraloc1);
  2047. paramanager.getcgtempparaloc(list,pd,2,paraloc2);
  2048. a_load_reg_cgpara(list,OS_8,src1,paraloc2);
  2049. a_load_reg_cgpara(list,OS_8,src2,paraloc1);
  2050. paramanager.freecgpara(list,paraloc2);
  2051. paramanager.freecgpara(list,paraloc1);
  2052. alloccpuregisters(list,R_INTREGISTER,paramanager.get_volatile_registers_int(pocall_default));
  2053. a_call_name(list,upper(name),false);
  2054. dealloccpuregisters(list,R_INTREGISTER,paramanager.get_volatile_registers_int(pocall_default));
  2055. cg.a_reg_alloc(list,NR_R24);
  2056. cg.a_load_reg_reg(list,OS_8,OS_8,NR_R24,dst);
  2057. cg.a_reg_dealloc(list,NR_R24);
  2058. paraloc2.done;
  2059. paraloc1.done;
  2060. end;
  2061. end
  2062. else if size in [OS_16,OS_S16] then
  2063. begin
  2064. if (CPUAVR_HAS_MUL in cpu_capabilities[current_settings.cputype]) and
  2065. ((not check_overflow) or
  2066. (size=OS_16)) then
  2067. begin
  2068. if check_overflow then
  2069. begin
  2070. current_asmdata.getjumplabel(hl);
  2071. current_asmdata.getjumplabel(no_overflow);
  2072. end;
  2073. cg.a_reg_alloc(list,NR_R0);
  2074. cg.a_reg_alloc(list,NR_R1);
  2075. list.concat(taicpu.op_reg_reg(A_MUL,src2,src1));
  2076. emit_mov(list,dst,NR_R0);
  2077. emit_mov(list,GetNextReg(dst),NR_R1);
  2078. list.concat(taicpu.op_reg_reg(A_MUL,GetNextReg(src1),src2));
  2079. perform_r1_check(hl);
  2080. list.concat(taicpu.op_reg_reg(A_ADD,GetNextReg(dst),NR_R0));
  2081. perform_ovf_check(hl);
  2082. list.concat(taicpu.op_reg_reg(A_MUL,src1,GetNextReg(src2)));
  2083. perform_r1_check(hl);
  2084. list.concat(taicpu.op_reg_reg(A_ADD,GetNextReg(dst),NR_R0));
  2085. perform_ovf_check(hl);
  2086. if check_overflow then
  2087. begin
  2088. list.concat(taicpu.op_reg_reg(A_MUL,GetNextReg(src1),GetNextReg(src2)));
  2089. perform_r1_check(hl,NR_R0);
  2090. end;
  2091. cg.a_reg_dealloc(list,NR_R0);
  2092. list.concat(taicpu.op_reg(A_CLR,NR_R1));
  2093. if check_overflow then
  2094. begin
  2095. {
  2096. CLV/CLC
  2097. JMP no_overflow
  2098. .hl:
  2099. CLR R1
  2100. SEV/SEC
  2101. .no_overflow:
  2102. }
  2103. if op=OP_MUL then
  2104. list.concat(taicpu.op_none(A_CLC))
  2105. else
  2106. list.concat(taicpu.op_none(A_CLV));
  2107. a_jmp_always(list,no_overflow);
  2108. a_label(list,hl);
  2109. list.concat(taicpu.op_reg(A_CLR,NR_R1));
  2110. if op=OP_MUL then
  2111. list.concat(taicpu.op_none(A_SEC))
  2112. else
  2113. list.concat(taicpu.op_none(A_SEV));
  2114. a_label(list,no_overflow);
  2115. ovloc.loc:=LOC_FLAGS;
  2116. end;
  2117. cg.a_reg_dealloc(list,NR_R1);
  2118. end
  2119. else
  2120. begin
  2121. if size=OS_16 then
  2122. name:='fpc_mul_word'
  2123. else
  2124. name:='fpc_mul_integer';
  2125. if check_overflow then
  2126. name:=name+'_checkoverflow';
  2127. pd:=search_system_proc(name);
  2128. paraloc1.init;
  2129. paraloc2.init;
  2130. paramanager.getcgtempparaloc(list,pd,1,paraloc1);
  2131. paramanager.getcgtempparaloc(list,pd,2,paraloc2);
  2132. a_load_reg_cgpara(list,OS_16,src1,paraloc2);
  2133. a_load_reg_cgpara(list,OS_16,src2,paraloc1);
  2134. paramanager.freecgpara(list,paraloc2);
  2135. paramanager.freecgpara(list,paraloc1);
  2136. alloccpuregisters(list,R_INTREGISTER,paramanager.get_volatile_registers_int(pocall_default));
  2137. a_call_name(list,upper(name),false);
  2138. dealloccpuregisters(list,R_INTREGISTER,paramanager.get_volatile_registers_int(pocall_default));
  2139. cg.a_reg_alloc(list,NR_R24);
  2140. cg.a_reg_alloc(list,NR_R25);
  2141. cg.a_load_reg_reg(list,OS_8,OS_8,NR_R24,dst);
  2142. cg.a_reg_dealloc(list,NR_R24);
  2143. cg.a_load_reg_reg(list,OS_8,OS_8,NR_R25,GetNextReg(dst));
  2144. cg.a_reg_dealloc(list,NR_R25);
  2145. paraloc2.done;
  2146. paraloc1.done;
  2147. end;
  2148. end
  2149. else
  2150. internalerror(2011022002);
  2151. end;
  2152. procedure tcgavr.g_proc_entry(list : TAsmList;localsize : longint;nostackframe:boolean);
  2153. var
  2154. regs : tcpuregisterset;
  2155. reg : tsuperregister;
  2156. begin
  2157. if current_procinfo.procdef.isempty then
  2158. exit;
  2159. if (po_interrupt in current_procinfo.procdef.procoptions) and
  2160. (not nostackframe) then
  2161. begin
  2162. { check if the framepointer is actually used, this is done here because
  2163. we have to know the size of the locals (must be 0), avr does not know
  2164. an sp based stack }
  2165. if not(current_procinfo.procdef.stack_tainting_parameter(calleeside)) and
  2166. (localsize=0) then
  2167. current_procinfo.framepointer:=NR_NO;
  2168. { save int registers,
  2169. but only if the procedure returns }
  2170. if not(po_noreturn in current_procinfo.procdef.procoptions) then
  2171. regs:=rg[R_INTREGISTER].used_in_proc
  2172. else
  2173. regs:=[];
  2174. { if the framepointer is potentially used, save it always because we need a proper stack frame,
  2175. even if the procedure never returns, the procedure could be e.g. a nested one accessing
  2176. an outer stackframe }
  2177. if current_procinfo.framepointer<>NR_NO then
  2178. regs:=regs+[RS_R28,RS_R29];
  2179. { we clear r1 }
  2180. include(regs,getsupreg(GetDefaultZeroReg));
  2181. regs:=regs+[getsupreg(GetDefaultTmpReg)];
  2182. if current_settings.cputype=cpu_avr1 then
  2183. message1(cg_w_interrupt_does_not_save_registers,current_procinfo.procdef.fullprocname(false))
  2184. else
  2185. begin
  2186. for reg:=RS_R31 downto RS_R0 do
  2187. if reg in regs then
  2188. list.concat(taicpu.op_reg(A_PUSH,newreg(R_INTREGISTER,reg,R_SUBWHOLE)));
  2189. { Save SREG }
  2190. cg.getcpuregister(list,GetDefaultTmpReg);
  2191. list.concat(taicpu.op_reg_const(A_IN, GetDefaultTmpReg, $3F));
  2192. list.concat(taicpu.op_reg(A_PUSH, GetDefaultTmpReg));
  2193. cg.ungetcpuregister(list,GetDefaultTmpReg);
  2194. end;
  2195. list.concat(taicpu.op_reg(A_CLR,GetDefaultZeroReg));
  2196. if current_procinfo.framepointer<>NR_NO then
  2197. begin
  2198. cg.getcpuregister(list,NR_R28);
  2199. list.concat(taicpu.op_reg_const(A_IN,NR_R28,NIO_SP_LO));
  2200. cg.getcpuregister(list,NR_R29);
  2201. list.concat(taicpu.op_reg_const(A_IN,NR_R29,NIO_SP_HI));
  2202. a_adjust_sp(list,-localsize);
  2203. end;
  2204. end
  2205. else if not(nostackframe) then
  2206. begin
  2207. { check if the framepointer is actually used, this is done here because
  2208. we have to know the size of the locals (must be 0), avr does not know
  2209. an sp based stack }
  2210. if not(current_procinfo.procdef.stack_tainting_parameter(calleeside)) and
  2211. (localsize=0) then
  2212. current_procinfo.framepointer:=NR_NO;
  2213. { save int registers,
  2214. but only if the procedure returns }
  2215. if not(po_noreturn in current_procinfo.procdef.procoptions) then
  2216. regs:=rg[R_INTREGISTER].used_in_proc-paramanager.get_volatile_registers_int(pocall_stdcall)
  2217. else
  2218. regs:=[];
  2219. { if the framepointer is potentially used, save it always because we need a proper stack frame,
  2220. even if the procedure never returns, the procedure could be e.g. a nested one accessing
  2221. an outer stackframe }
  2222. if current_procinfo.framepointer<>NR_NO then
  2223. regs:=regs+[RS_R28,RS_R29];
  2224. for reg:=RS_R31 downto RS_R0 do
  2225. if reg in regs then
  2226. list.concat(taicpu.op_reg(A_PUSH,newreg(R_INTREGISTER,reg,R_SUBWHOLE)));
  2227. if current_procinfo.framepointer<>NR_NO then
  2228. begin
  2229. cg.getcpuregister(list,NR_R28);
  2230. list.concat(taicpu.op_reg_const(A_IN,NR_R28,NIO_SP_LO));
  2231. cg.getcpuregister(list,NR_R29);
  2232. list.concat(taicpu.op_reg_const(A_IN,NR_R29,NIO_SP_HI));
  2233. a_adjust_sp(list,-localsize);
  2234. end;
  2235. end;
  2236. end;
  2237. procedure tcgavr.g_proc_exit(list : TAsmList;parasize : longint;nostackframe:boolean);
  2238. var
  2239. regs : tcpuregisterset;
  2240. reg : TSuperRegister;
  2241. LocalSize : longint;
  2242. begin
  2243. { every byte counts for avr, so if a subroutine is marked as non-returning, we do
  2244. not generate any exit code, so we really trust the noreturn directive
  2245. }
  2246. if po_noreturn in current_procinfo.procdef.procoptions then
  2247. exit;
  2248. if po_interrupt in current_procinfo.procdef.procoptions then
  2249. begin
  2250. if not(current_procinfo.procdef.isempty) and
  2251. (not nostackframe) then
  2252. begin
  2253. regs:=rg[R_INTREGISTER].used_in_proc;
  2254. if current_procinfo.framepointer<>NR_NO then
  2255. begin
  2256. regs:=regs+[RS_R28,RS_R29];
  2257. LocalSize:=current_procinfo.calc_stackframe_size;
  2258. a_adjust_sp(list,LocalSize);
  2259. end;
  2260. { we clear r1 }
  2261. include(regs,getsupreg(GetDefaultZeroReg));
  2262. if current_settings.cputype<>cpu_avr1 then
  2263. begin
  2264. { Reload SREG }
  2265. regs:=regs+[getsupreg(GetDefaultTmpReg)];
  2266. cg.getcpuregister(list,GetDefaultTmpReg);
  2267. list.concat(taicpu.op_reg(A_POP, GetDefaultTmpReg));
  2268. list.concat(taicpu.op_const_reg(A_OUT, $3F, GetDefaultTmpReg));
  2269. cg.ungetcpuregister(list,GetDefaultTmpReg);
  2270. for reg:=RS_R0 to RS_R31 do
  2271. if reg in regs then
  2272. list.concat(taicpu.op_reg(A_POP,newreg(R_INTREGISTER,reg,R_SUBWHOLE)));
  2273. end;
  2274. end;
  2275. list.concat(taicpu.op_none(A_RETI));
  2276. end
  2277. else if not(nostackframe) and not(current_procinfo.procdef.isempty) then
  2278. begin
  2279. regs:=rg[R_INTREGISTER].used_in_proc-paramanager.get_volatile_registers_int(pocall_stdcall);
  2280. if current_procinfo.framepointer<>NR_NO then
  2281. begin
  2282. regs:=regs+[RS_R28,RS_R29];
  2283. LocalSize:=current_procinfo.calc_stackframe_size;
  2284. a_adjust_sp(list,LocalSize);
  2285. end;
  2286. for reg:=RS_R0 to RS_R31 do
  2287. if reg in regs then
  2288. list.concat(taicpu.op_reg(A_POP,newreg(R_INTREGISTER,reg,R_SUBWHOLE)));
  2289. list.concat(taicpu.op_none(A_RET));
  2290. end
  2291. else
  2292. list.concat(taicpu.op_none(A_RET));
  2293. end;
  2294. procedure tcgavr.a_loadaddr_ref_reg(list : TAsmList;const ref : treference;r : tregister);
  2295. var
  2296. tmpref : treference;
  2297. begin
  2298. if ref.addressmode<>AM_UNCHANGED then
  2299. internalerror(2011021706);
  2300. if assigned(ref.symbol) or (ref.offset<>0) or
  2301. { If no other reference information it must imply an absolute reference to address 0 }
  2302. ((ref.index=NR_NO) and (ref.base=NR_NO)) then
  2303. begin
  2304. reference_reset(tmpref,0,[]);
  2305. tmpref.symbol:=ref.symbol;
  2306. tmpref.offset:=ref.offset;
  2307. if assigned(ref.symbol) and (ref.symbol.typ in [AT_FUNCTION,AT_LABEL]) then
  2308. tmpref.refaddr:=addr_lo8_gs
  2309. else
  2310. tmpref.refaddr:=addr_lo8;
  2311. list.concat(taicpu.op_reg_ref(A_LDI,r,tmpref));
  2312. if assigned(ref.symbol) and (ref.symbol.typ in [AT_FUNCTION,AT_LABEL]) then
  2313. tmpref.refaddr:=addr_hi8_gs
  2314. else
  2315. tmpref.refaddr:=addr_hi8;
  2316. list.concat(taicpu.op_reg_ref(A_LDI,GetNextReg(r),tmpref));
  2317. if (ref.base<>NR_NO) then
  2318. begin
  2319. cg.a_reg_alloc(list, NR_DEFAULTFLAGS);
  2320. list.concat(taicpu.op_reg_reg(A_ADD,r,ref.base));
  2321. list.concat(taicpu.op_reg_reg(A_ADC,GetNextReg(r),GetNextReg(ref.base)));
  2322. cg.a_reg_dealloc(list, NR_DEFAULTFLAGS);
  2323. end;
  2324. if (ref.index<>NR_NO) then
  2325. begin
  2326. cg.a_reg_alloc(list, NR_DEFAULTFLAGS);
  2327. list.concat(taicpu.op_reg_reg(A_ADD,r,ref.index));
  2328. list.concat(taicpu.op_reg_reg(A_ADC,GetNextReg(r),GetNextReg(ref.index)));
  2329. cg.a_reg_dealloc(list, NR_DEFAULTFLAGS);
  2330. end;
  2331. end
  2332. else if (ref.base<>NR_NO)then
  2333. begin
  2334. emit_mov(list,r,ref.base);
  2335. emit_mov(list,GetNextReg(r),GetNextReg(ref.base));
  2336. if (ref.index<>NR_NO) then
  2337. begin
  2338. cg.a_reg_alloc(list, NR_DEFAULTFLAGS);
  2339. list.concat(taicpu.op_reg_reg(A_ADD,r,ref.index));
  2340. list.concat(taicpu.op_reg_reg(A_ADC,GetNextReg(r),GetNextReg(ref.index)));
  2341. cg.a_reg_dealloc(list, NR_DEFAULTFLAGS);
  2342. end;
  2343. end
  2344. else if (ref.index<>NR_NO) then
  2345. begin
  2346. emit_mov(list,r,ref.index);
  2347. emit_mov(list,GetNextReg(r),GetNextReg(ref.index));
  2348. end;
  2349. end;
  2350. procedure tcgavr.fixref(list : TAsmList;var ref : treference);
  2351. begin
  2352. internalerror(2011021320);
  2353. end;
  2354. procedure tcgavr.g_concatcopy(list : TAsmList;const source,dest : treference;len : tcgint);
  2355. var
  2356. countreg,tmpreg,tmpreg2: tregister;
  2357. srcref,dstref : treference;
  2358. countregsize : tcgsize;
  2359. l : TAsmLabel;
  2360. i : longint;
  2361. SrcQuickRef, DestQuickRef : Boolean;
  2362. begin
  2363. if len>16 then
  2364. begin
  2365. current_asmdata.getjumplabel(l);
  2366. reference_reset(srcref,source.alignment,source.volatility);
  2367. reference_reset(dstref,dest.alignment,source.volatility);
  2368. srcref.base:=NR_R30;
  2369. srcref.addressmode:=AM_POSTINCREMENT;
  2370. dstref.base:=NR_R26;
  2371. dstref.addressmode:=AM_POSTINCREMENT;
  2372. if len<256 then
  2373. countregsize:=OS_8
  2374. else if len<65536 then
  2375. countregsize:=OS_16
  2376. else
  2377. internalerror(2011022007);
  2378. countreg:=getintregister(list,countregsize);
  2379. a_load_const_reg(list,countregsize,len,countreg);
  2380. cg.getcpuregister(list,NR_R30);
  2381. cg.getcpuregister(list,NR_R31);
  2382. a_loadaddr_ref_reg(list,source,NR_R30);
  2383. { only base or index register in dest? }
  2384. if ((dest.addressmode=AM_UNCHANGED) and (dest.offset=0) and not(assigned(dest.symbol))) and
  2385. ((dest.base<>NR_NO) xor (dest.index<>NR_NO)) then
  2386. begin
  2387. if dest.base<>NR_NO then
  2388. tmpreg:=dest.base
  2389. else if dest.index<>NR_NO then
  2390. tmpreg:=dest.index
  2391. else
  2392. internalerror(2016112001);
  2393. end
  2394. else
  2395. begin
  2396. tmpreg:=getaddressregister(list);
  2397. a_loadaddr_ref_reg(list,dest,tmpreg);
  2398. end;
  2399. { X is used for spilling code so we can load it
  2400. only by a push/pop sequence, this can be
  2401. optimized later on by the peephole optimizer
  2402. }
  2403. list.concat(taicpu.op_reg(A_PUSH,tmpreg));
  2404. list.concat(taicpu.op_reg(A_PUSH,GetNextReg(tmpreg)));
  2405. cg.getcpuregister(list,NR_R27);
  2406. list.concat(taicpu.op_reg(A_POP,NR_R27));
  2407. cg.getcpuregister(list,NR_R26);
  2408. list.concat(taicpu.op_reg(A_POP,NR_R26));
  2409. cg.a_label(list,l);
  2410. cg.getcpuregister(list,GetDefaultTmpReg);
  2411. list.concat(taicpu.op_reg_ref(GetLoad(srcref),GetDefaultTmpReg,srcref));
  2412. list.concat(taicpu.op_ref_reg(GetStore(dstref),dstref,GetDefaultTmpReg));
  2413. cg.ungetcpuregister(list,GetDefaultTmpReg);
  2414. cg.a_reg_alloc(list,NR_DEFAULTFLAGS);
  2415. if tcgsize2size[countregsize] = 1 then
  2416. list.concat(taicpu.op_reg(A_DEC,countreg))
  2417. else
  2418. begin
  2419. list.concat(taicpu.op_reg_const(A_SUBI,countreg,1));
  2420. list.concat(taicpu.op_reg_reg(A_SBC,GetNextReg(countreg),GetDefaultZeroReg));
  2421. end;
  2422. a_jmp_flags(list,F_NE,l);
  2423. cg.ungetcpuregister(list,NR_R26);
  2424. cg.ungetcpuregister(list,NR_R27);
  2425. cg.ungetcpuregister(list,NR_R30);
  2426. cg.ungetcpuregister(list,NR_R31);
  2427. { keep registers alive }
  2428. a_reg_sync(list,countreg);
  2429. end
  2430. else
  2431. begin
  2432. SrcQuickRef:=false;
  2433. DestQuickRef:=false;
  2434. if ((CPUAVR_16_REGS in cpu_capabilities[current_settings.cputype]) and
  2435. not((source.Base=NR_NO) and (source.Index=NR_NO) and (source.Offset in [0..192-len]))) or
  2436. (
  2437. not((source.addressmode=AM_UNCHANGED) and
  2438. (source.symbol=nil) and
  2439. ((source.base=NR_R28) or
  2440. (source.base=NR_R30)) and
  2441. (source.Index=NR_NO) and
  2442. (source.Offset in [0..64-len])) and
  2443. not((source.Base=NR_NO) and (source.Index=NR_NO))
  2444. ) then
  2445. begin
  2446. cg.getcpuregister(list,NR_R30);
  2447. cg.getcpuregister(list,NR_R31);
  2448. srcref:=normalize_ref(list,source,NR_R30);
  2449. end
  2450. else
  2451. begin
  2452. SrcQuickRef:=true;
  2453. srcref:=source;
  2454. end;
  2455. if ((CPUAVR_16_REGS in cpu_capabilities[current_settings.cputype]) and
  2456. not((dest.Base=NR_NO) and (dest.Index=NR_NO) and (dest.Offset in [0..192-len]))) or
  2457. (
  2458. not((dest.addressmode=AM_UNCHANGED) and
  2459. (dest.symbol=nil) and
  2460. ((dest.base=NR_R28) or
  2461. (dest.base=NR_R30)) and
  2462. (dest.Index=NR_No) and
  2463. (dest.Offset in [0..64-len])) and
  2464. not((dest.Base=NR_NO) and (dest.Index=NR_NO))
  2465. ) then
  2466. begin
  2467. if not(SrcQuickRef) then
  2468. begin
  2469. { only base or index register in dest? }
  2470. if ((dest.addressmode=AM_UNCHANGED) and (dest.offset=0) and not(assigned(dest.symbol))) and
  2471. ((dest.base<>NR_NO) xor (dest.index<>NR_NO)) then
  2472. begin
  2473. if dest.base<>NR_NO then
  2474. tmpreg:=dest.base
  2475. else if dest.index<>NR_NO then
  2476. tmpreg:=dest.index
  2477. else
  2478. internalerror(2016112002);
  2479. end
  2480. else
  2481. tmpreg:=getaddressregister(list);
  2482. dstref:=normalize_ref(list,dest,tmpreg);
  2483. { X is used for spilling code so we can load it
  2484. only by a push/pop sequence, this can be
  2485. optimized later on by the peephole optimizer
  2486. }
  2487. list.concat(taicpu.op_reg(A_PUSH,tmpreg));
  2488. list.concat(taicpu.op_reg(A_PUSH,GetNextReg(tmpreg)));
  2489. cg.getcpuregister(list,NR_R27);
  2490. list.concat(taicpu.op_reg(A_POP,NR_R27));
  2491. cg.getcpuregister(list,NR_R26);
  2492. list.concat(taicpu.op_reg(A_POP,NR_R26));
  2493. dstref.base:=NR_R26;
  2494. end
  2495. else
  2496. begin
  2497. cg.getcpuregister(list,NR_R30);
  2498. cg.getcpuregister(list,NR_R31);
  2499. dstref:=normalize_ref(list,dest,NR_R30);
  2500. end;
  2501. end
  2502. else
  2503. begin
  2504. DestQuickRef:=true;
  2505. dstref:=dest;
  2506. end;
  2507. { If dest is an ioreg and size = 16 bit then
  2508. write high byte first, then low byte
  2509. but not for avrxmega3 }
  2510. if (len = 2) and DestQuickRef and (current_settings.cputype <> cpu_avrxmega3) and
  2511. addr_is_io_register(dest.offset) then
  2512. begin
  2513. // If src is also a 16 bit ioreg then read low byte then high byte
  2514. if SrcQuickRef and addr_is_io_register(srcref.offset) then
  2515. begin
  2516. // First read source into temp registers
  2517. tmpreg:=getintregister(list, OS_16);
  2518. list.concat(taicpu.op_reg_ref(GetLoad(srcref),tmpreg,srcref));
  2519. inc(srcref.offset);
  2520. tmpreg2:=GetNextReg(tmpreg);
  2521. list.concat(taicpu.op_reg_ref(GetLoad(srcref),tmpreg2,srcref));
  2522. // then move temp registers to dest in reverse order
  2523. inc(dstref.offset);
  2524. list.concat(taicpu.op_ref_reg(GetStore(dstref),dstref,tmpreg2));
  2525. dec(dstref.offset);
  2526. list.concat(taicpu.op_ref_reg(GetStore(dstref),dstref,tmpreg));
  2527. end
  2528. else
  2529. begin
  2530. { avrtiny doesn't have LDD instruction, so use
  2531. predecrement version of LD with pre-incremented pointer }
  2532. if current_settings.cputype = cpu_avrtiny then
  2533. begin
  2534. srcref.addressmode:=AM_PREDECREMENT;
  2535. list.concat(taicpu.op_reg_const(A_SUBI,srcref.base,-2));
  2536. list.concat(taicpu.op_reg_const(A_SBCI,GetNextReg(srcref.base),$FF));
  2537. end
  2538. else
  2539. begin
  2540. srcref.addressmode:=AM_UNCHANGED;
  2541. inc(srcref.offset);
  2542. end;
  2543. dstref.addressmode:=AM_UNCHANGED;
  2544. inc(dstref.offset);
  2545. cg.getcpuregister(list,GetDefaultTmpReg);
  2546. list.concat(taicpu.op_reg_ref(GetLoad(srcref),GetDefaultTmpReg,srcref));
  2547. list.concat(taicpu.op_ref_reg(GetStore(dstref),dstref,GetDefaultTmpReg));
  2548. cg.ungetcpuregister(list,GetDefaultTmpReg);
  2549. if not(SrcQuickRef) and (current_settings.cputype <> cpu_avrtiny) then
  2550. srcref.addressmode:=AM_POSTINCREMENT
  2551. else if current_settings.cputype = cpu_avrtiny then
  2552. srcref.addressmode:=AM_PREDECREMENT
  2553. else
  2554. srcref.addressmode:=AM_UNCHANGED;
  2555. if current_settings.cputype <> cpu_avrtiny then
  2556. dec(srcref.offset);
  2557. dec(dstref.offset);
  2558. cg.getcpuregister(list,GetDefaultTmpReg);
  2559. list.concat(taicpu.op_reg_ref(GetLoad(srcref),GetDefaultTmpReg,srcref));
  2560. list.concat(taicpu.op_ref_reg(GetStore(dstref),dstref,GetDefaultTmpReg));
  2561. cg.ungetcpuregister(list,GetDefaultTmpReg);
  2562. end;
  2563. end
  2564. else
  2565. for i:=1 to len do
  2566. begin
  2567. if not(SrcQuickRef) and (i<len) then
  2568. srcref.addressmode:=AM_POSTINCREMENT
  2569. else
  2570. srcref.addressmode:=AM_UNCHANGED;
  2571. if not(DestQuickRef) and (i<len) then
  2572. dstref.addressmode:=AM_POSTINCREMENT
  2573. else
  2574. dstref.addressmode:=AM_UNCHANGED;
  2575. cg.getcpuregister(list,GetDefaultTmpReg);
  2576. list.concat(taicpu.op_reg_ref(GetLoad(srcref),GetDefaultTmpReg,srcref));
  2577. list.concat(taicpu.op_ref_reg(GetStore(dstref),dstref,GetDefaultTmpReg));
  2578. cg.ungetcpuregister(list,GetDefaultTmpReg);
  2579. if SrcQuickRef then
  2580. inc(srcref.offset);
  2581. if DestQuickRef then
  2582. inc(dstref.offset);
  2583. end;
  2584. if not(SrcQuickRef) then
  2585. begin
  2586. ungetcpuregister(list,srcref.base);
  2587. ungetcpuregister(list,TRegister(ord(srcref.base)+1));
  2588. end;
  2589. if not(DestQuickRef) then
  2590. begin
  2591. ungetcpuregister(list,dstref.base);
  2592. ungetcpuregister(list,TRegister(ord(dstref.base)+1));
  2593. end;
  2594. end;
  2595. end;
  2596. procedure tcgavr.g_overflowcheck(list: TAsmList; const l: tlocation; def: tdef);
  2597. var
  2598. hl : tasmlabel;
  2599. ai : taicpu;
  2600. cond : TAsmCond;
  2601. begin
  2602. if not(cs_check_overflow in current_settings.localswitches) then
  2603. exit;
  2604. current_asmdata.getjumplabel(hl);
  2605. if not ((def.typ=pointerdef) or
  2606. ((def.typ=orddef) and
  2607. (torddef(def).ordtype in [u64bit,u16bit,u32bit,u8bit,uchar,
  2608. pasbool1,pasbool8,pasbool16,pasbool32,pasbool64]))) then
  2609. cond:=C_VC
  2610. else
  2611. cond:=C_CC;
  2612. ai:=Taicpu.Op_Sym(A_BRxx,hl);
  2613. ai.SetCondition(cond);
  2614. ai.is_jmp:=true;
  2615. list.concat(ai);
  2616. a_call_name(list,'FPC_OVERFLOW',false);
  2617. a_label(list,hl);
  2618. end;
  2619. procedure tcgavr.g_overflowCheck_loc(List: TAsmList; const Loc: TLocation; def: TDef; ovloc: tlocation);
  2620. var
  2621. hl : tasmlabel;
  2622. ai : taicpu;
  2623. cond : TAsmCond;
  2624. begin
  2625. if not(cs_check_overflow in current_settings.localswitches) then
  2626. exit;
  2627. case ovloc.loc of
  2628. LOC_FLAGS:
  2629. begin
  2630. current_asmdata.getjumplabel(hl);
  2631. if not ((def.typ=pointerdef) or
  2632. ((def.typ=orddef) and
  2633. (torddef(def).ordtype in [u64bit,u16bit,u32bit,u8bit,uchar,
  2634. pasbool1,pasbool8,pasbool16,pasbool32,pasbool64]))) then
  2635. cond:=C_VC
  2636. else
  2637. cond:=C_CC;
  2638. ai:=Taicpu.Op_Sym(A_BRxx,hl);
  2639. ai.SetCondition(cond);
  2640. ai.is_jmp:=true;
  2641. list.concat(ai);
  2642. a_call_name(list,'FPC_OVERFLOW',false);
  2643. a_label(list,hl);
  2644. end;
  2645. end;
  2646. end;
  2647. procedure tcgavr.g_save_registers(list: TAsmList);
  2648. begin
  2649. { this is done by the entry code }
  2650. end;
  2651. procedure tcgavr.g_restore_registers(list: TAsmList);
  2652. begin
  2653. { this is done by the exit code }
  2654. end;
  2655. procedure tcgavr.a_jmp_cond(list : TAsmList;cond : TOpCmp;l: tasmlabel);
  2656. var
  2657. ai1,ai2 : taicpu;
  2658. hl : TAsmLabel;
  2659. begin
  2660. ai1:=Taicpu.Op_sym(A_BRxx,l);
  2661. ai1.is_jmp:=true;
  2662. hl:=nil;
  2663. case cond of
  2664. OC_EQ:
  2665. ai1.SetCondition(C_EQ);
  2666. OC_GT:
  2667. begin
  2668. { emulate GT }
  2669. current_asmdata.getjumplabel(hl);
  2670. ai2:=Taicpu.Op_Sym(A_BRxx,hl);
  2671. ai2.SetCondition(C_EQ);
  2672. ai2.is_jmp:=true;
  2673. list.concat(ai2);
  2674. ai1.SetCondition(C_GE);
  2675. end;
  2676. OC_LT:
  2677. ai1.SetCondition(C_LT);
  2678. OC_GTE:
  2679. ai1.SetCondition(C_GE);
  2680. OC_LTE:
  2681. begin
  2682. { emulate LTE }
  2683. ai2:=Taicpu.Op_Sym(A_BRxx,l);
  2684. ai2.SetCondition(C_EQ);
  2685. ai2.is_jmp:=true;
  2686. list.concat(ai2);
  2687. ai1.SetCondition(C_LT);
  2688. end;
  2689. OC_NE:
  2690. ai1.SetCondition(C_NE);
  2691. OC_BE:
  2692. begin
  2693. { emulate BE }
  2694. ai2:=Taicpu.Op_Sym(A_BRxx,l);
  2695. ai2.SetCondition(C_EQ);
  2696. ai2.is_jmp:=true;
  2697. list.concat(ai2);
  2698. ai1.SetCondition(C_LO);
  2699. end;
  2700. OC_B:
  2701. ai1.SetCondition(C_LO);
  2702. OC_AE:
  2703. ai1.SetCondition(C_SH);
  2704. OC_A:
  2705. begin
  2706. { emulate A (unsigned GT) }
  2707. current_asmdata.getjumplabel(hl);
  2708. ai2:=Taicpu.Op_Sym(A_BRxx,hl);
  2709. ai2.SetCondition(C_EQ);
  2710. ai2.is_jmp:=true;
  2711. list.concat(ai2);
  2712. ai1.SetCondition(C_SH);
  2713. end;
  2714. else
  2715. internalerror(2011082501);
  2716. end;
  2717. list.concat(ai1);
  2718. if assigned(hl) then
  2719. a_label(list,hl);
  2720. end;
  2721. procedure tcgavr.emit_mov(list: TAsmList;reg2: tregister; reg1: tregister);
  2722. var
  2723. instr: taicpu;
  2724. begin
  2725. instr:=taicpu.op_reg_reg(A_MOV,reg2,reg1);
  2726. list.Concat(instr);
  2727. { Notify the register allocator that we have written a move instruction so
  2728. it can try to eliminate it. }
  2729. add_move_instruction(instr);
  2730. end;
  2731. procedure tcg64favr.a_op64_reg_reg(list : TAsmList;op:TOpCG;size : tcgsize;regsrc,regdst : tregister64);
  2732. begin
  2733. if not(size in [OS_S64,OS_64]) then
  2734. internalerror(2012102402);
  2735. tcgavr(cg).a_op_reg_reg_internal(list,Op,size,regsrc.reglo,regsrc.reghi,regdst.reglo,regdst.reghi);
  2736. end;
  2737. procedure tcg64favr.a_op64_const_reg(list : TAsmList;op:TOpCG;size : tcgsize;value : int64;reg : tregister64);
  2738. begin
  2739. tcgavr(cg).a_op_const_reg_internal(list,Op,size,value,reg.reglo,reg.reghi);
  2740. end;
  2741. procedure tcg64favr.a_op64_const_reg_reg(list: TAsmList; op: TOpCg;size: tcgsize;value: int64;src,dst : tregister64);
  2742. begin
  2743. if op in [OP_SHL,OP_SHR] then
  2744. tcgavr(cg).a_op_const_reg_reg_internal(list,Op,size,value,src.reglo,src.reghi,dst.reglo,dst.reghi)
  2745. else
  2746. Inherited a_op64_const_reg_reg(list,op,size,value,src,dst);
  2747. end;
  2748. procedure create_codegen;
  2749. begin
  2750. cg:=tcgavr.create;
  2751. cg64:=tcg64favr.create;
  2752. end;
  2753. end.