Quick Search:

View

Revision:
Expand:  
Changeset: MAIN:ragge:20140928125131

Diff

Diff from 1.80 to:

Annotations

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

Annotated File View

ragge
1.80
1 /*      $Id: code.c,v 1.80 2014/09/28 12:51:31 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;
ragge
1.77
201                 if (typ == STRSSE)
ragge
1.71
202                         r2 = XMM1t2 = DOUBLE;
ragge
1.77
203                 else if (typ == STRFI)
204                         r2 = RAXt2 = LONG;
205                 else if (typ == STRIF)
206                         r2 = XMM0t2 = DOUBLE;
207                 else /* if (typ == STRREG) */
ragge
1.71
208                         r2 = RDXt2 = LONG;
209
210                 if (tsize(tsp->sdfsp->sap) > SZLONG) {
211                         p = block(REGNILNILINCREF(t2), 00);
212                         regno(p) = RAX;
213                         p = buildtree(UMULbuildtree(PLUSpbcon(1)), NIL);
214                         ecomp(movtoreg(pr2));
215                 }
216                 p = block(REGNILNILINCREF(t1), 00);
217                 regno(p) = RAX;
218                 p = buildtree(UMULpNIL);
219                 ecomp(movtoreg(pr1));
220         }
mickey
1.1
221 }
222
223 /*
224  * code for the beginning of a function; a is an array of
225  * indices in symtab for the arguments; n is the number
226  */
227 void
ragge
1.8
228 bfcode(struct symtab **sint cnt)
mickey
1.1
229 {
ragge
1.11
230         union arglist *al;
ragge
1.8
231         struct symtab *sp;
232         NODE *p, *r;
ragge
1.37
233         TWORD t;
ragge
1.71
234         int irnotypssz;
mickey
1.1
235
236         /* recalculate the arg offset and create TEMP moves */
ragge
1.8
237         /* Always do this for reg, even if not optimizing, to free arg regs */
ragge
1.9
238         nsse = ngpr = 0;
239         nrsp = ARGINIT;
ragge
1.17
240         if (cftnsp->stype == STRTY+FTN || cftnsp->stype == UNIONTY+FTN) {
241                 sp = cftnsp;
ragge
1.23
242                 if (argtyp(DECREF(sp->stype), sp->sdfsp->sap) == STRMEM) {
ragge
1.50
243                         r = block(REGNILNILLONG00);
ragge
1.21
244                         regno(r) = argregsi[ngpr++];
ragge
1.23
245                         p = tempnode(0r->n_typer->n_dfr->n_ap);
ragge
1.18
246                         stroffset = regno(p);
247                         ecomp(buildtree(ASSIGNpr));
248                 }
ragge
1.17
249         }
250
ragge
1.8
251         for (i = 0i < cnti++) {
252                 sp = s[i];
253
254                 if (sp == NULL)
255                         continue/* XXX when happens this? */
256
ragge
1.71
257                 ssz = tsize(sp->stypesp->sdfsp->sap);
ragge
1.23
258                 switch (typ = argtyp(sp->stypesp->sdfsp->sap)) {
ragge
1.8
259                 case INTEGER:
260                 case SSE:
261                         if (typ == SSE)
262                                 rno = XMM0 + nsse++;
263                         else
264                                 rno = argregsi[ngpr++];
ragge
1.23
265                         r = block(REGNILNILsp->stypesp->sdfsp->sap);
ragge
1.8
266                         regno(r) = rno;
ragge
1.23
267                         p = tempnode(0sp->stypesp->sdfsp->sap);
ragge
1.8
268                         sp->soffset = regno(p);
269                         sp->sflags |= STNODE;
270                         ecomp(buildtree(ASSIGNpr));
271                         break;
ragge
1.9
272
ragge
1.30
273                 case SSEMEM:
274                         sp->soffset = nrsp;
275                         nrsp += SZDOUBLE;
276                         if (xtemps) {
277                                 p = tempnode(0sp->stypesp->sdfsp->sap);
278                                 p = buildtree(ASSIGNpnametree(sp));
279                                 sp->soffset = regno(p->n_left);
280                                 sp->sflags |= STNODE;
281                                 ecomp(p);
282                         }
283                         break;
284
ragge
1.9
285                 case INTMEM:
286                         sp->soffset = nrsp;
287                         nrsp += SZLONG;
288                         if (xtemps) {
ragge
1.23
289                                 p = tempnode(0sp->stypesp->sdfsp->sap);
ragge
1.9
290                                 p = buildtree(ASSIGNpnametree(sp));
291                                 sp->soffset = regno(p->n_left);
292                                 sp->sflags |= STNODE;
293                                 ecomp(p);
294                         }
295                         break;
296
ragge
1.73
297                 case STRX87:
ragge
1.17
298                 case STRMEM/* Struct in memory */
299                         sp->soffset = nrsp;
ragge
1.71
300                         nrsp += ssz;
ragge
1.17
301                         break;
302
ragge
1.31
303                 case X87/* long double args */
304                         sp->soffset = nrsp;
305                         nrsp += SZLDOUBLE;
306                         break;
307
ragge
1.71
308                 case STRFI:
309                 case STRIF:
310                 case STRSSE:
ragge
1.17
311                 case STRREG/* Struct in register */
312                         autooff += (2*SZLONG);
313
ragge
1.71
314                         if (typ == STRSSE || typ == STRFI) {
315                                 rno = XMM0 + nsse++;
ragge
1.46
316                                 t = DOUBLE;
317                         } else {
ragge
1.71
318                                 rno = argregsi[ngpr++];
ragge
1.46
319                                 t = LONG;
320                         }
ragge
1.50
321                         r = block(REGNILNILt00);
ragge
1.46
322                         regno(r) = rno;
ragge
1.17
323                         ecomp(movtomem(r, -autooffFPREG));
324
ragge
1.72
325                         if (ssz > SZLONG) {
ragge
1.71
326                                 if (typ == STRSSE || typ == STRIF) {
327                                         rno = XMM0 + nsse++;
328                                         t = DOUBLE;
329                                 } else {
330                                         rno = argregsi[ngpr++];
331                                         t = LONG;
332                                 }
ragge
1.50
333                                 r = block(REGNILNILt00);
ragge
1.71
334                                 regno(r) = rno;
ragge
1.17
335                                 ecomp(movtomem(r, -autooff+SZLONGFPREG));
336                         }
337                         sp->soffset = -autooff;
338                         break;
339
ragge
1.8
340                 default:
ragge
1.9
341                         cerror("bfcode: %d"typ);
mickey
1.1
342                 }
343         }
ragge
1.11
344
345         /* Check if there are varargs */
346         if (cftnsp->sdf == NULL || cftnsp->sdf->dfun == NULL)
347                 return/* no prototype */
348         al = cftnsp->sdf->dfun;
ragge
1.15
349
ragge
1.11
350         for (; al->type != TELLIPSISal++) {
ragge
1.37
351                 t = al->type;
352                 if (t == TNULL)
ragge
1.11
353                         return;
ragge
1.61
354                 if (ISSOU(BTYPE(t)))
ragge
1.11
355                         al++;
ragge
1.61
356                 for (i = 0t > BTMASKt = DECREF(t))
ragge
1.37
357                         if (ISARY(t) || ISFTN(t))
ragge
1.61
358                                 i++;
359                 if (i)
360                         al++;
ragge
1.11
361         }
362
363         /* fix stack offset */
364         SETOFF(autooffALMAX);
365
366         /* Save reg arguments in the reg save area */
367         p = NIL;
368         for (i = ngpri < 6i++) {
ragge
1.50
369                 r = block(REGNILNILLONG00);
ragge
1.11
370                 regno(r) = argregsi[i];
ragge
1.14
371                 r = movtomem(r, -RSALONGOFF(i)-autooffFPREG);
ragge
1.50
372                 p = (p == NIL ? r : block(COMOPprINT00));
ragge
1.11
373         }
374         for (i = nssei < 8i++) {
ragge
1.50
375                 r = block(REGNILNILDOUBLE00);
ragge
1.11
376                 regno(r) = i + XMM0;
ragge
1.14
377                 r = movtomem(r, -RSADBLOFF(i)-autooffFPREG);
ragge
1.50
378                 p = (p == NIL ? r : block(COMOPprINT00));
ragge
1.11
379         }
380         autooff += RSASZ;
381         rsaoff = autooff;
ragge
1.14
382         thissse = nsse;
383         thisgpr = ngpr;
384         thisrsp = nrsp;
ragge
1.11
385
386         ecomp(p);
mickey
1.1
387 }
388
389
390 /* called just before final exit */
391 /* flag is 1 if errors, 0 if none */
392 void
plunky
1.64
393 ejobcode(int flag)
mickey
1.1
394 {
ragge
1.33
395         if (flag)
396                 return;
397
plunky
1.63
398 #ifdef MACHOABI
ragge
1.44
399 #define PT(x)
400 #else
401 #define PT(x) printf(".type __pcc_" x ",@function\n")
402 #endif
403
ragge
1.74
404 #define P(x) printf(x "\n")
ragge
1.33
405         /* printout varargs routines if used */
ragge
1.74
406         if (varneeds & NEED_STRFI) {    /* struct with one float and then int */
407                 P(".text\n.align 4");
408                 PT("strif");
409                 P("__pcc_strif:");
410                 P("cmpl $176,4(%%rdi)\njae .Ladd16");
411                 P("cmpl $48,(%%rdi)\njae .Ladd16\n");
412                 P("movl 4(%%rdi),%%eax\naddq 16(%%rdi),%%rax");
413                 P("movq (%%rax),%%rdx\nmovq %%rdx,24(%%rdi)");
414                 P("movl (%%rdi),%%eax\naddq 16(%%rdi),%%rax");
415                 P("movq 16(%%rax),%%rdx\nmovq %%rdx,32(%%rdi)");
416                 P("leaq 24(%%rdi),%%rax\nret");
417         }
418         if (varneeds & NEED_STRIF) {    /* struct with one int and one float */
419                 P(".text\n.align 4");
420                 PT("strif");
421                 P("__pcc_strif:");
422                 P("cmpl $176,4(%%rdi)\njae .Ladd16");
423                 P("cmpl $48,(%%rdi)\njae .Ladd16\n");
424                 P("movl (%%rdi),%%eax\naddq 16(%%rdi),%%rax");
425                 P("movq (%%rax),%%rdx\nmovq %%rdx,24(%%rdi)");
426                 P("movl 4(%%rdi),%%eax\naddq 16(%%rdi),%%rax");
427                 P("movq 16(%%rax),%%rdx\nmovq %%rdx,32(%%rdi)");
428                 P("leaq 24(%%rdi),%%rax\nret");
429         }
430         if (varneeds & NEED_2FPREF) {   /* struct with two float regs */
431                 P(".text\n.align 4");
432                 PT("2fpref");
433                 P("__pcc_2fpref:");
434                 P("cmpl $160,4(%%rdi)\njae .Ladd16");
435                 P("movl 4(%%rdi),%%eax\naddq 16(%%rdi),%%rax");
436                 P("addl $32,4(%%rdi)");
437                 P("movq (%%rax),%%rdx\nmovq %%rdx,24(%%rdi)");
438                 P("movq 16(%%rax),%%rdx\nmovq %%rdx,32(%%rdi)");
439                 P("leaq 24(%%rdi),%%rax\nret");
ragge
1.33
440         }
ragge
1.74
441         if (varneeds & NEED_1FPREF) {
ragge
1.44
442                 printf(".text\n.align 4\n");
ragge
1.74
443                 PT("1fpref");
444                 printf("__pcc_1fpref:\n");
445                 printf("cmpl $176,4(%%rdi)\njae .Ladd8\n");
ragge
1.33
446                 printf("movl 4(%%rdi),%%eax\naddq 16(%%rdi),%%rax\n");
ragge
1.74
447                 printf("addl $16,4(%%rdi)\nret\n");
ragge
1.33
448         }
449         if (varneeds & NEED_1REGREF) {
ragge
1.44
450                 printf(".text\n.align 4\n");
451                 PT("1regref");
ragge
1.33
452                 printf("__pcc_1regref:\n");
ragge
1.74
453                 printf("cmpl $48,(%%rdi)\njae .Ladd8\n");
ragge
1.33
454                 printf("movl (%%rdi),%%eax\naddq 16(%%rdi),%%rax\n");
455                 printf("addl $8,(%%rdi)\nret\n");
456         }
457         if (varneeds & NEED_2REGREF) {
ragge
1.44
458                 printf(".text\n.align 4\n");
459                 PT("2regref");
ragge
1.33
460                 printf("__pcc_2regref:\n");
ragge
1.74
461                 printf("cmpl $40,(%%rdi)\njae .Ladd16\n");
ragge
1.33
462                 printf("movl (%%rdi),%%eax\naddq 16(%%rdi),%%rax\n");
463                 printf("addl $16,(%%rdi)\nret\n");
464         }
465         if (varneeds & NEED_MEMREF) {
ragge
1.44
466                 printf(".text\n.align 4\n");
467                 PT("memref");
ragge
1.33
468                 printf("__pcc_memref:\n");
469                 printf("movq 8(%%rdi),%%rax\n");
470                 printf("addq %%rsi,8(%%rdi)\nret\n");
471         }
ragge
1.74
472
473         if (varneeds & (NEED_1FPREF|NEED_1REGREF)) {
474                 P(".Ladd8:");
475                 P("movq 8(%%rdi),%%rax");
476                 P("addq $8,8(%%rdi)");
477                 P("ret");
478         }
479         if (varneeds & (NEED_2FPREF|NEED_2REGREF|NEED_STRFI|NEED_STRIF)) {
480                 P(".Ladd16:");
481                 P("movq 8(%%rdi),%%rax");
482                 P("addq $16,8(%%rdi)");
483                 P("ret");
484         }
ragge
1.33
485
ragge
1.44
486 #ifdef MACHOABI
plunky
1.55
487         printf("\t.ident \"PCC: %s\"\n"VERSSTR);
ragge
1.44
488 #else
plunky
1.55
489         printf("\t.ident \"PCC: %s\"\n\t.end\n"VERSSTR);
ragge
1.44
490 #endif
mickey
1.1
491 }
492
ragge
1.11
493 /*
494  * Varargs stuff:
495  * The ABI says that va_list should be declared as this typedef.
496  * We handcraft it here and then just reference it.
497  *
498  * typedef struct {
499  *      unsigned int gp_offset;
500  *      unsigned int fp_offset;
501  *      void *overflow_arg_area;
502  *      void *reg_save_area;
503  * } __builtin_va_list[1];
ragge
1.33
504  *
ragge
1.74
505  * ...actually, we allocate two of them and use the second one as 
506  * bounce buffers for floating point structs...
507  *
ragge
1.33
508  * There are a number of asm routines printed out if varargs are used:
509  *      long __pcc_gpnext(va)   - get a gpreg value
510  *      long __pcc_fpnext(va)   - get a fpreg value
511  *      void *__pcc_1regref(va) - get reference to a onereg struct 
512  *      void *__pcc_2regref(va) - get reference to a tworeg struct 
513  *      void *__pcc_memref(va,sz)       - get reference to a large struct 
ragge
1.11
514  */
ragge
1.13
515
ragge
1.11
516 static char *gp_offset, *fp_offset, *overflow_arg_area, *reg_save_area;
ragge
1.74
517 static char *_1fpref, *_2fpref, *_1regref, *_2regref, *memref;
518 static char *strif, *strfi;
ragge
1.13
519
mickey
1.1
520 void
plunky
1.64
521 bjobcode(void)
mickey
1.1
522 {
ragge
1.33
523         struct symtab *sp;
ragge
1.11
524         struct rstack *rp;
525         NODE *p, *q;
526         char *c;
527
ragge
1.78
528 #if defined(__GNUC__) || defined(__PCC__)
529         /* Be sure that the compiler uses full x87 */
530         /* XXX cross-compiling will fail here */
531         int fcw = 0;
532         __asm("fstcw (%0)" : : "r"(&fcw));
ragge
1.80
533         fcw |= 0x33f;
ragge
1.78
534         __asm("fldcw (%0)" : : "r"(&fcw));
535 #endif
536
ragge
1.57
537         /* amd64 names for some asm constant printouts */
538         astypnames[INT] = astypnames[UNSIGNED] = "\t.long";
539         astypnames[LONG] = astypnames[ULONG] = "\t.quad";
540
ragge
1.11
541         gp_offset = addname("gp_offset");
542         fp_offset = addname("fp_offset");
543         overflow_arg_area = addname("overflow_arg_area");
544         reg_save_area = addname("reg_save_area");
545
546         rp = bstruct(NULLSTNAMENULL);
ragge
1.50
547         p = block(NAMENILNILUNSIGNED00);
ragge
1.11
548         soumemb(pgp_offset0);
549         soumemb(pfp_offset0);
550         p->n_type = VOID+PTR;
ragge
1.50
551         p->n_ap = NULL;
ragge
1.11
552         soumemb(poverflow_arg_area0);
553         soumemb(preg_save_area0);
554         nfree(p);
555         q = dclstruct(rp);
556         c = addname("__builtin_va_list");
ragge
1.74
557         p = block(LBbdty(NAMEc), bcon(2), INT00);
ragge
1.11
558         p = tymerge(qp);
559         p->n_sp = lookup(c0);
560         defid(pTYPEDEF);
561         nfree(q);
562         nfree(p);
ragge
1.33
563
564         /* for the static varargs functions */
ragge
1.74
565 #define MKN(vn, rn) \
ragge
1.33
566         { vn = addname(rn); sp = lookup(vnSNORMAL); \
ragge
1.74
567           sp->sclass = USTATICsp->stype = FTN|VOID|(PTR<<TSHIFT); }
ragge
1.33
568
ragge
1.74
569         MKN(strfi"__pcc_strfi");
570         MKN(strif"__pcc_strif");
571         MKN(_1fpref"__pcc_1fpref");
572         MKN(_2fpref"__pcc_2fpref");
573         MKN(_1regref"__pcc_1regref");
574         MKN(_2regref"__pcc_2regref");
575         MKN(memref"__pcc_memref");
ragge
1.11
576 }
577
578 static NODE *
579 mkstkref(int offTWORD typ)
580 {
581         NODE *p;
582
ragge
1.50
583         p = block(REGNILNILPTR|typ00);
ragge
1.11
584         regno(p) = FPREG;
585         return buildtree(PLUSpbcon(off/SZCHAR));
586 }
587
588 NODE *
ragge
1.65
589 amd64_builtin_stdarg_start(const struct bitable *btNODE *a)
ragge
1.11
590 {
591         NODE *p, *r;
592
593         /* use the values from the function header */
594         p = a->n_left;
595         r = buildtree(ASSIGNstructref(ccopy(p), STREFreg_save_area),
596             mkstkref(-rsaoffVOID));
597         r = buildtree(COMOPr,
598             buildtree(ASSIGNstructref(ccopy(p), STREFoverflow_arg_area),
ragge
1.14
599             mkstkref(thisrspVOID)));
ragge
1.11
600         r = buildtree(COMOPr,
601             buildtree(ASSIGNstructref(ccopy(p), STREFgp_offset),
ragge
1.14
602             bcon(thisgpr*(SZLONG/SZCHAR))));
ragge
1.11
603         r = buildtree(COMOPr,
604             buildtree(ASSIGNstructref(ccopy(p), STREFfp_offset),
ragge
1.14
605             bcon(thissse*(SZDOUBLE*2/SZCHAR)+48)));
ragge
1.11
606
607         tfree(a);
608         return r;
mickey
1.1
609 }
610
ragge
1.74
611 static NODE *
612 mkvacall(char *funNODE *aint typ)
613 {
614         NODE *r, *f = block(NAMENILNILINT00);
615         NODE *ap = a->n_left;
616         NODE *dp = a->n_right;
617         int sz = tsize(dp->n_typedp->n_dfdp->n_ap);
618
619         f->n_sp = lookup(funSNORMAL);
620         varneeds |= typ;
621         f->n_type = f->n_sp->stype;
622         f = clocal(f);
623         SETOFF(szALLONG);
624         r = buildtree(CALLf,
625             buildtree(CMccopy(ap), bcon(sz/SZCHAR)));
626         r = ccast(rINCREF(dp->n_type), 0dp->n_dfdp->n_ap);
627         r = buildtree(UMULrNIL);
628         return r;
629 }
630
ragge
1.11
631 NODE *
ragge
1.65
632 amd64_builtin_va_arg(const struct bitable *btNODE *a)
ragge
1.12
633 {
plunky
1.75
634         NODE *r, *dp;
ragge
1.74
635         int typsz;
ragge
1.12
636
ragge
1.29
637         dp = a->n_right;
ragge
1.74
638
639         nsse = ngpr = 0;
640         sz = tsize(dp->n_typedp->n_dfdp->n_ap);
641         switch (typ = argtyp(dp->n_typedp->n_dfdp->n_ap)) {
642         case INTEGER:
643                 r = mkvacall(_1regrefaNEED_1REGREF);
644                 break;
645
646         case SSE:
647                 r = mkvacall(_1fprefaNEED_1FPREF);
648                 break;
649
650         default:
651                 cerror("va_arg: bad type %d"typ);
652
653         case X87:
654         case STRX87:
655         case STRMEM/* stored in memory */
656                 r = mkvacall(memrefaNEED_MEMREF);
657                 break;
658
659         case STRREG/* struct in general regs */
660                 if (sz <= SZLONG)
661                         r = mkvacall(_1regrefaNEED_1REGREF);
662                 else
663                         r = mkvacall(_2regrefaNEED_2REGREF);
664                 break;
665
666         case STRSSE:
667                 if (sz <= SZLONG)
668                         r = mkvacall(_1fprefaNEED_1FPREF);
669                 else
670                         r = mkvacall(_2fprefaNEED_2FPREF);
671                 break;
672
673         case STRIF:
674                 r = mkvacall(strifaNEED_STRIF);
675                 break;
676
677         case STRFI:
678                 r = mkvacall(strfiaNEED_STRFI);
679                 break;
ragge
1.12
680         }
ragge
1.74
681
ragge
1.12
682         tfree(a);
683         return r;
684 }
ragge
1.11
685
686 NODE *
ragge
1.65
687 amd64_builtin_va_end(const struct bitable *btNODE *a)
ragge
1.13
688 {
689         tfree(a);
690         return bcon(0); /* nothing */
691 }
ragge
1.11
692
693 NODE *
ragge
1.65
694 amd64_builtin_va_copy(const struct bitable *btNODE *a)
ragge
1.33
695 {
ragge
1.65
696         NODE *f;
697
ragge
1.33
698         f = buildtree(ASSIGNbuildtree(UMULa->n_leftNIL),
699             buildtree(UMULa->n_rightNIL));
700         nfree(a);
701         return f;
702 }
ragge
1.11
703
ragge
1.7
704 static NODE *
705 movtoreg(NODE *pint rno)
mickey
1.1
706 {
707         NODE *r;
708
ragge
1.23
709         r = block(REGNILNILp->n_typep->n_dfp->n_ap);
ragge
1.7
710         regno(r) = rno;
711         return clocal(buildtree(ASSIGNrp));
712 }  
713
ragge
1.9
714 static NODE *
ragge
1.14
715 movtomem(NODE *pint offint reg)
ragge
1.9
716 {
717         struct symtab s;
718         NODE *r, *l;
719
720         s.stype = p->n_type;
ragge
1.25
721         s.squal = 0;
ragge
1.9
722         s.sdf = p->n_df;
ragge
1.23
723         s.sap = p->n_ap;
ragge
1.9
724         s.soffset = off;
ragge
1.11
725         s.sclass = AUTO;
ragge
1.9
726
727         l = block(REGNILNILPTR+STRTY00);
728         l->n_lval = 0;
ragge
1.14
729         regno(l) = reg;
ragge
1.9
730
ragge
1.23
731         r = block(NAMENILNILp->n_typep->n_dfp->n_ap);
ragge
1.9
732         r->n_sp = &s;
733         r = stref(block(STREFlr000));
734
735         return clocal(buildtree(ASSIGNrp));
736 }  
737
ragge
1.71
738 /*
739  * Check what to do with a struct.  We traverse down in the struct to 
740  * find which types it is and where the struct really should be.
741  * The return vals we may end up with are:
742  *      STRREG - The whole struct is saved in general registers.
743  *      STRMEM - the struct is saved in memory.
744  *      STRSSE - the whole struct is saved in SSE registers.
745  *      STRIF  - First word of struct is saved in general reg, other SSE.
746  *      STRFI  - First word of struct is saved in SSE, next in general reg.
747  *
748  * - If size > 16 bytes or there are packed fields, use memory.
749  * - If any part of an eight-byte should be in a general register,
750  *    the eight-byte is stored in a general register
751  * - If the eight-byte only contains float or double, use a SSE register
752  * - Otherwise use memory.
753  *
ragge
1.79
754  * Arrays must be broken up as separate elements, since the elements
755  * are classified separately. For example;
756  *      struct s { short s; float f[3]; } S;
757  * will have the first 64 bits passed in general reg and the second in SSE.
758  *
ragge
1.71
759  * sp below is a pointer to a member list.
760  * off tells whether is is the first or second eight-byte to check.
761  */
762 static int
763 classifystruct(struct symtab *spint off)
764 {
ragge
1.79
765         struct symtab sps[16];
766         union dimfun *df;
ragge
1.71
767         TWORD t;
ragge
1.79
768         int clcl2szi;
769
ragge
1.71
770
771         for (cl = 0spsp = sp->snext) {
772                 t = sp->stype;
773
ragge
1.79
774                 /* fake a linked list of all array members */
775                 if (ISARY(t)) {
776                         sz = 1;
777                         df = sp->sdf;
778                         do {
779                                 sz *= df->ddim;
780                                 t = DECREF(t);
781                                 df++;
782                         } while (ISARY(t));
783                         for (i = 0i < szi++) {
784                                 sps[i] = *sp;
785                                 sps[i].stype = t;
786                                 sps[i].sdf = df;
787                                 sps[i].snext = &sps[i+1];
788                                 sps[i].soffset = i * tsize(tdfsp->sap);
789                         }
790                         sps[i-1].snext = sp->snext;
791                         sp = &sps[0];
792                 }
793
ragge
1.71
794                 if (off == 0) {
795                         if (sp->soffset >= SZLONG)
796                                 continue;
797                 } else {
798                         if (sp->soffset < SZLONG)
799                                 continue;
800                 }
801
802                 if (t <= ULONGLONG || ISPTR(t)) {
803                         if (cl == 0 || cl == STRSSE)
804                                 cl = STRREG;
805                 } else if (t <= DOUBLE) {
806                         if (cl == 0)
807                                 cl = STRSSE;
808                 } else if (t == LDOUBLE) {
809                         return STRMEM;
810                 } else if (ISSOU(t)) {
ragge
1.76
811 #ifdef GCC_COMPAT
ragge
1.71
812                         if (attr_find(sp->sapGCC_ATYP_PACKED)) {
813                                 cl = STRMEM;
ragge
1.76
814                         } else
815 #endif
816                         {
ragge
1.71
817                                 cl2 = classifystruct(strmemb(sp->sap), off);
818                                 if (cl2 == STRMEM) {
819                                         cl = STRMEM;
820                                 } else if (cl2 == STRREG) {
821                                         if (cl == 0 || cl == STRSSE)
822                                                 cl = STRREG;
823                                 } else if (cl2 == STRSSE) {
824                                         if (cl == 0)
825                                                 cl = STRSSE;
826                                 }
827                         }
828                 } else
829                         cerror("classifystruct: unknown type %x"t);
830                 if (cl == STRMEM)
831                         break;
832         }
833         if (cl == 0)
834                 cerror("classifystruct: failed classify");
835         return cl;
836 }
837
ragge
1.73
838 /*
839  * Check for long double complex structs.
840  */
841 static int
842 iscplx87(struct symtab *sp)
843 {
844         if (sp->stype == LDOUBLE && sp->snext->stype == LDOUBLE &&
845             sp->snext->snext == NULL)
846                 return STRX87;
847         return 0;
848 }
ragge
1.7
849
850 /*
851  * AMD64 parameter classification.
852  */
853 static int
ragge
1.23
854 argtyp(TWORD tunion dimfun *dfstruct attr *ap)
ragge
1.7
855 {
ragge
1.71
856         int cl2cl = 0;
ragge
1.7
857
ragge
1.41
858         if (t <= ULONG || ISPTR(t) || t == BOOL) {
ragge
1.7
859                 cl = ngpr < 6 ? INTEGER : INTMEM;
ragge
1.47
860         } else if (t == FLOAT || t == DOUBLE || t == FIMAG || t == IMAG) {
ragge
1.8
861                 cl = nsse < 8 ? SSE : SSEMEM;
ragge
1.47
862         } else if (t == LDOUBLE || t == LIMAG) {
ragge
1.7
863                 cl = X87/* XXX */
ragge
1.26
864         } else if (t == STRTY || t == UNIONTY) {
ragge
1.32
865                 int sz = tsize(tdfap);
866
ragge
1.76
867 #ifdef GCC_COMPAT
ragge
1.73
868                 if (attr_find(apGCC_ATYP_PACKED)) {
869                         cl = STRMEM;
ragge
1.76
870                 } else
871 #endif
872                 if (iscplx87(strmemb(ap)) == STRX87) {
ragge
1.73
873                         cl = STRX87;
874                 } else if (sz > 2*SZLONG) {
ragge
1.7
875                         cl = STRMEM;
ragge
1.71
876                 } else if (sz <= SZLONG) {
877                         /* only one member to check */
878                         cl = classifystruct(strmemb(ap), 0);
879                         if (cl == STRREG && ngpr > 5)
880                                 cl = STRMEM;
881                         else if (cl == STRSSE && nsse > 7)
882                                 cl = STRMEM;
883                 } else {
884                         cl = classifystruct(strmemb(ap), 0);
885                         cl2 = classifystruct(strmemb(ap), 1);
886                         if (cl == STRMEM || cl2 == STRMEM)
887                                 cl = STRMEM;
888                         else if (cl == STRREG && cl2 == STRSSE)
889                                 cl = STRIF;
890                         else if (cl2 == STRREG && cl == STRSSE)
891                                 cl = STRFI;
892
893                         if (cl == STRREG && ngpr > 4)
894                                 cl = STRMEM;
895                         else if (cl == STRSSE && nsse > 6)
896                                 cl = STRMEM;
897                         else if ((cl == STRIF || cl == STRFI) &&
898                             (ngpr > 5 || nsse > 7))
899                                 cl = STRMEM;
900                 }
ragge
1.7
901         } else
902                 cerror("FIXME: classify");
903         return cl;
904 }
905
ragge
1.42
906 /*
907  * Do the "hard work" in assigning correct destination for arguments.
908  * Also convert arguments < INT to inte (default argument promotions).
909  * XXX - should be dome elsewhere.
910  */
ragge
1.26
911 static NODE *
ragge
1.7
912 argput(NODE *p)
913 {
ragge
1.71
914         NODE *q, *ql;
ragge
1.46
915         TWORD ty;
ragge
1.71
916         int typrsszrn;
mickey
1.1
917
ragge
1.26
918         if (p->n_op == CM) {
919                 p->n_left = argput(p->n_left);
920                 p->n_right = argput(p->n_right);
921                 return p;
922         }
923
ragge
1.7
924         /* first arg may be struct return pointer */
925         /* XXX - check if varargs; setup al */
ragge
1.23
926         switch (typ = argtyp(p->n_typep->n_dfp->n_ap)) {
ragge
1.7
927         case INTEGER:
928         case SSE:
929                 if (typ == SSE)
930                         r = XMM0 + nsse++;
931                 else
932                         r = argregsi[ngpr++];
ragge
1.43
933                 if (p->n_type < INT || p->n_type == BOOL)
ragge
1.42
934                         p = cast(pINT0);
ragge
1.26
935                 p = movtoreg(pr);
ragge
1.7
936                 break;
ragge
1.26
937
ragge
1.7
938         case X87:
ragge
1.25
939                 r = nrsp;
940                 nrsp += SZLDOUBLE;
ragge
1.26
941                 p = movtomem(prSTKREG);
ragge
1.7
942                 break;
ragge
1.9
943
ragge
1.30
944         case SSEMEM:
945                 r = nrsp;
946                 nrsp += SZDOUBLE;
947                 p = movtomem(prSTKREG);
948                 break;
949
ragge
1.9
950         case INTMEM:
951                 r = nrsp;
952                 nrsp += SZLONG;
ragge
1.26
953                 p = movtomem(prSTKREG);
ragge
1.9
954                 break;
955
ragge
1.71
956         case STRFI:
957         case STRIF:
958         case STRSSE:
ragge
1.17
959         case STRREG/* Struct in registers */
ragge
1.71
960                 /* Cast to long/sse pointer and move to the registers */
ragge
1.27
961                 /* XXX can overrun struct size */
ragge
1.23
962                 ssz = tsize(p->n_typep->n_dfp->n_ap);
ragge
1.17
963
ragge
1.71
964