cgai386.pas 146 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158315931603161316231633164316531663167316831693170317131723173317431753176317731783179318031813182318331843185318631873188318931903191319231933194319531963197319831993200320132023203320432053206320732083209321032113212321332143215321632173218321932203221322232233224322532263227322832293230323132323233323432353236323732383239324032413242324332443245324632473248324932503251325232533254325532563257325832593260326132623263326432653266326732683269327032713272327332743275327632773278327932803281328232833284328532863287328832893290329132923293329432953296329732983299330033013302330333043305330633073308330933103311331233133314331533163317331833193320332133223323332433253326332733283329333033313332333333343335333633373338333933403341334233433344334533463347334833493350335133523353335433553356335733583359336033613362336333643365336633673368336933703371337233733374337533763377337833793380338133823383338433853386338733883389339033913392339333943395339633973398339934003401340234033404340534063407340834093410341134123413341434153416341734183419342034213422342334243425342634273428342934303431343234333434343534363437343834393440344134423443344434453446344734483449345034513452345334543455345634573458345934603461346234633464346534663467346834693470347134723473347434753476347734783479348034813482348334843485348634873488348934903491349234933494349534963497349834993500350135023503350435053506350735083509351035113512351335143515351635173518351935203521352235233524352535263527352835293530353135323533353435353536353735383539354035413542354335443545354635473548354935503551355235533554355535563557355835593560356135623563356435653566356735683569357035713572357335743575357635773578357935803581358235833584358535863587358835893590359135923593359435953596359735983599360036013602360336043605360636073608360936103611361236133614361536163617361836193620362136223623362436253626362736283629363036313632363336343635363636373638363936403641364236433644364536463647364836493650365136523653365436553656365736583659366036613662366336643665366636673668366936703671367236733674367536763677367836793680368136823683368436853686368736883689369036913692369336943695369636973698369937003701370237033704370537063707370837093710371137123713371437153716371737183719372037213722372337243725372637273728372937303731373237333734373537363737373837393740374137423743374437453746374737483749375037513752375337543755375637573758375937603761376237633764376537663767376837693770377137723773377437753776377737783779378037813782378337843785378637873788378937903791379237933794379537963797379837993800380138023803380438053806380738083809381038113812381338143815381638173818381938203821382238233824382538263827382838293830383138323833383438353836383738383839384038413842384338443845384638473848384938503851385238533854385538563857385838593860386138623863386438653866386738683869387038713872387338743875387638773878387938803881388238833884
  1. {
  2. $Id$
  3. Copyright (c) 1998-2000 by Florian Klaempfl
  4. Helper routines for the i386 code generator
  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. unit cgai386;
  18. interface
  19. uses
  20. cobjects,tree,
  21. cpubase,cpuasm,
  22. symconst,symtable,aasm;
  23. {$define TESTGETTEMP to store const that
  24. are written into temps for later release PM }
  25. function def_opsize(p1:pdef):topsize;
  26. function def2def_opsize(p1,p2:pdef):topsize;
  27. function def_getreg(p1:pdef):tregister;
  28. function makereg8(r:tregister):tregister;
  29. function makereg16(r:tregister):tregister;
  30. function makereg32(r:tregister):tregister;
  31. procedure emitlab(var l : pasmlabel);
  32. procedure emitjmp(c : tasmcond;var l : pasmlabel);
  33. procedure emit_flag2reg(flag:tresflags;hregister:tregister);
  34. procedure emit_none(i : tasmop;s : topsize);
  35. procedure emit_const(i : tasmop;s : topsize;c : longint);
  36. procedure emit_reg(i : tasmop;s : topsize;reg : tregister);
  37. procedure emit_ref(i : tasmop;s : topsize;ref : preference);
  38. procedure emit_const_reg(i : tasmop;s : topsize;c : longint;reg : tregister);
  39. procedure emit_const_ref(i : tasmop;s : topsize;c : longint;ref : preference);
  40. procedure emit_ref_reg(i : tasmop;s : topsize;ref : preference;reg : tregister);
  41. procedure emit_reg_ref(i : tasmop;s : topsize;reg : tregister;ref : preference);
  42. procedure emit_reg_reg(i : tasmop;s : topsize;reg1,reg2 : tregister);
  43. procedure emit_const_reg_reg(i : tasmop;s : topsize;c : longint;reg1,reg2 : tregister);
  44. procedure emit_reg_reg_reg(i : tasmop;s : topsize;reg1,reg2,reg3 : tregister);
  45. procedure emit_sym(i : tasmop;s : topsize;op : pasmsymbol);
  46. procedure emit_sym_ofs(i : tasmop;s : topsize;op : pasmsymbol;ofs : longint);
  47. procedure emit_sym_ofs_reg(i : tasmop;s : topsize;op : pasmsymbol;ofs:longint;reg : tregister);
  48. procedure emit_sym_ofs_ref(i : tasmop;s : topsize;op : pasmsymbol;ofs:longint;ref : preference);
  49. procedure emitcall(const routine:string);
  50. procedure emit_mov_loc_ref(const t:tlocation;const ref:treference;siz:topsize);
  51. procedure emit_mov_loc_reg(const t:tlocation;reg:tregister);
  52. procedure emit_mov_ref_reg64(r : treference;rl,rh : tregister);
  53. procedure emit_lea_loc_ref(const t:tlocation;const ref:treference;freetemp:boolean);
  54. procedure emit_lea_loc_reg(const t:tlocation;reg:tregister;freetemp:boolean);
  55. procedure emit_push_loc(const t:tlocation);
  56. { pushes qword location to the stack }
  57. procedure emit_pushq_loc(const t : tlocation);
  58. procedure release_qword_loc(const t : tlocation);
  59. { remove non regvar registers in loc from regs (in the format }
  60. { pushusedregisters uses) }
  61. procedure remove_non_regvars_from_loc(const t: tlocation; var regs: byte);
  62. { releases the registers of a location }
  63. procedure release_loc(const t : tlocation);
  64. procedure emit_pushw_loc(const t:tlocation);
  65. procedure emit_push_lea_loc(const t:tlocation;freetemp:boolean);
  66. procedure emit_to_mem(var p:ptree);
  67. procedure emit_to_reg16(var hr:tregister);
  68. procedure emit_to_reg32(var hr:tregister);
  69. procedure emit_mov_reg_loc(reg: TRegister; const t:tlocation);
  70. procedure emit_movq_reg_loc(reghigh,reglow: TRegister;t:tlocation);
  71. procedure copyshortstring(const dref,sref : treference;len : byte;loadref:boolean);
  72. procedure loadansistring(p : ptree);
  73. procedure finalize(t : pdef;const ref : treference;is_already_ref : boolean);
  74. procedure decrstringref(t : pdef;const ref : treference);
  75. function maybe_push(needed : byte;p : ptree;isint64 : boolean) : boolean;
  76. procedure push_int(l : longint);
  77. procedure emit_push_mem(const ref : treference);
  78. procedure emitpushreferenceaddr(const ref : treference);
  79. procedure pushsetelement(p : ptree);
  80. procedure restore(p : ptree;isint64 : boolean);
  81. procedure push_value_para(p:ptree;inlined:boolean;para_offset:longint;alignment : longint);
  82. {$ifdef TEMPS_NOT_PUSH}
  83. { does the same as restore/ , but uses temp. space instead of pushing }
  84. function maybe_push(needed : byte;p : ptree;isint64 : boolean) : boolean;
  85. procedure restorefromtemp(p : ptree;isint64 : boolean);
  86. {$endif TEMPS_NOT_PUSH}
  87. procedure floatload(t : tfloattype;const ref : treference);
  88. procedure floatstore(t : tfloattype;const ref : treference);
  89. procedure floatloadops(t : tfloattype;var op : tasmop;var s : topsize);
  90. procedure floatstoreops(t : tfloattype;var op : tasmop;var s : topsize);
  91. procedure maybe_loadesi;
  92. procedure maketojumpbool(p : ptree);
  93. procedure emitloadord2reg(const location:Tlocation;orddef:Porddef;destreg:Tregister;delloc:boolean);
  94. procedure emitoverflowcheck(p:ptree);
  95. procedure emitrangecheck(p:ptree;todef:pdef);
  96. procedure concatcopy(source,dest : treference;size : longint;delsource : boolean;loadref:boolean);
  97. procedure firstcomplex(p : ptree);
  98. procedure genentrycode(alist : paasmoutput;const proc_names:Tstringcontainer;make_global:boolean;
  99. stackframe:longint;
  100. var parasize:longint;var nostackframe:boolean;
  101. inlined : boolean);
  102. procedure genexitcode(alist : paasmoutput;parasize:longint;
  103. nostackframe,inlined:boolean);
  104. {$ifdef test_dest_loc}
  105. const
  106. { used to avoid temporary assignments }
  107. dest_loc_known : boolean = false;
  108. in_dest_loc : boolean = false;
  109. dest_loc_tree : ptree = nil;
  110. var
  111. dest_loc : tlocation;
  112. procedure mov_reg_to_dest(p : ptree; s : topsize; reg : tregister);
  113. {$endif test_dest_loc}
  114. implementation
  115. uses
  116. strings,globtype,systems,globals,verbose,files,types,pbase,
  117. tgeni386,temp_gen,hcodegen,ppu
  118. {$ifdef GDB}
  119. ,gdb
  120. {$endif}
  121. {$ifndef NOTARGETWIN32}
  122. ,t_win32
  123. {$endif}
  124. ;
  125. {*****************************************************************************
  126. Helpers
  127. *****************************************************************************}
  128. function def_opsize(p1:pdef):topsize;
  129. begin
  130. case p1^.size of
  131. 1 : def_opsize:=S_B;
  132. 2 : def_opsize:=S_W;
  133. 4 : def_opsize:=S_L;
  134. else
  135. internalerror(78);
  136. end;
  137. end;
  138. function def2def_opsize(p1,p2:pdef):topsize;
  139. var
  140. o1 : topsize;
  141. begin
  142. case p1^.size of
  143. 1 : o1:=S_B;
  144. 2 : o1:=S_W;
  145. 4 : o1:=S_L;
  146. { I don't know if we need it (FK) }
  147. 8 : o1:=S_L;
  148. else
  149. internalerror(78);
  150. end;
  151. if assigned(p2) then
  152. begin
  153. case p2^.size of
  154. 1 : o1:=S_B;
  155. 2 : begin
  156. if o1=S_B then
  157. o1:=S_BW
  158. else
  159. o1:=S_W;
  160. end;
  161. 4,8:
  162. begin
  163. case o1 of
  164. S_B : o1:=S_BL;
  165. S_W : o1:=S_WL;
  166. end;
  167. end;
  168. end;
  169. end;
  170. def2def_opsize:=o1;
  171. end;
  172. function def_getreg(p1:pdef):tregister;
  173. begin
  174. case p1^.size of
  175. 1 : def_getreg:=reg32toreg8(getregister32);
  176. 2 : def_getreg:=reg32toreg16(getregister32);
  177. 4 : def_getreg:=getregister32;
  178. else
  179. internalerror(78);
  180. end;
  181. end;
  182. function makereg8(r:tregister):tregister;
  183. begin
  184. case r of
  185. R_EAX,R_EBX,R_ECX,R_EDX,R_EDI,R_ESI,R_ESP :
  186. makereg8:=reg32toreg8(r);
  187. R_AX,R_BX,R_CX,R_DX,R_DI,R_SI,R_SP :
  188. makereg8:=reg16toreg8(r);
  189. R_AL,R_BL,R_CL,R_DL :
  190. makereg8:=r;
  191. end;
  192. end;
  193. function makereg16(r:tregister):tregister;
  194. begin
  195. case r of
  196. R_EAX,R_EBX,R_ECX,R_EDX,R_EDI,R_ESI,R_ESP :
  197. makereg16:=reg32toreg16(r);
  198. R_AX,R_BX,R_CX,R_DX,R_DI,R_SI,R_SP :
  199. makereg16:=r;
  200. R_AL,R_BL,R_CL,R_DL :
  201. makereg16:=reg8toreg16(r);
  202. end;
  203. end;
  204. function makereg32(r:tregister):tregister;
  205. begin
  206. case r of
  207. R_EAX,R_EBX,R_ECX,R_EDX,R_EDI,R_ESI,R_ESP :
  208. makereg32:=r;
  209. R_AX,R_BX,R_CX,R_DX,R_DI,R_SI,R_SP :
  210. makereg32:=reg16toreg32(r);
  211. R_AL,R_BL,R_CL,R_DL :
  212. makereg32:=reg8toreg32(r);
  213. end;
  214. end;
  215. {*****************************************************************************
  216. Emit Assembler
  217. *****************************************************************************}
  218. procedure emitlab(var l : pasmlabel);
  219. begin
  220. if not l^.is_set then
  221. exprasmlist^.concat(new(pai_label,init(l)))
  222. else
  223. internalerror(7453984);
  224. end;
  225. {$ifdef nojmpfix}
  226. procedure emitjmp(c : tasmcond;var l : pasmlabel);
  227. var
  228. ai : Paicpu;
  229. begin
  230. if c=C_None then
  231. exprasmlist^.concat(new(paicpu,op_sym(A_JMP,S_NO,l)))
  232. else
  233. begin
  234. ai:=new(paicpu,op_sym(A_Jcc,S_NO,l));
  235. ai^.SetCondition(c);
  236. ai^.is_jmp:=true;
  237. exprasmlist^.concat(ai);
  238. end;
  239. end;
  240. {$else nojmpfix}
  241. procedure emitjmp(c : tasmcond;var l : pasmlabel);
  242. var
  243. ai : Paicpu;
  244. begin
  245. if c=C_None then
  246. ai := new(paicpu,op_sym(A_JMP,S_NO,l))
  247. else
  248. begin
  249. ai:=new(paicpu,op_sym(A_Jcc,S_NO,l));
  250. ai^.SetCondition(c);
  251. end;
  252. ai^.is_jmp:=true;
  253. exprasmlist^.concat(ai);
  254. end;
  255. {$endif nojmpfix}
  256. procedure emit_flag2reg(flag:tresflags;hregister:tregister);
  257. var
  258. ai : paicpu;
  259. hreg : tregister;
  260. begin
  261. hreg:=makereg8(hregister);
  262. ai:=new(paicpu,op_reg(A_Setcc,S_B,hreg));
  263. ai^.SetCondition(flag_2_cond[flag]);
  264. exprasmlist^.concat(ai);
  265. if hreg<>hregister then
  266. begin
  267. if hregister in regset16bit then
  268. emit_to_reg16(hreg)
  269. else
  270. emit_to_reg32(hreg);
  271. end;
  272. end;
  273. procedure emit_none(i : tasmop;s : topsize);
  274. begin
  275. exprasmlist^.concat(new(paicpu,op_none(i,s)));
  276. end;
  277. procedure emit_reg(i : tasmop;s : topsize;reg : tregister);
  278. begin
  279. exprasmlist^.concat(new(paicpu,op_reg(i,s,reg)));
  280. end;
  281. procedure emit_ref(i : tasmop;s : topsize;ref : preference);
  282. begin
  283. exprasmlist^.concat(new(paicpu,op_ref(i,s,ref)));
  284. end;
  285. procedure emit_const(i : tasmop;s : topsize;c : longint);
  286. begin
  287. exprasmlist^.concat(new(paicpu,op_const(i,s,c)));
  288. end;
  289. procedure emit_const_reg(i : tasmop;s : topsize;c : longint;reg : tregister);
  290. begin
  291. exprasmlist^.concat(new(paicpu,op_const_reg(i,s,c,reg)));
  292. end;
  293. procedure emit_const_ref(i : tasmop;s : topsize;c : longint;ref : preference);
  294. begin
  295. exprasmlist^.concat(new(paicpu,op_const_ref(i,s,c,ref)));
  296. end;
  297. procedure emit_ref_reg(i : tasmop;s : topsize;ref : preference;reg : tregister);
  298. begin
  299. exprasmlist^.concat(new(paicpu,op_ref_reg(i,s,ref,reg)));
  300. end;
  301. procedure emit_reg_ref(i : tasmop;s : topsize;reg : tregister;ref : preference);
  302. begin
  303. exprasmlist^.concat(new(paicpu,op_reg_ref(i,s,reg,ref)));
  304. end;
  305. procedure emit_reg_reg(i : tasmop;s : topsize;reg1,reg2 : tregister);
  306. begin
  307. if (reg1<>reg2) or (i<>A_MOV) then
  308. exprasmlist^.concat(new(paicpu,op_reg_reg(i,s,reg1,reg2)));
  309. end;
  310. procedure emit_const_reg_reg(i : tasmop;s : topsize;c : longint;reg1,reg2 : tregister);
  311. begin
  312. exprasmlist^.concat(new(paicpu,op_const_reg_reg(i,s,c,reg1,reg2)));
  313. end;
  314. procedure emit_reg_reg_reg(i : tasmop;s : topsize;reg1,reg2,reg3 : tregister);
  315. begin
  316. exprasmlist^.concat(new(paicpu,op_reg_reg_reg(i,s,reg1,reg2,reg3)));
  317. end;
  318. procedure emit_sym(i : tasmop;s : topsize;op : pasmsymbol);
  319. begin
  320. exprasmlist^.concat(new(paicpu,op_sym(i,s,op)));
  321. end;
  322. procedure emit_sym_ofs(i : tasmop;s : topsize;op : pasmsymbol;ofs : longint);
  323. begin
  324. exprasmlist^.concat(new(paicpu,op_sym_ofs(i,s,op,ofs)));
  325. end;
  326. procedure emit_sym_ofs_reg(i : tasmop;s : topsize;op : pasmsymbol;ofs:longint;reg : tregister);
  327. begin
  328. exprasmlist^.concat(new(paicpu,op_sym_ofs_reg(i,s,op,ofs,reg)));
  329. end;
  330. procedure emit_sym_ofs_ref(i : tasmop;s : topsize;op : pasmsymbol;ofs:longint;ref : preference);
  331. begin
  332. exprasmlist^.concat(new(paicpu,op_sym_ofs_ref(i,s,op,ofs,ref)));
  333. end;
  334. procedure emitcall(const routine:string);
  335. begin
  336. exprasmlist^.concat(new(paicpu,op_sym(A_CALL,S_NO,newasmsymbol(routine))));
  337. end;
  338. { only usefull in startup code }
  339. procedure emitinsertcall(const routine:string);
  340. begin
  341. exprasmlist^.insert(new(paicpu,op_sym(A_CALL,S_NO,newasmsymbol(routine))));
  342. end;
  343. procedure emit_mov_loc_ref(const t:tlocation;const ref:treference;siz:topsize);
  344. var
  345. hreg : tregister;
  346. pushedeax : boolean;
  347. begin
  348. pushedeax:=false;
  349. case t.loc of
  350. LOC_REGISTER,
  351. LOC_CREGISTER : begin
  352. exprasmlist^.concat(new(paicpu,op_reg_ref(A_MOV,siz,
  353. t.register,newreference(ref))));
  354. ungetregister32(t.register); { the register is not needed anymore }
  355. end;
  356. LOC_MEM,
  357. LOC_REFERENCE : begin
  358. if t.reference.is_immediate then
  359. emit_const_ref(A_MOV,siz,
  360. t.reference.offset,newreference(ref))
  361. else
  362. begin
  363. case siz of
  364. S_B : begin
  365. { we can't do a getregister in the code generator }
  366. { without problems!!! }
  367. if usablereg32>0 then
  368. hreg:=reg32toreg8(getregister32)
  369. else
  370. begin
  371. emit_reg(A_PUSH,S_L,R_EAX);
  372. pushedeax:=true;
  373. hreg:=R_AL;
  374. end;
  375. end;
  376. S_W : hreg:=R_DI;
  377. S_L : hreg:=R_EDI;
  378. end;
  379. {$ifndef noAllocEdi}
  380. if hreg in [R_DI,R_EDI] then
  381. getexplicitregister32(R_EDI);
  382. {$endif noAllocEdi}
  383. emit_ref_reg(A_MOV,siz,
  384. newreference(t.reference),hreg);
  385. del_reference(t.reference);
  386. exprasmlist^.concat(new(paicpu,op_reg_ref(A_MOV,siz,
  387. hreg,newreference(ref))));
  388. if siz=S_B then
  389. begin
  390. if pushedeax then
  391. emit_reg(A_POP,S_L,R_EAX)
  392. else
  393. ungetregister(hreg);
  394. end;
  395. {$ifndef noAllocEdi}
  396. if hreg in [R_DI,R_EDI] then
  397. ungetregister32(R_EDI);
  398. {$endif noAllocEdi}
  399. { we can release the registers }
  400. { but only AFTER the MOV! Important for the optimizer!
  401. (JM)}
  402. del_reference(ref);
  403. end;
  404. ungetiftemp(t.reference);
  405. end;
  406. else
  407. internalerror(330);
  408. end;
  409. end;
  410. procedure emit_mov_loc_reg(const t:tlocation;reg:tregister);
  411. begin
  412. case t.loc of
  413. LOC_REGISTER,
  414. LOC_CREGISTER : begin
  415. emit_reg_reg(A_MOV,S_L,t.register,reg);
  416. ungetregister32(t.register); { the register is not needed anymore }
  417. end;
  418. LOC_MEM,
  419. LOC_REFERENCE : begin
  420. if t.reference.is_immediate then
  421. emit_const_reg(A_MOV,S_L,
  422. t.reference.offset,reg)
  423. else
  424. begin
  425. emit_ref_reg(A_MOV,S_L,
  426. newreference(t.reference),reg);
  427. end;
  428. end;
  429. else
  430. internalerror(330);
  431. end;
  432. end;
  433. procedure emit_mov_reg_loc(reg: TRegister; const t:tlocation);
  434. begin
  435. case t.loc of
  436. LOC_REGISTER,
  437. LOC_CREGISTER : begin
  438. emit_reg_reg(A_MOV,RegSize(Reg),
  439. reg,t.register);
  440. end;
  441. LOC_MEM,
  442. LOC_REFERENCE : begin
  443. if t.reference.is_immediate then
  444. internalerror(334)
  445. else
  446. begin
  447. exprasmlist^.concat(new(paicpu,op_reg_ref(A_MOV,RegSize(Reg),
  448. Reg,newreference(t.reference))));
  449. end;
  450. end;
  451. else
  452. internalerror(330);
  453. end;
  454. end;
  455. procedure emit_lea_loc_reg(const t:tlocation;reg:tregister;freetemp:boolean);
  456. begin
  457. case t.loc of
  458. LOC_MEM,
  459. LOC_REFERENCE : begin
  460. if t.reference.is_immediate then
  461. internalerror(331)
  462. else
  463. begin
  464. emit_ref_reg(A_LEA,S_L,
  465. newreference(t.reference),reg);
  466. end;
  467. if freetemp then
  468. ungetiftemp(t.reference);
  469. end;
  470. else
  471. internalerror(332);
  472. end;
  473. end;
  474. procedure emit_movq_reg_loc(reghigh,reglow: TRegister;t:tlocation);
  475. begin
  476. case t.loc of
  477. LOC_REGISTER,
  478. LOC_CREGISTER : begin
  479. emit_reg_reg(A_MOV,S_L,
  480. reglow,t.registerlow);
  481. emit_reg_reg(A_MOV,S_L,
  482. reghigh,t.registerhigh);
  483. end;
  484. LOC_MEM,
  485. LOC_REFERENCE : begin
  486. if t.reference.is_immediate then
  487. internalerror(334)
  488. else
  489. begin
  490. exprasmlist^.concat(new(paicpu,op_reg_ref(A_MOV,S_L,
  491. Reglow,newreference(t.reference))));
  492. inc(t.reference.offset,4);
  493. exprasmlist^.concat(new(paicpu,op_reg_ref(A_MOV,S_L,
  494. Reghigh,newreference(t.reference))));
  495. end;
  496. end;
  497. else
  498. internalerror(330);
  499. end;
  500. end;
  501. procedure emit_pushq_loc(const t : tlocation);
  502. var
  503. hr : preference;
  504. begin
  505. case t.loc of
  506. LOC_REGISTER,
  507. LOC_CREGISTER:
  508. begin
  509. exprasmlist^.concat(new(paicpu,op_reg(A_PUSH,S_L,
  510. t.registerhigh)));
  511. exprasmlist^.concat(new(paicpu,op_reg(A_PUSH,S_L,
  512. t.registerlow)));
  513. end;
  514. LOC_MEM,
  515. LOC_REFERENCE:
  516. begin
  517. hr:=newreference(t.reference);
  518. inc(hr^.offset,4);
  519. exprasmlist^.concat(new(paicpu,op_ref(A_PUSH,S_L,
  520. hr)));
  521. exprasmlist^.concat(new(paicpu,op_ref(A_PUSH,S_L,
  522. newreference(t.reference))));
  523. ungetiftemp(t.reference);
  524. end;
  525. else internalerror(331);
  526. end;
  527. end;
  528. procedure remove_non_regvars_from_loc(const t: tlocation; var regs: byte);
  529. begin
  530. case t.loc of
  531. LOC_REGISTER:
  532. { can't be a regvar, since it would be LOC_CREGISTER then }
  533. regs := regs and not($80 shr byte(t.register));
  534. LOC_MEM,LOC_REFERENCE:
  535. begin
  536. if not(cs_regalloc in aktglobalswitches) or
  537. (t.reference.base in usableregs) then
  538. regs := regs and
  539. not($80 shr byte(t.reference.base));
  540. if not(cs_regalloc in aktglobalswitches) or
  541. (t.reference.index in usableregs) then
  542. regs := regs and
  543. not($80 shr byte(t.reference.index));
  544. end;
  545. end;
  546. end;
  547. procedure release_loc(const t : tlocation);
  548. begin
  549. case t.loc of
  550. LOC_REGISTER,
  551. LOC_CREGISTER:
  552. begin
  553. ungetregister32(t.register);
  554. end;
  555. LOC_MEM,
  556. LOC_REFERENCE:
  557. del_reference(t.reference);
  558. else internalerror(332);
  559. end;
  560. end;
  561. procedure release_qword_loc(const t : tlocation);
  562. begin
  563. case t.loc of
  564. LOC_REGISTER,
  565. LOC_CREGISTER:
  566. begin
  567. ungetregister32(t.registerhigh);
  568. ungetregister32(t.registerlow);
  569. end;
  570. LOC_MEM,
  571. LOC_REFERENCE:
  572. del_reference(t.reference);
  573. else internalerror(331);
  574. end;
  575. end;
  576. procedure emit_push_loc(const t:tlocation);
  577. begin
  578. case t.loc of
  579. LOC_REGISTER,
  580. LOC_CREGISTER : begin
  581. exprasmlist^.concat(new(paicpu,op_reg(A_PUSH,S_L,makereg32(t.register))));
  582. ungetregister(t.register); { the register is not needed anymore }
  583. end;
  584. LOC_MEM,
  585. LOC_REFERENCE : begin
  586. if t.reference.is_immediate then
  587. exprasmlist^.concat(new(paicpu,op_const(A_PUSH,S_L,t.reference.offset)))
  588. else
  589. exprasmlist^.concat(new(paicpu,op_ref(A_PUSH,S_L,newreference(t.reference))));
  590. del_reference(t.reference);
  591. ungetiftemp(t.reference);
  592. end;
  593. else
  594. internalerror(330);
  595. end;
  596. end;
  597. procedure emit_pushw_loc(const t:tlocation);
  598. var
  599. opsize : topsize;
  600. begin
  601. case t.loc of
  602. LOC_REGISTER,
  603. LOC_CREGISTER : begin
  604. if target_os.stackalignment=4 then
  605. exprasmlist^.concat(new(paicpu,op_reg(A_PUSH,S_L,makereg32(t.register))))
  606. else
  607. exprasmlist^.concat(new(paicpu,op_reg(A_PUSH,S_W,makereg16(t.register))));
  608. ungetregister(t.register); { the register is not needed anymore }
  609. end;
  610. LOC_MEM,
  611. LOC_REFERENCE : begin
  612. if target_os.stackalignment=4 then
  613. opsize:=S_L
  614. else
  615. opsize:=S_W;
  616. if t.reference.is_immediate then
  617. exprasmlist^.concat(new(paicpu,op_const(A_PUSH,opsize,t.reference.offset)))
  618. else
  619. exprasmlist^.concat(new(paicpu,op_ref(A_PUSH,opsize,newreference(t.reference))));
  620. del_reference(t.reference);
  621. ungetiftemp(t.reference);
  622. end;
  623. else
  624. internalerror(330);
  625. end;
  626. end;
  627. procedure emit_lea_loc_ref(const t:tlocation;const ref:treference;freetemp:boolean);
  628. begin
  629. case t.loc of
  630. LOC_MEM,
  631. LOC_REFERENCE : begin
  632. if t.reference.is_immediate then
  633. internalerror(331)
  634. else
  635. begin
  636. {$ifndef noAllocEdi}
  637. getexplicitregister32(R_EDI);
  638. {$endif noAllocEdi}
  639. emit_ref_reg(A_LEA,S_L,
  640. newreference(t.reference),R_EDI);
  641. exprasmlist^.concat(new(paicpu,op_reg_ref(A_MOV,S_L,
  642. R_EDI,newreference(ref))));
  643. {$ifndef noAllocEdi}
  644. ungetregister32(R_EDI);
  645. {$endif noAllocEdi}
  646. end;
  647. { release the registers }
  648. del_reference(t.reference);
  649. if freetemp then
  650. ungetiftemp(t.reference);
  651. end;
  652. else
  653. internalerror(332);
  654. end;
  655. end;
  656. procedure emit_push_lea_loc(const t:tlocation;freetemp:boolean);
  657. begin
  658. case t.loc of
  659. LOC_MEM,
  660. LOC_REFERENCE : begin
  661. if t.reference.is_immediate then
  662. internalerror(331)
  663. else
  664. begin
  665. {$ifndef noAllocEdi}
  666. getexplicitregister32(R_EDI);
  667. {$endif noAllocEdi}
  668. emit_ref_reg(A_LEA,S_L,
  669. newreference(t.reference),R_EDI);
  670. exprasmlist^.concat(new(paicpu,op_reg(A_PUSH,S_L,R_EDI)));
  671. {$ifndef noAllocEdi}
  672. ungetregister32(R_EDI);
  673. {$endif noAllocEdi}
  674. end;
  675. if freetemp then
  676. ungetiftemp(t.reference);
  677. end;
  678. else
  679. internalerror(332);
  680. end;
  681. end;
  682. procedure emit_to_mem(var p:ptree);
  683. begin
  684. case p^.location.loc of
  685. LOC_FPU : begin
  686. reset_reference(p^.location.reference);
  687. gettempofsizereference(10,p^.location.reference);
  688. floatstore(pfloatdef(p^.resulttype)^.typ,p^.location.reference);
  689. { This can't be never a l-value! (FK)
  690. p^.location.loc:=LOC_REFERENCE; }
  691. end;
  692. LOC_MEM,
  693. LOC_REFERENCE : ;
  694. LOC_CFPUREGISTER : begin
  695. emit_reg(A_FLD,S_NO,correct_fpuregister(p^.location.register,fpuvaroffset));
  696. inc(fpuvaroffset);
  697. reset_reference(p^.location.reference);
  698. gettempofsizereference(10,p^.location.reference);
  699. floatstore(pfloatdef(p^.resulttype)^.typ,p^.location.reference);
  700. { This can't be never a l-value! (FK)
  701. p^.location.loc:=LOC_REFERENCE; }
  702. end;
  703. else
  704. internalerror(333);
  705. end;
  706. p^.location.loc:=LOC_MEM;
  707. end;
  708. procedure emit_to_reg16(var hr:tregister);
  709. begin
  710. { ranges are a little bit bug sensitive ! }
  711. case hr of
  712. R_EAX,R_EBX,R_ECX,R_EDX,R_EDI,R_ESI,R_ESP,R_EBP:
  713. begin
  714. hr:=reg32toreg16(hr);
  715. end;
  716. R_AL,R_BL,R_CL,R_DL:
  717. begin
  718. hr:=reg8toreg16(hr);
  719. emit_const_reg(A_AND,S_W,$ff,hr);
  720. end;
  721. R_AH,R_BH,R_CH,R_DH:
  722. begin
  723. hr:=reg8toreg16(hr);
  724. emit_const_reg(A_AND,S_W,$ff00,hr);
  725. end;
  726. end;
  727. end;
  728. procedure emit_to_reg32(var hr:tregister);
  729. begin
  730. { ranges are a little bit bug sensitive ! }
  731. case hr of
  732. R_AX,R_BX,R_CX,R_DX,R_DI,R_SI,R_SP,R_BP:
  733. begin
  734. hr:=reg16toreg32(hr);
  735. emit_const_reg(A_AND,S_L,$ffff,hr);
  736. end;
  737. R_AL,R_BL,R_CL,R_DL:
  738. begin
  739. hr:=reg8toreg32(hr);
  740. emit_const_reg(A_AND,S_L,$ff,hr);
  741. end;
  742. R_AH,R_BH,R_CH,R_DH:
  743. begin
  744. hr:=reg8toreg32(hr);
  745. emit_const_reg(A_AND,S_L,$ff00,hr);
  746. end;
  747. end;
  748. end;
  749. procedure emit_mov_ref_reg64(r : treference;rl,rh : tregister);
  750. var
  751. hr : preference;
  752. begin
  753. { if we load a 64 bit reference, we must be careful because }
  754. { we could overwrite the registers of the reference by }
  755. { accident }
  756. if r.base=rl then
  757. begin
  758. emit_reg_reg(A_MOV,S_L,r.base,
  759. R_EDI);
  760. r.base:=R_EDI;
  761. end
  762. else if r.index=rl then
  763. begin
  764. emit_reg_reg(A_MOV,S_L,r.index,
  765. R_EDI);
  766. r.index:=R_EDI;
  767. end;
  768. emit_ref_reg(A_MOV,S_L,
  769. newreference(r),rl);
  770. hr:=newreference(r);
  771. inc(hr^.offset,4);
  772. emit_ref_reg(A_MOV,S_L,
  773. hr,rh);
  774. end;
  775. {*****************************************************************************
  776. Emit String Functions
  777. *****************************************************************************}
  778. procedure copyshortstring(const dref,sref : treference;len : byte;loadref:boolean);
  779. begin
  780. emitpushreferenceaddr(dref);
  781. if loadref then
  782. emit_push_mem(sref)
  783. else
  784. emitpushreferenceaddr(sref);
  785. push_int(len);
  786. emitcall('FPC_SHORTSTR_COPY');
  787. maybe_loadesi;
  788. end;
  789. procedure copylongstring(const dref,sref : treference;len : longint;loadref:boolean);
  790. begin
  791. emitpushreferenceaddr(dref);
  792. if loadref then
  793. emit_push_mem(sref)
  794. else
  795. emitpushreferenceaddr(sref);
  796. push_int(len);
  797. emitcall('FPC_LONGSTR_COPY');
  798. maybe_loadesi;
  799. end;
  800. procedure decrstringref(t : pdef;const ref : treference);
  801. var
  802. pushedregs : tpushed;
  803. begin
  804. pushusedregisters(pushedregs,$ff);
  805. emitpushreferenceaddr(ref);
  806. if is_ansistring(t) then
  807. begin
  808. emitcall('FPC_ANSISTR_DECR_REF');
  809. end
  810. else if is_widestring(t) then
  811. begin
  812. emitcall('FPC_WIDESTR_DECR_REF');
  813. end
  814. else internalerror(1859);
  815. popusedregisters(pushedregs);
  816. end;
  817. procedure loadansistring(p : ptree);
  818. {
  819. copies an ansistring from p^.right to p^.left, we
  820. assume, that both sides are ansistring, firstassignement have
  821. to take care of that, an ansistring can't be a register variable
  822. }
  823. var
  824. pushed : tpushed;
  825. ungettemp : boolean;
  826. begin
  827. { before pushing any parameter, we have to save all used }
  828. { registers, but before that we have to release the }
  829. { registers of that node to save uneccessary pushed }
  830. { so be careful, if you think you can optimize that code (FK) }
  831. { nevertheless, this has to be changed, because otherwise the }
  832. { register is released before it's contents are pushed -> }
  833. { problems with the optimizer (JM) }
  834. del_reference(p^.left^.location.reference);
  835. ungettemp:=false;
  836. case p^.right^.location.loc of
  837. LOC_REGISTER,LOC_CREGISTER:
  838. begin
  839. {$IfNDef regallocfix}
  840. ungetregister32(p^.right^.location.register);
  841. pushusedregisters(pushed,$ff);
  842. exprasmlist^.concat(new(paicpu,op_reg(A_PUSH,S_L,p^.right^.location.register)));
  843. {$Else regallocfix}
  844. pushusedregisters(pushed, $ff xor ($80 shr byte(p^.right^.location.register)));
  845. exprasmlist^.concat(new(paicpu,op_reg(A_PUSH,S_L,p^.right^.location.register)));
  846. ungetregister32(p^.right^.location.register);
  847. {$EndIf regallocfix}
  848. end;
  849. LOC_REFERENCE,LOC_MEM:
  850. begin
  851. {$IfNDef regallocfix}
  852. del_reference(p^.right^.location.reference);
  853. pushusedregisters(pushed,$ff);
  854. emit_push_mem(p^.right^.location.reference);
  855. {$Else regallocfix}
  856. pushusedregisters(pushed,$ff
  857. xor ($80 shr byte(p^.right^.location.reference.base))
  858. xor ($80 shr byte(p^.right^.location.reference.index)));
  859. emit_push_mem(p^.right^.location.reference);
  860. del_reference(p^.right^.location.reference);
  861. {$EndIf regallocfix}
  862. ungettemp:=true;
  863. end;
  864. end;
  865. emitpushreferenceaddr(p^.left^.location.reference);
  866. del_reference(p^.left^.location.reference);
  867. emitcall('FPC_ANSISTR_ASSIGN');
  868. maybe_loadesi;
  869. popusedregisters(pushed);
  870. if ungettemp then
  871. ungetiftemp(p^.right^.location.reference);
  872. end;
  873. {*****************************************************************************
  874. Emit Push Functions
  875. *****************************************************************************}
  876. function maybe_push(needed : byte;p : ptree;isint64 : boolean) : boolean;
  877. var
  878. pushed : boolean;
  879. {hregister : tregister; }
  880. {$ifdef TEMPS_NOT_PUSH}
  881. href : treference;
  882. {$endif TEMPS_NOT_PUSH}
  883. begin
  884. if needed>usablereg32 then
  885. begin
  886. if (p^.location.loc=LOC_REGISTER) then
  887. begin
  888. if isint64 then
  889. begin
  890. {$ifdef TEMPS_NOT_PUSH}
  891. gettempofsizereference(href,8);
  892. p^.temp_offset:=href.offset;
  893. href.offset:=href.offset+4;
  894. exprasmlist^.concat(new(paicpu,op_reg(A_MOV,S_L,p^.location.registerhigh,href)));
  895. href.offset:=href.offset-4;
  896. {$else TEMPS_NOT_PUSH}
  897. exprasmlist^.concat(new(paicpu,op_reg(A_PUSH,S_L,p^.location.registerhigh)));
  898. {$endif TEMPS_NOT_PUSH}
  899. ungetregister32(p^.location.registerhigh);
  900. end
  901. {$ifdef TEMPS_NOT_PUSH}
  902. else
  903. begin
  904. gettempofsizereference(href,4);
  905. p^.temp_offset:=href.offset;
  906. end
  907. {$endif TEMPS_NOT_PUSH}
  908. ;
  909. pushed:=true;
  910. {$ifdef TEMPS_NOT_PUSH}
  911. exprasmlist^.concat(new(paicpu,op_reg_ref(A_MOV,S_L,p^.location.register,href)));
  912. {$else TEMPS_NOT_PUSH}
  913. exprasmlist^.concat(new(paicpu,op_reg(A_PUSH,S_L,p^.location.register)));
  914. {$endif TEMPS_NOT_PUSH}
  915. ungetregister32(p^.location.register);
  916. end
  917. else if (p^.location.loc in [LOC_MEM,LOC_REFERENCE]) and
  918. ((p^.location.reference.base<>R_NO) or
  919. (p^.location.reference.index<>R_NO)
  920. ) then
  921. begin
  922. del_reference(p^.location.reference);
  923. {$ifndef noAllocEdi}
  924. getexplicitregister32(R_EDI);
  925. {$endif noAllocEdi}
  926. emit_ref_reg(A_LEA,S_L,newreference(p^.location.reference),
  927. R_EDI);
  928. {$ifdef TEMPS_NOT_PUSH}
  929. gettempofsizereference(href,4);
  930. exprasmlist^.concat(new(paicpu,op_reg_ref(A_MOV,S_L,R_EDI,href)));
  931. p^.temp_offset:=href.offset;
  932. {$else TEMPS_NOT_PUSH}
  933. exprasmlist^.concat(new(paicpu,op_reg(A_PUSH,S_L,R_EDI)));
  934. {$endif TEMPS_NOT_PUSH}
  935. {$ifndef noAllocEdi}
  936. ungetregister32(R_EDI);
  937. {$endif noAllocEdi}
  938. pushed:=true;
  939. end
  940. else pushed:=false;
  941. end
  942. else pushed:=false;
  943. maybe_push:=pushed;
  944. end;
  945. {$ifdef TEMPS_NOT_PUSH}
  946. function maybe_savetotemp(needed : byte;p : ptree;isint64 : boolean) : boolean;
  947. var
  948. pushed : boolean;
  949. href : treference;
  950. begin
  951. if needed>usablereg32 then
  952. begin
  953. if (p^.location.loc=LOC_REGISTER) then
  954. begin
  955. if isint64(p^.resulttype) then
  956. begin
  957. gettempofsizereference(href,8);
  958. p^.temp_offset:=href.offset;
  959. href.offset:=href.offset+4;
  960. exprasmlist^.concat(new(paicpu,op_reg(A_MOV,S_L,p^.location.registerhigh,href)));
  961. href.offset:=href.offset-4;
  962. ungetregister32(p^.location.registerhigh);
  963. end
  964. else
  965. begin
  966. gettempofsizereference(href,4);
  967. p^.temp_offset:=href.offset;
  968. end;
  969. pushed:=true;
  970. exprasmlist^.concat(new(paicpu,op_reg_ref(A_MOV,S_L,p^.location.register,href)));
  971. ungetregister32(p^.location.register);
  972. end
  973. else if (p^.location.loc in [LOC_MEM,LOC_REFERENCE]) and
  974. ((p^.location.reference.base<>R_NO) or
  975. (p^.location.reference.index<>R_NO)
  976. ) then
  977. begin
  978. del_reference(p^.location.reference);
  979. {$ifndef noAllocEdi}
  980. getexplicitregister32(R_EDI);
  981. {$endif noAllocEdi}
  982. emit_ref_reg(A_LEA,S_L,newreference(p^.location.reference),
  983. R_EDI);
  984. gettempofsizereference(href,4);
  985. exprasmlist^.concat(new(paicpu,op_reg_ref(A_MOV,S_L,R_EDI,href)));
  986. {$ifndef noAllocEdi}
  987. ungetregister32(R_EDI);
  988. {$endif noAllocEdi}
  989. p^.temp_offset:=href.offset;
  990. pushed:=true;
  991. end
  992. else pushed:=false;
  993. end
  994. else pushed:=false;
  995. maybe_push:=pushed;
  996. end;
  997. {$endif TEMPS_NOT_PUSH}
  998. procedure push_int(l : longint);
  999. begin
  1000. if (l = 0) and
  1001. not(aktoptprocessor in [Class386, ClassP6]) and
  1002. not(cs_littlesize in aktglobalswitches)
  1003. Then
  1004. begin
  1005. {$ifndef noAllocEdi}
  1006. getexplicitregister32(R_EDI);
  1007. {$endif noAllocEdi}
  1008. emit_reg_reg(A_XOR,S_L,R_EDI,R_EDI);
  1009. exprasmlist^.concat(new(paicpu,op_reg(A_PUSH,S_L,R_EDI)));
  1010. {$ifndef noAllocEdi}
  1011. ungetregister32(R_EDI);
  1012. {$endif noAllocEdi}
  1013. end
  1014. else
  1015. exprasmlist^.concat(new(paicpu,op_const(A_PUSH,S_L,l)));
  1016. end;
  1017. procedure emit_push_mem(const ref : treference);
  1018. begin
  1019. if ref.is_immediate then
  1020. push_int(ref.offset)
  1021. else
  1022. begin
  1023. if not(aktoptprocessor in [Class386, ClassP6]) and
  1024. not(cs_littlesize in aktglobalswitches)
  1025. then
  1026. begin
  1027. {$ifndef noAllocEdi}
  1028. getexplicitregister32(R_EDI);
  1029. {$endif noAllocEdi}
  1030. emit_ref_reg(A_MOV,S_L,newreference(ref),R_EDI);
  1031. exprasmlist^.concat(new(paicpu,op_reg(A_PUSH,S_L,R_EDI)));
  1032. {$ifndef noAllocEdi}
  1033. ungetregister32(R_EDI);
  1034. {$endif noAllocEdi}
  1035. end
  1036. else exprasmlist^.concat(new(paicpu,op_ref(A_PUSH,S_L,newreference(ref))));
  1037. end;
  1038. end;
  1039. procedure emitpushreferenceaddr(const ref : treference);
  1040. var
  1041. href : treference;
  1042. begin
  1043. { this will fail for references to other segments !!! }
  1044. if ref.is_immediate then
  1045. { is this right ? }
  1046. begin
  1047. { push_int(ref.offset)}
  1048. gettempofsizereference(4,href);
  1049. emit_const_ref(A_MOV,S_L,ref.offset,newreference(href));
  1050. emitpushreferenceaddr(href);
  1051. del_reference(href);
  1052. end
  1053. else
  1054. begin
  1055. if ref.segment<>R_NO then
  1056. CGMessage(cg_e_cant_use_far_pointer_there);
  1057. if (ref.base=R_NO) and (ref.index=R_NO) then
  1058. exprasmlist^.concat(new(paicpu,op_sym_ofs(A_PUSH,S_L,ref.symbol,ref.offset)))
  1059. else if (ref.base=R_NO) and (ref.index<>R_NO) and
  1060. (ref.offset=0) and (ref.scalefactor=0) and (ref.symbol=nil) then
  1061. exprasmlist^.concat(new(paicpu,op_reg(A_PUSH,S_L,ref.index)))
  1062. else if (ref.base<>R_NO) and (ref.index=R_NO) and
  1063. (ref.offset=0) and (ref.symbol=nil) then
  1064. exprasmlist^.concat(new(paicpu,op_reg(A_PUSH,S_L,ref.base)))
  1065. else
  1066. begin
  1067. {$ifndef noAllocEdi}
  1068. getexplicitregister32(R_EDI);
  1069. {$endif noAllocEdi}
  1070. emit_ref_reg(A_LEA,S_L,newreference(ref),R_EDI);
  1071. exprasmlist^.concat(new(paicpu,op_reg(A_PUSH,S_L,R_EDI)));
  1072. {$ifndef noAllocEdi}
  1073. ungetregister32(R_EDI);
  1074. {$endif noAllocEdi}
  1075. end;
  1076. end;
  1077. end;
  1078. procedure pushsetelement(p : ptree);
  1079. {
  1080. copies p a set element on the stack
  1081. }
  1082. var
  1083. hr,hr16,hr32 : tregister;
  1084. begin
  1085. { copy the element on the stack, slightly complicated }
  1086. if p^.treetype=ordconstn then
  1087. begin
  1088. if target_os.stackalignment=4 then
  1089. exprasmlist^.concat(new(paicpu,op_const(A_PUSH,S_L,p^.value)))
  1090. else
  1091. exprasmlist^.concat(new(paicpu,op_const(A_PUSH,S_W,p^.value)));
  1092. end
  1093. else
  1094. begin
  1095. case p^.location.loc of
  1096. LOC_REGISTER,
  1097. LOC_CREGISTER :
  1098. begin
  1099. hr:=p^.location.register;
  1100. case hr of
  1101. R_EAX,R_EBX,R_ECX,R_EDX,R_EDI,R_ESI,R_ESP :
  1102. begin
  1103. hr16:=reg32toreg16(hr);
  1104. hr32:=hr;
  1105. end;
  1106. R_AX,R_BX,R_CX,R_DX,R_DI,R_SI,R_SP :
  1107. begin
  1108. hr16:=hr;
  1109. hr32:=reg16toreg32(hr);
  1110. end;
  1111. R_AL,R_BL,R_CL,R_DL :
  1112. begin
  1113. hr16:=reg8toreg16(hr);
  1114. hr32:=reg8toreg32(hr);
  1115. end;
  1116. end;
  1117. if target_os.stackalignment=4 then
  1118. exprasmlist^.concat(new(paicpu,op_reg(A_PUSH,S_L,hr32)))
  1119. else
  1120. exprasmlist^.concat(new(paicpu,op_reg(A_PUSH,S_W,hr16)));
  1121. ungetregister32(hr32);
  1122. end;
  1123. else
  1124. begin
  1125. if target_os.stackalignment=4 then
  1126. exprasmlist^.concat(new(paicpu,op_ref(A_PUSH,S_L,newreference(p^.location.reference))))
  1127. else
  1128. exprasmlist^.concat(new(paicpu,op_ref(A_PUSH,S_W,newreference(p^.location.reference))));
  1129. del_reference(p^.location.reference);
  1130. end;
  1131. end;
  1132. end;
  1133. end;
  1134. procedure restore(p : ptree;isint64 : boolean);
  1135. var
  1136. hregister : tregister;
  1137. {$ifdef TEMPS_NOT_PUSH}
  1138. href : treference;
  1139. {$endif TEMPS_NOT_PUSH}
  1140. begin
  1141. hregister:=getregister32;
  1142. {$ifdef TEMPS_NOT_PUSH}
  1143. reset_reference(href);
  1144. href.base:=procinfo^.frame_pointer;
  1145. href.offset:=p^.temp_offset;
  1146. emit_ref_reg(A_MOV,S_L,href,hregister);
  1147. {$else TEMPS_NOT_PUSH}
  1148. exprasmlist^.concat(new(paicpu,op_reg(A_POP,S_L,hregister)));
  1149. {$endif TEMPS_NOT_PUSH}
  1150. if (p^.location.loc in [LOC_REGISTER,LOC_CREGISTER]) then
  1151. begin
  1152. p^.location.register:=hregister;
  1153. if isint64 then
  1154. begin
  1155. p^.location.registerhigh:=getregister32;
  1156. {$ifdef TEMPS_NOT_PUSH}
  1157. href.offset:=p^.temp_offset+4;
  1158. emit_ref_reg(A_MOV,S_L,p^.location.registerhigh);
  1159. { set correctly for release ! }
  1160. href.offset:=p^.temp_offset;
  1161. {$else TEMPS_NOT_PUSH}
  1162. exprasmlist^.concat(new(paicpu,op_reg(A_POP,S_L,p^.location.registerhigh)));
  1163. {$endif TEMPS_NOT_PUSH}
  1164. end;
  1165. end
  1166. else
  1167. begin
  1168. reset_reference(p^.location.reference);
  1169. { any reasons why this was moved into the index register ? }
  1170. { normally usage of base register is much better (FK) }
  1171. p^.location.reference.base:=hregister;
  1172. { Why is this done? We can never be sure about p^.left
  1173. because otherwise secondload fails !!!
  1174. set_location(p^.left^.location,p^.location);}
  1175. end;
  1176. {$ifdef TEMPS_NOT_PUSH}
  1177. ungetiftemp(href);
  1178. {$endif TEMPS_NOT_PUSH}
  1179. end;
  1180. {$ifdef TEMPS_NOT_PUSH}
  1181. procedure restorefromtemp(p : ptree;isint64 : boolean);
  1182. var
  1183. hregister : tregister;
  1184. href : treference;
  1185. begin
  1186. hregister:=getregister32;
  1187. reset_reference(href);
  1188. href.base:=procinfo^.frame_pointer;
  1189. href.offset:=p^.temp_offset;
  1190. emit_ref_reg(A_MOV,S_L,href,hregister);
  1191. if (p^.location.loc in [LOC_REGISTER,LOC_CREGISTER]) then
  1192. begin
  1193. p^.location.register:=hregister;
  1194. if isint64 then
  1195. begin
  1196. p^.location.registerhigh:=getregister32;
  1197. href.offset:=p^.temp_offset+4;
  1198. emit_ref_reg(A_MOV,S_L,p^.location.registerhigh);
  1199. { set correctly for release ! }
  1200. href.offset:=p^.temp_offset;
  1201. end;
  1202. end
  1203. else
  1204. begin
  1205. reset_reference(p^.location.reference);
  1206. p^.location.reference.base:=hregister;
  1207. { Why is this done? We can never be sure about p^.left
  1208. because otherwise secondload fails PM
  1209. set_location(p^.left^.location,p^.location);}
  1210. end;
  1211. ungetiftemp(href);
  1212. end;
  1213. {$endif TEMPS_NOT_PUSH}
  1214. procedure push_value_para(p:ptree;inlined:boolean;para_offset:longint;alignment : longint);
  1215. var
  1216. tempreference : treference;
  1217. r : preference;
  1218. opsize : topsize;
  1219. op : tasmop;
  1220. hreg : tregister;
  1221. size : longint;
  1222. hlabel : pasmlabel;
  1223. begin
  1224. case p^.location.loc of
  1225. LOC_REGISTER,
  1226. LOC_CREGISTER:
  1227. begin
  1228. case p^.location.register of
  1229. R_EAX,R_EBX,R_ECX,R_EDX,R_ESI,
  1230. R_EDI,R_ESP,R_EBP :
  1231. begin
  1232. if p^.resulttype^.size=8 then
  1233. begin
  1234. inc(pushedparasize,8);
  1235. if inlined then
  1236. begin
  1237. r:=new_reference(procinfo^.framepointer,para_offset-pushedparasize);
  1238. exprasmlist^.concat(new(paicpu,op_reg_ref(A_MOV,S_L,
  1239. p^.location.registerlow,r)));
  1240. r:=new_reference(procinfo^.framepointer,para_offset-pushedparasize+4);
  1241. exprasmlist^.concat(new(paicpu,op_reg_ref(A_MOV,S_L,
  1242. p^.location.registerhigh,r)));
  1243. end
  1244. else
  1245. exprasmlist^.concat(new(paicpu,op_reg(A_PUSH,S_L,p^.location.registerhigh)));
  1246. ungetregister32(p^.location.registerhigh);
  1247. exprasmlist^.concat(new(paicpu,op_reg(A_PUSH,S_L,p^.location.registerlow)));
  1248. ungetregister32(p^.location.registerlow);
  1249. end
  1250. else
  1251. begin
  1252. inc(pushedparasize,4);
  1253. if inlined then
  1254. begin
  1255. r:=new_reference(procinfo^.framepointer,para_offset-pushedparasize);
  1256. exprasmlist^.concat(new(paicpu,op_reg_ref(A_MOV,S_L,
  1257. p^.location.register,r)));
  1258. end
  1259. else
  1260. exprasmlist^.concat(new(paicpu,op_reg(A_PUSH,S_L,p^.location.register)));
  1261. ungetregister32(p^.location.register);
  1262. end;
  1263. end;
  1264. R_AX,R_BX,R_CX,R_DX,R_SI,R_DI:
  1265. begin
  1266. if alignment=4 then
  1267. begin
  1268. opsize:=S_L;
  1269. hreg:=reg16toreg32(p^.location.register);
  1270. inc(pushedparasize,4);
  1271. end
  1272. else
  1273. begin
  1274. opsize:=S_W;
  1275. hreg:=p^.location.register;
  1276. inc(pushedparasize,2);
  1277. end;
  1278. if inlined then
  1279. begin
  1280. r:=new_reference(procinfo^.framepointer,para_offset-pushedparasize);
  1281. exprasmlist^.concat(new(paicpu,op_reg_ref(A_MOV,opsize,hreg,r)));
  1282. end
  1283. else
  1284. exprasmlist^.concat(new(paicpu,op_reg(A_PUSH,opsize,hreg)));
  1285. ungetregister32(reg16toreg32(p^.location.register));
  1286. end;
  1287. R_AL,R_BL,R_CL,R_DL:
  1288. begin
  1289. if alignment=4 then
  1290. begin
  1291. opsize:=S_L;
  1292. hreg:=reg8toreg32(p^.location.register);
  1293. inc(pushedparasize,4);
  1294. end
  1295. else
  1296. begin
  1297. opsize:=S_W;
  1298. hreg:=reg8toreg16(p^.location.register);
  1299. inc(pushedparasize,2);
  1300. end;
  1301. { we must push always 16 bit }
  1302. if inlined then
  1303. begin
  1304. r:=new_reference(procinfo^.framepointer,para_offset-pushedparasize);
  1305. exprasmlist^.concat(new(paicpu,op_reg_ref(A_MOV,opsize,hreg,r)));
  1306. end
  1307. else
  1308. exprasmlist^.concat(new(paicpu,op_reg(A_PUSH,opsize,hreg)));
  1309. ungetregister32(reg8toreg32(p^.location.register));
  1310. end;
  1311. else internalerror(1899);
  1312. end;
  1313. end;
  1314. LOC_FPU:
  1315. begin
  1316. size:=align(pfloatdef(p^.resulttype)^.size,alignment);
  1317. inc(pushedparasize,size);
  1318. if not inlined then
  1319. emit_const_reg(A_SUB,S_L,size,R_ESP);
  1320. {$ifdef GDB}
  1321. if (cs_debuginfo in aktmoduleswitches) and
  1322. (exprasmlist^.first=exprasmlist^.last) then
  1323. exprasmlist^.concat(new(pai_force_line,init));
  1324. {$endif GDB}
  1325. r:=new_reference(R_ESP,0);
  1326. floatstoreops(pfloatdef(p^.resulttype)^.typ,op,opsize);
  1327. { this is the easiest case for inlined !! }
  1328. if inlined then
  1329. begin
  1330. r^.base:=procinfo^.framepointer;
  1331. r^.offset:=para_offset-pushedparasize;
  1332. end;
  1333. exprasmlist^.concat(new(paicpu,op_ref(op,opsize,r)));
  1334. dec(fpuvaroffset);
  1335. end;
  1336. LOC_CFPUREGISTER:
  1337. begin
  1338. exprasmlist^.concat(new(paicpu,op_reg(A_FLD,S_NO,
  1339. correct_fpuregister(p^.location.register,fpuvaroffset))));
  1340. size:=align(pfloatdef(p^.resulttype)^.size,alignment);
  1341. inc(pushedparasize,size);
  1342. if not inlined then
  1343. emit_const_reg(A_SUB,S_L,size,R_ESP);
  1344. {$ifdef GDB}
  1345. if (cs_debuginfo in aktmoduleswitches) and
  1346. (exprasmlist^.first=exprasmlist^.last) then
  1347. exprasmlist^.concat(new(pai_force_line,init));
  1348. {$endif GDB}
  1349. r:=new_reference(R_ESP,0);
  1350. floatstoreops(pfloatdef(p^.resulttype)^.typ,op,opsize);
  1351. { this is the easiest case for inlined !! }
  1352. if inlined then
  1353. begin
  1354. r^.base:=procinfo^.framepointer;
  1355. r^.offset:=para_offset-pushedparasize;
  1356. end;
  1357. exprasmlist^.concat(new(paicpu,op_ref(op,opsize,r)));
  1358. end;
  1359. LOC_REFERENCE,LOC_MEM:
  1360. begin
  1361. tempreference:=p^.location.reference;
  1362. del_reference(p^.location.reference);
  1363. case p^.resulttype^.deftype of
  1364. enumdef,
  1365. orddef :
  1366. begin
  1367. case p^.resulttype^.size of
  1368. 8 : begin
  1369. inc(pushedparasize,8);
  1370. if inlined then
  1371. begin
  1372. {$ifndef noAllocEdi}
  1373. getexplicitregister32(R_EDI);
  1374. {$endif noAllocEdi}
  1375. emit_ref_reg(A_MOV,S_L,
  1376. newreference(tempreference),R_EDI);
  1377. r:=new_reference(procinfo^.framepointer,para_offset-pushedparasize);
  1378. exprasmlist^.concat(new(paicpu,op_reg_ref(A_MOV,S_L,R_EDI,r)));
  1379. {$ifndef noAllocEdi}
  1380. ungetregister32(R_EDI);
  1381. getexplicitregister32(R_EDI);
  1382. {$endif noAllocEdi}
  1383. inc(tempreference.offset,4);
  1384. emit_ref_reg(A_MOV,S_L,
  1385. newreference(tempreference),R_EDI);
  1386. r:=new_reference(procinfo^.framepointer,para_offset-pushedparasize+4);
  1387. exprasmlist^.concat(new(paicpu,op_reg_ref(A_MOV,S_L,R_EDI,r)));
  1388. {$ifndef noAllocEdi}
  1389. ungetregister32(R_EDI);
  1390. {$endif noAllocEdi}
  1391. end
  1392. else
  1393. begin
  1394. inc(tempreference.offset,4);
  1395. emit_push_mem(tempreference);
  1396. dec(tempreference.offset,4);
  1397. emit_push_mem(tempreference);
  1398. end;
  1399. end;
  1400. 4 : begin
  1401. inc(pushedparasize,4);
  1402. if inlined then
  1403. begin
  1404. {$ifndef noAllocEdi}
  1405. getexplicitregister32(R_EDI);
  1406. {$endif noAllocEdi}
  1407. emit_ref_reg(A_MOV,S_L,
  1408. newreference(tempreference),R_EDI);
  1409. r:=new_reference(procinfo^.framepointer,para_offset-pushedparasize);
  1410. exprasmlist^.concat(new(paicpu,op_reg_ref(A_MOV,S_L,R_EDI,r)));
  1411. {$ifndef noAllocEdi}
  1412. ungetregister32(R_EDI);
  1413. {$endif noAllocEdi}
  1414. end
  1415. else
  1416. emit_push_mem(tempreference);
  1417. end;
  1418. 1,2 : begin
  1419. if alignment=4 then
  1420. begin
  1421. opsize:=S_L;
  1422. hreg:=R_EDI;
  1423. inc(pushedparasize,4);
  1424. end
  1425. else
  1426. begin
  1427. opsize:=S_W;
  1428. hreg:=R_DI;
  1429. inc(pushedparasize,2);
  1430. end;
  1431. if inlined then
  1432. begin
  1433. {$ifndef noAllocEdi}
  1434. getexplicitregister32(R_EDI);
  1435. {$endif noAllocEdi}
  1436. emit_ref_reg(A_MOV,opsize,
  1437. newreference(tempreference),hreg);
  1438. r:=new_reference(procinfo^.framepointer,para_offset-pushedparasize);
  1439. exprasmlist^.concat(new(paicpu,op_reg_ref(A_MOV,opsize,hreg,r)));
  1440. {$ifndef noAllocEdi}
  1441. ungetregister32(R_EDI);
  1442. {$endif noAllocEdi}
  1443. end
  1444. else
  1445. exprasmlist^.concat(new(paicpu,op_ref(A_PUSH,opsize,
  1446. newreference(tempreference))));
  1447. end;
  1448. else
  1449. internalerror(234231);
  1450. end;
  1451. end;
  1452. floatdef :
  1453. begin
  1454. case pfloatdef(p^.resulttype)^.typ of
  1455. f32bit,
  1456. s32real :
  1457. begin
  1458. inc(pushedparasize,4);
  1459. if inlined then
  1460. begin
  1461. {$ifndef noAllocEdi}
  1462. getexplicitregister32(R_EDI);
  1463. {$endif noAllocEdi}
  1464. emit_ref_reg(A_MOV,S_L,
  1465. newreference(tempreference),R_EDI);
  1466. r:=new_reference(procinfo^.framepointer,para_offset-pushedparasize);
  1467. exprasmlist^.concat(new(paicpu,op_reg_ref(A_MOV,S_L,R_EDI,r)));
  1468. {$ifndef noAllocEdi}
  1469. ungetregister32(R_EDI);
  1470. {$endif noAllocEdi}
  1471. end
  1472. else
  1473. emit_push_mem(tempreference);
  1474. end;
  1475. s64real,
  1476. s64comp :
  1477. begin
  1478. inc(pushedparasize,4);
  1479. inc(tempreference.offset,4);
  1480. if inlined then
  1481. begin
  1482. {$ifndef noAllocEdi}
  1483. getexplicitregister32(R_EDI);
  1484. {$endif noAllocEdi}
  1485. emit_ref_reg(A_MOV,S_L,
  1486. newreference(tempreference),R_EDI);
  1487. r:=new_reference(procinfo^.framepointer,para_offset-pushedparasize);
  1488. exprasmlist^.concat(new(paicpu,op_reg_ref(A_MOV,S_L,R_EDI,r)));
  1489. {$ifndef noAllocEdi}
  1490. ungetregister32(R_EDI);
  1491. {$endif noAllocEdi}
  1492. end
  1493. else
  1494. emit_push_mem(tempreference);
  1495. inc(pushedparasize,4);
  1496. dec(tempreference.offset,4);
  1497. if inlined then
  1498. begin
  1499. {$ifndef noAllocEdi}
  1500. getexplicitregister32(R_EDI);
  1501. {$endif noAllocEdi}
  1502. emit_ref_reg(A_MOV,S_L,
  1503. newreference(tempreference),R_EDI);
  1504. r:=new_reference(procinfo^.framepointer,para_offset-pushedparasize);
  1505. exprasmlist^.concat(new(paicpu,op_reg_ref(A_MOV,S_L,R_EDI,r)));
  1506. {$ifndef noAllocEdi}
  1507. ungetregister32(R_EDI);
  1508. {$endif noAllocEdi}
  1509. end
  1510. else
  1511. emit_push_mem(tempreference);
  1512. end;
  1513. s80real :
  1514. begin
  1515. inc(pushedparasize,4);
  1516. if alignment=4 then
  1517. inc(tempreference.offset,8)
  1518. else
  1519. inc(tempreference.offset,6);
  1520. if inlined then
  1521. begin
  1522. {$ifndef noAllocEdi}
  1523. getexplicitregister32(R_EDI);
  1524. {$endif noAllocEdi}
  1525. emit_ref_reg(A_MOV,S_L,
  1526. newreference(tempreference),R_EDI);
  1527. r:=new_reference(procinfo^.framepointer,para_offset-pushedparasize);
  1528. exprasmlist^.concat(new(paicpu,op_reg_ref(A_MOV,S_L,R_EDI,r)));
  1529. {$ifndef noAllocEdi}
  1530. ungetregister32(R_EDI);
  1531. {$endif noAllocEdi}
  1532. end
  1533. else
  1534. emit_push_mem(tempreference);
  1535. dec(tempreference.offset,4);
  1536. inc(pushedparasize,4);
  1537. if inlined then
  1538. begin
  1539. {$ifndef noAllocEdi}
  1540. getexplicitregister32(R_EDI);
  1541. {$endif noAllocEdi}
  1542. emit_ref_reg(A_MOV,S_L,
  1543. newreference(tempreference),R_EDI);
  1544. r:=new_reference(procinfo^.framepointer,para_offset-pushedparasize);
  1545. exprasmlist^.concat(new(paicpu,op_reg_ref(A_MOV,S_L,R_EDI,r)));
  1546. {$ifndef noAllocEdi}
  1547. ungetregister32(R_EDI);
  1548. {$endif noAllocEdi}
  1549. end
  1550. else
  1551. emit_push_mem(tempreference);
  1552. if alignment=4 then
  1553. begin
  1554. opsize:=S_L;
  1555. hreg:=R_EDI;
  1556. inc(pushedparasize,4);
  1557. dec(tempreference.offset,4);
  1558. end
  1559. else
  1560. begin
  1561. opsize:=S_W;
  1562. hreg:=R_DI;
  1563. inc(pushedparasize,2);
  1564. dec(tempreference.offset,2);
  1565. end;
  1566. if inlined then
  1567. begin
  1568. {$ifndef noAllocEdi}
  1569. getexplicitregister32(R_EDI);
  1570. {$endif noAllocEdi}
  1571. emit_ref_reg(A_MOV,opsize,
  1572. newreference(tempreference),hreg);
  1573. r:=new_reference(procinfo^.framepointer,para_offset-pushedparasize);
  1574. exprasmlist^.concat(new(paicpu,op_reg_ref(A_MOV,opsize,hreg,r)));
  1575. {$ifndef noAllocEdi}
  1576. ungetregister32(R_EDI);
  1577. {$endif noAllocEdi}
  1578. end
  1579. else
  1580. exprasmlist^.concat(new(paicpu,op_ref(A_PUSH,opsize,
  1581. newreference(tempreference))));
  1582. end;
  1583. end;
  1584. end;
  1585. pointerdef,
  1586. procvardef,
  1587. classrefdef:
  1588. begin
  1589. inc(pushedparasize,4);
  1590. if inlined then
  1591. begin
  1592. {$ifndef noAllocEdi}
  1593. getexplicitregister32(R_EDI);
  1594. {$endif noAllocEdi}
  1595. emit_ref_reg(A_MOV,S_L,
  1596. newreference(tempreference),R_EDI);
  1597. r:=new_reference(procinfo^.framepointer,para_offset-pushedparasize);
  1598. exprasmlist^.concat(new(paicpu,op_reg_ref(A_MOV,S_L,R_EDI,r)));
  1599. {$ifndef noAllocEdi}
  1600. ungetregister32(R_EDI);
  1601. {$endif noAllocEdi}
  1602. end
  1603. else
  1604. emit_push_mem(tempreference);
  1605. end;
  1606. arraydef,
  1607. recorddef,
  1608. stringdef,
  1609. setdef,
  1610. objectdef :
  1611. begin
  1612. { even some structured types are 32 bit }
  1613. if is_widestring(p^.resulttype) or
  1614. is_ansistring(p^.resulttype) or
  1615. is_smallset(p^.resulttype) or
  1616. ((p^.resulttype^.deftype in [recorddef,arraydef]) and (p^.resulttype^.size<=4)
  1617. and ((p^.resulttype^.deftype<>arraydef) or not
  1618. (parraydef(p^.resulttype)^.IsConstructor or
  1619. parraydef(p^.resulttype)^.isArrayOfConst or
  1620. is_open_array(p^.resulttype)))
  1621. ) or
  1622. ((p^.resulttype^.deftype=objectdef) and
  1623. pobjectdef(p^.resulttype)^.is_class) then
  1624. begin
  1625. if (p^.resulttype^.size>2) or
  1626. (alignment=4) then
  1627. begin
  1628. inc(pushedparasize,4);
  1629. if inlined then
  1630. begin
  1631. r:=new_reference(procinfo^.framepointer,para_offset-pushedparasize);
  1632. concatcopy(tempreference,r^,4,false,false);
  1633. end
  1634. else
  1635. emit_push_mem(tempreference);
  1636. end
  1637. else
  1638. begin
  1639. if p^.resulttype^.size>0 then
  1640. begin
  1641. inc(pushedparasize,2);
  1642. if inlined then
  1643. begin
  1644. r:=new_reference(procinfo^.framepointer,para_offset-pushedparasize);
  1645. concatcopy(tempreference,r^,2,false,false);
  1646. end
  1647. else
  1648. exprasmlist^.concat(new(paicpu,op_ref(A_PUSH,S_W,newreference(tempreference))));
  1649. end;
  1650. end;
  1651. end
  1652. { call by value open array ? }
  1653. else
  1654. internalerror(8954);
  1655. end;
  1656. else
  1657. CGMessage(cg_e_illegal_expression);
  1658. end;
  1659. end;
  1660. LOC_JUMP:
  1661. begin
  1662. getlabel(hlabel);
  1663. if alignment=4 then
  1664. begin
  1665. opsize:=S_L;
  1666. inc(pushedparasize,4);
  1667. end
  1668. else
  1669. begin
  1670. opsize:=S_W;
  1671. inc(pushedparasize,2);
  1672. end;
  1673. emitlab(truelabel);
  1674. if inlined then
  1675. begin
  1676. r:=new_reference(procinfo^.framepointer,para_offset-pushedparasize);
  1677. emit_const_ref(A_MOV,opsize,1,r);
  1678. end
  1679. else
  1680. exprasmlist^.concat(new(paicpu,op_const(A_PUSH,opsize,1)));
  1681. emitjmp(C_None,hlabel);
  1682. emitlab(falselabel);
  1683. if inlined then
  1684. begin
  1685. r:=new_reference(procinfo^.framepointer,para_offset-pushedparasize);
  1686. emit_const_ref(A_MOV,opsize,0,r);
  1687. end
  1688. else
  1689. exprasmlist^.concat(new(paicpu,op_const(A_PUSH,opsize,0)));
  1690. emitlab(hlabel);
  1691. end;
  1692. LOC_FLAGS:
  1693. begin
  1694. if not(R_EAX in unused) then
  1695. begin
  1696. {$ifndef noAllocEdi}
  1697. getexplicitregister32(R_EDI);
  1698. {$endif noAllocEdi}
  1699. emit_reg_reg(A_MOV,S_L,R_EAX,R_EDI);
  1700. end;
  1701. emit_flag2reg(p^.location.resflags,R_AL);
  1702. emit_reg_reg(A_MOVZX,S_BW,R_AL,R_AX);
  1703. if alignment=4 then
  1704. begin
  1705. opsize:=S_L;
  1706. hreg:=R_EAX;
  1707. inc(pushedparasize,4);
  1708. end
  1709. else
  1710. begin
  1711. opsize:=S_W;
  1712. hreg:=R_AX;
  1713. inc(pushedparasize,2);
  1714. end;
  1715. if inlined then
  1716. begin
  1717. r:=new_reference(procinfo^.framepointer,para_offset-pushedparasize);
  1718. exprasmlist^.concat(new(paicpu,op_reg_ref(A_MOV,opsize,hreg,r)));
  1719. end
  1720. else
  1721. exprasmlist^.concat(new(paicpu,op_reg(A_PUSH,opsize,hreg)));
  1722. if not(R_EAX in unused) then
  1723. begin
  1724. emit_reg_reg(A_MOV,S_L,R_EDI,R_EAX);
  1725. {$ifndef noAllocEdi}
  1726. ungetregister32(R_EDI);
  1727. {$endif noAllocEdi}
  1728. end;
  1729. end;
  1730. {$ifdef SUPPORT_MMX}
  1731. LOC_MMXREGISTER,
  1732. LOC_CMMXREGISTER:
  1733. begin
  1734. inc(pushedparasize,8); { was missing !!! (PM) }
  1735. emit_const_reg(
  1736. A_SUB,S_L,8,R_ESP);
  1737. {$ifdef GDB}
  1738. if (cs_debuginfo in aktmoduleswitches) and
  1739. (exprasmlist^.first=exprasmlist^.last) then
  1740. exprasmlist^.concat(new(pai_force_line,init));
  1741. {$endif GDB}
  1742. if inlined then
  1743. begin
  1744. r:=new_reference(procinfo^.framepointer,para_offset-pushedparasize);
  1745. exprasmlist^.concat(new(paicpu,op_reg_ref(A_MOVQ,S_NO,
  1746. p^.location.register,r)));
  1747. end
  1748. else
  1749. begin
  1750. r:=new_reference(R_ESP,0);
  1751. exprasmlist^.concat(new(paicpu,op_reg_ref(
  1752. A_MOVQ,S_NO,p^.location.register,r)));
  1753. end;
  1754. end;
  1755. {$endif SUPPORT_MMX}
  1756. end;
  1757. end;
  1758. {*****************************************************************************
  1759. Emit Float Functions
  1760. *****************************************************************************}
  1761. procedure floatloadops(t : tfloattype;var op : tasmop;var s : topsize);
  1762. begin
  1763. case t of
  1764. s32real : begin
  1765. op:=A_FLD;
  1766. s:=S_FS;
  1767. end;
  1768. s64real : begin
  1769. op:=A_FLD;
  1770. { ???? }
  1771. s:=S_FL;
  1772. end;
  1773. s80real : begin
  1774. op:=A_FLD;
  1775. s:=S_FX;
  1776. end;
  1777. s64comp : begin
  1778. op:=A_FILD;
  1779. s:=S_IQ;
  1780. end;
  1781. else internalerror(17);
  1782. end;
  1783. end;
  1784. procedure floatload(t : tfloattype;const ref : treference);
  1785. var
  1786. op : tasmop;
  1787. s : topsize;
  1788. begin
  1789. floatloadops(t,op,s);
  1790. exprasmlist^.concat(new(paicpu,op_ref(op,s,
  1791. newreference(ref))));
  1792. inc(fpuvaroffset);
  1793. end;
  1794. procedure floatstoreops(t : tfloattype;var op : tasmop;var s : topsize);
  1795. begin
  1796. case t of
  1797. s32real : begin
  1798. op:=A_FSTP;
  1799. s:=S_FS;
  1800. end;
  1801. s64real : begin
  1802. op:=A_FSTP;
  1803. s:=S_FL;
  1804. end;
  1805. s80real : begin
  1806. op:=A_FSTP;
  1807. s:=S_FX;
  1808. end;
  1809. s64comp : begin
  1810. op:=A_FISTP;
  1811. s:=S_IQ;
  1812. end;
  1813. else
  1814. internalerror(17);
  1815. end;
  1816. end;
  1817. procedure floatstore(t : tfloattype;const ref : treference);
  1818. var
  1819. op : tasmop;
  1820. s : topsize;
  1821. begin
  1822. floatstoreops(t,op,s);
  1823. exprasmlist^.concat(new(paicpu,op_ref(op,s,
  1824. newreference(ref))));
  1825. dec(fpuvaroffset);
  1826. end;
  1827. {*****************************************************************************
  1828. Emit Functions
  1829. *****************************************************************************}
  1830. procedure maketojumpbool(p : ptree);
  1831. {
  1832. produces jumps to true respectively false labels using boolean expressions
  1833. }
  1834. var
  1835. opsize : topsize;
  1836. storepos : tfileposinfo;
  1837. begin
  1838. if p^.error then
  1839. exit;
  1840. storepos:=aktfilepos;
  1841. aktfilepos:=p^.fileinfo;
  1842. if is_boolean(p^.resulttype) then
  1843. begin
  1844. if is_constboolnode(p) then
  1845. begin
  1846. if p^.value<>0 then
  1847. emitjmp(C_None,truelabel)
  1848. else
  1849. emitjmp(C_None,falselabel);
  1850. end
  1851. else
  1852. begin
  1853. opsize:=def_opsize(p^.resulttype);
  1854. case p^.location.loc of
  1855. LOC_CREGISTER,LOC_REGISTER : begin
  1856. emit_reg_reg(A_OR,opsize,p^.location.register,
  1857. p^.location.register);
  1858. ungetregister(p^.location.register);
  1859. emitjmp(C_NZ,truelabel);
  1860. emitjmp(C_None,falselabel);
  1861. end;
  1862. LOC_MEM,LOC_REFERENCE : begin
  1863. emit_const_ref(
  1864. A_CMP,opsize,0,newreference(p^.location.reference));
  1865. del_reference(p^.location.reference);
  1866. emitjmp(C_NZ,truelabel);
  1867. emitjmp(C_None,falselabel);
  1868. end;
  1869. LOC_FLAGS : begin
  1870. emitjmp(flag_2_cond[p^.location.resflags],truelabel);
  1871. emitjmp(C_None,falselabel);
  1872. end;
  1873. end;
  1874. end;
  1875. end
  1876. else
  1877. CGMessage(type_e_mismatch);
  1878. aktfilepos:=storepos;
  1879. end;
  1880. { produces if necessary overflowcode }
  1881. procedure emitoverflowcheck(p:ptree);
  1882. var
  1883. hl : pasmlabel;
  1884. begin
  1885. if not(cs_check_overflow in aktlocalswitches) then
  1886. exit;
  1887. getlabel(hl);
  1888. if not ((p^.resulttype^.deftype=pointerdef) or
  1889. ((p^.resulttype^.deftype=orddef) and
  1890. (porddef(p^.resulttype)^.typ in [u64bit,u16bit,u32bit,u8bit,uchar,
  1891. bool8bit,bool16bit,bool32bit]))) then
  1892. emitjmp(C_NO,hl)
  1893. else
  1894. emitjmp(C_NB,hl);
  1895. emitcall('FPC_OVERFLOW');
  1896. emitlab(hl);
  1897. end;
  1898. { produces range check code, while one of the operands is a 64 bit
  1899. integer }
  1900. procedure emitrangecheck64(p : ptree;todef : pdef);
  1901. begin
  1902. CGMessage(cg_w_64bit_range_check_not_supported);
  1903. {internalerror(28699);}
  1904. end;
  1905. { produces if necessary rangecheckcode }
  1906. procedure emitrangecheck(p:ptree;todef:pdef);
  1907. {
  1908. generate range checking code for the value at location t. The
  1909. type used is the checked against todefs ranges. fromdef (p.resulttype)
  1910. is the original type used at that location, when both defs are
  1911. equal the check is also insert (needed for succ,pref,inc,dec)
  1912. }
  1913. var
  1914. neglabel,
  1915. poslabel : pasmlabel;
  1916. href : treference;
  1917. rstr : string;
  1918. hreg : tregister;
  1919. opsize : topsize;
  1920. op : tasmop;
  1921. fromdef : pdef;
  1922. lto,hto,
  1923. lfrom,hfrom : longint;
  1924. doublebound,
  1925. is_reg,
  1926. popecx : boolean;
  1927. begin
  1928. { range checking on and range checkable value? }
  1929. if not(cs_check_range in aktlocalswitches) or
  1930. not(todef^.deftype in [orddef,enumdef,arraydef]) then
  1931. exit;
  1932. { only check when assigning to scalar, subranges are different,
  1933. when todef=fromdef then the check is always generated }
  1934. fromdef:=p^.resulttype;
  1935. if is_64bitint(fromdef) or is_64bitint(todef) then
  1936. begin
  1937. emitrangecheck64(p,todef);
  1938. exit;
  1939. end;
  1940. {we also need lto and hto when checking if we need to use doublebound!
  1941. (JM)}
  1942. getrange(todef,lto,hto);
  1943. if todef<>fromdef then
  1944. begin
  1945. getrange(p^.resulttype,lfrom,hfrom);
  1946. { first check for not being u32bit, then if the to is bigger than
  1947. from }
  1948. if (lto<hto) and (lfrom<hfrom) and
  1949. (lto<=lfrom) and (hto>=hfrom) then
  1950. exit;
  1951. end;
  1952. { generate the rangecheck code for the def where we are going to
  1953. store the result }
  1954. doublebound:=false;
  1955. case todef^.deftype of
  1956. orddef :
  1957. begin
  1958. porddef(todef)^.genrangecheck;
  1959. rstr:=porddef(todef)^.getrangecheckstring;
  1960. doublebound:=(porddef(todef)^.typ=u32bit) and (lto>hto);
  1961. end;
  1962. enumdef :
  1963. begin
  1964. penumdef(todef)^.genrangecheck;
  1965. rstr:=penumdef(todef)^.getrangecheckstring;
  1966. end;
  1967. arraydef :
  1968. begin
  1969. parraydef(todef)^.genrangecheck;
  1970. rstr:=parraydef(todef)^.getrangecheckstring;
  1971. end;
  1972. end;
  1973. { get op and opsize }
  1974. opsize:=def2def_opsize(fromdef,u32bitdef);
  1975. if opsize in [S_B,S_W,S_L] then
  1976. op:=A_MOV
  1977. else
  1978. if is_signed(fromdef) then
  1979. op:=A_MOVSX
  1980. else
  1981. op:=A_MOVZX;
  1982. is_reg:=(p^.location.loc in [LOC_REGISTER,LOC_CREGISTER]);
  1983. if is_reg then
  1984. hreg:=p^.location.register;
  1985. if not target_os.use_bound_instruction then
  1986. begin
  1987. { FPC_BOUNDCHECK needs to be called with
  1988. %ecx - value
  1989. %edi - pointer to the ranges }
  1990. popecx:=false;
  1991. if not(is_reg) or
  1992. (p^.location.register<>R_ECX) then
  1993. begin
  1994. if not(R_ECX in unused) then
  1995. begin
  1996. exprasmlist^.concat(new(paicpu,op_reg(A_PUSH,S_L,R_ECX)));
  1997. popecx:=true;
  1998. end
  1999. else exprasmlist^.concat(new(pairegalloc,alloc(R_ECX)));
  2000. if is_reg then
  2001. emit_reg_reg(op,opsize,p^.location.register,R_ECX)
  2002. else
  2003. emit_ref_reg(op,opsize,newreference(p^.location.reference),R_ECX);
  2004. end;
  2005. if doublebound then
  2006. begin
  2007. getlabel(neglabel);
  2008. getlabel(poslabel);
  2009. emit_reg_reg(A_OR,S_L,R_ECX,R_ECX);
  2010. emitjmp(C_L,neglabel);
  2011. end;
  2012. { insert bound instruction only }
  2013. {$ifndef noAllocEdi}
  2014. getexplicitregister32(R_EDI);
  2015. {$endif noAllocEdi}
  2016. exprasmlist^.concat(new(paicpu,op_sym_ofs_reg(A_MOV,S_L,newasmsymbol(rstr),0,R_EDI)));
  2017. emitcall('FPC_BOUNDCHECK');
  2018. {$ifndef noAllocEdi}
  2019. ungetregister32(R_EDI);
  2020. {$endif noAllocEdi}
  2021. { u32bit needs 2 checks }
  2022. if doublebound then
  2023. begin
  2024. emitjmp(C_None,poslabel);
  2025. emitlab(neglabel);
  2026. {$ifndef noAllocEdi}
  2027. getexplicitregister32(R_EDI);
  2028. {$endif noAllocEdi}
  2029. exprasmlist^.concat(new(paicpu,op_sym_ofs_reg(A_MOV,S_L,newasmsymbol(rstr),8,R_EDI)));
  2030. emitcall('FPC_BOUNDCHECK');
  2031. {$ifndef noAllocEdi}
  2032. ungetregister32(R_EDI);
  2033. {$endif noAllocEdi}
  2034. emitlab(poslabel);
  2035. end;
  2036. if popecx then
  2037. exprasmlist^.concat(new(paicpu,op_reg(A_POP,S_L,R_ECX)))
  2038. else exprasmlist^.concat(new(pairegalloc,dealloc(R_ECX)));
  2039. end
  2040. else
  2041. begin
  2042. reset_reference(href);
  2043. href.symbol:=newasmsymbol(rstr);
  2044. { load the value in a register }
  2045. if is_reg then
  2046. begin
  2047. { be sure that hreg is a 32 bit reg, if not load it in %edi }
  2048. if p^.location.register in [R_EAX..R_EDI] then
  2049. hreg:=p^.location.register
  2050. else
  2051. begin
  2052. {$ifndef noAllocEdi}
  2053. getexplicitregister32(R_EDI);
  2054. {$endif noAllocEdi}
  2055. emit_reg_reg(op,opsize,p^.location.register,R_EDI);
  2056. hreg:=R_EDI;
  2057. end;
  2058. end
  2059. else
  2060. begin
  2061. {$ifndef noAllocEdi}
  2062. getexplicitregister32(R_EDI);
  2063. {$endif noAllocEdi}
  2064. emit_ref_reg(op,opsize,newreference(p^.location.reference),R_EDI);
  2065. hreg:=R_EDI;
  2066. end;
  2067. if doublebound then
  2068. begin
  2069. getlabel(neglabel);
  2070. getlabel(poslabel);
  2071. emit_reg_reg(A_TEST,S_L,hreg,hreg);
  2072. emitjmp(C_L,neglabel);
  2073. end;
  2074. { insert bound instruction only }
  2075. exprasmlist^.concat(new(paicpu,op_reg_ref(A_BOUND,S_L,hreg,newreference(href))));
  2076. { u32bit needs 2 checks }
  2077. if doublebound then
  2078. begin
  2079. href.offset:=8;
  2080. emitjmp(C_None,poslabel);
  2081. emitlab(neglabel);
  2082. exprasmlist^.concat(new(paicpu,op_reg_ref(A_BOUND,S_L,hreg,newreference(href))));
  2083. emitlab(poslabel);
  2084. end;
  2085. {$ifndef noAllocEdi}
  2086. if hreg = R_EDI then
  2087. ungetregister32(R_EDI);
  2088. {$endif noAllocEdi}
  2089. end;
  2090. end;
  2091. procedure concatcopy(source,dest : treference;size : longint;delsource,loadref : boolean);
  2092. const
  2093. isizes : array[0..3] of topsize=(S_L,S_B,S_W,S_B);
  2094. ishr : array[0..3] of byte=(2,0,1,0);
  2095. var
  2096. ecxpushed : boolean;
  2097. helpsize : longint;
  2098. i : byte;
  2099. reg8,reg32 : tregister;
  2100. swap : boolean;
  2101. procedure maybepushecx;
  2102. begin
  2103. if not(R_ECX in unused) then
  2104. begin
  2105. exprasmlist^.concat(new(paicpu,op_reg(A_PUSH,S_L,R_ECX)));
  2106. ecxpushed:=true;
  2107. end;
  2108. end;
  2109. begin
  2110. {$IfNDef regallocfix}
  2111. If delsource then
  2112. del_reference(source);
  2113. {$EndIf regallocfix}
  2114. if (not loadref) and
  2115. ((size<=8) or
  2116. (not(cs_littlesize in aktglobalswitches ) and (size<=12))) then
  2117. begin
  2118. helpsize:=size shr 2;
  2119. {$ifndef noAllocEdi}
  2120. getexplicitregister32(R_EDI);
  2121. {$endif noAllocEdi}
  2122. for i:=1 to helpsize do
  2123. begin
  2124. emit_ref_reg(A_MOV,S_L,newreference(source),R_EDI);
  2125. {$ifdef regallocfix}
  2126. If (size = 4) and delsource then
  2127. del_reference(source);
  2128. {$endif regallocfix}
  2129. exprasmlist^.concat(new(paicpu,op_reg_ref(A_MOV,S_L,R_EDI,newreference(dest))));
  2130. inc(source.offset,4);
  2131. inc(dest.offset,4);
  2132. dec(size,4);
  2133. end;
  2134. if size>1 then
  2135. begin
  2136. emit_ref_reg(A_MOV,S_W,newreference(source),R_DI);
  2137. {$ifdef regallocfix}
  2138. If (size = 2) and delsource then
  2139. del_reference(source);
  2140. {$endif regallocfix}
  2141. exprasmlist^.concat(new(paicpu,op_reg_ref(A_MOV,S_W,R_DI,newreference(dest))));
  2142. inc(source.offset,2);
  2143. inc(dest.offset,2);
  2144. dec(size,2);
  2145. end;
  2146. {$ifndef noAllocEdi}
  2147. ungetregister32(R_EDI);
  2148. {$endif noAllocEdi}
  2149. if size>0 then
  2150. begin
  2151. { and now look for an 8 bit register }
  2152. swap:=false;
  2153. if R_EAX in unused then reg8:=R_AL
  2154. else if R_EBX in unused then reg8:=R_BL
  2155. else if R_ECX in unused then reg8:=R_CL
  2156. else if R_EDX in unused then reg8:=R_DL
  2157. else
  2158. begin
  2159. swap:=true;
  2160. { we need only to check 3 registers, because }
  2161. { one is always not index or base }
  2162. if (dest.base<>R_EAX) and (dest.index<>R_EAX) then
  2163. begin
  2164. reg8:=R_AL;
  2165. reg32:=R_EAX;
  2166. end
  2167. else if (dest.base<>R_EBX) and (dest.index<>R_EBX) then
  2168. begin
  2169. reg8:=R_BL;
  2170. reg32:=R_EBX;
  2171. end
  2172. else if (dest.base<>R_ECX) and (dest.index<>R_ECX) then
  2173. begin
  2174. reg8:=R_CL;
  2175. reg32:=R_ECX;
  2176. end;
  2177. end;
  2178. if swap then
  2179. { was earlier XCHG, of course nonsense }
  2180. begin
  2181. {$ifndef noAllocEdi}
  2182. getexplicitregister32(R_EDI);
  2183. {$endif noAllocEdi}
  2184. emit_reg_reg(A_MOV,S_L,reg32,R_EDI);
  2185. end;
  2186. emit_ref_reg(A_MOV,S_B,newreference(source),reg8);
  2187. {$ifdef regallocfix}
  2188. If delsource then
  2189. del_reference(source);
  2190. {$endif regallocfix}
  2191. exprasmlist^.concat(new(paicpu,op_reg_ref(A_MOV,S_B,reg8,newreference(dest))));
  2192. if swap then
  2193. begin
  2194. emit_reg_reg(A_MOV,S_L,R_EDI,reg32);
  2195. {$ifndef noAllocEdi}
  2196. ungetregister32(R_EDI);
  2197. {$endif noAllocEdi}
  2198. end;
  2199. end;
  2200. end
  2201. else
  2202. begin
  2203. {$ifndef noAllocEdi}
  2204. getexplicitregister32(R_EDI);
  2205. {$endif noAllocEdi}
  2206. emit_ref_reg(A_LEA,S_L,newreference(dest),R_EDI);
  2207. {$ifdef regallocfix}
  2208. {is this ok?? (JM)}
  2209. del_reference(dest);
  2210. {$endif regallocfix}
  2211. {$ifndef noAllocEdi}
  2212. exprasmlist^.concat(new(pairegalloc,alloc(R_ESI)));
  2213. {$endif noAllocEdi}
  2214. if loadref then
  2215. emit_ref_reg(A_MOV,S_L,newreference(source),R_ESI)
  2216. else
  2217. begin
  2218. emit_ref_reg(A_LEA,S_L,newreference(source),R_ESI);
  2219. {$ifdef regallocfix}
  2220. if delsource then
  2221. del_reference(source);
  2222. {$endif regallocfix}
  2223. end;
  2224. exprasmlist^.concat(new(paicpu,op_none(A_CLD,S_NO)));
  2225. ecxpushed:=false;
  2226. if cs_littlesize in aktglobalswitches then
  2227. begin
  2228. maybepushecx;
  2229. emit_const_reg(A_MOV,S_L,size,R_ECX);
  2230. exprasmlist^.concat(new(paicpu,op_none(A_REP,S_NO)));
  2231. exprasmlist^.concat(new(paicpu,op_none(A_MOVSB,S_NO)));
  2232. end
  2233. else
  2234. begin
  2235. helpsize:=size shr 2;
  2236. size:=size and 3;
  2237. if helpsize>1 then
  2238. begin
  2239. maybepushecx;
  2240. emit_const_reg(A_MOV,S_L,helpsize,R_ECX);
  2241. exprasmlist^.concat(new(paicpu,op_none(A_REP,S_NO)));
  2242. end;
  2243. if helpsize>0 then
  2244. exprasmlist^.concat(new(paicpu,op_none(A_MOVSD,S_NO)));
  2245. if size>1 then
  2246. begin
  2247. dec(size,2);
  2248. exprasmlist^.concat(new(paicpu,op_none(A_MOVSW,S_NO)));
  2249. end;
  2250. if size=1 then
  2251. exprasmlist^.concat(new(paicpu,op_none(A_MOVSB,S_NO)));
  2252. end;
  2253. {$ifndef noAllocEdi}
  2254. ungetregister32(R_EDI);
  2255. exprasmlist^.concat(new(pairegalloc,dealloc(R_ESI)));
  2256. {$endif noAllocEdi}
  2257. if ecxpushed then
  2258. begin
  2259. exprasmlist^.concat(new(paicpu,op_reg(A_POP,S_L,R_ECX)));
  2260. end;
  2261. { loading SELF-reference again }
  2262. maybe_loadesi;
  2263. end;
  2264. if delsource then
  2265. ungetiftemp(source);
  2266. end;
  2267. procedure emitloadord2reg(const location:Tlocation;orddef:Porddef;
  2268. destreg:Tregister;delloc:boolean);
  2269. {A lot smaller and less bug sensitive than the original unfolded loads.}
  2270. var tai:Paicpu;
  2271. r:Preference;
  2272. begin
  2273. case location.loc of
  2274. LOC_REGISTER,LOC_CREGISTER:
  2275. begin
  2276. case orddef^.typ of
  2277. u8bit:
  2278. tai:=new(paicpu,op_reg_reg(A_MOVZX,S_BL,location.register,destreg));
  2279. s8bit:
  2280. tai:=new(paicpu,op_reg_reg(A_MOVSX,S_BL,location.register,destreg));
  2281. u16bit:
  2282. tai:=new(paicpu,op_reg_reg(A_MOVZX,S_WL,location.register,destreg));
  2283. s16bit:
  2284. tai:=new(paicpu,op_reg_reg(A_MOVSX,S_WL,location.register,destreg));
  2285. u32bit:
  2286. tai:=new(paicpu,op_reg_reg(A_MOV,S_L,location.register,destreg));
  2287. s32bit:
  2288. tai:=new(paicpu,op_reg_reg(A_MOV,S_L,location.register,destreg));
  2289. end;
  2290. if delloc then
  2291. ungetregister(location.register);
  2292. end;
  2293. LOC_MEM,
  2294. LOC_REFERENCE:
  2295. begin
  2296. if location.reference.is_immediate then
  2297. tai:=new(paicpu,op_const_reg(A_MOV,S_L,location.reference.offset,destreg))
  2298. else
  2299. begin
  2300. r:=newreference(location.reference);
  2301. case orddef^.typ of
  2302. u8bit:
  2303. tai:=new(paicpu,op_ref_reg(A_MOVZX,S_BL,r,destreg));
  2304. s8bit:
  2305. tai:=new(paicpu,op_ref_reg(A_MOVSX,S_BL,r,destreg));
  2306. u16bit:
  2307. tai:=new(paicpu,op_ref_reg(A_MOVZX,S_WL,r,destreg));
  2308. s16bit:
  2309. tai:=new(paicpu,op_ref_reg(A_MOVSX,S_WL,r,destreg));
  2310. u32bit:
  2311. tai:=new(paicpu,op_ref_reg(A_MOV,S_L,r,destreg));
  2312. s32bit:
  2313. tai:=new(paicpu,op_ref_reg(A_MOV,S_L,r,destreg));
  2314. end;
  2315. end;
  2316. if delloc then
  2317. del_reference(location.reference);
  2318. end
  2319. else
  2320. internalerror(6);
  2321. end;
  2322. exprasmlist^.concat(tai);
  2323. end;
  2324. { if necessary ESI is reloaded after a call}
  2325. procedure maybe_loadesi;
  2326. var
  2327. hp : preference;
  2328. p : pprocinfo;
  2329. i : longint;
  2330. begin
  2331. if assigned(procinfo^._class) then
  2332. begin
  2333. {$ifndef noAllocEdi}
  2334. exprasmlist^.concat(new(pairegalloc,alloc(R_ESI)));
  2335. {$endif noAllocEdi}
  2336. if lexlevel>normal_function_level then
  2337. begin
  2338. new(hp);
  2339. reset_reference(hp^);
  2340. hp^.offset:=procinfo^.framepointer_offset;
  2341. hp^.base:=procinfo^.framepointer;
  2342. emit_ref_reg(A_MOV,S_L,hp,R_ESI);
  2343. p:=procinfo^.parent;
  2344. for i:=3 to lexlevel-1 do
  2345. begin
  2346. new(hp);
  2347. reset_reference(hp^);
  2348. hp^.offset:=p^.framepointer_offset;
  2349. hp^.base:=R_ESI;
  2350. emit_ref_reg(A_MOV,S_L,hp,R_ESI);
  2351. p:=p^.parent;
  2352. end;
  2353. new(hp);
  2354. reset_reference(hp^);
  2355. hp^.offset:=p^.selfpointer_offset;
  2356. hp^.base:=R_ESI;
  2357. emit_ref_reg(A_MOV,S_L,hp,R_ESI);
  2358. end
  2359. else
  2360. begin
  2361. new(hp);
  2362. reset_reference(hp^);
  2363. hp^.offset:=procinfo^.selfpointer_offset;
  2364. hp^.base:=procinfo^.framepointer;
  2365. emit_ref_reg(A_MOV,S_L,hp,R_ESI);
  2366. end;
  2367. end;
  2368. end;
  2369. procedure firstcomplex(p : ptree);
  2370. var
  2371. hp : ptree;
  2372. begin
  2373. { always calculate boolean AND and OR from left to right }
  2374. if (p^.treetype in [orn,andn]) and
  2375. (p^.left^.resulttype^.deftype=orddef) and
  2376. (porddef(p^.left^.resulttype)^.typ in [bool8bit,bool16bit,bool32bit]) then
  2377. p^.swaped:=false
  2378. else
  2379. if (p^.left^.registers32<p^.right^.registers32) and
  2380. { the following check is appropriate, because all }
  2381. { 4 registers are rarely used and it is thereby }
  2382. { achieved that the extra code is being dropped }
  2383. { by exchanging not commutative operators }
  2384. (p^.right^.registers32<=4) then
  2385. begin
  2386. hp:=p^.left;
  2387. p^.left:=p^.right;
  2388. p^.right:=hp;
  2389. p^.swaped:=true;
  2390. end
  2391. else
  2392. p^.swaped:=false;
  2393. end;
  2394. {*****************************************************************************
  2395. Entry/Exit Code Functions
  2396. *****************************************************************************}
  2397. procedure genprofilecode;
  2398. var
  2399. pl : pasmlabel;
  2400. begin
  2401. if (po_assembler in aktprocsym^.definition^.procoptions) then
  2402. exit;
  2403. case target_info.target of
  2404. target_i386_linux:
  2405. begin
  2406. getlabel(pl);
  2407. emitcall('mcount');
  2408. exprasmlist^.insert(new(paicpu,op_sym_ofs_reg(A_MOV,S_L,pl,0,R_EDX)));
  2409. exprasmlist^.insert(new(pai_section,init(sec_code)));
  2410. exprasmlist^.insert(new(pai_const,init_32bit(0)));
  2411. exprasmlist^.insert(new(pai_label,init(pl)));
  2412. exprasmlist^.insert(new(pai_align,init(4)));
  2413. exprasmlist^.insert(new(pai_section,init(sec_data)));
  2414. end;
  2415. target_i386_go32v2:
  2416. begin
  2417. emitinsertcall('MCOUNT');
  2418. end;
  2419. end;
  2420. end;
  2421. procedure generate_interrupt_stackframe_entry;
  2422. begin
  2423. { save the registers of an interrupt procedure }
  2424. exprasmlist^.insert(new(paicpu,op_reg(A_PUSH,S_L,R_EAX)));
  2425. exprasmlist^.insert(new(paicpu,op_reg(A_PUSH,S_L,R_EBX)));
  2426. exprasmlist^.insert(new(paicpu,op_reg(A_PUSH,S_L,R_ECX)));
  2427. exprasmlist^.insert(new(paicpu,op_reg(A_PUSH,S_L,R_EDX)));
  2428. exprasmlist^.insert(new(paicpu,op_reg(A_PUSH,S_L,R_ESI)));
  2429. exprasmlist^.insert(new(paicpu,op_reg(A_PUSH,S_L,R_EDI)));
  2430. { .... also the segment registers }
  2431. exprasmlist^.insert(new(paicpu,op_reg(A_PUSH,S_W,R_DS)));
  2432. exprasmlist^.insert(new(paicpu,op_reg(A_PUSH,S_W,R_ES)));
  2433. exprasmlist^.insert(new(paicpu,op_reg(A_PUSH,S_W,R_FS)));
  2434. exprasmlist^.insert(new(paicpu,op_reg(A_PUSH,S_W,R_GS)));
  2435. end;
  2436. procedure generate_interrupt_stackframe_exit;
  2437. begin
  2438. { restore the registers of an interrupt procedure }
  2439. { this was all with entrycode instead of exitcode !!}
  2440. procinfo^.aktexitcode^.concat(new(paicpu,op_reg(A_POP,S_L,R_EAX)));
  2441. procinfo^.aktexitcode^.concat(new(paicpu,op_reg(A_POP,S_L,R_EBX)));
  2442. procinfo^.aktexitcode^.concat(new(paicpu,op_reg(A_POP,S_L,R_ECX)));
  2443. procinfo^.aktexitcode^.concat(new(paicpu,op_reg(A_POP,S_L,R_EDX)));
  2444. procinfo^.aktexitcode^.concat(new(paicpu,op_reg(A_POP,S_L,R_ESI)));
  2445. procinfo^.aktexitcode^.concat(new(paicpu,op_reg(A_POP,S_L,R_EDI)));
  2446. { .... also the segment registers }
  2447. procinfo^.aktexitcode^.concat(new(paicpu,op_reg(A_POP,S_W,R_DS)));
  2448. procinfo^.aktexitcode^.concat(new(paicpu,op_reg(A_POP,S_W,R_ES)));
  2449. procinfo^.aktexitcode^.concat(new(paicpu,op_reg(A_POP,S_W,R_FS)));
  2450. procinfo^.aktexitcode^.concat(new(paicpu,op_reg(A_POP,S_W,R_GS)));
  2451. { this restores the flags }
  2452. procinfo^.aktexitcode^.concat(new(paicpu,op_none(A_IRET,S_NO)));
  2453. end;
  2454. { generates the code for threadvar initialisation }
  2455. procedure initialize_threadvar(p : pnamedindexobject);{$ifndef FPC}far;{$endif}
  2456. var
  2457. hr : treference;
  2458. begin
  2459. if (psym(p)^.typ=varsym) and
  2460. (vo_is_thread_var in pvarsym(p)^.varoptions) then
  2461. begin
  2462. exprasmlist^.concat(new(paicpu,op_const(A_PUSH,S_L,pvarsym(p)^.getsize)));
  2463. reset_reference(hr);
  2464. hr.symbol:=newasmsymbol(pvarsym(p)^.mangledname);
  2465. emitpushreferenceaddr(hr);
  2466. emitcall('FPC_INIT_THREADVAR');
  2467. end;
  2468. end;
  2469. { initilizes data of type t }
  2470. { if is_already_ref is true then the routines assumes }
  2471. { that r points to the data to initialize }
  2472. procedure initialize(t : pdef;const ref : treference;is_already_ref : boolean);
  2473. var
  2474. hr : treference;
  2475. begin
  2476. if is_ansistring(t) or
  2477. is_widestring(t) then
  2478. begin
  2479. emit_const_ref(A_MOV,S_L,0,
  2480. newreference(ref));
  2481. end
  2482. else
  2483. begin
  2484. reset_reference(hr);
  2485. hr.symbol:=t^.get_inittable_label;
  2486. emitpushreferenceaddr(hr);
  2487. if is_already_ref then
  2488. exprasmlist^.concat(new(paicpu,op_ref(A_PUSH,S_L,
  2489. newreference(ref))))
  2490. else
  2491. emitpushreferenceaddr(ref);
  2492. emitcall('FPC_INITIALIZE');
  2493. end;
  2494. end;
  2495. { finalizes data of type t }
  2496. { if is_already_ref is true then the routines assumes }
  2497. { that r points to the data to finalizes }
  2498. procedure finalize(t : pdef;const ref : treference;is_already_ref : boolean);
  2499. var
  2500. r : treference;
  2501. begin
  2502. if is_ansistring(t) or
  2503. is_widestring(t) then
  2504. begin
  2505. decrstringref(t,ref);
  2506. end
  2507. else
  2508. begin
  2509. reset_reference(r);
  2510. r.symbol:=t^.get_inittable_label;
  2511. emitpushreferenceaddr(r);
  2512. if is_already_ref then
  2513. exprasmlist^.concat(new(paicpu,op_ref(A_PUSH,S_L,
  2514. newreference(ref))))
  2515. else
  2516. emitpushreferenceaddr(ref);
  2517. emitcall('FPC_FINALIZE');
  2518. end;
  2519. end;
  2520. { generates the code for initialisation of local data }
  2521. procedure initialize_data(p : pnamedindexobject);{$ifndef FPC}far;{$endif}
  2522. var
  2523. hr : treference;
  2524. begin
  2525. if (psym(p)^.typ=varsym) and
  2526. assigned(pvarsym(p)^.vartype.def) and
  2527. not((pvarsym(p)^.vartype.def^.deftype=objectdef) and
  2528. pobjectdef(pvarsym(p)^.vartype.def)^.is_class) and
  2529. pvarsym(p)^.vartype.def^.needs_inittable then
  2530. begin
  2531. procinfo^.flags:=procinfo^.flags or pi_needs_implicit_finally;
  2532. reset_reference(hr);
  2533. if psym(p)^.owner^.symtabletype=localsymtable then
  2534. begin
  2535. hr.base:=procinfo^.framepointer;
  2536. hr.offset:=-pvarsym(p)^.address;
  2537. end
  2538. else
  2539. begin
  2540. hr.symbol:=newasmsymbol(pvarsym(p)^.mangledname);
  2541. end;
  2542. initialize(pvarsym(p)^.vartype.def,hr,false);
  2543. end;
  2544. end;
  2545. { generates the code for incrementing the reference count of parameters }
  2546. procedure incr_data(p : pnamedindexobject);{$ifndef FPC}far;{$endif}
  2547. var
  2548. hr : treference;
  2549. begin
  2550. if (psym(p)^.typ=varsym) and
  2551. not((pvarsym(p)^.vartype.def^.deftype=objectdef) and
  2552. pobjectdef(pvarsym(p)^.vartype.def)^.is_class) and
  2553. pvarsym(p)^.vartype.def^.needs_inittable and
  2554. ((pvarsym(p)^.varspez=vs_value) {or
  2555. (pvarsym(p)^.varspez=vs_const) and
  2556. not(dont_copy_const_param(pvarsym(p)^.definition))}) then
  2557. begin
  2558. procinfo^.flags:=procinfo^.flags or pi_needs_implicit_finally;
  2559. reset_reference(hr);
  2560. hr.symbol:=pvarsym(p)^.vartype.def^.get_inittable_label;
  2561. emitpushreferenceaddr(hr);
  2562. reset_reference(hr);
  2563. hr.base:=procinfo^.framepointer;
  2564. hr.offset:=pvarsym(p)^.address+procinfo^.para_offset;
  2565. emitpushreferenceaddr(hr);
  2566. reset_reference(hr);
  2567. emitcall('FPC_ADDREF');
  2568. end;
  2569. end;
  2570. { generates the code for finalisation of local data }
  2571. procedure finalize_data(p : pnamedindexobject);{$ifndef FPC}far;{$endif}
  2572. var
  2573. hr : treference;
  2574. begin
  2575. if (psym(p)^.typ=varsym) and
  2576. assigned(pvarsym(p)^.vartype.def) and
  2577. not((pvarsym(p)^.vartype.def^.deftype=objectdef) and
  2578. pobjectdef(pvarsym(p)^.vartype.def)^.is_class) and
  2579. pvarsym(p)^.vartype.def^.needs_inittable then
  2580. begin
  2581. { not all kind of parameters need to be finalized }
  2582. if (psym(p)^.owner^.symtabletype=parasymtable) and
  2583. ((pvarsym(p)^.varspez=vs_var) or
  2584. (pvarsym(p)^.varspez=vs_const) { and
  2585. (dont_copy_const_param(pvarsym(p)^.definition)) } ) then
  2586. exit;
  2587. procinfo^.flags:=procinfo^.flags or pi_needs_implicit_finally;
  2588. reset_reference(hr);
  2589. case psym(p)^.owner^.symtabletype of
  2590. localsymtable:
  2591. begin
  2592. hr.base:=procinfo^.framepointer;
  2593. hr.offset:=-pvarsym(p)^.address;
  2594. end;
  2595. parasymtable:
  2596. begin
  2597. hr.base:=procinfo^.framepointer;
  2598. hr.offset:=pvarsym(p)^.address+procinfo^.para_offset;
  2599. end;
  2600. else
  2601. hr.symbol:=newasmsymbol(pvarsym(p)^.mangledname);
  2602. end;
  2603. finalize(pvarsym(p)^.vartype.def,hr,false);
  2604. end;
  2605. end;
  2606. { generates the code to make local copies of the value parameters }
  2607. procedure copyvalueparas(p : pnamedindexobject);{$ifndef fpc}far;{$endif}
  2608. var
  2609. href1,href2 : treference;
  2610. r : preference;
  2611. len : longint;
  2612. opsize : topsize;
  2613. again,ok : pasmlabel;
  2614. begin
  2615. if (psym(p)^.typ=varsym) and
  2616. (pvarsym(p)^.varspez=vs_value) and
  2617. (push_addr_param(pvarsym(p)^.vartype.def)) then
  2618. begin
  2619. if is_open_array(pvarsym(p)^.vartype.def) or
  2620. is_array_of_const(pvarsym(p)^.vartype.def) then
  2621. begin
  2622. { get stack space }
  2623. new(r);
  2624. reset_reference(r^);
  2625. r^.base:=procinfo^.framepointer;
  2626. r^.offset:=pvarsym(p)^.address+4+procinfo^.para_offset;
  2627. {$ifndef noAllocEdi}
  2628. getexplicitregister32(R_EDI);
  2629. {$endif noAllocEdi}
  2630. exprasmlist^.concat(new(paicpu,
  2631. op_ref_reg(A_MOV,S_L,r,R_EDI)));
  2632. exprasmlist^.concat(new(paicpu,
  2633. op_reg(A_INC,S_L,R_EDI)));
  2634. exprasmlist^.concat(new(paicpu,
  2635. op_const_reg(A_IMUL,S_L,
  2636. parraydef(pvarsym(p)^.vartype.def)^.elementtype.def^.size,R_EDI)));
  2637. {$ifndef NOTARGETWIN32}
  2638. { windows guards only a few pages for stack growing, }
  2639. { so we have to access every page first }
  2640. if target_os.id=os_i386_win32 then
  2641. begin
  2642. getlabel(again);
  2643. getlabel(ok);
  2644. emitlab(again);
  2645. exprasmlist^.concat(new(paicpu,
  2646. op_const_reg(A_CMP,S_L,winstackpagesize,R_EDI)));
  2647. emitjmp(C_C,ok);
  2648. exprasmlist^.concat(new(paicpu,
  2649. op_const_reg(A_SUB,S_L,winstackpagesize-4,R_ESP)));
  2650. exprasmlist^.concat(new(paicpu,
  2651. op_reg(A_PUSH,S_L,R_EAX)));
  2652. exprasmlist^.concat(new(paicpu,
  2653. op_const_reg(A_SUB,S_L,winstackpagesize,R_EDI)));
  2654. emitjmp(C_None,again);
  2655. emitlab(ok);
  2656. exprasmlist^.concat(new(paicpu,
  2657. op_reg_reg(A_SUB,S_L,R_EDI,R_ESP)));
  2658. {$ifndef noAllocEdi}
  2659. ungetregister32(R_EDI);
  2660. {$endif noAllocEdi}
  2661. { now reload EDI }
  2662. new(r);
  2663. reset_reference(r^);
  2664. r^.base:=procinfo^.framepointer;
  2665. r^.offset:=pvarsym(p)^.address+4+procinfo^.para_offset;
  2666. {$ifndef noAllocEdi}
  2667. getexplicitregister32(R_EDI);
  2668. {$endif noAllocEdi}
  2669. exprasmlist^.concat(new(paicpu,
  2670. op_ref_reg(A_MOV,S_L,r,R_EDI)));
  2671. exprasmlist^.concat(new(paicpu,
  2672. op_reg(A_INC,S_L,R_EDI)));
  2673. exprasmlist^.concat(new(paicpu,
  2674. op_const_reg(A_IMUL,S_L,
  2675. parraydef(pvarsym(p)^.vartype.def)^.elementtype.def^.size,R_EDI)));
  2676. end
  2677. else
  2678. {$endif NOTARGETWIN32}
  2679. begin
  2680. exprasmlist^.concat(new(paicpu,
  2681. op_reg_reg(A_SUB,S_L,R_EDI,R_ESP)));
  2682. { load destination }
  2683. exprasmlist^.concat(new(paicpu,
  2684. op_reg_reg(A_MOV,S_L,R_ESP,R_EDI)));
  2685. end;
  2686. { don't destroy the registers! }
  2687. exprasmlist^.concat(new(paicpu,
  2688. op_reg(A_PUSH,S_L,R_ECX)));
  2689. exprasmlist^.concat(new(paicpu,
  2690. op_reg(A_PUSH,S_L,R_ESI)));
  2691. { load count }
  2692. new(r);
  2693. reset_reference(r^);
  2694. r^.base:=procinfo^.framepointer;
  2695. r^.offset:=pvarsym(p)^.address+4+procinfo^.para_offset;
  2696. exprasmlist^.concat(new(paicpu,
  2697. op_ref_reg(A_MOV,S_L,r,R_ECX)));
  2698. { load source }
  2699. new(r);
  2700. reset_reference(r^);
  2701. r^.base:=procinfo^.framepointer;
  2702. r^.offset:=pvarsym(p)^.address+procinfo^.para_offset;
  2703. exprasmlist^.concat(new(paicpu,
  2704. op_ref_reg(A_MOV,S_L,r,R_ESI)));
  2705. { scheduled .... }
  2706. exprasmlist^.concat(new(paicpu,
  2707. op_reg(A_INC,S_L,R_ECX)));
  2708. { calculate size }
  2709. len:=parraydef(pvarsym(p)^.vartype.def)^.elementtype.def^.size;
  2710. opsize:=S_B;
  2711. if (len and 3)=0 then
  2712. begin
  2713. opsize:=S_L;
  2714. len:=len shr 2;
  2715. end
  2716. else
  2717. if (len and 1)=0 then
  2718. begin
  2719. opsize:=S_W;
  2720. len:=len shr 1;
  2721. end;
  2722. exprasmlist^.concat(new(paicpu,
  2723. op_const_reg(A_IMUL,S_L,len,R_ECX)));
  2724. exprasmlist^.concat(new(paicpu,
  2725. op_none(A_REP,S_NO)));
  2726. case opsize of
  2727. S_B : exprasmlist^.concat(new(paicpu,op_none(A_MOVSB,S_NO)));
  2728. S_W : exprasmlist^.concat(new(paicpu,op_none(A_MOVSW,S_NO)));
  2729. S_L : exprasmlist^.concat(new(paicpu,op_none(A_MOVSD,S_NO)));
  2730. end;
  2731. {$ifndef noAllocEdi}
  2732. ungetregister32(R_EDI);
  2733. {$endif noAllocEdi}
  2734. exprasmlist^.concat(new(paicpu,
  2735. op_reg(A_POP,S_L,R_ESI)));
  2736. exprasmlist^.concat(new(paicpu,
  2737. op_reg(A_POP,S_L,R_ECX)));
  2738. { patch the new address }
  2739. new(r);
  2740. reset_reference(r^);
  2741. r^.base:=procinfo^.framepointer;
  2742. r^.offset:=pvarsym(p)^.address+procinfo^.para_offset;
  2743. exprasmlist^.concat(new(paicpu,
  2744. op_reg_ref(A_MOV,S_L,R_ESP,r)));
  2745. end
  2746. else
  2747. if is_shortstring(pvarsym(p)^.vartype.def) then
  2748. begin
  2749. reset_reference(href1);
  2750. href1.base:=procinfo^.framepointer;
  2751. href1.offset:=pvarsym(p)^.address+procinfo^.para_offset;
  2752. reset_reference(href2);
  2753. href2.base:=procinfo^.framepointer;
  2754. href2.offset:=-pvarsym(p)^.localvarsym^.address;
  2755. copyshortstring(href2,href1,pstringdef(pvarsym(p)^.vartype.def)^.len,true);
  2756. end
  2757. else
  2758. begin
  2759. reset_reference(href1);
  2760. href1.base:=procinfo^.framepointer;
  2761. href1.offset:=pvarsym(p)^.address+procinfo^.para_offset;
  2762. reset_reference(href2);
  2763. href2.base:=procinfo^.framepointer;
  2764. href2.offset:=-pvarsym(p)^.localvarsym^.address;
  2765. concatcopy(href1,href2,pvarsym(p)^.vartype.def^.size,true,true);
  2766. end;
  2767. end;
  2768. end;
  2769. procedure inittempansistrings;
  2770. var
  2771. hp : ptemprecord;
  2772. r : preference;
  2773. begin
  2774. hp:=templist;
  2775. while assigned(hp) do
  2776. begin
  2777. if hp^.temptype in [tt_ansistring,tt_freeansistring] then
  2778. begin
  2779. procinfo^.flags:=procinfo^.flags or pi_needs_implicit_finally;
  2780. new(r);
  2781. reset_reference(r^);
  2782. r^.base:=procinfo^.framepointer;
  2783. r^.offset:=hp^.pos;
  2784. emit_const_ref(A_MOV,S_L,0,r);
  2785. end;
  2786. hp:=hp^.next;
  2787. end;
  2788. end;
  2789. procedure finalizetempansistrings;
  2790. var
  2791. hp : ptemprecord;
  2792. hr : treference;
  2793. begin
  2794. hp:=templist;
  2795. while assigned(hp) do
  2796. begin
  2797. if hp^.temptype in [tt_ansistring,tt_freeansistring] then
  2798. begin
  2799. procinfo^.flags:=procinfo^.flags or pi_needs_implicit_finally;
  2800. reset_reference(hr);
  2801. hr.base:=procinfo^.framepointer;
  2802. hr.offset:=hp^.pos;
  2803. emitpushreferenceaddr(hr);
  2804. emitcall('FPC_ANSISTR_DECR_REF');
  2805. end;
  2806. hp:=hp^.next;
  2807. end;
  2808. end;
  2809. var
  2810. ls : longint;
  2811. procedure largest_size(p : pnamedindexobject);{$ifndef FPC}far;{$endif}
  2812. begin
  2813. if (psym(p)^.typ=varsym) and
  2814. (pvarsym(p)^.getsize>ls) then
  2815. ls:=pvarsym(p)^.getsize;
  2816. end;
  2817. procedure alignstack(alist : paasmoutput);
  2818. begin
  2819. {$ifdef dummy}
  2820. if (cs_optimize in aktglobalswitches) and
  2821. (aktoptprocessor in [classp5,classp6]) then
  2822. begin
  2823. ls:=0;
  2824. aktprocsym^.definition^.localst^.foreach({$ifndef TP}@{$endif}largest_size);
  2825. if ls>=8 then
  2826. alist^.insert(new(paicpu,op_const_reg(A_AND,S_L,-8,R_ESP)));
  2827. end;
  2828. {$endif dummy}
  2829. end;
  2830. procedure genentrycode(alist : paasmoutput;const proc_names:Tstringcontainer;make_global:boolean;
  2831. stackframe:longint;
  2832. var parasize:longint;var nostackframe:boolean;
  2833. inlined : boolean);
  2834. {
  2835. Generates the entry code for a procedure
  2836. }
  2837. var
  2838. hs : string;
  2839. {$ifdef GDB}
  2840. stab_function_name : Pai_stab_function_name;
  2841. {$endif GDB}
  2842. hr : preference;
  2843. p : psymtable;
  2844. r : treference;
  2845. oldlist,
  2846. oldexprasmlist : paasmoutput;
  2847. again : pasmlabel;
  2848. i : longint;
  2849. begin
  2850. oldexprasmlist:=exprasmlist;
  2851. exprasmlist:=alist;
  2852. if (not inlined) and (aktprocsym^.definition^.proctypeoption=potype_proginit) then
  2853. begin
  2854. emitinsertcall('FPC_INITIALIZEUNITS');
  2855. if target_info.target=target_I386_WIN32 then
  2856. begin
  2857. new(hr);
  2858. reset_reference(hr^);
  2859. hr^.symbol:=newasmsymbol(
  2860. 'U_SYSWIN32_ISCONSOLE');
  2861. if apptype=at_cui then
  2862. exprasmlist^.insert(new(paicpu,op_const_ref(A_MOV,S_B,
  2863. 1,hr)))
  2864. else
  2865. exprasmlist^.insert(new(paicpu,op_const_ref(A_MOV,S_B,
  2866. 0,hr)));
  2867. end;
  2868. oldlist:=exprasmlist;
  2869. exprasmlist:=new(paasmoutput,init);
  2870. p:=symtablestack;
  2871. while assigned(p) do
  2872. begin
  2873. p^.foreach({$ifndef TP}@{$endif}initialize_threadvar);
  2874. p:=p^.next;
  2875. end;
  2876. oldlist^.insertlist(exprasmlist);
  2877. dispose(exprasmlist,done);
  2878. exprasmlist:=oldlist;
  2879. end;
  2880. {$ifdef GDB}
  2881. if (not inlined) and (cs_debuginfo in aktmoduleswitches) then
  2882. exprasmlist^.insert(new(pai_force_line,init));
  2883. {$endif GDB}
  2884. { a constructor needs a help procedure }
  2885. if (aktprocsym^.definition^.proctypeoption=potype_constructor) then
  2886. begin
  2887. if procinfo^._class^.is_class then
  2888. begin
  2889. procinfo^.flags:=procinfo^.flags or pi_needs_implicit_finally;
  2890. exprasmlist^.insert(new(paicpu,op_cond_sym(A_Jcc,C_Z,S_NO,faillabel)));
  2891. emitinsertcall('FPC_NEW_CLASS');
  2892. end
  2893. else
  2894. begin
  2895. exprasmlist^.insert(new(paicpu,op_cond_sym(A_Jcc,C_Z,S_NO,faillabel)));
  2896. emitinsertcall('FPC_HELP_CONSTRUCTOR');
  2897. {$ifndef noAllocEdi}
  2898. getexplicitregister32(R_EDI);
  2899. {$endif noAllocEdi}
  2900. exprasmlist^.insert(new(paicpu,op_const_reg(A_MOV,S_L,procinfo^._class^.vmt_offset,R_EDI)));
  2901. end;
  2902. end;
  2903. { don't load ESI, does the caller }
  2904. { When message method contains self as a parameter,
  2905. we must load it into ESI }
  2906. If (po_containsself in aktprocsym^.definition^.procoptions) then
  2907. begin
  2908. new(hr);
  2909. reset_reference(hr^);
  2910. hr^.offset:=procinfo^.selfpointer_offset;
  2911. hr^.base:=procinfo^.framepointer;
  2912. {$ifndef noAllocEdi}
  2913. exprasmlist^.concat(new(pairegalloc,alloc(R_ESI)));
  2914. {$endif noAllocEdi}
  2915. exprasmlist^.insert(new(paicpu,op_ref_reg(A_MOV,S_L,hr,R_ESI)));
  2916. end;
  2917. { should we save edi,esi,ebx like C ? }
  2918. if (po_savestdregs in aktprocsym^.definition^.procoptions) then
  2919. begin
  2920. if (aktprocsym^.definition^.usedregisters and ($80 shr byte(R_EBX)))<>0 then
  2921. exprasmlist^.insert(new(paicpu,op_reg(A_PUSH,S_L,R_EBX)));
  2922. exprasmlist^.insert(new(paicpu,op_reg(A_PUSH,S_L,R_ESI)));
  2923. exprasmlist^.insert(new(paicpu,op_reg(A_PUSH,S_L,R_EDI)));
  2924. end;
  2925. { for the save all registers we can simply use a pusha,popa which
  2926. push edi,esi,ebp,esp(ignored),ebx,edx,ecx,eax }
  2927. if (po_saveregisters in aktprocsym^.definition^.procoptions) then
  2928. begin
  2929. exprasmlist^.insert(new(paicpu,op_none(A_PUSHA,S_L)));
  2930. end;
  2931. { omit stack frame ? }
  2932. if not inlined then
  2933. if procinfo^.framepointer=stack_pointer then
  2934. begin
  2935. CGMessage(cg_d_stackframe_omited);
  2936. nostackframe:=true;
  2937. if (aktprocsym^.definition^.proctypeoption in [potype_unitinit,potype_proginit,potype_unitfinalize]) then
  2938. parasize:=0
  2939. else
  2940. parasize:=aktprocsym^.definition^.parast^.datasize+procinfo^.para_offset-4;
  2941. if stackframe<>0 then
  2942. exprasmlist^.insert(new(paicpu,
  2943. op_const_reg(A_SUB,S_L,gettempsize,R_ESP)));
  2944. end
  2945. else
  2946. begin
  2947. alignstack(alist);
  2948. if (aktprocsym^.definition^.proctypeoption in [potype_unitinit,potype_proginit,potype_unitfinalize]) then
  2949. parasize:=0
  2950. else
  2951. parasize:=aktprocsym^.definition^.parast^.datasize+procinfo^.para_offset-8;
  2952. nostackframe:=false;
  2953. if stackframe<>0 then
  2954. begin
  2955. {$ifdef unused}
  2956. if (cs_littlesize in aktglobalswitches) and (stackframe<=65535) then
  2957. begin
  2958. if (cs_check_stack in aktlocalswitches) and
  2959. not(target_info.target in [target_i386_linux,target_i386_win32]) then
  2960. begin
  2961. emitinsertcall('FPC_STACKCHECK');
  2962. exprasmlist^.insert(new(paicpu,op_const(A_PUSH,S_L,stackframe)));
  2963. end;
  2964. if cs_profile in aktmoduleswitches then
  2965. genprofilecode;
  2966. { %edi is already saved when pocdecl is used
  2967. if (target_info.target=target_linux) and
  2968. ((aktprocsym^.definition^.options and poexports)<>0) then
  2969. exprasmlist^.insert(new(Paicpu,op_reg(A_PUSH,S_L,R_EDI))); }
  2970. exprasmlist^.insert(new(paicpu,op_const_const(A_ENTER,S_NO,stackframe,0)))
  2971. end
  2972. else
  2973. {$endif unused}
  2974. begin
  2975. { windows guards only a few pages for stack growing, }
  2976. { so we have to access every page first }
  2977. if (target_os.id=os_i386_win32) and
  2978. (stackframe>=winstackpagesize) then
  2979. begin
  2980. if stackframe div winstackpagesize<=5 then
  2981. begin
  2982. exprasmlist^.insert(new(paicpu,op_const_reg(A_SUB,S_L,stackframe-4,R_ESP)));
  2983. for i:=1 to stackframe div winstackpagesize do
  2984. begin
  2985. hr:=new_reference(R_ESP,stackframe-i*winstackpagesize);
  2986. exprasmlist^.concat(new(paicpu,
  2987. op_const_ref(A_MOV,S_L,0,hr)));
  2988. end;
  2989. exprasmlist^.concat(new(paicpu,
  2990. op_reg(A_PUSH,S_L,R_EAX)));
  2991. end
  2992. else
  2993. begin
  2994. getlabel(again);
  2995. {$ifndef noAllocEdi}
  2996. getexplicitregister32(R_EDI);
  2997. {$endif noAllocEdi}
  2998. exprasmlist^.concat(new(paicpu,
  2999. op_const_reg(A_MOV,S_L,stackframe div winstackpagesize,R_EDI)));
  3000. emitlab(again);
  3001. exprasmlist^.concat(new(paicpu,
  3002. op_const_reg(A_SUB,S_L,winstackpagesize-4,R_ESP)));
  3003. exprasmlist^.concat(new(paicpu,
  3004. op_reg(A_PUSH,S_L,R_EAX)));
  3005. exprasmlist^.concat(new(paicpu,
  3006. op_reg(A_DEC,S_L,R_EDI)));
  3007. emitjmp(C_NZ,again);
  3008. {$ifndef noAllocEdi}
  3009. ungetregister32(R_EDI);
  3010. {$endif noAllocEdi}
  3011. exprasmlist^.concat(new(paicpu,
  3012. op_const_reg(A_SUB,S_L,stackframe mod winstackpagesize,R_ESP)));
  3013. end
  3014. end
  3015. else
  3016. exprasmlist^.insert(new(paicpu,op_const_reg(A_SUB,S_L,stackframe,R_ESP)));
  3017. if (cs_check_stack in aktlocalswitches) and
  3018. not(target_info.target in [target_i386_linux,target_i386_win32]) then
  3019. begin
  3020. emitinsertcall('FPC_STACKCHECK');
  3021. exprasmlist^.insert(new(paicpu,op_const(A_PUSH,S_L,stackframe)));
  3022. end;
  3023. if cs_profile in aktmoduleswitches then
  3024. genprofilecode;
  3025. exprasmlist^.insert(new(paicpu,op_reg_reg(A_MOV,S_L,R_ESP,R_EBP)));
  3026. exprasmlist^.insert(new(paicpu,op_reg(A_PUSH,S_L,R_EBP)));
  3027. end;
  3028. end { endif stackframe <> 0 }
  3029. else
  3030. begin
  3031. if cs_profile in aktmoduleswitches then
  3032. genprofilecode;
  3033. exprasmlist^.insert(new(paicpu,op_reg_reg(A_MOV,S_L,R_ESP,R_EBP)));
  3034. exprasmlist^.insert(new(paicpu,op_reg(A_PUSH,S_L,R_EBP)));
  3035. end;
  3036. end;
  3037. if (po_interrupt in aktprocsym^.definition^.procoptions) then
  3038. generate_interrupt_stackframe_entry;
  3039. { initialize return value }
  3040. if (procinfo^.returntype.def<>pdef(voiddef)) and
  3041. (procinfo^.returntype.def^.needs_inittable) and
  3042. ((procinfo^.returntype.def^.deftype<>objectdef) or
  3043. not(pobjectdef(procinfo^.returntype.def)^.is_class)) then
  3044. begin
  3045. procinfo^.flags:=procinfo^.flags or pi_needs_implicit_finally;
  3046. reset_reference(r);
  3047. r.offset:=procinfo^.return_offset;
  3048. r.base:=procinfo^.framepointer;
  3049. initialize(procinfo^.returntype.def,r,ret_in_param(procinfo^.returntype.def));
  3050. end;
  3051. { generate copies of call by value parameters }
  3052. if not(po_assembler in aktprocsym^.definition^.procoptions) then
  3053. aktprocsym^.definition^.parast^.foreach({$ifndef TP}@{$endif}copyvalueparas);
  3054. { initialisizes local data }
  3055. aktprocsym^.definition^.localst^.foreach({$ifndef TP}@{$endif}initialize_data);
  3056. { add a reference to all call by value/const parameters }
  3057. aktprocsym^.definition^.parast^.foreach({$ifndef TP}@{$endif}incr_data);
  3058. { initilisizes temp. ansi/wide string data }
  3059. inittempansistrings;
  3060. { do we need an exception frame because of ansi/widestrings ? }
  3061. if (procinfo^.flags and pi_needs_implicit_finally)<>0 then
  3062. begin
  3063. usedinproc:=usedinproc or ($80 shr byte(R_EAX));
  3064. { Type of stack-frame must be pushed}
  3065. exprasmlist^.concat(new(paicpu,op_const(A_PUSH,S_L,1)));
  3066. emitcall('FPC_PUSHEXCEPTADDR');
  3067. exprasmlist^.concat(new(paicpu,
  3068. op_reg(A_PUSH,S_L,R_EAX)));
  3069. emitcall('FPC_SETJMP');
  3070. exprasmlist^.concat(new(paicpu,
  3071. op_reg(A_PUSH,S_L,R_EAX)));
  3072. exprasmlist^.concat(new(paicpu,
  3073. op_reg_reg(A_TEST,S_L,R_EAX,R_EAX)));
  3074. emitjmp(C_NE,aktexitlabel);
  3075. { probably we've to reload self here }
  3076. maybe_loadesi;
  3077. end;
  3078. if not inlined then
  3079. begin
  3080. if (cs_profile in aktmoduleswitches) or
  3081. (aktprocsym^.definition^.owner^.symtabletype=globalsymtable) or
  3082. (assigned(procinfo^._class) and (procinfo^._class^.owner^.symtabletype=globalsymtable)) then
  3083. make_global:=true;
  3084. hs:=proc_names.get;
  3085. {$ifdef GDB}
  3086. if (cs_debuginfo in aktmoduleswitches) and target_os.use_function_relative_addresses then
  3087. stab_function_name := new(pai_stab_function_name,init(strpnew(hs)));
  3088. {$EndIf GDB}
  3089. while hs<>'' do
  3090. begin
  3091. if make_global then
  3092. exprasmlist^.insert(new(pai_symbol,initname_global(hs,0)))
  3093. else
  3094. exprasmlist^.insert(new(pai_symbol,initname(hs,0)));
  3095. {$ifdef GDB}
  3096. if (cs_debuginfo in aktmoduleswitches) and
  3097. target_os.use_function_relative_addresses then
  3098. exprasmlist^.insert(new(pai_stab_function_name,init(strpnew(hs))));
  3099. {$endif GDB}
  3100. hs:=proc_names.get;
  3101. end;
  3102. if make_global or ((procinfo^.flags and pi_is_global) <> 0) then
  3103. aktprocsym^.is_global := True;
  3104. {$ifdef GDB}
  3105. if (cs_debuginfo in aktmoduleswitches) then
  3106. begin
  3107. if target_os.use_function_relative_addresses then
  3108. exprasmlist^.insert(stab_function_name);
  3109. exprasmlist^.insert(new(pai_stabs,init(aktprocsym^.stabstring)));
  3110. aktprocsym^.isstabwritten:=true;
  3111. end;
  3112. {$endif GDB}
  3113. { Align, gprof uses 16 byte granularity }
  3114. if (cs_profile in aktmoduleswitches) then
  3115. exprasmlist^.insert(new(pai_align,init_op(16,$90)))
  3116. else
  3117. if not(cs_littlesize in aktglobalswitches) then
  3118. exprasmlist^.insert(new(pai_align,init(16)));
  3119. end;
  3120. exprasmlist:=oldexprasmlist;
  3121. end;
  3122. procedure handle_return_value(inlined : boolean);
  3123. var
  3124. hr : preference;
  3125. op : Tasmop;
  3126. s : Topsize;
  3127. begin
  3128. if procinfo^.returntype.def<>pdef(voiddef) then
  3129. begin
  3130. {if ((procinfo^.flags and pi_operator)<>0) and
  3131. assigned(opsym) then
  3132. procinfo^.funcret_is_valid:=
  3133. procinfo^.funcret_is_valid or (opsym^.refs>0);}
  3134. if (procinfo^.funcret_state<>vs_assigned) and not inlined { and
  3135. ((procinfo^.flags and pi_uses_asm)=0)} then
  3136. CGMessage(sym_w_function_result_not_set);
  3137. hr:=new_reference(procinfo^.framepointer,procinfo^.return_offset);
  3138. if (procinfo^.returntype.def^.deftype in [orddef,enumdef]) then
  3139. begin
  3140. case procinfo^.returntype.def^.size of
  3141. 8:
  3142. begin
  3143. emit_ref_reg(A_MOV,S_L,hr,R_EAX);
  3144. hr:=new_reference(procinfo^.framepointer,procinfo^.return_offset+4);
  3145. emit_ref_reg(A_MOV,S_L,hr,R_EDX);
  3146. end;
  3147. 4:
  3148. emit_ref_reg(A_MOV,S_L,hr,R_EAX);
  3149. 2:
  3150. emit_ref_reg(A_MOV,S_W,hr,R_AX);
  3151. 1:
  3152. emit_ref_reg(A_MOV,S_B,hr,R_AL);
  3153. end;
  3154. end
  3155. else
  3156. if ret_in_acc(procinfo^.returntype.def) then
  3157. emit_ref_reg(A_MOV,S_L,hr,R_EAX)
  3158. else
  3159. if (procinfo^.returntype.def^.deftype=floatdef) then
  3160. begin
  3161. floatloadops(pfloatdef(procinfo^.returntype.def)^.typ,op,s);
  3162. exprasmlist^.concat(new(paicpu,op_ref(op,s,hr)))
  3163. end
  3164. else
  3165. dispose(hr);
  3166. end
  3167. end;
  3168. procedure genexitcode(alist : paasmoutput;parasize:longint;nostackframe,inlined:boolean);
  3169. var
  3170. {$ifdef GDB}
  3171. mangled_length : longint;
  3172. p : pchar;
  3173. {$endif GDB}
  3174. nofinal,okexitlabel,noreraiselabel,nodestroycall : pasmlabel;
  3175. hr : treference;
  3176. oldexprasmlist : paasmoutput;
  3177. ai : paicpu;
  3178. pd : pprocdef;
  3179. begin
  3180. oldexprasmlist:=exprasmlist;
  3181. exprasmlist:=alist;
  3182. if aktexitlabel^.is_used then
  3183. exprasmlist^.insert(new(pai_label,init(aktexitlabel)));
  3184. { call the destructor help procedure }
  3185. if (aktprocsym^.definition^.proctypeoption=potype_destructor) and
  3186. assigned(procinfo^._class) then
  3187. begin
  3188. if procinfo^._class^.is_class then
  3189. begin
  3190. emitinsertcall('FPC_DISPOSE_CLASS');
  3191. end
  3192. else
  3193. begin
  3194. emitinsertcall('FPC_HELP_DESTRUCTOR');
  3195. {$ifndef noAllocEdi}
  3196. getexplicitregister32(R_EDI);
  3197. {$endif noAllocEdi}
  3198. exprasmlist^.insert(new(paicpu,op_const_reg(A_MOV,S_L,procinfo^._class^.vmt_offset,R_EDI)));
  3199. { must the object be finalized ? }
  3200. if procinfo^._class^.needs_inittable then
  3201. begin
  3202. getlabel(nofinal);
  3203. exprasmlist^.insert(new(pai_label,init(nofinal)));
  3204. emitinsertcall('FPC_FINALIZE');
  3205. {$ifndef noAllocEdi}
  3206. ungetregister32(R_EDI);
  3207. {$endif noAllocEdi}
  3208. exprasmlist^.insert(new(paicpu,op_reg(A_PUSH,S_L,R_ESI)));
  3209. exprasmlist^.insert(new(paicpu,op_sym(A_PUSH,S_L,procinfo^._class^.get_inittable_label)));
  3210. ai:=new(paicpu,op_sym(A_Jcc,S_NO,nofinal));
  3211. ai^.SetCondition(C_Z);
  3212. exprasmlist^.insert(ai);
  3213. reset_reference(hr);
  3214. hr.base:=R_EBP;
  3215. hr.offset:=8;
  3216. exprasmlist^.insert(new(paicpu,op_const_ref(A_CMP,S_L,0,newreference(hr))));
  3217. end;
  3218. end;
  3219. end;
  3220. { finalize temporary data }
  3221. finalizetempansistrings;
  3222. { finalize local data }
  3223. aktprocsym^.definition^.localst^.foreach({$ifndef TP}@{$endif}finalize_data);
  3224. { finalize paras data }
  3225. if assigned(aktprocsym^.definition^.parast) then
  3226. aktprocsym^.definition^.parast^.foreach({$ifndef TP}@{$endif}finalize_data);
  3227. { do we need to handle exceptions because of ansi/widestrings ? }
  3228. if (procinfo^.flags and pi_needs_implicit_finally)<>0 then
  3229. begin
  3230. { the exception helper routines modify all registers }
  3231. aktprocsym^.definition^.usedregisters:=$ff;
  3232. getlabel(noreraiselabel);
  3233. emitcall('FPC_POPADDRSTACK');
  3234. exprasmlist^.concat(new(paicpu,
  3235. op_reg(A_POP,S_L,R_EAX)));
  3236. exprasmlist^.concat(new(paicpu,
  3237. op_reg_reg(A_TEST,S_L,R_EAX,R_EAX)));
  3238. emitjmp(C_E,noreraiselabel);
  3239. if (aktprocsym^.definition^.proctypeoption=potype_constructor) then
  3240. begin
  3241. if assigned(procinfo^._class) then
  3242. begin
  3243. pd:=procinfo^._class^.searchdestructor;
  3244. if assigned(pd) then
  3245. begin
  3246. getlabel(nodestroycall);
  3247. emit_const_ref(A_CMP,S_L,0,new_reference(procinfo^.framepointer,
  3248. procinfo^.selfpointer_offset));
  3249. emitjmp(C_E,nodestroycall);
  3250. if procinfo^._class^.is_class then
  3251. begin
  3252. emit_const(A_PUSH,S_L,1);
  3253. emit_reg(A_PUSH,S_L,R_ESI);
  3254. end
  3255. else
  3256. begin
  3257. emit_reg(A_PUSH,S_L,R_ESI);
  3258. emit_sym(A_PUSH,S_L,newasmsymbol(procinfo^._class^.vmt_mangledname));
  3259. end;
  3260. if (po_virtualmethod in pd^.procoptions) then
  3261. begin
  3262. emit_ref_reg(A_MOV,S_L,new_reference(R_ESI,0),R_EDI);
  3263. emit_ref(A_CALL,S_NO,new_reference(R_EDI,procinfo^._class^.vmtmethodoffset(pd^.extnumber)));
  3264. end
  3265. else
  3266. emitcall(pd^.mangledname);
  3267. { not necessary because the result is never assigned in the
  3268. case of an exception (FK)
  3269. emit_const_reg(A_MOV,S_L,0,R_ESI);
  3270. emit_const_ref(A_MOV,S_L,0,new_reference(procinfo^.framepointer,8));
  3271. }
  3272. emitlab(nodestroycall);
  3273. end;
  3274. end
  3275. end
  3276. else
  3277. { must be the return value finalized before reraising the exception? }
  3278. if (procinfo^.returntype.def<>pdef(voiddef)) and
  3279. (procinfo^.returntype.def^.needs_inittable) and
  3280. ((procinfo^.returntype.def^.deftype<>objectdef) or
  3281. not(pobjectdef(procinfo^.returntype.def)^.is_class)) then
  3282. begin
  3283. reset_reference(hr);
  3284. hr.offset:=procinfo^.return_offset;
  3285. hr.base:=procinfo^.framepointer;
  3286. finalize(procinfo^.returntype.def,hr,ret_in_param(procinfo^.returntype.def));
  3287. end;
  3288. emitcall('FPC_RERAISE');
  3289. emitlab(noreraiselabel);
  3290. end;
  3291. { call __EXIT for main program }
  3292. if (not DLLsource) and (not inlined) and (aktprocsym^.definition^.proctypeoption=potype_proginit) then
  3293. begin
  3294. emitcall('FPC_DO_EXIT');
  3295. end;
  3296. { handle return value }
  3297. if not(po_assembler in aktprocsym^.definition^.procoptions) then
  3298. if (aktprocsym^.definition^.proctypeoption<>potype_constructor) then
  3299. handle_return_value(inlined)
  3300. else
  3301. begin
  3302. { successful constructor deletes the zero flag }
  3303. { and returns self in eax }
  3304. { eax must be set to zero if the allocation failed !!! }
  3305. getlabel(okexitlabel);
  3306. emitjmp(C_NONE,okexitlabel);
  3307. emitlab(faillabel);
  3308. if procinfo^._class^.is_class then
  3309. begin
  3310. emit_ref_reg(A_MOV,S_L,new_reference(procinfo^.framepointer,8),R_ESI);
  3311. emitcall('FPC_HELP_FAIL_CLASS');
  3312. end
  3313. else
  3314. begin
  3315. emit_ref_reg(A_MOV,S_L,new_reference(procinfo^.framepointer,12),R_ESI);
  3316. {$ifndef noAllocEdi}
  3317. getexplicitregister32(R_EDI);
  3318. {$endif noAllocEdi}
  3319. emit_const_reg(A_MOV,S_L,procinfo^._class^.vmt_offset,R_EDI);
  3320. emitcall('FPC_HELP_FAIL');
  3321. {$ifndef noAllocEdi}
  3322. ungetregister32(R_EDI);
  3323. {$endif noAllocEdi}
  3324. end;
  3325. emitlab(okexitlabel);
  3326. emit_reg_reg(A_MOV,S_L,R_ESI,R_EAX);
  3327. emit_reg_reg(A_TEST,S_L,R_ESI,R_ESI);
  3328. end;
  3329. { stabs uses the label also ! }
  3330. if aktexit2label^.is_used or
  3331. ((cs_debuginfo in aktmoduleswitches) and not inlined) then
  3332. emitlab(aktexit2label);
  3333. { gives problems for long mangled names }
  3334. {list^.concat(new(pai_symbol,init(aktprocsym^.definition^.mangledname+'_end')));}
  3335. { should we restore edi ? }
  3336. { for all i386 gcc implementations }
  3337. if (po_savestdregs in aktprocsym^.definition^.procoptions) then
  3338. begin
  3339. if (aktprocsym^.definition^.usedregisters and ($80 shr byte(R_EBX)))<>0 then
  3340. exprasmlist^.concat(new(paicpu,op_reg(A_POP,S_L,R_EBX)));
  3341. exprasmlist^.concat(new(paicpu,op_reg(A_POP,S_L,R_ESI)));
  3342. exprasmlist^.concat(new(paicpu,op_reg(A_POP,S_L,R_EDI)));
  3343. { here we could reset R_EBX
  3344. but that is risky because it only works
  3345. if genexitcode is called after genentrycode
  3346. so lets skip this for the moment PM
  3347. aktprocsym^.definition^.usedregisters:=
  3348. aktprocsym^.definition^.usedregisters or not ($80 shr byte(R_EBX));
  3349. }
  3350. end;
  3351. { for the save all registers we can simply use a pusha,popa which
  3352. push edi,esi,ebp,esp(ignored),ebx,edx,ecx,eax }
  3353. if (po_saveregisters in aktprocsym^.definition^.procoptions) then
  3354. begin
  3355. exprasmlist^.concat(new(paicpu,op_none(A_POPA,S_L)));
  3356. end;
  3357. if not(nostackframe) then
  3358. begin
  3359. if not inlined then
  3360. exprasmlist^.concat(new(paicpu,op_none(A_LEAVE,S_NO)));
  3361. end
  3362. else
  3363. begin
  3364. if (gettempsize<>0) and not inlined then
  3365. exprasmlist^.insert(new(paicpu,
  3366. op_const_reg(A_ADD,S_L,gettempsize,R_ESP)));
  3367. end;
  3368. { parameters are limited to 65535 bytes because }
  3369. { ret allows only imm16 }
  3370. if (parasize>65535) and not(pocall_clearstack in aktprocsym^.definition^.proccalloptions) then
  3371. CGMessage(cg_e_parasize_too_big);
  3372. { at last, the return is generated }
  3373. if not inlined then
  3374. if (po_interrupt in aktprocsym^.definition^.procoptions) then
  3375. generate_interrupt_stackframe_exit
  3376. else
  3377. begin
  3378. {Routines with the poclearstack flag set use only a ret.}
  3379. { also routines with parasize=0 }
  3380. if (pocall_clearstack in aktprocsym^.definition^.proccalloptions) then
  3381. begin
  3382. {$ifndef OLD_C_STACK}
  3383. { complex return values are removed from stack in C code PM }
  3384. if ret_in_param(aktprocsym^.definition^.rettype.def) then
  3385. exprasmlist^.concat(new(paicpu,op_const(A_RET,S_NO,4)))
  3386. else
  3387. {$endif not OLD_C_STACK}
  3388. exprasmlist^.concat(new(paicpu,op_none(A_RET,S_NO)));
  3389. end
  3390. else if (parasize=0) then
  3391. exprasmlist^.concat(new(paicpu,op_none(A_RET,S_NO)))
  3392. else
  3393. exprasmlist^.concat(new(paicpu,op_const(A_RET,S_NO,parasize)));
  3394. end;
  3395. if not inlined then
  3396. exprasmlist^.concat(new(pai_symbol_end,initname(aktprocsym^.definition^.mangledname)));
  3397. {$ifdef GDB}
  3398. if (cs_debuginfo in aktmoduleswitches) and not inlined then
  3399. begin
  3400. aktprocsym^.concatstabto(exprasmlist);
  3401. if assigned(procinfo^._class) then
  3402. if (not assigned(procinfo^.parent) or
  3403. not assigned(procinfo^.parent^._class)) then
  3404. exprasmlist^.concat(new(pai_stabs,init(strpnew(
  3405. '"$t:v'+procinfo^._class^.numberstring+'",'+
  3406. tostr(N_PSYM)+',0,0,'+tostr(procinfo^.selfpointer_offset)))))
  3407. else
  3408. exprasmlist^.concat(new(pai_stabs,init(strpnew(
  3409. '"$t:r*'+procinfo^._class^.numberstring+'",'+
  3410. tostr(N_RSYM)+',0,0,'+tostr(GDB_i386index[R_ESI])))));
  3411. { define calling EBP as pseudo local var PM }
  3412. { this enables test if the function is a local one !! }
  3413. if assigned(procinfo^.parent) and (lexlevel>normal_function_level) then
  3414. exprasmlist^.concat(new(pai_stabs,init(strpnew(
  3415. '"parent_ebp:'+voidpointerdef^.numberstring+'",'+
  3416. tostr(N_LSYM)+',0,0,'+tostr(procinfo^.framepointer_offset)))));
  3417. if (pdef(aktprocsym^.definition^.rettype.def) <> pdef(voiddef)) then
  3418. begin
  3419. if ret_in_param(aktprocsym^.definition^.rettype.def) then
  3420. exprasmlist^.concat(new(pai_stabs,init(strpnew(
  3421. '"'+aktprocsym^.name+':X*'+aktprocsym^.definition^.rettype.def^.numberstring+'",'+
  3422. tostr(N_PSYM)+',0,0,'+tostr(procinfo^.return_offset)))))
  3423. else
  3424. exprasmlist^.concat(new(pai_stabs,init(strpnew(
  3425. '"'+aktprocsym^.name+':X'+aktprocsym^.definition^.rettype.def^.numberstring+'",'+
  3426. tostr(N_PSYM)+',0,0,'+tostr(procinfo^.return_offset)))));
  3427. if (m_result in aktmodeswitches) then
  3428. if ret_in_param(aktprocsym^.definition^.rettype.def) then
  3429. exprasmlist^.concat(new(pai_stabs,init(strpnew(
  3430. '"RESULT:X*'+aktprocsym^.definition^.rettype.def^.numberstring+'",'+
  3431. tostr(N_PSYM)+',0,0,'+tostr(procinfo^.return_offset)))))
  3432. else
  3433. exprasmlist^.concat(new(pai_stabs,init(strpnew(
  3434. '"RESULT:X'+aktprocsym^.definition^.rettype.def^.numberstring+'",'+
  3435. tostr(N_PSYM)+',0,0,'+tostr(procinfo^.return_offset)))));
  3436. end;
  3437. mangled_length:=length(aktprocsym^.definition^.mangledname);
  3438. getmem(p,2*mangled_length+50);
  3439. strpcopy(p,'192,0,0,');
  3440. strpcopy(strend(p),aktprocsym^.definition^.mangledname);
  3441. if (target_os.use_function_relative_addresses) then
  3442. begin
  3443. strpcopy(strend(p),'-');
  3444. strpcopy(strend(p),aktprocsym^.definition^.mangledname);
  3445. end;
  3446. exprasmlist^.concat(new(pai_stabn,init(strnew(p))));
  3447. {list^.concat(new(pai_stabn,init(strpnew('192,0,0,'
  3448. +aktprocsym^.definition^.mangledname))));
  3449. p[0]:='2';p[1]:='2';p[2]:='4';
  3450. strpcopy(strend(p),'_end');}
  3451. strpcopy(p,'224,0,0,'+aktexit2label^.name);
  3452. if (target_os.use_function_relative_addresses) then
  3453. begin
  3454. strpcopy(strend(p),'-');
  3455. strpcopy(strend(p),aktprocsym^.definition^.mangledname);
  3456. end;
  3457. exprasmlist^.concatlist(withdebuglist);
  3458. exprasmlist^.concat(new(pai_stabn,init(
  3459. strnew(p))));
  3460. { strpnew('224,0,0,'
  3461. +aktprocsym^.definition^.mangledname+'_end'))));}
  3462. freemem(p,2*mangled_length+50);
  3463. end;
  3464. {$endif GDB}
  3465. exprasmlist:=oldexprasmlist;
  3466. end;
  3467. {$ifdef test_dest_loc}
  3468. procedure mov_reg_to_dest(p : ptree; s : topsize; reg : tregister);
  3469. begin
  3470. if (dest_loc.loc=LOC_CREGISTER) or (dest_loc.loc=LOC_REGISTER) then
  3471. begin
  3472. emit_reg_reg(A_MOV,s,reg,dest_loc.register);
  3473. set_location(p^.location,dest_loc);
  3474. in_dest_loc:=true;
  3475. end
  3476. else
  3477. if (dest_loc.loc=LOC_REFERENCE) or (dest_loc.loc=LOC_MEM) then
  3478. begin
  3479. exprasmlist^.concat(new(paicpu,op_reg_ref(A_MOV,s,reg,newreference(dest_loc.reference))));
  3480. set_location(p^.location,dest_loc);
  3481. in_dest_loc:=true;
  3482. end
  3483. else
  3484. internalerror(20080);
  3485. end;
  3486. {$endif test_dest_loc}
  3487. end.
  3488. {
  3489. $Log$
  3490. Revision 1.83 2000-02-18 21:25:48 florian
  3491. * fixed a bug in int64/qword handling was a quite ugly one
  3492. Revision 1.82 2000/02/18 20:53:14 pierre
  3493. * fixes a stabs problem for functions
  3494. + includes a stabs local var for with statements
  3495. the name is with in lowercase followed by an index
  3496. for nested with.
  3497. + Withdebuglist added because the stabs declarations of local
  3498. var are postponed to end of function.
  3499. Revision 1.81 2000/02/10 23:44:43 florian
  3500. * big update for exception handling code generation: possible mem holes
  3501. fixed, break/continue/exit should work always now as expected
  3502. Revision 1.80 2000/02/09 17:36:10 jonas
  3503. * added missing regalloc for ecx in range check code
  3504. Revision 1.79 2000/02/09 13:22:50 peter
  3505. * log truncated
  3506. Revision 1.78 2000/02/04 21:00:31 florian
  3507. * some (small) problems with register saving fixed
  3508. Revision 1.77 2000/02/04 20:00:21 florian
  3509. * an exception in a construcor calls now the destructor (this applies only
  3510. to classes)
  3511. Revision 1.76 2000/02/04 14:29:57 pierre
  3512. + add pseudo local var parent_ebp for local procs
  3513. Revision 1.75 2000/01/25 08:46:03 pierre
  3514. * Range check for int64 produces a warning only
  3515. Revision 1.74 2000/01/24 12:17:22 florian
  3516. * some improvemenst to cmov support
  3517. * disabled excpetion frame generation in cosntructors temporarily
  3518. Revision 1.73 2000/01/23 21:29:14 florian
  3519. * CMOV support in optimizer (in define USECMOV)
  3520. + start of support of exceptions in constructors
  3521. Revision 1.72 2000/01/23 11:11:36 michael
  3522. + Fixes from Jonas.
  3523. Revision 1.71 2000/01/22 16:02:37 jonas
  3524. * fixed more regalloc bugs (for set adding and unsigned
  3525. multiplication)
  3526. Revision 1.70 2000/01/16 22:17:11 peter
  3527. * renamed call_offset to para_offset
  3528. Revision 1.69 2000/01/12 10:38:17 peter
  3529. * smartlinking fixes for binary writer
  3530. * release alignreg code and moved instruction writing align to cpuasm,
  3531. but it doesn't use the specified register yet
  3532. Revision 1.68 2000/01/09 12:35:02 jonas
  3533. * changed edi allocation to use getexplicitregister32/ungetregister
  3534. (adapted tgeni386 a bit for this) and enabled it by default
  3535. * fixed very big and stupid bug of mine in cg386mat that broke the
  3536. include() code (and make cycle :( ) if you compiled without
  3537. -dnewoptimizations
  3538. Revision 1.67 2000/01/09 01:44:21 jonas
  3539. + (de)allocation info for EDI to fix reported bug on mailinglist.
  3540. Also some (de)allocation info for ESI added. Between -dallocEDI
  3541. because at this time of the night bugs could easily slip in ;)
  3542. Revision 1.66 2000/01/07 01:14:22 peter
  3543. * updated copyright to 2000
  3544. Revision 1.65 1999/12/22 01:01:47 peter
  3545. - removed freelabel()
  3546. * added undefined label detection in internal assembler, this prevents
  3547. a lot of ld crashes and wrong .o files
  3548. * .o files aren't written anymore if errors have occured
  3549. * inlining of assembler labels is now correct
  3550. Revision 1.64 1999/12/20 21:42:35 pierre
  3551. + dllversion global variable
  3552. * FPC_USE_CPREFIX code removed, not necessary anymore
  3553. as we use .edata direct writing by default now.
  3554. Revision 1.63 1999/12/01 22:45:54 peter
  3555. * fixed wrong assembler with in-node
  3556. Revision 1.62 1999/11/30 10:40:43 peter
  3557. + ttype, tsymlist
  3558. Revision 1.61 1999/11/20 01:22:18 pierre
  3559. + cond FPC_USE_CPREFIX (needs also some RTL changes)
  3560. this allows to use unit global vars as DLL exports
  3561. (the underline prefix seems needed by dlltool)
  3562. Revision 1.60 1999/11/17 17:04:58 pierre
  3563. * Notes/hints changes
  3564. Revision 1.59 1999/11/15 14:04:00 pierre
  3565. * self pointer stabs for local function was wrong
  3566. }