optloadmodifystore.pas 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440
  1. {
  2. Copyright (c) 2017 by Nikolay Nikolov
  3. Optimizations for making use of load-modify-store operations in CISC-like
  4. instruction set architectures (such as x86)
  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 optloadmodifystore;
  19. {$i fpcdefs.inc}
  20. {$if defined(i386) or defined(x86_64) or defined(m68k)}
  21. {$define enable_shl_shr_assign_x_y}
  22. {$endif}
  23. interface
  24. uses
  25. node;
  26. procedure do_optloadmodifystore(var rootnode : tnode);
  27. implementation
  28. uses
  29. globtype,verbose,nutils,compinnr,
  30. defutil,defcmp,htypechk,pass_1,
  31. nadd,ncal,ncnv,ninl,nld,nmat;
  32. function try_opt_assignmentnode(assignmentnode: tassignmentnode): tnode;
  33. var
  34. newinlinenodetype: tinlinenumber;
  35. begin
  36. result:=nil;
  37. with assignmentnode do
  38. begin
  39. { replace i:=succ/pred(i) by inc/dec(i)? }
  40. if (right.nodetype=inlinen) and
  41. ((tinlinenode(right).inlinenumber=in_succ_x) or (tinlinenode(right).inlinenumber=in_pred_x)) and
  42. (tinlinenode(right).left.isequal(left)) and
  43. ((localswitches*[cs_check_overflow,cs_check_range])=[]) and
  44. ((right.localswitches*[cs_check_overflow,cs_check_range])=[]) and
  45. valid_for_var(tinlinenode(right).left,false) and
  46. not(might_have_sideeffects(tinlinenode(right).left)) then
  47. begin
  48. if tinlinenode(right).inlinenumber=in_succ_x then
  49. newinlinenodetype:=in_inc_x
  50. else
  51. newinlinenodetype:=in_dec_x;
  52. result:=cinlinenode.createintern(
  53. newinlinenodetype,false,ccallparanode.create(
  54. tinlinenode(right).left,nil));
  55. result.localswitches:=localswitches;
  56. result.fileinfo:=fileinfo;
  57. result.verbosity:=verbosity;
  58. tinlinenode(right).left:=nil;
  59. exit;
  60. end;
  61. { replace i:=i+k by inc(i,k)
  62. i:=i-k by dec(i,k)
  63. i:=i and/or/xor k by in_[and/or/xor]_assign_x_y(i,k)
  64. this handles the case, where there are no implicit type conversions }
  65. if (right.nodetype in [addn,subn,andn,orn,xorn]) and
  66. (taddnode(right).left.isequal(left)) and
  67. is_integer(taddnode(right).left.resultdef) and
  68. is_integer(taddnode(right).right.resultdef) and
  69. ((localswitches*[cs_check_overflow,cs_check_range])=[]) and
  70. ((right.localswitches*[cs_check_overflow,cs_check_range])=[]) and
  71. valid_for_var(taddnode(right).left,false) and
  72. not(might_have_sideeffects(taddnode(right).left)) then
  73. begin
  74. case right.nodetype of
  75. addn:
  76. newinlinenodetype:=in_inc_x;
  77. subn:
  78. newinlinenodetype:=in_dec_x;
  79. andn:
  80. newinlinenodetype:=in_and_assign_x_y;
  81. orn:
  82. newinlinenodetype:=in_or_assign_x_y;
  83. xorn:
  84. newinlinenodetype:=in_xor_assign_x_y;
  85. else
  86. internalerror(2017032901);
  87. end;
  88. if right.nodetype in [addn,subn] then
  89. result:=cinlinenode.createintern(
  90. newinlinenodetype,false,ccallparanode.create(
  91. taddnode(right).left,ccallparanode.create(taddnode(right).right,nil)))
  92. else
  93. result:=cinlinenode.createintern(
  94. newinlinenodetype,false,ccallparanode.create(
  95. taddnode(right).right,ccallparanode.create(taddnode(right).left,nil)));
  96. result.localswitches:=localswitches;
  97. result.fileinfo:=fileinfo;
  98. result.verbosity:=verbosity;
  99. taddnode(right).left:=nil;
  100. taddnode(right).right:=nil;
  101. exit;
  102. end;
  103. { replace i:=i+k by inc(i,k)
  104. i:=i-k by dec(i,k)
  105. i:=i and/or/xor k by in_[and/or/xor]_assign_x_y(i,k)
  106. this handles the case with two conversions (outer and inner):
  107. outer typeconv: right
  108. add/sub/and/or/xor: ttypeconvnode(right).left
  109. inner typeconv: taddnode(ttypeconvnode(right).left).left
  110. right side 'i': ttypeconvnode(taddnode(ttypeconvnode(right).left).left).left
  111. right side 'k': taddnode(ttypeconvnode(right).left).right }
  112. if (right.nodetype=typeconvn) and
  113. (ttypeconvnode(right).convtype=tc_int_2_int) and
  114. (ttypeconvnode(right).left.nodetype in [addn,subn,andn,orn,xorn]) and
  115. is_integer(ttypeconvnode(right).left.resultdef) and
  116. (right.resultdef.size<=ttypeconvnode(right).left.resultdef.size) and
  117. (taddnode(ttypeconvnode(right).left).left.nodetype=typeconvn) and
  118. (ttypeconvnode(taddnode(ttypeconvnode(right).left).left).convtype=tc_int_2_int) and
  119. are_equal_ints(right.resultdef,ttypeconvnode(taddnode(ttypeconvnode(right).left).left).left.resultdef) and
  120. ttypeconvnode(taddnode(ttypeconvnode(right).left).left).left.isequal(left) and
  121. is_integer(taddnode(ttypeconvnode(right).left).left.resultdef) and
  122. is_integer(taddnode(ttypeconvnode(right).left).right.resultdef) and
  123. is_integer(ttypeconvnode(taddnode(ttypeconvnode(right).left).left).left.resultdef) and
  124. ((localswitches*[cs_check_overflow,cs_check_range])=[]) and
  125. ((right.localswitches*[cs_check_overflow,cs_check_range])=[]) and
  126. valid_for_var(ttypeconvnode(taddnode(ttypeconvnode(right).left).left).left,false) and
  127. not(might_have_sideeffects(ttypeconvnode(taddnode(ttypeconvnode(right).left).left).left)) then
  128. begin
  129. case ttypeconvnode(right).left.nodetype of
  130. addn:
  131. newinlinenodetype:=in_inc_x;
  132. subn:
  133. newinlinenodetype:=in_dec_x;
  134. andn:
  135. newinlinenodetype:=in_and_assign_x_y;
  136. orn:
  137. newinlinenodetype:=in_or_assign_x_y;
  138. xorn:
  139. newinlinenodetype:=in_xor_assign_x_y;
  140. else
  141. internalerror(2017032901);
  142. end;
  143. inserttypeconv_internal(taddnode(ttypeconvnode(right).left).right,left.resultdef);
  144. if ttypeconvnode(right).left.nodetype in [addn,subn] then
  145. result:=cinlinenode.createintern(
  146. newinlinenodetype,false,ccallparanode.create(
  147. ttypeconvnode(taddnode(ttypeconvnode(right).left).left).left,ccallparanode.create(taddnode(ttypeconvnode(right).left).right,nil)))
  148. else
  149. result:=cinlinenode.createintern(
  150. newinlinenodetype,false,ccallparanode.create(
  151. taddnode(ttypeconvnode(right).left).right,ccallparanode.create(ttypeconvnode(taddnode(ttypeconvnode(right).left).left).left,nil)));
  152. result.localswitches:=localswitches;
  153. result.fileinfo:=fileinfo;
  154. result.verbosity:=verbosity;
  155. ttypeconvnode(taddnode(ttypeconvnode(right).left).left).left:=nil;
  156. taddnode(ttypeconvnode(right).left).right:=nil;
  157. exit;
  158. end;
  159. { replace i:=k+i by inc(i,k)
  160. i:=k and/or/xor i by in_[and/or/xor]_assign_x_y(i,k)
  161. this handles the case, where there are no implicit type conversions }
  162. if (right.nodetype in [addn,andn,orn,xorn]) and
  163. (taddnode(right).right.isequal(left)) and
  164. is_integer(taddnode(right).left.resultdef) and
  165. is_integer(taddnode(right).right.resultdef) and
  166. ((localswitches*[cs_check_overflow,cs_check_range])=[]) and
  167. ((right.localswitches*[cs_check_overflow,cs_check_range])=[]) and
  168. valid_for_var(taddnode(right).right,false) and
  169. not(might_have_sideeffects(taddnode(right).right)) then
  170. begin
  171. case right.nodetype of
  172. addn:
  173. newinlinenodetype:=in_inc_x;
  174. andn:
  175. newinlinenodetype:=in_and_assign_x_y;
  176. orn:
  177. newinlinenodetype:=in_or_assign_x_y;
  178. xorn:
  179. newinlinenodetype:=in_xor_assign_x_y;
  180. else
  181. internalerror(2017032902);
  182. end;
  183. if right.nodetype=addn then
  184. result:=cinlinenode.createintern(
  185. newinlinenodetype,false,ccallparanode.create(
  186. taddnode(right).right,ccallparanode.create(taddnode(right).left,nil)))
  187. else
  188. result:=cinlinenode.createintern(
  189. newinlinenodetype,false,ccallparanode.create(
  190. taddnode(right).left,ccallparanode.create(taddnode(right).right,nil)));
  191. result.localswitches:=localswitches;
  192. result.fileinfo:=fileinfo;
  193. result.verbosity:=verbosity;
  194. taddnode(right).right:=nil;
  195. taddnode(right).left:=nil;
  196. exit;
  197. end;
  198. { replace i:=k+i by inc(i,k)
  199. i:=k and/or/xor i by in_[and/or/xor]_assign_x_y(i,k)
  200. this handles the case with two conversions (outer and inner):
  201. outer typeconv: right
  202. add/and/or/xor: ttypeconvnode(right).left
  203. inner typeconv: taddnode(ttypeconvnode(right).left).right
  204. right side 'i': ttypeconvnode(taddnode(ttypeconvnode(right).left).right).left
  205. right side 'k': taddnode(ttypeconvnode(right).left).left }
  206. if (right.nodetype=typeconvn) and
  207. (ttypeconvnode(right).convtype=tc_int_2_int) and
  208. (ttypeconvnode(right).left.nodetype in [addn,andn,orn,xorn]) and
  209. is_integer(ttypeconvnode(right).left.resultdef) and
  210. (right.resultdef.size<=ttypeconvnode(right).left.resultdef.size) and
  211. (taddnode(ttypeconvnode(right).left).right.nodetype=typeconvn) and
  212. (ttypeconvnode(taddnode(ttypeconvnode(right).left).right).convtype=tc_int_2_int) and
  213. are_equal_ints(right.resultdef,ttypeconvnode(taddnode(ttypeconvnode(right).left).right).left.resultdef) and
  214. ttypeconvnode(taddnode(ttypeconvnode(right).left).right).left.isequal(left) and
  215. is_integer(taddnode(ttypeconvnode(right).left).left.resultdef) and
  216. is_integer(taddnode(ttypeconvnode(right).left).right.resultdef) and
  217. is_integer(ttypeconvnode(taddnode(ttypeconvnode(right).left).right).left.resultdef) and
  218. ((localswitches*[cs_check_overflow,cs_check_range])=[]) and
  219. ((right.localswitches*[cs_check_overflow,cs_check_range])=[]) and
  220. valid_for_var(ttypeconvnode(taddnode(ttypeconvnode(right).left).right).left,false) and
  221. not(might_have_sideeffects(ttypeconvnode(taddnode(ttypeconvnode(right).left).right).left)) then
  222. begin
  223. case ttypeconvnode(right).left.nodetype of
  224. addn:
  225. newinlinenodetype:=in_inc_x;
  226. andn:
  227. newinlinenodetype:=in_and_assign_x_y;
  228. orn:
  229. newinlinenodetype:=in_or_assign_x_y;
  230. xorn:
  231. newinlinenodetype:=in_xor_assign_x_y;
  232. else
  233. internalerror(2017051101);
  234. end;
  235. inserttypeconv_internal(taddnode(ttypeconvnode(right).left).left,left.resultdef);
  236. if ttypeconvnode(right).left.nodetype=addn then
  237. result:=cinlinenode.createintern(
  238. newinlinenodetype,false,ccallparanode.create(
  239. ttypeconvnode(taddnode(ttypeconvnode(right).left).right).left,ccallparanode.create(taddnode(ttypeconvnode(right).left).left,nil)))
  240. else
  241. result:=cinlinenode.createintern(
  242. newinlinenodetype,false,ccallparanode.create(
  243. taddnode(ttypeconvnode(right).left).left,ccallparanode.create(ttypeconvnode(taddnode(ttypeconvnode(right).left).right).left,nil)));
  244. result.localswitches:=localswitches;
  245. result.fileinfo:=fileinfo;
  246. result.verbosity:=verbosity;
  247. ttypeconvnode(taddnode(ttypeconvnode(right).left).right).left:=nil;
  248. taddnode(ttypeconvnode(right).left).left:=nil;
  249. exit;
  250. end;
  251. {$ifdef enable_shl_shr_assign_x_y}
  252. { replace i:=i shl k by in_shl_assign_x_y(i,k)
  253. i:=i shr k by in_shr_assign_x_y(i,k)
  254. this handles the case, where there are no implicit type conversions }
  255. if (right.nodetype in [shln,shrn]) and
  256. (tshlshrnode(right).left.isequal(left)) and
  257. is_integer(tshlshrnode(right).left.resultdef) and
  258. is_integer(tshlshrnode(right).right.resultdef) and
  259. {$if not defined(cpu64bitalu) and not defined(cpucg64shiftsupport)}
  260. not(is_64bitint(tshlshrnode(right).left.resultdef)) and
  261. {$endif}
  262. ((localswitches*[cs_check_overflow,cs_check_range])=[]) and
  263. ((right.localswitches*[cs_check_overflow,cs_check_range])=[]) and
  264. valid_for_var(tshlshrnode(right).left,false) and
  265. not(might_have_sideeffects(tshlshrnode(right).left)) then
  266. begin
  267. case right.nodetype of
  268. shln:
  269. newinlinenodetype:=in_shl_assign_x_y;
  270. shrn:
  271. newinlinenodetype:=in_shr_assign_x_y;
  272. else
  273. internalerror(2017051201);
  274. end;
  275. result:=cinlinenode.createintern(
  276. newinlinenodetype,false,ccallparanode.create(
  277. tshlshrnode(right).right,ccallparanode.create(tshlshrnode(right).left,nil)));
  278. result.localswitches:=localswitches;
  279. result.fileinfo:=fileinfo;
  280. result.verbosity:=verbosity;
  281. tshlshrnode(right).left:=nil;
  282. tshlshrnode(right).right:=nil;
  283. exit;
  284. end;
  285. { replace i:=i shl k by in_shl_assign_x_y(i,k)
  286. i:=i shr k by in_shr_assign_x_y(i,k)
  287. this handles the case with two conversions (outer and inner):
  288. outer typeconv: right
  289. shl/shr: ttypeconvnode(right).left
  290. inner typeconv: tshlshrnode(ttypeconvnode(right).left).left
  291. right side 'i': ttypeconvnode(tshlshrnode(ttypeconvnode(right).left).left).left
  292. right side 'k': tshlshrnode(ttypeconvnode(right).left).right }
  293. if (right.nodetype=typeconvn) and
  294. (ttypeconvnode(right).convtype=tc_int_2_int) and
  295. (ttypeconvnode(right).left.nodetype in [shln,shrn]) and
  296. is_integer(ttypeconvnode(right).left.resultdef) and
  297. {$if not defined(cpu64bitalu) and not defined(cpucg64shiftsupport)}
  298. not(is_64bitint(ttypeconvnode(right).left.resultdef)) and
  299. {$endif}
  300. (right.resultdef.size<=ttypeconvnode(right).left.resultdef.size) and
  301. (tshlshrnode(ttypeconvnode(right).left).left.nodetype=typeconvn) and
  302. (ttypeconvnode(tshlshrnode(ttypeconvnode(right).left).left).convtype=tc_int_2_int) and
  303. are_equal_ints(right.resultdef,ttypeconvnode(tshlshrnode(ttypeconvnode(right).left).left).left.resultdef) and
  304. ttypeconvnode(tshlshrnode(ttypeconvnode(right).left).left).left.isequal(left) and
  305. is_integer(tshlshrnode(ttypeconvnode(right).left).left.resultdef) and
  306. is_integer(tshlshrnode(ttypeconvnode(right).left).right.resultdef) and
  307. is_integer(ttypeconvnode(tshlshrnode(ttypeconvnode(right).left).left).left.resultdef) and
  308. ((localswitches*[cs_check_overflow,cs_check_range])=[]) and
  309. ((right.localswitches*[cs_check_overflow,cs_check_range])=[]) and
  310. valid_for_var(ttypeconvnode(tshlshrnode(ttypeconvnode(right).left).left).left,false) and
  311. not(might_have_sideeffects(ttypeconvnode(tshlshrnode(ttypeconvnode(right).left).left).left)) then
  312. begin
  313. case ttypeconvnode(right).left.nodetype of
  314. shln:
  315. newinlinenodetype:=in_shl_assign_x_y;
  316. shrn:
  317. newinlinenodetype:=in_shr_assign_x_y;
  318. else
  319. internalerror(2017051201);
  320. end;
  321. inserttypeconv_internal(tshlshrnode(ttypeconvnode(right).left).right,left.resultdef);
  322. result:=cinlinenode.createintern(
  323. newinlinenodetype,false,ccallparanode.create(
  324. tshlshrnode(ttypeconvnode(right).left).right,ccallparanode.create(ttypeconvnode(tshlshrnode(ttypeconvnode(right).left).left).left,nil)));
  325. result.localswitches:=localswitches;
  326. result.fileinfo:=fileinfo;
  327. result.verbosity:=verbosity;
  328. ttypeconvnode(tshlshrnode(ttypeconvnode(right).left).left).left:=nil;
  329. tshlshrnode(ttypeconvnode(right).left).right:=nil;
  330. exit;
  331. end;
  332. {$endif enable_shl_shr_assign_x_y}
  333. { replace i:=not i by in_not_assign_x(i)
  334. i:=-i by in_neg_assign_x(i)
  335. this handles the case, where there are no implicit type conversions }
  336. if (right.nodetype in [notn,unaryminusn]) and
  337. (tunarynode(right).left.isequal(left)) and
  338. is_integer(tunarynode(right).left.resultdef) and
  339. ((localswitches*[cs_check_overflow,cs_check_range])=[]) and
  340. ((right.localswitches*[cs_check_overflow,cs_check_range])=[]) and
  341. valid_for_var(tunarynode(right).left,false) and
  342. not(might_have_sideeffects(tunarynode(right).left)) then
  343. begin
  344. if right.nodetype=notn then
  345. newinlinenodetype:=in_not_assign_x
  346. else
  347. newinlinenodetype:=in_neg_assign_x;
  348. result:=cinlinenode.createintern(
  349. newinlinenodetype,false,tunarynode(right).left);
  350. result.localswitches:=localswitches;
  351. result.fileinfo:=fileinfo;
  352. result.verbosity:=verbosity;
  353. tunarynode(right).left:=nil;
  354. exit;
  355. end;
  356. { replace i:=not i by in_not_assign_x(i)
  357. i:=-i by in_neg_assign_x(i)
  358. this handles the case with type conversions:
  359. outer typeconv: right
  360. neg/not: ttypeconvnode(right).left
  361. inner typeconv: tunarynode(ttypeconvnode(right).left).left
  362. right side 'i': ttypeconvnode(tunarynode(ttypeconvnode(right).left).left).left }
  363. if (right.nodetype=typeconvn) and
  364. (ttypeconvnode(right).convtype=tc_int_2_int) and
  365. (ttypeconvnode(right).left.nodetype in [notn,unaryminusn]) and
  366. is_integer(ttypeconvnode(right).left.resultdef) and
  367. (right.resultdef.size<=ttypeconvnode(right).left.resultdef.size) and
  368. (tunarynode(ttypeconvnode(right).left).left.nodetype=typeconvn) and
  369. (ttypeconvnode(tunarynode(ttypeconvnode(right).left).left).convtype=tc_int_2_int) and
  370. are_equal_ints(right.resultdef,ttypeconvnode(tunarynode(ttypeconvnode(right).left).left).left.resultdef) and
  371. ttypeconvnode(tunarynode(ttypeconvnode(right).left).left).left.isequal(left) and
  372. is_integer(ttypeconvnode(tunarynode(ttypeconvnode(right).left).left).left.resultdef) and
  373. ((localswitches*[cs_check_overflow,cs_check_range])=[]) and
  374. ((right.localswitches*[cs_check_overflow,cs_check_range])=[]) and
  375. valid_for_var(ttypeconvnode(tunarynode(ttypeconvnode(right).left).left).left,false) and
  376. not(might_have_sideeffects(ttypeconvnode(tunarynode(ttypeconvnode(right).left).left).left)) then
  377. begin
  378. if ttypeconvnode(right).left.nodetype=notn then
  379. newinlinenodetype:=in_not_assign_x
  380. else
  381. newinlinenodetype:=in_neg_assign_x;
  382. result:=cinlinenode.createintern(
  383. newinlinenodetype,false,ttypeconvnode(tunarynode(ttypeconvnode(right).left).left).left);
  384. result.localswitches:=localswitches;
  385. result.fileinfo:=fileinfo;
  386. result.verbosity:=verbosity;
  387. ttypeconvnode(tunarynode(ttypeconvnode(right).left).left).left:=nil;
  388. exit;
  389. end;
  390. end;
  391. end;
  392. function try_opt_node(var n: tnode; arg: pointer): foreachnoderesult;
  393. var
  394. hn : tnode;
  395. begin
  396. result:=fen_false;
  397. if n.nodetype=assignn then
  398. begin
  399. hn:=try_opt_assignmentnode(tassignmentnode(n));
  400. if assigned(hn) then
  401. begin
  402. n.free;
  403. n:=hn;
  404. typecheckpass(n);
  405. do_firstpass(n);
  406. end;
  407. end;
  408. end;
  409. procedure do_optloadmodifystore(var rootnode : tnode);
  410. begin
  411. foreachnodestatic(pm_postprocess,rootnode,@try_opt_node,nil);
  412. end;
  413. end.