diff options
Diffstat (limited to 'usr.bin/pcc/ccom/inline.c')
-rw-r--r-- | usr.bin/pcc/ccom/inline.c | 209 |
1 files changed, 209 insertions, 0 deletions
diff --git a/usr.bin/pcc/ccom/inline.c b/usr.bin/pcc/ccom/inline.c new file mode 100644 index 00000000000..c9d0a829e58 --- /dev/null +++ b/usr.bin/pcc/ccom/inline.c @@ -0,0 +1,209 @@ +/* $OpenBSD: inline.c,v 1.1 2007/10/07 17:58:51 otto Exp $ */ +/* + * Copyright (c) 2003 Anders Magnusson (ragge@ludd.luth.se). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + +#include "pass1.h" + +#include <stdarg.h> + +/* + * ilink from ipole points to the next struct in the list of functions. + */ +static struct istat { + struct istat *ilink; + char *name; + int type; +#define NOTYETR 0 /* saved but not yet referenced */ +#define NOTYETW 1 /* saved and referenced but not yet written out */ +#define WRITTEN 2 /* is written out */ +#define NOTYETD 3 /* referenced but not yet saved */ + struct interpass shead; +} *ipole, *cifun; + +#define IP_REF (MAXIP+1) + +int isinlining, recovernodes; +int inlnodecnt, inlstatcnt; + +#define ialloc() permalloc(sizeof(struct istat)); inlstatcnt++ +#define nalloc() permalloc(sizeof(NODE)) + +static void +tcnt(NODE *p) +{ + inlnodecnt++; +} + +static struct istat * +findfun(char *name) +{ + struct istat *is = ipole; + while (is) { + if (is->name == name) + return is; + is = is->ilink; + } + return NULL; +} + +static void +refnode(char *str) +{ + struct interpass *ip; + + if (sdebug) + printf("refnode(%s)\n", str); + + ip = permalloc(sizeof(*ip)); + ip->type = IP_REF; + ip->ip_name = str; + inline_addarg(ip); +} + +void +inline_addarg(struct interpass *ip) +{ + DLIST_INSERT_BEFORE(&cifun->shead, ip, qelem); + if (ip->type == IP_NODE) + walkf(ip->ip_node, tcnt); /* Count as saved */ +} + +/* + * Called to setup for inlining of a new function. + */ +void +inline_start(char *name) +{ + struct istat *is; + + if (sdebug) + printf("inline_start(\"%s\")\n", name); + + if (isinlining) + cerror("already inlining function"); + + if ((is = findfun(name)) == 0) { + is = ialloc(); + is->ilink = ipole; + ipole = is; + is->name = name; + is->type = NOTYETR; + } else { + if (is->type != NOTYETD) + cerror("inline function already defined"); + is->type = NOTYETW; + } + DLIST_INIT(&is->shead, qelem); + cifun = is; + isinlining++; +} + +void +inline_end() +{ + if (sdebug) + printf("inline_end()\n"); + + isinlining = 0; +} + +/* + * Called when an inline function is found, to be sure that it will + * be written out. + * The function may not be defined when inline_ref() is called. + */ +void +inline_ref(char *name) +{ + struct istat *w = ipole; + + if (sdebug) + printf("inline_ref(\"%s\")\n", name); + if (isinlining) { + refnode(name); + } else { + while (w != NULL) { + if (w->name == name) { + if (w->type == NOTYETR) + w->type = NOTYETW; + return; /* setup for writeout */ + } + w = w->ilink; + } + /* function not yet defined, print out when found */ + w = ialloc(); + w->ilink = ipole; + ipole = w; + w->name = name; + w->type = NOTYETD; + } +} + +static void +puto(struct istat *w) +{ + struct interpass *ip, *nip; + + /* if -O, list will be saved again so foreach cannot be used */ + ip = DLIST_NEXT(&w->shead, qelem); + while (ip != (&w->shead)) { + nip = DLIST_NEXT(ip, qelem); + DLIST_REMOVE(ip, qelem); + if (ip->type == IP_REF) + inline_ref(ip->ip_name); + else + pass2_compile(ip); + ip = nip; + } + DLIST_INIT(&w->shead, qelem); +} + +/* + * printout functions that are referenced. + */ +void +inline_prtout() +{ + struct istat *w = ipole; + int gotone = 0; + + if (w == NULL) + return; + recovernodes++; + while (w != NULL) { + if (w->type == NOTYETW) { + puto(w); + w->type = WRITTEN; + gotone++; + } + w = w->ilink; + } + if (gotone) + inline_prtout(); + recovernodes--; +} |