Quick Search:

View

Revision:
Expand:  
Changeset: MAIN:plunky:20120422210740

Diff

Diff from 1.3 to:

Annotations

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

Annotated File View

plunky
1.3
1 /*      $Id: inline.c,v 1.3 2012/04/22 21:07:41 plunky Exp $    */
ragge
1.1
2 /*
3  * Copyright (c) 2003, 2008 Anders Magnusson (ragge@ludd.luth.se).
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  *
15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
19  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25  */
26
27
28 #include "pass1.h"
29
30 #include <stdarg.h>
31
32 /*
33  * Simple description of how the inlining works:
34  * A function found with the keyword "inline" is always saved.
35  * If it also has the keyword "extern" it is written out thereafter.
36  * If it has the keyword "static" it will be written out if it is referenced.
37  * inlining will only be done if -xinline is given, and only if it is 
38  * possible to inline the function.
39  */
40 static void printip(struct interpass *pole);
41
42 struct ntds {
43         int temp;
44         TWORD type;
45         union dimfun *df;
46         struct attr *attr;
47 };
48
49 /*
50  * ilink from ipole points to the next struct in the list of functions.
51  */
52 static struct istat {
53         SLIST_ENTRY(istatlink;
54         struct symtab *sp;
55         int flags;
56 #define CANINL  1       /* function is possible to inline */
57 #define WRITTEN 2       /* function is written out */
58 #define REFD    4       /* Referenced but not yet written out */
59         struct ntds *nt;/* Array of arg temp type data */
60         int nargs;      /* number of args in array */
61         int retval;     /* number of return temporary, if any */
62         struct interpass shead;
63 } *cifun;
64
65 static SLIST_HEAD(, istatipole = { NULL, &ipole.q_forw };
66 static int nlabs;
67
68 #define IP_REF  (MAXIP+1)
69 #ifdef PCC_DEBUG
70 #define SDEBUG(x)       if (sdebug) printf x
71 #else
72 #define SDEBUG(x)
73 #endif
74
75 int isinlining;
76 int inlnodecntinlstatcnt;
77
78 #define SZSI    sizeof(struct istat)
79 #define ialloc() memset(permalloc(SZSI), 0, SZSI); inlstatcnt++
80
81 static void
82 tcnt(NODE *pvoid *arg)
83 {
84         inlnodecnt++;
85         if (nlabs > 1 && (p->n_op == REG || p->n_op == OREG) &&
86             regno(p) == FPREG)
87                 SLIST_FIRST(&ipole)->flags &= ~CANINL/* no stack refs */
88         if (p->n_op == NAME || p->n_op == ICON)
89                 p->n_sp = NULL/* let symtabs be freed for inline funcs */
plunky
1.2
90         if (ndebug)
ragge
1.1
91                 printf("locking node %p\n"p);
92 }
93
94 static struct istat *
95 findfun(struct symtab *sp)
96 {
97         struct istat *is;
98
99         SLIST_FOREACH(is, &ipolelink)
100                 if (is->sp == sp)
101                         return is;
102         return NULL;
103 }
104
105 static void
106 refnode(struct symtab *sp)
107 {
108         struct interpass *ip;
109
110         SDEBUG(("refnode(%s)\n"sp->sname));
111
112         ip = permalloc(sizeof(*ip));
113         ip->type = IP_REF;
114         ip->ip_name = (char *)sp;
115         inline_addarg(ip);
116 }
117
118 void
119 inline_addarg(struct interpass *ip)
120 {
121         extern NODE *cftnod;
122
123         SDEBUG(("inline_addarg(%p)\n"ip));
124         DLIST_INSERT_BEFORE(&cifun->sheadipqelem);
125         if (ip->type == IP_DEFLAB)
126                 nlabs++;
127         if (ip->type == IP_NODE)
128                 walkf(ip->ip_nodetcnt0); /* Count as saved */
129         if (cftnod)
130                 cifun->retval = regno(cftnod);
131 }
132
133 /*
134  * Called to setup for inlining of a new function.
135  */
136 void
137 inline_start(struct symtab *sp)
138 {
139         struct istat *is;
140
141         SDEBUG(("inline_start(\"%s\")\n"sp->sname));
142
143         if (isinlining)
144                 cerror("already inlining function");
145
146         if ((is = findfun(sp)) != 0) {
147                 if (!DLIST_ISEMPTY(&is->sheadqelem))
148                         uerror("inline function already defined");
149         } else {
150                 is = ialloc();
151                 is->sp = sp;
152                 SLIST_INSERT_FIRST(&ipoleislink);
153                 DLIST_INIT(&is->sheadqelem);
154         }
155         cifun = is;
156         nlabs = 0;
157         isinlining++;
158 }
159
160 /*
161  * End of an inline function. In C99 an inline function declared "extern"
162  * should also have external linkage and are therefore printed out.
163  *
164  * Gcc inline syntax is a mess, see matrix below on emitting functions:
165  *                  without extern
166  *      -std=           -       gnu89   gnu99   
167  *      gcc 3.3.5:      ja      ja      ja
168  *      gcc 4.1.3:      ja      ja      ja
169  *      gcc 4.3.1       ja      ja      nej     
170  * 
171  *                   with extern
172  *      gcc 3.3.5:      nej     nej     nej
173  *      gcc 4.1.3:      nej     nej     nej
174  *      gcc 4.3.1       nej     nej     ja      
175  *
176  * The attribute gnu_inline sets gnu89 behaviour.
177  * Since pcc mimics gcc 4.3.1 that is the behaviour we emulate.
178  */
179 void
plunky
1.3
180 inline_end(void)
ragge
1.1
181 {
182         struct symtab *sp = cifun->sp;
183
184         SDEBUG(("inline_end()\n"));
185
186         if (sdebug)printip(&cifun->shead);
187         isinlining = 0;
188
189         if (sp->sclass != STATIC &&
190             (attr_find(sp->sapGCC_ATYP_GNU_INLINE) || xgnu89)) {
191                 if (sp->sclass == EXTDEF)
192                         sp->sclass = 0;
193                 else
194                         sp->sclass = EXTDEF;
195         }
196
197         if (sp->sclass == EXTDEF) {
198                 cifun->flags |= REFD;
199                 inline_prtout();
200         }
201 }
202
203 /*
204  * Called when an inline function is found, to be sure that it will
205  * be written out.
206  * The function may not be defined when inline_ref() is called.
207  */
208 void
209 inline_ref(struct symtab *sp)
210 {
211         struct istat *w;
212
213         SDEBUG(("inline_ref(\"%s\")\n"sp->sname));
214         if (sp->sclass == SNULL)
215                 return/* only inline, no references */
216         if (isinlining) {
217                 refnode(sp);
218         } else {
219                 SLIST_FOREACH(w,&ipolelink) {
220                         if (w->sp != sp)
221                                 continue;
222                         w->flags |= REFD;
223                         return;
224                 }
225                 /* function not yet defined, print out when found */
226                 w = ialloc();
227                 w->sp = sp;
228                 w->flags |= REFD;
229                 SLIST_INSERT_FIRST(&ipolewlink);
230                 DLIST_INIT(&w->sheadqelem);
231         }
232 }
233
234 static void
235 puto(struct istat *w)
236 {
237         struct interpass_prolog *ipp, *epp, *pp;
238         struct interpass *ip, *nip;
239         extern int crslab;
240         int lbloff = 0;
241
242         /* Copy the saved function and print it out */
243         ipp = 0/* XXX data flow analysis */
244         DLIST_FOREACH(ip, &w->sheadqelem) {
245                 switch (ip->type) {
246                 case IP_EPILOG:
247                 case IP_PROLOG:
248                         if (ip->type == IP_PROLOG) {
249                                 ipp = (struct interpass_prolog *)ip;
250                                 /* fix label offsets */
251                                 lbloff = crslab - ipp->ip_lblnum;
252                         } else {
253                                 epp = (struct interpass_prolog *)ip;
254                                 crslab += (epp->ip_lblnum - ipp->ip_lblnum);
255                         }
256                         pp = tmpalloc(sizeof(struct interpass_prolog));
257                         memcpy(ppipsizeof(struct interpass_prolog));
258                         pp->ip_lblnum += lbloff;
259 #ifdef PCC_DEBUG
260                         if (ip->type == IP_EPILOG && crslab != pp->ip_lblnum)
261                                 cerror("puto: %d != %d"crslabpp->ip_lblnum);
262 #endif
263                         pass2_compile((struct interpass *)pp);
264                         break;
265
266                 case IP_REF:
267                         inline_ref((struct symtab *)ip->ip_name);
268                         break;
269
270                 default:
271                         nip = tmpalloc(sizeof(struct interpass));
272                         *nip = *ip;
273                         if (nip->type == IP_NODE) {
274                                 NODE *p;
275
276                                 p = nip->ip_node = ccopy(nip->ip_node);
277                                 if (p->n_op == GOTO)
278                                         p->n_left->n_lval += lbloff;
279                                 else if (p->n_op == CBRANCH)
280                                         p->n_right->n_lval += lbloff;
281                         } else if (nip->type == IP_DEFLAB)
282                                 nip->ip_lbl += lbloff;
283                         pass2_compile(nip);
284                         break;
285                 }
286         }
287         w->flags |= WRITTEN;
288 }
289
290 /*
291  * printout functions that are referenced.
292  */
293 void
plunky
1.3
294 inline_prtout(void)
ragge
1.1
295 {
296         struct istat *w;
297         int gotone = 0;
298
299         SLIST_FOREACH(w, &ipolelink) {
300                 if ((w->flags & (REFD|WRITTEN)) == REFD &&
301                     !DLIST_ISEMPTY(&w->sheadqelem)) {
302                         locctr(PROGw->sp);
303                         defloc(w->sp);
304                         puto(w);
305                         w->flags |= WRITTEN;
306                         gotone++;
307                 }
308         }
309         if (gotone)
310                 inline_prtout();
311 }
312
313 #if 1
314 static void
315 printip(struct interpass *pole)
316 {
317         static char *foo[] = {
318            0"NODE""PROLOG""STKOFF""EPILOG""DEFLAB""DEFNAM""ASM" };
319         struct interpass *ip;
320         struct interpass_prolog *ipplg, *epplg;
321
322         DLIST_FOREACH(ippoleqelem) {
323                 if (ip->type > MAXIP)
324                         printf("IP(%d) (%p): "ip->typeip);
325                 else
326                         printf("%s (%p): "foo[ip->type], ip);
327                 switch (ip->type) {
328                 case IP_NODEprintf("\n");
329 #ifdef PCC_DEBUG
330                         fwalk(ip->ip_nodeeprint0); break;
331 #endif
332                 case IP_PROLOG:
333                         ipplg = (struct interpass_prolog *)ip;
334                         printf("%s %s regs %lx autos %d mintemp %d minlbl %d\n",
335                             ipplg->ipp_nameipplg->ipp_vis ? "(local)" : "",
336                             (long)ipplg->ipp_regs[0], ipplg->ipp_autos,
337                             ipplg->ip_tmpnumipplg->ip_lblnum);
338                         break;
339                 case IP_EPILOG:
340                         epplg = (struct interpass_prolog *)ip;
341                         printf("%s %s regs %lx autos %d mintemp %d minlbl %d\n",
342                             epplg->ipp_nameepplg->ipp_vis ? "(local)" : "",
343                             (long)epplg->ipp_regs[0], epplg->ipp_autos,
344                             epplg->ip_tmpnumepplg->ip_lblnum);
345                         break;
346                 case IP_DEFLABprintf(LABFMT "\n"ip->ip_lbl); break;
347                 case IP_DEFNAMprintf("\n"); break;
348                 case IP_ASMprintf("%s\n"ip->ip_asm); break;
349                 default:
350                         break;
351                 }
352         }
353 }
354 #endif
355
356 static int toff;
357
358 static NODE *
359 mnode(struct ntds *ntNODE *p)
360 {
361         NODE *q;
362         int num = nt->temp + toff;
363
364         if (p->n_op == CM) {
365                 q = p->n_right;
366                 q = tempnode(numnt->typent->dfnt->attr);
367                 nt--;
368                 p->n_right = buildtree(ASSIGNqp->n_right);
369                 p->n_left = mnode(ntp->n_left);
370                 p->n_op = COMOP;
371         } else {
372                 p = pconvert(p);
373                 q = tempnode(numnt->typent->dfnt->attr);
374                 p = buildtree(ASSIGNqp);
375         }
376         return p;
377 }
378
379 static void
380 rtmps(NODE *pvoid *arg)
381 {
382         if (p->n_op == TEMP)
383                 regno(p) += toff;
384 }
385
386 /*
387  * Inline a function. Returns the return value.
388  * There are two major things that must be converted when 
389  * inlining a function:
390  * - Label numbers must be updated with an offset.
391  * - The stack block must be relocated (add to REG or OREG).
392  * - Temporaries should be updated (but no must)
393  */
394 NODE *
395 inlinetree(struct symtab *spNODE *fNODE *ap)
396 {
397         extern int crslabtvaloff;
398         struct istat *is = findfun(sp);
399         struct interpass *ip, *ipf, *ipl;
400         int lminl0l1l2gainl;
401         NODE *p, *rp;
402
403         if (is == NULL || nerrors) {
404                 inline_ref(sp); /* prototype of not yet declared inline ftn */
405                 return NIL;
406         }
407
408         SDEBUG(("inlinetree(%p,%p) OK %d\n"fapis->flags & CANINL));
409
410         gainl = attr_find(sp->sapGCC_ATYP_ALW_INL) != NULL;
411
412         if ((is->flags & CANINL) == 0 && gainl)
413                 werror("cannot inline but always_inline");
414
415         if ((is->flags & CANINL) == 0 || (xinline == 0 && gainl == 0)) {
416                 if (is->sp->sclass == STATIC || is->sp->sclass == USTATIC)
417                         inline_ref(sp);
418                 return NIL;
419         }
420
421         if (isinlining && cifun->sp == sp) {
422                 /* Do not try to inline ourselves */
423                 inline_ref(sp);
424                 return NIL;
425         }
426
427 #ifdef mach_i386
428         if (kflag) {
429                 is->flags |= REFD/* if static inline, emit */
430                 return NIL/* XXX cannot handle hidden ebx arg */
431         }
432 #endif
433
434         /* emit jumps to surround inline function */
435         branch(l0 = getlab());
436         plabel(l1 = getlab());
437         l2 = getlab();
438         SDEBUG(("branch labels %d,%d,%d\n"l0l1l2));
439
440         ipf = DLIST_NEXT(&is->sheadqelem); /* prolog */
441         ipl = DLIST_PREV(&is->sheadqelem); /* epilog */
442
443         /* Fix label & temp offsets */
444 #define IPP(x) ((struct interpass_prolog *)x)
445         SDEBUG(("pre-offsets crslab %d tvaloff %d\n"crslabtvaloff));
446         lmin = crslab - IPP(ipf)->ip_lblnum;
447         crslab += (IPP(ipl)->ip_lblnum - IPP(ipf)->ip_lblnum) + 1;
448         toff = tvaloff - IPP(ipf)->ip_tmpnum;
449         tvaloff += (IPP(ipl)->ip_tmpnum - IPP(ipf)->ip_tmpnum) + 1;
450         SDEBUG(("offsets crslab %d lmin %d tvaloff %d toff %d\n",
451             crslablmintvalofftoff));
452
453         /* traverse until first real label */
454         ipf = DLIST_NEXT(ipfqelem);
455         do
456                 ipf = DLIST_NEXT(ipfqelem);
457         while (ipf->type != IP_DEFLAB);
458
459         /* traverse backwards to last label */
460         do
461                 ipl = DLIST_PREV(iplqelem);
462         while (ipl->type != IP_DEFLAB);
463
464         /* So, walk over all statements and emit them */
465         for (ip = ipfip != iplip = DLIST_NEXT(ipqelem)) {
466                 switch (ip->type) {
467                 case IP_NODE:
468                         p = ccopy(ip->ip_node);
469                         if (p->n_op == GOTO)
470                                 p->n_left->n_lval += lmin;
471                         else if (p->n_op == CBRANCH)
472                                 p->n_right->n_lval += lmin;
473                         walkf(prtmps0);
474 #ifdef PCC_DEBUG
475                         if (sdebug) {
476                                 printf("converted node\n");
477                                 fwalk(ip->ip_nodeeprint0);
478                                 fwalk(peprint0);
479                         }
480 #endif
481                         send_passt(IP_NODEp);
482                         break;
483
484                 case IP_DEFLAB:
485                         SDEBUG(("converted label %d to %d\n",
486                             ip->ip_lblip->ip_lbl + lmin));
487                         send_passt(IP_DEFLABip->ip_lbl + lmin);
488                         break;
489
490                 case IP_ASM:
491                         send_passt(IP_ASMip->ip_asm);
492                         break;
493
494                 case IP_REF:
495                         inline_ref((struct symtab *)ip->ip_name);
496                         break;
497
498                 default:
499                         cerror("bad inline stmt %d"ip->type);
500                 }
501         }
502         SDEBUG(("last label %d to %d\n"ip->ip_lblip->ip_lbl + lmin));
503         send_passt(IP_DEFLABip->ip_lbl + lmin);
504
505         branch(l2);
506         plabel(l0);
507
508         rp = block(GOTObcon(l1), NILINT00);
509         if (is->retval)
510                 p = tempnode(is->retval + toffDECREF(sp->stype),
511                     sp->sdfsp->sap);
512         else
513                 p = bcon(0);
514         rp = buildtree(COMOPrpp);
515
516         if (is->nargs) {
517                 p = mnode(&is->nt[is->nargs-1], ap);
518                 rp = buildtree(COMOPprp);
519         }
520
521         tfree(f);
522         return rp;
523 }
524
525 void
526 inline_args(struct symtab **spint nargs)
527 {
528         union arglist *al;
529         struct istat *cf;
530         TWORD t;
531         int i;
532
533         SDEBUG(("inline_args\n"));
534         cf = cifun;
535         /*
536          * First handle arguments.  We currently do not inline anything if:
537          * - function has varargs
538          * - function args are volatile, checked if no temp node is asg'd.
539          */
540         /* XXX - this is ugly, invent something better */
541         if (cf->sp->sdf->dfun == NULL)
542                 return/* no prototype */
543         for (al = cf->sp->sdf->dfunal->type != TNULLal++) {
544                 t = al->type;
545                 if (t == TELLIPSIS)
546                         return/* cannot inline */
547                 if (ISSOU(BTYPE(t)))
548                         al++;
549                 for (; t > BTMASKt = DECREF(t))
550                         if (ISARY(t) || ISFTN(t))
551                                 al++;
552         }
553
554         if (nargs) {
555                 for (i = 0i < nargsi++)
556                         if ((sp[i]->sflags & STNODE) == 0)
557                                 return/* not temporary */
558                 cf->nt = permalloc(sizeof(struct ntds)*nargs);
559                 for (i = 0i < nargsi++) {
560                         cf->nt[i].temp = sp[i]->soffset;
561                         cf->nt[i].type = sp[i]->stype;
562                         cf->nt[i].df = sp[i]->sdf;
563                         cf->nt[i].attr = sp[i]->sap;
564                 }
565         }
566         cf->nargs = nargs;
567         cf->flags |= CANINL;
568 }
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-10-31 05:06 +0100