1/* Id: local2.c,v 1.102 2008/11/22 16:12:25 ragge Exp */ 2/* $NetBSD$ */ 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# include "pass2.h" 32# include <ctype.h> 33 34# define putstr(s) fputs((s), stdout) 35 36void acon(FILE *, NODE *p); 37int argsize(NODE *p); 38void genargs(NODE *p); 39 40static int offlab; 41int offarg; 42static int addto; 43static int regoff[16]; 44 45void 46deflab(int label) 47{ 48 printf(LABFMT ":\n", label); 49} 50 51void 52prologue(struct interpass_prolog *ipp) 53{ 54 int i, j; 55 56 if (ipp->ipp_vis) 57 printf(" .globl %s\n", ipp->ipp_name); 58 printf("%s:\n", ipp->ipp_name); 59 addto = p2maxautooff; 60 if (addto >= AUTOINIT/SZCHAR) 61 addto -= AUTOINIT/SZCHAR; 62 addto /= SZINT/SZCHAR; /* use words here */ 63 printf(" push %s,%s\n",rnames[STKREG], rnames[FPREG]); 64 printf(" move %s,%s\n", rnames[FPREG],rnames[STKREG]); 65 66 for (i = ipp->ipp_regs[0], j = 0; i ; i >>= 1, j++) { 67 if (i & 1) 68 regoff[j] = addto++; 69 } 70 if (addto) 71 printf(" addi %s,0%o\n", rnames[STKREG], addto); 72 73 for (i = ipp->ipp_regs[0], j = 0; i ; i >>= 1, j++) { 74 if (i & 1) 75 printf(" movem %s,%d(%s)\n", 76 rnames[j], regoff[j], rnames[STKREG]); 77 } 78} 79 80void 81eoftn(struct interpass_prolog *ipp) 82{ 83 int i, j; 84 85 if (ipp->ipp_ip.ip_lbl == 0) 86 return; /* no code needs to be generated */ 87 for (i = ipp->ipp_regs[0], j = 0; i ; i >>= 1, j++) { 88 if (i & 1) 89 printf(" move %s,%d(%s)\n", 90 rnames[j], regoff[j], rnames[STKREG]); 91 } 92 printf(" move %s,%s\n", rnames[STKREG], rnames[FPREG]); 93 printf(" pop %s,%s\n", rnames[STKREG], rnames[FPREG]); 94 printf(" popj %s,\n", rnames[STKREG]); 95} 96 97#if 0 98void 99prologue(int regs, int autos) 100{ 101 int i, addto; 102 103 offlab = getlab2(); 104 if (regs < 0 || autos < 0) { 105 /* 106 * non-optimized code, jump to epilogue for code generation. 107 */ 108 ftlab1 = getlab2(); 109 ftlab2 = getlab2(); 110 printf(" jrst L%d\n", ftlab1); 111 printf("L%d:\n", ftlab2); 112 } else { 113 /* 114 * We here know what register to save and how much to 115 * add to the stack. 116 */ 117 autos = autos + (SZINT-1); 118 addto = (autos - AUTOINIT)/SZINT + (MAXRVAR-regs); 119 if (addto || gflag) { 120 printf(" push %s,%s\n",rnames[017], rnames[016]); 121 printf(" move %s,%s\n", rnames[016],rnames[017]); 122 for (i = regs; i < MAXRVAR; i++) { 123 int db = ((i+1) < MAXRVAR); 124 printf(" %smovem %s,0%o(%s)\n", 125 db ? "d" : "", 126 rnames[i+1], i+1-regs, rnames[016]); 127 if (db) 128 i++; 129 } 130 if (addto) 131 printf(" addi %s,0%o\n", rnames[017], addto); 132 } else 133 offarg = 1; 134 } 135} 136 137/* 138 * End of block. 139 */ 140void 141eoftn(int regs, int autos, int retlab) 142{ 143 register OFFSZ spoff; /* offset from stack pointer */ 144 int i; 145 146 spoff = autos + (SZINT-1); 147 if (spoff >= AUTOINIT) 148 spoff -= AUTOINIT; 149 spoff /= SZINT; 150 /* return from function code */ 151 printf("L%d:\n", retlab); 152 if (gflag || isoptim == 0 || autos != AUTOINIT || regs != MAXRVAR) { 153 for (i = regs; i < MAXRVAR; i++) { 154 int db = ((i+1) < MAXRVAR); 155 printf(" %smove %s,0%o(%s)\n", db ? "d" : "", 156 rnames[i+1], i+1-regs, rnames[016]); 157 if (db) 158 i++; 159 } 160 printf(" move %s,%s\n", rnames[017], rnames[016]); 161 printf(" pop %s,%s\n", rnames[017], rnames[016]); 162 } 163 printf(" popj %s,\n", rnames[017]); 164 165 /* Prolog code */ 166 if (isoptim == 0) { 167 printf("L%d:\n", ftlab1); 168 printf(" push %s,%s\n", rnames[017], rnames[016]); 169 printf(" move %s,%s\n", rnames[016], rnames[017]); 170 for (i = regs; i < MAXRVAR; i++) { 171 int db = ((i+1) < MAXRVAR); 172 printf(" %smovem %s,0%o(%s)\n", db ? "d" : "", 173 rnames[i+1], i+1-regs, rnames[016]); 174 spoff++; 175 if (db) 176 i++, spoff++; 177 } 178 if (spoff) 179 printf(" addi %s,0%llo\n", rnames[017], spoff); 180 printf(" jrst L%d\n", ftlab2); 181 } 182 printf(" .set " LABFMT ",0%o\n", offlab, MAXRVAR-regs); 183 offarg = isoptim = 0; 184} 185#endif 186 187/* 188 * add/sub/... 189 * 190 * Param given: 191 * R - Register 192 * M - Memory 193 * C - Constant 194 */ 195void 196hopcode(int f, int o) 197{ 198 cerror("hopcode: f %d %d", f, o); 199} 200 201char * 202rnames[] = { /* keyed to register number tokens */ 203 "%0", "%1", "%2", "%3", "%4", "%5", "%6", "%7", 204 "%10", "%11", "%12", "%13", "%14", "%15", "%16", "%17", 205 "%0", "%1", "%2", "%3", "%4", "%5", "%6", "%7", 206 "%10", "%11", "%12", "%13", "%14", "%15", 207}; 208 209int 210tlen(p) NODE *p; 211{ 212 switch(p->n_type) { 213 case CHAR: 214 case UCHAR: 215 return(1); 216 217 case SHORT: 218 case USHORT: 219 return(SZSHORT/SZCHAR); 220 221 case DOUBLE: 222 return(SZDOUBLE/SZCHAR); 223 224 case INT: 225 case UNSIGNED: 226 case LONG: 227 case ULONG: 228 return(SZINT/SZCHAR); 229 230 case LONGLONG: 231 case ULONGLONG: 232 return SZLONGLONG/SZCHAR; 233 234 default: 235 if (!ISPTR(p->n_type)) 236 cerror("tlen type %d not pointer"); 237 return SZPOINT(0)/SZCHAR; 238 } 239} 240 241static char * 242binskip[] = { 243 "e", /* jumpe */ 244 "n", /* jumpn */ 245 "le", /* jumple */ 246 "l", /* jumpl */ 247 "ge", /* jumpge */ 248 "g", /* jumpg */ 249}; 250 251/* 252 * Extract the higher 36 bits from a longlong. 253 */ 254static CONSZ 255gethval(CONSZ lval) 256{ 257 CONSZ hval = (lval >> 35) & 03777777777LL; 258 259 if ((hval & 03000000000LL) == 03000000000LL) { 260 hval |= 0777000000000LL; 261 } else if ((hval & 03000000000LL) == 02000000000LL) { 262 hval &= 01777777777LL; 263 hval |= 0400000000000LL; 264 } 265 return hval; 266} 267 268/* 269 * Do a binary comparision, and jump accordingly. 270 */ 271static void 272twocomp(NODE *p) 273{ 274 int o = p->n_op; 275 extern int negrel[]; 276 int isscon = 0, iscon = p->n_right->n_op == ICON; 277 278 if (o < EQ || o > GT) 279 cerror("bad binary conditional branch: %s", opst[o]); 280 281 if (iscon && p->n_right->n_name[0] != 0) { 282 printf(" cam%s ", binskip[negrel[o-EQ]-EQ]); 283 adrput(stdout, getlr(p, 'L')); 284 putchar(','); 285 printf("[ .long "); 286 adrput(stdout, getlr(p, 'R')); 287 putchar(']'); 288 printf("\n jrst L%d\n", p->n_label); 289 return; 290 } 291 if (iscon) 292 isscon = p->n_right->n_lval >= 0 && 293 p->n_right->n_lval < 01000000; 294 295 printf(" ca%c%s ", iscon && isscon ? 'i' : 'm', 296 binskip[negrel[o-EQ]-EQ]); 297 adrput(stdout, getlr(p, 'L')); 298 putchar(','); 299 if (iscon && (isscon == 0)) { 300 printf("[ .long "); 301 adrput(stdout, getlr(p, 'R')); 302 putchar(']'); 303 } else 304 adrput(stdout, getlr(p, 'R')); 305 printf("\n jrst L%d\n", p->n_label); 306} 307 308/* 309 * Compare byte/word pointers. 310 * XXX - do not work for highest bit set in address 311 */ 312static void 313ptrcomp(NODE *p) 314{ 315 printf(" rot "); adrput(stdout, getlr(p, 'L')); printf(",6\n"); 316 printf(" rot "); adrput(stdout, getlr(p, 'R')); printf(",6\n"); 317 twocomp(p); 318} 319 320/* 321 * Do a binary comparision of two long long, and jump accordingly. 322 * XXX - can optimize for constants. 323 */ 324static void 325twollcomp(NODE *p) 326{ 327 int o = p->n_op; 328 int iscon = p->n_right->n_op == ICON; 329 int m = 0; /* XXX gcc */ 330 331 if (o < EQ || o > GT) 332 cerror("bad long long conditional branch: %s", opst[o]); 333 334 /* Special strategy for equal/not equal */ 335 if (o == EQ || o == NE) { 336 if (o == EQ) 337 m = getlab2(); 338 printf(" came "); 339 upput(getlr(p, 'L'), SZLONG); 340 putchar(','); 341 if (iscon) 342 printf("[ .long "); 343 upput(getlr(p, 'R'), SZLONG); 344 if (iscon) 345 putchar(']'); 346 printf("\n jrst L%d\n", o == EQ ? m : p->n_label); 347 printf(" cam%c ", o == EQ ? 'n' : 'e'); 348 adrput(stdout, getlr(p, 'L')); 349 putchar(','); 350 if (iscon) 351 printf("[ .long "); 352 adrput(stdout, getlr(p, 'R')); 353 if (iscon) 354 putchar(']'); 355 printf("\n jrst L%d\n", p->n_label); 356 if (o == EQ) 357 printf("L%d:\n", m); 358 return; 359 } 360 /* First test highword */ 361 printf(" cam%ce ", o == GT || o == GE ? 'l' : 'g'); 362 adrput(stdout, getlr(p, 'L')); 363 putchar(','); 364 if (iscon) 365 printf("[ .long "); 366 adrput(stdout, getlr(p, 'R')); 367 if (iscon) 368 putchar(']'); 369 printf("\n jrst L%d\n", p->n_label); 370 371 /* Test equality */ 372 printf(" came "); 373 adrput(stdout, getlr(p, 'L')); 374 putchar(','); 375 if (iscon) 376 printf("[ .long "); 377 adrput(stdout, getlr(p, 'R')); 378 if (iscon) 379 putchar(']'); 380 printf("\n jrst L%d\n", m = getlab2()); 381 382 /* Test lowword. Only works with pdp10 format for longlongs */ 383 printf(" cam%c%c ", o == GT || o == GE ? 'l' : 'g', 384 o == LT || o == GT ? 'e' : ' '); 385 upput(getlr(p, 'L'), SZLONG); 386 putchar(','); 387 if (iscon) 388 printf("[ .long "); 389 upput(getlr(p, 'R'), SZLONG); 390 if (iscon) 391 putchar(']'); 392 printf("\n jrst L%d\n", p->n_label); 393 printf("L%d:\n", m); 394} 395 396/* 397 * Print the correct instruction for constants. 398 */ 399static void 400constput(NODE *p) 401{ 402 CONSZ val = p->n_right->n_lval; 403 int reg = p->n_left->n_rval; 404 405 /* Only numeric constant */ 406 if (p->n_right->n_name[0] == '\0') { 407 if (val == 0) { 408 printf("movei %s,0", rnames[reg]); 409 } else if ((val & 0777777000000LL) == 0) { 410 printf("movei %s,0%llo", rnames[reg], val); 411 } else if ((val & 0777777) == 0) { 412 printf("hrlzi %s,0%llo", rnames[reg], val >> 18); 413 } else { 414 printf("move %s,[ .long 0%llo]", rnames[reg], 415 szty(p->n_right->n_type) > 1 ? val : 416 val & 0777777777777LL); 417 } 418 /* Can have more tests here, hrloi etc */ 419 return; 420 } else { 421 printf("xmovei %s,%s", rnames[reg], p->n_right->n_name); 422 if (val) 423 printf("+" CONFMT, val); 424 } 425} 426 427/* 428 * Return true if the constant can be bundled in an instruction (immediate). 429 */ 430static int 431oneinstr(NODE *p) 432{ 433 if (p->n_name[0] != '\0') 434 return 0; 435 if ((p->n_lval & 0777777000000ULL) != 0) 436 return 0; 437 return 1; 438} 439 440/* 441 * Emit a halfword or byte instruction, from OREG to REG. 442 * Sign extension must also be done here. 443 */ 444static void 445emitshort(NODE *p) 446{ 447 CONSZ off = p->n_lval; 448 TWORD type = p->n_type; 449 int reg = p->n_rval; 450 int issigned = !ISUNSIGNED(type); 451 int ischar = type == CHAR || type == UCHAR; 452 int reg1 = getlr(p, '1')->n_rval; 453 454 if (off < 0) { /* argument, use move instead */ 455 printf(" move "); 456 } else if (off == 0 && p->n_name[0] == 0) { 457 printf(" ldb %s,%s\n", rnames[reg1], rnames[reg]); 458 /* XXX must sign extend here even if not necessary */ 459 switch (type) { 460 case CHAR: 461 printf(" lsh %s,033\n", rnames[reg1]); 462 printf(" ash %s,-033\n", rnames[reg1]); 463 break; 464 case SHORT: 465 printf(" hrre %s,%s\n", 466 rnames[reg1], rnames[reg1]); 467 break; 468 } 469 return; 470 } else if (ischar) { 471 if (off >= 0700000000000LL && p->n_name[0] != '\0') { 472 cerror("emitsh"); 473 /* reg contains index integer */ 474// if (!istreg(reg)) 475// cerror("emitshort !istreg"); 476 printf(" adjbp %s,[ .long 0%llo+%s ]\n", 477 rnames[reg], off, p->n_name); 478 printf(" ldb "); 479 adrput(stdout, getlr(p, '1')); 480 printf(",%s\n", rnames[reg]); 481 goto signe; 482 } 483 printf(" ldb "); 484 adrput(stdout, getlr(p, '1')); 485 if (off) 486 printf(",[ .long 0%02o11%02o%06o ]\n", 487 (int)(27-(9*(off&3))), reg, (int)off/4); 488 else 489 printf(",%s\n", rnames[reg]); 490signe: if (issigned) { 491 printf(" lsh "); 492 adrput(stdout, getlr(p, '1')); 493 printf(",033\n ash "); 494 adrput(stdout, getlr(p, '1')); 495 printf(",-033\n"); 496 } 497 return; 498 } else { 499 printf(" h%cr%c ", off & 1 ? 'r' : 'l', 500 issigned ? 'e' : 'z'); 501 } 502 p->n_lval /= (ischar ? 4 : 2); 503 adrput(stdout, getlr(p, '1')); 504 putchar(','); 505 adrput(stdout, getlr(p, 'L')); 506 putchar('\n'); 507} 508 509/* 510 * Store a short from a register. Destination is a OREG. 511 */ 512static void 513storeshort(NODE *p) 514{ 515 NODE *l = p->n_left; 516 CONSZ off = l->n_lval; 517 int reg = l->n_rval; 518 int ischar = BTYPE(p->n_type) == CHAR || BTYPE(p->n_type) == UCHAR; 519 520 if (l->n_op == NAME) { 521 if (ischar) { 522 printf(" dpb "); 523 adrput(stdout, getlr(p, 'R')); 524 printf(",[ .long 0%02o%010o+%s ]\n", 525 070+((int)off&3), (int)(off/4), l->n_name); 526 return; 527 } 528 printf(" hr%cm ", off & 1 ? 'r' : 'l'); 529 l->n_lval /= 2; 530 adrput(stdout, getlr(p, 'R')); 531 putchar(','); 532 adrput(stdout, getlr(p, 'L')); 533 putchar('\n'); 534 return; 535 } 536 537 if (off || reg == FPREG) { /* Can emit halfword instructions */ 538 if (off < 0) { /* argument, use move instead */ 539 printf(" movem "); 540 } else if (ischar) { 541 printf(" dpb "); 542 adrput(stdout, getlr(p, '1')); 543 printf(",[ .long 0%02o11%02o%06o ]\n", 544 (int)(27-(9*(off&3))), reg, (int)off/4); 545 return; 546 } else { 547 printf(" hr%cm ", off & 1 ? 'r' : 'l'); 548 } 549 l->n_lval /= 2; 550 adrput(stdout, getlr(p, 'R')); 551 putchar(','); 552 adrput(stdout, getlr(p, 'L')); 553 } else { 554 printf(" dpb "); 555 adrput(stdout, getlr(p, 'R')); 556 putchar(','); 557 l = getlr(p, 'L'); 558 l->n_op = REG; 559 adrput(stdout, l); 560 l->n_op = OREG; 561 } 562 putchar('\n'); 563} 564 565/* 566 * Multiply a register with a constant. 567 */ 568static void 569imuli(NODE *p) 570{ 571 NODE *r = p->n_right; 572 573 if (r->n_lval >= 0 && r->n_lval <= 0777777) { 574 printf(" imuli "); 575 adrput(stdout, getlr(p, 'L')); 576 printf(",0%llo\n", r->n_lval); 577 } else { 578 printf(" imul "); 579 adrput(stdout, getlr(p, 'L')); 580 printf(",[ .long 0%llo ]\n", r->n_lval & 0777777777777LL); 581 } 582} 583 584/* 585 * Divide a register with a constant. 586 */ 587static void 588idivi(NODE *p) 589{ 590 NODE *r = p->n_right; 591 592 if (r->n_lval >= 0 && r->n_lval <= 0777777) { 593 printf(" idivi "); 594 adrput(stdout, getlr(p, '1')); 595 printf(",0%llo\n", r->n_lval); 596 } else { 597 printf(" idiv "); 598 adrput(stdout, getlr(p, '1')); 599 printf(",[ .long 0%llo ]\n", r->n_lval & 0777777777777LL); 600 } 601} 602 603/* 604 * move a constant into a register. 605 */ 606static void 607xmovei(NODE *p) 608{ 609 /* 610 * Trick: If this is an unnamed constant, just move it directly, 611 * otherwise use xmovei to get section number. 612 */ 613 if (p->n_name[0] == '\0' || p->n_lval > 0777777) { 614 printf(" "); 615 zzzcode(p, 'D'); 616 putchar(' '); 617 adrput(stdout, getlr(p, '1')); 618 putchar(','); 619 zzzcode(p, 'E'); 620 } else { 621 printf(" xmovei "); 622 adrput(stdout, getlr(p, '1')); 623 printf(",%s", p->n_name); 624 if (p->n_lval != 0) 625 printf("+0%llo", p->n_lval); 626 } 627 putchar('\n'); 628} 629 630static void 631printcon(NODE *p) 632{ 633 CONSZ cz; 634 635 p = p->n_left; 636 if (p->n_lval >= 0700000000000LL) { 637 /* converted to pointer in clocal() */ 638 conput(0, p); 639 return; 640 } 641 if (p->n_lval == 0 && p->n_name[0] == '\0') { 642 putchar('0'); 643 return; 644 } 645 if (BTYPE(p->n_type) == CHAR || BTYPE(p->n_type) == UCHAR) 646 cz = (p->n_lval/4) | ((p->n_lval & 3) << 30); 647 else 648 cz = (p->n_lval/2) | (((p->n_lval & 1) + 5) << 30); 649 cz |= 0700000000000LL; 650 printf("0%llo", cz); 651 if (p->n_name[0] != '\0') 652 printf("+%s", p->n_name); 653} 654 655static void 656putcond(NODE *p) 657{ 658 char *c = 0; /* XXX gcc */ 659 660 switch (p->n_op) { 661 case EQ: c = "e"; break; 662 case NE: c = "n"; break; 663 case LE: c = "le"; break; 664 case LT: c = "l"; break; 665 case GT: c = "g"; break; 666 case GE: c = "ge"; break; 667 default: 668 cerror("putcond"); 669 } 670 printf("%s", c); 671} 672 673void 674zzzcode(NODE *p, int c) 675{ 676 NODE *l; 677 CONSZ hval; 678 679 switch (c) { 680 case 'A': /* ildb right arg */ 681 adrput(stdout, p->n_left->n_left); 682 break; 683 684 case 'B': /* remove from stack after subroutine call */ 685 if (p->n_qual) 686 printf(" subi %%17,0%o\n", p->n_qual); 687 break; 688 689 case 'C': 690 constput(p); 691 break; 692 693 case 'D': /* Find out which type of const load insn to use */ 694 if (p->n_op != ICON) 695 cerror("zzzcode not ICON"); 696 if (p->n_name[0] == '\0') { 697 if ((p->n_lval <= 0777777) && (p->n_lval > 0)) 698 printf("movei"); 699 else if ((p->n_lval & 0777777) == 0) 700 printf("hrlzi"); 701 else 702 printf("move"); 703 } else 704 printf("move"); 705 break; 706 707 case 'E': /* Print correct constant expression */ 708 if (p->n_name[0] == '\0') { 709 if ((p->n_lval <= 0777777) && (p->n_lval > 0)){ 710 printf("0%llo", p->n_lval); 711 } else if ((p->n_lval & 0777777) == 0) { 712 printf("0%llo", p->n_lval >> 18); 713 } else { 714 if (p->n_lval < 0) 715 printf("[ .long -0%llo]", -p->n_lval); 716 else 717 printf("[ .long 0%llo]", p->n_lval); 718 } 719 } else { 720 if (p->n_lval == 0) 721 printf("[ .long %s]", p->n_name); 722 else 723 printf("[ .long %s+0%llo]", 724 p->n_name, p->n_lval); 725 } 726 break; 727 728 case 'G': /* structure argument */ 729 printf(" addl %%17,0%o\n", p->n_stsize/(SZINT/SZCHAR)); 730 printf(" foo...\n"); 731 break; 732 733 case 'P': 734 p = getlr(p, 'R'); 735 /* FALLTHROUGH */ 736 case 'O': 737 /* 738 * Print long long expression. 739 */ 740 hval = gethval(p->n_lval); 741 printf("[ .long 0%llo,0%llo", hval, 742 (p->n_lval & 0377777777777LL) | (hval & 0400000000000LL)); 743 if (p->n_name[0] != '\0') 744 printf("+%s", p->n_name); 745 printf(" ]"); 746 break; 747 748 case 'F': /* Print an "opsimp" instruction based on its const type */ 749 hopcode(oneinstr(p->n_right) ? 'C' : 'R', p->n_op); 750 break; 751 752 case 'H': /* Print a small constant */ 753 p = p->n_right; 754 printf("0%llo", p->n_lval & 0777777); 755 break; 756 757 case 'Q': /* two-param long long comparisions */ 758 twollcomp(p); 759 break; 760 761 case 'R': /* two-param conditionals */ 762 twocomp(p); 763 break; 764 765 case 'U': 766 emitshort(p); 767 break; 768 769 case 'V': 770 storeshort(p); 771 break; 772 773 case 'Z': 774 ptrcomp(p); 775 break; 776 777 case 'a': 778 imuli(p); 779 break; 780 781 case 'b': 782 idivi(p); 783 break; 784 785 case 'c': 786 xmovei(p); 787 break; 788 789 case 'd': 790 printcon(p); 791 break; 792 793 case 'e': 794 putcond(p); 795 break; 796 797 case 'g': 798 if (p->n_right->n_op != OREG || p->n_right->n_lval != 0) 799 comperr("bad Zg oreg"); 800 printf("%s", rnames[p->n_right->n_rval]); 801 break; 802 803#if 0 804 case '1': /* double upput */ 805 p = getlr(p, '1'); 806 p->n_rval += 2; 807 adrput(stdout, p); 808 p->n_rval -= 2; 809 break; 810#endif 811 812 case 'i': /* Write instruction for short load from name */ 813 l = getlr(p, 'L'); 814 printf(" h%cr%c %s,%s+" CONFMT "\n", 815 l->n_lval & 1 ? 'r' : 'l', 816 ISUNSIGNED(p->n_type) ? 'z' : 'e', 817 rnames[getlr(p, '1')->n_rval], 818 l->n_name, l->n_lval >> 1); 819 break; 820 821 default: 822 cerror("zzzcode %c", c); 823 } 824} 825 826/* set up temporary registers */ 827void 828setregs() 829{ 830 fregs = 7; /* 7 free regs on PDP10 (1-7) */ 831} 832 833/*ARGSUSED*/ 834int 835rewfld(NODE *p) 836{ 837 return(1); 838} 839 840int 841fldexpand(NODE *p, int cookie, char **cp) 842{ 843 return 0; 844} 845 846int 847flshape(NODE *p) 848{ 849 register int o = p->n_op; 850 851 return (o == REG || o == NAME || o == ICON || 852 (o == OREG && (!R2TEST(p->n_rval) || tlen(p) == 1))); 853} 854 855/* INTEMP shapes must not contain any temporary registers */ 856int 857shtemp(NODE *p) 858{ 859 return(0); 860} 861 862int 863shumul(NODE *p, int order) 864{ 865 register int o; 866 867 if (x2debug) { 868 int val; 869 printf("shumul(%p)\n", p); 870 eprint(p, 0, &val, &val); 871 } 872 873 o = p->n_op; 874#if 0 875 if (o == NAME || (o == OREG && !R2TEST(p->n_rval)) || o == ICON) 876 return(STARNM); 877#endif 878 879#if 0 880 if ((o == INCR) && 881 (p->n_left->n_op == REG && p->n_right->n_op == ICON) && 882 p->n_right->n_name[0] == '\0') { 883 switch (p->n_type) { 884 case CHAR|PTR: 885 case UCHAR|PTR: 886 o = 1; 887 break; 888 889 case SHORT|PTR: 890 case USHORT|PTR: 891 o = 2; 892 break; 893 894 case INT|PTR: 895 case UNSIGNED|PTR: 896 case LONG|PTR: 897 case ULONG|PTR: 898 case FLOAT|PTR: 899 o = 4; 900 break; 901 902 case DOUBLE|PTR: 903 case LONGLONG|PTR: 904 case ULONGLONG|PTR: 905 o = 8; 906 break; 907 908 default: 909 if (ISPTR(p->n_type) && 910 ISPTR(DECREF(p->n_type))) { 911 o = 4; 912 break; 913 } else 914 return(0); 915 } 916 return( 0); 917 } 918#endif 919 return( SRNOPE ); 920} 921 922void 923adrcon(CONSZ val) 924{ 925 cerror("adrcon: val %llo\n", val); 926} 927 928void 929conput(FILE *fp, NODE *p) 930{ 931 switch (p->n_op) { 932 case ICON: 933 if (p->n_lval != 0) { 934 acon(stdout, p); 935 if (p->n_name[0] != '\0') 936 putchar('+'); 937 } 938 if (p->n_name[0] != '\0') 939 printf("%s", p->n_name); 940 if (p->n_name[0] == '\0' && p->n_lval == 0) 941 putchar('0'); 942 return; 943 944 case REG: 945 putstr(rnames[p->n_rval]); 946 return; 947 948 default: 949 cerror("illegal conput"); 950 } 951} 952 953/*ARGSUSED*/ 954void 955insput(NODE *p) 956{ 957 cerror("insput"); 958} 959 960/* 961 * Write out the upper address, like the upper register of a 2-register 962 * reference, or the next memory location. 963 */ 964void 965upput(NODE *p, int size) 966{ 967 968 size /= SZLONG; 969 switch (p->n_op) { 970 case REG: 971 putstr(rnames[p->n_rval + size]); 972 break; 973 974 case NAME: 975 case OREG: 976 p->n_lval += size; 977 adrput(stdout, p); 978 p->n_lval -= size; 979 break; 980 case ICON: 981 printf(CONFMT, p->n_lval >> (36 * size)); 982 break; 983 default: 984 cerror("upput bad op %d size %d", p->n_op, size); 985 } 986} 987 988void 989adrput(FILE *fp, NODE *p) 990{ 991 int r; 992 /* output an address, with offsets, from p */ 993 994 if (p->n_op == FLD) 995 p = p->n_left; 996 997 switch (p->n_op) { 998 999 case NAME: 1000 if (p->n_name[0] != '\0') 1001 fputs(p->n_name, fp); 1002 if (p->n_lval != 0) 1003 fprintf(fp, "+" CONFMT, p->n_lval & 0777777777777LL); 1004 return; 1005 1006 case OREG: 1007 r = p->n_rval; 1008#if 0 1009 if (R2TEST(r)) { /* double indexing */ 1010 register int flags; 1011 1012 flags = R2UPK3(r); 1013 if (flags & 1) 1014 putc('*', fp); 1015 if (flags & 4) 1016 putc('-', fp); 1017 if (p->n_lval != 0 || p->n_name[0] != '\0') 1018 acon(p); 1019 if (R2UPK1(r) != 100) 1020 printf("(%s)", rnames[R2UPK1(r)]); 1021 if (flags & 2) 1022 putchar('+'); 1023 printf("[%s]", rnames[R2UPK2(r)]); 1024 return; 1025 } 1026#endif 1027 if (R2TEST(r)) 1028 cerror("adrput: unwanted double indexing: r %o", r); 1029 if (p->n_rval != FPREG && p->n_lval < 0 && p->n_name[0]) { 1030 fprintf(fp, "%s", p->n_name); 1031 acon(fp, p); 1032 fprintf(fp, "(%s)", rnames[p->n_rval]); 1033 return; 1034 } 1035 if (p->n_lval < 0 && p->n_rval == FPREG && offarg) { 1036 p->n_lval -= offarg-2; acon(fp, p); p->n_lval += offarg-2; 1037 } else if (p->n_lval != 0) 1038 acon(fp, p); 1039 if (p->n_name[0] != '\0') 1040 fprintf(fp, "%s%s", p->n_lval ? "+" : "", p->n_name); 1041 if (p->n_lval > 0 && p->n_rval == FPREG && offlab) 1042 fprintf(fp, "+" LABFMT, offlab); 1043 if (p->n_lval < 0 && p->n_rval == FPREG && offarg) 1044 fprintf(fp, "(017)"); 1045 else 1046 fprintf(fp, "(%s)", rnames[p->n_rval]); 1047 return; 1048 case ICON: 1049 /* addressable value of the constant */ 1050 if (p->n_lval > 0) { 1051 acon(fp, p); 1052 if (p->n_name[0] != '\0') 1053 putc('+', fp); 1054 } 1055 if (p->n_name[0] != '\0') 1056 fprintf(fp, "%s", p->n_name); 1057 if (p->n_lval < 0) 1058 acon(fp, p); 1059 if (p->n_name[0] == '\0' && p->n_lval == 0) 1060 putc('0', fp); 1061 return; 1062 1063 case REG: 1064 fputs(rnames[p->n_rval], fp); 1065 return; 1066 1067 default: 1068 cerror("illegal address, op %d", p->n_op); 1069 return; 1070 1071 } 1072} 1073 1074/* 1075 * print out a constant 1076*/ 1077void 1078acon(FILE *fp, NODE *p) 1079{ 1080 if (p->n_lval < 0 && p->n_lval > -0777777777777ULL) 1081 fprintf(fp, "-" CONFMT, -p->n_lval); 1082 else 1083 fprintf(fp, CONFMT, p->n_lval); 1084} 1085 1086/* printf conditional and unconditional branches */ 1087void 1088cbgen(int o,int lab) 1089{ 1090} 1091 1092/* 1093 * Do some local optimizations that must be done after optim is called. 1094 */ 1095static void 1096optim2(NODE *p, void *arg) 1097{ 1098 int op = p->n_op; 1099 int m, ml; 1100 NODE *l; 1101 1102 /* Remove redundant PCONV's */ 1103 if (op == PCONV) { 1104 l = p->n_left; 1105 m = BTYPE(p->n_type); 1106 ml = BTYPE(l->n_type); 1107 if ((m == INT || m == LONG || m == LONGLONG || m == FLOAT || 1108 m == DOUBLE || m == STRTY || m == UNIONTY || 1109 m == UNSIGNED || m == ULONG || m == ULONGLONG) && 1110 (ml == INT || ml == LONG || ml == LONGLONG || ml == FLOAT || 1111 ml == DOUBLE || ml == STRTY || ml == UNIONTY || 1112 ml == UNSIGNED || ml == ULONG || 1113 ml == ULONGLONG) && ISPTR(l->n_type)) { 1114 *p = *l; 1115 nfree(l); 1116 op = p->n_op; 1117 } else 1118 if (ISPTR(DECREF(p->n_type)) && 1119 (l->n_type == INCREF(STRTY))) { 1120 *p = *l; 1121 nfree(l); 1122 op = p->n_op; 1123 } else 1124 if (ISPTR(DECREF(l->n_type)) && 1125 (p->n_type == INCREF(INT) || 1126 p->n_type == INCREF(STRTY) || 1127 p->n_type == INCREF(UNSIGNED))) { 1128 *p = *l; 1129 nfree(l); 1130 op = p->n_op; 1131 } 1132 1133 } 1134 /* Add constands, similar to the one in optim() */ 1135 if (op == PLUS && p->n_right->n_op == ICON) { 1136 l = p->n_left; 1137 if (l->n_op == PLUS && l->n_right->n_op == ICON && 1138 (p->n_right->n_name[0] == '\0' || 1139 l->n_right->n_name[0] == '\0')) { 1140 l->n_right->n_lval += p->n_right->n_lval; 1141 if (l->n_right->n_name[0] == '\0') 1142 l->n_right->n_name = p->n_right->n_name; 1143 nfree(p->n_right); 1144 *p = *l; 1145 nfree(l); 1146 } 1147 } 1148 1149 /* Convert "PTR undef" (void *) to "PTR uchar" */ 1150 /* XXX - should be done in MI code */ 1151 if (BTYPE(p->n_type) == VOID) 1152 p->n_type = (p->n_type & ~BTMASK) | UCHAR; 1153 if (op == ICON) { 1154 if ((p->n_type == (PTR|CHAR) || p->n_type == (PTR|UCHAR)) 1155 && p->n_lval == 0 && p->n_name[0] != '\0') 1156 p->n_lval = 0700000000000LL; 1157 if ((p->n_type == (PTR|SHORT) || p->n_type == (PTR|USHORT)) 1158 && p->n_lval == 0 && p->n_name[0] != '\0') 1159 p->n_lval = 0750000000000LL; 1160 } 1161 if (op == MINUS) { 1162 if ((p->n_left->n_type == (PTR|CHAR) || 1163 p->n_left->n_type == (PTR|UCHAR)) && 1164 (p->n_right->n_type == (PTR|CHAR) || 1165 p->n_right->n_type == (PTR|UCHAR))) { 1166 l = talloc(); 1167 l->n_op = SCONV; 1168 l->n_type = INT; 1169 l->n_left = p->n_right; 1170 p->n_right = l; 1171 l = talloc(); 1172 l->n_op = SCONV; 1173 l->n_type = INT; 1174 l->n_left = p->n_left; 1175 p->n_left = l; 1176 } 1177 } 1178} 1179 1180void 1181myreader(struct interpass *ipole) 1182{ 1183 struct interpass *ip; 1184 1185 DLIST_FOREACH(ip, ipole, qelem) { 1186 if (ip->type != IP_NODE) 1187 continue; 1188 walkf(ip->ip_node, optim2, 0); 1189 } 1190 1191 if (x2debug) { 1192 printf("myreader final tree:\n"); 1193 printip(ipole); 1194 } 1195} 1196 1197/* 1198 * Remove some PCONVs after OREGs are created. 1199 */ 1200static void 1201pconv2(NODE *p, void *arg) 1202{ 1203 NODE *q; 1204 1205 if (p->n_op == PLUS) { 1206 if (p->n_type == (PTR|SHORT) || p->n_type == (PTR|USHORT)) { 1207 if (p->n_right->n_op != ICON) 1208 return; 1209 if (p->n_left->n_op != PCONV) 1210 return; 1211 if (p->n_left->n_left->n_op != OREG) 1212 return; 1213 q = p->n_left->n_left; 1214 nfree(p->n_left); 1215 p->n_left = q; 1216 /* 1217 * This will be converted to another OREG later. 1218 */ 1219 } 1220 } 1221} 1222 1223void 1224mycanon(NODE *p) 1225{ 1226 walkf(p, pconv2, 0); 1227} 1228 1229/* 1230 * Remove last goto. 1231 */ 1232void 1233myoptim(struct interpass *ip) 1234{ 1235} 1236 1237/* 1238 * Return a class suitable for a specific type. 1239 */ 1240int 1241gclass(TWORD t) 1242{ 1243 return (szty(t) == 2 ? CLASSB : CLASSA); 1244} 1245 1246static int 1247argsiz(NODE *p) 1248{ 1249 TWORD t = p->n_type; 1250 1251 if (t == STRTY || t == UNIONTY) 1252 return p->n_stsize/(SZINT/SZCHAR); 1253 return szty(t); 1254} 1255 1256/* 1257 * Calculate argument sizes. 1258 */ 1259void 1260lastcall(NODE *p) 1261{ 1262 NODE *op = p; 1263 int size = 0; 1264 1265 p->n_qual = 0; 1266 if (p->n_op != CALL && p->n_op != FORTCALL && p->n_op != STCALL) 1267 return; 1268 for (p = p->n_right; p->n_op == CM; p = p->n_left) 1269 if (p->n_right->n_op != ASSIGN) 1270 size += argsiz(p->n_right); 1271 if (p->n_op != ASSIGN) 1272 size += argsiz(p); 1273 op->n_qual = size; /* XXX */ 1274} 1275 1276void 1277rmove(int s, int d, TWORD t) 1278{ 1279 printf(" %smove %s,%s\n", 1280 (s > 017 ? "d" : ""), rnames[d], rnames[s]); 1281} 1282 1283/* 1284 * For class c, find worst-case displacement of the number of 1285 * registers in the array r[] indexed by class. 1286 */ 1287int 1288COLORMAP(int c, int *r) 1289{ 1290 int num; 1291 1292 switch (c) { 1293 case CLASSA: 1294 /* there are 13 classa, so min 6 classb are needed to block */ 1295 num = r[CLASSB] * 2; 1296 num += r[CLASSA]; 1297 return num < 13; 1298 case CLASSB: 1299 /* 7 classa may block all classb */ 1300 num = r[CLASSB] + r[CLASSA]; 1301 return num < 7; 1302 } 1303 comperr("COLORMAP"); 1304 return 0; /* XXX gcc */ 1305} 1306 1307/* 1308 * Target-dependent command-line options. 1309 */ 1310void 1311mflags(char *str) 1312{ 1313} 1314/* 1315 * Do something target-dependent for xasm arguments. 1316 * Supposed to find target-specific constraints and rewrite them. 1317 */ 1318int 1319myxasm(struct interpass *ip, NODE *p) 1320{ 1321 return 0; 1322} 1323