cgcpu.pas 99 KB

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