cgcpu.pas 88 KB

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