2
0

nopt.pas 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505
  1. {
  2. Copyright (c) 1998-2002 by Jonas Maebe
  3. This unit implements optimized nodes
  4. This program is free software; you can redistribute it and/or modify
  5. it under the terms of the GNU General Public License as published by
  6. the Free Software Foundation; either version 2 of the License, or
  7. (at your option) any later version.
  8. This program is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. GNU General Public License for more details.
  12. You should have received a copy of the GNU General Public License
  13. along with this program; if not, write to the Free Software
  14. Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  15. ****************************************************************************
  16. }
  17. unit nopt;
  18. {$i fpcdefs.inc}
  19. interface
  20. uses node,nbas,nadd,constexp;
  21. type
  22. tsubnodetype = (
  23. addsstringcharoptn, { shorstring + char }
  24. addsstringcsstringoptn { shortstring + constant shortstring }
  25. );
  26. taddoptnode = class(taddnode)
  27. subnodetype: tsubnodetype;
  28. constructor create(ts: tsubnodetype; l,r : tnode); virtual; reintroduce;
  29. { pass_1 will be overridden by the separate subclasses }
  30. { By default, pass_generate_code is the same as for addnode }
  31. { Only if there's a processor specific implementation, it }
  32. { will be overridden. }
  33. function dogetcopy: tnode; override;
  34. function docompare(p: tnode): boolean; override;
  35. end;
  36. taddsstringoptnode = class(taddoptnode)
  37. { maximum length of the string until now, allows us to skip a compare }
  38. { sometimes (it's initialized/updated by calling updatecurmaxlen) }
  39. curmaxlen: byte;
  40. { pass_1 must be overridden, otherwise we get an endless loop }
  41. function pass_typecheck: tnode; override;
  42. function pass_1: tnode; override;
  43. function dogetcopy: tnode; override;
  44. function docompare(p: tnode): boolean; override;
  45. protected
  46. procedure updatecurmaxlen;
  47. end;
  48. { add a char to a shortstring }
  49. taddsstringcharoptnode = class(taddsstringoptnode)
  50. constructor create(l,r : tnode); virtual; reintroduce;
  51. end;
  52. taddsstringcharoptnodeclass = class of taddsstringcharoptnode;
  53. { add a constant string to a short string }
  54. taddsstringcsstringoptnode = class(taddsstringoptnode)
  55. constructor create(l,r : tnode); virtual; reintroduce;
  56. function pass_1: tnode; override;
  57. end;
  58. taddsstringcsstringoptnodeclass = class of taddsstringcsstringoptnode;
  59. function canbeaddsstringcharoptnode(p: taddnode): boolean;
  60. function genaddsstringcharoptnode(p: taddnode): tnode;
  61. function canbeaddsstringcsstringoptnode(p: taddnode): boolean;
  62. function genaddsstringcsstringoptnode(p: taddnode): tnode;
  63. function canbemultistringadd(p: taddnode): boolean;
  64. function genmultistringadd(p: taddnode): tnode;
  65. function canbemultidynarrayadd(p: taddnode): boolean;
  66. function genmultidynarrayadd(p: taddnode): tnode;
  67. function is_addsstringoptnode(p: tnode): boolean;
  68. var
  69. caddsstringcharoptnode: taddsstringcharoptnodeclass;
  70. caddsstringcsstringoptnode: taddsstringcsstringoptnodeclass;
  71. implementation
  72. uses cutils, systems,
  73. htypechk, defutil, defcmp, globtype, globals, cpubase, compinnr,
  74. ncnv, ncon, ncal, ninl, nld, nmem,
  75. verbose, symconst,symdef, cgbase, procinfo;
  76. {*****************************************************************************
  77. TADDOPTNODE
  78. *****************************************************************************}
  79. constructor taddoptnode.create(ts: tsubnodetype; l,r : tnode);
  80. begin
  81. { we need to keep the addn nodetype, otherwise taddnode.pass_generate_code will be }
  82. { confused. Comparison for equal nodetypes therefore has to be }
  83. { implemented using the classtype() method (JM) }
  84. inherited create(addn,l,r);
  85. subnodetype := ts;
  86. end;
  87. function taddoptnode.dogetcopy: tnode;
  88. var
  89. hp: taddoptnode;
  90. begin
  91. hp := taddoptnode(inherited dogetcopy);
  92. hp.subnodetype := subnodetype;
  93. dogetcopy := hp;
  94. end;
  95. function taddoptnode.docompare(p: tnode): boolean;
  96. begin
  97. docompare :=
  98. inherited docompare(p) and
  99. (subnodetype = taddoptnode(p).subnodetype);
  100. end;
  101. {*****************************************************************************
  102. TADDSSTRINGOPTNODE
  103. *****************************************************************************}
  104. function taddsstringoptnode.pass_typecheck: tnode;
  105. begin
  106. result := nil;
  107. updatecurmaxlen;
  108. { left and right are already firstpass'ed by taddnode.pass_1 }
  109. if not is_shortstring(left.resultdef) then
  110. inserttypeconv(left,cshortstringtype);
  111. if not is_shortstring(right.resultdef) then
  112. inserttypeconv(right,cshortstringtype);
  113. resultdef := left.resultdef;
  114. end;
  115. function taddsstringoptnode.pass_1: tnode;
  116. begin
  117. pass_1 := nil;
  118. expectloc:= LOC_REFERENCE;
  119. { here we call STRCONCAT or STRCMP or STRCOPY }
  120. include(current_procinfo.flags,pi_do_call);
  121. end;
  122. function taddsstringoptnode.dogetcopy: tnode;
  123. var
  124. hp: taddsstringoptnode;
  125. begin
  126. hp := taddsstringoptnode(inherited dogetcopy);
  127. hp.curmaxlen := curmaxlen;
  128. dogetcopy := hp;
  129. end;
  130. function taddsstringoptnode.docompare(p: tnode): boolean;
  131. begin
  132. docompare :=
  133. inherited docompare(p) and
  134. (curmaxlen = taddsstringcharoptnode(p).curmaxlen);
  135. end;
  136. function is_addsstringoptnode(p: tnode): boolean;
  137. begin
  138. is_addsstringoptnode :=
  139. p.inheritsfrom(taddsstringoptnode);
  140. end;
  141. procedure taddsstringoptnode.updatecurmaxlen;
  142. begin
  143. if is_addsstringoptnode(left) then
  144. begin
  145. { made it a separate block so no other if's are processed (would be a }
  146. { simple waste of time) (JM) }
  147. if (taddsstringoptnode(left).curmaxlen < 255) then
  148. case subnodetype of
  149. addsstringcharoptn:
  150. curmaxlen := succ(taddsstringoptnode(left).curmaxlen);
  151. addsstringcsstringoptn:
  152. curmaxlen := min(taddsstringoptnode(left).curmaxlen +
  153. tstringconstnode(right).len,255)
  154. else
  155. internalerror(291220001);
  156. end
  157. else curmaxlen := 255;
  158. end
  159. else if (left.nodetype = stringconstn) then
  160. curmaxlen := min(tstringconstnode(left).len,255)
  161. else if is_char(left.resultdef) then
  162. curmaxlen := 1
  163. else if (left.nodetype = typeconvn) then
  164. begin
  165. case ttypeconvnode(left).convtype of
  166. tc_char_2_string:
  167. curmaxlen := 1;
  168. { doesn't work yet, don't know why (JM)
  169. tc_chararray_2_string:
  170. curmaxlen :=
  171. min(ttypeconvnode(left).left.resultdef.size,255); }
  172. else curmaxlen := 255;
  173. end;
  174. end
  175. else
  176. curmaxlen := 255;
  177. end;
  178. {*****************************************************************************
  179. TADDSSTRINGCHAROPTNODE
  180. *****************************************************************************}
  181. constructor taddsstringcharoptnode.create(l,r : tnode);
  182. begin
  183. inherited create(addsstringcharoptn,l,r);
  184. end;
  185. {*****************************************************************************
  186. TADDSSTRINGCSSTRINGOPTNODE
  187. *****************************************************************************}
  188. constructor taddsstringcsstringoptnode.create(l,r : tnode);
  189. begin
  190. inherited create(addsstringcsstringoptn,l,r);
  191. end;
  192. function taddsstringcsstringoptnode.pass_1: tnode;
  193. begin
  194. { create the call to the concat routine both strings as arguments }
  195. result := ccallnode.createintern('fpc_shortstr_append_shortstr',
  196. ccallparanode.create(left,ccallparanode.create(right,nil)));
  197. left:=nil;
  198. right:=nil;
  199. end;
  200. {*****************************************************************************
  201. HELPERS
  202. *****************************************************************************}
  203. function canbeaddsstringcharoptnode(p: taddnode): boolean;
  204. begin
  205. canbeaddsstringcharoptnode :=
  206. (cs_opt_level1 in current_settings.optimizerswitches) and
  207. { the shortstring will be gotten through conversion if necessary (JM)
  208. is_shortstring(p.left.resultdef) and }
  209. ((p.nodetype = addn) and
  210. is_char(p.right.resultdef));
  211. end;
  212. function genaddsstringcharoptnode(p: taddnode): tnode;
  213. var
  214. hp: tnode;
  215. begin
  216. hp := caddsstringcharoptnode.create(p.left.getcopy,p.right.getcopy);
  217. hp.flags := p.flags;
  218. genaddsstringcharoptnode := hp;
  219. end;
  220. function canbeaddsstringcsstringoptnode(p: taddnode): boolean;
  221. begin
  222. canbeaddsstringcsstringoptnode :=
  223. (cs_opt_level1 in current_settings.optimizerswitches) and
  224. { the shortstring will be gotten through conversion if necessary (JM)
  225. is_shortstring(p.left.resultdef) and }
  226. ((p.nodetype = addn) and
  227. (p.right.nodetype = stringconstn));
  228. end;
  229. function genaddsstringcsstringoptnode(p: taddnode): tnode;
  230. var
  231. hp: tnode;
  232. begin
  233. hp := caddsstringcsstringoptnode.create(p.left.getcopy,p.right.getcopy);
  234. hp.flags := p.flags;
  235. genaddsstringcsstringoptnode := hp;
  236. end;
  237. function canbemultistringadd(p: taddnode): boolean;
  238. var
  239. hp : tnode;
  240. i : longint;
  241. begin
  242. result:=false;
  243. if p.resultdef.typ<>stringdef then
  244. exit;
  245. i:=0;
  246. hp:=p;
  247. while assigned(hp) and (hp.nodetype=addn) do
  248. begin
  249. inc(i);
  250. hp:=taddnode(hp).left;
  251. end;
  252. result:=(i>1);
  253. end;
  254. function genmultistringadd(p: taddnode): tnode;
  255. var
  256. hp,sn : tnode;
  257. arrp : tarrayconstructornode;
  258. newstatement : tstatementnode;
  259. tempnode : ttempcreatenode;
  260. is_shortstr : boolean;
  261. para : tcallparanode;
  262. begin
  263. arrp:=nil;
  264. hp:=p;
  265. is_shortstr:=is_shortstring(p.resultdef);
  266. while assigned(hp) and (hp.nodetype=addn) do
  267. begin
  268. sn:=taddnode(hp).right.getcopy;
  269. inserttypeconv(sn,p.resultdef);
  270. if is_shortstr then
  271. begin
  272. sn:=caddrnode.create(sn);
  273. include(taddrnode(sn).addrnodeflags,anf_typedaddr);
  274. include(sn.flags,nf_internal);
  275. end;
  276. arrp:=carrayconstructornode.create(sn,arrp);
  277. hp:=taddnode(hp).left;
  278. end;
  279. sn:=hp.getcopy;
  280. inserttypeconv(sn,p.resultdef);
  281. if is_shortstr then
  282. begin
  283. sn:=caddrnode.create(sn);
  284. include(sn.flags,nf_internal);
  285. end;
  286. arrp:=carrayconstructornode.create(sn,arrp);
  287. arrp.allow_array_constructor:=true;
  288. if assigned(aktassignmentnode) and
  289. (aktassignmentnode.right=p) and
  290. (aktassignmentnode.left.resultdef=p.resultdef) and
  291. valid_for_var(aktassignmentnode.left,false) then
  292. begin
  293. para:=ccallparanode.create(
  294. arrp,
  295. ccallparanode.create(aktassignmentnode.left.getcopy,nil)
  296. );
  297. if is_ansistring(p.resultdef) then
  298. para:=ccallparanode.create(
  299. cordconstnode.create(
  300. { don't use getparaencoding(), we have to know
  301. when the result is rawbytestring }
  302. tstringdef(p.resultdef).encoding,
  303. u16inttype,
  304. true
  305. ),
  306. para
  307. );
  308. result:=ccallnode.createintern(
  309. 'fpc_'+tstringdef(p.resultdef).stringtypname+'_concat_multi',
  310. para
  311. );
  312. include(aktassignmentnode.flags,nf_assign_done_in_right);
  313. end
  314. else
  315. begin
  316. result:=internalstatements(newstatement);
  317. tempnode:=ctempcreatenode.create(p.resultdef,p.resultdef.size,tt_persistent ,true);
  318. addstatement(newstatement,tempnode);
  319. { initialize the temp, since it will be passed to a
  320. var-parameter (and finalization, which is performed by the
  321. ttempcreate node and which takes care of the initialization
  322. on native targets, is a noop on managed VM targets) }
  323. if (target_info.system in systems_managed_vm) and
  324. is_managed_type(p.resultdef) then
  325. addstatement(newstatement,cinlinenode.create(in_setlength_x,
  326. false,
  327. ccallparanode.create(genintconstnode(0),
  328. ccallparanode.create(ctemprefnode.create(tempnode),nil))));
  329. para:=ccallparanode.create(
  330. arrp,
  331. ccallparanode.create(ctemprefnode.create(tempnode),nil)
  332. );
  333. if is_ansistring(p.resultdef) then
  334. para:=ccallparanode.create(
  335. cordconstnode.create(
  336. { don't use getparaencoding(), we have to know
  337. when the result is rawbytestring }
  338. tstringdef(p.resultdef).encoding,
  339. u16inttype,
  340. true
  341. ),
  342. para
  343. );
  344. addstatement(
  345. newstatement,
  346. ccallnode.createintern(
  347. 'fpc_'+tstringdef(p.resultdef).stringtypname+'_concat_multi',
  348. para
  349. )
  350. );
  351. addstatement(newstatement,ctempdeletenode.create_normal_temp(tempnode));
  352. addstatement(newstatement,ctemprefnode.create(tempnode));
  353. end;
  354. end;
  355. function canbemultidynarrayadd(p: taddnode): boolean;
  356. var
  357. hp : tnode;
  358. i : longint;
  359. begin
  360. result:=false;
  361. if not(is_dynamic_array(p.resultdef)) then
  362. exit;
  363. i:=0;
  364. hp:=p;
  365. while assigned(hp) and (hp.nodetype=addn) do
  366. begin
  367. inc(i);
  368. hp:=taddnode(hp).left;
  369. end;
  370. result:=(i>1);
  371. end;
  372. function genmultidynarrayadd(p: taddnode): tnode;
  373. var
  374. hp,sn : tnode;
  375. arrp : tarrayconstructornode;
  376. newstatement : tstatementnode;
  377. tempnode : ttempcreatenode;
  378. para : tcallparanode;
  379. begin
  380. arrp:=nil;
  381. hp:=p;
  382. while assigned(hp) and (hp.nodetype=addn) do
  383. begin
  384. sn:=ctypeconvnode.create_internal(taddnode(hp).right.getcopy,voidpointertype);
  385. arrp:=carrayconstructornode.create(sn,arrp);
  386. hp:=taddnode(hp).left;
  387. end;
  388. sn:=ctypeconvnode.create_internal(hp.getcopy,voidpointertype);
  389. arrp:=carrayconstructornode.create(sn,arrp);
  390. arrp.allow_array_constructor:=true;
  391. if assigned(aktassignmentnode) and
  392. (aktassignmentnode.right=p) and
  393. (aktassignmentnode.left.resultdef=p.resultdef) and
  394. valid_for_var(aktassignmentnode.left,false) then
  395. begin
  396. para:=ccallparanode.create(
  397. arrp,
  398. ccallparanode.create(
  399. caddrnode.create_internal(crttinode.create(tstoreddef(p.resultdef),initrtti,rdt_normal)),
  400. ccallparanode.create(
  401. ctypeconvnode.create_internal(aktassignmentnode.left.getcopy,voidpointertype),nil)
  402. ));
  403. result:=ccallnode.createintern(
  404. 'fpc_dynarray_concat_multi',
  405. para
  406. );
  407. include(aktassignmentnode.flags,nf_assign_done_in_right);
  408. end
  409. else
  410. begin
  411. result:=internalstatements(newstatement);
  412. tempnode:=ctempcreatenode.create(p.resultdef,p.resultdef.size,tt_persistent ,true);
  413. addstatement(newstatement,tempnode);
  414. { initialize the temp, since it will be passed to a
  415. var-parameter (and finalization, which is performed by the
  416. ttempcreate node and which takes care of the initialization
  417. on native targets, is a noop on managed VM targets) }
  418. if (target_info.system in systems_managed_vm) and
  419. is_managed_type(p.resultdef) then
  420. addstatement(newstatement,cinlinenode.create(in_setlength_x,
  421. false,
  422. ccallparanode.create(genintconstnode(0),
  423. ccallparanode.create(ctemprefnode.create(tempnode),nil))));
  424. para:=ccallparanode.create(
  425. arrp,
  426. ccallparanode.create(
  427. caddrnode.create_internal(crttinode.create(tstoreddef(p.resultdef),initrtti,rdt_normal)),
  428. ccallparanode.create(
  429. ctypeconvnode.create_internal(ctemprefnode.create(tempnode),voidpointertype),nil)
  430. ));
  431. addstatement(
  432. newstatement,
  433. ccallnode.createintern(
  434. 'fpc_dynarray_concat_multi',
  435. para
  436. )
  437. );
  438. addstatement(newstatement,ctempdeletenode.create_normal_temp(tempnode));
  439. addstatement(newstatement,ctemprefnode.create(tempnode));
  440. end;
  441. end;
  442. begin
  443. caddsstringcharoptnode := taddsstringcharoptnode;
  444. caddsstringcsstringoptnode := taddsstringcsstringoptnode;
  445. end.