Quick Search:

View

Revision:
Expand:  
Changeset: MAIN:ragge:20121228160312

Diff

Diff from 1.68 to:

Annotations

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

Annotated File View

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