1 /* $Id: il2_aux.c,v 1.14 1994/06/24 10:25:42 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 /* I N L I N E S U B S T I T U T I O N
14 #include "../share/types.h"
16 #include "../share/debug.h"
17 #include "../share/alloc.h"
18 #include "../share/global.h"
19 #include "../share/lset.h"
22 #include "../share/get.h"
23 #include "../share/aux.h"
25 #define USE_INDIR(p) (p->p_use->u_flags & UF_INDIR)
27 #define OFTEN_USED(f) ((f->f_flags&FF_OFTENUSED) == FF_OFTENUSED)
28 #define CHANGE_EXT(p) (Cnrelems(p->p_change->c_ext) > 0)
29 #define NOT_INLINE(a) (a->ac_inl = FALSE)
30 #define INLINE(a) (a->ac_inl = TRUE)
33 #define CHANGED(p) p->p_flags2 |= PF_CHANGED
34 #define IS_CHANGED(p) (p->p_flags2 & PF_CHANGED)
38 STATIC bool match_pars(fm,act)
42 /* Check if every actual parameter has the same
43 * size as its corresponding formal. If not, the
44 * actual parameters should not be expanded in line.
47 while (act != (actual_p) 0) {
48 if (fm == (formal_p) 0 || tsize(fm->f_type) != act->ac_size) {
54 return (fm == (formal_p) 0 ? TRUE : FALSE);
58 STATIC bool change_act(p,act)
62 /* See if a call to p migth change any of the
63 * operands of the actual parameter expression.
64 * If the parameter is to be expanded in line,
65 * we must be sure its value does not depend
66 * on the point in the program where it is
72 for (l = act->ac_exp; l != (line_p) 0; l = l->l_next) {
80 /* assume worst case */
83 if (CHANGE_INDIR(p)) {
89 if (CHANGE_INDIR(p) || CHANGE_EXT(p)) {
100 STATIC bool is_simple(expr)
103 /* See if expr is something simple, i.e. a constant or
104 * a variable. So the expression must consist of
105 * only one instruction.
109 if (expr->l_next == (line_p) 0) {
110 switch(INSTR(expr)) {
125 STATIC bool too_expensive(fm,act)
129 /* If the formal parameter is used often and the
130 * actual parameter is not something simple
131 * (i.e. an expression, not a constant or variable)
132 * it may be too expensive too expand the parameter
136 return (OFTEN_USED(fm) && !is_simple(act->ac_exp));
141 /* Determine which of the actual parameters of a
142 * call may be expanded in line.
150 p = c->cl_proc; /* the called procedure */
151 if (!match_pars(p->P_FORMALS, c->cl_actuals)) return FALSE;
152 if (!INLINE_PARS(p)) {
153 for (act = c->cl_actuals; act != (actual_p) 0;
154 act = act->ac_next) {
157 return TRUE; /* "# of inline pars." field in cl_flags remains 0 */
159 for (act = c->cl_actuals, form = p->P_FORMALS; act != (actual_p) 0;
160 act = act->ac_next, form = form->f_next) {
161 if (form->f_flags & FF_BAD ||
162 change_act(p,act) || too_expensive(form,act)) {
169 if (inlpars > 15) inlpars = 15; /* We've only got 4 bits! */
170 c->cl_flags |= inlpars; /* number of inline parameters */
175 STATIC short space_saved(c)
178 /* When a call gets expanded in line, the total size of the
179 * code usually gets incremented, because we have to
180 * duplicate the text of the called routine. However, we save
181 * ourselves a CAL instruction and possibly anASP instruction
182 * (if the called procedure has parameters). Moreover, if we
183 * can put some parameters in line, we don't have to push
184 * their results on the stack before doing the call, so we
185 * save some code here too. The routine estimates the amount of
186 * code saved, expressed in number of EM instructions.
189 return (1 + (c->cl_flags & CLF_INLPARS) + (c->cl_proc->p_nrformals>0));
192 STATIC short param_score(c)
195 /* If a call has an inline parameter that is a constant,
196 * chances are high that other optimization techniques
197 * can do further optimizations, especially if the constant
198 * happens to be "0". So the call gets extra points for this.
201 register actual_p act;
205 for (act = c->cl_actuals; act != (actual_p) 0; act = act->ac_next) {
208 if (l->l_next == (line_p) 0 &&
209 (INSTR(l) == op_loc || INSTR(l) == op_ldc)) {
210 score += (off_set(l) == (offset) 0 ? 2 : 1);
211 /* 0's count for two! */
225 /* This routine is one of the most important ones
226 * of the inline substitution phase. It assigns a number
227 * (a 'ratio') to a call, indicating how desirable
228 * it is to expand the call in line.
229 * Currently, a very simplified straightforward heuristic
233 short ll, loopfact, ratio;
235 ll = c->cl_proc->P_SIZE - space_saved(c);
238 if (ratio == 0) ratio = 1;
239 /* Add points if the called procedure falls through
240 * it's end (no BRA needed) or has formal parameters
241 * (ASP can be deleted).
243 if (c->cl_proc->p_flags2 & PF_FALLTHROUGH) {
246 if (c->cl_proc->p_nrformals > 0) {
249 if (c->cl_caller->p_localbytes == 0) {
252 ratio += (10 *param_score(c));
253 /* Extra points for constants as parameters */
254 if (ratio <= 0) ratio = 1;
255 ll = c->cl_looplevel+1;
256 if (ll == 1 && !IS_CALLED_IN_LOOP(c->cl_caller)) ll = 0;
257 /* If the call is not in a loop and the called proc. is never called
258 * in a loop, ll is set to 0.
260 loopfact = (ll > 3 ? 10 : ll*ll);
262 if (c->cl_flags & CLF_FIRM) {
272 /* Abstract information from the call that is essential
273 * for choosing the calls that will be expanded.
274 * Put the information is an 'abstracted call'.
280 a->cl_caller = c->cl_caller;
282 a->cl_proc = c->cl_proc;
283 a->cl_looplevel = c->cl_looplevel;
284 a->cl_ratio = c->cl_ratio;
285 a->cl_flags = c->cl_flags;
291 STATIC adjust_counts(callee,ccf)
295 /* A call to callee is expanded in line;
296 * the text of callee is not removed, so
297 * every proc called by callee gets its
298 * P_NRCALLED field incremented.
303 head = getcc(ccf,callee); /* get calcnt info of called proc */
304 for (cc = head; cc != (calcnt_p) 0; cc = cc->cc_next) {
305 cc->cc_proc->P_NRCALLED += cc->cc_count;
307 remcc(head); /* remove calcnt info */
312 STATIC bool is_dispensable(callee,ccf)
316 /* A call to callee is expanded in line.
317 * Decrement its P_NRCALLED field and see if
318 * it can now be removed because it is no
319 * longer called. Procedures that ever have
320 * their address taken (via LPI) will never
321 * be removed, as they might be called indirectly.
324 if ((--callee->P_NRCALLED) == 0 &&
325 (complete_program || (callee->p_flags1 & PF_EXTERNAL) == 0) &&
326 (callee->p_flags1 & PF_LPI) == 0) {
328 OUTVERBOSE("dispensable: procedure %d can be removed",callee->p_id);
334 adjust_counts(callee,ccf);
342 STATIC call_p nested_calls(a)
345 /* Get a list of all calls that will appear in the
346 * EM text if the call 'a' is expanded in line.
347 * These are the calls in the P_CALS list of the
351 call_p c, cp, head, *cpp;
355 for (c = a->cl_proc->P_CALS; c != (call_p) 0; c = c->cl_cdr) {
357 cp->cl_looplevel += a->cl_looplevel;
358 cp->cl_flags = (byte) 0;
359 if (a->cl_flags & CLF_FIRM) {
360 cp->cl_flags |= CLF_FIRM;
372 STATIC call_p find_origin(c)
375 /* c is a nested call. Find the original call.
376 * This origional must be in the P_CALS list
377 * of the calling procedure.
382 for (x = c->cl_caller->P_CALS; x != (call_p) 0; x = x->cl_cdr) {
383 if (x->cl_id == c->cl_id) return x;
394 /* The call a is selected for in line expansion.
395 * Mark the call as being selected and get the
396 * calls nested in it; these will be candidates
401 EVER_EXPANDED(find_origin(a));
402 a->cl_car = nested_calls(a);
408 STATIC compare(x,best,space)
412 /* See if x is better than the current best choice */
414 if (x != (call_p) 0 && !IS_CHANGED(x->cl_proc) &&
415 x->cl_proc->P_SIZE - space_saved(x) <= space) {
416 if ((*best == (call_p) 0 && x->cl_ratio != 0) ||
417 (*best != (call_p) 0 && x->cl_ratio > (*best)->cl_ratio )) {
426 STATIC call_p best_one(list,space)
430 /* Find the best candidate of the list
431 * that has not already been selected. The
432 * candidate must fit in the given space.
433 * We look in the cdr as well as in the car
437 call_p best = (call_p) 0;
440 for (c = list; c != (call_p) 0; c = c->cl_cdr) {
441 if (IS_SELECTED(c)) {
442 compare(best_one(c->cl_car,space),&best,space);
444 compare(c,&best,space);
455 /* If a procedure is only called once, this call
456 * will be expanded in line, because it costs
462 for (c = cals; c != (call_p) 0; c = c->cl_cdr) {
463 if (IS_SELECTED(c)) {
466 if (c->cl_proc->P_NRCALLED == 1 &&
467 !IS_CHANGED(c->cl_proc) &&
469 (c->cl_proc->p_flags1 & PF_EXTERNAL) == 0) &&
470 (c->cl_proc->p_flags1 & PF_LPI) == 0) {
471 c->cl_proc->P_NRCALLED = 0;
473 EVER_EXPANDED(find_origin(c));
474 DISPENSABLE(c->cl_proc);
475 CHANGED(c->cl_caller);
476 OUTVERBOSE("singles: procedure %d can be removed",
488 STATIC single_calls(proclist)
493 for (p = proclist; p != (proc_p) 0; p = p->p_next) {
494 if (!BIG_CALLER(p) && !IS_DISPENSABLE(p)) {
495 /* Calls appearing in a large procedure or in
496 * a procedure that was already eliminated
497 * are not considered.
507 select_calls(proclist,ccf,space)
512 /* Select all calls that are to be expanded in line. */
519 chp = (proc_p) 0; /* the changed procedure */
520 for (p = proclist; p != (proc_p) 0; p = p->p_next) {
521 if (!BIG_CALLER(p) && !IS_DISPENSABLE(p)) {
522 /* Calls appearing in a large procedure or in
523 * a procedure that was already eliminated
524 * are not considered.
526 x = best_one(p->P_CALS,space);
527 compare(x,&best,space);
528 if (x == best) chp = p;
531 if (best == (call_p) 0) break;
532 if (!is_dispensable(best->cl_proc,ccf)) {
533 space -= (best->cl_proc->P_SIZE - space_saved(best));
535 else space += space_saved(best);
537 if (verbose_flag) fprintf(stderr, "space left: %ld\n", space);
542 single_calls(proclist);
544 Sstat(proclist,space);
551 STATIC nonnested_calls(cfile)
556 while((c = getcall(cfile)) != (call_p) 0) {
557 /* find the call in the call list of the caller */
558 for (a = c->cl_caller->P_CALS;
559 a != (call_p) 0 && c->cl_id != a->cl_id; a = a->cl_cdr);
560 assert(a != (call_p) 0 && a->cl_proc == c->cl_proc);
561 if (IS_EVER_EXPANDED(a)) {
562 a->cl_actuals = c->cl_actuals;
563 c->cl_actuals = (actual_p) 0;
571 STATIC copy_pars(src,dest)
574 /* Copy the actual parameters of src to dest. */
576 actual_p as,ad, *app;
578 app = &dest->cl_actuals;
579 for (as = src->cl_actuals; as != (actual_p) 0; as = as->ac_next) {
581 ad->ac_exp = copy_expr(as->ac_exp);
582 ad->ac_size = as->ac_size;
583 ad->ac_inl = as->ac_inl;
591 STATIC nest_pars(cals)
594 /* Recursive auxiliary procedure of add_actuals. */
598 for (c = cals; c != (call_p) 0; c = c->cl_cdr) {
599 if (IS_SELECTED(c)) {
600 org = find_origin(c);
602 nest_pars(c->cl_car);
609 add_actuals(proclist,cfile)
613 /* Fetch the actual parameters of all selected calls.
614 * For all non-nested calls (i.e. those calls that
615 * appeared originally in the EM text), we get the
616 * parameters from the cal-file.
617 * For nested calls (i.e. calls
618 * that are a result of in line substitution) we
619 * get the parameters from the original call.
625 nonnested_calls(cfile);
626 for (p = proclist; p != (proc_p) 0; p = p->p_next) {
627 for (a = p->P_CALS; a != (call_p) 0; a = a->cl_cdr) {
628 nest_pars(a->cl_car);
640 /* Recursive auxiliary routine of cleancals */
643 for (c = *cpp; c != (call_p) 0; c = next) {
645 if (IS_SELECTED(c)) {
649 assert(c->cl_car == (call_p) 0);
660 /* Remove all calls in the P_CALS list of p
661 * that were not selected for in line expansion.
666 for (p = proclist; p != (proc_p) 0; p = p->p_next) {
678 /* Append an abstract of a call-descriptor to
679 * the call-list of procedure p.
684 if (p->P_CALS == (call_p) 0) {
687 for (c = p->P_CALS; c->cl_cdr != (call_p) 0; c = c->cl_cdr);
695 /* At the end, we traverse the entire call-list, to see why the
696 * remaining calls were not expanded inline.
706 for (c = list; c != (call_p) 0; c = c->cl_cdr) {
707 if (IS_SELECTED(c)) {
708 Sstatist(c->cl_car,space);
710 if (IS_CHANGED(c->cl_proc)) Schangedcallee++;
711 else if (BIG_PROC(c->cl_proc)) Sbigcallee++;
712 else if (c->cl_proc->P_SIZE > space) Sspace++;
713 else if (c->cl_ratio == 0) Szeroratio++;
719 Sstat(proclist,space)
725 for (p = proclist; p != (proc_p) 0; p = p->p_next) {
726 if (BIG_CALLER(p)) Sbig_caller++;
727 else if (IS_DISPENSABLE(p)) Sdispensable++;
728 else Sstatist(p->P_CALS,space);