1 /* Id: code.c,v 1.85 2015/12/13 09:00:04 ragge Exp */
2 /* $NetBSD: code.c,v 1.3 2016/02/09 20:37:32 plunky Exp $ */
3 /*
4 * Copyright (c) 2008 Michael Shalayeff
5 * Copyright (c) 2003 Anders Magnusson (ragge@ludd.luth.se).
6 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * 3. The name of the author may not be used to endorse or promote products
17 * derived from this software without specific prior written permission
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
20 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
21 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
22 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
23 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
24 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
28 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 */
30
31
32 # include "pass1.h"
33
34 #ifndef LANG_CXX
35 #undef NIL
36 #define NIL NULL
37 #define NODE P1ND
38 #define nfree p1nfree
39 #define ccopy p1tcopy
40 #define tfree p1tfree
41 #endif
42
43 static int nsse, ngpr, nrsp, rsaoff;
44 static int thissse, thisgpr, thisrsp;
45 enum { INTEGER = 1, INTMEM, SSE, SSEMEM, X87,
46 STRREG, STRMEM, STRSSE, STRIF, STRFI, STRX87 };
47 static const int argregsi[] = { RDI, RSI, RDX, RCX, R08, R09 };
48 /*
49 * The Register Save Area looks something like this.
50 * It is put first on stack with fixed offsets.
51 * struct {
52 * long regs[6];
53 * double xmm[8][2]; // 16 byte in width
54 * };
55 */
56 #define RSASZ (6*SZLONG+8*2*SZDOUBLE)
57 #define RSALONGOFF(x) (RSASZ-(x)*SZLONG)
58 #define RSADBLOFF(x) ((8*2*SZDOUBLE)-(x)*SZDOUBLE*2)
59 /* va_list */
60 #define VAARGSZ (SZINT*2+SZPOINT(CHAR)*2)
61 #define VAGPOFF(x) (x)
62 #define VAFPOFF(x) (x-SZINT)
63 #define VAOFA(x) (x-SZINT-SZINT)
64 #define VARSA(x) (x-SZINT-SZINT-SZPOINT(0))
65
66 static int stroffset;
67
68 static int varneeds;
69 #define NEED_1FPREF 001
70 #define NEED_2FPREF 002
71 #define NEED_1REGREF 004
72 #define NEED_2REGREF 010
73 #define NEED_MEMREF 020
74 #define NEED_STRFI 040
75 #define NEED_STRIF 0100
76
77 static int argtyp(TWORD t, union dimfun *df, struct attr *ap);
78 static NODE *movtomem(NODE *p, int off, int reg);
79 static NODE *movtoreg(NODE *p, int rno);
80 void varattrib(char *name, struct attr *sap);
81
82 /*
83 * Print out assembler segment name.
84 */
85 #ifdef MACHOABI
86 void
setseg(int seg,char * name)87 setseg(int seg, char *name)
88 {
89 switch (seg) {
90 case PROG: name = ".text"; break;
91 case DATA:
92 case LDATA: name = ".data"; break;
93 case RDATA: name = ".const"; break;
94 case STRNG: name = ".cstring"; break;
95 case UDATA: break;
96 case CTORS: name = ".mod_init_func"; break;
97 case DTORS: name = ".mod_term_func"; break;
98 default:
99 cerror("unknown seg %d", seg);
100 }
101 printf("\t%s\n", name);
102 }
103
104 #else
105 void
setseg(int seg,char * name)106 setseg(int seg, char *name)
107 {
108 switch (seg) {
109 case PROG: name = ".text"; break;
110 case DATA:
111 case LDATA: name = ".data"; break;
112 case STRNG:
113 case RDATA: name = ".section .rodata"; break;
114 case UDATA: break;
115 case PICLDATA:
116 case PICDATA: name = ".section .data.rel.rw,\"aw\",@progbits"; break;
117 case PICRDATA: name = ".section .data.rel.ro,\"aw\",@progbits"; break;
118 case TLSDATA: name = ".section .tdata,\"awT\",@progbits"; break;
119 case TLSUDATA: name = ".section .tbss,\"awT\",@nobits"; break;
120 case CTORS: name = ".section\t.ctors,\"aw\",@progbits"; break;
121 case DTORS: name = ".section\t.dtors,\"aw\",@progbits"; break;
122 case NMSEG:
123 printf("\t.section %s,\"a%c\",@progbits\n", name,
124 cftnsp ? 'x' : 'w');
125 return;
126 }
127 printf("\t%s\n", name);
128 }
129 #endif
130
131 /*
132 * Define everything needed to print out some data (or text).
133 * This means segment, alignment, visibility, etc.
134 */
135 void
defloc(struct symtab * sp)136 defloc(struct symtab *sp)
137 {
138 char *name;
139
140 name = getexname(sp);
141
142 if (sp->sclass == EXTDEF) {
143 printf("\t.globl %s\n", name);
144 #ifndef MACHOABI
145 if (ISFTN(sp->stype)) {
146 printf("\t.type %s,@function\n", name);
147 } else {
148 printf("\t.type %s,@object\n", name);
149 printf("\t.size %s,%d\n", name,
150 (int)tsize(sp->stype, sp->sdf, sp->sap)/SZCHAR);
151 }
152 #endif
153 }
154 if (sp->slevel == 0)
155 printf("%s:\n", name);
156 else
157 printf(LABFMT ":\n", sp->soffset);
158 }
159
160 /*
161 * code for the end of a function
162 * deals with struct return here
163 * The return value is in (or pointed to by) RETREG.
164 */
165 void
efcode(void)166 efcode(void)
167 {
168 struct symtab *sp;
169 extern int gotnr;
170 TWORD t;
171 NODE *p, *r, *l;
172 int typ;
173
174 gotnr = 0; /* new number for next fun */
175 sp = cftnsp;
176 t = DECREF(sp->stype);
177 if (t != STRTY && t != UNIONTY)
178 return;
179
180 /* XXX should have one routine for this */
181 ngpr = nsse = 0;
182 typ = argtyp(t, sp->sdf, sp->sap);
183 if (typ == STRMEM) {
184 r = block(REG, NIL, NIL, INCREF(t), sp->sdf, sp->sap);
185 regno(r) = RAX;
186 r = buildtree(UMUL, r, NIL);
187 l = tempnode(stroffset, INCREF(t), sp->sdf, sp->sap);
188 l = buildtree(UMUL, l, NIL);
189 ecomp(buildtree(ASSIGN, l, r));
190 l = block(REG, NIL, NIL, LONG, 0, 0);
191 regno(l) = RAX;
192 r = tempnode(stroffset, LONG, 0, 0);
193 ecomp(buildtree(ASSIGN, l, r));
194 } else if (typ == STRX87) {
195 p = block(REG, NIL, NIL, INCREF(LDOUBLE), 0, 0);
196 regno(p) = RAX;
197 p = buildtree(UMUL, buildtree(PLUS, p, bcon(1)), NIL);
198 ecomp(movtoreg(p, 041));
199 p = block(REG, NIL, NIL, INCREF(LDOUBLE), 0, 0);
200 regno(p) = RAX;
201 p = buildtree(UMUL, p, NIL);
202 ecomp(movtoreg(p, 040));
203 } else {
204 TWORD t1, t2;
205 int r1, r2;
206 if (typ == STRSSE || typ == STRFI)
207 r1 = XMM0, t1 = DOUBLE;
208 else
209 r1 = RAX, t1 = LONG;
210 if (typ == STRSSE)
211 r2 = XMM1, t2 = DOUBLE;
212 else if (typ == STRFI)
213 r2 = RAX, t2 = LONG;
214 else if (typ == STRIF)
215 r2 = XMM0, t2 = DOUBLE;
216 else /* if (typ == STRREG) */
217 r2 = RDX, t2 = LONG;
218
219 if (tsize(t, sp->sdf, sp->sap) > SZLONG) {
220 p = block(REG, NIL, NIL, INCREF(t2), 0, 0);
221 regno(p) = RAX;
222 p = buildtree(UMUL, buildtree(PLUS, p, bcon(1)), NIL);
223 ecomp(movtoreg(p, r2));
224 }
225 p = block(REG, NIL, NIL, INCREF(t1), 0, 0);
226 regno(p) = RAX;
227 p = buildtree(UMUL, p, NIL);
228 ecomp(movtoreg(p, r1));
229 }
230 }
231
232 /*
233 * code for the beginning of a function; a is an array of
234 * indices in symtab for the arguments; n is the number
235 */
236 void
bfcode(struct symtab ** s,int cnt)237 bfcode(struct symtab **s, int cnt)
238 {
239 union arglist *al;
240 struct symtab *sp;
241 NODE *p, *r;
242 TWORD t;
243 int i, rno, typ, ssz;
244
245 /* recalculate the arg offset and create TEMP moves */
246 /* Always do this for reg, even if not optimizing, to free arg regs */
247 nsse = ngpr = 0;
248 nrsp = ARGINIT;
249 if (cftnsp->stype == STRTY+FTN || cftnsp->stype == UNIONTY+FTN) {
250 sp = cftnsp;
251 if (argtyp(DECREF(sp->stype), sp->sdf, sp->sap) == STRMEM) {
252 r = block(REG, NIL, NIL, LONG, 0, 0);
253 regno(r) = argregsi[ngpr++];
254 p = tempnode(0, r->n_type, r->n_df, r->n_ap);
255 stroffset = regno(p);
256 ecomp(buildtree(ASSIGN, p, r));
257 }
258 }
259
260 for (i = 0; i < cnt; i++) {
261 sp = s[i];
262
263 if (sp == NULL)
264 continue; /* XXX when happens this? */
265
266 ssz = tsize(sp->stype, sp->sdf, sp->sap);
267 switch (typ = argtyp(sp->stype, sp->sdf, sp->sap)) {
268 case INTEGER:
269 case SSE:
270 if (typ == SSE)
271 rno = XMM0 + nsse++;
272 else
273 rno = argregsi[ngpr++];
274 r = block(REG, NIL, NIL, sp->stype, sp->sdf, sp->sap);
275 regno(r) = rno;
276 p = tempnode(0, sp->stype, sp->sdf, sp->sap);
277 sp->soffset = regno(p);
278 sp->sflags |= STNODE;
279 ecomp(buildtree(ASSIGN, p, r));
280 break;
281
282 case SSEMEM:
283 sp->soffset = nrsp;
284 nrsp += SZDOUBLE;
285 if (xtemps) {
286 p = tempnode(0, sp->stype, sp->sdf, sp->sap);
287 p = buildtree(ASSIGN, p, nametree(sp));
288 sp->soffset = regno(p->n_left);
289 sp->sflags |= STNODE;
290 ecomp(p);
291 }
292 break;
293
294 case INTMEM:
295 sp->soffset = nrsp;
296 nrsp += SZLONG;
297 if (xtemps) {
298 p = tempnode(0, sp->stype, sp->sdf, sp->sap);
299 p = buildtree(ASSIGN, p, nametree(sp));
300 sp->soffset = regno(p->n_left);
301 sp->sflags |= STNODE;
302 ecomp(p);
303 }
304 break;
305
306 case STRX87:
307 case STRMEM: /* Struct in memory */
308 sp->soffset = nrsp;
309 nrsp += ssz;
310 break;
311
312 case X87: /* long double args */
313 sp->soffset = nrsp;
314 nrsp += SZLDOUBLE;
315 break;
316
317 case STRFI:
318 case STRIF:
319 case STRSSE:
320 case STRREG: /* Struct in register */
321 autooff += (2*SZLONG);
322
323 if (typ == STRSSE || typ == STRFI) {
324 rno = XMM0 + nsse++;
325 t = DOUBLE;
326 } else {
327 rno = argregsi[ngpr++];
328 t = LONG;
329 }
330 r = block(REG, NIL, NIL, t, 0, 0);
331 regno(r) = rno;
332 ecomp(movtomem(r, -autooff, FPREG));
333
334 if (ssz > SZLONG) {
335 if (typ == STRSSE || typ == STRIF) {
336 rno = XMM0 + nsse++;
337 t = DOUBLE;
338 } else {
339 rno = argregsi[ngpr++];
340 t = LONG;
341 }
342 r = block(REG, NIL, NIL, t, 0, 0);
343 regno(r) = rno;
344 ecomp(movtomem(r, -autooff+SZLONG, FPREG));
345 }
346 sp->soffset = -autooff;
347 break;
348
349 default:
350 cerror("bfcode: %d", typ);
351 }
352 }
353
354 /* Check if there are varargs */
355 if (cftnsp->sdf == NULL || cftnsp->sdf->dfun == NULL)
356 return; /* no prototype */
357 al = cftnsp->sdf->dfun;
358
359 for (; al->type != TELLIPSIS; al++) {
360 t = al->type;
361 if (t == TNULL)
362 return;
363 if (ISSOU(BTYPE(t)))
364 al++;
365 for (i = 0; t > BTMASK; t = DECREF(t))
366 if (ISARY(t) || ISFTN(t))
367 i++;
368 if (i)
369 al++;
370 }
371
372 /* fix stack offset */
373 SETOFF(autooff, ALMAX);
374
375 /* Save reg arguments in the reg save area */
376 p = NIL;
377 for (i = ngpr; i < 6; i++) {
378 r = block(REG, NIL, NIL, LONG, 0, 0);
379 regno(r) = argregsi[i];
380 r = movtomem(r, -RSALONGOFF(i)-autooff, FPREG);
381 p = (p == NIL ? r : block(COMOP, p, r, INT, 0, 0));
382 }
383 for (i = nsse; i < 8; i++) {
384 r = block(REG, NIL, NIL, DOUBLE, 0, 0);
385 regno(r) = i + XMM0;
386 r = movtomem(r, -RSADBLOFF(i)-autooff, FPREG);
387 p = (p == NIL ? r : block(COMOP, p, r, INT, 0, 0));
388 }
389 autooff += RSASZ;
390 rsaoff = autooff;
391 thissse = nsse;
392 thisgpr = ngpr;
393 thisrsp = nrsp;
394
395 ecomp(p);
396 }
397
398
399 /* called just before final exit */
400 /* flag is 1 if errors, 0 if none */
401 void
ejobcode(int flag)402 ejobcode(int flag)
403 {
404 if (flag)
405 return;
406
407 #ifdef MACHOABI
408 #define PT(x)
409 #else
410 #define PT(x) printf(".type __pcc_" x ",@function\n")
411 #endif
412
413 #define P(x) printf(x "\n")
414 /* printout varargs routines if used */
415 if (varneeds & NEED_STRFI) { /* struct with one float and then int */
416 P(".text\n.align 4");
417 PT("strif");
418 P("__pcc_strif:");
419 P("cmpl $176,4(%%rdi)\njae .Ladd16");
420 P("cmpl $48,(%%rdi)\njae .Ladd16\n");
421 P("movl 4(%%rdi),%%eax\naddq 16(%%rdi),%%rax");
422 P("movq (%%rax),%%rdx\nmovq %%rdx,24(%%rdi)");
423 P("movl (%%rdi),%%eax\naddq 16(%%rdi),%%rax");
424 P("movq 16(%%rax),%%rdx\nmovq %%rdx,32(%%rdi)");
425 P("leaq 24(%%rdi),%%rax\nret");
426 }
427 if (varneeds & NEED_STRIF) { /* struct with one int and one float */
428 P(".text\n.align 4");
429 PT("strif");
430 P("__pcc_strif:");
431 P("cmpl $176,4(%%rdi)\njae .Ladd16");
432 P("cmpl $48,(%%rdi)\njae .Ladd16\n");
433 P("movl (%%rdi),%%eax\naddq 16(%%rdi),%%rax");
434 P("movq (%%rax),%%rdx\nmovq %%rdx,24(%%rdi)");
435 P("movl 4(%%rdi),%%eax\naddq 16(%%rdi),%%rax");
436 P("movq 16(%%rax),%%rdx\nmovq %%rdx,32(%%rdi)");
437 P("leaq 24(%%rdi),%%rax\nret");
438 }
439 if (varneeds & NEED_2FPREF) { /* struct with two float regs */
440 P(".text\n.align 4");
441 PT("2fpref");
442 P("__pcc_2fpref:");
443 P("cmpl $160,4(%%rdi)\njae .Ladd16");
444 P("movl 4(%%rdi),%%eax\naddq 16(%%rdi),%%rax");
445 P("addl $32,4(%%rdi)");
446 P("movq (%%rax),%%rdx\nmovq %%rdx,24(%%rdi)");
447 P("movq 16(%%rax),%%rdx\nmovq %%rdx,32(%%rdi)");
448 P("leaq 24(%%rdi),%%rax\nret");
449 }
450 if (varneeds & NEED_1FPREF) {
451 printf(".text\n.align 4\n");
452 PT("1fpref");
453 printf("__pcc_1fpref:\n");
454 printf("cmpl $176,4(%%rdi)\njae .Ladd8\n");
455 printf("movl 4(%%rdi),%%eax\naddq 16(%%rdi),%%rax\n");
456 printf("addl $16,4(%%rdi)\nret\n");
457 }
458 if (varneeds & NEED_1REGREF) {
459 printf(".text\n.align 4\n");
460 PT("1regref");
461 printf("__pcc_1regref:\n");
462 printf("cmpl $48,(%%rdi)\njae .Ladd8\n");
463 printf("movl (%%rdi),%%eax\naddq 16(%%rdi),%%rax\n");
464 printf("addl $8,(%%rdi)\nret\n");
465 }
466 if (varneeds & NEED_2REGREF) {
467 printf(".text\n.align 4\n");
468 PT("2regref");
469 printf("__pcc_2regref:\n");
470 printf("cmpl $40,(%%rdi)\njae .Ladd16\n");
471 printf("movl (%%rdi),%%eax\naddq 16(%%rdi),%%rax\n");
472 printf("addl $16,(%%rdi)\nret\n");
473 }
474 if (varneeds & NEED_MEMREF) {
475 printf(".text\n.align 4\n");
476 PT("memref");
477 printf("__pcc_memref:\n");
478 printf("movq 8(%%rdi),%%rax\n");
479 printf("addq %%rsi,8(%%rdi)\nret\n");
480 }
481
482 if (varneeds & (NEED_1FPREF|NEED_1REGREF)) {
483 P(".Ladd8:");
484 P("movq 8(%%rdi),%%rax");
485 P("addq $8,8(%%rdi)");
486 P("ret");
487 }
488 if (varneeds & (NEED_2FPREF|NEED_2REGREF|NEED_STRFI|NEED_STRIF)) {
489 P(".Ladd16:");
490 P("movq 8(%%rdi),%%rax");
491 P("addq $16,8(%%rdi)");
492 P("ret");
493 }
494
495 #ifdef MACHOABI
496 printf("\t.ident \"PCC: %s\"\n", VERSSTR);
497 #else
498 printf("\t.ident \"PCC: %s\"\n\t.end\n", VERSSTR);
499 #endif
500 }
501
502 /*
503 * Varargs stuff:
504 * The ABI says that va_list should be declared as this typedef.
505 * We handcraft it here and then just reference it.
506 *
507 * typedef struct {
508 * unsigned int gp_offset;
509 * unsigned int fp_offset;
510 * void *overflow_arg_area;
511 * void *reg_save_area;
512 * } __builtin_va_list[1];
513 *
514 * ...actually, we allocate two of them and use the second one as
515 * bounce buffers for floating point structs...
516 *
517 * There are a number of asm routines printed out if varargs are used:
518 * long __pcc_gpnext(va) - get a gpreg value
519 * long __pcc_fpnext(va) - get a fpreg value
520 * void *__pcc_1regref(va) - get reference to a onereg struct
521 * void *__pcc_2regref(va) - get reference to a tworeg struct
522 * void *__pcc_memref(va,sz) - get reference to a large struct
523 */
524
525 static char *gp_offset, *fp_offset, *overflow_arg_area, *reg_save_area;
526 static char *_1fpref, *_2fpref, *_1regref, *_2regref, *memref;
527 static char *strif, *strfi;
528
529 void
bjobcode(void)530 bjobcode(void)
531 {
532 struct symtab *sp;
533 struct rstack *rp;
534 NODE *p, *q;
535 char *c;
536
537 #if defined(__GNUC__) || defined(__PCC__)
538 /* Be sure that the compiler uses full x87 */
539 /* XXX cross-compiling will fail here */
540 int fcw = 0;
541 __asm("fstcw (%0)" : : "r"(&fcw));
542 fcw |= 0x33f;
543 __asm("fldcw (%0)" : : "r"(&fcw));
544 #endif
545
546 /* amd64 names for some asm constant printouts */
547 astypnames[INT] = astypnames[UNSIGNED] = "\t.long";
548 astypnames[LONG] = astypnames[ULONG] = "\t.quad";
549
550 gp_offset = addname("gp_offset");
551 fp_offset = addname("fp_offset");
552 overflow_arg_area = addname("overflow_arg_area");
553 reg_save_area = addname("reg_save_area");
554
555 rp = bstruct(NULL, STNAME, NULL);
556 p = block(NAME, NIL, NIL, UNSIGNED, 0, 0);
557 soumemb(p, gp_offset, 0);
558 soumemb(p, fp_offset, 0);
559 p->n_type = VOID+PTR;
560 p->n_ap = NULL;
561 soumemb(p, overflow_arg_area, 0);
562 soumemb(p, reg_save_area, 0);
563 nfree(p);
564 q = dclstruct(rp);
565 c = addname("__builtin_va_list");
566 p = block(LB, bdty(NAME, c), bcon(2), INT, 0, 0);
567 p = tymerge(q, p);
568 p->n_sp = lookup(c, 0);
569 defid(p, TYPEDEF);
570 nfree(q);
571 nfree(p);
572
573 /* for the static varargs functions */
574 #define MKN(vn, rn) \
575 { vn = addname(rn); sp = lookup(vn, SNORMAL); \
576 sp->sclass = USTATIC; sp->stype = FTN|VOID|(PTR<<TSHIFT); }
577
578 MKN(strfi, "__pcc_strfi");
579 MKN(strif, "__pcc_strif");
580 MKN(_1fpref, "__pcc_1fpref");
581 MKN(_2fpref, "__pcc_2fpref");
582 MKN(_1regref, "__pcc_1regref");
583 MKN(_2regref, "__pcc_2regref");
584 MKN(memref, "__pcc_memref");
585 }
586
587 static NODE *
mkstkref(int off,TWORD typ)588 mkstkref(int off, TWORD typ)
589 {
590 NODE *p;
591
592 p = block(REG, NIL, NIL, PTR|typ, 0, 0);
593 regno(p) = FPREG;
594 return buildtree(PLUS, p, bcon(off/SZCHAR));
595 }
596
597 NODE *
amd64_builtin_stdarg_start(const struct bitable * bt,NODE * a)598 amd64_builtin_stdarg_start(const struct bitable *bt, NODE *a)
599 {
600 NODE *p, *r;
601
602 /* use the values from the function header */
603 p = a->n_left;
604 r = buildtree(ASSIGN, structref(ccopy(p), STREF, reg_save_area),
605 mkstkref(-rsaoff, VOID));
606 r = buildtree(COMOP, r,
607 buildtree(ASSIGN, structref(ccopy(p), STREF, overflow_arg_area),
608 mkstkref(thisrsp, VOID)));
609 r = buildtree(COMOP, r,
610 buildtree(ASSIGN, structref(ccopy(p), STREF, gp_offset),
611 bcon(thisgpr*(SZLONG/SZCHAR))));
612 r = buildtree(COMOP, r,
613 buildtree(ASSIGN, structref(ccopy(p), STREF, fp_offset),
614 bcon(thissse*(SZDOUBLE*2/SZCHAR)+48)));
615
616 tfree(a);
617 return r;
618 }
619
620 static NODE *
mkvacall(char * fun,NODE * a,int typ)621 mkvacall(char *fun, NODE *a, int typ)
622 {
623 NODE *r, *f = block(NAME, NIL, NIL, INT, 0, 0);
624 NODE *ap = a->n_left;
625 NODE *dp = a->n_right;
626 int sz = tsize(dp->n_type, dp->n_df, dp->n_ap);
627
628 f->n_sp = lookup(fun, SNORMAL);
629 varneeds |= typ;
630 f->n_type = f->n_sp->stype;
631 f = clocal(f);
632 SETOFF(sz, ALLONG);
633 r = buildtree(CALL, f,
634 buildtree(CM, ccopy(ap), bcon(sz/SZCHAR)));
635 r = ccast(r, INCREF(dp->n_type), 0, dp->n_df, dp->n_ap);
636 r = buildtree(UMUL, r, NIL);
637 return r;
638 }
639
640 NODE *
amd64_builtin_va_arg(const struct bitable * bt,NODE * a)641 amd64_builtin_va_arg(const struct bitable *bt, NODE *a)
642 {
643 NODE *r, *dp;
644 int typ, sz;
645
646 dp = a->n_right;
647
648 nsse = ngpr = 0;
649 sz = tsize(dp->n_type, dp->n_df, dp->n_ap);
650 switch (typ = argtyp(dp->n_type, dp->n_df, dp->n_ap)) {
651 case INTEGER:
652 r = mkvacall(_1regref, a, NEED_1REGREF);
653 break;
654
655 case SSE:
656 r = mkvacall(_1fpref, a, NEED_1FPREF);
657 break;
658
659 default:
660 cerror("va_arg: bad type %d", typ);
661
662 case X87:
663 case STRX87:
664 case STRMEM: /* stored in memory */
665 r = mkvacall(memref, a, NEED_MEMREF);
666 break;
667
668 case STRREG: /* struct in general regs */
669 if (sz <= SZLONG)
670 r = mkvacall(_1regref, a, NEED_1REGREF);
671 else
672 r = mkvacall(_2regref, a, NEED_2REGREF);
673 break;
674
675 case STRSSE:
676 if (sz <= SZLONG)
677 r = mkvacall(_1fpref, a, NEED_1FPREF);
678 else
679 r = mkvacall(_2fpref, a, NEED_2FPREF);
680 break;
681
682 case STRIF:
683 r = mkvacall(strif, a, NEED_STRIF);
684 break;
685
686 case STRFI:
687 r = mkvacall(strfi, a, NEED_STRFI);
688 break;
689 }
690
691 tfree(a);
692 return r;
693 }
694
695 NODE *
amd64_builtin_va_end(const struct bitable * bt,NODE * a)696 amd64_builtin_va_end(const struct bitable *bt, NODE *a)
697 {
698 tfree(a);
699 return bcon(0); /* nothing */
700 }
701
702 NODE *
amd64_builtin_va_copy(const struct bitable * bt,NODE * a)703 amd64_builtin_va_copy(const struct bitable *bt, NODE *a)
704 {
705 NODE *f;
706
707 f = buildtree(ASSIGN, buildtree(UMUL, a->n_left, NIL),
708 buildtree(UMUL, a->n_right, NIL));
709 nfree(a);
710 return f;
711 }
712
713 static NODE *
movtoreg(NODE * p,int rno)714 movtoreg(NODE *p, int rno)
715 {
716 NODE *r;
717
718 r = block(REG, NIL, NIL, p->n_type, p->n_df, p->n_ap);
719 regno(r) = rno;
720 return clocal(buildtree(ASSIGN, r, p));
721 }
722
723 static NODE *
movtomem(NODE * p,int off,int reg)724 movtomem(NODE *p, int off, int reg)
725 {
726 struct symtab s;
727 NODE *r, *l;
728
729 s.stype = p->n_type;
730 s.squal = 0;
731 s.sdf = p->n_df;
732 s.sap = p->n_ap;
733 s.soffset = off;
734 s.sclass = AUTO;
735
736 l = block(REG, NIL, NIL, PTR+STRTY, 0, 0);
737 slval(l, 0);
738 regno(l) = reg;
739
740 r = block(NAME, NIL, NIL, p->n_type, p->n_df, p->n_ap);
741 r->n_sp = &s;
742 r = stref(block(STREF, l, r, 0, 0, 0));
743
744 return clocal(buildtree(ASSIGN, r, p));
745 }
746
747 /*
748 * Check what to do with a struct. We traverse down in the struct to
749 * find which types it is and where the struct really should be.
750 * The return vals we may end up with are:
751 * STRREG - The whole struct is saved in general registers.
752 * STRMEM - the struct is saved in memory.
753 * STRSSE - the whole struct is saved in SSE registers.
754 * STRIF - First word of struct is saved in general reg, other SSE.
755 * STRFI - First word of struct is saved in SSE, next in general reg.
756 *
757 * - If size > 16 bytes or there are packed fields, use memory.
758 * - If any part of an eight-byte should be in a general register,
759 * the eight-byte is stored in a general register
760 * - If the eight-byte only contains float or double, use a SSE register
761 * - Otherwise use memory.
762 *
763 * Arrays must be broken up as separate elements, since the elements
764 * are classified separately. For example;
765 * struct s { short s; float f[3]; } S;
766 * will have the first 64 bits passed in general reg and the second in SSE.
767 *
768 * sp below is a pointer to a member list.
769 * off tells whether is is the first or second eight-byte to check.
770 */
771 static int
classifystruct(struct symtab * sp,int off)772 classifystruct(struct symtab *sp, int off)
773 {
774 struct symtab sps[16];
775 union dimfun *df;
776 TWORD t;
777 int cl, cl2, sz, i;
778
779
780 for (cl = 0; sp; sp = sp->snext) {
781 t = sp->stype;
782
783 /* fake a linked list of all array members */
784 if (ISARY(t)) {
785 sz = 1;
786 df = sp->sdf;
787 do {
788 sz *= df->ddim;
789 t = DECREF(t);
790 df++;
791 } while (ISARY(t));
792 for (i = 0; i < sz; i++) {
793 sps[i] = *sp;
794 sps[i].stype = t;
795 sps[i].sdf = df;
796 sps[i].snext = &sps[i+1];
797 sps[i].soffset = i * tsize(t, df, sp->sap);
798 sps[i].soffset += sp->soffset;
799 }
800 sps[i-1].snext = sp->snext;
801 sp = &sps[0];
802 }
803
804 if (off == 0) {
805 if (sp->soffset >= SZLONG)
806 continue;
807 } else {
808 if (sp->soffset < SZLONG)
809 continue;
810 }
811
812 if (t <= ULONGLONG || ISPTR(t)) {
813 if (cl == 0 || cl == STRSSE)
814 cl = STRREG;
815 } else if (t <= DOUBLE) {
816 if (cl == 0)
817 cl = STRSSE;
818 } else if (t == LDOUBLE) {
819 return STRMEM;
820 } else if (ISSOU(t)) {
821 #ifdef GCC_COMPAT
822 if (attr_find(sp->sap, GCC_ATYP_PACKED)) {
823 cl = STRMEM;
824 } else
825 #endif
826 {
827 cl2 = classifystruct(strmemb(sp->sap), off);
828 if (cl2 == STRMEM) {
829 cl = STRMEM;
830 } else if (cl2 == STRREG) {
831 if (cl == 0 || cl == STRSSE)
832 cl = STRREG;
833 } else if (cl2 == STRSSE) {
834 if (cl == 0)
835 cl = STRSSE;
836 }
837 }
838 } else
839 cerror("classifystruct: unknown type %x", t);
840 if (cl == STRMEM)
841 break;
842 }
843 if (cl == 0)
844 cerror("classifystruct: failed classify");
845 return cl;
846 }
847
848 /*
849 * Check for long double complex structs.
850 */
851 static int
iscplx87(struct symtab * sp)852 iscplx87(struct symtab *sp)
853 {
854 if (sp->stype == LDOUBLE && sp->snext->stype == LDOUBLE &&
855 sp->snext->snext == NULL)
856 return STRX87;
857 return 0;
858 }
859
860 /*
861 * AMD64 parameter classification.
862 */
863 static int
argtyp(TWORD t,union dimfun * df,struct attr * ap)864 argtyp(TWORD t, union dimfun *df, struct attr *ap)
865 {
866 int cl2, cl = 0;
867
868 if (t <= ULONG || ISPTR(t) || t == BOOL) {
869 cl = ngpr < 6 ? INTEGER : INTMEM;
870 } else if (t == FLOAT || t == DOUBLE || t == FIMAG || t == IMAG) {
871 cl = nsse < 8 ? SSE : SSEMEM;
872 } else if (t == LDOUBLE || t == LIMAG) {
873 cl = X87; /* XXX */
874 } else if (t == STRTY || t == UNIONTY) {
875 int sz = tsize(t, df, ap);
876
877 #ifdef GCC_COMPAT
878 if (attr_find(ap, GCC_ATYP_PACKED)) {
879 cl = STRMEM;
880 } else
881 #endif
882 if (iscplx87(strmemb(ap)) == STRX87) {
883 cl = STRX87;
884 } else if (sz > 2*SZLONG) {
885 cl = STRMEM;
886 } else if (sz <= SZLONG) {
887 /* only one member to check */
888 cl = classifystruct(strmemb(ap), 0);
889 if (cl == STRREG && ngpr > 5)
890 cl = STRMEM;
891 else if (cl == STRSSE && nsse > 7)
892 cl = STRMEM;
893 } else {
894 cl = classifystruct(strmemb(ap), 0);
895 cl2 = classifystruct(strmemb(ap), 1);
896 if (cl == STRMEM || cl2 == STRMEM)
897 cl = STRMEM;
898 else if (cl == STRREG && cl2 == STRSSE)
899 cl = STRIF;
900 else if (cl2 == STRREG && cl == STRSSE)
901 cl = STRFI;
902
903 if (cl == STRREG && ngpr > 4)
904 cl = STRMEM;
905 else if (cl == STRSSE && nsse > 6)
906 cl = STRMEM;
907 else if ((cl == STRIF || cl == STRFI) &&
908 (ngpr > 5 || nsse > 7))
909 cl = STRMEM;
910 }
911 } else
912 cerror("FIXME: classify");
913 return cl;
914 }
915
916 /*
917 * Do the "hard work" in assigning correct destination for arguments.
918 * Also convert arguments < INT to inte (default argument promotions).
919 * XXX - should be dome elsewhere.
920 */
921 static NODE *
argput(NODE * p)922 argput(NODE *p)
923 {
924 NODE *q, *ql;
925 TWORD ty;
926 int typ, r, ssz, rn;
927
928 if (p->n_op == CM) {
929 p->n_left = argput(p->n_left);
930 p->n_right = argput(p->n_right);
931 return p;
932 }
933
934 /* first arg may be struct return pointer */
935 /* XXX - check if varargs; setup al */
936 switch (typ = argtyp(p->n_type, p->n_df, p->n_ap)) {
937 case INTEGER:
938 case SSE:
939 if (typ == SSE)
940 r = XMM0 + nsse++;
941 else
942 r = argregsi[ngpr++];
943 if (p->n_type < INT || p->n_type == BOOL)
944 p = cast(p, INT, 0);
945 p = movtoreg(p, r);
946 break;
947
948 case X87:
949 r = nrsp;
950 nrsp += SZLDOUBLE;
951 p = movtomem(p, r, STKREG);
952 break;
953
954 case SSEMEM:
955 r = nrsp;
956 nrsp += SZDOUBLE;
957 p = movtomem(p, r, STKREG);
958 break;
959
960 case INTMEM:
961 r = nrsp;
962 nrsp += SZLONG;
963 if (p->n_type < INT || p->n_type == BOOL)
964 p = cast(p, INT, 0);
965 p = movtomem(p, r, STKREG);
966 break;
967
968 case STRFI:
969 case STRIF:
970 case STRSSE:
971 case STRREG: /* Struct in registers */
972 /* Cast to long/sse pointer and move to the registers */
973 /* XXX can overrun struct size */
974 ssz = tsize(p->n_type, p->n_df, p->n_ap);
975
976 if (typ == STRSSE || typ == STRFI) {
977 r = XMM0 + nsse++;
978 ty = DOUBLE;
979 } else {
980 r = argregsi[ngpr++];
981 ty = LONG;
982 }
983
984 p = nfree(p); /* remove STARG */
985 p = makety(p, PTR|ty, 0, 0, 0);
986 ql = tempnode(0, PTR|ty, 0, 0);
987 rn = regno(ql);
988 p = buildtree(ASSIGN, ql, p);
989 ql = tempnode(rn, PTR|ty, 0, 0);
990 ql = movtoreg(buildtree(UMUL, ql, NIL), r);
991 p = buildtree(COMOP, p, ql);
992
993 if (ssz > SZLONG) {
994 if (typ == STRSSE || typ == STRIF) {
995 r = XMM0 + nsse++;
996 ty = DOUBLE;
997 } else {
998 r = argregsi[ngpr++];
999 ty = LONG;
1000 }
1001
1002 ql = tempnode(rn, PTR|ty, 0, 0);
1003 ql = buildtree(UMUL, buildtree(PLUS, ql, bcon(1)), NIL);
1004 ql = movtoreg(ql, r);
1005
1006 p = buildtree(CM, p, ql);
1007 }
1008 break;
1009
1010 case STRX87:
1011 case STRMEM: {
1012 struct symtab s;
1013 NODE *l, *t;
1014
1015 q = buildtree(UMUL, p->n_left, NIL);
1016
1017 s.stype = p->n_type;
1018 s.squal = 0;
1019 s.sdf = p->n_df;
1020 s.sap = p->n_ap;
1021 s.soffset = nrsp;
1022 s.sclass = AUTO;
1023
1024 nrsp += tsize(p->n_type, p->n_df, p->n_ap);
1025
1026 l = block(REG, NIL, NIL, PTR+STRTY, 0, 0);
1027 slval(l, 0);
1028 regno(l) = STKREG;
1029
1030 t = block(NAME, NIL, NIL, p->n_type, p->n_df, p->n_ap);
1031 t->n_sp = &s;
1032 t = stref(block(STREF, l, t, 0, 0, 0));
1033
1034 t = (buildtree(ASSIGN, t, q));
1035 nfree(p);
1036 p = t->n_left;
1037 nfree(t);
1038 break;
1039 }
1040
1041 default:
1042 cerror("argument %d", typ);
1043 }
1044 return p;
1045 }
1046
1047 /*
1048 * Sort arglist so that register assignments ends up last.
1049 */
1050 static int
argsort(NODE * p)1051 argsort(NODE *p)
1052 {
1053 NODE *q, *r;
1054 int rv = 0;
1055
1056 if (p->n_op != CM) {
1057 if (p->n_op == ASSIGN && p->n_left->n_op == REG &&
1058 coptype(p->n_right->n_op) != LTYPE) {
1059 q = tempnode(0, p->n_type, p->n_df, p->n_ap);
1060 r = ccopy(q);
1061 p->n_right = buildtree(COMOP,
1062 buildtree(ASSIGN, q, p->n_right), r);
1063 }
1064 return rv;
1065 }
1066 if (p->n_right->n_op == CM) {
1067 /* fixup for small structs in regs */
1068 q = p->n_right->n_left;
1069 p->n_right->n_left = p->n_left;
1070 p->n_left = p->n_right;
1071 p->n_right = p->n_left->n_right;
1072 p->n_left->n_right = q;
1073 }
1074 if (p->n_right->n_op == ASSIGN && p->n_right->n_left->n_op == REG &&
1075 coptype(p->n_right->n_right->n_op) != LTYPE) {
1076 /* move before everything to avoid reg trashing */
1077 q = tempnode(0, p->n_right->n_type,
1078 p->n_right->n_df, p->n_right->n_ap);
1079 r = ccopy(q);
1080 p->n_right->n_right = buildtree(COMOP,
1081 buildtree(ASSIGN, q, p->n_right->n_right), r);
1082 }
1083 if (p->n_right->n_op == ASSIGN && p->n_right->n_left->n_op == REG) {
1084 if (p->n_left->n_op == CM &&
1085 p->n_left->n_right->n_op == STASG) {
1086 q = p->n_left->n_right;
1087 p->n_left->n_right = p->n_right;
1088 p->n_right = q;
1089 rv = 1;
1090 } else if (p->n_left->n_op == STASG) {
1091 q = p->n_left;
1092 p->n_left = p->n_right;
1093 p->n_right = q;
1094 rv = 1;
1095 }
1096 }
1097 return rv | argsort(p->n_left);
1098 }
1099
1100 /*
1101 * Called with a function call with arguments as argument.
1102 * This is done early in buildtree() and only done once.
1103 * Returns p.
1104 */
1105 NODE *
funcode(NODE * p)1106 funcode(NODE *p)
1107 {
1108 NODE *l, *r;
1109 TWORD t;
1110 int i;
1111
1112 nsse = ngpr = nrsp = 0;
1113 /* Check if hidden arg needed */
1114 /* If so, add it in pass2 */
1115 if ((l = p->n_left)->n_type == INCREF(FTN)+STRTY ||
1116 l->n_type == INCREF(FTN)+UNIONTY) {
1117 int ssz = tsize(BTYPE(l->n_type), l->n_df, l->n_ap);
1118 struct symtab *sp = strmemb(l->n_ap);
1119 if (ssz == 2*SZLDOUBLE && sp->stype == LDOUBLE &&
1120 sp->snext->stype == LDOUBLE)
1121 ; /* long complex struct */
1122 else if (ssz > 2*SZLONG)
1123 ngpr++;
1124 }
1125
1126 /* Convert just regs to assign insn's */
1127 p->n_right = argput(p->n_right);
1128
1129 /* Must sort arglist so that STASG ends up first */
1130 /* This avoids registers being clobbered */
1131 while (argsort(p->n_right))
1132 ;
1133 /* Check if there are varargs */
1134 if (nsse || l->n_df == NULL || l->n_df->dfun == NULL) {
1135 ; /* Need RAX */
1136 } else {
1137 union arglist *al = l->n_df->dfun;
1138
1139 for (; al->type != TELLIPSIS; al++) {
1140 if ((t = al->type) == TNULL)
1141 return p; /* No need */
1142 if (ISSOU(BTYPE(t)))
1143 al++;
1144 for (i = 0; t > BTMASK; t = DECREF(t))
1145 if (ISARY(t) || ISFTN(t))
1146 i++;
1147 if (i)
1148 al++;
1149 }
1150 }
1151
1152 /* Always emit number of SSE regs used */
1153 l = movtoreg(bcon(nsse), RAX);
1154 if (p->n_right->n_op != CM) {
1155 p->n_right = block(CM, l, p->n_right, INT, 0, 0);
1156 } else {
1157 for (r = p->n_right; r->n_left->n_op == CM; r = r->n_left)
1158 ;
1159 r->n_left = block(CM, l, r->n_left, INT, 0, 0);
1160 }
1161 return p;
1162 }
1163
1164 /* fix up type of field p */
1165 void
fldty(struct symtab * p)1166 fldty(struct symtab *p)
1167 {
1168 }
1169
1170 /*
1171 * XXX - fix genswitch.
1172 */
1173 int
mygenswitch(int num,TWORD type,struct swents ** p,int n)1174 mygenswitch(int num, TWORD type, struct swents **p, int n)
1175 {
1176 return 0;
1177 }
1178
1179 /*
1180 * Return return as given by a.
1181 */
1182 NODE *
builtin_return_address(const struct bitable * bt,NODE * a)1183 builtin_return_address(const struct bitable *bt, NODE *a)
1184 {
1185 int nframes;
1186 NODE *f;
1187
1188 nframes = glval(a);
1189 tfree(a);
1190
1191 f = block(REG, NIL, NIL, PTR+VOID, 0, 0);
1192 regno(f) = FPREG;
1193
1194 while (nframes--)
1195 f = block(UMUL, f, NIL, PTR+VOID, 0, 0);
1196
1197 f = block(PLUS, f, bcon(8), INCREF(PTR+VOID), 0, 0);
1198 f = buildtree(UMUL, f, NIL);
1199
1200 return f;
1201 }
1202
1203 /*
1204 * Return frame as given by a.
1205 */
1206 NODE *
builtin_frame_address(const struct bitable * bt,NODE * a)1207 builtin_frame_address(const struct bitable *bt, NODE *a)
1208 {
1209 int nframes;
1210 NODE *f;
1211
1212 nframes = glval(a);
1213 tfree(a);
1214
1215 f = block(REG, NIL, NIL, PTR+VOID, 0, 0);
1216 regno(f) = FPREG;
1217
1218 while (nframes--)
1219 f = block(UMUL, f, NIL, PTR+VOID, 0, 0);
1220
1221 return f;
1222 }
1223
1224 /*
1225 * Return "canonical frame address".
1226 */
1227 NODE *
builtin_cfa(const struct bitable * bt,NODE * a)1228 builtin_cfa(const struct bitable *bt, NODE *a)
1229 {
1230 NODE *f;
1231
1232 f = block(REG, NIL, NIL, PTR+VOID, 0, 0);
1233 regno(f) = FPREG;
1234 return block(PLUS, f, bcon(16), INCREF(PTR+VOID), 0, 0);
1235 }
1236
1237 int codeatyp(NODE *);
1238 int
codeatyp(NODE * p)1239 codeatyp(NODE *p)
1240 {
1241 TWORD t;
1242 int typ;
1243
1244 ngpr = nsse = 0;
1245 t = DECREF(p->n_type);
1246 if (ISSOU(t) == 0) {
1247 p = p->n_left;
1248 t = DECREF(DECREF(p->n_type));
1249 }
1250 if (ISSOU(t) == 0)
1251 cerror("codeatyp");
1252 typ = argtyp(t, p->n_df, p->n_ap);
1253 return typ;
1254 }
1255