Quick Search:

View

Revision:
Expand:  
Changeset: MAIN:ragge:20110623133823

Diff

Diff from 1.58 to:

Annotations

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

Annotated File View

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