tcld.pas 21 KB

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