Quick Search:

View

Revision:
Expand:  
Changeset: MAIN:mickey:20091219135256

Diff

Diff from 1.16 to:

Annotations

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

Annotated File View

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