mirror of
https://gitlab.com/freepascal.org/fpc/source.git
synced 2025-04-26 19:23:41 +02:00
1756 lines
53 KiB
ObjectPascal
1756 lines
53 KiB
ObjectPascal
{
|
|
$Id$
|
|
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
|
|
node,cpubase,
|
|
aasmbase,aasmtai,aasmcpu,symnot,
|
|
symtype,symbase,symdef,symsym;
|
|
|
|
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
|
|
tloopnode = class(tbinarynode)
|
|
t1,t2 : tnode;
|
|
loopflags : tloopflags;
|
|
constructor create(tt : tnodetype;l,r,_t1,_t2 : tnode);virtual;
|
|
destructor destroy;override;
|
|
function getcopy : 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,_t1:Tnode;tab,cn:boolean);virtual;
|
|
function det_resulttype: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;
|
|
function det_resulttype:tnode;override;
|
|
function pass_1 : tnode;override;
|
|
end;
|
|
tifnodeclass = class of tifnode;
|
|
|
|
tfornode = class(tloopnode)
|
|
loopvar_notid:cardinal;
|
|
constructor create(l,r,_t1,_t2 : tnode;back : boolean);virtual;
|
|
procedure loop_var_access(not_type:Tnotification_flag;symbol:Tsym);
|
|
function det_resulttype: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 det_resulttype:tnode;override;
|
|
function pass_1 : tnode;override;
|
|
end;
|
|
texitnodeclass = class of texitnode;
|
|
|
|
tbreaknode = class(tnode)
|
|
constructor create;virtual;
|
|
function det_resulttype:tnode;override;
|
|
function pass_1 : tnode;override;
|
|
end;
|
|
tbreaknodeclass = class of tbreaknode;
|
|
|
|
tcontinuenode = class(tnode)
|
|
constructor create;virtual;
|
|
function det_resulttype:tnode;override;
|
|
function pass_1 : tnode;override;
|
|
end;
|
|
tcontinuenodeclass = class of tcontinuenode;
|
|
|
|
tgotonode = class(tnode)
|
|
labsym : tlabelsym;
|
|
labsymderef : tderef;
|
|
exceptionblock : integer;
|
|
{ internlab : tinterngotolabel;}
|
|
constructor create(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 getcopy : tnode;override;
|
|
function det_resulttype:tnode;override;
|
|
function pass_1 : tnode;override;
|
|
function docompare(p: tnode): boolean; override;
|
|
end;
|
|
tgotonodeclass = class of tgotonode;
|
|
|
|
tlabelnode = class(tunarynode)
|
|
labelnr : tasmlabel;
|
|
labsym : tlabelsym;
|
|
labsymderef : tderef;
|
|
exceptionblock : integer;
|
|
constructor createcase(p : tasmlabel;l:tnode);virtual;
|
|
constructor create(p : tlabelsym;l:tnode);virtual;
|
|
constructor ppuload(t:tnodetype;ppufile:tcompilerppufile);override;
|
|
procedure ppuwrite(ppufile:tcompilerppufile);override;
|
|
procedure buildderefimpl;override;
|
|
procedure derefimpl;override;
|
|
function getcopy : tnode;override;
|
|
function det_resulttype:tnode;override;
|
|
function pass_1 : tnode;override;
|
|
function docompare(p: tnode): boolean; override;
|
|
end;
|
|
tlabelnodeclass = class of tlabelnode;
|
|
|
|
traisenode = class(tbinarynode)
|
|
frametree : tnode;
|
|
constructor create(l,taddr,tframe:tnode);virtual;
|
|
constructor ppuload(t:tnodetype;ppufile:tcompilerppufile);override;
|
|
procedure ppuwrite(ppufile:tcompilerppufile);override;
|
|
procedure buildderefimpl;override;
|
|
procedure derefimpl;override;
|
|
function getcopy : tnode;override;
|
|
procedure insertintolist(l : tnodelist);override;
|
|
function det_resulttype:tnode;override;
|
|
function pass_1 : tnode;override;
|
|
function docompare(p: tnode): boolean; override;
|
|
end;
|
|
traisenodeclass = class of traisenode;
|
|
|
|
ttryexceptnode = class(tloopnode)
|
|
constructor create(l,r,_t1 : tnode);virtual;
|
|
function det_resulttype:tnode;override;
|
|
function pass_1 : tnode;override;
|
|
end;
|
|
ttryexceptnodeclass = class of ttryexceptnode;
|
|
|
|
ttryfinallynode = class(tloopnode)
|
|
implicitframe : boolean;
|
|
constructor create(l,r:tnode);virtual;
|
|
constructor create_implicit(l,r,_t1:tnode);virtual;
|
|
function det_resulttype: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 det_resulttype:tnode;override;
|
|
function pass_1 : tnode;override;
|
|
function getcopy : tnode;override;
|
|
function docompare(p: tnode): boolean; override;
|
|
end;
|
|
tonnodeclass = class of tonnode;
|
|
|
|
{ for compatibilty }
|
|
function genloopnode(t : tnodetype;l,r,n1 : tnode;back : boolean) : tnode;
|
|
|
|
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,
|
|
{$ifdef state_tracking}
|
|
nstate,
|
|
{$endif}
|
|
cgbase,procinfo
|
|
;
|
|
|
|
function genloopnode(t : tnodetype;l,r,n1 : tnode;back : boolean) : tnode;
|
|
|
|
var
|
|
p : tnode;
|
|
|
|
begin
|
|
case t of
|
|
ifn:
|
|
p:=cifnode.create(l,r,n1);
|
|
whilerepeatn:
|
|
if back then
|
|
{Repeat until.}
|
|
p:=cwhilerepeatnode.create(l,r,n1,false,true)
|
|
else
|
|
{While do.}
|
|
p:=cwhilerepeatnode.create(l,r,n1,true,false);
|
|
forn:
|
|
p:=cfornode.create(l,r,n1,nil,back);
|
|
end;
|
|
resulttypepass(p);
|
|
genloopnode:=p;
|
|
end;
|
|
|
|
{****************************************************************************
|
|
TLOOPNODE
|
|
*****************************************************************************}
|
|
|
|
constructor tloopnode.create(tt : tnodetype;l,r,_t1,_t2 : tnode);
|
|
|
|
begin
|
|
inherited create(tt,l,r);
|
|
t1:=_t1;
|
|
t2:=_t2;
|
|
set_file_line(l);
|
|
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.getcopy : tnode;
|
|
|
|
var
|
|
p : tloopnode;
|
|
|
|
begin
|
|
p:=tloopnode(inherited getcopy);
|
|
if assigned(t1) then
|
|
p.t1:=t1.getcopy
|
|
else
|
|
p.t1:=nil;
|
|
if assigned(t2) then
|
|
p.t2:=t2.getcopy
|
|
else
|
|
p.t2:=nil;
|
|
p.loopflags:=loopflags;
|
|
getcopy:=p;
|
|
end;
|
|
|
|
procedure tloopnode.insertintolist(l : tnodelist);
|
|
|
|
begin
|
|
end;
|
|
|
|
|
|
procedure tloopnode.printnodetree(var t:text);
|
|
begin
|
|
write(t,printnodeindention,'(');
|
|
printnodeindent;
|
|
printnodeinfo(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,_t1:Tnode;tab,cn:boolean);
|
|
begin
|
|
inherited create(whilerepeatn,l,r,_t1,nil);
|
|
if tab then
|
|
include(loopflags, lnf_testatbegin);
|
|
if cn then
|
|
include(loopflags,lnf_checknegate);
|
|
end;
|
|
|
|
|
|
function twhilerepeatnode.det_resulttype:tnode;
|
|
var
|
|
t:Tunarynode;
|
|
begin
|
|
result:=nil;
|
|
resulttype:=voidtype;
|
|
|
|
resulttypepass(left);
|
|
{A not node can be removed.}
|
|
if left.nodetype=notn then
|
|
begin
|
|
t:=Tunarynode(left);
|
|
left:=Tunarynode(left).left;
|
|
t.left:=nil;
|
|
t.destroy;
|
|
{$ifdef Delphi}
|
|
{ How can this be handled in Delphi ? }
|
|
RunError(255);
|
|
{$else}
|
|
{Symdif operator, in case you are wondering:}
|
|
loopflags:=loopflags >< [lnf_checknegate];
|
|
{$endif}
|
|
end;
|
|
{ loop instruction }
|
|
if assigned(right) then
|
|
resulttypepass(right);
|
|
set_varstate(left,vs_used,true);
|
|
if codegenerror then
|
|
exit;
|
|
if not is_boolean(left.resulttype.def) then
|
|
begin
|
|
CGMessage1(type_e_boolean_expr_expected,left.resulttype.def.typename);
|
|
exit;
|
|
end;
|
|
end;
|
|
|
|
|
|
function twhilerepeatnode.pass_1 : tnode;
|
|
var
|
|
old_t_times : longint;
|
|
begin
|
|
result:=nil;
|
|
expectloc:=LOC_VOID;
|
|
old_t_times:=cg.t_times;
|
|
|
|
{ calc register weight }
|
|
if not(cs_littlesize in aktglobalswitches ) 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;
|
|
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 resulttype pass.}
|
|
condition.resulttype.def:=nil;
|
|
do_resulttypepass(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 resulttype pass.}
|
|
condition.resulttype.def:=nil;
|
|
do_resulttypepass(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.det_resulttype:tnode;
|
|
begin
|
|
result:=nil;
|
|
resulttype:=voidtype;
|
|
|
|
resulttypepass(left);
|
|
{ if path }
|
|
if assigned(right) then
|
|
resulttypepass(right);
|
|
{ else path }
|
|
if assigned(t1) then
|
|
resulttypepass(t1);
|
|
set_varstate(left,vs_used,true);
|
|
if codegenerror then
|
|
exit;
|
|
|
|
if not is_boolean(left.resulttype.def) then
|
|
Message1(type_e_boolean_expr_expected,left.resulttype.def.typename);
|
|
end;
|
|
|
|
|
|
function tifnode.pass_1 : tnode;
|
|
var
|
|
old_t_times : longint;
|
|
hp : tnode;
|
|
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_littlesize in aktglobalswitches) 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;
|
|
|
|
if left.nodetype=ordconstn then
|
|
begin
|
|
{ optimize }
|
|
if tordconstnode(left).value=1 then
|
|
begin
|
|
hp:=right;
|
|
right:=nil;
|
|
{ we cannot set p to nil !!! }
|
|
if assigned(hp) then
|
|
result:=hp
|
|
else
|
|
result:=cnothingnode.create;
|
|
end
|
|
else
|
|
begin
|
|
hp:=t1;
|
|
t1:=nil;
|
|
{ we cannot set p to nil !!! }
|
|
if assigned(hp) then
|
|
result:=hp
|
|
else
|
|
result:=cnothingnode.create;
|
|
end;
|
|
end;
|
|
|
|
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;
|
|
Tvarsym(symbol).unregister_notification(loopvar_notid);
|
|
end;
|
|
|
|
function tfornode.det_resulttype:tnode;
|
|
var
|
|
hp : tnode;
|
|
begin
|
|
result:=nil;
|
|
resulttype:=voidtype;
|
|
|
|
|
|
if left.nodetype<>assignn then
|
|
begin
|
|
CGMessage(cg_e_illegal_expression);
|
|
exit;
|
|
end;
|
|
|
|
{Can we spare the first comparision?}
|
|
if (right.nodetype=ordconstn) and (Tassignmentnode(left).right.nodetype=ordconstn) then
|
|
if (
|
|
(lnf_backward in loopflags) and
|
|
(Tordconstnode(Tassignmentnode(left).right).value>=Tordconstnode(right).value)
|
|
)
|
|
or not(
|
|
(lnf_backward in loopflags) and
|
|
(Tordconstnode(Tassignmentnode(left).right).value<=Tordconstnode(right).value)
|
|
) then
|
|
exclude(loopflags,lnf_testatbegin);
|
|
|
|
{ save counter var }
|
|
t2:=tassignmentnode(left).left.getcopy;
|
|
|
|
resulttypepass(left);
|
|
set_varstate(left,vs_used,true);
|
|
|
|
if assigned(t1) then
|
|
begin
|
|
resulttypepass(t1);
|
|
if codegenerror then
|
|
exit;
|
|
end;
|
|
|
|
{ process count var }
|
|
resulttypepass(t2);
|
|
set_varstate(t2,vs_used,false);
|
|
if codegenerror then
|
|
exit;
|
|
|
|
{ Check count var, record fields are also allowed in tp7 }
|
|
hp:=t2;
|
|
while (hp.nodetype=subscriptn) or
|
|
((hp.nodetype=vecn) and
|
|
is_constintnode(tvecnode(hp).right)) or
|
|
((hp.nodetype=typeconvn) and
|
|
(ttypeconvnode(hp).convtype=tc_equal)) do
|
|
hp:=tunarynode(hp).left;
|
|
{ we need a simple loadn, but the load must be in a global symtable or
|
|
in the same level as the para of the current proc }
|
|
if (
|
|
(hp.nodetype=loadn) and
|
|
(
|
|
(tloadnode(hp).symtable.symtablelevel=main_program_level) or
|
|
(tloadnode(hp).symtable.symtablelevel=current_procinfo.procdef.parast.symtablelevel)
|
|
) and
|
|
not(
|
|
(tloadnode(hp).symtableentry.typ=varsym) and
|
|
((tvarsym(tloadnode(hp).symtableentry).varspez in [vs_var,vs_out]) or
|
|
(vo_is_thread_var in tvarsym(tloadnode(hp).symtableentry).varoptions))
|
|
)
|
|
) then
|
|
begin
|
|
if (hp.nodetype=loadn) and
|
|
(tloadnode(hp).symtableentry.typ=varsym) then
|
|
tvarsym(tloadnode(hp).symtableentry).varstate:=vs_used;
|
|
if not(is_ordinal(t2.resulttype.def))
|
|
{$ifndef cpu64bit}
|
|
or is_64bitint(t2.resulttype.def)
|
|
{$endif cpu64bit}
|
|
then
|
|
CGMessagePos(hp.fileinfo,type_e_ordinal_expr_expected);
|
|
end
|
|
else
|
|
CGMessagePos(hp.fileinfo,cg_e_illegal_count_var);
|
|
|
|
resulttypepass(right);
|
|
set_varstate(right,vs_used,true);
|
|
inserttypeconv(right,t2.resulttype);
|
|
end;
|
|
|
|
|
|
function tfornode.pass_1 : tnode;
|
|
var
|
|
old_t_times : longint;
|
|
{$ifdef loopvar_dont_mind}
|
|
hp : Tnode;
|
|
{$endif loopvar_dont_mind}
|
|
begin
|
|
result:=nil;
|
|
expectloc:=LOC_VOID;
|
|
{ Calc register weight }
|
|
old_t_times:=cg.t_times;
|
|
if not(cs_littlesize in aktglobalswitches) then
|
|
cg.t_times:=cg.t_times*8;
|
|
|
|
firstpass(left);
|
|
|
|
if assigned(t1) then
|
|
begin
|
|
firstpass(t1);
|
|
if codegenerror then
|
|
exit;
|
|
end;
|
|
registersint:=t1.registersint;
|
|
registersfpu:=t1.registersfpu;
|
|
{$ifdef SUPPORT_MMX}
|
|
registersmmx:=left.registersmmx;
|
|
{$endif SUPPORT_MMX}
|
|
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}
|
|
|
|
{ process count var }
|
|
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}
|
|
|
|
firstpass(right);
|
|
{$ifdef loopvar_dont_mind}
|
|
{ Check count var, record fields are also allowed in tp7 }
|
|
include(loopflags,lnf_dont_mind_loopvar_on_exit);
|
|
hp:=t2;
|
|
while (hp.nodetype=subscriptn) or
|
|
((hp.nodetype=vecn) and
|
|
is_constintnode(tvecnode(hp).right)) do
|
|
hp:=tunarynode(hp).left;
|
|
if (hp.nodetype=loadn) and (Tloadnode(hp).symtableentry.typ=varsym) then
|
|
loopvar_notid:=Tvarsym(Tloadnode(hp).symtableentry).
|
|
register_notification([vn_onread,vn_onwrite],@loop_var_access);
|
|
{$endif}
|
|
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}
|
|
{ we need at least one register for comparisons PM }
|
|
if registersint=0 then
|
|
inc(registersint);
|
|
cg.t_times:=old_t_times;
|
|
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.det_resulttype:tnode;
|
|
begin
|
|
result:=nil;
|
|
if assigned(left) then
|
|
begin
|
|
{ add assignment to funcretsym }
|
|
inserttypeconv(left,current_procinfo.procdef.rettype);
|
|
left:=cassignmentnode.create(
|
|
cloadnode.create(current_procinfo.procdef.funcretsym,current_procinfo.procdef.funcretsym.owner),
|
|
left);
|
|
resulttypepass(left);
|
|
set_varstate(left,vs_used,true);
|
|
end;
|
|
resulttype:=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.det_resulttype:tnode;
|
|
begin
|
|
result:=nil;
|
|
resulttype:=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.det_resulttype:tnode;
|
|
begin
|
|
result:=nil;
|
|
resulttype:=voidtype;
|
|
end;
|
|
|
|
|
|
function tcontinuenode.pass_1 : tnode;
|
|
begin
|
|
result:=nil;
|
|
expectloc:=LOC_VOID;
|
|
end;
|
|
|
|
|
|
{*****************************************************************************
|
|
TGOTONODE
|
|
*****************************************************************************}
|
|
|
|
constructor tgotonode.create(p : tlabelsym);
|
|
begin
|
|
inherited create(goton);
|
|
exceptionblock:=aktexceptblock;
|
|
labsym:=p;
|
|
end;
|
|
|
|
|
|
constructor tgotonode.ppuload(t:tnodetype;ppufile:tcompilerppufile);
|
|
begin
|
|
inherited ppuload(t,ppufile);
|
|
ppufile.getderef(labsymderef);
|
|
exceptionblock:=ppufile.getbyte;
|
|
end;
|
|
|
|
|
|
procedure tgotonode.ppuwrite(ppufile:tcompilerppufile);
|
|
begin
|
|
inherited ppuwrite(ppufile);
|
|
ppufile.putderef(labsymderef);
|
|
ppufile.putbyte(exceptionblock);
|
|
end;
|
|
|
|
|
|
procedure tgotonode.buildderefimpl;
|
|
begin
|
|
inherited buildderefimpl;
|
|
labsymderef.build(labsym);
|
|
end;
|
|
|
|
|
|
procedure tgotonode.derefimpl;
|
|
begin
|
|
inherited derefimpl;
|
|
labsym:=tlabelsym(labsymderef.resolve);
|
|
end;
|
|
|
|
|
|
function tgotonode.det_resulttype:tnode;
|
|
begin
|
|
result:=nil;
|
|
resulttype:=voidtype;
|
|
end;
|
|
|
|
|
|
function tgotonode.pass_1 : tnode;
|
|
begin
|
|
result:=nil;
|
|
expectloc:=LOC_VOID;
|
|
{ check if }
|
|
if assigned(labsym) and
|
|
assigned(labsym.code) and
|
|
(exceptionblock<>tlabelnode(labsym.code).exceptionblock) then
|
|
begin
|
|
writeln('goto exceptblock: ',exceptionblock);
|
|
writeln('label exceptblock: ',tlabelnode(labsym.code).exceptionblock);
|
|
CGMessage(cg_e_goto_inout_of_exception_block);
|
|
end;
|
|
end;
|
|
|
|
|
|
function tgotonode.getcopy : tnode;
|
|
var
|
|
p : tgotonode;
|
|
begin
|
|
p:=tgotonode(inherited getcopy);
|
|
p.labsym:=labsym;
|
|
p.exceptionblock:=exceptionblock;
|
|
result:=p;
|
|
end;
|
|
|
|
|
|
function tgotonode.docompare(p: tnode): boolean;
|
|
begin
|
|
docompare := false;
|
|
end;
|
|
|
|
|
|
{*****************************************************************************
|
|
TLABELNODE
|
|
*****************************************************************************}
|
|
|
|
constructor tlabelnode.createcase(p : tasmlabel;l:tnode);
|
|
begin
|
|
inherited create(labeln,l);
|
|
{ it shouldn't be possible to jump to case labels using goto }
|
|
exceptionblock:=-1;
|
|
labsym:=nil;
|
|
labelnr:=p;
|
|
end;
|
|
|
|
|
|
constructor tlabelnode.create(p : tlabelsym;l:tnode);
|
|
begin
|
|
inherited create(labeln,l);
|
|
exceptionblock:=aktexceptblock;
|
|
labsym:=p;
|
|
labelnr:=p.lab;
|
|
{ save the current labelnode in the labelsym }
|
|
p.code:=self;
|
|
end;
|
|
|
|
|
|
constructor tlabelnode.ppuload(t:tnodetype;ppufile:tcompilerppufile);
|
|
begin
|
|
inherited ppuload(t,ppufile);
|
|
ppufile.getderef(labsymderef);
|
|
labelnr:=tasmlabel(ppufile.getasmsymbol);
|
|
exceptionblock:=ppufile.getbyte;
|
|
end;
|
|
|
|
|
|
procedure tlabelnode.ppuwrite(ppufile:tcompilerppufile);
|
|
begin
|
|
inherited ppuwrite(ppufile);
|
|
ppufile.putderef(labsymderef);
|
|
ppufile.putasmsymbol(labelnr);
|
|
ppufile.putbyte(exceptionblock);
|
|
end;
|
|
|
|
|
|
procedure tlabelnode.buildderefimpl;
|
|
begin
|
|
inherited buildderefimpl;
|
|
labsymderef.build(labsym);
|
|
end;
|
|
|
|
|
|
procedure tlabelnode.derefimpl;
|
|
begin
|
|
inherited derefimpl;
|
|
labsym:=tlabelsym(labsymderef.resolve);
|
|
objectlibrary.derefasmsymbol(tasmsymbol(labelnr));
|
|
end;
|
|
|
|
|
|
function tlabelnode.det_resulttype:tnode;
|
|
begin
|
|
result:=nil;
|
|
{ left could still be unassigned }
|
|
if assigned(left) then
|
|
resulttypepass(left);
|
|
resulttype:=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.getcopy : tnode;
|
|
var
|
|
p : tlabelnode;
|
|
begin
|
|
p:=tlabelnode(inherited getcopy);
|
|
p.labelnr:=labelnr;
|
|
p.exceptionblock:=exceptionblock;
|
|
p.labsym:=labsym;
|
|
result:=p;
|
|
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);
|
|
frametree:=tframe;
|
|
end;
|
|
|
|
|
|
constructor traisenode.ppuload(t:tnodetype;ppufile:tcompilerppufile);
|
|
begin
|
|
inherited ppuload(t,ppufile);
|
|
frametree:=ppuloadnode(ppufile);
|
|
end;
|
|
|
|
|
|
procedure traisenode.ppuwrite(ppufile:tcompilerppufile);
|
|
begin
|
|
inherited ppuwrite(ppufile);
|
|
ppuwritenode(ppufile,frametree);
|
|
end;
|
|
|
|
|
|
procedure traisenode.buildderefimpl;
|
|
begin
|
|
inherited buildderefimpl;
|
|
if assigned(frametree) then
|
|
frametree.buildderefimpl;
|
|
end;
|
|
|
|
|
|
procedure traisenode.derefimpl;
|
|
begin
|
|
inherited derefimpl;
|
|
if assigned(frametree) then
|
|
frametree.derefimpl;
|
|
end;
|
|
|
|
|
|
function traisenode.getcopy : tnode;
|
|
var
|
|
n : traisenode;
|
|
begin
|
|
n:=traisenode(inherited getcopy);
|
|
if assigned(frametree) then
|
|
n.frametree:=frametree.getcopy
|
|
else
|
|
n.frametree:=nil;
|
|
getcopy:=n;
|
|
end;
|
|
|
|
|
|
procedure traisenode.insertintolist(l : tnodelist);
|
|
begin
|
|
end;
|
|
|
|
|
|
function traisenode.det_resulttype:tnode;
|
|
begin
|
|
result:=nil;
|
|
resulttype:=voidtype;
|
|
if assigned(left) then
|
|
begin
|
|
{ first para must be a _class_ }
|
|
resulttypepass(left);
|
|
set_varstate(left,vs_used,true);
|
|
if codegenerror then
|
|
exit;
|
|
if not(is_class(left.resulttype.def)) then
|
|
CGMessage1(type_e_class_type_expected,left.resulttype.def.typename);
|
|
{ insert needed typeconvs for addr,frame }
|
|
if assigned(right) then
|
|
begin
|
|
{ addr }
|
|
resulttypepass(right);
|
|
inserttypeconv(right,voidpointertype);
|
|
{ frame }
|
|
if assigned(frametree) then
|
|
begin
|
|
resulttypepass(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;
|
|
|
|
|
|
function traisenode.docompare(p: tnode): boolean;
|
|
begin
|
|
docompare := false;
|
|
end;
|
|
|
|
|
|
{*****************************************************************************
|
|
TTRYEXCEPTNODE
|
|
*****************************************************************************}
|
|
|
|
constructor ttryexceptnode.create(l,r,_t1 : tnode);
|
|
begin
|
|
inherited create(tryexceptn,l,r,_t1,nil);
|
|
end;
|
|
|
|
|
|
function ttryexceptnode.det_resulttype:tnode;
|
|
begin
|
|
result:=nil;
|
|
resulttypepass(left);
|
|
{ on statements }
|
|
if assigned(right) then
|
|
resulttypepass(right);
|
|
{ else block }
|
|
if assigned(t1) then
|
|
resulttypepass(t1);
|
|
resulttype:=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.det_resulttype:tnode;
|
|
begin
|
|
result:=nil;
|
|
include(current_procinfo.flags,pi_do_call);
|
|
resulttype:=voidtype;
|
|
|
|
resulttypepass(left);
|
|
set_varstate(left,vs_used,true);
|
|
|
|
resulttypepass(right);
|
|
set_varstate(right,vs_used,true);
|
|
|
|
{ special finally block only executed when there was an exception }
|
|
if assigned(t1) then
|
|
begin
|
|
resulttypepass(t1);
|
|
set_varstate(t1,vs_used,true);
|
|
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.getcopy : tnode;
|
|
var
|
|
n : tonnode;
|
|
begin
|
|
n:=tonnode(inherited getcopy);
|
|
n.exceptsymtable:=exceptsymtable.getcopy;
|
|
n.excepttype:=excepttype;
|
|
result:=n;
|
|
end;
|
|
|
|
|
|
function tonnode.det_resulttype:tnode;
|
|
begin
|
|
result:=nil;
|
|
resulttype:=voidtype;
|
|
if not(is_class(excepttype)) then
|
|
CGMessage1(type_e_class_type_expected,excepttype.typename);
|
|
if assigned(left) then
|
|
resulttypepass(left);
|
|
if assigned(right) then
|
|
resulttypepass(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.
|
|
{
|
|
$Log$
|
|
Revision 1.95 2004-03-18 16:19:03 peter
|
|
* fixed operator overload allowing for pointer-string
|
|
* replaced some type_e_mismatch with more informational messages
|
|
|
|
Revision 1.94 2004/02/05 01:24:08 florian
|
|
* several fixes to compile x86-64 system
|
|
|
|
Revision 1.93 2004/02/03 22:32:54 peter
|
|
* renamed xNNbittype to xNNinttype
|
|
* renamed registers32 to registersint
|
|
* replace some s32bit,u32bit with torddef([su]inttype).def.typ
|
|
|
|
Revision 1.92 2004/01/26 16:12:27 daniel
|
|
* reginfo now also only allocated during register allocation
|
|
* third round of gdb cleanups: kick out most of concatstabto
|
|
|
|
Revision 1.91 2003/12/28 22:51:18 florian
|
|
+ except handling related nodes now include pi_do_call if necessary
|
|
|
|
Revision 1.90 2003/12/08 19:29:21 peter
|
|
* copy loopflags
|
|
|
|
Revision 1.89 2003/12/01 18:44:15 peter
|
|
* fixed some crashes
|
|
* fixed varargs and register calling probs
|
|
|
|
Revision 1.88 2003/11/23 17:39:16 peter
|
|
* don't release exceptsymtable for copied nodes
|
|
|
|
Revision 1.87 2003/11/12 15:48:27 peter
|
|
* fix set_varstate in for loops
|
|
* fix set_varstate from case statements
|
|
|
|
Revision 1.86 2003/10/28 15:36:01 peter
|
|
* absolute to object field supported, fixes tb0458
|
|
|
|
Revision 1.85 2003/10/23 14:44:07 peter
|
|
* splitted buildderef and buildderefimpl to fix interface crc
|
|
calculation
|
|
|
|
Revision 1.84 2003/10/22 20:40:00 peter
|
|
* write derefdata in a separate ppu entry
|
|
|
|
Revision 1.83 2003/10/09 21:31:37 daniel
|
|
* Register allocator splitted, ans abstract now
|
|
|
|
Revision 1.82 2003/10/08 19:19:45 peter
|
|
* set_varstate cleanup
|
|
|
|
Revision 1.81 2003/10/05 11:53:57 florian
|
|
* writing of loop nodes fixed
|
|
|
|
Revision 1.80 2003/10/01 20:34:48 peter
|
|
* procinfo unit contains tprocinfo
|
|
* cginfo renamed to cgbase
|
|
* moved cgmessage to verbose
|
|
* fixed ppc and sparc compiles
|
|
|
|
Revision 1.79 2003/07/06 15:31:20 daniel
|
|
* Fixed register allocator. *Lots* of fixes.
|
|
|
|
Revision 1.78 2003/06/13 21:19:30 peter
|
|
* current_procdef removed, use current_procinfo.procdef instead
|
|
|
|
Revision 1.77 2003/06/07 20:26:32 peter
|
|
* re-resolving added instead of reloading from ppu
|
|
* tderef object added to store deref info for resolving
|
|
|
|
Revision 1.76 2003/06/07 18:57:04 jonas
|
|
+ added freeintparaloc
|
|
* ppc get/freeintparaloc now check whether the parameter regs are
|
|
properly allocated/deallocated (and get an extra list para)
|
|
* ppc a_call_* now internalerrors if pi_do_call is not yet set
|
|
* fixed lot of missing pi_do_call's
|
|
|
|
Revision 1.75 2003/05/26 21:17:17 peter
|
|
* procinlinenode removed
|
|
* aktexit2label removed, fast exit removed
|
|
+ tcallnode.inlined_pass_2 added
|
|
|
|
Revision 1.74 2003/05/13 19:14:41 peter
|
|
* failn removed
|
|
* inherited result code check moven to pexpr
|
|
|
|
Revision 1.73 2003/05/11 21:37:03 peter
|
|
* moved implicit exception frame from ncgutil to psub
|
|
* constructor/destructor helpers moved from cobj/ncgutil to psub
|
|
|
|
Revision 1.72 2003/05/01 07:59:42 florian
|
|
* introduced defaultordconsttype to decribe the default size of ordinal constants
|
|
on 64 bit CPUs it's equal to cs64bitdef while on 32 bit CPUs it's equal to s32bitdef
|
|
+ added defines CPU32 and CPU64 for 32 bit and 64 bit CPUs
|
|
* int64s/qwords are allowed as for loop counter on 64 bit CPUs
|
|
|
|
Revision 1.71 2003/04/27 11:21:33 peter
|
|
* aktprocdef renamed to current_procinfo.procdef
|
|
* procinfo renamed to current_procinfo
|
|
* procinfo will now be stored in current_module so it can be
|
|
cleaned up properly
|
|
* gen_main_procsym changed to create_main_proc and release_main_proc
|
|
to also generate a tprocinfo structure
|
|
* fixed unit implicit initfinal
|
|
|
|
Revision 1.70 2003/04/27 07:29:50 peter
|
|
* current_procinfo.procdef cleanup, current_procdef is now always nil when parsing
|
|
a new procdef declaration
|
|
* aktprocsym removed
|
|
* lexlevel removed, use symtable.symtablelevel instead
|
|
* implicit init/final code uses the normal genentry/genexit
|
|
* funcret state checking updated for new funcret handling
|
|
|
|
Revision 1.69 2003/04/26 00:28:41 peter
|
|
* removed load_funcret
|
|
|
|
Revision 1.68 2003/04/25 20:59:33 peter
|
|
* removed funcretn,funcretsym, function result is now in varsym
|
|
and aliases for result and function name are added using absolutesym
|
|
* vs_hidden parameter for funcret passed in parameter
|
|
* vs_hidden fixes
|
|
* writenode changed to printnode and released from extdebug
|
|
* -vp option added to generate a tree.log with the nodetree
|
|
* nicer printnode for statements, callnode
|
|
|
|
Revision 1.67 2003/04/25 08:25:26 daniel
|
|
* Ifdefs around a lot of calls to cleartempgen
|
|
* Fixed registers that are allocated but not freed in several nodes
|
|
* Tweak to register allocator to cause less spills
|
|
* 8-bit registers now interfere with esi,edi and ebp
|
|
Compiler can now compile rtl successfully when using new register
|
|
allocator
|
|
|
|
Revision 1.66 2003/04/22 23:50:23 peter
|
|
* firstpass uses expectloc
|
|
* checks if there are differences between the expectloc and
|
|
location.loc from secondpass in EXTDEBUG
|
|
|
|
Revision 1.65 2003/03/20 15:54:46 peter
|
|
* don't allow var and out parameters as for loop counter
|
|
|
|
Revision 1.64 2003/01/09 21:52:37 peter
|
|
* merged some verbosity options.
|
|
* V_LineInfo is a verbosity flag to include line info
|
|
|
|
Revision 1.63 2003/01/04 08:08:47 daniel
|
|
* Readded missing variable
|
|
|
|
Revision 1.62 2003/01/03 17:16:57 peter
|
|
* fixed warning about unset funcret
|
|
|
|
Revision 1.61 2003/01/03 12:15:56 daniel
|
|
* Removed ifdefs around notifications
|
|
ifdefs around for loop optimizations remain
|
|
|
|
Revision 1.60 2002/12/31 09:55:58 daniel
|
|
+ Notification implementation complete
|
|
+ Add for loop code optimization using notifications
|
|
results in 1.5-1.9% speed improvement in nestloop benchmark
|
|
Optimization incomplete, compiler does not cycle yet with
|
|
notifications enabled.
|
|
|
|
Revision 1.59 2002/12/30 22:44:53 daniel
|
|
* Some work on notifications
|
|
|
|
Revision 1.58 2002/12/27 15:25:40 peter
|
|
* do not allow threadvar as loop counter
|
|
|
|
Revision 1.57 2002/11/28 11:17:02 florian
|
|
* loop node flags from node flags splitted
|
|
|
|
Revision 1.56 2002/11/25 17:43:18 peter
|
|
* splitted defbase in defutil,symutil,defcmp
|
|
* merged isconvertable and is_equal into compare_defs(_ext)
|
|
* made operator search faster by walking the list only once
|
|
|
|
Revision 1.55 2002/11/18 17:31:56 peter
|
|
* pass proccalloption to ret_in_xxx and push_xxx functions
|
|
|
|
Revision 1.54 2002/10/20 15:31:49 peter
|
|
* set funcret state for exit(0)
|
|
|
|
Revision 1.53 2002/10/05 12:43:25 carl
|
|
* fixes for Delphi 6 compilation
|
|
(warning : Some features do not work under Delphi)
|
|
|
|
Revision 1.52 2002/09/07 15:25:03 peter
|
|
* old logs removed and tabs fixed
|
|
|
|
Revision 1.51 2002/09/07 12:16:04 carl
|
|
* second part bug report 1996 fix, testrange in cordconstnode
|
|
only called if option is set (also make parsing a tiny faster)
|
|
|
|
Revision 1.50 2002/09/01 18:47:00 peter
|
|
* assignn check in exitnode changed to use a separate boolean as the
|
|
assignn can be changed to a calln
|
|
|
|
Revision 1.49 2002/09/01 08:01:16 daniel
|
|
* Removed sets from Tcallnode.det_resulttype
|
|
+ Added read/write notifications of variables. These will be usefull
|
|
for providing information for several optimizations. For example
|
|
the value of the loop variable of a for loop does matter is the
|
|
variable is read after the for loop, but if it's no longer used
|
|
or written, it doesn't matter and this can be used to optimize
|
|
the loop code generation.
|
|
|
|
Revision 1.48 2002/08/22 15:15:20 daniel
|
|
* Fixed the detection wether the first check of a for loop can be skipped
|
|
|
|
Revision 1.47 2002/08/19 19:36:43 peter
|
|
* More fixes for cross unit inlining, all tnodes are now implemented
|
|
* Moved pocall_internconst to po_internconst because it is not a
|
|
calling type at all and it conflicted when inlining of these small
|
|
functions was requested
|
|
|
|
Revision 1.46 2002/08/17 22:09:46 florian
|
|
* result type handling in tcgcal.pass_2 overhauled
|
|
* better tnode.dowrite
|
|
* some ppc stuff fixed
|
|
|
|
Revision 1.45 2002/08/17 09:23:37 florian
|
|
* first part of current_procinfo rewrite
|
|
|
|
Revision 1.44 2002/07/21 06:58:49 daniel
|
|
* Changed booleans into flags
|
|
|
|
Revision 1.43 2002/07/20 11:57:54 florian
|
|
* types.pas renamed to defbase.pas because D6 contains a types
|
|
unit so this would conflicts if D6 programms are compiled
|
|
+ Willamette/SSE2 instructions to assembler added
|
|
|
|
Revision 1.42 2002/07/20 11:18:18 daniel
|
|
* Small mistake fixed; the skip test was done before we know the for node
|
|
is correct.
|
|
|
|
Revision 1.40 2002/07/20 08:19:31 daniel
|
|
* State tracker automatically changes while loops into repeat loops
|
|
|
|
Revision 1.39 2002/07/19 12:55:27 daniel
|
|
* Further developed state tracking in whilerepeatn
|
|
|
|
Revision 1.38 2002/07/19 11:41:35 daniel
|
|
* State tracker work
|
|
* The whilen and repeatn are now completely unified into whilerepeatn. This
|
|
allows the state tracker to change while nodes automatically into
|
|
repeat nodes.
|
|
* Resulttypepass improvements to the notn. 'not not a' is optimized away and
|
|
'not(a>b)' is optimized into 'a<=b'.
|
|
* Resulttypepass improvements to the whilerepeatn. 'while not a' is optimized
|
|
by removing the notn and later switchting the true and falselabels. The
|
|
same is done with 'repeat until not a'.
|
|
|
|
Revision 1.37 2002/07/16 13:57:02 florian
|
|
* raise takes now a void pointer as at and frame address
|
|
instead of a longint
|
|
|
|
Revision 1.36 2002/07/15 18:03:15 florian
|
|
* readded removed changes
|
|
|
|
Revision 1.35 2002/07/14 18:00:44 daniel
|
|
+ Added the beginning of a state tracker. This will track the values of
|
|
variables through procedures and optimize things away.
|
|
|
|
Revision 1.34 2002/07/11 14:41:28 florian
|
|
* start of the new generic parameter handling
|
|
|
|
Revision 1.33 2002/07/01 18:46:23 peter
|
|
* internal linker
|
|
* reorganized aasm layer
|
|
|
|
Revision 1.32 2002/05/18 13:34:10 peter
|
|
* readded missing revisions
|
|
|
|
Revision 1.31 2002/05/16 19:46:38 carl
|
|
+ defines.inc -> fpcdefs.inc to avoid conflicts if compiling by hand
|
|
+ try to fix temp allocation (still in ifdef)
|
|
+ generic constructor calls
|
|
+ start of tassembler / tmodulebase class cleanup
|
|
|
|
}
|