cgcpu.pas 93 KB

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