tcld.pas 23 KB

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