cgcpu.pas 108 KB

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