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 (at) 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 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 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 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 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 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 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 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 * 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 * 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 * 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 * 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 * 696 amd64_builtin_va_end(const struct bitable *bt, NODE *a) 697 { 698 tfree(a); 699 return bcon(0); /* nothing */ 700 } 701 702 NODE * 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 * 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 * 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 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 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 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 * 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 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 * 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 1166 fldty(struct symtab *p) 1167 { 1168 } 1169 1170 /* 1171 * XXX - fix genswitch. 1172 */ 1173 int 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 * 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 * 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 * 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 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