Quick Search:

View

Revision:
Expand:  
Changeset: MAIN:ragge:20081116133016

Diff

Diff from 1.21 to:

Annotations

Annotate by Age | Author | Mixed | None
/fisheye/browse/pcc/pcc/cc/ccom/inline.c

Annotated File View

ragge
1.21
1 /*      $Id: inline.c,v 1.21 2008/11/16 13:30:17 ragge Exp $    */
ragge
1.12
2 /*
ragge
1.20
3  * Copyright (c) 2003, 2008 Anders Magnusson (ragge@ludd.luth.se).
ragge
1.12
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  * 3. The name of the author may not be used to endorse or promote products
15  *    derived from this software without specific prior written permission
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27  */
ragge
1.1
28
29
30 #include "pass1.h"
31
32 #include <stdarg.h>
33
34 /*
ragge
1.20
35  * Simple description of how the inlining works:
36  * A function found with the keyword "inline" is always saved.
37  * If it also has the keyword "extern" it is written out thereafter.
38  * If it has the keyword "static" it will be written out if it is referenced.
39  * inlining will only be done if -xinline is given, and only if it is 
40  * possible to inline the function.
41  */
42 static void printip(struct interpass *pole);
43
44 /*
ragge
1.1
45  * ilink from ipole points to the next struct in the list of functions.
46  */
47 static struct istat {
ragge
1.20
48         SLIST_ENTRY(istatlink;
ragge
1.18
49         struct symtab *sp;
ragge
1.20
50         int flags;
51 #define CANINL  1       /* function is possible to inline */
52 #define WRITTEN 2       /* function is written out */
53 #define REFD    4       /* Referenced but not yet written out */
54         int *args;      /* Array of arg temp numbers */
55         int nargs;      /* number of args in array */
56         int retval;     /* number of return temporary, if any */
ragge
1.15
57         struct interpass shead;
ragge
1.20
58 } *cifun;
59
60 static SLIST_HEAD(, istatipole = { NULL, &ipole.q_forw };
61 static int nlabs;
ragge
1.1
62
ragge
1.9
63 #define IP_REF  (MAXIP+1)
ragge
1.20
64 #ifdef PCC_DEBUG
65 #define SDEBUG(x)       if (sdebug) printf x
66 #else
67 #define SDEBUG(x)
68 #endif
ragge
1.1
69
ragge
1.20
70 int isinlining;
ragge
1.4
71 int inlnodecntinlstatcnt;
ragge
1.1
72
ragge
1.20
73 #define SZSI    sizeof(struct istat)
74 #define ialloc() memset(permalloc(SZSI), 0, SZSI); inlstatcnt++
ragge
1.1
75
ragge
1.11
76 static void
ragge
1.21
77 tcnt(NODE *pvoid *arg)
ragge
1.11
78 {
79         inlnodecnt++;
ragge
1.20
80         if (nlabs > 1 && (p->n_op == REG || p->n_op == OREG) &&
81             regno(p) == FPREG)
82                 SLIST_FIRST(&ipole)->flags &= ~CANINL/* no stack refs */
83         if (nflag)
84                 printf("locking node %p\n"p);
ragge
1.1
85 }
86
87 static struct istat *
ragge
1.18
88 findfun(struct symtab *sp)
ragge
1.1
89 {
ragge
1.20
90         struct istat *is;
91
92         SLIST_FOREACH(is, &ipolelink)
ragge
1.18
93                 if (is->sp == sp)
ragge
1.1
94                         return is;
95         return NULL;
96 }
97
ragge
1.2
98 static void
ragge
1.18
99 refnode(struct symtab *sp)
ragge
1.2
100 {
ragge
1.9
101         struct interpass *ip;
ragge
1.2
102
ragge
1.20
103         SDEBUG(("refnode(%s)\n"sp->sname));
ragge
1.2
104
ragge
1.9
105         ip = permalloc(sizeof(*ip));
106         ip->type = IP_REF;
ragge
1.18
107         ip->ip_name = (char *)sp;
ragge
1.9
108         inline_addarg(ip);
ragge
1.1
109 }
110
111 void
ragge
1.8
112 inline_addarg(struct interpass *ip)
113 {
ragge
1.20
114         extern NODE *cftnod;
115
116 //      SDEBUG(("inline_addarg(%p)\n", ip));
ragge
1.17
117         DLIST_INSERT_BEFORE(&cifun->sheadipqelem);
ragge
1.20
118         if (ip->type == IP_DEFLAB)
119                 nlabs++;
ragge
1.9
120         if (ip->type == IP_NODE)
ragge
1.21
121                 walkf(ip->ip_nodetcnt0); /* Count as saved */
ragge
1.20
122         if (cftnod)
123                 cifun->retval = regno(cftnod);
ragge
1.8
124 }
125
ragge
1.17
126 /*
127  * Called to setup for inlining of a new function.
128  */
ragge
1.8
129 void
ragge
1.18
130 inline_start(struct symtab *sp)
ragge
1.1
131 {
132         struct istat *is;
133
ragge
1.20
134         SDEBUG(("inline_start(\"%s\")\n"sp->sname));
ragge
1.1
135
136         if (isinlining)
137                 cerror("already inlining function");
138
ragge
1.20
139         if ((is = findfun(sp)) != 0) {
140                 if (!DLIST_ISEMPTY(&is->sheadqelem))
141                         uerror("inline function already defined");
142         } else {
ragge
1.16
143                 is = ialloc();
ragge
1.18
144                 is->sp = sp;
ragge
1.20
145                 SLIST_INSERT_FIRST(&ipoleislink);
146                 DLIST_INIT(&is->sheadqelem);
ragge
1.16
147         }
ragge
1.17
148         cifun = is;
ragge
1.20
149         nlabs = 0;
ragge
1.1
150         isinlining++;
151 }
152
153 void
154 inline_end()
155 {
ragge
1.20
156         SDEBUG(("inline_end()\n"));
ragge
1.1
157
ragge
1.20
158         if (sdebug)printip(&cifun->shead);
ragge
1.1
159         isinlining = 0;
ragge
1.20
160         if (cifun->sp->sclass == EXTDEF) {
161                 cifun->flags |= REFD;
162                 inline_prtout();
163         }
ragge
1.1
164 }
165
ragge
1.17
166 /*
167  * Called when an inline function is found, to be sure that it will
168  * be written out.
169  * The function may not be defined when inline_ref() is called.
170  */
ragge
1.1
171 void
ragge
1.18
172 inline_ref(struct symtab *sp)
ragge
1.1
173 {
ragge
1.20
174         struct istat *w;
ragge
1.1
175
ragge
1.20
176         SDEBUG(("inline_ref(\"%s\")\n"sp->sname));
177         if (sp->sclass == SNULL)
178                 return/* only inline, no references */
ragge
1.16
179         if (isinlining) {
ragge
1.18
180                 refnode(sp);
ragge
1.16
181         } else {
ragge
1.20
182                 SLIST_FOREACH(w,&ipolelink) {
183                         if (w->sp != sp)
184                                 continue;
185                         w->flags |= REFD;
186                         return;
ragge
1.1
187                 }
ragge
1.16
188                 /* function not yet defined, print out when found */
189                 w = ialloc();
ragge
1.18
190                 w->sp = sp;
ragge
1.20
191                 w->flags |= REFD;
192                 SLIST_INSERT_FIRST(&ipolewlink);
193                 DLIST_INIT(&w->sheadqelem);
ragge
1.16
194         }
ragge
1.1
195 }
196
197 static void
198 puto(struct istat *w)
199 {
ragge
1.15
200         struct interpass *ip, *nip;
ragge
1.9
201
ragge
1.20
202         /* Copy the saved function and print it out */
203         DLIST_FOREACH(ip, &w->sheadqelem) {
204                 if (ip->type == IP_PROLOG || ip->type == IP_EPILOG) {
205                         nip = tmpalloc(sizeof(struct interpass_prolog));
206                         memcpy(nipipsizeof(struct interpass_prolog));
207                         pass2_compile(nip);
208                 } else if (ip->type == IP_REF) {
ragge
1.18
209                         inline_ref((struct symtab *)ip->ip_name);
ragge
1.20
210                 } else {
211                         nip = tmpalloc(sizeof(struct interpass));
212                         *nip = *ip;
213                         if (nip->type == IP_NODE)
214                                 nip->ip_node = tcopy(nip->ip_node);
215                         pass2_compile(nip);
216                 }
ragge
1.1
217         }
ragge
1.20
218         w->flags |= WRITTEN;
ragge
1.1
219 }
220
ragge
1.17
221 /*
222  * printout functions that are referenced.
223  */
ragge
1.1
224 void
225 inline_prtout()
226 {
ragge
1.20
227         struct istat *w;
ragge
1.2
228         int gotone = 0;
ragge
1.1
229
ragge
1.20
230         SLIST_FOREACH(w, &ipolelink) {
231                 if ((w->flags & (REFD|WRITTEN)) == REFD &&
232                     !DLIST_ISEMPTY(&w->sheadqelem)) {
ragge
1.18
233                         defloc(w->sp);
ragge
1.9
234                         puto(w);
ragge
1.20
235                         w->flags |= WRITTEN;
ragge
1.2
236                         gotone++;
ragge
1.1
237                 }
238         }
ragge
1.2
239         if (gotone)
ragge
1.10
240                 inline_prtout();
ragge
1.1
241 }
ragge
1.19
242
ragge
1.20
243 #if 1
ragge
1.19
244 static void
245 printip(struct interpass *pole)
246 {
247         static char *foo[] = {
248            0"NODE""PROLOG""STKOFF""EPILOG""DEFLAB""DEFNAM""ASM" };
249         struct interpass *ip;
250         struct interpass_prolog *ipplg, *epplg;
251
252         DLIST_FOREACH(ippoleqelem) {
253                 if (ip->type > MAXIP)
254                         printf("IP(%d) (%p): "ip->typeip);
255                 else
256                         printf("%s (%p): "foo[ip->type], ip);
257                 switch (ip->type) {
258                 case IP_NODEprintf("\n");
259 #ifdef PCC_DEBUG
260                         fwalk(ip->ip_nodeeprint0); break;
261 #endif
262                 case IP_PROLOG:
263                         ipplg = (struct interpass_prolog *)ip;
264                         printf("%s %s regs %x autos %d mintemp %d minlbl %d\n",
265                             ipplg->ipp_nameipplg->ipp_vis ? "(local)" : "",
ragge
1.20
266                             ipplg->ipp_regs[0], ipplg->ipp_autosipplg->ip_tmpnum,
ragge
1.19
267                             ipplg->ip_lblnum);
268                         break;
269                 case IP_EPILOG:
270                         epplg = (struct interpass_prolog *)ip;
271                         printf("%s %s regs %x autos %d mintemp %d minlbl %d\n",
272                             epplg->ipp_nameepplg->ipp_vis ? "(local)" : "",
ragge
1.20
273                             epplg->ipp_regs[0], epplg->ipp_autosepplg->ip_tmpnum,
ragge
1.19
274                             epplg->ip_lblnum);
275                         break;
276                 case IP_DEFLABprintf(LABFMT "\n"ip->ip_lbl); break;
277                 case IP_DEFNAMprintf("\n"); break;
278                 case IP_ASMprintf("%s\n"ip->ip_asm); break;
279                 default:
280                         break;
281                 }
282         }
283 }
284 #endif
285
ragge
1.20
286 static int toff;
287
288 static NODE *
289 mnode(int *nNODE *p)
290 {
291         NODE *q;
292         int num = *n + toff;
293
294         if (p->n_op == CM) {
295                 q = p->n_right;
296                 q = tempnode(numq->n_typeq->n_dfq->n_sue);
297                 n--;
298                 p->n_right = buildtree(ASSIGNqp->n_right);
299                 p->n_left = mnode(np->n_left);
300                 p->n_op = COMOP;
301         } else {
302                 p = pconvert(p);
303                 q = tempnode(nump->n_typep->n_dfp->n_sue);
304                 p = buildtree(ASSIGNqp);
305         }
306         return p;
307 }
308
309 static void
ragge
1.21
310 rtmps(NODE *pvoid *arg)
ragge
1.20
311 {
312         if (p->n_op == TEMP)
313                 regno(p) += toff;
314 }
315
ragge
1.19
316 /*
317  * Inline a function. Returns the return value.
ragge
1.20
318  * There are two major things that must be converted when 
319  * inlining a function:
320  * - Label numbers must be updated with an offset.
321  * - The stack block must be relocated (add to REG or OREG).
322  * - Temporaries should be updated (but no must)
ragge
1.19
323  */
324 NODE *
ragge
1.20
325 inlinetree(struct symtab *spNODE *fNODE *ap)
ragge
1.19
326 {
ragge
1.20
327         extern int crslabtvaloff;
ragge
1.19
328         struct istat *is = findfun(sp);
ragge
1.20
329         struct interpass *ip, *ipf, *ipl;
330         int lminstkszL0L1L2;
331         OFFSZ stkoff;
332         NODE *p, *rp;
333
334         if (is == NULL) {
335                 inline_ref(sp); /* prototype of not yet declared inline ftn */
336                 return NIL;
337         }
338
339         SDEBUG(("inlinetree(%p,%p) OK %d\n"fapis->flags & CANINL));
ragge
1.19
340
ragge
1.20
341         if ((is->flags & CANINL) == 0 || xinline == 0) {
342                 if (is->sp->sclass == STATIC || is->sp->sclass == USTATIC)
343                         is->flags |= REFD/* if static inline, emit */
344                 return NIL;
345         }
346
347         stksz = stkoff = 0;
348         /* emit jumps to surround inline function */
349         branch(L0 = getlab());
350         plabel(L1 = getlab());
351         L2 = getlab();
352         SDEBUG(("branch labels %d,%d,%d\n"L0L1L2));
353
354         ipf = DLIST_NEXT(&is->sheadqelem); /* prolog */
355         ipl = DLIST_PREV(&is->sheadqelem); /* epilog */
356
357         /* Fix label & temp offsets */
358 #define IPP(x) ((struct interpass_prolog *)x)
359         SDEBUG(("pre-offsets crslab %d tvaloff %d\n"crslabtvaloff));
360         lmin = crslab - IPP(ipf)->ip_lblnum;
361         crslab += (IPP(ipl)->ip_lblnum - IPP(ipf)->ip_lblnum) + 1;
362         toff = tvaloff - IPP(ipf)->ip_tmpnum;
363         tvaloff += (IPP(ipl)->ip_tmpnum - IPP(ipf)->ip_tmpnum) + 1;
364         SDEBUG(("offsets crslab %d lmin %d tvaloff %d toff %d\n",
365             crslablmintvalofftoff));
366
367         /* traverse until first real label */
368         ipf = DLIST_NEXT(ipfqelem);
369         do
370                 ipf = DLIST_NEXT(ipfqelem);
371         while (ipf->type != IP_DEFLAB);
372
373         /* traverse backwards to last label */
374         do
375                 ipl = DLIST_PREV(iplqelem);
376         while (ipl->type != IP_DEFLAB);
377
378         /* So, walk over all statements and emit them */
379         for (ip = ipfip != iplip = DLIST_NEXT(ipqelem)) {
380                 switch (ip->type) {
381                 case IP_NODE:
382                         p = tcopy(ip->ip_node);
383                         if (p->n_op == GOTO)
384                                 p->n_left->n_lval += lmin;
385                         else if (p->n_op == CBRANCH)
386                                 p->n_right->n_lval += lmin;
ragge
1.21
387                         walkf(prtmps0);
ragge
1.20
388 #ifdef PCC_DEBUG
389                         if (sdebug) {
390                                 printf("converted node\n");
391                                 fwalk(ip->ip_nodeeprint0);
392                                 fwalk(peprint0);
393                         }
394 #endif
395                         send_passt(IP_NODEp);
396                         break;
397
398                 case IP_DEFLAB:
399                         SDEBUG(("converted label %d to %d\n",
400                             ip->ip_lblip->ip_lbl + lmin));
401                         send_passt(IP_DEFLABip->ip_lbl + lmin);
402                         break;
403
404                 case IP_ASM:
405                         send_passt(IP_ASMip->ip_asm);
406                         break;
407
408                 case IP_REF:
409                         inline_ref((struct symtab *)ip->ip_name);
410                         break;
411
412                 default:
413                         cerror("bad inline stmt %d"ip->type);
414                 }
415         }
416         SDEBUG(("last label %d to %d\n"ip->ip_lblip->ip_lbl + lmin));
417         send_passt(IP_DEFLABip->ip_lbl + lmin);
418
419         branch(L2);
420         plabel(L0);
421
422         rp = block(GOTObcon(L1), NILINT0MKSUE(INT));
423         if (is->retval)
424                 p = tempnode(is->retval + toffDECREF(sp->stype),
425                     sp->sdfsp->ssue);
426         else
427                 p = bcon(0);
428         rp = buildtree(COMOPrpp);
429
430         if (is->nargs) {
431                 p = mnode(&is->args[is->nargs-1], ap);
432                 rp = buildtree(COMOPprp);
433         }
434
435         tfree(f);
436         return rp;
437 }
438
439 void
440 inline_args(struct symtab **spint nargs)
441 {
442         struct istat *cf;
443         int i;
444
445         SDEBUG(("inline_args\n"));
446         cf = cifun;
ragge
1.19
447         /*
448          * First handle arguments.  We currently do not inline anything if:
449          * - function has varargs
ragge
1.20
450          * - function args are volatile, checked if no temp node is asg'd.
ragge
1.19
451          */
ragge
1.20
452         if (nargs) {
453                 for (i = 0i < nargsi++)
454                         if ((sp[i]->sflags & STNODE) == 0)
455                                 return/* not temporary */
456                 cf->args = permalloc(sizeof(int)*nargs);
457                 for (i = 0i < nargsi++)
458                         cf->args[i] = sp[i]->soffset;
459         }
460         cf->nargs = nargs;
461         cf->flags |= CANINL;
ragge
1.19
462 }
FishEye: Open Source License registered to PCC.
Your maintenance has expired. You can renew your license at http://www.atlassian.com/fisheye/renew
Atlassian FishEye, CVS analysis. (Version:1.6.3 Build:build-336 2008-11-04) - Administration - Page generated 2014-08-28 17:07 +0200