nopt.pas 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504
  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. end
  155. else
  156. curmaxlen := 255;
  157. end
  158. else if (left.nodetype = stringconstn) then
  159. curmaxlen := min(tstringconstnode(left).len,255)
  160. else if is_char(left.resultdef) then
  161. curmaxlen := 1
  162. else if (left.nodetype = typeconvn) then
  163. begin
  164. case ttypeconvnode(left).convtype of
  165. tc_char_2_string:
  166. curmaxlen := 1;
  167. { doesn't work yet, don't know why (JM)
  168. tc_chararray_2_string:
  169. curmaxlen :=
  170. min(ttypeconvnode(left).left.resultdef.size,255); }
  171. else curmaxlen := 255;
  172. end;
  173. end
  174. else
  175. curmaxlen := 255;
  176. end;
  177. {*****************************************************************************
  178. TADDSSTRINGCHAROPTNODE
  179. *****************************************************************************}
  180. constructor taddsstringcharoptnode.create(l,r : tnode);
  181. begin
  182. inherited create(addsstringcharoptn,l,r);
  183. end;
  184. {*****************************************************************************
  185. TADDSSTRINGCSSTRINGOPTNODE
  186. *****************************************************************************}
  187. constructor taddsstringcsstringoptnode.create(l,r : tnode);
  188. begin
  189. inherited create(addsstringcsstringoptn,l,r);
  190. end;
  191. function taddsstringcsstringoptnode.pass_1: tnode;
  192. begin
  193. { create the call to the concat routine both strings as arguments }
  194. result := ccallnode.createintern('fpc_shortstr_append_shortstr',
  195. ccallparanode.create(left,ccallparanode.create(right,nil)));
  196. left:=nil;
  197. right:=nil;
  198. end;
  199. {*****************************************************************************
  200. HELPERS
  201. *****************************************************************************}
  202. function canbeaddsstringcharoptnode(p: taddnode): boolean;
  203. begin
  204. canbeaddsstringcharoptnode :=
  205. (cs_opt_level1 in current_settings.optimizerswitches) and
  206. { the shortstring will be gotten through conversion if necessary (JM)
  207. is_shortstring(p.left.resultdef) and }
  208. ((p.nodetype = addn) and
  209. is_char(p.right.resultdef));
  210. end;
  211. function genaddsstringcharoptnode(p: taddnode): tnode;
  212. var
  213. hp: tnode;
  214. begin
  215. hp := caddsstringcharoptnode.create(p.left.getcopy,p.right.getcopy);
  216. hp.flags := p.flags;
  217. genaddsstringcharoptnode := hp;
  218. end;
  219. function canbeaddsstringcsstringoptnode(p: taddnode): boolean;
  220. begin
  221. canbeaddsstringcsstringoptnode :=
  222. (cs_opt_level1 in current_settings.optimizerswitches) and
  223. { the shortstring will be gotten through conversion if necessary (JM)
  224. is_shortstring(p.left.resultdef) and }
  225. ((p.nodetype = addn) and
  226. (p.right.nodetype = stringconstn));
  227. end;
  228. function genaddsstringcsstringoptnode(p: taddnode): tnode;
  229. var
  230. hp: tnode;
  231. begin
  232. hp := caddsstringcsstringoptnode.create(p.left.getcopy,p.right.getcopy);
  233. hp.flags := p.flags;
  234. genaddsstringcsstringoptnode := hp;
  235. end;
  236. function canbemultistringadd(p: taddnode): boolean;
  237. var
  238. hp : tnode;
  239. i : longint;
  240. begin
  241. result:=false;
  242. if p.resultdef.typ<>stringdef then
  243. exit;
  244. i:=0;
  245. hp:=p;
  246. while assigned(hp) and (hp.nodetype=addn) do
  247. begin
  248. inc(i);
  249. hp:=taddnode(hp).left;
  250. end;
  251. result:=(i>1);
  252. end;
  253. function genmultistringadd(p: taddnode): tnode;
  254. var
  255. hp,sn : tnode;
  256. arrp : tarrayconstructornode;
  257. newstatement : tstatementnode;
  258. tempnode : ttempcreatenode;
  259. is_shortstr : boolean;
  260. para : tcallparanode;
  261. begin
  262. arrp:=nil;
  263. hp:=p;
  264. is_shortstr:=is_shortstring(p.resultdef);
  265. while assigned(hp) and (hp.nodetype=addn) do
  266. begin
  267. sn:=taddnode(hp).right.getcopy;
  268. inserttypeconv(sn,p.resultdef);
  269. if is_shortstr then
  270. begin
  271. sn:=caddrnode.create(sn);
  272. include(taddrnode(sn).addrnodeflags,anf_typedaddr);
  273. include(sn.flags,nf_internal);
  274. end;
  275. arrp:=carrayconstructornode.create(sn,arrp);
  276. hp:=taddnode(hp).left;
  277. end;
  278. sn:=hp.getcopy;
  279. inserttypeconv(sn,p.resultdef);
  280. if is_shortstr then
  281. begin
  282. sn:=caddrnode.create(sn);
  283. include(sn.flags,nf_internal);
  284. end;
  285. arrp:=carrayconstructornode.create(sn,arrp);
  286. arrp.allow_array_constructor:=true;
  287. if assigned(aktassignmentnode) and
  288. (aktassignmentnode.right=p) and
  289. (aktassignmentnode.left.resultdef=p.resultdef) and
  290. valid_for_var(aktassignmentnode.left,false) then
  291. begin
  292. para:=ccallparanode.create(
  293. arrp,
  294. ccallparanode.create(aktassignmentnode.left.getcopy,nil)
  295. );
  296. if is_ansistring(p.resultdef) then
  297. para:=ccallparanode.create(
  298. cordconstnode.create(
  299. { don't use getparaencoding(), we have to know
  300. when the result is rawbytestring }
  301. tstringdef(p.resultdef).encoding,
  302. u16inttype,
  303. true
  304. ),
  305. para
  306. );
  307. result:=ccallnode.createintern(
  308. 'fpc_'+tstringdef(p.resultdef).stringtypname+'_concat_multi',
  309. para
  310. );
  311. include(aktassignmentnode.flags,nf_assign_done_in_right);
  312. end
  313. else
  314. begin
  315. result:=internalstatements(newstatement);
  316. tempnode:=ctempcreatenode.create(p.resultdef,p.resultdef.size,tt_persistent ,true);
  317. addstatement(newstatement,tempnode);
  318. { initialize the temp, since it will be passed to a
  319. var-parameter (and finalization, which is performed by the
  320. ttempcreate node and which takes care of the initialization
  321. on native targets, is a noop on managed VM targets) }
  322. if (target_info.system in systems_managed_vm) and
  323. is_managed_type(p.resultdef) then
  324. addstatement(newstatement,cinlinenode.create(in_setlength_x,
  325. false,
  326. ccallparanode.create(genintconstnode(0),
  327. ccallparanode.create(ctemprefnode.create(tempnode),nil))));
  328. para:=ccallparanode.create(
  329. arrp,
  330. ccallparanode.create(ctemprefnode.create(tempnode),nil)
  331. );
  332. if is_ansistring(p.resultdef) then
  333. para:=ccallparanode.create(
  334. cordconstnode.create(
  335. { don't use getparaencoding(), we have to know
  336. when the result is rawbytestring }
  337. tstringdef(p.resultdef).encoding,
  338. u16inttype,
  339. true
  340. ),
  341. para
  342. );
  343. addstatement(
  344. newstatement,
  345. ccallnode.createintern(
  346. 'fpc_'+tstringdef(p.resultdef).stringtypname+'_concat_multi',
  347. para
  348. )
  349. );
  350. addstatement(newstatement,ctempdeletenode.create_normal_temp(tempnode));
  351. addstatement(newstatement,ctemprefnode.create(tempnode));
  352. end;
  353. end;
  354. function canbemultidynarrayadd(p: taddnode): boolean;
  355. var
  356. hp : tnode;
  357. i : longint;
  358. begin
  359. result:=false;
  360. if not(is_dynamic_array(p.resultdef)) then
  361. exit;
  362. i:=0;
  363. hp:=p;
  364. while assigned(hp) and (hp.nodetype=addn) do
  365. begin
  366. inc(i);
  367. hp:=taddnode(hp).left;
  368. end;
  369. result:=(i>1);
  370. end;
  371. function genmultidynarrayadd(p: taddnode): tnode;
  372. var
  373. hp,sn : tnode;
  374. arrp : tarrayconstructornode;
  375. newstatement : tstatementnode;
  376. tempnode : ttempcreatenode;
  377. para : tcallparanode;
  378. begin
  379. arrp:=nil;
  380. hp:=p;
  381. while assigned(hp) and (hp.nodetype=addn) do
  382. begin
  383. sn:=ctypeconvnode.create_internal(taddnode(hp).right.getcopy,voidpointertype);
  384. arrp:=carrayconstructornode.create(sn,arrp);
  385. hp:=taddnode(hp).left;
  386. end;
  387. sn:=ctypeconvnode.create_internal(hp.getcopy,voidpointertype);
  388. arrp:=carrayconstructornode.create(sn,arrp);
  389. arrp.allow_array_constructor:=true;
  390. if assigned(aktassignmentnode) and
  391. (aktassignmentnode.right=p) and
  392. (aktassignmentnode.left.resultdef=p.resultdef) and
  393. valid_for_var(aktassignmentnode.left,false) then
  394. begin
  395. para:=ccallparanode.create(
  396. arrp,
  397. ccallparanode.create(
  398. caddrnode.create_internal(crttinode.create(tstoreddef(p.resultdef),initrtti,rdt_normal)),
  399. ccallparanode.create(
  400. ctypeconvnode.create_internal(aktassignmentnode.left.getcopy,voidpointertype),nil)
  401. ));
  402. result:=ccallnode.createintern(
  403. 'fpc_dynarray_concat_multi',
  404. para
  405. );
  406. include(aktassignmentnode.flags,nf_assign_done_in_right);
  407. end
  408. else
  409. begin
  410. result:=internalstatements(newstatement);
  411. tempnode:=ctempcreatenode.create(p.resultdef,p.resultdef.size,tt_persistent ,true);
  412. addstatement(newstatement,tempnode);
  413. { initialize the temp, since it will be passed to a
  414. var-parameter (and finalization, which is performed by the
  415. ttempcreate node and which takes care of the initialization
  416. on native targets, is a noop on managed VM targets) }
  417. if (target_info.system in systems_managed_vm) and
  418. is_managed_type(p.resultdef) then
  419. addstatement(newstatement,cinlinenode.create(in_setlength_x,
  420. false,
  421. ccallparanode.create(genintconstnode(0),
  422. ccallparanode.create(ctemprefnode.create(tempnode),nil))));
  423. para:=ccallparanode.create(
  424. arrp,
  425. ccallparanode.create(
  426. caddrnode.create_internal(crttinode.create(tstoreddef(p.resultdef),initrtti,rdt_normal)),
  427. ccallparanode.create(
  428. ctypeconvnode.create_internal(ctemprefnode.create(tempnode),voidpointertype),nil)
  429. ));
  430. addstatement(
  431. newstatement,
  432. ccallnode.createintern(
  433. 'fpc_dynarray_concat_multi',
  434. para
  435. )
  436. );
  437. addstatement(newstatement,ctempdeletenode.create_normal_temp(tempnode));
  438. addstatement(newstatement,ctemprefnode.create(tempnode));
  439. end;
  440. end;
  441. begin
  442. caddsstringcharoptnode := taddsstringcharoptnode;
  443. caddsstringcsstringoptnode := taddsstringcsstringoptnode;
  444. end.