Quick Search:

View

Revision:
Expand:  
Changeset: MAIN:ragge:20090621081031

Diff

Diff from 1.14 to:

Annotations

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

Annotated File View

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