Quick Search:

View

Revision:
Expand:  
Changeset: MAIN:ragge:20090620072300

Diff

Diff from 1.13 to:

Annotations

Annotate by Age | Author | Mixed | None
/fisheye/browse/pcc/pcc/arch/amd64/code.c

Annotated File View

ragge
1.13
1 /*      $Id: code.c,v 1.13 2009/06/20 07:23:00 ragge Exp $      */
mickey
1.1
2 /*
3  * Copyright (c) 2008 Michael Shalayeff
4  * Copyright (c) 2003 Anders Magnusson (ragge@ludd.luth.se).
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  * 3. The name of the author may not be used to endorse or promote products
16  *    derived from this software without specific prior written permission
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28  */
29
30
31 # include "pass1.h"
32
ragge
1.11
33 static int nssengprnrsprsaoff;
ragge
1.8
34 enum { INTEGER = 1INTMEMSSESSEMEMX87STRREGSTRMEM };
ragge
1.10
35 static const int argregsi[] = { RDIRSIRDXRCXR08R09 };
ragge
1.11
36 /*
37  * The Register Save Area looks something like this.
38  * It is put first on stack with fixed offsets.
39  * struct {
40  *      long regs[6];
41  *      double xmm[8][2]; // 16 byte in width
42  * };
43  */
44 #define RSASZ           (6*SZLONG+8*2*SZDOUBLE)
45 #define RSALONGOFF(x)   (RSASZ-(x)*SZLONG)
46 #define RSADBLOFF(x)    ((8*2*SZDOUBLE)-(x)*SZDOUBLE*2)
47 /* va_list */
48 #define VAARGSZ         (SZINT*2+SZPOINT(CHAR)*2)
49 #define VAGPOFF(x)      (x)
50 #define VAFPOFF(x)      (x-SZINT)
51 #define VAOFA(x)        (x-SZINT-SZINT)
52 #define VARSA(x)        (x-SZINT-SZINT-SZPOINT(0))
mickey
1.1
53
54 int lastloc = -1;
55
ragge
1.8
56 static int argtyp(TWORD tunion dimfun *dfstruct suedef *sue);
ragge
1.11
57 static NODE *movtomem(NODE *pint off);
ragge
1.8
58
mickey
1.1
59 /*
60  * Define everything needed to print out some data (or text).
61  * This means segment, alignment, visibility, etc.
62  */
63 void
64 defloc(struct symtab *sp)
65 {
66         extern char *nextsect;
67         static char *loctbl[] = { "text""data""section .rodata" };
ragge
1.6
68         int weak = 0;
69         char *name = NULL;
mickey
1.1
70         TWORD t;
71         int s;
72
73         if (sp == NULL) {
74                 lastloc = -1;
75                 return;
76         }
77         t = sp->stype;
78         s = ISFTN(t) ? PROG : ISCON(cqual(tsp->squal)) ? RDATA : DATA;
79 #ifdef TLS
80         if (sp->sflags & STLS) {
81                 if (s != DATA)
82                         cerror("non-data symbol in tls section");
83                 nextsect = ".tdata";
84         }
85 #endif
ragge
1.6
86 #ifdef GCC_COMPAT
87         {
88                 struct gcc_attrib *ga;
89
90                 if ((ga = gcc_get_attr(sp->ssueGCC_ATYP_SECTION)) != NULL)
91                         nextsect = ga->a1.sarg;
92                 if ((ga = gcc_get_attr(sp->ssueGCC_ATYP_WEAK)) != NULL)
93                         weak = 1;
94         }
95 #endif
96
mickey
1.1
97         if (nextsect) {
98                 printf("        .section %s\n"nextsect);
99                 nextsect = NULL;
100                 s = -1;
101         } else if (s != lastloc)
102                 printf("        .%s\n"loctbl[s]);
103         lastloc = s;
104         while (ISARY(t))
105                 t = DECREF(t);
ragge
1.3
106         s = ISFTN(t) ? ALINT : talign(tsp->ssue);
107         if (s > ALCHAR)
108                 printf("        .align %d\n"s/ALCHAR);
ragge
1.6
109         if (weak || sp->sclass == EXTDEF || sp->slevel == 0 || ISFTN(t))
110                 if ((name = sp->soname) == NULL)
111                         name = exname(sp->sname);
112         if (weak)
113                 printf("        .weak %s\n"name);
114         else if (sp->sclass == EXTDEF)
115                 printf("        .globl %s\n"name);
mickey
1.1
116         if (ISFTN(t))
ragge
1.6
117                 printf("\t.type %s,@function\n"name);
mickey
1.1
118         if (sp->slevel == 0)
ragge
1.6
119                 printf("%s:\n"name);
mickey
1.1
120         else
121                 printf(LABFMT ":\n"sp->soffset);
122 }
123
124 /*
125  * code for the end of a function
126  * deals with struct return here
127  */
128 void
129 efcode()
130 {
131         extern int gotnr;
132         NODE *p, *q;
133
134         gotnr = 0;      /* new number for next fun */
135         if (cftnsp->stype != STRTY+FTN && cftnsp->stype != UNIONTY+FTN)
136                 return;
137         /* Create struct assignment */
138         q = block(OREGNILNILPTR+STRTY0cftnsp->ssue);
ragge
1.5
139         q->n_rval = RBP;
mickey
1.1
140         q->n_lval = 8/* return buffer offset */
141         q = buildtree(UMULqNIL);
142         p = block(REGNILNILPTR+STRTY0cftnsp->ssue);
143         p = buildtree(UMULpNIL);
144         p = buildtree(ASSIGNqp);
145         ecomp(p);
146 }
147
148 /*
149  * code for the beginning of a function; a is an array of
150  * indices in symtab for the arguments; n is the number
151  */
152 void
ragge
1.8
153 bfcode(struct symtab **sint cnt)
mickey
1.1
154 {
ragge
1.11
155         union arglist *al;
ragge
1.8
156         struct symtab *sp;
157         NODE *p, *r;
158         int irnotyp;
mickey
1.1
159
160         if (cftnsp->stype == STRTY+FTN || cftnsp->stype == UNIONTY+FTN) {
161                 /* Function returns struct, adjust arg offset */
162                 for (i = 0i < cnti++) 
ragge
1.8
163                         s[i]->soffset += SZPOINT(LONG);
mickey
1.1
164         }
165
166         /* recalculate the arg offset and create TEMP moves */
ragge
1.8
167         /* Always do this for reg, even if not optimizing, to free arg regs */
ragge
1.9
168         nsse = ngpr = 0;
169         nrsp = ARGINIT;
ragge
1.8
170         for (i = 0i < cnti++) {
171                 sp = s[i];
172
173                 if (sp == NULL)
174                         continue/* XXX when happens this? */
175
176                 switch (typ = argtyp(sp->stypesp->sdfsp->ssue)) {
177                 case INTEGER:
178                 case SSE:
179                         if (typ == SSE)
180                                 rno = XMM0 + nsse++;
181                         else
182                                 rno = argregsi[ngpr++];
183                         r = block(REGNILNILsp->stypesp->sdfsp->ssue);
184                         regno(r) = rno;
185                         p = tempnode(0sp->stypesp->sdfsp->ssue);
186                         sp->soffset = regno(p);
187                         sp->sflags |= STNODE;
188                         ecomp(buildtree(ASSIGNpr));
189                         break;
ragge
1.9
190
191                 case INTMEM:
192                         sp->soffset = nrsp;
193                         nrsp += SZLONG;
194                         if (xtemps) {
195                                 p = tempnode(0sp->stypesp->sdfsp->ssue);
196                                 p = buildtree(ASSIGNpnametree(sp));
197                                 sp->soffset = regno(p->n_left);
198                                 sp->sflags |= STNODE;
199                                 ecomp(p);
200                         }
201                         break;
202
ragge
1.8
203                 default:
ragge
1.9
204                         cerror("bfcode: %d"typ);
mickey
1.1
205                 }
206         }
ragge
1.11
207
208         /* Check if there are varargs */
209         if (cftnsp->sdf == NULL || cftnsp->sdf->dfun == NULL)
210                 return/* no prototype */
211         al = cftnsp->sdf->dfun;
212         for (; al->type != TELLIPSISal++) {
213                 if (al->type == TNULL)
214                         return;
215                 if (al->type == STRTY || ISARY(al->type))
216                         al++;
217         }
218
219         /* fix stack offset */
220         SETOFF(autooffALMAX);
221
222         /* Save reg arguments in the reg save area */
223         p = NIL;
224         for (i = ngpri < 6i++) {
225                 r = block(REGNILNILLONG0MKSUE(LONG));
226                 regno(r) = argregsi[i];
227                 r = movtomem(r, -RSALONGOFF(i)-autooff);
228                 p = (p == NIL ? r : block(COMOPprINT0MKSUE(INT)));
229         }
230         for (i = nssei < 8i++) {
231                 r = block(REGNILNILDOUBLE0MKSUE(DOUBLE));
232                 regno(r) = i + XMM0;
233                 r = movtomem(r, -RSADBLOFF(i)-autooff);
234                 p = (p == NIL ? r : block(COMOPprINT0MKSUE(INT)));
235         }
236         autooff += RSASZ;
237         rsaoff = autooff;
238
239         ecomp(p);
mickey
1.1
240 }
241
242
243 /*
244  * by now, the automatics and register variables are allocated
245  */
246 void
247 bccode()
248 {
249         SETOFF(autooffSZINT);
250 }
251
252 /* called just before final exit */
253 /* flag is 1 if errors, 0 if none */
254 void
255 ejobcode(int flag )
256 {
257 #define _MKSTR(x) #x
258 #define MKSTR(x) _MKSTR(x)
259 #define OS MKSTR(TARGOS)
260         printf("\t.ident \"PCC: %s (%s)\"\n\t.end\n"PACKAGE_STRINGOS);
261 }
262
ragge
1.11
263 /*
264  * Varargs stuff:
265  * The ABI says that va_list should be declared as this typedef.
266  * We handcraft it here and then just reference it.
267  *
268  * typedef struct {
269  *      unsigned int gp_offset;
270  *      unsigned int fp_offset;
271  *      void *overflow_arg_area;
272  *      void *reg_save_area;
273  * } __builtin_va_list[1];
274  */
ragge
1.13
275
ragge
1.11
276 static char *gp_offset, *fp_offset, *overflow_arg_area, *reg_save_area;
ragge
1.13
277
mickey
1.1
278 void
279 bjobcode()
280 {
ragge
1.11
281         struct rstack *rp;
282         NODE *p, *q;
283         char *c;
284
285         gp_offset = addname("gp_offset");
286         fp_offset = addname("fp_offset");
287         overflow_arg_area = addname("overflow_arg_area");
288         reg_save_area = addname("reg_save_area");
289
290         rp = bstruct(NULLSTNAMENULL);
291         p = block(NAMENILNILUNSIGNED0MKSUE(UNSIGNED));
292         soumemb(pgp_offset0);
293         soumemb(pfp_offset0);
294         p->n_type = VOID+PTR;
295         p->n_sue = MKSUE(VOID);
296         soumemb(poverflow_arg_area0);
297         soumemb(preg_save_area0);
298         nfree(p);
299         q = dclstruct(rp);
300         c = addname("__builtin_va_list");
301         p = block(LBbdty(NAMEc), bcon(1), INT0MKSUE(INT));
302         p = tymerge(qp);
303         p->n_sp = lookup(c0);
304         defid(pTYPEDEF);
305         nfree(q);
306         nfree(p);
307 }
308
309 static NODE *
310 mkstkref(int offTWORD typ)
311 {
312         NODE *p;
313
314         p = block(REGNILNILPTR|typ0MKSUE(LONG));
315         regno(p) = FPREG;
316         return buildtree(PLUSpbcon(off/SZCHAR));
317 }
318
319 NODE *
320 amd64_builtin_stdarg_start(NODE *fNODE *a)
321 {
322         NODE *p, *r;
323
324         /* check num args and type */
325         if (a == NULL || a->n_op != CM || a->n_left->n_op == CM ||
326             !ISPTR(a->n_left->n_type))
327                 goto bad;
328
329         /* use the values from the function header */
330         p = a->n_left;
331         r = buildtree(ASSIGNstructref(ccopy(p), STREFreg_save_area),
332             mkstkref(-rsaoffVOID));
333         r = buildtree(COMOPr,
334             buildtree(ASSIGNstructref(ccopy(p), STREFoverflow_arg_area),
335             mkstkref(ARGINITVOID)));
336         r = buildtree(COMOPr,
337             buildtree(ASSIGNstructref(ccopy(p), STREFgp_offset),
338             bcon(ngpr*(SZLONG/SZCHAR))));
339         r = buildtree(COMOPr,
340             buildtree(ASSIGNstructref(ccopy(p), STREFfp_offset),
341             bcon(nsse*(SZDOUBLE*2/SZCHAR)+48)));
342
343         tfree(f);
344         tfree(a);
345         return r;
346 bad:
347         uerror("bad argument to __builtin_stdarg_start");
348         return bcon(0);
mickey
1.1
349 }
350
ragge
1.12
351 /*
352  * Create a tree that should be like the expression
353  *      ((long *)(l->gp_offset >= 48 ?
354  *          l->overflow_arg_area += 8, l->overflow_arg_area :
355  *          l->gp_offset += 8, l->reg_save_area + l->gp_offset))[-1]
ragge
1.13
356  * ...or similar for floats.
ragge
1.12
357  */
358 static NODE *
ragge
1.13
359 bva(NODE *apTWORD dtchar *otint addtoint max)
ragge
1.12
360 {
361         NODE *cm1, *cm2, *gpo, *ofa, *l1, *qc;
ragge
1.13
362         TWORD nt;
ragge
1.12
363
364         ofa = structref(ccopy(ap), STREFoverflow_arg_area);
ragge
1.13
365         l1 = buildtree(PLUSEQccopy(ofa), bcon(addto));
ragge
1.12
366         cm1 = buildtree(COMOPl1ofa);
367
ragge
1.13
368         gpo = structref(ccopy(ap), STREFot);
369         l1 = buildtree(PLUSEQccopy(gpo), bcon(addto));
ragge
1.12
370         cm2 = buildtree(COMOPl1buildtree(PLUSccopy(gpo),
371             structref(ccopy(ap), STREFreg_save_area)));
372         qc = buildtree(QUEST,
ragge
1.13
373             buildtree(GEgpobcon(max)),
ragge
1.12
374             buildtree(COLONcm1cm2));
ragge
1.13
375
376         nt = (dt == DOUBLE ? DOUBLE : LONG);
377         l1 = block(NAMENILNILnt|PTR0MKSUE(nt));
378         l1 = buildtree(CASTl1qc);
379         qc = l1->n_right;
380         nfree(l1->n_left);
381         nfree(l1);
382
383         qc = buildtree(UMULbuildtree(PLUSqcbcon(-addto)), NIL);
384
385         l1 = block(NAMENILNILdt0MKSUE(BTYPE(dt)));
ragge
1.12
386         l1 = buildtree(CASTl1qc);
ragge
1.13
387         qc = l1->n_right;
ragge
1.12
388         nfree(l1->n_left);
389         nfree(l1);
ragge
1.13
390
391         return qc;
ragge
1.12
392 }
393
ragge
1.11
394 NODE *
ragge
1.12
395 amd64_builtin_va_arg(NODE *fNODE *a)
396 {
397         NODE *ap, *r;
ragge
1.13
398         TWORD dt;
ragge
1.12
399
400         /* check num args and type */
401         if (a == NULL || a->n_op != CM || a->n_left->n_op == CM ||
402             !ISPTR(a->n_left->n_type) || a->n_right->n_op != TYPE)
403                 goto bad;
404
405         ap = a->n_left;
ragge
1.13
406         dt = a->n_right->n_type;
407         if (dt <= ULONGLONG || ISPTR(dt)) {
ragge
1.12
408                 /* type might be in general register */
ragge
1.13
409                 r = bva(apdtgp_offset848);
410         } else if (dt == FLOAT || dt == DOUBLE) {
411                 /* Float are promoted to double here */
412                 if (dt == FLOAT)
413                         dt = DOUBLE;
414                 r = bva(apdtfp_offset16RSASZ/SZCHAR);
ragge
1.12
415         } else {
ragge
1.13
416                 uerror("amd64_builtin_va_arg not supported type");
417                 goto bad;
ragge
1.12
418         }
419         tfree(a);
420         tfree(f);
421         return r;
422 bad:
423         uerror("bad argument to __builtin_va_arg");
424         return bcon(0);
425 }
ragge
1.11
426
427 NODE *
ragge
1.13
428 amd64_builtin_va_end(NODE *fNODE *a)
429 {
430         tfree(f);
431         tfree(a);
432         return bcon(0); /* nothing */
433 }
ragge
1.11
434
435 NODE *
436 amd64_builtin_va_copy(NODE *fNODE *a) { cerror("amd64_builtin_va_copy"); return NULL; }
437
ragge
1.7
438 static NODE *
439 movtoreg(NODE *pint rno)
mickey
1.1
440 {
441         NODE *r;
442
ragge
1.9
443         r = block(REGNILNILp->n_typep->n_dfp->n_sue);
ragge
1.7
444         regno(r) = rno;
445         return clocal(buildtree(ASSIGNrp));
446 }  
447
ragge
1.9
448 static NODE *
449 movtomem(NODE *pint off)
450 {
451         struct symtab s;
452         NODE *r, *l;
453
454         s.stype = p->n_type;
455         s.sdf = p->n_df;
456         s.ssue = p->n_sue;
457         s.soffset = off;
ragge
1.11
458         s.sclass = AUTO;
ragge
1.9
459
460         l = block(REGNILNILPTR+STRTY00);
461         l->n_lval = 0;
ragge
1.11
462         regno(l) = FPREG;
ragge
1.9
463
464         r = block(NAMENILNILp->n_typep->n_dfp->n_sue);
465         r->n_sp = &s;
466         r = stref(block(STREFlr000));
467
468         return clocal(buildtree(ASSIGNrp));
469 }  
470
ragge
1.7
471
472 /*
473  * AMD64 parameter classification.
474  */
475 static int
ragge
1.8
476 argtyp(TWORD tunion dimfun *dfstruct suedef *sue)
ragge
1.7
477 {
478         int cl = 0;
479
ragge
1.9
480         if (t <= ULONG || ISPTR(t)) {
ragge
1.7
481                 cl = ngpr < 6 ? INTEGER : INTMEM;
482         } else if (t == FLOAT || t == DOUBLE) {
ragge
1.8
483                 cl = nsse < 8 ? SSE : SSEMEM;
ragge
1.7
484         } else if (t == LDOUBLE) {
485                 cl = X87/* XXX */
486         } else if (t == STRTY) {
ragge
1.8
487                 if (tsize(tdfsue) > 4*SZLONG)
ragge
1.7
488                         cl = STRMEM;
489                 else
490                         cerror("clasif");
491         } else
492                 cerror("FIXME: classify");
493         return cl;
494 }
495
496 static void
497 argput(NODE *p)
498 {
499         NODE *q;
500         int typr;
mickey
1.1
501
ragge
1.7
502         /* first arg may be struct return pointer */
503         /* XXX - check if varargs; setup al */
ragge
1.8
504         switch (typ = argtyp(p->n_typep->n_dfp->n_sue)) {
ragge
1.7
505         case INTEGER:
506         case SSE:
507                 q = talloc();
508                 *q = *p;
509                 if (typ == SSE)
510                         r = XMM0 + nsse++;
511                 else
512                         r = argregsi[ngpr++];
513                 q = movtoreg(qr);
514                 *p = *q;
515                 nfree(q);
516                 break;
517         case X87:
518                 cerror("no long double yet");
519                 break;
ragge
1.9
520
521         case INTMEM:
522                 q = talloc();
523                 *q = *p;
524                 r = nrsp;
525                 nrsp += SZLONG;
526                 q = movtomem(qr);
527                 *p = *q;
528                 nfree(q);
529                 break;
530
ragge
1.7
531         case STRMEM:
532                 /* Struct moved to memory */
533         case STRREG:
534                 /* Struct in registers */
535         default:
ragge
1.9
536                 cerror("argument %d"typ);
mickey
1.1
537         }
ragge
1.7
538 }
mickey
1.1
539
540
541 /*
542  * Called with a function call with arguments as argument.
543  * This is done early in buildtree() and only done once.
544  * Returns p.
545  */
546 NODE *
547 funcode(NODE *p)
548 {
ragge
1.8
549         NODE *l, *r;
mickey
1.1
550
ragge
1.9
551         nsse = ngpr = nrsp = 0;
ragge
1.7
552         listf(p->n_rightargput);
ragge
1.8
553
554         /* Always emit number of SSE regs used */
555         l = movtoreg(bcon(nsse), RAX);
556         if (p->n_right->n_op != CM) {
557                 p->n_right = block(CMlp->n_rightINT0MKSUE(INT));
558         } else {
559                 for (r = p->n_rightr->n_left->n_op == CMr = r->n_left)
560                         ;
561                 r->n_left = block(CMlr->n_leftINT0MKSUE(INT));
562         }
mickey
1.1
563         return p;
564 }
565
566 /*
567  * return the alignment of field of type t
568  */
569 int
570 fldal(unsigned int t)
571 {
572         uerror("illegal field type");
573         return(ALINT);
574 }
575
576 /* fix up type of field p */
577 void
578 fldty(struct symtab *p)
579 {
580 }
581
582 /*
583  * XXX - fix genswitch.
584  */
585 int
586 mygenswitch(int numTWORD typestruct swents **pint n)
587 {
588         return 0;
589 }
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-09-02 21:12 +0200