* Copyright (c) 1980 Regents of the University of California.
* All rights reserved. The Berkeley software License Agreement
* specifies the terms and conditions for redistribution.
static char sccsid
[] = "@(#)bb.c 5.1 (Berkeley) 6/7/85";
* Basic block optimizations.
* University of Utah CS Dept modification history:
* Revision 2.1 84/07/19 12:01:20 donn
* Changed comment headers for UofU.
* Revision 1.2 84/04/02 14:22:49 donn
* Bug in copy propagation missed places where temporaries are assigned to
* by OPSTAREQ or OPPLUSEQ, e.g. exponentiation with an integer constant
* power, expanded inline.
* This file contains code for determination of basic blocks,
* as well as some other optimization supporting routines
* [including the main routine 'optimize()'].
* The compiler's general debugging flag ['debugflag'] has been
* extended to provide the capability of having multiple flags
* which are contained in an array. If the option -d is used,
* then the flag debugflag[0] is set. If a sequence of one or more
* numbers are given (e.g, -d3,7,12), then the flags debugflag[3],
* debugflag[7], and debugflag[12] are set. The maximum number of
* flags available is specified in the defines.h file.
Bblockp firstblock
= NULL
; /* first block in buffer */
Bblockp lastblock
= NULL
; /* last block in buffer */
if (debugflag
[2]) showbuffer ();
if (debugflag
[3]) showbuffer ();
if (debugflag
[4]) showbuffer ();
if (debugflag
[9]) showbuffer ();
for (sl
= firstslot
; sl
; sl
= nextsl
)
if (sl
->type
== SKFRTEMP
)
templist
= mkchain (sl
->expr
,templist
);
sl
->expr
= tempalloc (sl
->expr
);
* creates a new basic block record
LOCAL Bblockp
newblock (sl
)
firstblock
= lastblock
= bb
;
* scans slot buffer, creating basic block records
for (sl
= firstslot
; sl
; sl
= sl
->next
)
if (containscall(sl
->expr
))
badthing("SKtype", "formbblock", type
);
* frees all basic block records
* as well as the id and value node chains hanging off the bb and their
* respective cross link chains (IDlist, DUPlist and NODElist structs)
for (bb
= firstblock
; bb
; bb
= next
)
for(idp
= bb
->headid
; idp
; idp
= next
)
for(nodelp
= idp
->headnodelist
; nodelp
; nodelp
= next
)
for(vp
= bb
->headnode
; vp
; vp
= next
)
for(idlp
= vp
->headdeplist
; idlp
; idlp
= next
)
for(duplp
= vp
->headduplist
; duplp
; duplp
= next
)
firstblock
= lastblock
= NULL
;
/* structure for maintaining records on copy statements */
LOCAL chainp sublist
; /* list of copy statements */
LOCAL
int prop1count
; /* count of number of temporaries eliminated */
LOCAL
int prop2count
; /* count of number of uses of temporaries replaced */
* eliminates copy statements of the form T1 = T2 from the intermediate
* code, where T1 and T2 are temporary variables which are each
* set only once; eliminates the copy statement and replaces each
* use of T1 by T2 (T1 is therefore totally eliminated).
for (sl
= firstslot
; sl
; sl
= sl
->next
)
sl
->expr
= rmcommaop (sl
->expr
,sl
);
prop1count
= prop2count
= 0;
for (sl
= firstslot
; sl
; sl
= nextsl
)
if ((sl
->type
== SKFRTEMP
) && subfor (expr
))
else if (expr
&& expr
->tag
== TEXPR
&&
expr
->exprblock
.opcode
== OPASSIGN
)
lp
= (Tempp
) expr
->exprblock
.leftp
;
rp
= (Tempp
) expr
->exprblock
.rightp
;
if (lp
->tag
== TTEMP
&& rp
->tag
== TTEMP
)
if (subfor(lp
->memalloc
) == rp
->memalloc
&& !subfor (rp
->memalloc
))
"%d temporarie%s replaced by copy propagation (%d use%s)\n",
prop1count
,(prop1count
==1 ? "" : "s"),
prop2count
,(prop2count
==1 ? "" : "s") );
* finds copy statements and enters information in table
for (sl
= firstslot
; sl
; sl
= sl
->next
)
if (expr
) switch (expr
->tag
)
for (cp
= expr
->listblock
.listp
; cp
; cp
= cp
->nextp
)
expr
= (expptr
) cp
->datap
;
* checks an individual expression
int oc
= expr
->exprblock
.opcode
;
if (oc
== OPASSIGN
|| oc
== OPPLUSEQ
|| oc
== OPSTAREQ
)
lp
= (Tempp
) expr
->exprblock
.leftp
;
rp
= (Tempp
) expr
->exprblock
.rightp
;
if (rp
->tag
== TTEMP
&& oc
== OPASSIGN
)
enter (lp
->memalloc
, rp
->memalloc
);
enter (lp
->memalloc
, ENULL
);
* Enters the given memalloc values in the table (or update if they
* are already there), for the assignment statement m1 = m2.
* If m2 is NULL, this indicates that the assignment is not a copy
for (cp
= sublist
; cp
; cp
= cp
->nextp
)
old
= (Subrecp
) cp
->datap
;
sublist
= mkchain (new, sublist
);
* looks for record for the given memalloc value
LOCAL Subrecp
lookup (mem
)
for (cp
= sublist
; cp
; cp
= cp
->nextp
)
rec
= (Subrecp
) cp
->datap
;
* checks to see if there is a substitute for given memalloc value
if (rec
&& rec
->sets
== 1)
if (rec2
&& rec2
->sets
== 1)
* actually propagates the information
propagate (expr
->exprblock
.leftp
);
propagate (expr
->exprblock
.rightp
);
propagate (expr
->addrblock
.vleng
);
propagate (expr
->addrblock
.memoffset
);
for (t
= expr
->listblock
.listp
; t
; t
= t
->nextp
)
new = subfor (expr
->tempblock
.memalloc
);
expr
->tempblock
.memalloc
= new;
* allocates ADDR blocks for each TEMP in the expression
LOCAL expptr
tempalloc (expr
)
expr
->exprblock
.leftp
= tempalloc (expr
->exprblock
.leftp
);
expr
->exprblock
.rightp
= tempalloc (expr
->exprblock
.rightp
);
expr
->addrblock
.vleng
= tempalloc (expr
->addrblock
.vleng
);
expr
->addrblock
.memoffset
= tempalloc (expr
->addrblock
.memoffset
);
for (t
= expr
->listblock
.listp
; t
; t
= t
->nextp
)
t
->datap
= (tagptr
) tempalloc (t
->datap
);
return (expptr
) cpexpr (altmpn (expr
));
/********************* debugging routines *********************/
fprintf (diagfile
,"\nAn expression [%s]----->\n",s
);
fprintf (diagfile
,"\n-------------end of expr--------------\n");
* dump the basic block buffer, including expressions, mnemonically
fprintf (diagfile
,"Basic blocks with first and last slots ----------\n");
for (i
=1, bb
= firstblock
; bb
; i
++, bb
= bb
->next
)
fprintf (diagfile
,"%2d. %d %d\n",i
,bb
->first
,bb
->last
);
fprintf (diagfile
,"Slots and expressions ----------\n");
fprintf (diagfile
,"tag pointer vtype vclass vstg vleng\n");
fprintf (diagfile
," ADDR memno memoffset istemp ntempelt varleng\n");
fprintf (diagfile
," TEMP memalloc istemp ntempelt varleng\n");
fprintf (diagfile
," EXPR opcode leftp rightp\n");
fprintf (diagfile
," LIST type listp\n");
for (i
=1, sl
= firstslot
; sl
; i
++, sl
= sl
->next
)
fprintf (diagfile
,"%2d. ",i
);
fprintf (diagfile
,"---------- End of showbuffer ----------\n");
* dumps a single slot in the code buffer
LOCAL charptr Zslot
[] = {"NULL",
"IFN","GOTO","LABEL","EQ","CALL","CMGOTO","STOP","DOHEAD",
"ENDDO","ARIF","RETURN","ASGOTO","PAUSE","ASSIGN","IOIFN","FRTEMP"};
fprintf (diagfile
,"(%2d) %d %s %d\n",
sl
->lineno
,sl
,Zslot
[sl
->type
],sl
->label
);
fprintf (diagfile
,"%s\n",Zslot
[type
]);
* displays the given expression at the given indentation, showing
* its subexpressions at further indentations
LOCAL charptr Ztag
[] = {"----",
"NAME","CONST","EXPR","ADDR","TEMP","PRIM","LIST","IMPLDO","ERROR"};
LOCAL charptr Zstg
[] = {"unk",
"ARG","AUTO","BSS","INIT","CONST","EXT","INTR","STFUNCT",
"COMMON","EQUIV","REG","LENG","NULL","PREG"};
LOCAL charptr Zclass
[] = {"unk",
"PARAM","VAR","ENTRY","MAIN","BLOCK","PROC","NAMELIST"};
LOCAL charptr Zop
[] = {"----",
"PLUS","MINUS","STAR","SLASH","POWER","NEG","OR","AND","EQV",
"NEQV","NOT","CONCAT","LT","EQ","GT","LE","NE","GE","CALL",
"CCALL","ASSIGN","PLUSEQ","STAREQ","CONV","LSHIFT","MOD",
"COMMA","QUEST","COLON","ABS","MIN","MAX","ADDR","INDIRECT",
"BITOR","BITAND","BITXOR","BITNOT","RSHIFT","PAREN"};
LOCAL charptr Ztype
[] = {"unk",
"ADDR","SHORT","LONG","REAL","DREAL","COMPLEX","DCOMPLEX",
"LOGICAL","CHAR","SUBR","ERROR"};
#define PRHEAD(q) fprintf(diagfile,"%s %d %s %s %s %d", \
Ztag[q->tag], q, Ztype[q->headblock.vtype], \
Zclass[q->headblock.vclass], Zstg[q->headblock.vstg], \
#define SHOWEXPR(p) showexpr(p,indent+2)
type
=p
->constblock
.vtype
;
fprintf(diagfile
," ISCHAR ccp= %d\n",
p
->constblock
.const.ccp
);
SHOWEXPR(p
->constblock
.vleng
);
fprintf(diagfile
," ci= %d\n",p
->constblock
.const.ci
);
fprintf(diagfile
," cd[0]= %e\n",p
->constblock
.const.cd
[0]);
else fprintf(diagfile
," cd[0]= %e cd[1]= %e\n",
p
->constblock
.const.cd
[0],
p
->constblock
.const.cd
[1] );
" memno= %d %d %d %d %d\n",
p
->addrblock
.memno
,p
->addrblock
.memoffset
,p
->addrblock
.istemp
,
p
->addrblock
.ntempelt
,p
->addrblock
.varleng
);
SHOWEXPR(p
->addrblock
.vleng
);
SHOWEXPR(p
->addrblock
.memoffset
);
fprintf(diagfile
,"%s %d %s %s %d",
Ztag
[p
->tag
], p
, Ztype
[p
->headblock
.vtype
],
Zclass
[p
->headblock
.vclass
],
" memalloc= %d %d %d %d\n",
p
->tempblock
.memalloc
,p
->tempblock
.istemp
,
p
->tempblock
.ntempelt
,p
->tempblock
.varleng
);
SHOWEXPR(p
->tempblock
.vleng
);
SHOWEXPR(p
->tempblock
.memalloc
);
fprintf(diagfile
,"ERROR %d\n",p
);
fprintf(diagfile
,"NAME %d\n",p
);
fprintf(diagfile
,"PRIM %d --- not implemented\n",p
);
fprintf(diagfile
," opcode= %s %d %d\n",
Zop
[p
->exprblock
.opcode
],p
->exprblock
.leftp
,
SHOWEXPR(p
->exprblock
.leftp
);
SHOWEXPR(p
->exprblock
.rightp
);
fprintf(diagfile
,"LIST %d %s %d\n",p
,
Ztype
[p
->listblock
.vtype
],p
->listblock
.listp
);
for(q
= p
->listblock
.listp
; q
; q
= q
->nextp
)
fprintf(diagfile
,"END LIST %d\n",p
);
fprintf(diagfile
,"showexpr BAD TAG= %d at %d \n",p
->tag
,p
);
selective()/************************************/
fprintf (stderr
,"SELECTIVE OUTPUT\n");
for (sl
=firstslot
;sl
;sl
=sl
->next
)
fprintf (stderr
,"%d. ",i
);
if (containscall(p
->addrblock
.vleng
)
|| containscall(p
->addrblock
.memoffset
))
if (p
->exprblock
.opcode
== OPCALL
||
p
->exprblock
.opcode
== OPCCALL
)
if (containscall(p
->exprblock
.vleng
) ||
containscall(p
->exprblock
.leftp
) ||
containscall(p
->exprblock
.rightp
))
if (containscall(cp
->datap
))