Quick Search:

View

Revision:
Expand:  
Changeset: MAIN:ragge:20140818151951

Diff

Diff from 1.76 to:

Annotations

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

Annotated File View

ragge
1.76
1 /*      $Id: code.c,v 1.76 2014/08/18 15:19:51 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.71
35 enum { INTEGER = 1INTMEMSSESSEMEMX87,
ragge
1.73
36         STRREGSTRMEMSTRSSESTRIFSTRFISTRX87 };
ragge
1.10
37 static const int argregsi[] = { RDIRSIRDXRCXR08R09 };
ragge
1.11
38 /*
39  * The Register Save Area looks something like this.
40  * It is put first on stack with fixed offsets.
41  * struct {
42  *      long regs[6];
43  *      double xmm[8][2]; // 16 byte in width
44  * };
45  */
46 #define RSASZ           (6*SZLONG+8*2*SZDOUBLE)
47 #define RSALONGOFF(x)   (RSASZ-(x)*SZLONG)
48 #define RSADBLOFF(x)    ((8*2*SZDOUBLE)-(x)*SZDOUBLE*2)
49 /* va_list */
50 #define VAARGSZ         (SZINT*2+SZPOINT(CHAR)*2)
51 #define VAGPOFF(x)      (x)
52 #define VAFPOFF(x)      (x-SZINT)
53 #define VAOFA(x)        (x-SZINT-SZINT)
54 #define VARSA(x)        (x-SZINT-SZINT-SZPOINT(0))
mickey
1.1
55
ragge
1.18
56 static int stroffset;
mickey
1.1
57
ragge
1.33
58 static int varneeds;
ragge
1.74
59 #define NEED_1FPREF      001
60 #define NEED_2FPREF      002
61 #define NEED_1REGREF     004
62 #define NEED_2REGREF     010
63 #define NEED_MEMREF      020
64 #define NEED_STRFI       040
65 #define NEED_STRIF      0100
ragge
1.33
66
ragge
1.23
67 static int argtyp(TWORD tunion dimfun *dfstruct attr *ap);
ragge
1.14
68 static NODE *movtomem(NODE *pint offint reg);
ragge
1.18
69 static NODE *movtoreg(NODE *pint rno);
ragge
1.48
70 void varattrib(char *namestruct attr *sap);
ragge
1.8
71
ragge
1.58
72 /*
73  * Print out assembler segment name.
74  */
ragge
1.70
75 #ifdef MACHOABI
76 void
77 setseg(int segchar *name)
78 {
79         switch (seg) {
80         case PROGname = ".text"break;
81         case DATA:
82         case LDATAname = ".data"break;
83         case RDATAname = ".const"break;
84         case STRNGname = ".cstring"break;
85         case UDATAbreak;
86         case CTORSname = ".mod_init_func"break;
87         case DTORSname = ".mod_term_func"break;
88         default:
89                 cerror("unknown seg %d"seg);
90         }
91         printf("\t%s\n"name);
92 }
93
94 #else
ragge
1.58
95 void
96 setseg(int segchar *name)
97 {
98         switch (seg) {
99         case PROGname = ".text"break;
100         case DATA:
101         case LDATAname = ".data"break;
102         case STRNG:
103         case RDATAname = ".section .rodata"break;
104         case UDATAbreak;
105         case PICLDATA:
106         case PICDATAname = ".section .data.rel.rw,\"aw\",@progbits"break;
107         case PICRDATAname = ".section .data.rel.ro,\"aw\",@progbits"break;
108         case TLSDATAname = ".section .tdata,\"awT\",@progbits"break;
109         case TLSUDATAname = ".section .tbss,\"awT\",@nobits"break;
110         case CTORSname = ".section\t.ctors,\"aw\",@progbits"break;
111         case DTORSname = ".section\t.dtors,\"aw\",@progbits"break;
112         case NMSEG
ragge
1.69
113                 printf("\t.section %s,\"a%c\",@progbits\n"name,
114                     cftnsp ? 'x' : 'w');
ragge
1.58
115                 return;
116         }
117         printf("\t%s\n"name);
118 }
ragge
1.70
119 #endif
ragge
1.52
120
mickey
1.1
121 /*
122  * Define everything needed to print out some data (or text).
123  * This means segment, alignment, visibility, etc.
124  */
125 void
126 defloc(struct symtab *sp)
127 {
ragge
1.18
128         char *name;
mickey
1.1
129
ragge
1.18
130         if ((name = sp->soname) == NULL)
131                 name = exname(sp->sname);
ragge
1.40
132
ragge
1.48
133         if (sp->sclass == EXTDEF) {
mickey
1.16
134                 printf("\t.globl %s\n"name);
ragge
1.44
135 #ifndef MACHOABI
ragge
1.68
136                 if (ISFTN(sp->stype)) {
137                         printf("\t.type %s,@function\n"name);
138                 } else {
139                         printf("\t.type %s,@object\n"name);
140                         printf("\t.size %s,%d\n"name,
141                             (int)tsize(sp->stypesp->sdfsp->sap)/SZCHAR);
142                 }
ragge
1.44
143 #endif
mickey
1.16
144         }
mickey
1.1
145         if (sp->slevel == 0)
ragge
1.6
146                 printf("%s:\n"name);
mickey
1.1
147         else
148                 printf(LABFMT ":\n"sp->soffset);
149 }
150
151 /*
152  * code for the end of a function
153  * deals with struct return here
ragge
1.38
154  * The return value is in (or pointed to by) RETREG.
mickey
1.1
155  */
156 void
plunky
1.64
157 efcode(void)
mickey
1.1
158 {
ragge
1.18
159         struct symtab *sp;
mickey
1.1
160         extern int gotnr;
ragge
1.18
161         TWORD t;
ragge
1.21
162         NODE *p, *r, *l;
ragge
1.71
163         int typ;
mickey
1.1
164
165         gotnr = 0;      /* new number for next fun */
ragge
1.18
166         sp = cftnsp;
167         t = DECREF(sp->stype);
ragge
1.21
168         if (t != STRTY && t != UNIONTY)
mickey
1.1
169                 return;
ragge
1.18
170
ragge
1.38
171         /* XXX should have one routine for this */
ragge
1.51
172         ngpr = nsse = 0;
ragge
1.71
173         typ = argtyp(tsp->sdfsp->sap);
174         if (typ == STRMEM) {
ragge
1.38
175                 r = block(REGNILNILINCREF(t), sp->sdfsp->sap);
176                 regno(r) = RAX;
177                 r = buildtree(UMULrNIL);
178                 l = tempnode(stroffsetINCREF(t), sp->sdfsp->sap);
179                 l = buildtree(UMULlNIL);
180                 ecomp(buildtree(ASSIGNlr));
ragge
1.50
181                 l = block(REGNILNILLONG00);
ragge
1.38
182                 regno(l) = RAX;
ragge
1.50
183                 r = tempnode(stroffsetLONG00);
ragge
1.38
184                 ecomp(buildtree(ASSIGNlr));
ragge
1.73
185         } else if (typ == STRX87) {
186                 p = block(REGNILNILINCREF(LDOUBLE), 00);
187                 regno(p) = RAX;
188                 p = buildtree(UMULbuildtree(PLUSpbcon(1)), NIL);
189                 ecomp(movtoreg(p041));
190                 p = block(REGNILNILINCREF(LDOUBLE), 00);
191                 regno(p) = RAX;
192                 p = buildtree(UMULpNIL);
193                 ecomp(movtoreg(p040));
ragge
1.71
194         } else {
195                 TWORD t1t2;
196                 int r1r2;
197                 if (typ == STRSSE || typ == STRFI)
198                         r1 = XMM0t1 = DOUBLE;
199                 else
200                         r1 = RAXt1 = LONG;
201                 if (typ == STRSSE || typ == STRIF)
202                         r2 = XMM1t2 = DOUBLE;
203                 else
204                         r2 = RDXt2 = LONG;
205
206                 if (tsize(tsp->sdfsp->sap) > SZLONG) {
207                         p = block(REGNILNILINCREF(t2), 00);
208                         regno(p) = RAX;
209                         p = buildtree(UMULbuildtree(PLUSpbcon(1)), NIL);
210                         ecomp(movtoreg(pr2));
211                 }
212                 p = block(REGNILNILINCREF(t1), 00);
213                 regno(p) = RAX;
214                 p = buildtree(UMULpNIL);
215                 ecomp(movtoreg(pr1));
216         }
mickey
1.1
217 }
218
219 /*
220  * code for the beginning of a function; a is an array of
221  * indices in symtab for the arguments; n is the number
222  */
223 void
ragge
1.8
224 bfcode(struct symtab **sint cnt)
mickey
1.1
225 {
ragge
1.11
226         union arglist *al;
ragge
1.8
227         struct symtab *sp;
228         NODE *p, *r;
ragge
1.37
229         TWORD t;
ragge
1.71
230         int irnotypssz;
mickey
1.1
231
232         /* recalculate the arg offset and create TEMP moves */
ragge
1.8
233         /* Always do this for reg, even if not optimizing, to free arg regs */
ragge
1.9
234         nsse = ngpr = 0;
235         nrsp = ARGINIT;
ragge
1.17
236         if (cftnsp->stype == STRTY+FTN || cftnsp->stype == UNIONTY+FTN) {
237                 sp = cftnsp;
ragge
1.23
238                 if (argtyp(DECREF(sp->stype), sp->sdfsp->sap) == STRMEM) {
ragge
1.50
239                         r = block(REGNILNILLONG00);
ragge
1.21
240                         regno(r) = argregsi[ngpr++];
ragge
1.23
241                         p = tempnode(0r->n_typer->n_dfr->n_ap);
ragge
1.18
242                         stroffset = regno(p);
243                         ecomp(buildtree(ASSIGNpr));
244                 }
ragge
1.17
245         }
246
ragge
1.8
247         for (i = 0i < cnti++) {
248                 sp = s[i];
249
250                 if (sp == NULL)
251                         continue/* XXX when happens this? */
252
ragge
1.71
253                 ssz = tsize(sp->stypesp->sdfsp->sap);
ragge
1.23
254                 switch (typ = argtyp(sp->stypesp->sdfsp->sap)) {
ragge
1.8
255                 case INTEGER:
256                 case SSE:
257                         if (typ == SSE)
258                                 rno = XMM0 + nsse++;
259                         else
260                                 rno = argregsi[ngpr++];
ragge
1.23
261                         r = block(REGNILNILsp->stypesp->sdfsp->sap);
ragge
1.8
262                         regno(r) = rno;
ragge
1.23
263                         p = tempnode(0sp->stypesp->sdfsp->sap);
ragge
1.8
264                         sp->soffset = regno(p);
265                         sp->sflags |= STNODE;
266                         ecomp(buildtree(ASSIGNpr));
267                         break;
ragge
1.9
268
ragge
1.30
269                 case SSEMEM:
270                         sp->soffset = nrsp;
271                         nrsp += SZDOUBLE;
272                         if (xtemps) {
273                                 p = tempnode(0sp->stypesp->sdfsp->sap);
274                                 p = buildtree(ASSIGNpnametree(sp));
275                                 sp->soffset = regno(p->n_left);
276                                 sp->sflags |= STNODE;
277                                 ecomp(p);
278                         }
279                         break;
280
ragge
1.9
281                 case INTMEM:
282                         sp->soffset = nrsp;
283                         nrsp += SZLONG;
284                         if (xtemps) {
ragge
1.23
285                                 p = tempnode(0sp->stypesp->sdfsp->sap);
ragge
1.9
286                                 p = buildtree(ASSIGNpnametree(sp));
287                                 sp->soffset = regno(p->n_left);
288                                 sp->sflags |= STNODE;
289                                 ecomp(p);
290                         }
291                         break;
292
ragge
1.73
293                 case STRX87:
ragge
1.17
294                 case STRMEM/* Struct in memory */
295                         sp->soffset = nrsp;
ragge
1.71
296                         nrsp += ssz;
ragge
1.17
297                         break;
298
ragge
1.31
299                 case X87/* long double args */
300                         sp->soffset = nrsp;
301                         nrsp += SZLDOUBLE;
302                         break;
303
ragge
1.71
304                 case STRFI:
305                 case STRIF:
306                 case STRSSE:
ragge
1.17
307                 case STRREG/* Struct in register */
308                         autooff += (2*SZLONG);
309
ragge
1.71
310                         if (typ == STRSSE || typ == STRFI) {
311                                 rno = XMM0 + nsse++;
ragge
1.46
312                                 t = DOUBLE;
313                         } else {
ragge
1.71
314                                 rno = argregsi[ngpr++];
ragge
1.46
315                                 t = LONG;
316                         }
ragge
1.50
317                         r = block(REGNILNILt00);
ragge
1.46
318                         regno(r) = rno;
ragge
1.17
319                         ecomp(movtomem(r, -autooffFPREG));
320
ragge
1.72
321                         if (ssz > SZLONG) {
ragge
1.71
322                                 if (typ == STRSSE || typ == STRIF) {
323                                         rno = XMM0 + nsse++;
324                                         t = DOUBLE;
325                                 } else {
326                                         rno = argregsi[ngpr++];
327                                         t = LONG;
328                                 }
ragge
1.50
329                                 r = block(REGNILNILt00);
ragge
1.71
330                                 regno(r) = rno;
ragge
1.17
331                                 ecomp(movtomem(r, -autooff+SZLONGFPREG));
332                         }
333                         sp->soffset = -autooff;
334                         break;
335
ragge
1.8
336                 default:
ragge
1.9
337                         cerror("bfcode: %d"typ);
mickey
1.1
338                 }
339         }
ragge
1.11
340
341         /* Check if there are varargs */
342         if (cftnsp->sdf == NULL || cftnsp->sdf->dfun == NULL)
343                 return/* no prototype */
344         al = cftnsp->sdf->dfun;
ragge
1.15
345
ragge
1.11
346         for (; al->type != TELLIPSISal++) {
ragge
1.37
347                 t = al->type;
348                 if (t == TNULL)
ragge
1.11
349                         return;
ragge
1.61
350                 if (ISSOU(BTYPE(t)))
ragge
1.11
351                         al++;
ragge
1.61
352                 for (i = 0t > BTMASKt = DECREF(t))
ragge
1.37
353                         if (ISARY(t) || ISFTN(t))
ragge
1.61
354                                 i++;
355                 if (i)
356                         al++;
ragge
1.11
357         }
358
359         /* fix stack offset */
360         SETOFF(autooffALMAX);
361
362         /* Save reg arguments in the reg save area */
363         p = NIL;
364         for (i = ngpri < 6i++) {
ragge
1.50
365                 r = block(REGNILNILLONG00);
ragge
1.11
366                 regno(r) = argregsi[i];
ragge
1.14
367                 r = movtomem(r, -RSALONGOFF(i)-autooffFPREG);
ragge
1.50
368                 p = (p == NIL ? r : block(COMOPprINT00));
ragge
1.11
369         }
370         for (i = nssei < 8i++) {
ragge
1.50
371                 r = block(REGNILNILDOUBLE00);
ragge
1.11
372                 regno(r) = i + XMM0;
ragge
1.14
373                 r = movtomem(r, -RSADBLOFF(i)-autooffFPREG);
ragge
1.50
374                 p = (p == NIL ? r : block(COMOPprINT00));
ragge
1.11
375         }
376         autooff += RSASZ;
377         rsaoff = autooff;
ragge
1.14
378         thissse = nsse;
379         thisgpr = ngpr;
380         thisrsp = nrsp;
ragge
1.11
381
382         ecomp(p);
mickey
1.1
383 }
384
385
386 /* called just before final exit */
387 /* flag is 1 if errors, 0 if none */
388 void
plunky
1.64
389 ejobcode(int flag)
mickey
1.1
390 {
ragge
1.33
391         if (flag)
392                 return;
393
plunky
1.63
394 #ifdef MACHOABI
ragge
1.44
395 #define PT(x)
396 #else
397 #define PT(x) printf(".type __pcc_" x ",@function\n")
398 #endif
399
ragge
1.74
400 #define P(x) printf(x "\n")
ragge
1.33
401         /* printout varargs routines if used */
ragge
1.74
402         if (varneeds & NEED_STRFI) {    /* struct with one float and then int */
403                 P(".text\n.align 4");
404                 PT("strif");
405                 P("__pcc_strif:");
406                 P("cmpl $176,4(%%rdi)\njae .Ladd16");
407                 P("cmpl $48,(%%rdi)\njae .Ladd16\n");
408                 P("movl 4(%%rdi),%%eax\naddq 16(%%rdi),%%rax");
409                 P("movq (%%rax),%%rdx\nmovq %%rdx,24(%%rdi)");
410                 P("movl (%%rdi),%%eax\naddq 16(%%rdi),%%rax");
411                 P("movq 16(%%rax),%%rdx\nmovq %%rdx,32(%%rdi)");
412                 P("leaq 24(%%rdi),%%rax\nret");
413         }
414         if (varneeds & NEED_STRIF) {    /* struct with one int and one float */
415                 P(".text\n.align 4");
416                 PT("strif");
417                 P("__pcc_strif:");
418                 P("cmpl $176,4(%%rdi)\njae .Ladd16");
419                 P("cmpl $48,(%%rdi)\njae .Ladd16\n");
420                 P("movl (%%rdi),%%eax\naddq 16(%%rdi),%%rax");
421                 P("movq (%%rax),%%rdx\nmovq %%rdx,24(%%rdi)");
422                 P("movl 4(%%rdi),%%eax\naddq 16(%%rdi),%%rax");
423                 P("movq 16(%%rax),%%rdx\nmovq %%rdx,32(%%rdi)");
424                 P("leaq 24(%%rdi),%%rax\nret");
425         }
426         if (varneeds & NEED_2FPREF) {   /* struct with two float regs */
427                 P(".text\n.align 4");
428                 PT("2fpref");
429                 P("__pcc_2fpref:");
430                 P("cmpl $160,4(%%rdi)\njae .Ladd16");
431                 P("movl 4(%%rdi),%%eax\naddq 16(%%rdi),%%rax");
432                 P("addl $32,4(%%rdi)");
433                 P("movq (%%rax),%%rdx\nmovq %%rdx,24(%%rdi)");
434                 P("movq 16(%%rax),%%rdx\nmovq %%rdx,32(%%rdi)");
435                 P("leaq 24(%%rdi),%%rax\nret");
ragge
1.33
436         }
ragge
1.74
437         if (varneeds & NEED_1FPREF) {
ragge
1.44
438                 printf(".text\n.align 4\n");
ragge
1.74
439                 PT("1fpref");
440                 printf("__pcc_1fpref:\n");
441                 printf("cmpl $176,4(%%rdi)\njae .Ladd8\n");
ragge
1.33
442                 printf("movl 4(%%rdi),%%eax\naddq 16(%%rdi),%%rax\n");
ragge
1.74
443                 printf("addl $16,4(%%rdi)\nret\n");
ragge
1.33
444         }
445         if (varneeds & NEED_1REGREF) {
ragge
1.44
446                 printf(".text\n.align 4\n");
447                 PT("1regref");
ragge
1.33
448                 printf("__pcc_1regref:\n");
ragge
1.74
449                 printf("cmpl $48,(%%rdi)\njae .Ladd8\n");
ragge
1.33
450                 printf("movl (%%rdi),%%eax\naddq 16(%%rdi),%%rax\n");
451                 printf("addl $8,(%%rdi)\nret\n");
452         }
453         if (varneeds & NEED_2REGREF) {
ragge
1.44
454                 printf(".text\n.align 4\n");
455                 PT("2regref");
ragge
1.33
456                 printf("__pcc_2regref:\n");
ragge
1.74
457                 printf("cmpl $40,(%%rdi)\njae .Ladd16\n");
ragge
1.33
458                 printf("movl (%%rdi),%%eax\naddq 16(%%rdi),%%rax\n");
459                 printf("addl $16,(%%rdi)\nret\n");
460         }
461         if (varneeds & NEED_MEMREF) {
ragge
1.44
462                 printf(".text\n.align 4\n");
463                 PT("memref");
ragge
1.33
464                 printf("__pcc_memref:\n");
465                 printf("movq 8(%%rdi),%%rax\n");
466                 printf("addq %%rsi,8(%%rdi)\nret\n");
467         }
ragge
1.74
468
469         if (varneeds & (NEED_1FPREF|NEED_1REGREF)) {
470                 P(".Ladd8:");
471                 P("movq 8(%%rdi),%%rax");
472                 P("addq $8,8(%%rdi)");
473                 P("ret");
474         }
475         if (varneeds & (NEED_2FPREF|NEED_2REGREF|NEED_STRFI|NEED_STRIF)) {
476                 P(".Ladd16:");
477                 P("movq 8(%%rdi),%%rax");
478                 P("addq $16,8(%%rdi)");
479                 P("ret");
480         }
ragge
1.33
481
ragge
1.44
482 #ifdef MACHOABI
plunky
1.55
483         printf("\t.ident \"PCC: %s\"\n"VERSSTR);
ragge
1.44
484 #else
plunky
1.55
485         printf("\t.ident \"PCC: %s\"\n\t.end\n"VERSSTR);
ragge
1.44
486 #endif
mickey
1.1
487 }
488
ragge
1.11
489 /*
490  * Varargs stuff:
491  * The ABI says that va_list should be declared as this typedef.
492  * We handcraft it here and then just reference it.
493  *
494  * typedef struct {
495  *      unsigned int gp_offset;
496  *      unsigned int fp_offset;
497  *      void *overflow_arg_area;
498  *      void *reg_save_area;
499  * } __builtin_va_list[1];
ragge
1.33
500  *
ragge
1.74
501  * ...actually, we allocate two of them and use the second one as 
502  * bounce buffers for floating point structs...
503  *
ragge
1.33
504  * There are a number of asm routines printed out if varargs are used:
505  *      long __pcc_gpnext(va)   - get a gpreg value
506  *      long __pcc_fpnext(va)   - get a fpreg value
507  *      void *__pcc_1regref(va) - get reference to a onereg struct 
508  *      void *__pcc_2regref(va) - get reference to a tworeg struct 
509  *      void *__pcc_memref(va,sz)       - get reference to a large struct 
ragge
1.11
510  */
ragge
1.13
511
ragge
1.11
512 static char *gp_offset, *fp_offset, *overflow_arg_area, *reg_save_area;
ragge
1.74
513 static char *_1fpref, *_2fpref, *_1regref, *_2regref, *memref;
514 static char *strif, *strfi;
ragge
1.13
515
mickey
1.1
516 void
plunky
1.64
517 bjobcode(void)
mickey
1.1
518 {
ragge
1.33
519         struct symtab *sp;
ragge
1.11
520         struct rstack *rp;
521         NODE *p, *q;
522         char *c;
523
ragge
1.57
524         /* amd64 names for some asm constant printouts */
525         astypnames[INT] = astypnames[UNSIGNED] = "\t.long";
526         astypnames[LONG] = astypnames[ULONG] = "\t.quad";
527
ragge
1.11
528         gp_offset = addname("gp_offset");
529         fp_offset = addname("fp_offset");
530         overflow_arg_area = addname("overflow_arg_area");
531         reg_save_area = addname("reg_save_area");
532
533         rp = bstruct(NULLSTNAMENULL);
ragge
1.50
534         p = block(NAMENILNILUNSIGNED00);
ragge
1.11
535         soumemb(pgp_offset0);
536         soumemb(pfp_offset0);
537         p->n_type = VOID+PTR;
ragge
1.50
538         p->n_ap = NULL;
ragge
1.11
539         soumemb(poverflow_arg_area0);
540         soumemb(preg_save_area0);
541         nfree(p);
542         q = dclstruct(rp);
543         c = addname("__builtin_va_list");
ragge
1.74
544         p = block(LBbdty(NAMEc), bcon(2), INT00);
ragge
1.11
545         p = tymerge(qp);
546         p->n_sp = lookup(c0);
547         defid(pTYPEDEF);
548         nfree(q);
549         nfree(p);
ragge
1.33
550
551         /* for the static varargs functions */
ragge
1.74
552 #define MKN(vn, rn) \
ragge
1.33
553         { vn = addname(rn); sp = lookup(vnSNORMAL); \
ragge
1.74
554           sp->sclass = USTATICsp->stype = FTN|VOID|(PTR<<TSHIFT); }
ragge
1.33
555
ragge
1.74
556         MKN(strfi"__pcc_strfi");
557         MKN(strif"__pcc_strif");
558         MKN(_1fpref"__pcc_1fpref");
559         MKN(_2fpref"__pcc_2fpref");
560         MKN(_1regref"__pcc_1regref");
561         MKN(_2regref"__pcc_2regref");
562         MKN(memref"__pcc_memref");
ragge
1.11
563 }
564
565 static NODE *
566 mkstkref(int offTWORD typ)
567 {
568         NODE *p;
569
ragge
1.50
570         p = block(REGNILNILPTR|typ00);
ragge
1.11
571         regno(p) = FPREG;
572         return buildtree(PLUSpbcon(off/SZCHAR));
573 }
574
575 NODE *
ragge
1.65
576 amd64_builtin_stdarg_start(const struct bitable *btNODE *a)
ragge
1.11
577 {
578         NODE *p, *r;
579
580         /* use the values from the function header */
581         p = a->n_left;
582         r = buildtree(ASSIGNstructref(ccopy(p), STREFreg_save_area),
583             mkstkref(-rsaoffVOID));
584         r = buildtree(COMOPr,
585             buildtree(ASSIGNstructref(ccopy(p), STREFoverflow_arg_area),
ragge
1.14
586             mkstkref(thisrspVOID)));
ragge
1.11
587         r = buildtree(COMOPr,
588             buildtree(ASSIGNstructref(ccopy(p), STREFgp_offset),
ragge
1.14
589             bcon(thisgpr*(SZLONG/SZCHAR))));
ragge
1.11
590         r = buildtree(COMOPr,
591             buildtree(ASSIGNstructref(ccopy(p), STREFfp_offset),
ragge
1.14
592             bcon(thissse*(SZDOUBLE*2/SZCHAR)+48)));
ragge
1.11
593
594         tfree(a);
595         return r;
mickey
1.1
596 }
597
ragge
1.74
598 static NODE *
599 mkvacall(char *funNODE *aint typ)
600 {
601         NODE *r, *f = block(NAMENILNILINT00);
602         NODE *ap = a->n_left;
603         NODE *dp = a->n_right;
604         int sz = tsize(dp->n_typedp->n_dfdp->n_ap);
605
606         f->n_sp = lookup(funSNORMAL);
607         varneeds |= typ;
608         f->n_type = f->n_sp->stype;
609         f = clocal(f);
610         SETOFF(szALLONG);
611         r = buildtree(CALLf,
612             buildtree(CMccopy(ap), bcon(sz/SZCHAR)));
613         r = ccast(rINCREF(dp->n_type), 0dp->n_dfdp->n_ap);
614         r = buildtree(UMULrNIL);
615         return r;
616 }
617
ragge
1.11
618 NODE *
ragge
1.65
619 amd64_builtin_va_arg(const struct bitable *btNODE *a)
ragge
1.12
620 {
plunky
1.75
621         NODE *r, *dp;
ragge
1.74
622         int typsz;
ragge
1.12
623
ragge
1.29
624         dp = a->n_right;
ragge
1.74
625
626         nsse = ngpr = 0;
627         sz = tsize(dp->n_typedp->n_dfdp->n_ap);
628         switch (typ = argtyp(dp->n_typedp->n_dfdp->n_ap)) {
629         case INTEGER:
630                 r = mkvacall(_1regrefaNEED_1REGREF);
631                 break;
632
633         case SSE:
634                 r = mkvacall(_1fprefaNEED_1FPREF);
635                 break;
636
637         default:
638                 cerror("va_arg: bad type %d"typ);
639
640         case X87:
641         case STRX87:
642         case STRMEM/* stored in memory */
643                 r = mkvacall(memrefaNEED_MEMREF);
644                 break;
645
646         case STRREG/* struct in general regs */
647                 if (sz <= SZLONG)
648                         r = mkvacall(_1regrefaNEED_1REGREF);
649                 else
650                         r = mkvacall(_2regrefaNEED_2REGREF);
651                 break;
652
653         case STRSSE:
654                 if (sz <= SZLONG)
655                         r = mkvacall(_1fprefaNEED_1FPREF);
656                 else
657                         r = mkvacall(_2fprefaNEED_2FPREF);
658                 break;
659
660         case STRIF:
661                 r = mkvacall(strifaNEED_STRIF);
662                 break;
663
664         case STRFI:
665                 r = mkvacall(strfiaNEED_STRFI);
666                 break;
ragge
1.12
667         }
ragge
1.74
668
ragge
1.12
669         tfree(a);
670         return r;
671 }
ragge
1.11
672
673 NODE *
ragge
1.65
674 amd64_builtin_va_end(const struct bitable *btNODE *a)
ragge
1.13
675 {
676         tfree(a);
677         return bcon(0); /* nothing */
678 }
ragge
1.11
679
680 NODE *
ragge
1.65
681 amd64_builtin_va_copy(const struct bitable *btNODE *a)
ragge
1.33
682 {
ragge
1.65
683         NODE *f;
684
ragge
1.33
685         f = buildtree(ASSIGNbuildtree(UMULa->n_leftNIL),
686             buildtree(UMULa->n_rightNIL));
687         nfree(a);
688         return f;
689 }
ragge
1.11
690
ragge
1.7
691 static NODE *
692 movtoreg(NODE *pint rno)
mickey
1.1
693 {
694         NODE *r;
695
ragge
1.23
696         r = block(REGNILNILp->n_typep->n_dfp->n_ap);
ragge
1.7
697         regno(r) = rno;
698         return clocal(buildtree(ASSIGNrp));
699 }  
700
ragge
1.9
701 static NODE *
ragge
1.14
702 movtomem(NODE *pint offint reg)
ragge
1.9
703 {
704         struct symtab s;
705         NODE *r, *l;
706
707         s.stype = p->n_type;
ragge
1.25
708         s.squal = 0;
ragge
1.9
709         s.sdf = p->n_df;
ragge
1.23
710         s.sap = p->n_ap;
ragge
1.9
711         s.soffset = off;
ragge
1.11
712         s.sclass = AUTO;
ragge
1.9
713
714         l = block(REGNILNILPTR+STRTY00);
715         l->n_lval = 0;
ragge
1.14
716         regno(l) = reg;
ragge
1.9
717
ragge
1.23
718         r = block(NAMENILNILp->n_typep->n_dfp->n_ap);
ragge
1.9
719         r->n_sp = &s;
720         r = stref(block(STREFlr000));
721
722         return clocal(buildtree(ASSIGNrp));
723 }  
724
ragge
1.71
725 /*
726  * Check what to do with a struct.  We traverse down in the struct to 
727  * find which types it is and where the struct really should be.
728  * The return vals we may end up with are:
729  *      STRREG - The whole struct is saved in general registers.
730  *      STRMEM - the struct is saved in memory.
731  *      STRSSE - the whole struct is saved in SSE registers.
732  *      STRIF  - First word of struct is saved in general reg, other SSE.
733  *      STRFI  - First word of struct is saved in SSE, next in general reg.
734  *
735  * - If size > 16 bytes or there are packed fields, use memory.
736  * - If any part of an eight-byte should be in a general register,
737  *    the eight-byte is stored in a general register
738  * - If the eight-byte only contains float or double, use a SSE register
739  * - Otherwise use memory.
740  *
741  * sp below is a pointer to a member list.
742  * off tells whether is is the first or second eight-byte to check.
743  */
744 static int
745 classifystruct(struct symtab *spint off)
746 {
747         TWORD t;
748         int clcl2;
749
750         for (cl = 0spsp = sp->snext) {
751                 t = sp->stype;
752
753                 if (off == 0) {
754                         if (sp->soffset >= SZLONG)
755                                 continue;
756                 } else {
757                         if (sp->soffset < SZLONG)
758                                 continue;
759                 }
760
761                 if (t <= ULONGLONG || ISPTR(t)) {
762                         if (cl == 0 || cl == STRSSE)
763                                 cl = STRREG;
764                 } else if (t <= DOUBLE) {
765                         if (cl == 0)
766                                 cl = STRSSE;
767                 } else if (t == LDOUBLE) {
768                         return STRMEM;
769                 } else if (ISSOU(t)) {
ragge
1.76
770 #ifdef GCC_COMPAT
ragge
1.71
771                         if (attr_find(sp->sapGCC_ATYP_PACKED)) {
772                                 cl = STRMEM;
ragge
1.76
773                         } else
774 #endif
775                         {
ragge
1.71
776                                 cl2 = classifystruct(strmemb(sp->sap), off);
777                                 if (cl2 == STRMEM) {
778                                         cl = STRMEM;
779                                 } else if (cl2 == STRREG) {
780                                         if (cl == 0 || cl == STRSSE)
781                                                 cl = STRREG;
782                                 } else if (cl2 == STRSSE) {
783                                         if (cl == 0)
784                                                 cl = STRSSE;
785                                 }
786                         }
787                 } else
788                         cerror("classifystruct: unknown type %x"t);
789                 if (cl == STRMEM)
790                         break;
791         }
792         if (cl == 0)
793                 cerror("classifystruct: failed classify");
794         return cl;
795 }
796
ragge
1.73
797 /*
798  * Check for long double complex structs.
799  */
800 static int
801 iscplx87(struct symtab *sp)
802 {
803         if (sp->stype == LDOUBLE && sp->snext->stype == LDOUBLE &&
804             sp->snext->snext == NULL)
805                 return STRX87;
806         return 0;
807 }
ragge
1.7
808
809 /*
810  * AMD64 parameter classification.
811  */
812 static int
ragge
1.23
813 argtyp(TWORD tunion dimfun *dfstruct attr *ap)
ragge
1.7
814 {
ragge
1.71
815         int cl2cl = 0;
ragge
1.7
816
ragge
1.41
817         if (t <= ULONG || ISPTR(t) || t == BOOL) {
ragge
1.7
818                 cl = ngpr < 6 ? INTEGER : INTMEM;
ragge
1.47
819         } else if (t == FLOAT || t == DOUBLE || t == FIMAG || t == IMAG) {
ragge
1.8
820                 cl = nsse < 8 ? SSE : SSEMEM;
ragge
1.47
821         } else if (t == LDOUBLE || t == LIMAG) {
ragge
1.7
822                 cl = X87/* XXX */
ragge
1.26
823         } else if (t == STRTY || t == UNIONTY) {
ragge
1.32
824                 int sz = tsize(tdfap);
825
ragge
1.76
826 #ifdef GCC_COMPAT
ragge
1.73
827                 if (attr_find(apGCC_ATYP_PACKED)) {
828                         cl = STRMEM;
ragge
1.76
829                 } else
830 #endif
831                 if (iscplx87(strmemb(ap)) == STRX87) {
ragge
1.73
832                         cl = STRX87;
833                 } else if (sz > 2*SZLONG) {
ragge
1.7
834                         cl = STRMEM;
ragge
1.71
835                 } else if (sz <= SZLONG) {
836                         /* only one member to check */
837                         cl = classifystruct(strmemb(ap), 0);
838                         if (cl == STRREG && ngpr > 5)
839                                 cl = STRMEM;
840                         else if (cl == STRSSE && nsse > 7)
841                                 cl = STRMEM;
842                 } else {
843                         cl = classifystruct(strmemb(ap), 0);
844                         cl2 = classifystruct(strmemb(ap), 1);
845                         if (cl == STRMEM || cl2 == STRMEM)
846                                 cl = STRMEM;
847                         else if (cl == STRREG && cl2 == STRSSE)
848                                 cl = STRIF;
849                         else if (cl2 == STRREG && cl == STRSSE)
850                                 cl = STRFI;
851
852                         if (cl == STRREG && ngpr > 4)
853                                 cl = STRMEM;
854                         else if (cl == STRSSE && nsse > 6)
855                                 cl = STRMEM;
856                         else if ((cl == STRIF || cl == STRFI) &&
857                             (ngpr > 5 || nsse > 7))
858                                 cl = STRMEM;
859                 }
ragge
1.7
860         } else
861                 cerror("FIXME: classify");
862         return cl;
863 }
864
ragge
1.42
865 /*
866  * Do the "hard work" in assigning correct destination for arguments.
867  * Also convert arguments < INT to inte (default argument promotions).
868  * XXX - should be dome elsewhere.
869  */
ragge
1.26
870 static NODE *
ragge
1.7
871 argput(NODE *p)
872 {
ragge
1.71
873         NODE *q, *ql;
ragge
1.46
874         TWORD ty;
ragge
1.71
875         int typrsszrn;
mickey
1.1
876
ragge
1.26
877         if (p->n_op == CM) {
878                 p->n_left = argput(p->n_left);
879                 p->n_right = argput(p->n_right);
880                 return p;
881         }
882
ragge
1.7
883         /* first arg may be struct return pointer */
884         /* XXX - check if varargs; setup al */
ragge
1.23
885         switch (typ = argtyp(p->n_typep->n_dfp->n_ap)) {
ragge
1.7
886         case INTEGER:
887         case SSE:
888                 if (typ == SSE)
889                         r = XMM0 + nsse++;
890                 else
891                         r = argregsi[ngpr++];
ragge
1.43
892                 if (p->n_type < INT || p->n_type == BOOL)
ragge
1.42
893                         p = cast(pINT0);
ragge
1.26
894                 p = movtoreg(pr);
ragge
1.7
895                 break;
ragge
1.26
896
ragge
1.7
897         case X87:
ragge
1.25
898                 r = nrsp;
899                 nrsp += SZLDOUBLE;
ragge
1.26
900                 p = movtomem(prSTKREG);
ragge
1.7
901                 break;
ragge
1.9
902
ragge
1.30
903         case SSEMEM:
904                 r = nrsp;
905                 nrsp += SZDOUBLE;
906                 p = movtomem(prSTKREG);
907                 break;
908
ragge
1.9
909         case INTMEM:
910                 r = nrsp;
911                 nrsp += SZLONG;
ragge
1.26
912                 p = movtomem(prSTKREG);
ragge
1.9
913                 break;
914
ragge
1.71
915         case STRFI:
916         case STRIF:
917         case STRSSE:
ragge
1.17
918         case STRREG/* Struct in registers */
ragge
1.71
919                 /* Cast to long/sse pointer and move to the registers */
ragge
1.27
920                 /* XXX can overrun struct size */
ragge
1.23
921                 ssz = tsize(p->n_typep->n_dfp->n_ap);
ragge
1.17
922
ragge
1.71
923                 if (typ == STRSSE || typ == STRFI) {
924                         r = XMM0 + nsse++;
ragge
1.46
925                         ty = DOUBLE;
926                 } else {
ragge
1.71
927                         r = argregsi[ngpr++];
ragge
1.46
928                         ty = LONG;
929                 }
ragge
1.33
930
ragge
1.71
931                 p = nfree(p);   /* remove STARG */
932                 p = makety(pPTR|ty000);
933                 ql = tempnode(0PTR|ty00);
934                 rn = regno(ql);
935                 p = buildtree(ASSIGNqlp);
936                 ql = tempnode(rnPTR|ty00);
937                 ql = movtoreg(buildtree(UMULqlNIL), r);
938                 p = buildtree(COMOPpql);
ragge
1.60
939
ragge
1.71
940                 if (ssz > SZLONG) {
941                         if (typ == STRSSE || typ == STRIF) {
942                                 r = XMM0 + nsse++;
943                                 ty = DOUBLE;
944                         } else {
945                                 r = argregsi[ngpr++];
946                                 ty = LONG;
947                         }
948
949                         ql = tempnode(rnPTR|ty00);
950                         ql = buildtree(UMULbuildtree(PLUSqlbcon(1)), NIL);
ragge
1.46
951                         ql = movtoreg(qlr);
ragge
1.17
952
ragge
1.66
953                         p = buildtree(CMpql);
ragge
1.71
954                 }
ragge
1.17
955                 break;
956
ragge
1.73
957         case STRX87:
ragge
1.26
958         case STRMEM: {
959                 struct symtab s;
960                 NODE *l, *t;
961
962                 q = buildtree(UMULp->n_leftNIL);