cgai386.pas 145 KB

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