cgcpu.pas 105 KB

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