mirror of
				https://gitlab.com/freepascal.org/fpc/source.git
				synced 2025-10-31 20:31:51 +01:00 
			
		
		
		
	 4dee36b64b
			
		
	
	
		4dee36b64b
		
	
	
	
	
		
			
			implicit pointer types into the nestedfpstruct, so that the original
    parameter is properly changed when updated from inside nested routines
git-svn-id: branches/jvmbackend@19645 -
		
	
			
		
			
				
	
	
		
			238 lines
		
	
	
		
			8.7 KiB
		
	
	
	
		
			ObjectPascal
		
	
	
	
	
	
			
		
		
	
	
			238 lines
		
	
	
		
			8.7 KiB
		
	
	
	
		
			ObjectPascal
		
	
	
	
	
	
| {
 | |
|     Copyright (c) 2011 by Jonas Maebe
 | |
| 
 | |
|     Support for load nodes on targets that have to group all local variables
 | |
|     and parameters accessed by nested routines into structs (and then pass the
 | |
|     address of these structs to nested routines rather than the frame pointer,
 | |
|     and access the local variables as fields thereof)
 | |
| 
 | |
|     This program is free software; you can redistribute it and/or modify
 | |
|     it under the terms of the GNU General Public License as published by
 | |
|     the Free Software Foundation; either version 2 of the License, or
 | |
|     (at your option) any later version.
 | |
| 
 | |
|     This program is distributed in the hope that it will be useful,
 | |
|     but WITHOUT ANY WARRANTY; without even the implied warranty of
 | |
|     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | |
|     GNU General Public License for more details.
 | |
| 
 | |
|     You should have received a copy of the GNU General Public License
 | |
|     along with this program; if not, write to the Free Software
 | |
|     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 | |
| 
 | |
|  ****************************************************************************
 | |
| }
 | |
| unit ncgnstld;
 | |
| 
 | |
| {$i fpcdefs.inc}
 | |
| 
 | |
| interface
 | |
| 
 | |
|     uses
 | |
|        node,
 | |
|        symtype,
 | |
|        nld,
 | |
|        ncgld;
 | |
| 
 | |
|     type
 | |
|        tcgnestloadnode = class(tcgloadnode)
 | |
|         protected
 | |
|          nestsym: tsym;
 | |
|          nestsymderef: tderef;
 | |
|          procedure generate_nested_access(vs: tsym);override;
 | |
|          function  keep_param_address_in_nested_struct: boolean; virtual;
 | |
|         public
 | |
|          function  pass_typecheck: tnode; override;
 | |
|          function  pass_1:tnode;override;
 | |
|          function  dogetcopy: tnode; override;
 | |
|          function  docompare(p: tnode): boolean; override;
 | |
|          constructor ppuload(t: tnodetype; ppufile: tcompilerppufile); override;
 | |
|          procedure ppuwrite(ppufile: tcompilerppufile); override;
 | |
|          procedure buildderefimpl; override;
 | |
|          procedure derefimpl; override;
 | |
|        end;
 | |
| 
 | |
| implementation
 | |
| 
 | |
|     uses
 | |
|       cutils,verbose,globtype,globals,systems,constexp,
 | |
|       symnot,
 | |
|       defutil,defcmp,
 | |
|       htypechk,pass_1,procinfo,paramgr,
 | |
|       cpuinfo,
 | |
|       symconst,symbase,symsym,symdef,symtable,symcreat,
 | |
|       ncon,ninl,ncnv,nmem,ncal,nutils,nbas,
 | |
|       pass_2,cgbase
 | |
|       ;
 | |
| 
 | |
| {*****************************************************************************
 | |
|                           TCGNESTLOADNODE
 | |
| *****************************************************************************}
 | |
| 
 | |
|     procedure tcgnestloadnode.generate_nested_access(vs: tsym);
 | |
|       begin
 | |
|         { left has been transformed into a string of accesses that result in
 | |
|           the location of the original variable's copy in the appropriate
 | |
|           parentfpstruct (via tcgnestloadparentfpnode.pass_1). In case it is a
 | |
|           var/out/constref parameter, that "copy" will have been a copy of the
 | |
|           address so the normal handling of such parameters in ncgld is ok) }
 | |
|         secondpass(left);
 | |
|         location:=left.location;
 | |
|       end;
 | |
| 
 | |
| 
 | |
|     function tcgnestloadnode.keep_param_address_in_nested_struct: boolean;
 | |
|       begin
 | |
|         result:=is_addr_param_load;
 | |
|       end;
 | |
| 
 | |
| 
 | |
|     function tcgnestloadnode.pass_typecheck: tnode;
 | |
|       var
 | |
|         nestedvars: tsym;
 | |
|       begin
 | |
|         result:=inherited pass_typecheck;
 | |
|         if assigned(result) then
 | |
|           exit;
 | |
|         case symtableentry.typ of
 | |
|           paravarsym,
 | |
|           localvarsym :
 | |
|             begin
 | |
|               { Nested variable? Then we have to move it to a structure that
 | |
|                 can be passed by reference to nested routines }
 | |
|               if assigned(current_procinfo) and
 | |
|                  (symtable.symtabletype in [localsymtable,parasymtable]) and
 | |
|                  ((symtable.symtablelevel<>current_procinfo.procdef.parast.symtablelevel) or
 | |
|                   { also redirect loads of locals/paras that have been moved to
 | |
|                      the parentfpstruct inside the routine in which they were
 | |
|                      originally declared, except in the initialisation code for
 | |
|                      the parentfpstruct (nf_internal flag) }
 | |
|                   (tabstractnormalvarsym(symtableentry).inparentfpstruct and
 | |
|                    not(nf_internal in flags))) then
 | |
|                 begin
 | |
|                   { get struct holding all locals accessed by nested routines }
 | |
|                   nestedvars:=tprocdef(symtable.defowner).parentfpstruct;
 | |
|                   { don't add the parentfpstruct to itself! }
 | |
|                   if nestedvars=symtableentry then
 | |
|                     exit;
 | |
|                   if not assigned(nestedvars) then
 | |
|                     begin
 | |
|                       { create this struct }
 | |
|                       build_parentfpstruct(tprocdef(symtable.defowner));
 | |
|                       nestedvars:=tprocdef(symtable.defowner).parentfpstruct;
 | |
|                     end;
 | |
|                   {  store result for use in pass_1 }
 | |
|                   nestsym:=maybe_add_sym_to_parentfpstruct(tprocdef(symtableentry.owner.defowner),symtableentry,resultdef,keep_param_address_in_nested_struct);
 | |
|                   { left normally holds the parentfp node. If it's not assigned,
 | |
|                     this is an access to a local variable/para from the routine
 | |
|                     in which it was actually declared -> redirect to its
 | |
|                     equivalent in the parentfp struct }
 | |
|                   if not assigned(left) then
 | |
|                     begin
 | |
|                       left:=caddrnode.create_internal(cloadnode.create(tprocdef(symtableentry.owner.defowner).parentfpstruct,tprocdef(symtableentry.owner.defowner).parentfpstruct.owner));
 | |
|                       include(left.flags,nf_typedaddr);
 | |
|                     end;
 | |
|                   typecheckpass(left);
 | |
|                 end;
 | |
|             end;
 | |
|         end;
 | |
|       end;
 | |
| 
 | |
| 
 | |
|     function tcgnestloadnode.pass_1:tnode;
 | |
|       var
 | |
|         thissym,
 | |
|         nestedvars: tsym;
 | |
|         nestedvarsdef: tdef;
 | |
|       begin
 | |
|         result:=inherited;
 | |
|         if assigned(result) then
 | |
|           exit;
 | |
|         case symtableentry.typ of
 | |
|           paravarsym,
 | |
|           localvarsym :
 | |
|             begin
 | |
|               { Nested variable? Then we have to move it to a structure that
 | |
|                 can be passed by reference to nested routines }
 | |
|               if assigned(current_procinfo) and
 | |
|                  (symtable.symtabletype in [localsymtable,parasymtable]) and
 | |
|                  ((symtable.symtablelevel<>current_procinfo.procdef.parast.symtablelevel) or
 | |
|                   (tabstractnormalvarsym(symtableentry).inparentfpstruct and
 | |
|                    not(nf_internal in flags))) then
 | |
|                 begin
 | |
|                   { get struct holding all locals accessed by nested routines }
 | |
|                   nestedvars:=tprocdef(symtable.defowner).parentfpstruct;
 | |
|                   if not assigned(nestedvars) then
 | |
|                     begin
 | |
|                       { create this struct }
 | |
|                       build_parentfpstruct(tprocdef(symtable.defowner));
 | |
|                       nestedvars:=tprocdef(symtable.defowner).parentfpstruct;
 | |
|                     end;
 | |
|                   nestedvarsdef:=tlocalvarsym(nestedvars).vardef;
 | |
|                   if nestedvars<>symtableentry then
 | |
|                     thissym:=nestsym
 | |
|                   else
 | |
|                     thissym:=find_sym_in_parentfpstruct(tprocdef(symtableentry.owner.defowner),symtableentry);
 | |
|                   if not assigned(thissym) then
 | |
|                     internalerror(2011060406);
 | |
|                   { firstpass the parentfpnode. This will transform it into
 | |
|                     a load of the appropriate parentfpstruct }
 | |
|                   if not assigned(left) then
 | |
|                     internalerror(2011060104);
 | |
|                   firstpass(left);
 | |
|                   { subscript it to get the variable }
 | |
|                   left:=csubscriptnode.create(thissym,cderefnode.create(left));
 | |
|                   firstpass(left);
 | |
|                  end;
 | |
|             end;
 | |
|         end;
 | |
|       end;
 | |
| 
 | |
| 
 | |
|     function tcgnestloadnode.dogetcopy: tnode;
 | |
|       begin
 | |
|         result:=inherited dogetcopy;
 | |
|         tcgnestloadnode(result).nestsym:=nestsym;
 | |
|       end;
 | |
| 
 | |
| 
 | |
|     function tcgnestloadnode.docompare(p: tnode): boolean;
 | |
|       begin
 | |
|         result:=
 | |
|           inherited docompare(p) and
 | |
|           (tcgnestloadnode(p).nestsym=nestsym);
 | |
|       end;
 | |
| 
 | |
| 
 | |
|     constructor tcgnestloadnode.ppuload(t: tnodetype; ppufile: tcompilerppufile);
 | |
|       begin
 | |
|         inherited ppuload(t, ppufile);
 | |
|         ppufile.getderef(nestsymderef);
 | |
|       end;
 | |
| 
 | |
| 
 | |
|     procedure tcgnestloadnode.ppuwrite(ppufile: tcompilerppufile);
 | |
|       begin
 | |
|         inherited ppuwrite(ppufile);
 | |
|         ppufile.putderef(nestsymderef);
 | |
|       end;
 | |
| 
 | |
| 
 | |
|     procedure tcgnestloadnode.buildderefimpl;
 | |
|       begin
 | |
|         inherited buildderefimpl;
 | |
|         nestsymderef.build(nestsym);
 | |
|       end;
 | |
| 
 | |
| 
 | |
|     procedure tcgnestloadnode.derefimpl;
 | |
|       begin
 | |
|         inherited derefimpl;
 | |
|         nestsym:=tsym(nestsymderef.resolve);
 | |
|       end;
 | |
| 
 | |
| 
 | |
| begin
 | |
|   cloadnode:=tcgnestloadnode;
 | |
| end.
 |