1 /* $Id: il3_change.c,v 1.6 1994/06/24 10:25:54 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
8 * I L 3 _ C H A N G E . C
17 #include "../share/types.h"
19 #include "../share/debug.h"
20 #include "../share/alloc.h"
21 #include "../share/global.h"
22 #include "../share/def.h"
23 #include "../share/lset.h"
24 #include "../share/aux.h"
25 #include "../share/get.h"
26 #include "../share/put.h"
28 #include "il3_change.h"
36 STATIC line_p par_expr(l,expr)
39 /* Find the first line of the expression of which
40 * l is the last line; expr contains a pointer
41 * to a copy of that expression; effectively we
42 * just have to tally lines.
47 for (lnp = expr->l_next; lnp != (line_p) 0; lnp = lnp->l_next) {
48 assert(l != (line_p) 0);
56 STATIC rem_text(l1,l2)
59 /* Remove the lines from l1 to l2 (inclusive) */
64 while (l->l_next != lstop) {
71 STATIC store_tmp(p,l,size)
76 /* Emit code to store a 'size'-byte value in a new
77 * temporary local variable in the stack frame of p.
78 * Put this code after line l.
83 lnp = int_line(tmplocal(p,size)); /* line with operand temp. */
85 lnp->l_instr = op_stl; /* STL temp. */
88 lnp->l_instr = op_sdl; /* SDL temp. */
90 /* emit 'LAL temp; STI size' */
91 lnp->l_instr = op_lal;
94 assert ((short) size == size);
95 lnp = newline(OPSHORT);
97 lnp->l_instr = op_sti;
105 STATIC chg_actuals(c,cal)
109 /* Change the actual parameter expressions of the call. */
112 line_p llast,lfirst,l;
115 for (act = c->cl_actuals; act != (actual_p) 0; act = act->ac_next) {
116 lfirst = par_expr(llast,act->ac_exp);
117 /* the code from lfirst to llast is a parameter expression */
119 /* in line parameter; remove it */
121 llast = PREV(lfirst);
124 store_tmp(curproc,llast,act->ac_size);
125 /* put a "STL tmp" -like instruction after the code */
126 llast = PREV(lfirst);
133 STATIC rm_callpart(c,cal)
137 /* Remove the call part, consisting of a CAL,
138 * an optional ASP and an optional LFR.
145 if (c->cl_proc->p_nrformals > 0) {
146 /* called procedure has parameters */
147 assert (INSTR(l->l_next) == op_asp);
150 if (INSTR(l->l_next) == op_lfr) {
157 chg_callseq(c,cal,l_out)
161 /* Change the calling sequence. The actual parameter
162 * expressions are changed (in line parameters are
163 * removed, all other ones now store their result
164 * in a temporary local of the caller);
165 * the sequence "CAL ; ASP ; LFR" is removed.
170 *l_out = PREV(cal); /* last instr. of new parameter part */
177 line_p make_label(l,p)
181 /* Make sure that the instruction after l
182 * contains an instruction label. If this is
183 * not already the case, create a new label.
188 if (l->l_next != (line_p) 0 && INSTR(l->l_next) == op_lab) {
191 lab = newline(OPINSTRLAB);
192 lab->l_instr = op_lab;
194 INSTRLAB(lab) = p->p_nrlabels;
203 STATIC act_info(off,acts,ab_off,act_out,off_out)
204 offset off, ab_off, *off_out;
205 actual_p acts, *act_out;
207 /* Find the actual parameter that corresponds to
208 * the formal parameter with the given offset.
209 * Return it via act_out. If the actual is not
210 * an in-line actual, determine which temporary
211 * local is used for it; return the offset of that
215 offset sum = 0, tmp = 0;
218 for (act = acts; act != (actual_p) 0; act = act->ac_next) {
226 *off_out = tmp + sum - off + ab_off;
239 STATIC store_off(off,l)
243 if (TYPE(l) == OPSHORT) {
244 assert ((short) off == off);
245 SHORT(l) = (short) off;
253 STATIC inl_actual(l,expr)
256 /* Expand an actual parameter in line.
257 * A LOL or LDL instruction is replaced
259 * A SIL or LIL is replaced by the expression
260 * followed by a STI or LOI.
267 assert(expr != (line_p) 0);
268 e = copy_expr(expr); /* make a copy of expr. */
269 if (instr == op_sil || instr == op_lil) {
270 s = int_line((offset) ws);
271 s->l_instr = (instr == op_sil ? op_sti : op_loi);
272 appnd_line(s,last_line(e));
274 assert(instr == op_lol || instr == op_ldl);
283 STATIC localref(l,c,ab_off,lb_off)
286 offset ab_off, lb_off;
288 /* Change a reference to a local variable or parameter
289 * of the called procedure.
297 /* local variable, only the offset changes */
298 store_off(lb_off + off,l);
300 act_info(off,c->cl_actuals,ab_off,&act,&tmpoff); /* find actual */
302 /* inline actual parameter */
303 inl_actual(l,act->ac_exp);
305 /* parameter stored in temporary local */
313 STATIC chg_mes(l,c,ab_off,lb_off)
316 offset ab_off, lb_off;
318 /* The register messages of the called procedure
319 * must be changed. If the message applies to a
320 * local variable or to a parameter that is not
321 * expanded in line, the offset of the variable
322 * is changed; else the entire message is deleted.
330 switch ((int) arg->a_a.a_offset) {
332 if ((arg = arg->a_next) != (arg_p) 0) {
333 /* "mes 3" without further argument is not changed */
334 off = arg->a_a.a_offset;
337 arg->a_a.a_offset += lb_off;
339 act_info(off,c->cl_actuals,ab_off,&act,&tmpoff);
344 arg->a_a.a_offset = tmpoff;
357 STATIC chg_ret(l,c,lab)
361 /* Change the RET instruction appearing in the
362 * expanded text of a call. If the called procedure
363 * falls through, the RET is just deleted; else it
364 * is replaced by a branch.
371 if (!FALLTHROUGH(c->cl_proc)) {
372 bra = newline(OPINSTRLAB);
373 bra->l_instr = op_bra;
374 INSTRLAB(bra) = INSTRLAB(lab);
381 STATIC mod_instr(l,c,lab,ab_off,lb_off,lab_off)
384 offset ab_off,lb_off;
387 if (TYPE(l) == OPINSTRLAB) {
388 INSTRLAB(l) += lab_off;
401 localref(l,c,ab_off,lb_off);
416 chg_mes(l,c,ab_off,lb_off);
423 modify(text,c,lab,ab_off,lb_off,lab_off)
426 offset ab_off,lb_off;
429 /* Modify the EM text of the called procedure.
430 * References to locals and parameters are
431 * changed; RETs are either deleted or replaced
432 * by a BRA to the given label; PRO and END pseudos
433 * are removed; instruction labels are changed, in
434 * order to make them different from any label used
435 * by the caller; some messages need to be changed too.
436 * Note that the first line of the text is a dummy instruction.
442 for (l = text->l_next; l != (line_p) 0; l = next) {
444 /* This is rather tricky. An instruction like
445 * LOL 2 may be replaced by a number of instructions
446 * (if the parameter is expanded in line). This inserted
447 * code, however, should not be modified!
449 mod_instr(l,c,lab,ab_off,lb_off,lab_off);
455 mod_actuals(nc,c,lab,ab_off,lb_off,lab_off)
458 offset ab_off,lb_off;
465 PREV(dum) = (line_p) 0;
466 for (act = nc->cl_actuals; act != (actual_p) 0; act = act->ac_next) {
468 assert(l != (line_p) 0);
469 /* Insert a dummy instruction before l */
472 while(l != (line_p) 0) {
474 mod_instr(l,c,lab,ab_off,lb_off,lab_off);
477 act->ac_exp = dum->l_next;
478 PREV(dum->l_next) = (line_p) 0;
487 STATIC line_p first_nonpseudo(l)
490 /* Find the first non-pseudo instruction of
491 * a list of instructions.
494 while (l != (line_p) 0 && INSTR(l) >= sp_fpseu &&
495 INSTR(l) <= ps_last) l = l->l_next;
501 insert(text,l,firstline)
502 line_p text,l,firstline;
504 /* Insert the modified EM text of the called
505 * routine in the calling routine. Pseudos are
506 * put after the pseudos of the caller; all
507 * normal instructions are put at the place
508 * where the CAL originally was.
511 line_p l1,l2,lastpseu;
514 oldline(text); /* remove dummy head instruction */
515 if (l1 == (line_p) 0) return; /* no text at all! */
516 l2 = first_nonpseudo(l1);
517 if (l2 == (line_p) 0) {
518 /* modified code consists only of pseudos */
519 app_list(l1,PREV(first_nonpseudo(firstline)));
525 lastpseu = PREV(first_nonpseudo(firstline));
526 PREV(l2)->l_next = (line_p) 0; /* cut link */
527 app_list(l2,l); /* insert normal instructions */
528 app_list(l1,lastpseu);
539 /* All calls to procedure p were expanded in line, so
540 * p is no longer needed. However, we must not throw away
541 * any data declarations appearing in p.
542 * The proctable entry of p is not removed, as we do not
543 * want to create holes in this table; however the PF_BODYSEEN
544 * flag is cleared, so p gets the same status as a procedure
545 * whose body is unmkown.
548 line_p l, nextl, lastkept = (line_p) 0;
551 for (l = text; l != (line_p) 0; l = nextl) {
565 if (lastkept != (line_p) 0) {
566 /* There were some data declarations in p,
567 * so we'll turn p into a data-unit; we'll
568 * have to append an end-pseudo for this
571 lastkept->l_next = newline(OPNO);
572 lastkept->l_next->l_instr = (byte) ps_end;
574 /* There may be some calls in the body of p that
575 * ought to be expanded in line. As p is removed
576 * anyway, there is no use in really performing
577 * these substitutions, so the call-descriptors
578 * are just thrown away.
581 for (c = p->P_CALS; c != (call_p) 0; c = nextc) {
585 /* change the proctable entry */
586 p->p_flags1 &= (byte) ~PF_BODYSEEN;
587 oldchange(p->p_change);