cgcpu.pas 108 KB

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