cga.pas 87 KB

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