Quick Search:

View

Revision:
Expand:  
Changeset: MAIN:ragge:20110419171902

Diff

Diff from 1.52 to:

Annotations

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

Annotated File View

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