nopt.pas 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407
  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 is_addsstringoptnode(p: tnode): boolean;
  66. var
  67. caddsstringcharoptnode: taddsstringcharoptnodeclass;
  68. caddsstringcsstringoptnode: taddsstringcsstringoptnodeclass;
  69. implementation
  70. uses cutils, systems,
  71. htypechk, defutil, defcmp, globtype, globals, cpubase,
  72. ncnv, ncon, ncal, ninl, nld, nmem,
  73. verbose, symconst,symdef, cgbase, procinfo;
  74. {*****************************************************************************
  75. TADDOPTNODE
  76. *****************************************************************************}
  77. constructor taddoptnode.create(ts: tsubnodetype; l,r : tnode);
  78. begin
  79. { we need to keep the addn nodetype, otherwise taddnode.pass_generate_code will be }
  80. { confused. Comparison for equal nodetypes therefore has to be }
  81. { implemented using the classtype() method (JM) }
  82. inherited create(addn,l,r);
  83. subnodetype := ts;
  84. end;
  85. function taddoptnode.dogetcopy: tnode;
  86. var
  87. hp: taddoptnode;
  88. begin
  89. hp := taddoptnode(inherited dogetcopy);
  90. hp.subnodetype := subnodetype;
  91. dogetcopy := hp;
  92. end;
  93. function taddoptnode.docompare(p: tnode): boolean;
  94. begin
  95. docompare :=
  96. inherited docompare(p) and
  97. (subnodetype = taddoptnode(p).subnodetype);
  98. end;
  99. {*****************************************************************************
  100. TADDSSTRINGOPTNODE
  101. *****************************************************************************}
  102. function taddsstringoptnode.pass_typecheck: tnode;
  103. begin
  104. result := nil;
  105. updatecurmaxlen;
  106. { left and right are already firstpass'ed by taddnode.pass_1 }
  107. if not is_shortstring(left.resultdef) then
  108. inserttypeconv(left,cshortstringtype);
  109. if not is_shortstring(right.resultdef) then
  110. inserttypeconv(right,cshortstringtype);
  111. resultdef := left.resultdef;
  112. end;
  113. function taddsstringoptnode.pass_1: tnode;
  114. begin
  115. pass_1 := nil;
  116. expectloc:= LOC_REFERENCE;
  117. { here we call STRCONCAT or STRCMP or STRCOPY }
  118. include(current_procinfo.flags,pi_do_call);
  119. end;
  120. function taddsstringoptnode.dogetcopy: tnode;
  121. var
  122. hp: taddsstringoptnode;
  123. begin
  124. hp := taddsstringoptnode(inherited dogetcopy);
  125. hp.curmaxlen := curmaxlen;
  126. dogetcopy := hp;
  127. end;
  128. function taddsstringoptnode.docompare(p: tnode): boolean;
  129. begin
  130. docompare :=
  131. inherited docompare(p) and
  132. (curmaxlen = taddsstringcharoptnode(p).curmaxlen);
  133. end;
  134. function is_addsstringoptnode(p: tnode): boolean;
  135. begin
  136. is_addsstringoptnode :=
  137. p.inheritsfrom(taddsstringoptnode);
  138. end;
  139. procedure taddsstringoptnode.updatecurmaxlen;
  140. begin
  141. if is_addsstringoptnode(left) then
  142. begin
  143. { made it a separate block so no other if's are processed (would be a }
  144. { simple waste of time) (JM) }
  145. if (taddsstringoptnode(left).curmaxlen < 255) then
  146. case subnodetype of
  147. addsstringcharoptn:
  148. curmaxlen := succ(taddsstringoptnode(left).curmaxlen);
  149. addsstringcsstringoptn:
  150. curmaxlen := min(taddsstringoptnode(left).curmaxlen +
  151. tstringconstnode(right).len,255)
  152. else
  153. internalerror(291220001);
  154. end
  155. else curmaxlen := 255;
  156. end
  157. else if (left.nodetype = stringconstn) then
  158. curmaxlen := min(tstringconstnode(left).len,255)
  159. else if is_char(left.resultdef) then
  160. curmaxlen := 1
  161. else if (left.nodetype = typeconvn) then
  162. begin
  163. case ttypeconvnode(left).convtype of
  164. tc_char_2_string:
  165. curmaxlen := 1;
  166. { doesn't work yet, don't know why (JM)
  167. tc_chararray_2_string:
  168. curmaxlen :=
  169. min(ttypeconvnode(left).left.resultdef.size,255); }
  170. else curmaxlen := 255;
  171. end;
  172. end
  173. else
  174. curmaxlen := 255;
  175. end;
  176. {*****************************************************************************
  177. TADDSSTRINGCHAROPTNODE
  178. *****************************************************************************}
  179. constructor taddsstringcharoptnode.create(l,r : tnode);
  180. begin
  181. inherited create(addsstringcharoptn,l,r);
  182. end;
  183. {*****************************************************************************
  184. TADDSSTRINGCSSTRINGOPTNODE
  185. *****************************************************************************}
  186. constructor taddsstringcsstringoptnode.create(l,r : tnode);
  187. begin
  188. inherited create(addsstringcsstringoptn,l,r);
  189. end;
  190. function taddsstringcsstringoptnode.pass_1: tnode;
  191. begin
  192. { create the call to the concat routine both strings as arguments }
  193. result := ccallnode.createintern('fpc_shortstr_append_shortstr',
  194. ccallparanode.create(left,ccallparanode.create(right,nil)));
  195. left:=nil;
  196. right:=nil;
  197. end;
  198. {*****************************************************************************
  199. HELPERS
  200. *****************************************************************************}
  201. function canbeaddsstringcharoptnode(p: taddnode): boolean;
  202. begin
  203. canbeaddsstringcharoptnode :=
  204. (cs_opt_level1 in current_settings.optimizerswitches) and
  205. { the shortstring will be gotten through conversion if necessary (JM)
  206. is_shortstring(p.left.resultdef) and }
  207. ((p.nodetype = addn) and
  208. is_char(p.right.resultdef));
  209. end;
  210. function genaddsstringcharoptnode(p: taddnode): tnode;
  211. var
  212. hp: tnode;
  213. begin
  214. hp := caddsstringcharoptnode.create(p.left.getcopy,p.right.getcopy);
  215. hp.flags := p.flags;
  216. genaddsstringcharoptnode := hp;
  217. end;
  218. function canbeaddsstringcsstringoptnode(p: taddnode): boolean;
  219. begin
  220. canbeaddsstringcsstringoptnode :=
  221. (cs_opt_level1 in current_settings.optimizerswitches) and
  222. { the shortstring will be gotten through conversion if necessary (JM)
  223. is_shortstring(p.left.resultdef) and }
  224. ((p.nodetype = addn) and
  225. (p.right.nodetype = stringconstn));
  226. end;
  227. function genaddsstringcsstringoptnode(p: taddnode): tnode;
  228. var
  229. hp: tnode;
  230. begin
  231. hp := caddsstringcsstringoptnode.create(p.left.getcopy,p.right.getcopy);
  232. hp.flags := p.flags;
  233. genaddsstringcsstringoptnode := hp;
  234. end;
  235. function canbemultistringadd(p: taddnode): boolean;
  236. var
  237. hp : tnode;
  238. i : longint;
  239. begin
  240. result:=false;
  241. if p.resultdef.typ<>stringdef then
  242. exit;
  243. i:=0;
  244. hp:=p;
  245. while assigned(hp) and (hp.nodetype=addn) do
  246. begin
  247. inc(i);
  248. hp:=taddnode(hp).left;
  249. end;
  250. result:=(i>1);
  251. end;
  252. function genmultistringadd(p: taddnode): tnode;
  253. var
  254. hp,sn : tnode;
  255. arrp : tarrayconstructornode;
  256. newstatement : tstatementnode;
  257. tempnode : ttempcreatenode;
  258. is_shortstr : boolean;
  259. para : tcallparanode;
  260. begin
  261. arrp:=nil;
  262. hp:=p;
  263. is_shortstr:=is_shortstring(p.resultdef);
  264. while assigned(hp) and (hp.nodetype=addn) do
  265. begin
  266. sn:=taddnode(hp).right.getcopy;
  267. inserttypeconv(sn,p.resultdef);
  268. if is_shortstr then
  269. begin
  270. sn:=caddrnode.create(sn);
  271. include(sn.flags,nf_typedaddr);
  272. include(sn.flags,nf_internal);
  273. end;
  274. arrp:=carrayconstructornode.create(sn,arrp);
  275. hp:=taddnode(hp).left;
  276. end;
  277. sn:=hp.getcopy;
  278. inserttypeconv(sn,p.resultdef);
  279. if is_shortstr then
  280. begin
  281. sn:=caddrnode.create(sn);
  282. include(sn.flags,nf_internal);
  283. end;
  284. arrp:=carrayconstructornode.create(sn,arrp);
  285. if assigned(aktassignmentnode) and
  286. (aktassignmentnode.right=p) and
  287. (aktassignmentnode.left.resultdef=p.resultdef) and
  288. valid_for_var(aktassignmentnode.left,false) then
  289. begin
  290. para:=ccallparanode.create(
  291. arrp,
  292. ccallparanode.create(aktassignmentnode.left.getcopy,nil)
  293. );
  294. if is_ansistring(p.resultdef) then
  295. para:=ccallparanode.create(
  296. cordconstnode.create(
  297. getparaencoding(p.resultdef),
  298. u16inttype,
  299. true
  300. ),
  301. para
  302. );
  303. result:=ccallnode.createintern(
  304. 'fpc_'+tstringdef(p.resultdef).stringtypname+'_concat_multi',
  305. para
  306. );
  307. include(aktassignmentnode.flags,nf_assign_done_in_right);
  308. end
  309. else
  310. begin
  311. result:=internalstatements(newstatement);
  312. tempnode:=ctempcreatenode.create(p.resultdef,p.resultdef.size,tt_persistent ,true);
  313. addstatement(newstatement,tempnode);
  314. { initialize the temp, since it will be passed to a
  315. var-parameter (and finalization, which is performed by the
  316. ttempcreate node and which takes care of the initialization
  317. on native targets, is a noop on managed VM targets) }
  318. if (target_info.system in systems_managed_vm) and
  319. is_managed_type(p.resultdef) then
  320. addstatement(newstatement,cinlinenode.create(in_setlength_x,
  321. false,
  322. ccallparanode.create(genintconstnode(0),
  323. ccallparanode.create(ctemprefnode.create(tempnode),nil))));
  324. para:=ccallparanode.create(
  325. arrp,
  326. ccallparanode.create(ctemprefnode.create(tempnode),nil)
  327. );
  328. if is_ansistring(p.resultdef) then
  329. para:=ccallparanode.create(
  330. cordconstnode.create(
  331. getparaencoding(p.resultdef),
  332. u16inttype,
  333. true
  334. ),
  335. para
  336. );
  337. addstatement(
  338. newstatement,
  339. ccallnode.createintern(
  340. 'fpc_'+tstringdef(p.resultdef).stringtypname+'_concat_multi',
  341. para
  342. )
  343. );
  344. addstatement(newstatement,ctempdeletenode.create_normal_temp(tempnode));
  345. addstatement(newstatement,ctemprefnode.create(tempnode));
  346. end;
  347. end;
  348. begin
  349. caddsstringcharoptnode := taddsstringcharoptnode;
  350. caddsstringcsstringoptnode := taddsstringcsstringoptnode;
  351. end.