cgai386.pas 116 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180
  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. }
  18. unit cgai386;
  19. {$i defines.inc}
  20. interface
  21. uses
  22. cpubase,cpuasm,
  23. symconst,symtype,symdef,aasm;
  24. {$define TESTGETTEMP to store const that
  25. are written into temps for later release PM }
  26. function def_opsize(p1:tdef):topsize;
  27. function def2def_opsize(p1,p2:tdef):topsize;
  28. function def_getreg(p1:tdef):tregister;
  29. function makereg8(r:tregister):tregister;
  30. function makereg16(r:tregister):tregister;
  31. function makereg32(r:tregister):tregister;
  32. procedure locflags2reg(var l:tlocation;opsize:topsize);
  33. procedure locjump2reg(var l:tlocation;opsize:topsize; otl, ofl: tasmlabel);
  34. procedure emitlab(var l : tasmlabel);
  35. procedure emitjmp(c : tasmcond;var l : tasmlabel);
  36. procedure emit_flag2reg(flag:tresflags;hregister:tregister);
  37. procedure emit_none(i : tasmop;s : topsize);
  38. procedure emit_const(i : tasmop;s : topsize;c : longint);
  39. procedure emit_reg(i : tasmop;s : topsize;reg : tregister);
  40. procedure emit_ref(i : tasmop;s : topsize;ref : preference);
  41. procedure emit_const_reg(i : tasmop;s : topsize;c : longint;reg : tregister);
  42. procedure emit_const_ref(i : tasmop;s : topsize;c : longint;ref : preference);
  43. procedure emit_ref_reg(i : tasmop;s : topsize;ref : preference;reg : tregister);
  44. procedure emit_reg_ref(i : tasmop;s : topsize;reg : tregister;ref : preference);
  45. procedure emit_reg_reg(i : tasmop;s : topsize;reg1,reg2 : tregister);
  46. procedure emit_const_reg_reg(i : tasmop;s : topsize;c : longint;reg1,reg2 : tregister);
  47. procedure emit_reg_reg_reg(i : tasmop;s : topsize;reg1,reg2,reg3 : tregister);
  48. procedure emit_sym(i : tasmop;s : topsize;op : tasmsymbol);
  49. procedure emit_sym_ofs(i : tasmop;s : topsize;op : tasmsymbol;ofs : longint);
  50. procedure emit_sym_ofs_reg(i : tasmop;s : topsize;op : tasmsymbol;ofs:longint;reg : tregister);
  51. procedure emit_sym_ofs_ref(i : tasmop;s : topsize;op : tasmsymbol;ofs:longint;ref : preference);
  52. procedure emitcall(const routine:string);
  53. procedure emit_mov_loc_ref(const t:tlocation;const ref:treference;siz:topsize;freetemp:boolean);
  54. procedure emit_mov_loc_reg(const t:tlocation;reg:tregister);
  55. procedure emit_mov_ref_reg64(r : treference;rl,rh : tregister);
  56. procedure emit_lea_loc_ref(const t:tlocation;const ref:treference;freetemp:boolean);
  57. procedure emit_lea_loc_reg(const t:tlocation;reg:tregister;freetemp:boolean);
  58. procedure emit_push_loc(const t:tlocation);
  59. procedure emit_push_mem_size(const t: treference; size: longint);
  60. { pushes qword location to the stack }
  61. procedure emit_pushq_loc(const t : tlocation);
  62. procedure release_qword_loc(const t : tlocation);
  63. { remove non regvar registers in loc from regs (in the format }
  64. { pushusedregisters uses) }
  65. procedure remove_non_regvars_from_loc(const t: tlocation; var regs: byte);
  66. { releases the registers of a location }
  67. procedure release_loc(const t : tlocation);
  68. procedure emit_pushw_loc(const t:tlocation);
  69. procedure emit_push_lea_loc(const t:tlocation;freetemp:boolean);
  70. procedure emit_to_mem(var t:tlocation;def:tdef);
  71. procedure emit_to_reg16(var hr:tregister);
  72. procedure emit_to_reg32(var hr:tregister);
  73. procedure emit_mov_reg_loc(reg: TRegister; const t:tlocation);
  74. procedure emit_movq_reg_loc(reghigh,reglow: TRegister;t:tlocation);
  75. procedure copyshortstring(const dref,sref : treference;len : byte;
  76. loadref, del_sref: boolean);
  77. procedure finalize(t : tdef;const ref : treference;is_already_ref : boolean);
  78. procedure incrstringref(t : tdef;const ref : treference);
  79. procedure decrstringref(t : tdef;const ref : treference);
  80. procedure push_int(l : longint);
  81. procedure emit_push_mem(const ref : treference);
  82. procedure emitpushreferenceaddr(const ref : treference);
  83. procedure incrcomintfref(t: tdef; const ref: treference);
  84. procedure decrcomintfref(t: tdef; const ref: treference);
  85. procedure floatload(t : tfloattype;const ref : treference);
  86. procedure floatstore(t : tfloattype;const ref : treference);
  87. procedure floatloadops(t : tfloattype;var op : tasmop;var s : topsize);
  88. procedure floatstoreops(t : tfloattype;var op : tasmop;var s : topsize);
  89. procedure maybe_loadself;
  90. procedure emitloadord2reg(const location:Tlocation;orddef:torddef;destreg:Tregister;delloc:boolean);
  91. procedure concatcopy(source,dest : treference;size : longint;delsource : boolean;loadref:boolean);
  92. procedure genentrycode(alist : TAAsmoutput;make_global:boolean;
  93. stackframe:longint;
  94. var parasize:longint;var nostackframe:boolean;
  95. inlined : boolean);
  96. procedure genexitcode(alist : TAAsmoutput;parasize:longint;
  97. nostackframe,inlined:boolean);
  98. { if a unit doesn't have a explicit init/final code, }
  99. { we've to generate one, if the units has ansistrings }
  100. { in the interface or implementation }
  101. procedure genimplicitunitfinal(alist : TAAsmoutput);
  102. procedure genimplicitunitinit(alist : TAAsmoutput);
  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. {$ifdef delphi}
  116. sysutils,
  117. {$else}
  118. strings,
  119. {$endif}
  120. cutils,cclasses,
  121. globtype,systems,globals,verbose,
  122. fmodule,
  123. symbase,symsym,symtable,types,
  124. tgcpu,temp_gen,hcodegen,regvars
  125. {$ifdef GDB}
  126. ,gdb
  127. {$endif}
  128. ;
  129. {$ifndef NOTARGETWIN32}
  130. const
  131. winstackpagesize = 4096;
  132. {$endif}
  133. {*****************************************************************************
  134. Helpers
  135. *****************************************************************************}
  136. function def_opsize(p1:tdef):topsize;
  137. begin
  138. case p1.size of
  139. 1 : def_opsize:=S_B;
  140. 2 : def_opsize:=S_W;
  141. 4 : def_opsize:=S_L;
  142. else
  143. internalerror(130820001);
  144. end;
  145. end;
  146. function def2def_opsize(p1,p2:tdef):topsize;
  147. var
  148. o1 : topsize;
  149. begin
  150. case p1.size of
  151. 1 : o1:=S_B;
  152. 2 : o1:=S_W;
  153. 4 : o1:=S_L;
  154. { I don't know if we need it (FK) }
  155. 8 : o1:=S_L;
  156. else
  157. internalerror(130820002);
  158. end;
  159. if assigned(p2) then
  160. begin
  161. case p2.size of
  162. 1 : o1:=S_B;
  163. 2 : begin
  164. if o1=S_B then
  165. o1:=S_BW
  166. else
  167. o1:=S_W;
  168. end;
  169. 4,8:
  170. begin
  171. case o1 of
  172. S_B : o1:=S_BL;
  173. S_W : o1:=S_WL;
  174. end;
  175. end;
  176. end;
  177. end;
  178. def2def_opsize:=o1;
  179. end;
  180. function def_getreg(p1:tdef):tregister;
  181. begin
  182. case p1.size of
  183. 1 : def_getreg:=reg32toreg8(getregister32);
  184. 2 : def_getreg:=reg32toreg16(getregister32);
  185. 4 : def_getreg:=getregister32;
  186. else
  187. internalerror(130820003);
  188. end;
  189. end;
  190. function makereg8(r:tregister):tregister;
  191. begin
  192. case r of
  193. R_EAX,R_EBX,R_ECX,R_EDX,R_EDI,R_ESI,R_ESP :
  194. makereg8:=reg32toreg8(r);
  195. R_AX,R_BX,R_CX,R_DX,R_DI,R_SI,R_SP :
  196. makereg8:=reg16toreg8(r);
  197. R_AL,R_BL,R_CL,R_DL :
  198. makereg8:=r;
  199. end;
  200. end;
  201. function makereg16(r:tregister):tregister;
  202. begin
  203. case r of
  204. R_EAX,R_EBX,R_ECX,R_EDX,R_EDI,R_ESI,R_ESP :
  205. makereg16:=reg32toreg16(r);
  206. R_AX,R_BX,R_CX,R_DX,R_DI,R_SI,R_SP :
  207. makereg16:=r;
  208. R_AL,R_BL,R_CL,R_DL :
  209. makereg16:=reg8toreg16(r);
  210. end;
  211. end;
  212. function makereg32(r:tregister):tregister;
  213. begin
  214. case r of
  215. R_EAX,R_EBX,R_ECX,R_EDX,R_EDI,R_ESI,R_ESP :
  216. makereg32:=r;
  217. R_AX,R_BX,R_CX,R_DX,R_DI,R_SI,R_SP :
  218. makereg32:=reg16toreg32(r);
  219. R_AL,R_BL,R_CL,R_DL :
  220. makereg32:=reg8toreg32(r);
  221. end;
  222. end;
  223. procedure locflags2reg(var l:tlocation;opsize:topsize);
  224. var
  225. hregister : tregister;
  226. begin
  227. if (l.loc=LOC_FLAGS) then
  228. begin
  229. hregister:=getregister32;
  230. case opsize of
  231. S_W : hregister:=reg32toreg16(hregister);
  232. S_B : hregister:=reg32toreg8(hregister);
  233. end;
  234. emit_flag2reg(l.resflags,hregister);
  235. l.loc:=LOC_REGISTER;
  236. l.register:=hregister;
  237. end
  238. else internalerror(270720001);
  239. end;
  240. procedure locjump2reg(var l:tlocation;opsize:topsize; otl, ofl: tasmlabel);
  241. var
  242. hregister : tregister;
  243. hl : tasmlabel;
  244. begin
  245. if l.loc = LOC_JUMP then
  246. begin
  247. hregister:=getregister32;
  248. case opsize of
  249. S_W : hregister:=reg32toreg16(hregister);
  250. S_B : hregister:=reg32toreg8(hregister);
  251. end;
  252. l.loc:=LOC_REGISTER;
  253. l.register:=hregister;
  254. emitlab(truelabel);
  255. truelabel:=otl;
  256. emit_const_reg(A_MOV,opsize,1,hregister);
  257. getlabel(hl);
  258. emitjmp(C_None,hl);
  259. emitlab(falselabel);
  260. falselabel:=ofl;
  261. emit_reg_reg(A_XOR,S_L,makereg32(hregister),
  262. makereg32(hregister));
  263. emitlab(hl);
  264. end
  265. else internalerror(270720002);
  266. end;
  267. {*****************************************************************************
  268. Emit Assembler
  269. *****************************************************************************}
  270. procedure emitlab(var l : tasmlabel);
  271. begin
  272. if not l.is_set then
  273. exprasmList.concat(Tai_label.Create(l))
  274. else
  275. internalerror(7453984);
  276. end;
  277. procedure emitjmp(c : tasmcond;var l : tasmlabel);
  278. var
  279. ai : taicpu;
  280. begin
  281. if c=C_None then
  282. ai := Taicpu.Op_sym(A_JMP,S_NO,l)
  283. else
  284. begin
  285. ai:=Taicpu.Op_sym(A_Jcc,S_NO,l);
  286. ai.SetCondition(c);
  287. end;
  288. ai.is_jmp:=true;
  289. exprasmList.concat(ai);
  290. end;
  291. procedure emit_flag2reg(flag:tresflags;hregister:tregister);
  292. var
  293. ai : taicpu;
  294. hreg : tregister;
  295. begin
  296. hreg:=makereg8(hregister);
  297. ai:=Taicpu.Op_reg(A_Setcc,S_B,hreg);
  298. ai.SetCondition(flag_2_cond[flag]);
  299. exprasmList.concat(ai);
  300. if hreg<>hregister then
  301. begin
  302. if hregister in regset16bit then
  303. emit_to_reg16(hreg)
  304. else
  305. emit_to_reg32(hreg);
  306. end;
  307. end;
  308. procedure emit_none(i : tasmop;s : topsize);
  309. begin
  310. exprasmList.concat(Taicpu.Op_none(i,s));
  311. end;
  312. procedure emit_reg(i : tasmop;s : topsize;reg : tregister);
  313. begin
  314. exprasmList.concat(Taicpu.Op_reg(i,s,reg));
  315. end;
  316. procedure emit_ref(i : tasmop;s : topsize;ref : preference);
  317. begin
  318. exprasmList.concat(Taicpu.Op_ref(i,s,ref));
  319. end;
  320. procedure emit_const(i : tasmop;s : topsize;c : longint);
  321. begin
  322. exprasmList.concat(Taicpu.Op_const(i,s,c));
  323. end;
  324. procedure emit_const_reg(i : tasmop;s : topsize;c : longint;reg : tregister);
  325. begin
  326. exprasmList.concat(Taicpu.Op_const_reg(i,s,c,reg));
  327. end;
  328. procedure emit_const_ref(i : tasmop;s : topsize;c : longint;ref : preference);
  329. begin
  330. exprasmList.concat(Taicpu.Op_const_ref(i,s,c,ref));
  331. end;
  332. procedure emit_ref_reg(i : tasmop;s : topsize;ref : preference;reg : tregister);
  333. begin
  334. exprasmList.concat(Taicpu.Op_ref_reg(i,s,ref,reg));
  335. end;
  336. procedure emit_reg_ref(i : tasmop;s : topsize;reg : tregister;ref : preference);
  337. begin
  338. exprasmList.concat(Taicpu.Op_reg_ref(i,s,reg,ref));
  339. end;
  340. procedure emit_reg_reg(i : tasmop;s : topsize;reg1,reg2 : tregister);
  341. begin
  342. if (reg1<>reg2) or (i<>A_MOV) then
  343. exprasmList.concat(Taicpu.Op_reg_reg(i,s,reg1,reg2));
  344. end;
  345. procedure emit_const_reg_reg(i : tasmop;s : topsize;c : longint;reg1,reg2 : tregister);
  346. begin
  347. exprasmList.concat(Taicpu.Op_const_reg_reg(i,s,c,reg1,reg2));
  348. end;
  349. procedure emit_reg_reg_reg(i : tasmop;s : topsize;reg1,reg2,reg3 : tregister);
  350. begin
  351. exprasmList.concat(Taicpu.Op_reg_reg_reg(i,s,reg1,reg2,reg3));
  352. end;
  353. procedure emit_sym(i : tasmop;s : topsize;op : tasmsymbol);
  354. begin
  355. exprasmList.concat(Taicpu.Op_sym(i,s,op));
  356. end;
  357. procedure emit_sym_ofs(i : tasmop;s : topsize;op : tasmsymbol;ofs : longint);
  358. begin
  359. exprasmList.concat(Taicpu.Op_sym_ofs(i,s,op,ofs));
  360. end;
  361. procedure emit_sym_ofs_reg(i : tasmop;s : topsize;op : tasmsymbol;ofs:longint;reg : tregister);
  362. begin
  363. exprasmList.concat(Taicpu.Op_sym_ofs_reg(i,s,op,ofs,reg));
  364. end;
  365. procedure emit_sym_ofs_ref(i : tasmop;s : topsize;op : tasmsymbol;ofs:longint;ref : preference);
  366. begin
  367. exprasmList.concat(Taicpu.Op_sym_ofs_ref(i,s,op,ofs,ref));
  368. end;
  369. procedure emitcall(const routine:string);
  370. begin
  371. exprasmList.concat(Taicpu.Op_sym(A_CALL,S_NO,newasmsymbol(routine)));
  372. end;
  373. { only usefull in startup code }
  374. procedure emitinsertcall(const routine:string);
  375. begin
  376. exprasmList.insert(Taicpu.Op_sym(A_CALL,S_NO,newasmsymbol(routine)));
  377. end;
  378. procedure emit_mov_loc_ref(const t:tlocation;const ref:treference;siz:topsize;freetemp:boolean);
  379. var
  380. hreg : tregister;
  381. pushedeax : boolean;
  382. begin
  383. pushedeax:=false;
  384. case t.loc of
  385. LOC_REGISTER,
  386. LOC_CREGISTER : begin
  387. exprasmList.concat(Taicpu.Op_reg_ref(A_MOV,siz,
  388. t.register,newreference(ref)));
  389. ungetregister32(t.register); { the register is not needed anymore }
  390. end;
  391. LOC_MEM,
  392. LOC_REFERENCE : begin
  393. if t.reference.is_immediate then
  394. emit_const_ref(A_MOV,siz,
  395. t.reference.offset,newreference(ref))
  396. else
  397. begin
  398. case siz of
  399. S_B : begin
  400. { we can't do a getregister in the code generator }
  401. { without problems!!! }
  402. if usablereg32>0 then
  403. hreg:=reg32toreg8(getregister32)
  404. else
  405. begin
  406. emit_reg(A_PUSH,S_L,R_EAX);
  407. pushedeax:=true;
  408. hreg:=R_AL;
  409. end;
  410. end;
  411. S_W : hreg:=R_DI;
  412. S_L : hreg:=R_EDI;
  413. end;
  414. if hreg in [R_DI,R_EDI] then
  415. getexplicitregister32(R_EDI);
  416. emit_ref_reg(A_MOV,siz,
  417. newreference(t.reference),hreg);
  418. del_reference(t.reference);
  419. exprasmList.concat(Taicpu.Op_reg_ref(A_MOV,siz,
  420. hreg,newreference(ref)));
  421. if siz=S_B then
  422. begin
  423. if pushedeax then
  424. emit_reg(A_POP,S_L,R_EAX)
  425. else
  426. ungetregister(hreg);
  427. end;
  428. if hreg in [R_DI,R_EDI] then
  429. ungetregister32(R_EDI);
  430. { we can release the registers }
  431. { but only AFTER the MOV! Important for the optimizer!
  432. (JM)}
  433. del_reference(ref);
  434. end;
  435. if freetemp then
  436. ungetiftemp(t.reference);
  437. end;
  438. else
  439. internalerror(330);
  440. end;
  441. end;
  442. procedure emit_mov_loc_reg(const t:tlocation;reg:tregister);
  443. begin
  444. case t.loc of
  445. LOC_REGISTER,
  446. LOC_CREGISTER : begin
  447. emit_reg_reg(A_MOV,S_L,t.register,reg);
  448. ungetregister32(t.register); { the register is not needed anymore }
  449. end;
  450. LOC_MEM,
  451. LOC_REFERENCE : begin
  452. if t.reference.is_immediate then
  453. emit_const_reg(A_MOV,S_L,
  454. t.reference.offset,reg)
  455. else
  456. begin
  457. emit_ref_reg(A_MOV,S_L,
  458. newreference(t.reference),reg);
  459. end;
  460. end;
  461. else
  462. internalerror(330);
  463. end;
  464. end;
  465. procedure emit_mov_reg_loc(reg: TRegister; const t:tlocation);
  466. begin
  467. case t.loc of
  468. LOC_REGISTER,
  469. LOC_CREGISTER : begin
  470. emit_reg_reg(A_MOV,RegSize(Reg),
  471. reg,t.register);
  472. end;
  473. LOC_MEM,
  474. LOC_REFERENCE : begin
  475. if t.reference.is_immediate then
  476. internalerror(334)
  477. else
  478. begin
  479. exprasmList.concat(Taicpu.Op_reg_ref(A_MOV,RegSize(Reg),
  480. Reg,newreference(t.reference)));
  481. end;
  482. end;
  483. else
  484. internalerror(330);
  485. end;
  486. end;
  487. procedure emit_lea_loc_reg(const t:tlocation;reg:tregister;freetemp:boolean);
  488. begin
  489. case t.loc of
  490. LOC_MEM,
  491. LOC_REFERENCE : begin
  492. if t.reference.is_immediate then
  493. internalerror(331)
  494. else
  495. begin
  496. emit_ref_reg(A_LEA,S_L,
  497. newreference(t.reference),reg);
  498. end;
  499. if freetemp then
  500. ungetiftemp(t.reference);
  501. end;
  502. else
  503. internalerror(332);
  504. end;
  505. end;
  506. procedure emit_movq_reg_loc(reghigh,reglow: TRegister;t:tlocation);
  507. begin
  508. case t.loc of
  509. LOC_REGISTER,
  510. LOC_CREGISTER : begin
  511. emit_reg_reg(A_MOV,S_L,
  512. reglow,t.registerlow);
  513. emit_reg_reg(A_MOV,S_L,
  514. reghigh,t.registerhigh);
  515. end;
  516. LOC_MEM,
  517. LOC_REFERENCE : begin
  518. if t.reference.is_immediate then
  519. internalerror(334)
  520. else
  521. begin
  522. exprasmList.concat(Taicpu.Op_reg_ref(A_MOV,S_L,
  523. Reglow,newreference(t.reference)));
  524. inc(t.reference.offset,4);
  525. exprasmList.concat(Taicpu.Op_reg_ref(A_MOV,S_L,
  526. Reghigh,newreference(t.reference)));
  527. end;
  528. end;
  529. else
  530. internalerror(330);
  531. end;
  532. end;
  533. procedure emit_pushq_loc(const t : tlocation);
  534. var
  535. hr : preference;
  536. begin
  537. case t.loc of
  538. LOC_REGISTER,
  539. LOC_CREGISTER:
  540. begin
  541. exprasmList.concat(Taicpu.Op_reg(A_PUSH,S_L,
  542. t.registerhigh));
  543. exprasmList.concat(Taicpu.Op_reg(A_PUSH,S_L,
  544. t.registerlow));
  545. end;
  546. LOC_MEM,
  547. LOC_REFERENCE:
  548. begin
  549. hr:=newreference(t.reference);
  550. inc(hr^.offset,4);
  551. exprasmList.concat(Taicpu.Op_ref(A_PUSH,S_L,
  552. hr));
  553. exprasmList.concat(Taicpu.Op_ref(A_PUSH,S_L,
  554. newreference(t.reference)));
  555. ungetiftemp(t.reference);
  556. end;
  557. else internalerror(331);
  558. end;
  559. end;
  560. procedure remove_non_regvars_from_loc(const t: tlocation; var regs: byte);
  561. begin
  562. case t.loc of
  563. LOC_REGISTER:
  564. { can't be a regvar, since it would be LOC_CREGISTER then }
  565. regs := regs and not($80 shr byte(t.register));
  566. LOC_MEM,LOC_REFERENCE:
  567. begin
  568. if not(cs_regalloc in aktglobalswitches) or
  569. (t.reference.base in usableregs) then
  570. regs := regs and
  571. not($80 shr byte(t.reference.base));
  572. if not(cs_regalloc in aktglobalswitches) or
  573. (t.reference.index in usableregs) then
  574. regs := regs and
  575. not($80 shr byte(t.reference.index));
  576. end;
  577. end;
  578. end;
  579. procedure release_loc(const t : tlocation);
  580. begin
  581. case t.loc of
  582. LOC_REGISTER,
  583. LOC_CREGISTER:
  584. begin
  585. ungetregister32(t.register);
  586. end;
  587. LOC_MEM,
  588. LOC_REFERENCE:
  589. del_reference(t.reference);
  590. else internalerror(332);
  591. end;
  592. end;
  593. procedure release_qword_loc(const t : tlocation);
  594. begin
  595. case t.loc of
  596. LOC_REGISTER,
  597. LOC_CREGISTER:
  598. begin
  599. ungetregister32(t.registerhigh);
  600. ungetregister32(t.registerlow);
  601. end;
  602. LOC_MEM,
  603. LOC_REFERENCE:
  604. del_reference(t.reference);
  605. else internalerror(331);
  606. end;
  607. end;
  608. procedure emit_push_loc(const t:tlocation);
  609. begin
  610. case t.loc of
  611. LOC_REGISTER,
  612. LOC_CREGISTER : begin
  613. exprasmList.concat(Taicpu.Op_reg(A_PUSH,S_L,makereg32(t.register)));
  614. ungetregister(t.register); { the register is not needed anymore }
  615. end;
  616. LOC_MEM,
  617. LOC_REFERENCE : begin
  618. if t.reference.is_immediate then
  619. exprasmList.concat(Taicpu.Op_const(A_PUSH,S_L,t.reference.offset))
  620. else
  621. exprasmList.concat(Taicpu.Op_ref(A_PUSH,S_L,newreference(t.reference)));
  622. del_reference(t.reference);
  623. ungetiftemp(t.reference);
  624. end;
  625. else
  626. internalerror(330);
  627. end;
  628. end;
  629. procedure emit_pushw_loc(const t:tlocation);
  630. var
  631. opsize : topsize;
  632. begin
  633. case t.loc of
  634. LOC_REGISTER,
  635. LOC_CREGISTER : begin
  636. if aktalignment.paraalign=4 then
  637. exprasmList.concat(Taicpu.Op_reg(A_PUSH,S_L,makereg32(t.register)))
  638. else
  639. exprasmList.concat(Taicpu.Op_reg(A_PUSH,S_W,makereg16(t.register)));
  640. ungetregister(t.register); { the register is not needed anymore }
  641. end;
  642. LOC_MEM,
  643. LOC_REFERENCE : begin
  644. if aktalignment.paraalign=4 then
  645. opsize:=S_L
  646. else
  647. opsize:=S_W;
  648. if t.reference.is_immediate then
  649. exprasmList.concat(Taicpu.Op_const(A_PUSH,opsize,t.reference.offset))
  650. else
  651. exprasmList.concat(Taicpu.Op_ref(A_PUSH,opsize,newreference(t.reference)));
  652. del_reference(t.reference);
  653. ungetiftemp(t.reference);
  654. end;
  655. else
  656. internalerror(330);
  657. end;
  658. end;
  659. procedure emit_lea_loc_ref(const t:tlocation;const ref:treference;freetemp:boolean);
  660. begin
  661. case t.loc of
  662. LOC_MEM,
  663. LOC_REFERENCE : begin
  664. if t.reference.is_immediate then
  665. internalerror(331)
  666. else
  667. begin
  668. getexplicitregister32(R_EDI);
  669. emit_ref_reg(A_LEA,S_L,
  670. newreference(t.reference),R_EDI);
  671. exprasmList.concat(Taicpu.Op_reg_ref(A_MOV,S_L,
  672. R_EDI,newreference(ref)));
  673. ungetregister32(R_EDI);
  674. end;
  675. { release the registers }
  676. del_reference(t.reference);
  677. if freetemp then
  678. ungetiftemp(t.reference);
  679. end;
  680. else
  681. internalerror(332);
  682. end;
  683. end;
  684. procedure emit_push_lea_loc(const t:tlocation;freetemp:boolean);
  685. begin
  686. case t.loc of
  687. LOC_MEM,
  688. LOC_REFERENCE : begin
  689. if t.reference.is_immediate then
  690. internalerror(331)
  691. else
  692. begin
  693. getexplicitregister32(R_EDI);
  694. emit_ref_reg(A_LEA,S_L,
  695. newreference(t.reference),R_EDI);
  696. exprasmList.concat(Taicpu.Op_reg(A_PUSH,S_L,R_EDI));
  697. ungetregister32(R_EDI);
  698. end;
  699. if freetemp then
  700. ungetiftemp(t.reference);
  701. end;
  702. else
  703. internalerror(332);
  704. end;
  705. end;
  706. procedure emit_push_mem_size(const t: treference; size: longint);
  707. var
  708. s: topsize;
  709. begin
  710. if t.is_immediate then
  711. begin
  712. if (size=4) or
  713. (aktalignment.paraalign=4) then
  714. exprasmList.concat(Taicpu.Op_const(A_PUSH,S_L,t.offset))
  715. else
  716. exprasmList.concat(Taicpu.Op_const(A_PUSH,S_W,t.offset));
  717. end
  718. else
  719. if size < 4 then
  720. begin
  721. getexplicitregister32(R_EDI);
  722. case size of
  723. 1: s := S_BL;
  724. 2: s := S_WL;
  725. else internalerror(200008071);
  726. end;
  727. exprasmList.concat(Taicpu.Op_ref_reg(A_MOVZX,s,
  728. newreference(t),R_EDI));
  729. if aktalignment.paraalign=4 then
  730. exprasmList.concat(Taicpu.Op_reg(A_PUSH,S_L,R_EDI))
  731. else
  732. exprasmList.concat(Taicpu.Op_reg(A_PUSH,S_W,R_DI));
  733. ungetregister32(R_EDI);
  734. end
  735. else
  736. if size = 4 then
  737. emit_push_mem(t)
  738. else
  739. internalerror(200008072);
  740. end;
  741. procedure emit_to_mem(var t:tlocation;def:tdef);
  742. var
  743. r : treference;
  744. begin
  745. case t.loc of
  746. LOC_FPU : begin
  747. reset_reference(t.reference);
  748. gettempofsizereference(10,t.reference);
  749. floatstore(tfloatdef(def).typ,t.reference);
  750. end;
  751. LOC_REGISTER:
  752. begin
  753. if is_64bitint(def) then
  754. begin
  755. gettempofsizereference(8,r);
  756. emit_reg_ref(A_MOV,S_L,t.registerlow,newreference(r));
  757. inc(r.offset,4);
  758. emit_reg_ref(A_MOV,S_L,t.registerhigh,newreference(r));
  759. dec(r.offset,4);
  760. t.reference:=r;
  761. end
  762. else
  763. internalerror(1405001);
  764. end;
  765. LOC_MEM,
  766. LOC_REFERENCE : ;
  767. LOC_CFPUREGISTER : begin
  768. emit_reg(A_FLD,S_NO,correct_fpuregister(t.register,fpuvaroffset));
  769. inc(fpuvaroffset);
  770. reset_reference(t.reference);
  771. gettempofsizereference(10,t.reference);
  772. floatstore(tfloatdef(def).typ,t.reference);
  773. end;
  774. else
  775. internalerror(333);
  776. end;
  777. t.loc:=LOC_MEM;
  778. end;
  779. procedure emit_to_reg16(var hr:tregister);
  780. begin
  781. { ranges are a little bit bug sensitive ! }
  782. case hr of
  783. R_EAX,R_EBX,R_ECX,R_EDX,R_EDI,R_ESI,R_ESP,R_EBP:
  784. begin
  785. hr:=reg32toreg16(hr);
  786. end;
  787. R_AL,R_BL,R_CL,R_DL:
  788. begin
  789. hr:=reg8toreg16(hr);
  790. emit_const_reg(A_AND,S_W,$ff,hr);
  791. end;
  792. R_AH,R_BH,R_CH,R_DH:
  793. begin
  794. hr:=reg8toreg16(hr);
  795. emit_const_reg(A_AND,S_W,$ff00,hr);
  796. end;
  797. end;
  798. end;
  799. procedure emit_to_reg32(var hr:tregister);
  800. begin
  801. { ranges are a little bit bug sensitive ! }
  802. case hr of
  803. R_AX,R_BX,R_CX,R_DX,R_DI,R_SI,R_SP,R_BP:
  804. begin
  805. hr:=reg16toreg32(hr);
  806. emit_const_reg(A_AND,S_L,$ffff,hr);
  807. end;
  808. R_AL,R_BL,R_CL,R_DL:
  809. begin
  810. hr:=reg8toreg32(hr);
  811. emit_const_reg(A_AND,S_L,$ff,hr);
  812. end;
  813. R_AH,R_BH,R_CH,R_DH:
  814. begin
  815. hr:=reg8toreg32(hr);
  816. emit_const_reg(A_AND,S_L,$ff00,hr);
  817. end;
  818. end;
  819. end;
  820. procedure emit_mov_ref_reg64(r : treference;rl,rh : tregister);
  821. var
  822. hr : preference;
  823. begin
  824. { if we load a 64 bit reference, we must be careful because }
  825. { we could overwrite the registers of the reference by }
  826. { accident }
  827. getexplicitregister32(R_EDI);
  828. if r.base=rl then
  829. begin
  830. emit_reg_reg(A_MOV,S_L,r.base,
  831. R_EDI);
  832. r.base:=R_EDI;
  833. end
  834. else if r.index=rl then
  835. begin
  836. emit_reg_reg(A_MOV,S_L,r.index,
  837. R_EDI);
  838. r.index:=R_EDI;
  839. end;
  840. emit_ref_reg(A_MOV,S_L,
  841. newreference(r),rl);
  842. hr:=newreference(r);
  843. inc(hr^.offset,4);
  844. emit_ref_reg(A_MOV,S_L,
  845. hr,rh);
  846. ungetregister32(R_EDI);
  847. end;
  848. {*****************************************************************************
  849. Emit String Functions
  850. *****************************************************************************}
  851. procedure incrcomintfref(t: tdef; const ref: treference);
  852. var
  853. pushedregs : tpushed;
  854. begin
  855. pushusedregisters(pushedregs,$ff);
  856. emit_ref(A_PUSH,S_L,newreference(ref));
  857. saveregvars($ff);
  858. if is_interfacecom(t) then
  859. emitcall('FPC_INTF_INCR_REF')
  860. else
  861. internalerror(1859);
  862. popusedregisters(pushedregs);
  863. end;
  864. procedure decrcomintfref(t: tdef; const ref: treference);
  865. var
  866. pushedregs : tpushed;
  867. begin
  868. pushusedregisters(pushedregs,$ff);
  869. emitpushreferenceaddr(ref);
  870. saveregvars($ff);
  871. if is_interfacecom(t) then
  872. begin
  873. emitcall('FPC_INTF_DECR_REF');
  874. end
  875. else internalerror(1859);
  876. popusedregisters(pushedregs);
  877. end;
  878. procedure copyshortstring(const dref,sref : treference;len : byte;
  879. loadref, del_sref: boolean);
  880. begin
  881. emitpushreferenceaddr(dref);
  882. { if it's deleted right before it's used, the optimizer can move }
  883. { the reg deallocations to the right places (JM) }
  884. if del_sref then
  885. del_reference(sref);
  886. if loadref then
  887. emit_push_mem(sref)
  888. else
  889. emitpushreferenceaddr(sref);
  890. push_int(len);
  891. emitcall('FPC_SHORTSTR_COPY');
  892. maybe_loadself;
  893. end;
  894. {$ifdef unused}
  895. procedure copylongstring(const dref,sref : treference;len : longint;loadref:boolean);
  896. begin
  897. emitpushreferenceaddr(dref);
  898. if loadref then
  899. emit_push_mem(sref)
  900. else
  901. emitpushreferenceaddr(sref);
  902. push_int(len);
  903. saveregvars($ff);
  904. emitcall('FPC_LONGSTR_COPY');
  905. maybe_loadself;
  906. end;
  907. {$endif unused}
  908. procedure incrstringref(t : tdef;const ref : treference);
  909. var
  910. pushedregs : tpushed;
  911. begin
  912. pushusedregisters(pushedregs,$ff);
  913. emitpushreferenceaddr(ref);
  914. saveregvars($ff);
  915. if is_ansistring(t) then
  916. begin
  917. emitcall('FPC_ANSISTR_INCR_REF');
  918. end
  919. else if is_widestring(t) then
  920. begin
  921. emitcall('FPC_WIDESTR_INCR_REF');
  922. end
  923. else internalerror(1859);
  924. popusedregisters(pushedregs);
  925. end;
  926. procedure decrstringref(t : tdef;const ref : treference);
  927. var
  928. pushedregs : tpushed;
  929. begin
  930. pushusedregisters(pushedregs,$ff);
  931. emitpushreferenceaddr(ref);
  932. saveregvars($ff);
  933. if is_ansistring(t) then
  934. begin
  935. emitcall('FPC_ANSISTR_DECR_REF');
  936. end
  937. else if is_widestring(t) then
  938. begin
  939. emitcall('FPC_WIDESTR_DECR_REF');
  940. end
  941. else internalerror(1859);
  942. popusedregisters(pushedregs);
  943. end;
  944. {*****************************************************************************
  945. Emit Push Functions
  946. *****************************************************************************}
  947. procedure push_int(l : longint);
  948. begin
  949. if (l = 0) and
  950. not(aktoptprocessor in [Class386, ClassP6]) and
  951. not(cs_littlesize in aktglobalswitches)
  952. Then
  953. begin
  954. getexplicitregister32(R_EDI);
  955. emit_reg_reg(A_XOR,S_L,R_EDI,R_EDI);
  956. exprasmList.concat(Taicpu.Op_reg(A_PUSH,S_L,R_EDI));
  957. ungetregister32(R_EDI);
  958. end
  959. else
  960. exprasmList.concat(Taicpu.Op_const(A_PUSH,S_L,l));
  961. end;
  962. procedure emit_push_mem(const ref : treference);
  963. begin
  964. if ref.is_immediate then
  965. push_int(ref.offset)
  966. else
  967. begin
  968. if not(aktoptprocessor in [Class386, ClassP6]) and
  969. not(cs_littlesize in aktglobalswitches)
  970. then
  971. begin
  972. getexplicitregister32(R_EDI);
  973. emit_ref_reg(A_MOV,S_L,newreference(ref),R_EDI);
  974. exprasmList.concat(Taicpu.Op_reg(A_PUSH,S_L,R_EDI));
  975. ungetregister32(R_EDI);
  976. end
  977. else exprasmList.concat(Taicpu.Op_ref(A_PUSH,S_L,newreference(ref)));
  978. end;
  979. end;
  980. procedure emitpushreferenceaddr(const ref : treference);
  981. var
  982. href : treference;
  983. begin
  984. { this will fail for references to other segments !!! }
  985. if ref.is_immediate then
  986. { is this right ? }
  987. begin
  988. { push_int(ref.offset)}
  989. gettempofsizereference(4,href);
  990. emit_const_ref(A_MOV,S_L,ref.offset,newreference(href));
  991. emitpushreferenceaddr(href);
  992. del_reference(href);
  993. end
  994. else
  995. begin
  996. if ref.segment<>R_NO then
  997. CGMessage(cg_e_cant_use_far_pointer_there);
  998. if (ref.base=R_NO) and (ref.index=R_NO) then
  999. exprasmList.concat(Taicpu.Op_sym_ofs(A_PUSH,S_L,ref.symbol,ref.offset))
  1000. else if (ref.base=R_NO) and (ref.index<>R_NO) and
  1001. (ref.offset=0) and (ref.scalefactor=0) and (ref.symbol=nil) then
  1002. exprasmList.concat(Taicpu.Op_reg(A_PUSH,S_L,ref.index))
  1003. else if (ref.base<>R_NO) and (ref.index=R_NO) and
  1004. (ref.offset=0) and (ref.symbol=nil) then
  1005. exprasmList.concat(Taicpu.Op_reg(A_PUSH,S_L,ref.base))
  1006. else
  1007. begin
  1008. getexplicitregister32(R_EDI);
  1009. emit_ref_reg(A_LEA,S_L,newreference(ref),R_EDI);
  1010. exprasmList.concat(Taicpu.Op_reg(A_PUSH,S_L,R_EDI));
  1011. ungetregister32(R_EDI);
  1012. end;
  1013. end;
  1014. end;
  1015. {*****************************************************************************
  1016. Emit Float Functions
  1017. *****************************************************************************}
  1018. procedure floatloadops(t : tfloattype;var op : tasmop;var s : topsize);
  1019. begin
  1020. case t of
  1021. s32real : begin
  1022. op:=A_FLD;
  1023. s:=S_FS;
  1024. end;
  1025. s64real : begin
  1026. op:=A_FLD;
  1027. { ???? }
  1028. s:=S_FL;
  1029. end;
  1030. s80real : begin
  1031. op:=A_FLD;
  1032. s:=S_FX;
  1033. end;
  1034. s64comp : begin
  1035. op:=A_FILD;
  1036. s:=S_IQ;
  1037. end;
  1038. else internalerror(17);
  1039. end;
  1040. end;
  1041. procedure floatload(t : tfloattype;const ref : treference);
  1042. var
  1043. op : tasmop;
  1044. s : topsize;
  1045. begin
  1046. floatloadops(t,op,s);
  1047. exprasmList.concat(Taicpu.Op_ref(op,s,
  1048. newreference(ref)));
  1049. inc(fpuvaroffset);
  1050. end;
  1051. procedure floatstoreops(t : tfloattype;var op : tasmop;var s : topsize);
  1052. begin
  1053. case t of
  1054. s32real : begin
  1055. op:=A_FSTP;
  1056. s:=S_FS;
  1057. end;
  1058. s64real : begin
  1059. op:=A_FSTP;
  1060. s:=S_FL;
  1061. end;
  1062. s80real : begin
  1063. op:=A_FSTP;
  1064. s:=S_FX;
  1065. end;
  1066. s64comp : begin
  1067. op:=A_FISTP;
  1068. s:=S_IQ;
  1069. end;
  1070. else
  1071. internalerror(17);
  1072. end;
  1073. end;
  1074. procedure floatstore(t : tfloattype;const ref : treference);
  1075. var
  1076. op : tasmop;
  1077. s : topsize;
  1078. begin
  1079. floatstoreops(t,op,s);
  1080. exprasmList.concat(Taicpu.Op_ref(op,s,
  1081. newreference(ref)));
  1082. dec(fpuvaroffset);
  1083. end;
  1084. {*****************************************************************************
  1085. Emit Functions
  1086. *****************************************************************************}
  1087. procedure concatcopy(source,dest : treference;size : longint;delsource,loadref : boolean);
  1088. const
  1089. isizes : array[0..3] of topsize=(S_L,S_B,S_W,S_B);
  1090. ishr : array[0..3] of byte=(2,0,1,0);
  1091. var
  1092. ecxpushed : boolean;
  1093. helpsize : longint;
  1094. i : byte;
  1095. reg8,reg32 : tregister;
  1096. swap : boolean;
  1097. procedure maybepushecx;
  1098. begin
  1099. if not(R_ECX in unused) then
  1100. begin
  1101. exprasmList.concat(Taicpu.Op_reg(A_PUSH,S_L,R_ECX));
  1102. ecxpushed:=true;
  1103. end
  1104. else getexplicitregister32(R_ECX);
  1105. end;
  1106. begin
  1107. {$IfNDef regallocfix}
  1108. If delsource then
  1109. del_reference(source);
  1110. {$EndIf regallocfix}
  1111. if (not loadref) and
  1112. ((size<=8) or
  1113. (not(cs_littlesize in aktglobalswitches ) and (size<=12))) then
  1114. begin
  1115. helpsize:=size shr 2;
  1116. getexplicitregister32(R_EDI);
  1117. for i:=1 to helpsize do
  1118. begin
  1119. emit_ref_reg(A_MOV,S_L,newreference(source),R_EDI);
  1120. {$ifdef regallocfix}
  1121. If (size = 4) and delsource then
  1122. del_reference(source);
  1123. {$endif regallocfix}
  1124. exprasmList.concat(Taicpu.Op_reg_ref(A_MOV,S_L,R_EDI,newreference(dest)));
  1125. inc(source.offset,4);
  1126. inc(dest.offset,4);
  1127. dec(size,4);
  1128. end;
  1129. if size>1 then
  1130. begin
  1131. emit_ref_reg(A_MOV,S_W,newreference(source),R_DI);
  1132. {$ifdef regallocfix}
  1133. If (size = 2) and delsource then
  1134. del_reference(source);
  1135. {$endif regallocfix}
  1136. exprasmList.concat(Taicpu.Op_reg_ref(A_MOV,S_W,R_DI,newreference(dest)));
  1137. inc(source.offset,2);
  1138. inc(dest.offset,2);
  1139. dec(size,2);
  1140. end;
  1141. ungetregister32(R_EDI);
  1142. if size>0 then
  1143. begin
  1144. { and now look for an 8 bit register }
  1145. swap:=false;
  1146. if R_EAX in unused then reg8:=reg32toreg8(getexplicitregister32(R_EAX))
  1147. else if R_EDX in unused then reg8:=reg32toreg8(getexplicitregister32(R_EDX))
  1148. else if R_EBX in unused then reg8:=reg32toreg8(getexplicitregister32(R_EBX))
  1149. else if R_ECX in unused then reg8:=reg32toreg8(getexplicitregister32(R_ECX))
  1150. else
  1151. begin
  1152. swap:=true;
  1153. { we need only to check 3 registers, because }
  1154. { one is always not index or base }
  1155. if (dest.base<>R_EAX) and (dest.index<>R_EAX) then
  1156. begin
  1157. reg8:=R_AL;
  1158. reg32:=R_EAX;
  1159. end
  1160. else if (dest.base<>R_EBX) and (dest.index<>R_EBX) then
  1161. begin
  1162. reg8:=R_BL;
  1163. reg32:=R_EBX;
  1164. end
  1165. else if (dest.base<>R_ECX) and (dest.index<>R_ECX) then
  1166. begin
  1167. reg8:=R_CL;
  1168. reg32:=R_ECX;
  1169. end;
  1170. end;
  1171. if swap then
  1172. { was earlier XCHG, of course nonsense }
  1173. begin
  1174. getexplicitregister32(R_EDI);
  1175. emit_reg_reg(A_MOV,S_L,reg32,R_EDI);
  1176. end;
  1177. emit_ref_reg(A_MOV,S_B,newreference(source),reg8);
  1178. {$ifdef regallocfix}
  1179. If delsource then
  1180. del_reference(source);
  1181. {$endif regallocfix}
  1182. exprasmList.concat(Taicpu.Op_reg_ref(A_MOV,S_B,reg8,newreference(dest)));
  1183. if swap then
  1184. begin
  1185. emit_reg_reg(A_MOV,S_L,R_EDI,reg32);
  1186. ungetregister32(R_EDI);
  1187. end
  1188. else
  1189. ungetregister(reg8);
  1190. end;
  1191. end
  1192. else
  1193. begin
  1194. getexplicitregister32(R_EDI);
  1195. emit_ref_reg(A_LEA,S_L,newreference(dest),R_EDI);
  1196. {$ifdef regallocfix}
  1197. {is this ok?? (JM)}
  1198. del_reference(dest);
  1199. {$endif regallocfix}
  1200. exprasmList.concat(Tairegalloc.Alloc(R_ESI));
  1201. if loadref then
  1202. emit_ref_reg(A_MOV,S_L,newreference(source),R_ESI)
  1203. else
  1204. begin
  1205. emit_ref_reg(A_LEA,S_L,newreference(source),R_ESI);
  1206. {$ifdef regallocfix}
  1207. if delsource then
  1208. del_reference(source);
  1209. {$endif regallocfix}
  1210. end;
  1211. exprasmList.concat(Taicpu.Op_none(A_CLD,S_NO));
  1212. ecxpushed:=false;
  1213. if cs_littlesize in aktglobalswitches then
  1214. begin
  1215. maybepushecx;
  1216. emit_const_reg(A_MOV,S_L,size,R_ECX);
  1217. exprasmList.concat(Taicpu.Op_none(A_REP,S_NO));
  1218. exprasmList.concat(Taicpu.Op_none(A_MOVSB,S_NO));
  1219. end
  1220. else
  1221. begin
  1222. helpsize:=size shr 2;
  1223. size:=size and 3;
  1224. if helpsize>1 then
  1225. begin
  1226. maybepushecx;
  1227. emit_const_reg(A_MOV,S_L,helpsize,R_ECX);
  1228. exprasmList.concat(Taicpu.Op_none(A_REP,S_NO));
  1229. end;
  1230. if helpsize>0 then
  1231. exprasmList.concat(Taicpu.Op_none(A_MOVSD,S_NO));
  1232. if size>1 then
  1233. begin
  1234. dec(size,2);
  1235. exprasmList.concat(Taicpu.Op_none(A_MOVSW,S_NO));
  1236. end;
  1237. if size=1 then
  1238. exprasmList.concat(Taicpu.Op_none(A_MOVSB,S_NO));
  1239. end;
  1240. ungetregister32(R_EDI);
  1241. exprasmList.concat(Tairegalloc.DeAlloc(R_ESI));
  1242. if ecxpushed then
  1243. exprasmList.concat(Taicpu.Op_reg(A_POP,S_L,R_ECX))
  1244. else
  1245. ungetregister32(R_ECX);
  1246. { loading SELF-reference again }
  1247. maybe_loadself;
  1248. end;
  1249. if delsource then
  1250. ungetiftemp(source);
  1251. end;
  1252. procedure emitloadord2reg(const location:Tlocation;orddef:torddef;
  1253. destreg:Tregister;delloc:boolean);
  1254. {A lot smaller and less bug sensitive than the original unfolded loads.}
  1255. var tai:Taicpu;
  1256. r:Preference;
  1257. begin
  1258. tai := nil;
  1259. case location.loc of
  1260. LOC_REGISTER,LOC_CREGISTER:
  1261. begin
  1262. case orddef.typ of
  1263. u8bit,uchar,bool8bit:
  1264. tai:=Taicpu.Op_reg_reg(A_MOVZX,S_BL,location.register,destreg);
  1265. s8bit:
  1266. tai:=Taicpu.Op_reg_reg(A_MOVSX,S_BL,location.register,destreg);
  1267. u16bit,uwidechar,bool16bit:
  1268. tai:=Taicpu.Op_reg_reg(A_MOVZX,S_WL,location.register,destreg);
  1269. s16bit:
  1270. tai:=Taicpu.Op_reg_reg(A_MOVSX,S_WL,location.register,destreg);
  1271. u32bit,bool32bit,s32bit:
  1272. if location.register <> destreg then
  1273. tai:=Taicpu.Op_reg_reg(A_MOV,S_L,location.register,destreg);
  1274. else
  1275. internalerror(330);
  1276. end;
  1277. if delloc then
  1278. ungetregister(location.register);
  1279. end;
  1280. LOC_MEM,
  1281. LOC_REFERENCE:
  1282. begin
  1283. if location.reference.is_immediate then
  1284. tai:=Taicpu.Op_const_reg(A_MOV,S_L,location.reference.offset,destreg)
  1285. else
  1286. begin
  1287. r:=newreference(location.reference);
  1288. case orddef.typ of
  1289. u8bit,uchar,bool8bit:
  1290. tai:=Taicpu.Op_ref_reg(A_MOVZX,S_BL,r,destreg);
  1291. s8bit:
  1292. tai:=Taicpu.Op_ref_reg(A_MOVSX,S_BL,r,destreg);
  1293. u16bit,uwidechar,bool16bit:
  1294. tai:=Taicpu.Op_ref_reg(A_MOVZX,S_WL,r,destreg);
  1295. s16bit:
  1296. tai:=Taicpu.Op_ref_reg(A_MOVSX,S_WL,r,destreg);
  1297. u32bit,bool32bit:
  1298. tai:=Taicpu.Op_ref_reg(A_MOV,S_L,r,destreg);
  1299. s32bit:
  1300. tai:=Taicpu.Op_ref_reg(A_MOV,S_L,r,destreg);
  1301. else
  1302. internalerror(330);
  1303. end;
  1304. end;
  1305. if delloc then
  1306. del_reference(location.reference);
  1307. end
  1308. else
  1309. internalerror(6);
  1310. end;
  1311. if assigned(tai) then
  1312. exprasmList.concat(tai);
  1313. end;
  1314. { if necessary ESI is reloaded after a call}
  1315. procedure maybe_loadself;
  1316. var
  1317. hp : preference;
  1318. p : pprocinfo;
  1319. i : longint;
  1320. begin
  1321. if assigned(procinfo^._class) then
  1322. begin
  1323. exprasmList.concat(Tairegalloc.Alloc(R_ESI));
  1324. if lexlevel>normal_function_level then
  1325. begin
  1326. new(hp);
  1327. reset_reference(hp^);
  1328. hp^.offset:=procinfo^.framepointer_offset;
  1329. hp^.base:=procinfo^.framepointer;
  1330. emit_ref_reg(A_MOV,S_L,hp,R_ESI);
  1331. p:=procinfo^.parent;
  1332. for i:=3 to lexlevel-1 do
  1333. begin
  1334. new(hp);
  1335. reset_reference(hp^);
  1336. hp^.offset:=p^.framepointer_offset;
  1337. hp^.base:=R_ESI;
  1338. emit_ref_reg(A_MOV,S_L,hp,R_ESI);
  1339. p:=p^.parent;
  1340. end;
  1341. new(hp);
  1342. reset_reference(hp^);
  1343. hp^.offset:=p^.selfpointer_offset;
  1344. hp^.base:=R_ESI;
  1345. emit_ref_reg(A_MOV,S_L,hp,R_ESI);
  1346. end
  1347. else
  1348. begin
  1349. new(hp);
  1350. reset_reference(hp^);
  1351. hp^.offset:=procinfo^.selfpointer_offset;
  1352. hp^.base:=procinfo^.framepointer;
  1353. emit_ref_reg(A_MOV,S_L,hp,R_ESI);
  1354. end;
  1355. end;
  1356. end;
  1357. {*****************************************************************************
  1358. Entry/Exit Code Functions
  1359. *****************************************************************************}
  1360. procedure genprofilecode;
  1361. var
  1362. pl : tasmlabel;
  1363. begin
  1364. if (po_assembler in aktprocsym.definition.procoptions) then
  1365. exit;
  1366. case target_info.target of
  1367. target_i386_win32,
  1368. target_i386_freebsd,
  1369. target_i386_linux:
  1370. begin
  1371. getaddrlabel(pl);
  1372. emitinsertcall(target_info.Cprefix+'mcount');
  1373. usedinproc:=usedinproc or ($80 shr byte(R_EDX));
  1374. exprasmList.insert(Taicpu.Op_sym_ofs_reg(A_MOV,S_L,pl,0,R_EDX));
  1375. exprasmList.insert(Tai_section.Create(sec_code));
  1376. exprasmList.insert(Tai_const.Create_32bit(0));
  1377. exprasmList.insert(Tai_label.Create(pl));
  1378. exprasmList.insert(Tai_align.Create(4));
  1379. exprasmList.insert(Tai_section.Create(sec_data));
  1380. end;
  1381. target_i386_go32v2:
  1382. begin
  1383. emitinsertcall('MCOUNT');
  1384. end;
  1385. end;
  1386. end;
  1387. procedure generate_interrupt_stackframe_entry;
  1388. begin
  1389. { save the registers of an interrupt procedure }
  1390. exprasmList.insert(Taicpu.Op_reg(A_PUSH,S_L,R_EAX));
  1391. exprasmList.insert(Taicpu.Op_reg(A_PUSH,S_L,R_EBX));
  1392. exprasmList.insert(Taicpu.Op_reg(A_PUSH,S_L,R_ECX));
  1393. exprasmList.insert(Taicpu.Op_reg(A_PUSH,S_L,R_EDX));
  1394. exprasmList.insert(Taicpu.Op_reg(A_PUSH,S_L,R_ESI));
  1395. exprasmList.insert(Taicpu.Op_reg(A_PUSH,S_L,R_EDI));
  1396. { .... also the segment registers }
  1397. exprasmList.insert(Taicpu.Op_reg(A_PUSH,S_W,R_DS));
  1398. exprasmList.insert(Taicpu.Op_reg(A_PUSH,S_W,R_ES));
  1399. exprasmList.insert(Taicpu.Op_reg(A_PUSH,S_W,R_FS));
  1400. exprasmList.insert(Taicpu.Op_reg(A_PUSH,S_W,R_GS));
  1401. end;
  1402. procedure generate_interrupt_stackframe_exit;
  1403. begin
  1404. { restore the registers of an interrupt procedure }
  1405. { this was all with entrycode instead of exitcode !!}
  1406. procinfo^.aktexitcode.concat(Taicpu.Op_reg(A_POP,S_L,R_EAX));
  1407. procinfo^.aktexitcode.concat(Taicpu.Op_reg(A_POP,S_L,R_EBX));
  1408. procinfo^.aktexitcode.concat(Taicpu.Op_reg(A_POP,S_L,R_ECX));
  1409. procinfo^.aktexitcode.concat(Taicpu.Op_reg(A_POP,S_L,R_EDX));
  1410. procinfo^.aktexitcode.concat(Taicpu.Op_reg(A_POP,S_L,R_ESI));
  1411. procinfo^.aktexitcode.concat(Taicpu.Op_reg(A_POP,S_L,R_EDI));
  1412. { .... also the segment registers }
  1413. procinfo^.aktexitcode.concat(Taicpu.Op_reg(A_POP,S_W,R_DS));
  1414. procinfo^.aktexitcode.concat(Taicpu.Op_reg(A_POP,S_W,R_ES));
  1415. procinfo^.aktexitcode.concat(Taicpu.Op_reg(A_POP,S_W,R_FS));
  1416. procinfo^.aktexitcode.concat(Taicpu.Op_reg(A_POP,S_W,R_GS));
  1417. { this restores the flags }
  1418. procinfo^.aktexitcode.concat(Taicpu.Op_none(A_IRET,S_NO));
  1419. end;
  1420. { generates the code for threadvar initialisation }
  1421. procedure initialize_threadvar(p : tnamedindexitem);
  1422. var
  1423. hr : treference;
  1424. begin
  1425. if (tsym(p).typ=varsym) and
  1426. (vo_is_thread_var in tvarsym(p).varoptions) then
  1427. begin
  1428. exprasmList.concat(Taicpu.Op_const(A_PUSH,S_L,tvarsym(p).getsize));
  1429. reset_reference(hr);
  1430. hr.symbol:=newasmsymbol(tvarsym(p).mangledname);
  1431. emitpushreferenceaddr(hr);
  1432. saveregvars($ff);
  1433. emitcall('FPC_INIT_THREADVAR');
  1434. end;
  1435. end;
  1436. { initilizes data of type t }
  1437. { if is_already_ref is true then the routines assumes }
  1438. { that r points to the data to initialize }
  1439. procedure initialize(t : tdef;const ref : treference;is_already_ref : boolean);
  1440. var
  1441. hr : treference;
  1442. begin
  1443. if is_ansistring(t) or
  1444. is_widestring(t) or
  1445. is_interfacecom(t) then
  1446. begin
  1447. emit_const_ref(A_MOV,S_L,0,
  1448. newreference(ref));
  1449. end
  1450. else
  1451. begin
  1452. reset_reference(hr);
  1453. hr.symbol:=tstoreddef(t).get_inittable_label;
  1454. emitpushreferenceaddr(hr);
  1455. if is_already_ref then
  1456. exprasmList.concat(Taicpu.Op_ref(A_PUSH,S_L,
  1457. newreference(ref)))
  1458. else
  1459. emitpushreferenceaddr(ref);
  1460. emitcall('FPC_INITIALIZE');
  1461. end;
  1462. end;
  1463. { finalizes data of type t }
  1464. { if is_already_ref is true then the routines assumes }
  1465. { that r points to the data to finalizes }
  1466. procedure finalize(t : tdef;const ref : treference;is_already_ref : boolean);
  1467. var
  1468. r : treference;
  1469. begin
  1470. if is_ansistring(t) or
  1471. is_widestring(t) then
  1472. begin
  1473. decrstringref(t,ref);
  1474. end
  1475. else if is_interfacecom(t) then
  1476. begin
  1477. decrcomintfref(t,ref);
  1478. end
  1479. else
  1480. begin
  1481. reset_reference(r);
  1482. r.symbol:=tstoreddef(t).get_inittable_label;
  1483. emitpushreferenceaddr(r);
  1484. if is_already_ref then
  1485. exprasmList.concat(Taicpu.Op_ref(A_PUSH,S_L,
  1486. newreference(ref)))
  1487. else
  1488. emitpushreferenceaddr(ref);
  1489. emitcall('FPC_FINALIZE');
  1490. end;
  1491. end;
  1492. { generates the code for initialisation of local data }
  1493. procedure initialize_data(p : tnamedindexitem);
  1494. var
  1495. hr : treference;
  1496. begin
  1497. if (tsym(p).typ=varsym) and
  1498. assigned(tvarsym(p).vartype.def) and
  1499. not(is_class(tvarsym(p).vartype.def)) and
  1500. tvarsym(p).vartype.def.needs_inittable then
  1501. begin
  1502. if assigned(procinfo) then
  1503. procinfo^.flags:=procinfo^.flags or pi_needs_implicit_finally;
  1504. reset_reference(hr);
  1505. if tsym(p).owner.symtabletype in [localsymtable,inlinelocalsymtable] then
  1506. begin
  1507. hr.base:=procinfo^.framepointer;
  1508. hr.offset:=-tvarsym(p).address+tvarsym(p).owner.address_fixup;
  1509. end
  1510. else
  1511. begin
  1512. hr.symbol:=newasmsymbol(tvarsym(p).mangledname);
  1513. end;
  1514. initialize(tvarsym(p).vartype.def,hr,false);
  1515. end;
  1516. end;
  1517. { generates the code for incrementing the reference count of parameters and
  1518. initialize out parameters }
  1519. procedure init_paras(p : tnamedindexitem);
  1520. var
  1521. hrv : treference;
  1522. hr: treference;
  1523. begin
  1524. if (tsym(p).typ=varsym) and
  1525. not is_class(tvarsym(p).vartype.def) and
  1526. tvarsym(p).vartype.def.needs_inittable then
  1527. begin
  1528. if (tvarsym(p).varspez=vs_value) then
  1529. begin
  1530. procinfo^.flags:=procinfo^.flags or pi_needs_implicit_finally;
  1531. reset_reference(hrv);
  1532. hrv.base:=procinfo^.framepointer;
  1533. hrv.offset:=tvarsym(p).address+procinfo^.para_offset;
  1534. if is_ansistring(tvarsym(p).vartype.def) or
  1535. is_widestring(tvarsym(p).vartype.def) then
  1536. begin
  1537. incrstringref(tvarsym(p).vartype.def,hrv)
  1538. end
  1539. else if is_interfacecom(tvarsym(p).vartype.def) then
  1540. begin
  1541. incrcomintfref(tvarsym(p).vartype.def,hrv)
  1542. end
  1543. else
  1544. begin
  1545. reset_reference(hr);
  1546. hr.symbol:=tstoreddef(tvarsym(p).vartype.def).get_inittable_label;
  1547. emitpushreferenceaddr(hr);
  1548. emitpushreferenceaddr(hrv);
  1549. emitcall('FPC_ADDREF');
  1550. end;
  1551. end
  1552. else if (tvarsym(p).varspez=vs_out) then
  1553. begin
  1554. reset_reference(hrv);
  1555. hrv.base:=procinfo^.framepointer;
  1556. hrv.offset:=tvarsym(p).address+procinfo^.para_offset;
  1557. getexplicitregister32(R_EDI);
  1558. exprasmList.concat(Taicpu.Op_ref_reg(A_MOV,S_L,newreference(hrv),R_EDI));
  1559. reset_reference(hr);
  1560. hr.base:=R_EDI;
  1561. initialize(tvarsym(p).vartype.def,hr,false);
  1562. end;
  1563. end;
  1564. end;
  1565. { generates the code for decrementing the reference count of parameters }
  1566. procedure final_paras(p : tnamedindexitem);
  1567. var
  1568. hrv : treference;
  1569. hr: treference;
  1570. begin
  1571. if (tsym(p).typ=varsym) and
  1572. not is_class(tvarsym(p).vartype.def) and
  1573. tvarsym(p).vartype.def.needs_inittable then
  1574. begin
  1575. if (tvarsym(p).varspez=vs_value) then
  1576. begin
  1577. procinfo^.flags:=procinfo^.flags or pi_needs_implicit_finally;
  1578. reset_reference(hrv);
  1579. hrv.base:=procinfo^.framepointer;
  1580. hrv.offset:=tvarsym(p).address+procinfo^.para_offset;
  1581. if is_ansistring(tvarsym(p).vartype.def) or
  1582. is_widestring(tvarsym(p).vartype.def) then
  1583. begin
  1584. decrstringref(tvarsym(p).vartype.def,hrv)
  1585. end
  1586. else if is_interfacecom(tvarsym(p).vartype.def) then
  1587. begin
  1588. decrcomintfref(tvarsym(p).vartype.def,hrv)
  1589. end
  1590. else
  1591. begin
  1592. reset_reference(hr);
  1593. hr.symbol:=tstoreddef(tvarsym(p).vartype.def).get_inittable_label;
  1594. emitpushreferenceaddr(hr);
  1595. emitpushreferenceaddr(hrv);
  1596. emitcall('FPC_DECREF');
  1597. end;
  1598. end;
  1599. end;
  1600. end;
  1601. { generates the code for finalisation of local data }
  1602. procedure finalize_data(p : tnamedindexitem);
  1603. var
  1604. hr : treference;
  1605. begin
  1606. if (tsym(p).typ=varsym) and
  1607. assigned(tvarsym(p).vartype.def) and
  1608. not(is_class(tvarsym(p).vartype.def)) and
  1609. tvarsym(p).vartype.def.needs_inittable then
  1610. begin
  1611. if assigned(procinfo) then
  1612. procinfo^.flags:=procinfo^.flags or pi_needs_implicit_finally;
  1613. reset_reference(hr);
  1614. case tsym(p).owner.symtabletype of
  1615. localsymtable,inlinelocalsymtable:
  1616. begin
  1617. hr.base:=procinfo^.framepointer;
  1618. hr.offset:=-tvarsym(p).address+tvarsym(p).owner.address_fixup;
  1619. end;
  1620. else
  1621. hr.symbol:=newasmsymbol(tvarsym(p).mangledname);
  1622. end;
  1623. finalize(tvarsym(p).vartype.def,hr,false);
  1624. end;
  1625. end;
  1626. { generates the code to make local copies of the value parameters }
  1627. procedure copyvalueparas(p : tnamedindexitem);
  1628. var
  1629. href1,href2 : treference;
  1630. r : preference;
  1631. power,len : longint;
  1632. opsize : topsize;
  1633. {$ifndef NOTARGETWIN32}
  1634. again,ok : tasmlabel;
  1635. {$endif}
  1636. begin
  1637. if (tsym(p).typ=varsym) and
  1638. (tvarsym(p).varspez=vs_value) and
  1639. (push_addr_param(tvarsym(p).vartype.def)) then
  1640. begin
  1641. if is_open_array(tvarsym(p).vartype.def) or
  1642. is_array_of_const(tvarsym(p).vartype.def) then
  1643. begin
  1644. { get stack space }
  1645. new(r);
  1646. reset_reference(r^);
  1647. r^.base:=procinfo^.framepointer;
  1648. r^.offset:=tvarsym(p).address+4+procinfo^.para_offset;
  1649. getexplicitregister32(R_EDI);
  1650. exprasmList.concat(Taicpu.op_ref_reg(A_MOV,S_L,r,R_EDI));
  1651. exprasmList.concat(Taicpu.op_reg(A_INC,S_L,R_EDI));
  1652. if (tarraydef(tvarsym(p).vartype.def).elesize<>1) then
  1653. begin
  1654. if ispowerof2(tarraydef(tvarsym(p).vartype.def).elesize, power) then
  1655. exprasmList.concat(Taicpu.op_const_reg(A_SHL,S_L,power,R_EDI))
  1656. else
  1657. exprasmList.concat(Taicpu.op_const_reg(A_IMUL,S_L,
  1658. tarraydef(tvarsym(p).vartype.def).elesize,R_EDI));
  1659. end;
  1660. {$ifndef NOTARGETWIN32}
  1661. { windows guards only a few pages for stack growing, }
  1662. { so we have to access every page first }
  1663. if target_info.target=target_i386_win32 then
  1664. begin
  1665. getlabel(again);
  1666. getlabel(ok);
  1667. emitlab(again);
  1668. exprasmList.concat(Taicpu.op_const_reg(A_CMP,S_L,winstackpagesize,R_EDI));
  1669. emitjmp(C_C,ok);
  1670. exprasmList.concat(Taicpu.op_const_reg(A_SUB,S_L,winstackpagesize-4,R_ESP));
  1671. exprasmList.concat(Taicpu.op_reg(A_PUSH,S_L,R_EAX));
  1672. exprasmList.concat(Taicpu.op_const_reg(A_SUB,S_L,winstackpagesize,R_EDI));
  1673. emitjmp(C_None,again);
  1674. emitlab(ok);
  1675. exprasmList.concat(Taicpu.op_reg_reg(A_SUB,S_L,R_EDI,R_ESP));
  1676. ungetregister32(R_EDI);
  1677. { now reload EDI }
  1678. new(r);
  1679. reset_reference(r^);
  1680. r^.base:=procinfo^.framepointer;
  1681. r^.offset:=tvarsym(p).address+4+procinfo^.para_offset;
  1682. getexplicitregister32(R_EDI);
  1683. exprasmList.concat(Taicpu.op_ref_reg(A_MOV,S_L,r,R_EDI));
  1684. exprasmList.concat(Taicpu.op_reg(A_INC,S_L,R_EDI));
  1685. if (tarraydef(tvarsym(p).vartype.def).elesize<>1) then
  1686. begin
  1687. if ispowerof2(tarraydef(tvarsym(p).vartype.def).elesize, power) then
  1688. exprasmList.concat(Taicpu.op_const_reg(A_SHL,S_L,power,R_EDI))
  1689. else
  1690. exprasmList.concat(Taicpu.op_const_reg(A_IMUL,S_L,
  1691. tarraydef(tvarsym(p).vartype.def).elesize,R_EDI));
  1692. end;
  1693. end
  1694. else
  1695. {$endif NOTARGETWIN32}
  1696. exprasmList.concat(Taicpu.op_reg_reg(A_SUB,S_L,R_EDI,R_ESP));
  1697. { load destination }
  1698. exprasmList.concat(Taicpu.op_reg_reg(A_MOV,S_L,R_ESP,R_EDI));
  1699. { don't destroy the registers! }
  1700. exprasmList.concat(Taicpu.op_reg(A_PUSH,S_L,R_ECX));
  1701. exprasmList.concat(Taicpu.op_reg(A_PUSH,S_L,R_ESI));
  1702. { load count }
  1703. new(r);
  1704. reset_reference(r^);
  1705. r^.base:=procinfo^.framepointer;
  1706. r^.offset:=tvarsym(p).address+4+procinfo^.para_offset;
  1707. exprasmList.concat(Taicpu.op_ref_reg(A_MOV,S_L,r,R_ECX));
  1708. { load source }
  1709. new(r);
  1710. reset_reference(r^);
  1711. r^.base:=procinfo^.framepointer;
  1712. r^.offset:=tvarsym(p).address+procinfo^.para_offset;
  1713. exprasmList.concat(Taicpu.op_ref_reg(A_MOV,S_L,r,R_ESI));
  1714. { scheduled .... }
  1715. exprasmList.concat(Taicpu.op_reg(A_INC,S_L,R_ECX));
  1716. { calculate size }
  1717. len:=tarraydef(tvarsym(p).vartype.def).elesize;
  1718. opsize:=S_B;
  1719. if (len and 3)=0 then
  1720. begin
  1721. opsize:=S_L;
  1722. len:=len shr 2;
  1723. end
  1724. else
  1725. if (len and 1)=0 then
  1726. begin
  1727. opsize:=S_W;
  1728. len:=len shr 1;
  1729. end;
  1730. if ispowerof2(len, power) then
  1731. exprasmList.concat(Taicpu.op_const_reg(A_SHL,S_L,power,R_ECX))
  1732. else
  1733. exprasmList.concat(Taicpu.op_const_reg(A_IMUL,S_L,len,R_ECX));
  1734. exprasmList.concat(Taicpu.op_none(A_REP,S_NO));
  1735. case opsize of
  1736. S_B : exprasmList.concat(Taicpu.Op_none(A_MOVSB,S_NO));
  1737. S_W : exprasmList.concat(Taicpu.Op_none(A_MOVSW,S_NO));
  1738. S_L : exprasmList.concat(Taicpu.Op_none(A_MOVSD,S_NO));
  1739. end;
  1740. ungetregister32(R_EDI);
  1741. exprasmList.concat(Taicpu.op_reg(A_POP,S_L,R_ESI));
  1742. exprasmList.concat(Taicpu.op_reg(A_POP,S_L,R_ECX));
  1743. { patch the new address }
  1744. new(r);
  1745. reset_reference(r^);
  1746. r^.base:=procinfo^.framepointer;
  1747. r^.offset:=tvarsym(p).address+procinfo^.para_offset;
  1748. exprasmList.concat(Taicpu.op_reg_ref(A_MOV,S_L,R_ESP,r));
  1749. end
  1750. else
  1751. if is_shortstring(tvarsym(p).vartype.def) then
  1752. begin
  1753. reset_reference(href1);
  1754. href1.base:=procinfo^.framepointer;
  1755. href1.offset:=tvarsym(p).address+procinfo^.para_offset;
  1756. reset_reference(href2);
  1757. href2.base:=procinfo^.framepointer;
  1758. href2.offset:=-tvarsym(p).localvarsym.address+tvarsym(p).localvarsym.owner.address_fixup;
  1759. copyshortstring(href2,href1,tstringdef(tvarsym(p).vartype.def).len,true,false);
  1760. end
  1761. else
  1762. begin
  1763. reset_reference(href1);
  1764. href1.base:=procinfo^.framepointer;
  1765. href1.offset:=tvarsym(p).address+procinfo^.para_offset;
  1766. reset_reference(href2);
  1767. href2.base:=procinfo^.framepointer;
  1768. href2.offset:=-tvarsym(p).localvarsym.address+tvarsym(p).localvarsym.owner.address_fixup;
  1769. concatcopy(href1,href2,tvarsym(p).vartype.def.size,true,true);
  1770. end;
  1771. end;
  1772. end;
  1773. procedure inittempvariables;
  1774. var
  1775. hp : ptemprecord;
  1776. r : preference;
  1777. begin
  1778. hp:=templist;
  1779. while assigned(hp) do
  1780. begin
  1781. if hp^.temptype in [tt_ansistring,tt_freeansistring,
  1782. tt_widestring,tt_freewidestring,
  1783. tt_interfacecom] then
  1784. begin
  1785. procinfo^.flags:=procinfo^.flags or pi_needs_implicit_finally;
  1786. new(r);
  1787. reset_reference(r^);
  1788. r^.base:=procinfo^.framepointer;
  1789. r^.offset:=hp^.pos;
  1790. emit_const_ref(A_MOV,S_L,0,r);
  1791. end;
  1792. hp:=hp^.next;
  1793. end;
  1794. end;
  1795. procedure finalizetempvariables;
  1796. var
  1797. hp : ptemprecord;
  1798. hr : treference;
  1799. begin
  1800. hp:=templist;
  1801. while assigned(hp) do
  1802. begin
  1803. if hp^.temptype in [tt_ansistring,tt_freeansistring] then
  1804. begin
  1805. procinfo^.flags:=procinfo^.flags or pi_needs_implicit_finally;
  1806. reset_reference(hr);
  1807. hr.base:=procinfo^.framepointer;
  1808. hr.offset:=hp^.pos;
  1809. emitpushreferenceaddr(hr);
  1810. emitcall('FPC_ANSISTR_DECR_REF');
  1811. end
  1812. else if hp^.temptype in [tt_widestring,tt_freewidestring] then
  1813. begin
  1814. procinfo^.flags:=procinfo^.flags or pi_needs_implicit_finally;
  1815. reset_reference(hr);
  1816. hr.base:=procinfo^.framepointer;
  1817. hr.offset:=hp^.pos;
  1818. emitpushreferenceaddr(hr);
  1819. emitcall('FPC_WIDESTR_DECR_REF');
  1820. end
  1821. else if hp^.temptype=tt_interfacecom then
  1822. begin
  1823. procinfo^.flags:=procinfo^.flags or pi_needs_implicit_finally;
  1824. reset_reference(hr);
  1825. hr.base:=procinfo^.framepointer;
  1826. hr.offset:=hp^.pos;
  1827. emitpushreferenceaddr(hr);
  1828. emitcall('FPC_INTF_DECR_REF');
  1829. end;
  1830. hp:=hp^.next;
  1831. end;
  1832. end;
  1833. {$ifdef dummy}
  1834. var
  1835. ls : longint;
  1836. procedure largest_size(p : tnamedindexitem);
  1837. begin
  1838. if (tsym(p).typ=varsym) and
  1839. (tvarsym(p).getvaluesize>ls) then
  1840. ls:=tvarsym(p).getvaluesize;
  1841. end;
  1842. {$endif dummy}
  1843. procedure alignstack(alist : TAAsmoutput);
  1844. begin
  1845. {$ifdef dummy}
  1846. if (cs_optimize in aktglobalswitches) and
  1847. (aktoptprocessor in [classp5,classp6]) then
  1848. begin
  1849. ls:=0;
  1850. aktprocsym.definition.localst.foreach({$ifndef TP}@{$endif}largest_size);
  1851. if ls>=8 then
  1852. aList.insert(Taicpu.Op_const_reg(A_AND,S_L,-8,R_ESP));
  1853. end;
  1854. {$endif dummy}
  1855. end;
  1856. procedure genentrycode(alist : TAAsmoutput;make_global:boolean;
  1857. stackframe:longint;
  1858. var parasize:longint;var nostackframe:boolean;
  1859. inlined : boolean);
  1860. {
  1861. Generates the entry code for a procedure
  1862. }
  1863. var
  1864. hs : string;
  1865. {$ifdef GDB}
  1866. stab_function_name : tai_stab_function_name;
  1867. {$endif GDB}
  1868. hr : preference;
  1869. p : tsymtable;
  1870. r : treference;
  1871. oldlist,
  1872. oldexprasmlist : TAAsmoutput;
  1873. again : tasmlabel;
  1874. i : longint;
  1875. tempbuf,tempaddr : treference;
  1876. begin
  1877. oldexprasmlist:=exprasmlist;
  1878. exprasmlist:=alist;
  1879. if (not inlined) and (aktprocsym.definition.proctypeoption=potype_proginit) then
  1880. begin
  1881. emitinsertcall('FPC_INITIALIZEUNITS');
  1882. { initialize profiling for win32 }
  1883. if (target_info.target=target_I386_WIN32) and
  1884. (cs_profile in aktmoduleswitches) then
  1885. emitinsertcall('__monstartup');
  1886. { add threadvars }
  1887. oldlist:=exprasmlist;
  1888. exprasmlist:=TAAsmoutput.Create;
  1889. p:=symtablestack;
  1890. while assigned(p) do
  1891. begin
  1892. p.foreach_static({$ifndef TP}@{$endif}initialize_threadvar);
  1893. p:=p.next;
  1894. end;
  1895. oldList.insertlist(exprasmlist);
  1896. exprasmlist.free;
  1897. exprasmlist:=oldlist;
  1898. end;
  1899. {$ifdef GDB}
  1900. if (not inlined) and (cs_debuginfo in aktmoduleswitches) then
  1901. exprasmList.insert(Tai_force_line.Create);
  1902. {$endif GDB}
  1903. { a constructor needs a help procedure }
  1904. if (aktprocsym.definition.proctypeoption=potype_constructor) then
  1905. begin
  1906. if is_class(procinfo^._class) then
  1907. begin
  1908. procinfo^.flags:=procinfo^.flags or pi_needs_implicit_finally;
  1909. exprasmList.insert(Taicpu.Op_cond_sym(A_Jcc,C_Z,S_NO,faillabel));
  1910. emitinsertcall('FPC_NEW_CLASS');
  1911. end
  1912. else if is_object(procinfo^._class) then
  1913. begin
  1914. exprasmList.insert(Taicpu.Op_cond_sym(A_Jcc,C_Z,S_NO,faillabel));
  1915. emitinsertcall('FPC_HELP_CONSTRUCTOR');
  1916. getexplicitregister32(R_EDI);
  1917. exprasmList.insert(Taicpu.Op_const_reg(A_MOV,S_L,procinfo^._class.vmt_offset,R_EDI));
  1918. end
  1919. else
  1920. Internalerror(200006161);
  1921. end;
  1922. { don't load ESI, does the caller }
  1923. { we must do it for local function }
  1924. { that can be called from a foreach_static }
  1925. { of another object than self !! PM }
  1926. if assigned(procinfo^._class) and { !!!!! shouldn't we load ESI always? }
  1927. (lexlevel>normal_function_level) then
  1928. maybe_loadself;
  1929. { When message method contains self as a parameter,
  1930. we must load it into ESI }
  1931. If (po_containsself in aktprocsym.definition.procoptions) then
  1932. begin
  1933. new(hr);
  1934. reset_reference(hr^);
  1935. hr^.offset:=procinfo^.selfpointer_offset;
  1936. hr^.base:=procinfo^.framepointer;
  1937. exprasmList.insert(Taicpu.Op_ref_reg(A_MOV,S_L,hr,R_ESI));
  1938. exprasmList.insert(Tairegalloc.Alloc(R_ESI));
  1939. end;
  1940. { should we save edi,esi,ebx like C ? }
  1941. if (po_savestdregs in aktprocsym.definition.procoptions) then
  1942. begin
  1943. if (aktprocsym.definition.usedregisters and ($80 shr byte(R_EBX)))<>0 then
  1944. exprasmList.insert(Taicpu.Op_reg(A_PUSH,S_L,R_EBX));
  1945. exprasmList.insert(Taicpu.Op_reg(A_PUSH,S_L,R_ESI));
  1946. exprasmList.insert(Taicpu.Op_reg(A_PUSH,S_L,R_EDI));
  1947. end;
  1948. { for the save all registers we can simply use a pusha,popa which
  1949. push edi,esi,ebp,esp(ignored),ebx,edx,ecx,eax }
  1950. if (po_saveregisters in aktprocsym.definition.procoptions) then
  1951. begin
  1952. exprasmList.insert(Taicpu.Op_none(A_PUSHA,S_L));
  1953. end;
  1954. { omit stack frame ? }
  1955. if (not inlined) then
  1956. if (procinfo^.framepointer=stack_pointer) then
  1957. begin
  1958. CGMessage(cg_d_stackframe_omited);
  1959. nostackframe:=true;
  1960. if (aktprocsym.definition.proctypeoption in [potype_unitinit,potype_proginit,potype_unitfinalize]) then
  1961. parasize:=0
  1962. else
  1963. parasize:=aktprocsym.definition.parast.datasize+procinfo^.para_offset-4;
  1964. if stackframe<>0 then
  1965. exprasmList.insert(Taicpu.op_const_reg(A_SUB,S_L,stackframe,R_ESP));
  1966. end
  1967. else
  1968. begin
  1969. alignstack(alist);
  1970. if (aktprocsym.definition.proctypeoption in [potype_unitinit,potype_proginit,potype_unitfinalize]) then
  1971. parasize:=0
  1972. else
  1973. parasize:=aktprocsym.definition.parast.datasize+procinfo^.para_offset-8;
  1974. nostackframe:=false;
  1975. if stackframe<>0 then
  1976. begin
  1977. {$ifdef unused}
  1978. if (cs_littlesize in aktglobalswitches) and (stackframe<=65535) then
  1979. begin
  1980. if (cs_check_stack in aktlocalswitches) and
  1981. not(target_info.target in [target_386_freebsd,
  1982. target_i386_linux,target_i386_win32]) then
  1983. begin
  1984. emitinsertcall('FPC_STACKCHECK');
  1985. exprasmList.insert(Taicpu.Op_const(A_PUSH,S_L,stackframe));
  1986. end;
  1987. if cs_profile in aktmoduleswitches then
  1988. genprofilecode;
  1989. { %edi is already saved when pocdecl is used
  1990. if ((target_info.target=target_linux) or (target_info.target=target_freebsd)) and
  1991. ((aktprocsym.definition.options and poexports)<>0) then
  1992. exprasmList.insert(Taicpu.Op_reg(A_PUSH,S_L,R_EDI)); }
  1993. { ATTENTION:
  1994. never use ENTER in linux !!! (or freebsd MvdV)
  1995. the stack page fault does not support it PM }
  1996. exprasmList.insert(Taicpu.Op_const_const(A_ENTER,S_NO,stackframe,0)))
  1997. end
  1998. else
  1999. {$endif unused}
  2000. begin
  2001. {$ifndef NOTARGETWIN32}
  2002. { windows guards only a few pages for stack growing, }
  2003. { so we have to access every page first }
  2004. if (target_info.target=target_i386_win32) and
  2005. (stackframe>=winstackpagesize) then
  2006. begin
  2007. if stackframe div winstackpagesize<=5 then
  2008. begin
  2009. exprasmList.insert(Taicpu.Op_const_reg(A_SUB,S_L,stackframe-4,R_ESP));
  2010. for i:=1 to stackframe div winstackpagesize do
  2011. begin
  2012. hr:=new_reference(R_ESP,stackframe-i*winstackpagesize);
  2013. exprasmList.concat(Taicpu.op_const_ref(A_MOV,S_L,0,hr));
  2014. end;
  2015. exprasmList.concat(Taicpu.op_reg(A_PUSH,S_L,R_EAX));
  2016. end
  2017. else
  2018. begin
  2019. getlabel(again);
  2020. getexplicitregister32(R_EDI);
  2021. exprasmList.concat(Taicpu.op_const_reg(A_MOV,S_L,stackframe div winstackpagesize,R_EDI));
  2022. emitlab(again);
  2023. exprasmList.concat(Taicpu.op_const_reg(A_SUB,S_L,winstackpagesize-4,R_ESP));
  2024. exprasmList.concat(Taicpu.op_reg(A_PUSH,S_L,R_EAX));
  2025. exprasmList.concat(Taicpu.op_reg(A_DEC,S_L,R_EDI));
  2026. emitjmp(C_NZ,again);
  2027. ungetregister32(R_EDI);
  2028. exprasmList.concat(Taicpu.op_const_reg(A_SUB,S_L,stackframe mod winstackpagesize,R_ESP));
  2029. end
  2030. end
  2031. else
  2032. {$endif NOTARGETWIN32}
  2033. exprasmList.insert(Taicpu.Op_const_reg(A_SUB,S_L,stackframe,R_ESP));
  2034. if (cs_check_stack in aktlocalswitches) and
  2035. not(target_info.target in [target_i386_freebsd,
  2036. target_i386_linux,target_i386_win32]) then
  2037. begin
  2038. emitinsertcall('FPC_STACKCHECK');
  2039. exprasmList.insert(Taicpu.Op_const(A_PUSH,S_L,stackframe));
  2040. end;
  2041. if cs_profile in aktmoduleswitches then
  2042. genprofilecode;
  2043. exprasmList.insert(Taicpu.Op_reg_reg(A_MOV,S_L,R_ESP,R_EBP));
  2044. exprasmList.insert(Taicpu.Op_reg(A_PUSH,S_L,R_EBP));
  2045. end;
  2046. end { endif stackframe <> 0 }
  2047. else
  2048. begin
  2049. if cs_profile in aktmoduleswitches then
  2050. genprofilecode;
  2051. exprasmList.insert(Taicpu.Op_reg_reg(A_MOV,S_L,R_ESP,R_EBP));
  2052. exprasmList.insert(Taicpu.Op_reg(A_PUSH,S_L,R_EBP));
  2053. end;
  2054. end;
  2055. if (po_interrupt in aktprocsym.definition.procoptions) then
  2056. generate_interrupt_stackframe_entry;
  2057. { initialize return value }
  2058. if (not is_void(aktprocsym.definition.rettype.def)) and
  2059. (aktprocsym.definition.rettype.def.needs_inittable) then
  2060. begin
  2061. procinfo^.flags:=procinfo^.flags or pi_needs_implicit_finally;
  2062. reset_reference(r);
  2063. r.offset:=procinfo^.return_offset;
  2064. r.base:=procinfo^.framepointer;
  2065. initialize(aktprocsym.definition.rettype.def,r,ret_in_param(aktprocsym.definition.rettype.def));
  2066. end;
  2067. { initialisize local data like ansistrings }
  2068. case aktprocsym.definition.proctypeoption of
  2069. potype_unitinit:
  2070. begin
  2071. { using current_module.globalsymtable is hopefully }
  2072. { more robust than symtablestack and symtablestack.next }
  2073. tsymtable(current_module.globalsymtable).foreach_static({$ifndef TP}@{$endif}initialize_data);
  2074. tsymtable(current_module.localsymtable).foreach_static({$ifndef TP}@{$endif}initialize_data);
  2075. end;
  2076. { units have seperate code for initilization and finalization }
  2077. potype_unitfinalize: ;
  2078. else
  2079. aktprocsym.definition.localst.foreach_static({$ifndef TP}@{$endif}initialize_data);
  2080. end;
  2081. { initialisizes temp. ansi/wide string data }
  2082. inittempvariables;
  2083. { generate copies of call by value parameters }
  2084. if not(po_assembler in aktprocsym.definition.procoptions) and
  2085. (([pocall_cdecl,pocall_cppdecl]*aktprocsym.definition.proccalloptions)=[]) then
  2086. aktprocsym.definition.parast.foreach_static({$ifndef TP}@{$endif}copyvalueparas);
  2087. if assigned( aktprocsym.definition.parast) then
  2088. aktprocsym.definition.parast.foreach_static({$ifndef TP}@{$endif}init_paras);
  2089. { do we need an exception frame because of ansi/widestrings/interfaces ? }
  2090. if not inlined and
  2091. ((procinfo^.flags and pi_needs_implicit_finally)<>0) and
  2092. { but it's useless in init/final code of units }
  2093. not(aktprocsym.definition.proctypeoption in [potype_unitfinalize,potype_unitinit]) then
  2094. begin
  2095. usedinproc:=usedinproc or ($80 shr byte(R_EAX));
  2096. exprasmList.concat(Taicpu.op_const_reg(A_SUB,S_L,36,R_ESP));
  2097. exprasmList.concat(Taicpu.op_reg_reg(A_MOV,S_L,R_ESP,R_EDI));
  2098. reset_reference(tempaddr);
  2099. tempaddr.base:=R_EDI;
  2100. emitpushreferenceaddr(tempaddr);
  2101. reset_reference(tempbuf);
  2102. tempbuf.base:=R_EDI;
  2103. tempbuf.offset:=12;
  2104. emitpushreferenceaddr(tempbuf);
  2105. { Type of stack-frame must be pushed}
  2106. exprasmList.concat(Taicpu.op_const(A_PUSH,S_L,1));
  2107. emitcall('FPC_PUSHEXCEPTADDR');
  2108. exprasmList.concat(Taicpu.op_reg(A_PUSH,S_L,R_EAX));
  2109. emitcall('FPC_SETJMP');
  2110. exprasmList.concat(Taicpu.op_reg(A_PUSH,S_L,R_EAX));
  2111. exprasmList.concat(Taicpu.op_reg_reg(A_TEST,S_L,R_EAX,R_EAX));
  2112. emitjmp(C_NE,aktexitlabel);
  2113. { probably we've to reload self here }
  2114. maybe_loadself;
  2115. end;
  2116. if not inlined then
  2117. begin
  2118. if (cs_profile in aktmoduleswitches) or
  2119. (aktprocsym.definition.owner.symtabletype=globalsymtable) or
  2120. (assigned(procinfo^._class) and (procinfo^._class.owner.symtabletype=globalsymtable)) then
  2121. make_global:=true;
  2122. hs:=aktprocsym.definition.aliasnames.getfirst;
  2123. {$ifdef GDB}
  2124. if (cs_debuginfo in aktmoduleswitches) and target_info.use_function_relative_addresses then
  2125. stab_function_name := Tai_stab_function_name.Create(strpnew(hs));
  2126. {$EndIf GDB}
  2127. while hs<>'' do
  2128. begin
  2129. if make_global then
  2130. exprasmList.insert(Tai_symbol.Createname_global(hs,0))
  2131. else
  2132. exprasmList.insert(Tai_symbol.Createname(hs,0));
  2133. {$ifdef GDB}
  2134. if (cs_debuginfo in aktmoduleswitches) and
  2135. target_info.use_function_relative_addresses then
  2136. exprasmList.insert(Tai_stab_function_name.Create(strpnew(hs)));
  2137. {$endif GDB}
  2138. hs:=aktprocsym.definition.aliasnames.getfirst;
  2139. end;
  2140. if make_global or ((procinfo^.flags and pi_is_global) <> 0) then
  2141. aktprocsym.is_global := True;
  2142. {$ifdef GDB}
  2143. if (cs_debuginfo in aktmoduleswitches) then
  2144. begin
  2145. if target_info.use_function_relative_addresses then
  2146. exprasmList.insert(stab_function_name);
  2147. exprasmList.insert(Tai_stabs.Create(aktprocsym.stabstring));
  2148. aktprocsym.isstabwritten:=true;
  2149. end;
  2150. {$endif GDB}
  2151. { Align, gprof uses 16 byte granularity }
  2152. if (cs_profile in aktmoduleswitches) then
  2153. exprasmList.insert(Tai_align.Create_op(16,$90))
  2154. else
  2155. exprasmList.insert(Tai_align.Create(aktalignment.procalign));
  2156. end;
  2157. if inlined then
  2158. load_regvars(exprasmlist,nil);
  2159. exprasmlist:=oldexprasmlist;
  2160. end;
  2161. procedure handle_return_value(inlined : boolean;var uses_eax,uses_edx : boolean);
  2162. var
  2163. hr : preference;
  2164. op : Tasmop;
  2165. s : Topsize;
  2166. begin
  2167. if not is_void(aktprocsym.definition.rettype.def) then
  2168. begin
  2169. {if ((procinfo^.flags and pi_operator)<>0) and
  2170. assigned(otsym) then
  2171. procinfo^.funcret_is_valid:=
  2172. procinfo^.funcret_is_valid or (otsym.refs>0);}
  2173. if (tfuncretsym(aktprocsym.definition.funcretsym).funcretstate<>vs_assigned) and not inlined { and
  2174. ((procinfo^.flags and pi_uses_asm)=0)} then
  2175. CGMessage(sym_w_function_result_not_set);
  2176. hr:=new_reference(procinfo^.framepointer,procinfo^.return_offset);
  2177. if (aktprocsym.definition.rettype.def.deftype in [orddef,enumdef]) then
  2178. begin
  2179. uses_eax:=true;
  2180. exprasmList.concat(Tairegalloc.Alloc(R_EAX));
  2181. case aktprocsym.definition.rettype.def.size of
  2182. 8:
  2183. begin
  2184. emit_ref_reg(A_MOV,S_L,hr,R_EAX);
  2185. hr:=new_reference(procinfo^.framepointer,procinfo^.return_offset+4);
  2186. exprasmList.concat(Tairegalloc.Alloc(R_EDX));
  2187. emit_ref_reg(A_MOV,S_L,hr,R_EDX);
  2188. uses_edx:=true;
  2189. end;
  2190. 4:
  2191. emit_ref_reg(A_MOV,S_L,hr,R_EAX);
  2192. 2:
  2193. emit_ref_reg(A_MOV,S_W,hr,R_AX);
  2194. 1:
  2195. emit_ref_reg(A_MOV,S_B,hr,R_AL);
  2196. end;
  2197. end
  2198. else
  2199. if ret_in_acc(aktprocsym.definition.rettype.def) then
  2200. begin
  2201. uses_eax:=true;
  2202. exprasmList.concat(Tairegalloc.Alloc(R_EAX));
  2203. emit_ref_reg(A_MOV,S_L,hr,R_EAX);
  2204. end
  2205. else
  2206. if (aktprocsym.definition.rettype.def.deftype=floatdef) then
  2207. begin
  2208. floatloadops(tfloatdef(aktprocsym.definition.rettype.def).typ,op,s);
  2209. exprasmList.concat(Taicpu.Op_ref(op,s,hr));
  2210. end
  2211. else
  2212. dispose(hr);
  2213. end
  2214. end;
  2215. procedure handle_fast_exit_return_value;
  2216. var
  2217. hr : preference;
  2218. op : Tasmop;
  2219. s : Topsize;
  2220. begin
  2221. if not is_void(aktprocsym.definition.rettype.def) then
  2222. begin
  2223. hr:=new_reference(procinfo^.framepointer,procinfo^.return_offset);
  2224. if (aktprocsym.definition.rettype.def.deftype in [orddef,enumdef]) then
  2225. begin
  2226. case aktprocsym.definition.rettype.def.size of
  2227. 8:
  2228. begin
  2229. emit_reg_ref(A_MOV,S_L,R_EAX,hr);
  2230. hr:=new_reference(procinfo^.framepointer,procinfo^.return_offset+4);
  2231. emit_reg_ref(A_MOV,S_L,R_EDX,hr);
  2232. end;
  2233. 4:
  2234. emit_reg_ref(A_MOV,S_L,R_EAX,hr);
  2235. 2:
  2236. emit_reg_ref(A_MOV,S_W,R_AX,hr);
  2237. 1:
  2238. emit_reg_ref(A_MOV,S_B,R_AL,hr);
  2239. end;
  2240. end
  2241. else
  2242. if ret_in_acc(aktprocsym.definition.rettype.def) then
  2243. begin
  2244. emit_reg_ref(A_MOV,S_L,R_EAX,hr);
  2245. end
  2246. else
  2247. if (aktprocsym.definition.rettype.def.deftype=floatdef) then
  2248. begin
  2249. floatstoreops(tfloatdef(aktprocsym.definition.rettype.def).typ,op,s);
  2250. exprasmlist.concat(taicpu.op_ref(op,s,hr));
  2251. end
  2252. else
  2253. dispose(hr);
  2254. end
  2255. end;
  2256. procedure genexitcode(alist : TAAsmoutput;parasize:longint;nostackframe,inlined:boolean);
  2257. var
  2258. {$ifdef GDB}
  2259. mangled_length : longint;
  2260. p : pchar;
  2261. st : string[2];
  2262. {$endif GDB}
  2263. stabsendlabel,nofinal,okexitlabel,
  2264. noreraiselabel,nodestroycall : tasmlabel;
  2265. hr : treference;
  2266. uses_eax,uses_edx,uses_esi : boolean;
  2267. oldexprasmlist : TAAsmoutput;
  2268. ai : taicpu;
  2269. pd : tprocdef;
  2270. begin
  2271. oldexprasmlist:=exprasmlist;
  2272. exprasmlist:=alist;
  2273. if aktexit2label.is_used and
  2274. ((procinfo^.flags and (pi_needs_implicit_finally or pi_uses_exceptions)) <> 0) then
  2275. begin
  2276. exprasmlist.concat(taicpu.op_sym(A_JMP,S_NO,aktexitlabel));
  2277. exprasmlist.concat(tai_label.create(aktexit2label));
  2278. handle_fast_exit_return_value;
  2279. end;
  2280. if aktexitlabel.is_used then
  2281. exprasmList.concat(Tai_label.Create(aktexitlabel));
  2282. { call the destructor help procedure }
  2283. if (aktprocsym.definition.proctypeoption=potype_destructor) and
  2284. assigned(procinfo^._class) then
  2285. begin
  2286. if is_class(procinfo^._class) then
  2287. begin
  2288. emitinsertcall('FPC_DISPOSE_CLASS');
  2289. end
  2290. else if is_object(procinfo^._class) then
  2291. begin
  2292. emitinsertcall('FPC_HELP_DESTRUCTOR');
  2293. getexplicitregister32(R_EDI);
  2294. exprasmList.insert(Taicpu.Op_const_reg(A_MOV,S_L,procinfo^._class.vmt_offset,R_EDI));
  2295. { must the object be finalized ? }
  2296. if procinfo^._class.needs_inittable then
  2297. begin
  2298. getlabel(nofinal);
  2299. exprasmList.insert(Tai_label.Create(nofinal));
  2300. emitinsertcall('FPC_FINALIZE');
  2301. ungetregister32(R_EDI);
  2302. exprasmList.insert(Taicpu.Op_reg(A_PUSH,S_L,R_ESI));
  2303. exprasmList.insert(Taicpu.Op_sym(A_PUSH,S_L,procinfo^._class.get_inittable_label));
  2304. ai:=Taicpu.Op_sym(A_Jcc,S_NO,nofinal);
  2305. ai.SetCondition(C_Z);
  2306. exprasmList.insert(ai);
  2307. reset_reference(hr);
  2308. hr.base:=R_EBP;
  2309. hr.offset:=8;
  2310. exprasmList.insert(Taicpu.Op_const_ref(A_CMP,S_L,0,newreference(hr)));
  2311. end;
  2312. end
  2313. else
  2314. begin
  2315. Internalerror(200006161);
  2316. end;
  2317. end;
  2318. { finalize temporary data }
  2319. finalizetempvariables;
  2320. { finalize local data like ansistrings}
  2321. case aktprocsym.definition.proctypeoption of
  2322. potype_unitfinalize:
  2323. begin
  2324. { using current_module.globalsymtable is hopefully }
  2325. { more robust than symtablestack and symtablestack.next }
  2326. tsymtable(current_module.globalsymtable).foreach_static({$ifndef TP}@{$endif}finalize_data);
  2327. tsymtable(current_module.localsymtable).foreach_static({$ifndef TP}@{$endif}finalize_data);
  2328. end;
  2329. { units have seperate code for initialization and finalization }
  2330. potype_unitinit: ;
  2331. else
  2332. aktprocsym.definition.localst.foreach_static({$ifndef TP}@{$endif}finalize_data);
  2333. end;
  2334. { finalize paras data }
  2335. if assigned(aktprocsym.definition.parast) then
  2336. aktprocsym.definition.parast.foreach_static({$ifndef TP}@{$endif}final_paras);
  2337. { do we need to handle exceptions because of ansi/widestrings ? }
  2338. if not inlined and
  2339. ((procinfo^.flags and pi_needs_implicit_finally)<>0) and
  2340. { but it's useless in init/final code of units }
  2341. not(aktprocsym.definition.proctypeoption in [potype_unitfinalize,potype_unitinit]) then
  2342. begin
  2343. { the exception helper routines modify all registers }
  2344. aktprocsym.definition.usedregisters:=$ff;
  2345. getlabel(noreraiselabel);
  2346. emitcall('FPC_POPADDRSTACK');
  2347. exprasmList.concat(Tairegalloc.Alloc(R_EAX));
  2348. exprasmList.concat(Taicpu.op_reg(A_POP,S_L,R_EAX));
  2349. exprasmList.concat(Taicpu.op_reg_reg(A_TEST,S_L,R_EAX,R_EAX));
  2350. ungetregister32(R_EAX);
  2351. emitjmp(C_E,noreraiselabel);
  2352. if (aktprocsym.definition.proctypeoption=potype_constructor) then
  2353. begin
  2354. if assigned(procinfo^._class) then
  2355. begin
  2356. pd:=procinfo^._class.searchdestructor;
  2357. if assigned(pd) then
  2358. begin
  2359. getlabel(nodestroycall);
  2360. emit_const_ref(A_CMP,S_L,0,new_reference(procinfo^.framepointer,
  2361. procinfo^.selfpointer_offset));
  2362. emitjmp(C_E,nodestroycall);
  2363. if is_class(procinfo^._class) then
  2364. begin
  2365. emit_const(A_PUSH,S_L,1);
  2366. emit_reg(A_PUSH,S_L,R_ESI);
  2367. end
  2368. else if is_object(procinfo^._class) then
  2369. begin
  2370. emit_reg(A_PUSH,S_L,R_ESI);
  2371. emit_sym(A_PUSH,S_L,newasmsymbol(procinfo^._class.vmt_mangledname));
  2372. end
  2373. else
  2374. begin
  2375. Internalerror(200006161);
  2376. end;
  2377. if (po_virtualmethod in pd.procoptions) then
  2378. begin
  2379. emit_ref_reg(A_MOV,S_L,new_reference(R_ESI,0),R_EDI);
  2380. emit_ref(A_CALL,S_NO,new_reference(R_EDI,procinfo^._class.vmtmethodoffset(pd.extnumber)));
  2381. end
  2382. else
  2383. emitcall(pd.mangledname);
  2384. { not necessary because the result is never assigned in the
  2385. case of an exception (FK)
  2386. emit_const_reg(A_MOV,S_L,0,R_ESI);
  2387. emit_const_ref(A_MOV,S_L,0,new_reference(procinfo^.framepointer,8));
  2388. }
  2389. emitlab(nodestroycall);
  2390. end;
  2391. end
  2392. end
  2393. else
  2394. { must be the return value finalized before reraising the exception? }
  2395. if (not is_void(aktprocsym.definition.rettype.def)) and
  2396. (aktprocsym.definition.rettype.def.needs_inittable) and
  2397. ((aktprocsym.definition.rettype.def.deftype<>objectdef) or
  2398. not is_class(aktprocsym.definition.rettype.def)) then
  2399. begin
  2400. reset_reference(hr);
  2401. hr.offset:=procinfo^.return_offset;
  2402. hr.base:=procinfo^.framepointer;
  2403. finalize(aktprocsym.definition.rettype.def,hr,ret_in_param(aktprocsym.definition.rettype.def));
  2404. end;
  2405. emitcall('FPC_RERAISE');
  2406. emitlab(noreraiselabel);
  2407. end;
  2408. { call __EXIT for main program }
  2409. if (not DLLsource) and (not inlined) and (aktprocsym.definition.proctypeoption=potype_proginit) then
  2410. begin
  2411. emitcall('FPC_DO_EXIT');
  2412. end;
  2413. { handle return value }
  2414. uses_eax:=false;
  2415. uses_edx:=false;
  2416. uses_esi:=false;
  2417. if not(po_assembler in aktprocsym.definition.procoptions) then
  2418. if (aktprocsym.definition.proctypeoption<>potype_constructor) then
  2419. handle_return_value(inlined,uses_eax,uses_edx)
  2420. else
  2421. begin
  2422. { successful constructor deletes the zero flag }
  2423. { and returns self in eax }
  2424. { eax must be set to zero if the allocation failed !!! }
  2425. getlabel(okexitlabel);
  2426. emitjmp(C_NONE,okexitlabel);
  2427. emitlab(faillabel);
  2428. if is_class(procinfo^._class) then
  2429. begin
  2430. emit_ref_reg(A_MOV,S_L,new_reference(procinfo^.framepointer,8),R_ESI);
  2431. emitcall('FPC_HELP_FAIL_CLASS');
  2432. end
  2433. else if is_object(procinfo^._class) then
  2434. begin
  2435. emit_ref_reg(A_MOV,S_L,new_reference(procinfo^.framepointer,12),R_ESI);
  2436. getexplicitregister32(R_EDI);
  2437. emit_const_reg(A_MOV,S_L,procinfo^._class.vmt_offset,R_EDI);
  2438. emitcall('FPC_HELP_FAIL');
  2439. ungetregister32(R_EDI);
  2440. end
  2441. else
  2442. Internalerror(200006161);
  2443. emitlab(okexitlabel);
  2444. { for classes this is done after the call to }
  2445. { AfterConstruction }
  2446. if is_object(procinfo^._class) then
  2447. begin
  2448. exprasmList.concat(Tairegalloc.Alloc(R_EAX));
  2449. emit_reg_reg(A_MOV,S_L,R_ESI,R_EAX);
  2450. uses_eax:=true;
  2451. end;
  2452. emit_reg_reg(A_TEST,S_L,R_ESI,R_ESI);
  2453. uses_esi:=true;
  2454. end;
  2455. if aktexit2label.is_used and not aktexit2label.is_set then
  2456. emitlab(aktexit2label);
  2457. if ((cs_debuginfo in aktmoduleswitches) and not inlined) then
  2458. begin
  2459. getlabel(stabsendlabel);
  2460. emitlab(stabsendlabel);
  2461. end;
  2462. { gives problems for long mangled names }
  2463. {List.concat(Tai_symbol.Create(aktprocsym.definition.mangledname+'_end'));}
  2464. { should we restore edi ? }
  2465. { for all i386 gcc implementations }
  2466. if (po_savestdregs in aktprocsym.definition.procoptions) then
  2467. begin
  2468. if (aktprocsym.definition.usedregisters and ($80 shr byte(R_EBX)))<>0 then
  2469. exprasmList.concat(Taicpu.Op_reg(A_POP,S_L,R_EBX));
  2470. exprasmList.concat(Taicpu.Op_reg(A_POP,S_L,R_ESI));
  2471. exprasmList.concat(Taicpu.Op_reg(A_POP,S_L,R_EDI));
  2472. { here we could reset R_EBX
  2473. but that is risky because it only works
  2474. if genexitcode is called after genentrycode
  2475. so lets skip this for the moment PM
  2476. aktprocsym.definition.usedregisters:=
  2477. aktprocsym.definition.usedregisters or not ($80 shr byte(R_EBX));
  2478. }
  2479. end;
  2480. { for the save all registers we can simply use a pusha,popa which
  2481. push edi,esi,ebp,esp(ignored),ebx,edx,ecx,eax }
  2482. if (po_saveregisters in aktprocsym.definition.procoptions) then
  2483. begin
  2484. if uses_esi then
  2485. exprasmList.concat(Taicpu.Op_reg_ref(A_MOV,S_L,R_ESI,new_reference(R_ESP,4)));
  2486. if uses_edx then
  2487. exprasmList.concat(Taicpu.Op_reg_ref(A_MOV,S_L,R_EDX,new_reference(R_ESP,20)));
  2488. if uses_eax then
  2489. exprasmList.concat(Taicpu.Op_reg_ref(A_MOV,S_L,R_EAX,new_reference(R_ESP,28)));
  2490. exprasmList.concat(Taicpu.Op_none(A_POPA,S_L));
  2491. { We add a NOP because of the 386DX CPU bugs with POPAD }
  2492. exprasmlist.concat(taicpu.op_none(A_NOP,S_L));
  2493. end;
  2494. if not(nostackframe) then
  2495. begin
  2496. if not inlined then
  2497. exprasmList.concat(Taicpu.Op_none(A_LEAVE,S_NO));
  2498. end
  2499. else
  2500. begin
  2501. if (gettempsize<>0) and not inlined then
  2502. exprasmList.insert(Taicpu.op_const_reg(A_ADD,S_L,gettempsize,R_ESP));
  2503. end;
  2504. { parameters are limited to 65535 bytes because }
  2505. { ret allows only imm16 }
  2506. if (parasize>65535) and not(pocall_clearstack in aktprocsym.definition.proccalloptions) then
  2507. CGMessage(cg_e_parasize_too_big);
  2508. { at last, the return is generated }
  2509. if not inlined then
  2510. if (po_interrupt in aktprocsym.definition.procoptions) then
  2511. begin
  2512. if uses_esi then
  2513. exprasmList.concat(Taicpu.Op_reg_ref(A_MOV,S_L,R_ESI,new_reference(R_ESP,16)));
  2514. if uses_edx then
  2515. begin
  2516. exprasmList.concat(Tairegalloc.Alloc(R_EAX));
  2517. exprasmList.concat(Taicpu.Op_reg_ref(A_MOV,S_L,R_EDX,new_reference(R_ESP,12)));
  2518. end;
  2519. if uses_eax then
  2520. begin
  2521. exprasmList.concat(Tairegalloc.Alloc(R_EAX));
  2522. exprasmList.concat(Taicpu.Op_reg_ref(A_MOV,S_L,R_EAX,new_reference(R_ESP,0)));
  2523. end;
  2524. generate_interrupt_stackframe_exit;
  2525. end
  2526. else
  2527. begin
  2528. {Routines with the poclearstack flag set use only a ret.}
  2529. { also routines with parasize=0 }
  2530. if (pocall_clearstack in aktprocsym.definition.proccalloptions) then
  2531. begin
  2532. {$ifndef OLD_C_STACK}
  2533. { complex return values are removed from stack in C code PM }
  2534. if ret_in_param(aktprocsym.definition.rettype.def) then
  2535. exprasmList.concat(Taicpu.Op_const(A_RET,S_NO,4))
  2536. else
  2537. {$endif not OLD_C_STACK}
  2538. exprasmList.concat(Taicpu.Op_none(A_RET,S_NO));
  2539. end
  2540. else if (parasize=0) then
  2541. exprasmList.concat(Taicpu.Op_none(A_RET,S_NO))
  2542. else
  2543. exprasmList.concat(Taicpu.Op_const(A_RET,S_NO,parasize));
  2544. end;
  2545. if not inlined then
  2546. exprasmList.concat(Tai_symbol_end.Createname(aktprocsym.definition.mangledname));
  2547. {$ifdef GDB}
  2548. if (cs_debuginfo in aktmoduleswitches) and not inlined then
  2549. begin
  2550. aktprocsym.concatstabto(exprasmlist);
  2551. if assigned(procinfo^._class) then
  2552. if (not assigned(procinfo^.parent) or
  2553. not assigned(procinfo^.parent^._class)) then
  2554. begin
  2555. if (po_classmethod in aktprocsym.definition.procoptions) or
  2556. ((po_virtualmethod in aktprocsym.definition.procoptions) and
  2557. (potype_constructor=aktprocsym.definition.proctypeoption)) or
  2558. (po_staticmethod in aktprocsym.definition.procoptions) then
  2559. begin
  2560. exprasmList.concat(Tai_stabs.Create(strpnew(
  2561. '"pvmt:p'+tstoreddef(pvmttype.def).numberstring+'",'+
  2562. tostr(N_tsym)+',0,0,'+tostr(procinfo^.selfpointer_offset))));
  2563. end
  2564. else
  2565. begin
  2566. if not(is_class(procinfo^._class)) then
  2567. st:='v'
  2568. else
  2569. st:='p';
  2570. exprasmList.concat(Tai_stabs.Create(strpnew(
  2571. '"$t:'+st+procinfo^._class.numberstring+'",'+
  2572. tostr(N_tsym)+',0,0,'+tostr(procinfo^.selfpointer_offset))));
  2573. end;
  2574. end
  2575. else
  2576. begin
  2577. if not is_class(procinfo^._class) then
  2578. st:='*'
  2579. else
  2580. st:='';
  2581. exprasmList.concat(Tai_stabs.Create(strpnew(
  2582. '"$t:r'+st+procinfo^._class.numberstring+'",'+
  2583. tostr(N_RSYM)+',0,0,'+tostr(GDB_i386index[R_ESI]))));
  2584. end;
  2585. { define calling EBP as pseudo local var PM }
  2586. { this enables test if the function is a local one !! }
  2587. if assigned(procinfo^.parent) and (lexlevel>normal_function_level) then
  2588. exprasmList.concat(Tai_stabs.Create(strpnew(
  2589. '"parent_ebp:'+tstoreddef(voidpointertype.def).numberstring+'",'+
  2590. tostr(N_LSYM)+',0,0,'+tostr(procinfo^.framepointer_offset))));
  2591. if (not is_void(aktprocsym.definition.rettype.def)) then
  2592. begin
  2593. if ret_in_param(aktprocsym.definition.rettype.def) then
  2594. exprasmList.concat(Tai_stabs.Create(strpnew(
  2595. '"'+aktprocsym.name+':X*'+tstoreddef(aktprocsym.definition.rettype.def).numberstring+'",'+
  2596. tostr(N_tsym)+',0,0,'+tostr(procinfo^.return_offset))))
  2597. else
  2598. exprasmList.concat(Tai_stabs.Create(strpnew(
  2599. '"'+aktprocsym.name+':X'+tstoreddef(aktprocsym.definition.rettype.def).numberstring+'",'+
  2600. tostr(N_tsym)+',0,0,'+tostr(procinfo^.return_offset))));
  2601. if (m_result in aktmodeswitches) then
  2602. if ret_in_param(aktprocsym.definition.rettype.def) then
  2603. exprasmList.concat(Tai_stabs.Create(strpnew(
  2604. '"RESULT:X*'+tstoreddef(aktprocsym.definition.rettype.def).numberstring+'",'+
  2605. tostr(N_tsym)+',0,0,'+tostr(procinfo^.return_offset))))
  2606. else
  2607. exprasmList.concat(Tai_stabs.Create(strpnew(
  2608. '"RESULT:X'+tstoreddef(aktprocsym.definition.rettype.def).numberstring+'",'+
  2609. tostr(N_tsym)+',0,0,'+tostr(procinfo^.return_offset))));
  2610. end;
  2611. mangled_length:=length(aktprocsym.definition.mangledname);
  2612. getmem(p,2*mangled_length+50);
  2613. strpcopy(p,'192,0,0,');
  2614. strpcopy(strend(p),aktprocsym.definition.mangledname);
  2615. if (target_info.use_function_relative_addresses) then
  2616. begin
  2617. strpcopy(strend(p),'-');
  2618. strpcopy(strend(p),aktprocsym.definition.mangledname);
  2619. end;
  2620. exprasmList.concat(Tai_stabn.Create(strnew(p)));
  2621. {List.concat(Tai_stabn.Create(strpnew('192,0,0,'
  2622. +aktprocsym.definition.mangledname))));
  2623. p[0]:='2';p[1]:='2';p[2]:='4';
  2624. strpcopy(strend(p),'_end');}
  2625. strpcopy(p,'224,0,0,'+stabsendlabel.name);
  2626. if (target_info.use_function_relative_addresses) then
  2627. begin
  2628. strpcopy(strend(p),'-');
  2629. strpcopy(strend(p),aktprocsym.definition.mangledname);
  2630. end;
  2631. exprasmList.concatlist(withdebuglist);
  2632. exprasmList.concat(Tai_stabn.Create(strnew(p)));
  2633. { strpnew('224,0,0,'
  2634. +aktprocsym.definition.mangledname+'_end'))));}
  2635. freemem(p,2*mangled_length+50);
  2636. end;
  2637. {$endif GDB}
  2638. if inlined then
  2639. cleanup_regvars(exprasmlist);
  2640. exprasmlist:=oldexprasmlist;
  2641. end;
  2642. procedure genimplicitunitfinal(alist : TAAsmoutput);
  2643. begin
  2644. { using current_module.globalsymtable is hopefully }
  2645. { more robust than symtablestack and symtablestack.next }
  2646. tsymtable(current_module.globalsymtable).foreach_static({$ifndef TP}@{$endif}finalize_data);
  2647. tsymtable(current_module.localsymtable).foreach_static({$ifndef TP}@{$endif}finalize_data);
  2648. exprasmList.insert(Tai_symbol.Createname_global('FINALIZE$$'+current_module.modulename^,0));
  2649. exprasmList.insert(Tai_symbol.Createname_global(target_info.cprefix+current_module.modulename^+'_finalize',0));
  2650. {$ifdef GDB}
  2651. if (cs_debuginfo in aktmoduleswitches) and
  2652. target_info.use_function_relative_addresses then
  2653. exprasmList.insert(Tai_stab_function_name.Create(strpnew('FINALIZE$$'+current_module.modulename^)));
  2654. {$endif GDB}
  2655. exprasmList.concat(Taicpu.Op_none(A_RET,S_NO));
  2656. aList.concatlist(exprasmlist);
  2657. end;
  2658. procedure genimplicitunitinit(alist : TAAsmoutput);
  2659. begin
  2660. { using current_module.globalsymtable is hopefully }
  2661. { more robust than symtablestack and symtablestack.next }
  2662. tsymtable(current_module.globalsymtable).foreach_static({$ifndef TP}@{$endif}finalize_data);
  2663. tsymtable(current_module.localsymtable).foreach_static({$ifndef TP}@{$endif}finalize_data);
  2664. exprasmList.insert(Tai_symbol.Createname_global('INIT$$'+current_module.modulename^,0));
  2665. exprasmList.insert(Tai_symbol.Createname_global(target_info.cprefix+current_module.modulename^+'_init',0));
  2666. {$ifdef GDB}
  2667. if (cs_debuginfo in aktmoduleswitches) and
  2668. target_info.use_function_relative_addresses then
  2669. exprasmList.insert(Tai_stab_function_name.Create(strpnew('INIT$$'+current_module.modulename^)));
  2670. {$endif GDB}
  2671. exprasmList.concat(Taicpu.Op_none(A_RET,S_NO));
  2672. aList.concatlist(exprasmlist);
  2673. end;
  2674. {$ifdef test_dest_loc}
  2675. procedure mov_reg_to_dest(p : ptree; s : topsize; reg : tregister);
  2676. begin
  2677. if (dest_loc.loc=LOC_CREGISTER) or (dest_loc.loc=LOC_REGISTER) then
  2678. begin
  2679. emit_reg_reg(A_MOV,s,reg,dest_loc.register);
  2680. set_location(p^.location,dest_loc);
  2681. in_dest_loc:=true;
  2682. end
  2683. else
  2684. if (dest_loc.loc=LOC_REFERENCE) or (dest_loc.loc=LOC_MEM) then
  2685. begin
  2686. exprasmList.concat(Taicpu.Op_reg_ref(A_MOV,s,reg,newreference(dest_loc.reference)));
  2687. set_location(p^.location,dest_loc);
  2688. in_dest_loc:=true;
  2689. end
  2690. else
  2691. internalerror(20080);
  2692. end;
  2693. {$endif test_dest_loc}
  2694. end.
  2695. {
  2696. $Log$
  2697. Revision 1.28 2001-08-07 18:47:13 peter
  2698. * merged netbsd start
  2699. * profile for win32
  2700. Revision 1.27 2001/08/06 21:40:49 peter
  2701. * funcret moved from tprocinfo to tprocdef
  2702. Revision 1.26 2001/07/30 20:59:28 peter
  2703. * m68k updates from v10 merged
  2704. Revision 1.25 2001/07/01 20:16:18 peter
  2705. * alignmentinfo record added
  2706. * -Oa argument supports more alignment settings that can be specified
  2707. per type: PROC,LOOP,VARMIN,VARMAX,CONSTMIN,CONSTMAX,RECORDMIN
  2708. RECORDMAX,LOCALMIN,LOCALMAX. It is possible to set the mimimum
  2709. required alignment and the maximum usefull alignment. The final
  2710. alignment will be choosen per variable size dependent on these
  2711. settings
  2712. Revision 1.24 2001/05/27 14:30:55 florian
  2713. + some widestring stuff added
  2714. Revision 1.23 2001/04/21 13:33:16 peter
  2715. * move winstackpagesize const to cgai386 to remove uses t_win32
  2716. Revision 1.22 2001/04/21 12:05:32 peter
  2717. * add nop after popa (merged)
  2718. Revision 1.21 2001/04/18 22:02:00 peter
  2719. * registration of targets and assemblers
  2720. Revision 1.20 2001/04/13 01:22:17 peter
  2721. * symtable change to classes
  2722. * range check generation and errors fixed, make cycle DEBUG=1 works
  2723. * memory leaks fixed
  2724. Revision 1.19 2001/04/05 21:33:07 peter
  2725. * fast exit fix merged
  2726. Revision 1.18 2001/04/02 21:20:35 peter
  2727. * resulttype rewrite
  2728. Revision 1.17 2001/01/05 17:36:58 florian
  2729. * the info about exception frames is stored now on the stack
  2730. instead on the heap
  2731. Revision 1.16 2000/12/25 00:07:31 peter
  2732. + new tlinkedlist class (merge of old tstringqueue,tcontainer and
  2733. tlinkedlist objects)
  2734. Revision 1.15 2000/12/05 11:44:32 jonas
  2735. + new integer regvar handling, should be much more efficient
  2736. Revision 1.14 2000/11/29 00:30:43 florian
  2737. * unused units removed from uses clause
  2738. * some changes for widestrings
  2739. Revision 1.13 2000/11/28 00:28:07 pierre
  2740. * stabs fixing
  2741. Revision 1.12 2000/11/22 15:12:06 jonas
  2742. * fixed inline-related problems (partially "merges")
  2743. Revision 1.11 2000/11/17 10:30:24 florian
  2744. * passing interfaces as parameters fixed
  2745. Revision 1.10 2000/11/07 23:40:48 florian
  2746. + AfterConstruction and BeforeDestruction impemented
  2747. Revision 1.9 2000/11/06 23:49:20 florian
  2748. * fixed init_paras call
  2749. Revision 1.8 2000/11/06 23:15:01 peter
  2750. * added copyvaluepara call again
  2751. Revision 1.7 2000/11/04 14:25:23 florian
  2752. + merged Attila's changes for interfaces, not tested yet
  2753. Revision 1.6 2000/10/31 22:02:55 peter
  2754. * symtable splitted, no real code changes
  2755. Revision 1.5 2000/10/24 22:23:04 peter
  2756. * emitcall -> emitinsertcall for profiling (merged)
  2757. Revision 1.4 2000/10/24 12:47:45 jonas
  2758. * allocate registers which hold function result
  2759. Revision 1.3 2000/10/24 08:54:25 michael
  2760. + Extra patch from peter
  2761. Revision 1.2 2000/10/24 07:20:03 pierre
  2762. * fix for bug 1193 (merged)
  2763. Revision 1.1 2000/10/15 09:47:42 peter
  2764. * moved to i386/
  2765. Revision 1.19 2000/10/14 10:14:46 peter
  2766. * moehrendorf oct 2000 rewrite
  2767. Revision 1.18 2000/10/10 14:55:28 jonas
  2768. * added missing regallocs for edi in emit_mov_ref_reg64 (merged)
  2769. Revision 1.17 2000/10/01 19:48:23 peter
  2770. * lot of compile updates for cg11
  2771. Revision 1.16 2000/09/30 16:08:45 peter
  2772. * more cg11 updates
  2773. Revision 1.15 2000/09/24 15:06:12 peter
  2774. * use defines.inc
  2775. Revision 1.14 2000/09/16 12:22:52 peter
  2776. * freebsd support merged
  2777. Revision 1.13 2000/08/27 16:11:49 peter
  2778. * moved some util functions from globals,cobjects to cutils
  2779. * splitted files into finput,fmodule
  2780. Revision 1.12 2000/08/24 19:07:54 peter
  2781. * don't initialize if localvarsym is set because that varsym will
  2782. already be initialized
  2783. * first initialize local data before copy of value para's (merged)
  2784. Revision 1.11 2000/08/19 20:09:33 peter
  2785. * check size after checking openarray in push_value_para (merged)
  2786. Revision 1.10 2000/08/16 13:06:06 florian
  2787. + support of 64 bit integer constants
  2788. Revision 1.9 2000/08/10 18:42:03 peter
  2789. * fixed for constants in emit_push_mem_size for go32v2 (merged)
  2790. Revision 1.8 2000/08/07 11:29:40 jonas
  2791. + emit_push_mem_size() which pushes a value in memory of a certain size
  2792. * pushsetelement() and pushvaluepara() use this new procedure, because
  2793. otherwise they could sometimes try to push data past the end of the
  2794. heap, causing a crash
  2795. (merged from fixes branch)
  2796. Revision 1.7 2000/08/03 13:17:25 jonas
  2797. + allow regvars to be used inside inlined procs, which required the
  2798. following changes:
  2799. + load regvars in genentrycode/free them in genexitcode (cgai386)
  2800. * moved all regvar related code to new regvars unit
  2801. + added pregvarinfo type to hcodegen
  2802. + added regvarinfo field to tprocinfo (symdef/symdefh)
  2803. * deallocate the regvars of the caller in secondprocinline before
  2804. inlining the called procedure and reallocate them afterwards
  2805. Revision 1.6 2000/08/02 08:05:04 jonas
  2806. * fixed web bug1087
  2807. * allocate R_ECX explicitely if it's used
  2808. (merged from fixes branch)
  2809. Revision 1.5 2000/07/27 09:25:05 jonas
  2810. * moved locflags2reg() procedure from cg386add to cgai386
  2811. + added locjump2reg() procedure to cgai386
  2812. * fixed internalerror(2002) when the result of a case expression has
  2813. LOC_JUMP
  2814. (all merged from fixes branch)
  2815. Revision 1.4 2000/07/21 15:14:02 jonas
  2816. + added is_addr field for labels, if they are only used for getting the address
  2817. (e.g. for io checks) and corresponding getaddrlabel() procedure
  2818. Revision 1.3 2000/07/13 12:08:25 michael
  2819. + patched to 1.1.0 with former 1.09patch from peter
  2820. Revision 1.2 2000/07/13 11:32:37 michael
  2821. + removed logs
  2822. }