cgai386.pas 157 KB

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