ncgnstld.pas 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197
  1. {
  2. Copyright (c) 2011 by Jonas Maebe
  3. Support for load nodes on targets that have to group all local variables
  4. and parameters accessed by nested routines into structs (and then pass the
  5. address of these structs to nested routines rather than the frame pointer,
  6. and access the local variables as fields thereof)
  7. This program is free software; you can redistribute it and/or modify
  8. it under the terms of the GNU General Public License as published by
  9. the Free Software Foundation; either version 2 of the License, or
  10. (at your option) any later version.
  11. This program is distributed in the hope that it will be useful,
  12. but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. GNU General Public License for more details.
  15. You should have received a copy of the GNU General Public License
  16. along with this program; if not, write to the Free Software
  17. Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  18. ****************************************************************************
  19. }
  20. unit ncgnstld;
  21. {$i fpcdefs.inc}
  22. interface
  23. uses
  24. node,
  25. symtype,
  26. nld,
  27. ncgld;
  28. type
  29. tcgnestloadnode = class(tcgloadnode)
  30. protected
  31. nestsym: tsym;
  32. procedure generate_nested_access(vs: tsym);override;
  33. public
  34. function pass_typecheck: tnode; override;
  35. function pass_1:tnode;override;
  36. function dogetcopy: tnode; override;
  37. function docompare(p: tnode): boolean; override;
  38. end;
  39. implementation
  40. uses
  41. cutils,verbose,globtype,globals,systems,constexp,
  42. symnot,
  43. defutil,defcmp,
  44. htypechk,pass_1,procinfo,paramgr,
  45. cpuinfo,
  46. symconst,symbase,symsym,symdef,symtable,symcreat,
  47. ncon,ninl,ncnv,nmem,ncal,nutils,nbas,
  48. pass_2,cgbase
  49. ;
  50. {*****************************************************************************
  51. TCGNESTLOADNODE
  52. *****************************************************************************}
  53. procedure tcgnestloadnode.generate_nested_access(vs: tsym);
  54. begin
  55. { left has been transformed into a string of accesses that result in
  56. the location of the original variable's copy in the appropriate
  57. parentfpstruct (via tcgnestloadparentfpnode.pass_1). In case it is a
  58. var/out/constref parameter, that "copy" will have been a copy of the
  59. address so the normal handling of such parameters in ncgld is ok) }
  60. secondpass(left);
  61. location:=left.location;
  62. end;
  63. function tcgnestloadnode.pass_typecheck: tnode;
  64. var
  65. nestedvars: tsym;
  66. begin
  67. result:=inherited pass_typecheck;
  68. if assigned(result) then
  69. exit;
  70. case symtableentry.typ of
  71. paravarsym,
  72. localvarsym :
  73. begin
  74. { Nested variable? Then we have to move it to a structure that
  75. can be passed by reference to nested routines }
  76. if assigned(current_procinfo) and
  77. (symtable.symtabletype in [localsymtable,parasymtable]) and
  78. ((symtable.symtablelevel<>current_procinfo.procdef.parast.symtablelevel) or
  79. { also redirect loads of locals/paras that have been moved to
  80. the parentfpstruct inside the routine in which they were
  81. originally declared, except in the initialisation code for
  82. the parentfpstruct (nf_internal flag) }
  83. (tabstractnormalvarsym(symtableentry).inparentfpstruct and
  84. not(nf_internal in flags))) then
  85. begin
  86. { get struct holding all locals accessed by nested routines }
  87. nestedvars:=tprocdef(symtable.defowner).parentfpstruct;
  88. { don't add the parentfpstruct to itself! }
  89. if nestedvars=symtableentry then
  90. exit;
  91. if not assigned(nestedvars) then
  92. begin
  93. { create this struct }
  94. build_parentfpstruct(tprocdef(symtable.defowner));
  95. nestedvars:=tprocdef(symtable.defowner).parentfpstruct;
  96. end;
  97. { store result for use in pass_1 }
  98. nestsym:=maybe_add_sym_to_parentfpstruct(tprocdef(symtableentry.owner.defowner),symtableentry,resultdef,is_addr_param_load);
  99. { left normally holds the parentfp node. If it's not assigned,
  100. this is an access to a local variable/para from the routine
  101. in which it was actually declared -> redirect to its
  102. equivalent in the parentfp struct }
  103. if not assigned(left) then
  104. begin
  105. left:=caddrnode.create_internal(cloadnode.create(tprocdef(symtableentry.owner.defowner).parentfpstruct,tprocdef(symtableentry.owner.defowner).parentfpstruct.owner));
  106. include(left.flags,nf_typedaddr);
  107. end;
  108. typecheckpass(left);
  109. end;
  110. end;
  111. end;
  112. end;
  113. function tcgnestloadnode.pass_1:tnode;
  114. var
  115. thissym,
  116. nestedvars: tsym;
  117. nestedvarsdef: tdef;
  118. begin
  119. result:=inherited;
  120. if assigned(result) then
  121. exit;
  122. case symtableentry.typ of
  123. paravarsym,
  124. localvarsym :
  125. begin
  126. { Nested variable? Then we have to move it to a structure that
  127. can be passed by reference to nested routines }
  128. if assigned(current_procinfo) and
  129. (symtable.symtabletype in [localsymtable,parasymtable]) and
  130. ((symtable.symtablelevel<>current_procinfo.procdef.parast.symtablelevel) or
  131. (tabstractnormalvarsym(symtableentry).inparentfpstruct and
  132. not(nf_internal in flags))) then
  133. begin
  134. { get struct holding all locals accessed by nested routines }
  135. nestedvars:=tprocdef(symtable.defowner).parentfpstruct;
  136. if not assigned(nestedvars) then
  137. begin
  138. { create this struct }
  139. build_parentfpstruct(tprocdef(symtable.defowner));
  140. nestedvars:=tprocdef(symtable.defowner).parentfpstruct;
  141. end;
  142. nestedvarsdef:=tlocalvarsym(nestedvars).vardef;
  143. if nestedvars<>symtableentry then
  144. thissym:=nestsym
  145. else
  146. thissym:=find_sym_in_parentfpstruct(tprocdef(symtableentry.owner.defowner),symtableentry);
  147. if not assigned(thissym) then
  148. internalerror(2011060406);
  149. { firstpass the parentfpnode. This will transform it into
  150. a load of the appropriate parentfpstruct }
  151. if not assigned(left) then
  152. internalerror(2011060104);
  153. firstpass(left);
  154. { subscript it to get the variable }
  155. left:=csubscriptnode.create(thissym,cderefnode.create(left));
  156. firstpass(left);
  157. end;
  158. end;
  159. end;
  160. end;
  161. function tcgnestloadnode.dogetcopy: tnode;
  162. begin
  163. result:=inherited dogetcopy;
  164. tcgnestloadnode(result).nestsym:=nestsym;
  165. end;
  166. function tcgnestloadnode.docompare(p: tnode): boolean;
  167. begin
  168. result:=
  169. inherited docompare(p) and
  170. (tcgnestloadnode(p).nestsym=nestsym);
  171. end;
  172. begin
  173. cloadnode:=tcgnestloadnode;
  174. end.