Quick Search:

View

Revision:
Expand:  
Changeset: MAIN:ragge:20160715203101

Diff

Diff from 1.86 to:

Annotations

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

Annotated File View

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