cgcpu.pas 107 KB

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