fpc/compiler/optutils.pas
pierre d8b0ded10c Marge of more trunk fixes into fixes branch.
------------------------------------------------------------------------
r39725 | pierre | 2018-09-10 13:28:33 +0000 (Mon, 10 Sep 2018) | 1 line

 Add branches for 3.2.0, 3.2.1 and 3.3.1 versions
------------------------------------------------------------------------
--- Merging r39725 into '.':
U    tests/utils/testsuite/utests.pp
--- Recording mergeinfo for merge of r39725 into '.':
 U   .
------------------------------------------------------------------------
r39733 | pierre | 2018-09-11 08:16:56 +0000 (Tue, 11 Sep 2018) | 1 line

 sparc64-linux objects recompiled with GCC 7.3.0
------------------------------------------------------------------------
--- Merging r39733 into '.':
U    tests/test/cg/obj/readme.txt
U    tests/test/cg/obj/linux/sparc64/ctest.o
U    tests/test/cg/obj/linux/sparc64/cpptcl1.o
U    tests/test/cg/obj/linux/sparc64/cpptcl2.o
U    tests/test/cg/obj/linux/sparc64/tcext3.o
U    tests/test/cg/obj/linux/sparc64/tcext4.o
U    tests/test/cg/obj/linux/sparc64/tcext5.o
U    tests/test/cg/obj/linux/sparc64/tcext6.o
--- Recording mergeinfo for merge of r39733 into '.':
 G   .
------------------------------------------------------------------------
r39808 | pierre | 2018-09-26 09:29:33 +0000 (Wed, 26 Sep 2018) | 1 line

Disable libraries not compiling for jvm-java or jvm-android targets
------------------------------------------------------------------------
--- Merging r39808 into '.':
U    packages/fppkg/fpmake.pp
U    packages/fcl-base/fpmake.pp
U    packages/rtl-extra/fpmake.pp
U    packages/hermes/fpmake.pp
U    packages/fcl-extra/fpmake.pp
U    packages/fcl-db/fpmake.pp
U    packages/unzip/fpmake.pp
U    packages/odbc/fpmake.pp
U    packages/gdbm/fpmake.pp
U    packages/pthreads/fpmake.pp
U    packages/fcl-json/fpmake.pp
U    packages/pcap/fpmake.pp
U    packages/numlib/fpmake.pp
U    packages/rtl-generics/fpmake.pp
U    packages/zlib/fpmake.pp
U    packages/paszlib/fpmake.pp
U    packages/webidl/fpmake.pp
U    packages/regexpr/fpmake.pp
U    packages/libgd/fpmake.pp
U    packages/fcl-net/fpmake.pp
U    packages/fcl-res/fpmake.pp
U    packages/libpng/fpmake.pp
U    packages/dblib/fpmake.pp
U    packages/tcl/fpmake.pp
U    packages/openssl/fpmake.pp
U    packages/ibase/fpmake.pp
U    packages/bzip2/fpmake.pp
U    packages/fcl-sdo/fpmake.pp
U    packages/fcl-sound/fpmake.pp
U    packages/fcl-passrc/fpmake.pp
U    packages/fcl-stl/fpmake.pp
U    packages/libmicrohttpd/fpmake.pp
U    packages/mysql/fpmake.pp
U    packages/postgres/fpmake.pp
U    packages/httpd22/fpmake.pp
U    packages/httpd24/fpmake.pp
U    packages/rtl-console/fpmake.pp
U    packages/sqlite/fpmake.pp
U    packages/fftw/fpmake.pp
U    packages/fcl-pdf/fpmake.pp
U    packages/rtl-objpas/fpmake.pp
U    packages/fcl-image/fpmake.pp
U    packages/pasjpeg/fpmake.pp
U    packages/chm/fpmake.pp
U    packages/fcl-registry/fpmake.pp
U    packages/libtar/fpmake.pp
U    packages/symbolic/fpmake.pp
U    packages/libenet/fpmake.pp
U    packages/imagemagick/fpmake.pp
U    packages/fcl-xml/fpmake.pp
U    packages/oracle/fpmake.pp
U    packages/fcl-fpcunit/fpmake.pp
U    packages/fcl-js/fpmake.pp
U    packages/fcl-async/fpmake.pp
U    packages/fcl-process/fpmake.pp
U    packages/pastojs/fpmake.pp
U    packages/hash/fpmake.pp
U    packages/rtl-unicode/fpmake.pp
U    packages/fpmkunit/fpmake.pp
--- Recording mergeinfo for merge of r39808 into '.':
 G   .
------------------------------------------------------------------------
r40027 | pierre | 2018-10-24 21:37:54 +0000 (Wed, 24 Oct 2018) | 1 line

 Fix compilation of RTL for watcom target
------------------------------------------------------------------------
--- Merging r40027 into '.':
U    compiler/x86/agx86int.pas
--- Recording mergeinfo for merge of r40027 into '.':
 G   .
------------------------------------------------------------------------
r40028 | pierre | 2018-10-25 06:39:42 +0000 (Thu, 25 Oct 2018) | 1 line

Try to fix compilation error after commit #40027
------------------------------------------------------------------------
--- Merging r40028 into '.':
G    compiler/x86/agx86int.pas
--- Recording mergeinfo for merge of r40028 into '.':
 G   .
------------------------------------------------------------------------
r40102 | pierre | 2018-10-31 09:07:57 +0000 (Wed, 31 Oct 2018) | 1 line

 Replace aint (which is a compiler specific type) by ptruint type, which is defined in system unit
------------------------------------------------------------------------
--- Merging r40102 into '.':
U    tests/test/tarray5.pp
--- Recording mergeinfo for merge of r40102 into '.':
 G   .
------------------------------------------------------------------------
r40103 | pierre | 2018-10-31 09:59:45 +0000 (Wed, 31 Oct 2018) | 1 line

 Use pdword to avoid range check erro in tentryfile.getdword method
------------------------------------------------------------------------
--- Merging r40103 into '.':
U    compiler/entfile.pas
--- Recording mergeinfo for merge of r40103 into '.':
 G   .
------------------------------------------------------------------------
r40104 | pierre | 2018-10-31 10:21:51 +0000 (Wed, 31 Oct 2018) | 1 line

 Use longint type instead of AWord for Initial parameter in CalcExecutionWeigths (to avoid range error for avr compiler)
------------------------------------------------------------------------
@@
      begin
        Result:=fen_false;
        n.allocoptinfo;
<<<<<<< MINE (select with 'mc') (367)
        Weight:=PAWord(arg)^;
||||||| ORIGINAL (367)
        Weight:=max(PAWord(arg)^,1);
=======
        Weight:=max(plongint(arg)^,1);
>>>>>>> THEIRS (select with 'tc') (367)
        case n.nodetype of
          casen:
            begin
--- Merging r40104 into '.':
C    compiler/optutils.pas
--- Recording mergeinfo for merge of r40104 into '.':
 G   .
Summary of conflicts:
  Text conflicts: 1
------------------------------------------------------------------------
r40110 | pierre | 2018-10-31 14:51:23 +0000 (Wed, 31 Oct 2018) | 1 line

 Avoid range check error in MaskLength evaluation
------------------------------------------------------------------------
--- Merging r40110 into '.':
U    compiler/x86/aoptx86.pas
--- Recording mergeinfo for merge of r40110 into '.':
 G   .
------------------------------------------------------------------------
r40111 | pierre | 2018-10-31 15:47:53 +0000 (Wed, 31 Oct 2018) | 1 line

 Complement commit 40104, by changing type of executionweight in toptinfo record and adapt pass_2 code
------------------------------------------------------------------------
--- Merging r40111 into '.':
U    compiler/pass_2.pas
U    compiler/optbase.pas
--- Recording mergeinfo for merge of r40111 into '.':
 G   .
------------------------------------------------------------------------
r40112 | pierre | 2018-10-31 15:48:32 +0000 (Wed, 31 Oct 2018) | 1 line

 Disable range check completely in arm/cgcpu unit
------------------------------------------------------------------------
--- Merging r40112 into '.':
U    compiler/arm/cgcpu.pas
--- Recording mergeinfo for merge of r40112 into '.':
 G   .
------------------------------------------------------------------------
r40113 | pierre | 2018-10-31 15:49:14 +0000 (Wed, 31 Oct 2018) | 1 line

 Avoid overflow in code
------------------------------------------------------------------------
--- Merging r40113 into '.':
U    compiler/symdef.pas
--- Recording mergeinfo for merge of r40113 into '.':
 G   .
------------------------------------------------------------------------
r40114 | pierre | 2018-10-31 15:50:26 +0000 (Wed, 31 Oct 2018) | 1 line

Add explicit rtlclean/rtl targets in fullcycle rule if DOWPOCYCLE is set
------------------------------------------------------------------------
--- Merging r40114 into '.':
U    compiler/Makefile.fpc
U    compiler/Makefile
--- Recording mergeinfo for merge of r40114 into '.':
 G   .
------------------------------------------------------------------------
r40120 | pierre | 2018-10-31 23:15:22 +0000 (Wed, 31 Oct 2018) | 1 line

 Change RemoveCurrentP parameter type to tai, because GetNextInstruction does not always return a taicpu, adapt code in avr/aoptcpu unit
------------------------------------------------------------------------
--- Merging r40120 into '.':
U    compiler/aoptobj.pas
U    compiler/avr/aoptcpu.pas
--- Recording mergeinfo for merge of r40120 into '.':
 G   .
------------------------------------------------------------------------
r40121 | pierre | 2018-10-31 23:16:51 +0000 (Wed, 31 Oct 2018) | 1 line

Add check about tloadnode.symtableentry type before typecast
------------------------------------------------------------------------
--- Merging r40121 into '.':
U    compiler/ncal.pas
--- Recording mergeinfo for merge of r40121 into '.':
 G   .
------------------------------------------------------------------------
r40122 | pierre | 2018-10-31 23:18:09 +0000 (Wed, 31 Oct 2018) | 1 line

Fix typecast in FindRegDeAlloc call
------------------------------------------------------------------------
--- Merging r40122 into '.':
U    compiler/arm/aoptcpu.pas
--- Recording mergeinfo for merge of r40122 into '.':
 G   .
------------------------------------------------------------------------
r40123 | pierre | 2018-10-31 23:19:39 +0000 (Wed, 31 Oct 2018) | 1 line

 Remove unneeded typecasts in TryTOptimizeMove
------------------------------------------------------------------------
--- Merging r40123 into '.':
U    compiler/m68k/aoptcpu.pas
--- Recording mergeinfo for merge of r40123 into '.':
 G   .
------------------------------------------------------------------------
r40124 | pierre | 2018-10-31 23:20:29 +0000 (Wed, 31 Oct 2018) | 1 line

 Add global range check disable for i8086 cgcpu and x86 nx86add units
------------------------------------------------------------------------
--- Merging r40124 into '.':
U    compiler/i8086/cgcpu.pas
U    compiler/x86/nx86add.pas
--- Recording mergeinfo for merge of r40124 into '.':
 G   .
------------------------------------------------------------------------
r40131 | pierre | 2018-11-01 07:01:02 +0000 (Thu, 01 Nov 2018) | 1 line

 Remove another wrong typecast when testing  that a tai is an instruction
------------------------------------------------------------------------
--- Merging r40131 into '.':
G    compiler/m68k/aoptcpu.pas
--- Recording mergeinfo for merge of r40131 into '.':
 G   .
------------------------------------------------------------------------
r40236 | pierre | 2018-11-06 07:40:31 +0000 (Tue, 06 Nov 2018) | 1 line

 Really change extension of hs1 local variable in get_exepath
------------------------------------------------------------------------
--- Merging r40236 into '.':
U    compiler/globals.pas
--- Recording mergeinfo for merge of r40236 into '.':
 G   .
------------------------------------------------------------------------
r40237 | pierre | 2018-11-06 07:41:15 +0000 (Tue, 06 Nov 2018) | 1 line

 Disable range checking in rax86int unit
------------------------------------------------------------------------
--- Merging r40237 into '.':
U    compiler/x86/rax86int.pas
--- Recording mergeinfo for merge of r40237 into '.':
 G   .
------------------------------------------------------------------------
r40278 | pierre | 2018-11-08 20:19:54 +0000 (Thu, 08 Nov 2018) | 1 line

 Downgrade EXTDEBUG warning to note about zero size temp, as it is used for empty sets
------------------------------------------------------------------------
--- Merging r40278 into '.':
U    compiler/tgobj.pas
--- Recording mergeinfo for merge of r40278 into '.':
 G   .

git-svn-id: branches/fixes_3_2@40624 -
2018-12-23 22:27:05 +00:00

420 lines
13 KiB
ObjectPascal

{
Helper routines for the optimizer
Copyright (c) 2007 by Florian Klaempfl
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 optutils;
{$i fpcdefs.inc}
interface
uses
cclasses,
node,
globtype;
type
{ this implementation should be really improved,
its purpose is to find equal nodes }
TIndexedNodeSet = class(TFPList)
function Add(node : tnode) : boolean;
function Includes(node : tnode) : tnode;
function Remove(node : tnode) : boolean;
end;
procedure SetNodeSucessors(p,last : tnode);
procedure PrintDFAInfo(var f : text;p : tnode);
procedure PrintIndexedNodeSet(var f : text;s : TIndexedNodeSet);
{ determines the optinfo.defsum field for the given node
this field contains a sum of all expressions defined by
all child expressions reachable through p
}
procedure CalcDefSum(p : tnode);
{ calculates/estimates the field execution weight of optinfo }
procedure CalcExecutionWeights(p : tnode;Initial : longint = 100);
{ returns true, if n is a valid node and has life info }
function has_life_info(n : tnode) : boolean;
implementation
uses
cutils,
verbose,
optbase,
ncal,nbas,nflw,nutils,nset,ncon;
function TIndexedNodeSet.Add(node : tnode) : boolean;
var
i : Integer;
p : tnode;
begin
node.allocoptinfo;
p:=Includes(node);
if assigned(p) then
begin
result:=false;
node.optinfo^.index:=p.optinfo^.index;
end
else
begin
i:=inherited Add(node);
node.optinfo^.index:=i;
result:=true;
end
end;
function TIndexedNodeSet.Includes(node : tnode) : tnode;
var
i : longint;
begin
for i:=0 to Count-1 do
if tnode(List^[i]).isequal(node) then
begin
result:=tnode(List^[i]);
exit;
end;
result:=nil;
end;
function TIndexedNodeSet.Remove(node : tnode) : boolean;
var
p : tnode;
begin
result:=false;
p:=Includes(node);
if assigned(p) then
begin
if inherited Remove(p)<>-1 then
result:=true;
end;
end;
procedure PrintIndexedNodeSet(var f : text;s : TIndexedNodeSet);
var
i : integer;
begin
for i:=0 to s.count-1 do
begin
writeln(f,'=============================== Node ',i,' ===============================');
printnode(f,tnode(s[i]));
writeln(f);
end;
end;
function PrintNodeDFA(var n: tnode; arg: pointer): foreachnoderesult;
begin
if assigned(n.optinfo) and ((n.optinfo^.life<>nil) or (n.optinfo^.use<>nil) or (n.optinfo^.def<>nil)) then
begin
write(text(arg^),nodetype2str[n.nodetype],'(',n.fileinfo.line,',',n.fileinfo.column,') Life: ');
PrintDFASet(text(arg^),n.optinfo^.life);
write(text(arg^),' Def: ');
PrintDFASet(text(arg^),n.optinfo^.def);
write(text(arg^),' Use: ');
PrintDFASet(text(arg^),n.optinfo^.use);
if assigned(n.successor) then
write(text(arg^),' Successor: ',nodetype2str[n.successor.nodetype],'(',n.successor.fileinfo.line,',',n.successor.fileinfo.column,')')
else
write(text(arg^),' Successor: nil');
write(text(arg^),' DefSum: ');
PrintDFASet(text(arg^),n.optinfo^.defsum);
writeln(text(arg^));
end;
result:=fen_false;
end;
procedure PrintDFAInfo(var f : text;p : tnode);
begin
foreachnodestatic(pm_postprocess,p,@PrintNodeDFA,@f);
end;
procedure SetNodeSucessors(p,last : tnode);
var
Continuestack : TFPList;
Breakstack : TFPList;
{ sets the successor nodes of a node tree block
returns the first node of the tree if it's a controll flow node }
function DoSet(p : tnode;succ : tnode) : tnode;
var
hp1,hp2 : tnode;
i : longint;
begin
result:=nil;
if p=nil then
exit;
case p.nodetype of
statementn:
begin
hp1:=p;
result:=p;
while assigned(hp1) do
begin
{ does another statement follow? }
if assigned(tstatementnode(hp1).next) then
begin
hp2:=DoSet(tstatementnode(hp1).statement,tstatementnode(hp1).next);
if assigned(hp2) then
tstatementnode(hp1).successor:=hp2
else
tstatementnode(hp1).successor:=tstatementnode(hp1).next;
end
else
begin
hp2:=DoSet(tstatementnode(hp1).statement,succ);
if assigned(hp2) then
tstatementnode(hp1).successor:=hp2
else
tstatementnode(hp1).successor:=succ;
end;
hp1:=tstatementnode(hp1).next;
end;
end;
blockn:
begin
result:=p;
DoSet(tblocknode(p).statements,succ);
if assigned(tblocknode(p).statements) then
p.successor:=tblocknode(p).statements
else
p.successor:=succ;
end;
forn:
begin
Breakstack.Add(succ);
Continuestack.Add(p);
result:=p;
{ the successor of the last node of the for body is the dummy loop iteration node
it allows the dfa to inject needed life information into the loop }
tfornode(p).loopiteration:=cnothingnode.create;
DoSet(tfornode(p).t2,tfornode(p).loopiteration);
p.successor:=succ;
Breakstack.Delete(Breakstack.Count-1);
Continuestack.Delete(Continuestack.Count-1);
end;
breakn:
begin
result:=p;
p.successor:=tnode(Breakstack.Last);
end;
continuen:
begin
result:=p;
p.successor:=tnode(Continuestack.Last);
end;
whilerepeatn:
begin
Breakstack.Add(succ);
Continuestack.Add(p);
result:=p;
{ the successor of the last node of the while/repeat body is the while node itself }
DoSet(twhilerepeatnode(p).right,p);
p.successor:=succ;
{ special case: we do not do a dyn. dfa, but we should handle endless loops }
if is_constboolnode(twhilerepeatnode(p).left) then
begin
if ((lnf_testatbegin in twhilerepeatnode(p).loopflags) and
getbooleanvalue(twhilerepeatnode(p).left)) or (not(lnf_testatbegin in twhilerepeatnode(p).loopflags) and
not(getbooleanvalue(twhilerepeatnode(p).left))) then
p.successor:=nil;
end;
Breakstack.Delete(Breakstack.Count-1);
Continuestack.Delete(Continuestack.Count-1);
end;
ifn:
begin
result:=p;
DoSet(tifnode(p).right,succ);
DoSet(tifnode(p).t1,succ);
p.successor:=succ;
end;
labeln:
begin
result:=p;
if assigned(tlabelnode(p).left) then
begin
DoSet(tlabelnode(p).left,succ);
p.successor:=tlabelnode(p).left;
end
else
p.successor:=succ;
end;
assignn:
begin
result:=p;
p.successor:=succ;
end;
goton:
begin
result:=p;
if not(assigned(tgotonode(p).labelnode)) then
internalerror(2007050701);
p.successor:=tgotonode(p).labelnode;
end;
exitn:
begin
result:=p;
p.successor:=nil;
end;
casen:
begin
result:=p;
DoSet(tcasenode(p).elseblock,succ);
for i:=0 to tcasenode(p).blocks.count-1 do
DoSet(pcaseblock(tcasenode(p).blocks[i])^.statement,succ);
p.successor:=succ;
end;
calln:
begin
{ not sure if this is enough (FK) }
result:=p;
if not(cnf_call_never_returns in tcallnode(p).callnodeflags) then
p.successor:=succ;
end;
inlinen:
begin
{ not sure if this is enough (FK) }
result:=p;
p.successor:=succ;
end;
loadn,
tempcreaten,
tempdeleten,
nothingn:
begin
result:=p;
p.successor:=succ;
end;
raisen:
begin
result:=p;
{ raise never returns }
p.successor:=nil;
end;
withn,
tryexceptn,
tryfinallyn,
onn:
internalerror(2007050501);
end;
end;
begin
Breakstack:=TFPList.Create;
Continuestack:=TFPList.Create;
DoSet(p,last);
Continuestack.Free;
Breakstack.Free;
end;
var
sum : TDFASet;
function adddef(var n: tnode; arg: pointer): foreachnoderesult;
begin
if assigned(n.optinfo) then
DFASetIncludeSet(sum,n.optinfo^.def);
Result:=fen_false;
end;
procedure CalcDefSum(p : tnode);
begin
p.allocoptinfo;
if not assigned(p.optinfo^.defsum) then
begin
sum:=nil;
foreachnodestatic(pm_postprocess,p,@adddef,nil);
p.optinfo^.defsum:=sum;
end;
end;
function SetExecutionWeight(var n: tnode; arg: pointer): foreachnoderesult;
var
Weight : longint;
i : Integer;
begin
Result:=fen_false;
n.allocoptinfo;
Weight:=max(plongint(arg)^,1);
case n.nodetype of
casen:
begin
CalcExecutionWeights(tcasenode(n).left,Weight);
for i:=0 to tcasenode(n).blocks.count-1 do
CalcExecutionWeights(pcaseblock(tcasenode(n).blocks[i])^.statement,max(1,Weight div case_count_labels(tcasenode(n).labels)));
CalcExecutionWeights(tcasenode(n).elseblock,max(1,Weight div case_count_labels(tcasenode(n).labels)));
Result:=fen_norecurse_false;
end;
whilerepeatn:
begin
CalcExecutionWeights(twhilerepeatnode(n).right,max(Weight,1)*8);
CalcExecutionWeights(twhilerepeatnode(n).left,max(Weight,1)*8);
Result:=fen_norecurse_false;
end;
ifn:
begin
CalcExecutionWeights(tifnode(n).left,Weight);
CalcExecutionWeights(tifnode(n).right,max(Weight div 2,1));
CalcExecutionWeights(tifnode(n).t1,max(Weight div 2,1));
Result:=fen_norecurse_false;
end;
else
{$push}
{ The code below emits two warnings if ptruint and aword are the same type }
{$warn 4044 off}
{$warn 6018 off}
if PAWord(arg)^ > high(aword) then
n.optinfo^.executionweight:=high(AWord)
else
n.optinfo^.executionweight:=PAWord(arg)^;
{$pop}
end;
end;
procedure CalcExecutionWeights(p : tnode;Initial : longint = 100);
begin
if assigned(p) then
foreachnodestatic(pm_postprocess,p,@SetExecutionWeight,Pointer(@Initial));
end;
function has_life_info(n : tnode) : boolean;
begin
result:=assigned(n) and assigned(n.optinfo) and
assigned(n.optinfo^.life);
end;
end.