cgcpu.pas 93 KB

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