tcld.pas 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601
  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. {$ifdef newoptimizations2}
  184. var
  185. hp : ptree;
  186. {$endif newoptimizations2}
  187. begin
  188. { must be made unique }
  189. set_unique(p^.left);
  190. { set we the function result? }
  191. set_funcret_is_valid(p^.left);
  192. firstpass(p^.left);
  193. set_varstate(p^.left,false);
  194. if codegenerror then
  195. exit;
  196. { assignements to open arrays aren't allowed }
  197. if is_open_array(p^.left^.resulttype) then
  198. CGMessage(type_e_mismatch);
  199. { test if we can avoid copying string to temp
  200. as in s:=s+...; (PM) }
  201. {$ifdef dummyi386}
  202. if ((p^.right^.treetype=addn) or (p^.right^.treetype=subn)) and
  203. equal_trees(p^.left,p^.right^.left) and
  204. (ret_in_acc(p^.left^.resulttype)) and
  205. (not cs_rangechecking in aktmoduleswitches^) then
  206. begin
  207. disposetree(p^.right^.left);
  208. hp:=p^.right;
  209. p^.right:=p^.right^.right;
  210. if hp^.treetype=addn then
  211. p^.assigntyp:=at_plus
  212. else
  213. p^.assigntyp:=at_minus;
  214. putnode(hp);
  215. end;
  216. if p^.assigntyp<>at_normal then
  217. begin
  218. { for fpu type there is no faster way }
  219. if is_fpu(p^.left^.resulttype) then
  220. case p^.assigntyp of
  221. at_plus : p^.right:=gennode(addn,getcopy(p^.left),p^.right);
  222. at_minus : p^.right:=gennode(subn,getcopy(p^.left),p^.right);
  223. at_star : p^.right:=gennode(muln,getcopy(p^.left),p^.right);
  224. at_slash : p^.right:=gennode(slashn,getcopy(p^.left),p^.right);
  225. end;
  226. end;
  227. {$endif i386}
  228. firstpass(p^.right);
  229. set_varstate(p^.right,true);
  230. if codegenerror then
  231. exit;
  232. { some string functions don't need conversion, so treat them separatly }
  233. if is_shortstring(p^.left^.resulttype) and (assigned(p^.right^.resulttype)) then
  234. begin
  235. if not (is_shortstring(p^.right^.resulttype) or
  236. is_ansistring(p^.right^.resulttype) or
  237. is_char(p^.right^.resulttype)) then
  238. begin
  239. p^.right:=gentypeconvnode(p^.right,p^.left^.resulttype);
  240. firstpass(p^.right);
  241. if codegenerror then
  242. exit;
  243. end;
  244. { we call STRCOPY }
  245. procinfo^.flags:=procinfo^.flags or pi_do_call;
  246. { test for s:=s+anything ... }
  247. { the problem is for
  248. s:=s+s+s;
  249. this is broken here !! }
  250. {$ifdef newoptimizations2}
  251. { the above is fixed now, but still problem with s := s + f(); if }
  252. { f modifies s (bad programming, so only enable if uncertain }
  253. { optimizations are on) (JM) }
  254. if (cs_UncertainOpts in aktglobalswitches) then
  255. begin
  256. hp := p^.right;
  257. while hp^.treetype=addn do hp:=hp^.left;
  258. if equal_trees(p^.left,hp) and
  259. not multiple_uses(p^.left,p^.right) then
  260. begin
  261. p^.concat_string:=true;
  262. hp:=p^.right;
  263. while hp^.treetype=addn do
  264. begin
  265. hp^.use_strconcat:=true;
  266. hp:=hp^.left;
  267. end;
  268. end;
  269. end;
  270. {$endif newoptimizations2}
  271. end
  272. else
  273. begin
  274. p^.right:=gentypeconvnode(p^.right,p^.left^.resulttype);
  275. firstpass(p^.right);
  276. if codegenerror then
  277. exit;
  278. end;
  279. { test if node can be assigned, properties are allowed }
  280. valid_for_assign(p^.left,true);
  281. { check if local proc/func is assigned to procvar }
  282. if p^.right^.resulttype^.deftype=procvardef then
  283. test_local_to_procvar(pprocvardef(p^.right^.resulttype),p^.left^.resulttype);
  284. p^.resulttype:=voiddef;
  285. {
  286. p^.registers32:=max(p^.left^.registers32,p^.right^.registers32);
  287. p^.registersfpu:=max(p^.left^.registersfpu,p^.right^.registersfpu);
  288. }
  289. p^.registers32:=p^.left^.registers32+p^.right^.registers32;
  290. p^.registersfpu:=max(p^.left^.registersfpu,p^.right^.registersfpu);
  291. {$ifdef SUPPORT_MMX}
  292. p^.registersmmx:=max(p^.left^.registersmmx,p^.right^.registersmmx);
  293. {$endif SUPPORT_MMX}
  294. end;
  295. {*****************************************************************************
  296. FirstFuncRet
  297. *****************************************************************************}
  298. procedure firstfuncret(var p : ptree);
  299. begin
  300. p^.resulttype:=p^.rettype.def;
  301. p^.location.loc:=LOC_REFERENCE;
  302. if ret_in_param(p^.rettype.def) or
  303. (procinfo<>pprocinfo(p^.funcretprocinfo)) then
  304. p^.registers32:=1;
  305. end;
  306. {*****************************************************************************
  307. FirstArrayConstructRange
  308. *****************************************************************************}
  309. procedure firstarrayconstructrange(var p:ptree);
  310. begin
  311. firstpass(p^.left);
  312. set_varstate(p^.left,true);
  313. firstpass(p^.right);
  314. set_varstate(p^.right,true);
  315. calcregisters(p,0,0,0);
  316. p^.resulttype:=p^.left^.resulttype;
  317. end;
  318. {*****************************************************************************
  319. FirstArrayConstruct
  320. *****************************************************************************}
  321. procedure firstarrayconstruct(var p : ptree);
  322. var
  323. pd : pdef;
  324. thp,
  325. chp,
  326. hp : ptree;
  327. len : longint;
  328. varia : boolean;
  329. begin
  330. { are we allowing array constructor? Then convert it to a set }
  331. if not allow_array_constructor then
  332. begin
  333. arrayconstructor_to_set(p);
  334. firstpass(p);
  335. exit;
  336. end;
  337. { only pass left tree, right tree contains next construct if any }
  338. pd:=p^.constructdef;
  339. len:=0;
  340. varia:=false;
  341. if assigned(p^.left) then
  342. begin
  343. hp:=p;
  344. while assigned(hp) do
  345. begin
  346. firstpass(hp^.left);
  347. set_varstate(hp^.left,true);
  348. if (not get_para_resulttype) and (not p^.novariaallowed) then
  349. begin
  350. case hp^.left^.resulttype^.deftype of
  351. enumdef :
  352. begin
  353. hp^.left:=gentypeconvnode(hp^.left,s32bitdef);
  354. firstpass(hp^.left);
  355. end;
  356. orddef :
  357. begin
  358. if is_integer(hp^.left^.resulttype) then
  359. begin
  360. hp^.left:=gentypeconvnode(hp^.left,s32bitdef);
  361. firstpass(hp^.left);
  362. end;
  363. end;
  364. floatdef :
  365. begin
  366. hp^.left:=gentypeconvnode(hp^.left,bestrealdef^);
  367. firstpass(hp^.left);
  368. end;
  369. stringdef :
  370. begin
  371. if p^.cargs then
  372. begin
  373. hp^.left:=gentypeconvnode(hp^.left,charpointerdef);
  374. firstpass(hp^.left);
  375. end;
  376. end;
  377. procvardef :
  378. begin
  379. hp^.left:=gentypeconvnode(hp^.left,voidpointerdef);
  380. firstpass(hp^.left);
  381. end;
  382. pointerdef,
  383. classrefdef,
  384. objectdef : ;
  385. else
  386. CGMessagePos1(hp^.left^.fileinfo,type_e_wrong_type_in_array_constructor,hp^.left^.resulttype^.typename);
  387. end;
  388. end;
  389. if (pd=nil) then
  390. pd:=hp^.left^.resulttype
  391. else
  392. begin
  393. if ((p^.novariaallowed) or (not varia)) and
  394. (not is_equal(pd,hp^.left^.resulttype)) then
  395. begin
  396. { if both should be equal try inserting a conversion }
  397. if p^.novariaallowed then
  398. begin
  399. hp^.left:=gentypeconvnode(hp^.left,pd);
  400. firstpass(hp^.left);
  401. end;
  402. varia:=true;
  403. end;
  404. end;
  405. inc(len);
  406. hp:=hp^.right;
  407. end;
  408. { swap the tree for cargs }
  409. if p^.cargs and (not p^.cargswap) then
  410. begin
  411. chp:=nil;
  412. hp:=p;
  413. while assigned(hp) do
  414. begin
  415. thp:=hp^.right;
  416. hp^.right:=chp;
  417. chp:=hp;
  418. hp:=thp;
  419. end;
  420. p:=chp;
  421. p^.cargs:=true;
  422. p^.cargswap:=true;
  423. end;
  424. end;
  425. calcregisters(p,0,0,0);
  426. { looks a little bit dangerous to me }
  427. { len-1 gives problems with is_open_array if len=0, }
  428. { is_open_array checks now for isconstructor (FK) }
  429. { if no type is set then we set the type to voiddef to overcome a
  430. 0 addressing }
  431. if not assigned(pd) then
  432. pd:=voiddef;
  433. { skip if already done ! (PM) }
  434. if not assigned(p^.resulttype) or
  435. (p^.resulttype^.deftype<>arraydef) or
  436. not parraydef(p^.resulttype)^.IsConstructor or
  437. (parraydef(p^.resulttype)^.lowrange<>0) or
  438. (parraydef(p^.resulttype)^.highrange<>len-1) then
  439. p^.resulttype:=new(parraydef,init(0,len-1,s32bitdef));
  440. parraydef(p^.resulttype)^.elementtype.def:=pd;
  441. parraydef(p^.resulttype)^.IsConstructor:=true;
  442. parraydef(p^.resulttype)^.IsVariant:=varia;
  443. p^.location.loc:=LOC_MEM;
  444. end;
  445. {*****************************************************************************
  446. Type
  447. *****************************************************************************}
  448. procedure firsttype(var p : ptree);
  449. begin
  450. { do nothing, p^.resulttype is already set }
  451. end;
  452. end.
  453. {
  454. $Log$
  455. Revision 1.64 2000-04-25 14:43:36 jonas
  456. - disabled "string_var := string_var + ... " and "string_var + char_var"
  457. optimizations (were only active with -dnewoptimizations) because of
  458. several internal issues
  459. Revision 1.63 2000/04/23 21:04:09 jonas
  460. * only enable string_concat optimization with uncertain optimizations,
  461. because it gives wrong results with "s := s + f()" where s is a
  462. string and f() is a call to a function that modifies s
  463. Revision 1.62 2000/04/08 16:22:11 jonas
  464. * fixed concat_string optimization and enabled it when
  465. -dnewoptimizations is used
  466. Revision 1.61 2000/02/24 18:41:39 peter
  467. * removed warnings/notes
  468. Revision 1.60 2000/02/17 14:53:43 florian
  469. * some updates for the newcg
  470. Revision 1.59 2000/02/09 13:23:07 peter
  471. * log truncated
  472. Revision 1.58 2000/01/21 22:06:16 florian
  473. * fixed for the fix of bug 793
  474. * fpu variables modified by nested subroutines aren't regable anymore
  475. * $maxfpuregisters doesn't modify anymore the behavior of a procedure before
  476. Revision 1.57 2000/01/07 01:14:46 peter
  477. * updated copyright to 2000
  478. Revision 1.56 2000/01/06 01:08:59 pierre
  479. * fix for web bug 776
  480. Revision 1.55 1999/12/31 14:26:27 peter
  481. * fixed crash with empty array constructors
  482. Revision 1.54 1999/12/09 23:18:05 pierre
  483. * no_fast_exit if procedure contains implicit termination code
  484. Revision 1.53 1999/12/02 17:28:53 peter
  485. * fixed procvar -> pointer for array of const
  486. Revision 1.52 1999/11/30 10:40:58 peter
  487. + ttype, tsymlist
  488. Revision 1.51 1999/11/18 15:34:50 pierre
  489. * Notes/Hints for local syms changed to
  490. Set_varstate function
  491. Revision 1.50 1999/11/17 17:05:07 pierre
  492. * Notes/hints changes
  493. Revision 1.49 1999/11/06 14:34:30 peter
  494. * truncated log to 20 revs
  495. Revision 1.48 1999/10/26 12:30:46 peter
  496. * const parameter is now checked
  497. * better and generic check if a node can be used for assigning
  498. * export fixes
  499. * procvar equal works now (it never had worked at least from 0.99.8)
  500. * defcoll changed to linkedlist with pparaitem so it can easily be
  501. walked both directions
  502. Revision 1.47 1999/10/13 10:35:27 peter
  503. * var must match exactly error msg extended with got and expected type
  504. * array constructor type check now gives error on wrong types
  505. Revision 1.46 1999/09/27 23:45:01 peter
  506. * procinfo is now a pointer
  507. * support for result setting in sub procedure
  508. Revision 1.45 1999/09/17 17:14:12 peter
  509. * @procvar fixes for tp mode
  510. * @<id>:= gives now an error
  511. Revision 1.44 1999/09/11 19:47:26 florian
  512. * bug fix for @tobject.method, fixes bug 557, 605 and 606
  513. Revision 1.43 1999/09/11 09:08:34 florian
  514. * fixed bug 596
  515. * fixed some problems with procedure variables and procedures of object,
  516. especially in TP mode. Procedure of object doesn't apply only to classes,
  517. it is also allowed for objects !!
  518. Revision 1.42 1999/09/10 18:48:11 florian
  519. * some bug fixes (e.g. must_be_valid and procinfo^.funcret_is_valid)
  520. * most things for stored properties fixed
  521. Revision 1.41 1999/08/16 23:23:41 peter
  522. * arrayconstructor -> openarray type conversions for element types
  523. Revision 1.40 1999/08/13 21:33:17 peter
  524. * support for array constructors extended and more error checking
  525. Revision 1.39 1999/08/05 16:53:24 peter
  526. * V_Fatal=1, all other V_ are also increased
  527. * Check for local procedure when assigning procvar
  528. * fixed comment parsing because directives
  529. * oldtp mode directives better supported
  530. * added some messages to errore.msg
  531. }