Quick Search:

View

Revision:
Expand:  
Changeset: MAIN:plunky:20110927081045

Diff

Diff from 1.63 to:

Annotations

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

Annotated File View

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