1 /* Id: code.c,v 1.22 2010/05/30 19:00:04 ragge Exp */ 2 /* $NetBSD: code.c,v 1.1.1.2 2010/06/03 18:57:07 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 static int nsse, ngpr, nrsp, rsaoff; 35 static int thissse, thisgpr, thisrsp; 36 enum { INTEGER = 1, INTMEM, SSE, SSEMEM, X87, STRREG, STRMEM }; 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 int lastloc = -1; 57 static int stroffset; 58 59 static int argtyp(TWORD t, union dimfun *df, struct suedef *sue); 60 static NODE *movtomem(NODE *p, int off, int reg); 61 static NODE *movtoreg(NODE *p, int rno); 62 63 /* 64 * Define everything needed to print out some data (or text). 65 * This means segment, alignment, visibility, etc. 66 */ 67 void 68 defloc(struct symtab *sp) 69 { 70 extern char *nextsect; 71 static char *loctbl[] = { "text", "data", "section .rodata" }; 72 int weak = 0; 73 char *name; 74 TWORD t; 75 int s; 76 77 if (sp == NULL) { 78 lastloc = -1; 79 return; 80 } 81 t = sp->stype; 82 s = ISFTN(t) ? PROG : ISCON(cqual(t, sp->squal)) ? RDATA : DATA; 83 if ((name = sp->soname) == NULL) 84 name = exname(sp->sname); 85 #ifdef TLS 86 if (sp->sflags & STLS) { 87 if (s != DATA) 88 cerror("non-data symbol in tls section"); 89 nextsect = ".tdata"; 90 } 91 #endif 92 #ifdef GCC_COMPAT 93 { 94 struct gcc_attrib *ga; 95 96 if ((ga = gcc_get_attr(sp->ssue, GCC_ATYP_SECTION)) != NULL) 97 nextsect = ga->a1.sarg; 98 if ((ga = gcc_get_attr(sp->ssue, GCC_ATYP_WEAK)) != NULL) 99 weak = 1; 100 if (gcc_get_attr(sp->ssue, GCC_ATYP_DESTRUCTOR)) { 101 printf("\t.section\t.dtors,\"aw\",@progbits\n"); 102 printf("\t.align 8\n\t.quad\t%s\n", name); 103 lastloc = -1; 104 } 105 if (gcc_get_attr(sp->ssue, GCC_ATYP_CONSTRUCTOR)) { 106 printf("\t.section\t.ctors,\"aw\",@progbits\n"); 107 printf("\t.align 8\n\t.quad\t%s\n", name); 108 lastloc = -1; 109 } 110 if ((ga = gcc_get_attr(sp->ssue, GCC_ATYP_VISIBILITY)) && 111 strcmp(ga->a1.sarg, "default")) 112 printf("\t.%s %s\n", ga->a1.sarg, name); 113 } 114 #endif 115 116 if (nextsect) { 117 printf(" .section %s\n", nextsect); 118 nextsect = NULL; 119 s = -1; 120 } else if (s != lastloc) 121 printf(" .%s\n", loctbl[s]); 122 lastloc = s; 123 while (ISARY(t)) 124 t = DECREF(t); 125 s = ISFTN(t) ? ALINT : talign(t, sp->ssue); 126 if (s > ALCHAR) 127 printf(" .align %d\n", s/ALCHAR); 128 if (weak) 129 printf(" .weak %s\n", name); 130 else if (sp->sclass == EXTDEF) { 131 printf("\t.globl %s\n", name); 132 printf("\t.type %s,@%s\n", name, 133 ISFTN(t)? "function" : "object"); 134 } 135 if (sp->slevel == 0) 136 printf("%s:\n", name); 137 else 138 printf(LABFMT ":\n", sp->soffset); 139 } 140 141 /* 142 * code for the end of a function 143 * deals with struct return here 144 */ 145 void 146 efcode() 147 { 148 struct symtab *sp; 149 extern int gotnr; 150 TWORD t; 151 NODE *p, *r, *l; 152 int o; 153 154 gotnr = 0; /* new number for next fun */ 155 sp = cftnsp; 156 t = DECREF(sp->stype); 157 if (t != STRTY && t != UNIONTY) 158 return; 159 if (argtyp(t, sp->sdf, sp->ssue) != STRMEM) 160 return; 161 162 /* call memcpy() to put return struct at destination */ 163 #define cmop(x,y) block(CM, x, y, INT, 0, MKSUE(INT)) 164 r = tempnode(stroffset, INCREF(t), sp->sdf, sp->ssue); 165 l = block(REG, NIL, NIL, INCREF(t), sp->sdf, sp->ssue); 166 regno(l) = RAX; 167 o = tsize(t, sp->sdf, sp->ssue)/SZCHAR; 168 r = cmop(cmop(r, l), bcon(o)); 169 170 blevel++; /* Remove prototype at exit of function */ 171 sp = lookup(addname("memcpy"), 0); 172 if (sp->stype == UNDEF) { 173 sp->ssue = MKSUE(VOID); 174 p = talloc(); 175 p->n_op = NAME; 176 p->n_sp = sp; 177 p->n_sue = sp->ssue; 178 p->n_type = VOID|FTN|(PTR<<TSHIFT); 179 defid(p, EXTERN); 180 nfree(p); 181 } 182 blevel--; 183 184 p = doacall(sp, nametree(sp), r); 185 ecomp(p); 186 187 188 /* RAX contains destination after memcpy() */ 189 } 190 191 /* 192 * code for the beginning of a function; a is an array of 193 * indices in symtab for the arguments; n is the number 194 */ 195 void 196 bfcode(struct symtab **s, int cnt) 197 { 198 union arglist *al; 199 struct symtab *sp; 200 NODE *p, *r; 201 int i, rno, typ; 202 203 /* recalculate the arg offset and create TEMP moves */ 204 /* Always do this for reg, even if not optimizing, to free arg regs */ 205 nsse = ngpr = 0; 206 nrsp = ARGINIT; 207 if (cftnsp->stype == STRTY+FTN || cftnsp->stype == UNIONTY+FTN) { 208 sp = cftnsp; 209 if (argtyp(DECREF(sp->stype), sp->sdf, sp->ssue) == STRMEM) { 210 r = block(REG, NIL, NIL, LONG, 0, MKSUE(LONG)); 211 regno(r) = argregsi[ngpr++]; 212 p = tempnode(0, r->n_type, r->n_df, r->n_sue); 213 stroffset = regno(p); 214 ecomp(buildtree(ASSIGN, p, r)); 215 } 216 } 217 218 for (i = 0; i < cnt; i++) { 219 sp = s[i]; 220 221 if (sp == NULL) 222 continue; /* XXX when happens this? */ 223 224 switch (typ = argtyp(sp->stype, sp->sdf, sp->ssue)) { 225 case INTEGER: 226 case SSE: 227 if (typ == SSE) 228 rno = XMM0 + nsse++; 229 else 230 rno = argregsi[ngpr++]; 231 r = block(REG, NIL, NIL, sp->stype, sp->sdf, sp->ssue); 232 regno(r) = rno; 233 p = tempnode(0, sp->stype, sp->sdf, sp->ssue); 234 sp->soffset = regno(p); 235 sp->sflags |= STNODE; 236 ecomp(buildtree(ASSIGN, p, r)); 237 break; 238 239 case INTMEM: 240 sp->soffset = nrsp; 241 nrsp += SZLONG; 242 if (xtemps) { 243 p = tempnode(0, sp->stype, sp->sdf, sp->ssue); 244 p = buildtree(ASSIGN, p, nametree(sp)); 245 sp->soffset = regno(p->n_left); 246 sp->sflags |= STNODE; 247 ecomp(p); 248 } 249 break; 250 251 case STRMEM: /* Struct in memory */ 252 sp->soffset = nrsp; 253 nrsp += tsize(sp->stype, sp->sdf, sp->ssue); 254 break; 255 256 case STRREG: /* Struct in register */ 257 /* Allocate space on stack for the struct */ 258 /* For simplicity always fetch two longwords */ 259 autooff += (2*SZLONG); 260 261 r = block(REG, NIL, NIL, LONG, 0, MKSUE(LONG)); 262 regno(r) = argregsi[ngpr++]; 263 ecomp(movtomem(r, -autooff, FPREG)); 264 265 if (tsize(sp->stype, sp->sdf, sp->ssue) > SZLONG) { 266 r = block(REG, NIL, NIL, LONG, 0, MKSUE(LONG)); 267 regno(r) = argregsi[ngpr++]; 268 ecomp(movtomem(r, -autooff+SZLONG, FPREG)); 269 } 270 271 sp->soffset = -autooff; 272 break; 273 274 default: 275 cerror("bfcode: %d", typ); 276 } 277 } 278 279 /* Check if there are varargs */ 280 if (cftnsp->sdf == NULL || cftnsp->sdf->dfun == NULL) 281 return; /* no prototype */ 282 al = cftnsp->sdf->dfun; 283 284 for (; al->type != TELLIPSIS; al++) { 285 if (al->type == TNULL) 286 return; 287 if (BTYPE(al->type) == STRTY || BTYPE(al->type) == UNIONTY || 288 ISARY(al->type)) 289 al++; 290 } 291 292 /* fix stack offset */ 293 SETOFF(autooff, ALMAX); 294 295 /* Save reg arguments in the reg save area */ 296 p = NIL; 297 for (i = ngpr; i < 6; i++) { 298 r = block(REG, NIL, NIL, LONG, 0, MKSUE(LONG)); 299 regno(r) = argregsi[i]; 300 r = movtomem(r, -RSALONGOFF(i)-autooff, FPREG); 301 p = (p == NIL ? r : block(COMOP, p, r, INT, 0, MKSUE(INT))); 302 } 303 for (i = nsse; i < 8; i++) { 304 r = block(REG, NIL, NIL, DOUBLE, 0, MKSUE(DOUBLE)); 305 regno(r) = i + XMM0; 306 r = movtomem(r, -RSADBLOFF(i)-autooff, FPREG); 307 p = (p == NIL ? r : block(COMOP, p, r, INT, 0, MKSUE(INT))); 308 } 309 autooff += RSASZ; 310 rsaoff = autooff; 311 thissse = nsse; 312 thisgpr = ngpr; 313 thisrsp = nrsp; 314 315 ecomp(p); 316 } 317 318 319 /* 320 * by now, the automatics and register variables are allocated 321 */ 322 void 323 bccode() 324 { 325 SETOFF(autooff, SZINT); 326 } 327 328 /* called just before final exit */ 329 /* flag is 1 if errors, 0 if none */ 330 void 331 ejobcode(int flag ) 332 { 333 #define _MKSTR(x) #x 334 #define MKSTR(x) _MKSTR(x) 335 #define OS MKSTR(TARGOS) 336 printf("\t.ident \"PCC: %s (%s)\"\n\t.end\n", PACKAGE_STRING, OS); 337 } 338 339 /* 340 * Varargs stuff: 341 * The ABI says that va_list should be declared as this typedef. 342 * We handcraft it here and then just reference it. 343 * 344 * typedef struct { 345 * unsigned int gp_offset; 346 * unsigned int fp_offset; 347 * void *overflow_arg_area; 348 * void *reg_save_area; 349 * } __builtin_va_list[1]; 350 */ 351 352 static char *gp_offset, *fp_offset, *overflow_arg_area, *reg_save_area; 353 354 void 355 bjobcode() 356 { 357 struct rstack *rp; 358 NODE *p, *q; 359 char *c; 360 361 gp_offset = addname("gp_offset"); 362 fp_offset = addname("fp_offset"); 363 overflow_arg_area = addname("overflow_arg_area"); 364 reg_save_area = addname("reg_save_area"); 365 366 rp = bstruct(NULL, STNAME, NULL); 367 p = block(NAME, NIL, NIL, UNSIGNED, 0, MKSUE(UNSIGNED)); 368 soumemb(p, gp_offset, 0); 369 soumemb(p, fp_offset, 0); 370 p->n_type = VOID+PTR; 371 p->n_sue = MKSUE(VOID); 372 soumemb(p, overflow_arg_area, 0); 373 soumemb(p, reg_save_area, 0); 374 nfree(p); 375 q = dclstruct(rp); 376 c = addname("__builtin_va_list"); 377 p = block(LB, bdty(NAME, c), bcon(1), INT, 0, MKSUE(INT)); 378 p = tymerge(q, p); 379 p->n_sp = lookup(c, 0); 380 defid(p, TYPEDEF); 381 nfree(q); 382 nfree(p); 383 } 384 385 static NODE * 386 mkstkref(int off, TWORD typ) 387 { 388 NODE *p; 389 390 p = block(REG, NIL, NIL, PTR|typ, 0, MKSUE(LONG)); 391 regno(p) = FPREG; 392 return buildtree(PLUS, p, bcon(off/SZCHAR)); 393 } 394 395 NODE * 396 amd64_builtin_stdarg_start(NODE *f, NODE *a) 397 { 398 NODE *p, *r; 399 400 /* use the values from the function header */ 401 p = a->n_left; 402 r = buildtree(ASSIGN, structref(ccopy(p), STREF, reg_save_area), 403 mkstkref(-rsaoff, VOID)); 404 r = buildtree(COMOP, r, 405 buildtree(ASSIGN, structref(ccopy(p), STREF, overflow_arg_area), 406 mkstkref(thisrsp, VOID))); 407 r = buildtree(COMOP, r, 408 buildtree(ASSIGN, structref(ccopy(p), STREF, gp_offset), 409 bcon(thisgpr*(SZLONG/SZCHAR)))); 410 r = buildtree(COMOP, r, 411 buildtree(ASSIGN, structref(ccopy(p), STREF, fp_offset), 412 bcon(thissse*(SZDOUBLE*2/SZCHAR)+48))); 413 414 tfree(f); 415 tfree(a); 416 return r; 417 } 418 419 /* 420 * Create a tree that should be like the expression 421 * ((long *)(l->gp_offset >= 48 ? 422 * l->overflow_arg_area += 8, l->overflow_arg_area : 423 * l->gp_offset += 8, l->reg_save_area + l->gp_offset))[-1] 424 * ...or similar for floats. 425 */ 426 static NODE * 427 bva(NODE *ap, TWORD dt, char *ot, int addto, int max) 428 { 429 NODE *cm1, *cm2, *gpo, *ofa, *l1, *qc; 430 TWORD nt; 431 432 ofa = structref(ccopy(ap), STREF, overflow_arg_area); 433 l1 = buildtree(PLUSEQ, ccopy(ofa), bcon(addto)); 434 cm1 = buildtree(COMOP, l1, ofa); 435 436 gpo = structref(ccopy(ap), STREF, ot); 437 l1 = buildtree(PLUSEQ, ccopy(gpo), bcon(addto)); 438 cm2 = buildtree(COMOP, l1, buildtree(PLUS, ccopy(gpo), 439 structref(ccopy(ap), STREF, reg_save_area))); 440 qc = buildtree(QUEST, 441 buildtree(GE, gpo, bcon(max)), 442 buildtree(COLON, cm1, cm2)); 443 444 nt = (dt == DOUBLE ? DOUBLE : LONG); 445 l1 = block(NAME, NIL, NIL, nt|PTR, 0, MKSUE(nt)); 446 l1 = buildtree(CAST, l1, qc); 447 qc = l1->n_right; 448 nfree(l1->n_left); 449 nfree(l1); 450 451 /* qc has now a real type, for indexing */ 452 addto = dt == DOUBLE ? 2 : 1; 453 qc = buildtree(UMUL, buildtree(PLUS, qc, bcon(-addto)), NIL); 454 455 l1 = block(NAME, NIL, NIL, dt, 0, MKSUE(BTYPE(dt))); 456 l1 = buildtree(CAST, l1, qc); 457 qc = l1->n_right; 458 nfree(l1->n_left); 459 nfree(l1); 460 461 return qc; 462 } 463 464 NODE * 465 amd64_builtin_va_arg(NODE *f, NODE *a) 466 { 467 NODE *ap, *r; 468 TWORD dt; 469 470 ap = a->n_left; 471 dt = a->n_right->n_type; 472 if (dt <= ULONGLONG || ISPTR(dt)) { 473 /* type might be in general register */ 474 r = bva(ap, dt, gp_offset, 8, 48); 475 } else if (dt == FLOAT || dt == DOUBLE) { 476 /* Float are promoted to double here */ 477 if (dt == FLOAT) 478 dt = DOUBLE; 479 r = bva(ap, dt, fp_offset, 16, RSASZ/SZCHAR); 480 } else { 481 uerror("amd64_builtin_va_arg not supported type"); 482 goto bad; 483 } 484 tfree(a); 485 tfree(f); 486 return r; 487 bad: 488 uerror("bad argument to __builtin_va_arg"); 489 return bcon(0); 490 } 491 492 NODE * 493 amd64_builtin_va_end(NODE *f, NODE *a) 494 { 495 tfree(f); 496 tfree(a); 497 return bcon(0); /* nothing */ 498 } 499 500 NODE * 501 amd64_builtin_va_copy(NODE *f, NODE *a) { cerror("amd64_builtin_va_copy"); return NULL; } 502 503 static NODE * 504 movtoreg(NODE *p, int rno) 505 { 506 NODE *r; 507 508 r = block(REG, NIL, NIL, p->n_type, p->n_df, p->n_sue); 509 regno(r) = rno; 510 return clocal(buildtree(ASSIGN, r, p)); 511 } 512 513 static NODE * 514 movtomem(NODE *p, int off, int reg) 515 { 516 struct symtab s; 517 NODE *r, *l; 518 519 s.stype = p->n_type; 520 s.sdf = p->n_df; 521 s.ssue = p->n_sue; 522 s.soffset = off; 523 s.sclass = AUTO; 524 525 l = block(REG, NIL, NIL, PTR+STRTY, 0, 0); 526 l->n_lval = 0; 527 regno(l) = reg; 528 529 r = block(NAME, NIL, NIL, p->n_type, p->n_df, p->n_sue); 530 r->n_sp = &s; 531 r = stref(block(STREF, l, r, 0, 0, 0)); 532 533 return clocal(buildtree(ASSIGN, r, p)); 534 } 535 536 537 /* 538 * AMD64 parameter classification. 539 */ 540 static int 541 argtyp(TWORD t, union dimfun *df, struct suedef *sue) 542 { 543 int cl = 0; 544 545 if (t <= ULONG || ISPTR(t)) { 546 cl = ngpr < 6 ? INTEGER : INTMEM; 547 } else if (t == FLOAT || t == DOUBLE) { 548 cl = nsse < 8 ? SSE : SSEMEM; 549 } else if (t == LDOUBLE) { 550 cl = X87; /* XXX */ 551 } else if (t == STRTY) { 552 /* XXX no SSEOP handling */ 553 if ((tsize(t, df, sue) > 2*SZLONG) || 554 (gcc_get_attr(sue, GCC_ATYP_PACKED) != NULL)) 555 cl = STRMEM; 556 else 557 cl = STRREG; 558 } else 559 cerror("FIXME: classify"); 560 return cl; 561 } 562 563 static void 564 argput(NODE *p) 565 { 566 NODE *q; 567 int typ, r, ssz; 568 569 /* first arg may be struct return pointer */ 570 /* XXX - check if varargs; setup al */ 571 switch (typ = argtyp(p->n_type, p->n_df, p->n_sue)) { 572 case INTEGER: 573 case SSE: 574 q = talloc(); 575 *q = *p; 576 if (typ == SSE) 577 r = XMM0 + nsse++; 578 else 579 r = argregsi[ngpr++]; 580 q = movtoreg(q, r); 581 *p = *q; 582 nfree(q); 583 break; 584 case X87: 585 cerror("no long double yet"); 586 break; 587 588 case INTMEM: 589 q = talloc(); 590 *q = *p; 591 r = nrsp; 592 nrsp += SZLONG; 593 q = movtomem(q, r, STKREG); 594 *p = *q; 595 nfree(q); 596 break; 597 598 case STRREG: /* Struct in registers */ 599 /* Cast to long pointer and move to the registers */ 600 ssz = tsize(p->n_type, p->n_df, p->n_sue); 601 602 if (ssz <= SZLONG) { 603 q = cast(p->n_left, LONG+PTR, 0); 604 q = buildtree(UMUL, q, NIL); 605 q = movtoreg(q, argregsi[ngpr++]); 606 *p = *q; 607 nfree(q); 608 } else if (ssz <= SZLONG*2) { 609 NODE *qt, *q1, *q2, *ql, *qr; 610 611 qt = tempnode(0, LONG+PTR, 0, MKSUE(LONG)); 612 q1 = ccopy(qt); 613 q2 = ccopy(qt); 614 ql = buildtree(ASSIGN, qt, cast(p->n_left,LONG+PTR, 0)); 615 qr = movtoreg(buildtree(UMUL, q1, NIL), 616 argregsi[ngpr++]); 617 ql = buildtree(COMOP, ql, qr); 618 qr = buildtree(UMUL, buildtree(PLUS, q2, bcon(1)), NIL); 619 qr = movtoreg(qr, argregsi[ngpr++]); 620 q = buildtree(COMOP, ql, qr); 621 *p = *q; 622 nfree(q); 623 } else 624 cerror("STRREG"); 625 break; 626 627 case STRMEM: 628 /* Struct moved to memory */ 629 default: 630 cerror("argument %d", typ); 631 } 632 } 633 634 635 /* 636 * Called with a function call with arguments as argument. 637 * This is done early in buildtree() and only done once. 638 * Returns p. 639 */ 640 NODE * 641 funcode(NODE *p) 642 { 643 NODE *l, *r; 644 645 nsse = ngpr = nrsp = 0; 646 /* Check if hidden arg needed */ 647 /* If so, add it in pass2 */ 648 if ((l = p->n_left)->n_type == INCREF(FTN)+STRTY || 649 l->n_type == INCREF(FTN)+UNIONTY) { 650 int ssz = tsize(BTYPE(l->n_type), l->n_df, l->n_sue); 651 if (ssz > 2*SZLONG) 652 ngpr++; 653 } 654 listf(p->n_right, argput); 655 656 /* Check if there are varargs */ 657 if (nsse || l->n_df == NULL || l->n_df->dfun == NULL) { 658 ; /* Need RAX */ 659 } else { 660 union arglist *al = l->n_df->dfun; 661 662 for (; al->type != TELLIPSIS; al++) { 663 if (al->type == TNULL) 664 return p; /* No need */ 665 if (BTYPE(al->type) == STRTY || 666 BTYPE(al->type) == UNIONTY || 667 ISARY(al->type)) 668 al++; 669 } 670 } 671 672 /* Always emit number of SSE regs used */ 673 l = movtoreg(bcon(nsse), RAX); 674 if (p->n_right->n_op != CM) { 675 p->n_right = block(CM, l, p->n_right, INT, 0, MKSUE(INT)); 676 } else { 677 for (r = p->n_right; r->n_left->n_op == CM; r = r->n_left) 678 ; 679 r->n_left = block(CM, l, r->n_left, INT, 0, MKSUE(INT)); 680 } 681 return p; 682 } 683 684 /* 685 * return the alignment of field of type t 686 */ 687 int 688 fldal(unsigned int t) 689 { 690 uerror("illegal field type"); 691 return(ALINT); 692 } 693 694 /* fix up type of field p */ 695 void 696 fldty(struct symtab *p) 697 { 698 } 699 700 /* 701 * XXX - fix genswitch. 702 */ 703 int 704 mygenswitch(int num, TWORD type, struct swents **p, int n) 705 { 706 return 0; 707 } 708