123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240 |
- {
- 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,
- defutil,defcmp,
- htypechk,pass_1,procinfo,paramgr,
- cpuinfo,
- symconst,symbase,symsym,symdef,symtable,pparautl,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) or
- (assigned(current_procinfo) and
- (df_generic in current_procinfo.procdef.defoptions)) 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(taddrnode(left).addrnodeflags,anf_typedaddr);
- end;
- typecheckpass(left);
- end;
- end;
- else
- ;
- end;
- end;
- function tcgnestloadnode.pass_1:tnode;
- var
- thissym,
- nestedvars: tsym;
- 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(left) 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;
- 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);
- if left.resultdef.typ<>pointerdef then
- internalerror(2015122801);
- { subscript it to get the variable }
- left:=csubscriptnode.create(thissym,cderefnode.create(left));
- firstpass(left);
- include(flags,nf_internal);
- end;
- end;
- else
- ;
- 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.
|