cga.pas 97 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605
  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. cpuinfo,cpubase,cpuasm,cginfo,
  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. procedure emitlab(var l : tasmlabel);
  30. procedure emitjmp(c : tasmcond;var l : tasmlabel);
  31. procedure emit_none(i : tasmop;s : topsize);
  32. procedure emit_const(i : tasmop;s : topsize;c : longint);
  33. procedure emit_reg(i : tasmop;s : topsize;reg : tregister);
  34. procedure emit_ref(i : tasmop;s : topsize;const ref : treference);
  35. procedure emit_const_reg(i : tasmop;s : topsize;c : longint;reg : tregister);
  36. procedure emit_const_ref(i : tasmop;s : topsize;c : longint;const ref : treference);
  37. procedure emit_ref_reg(i : tasmop;s : topsize;const ref : treference;reg : tregister);
  38. procedure emit_reg_ref(i : tasmop;s : topsize;reg : tregister;const ref : treference);
  39. procedure emit_reg_reg(i : tasmop;s : topsize;reg1,reg2 : tregister);
  40. procedure emit_const_reg_reg(i : tasmop;s : topsize;c : longint;reg1,reg2 : tregister);
  41. procedure emit_reg_reg_reg(i : tasmop;s : topsize;reg1,reg2,reg3 : tregister);
  42. procedure emit_sym(i : tasmop;s : topsize;op : tasmsymbol);
  43. procedure emit_sym_ofs(i : tasmop;s : topsize;op : tasmsymbol;ofs : longint);
  44. procedure emit_sym_ofs_reg(i : tasmop;s : topsize;op : tasmsymbol;ofs:longint;reg : tregister);
  45. procedure emit_sym_ofs_ref(i : tasmop;s : topsize;op : tasmsymbol;ofs:longint;const ref : treference);
  46. procedure emitcall(const routine:string);
  47. procedure emit_push_mem_size(const t: treference; size: longint);
  48. { remove non regvar registers in loc from regs (in the format }
  49. { pushusedregisters uses) }
  50. procedure remove_non_regvars_from_loc(const t: tlocation; var regs: tregisterset);
  51. procedure emit_pushw_loc(const t:tlocation);
  52. procedure emit_push_lea_loc(const t:tlocation;freetemp:boolean);
  53. procedure copyshortstring(const dref,sref : treference;len : byte;
  54. loadref, del_sref: boolean);
  55. procedure finalize(t : tdef;const ref : treference;is_already_ref : boolean);
  56. procedure incrstringref(t : tdef;const ref : treference);
  57. procedure decrstringref(t : tdef;const ref : treference);
  58. procedure push_int(l : longint);
  59. procedure emit_push_mem(const ref : treference);
  60. procedure emitpushreferenceaddr(const ref : treference);
  61. procedure incrcomintfref(t: tdef; const ref: treference);
  62. procedure decrcomintfref(t: tdef; const ref: treference);
  63. procedure maybe_loadself;
  64. procedure emitloadord2reg(const location:Tlocation;orddef:torddef;destreg:Tregister;delloc:boolean);
  65. procedure concatcopy(source,dest : treference;size : longint;delsource : boolean;loadref:boolean);
  66. procedure genentrycode(alist : TAAsmoutput;make_global:boolean;
  67. stackframe:longint;
  68. var parasize:longint;var nostackframe:boolean;
  69. inlined : boolean);
  70. procedure genexitcode(alist : TAAsmoutput;parasize:longint;
  71. nostackframe,inlined:boolean);
  72. { if a unit doesn't have a explicit init/final code, }
  73. { we've to generate one, if the units has ansistrings }
  74. { in the interface or implementation }
  75. procedure genimplicitunitfinal(alist : TAAsmoutput);
  76. procedure genimplicitunitinit(alist : TAAsmoutput);
  77. {$ifdef test_dest_loc}
  78. const
  79. { used to avoid temporary assignments }
  80. dest_loc_known : boolean = false;
  81. in_dest_loc : boolean = false;
  82. dest_loc_tree : ptree = nil;
  83. var
  84. dest_loc : tlocation;
  85. procedure mov_reg_to_dest(p : ptree; s : topsize; reg : tregister);
  86. {$endif test_dest_loc}
  87. implementation
  88. uses
  89. cutils,cclasses,
  90. globtype,systems,globals,verbose,
  91. fmodule,
  92. symbase,symsym,symtable,types,
  93. tainst,cgbase,regvars,cgobj,tgobj,rgobj,rgcpu
  94. {$ifdef GDB}
  95. {$ifdef delphi}
  96. ,sysutils
  97. {$else}
  98. ,strings
  99. {$endif}
  100. ,gdb
  101. {$endif}
  102. ;
  103. {$ifdef NOTARGETWIN32}
  104. {$define __NOWINPECOFF__}
  105. {$endif}
  106. {$ifdef NOTARGETWDOSX}
  107. {$define __NOWINPECOFF__}
  108. {$endif}
  109. {$ifndef __NOWINPECOFF__}
  110. const
  111. winstackpagesize = 4096;
  112. {$endif}
  113. {*****************************************************************************
  114. Helpers
  115. *****************************************************************************}
  116. function def_opsize(p1:tdef):topsize;
  117. begin
  118. case p1.size of
  119. 1 : def_opsize:=S_B;
  120. 2 : def_opsize:=S_W;
  121. 4 : def_opsize:=S_L;
  122. { I don't know if we need it (FK) }
  123. 8 : def_opsize:=S_L;
  124. else
  125. internalerror(130820001);
  126. end;
  127. end;
  128. function def2def_opsize(p1,p2:tdef):topsize;
  129. var
  130. o1 : topsize;
  131. begin
  132. case p1.size of
  133. 1 : o1:=S_B;
  134. 2 : o1:=S_W;
  135. 4 : o1:=S_L;
  136. { I don't know if we need it (FK) }
  137. 8 : o1:=S_L;
  138. else
  139. internalerror(130820002);
  140. end;
  141. if assigned(p2) then
  142. begin
  143. case p2.size of
  144. 1 : o1:=S_B;
  145. 2 : begin
  146. if o1=S_B then
  147. o1:=S_BW
  148. else
  149. o1:=S_W;
  150. end;
  151. 4,8:
  152. begin
  153. case o1 of
  154. S_B : o1:=S_BL;
  155. S_W : o1:=S_WL;
  156. end;
  157. end;
  158. end;
  159. end;
  160. def2def_opsize:=o1;
  161. end;
  162. function def_getreg(p1:tdef):tregister;
  163. begin
  164. def_getreg:=rg.makeregsize(rg.getregisterint(exprasmlist),int_cgsize(p1.size));
  165. end;
  166. {*****************************************************************************
  167. Emit Assembler
  168. *****************************************************************************}
  169. procedure emitlab(var l : tasmlabel);
  170. begin
  171. if not l.is_set then
  172. exprasmList.concat(Tai_label.Create(l))
  173. else
  174. internalerror(7453984);
  175. end;
  176. procedure emitjmp(c : tasmcond;var l : tasmlabel);
  177. var
  178. ai : taicpu;
  179. begin
  180. if c=C_None then
  181. ai := Taicpu.Op_sym(A_JMP,S_NO,l)
  182. else
  183. begin
  184. ai:=Taicpu.Op_sym(A_Jcc,S_NO,l);
  185. ai.SetCondition(c);
  186. end;
  187. ai.is_jmp:=true;
  188. exprasmList.concat(ai);
  189. end;
  190. procedure emit_none(i : tasmop;s : topsize);
  191. begin
  192. exprasmList.concat(Taicpu.Op_none(i,s));
  193. end;
  194. procedure emit_reg(i : tasmop;s : topsize;reg : tregister);
  195. begin
  196. exprasmList.concat(Taicpu.Op_reg(i,s,reg));
  197. end;
  198. procedure emit_ref(i : tasmop;s : topsize;const ref : treference);
  199. begin
  200. exprasmList.concat(Taicpu.Op_ref(i,s,ref));
  201. end;
  202. procedure emit_const(i : tasmop;s : topsize;c : longint);
  203. begin
  204. exprasmList.concat(Taicpu.Op_const(i,s,aword(c)));
  205. end;
  206. procedure emit_const_reg(i : tasmop;s : topsize;c : longint;reg : tregister);
  207. begin
  208. exprasmList.concat(Taicpu.Op_const_reg(i,s,aword(c),reg));
  209. end;
  210. procedure emit_const_ref(i : tasmop;s : topsize;c : longint;const ref : treference);
  211. begin
  212. exprasmList.concat(Taicpu.Op_const_ref(i,s,aword(c),ref));
  213. end;
  214. procedure emit_ref_reg(i : tasmop;s : topsize;const ref : treference;reg : tregister);
  215. begin
  216. exprasmList.concat(Taicpu.Op_ref_reg(i,s,ref,reg));
  217. end;
  218. procedure emit_reg_ref(i : tasmop;s : topsize;reg : tregister;const ref : treference);
  219. begin
  220. exprasmList.concat(Taicpu.Op_reg_ref(i,s,reg,ref));
  221. end;
  222. procedure emit_reg_reg(i : tasmop;s : topsize;reg1,reg2 : tregister);
  223. begin
  224. if (reg1<>reg2) or (i<>A_MOV) then
  225. exprasmList.concat(Taicpu.Op_reg_reg(i,s,reg1,reg2));
  226. end;
  227. procedure emit_const_reg_reg(i : tasmop;s : topsize;c : longint;reg1,reg2 : tregister);
  228. begin
  229. exprasmList.concat(Taicpu.Op_const_reg_reg(i,s,c,reg1,reg2));
  230. end;
  231. procedure emit_reg_reg_reg(i : tasmop;s : topsize;reg1,reg2,reg3 : tregister);
  232. begin
  233. exprasmList.concat(Taicpu.Op_reg_reg_reg(i,s,reg1,reg2,reg3));
  234. end;
  235. procedure emit_sym(i : tasmop;s : topsize;op : tasmsymbol);
  236. begin
  237. exprasmList.concat(Taicpu.Op_sym(i,s,op));
  238. end;
  239. procedure emit_sym_ofs(i : tasmop;s : topsize;op : tasmsymbol;ofs : longint);
  240. begin
  241. exprasmList.concat(Taicpu.Op_sym_ofs(i,s,op,ofs));
  242. end;
  243. procedure emit_sym_ofs_reg(i : tasmop;s : topsize;op : tasmsymbol;ofs:longint;reg : tregister);
  244. begin
  245. exprasmList.concat(Taicpu.Op_sym_ofs_reg(i,s,op,ofs,reg));
  246. end;
  247. procedure emit_sym_ofs_ref(i : tasmop;s : topsize;op : tasmsymbol;ofs:longint;const ref : treference);
  248. begin
  249. exprasmList.concat(Taicpu.Op_sym_ofs_ref(i,s,op,ofs,ref));
  250. end;
  251. procedure emitcall(const routine:string);
  252. begin
  253. exprasmList.concat(Taicpu.Op_sym(A_CALL,S_NO,newasmsymbol(routine)));
  254. end;
  255. { only usefull in startup code }
  256. procedure emitinsertcall(const routine:string);
  257. begin
  258. exprasmList.insert(Taicpu.Op_sym(A_CALL,S_NO,newasmsymbol(routine)));
  259. end;
  260. procedure remove_non_regvars_from_loc(const t: tlocation; var regs: tregisterset);
  261. begin
  262. case t.loc of
  263. LOC_REGISTER:
  264. begin
  265. { can't be a regvar, since it would be LOC_CREGISTER then }
  266. exclude(regs,t.register);
  267. if t.registerhigh <> R_NO then
  268. exclude(regs,t.registerhigh);
  269. end;
  270. LOC_CREFERENCE,LOC_REFERENCE:
  271. begin
  272. if not(cs_regalloc in aktglobalswitches) or
  273. (t.reference.base in rg.usableregsint) then
  274. exclude(regs,t.reference.base);
  275. if not(cs_regalloc in aktglobalswitches) or
  276. (t.reference.index in rg.usableregsint) then
  277. exclude(regs,t.reference.index);
  278. end;
  279. end;
  280. end;
  281. procedure emit_pushw_loc(const t:tlocation);
  282. var
  283. opsize : topsize;
  284. begin
  285. case t.loc of
  286. LOC_REGISTER,
  287. LOC_CREGISTER : begin
  288. if aktalignment.paraalign=4 then
  289. exprasmList.concat(Taicpu.Op_reg(A_PUSH,S_L,rg.makeregsize(t.register,OS_32)))
  290. else
  291. exprasmList.concat(Taicpu.Op_reg(A_PUSH,S_W,rg.makeregsize(t.register,OS_16)));
  292. end;
  293. LOC_CONSTANT : begin
  294. if aktalignment.paraalign=4 then
  295. opsize:=S_L
  296. else
  297. opsize:=S_W;
  298. exprasmList.concat(Taicpu.Op_const(A_PUSH,opsize,t.value));
  299. end;
  300. LOC_CREFERENCE,
  301. LOC_REFERENCE : begin
  302. if aktalignment.paraalign=4 then
  303. opsize:=S_L
  304. else
  305. opsize:=S_W;
  306. exprasmList.concat(Taicpu.Op_ref(A_PUSH,opsize,t.reference));
  307. end;
  308. else
  309. internalerror(200203213);
  310. end;
  311. location_release(exprasmlist,t);
  312. location_freetemp(exprasmlist,t);
  313. end;
  314. procedure emit_push_lea_loc(const t:tlocation;freetemp:boolean);
  315. begin
  316. case t.loc of
  317. LOC_CREFERENCE,
  318. LOC_REFERENCE : begin
  319. rg.getexplicitregisterint(exprasmlist,R_EDI);
  320. emit_ref_reg(A_LEA,S_L,t.reference,R_EDI);
  321. exprasmList.concat(Taicpu.Op_reg(A_PUSH,S_L,R_EDI));
  322. rg.ungetregisterint(exprasmlist,R_EDI);
  323. end;
  324. else
  325. internalerror(200203218);
  326. end;
  327. location_release(exprasmlist,t);
  328. if freetemp then
  329. location_freetemp(exprasmlist,t);
  330. end;
  331. procedure emit_push_mem_size(const t: treference; size: longint);
  332. var
  333. s: topsize;
  334. begin
  335. if size < 4 then
  336. begin
  337. rg.getexplicitregisterint(exprasmlist,R_EDI);
  338. case size of
  339. 1: s := S_BL;
  340. 2: s := S_WL;
  341. else internalerror(200008071);
  342. end;
  343. exprasmList.concat(Taicpu.Op_ref_reg(A_MOVZX,s,t,R_EDI));
  344. if aktalignment.paraalign=4 then
  345. exprasmList.concat(Taicpu.Op_reg(A_PUSH,S_L,R_EDI))
  346. else
  347. exprasmList.concat(Taicpu.Op_reg(A_PUSH,S_W,R_DI));
  348. rg.ungetregisterint(exprasmlist,R_EDI);
  349. end
  350. end;
  351. {*****************************************************************************
  352. Emit String Functions
  353. *****************************************************************************}
  354. procedure incrcomintfref(t: tdef; const ref: treference);
  355. var
  356. pushedregs : tpushedsaved;
  357. begin
  358. rg.saveusedregisters(exprasmlist,pushedregs,all_registers);
  359. emit_ref(A_PUSH,S_L,ref);
  360. rg.saveregvars(exprasmlist,all_registers);
  361. if is_interfacecom(t) then
  362. emitcall('FPC_INTF_INCR_REF')
  363. else
  364. internalerror(1859);
  365. rg.restoreusedregisters(exprasmlist,pushedregs);
  366. end;
  367. procedure decrcomintfref(t: tdef; const ref: treference);
  368. var
  369. pushedregs : tpushedsaved;
  370. begin
  371. rg.saveusedregisters(exprasmlist,pushedregs,all_registers);
  372. emitpushreferenceaddr(ref);
  373. rg.saveregvars(exprasmlist,all_registers);
  374. if is_interfacecom(t) then
  375. begin
  376. emitcall('FPC_INTF_DECR_REF');
  377. end
  378. else internalerror(1859);
  379. rg.restoreusedregisters(exprasmlist,pushedregs);
  380. end;
  381. procedure copyshortstring(const dref,sref : treference;len : byte;
  382. loadref, del_sref: boolean);
  383. begin
  384. emitpushreferenceaddr(dref);
  385. { if it's deleted right before it's used, the optimizer can move }
  386. { the reg deallocations to the right places (JM) }
  387. if del_sref then
  388. reference_release(exprasmlist,sref);
  389. if loadref then
  390. emit_push_mem(sref)
  391. else
  392. emitpushreferenceaddr(sref);
  393. push_int(len);
  394. emitcall('FPC_SHORTSTR_COPY');
  395. maybe_loadself;
  396. end;
  397. {$ifdef unused}
  398. procedure copylongstring(const dref,sref : treference;len : longint;loadref:boolean);
  399. begin
  400. emitpushreferenceaddr(dref);
  401. if loadref then
  402. emit_push_mem(sref)
  403. else
  404. emitpushreferenceaddr(sref);
  405. push_int(len);
  406. rg.saveregvars(exprasmlist,all_registers);
  407. emitcall('FPC_LONGSTR_COPY');
  408. maybe_loadself;
  409. end;
  410. {$endif unused}
  411. procedure incrstringref(t : tdef;const ref : treference);
  412. var
  413. pushedregs : tpushedsaved;
  414. begin
  415. rg.saveusedregisters(exprasmlist,pushedregs,all_registers);
  416. emitpushreferenceaddr(ref);
  417. rg.saveregvars(exprasmlist,all_registers);
  418. if is_ansistring(t) then
  419. begin
  420. emitcall('FPC_ANSISTR_INCR_REF');
  421. end
  422. else if is_widestring(t) then
  423. begin
  424. emitcall('FPC_WIDESTR_INCR_REF');
  425. end
  426. else internalerror(1859);
  427. rg.restoreusedregisters(exprasmlist,pushedregs);
  428. end;
  429. procedure decrstringref(t : tdef;const ref : treference);
  430. var
  431. pushedregs : tpushedsaved;
  432. begin
  433. rg.saveusedregisters(exprasmlist,pushedregs,all_registers);
  434. emitpushreferenceaddr(ref);
  435. rg.saveregvars(exprasmlist,all_registers);
  436. if is_ansistring(t) then
  437. begin
  438. emitcall('FPC_ANSISTR_DECR_REF');
  439. end
  440. else if is_widestring(t) then
  441. begin
  442. emitcall('FPC_WIDESTR_DECR_REF');
  443. end
  444. else internalerror(1859);
  445. rg.restoreusedregisters(exprasmlist,pushedregs);
  446. end;
  447. {*****************************************************************************
  448. Emit Push Functions
  449. *****************************************************************************}
  450. procedure push_int(l : longint);
  451. begin
  452. if (l = 0) and
  453. not(aktoptprocessor in [Class386, ClassP6]) and
  454. not(cs_littlesize in aktglobalswitches)
  455. Then
  456. begin
  457. rg.getexplicitregisterint(exprasmlist,R_EDI);
  458. emit_reg_reg(A_XOR,S_L,R_EDI,R_EDI);
  459. exprasmList.concat(Taicpu.Op_reg(A_PUSH,S_L,R_EDI));
  460. rg.ungetregisterint(exprasmlist,R_EDI);
  461. end
  462. else
  463. exprasmList.concat(Taicpu.Op_const(A_PUSH,S_L,aword(l)));
  464. end;
  465. procedure emit_push_mem(const ref : treference);
  466. begin
  467. if not(aktoptprocessor in [Class386, ClassP6]) and
  468. not(cs_littlesize in aktglobalswitches)
  469. then
  470. begin
  471. rg.getexplicitregisterint(exprasmlist,R_EDI);
  472. emit_ref_reg(A_MOV,S_L,ref,R_EDI);
  473. exprasmList.concat(Taicpu.Op_reg(A_PUSH,S_L,R_EDI));
  474. rg.ungetregisterint(exprasmlist,R_EDI);
  475. end
  476. else exprasmList.concat(Taicpu.Op_ref(A_PUSH,S_L,ref));
  477. end;
  478. procedure emitpushreferenceaddr(const ref : treference);
  479. begin
  480. if ref.segment<>R_NO then
  481. CGMessage(cg_e_cant_use_far_pointer_there);
  482. if (ref.base=R_NO) and (ref.index=R_NO) then
  483. exprasmList.concat(Taicpu.Op_sym_ofs(A_PUSH,S_L,ref.symbol,ref.offset))
  484. else if (ref.base=R_NO) and (ref.index<>R_NO) and
  485. (ref.offset=0) and (ref.scalefactor=0) and (ref.symbol=nil) then
  486. exprasmList.concat(Taicpu.Op_reg(A_PUSH,S_L,ref.index))
  487. else if (ref.base<>R_NO) and (ref.index=R_NO) and
  488. (ref.offset=0) and (ref.symbol=nil) then
  489. exprasmList.concat(Taicpu.Op_reg(A_PUSH,S_L,ref.base))
  490. else
  491. begin
  492. rg.getexplicitregisterint(exprasmlist,R_EDI);
  493. emit_ref_reg(A_LEA,S_L,ref,R_EDI);
  494. exprasmList.concat(Taicpu.Op_reg(A_PUSH,S_L,R_EDI));
  495. rg.ungetregisterint(exprasmlist,R_EDI);
  496. end;
  497. end;
  498. {*****************************************************************************
  499. Emit Functions
  500. *****************************************************************************}
  501. procedure concatcopy(source,dest : treference;size : longint;delsource,loadref : boolean);
  502. {const
  503. isizes : array[0..3] of topsize=(S_L,S_B,S_W,S_B);
  504. ishr : array[0..3] of byte=(2,0,1,0);}
  505. var
  506. ecxpushed : boolean;
  507. oldsourceoffset,
  508. helpsize : longint;
  509. i : byte;
  510. reg8,reg32 : tregister;
  511. swap : boolean;
  512. procedure maybepushecx;
  513. begin
  514. if not(R_ECX in rg.unusedregsint) then
  515. begin
  516. exprasmList.concat(Taicpu.Op_reg(A_PUSH,S_L,R_ECX));
  517. ecxpushed:=true;
  518. end
  519. else rg.getexplicitregisterint(exprasmlist,R_ECX);
  520. end;
  521. begin
  522. oldsourceoffset:=source.offset;
  523. if (not loadref) and
  524. ((size<=8) or
  525. (not(cs_littlesize in aktglobalswitches ) and (size<=12))) then
  526. begin
  527. helpsize:=size shr 2;
  528. rg.getexplicitregisterint(exprasmlist,R_EDI);
  529. for i:=1 to helpsize do
  530. begin
  531. emit_ref_reg(A_MOV,S_L,source,R_EDI);
  532. If (size = 4) and delsource then
  533. reference_release(exprasmlist,source);
  534. exprasmList.concat(Taicpu.Op_reg_ref(A_MOV,S_L,R_EDI,dest));
  535. inc(source.offset,4);
  536. inc(dest.offset,4);
  537. dec(size,4);
  538. end;
  539. if size>1 then
  540. begin
  541. emit_ref_reg(A_MOV,S_W,source,R_DI);
  542. If (size = 2) and delsource then
  543. reference_release(exprasmlist,source);
  544. exprasmList.concat(Taicpu.Op_reg_ref(A_MOV,S_W,R_DI,dest));
  545. inc(source.offset,2);
  546. inc(dest.offset,2);
  547. dec(size,2);
  548. end;
  549. rg.ungetregisterint(exprasmlist,R_EDI);
  550. if size>0 then
  551. begin
  552. { and now look for an 8 bit register }
  553. swap:=false;
  554. if R_EAX in rg.unusedregsint then reg8:=rg.makeregsize(rg.getexplicitregisterint(exprasmlist,R_EAX),OS_8)
  555. else if R_EDX in rg.unusedregsint then reg8:=rg.makeregsize(rg.getexplicitregisterint(exprasmlist,R_EDX),OS_8)
  556. else if R_EBX in rg.unusedregsint then reg8:=rg.makeregsize(rg.getexplicitregisterint(exprasmlist,R_EBX),OS_8)
  557. else if R_ECX in rg.unusedregsint then reg8:=rg.makeregsize(rg.getexplicitregisterint(exprasmlist,R_ECX),OS_8)
  558. else
  559. begin
  560. swap:=true;
  561. { we need only to check 3 registers, because }
  562. { one is always not index or base }
  563. if (dest.base<>R_EAX) and (dest.index<>R_EAX) then
  564. begin
  565. reg8:=R_AL;
  566. reg32:=R_EAX;
  567. end
  568. else if (dest.base<>R_EBX) and (dest.index<>R_EBX) then
  569. begin
  570. reg8:=R_BL;
  571. reg32:=R_EBX;
  572. end
  573. else if (dest.base<>R_ECX) and (dest.index<>R_ECX) then
  574. begin
  575. reg8:=R_CL;
  576. reg32:=R_ECX;
  577. end;
  578. end;
  579. if swap then
  580. { was earlier XCHG, of course nonsense }
  581. begin
  582. rg.getexplicitregisterint(exprasmlist,R_EDI);
  583. emit_reg_reg(A_MOV,S_L,reg32,R_EDI);
  584. end;
  585. emit_ref_reg(A_MOV,S_B,source,reg8);
  586. If delsource then
  587. reference_release(exprasmlist,source);
  588. exprasmList.concat(Taicpu.Op_reg_ref(A_MOV,S_B,reg8,dest));
  589. if swap then
  590. begin
  591. emit_reg_reg(A_MOV,S_L,R_EDI,reg32);
  592. rg.ungetregisterint(exprasmlist,R_EDI);
  593. end
  594. else
  595. rg.ungetregister(exprasmlist,reg8);
  596. end;
  597. end
  598. else
  599. begin
  600. rg.getexplicitregisterint(exprasmlist,R_EDI);
  601. emit_ref_reg(A_LEA,S_L,dest,R_EDI);
  602. exprasmList.concat(Tairegalloc.Alloc(R_ESI));
  603. if loadref then
  604. emit_ref_reg(A_MOV,S_L,source,R_ESI)
  605. else
  606. begin
  607. emit_ref_reg(A_LEA,S_L,source,R_ESI);
  608. if delsource then
  609. reference_release(exprasmlist,source);
  610. end;
  611. exprasmList.concat(Taicpu.Op_none(A_CLD,S_NO));
  612. ecxpushed:=false;
  613. if cs_littlesize in aktglobalswitches then
  614. begin
  615. maybepushecx;
  616. emit_const_reg(A_MOV,S_L,size,R_ECX);
  617. exprasmList.concat(Taicpu.Op_none(A_REP,S_NO));
  618. exprasmList.concat(Taicpu.Op_none(A_MOVSB,S_NO));
  619. end
  620. else
  621. begin
  622. helpsize:=size shr 2;
  623. size:=size and 3;
  624. if helpsize>1 then
  625. begin
  626. maybepushecx;
  627. emit_const_reg(A_MOV,S_L,helpsize,R_ECX);
  628. exprasmList.concat(Taicpu.Op_none(A_REP,S_NO));
  629. end;
  630. if helpsize>0 then
  631. exprasmList.concat(Taicpu.Op_none(A_MOVSD,S_NO));
  632. if size>1 then
  633. begin
  634. dec(size,2);
  635. exprasmList.concat(Taicpu.Op_none(A_MOVSW,S_NO));
  636. end;
  637. if size=1 then
  638. exprasmList.concat(Taicpu.Op_none(A_MOVSB,S_NO));
  639. end;
  640. rg.ungetregisterint(exprasmlist,R_EDI);
  641. exprasmList.concat(Tairegalloc.DeAlloc(R_ESI));
  642. if ecxpushed then
  643. exprasmList.concat(Taicpu.Op_reg(A_POP,S_L,R_ECX))
  644. else
  645. rg.ungetregisterint(exprasmlist,R_ECX);
  646. { loading SELF-reference again }
  647. maybe_loadself;
  648. end;
  649. if delsource then
  650. begin
  651. source.offset:=oldsourceoffset;
  652. tg.ungetiftemp(exprasmlist,source);
  653. end;
  654. end;
  655. procedure emitloadord2reg(const location:Tlocation;orddef:torddef;
  656. destreg:Tregister;delloc:boolean);
  657. {A lot smaller and less bug sensitive than the original unfolded loads.}
  658. var tai:Taicpu;
  659. begin
  660. tai := nil;
  661. case location.loc of
  662. LOC_REGISTER,LOC_CREGISTER:
  663. begin
  664. case orddef.typ of
  665. u8bit,uchar,bool8bit:
  666. tai:=Taicpu.Op_reg_reg(A_MOVZX,S_BL,location.register,destreg);
  667. s8bit:
  668. tai:=Taicpu.Op_reg_reg(A_MOVSX,S_BL,location.register,destreg);
  669. u16bit,uwidechar,bool16bit:
  670. tai:=Taicpu.Op_reg_reg(A_MOVZX,S_WL,location.register,destreg);
  671. s16bit:
  672. tai:=Taicpu.Op_reg_reg(A_MOVSX,S_WL,location.register,destreg);
  673. u32bit,bool32bit,s32bit:
  674. if location.register <> destreg then
  675. tai:=Taicpu.Op_reg_reg(A_MOV,S_L,location.register,destreg);
  676. else
  677. internalerror(330);
  678. end;
  679. if delloc then
  680. rg.ungetregister(exprasmlist,location.register);
  681. end;
  682. LOC_CONSTANT:
  683. begin
  684. tai:=Taicpu.Op_const_reg(A_MOV,S_L,location.value,destreg)
  685. end;
  686. LOC_CREFERENCE,
  687. LOC_REFERENCE:
  688. begin
  689. case orddef.typ of
  690. u8bit,uchar,bool8bit:
  691. tai:=Taicpu.Op_ref_reg(A_MOVZX,S_BL,location.reference,destreg);
  692. s8bit:
  693. tai:=Taicpu.Op_ref_reg(A_MOVSX,S_BL,location.reference,destreg);
  694. u16bit,uwidechar,bool16bit:
  695. tai:=Taicpu.Op_ref_reg(A_MOVZX,S_WL,location.reference,destreg);
  696. s16bit:
  697. tai:=Taicpu.Op_ref_reg(A_MOVSX,S_WL,location.reference,destreg);
  698. u32bit,bool32bit:
  699. tai:=Taicpu.Op_ref_reg(A_MOV,S_L,location.reference,destreg);
  700. s32bit:
  701. tai:=Taicpu.Op_ref_reg(A_MOV,S_L,location.reference,destreg);
  702. else
  703. internalerror(330);
  704. end;
  705. if delloc then
  706. reference_release(exprasmlist,location.reference);
  707. end
  708. else
  709. internalerror(6);
  710. end;
  711. if assigned(tai) then
  712. exprasmList.concat(tai);
  713. end;
  714. { if necessary ESI is reloaded after a call}
  715. procedure maybe_loadself;
  716. var
  717. hp : treference;
  718. p : pprocinfo;
  719. i : longint;
  720. begin
  721. if assigned(procinfo^._class) then
  722. begin
  723. exprasmList.concat(Tairegalloc.Alloc(R_ESI));
  724. if lexlevel>normal_function_level then
  725. begin
  726. reference_reset_base(hp,procinfo^.framepointer,procinfo^.framepointer_offset);
  727. emit_ref_reg(A_MOV,S_L,hp,R_ESI);
  728. p:=procinfo^.parent;
  729. for i:=3 to lexlevel-1 do
  730. begin
  731. reference_reset_base(hp,R_ESI,p^.framepointer_offset);
  732. emit_ref_reg(A_MOV,S_L,hp,R_ESI);
  733. p:=p^.parent;
  734. end;
  735. reference_reset_base(hp,R_ESI,p^.selfpointer_offset);
  736. emit_ref_reg(A_MOV,S_L,hp,R_ESI);
  737. end
  738. else
  739. begin
  740. reference_reset_base(hp,procinfo^.framepointer,procinfo^.selfpointer_offset);
  741. emit_ref_reg(A_MOV,S_L,hp,R_ESI);
  742. end;
  743. end;
  744. end;
  745. {*****************************************************************************
  746. Entry/Exit Code Functions
  747. *****************************************************************************}
  748. procedure genprofilecode;
  749. var
  750. pl : tasmlabel;
  751. begin
  752. if (po_assembler in aktprocdef.procoptions) then
  753. exit;
  754. case target_info.target of
  755. target_i386_win32,
  756. target_i386_freebsd,
  757. target_i386_wdosx,
  758. target_i386_linux:
  759. begin
  760. getaddrlabel(pl);
  761. emitinsertcall(target_info.Cprefix+'mcount');
  762. include(rg.usedinproc,R_EDX);
  763. exprasmList.insert(Taicpu.Op_sym_ofs_reg(A_MOV,S_L,pl,0,R_EDX));
  764. exprasmList.insert(Tai_section.Create(sec_code));
  765. exprasmList.insert(Tai_const.Create_32bit(0));
  766. exprasmList.insert(Tai_label.Create(pl));
  767. exprasmList.insert(Tai_align.Create(4));
  768. exprasmList.insert(Tai_section.Create(sec_data));
  769. end;
  770. target_i386_go32v2:
  771. begin
  772. emitinsertcall('MCOUNT');
  773. end;
  774. end;
  775. end;
  776. procedure generate_interrupt_stackframe_entry;
  777. begin
  778. { save the registers of an interrupt procedure }
  779. exprasmList.insert(Taicpu.Op_reg(A_PUSH,S_L,R_EAX));
  780. exprasmList.insert(Taicpu.Op_reg(A_PUSH,S_L,R_EBX));
  781. exprasmList.insert(Taicpu.Op_reg(A_PUSH,S_L,R_ECX));
  782. exprasmList.insert(Taicpu.Op_reg(A_PUSH,S_L,R_EDX));
  783. exprasmList.insert(Taicpu.Op_reg(A_PUSH,S_L,R_ESI));
  784. exprasmList.insert(Taicpu.Op_reg(A_PUSH,S_L,R_EDI));
  785. { .... also the segment registers }
  786. exprasmList.insert(Taicpu.Op_reg(A_PUSH,S_W,R_DS));
  787. exprasmList.insert(Taicpu.Op_reg(A_PUSH,S_W,R_ES));
  788. exprasmList.insert(Taicpu.Op_reg(A_PUSH,S_W,R_FS));
  789. exprasmList.insert(Taicpu.Op_reg(A_PUSH,S_W,R_GS));
  790. end;
  791. procedure generate_interrupt_stackframe_exit;
  792. begin
  793. { restore the registers of an interrupt procedure }
  794. { this was all with entrycode instead of exitcode !!}
  795. procinfo^.aktexitcode.concat(Taicpu.Op_reg(A_POP,S_L,R_EAX));
  796. procinfo^.aktexitcode.concat(Taicpu.Op_reg(A_POP,S_L,R_EBX));
  797. procinfo^.aktexitcode.concat(Taicpu.Op_reg(A_POP,S_L,R_ECX));
  798. procinfo^.aktexitcode.concat(Taicpu.Op_reg(A_POP,S_L,R_EDX));
  799. procinfo^.aktexitcode.concat(Taicpu.Op_reg(A_POP,S_L,R_ESI));
  800. procinfo^.aktexitcode.concat(Taicpu.Op_reg(A_POP,S_L,R_EDI));
  801. { .... also the segment registers }
  802. procinfo^.aktexitcode.concat(Taicpu.Op_reg(A_POP,S_W,R_DS));
  803. procinfo^.aktexitcode.concat(Taicpu.Op_reg(A_POP,S_W,R_ES));
  804. procinfo^.aktexitcode.concat(Taicpu.Op_reg(A_POP,S_W,R_FS));
  805. procinfo^.aktexitcode.concat(Taicpu.Op_reg(A_POP,S_W,R_GS));
  806. { this restores the flags }
  807. procinfo^.aktexitcode.concat(Taicpu.Op_none(A_IRET,S_NO));
  808. end;
  809. { generates the code for threadvar initialisation }
  810. procedure initialize_threadvar(p : tnamedindexitem);
  811. var
  812. hr : treference;
  813. begin
  814. if (tsym(p).typ=varsym) and
  815. (vo_is_thread_var in tvarsym(p).varoptions) then
  816. begin
  817. exprasmList.concat(Taicpu.Op_const(A_PUSH,S_L,tvarsym(p).getsize));
  818. reference_reset(hr);
  819. hr.symbol:=newasmsymbol(tvarsym(p).mangledname);
  820. emitpushreferenceaddr(hr);
  821. rg.saveregvars(exprasmlist,all_registers);
  822. emitcall('FPC_INIT_THREADVAR');
  823. end;
  824. end;
  825. { initilizes data of type t }
  826. { if is_already_ref is true then the routines assumes }
  827. { that r points to the data to initialize }
  828. procedure initialize(t : tdef;const ref : treference;is_already_ref : boolean);
  829. var
  830. hr : treference;
  831. begin
  832. if is_ansistring(t) or
  833. is_widestring(t) or
  834. is_interfacecom(t) then
  835. begin
  836. emit_const_ref(A_MOV,S_L,0,ref);
  837. end
  838. else
  839. begin
  840. reference_reset(hr);
  841. hr.symbol:=tstoreddef(t).get_rtti_label(initrtti);
  842. emitpushreferenceaddr(hr);
  843. if is_already_ref then
  844. exprasmList.concat(Taicpu.Op_ref(A_PUSH,S_L,ref))
  845. else
  846. emitpushreferenceaddr(ref);
  847. emitcall('FPC_INITIALIZE');
  848. end;
  849. end;
  850. { finalizes data of type t }
  851. { if is_already_ref is true then the routines assumes }
  852. { that r points to the data to finalizes }
  853. procedure finalize(t : tdef;const ref : treference;is_already_ref : boolean);
  854. var
  855. r : treference;
  856. begin
  857. if is_ansistring(t) or
  858. is_widestring(t) then
  859. begin
  860. decrstringref(t,ref);
  861. end
  862. else if is_interfacecom(t) then
  863. begin
  864. decrcomintfref(t,ref);
  865. end
  866. else
  867. begin
  868. reference_reset(r);
  869. r.symbol:=tstoreddef(t).get_rtti_label(initrtti);
  870. emitpushreferenceaddr(r);
  871. if is_already_ref then
  872. exprasmList.concat(Taicpu.Op_ref(A_PUSH,S_L,ref))
  873. else
  874. emitpushreferenceaddr(ref);
  875. emitcall('FPC_FINALIZE');
  876. end;
  877. end;
  878. { generates the code for initialisation of local data }
  879. procedure initialize_data(p : tnamedindexitem);
  880. var
  881. hr : treference;
  882. begin
  883. if (tsym(p).typ=varsym) and
  884. assigned(tvarsym(p).vartype.def) and
  885. not(is_class(tvarsym(p).vartype.def)) and
  886. tvarsym(p).vartype.def.needs_inittable then
  887. begin
  888. if assigned(procinfo) then
  889. procinfo^.flags:=procinfo^.flags or pi_needs_implicit_finally;
  890. reference_reset(hr);
  891. if tsym(p).owner.symtabletype in [localsymtable,inlinelocalsymtable] then
  892. begin
  893. hr.base:=procinfo^.framepointer;
  894. hr.offset:=-tvarsym(p).address+tvarsym(p).owner.address_fixup;
  895. end
  896. else
  897. begin
  898. hr.symbol:=newasmsymbol(tvarsym(p).mangledname);
  899. end;
  900. initialize(tvarsym(p).vartype.def,hr,false);
  901. end;
  902. end;
  903. { generates the code for incrementing the reference count of parameters and
  904. initialize out parameters }
  905. procedure init_paras(p : tnamedindexitem);
  906. var
  907. hrv : treference;
  908. hr: treference;
  909. begin
  910. if (tsym(p).typ=varsym) and
  911. not is_class(tvarsym(p).vartype.def) and
  912. tvarsym(p).vartype.def.needs_inittable then
  913. begin
  914. if (tvarsym(p).varspez=vs_value) then
  915. begin
  916. procinfo^.flags:=procinfo^.flags or pi_needs_implicit_finally;
  917. reference_reset(hrv);
  918. hrv.base:=procinfo^.framepointer;
  919. if assigned(tvarsym(p).localvarsym) then
  920. hrv.offset:=-tvarsym(p).localvarsym.address+tvarsym(p).localvarsym.owner.address_fixup
  921. else
  922. hrv.offset:=tvarsym(p).address+procinfo^.para_offset;
  923. if is_ansistring(tvarsym(p).vartype.def) or
  924. is_widestring(tvarsym(p).vartype.def) then
  925. begin
  926. incrstringref(tvarsym(p).vartype.def,hrv)
  927. end
  928. else if is_interfacecom(tvarsym(p).vartype.def) then
  929. begin
  930. incrcomintfref(tvarsym(p).vartype.def,hrv)
  931. end
  932. else
  933. begin
  934. reference_reset(hr);
  935. hr.symbol:=tstoreddef(tvarsym(p).vartype.def).get_rtti_label(initrtti);
  936. emitpushreferenceaddr(hr);
  937. emitpushreferenceaddr(hrv);
  938. emitcall('FPC_ADDREF');
  939. end;
  940. end
  941. else if (tvarsym(p).varspez=vs_out) then
  942. begin
  943. reference_reset(hrv);
  944. hrv.base:=procinfo^.framepointer;
  945. hrv.offset:=tvarsym(p).address+procinfo^.para_offset;
  946. rg.getexplicitregisterint(exprasmlist,R_EDI);
  947. exprasmList.concat(Taicpu.Op_ref_reg(A_MOV,S_L,hrv,R_EDI));
  948. reference_reset(hr);
  949. hr.base:=R_EDI;
  950. initialize(tvarsym(p).vartype.def,hr,false);
  951. end;
  952. end;
  953. end;
  954. { generates the code for decrementing the reference count of parameters }
  955. procedure final_paras(p : tnamedindexitem);
  956. var
  957. hrv : treference;
  958. hr: treference;
  959. begin
  960. if (tsym(p).typ=varsym) and
  961. not is_class(tvarsym(p).vartype.def) and
  962. tvarsym(p).vartype.def.needs_inittable then
  963. begin
  964. if (tvarsym(p).varspez=vs_value) then
  965. begin
  966. procinfo^.flags:=procinfo^.flags or pi_needs_implicit_finally;
  967. reference_reset(hrv);
  968. hrv.base:=procinfo^.framepointer;
  969. if assigned(tvarsym(p).localvarsym) then
  970. hrv.offset:=-tvarsym(p).localvarsym.address+tvarsym(p).localvarsym.owner.address_fixup
  971. else
  972. hrv.offset:=tvarsym(p).address+procinfo^.para_offset;
  973. if is_ansistring(tvarsym(p).vartype.def) or
  974. is_widestring(tvarsym(p).vartype.def) then
  975. begin
  976. decrstringref(tvarsym(p).vartype.def,hrv)
  977. end
  978. else if is_interfacecom(tvarsym(p).vartype.def) then
  979. begin
  980. decrcomintfref(tvarsym(p).vartype.def,hrv)
  981. end
  982. else
  983. begin
  984. reference_reset(hr);
  985. hr.symbol:=tstoreddef(tvarsym(p).vartype.def).get_rtti_label(initrtti);
  986. emitpushreferenceaddr(hr);
  987. emitpushreferenceaddr(hrv);
  988. emitcall('FPC_DECREF');
  989. end;
  990. end;
  991. end;
  992. end;
  993. { generates the code for finalisation of local data }
  994. procedure finalize_data(p : tnamedindexitem);
  995. var
  996. hr : treference;
  997. begin
  998. if (tsym(p).typ=varsym) and
  999. assigned(tvarsym(p).vartype.def) and
  1000. not(is_class(tvarsym(p).vartype.def)) and
  1001. tvarsym(p).vartype.def.needs_inittable then
  1002. begin
  1003. if assigned(procinfo) then
  1004. procinfo^.flags:=procinfo^.flags or pi_needs_implicit_finally;
  1005. reference_reset(hr);
  1006. case tsym(p).owner.symtabletype of
  1007. localsymtable,inlinelocalsymtable:
  1008. begin
  1009. hr.base:=procinfo^.framepointer;
  1010. hr.offset:=-tvarsym(p).address+tvarsym(p).owner.address_fixup;
  1011. end;
  1012. else
  1013. hr.symbol:=newasmsymbol(tvarsym(p).mangledname);
  1014. end;
  1015. finalize(tvarsym(p).vartype.def,hr,false);
  1016. end;
  1017. end;
  1018. { generates the code to make local copies of the value parameters }
  1019. procedure copyvalueparas(p : tnamedindexitem);
  1020. var
  1021. href1,href2 : treference;
  1022. r : treference;
  1023. power,len : longint;
  1024. opsize : topsize;
  1025. {$ifndef __NOWINPECOFF__}
  1026. again,ok : tasmlabel;
  1027. {$endif}
  1028. begin
  1029. if (tsym(p).typ=varsym) and
  1030. (tvarsym(p).varspez=vs_value) and
  1031. (push_addr_param(tvarsym(p).vartype.def)) then
  1032. begin
  1033. if is_open_array(tvarsym(p).vartype.def) or
  1034. is_array_of_const(tvarsym(p).vartype.def) then
  1035. begin
  1036. { get stack space }
  1037. reference_reset_base(r,procinfo^.framepointer,tvarsym(p).address+4+procinfo^.para_offset);
  1038. rg.getexplicitregisterint(exprasmlist,R_EDI);
  1039. exprasmList.concat(Taicpu.op_ref_reg(A_MOV,S_L,r,R_EDI));
  1040. exprasmList.concat(Taicpu.op_reg(A_INC,S_L,R_EDI));
  1041. if (tarraydef(tvarsym(p).vartype.def).elesize<>1) then
  1042. begin
  1043. if ispowerof2(tarraydef(tvarsym(p).vartype.def).elesize, power) then
  1044. exprasmList.concat(Taicpu.op_const_reg(A_SHL,S_L,power,R_EDI))
  1045. else
  1046. exprasmList.concat(Taicpu.op_const_reg(A_IMUL,S_L,
  1047. tarraydef(tvarsym(p).vartype.def).elesize,R_EDI));
  1048. end;
  1049. {$ifndef NOTARGETWIN32}
  1050. { windows guards only a few pages for stack growing, }
  1051. { so we have to access every page first }
  1052. if target_info.target=target_i386_win32 then
  1053. begin
  1054. getlabel(again);
  1055. getlabel(ok);
  1056. emitlab(again);
  1057. exprasmList.concat(Taicpu.op_const_reg(A_CMP,S_L,winstackpagesize,R_EDI));
  1058. emitjmp(C_C,ok);
  1059. exprasmList.concat(Taicpu.op_const_reg(A_SUB,S_L,winstackpagesize-4,R_ESP));
  1060. exprasmList.concat(Taicpu.op_reg(A_PUSH,S_L,R_EAX));
  1061. exprasmList.concat(Taicpu.op_const_reg(A_SUB,S_L,winstackpagesize,R_EDI));
  1062. emitjmp(C_None,again);
  1063. emitlab(ok);
  1064. exprasmList.concat(Taicpu.op_reg_reg(A_SUB,S_L,R_EDI,R_ESP));
  1065. rg.ungetregisterint(exprasmlist,R_EDI);
  1066. { now reload EDI }
  1067. reference_reset_base(r,procinfo^.framepointer,tvarsym(p).address+4+procinfo^.para_offset);
  1068. rg.getexplicitregisterint(exprasmlist,R_EDI);
  1069. exprasmList.concat(Taicpu.op_ref_reg(A_MOV,S_L,r,R_EDI));
  1070. exprasmList.concat(Taicpu.op_reg(A_INC,S_L,R_EDI));
  1071. if (tarraydef(tvarsym(p).vartype.def).elesize<>1) then
  1072. begin
  1073. if ispowerof2(tarraydef(tvarsym(p).vartype.def).elesize, power) then
  1074. exprasmList.concat(Taicpu.op_const_reg(A_SHL,S_L,power,R_EDI))
  1075. else
  1076. exprasmList.concat(Taicpu.op_const_reg(A_IMUL,S_L,
  1077. tarraydef(tvarsym(p).vartype.def).elesize,R_EDI));
  1078. end;
  1079. end
  1080. else
  1081. {$endif NOTARGETWIN32}
  1082. exprasmList.concat(Taicpu.op_reg_reg(A_SUB,S_L,R_EDI,R_ESP));
  1083. { load destination }
  1084. exprasmList.concat(Taicpu.op_reg_reg(A_MOV,S_L,R_ESP,R_EDI));
  1085. { don't destroy the registers! }
  1086. exprasmList.concat(Taicpu.op_reg(A_PUSH,S_L,R_ECX));
  1087. exprasmList.concat(Taicpu.op_reg(A_PUSH,S_L,R_ESI));
  1088. { load count }
  1089. reference_reset_base(r,procinfo^.framepointer,tvarsym(p).address+4+procinfo^.para_offset);
  1090. exprasmList.concat(Taicpu.op_ref_reg(A_MOV,S_L,r,R_ECX));
  1091. { load source }
  1092. reference_reset_base(r,procinfo^.framepointer,tvarsym(p).address+procinfo^.para_offset);
  1093. exprasmList.concat(Taicpu.op_ref_reg(A_MOV,S_L,r,R_ESI));
  1094. { scheduled .... }
  1095. exprasmList.concat(Taicpu.op_reg(A_INC,S_L,R_ECX));
  1096. { calculate size }
  1097. len:=tarraydef(tvarsym(p).vartype.def).elesize;
  1098. opsize:=S_B;
  1099. if (len and 3)=0 then
  1100. begin
  1101. opsize:=S_L;
  1102. len:=len shr 2;
  1103. end
  1104. else
  1105. if (len and 1)=0 then
  1106. begin
  1107. opsize:=S_W;
  1108. len:=len shr 1;
  1109. end;
  1110. if ispowerof2(len, power) then
  1111. exprasmList.concat(Taicpu.op_const_reg(A_SHL,S_L,power,R_ECX))
  1112. else
  1113. exprasmList.concat(Taicpu.op_const_reg(A_IMUL,S_L,len,R_ECX));
  1114. exprasmList.concat(Taicpu.op_none(A_REP,S_NO));
  1115. case opsize of
  1116. S_B : exprasmList.concat(Taicpu.Op_none(A_MOVSB,S_NO));
  1117. S_W : exprasmList.concat(Taicpu.Op_none(A_MOVSW,S_NO));
  1118. S_L : exprasmList.concat(Taicpu.Op_none(A_MOVSD,S_NO));
  1119. end;
  1120. rg.ungetregisterint(exprasmlist,R_EDI);
  1121. exprasmList.concat(Taicpu.op_reg(A_POP,S_L,R_ESI));
  1122. exprasmList.concat(Taicpu.op_reg(A_POP,S_L,R_ECX));
  1123. { patch the new address }
  1124. reference_reset_base(r,procinfo^.framepointer,tvarsym(p).address+procinfo^.para_offset);
  1125. exprasmList.concat(Taicpu.op_reg_ref(A_MOV,S_L,R_ESP,r));
  1126. end
  1127. else
  1128. if is_shortstring(tvarsym(p).vartype.def) then
  1129. begin
  1130. reference_reset_base(href1,procinfo^.framepointer,tvarsym(p).address+procinfo^.para_offset);
  1131. reference_reset_base(href2,procinfo^.framepointer,-tvarsym(p).localvarsym.address+tvarsym(p).localvarsym.owner.address_fixup);
  1132. copyshortstring(href2,href1,tstringdef(tvarsym(p).vartype.def).len,true,false);
  1133. end
  1134. else
  1135. begin
  1136. reference_reset_base(href1,procinfo^.framepointer,tvarsym(p).address+procinfo^.para_offset);
  1137. reference_reset_base(href2,procinfo^.framepointer,-tvarsym(p).localvarsym.address+tvarsym(p).localvarsym.owner.address_fixup);
  1138. concatcopy(href1,href2,tvarsym(p).vartype.def.size,true,true);
  1139. end;
  1140. end;
  1141. end;
  1142. procedure inittempvariables;
  1143. var
  1144. hp : ptemprecord;
  1145. r : treference;
  1146. begin
  1147. hp:=tg.templist;
  1148. while assigned(hp) do
  1149. begin
  1150. if hp^.temptype in [tt_ansistring,tt_freeansistring,
  1151. tt_widestring,tt_freewidestring,
  1152. tt_interfacecom] then
  1153. begin
  1154. procinfo^.flags:=procinfo^.flags or pi_needs_implicit_finally;
  1155. reference_reset_base(r,procinfo^.framepointer,hp^.pos);
  1156. emit_const_ref(A_MOV,S_L,0,r);
  1157. end;
  1158. hp:=hp^.next;
  1159. end;
  1160. end;
  1161. procedure finalizetempvariables;
  1162. var
  1163. hp : ptemprecord;
  1164. hr : treference;
  1165. begin
  1166. hp:=tg.templist;
  1167. while assigned(hp) do
  1168. begin
  1169. if hp^.temptype in [tt_ansistring,tt_freeansistring] then
  1170. begin
  1171. procinfo^.flags:=procinfo^.flags or pi_needs_implicit_finally;
  1172. reference_reset_base(hr,procinfo^.framepointer,hp^.pos);
  1173. emitpushreferenceaddr(hr);
  1174. emitcall('FPC_ANSISTR_DECR_REF');
  1175. end
  1176. else if hp^.temptype in [tt_widestring,tt_freewidestring] then
  1177. begin
  1178. procinfo^.flags:=procinfo^.flags or pi_needs_implicit_finally;
  1179. reference_reset_base(hr,procinfo^.framepointer,hp^.pos);
  1180. emitpushreferenceaddr(hr);
  1181. emitcall('FPC_WIDESTR_DECR_REF');
  1182. end
  1183. else if hp^.temptype=tt_interfacecom then
  1184. begin
  1185. procinfo^.flags:=procinfo^.flags or pi_needs_implicit_finally;
  1186. reference_reset_base(hr,procinfo^.framepointer,hp^.pos);
  1187. emitpushreferenceaddr(hr);
  1188. emitcall('FPC_INTF_DECR_REF');
  1189. end;
  1190. hp:=hp^.next;
  1191. end;
  1192. end;
  1193. {$ifdef dummy}
  1194. var
  1195. ls : longint;
  1196. procedure largest_size(p : tnamedindexitem);
  1197. begin
  1198. if (tsym(p).typ=varsym) and
  1199. (tvarsym(p).getvaluesize>ls) then
  1200. ls:=tvarsym(p).getvaluesize;
  1201. end;
  1202. {$endif dummy}
  1203. procedure alignstack(alist : TAAsmoutput);
  1204. begin
  1205. {$ifdef dummy}
  1206. if (cs_optimize in aktglobalswitches) and
  1207. (aktoptprocessor in [classp5,classp6]) then
  1208. begin
  1209. ls:=0;
  1210. aktprocdef.localst.foreach({$ifndef TP}@{$endif}largest_size);
  1211. if ls>=8 then
  1212. aList.insert(Taicpu.Op_const_reg(A_AND,S_L,aword(-8),R_ESP));
  1213. end;
  1214. {$endif dummy}
  1215. end;
  1216. procedure genentrycode(alist : TAAsmoutput;make_global:boolean;
  1217. stackframe:longint;
  1218. var parasize:longint;var nostackframe:boolean;
  1219. inlined : boolean);
  1220. {
  1221. Generates the entry code for a procedure
  1222. }
  1223. var
  1224. hs : string;
  1225. {$ifdef GDB}
  1226. stab_function_name : tai_stab_function_name;
  1227. {$endif GDB}
  1228. hr : treference;
  1229. p : tsymtable;
  1230. r : treference;
  1231. oldlist,
  1232. oldexprasmlist : TAAsmoutput;
  1233. again : tasmlabel;
  1234. i : longint;
  1235. tempbuf,tempaddr : treference;
  1236. begin
  1237. oldexprasmlist:=exprasmlist;
  1238. exprasmlist:=alist;
  1239. if (not inlined) and (aktprocdef.proctypeoption=potype_proginit) then
  1240. begin
  1241. emitinsertcall('FPC_INITIALIZEUNITS');
  1242. { add global threadvars }
  1243. oldlist:=exprasmlist;
  1244. exprasmlist:=TAAsmoutput.Create;
  1245. p:=symtablestack;
  1246. while assigned(p) do
  1247. begin
  1248. p.foreach_static({$ifndef TP}@{$endif}initialize_threadvar);
  1249. p:=p.next;
  1250. end;
  1251. oldList.insertlist(exprasmlist);
  1252. exprasmlist.free;
  1253. exprasmlist:=oldlist;
  1254. { add local threadvars in units (only if needed because not all platforms
  1255. have threadvar support) }
  1256. if have_local_threadvars then
  1257. emitinsertcall('FPC_INITIALIZELOCALTHREADVARS');
  1258. { initialize profiling for win32 }
  1259. if (target_info.target in [target_I386_WIN32,target_I386_wdosx]) and
  1260. (cs_profile in aktmoduleswitches) then
  1261. emitinsertcall('__monstartup');
  1262. end;
  1263. {$ifdef GDB}
  1264. if (not inlined) and (cs_debuginfo in aktmoduleswitches) then
  1265. exprasmList.insert(Tai_force_line.Create);
  1266. {$endif GDB}
  1267. { a constructor needs a help procedure }
  1268. if (aktprocdef.proctypeoption=potype_constructor) then
  1269. begin
  1270. if is_class(procinfo^._class) then
  1271. begin
  1272. procinfo^.flags:=procinfo^.flags or pi_needs_implicit_finally;
  1273. exprasmList.insert(Taicpu.Op_cond_sym(A_Jcc,C_Z,S_NO,faillabel));
  1274. emitinsertcall('FPC_NEW_CLASS');
  1275. end
  1276. else if is_object(procinfo^._class) then
  1277. begin
  1278. exprasmList.insert(Taicpu.Op_cond_sym(A_Jcc,C_Z,S_NO,faillabel));
  1279. emitinsertcall('FPC_HELP_CONSTRUCTOR');
  1280. rg.getexplicitregisterint(exprasmlist,R_EDI);
  1281. exprasmList.insert(Taicpu.Op_const_reg(A_MOV,S_L,procinfo^._class.vmt_offset,R_EDI));
  1282. end
  1283. else
  1284. Internalerror(200006161);
  1285. end;
  1286. { don't load ESI, does the caller }
  1287. { we must do it for local function }
  1288. { that can be called from a foreach_static }
  1289. { of another object than self !! PM }
  1290. if assigned(procinfo^._class) and { !!!!! shouldn't we load ESI always? }
  1291. (lexlevel>normal_function_level) then
  1292. maybe_loadself;
  1293. { When message method contains self as a parameter,
  1294. we must load it into ESI }
  1295. If (po_containsself in aktprocdef.procoptions) then
  1296. begin
  1297. reference_reset_base(hr,procinfo^.framepointer,procinfo^.selfpointer_offset);
  1298. exprasmList.insert(Taicpu.Op_ref_reg(A_MOV,S_L,hr,R_ESI));
  1299. exprasmList.insert(Tairegalloc.Alloc(R_ESI));
  1300. end;
  1301. { should we save edi,esi,ebx like C ? }
  1302. if (po_savestdregs in aktprocdef.procoptions) then
  1303. begin
  1304. if (R_EBX in aktprocdef.usedregisters) then
  1305. exprasmList.insert(Taicpu.Op_reg(A_PUSH,S_L,R_EBX));
  1306. exprasmList.insert(Taicpu.Op_reg(A_PUSH,S_L,R_ESI));
  1307. exprasmList.insert(Taicpu.Op_reg(A_PUSH,S_L,R_EDI));
  1308. end;
  1309. { for the save all registers we can simply use a pusha,popa which
  1310. push edi,esi,ebp,esp(ignored),ebx,edx,ecx,eax }
  1311. if (po_saveregisters in aktprocdef.procoptions) then
  1312. begin
  1313. exprasmList.insert(Taicpu.Op_none(A_PUSHA,S_L));
  1314. end;
  1315. { omit stack frame ? }
  1316. if (not inlined) then
  1317. if (procinfo^.framepointer=STACK_POINTER_REG) then
  1318. begin
  1319. CGMessage(cg_d_stackframe_omited);
  1320. nostackframe:=true;
  1321. if (aktprocdef.proctypeoption in [potype_unitinit,potype_proginit,potype_unitfinalize]) then
  1322. parasize:=0
  1323. else
  1324. parasize:=aktprocdef.parast.datasize+procinfo^.para_offset-4;
  1325. if stackframe<>0 then
  1326. exprasmList.insert(Taicpu.op_const_reg(A_SUB,S_L,stackframe,R_ESP));
  1327. end
  1328. else
  1329. begin
  1330. alignstack(alist);
  1331. if (aktprocdef.proctypeoption in [potype_unitinit,potype_proginit,potype_unitfinalize]) then
  1332. parasize:=0
  1333. else
  1334. parasize:=aktprocdef.parast.datasize+procinfo^.para_offset-target_info.first_parm_offset;
  1335. nostackframe:=false;
  1336. if stackframe<>0 then
  1337. begin
  1338. {$ifndef __NOWINPECOFF__}
  1339. { windows guards only a few pages for stack growing, }
  1340. { so we have to access every page first }
  1341. if (target_info.target=target_i386_win32) and
  1342. (stackframe>=winstackpagesize) then
  1343. begin
  1344. if stackframe div winstackpagesize<=5 then
  1345. begin
  1346. exprasmList.insert(Taicpu.Op_const_reg(A_SUB,S_L,stackframe-4,R_ESP));
  1347. for i:=1 to stackframe div winstackpagesize do
  1348. begin
  1349. reference_reset_base(hr,R_ESP,stackframe-i*winstackpagesize);
  1350. exprasmList.concat(Taicpu.op_const_ref(A_MOV,S_L,0,hr));
  1351. end;
  1352. exprasmList.concat(Taicpu.op_reg(A_PUSH,S_L,R_EAX));
  1353. end
  1354. else
  1355. begin
  1356. getlabel(again);
  1357. rg.getexplicitregisterint(exprasmlist,R_EDI);
  1358. exprasmList.concat(Taicpu.op_const_reg(A_MOV,S_L,stackframe div winstackpagesize,R_EDI));
  1359. emitlab(again);
  1360. exprasmList.concat(Taicpu.op_const_reg(A_SUB,S_L,winstackpagesize-4,R_ESP));
  1361. exprasmList.concat(Taicpu.op_reg(A_PUSH,S_L,R_EAX));
  1362. exprasmList.concat(Taicpu.op_reg(A_DEC,S_L,R_EDI));
  1363. emitjmp(C_NZ,again);
  1364. rg.ungetregisterint(exprasmlist,R_EDI);
  1365. exprasmList.concat(Taicpu.op_const_reg(A_SUB,S_L,stackframe mod winstackpagesize,R_ESP));
  1366. end
  1367. end
  1368. else
  1369. {$endif __NOWINPECOFF__}
  1370. exprasmList.insert(Taicpu.Op_const_reg(A_SUB,S_L,stackframe,R_ESP));
  1371. if (cs_check_stack in aktlocalswitches) then
  1372. begin
  1373. emitinsertcall('FPC_STACKCHECK');
  1374. exprasmList.insert(Taicpu.Op_const(A_PUSH,S_L,stackframe));
  1375. end;
  1376. if cs_profile in aktmoduleswitches then
  1377. genprofilecode;
  1378. exprasmList.insert(Taicpu.Op_reg_reg(A_MOV,S_L,R_ESP,R_EBP));
  1379. exprasmList.insert(Taicpu.Op_reg(A_PUSH,S_L,R_EBP));
  1380. end { endif stackframe <> 0 }
  1381. else
  1382. begin
  1383. if cs_profile in aktmoduleswitches then
  1384. genprofilecode;
  1385. exprasmList.insert(Taicpu.Op_reg_reg(A_MOV,S_L,R_ESP,R_EBP));
  1386. exprasmList.insert(Taicpu.Op_reg(A_PUSH,S_L,R_EBP));
  1387. end;
  1388. end;
  1389. if (po_interrupt in aktprocdef.procoptions) then
  1390. generate_interrupt_stackframe_entry;
  1391. { initialize return value }
  1392. if (not is_void(aktprocdef.rettype.def)) and
  1393. (aktprocdef.rettype.def.needs_inittable) then
  1394. begin
  1395. procinfo^.flags:=procinfo^.flags or pi_needs_implicit_finally;
  1396. reference_reset(r);
  1397. r.offset:=procinfo^.return_offset;
  1398. r.base:=procinfo^.framepointer;
  1399. initialize(aktprocdef.rettype.def,r,ret_in_param(aktprocdef.rettype.def));
  1400. end;
  1401. { initialisize local data like ansistrings }
  1402. case aktprocdef.proctypeoption of
  1403. potype_unitinit:
  1404. begin
  1405. { using current_module.globalsymtable is hopefully }
  1406. { more robust than symtablestack and symtablestack.next }
  1407. tsymtable(current_module.globalsymtable).foreach_static({$ifndef TP}@{$endif}initialize_data);
  1408. tsymtable(current_module.localsymtable).foreach_static({$ifndef TP}@{$endif}initialize_data);
  1409. end;
  1410. { units have seperate code for initilization and finalization }
  1411. potype_unitfinalize: ;
  1412. else
  1413. aktprocdef.localst.foreach_static({$ifndef TP}@{$endif}initialize_data);
  1414. end;
  1415. { initialisizes temp. ansi/wide string data }
  1416. inittempvariables;
  1417. { generate copies of call by value parameters }
  1418. if not(po_assembler in aktprocdef.procoptions) and
  1419. not(aktprocdef.proccalloption in [pocall_cdecl,pocall_cppdecl,pocall_palmossyscall,pocall_system]) then
  1420. aktprocdef.parast.foreach_static({$ifndef TP}@{$endif}copyvalueparas);
  1421. if assigned( aktprocdef.parast) then
  1422. aktprocdef.parast.foreach_static({$ifndef TP}@{$endif}init_paras);
  1423. { do we need an exception frame because of ansi/widestrings/interfaces ? }
  1424. if not inlined and
  1425. ((procinfo^.flags and pi_needs_implicit_finally)<>0) and
  1426. { but it's useless in init/final code of units }
  1427. not(aktprocdef.proctypeoption in [potype_unitfinalize,potype_unitinit]) then
  1428. begin
  1429. include(rg.usedinproc,R_EAX);
  1430. exprasmList.concat(Taicpu.op_const_reg(A_SUB,S_L,36,R_ESP));
  1431. exprasmList.concat(Taicpu.op_reg_reg(A_MOV,S_L,R_ESP,R_EDI));
  1432. reference_reset(tempaddr);
  1433. tempaddr.base:=R_EDI;
  1434. emitpushreferenceaddr(tempaddr);
  1435. reference_reset(tempbuf);
  1436. tempbuf.base:=R_EDI;
  1437. tempbuf.offset:=12;
  1438. emitpushreferenceaddr(tempbuf);
  1439. { Type of stack-frame must be pushed}
  1440. exprasmList.concat(Taicpu.op_const(A_PUSH,S_L,1));
  1441. emitcall('FPC_PUSHEXCEPTADDR');
  1442. exprasmList.concat(Taicpu.op_reg(A_PUSH,S_L,R_EAX));
  1443. emitcall('FPC_SETJMP');
  1444. exprasmList.concat(Taicpu.op_reg(A_PUSH,S_L,R_EAX));
  1445. exprasmList.concat(Taicpu.op_reg_reg(A_TEST,S_L,R_EAX,R_EAX));
  1446. emitjmp(C_NE,aktexitlabel);
  1447. { probably we've to reload self here }
  1448. maybe_loadself;
  1449. end;
  1450. if not inlined then
  1451. begin
  1452. if (cs_profile in aktmoduleswitches) or
  1453. (aktprocdef.owner.symtabletype=globalsymtable) or
  1454. (assigned(procinfo^._class) and (procinfo^._class.owner.symtabletype=globalsymtable)) then
  1455. make_global:=true;
  1456. hs:=aktprocdef.aliasnames.getfirst;
  1457. {$ifdef GDB}
  1458. if (cs_debuginfo in aktmoduleswitches) and target_info.use_function_relative_addresses then
  1459. stab_function_name := Tai_stab_function_name.Create(strpnew(hs));
  1460. {$EndIf GDB}
  1461. while hs<>'' do
  1462. begin
  1463. if make_global then
  1464. exprasmList.insert(Tai_symbol.Createname_global(hs,0))
  1465. else
  1466. exprasmList.insert(Tai_symbol.Createname(hs,0));
  1467. {$ifdef GDB}
  1468. if (cs_debuginfo in aktmoduleswitches) and
  1469. target_info.use_function_relative_addresses then
  1470. exprasmList.insert(Tai_stab_function_name.Create(strpnew(hs)));
  1471. {$endif GDB}
  1472. hs:=aktprocdef.aliasnames.getfirst;
  1473. end;
  1474. if make_global or ((procinfo^.flags and pi_is_global) <> 0) then
  1475. aktprocsym.is_global := True;
  1476. {$ifdef GDB}
  1477. if (cs_debuginfo in aktmoduleswitches) then
  1478. begin
  1479. if target_info.use_function_relative_addresses then
  1480. exprasmList.insert(stab_function_name);
  1481. exprasmList.insert(Tai_stabs.Create(aktprocdef.stabstring));
  1482. aktprocsym.isstabwritten:=true;
  1483. end;
  1484. {$endif GDB}
  1485. { Align, gprof uses 16 byte granularity }
  1486. if (cs_profile in aktmoduleswitches) then
  1487. exprasmList.insert(Tai_align.Create_op(16,$90))
  1488. else
  1489. exprasmList.insert(Tai_align.Create(aktalignment.procalign));
  1490. end;
  1491. if inlined then
  1492. load_regvars(exprasmlist,nil);
  1493. exprasmlist:=oldexprasmlist;
  1494. end;
  1495. procedure handle_return_value(inlined : boolean;var uses_eax,uses_edx : boolean);
  1496. var
  1497. hr : treference;
  1498. begin
  1499. if not is_void(aktprocdef.rettype.def) then
  1500. begin
  1501. {if ((procinfo^.flags and pi_operator)<>0) and
  1502. assigned(otsym) then
  1503. procinfo^.funcret_is_valid:=
  1504. procinfo^.funcret_is_valid or (otsym.refs>0);}
  1505. if (tfuncretsym(aktprocdef.funcretsym).funcretstate<>vs_assigned) and not inlined { and
  1506. ((procinfo^.flags and pi_uses_asm)=0)} then
  1507. CGMessage(sym_w_function_result_not_set);
  1508. reference_reset_base(hr,procinfo^.framepointer,procinfo^.return_offset);
  1509. if (aktprocdef.rettype.def.deftype in [orddef,enumdef]) then
  1510. begin
  1511. uses_eax:=true;
  1512. exprasmList.concat(Tairegalloc.Alloc(R_EAX));
  1513. case aktprocdef.rettype.def.size of
  1514. 8:
  1515. begin
  1516. emit_ref_reg(A_MOV,S_L,hr,R_EAX);
  1517. reference_reset_base(hr,procinfo^.framepointer,procinfo^.return_offset+4);
  1518. exprasmList.concat(Tairegalloc.Alloc(R_EDX));
  1519. emit_ref_reg(A_MOV,S_L,hr,R_EDX);
  1520. uses_edx:=true;
  1521. end;
  1522. 4:
  1523. emit_ref_reg(A_MOV,S_L,hr,R_EAX);
  1524. 2:
  1525. emit_ref_reg(A_MOV,S_W,hr,R_AX);
  1526. 1:
  1527. emit_ref_reg(A_MOV,S_B,hr,R_AL);
  1528. end;
  1529. end
  1530. else
  1531. if ret_in_acc(aktprocdef.rettype.def) then
  1532. begin
  1533. uses_eax:=true;
  1534. exprasmList.concat(Tairegalloc.Alloc(R_EAX));
  1535. emit_ref_reg(A_MOV,S_L,hr,R_EAX);
  1536. end
  1537. else
  1538. if (aktprocdef.rettype.def.deftype=floatdef) then
  1539. begin
  1540. cg.a_loadfpu_ref_reg(exprasmlist,
  1541. def_cgsize(aktprocdef.rettype.def),hr,R_ST);
  1542. end;
  1543. end
  1544. end;
  1545. procedure handle_fast_exit_return_value;
  1546. var
  1547. hr : treference;
  1548. begin
  1549. if not is_void(aktprocdef.rettype.def) then
  1550. begin
  1551. reference_reset_base(hr,procinfo^.framepointer,procinfo^.return_offset);
  1552. if (aktprocdef.rettype.def.deftype in [orddef,enumdef]) then
  1553. begin
  1554. case aktprocdef.rettype.def.size of
  1555. 8:
  1556. begin
  1557. emit_reg_ref(A_MOV,S_L,R_EAX,hr);
  1558. reference_reset_base(hr,procinfo^.framepointer,procinfo^.return_offset+4);
  1559. emit_reg_ref(A_MOV,S_L,R_EDX,hr);
  1560. end;
  1561. 4:
  1562. emit_reg_ref(A_MOV,S_L,R_EAX,hr);
  1563. 2:
  1564. emit_reg_ref(A_MOV,S_W,R_AX,hr);
  1565. 1:
  1566. emit_reg_ref(A_MOV,S_B,R_AL,hr);
  1567. end;
  1568. end
  1569. else
  1570. if ret_in_acc(aktprocdef.rettype.def) then
  1571. begin
  1572. emit_reg_ref(A_MOV,S_L,R_EAX,hr);
  1573. end
  1574. else
  1575. if (aktprocdef.rettype.def.deftype=floatdef) then
  1576. begin
  1577. cg.a_loadfpu_reg_ref(exprasmlist,
  1578. def_cgsize(aktprocdef.rettype.def),
  1579. R_ST,hr);
  1580. end;
  1581. end
  1582. end;
  1583. procedure genexitcode(alist : TAAsmoutput;parasize:longint;nostackframe,inlined:boolean);
  1584. var
  1585. {$ifdef GDB}
  1586. mangled_length : longint;
  1587. p : pchar;
  1588. st : string[2];
  1589. {$endif GDB}
  1590. stabsendlabel,nofinal,okexitlabel,
  1591. noreraiselabel,nodestroycall : tasmlabel;
  1592. hr : treference;
  1593. uses_eax,uses_edx,uses_esi : boolean;
  1594. oldexprasmlist : TAAsmoutput;
  1595. ai : taicpu;
  1596. pd : tprocdef;
  1597. begin
  1598. oldexprasmlist:=exprasmlist;
  1599. exprasmlist:=alist;
  1600. if aktexit2label.is_used and
  1601. ((procinfo^.flags and (pi_needs_implicit_finally or pi_uses_exceptions)) <> 0) then
  1602. begin
  1603. exprasmlist.concat(taicpu.op_sym(A_JMP,S_NO,aktexitlabel));
  1604. exprasmlist.concat(tai_label.create(aktexit2label));
  1605. handle_fast_exit_return_value;
  1606. end;
  1607. if aktexitlabel.is_used then
  1608. exprasmList.concat(Tai_label.Create(aktexitlabel));
  1609. cleanup_regvars(alist);
  1610. { call the destructor help procedure }
  1611. if (aktprocdef.proctypeoption=potype_destructor) and
  1612. assigned(procinfo^._class) then
  1613. begin
  1614. if is_class(procinfo^._class) then
  1615. begin
  1616. emitinsertcall('FPC_DISPOSE_CLASS');
  1617. end
  1618. else if is_object(procinfo^._class) then
  1619. begin
  1620. emitinsertcall('FPC_HELP_DESTRUCTOR');
  1621. rg.getexplicitregisterint(exprasmlist,R_EDI);
  1622. exprasmList.insert(Taicpu.Op_const_reg(A_MOV,S_L,procinfo^._class.vmt_offset,R_EDI));
  1623. { must the object be finalized ? }
  1624. if procinfo^._class.needs_inittable then
  1625. begin
  1626. getlabel(nofinal);
  1627. exprasmList.insert(Tai_label.Create(nofinal));
  1628. emitinsertcall('FPC_FINALIZE');
  1629. rg.ungetregisterint(exprasmlist,R_EDI);
  1630. exprasmList.insert(Taicpu.Op_reg(A_PUSH,S_L,R_ESI));
  1631. exprasmList.insert(Taicpu.Op_sym(A_PUSH,S_L,procinfo^._class.get_rtti_label(initrtti)));
  1632. ai:=Taicpu.Op_sym(A_Jcc,S_NO,nofinal);
  1633. ai.SetCondition(C_Z);
  1634. exprasmList.insert(ai);
  1635. reference_reset_base(hr,R_EBP,8);
  1636. exprasmList.insert(Taicpu.Op_const_ref(A_CMP,S_L,0,hr));
  1637. end;
  1638. end
  1639. else
  1640. begin
  1641. Internalerror(200006161);
  1642. end;
  1643. end;
  1644. { finalize temporary data }
  1645. finalizetempvariables;
  1646. { finalize local data like ansistrings}
  1647. case aktprocdef.proctypeoption of
  1648. potype_unitfinalize:
  1649. begin
  1650. { using current_module.globalsymtable is hopefully }
  1651. { more robust than symtablestack and symtablestack.next }
  1652. tsymtable(current_module.globalsymtable).foreach_static({$ifndef TP}@{$endif}finalize_data);
  1653. tsymtable(current_module.localsymtable).foreach_static({$ifndef TP}@{$endif}finalize_data);
  1654. end;
  1655. { units have seperate code for initialization and finalization }
  1656. potype_unitinit: ;
  1657. else
  1658. aktprocdef.localst.foreach_static({$ifndef TP}@{$endif}finalize_data);
  1659. end;
  1660. { finalize paras data }
  1661. if assigned(aktprocdef.parast) then
  1662. aktprocdef.parast.foreach_static({$ifndef TP}@{$endif}final_paras);
  1663. { do we need to handle exceptions because of ansi/widestrings ? }
  1664. if not inlined and
  1665. ((procinfo^.flags and pi_needs_implicit_finally)<>0) and
  1666. { but it's useless in init/final code of units }
  1667. not(aktprocdef.proctypeoption in [potype_unitfinalize,potype_unitinit]) then
  1668. begin
  1669. { the exception helper routines modify all registers }
  1670. aktprocdef.usedregisters:=all_registers;
  1671. getlabel(noreraiselabel);
  1672. emitcall('FPC_POPADDRSTACK');
  1673. exprasmList.concat(Tairegalloc.Alloc(R_EAX));
  1674. exprasmList.concat(Taicpu.op_reg(A_POP,S_L,R_EAX));
  1675. exprasmList.concat(Taicpu.op_reg_reg(A_TEST,S_L,R_EAX,R_EAX));
  1676. rg.ungetregisterint(exprasmlist,R_EAX);
  1677. emitjmp(C_E,noreraiselabel);
  1678. if (aktprocdef.proctypeoption=potype_constructor) then
  1679. begin
  1680. if assigned(procinfo^._class) then
  1681. begin
  1682. pd:=procinfo^._class.searchdestructor;
  1683. if assigned(pd) then
  1684. begin
  1685. getlabel(nodestroycall);
  1686. reference_reset_base(hr,procinfo^.framepointer,procinfo^.selfpointer_offset);
  1687. emit_const_ref(A_CMP,S_L,0,hr);
  1688. emitjmp(C_E,nodestroycall);
  1689. if is_class(procinfo^._class) then
  1690. begin
  1691. emit_const(A_PUSH,S_L,1);
  1692. emit_reg(A_PUSH,S_L,R_ESI);
  1693. end
  1694. else if is_object(procinfo^._class) then
  1695. begin
  1696. emit_reg(A_PUSH,S_L,R_ESI);
  1697. emit_sym(A_PUSH,S_L,newasmsymbol(procinfo^._class.vmt_mangledname));
  1698. end
  1699. else
  1700. begin
  1701. Internalerror(200006161);
  1702. end;
  1703. if (po_virtualmethod in pd.procoptions) then
  1704. begin
  1705. reference_reset_base(hr,R_ESI,0);
  1706. emit_ref_reg(A_MOV,S_L,hr,R_EDI);
  1707. reference_reset_base(hr,R_EDI,procinfo^._class.vmtmethodoffset(pd.extnumber));
  1708. emit_ref(A_CALL,S_NO,hr);
  1709. end
  1710. else
  1711. emitcall(pd.mangledname);
  1712. { not necessary because the result is never assigned in the
  1713. case of an exception (FK)
  1714. emit_const_reg(A_MOV,S_L,0,R_ESI);
  1715. emit_const_ref(A_MOV,S_L,0,reference_reset_base(procinfo^.framepointer,8));
  1716. }
  1717. emitlab(nodestroycall);
  1718. end;
  1719. end
  1720. end
  1721. else
  1722. { must be the return value finalized before reraising the exception? }
  1723. if (not is_void(aktprocdef.rettype.def)) and
  1724. (aktprocdef.rettype.def.needs_inittable) and
  1725. ((aktprocdef.rettype.def.deftype<>objectdef) or
  1726. not is_class(aktprocdef.rettype.def)) then
  1727. begin
  1728. reference_reset(hr);
  1729. hr.offset:=procinfo^.return_offset;
  1730. hr.base:=procinfo^.framepointer;
  1731. finalize(aktprocdef.rettype.def,hr,ret_in_param(aktprocdef.rettype.def));
  1732. end;
  1733. emitcall('FPC_RERAISE');
  1734. emitlab(noreraiselabel);
  1735. end;
  1736. { call __EXIT for main program }
  1737. if (not DLLsource) and (not inlined) and (aktprocdef.proctypeoption=potype_proginit) then
  1738. begin
  1739. emitcall('FPC_DO_EXIT');
  1740. end;
  1741. { handle return value, this is not done for assembler routines when
  1742. they didn't reference the result variable }
  1743. uses_eax:=false;
  1744. uses_edx:=false;
  1745. uses_esi:=false;
  1746. if not(po_assembler in aktprocdef.procoptions) or
  1747. (assigned(aktprocdef.funcretsym) and
  1748. (tfuncretsym(aktprocdef.funcretsym).refcount>1)) then
  1749. begin
  1750. if (aktprocdef.proctypeoption<>potype_constructor) then
  1751. handle_return_value(inlined,uses_eax,uses_edx)
  1752. else
  1753. begin
  1754. { successful constructor deletes the zero flag }
  1755. { and returns self in eax }
  1756. { eax must be set to zero if the allocation failed !!! }
  1757. getlabel(okexitlabel);
  1758. emitjmp(C_NONE,okexitlabel);
  1759. emitlab(faillabel);
  1760. if is_class(procinfo^._class) then
  1761. begin
  1762. reference_reset_base(hr,procinfo^.framepointer,8);
  1763. emit_ref_reg(A_MOV,S_L,hr,R_ESI);
  1764. emitcall('FPC_HELP_FAIL_CLASS');
  1765. end
  1766. else if is_object(procinfo^._class) then
  1767. begin
  1768. reference_reset_base(hr,procinfo^.framepointer,12);
  1769. emit_ref_reg(A_MOV,S_L,hr,R_ESI);
  1770. rg.getexplicitregisterint(exprasmlist,R_EDI);
  1771. emit_const_reg(A_MOV,S_L,procinfo^._class.vmt_offset,R_EDI);
  1772. emitcall('FPC_HELP_FAIL');
  1773. rg.ungetregisterint(exprasmlist,R_EDI);
  1774. end
  1775. else
  1776. Internalerror(200006161);
  1777. emitlab(okexitlabel);
  1778. { for classes this is done after the call to }
  1779. { AfterConstruction }
  1780. if is_object(procinfo^._class) then
  1781. begin
  1782. exprasmList.concat(Tairegalloc.Alloc(R_EAX));
  1783. emit_reg_reg(A_MOV,S_L,R_ESI,R_EAX);
  1784. uses_eax:=true;
  1785. end;
  1786. emit_reg_reg(A_TEST,S_L,R_ESI,R_ESI);
  1787. uses_esi:=true;
  1788. end;
  1789. end;
  1790. if aktexit2label.is_used and not aktexit2label.is_set then
  1791. emitlab(aktexit2label);
  1792. if ((cs_debuginfo in aktmoduleswitches) and not inlined) then
  1793. begin
  1794. getlabel(stabsendlabel);
  1795. emitlab(stabsendlabel);
  1796. end;
  1797. { gives problems for long mangled names }
  1798. {List.concat(Tai_symbol.Create(aktprocdef.mangledname+'_end'));}
  1799. { should we restore edi ? }
  1800. { for all i386 gcc implementations }
  1801. if (po_savestdregs in aktprocdef.procoptions) then
  1802. begin
  1803. if (R_EBX in aktprocdef.usedregisters) then
  1804. exprasmList.concat(Taicpu.Op_reg(A_POP,S_L,R_EBX));
  1805. exprasmList.concat(Taicpu.Op_reg(A_POP,S_L,R_ESI));
  1806. exprasmList.concat(Taicpu.Op_reg(A_POP,S_L,R_EDI));
  1807. { here we could reset R_EBX
  1808. but that is risky because it only works
  1809. if genexitcode is called after genentrycode
  1810. so lets skip this for the moment PM
  1811. aktprocdef.usedregisters:=
  1812. aktprocdef.usedregisters or not ($80 shr byte(R_EBX));
  1813. }
  1814. end;
  1815. { for the save all registers we can simply use a pusha,popa which
  1816. push edi,esi,ebp,esp(ignored),ebx,edx,ecx,eax }
  1817. if (po_saveregisters in aktprocdef.procoptions) then
  1818. begin
  1819. if uses_esi then
  1820. begin
  1821. reference_reset_base(hr,R_ESP,4);
  1822. exprasmList.concat(Taicpu.Op_reg_ref(A_MOV,S_L,R_ESI,hr));
  1823. end;
  1824. if uses_edx then
  1825. begin
  1826. reference_reset_base(hr,R_ESP,20);
  1827. exprasmList.concat(Taicpu.Op_reg_ref(A_MOV,S_L,R_EDX,hr));
  1828. end;
  1829. if uses_eax then
  1830. begin
  1831. reference_reset_base(hr,R_ESP,28);
  1832. exprasmList.concat(Taicpu.Op_reg_ref(A_MOV,S_L,R_EAX,hr));
  1833. end;
  1834. exprasmList.concat(Taicpu.Op_none(A_POPA,S_L));
  1835. { We add a NOP because of the 386DX CPU bugs with POPAD }
  1836. exprasmlist.concat(taicpu.op_none(A_NOP,S_L));
  1837. end;
  1838. if not(nostackframe) then
  1839. begin
  1840. if not inlined then
  1841. exprasmList.concat(Taicpu.Op_none(A_LEAVE,S_NO));
  1842. end
  1843. else
  1844. begin
  1845. if (tg.gettempsize<>0) and not inlined then
  1846. exprasmList.insert(Taicpu.op_const_reg(A_ADD,S_L,tg.gettempsize,R_ESP));
  1847. end;
  1848. { parameters are limited to 65535 bytes because }
  1849. { ret allows only imm16 }
  1850. if (parasize>65535) and not(po_clearstack in aktprocdef.procoptions) then
  1851. CGMessage(cg_e_parasize_too_big);
  1852. { at last, the return is generated }
  1853. if not inlined then
  1854. if (po_interrupt in aktprocdef.procoptions) then
  1855. begin
  1856. if uses_esi then
  1857. begin
  1858. reference_reset_base(hr,R_ESP,16);
  1859. exprasmList.concat(Taicpu.Op_reg_ref(A_MOV,S_L,R_ESI,hr));
  1860. end;
  1861. if uses_edx then
  1862. begin
  1863. reference_reset_base(hr,R_ESP,12);
  1864. exprasmList.concat(Tairegalloc.Alloc(R_EAX));
  1865. exprasmList.concat(Taicpu.Op_reg_ref(A_MOV,S_L,R_EDX,hr));
  1866. end;
  1867. if uses_eax then
  1868. begin
  1869. reference_reset_base(hr,R_ESP,0);
  1870. exprasmList.concat(Tairegalloc.Alloc(R_EAX));
  1871. exprasmList.concat(Taicpu.Op_reg_ref(A_MOV,S_L,R_EAX,hr));
  1872. end;
  1873. generate_interrupt_stackframe_exit;
  1874. end
  1875. else
  1876. begin
  1877. {Routines with the poclearstack flag set use only a ret.}
  1878. { also routines with parasize=0 }
  1879. if (po_clearstack in aktprocdef.procoptions) then
  1880. begin
  1881. {$ifndef OLD_C_STACK}
  1882. { complex return values are removed from stack in C code PM }
  1883. if ret_in_param(aktprocdef.rettype.def) then
  1884. exprasmList.concat(Taicpu.Op_const(A_RET,S_NO,4))
  1885. else
  1886. {$endif not OLD_C_STACK}
  1887. exprasmList.concat(Taicpu.Op_none(A_RET,S_NO));
  1888. end
  1889. else if (parasize=0) then
  1890. exprasmList.concat(Taicpu.Op_none(A_RET,S_NO))
  1891. else
  1892. exprasmList.concat(Taicpu.Op_const(A_RET,S_NO,parasize));
  1893. end;
  1894. if not inlined then
  1895. exprasmList.concat(Tai_symbol_end.Createname(aktprocdef.mangledname));
  1896. {$ifdef GDB}
  1897. if (cs_debuginfo in aktmoduleswitches) and not inlined then
  1898. begin
  1899. aktprocdef.concatstabto(exprasmlist);
  1900. if assigned(procinfo^._class) then
  1901. if (not assigned(procinfo^.parent) or
  1902. not assigned(procinfo^.parent^._class)) then
  1903. begin
  1904. if (po_classmethod in aktprocdef.procoptions) or
  1905. ((po_virtualmethod in aktprocdef.procoptions) and
  1906. (potype_constructor=aktprocdef.proctypeoption)) or
  1907. (po_staticmethod in aktprocdef.procoptions) then
  1908. begin
  1909. exprasmList.concat(Tai_stabs.Create(strpnew(
  1910. '"pvmt:p'+tstoreddef(pvmttype.def).numberstring+'",'+
  1911. tostr(N_tsym)+',0,0,'+tostr(procinfo^.selfpointer_offset))));
  1912. end
  1913. else
  1914. begin
  1915. if not(is_class(procinfo^._class)) then
  1916. st:='v'
  1917. else
  1918. st:='p';
  1919. exprasmList.concat(Tai_stabs.Create(strpnew(
  1920. '"$t:'+st+procinfo^._class.numberstring+'",'+
  1921. tostr(N_tsym)+',0,0,'+tostr(procinfo^.selfpointer_offset))));
  1922. end;
  1923. end
  1924. else
  1925. begin
  1926. if not is_class(procinfo^._class) then
  1927. st:='*'
  1928. else
  1929. st:='';
  1930. exprasmList.concat(Tai_stabs.Create(strpnew(
  1931. '"$t:r'+st+procinfo^._class.numberstring+'",'+
  1932. tostr(N_RSYM)+',0,0,'+tostr(GDB_i386index[R_ESI]))));
  1933. end;
  1934. { define calling EBP as pseudo local var PM }
  1935. { this enables test if the function is a local one !! }
  1936. if assigned(procinfo^.parent) and (lexlevel>normal_function_level) then
  1937. exprasmList.concat(Tai_stabs.Create(strpnew(
  1938. '"parent_ebp:'+tstoreddef(voidpointertype.def).numberstring+'",'+
  1939. tostr(N_LSYM)+',0,0,'+tostr(procinfo^.framepointer_offset))));
  1940. if (not is_void(aktprocdef.rettype.def)) then
  1941. begin
  1942. if ret_in_param(aktprocdef.rettype.def) then
  1943. exprasmList.concat(Tai_stabs.Create(strpnew(
  1944. '"'+aktprocsym.name+':X*'+tstoreddef(aktprocdef.rettype.def).numberstring+'",'+
  1945. tostr(N_tsym)+',0,0,'+tostr(procinfo^.return_offset))))
  1946. else
  1947. exprasmList.concat(Tai_stabs.Create(strpnew(
  1948. '"'+aktprocsym.name+':X'+tstoreddef(aktprocdef.rettype.def).numberstring+'",'+
  1949. tostr(N_tsym)+',0,0,'+tostr(procinfo^.return_offset))));
  1950. if (m_result in aktmodeswitches) then
  1951. if ret_in_param(aktprocdef.rettype.def) then
  1952. exprasmList.concat(Tai_stabs.Create(strpnew(
  1953. '"RESULT:X*'+tstoreddef(aktprocdef.rettype.def).numberstring+'",'+
  1954. tostr(N_tsym)+',0,0,'+tostr(procinfo^.return_offset))))
  1955. else
  1956. exprasmList.concat(Tai_stabs.Create(strpnew(
  1957. '"RESULT:X'+tstoreddef(aktprocdef.rettype.def).numberstring+'",'+
  1958. tostr(N_tsym)+',0,0,'+tostr(procinfo^.return_offset))));
  1959. end;
  1960. mangled_length:=length(aktprocdef.mangledname);
  1961. getmem(p,2*mangled_length+50);
  1962. strpcopy(p,'192,0,0,');
  1963. strpcopy(strend(p),aktprocdef.mangledname);
  1964. if (target_info.use_function_relative_addresses) then
  1965. begin
  1966. strpcopy(strend(p),'-');
  1967. strpcopy(strend(p),aktprocdef.mangledname);
  1968. end;
  1969. exprasmList.concat(Tai_stabn.Create(strnew(p)));
  1970. {List.concat(Tai_stabn.Create(strpnew('192,0,0,'
  1971. +aktprocdef.mangledname))));
  1972. p[0]:='2';p[1]:='2';p[2]:='4';
  1973. strpcopy(strend(p),'_end');}
  1974. strpcopy(p,'224,0,0,'+stabsendlabel.name);
  1975. if (target_info.use_function_relative_addresses) then
  1976. begin
  1977. strpcopy(strend(p),'-');
  1978. strpcopy(strend(p),aktprocdef.mangledname);
  1979. end;
  1980. exprasmList.concatlist(withdebuglist);
  1981. exprasmList.concat(Tai_stabn.Create(strnew(p)));
  1982. { strpnew('224,0,0,'
  1983. +aktprocdef.mangledname+'_end'))));}
  1984. freemem(p,2*mangled_length+50);
  1985. end;
  1986. {$endif GDB}
  1987. if inlined then
  1988. cleanup_regvars(exprasmlist);
  1989. exprasmlist:=oldexprasmlist;
  1990. end;
  1991. procedure genimplicitunitfinal(alist : TAAsmoutput);
  1992. begin
  1993. { using current_module.globalsymtable is hopefully }
  1994. { more robust than symtablestack and symtablestack.next }
  1995. tsymtable(current_module.globalsymtable).foreach_static({$ifndef TP}@{$endif}finalize_data);
  1996. tsymtable(current_module.localsymtable).foreach_static({$ifndef TP}@{$endif}finalize_data);
  1997. exprasmList.insert(Tai_symbol.Createname_global('FINALIZE$$'+current_module.modulename^,0));
  1998. exprasmList.insert(Tai_symbol.Createname_global(target_info.cprefix+current_module.modulename^+'_finalize',0));
  1999. {$ifdef GDB}
  2000. if (cs_debuginfo in aktmoduleswitches) and
  2001. target_info.use_function_relative_addresses then
  2002. exprasmList.insert(Tai_stab_function_name.Create(strpnew('FINALIZE$$'+current_module.modulename^)));
  2003. {$endif GDB}
  2004. exprasmList.concat(Taicpu.Op_none(A_RET,S_NO));
  2005. aList.concatlist(exprasmlist);
  2006. end;
  2007. procedure genimplicitunitinit(alist : TAAsmoutput);
  2008. begin
  2009. { using current_module.globalsymtable is hopefully }
  2010. { more robust than symtablestack and symtablestack.next }
  2011. tsymtable(current_module.globalsymtable).foreach_static({$ifndef TP}@{$endif}finalize_data);
  2012. tsymtable(current_module.localsymtable).foreach_static({$ifndef TP}@{$endif}finalize_data);
  2013. exprasmList.insert(Tai_symbol.Createname_global('INIT$$'+current_module.modulename^,0));
  2014. exprasmList.insert(Tai_symbol.Createname_global(target_info.cprefix+current_module.modulename^+'_init',0));
  2015. {$ifdef GDB}
  2016. if (cs_debuginfo in aktmoduleswitches) and
  2017. target_info.use_function_relative_addresses then
  2018. exprasmList.insert(Tai_stab_function_name.Create(strpnew('INIT$$'+current_module.modulename^)));
  2019. {$endif GDB}
  2020. exprasmList.concat(Taicpu.Op_none(A_RET,S_NO));
  2021. aList.concatlist(exprasmlist);
  2022. end;
  2023. {$ifdef test_dest_loc}
  2024. procedure mov_reg_to_dest(p : ptree; s : topsize; reg : tregister);
  2025. begin
  2026. if (dest_loc.loc=LOC_CREGISTER) or (dest_loc.loc=LOC_REGISTER) then
  2027. begin
  2028. emit_reg_reg(A_MOV,s,reg,dest_loc.register);
  2029. set_location(p^.location,dest_loc);
  2030. in_dest_loc:=true;
  2031. end
  2032. else
  2033. if (dest_loc.loc=LOC_REFERENCE) or (dest_loc.loc=LOC_CREFERENCE) then
  2034. begin
  2035. exprasmList.concat(Taicpu.Op_reg_ref(A_MOV,s,reg,dest_loc.reference));
  2036. set_location(p^.location,dest_loc);
  2037. in_dest_loc:=true;
  2038. end
  2039. else
  2040. internalerror(20080);
  2041. end;
  2042. {$endif test_dest_loc}
  2043. {$ifdef __NOWINPECOFF__}
  2044. {$undef __NOWINPECOFF__}
  2045. {$endif}
  2046. end.
  2047. {
  2048. $Log$
  2049. Revision 1.26 2002-04-21 15:29:53 carl
  2050. * changeregsize -> rg.makeregsize
  2051. Revision 1.25 2002/04/20 21:37:07 carl
  2052. + generic FPC_CHECKPOINTER
  2053. + first parameter offset in stack now portable
  2054. * rename some constants
  2055. + move some cpu stuff to other units
  2056. - remove unused constents
  2057. * fix stacksize for some targets
  2058. * fix generic size problems which depend now on EXTEND_SIZE constant
  2059. * removing frame pointer in routines is only available for : i386,m68k and vis targets
  2060. Revision 1.24 2002/04/19 15:39:34 peter
  2061. * removed some more routines from cga
  2062. * moved location_force_reg/mem to ncgutil
  2063. * moved arrayconstructnode secondpass to ncgld
  2064. Revision 1.23 2002/04/15 19:44:20 peter
  2065. * fixed stackcheck that would be called recursively when a stack
  2066. error was found
  2067. * generic changeregsize(reg,size) for i386 register resizing
  2068. * removed some more routines from cga unit
  2069. * fixed returnvalue handling
  2070. * fixed default stacksize of linux and go32v2, 8kb was a bit small :-)
  2071. Revision 1.22 2002/04/14 20:54:17 carl
  2072. + stack checking enabled for all targets (it is simulated now)
  2073. Revision 1.21 2002/04/04 19:06:08 peter
  2074. * removed unused units
  2075. * use tlocation.size in cg.a_*loc*() routines
  2076. Revision 1.20 2002/04/04 18:30:22 carl
  2077. + added wdosx support (patch from Pavel)
  2078. Revision 1.19 2002/04/02 17:11:33 peter
  2079. * tlocation,treference update
  2080. * LOC_CONSTANT added for better constant handling
  2081. * secondadd splitted in multiple routines
  2082. * location_force_reg added for loading a location to a register
  2083. of a specified size
  2084. * secondassignment parses now first the right and then the left node
  2085. (this is compatible with Kylix). This saves a lot of push/pop especially
  2086. with string operations
  2087. * adapted some routines to use the new cg methods
  2088. Revision 1.18 2002/03/31 20:26:37 jonas
  2089. + a_loadfpu_* and a_loadmm_* methods in tcg
  2090. * register allocation is now handled by a class and is mostly processor
  2091. independent (+rgobj.pas and i386/rgcpu.pas)
  2092. * temp allocation is now handled by a class (+tgobj.pas, -i386\tgcpu.pas)
  2093. * some small improvements and fixes to the optimizer
  2094. * some register allocation fixes
  2095. * some fpuvaroffset fixes in the unary minus node
  2096. * push/popusedregisters is now called rg.save/restoreusedregisters and
  2097. (for i386) uses temps instead of push/pop's when using -Op3 (that code is
  2098. also better optimizable)
  2099. * fixed and optimized register saving/restoring for new/dispose nodes
  2100. * LOC_FPU locations now also require their "register" field to be set to
  2101. R_ST, not R_ST0 (the latter is used for LOC_CFPUREGISTER locations only)
  2102. - list field removed of the tnode class because it's not used currently
  2103. and can cause hard-to-find bugs
  2104. Revision 1.17 2002/03/28 16:07:52 armin
  2105. + initialize threadvars defined local in units
  2106. Revision 1.16 2002/03/04 19:10:12 peter
  2107. * removed compiler warnings
  2108. Revision 1.15 2002/01/24 18:25:53 peter
  2109. * implicit result variable generation for assembler routines
  2110. * removed m_tp modeswitch, use m_tp7 or not(m_fpc) instead
  2111. Revision 1.14 2002/01/19 14:21:17 peter
  2112. * fixed init/final for value parameters
  2113. Revision 1.13 2001/12/30 17:24:45 jonas
  2114. * range checking is now processor independent (part in cgobj,
  2115. part in cg64f32) and should work correctly again (it needed
  2116. some changes after the changes of the low and high of
  2117. tordef's to int64)
  2118. * maketojumpbool() is now processor independent (in ncgutil)
  2119. * getregister32 is now called getregisterint
  2120. Revision 1.12 2001/12/29 15:28:58 jonas
  2121. * powerpc/cgcpu.pas compiles :)
  2122. * several powerpc-related fixes
  2123. * cpuasm unit is now based on common tainst unit
  2124. + nppcmat unit for powerpc (almost complete)
  2125. Revision 1.11 2001/11/18 18:59:59 peter
  2126. * changed aktprocsym to aktprocdef for stabs generation
  2127. Revision 1.10 2001/11/06 16:39:02 jonas
  2128. * moved call to "cleanup_regvars" to cga.pas for i386 because it has
  2129. to insert "fstp %st0" instructions after the exit label
  2130. Revision 1.9 2001/11/02 22:58:09 peter
  2131. * procsym definition rewrite
  2132. Revision 1.8 2001/10/25 21:22:41 peter
  2133. * calling convention rewrite
  2134. Revision 1.7 2001/10/20 17:22:57 peter
  2135. * concatcopy could release a wrong reference because the offset was
  2136. increased without restoring the original before the release of
  2137. a temp
  2138. Revision 1.6 2001/10/14 11:49:51 jonas
  2139. * finetuned register allocation info for assignments
  2140. Revision 1.5 2001/09/30 21:28:34 peter
  2141. * int64->boolean fixed
  2142. Revision 1.4 2001/08/30 20:13:57 peter
  2143. * rtti/init table updates
  2144. * rttisym for reusable global rtti/init info
  2145. * support published for interfaces
  2146. Revision 1.3 2001/08/29 12:01:47 jonas
  2147. + support for int64 LOC_REGISTERS in remove_non_regvars_from_loc
  2148. Revision 1.2 2001/08/26 13:36:52 florian
  2149. * some cg reorganisation
  2150. * some PPC updates
  2151. Revision 1.29 2001/08/12 20:23:02 peter
  2152. * netbsd doesn't use stackchecking
  2153. Revision 1.28 2001/08/07 18:47:13 peter
  2154. * merged netbsd start
  2155. * profile for win32
  2156. Revision 1.27 2001/08/06 21:40:49 peter
  2157. * funcret moved from tprocinfo to tprocdef
  2158. Revision 1.26 2001/07/30 20:59:28 peter
  2159. * m68k updates from v10 merged
  2160. Revision 1.25 2001/07/01 20:16:18 peter
  2161. * alignmentinfo record added
  2162. * -Oa argument supports more alignment settings that can be specified
  2163. per type: PROC,LOOP,VARMIN,VARMAX,CONSTMIN,CONSTMAX,RECORDMIN
  2164. RECORDMAX,LOCALMIN,LOCALMAX. It is possible to set the mimimum
  2165. required alignment and the maximum usefull alignment. The final
  2166. alignment will be choosen per variable size dependent on these
  2167. settings
  2168. Revision 1.24 2001/05/27 14:30:55 florian
  2169. + some widestring stuff added
  2170. Revision 1.23 2001/04/21 13:33:16 peter
  2171. * move winstackpagesize const to cgai386 to remove uses t_win32
  2172. Revision 1.22 2001/04/21 12:05:32 peter
  2173. * add nop after popa (merged)
  2174. Revision 1.21 2001/04/18 22:02:00 peter
  2175. * registration of targets and assemblers
  2176. Revision 1.20 2001/04/13 01:22:17 peter
  2177. * symtable change to classes
  2178. * range check generation and errors fixed, make cycle DEBUG=1 works
  2179. * memory leaks fixed
  2180. Revision 1.19 2001/04/05 21:33:07 peter
  2181. * fast exit fix merged
  2182. Revision 1.18 2001/04/02 21:20:35 peter
  2183. * resulttype rewrite
  2184. Revision 1.17 2001/01/05 17:36:58 florian
  2185. * the info about exception frames is stored now on the stack
  2186. instead on the heap
  2187. Revision 1.16 2000/12/25 00:07:31 peter
  2188. + new tlinkedlist class (merge of old tstringqueue,tcontainer and
  2189. tlinkedlist objects)
  2190. Revision 1.15 2000/12/05 11:44:32 jonas
  2191. + new integer regvar handling, should be much more efficient
  2192. Revision 1.14 2000/11/29 00:30:43 florian
  2193. * unused units removed from uses clause
  2194. * some changes for widestrings
  2195. Revision 1.13 2000/11/28 00:28:07 pierre
  2196. * stabs fixing
  2197. Revision 1.12 2000/11/22 15:12:06 jonas
  2198. * fixed inline-related problems (partially "merges")
  2199. Revision 1.11 2000/11/17 10:30:24 florian
  2200. * passing interfaces as parameters fixed
  2201. Revision 1.10 2000/11/07 23:40:48 florian
  2202. + AfterConstruction and BeforeDestruction impemented
  2203. Revision 1.9 2000/11/06 23:49:20 florian
  2204. * fixed init_paras call
  2205. Revision 1.8 2000/11/06 23:15:01 peter
  2206. * added copyvaluepara call again
  2207. Revision 1.7 2000/11/04 14:25:23 florian
  2208. + merged Attila's changes for interfaces, not tested yet
  2209. Revision 1.6 2000/10/31 22:02:55 peter
  2210. * symtable splitted, no real code changes
  2211. Revision 1.5 2000/10/24 22:23:04 peter
  2212. * emitcall -> emitinsertcall for profiling (merged)
  2213. Revision 1.4 2000/10/24 12:47:45 jonas
  2214. * allocate registers which hold function result
  2215. Revision 1.3 2000/10/24 08:54:25 michael
  2216. + Extra patch from peter
  2217. Revision 1.2 2000/10/24 07:20:03 pierre
  2218. * fix for bug 1193 (merged)
  2219. Revision 1.1 2000/10/15 09:47:42 peter
  2220. * moved to i386/
  2221. Revision 1.19 2000/10/14 10:14:46 peter
  2222. * moehrendorf oct 2000 rewrite
  2223. Revision 1.18 2000/10/10 14:55:28 jonas
  2224. * added missing regallocs for edi in emit_mov_ref_reg64 (merged)
  2225. Revision 1.17 2000/10/01 19:48:23 peter
  2226. * lot of compile updates for cg11
  2227. Revision 1.16 2000/09/30 16:08:45 peter
  2228. * more cg11 updates
  2229. Revision 1.15 2000/09/24 15:06:12 peter
  2230. * use defines.inc
  2231. Revision 1.14 2000/09/16 12:22:52 peter
  2232. * freebsd support merged
  2233. Revision 1.13 2000/08/27 16:11:49 peter
  2234. * moved some util functions from globals,cobjects to cutils
  2235. * splitted files into finput,fmodule
  2236. Revision 1.12 2000/08/24 19:07:54 peter
  2237. * don't initialize if localvarsym is set because that varsym will
  2238. already be initialized
  2239. * first initialize local data before copy of value para's (merged)
  2240. Revision 1.11 2000/08/19 20:09:33 peter
  2241. * check size after checking openarray in push_value_para (merged)
  2242. Revision 1.10 2000/08/16 13:06:06 florian
  2243. + support of 64 bit integer constants
  2244. Revision 1.9 2000/08/10 18:42:03 peter
  2245. * fixed for constants in emit_push_mem_size for go32v2 (merged)
  2246. Revision 1.8 2000/08/07 11:29:40 jonas
  2247. + emit_push_mem_size() which pushes a value in memory of a certain size
  2248. * pushsetelement() and pushvaluepara() use this new procedure, because
  2249. otherwise they could sometimes try to push data past the end of the
  2250. heap, causing a crash
  2251. (merged from fixes branch)
  2252. Revision 1.7 2000/08/03 13:17:25 jonas
  2253. + allow regvars to be used inside inlined procs, which required the
  2254. following changes:
  2255. + load regvars in genentrycode/free them in genexitcode (cgai386)
  2256. * moved all regvar related code to new regvars unit
  2257. + added pregvarinfo type to hcodegen
  2258. + added regvarinfo field to tprocinfo (symdef/symdefh)
  2259. * deallocate the regvars of the caller in secondprocinline before
  2260. inlining the called procedure and reallocate them afterwards
  2261. Revision 1.6 2000/08/02 08:05:04 jonas
  2262. * fixed web bug1087
  2263. * allocate R_ECX explicitely if it's used
  2264. (merged from fixes branch)
  2265. Revision 1.5 2000/07/27 09:25:05 jonas
  2266. * moved locflags2reg() procedure from cg386add to cgai386
  2267. + added locjump2reg() procedure to cgai386
  2268. * fixed internalerror(2002) when the result of a case expression has
  2269. LOC_JUMP
  2270. (all merged from fixes branch)
  2271. Revision 1.4 2000/07/21 15:14:02 jonas
  2272. + added is_addr field for labels, if they are only used for getting the address
  2273. (e.g. for io checks) and corresponding getaddrlabel() procedure
  2274. Revision 1.3 2000/07/13 12:08:25 michael
  2275. + patched to 1.1.0 with former 1.09patch from peter
  2276. Revision 1.2 2000/07/13 11:32:37 michael
  2277. + removed logs
  2278. }