xref: /netbsd/external/bsd/pcc/dist/pcc/cc/ccom/inline.c (revision 6935091c)
1*6935091cSplunky /*	Id: inline.c,v 1.65 2015/11/17 19:19:40 ragge Exp 	*/
2*6935091cSplunky /*	$NetBSD: inline.c,v 1.1.1.7 2016/02/09 20:28:50 plunky Exp $	*/
36e0bca22Sgmcgarry /*
4c4627bc7Sgmcgarry  * Copyright (c) 2003, 2008 Anders Magnusson (ragge@ludd.luth.se).
56e0bca22Sgmcgarry  * All rights reserved.
66e0bca22Sgmcgarry  *
76e0bca22Sgmcgarry  * Redistribution and use in source and binary forms, with or without
86e0bca22Sgmcgarry  * modification, are permitted provided that the following conditions
96e0bca22Sgmcgarry  * are met:
106e0bca22Sgmcgarry  * 1. Redistributions of source code must retain the above copyright
116e0bca22Sgmcgarry  *    notice, this list of conditions and the following disclaimer.
126e0bca22Sgmcgarry  * 2. Redistributions in binary form must reproduce the above copyright
136e0bca22Sgmcgarry  *    notice, this list of conditions and the following disclaimer in the
146e0bca22Sgmcgarry  *    documentation and/or other materials provided with the distribution.
156e0bca22Sgmcgarry  *
166e0bca22Sgmcgarry  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
176e0bca22Sgmcgarry  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
186e0bca22Sgmcgarry  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
196e0bca22Sgmcgarry  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
206e0bca22Sgmcgarry  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
216e0bca22Sgmcgarry  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
226e0bca22Sgmcgarry  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
236e0bca22Sgmcgarry  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
246e0bca22Sgmcgarry  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
256e0bca22Sgmcgarry  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
266e0bca22Sgmcgarry  */
276e0bca22Sgmcgarry 
286e0bca22Sgmcgarry 
296e0bca22Sgmcgarry #include "pass1.h"
306e0bca22Sgmcgarry 
316e0bca22Sgmcgarry #include <stdarg.h>
326e0bca22Sgmcgarry 
336e0bca22Sgmcgarry /*
34c4627bc7Sgmcgarry  * Simple description of how the inlining works:
35c4627bc7Sgmcgarry  * A function found with the keyword "inline" is always saved.
36c4627bc7Sgmcgarry  * If it also has the keyword "extern" it is written out thereafter.
37c4627bc7Sgmcgarry  * If it has the keyword "static" it will be written out if it is referenced.
38c4627bc7Sgmcgarry  * inlining will only be done if -xinline is given, and only if it is
39c4627bc7Sgmcgarry  * possible to inline the function.
40c4627bc7Sgmcgarry  */
41c4627bc7Sgmcgarry static void printip(struct interpass *pole);
42c4627bc7Sgmcgarry 
43a301e773Splunky struct ntds {
44a301e773Splunky 	int temp;
45a301e773Splunky 	TWORD type;
46a301e773Splunky 	union dimfun *df;
47a301e773Splunky 	struct attr *attr;
48a301e773Splunky };
49a301e773Splunky 
50c4627bc7Sgmcgarry /*
516e0bca22Sgmcgarry  * ilink from ipole points to the next struct in the list of functions.
526e0bca22Sgmcgarry  */
536e0bca22Sgmcgarry static struct istat {
54c4627bc7Sgmcgarry 	SLIST_ENTRY(istat) link;
556e0bca22Sgmcgarry 	struct symtab *sp;
56c4627bc7Sgmcgarry 	int flags;
57c4627bc7Sgmcgarry #define	CANINL	1	/* function is possible to inline */
58c4627bc7Sgmcgarry #define	WRITTEN	2	/* function is written out */
59c4627bc7Sgmcgarry #define	REFD	4	/* Referenced but not yet written out */
60a301e773Splunky 	struct ntds *nt;/* Array of arg temp type data */
61c4627bc7Sgmcgarry 	int nargs;	/* number of args in array */
62c4627bc7Sgmcgarry 	int retval;	/* number of return temporary, if any */
636e0bca22Sgmcgarry 	struct interpass shead;
64c4627bc7Sgmcgarry } *cifun;
65c4627bc7Sgmcgarry 
66c4627bc7Sgmcgarry static SLIST_HEAD(, istat) ipole = { NULL, &ipole.q_forw };
672d03e475Splunky static int nlabs, svclass;
686e0bca22Sgmcgarry 
696e0bca22Sgmcgarry #define	IP_REF	(MAXIP+1)
70c4627bc7Sgmcgarry #ifdef PCC_DEBUG
71c4627bc7Sgmcgarry #define	SDEBUG(x)	if (sdebug) printf x
72c4627bc7Sgmcgarry #else
73c4627bc7Sgmcgarry #define	SDEBUG(x)
74c4627bc7Sgmcgarry #endif
756e0bca22Sgmcgarry 
76c4627bc7Sgmcgarry int isinlining;
77*6935091cSplunky int inlstatcnt;
786e0bca22Sgmcgarry 
79c4627bc7Sgmcgarry #define	SZSI	sizeof(struct istat)
80*6935091cSplunky int istatsz = SZSI;
81c4627bc7Sgmcgarry #define	ialloc() memset(permalloc(SZSI), 0, SZSI); inlstatcnt++
826e0bca22Sgmcgarry 
832d03e475Splunky /*
842d03e475Splunky  * Get prolog/epilog for a function.
852d03e475Splunky  */
862d03e475Splunky static struct interpass_prolog *
getprol(struct istat * is,int type)872d03e475Splunky getprol(struct istat *is, int type)
882d03e475Splunky {
892d03e475Splunky 	struct interpass *ip;
902d03e475Splunky 
912d03e475Splunky 	DLIST_FOREACH(ip, &is->shead, qelem)
922d03e475Splunky 		if (ip->type == type)
932d03e475Splunky 			return (struct interpass_prolog *)ip;
942d03e475Splunky 	cerror("getprol: %d not found", type);
952d03e475Splunky 	return 0; /* XXX */
962d03e475Splunky }
972d03e475Splunky 
986e0bca22Sgmcgarry static struct istat *
findfun(struct symtab * sp)996e0bca22Sgmcgarry findfun(struct symtab *sp)
1006e0bca22Sgmcgarry {
101c4627bc7Sgmcgarry 	struct istat *is;
102c4627bc7Sgmcgarry 
103c4627bc7Sgmcgarry 	SLIST_FOREACH(is, &ipole, link)
1046e0bca22Sgmcgarry 		if (is->sp == sp)
1056e0bca22Sgmcgarry 			return is;
1066e0bca22Sgmcgarry 	return NULL;
1076e0bca22Sgmcgarry }
1086e0bca22Sgmcgarry 
1096e0bca22Sgmcgarry static void
refnode(struct symtab * sp)1106e0bca22Sgmcgarry refnode(struct symtab *sp)
1116e0bca22Sgmcgarry {
1126e0bca22Sgmcgarry 	struct interpass *ip;
1136e0bca22Sgmcgarry 
114c4627bc7Sgmcgarry 	SDEBUG(("refnode(%s)\n", sp->sname));
1156e0bca22Sgmcgarry 
1166e0bca22Sgmcgarry 	ip = permalloc(sizeof(*ip));
1176e0bca22Sgmcgarry 	ip->type = IP_REF;
1186e0bca22Sgmcgarry 	ip->ip_name = (char *)sp;
1196e0bca22Sgmcgarry 	inline_addarg(ip);
1206e0bca22Sgmcgarry }
1216e0bca22Sgmcgarry 
122*6935091cSplunky /*
123*6935091cSplunky  * Save attributes permanent.
124*6935091cSplunky  */
125*6935091cSplunky static struct attr *
inapcopy(struct attr * ap)126*6935091cSplunky inapcopy(struct attr *ap)
127*6935091cSplunky {
128*6935091cSplunky 	struct attr *nap = attr_dup(ap);
129*6935091cSplunky 
130*6935091cSplunky 	if (ap->next)
131*6935091cSplunky 		nap->next = inapcopy(ap->next);
132*6935091cSplunky 	return nap;
133*6935091cSplunky }
134*6935091cSplunky 
135*6935091cSplunky /*
136*6935091cSplunky  * Copy a tree onto the permanent heap to save for inline.
137*6935091cSplunky  */
138*6935091cSplunky static NODE *
intcopy(NODE * p)139*6935091cSplunky intcopy(NODE *p)
140*6935091cSplunky {
141*6935091cSplunky 	NODE *q = permalloc(sizeof(NODE));
142*6935091cSplunky 	int o = coptype(p->n_op); /* XXX pass2 optype? */
143*6935091cSplunky 
144*6935091cSplunky 	*q = *p;
145*6935091cSplunky 	if (nlabs > 1 && (p->n_op == REG || p->n_op == OREG) &&
146*6935091cSplunky 	    regno(p) == FPREG)
147*6935091cSplunky 		SLIST_FIRST(&ipole)->flags &= ~CANINL; /* no stack refs */
148*6935091cSplunky 	if (q->n_ap)
149*6935091cSplunky 		q->n_ap = inapcopy(q->n_ap);
150*6935091cSplunky 	if (q->n_op == NAME || q->n_op == ICON ||
151*6935091cSplunky 	    q->n_op == XASM || q->n_op == XARG) {
152*6935091cSplunky 		if (*q->n_name)
153*6935091cSplunky 			q->n_name = xstrdup(q->n_name); /* XXX permstrdup */
154*6935091cSplunky 		else
155*6935091cSplunky 			q->n_name = "";
156*6935091cSplunky 	}
157*6935091cSplunky 	if (o == BITYPE)
158*6935091cSplunky 		q->n_right = intcopy(q->n_right);
159*6935091cSplunky 	if (o != LTYPE)
160*6935091cSplunky 		q->n_left = intcopy(q->n_left);
161*6935091cSplunky 	return q;
162*6935091cSplunky }
163*6935091cSplunky 
1646e0bca22Sgmcgarry void
inline_addarg(struct interpass * ip)1656e0bca22Sgmcgarry inline_addarg(struct interpass *ip)
1666e0bca22Sgmcgarry {
167*6935091cSplunky 	struct interpass_prolog *ipp;
168*6935091cSplunky 	NODE *q;
169*6935091cSplunky 	static int g = 0;
170*6935091cSplunky 	extern P1ND *cftnod;
171c4627bc7Sgmcgarry 
172c4627bc7Sgmcgarry 	SDEBUG(("inline_addarg(%p)\n", ip));
1736e0bca22Sgmcgarry 	DLIST_INSERT_BEFORE(&cifun->shead, ip, qelem);
174*6935091cSplunky 	switch (ip->type) {
175*6935091cSplunky 	case IP_ASM:
176*6935091cSplunky 		ip->ip_asm = xstrdup(ip->ip_asm);
177*6935091cSplunky 		break;
178*6935091cSplunky 	case IP_DEFLAB:
179c4627bc7Sgmcgarry 		nlabs++;
180*6935091cSplunky 		break;
181*6935091cSplunky 	case IP_NODE:
182*6935091cSplunky 		q = ip->ip_node;
183*6935091cSplunky 		ip->ip_node = intcopy(ip->ip_node);
184*6935091cSplunky 		tfree(q);
185*6935091cSplunky 		break;
186*6935091cSplunky 	case IP_EPILOG:
187*6935091cSplunky 		ipp = (struct interpass_prolog *)ip;
188*6935091cSplunky 		if (ipp->ip_labels[0])
189*6935091cSplunky 			uerror("no computed goto in inlined functions");
190*6935091cSplunky 		ipp->ip_labels = &g;
191*6935091cSplunky 		break;
192*6935091cSplunky 	}
193c4627bc7Sgmcgarry 	if (cftnod)
194c4627bc7Sgmcgarry 		cifun->retval = regno(cftnod);
1956e0bca22Sgmcgarry }
1966e0bca22Sgmcgarry 
1976e0bca22Sgmcgarry /*
1986e0bca22Sgmcgarry  * Called to setup for inlining of a new function.
1996e0bca22Sgmcgarry  */
2006e0bca22Sgmcgarry void
inline_start(struct symtab * sp,int class)2012d03e475Splunky inline_start(struct symtab *sp, int class)
2026e0bca22Sgmcgarry {
2036e0bca22Sgmcgarry 	struct istat *is;
2046e0bca22Sgmcgarry 
205c4627bc7Sgmcgarry 	SDEBUG(("inline_start(\"%s\")\n", sp->sname));
2066e0bca22Sgmcgarry 
2076e0bca22Sgmcgarry 	if (isinlining)
2086e0bca22Sgmcgarry 		cerror("already inlining function");
2096e0bca22Sgmcgarry 
2102d03e475Splunky 	svclass = class;
211c4627bc7Sgmcgarry 	if ((is = findfun(sp)) != 0) {
212c4627bc7Sgmcgarry 		if (!DLIST_ISEMPTY(&is->shead, qelem))
213c4627bc7Sgmcgarry 			uerror("inline function already defined");
2146e0bca22Sgmcgarry 	} else {
215c4627bc7Sgmcgarry 		is = ialloc();
216c4627bc7Sgmcgarry 		is->sp = sp;
217c4627bc7Sgmcgarry 		SLIST_INSERT_FIRST(&ipole, is, link);
2186e0bca22Sgmcgarry 		DLIST_INIT(&is->shead, qelem);
219c4627bc7Sgmcgarry 	}
2206e0bca22Sgmcgarry 	cifun = is;
221c4627bc7Sgmcgarry 	nlabs = 0;
2226e0bca22Sgmcgarry 	isinlining++;
2236e0bca22Sgmcgarry }
2246e0bca22Sgmcgarry 
225c4627bc7Sgmcgarry /*
226c4627bc7Sgmcgarry  * End of an inline function. In C99 an inline function declared "extern"
227c4627bc7Sgmcgarry  * should also have external linkage and are therefore printed out.
228a301e773Splunky  *
229a301e773Splunky  * Gcc inline syntax is a mess, see matrix below on emitting functions:
230a301e773Splunky  *		    without extern
231a301e773Splunky  *	-std=		-	gnu89	gnu99
232a301e773Splunky  *	gcc 3.3.5:	ja	ja	ja
233a301e773Splunky  *	gcc 4.1.3:	ja	ja	ja
234a301e773Splunky  *	gcc 4.3.1	ja	ja	nej
235a301e773Splunky  *
236a301e773Splunky  *		     with extern
237a301e773Splunky  *	gcc 3.3.5:	nej	nej	nej
238a301e773Splunky  *	gcc 4.1.3:	nej	nej	nej
239a301e773Splunky  *	gcc 4.3.1	nej	nej	ja
240a301e773Splunky  *
2412d03e475Splunky  * The above is only true if extern is given on the same line as the
2422d03e475Splunky  * function declaration.  If given as a separate definition it do not count.
2432d03e475Splunky  *
244a301e773Splunky  * The attribute gnu_inline sets gnu89 behaviour.
245a301e773Splunky  * Since pcc mimics gcc 4.3.1 that is the behaviour we emulate.
246c4627bc7Sgmcgarry  */
2476e0bca22Sgmcgarry void
inline_end(void)2482d03e475Splunky inline_end(void)
2496e0bca22Sgmcgarry {
250a301e773Splunky 	struct symtab *sp = cifun->sp;
2516e0bca22Sgmcgarry 
252c4627bc7Sgmcgarry 	SDEBUG(("inline_end()\n"));
253c4627bc7Sgmcgarry 
254c4627bc7Sgmcgarry 	if (sdebug)printip(&cifun->shead);
2556e0bca22Sgmcgarry 	isinlining = 0;
256c4627bc7Sgmcgarry 
2572d03e475Splunky 	if (xgnu89 && svclass == SNULL)
2582d03e475Splunky 		sp->sclass = EXTERN;
2592d03e475Splunky 
2602d03e475Splunky #ifdef GCC_COMPAT
261a301e773Splunky 	if (sp->sclass != STATIC &&
262a301e773Splunky 	    (attr_find(sp->sap, GCC_ATYP_GNU_INLINE) || xgnu89)) {
263a301e773Splunky 		if (sp->sclass == EXTDEF)
2642d03e475Splunky 			sp->sclass = EXTERN;
265c4627bc7Sgmcgarry 		else
266a301e773Splunky 			sp->sclass = EXTDEF;
267c4627bc7Sgmcgarry 	}
2682d03e475Splunky #endif
269c4627bc7Sgmcgarry 
270a301e773Splunky 	if (sp->sclass == EXTDEF) {
271c4627bc7Sgmcgarry 		cifun->flags |= REFD;
272c4627bc7Sgmcgarry 		inline_prtout();
273c4627bc7Sgmcgarry 	}
2746e0bca22Sgmcgarry }
2756e0bca22Sgmcgarry 
2766e0bca22Sgmcgarry /*
2776e0bca22Sgmcgarry  * Called when an inline function is found, to be sure that it will
2786e0bca22Sgmcgarry  * be written out.
2796e0bca22Sgmcgarry  * The function may not be defined when inline_ref() is called.
2806e0bca22Sgmcgarry  */
2816e0bca22Sgmcgarry void
inline_ref(struct symtab * sp)2826e0bca22Sgmcgarry inline_ref(struct symtab *sp)
2836e0bca22Sgmcgarry {
284c4627bc7Sgmcgarry 	struct istat *w;
2856e0bca22Sgmcgarry 
286c4627bc7Sgmcgarry 	SDEBUG(("inline_ref(\"%s\")\n", sp->sname));
287c4627bc7Sgmcgarry 	if (sp->sclass == SNULL)
288c4627bc7Sgmcgarry 		return; /* only inline, no references */
2896e0bca22Sgmcgarry 	if (isinlining) {
2906e0bca22Sgmcgarry 		refnode(sp);
2916e0bca22Sgmcgarry 	} else {
292c4627bc7Sgmcgarry 		SLIST_FOREACH(w,&ipole, link) {
293c4627bc7Sgmcgarry 			if (w->sp != sp)
294c4627bc7Sgmcgarry 				continue;
295c4627bc7Sgmcgarry 			w->flags |= REFD;
296c4627bc7Sgmcgarry 			return;
2976e0bca22Sgmcgarry 		}
2986e0bca22Sgmcgarry 		/* function not yet defined, print out when found */
2996e0bca22Sgmcgarry 		w = ialloc();
3006e0bca22Sgmcgarry 		w->sp = sp;
301c4627bc7Sgmcgarry 		w->flags |= REFD;
302c4627bc7Sgmcgarry 		SLIST_INSERT_FIRST(&ipole, w, link);
303c4627bc7Sgmcgarry 		DLIST_INIT(&w->shead, qelem);
3046e0bca22Sgmcgarry 	}
3056e0bca22Sgmcgarry }
3066e0bca22Sgmcgarry 
3076e0bca22Sgmcgarry static void
puto(struct istat * w)3086e0bca22Sgmcgarry puto(struct istat *w)
3096e0bca22Sgmcgarry {
310c4627bc7Sgmcgarry 	struct interpass_prolog *ipp, *epp, *pp;
3116e0bca22Sgmcgarry 	struct interpass *ip, *nip;
312c4627bc7Sgmcgarry 	extern int crslab;
313c4627bc7Sgmcgarry 	int lbloff = 0;
3146e0bca22Sgmcgarry 
315c4627bc7Sgmcgarry 	/* Copy the saved function and print it out */
316c4627bc7Sgmcgarry 	ipp = 0; /* XXX data flow analysis */
317c4627bc7Sgmcgarry 	DLIST_FOREACH(ip, &w->shead, qelem) {
318c4627bc7Sgmcgarry 		switch (ip->type) {
319c4627bc7Sgmcgarry 		case IP_EPILOG:
320c4627bc7Sgmcgarry 		case IP_PROLOG:
321c4627bc7Sgmcgarry 			if (ip->type == IP_PROLOG) {
322c4627bc7Sgmcgarry 				ipp = (struct interpass_prolog *)ip;
323c4627bc7Sgmcgarry 				/* fix label offsets */
324c4627bc7Sgmcgarry 				lbloff = crslab - ipp->ip_lblnum;
325c4627bc7Sgmcgarry 			} else {
326c4627bc7Sgmcgarry 				epp = (struct interpass_prolog *)ip;
327c4627bc7Sgmcgarry 				crslab += (epp->ip_lblnum - ipp->ip_lblnum);
3286e0bca22Sgmcgarry 			}
329*6935091cSplunky 			pp = xmalloc(sizeof(struct interpass_prolog));
330c4627bc7Sgmcgarry 			memcpy(pp, ip, sizeof(struct interpass_prolog));
331c4627bc7Sgmcgarry 			pp->ip_lblnum += lbloff;
332c4627bc7Sgmcgarry #ifdef PCC_DEBUG
333c4627bc7Sgmcgarry 			if (ip->type == IP_EPILOG && crslab != pp->ip_lblnum)
334c4627bc7Sgmcgarry 				cerror("puto: %d != %d", crslab, pp->ip_lblnum);
335c4627bc7Sgmcgarry #endif
336c4627bc7Sgmcgarry 			pass2_compile((struct interpass *)pp);
337c4627bc7Sgmcgarry 			break;
338c4627bc7Sgmcgarry 
339c4627bc7Sgmcgarry 		case IP_REF:
340c4627bc7Sgmcgarry 			inline_ref((struct symtab *)ip->ip_name);
341c4627bc7Sgmcgarry 			break;
342c4627bc7Sgmcgarry 
343c4627bc7Sgmcgarry 		default:
344*6935091cSplunky 			nip = xmalloc(sizeof(struct interpass));
345c4627bc7Sgmcgarry 			*nip = *ip;
346c4627bc7Sgmcgarry 			if (nip->type == IP_NODE) {
347c4627bc7Sgmcgarry 				NODE *p;
348c4627bc7Sgmcgarry 
349*6935091cSplunky 				p = nip->ip_node = tcopy(nip->ip_node);
350c4627bc7Sgmcgarry 				if (p->n_op == GOTO)
351*6935091cSplunky 					slval(p->n_left,
352*6935091cSplunky 					    glval(p->n_left) + lbloff);
353c4627bc7Sgmcgarry 				else if (p->n_op == CBRANCH)
354*6935091cSplunky 					slval(p->n_right,
355*6935091cSplunky 					    glval(p->n_right) + lbloff);
356c4627bc7Sgmcgarry 			} else if (nip->type == IP_DEFLAB)
357c4627bc7Sgmcgarry 				nip->ip_lbl += lbloff;
358c4627bc7Sgmcgarry 			pass2_compile(nip);
359c4627bc7Sgmcgarry 			break;
360c4627bc7Sgmcgarry 		}
361c4627bc7Sgmcgarry 	}
362c4627bc7Sgmcgarry 	w->flags |= WRITTEN;
3636e0bca22Sgmcgarry }
3646e0bca22Sgmcgarry 
3656e0bca22Sgmcgarry /*
3666e0bca22Sgmcgarry  * printout functions that are referenced.
3676e0bca22Sgmcgarry  */
3686e0bca22Sgmcgarry void
inline_prtout(void)3692d03e475Splunky inline_prtout(void)
3706e0bca22Sgmcgarry {
371c4627bc7Sgmcgarry 	struct istat *w;
3726e0bca22Sgmcgarry 	int gotone = 0;
3736e0bca22Sgmcgarry 
374c4627bc7Sgmcgarry 	SLIST_FOREACH(w, &ipole, link) {
375c4627bc7Sgmcgarry 		if ((w->flags & (REFD|WRITTEN)) == REFD &&
376c4627bc7Sgmcgarry 		    !DLIST_ISEMPTY(&w->shead, qelem)) {
377a301e773Splunky 			locctr(PROG, w->sp);
3786e0bca22Sgmcgarry 			defloc(w->sp);
3796e0bca22Sgmcgarry 			puto(w);
380c4627bc7Sgmcgarry 			w->flags |= WRITTEN;
3816e0bca22Sgmcgarry 			gotone++;
3826e0bca22Sgmcgarry 		}
3836e0bca22Sgmcgarry 	}
3846e0bca22Sgmcgarry 	if (gotone)
3856e0bca22Sgmcgarry 		inline_prtout();
386c4627bc7Sgmcgarry }
387c4627bc7Sgmcgarry 
388c4627bc7Sgmcgarry #if 1
389c4627bc7Sgmcgarry static void
printip(struct interpass * pole)390c4627bc7Sgmcgarry printip(struct interpass *pole)
391c4627bc7Sgmcgarry {
392c4627bc7Sgmcgarry 	static char *foo[] = {
393c4627bc7Sgmcgarry 	   0, "NODE", "PROLOG", "STKOFF", "EPILOG", "DEFLAB", "DEFNAM", "ASM" };
394c4627bc7Sgmcgarry 	struct interpass *ip;
395c4627bc7Sgmcgarry 	struct interpass_prolog *ipplg, *epplg;
396c4627bc7Sgmcgarry 
397c4627bc7Sgmcgarry 	DLIST_FOREACH(ip, pole, qelem) {
398c4627bc7Sgmcgarry 		if (ip->type > MAXIP)
399c4627bc7Sgmcgarry 			printf("IP(%d) (%p): ", ip->type, ip);
400c4627bc7Sgmcgarry 		else
401c4627bc7Sgmcgarry 			printf("%s (%p): ", foo[ip->type], ip);
402c4627bc7Sgmcgarry 		switch (ip->type) {
403c4627bc7Sgmcgarry 		case IP_NODE: printf("\n");
404c4627bc7Sgmcgarry #ifdef PCC_DEBUG
405*6935091cSplunky #ifndef TWOPASS
406*6935091cSplunky 			{ extern void e2print(NODE *p, int down, int *a, int *b);
407*6935091cSplunky 			fwalk(ip->ip_node, e2print, 0); break; }
408*6935091cSplunky #endif
409c4627bc7Sgmcgarry #endif
410c4627bc7Sgmcgarry 		case IP_PROLOG:
411c4627bc7Sgmcgarry 			ipplg = (struct interpass_prolog *)ip;
412c4627bc7Sgmcgarry 			printf("%s %s regs %lx autos %d mintemp %d minlbl %d\n",
413c4627bc7Sgmcgarry 			    ipplg->ipp_name, ipplg->ipp_vis ? "(local)" : "",
414c4627bc7Sgmcgarry 			    (long)ipplg->ipp_regs[0], ipplg->ipp_autos,
415c4627bc7Sgmcgarry 			    ipplg->ip_tmpnum, ipplg->ip_lblnum);
416c4627bc7Sgmcgarry 			break;
417c4627bc7Sgmcgarry 		case IP_EPILOG:
418c4627bc7Sgmcgarry 			epplg = (struct interpass_prolog *)ip;
419c4627bc7Sgmcgarry 			printf("%s %s regs %lx autos %d mintemp %d minlbl %d\n",
420c4627bc7Sgmcgarry 			    epplg->ipp_name, epplg->ipp_vis ? "(local)" : "",
421c4627bc7Sgmcgarry 			    (long)epplg->ipp_regs[0], epplg->ipp_autos,
422c4627bc7Sgmcgarry 			    epplg->ip_tmpnum, epplg->ip_lblnum);
423c4627bc7Sgmcgarry 			break;
424c4627bc7Sgmcgarry 		case IP_DEFLAB: printf(LABFMT "\n", ip->ip_lbl); break;
425c4627bc7Sgmcgarry 		case IP_DEFNAM: printf("\n"); break;
4262d03e475Splunky 		case IP_ASM: printf("%s", ip->ip_asm); break;
427c4627bc7Sgmcgarry 		default:
428c4627bc7Sgmcgarry 			break;
429c4627bc7Sgmcgarry 		}
430c4627bc7Sgmcgarry 	}
431c4627bc7Sgmcgarry }
432c4627bc7Sgmcgarry #endif
433c4627bc7Sgmcgarry 
434c4627bc7Sgmcgarry static int toff;
435c4627bc7Sgmcgarry 
436*6935091cSplunky static P1ND *
mnode(struct ntds * nt,P1ND * p)437*6935091cSplunky mnode(struct ntds *nt, P1ND *p)
438c4627bc7Sgmcgarry {
439*6935091cSplunky 	P1ND *q;
440a301e773Splunky 	int num = nt->temp + toff;
441c4627bc7Sgmcgarry 
442c4627bc7Sgmcgarry 	if (p->n_op == CM) {
443c4627bc7Sgmcgarry 		q = p->n_right;
444a301e773Splunky 		q = tempnode(num, nt->type, nt->df, nt->attr);
445a301e773Splunky 		nt--;
446c4627bc7Sgmcgarry 		p->n_right = buildtree(ASSIGN, q, p->n_right);
447a301e773Splunky 		p->n_left = mnode(nt, p->n_left);
448c4627bc7Sgmcgarry 		p->n_op = COMOP;
449c4627bc7Sgmcgarry 	} else {
450c4627bc7Sgmcgarry 		p = pconvert(p);
451a301e773Splunky 		q = tempnode(num, nt->type, nt->df, nt->attr);
452c4627bc7Sgmcgarry 		p = buildtree(ASSIGN, q, p);
453c4627bc7Sgmcgarry 	}
454c4627bc7Sgmcgarry 	return p;
455c4627bc7Sgmcgarry }
456c4627bc7Sgmcgarry 
457c4627bc7Sgmcgarry static void
rtmps(NODE * p,void * arg)458c4627bc7Sgmcgarry rtmps(NODE *p, void *arg)
459c4627bc7Sgmcgarry {
460c4627bc7Sgmcgarry 	if (p->n_op == TEMP)
461c4627bc7Sgmcgarry 		regno(p) += toff;
462c4627bc7Sgmcgarry }
463c4627bc7Sgmcgarry 
464c4627bc7Sgmcgarry /*
465c4627bc7Sgmcgarry  * Inline a function. Returns the return value.
466c4627bc7Sgmcgarry  * There are two major things that must be converted when
467c4627bc7Sgmcgarry  * inlining a function:
468c4627bc7Sgmcgarry  * - Label numbers must be updated with an offset.
469c4627bc7Sgmcgarry  * - The stack block must be relocated (add to REG or OREG).
470c4627bc7Sgmcgarry  * - Temporaries should be updated (but no must)
471*6935091cSplunky  *
472*6935091cSplunky  * Extra tricky:  The call is P1ND, nut the resulting tree is already NODE...
473c4627bc7Sgmcgarry  */
474*6935091cSplunky P1ND *
inlinetree(struct symtab * sp,P1ND * f,P1ND * ap)475*6935091cSplunky inlinetree(struct symtab *sp, P1ND *f, P1ND *ap)
476c4627bc7Sgmcgarry {
477c4627bc7Sgmcgarry 	extern int crslab, tvaloff;
478c4627bc7Sgmcgarry 	struct istat *is = findfun(sp);
479c4627bc7Sgmcgarry 	struct interpass *ip, *ipf, *ipl;
4802d03e475Splunky 	struct interpass_prolog *ipp, *ipe;
4812d03e475Splunky 	int lmin, l0, l1, l2, gainl, n;
482*6935091cSplunky 	NODE *pp;
483*6935091cSplunky 	P1ND *p, *rp;
484c4627bc7Sgmcgarry 
485a301e773Splunky 	if (is == NULL || nerrors) {
486c4627bc7Sgmcgarry 		inline_ref(sp); /* prototype of not yet declared inline ftn */
487*6935091cSplunky 		return NULL;
488c4627bc7Sgmcgarry 	}
489c4627bc7Sgmcgarry 
490c4627bc7Sgmcgarry 	SDEBUG(("inlinetree(%p,%p) OK %d\n", f, ap, is->flags & CANINL));
491c4627bc7Sgmcgarry 
4922d03e475Splunky #ifdef GCC_COMPAT
493a301e773Splunky 	gainl = attr_find(sp->sap, GCC_ATYP_ALW_INL) != NULL;
4942d03e475Splunky #else
4952d03e475Splunky 	gainl = 0;
4962d03e475Splunky #endif
497a301e773Splunky 
4982d03e475Splunky 	n = nerrors;
499a301e773Splunky 	if ((is->flags & CANINL) == 0 && gainl)
500a301e773Splunky 		werror("cannot inline but always_inline");
5012d03e475Splunky 	nerrors = n;
502a301e773Splunky 
503a301e773Splunky 	if ((is->flags & CANINL) == 0 || (xinline == 0 && gainl == 0)) {
504c4627bc7Sgmcgarry 		if (is->sp->sclass == STATIC || is->sp->sclass == USTATIC)
505a301e773Splunky 			inline_ref(sp);
506*6935091cSplunky 		return NULL;
507a301e773Splunky 	}
508a301e773Splunky 
509a301e773Splunky 	if (isinlining && cifun->sp == sp) {
510a301e773Splunky 		/* Do not try to inline ourselves */
511a301e773Splunky 		inline_ref(sp);
512*6935091cSplunky 		return NULL;
513c4627bc7Sgmcgarry 	}
514c4627bc7Sgmcgarry 
515c4627bc7Sgmcgarry #ifdef mach_i386
516c4627bc7Sgmcgarry 	if (kflag) {
517c4627bc7Sgmcgarry 		is->flags |= REFD; /* if static inline, emit */
518*6935091cSplunky 		return NULL; /* XXX cannot handle hidden ebx arg */
519c4627bc7Sgmcgarry 	}
520c4627bc7Sgmcgarry #endif
521c4627bc7Sgmcgarry 
522c4627bc7Sgmcgarry 	/* emit jumps to surround inline function */
523c4627bc7Sgmcgarry 	branch(l0 = getlab());
524c4627bc7Sgmcgarry 	plabel(l1 = getlab());
525c4627bc7Sgmcgarry 	l2 = getlab();
526c4627bc7Sgmcgarry 	SDEBUG(("branch labels %d,%d,%d\n", l0, l1, l2));
527c4627bc7Sgmcgarry 
528*6935091cSplunky 	/* From here it is NODE */
529*6935091cSplunky 
5302d03e475Splunky 	ipp = getprol(is, IP_PROLOG);
5312d03e475Splunky 	ipe = getprol(is, IP_EPILOG);
532c4627bc7Sgmcgarry 
533c4627bc7Sgmcgarry 	/* Fix label & temp offsets */
5342d03e475Splunky 
535c4627bc7Sgmcgarry 	SDEBUG(("pre-offsets crslab %d tvaloff %d\n", crslab, tvaloff));
5362d03e475Splunky 	lmin = crslab - ipp->ip_lblnum;
537*6935091cSplunky 	crslab += (ipe->ip_lblnum - ipp->ip_lblnum) + 2;
5382d03e475Splunky 	toff = tvaloff - ipp->ip_tmpnum;
5392d03e475Splunky 	tvaloff += (ipe->ip_tmpnum - ipp->ip_tmpnum) + 1;
540c4627bc7Sgmcgarry 	SDEBUG(("offsets crslab %d lmin %d tvaloff %d toff %d\n",
541c4627bc7Sgmcgarry 	    crslab, lmin, tvaloff, toff));
542c4627bc7Sgmcgarry 
543c4627bc7Sgmcgarry 	/* traverse until first real label */
5442d03e475Splunky 	n = 0;
5452d03e475Splunky 	DLIST_FOREACH(ipf, &is->shead, qelem) {
5462d03e475Splunky 		if (ipf->type == IP_REF)
5472d03e475Splunky 			inline_ref((struct symtab *)ipf->ip_name);
5482d03e475Splunky 		if (ipf->type == IP_DEFLAB && n++ == 1)
5492d03e475Splunky 			break;
5502d03e475Splunky 	}
551c4627bc7Sgmcgarry 
552c4627bc7Sgmcgarry 	/* traverse backwards to last label */
5532d03e475Splunky 	DLIST_FOREACH_REVERSE(ipl, &is->shead, qelem) {
5542d03e475Splunky 		if (ipl->type == IP_REF)
5552d03e475Splunky 			inline_ref((struct symtab *)ipl->ip_name);
5562d03e475Splunky 		if (ipl->type == IP_DEFLAB)
5572d03e475Splunky 			break;
5582d03e475Splunky 	}
559c4627bc7Sgmcgarry 
560c4627bc7Sgmcgarry 	/* So, walk over all statements and emit them */
561c4627bc7Sgmcgarry 	for (ip = ipf; ip != ipl; ip = DLIST_NEXT(ip, qelem)) {
562c4627bc7Sgmcgarry 		switch (ip->type) {
563c4627bc7Sgmcgarry 		case IP_NODE:
564*6935091cSplunky 			pp = tcopy(ip->ip_node);
565*6935091cSplunky 			if (pp->n_op == GOTO)
566*6935091cSplunky 				slval(pp->n_left, glval(pp->n_left) + lmin);
567*6935091cSplunky 			else if (pp->n_op == CBRANCH)
568*6935091cSplunky 				slval(pp->n_right, glval(pp->n_right) + lmin);
569*6935091cSplunky 			walkf(pp, rtmps, 0);
570c4627bc7Sgmcgarry #ifdef PCC_DEBUG
571*6935091cSplunky #ifndef TWOPASS
572c4627bc7Sgmcgarry 			if (sdebug) {
573*6935091cSplunky 				extern void e2print(NODE *p, int down, int *a, int *b);
574c4627bc7Sgmcgarry 				printf("converted node\n");
575*6935091cSplunky 				fwalk(ip->ip_node, e2print, 0);
576*6935091cSplunky 				fwalk(pp, e2print, 0);
577c4627bc7Sgmcgarry 			}
578c4627bc7Sgmcgarry #endif
579*6935091cSplunky #endif
580*6935091cSplunky 			send_passt(IP_NODE, pp);
581c4627bc7Sgmcgarry 			break;
582c4627bc7Sgmcgarry 
583c4627bc7Sgmcgarry 		case IP_DEFLAB:
584c4627bc7Sgmcgarry 			SDEBUG(("converted label %d to %d\n",
585c4627bc7Sgmcgarry 			    ip->ip_lbl, ip->ip_lbl + lmin));
586c4627bc7Sgmcgarry 			send_passt(IP_DEFLAB, ip->ip_lbl + lmin);
587c4627bc7Sgmcgarry 			break;
588c4627bc7Sgmcgarry 
589c4627bc7Sgmcgarry 		case IP_ASM:
590c4627bc7Sgmcgarry 			send_passt(IP_ASM, ip->ip_asm);
591c4627bc7Sgmcgarry 			break;
592c4627bc7Sgmcgarry 
593c4627bc7Sgmcgarry 		case IP_REF:
594c4627bc7Sgmcgarry 			inline_ref((struct symtab *)ip->ip_name);
595c4627bc7Sgmcgarry 			break;
596c4627bc7Sgmcgarry 
597c4627bc7Sgmcgarry 		default:
598c4627bc7Sgmcgarry 			cerror("bad inline stmt %d", ip->type);
599c4627bc7Sgmcgarry 		}
600c4627bc7Sgmcgarry 	}
601c4627bc7Sgmcgarry 	SDEBUG(("last label %d to %d\n", ip->ip_lbl, ip->ip_lbl + lmin));
602c4627bc7Sgmcgarry 	send_passt(IP_DEFLAB, ip->ip_lbl + lmin);
603c4627bc7Sgmcgarry 
604c4627bc7Sgmcgarry 	branch(l2);
605c4627bc7Sgmcgarry 	plabel(l0);
606c4627bc7Sgmcgarry 
607*6935091cSplunky 	/* Here we are P1ND again */
608*6935091cSplunky 	rp = block(GOTO, bcon(l1), NULL, INT, 0, 0);
609c4627bc7Sgmcgarry 	if (is->retval)
610c4627bc7Sgmcgarry 		p = tempnode(is->retval + toff, DECREF(sp->stype),
611a301e773Splunky 		    sp->sdf, sp->sap);
612c4627bc7Sgmcgarry 	else
613*6935091cSplunky 		p = xbcon(0, NULL, DECREF(sp->stype));
614c4627bc7Sgmcgarry 	rp = buildtree(COMOP, rp, p);
615c4627bc7Sgmcgarry 
616c4627bc7Sgmcgarry 	if (is->nargs) {
617a301e773Splunky 		p = mnode(&is->nt[is->nargs-1], ap);
618c4627bc7Sgmcgarry 		rp = buildtree(COMOP, p, rp);
619c4627bc7Sgmcgarry 	}
620c4627bc7Sgmcgarry 
621*6935091cSplunky 	p1tfree(f);
622c4627bc7Sgmcgarry 	return rp;
623c4627bc7Sgmcgarry }
624c4627bc7Sgmcgarry 
625c4627bc7Sgmcgarry void
inline_args(struct symtab ** sp,int nargs)626c4627bc7Sgmcgarry inline_args(struct symtab **sp, int nargs)
627c4627bc7Sgmcgarry {
628a301e773Splunky 	union arglist *al;
629c4627bc7Sgmcgarry 	struct istat *cf;
630a301e773Splunky 	TWORD t;
631c4627bc7Sgmcgarry 	int i;
632c4627bc7Sgmcgarry 
633c4627bc7Sgmcgarry 	SDEBUG(("inline_args\n"));
634c4627bc7Sgmcgarry 	cf = cifun;
635c4627bc7Sgmcgarry 	/*
636c4627bc7Sgmcgarry 	 * First handle arguments.  We currently do not inline anything if:
637c4627bc7Sgmcgarry 	 * - function has varargs
638c4627bc7Sgmcgarry 	 * - function args are volatile, checked if no temp node is asg'd.
639c4627bc7Sgmcgarry 	 */
640a301e773Splunky 	/* XXX - this is ugly, invent something better */
641a301e773Splunky 	if (cf->sp->sdf->dfun == NULL)
642a301e773Splunky 		return; /* no prototype */
643a301e773Splunky 	for (al = cf->sp->sdf->dfun; al->type != TNULL; al++) {
644a301e773Splunky 		t = al->type;
645a301e773Splunky 		if (t == TELLIPSIS)
646a301e773Splunky 			return; /* cannot inline */
647a301e773Splunky 		if (ISSOU(BTYPE(t)))
648a301e773Splunky 			al++;
649a301e773Splunky 		for (; t > BTMASK; t = DECREF(t))
650a301e773Splunky 			if (ISARY(t) || ISFTN(t))
651a301e773Splunky 				al++;
652a301e773Splunky 	}
653a301e773Splunky 
654c4627bc7Sgmcgarry 	if (nargs) {
655c4627bc7Sgmcgarry 		for (i = 0; i < nargs; i++)
656c4627bc7Sgmcgarry 			if ((sp[i]->sflags & STNODE) == 0)
657c4627bc7Sgmcgarry 				return; /* not temporary */
658a301e773Splunky 		cf->nt = permalloc(sizeof(struct ntds)*nargs);
659a301e773Splunky 		for (i = 0; i < nargs; i++) {
660a301e773Splunky 			cf->nt[i].temp = sp[i]->soffset;
661a301e773Splunky 			cf->nt[i].type = sp[i]->stype;
662a301e773Splunky 			cf->nt[i].df = sp[i]->sdf;
663a301e773Splunky 			cf->nt[i].attr = sp[i]->sap;
664a301e773Splunky 		}
665c4627bc7Sgmcgarry 	}
666c4627bc7Sgmcgarry 	cf->nargs = nargs;
667c4627bc7Sgmcgarry 	cf->flags |= CANINL;
6686e0bca22Sgmcgarry }
669