2
0

cgcpu.pas 90 KB

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