tcld.pas 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563
  1. {
  2. $Id$
  3. Copyright (c) 1998-2000 by Florian Klaempfl
  4. Type checking and register allocation for load/assignment 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 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 tcld;
  19. interface
  20. uses
  21. tree;
  22. procedure firstload(var p : ptree);
  23. procedure firstassignment(var p : ptree);
  24. procedure firstfuncret(var p : ptree);
  25. procedure firstarrayconstructrange(var p:ptree);
  26. procedure firstarrayconstruct(var p : ptree);
  27. procedure firsttype(var p : ptree);
  28. implementation
  29. uses
  30. cobjects,verbose,globtype,globals,systems,
  31. symconst,symtable,aasm,types,
  32. hcodegen,htypechk,pass_1,
  33. tccnv,cpubase
  34. {$ifdef i386}
  35. ,tgeni386
  36. {$endif}
  37. ;
  38. {*****************************************************************************
  39. FirstLoad
  40. *****************************************************************************}
  41. procedure firstload(var p : ptree);
  42. var
  43. p1 : ptree;
  44. begin
  45. if (p^.symtable^.symtabletype=withsymtable) and
  46. (pwithsymtable(p^.symtable)^.direct_with) and
  47. (p^.symtableentry^.typ=varsym) then
  48. begin
  49. p1:=getcopy(ptree(pwithsymtable(p^.symtable)^.withrefnode));
  50. p1:=gensubscriptnode(pvarsym(p^.symtableentry),p1);
  51. putnode(p);
  52. p:=p1;
  53. firstpass(p);
  54. exit;
  55. end;
  56. p^.location.loc:=LOC_REFERENCE;
  57. p^.registers32:=0;
  58. p^.registersfpu:=0;
  59. {$ifdef SUPPORT_MMX}
  60. p^.registersmmx:=0;
  61. {$endif SUPPORT_MMX}
  62. if p^.symtableentry^.typ=funcretsym then
  63. begin
  64. p1:=genzeronode(funcretn);
  65. p1^.funcretprocinfo:=pprocinfo(pfuncretsym(p^.symtableentry)^.funcretprocinfo);
  66. p1^.rettype:=pfuncretsym(p^.symtableentry)^.rettype;
  67. firstpass(p1);
  68. putnode(p);
  69. p:=p1;
  70. exit;
  71. end;
  72. if p^.symtableentry^.typ=absolutesym then
  73. begin
  74. p^.resulttype:=pabsolutesym(p^.symtableentry)^.vartype.def;
  75. if pabsolutesym(p^.symtableentry)^.abstyp=tovar then
  76. p^.symtableentry:=pabsolutesym(p^.symtableentry)^.ref;
  77. p^.symtable:=p^.symtableentry^.owner;
  78. p^.is_absolute:=true;
  79. end;
  80. case p^.symtableentry^.typ of
  81. absolutesym :;
  82. constsym:
  83. begin
  84. if pconstsym(p^.symtableentry)^.consttyp=constresourcestring then
  85. begin
  86. p^.resulttype:=cansistringdef;
  87. { we use ansistrings so no fast exit here }
  88. procinfo^.no_fast_exit:=true;
  89. p^.location.loc:=LOC_MEM;
  90. end
  91. else
  92. internalerror(22799);
  93. end;
  94. varsym :
  95. begin
  96. if not(p^.is_absolute) and (p^.resulttype=nil) then
  97. p^.resulttype:=pvarsym(p^.symtableentry)^.vartype.def;
  98. if (p^.symtable^.symtabletype in [parasymtable,localsymtable]) and
  99. (lexlevel>p^.symtable^.symtablelevel) then
  100. begin
  101. { if the variable is in an other stackframe then we need
  102. a register to dereference }
  103. if (p^.symtable^.symtablelevel)>0 then
  104. begin
  105. p^.registers32:=1;
  106. { further, the variable can't be put into a register }
  107. pvarsym(p^.symtableentry)^.varoptions:=
  108. pvarsym(p^.symtableentry)^.varoptions-[vo_fpuregable,vo_regable];
  109. end;
  110. end;
  111. if (pvarsym(p^.symtableentry)^.varspez=vs_const) then
  112. p^.location.loc:=LOC_MEM;
  113. { we need a register for call by reference parameters }
  114. if (pvarsym(p^.symtableentry)^.varspez=vs_var) or
  115. ((pvarsym(p^.symtableentry)^.varspez=vs_const) and
  116. push_addr_param(pvarsym(p^.symtableentry)^.vartype.def)) or
  117. { call by value open arrays are also indirect addressed }
  118. is_open_array(pvarsym(p^.symtableentry)^.vartype.def) then
  119. p^.registers32:=1;
  120. if p^.symtable^.symtabletype=withsymtable then
  121. inc(p^.registers32);
  122. if ([vo_is_thread_var,vo_is_dll_var]*pvarsym(p^.symtableentry)^.varoptions)<>[] then
  123. p^.registers32:=1;
  124. { a class variable is a pointer !!!
  125. yes, but we have to resolve the reference in an
  126. appropriate tree node (FK)
  127. if (pvarsym(p^.symtableentry)^.definition^.deftype=objectdef) and
  128. ((pobjectdef(pvarsym(p^.symtableentry)^.definition)^.options and oo_is_class)<>0) then
  129. p^.registers32:=1;
  130. }
  131. { count variable references }
  132. { this will create problem with local var set by
  133. under_procedures
  134. if (assigned(pvarsym(p^.symtableentry)^.owner) and assigned(aktprocsym)
  135. and ((pvarsym(p^.symtableentry)^.owner = aktprocsym^.definition^.localst)
  136. or (pvarsym(p^.symtableentry)^.owner = aktprocsym^.definition^.localst))) then }
  137. if t_times<1 then
  138. inc(pvarsym(p^.symtableentry)^.refs)
  139. else
  140. inc(pvarsym(p^.symtableentry)^.refs,t_times);
  141. end;
  142. typedconstsym :
  143. if not p^.is_absolute then
  144. p^.resulttype:=ptypedconstsym(p^.symtableentry)^.typedconsttype.def;
  145. procsym :
  146. begin
  147. if assigned(pprocsym(p^.symtableentry)^.definition^.nextoverloaded) then
  148. CGMessage(parser_e_no_overloaded_procvars);
  149. p^.resulttype:=pprocsym(p^.symtableentry)^.definition;
  150. { if the owner of the procsym is a object, }
  151. { left must be set, if left isn't set }
  152. { it can be only self }
  153. { this code is only used in TP procvar mode }
  154. if (m_tp_procvar in aktmodeswitches) and
  155. not(assigned(p^.left)) and
  156. (pprocsym(p^.symtableentry)^.owner^.symtabletype=objectsymtable) then
  157. p^.left:=genselfnode(procinfo^._class);
  158. { method pointer ? }
  159. if assigned(p^.left) then
  160. begin
  161. firstpass(p^.left);
  162. p^.registers32:=max(p^.registers32,p^.left^.registers32);
  163. p^.registersfpu:=max(p^.registersfpu,p^.left^.registersfpu);
  164. {$ifdef SUPPORT_MMX}
  165. p^.registersmmx:=max(p^.registersmmx,p^.left^.registersmmx);
  166. {$endif SUPPORT_MMX}
  167. end;
  168. end;
  169. else internalerror(3);
  170. end;
  171. end;
  172. {*****************************************************************************
  173. FirstAssignment
  174. *****************************************************************************}
  175. procedure firstassignment(var p : ptree);
  176. var
  177. hp : ptree;
  178. begin
  179. { must be made unique }
  180. set_unique(p^.left);
  181. { set we the function result? }
  182. set_funcret_is_valid(p^.left);
  183. firstpass(p^.left);
  184. set_varstate(p^.left,false);
  185. if codegenerror then
  186. exit;
  187. { assignements to open arrays aren't allowed }
  188. if is_open_array(p^.left^.resulttype) then
  189. CGMessage(type_e_mismatch);
  190. { test if we can avoid copying string to temp
  191. as in s:=s+...; (PM) }
  192. {$ifdef dummyi386}
  193. if ((p^.right^.treetype=addn) or (p^.right^.treetype=subn)) and
  194. equal_trees(p^.left,p^.right^.left) and
  195. (ret_in_acc(p^.left^.resulttype)) and
  196. (not cs_rangechecking in aktmoduleswitches^) then
  197. begin
  198. disposetree(p^.right^.left);
  199. hp:=p^.right;
  200. p^.right:=p^.right^.right;
  201. if hp^.treetype=addn then
  202. p^.assigntyp:=at_plus
  203. else
  204. p^.assigntyp:=at_minus;
  205. putnode(hp);
  206. end;
  207. if p^.assigntyp<>at_normal then
  208. begin
  209. { for fpu type there is no faster way }
  210. if is_fpu(p^.left^.resulttype) then
  211. case p^.assigntyp of
  212. at_plus : p^.right:=gennode(addn,getcopy(p^.left),p^.right);
  213. at_minus : p^.right:=gennode(subn,getcopy(p^.left),p^.right);
  214. at_star : p^.right:=gennode(muln,getcopy(p^.left),p^.right);
  215. at_slash : p^.right:=gennode(slashn,getcopy(p^.left),p^.right);
  216. end;
  217. end;
  218. {$endif i386}
  219. firstpass(p^.right);
  220. set_varstate(p^.right,true);
  221. if codegenerror then
  222. exit;
  223. { some string functions don't need conversion, so treat them separatly }
  224. if is_shortstring(p^.left^.resulttype) and (assigned(p^.right^.resulttype)) then
  225. begin
  226. if not (is_shortstring(p^.right^.resulttype) or
  227. is_ansistring(p^.right^.resulttype) or
  228. is_char(p^.right^.resulttype)) then
  229. begin
  230. p^.right:=gentypeconvnode(p^.right,p^.left^.resulttype);
  231. firstpass(p^.right);
  232. if codegenerror then
  233. exit;
  234. end;
  235. { we call STRCOPY }
  236. procinfo^.flags:=procinfo^.flags or pi_do_call;
  237. hp:=p^.right;
  238. { test for s:=s+anything ... }
  239. { the problem is for
  240. s:=s+s+s;
  241. this is broken here !! }
  242. { while hp^.treetype=addn do hp:=hp^.left;
  243. if equal_trees(p^.left,hp) then
  244. begin
  245. p^.concat_string:=true;
  246. hp:=p^.right;
  247. while hp^.treetype=addn do
  248. begin
  249. hp^.use_strconcat:=true;
  250. hp:=hp^.left;
  251. end;
  252. end; }
  253. end
  254. else
  255. begin
  256. p^.right:=gentypeconvnode(p^.right,p^.left^.resulttype);
  257. firstpass(p^.right);
  258. if codegenerror then
  259. exit;
  260. end;
  261. { test if node can be assigned, properties are allowed }
  262. valid_for_assign(p^.left,true);
  263. { check if local proc/func is assigned to procvar }
  264. if p^.right^.resulttype^.deftype=procvardef then
  265. test_local_to_procvar(pprocvardef(p^.right^.resulttype),p^.left^.resulttype);
  266. p^.resulttype:=voiddef;
  267. {
  268. p^.registers32:=max(p^.left^.registers32,p^.right^.registers32);
  269. p^.registersfpu:=max(p^.left^.registersfpu,p^.right^.registersfpu);
  270. }
  271. p^.registers32:=p^.left^.registers32+p^.right^.registers32;
  272. p^.registersfpu:=max(p^.left^.registersfpu,p^.right^.registersfpu);
  273. {$ifdef SUPPORT_MMX}
  274. p^.registersmmx:=max(p^.left^.registersmmx,p^.right^.registersmmx);
  275. {$endif SUPPORT_MMX}
  276. end;
  277. {*****************************************************************************
  278. FirstFuncRet
  279. *****************************************************************************}
  280. procedure firstfuncret(var p : ptree);
  281. begin
  282. p^.resulttype:=p^.rettype.def;
  283. p^.location.loc:=LOC_REFERENCE;
  284. if ret_in_param(p^.rettype.def) or
  285. (procinfo<>pprocinfo(p^.funcretprocinfo)) then
  286. p^.registers32:=1;
  287. end;
  288. {*****************************************************************************
  289. FirstArrayConstructRange
  290. *****************************************************************************}
  291. procedure firstarrayconstructrange(var p:ptree);
  292. begin
  293. firstpass(p^.left);
  294. set_varstate(p^.left,true);
  295. firstpass(p^.right);
  296. set_varstate(p^.right,true);
  297. calcregisters(p,0,0,0);
  298. p^.resulttype:=p^.left^.resulttype;
  299. end;
  300. {*****************************************************************************
  301. FirstArrayConstruct
  302. *****************************************************************************}
  303. procedure firstarrayconstruct(var p : ptree);
  304. var
  305. pd : pdef;
  306. thp,
  307. chp,
  308. hp : ptree;
  309. len : longint;
  310. varia : boolean;
  311. begin
  312. { are we allowing array constructor? Then convert it to a set }
  313. if not allow_array_constructor then
  314. begin
  315. arrayconstructor_to_set(p);
  316. firstpass(p);
  317. exit;
  318. end;
  319. { only pass left tree, right tree contains next construct if any }
  320. pd:=p^.constructdef;
  321. len:=0;
  322. varia:=false;
  323. if assigned(p^.left) then
  324. begin
  325. hp:=p;
  326. while assigned(hp) do
  327. begin
  328. firstpass(hp^.left);
  329. set_varstate(hp^.left,true);
  330. if (not get_para_resulttype) and (not p^.novariaallowed) then
  331. begin
  332. case hp^.left^.resulttype^.deftype of
  333. enumdef :
  334. begin
  335. hp^.left:=gentypeconvnode(hp^.left,s32bitdef);
  336. firstpass(hp^.left);
  337. end;
  338. orddef :
  339. begin
  340. if is_integer(hp^.left^.resulttype) then
  341. begin
  342. hp^.left:=gentypeconvnode(hp^.left,s32bitdef);
  343. firstpass(hp^.left);
  344. end;
  345. end;
  346. floatdef :
  347. begin
  348. hp^.left:=gentypeconvnode(hp^.left,bestrealdef^);
  349. firstpass(hp^.left);
  350. end;
  351. stringdef :
  352. begin
  353. if p^.cargs then
  354. begin
  355. hp^.left:=gentypeconvnode(hp^.left,charpointerdef);
  356. firstpass(hp^.left);
  357. end;
  358. end;
  359. procvardef :
  360. begin
  361. hp^.left:=gentypeconvnode(hp^.left,voidpointerdef);
  362. firstpass(hp^.left);
  363. end;
  364. pointerdef,
  365. classrefdef,
  366. objectdef : ;
  367. else
  368. CGMessagePos1(hp^.left^.fileinfo,type_e_wrong_type_in_array_constructor,hp^.left^.resulttype^.typename);
  369. end;
  370. end;
  371. if (pd=nil) then
  372. pd:=hp^.left^.resulttype
  373. else
  374. begin
  375. if ((p^.novariaallowed) or (not varia)) and
  376. (not is_equal(pd,hp^.left^.resulttype)) then
  377. begin
  378. { if both should be equal try inserting a conversion }
  379. if p^.novariaallowed then
  380. begin
  381. hp^.left:=gentypeconvnode(hp^.left,pd);
  382. firstpass(hp^.left);
  383. end;
  384. varia:=true;
  385. end;
  386. end;
  387. inc(len);
  388. hp:=hp^.right;
  389. end;
  390. { swap the tree for cargs }
  391. if p^.cargs and (not p^.cargswap) then
  392. begin
  393. chp:=nil;
  394. hp:=p;
  395. while assigned(hp) do
  396. begin
  397. thp:=hp^.right;
  398. hp^.right:=chp;
  399. chp:=hp;
  400. hp:=thp;
  401. end;
  402. p:=chp;
  403. p^.cargs:=true;
  404. p^.cargswap:=true;
  405. end;
  406. end;
  407. calcregisters(p,0,0,0);
  408. { looks a little bit dangerous to me }
  409. { len-1 gives problems with is_open_array if len=0, }
  410. { is_open_array checks now for isconstructor (FK) }
  411. { if no type is set then we set the type to voiddef to overcome a
  412. 0 addressing }
  413. if not assigned(pd) then
  414. pd:=voiddef;
  415. { skip if already done ! (PM) }
  416. if not assigned(p^.resulttype) or
  417. (p^.resulttype^.deftype<>arraydef) or
  418. not parraydef(p^.resulttype)^.IsConstructor or
  419. (parraydef(p^.resulttype)^.lowrange<>0) or
  420. (parraydef(p^.resulttype)^.highrange<>len-1) then
  421. p^.resulttype:=new(parraydef,init(0,len-1,s32bitdef));
  422. parraydef(p^.resulttype)^.elementtype.def:=pd;
  423. parraydef(p^.resulttype)^.IsConstructor:=true;
  424. parraydef(p^.resulttype)^.IsVariant:=varia;
  425. p^.location.loc:=LOC_MEM;
  426. end;
  427. {*****************************************************************************
  428. Type
  429. *****************************************************************************}
  430. procedure firsttype(var p : ptree);
  431. begin
  432. { do nothing, p^.resulttype is already set }
  433. end;
  434. end.
  435. {
  436. $Log$
  437. Revision 1.59 2000-02-09 13:23:07 peter
  438. * log truncated
  439. Revision 1.58 2000/01/21 22:06:16 florian
  440. * fixed for the fix of bug 793
  441. * fpu variables modified by nested subroutines aren't regable anymore
  442. * $maxfpuregisters doesn't modify anymore the behavior of a procedure before
  443. Revision 1.57 2000/01/07 01:14:46 peter
  444. * updated copyright to 2000
  445. Revision 1.56 2000/01/06 01:08:59 pierre
  446. * fix for web bug 776
  447. Revision 1.55 1999/12/31 14:26:27 peter
  448. * fixed crash with empty array constructors
  449. Revision 1.54 1999/12/09 23:18:05 pierre
  450. * no_fast_exit if procedure contains implicit termination code
  451. Revision 1.53 1999/12/02 17:28:53 peter
  452. * fixed procvar -> pointer for array of const
  453. Revision 1.52 1999/11/30 10:40:58 peter
  454. + ttype, tsymlist
  455. Revision 1.51 1999/11/18 15:34:50 pierre
  456. * Notes/Hints for local syms changed to
  457. Set_varstate function
  458. Revision 1.50 1999/11/17 17:05:07 pierre
  459. * Notes/hints changes
  460. Revision 1.49 1999/11/06 14:34:30 peter
  461. * truncated log to 20 revs
  462. Revision 1.48 1999/10/26 12:30:46 peter
  463. * const parameter is now checked
  464. * better and generic check if a node can be used for assigning
  465. * export fixes
  466. * procvar equal works now (it never had worked at least from 0.99.8)
  467. * defcoll changed to linkedlist with pparaitem so it can easily be
  468. walked both directions
  469. Revision 1.47 1999/10/13 10:35:27 peter
  470. * var must match exactly error msg extended with got and expected type
  471. * array constructor type check now gives error on wrong types
  472. Revision 1.46 1999/09/27 23:45:01 peter
  473. * procinfo is now a pointer
  474. * support for result setting in sub procedure
  475. Revision 1.45 1999/09/17 17:14:12 peter
  476. * @procvar fixes for tp mode
  477. * @<id>:= gives now an error
  478. Revision 1.44 1999/09/11 19:47:26 florian
  479. * bug fix for @tobject.method, fixes bug 557, 605 and 606
  480. Revision 1.43 1999/09/11 09:08:34 florian
  481. * fixed bug 596
  482. * fixed some problems with procedure variables and procedures of object,
  483. especially in TP mode. Procedure of object doesn't apply only to classes,
  484. it is also allowed for objects !!
  485. Revision 1.42 1999/09/10 18:48:11 florian
  486. * some bug fixes (e.g. must_be_valid and procinfo^.funcret_is_valid)
  487. * most things for stored properties fixed
  488. Revision 1.41 1999/08/16 23:23:41 peter
  489. * arrayconstructor -> openarray type conversions for element types
  490. Revision 1.40 1999/08/13 21:33:17 peter
  491. * support for array constructors extended and more error checking
  492. Revision 1.39 1999/08/05 16:53:24 peter
  493. * V_Fatal=1, all other V_ are also increased
  494. * Check for local procedure when assigning procvar
  495. * fixed comment parsing because directives
  496. * oldtp mode directives better supported
  497. * added some messages to errore.msg
  498. }