tcld.pas 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537
  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. cutils,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. { handle first absolute as it will replace the p^.symtableentry }
  70. if p^.symtableentry^.typ=absolutesym then
  71. begin
  72. p^.resulttype:=pabsolutesym(p^.symtableentry)^.vartype.def;
  73. { replace the symtableentry when it points to a var, else
  74. we are finished }
  75. if pabsolutesym(p^.symtableentry)^.abstyp=tovar then
  76. begin
  77. p^.symtableentry:=pabsolutesym(p^.symtableentry)^.ref;
  78. p^.symtable:=p^.symtableentry^.owner;
  79. p^.is_absolute:=true;
  80. end
  81. else
  82. exit;
  83. end;
  84. case p^.symtableentry^.typ of
  85. funcretsym :
  86. begin
  87. p1:=genzeronode(funcretn);
  88. p1^.funcretprocinfo:=pprocinfo(pfuncretsym(p^.symtableentry)^.funcretprocinfo);
  89. p1^.rettype:=pfuncretsym(p^.symtableentry)^.rettype;
  90. firstpass(p1);
  91. { if it's refered as absolute then we need to have the
  92. type of the absolute instead of the function return,
  93. the function return is then also assigned }
  94. if p^.is_absolute then
  95. begin
  96. pprocinfo(p1^.funcretprocinfo)^.funcret_state:=vs_assigned;
  97. p1^.resulttype:=p^.resulttype;
  98. end;
  99. putnode(p);
  100. p:=p1;
  101. end;
  102. constsym:
  103. begin
  104. if pconstsym(p^.symtableentry)^.consttyp=constresourcestring then
  105. begin
  106. p^.resulttype:=cansistringdef;
  107. { we use ansistrings so no fast exit here }
  108. if assigned(procinfo) then
  109. procinfo^.no_fast_exit:=true;
  110. p^.location.loc:=LOC_MEM;
  111. end
  112. else
  113. internalerror(22799);
  114. end;
  115. varsym :
  116. begin
  117. { if it's refered by absolute then it's used }
  118. if p^.is_absolute then
  119. pvarsym(p^.symtableentry)^.varstate:=vs_used
  120. else
  121. if (p^.resulttype=nil) then
  122. p^.resulttype:=pvarsym(p^.symtableentry)^.vartype.def;
  123. if (p^.symtable^.symtabletype in [parasymtable,localsymtable]) and
  124. (lexlevel>p^.symtable^.symtablelevel) then
  125. begin
  126. { if the variable is in an other stackframe then we need
  127. a register to dereference }
  128. if (p^.symtable^.symtablelevel)>0 then
  129. begin
  130. p^.registers32:=1;
  131. { further, the variable can't be put into a register }
  132. pvarsym(p^.symtableentry)^.varoptions:=
  133. pvarsym(p^.symtableentry)^.varoptions-[vo_fpuregable,vo_regable];
  134. end;
  135. end;
  136. if (pvarsym(p^.symtableentry)^.varspez=vs_const) then
  137. p^.location.loc:=LOC_MEM;
  138. { we need a register for call by reference parameters }
  139. if (pvarsym(p^.symtableentry)^.varspez in [vs_var,vs_out]) or
  140. ((pvarsym(p^.symtableentry)^.varspez=vs_const) and
  141. push_addr_param(pvarsym(p^.symtableentry)^.vartype.def)) or
  142. { call by value open arrays are also indirect addressed }
  143. is_open_array(pvarsym(p^.symtableentry)^.vartype.def) then
  144. p^.registers32:=1;
  145. if p^.symtable^.symtabletype=withsymtable then
  146. inc(p^.registers32);
  147. if ([vo_is_thread_var,vo_is_dll_var]*pvarsym(p^.symtableentry)^.varoptions)<>[] then
  148. p^.registers32:=1;
  149. { a class variable is a pointer !!!
  150. yes, but we have to resolve the reference in an
  151. appropriate tree node (FK)
  152. if (pvarsym(p^.symtableentry)^.definition^.deftype=objectdef) and
  153. ((pobjectdef(pvarsym(p^.symtableentry)^.definition)^.options and oo_is_class)<>0) then
  154. p^.registers32:=1;
  155. }
  156. { count variable references }
  157. { this will create problem with local var set by
  158. under_procedures
  159. if (assigned(pvarsym(p^.symtableentry)^.owner) and assigned(aktprocsym)
  160. and ((pvarsym(p^.symtableentry)^.owner = aktprocsym^.definition^.localst)
  161. or (pvarsym(p^.symtableentry)^.owner = aktprocsym^.definition^.localst))) then }
  162. if t_times<1 then
  163. inc(pvarsym(p^.symtableentry)^.refs)
  164. else
  165. inc(pvarsym(p^.symtableentry)^.refs,t_times);
  166. end;
  167. typedconstsym :
  168. if not p^.is_absolute then
  169. p^.resulttype:=ptypedconstsym(p^.symtableentry)^.typedconsttype.def;
  170. procsym :
  171. begin
  172. if assigned(pprocsym(p^.symtableentry)^.definition^.nextoverloaded) then
  173. CGMessage(parser_e_no_overloaded_procvars);
  174. p^.resulttype:=pprocsym(p^.symtableentry)^.definition;
  175. { if the owner of the procsym is a object, }
  176. { left must be set, if left isn't set }
  177. { it can be only self }
  178. { this code is only used in TP procvar mode }
  179. if (m_tp_procvar in aktmodeswitches) and
  180. not(assigned(p^.left)) and
  181. (pprocsym(p^.symtableentry)^.owner^.symtabletype=objectsymtable) then
  182. p^.left:=genselfnode(pobjectdef(p^.symtableentry^.owner^.defowner));
  183. { method pointer ? }
  184. if assigned(p^.left) then
  185. begin
  186. firstpass(p^.left);
  187. p^.registers32:=max(p^.registers32,p^.left^.registers32);
  188. p^.registersfpu:=max(p^.registersfpu,p^.left^.registersfpu);
  189. {$ifdef SUPPORT_MMX}
  190. p^.registersmmx:=max(p^.registersmmx,p^.left^.registersmmx);
  191. {$endif SUPPORT_MMX}
  192. end;
  193. end;
  194. else
  195. internalerror(3);
  196. end;
  197. end;
  198. {*****************************************************************************
  199. FirstAssignment
  200. *****************************************************************************}
  201. procedure firstassignment(var p : ptree);
  202. {$ifdef newoptimizations2}
  203. var
  204. hp : ptree;
  205. {$endif newoptimizations2}
  206. begin
  207. { must be made unique }
  208. set_unique(p^.left);
  209. { set we the function result? }
  210. set_funcret_is_valid(p^.left);
  211. firstpass(p^.left);
  212. set_varstate(p^.left,false);
  213. if codegenerror then
  214. exit;
  215. { assignements to open arrays aren't allowed }
  216. if is_open_array(p^.left^.resulttype) then
  217. CGMessage(type_e_mismatch);
  218. { test if we can avoid copying string to temp
  219. as in s:=s+...; (PM) }
  220. {$ifdef dummyi386}
  221. if ((p^.right^.treetype=addn) or (p^.right^.treetype=subn)) and
  222. equal_trees(p^.left,p^.right^.left) and
  223. (ret_in_acc(p^.left^.resulttype)) and
  224. (not cs_rangechecking in aktmoduleswitches^) then
  225. begin
  226. disposetree(p^.right^.left);
  227. hp:=p^.right;
  228. p^.right:=p^.right^.right;
  229. if hp^.treetype=addn then
  230. p^.assigntyp:=at_plus
  231. else
  232. p^.assigntyp:=at_minus;
  233. putnode(hp);
  234. end;
  235. if p^.assigntyp<>at_normal then
  236. begin
  237. { for fpu type there is no faster way }
  238. if is_fpu(p^.left^.resulttype) then
  239. case p^.assigntyp of
  240. at_plus : p^.right:=gennode(addn,getcopy(p^.left),p^.right);
  241. at_minus : p^.right:=gennode(subn,getcopy(p^.left),p^.right);
  242. at_star : p^.right:=gennode(muln,getcopy(p^.left),p^.right);
  243. at_slash : p^.right:=gennode(slashn,getcopy(p^.left),p^.right);
  244. end;
  245. end;
  246. {$endif i386}
  247. firstpass(p^.right);
  248. set_varstate(p^.right,true);
  249. if codegenerror then
  250. exit;
  251. { some string functions don't need conversion, so treat them separatly }
  252. if is_shortstring(p^.left^.resulttype) and (assigned(p^.right^.resulttype)) then
  253. begin
  254. if not (is_shortstring(p^.right^.resulttype) or
  255. is_ansistring(p^.right^.resulttype) or
  256. is_char(p^.right^.resulttype)) then
  257. begin
  258. p^.right:=gentypeconvnode(p^.right,p^.left^.resulttype);
  259. firstpass(p^.right);
  260. if codegenerror then
  261. exit;
  262. end;
  263. { we call STRCOPY }
  264. procinfo^.flags:=procinfo^.flags or pi_do_call;
  265. { test for s:=s+anything ... }
  266. { the problem is for
  267. s:=s+s+s;
  268. this is broken here !! }
  269. {$ifdef newoptimizations2}
  270. { the above is fixed now, but still problem with s := s + f(); if }
  271. { f modifies s (bad programming, so only enable if uncertain }
  272. { optimizations are on) (JM) }
  273. if (cs_UncertainOpts in aktglobalswitches) then
  274. begin
  275. hp := p^.right;
  276. while hp^.treetype=addn do hp:=hp^.left;
  277. if equal_trees(p^.left,hp) and
  278. not multiple_uses(p^.left,p^.right) then
  279. begin
  280. p^.concat_string:=true;
  281. hp:=p^.right;
  282. while hp^.treetype=addn do
  283. begin
  284. hp^.use_strconcat:=true;
  285. hp:=hp^.left;
  286. end;
  287. end;
  288. end;
  289. {$endif newoptimizations2}
  290. end
  291. else
  292. begin
  293. p^.right:=gentypeconvnode(p^.right,p^.left^.resulttype);
  294. firstpass(p^.right);
  295. if codegenerror then
  296. exit;
  297. end;
  298. { test if node can be assigned, properties are allowed }
  299. valid_for_assign(p^.left,true);
  300. { check if local proc/func is assigned to procvar }
  301. if p^.right^.resulttype^.deftype=procvardef then
  302. test_local_to_procvar(pprocvardef(p^.right^.resulttype),p^.left^.resulttype);
  303. p^.resulttype:=voiddef;
  304. {
  305. p^.registers32:=max(p^.left^.registers32,p^.right^.registers32);
  306. p^.registersfpu:=max(p^.left^.registersfpu,p^.right^.registersfpu);
  307. }
  308. p^.registers32:=p^.left^.registers32+p^.right^.registers32;
  309. p^.registersfpu:=max(p^.left^.registersfpu,p^.right^.registersfpu);
  310. {$ifdef SUPPORT_MMX}
  311. p^.registersmmx:=max(p^.left^.registersmmx,p^.right^.registersmmx);
  312. {$endif SUPPORT_MMX}
  313. end;
  314. {*****************************************************************************
  315. FirstFuncRet
  316. *****************************************************************************}
  317. procedure firstfuncret(var p : ptree);
  318. begin
  319. p^.resulttype:=p^.rettype.def;
  320. p^.location.loc:=LOC_REFERENCE;
  321. if ret_in_param(p^.rettype.def) or
  322. (procinfo<>pprocinfo(p^.funcretprocinfo)) then
  323. p^.registers32:=1;
  324. end;
  325. {*****************************************************************************
  326. FirstArrayConstructRange
  327. *****************************************************************************}
  328. procedure firstarrayconstructrange(var p:ptree);
  329. begin
  330. firstpass(p^.left);
  331. set_varstate(p^.left,true);
  332. firstpass(p^.right);
  333. set_varstate(p^.right,true);
  334. calcregisters(p,0,0,0);
  335. p^.resulttype:=p^.left^.resulttype;
  336. end;
  337. {*****************************************************************************
  338. FirstArrayConstruct
  339. *****************************************************************************}
  340. procedure firstarrayconstruct(var p : ptree);
  341. var
  342. pd : pdef;
  343. thp,
  344. chp,
  345. hp : ptree;
  346. len : longint;
  347. varia : boolean;
  348. begin
  349. { are we allowing array constructor? Then convert it to a set }
  350. if not allow_array_constructor then
  351. begin
  352. arrayconstructor_to_set(p);
  353. firstpass(p);
  354. exit;
  355. end;
  356. { only pass left tree, right tree contains next construct if any }
  357. pd:=p^.constructdef;
  358. len:=0;
  359. varia:=false;
  360. if assigned(p^.left) then
  361. begin
  362. hp:=p;
  363. while assigned(hp) do
  364. begin
  365. firstpass(hp^.left);
  366. set_varstate(hp^.left,true);
  367. if (not get_para_resulttype) and (not p^.novariaallowed) then
  368. begin
  369. case hp^.left^.resulttype^.deftype of
  370. enumdef :
  371. begin
  372. hp^.left:=gentypeconvnode(hp^.left,s32bitdef);
  373. firstpass(hp^.left);
  374. end;
  375. orddef :
  376. begin
  377. if is_integer(hp^.left^.resulttype) and
  378. not(is_64bitint(hp^.left^.resulttype)) then
  379. begin
  380. hp^.left:=gentypeconvnode(hp^.left,s32bitdef);
  381. firstpass(hp^.left);
  382. end;
  383. end;
  384. floatdef :
  385. begin
  386. hp^.left:=gentypeconvnode(hp^.left,bestrealdef^);
  387. firstpass(hp^.left);
  388. end;
  389. stringdef :
  390. begin
  391. if p^.cargs then
  392. begin
  393. hp^.left:=gentypeconvnode(hp^.left,charpointerdef);
  394. firstpass(hp^.left);
  395. end;
  396. end;
  397. procvardef :
  398. begin
  399. hp^.left:=gentypeconvnode(hp^.left,voidpointerdef);
  400. firstpass(hp^.left);
  401. end;
  402. pointerdef,
  403. classrefdef,
  404. objectdef : ;
  405. else
  406. CGMessagePos1(hp^.left^.fileinfo,type_e_wrong_type_in_array_constructor,hp^.left^.resulttype^.typename);
  407. end;
  408. end;
  409. if (pd=nil) then
  410. pd:=hp^.left^.resulttype
  411. else
  412. begin
  413. if ((p^.novariaallowed) or (not varia)) and
  414. (not is_equal(pd,hp^.left^.resulttype)) then
  415. begin
  416. { if both should be equal try inserting a conversion }
  417. if p^.novariaallowed then
  418. begin
  419. hp^.left:=gentypeconvnode(hp^.left,pd);
  420. firstpass(hp^.left);
  421. end;
  422. varia:=true;
  423. end;
  424. end;
  425. inc(len);
  426. hp:=hp^.right;
  427. end;
  428. { swap the tree for cargs }
  429. if p^.cargs and (not p^.cargswap) then
  430. begin
  431. chp:=nil;
  432. hp:=p;
  433. while assigned(hp) do
  434. begin
  435. thp:=hp^.right;
  436. hp^.right:=chp;
  437. chp:=hp;
  438. hp:=thp;
  439. end;
  440. p:=chp;
  441. p^.cargs:=true;
  442. p^.cargswap:=true;
  443. end;
  444. end;
  445. calcregisters(p,0,0,0);
  446. { looks a little bit dangerous to me }
  447. { len-1 gives problems with is_open_array if len=0, }
  448. { is_open_array checks now for isconstructor (FK) }
  449. { if no type is set then we set the type to voiddef to overcome a
  450. 0 addressing }
  451. if not assigned(pd) then
  452. pd:=voiddef;
  453. { skip if already done ! (PM) }
  454. if not assigned(p^.resulttype) or
  455. (p^.resulttype^.deftype<>arraydef) or
  456. not parraydef(p^.resulttype)^.IsConstructor or
  457. (parraydef(p^.resulttype)^.lowrange<>0) or
  458. (parraydef(p^.resulttype)^.highrange<>len-1) then
  459. p^.resulttype:=new(parraydef,init(0,len-1,s32bitdef));
  460. parraydef(p^.resulttype)^.elementtype.def:=pd;
  461. parraydef(p^.resulttype)^.IsConstructor:=true;
  462. parraydef(p^.resulttype)^.IsVariant:=varia;
  463. p^.location.loc:=LOC_MEM;
  464. end;
  465. {*****************************************************************************
  466. Type
  467. *****************************************************************************}
  468. procedure firsttype(var p : ptree);
  469. begin
  470. { do nothing, p^.resulttype is already set }
  471. end;
  472. end.
  473. {
  474. $Log$
  475. Revision 1.7 2000-08-27 16:11:55 peter
  476. * moved some util functions from globals,cobjects to cutils
  477. * splitted files into finput,fmodule
  478. Revision 1.6 2000/08/15 03:41:27 peter
  479. * previous commit was wrong file :(
  480. Revision 1.5 2000/08/13 19:21:13 peter
  481. * fix for absolute to mem address (merged)
  482. Revision 1.4 2000/08/13 08:42:59 peter
  483. * support absolute refering to funcret (merged)
  484. Revision 1.3 2000/07/13 12:08:28 michael
  485. + patched to 1.1.0 with former 1.09patch from peter
  486. Revision 1.2 2000/07/13 11:32:52 michael
  487. + removed logs
  488. }