summaryrefslogtreecommitdiff
path: root/usr.bin/pcc/ccom/inline.c
diff options
context:
space:
mode:
Diffstat (limited to 'usr.bin/pcc/ccom/inline.c')
-rw-r--r--usr.bin/pcc/ccom/inline.c209
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--;
+}