Quick Search:

View

Revision:
Expand:  
Changeset: MAIN:ragge:20101108180808

Diff

Diff from 1.38 to:

Annotations

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

Annotated File View

ragge
1.38
1 /*      $Id: code.c,v 1.38 2010/11/08 18:08:08 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;
ragge
1.18
56 static int stroffset;
mickey
1.1
57
ragge
1.33
58 static int varneeds;
59 #define NEED_GPNEXT     001
60 #define NEED_FPNEXT     002
61 #define NEED_1REGREF    004
62 #define NEED_2REGREF    010
63 #define NEED_MEMREF     020
64
ragge
1.23
65 static int argtyp(TWORD tunion dimfun *dfstruct attr *ap);
ragge
1.14
66 static NODE *movtomem(NODE *pint offint reg);
ragge
1.18
67 static NODE *movtoreg(NODE *pint rno);
ragge
1.8
68
mickey
1.1
69 /*
70  * Define everything needed to print out some data (or text).
71  * This means segment, alignment, visibility, etc.
72  */
73 void
74 defloc(struct symtab *sp)
75 {
76         extern char *nextsect;
77         static char *loctbl[] = { "text""data""section .rodata" };
ragge
1.6
78         int weak = 0;
ragge
1.18
79         char *name;
mickey
1.1
80         TWORD t;
81         int s;
82
83         if (sp == NULL) {
84                 lastloc = -1;
85                 return;
86         }
ragge
1.28
87         if (kflag) {
88                 loctbl[DATA] = "section .data.rel.rw,\"aw\",@progbits";
89                 loctbl[RDATA] = "section .data.rel.ro,\"aw\",@progbits";
90         }
mickey
1.1
91         t = sp->stype;
92         s = ISFTN(t) ? PROG : ISCON(cqual(tsp->squal)) ? RDATA : DATA;
ragge
1.18
93         if ((name = sp->soname) == NULL)
94                 name = exname(sp->sname);
mickey
1.1
95 #ifdef TLS
96         if (sp->sflags & STLS) {
97                 if (s != DATA)
98                         cerror("non-data symbol in tls section");
99                 nextsect = ".tdata";
100         }
101 #endif
ragge
1.6
102 #ifdef GCC_COMPAT
103         {
ragge
1.23
104                 struct attr *ga;
ragge
1.6
105
ragge
1.23
106                 if ((ga = attr_find(sp->sapGCC_ATYP_SECTION)) != NULL)
107                         nextsect = ga->sarg(0);
108                 if ((ga = attr_find(sp->sapGCC_ATYP_WEAK)) != NULL)
ragge
1.6
109                         weak = 1;
ragge
1.23
110                 if (attr_find(sp->sapGCC_ATYP_DESTRUCTOR)) {
ragge
1.18
111                         printf("\t.section\t.dtors,\"aw\",@progbits\n");
112                         printf("\t.align 8\n\t.quad\t%s\n"name);
113                         lastloc = -1;
114                 }
ragge
1.23
115                 if (attr_find(sp->sapGCC_ATYP_CONSTRUCTOR)) {
ragge
1.18
116                         printf("\t.section\t.ctors,\"aw\",@progbits\n");
117                         printf("\t.align 8\n\t.quad\t%s\n"name);
118                         lastloc = -1;
119                 }
ragge
1.23
120                 if ((ga = attr_find(sp->sapGCC_ATYP_VISIBILITY)) &&
121                     strcmp(ga->sarg(0), "default"))
122                         printf("\t.%s %s\n"ga->sarg(0), name);
ragge
1.6
123         }
124 #endif
125
mickey
1.1
126         if (nextsect) {
127                 printf("        .section %s\n"nextsect);
128                 nextsect = NULL;
129                 s = -1;
130         } else if (s != lastloc)
131                 printf("        .%s\n"loctbl[s]);
132         lastloc = s;
133         while (ISARY(t))
134                 t = DECREF(t);
ragge
1.23
135         s = ISFTN(t) ? ALINT : talign(tsp->sap);
ragge
1.3
136         if (s > ALCHAR)
137                 printf("        .align %d\n"s/ALCHAR);
ragge
1.6
138         if (weak)
139                 printf("        .weak %s\n"name);
mickey
1.16
140         else if (sp->sclass == EXTDEF) {
141                 printf("\t.globl %s\n"name);
142                 printf("\t.type %s,@%s\n"name,
143                     ISFTN(t)? "function" : "object");
144         }
mickey
1.1
145         if (sp->slevel == 0)
ragge
1.6
146                 printf("%s:\n"name);
mickey
1.1
147         else
148                 printf(LABFMT ":\n"sp->soffset);
149 }
150
151 /*
152  * code for the end of a function
153  * deals with struct return here
ragge
1.38
154  * The return value is in (or pointed to by) RETREG.
mickey
1.1
155  */
156 void
157 efcode()
158 {
ragge
1.18
159         struct symtab *sp;
mickey
1.1
160         extern int gotnr;
ragge
1.18
161         TWORD t;
ragge
1.21
162         NODE *p, *r, *l;
ragge
1.38
163         int typssz;
mickey
1.1
164
165         gotnr = 0;      /* new number for next fun */
ragge
1.18
166         sp = cftnsp;
167         t = DECREF(sp->stype);
ragge
1.21
168         if (t != STRTY && t != UNIONTY)
mickey
1.1
169                 return;
ragge
1.18
170
ragge
1.38
171         /* XXX should have one routine for this */
172         if ((typ = argtyp(tsp->sdfsp->sap)) == STRREG) {
173                 /* Cast to long pointer and move to the registers */
174                 /* XXX can overrun struct size */
175                 /* XXX check carefully for SSE members */
ragge
1.21
176
ragge
1.38
177                 if ((ssz = tsize(tsp->sdfsp->sap)) > SZLONG*2)
178                         cerror("efcode1");
ragge
1.21
179
ragge
1.38
180                 if (ssz > SZLONG) {
181                         p = block(REGNILNILLONG+PTR0MKAP(LONG));
182                         regno(p) = RAX;
183                         p = buildtree(UMULbuildtree(PLUSpbcon(1)), NIL);
184                         ecomp(movtoreg(pRDX));
185                 }
186                 p = block(REGNILNILLONG+PTR0MKAP(LONG));
187                 regno(p) = RAX;
188                 p = buildtree(UMULpNIL);
189                 ecomp(movtoreg(pRAX));
190         } else if (typ == STRMEM) {
191                 r = block(REGNILNILINCREF(t), sp->sdfsp->sap);
192                 regno(r) = RAX;
193                 r = buildtree(UMULrNIL);
194                 l = tempnode(stroffsetINCREF(t), sp->sdfsp->sap);
195                 l = buildtree(UMULlNIL);
196                 ecomp(buildtree(ASSIGNlr));
197                 l = block(REGNILNILLONG0MKAP(LONG));
198                 regno(l) = RAX;
199                 r = tempnode(stroffsetLONG0MKAP(LONG));
200                 ecomp(buildtree(ASSIGNlr));
201         } else
202                 cerror("efcode");
mickey
1.1
203 }
204
205 /*
206  * code for the beginning of a function; a is an array of
207  * indices in symtab for the arguments; n is the number
208  */
209 void
ragge
1.8
210 bfcode(struct symtab **sint cnt)
mickey
1.1
211 {
ragge
1.11
212         union arglist *al;
ragge
1.8
213         struct symtab *sp;
214         NODE *p, *r;
ragge
1.37
215         TWORD t;
ragge
1.8
216         int irnotyp;
mickey
1.1
217
218         /* recalculate the arg offset and create TEMP moves */
ragge
1.8
219         /* Always do this for reg, even if not optimizing, to free arg regs */
ragge
1.9
220         nsse = ngpr = 0;
221         nrsp = ARGINIT;
ragge
1.17
222         if (cftnsp->stype == STRTY+FTN || cftnsp->stype == UNIONTY+FTN) {
223                 sp = cftnsp;
ragge
1.23
224                 if (argtyp(DECREF(sp->stype), sp->sdfsp->sap) == STRMEM) {
225                         r = block(REGNILNILLONG0MKAP(LONG));
ragge
1.21
226                         regno(r) = argregsi[ngpr++];
ragge
1.23
227                         p = tempnode(0r->n_typer->n_dfr->n_ap);
ragge
1.18
228                         stroffset = regno(p);
229                         ecomp(buildtree(ASSIGNpr));
230                 }
ragge
1.17
231         }
232
ragge
1.8
233         for (i = 0i < cnti++) {
234                 sp = s[i];
235
236                 if (sp == NULL)
237                         continue/* XXX when happens this? */
238
ragge
1.23
239                 switch (typ = argtyp(sp->stypesp->sdfsp->sap)) {
ragge
1.8
240                 case INTEGER:
241                 case SSE:
242                         if (typ == SSE)
243                                 rno = XMM0 + nsse++;
244                         else
245                                 rno = argregsi[ngpr++];
ragge
1.23
246                         r = block(REGNILNILsp->stypesp->sdfsp->sap);
ragge
1.8
247                         regno(r) = rno;
ragge
1.23
248                         p = tempnode(0sp->stypesp->sdfsp->sap);
ragge
1.8
249                         sp->soffset = regno(p);
250                         sp->sflags |= STNODE;
251                         ecomp(buildtree(ASSIGNpr));
252                         break;
ragge
1.9
253
ragge
1.30
254                 case SSEMEM:
255                         sp->soffset = nrsp;
256                         nrsp += SZDOUBLE;
257                         if (xtemps) {
258                                 p = tempnode(0sp->stypesp->sdfsp->sap);
259                                 p = buildtree(ASSIGNpnametree(sp));
260                                 sp->soffset = regno(p->n_left);
261                                 sp->sflags |= STNODE;
262                                 ecomp(p);
263                         }
264                         break;
265
ragge
1.9
266                 case INTMEM:
267                         sp->soffset = nrsp;
268                         nrsp += SZLONG;
269                         if (xtemps) {
ragge
1.23
270                                 p = tempnode(0sp->stypesp->sdfsp->sap);
ragge
1.9
271                                 p = buildtree(ASSIGNpnametree(sp));
272                                 sp->soffset = regno(p->n_left);
273                                 sp->sflags |= STNODE;
274                                 ecomp(p);
275                         }
276                         break;
277
ragge
1.17
278                 case STRMEM/* Struct in memory */
279                         sp->soffset = nrsp;
ragge
1.23
280                         nrsp += tsize(sp->stypesp->sdfsp->sap);
ragge
1.17
281                         break;
282
ragge
1.31
283                 case X87/* long double args */
284                         sp->soffset = nrsp;
285                         nrsp += SZLDOUBLE;
286                         break;
287
ragge
1.17
288                 case STRREG/* Struct in register */
289                         /* Allocate space on stack for the struct */
290                         /* For simplicity always fetch two longwords */
291                         autooff += (2*SZLONG);
292
ragge
1.23
293                         r = block(REGNILNILLONG0MKAP(LONG));
ragge
1.17
294                         regno(r) = argregsi[ngpr++];
295                         ecomp(movtomem(r, -autooffFPREG));
296
ragge
1.23
297                         if (tsize(sp->stypesp->sdfsp->sap) > SZLONG) {
298                                 r = block(REGNILNILLONG0MKAP(LONG));
ragge
1.17
299                                 regno(r) = argregsi[ngpr++];
300                                 ecomp(movtomem(r, -autooff+SZLONGFPREG));
301                         }
302
303                         sp->soffset = -autooff;
304                         break;
305
ragge
1.8
306                 default:
ragge
1.9
307                         cerror("bfcode: %d"typ);
mickey
1.1
308                 }
309         }
ragge
1.11
310
311         /* Check if there are varargs */
312         if (cftnsp->sdf == NULL || cftnsp->sdf->dfun == NULL)
313                 return/* no prototype */
314         al = cftnsp->sdf->dfun;
ragge
1.15
315
ragge
1.11
316         for (; al->type != TELLIPSISal++) {
ragge
1.37
317                 t = al->type;
318                 if (t == TNULL)
ragge
1.11
319                         return;
ragge
1.37
320                 if (BTYPE(t) == STRTY || BTYPE(t) == UNIONTY)
ragge
1.11
321                         al++;
ragge
1.37
322                 for (; t > BTMASKt = DECREF(t))
323                         if (ISARY(t) || ISFTN(t))
324                                 al++;
ragge
1.11
325         }
326
327         /* fix stack offset */
328         SETOFF(autooffALMAX);
329
330         /* Save reg arguments in the reg save area */
331         p = NIL;
332         for (i = ngpri < 6i++) {
ragge
1.23
333                 r = block(REGNILNILLONG0MKAP(LONG));
ragge
1.11
334                 regno(r) = argregsi[i];
ragge
1.14
335                 r = movtomem(r, -RSALONGOFF(i)-autooffFPREG);
ragge
1.23
336                 p = (p == NIL ? r : block(COMOPprINT0MKAP(INT)));
ragge
1.11
337         }
338         for (i = nssei < 8i++) {
ragge
1.23
339                 r = block(REGNILNILDOUBLE0MKAP(DOUBLE));
ragge
1.11
340                 regno(r) = i + XMM0;
ragge
1.14
341                 r = movtomem(r, -RSADBLOFF(i)-autooffFPREG);
ragge
1.23
342                 p = (p == NIL ? r : block(COMOPprINT0MKAP(INT)));
ragge
1.11
343         }
344         autooff += RSASZ;
345         rsaoff = autooff;
ragge
1.14
346         thissse = nsse;
347         thisgpr = ngpr;
348         thisrsp = nrsp;
ragge
1.11
349
350         ecomp(p);
mickey
1.1
351 }
352
353
354 /*
355  * by now, the automatics and register variables are allocated
356  */
357 void
358 bccode()
359 {
360         SETOFF(autooffSZINT);
361 }
362
363 /* called just before final exit */
364 /* flag is 1 if errors, 0 if none */
365 void
366 ejobcode(int flag )
367 {
ragge
1.33
368         if (flag)
369                 return;
370
371         /* printout varargs routines if used */
372         if (varneeds & NEED_GPNEXT) {
373                 printf(".text\n.align 4\n.type __pcc_gpnext,@function\n");
374                 printf("__pcc_gpnext:\n");
375                 printf("cmpl $48,(%%rdi)\njae 1f\n");
376                 printf("movl (%%rdi),%%eax\naddq 16(%%rdi),%%rax\n");
377                 printf("movq (%%rax),%%rax\naddl $8,(%%rdi)\nret\n");
378                 printf("1:movq 8(%%rdi),%%rax\nmovq (%%rax),%%rax\n");
379                 printf("addq $8,8(%%rdi)\nret\n");
380         }
381         if (varneeds & NEED_FPNEXT) {
382                 printf(".text\n.align 4\n.type __pcc_fpnext,@function\n");
383                 printf("__pcc_fpnext:\n");
384                 printf("cmpl $176,4(%%rdi)\njae 1f\n");
385                 printf("movl 4(%%rdi),%%eax\naddq 16(%%rdi),%%rax\n");
386                 printf("movsd (%%rax),%%xmm0\naddl $16,4(%%rdi)\nret\n");
387                 printf("1:movq 8(%%rdi),%%rax\nmovsd (%%rax),%%xmm0\n");
388                 printf("addq $8,8(%%rdi)\nret\n");
389         }
390         if (varneeds & NEED_1REGREF) {
391                 printf(".text\n.align 4\n.type __pcc_1regref,@function\n");
392                 printf("__pcc_1regref:\n");
393                 printf("cmpl $48,(%%rdi)\njae 1f\n");
394                 printf("movl (%%rdi),%%eax\naddq 16(%%rdi),%%rax\n");
395                 printf("addl $8,(%%rdi)\nret\n");
396                 printf("1:movq 8(%%rdi),%%rax\n");
397                 printf("addq $8,8(%%rdi)\nret\n");
398         }
399         if (varneeds & NEED_2REGREF) {
400                 printf(".text\n.align 4\n.type __pcc_2regref,@function\n");
401                 printf("__pcc_2regref:\n");
402                 printf("cmpl $40,(%%rdi)\njae 1f\n");
403                 printf("movl (%%rdi),%%eax\naddq 16(%%rdi),%%rax\n");
404                 printf("addl $16,(%%rdi)\nret\n");
405                 printf("1:movq 8(%%rdi),%%rax\n");
406                 printf("addq $16,8(%%rdi)\nret\n");
407         }
408         if (varneeds & NEED_MEMREF) {
409                 printf(".text\n.align 4\n.type __pcc_memref,@function\n");
410                 printf("__pcc_memref:\n");
411                 printf("movq 8(%%rdi),%%rax\n");
412                 printf("addq %%rsi,8(%%rdi)\nret\n");
413         }
414                 
415
mickey
1.1
416 #define _MKSTR(x) #x
417 #define MKSTR(x) _MKSTR(x)
418 #define OS MKSTR(TARGOS)
419         printf("\t.ident \"PCC: %s (%s)\"\n\t.end\n"PACKAGE_STRINGOS);
420 }
421
ragge
1.11
422 /*
423  * Varargs stuff:
424  * The ABI says that va_list should be declared as this typedef.
425  * We handcraft it here and then just reference it.
426  *
427  * typedef struct {
428  *      unsigned int gp_offset;
429  *      unsigned int fp_offset;
430  *      void *overflow_arg_area;
431  *      void *reg_save_area;
432  * } __builtin_va_list[1];
ragge
1.33
433  *
434  * There are a number of asm routines printed out if varargs are used:
435  *      long __pcc_gpnext(va)   - get a gpreg value
436  *      long __pcc_fpnext(va)   - get a fpreg value
437  *      void *__pcc_1regref(va) - get reference to a onereg struct 
438  *      void *__pcc_2regref(va) - get reference to a tworeg struct 
439  *      void *__pcc_memref(va,sz)       - get reference to a large struct 
ragge
1.11
440  */
ragge
1.13
441
ragge
1.11
442 static char *gp_offset, *fp_offset, *overflow_arg_area, *reg_save_area;
ragge
1.33
443 static char *gpnext, *fpnext, *_1regref, *_2regref, *memref;
ragge
1.13
444
mickey
1.1
445 void
446 bjobcode()
447 {
ragge
1.33
448         struct symtab *sp;
ragge
1.11
449         struct rstack *rp;
450         NODE *p, *q;
451         char *c;
452
453         gp_offset = addname("gp_offset");
454         fp_offset = addname("fp_offset");
455         overflow_arg_area = addname("overflow_arg_area");
456         reg_save_area = addname("reg_save_area");
457
458         rp = bstruct(NULLSTNAMENULL);
ragge
1.23
459         p = block(NAMENILNILUNSIGNED0MKAP(UNSIGNED));
ragge
1.11
460         soumemb(pgp_offset0);
461         soumemb(pfp_offset0);
462         p->n_type = VOID+PTR;
ragge
1.23
463         p->n_ap = MKAP(VOID);
ragge
1.11
464         soumemb(poverflow_arg_area0);
465         soumemb(preg_save_area0);
466         nfree(p);
467         q = dclstruct(rp);
468         c = addname("__builtin_va_list");
ragge
1.23
469         p = block(LBbdty(NAMEc), bcon(1), INT0MKAP(INT));
ragge
1.11
470         p = tymerge(qp);
471         p->n_sp = lookup(c0);
472         defid(pTYPEDEF);
473         nfree(q);
474         nfree(p);
ragge
1.33
475
476         /* for the static varargs functions */
477 #define MKN(vn, rn, tp) \
478         { vn = addname(rn); sp = lookup(vnSNORMAL); \
479           sp->sclass = USTATICsp->stype = tp; }
480
481         MKN(gpnext"__pcc_gpnext"FTN|LONG);
482         MKN(fpnext"__pcc_fpnext"FTN|DOUBLE);
483         MKN(_1regref"__pcc_1regref"FTN|VOID|(PTR<<TSHIFT));
484         MKN(_2regref"__pcc_2regref"FTN|VOID|(PTR<<TSHIFT));
485         MKN(memref"__pcc_memref"FTN|VOID|(PTR<<TSHIFT));
ragge
1.11
486 }
487
488 static NODE *
489 mkstkref(int offTWORD typ)
490 {
491         NODE *p;
492
ragge
1.23
493         p = block(REGNILNILPTR|typ0MKAP(LONG));
ragge
1.11
494         regno(p) = FPREG;
495         return buildtree(PLUSpbcon(off/SZCHAR));
496 }
497
498 NODE *
ragge
1.24
499 amd64_builtin_stdarg_start(NODE *fNODE *aTWORD t)
ragge
1.11
500 {
501         NODE *p, *r;
502
503         /* use the values from the function header */
504         p = a->n_left;
505         r = buildtree(ASSIGNstructref(ccopy(p), STREFreg_save_area),
506             mkstkref(-rsaoffVOID));
507         r = buildtree(COMOPr,
508             buildtree(ASSIGNstructref(ccopy(p), STREFoverflow_arg_area),
ragge
1.14
509             mkstkref(thisrspVOID)));
ragge
1.11
510         r = buildtree(COMOPr,
511             buildtree(ASSIGNstructref(ccopy(p), STREFgp_offset),
ragge
1.14
512             bcon(thisgpr*(SZLONG/SZCHAR))));
ragge
1.11
513         r = buildtree(COMOPr,
514             buildtree(ASSIGNstructref(ccopy(p), STREFfp_offset),
ragge
1.14
515             bcon(thissse*(SZDOUBLE*2/SZCHAR)+48)));
ragge
1.11
516
517         tfree(f);
518         tfree(a);
519         return r;
mickey
1.1
520 }
521
ragge
1.11
522 NODE *
ragge
1.24
523 amd64_builtin_va_arg(NODE *fNODE *aTWORD t)
ragge
1.12
524 {
ragge
1.29
525         NODE *ap, *r, *dp;
ragge
1.12
526
527         ap = a->n_left;
ragge
1.29
528         dp = a->n_right;
ragge
1.33
529         if (dp->n_type <= ULONGLONG || ISPTR(dp->n_type) ||
530             dp->n_type == FLOAT || dp->n_type == DOUBLE) {
ragge
1.12
531                 /* type might be in general register */
ragge
1.33
532                 if (dp->n_type == FLOAT || dp->n_type == DOUBLE) {
533                         f->n_sp = lookup(fpnextSNORMAL);
534                         varneeds |= NEED_FPNEXT;
535                 } else {
536                         f->n_sp = lookup(gpnextSNORMAL);
537                         varneeds |= NEED_GPNEXT;
538                 }
ragge
1.35
539                 f->n_type = f->n_sp->stype = INCREF(dp->n_type) + (FTN-PTR);
540                 f->n_ap = dp->n_ap;
541                 f->n_df = dp->n_df;
ragge
1.33
542                 f = clocal(f);
543                 r = buildtree(CALLfccopy(ap));
544         } else if (ISSOU(dp->n_type)) {
545                 /* put a reference directly to the stack */
546                 int sz = tsize(dp->n_typedp->n_dfdp->n_ap);
547                 int al = talign(dp->n_typedp->n_ap);
548                 if (al < ALLONG)
549                         al = ALLONG;
550                 if (sz <= SZLONG*2 && al == ALLONG) {
551                         if (sz <= SZLONG) {
552                                 f->n_sp = lookup(_1regrefSNORMAL);
553                                 varneeds |= NEED_1REGREF;
554                         } else {
555                                 f->n_sp = lookup(_2regrefSNORMAL);
556                                 varneeds |= NEED_2REGREF;
557                         }
558                         f->n_type = f->n_sp->stype;
559                         f = clocal(f);
560                         r = buildtree(CALLfccopy(ap));
561                         r = ccast(rINCREF(dp->n_type), 0dp->n_dfdp->n_ap);
562                         r = buildtree(UMULrNIL);
563                 } else {
564                         f->n_sp = lookup(memrefSNORMAL);
565                         varneeds |= NEED_MEMREF;
566                         f->n_type = f->n_sp->stype;
567                         f = clocal(f);
568                         SETOFF(szal);
569                         r = buildtree(CALLf,
570                             buildtree(CMccopy(ap), bcon(sz/SZCHAR)));
571                         r = ccast(rINCREF(dp->n_type), 0dp->n_dfdp->n_ap);
572                         r = buildtree(UMULrNIL);
573                 }
ragge
1.12
574         } else {
ragge
1.13
575                 uerror("amd64_builtin_va_arg not supported type");
576                 goto bad;
ragge
1.12
577         }
578         tfree(a);
579         return r;
580 bad:
581         uerror("bad argument to __builtin_va_arg");
582         return bcon(0);
583 }
ragge
1.11
584
585 NODE *
ragge
1.24
586 amd64_builtin_va_end(NODE *fNODE *aTWORD t)
ragge
1.13
587 {
588         tfree(f);
589         tfree(a);
590         return bcon(0); /* nothing */
591 }
ragge
1.11
592
593 NODE *
ragge
1.33
594 amd64_builtin_va_copy(NODE *fNODE *aTWORD t)
595 {
596         tfree(f);
597         f = buildtree(ASSIGNbuildtree(UMULa->n_leftNIL),
598             buildtree(UMULa->n_rightNIL));
599         nfree(a);
600         return f;
601 }
ragge
1.11
602
ragge
1.7
603 static NODE *
604 movtoreg(NODE *pint rno)
mickey
1.1
605 {
606         NODE *r;
607
ragge
1.23
608         r = block(REGNILNILp->n_typep->n_dfp->n_ap);
ragge
1.7
609         regno(r) = rno;
610         return clocal(buildtree(ASSIGNrp));
611 }  
612
ragge
1.9
613 static NODE *
ragge
1.14
614 movtomem(NODE *pint offint reg)
ragge
1.9
615 {
616         struct symtab s;
617         NODE *r, *l;
618
619         s.stype = p->n_type;
ragge
1.25
620         s.squal = 0;
ragge
1.9
621         s.sdf = p->n_df;
ragge
1.23
622         s.sap = p->n_ap;
ragge
1.9
623         s.soffset = off;
ragge
1.11
624         s.sclass = AUTO;
ragge
1.9
625
626         l = block(REGNILNILPTR+STRTY00);
627         l->n_lval = 0;
ragge
1.14
628         regno(l) = reg;
ragge
1.9
629
ragge
1.23
630         r = block(NAMENILNILp->n_typep->n_dfp->n_ap);
ragge
1.9
631         r->n_sp = &s;
632         r = stref(block(STREFlr000));
633
634         return clocal(buildtree(ASSIGNrp));
635 }  
636
ragge
1.7
637
638 /*
639  * AMD64 parameter classification.
640  */
641 static int
ragge
1.23
642 argtyp(TWORD tunion dimfun *dfstruct attr *ap)
ragge
1.7
643 {
644         int cl = 0;
645
ragge
1.9
646         if (t <= ULONG || ISPTR(t)) {
ragge
1.7
647                 cl = ngpr < 6 ? INTEGER : INTMEM;
648         } else if (t == FLOAT || t == DOUBLE) {
ragge
1.8
649                 cl = nsse < 8 ? SSE : SSEMEM;
ragge
1.7
650         } else if (t == LDOUBLE) {
651                 cl = X87/* XXX */
ragge
1.26
652         } else if (t == STRTY || t == UNIONTY) {
ragge
1.32
653                 int sz = tsize(tdfap);
654
655                 if (sz > 2*SZLONG || ((sz+SZLONG)/SZLONG)+ngpr > 6 ||
656                     attr_find(apGCC_ATYP_PACKED) != NULL)
ragge
1.7
657                         cl = STRMEM;
658                 else
ragge
1.17
659                         cl = STRREG;
ragge
1.7
660         } else
661                 cerror("FIXME: classify");
662         return cl;
663 }
664
ragge
1.26
665 static NODE *
ragge
1.7
666 argput(NODE *p)
667 {
668         NODE *q;
ragge
1.17
669         int typrssz;
mickey
1.1
670
ragge
1.26
671         if (p->n_op == CM) {
672                 p->n_left = argput(p->n_left);
673                 p->n_right = argput(p->n_right);
674                 return p;
675         }
676
ragge
1.7
677         /* first arg may be struct return pointer */
678         /* XXX - check if varargs; setup al */
ragge
1.23
679         switch (typ = argtyp(p->n_typep->n_dfp->n_ap)) {
ragge
1.7
680         case INTEGER:
681         case SSE:
682                 if (typ == SSE)
683                         r = XMM0 + nsse++;
684                 else
685                         r = argregsi[ngpr++];
ragge
1.26
686                 p = movtoreg(pr);
ragge
1.7
687                 break;
ragge
1.26
688
ragge
1.7
689         case X87:
ragge
1.25
690                 r = nrsp;
691                 nrsp += SZLDOUBLE;
ragge
1.26
692                 p = movtomem(prSTKREG);
ragge
1.7
693                 break;
ragge
1.9
694
ragge
1.30
695         case SSEMEM:
696                 r = nrsp;
697                 nrsp += SZDOUBLE;
698                 p = movtomem(prSTKREG);
699                 break;
700
ragge
1.9
701         case INTMEM:
702                 r = nrsp;
703                 nrsp += SZLONG;
ragge
1.26
704                 p = movtomem(prSTKREG);
ragge
1.9
705                 break;
706
ragge
1.17
707         case STRREG/* Struct in registers */
708                 /* Cast to long pointer and move to the registers */
ragge
1.27
709                 /* XXX can overrun struct size */
ragge
1.36
710                 /* XXX check carefully for SSE members */
ragge
1.23
711                 ssz = tsize(p->n_typep->n_dfp->n_ap);
ragge
1.17
712
713                 if (ssz <= SZLONG) {
714                         q = cast(p->n_leftLONG+PTR0);
ragge
1.27
715                         nfree(p);
ragge
1.17
716                         q = buildtree(UMULqNIL);
ragge
1.26
717                         p = movtoreg(qargregsi[ngpr++]);
ragge
1.17
718                 } else if (ssz <= SZLONG*2) {
ragge
1.33
719                         NODE *ql, *qr;
720
721                         qr = cast(ccopy(p->n_left), LONG+PTR0);
722                         qr = movtoreg(buildtree(UMULqrNIL),
723                             argregsi[ngpr++]);
724
725                         ql = cast(p->n_leftLONG+PTR0);
726                         ql = buildtree(UMULbuildtree(PLUSqlbcon(1)), NIL);
727                         ql = movtoreg(qlargregsi[ngpr++]);
ragge
1.17
728
ragge
1.27
729                         nfree(p);
ragge
1.33
730                         p = buildtree(CMqlqr);
ragge
1.17
731                 } else
732                         cerror("STRREG");
733                 break;
734
ragge
1.26
735         case STRMEM: {
736                 struct symtab s;
737                 NODE *l, *t;
738
739                 q = buildtree(UMULp->n_leftNIL);
740
741                 s.stype = p->n_type;
742                 s.squal = 0;
743                 s.sdf = p->n_df;
744                 s.sap = p->n_ap;
745                 s.soffset = nrsp;
746                 s.sclass = AUTO;
747
748                 nrsp += tsize(p->n_typep->n_dfp->n_ap);
749
750                 l = block(REGNILNILPTR+STRTY00);
751                 l->n_lval = 0;
752                 regno(l) = STKREG;
753
754                 t = block(NAMENILNILp->n_typep->n_dfp->n_ap);
755                 t->n_sp = &s;
756                 t = stref(block(STREFlt000));
757
758                 t = (buildtree(ASSIGNtq));
759                 nfree(p);
760                 p = t->n_left;
761                 nfree(t);
762                 break;
763                 }
764
ragge
1.7
765         default:
ragge
1.9
766                 cerror("argument %d"typ);
mickey
1.1
767         }
ragge
1.26
768         return p;
ragge
1.7
769 }
mickey
1.1
770
ragge
1.26
771 /*
772  * Sort arglist so that register assignments ends up last.
773  */
774 static int
775 argsort(NODE *p)
776 {
ragge
1.36
777         NODE *q, *r;
ragge
1.26
778         int rv = 0;
779
ragge
1.36
780         if (p->n_op != CM) {
781                 if (p->n_op == ASSIGN && p->n_left->n_op == REG &&
782                     coptype(p->n_right->n_op) != LTYPE) {
783                         q = tempnode(0p->n_typep->n_dfp->n_ap);
784                         r = ccopy(q);
785                         p->n_right = buildtree(COMOP,
786                             buildtree(ASSIGNqp->n_right), r);
787                 }
ragge
1.26
788                 return rv;
ragge
1.36
789         }
ragge
1.33
790         if (p->n_right->n_op == CM) {
791                 /* fixup for small structs in regs */
792                 q = p->n_right->n_left;
793                 p->n_right->n_left = p->n_left;
794                 p->n_left = p->n_right;
795                 p->n_right = q;
796         }
ragge
1.36
797         if (p->n_right->n_op == ASSIGN && p->n_right->n_left->n_op == REG &&
798             coptype(p->n_right->n_right->n_op) != LTYPE) {
799                 /* move before everything to avoid reg trashing */
800                 q = tempnode(0p->n_right->n_type,
801                     p->n_right->n_dfp->n_right->n_ap);
802                 r = ccopy(q);
803                 p->n_right->n_right = buildtree(COMOP,
804                     buildtree(ASSIGNqp->n_right->n_right), r);
805         }
ragge
1.26
806         if (p->n_right->n_op == ASSIGN && p->n_right->n_left->n_op == REG) {
807                 if (p->n_left->n_op == CM &&
808                     p->n_left->n_right->n_op == STASG) {
809                         q = p->n_left->n_right;
810                         p->n_left->n_right = p->n_right;
811                         p->n_right = q;
812                         rv = 1;
813                 } else if (p->n_left->n_op == STASG) {
814                         q = p->n_left;
815                         p->n_left = p->n_right;
816                         p->n_right = q;
817                         rv = 1;
818                 }
819         }
820         return rv | argsort(p->n_left);
821 }
mickey
1.1
822
823 /*
824  * Called with a function call with arguments as argument.
825  * This is done early in buildtree() and only done once.
826  * Returns p.
827  */
828 NODE *
829 funcode(NODE *p)
830 {
ragge
1.8
831         NODE *l, *r;
mickey
1.1
832
ragge
1.9
833         nsse = ngpr = nrsp = 0;
ragge
1.17
834         /* Check if hidden arg needed */
835         /* If so, add it in pass2 */
836         if ((l = p->n_left)->n_type == INCREF(FTN)+STRTY ||
837             l->n_type == INCREF(FTN)+UNIONTY) {
ragge
1.23
838                 int ssz = tsize(BTYPE(l->n_type), l->n_dfl->n_ap);
ragge
1.17
839                 if (ssz > 2*SZLONG)
840                         ngpr++;
841         }
ragge
1.26
842
843         /* Convert just regs to assign insn's */
844         p->n_right = argput(p->n_right);
845
846         /* Must sort arglist so that STASG ends up first */
847         /* This avoids registers being clobbered */
848         while (argsort(p->n_right))
849                 ;
ragge
1.22
850         /* Check if there are varargs */
851         if (nsse || l->n_df == NULL || l->n_df->dfun == NULL) {
852                 ; /* Need RAX */
853         } else {
854                 union arglist *al = l->n_df->dfun;
855
856                 for (; al->type != TELLIPSISal++) {
857                         if (al->type == TNULL)
858                                 return p/* No need */
859                         if (BTYPE(al->type) == STRTY ||
860                             BTYPE(al->type) == UNIONTY ||
861                             ISARY(al->type))
862                                 al++;
863                 }
864         }
865
ragge
1.8
866         /* Always emit number of SSE regs used */
867         l = movtoreg(bcon(nsse), RAX);
868         if (p->n_right->n_op != CM) {
ragge
1.23
869                 p->n_right = block(CMlp->n_rightINT0MKAP(INT));
ragge
1.8
870         } else {
871                 for (r = p->n_rightr->n_left->n_op == CMr = r->n_left)
872                         ;
ragge
1.23
873                 r->n_left = block(CMlr->n_leftINT0MKAP(INT));
ragge
1.8
874         }
mickey
1.1
875         return p;
876 }
877
878 /*
879  * return the alignment of field of type t
880  */
881 int
882 fldal(unsigned int t)
883 {
884         uerror("illegal field type");
885         return(ALINT);
886 }
887
888 /* fix up type of field p */
889 void
890 fldty(struct symtab *p)
891 {
892 }
893
894 /*
895  * XXX - fix genswitch.
896  */
897 int
898 mygenswitch(int numTWORD typestruct swents **pint n)
899 {
900         return 0;
901 }
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 09:04 +0200