589 lines
		
	
	
	
		
			12 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			589 lines
		
	
	
	
		
			12 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/* $Header$ */
 | 
						|
/*
 | 
						|
 * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
 | 
						|
 * See the copyright notice in the ACK home directory, in the file "Copyright".
 | 
						|
 */
 | 
						|
/*  I N L I N E   S U B S T I T U T I O N
 | 
						|
 *
 | 
						|
 *  I L 3 _ C H A N G E . C
 | 
						|
 */
 | 
						|
 | 
						|
 | 
						|
#include <stdio.h>
 | 
						|
#include "../share/types.h"
 | 
						|
#include "il.h"
 | 
						|
#include "../share/debug.h"
 | 
						|
#include "../share/alloc.h"
 | 
						|
#include "../share/global.h"
 | 
						|
#include "../share/def.h"
 | 
						|
#include "../share/lset.h"
 | 
						|
#include "../share/aux.h"
 | 
						|
#include "../../../h/em_mnem.h"
 | 
						|
#include "../../../h/em_pseu.h"
 | 
						|
#include "../../../h/em_spec.h"
 | 
						|
#include "../../../h/em_mes.h"
 | 
						|
#include "../share/get.h"
 | 
						|
#include "../share/put.h"
 | 
						|
#include "il_aux.h"
 | 
						|
#include "il3_change.h"
 | 
						|
#include "il3_aux.h"
 | 
						|
 | 
						|
/* chg_callseq */
 | 
						|
 | 
						|
 | 
						|
 | 
						|
 | 
						|
STATIC line_p par_expr(l,expr)
 | 
						|
	line_p l, expr;
 | 
						|
{
 | 
						|
	/* Find the first line of the expression of which
 | 
						|
	 * l is the last line; expr contains a pointer
 | 
						|
	 * to a copy of that expression; effectively we
 | 
						|
	 * just have to tally lines.
 | 
						|
	 */
 | 
						|
 | 
						|
	line_p lnp;
 | 
						|
 | 
						|
	for (lnp = expr->l_next; lnp != (line_p) 0; lnp = lnp->l_next) {
 | 
						|
		assert(l != (line_p) 0);
 | 
						|
		l = PREV(l);
 | 
						|
	}
 | 
						|
	return l;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
 | 
						|
STATIC rem_text(l1,l2)
 | 
						|
	line_p l1,l2;
 | 
						|
{
 | 
						|
	/* Remove the lines from l1 to l2 (inclusive) */
 | 
						|
 | 
						|
	line_p l, lstop;
 | 
						|
	l = PREV(l1);
 | 
						|
	lstop = l2->l_next;
 | 
						|
	while (l->l_next != lstop) {
 | 
						|
		rem_line(l->l_next);
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
 | 
						|
STATIC store_tmp(p,l,size)
 | 
						|
	proc_p p;
 | 
						|
	line_p l;
 | 
						|
	offset  size;
 | 
						|
{
 | 
						|
	/* Emit code to store a 'size'-byte value in a new
 | 
						|
	 * temporary local variable in the stack frame of p.
 | 
						|
	 * Put this code after line l.
 | 
						|
	 */
 | 
						|
 | 
						|
	line_p lnp;
 | 
						|
 | 
						|
	lnp = int_line(tmplocal(p,size)); /* line with operand temp. */
 | 
						|
	if (size == ws) {
 | 
						|
		lnp->l_instr = op_stl;  /* STL temp. */
 | 
						|
	} else {
 | 
						|
		if (size == 2*ws) {
 | 
						|
			lnp->l_instr = op_sdl; /* SDL temp. */
 | 
						|
		} else {
 | 
						|
			/* emit 'LAL temp; STI size' */
 | 
						|
			lnp->l_instr = op_lal;
 | 
						|
			appnd_line(lnp,l);
 | 
						|
			l = lnp;
 | 
						|
			assert ((short) size == size);
 | 
						|
			lnp = newline(OPSHORT);
 | 
						|
			SHORT(lnp) = size;
 | 
						|
			lnp->l_instr = op_sti;
 | 
						|
		}
 | 
						|
	}
 | 
						|
	appnd_line(lnp,l);
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
 | 
						|
STATIC chg_actuals(c,cal)
 | 
						|
	call_p c;
 | 
						|
	line_p cal;
 | 
						|
{
 | 
						|
	/* Change the actual parameter expressions of the call. */
 | 
						|
 | 
						|
	actual_p act;
 | 
						|
	line_p llast,lfirst,l;
 | 
						|
 | 
						|
	llast = PREV(cal);
 | 
						|
	for (act = c->cl_actuals; act != (actual_p) 0; act = act->ac_next) {
 | 
						|
		lfirst = par_expr(llast,act->ac_exp);
 | 
						|
		/* the code from lfirst to llast is a parameter expression */
 | 
						|
		if (act->ac_inl) {
 | 
						|
			/* in line parameter; remove it */
 | 
						|
			l = llast;
 | 
						|
			llast = PREV(lfirst);
 | 
						|
			rem_text(lfirst,l);
 | 
						|
		} else {
 | 
						|
			store_tmp(curproc,llast,act->ac_size);
 | 
						|
			/* put a "STL tmp" -like instruction after the code */
 | 
						|
			llast = PREV(lfirst);
 | 
						|
		}
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
 | 
						|
STATIC rm_callpart(c,cal)
 | 
						|
	call_p c;
 | 
						|
	line_p cal;
 | 
						|
{
 | 
						|
	/* Remove the call part, consisting of a CAL,
 | 
						|
	 * an optional ASP and an optional LFR.
 | 
						|
	 */
 | 
						|
 | 
						|
	line_p l;
 | 
						|
 | 
						|
	l= PREV(cal);
 | 
						|
	rem_line(cal);
 | 
						|
	if (c->cl_proc->p_nrformals > 0) {
 | 
						|
		/* called procedure has parameters */
 | 
						|
		assert (INSTR(l->l_next) == op_asp);
 | 
						|
		rem_line(l->l_next);
 | 
						|
	}
 | 
						|
	if (INSTR(l->l_next) == op_lfr) {
 | 
						|
		rem_line(l->l_next);
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
 | 
						|
chg_callseq(c,cal,l_out)
 | 
						|
	call_p c;
 | 
						|
	line_p cal,*l_out;
 | 
						|
{
 | 
						|
	/* Change the calling sequence. The actual parameter
 | 
						|
	 * expressions are changed (in line parameters are
 | 
						|
	 * removed, all other ones now store their result
 | 
						|
	 * in a temporary local of the caller);
 | 
						|
	 * the sequence "CAL ; ASP ; LFR" is removed.
 | 
						|
	 */
 | 
						|
 | 
						|
 | 
						|
	chg_actuals(c,cal);
 | 
						|
	*l_out = PREV(cal); /* last instr. of new parameter part */
 | 
						|
	rm_callpart(c,cal);
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/* make_label */
 | 
						|
 | 
						|
line_p make_label(l,p)
 | 
						|
	line_p l;
 | 
						|
	proc_p p;
 | 
						|
{
 | 
						|
	/* Make sure that the instruction after l
 | 
						|
	 * contains an instruction label. If this is
 | 
						|
	 * not already the case, create a new label.
 | 
						|
	 */
 | 
						|
 | 
						|
	line_p lab;
 | 
						|
 | 
						|
	if (l->l_next != (line_p) 0 && INSTR(l->l_next) == op_lab) {
 | 
						|
		return l->l_next;
 | 
						|
	}
 | 
						|
	lab = newline(OPINSTRLAB);
 | 
						|
	lab->l_instr = op_lab;
 | 
						|
	p->p_nrlabels++;
 | 
						|
	INSTRLAB(lab) = p->p_nrlabels;
 | 
						|
	appnd_line(lab,l);
 | 
						|
	return lab;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
 | 
						|
/* modify */
 | 
						|
 | 
						|
STATIC act_info(off,acts,ab_off,act_out,off_out)
 | 
						|
	offset off, ab_off, *off_out;
 | 
						|
	actual_p acts, *act_out;
 | 
						|
{
 | 
						|
	/* Find the actual parameter that corresponds to
 | 
						|
	 * the formal parameter with the given offset.
 | 
						|
	 * Return it via act_out. If the actual is not
 | 
						|
	 * an in-line actual, determine which temporary
 | 
						|
	 * local is used for it; return the offset of that
 | 
						|
	 * local via off_out.
 | 
						|
	 */
 | 
						|
 | 
						|
	offset sum = 0, tmp = 0;
 | 
						|
	actual_p act;
 | 
						|
 | 
						|
	for (act = acts; act != (actual_p) 0; act = act->ac_next) {
 | 
						|
		if (!act->ac_inl) {
 | 
						|
			tmp -= act->ac_size;
 | 
						|
		}
 | 
						|
		if (sum >= off) {
 | 
						|
			/* found */
 | 
						|
			*act_out = act;
 | 
						|
			if (!act->ac_inl) {
 | 
						|
				*off_out = tmp + sum - off + ab_off;
 | 
						|
			} else {
 | 
						|
				assert (sum == off);
 | 
						|
			}
 | 
						|
			return;
 | 
						|
		}
 | 
						|
		sum += act->ac_size;
 | 
						|
	}
 | 
						|
	assert(FALSE);
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
 | 
						|
STATIC store_off(off,l)
 | 
						|
	offset off;
 | 
						|
	line_p l;
 | 
						|
{
 | 
						|
	if (TYPE(l) == OPSHORT) {
 | 
						|
		assert ((short) off == off);
 | 
						|
		SHORT(l) = (short) off;
 | 
						|
	} else {
 | 
						|
		OFFSET(l) = off;
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
 | 
						|
STATIC inl_actual(l,expr)
 | 
						|
	line_p l, expr;
 | 
						|
{
 | 
						|
	/* Expand an actual parameter in line.
 | 
						|
	 * A LOL or LDL instruction is replaced
 | 
						|
	 * by an expression.
 | 
						|
	 * A SIL or LIL is replaced by the expression
 | 
						|
	 * followed by a STI or LOI.
 | 
						|
	 */
 | 
						|
 | 
						|
	line_p e, lnp, s;
 | 
						|
	short  instr;
 | 
						|
 | 
						|
	instr = INSTR(l);
 | 
						|
	assert(expr != (line_p) 0);
 | 
						|
	e = copy_expr(expr); /* make a copy of expr. */
 | 
						|
	if (instr == op_sil || instr == op_lil) {
 | 
						|
		s = int_line((offset) ws);
 | 
						|
		s->l_instr = (instr == op_sil ? op_sti : op_loi);
 | 
						|
		appnd_line(s,last_line(e));
 | 
						|
	} else {
 | 
						|
		assert(instr == op_lol || instr == op_ldl);
 | 
						|
	}
 | 
						|
	lnp = PREV(l);
 | 
						|
	rem_line(l);
 | 
						|
	app_list(e,lnp);
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
 | 
						|
STATIC localref(l,c,ab_off,lb_off)
 | 
						|
	line_p l;
 | 
						|
	call_p c;
 | 
						|
	offset ab_off, lb_off;
 | 
						|
{
 | 
						|
	/* Change a reference to a local variable or parameter
 | 
						|
	 * of the called procedure.
 | 
						|
	 */
 | 
						|
 | 
						|
	offset off, tmpoff;
 | 
						|
	actual_p act;
 | 
						|
 | 
						|
	off = off_set(l);
 | 
						|
	if (off < 0) {
 | 
						|
		/* local variable, only the offset changes */
 | 
						|
		store_off(lb_off + off,l);
 | 
						|
	} else {
 | 
						|
		act_info(off,c->cl_actuals,ab_off,&act,&tmpoff); /* find actual */
 | 
						|
		if (act->ac_inl) {
 | 
						|
			/* inline actual parameter */
 | 
						|
			inl_actual(l,act->ac_exp);
 | 
						|
		} else {
 | 
						|
			/* parameter stored in temporary local */
 | 
						|
			store_off(tmpoff,l);
 | 
						|
		}
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
 | 
						|
STATIC chg_mes(l,c,ab_off,lb_off)
 | 
						|
	line_p l;
 | 
						|
	call_p c;
 | 
						|
	offset ab_off, lb_off;
 | 
						|
{
 | 
						|
	/* The register messages of the called procedure
 | 
						|
	 * must be changed. If the message applies to a
 | 
						|
	 * local variable or to a parameter that is not
 | 
						|
	 * expanded in line, the offset of the variable
 | 
						|
	 * is changed; else the entire message is deleted.
 | 
						|
	 */
 | 
						|
 | 
						|
	offset off, tmpoff;
 | 
						|
	actual_p act;
 | 
						|
	arg_p arg;
 | 
						|
 | 
						|
	arg = ARG(l);
 | 
						|
	switch ((int) arg->a_a.a_offset) {
 | 
						|
	   case ms_reg:
 | 
						|
		if ((arg = arg->a_next) != (arg_p) 0) {
 | 
						|
			/* "mes 3" without further argument is not changed */
 | 
						|
			off = arg->a_a.a_offset;
 | 
						|
			if (off < 0) {
 | 
						|
				/* local variable */
 | 
						|
				arg->a_a.a_offset += lb_off;
 | 
						|
			} else {
 | 
						|
				act_info(off,c->cl_actuals,ab_off,&act,&tmpoff);
 | 
						|
				if (act->ac_inl) {
 | 
						|
					/* in line actual */
 | 
						|
					rem_line(l);
 | 
						|
				} else {
 | 
						|
					arg->a_a.a_offset = tmpoff;
 | 
						|
				}
 | 
						|
			}
 | 
						|
		}
 | 
						|
		break;
 | 
						|
	   case ms_par:
 | 
						|
		rem_line(l);
 | 
						|
		break;
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
 | 
						|
STATIC chg_ret(l,c,lab)
 | 
						|
	line_p l,lab;
 | 
						|
	call_p c;
 | 
						|
{
 | 
						|
	/* Change the RET instruction appearing in the
 | 
						|
	 * expanded text of a call. If the called procedure
 | 
						|
	 * falls through, the RET is just deleted; else it
 | 
						|
	 * is replaced by a branch.
 | 
						|
	 */
 | 
						|
 | 
						|
	line_p lnp, bra;
 | 
						|
 | 
						|
	lnp = PREV(l);
 | 
						|
	rem_line(l);
 | 
						|
	if (!FALLTHROUGH(c->cl_proc)) {
 | 
						|
		bra = newline(OPINSTRLAB);
 | 
						|
		bra->l_instr = op_bra;
 | 
						|
		INSTRLAB(bra) = INSTRLAB(lab);
 | 
						|
		appnd_line(bra,lnp);
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
 | 
						|
STATIC mod_instr(l,c,lab,ab_off,lb_off,lab_off)
 | 
						|
	line_p l,lab;
 | 
						|
	call_p c;
 | 
						|
	offset ab_off,lb_off;
 | 
						|
	int    lab_off;
 | 
						|
{
 | 
						|
	if (TYPE(l) == OPINSTRLAB) {
 | 
						|
		INSTRLAB(l) += lab_off;
 | 
						|
	} else {
 | 
						|
	    switch(INSTR(l)) {
 | 
						|
		case op_stl:
 | 
						|
		case op_inl:
 | 
						|
		case op_del:
 | 
						|
		case op_zrl:
 | 
						|
		case op_sdl:
 | 
						|
		case op_lol:
 | 
						|
		case op_ldl:
 | 
						|
		case op_sil:
 | 
						|
		case op_lil:
 | 
						|
		case op_lal:
 | 
						|
			localref(l,c,ab_off,lb_off);
 | 
						|
			break;
 | 
						|
		case op_ret:
 | 
						|
			chg_ret(l,c,lab);
 | 
						|
			break;
 | 
						|
		case ps_pro:
 | 
						|
		case ps_end:
 | 
						|
		case ps_sym:
 | 
						|
		case ps_hol:
 | 
						|
		case ps_bss:
 | 
						|
		case ps_con:
 | 
						|
		case ps_rom:
 | 
						|
			rem_line(l);
 | 
						|
			break;
 | 
						|
		case ps_mes:
 | 
						|
			chg_mes(l,c,ab_off,lb_off);
 | 
						|
			break;
 | 
						|
	    }
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
modify(text,c,lab,ab_off,lb_off,lab_off)
 | 
						|
	line_p text,lab;
 | 
						|
	call_p c;
 | 
						|
	offset ab_off,lb_off;
 | 
						|
	int    lab_off;
 | 
						|
{
 | 
						|
	/* Modify the EM text of the called procedure.
 | 
						|
	 * References to locals and parameters are
 | 
						|
	 * changed; RETs are either deleted or replaced
 | 
						|
	 * by a BRA to the given label; PRO and END pseudos
 | 
						|
	 * are removed; instruction labels are changed, in
 | 
						|
	 * order to make them different from any label used
 | 
						|
	 * by the caller; some messages need to be changed too.
 | 
						|
	 * Note that the first line of the text is a dummy instruction.
 | 
						|
	 */
 | 
						|
 | 
						|
	register line_p l;
 | 
						|
	line_p next;
 | 
						|
 | 
						|
	for (l = text->l_next; l != (line_p) 0; l = next) {
 | 
						|
		next = l->l_next;
 | 
						|
		/* This is rather tricky. An instruction like
 | 
						|
		 * LOL 2 may be replaced by a number of instructions
 | 
						|
		 * (if the parameter is expanded in line). This inserted
 | 
						|
		 * code, however, should not be modified!
 | 
						|
		 */
 | 
						|
		mod_instr(l,c,lab,ab_off,lb_off,lab_off);
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
 | 
						|
mod_actuals(nc,c,lab,ab_off,lb_off,lab_off)
 | 
						|
	call_p nc,c;
 | 
						|
	line_p lab;
 | 
						|
	offset ab_off,lb_off;
 | 
						|
	int    lab_off;
 | 
						|
{
 | 
						|
	actual_p act;
 | 
						|
	line_p l, next, dum;
 | 
						|
 | 
						|
	dum = newline(OPNO);
 | 
						|
	PREV(dum) = (line_p) 0;
 | 
						|
	for (act = nc->cl_actuals; act != (actual_p) 0; act = act->ac_next) {
 | 
						|
		l = act->ac_exp;
 | 
						|
		assert(l != (line_p) 0);
 | 
						|
		/* Insert a dummy instruction before l */
 | 
						|
		dum->l_next = l;
 | 
						|
		PREV(l) = dum;
 | 
						|
		while(l != (line_p) 0) {
 | 
						|
			next = l->l_next;
 | 
						|
			mod_instr(l,c,lab,ab_off,lb_off,lab_off);
 | 
						|
			l = next;
 | 
						|
		}
 | 
						|
		act->ac_exp = dum->l_next;
 | 
						|
		PREV(dum->l_next) = (line_p) 0;
 | 
						|
	}
 | 
						|
	oldline(dum);
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
 | 
						|
/* insert */
 | 
						|
 | 
						|
STATIC line_p first_nonpseudo(l)
 | 
						|
	line_p l;
 | 
						|
{
 | 
						|
	/* Find the first non-pseudo instruction of
 | 
						|
	 * a list of instructions.
 | 
						|
	 */
 | 
						|
 | 
						|
	while (l != (line_p) 0 && INSTR(l) >= sp_fpseu &&
 | 
						|
		INSTR(l) <= ps_last) l = l->l_next;
 | 
						|
	return l;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
 | 
						|
insert(text,l,firstline)
 | 
						|
	line_p text,l,firstline;
 | 
						|
{
 | 
						|
	/* Insert the modified EM text of the called
 | 
						|
	 * routine in the calling routine. Pseudos are
 | 
						|
	 * put after the pseudos of the caller; all
 | 
						|
	 * normal instructions are put at the place
 | 
						|
	 * where the CAL originally was.
 | 
						|
	 */
 | 
						|
 | 
						|
	line_p l1,l2,lastpseu;
 | 
						|
 | 
						|
	l1 = text->l_next;
 | 
						|
	oldline(text);  /* remove dummy head instruction */
 | 
						|
	if (l1 == (line_p) 0) return; /* no text at all! */
 | 
						|
	l2 = first_nonpseudo(l1);
 | 
						|
	if (l2 == (line_p) 0) {
 | 
						|
		/* modified code consists only  of pseudos */
 | 
						|
		app_list(l1,PREV(first_nonpseudo(firstline)));
 | 
						|
	} else {
 | 
						|
		if (l1 == l2) {
 | 
						|
			/* no pseudos */
 | 
						|
			app_list(l2,l);
 | 
						|
		} else {
 | 
						|
			lastpseu = PREV(first_nonpseudo(firstline));
 | 
						|
			PREV(l2)->l_next = (line_p) 0; /* cut link */
 | 
						|
			app_list(l2,l);  /* insert normal instructions */
 | 
						|
			app_list(l1,lastpseu);
 | 
						|
		}
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
 | 
						|
liquidate(p,text)
 | 
						|
	proc_p p;
 | 
						|
	line_p text;
 | 
						|
{
 | 
						|
	/* All calls to procedure p were expanded in line, so
 | 
						|
	 * p is no longer needed. However, we must not throw away
 | 
						|
	 * any data declarations appearing in p.
 | 
						|
	 * The proctable entry of p is not removed, as we do not
 | 
						|
	 * want to create holes in this table; however the PF_BODYSEEN
 | 
						|
	 * flag is cleared, so p gets the same status as a procedure
 | 
						|
	 * whose body is unmkown.
 | 
						|
	 */
 | 
						|
 | 
						|
	line_p l, nextl, lastkept = (line_p) 0;
 | 
						|
	call_p c, nextc;
 | 
						|
 | 
						|
	for (l = text; l != (line_p) 0; l = nextl) {
 | 
						|
		nextl = l->l_next;
 | 
						|
		switch(INSTR(l)) {
 | 
						|
			case ps_sym:
 | 
						|
			case ps_hol:
 | 
						|
			case ps_bss:
 | 
						|
			case ps_con:
 | 
						|
			case ps_rom:
 | 
						|
				lastkept = l;
 | 
						|
				break;
 | 
						|
			default:
 | 
						|
				rem_line(l);
 | 
						|
		}
 | 
						|
	}
 | 
						|
	if (lastkept != (line_p) 0) {
 | 
						|
		/* There were some data declarations in p,
 | 
						|
		 * so we'll turn p into a data-unit; we'll
 | 
						|
		 * have to append an end-pseudo for this
 | 
						|
		 * purpose.
 | 
						|
		 */
 | 
						|
		lastkept->l_next = newline(OPNO);
 | 
						|
		lastkept->l_next->l_instr = (byte) ps_end;
 | 
						|
	}
 | 
						|
	/* There may be some calls in the body of p that
 | 
						|
	 * ought to be expanded in line. As p is removed
 | 
						|
	 * anyway, there is no use in really performing
 | 
						|
	 * these substitutions, so the call-descriptors
 | 
						|
	 * are just thrown away.
 | 
						|
	 */
 | 
						|
 | 
						|
	 for (c = p->P_CALS; c != (call_p) 0; c = nextc) {
 | 
						|
		nextc = c->cl_cdr;
 | 
						|
		rem_call(c);
 | 
						|
	}
 | 
						|
	/* change the proctable entry */
 | 
						|
	p->p_flags1 &= (byte) ~PF_BODYSEEN;
 | 
						|
	oldchange(p->p_change);
 | 
						|
	olduse(p->p_use);
 | 
						|
}
 |