cgai386.pas 158 KB

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