cgcpu.pas 100 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741
  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. begin
  1571. current_asmdata.getjumplabel(l);
  1572. {
  1573. if flags_to_cond(f) then
  1574. begin
  1575. tmpflags:=f;
  1576. inverse_flags(tmpflags);
  1577. emit_mov(reg,NR_R1);
  1578. a_jmp_flags(list,tmpflags,l);
  1579. list.concat(taicpu.op_reg_const(A_LDI,reg,1));
  1580. end
  1581. else
  1582. }
  1583. begin
  1584. list.concat(taicpu.op_reg_const(A_LDI,reg,1));
  1585. a_jmp_flags(list,f,l);
  1586. emit_mov(list,reg,NR_R1);
  1587. end;
  1588. cg.a_label(list,l);
  1589. end;
  1590. procedure tcgavr.a_adjust_sp(list : TAsmList; value : longint);
  1591. var
  1592. i : integer;
  1593. begin
  1594. case value of
  1595. 0:
  1596. ;
  1597. {-14..-1:
  1598. begin
  1599. if ((-value) mod 2)<>0 then
  1600. list.concat(taicpu.op_reg(A_PUSH,NR_R0));
  1601. for i:=1 to (-value) div 2 do
  1602. list.concat(taicpu.op_const(A_RCALL,0));
  1603. end;
  1604. 1..7:
  1605. begin
  1606. for i:=1 to value do
  1607. list.concat(taicpu.op_reg(A_POP,NR_R0));
  1608. end;}
  1609. else
  1610. begin
  1611. list.concat(taicpu.op_reg_const(A_SUBI,NR_R28,lo(word(-value))));
  1612. list.concat(taicpu.op_reg_const(A_SBCI,NR_R29,hi(word(-value))));
  1613. // get SREG
  1614. list.concat(taicpu.op_reg_const(A_IN,NR_R0,NIO_SREG));
  1615. // block interrupts
  1616. list.concat(taicpu.op_none(A_CLI));
  1617. // write high SP
  1618. list.concat(taicpu.op_const_reg(A_OUT,NIO_SP_HI,NR_R29));
  1619. // release interrupts
  1620. list.concat(taicpu.op_const_reg(A_OUT,NIO_SREG,NR_R0));
  1621. // write low SP
  1622. list.concat(taicpu.op_const_reg(A_OUT,NIO_SP_LO,NR_R28));
  1623. end;
  1624. end;
  1625. end;
  1626. function tcgavr.GetLoad(const ref: treference) : tasmop;
  1627. begin
  1628. if (ref.base=NR_NO) and (ref.index=NR_NO) then
  1629. result:=A_LDS
  1630. else if (ref.base<>NR_NO) and (ref.offset<>0) then
  1631. result:=A_LDD
  1632. else
  1633. result:=A_LD;
  1634. end;
  1635. function tcgavr.GetStore(const ref: treference) : tasmop;
  1636. begin
  1637. if (ref.base=NR_NO) and (ref.index=NR_NO) then
  1638. result:=A_STS
  1639. else if (ref.base<>NR_NO) and (ref.offset<>0) then
  1640. result:=A_STD
  1641. else
  1642. result:=A_ST;
  1643. end;
  1644. procedure tcgavr.gen_multiply(list: TAsmList; op: topcg; size: TCgSize; src2, src1, dst: tregister; check_overflow: boolean; var ovloc: tlocation);
  1645. procedure perform_r1_check(overflow_label: TAsmLabel; other_reg: TRegister=NR_R1);
  1646. var
  1647. ai: taicpu;
  1648. begin
  1649. if check_overflow then
  1650. begin
  1651. list.concat(taicpu.op_reg_reg(A_OR,NR_R1,other_reg));
  1652. ai:=Taicpu.Op_Sym(A_BRxx,overflow_label);
  1653. ai.SetCondition(C_NE);
  1654. ai.is_jmp:=true;
  1655. list.concat(ai);
  1656. end;
  1657. end;
  1658. procedure perform_ovf_check(overflow_label: TAsmLabel);
  1659. var
  1660. ai: taicpu;
  1661. begin
  1662. if check_overflow then
  1663. begin
  1664. ai:=Taicpu.Op_Sym(A_BRxx,overflow_label);
  1665. ai.SetCondition(C_CS);
  1666. ai.is_jmp:=true;
  1667. list.concat(ai);
  1668. end;
  1669. end;
  1670. var
  1671. pd: tprocdef;
  1672. paraloc1, paraloc2: tcgpara;
  1673. ai: taicpu;
  1674. hl, no_overflow: TAsmLabel;
  1675. name: String;
  1676. begin
  1677. ovloc.loc:=LOC_VOID;
  1678. if size in [OS_8,OS_S8] then
  1679. begin
  1680. if (CPUAVR_HAS_MUL in cpu_capabilities[current_settings.cputype]) and
  1681. (op=OP_MUL) then
  1682. begin
  1683. cg.a_reg_alloc(list,NR_R0);
  1684. cg.a_reg_alloc(list,NR_R1);
  1685. list.concat(taicpu.op_reg_reg(topcg2asmop[op],src1,src2));
  1686. // Check overflow
  1687. if check_overflow then
  1688. begin
  1689. current_asmdata.getjumplabel(hl);
  1690. list.concat(taicpu.op_reg_reg(A_AND,NR_R1,NR_R1));
  1691. { Clear carry as it's not affected by any of the instructions }
  1692. list.concat(taicpu.op_none(A_CLC));
  1693. ai:=Taicpu.Op_Sym(A_BRxx,hl);
  1694. ai.SetCondition(C_EQ);
  1695. ai.is_jmp:=true;
  1696. list.concat(ai);
  1697. list.concat(taicpu.op_reg(A_CLR,NR_R1));
  1698. list.concat(taicpu.op_none(A_SEC));
  1699. a_label(list,hl);
  1700. ovloc.loc:=LOC_FLAGS;
  1701. end
  1702. else
  1703. list.concat(taicpu.op_reg(A_CLR,NR_R1));
  1704. cg.a_reg_dealloc(list,NR_R1);
  1705. list.concat(taicpu.op_reg_reg(A_MOV,dst,NR_R0));
  1706. cg.a_reg_dealloc(list,NR_R0);
  1707. end
  1708. else if (CPUAVR_HAS_MUL in cpu_capabilities[current_settings.cputype]) and
  1709. (op=OP_IMUL) then
  1710. begin
  1711. cg.a_reg_alloc(list,NR_R0);
  1712. cg.a_reg_alloc(list,NR_R1);
  1713. list.concat(taicpu.op_reg_reg(A_MULS,src1,src2));
  1714. list.concat(taicpu.op_reg_reg(A_MOV,dst,NR_R0));
  1715. // Check overflow
  1716. if check_overflow then
  1717. begin
  1718. current_asmdata.getjumplabel(no_overflow);
  1719. list.concat(taicpu.op_reg_const(A_SBRC,NR_R0,7));
  1720. list.concat(taicpu.op_reg(A_INC,NR_R1));
  1721. list.concat(taicpu.op_reg(A_TST,NR_R1));
  1722. ai:=Taicpu.Op_Sym(A_BRxx,no_overflow);
  1723. ai.SetCondition(C_EQ);
  1724. ai.is_jmp:=true;
  1725. list.concat(ai);
  1726. list.concat(taicpu.op_reg(A_CLR,NR_R1));
  1727. a_call_name(list,'FPC_OVERFLOW',false);
  1728. a_label(list,no_overflow);
  1729. ovloc.loc:=LOC_VOID;
  1730. end
  1731. else
  1732. list.concat(taicpu.op_reg(A_CLR,NR_R1));
  1733. cg.a_reg_dealloc(list,NR_R1);
  1734. cg.a_reg_dealloc(list,NR_R0);
  1735. end
  1736. else
  1737. begin
  1738. if size=OS_8 then
  1739. name:='fpc_mul_byte'
  1740. else
  1741. name:='fpc_mul_shortint';
  1742. if check_overflow then
  1743. name:=name+'_checkoverflow';
  1744. pd:=search_system_proc(name);
  1745. paraloc1.init;
  1746. paraloc2.init;
  1747. paramanager.getintparaloc(list,pd,1,paraloc1);
  1748. paramanager.getintparaloc(list,pd,2,paraloc2);
  1749. a_load_reg_cgpara(list,OS_8,src1,paraloc2);
  1750. a_load_reg_cgpara(list,OS_8,src2,paraloc1);
  1751. paramanager.freecgpara(list,paraloc2);
  1752. paramanager.freecgpara(list,paraloc1);
  1753. alloccpuregisters(list,R_INTREGISTER,paramanager.get_volatile_registers_int(pocall_default));
  1754. a_call_name(list,upper(name),false);
  1755. dealloccpuregisters(list,R_INTREGISTER,paramanager.get_volatile_registers_int(pocall_default));
  1756. cg.a_reg_alloc(list,NR_R24);
  1757. cg.a_load_reg_reg(list,OS_8,OS_8,NR_R24,dst);
  1758. cg.a_reg_dealloc(list,NR_R24);
  1759. paraloc2.done;
  1760. paraloc1.done;
  1761. end;
  1762. end
  1763. else if size in [OS_16,OS_S16] then
  1764. begin
  1765. if (CPUAVR_HAS_MUL in cpu_capabilities[current_settings.cputype]) and
  1766. ((not check_overflow) or
  1767. (size=OS_16)) then
  1768. begin
  1769. if check_overflow then
  1770. begin
  1771. current_asmdata.getjumplabel(hl);
  1772. current_asmdata.getjumplabel(no_overflow);
  1773. end;
  1774. cg.a_reg_alloc(list,NR_R0);
  1775. cg.a_reg_alloc(list,NR_R1);
  1776. list.concat(taicpu.op_reg_reg(A_MUL,src2,src1));
  1777. emit_mov(list,dst,NR_R0);
  1778. emit_mov(list,GetNextReg(dst),NR_R1);
  1779. list.concat(taicpu.op_reg_reg(A_MUL,GetNextReg(src1),src2));
  1780. perform_r1_check(hl);
  1781. list.concat(taicpu.op_reg_reg(A_ADD,GetNextReg(dst),NR_R0));
  1782. perform_ovf_check(hl);
  1783. list.concat(taicpu.op_reg_reg(A_MUL,src1,GetNextReg(src2)));
  1784. perform_r1_check(hl);
  1785. list.concat(taicpu.op_reg_reg(A_ADD,GetNextReg(dst),NR_R0));
  1786. perform_ovf_check(hl);
  1787. if check_overflow then
  1788. begin
  1789. list.concat(taicpu.op_reg_reg(A_MUL,GetNextReg(src1),GetNextReg(src2)));
  1790. perform_r1_check(hl,NR_R0);
  1791. end;
  1792. cg.a_reg_dealloc(list,NR_R0);
  1793. list.concat(taicpu.op_reg(A_CLR,NR_R1));
  1794. if check_overflow then
  1795. begin
  1796. {
  1797. CLV/CLC
  1798. JMP no_overflow
  1799. .hl:
  1800. CLR R1
  1801. SEV/SEC
  1802. .no_overflow:
  1803. }
  1804. if op=OP_MUL then
  1805. list.concat(taicpu.op_none(A_CLC))
  1806. else
  1807. list.concat(taicpu.op_none(A_CLV));
  1808. a_jmp_always(list,no_overflow);
  1809. a_label(list,hl);
  1810. list.concat(taicpu.op_reg(A_CLR,NR_R1));
  1811. if op=OP_MUL then
  1812. list.concat(taicpu.op_none(A_SEC))
  1813. else
  1814. list.concat(taicpu.op_none(A_SEV));
  1815. a_label(list,no_overflow);
  1816. ovloc.loc:=LOC_FLAGS;
  1817. end;
  1818. cg.a_reg_dealloc(list,NR_R1);
  1819. end
  1820. else
  1821. begin
  1822. if size=OS_16 then
  1823. name:='fpc_mul_word'
  1824. else
  1825. name:='fpc_mul_integer';
  1826. if check_overflow then
  1827. name:=name+'_checkoverflow';
  1828. pd:=search_system_proc(name);
  1829. paraloc1.init;
  1830. paraloc2.init;
  1831. paramanager.getintparaloc(list,pd,1,paraloc1);
  1832. paramanager.getintparaloc(list,pd,2,paraloc2);
  1833. a_load_reg_cgpara(list,OS_16,src1,paraloc2);
  1834. a_load_reg_cgpara(list,OS_16,src2,paraloc1);
  1835. paramanager.freecgpara(list,paraloc2);
  1836. paramanager.freecgpara(list,paraloc1);
  1837. alloccpuregisters(list,R_INTREGISTER,paramanager.get_volatile_registers_int(pocall_default));
  1838. a_call_name(list,upper(name),false);
  1839. dealloccpuregisters(list,R_INTREGISTER,paramanager.get_volatile_registers_int(pocall_default));
  1840. cg.a_reg_alloc(list,NR_R24);
  1841. cg.a_reg_alloc(list,NR_R25);
  1842. cg.a_load_reg_reg(list,OS_8,OS_8,NR_R24,dst);
  1843. cg.a_reg_dealloc(list,NR_R24);
  1844. cg.a_load_reg_reg(list,OS_8,OS_8,NR_R25,GetNextReg(dst));
  1845. cg.a_reg_dealloc(list,NR_R25);
  1846. paraloc2.done;
  1847. paraloc1.done;
  1848. end;
  1849. end
  1850. else
  1851. internalerror(2011022002);
  1852. end;
  1853. procedure tcgavr.g_proc_entry(list : TAsmList;localsize : longint;nostackframe:boolean);
  1854. var
  1855. regs : tcpuregisterset;
  1856. reg : tsuperregister;
  1857. begin
  1858. if current_procinfo.procdef.isempty then
  1859. exit;
  1860. if (po_interrupt in current_procinfo.procdef.procoptions) and
  1861. (not nostackframe) then
  1862. begin
  1863. { check if the framepointer is actually used, this is done here because
  1864. we have to know the size of the locals (must be 0), avr does not know
  1865. an sp based stack }
  1866. if not(current_procinfo.procdef.stack_tainting_parameter(calleeside)) and
  1867. (localsize=0) then
  1868. current_procinfo.framepointer:=NR_NO;
  1869. { save int registers,
  1870. but only if the procedure returns }
  1871. if not(po_noreturn in current_procinfo.procdef.procoptions) then
  1872. regs:=rg[R_INTREGISTER].used_in_proc
  1873. else
  1874. regs:=[];
  1875. { if the framepointer is potentially used, save it always because we need a proper stack frame,
  1876. even if the procedure never returns, the procedure could be e.g. a nested one accessing
  1877. an outer stackframe }
  1878. if current_procinfo.framepointer<>NR_NO then
  1879. regs:=regs+[RS_R28,RS_R29];
  1880. { we clear r1 }
  1881. include(regs,RS_R1);
  1882. regs:=regs+[RS_R0];
  1883. for reg:=RS_R31 downto RS_R0 do
  1884. if reg in regs then
  1885. list.concat(taicpu.op_reg(A_PUSH,newreg(R_INTREGISTER,reg,R_SUBWHOLE)));
  1886. { Save SREG }
  1887. cg.getcpuregister(list,NR_R0);
  1888. list.concat(taicpu.op_reg_const(A_IN, NR_R0, $3F));
  1889. list.concat(taicpu.op_reg(A_PUSH, NR_R0));
  1890. cg.ungetcpuregister(list,NR_R0);
  1891. list.concat(taicpu.op_reg(A_CLR,NR_R1));
  1892. if current_procinfo.framepointer<>NR_NO then
  1893. begin
  1894. cg.getcpuregister(list,NR_R28);
  1895. list.concat(taicpu.op_reg_const(A_IN,NR_R28,NIO_SP_LO));
  1896. cg.getcpuregister(list,NR_R29);
  1897. list.concat(taicpu.op_reg_const(A_IN,NR_R29,NIO_SP_HI));
  1898. a_adjust_sp(list,-localsize);
  1899. end;
  1900. end
  1901. else if not(nostackframe) then
  1902. begin
  1903. { check if the framepointer is actually used, this is done here because
  1904. we have to know the size of the locals (must be 0), avr does not know
  1905. an sp based stack }
  1906. if not(current_procinfo.procdef.stack_tainting_parameter(calleeside)) and
  1907. (localsize=0) then
  1908. current_procinfo.framepointer:=NR_NO;
  1909. { save int registers,
  1910. but only if the procedure returns }
  1911. if not(po_noreturn in current_procinfo.procdef.procoptions) then
  1912. regs:=rg[R_INTREGISTER].used_in_proc-paramanager.get_volatile_registers_int(pocall_stdcall)
  1913. else
  1914. regs:=[];
  1915. { if the framepointer is potentially used, save it always because we need a proper stack frame,
  1916. even if the procedure never returns, the procedure could be e.g. a nested one accessing
  1917. an outer stackframe }
  1918. if current_procinfo.framepointer<>NR_NO then
  1919. regs:=regs+[RS_R28,RS_R29];
  1920. for reg:=RS_R31 downto RS_R0 do
  1921. if reg in regs then
  1922. list.concat(taicpu.op_reg(A_PUSH,newreg(R_INTREGISTER,reg,R_SUBWHOLE)));
  1923. if current_procinfo.framepointer<>NR_NO then
  1924. begin
  1925. cg.getcpuregister(list,NR_R28);
  1926. list.concat(taicpu.op_reg_const(A_IN,NR_R28,NIO_SP_LO));
  1927. cg.getcpuregister(list,NR_R29);
  1928. list.concat(taicpu.op_reg_const(A_IN,NR_R29,NIO_SP_HI));
  1929. a_adjust_sp(list,-localsize);
  1930. end;
  1931. end;
  1932. end;
  1933. procedure tcgavr.g_proc_exit(list : TAsmList;parasize : longint;nostackframe:boolean);
  1934. var
  1935. regs : tcpuregisterset;
  1936. reg : TSuperRegister;
  1937. LocalSize : longint;
  1938. begin
  1939. { every byte counts for avr, so if a subroutine is marked as non-returning, we do
  1940. not generate any exit code, so we really trust the noreturn directive
  1941. }
  1942. if po_noreturn in current_procinfo.procdef.procoptions then
  1943. exit;
  1944. if po_interrupt in current_procinfo.procdef.procoptions then
  1945. begin
  1946. if not(current_procinfo.procdef.isempty) and
  1947. (not nostackframe) then
  1948. begin
  1949. regs:=rg[R_INTREGISTER].used_in_proc;
  1950. if current_procinfo.framepointer<>NR_NO then
  1951. begin
  1952. regs:=regs+[RS_R28,RS_R29];
  1953. LocalSize:=current_procinfo.calc_stackframe_size;
  1954. a_adjust_sp(list,LocalSize);
  1955. end;
  1956. { we clear r1 }
  1957. include(regs,RS_R1);
  1958. { Reload SREG }
  1959. regs:=regs+[RS_R0];
  1960. cg.getcpuregister(list,NR_R0);
  1961. list.concat(taicpu.op_reg(A_POP, NR_R0));
  1962. list.concat(taicpu.op_const_reg(A_OUT, $3F, NR_R0));
  1963. cg.ungetcpuregister(list,NR_R0);
  1964. for reg:=RS_R0 to RS_R31 do
  1965. if reg in regs then
  1966. list.concat(taicpu.op_reg(A_POP,newreg(R_INTREGISTER,reg,R_SUBWHOLE)));
  1967. end;
  1968. list.concat(taicpu.op_none(A_RETI));
  1969. end
  1970. else if not(nostackframe) and not(current_procinfo.procdef.isempty) then
  1971. begin
  1972. regs:=rg[R_INTREGISTER].used_in_proc-paramanager.get_volatile_registers_int(pocall_stdcall);
  1973. if current_procinfo.framepointer<>NR_NO then
  1974. begin
  1975. regs:=regs+[RS_R28,RS_R29];
  1976. LocalSize:=current_procinfo.calc_stackframe_size;
  1977. a_adjust_sp(list,LocalSize);
  1978. end;
  1979. for reg:=RS_R0 to RS_R31 do
  1980. if reg in regs then
  1981. list.concat(taicpu.op_reg(A_POP,newreg(R_INTREGISTER,reg,R_SUBWHOLE)));
  1982. list.concat(taicpu.op_none(A_RET));
  1983. end
  1984. else
  1985. list.concat(taicpu.op_none(A_RET));
  1986. end;
  1987. procedure tcgavr.a_loadaddr_ref_reg(list : TAsmList;const ref : treference;r : tregister);
  1988. var
  1989. tmpref : treference;
  1990. begin
  1991. if ref.addressmode<>AM_UNCHANGED then
  1992. internalerror(2011021701);
  1993. if assigned(ref.symbol) or (ref.offset<>0) then
  1994. begin
  1995. reference_reset(tmpref,0,[]);
  1996. tmpref.symbol:=ref.symbol;
  1997. tmpref.offset:=ref.offset;
  1998. if assigned(ref.symbol) and (ref.symbol.typ in [AT_FUNCTION,AT_LABEL]) then
  1999. tmpref.refaddr:=addr_lo8_gs
  2000. else
  2001. tmpref.refaddr:=addr_lo8;
  2002. list.concat(taicpu.op_reg_ref(A_LDI,r,tmpref));
  2003. if assigned(ref.symbol) and (ref.symbol.typ in [AT_FUNCTION,AT_LABEL]) then
  2004. tmpref.refaddr:=addr_hi8_gs
  2005. else
  2006. tmpref.refaddr:=addr_hi8;
  2007. list.concat(taicpu.op_reg_ref(A_LDI,GetNextReg(r),tmpref));
  2008. if (ref.base<>NR_NO) then
  2009. begin
  2010. list.concat(taicpu.op_reg_reg(A_ADD,r,ref.base));
  2011. list.concat(taicpu.op_reg_reg(A_ADC,GetNextReg(r),GetNextReg(ref.base)));
  2012. end;
  2013. if (ref.index<>NR_NO) then
  2014. begin
  2015. list.concat(taicpu.op_reg_reg(A_ADD,r,ref.index));
  2016. list.concat(taicpu.op_reg_reg(A_ADC,GetNextReg(r),GetNextReg(ref.index)));
  2017. end;
  2018. end
  2019. else if (ref.base<>NR_NO)then
  2020. begin
  2021. emit_mov(list,r,ref.base);
  2022. emit_mov(list,GetNextReg(r),GetNextReg(ref.base));
  2023. if (ref.index<>NR_NO) then
  2024. begin
  2025. list.concat(taicpu.op_reg_reg(A_ADD,r,ref.index));
  2026. list.concat(taicpu.op_reg_reg(A_ADC,GetNextReg(r),GetNextReg(ref.index)));
  2027. end;
  2028. end
  2029. else if (ref.index<>NR_NO) then
  2030. begin
  2031. emit_mov(list,r,ref.index);
  2032. emit_mov(list,GetNextReg(r),GetNextReg(ref.index));
  2033. end;
  2034. end;
  2035. procedure tcgavr.fixref(list : TAsmList;var ref : treference);
  2036. begin
  2037. internalerror(2011021320);
  2038. end;
  2039. procedure tcgavr.g_concatcopy_move(list : TAsmList;const source,dest : treference;len : tcgint);
  2040. var
  2041. paraloc1,paraloc2,paraloc3 : TCGPara;
  2042. pd : tprocdef;
  2043. begin
  2044. pd:=search_system_proc('MOVE');
  2045. paraloc1.init;
  2046. paraloc2.init;
  2047. paraloc3.init;
  2048. paramanager.getintparaloc(list,pd,1,paraloc1);
  2049. paramanager.getintparaloc(list,pd,2,paraloc2);
  2050. paramanager.getintparaloc(list,pd,3,paraloc3);
  2051. a_load_const_cgpara(list,OS_SINT,len,paraloc3);
  2052. a_loadaddr_ref_cgpara(list,dest,paraloc2);
  2053. a_loadaddr_ref_cgpara(list,source,paraloc1);
  2054. paramanager.freecgpara(list,paraloc3);
  2055. paramanager.freecgpara(list,paraloc2);
  2056. paramanager.freecgpara(list,paraloc1);
  2057. alloccpuregisters(list,R_INTREGISTER,paramanager.get_volatile_registers_int(pocall_default));
  2058. a_call_name_static(list,'FPC_MOVE');
  2059. dealloccpuregisters(list,R_INTREGISTER,paramanager.get_volatile_registers_int(pocall_default));
  2060. paraloc3.done;
  2061. paraloc2.done;
  2062. paraloc1.done;
  2063. end;
  2064. procedure tcgavr.g_concatcopy(list : TAsmList;const source,dest : treference;len : tcgint);
  2065. var
  2066. countreg,tmpreg,tmpreg2: tregister;
  2067. srcref,dstref : treference;
  2068. copysize,countregsize : tcgsize;
  2069. l : TAsmLabel;
  2070. i : longint;
  2071. SrcQuickRef, DestQuickRef : Boolean;
  2072. begin
  2073. if len>16 then
  2074. begin
  2075. current_asmdata.getjumplabel(l);
  2076. reference_reset(srcref,source.alignment,source.volatility);
  2077. reference_reset(dstref,dest.alignment,source.volatility);
  2078. srcref.base:=NR_R30;
  2079. srcref.addressmode:=AM_POSTINCREMENT;
  2080. dstref.base:=NR_R26;
  2081. dstref.addressmode:=AM_POSTINCREMENT;
  2082. copysize:=OS_8;
  2083. if len<256 then
  2084. countregsize:=OS_8
  2085. else if len<65536 then
  2086. countregsize:=OS_16
  2087. else
  2088. internalerror(2011022007);
  2089. countreg:=getintregister(list,countregsize);
  2090. a_load_const_reg(list,countregsize,len,countreg);
  2091. cg.getcpuregister(list,NR_R30);
  2092. cg.getcpuregister(list,NR_R31);
  2093. a_loadaddr_ref_reg(list,source,NR_R30);
  2094. { only base or index register in dest? }
  2095. if ((dest.addressmode=AM_UNCHANGED) and (dest.offset=0) and not(assigned(dest.symbol))) and
  2096. ((dest.base<>NR_NO) xor (dest.index<>NR_NO)) then
  2097. begin
  2098. if dest.base<>NR_NO then
  2099. tmpreg:=dest.base
  2100. else if dest.index<>NR_NO then
  2101. tmpreg:=dest.index
  2102. else
  2103. internalerror(2016112001);
  2104. end
  2105. else
  2106. begin
  2107. tmpreg:=getaddressregister(list);
  2108. a_loadaddr_ref_reg(list,dest,tmpreg);
  2109. end;
  2110. { X is used for spilling code so we can load it
  2111. only by a push/pop sequence, this can be
  2112. optimized later on by the peephole optimizer
  2113. }
  2114. list.concat(taicpu.op_reg(A_PUSH,tmpreg));
  2115. list.concat(taicpu.op_reg(A_PUSH,GetNextReg(tmpreg)));
  2116. cg.getcpuregister(list,NR_R27);
  2117. list.concat(taicpu.op_reg(A_POP,NR_R27));
  2118. cg.getcpuregister(list,NR_R26);
  2119. list.concat(taicpu.op_reg(A_POP,NR_R26));
  2120. cg.a_label(list,l);
  2121. cg.getcpuregister(list,NR_R0);
  2122. list.concat(taicpu.op_reg_ref(GetLoad(srcref),NR_R0,srcref));
  2123. list.concat(taicpu.op_ref_reg(GetStore(dstref),dstref,NR_R0));
  2124. cg.ungetcpuregister(list,NR_R0);
  2125. list.concat(taicpu.op_reg(A_DEC,countreg));
  2126. a_jmp_flags(list,F_NE,l);
  2127. cg.ungetcpuregister(list,NR_R26);
  2128. cg.ungetcpuregister(list,NR_R27);
  2129. cg.ungetcpuregister(list,NR_R30);
  2130. cg.ungetcpuregister(list,NR_R31);
  2131. // keep registers alive
  2132. list.concat(taicpu.op_reg_reg(A_MOV,countreg,countreg));
  2133. end
  2134. else
  2135. begin
  2136. SrcQuickRef:=false;
  2137. DestQuickRef:=false;
  2138. if not((source.addressmode=AM_UNCHANGED) and
  2139. (source.symbol=nil) and
  2140. ((source.base=NR_R28) or
  2141. (source.base=NR_R30)) and
  2142. (source.Index=NR_NO) and
  2143. (source.Offset in [0..64-len])) and
  2144. not((source.Base=NR_NO) and (source.Index=NR_NO)) then
  2145. begin
  2146. cg.getcpuregister(list,NR_R30);
  2147. cg.getcpuregister(list,NR_R31);
  2148. srcref:=normalize_ref(list,source,NR_R30)
  2149. end
  2150. else
  2151. begin
  2152. SrcQuickRef:=true;
  2153. srcref:=source;
  2154. end;
  2155. if not((dest.addressmode=AM_UNCHANGED) and
  2156. (dest.symbol=nil) and
  2157. ((dest.base=NR_R28) or
  2158. (dest.base=NR_R30)) and
  2159. (dest.Index=NR_No) and
  2160. (dest.Offset in [0..64-len])) and
  2161. not((dest.Base=NR_NO) and (dest.Index=NR_NO)) then
  2162. begin
  2163. if not(SrcQuickRef) then
  2164. begin
  2165. { only base or index register in dest? }
  2166. if ((dest.addressmode=AM_UNCHANGED) and (dest.offset=0) and not(assigned(dest.symbol))) and
  2167. ((dest.base<>NR_NO) xor (dest.index<>NR_NO)) then
  2168. begin
  2169. if dest.base<>NR_NO then
  2170. tmpreg:=dest.base
  2171. else if dest.index<>NR_NO then
  2172. tmpreg:=dest.index
  2173. else
  2174. internalerror(2016112002);
  2175. end
  2176. else
  2177. tmpreg:=getaddressregister(list);
  2178. dstref:=normalize_ref(list,dest,tmpreg);
  2179. { X is used for spilling code so we can load it
  2180. only by a push/pop sequence, this can be
  2181. optimized later on by the peephole optimizer
  2182. }
  2183. list.concat(taicpu.op_reg(A_PUSH,tmpreg));
  2184. list.concat(taicpu.op_reg(A_PUSH,GetNextReg(tmpreg)));
  2185. cg.getcpuregister(list,NR_R27);
  2186. list.concat(taicpu.op_reg(A_POP,NR_R27));
  2187. cg.getcpuregister(list,NR_R26);
  2188. list.concat(taicpu.op_reg(A_POP,NR_R26));
  2189. dstref.base:=NR_R26;
  2190. end
  2191. else
  2192. begin
  2193. cg.getcpuregister(list,NR_R30);
  2194. cg.getcpuregister(list,NR_R31);
  2195. dstref:=normalize_ref(list,dest,NR_R30);
  2196. end;
  2197. end
  2198. else
  2199. begin
  2200. DestQuickRef:=true;
  2201. dstref:=dest;
  2202. end;
  2203. // CC
  2204. // If dest is an ioreg (31 < offset < srambase) and size = 16 bit then
  2205. // load high byte first, then low byte
  2206. if (len = 2) and DestQuickRef
  2207. and (dest.offset > 31)
  2208. and (dest.offset < cpuinfo.embedded_controllers[current_settings.controllertype].srambase) then
  2209. begin
  2210. // If src is also a 16 bit ioreg then read low byte then high byte
  2211. if SrcQuickRef and (srcref.offset > 31)
  2212. and (srcref.offset < cpuinfo.embedded_controllers[current_settings.controllertype].srambase) then
  2213. begin
  2214. // First read source into temp registers
  2215. tmpreg:=getintregister(list, OS_16);
  2216. list.concat(taicpu.op_reg_ref(GetLoad(srcref),tmpreg,srcref));
  2217. inc(srcref.offset);
  2218. tmpreg2:=GetNextReg(tmpreg);
  2219. list.concat(taicpu.op_reg_ref(GetLoad(srcref),tmpreg2,srcref));
  2220. // then move temp registers to dest in reverse order
  2221. inc(dstref.offset);
  2222. list.concat(taicpu.op_ref_reg(GetStore(dstref),dstref,tmpreg2));
  2223. dec(dstref.offset);
  2224. list.concat(taicpu.op_ref_reg(GetStore(dstref),dstref,tmpreg));
  2225. end
  2226. else
  2227. begin
  2228. srcref.addressmode:=AM_UNCHANGED;
  2229. inc(srcref.offset);
  2230. dstref.addressmode:=AM_UNCHANGED;
  2231. inc(dstref.offset);
  2232. cg.getcpuregister(list,NR_R0);
  2233. list.concat(taicpu.op_reg_ref(GetLoad(srcref),NR_R0,srcref));
  2234. list.concat(taicpu.op_ref_reg(GetStore(dstref),dstref,NR_R0));
  2235. cg.ungetcpuregister(list,NR_R0);
  2236. if not(SrcQuickRef) then
  2237. srcref.addressmode:=AM_POSTINCREMENT
  2238. else
  2239. srcref.addressmode:=AM_UNCHANGED;
  2240. dec(srcref.offset);
  2241. dec(dstref.offset);
  2242. cg.getcpuregister(list,NR_R0);
  2243. list.concat(taicpu.op_reg_ref(GetLoad(srcref),NR_R0,srcref));
  2244. list.concat(taicpu.op_ref_reg(GetStore(dstref),dstref,NR_R0));
  2245. cg.ungetcpuregister(list,NR_R0);
  2246. end;
  2247. end
  2248. else
  2249. for i:=1 to len do
  2250. begin
  2251. if not(SrcQuickRef) and (i<len) then
  2252. srcref.addressmode:=AM_POSTINCREMENT
  2253. else
  2254. srcref.addressmode:=AM_UNCHANGED;
  2255. if not(DestQuickRef) and (i<len) then
  2256. dstref.addressmode:=AM_POSTINCREMENT
  2257. else
  2258. dstref.addressmode:=AM_UNCHANGED;
  2259. cg.getcpuregister(list,NR_R0);
  2260. list.concat(taicpu.op_reg_ref(GetLoad(srcref),NR_R0,srcref));
  2261. list.concat(taicpu.op_ref_reg(GetStore(dstref),dstref,NR_R0));
  2262. cg.ungetcpuregister(list,NR_R0);
  2263. if SrcQuickRef then
  2264. inc(srcref.offset);
  2265. if DestQuickRef then
  2266. inc(dstref.offset);
  2267. end;
  2268. if not(SrcQuickRef) then
  2269. begin
  2270. ungetcpuregister(list,srcref.base);
  2271. ungetcpuregister(list,TRegister(ord(srcref.base)+1));
  2272. end;
  2273. if not(DestQuickRef) then
  2274. begin
  2275. ungetcpuregister(list,dstref.base);
  2276. ungetcpuregister(list,TRegister(ord(dstref.base)+1));
  2277. end;
  2278. end;
  2279. end;
  2280. procedure tcgavr.g_overflowcheck(list: TAsmList; const l: tlocation; def: tdef);
  2281. var
  2282. hl : tasmlabel;
  2283. ai : taicpu;
  2284. cond : TAsmCond;
  2285. begin
  2286. if not(cs_check_overflow in current_settings.localswitches) then
  2287. exit;
  2288. current_asmdata.getjumplabel(hl);
  2289. if not ((def.typ=pointerdef) or
  2290. ((def.typ=orddef) and
  2291. (torddef(def).ordtype in [u64bit,u16bit,u32bit,u8bit,uchar,
  2292. pasbool1,pasbool8,pasbool16,pasbool32,pasbool64]))) then
  2293. cond:=C_VC
  2294. else
  2295. cond:=C_CC;
  2296. ai:=Taicpu.Op_Sym(A_BRxx,hl);
  2297. ai.SetCondition(cond);
  2298. ai.is_jmp:=true;
  2299. list.concat(ai);
  2300. a_call_name(list,'FPC_OVERFLOW',false);
  2301. a_label(list,hl);
  2302. end;
  2303. procedure tcgavr.g_overflowCheck_loc(List: TAsmList; const Loc: TLocation; def: TDef; ovloc: tlocation);
  2304. var
  2305. hl : tasmlabel;
  2306. ai : taicpu;
  2307. cond : TAsmCond;
  2308. begin
  2309. if not(cs_check_overflow in current_settings.localswitches) then
  2310. exit;
  2311. case ovloc.loc of
  2312. LOC_FLAGS:
  2313. begin
  2314. current_asmdata.getjumplabel(hl);
  2315. if not ((def.typ=pointerdef) or
  2316. ((def.typ=orddef) and
  2317. (torddef(def).ordtype in [u64bit,u16bit,u32bit,u8bit,uchar,
  2318. pasbool1,pasbool8,pasbool16,pasbool32,pasbool64]))) then
  2319. cond:=C_VC
  2320. else
  2321. cond:=C_CC;
  2322. ai:=Taicpu.Op_Sym(A_BRxx,hl);
  2323. ai.SetCondition(cond);
  2324. ai.is_jmp:=true;
  2325. list.concat(ai);
  2326. a_call_name(list,'FPC_OVERFLOW',false);
  2327. a_label(list,hl);
  2328. end;
  2329. end;
  2330. end;
  2331. procedure tcgavr.g_save_registers(list: TAsmList);
  2332. begin
  2333. { this is done by the entry code }
  2334. end;
  2335. procedure tcgavr.g_restore_registers(list: TAsmList);
  2336. begin
  2337. { this is done by the exit code }
  2338. end;
  2339. procedure tcgavr.a_jmp_cond(list : TAsmList;cond : TOpCmp;l: tasmlabel);
  2340. var
  2341. ai1,ai2 : taicpu;
  2342. hl : TAsmLabel;
  2343. begin
  2344. ai1:=Taicpu.Op_sym(A_BRxx,l);
  2345. ai1.is_jmp:=true;
  2346. hl:=nil;
  2347. case cond of
  2348. OC_EQ:
  2349. ai1.SetCondition(C_EQ);
  2350. OC_GT:
  2351. begin
  2352. { emulate GT }
  2353. current_asmdata.getjumplabel(hl);
  2354. ai2:=Taicpu.Op_Sym(A_BRxx,hl);
  2355. ai2.SetCondition(C_EQ);
  2356. ai2.is_jmp:=true;
  2357. list.concat(ai2);
  2358. ai1.SetCondition(C_GE);
  2359. end;
  2360. OC_LT:
  2361. ai1.SetCondition(C_LT);
  2362. OC_GTE:
  2363. ai1.SetCondition(C_GE);
  2364. OC_LTE:
  2365. begin
  2366. { emulate LTE }
  2367. ai2:=Taicpu.Op_Sym(A_BRxx,l);
  2368. ai2.SetCondition(C_EQ);
  2369. ai2.is_jmp:=true;
  2370. list.concat(ai2);
  2371. ai1.SetCondition(C_LT);
  2372. end;
  2373. OC_NE:
  2374. ai1.SetCondition(C_NE);
  2375. OC_BE:
  2376. begin
  2377. { emulate BE }
  2378. ai2:=Taicpu.Op_Sym(A_BRxx,l);
  2379. ai2.SetCondition(C_EQ);
  2380. ai2.is_jmp:=true;
  2381. list.concat(ai2);
  2382. ai1.SetCondition(C_LO);
  2383. end;
  2384. OC_B:
  2385. ai1.SetCondition(C_LO);
  2386. OC_AE:
  2387. ai1.SetCondition(C_SH);
  2388. OC_A:
  2389. begin
  2390. { emulate A (unsigned GT) }
  2391. current_asmdata.getjumplabel(hl);
  2392. ai2:=Taicpu.Op_Sym(A_BRxx,hl);
  2393. ai2.SetCondition(C_EQ);
  2394. ai2.is_jmp:=true;
  2395. list.concat(ai2);
  2396. ai1.SetCondition(C_SH);
  2397. end;
  2398. else
  2399. internalerror(2011082501);
  2400. end;
  2401. list.concat(ai1);
  2402. if assigned(hl) then
  2403. a_label(list,hl);
  2404. end;
  2405. procedure tcgavr.emit_mov(list: TAsmList;reg2: tregister; reg1: tregister);
  2406. var
  2407. instr: taicpu;
  2408. begin
  2409. instr:=taicpu.op_reg_reg(A_MOV,reg2,reg1);
  2410. list.Concat(instr);
  2411. { Notify the register allocator that we have written a move instruction so
  2412. it can try to eliminate it. }
  2413. add_move_instruction(instr);
  2414. end;
  2415. procedure tcg64favr.a_op64_reg_reg(list : TAsmList;op:TOpCG;size : tcgsize;regsrc,regdst : tregister64);
  2416. begin
  2417. if not(size in [OS_S64,OS_64]) then
  2418. internalerror(2012102402);
  2419. tcgavr(cg).a_op_reg_reg_internal(list,Op,size,regsrc.reglo,regsrc.reghi,regdst.reglo,regdst.reghi);
  2420. end;
  2421. procedure tcg64favr.a_op64_const_reg(list : TAsmList;op:TOpCG;size : tcgsize;value : int64;reg : tregister64);
  2422. begin
  2423. tcgavr(cg).a_op_const_reg_internal(list,Op,size,value,reg.reglo,reg.reghi);
  2424. end;
  2425. procedure create_codegen;
  2426. begin
  2427. cg:=tcgavr.create;
  2428. cg64:=tcg64favr.create;
  2429. end;
  2430. end.