cga.pas 115 KB

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