1/* Id: code.c,v 1.27 2016/01/06 16:11:24 ragge Exp */ 2/* $NetBSD: code.c,v 1.1.1.6 2016/02/09 20:28:21 plunky Exp $ */ 3/* 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/* 32 * MIPS port by Jan Enoksson (janeno-1@student.ltu.se) and 33 * Simon Olsson (simols-1@student.ltu.se) 2005. 34 */ 35 36#include <assert.h> 37#include "pass1.h" 38 39#ifndef LANG_CXX 40#undef NIL 41#define NIL NULL 42#define NODE P1ND 43#define nfree p1nfree 44#define ccopy p1tcopy 45#define tfree p1tfree 46#endif 47 48/* 49 * Print out assembler segment name. 50 */ 51void 52setseg(int seg, char *name) 53{ 54 switch (seg) { 55 case PROG: name = ".text"; break; 56 case DATA: 57 case LDATA: name = ".data"; break; 58 case STRNG: 59 case RDATA: name = ".section .rodata"; break; 60 case UDATA: break; 61 case PICLDATA: 62 case PICDATA: name = ".section .data.rel.rw,\"aw\",@progbits"; break; 63 case PICRDATA: name = ".section .data.rel.ro,\"aw\",@progbits"; break; 64 case TLSDATA: name = ".section .tdata,\"awT\",@progbits"; break; 65 case TLSUDATA: name = ".section .tbss,\"awT\",@nobits"; break; 66 case CTORS: name = ".section\t.ctors,\"aw\",@progbits"; break; 67 case DTORS: name = ".section\t.dtors,\"aw\",@progbits"; break; 68 case NMSEG: 69 printf("\t.section %s,\"a%c\",@progbits\n", name, 70 cftnsp ? 'x' : 'w'); 71 return; 72 } 73 printf("\t%s\n", name); 74} 75 76/* 77 * Define everything needed to print out some data (or text). 78 * This means segment, alignment, visibility, etc. 79 */ 80void 81defloc(struct symtab *sp) 82{ 83 char *n; 84 85 if (ISFTN(sp->stype)) 86 return; /* XXX until fixed */ 87 88 n = getexname(sp); 89 90 if (sp->sclass == EXTDEF) 91 printf(" .globl %s\n", n); 92 if (sp->slevel == 0) { 93#ifdef USE_GAS 94 printf("\t.type %s,@%s\n", n, 95 ISFTN(sp->stype) ? "function" : "object"); 96 if (!ISFTN(sp->stype)) 97 printf("\t.size %s," CONFMT "\n", n, 98 tsize(sp->stype, sp->sdf, sp->sap)); 99#endif 100 printf("%s:\n", n); 101 } else 102 printf(LABFMT ":\n", sp->soffset); 103} 104 105 106/* 107 * cause the alignment to become a multiple of n 108 */ 109void 110defalign(int n) 111{ 112 n = ispow2(n / SZCHAR); 113 if (n == -1) 114 cerror("defalign: n != 2^i"); 115 printf("\t.p2align %d\n", n); 116} 117 118static int rvnr; 119 120/* 121 * code for the end of a function 122 * deals with struct return here 123 */ 124void 125efcode(void) 126{ 127 NODE *p, *q; 128 int tempnr; 129 int ty; 130 131 if (cftnsp->stype != STRTY+FTN && cftnsp->stype != UNIONTY+FTN) 132 return; 133 134 ty = cftnsp->stype - FTN; 135 136 q = block(REG, NIL, NIL, INCREF(ty), 0, cftnsp->sap); 137 q->n_rval = V0; 138 p = tempnode(0, INCREF(ty), 0, cftnsp->sap); 139 tempnr = regno(p); 140 p = buildtree(ASSIGN, p, q); 141 ecomp(p); 142 143 q = tempnode(tempnr, INCREF(ty), 0, cftnsp->sap); 144 q = buildtree(UMUL, q, NIL); 145 146 p = tempnode(rvnr, INCREF(ty), 0, cftnsp->sap); 147 p = buildtree(UMUL, p, NIL); 148 149 p = buildtree(ASSIGN, p, q); 150 ecomp(p); 151 152 q = tempnode(rvnr, INCREF(ty), 0, cftnsp->sap); 153 p = block(REG, NIL, NIL, INCREF(ty), 0, cftnsp->sap); 154 p->n_rval = V0; 155 p = buildtree(ASSIGN, p, q); 156 ecomp(p); 157} 158 159/* Put a symbol in a temporary 160 * used by bfcode() and its helpers */ 161static void 162putintemp(struct symtab *sym) 163{ 164 NODE *p; 165 p = tempnode(0, sym->stype, sym->sdf, sym->sap); 166 p = buildtree(ASSIGN, p, nametree(sym)); 167 sym->soffset = regno(p->n_left); 168 sym->sflags |= STNODE; 169 ecomp(p); 170} 171 172/* setup the hidden pointer to struct return parameter 173 * used by bfcode() */ 174static void 175param_retptr(void) 176{ 177 NODE *p, *q; 178 179 p = tempnode(0, PTR+STRTY, 0, cftnsp->sap); 180 rvnr = regno(p); 181 q = block(REG, NIL, NIL, PTR+STRTY, 0, cftnsp->sap); 182 q->n_rval = A0; 183 p = buildtree(ASSIGN, p, q); 184 ecomp(p); 185} 186 187/* setup struct parameter 188 * push the registers out to memory 189 * used by bfcode() */ 190static void 191param_struct(struct symtab *sym, int *regp) 192{ 193 int reg = *regp; 194 NODE *p, *q; 195 int navail; 196 int sz; 197 int off; 198 int num; 199 int i; 200 201 navail = nargregs - (reg - A0); 202 sz = tsize(sym->stype, sym->sdf, sym->sap) / SZINT; 203 off = ARGINIT/SZINT + (reg - A0); 204 num = sz > navail ? navail : sz; 205 for (i = 0; i < num; i++) { 206 q = block(REG, NIL, NIL, INT, 0, 0); 207 q->n_rval = reg++; 208 p = block(REG, NIL, NIL, INT, 0, 0); 209 p->n_rval = FP; 210 p = block(PLUS, p, bcon(4*off++), INT, 0, 0); 211 p = block(UMUL, p, NIL, INT, 0, 0); 212 p = buildtree(ASSIGN, p, q); 213 ecomp(p); 214 } 215 216 *regp = reg; 217} 218 219/* setup a 64-bit parameter (double/ldouble/longlong) 220 * used by bfcode() */ 221static void 222param_64bit(struct symtab *sym, int *regp, int dotemps) 223{ 224 int reg = *regp; 225 NODE *p, *q; 226 int navail; 227 228 /* alignment */ 229 ++reg; 230 reg &= ~1; 231 232 navail = nargregs - (reg - A0); 233 234 if (navail < 2) { 235 /* would have appeared half in registers/half 236 * on the stack, but alignment ensures it 237 * appears on the stack */ 238 if (dotemps) 239 putintemp(sym); 240 *regp = reg; 241 return; 242 } 243 244 q = block(REG, NIL, NIL, sym->stype, sym->sdf, sym->sap); 245 q->n_rval = A0A1 + (reg - A0); 246 if (dotemps) { 247 p = tempnode(0, sym->stype, sym->sdf, sym->sap); 248 sym->soffset = regno(p); 249 sym->sflags |= STNODE; 250 } else { 251 p = nametree(sym); 252 } 253 p = buildtree(ASSIGN, p, q); 254 ecomp(p); 255 *regp = reg + 2; 256} 257 258/* setup a 32-bit param on the stack 259 * used by bfcode() */ 260static void 261param_32bit(struct symtab *sym, int *regp, int dotemps) 262{ 263 NODE *p, *q; 264 265 q = block(REG, NIL, NIL, sym->stype, sym->sdf, sym->sap); 266 q->n_rval = (*regp)++; 267 if (dotemps) { 268 p = tempnode(0, sym->stype, sym->sdf, sym->sap); 269 sym->soffset = regno(p); 270 sym->sflags |= STNODE; 271 } else { 272 p = nametree(sym); 273 } 274 p = buildtree(ASSIGN, p, q); 275 ecomp(p); 276} 277 278/* 279 * XXX This is a hack. We cannot have (l)doubles in more than one 280 * register class. So we bounce them in and out of temps to 281 * move them in and out of the right registers. 282 */ 283static void 284param_double(struct symtab *sym, int *regp, int dotemps) 285{ 286 int reg = *regp; 287 NODE *p, *q, *t; 288 int navail; 289 int tmpnr; 290 291 /* alignment */ 292 ++reg; 293 reg &= ~1; 294 295 navail = nargregs - (reg - A0); 296 297 if (navail < 2) { 298 /* would have appeared half in registers/half 299 * on the stack, but alignment ensures it 300 * appears on the stack */ 301 if (dotemps) 302 putintemp(sym); 303 *regp = reg; 304 return; 305 } 306 307 t = tempnode(0, LONGLONG, 0, 0); 308 tmpnr = regno(t); 309 q = block(REG, NIL, NIL, LONGLONG, 0, 0); 310 q->n_rval = A0A1 + (reg - A0); 311 p = buildtree(ASSIGN, t, q); 312 ecomp(p); 313 314 if (dotemps) { 315 sym->soffset = tmpnr; 316 sym->sflags |= STNODE; 317 } else { 318 q = tempnode(tmpnr, sym->stype, sym->sdf, sym->sap); 319 p = nametree(sym); 320 p = buildtree(ASSIGN, p, q); 321 ecomp(p); 322 } 323 *regp = reg + 2; 324} 325 326/* 327 * XXX This is a hack. We cannot have floats in more than one 328 * register class. So we bounce them in and out of temps to 329 * move them in and out of the right registers. 330 */ 331static void 332param_float(struct symtab *sym, int *regp, int dotemps) 333{ 334 NODE *p, *q, *t; 335 int tmpnr; 336 337 t = tempnode(0, INT, 0, 0); 338 tmpnr = regno(t); 339 q = block(REG, NIL, NIL, INT, 0, 0); 340 q->n_rval = (*regp)++; 341 p = buildtree(ASSIGN, t, q); 342 ecomp(p); 343 344 if (dotemps) { 345 sym->soffset = tmpnr; 346 sym->sflags |= STNODE; 347 } else { 348 q = tempnode(tmpnr, sym->stype, sym->sdf, sym->sap); 349 p = nametree(sym); 350 p = buildtree(ASSIGN, p, q); 351 ecomp(p); 352 } 353} 354 355/* 356 * code for the beginning of a function; a is an array of 357 * indices in symtab for the arguments; n is the number 358 */ 359void 360bfcode(struct symtab **sp, int cnt) 361{ 362 union arglist *usym; 363 int lastreg = A0 + nargregs - 1; 364 int saveallargs = 0; 365 int i, reg; 366 367 /* 368 * Detect if this function has ellipses and save all 369 * argument register onto stack. 370 */ 371 usym = cftnsp->sdf->dfun; 372 while (usym && usym->type != TNULL) { 373 if (usym->type == TELLIPSIS) { 374 saveallargs = 1; 375 break; 376 } 377 ++usym; 378 } 379 380 reg = A0; 381 382 /* assign hidden return structure to temporary */ 383 if (cftnsp->stype == STRTY+FTN || cftnsp->stype == UNIONTY+FTN) { 384 param_retptr(); 385 ++reg; 386 } 387 388 /* recalculate the arg offset and create TEMP moves */ 389 for (i = 0; i < cnt; i++) { 390 391 if ((reg > lastreg) && !xtemps) 392 break; 393 else if (reg > lastreg) 394 putintemp(sp[i]); 395 else if (sp[i]->stype == STRTY || sp[i]->stype == UNIONTY) 396 param_struct(sp[i], ®); 397 else if (DEUNSIGN(sp[i]->stype) == LONGLONG) 398 param_64bit(sp[i], ®, xtemps && !saveallargs); 399 else if (sp[i]->stype == DOUBLE || sp[i]->stype == LDOUBLE) 400 param_double(sp[i], ®, xtemps && !saveallargs); 401 else if (sp[i]->stype == FLOAT) 402 param_float(sp[i], ®, xtemps && !saveallargs); 403 else 404 param_32bit(sp[i], ®, xtemps && !saveallargs); 405 } 406 407 /* if saveallargs, save the rest of the args onto the stack */ 408 if (!saveallargs) 409 return; 410 while (reg <= lastreg) { 411 NODE *p, *q; 412 int off = ARGINIT/SZINT + (reg - A0); 413 q = block(REG, NIL, NIL, INT, 0, 0); 414 q->n_rval = reg++; 415 p = block(REG, NIL, NIL, INT, 0, 0); 416 p->n_rval = FP; 417 p = block(PLUS, p, bcon(4*off), INT, 0, 0); 418 p = block(UMUL, p, NIL, INT, 0, 0); 419 p = buildtree(ASSIGN, p, q); 420 ecomp(p); 421 } 422 423} 424 425 426/* called just before final exit */ 427/* flag is 1 if errors, 0 if none */ 428void 429ejobcode(int flag) 430{ 431} 432 433void 434bjobcode(void) 435{ 436 printf("\t.section .mdebug.abi32\n"); 437 printf("\t.previous\n"); 438 439 /* only if -fpic or -fPIC */ 440 if (kflag > 0) 441 printf("\t.abicalls\n"); 442} 443 444#ifdef notdef 445/* 446 * Print character t at position i in one string, until t == -1. 447 * Locctr & label is already defined. 448 */ 449void 450bycode(int t, int i) 451{ 452 static int lastoctal = 0; 453 454 /* put byte i+1 in a string */ 455 456 if (t < 0) { 457 if (i != 0) 458 puts("\\000\""); 459 } else { 460 if (i == 0) 461 printf("\t.ascii \""); 462 if (t == 0) 463 return; 464 else if (t == '\\' || t == '"') { 465 lastoctal = 0; 466 putchar('\\'); 467 putchar(t); 468 } else if (t == 011) { 469 printf("\\t"); 470 } else if (t == 012) { 471 printf("\\n"); 472 } else if (t < 040 || t >= 0177) { 473 lastoctal++; 474 printf("\\%o",t); 475 } else if (lastoctal && '0' <= t && t <= '9') { 476 lastoctal = 0; 477 printf("\"\n\t.ascii \"%c", t); 478 } else { 479 lastoctal = 0; 480 putchar(t); 481 } 482 } 483} 484#endif 485 486/* fix up type of field p */ 487void 488fldty(struct symtab *p) 489{ 490} 491 492/* 493 * XXX - fix genswitch. 494 */ 495int 496mygenswitch(int num, TWORD type, struct swents **p, int n) 497{ 498 return 0; 499} 500 501 502/* setup call stack with a structure */ 503/* called from moveargs() */ 504static NODE * 505movearg_struct(NODE *p, NODE *parent, int *regp) 506{ 507 int reg = *regp; 508 NODE *l, *q, *t, *r; 509 int tmpnr; 510 int navail; 511 int off; 512 int num; 513 int sz; 514 int ty; 515 int i; 516 517 navail = nargregs - (reg - A0); 518 sz = tsize(p->n_type, p->n_df, p->n_ap) / SZINT; 519 num = sz > navail ? navail : sz; 520 521 l = p->n_left; 522 nfree(p); 523 ty = l->n_type; 524 t = tempnode(0, l->n_type, l->n_df, l->n_ap); 525 tmpnr = regno(t); 526 l = buildtree(ASSIGN, t, l); 527 528 if (p != parent) { 529 q = parent->n_left; 530 } else 531 q = NULL; 532 533 /* copy structure into registers */ 534 for (i = 0; i < num; i++) { 535 t = tempnode(tmpnr, ty, 0, 0); 536 t = block(SCONV, t, NIL, PTR+INT, 0, 0); 537 t = block(PLUS, t, bcon(4*i), PTR+INT, 0, 0); 538 t = buildtree(UMUL, t, NIL); 539 540 r = block(REG, NIL, NIL, INT, 0, 0); 541 r->n_rval = reg++; 542 543 r = buildtree(ASSIGN, r, t); 544 if (q == NULL) 545 q = r; 546 else 547 q = block(CM, q, r, INT, 0, 0); 548 } 549 off = ARGINIT/SZINT + nargregs; 550 for (i = num; i < sz; i++) { 551 t = tempnode(tmpnr, ty, 0, 0); 552 t = block(SCONV, t, NIL, PTR+INT, 0, 0); 553 t = block(PLUS, t, bcon(4*i), PTR+INT, 0, 0); 554 t = buildtree(UMUL, t, NIL); 555 556 r = block(REG, NIL, NIL, INT, 0, 0); 557 r->n_rval = FP; 558 r = block(PLUS, r, bcon(4*off++), INT, 0, 0); 559 r = block(UMUL, r, NIL, INT, 0, 0); 560 561 r = buildtree(ASSIGN, r, t); 562 if (q == NULL) 563 q = r; 564 else 565 q = block(CM, q, r, INT, 0, 0); 566 } 567 568 if (parent->n_op == CM) { 569 parent->n_left = q; 570 q = l; 571 } else { 572 q = block(CM, q, l, INT, 0, 0); 573 } 574 575 *regp = reg; 576 return q; 577} 578 579/* setup call stack with 64-bit argument */ 580/* called from moveargs() */ 581static NODE * 582movearg_64bit(NODE *p, int *regp) 583{ 584 int reg = *regp; 585 NODE *q; 586 int lastarg; 587 588 /* alignment */ 589 ++reg; 590 reg &= ~1; 591 592 lastarg = A0 + nargregs - 1; 593 if (reg > lastarg) { 594 *regp = reg; 595 return block(FUNARG, p, NIL, p->n_type, p->n_df, p->n_ap); 596 } 597 598 q = block(REG, NIL, NIL, p->n_type, p->n_df, p->n_ap); 599 q->n_rval = A0A1 + (reg - A0); 600 q = buildtree(ASSIGN, q, p); 601 602 *regp = reg + 2; 603 return q; 604} 605 606/* setup call stack with 32-bit argument */ 607/* called from moveargs() */ 608static NODE * 609movearg_32bit(NODE *p, int *regp) 610{ 611 int reg = *regp; 612 NODE *q; 613 614 q = block(REG, NIL, NIL, p->n_type, p->n_df, p->n_ap); 615 q->n_rval = reg++; 616 q = buildtree(ASSIGN, q, p); 617 618 *regp = reg; 619 return q; 620} 621 622static NODE * 623moveargs(NODE *p, int *regp) 624{ 625 NODE *r, **rp; 626 int lastreg; 627 int reg; 628 629 if (p->n_op == CM) { 630 p->n_left = moveargs(p->n_left, regp); 631 r = p->n_right; 632 rp = &p->n_right; 633 } else { 634 r = p; 635 rp = &p; 636 } 637 638 lastreg = A0 + nargregs - 1; 639 reg = *regp; 640 641 if (reg > lastreg && r->n_op != STARG) 642 *rp = block(FUNARG, r, NIL, r->n_type, r->n_df, r->n_ap); 643 else if (r->n_op == STARG) { 644 *rp = movearg_struct(r, p, regp); 645 } else if (DEUNSIGN(r->n_type) == LONGLONG) { 646 *rp = movearg_64bit(r, regp); 647 } else if (r->n_type == DOUBLE || r->n_type == LDOUBLE) { 648 /* XXX bounce in and out of temporary to change to longlong */ 649 NODE *t1 = tempnode(0, LONGLONG, 0, 0); 650 int tmpnr = regno(t1); 651 NODE *t2 = tempnode(tmpnr, r->n_type, r->n_df, r->n_ap); 652 t1 = movearg_64bit(t1, regp); 653 r = block(ASSIGN, t2, r, r->n_type, r->n_df, r->n_ap); 654 if (p->n_op == CM) { 655 p->n_left = buildtree(CM, p->n_left, t1); 656 p->n_right = r; 657 } else { 658 p = buildtree(CM, t1, r); 659 } 660 } else if (r->n_type == FLOAT) { 661 /* XXX bounce in and out of temporary to change to int */ 662 NODE *t1 = tempnode(0, INT, 0, 0); 663 int tmpnr = regno(t1); 664 NODE *t2 = tempnode(tmpnr, r->n_type, r->n_df, r->n_ap); 665 t1 = movearg_32bit(t1, regp); 666 r = block(ASSIGN, t2, r, r->n_type, r->n_df, r->n_ap); 667 if (p->n_op == CM) { 668 p->n_left = buildtree(CM, p->n_left, t1); 669 p->n_right = r; 670 } else { 671 p = buildtree(CM, t1, r); 672 } 673 } else { 674 *rp = movearg_32bit(r, regp); 675 } 676 677 return p; 678} 679 680/* 681 * Called with a function call with arguments as argument. 682 * This is done early in buildtree() and only done once. 683 */ 684NODE * 685funcode(NODE *p) 686{ 687 int regnum = A0; 688 NODE *l, *r, *t, *q; 689 int ty; 690 691 l = p->n_left; 692 r = p->n_right; 693 694 /* 695 * if returning a structure, make the first argument 696 * a hidden pointer to return structure. 697 */ 698 ty = DECREF(l->n_type); 699 if (ty == STRTY+FTN || ty == UNIONTY+FTN) { 700 ty = DECREF(l->n_type) - FTN; 701 q = tempnode(0, ty, l->n_df, l->n_ap); 702 q = buildtree(ADDROF, q, NIL); 703 if (r->n_op != CM) { 704 p->n_right = block(CM, q, r, INCREF(ty), 705 l->n_df, l->n_ap); 706 } else { 707 for (t = r; t->n_left->n_op == CM; t = t->n_left) 708 ; 709 t->n_left = block(CM, q, t->n_left, INCREF(ty), 710 l->n_df, l->n_ap); 711 } 712 } 713 714 p->n_right = moveargs(p->n_right, ®num); 715 716 return p; 717} 718 719NODE * 720builtin_cfa(const struct bitable *bt, NODE *a) 721{ 722 uerror("missing builtin_cfa"); 723 return bcon(0); 724} 725 726NODE * 727builtin_frame_address(const struct bitable *bt, NODE *a) 728{ 729 uerror("missing builtin_frame_address"); 730 return bcon(0); 731} 732 733NODE * 734builtin_return_address(const struct bitable *bt, NODE *a) 735{ 736 uerror("missing builtin_return_address"); 737 return bcon(0); 738} 739 740