| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497 | {    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;       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.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;         { 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 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 assigned(right) then                     CGMessagePos(right.fileinfo,cg_w_unreachable_code);                end;           end;      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.
 |