Quick Search:

View

Revision:
Expand:  
Changeset: MAIN:ragge:20090708082323

Diff

Diff from 1.15 to:

Annotations

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

Annotated File View

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