Quick Search:

View

Revision:
Expand:  
Changeset: MAIN:ragge:20101226172603

Diff

Diff from 1.47 to:

Annotations

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

Annotated File View

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