cgcpu.pas 106 KB

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