Quick Search:

View

Revision:
Expand:  
Changeset: MAIN:ragge:20110410183601

Diff

Diff from 1.51 to:

Annotations

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

Annotated File View

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