2
0

cgcpu.pas 82 KB

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