2
0

cgcpu.pas 116 KB

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