1 /* $Id: code.c,v 1.80 2014/09/28 12:51:31 ragge Exp $ */
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
33 static int nsse, ngpr, nrsp, rsaoff;
34 static int thissse, thisgpr, thisrsp;
35 enum { INTEGER = 1, INTMEM, SSE, SSEMEM, X87,
36 STRREG, STRMEM, STRSSE, STRIF, STRFI, STRX87 };
37 static const int argregsi[] = { RDI, RSI, RDX, RCX, R08, R09 };
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))
55
56 static int stroffset;
57
58 static int varneeds;
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
66
67 static int argtyp(TWORD t, union dimfun *df, struct attr *ap);
68 static NODE *movtomem(NODE *p, int off, int reg);
69 static NODE *movtoreg(NODE *p, int rno);
70 void varattrib(char *name, struct attr *sap);
71
72 /*
73 * Print out assembler segment name.
74 */
75 #ifdef MACHOABI
76 void
setseg(int seg,char * name)77 setseg(int seg, char *name)
78 {
79 switch (seg) {
80 case PROG: name = ".text"; break;
81 case DATA:
82 case LDATA: name = ".data"; break;
83 case RDATA: name = ".const"; break;
84 case STRNG: name = ".cstring"; break;
85 case UDATA: break;
86 case CTORS: name = ".mod_init_func"; break;
87 case DTORS: name = ".mod_term_func"; break;
88 default:
89 cerror("unknown seg %d", seg);
90 }
91 printf("\t%s\n", name);
92 }
93
94 #else
95 void
setseg(int seg,char * name)96 setseg(int seg, char *name)
97 {
98 switch (seg) {
99 case PROG: name = ".text"; break;
100 case DATA:
101 case LDATA: name = ".data"; break;
102 case STRNG:
103 case RDATA: name = ".section .rodata"; break;
104 case UDATA: break;
105 case PICLDATA:
106 case PICDATA: name = ".section .data.rel.rw,\"aw\",@progbits"; break;
107 case PICRDATA: name = ".section .data.rel.ro,\"aw\",@progbits"; break;
108 case TLSDATA: name = ".section .tdata,\"awT\",@progbits"; break;
109 case TLSUDATA: name = ".section .tbss,\"awT\",@nobits"; break;
110 case CTORS: name = ".section\t.ctors,\"aw\",@progbits"; break;
111 case DTORS: name = ".section\t.dtors,\"aw\",@progbits"; break;
112 case NMSEG:
113 printf("\t.section %s,\"a%c\",@progbits\n", name,
114 cftnsp ? 'x' : 'w');
115 return;
116 }
117 printf("\t%s\n", name);
118 }
119 #endif
120
121 /*
122 * Define everything needed to print out some data (or text).
123 * This means segment, alignment, visibility, etc.
124 */
125 void
defloc(struct symtab * sp)126 defloc(struct symtab *sp)
127 {
128 char *name;
129
130 if ((name = sp->soname) == NULL)
131 name = exname(sp->sname);
132
133 if (sp->sclass == EXTDEF) {
134 printf("\t.globl %s\n", name);
135 #ifndef MACHOABI
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->stype, sp->sdf, sp->sap)/SZCHAR);
142 }
143 #endif
144 }
145 if (sp->slevel == 0)
146 printf("%s:\n", name);
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
154 * The return value is in (or pointed to by) RETREG.
155 */
156 void
efcode(void)157 efcode(void)
158 {
159 struct symtab *sp;
160 extern int gotnr;
161 TWORD t;
162 NODE *p, *r, *l;
163 int typ;
164
165 gotnr = 0; /* new number for next fun */
166 sp = cftnsp;
167 t = DECREF(sp->stype);
168 if (t != STRTY && t != UNIONTY)
169 return;
170
171 /* XXX should have one routine for this */
172 ngpr = nsse = 0;
173 typ = argtyp(t, sp->sdf, sp->sap);
174 if (typ == STRMEM) {
175 r = block(REG, NIL, NIL, INCREF(t), sp->sdf, sp->sap);
176 regno(r) = RAX;
177 r = buildtree(UMUL, r, NIL);
178 l = tempnode(stroffset, INCREF(t), sp->sdf, sp->sap);
179 l = buildtree(UMUL, l, NIL);
180 ecomp(buildtree(ASSIGN, l, r));
181 l = block(REG, NIL, NIL, LONG, 0, 0);
182 regno(l) = RAX;
183 r = tempnode(stroffset, LONG, 0, 0);
184 ecomp(buildtree(ASSIGN, l, r));
185 } else if (typ == STRX87) {
186 p = block(REG, NIL, NIL, INCREF(LDOUBLE), 0, 0);
187 regno(p) = RAX;
188 p = buildtree(UMUL, buildtree(PLUS, p, bcon(1)), NIL);
189 ecomp(movtoreg(p, 041));
190 p = block(REG, NIL, NIL, INCREF(LDOUBLE), 0, 0);
191 regno(p) = RAX;
192 p = buildtree(UMUL, p, NIL);
193 ecomp(movtoreg(p, 040));
194 } else {
195 TWORD t1, t2;
196 int r1, r2;
197 if (typ == STRSSE || typ == STRFI)
198 r1 = XMM0, t1 = DOUBLE;
199 else
200 r1 = RAX, t1 = LONG;
201 if (typ == STRSSE)
202 r2 = XMM1, t2 = DOUBLE;
203 else if (typ == STRFI)
204 r2 = RAX, t2 = LONG;
205 else if (typ == STRIF)
206 r2 = XMM0, t2 = DOUBLE;
207 else /* if (typ == STRREG) */
208 r2 = RDX, t2 = LONG;
209
210 if (tsize(t, sp->sdf, sp->sap) > SZLONG) {
211 p = block(REG, NIL, NIL, INCREF(t2), 0, 0);
212 regno(p) = RAX;
213 p = buildtree(UMUL, buildtree(PLUS, p, bcon(1)), NIL);
214 ecomp(movtoreg(p, r2));
215 }
216 p = block(REG, NIL, NIL, INCREF(t1), 0, 0);
217 regno(p) = RAX;
218 p = buildtree(UMUL, p, NIL);
219 ecomp(movtoreg(p, r1));
220 }
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
bfcode(struct symtab ** s,int cnt)228 bfcode(struct symtab **s, int cnt)
229 {
230 union arglist *al;
231 struct symtab *sp;
232 NODE *p, *r;
233 TWORD t;
234 int i, rno, typ, ssz;
235
236 /* recalculate the arg offset and create TEMP moves */
237 /* Always do this for reg, even if not optimizing, to free arg regs */
238 nsse = ngpr = 0;
239 nrsp = ARGINIT;
240 if (cftnsp->stype == STRTY+FTN || cftnsp->stype == UNIONTY+FTN) {
241 sp = cftnsp;
242 if (argtyp(DECREF(sp->stype), sp->sdf, sp->sap) == STRMEM) {
243 r = block(REG, NIL, NIL, LONG, 0, 0);
244 regno(r) = argregsi[ngpr++];
245 p = tempnode(0, r->n_type, r->n_df, r->n_ap);
246 stroffset = regno(p);
247 ecomp(buildtree(ASSIGN, p, r));
248 }
249 }
250
251 for (i = 0; i < cnt; i++) {
252 sp = s[i];
253
254 if (sp == NULL)
255 continue; /* XXX when happens this? */
256
257 ssz = tsize(sp->stype, sp->sdf, sp->sap);
258 switch (typ = argtyp(sp->stype, sp->sdf, sp->sap)) {
259 case INTEGER:
260 case SSE:
261 if (typ == SSE)
262 rno = XMM0 + nsse++;
263 else
264 rno = argregsi[ngpr++];
265 r = block(REG, NIL, NIL, sp->stype, sp->sdf, sp->sap);
266 regno(r) = rno;
267 p = tempnode(0, sp->stype, sp->sdf, sp->sap);
268 sp->soffset = regno(p);
269 sp->sflags |= STNODE;
270 ecomp(buildtree(ASSIGN, p, r));
271 break;
272
273 case SSEMEM:
274 sp->soffset = nrsp;
275 nrsp += SZDOUBLE;
276 if (xtemps) {
277 p = tempnode(0, sp->stype, sp->sdf, sp->sap);
278 p = buildtree(ASSIGN, p, nametree(sp));
279 sp->soffset = regno(p->n_left);
280 sp->sflags |= STNODE;
281 ecomp(p);
282 }
283 break;
284
285 case INTMEM:
286 sp->soffset = nrsp;
287 nrsp += SZLONG;
288 if (xtemps) {
289 p = tempnode(0, sp->stype, sp->sdf, sp->sap);
290 p = buildtree(ASSIGN, p, nametree(sp));
291 sp->soffset = regno(p->n_left);
292 sp->sflags |= STNODE;
293 ecomp(p);
294 }
295 break;
296
297 case STRX87:
298 case STRMEM: /* Struct in memory */
299 sp->soffset = nrsp;
300 nrsp += ssz;
301 break;
302
303 case X87: /* long double args */
304 sp->soffset = nrsp;
305 nrsp += SZLDOUBLE;
306 break;
307
308 case STRFI:
309 case STRIF:
310 case STRSSE:
311 case STRREG: /* Struct in register */
312 autooff += (2*SZLONG);
313
314 if (typ == STRSSE || typ == STRFI) {
315 rno = XMM0 + nsse++;
316 t = DOUBLE;
317 } else {
318 rno = argregsi[ngpr++];
319 t = LONG;
320 }
321 r = block(REG, NIL, NIL, t, 0, 0);
322 regno(r) = rno;
323 ecomp(movtomem(r, -autooff, FPREG));
324
325 if (ssz > SZLONG) {
326 if (typ == STRSSE || typ == STRIF) {
327 rno = XMM0 + nsse++;
328 t = DOUBLE;
329 } else {
330 rno = argregsi[ngpr++];
331 t = LONG;
332 }
333 r = block(REG, NIL, NIL, t, 0, 0);
334 regno(r) = rno;
335 ecomp(movtomem(r, -autooff+SZLONG, FPREG));
336 }
337 sp->soffset = -autooff;
338 break;
339
340 default:
341 cerror("bfcode: %d", typ);
342 }
343 }
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;
349
350 for (; al->type != TELLIPSIS; al++) {
351 t = al->type;
352 if (t == TNULL)
353 return;
354 if (ISSOU(BTYPE(t)))
355 al++;
356 for (i = 0; t > BTMASK; t = DECREF(t))
357 if (ISARY(t) || ISFTN(t))
358 i++;
359 if (i)
360 al++;
361 }
362
363 /* fix stack offset */
364 SETOFF(autooff, ALMAX);
365
366 /* Save reg arguments in the reg save area */
367 p = NIL;
368 for (i = ngpr; i < 6; i++) {
369 r = block(REG, NIL, NIL, LONG, 0, 0);
370 regno(r) = argregsi[i];
371 r = movtomem(r, -RSALONGOFF(i)-autooff, FPREG);
372 p = (p == NIL ? r : block(COMOP, p, r, INT, 0, 0));
373 }
374 for (i = nsse; i < 8; i++) {
375 r = block(REG, NIL, NIL, DOUBLE, 0, 0);
376 regno(r) = i + XMM0;
377 r = movtomem(r, -RSADBLOFF(i)-autooff, FPREG);
378 p = (p == NIL ? r : block(COMOP, p, r, INT, 0, 0));
379 }
380 autooff += RSASZ;
381 rsaoff = autooff;
382 thissse = nsse;
383 thisgpr = ngpr;
384 thisrsp = nrsp;
385
386 ecomp(p);
387 }
388
389
390 /* called just before final exit */
391 /* flag is 1 if errors, 0 if none */
392 void
ejobcode(int flag)393 ejobcode(int flag)
394 {
395 if (flag)
396 return;
397
398 #ifdef MACHOABI
399 #define PT(x)
400 #else
401 #define PT(x) printf(".type __pcc_" x ",@function\n")
402 #endif
403
404 #define P(x) printf(x "\n")
405 /* printout varargs routines if used */
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");
440 }
441 if (varneeds & NEED_1FPREF) {
442 printf(".text\n.align 4\n");
443 PT("1fpref");
444 printf("__pcc_1fpref:\n");
445 printf("cmpl $176,4(%%rdi)\njae .Ladd8\n");
446 printf("movl 4(%%rdi),%%eax\naddq 16(%%rdi),%%rax\n");
447 printf("addl $16,4(%%rdi)\nret\n");
448 }
449 if (varneeds & NEED_1REGREF) {
450 printf(".text\n.align 4\n");
451 PT("1regref");
452 printf("__pcc_1regref:\n");
453 printf("cmpl $48,(%%rdi)\njae .Ladd8\n");
454 printf("movl (%%rdi),%%eax\naddq 16(%%rdi),%%rax\n");
455 printf("addl $8,(%%rdi)\nret\n");
456 }
457 if (varneeds & NEED_2REGREF) {
458 printf(".text\n.align 4\n");
459 PT("2regref");
460 printf("__pcc_2regref:\n");
461 printf("cmpl $40,(%%rdi)\njae .Ladd16\n");
462 printf("movl (%%rdi),%%eax\naddq 16(%%rdi),%%rax\n");
463 printf("addl $16,(%%rdi)\nret\n");
464 }
465 if (varneeds & NEED_MEMREF) {
466 printf(".text\n.align 4\n");
467 PT("memref");
468 printf("__pcc_memref:\n");
469 printf("movq 8(%%rdi),%%rax\n");
470 printf("addq %%rsi,8(%%rdi)\nret\n");
471 }
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 }
485
486 #ifdef MACHOABI
487 printf("\t.ident \"PCC: %s\"\n", VERSSTR);
488 #else
489 printf("\t.ident \"PCC: %s\"\n\t.end\n", VERSSTR);
490 #endif
491 }
492
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];
504 *
505 * ...actually, we allocate two of them and use the second one as
506 * bounce buffers for floating point structs...
507 *
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
514 */
515
516 static char *gp_offset, *fp_offset, *overflow_arg_area, *reg_save_area;
517 static char *_1fpref, *_2fpref, *_1regref, *_2regref, *memref;
518 static char *strif, *strfi;
519
520 void
bjobcode(void)521 bjobcode(void)
522 {
523 struct symtab *sp;
524 struct rstack *rp;
525 NODE *p, *q;
526 char *c;
527
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));
533 fcw |= 0x33f;
534 __asm("fldcw (%0)" : : "r"(&fcw));
535 #endif
536
537 /* amd64 names for some asm constant printouts */
538 astypnames[INT] = astypnames[UNSIGNED] = "\t.long";
539 astypnames[LONG] = astypnames[ULONG] = "\t.quad";
540
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(NULL, STNAME, NULL);
547 p = block(NAME, NIL, NIL, UNSIGNED, 0, 0);
548 soumemb(p, gp_offset, 0);
549 soumemb(p, fp_offset, 0);
550 p->n_type = VOID+PTR;
551 p->n_ap = NULL;
552 soumemb(p, overflow_arg_area, 0);
553 soumemb(p, reg_save_area, 0);
554 nfree(p);
555 q = dclstruct(rp);
556 c = addname("__builtin_va_list");
557 p = block(LB, bdty(NAME, c), bcon(2), INT, 0, 0);
558 p = tymerge(q, p);
559 p->n_sp = lookup(c, 0);
560 defid(p, TYPEDEF);
561 nfree(q);
562 nfree(p);
563
564 /* for the static varargs functions */
565 #define MKN(vn, rn) \
566 { vn = addname(rn); sp = lookup(vn, SNORMAL); \
567 sp->sclass = USTATIC; sp->stype = FTN|VOID|(PTR<<TSHIFT); }
568
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");
576 }
577
578 static NODE *
mkstkref(int off,TWORD typ)579 mkstkref(int off, TWORD typ)
580 {
581 NODE *p;
582
583 p = block(REG, NIL, NIL, PTR|typ, 0, 0);
584 regno(p) = FPREG;
585 return buildtree(PLUS, p, bcon(off/SZCHAR));
586 }
587
588 NODE *
amd64_builtin_stdarg_start(const struct bitable * bt,NODE * a)589 amd64_builtin_stdarg_start(const struct bitable *bt, NODE *a)
590 {
591 NODE *p, *r;
592
593 /* use the values from the function header */
594 p = a->n_left;
595 r = buildtree(ASSIGN, structref(ccopy(p), STREF, reg_save_area),
596 mkstkref(-rsaoff, VOID));
597 r = buildtree(COMOP, r,
598 buildtree(ASSIGN, structref(ccopy(p), STREF, overflow_arg_area),
599 mkstkref(thisrsp, VOID)));
600 r = buildtree(COMOP, r,
601 buildtree(ASSIGN, structref(ccopy(p), STREF, gp_offset),
602 bcon(thisgpr*(SZLONG/SZCHAR))));
603 r = buildtree(COMOP, r,
604 buildtree(ASSIGN, structref(ccopy(p), STREF, fp_offset),
605 bcon(thissse*(SZDOUBLE*2/SZCHAR)+48)));
606
607 tfree(a);
608 return r;
609 }
610
611 static NODE *
mkvacall(char * fun,NODE * a,int typ)612 mkvacall(char *fun, NODE *a, int typ)
613 {
614 NODE *r, *f = block(NAME, NIL, NIL, INT, 0, 0);
615 NODE *ap = a->n_left;
616 NODE *dp = a->n_right;
617 int sz = tsize(dp->n_type, dp->n_df, dp->n_ap);
618
619 f->n_sp = lookup(fun, SNORMAL);
620 varneeds |= typ;
621 f->n_type = f->n_sp->stype;
622 f = clocal(f);
623 SETOFF(sz, ALLONG);
624 r = buildtree(CALL, f,
625 buildtree(CM, ccopy(ap), bcon(sz/SZCHAR)));
626 r = ccast(r, INCREF(dp->n_type), 0, dp->n_df, dp->n_ap);
627 r = buildtree(UMUL, r, NIL);
628 return r;
629 }
630
631 NODE *
amd64_builtin_va_arg(const struct bitable * bt,NODE * a)632 amd64_builtin_va_arg(const struct bitable *bt, NODE *a)
633 {
634 NODE *r, *dp;
635 int typ, sz;
636
637 dp = a->n_right;
638
639 nsse = ngpr = 0;
640 sz = tsize(dp->n_type, dp->n_df, dp->n_ap);
641 switch (typ = argtyp(dp->n_type, dp->n_df, dp->n_ap)) {
642 case INTEGER:
643 r = mkvacall(_1regref, a, NEED_1REGREF);
644 break;
645
646 case SSE:
647 r = mkvacall(_1fpref, a, NEED_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(memref, a, NEED_MEMREF);
657 break;
658
659 case STRREG: /* struct in general regs */
660 if (sz <= SZLONG)
661 r = mkvacall(_1regref, a, NEED_1REGREF);
662 else
663 r = mkvacall(_2regref, a, NEED_2REGREF);
664 break;
665
666 case STRSSE:
667 if (sz <= SZLONG)
668 r = mkvacall(_1fpref, a, NEED_1FPREF);
669 else
670 r = mkvacall(_2fpref, a, NEED_2FPREF);
671 break;
672
673 case STRIF:
674 r = mkvacall(strif, a, NEED_STRIF);
675 break;
676
677 case STRFI:
678 r = mkvacall(strfi, a, NEED_STRFI);
679 break;
680 }
681
682 tfree(a);
683 return r;
684 }
685
686 NODE *
amd64_builtin_va_end(const struct bitable * bt,NODE * a)687 amd64_builtin_va_end(const struct bitable *bt, NODE *a)
688 {
689 tfree(a);
690 return bcon(0); /* nothing */
691 }
692
693 NODE *
amd64_builtin_va_copy(const struct bitable * bt,NODE * a)694 amd64_builtin_va_copy(const struct bitable *bt, NODE *a)
695 {
696 NODE *f;
697
698 f = buildtree(ASSIGN, buildtree(UMUL, a->n_left, NIL),
699 buildtree(UMUL, a->n_right, NIL));
700 nfree(a);
701 return f;
702 }
703
704 static NODE *
movtoreg(NODE * p,int rno)705 movtoreg(NODE *p, int rno)
706 {
707 NODE *r;
708
709 r = block(REG, NIL, NIL, p->n_type, p->n_df, p->n_ap);
710 regno(r) = rno;
711 return clocal(buildtree(ASSIGN, r, p));
712 }
713
714 static NODE *
movtomem(NODE * p,int off,int reg)715 movtomem(NODE *p, int off, int reg)
716 {
717 struct symtab s;
718 NODE *r, *l;
719
720 s.stype = p->n_type;
721 s.squal = 0;
722 s.sdf = p->n_df;
723 s.sap = p->n_ap;
724 s.soffset = off;
725 s.sclass = AUTO;
726
727 l = block(REG, NIL, NIL, PTR+STRTY, 0, 0);
728 l->n_lval = 0;
729 regno(l) = reg;
730
731 r = block(NAME, NIL, NIL, p->n_type, p->n_df, p->n_ap);
732 r->n_sp = &s;
733 r = stref(block(STREF, l, r, 0, 0, 0));
734
735 return clocal(buildtree(ASSIGN, r, p));
736 }
737
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 *
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 *
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
classifystruct(struct symtab * sp,int off)763 classifystruct(struct symtab *sp, int off)
764 {
765 struct symtab sps[16];
766 union dimfun *df;
767 TWORD t;
768 int cl, cl2, sz, i;
769
770
771 for (cl = 0; sp; sp = sp->snext) {
772 t = sp->stype;
773
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 = 0; i < sz; i++) {
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(t, df, sp->sap);
789 }
790 sps[i-1].snext = sp->snext;
791 sp = &sps[0];
792 }
793
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)) {
811 #ifdef GCC_COMPAT
812 if (attr_find(sp->sap, GCC_ATYP_PACKED)) {
813 cl = STRMEM;
814 } else
815 #endif
816 {
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
838 /*
839 * Check for long double complex structs.
840 */
841 static int
iscplx87(struct symtab * sp)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 }
849
850 /*
851 * AMD64 parameter classification.
852 */
853 static int
argtyp(TWORD t,union dimfun * df,struct attr * ap)854 argtyp(TWORD t, union dimfun *df, struct attr *ap)
855 {
856 int cl2, cl = 0;
857
858 if (t <= ULONG || ISPTR(t) || t == BOOL) {
859 cl = ngpr < 6 ? INTEGER : INTMEM;
860 } else if (t == FLOAT || t == DOUBLE || t == FIMAG || t == IMAG) {
861 cl = nsse < 8 ? SSE : SSEMEM;
862 } else if (t == LDOUBLE || t == LIMAG) {
863 cl = X87; /* XXX */
864 } else if (t == STRTY || t == UNIONTY) {
865 int sz = tsize(t, df, ap);
866
867 #ifdef GCC_COMPAT
868 if (attr_find(ap, GCC_ATYP_PACKED)) {
869 cl = STRMEM;
870 } else
871 #endif
872 if (iscplx87(strmemb(ap)) == STRX87) {
873 cl = STRX87;
874 } else if (sz > 2*SZLONG) {
875 cl = STRMEM;
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 }
901 } else
902 cerror("FIXME: classify");
903 return cl;
904 }
905
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 */
911 static NODE *
argput(NODE * p)912 argput(NODE *p)
913 {
914 NODE *q, *ql;
915 TWORD ty;
916 int typ, r, ssz, rn;
917
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
924 /* first arg may be struct return pointer */
925 /* XXX - check if varargs; setup al */
926 switch (typ = argtyp(p->n_type, p->n_df, p->n_ap)) {
927 case INTEGER:
928 case SSE:
929 if (typ == SSE)
930 r = XMM0 + nsse++;
931 else
932 r = argregsi[ngpr++];
933 if (p->n_type < INT || p->n_type == BOOL)
934 p = cast(p, INT, 0);
935 p = movtoreg(p, r);
936 break;
937
938 case X87:
939 r = nrsp;
940 nrsp += SZLDOUBLE;
941 p = movtomem(p, r, STKREG);
942 break;
943
944 case SSEMEM:
945 r = nrsp;
946 nrsp += SZDOUBLE;
947 p = movtomem(p, r, STKREG);
948 break;
949
950 case INTMEM:
951 r = nrsp;
952 nrsp += SZLONG;
953 p = movtomem(p, r, STKREG);
954 break;
955
956 case STRFI:
957 case STRIF:
958 case STRSSE:
959 case STRREG: /* Struct in registers */
960 /* Cast to long/sse pointer and move to the registers */
961 /* XXX can overrun struct size */
962 ssz = tsize(p->n_type, p->n_df, p->n_ap);
963
964 if (typ == STRSSE || typ == STRFI) {
965 r = XMM0 + nsse++;
966 ty = DOUBLE;
967 } else {
968 r = argregsi[ngpr++];
969 ty = LONG;
970 }
971
972 p = nfree(p); /* remove STARG */
973 p = makety(p, PTR|ty, 0, 0, 0);
974 ql = tempnode(0, PTR|ty, 0, 0);
975 rn = regno(ql);
976 p = buildtree(ASSIGN, ql, p);
977 ql = tempnode(rn, PTR|ty, 0, 0);
978 ql = movtoreg(buildtree(UMUL, ql, NIL), r);
979 p = buildtree(COMOP, p, ql);
980
981 if (ssz > SZLONG) {
982 if (typ == STRSSE || typ == STRIF) {
983 r = XMM0 + nsse++;
984 ty = DOUBLE;
985 } else {
986 r = argregsi[ngpr++];
987 ty = LONG;
988 }
989
990 ql = tempnode(rn, PTR|ty, 0, 0);
991 ql = buildtree(UMUL, buildtree(PLUS, ql, bcon(1)), NIL);
992 ql = movtoreg(ql, r);
993
994 p = buildtree(CM, p, ql);
995 }
996 break;
997
998 case STRX87:
999 case STRMEM: {
1000 struct symtab s;
1001 NODE *l, *t;
1002
1003 q = buildtree(UMUL, p->n_left, NIL);
1004
1005 s.stype = p->n_type;
1006 s.squal = 0;
1007 s.sdf = p->n_df;
1008 s.sap = p->n_ap;
1009 s.soffset = nrsp;
1010 s.sclass = AUTO;
1011
1012 nrsp += tsize(p->n_type, p->n_df, p->n_ap);
1013
1014 l = block(REG, NIL, NIL, PTR+STRTY, 0, 0);
1015 l->n_lval = 0;
1016 regno(l) = STKREG;
1017
1018 t = block(NAME, NIL, NIL, p->n_type, p->n_df, p->n_ap);
1019 t->n_sp = &s;
1020 t = stref(block(STREF, l, t, 0, 0, 0));
1021
1022 t = (buildtree(ASSIGN, t, q));
1023 nfree(p);
1024 p = t->n_left;
1025 nfree(t);
1026 break;
1027 }
1028
1029 default:
1030 cerror("argument %d", typ);
1031 }
1032 return p;
1033 }
1034
1035 /*
1036 * Sort arglist so that register assignments ends up last.
1037 */
1038 static int
argsort(NODE * p)1039 argsort(NODE *p)
1040 {
1041 NODE *q, *r;
1042 int rv = 0;
1043
1044 if (p->n_op != CM) {
1045 if (p->n_op == ASSIGN && p->n_left->n_op == REG &&
1046 coptype(p->n_right->n_op) != LTYPE) {
1047 q = tempnode(0, p->n_type, p->n_df, p->n_ap);
1048 r = ccopy(q);
1049 p->n_right = buildtree(COMOP,
1050 buildtree(ASSIGN, q, p->n_right), r);
1051 }
1052 return rv;
1053 }
1054 if (p->n_right->n_op == CM) {
1055 /* fixup for small structs in regs */
1056 q = p->n_right->n_left;
1057 p->n_right->n_left = p->n_left;
1058 p->n_left = p->n_right;
1059 p->n_right = p->n_left->n_right;
1060 p->n_left->n_right = q;
1061 }
1062 if (p->n_right->n_op == ASSIGN && p->n_right->n_left->n_op == REG &&
1063 coptype(p->n_right->n_right->n_op) != LTYPE) {
1064 /* move before everything to avoid reg trashing */
1065 q = tempnode(0, p->n_right->n_type,
1066 p->n_right->n_df, p->n_right->n_ap);
1067 r = ccopy(q);
1068 p->n_right->n_right = buildtree(COMOP,
1069 buildtree(ASSIGN, q, p->n_right->n_right), r);
1070 }
1071 if (p->n_right->n_op == ASSIGN && p->n_right->n_left->n_op == REG) {
1072 if (p->n_left->n_op == CM &&
1073 p->n_left->n_right->n_op == STASG) {
1074 q = p->n_left->n_right;
1075 p->n_left->n_right = p->n_right;
1076 p->n_right = q;
1077 rv = 1;
1078 } else if (p->n_left->n_op == STASG) {
1079 q = p->n_left;
1080 p->n_left = p->n_right;
1081 p->n_right = q;
1082 rv = 1;
1083 }
1084 }
1085 return rv | argsort(p->n_left);
1086 }
1087
1088 /*
1089 * Called with a function call with arguments as argument.
1090 * This is done early in buildtree() and only done once.
1091 * Returns p.
1092 */
1093 NODE *
funcode(NODE * p)1094 funcode(NODE *p)
1095 {
1096 NODE *l, *r;
1097 TWORD t;
1098 int i;
1099
1100 nsse = ngpr = nrsp = 0;
1101 /* Check if hidden arg needed */
1102 /* If so, add it in pass2 */
1103 if ((l = p->n_left)->n_type == INCREF(FTN)+STRTY ||
1104 l->n_type == INCREF(FTN)+UNIONTY) {
1105 int ssz = tsize(BTYPE(l->n_type), l->n_df, l->n_ap);
1106 struct symtab *sp = strmemb(l->n_ap);
1107 if (ssz == 2*SZLDOUBLE && sp->stype == LDOUBLE &&
1108 sp->snext->stype == LDOUBLE)
1109 ; /* long complex struct */
1110 else if (ssz > 2*SZLONG)
1111 ngpr++;
1112 }
1113
1114 /* Convert just regs to assign insn's */
1115 p->n_right = argput(p->n_right);
1116
1117 /* Must sort arglist so that STASG ends up first */
1118 /* This avoids registers being clobbered */
1119 while (argsort(p->n_right))
1120 ;
1121 /* Check if there are varargs */
1122 if (nsse || l->n_df == NULL || l->n_df->dfun == NULL) {
1123 ; /* Need RAX */
1124 } else {
1125 union arglist *al = l->n_df->dfun;
1126
1127 for (; al->type != TELLIPSIS; al++) {
1128 if ((t = al->type) == TNULL)
1129 return p; /* No need */
1130 if (ISSOU(BTYPE(t)))
1131 al++;
1132 for (i = 0; t > BTMASK; t = DECREF(t))
1133 if (ISARY(t) || ISFTN(t))
1134 i++;
1135 if (i)
1136 al++;
1137 }
1138 }
1139
1140 /* Always emit number of SSE regs used */
1141 l = movtoreg(bcon(nsse), RAX);
1142 if (p->n_right->n_op != CM) {
1143 p->n_right = block(CM, l, p->n_right, INT, 0, 0);
1144 } else {
1145 for (r = p->n_right; r->n_left->n_op == CM; r = r->n_left)
1146 ;
1147 r->n_left = block(CM, l, r->n_left, INT, 0, 0);
1148 }
1149 return p;
1150 }
1151
1152 /* fix up type of field p */
1153 void
fldty(struct symtab * p)1154 fldty(struct symtab *p)
1155 {
1156 }
1157
1158 /*
1159 * XXX - fix genswitch.
1160 */
1161 int
mygenswitch(int num,TWORD type,struct swents ** p,int n)1162 mygenswitch(int num, TWORD type, struct swents **p, int n)
1163 {
1164 return 0;
1165 }
1166
1167 /*
1168 * Return return as given by a.
1169 */
1170 NODE *
builtin_return_address(const struct bitable * bt,NODE * a)1171 builtin_return_address(const struct bitable *bt, NODE *a)
1172 {
1173 int nframes;
1174 NODE *f;
1175
1176 nframes = a->n_lval;
1177 tfree(a);
1178
1179 f = block(REG, NIL, NIL, PTR+VOID, 0, 0);
1180 regno(f) = FPREG;
1181
1182 while (nframes--)
1183 f = block(UMUL, f, NIL, PTR+VOID, 0, 0);
1184
1185 f = block(PLUS, f, bcon(8), INCREF(PTR+VOID), 0, 0);
1186 f = buildtree(UMUL, f, NIL);
1187
1188 return f;
1189 }
1190
1191 /*
1192 * Return frame as given by a.
1193 */
1194 NODE *
builtin_frame_address(const struct bitable * bt,NODE * a)1195 builtin_frame_address(const struct bitable *bt, NODE *a)
1196 {
1197 int nframes;
1198 NODE *f;
1199
1200 nframes = a->n_lval;
1201 tfree(a);
1202
1203 f = block(REG, NIL, NIL, PTR+VOID, 0, 0);
1204 regno(f) = FPREG;
1205
1206 while (nframes--)
1207 f = block(UMUL, f, NIL, PTR+VOID, 0, 0);
1208
1209 return f;
1210 }
1211
1212 /*
1213 * Return "canonical frame address".
1214 */
1215 NODE *
builtin_cfa(const struct bitable * bt,NODE * a)1216 builtin_cfa(const struct bitable *bt, NODE *a)
1217 {
1218 NODE *f;
1219
1220 f = block(REG, NIL, NIL, PTR+VOID, 0, 0);
1221 regno(f) = FPREG;
1222 return block(PLUS, f, bcon(16), INCREF(PTR+VOID), 0, 0);
1223 }
1224
1225 int codeatyp(NODE *);
1226 int
codeatyp(NODE * p)1227 codeatyp(NODE *p)
1228 {
1229 TWORD t;
1230 int typ;
1231
1232 ngpr = nsse = 0;
1233 t = DECREF(p->n_type);
1234 if (ISSOU(t) == 0) {
1235 p = p->n_left;
1236 t = DECREF(DECREF(p->n_type));
1237 }
1238 if (ISSOU(t) == 0)
1239 cerror("codeatyp");
1240 typ = argtyp(t, p->n_df, p->n_ap);
1241 return typ;
1242 }
1243