79 lines
2.9 KiB
Plaintext
79 lines
2.9 KiB
Plaintext
|
.NH 2
|
||
|
Implementation
|
||
|
.PP
|
||
|
UD first builds a number of tables:
|
||
|
.IP locals: 9
|
||
|
contains information about the local variables of the
|
||
|
current procedure (offset,size,whether a register message was found
|
||
|
for it and, if so, the score field of that message)
|
||
|
.IP defs:
|
||
|
a table of all explicit definitions appearing in the
|
||
|
current procedure.
|
||
|
.IP copies:
|
||
|
a table of all copies appearing in the
|
||
|
current procedure.
|
||
|
.LP
|
||
|
Every variable (local as well as global), definition and copy
|
||
|
is identified by a unique number, which is the index
|
||
|
in the table.
|
||
|
All tables are constructed by traversing the EM code.
|
||
|
A fourth table, "vardefs" is used, indexed by a 'variable number',
|
||
|
which contains for every variable the set of explicit definitions of it.
|
||
|
Also, for each basic block b, the set CHGVARS containing all variables
|
||
|
changed by it is computed.
|
||
|
.PP
|
||
|
The GEN sets are obtained in one scan over the EM text,
|
||
|
by analyzing every EM instruction.
|
||
|
The KILL set of a basic block b is computed by looking at the
|
||
|
set of variables
|
||
|
changed by b (i.e. CHGVARS[b]).
|
||
|
For every such variable v, all explicit definitions to v
|
||
|
(i.e. vardefs[v]) that are not in GEN[b] are added to KILL[b].
|
||
|
Also, the implicit defininition of v is added to KILL[b].
|
||
|
Next, the data flow equations for use-definition information
|
||
|
are solved,
|
||
|
using a straight forward, iterative algorithm.
|
||
|
All sets are represented as bitvectors, so the operations
|
||
|
on sets (union, difference) can be implemented efficiently.
|
||
|
.PP
|
||
|
The C_GEN and C_KILL sets are computed simultaneously in one scan
|
||
|
over the EM text.
|
||
|
For every copy A := B appearing in basic block b we do
|
||
|
the following:
|
||
|
.IP 1.
|
||
|
for every basic block n /= b that changes B, see if the definition A := B
|
||
|
reaches the beginning of n (i.e. check if the index number of A := B in
|
||
|
the "defs" table is an element of IN[n]);
|
||
|
if so, add the copy to C_KILL[n]
|
||
|
.IP 2.
|
||
|
if B is redefined later on in b, add the copy to C_KILL[b], else
|
||
|
add it to C_GEN[b]
|
||
|
.LP
|
||
|
C_IN and C_OUT are computed from C_GEN and C_KILL via the second set of
|
||
|
data flow equations.
|
||
|
.PP
|
||
|
Finally, in one last scan all opportunities for optimization are
|
||
|
detected.
|
||
|
For every use u of a variable A, we check if
|
||
|
there is a unique explicit definition d reaching u.
|
||
|
.sp
|
||
|
If the definition is a copy A := B and B has the same value at d as
|
||
|
at u, then the use of A at u may be changed into B.
|
||
|
The latter condition can be verified as follows:
|
||
|
.IP -
|
||
|
if u and d are in the same basic block, see if there is
|
||
|
any assignment to B in between d and u
|
||
|
.IP -
|
||
|
if u and d are in different basic blocks, the condition is
|
||
|
satisfied if there is no assignment to B in the block of u prior to u
|
||
|
and d is in C_IN[b].
|
||
|
.LP
|
||
|
Before the transformation is actually done, UD first makes sure the
|
||
|
alteration is really desirable, as described before.
|
||
|
The information needed for this purpose (access costs of local and
|
||
|
global variables) is read from a machine descriptor file.
|
||
|
.sp
|
||
|
If the only definition reaching u has the form "A := constant", the use
|
||
|
of A at u is replaced by the constant.
|
||
|
|