ncgcal.pas 74 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686
  1. {
  2. Id: ncgcal.pas,v 1.10 2002/08/17 09:23:35 florian Exp $
  3. Copyright (c) 1998-2002 by Florian Klaempfl
  4. Generate i386 assembler for in call nodes
  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 bymethodpointer
  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 ncgcal;
  19. {$i fpcdefs.inc}
  20. interface
  21. { $define AnsiStrRef}
  22. uses
  23. cpubase,
  24. globtype,
  25. symdef,node,ncal;
  26. type
  27. tcgcallparanode = class(tcallparanode)
  28. procedure secondcallparan(push_from_left_to_right:boolean;calloption:tproccalloption;
  29. para_alignment,para_offset : longint);override;
  30. end;
  31. tcgcallnode = class(tcallnode)
  32. protected
  33. funcretref : treference;
  34. refcountedtemp : treference;
  35. procedure handle_return_value(inlined,extended_new:boolean);
  36. procedure load_framepointer;virtual;abstract;
  37. procedure extra_interrupt_code;virtual;
  38. public
  39. procedure pass_2;override;
  40. end;
  41. tcgprocinlinenode = class(tprocinlinenode)
  42. procedure pass_2;override;
  43. end;
  44. implementation
  45. uses
  46. systems,
  47. cutils,verbose,globals,
  48. symconst,symbase,symsym,symtable,defutil,paramgr,
  49. {$ifdef GDB}
  50. {$ifdef delphi}
  51. sysutils,
  52. {$else}
  53. strings,
  54. {$endif}
  55. gdb,
  56. {$endif GDB}
  57. cginfo,cgbase,pass_2,
  58. cpuinfo,cpupi,aasmbase,aasmtai,aasmcpu,
  59. nmem,nld,ncnv,
  60. {$ifdef i386}
  61. cga,
  62. {$endif i386}
  63. cg64f32,ncgutil,cgobj,tgobj,regvars,rgobj,rgcpu,cgcpu;
  64. {*****************************************************************************
  65. TCGCALLPARANODE
  66. *****************************************************************************}
  67. procedure tcgcallparanode.secondcallparan(push_from_left_to_right:boolean;calloption:tproccalloption;para_alignment,para_offset : longint);
  68. { goes to pass 1 }
  69. procedure maybe_push_high;
  70. begin
  71. { open array ? }
  72. { defcoll.data can be nil for read/write }
  73. if assigned(paraitem.paratype.def) and
  74. assigned(hightree) then
  75. begin
  76. secondpass(hightree);
  77. { this is a longint anyway ! }
  78. push_value_para(hightree,calloption,para_offset,4,paraitem.paraloc);
  79. end;
  80. end;
  81. var
  82. otlabel,oflabel : tasmlabel;
  83. { temporary variables: }
  84. tempdeftype : tdeftype;
  85. tmpreg : tregister;
  86. href : treference;
  87. begin
  88. { push from left to right if specified }
  89. if push_from_left_to_right and assigned(right) then
  90. begin
  91. if (nf_varargs_para in flags) then
  92. tcallparanode(right).secondcallparan(push_from_left_to_right,
  93. calloption,para_alignment,para_offset)
  94. else
  95. tcallparanode(right).secondcallparan(push_from_left_to_right,
  96. calloption,para_alignment,para_offset);
  97. end;
  98. otlabel:=truelabel;
  99. oflabel:=falselabel;
  100. objectlibrary.getlabel(truelabel);
  101. objectlibrary.getlabel(falselabel);
  102. secondpass(left);
  103. { handle varargs first, because defcoll is not valid }
  104. if (nf_varargs_para in flags) then
  105. begin
  106. if paramanager.push_addr_param(left.resulttype.def,calloption) then
  107. begin
  108. inc(pushedparasize,4);
  109. cg.a_paramaddr_ref(exprasmlist,left.location.reference,paraitem.paraloc);
  110. location_release(exprasmlist,left.location);
  111. end
  112. else
  113. push_value_para(left,calloption,para_offset,para_alignment,paraitem.paraloc);
  114. end
  115. { filter array constructor with c styled args }
  116. else if is_array_constructor(left.resulttype.def) and (nf_cargs in left.flags) then
  117. begin
  118. { nothing, everything is already pushed }
  119. end
  120. { in codegen.handleread.. paraitem.data is set to nil }
  121. else if assigned(paraitem.paratype.def) and
  122. (paraitem.paratype.def.deftype=formaldef) then
  123. begin
  124. { allow passing of a constant to a const formaldef }
  125. if (paraitem.paratyp=vs_const) and
  126. (left.location.loc=LOC_CONSTANT) then
  127. location_force_mem(exprasmlist,left.location);
  128. { allow @var }
  129. inc(pushedparasize,4);
  130. if (left.nodetype=addrn) and
  131. (not(nf_procvarload in left.flags)) then
  132. begin
  133. if calloption=pocall_inline then
  134. begin
  135. reference_reset_base(href,procinfo.framepointer,para_offset-pushedparasize);
  136. cg.a_load_loc_ref(exprasmlist,left.location,href);
  137. end
  138. else
  139. cg.a_param_loc(exprasmlist,left.location,paraitem.paraloc);
  140. location_release(exprasmlist,left.location);
  141. end
  142. else
  143. begin
  144. if not(left.location.loc in [LOC_CREFERENCE,LOC_REFERENCE]) then
  145. begin
  146. CGMessage(type_e_mismatch)
  147. end
  148. else
  149. begin
  150. if calloption=pocall_inline then
  151. begin
  152. tmpreg:=cg.get_scratch_reg_address(exprasmlist);
  153. cg.a_loadaddr_ref_reg(exprasmlist,left.location.reference,tmpreg);
  154. reference_reset_base(href,procinfo.framepointer,para_offset-pushedparasize);
  155. cg.a_load_reg_ref(exprasmlist,OS_ADDR,tmpreg,href);
  156. cg.free_scratch_reg(exprasmlist,tmpreg);
  157. end
  158. else
  159. cg.a_paramaddr_ref(exprasmlist,left.location.reference,paraitem.paraloc);
  160. location_release(exprasmlist,left.location);
  161. end;
  162. end;
  163. end
  164. { handle call by reference parameter }
  165. else if (paraitem.paratyp in [vs_var,vs_out]) then
  166. begin
  167. if (left.location.loc<>LOC_REFERENCE) then
  168. begin
  169. { passing self to a var parameter is allowed in
  170. TP and delphi }
  171. if not((left.location.loc=LOC_CREFERENCE) and
  172. (left.nodetype=selfn)) then
  173. internalerror(200106041);
  174. end;
  175. {$ifdef unused}
  176. if not push_from_left_to_right then
  177. {$endif unused}
  178. maybe_push_high;
  179. if (paraitem.paratyp=vs_out) and
  180. assigned(paraitem.paratype.def) and
  181. not is_class(paraitem.paratype.def) and
  182. paraitem.paratype.def.needs_inittable then
  183. cg.g_finalize(exprasmlist,paraitem.paratype.def,left.location.reference,false);
  184. inc(pushedparasize,4);
  185. if calloption=pocall_inline then
  186. begin
  187. tmpreg:=cg.get_scratch_reg_address(exprasmlist);
  188. cg.a_loadaddr_ref_reg(exprasmlist,left.location.reference,tmpreg);
  189. reference_reset_base(href,procinfo.framepointer,para_offset-pushedparasize);
  190. cg.a_load_reg_ref(exprasmlist,OS_ADDR,tmpreg,href);
  191. cg.free_scratch_reg(exprasmlist,tmpreg);
  192. end
  193. else
  194. cg.a_paramaddr_ref(exprasmlist,left.location.reference,paraitem.paraloc);
  195. location_release(exprasmlist,left.location);
  196. {$ifdef unused}
  197. if push_from_left_to_right then
  198. maybe_push_high;
  199. {$endif unused}
  200. end
  201. else
  202. begin
  203. tempdeftype:=resulttype.def.deftype;
  204. if tempdeftype=filedef then
  205. CGMessage(cg_e_file_must_call_by_reference);
  206. { open array must always push the address, this is needed to
  207. also push addr of small open arrays and with cdecl functions (PFV) }
  208. if (
  209. assigned(paraitem.paratype.def) and
  210. (is_open_array(paraitem.paratype.def) or
  211. is_array_of_const(paraitem.paratype.def))
  212. ) or
  213. (
  214. paramanager.push_addr_param(resulttype.def,calloption)
  215. ) then
  216. begin
  217. if not(left.location.loc in [LOC_CREFERENCE,LOC_REFERENCE]) then
  218. begin
  219. { allow passing nil to a procvardef (methodpointer) }
  220. (* if (left.nodetype=typeconvn) and
  221. (left.resulttype.def.deftype=procvardef) and
  222. (ttypeconvnode(left).left.nodetype=niln) then
  223. *)
  224. if (left.location.size <> OS_NO) then
  225. begin
  226. tg.GetTemp(exprasmlist,tcgsize2size[left.location.size],tt_normal,href);
  227. if not (left.location.size in [OS_64,OS_S64]) then
  228. cg.a_load_loc_ref(exprasmlist,left.location,href)
  229. else
  230. cg64.a_load64_loc_ref(exprasmlist,left.location,href);
  231. location_reset(left.location,LOC_REFERENCE,left.location.size);
  232. left.location.reference:=href;
  233. end
  234. else
  235. internalerror(200204011);
  236. end;
  237. {$ifdef unused}
  238. if not push_from_left_to_right then
  239. {$endif unused}
  240. maybe_push_high;
  241. inc(pushedparasize,4);
  242. if calloption=pocall_inline then
  243. begin
  244. tmpreg:=cg.get_scratch_reg_address(exprasmlist);
  245. cg.a_loadaddr_ref_reg(exprasmlist,left.location.reference,tmpreg);
  246. reference_reset_base(href,procinfo.framepointer,para_offset-pushedparasize);
  247. cg.a_load_reg_ref(exprasmlist,OS_ADDR,tmpreg,href);
  248. cg.free_scratch_reg(exprasmlist,tmpreg);
  249. end
  250. else
  251. cg.a_paramaddr_ref(exprasmlist,left.location.reference,paraitem.paraloc);
  252. location_release(exprasmlist,left.location);
  253. {$ifdef unused}
  254. if push_from_left_to_right then
  255. maybe_push_high;
  256. {$endif unused}
  257. end
  258. else
  259. begin
  260. push_value_para(left,calloption,
  261. para_offset,para_alignment,paraitem.paraloc);
  262. end;
  263. end;
  264. truelabel:=otlabel;
  265. falselabel:=oflabel;
  266. { push from right to left }
  267. if not push_from_left_to_right and assigned(right) then
  268. begin
  269. if (nf_varargs_para in flags) then
  270. tcallparanode(right).secondcallparan(push_from_left_to_right,
  271. calloption,para_alignment,para_offset)
  272. else
  273. tcallparanode(right).secondcallparan(push_from_left_to_right,
  274. calloption,para_alignment,para_offset);
  275. end;
  276. end;
  277. {*****************************************************************************
  278. TCGCALLNODE
  279. *****************************************************************************}
  280. procedure tcgcallnode.extra_interrupt_code;
  281. begin
  282. {$ifdef i386}
  283. { if the i386 ever uses tcgcal, we've to move this into an overriden method }
  284. emit_none(A_PUSHF,S_L);
  285. emit_reg(A_PUSH,S_L,R_CS);
  286. {$endif i386}
  287. end;
  288. procedure tcgcallnode.handle_return_value(inlined,extended_new:boolean);
  289. var
  290. cgsize : tcgsize;
  291. hregister : tregister;
  292. begin
  293. { structured results are easy to handle.... }
  294. { needed also when result_no_used !! }
  295. if paramanager.ret_in_param(resulttype.def,procdefinition.proccalloption) then
  296. begin
  297. location_reset(location,LOC_CREFERENCE,def_cgsize(resulttype.def));
  298. location.reference.symbol:=nil;
  299. location.reference:=funcretref;
  300. end
  301. else
  302. { ansi/widestrings must be registered, so we can dispose them }
  303. if is_ansistring(resulttype.def) or
  304. is_widestring(resulttype.def) then
  305. begin
  306. location_reset(location,LOC_CREFERENCE,OS_ADDR);
  307. location.reference:=refcountedtemp;
  308. cg.a_reg_alloc(exprasmlist,accumulator);
  309. cg.a_load_reg_ref(exprasmlist,OS_ADDR,accumulator,location.reference);
  310. cg.a_reg_dealloc(exprasmlist,accumulator);
  311. end
  312. else
  313. { we have only to handle the result if it is used }
  314. if (nf_return_value_used in flags) then
  315. begin
  316. case resulttype.def.deftype of
  317. enumdef,
  318. orddef :
  319. begin
  320. cgsize:=def_cgsize(resulttype.def);
  321. { an object constructor is a function with boolean result }
  322. if (inlined or (right=nil)) and
  323. (procdefinition.proctypeoption=potype_constructor) then
  324. begin
  325. {$ifdef x86}
  326. if extended_new then
  327. cgsize:=OS_INT
  328. else
  329. begin
  330. cgsize:=OS_NO;
  331. { this fails if popsize > 0 PM }
  332. location_reset(location,LOC_FLAGS,OS_NO);
  333. location.resflags:=F_NE;
  334. end;
  335. {$else x86}
  336. cgsize:=OS_INT
  337. {$endif x86}
  338. end;
  339. if cgsize<>OS_NO then
  340. begin
  341. location_reset(location,LOC_REGISTER,cgsize);
  342. cg.a_reg_alloc(exprasmlist,accumulator);
  343. {$ifndef cpu64bit}
  344. if cgsize in [OS_64,OS_S64] then
  345. begin
  346. cg.a_reg_alloc(exprasmlist,accumulatorhigh);
  347. location.registerhigh:=rg.getexplicitregisterint(exprasmlist,accumulatorhigh);
  348. location.registerlow:=rg.getexplicitregisterint(exprasmlist,accumulator);
  349. cg64.a_load64_reg_reg(exprasmlist,joinreg64(accumulator,accumulatorhigh),
  350. location.register64);
  351. end
  352. else
  353. {$endif cpu64bit}
  354. begin
  355. location.register:=rg.getexplicitregisterint(exprasmlist,accumulator);
  356. hregister:=rg.makeregsize(accumulator,cgsize);
  357. location.register:=rg.makeregsize(location.register,cgsize);
  358. cg.a_load_reg_reg(exprasmlist,cgsize,cgsize,hregister,location.register);
  359. end;
  360. end;
  361. end;
  362. floatdef :
  363. begin
  364. location_reset(location,LOC_FPUREGISTER,def_cgsize(resulttype.def));
  365. location.register:=fpu_result_reg;
  366. {$ifdef x86}
  367. inc(trgcpu(rg).fpuvaroffset);
  368. {$endif x86}
  369. end;
  370. {$ifdef TEST_WIN32_RECORDS}
  371. recorddef :
  372. begin
  373. if (target_info.system=system_i386_win32) then
  374. begin
  375. location_reset(location,LOC_REFERENCE,def_cgsize(resulttype.def));
  376. tg.GetTemp(exprasmlist,resulttype.size,tt_normal,location);
  377. {$ifndef cpu64bit}
  378. if cgsize in [OS_64,OS_S64] then
  379. cg64.a_load64_reg_loc(exprasmlist,joinreg64(accumulator,accumulatorhigh),location)
  380. else
  381. {$endif cpu64bit}
  382. cg.a_load_reg_loc(exprasmlist,accumulator,location);
  383. end
  384. else
  385. internalerror(200211141);
  386. end;
  387. {$endif TEST_WIN32_RECORDS}
  388. else
  389. begin
  390. location_reset(location,LOC_REGISTER,OS_INT);
  391. location.register:=rg.getexplicitregisterint(exprasmlist,accumulator);
  392. cg.a_load_reg_reg(exprasmlist,OS_INT,OS_INT,accumulator,location.register);
  393. end;
  394. end;
  395. end;
  396. end;
  397. procedure tcgcallnode.pass_2;
  398. var
  399. regs_to_push : tregisterset;
  400. unusedstate: pointer;
  401. pushed : tpushedsaved;
  402. tmpreg : tregister;
  403. hregister : tregister;
  404. hregister64 : tregister64;
  405. oldpushedparasize : longint;
  406. { true if ESI must be loaded again after the subroutine }
  407. loadesi : boolean;
  408. { true if a virtual method must be called directly }
  409. no_virtual_call : boolean;
  410. { true if we produce a con- or destrutor in a call }
  411. is_con_or_destructor : boolean;
  412. { true if a constructor is called again }
  413. extended_new : boolean;
  414. { adress returned from an I/O-error }
  415. iolabel : tasmlabel;
  416. { lexlevel count }
  417. i : longint;
  418. { help reference pointer }
  419. href : treference;
  420. hrefvmt : treference;
  421. hp : tnode;
  422. pp : tbinarynode;
  423. params : tnode;
  424. inlined : boolean;
  425. inlinecode : tprocinlinenode;
  426. store_parast_fixup,
  427. para_alignment,
  428. para_offset : longint;
  429. cgsize : tcgsize;
  430. { instruction for alignement correction }
  431. { corr : paicpu;}
  432. { we must pop this size also after !! }
  433. { must_pop : boolean; }
  434. pop_size : longint;
  435. {$ifdef OPTALIGN}
  436. pop_esp : boolean;
  437. push_size : longint;
  438. {$endif OPTALIGN}
  439. pop_allowed : boolean;
  440. release_tmpreg : boolean;
  441. constructorfailed : tasmlabel;
  442. resultloc : tparalocation;
  443. returnref,
  444. pararef : treference;
  445. label
  446. dont_call;
  447. begin
  448. extended_new:=false;
  449. iolabel:=nil;
  450. inlinecode:=nil;
  451. inlined:=false;
  452. loadesi:=true;
  453. no_virtual_call:=false;
  454. rg.saveunusedstate(unusedstate);
  455. { if we allocate the temp. location for ansi- or widestrings }
  456. { already here, we avoid later a push/pop }
  457. if is_widestring(resulttype.def) then
  458. begin
  459. tg.GetTemp(exprasmlist,pointer_size,tt_widestring,refcountedtemp);
  460. cg.g_decrrefcount(exprasmlist,resulttype.def,refcountedtemp);
  461. end
  462. else if is_ansistring(resulttype.def) then
  463. begin
  464. tg.GetTemp(exprasmlist,pointer_size,tt_ansistring,refcountedtemp);
  465. cg.g_decrrefcount(exprasmlist,resulttype.def,refcountedtemp);
  466. end;
  467. if (procdefinition.proccalloption in [pocall_cdecl,pocall_cppdecl,pocall_stdcall]) then
  468. para_alignment:=4
  469. else
  470. para_alignment:=aktalignment.paraalign;
  471. if not assigned(procdefinition) then
  472. exit;
  473. { Deciding whether we may still need the parameters happens next (JM) }
  474. if assigned(left) then
  475. params:=left.getcopy
  476. else
  477. params := nil;
  478. if (procdefinition.proccalloption=pocall_inline) then
  479. begin
  480. inlined:=true;
  481. inlinecode:=tprocinlinenode(right);
  482. right:=nil;
  483. { set it to the same lexical level as the local symtable, becuase
  484. the para's are stored there }
  485. tprocdef(procdefinition).parast.symtablelevel:=aktprocdef.localst.symtablelevel;
  486. if assigned(params) then
  487. begin
  488. inlinecode.para_size:=tprocdef(procdefinition).para_size(para_alignment);
  489. tg.GetTemp(exprasmlist,inlinecode.para_size,tt_persistant,pararef);
  490. inlinecode.para_offset:=pararef.offset;
  491. end;
  492. store_parast_fixup:=tprocdef(procdefinition).parast.address_fixup;
  493. tprocdef(procdefinition).parast.address_fixup:=inlinecode.para_offset;
  494. {$ifdef extdebug}
  495. Comment(V_debug,
  496. 'inlined parasymtable is at offset '
  497. +tostr(tprocdef(procdefinition).parast.address_fixup));
  498. exprasmList.concat(tai_comment.Create(
  499. strpnew('inlined parasymtable is at offset '
  500. +tostr(tprocdef(procdefinition).parast.address_fixup))));
  501. {$endif extdebug}
  502. end;
  503. { only if no proc var }
  504. if inlined or
  505. not(assigned(right)) then
  506. is_con_or_destructor:=(procdefinition.proctypeoption in [potype_constructor,potype_destructor]);
  507. { proc variables destroy all registers }
  508. if (inlined or
  509. (right=nil)) and
  510. { virtual methods too }
  511. not(po_virtualmethod in procdefinition.procoptions) then
  512. begin
  513. if (cs_check_io in aktlocalswitches) and
  514. (po_iocheck in procdefinition.procoptions) and
  515. not(po_iocheck in aktprocdef.procoptions) then
  516. begin
  517. objectlibrary.getaddrlabel(iolabel);
  518. cg.a_label(exprasmlist,iolabel);
  519. end
  520. else
  521. iolabel:=nil;
  522. { save all used registers and possible registers
  523. used for the return value }
  524. regs_to_push := tprocdef(procdefinition).usedregisters;
  525. if (not is_void(resulttype.def)) and
  526. (not paramanager.ret_in_param(resulttype.def,procdefinition.proccalloption)) then
  527. begin
  528. include(regs_to_push,accumulator);
  529. {$ifndef cpu64bit}
  530. if resulttype.def.size>sizeof(aword) then
  531. include(regs_to_push,accumulatorhigh);
  532. {$endif cpu64bit}
  533. end;
  534. rg.saveusedregisters(exprasmlist,pushed,regs_to_push);
  535. { give used registers through }
  536. rg.usedinproc:=rg.usedinproc + tprocdef(procdefinition).usedregisters;
  537. end
  538. else
  539. begin
  540. regs_to_push := all_registers;
  541. rg.saveusedregisters(exprasmlist,pushed,regs_to_push);
  542. rg.usedinproc:=all_registers;
  543. { no IO check for methods and procedure variables }
  544. iolabel:=nil;
  545. end;
  546. { generate the code for the parameter and push them }
  547. oldpushedparasize:=pushedparasize;
  548. pushedparasize:=0;
  549. pop_size:=0;
  550. {$ifdef dummy}
  551. { no inc esp for inlined procedure
  552. and for objects constructors PM }
  553. if inlined or
  554. ((procdefinition.proctypeoption=potype_constructor) and
  555. { quick'n'dirty check if it is a class or an object }
  556. (resulttype.def.deftype=orddef)) then
  557. pop_allowed:=false
  558. else
  559. pop_allowed:=true;
  560. if pop_allowed then
  561. begin
  562. { Old pushedsize aligned on 4 ? }
  563. i:=oldpushedparasize and 3;
  564. if i>0 then
  565. inc(pop_size,4-i);
  566. { This parasize aligned on 4 ? }
  567. i:=procdefinition.para_size(para_alignment) and 3;
  568. if i>0 then
  569. inc(pop_size,4-i);
  570. { insert the opcode and update pushedparasize }
  571. { never push 4 or more !! }
  572. pop_size:=pop_size mod 4;
  573. if pop_size>0 then
  574. begin
  575. inc(pushedparasize,pop_size);
  576. cg.a_const_reg(A_SUB,S_L,pop_size,R_ESP);
  577. {$ifdef GDB}
  578. if (cs_debuginfo in aktmoduleswitches) and
  579. (exprasmList.first=exprasmList.last) then
  580. exprasmList.concat(Tai_force_line.Create);
  581. {$endif GDB}
  582. end;
  583. end;
  584. {$endif dummy}
  585. {$ifdef OPTALIGN}
  586. if pop_allowed and (cs_align in aktglobalswitches) then
  587. begin
  588. pop_esp:=true;
  589. push_size:=procdefinition.para_size(para_alignment);
  590. { !!!! here we have to take care of return type, self
  591. and nested procedures
  592. }
  593. inc(push_size,12);
  594. emit_reg_reg(A_MOV,S_L,R_ESP,R_EDI);
  595. if (push_size mod 8)=0 then
  596. emit_const_reg(A_AND,S_L,$fffffff8,R_ESP)
  597. else
  598. begin
  599. emit_const_reg(A_SUB,S_L,push_size,R_ESP);
  600. emit_const_reg(A_AND,S_L,$fffffff8,R_ESP);
  601. emit_const_reg(A_SUB,S_L,push_size,R_ESP);
  602. end;
  603. emit_reg(A_PUSH,S_L,R_EDI);
  604. end
  605. else
  606. pop_esp:=false;
  607. {$endif OPTALIGN}
  608. { Push parameters }
  609. if assigned(params) then
  610. begin
  611. { be found elsewhere }
  612. if inlined then
  613. para_offset:=tprocdef(procdefinition).parast.address_fixup+
  614. tprocdef(procdefinition).parast.datasize
  615. else
  616. para_offset:=0;
  617. if not(inlined) and
  618. assigned(right) then
  619. tcallparanode(params).secondcallparan(
  620. { TParaItem(tabstractprocdef(right.resulttype.def).Para.first), }
  621. (po_leftright in procdefinition.procoptions),procdefinition.proccalloption,
  622. para_alignment,para_offset)
  623. else
  624. tcallparanode(params).secondcallparan(
  625. { TParaItem(procdefinition.Para.first), }
  626. (po_leftright in procdefinition.procoptions),procdefinition.proccalloption,
  627. para_alignment,para_offset);
  628. end;
  629. { Allocate return value for inlined routines }
  630. if inlined and
  631. (resulttype.def.size>0) then
  632. begin
  633. tg.GetTemp(exprasmlist,Align(resulttype.def.size,aktalignment.paraalign),tt_persistant,returnref);
  634. inlinecode.retoffset:=returnref.offset;
  635. end;
  636. { Allocate return value when returned in argument }
  637. if paramanager.ret_in_param(resulttype.def,procdefinition.proccalloption) then
  638. begin
  639. if assigned(funcretrefnode) then
  640. begin
  641. secondpass(funcretrefnode);
  642. if codegenerror then
  643. exit;
  644. if (funcretrefnode.location.loc<>LOC_REFERENCE) then
  645. internalerror(200204246);
  646. funcretref:=funcretrefnode.location.reference;
  647. end
  648. else
  649. begin
  650. if inlined then
  651. begin
  652. tg.GetTemp(exprasmlist,resulttype.def.size,tt_persistant,funcretref);
  653. {$ifdef extdebug}
  654. Comment(V_debug,'function return value is at offset '
  655. +tostr(funcretref.offset));
  656. exprasmlist.concat(tai_comment.create(
  657. strpnew('function return value is at offset '
  658. +tostr(funcretref.offset))));
  659. {$endif extdebug}
  660. end
  661. else
  662. tg.GetTemp(exprasmlist,resulttype.def.size,tt_normal,funcretref);
  663. end;
  664. { This must not be counted for C code
  665. complex return address is removed from stack
  666. by function itself ! }
  667. {$ifdef OLD_C_STACK}
  668. inc(pushedparasize,4); { lets try without it PM }
  669. {$endif not OLD_C_STACK}
  670. if inlined then
  671. begin
  672. hregister:=cg.get_scratch_reg_address(exprasmlist);
  673. cg.a_loadaddr_ref_reg(exprasmlist,funcretref,hregister);
  674. reference_reset_base(href,procinfo.framepointer,inlinecode.retoffset);
  675. cg.a_load_reg_ref(exprasmlist,OS_ADDR,hregister,href);
  676. cg.free_scratch_reg(exprasmlist,hregister);
  677. end
  678. else
  679. cg.a_paramaddr_ref(exprasmlist,funcretref,
  680. paramanager.getfuncretparaloc(procdefinition));
  681. end;
  682. { procedure variable or normal function call ? }
  683. if inlined or
  684. (right=nil) then
  685. begin
  686. { Normal function call }
  687. {$ifdef dummy}
  688. { overloaded operator has no symtable }
  689. { push self }
  690. if assigned(symtableproc) and
  691. (symtableproc.symtabletype=withsymtable) then
  692. begin
  693. { dirty trick to avoid the secondcall below }
  694. methodpointer:=ccallparanode.create(nil,nil);
  695. location_reset(methodpointer.location,LOC_REGISTER,OS_ADDR);
  696. rg.getexplicitregisterint(exprasmlist,R_ESI);
  697. methodpointer.location.register:=R_ESI;
  698. { ARGHHH this is wrong !!!
  699. if we can init from base class for a child
  700. class that the wrong VMT will be
  701. transfered to constructor !! }
  702. methodpointer.resulttype:=
  703. twithnode(twithsymtable(symtableproc).withnode).left.resulttype;
  704. { make a reference }
  705. href:=twithnode(twithsymtable(symtableproc).withnode).withreference;
  706. if ((not(nf_islocal in twithnode(twithsymtable(symtableproc).withnode).flags)) and
  707. (not twithsymtable(symtableproc).direct_with)) or
  708. is_class_or_interface(methodpointer.resulttype.def) then
  709. cg.a_load_ref_reg(exprasmlist,OS_ADDR,href,self_pointer_reg)
  710. else
  711. cg.a_loadaddr_ref_reg(exprasmlist,href,self_pointer_reg);
  712. end;
  713. { push self }
  714. if assigned(symtableproc) and
  715. ((symtableproc.symtabletype=objectsymtable) or
  716. (symtableproc.symtabletype=withsymtable)) then
  717. begin
  718. if assigned(methodpointer) then
  719. begin
  720. {
  721. if methodpointer^.resulttype.def=classrefdef then
  722. begin
  723. two possibilities:
  724. 1. constructor
  725. 2. class method
  726. end
  727. else }
  728. begin
  729. case methodpointer.nodetype of
  730. typen:
  731. begin
  732. { direct call to inherited method }
  733. if (po_abstractmethod in procdefinition.procoptions) then
  734. begin
  735. CGMessage(cg_e_cant_call_abstract_method);
  736. goto dont_call;
  737. end;
  738. { generate no virtual call }
  739. no_virtual_call:=true;
  740. if (sp_static in symtableprocentry.symoptions) then
  741. begin
  742. { well lets put the VMT address directly into ESI }
  743. { it is kind of dirty but that is the simplest }
  744. { way to accept virtual static functions (PM) }
  745. loadesi:=true;
  746. { if no VMT just use $0 bug0214 PM }
  747. rg.getexplicitregisterint(exprasmlist,R_ESI);
  748. if not(oo_has_vmt in tobjectdef(methodpointer.resulttype.def).objectoptions) then
  749. cg.a_load_const_reg(exprasmlist,OS_ADDR,0,self_pointer_reg)
  750. else
  751. begin
  752. reference_reset_symbol(href,objectlibrary.newasmsymbol(tobjectdef(methodpointer.resulttype.def).vmt_mangledname),0);
  753. cg.a_loadaddr_ref_reg(exprasmlist,href,self_pointer_reg);
  754. end;
  755. { emit_reg(A_PUSH,S_L,R_ESI);
  756. this is done below !! }
  757. end
  758. else
  759. { this is a member call, so ESI isn't modfied }
  760. loadesi:=false;
  761. { a class destructor needs a flag }
  762. if is_class(tobjectdef(methodpointer.resulttype.def)) and
  763. (procdefinition.proctypeoption=potype_destructor) then
  764. begin
  765. cg.a_param_const(exprasmlist,OS_ADDR,0,2);
  766. cg.a_param_reg(exprasmlist,OS_ADDR,self_pointer_reg,1);
  767. end;
  768. if not(is_con_or_destructor and
  769. is_class(methodpointer.resulttype.def) and
  770. (procdefinition.proctypeoption in [potype_constructor,potype_destructor])
  771. ) then
  772. cg.a_param_reg(exprasmlist,OS_ADDR,self_pointer_reg,1);
  773. { if an inherited con- or destructor should be }
  774. { called in a con- or destructor then a warning }
  775. { will be made }
  776. { con- and destructors need a pointer to the vmt }
  777. if is_con_or_destructor and
  778. is_object(methodpointer.resulttype.def) and
  779. assigned(aktprocdef) then
  780. begin
  781. if not(aktprocdef.proctypeoption in
  782. [potype_constructor,potype_destructor]) then
  783. CGMessage(cg_w_member_cd_call_from_method);
  784. end;
  785. { class destructors get there flag above }
  786. { constructor flags ? }
  787. if is_con_or_destructor and
  788. not(
  789. is_class(methodpointer.resulttype.def) and
  790. assigned(aktprocdef) and
  791. (aktprocdef.proctypeoption=potype_destructor)) then
  792. begin
  793. { a constructor needs also a flag }
  794. if is_class(methodpointer.resulttype.def) then
  795. cg.a_param_const(exprasmlist,OS_ADDR,0,2);
  796. cg.a_param_const(exprasmlist,OS_ADDR,0,1);
  797. end;
  798. end;
  799. hnewn:
  800. begin
  801. { extended syntax of new }
  802. { ESI must be zero }
  803. rg.getexplicitregisterint(exprasmlist,R_ESI);
  804. cg.a_load_const_reg(exprasmlist,OS_ADDR,0,self_pointer_reg);
  805. cg.a_param_reg(exprasmlist,OS_ADDR,self_pointer_reg,2);
  806. { insert the vmt }
  807. reference_reset_symbol(href,objectlibrary.newasmsymbol(tobjectdef(methodpointer.resulttype.def).vmt_mangledname),0);
  808. cg.a_paramaddr_ref(exprasmlist,href,1);
  809. extended_new:=true;
  810. end;
  811. hdisposen:
  812. begin
  813. secondpass(methodpointer);
  814. { destructor with extended syntax called from dispose }
  815. { hdisposen always deliver LOC_REFERENCE }
  816. rg.getexplicitregisterint(exprasmlist,R_ESI);
  817. emit_ref_reg(A_LEA,S_L,methodpointer.location.reference,R_ESI);
  818. reference_release(exprasmlist,methodpointer.location.reference);
  819. cg.a_param_reg(exprasmlist,OS_ADDR,self_pointer_reg,2);
  820. reference_reset_symbol(href,objectlibrary.newasmsymbol(tobjectdef(methodpointer.resulttype.def).vmt_mangledname),0);
  821. cg.a_paramaddr_ref(exprasmlist,href,1);
  822. end;
  823. else
  824. begin
  825. { call to an instance member }
  826. if (symtableproc.symtabletype<>withsymtable) then
  827. begin
  828. secondpass(methodpointer);
  829. rg.getexplicitregisterint(exprasmlist,R_ESI);
  830. case methodpointer.location.loc of
  831. LOC_CREGISTER,
  832. LOC_REGISTER:
  833. begin
  834. cg.a_load_reg_reg(exprasmlist,OS_ADDR,OS_ADDR,methodpointer.location.register,R_ESI);
  835. rg.ungetregisterint(exprasmlist,methodpointer.location.register);
  836. end;
  837. else
  838. begin
  839. if (methodpointer.resulttype.def.deftype=classrefdef) or
  840. is_class_or_interface(methodpointer.resulttype.def) then
  841. cg.a_load_ref_reg(exprasmlist,OS_ADDR,methodpointer.location.reference,R_ESI)
  842. else
  843. cg.a_loadaddr_ref_reg(exprasmlist,methodpointer.location.reference,R_ESI);
  844. reference_release(exprasmlist,methodpointer.location.reference);
  845. end;
  846. end;
  847. end;
  848. { when calling a class method, we have to load ESI with the VMT !
  849. But, not for a class method via self }
  850. if not(po_containsself in procdefinition.procoptions) then
  851. begin
  852. if (po_classmethod in procdefinition.procoptions) and
  853. not(methodpointer.resulttype.def.deftype=classrefdef) then
  854. begin
  855. { class method needs current VMT }
  856. rg.getexplicitregisterint(exprasmlist,R_ESI);
  857. reference_reset_base(href,R_ESI,tprocdef(procdefinition)._class.vmt_offset);
  858. cg.a_maybe_testself(exprasmlist);
  859. cg.a_load_ref_reg(exprasmlist,OS_ADDR,href,self_pointer_reg);
  860. end;
  861. { direct call to destructor: remove data }
  862. if (procdefinition.proctypeoption=potype_destructor) and
  863. is_class(methodpointer.resulttype.def) then
  864. cg.a_param_const(exprasmlist,OS_INT,1,1);
  865. { direct call to class constructor, don't allocate memory }
  866. if (procdefinition.proctypeoption=potype_constructor) and
  867. is_class(methodpointer.resulttype.def) then
  868. begin
  869. cg.a_param_const(exprasmlist,OS_INT,0,2);
  870. cg.a_param_const(exprasmlist,OS_INT,0,1);
  871. end
  872. else
  873. begin
  874. { constructor call via classreference => allocate memory }
  875. if (procdefinition.proctypeoption=potype_constructor) and
  876. (methodpointer.resulttype.def.deftype=classrefdef) and
  877. is_class(tclassrefdef(methodpointer.resulttype.def).pointertype.def) then
  878. cg.a_param_const(exprasmlist,OS_INT,1,1);
  879. cg.a_param_reg(exprasmlist,OS_ADDR,self_pointer_reg,1);
  880. end;
  881. end;
  882. if is_con_or_destructor then
  883. begin
  884. { classes don't get a VMT pointer pushed }
  885. if is_object(methodpointer.resulttype.def) then
  886. begin
  887. if (procdefinition.proctypeoption=potype_constructor) then
  888. begin
  889. { it's no bad idea, to insert the VMT }
  890. reference_reset_symbol(href,objectlibrary.newasmsymbol(
  891. tobjectdef(methodpointer.resulttype.def).vmt_mangledname),0);
  892. cg.a_paramaddr_ref(exprasmlist,href,1);
  893. end
  894. { destructors haven't to dispose the instance, if this is }
  895. { a direct call }
  896. else
  897. cg.a_param_const(exprasmlist,OS_INT,0,1);
  898. end;
  899. end;
  900. end;
  901. end;
  902. end;
  903. end
  904. else
  905. begin
  906. if (po_classmethod in procdefinition.procoptions) and
  907. not(
  908. assigned(aktprocdef) and
  909. (po_classmethod in aktprocdef.procoptions)
  910. ) then
  911. begin
  912. { class method needs current VMT }
  913. rg.getexplicitregisterint(exprasmlist,R_ESI);
  914. reference_reset_base(href,R_ESI,tprocdef(procdefinition)._class.vmt_offset);
  915. cg.a_maybe_testself(exprasmlist);
  916. cg.a_load_ref_reg(exprasmlist,OS_ADDR,href,R_ESI);
  917. end
  918. else
  919. begin
  920. { member call, ESI isn't modified }
  921. loadesi:=false;
  922. end;
  923. { direct call to destructor: don't remove data! }
  924. if is_class(procinfo._class) then
  925. begin
  926. if (procdefinition.proctypeoption=potype_destructor) then
  927. begin
  928. cg.a_param_const(exprasmlist,OS_INT,0,2);
  929. cg.a_param_reg(exprasmlist,OS_ADDR,R_ESI,1);
  930. end
  931. else if (procdefinition.proctypeoption=potype_constructor) then
  932. begin
  933. cg.a_param_const(exprasmlist,OS_INT,0,2);
  934. cg.a_param_const(exprasmlist,OS_INT,0,1);
  935. end
  936. else
  937. cg.a_param_reg(exprasmlist,OS_ADDR,R_ESI,1);
  938. end
  939. else if is_object(procinfo._class) then
  940. begin
  941. cg.a_param_reg(exprasmlist,OS_ADDR,R_ESI,1);
  942. if is_con_or_destructor then
  943. begin
  944. if (procdefinition.proctypeoption=potype_constructor) then
  945. begin
  946. { it's no bad idea, to insert the VMT }
  947. reference_reset_symbol(href,objectlibrary.newasmsymbol(procinfo._class.vmt_mangledname),0);
  948. cg.a_paramaddr_ref(exprasmlist,href,1);
  949. end
  950. { destructors haven't to dispose the instance, if this is }
  951. { a direct call }
  952. else
  953. cg.a_param_const(exprasmlist,OS_INT,0,1);
  954. end;
  955. end
  956. else
  957. Internalerror(200006165);
  958. end;
  959. end;
  960. {$endif dummy}
  961. { call to BeforeDestruction? }
  962. if (procdefinition.proctypeoption=potype_destructor) and
  963. assigned(methodpointer) and
  964. (methodpointer.nodetype<>typen) and
  965. is_class(tobjectdef(methodpointer.resulttype.def)) and
  966. (inlined or
  967. (right=nil)) then
  968. begin
  969. cg.a_param_reg(exprasmlist,OS_ADDR,self_pointer_reg,paramanager.getintparaloc(1));
  970. reference_reset_base(href,self_pointer_reg,0);
  971. tmpreg:=cg.get_scratch_reg_address(exprasmlist);
  972. cg.a_load_ref_reg(exprasmlist,OS_ADDR,href,tmpreg);
  973. reference_reset_base(href,tmpreg,72);
  974. cg.a_call_ref(exprasmlist,href);
  975. cg.free_scratch_reg(exprasmlist,tmpreg);
  976. end;
  977. { push base pointer ?}
  978. { never when inlining, since if necessary, the base pointer }
  979. { can/will be gottten from the current procedure's symtable }
  980. { (JM) }
  981. if not inlined then
  982. if (lexlevel>=normal_function_level) and assigned(tprocdef(procdefinition).parast) and
  983. ((tprocdef(procdefinition).parast.symtablelevel)>normal_function_level) then
  984. load_framepointer;
  985. rg.saveregvars(exprasmlist,regs_to_push);
  986. {$ifdef dummy}
  987. if (po_virtualmethod in procdefinition.procoptions) and
  988. not(no_virtual_call) then
  989. begin
  990. { static functions contain the vmt_address in ESI }
  991. { also class methods }
  992. { Here it is quite tricky because it also depends }
  993. { on the methodpointer PM }
  994. release_tmpreg:=false;
  995. rg.getexplicitregisterint(exprasmlist,R_ESI);
  996. if assigned(aktprocdef) then
  997. begin
  998. if (((sp_static in aktprocdef.procsym.symoptions) or
  999. (po_classmethod in aktprocdef.procoptions)) and
  1000. ((methodpointer=nil) or (methodpointer.nodetype=typen)))
  1001. or
  1002. (po_staticmethod in procdefinition.procoptions) or
  1003. ((procdefinition.proctypeoption=potype_constructor) and
  1004. { esi contains the vmt if we call a constructor via a class ref }
  1005. assigned(methodpointer) and
  1006. (methodpointer.resulttype.def.deftype=classrefdef)
  1007. ) or
  1008. { is_interface(tprocdef(procdefinition)._class) or }
  1009. { ESI is loaded earlier }
  1010. (po_classmethod in procdefinition.procoptions) then
  1011. begin
  1012. reference_reset_base(href,R_ESI,0);
  1013. end
  1014. else
  1015. begin
  1016. { this is one point where we need vmt_offset (PM) }
  1017. reference_reset_base(href,R_ESI,tprocdef(procdefinition)._class.vmt_offset);
  1018. cg.a_maybe_testself(exprasmlist);
  1019. tmpreg:=cg.get_scratch_reg_address(exprasmlist);
  1020. cg.a_load_ref_reg(exprasmlist,OS_ADDR,href,tmpreg);
  1021. reference_reset_base(href,tmpreg,0);
  1022. release_tmpreg:=true;
  1023. end;
  1024. end
  1025. else
  1026. { aktprocdef should be assigned, also in main program }
  1027. internalerror(12345);
  1028. if tprocdef(procdefinition).extnumber=-1 then
  1029. internalerror(44584);
  1030. href.offset:=tprocdef(procdefinition)._class.vmtmethodoffset(tprocdef(procdefinition).extnumber);
  1031. if not(is_interface(tprocdef(procdefinition)._class)) and
  1032. not(is_cppclass(tprocdef(procdefinition)._class)) then
  1033. begin
  1034. if (cs_check_object in aktlocalswitches) then
  1035. begin
  1036. reference_reset_symbol(hrefvmt,objectlibrary.newasmsymbol(tprocdef(procdefinition)._class.vmt_mangledname),0);
  1037. cg.a_paramaddr_ref(exprasmlist,hrefvmt,2);
  1038. cg.a_param_reg(exprasmlist,OS_ADDR,href.base,1);
  1039. cg.a_call_name(exprasmlist,'FPC_CHECK_OBJECT_EXT');
  1040. end
  1041. else if (cs_check_range in aktlocalswitches) then
  1042. begin
  1043. cg.a_param_reg(exprasmlist,OS_ADDR,href.base,1);
  1044. cg.a_call_name(exprasmlist,'FPC_CHECK_OBJECT');
  1045. end;
  1046. end;
  1047. cg.a_call_ref(exprasmlist,href);
  1048. if release_tmpreg then
  1049. cg.free_scratch_reg(exprasmlist,tmpreg);
  1050. end
  1051. else
  1052. {$endif dummy}
  1053. if not inlined then
  1054. begin
  1055. { We can call interrupts from within the smae code
  1056. by just pushing the flags and CS PM }
  1057. if (po_interrupt in procdefinition.procoptions) then
  1058. extra_interrupt_code;
  1059. cg.a_call_name(exprasmlist,tprocdef(procdefinition).mangledname);
  1060. end
  1061. else { inlined proc }
  1062. { inlined code is in inlinecode }
  1063. begin
  1064. { process the inlinecode }
  1065. secondpass(tnode(inlinecode));
  1066. { free the args }
  1067. if tprocdef(procdefinition).parast.datasize>0 then
  1068. tg.UnGetTemp(exprasmlist,pararef);
  1069. end;
  1070. end
  1071. else
  1072. { now procedure variable case }
  1073. begin
  1074. secondpass(right);
  1075. if (po_interrupt in procdefinition.procoptions) then
  1076. extra_interrupt_code;
  1077. { procedure of object? }
  1078. if (po_methodpointer in procdefinition.procoptions) then
  1079. begin
  1080. {$ifdef dummy}
  1081. { method pointer can't be in a register }
  1082. hregister:=R_NO;
  1083. { do some hacking if we call a method pointer }
  1084. { which is a class member }
  1085. { else ESI is overwritten ! }
  1086. if (right.location.reference.base=R_ESI) or
  1087. (right.location.reference.index=R_ESI) then
  1088. begin
  1089. reference_release(exprasmlist,right.location.reference);
  1090. hregister:=cg.get_scratch_reg_address(exprasmlist);
  1091. cg.a_load_ref_reg(exprasmlist,OS_ADDR,right.location.reference,hregister);
  1092. end;
  1093. { load self, but not if it's already explicitly pushed }
  1094. if not(po_containsself in procdefinition.procoptions) then
  1095. begin
  1096. { load ESI }
  1097. href:=right.location.reference;
  1098. inc(href.offset,4);
  1099. rg.getexplicitregisterint(exprasmlist,R_ESI);
  1100. cg.a_load_ref_reg(exprasmlist,OS_ADDR,href,self_pointer_reg);
  1101. { push self pointer }
  1102. cg.a_param_reg(exprasmlist,OS_ADDR,self_pointer_reg,-1);
  1103. end;
  1104. rg.saveregvars(exprasmlist,ALL_REGISTERS);
  1105. if hregister<>R_NO then
  1106. cg.a_call_reg(exprasmlist,hregister)
  1107. else
  1108. cg.a_call_ref(exprasmlist,right.location.reference);
  1109. if hregister<>R_NO then
  1110. cg.free_scratch_reg(exprasmlist,hregister);
  1111. reference_release(exprasmlist,right.location.reference);
  1112. tg.Ungetiftemp(exprasmlist,right.location.reference);
  1113. {$endif dummy}
  1114. end
  1115. else
  1116. begin
  1117. rg.saveregvars(exprasmlist,ALL_REGISTERS);
  1118. cg.a_call_loc(exprasmlist,right.location);
  1119. location_release(exprasmlist,right.location);
  1120. location_freetemp(exprasmlist,right.location);
  1121. end;
  1122. end;
  1123. {$ifdef dummy}
  1124. { this was only for normal functions
  1125. displaced here so we also get
  1126. it to work for procvars PM }
  1127. if (not inlined) and (po_clearstack in procdefinition.procoptions) then
  1128. begin
  1129. { we also add the pop_size which is included in pushedparasize }
  1130. pop_size:=0;
  1131. { better than an add on all processors }
  1132. if pushedparasize=4 then
  1133. begin
  1134. rg.getexplicitregisterint(exprasmlist,R_EDI);
  1135. emit_reg(A_POP,S_L,R_EDI);
  1136. rg.ungetregisterint(exprasmlist,R_EDI);
  1137. end
  1138. { the pentium has two pipes and pop reg is pairable }
  1139. { but the registers must be different! }
  1140. else if (pushedparasize=8) and
  1141. not(cs_littlesize in aktglobalswitches) and
  1142. {$ifdef i386}
  1143. (aktoptprocessor=ClassP5) and
  1144. {$endif}
  1145. (procinfo._class=nil) then
  1146. begin
  1147. rg.getexplicitregisterint(exprasmlist,R_EDI);
  1148. emit_reg(A_POP,S_L,R_EDI);
  1149. rg.ungetregisterint(exprasmlist,R_EDI);
  1150. exprasmList.concat(tai_regalloc.Alloc(R_ESI));
  1151. emit_reg(A_POP,S_L,R_ESI);
  1152. exprasmList.concat(tai_regalloc.DeAlloc(R_ESI));
  1153. end
  1154. else if pushedparasize<>0 then
  1155. emit_const_reg(A_ADD,S_L,pushedparasize,R_ESP);
  1156. end;
  1157. {$endif dummy}
  1158. {$ifdef powerpc}
  1159. { this calculation must be done in pass_1 anyway, so don't worry }
  1160. if tppcprocinfo(procinfo).maxpushedparasize<pushedparasize then
  1161. tppcprocinfo(procinfo).maxpushedparasize:=pushedparasize;
  1162. {$endif powerpc}
  1163. {$ifdef OPTALIGN}
  1164. if pop_esp then
  1165. emit_reg(A_POP,S_L,R_ESP);
  1166. {$endif OPTALIGN}
  1167. dont_call:
  1168. pushedparasize:=oldpushedparasize;
  1169. rg.restoreunusedstate(unusedstate);
  1170. {$ifdef TEMPREGDEBUG}
  1171. testregisters32;
  1172. {$endif TEMPREGDEBUG}
  1173. { a constructor could be a function with boolean result }
  1174. { if calling constructor called fail we
  1175. must jump directly to quickexitlabel PM
  1176. but only if it is a call of an inherited constructor }
  1177. if (inlined or
  1178. (right=nil)) and
  1179. (procdefinition.proctypeoption=potype_constructor) and
  1180. assigned(methodpointer) and
  1181. (methodpointer.nodetype=typen) and
  1182. (aktprocdef.proctypeoption=potype_constructor) then
  1183. begin
  1184. cg.a_cmp_const_reg_label(exprasmlist,OS_ADDR,OC_EQ,0,accumulator,faillabel);
  1185. end;
  1186. { call to AfterConstruction? }
  1187. if is_class(resulttype.def) and
  1188. (inlined or
  1189. (right=nil)) and
  1190. (procdefinition.proctypeoption=potype_constructor) and
  1191. assigned(methodpointer) and
  1192. (methodpointer.nodetype<>typen) then
  1193. begin
  1194. objectlibrary.getlabel(constructorfailed);
  1195. cg.a_cmp_const_reg_label(exprasmlist,OS_ADDR,OC_EQ,0,self_pointer_reg,constructorfailed);
  1196. cg.a_param_reg(exprasmlist,OS_ADDR,accumulator,paramanager.getintparaloc(1));
  1197. reference_reset_base(href,self_pointer_reg,0);
  1198. tmpreg:=cg.get_scratch_reg_address(exprasmlist);
  1199. cg.a_load_ref_reg(exprasmlist,OS_ADDR,href,tmpreg);
  1200. reference_reset_base(href,tmpreg,17*pointer_size);
  1201. cg.a_call_ref(exprasmlist,href);
  1202. cg.free_scratch_reg(exprasmlist,tmpreg);
  1203. exprasmList.concat(tai_regalloc.Alloc(accumulator));
  1204. cg.a_label(exprasmlist,constructorfailed);
  1205. cg.a_load_reg_reg(exprasmlist,OS_ADDR,OS_ADDR,self_pointer_reg,accumulator);
  1206. end;
  1207. { handle function results }
  1208. if (not is_void(resulttype.def)) then
  1209. handle_return_value(inlined,extended_new);
  1210. { perhaps i/o check ? }
  1211. if iolabel<>nil then
  1212. begin
  1213. reference_reset_symbol(href,iolabel,0);
  1214. cg.a_paramaddr_ref(exprasmlist,href,paramanager.getintparaloc(1));
  1215. cg.a_call_name(exprasmlist,'FPC_IOCHECK');
  1216. end;
  1217. {$ifdef i386}
  1218. if pop_size>0 then
  1219. emit_const_reg(A_ADD,S_L,pop_size,R_ESP);
  1220. {$endif i386}
  1221. { restore registers }
  1222. rg.restoreusedregisters(exprasmlist,pushed);
  1223. { at last, restore instance pointer (SELF) }
  1224. if loadesi then
  1225. cg.g_maybe_loadself(exprasmlist);
  1226. pp:=tbinarynode(params);
  1227. while assigned(pp) do
  1228. begin
  1229. if assigned(pp.left) then
  1230. begin
  1231. location_freetemp(exprasmlist,pp.left.location);
  1232. { process also all nodes of an array of const }
  1233. if pp.left.nodetype=arrayconstructorn then
  1234. begin
  1235. if assigned(tarrayconstructornode(pp.left).left) then
  1236. begin
  1237. hp:=pp.left;
  1238. while assigned(hp) do
  1239. begin
  1240. location_freetemp(exprasmlist,tarrayconstructornode(hp).left.location);
  1241. hp:=tarrayconstructornode(hp).right;
  1242. end;
  1243. end;
  1244. end;
  1245. end;
  1246. pp:=tbinarynode(pp.right);
  1247. end;
  1248. if inlined then
  1249. begin
  1250. if (resulttype.def.size>0) then
  1251. tg.UnGetTemp(exprasmlist,returnref);
  1252. tprocdef(procdefinition).parast.address_fixup:=store_parast_fixup;
  1253. right:=inlinecode;
  1254. end;
  1255. if assigned(params) then
  1256. params.free;
  1257. { from now on the result can be freed normally }
  1258. if inlined and paramanager.ret_in_param(resulttype.def,procdefinition.proccalloption) then
  1259. tg.ChangeTempType(exprasmlist,funcretref,tt_normal);
  1260. { if return value is not used }
  1261. if (not(nf_return_value_used in flags)) and (not is_void(resulttype.def)) then
  1262. begin
  1263. if location.loc in [LOC_CREFERENCE,LOC_REFERENCE] then
  1264. begin
  1265. { data which must be finalized ? }
  1266. if (resulttype.def.needs_inittable) then
  1267. cg.g_finalize(exprasmlist,resulttype.def,location.reference,false);
  1268. { release unused temp }
  1269. tg.ungetiftemp(exprasmlist,location.reference)
  1270. end
  1271. else if location.loc=LOC_FPUREGISTER then
  1272. begin
  1273. {$ifdef i386}
  1274. { release FPU stack }
  1275. emit_reg(A_FSTP,S_NO,R_ST);
  1276. {
  1277. dec(trgcpu(rg).fpuvaroffset);
  1278. do NOT decrement as the increment before
  1279. is not called for unused results PM }
  1280. {$endif i386}
  1281. end;
  1282. end;
  1283. end;
  1284. {*****************************************************************************
  1285. TCGPROCINLINENODE
  1286. *****************************************************************************}
  1287. procedure tcgprocinlinenode.pass_2;
  1288. var st : tsymtable;
  1289. oldprocdef : tprocdef;
  1290. ps, i : longint;
  1291. tmpreg: tregister;
  1292. oldprocinfo : tprocinfo;
  1293. oldinlining_procedure,
  1294. nostackframe,make_global : boolean;
  1295. inlineentrycode,inlineexitcode : TAAsmoutput;
  1296. oldexitlabel,oldexit2label,oldquickexitlabel:tasmlabel;
  1297. oldregstate: pointer;
  1298. localsref : treference;
  1299. {$ifdef GDB}
  1300. startlabel,endlabel : tasmlabel;
  1301. pp : pchar;
  1302. mangled_length : longint;
  1303. {$endif GDB}
  1304. begin
  1305. { deallocate the registers used for the current procedure's regvars }
  1306. if assigned(aktprocdef.regvarinfo) then
  1307. begin
  1308. with pregvarinfo(aktprocdef.regvarinfo)^ do
  1309. for i := 1 to maxvarregs do
  1310. if assigned(regvars[i]) then
  1311. store_regvar(exprasmlist,regvars[i].reg);
  1312. rg.saveStateForInline(oldregstate);
  1313. { make sure the register allocator knows what the regvars in the }
  1314. { inlined code block are (JM) }
  1315. rg.resetusableregisters;
  1316. rg.clearregistercount;
  1317. rg.cleartempgen;
  1318. if assigned(inlineprocdef.regvarinfo) then
  1319. with pregvarinfo(inlineprocdef.regvarinfo)^ do
  1320. for i := 1 to maxvarregs do
  1321. if assigned(regvars[i]) then
  1322. begin
  1323. tmpreg:=rg.makeregsize(regvars[i].reg,OS_INT);
  1324. rg.makeregvar(tmpreg);
  1325. end;
  1326. end;
  1327. oldinlining_procedure:=inlining_procedure;
  1328. oldexitlabel:=aktexitlabel;
  1329. oldexit2label:=aktexit2label;
  1330. oldquickexitlabel:=quickexitlabel;
  1331. oldprocdef:=aktprocdef;
  1332. oldprocinfo:=procinfo;
  1333. objectlibrary.getlabel(aktexitlabel);
  1334. objectlibrary.getlabel(aktexit2label);
  1335. { we're inlining a procedure }
  1336. inlining_procedure:=true;
  1337. aktprocdef:=inlineprocdef;
  1338. { clone procinfo, but not the asmlists }
  1339. procinfo:=tprocinfo(cprocinfo.newinstance);
  1340. move(pointer(oldprocinfo)^,pointer(procinfo)^,cprocinfo.InstanceSize);
  1341. procinfo.aktentrycode:=nil;
  1342. procinfo.aktexitcode:=nil;
  1343. procinfo.aktproccode:=nil;
  1344. procinfo.aktlocaldata:=nil;
  1345. { set new procinfo }
  1346. procinfo.return_offset:=retoffset;
  1347. procinfo.para_offset:=para_offset;
  1348. procinfo.no_fast_exit:=false;
  1349. { arg space has been filled by the parent secondcall }
  1350. st:=aktprocdef.localst;
  1351. { set it to the same lexical level }
  1352. st.symtablelevel:=oldprocdef.localst.symtablelevel;
  1353. if st.datasize>0 then
  1354. begin
  1355. tg.GetTemp(exprasmlist,st.datasize,tt_persistant,localsref);
  1356. st.address_fixup:=localsref.offset+st.datasize;
  1357. {$ifdef extdebug}
  1358. Comment(V_debug,'local symtable is at offset '+tostr(st.address_fixup));
  1359. exprasmList.concat(tai_comment.Create(strpnew(
  1360. 'local symtable is at offset '+tostr(st.address_fixup))));
  1361. {$endif extdebug}
  1362. end;
  1363. exprasmList.concat(Tai_Marker.Create(InlineStart));
  1364. {$ifdef extdebug}
  1365. exprasmList.concat(tai_comment.Create(strpnew('Start of inlined proc')));
  1366. {$endif extdebug}
  1367. {$ifdef GDB}
  1368. if (cs_debuginfo in aktmoduleswitches) then
  1369. begin
  1370. objectlibrary.getaddrlabel(startlabel);
  1371. objectlibrary.getaddrlabel(endlabel);
  1372. cg.a_label(exprasmlist,startlabel);
  1373. inlineprocdef.localst.symtabletype:=inlinelocalsymtable;
  1374. inlineprocdef.parast.symtabletype:=inlineparasymtable;
  1375. { Here we must include the para and local symtable info }
  1376. inlineprocdef.concatstabto(withdebuglist);
  1377. { set it back for safety }
  1378. inlineprocdef.localst.symtabletype:=localsymtable;
  1379. inlineprocdef.parast.symtabletype:=parasymtable;
  1380. mangled_length:=length(oldprocdef.mangledname);
  1381. getmem(pp,mangled_length+50);
  1382. strpcopy(pp,'192,0,0,'+startlabel.name);
  1383. if (target_info.use_function_relative_addresses) then
  1384. begin
  1385. strpcopy(strend(pp),'-');
  1386. strpcopy(strend(pp),oldprocdef.mangledname);
  1387. end;
  1388. withdebugList.concat(Tai_stabn.Create(strnew(pp)));
  1389. end;
  1390. {$endif GDB}
  1391. { takes care of local data initialization }
  1392. inlineentrycode:=TAAsmoutput.Create;
  1393. inlineexitcode:=TAAsmoutput.Create;
  1394. ps:=para_size;
  1395. make_global:=false; { to avoid warning }
  1396. genentrycode(inlineentrycode,make_global,0,ps,nostackframe,true);
  1397. if po_assembler in aktprocdef.procoptions then
  1398. inlineentrycode.insert(Tai_marker.Create(asmblockstart));
  1399. exprasmList.concatlist(inlineentrycode);
  1400. secondpass(inlinetree);
  1401. genexitcode(inlineexitcode,0,false,true);
  1402. if po_assembler in aktprocdef.procoptions then
  1403. inlineexitcode.concat(Tai_marker.Create(asmblockend));
  1404. exprasmList.concatlist(inlineexitcode);
  1405. inlineentrycode.free;
  1406. inlineexitcode.free;
  1407. {$ifdef extdebug}
  1408. exprasmList.concat(tai_comment.Create(strpnew('End of inlined proc')));
  1409. {$endif extdebug}
  1410. exprasmList.concat(Tai_Marker.Create(InlineEnd));
  1411. {we can free the local data now, reset also the fixup address }
  1412. if st.datasize>0 then
  1413. begin
  1414. tg.UnGetTemp(exprasmlist,localsref);
  1415. st.address_fixup:=0;
  1416. end;
  1417. { restore procinfo }
  1418. procinfo.free;
  1419. procinfo:=oldprocinfo;
  1420. {$ifdef GDB}
  1421. if (cs_debuginfo in aktmoduleswitches) then
  1422. begin
  1423. cg.a_label(exprasmlist,endlabel);
  1424. strpcopy(pp,'224,0,0,'+endlabel.name);
  1425. if (target_info.use_function_relative_addresses) then
  1426. begin
  1427. strpcopy(strend(pp),'-');
  1428. strpcopy(strend(pp),oldprocdef.mangledname);
  1429. end;
  1430. withdebugList.concat(Tai_stabn.Create(strnew(pp)));
  1431. freemem(pp,mangled_length+50);
  1432. end;
  1433. {$endif GDB}
  1434. { restore }
  1435. aktprocdef:=oldprocdef;
  1436. aktexitlabel:=oldexitlabel;
  1437. aktexit2label:=oldexit2label;
  1438. quickexitlabel:=oldquickexitlabel;
  1439. inlining_procedure:=oldinlining_procedure;
  1440. { reallocate the registers used for the current procedure's regvars, }
  1441. { since they may have been used and then deallocated in the inlined }
  1442. { procedure (JM) }
  1443. if assigned(aktprocdef.regvarinfo) then
  1444. begin
  1445. rg.restoreStateAfterInline(oldregstate);
  1446. end;
  1447. end;
  1448. begin
  1449. ccallparanode:=tcgcallparanode;
  1450. ccallnode:=tcgcallnode;
  1451. cprocinlinenode:=tcgprocinlinenode;
  1452. end.
  1453. {
  1454. $Log$
  1455. Revision 1.31 2002-12-15 21:30:12 florian
  1456. * tcallnode.paraitem introduced, all references to defcoll removed
  1457. Revision 1.30 2002/11/27 20:04:39 peter
  1458. * cdecl array of const fixes
  1459. Revision 1.29 2002/11/25 17:43:17 peter
  1460. * splitted defbase in defutil,symutil,defcmp
  1461. * merged isconvertable and is_equal into compare_defs(_ext)
  1462. * made operator search faster by walking the list only once
  1463. Revision 1.28 2002/11/18 17:31:54 peter
  1464. * pass proccalloption to ret_in_xxx and push_xxx functions
  1465. Revision 1.27 2002/11/16 15:34:30 florian
  1466. * generic location for float results
  1467. Revision 1.26 2002/11/15 01:58:51 peter
  1468. * merged changes from 1.0.7 up to 04-11
  1469. - -V option for generating bug report tracing
  1470. - more tracing for option parsing
  1471. - errors for cdecl and high()
  1472. - win32 import stabs
  1473. - win32 records<=8 are returned in eax:edx (turned off by default)
  1474. - heaptrc update
  1475. - more info for temp management in .s file with EXTDEBUG
  1476. Revision 1.25 2002/10/05 12:43:25 carl
  1477. * fixes for Delphi 6 compilation
  1478. (warning : Some features do not work under Delphi)
  1479. Revision 1.24 2002/09/30 07:00:45 florian
  1480. * fixes to common code to get the alpha compiler compiled applied
  1481. Revision 1.23 2002/09/17 18:54:02 jonas
  1482. * a_load_reg_reg() now has two size parameters: source and dest. This
  1483. allows some optimizations on architectures that don't encode the
  1484. register size in the register name.
  1485. Revision 1.22 2002/09/07 15:25:02 peter
  1486. * old logs removed and tabs fixed
  1487. Revision 1.21 2002/09/07 11:50:02 jonas
  1488. * fixed small regalloction info bug
  1489. Revision 1.20 2002/09/02 11:25:20 florian
  1490. * fixed generic procedure variable calling
  1491. Revision 1.19 2002/09/01 21:04:48 florian
  1492. * several powerpc related stuff fixed
  1493. Revision 1.18 2002/09/01 18:43:27 peter
  1494. * include accumulator in regs_to_push list
  1495. Revision 1.17 2002/09/01 12:13:00 peter
  1496. * use a_call_reg
  1497. * ungetiftemp for procvar of object temp
  1498. Revision 1.16 2002/08/25 19:25:18 peter
  1499. * sym.insert_in_data removed
  1500. * symtable.insertvardata/insertconstdata added
  1501. * removed insert_in_data call from symtable.insert, it needs to be
  1502. called separatly. This allows to deref the address calculation
  1503. * procedures now calculate the parast addresses after the procedure
  1504. directives are parsed. This fixes the cdecl parast problem
  1505. * push_addr_param has an extra argument that specifies if cdecl is used
  1506. or not
  1507. Revision 1.15 2002/08/23 16:14:48 peter
  1508. * tempgen cleanup
  1509. * tt_noreuse temp type added that will be used in genentrycode
  1510. Revision 1.14 2002/08/20 16:55:38 peter
  1511. * don't write (stabs)line info when inlining a procedure
  1512. Revision 1.13 2002/08/19 19:36:42 peter
  1513. * More fixes for cross unit inlining, all tnodes are now implemented
  1514. * Moved pocall_internconst to po_internconst because it is not a
  1515. calling type at all and it conflicted when inlining of these small
  1516. functions was requested
  1517. Revision 1.12 2002/08/18 20:06:23 peter
  1518. * inlining is now also allowed in interface
  1519. * renamed write/load to ppuwrite/ppuload
  1520. * tnode storing in ppu
  1521. * nld,ncon,nbas are already updated for storing in ppu
  1522. Revision 1.11 2002/08/17 22:09:44 florian
  1523. * result type handling in tcgcal.pass_2 overhauled
  1524. * better tnode.dowrite
  1525. * some ppc stuff fixed
  1526. Revision 1.10 2002/08/17 09:23:35 florian
  1527. * first part of procinfo rewrite
  1528. Revision 1.9 2002/08/13 21:40:55 florian
  1529. * more fixes for ppc calling conventions
  1530. Revision 1.8 2002/08/13 18:01:51 carl
  1531. * rename swatoperands to swapoperands
  1532. + m68k first compilable version (still needs a lot of testing):
  1533. assembler generator, system information , inline
  1534. assembler reader.
  1535. Revision 1.7 2002/08/12 15:08:39 carl
  1536. + stab register indexes for powerpc (moved from gdb to cpubase)
  1537. + tprocessor enumeration moved to cpuinfo
  1538. + linker in target_info is now a class
  1539. * many many updates for m68k (will soon start to compile)
  1540. - removed some ifdef or correct them for correct cpu
  1541. Revision 1.6 2002/08/11 14:32:26 peter
  1542. * renamed current_library to objectlibrary
  1543. Revision 1.5 2002/08/11 13:24:11 peter
  1544. * saving of asmsymbols in ppu supported
  1545. * asmsymbollist global is removed and moved into a new class
  1546. tasmlibrarydata that will hold the info of a .a file which
  1547. corresponds with a single module. Added librarydata to tmodule
  1548. to keep the library info stored for the module. In the future the
  1549. objectfiles will also be stored to the tasmlibrarydata class
  1550. * all getlabel/newasmsymbol and friends are moved to the new class
  1551. Revision 1.4 2002/08/06 20:55:20 florian
  1552. * first part of ppc calling conventions fix
  1553. Revision 1.3 2002/07/20 11:57:53 florian
  1554. * types.pas renamed to defbase.pas because D6 contains a types
  1555. unit so this would conflicts if D6 programms are compiled
  1556. + Willamette/SSE2 instructions to assembler added
  1557. Revision 1.2 2002/07/13 19:38:43 florian
  1558. * some more generic calling stuff fixed
  1559. }