opttree.pas 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227
  1. {
  2. General tree transformations
  3. Copyright (c) 2013 by Florian Klaempfl
  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. { $define DEBUG_NORMALIZE}
  18. { this unit implements routines to perform all-purpose tree transformations }
  19. unit opttree;
  20. {$i fpcdefs.inc}
  21. interface
  22. uses
  23. node,optutils;
  24. { tries to bring the tree in a normalized form:
  25. - expressions are free of control statements
  26. - callinitblock/callcleanupblocks are converted into statements
  27. rationale is that this simplifies data flow analysis
  28. returns true, if this was successful
  29. }
  30. function normalize(var n : tnode) : Boolean;
  31. implementation
  32. uses
  33. verbose,
  34. globtype,
  35. defutil,
  36. nbas,nld,ncal,
  37. nutils,
  38. pass_1;
  39. function searchstatements(var n : tnode;arg : pointer) : foreachnoderesult;forward;
  40. function hasblock(var n : tnode;arg : pointer) : foreachnoderesult;
  41. begin
  42. result:=fen_false;
  43. if n.nodetype=blockn then
  44. result:=fen_norecurse_true;
  45. end;
  46. function searchblock(var n : tnode;arg : pointer) : foreachnoderesult;
  47. var
  48. hp,
  49. statements,
  50. stmnt : tstatementnode;
  51. res : pnode;
  52. tempcreatenode : ttempcreatenode;
  53. newblock : tnode;
  54. begin
  55. result:=fen_true;
  56. if n.nodetype in [addn,orn] then
  57. begin
  58. { so far we cannot fiddle with short boolean evaluations containing blocks }
  59. if doshortbooleval(n) and foreachnodestatic(n,@hasblock,nil) then
  60. begin
  61. result:=fen_norecurse_false;
  62. exit;
  63. end;
  64. end;
  65. case n.nodetype of
  66. calln:
  67. begin
  68. if assigned(tcallnode(n).callinitblock) then
  69. begin
  70. { create a new statement node and insert it }
  71. hp:=cstatementnode.create(tcallnode(n).callinitblock,pnode(arg)^);
  72. pnode(arg)^:=hp;
  73. { tree moved }
  74. tcallnode(n).callinitblock:=nil;
  75. { process the newly generated block }
  76. foreachnodestatic(pnode(arg)^,@searchstatements,nil);
  77. end;
  78. if assigned(tcallnode(n).callcleanupblock) then
  79. begin
  80. { create a new statement node and append it }
  81. hp:=cstatementnode.create(tcallnode(n).callcleanupblock,tstatementnode(pnode(arg)^).right);
  82. tstatementnode(pnode(arg)^).right:=hp;
  83. { tree moved }
  84. tcallnode(n).callcleanupblock:=nil;
  85. { process the newly generated block }
  86. foreachnodestatic(tstatementnode(pnode(arg)^).right,@searchstatements,nil);
  87. end;
  88. end;
  89. blockn:
  90. begin
  91. if assigned(tblocknode(n).left) and (tblocknode(n).left.nodetype<>statementn) then
  92. internalerror(2013120502);
  93. stmnt:=tstatementnode(tblocknode(n).left);
  94. { search for the result of the block node }
  95. if assigned(stmnt) then
  96. begin
  97. res:=nil;
  98. hp:=tstatementnode(stmnt);
  99. while assigned(hp) do
  100. begin
  101. if assigned(hp.left) then
  102. res:[email protected];
  103. hp:=tstatementnode(hp.right);
  104. end;
  105. { did we find a last node? }
  106. if assigned(res^) then
  107. begin
  108. case res^.nodetype of
  109. ordconstn,
  110. realconstn,
  111. stringconstn,
  112. pointerconstn,
  113. setconstn,
  114. temprefn:
  115. begin
  116. { create a new statement node and insert it }
  117. hp:=cstatementnode.create(n,pnode(arg)^);
  118. pnode(arg)^:=hp;
  119. { use the result node instead of the block node }
  120. n:=res^;
  121. { the old statement is not used anymore }
  122. res^:=cnothingnode.create;
  123. { process the newly generated statement }
  124. foreachnodestatic(pnode(arg)^,@searchstatements,nil);
  125. end
  126. else if assigned(res^.resultdef) and not(is_void(res^.resultdef)) then
  127. begin
  128. { replace the last node of the block by an assignment to a temp, and move the block out
  129. of the expression }
  130. newblock:=internalstatements(statements);
  131. tempcreatenode:=ctempcreatenode.create(res^.resultdef,res^.resultdef.size,tt_persistent,true);
  132. addstatement(statements,tempcreatenode);
  133. addstatement(statements,n);
  134. { replace the old result node of the block by an assignement to the newly generated temp }
  135. res^:=cassignmentnode.create_internal(ctemprefnode.create(tempcreatenode),res^);
  136. do_firstpass(res^);
  137. addstatement(statements,ctempdeletenode.create_normal_temp(tempcreatenode));
  138. addstatement(statements,pnode(arg)^);
  139. { use the temp. ref instead of the block node }
  140. n:=ctemprefnode.create(tempcreatenode);
  141. { replace the statement with the block }
  142. pnode(arg)^:=newblock;
  143. { first pass the newly generated block }
  144. do_firstpass(newblock);
  145. { ... and the inserted temp. }
  146. do_firstpass(n);
  147. { process the newly generated block }
  148. foreachnodestatic(pnode(arg)^,@searchstatements,nil);
  149. end;
  150. end;
  151. end;
  152. end;
  153. end;
  154. else
  155. ;
  156. end;
  157. end;
  158. var
  159. searchstatementsproc : staticforeachnodefunction;
  160. function searchstatements(var n : tnode;arg : pointer) : foreachnoderesult;
  161. begin
  162. if n.nodetype=statementn then
  163. begin
  164. if not(foreachnodestatic(tstatementnode(n).left,@searchblock,@n)) then
  165. begin
  166. pboolean(arg)^:=false;
  167. result:=fen_norecurse_false;
  168. exit;
  169. end;
  170. { do not recurse automatically, but continue with the next statement }
  171. result:=fen_norecurse_false;
  172. foreachnodestatic(tstatementnode(n).right,searchstatementsproc,arg);
  173. end
  174. else
  175. result:=fen_false;
  176. end;
  177. function normalize(var n: tnode) : Boolean;
  178. var
  179. success : Boolean;
  180. begin
  181. success:=true;
  182. {$ifdef DEBUG_NORMALIZE}
  183. writeln('******************************************** Before ********************************************');
  184. printnode(n);
  185. {$endif DEBUG_NORMALIZE}
  186. searchstatementsproc:=@searchstatements;
  187. foreachnodestatic(n,@searchstatements,@success);
  188. {$ifdef DEBUG_NORMALIZE}
  189. if success then
  190. begin
  191. writeln('******************************************** After ********************************************');
  192. printnode(n);
  193. end
  194. else
  195. writeln('************************* Normalization not possible ********************************');
  196. {$endif DEBUG_NORMALIZE}
  197. Result:=success;
  198. end;
  199. end.