tcld.pas 22 KB

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