cpupara.pas 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645
  1. {
  2. Copyright (c) 2002 by Florian Klaempfl
  3. Generates the argument location information for i386
  4. This program is free software; you can redistribute it and/or modify
  5. it under the terms of the GNU General Public License as published bymethodpointer
  6. the Free Software Foundation; either version 2 of the License, or
  7. (at your option) any later version.
  8. This program is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. GNU General Public License for more details.
  12. You should have received a copy of the GNU General Public License
  13. along with this program; if not, write to the Free Software
  14. Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  15. ****************************************************************************
  16. }
  17. unit cpupara;
  18. {$i fpcdefs.inc}
  19. interface
  20. uses
  21. globtype,
  22. aasmtai,aasmdata,cpubase,cgbase,
  23. symconst,symtype,symsym,symdef,
  24. parabase,paramgr;
  25. type
  26. ti386paramanager = class(tparamanager)
  27. function param_use_paraloc(const cgpara:tcgpara):boolean;override;
  28. function ret_in_param(def : tdef;calloption : tproccalloption) : boolean;override;
  29. function push_addr_param(varspez:tvarspez;def : tdef;calloption : tproccalloption) : boolean;override;
  30. function get_para_align(calloption : tproccalloption):byte;override;
  31. function get_volatile_registers_int(calloption : tproccalloption):tcpuregisterset;override;
  32. function get_volatile_registers_fpu(calloption : tproccalloption):tcpuregisterset;override;
  33. function get_volatile_registers_mm(calloption : tproccalloption):tcpuregisterset;override;
  34. { Returns the location for the nr-st 32 Bit int parameter
  35. if every parameter before is an 32 Bit int parameter as well
  36. and if the calling conventions for the helper routines of the
  37. rtl are used.
  38. }
  39. procedure getintparaloc(calloption : tproccalloption; nr : longint;var cgpara:TCGPara);override;
  40. function create_paraloc_info(p : tabstractprocdef; side: tcallercallee):longint;override;
  41. function create_varargs_paraloc_info(p : tabstractprocdef; varargspara:tvarargsparalist):longint;override;
  42. procedure createtempparaloc(list: TAsmList;calloption : tproccalloption;parasym : tparavarsym;var cgpara:TCGPara);override;
  43. private
  44. procedure create_funcretloc_info(p : tabstractprocdef; side: tcallercallee);
  45. procedure create_stdcall_paraloc_info(p : tabstractprocdef; side: tcallercallee;paras:tparalist;var parasize:longint);
  46. procedure create_register_paraloc_info(p : tabstractprocdef; side: tcallercallee;paras:tparalist;var parareg,parasize:longint);
  47. end;
  48. implementation
  49. uses
  50. cutils,
  51. systems,verbose,
  52. defutil,
  53. cgutils;
  54. const
  55. parasupregs : array[0..2] of tsuperregister = (RS_EAX,RS_EDX,RS_ECX);
  56. {****************************************************************************
  57. TI386PARAMANAGER
  58. ****************************************************************************}
  59. function ti386paramanager.param_use_paraloc(const cgpara:tcgpara):boolean;
  60. var
  61. paraloc : pcgparalocation;
  62. begin
  63. if not assigned(cgpara.location) then
  64. internalerror(200410102);
  65. result:=true;
  66. { All locations are LOC_REFERENCE }
  67. paraloc:=cgpara.location;
  68. while assigned(paraloc) do
  69. begin
  70. if (paraloc^.loc<>LOC_REFERENCE) then
  71. begin
  72. result:=false;
  73. exit;
  74. end;
  75. paraloc:=paraloc^.next;
  76. end;
  77. end;
  78. function ti386paramanager.ret_in_param(def : tdef;calloption : tproccalloption) : boolean;
  79. var
  80. size: longint;
  81. begin
  82. case target_info.system of
  83. system_i386_win32 :
  84. begin
  85. case def.deftype of
  86. recorddef :
  87. begin
  88. { Win32 GCC returns small records in the FUNCTION_RETURN_REG.
  89. For stdcall we follow delphi instead of GCC }
  90. if (calloption in [pocall_cdecl,pocall_cppdecl]) and
  91. (def.size>0) and
  92. (def.size<=8) then
  93. begin
  94. result:=false;
  95. exit;
  96. end;
  97. end;
  98. end;
  99. end;
  100. system_i386_darwin :
  101. begin
  102. case def.deftype of
  103. recorddef :
  104. begin
  105. size := def.size;
  106. if (size > 0) and
  107. (size <= 8) and
  108. { only if size is a power of 2 }
  109. ((size and (size-1)) = 0) then
  110. begin
  111. result := false;
  112. exit;
  113. end;
  114. end;
  115. end;
  116. end;
  117. end;
  118. result:=inherited ret_in_param(def,calloption);
  119. end;
  120. function ti386paramanager.push_addr_param(varspez:tvarspez;def : tdef;calloption : tproccalloption) : boolean;
  121. begin
  122. result:=false;
  123. { var,out always require address }
  124. if varspez in [vs_var,vs_out] then
  125. begin
  126. result:=true;
  127. exit;
  128. end;
  129. { Only vs_const, vs_value here }
  130. case def.deftype of
  131. variantdef :
  132. begin
  133. { variants are small enough to be passed by value except if
  134. required by the windows api
  135. }
  136. if (target_info.system=system_i386_win32) and
  137. (calloption=pocall_stdcall) and
  138. (varspez=vs_const) then
  139. result:=true
  140. else
  141. result:=false;
  142. end;
  143. formaldef :
  144. result:=true;
  145. recorddef :
  146. begin
  147. { Win32 stdcall passes small records on the stack for call by
  148. value }
  149. if (target_info.system=system_i386_win32) and
  150. (calloption=pocall_stdcall) and
  151. (varspez=vs_value) and
  152. (def.size<=16) then
  153. result:=false
  154. else
  155. result:=
  156. (not(calloption in [pocall_cdecl,pocall_cppdecl]) and
  157. (def.size>sizeof(aint))) or
  158. ((calloption = pocall_mwpascal) and
  159. (varspez=vs_const));
  160. end;
  161. arraydef :
  162. begin
  163. { Win32 stdcall passes arrays on the stack for call by
  164. value }
  165. if (target_info.system=system_i386_win32) and
  166. (calloption=pocall_stdcall) and
  167. (varspez=vs_value) and
  168. (tarraydef(def).highrange>=tarraydef(def).lowrange) then
  169. result:=false
  170. else
  171. { array of const values are pushed on the stack as
  172. well as dyn. arrays }
  173. if (calloption in [pocall_cdecl,pocall_cppdecl]) then
  174. result:=not(is_array_of_const(def) or
  175. is_dynamic_array(def))
  176. else
  177. begin
  178. result:=(
  179. (tarraydef(def).highrange>=tarraydef(def).lowrange) and
  180. (def.size>sizeof(aint))
  181. ) or
  182. is_open_array(def) or
  183. is_array_of_const(def) or
  184. is_array_constructor(def);
  185. end;
  186. end;
  187. objectdef :
  188. result:=is_object(def);
  189. stringdef :
  190. result:=not(calloption in [pocall_cdecl,pocall_cppdecl]) and (tstringdef(def).string_typ in [st_shortstring,st_longstring]);
  191. procvardef :
  192. result:=not(calloption in [pocall_cdecl,pocall_cppdecl]) and (po_methodpointer in tprocvardef(def).procoptions);
  193. setdef :
  194. result:=not(calloption in [pocall_cdecl,pocall_cppdecl]) and (tsetdef(def).settype<>smallset);
  195. end;
  196. end;
  197. function ti386paramanager.get_para_align(calloption : tproccalloption):byte;
  198. begin
  199. if calloption=pocall_oldfpccall then
  200. begin
  201. if target_info.system in [system_i386_go32v2,system_i386_watcom] then
  202. result:=2
  203. else
  204. result:=4;
  205. end
  206. else
  207. result:=std_param_align;
  208. end;
  209. function ti386paramanager.get_volatile_registers_int(calloption : tproccalloption):tcpuregisterset;
  210. begin
  211. case calloption of
  212. pocall_internproc :
  213. result:=[];
  214. pocall_register,
  215. pocall_safecall,
  216. pocall_stdcall,
  217. pocall_cdecl,
  218. pocall_cppdecl,
  219. pocall_mwpascal :
  220. result:=[RS_EAX,RS_EDX,RS_ECX];
  221. pocall_far16,
  222. pocall_pascal,
  223. pocall_oldfpccall :
  224. result:=[RS_EAX,RS_EDX,RS_ECX,RS_ESI,RS_EDI,RS_EBX];
  225. else
  226. internalerror(200309071);
  227. end;
  228. end;
  229. function ti386paramanager.get_volatile_registers_fpu(calloption : tproccalloption):tcpuregisterset;
  230. begin
  231. result:=[0..first_fpu_imreg-1];
  232. end;
  233. function ti386paramanager.get_volatile_registers_mm(calloption : tproccalloption):tcpuregisterset;
  234. begin
  235. result:=[0..first_mm_imreg-1];
  236. end;
  237. procedure ti386paramanager.getintparaloc(calloption : tproccalloption; nr : longint;var cgpara:TCGPara);
  238. var
  239. paraloc : pcgparalocation;
  240. begin
  241. cgpara.reset;
  242. cgpara.size:=OS_INT;
  243. cgpara.intsize:=tcgsize2size[OS_INT];
  244. cgpara.alignment:=get_para_align(calloption);
  245. paraloc:=cgpara.add_location;
  246. with paraloc^ do
  247. begin
  248. size:=OS_INT;
  249. if calloption=pocall_register then
  250. begin
  251. if (nr<=high(parasupregs)+1) then
  252. begin
  253. if nr=0 then
  254. internalerror(200309271);
  255. loc:=LOC_REGISTER;
  256. register:=newreg(R_INTREGISTER,parasupregs[nr-1],R_SUBWHOLE);
  257. end
  258. else
  259. begin
  260. loc:=LOC_REFERENCE;
  261. reference.index:=NR_STACK_POINTER_REG;
  262. reference.offset:=sizeof(aint)*nr;
  263. end;
  264. end
  265. else
  266. begin
  267. loc:=LOC_REFERENCE;
  268. reference.index:=NR_STACK_POINTER_REG;
  269. reference.offset:=sizeof(aint)*nr;
  270. end;
  271. end;
  272. end;
  273. procedure ti386paramanager.create_funcretloc_info(p : tabstractprocdef; side: tcallercallee);
  274. var
  275. retcgsize : tcgsize;
  276. begin
  277. { Constructors return self instead of a boolean }
  278. if (p.proctypeoption=potype_constructor) then
  279. retcgsize:=OS_ADDR
  280. else
  281. retcgsize:=def_cgsize(p.rettype.def);
  282. location_reset(p.funcretloc[side],LOC_INVALID,OS_NO);
  283. { void has no location }
  284. if is_void(p.rettype.def) then
  285. begin
  286. location_reset(p.funcretloc[side],LOC_VOID,OS_NO);
  287. exit;
  288. end;
  289. { Return in FPU register? }
  290. if p.rettype.def.deftype=floatdef then
  291. begin
  292. p.funcretloc[side].loc:=LOC_FPUREGISTER;
  293. p.funcretloc[side].register:=NR_FPU_RESULT_REG;
  294. p.funcretloc[side].size:=retcgsize;
  295. end
  296. else
  297. { Return in register? }
  298. if not ret_in_param(p.rettype.def,p.proccalloption) then
  299. begin
  300. if retcgsize in [OS_64,OS_S64] then
  301. begin
  302. { low 32bits }
  303. p.funcretloc[side].loc:=LOC_REGISTER;
  304. p.funcretloc[side].size:=OS_64;
  305. if side=callerside then
  306. p.funcretloc[side].register64.reglo:=NR_FUNCTION_RESULT64_LOW_REG
  307. else
  308. p.funcretloc[side].register64.reglo:=NR_FUNCTION_RETURN64_LOW_REG;
  309. { high 32bits }
  310. if side=callerside then
  311. p.funcretloc[side].register64.reghi:=NR_FUNCTION_RESULT64_HIGH_REG
  312. else
  313. p.funcretloc[side].register64.reghi:=NR_FUNCTION_RETURN64_HIGH_REG;
  314. end
  315. else
  316. begin
  317. p.funcretloc[side].loc:=LOC_REGISTER;
  318. p.funcretloc[side].size:=retcgsize;
  319. if side=callerside then
  320. p.funcretloc[side].register:=newreg(R_INTREGISTER,RS_FUNCTION_RESULT_REG,cgsize2subreg(retcgsize))
  321. else
  322. p.funcretloc[side].register:=newreg(R_INTREGISTER,RS_FUNCTION_RETURN_REG,cgsize2subreg(retcgsize));
  323. end;
  324. end
  325. else
  326. begin
  327. p.funcretloc[side].loc:=LOC_REFERENCE;
  328. p.funcretloc[side].size:=retcgsize;
  329. end;
  330. end;
  331. procedure ti386paramanager.create_stdcall_paraloc_info(p : tabstractprocdef; side: tcallercallee;paras:tparalist;var parasize:longint);
  332. var
  333. i : integer;
  334. hp : tparavarsym;
  335. paraloc : pcgparalocation;
  336. l,
  337. paralen,
  338. varalign : longint;
  339. paraalign : shortint;
  340. pushaddr : boolean;
  341. paracgsize : tcgsize;
  342. begin
  343. paraalign:=get_para_align(p.proccalloption);
  344. { we push Flags and CS as long
  345. to cope with the IRETD
  346. and we save 6 register + 4 selectors }
  347. if po_interrupt in p.procoptions then
  348. inc(parasize,8+6*4+4*2);
  349. { Offset is calculated like:
  350. sub esp,12
  351. mov [esp+8],para3
  352. mov [esp+4],para2
  353. mov [esp],para1
  354. call function
  355. That means for pushes the para with the
  356. highest offset (see para3) needs to be pushed first
  357. }
  358. for i:=0 to paras.count-1 do
  359. begin
  360. hp:=tparavarsym(paras[i]);
  361. pushaddr:=push_addr_param(hp.varspez,hp.vartype.def,p.proccalloption);
  362. if pushaddr then
  363. begin
  364. paralen:=sizeof(aint);
  365. paracgsize:=OS_ADDR;
  366. end
  367. else
  368. begin
  369. paralen:=push_size(hp.varspez,hp.vartype.def,p.proccalloption);
  370. paracgsize:=def_cgsize(hp.vartype.def);
  371. end;
  372. hp.paraloc[side].reset;
  373. hp.paraloc[side].size:=paracgsize;
  374. hp.paraloc[side].intsize:=paralen;
  375. hp.paraloc[side].Alignment:=paraalign;
  376. { Copy to stack? }
  377. if (paracgsize=OS_NO) or
  378. (use_fixed_stack) then
  379. begin
  380. paraloc:=hp.paraloc[side].add_location;
  381. paraloc^.loc:=LOC_REFERENCE;
  382. paraloc^.size:=paracgsize;
  383. if side=callerside then
  384. paraloc^.reference.index:=NR_STACK_POINTER_REG
  385. else
  386. paraloc^.reference.index:=NR_FRAME_POINTER_REG;
  387. varalign:=used_align(size_2_align(paralen),paraalign,paraalign);
  388. { don't let push_size return 16, because then we can }
  389. { read past the end of the heap since the value is only }
  390. { 10 bytes long (JM) }
  391. if (paracgsize = OS_F80) and
  392. (target_info.system = system_i386_darwin) then
  393. paralen:=16;
  394. paraloc^.reference.offset:=parasize;
  395. if side=calleeside then
  396. inc(paraloc^.reference.offset,target_info.first_parm_offset);
  397. parasize:=align(parasize+paralen,varalign);
  398. end
  399. else
  400. begin
  401. if paralen=0 then
  402. internalerror(200501163);
  403. while (paralen>0) do
  404. begin
  405. paraloc:=hp.paraloc[side].add_location;
  406. paraloc^.loc:=LOC_REFERENCE;
  407. { single and double need a single location }
  408. if (paracgsize in [OS_F64,OS_F32]) then
  409. begin
  410. paraloc^.size:=paracgsize;
  411. l:=paralen;
  412. end
  413. else
  414. begin
  415. { We can allocate at maximum 32 bits per location }
  416. if paralen>sizeof(aint) then
  417. l:=sizeof(aint)
  418. else
  419. l:=paralen;
  420. paraloc^.size:=int_cgsize(l);
  421. end;
  422. if side=callerside then
  423. paraloc^.reference.index:=NR_STACK_POINTER_REG
  424. else
  425. paraloc^.reference.index:=NR_FRAME_POINTER_REG;
  426. varalign:=used_align(size_2_align(l),paraalign,paraalign);
  427. paraloc^.reference.offset:=parasize;
  428. if side=calleeside then
  429. inc(paraloc^.reference.offset,target_info.first_parm_offset);
  430. parasize:=align(parasize+l,varalign);
  431. dec(paralen,l);
  432. end;
  433. end;
  434. end;
  435. end;
  436. procedure ti386paramanager.create_register_paraloc_info(p : tabstractprocdef; side: tcallercallee;paras:tparalist;
  437. var parareg,parasize:longint);
  438. var
  439. hp : tparavarsym;
  440. paraloc : pcgparalocation;
  441. paracgsize : tcgsize;
  442. i : integer;
  443. l,
  444. paralen,
  445. varalign : longint;
  446. pushaddr : boolean;
  447. paraalign : shortint;
  448. begin
  449. paraalign:=get_para_align(p.proccalloption);
  450. { Register parameters are assigned from left to right }
  451. for i:=0 to paras.count-1 do
  452. begin
  453. hp:=tparavarsym(paras[i]);
  454. pushaddr:=push_addr_param(hp.varspez,hp.vartype.def,p.proccalloption);
  455. if pushaddr then
  456. begin
  457. paralen:=sizeof(aint);
  458. paracgsize:=OS_ADDR;
  459. end
  460. else
  461. begin
  462. paralen:=push_size(hp.varspez,hp.vartype.def,p.proccalloption);
  463. paracgsize:=def_cgsize(hp.vartype.def);
  464. end;
  465. hp.paraloc[side].reset;
  466. hp.paraloc[side].size:=paracgsize;
  467. hp.paraloc[side].intsize:=paralen;
  468. hp.paraloc[side].Alignment:=paraalign;
  469. {
  470. EAX
  471. EDX
  472. ECX
  473. Stack
  474. Stack
  475. 64bit values,floats,arrays and records are always
  476. on the stack.
  477. }
  478. if (parareg<=high(parasupregs)) and
  479. (paralen<=sizeof(aint)) and
  480. (
  481. not(hp.vartype.def.deftype in [floatdef,recorddef,arraydef]) or
  482. pushaddr
  483. ) then
  484. begin
  485. paraloc:=hp.paraloc[side].add_location;
  486. paraloc^.size:=paracgsize;
  487. paraloc^.loc:=LOC_REGISTER;
  488. paraloc^.register:=newreg(R_INTREGISTER,parasupregs[parareg],cgsize2subreg(paracgsize));
  489. inc(parareg);
  490. end
  491. else
  492. begin
  493. { Copy to stack? }
  494. if (use_fixed_stack) or
  495. (paracgsize=OS_NO) then
  496. begin
  497. paraloc:=hp.paraloc[side].add_location;
  498. paraloc^.loc:=LOC_REFERENCE;
  499. paraloc^.size:=paracgsize;
  500. if side=callerside then
  501. paraloc^.reference.index:=NR_STACK_POINTER_REG
  502. else
  503. paraloc^.reference.index:=NR_FRAME_POINTER_REG;
  504. varalign:=used_align(size_2_align(paralen),paraalign,paraalign);
  505. paraloc^.reference.offset:=parasize;
  506. if side=calleeside then
  507. inc(paraloc^.reference.offset,target_info.first_parm_offset);
  508. parasize:=align(parasize+paralen,varalign);
  509. end
  510. else
  511. begin
  512. if paralen=0 then
  513. internalerror(200501163);
  514. while (paralen>0) do
  515. begin
  516. paraloc:=hp.paraloc[side].add_location;
  517. paraloc^.loc:=LOC_REFERENCE;
  518. { Extended and double need a single location }
  519. if (paracgsize in [OS_F64,OS_F32]) then
  520. begin
  521. paraloc^.size:=paracgsize;
  522. l:=paralen;
  523. end
  524. else
  525. begin
  526. { We can allocate at maximum 32 bits per location }
  527. if paralen>sizeof(aint) then
  528. l:=sizeof(aint)
  529. else
  530. l:=paralen;
  531. paraloc^.size:=int_cgsize(l);
  532. end;
  533. if side=callerside then
  534. paraloc^.reference.index:=NR_STACK_POINTER_REG
  535. else
  536. paraloc^.reference.index:=NR_FRAME_POINTER_REG;
  537. varalign:=used_align(size_2_align(l),paraalign,paraalign);
  538. paraloc^.reference.offset:=parasize;
  539. if side=calleeside then
  540. inc(paraloc^.reference.offset,target_info.first_parm_offset);
  541. parasize:=align(parasize+l,varalign);
  542. dec(paralen,l);
  543. end;
  544. end;
  545. end;
  546. end;
  547. end;
  548. function ti386paramanager.create_paraloc_info(p : tabstractprocdef; side: tcallercallee):longint;
  549. var
  550. parasize,
  551. parareg : longint;
  552. begin
  553. parasize:=0;
  554. parareg:=0;
  555. case p.proccalloption of
  556. pocall_register :
  557. create_register_paraloc_info(p,side,p.paras,parareg,parasize);
  558. pocall_internproc :
  559. begin
  560. { Use default calling }
  561. if (pocall_default=pocall_register) then
  562. create_register_paraloc_info(p,side,p.paras,parareg,parasize)
  563. else
  564. create_stdcall_paraloc_info(p,side,p.paras,parasize);
  565. end;
  566. else
  567. create_stdcall_paraloc_info(p,side,p.paras,parasize);
  568. end;
  569. create_funcretloc_info(p,side);
  570. result:=parasize;
  571. end;
  572. function ti386paramanager.create_varargs_paraloc_info(p : tabstractprocdef; varargspara:tvarargsparalist):longint;
  573. var
  574. parasize : longint;
  575. begin
  576. parasize:=0;
  577. { calculate the registers for the normal parameters }
  578. create_stdcall_paraloc_info(p,callerside,p.paras,parasize);
  579. { append the varargs }
  580. create_stdcall_paraloc_info(p,callerside,varargspara,parasize);
  581. result:=parasize;
  582. end;
  583. procedure ti386paramanager.createtempparaloc(list: TAsmList;calloption : tproccalloption;parasym : tparavarsym;var cgpara:TCGPara);
  584. var
  585. paraloc : pcgparalocation;
  586. begin
  587. paraloc:=parasym.paraloc[callerside].location;
  588. { No need for temps when value is pushed }
  589. if not(use_fixed_stack) and
  590. assigned(paraloc) and
  591. (paraloc^.loc=LOC_REFERENCE) and
  592. (paraloc^.reference.index=NR_STACK_POINTER_REG) then
  593. duplicateparaloc(list,calloption,parasym,cgpara)
  594. else
  595. inherited createtempparaloc(list,calloption,parasym,cgpara);
  596. end;
  597. begin
  598. paramanager:=ti386paramanager.create;
  599. end.