optloadmodifystore.pas 34 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664
  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. {$if defined(i386) or defined(x86_64)}
  24. {$define enable_sar_assign_x_y}
  25. {$endif}
  26. {$if defined(i386) or defined(x86_64)}
  27. {$define enable_rox_assign_x_y}
  28. {$endif}
  29. interface
  30. uses
  31. node,nld;
  32. procedure do_optloadmodifystore(var rootnode : tnode);
  33. function try_opt_assignmentnode(assignmentnode : tassignmentnode): tnode;
  34. implementation
  35. uses
  36. globtype,globals,verbose,nutils,compinnr,
  37. defutil,defcmp,htypechk,pass_1,constexp,
  38. nadd,ncal,ncon,ncnv,ninl,nmat,
  39. symdef;
  40. function try_opt_assignmentnode(assignmentnode: tassignmentnode): tnode;
  41. {$ifndef llvm}
  42. var
  43. newinlinenodetype: tinlinenumber;
  44. {$endif llvm}
  45. begin
  46. result:=nil;
  47. {$ifndef llvm}
  48. foreachnodestatic(pm_postprocess,rootnode,@try_opt_node,nil);
  49. with assignmentnode do
  50. begin
  51. { *** Here are simple optimizations which are performed
  52. when -O2 (via a call from tassignmentnode.simplify) or
  53. when cs_opt_use_load_modify_store is enabled (in a separate pass).
  54. }
  55. { replace i:=succ/pred(i) by inc/dec(i)? }
  56. if (right.nodetype=inlinen) and
  57. ((tinlinenode(right).inlinenumber=in_succ_x) or (tinlinenode(right).inlinenumber=in_pred_x)) and
  58. (tinlinenode(right).left.isequal(left)) and
  59. ((localswitches*[cs_check_overflow,cs_check_range])=[]) and
  60. ((right.localswitches*[cs_check_overflow,cs_check_range])=[]) and
  61. valid_for_var(tinlinenode(right).left,false) and
  62. not(might_have_sideeffects(tinlinenode(right).left)) then
  63. begin
  64. if tinlinenode(right).inlinenumber=in_succ_x then
  65. newinlinenodetype:=in_inc_x
  66. else
  67. newinlinenodetype:=in_dec_x;
  68. result:=cinlinenode.createintern(
  69. newinlinenodetype,false,ccallparanode.create(
  70. tinlinenode(right).left,nil));
  71. result.localswitches:=localswitches;
  72. result.fileinfo:=fileinfo;
  73. result.verbosity:=verbosity;
  74. tinlinenode(right).left:=nil;
  75. exit;
  76. end;
  77. { replace i:=i+k by inc(i,k)
  78. i:=i-k by dec(i,k)
  79. i:=i and/or/xor k by in_[and/or/xor]_assign_x_y(i,k)
  80. this handles the case, where there are no implicit type conversions }
  81. if (right.nodetype in [addn,subn,andn,orn,xorn]) and
  82. (taddnode(right).left.isequal(left)) and
  83. is_integer(taddnode(right).left.resultdef) and
  84. is_integer(taddnode(right).right.resultdef) and
  85. ((localswitches*[cs_check_overflow,cs_check_range])=[]) and
  86. ((right.localswitches*[cs_check_overflow,cs_check_range])=[]) and
  87. valid_for_var(taddnode(right).left,false) and
  88. not(might_have_sideeffects(taddnode(right).left)) then
  89. begin
  90. case right.nodetype of
  91. addn:
  92. newinlinenodetype:=in_inc_x;
  93. subn:
  94. newinlinenodetype:=in_dec_x;
  95. andn:
  96. newinlinenodetype:=in_and_assign_x_y;
  97. orn:
  98. newinlinenodetype:=in_or_assign_x_y;
  99. xorn:
  100. newinlinenodetype:=in_xor_assign_x_y;
  101. else
  102. internalerror(2017032901);
  103. end;
  104. if right.nodetype in [addn,subn] then
  105. result:=cinlinenode.createintern(
  106. newinlinenodetype,false,ccallparanode.create(
  107. taddnode(right).left,ccallparanode.create(taddnode(right).right,nil)))
  108. else
  109. result:=cinlinenode.createintern(
  110. newinlinenodetype,false,ccallparanode.create(
  111. taddnode(right).right,ccallparanode.create(taddnode(right).left,nil)));
  112. result.localswitches:=localswitches;
  113. result.fileinfo:=fileinfo;
  114. result.verbosity:=verbosity;
  115. taddnode(right).left:=nil;
  116. taddnode(right).right:=nil;
  117. exit;
  118. end;
  119. { replace i:=i+k by inc(i,k)
  120. i:=i-k by dec(i,k)
  121. i:=i and/or/xor k by in_[and/or/xor]_assign_x_y(i,k)
  122. this handles the case with two conversions (outer and inner):
  123. outer typeconv: right
  124. add/sub/and/or/xor: ttypeconvnode(right).left
  125. inner typeconv: taddnode(ttypeconvnode(right).left).left
  126. right side 'i': ttypeconvnode(taddnode(ttypeconvnode(right).left).left).left
  127. right side 'k': taddnode(ttypeconvnode(right).left).right }
  128. if (right.nodetype=typeconvn) and
  129. (ttypeconvnode(right).convtype=tc_int_2_int) and
  130. (ttypeconvnode(right).left.nodetype in [addn,subn,andn,orn,xorn]) and
  131. is_integer(ttypeconvnode(right).left.resultdef) and
  132. (right.resultdef.size<=ttypeconvnode(right).left.resultdef.size) and
  133. (taddnode(ttypeconvnode(right).left).left.nodetype=typeconvn) and
  134. (ttypeconvnode(taddnode(ttypeconvnode(right).left).left).convtype=tc_int_2_int) and
  135. are_equal_ints(right.resultdef,ttypeconvnode(taddnode(ttypeconvnode(right).left).left).left.resultdef) and
  136. ttypeconvnode(taddnode(ttypeconvnode(right).left).left).left.isequal(left) and
  137. is_integer(taddnode(ttypeconvnode(right).left).left.resultdef) and
  138. is_integer(taddnode(ttypeconvnode(right).left).right.resultdef) and
  139. is_integer(ttypeconvnode(taddnode(ttypeconvnode(right).left).left).left.resultdef) and
  140. ((localswitches*[cs_check_overflow,cs_check_range])=[]) and
  141. ((right.localswitches*[cs_check_overflow,cs_check_range])=[]) and
  142. valid_for_var(ttypeconvnode(taddnode(ttypeconvnode(right).left).left).left,false) and
  143. not(might_have_sideeffects(ttypeconvnode(taddnode(ttypeconvnode(right).left).left).left)) then
  144. begin
  145. case ttypeconvnode(right).left.nodetype of
  146. addn:
  147. newinlinenodetype:=in_inc_x;
  148. subn:
  149. newinlinenodetype:=in_dec_x;
  150. andn:
  151. newinlinenodetype:=in_and_assign_x_y;
  152. orn:
  153. newinlinenodetype:=in_or_assign_x_y;
  154. xorn:
  155. newinlinenodetype:=in_xor_assign_x_y;
  156. else
  157. internalerror(2017032903);
  158. end;
  159. inserttypeconv_internal(taddnode(ttypeconvnode(right).left).right,left.resultdef);
  160. if ttypeconvnode(right).left.nodetype in [addn,subn] then
  161. result:=cinlinenode.createintern(
  162. newinlinenodetype,false,ccallparanode.create(
  163. ttypeconvnode(taddnode(ttypeconvnode(right).left).left).left,ccallparanode.create(taddnode(ttypeconvnode(right).left).right,nil)))
  164. else
  165. result:=cinlinenode.createintern(
  166. newinlinenodetype,false,ccallparanode.create(
  167. taddnode(ttypeconvnode(right).left).right,ccallparanode.create(ttypeconvnode(taddnode(ttypeconvnode(right).left).left).left,nil)));
  168. result.localswitches:=localswitches;
  169. result.fileinfo:=fileinfo;
  170. result.verbosity:=verbosity;
  171. ttypeconvnode(taddnode(ttypeconvnode(right).left).left).left:=nil;
  172. taddnode(ttypeconvnode(right).left).right:=nil;
  173. exit;
  174. end;
  175. { replace i:=k+i by inc(i,k)
  176. i:=k and/or/xor i by in_[and/or/xor]_assign_x_y(i,k)
  177. this handles the case, where there are no implicit type conversions }
  178. if (right.nodetype in [addn,andn,orn,xorn]) and
  179. (taddnode(right).right.isequal(left)) and
  180. is_integer(taddnode(right).left.resultdef) and
  181. is_integer(taddnode(right).right.resultdef) and
  182. ((localswitches*[cs_check_overflow,cs_check_range])=[]) and
  183. ((right.localswitches*[cs_check_overflow,cs_check_range])=[]) and
  184. valid_for_var(taddnode(right).right,false) and
  185. not(might_have_sideeffects(taddnode(right).right)) then
  186. begin
  187. case right.nodetype of
  188. addn:
  189. newinlinenodetype:=in_inc_x;
  190. andn:
  191. newinlinenodetype:=in_and_assign_x_y;
  192. orn:
  193. newinlinenodetype:=in_or_assign_x_y;
  194. xorn:
  195. newinlinenodetype:=in_xor_assign_x_y;
  196. else
  197. internalerror(2017032902);
  198. end;
  199. if right.nodetype=addn then
  200. result:=cinlinenode.createintern(
  201. newinlinenodetype,false,ccallparanode.create(
  202. taddnode(right).right,ccallparanode.create(taddnode(right).left,nil)))
  203. else
  204. result:=cinlinenode.createintern(
  205. newinlinenodetype,false,ccallparanode.create(
  206. taddnode(right).left,ccallparanode.create(taddnode(right).right,nil)));
  207. result.localswitches:=localswitches;
  208. result.fileinfo:=fileinfo;
  209. result.verbosity:=verbosity;
  210. taddnode(right).right:=nil;
  211. taddnode(right).left:=nil;
  212. exit;
  213. end;
  214. { replace i:=k+i by inc(i,k)
  215. i:=k and/or/xor i by in_[and/or/xor]_assign_x_y(i,k)
  216. this handles the case with two conversions (outer and inner):
  217. outer typeconv: right
  218. add/and/or/xor: ttypeconvnode(right).left
  219. inner typeconv: taddnode(ttypeconvnode(right).left).right
  220. right side 'i': ttypeconvnode(taddnode(ttypeconvnode(right).left).right).left
  221. right side 'k': taddnode(ttypeconvnode(right).left).left }
  222. if (right.nodetype=typeconvn) and
  223. (ttypeconvnode(right).convtype=tc_int_2_int) and
  224. (ttypeconvnode(right).left.nodetype in [addn,andn,orn,xorn]) and
  225. is_integer(ttypeconvnode(right).left.resultdef) and
  226. (right.resultdef.size<=ttypeconvnode(right).left.resultdef.size) and
  227. (taddnode(ttypeconvnode(right).left).right.nodetype=typeconvn) and
  228. (ttypeconvnode(taddnode(ttypeconvnode(right).left).right).convtype=tc_int_2_int) and
  229. are_equal_ints(right.resultdef,ttypeconvnode(taddnode(ttypeconvnode(right).left).right).left.resultdef) and
  230. ttypeconvnode(taddnode(ttypeconvnode(right).left).right).left.isequal(left) and
  231. is_integer(taddnode(ttypeconvnode(right).left).left.resultdef) and
  232. is_integer(taddnode(ttypeconvnode(right).left).right.resultdef) and
  233. is_integer(ttypeconvnode(taddnode(ttypeconvnode(right).left).right).left.resultdef) and
  234. ((localswitches*[cs_check_overflow,cs_check_range])=[]) and
  235. ((right.localswitches*[cs_check_overflow,cs_check_range])=[]) and
  236. valid_for_var(ttypeconvnode(taddnode(ttypeconvnode(right).left).right).left,false) and
  237. not(might_have_sideeffects(ttypeconvnode(taddnode(ttypeconvnode(right).left).right).left)) then
  238. begin
  239. case ttypeconvnode(right).left.nodetype of
  240. addn:
  241. newinlinenodetype:=in_inc_x;
  242. andn:
  243. newinlinenodetype:=in_and_assign_x_y;
  244. orn:
  245. newinlinenodetype:=in_or_assign_x_y;
  246. xorn:
  247. newinlinenodetype:=in_xor_assign_x_y;
  248. else
  249. internalerror(2017051101);
  250. end;
  251. inserttypeconv_internal(taddnode(ttypeconvnode(right).left).left,left.resultdef);
  252. if ttypeconvnode(right).left.nodetype=addn then
  253. result:=cinlinenode.createintern(
  254. newinlinenodetype,false,ccallparanode.create(
  255. ttypeconvnode(taddnode(ttypeconvnode(right).left).right).left,ccallparanode.create(taddnode(ttypeconvnode(right).left).left,nil)))
  256. else
  257. result:=cinlinenode.createintern(
  258. newinlinenodetype,false,ccallparanode.create(
  259. taddnode(ttypeconvnode(right).left).left,ccallparanode.create(ttypeconvnode(taddnode(ttypeconvnode(right).left).right).left,nil)));
  260. result.localswitches:=localswitches;
  261. result.fileinfo:=fileinfo;
  262. result.verbosity:=verbosity;
  263. ttypeconvnode(taddnode(ttypeconvnode(right).left).right).left:=nil;
  264. taddnode(ttypeconvnode(right).left).left:=nil;
  265. exit;
  266. end;
  267. { replace i:=not i by in_not_assign_x(i)
  268. i:=-i by in_neg_assign_x(i)
  269. this handles the case, where there are no implicit type conversions }
  270. if (right.nodetype in [notn,unaryminusn]) and
  271. (tunarynode(right).left.isequal(left)) and
  272. is_integer(tunarynode(right).left.resultdef) and
  273. ((localswitches*[cs_check_overflow,cs_check_range])=[]) and
  274. ((right.localswitches*[cs_check_overflow,cs_check_range])=[]) and
  275. valid_for_var(tunarynode(right).left,false) and
  276. not(might_have_sideeffects(tunarynode(right).left)) then
  277. begin
  278. if right.nodetype=notn then
  279. newinlinenodetype:=in_not_assign_x
  280. else
  281. newinlinenodetype:=in_neg_assign_x;
  282. result:=cinlinenode.createintern(
  283. newinlinenodetype,false,tunarynode(right).left);
  284. result.localswitches:=localswitches;
  285. result.fileinfo:=fileinfo;
  286. result.verbosity:=verbosity;
  287. tunarynode(right).left:=nil;
  288. exit;
  289. end;
  290. { replace i:=not i by in_not_assign_x(i)
  291. i:=-i by in_neg_assign_x(i)
  292. this handles the case with type conversions:
  293. outer typeconv: right
  294. neg/not: ttypeconvnode(right).left
  295. inner typeconv: tunarynode(ttypeconvnode(right).left).left
  296. right side 'i': ttypeconvnode(tunarynode(ttypeconvnode(right).left).left).left }
  297. if (right.nodetype=typeconvn) and
  298. (ttypeconvnode(right).convtype=tc_int_2_int) and
  299. (ttypeconvnode(right).left.nodetype in [notn,unaryminusn]) and
  300. is_integer(ttypeconvnode(right).left.resultdef) and
  301. (right.resultdef.size<=ttypeconvnode(right).left.resultdef.size) and
  302. (tunarynode(ttypeconvnode(right).left).left.nodetype=typeconvn) and
  303. (ttypeconvnode(tunarynode(ttypeconvnode(right).left).left).convtype=tc_int_2_int) and
  304. are_equal_ints(right.resultdef,ttypeconvnode(tunarynode(ttypeconvnode(right).left).left).left.resultdef) and
  305. ttypeconvnode(tunarynode(ttypeconvnode(right).left).left).left.isequal(left) and
  306. is_integer(ttypeconvnode(tunarynode(ttypeconvnode(right).left).left).left.resultdef) and
  307. ((localswitches*[cs_check_overflow,cs_check_range])=[]) and
  308. ((right.localswitches*[cs_check_overflow,cs_check_range])=[]) and
  309. valid_for_var(ttypeconvnode(tunarynode(ttypeconvnode(right).left).left).left,false) and
  310. not(might_have_sideeffects(ttypeconvnode(tunarynode(ttypeconvnode(right).left).left).left)) then
  311. begin
  312. if ttypeconvnode(right).left.nodetype=notn then
  313. newinlinenodetype:=in_not_assign_x
  314. else
  315. newinlinenodetype:=in_neg_assign_x;
  316. result:=cinlinenode.createintern(
  317. newinlinenodetype,false,ttypeconvnode(tunarynode(ttypeconvnode(right).left).left).left);
  318. result.localswitches:=localswitches;
  319. result.fileinfo:=fileinfo;
  320. result.verbosity:=verbosity;
  321. ttypeconvnode(tunarynode(ttypeconvnode(right).left).left).left:=nil;
  322. exit;
  323. end;
  324. if not (cs_opt_use_load_modify_store in current_settings.optimizerswitches) then
  325. exit;
  326. { *** Here are more complex optimizations which are performed only
  327. when cs_opt_use_load_modify_store is enabled.
  328. }
  329. {$ifdef enable_shl_shr_assign_x_y}
  330. { replace i:=i shl k by in_shl_assign_x_y(i,k)
  331. i:=i shr k by in_shr_assign_x_y(i,k)
  332. this handles the case, where there are no implicit type conversions }
  333. if (right.nodetype in [shln,shrn]) and
  334. (tshlshrnode(right).left.isequal(left)) and
  335. is_integer(tshlshrnode(right).left.resultdef) and
  336. is_integer(tshlshrnode(right).right.resultdef) and
  337. {$if not defined(cpu64bitalu) and not defined(cpucg64shiftsupport)}
  338. not(is_64bitint(tshlshrnode(right).left.resultdef)) and
  339. {$endif}
  340. ((localswitches*[cs_check_overflow,cs_check_range])=[]) and
  341. ((right.localswitches*[cs_check_overflow,cs_check_range])=[]) and
  342. valid_for_var(tshlshrnode(right).left,false) and
  343. not(might_have_sideeffects(tshlshrnode(right).left)) then
  344. begin
  345. case right.nodetype of
  346. shln:
  347. newinlinenodetype:=in_shl_assign_x_y;
  348. shrn:
  349. newinlinenodetype:=in_shr_assign_x_y;
  350. else
  351. internalerror(2017051201);
  352. end;
  353. result:=cinlinenode.createintern(
  354. newinlinenodetype,false,ccallparanode.create(
  355. tshlshrnode(right).right,ccallparanode.create(tshlshrnode(right).left,nil)));
  356. result.localswitches:=localswitches;
  357. result.fileinfo:=fileinfo;
  358. result.verbosity:=verbosity;
  359. tshlshrnode(right).left:=nil;
  360. tshlshrnode(right).right:=nil;
  361. exit;
  362. end;
  363. { replace i:=i shl k by in_shl_assign_x_y(i,k)
  364. i:=i shr k by in_shr_assign_x_y(i,k)
  365. this handles the case with two conversions (outer and inner):
  366. outer typeconv: right
  367. shl/shr: ttypeconvnode(right).left
  368. inner typeconv: tshlshrnode(ttypeconvnode(right).left).left
  369. right side 'i': ttypeconvnode(tshlshrnode(ttypeconvnode(right).left).left).left
  370. right side 'k': tshlshrnode(ttypeconvnode(right).left).right }
  371. if (right.nodetype=typeconvn) and
  372. (ttypeconvnode(right).convtype=tc_int_2_int) and
  373. (ttypeconvnode(right).left.nodetype in [shln,shrn]) and
  374. is_integer(ttypeconvnode(right).left.resultdef) and
  375. {$if not defined(cpu64bitalu) and not defined(cpucg64shiftsupport)}
  376. not(is_64bitint(ttypeconvnode(right).left.resultdef)) and
  377. {$endif}
  378. (right.resultdef.size<=ttypeconvnode(right).left.resultdef.size) and
  379. (tshlshrnode(ttypeconvnode(right).left).left.nodetype=typeconvn) and
  380. (ttypeconvnode(tshlshrnode(ttypeconvnode(right).left).left).convtype=tc_int_2_int) and
  381. are_equal_ints(right.resultdef,ttypeconvnode(tshlshrnode(ttypeconvnode(right).left).left).left.resultdef) and
  382. ttypeconvnode(tshlshrnode(ttypeconvnode(right).left).left).left.isequal(left) and
  383. is_integer(tshlshrnode(ttypeconvnode(right).left).left.resultdef) and
  384. is_integer(tshlshrnode(ttypeconvnode(right).left).right.resultdef) and
  385. is_integer(ttypeconvnode(tshlshrnode(ttypeconvnode(right).left).left).left.resultdef) and
  386. ((localswitches*[cs_check_overflow,cs_check_range])=[]) and
  387. ((right.localswitches*[cs_check_overflow,cs_check_range])=[]) and
  388. valid_for_var(ttypeconvnode(tshlshrnode(ttypeconvnode(right).left).left).left,false) and
  389. not(might_have_sideeffects(ttypeconvnode(tshlshrnode(ttypeconvnode(right).left).left).left)) then
  390. begin
  391. case ttypeconvnode(right).left.nodetype of
  392. shln:
  393. newinlinenodetype:=in_shl_assign_x_y;
  394. shrn:
  395. newinlinenodetype:=in_shr_assign_x_y;
  396. else
  397. internalerror(2017051202);
  398. end;
  399. inserttypeconv_internal(tshlshrnode(ttypeconvnode(right).left).right,left.resultdef);
  400. result:=cinlinenode.createintern(
  401. newinlinenodetype,false,ccallparanode.create(
  402. tshlshrnode(ttypeconvnode(right).left).right,ccallparanode.create(ttypeconvnode(tshlshrnode(ttypeconvnode(right).left).left).left,nil)));
  403. result.localswitches:=localswitches;
  404. result.fileinfo:=fileinfo;
  405. result.verbosity:=verbosity;
  406. ttypeconvnode(tshlshrnode(ttypeconvnode(right).left).left).left:=nil;
  407. tshlshrnode(ttypeconvnode(right).left).right:=nil;
  408. exit;
  409. end;
  410. {$endif enable_shl_shr_assign_x_y}
  411. {$if defined(enable_sar_assign_x_y) or defined(enable_rox_assign_x_y)}
  412. { replace i:=sar(i) by in_sar_assign_x_y(i,1)
  413. i:=rol(i) by in_rol_assign_x_y(i,1)
  414. i:=ror(i) by in_ror_assign_x_y(i,1)
  415. this handles the case, where there are no implicit type conversions }
  416. if (right.nodetype=inlinen) and
  417. (tinlinenode(right).inlinenumber in [
  418. {$ifdef enable_sar_assign_x_y}
  419. in_sar_x{$ifdef enable_rox_assign_x_y},{$endif}
  420. {$endif enable_sar_assign_x_y}
  421. {$ifdef enable_rox_assign_x_y}
  422. in_rol_x,in_ror_x
  423. {$endif enable_rox_assign_x_y}
  424. ]) and
  425. (tinlinenode(right).left.isequal(left)) and
  426. is_integer(tinlinenode(right).left.resultdef) and
  427. {$if not defined(cpu64bitalu) and not defined(cpucg64shiftsupport)}
  428. not(is_64bitint(tinlinenode(right).left.resultdef)) and
  429. {$endif}
  430. ((localswitches*[cs_check_overflow,cs_check_range])=[]) and
  431. ((right.localswitches*[cs_check_overflow,cs_check_range])=[]) and
  432. valid_for_var(tinlinenode(right).left,false) and
  433. not(might_have_sideeffects(tinlinenode(right).left)) then
  434. begin
  435. case tinlinenode(right).inlinenumber of
  436. in_sar_x:
  437. newinlinenodetype:=in_sar_assign_x_y;
  438. in_rol_x:
  439. newinlinenodetype:=in_rol_assign_x_y;
  440. in_ror_x:
  441. newinlinenodetype:=in_ror_assign_x_y;
  442. else
  443. internalerror(2017071701);
  444. end;
  445. result:=cinlinenode.createintern(
  446. newinlinenodetype,false,ccallparanode.create(
  447. cordconstnode.create(1,u8inttype,false),ccallparanode.create(tinlinenode(right).left,nil)));
  448. result.localswitches:=localswitches;
  449. result.fileinfo:=fileinfo;
  450. result.verbosity:=verbosity;
  451. tinlinenode(right).left:=nil;
  452. exit;
  453. end;
  454. { replace i:=sar(i) by in_sar_assign_x_y(i,1)
  455. i:=rol(i) by in_rol_assign_x_y(i,1)
  456. i:=ror(i) by in_ror_assign_x_y(i,1)
  457. this handles the case with type conversions:
  458. outer typeconv: right
  459. sar/rol/ror inline node: ttypeconvnode(right).left
  460. inner typeconv: tinlinenode(ttypeconvnode(right).left).left
  461. right side 'i': ttypeconvnode(tinlinenode(ttypeconvnode(right).left).left).left }
  462. if (right.nodetype=typeconvn) and
  463. (ttypeconvnode(right).convtype=tc_int_2_int) and
  464. (ttypeconvnode(right).left.nodetype=inlinen) and
  465. (tinlinenode(ttypeconvnode(right).left).inlinenumber in [
  466. {$ifdef enable_sar_assign_x_y}
  467. in_sar_x{$ifdef enable_rox_assign_x_y},{$endif}
  468. {$endif enable_sar_assign_x_y}
  469. {$ifdef enable_rox_assign_x_y}
  470. in_rol_x,in_ror_x
  471. {$endif enable_rox_assign_x_y}
  472. ]) and
  473. is_integer(ttypeconvnode(right).left.resultdef) and
  474. (right.resultdef.size=ttypeconvnode(right).left.resultdef.size) and
  475. (tinlinenode(ttypeconvnode(right).left).left.nodetype=typeconvn) and
  476. (ttypeconvnode(tinlinenode(ttypeconvnode(right).left).left).convtype=tc_int_2_int) and
  477. are_equal_ints(right.resultdef,ttypeconvnode(tinlinenode(ttypeconvnode(right).left).left).left.resultdef) and
  478. ttypeconvnode(tinlinenode(ttypeconvnode(right).left).left).left.isequal(left) and
  479. is_integer(ttypeconvnode(tinlinenode(ttypeconvnode(right).left).left).left.resultdef) and
  480. ((localswitches*[cs_check_overflow,cs_check_range])=[]) and
  481. ((right.localswitches*[cs_check_overflow,cs_check_range])=[]) and
  482. valid_for_var(ttypeconvnode(tinlinenode(ttypeconvnode(right).left).left).left,false) and
  483. not(might_have_sideeffects(ttypeconvnode(tinlinenode(ttypeconvnode(right).left).left).left)) then
  484. begin
  485. case tinlinenode(ttypeconvnode(right).left).inlinenumber of
  486. in_sar_x:
  487. newinlinenodetype:=in_sar_assign_x_y;
  488. in_rol_x:
  489. newinlinenodetype:=in_rol_assign_x_y;
  490. in_ror_x:
  491. newinlinenodetype:=in_ror_assign_x_y;
  492. else
  493. internalerror(2017071801);
  494. end;
  495. result:=cinlinenode.createintern(
  496. newinlinenodetype,false,ccallparanode.create(
  497. cordconstnode.create(1,u8inttype,false),ccallparanode.create(
  498. ttypeconvnode(tinlinenode(ttypeconvnode(right).left).left).left,nil)));
  499. result.localswitches:=localswitches;
  500. result.fileinfo:=fileinfo;
  501. result.verbosity:=verbosity;
  502. ttypeconvnode(tinlinenode(ttypeconvnode(right).left).left).left:=nil;
  503. exit;
  504. end;
  505. { replace i:=sar(i,k) by in_sar_assign_x_y(i,k)
  506. i:=rol(i,k) by in_rol_assign_x_y(i,k)
  507. i:=ror(i,k) by in_ror_assign_x_y(i,k)
  508. this handles the case, where there are no implicit type conversions }
  509. if (right.nodetype=inlinen) and
  510. (tinlinenode(right).inlinenumber in [
  511. {$ifdef enable_sar_assign_x_y}
  512. in_sar_x_y{$ifdef enable_rox_assign_x_y},{$endif}
  513. {$endif enable_sar_assign_x_y}
  514. {$ifdef enable_rox_assign_x_y}
  515. in_rol_x_y,in_ror_x_y
  516. {$endif enable_rox_assign_x_y}
  517. ]) and
  518. (tinlinenode(right).left.nodetype=callparan) and
  519. tcallparanode(tcallparanode(tinlinenode(right).left).right).left.isequal(left) and
  520. is_integer(tcallparanode(tcallparanode(tinlinenode(right).left).right).left.resultdef) and
  521. {$if not defined(cpu64bitalu) and not defined(cpucg64shiftsupport)}
  522. not(is_64bitint(tcallparanode(tcallparanode(tinlinenode(right).left).right).left.resultdef)) and
  523. {$endif}
  524. ((localswitches*[cs_check_overflow,cs_check_range])=[]) and
  525. ((right.localswitches*[cs_check_overflow,cs_check_range])=[]) and
  526. valid_for_var(tcallparanode(tcallparanode(tinlinenode(right).left).right).left,false) and
  527. not(might_have_sideeffects(tcallparanode(tcallparanode(tinlinenode(right).left).right).left)) then
  528. begin
  529. case tinlinenode(right).inlinenumber of
  530. in_sar_x_y:
  531. newinlinenodetype:=in_sar_assign_x_y;
  532. in_rol_x_y:
  533. newinlinenodetype:=in_rol_assign_x_y;
  534. in_ror_x_y:
  535. newinlinenodetype:=in_ror_assign_x_y;
  536. else
  537. internalerror(2017071702);
  538. end;
  539. result:=cinlinenode.createintern(
  540. newinlinenodetype,false,ccallparanode.create(
  541. tcallparanode(tinlinenode(right).left).left,
  542. ccallparanode.create(tcallparanode(tcallparanode(tinlinenode(right).left).right).left,nil)));
  543. result.localswitches:=localswitches;
  544. result.fileinfo:=fileinfo;
  545. result.verbosity:=verbosity;
  546. tcallparanode(tinlinenode(right).left).left:=nil;
  547. tcallparanode(tcallparanode(tinlinenode(right).left).right).left:=nil;
  548. exit;
  549. end;
  550. { replace i:=sar(i,k) by in_sar_assign_x_y(i,k)
  551. i:=rol(i,k) by in_rol_assign_x_y(i,k)
  552. i:=ror(i,k) by in_ror_assign_x_y(i,k)
  553. this handles the case with two conversions (outer and inner):
  554. outer typeconv: right
  555. sar/rol/ror inline node: ttypeconvnode(right).left
  556. inner typeconv: tcallparanode(tcallparanode(tinlinenode(ttypeconvnode(right).left).left).right).left
  557. right side 'i': ttypeconvnode(tcallparanode(tcallparanode(tinlinenode(ttypeconvnode(right).left).left).right).left).left
  558. right side 'k': tcallparanode(tinlinenode(ttypeconvnode(right).left).left).left }
  559. if (right.nodetype=typeconvn) and
  560. (ttypeconvnode(right).convtype=tc_int_2_int) and
  561. (ttypeconvnode(right).left.nodetype=inlinen) and
  562. (tinlinenode(ttypeconvnode(right).left).inlinenumber in [
  563. {$ifdef enable_sar_assign_x_y}
  564. in_sar_x_y{$ifdef enable_rox_assign_x_y},{$endif}
  565. {$endif enable_sar_assign_x_y}
  566. {$ifdef enable_rox_assign_x_y}
  567. in_rol_x_y,in_ror_x_y
  568. {$endif enable_rox_assign_x_y}
  569. ]) and
  570. is_integer(ttypeconvnode(right).left.resultdef) and
  571. (right.resultdef.size=ttypeconvnode(right).left.resultdef.size) and
  572. (tinlinenode(ttypeconvnode(right).left).left.nodetype=callparan) and
  573. (tcallparanode(tcallparanode(tinlinenode(ttypeconvnode(right).left).left).right).left.nodetype=typeconvn) and
  574. (ttypeconvnode(tcallparanode(tcallparanode(tinlinenode(ttypeconvnode(right).left).left).right).left).convtype=tc_int_2_int) and
  575. are_equal_ints(right.resultdef,ttypeconvnode(tcallparanode(tcallparanode(tinlinenode(ttypeconvnode(right).left).left).right).left).left.resultdef) and
  576. ttypeconvnode(tcallparanode(tcallparanode(tinlinenode(ttypeconvnode(right).left).left).right).left).left.isequal(left) and
  577. is_integer(ttypeconvnode(tcallparanode(tcallparanode(tinlinenode(ttypeconvnode(right).left).left).right).left).left.resultdef) and
  578. ((localswitches*[cs_check_overflow,cs_check_range])=[]) and
  579. ((right.localswitches*[cs_check_overflow,cs_check_range])=[]) and
  580. valid_for_var(ttypeconvnode(tcallparanode(tcallparanode(tinlinenode(ttypeconvnode(right).left).left).right).left).left,false) and
  581. not(might_have_sideeffects(ttypeconvnode(tcallparanode(tcallparanode(tinlinenode(ttypeconvnode(right).left).left).right).left).left)) then
  582. begin
  583. case tinlinenode(ttypeconvnode(right).left).inlinenumber of
  584. in_sar_x_y:
  585. newinlinenodetype:=in_sar_assign_x_y;
  586. in_rol_x_y:
  587. newinlinenodetype:=in_rol_assign_x_y;
  588. in_ror_x_y:
  589. newinlinenodetype:=in_ror_assign_x_y;
  590. else
  591. internalerror(2017072002);
  592. end;
  593. result:=cinlinenode.createintern(
  594. newinlinenodetype,false,ccallparanode.create(
  595. tcallparanode(tinlinenode(ttypeconvnode(right).left).left).left,
  596. ccallparanode.create(ttypeconvnode(tcallparanode(tcallparanode(tinlinenode(ttypeconvnode(right).left).left).right).left).left,nil)));
  597. result.localswitches:=localswitches;
  598. result.fileinfo:=fileinfo;
  599. result.verbosity:=verbosity;
  600. tcallparanode(tinlinenode(ttypeconvnode(right).left).left).left:=nil;
  601. ttypeconvnode(tcallparanode(tcallparanode(tinlinenode(ttypeconvnode(right).left).left).right).left).left:=nil;
  602. exit;
  603. end;
  604. {$endif enable_sar_assign_x_y or enable_rox_assign_x_y}
  605. end;
  606. {$endif llvm}
  607. end;
  608. function try_opt_node(var n: tnode; arg: pointer): foreachnoderesult;
  609. var
  610. hn : tnode;
  611. begin
  612. result:=fen_false;
  613. if n.nodetype=assignn then
  614. begin
  615. hn:=try_opt_assignmentnode(tassignmentnode(n));
  616. if assigned(hn) then
  617. begin
  618. n.free;
  619. n:=hn;
  620. typecheckpass(n);
  621. do_firstpass(n);
  622. end;
  623. end;
  624. end;
  625. procedure do_optloadmodifystore(var rootnode : tnode);
  626. begin
  627. {$ifndef llvm}
  628. foreachnodestatic(pm_postprocess,rootnode,@try_opt_node,nil);
  629. {$endif llvm}
  630. end;
  631. end.