tcld.pas 21 KB

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