Quick Search:

View

Revision:
Expand:  
Changeset: MAIN:ragge:20110604074111

Diff

Diff from 1.56 to:

Annotations

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

Annotated File View

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