tcld.pas 23 KB

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