mirror of
				https://gitlab.com/freepascal.org/fpc/source.git
				synced 2025-10-29 17:45:04 +01:00 
			
		
		
		
	 b50d0aa3d0
			
		
	
	
		b50d0aa3d0
		
	
	
	
	
		
			
			called function, fixes webtbs/tw3742.pp after r21955 (looked at wrong
    testsuite results :/ )
git-svn-id: trunk@21963 -
		
	
			
		
			
				
	
	
		
			1212 lines
		
	
	
		
			41 KiB
		
	
	
	
		
			ObjectPascal
		
	
	
	
	
	
			
		
		
	
	
			1212 lines
		
	
	
		
			41 KiB
		
	
	
	
		
			ObjectPascal
		
	
	
	
	
	
| {
 | |
|     Copyright (c) 2000-2002 by Florian Klaempfl
 | |
| 
 | |
|     This unit implements some basic nodes
 | |
| 
 | |
|     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 nbas;
 | |
| 
 | |
| {$i fpcdefs.inc}
 | |
| 
 | |
| interface
 | |
| 
 | |
|     uses
 | |
|        globtype,
 | |
|        cpuinfo,cpubase,cgbase,cgutils,
 | |
|        aasmbase,aasmtai,aasmdata,aasmcpu,
 | |
|        node,
 | |
|        symtype;
 | |
| 
 | |
|     type
 | |
|        tnothingnode = class(tnode)
 | |
|           constructor create;virtual;
 | |
|           function pass_1 : tnode;override;
 | |
|           function pass_typecheck:tnode;override;
 | |
|        end;
 | |
|        tnothingnodeclass = class of tnothingnode;
 | |
| 
 | |
|        terrornode = class(tnode)
 | |
|           constructor create;virtual;
 | |
|           function pass_1 : tnode;override;
 | |
|           function pass_typecheck:tnode;override;
 | |
|           procedure mark_write;override;
 | |
|        end;
 | |
|        terrornodeclass = class of terrornode;
 | |
| 
 | |
|        tasmnode = class(tnode)
 | |
|           p_asm : TAsmList;
 | |
|           currenttai : tai;
 | |
|           { Used registers in assembler block }
 | |
|           used_regs_int,
 | |
|           used_regs_fpu : tcpuregisterset;
 | |
|           constructor create(p : TAsmList);virtual;
 | |
|           constructor create_get_position;
 | |
|           destructor destroy;override;
 | |
|           constructor ppuload(t:tnodetype;ppufile:tcompilerppufile);override;
 | |
|           procedure ppuwrite(ppufile:tcompilerppufile);override;
 | |
|           procedure buildderefimpl;override;
 | |
|           procedure derefimpl;override;
 | |
|           function dogetcopy : tnode;override;
 | |
|           function pass_1 : tnode;override;
 | |
|           function pass_typecheck:tnode;override;
 | |
|           function docompare(p: tnode): boolean; override;
 | |
|        end;
 | |
|        tasmnodeclass = class of tasmnode;
 | |
| 
 | |
|        tstatementnode = class(tbinarynode)
 | |
|           constructor create(l,r : tnode);virtual;
 | |
|           function simplify(forinline : boolean) : tnode; override;
 | |
|           function pass_1 : tnode;override;
 | |
|           function pass_typecheck:tnode;override;
 | |
|           procedure printnodetree(var t:text);override;
 | |
|           property statement : tnode read left write left;
 | |
|           property next : tnode read right write right;
 | |
|        end;
 | |
|        tstatementnodeclass = class of tstatementnode;
 | |
| 
 | |
|        tblocknode = class(tunarynode)
 | |
|           constructor create(l : tnode);virtual;
 | |
|           destructor destroy; override;
 | |
|           function simplify(forinline : boolean) : tnode; override;
 | |
|           function pass_1 : tnode;override;
 | |
|           function pass_typecheck:tnode;override;
 | |
| {$ifdef state_tracking}
 | |
|           function track_state_pass(exec_known:boolean):boolean;override;
 | |
| {$endif state_tracking}
 | |
|           property statements : tnode read left write left;
 | |
|        end;
 | |
|        tblocknodeclass = class of tblocknode;
 | |
| 
 | |
|        ttempcreatenode = class;
 | |
| 
 | |
|        ttempinfoflag = (
 | |
|          { temp can be kept in a register as far as the original creator is
 | |
|           concerned }
 | |
|          ti_may_be_in_reg,
 | |
|          { the ttempcreatenode has been process and the temp's location is
 | |
|            valid (-> the ttempdeletenode has not yet been processed, or
 | |
|            in case it's a "create_to_normal()" one, the final ttemprefnode
 | |
|            has not yet been processed) }
 | |
|          ti_valid,
 | |
|          { when performing a getcopy of a nodetree, we have to hook up the
 | |
|            copies of ttemprefnodes and ttempdestroynode to the copied
 | |
|            ttempinfo. this is done by setting hookoncopy in the original
 | |
|            ttempinfo to point to the new one. if the temp is deleted via a
 | |
|            regular ttempdeletenode, the hookoncopy is simply set to nil once
 | |
|            it's processed. otherwise, it sets the ti_nextref_set_hookoncopy_nil
 | |
|            and after processing the final ttemprefnode, hookoncopy is set to nil
 | |
|          }
 | |
|          ti_nextref_set_hookoncopy_nil,
 | |
|          { the address of this temp is taken (-> cannot be kept in a register,
 | |
|            even if the creator didn't mind)
 | |
|          }
 | |
|          ti_addr_taken,
 | |
|          { temps can get an extra node tree that contains the value to which
 | |
|            they should be initialised when they are created. this initialisation
 | |
|            has to be performed right before the first reference to the temp.
 | |
|            this flag indicates that the ttempcreatenode has been
 | |
|            processed by pass_generate_code, but that the first ttemprefnode
 | |
|            hasn't yet and hence will have to perform the initialisation
 | |
|          }
 | |
|          ti_executeinitialisation,
 | |
|          { in case an expression like "inc(x[func()],1)" is translated into
 | |
|            a regular addition, you have to create a temp to hold the address
 | |
|            representing x[func()], since otherwise func() will be called twice
 | |
|            and that can spell trouble in case it has side effects. on platforms
 | |
|            without pointers, we cannot just take the address though. this flag
 | |
|            has to be combined with ti_executeinitialisation above and will,
 | |
|            rather than loading the value at the calculated location and store
 | |
|            it in the temp, keep a copy of the calculated location if possible
 | |
|            and required (not possible for regvars, because SSA may change their
 | |
|            register, but not required for them either since calculating their
 | |
|            location has no side-effects
 | |
|          }
 | |
|          ti_reference,
 | |
|          { this temp only allows reading (makes it possible to safely use as
 | |
|            reference under more circumstances)
 | |
|          }
 | |
|          ti_readonly,
 | |
|          { if this is a managed temp, it doesn't have to be finalised before use
 | |
|          }
 | |
|          ti_nofini
 | |
|          );
 | |
|        ttempinfoflags = set of ttempinfoflag;
 | |
| 
 | |
|      const
 | |
|        tempinfostoreflags = [ti_may_be_in_reg,ti_addr_taken,ti_reference,ti_readonly];
 | |
| 
 | |
|      type
 | |
|        { to allow access to the location by temp references even after the temp has }
 | |
|        { already been disposed and to make sure the coherency between temps and     }
 | |
|        { temp references is kept after a getcopy                                    }
 | |
|        ptempinfo = ^ttempinfo;
 | |
|        ttempinfo = record
 | |
|          { set to the copy of a tempcreate pnode (if it gets copied) so that the }
 | |
|          { refs and deletenode can hook to this copy once they get copied too    }
 | |
|          hookoncopy                 : ptempinfo;
 | |
|          typedef                    : tdef;
 | |
|          typedefderef               : tderef;
 | |
|          temptype                   : ttemptype;
 | |
|          owner                      : ttempcreatenode;
 | |
|          withnode                   : tnode;
 | |
|          location                   : tlocation;
 | |
|          flags                      : ttempinfoflags;
 | |
|          tempinitcode               : tnode;
 | |
|        end;
 | |
| 
 | |
|        { a node which will create a (non)persistent temp of a given type with a given  }
 | |
|        { size (the size is separate to allow creating "void" temps with a custom size) }
 | |
|        ttempcreatenode = class(tnode)
 | |
|           size: tcgint;
 | |
|           tempinfo: ptempinfo;
 | |
|           ftemplvalue : tnode;
 | |
|           { * persistent temps are used in manually written code where the temp }
 | |
|           { be usable among different statements and where you can manually say }
 | |
|           { when the temp has to be freed (using a ttempdeletenode)             }
 | |
|           { * non-persistent temps are mostly used in typeconversion helpers,   }
 | |
|           { where the node that receives the temp becomes responsible for       }
 | |
|           { freeing it. In this last case, you must use only one reference      }
 | |
|           { to it and *not* generate a ttempdeletenode                          }
 | |
|           constructor create(_typedef: tdef; _size: tcgint; _temptype: ttemptype;allowreg:boolean); virtual;
 | |
|           constructor create_withnode(_typedef: tdef; _size: tcgint; _temptype: ttemptype; allowreg:boolean; withnode: tnode); virtual;
 | |
|           constructor create_value(_typedef:tdef; _size: tcgint; _temptype: ttemptype;allowreg:boolean; templvalue: tnode);
 | |
|           constructor create_reference(_typedef:tdef; _size: tcgint; _temptype: ttemptype;allowreg:boolean; templvalue: tnode; readonly: boolean);
 | |
|           constructor ppuload(t:tnodetype;ppufile:tcompilerppufile);override;
 | |
|           procedure ppuwrite(ppufile:tcompilerppufile);override;
 | |
|           procedure buildderefimpl;override;
 | |
|           procedure derefimpl;override;
 | |
|           function dogetcopy: tnode; override;
 | |
|           function pass_1 : tnode; override;
 | |
|           function pass_typecheck: tnode; override;
 | |
|           function docompare(p: tnode): boolean; override;
 | |
|           procedure printnodedata(var t:text);override;
 | |
|         end;
 | |
|        ttempcreatenodeclass = class of ttempcreatenode;
 | |
| 
 | |
|         { a node which is a reference to a certain temp }
 | |
|         ttemprefnode = class(tnode)
 | |
|           tempinfo: ptempinfo;
 | |
| 
 | |
|           constructor create(const temp: ttempcreatenode); virtual;
 | |
|           constructor create_offset(const temp: ttempcreatenode;aoffset:longint);
 | |
|           constructor ppuload(t:tnodetype;ppufile:tcompilerppufile);override;
 | |
|           procedure ppuwrite(ppufile:tcompilerppufile);override;
 | |
|           procedure resolveppuidx;override;
 | |
|           function dogetcopy: tnode; override;
 | |
|           function pass_1 : tnode; override;
 | |
|           function pass_typecheck : tnode; override;
 | |
|           procedure mark_write;override;
 | |
|           function docompare(p: tnode): boolean; override;
 | |
|           procedure printnodedata(var t:text);override;
 | |
|          protected
 | |
|           offset : longint;
 | |
|          private
 | |
|           tempidx : longint;
 | |
|         end;
 | |
|        ttemprefnodeclass = class of ttemprefnode;
 | |
| 
 | |
|         { a node which removes a temp }
 | |
|         ttempdeletenode = class(tnode)
 | |
|           tempinfo: ptempinfo;
 | |
|           constructor create(const temp: ttempcreatenode); virtual;
 | |
|           { this will convert the persistant temp to a normal temp
 | |
|             for returning to the other nodes }
 | |
|           constructor create_normal_temp(const temp: ttempcreatenode);
 | |
|           constructor ppuload(t:tnodetype;ppufile:tcompilerppufile);override;
 | |
|           procedure ppuwrite(ppufile:tcompilerppufile);override;
 | |
|           procedure resolveppuidx;override;
 | |
|           function dogetcopy: tnode; override;
 | |
|           function pass_1: tnode; override;
 | |
|           function pass_typecheck: tnode; override;
 | |
|           function docompare(p: tnode): boolean; override;
 | |
|           destructor destroy; override;
 | |
|           procedure printnodedata(var t:text);override;
 | |
|          protected
 | |
|           release_to_normal : boolean;
 | |
|         private
 | |
|           tempidx : longint;
 | |
|         end;
 | |
|        ttempdeletenodeclass = class of ttempdeletenode;
 | |
| 
 | |
|     var
 | |
|        cnothingnode : tnothingnodeclass = tnothingnode;
 | |
|        cerrornode : terrornodeclass = terrornode;
 | |
|        casmnode : tasmnodeclass = tasmnode;
 | |
|        cstatementnode : tstatementnodeclass = tstatementnode;
 | |
|        cblocknode : tblocknodeclass = tblocknode;
 | |
|        ctempcreatenode : ttempcreatenodeclass = ttempcreatenode;
 | |
|        ctemprefnode : ttemprefnodeclass = ttemprefnode;
 | |
|        ctempdeletenode : ttempdeletenodeclass = ttempdeletenode;
 | |
| 
 | |
|        { Create a blocknode and statement node for multiple statements
 | |
|          generated internally by the parser }
 | |
|        function  internalstatements(var laststatement:tstatementnode):tblocknode;
 | |
|        function  laststatement(block:tblocknode):tstatementnode;
 | |
|        procedure addstatement(var laststatement:tstatementnode;n:tnode);
 | |
| 
 | |
|        { if the complexity of n is "high", creates a reference temp to n's
 | |
|          location and replace n with a ttemprefnode referring to that location }
 | |
|        function maybereplacewithtempref(var n: tnode; var block: tblocknode; var stat: tstatementnode; size: ASizeInt; readonly: boolean): ttempcreatenode;
 | |
| 
 | |
| implementation
 | |
| 
 | |
|     uses
 | |
|       cutils,
 | |
|       verbose,globals,systems,
 | |
|       symconst,symdef,defutil,defcmp,
 | |
|       pass_1,
 | |
|       nutils,nld,ncal,nflw,
 | |
|       procinfo
 | |
|       ;
 | |
| 
 | |
| 
 | |
| {*****************************************************************************
 | |
|                                      Helpers
 | |
| *****************************************************************************}
 | |
| 
 | |
|     function internalstatements(var laststatement:tstatementnode):tblocknode;
 | |
|       begin
 | |
|         { create dummy initial statement }
 | |
|         laststatement := cstatementnode.create(cnothingnode.create,nil);
 | |
|         internalstatements := cblocknode.create(laststatement);
 | |
|       end;
 | |
| 
 | |
| 
 | |
|     function laststatement(block:tblocknode):tstatementnode;
 | |
|       begin
 | |
|         result:=tstatementnode(block.left);
 | |
|         while assigned(result) and assigned(result.right) do
 | |
|           result:=tstatementnode(result.right);
 | |
|       end;
 | |
| 
 | |
| 
 | |
|     procedure addstatement(var laststatement:tstatementnode;n:tnode);
 | |
|       begin
 | |
|         if assigned(laststatement.right) then
 | |
|           internalerror(200204201);
 | |
|         laststatement.right:=cstatementnode.create(n,nil);
 | |
|         laststatement:=tstatementnode(laststatement.right);
 | |
|       end;
 | |
| 
 | |
| 
 | |
|     function maybereplacewithtempref(var n: tnode; var block: tblocknode; var stat: tstatementnode; size: ASizeInt; readonly: boolean): ttempcreatenode;
 | |
|       begin
 | |
|         result:=nil;
 | |
|         if node_complexity(n) > 4 then
 | |
|           begin
 | |
|             result:=ctempcreatenode.create_reference(n.resultdef,size,tt_persistent,true,n,readonly);
 | |
|             typecheckpass(tnode(result));
 | |
|             n:=ctemprefnode.create(result);
 | |
|             typecheckpass(n);
 | |
|             if not assigned(stat) then
 | |
|               block:=internalstatements(stat);
 | |
|             addstatement(stat,result)
 | |
|           end;
 | |
|       end;
 | |
| 
 | |
| 
 | |
| 
 | |
| {*****************************************************************************
 | |
|                              TFIRSTNOTHING
 | |
| *****************************************************************************}
 | |
| 
 | |
|     constructor tnothingnode.create;
 | |
|       begin
 | |
|         inherited create(nothingn);
 | |
|       end;
 | |
| 
 | |
| 
 | |
|     function tnothingnode.pass_typecheck:tnode;
 | |
|       begin
 | |
|         result:=nil;
 | |
|         resultdef:=voidtype;
 | |
|       end;
 | |
| 
 | |
| 
 | |
|     function tnothingnode.pass_1 : tnode;
 | |
|       begin
 | |
|         result:=nil;
 | |
|         expectloc:=LOC_VOID;
 | |
|       end;
 | |
| 
 | |
| 
 | |
| {*****************************************************************************
 | |
|                              TFIRSTERROR
 | |
| *****************************************************************************}
 | |
| 
 | |
|     constructor terrornode.create;
 | |
| 
 | |
|       begin
 | |
|          inherited create(errorn);
 | |
|       end;
 | |
| 
 | |
| 
 | |
|     function terrornode.pass_typecheck:tnode;
 | |
|       begin
 | |
|          result:=nil;
 | |
|          include(flags,nf_error);
 | |
|          codegenerror:=true;
 | |
|          resultdef:=generrordef;
 | |
|       end;
 | |
| 
 | |
| 
 | |
|     function terrornode.pass_1 : tnode;
 | |
|       begin
 | |
|          result:=nil;
 | |
|          expectloc:=LOC_VOID;
 | |
|          codegenerror:=true;
 | |
|       end;
 | |
| 
 | |
| 
 | |
|     procedure terrornode.mark_write;
 | |
|       begin
 | |
|       end;
 | |
| 
 | |
| {*****************************************************************************
 | |
|                             TSTATEMENTNODE
 | |
| *****************************************************************************}
 | |
| 
 | |
|     constructor tstatementnode.create(l,r : tnode);
 | |
| 
 | |
|       begin
 | |
|          inherited create(statementn,l,r);
 | |
|       end;
 | |
| 
 | |
| 
 | |
|     function is_exit_statement(var n: tnode; arg: pointer): foreachnoderesult;
 | |
|       begin
 | |
|         if (n.nodetype<>exitn) then
 | |
|           result:=fen_false
 | |
|         else
 | |
|           result:=fen_norecurse_true;
 | |
|       end;
 | |
| 
 | |
| 
 | |
|     function no_exit_statement_in_block(n: tnode): boolean;
 | |
|       begin
 | |
|         result:=not foreachnodestatic(n,@is_exit_statement,nil);
 | |
|       end;
 | |
| 
 | |
| 
 | |
|     function tstatementnode.simplify(forinline: boolean) : tnode;
 | |
|       begin
 | |
|         result:=nil;
 | |
|         { these "optimizations" are only to make it more easy to recognise    }
 | |
|         { blocknodes which at the end of inlining only contain one single     }
 | |
|         { statement. Simplifying inside blocknode.simplify could be dangerous }
 | |
|         { because if the main blocknode which makes up a procedure/function   }
 | |
|         { body were replaced with a statementn/nothingn, this could cause     }
 | |
|         { problems elsewhere in the compiler which expects a blocknode        }
 | |
| 
 | |
|         { remove next statement if it's a nothing-statement (since if it's }
 | |
|         { the last, it won't remove itself -- see next simplification)     }
 | |
|         while assigned(right) and
 | |
|               (tstatementnode(right).left.nodetype = nothingn) do
 | |
|           begin
 | |
|             result:=tstatementnode(right).right;
 | |
|             tstatementnode(right).right:=nil;
 | |
|             right.free;
 | |
|             right:=result;
 | |
|             result:=nil;
 | |
|           end;
 | |
| 
 | |
|         { Remove initial nothingn if there are other statements. If there }
 | |
|         { are no other statements, returning nil doesn't help (will be    }
 | |
|         { interpreted as "can't be simplified") and replacing the         }
 | |
|         { statementnode with a nothingnode cannot be done (because it's   }
 | |
|         { possible this statementnode is a child of a blocknode, and      }
 | |
|         { blocknodes are expected to only contain statementnodes)         }
 | |
|         if (left.nodetype = nothingn) and
 | |
|            assigned(right) then
 | |
|           begin
 | |
|             result:=right;
 | |
|             right:=nil;
 | |
|             exit;
 | |
|           end;
 | |
| 
 | |
|         { if the current statement contains a block with one statement, }
 | |
|         { replace the current statement with that block's statement     }
 | |
|         { (but only if the block does not have nf_block_with_exit set   }
 | |
|         {  or has no exit statement, because otherwise it needs an own  }
 | |
|         {  exit label, see tests/test/tinline10)                        }
 | |
|         if (left.nodetype = blockn) and
 | |
|            (not(nf_block_with_exit in left.flags) or
 | |
|             no_exit_statement_in_block(left)) and
 | |
|            assigned(tblocknode(left).left) and
 | |
|            not assigned(tstatementnode(tblocknode(left).left).right) then
 | |
|           begin
 | |
|             result:=tblocknode(left).left;
 | |
|             tstatementnode(result).right:=right;
 | |
|             right:=nil;
 | |
|             tblocknode(left).left:=nil;
 | |
|             exit;
 | |
|           end;
 | |
|       end;
 | |
| 
 | |
| 
 | |
|     function tstatementnode.pass_typecheck:tnode;
 | |
|       begin
 | |
|          result:=nil;
 | |
|          resultdef:=voidtype;
 | |
| 
 | |
|          { left is the statement itself calln assignn or a complex one }
 | |
|          typecheckpass(left);
 | |
|          if codegenerror then
 | |
|            exit;
 | |
| 
 | |
|          { right is the next statement in the list }
 | |
|          if assigned(right) then
 | |
|            typecheckpass(right);
 | |
|          if codegenerror then
 | |
|            exit;
 | |
|       end;
 | |
| 
 | |
| 
 | |
|     function tstatementnode.pass_1 : tnode;
 | |
|       begin
 | |
|          result:=nil;
 | |
|          { left is the statement itself calln assignn or a complex one }
 | |
|          firstpass(left);
 | |
|          if codegenerror then
 | |
|            exit;
 | |
|          expectloc:=left.expectloc;
 | |
|          { right is the next in the list }
 | |
|          if assigned(right) then
 | |
|            firstpass(right);
 | |
|          if codegenerror then
 | |
|            exit;
 | |
|       end;
 | |
| 
 | |
| 
 | |
|     procedure tstatementnode.printnodetree(var t:text);
 | |
|       begin
 | |
|         printnodelist(t);
 | |
|       end;
 | |
| 
 | |
| {*****************************************************************************
 | |
|                              TBLOCKNODE
 | |
| *****************************************************************************}
 | |
| 
 | |
|     constructor tblocknode.create(l : tnode);
 | |
| 
 | |
|       begin
 | |
|          inherited create(blockn,l);
 | |
|       end;
 | |
| 
 | |
|     destructor tblocknode.destroy;
 | |
| 
 | |
|       var
 | |
|         hp, next: tstatementnode;
 | |
|       begin
 | |
|         hp := tstatementnode(left);
 | |
|         left := nil;
 | |
|         while assigned(hp) do
 | |
|           begin
 | |
|             next := tstatementnode(hp.right);
 | |
|             hp.right := nil;
 | |
|             hp.free;
 | |
|             hp := next;
 | |
|           end;
 | |
|         inherited destroy;
 | |
|       end;
 | |
| 
 | |
| 
 | |
|     function tblocknode.simplify(forinline : boolean): tnode;
 | |
|       begin
 | |
|         result := nil;
 | |
|         { Warning: never replace a blocknode with another node type,      }
 | |
|         {  since the block may be the main block of a procedure/function/ }
 | |
|         {  main program body, and those nodes should always be blocknodes }
 | |
|         {  since that's what the compiler expects elsewhere.              }
 | |
| 
 | |
|         { if the current block contains only one statement, and   }
 | |
|         { this one statement only contains another block, replace }
 | |
|         { this block with that other block.                       }
 | |
|         if assigned(left) and
 | |
|            not assigned(tstatementnode(left).right) and
 | |
|            (tstatementnode(left).left.nodetype = blockn) then
 | |
|           begin
 | |
|             result:=tstatementnode(left).left;
 | |
|             tstatementnode(left).left:=nil;
 | |
|             { make sure the nf_block_with_exit flag is safeguarded }
 | |
|             result.flags:=result.flags+(flags * [nf_block_with_exit]);
 | |
|             exit;
 | |
|           end;
 | |
|       end;
 | |
| 
 | |
| 
 | |
|     function tblocknode.pass_typecheck:tnode;
 | |
|       var
 | |
|          hp : tstatementnode;
 | |
|       begin
 | |
|          result:=nil;
 | |
|          resultdef:=voidtype;
 | |
| 
 | |
|          hp:=tstatementnode(left);
 | |
|          while assigned(hp) do
 | |
|            begin
 | |
|               if assigned(hp.left) then
 | |
|                 begin
 | |
|                    codegenerror:=false;
 | |
|                    typecheckpass(hp.left);
 | |
|                    { the resultdef of the block is the last type that is
 | |
|                      returned. Normally this is a voidtype. But when the
 | |
|                      compiler inserts a block of multiple statements then the
 | |
|                      last entry can return a value }
 | |
|                    resultdef:=hp.left.resultdef;
 | |
|                 end;
 | |
|               hp:=tstatementnode(hp.right);
 | |
|            end;
 | |
|       end;
 | |
| 
 | |
| 
 | |
|     function tblocknode.pass_1 : tnode;
 | |
|       var
 | |
|          hp : tstatementnode;
 | |
|          //count : longint;
 | |
|       begin
 | |
|          result:=nil;
 | |
|          expectloc:=LOC_VOID;
 | |
|          //count:=0;
 | |
|          hp:=tstatementnode(left);
 | |
|          while assigned(hp) do
 | |
|            begin
 | |
|               if assigned(hp.left) then
 | |
|                 begin
 | |
|                    codegenerror:=false;
 | |
|                    firstpass(hp.left);
 | |
|                    hp.expectloc:=hp.left.expectloc;
 | |
|                 end;
 | |
|               expectloc:=hp.expectloc;
 | |
|               //inc(count);
 | |
|               hp:=tstatementnode(hp.right);
 | |
|            end;
 | |
|       end;
 | |
| 
 | |
| {$ifdef state_tracking}
 | |
|       function Tblocknode.track_state_pass(exec_known:boolean):boolean;
 | |
| 
 | |
|       var hp:Tstatementnode;
 | |
| 
 | |
|       begin
 | |
|         track_state_pass:=false;
 | |
|         hp:=Tstatementnode(left);
 | |
|         while assigned(hp) do
 | |
|             begin
 | |
|                 if hp.left.track_state_pass(exec_known) then
 | |
|                     track_state_pass:=true;
 | |
|                 hp:=Tstatementnode(hp.right);
 | |
|             end;
 | |
|       end;
 | |
| {$endif state_tracking}
 | |
| 
 | |
| {*****************************************************************************
 | |
|                              TASMNODE
 | |
| *****************************************************************************}
 | |
| 
 | |
|     constructor tasmnode.create(p : TAsmList);
 | |
|       begin
 | |
|         inherited create(asmn);
 | |
|         p_asm:=p;
 | |
|         currenttai:=nil;
 | |
|         used_regs_int:=[];
 | |
|         used_regs_fpu:=[];
 | |
|       end;
 | |
| 
 | |
| 
 | |
|     constructor tasmnode.create_get_position;
 | |
|       begin
 | |
|         inherited create(asmn);
 | |
|         p_asm:=nil;
 | |
|         include(flags,nf_get_asm_position);
 | |
|         currenttai:=nil;
 | |
|       end;
 | |
| 
 | |
| 
 | |
|     destructor tasmnode.destroy;
 | |
|       begin
 | |
|         if assigned(p_asm) then
 | |
|          p_asm.free;
 | |
|         inherited destroy;
 | |
|       end;
 | |
| 
 | |
| 
 | |
|     constructor tasmnode.ppuload(t:tnodetype;ppufile:tcompilerppufile);
 | |
|       var
 | |
|         hp : tai;
 | |
|       begin
 | |
|         inherited ppuload(t,ppufile);
 | |
|         if not(nf_get_asm_position in flags) then
 | |
|           begin
 | |
|             p_asm:=TAsmList.create;
 | |
|             repeat
 | |
|               hp:=ppuloadai(ppufile);
 | |
|               if hp=nil then
 | |
|                 break;
 | |
|               p_asm.concat(hp);
 | |
|             until false;
 | |
|           end
 | |
|         else
 | |
|           p_asm:=nil;
 | |
|         currenttai:=nil;
 | |
|       end;
 | |
| 
 | |
| 
 | |
|     procedure tasmnode.ppuwrite(ppufile:tcompilerppufile);
 | |
|       var
 | |
|         hp : tai;
 | |
|       begin
 | |
|         inherited ppuwrite(ppufile);
 | |
| { TODO: FIXME Add saving of register sets}
 | |
|         if not(nf_get_asm_position in flags) then
 | |
|           begin
 | |
|             hp:=tai(p_asm.first);
 | |
|             while assigned(hp) do
 | |
|              begin
 | |
|                ppuwriteai(ppufile,hp);
 | |
|                hp:=tai(hp.next);
 | |
|              end;
 | |
|             { end is marked by a nil }
 | |
|             ppuwriteai(ppufile,nil);
 | |
|           end;
 | |
|       end;
 | |
| 
 | |
| 
 | |
|     procedure tasmnode.buildderefimpl;
 | |
|       var
 | |
|         hp : tai;
 | |
|       begin
 | |
|         inherited buildderefimpl;
 | |
|         if not(nf_get_asm_position in flags) then
 | |
|           begin
 | |
|             hp:=tai(p_asm.first);
 | |
|             while assigned(hp) do
 | |
|              begin
 | |
|                hp.buildderefimpl;
 | |
|                hp:=tai(hp.next);
 | |
|              end;
 | |
|           end;
 | |
|       end;
 | |
| 
 | |
| 
 | |
|     procedure tasmnode.derefimpl;
 | |
|       var
 | |
|         hp : tai;
 | |
|       begin
 | |
|         inherited derefimpl;
 | |
|         if not(nf_get_asm_position in flags) then
 | |
|           begin
 | |
|             hp:=tai(p_asm.first);
 | |
|             while assigned(hp) do
 | |
|              begin
 | |
|                hp.derefimpl;
 | |
|                hp:=tai(hp.next);
 | |
|              end;
 | |
|           end;
 | |
|       end;
 | |
| 
 | |
| 
 | |
|     function tasmnode.dogetcopy: tnode;
 | |
|       var
 | |
|         n: tasmnode;
 | |
|       begin
 | |
|         n := tasmnode(inherited dogetcopy);
 | |
|         if assigned(p_asm) then
 | |
|           begin
 | |
|             n.p_asm:=TAsmList.create;
 | |
|             n.p_asm.concatlistcopy(p_asm);
 | |
|           end
 | |
|         else n.p_asm := nil;
 | |
|         n.currenttai:=currenttai;
 | |
|         result:=n;
 | |
|       end;
 | |
| 
 | |
| 
 | |
|     function tasmnode.pass_typecheck:tnode;
 | |
|       begin
 | |
|         result:=nil;
 | |
|         resultdef:=voidtype;
 | |
|         if not(nf_get_asm_position in flags) then
 | |
|           include(current_procinfo.flags,pi_has_assembler_block);
 | |
|       end;
 | |
| 
 | |
| 
 | |
|     function tasmnode.pass_1 : tnode;
 | |
|       begin
 | |
|         result:=nil;
 | |
|         expectloc:=LOC_VOID;
 | |
|       end;
 | |
| 
 | |
| 
 | |
|     function tasmnode.docompare(p: tnode): boolean;
 | |
|       begin
 | |
|         { comparing of asmlists is not implemented (JM) }
 | |
|         docompare := false;
 | |
|       end;
 | |
| 
 | |
| 
 | |
| {*****************************************************************************
 | |
|                           TEMPCREATENODE
 | |
| *****************************************************************************}
 | |
| 
 | |
|     constructor ttempcreatenode.create(_typedef:tdef; _size: tcgint; _temptype: ttemptype;allowreg:boolean);
 | |
|       begin
 | |
|         inherited create(tempcreaten);
 | |
|         size := _size;
 | |
|         new(tempinfo);
 | |
|         fillchar(tempinfo^,sizeof(tempinfo^),0);
 | |
|         tempinfo^.typedef := _typedef;
 | |
|         tempinfo^.temptype := _temptype;
 | |
|         tempinfo^.owner := self;
 | |
|         tempinfo^.withnode := nil;
 | |
|         if allowreg and
 | |
|            { temp must fit a single register }
 | |
|            (tstoreddef(_typedef).is_fpuregable or
 | |
|             (tstoreddef(_typedef).is_intregable and
 | |
|              (_size<=TCGSize2Size[OS_64]))) and
 | |
|            { size of register operations must be known }
 | |
|            (def_cgsize(_typedef)<>OS_NO) and
 | |
|            { no init/final needed }
 | |
|            not is_managed_type(_typedef) then
 | |
|           include(tempinfo^.flags,ti_may_be_in_reg);
 | |
|       end;
 | |
| 
 | |
| 
 | |
|     constructor ttempcreatenode.create_withnode(_typedef: tdef; _size: tcgint; _temptype: ttemptype; allowreg:boolean; withnode: tnode);
 | |
|       begin
 | |
|         self.create(_typedef,_size,_temptype,allowreg);
 | |
|         tempinfo^.withnode:=withnode.getcopy;
 | |
|       end;
 | |
| 
 | |
| 
 | |
|     constructor ttempcreatenode.create_value(_typedef:tdef; _size: tcgint; _temptype: ttemptype;allowreg:boolean; templvalue: tnode);
 | |
|       begin
 | |
|         self.create(_typedef,_size,_temptype,allowreg);
 | |
|         // store in ppuwrite
 | |
|         ftemplvalue:=templvalue;
 | |
|         // create from stored ftemplvalue in ppuload
 | |
|         tempinfo^.tempinitcode:=cassignmentnode.create(ctemprefnode.create(self),ftemplvalue);
 | |
|       end;
 | |
| 
 | |
| 
 | |
|      constructor ttempcreatenode.create_reference(_typedef: tdef; _size: tcgint; _temptype: ttemptype; allowreg: boolean; templvalue: tnode; readonly: boolean);
 | |
|       begin
 | |
|         // store in ppuwrite
 | |
|         self.create(_typedef,_size,_temptype,allowreg);
 | |
|         ftemplvalue:=templvalue;
 | |
|         // no assignment node, just the tempvalue
 | |
|         tempinfo^.tempinitcode:=ftemplvalue;
 | |
|         include(tempinfo^.flags,ti_reference);
 | |
|         if readonly then
 | |
|           include(tempinfo^.flags,ti_readonly);
 | |
|       end;
 | |
| 
 | |
| 
 | |
|     function ttempcreatenode.dogetcopy: tnode;
 | |
|       var
 | |
|         n: ttempcreatenode;
 | |
|       begin
 | |
|         n := ttempcreatenode(inherited dogetcopy);
 | |
|         n.size := size;
 | |
| 
 | |
|         new(n.tempinfo);
 | |
|         fillchar(n.tempinfo^,sizeof(n.tempinfo^),0);
 | |
|         n.tempinfo^.owner:=n;
 | |
|         n.tempinfo^.typedef := tempinfo^.typedef;
 | |
|         n.tempinfo^.temptype := tempinfo^.temptype;
 | |
|         n.tempinfo^.flags := tempinfo^.flags * tempinfostoreflags;
 | |
| 
 | |
|         { when the tempinfo has already a hookoncopy then it is not
 | |
|           reset by a tempdeletenode }
 | |
|         if assigned(tempinfo^.hookoncopy) then
 | |
|           internalerror(200211262);
 | |
|         { signal the temprefs that the temp they point to has been copied, }
 | |
|         { so that if the refs get copied as well, they can hook themselves }
 | |
|         { to the copy of the temp                                          }
 | |
|         tempinfo^.hookoncopy := n.tempinfo;
 | |
|         exclude(tempinfo^.flags,ti_nextref_set_hookoncopy_nil);
 | |
| 
 | |
|         if assigned(tempinfo^.withnode) then
 | |
|           n.tempinfo^.withnode := tempinfo^.withnode.getcopy
 | |
|         else
 | |
|           n.tempinfo^.withnode := nil;
 | |
| 
 | |
|         if assigned(tempinfo^.tempinitcode) then
 | |
|           n.tempinfo^.tempinitcode := tempinfo^.tempinitcode.getcopy
 | |
|         else
 | |
|           n.tempinfo^.tempinitcode := nil;
 | |
| 
 | |
|         result := n;
 | |
|       end;
 | |
| 
 | |
| 
 | |
|     constructor ttempcreatenode.ppuload(t:tnodetype;ppufile:tcompilerppufile);
 | |
|       begin
 | |
|         inherited ppuload(t,ppufile);
 | |
| 
 | |
|         size:=ppufile.getlongint;
 | |
|         new(tempinfo);
 | |
|         fillchar(tempinfo^,sizeof(tempinfo^),0);
 | |
|         ppufile.getsmallset(tempinfo^.flags);
 | |
|         ppufile.getderef(tempinfo^.typedefderef);
 | |
|         tempinfo^.temptype := ttemptype(ppufile.getbyte);
 | |
|         tempinfo^.owner:=self;
 | |
|         tempinfo^.withnode:=ppuloadnode(ppufile);
 | |
|         ftemplvalue:=ppuloadnode(ppufile);
 | |
|       end;
 | |
| 
 | |
| 
 | |
|     procedure ttempcreatenode.ppuwrite(ppufile:tcompilerppufile);
 | |
|       begin
 | |
|         inherited ppuwrite(ppufile);
 | |
|         ppufile.putlongint(size);
 | |
|         ppufile.putsmallset(tempinfo^.flags);
 | |
|         ppufile.putderef(tempinfo^.typedefderef);
 | |
|         ppufile.putbyte(byte(tempinfo^.temptype));
 | |
|         ppuwritenode(ppufile,tempinfo^.withnode);
 | |
|         ppuwritenode(ppufile,ftemplvalue);
 | |
|       end;
 | |
| 
 | |
| 
 | |
|     procedure ttempcreatenode.buildderefimpl;
 | |
|       begin
 | |
|         inherited buildderefimpl;
 | |
|         tempinfo^.typedefderef.build(tempinfo^.typedef);
 | |
|         if assigned(tempinfo^.withnode) then
 | |
|           tempinfo^.withnode.buildderefimpl;
 | |
|         if assigned(ftemplvalue) then
 | |
|           ftemplvalue.buildderefimpl;
 | |
|       end;
 | |
| 
 | |
| 
 | |
|     procedure ttempcreatenode.derefimpl;
 | |
|       begin
 | |
|         inherited derefimpl;
 | |
|         tempinfo^.typedef:=tdef(tempinfo^.typedefderef.resolve);
 | |
|         if assigned(tempinfo^.withnode) then
 | |
|           tempinfo^.withnode.derefimpl;
 | |
|         if assigned(ftemplvalue) then
 | |
|           begin
 | |
|             ftemplvalue.derefimpl;
 | |
|             tempinfo^.tempinitcode:=cassignmentnode.create(ctemprefnode.create(self),ftemplvalue);
 | |
|           end;
 | |
|       end;
 | |
| 
 | |
| 
 | |
|     function ttempcreatenode.pass_1 : tnode;
 | |
|       begin
 | |
|         result := nil;
 | |
|         expectloc:=LOC_VOID;
 | |
|         if (tempinfo^.typedef.needs_inittable) then
 | |
|           include(current_procinfo.flags,pi_needs_implicit_finally);
 | |
|         if assigned(tempinfo^.withnode) then
 | |
|           firstpass(tempinfo^.withnode);
 | |
|         if assigned(tempinfo^.tempinitcode) then
 | |
|           firstpass(tempinfo^.tempinitcode);
 | |
|       end;
 | |
| 
 | |
| 
 | |
|     function ttempcreatenode.pass_typecheck: tnode;
 | |
|       begin
 | |
|         result := nil;
 | |
|         { a tempcreatenode doesn't have a resultdef, only temprefnodes do }
 | |
|         resultdef := voidtype;
 | |
|         if assigned(tempinfo^.withnode) then
 | |
|           typecheckpass(tempinfo^.withnode);
 | |
|         if assigned(tempinfo^.tempinitcode) then
 | |
|           typecheckpass(tempinfo^.tempinitcode);
 | |
|       end;
 | |
| 
 | |
| 
 | |
|     function ttempcreatenode.docompare(p: tnode): boolean;
 | |
|       begin
 | |
|         result :=
 | |
|           inherited docompare(p) and
 | |
|           (ttempcreatenode(p).size = size) and
 | |
|           (ttempcreatenode(p).tempinfo^.flags*tempinfostoreflags=tempinfo^.flags*tempinfostoreflags) and
 | |
|           equal_defs(ttempcreatenode(p).tempinfo^.typedef,tempinfo^.typedef) and
 | |
|           (ttempcreatenode(p).tempinfo^.withnode.isequal(tempinfo^.withnode)) and
 | |
|           (ttempcreatenode(p).tempinfo^.tempinitcode.isequal(tempinfo^.tempinitcode));
 | |
|       end;
 | |
| 
 | |
| 
 | |
|     procedure ttempcreatenode.printnodedata(var t:text);
 | |
|       begin
 | |
|         inherited printnodedata(t);
 | |
|         writeln(t,printnodeindention,'size = ',size,', temptypedef = ',tempinfo^.typedef.typesymbolprettyname,' = "',
 | |
|           tempinfo^.typedef.GetTypeName,'", tempinfo = $',hexstr(ptrint(tempinfo),sizeof(ptrint)*2));
 | |
|       end;
 | |
| 
 | |
| {*****************************************************************************
 | |
|                              TEMPREFNODE
 | |
| *****************************************************************************}
 | |
| 
 | |
|     constructor ttemprefnode.create(const temp: ttempcreatenode);
 | |
|       begin
 | |
|         inherited create(temprefn);
 | |
|         tempinfo := temp.tempinfo;
 | |
|         offset:=0;
 | |
|       end;
 | |
| 
 | |
| 
 | |
|     constructor ttemprefnode.create_offset(const temp: ttempcreatenode;aoffset:longint);
 | |
|       begin
 | |
|         self.create(temp);
 | |
|         offset := aoffset;
 | |
|       end;
 | |
| 
 | |
| 
 | |
|     function ttemprefnode.dogetcopy: tnode;
 | |
|       var
 | |
|         n: ttemprefnode;
 | |
|       begin
 | |
|         n := ttemprefnode(inherited dogetcopy);
 | |
|         n.offset := offset;
 | |
| 
 | |
|         if assigned(tempinfo^.hookoncopy) then
 | |
|           { if the temp has been copied, assume it becomes a new }
 | |
|           { temp which has to be hooked by the copied reference  }
 | |
|           begin
 | |
|             { hook the ref to the copied temp }
 | |
|             n.tempinfo := tempinfo^.hookoncopy;
 | |
|             { if we passed a ttempdeletenode that changed the temp }
 | |
|             { from a persistent one into a normal one, we must be  }
 | |
|             { the last reference (since our parent should free the }
 | |
|             { temp (JM)                                            }
 | |
|             if (ti_nextref_set_hookoncopy_nil in tempinfo^.flags) then
 | |
|               tempinfo^.hookoncopy := nil;
 | |
|           end
 | |
|         else
 | |
|           { if the temp we refer to hasn't been copied, assume }
 | |
|           { we're just a new reference to that temp            }
 | |
|           begin
 | |
|             n.tempinfo := tempinfo;
 | |
|           end;
 | |
| 
 | |
|         if not assigned(n.tempinfo) then
 | |
|           internalerror(2005071901);
 | |
| 
 | |
|         result := n;
 | |
|       end;
 | |
| 
 | |
| 
 | |
|     constructor ttemprefnode.ppuload(t:tnodetype;ppufile:tcompilerppufile);
 | |
|       begin
 | |
|         inherited ppuload(t,ppufile);
 | |
|         tempidx:=ppufile.getlongint;
 | |
|         offset:=ppufile.getlongint;
 | |
|       end;
 | |
| 
 | |
| 
 | |
|     procedure ttemprefnode.ppuwrite(ppufile:tcompilerppufile);
 | |
|       begin
 | |
|         inherited ppuwrite(ppufile);
 | |
|         ppufile.putlongint(tempinfo^.owner.ppuidx);
 | |
|         ppufile.putlongint(offset);
 | |
|       end;
 | |
| 
 | |
| 
 | |
|     procedure ttemprefnode.resolveppuidx;
 | |
|       var
 | |
|         temp : ttempcreatenode;
 | |
|       begin
 | |
|         temp:=ttempcreatenode(nodeppuidxget(tempidx));
 | |
|         if temp.nodetype<>tempcreaten then
 | |
|           internalerror(200311075);
 | |
|         tempinfo:=temp.tempinfo;
 | |
|       end;
 | |
| 
 | |
| 
 | |
|     function ttemprefnode.pass_1 : tnode;
 | |
|       begin
 | |
|         expectloc := LOC_REFERENCE;
 | |
|         if not tempinfo^.typedef.needs_inittable and
 | |
|            (ti_may_be_in_reg in tempinfo^.flags) then
 | |
|           begin
 | |
|             if tempinfo^.typedef.typ=floatdef then
 | |
|               begin
 | |
|                 if not use_vectorfpu(tempinfo^.typedef) then
 | |
|                   if (tempinfo^.temptype = tt_persistent) then
 | |
|                     expectloc := LOC_CFPUREGISTER
 | |
|                   else
 | |
|                     expectloc := LOC_FPUREGISTER
 | |
|                 else
 | |
|                   if (tempinfo^.temptype = tt_persistent) then
 | |
|                     expectloc := LOC_CMMREGISTER
 | |
|                   else
 | |
|                     expectloc := LOC_MMREGISTER
 | |
|               end
 | |
|             else
 | |
|               begin
 | |
|                 if (tempinfo^.temptype = tt_persistent) then
 | |
|                   expectloc := LOC_CREGISTER
 | |
|                 else
 | |
|                   expectloc := LOC_REGISTER;
 | |
|               end;
 | |
|           end;
 | |
|         result := nil;
 | |
|       end;
 | |
| 
 | |
| 
 | |
|     function ttemprefnode.pass_typecheck: tnode;
 | |
|       begin
 | |
|         { check if the temp is already resultdef passed }
 | |
|         if not assigned(tempinfo^.typedef) then
 | |
|           internalerror(200108233);
 | |
|         result := nil;
 | |
|         resultdef := tempinfo^.typedef;
 | |
|       end;
 | |
| 
 | |
| 
 | |
|     function ttemprefnode.docompare(p: tnode): boolean;
 | |
|       begin
 | |
|         result :=
 | |
|           inherited docompare(p) and
 | |
|           (ttemprefnode(p).tempinfo = tempinfo) and
 | |
|           (ttemprefnode(p).offset = offset);
 | |
|       end;
 | |
| 
 | |
| 
 | |
|     procedure ttemprefnode.mark_write;
 | |
| 
 | |
|     begin
 | |
|       include(flags,nf_write);
 | |
|     end;
 | |
| 
 | |
|     procedure ttemprefnode.printnodedata(var t:text);
 | |
|       begin
 | |
|         inherited printnodedata(t);
 | |
|         writeln(t,printnodeindention,'temptypedef = ',tempinfo^.typedef.typesymbolprettyname,' = "',
 | |
|           tempinfo^.typedef.GetTypeName,'", tempinfo = $',hexstr(ptrint(tempinfo),sizeof(ptrint)*2));
 | |
|       end;
 | |
| 
 | |
| 
 | |
| {*****************************************************************************
 | |
|                              TEMPDELETENODE
 | |
| *****************************************************************************}
 | |
| 
 | |
|     constructor ttempdeletenode.create(const temp: ttempcreatenode);
 | |
|       begin
 | |
|         inherited create(tempdeleten);
 | |
|         tempinfo := temp.tempinfo;
 | |
|         release_to_normal := false;
 | |
|       end;
 | |
| 
 | |
| 
 | |
|     constructor ttempdeletenode.create_normal_temp(const temp: ttempcreatenode);
 | |
|       begin
 | |
|         inherited create(tempdeleten);
 | |
|         tempinfo := temp.tempinfo;
 | |
|         release_to_normal := true;
 | |
|         if tempinfo^.temptype <> tt_persistent then
 | |
|           internalerror(200204211);
 | |
|       end;
 | |
| 
 | |
| 
 | |
|     function ttempdeletenode.dogetcopy: tnode;
 | |
|       var
 | |
|         n: ttempdeletenode;
 | |
|       begin
 | |
|         n:=ttempdeletenode(inherited dogetcopy);
 | |
|         n.release_to_normal:=release_to_normal;
 | |
| 
 | |
|         if assigned(tempinfo^.hookoncopy) then
 | |
|           { if the temp has been copied, assume it becomes a new }
 | |
|           { temp which has to be hooked by the copied deletenode }
 | |
|           begin
 | |
|             { hook the tempdeletenode to the copied temp }
 | |
|             n.tempinfo:=tempinfo^.hookoncopy;
 | |
|             { the temp shall not be used, reset hookoncopy    }
 | |
|             { Only if release_to_normal is false, otherwise   }
 | |
|             { the temp can still be referenced once more (JM) }
 | |
|             if (not release_to_normal) then
 | |
|               tempinfo^.hookoncopy:=nil
 | |
|             else
 | |
|               include(tempinfo^.flags,ti_nextref_set_hookoncopy_nil);
 | |
|           end
 | |
|         else
 | |
|           { if the temp we refer to hasn't been copied, we have a }
 | |
|           { problem since that means we now have two delete nodes }
 | |
|           { for one temp                                          }
 | |
|           internalerror(200108234);
 | |
|         result:=n;
 | |
|       end;
 | |
| 
 | |
| 
 | |
|     constructor ttempdeletenode.ppuload(t:tnodetype;ppufile:tcompilerppufile);
 | |
|       begin
 | |
|         inherited ppuload(t,ppufile);
 | |
|         tempidx:=ppufile.getlongint;
 | |
|         release_to_normal:=(ppufile.getbyte<>0);
 | |
|       end;
 | |
| 
 | |
| 
 | |
|     procedure ttempdeletenode.ppuwrite(ppufile:tcompilerppufile);
 | |
|       begin
 | |
|         inherited ppuwrite(ppufile);
 | |
|         ppufile.putlongint(tempinfo^.owner.ppuidx);
 | |
|         ppufile.putbyte(byte(release_to_normal));
 | |
|       end;
 | |
| 
 | |
| 
 | |
|     procedure ttempdeletenode.resolveppuidx;
 | |
|       var
 | |
|         temp : ttempcreatenode;
 | |
|       begin
 | |
|         temp:=ttempcreatenode(nodeppuidxget(tempidx));
 | |
|         if temp.nodetype<>tempcreaten then
 | |
|           internalerror(200311075);
 | |
|         tempinfo:=temp.tempinfo;
 | |
|       end;
 | |
| 
 | |
| 
 | |
|     function ttempdeletenode.pass_1 : tnode;
 | |
|       begin
 | |
|          expectloc:=LOC_VOID;
 | |
|          result := nil;
 | |
|       end;
 | |
| 
 | |
|     function ttempdeletenode.pass_typecheck: tnode;
 | |
|       begin
 | |
|         result := nil;
 | |
|         resultdef := voidtype;
 | |
|       end;
 | |
| 
 | |
|     function ttempdeletenode.docompare(p: tnode): boolean;
 | |
|       begin
 | |
|         result :=
 | |
|           inherited docompare(p) and
 | |
|           (ttemprefnode(p).tempinfo = tempinfo);
 | |
|       end;
 | |
| 
 | |
|     destructor ttempdeletenode.destroy;
 | |
|       begin
 | |
|         tempinfo^.withnode.free;
 | |
|         tempinfo^.tempinitcode.free;
 | |
|         dispose(tempinfo);
 | |
|       end;
 | |
| 
 | |
|     procedure ttempdeletenode.printnodedata(var t:text);
 | |
|       begin
 | |
|         inherited printnodedata(t);
 | |
|         writeln(t,printnodeindention,'release_to_normal: ',release_to_normal,', temptypedef = ',tempinfo^.typedef.typesymbolprettyname,' = "',
 | |
|           tempinfo^.typedef.GetTypeName,'", temptype = ',tempinfo^.temptype,', tempinfo = $',hexstr(ptrint(tempinfo),sizeof(ptrint)*2));
 | |
|       end;
 | |
| 
 | |
| end.
 |