tcld.pas 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605
  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) and
  359. not(is_64bitint(hp^.left^.resulttype)) then
  360. begin
  361. hp^.left:=gentypeconvnode(hp^.left,s32bitdef);
  362. firstpass(hp^.left);
  363. end;
  364. end;
  365. floatdef :
  366. begin
  367. hp^.left:=gentypeconvnode(hp^.left,bestrealdef^);
  368. firstpass(hp^.left);
  369. end;
  370. stringdef :
  371. begin
  372. if p^.cargs then
  373. begin
  374. hp^.left:=gentypeconvnode(hp^.left,charpointerdef);
  375. firstpass(hp^.left);
  376. end;
  377. end;
  378. procvardef :
  379. begin
  380. hp^.left:=gentypeconvnode(hp^.left,voidpointerdef);
  381. firstpass(hp^.left);
  382. end;
  383. pointerdef,
  384. classrefdef,
  385. objectdef : ;
  386. else
  387. CGMessagePos1(hp^.left^.fileinfo,type_e_wrong_type_in_array_constructor,hp^.left^.resulttype^.typename);
  388. end;
  389. end;
  390. if (pd=nil) then
  391. pd:=hp^.left^.resulttype
  392. else
  393. begin
  394. if ((p^.novariaallowed) or (not varia)) and
  395. (not is_equal(pd,hp^.left^.resulttype)) then
  396. begin
  397. { if both should be equal try inserting a conversion }
  398. if p^.novariaallowed then
  399. begin
  400. hp^.left:=gentypeconvnode(hp^.left,pd);
  401. firstpass(hp^.left);
  402. end;
  403. varia:=true;
  404. end;
  405. end;
  406. inc(len);
  407. hp:=hp^.right;
  408. end;
  409. { swap the tree for cargs }
  410. if p^.cargs and (not p^.cargswap) then
  411. begin
  412. chp:=nil;
  413. hp:=p;
  414. while assigned(hp) do
  415. begin
  416. thp:=hp^.right;
  417. hp^.right:=chp;
  418. chp:=hp;
  419. hp:=thp;
  420. end;
  421. p:=chp;
  422. p^.cargs:=true;
  423. p^.cargswap:=true;
  424. end;
  425. end;
  426. calcregisters(p,0,0,0);
  427. { looks a little bit dangerous to me }
  428. { len-1 gives problems with is_open_array if len=0, }
  429. { is_open_array checks now for isconstructor (FK) }
  430. { if no type is set then we set the type to voiddef to overcome a
  431. 0 addressing }
  432. if not assigned(pd) then
  433. pd:=voiddef;
  434. { skip if already done ! (PM) }
  435. if not assigned(p^.resulttype) or
  436. (p^.resulttype^.deftype<>arraydef) or
  437. not parraydef(p^.resulttype)^.IsConstructor or
  438. (parraydef(p^.resulttype)^.lowrange<>0) or
  439. (parraydef(p^.resulttype)^.highrange<>len-1) then
  440. p^.resulttype:=new(parraydef,init(0,len-1,s32bitdef));
  441. parraydef(p^.resulttype)^.elementtype.def:=pd;
  442. parraydef(p^.resulttype)^.IsConstructor:=true;
  443. parraydef(p^.resulttype)^.IsVariant:=varia;
  444. p^.location.loc:=LOC_MEM;
  445. end;
  446. {*****************************************************************************
  447. Type
  448. *****************************************************************************}
  449. procedure firsttype(var p : ptree);
  450. begin
  451. { do nothing, p^.resulttype is already set }
  452. end;
  453. end.
  454. {
  455. $Log$
  456. Revision 1.65 2000-05-14 18:48:24 florian
  457. + Int64/QWord stuff for array of const added
  458. Revision 1.64 2000/04/25 14:43:36 jonas
  459. - disabled "string_var := string_var + ... " and "string_var + char_var"
  460. optimizations (were only active with -dnewoptimizations) because of
  461. several internal issues
  462. Revision 1.63 2000/04/23 21:04:09 jonas
  463. * only enable string_concat optimization with uncertain optimizations,
  464. because it gives wrong results with "s := s + f()" where s is a
  465. string and f() is a call to a function that modifies s
  466. Revision 1.62 2000/04/08 16:22:11 jonas
  467. * fixed concat_string optimization and enabled it when
  468. -dnewoptimizations is used
  469. Revision 1.61 2000/02/24 18:41:39 peter
  470. * removed warnings/notes
  471. Revision 1.60 2000/02/17 14:53:43 florian
  472. * some updates for the newcg
  473. Revision 1.59 2000/02/09 13:23:07 peter
  474. * log truncated
  475. Revision 1.58 2000/01/21 22:06:16 florian
  476. * fixed for the fix of bug 793
  477. * fpu variables modified by nested subroutines aren't regable anymore
  478. * $maxfpuregisters doesn't modify anymore the behavior of a procedure before
  479. Revision 1.57 2000/01/07 01:14:46 peter
  480. * updated copyright to 2000
  481. Revision 1.56 2000/01/06 01:08:59 pierre
  482. * fix for web bug 776
  483. Revision 1.55 1999/12/31 14:26:27 peter
  484. * fixed crash with empty array constructors
  485. Revision 1.54 1999/12/09 23:18:05 pierre
  486. * no_fast_exit if procedure contains implicit termination code
  487. Revision 1.53 1999/12/02 17:28:53 peter
  488. * fixed procvar -> pointer for array of const
  489. Revision 1.52 1999/11/30 10:40:58 peter
  490. + ttype, tsymlist
  491. Revision 1.51 1999/11/18 15:34:50 pierre
  492. * Notes/Hints for local syms changed to
  493. Set_varstate function
  494. Revision 1.50 1999/11/17 17:05:07 pierre
  495. * Notes/hints changes
  496. Revision 1.49 1999/11/06 14:34:30 peter
  497. * truncated log to 20 revs
  498. Revision 1.48 1999/10/26 12:30:46 peter
  499. * const parameter is now checked
  500. * better and generic check if a node can be used for assigning
  501. * export fixes
  502. * procvar equal works now (it never had worked at least from 0.99.8)
  503. * defcoll changed to linkedlist with pparaitem so it can easily be
  504. walked both directions
  505. Revision 1.47 1999/10/13 10:35:27 peter
  506. * var must match exactly error msg extended with got and expected type
  507. * array constructor type check now gives error on wrong types
  508. Revision 1.46 1999/09/27 23:45:01 peter
  509. * procinfo is now a pointer
  510. * support for result setting in sub procedure
  511. Revision 1.45 1999/09/17 17:14:12 peter
  512. * @procvar fixes for tp mode
  513. * @<id>:= gives now an error
  514. Revision 1.44 1999/09/11 19:47:26 florian
  515. * bug fix for @tobject.method, fixes bug 557, 605 and 606
  516. Revision 1.43 1999/09/11 09:08:34 florian
  517. * fixed bug 596
  518. * fixed some problems with procedure variables and procedures of object,
  519. especially in TP mode. Procedure of object doesn't apply only to classes,
  520. it is also allowed for objects !!
  521. Revision 1.42 1999/09/10 18:48:11 florian
  522. * some bug fixes (e.g. must_be_valid and procinfo^.funcret_is_valid)
  523. * most things for stored properties fixed
  524. Revision 1.41 1999/08/16 23:23:41 peter
  525. * arrayconstructor -> openarray type conversions for element types
  526. Revision 1.40 1999/08/13 21:33:17 peter
  527. * support for array constructors extended and more error checking
  528. Revision 1.39 1999/08/05 16:53:24 peter
  529. * V_Fatal=1, all other V_ are also increased
  530. * Check for local procedure when assigning procvar
  531. * fixed comment parsing because directives
  532. * oldtp mode directives better supported
  533. * added some messages to errore.msg
  534. }