Quick Search:

View

Revision:
Expand:  
Changeset: MAIN:ragge:20101127211247

Diff

Diff from 1.42 to:

Annotations

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

Annotated File View

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