1 /* $Id: ud_copy.c,v 1.6 1994/06/24 10:33:25 ceriel Exp $ */
3 * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
4 * See the copyright notice in the ACK home directory, in the file "Copyright".
6 /* C O P Y P R O P A G A T I O N */
11 #include "../share/types.h"
13 #include "../share/debug.h"
14 #include "../share/global.h"
15 #include "../share/alloc.h"
16 #include "../share/lset.h"
17 #include "../share/cset.h"
18 #include "../share/def.h"
19 #include "../share/aux.h"
20 #include "../share/locals.h"
21 #include "../ud/ud_defs.h"
28 line_p *copies; /* table of copies; every entry points to the
31 short *def_to_copynr; /* table that maps a 'definition'-number to a
34 short nrcopies; /* number of copies in the current procedure
35 * (length of copies-table)
38 #define COPY_NR(c) def_to_copynr[c]
39 #define CHANGED(v,b) (Cis_elem(v,CHGVARS(b)) || Cis_elem(IMPLICIT_DEF(v),GEN(b)))
45 STATIC traverse_defs(p,action)
55 if (action == COUNT) {
58 copies = (line_p *) newmap(nrcopies);
59 def_to_copynr = newtable(nrdefs);
62 if (defcnt > nrdefs) return;
63 for (b = p->p_start; b != (bblock_p) 0; b = b->b_next) {
64 for (l = b->b_start; l != (line_p) 0; l = l->l_next) {
65 if (defs[defcnt] == l) {
67 var_nr(PREV(l),&v,&found);
69 if (action == COUNT) {
73 def_to_copynr[defcnt] =
78 if (++defcnt > nrdefs) return;
86 STATIC make_copytab(p)
89 /* Make a table of all copies appearing in procedure p.
90 * We first count how many there are, because we
91 * have to allocate a dynamic array of the correct size.
94 traverse_defs(p,COUNT);
100 STATIC bool is_changed(varl,start,stop)
101 line_p varl, start, stop;
103 /* See if the variable used by instruction varl
104 * is changed anywhere between 'start' and 'stop'
111 var_nr(varl,&v,&found);
113 return TRUE; /* We don't maintain ud-info for this variable */
115 for (l = start; l != (line_p) 0 && l != stop; l = l->l_next) {
116 if (does_expl_def(l) && same_var(varl,l)) return TRUE;
117 if (does_impl_def(l) && affected(varl,v,l)) return TRUE;
124 STATIC gen_kill_copies(p)
127 /* Compute C_GEN and C_KILL for every basic block
132 register bblock_p b,n;
135 short copycnt = 1, defcnt = 1;
137 for (b = p->p_start; b != (bblock_p) 0; b = b->b_next) {
138 C_GEN(b) = Cempty_set(nrcopies);
139 C_KILL(b) = Cempty_set(nrcopies);
141 if (nrcopies == 0) return;
142 for (b = p->p_start; b != (bblock_p) 0; b = b->b_next) {
143 for (l = b->b_start; l != (line_p) 0; l = l->l_next) {
144 if (copies[copycnt] == l) {
145 var_nr(PREV(l),&v,&found);
147 for (n = p->p_start; n != (bblock_p) 0;
149 if (n != b && CHANGED(v,n) &&
150 Cis_elem(EXPL_TO_DEFNR(defcnt),IN(n))) {
151 Cadd(copycnt,&C_KILL(n));
154 if (is_changed(PREV(l),l,(line_p) 0)) {
155 Cadd(copycnt,&C_KILL(b));
157 Cadd(copycnt,&C_GEN(b));
159 if (++copycnt > nrcopies) return;
161 if (defs[defcnt] == l) defcnt++;
168 STATIC intersect_outs(bbset,setp,full_set)
172 /* Take the intersection of C_OUT(b), for all b in bbset,
173 * and put the result in setp.
178 Ccopy_set(full_set,setp);
179 for (i = Lfirst(bbset); i != (Lindex) 0; i = Lnext(i,bbset)) {
180 Cintersect(C_OUT((bblock_p) Lelem(i)), setp);
186 STATIC init_cin(p,full_set)
190 /* Initialize C_IN(b) and C_OUT(b), for every basic block b.
191 * C_IN of the root of the CFG (i.e. the procedure entry block)
192 * will contain every copy, as it trivially holds that for
193 * every copy "s: A := B" there is no assignment to B on any
194 * path from s to the beginning of the root (because PRED(root)=empty).
195 * C_IN and C_OUT of the root will never be changed.
196 * For all remaining blocks b, C_IN(b) is initialized to the set of
197 * all copies, and C_OUT is set to all copies but those killed in b.
201 bblock_p root = p->p_start;
203 C_IN(root) = Cempty_set(nrcopies);
204 Ccopy_set(full_set,&C_IN(root)); /* full_set is the set of all copies */
205 /* C_OUT(root) = {all copies} - C_KILL(root) + C_GEN(root) */
206 C_OUT(root) = Cempty_set(nrcopies);
207 Ccopy_set(full_set,&C_OUT(root));
208 Csubtract(C_KILL(root),&C_OUT(root));
209 Cjoin(C_GEN(root),&C_OUT(root));
210 for (b = root->b_next; b != (bblock_p) 0; b = b->b_next) {
211 C_IN(b) = Cempty_set(nrcopies);
212 Ccopy_set(full_set,&C_IN(b));
213 C_OUT(b) = Cempty_set(nrcopies);
214 Ccopy_set(full_set,&C_OUT(b));
215 Csubtract(C_KILL(b),&C_OUT(b));
224 /* Solve the data flow equations for reaching
225 * definitions of procedure p.
226 * These equations are:
227 * (1) C_OUT(b) = C_IN(b) - C_KILL(b) + C_GEN(b)
228 * (2) C_IN(b) = C_OUT(p1) * .. * C_OUT(pn)
229 * (3) C_IN(root) = {all copies} ;
230 * where PRED(b) = {p1, .. , pn}
231 * and '*' denotes set intersection.
232 * We use the iterative algorithm of Aho&Ullman to
233 * solve the equations.
241 /* initializations */
242 full_set = Cempty_set(nrcopies);
243 for (n = 1; n <= nrcopies; n++) {
246 newin = Cempty_set(nrcopies);
247 init_cin(p,full_set);
252 for (b = p->p_start->b_next; b != (bblock_p) 0; b = b->b_next) {
253 intersect_outs(b->b_pred, &newin,full_set);
254 /* newin = C_OUT(p1) * .. * C_OUT(pn) */
255 if (!Cequal(newin,C_IN(b))) {
257 Ccopy_set(newin, &C_IN(b));
258 Ccopy_set(C_IN(b), &C_OUT(b));
259 Csubtract(C_KILL(b), &C_OUT(b));
260 Cjoin(C_GEN(b), &C_OUT(b));
265 Cdeleteset(full_set);
273 /* Determine which copies procedure p has. Compute C_IN(b),
274 * for every basic block b.
277 make_copytab(p); /* Make a table of all copies */
278 gen_kill_copies(p); /* Compute C_GEN(b) and C_KILL(b), for every b */
279 solve_cin(p); /* Solve equations for C_IN(b) */
287 /* See if the definition def is also a 'copy', i.e. an
288 * statement of the form 'A := B' (or, in EM terminology:
289 * a sequence 'Load Variable; Store Variable').
297 if (lhs == (line_p) 0) return FALSE;
302 return instr == op_stl || instr == op_ste;
305 return instr == op_sdl || instr == op_sde;
318 /* The variable referenced by the EM instruction 'old'
319 * must be replaced by the variable referenced by 'new'.
328 if (TYPE(old) == OPOBJECT) {
329 printf("global var.");
331 printf("local var. with off. %ld",off_set(old));
332 find_local(off_set(old),&nr,&ok);
335 printf(",score %ld",loc->lc_score);
337 printf(" replaced by ");
338 if (TYPE(new) == OPOBJECT) {
339 printf("global var.");
341 printf("local var. with off. %ld",off_set(new));
342 find_local(off_set(new),&nr,&ok);
345 printf(",score %ld",loc->lc_score);
350 if (TYPE(l) != TYPE(new)) {
351 l = newline(TYPE(new));
352 l->l_instr = INSTR(new);
360 SHORT(l) = SHORT(new);
363 OFFSET(l) = OFFSET(new);
372 bool value_retained(copy,defnr,use,b)
377 /* See if the right hand side variable of the
378 * copy still has the same value at 'use'.
379 * If the copy and the use are in the same
380 * basic block (defnr = 0), search from the
381 * copy to the use, to see if the rhs variable
382 * is changed. If the copy is in another block,
383 * defnr is the definition-number of the copy.
384 * Search from the beginning of the block to
385 * the use, to see if the rhs is changed; if not,
386 * check that the copy is in C_IN(b).
392 start = (defnr == 0 ? copy : b->b_start);
393 return !is_changed(rhs,start,use) &&
394 (defnr == 0 || Cis_elem(COPY_NR(defnr), C_IN(b)));