cgcpu.pas 114 KB

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