Pristine Ack-5.5
[Ack-5.5.git] / util / ego / il / il3_change.c
1 /* $Id: il3_change.c,v 1.6 1994/06/24 10:25:54 ceriel Exp $ */
2 /*
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".
5  */
6 /*  I N L I N E   S U B S T I T U T I O N
7  *
8  *  I L 3 _ C H A N G E . C
9  */
10
11
12 #include <stdio.h>
13 #include <em_mnem.h>
14 #include <em_pseu.h>
15 #include <em_spec.h>
16 #include <em_mes.h>
17 #include "../share/types.h"
18 #include "il.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"
27 #include "il_aux.h"
28 #include "il3_change.h"
29 #include "il3_aux.h"
30
31 /* chg_callseq */
32
33
34
35
36 STATIC line_p par_expr(l,expr)
37         line_p l, expr;
38 {
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.
43          */
44
45         line_p lnp;
46
47         for (lnp = expr->l_next; lnp != (line_p) 0; lnp = lnp->l_next) {
48                 assert(l != (line_p) 0);
49                 l = PREV(l);
50         }
51         return l;
52 }
53
54
55
56 STATIC rem_text(l1,l2)
57         line_p l1,l2;
58 {
59         /* Remove the lines from l1 to l2 (inclusive) */
60
61         line_p l, lstop;
62         l = PREV(l1);
63         lstop = l2->l_next;
64         while (l->l_next != lstop) {
65                 rem_line(l->l_next);
66         }
67 }
68
69
70
71 STATIC store_tmp(p,l,size)
72         proc_p p;
73         line_p l;
74         offset  size;
75 {
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.
79          */
80
81         line_p lnp;
82
83         lnp = int_line(tmplocal(p,size)); /* line with operand temp. */
84         if (size == ws) {
85                 lnp->l_instr = op_stl;  /* STL temp. */
86         } else {
87                 if (size == 2*ws) {
88                         lnp->l_instr = op_sdl; /* SDL temp. */
89                 } else {
90                         /* emit 'LAL temp; STI size' */
91                         lnp->l_instr = op_lal;
92                         appnd_line(lnp,l);
93                         l = lnp;
94                         assert ((short) size == size);
95                         lnp = newline(OPSHORT);
96                         SHORT(lnp) = size;
97                         lnp->l_instr = op_sti;
98                 }
99         }
100         appnd_line(lnp,l);
101 }
102
103
104
105 STATIC chg_actuals(c,cal)
106         call_p c;
107         line_p cal;
108 {
109         /* Change the actual parameter expressions of the call. */
110
111         actual_p act;
112         line_p llast,lfirst,l;
113
114         llast = PREV(cal);
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 */
118                 if (act->ac_inl) {
119                         /* in line parameter; remove it */
120                         l = llast;
121                         llast = PREV(lfirst);
122                         rem_text(lfirst,l);
123                 } else {
124                         store_tmp(curproc,llast,act->ac_size);
125                         /* put a "STL tmp" -like instruction after the code */
126                         llast = PREV(lfirst);
127                 }
128         }
129 }
130
131
132
133 STATIC rm_callpart(c,cal)
134         call_p c;
135         line_p cal;
136 {
137         /* Remove the call part, consisting of a CAL,
138          * an optional ASP and an optional LFR.
139          */
140
141         line_p l;
142
143         l= PREV(cal);
144         rem_line(cal);
145         if (c->cl_proc->p_nrformals > 0) {
146                 /* called procedure has parameters */
147                 assert (INSTR(l->l_next) == op_asp);
148                 rem_line(l->l_next);
149         }
150         if (INSTR(l->l_next) == op_lfr) {
151                 rem_line(l->l_next);
152         }
153 }
154
155
156
157 chg_callseq(c,cal,l_out)
158         call_p c;
159         line_p cal,*l_out;
160 {
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.
166          */
167
168
169         chg_actuals(c,cal);
170         *l_out = PREV(cal); /* last instr. of new parameter part */
171         rm_callpart(c,cal);
172 }
173
174
175 /* make_label */
176
177 line_p make_label(l,p)
178         line_p l;
179         proc_p p;
180 {
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.
184          */
185
186         line_p lab;
187
188         if (l->l_next != (line_p) 0 && INSTR(l->l_next) == op_lab) {
189                 return l->l_next;
190         }
191         lab = newline(OPINSTRLAB);
192         lab->l_instr = op_lab;
193         p->p_nrlabels++;
194         INSTRLAB(lab) = p->p_nrlabels;
195         appnd_line(lab,l);
196         return lab;
197 }
198
199
200
201 /* modify */
202
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;
206 {
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
212          * local via off_out.
213          */
214
215         offset sum = 0, tmp = 0;
216         actual_p act;
217
218         for (act = acts; act != (actual_p) 0; act = act->ac_next) {
219                 if (!act->ac_inl) {
220                         tmp -= act->ac_size;
221                 }
222                 if (sum >= off) {
223                         /* found */
224                         *act_out = act;
225                         if (!act->ac_inl) {
226                                 *off_out = tmp + sum - off + ab_off;
227                         } else {
228                                 assert (sum == off);
229                         }
230                         return;
231                 }
232                 sum += act->ac_size;
233         }
234         assert(FALSE);
235 }
236
237
238
239 STATIC store_off(off,l)
240         offset off;
241         line_p l;
242 {
243         if (TYPE(l) == OPSHORT) {
244                 assert ((short) off == off);
245                 SHORT(l) = (short) off;
246         } else {
247                 OFFSET(l) = off;
248         }
249 }
250
251
252
253 STATIC inl_actual(l,expr)
254         line_p l, expr;
255 {
256         /* Expand an actual parameter in line.
257          * A LOL or LDL instruction is replaced
258          * by an expression.
259          * A SIL or LIL is replaced by the expression
260          * followed by a STI or LOI.
261          */
262
263         line_p e, lnp, s;
264         short  instr;
265
266         instr = INSTR(l);
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));
273         } else {
274                 assert(instr == op_lol || instr == op_ldl);
275         }
276         lnp = PREV(l);
277         rem_line(l);
278         app_list(e,lnp);
279 }
280
281
282
283 STATIC localref(l,c,ab_off,lb_off)
284         line_p l;
285         call_p c;
286         offset ab_off, lb_off;
287 {
288         /* Change a reference to a local variable or parameter
289          * of the called procedure.
290          */
291
292         offset off, tmpoff;
293         actual_p act;
294
295         off = off_set(l);
296         if (off < 0) {
297                 /* local variable, only the offset changes */
298                 store_off(lb_off + off,l);
299         } else {
300                 act_info(off,c->cl_actuals,ab_off,&act,&tmpoff); /* find actual */
301                 if (act->ac_inl) {
302                         /* inline actual parameter */
303                         inl_actual(l,act->ac_exp);
304                 } else {
305                         /* parameter stored in temporary local */
306                         store_off(tmpoff,l);
307                 }
308         }
309 }
310
311
312
313 STATIC chg_mes(l,c,ab_off,lb_off)
314         line_p l;
315         call_p c;
316         offset ab_off, lb_off;
317 {
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.
323          */
324
325         offset off, tmpoff;
326         actual_p act;
327         arg_p arg;
328
329         arg = ARG(l);
330         switch ((int) arg->a_a.a_offset) {
331            case ms_reg:
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;
335                         if (off < 0) {
336                                 /* local variable */
337                                 arg->a_a.a_offset += lb_off;
338                         } else {
339                                 act_info(off,c->cl_actuals,ab_off,&act,&tmpoff);
340                                 if (act->ac_inl) {
341                                         /* in line actual */
342                                         rem_line(l);
343                                 } else {
344                                         arg->a_a.a_offset = tmpoff;
345                                 }
346                         }
347                 }
348                 break;
349            case ms_par:
350                 rem_line(l);
351                 break;
352         }
353 }
354
355
356
357 STATIC chg_ret(l,c,lab)
358         line_p l,lab;
359         call_p c;
360 {
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.
365          */
366
367         line_p lnp, bra;
368
369         lnp = PREV(l);
370         rem_line(l);
371         if (!FALLTHROUGH(c->cl_proc)) {
372                 bra = newline(OPINSTRLAB);
373                 bra->l_instr = op_bra;
374                 INSTRLAB(bra) = INSTRLAB(lab);
375                 appnd_line(bra,lnp);
376         }
377 }
378
379
380
381 STATIC mod_instr(l,c,lab,ab_off,lb_off,lab_off)
382         line_p l,lab;
383         call_p c;
384         offset ab_off,lb_off;
385         int    lab_off;
386 {
387         if (TYPE(l) == OPINSTRLAB) {
388                 INSTRLAB(l) += lab_off;
389         } else {
390             switch(INSTR(l)) {
391                 case op_stl:
392                 case op_inl:
393                 case op_del:
394                 case op_zrl:
395                 case op_sdl:
396                 case op_lol:
397                 case op_ldl:
398                 case op_sil:
399                 case op_lil:
400                 case op_lal:
401                         localref(l,c,ab_off,lb_off);
402                         break;
403                 case op_ret:
404                         chg_ret(l,c,lab);
405                         break;
406                 case ps_pro:
407                 case ps_end:
408                 case ps_sym:
409                 case ps_hol:
410                 case ps_bss:
411                 case ps_con:
412                 case ps_rom:
413                         rem_line(l);
414                         break;
415                 case ps_mes:
416                         chg_mes(l,c,ab_off,lb_off);
417                         break;
418             }
419         }
420 }
421
422
423 modify(text,c,lab,ab_off,lb_off,lab_off)
424         line_p text,lab;
425         call_p c;
426         offset ab_off,lb_off;
427         int    lab_off;
428 {
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.
437          */
438
439         register line_p l;
440         line_p next;
441
442         for (l = text->l_next; l != (line_p) 0; l = next) {
443                 next = l->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!
448                  */
449                 mod_instr(l,c,lab,ab_off,lb_off,lab_off);
450         }
451 }
452
453
454
455 mod_actuals(nc,c,lab,ab_off,lb_off,lab_off)
456         call_p nc,c;
457         line_p lab;
458         offset ab_off,lb_off;
459         int    lab_off;
460 {
461         actual_p act;
462         line_p l, next, dum;
463
464         dum = newline(OPNO);
465         PREV(dum) = (line_p) 0;
466         for (act = nc->cl_actuals; act != (actual_p) 0; act = act->ac_next) {
467                 l = act->ac_exp;
468                 assert(l != (line_p) 0);
469                 /* Insert a dummy instruction before l */
470                 dum->l_next = l;
471                 PREV(l) = dum;
472                 while(l != (line_p) 0) {
473                         next = l->l_next;
474                         mod_instr(l,c,lab,ab_off,lb_off,lab_off);
475                         l = next;
476                 }
477                 act->ac_exp = dum->l_next;
478                 PREV(dum->l_next) = (line_p) 0;
479         }
480         oldline(dum);
481 }
482
483
484
485 /* insert */
486
487 STATIC line_p first_nonpseudo(l)
488         line_p l;
489 {
490         /* Find the first non-pseudo instruction of
491          * a list of instructions.
492          */
493
494         while (l != (line_p) 0 && INSTR(l) >= sp_fpseu &&
495                 INSTR(l) <= ps_last) l = l->l_next;
496         return l;
497 }
498
499
500
501 insert(text,l,firstline)
502         line_p text,l,firstline;
503 {
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.
509          */
510
511         line_p l1,l2,lastpseu;
512
513         l1 = text->l_next;
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)));
520         } else {
521                 if (l1 == l2) {
522                         /* no pseudos */
523                         app_list(l2,l);
524                 } else {
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);
529                 }
530         }
531 }
532
533
534
535 liquidate(p,text)
536         proc_p p;
537         line_p text;
538 {
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.
546          */
547
548         line_p l, nextl, lastkept = (line_p) 0;
549         call_p c, nextc;
550
551         for (l = text; l != (line_p) 0; l = nextl) {
552                 nextl = l->l_next;
553                 switch(INSTR(l)) {
554                         case ps_sym:
555                         case ps_hol:
556                         case ps_bss:
557                         case ps_con:
558                         case ps_rom:
559                                 lastkept = l;
560                                 break;
561                         default:
562                                 rem_line(l);
563                 }
564         }
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
569                  * purpose.
570                  */
571                 lastkept->l_next = newline(OPNO);
572                 lastkept->l_next->l_instr = (byte) ps_end;
573         }
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.
579          */
580
581          for (c = p->P_CALS; c != (call_p) 0; c = nextc) {
582                 nextc = c->cl_cdr;
583                 rem_call(c);
584         }
585         /* change the proctable entry */
586         p->p_flags1 &= (byte) ~PF_BODYSEEN;
587         oldchange(p->p_change);
588         olduse(p->p_use);
589 }