1/* Id: local2.c,v 1.17 2016/01/30 17:26:19 ragge Exp */ 2/* $NetBSD: local2.c,v 1.1.1.2 2016/02/09 20:28:34 plunky Exp $ */ 3/* 4 * Copyright (c) 2014 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 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 18 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 19 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 21 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 22 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 23 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 25 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 */ 27 28# include "pass2.h" 29# include <ctype.h> 30# include <string.h> 31 32static int stkpos; 33 34void 35deflab(int label) 36{ 37 printf(LABFMT ":\n", label); 38} 39 40static int regm, regf, fpsub, nfp; 41 42void 43prologue(struct interpass_prolog *ipp) 44{ 45 int i; 46 47 /* 48 * Subtract both space for automatics and permanent regs. 49 * XXX - no struct return yet. 50 */ 51 52 fpsub = p2maxautooff; 53 if (fpsub >= AUTOINIT/SZCHAR) 54 fpsub -= AUTOINIT/SZCHAR; 55 regm = regf = nfp = 0; 56 for (i = 0; i < MAXREGS; i++) 57 if (TESTBIT(ipp->ipp_regs, i)) { 58 if (i <= A7) { 59 regm |= (1 << i); 60 fpsub += 4; 61 } else if (i >= FP0) { 62 regf |= (1 << (i - FP0)); 63 fpsub += 12; 64 nfp += 12; 65 } else 66 comperr("bad reg range"); 67 } 68 printf(" link.%c %%fp,#%d\n", fpsub > 32768 ? 'l' : 'w', -fpsub); 69 if (regm) 70 printf(" movem.l #%d,%d(%%fp)\n", regm, -fpsub + nfp); 71 if (regf) 72 printf(" fmovem #%d,%d(%%fp)\n", regf, -fpsub); 73} 74 75void 76eoftn(struct interpass_prolog *ipp) 77{ 78 if (ipp->ipp_ip.ip_lbl == 0) 79 return; /* no code needs to be generated */ 80 81 if (regm) 82 printf(" movem.l %d(%%fp),#%d\n", -fpsub + nfp, regm); 83 if (regf) 84 printf(" fmovem %d(%%fp),#%d\n", -fpsub, regf); 85 printf(" unlk %%fp\n rts\n"); 86} 87 88/* 89 * add/sub/... 90 * 91 * Param given: 92 */ 93void 94hopcode(int f, int o) 95{ 96 char *str; 97 98 switch (o) { 99 case PLUS: 100 str = "add"; 101 break; 102 case MINUS: 103 str = "sub"; 104 break; 105 case AND: 106 str = "and"; 107 break; 108 case OR: 109 str = "or"; 110 break; 111 case ER: 112 str = "eor"; 113 break; 114 default: 115 comperr("hopcode2: %d", o); 116 str = 0; /* XXX gcc */ 117 } 118 printf("%s", str); 119} 120 121/* 122 * Return type size in bytes. Used by R2REGS, arg 2 to offset(). 123 */ 124int 125tlen(NODE *p) 126{ 127 switch(p->n_type) { 128 case CHAR: 129 case UCHAR: 130 return(1); 131 132 case SHORT: 133 case USHORT: 134 return(SZSHORT/SZCHAR); 135 136 case DOUBLE: 137 return(SZDOUBLE/SZCHAR); 138 139 case INT: 140 case UNSIGNED: 141 return(SZINT/SZCHAR); 142 143 case LONG: 144 case ULONG: 145 case LONGLONG: 146 case ULONGLONG: 147 return SZLONGLONG/SZCHAR; 148 149 default: 150 if (!ISPTR(p->n_type)) 151 comperr("tlen type %d not pointer"); 152 return SZPOINT(p->n_type)/SZCHAR; 153 } 154} 155 156int 157fldexpand(NODE *p, int cookie, char **cp) 158{ 159 comperr("fldexpand"); 160 return 0; 161} 162 163static void 164starg(NODE *p) 165{ 166 int sz = attr_find(p->n_ap, ATTR_P2STRUCT)->iarg(0); 167 int subsz = (sz + 3) & ~3; 168 int fr, tr, cr; 169 170 fr = regno(getlr(p, 'L')); /* from reg (struct pointer) */ 171 cr = regno(getlr(p, '1')); /* count reg (number of words) */ 172 tr = regno(getlr(p, '2')); /* to reg (stack) */ 173 174 /* Sub from stack and put in toreg */ 175 printf(" sub.l #%d,%%sp\n", subsz); 176 printf(" move.l %%sp,%s\n", rnames[tr]); 177 178 /* Gen an even copy start */ 179 if (sz & 1) 180 expand(p, INBREG, " move.b (AL)+,(A2)+\n"); 181 if (sz & 2) 182 expand(p, INBREG, " move.w (AL)+,(A2)+\n"); 183 sz -= (sz & 3); 184 185 /* if more than 4 words, use loop, otherwise output instructions */ 186 if (sz > 16) { 187 printf(" move.l #%d,%s\n", (sz/4)-1, rnames[cr]); 188 expand(p, INBREG, "1: move.l (AL)+,(A2)+\n"); 189 expand(p, INBREG, " dbra A1,1b\n"); 190 } else { 191 if (sz > 12) 192 expand(p, INBREG, " move.l (AL)+,(A2)+\n"), sz -= 4; 193 if (sz > 8) 194 expand(p, INBREG, " move.l (AL)+,(A2)+\n"), sz -= 4; 195 if (sz > 4) 196 expand(p, INBREG, " move.l (AL)+,(A2)+\n"), sz -= 4; 197 if (sz == 4) 198 expand(p, INBREG, " move.l (AL)+,(A2)+\n"); 199 } 200} 201 202void 203zzzcode(NODE *p, int c) 204{ 205 TWORD t = p->n_type; 206 char *s; 207 208 switch (c) { 209 case 'L': 210 t = p->n_left->n_type; 211 /* FALLTHROUGH */ 212 case 'A': 213 s = (t == CHAR || t == UCHAR ? "b" : 214 t == SHORT || t == USHORT ? "w" : 215 t == FLOAT ? "s" : 216 t == DOUBLE ? "d" : 217 t == LDOUBLE ? "x" : "l"); 218 printf("%s", s); 219 break; 220 221 case 'B': 222 if (p->n_qual) 223 printf(" add.l #%d,%%sp\n", (int)p->n_qual); 224 break; 225 226 case 'C': /* jsr or bsr.l XXX - type of CPU? */ 227 printf("%s", kflag ? "bsr.l" : "jsr"); 228 break; 229 230 case 'F': /* Emit float branches */ 231 switch (p->n_op) { 232 case GT: s = "fjnle"; break; 233 case GE: s = "fjnlt"; break; 234 case LE: s = "fjngt"; break; 235 case LT: s = "fjnge"; break; 236 case NE: s = "fjne"; break; 237 case EQ: s = "fjeq"; break; 238 default: comperr("ZF"); s = 0; 239 } 240 printf("%s " LABFMT "\n", s, p->n_label); 241 break; 242 243 case 'P': 244 printf(" lea -%d(%%fp),%%a0\n", stkpos); 245 break; 246 247 case 'Q': /* struct assign */ 248 printf(" move.l %d,-(%%sp)\n", 249 attr_find(p->n_ap, ATTR_P2STRUCT)->iarg(0)); 250 expand(p, INAREG, " move.l AR,-(%sp)\n"); 251 expand(p, INAREG, " move.l AL,-(%sp)\n"); 252 printf(" jsr memcpy\n"); 253 printf(" add.l #12,%%sp\n"); 254 break; 255 256 case 'S': /* struct arg */ 257 starg(p); 258 break; 259 260 case '2': 261 if (regno(getlr(p, '2')) != regno(getlr(p, 'L'))) 262 expand(p, INAREG, " fmove.x AL,A2\n"); 263 break; 264 265 default: 266 comperr("zzzcode %c", c); 267 } 268} 269 270#if 0 271int canaddr(NODE *); 272int 273canaddr(NODE *p) 274{ 275 int o = p->n_op; 276 277 if (o==NAME || o==REG || o==ICON || o==OREG || 278 (o==UMUL && shumul(p->n_left, SOREG))) 279 return(1); 280 return(0); 281} 282#endif 283 284/* 285 * Does the bitfield shape match? 286 */ 287int 288flshape(NODE *p) 289{ 290 comperr("flshape"); 291 return(0); 292} 293 294/* INTEMP shapes must not contain any temporary registers */ 295/* XXX should this go away now? */ 296int 297shtemp(NODE *p) 298{ 299 return 0; 300#if 0 301 int r; 302 303 if (p->n_op == STARG ) 304 p = p->n_left; 305 306 switch (p->n_op) { 307 case REG: 308 return (!istreg(p->n_rval)); 309 310 case OREG: 311 r = p->n_rval; 312 if (R2TEST(r)) { 313 if (istreg(R2UPK1(r))) 314 return(0); 315 r = R2UPK2(r); 316 } 317 return (!istreg(r)); 318 319 case UMUL: 320 p = p->n_left; 321 return (p->n_op != UMUL && shtemp(p)); 322 } 323 324 if (optype(p->n_op) != LTYPE) 325 return(0); 326 return(1); 327#endif 328} 329 330void 331adrcon(CONSZ val) 332{ 333 printf("#" CONFMT, val); 334} 335 336void 337conput(FILE *fp, NODE *p) 338{ 339 long val = getlval(p); 340 341 if (p->n_type <= UCHAR) 342 val &= 255; 343 else if (p->n_type <= USHORT) 344 val &= 65535; 345 346 switch (p->n_op) { 347 case ICON: 348 fprintf(fp, "%ld", val); 349 if (p->n_name[0]) 350 printf("+%s", p->n_name); 351 break; 352 353 default: 354 comperr("illegal conput, p %p", p); 355 } 356} 357 358/*ARGSUSED*/ 359void 360insput(NODE *p) 361{ 362 comperr("insput"); 363} 364 365/* 366 * Write out the upper address, like the upper register of a 2-register 367 * reference, or the next memory location. 368 */ 369void 370upput(NODE *p, int size) 371{ 372 switch (p->n_op) { 373 case REG: 374 printf("%%%s", &rnames[p->n_rval][2]); 375 break; 376 case NAME: 377 case OREG: 378 setlval(p, getlval(p) + 4); 379 adrput(stdout, p); 380 setlval(p, getlval(p) - 4); 381 break; 382 383 case ICON: 384 printf("#%d", (int)getlval(p)); 385 break; 386 387 default: 388 comperr("upput bad op %d size %d", p->n_op, size); 389 } 390} 391 392void 393adrput(FILE *io, NODE *p) 394{ 395 int r; 396 397 /* output an address, with offsets, from p */ 398 switch (p->n_op) { 399 case NAME: 400 if (getlval(p)) 401 fprintf(io, CONFMT "%s", getlval(p), 402 *p->n_name ? "+" : ""); 403 if (p->n_name[0]) 404 printf("%s", p->n_name); 405 else 406 comperr("adrput"); 407 return; 408 409 case OREG: 410 r = p->n_rval; 411 412 if (getlval(p)) 413 fprintf(io, CONFMT "%s", getlval(p), 414 *p->n_name ? "+" : ""); 415 if (p->n_name[0]) 416 printf("%s", p->n_name); 417 if (R2TEST(r)) { 418 int r1 = R2UPK1(r); 419 int r2 = R2UPK2(r); 420 int sh = R2UPK3(r); 421 422 fprintf(io, "(%s,%s,%d)", 423 r1 == MAXREGS ? "" : rnames[r1], 424 r2 == MAXREGS ? "" : rnames[r2], sh); 425 } else 426 fprintf(io, "(%s)", rnames[p->n_rval]); 427 return; 428 case ICON: 429 /* addressable value of the constant */ 430 if (p->n_type == LONGLONG || p->n_type == ULONGLONG) { 431 fprintf(io, "#" CONFMT, getlval(p) >> 32); 432 } else { 433 fputc('#', io); 434 conput(io, p); 435 } 436 return; 437 438 case REG: 439 if ((p->n_type == LONGLONG || p->n_type == ULONGLONG) && 440 /* XXX allocated reg may get wrong type here */ 441 (p->n_rval > A7 && p->n_rval < FP0)) { 442 fprintf(io, "%%%c%c", rnames[p->n_rval][0], 443 rnames[p->n_rval][1]); 444 } else 445 fprintf(io, "%s", rnames[p->n_rval]); 446 return; 447 448 default: 449 comperr("illegal address, op %d, node %p", p->n_op, p); 450 return; 451 452 } 453} 454 455static char * 456ccbranches[] = { 457 "jeq", /* jumpe */ 458 "jne", /* jumpn */ 459 "jle", /* jumple */ 460 "jlt", /* jumpl */ 461 "jge", /* jumpge */ 462 "jgt", /* jumpg */ 463 "jls", /* jumple (jlequ) */ 464 "jcs", /* jumpl (jlssu) */ 465 "jcc", /* jumpge (jgequ) */ 466 "jhi", /* jumpg (jgtru) */ 467}; 468 469 470/* printf conditional and unconditional branches */ 471void 472cbgen(int o, int lab) 473{ 474 if (o < EQ || o > UGT) 475 comperr("bad conditional branch: %s", opst[o]); 476 printf(" %s " LABFMT "\n", ccbranches[o-EQ], lab); 477} 478 479static void 480mkcall(NODE *p, char *name) 481{ 482 p->n_op = CALL; 483 p->n_right = mkunode(FUNARG, p->n_left, 0, p->n_left->n_type); 484 p->n_left = mklnode(ICON, 0, 0, FTN|p->n_type); 485 p->n_left->n_name = name; 486} 487 488static void 489mkcall2(NODE *p, char *name) 490{ 491 p->n_op = CALL; 492 p->n_right = mkunode(FUNARG, p->n_right, 0, p->n_right->n_type); 493 p->n_left = mkunode(FUNARG, p->n_left, 0, p->n_left->n_type); 494 p->n_right = mkbinode(CM, p->n_left, p->n_right, INT); 495 p->n_left = mklnode(ICON, 0, 0, FTN|p->n_type); 496 p->n_left->n_name = name; 497} 498 499 500static void 501fixcalls(NODE *p, void *arg) 502{ 503 struct attr *ap; 504 TWORD lt; 505 506 switch (p->n_op) { 507 case STCALL: 508 case USTCALL: 509 ap = attr_find(p->n_ap, ATTR_P2STRUCT); 510 if (ap->iarg(0)+p2autooff > stkpos) 511 stkpos = ap->iarg(0)+p2autooff; 512 break; 513 514 case DIV: 515 if (p->n_type == LONGLONG) 516 mkcall2(p, "__divdi3"); 517 else if (p->n_type == ULONGLONG) 518 mkcall2(p, "__udivdi3"); 519 break; 520 521 case MOD: 522 if (p->n_type == LONGLONG) 523 mkcall2(p, "__moddi3"); 524 else if (p->n_type == ULONGLONG) 525 mkcall2(p, "__umoddi3"); 526 break; 527 528 case MUL: 529 if (p->n_type == LONGLONG || p->n_type == ULONGLONG) 530 mkcall2(p, "__muldi3"); 531 break; 532 533 case LS: 534 if (p->n_type == LONGLONG || p->n_type == ULONGLONG) 535 mkcall2(p, "__ashldi3"); 536 break; 537 538 case RS: 539 if (p->n_type == LONGLONG) 540 mkcall2(p, "__ashrdi3"); 541 else if (p->n_type == ULONGLONG) 542 mkcall2(p, "__lshrdi3"); 543 break; 544 545 case SCONV: 546 lt = p->n_left->n_type; 547 switch (p->n_type) { 548 case LONGLONG: 549 if (lt == FLOAT) 550 mkcall(p, "__fixsfdi"); 551 else if (lt == DOUBLE) 552 mkcall(p, "__fixdfdi"); 553 else if (lt == LDOUBLE) 554 mkcall(p, "__fixxfdi"); 555 break; 556 case ULONGLONG: 557 if (lt == FLOAT) 558 mkcall(p, "__fixunssfdi"); 559 else if (lt == DOUBLE) 560 mkcall(p, "__fixunsdfdi"); 561 else if (lt == LDOUBLE) 562 mkcall(p, "__fixunsxfdi"); 563 break; 564 case FLOAT: 565 if (lt == LONGLONG) 566 mkcall(p, "__floatdisf"); 567 else if (lt == ULONGLONG) 568 mkcall(p, "__floatundisf"); 569 break; 570 case DOUBLE: 571 if (lt == LONGLONG) 572 mkcall(p, "__floatdidf"); 573 else if (lt == ULONGLONG) 574 mkcall(p, "__floatundidf"); 575 break; 576 case LDOUBLE: 577 if (lt == LONGLONG) 578 mkcall(p, "__floatdixf"); 579 else if (lt == ULONGLONG) 580 mkcall(p, "__floatundixf"); 581 break; 582 } 583 break; 584#if 0 585 case XASM: 586 p->n_name = adjustname(p->n_name); 587 break; 588#endif 589 } 590} 591 592void 593myreader(struct interpass *ipole) 594{ 595 struct interpass *ip; 596 597 stkpos = p2autooff; 598 DLIST_FOREACH(ip, ipole, qelem) { 599 if (ip->type != IP_NODE) 600 continue; 601 walkf(ip->ip_node, fixcalls, 0); 602 } 603 if (stkpos > p2autooff) 604 p2autooff = stkpos; 605 if (stkpos > p2maxautooff) 606 p2maxautooff = stkpos; 607 if (x2debug) 608 printip(ipole); 609} 610 611/* 612 * Remove some PCONVs after OREGs are created. 613 */ 614static void 615pconv2(NODE *p, void *arg) 616{ 617 NODE *q; 618 619 if (p->n_op == PLUS) { 620 if (p->n_type == (PTR|SHORT) || p->n_type == (PTR|USHORT)) { 621 if (p->n_right->n_op != ICON) 622 return; 623 if (p->n_left->n_op != PCONV) 624 return; 625 if (p->n_left->n_left->n_op != OREG) 626 return; 627 q = p->n_left->n_left; 628 nfree(p->n_left); 629 p->n_left = q; 630 /* 631 * This will be converted to another OREG later. 632 */ 633 } 634 } 635} 636 637void 638mycanon(NODE *p) 639{ 640 walkf(p, pconv2, 0); 641} 642 643void 644myoptim(struct interpass *ip) 645{ 646} 647 648void 649rmove(int s, int d, TWORD t) 650{ 651 652 if (s >= D0D1 && s <= D6D7) { 653 printf(" move.l %s,%s\n", 654 rnames[s-D0D1], rnames[d-D0D1]); 655 printf(" move.l %s,%s\n", 656 rnames[s+1-D0D1], rnames[d+1-D0D1]); 657 } else if (t >= FLOAT && t <= TDOUBLE) 658 printf(" fmove.x %s,%s\n", rnames[s], rnames[d]); 659 else 660 printf(" move.l %s,%s\n", rnames[s], rnames[d]); 661} 662 663/* 664 * For class cc, find worst-case displacement of the number of 665 * registers in the array r[] indexed by class. 666 */ 667int 668COLORMAP(int cc, int *r) 669{ 670 int a,c; 671 672 a = r[CLASSA]; 673 c = r[CLASSC]; 674 675 switch (cc) { 676 case CLASSA: 677 if (c * 2 + a < 8) 678 return 1; 679 break; 680 case CLASSB: 681 return r[CLASSB] < 6; 682 case CLASSC: 683 if (c > 2) 684 return 0; 685 if (c == 2 && a > 0) 686 return 0; 687 if (c == 1 && a > 1) 688 return 0; 689 if (c == 0 && a > 3) 690 return 0; 691 return 1; 692 } 693 return 0; 694} 695 696char *rnames[] = { 697 "%d0", "%d1", "%d2", "%d3", "%d4", "%d5", "%d6", "%d7", 698 "%a0", "%a1", "%a2", "%a3", "%a4", "%a5", "%a6", "%a7", 699 "d0d1", "d1d2", "d2d3", "d3d4", "d4d5", "d5d6", "d6d7", 700 "%fp0", "%fp1", "%fp2", "%fp3", "%fp4", "%fp5", "%fp6", "%fp7", 701}; 702 703/* 704 * Return a class suitable for a specific type. 705 */ 706int 707gclass(TWORD t) 708{ 709 if (t > BTMASK) 710 return CLASSB; 711 if (t == LONGLONG || t == ULONGLONG) 712 return CLASSC; 713 if (t == FLOAT || t == DOUBLE || t == LDOUBLE) 714 return CLASSD; 715 return CLASSA; 716} 717 718static int 719argsiz(NODE *p) 720{ 721 TWORD t = p->n_type; 722 723 if (t < LONGLONG || t == FLOAT || t > BTMASK) 724 return 4; 725 if (t == LONGLONG || t == ULONGLONG || t == DOUBLE) 726 return 8; 727 if (t == LDOUBLE) 728 return 12; 729 if (t == STRTY || t == UNIONTY) 730 return (attr_find(p->n_ap, ATTR_P2STRUCT)->iarg(0)+3) & ~3; 731 comperr("argsiz"); 732 return 0; 733} 734 735/* 736 * Calculate argument sizes. 737 */ 738void 739lastcall(NODE *p) 740{ 741 NODE *op = p; 742 int size = 0; 743 744 p->n_qual = 0; 745 if (p->n_op != CALL && p->n_op != FORTCALL && p->n_op != STCALL) 746 return; 747 for (p = p->n_right; p->n_op == CM; p = p->n_left) 748 size += argsiz(p->n_right); 749 size += argsiz(p); 750 op->n_qual = size; /* XXX */ 751} 752 753/* 754 * Special shapes. 755 */ 756int 757special(NODE *p, int shape) 758{ 759 return SRNOPE; 760} 761 762/* 763 * Target-dependent command-line options. 764 */ 765void 766mflags(char *str) 767{ 768} 769 770/* 771 * Do something target-dependent for xasm arguments. 772 */ 773int 774myxasm(struct interpass *ip, NODE *p) 775{ 776 int cw = xasmcode(p->n_name); 777 int ww; 778 char *w; 779 780 ww = XASMVAL(cw); 781again: switch (ww) { 782 case 'd': /* Just convert to reg */ 783 case 'a': 784 p->n_name = tmpstrdup(p->n_name); 785 w = strchr(p->n_name, XASMVAL(cw)); 786 *w = 'r'; /* now reg */ 787 break; 788 case 'o': /* offsetable reg */ 789 if (p->n_left->n_op == UMUL || p->n_left->n_op == OREG || 790 p->n_left->n_op == NAME) { 791 return 1; 792 } 793 if (ww == XASMVAL(cw)) 794 ww = XASMVAL1(cw); 795 else 796 ww = XASMVAL2(cw); 797 goto again; 798 } 799 return 0; 800} 801 802/* 803 * Handle special characters following % in gcc extended assembler. 804 */ 805int 806targarg(char *w, void *arg) 807{ 808 switch (w[1]) { 809 case '.': /* Remove dot if not needed */ 810 printf("."); 811 break; 812 default: 813 return 0; 814 } 815 return 1; 816} 817