1 /* $Id: cs_elim.c,v 1.7 1994/06/24 10:22:09 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".
8 #include "../share/types.h"
9 #include "../share/alloc.h"
10 #include "../share/lset.h"
11 #include "../share/aux.h"
12 #include "../share/global.h"
13 #include "../share/debug.h"
19 #include "cs_profit.h"
20 #include "cs_partit.h"
26 /* Doubly link the lines in l1 and l2. */
34 STATIC remove_lines(first, last)
37 /* Throw away the lines between and including first and last.
38 * Don't worry about any pointers; the (must) have been taken care of.
40 register line_p lnp, next;
42 last->l_next = (line_p) 0; /* Delimit the list. */
43 for (lnp = first; lnp != (line_p) 0; lnp = next) {
49 STATIC bool contained(ocp1, ocp2)
52 /* Determine whether ocp1 is contained within ocp2. */
54 register line_p lnp, next;
56 for (lnp = ocp2->oc_lfirst; lnp != (line_p) 0; lnp = next) {
57 next = lnp != ocp2->oc_llast ? lnp->l_next : (line_p) 0;
59 if (lnp == ocp1->oc_llast) return TRUE;
64 STATIC delete(ocp, start)
68 /* Delete all occurrences that are contained within ocp.
69 * They must have been entered in the list before start:
70 * if an expression is contained with an other, its operator line
71 * appears before the operator line of the other because EM-expressions
74 register avail_p ravp;
75 register Lindex i, next;
77 for (ravp = start; ravp != (avail_p) 0; ravp = ravp->av_before) {
78 for (i = Lfirst(ravp->av_occurs); i != (Lindex) 0; i = next) {
79 next = Lnext(i, ravp->av_occurs);
81 if (contained(occ_elem(i), ocp)) {
82 OUTTRACE("delete contained occurrence", 0);
84 SHOWOCCUR(occ_elem(i));
86 oldoccur(occ_elem(i));
87 Lremove(Lelem(i), &ravp->av_occurs);
93 STATIC complete_aar(lnp, instr, descr_vn)
98 /* Lnp is an instruction that loads the address of an array-element.
99 * Instr tells us what effect we should achieve; load (instr is op_lar)
100 * or store (instr is op_sar) this array-element. Descr_vn is the
101 * valuenumber of the address of the descriptor of this array.
102 * We append a loi or sti of the correct number of bytes.
104 register line_p lindir;
106 lindir = int_line(array_elemsize(descr_vn));
107 lindir->l_instr = instr == op_lar ? op_loi : op_sti;
108 dlink(lindir, lnp->l_next);
112 STATIC replace(ocp, tmp, avp)
117 /* Replace the lines in the occurrence in ocp by a load of the
118 * temporary with offset tmp.
120 register line_p lol, first, last;
122 assert(avp->av_size == ws || avp->av_size == 2*ws);
124 first = ocp->oc_lfirst; last = ocp->oc_llast;
127 lol->l_instr = avp->av_size == ws ? op_lol : op_ldl;
128 dlink(lol, last->l_next);
130 if (first->l_prev == (line_p) 0) ocp->oc_belongs->b_start = lol;
131 dlink(first->l_prev, lol);
133 if (avp->av_instr == (byte) op_aar) {
134 /* There may actually be a LAR or a SAR instruction; in that
135 * case we have to complete the array-instruction.
137 register int instr = INSTR(last);
139 if (instr != op_aar) complete_aar(lol, instr, avp->av_othird);
142 /* Throw away the by now useless lines. */
143 remove_lines(first, last);
146 STATIC append(avp, tmp)
150 /* Avp->av_found points to a line with an operator in it. This
151 * routine emits a sequence of instructions that saves the result
152 * in a local with offset tmp. In most cases we just append
153 * avp->av_found with stl/sdl tmp and lol/ldl tmp depending on
154 * avp->av_size. If however the operator is an aar contained
155 * within a lar or sar, we must first generate the aar.
157 register line_p stl, lol;
159 assert(avp->av_size == ws || avp->av_size == 2*ws);
162 stl->l_instr = avp->av_size == ws ? op_stl : op_sdl;
164 lol->l_instr = avp->av_size == ws ? op_lol : op_ldl;
166 dlink(lol, avp->av_found->l_next);
168 dlink(avp->av_found, stl);
170 if (avp->av_instr == (byte) op_aar) {
171 register int instr = INSTR(avp->av_found);
173 if (instr != op_aar) {
174 complete_aar(lol, instr, avp->av_othird);
175 avp->av_found->l_instr = op_aar;
180 STATIC set_replace(avp, tmp)
184 /* Avp->av_occurs is now a set of occurrences, each of which will be
185 * replaced by a reference to a local.
186 * Each time we eliminate an expression, we delete from our
187 * list those expressions that are physically contained in them,
188 * because we cannot eliminate them again.
191 register lset s = avp->av_occurs;
193 for (i = Lfirst(s); i != (Lindex) 0; i = Lnext(i, s)) {
194 OUTVERBOSE("eliminate duplicate", 0);
195 SHOWOCCUR(occ_elem(i));
197 delete(occ_elem(i), avp->av_before);
198 replace(occ_elem(i), tmp, avp);
202 STATIC int reg_score(enp)
205 /* Enp is a local that will go into a register.
206 * We return its score upto now.
208 assert(is_regvar(enp->en_loc));
209 return regv_arg(enp->en_loc, 4);
212 STATIC line_p gen_mesreg(off, avp, pp)
217 /* Generate a register message for the local that will hold the
218 * result of the expression in avp, at the appropriate place in
219 * the procedure in pp.
223 reg = reg_mes(off, (short) avp->av_size, regtype(avp->av_instr), 0);
224 appnd_line(reg, pp->p_start->b_start);
229 STATIC change_score(mes, score)
233 /* Change the score in the register message in mes to score. */
235 register arg_p ap = ARG(mes);
237 ap = ap->a_next; /* Offset. */
238 ap = ap->a_next; /* Size. */
239 ap = ap->a_next; /* Type. */
240 ap = ap->a_next; /* Score. */
242 ap->a_a.a_offset = score;
248 /* Eliminate costly common subexpressions within procedure pp.
249 * We scan the available expressions in - with respect to time found -
250 * reverse order, to find largest first, e.g. `A + B + C' before
252 * We do not eliminate an expression when the size
253 * is not one of ws or 2*ws, because then we cannot use lol or ldl.
254 * Code is appended to the first occurrence of the expression
255 * to store the result into a local.
257 register avail_p ravp;
262 for (ravp = avails; ravp != (avail_p) 0; ravp = ravp->av_before) {
264 if (ravp->av_size != ws && ravp->av_size != 2*ws) continue;
266 if (ravp->av_saveloc == (entity_p) 0) {
267 /* We save it ourselves. */
268 score = 2; /* Stl and lol. */
270 score = reg_score(ravp->av_saveloc);
272 if (desirable(ravp)) {
273 score += Lnrelems(ravp->av_occurs);
274 OUTTRACE("temporary local score %d", score);
275 if (ravp->av_saveloc != (entity_p) 0) {
276 tmp = ravp->av_saveloc->en_loc;
277 mes = find_mesreg(tmp);
278 OUTVERBOSE("re-using %ld(LB)", tmp);
280 tmp = tmplocal(pp, ravp->av_size);
281 mes = gen_mesreg(tmp, ravp, pp);
284 change_score(mes, score);
285 set_replace(ravp, tmp);