tcld.pas 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609
  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(procinfo^._class);
  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.66 2000-05-15 19:29:50 peter
  458. * fixed crash with resourcestring in const
  459. Revision 1.65 2000/05/14 18:48:24 florian
  460. + Int64/QWord stuff for array of const added
  461. Revision 1.64 2000/04/25 14:43:36 jonas
  462. - disabled "string_var := string_var + ... " and "string_var + char_var"
  463. optimizations (were only active with -dnewoptimizations) because of
  464. several internal issues
  465. Revision 1.63 2000/04/23 21:04:09 jonas
  466. * only enable string_concat optimization with uncertain optimizations,
  467. because it gives wrong results with "s := s + f()" where s is a
  468. string and f() is a call to a function that modifies s
  469. Revision 1.62 2000/04/08 16:22:11 jonas
  470. * fixed concat_string optimization and enabled it when
  471. -dnewoptimizations is used
  472. Revision 1.61 2000/02/24 18:41:39 peter
  473. * removed warnings/notes
  474. Revision 1.60 2000/02/17 14:53:43 florian
  475. * some updates for the newcg
  476. Revision 1.59 2000/02/09 13:23:07 peter
  477. * log truncated
  478. Revision 1.58 2000/01/21 22:06:16 florian
  479. * fixed for the fix of bug 793
  480. * fpu variables modified by nested subroutines aren't regable anymore
  481. * $maxfpuregisters doesn't modify anymore the behavior of a procedure before
  482. Revision 1.57 2000/01/07 01:14:46 peter
  483. * updated copyright to 2000
  484. Revision 1.56 2000/01/06 01:08:59 pierre
  485. * fix for web bug 776
  486. Revision 1.55 1999/12/31 14:26:27 peter
  487. * fixed crash with empty array constructors
  488. Revision 1.54 1999/12/09 23:18:05 pierre
  489. * no_fast_exit if procedure contains implicit termination code
  490. Revision 1.53 1999/12/02 17:28:53 peter
  491. * fixed procvar -> pointer for array of const
  492. Revision 1.52 1999/11/30 10:40:58 peter
  493. + ttype, tsymlist
  494. Revision 1.51 1999/11/18 15:34:50 pierre
  495. * Notes/Hints for local syms changed to
  496. Set_varstate function
  497. Revision 1.50 1999/11/17 17:05:07 pierre
  498. * Notes/hints changes
  499. Revision 1.49 1999/11/06 14:34:30 peter
  500. * truncated log to 20 revs
  501. Revision 1.48 1999/10/26 12:30:46 peter
  502. * const parameter is now checked
  503. * better and generic check if a node can be used for assigning
  504. * export fixes
  505. * procvar equal works now (it never had worked at least from 0.99.8)
  506. * defcoll changed to linkedlist with pparaitem so it can easily be
  507. walked both directions
  508. Revision 1.47 1999/10/13 10:35:27 peter
  509. * var must match exactly error msg extended with got and expected type
  510. * array constructor type check now gives error on wrong types
  511. Revision 1.46 1999/09/27 23:45:01 peter
  512. * procinfo is now a pointer
  513. * support for result setting in sub procedure
  514. Revision 1.45 1999/09/17 17:14:12 peter
  515. * @procvar fixes for tp mode
  516. * @<id>:= gives now an error
  517. Revision 1.44 1999/09/11 19:47:26 florian
  518. * bug fix for @tobject.method, fixes bug 557, 605 and 606
  519. Revision 1.43 1999/09/11 09:08:34 florian
  520. * fixed bug 596
  521. * fixed some problems with procedure variables and procedures of object,
  522. especially in TP mode. Procedure of object doesn't apply only to classes,
  523. it is also allowed for objects !!
  524. Revision 1.42 1999/09/10 18:48:11 florian
  525. * some bug fixes (e.g. must_be_valid and procinfo^.funcret_is_valid)
  526. * most things for stored properties fixed
  527. Revision 1.41 1999/08/16 23:23:41 peter
  528. * arrayconstructor -> openarray type conversions for element types
  529. Revision 1.40 1999/08/13 21:33:17 peter
  530. * support for array constructors extended and more error checking
  531. Revision 1.39 1999/08/05 16:53:24 peter
  532. * V_Fatal=1, all other V_ are also increased
  533. * Check for local procedure when assigning procvar
  534. * fixed comment parsing because directives
  535. * oldtp mode directives better supported
  536. * added some messages to errore.msg
  537. }