fpc/compiler/nflw.pas
Jonas Maebe c13ff3729b * Merged 2.3 branch changes:
+ darwin/ppc64 support
    + val/str/read(ln)/write(ln) support for enums
    + simple cse at the node tree level
    + if-node simplify support
    + simple ssa support for memory locations
    + support for optional overflow/rangecheck boolean parameters for
      operators
    * a lot of unification of the ppc32/ppc64 code generators


........
r6380 | jonas | 2007-02-08 21:25:36 +0100 (Thu, 08 Feb 2007) | 4 lines
Changed paths:
   M /branches/fpc_2_3/compiler/ncgld.pas
   M /branches/fpc_2_3/compiler/tgobj.pas
   A /branches/fpc_2_3/tests/webtbs/tw8283.pp

  + support for replacing the memory location of a temp (including
    local variables) with that of another temp to avoid unnecessary
    copies (mantis #8283)

........
r6381 | jonas | 2007-02-08 22:53:36 +0100 (Thu, 08 Feb 2007) | 2 lines
Changed paths:
   M /branches/fpc_2_3/compiler/nflw.pas
   A /branches/fpc_2_3/tests/webtbs/tw8282.pp

  + simplify support for ifn (based on patch by Florian)

........
r6386 | peter | 2007-02-09 13:48:53 +0100 (Fri, 09 Feb 2007) | 2 lines
Changed paths:
   M /branches/fpc_2_3/compiler/htypechk.pas
   M /branches/fpc_2_3/compiler/ncal.pas
   M /branches/fpc_2_3/compiler/symconst.pas

  * overflow,rangecheck optional parameters for operators, patch from 8281

........
r6391 | jonas | 2007-02-09 23:52:13 +0100 (Fri, 09 Feb 2007) | 4 lines
Changed paths:
   M /branches/fpc_2_3/compiler/powerpc/agppcgas.pas
   M /branches/fpc_2_3/compiler/powerpc64/cpunode.pas
   D /branches/fpc_2_3/compiler/powerpc64/nppcinl.pas
   M /branches/fpc_2_3/compiler/ppcgen/ngppcinl.pas

  * merged fsqrt(s) support to common powerpc unit, activate for ppc32
    if -Op970 is used (still default for ppc64, since default cpu there
    is already ppc970)

........
r6394 | jonas | 2007-02-10 18:58:47 +0100 (Sat, 10 Feb 2007) | 4 lines
Changed paths:
   M /branches/fpc_2_3/compiler/powerpc/cgcpu.pas
   M /branches/fpc_2_3/compiler/powerpc64/cgcpu.pas
   M /branches/fpc_2_3/compiler/ppcgen/cgppc.pas

  * adapted a_jmp_name for darwin/ppc64
  * merged g_intf_wrapper for ppc32 and ppc64, and added darwin/ppc64
    support to it

........
r6396 | jonas | 2007-02-10 20:16:06 +0100 (Sat, 10 Feb 2007) | 2 lines
Changed paths:
   M /branches/fpc_2_3/compiler/cgobj.pas

  + darwin/ppc64 support for g_indirect_sym_load

........
r6397 | jonas | 2007-02-10 20:22:49 +0100 (Sat, 10 Feb 2007) | 4 lines
Changed paths:
   M /branches/fpc_2_3/compiler/powerpc/cgcpu.pas
   M /branches/fpc_2_3/compiler/powerpc64/cgcpu.pas
   M /branches/fpc_2_3/compiler/ppcgen/cgppc.pas

  + darwin/ppc64 support to ppc64's fixref
  * moved ppc32 a_load_store to cgppc and use it for darwin/ppc64 as
    well (its relocatable symbols are only 32 bits large)

........
r6399 | jonas | 2007-02-10 22:02:37 +0100 (Sat, 10 Feb 2007) | 4 lines
Changed paths:
   M /branches/fpc_2_3/compiler/systems.pas

  + system_x86_64_darwin identifier
  + set default source system for system_x86_64_darwin and
    system_powerpc64_darwin

........
r6404 | jonas | 2007-02-10 23:01:23 +0100 (Sat, 10 Feb 2007) | 5 lines
Changed paths:
   M /branches/fpc_2_3/compiler/aasmdata.pas
   M /branches/fpc_2_3/compiler/aggas.pas
   M /branches/fpc_2_3/compiler/cgobj.pas
   M /branches/fpc_2_3/compiler/cgutils.pas
   M /branches/fpc_2_3/compiler/cresstr.pas
   M /branches/fpc_2_3/compiler/dbgdwarf.pas
   M /branches/fpc_2_3/compiler/dbgstabs.pas
   M /branches/fpc_2_3/compiler/ncgutil.pas
   M /branches/fpc_2_3/compiler/ogelf.pas
   M /branches/fpc_2_3/compiler/pdecvar.pas
   M /branches/fpc_2_3/compiler/pmodules.pas
   M /branches/fpc_2_3/compiler/symdef.pas
   M /branches/fpc_2_3/compiler/systems.pas

  + system_x86_64_darwin identifier
  + systems_darwin set which collects all darwin variants
  + added support for darwin/ppc64 and darwin/x86_64 where needed in
    the generic code

........
r6406 | jonas | 2007-02-10 23:24:32 +0100 (Sat, 10 Feb 2007) | 2 lines
Changed paths:
   M /branches/fpc_2_3/compiler/cgobj.pas

  * ifdef cpu64 -> ifdef cpu64bit

........
r6409 | jonas | 2007-02-11 00:34:04 +0100 (Sun, 11 Feb 2007) | 2 lines
Changed paths:
   M /branches/fpc_2_3/compiler/pdecvar.pas

  * fixed ppc64 compilation

........
r6413 | jonas | 2007-02-11 12:41:27 +0100 (Sun, 11 Feb 2007) | 2 lines
Changed paths:
   M /branches/fpc_2_3/rtl/bsd/system.pp
   M /branches/fpc_2_3/rtl/darwin/powerpc/sig_cpu.inc
   M /branches/fpc_2_3/rtl/darwin/signal.inc

  + darwin/ppc64 support for signal routines

........
r6415 | jonas | 2007-02-11 13:54:53 +0100 (Sun, 11 Feb 2007) | 2 lines
Changed paths:
   M /branches/fpc_2_3/compiler/systems/i_linux.pas

  * set abi of linux/ppc64 to abi_powerpc_sysv

........
r6416 | jonas | 2007-02-11 13:55:51 +0100 (Sun, 11 Feb 2007) | 2 lines
Changed paths:
   M /branches/fpc_2_3/compiler/powerpc64/cputarg.pas
   M /branches/fpc_2_3/compiler/systems/i_bsd.pas
   M /branches/fpc_2_3/compiler/systems/t_bsd.pas

  + darwin/ppc64 source and target information

........
r6418 | jonas | 2007-02-11 14:19:55 +0100 (Sun, 11 Feb 2007) | 2 lines
Changed paths:
   M /branches/fpc_2_3/rtl/powerpc64/math.inc

  * darwin/ppc64 compilation fixes

........
r6419 | jonas | 2007-02-11 14:22:22 +0100 (Sun, 11 Feb 2007) | 2 lines
Changed paths:
   M /branches/fpc_2_3/compiler/powerpc/cgcpu.pas
   M /branches/fpc_2_3/compiler/powerpc64/cgcpu.pas
   M /branches/fpc_2_3/compiler/ppcgen/cgppc.pas

  * darwin/ppc64 needs the 32 bit version of a_loadaddr_ref_reg

........
r6420 | jonas | 2007-02-11 14:22:55 +0100 (Sun, 11 Feb 2007) | 2 lines
Changed paths:
   M /branches/fpc_2_3/utils/fpcm/fpcmmain.pp

  + darwin/ppc64 support

........
r6426 | jonas | 2007-02-11 16:13:19 +0100 (Sun, 11 Feb 2007) | 2 lines
Changed paths:
   M /branches/fpc_2_3/compiler/powerpc64/rappcgas.pas

  * fixed refaddr parsing for darwin/ppc64

........
r6427 | jonas | 2007-02-11 16:14:21 +0100 (Sun, 11 Feb 2007) | 2 lines
Changed paths:
   M /branches/fpc_2_3/compiler/powerpc/agppcgas.pas
   M /branches/fpc_2_3/compiler/powerpc64/agppcgas.pas
   A /branches/fpc_2_3/compiler/ppcgen/agppcutl.pas

  * moved ppc32/ppc64 assembler writer helpers to a common unit

........
r6430 | jonas | 2007-02-11 17:53:23 +0100 (Sun, 11 Feb 2007) | 4 lines
Changed paths:
   D /branches/fpc_2_3/rtl/darwin/powerpc/sig_cpu.inc
   D /branches/fpc_2_3/rtl/darwin/powerpc/sighnd.inc
   A /branches/fpc_2_3/rtl/darwin/powerpc64
   A /branches/fpc_2_3/rtl/darwin/powerpc64/sig_cpu.inc
   A /branches/fpc_2_3/rtl/darwin/powerpc64/sighnd.inc
   A /branches/fpc_2_3/rtl/darwin/ppcgen
   A /branches/fpc_2_3/rtl/darwin/ppcgen/ppchnd.inc (from /branches/fpc_2_3/rtl/darwin/powerpc/sighnd.inc:6422)
   A /branches/fpc_2_3/rtl/darwin/ppcgen/sig_ppc.inc (from /branches/fpc_2_3/rtl/darwin/powerpc/sig_cpu.inc:6422)
   M /branches/fpc_2_3/rtl/darwin/signal.inc

  * fixed ppc/ppc64 signal include handling (both real files are in
    ppcgen, dummies in powerpc and powerpc64 which include those files)
    (1st step because pre-commit filter can't handle replaced files)

........
r6431 | jonas | 2007-02-11 17:53:47 +0100 (Sun, 11 Feb 2007) | 2 lines
Changed paths:
   A /branches/fpc_2_3/rtl/darwin/powerpc/sig_cpu.inc
   A /branches/fpc_2_3/rtl/darwin/powerpc/sighnd.inc

  * second step of signal include patch

........
r6432 | jonas | 2007-02-11 19:00:12 +0100 (Sun, 11 Feb 2007) | 2 lines
Changed paths:
   M /branches/fpc_2_3/compiler/systems/t_bsd.pas

  * changed darwin checks to use systems_darwin constant

........
r6433 | jonas | 2007-02-11 19:05:38 +0100 (Sun, 11 Feb 2007) | 3 lines
Changed paths:
   M /branches/fpc_2_3/compiler/powerpc64/cgcpu.pas

  * handle non-multiple-of-4 offsets with 64 bit loads/stores for
    darwin/ppc64

........
r6434 | jonas | 2007-02-11 19:05:56 +0100 (Sun, 11 Feb 2007) | 2 lines
Changed paths:
   D /branches/fpc_2_3/compiler/powerpc/agppcgas.pas
   D /branches/fpc_2_3/compiler/powerpc64/agppcgas.pas
   A /branches/fpc_2_3/compiler/ppcgen/agppcgas.pas (from /branches/fpc_2_3/compiler/ppcgen/agppcutl.pas:6427)
   D /branches/fpc_2_3/compiler/ppcgen/agppcutl.pas

  * completely merged ppc assembler writers

........
r6435 | jonas | 2007-02-11 19:06:40 +0100 (Sun, 11 Feb 2007) | 2 lines
Changed paths:
   M /branches/fpc_2_3/rtl/darwin/console.pp
   M /branches/fpc_2_3/rtl/darwin/termiosproc.inc

  * fixed 64 bit compilation

........
r6436 | jonas | 2007-02-11 19:09:28 +0100 (Sun, 11 Feb 2007) | 3 lines
Changed paths:
   M /branches/fpc_2_3/packages/extra/Makefile.fpc

  * universal interfaces aren't 64 bit ready yet -> only compile for
    darwin/ppc and darwin/i386

........
r6438 | jonas | 2007-02-11 19:22:34 +0100 (Sun, 11 Feb 2007) | 2 lines
Changed paths:
   A /branches/fpc_2_3/tests/test/cg/obj/darwin/powerpc64
   A /branches/fpc_2_3/tests/test/cg/obj/darwin/powerpc64/ctest.o
   A /branches/fpc_2_3/tests/test/cg/obj/darwin/powerpc64/tcext3.o
   A /branches/fpc_2_3/tests/test/cg/obj/darwin/powerpc64/tcext4.o
   A /branches/fpc_2_3/tests/test/cg/obj/darwin/powerpc64/tcext5.o

  + compiled for darwin/ppc64

........
r6439 | jonas | 2007-02-11 20:24:42 +0100 (Sun, 11 Feb 2007) | 2 lines
Changed paths:
   M /branches/fpc_2_3/compiler/ppcgen/cgppc.pas

  * patch from Thomas to fix linux/ppc64

........
r6440 | jonas | 2007-02-11 20:25:15 +0100 (Sun, 11 Feb 2007) | 2 lines
Changed paths:
   M /branches/fpc_2_3/compiler/systems.pas

  * fixed setting source OS for darwin/ppc64

........
r6444 | florian | 2007-02-11 22:24:20 +0100 (Sun, 11 Feb 2007) | 2 lines
Changed paths:
   M /branches/fpc_2_3/compiler/globtype.pas
   M /branches/fpc_2_3/compiler/nopt.pas
   M /branches/fpc_2_3/compiler/nutils.pas
   M /branches/fpc_2_3/compiler/optcse.pas
   M /branches/fpc_2_3/compiler/psub.pas

+ first node cse implementation

........
r6445 | jonas | 2007-02-11 22:30:07 +0100 (Sun, 11 Feb 2007) | 6 lines
Changed paths:
   M /branches/fpc_2_3/compiler/cresstr.pas

  * hack to work around strange darwin/ppc64 linker bug: it seems to
    have problems if you put a global symbol at the end of a section
    without any data following (at least in case of the resource strings
    section) -> add dummy byte at the end for darwin/ppc64 (otherwise
    it messes up the address of the first symbol stub entry)

........
r6449 | jonas | 2007-02-11 23:23:44 +0100 (Sun, 11 Feb 2007) | 4 lines
Changed paths:
   M /branches/fpc_2_3/compiler/systems/i_bsd.pas

  * cpupowerpc is defined for both ppc32 and ppc64 ->
    changed to cpupowerpc32 to avoid defining source
    wrongly on ppc64

........
r6450 | jonas | 2007-02-11 23:26:34 +0100 (Sun, 11 Feb 2007) | 3 lines
Changed paths:
   M /branches/fpc_2_3/compiler/ppcgen/ngppcset.pas

  * disable jump tables for darwin/ppc64 for now, don't work
    yet for some reason

........
r6451 | florian | 2007-02-11 23:54:37 +0100 (Sun, 11 Feb 2007) | 3 lines
Changed paths:
   M /branches/fpc_2_3/compiler/ncal.pas
   M /branches/fpc_2_3/compiler/nutils.pas
   M /branches/fpc_2_3/compiler/optcse.pas

* improved cse
* better complexity calculation for subscript nodes with classes or interfaces

........
r6456 | jonas | 2007-02-12 19:33:22 +0100 (Mon, 12 Feb 2007) | 4 lines
Changed paths:
   M /branches/fpc_2_3/compiler/nutils.pas

  + support for notn,shln,shrn,equaln,unequaln,gtn,gten,ltn,lten in
    node_cplexity()
  * mark muln,divn,modn as more complex

........
r6469 | jonas | 2007-02-13 15:56:01 +0100 (Tue, 13 Feb 2007) | 2 lines
Changed paths:
   M /branches/fpc_2_3/compiler/optcse.pas

  * fixed when cross-compiling a 64 bit compiler from a 32 bit platform

........
r6471 | jonas | 2007-02-13 16:17:16 +0100 (Tue, 13 Feb 2007) | 3 lines
Changed paths:
   M /branches/fpc_2_3/compiler/powerpc64/cputarg.pas

  * include stabs support (can work on darwin/ppc64, but doesn't work
    yet)

........
r6473 | jonas | 2007-02-13 16:45:48 +0100 (Tue, 13 Feb 2007) | 3 lines
Changed paths:
   M /branches/fpc_2_3/compiler/powerpc64/cgcpu.pas
   M /branches/fpc_2_3/compiler/powerpc64/cpupara.pas

  * R2 is a volatile and usable register under darwin/ppc64
  * R13 is a reserved non-volatile register under darwin/ppc64 (tls)

........
r6479 | jonas | 2007-02-13 20:40:50 +0100 (Tue, 13 Feb 2007) | 3 lines
Changed paths:
   M /branches/fpc_2_3/compiler/systems/i_bsd.pas

  * maxCrecordalign seems to have to be 8 rather 4, in spite of what
    the ABI docs say (although they are contradictory to some extent)

........
r6487 | jonas | 2007-02-14 15:57:40 +0100 (Wed, 14 Feb 2007) | 2 lines
Changed paths:
   M /branches/fpc_2_3/tests/webtbs/tw8153a.pp

  * fixed for darwin/ppc64

........
r6488 | jonas | 2007-02-14 15:58:56 +0100 (Wed, 14 Feb 2007) | 2 lines
Changed paths:
   M /branches/fpc_2_3/tests/webtbs/tw7851a.pp

  * fixed for darwin/ppc64

........
r6494 | jonas | 2007-02-15 19:36:55 +0100 (Thu, 15 Feb 2007) | 3 lines
Changed paths:
   M /branches/fpc_2_3/compiler/systems/i_bsd.pas

  * set default debug info for darwin/ppc64 to dwarf2 since
    it works better than stabs currently

........
r6500 | jonas | 2007-02-15 21:38:16 +0100 (Thu, 15 Feb 2007) | 2 lines
Changed paths:
   M /branches/fpc_2_3/compiler/version.pas

  * updated version to 2.3.0

........
r6505 | jonas | 2007-02-15 22:39:28 +0100 (Thu, 15 Feb 2007) | 2 lines
Changed paths:
   M /branches/fpc_2_3/compiler/version.pas

  * changed version to 2.3.1

........
r6511 | jonas | 2007-02-16 15:17:24 +0100 (Fri, 16 Feb 2007) | 2 lines
Changed paths:
   M /branches/fpc_2_3/compiler/powerpc64/itcpugas.pas

  * system_powerpc_darwin -> system_powerpc64_darwin

........
r6546 | daniel | 2007-02-18 15:48:54 +0100 (Sun, 18 Feb 2007) | 2 lines
Changed paths:
   M /branches/fpc_2_3/compiler/ncginl.pas
   M /branches/fpc_2_3/compiler/ncgld.pas
   M /branches/fpc_2_3/compiler/ncgrtti.pas
   M /branches/fpc_2_3/compiler/ncnv.pas
   M /branches/fpc_2_3/compiler/ninl.pas
   M /branches/fpc_2_3/compiler/nld.pas
   M /branches/fpc_2_3/compiler/nutils.pas
   M /branches/fpc_2_3/compiler/pinline.pas
   M /branches/fpc_2_3/rtl/inc/astrings.inc
   M /branches/fpc_2_3/rtl/inc/compproc.inc
   M /branches/fpc_2_3/rtl/inc/sstrings.inc
   M /branches/fpc_2_3/rtl/inc/text.inc
   M /branches/fpc_2_3/rtl/inc/wstrings.inc

  + Val/str/read/write support for enumeration types.

........
r6547 | daniel | 2007-02-18 17:01:20 +0100 (Sun, 18 Feb 2007) | 2 lines
Changed paths:
   M /branches/fpc_2_3/rtl/inc/sstrings.inc

  * Fix val code that I broke.

........
r6571 | daniel | 2007-02-20 09:27:44 +0100 (Tue, 20 Feb 2007) | 2 lines
Changed paths:
   M /branches/fpc_2_3/rtl/inc/astrings.inc
   M /branches/fpc_2_3/rtl/inc/sstrings.inc
   M /branches/fpc_2_3/rtl/inc/text.inc
   M /branches/fpc_2_3/rtl/inc/wstrings.inc

  * o2s -> ord2str, s2o -> str2ord

........
r6572 | daniel | 2007-02-20 09:33:30 +0100 (Tue, 20 Feb 2007) | 2 lines
Changed paths:
   M /branches/fpc_2_3/compiler/ncgld.pas
   M /branches/fpc_2_3/compiler/ncgrtti.pas
   M /branches/fpc_2_3/compiler/ninl.pas
   M /branches/fpc_2_3/compiler/nld.pas

  * o2s -> ord2str, s2o -> str2ord

........
r6574 | daniel | 2007-02-20 12:07:58 +0100 (Tue, 20 Feb 2007) | 2 lines
Changed paths:
   M /branches/fpc_2_3/rtl/inc/compproc.inc

  * o2s -> ord2str, s2o -> str2ord

........
r6578 | daniel | 2007-02-20 22:18:49 +0100 (Tue, 20 Feb 2007) | 2 lines
Changed paths:
   M /branches/fpc_2_3/rtl/inc/text.inc

  * Change longint to valsint.

........
r6579 | daniel | 2007-02-20 22:29:09 +0100 (Tue, 20 Feb 2007) | 2 lines
Changed paths:
   M /branches/fpc_2_3/compiler/ninl.pas

  * Handle ordinal currency types.

........
r6580 | jonas | 2007-02-20 22:29:11 +0100 (Tue, 20 Feb 2007) | 2 lines
Changed paths:
   M /branches/fpc_2_3/compiler/ncgrtti.pas

  * fixed compilation for cpurequiresproperalignment

........
r6581 | jonas | 2007-02-20 22:30:21 +0100 (Tue, 20 Feb 2007) | 2 lines
Changed paths:
   M /branches/fpc_2_3/compiler/ninl.pas

  * fixed typo

........
r6582 | daniel | 2007-02-20 22:36:19 +0100 (Tue, 20 Feb 2007) | 2 lines
Changed paths:
   M /branches/fpc_2_3/compiler/ninl.pas

  * Set is_real to true.

........
r6590 | jonas | 2007-02-21 20:23:54 +0100 (Wed, 21 Feb 2007) | 2 lines
Changed paths:
   M /branches/fpc_2_3/compiler/systems/i_bsd.pas

  * set tf_dwarf_only_local_labels for darwin/ppc64

git-svn-id: trunk@6720 -
2007-03-04 20:16:57 +00:00

1513 lines
45 KiB
ObjectPascal

{
Copyright (c) 1998-2002 by Florian Klaempfl
Type checking and register allocation for nodes that influence
the flow
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 nflw;
{$i fpcdefs.inc}
interface
uses
cclasses,
node,cpubase,
symnot,
symtype,symbase,symdef,symsym,
optunrol;
type
{ flags used by loop nodes }
tloopflag = (
{ set if it is a for ... downto ... do loop }
lnf_backward,
{ Do we need to parse childs to set var state? }
lnf_varstate,
{ Do a test at the begin of the loop?}
lnf_testatbegin,
{ Negate the loop test? }
lnf_checknegate,
{ Should the value of the loop variable on exit be correct. }
lnf_dont_mind_loopvar_on_exit);
tloopflags = set of tloopflag;
const
{ loop flags which must match to consider loop nodes equal regarding the flags }
loopflagsequal = [lnf_backward];
type
tlabelnode = class;
tloopnode = class(tbinarynode)
t1,t2 : tnode;
loopflags : tloopflags;
constructor create(tt : tnodetype;l,r,_t1,_t2 : tnode);virtual;
destructor destroy;override;
function dogetcopy : tnode;override;
constructor ppuload(t:tnodetype;ppufile:tcompilerppufile);override;
procedure ppuwrite(ppufile:tcompilerppufile);override;
procedure buildderefimpl;override;
procedure derefimpl;override;
procedure insertintolist(l : tnodelist);override;
procedure printnodetree(var t:text);override;
function docompare(p: tnode): boolean; override;
end;
twhilerepeatnode = class(tloopnode)
constructor create(l,r:Tnode;tab,cn:boolean);virtual;reintroduce;
function pass_typecheck:tnode;override;
function pass_1 : tnode;override;
{$ifdef state_tracking}
function track_state_pass(exec_known:boolean):boolean;override;
{$endif}
end;
twhilerepeatnodeclass = class of twhilerepeatnode;
tifnode = class(tloopnode)
constructor create(l,r,_t1 : tnode);virtual;reintroduce;
function pass_typecheck:tnode;override;
function pass_1 : tnode;override;
function simplify : tnode;override;
private
function internalsimplify(warn: boolean) : tnode;
end;
tifnodeclass = class of tifnode;
tfornode = class(tloopnode)
{ if count isn divisable by unrolls then
the for loop must jump to this label to get the correct
number of executions }
entrylabel : tnode;
loopvar_notid:cardinal;
constructor create(l,r,_t1,_t2 : tnode;back : boolean);virtual;reintroduce;
procedure loop_var_access(not_type:Tnotification_flag;symbol:Tsym);
function pass_typecheck:tnode;override;
function pass_1 : tnode;override;
end;
tfornodeclass = class of tfornode;
texitnode = class(tunarynode)
constructor create(l:tnode);virtual;
constructor ppuload(t:tnodetype;ppufile:tcompilerppufile);override;
procedure ppuwrite(ppufile:tcompilerppufile);override;
function pass_typecheck:tnode;override;
function pass_1 : tnode;override;
end;
texitnodeclass = class of texitnode;
tbreaknode = class(tnode)
constructor create;virtual;
function pass_typecheck:tnode;override;
function pass_1 : tnode;override;
end;
tbreaknodeclass = class of tbreaknode;
tcontinuenode = class(tnode)
constructor create;virtual;
function pass_typecheck:tnode;override;
function pass_1 : tnode;override;
end;
tcontinuenodeclass = class of tcontinuenode;
tgotonode = class(tnode)
{ we still need this for resolving forward gotos }
labelsym : tlabelsym;
labelnode : tlabelnode;
exceptionblock : integer;
{ internlab : tinterngotolabel;}
constructor create(p : tlabelnode);virtual;
{ as long as we don't know the label node we can't resolve it }
constructor create_sym(p : tlabelsym);virtual;
{ constructor createintern(g:tinterngotolabel);}
constructor ppuload(t:tnodetype;ppufile:tcompilerppufile);override;
procedure ppuwrite(ppufile:tcompilerppufile);override;
procedure buildderefimpl;override;
procedure derefimpl;override;
function dogetcopy : tnode;override;
function pass_typecheck:tnode;override;
function pass_1 : tnode;override;
function docompare(p: tnode): boolean; override;
end;
tgotonodeclass = class of tgotonode;
tlabelnode = class(tunarynode)
exceptionblock : integer;
{ when copying trees, this points to the newly created copy of a label }
copiedto : tlabelnode;
{ contains all goto nodesrefering to this label }
referinggotonodes : TFPObjectList;
constructor create(l:tnode);virtual;
constructor ppuload(t:tnodetype;ppufile:tcompilerppufile);override;
procedure ppuwrite(ppufile:tcompilerppufile);override;
procedure buildderefimpl;override;
procedure derefimpl;override;
function dogetcopy : tnode;override;
function pass_typecheck:tnode;override;
function pass_1 : tnode;override;
function docompare(p: tnode): boolean; override;
end;
tlabelnodeclass = class of tlabelnode;
traisenode = class(ttertiarynode)
constructor create(l,taddr,tframe:tnode);virtual;
function pass_typecheck:tnode;override;
function pass_1 : tnode;override;
property frametree : tnode read third write third;
end;
traisenodeclass = class of traisenode;
ttryexceptnode = class(tloopnode)
constructor create(l,r,_t1 : tnode);virtual;reintroduce;
function pass_typecheck:tnode;override;
function pass_1 : tnode;override;
end;
ttryexceptnodeclass = class of ttryexceptnode;
ttryfinallynode = class(tloopnode)
implicitframe : boolean;
constructor create(l,r:tnode);virtual;reintroduce;
constructor create_implicit(l,r,_t1:tnode);virtual;
function pass_typecheck:tnode;override;
function pass_1 : tnode;override;
end;
ttryfinallynodeclass = class of ttryfinallynode;
tonnode = class(tbinarynode)
excepTSymtable : TSymtable;
excepttype : tobjectdef;
constructor create(l,r:tnode);virtual;
destructor destroy;override;
constructor ppuload(t:tnodetype;ppufile:tcompilerppufile);override;
function pass_typecheck:tnode;override;
function pass_1 : tnode;override;
function dogetcopy : tnode;override;
function docompare(p: tnode): boolean; override;
end;
tonnodeclass = class of tonnode;
var
cwhilerepeatnode : twhilerepeatnodeclass;
cifnode : tifnodeclass;
cfornode : tfornodeclass;
cexitnode : texitnodeclass;
cbreaknode : tbreaknodeclass;
ccontinuenode : tcontinuenodeclass;
cgotonode : tgotonodeclass;
clabelnode : tlabelnodeclass;
craisenode : traisenodeclass;
ctryexceptnode : ttryexceptnodeclass;
ctryfinallynode : ttryfinallynodeclass;
connode : tonnodeclass;
implementation
uses
globtype,systems,
cutils,verbose,globals,
symconst,paramgr,defcmp,defutil,htypechk,pass_1,
ncal,nadd,ncon,nmem,nld,ncnv,nbas,cgobj,nutils,
{$ifdef prefetchnext}
ninl,
{$endif prefetchnext}
{$ifdef state_tracking}
nstate,
{$endif}
cgbase,procinfo
;
{****************************************************************************
TLOOPNODE
*****************************************************************************}
constructor tloopnode.create(tt : tnodetype;l,r,_t1,_t2 : tnode);
begin
inherited create(tt,l,r);
t1:=_t1;
t2:=_t2;
fileinfo:=l.fileinfo;
end;
destructor tloopnode.destroy;
begin
t1.free;
t2.free;
inherited destroy;
end;
constructor tloopnode.ppuload(t:tnodetype;ppufile:tcompilerppufile);
begin
inherited ppuload(t,ppufile);
t1:=ppuloadnode(ppufile);
t2:=ppuloadnode(ppufile);
end;
procedure tloopnode.ppuwrite(ppufile:tcompilerppufile);
begin
inherited ppuwrite(ppufile);
ppuwritenode(ppufile,t1);
ppuwritenode(ppufile,t2);
end;
procedure tloopnode.buildderefimpl;
begin
inherited buildderefimpl;
if assigned(t1) then
t1.buildderefimpl;
if assigned(t2) then
t2.buildderefimpl;
end;
procedure tloopnode.derefimpl;
begin
inherited derefimpl;
if assigned(t1) then
t1.derefimpl;
if assigned(t2) then
t2.derefimpl;
end;
function tloopnode.dogetcopy : tnode;
var
p : tloopnode;
begin
p:=tloopnode(inherited dogetcopy);
if assigned(t1) then
p.t1:=t1.dogetcopy
else
p.t1:=nil;
if assigned(t2) then
p.t2:=t2.dogetcopy
else
p.t2:=nil;
p.loopflags:=loopflags;
dogetcopy:=p;
end;
procedure tloopnode.insertintolist(l : tnodelist);
begin
end;
procedure tloopnode.printnodetree(var t:text);
begin
write(t,printnodeindention,'(');
printnodeindent;
printnodeinfo(t);
writeln(t);
printnode(t,left);
printnode(t,right);
printnode(t,t1);
printnode(t,t2);
printnodeunindent;
writeln(t,printnodeindention,')');
end;
function tloopnode.docompare(p: tnode): boolean;
begin
docompare :=
inherited docompare(p) and
(loopflags*loopflagsequal=tloopnode(p).loopflags*loopflagsequal) and
t1.isequal(tloopnode(p).t1) and
t2.isequal(tloopnode(p).t2);
end;
{****************************************************************************
TWHILEREPEATNODE
*****************************************************************************}
constructor Twhilerepeatnode.create(l,r:Tnode;tab,cn:boolean);
begin
inherited create(whilerepeatn,l,r,nil,nil);
if tab then
include(loopflags, lnf_testatbegin);
if cn then
include(loopflags,lnf_checknegate);
end;
function twhilerepeatnode.pass_typecheck:tnode;
var
t:Tunarynode;
begin
result:=nil;
resultdef:=voidtype;
typecheckpass(left);
{ tp procvar support }
maybe_call_procvar(left,true);
{A not node can be removed.}
if left.nodetype=notn then
begin
t:=Tunarynode(left);
left:=Tunarynode(left).left;
t.left:=nil;
t.destroy;
{Symdif operator, in case you are wondering:}
loopflags:=loopflags >< [lnf_checknegate];
end;
{ loop instruction }
if assigned(right) then
typecheckpass(right);
set_varstate(left,vs_read,[vsf_must_be_valid]);
if codegenerror then
exit;
if not is_boolean(left.resultdef) then
begin
if left.resultdef.typ=variantdef then
inserttypeconv(left,booltype)
else
CGMessage1(type_e_boolean_expr_expected,left.resultdef.typename);
end;
{ Give warnings for code that will never be executed for
while false do }
if (lnf_testatbegin in loopflags) and
(left.nodetype=ordconstn) and
(tordconstnode(left).value=0) and
assigned(right) then
CGMessagePos(right.fileinfo,cg_w_unreachable_code);
end;
{$ifdef prefetchnext}
type
passignmentquery = ^tassignmentquery;
tassignmentquery = record
towhat: tnode;
source: tassignmentnode;
statementcount: cardinal;
end;
function checkassignment(var n: tnode; arg: pointer): foreachnoderesult;
var
query: passignmentquery absolute arg;
temp, prederef: tnode;
begin
result := fen_norecurse_false;
if (n.nodetype in [assignn,inlinen,forn,calln,whilerepeatn,casen,ifn]) then
inc(query^.statementcount);
{ make sure there's something else in the loop besides going to the }
{ next item }
if (query^.statementcount > 1) and
(n.nodetype = assignn) then
begin
{ skip type conversions of assignment target }
temp := tassignmentnode(n).left;
while (temp.nodetype = typeconvn) do
temp := ttypeconvnode(temp).left;
{ assignment to x of the while assigned(x) check? }
if not(temp.isequal(query^.towhat)) then
exit;
{ right hand side of assignment dereferenced field of }
{ x? (no derefn in case of class) }
temp := tassignmentnode(n).right;
while (temp.nodetype = typeconvn) do
temp := ttypeconvnode(temp).left;
if (temp.nodetype <> subscriptn) then
exit;
prederef := tsubscriptnode(temp).left;
temp := prederef;
while (temp.nodetype = typeconvn) do
temp := ttypeconvnode(temp).left;
{ see tests/test/prefetch1.pp }
if (temp.nodetype = derefn) then
temp := tderefnode(temp).left
else
temp := prederef;
if temp.isequal(query^.towhat) then
begin
query^.source := tassignmentnode(n);
result := fen_norecurse_true;
end
end
{ don't check nodes which can't contain an assignment or whose }
{ final assignment can vary a lot }
else if not(n.nodetype in [calln,inlinen,casen,whilerepeatn,forn]) then
result := fen_false;
end;
function findassignment(where: tnode; towhat: tnode): tassignmentnode;
var
query: tassignmentquery;
begin
query.towhat := towhat;
query.source := nil;
query.statementcount := 0;
if foreachnodestatic(where,@checkassignment,@query) then
result := query.source
else
result := nil;
end;
{$endif prefetchnext}
function twhilerepeatnode.pass_1 : tnode;
var
{$ifdef prefetchnext}
runnernode, prefetchcode: tnode;
assignmentnode: tassignmentnode;
prefetchstatements: tstatementnode;
{$endif prefetchnext}
old_t_times : longint;
begin
result:=nil;
expectloc:=LOC_VOID;
old_t_times:=cg.t_times;
{ calc register weight }
if not(cs_opt_size in current_settings.optimizerswitches) then
cg.t_times:=cg.t_times*8;
firstpass(left);
if codegenerror then
exit;
registersint:=left.registersint;
registersfpu:=left.registersfpu;
{$ifdef SUPPORT_MMX}
registersmmx:=left.registersmmx;
{$endif SUPPORT_MMX}
{ loop instruction }
if assigned(right) then
begin
firstpass(right);
if codegenerror then
exit;
if registersint<right.registersint then
registersint:=right.registersint;
if registersfpu<right.registersfpu then
registersfpu:=right.registersfpu;
{$ifdef SUPPORT_MMX}
if registersmmx<right.registersmmx then
registersmmx:=right.registersmmx;
{$endif SUPPORT_MMX}
end;
cg.t_times:=old_t_times;
{$ifdef prefetchnext}
{ do at the end so all complex typeconversions are already }
{ converted to calln's }
if (cs_opt_level1 in current_settings.optimizerswitches) and
(lnf_testatbegin in loopflags) then
begin
{ get first component of the while check }
runnernode := left;
while (runnernode.nodetype in [andn,orn,notn,xorn,typeconvn]) do
runnernode := tunarynode(runnernode).left;
{ is it an assigned(x) check? }
if ((runnernode.nodetype = inlinen) and
(tinlinenode(runnernode).inlinenumber = in_assigned_x)) or
((runnernode.nodetype = unequaln) and
(taddnode(runnernode).right.nodetype = niln)) then
begin
runnernode := tunarynode(runnernode).left;
{ in case of in_assigned_x, there's a callparan in between }
if (runnernode.nodetype = callparan) then
runnernode := tcallparanode(runnernode).left;
while (runnernode.nodetype = typeconvn) do
runnernode := ttypeconvnode(runnernode).left;
{ is there an "x := x(^).somefield"? }
assignmentnode := findassignment(right,runnernode);
if assigned(assignmentnode) then
begin
prefetchcode := internalstatements(prefetchstatements);
addstatement(prefetchstatements,geninlinenode(in_prefetch_var,false,
cderefnode.create(ctypeconvnode.create(assignmentnode.right.getcopy,voidpointertype))));
addstatement(prefetchstatements,right);
right := prefetchcode;
typecheckpass(right);
end;
end;
end;
{$endif prefetchnext}
end;
{$ifdef state_tracking}
function Twhilerepeatnode.track_state_pass(exec_known:boolean):boolean;
var condition:Tnode;
code:Tnode;
done:boolean;
value:boolean;
change:boolean;
firsttest:boolean;
factval:Tnode;
begin
track_state_pass:=false;
done:=false;
firsttest:=true;
{For repeat until statements, first do a pass through the code.}
if not(lnf_testatbegin in flags) then
begin
code:=right.getcopy;
if code.track_state_pass(exec_known) then
track_state_pass:=true;
code.destroy;
end;
repeat
condition:=left.getcopy;
code:=right.getcopy;
change:=condition.track_state_pass(exec_known);
factval:=aktstate.find_fact(left);
if factval<>nil then
begin
condition.destroy;
condition:=factval.getcopy;
change:=true;
end;
if change then
begin
track_state_pass:=true;
{Force new resultdef pass.}
condition.resultdef:=nil;
do_typecheckpass(condition);
end;
if is_constboolnode(condition) then
begin
{Try to turn a while loop into a repeat loop.}
if firsttest then
exclude(flags,testatbegin);
value:=(Tordconstnode(condition).value<>0) xor checknegate;
if value then
begin
if code.track_state_pass(exec_known) then
track_state_pass:=true;
end
else
done:=true;
end
else
begin
{Remove any modified variables from the state.}
code.track_state_pass(false);
done:=true;
end;
code.destroy;
condition.destroy;
firsttest:=false;
until done;
{The loop condition is also known, for example:
while i<10 do
begin
...
end;
When the loop is done, we do know that i<10 = false.
}
condition:=left.getcopy;
if condition.track_state_pass(exec_known) then
begin
track_state_pass:=true;
{Force new resultdef pass.}
condition.resultdef:=nil;
do_typecheckpass(condition);
end;
if not is_constboolnode(condition) then
aktstate.store_fact(condition,
cordconstnode.create(byte(checknegate),booltype,true))
else
condition.destroy;
end;
{$endif}
{*****************************************************************************
TIFNODE
*****************************************************************************}
constructor tifnode.create(l,r,_t1 : tnode);
begin
inherited create(ifn,l,r,_t1,nil);
end;
function tifnode.internalsimplify(warn: boolean) : tnode;
begin
result:=nil;
{ optimize constant expressions }
if left.nodetype=ordconstn then
begin
if tordconstnode(left).value=1 then
begin
if assigned(right) then
result:=right
else
result:=cnothingnode.create;
right:=nil;
if warn and assigned(t1) then
CGMessagePos(t1.fileinfo,cg_w_unreachable_code);
end
else
begin
if assigned(t1) then
result:=t1
else
result:=cnothingnode.create;
t1:=nil;
if warn and assigned(right) then
CGMessagePos(right.fileinfo,cg_w_unreachable_code);
end;
end;
end;
function tifnode.simplify : tnode;
begin
result:=internalsimplify(false);
end;
function tifnode.pass_typecheck:tnode;
begin
result:=nil;
resultdef:=voidtype;
typecheckpass(left);
{ tp procvar support }
maybe_call_procvar(left,true);
{ if path }
if assigned(right) then
typecheckpass(right);
{ else path }
if assigned(t1) then
typecheckpass(t1);
set_varstate(left,vs_read,[vsf_must_be_valid]);
if codegenerror then
exit;
if not is_boolean(left.resultdef) then
begin
if left.resultdef.typ=variantdef then
inserttypeconv(left,booltype)
else
Message1(type_e_boolean_expr_expected,left.resultdef.typename);
end;
result:=internalsimplify(true);
end;
function tifnode.pass_1 : tnode;
var
old_t_times : longint;
begin
result:=nil;
expectloc:=LOC_VOID;
old_t_times:=cg.t_times;
firstpass(left);
registersint:=left.registersint;
registersfpu:=left.registersfpu;
{$ifdef SUPPORT_MMX}
registersmmx:=left.registersmmx;
{$endif SUPPORT_MMX}
{ determines registers weigths }
if not(cs_opt_size in current_settings.optimizerswitches) then
cg.t_times:=cg.t_times div 2;
if cg.t_times=0 then
cg.t_times:=1;
{ if path }
if assigned(right) then
begin
firstpass(right);
if registersint<right.registersint then
registersint:=right.registersint;
if registersfpu<right.registersfpu then
registersfpu:=right.registersfpu;
{$ifdef SUPPORT_MMX}
if registersmmx<right.registersmmx then
registersmmx:=right.registersmmx;
{$endif SUPPORT_MMX}
end;
{ else path }
if assigned(t1) then
begin
firstpass(t1);
if registersint<t1.registersint then
registersint:=t1.registersint;
if registersfpu<t1.registersfpu then
registersfpu:=t1.registersfpu;
{$ifdef SUPPORT_MMX}
if registersmmx<t1.registersmmx then
registersmmx:=t1.registersmmx;
{$endif SUPPORT_MMX}
end;
{ leave if we've got an error in one of the paths }
if codegenerror then
exit;
cg.t_times:=old_t_times;
end;
{*****************************************************************************
TFORNODE
*****************************************************************************}
constructor tfornode.create(l,r,_t1,_t2 : tnode;back : boolean);
begin
inherited create(forn,l,r,_t1,_t2);
if back then
include(loopflags,lnf_backward);
include(loopflags,lnf_testatbegin);
end;
procedure Tfornode.loop_var_access(not_type:Tnotification_flag;
symbol:Tsym);
begin
{If there is a read access, the value of the loop counter is important;
at the end of the loop the loop variable should contain the value it
had in the last iteration.}
if not_type=vn_onwrite then
begin
writeln('Loopvar does not matter on exit');
end
else
begin
exclude(loopflags,lnf_dont_mind_loopvar_on_exit);
writeln('Loopvar does matter on exit');
end;
Tabstractvarsym(symbol).unregister_notification(loopvar_notid);
end;
function tfornode.pass_typecheck:tnode;
var
unrollres : tnode;
begin
result:=nil;
resultdef:=voidtype;
{ loop unrolling }
if cs_opt_loopunroll in current_settings.optimizerswitches then
begin
unrollres:=unroll_loop(self);
if assigned(unrollres) then
begin
typecheckpass(unrollres);
result:=unrollres;
exit;
end;
end;
{ process the loopvar, from and to, varstates are already set }
typecheckpass(left);
typecheckpass(right);
typecheckpass(t1);
{Can we spare the first comparision?}
if (t1.nodetype=ordconstn) and
(right.nodetype=ordconstn) and
(
(
(lnf_backward in loopflags) and
(Tordconstnode(right).value>=Tordconstnode(t1).value)
) or
(
not(lnf_backward in loopflags) and
(Tordconstnode(right).value<=Tordconstnode(t1).value)
)
) then
exclude(loopflags,lnf_testatbegin);
{ Make sure that the loop var and the
from and to values are compatible types }
check_ranges(right.fileinfo,right,left.resultdef);
inserttypeconv(right,left.resultdef);
check_ranges(t1.fileinfo,t1,left.resultdef);
inserttypeconv(t1,left.resultdef);
if assigned(t2) then
typecheckpass(t2);
end;
function tfornode.pass_1 : tnode;
var
old_t_times : longint;
begin
result:=nil;
expectloc:=LOC_VOID;
firstpass(left);
if left.registersint>registersint then
registersint:=left.registersint;
if left.registersfpu>registersfpu then
registersfpu:=left.registersfpu;
{$ifdef SUPPORT_MMX}
if left.registersmmx>registersmmx then
registersmmx:=left.registersmmx;
{$endif SUPPORT_MMX}
firstpass(right);
if right.registersint>registersint then
registersint:=right.registersint;
if right.registersfpu>registersfpu then
registersfpu:=right.registersfpu;
{$ifdef SUPPORT_MMX}
if right.registersmmx>registersmmx then
registersmmx:=right.registersmmx;
{$endif SUPPORT_MMX}
firstpass(t1);
if t1.registersint>registersint then
registersint:=t1.registersint;
if t1.registersfpu>registersfpu then
registersfpu:=t1.registersfpu;
{$ifdef SUPPORT_MMX}
if t1.registersmmx>registersmmx then
registersmmx:=t1.registersmmx;
{$endif SUPPORT_MMX}
if assigned(t2) then
begin
{ Calc register weight }
old_t_times:=cg.t_times;
if not(cs_opt_size in current_settings.optimizerswitches) then
cg.t_times:=cg.t_times*8;
firstpass(t2);
if codegenerror then
exit;
if t2.registersint>registersint then
registersint:=t2.registersint;
if t2.registersfpu>registersfpu then
registersfpu:=t2.registersfpu;
{$ifdef SUPPORT_MMX}
if t2.registersmmx>registersmmx then
registersmmx:=t2.registersmmx;
{$endif SUPPORT_MMX}
cg.t_times:=old_t_times;
end;
{ we need at least one register for comparisons PM }
if registersint=0 then
inc(registersint);
end;
{*****************************************************************************
TEXITNODE
*****************************************************************************}
constructor texitnode.create(l:tnode);
begin
inherited create(exitn,l);
end;
constructor texitnode.ppuload(t:tnodetype;ppufile:tcompilerppufile);
begin
inherited ppuload(t,ppufile);
end;
procedure texitnode.ppuwrite(ppufile:tcompilerppufile);
begin
inherited ppuwrite(ppufile);
end;
function texitnode.pass_typecheck:tnode;
begin
result:=nil;
if assigned(left) then
begin
{ add assignment to funcretsym }
inserttypeconv(left,current_procinfo.procdef.returndef);
left:=cassignmentnode.create(
cloadnode.create(current_procinfo.procdef.funcretsym,current_procinfo.procdef.funcretsym.owner),
left);
typecheckpass(left);
set_varstate(left,vs_read,[vsf_must_be_valid]);
end;
resultdef:=voidtype;
end;
function texitnode.pass_1 : tnode;
begin
result:=nil;
expectloc:=LOC_VOID;
if assigned(left) then
begin
firstpass(left);
if codegenerror then
exit;
registersint:=left.registersint;
registersfpu:=left.registersfpu;
{$ifdef SUPPORT_MMX}
registersmmx:=left.registersmmx;
{$endif SUPPORT_MMX}
end;
end;
{*****************************************************************************
TBREAKNODE
*****************************************************************************}
constructor tbreaknode.create;
begin
inherited create(breakn);
end;
function tbreaknode.pass_typecheck:tnode;
begin
result:=nil;
resultdef:=voidtype;
end;
function tbreaknode.pass_1 : tnode;
begin
result:=nil;
expectloc:=LOC_VOID;
end;
{*****************************************************************************
TCONTINUENODE
*****************************************************************************}
constructor tcontinuenode.create;
begin
inherited create(continuen);
end;
function tcontinuenode.pass_typecheck:tnode;
begin
result:=nil;
resultdef:=voidtype;
end;
function tcontinuenode.pass_1 : tnode;
begin
result:=nil;
expectloc:=LOC_VOID;
end;
{*****************************************************************************
TGOTONODE
*****************************************************************************}
constructor tgotonode.create(p : tlabelnode);
begin
inherited create(goton);
exceptionblock:=aktexceptblock;
labelnode:=p;
labelsym:=nil;
end;
constructor tgotonode.create_sym(p : tlabelsym);
begin
inherited create(goton);
exceptionblock:=aktexceptblock;
if assigned(p.code) then
labelnode:=tlabelnode(p.code)
else
labelnode:=nil;
labelsym:=p;
end;
constructor tgotonode.ppuload(t:tnodetype;ppufile:tcompilerppufile);
begin
inherited ppuload(t,ppufile);
labelnode:=tlabelnode(ppuloadnoderef(ppufile));
exceptionblock:=ppufile.getbyte;
end;
procedure tgotonode.ppuwrite(ppufile:tcompilerppufile);
begin
inherited ppuwrite(ppufile);
ppuwritenoderef(ppufile,labelnode);
ppufile.putbyte(exceptionblock);
end;
procedure tgotonode.buildderefimpl;
begin
inherited buildderefimpl;
//!!! deref(labelnode);
end;
procedure tgotonode.derefimpl;
begin
inherited derefimpl;
//!!! deref(labelnode);
end;
function tgotonode.pass_typecheck:tnode;
begin
result:=nil;
resultdef:=voidtype;
end;
function tgotonode.pass_1 : tnode;
begin
result:=nil;
expectloc:=LOC_VOID;
include(current_procinfo.flags,pi_has_goto);
if not(assigned(labelnode)) then
begin
if assigned(labelsym) and assigned(labelsym.code) then
labelnode:=tlabelnode(labelsym.code)
else
internalerror(200506183);
end;
{ check if we don't mess with exception blocks }
if assigned(labelnode) and
(exceptionblock<>labelnode.exceptionblock) then
CGMessage(cg_e_goto_inout_of_exception_block);
end;
function tgotonode.dogetcopy : tnode;
var
p : tgotonode;
begin
p:=tgotonode(inherited dogetcopy);
p.exceptionblock:=exceptionblock;
{ force a valid labelnode }
if not(assigned(labelnode)) then
begin
if assigned(labelsym) and assigned(labelsym.code) then
labelnode:=tlabelnode(labelsym.code)
else
internalerror(200610291);
end;
p.labelnode:=tlabelnode(labelnode.dogetcopy);
result:=p;
end;
function tgotonode.docompare(p: tnode): boolean;
begin
docompare := false;
end;
{*****************************************************************************
TLABELNODE
*****************************************************************************}
constructor tlabelnode.create(l:tnode);
begin
inherited create(labeln,l);
exceptionblock:=aktexceptblock;
end;
constructor tlabelnode.ppuload(t:tnodetype;ppufile:tcompilerppufile);
begin
inherited ppuload(t,ppufile);
exceptionblock:=ppufile.getbyte;
end;
procedure tlabelnode.ppuwrite(ppufile:tcompilerppufile);
begin
inherited ppuwrite(ppufile);
ppufile.putbyte(exceptionblock);
end;
procedure tlabelnode.buildderefimpl;
begin
inherited buildderefimpl;
end;
procedure tlabelnode.derefimpl;
begin
inherited derefimpl;
end;
function tlabelnode.pass_typecheck:tnode;
begin
result:=nil;
{ left could still be unassigned }
if assigned(left) then
typecheckpass(left);
resultdef:=voidtype;
end;
function tlabelnode.pass_1 : tnode;
begin
result:=nil;
expectloc:=LOC_VOID;
if assigned(left) then
begin
firstpass(left);
registersint:=left.registersint;
registersfpu:=left.registersfpu;
{$ifdef SUPPORT_MMX}
registersmmx:=left.registersmmx;
{$endif SUPPORT_MMX}
end;
end;
function tlabelnode.dogetcopy : tnode;
begin
if not(assigned(copiedto)) then
copiedto:=tlabelnode(inherited dogetcopy);
copiedto.exceptionblock:=exceptionblock;
result:=copiedto;
end;
function tlabelnode.docompare(p: tnode): boolean;
begin
docompare := false;
end;
{*****************************************************************************
TRAISENODE
*****************************************************************************}
constructor traisenode.create(l,taddr,tframe:tnode);
begin
inherited create(raisen,l,taddr,tframe);
end;
function traisenode.pass_typecheck:tnode;
begin
result:=nil;
resultdef:=voidtype;
if assigned(left) then
begin
{ first para must be a _class_ }
typecheckpass(left);
set_varstate(left,vs_read,[vsf_must_be_valid]);
if codegenerror then
exit;
if not(is_class(left.resultdef)) then
CGMessage1(type_e_class_type_expected,left.resultdef.typename);
{ insert needed typeconvs for addr,frame }
if assigned(right) then
begin
{ addr }
typecheckpass(right);
inserttypeconv(right,voidpointertype);
{ frame }
if assigned(frametree) then
begin
typecheckpass(frametree);
inserttypeconv(frametree,voidpointertype);
end;
end;
end;
end;
function traisenode.pass_1 : tnode;
begin
result:=nil;
include(current_procinfo.flags,pi_do_call);
expectloc:=LOC_VOID;
if assigned(left) then
begin
{ first para must be a _class_ }
firstpass(left);
{ insert needed typeconvs for addr,frame }
if assigned(right) then
begin
{ addr }
firstpass(right);
{ frame }
if assigned(frametree) then
firstpass(frametree);
end;
left_right_max;
end;
end;
{*****************************************************************************
TTRYEXCEPTNODE
*****************************************************************************}
constructor ttryexceptnode.create(l,r,_t1 : tnode);
begin
inherited create(tryexceptn,l,r,_t1,nil);
end;
function ttryexceptnode.pass_typecheck:tnode;
begin
result:=nil;
typecheckpass(left);
{ on statements }
if assigned(right) then
typecheckpass(right);
{ else block }
if assigned(t1) then
typecheckpass(t1);
resultdef:=voidtype;
end;
function ttryexceptnode.pass_1 : tnode;
begin
result:=nil;
include(current_procinfo.flags,pi_do_call);
expectloc:=LOC_VOID;
firstpass(left);
{ on statements }
if assigned(right) then
begin
firstpass(right);
registersint:=max(registersint,right.registersint);
registersfpu:=max(registersfpu,right.registersfpu);
{$ifdef SUPPORT_MMX}
registersmmx:=max(registersmmx,right.registersmmx);
{$endif SUPPORT_MMX}
end;
{ else block }
if assigned(t1) then
begin
firstpass(t1);
registersint:=max(registersint,t1.registersint);
registersfpu:=max(registersfpu,t1.registersfpu);
{$ifdef SUPPORT_MMX}
registersmmx:=max(registersmmx,t1.registersmmx);
{$endif SUPPORT_MMX}
end;
end;
{*****************************************************************************
TTRYFINALLYNODE
*****************************************************************************}
constructor ttryfinallynode.create(l,r:tnode);
begin
inherited create(tryfinallyn,l,r,nil,nil);
implicitframe:=false;
end;
constructor ttryfinallynode.create_implicit(l,r,_t1:tnode);
begin
inherited create(tryfinallyn,l,r,_t1,nil);
implicitframe:=true;
end;
function ttryfinallynode.pass_typecheck:tnode;
begin
result:=nil;
include(current_procinfo.flags,pi_do_call);
resultdef:=voidtype;
typecheckpass(left);
// "try block" is "used"? (JM)
set_varstate(left,vs_readwritten,[vsf_must_be_valid]);
typecheckpass(right);
// "except block" is "used"? (JM)
set_varstate(right,vs_readwritten,[vsf_must_be_valid]);
{ special finally block only executed when there was an exception }
if assigned(t1) then
begin
typecheckpass(t1);
// "finally block" is "used"? (JM)
set_varstate(t1,vs_readwritten,[vsf_must_be_valid]);
end;
end;
function ttryfinallynode.pass_1 : tnode;
begin
result:=nil;
expectloc:=LOC_VOID;
firstpass(left);
firstpass(right);
left_right_max;
if assigned(t1) then
begin
firstpass(t1);
registersint:=max(registersint,t1.registersint);
registersfpu:=max(registersfpu,t1.registersfpu);
{$ifdef SUPPORT_MMX}
registersmmx:=max(registersmmx,t1.registersmmx);
{$endif SUPPORT_MMX}
end;
end;
{*****************************************************************************
TONNODE
*****************************************************************************}
constructor tonnode.create(l,r:tnode);
begin
inherited create(onn,l,r);
excepTSymtable:=nil;
excepttype:=nil;
end;
destructor tonnode.destroy;
begin
{ copied nodes don't need to release the symtable }
if assigned(excepTSymtable) then
excepTSymtable.free;
inherited destroy;
end;
constructor tonnode.ppuload(t:tnodetype;ppufile:tcompilerppufile);
begin
inherited ppuload(t,ppufile);
excepTSymtable:=nil;
excepttype:=nil;
end;
function tonnode.dogetcopy : tnode;
var
n : tonnode;
begin
n:=tonnode(inherited dogetcopy);
n.excepTSymtable:=excepTSymtable.getcopy;
n.excepttype:=excepttype;
result:=n;
end;
function tonnode.pass_typecheck:tnode;
begin
result:=nil;
resultdef:=voidtype;
if not(is_class(excepttype)) then
CGMessage1(type_e_class_type_expected,excepttype.typename);
if assigned(left) then
typecheckpass(left);
if assigned(right) then
typecheckpass(right);
end;
function tonnode.pass_1 : tnode;
begin
result:=nil;
include(current_procinfo.flags,pi_do_call);
expectloc:=LOC_VOID;
registersint:=0;
registersfpu:=0;
{$ifdef SUPPORT_MMX}
registersmmx:=0;
{$endif SUPPORT_MMX}
if assigned(left) then
begin
firstpass(left);
registersint:=left.registersint;
registersfpu:=left.registersfpu;
{$ifdef SUPPORT_MMX}
registersmmx:=left.registersmmx;
{$endif SUPPORT_MMX}
end;
if assigned(right) then
begin
firstpass(right);
registersint:=max(registersint,right.registersint);
registersfpu:=max(registersfpu,right.registersfpu);
{$ifdef SUPPORT_MMX}
registersmmx:=max(registersmmx,right.registersmmx);
{$endif SUPPORT_MMX}
end;
end;
function tonnode.docompare(p: tnode): boolean;
begin
docompare := false;
end;
begin
cwhilerepeatnode:=twhilerepeatnode;
cifnode:=tifnode;
cfornode:=tfornode;
cexitnode:=texitnode;
cgotonode:=tgotonode;
clabelnode:=tlabelnode;
craisenode:=traisenode;
ctryexceptnode:=ttryexceptnode;
ctryfinallynode:=ttryfinallynode;
connode:=tonnode;
end.