tcmem.pas 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524
  1. {
  2. $Id$
  3. Copyright (c) 1993-98 by Florian Klaempfl
  4. Type checking and register allocation for memory related 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 tcmem;
  19. interface
  20. uses
  21. tree;
  22. procedure firstloadvmt(var p : ptree);
  23. procedure firsthnew(var p : ptree);
  24. procedure firstnew(var p : ptree);
  25. procedure firsthdispose(var p : ptree);
  26. procedure firstsimplenewdispose(var p : ptree);
  27. procedure firstaddr(var p : ptree);
  28. procedure firstdoubleaddr(var p : ptree);
  29. procedure firstderef(var p : ptree);
  30. procedure firstsubscript(var p : ptree);
  31. procedure firstvec(var p : ptree);
  32. procedure firstself(var p : ptree);
  33. procedure firstwith(var p : ptree);
  34. implementation
  35. uses
  36. cobjects,verbose,globals,systems,
  37. symtable,aasm,types,
  38. hcodegen,htypechk,pass_1
  39. {$ifdef i386}
  40. ,i386
  41. {$endif}
  42. {$ifdef m68k}
  43. ,m68k
  44. {$endif}
  45. ;
  46. {*****************************************************************************
  47. FirstLoadVMT
  48. *****************************************************************************}
  49. procedure firstloadvmt(var p : ptree);
  50. begin
  51. p^.registers32:=1;
  52. p^.location.loc:=LOC_REGISTER;
  53. end;
  54. {*****************************************************************************
  55. FirstHNew
  56. *****************************************************************************}
  57. procedure firsthnew(var p : ptree);
  58. begin
  59. end;
  60. {*****************************************************************************
  61. FirstNewN
  62. *****************************************************************************}
  63. procedure firstnew(var p : ptree);
  64. begin
  65. { Standardeinleitung }
  66. if assigned(p^.left) then
  67. firstpass(p^.left);
  68. if codegenerror then
  69. exit;
  70. if assigned(p^.left) then
  71. begin
  72. p^.registers32:=p^.left^.registers32;
  73. p^.registersfpu:=p^.left^.registersfpu;
  74. {$ifdef SUPPORT_MMX}
  75. p^.registersmmx:=p^.left^.registersmmx;
  76. {$endif SUPPORT_MMX}
  77. end;
  78. { result type is already set }
  79. procinfo.flags:=procinfo.flags or pi_do_call;
  80. if assigned(p^.left) then
  81. p^.location.loc:=LOC_REGISTER
  82. else
  83. p^.location.loc:=LOC_REFERENCE;
  84. end;
  85. {*****************************************************************************
  86. FirstDispose
  87. *****************************************************************************}
  88. procedure firsthdispose(var p : ptree);
  89. begin
  90. firstpass(p^.left);
  91. if codegenerror then
  92. exit;
  93. p^.registers32:=p^.left^.registers32;
  94. p^.registersfpu:=p^.left^.registersfpu;
  95. {$ifdef SUPPORT_MMX}
  96. p^.registersmmx:=p^.left^.registersmmx;
  97. {$endif SUPPORT_MMX}
  98. if p^.registers32<1 then
  99. p^.registers32:=1;
  100. {
  101. if p^.left^.location.loc<>LOC_REFERENCE then
  102. CGMessage(cg_e_illegal_expression);
  103. }
  104. p^.location.loc:=LOC_REFERENCE;
  105. p^.resulttype:=ppointerdef(p^.left^.resulttype)^.definition;
  106. end;
  107. {*****************************************************************************
  108. FirstSimpleNewDispose
  109. *****************************************************************************}
  110. procedure firstsimplenewdispose(var p : ptree);
  111. begin
  112. { this cannot be in a register !! }
  113. make_not_regable(p^.left);
  114. firstpass(p^.left);
  115. if codegenerror then
  116. exit;
  117. { check the type }
  118. if (p^.left^.resulttype=nil) or (p^.left^.resulttype^.deftype<>pointerdef) then
  119. CGMessage(type_e_pointer_type_expected);
  120. if (p^.left^.location.loc<>LOC_REFERENCE) {and
  121. (p^.left^.location.loc<>LOC_CREGISTER)} then
  122. CGMessage(cg_e_illegal_expression);
  123. p^.registers32:=p^.left^.registers32;
  124. p^.registersfpu:=p^.left^.registersfpu;
  125. {$ifdef SUPPORT_MMX}
  126. p^.registersmmx:=p^.left^.registersmmx;
  127. {$endif SUPPORT_MMX}
  128. p^.resulttype:=voiddef;
  129. procinfo.flags:=procinfo.flags or pi_do_call;
  130. end;
  131. {*****************************************************************************
  132. FirstAddr
  133. *****************************************************************************}
  134. procedure firstaddr(var p : ptree);
  135. var
  136. hp : ptree;
  137. hp2 : pdefcoll;
  138. store_valid : boolean;
  139. hp3 : pabstractprocdef;
  140. begin
  141. make_not_regable(p^.left);
  142. if not(assigned(p^.resulttype)) then
  143. begin
  144. if p^.left^.treetype=calln then
  145. begin
  146. { it could also be a procvar, not only pprocsym ! }
  147. if p^.left^.symtableprocentry^.typ=varsym then
  148. hp:=genloadnode(pvarsym(p^.left^.symtableprocentry),p^.left^.symtableproc)
  149. else
  150. hp:=genloadcallnode(pprocsym(p^.left^.symtableprocentry),p^.left^.symtableproc);
  151. { result is a procedure variable }
  152. { No, to be TP compatible, you must return a pointer to
  153. the procedure that is stored in the procvar.}
  154. if not(m_tp_procvar in aktmodeswitches) then
  155. begin
  156. p^.resulttype:=new(pprocvardef,init);
  157. { it could also be a procvar, not only pprocsym ! }
  158. if p^.left^.symtableprocentry^.typ=varsym then
  159. hp3:=pabstractprocdef(pvarsym(p^.left^.symtableprocentry)^.definition)
  160. else
  161. hp3:=pabstractprocdef(pprocsym(p^.left^.symtableprocentry)^.definition);
  162. pprocvardef(p^.resulttype)^.options:=hp3^.options;
  163. pprocvardef(p^.resulttype)^.retdef:=hp3^.retdef;
  164. hp2:=hp3^.para1;
  165. while assigned(hp2) do
  166. begin
  167. pprocvardef(p^.resulttype)^.concatdef(hp2^.data,hp2^.paratyp);
  168. hp2:=hp2^.next;
  169. end;
  170. end
  171. else
  172. p^.resulttype:=voidpointerdef;
  173. disposetree(p^.left);
  174. p^.left:=hp;
  175. end
  176. else
  177. begin
  178. if not(cs_typed_addresses in aktlocalswitches) then
  179. p^.resulttype:=voidpointerdef
  180. else p^.resulttype:=new(ppointerdef,init(p^.left^.resulttype));
  181. end;
  182. end;
  183. store_valid:=must_be_valid;
  184. must_be_valid:=false;
  185. firstpass(p^.left);
  186. must_be_valid:=store_valid;
  187. if codegenerror then
  188. exit;
  189. { we should allow loc_mem for @string }
  190. if (p^.left^.location.loc<>LOC_REFERENCE) and
  191. (p^.left^.location.loc<>LOC_MEM) then
  192. CGMessage(cg_e_illegal_expression);
  193. p^.registers32:=p^.left^.registers32;
  194. p^.registersfpu:=p^.left^.registersfpu;
  195. {$ifdef SUPPORT_MMX}
  196. p^.registersmmx:=p^.left^.registersmmx;
  197. {$endif SUPPORT_MMX}
  198. if p^.registers32<1 then
  199. p^.registers32:=1;
  200. p^.location.loc:=LOC_REGISTER;
  201. end;
  202. {*****************************************************************************
  203. FirstDoubleAddr
  204. *****************************************************************************}
  205. procedure firstdoubleaddr(var p : ptree);
  206. begin
  207. make_not_regable(p^.left);
  208. firstpass(p^.left);
  209. if p^.resulttype=nil then
  210. p^.resulttype:=voidpointerdef;
  211. if codegenerror then
  212. exit;
  213. if (p^.left^.resulttype^.deftype)<>procvardef then
  214. CGMessage(cg_e_illegal_expression);
  215. if (p^.left^.location.loc<>LOC_REFERENCE) then
  216. CGMessage(cg_e_illegal_expression);
  217. p^.registers32:=p^.left^.registers32;
  218. p^.registersfpu:=p^.left^.registersfpu;
  219. {$ifdef SUPPORT_MMX}
  220. p^.registersmmx:=p^.left^.registersmmx;
  221. {$endif SUPPORT_MMX}
  222. if p^.registers32<1 then
  223. p^.registers32:=1;
  224. p^.location.loc:=LOC_REGISTER;
  225. end;
  226. {*****************************************************************************
  227. FirstDeRef
  228. *****************************************************************************}
  229. procedure firstderef(var p : ptree);
  230. begin
  231. firstpass(p^.left);
  232. if codegenerror then
  233. begin
  234. p^.resulttype:=generrordef;
  235. exit;
  236. end;
  237. p^.registers32:=max(p^.left^.registers32,1);
  238. p^.registersfpu:=p^.left^.registersfpu;
  239. {$ifdef SUPPORT_MMX}
  240. p^.registersmmx:=p^.left^.registersmmx;
  241. {$endif SUPPORT_MMX}
  242. if p^.left^.resulttype^.deftype<>pointerdef then
  243. CGMessage(cg_e_invalid_qualifier);
  244. p^.resulttype:=ppointerdef(p^.left^.resulttype)^.definition;
  245. p^.location.loc:=LOC_REFERENCE;
  246. end;
  247. {*****************************************************************************
  248. FirstSubScript
  249. *****************************************************************************}
  250. procedure firstsubscript(var p : ptree);
  251. begin
  252. firstpass(p^.left);
  253. if codegenerror then
  254. begin
  255. p^.resulttype:=generrordef;
  256. exit;
  257. end;
  258. p^.resulttype:=p^.vs^.definition;
  259. { this must be done in the parser
  260. if count_ref and not must_be_valid then
  261. if (p^.vs^.properties and sp_protected)<>0 then
  262. CGMessage(parser_e_cant_write_protected_member);
  263. }
  264. p^.registers32:=p^.left^.registers32;
  265. p^.registersfpu:=p^.left^.registersfpu;
  266. {$ifdef SUPPORT_MMX}
  267. p^.registersmmx:=p^.left^.registersmmx;
  268. {$endif SUPPORT_MMX}
  269. { classes must be dereferenced implicit }
  270. if (p^.left^.resulttype^.deftype=objectdef) and
  271. pobjectdef(p^.left^.resulttype)^.isclass then
  272. begin
  273. if p^.registers32=0 then
  274. p^.registers32:=1;
  275. p^.location.loc:=LOC_REFERENCE;
  276. end
  277. else
  278. begin
  279. if (p^.left^.location.loc<>LOC_MEM) and
  280. (p^.left^.location.loc<>LOC_REFERENCE) then
  281. CGMessage(cg_e_illegal_expression);
  282. set_location(p^.location,p^.left^.location);
  283. end;
  284. end;
  285. {*****************************************************************************
  286. FirstVec
  287. *****************************************************************************}
  288. procedure firstvec(var p : ptree);
  289. var
  290. harr : pdef;
  291. ct : tconverttype;
  292. begin
  293. firstpass(p^.left);
  294. firstpass(p^.right);
  295. if codegenerror then
  296. exit;
  297. { range check only for arrays }
  298. if (p^.left^.resulttype^.deftype=arraydef) then
  299. begin
  300. if not(isconvertable(p^.right^.resulttype,
  301. parraydef(p^.left^.resulttype)^.rangedef,
  302. ct,ordconstn,false)) and
  303. not(is_equal(p^.right^.resulttype,
  304. parraydef(p^.left^.resulttype)^.rangedef)) then
  305. CGMessage(type_e_mismatch);
  306. end;
  307. { Never convert a boolean or a char !}
  308. { maybe type conversion }
  309. if (p^.right^.resulttype^.deftype<>enumdef) and
  310. not ((p^.right^.resulttype^.deftype=orddef) and
  311. (Porddef(p^.right^.resulttype)^.typ in [bool8bit,bool16bit,bool32bit,uchar])) then
  312. begin
  313. p^.right:=gentypeconvnode(p^.right,s32bitdef);
  314. { once more firstpass }
  315. {?? It's better to only firstpass when the tree has
  316. changed, isn't it ?}
  317. firstpass(p^.right);
  318. end;
  319. if codegenerror then
  320. exit;
  321. { determine return type }
  322. if not assigned(p^.resulttype) then
  323. if p^.left^.resulttype^.deftype=arraydef then
  324. p^.resulttype:=parraydef(p^.left^.resulttype)^.definition
  325. else if (p^.left^.resulttype^.deftype=pointerdef) then
  326. begin
  327. { convert pointer to array }
  328. harr:=new(parraydef,init(0,$7fffffff,s32bitdef));
  329. parraydef(harr)^.definition:=ppointerdef(p^.left^.resulttype)^.definition;
  330. p^.left:=gentypeconvnode(p^.left,harr);
  331. firstpass(p^.left);
  332. if codegenerror then
  333. exit;
  334. p^.resulttype:=parraydef(harr)^.definition
  335. end
  336. else if p^.left^.resulttype^.deftype=stringdef then
  337. begin
  338. { indexed access to strings }
  339. case pstringdef(p^.left^.resulttype)^.string_typ of
  340. {
  341. st_widestring : p^.resulttype:=cwchardef;
  342. }
  343. st_ansistring : p^.resulttype:=cchardef;
  344. st_longstring : p^.resulttype:=cchardef;
  345. st_shortstring : p^.resulttype:=cchardef;
  346. end;
  347. end
  348. else
  349. CGMessage(type_e_mismatch);
  350. { the register calculation is easy if a const index is used }
  351. if p^.right^.treetype=ordconstn then
  352. begin
  353. p^.registers32:=p^.left^.registers32;
  354. { for ansi/wide strings, we need at least one register }
  355. if is_ansistring(p^.left^.resulttype) or
  356. is_widestring(p^.left^.resulttype) then
  357. p^.registers32:=max(p^.registers32,1);
  358. end
  359. else
  360. begin
  361. { this rules are suboptimal, but they should give }
  362. { good results }
  363. p^.registers32:=max(p^.left^.registers32,p^.right^.registers32);
  364. { for ansi/wide strings, we need at least one register }
  365. if is_ansistring(p^.left^.resulttype) or
  366. is_widestring(p^.left^.resulttype) then
  367. p^.registers32:=max(p^.registers32,1);
  368. { need we an extra register when doing the restore ? }
  369. if (p^.left^.registers32<=p^.right^.registers32) and
  370. { only if the node needs less than 3 registers }
  371. { two for the right node and one for the }
  372. { left address }
  373. (p^.registers32<3) then
  374. inc(p^.registers32);
  375. { need we an extra register for the index ? }
  376. if (p^.right^.location.loc<>LOC_REGISTER)
  377. { only if the right node doesn't need a register }
  378. and (p^.right^.registers32<1) then
  379. inc(p^.registers32);
  380. { not correct, but what works better ?
  381. if p^.left^.registers32>0 then
  382. p^.registers32:=max(p^.registers32,2)
  383. else
  384. min. one register
  385. p^.registers32:=max(p^.registers32,1);
  386. }
  387. end;
  388. p^.registersfpu:=max(p^.left^.registersfpu,p^.right^.registersfpu);
  389. {$ifdef SUPPORT_MMX}
  390. p^.registersmmx:=max(p^.left^.registersmmx,p^.right^.registersmmx);
  391. {$endif SUPPORT_MMX}
  392. p^.location.loc:=p^.left^.location.loc;
  393. end;
  394. {*****************************************************************************
  395. FirstSelf
  396. *****************************************************************************}
  397. procedure firstself(var p : ptree);
  398. begin
  399. if (p^.resulttype^.deftype=classrefdef) or
  400. ((p^.resulttype^.deftype=objectdef)
  401. and pobjectdef(p^.resulttype)^.isclass
  402. ) then
  403. p^.location.loc:=LOC_CREGISTER
  404. else
  405. p^.location.loc:=LOC_REFERENCE;
  406. end;
  407. {*****************************************************************************
  408. FirstWithN
  409. *****************************************************************************}
  410. procedure firstwith(var p : ptree);
  411. begin
  412. if assigned(p^.left) and assigned(p^.right) then
  413. begin
  414. firstpass(p^.left);
  415. if codegenerror then
  416. exit;
  417. firstpass(p^.right);
  418. if codegenerror then
  419. exit;
  420. left_right_max(p);
  421. p^.resulttype:=voiddef;
  422. end
  423. else
  424. begin
  425. { optimization }
  426. disposetree(p);
  427. p:=nil;
  428. end;
  429. end;
  430. end.
  431. {
  432. $Log$
  433. Revision 1.4 1998-11-25 19:12:53 pierre
  434. * var:=new(pointer_type) support added
  435. Revision 1.3 1998/09/26 15:03:05 florian
  436. * small problems with DOM and excpetions fixed (code generation
  437. of raise was wrong and self was sometimes destroyed :()
  438. Revision 1.2 1998/09/24 23:49:24 peter
  439. + aktmodeswitches
  440. Revision 1.1 1998/09/23 20:42:24 peter
  441. * splitted pass_1
  442. }