ncgnstld.pas 8.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240
  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. nestsymderef: tderef;
  33. procedure generate_nested_access(vs: tsym);override;
  34. function keep_param_address_in_nested_struct: boolean; virtual;
  35. public
  36. function pass_typecheck: tnode; override;
  37. function pass_1:tnode;override;
  38. function dogetcopy: tnode; override;
  39. function docompare(p: tnode): boolean; override;
  40. constructor ppuload(t: tnodetype; ppufile: tcompilerppufile); override;
  41. procedure ppuwrite(ppufile: tcompilerppufile); override;
  42. procedure buildderefimpl; override;
  43. procedure derefimpl; override;
  44. end;
  45. implementation
  46. uses
  47. cutils,verbose,globtype,globals,systems,constexp,
  48. defutil,defcmp,
  49. htypechk,pass_1,procinfo,paramgr,
  50. cpuinfo,
  51. symconst,symbase,symsym,symdef,symtable,pparautl,symcreat,
  52. ncon,ninl,ncnv,nmem,ncal,nutils,nbas,
  53. pass_2,cgbase
  54. ;
  55. {*****************************************************************************
  56. TCGNESTLOADNODE
  57. *****************************************************************************}
  58. procedure tcgnestloadnode.generate_nested_access(vs: tsym);
  59. begin
  60. { left has been transformed into a string of accesses that result in
  61. the location of the original variable's copy in the appropriate
  62. parentfpstruct (via tcgnestloadparentfpnode.pass_1). In case it is a
  63. var/out/constref parameter, that "copy" will have been a copy of the
  64. address so the normal handling of such parameters in ncgld is ok) }
  65. secondpass(left);
  66. location:=left.location;
  67. end;
  68. function tcgnestloadnode.keep_param_address_in_nested_struct: boolean;
  69. begin
  70. result:=is_addr_param_load;
  71. end;
  72. function tcgnestloadnode.pass_typecheck: tnode;
  73. var
  74. nestedvars: tsym;
  75. begin
  76. result:=inherited pass_typecheck;
  77. if assigned(result) or
  78. (assigned(current_procinfo) and
  79. (df_generic in current_procinfo.procdef.defoptions)) then
  80. exit;
  81. case symtableentry.typ of
  82. paravarsym,
  83. localvarsym :
  84. begin
  85. { Nested variable? Then we have to move it to a structure that
  86. can be passed by reference to nested routines }
  87. if assigned(current_procinfo) and
  88. (symtable.symtabletype in [localsymtable,parasymtable]) and
  89. ((symtable.symtablelevel<>current_procinfo.procdef.parast.symtablelevel) or
  90. { also redirect loads of locals/paras that have been moved to
  91. the parentfpstruct inside the routine in which they were
  92. originally declared, except in the initialisation code for
  93. the parentfpstruct (nf_internal flag) }
  94. tabstractnormalvarsym(symtableentry).inparentfpstruct) and
  95. not(nf_internal in flags) then
  96. begin
  97. { get struct holding all locals accessed by nested routines }
  98. nestedvars:=tprocdef(symtable.defowner).parentfpstruct;
  99. { don't add the parentfpstruct to itself! }
  100. if nestedvars=symtableentry then
  101. exit;
  102. if not assigned(nestedvars) then
  103. begin
  104. { create this struct }
  105. build_parentfpstruct(tprocdef(symtable.defowner));
  106. nestedvars:=tprocdef(symtable.defowner).parentfpstruct;
  107. end;
  108. { store result for use in pass_1 }
  109. nestsym:=maybe_add_sym_to_parentfpstruct(tprocdef(symtableentry.owner.defowner),symtableentry,resultdef,keep_param_address_in_nested_struct);
  110. { left normally holds the parentfp node. If it's not assigned,
  111. this is an access to a local variable/para from the routine
  112. in which it was actually declared -> redirect to its
  113. equivalent in the parentfp struct }
  114. if not assigned(left) then
  115. begin
  116. left:=caddrnode.create_internal(cloadnode.create(tprocdef(symtableentry.owner.defowner).parentfpstruct,tprocdef(symtableentry.owner.defowner).parentfpstruct.owner));
  117. include(taddrnode(left).addrnodeflags,anf_typedaddr);
  118. end;
  119. typecheckpass(left);
  120. end;
  121. end;
  122. else
  123. ;
  124. end;
  125. end;
  126. function tcgnestloadnode.pass_1:tnode;
  127. var
  128. thissym,
  129. nestedvars: tsym;
  130. begin
  131. result:=inherited;
  132. if assigned(result) then
  133. exit;
  134. case symtableentry.typ of
  135. paravarsym,
  136. localvarsym :
  137. begin
  138. { Nested variable? Then we have to move it to a structure that
  139. can be passed by reference to nested routines }
  140. if assigned(left) and
  141. not(nf_internal in flags) then
  142. begin
  143. { get struct holding all locals accessed by nested routines }
  144. nestedvars:=tprocdef(symtable.defowner).parentfpstruct;
  145. if not assigned(nestedvars) then
  146. begin
  147. { create this struct }
  148. build_parentfpstruct(tprocdef(symtable.defowner));
  149. nestedvars:=tprocdef(symtable.defowner).parentfpstruct;
  150. end;
  151. if nestedvars<>symtableentry then
  152. thissym:=nestsym
  153. else
  154. thissym:=find_sym_in_parentfpstruct(tprocdef(symtableentry.owner.defowner),symtableentry);
  155. if not assigned(thissym) then
  156. internalerror(2011060406);
  157. { firstpass the parentfpnode. This will transform it into
  158. a load of the appropriate parentfpstruct }
  159. if not assigned(left) then
  160. internalerror(2011060104);
  161. firstpass(left);
  162. if left.resultdef.typ<>pointerdef then
  163. internalerror(2015122801);
  164. { subscript it to get the variable }
  165. left:=csubscriptnode.create(thissym,cderefnode.create(left));
  166. firstpass(left);
  167. include(flags,nf_internal);
  168. end;
  169. end;
  170. else
  171. ;
  172. end;
  173. end;
  174. function tcgnestloadnode.dogetcopy: tnode;
  175. begin
  176. result:=inherited dogetcopy;
  177. tcgnestloadnode(result).nestsym:=nestsym;
  178. end;
  179. function tcgnestloadnode.docompare(p: tnode): boolean;
  180. begin
  181. result:=
  182. inherited docompare(p) and
  183. (tcgnestloadnode(p).nestsym=nestsym);
  184. end;
  185. constructor tcgnestloadnode.ppuload(t: tnodetype; ppufile: tcompilerppufile);
  186. begin
  187. inherited ppuload(t, ppufile);
  188. ppufile.getderef(nestsymderef);
  189. end;
  190. procedure tcgnestloadnode.ppuwrite(ppufile: tcompilerppufile);
  191. begin
  192. inherited ppuwrite(ppufile);
  193. ppufile.putderef(nestsymderef);
  194. end;
  195. procedure tcgnestloadnode.buildderefimpl;
  196. begin
  197. inherited buildderefimpl;
  198. nestsymderef.build(nestsym);
  199. end;
  200. procedure tcgnestloadnode.derefimpl;
  201. begin
  202. inherited derefimpl;
  203. nestsym:=tsym(nestsymderef.resolve);
  204. end;
  205. begin
  206. cloadnode:=tcgnestloadnode;
  207. end.