cgcpu.pas 106 KB

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