cgcpu.pas 100 KB

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