cgcpu.pas 78 KB

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