nset.pas 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655
  1. {
  2. $Id$
  3. Copyright (c) 2000 by Florian Klaempfl
  4. Type checking and register allocation for set/case 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 nset;
  19. {$i defines.inc}
  20. interface
  21. uses
  22. node,cpuinfo,aasm;
  23. type
  24. pcaserecord = ^tcaserecord;
  25. tcaserecord = record
  26. { range }
  27. _low,_high : TConstExprInt;
  28. { only used by gentreejmp }
  29. _at : tasmlabel;
  30. { label of instruction }
  31. statement : tasmlabel;
  32. { is this the first of an case entry, needed to release statement
  33. label (PFV) }
  34. firstlabel : boolean;
  35. { left and right tree node }
  36. less,greater : pcaserecord;
  37. end;
  38. tsetelementnode = class(tbinarynode)
  39. constructor create(l,r : tnode);virtual;
  40. function det_resulttype:tnode;override;
  41. function pass_1 : tnode;override;
  42. end;
  43. tsetelementnodeclass = class of tsetelementnode;
  44. tinnode = class(tbinopnode)
  45. constructor create(l,r : tnode);virtual;
  46. function det_resulttype:tnode;override;
  47. function pass_1 : tnode;override;
  48. end;
  49. tinnodeclass = class of tinnode;
  50. trangenode = class(tbinarynode)
  51. constructor create(l,r : tnode);virtual;
  52. function det_resulttype:tnode;override;
  53. function pass_1 : tnode;override;
  54. end;
  55. trangenodeclass = class of trangenode;
  56. tcasenode = class(tbinarynode)
  57. nodes : pcaserecord;
  58. elseblock : tnode;
  59. constructor create(l,r : tnode;n : pcaserecord);virtual;
  60. destructor destroy;override;
  61. function getcopy : tnode;override;
  62. procedure insertintolist(l : tnodelist);override;
  63. function det_resulttype:tnode;override;
  64. function pass_1 : tnode;override;
  65. function docompare(p: tnode): boolean; override;
  66. end;
  67. tcasenodeclass = class of tcasenode;
  68. var
  69. csetelementnode : tsetelementnodeclass;
  70. cinnode : tinnodeclass;
  71. crangenode : trangenodeclass;
  72. ccasenode : tcasenodeclass;
  73. { counts the labels }
  74. function case_count_labels(root : pcaserecord) : longint;
  75. { searches the highest label }
  76. {$ifdef int64funcresok}
  77. function case_get_max(root : pcaserecord) : tconstexprint;
  78. {$else int64funcresok}
  79. function case_get_max(root : pcaserecord) : longint;
  80. {$endif int64funcresok}
  81. { searches the lowest label }
  82. {$ifdef int64funcresok}
  83. function case_get_min(root : pcaserecord) : tconstexprint;
  84. {$else int64funcresok}
  85. function case_get_min(root : pcaserecord) : longint;
  86. {$endif int64funcresok}
  87. function gencasenode(l,r : tnode;nodes : pcaserecord) : tnode;
  88. implementation
  89. uses
  90. globtype,systems,
  91. verbose,globals,
  92. symconst,symdef,symsym,types,
  93. htypechk,pass_1,
  94. ncnv,ncon,cpubase,nld,tgcpu,cgbase;
  95. function gencasenode(l,r : tnode;nodes : pcaserecord) : tnode;
  96. var
  97. t : tnode;
  98. begin
  99. t:=ccasenode.create(l,r,nodes);
  100. gencasenode:=t;
  101. end;
  102. {*****************************************************************************
  103. TSETELEMENTNODE
  104. *****************************************************************************}
  105. constructor tsetelementnode.create(l,r : tnode);
  106. begin
  107. inherited create(setelementn,l,r);
  108. end;
  109. function tsetelementnode.det_resulttype:tnode;
  110. begin
  111. result:=nil;
  112. resulttypepass(left);
  113. if assigned(right) then
  114. resulttypepass(right);
  115. set_varstate(left,true);
  116. if codegenerror then
  117. exit;
  118. resulttype:=left.resulttype;
  119. end;
  120. function tsetelementnode.pass_1 : tnode;
  121. begin
  122. result:=nil;
  123. firstpass(left);
  124. if assigned(right) then
  125. firstpass(right);
  126. if codegenerror then
  127. exit;
  128. set_location(location,left.location);
  129. calcregisters(self,0,0,0);
  130. end;
  131. {*****************************************************************************
  132. TINNODE
  133. *****************************************************************************}
  134. constructor tinnode.create(l,r : tnode);
  135. begin
  136. inherited create(inn,l,r);
  137. end;
  138. function tinnode.det_resulttype:tnode;
  139. var
  140. t : tnode;
  141. pst : pconstset;
  142. function createsetconst(psd : tsetdef) : pconstset;
  143. var
  144. pcs : pconstset;
  145. pes : tenumsym;
  146. i : longint;
  147. begin
  148. new(pcs);
  149. case psd.elementtype.def.deftype of
  150. enumdef :
  151. begin
  152. pes:=tenumsym(tenumdef(psd.elementtype.def).firstenum);
  153. while assigned(pes) do
  154. begin
  155. pcs^[pes.value div 8]:=pcs^[pes.value div 8] or (1 shl (pes.value mod 8));
  156. pes:=pes.nextenum;
  157. end;
  158. end;
  159. orddef :
  160. begin
  161. for i:=torddef(psd.elementtype.def).low to torddef(psd.elementtype.def).high do
  162. begin
  163. pcs^[i div 8]:=pcs^[i div 8] or (1 shl (i mod 8));
  164. end;
  165. end;
  166. end;
  167. createsetconst:=pcs;
  168. end;
  169. begin
  170. result:=nil;
  171. resulttype:=booltype;
  172. resulttypepass(right);
  173. set_varstate(right,true);
  174. if codegenerror then
  175. exit;
  176. { Convert array constructor first to set }
  177. if is_array_constructor(right.resulttype.def) then
  178. begin
  179. arrayconstructor_to_set(tarrayconstructornode(right));
  180. firstpass(right);
  181. if codegenerror then
  182. exit;
  183. end;
  184. if right.resulttype.def.deftype<>setdef then
  185. CGMessage(sym_e_set_expected);
  186. if (right.nodetype=typen) then
  187. begin
  188. { we need to create a setconstn }
  189. pst:=createsetconst(tsetdef(ttypenode(right).resulttype.def));
  190. t:=csetconstnode.create(pst,ttypenode(right).resulttype);
  191. dispose(pst);
  192. right.free;
  193. right:=t;
  194. end;
  195. resulttypepass(left);
  196. set_varstate(left,true);
  197. if codegenerror then
  198. exit;
  199. { type conversion/check }
  200. if assigned(tsetdef(right.resulttype.def).elementtype.def) then
  201. inserttypeconv(left,tsetdef(right.resulttype.def).elementtype);
  202. end;
  203. function tinnode.pass_1 : tnode;
  204. type
  205. byteset = set of byte;
  206. var
  207. t : tnode;
  208. begin
  209. result:=nil;
  210. location.loc:=LOC_FLAGS;
  211. firstpass(right);
  212. firstpass(left);
  213. if codegenerror then
  214. exit;
  215. { empty set then return false }
  216. if not assigned(tsetdef(right.resulttype.def).elementtype.def) then
  217. begin
  218. t:=cordconstnode.create(0,booltype);
  219. firstpass(t);
  220. result:=t;
  221. exit;
  222. end;
  223. { constant evaulation }
  224. if (left.nodetype=ordconstn) and (right.nodetype=setconstn) then
  225. begin
  226. t:=cordconstnode.create(byte(tordconstnode(left).value in byteset(tsetconstnode(right).value_set^)),booltype);
  227. firstpass(t);
  228. result:=t;
  229. exit;
  230. end;
  231. left_right_max;
  232. { this is not allways true due to optimization }
  233. { but if we don't set this we get problems with optimizing self code }
  234. if tsetdef(right.resulttype.def).settype<>smallset then
  235. procinfo^.flags:=procinfo^.flags or pi_do_call
  236. else
  237. begin
  238. { a smallset needs maybe an misc. register }
  239. if (left.nodetype<>ordconstn) and
  240. not(right.location.loc in [LOC_CREGISTER,LOC_REGISTER]) and
  241. (right.registers32<1) then
  242. inc(registers32);
  243. end;
  244. end;
  245. {*****************************************************************************
  246. TRANGENODE
  247. *****************************************************************************}
  248. constructor trangenode.create(l,r : tnode);
  249. begin
  250. inherited create(rangen,l,r);
  251. end;
  252. function trangenode.det_resulttype : tnode;
  253. var
  254. ct : tconverttype;
  255. begin
  256. result:=nil;
  257. resulttypepass(left);
  258. resulttypepass(right);
  259. set_varstate(left,true);
  260. set_varstate(right,true);
  261. if codegenerror then
  262. exit;
  263. { both types must be compatible }
  264. if not(is_equal(left.resulttype.def,right.resulttype.def)) and
  265. (isconvertable(left.resulttype.def,right.resulttype.def,ct,ordconstn,false)=0) then
  266. CGMessage(type_e_mismatch);
  267. { Check if only when its a constant set }
  268. if (left.nodetype=ordconstn) and (right.nodetype=ordconstn) then
  269. begin
  270. { upper limit must be greater or equal than lower limit }
  271. if (tordconstnode(left).value>tordconstnode(right).value) and
  272. ((tordconstnode(left).value<0) or (tordconstnode(right).value>=0)) then
  273. CGMessage(cg_e_upper_lower_than_lower);
  274. end;
  275. resulttype:=left.resulttype;
  276. end;
  277. function trangenode.pass_1 : tnode;
  278. begin
  279. result:=nil;
  280. firstpass(left);
  281. firstpass(right);
  282. if codegenerror then
  283. exit;
  284. left_right_max;
  285. set_location(location,left.location);
  286. end;
  287. {*****************************************************************************
  288. Case Helpers
  289. *****************************************************************************}
  290. function case_count_labels(root : pcaserecord) : longint;
  291. var
  292. _l : longint;
  293. procedure count(p : pcaserecord);
  294. begin
  295. inc(_l);
  296. if assigned(p^.less) then
  297. count(p^.less);
  298. if assigned(p^.greater) then
  299. count(p^.greater);
  300. end;
  301. begin
  302. _l:=0;
  303. count(root);
  304. case_count_labels:=_l;
  305. end;
  306. {$ifdef int64funcresok}
  307. function case_get_max(root : pcaserecord) : tconstexprint;
  308. {$else int64funcresok}
  309. function case_get_max(root : pcaserecord) : longint;
  310. {$endif int64funcresok}
  311. var
  312. hp : pcaserecord;
  313. begin
  314. hp:=root;
  315. while assigned(hp^.greater) do
  316. hp:=hp^.greater;
  317. case_get_max:=hp^._high;
  318. end;
  319. {$ifdef int64funcresok}
  320. function case_get_min(root : pcaserecord) : tconstexprint;
  321. {$else int64funcresok}
  322. function case_get_min(root : pcaserecord) : longint;
  323. {$endif int64funcresok}
  324. var
  325. hp : pcaserecord;
  326. begin
  327. hp:=root;
  328. while assigned(hp^.less) do
  329. hp:=hp^.less;
  330. case_get_min:=hp^._low;
  331. end;
  332. procedure deletecaselabels(p : pcaserecord);
  333. begin
  334. if assigned(p^.greater) then
  335. deletecaselabels(p^.greater);
  336. if assigned(p^.less) then
  337. deletecaselabels(p^.less);
  338. dispose(p);
  339. end;
  340. function copycaserecord(p : pcaserecord) : pcaserecord;
  341. var
  342. n : pcaserecord;
  343. begin
  344. new(n);
  345. n^:=p^;
  346. if assigned(p^.greater) then
  347. n^.greater:=copycaserecord(p^.greater);
  348. if assigned(p^.less) then
  349. n^.less:=copycaserecord(p^.less);
  350. copycaserecord:=n;
  351. end;
  352. {*****************************************************************************
  353. TCASENODE
  354. *****************************************************************************}
  355. constructor tcasenode.create(l,r : tnode;n : pcaserecord);
  356. begin
  357. inherited create(casen,l,r);
  358. nodes:=n;
  359. elseblock:=nil;
  360. set_file_line(l);
  361. end;
  362. destructor tcasenode.destroy;
  363. begin
  364. elseblock.free;
  365. deletecaselabels(nodes);
  366. inherited destroy;
  367. end;
  368. function tcasenode.det_resulttype : tnode;
  369. begin
  370. result:=nil;
  371. resulttype:=voidtype;
  372. end;
  373. function tcasenode.pass_1 : tnode;
  374. var
  375. old_t_times : longint;
  376. hp : tbinarynode;
  377. begin
  378. result:=nil;
  379. { evalutes the case expression }
  380. {$ifdef newcg}
  381. tg.cleartempgen;
  382. {$else newcg}
  383. cleartempgen;
  384. {$endif newcg}
  385. firstpass(left);
  386. set_varstate(left,true);
  387. if codegenerror then
  388. exit;
  389. registers32:=left.registers32;
  390. registersfpu:=left.registersfpu;
  391. {$ifdef SUPPORT_MMX}
  392. registersmmx:=left.registersmmx;
  393. {$endif SUPPORT_MMX}
  394. { walk through all instructions }
  395. { estimates the repeat of each instruction }
  396. old_t_times:=t_times;
  397. if not(cs_littlesize in aktglobalswitches) then
  398. begin
  399. t_times:=t_times div case_count_labels(nodes);
  400. if t_times<1 then
  401. t_times:=1;
  402. end;
  403. { first case }
  404. hp:=tbinarynode(right);
  405. while assigned(hp) do
  406. begin
  407. {$ifdef newcg}
  408. tg.cleartempgen;
  409. {$else newcg}
  410. cleartempgen;
  411. {$endif newcg}
  412. firstpass(hp.right);
  413. { searchs max registers }
  414. if hp.right.registers32>registers32 then
  415. registers32:=hp.right.registers32;
  416. if hp.right.registersfpu>registersfpu then
  417. registersfpu:=hp.right.registersfpu;
  418. {$ifdef SUPPORT_MMX}
  419. if hp.right.registersmmx>registersmmx then
  420. registersmmx:=hp.right.registersmmx;
  421. {$endif SUPPORT_MMX}
  422. hp:=tbinarynode(hp.left);
  423. end;
  424. { may be handle else tree }
  425. if assigned(elseblock) then
  426. begin
  427. {$ifdef newcg}
  428. tg.cleartempgen;
  429. {$else newcg}
  430. cleartempgen;
  431. {$endif newcg}
  432. firstpass(elseblock);
  433. if codegenerror then
  434. exit;
  435. if registers32<elseblock.registers32 then
  436. registers32:=elseblock.registers32;
  437. if registersfpu<elseblock.registersfpu then
  438. registersfpu:=elseblock.registersfpu;
  439. {$ifdef SUPPORT_MMX}
  440. if registersmmx<elseblock.registersmmx then
  441. registersmmx:=elseblock.registersmmx;
  442. {$endif SUPPORT_MMX}
  443. end;
  444. t_times:=old_t_times;
  445. { there is one register required for the case expression }
  446. { for 64 bit ints we cheat: the high dword is stored in EDI }
  447. { so we don't need an extra register }
  448. if registers32<1 then registers32:=1;
  449. end;
  450. function tcasenode.getcopy : tnode;
  451. var
  452. p : tcasenode;
  453. begin
  454. p:=tcasenode(inherited getcopy);
  455. if assigned(elseblock) then
  456. p.elseblock:=elseblock.getcopy
  457. else
  458. p.elseblock:=nil;
  459. p.nodes:=copycaserecord(nodes);
  460. getcopy:=p;
  461. end;
  462. procedure tcasenode.insertintolist(l : tnodelist);
  463. begin
  464. end;
  465. function casenodesequal(n1,n2: pcaserecord): boolean;
  466. begin
  467. casenodesequal :=
  468. (not assigned(n1) and not assigned(n2)) or
  469. (assigned(n1) and assigned(n2) and
  470. (n1^._low = n2^._low) and
  471. (n1^._high = n2^._high) and
  472. { the rest of the fields don't matter for equality (JM) }
  473. casenodesequal(n1^.less,n2^.less) and
  474. casenodesequal(n1^.greater,n2^.greater))
  475. end;
  476. function tcasenode.docompare(p: tnode): boolean;
  477. begin
  478. docompare :=
  479. inherited docompare(p) and
  480. casenodesequal(nodes,tcasenode(p).nodes) and
  481. elseblock.isequal(tcasenode(p).elseblock);
  482. end;
  483. begin
  484. csetelementnode:=tsetelementnode;
  485. cinnode:=tinnode;
  486. crangenode:=trangenode;
  487. ccasenode:=tcasenode;
  488. end.
  489. {
  490. $Log$
  491. Revision 1.16 2001-10-12 13:51:51 jonas
  492. * fixed internalerror(10) due to previous fpu overflow fixes ("merged")
  493. * fixed bug in n386add (introduced after compilerproc changes for string
  494. operations) where calcregisters wasn't called for shortstring addnodes
  495. * NOTE: from now on, the location of a binary node must now always be set
  496. before you call calcregisters() for it
  497. Revision 1.15 2001/09/02 21:12:07 peter
  498. * move class of definitions into type section for delphi
  499. Revision 1.14 2001/08/26 13:36:43 florian
  500. * some cg reorganisation
  501. * some PPC updates
  502. Revision 1.13 2001/04/13 01:22:10 peter
  503. * symtable change to classes
  504. * range check generation and errors fixed, make cycle DEBUG=1 works
  505. * memory leaks fixed
  506. Revision 1.12 2001/04/02 21:20:31 peter
  507. * resulttype rewrite
  508. Revision 1.11 2000/12/31 11:14:11 jonas
  509. + implemented/fixed docompare() mathods for all nodes (not tested)
  510. + nopt.pas, nadd.pas, i386/n386opt.pas: optimized nodes for adding strings
  511. and constant strings/chars together
  512. * n386add.pas: don't copy temp strings (of size 256) to another temp string
  513. when adding
  514. Revision 1.10 2000/12/18 17:44:26 jonas
  515. * more int64 case fixes
  516. Revision 1.9 2000/11/29 00:30:34 florian
  517. * unused units removed from uses clause
  518. * some changes for widestrings
  519. Revision 1.8 2000/11/04 14:25:20 florian
  520. + merged Attila's changes for interfaces, not tested yet
  521. Revision 1.7 2000/10/31 22:02:49 peter
  522. * symtable splitted, no real code changes
  523. Revision 1.6 2000/10/21 18:16:11 florian
  524. * a lot of changes:
  525. - basic dyn. array support
  526. - basic C++ support
  527. - some work for interfaces done
  528. ....
  529. Revision 1.5 2000/10/14 10:14:51 peter
  530. * moehrendorf oct 2000 rewrite
  531. Revision 1.4 2000/10/01 19:48:25 peter
  532. * lot of compile updates for cg11
  533. Revision 1.3 2000/09/27 18:14:31 florian
  534. * fixed a lot of syntax errors in the n*.pas stuff
  535. Revision 1.2 2000/09/24 20:17:44 florian
  536. * more conversion work done
  537. Revision 1.1 2000/09/24 19:38:39 florian
  538. * initial implementation
  539. }