|
|
1.1 ! root 1: /* ! 2: * Copyright (c) 1980 Regents of the University of California. ! 3: * All rights reserved. The Berkeley software License Agreement ! 4: * specifies the terms and conditions for redistribution. ! 5: */ ! 6: ! 7: #ifndef lint ! 8: static char sccsid[] = "@(#)optim.c 5.2 (Berkeley) 6/9/85"; ! 9: #endif not lint ! 10: ! 11: /* ! 12: * optim.c ! 13: * ! 14: * Miscellaneous optimizer routines, f77 compiler pass 1. ! 15: * ! 16: * UCSD Chemistry modification history: ! 17: * ! 18: * $Log: optim.c,v $ ! 19: * Revision 1.2 86/02/12 15:28:39 rcs ! 20: * 4.3 F77. C. Keating. ! 21: * ! 22: * Revision 2.12 85/06/08 22:57:01 donn ! 23: * Prevent core dumps -- bug in optinsert was causing lastslot to be wrong ! 24: * when a slot was inserted at the end of the buffer. ! 25: * ! 26: * Revision 2.11 85/03/18 08:05:05 donn ! 27: * Prevent warnings about implicit conversions. ! 28: * ! 29: * Revision 2.10 85/02/12 20:13:00 donn ! 30: * Resurrected the hack in 2.6.1.1 to avoid creating a temporary when ! 31: * there is a concatenation on the rhs of an assignment, and threw out ! 32: * all the code dealing with starcat(). It seems that we can't use a ! 33: * temporary because the lhs as well as the rhs may have nonconstant length. ! 34: * ! 35: * Revision 2.9 85/01/18 00:53:52 donn ! 36: * Missed a call to free() in the last change... ! 37: * ! 38: * Revision 2.8 85/01/18 00:50:03 donn ! 39: * Fixed goof made when modifying buffmnmx() to explicitly call expand(). ! 40: * ! 41: * Revision 2.7 85/01/15 18:47:35 donn ! 42: * Changes to allow character*(*) variables to appear in concatenations in ! 43: * the rhs of an assignment statement. ! 44: * ! 45: * Revision 2.6 84/12/16 21:46:27 donn ! 46: * Fixed bug that prevented concatenations from being run together. Changed ! 47: * buffpower() to not touch exponents greater than 64 -- let putpower do them. ! 48: * ! 49: * Revision 2.5 84/10/29 08:41:45 donn ! 50: * Added hack to flushopt() to prevent the compiler from trying to generate ! 51: * intermediate code after an error. ! 52: * ! 53: * Revision 2.4 84/08/07 21:28:00 donn ! 54: * Removed call to p2flush() in putopt() -- this allows us to make better use ! 55: * of the buffering on the intermediate code file. ! 56: * ! 57: * Revision 2.3 84/08/01 16:06:24 donn ! 58: * Forced expand() to expand subscripts. ! 59: * ! 60: * Revision 2.2 84/07/19 20:21:55 donn ! 61: * Decided I liked the expression tree algorithm after all. The algorithm ! 62: * which repeatedly squares temporaries is now checked in as rev. 2.1. ! 63: * ! 64: * Revision 1.3.1.1 84/07/10 14:18:18 donn ! 65: * I'm taking this branch off the trunk -- it works but it's not as good as ! 66: * the old version would be if it worked right. ! 67: * ! 68: * Revision 1.5 84/07/09 22:28:50 donn ! 69: * Added fix to buffpower() to prevent it chasing after huge exponents. ! 70: * ! 71: * Revision 1.4 84/07/09 20:13:59 donn ! 72: * Replaced buffpower() routine with a new one that generates trees which can ! 73: * be handled by CSE later on. ! 74: * ! 75: * Revision 1.3 84/05/04 21:02:07 donn ! 76: * Added fix for a bug in buffpower() that caused func(x)**2 to turn into ! 77: * func(x) * func(x). This bug had already been fixed in putpower()... ! 78: * ! 79: * Revision 1.2 84/03/23 22:47:21 donn ! 80: * The subroutine argument temporary fixes from Bob Corbett didn't take into ! 81: * account the fact that the code generator collects all the assignments to ! 82: * temporaries at the start of a statement -- hence the temporaries need to ! 83: * be initialized once per statement instead of once per call. ! 84: * ! 85: */ ! 86: ! 87: #include "defs.h" ! 88: #include "optim.h" ! 89: ! 90: ! 91: ! 92: /* ! 93: * Information buffered for each slot type ! 94: * ! 95: * slot type expptr integer pointer ! 96: * ! 97: * IFN expr label - ! 98: * GOTO - label - ! 99: * LABEL - label - ! 100: * EQ expr - - ! 101: * CALL expr - - ! 102: * CMGOTO expr num labellist* ! 103: * STOP expr - - ! 104: * DOHEAD [1] - ctlframe* ! 105: * ENDDO [1] - ctlframe* ! 106: * ARIF expr - labellist* ! 107: * RETURN expr label - ! 108: * ASGOTO expr - labellist* ! 109: * PAUSE expr - - ! 110: * ASSIGN expr label - ! 111: * SKIOIFN expr label - ! 112: * SKFRTEMP expr - - ! 113: * ! 114: * Note [1]: the nullslot field is a pointer to a fake slot which is ! 115: * at the end of the slots which may be replaced by this slot. In ! 116: * other words, it looks like this: ! 117: * DOHEAD slot ! 118: * slot \ ! 119: * slot > ordinary IF, GOTO, LABEL slots which implement the DO ! 120: * slot / ! 121: * NULL slot ! 122: */ ! 123: ! 124: ! 125: expptr expand(); ! 126: ! 127: Slotp firstslot = NULL; ! 128: Slotp lastslot = NULL; ! 129: int numslots = 0; ! 130: ! 131: ! 132: /* ! 133: * turns off optimization option ! 134: */ ! 135: ! 136: optoff() ! 137: ! 138: { ! 139: flushopt(); ! 140: optimflag = 0; ! 141: } ! 142: ! 143: ! 144: ! 145: /* ! 146: * initializes the code buffer for optimization ! 147: */ ! 148: ! 149: setopt() ! 150: ! 151: { ! 152: register Slotp sp; ! 153: ! 154: for (sp = firstslot; sp; sp = sp->next) ! 155: free ( (charptr) sp); ! 156: firstslot = lastslot = NULL; ! 157: numslots = 0; ! 158: } ! 159: ! 160: ! 161: ! 162: /* ! 163: * flushes the code buffer ! 164: */ ! 165: ! 166: LOCAL int alreadycalled = 0; ! 167: ! 168: flushopt() ! 169: { ! 170: register Slotp sp; ! 171: int savelineno; ! 172: ! 173: if (alreadycalled) return; /* to prevent recursive call during errors */ ! 174: alreadycalled = 1; ! 175: ! 176: if (debugflag[1]) ! 177: showbuffer (); ! 178: ! 179: frtempbuff (); ! 180: ! 181: savelineno = lineno; ! 182: for (sp = firstslot; sp; sp = sp->next) ! 183: { ! 184: if (nerr == 0) ! 185: putopt (sp); ! 186: else ! 187: frexpr (sp->expr); ! 188: if(sp->ctlinfo) free ( (charptr) sp->ctlinfo); ! 189: free ( (charptr) sp); ! 190: numslots--; ! 191: } ! 192: firstslot = lastslot = NULL; ! 193: numslots = 0; ! 194: clearbb(); ! 195: lineno = savelineno; ! 196: ! 197: alreadycalled = 0; ! 198: } ! 199: ! 200: ! 201: ! 202: /* ! 203: * puts out code for the given slot (from the code buffer) ! 204: */ ! 205: ! 206: LOCAL putopt (sp) ! 207: register Slotp sp; ! 208: { ! 209: lineno = sp->lineno; ! 210: switch (sp->type) { ! 211: case SKNULL: ! 212: break; ! 213: case SKIFN: ! 214: case SKIOIFN: ! 215: putif(sp->expr, sp->label); ! 216: break; ! 217: case SKGOTO: ! 218: putgoto(sp->label); ! 219: break; ! 220: case SKCMGOTO: ! 221: putcmgo(sp->expr, sp->label, sp->ctlinfo); ! 222: break; ! 223: case SKCALL: ! 224: putexpr(sp->expr); ! 225: break; ! 226: case SKSTOP: ! 227: putexpr (call1 (TYSUBR, "s_stop", sp->expr)); ! 228: break; ! 229: case SKPAUSE: ! 230: putexpr (call1 (TYSUBR, "s_paus", sp->expr)); ! 231: break; ! 232: case SKASSIGN: ! 233: puteq (sp->expr, ! 234: intrconv(sp->expr->headblock.vtype, mkaddcon(sp->label))); ! 235: break; ! 236: case SKDOHEAD: ! 237: case SKENDDO: ! 238: break; ! 239: case SKEQ: ! 240: putexpr(sp->expr); ! 241: break; ! 242: case SKARIF: ! 243: #define LM ((struct Labelblock * *)sp->ctlinfo)[0]->labelno ! 244: #define LZ ((struct Labelblock * *)sp->ctlinfo)[1]->labelno ! 245: #define LP ((struct Labelblock * *)sp->ctlinfo)[2]->labelno ! 246: prarif(sp->expr, LM, LZ, LP); ! 247: break; ! 248: case SKASGOTO: ! 249: putbranch((Addrp) sp->expr); ! 250: break; ! 251: case SKLABEL: ! 252: putlabel(sp->label); ! 253: break; ! 254: case SKRETURN: ! 255: if (sp->expr) ! 256: { ! 257: putforce(TYINT, sp->expr); ! 258: putgoto(sp->label); ! 259: } ! 260: else ! 261: putgoto(sp->label); ! 262: break; ! 263: case SKFRTEMP: ! 264: templist = mkchain (sp->expr,templist); ! 265: break; ! 266: default: ! 267: badthing("SKtype", "putopt", sp->type); ! 268: break; ! 269: } ! 270: ! 271: /* ! 272: * Recycle argument temporaries here. This must get done on a ! 273: * statement-by-statement basis because the code generator ! 274: * makes side effects happen at the start of a statement. ! 275: */ ! 276: argtemplist = hookup(argtemplist, activearglist); ! 277: activearglist = CHNULL; ! 278: } ! 279: ! 280: ! 281: ! 282: /* ! 283: * copies one element of the control stack ! 284: */ ! 285: ! 286: LOCAL struct Ctlframe *cpframe(p) ! 287: register char *p; ! 288: { ! 289: static int size = sizeof (struct Ctlframe); ! 290: register int n; ! 291: register char *q; ! 292: struct Ctlframe *q0; ! 293: ! 294: q0 = ALLOC(Ctlframe); ! 295: q = (char *) q0; ! 296: n = size; ! 297: while(n-- > 0) ! 298: *q++ = *p++; ! 299: return( q0); ! 300: } ! 301: ! 302: ! 303: ! 304: /* ! 305: * copies an array of labelblock pointers ! 306: */ ! 307: ! 308: LOCAL struct Labelblock **cplabarr(n,arr) ! 309: struct Labelblock *arr[]; ! 310: int n; ! 311: { ! 312: struct Labelblock **newarr; ! 313: register char *in, *out; ! 314: register int i,j; ! 315: ! 316: newarr = (struct Labelblock **) ckalloc (n * sizeof (char *)); ! 317: for (i = 0; i < n; i++) ! 318: { ! 319: newarr[i] = ALLOC (Labelblock); ! 320: out = (char *) newarr[i]; ! 321: in = (char *) arr[i]; ! 322: j = sizeof (struct Labelblock); ! 323: while (j-- > 0) ! 324: *out++ = *in++; ! 325: } ! 326: return (newarr); ! 327: } ! 328: ! 329: ! 330: ! 331: /* ! 332: * creates a new slot in the code buffer ! 333: */ ! 334: ! 335: LOCAL Slotp newslot() ! 336: { ! 337: register Slotp sp; ! 338: ! 339: ++numslots; ! 340: sp = ALLOC( slt ); ! 341: sp->next = NULL ; ! 342: if (lastslot) ! 343: { ! 344: sp->prev = lastslot; ! 345: lastslot = lastslot->next = sp; ! 346: } ! 347: else ! 348: { ! 349: firstslot = lastslot = sp; ! 350: sp->prev = NULL; ! 351: } ! 352: sp->lineno = lineno; ! 353: return (sp); ! 354: } ! 355: ! 356: ! 357: ! 358: /* ! 359: * removes (but not deletes) the specified slot from the code buffer ! 360: */ ! 361: ! 362: removeslot (sl) ! 363: Slotp sl; ! 364: ! 365: { ! 366: if (sl->next) ! 367: sl->next->prev = sl->prev; ! 368: else ! 369: lastslot = sl->prev; ! 370: if (sl->prev) ! 371: sl->prev->next = sl->next; ! 372: else ! 373: firstslot = sl->next; ! 374: sl->next = sl->prev = NULL; ! 375: ! 376: --numslots; ! 377: } ! 378: ! 379: ! 380: ! 381: /* ! 382: * inserts slot s1 before existing slot s2 in the code buffer; ! 383: * appends to end of list if s2 is NULL. ! 384: */ ! 385: ! 386: insertslot (s1,s2) ! 387: Slotp s1,s2; ! 388: ! 389: { ! 390: if (s2) ! 391: { ! 392: if (s2->prev) ! 393: s2->prev->next = s1; ! 394: else ! 395: firstslot = s1; ! 396: s1->prev = s2->prev; ! 397: s2->prev = s1; ! 398: } ! 399: else ! 400: { ! 401: s1->prev = lastslot; ! 402: lastslot->next = s1; ! 403: lastslot = s1; ! 404: } ! 405: s1->next = s2; ! 406: ! 407: ++numslots; ! 408: } ! 409: ! 410: ! 411: ! 412: /* ! 413: * deletes the specified slot from the code buffer ! 414: */ ! 415: ! 416: delslot (sl) ! 417: Slotp sl; ! 418: ! 419: { ! 420: removeslot (sl); ! 421: ! 422: if (sl->ctlinfo) ! 423: free ((charptr) sl->ctlinfo); ! 424: frexpr (sl->expr); ! 425: free ((charptr) sl); ! 426: numslots--; ! 427: } ! 428: ! 429: ! 430: ! 431: /* ! 432: * inserts a slot before the specified slot; if given NULL, it is ! 433: * inserted at the end of the buffer ! 434: */ ! 435: ! 436: Slotp optinsert (type,p,l,c,currslot) ! 437: int type; ! 438: expptr p; ! 439: int l; ! 440: int *c; ! 441: Slotp currslot; ! 442: ! 443: { ! 444: Slotp savelast,new; ! 445: ! 446: savelast = lastslot; ! 447: if (currslot) ! 448: lastslot = currslot->prev; ! 449: new = optbuff (type,p,l,c); ! 450: new->next = currslot; ! 451: if (currslot) ! 452: currslot->prev = new; ! 453: new->lineno = -1; /* who knows what the line number should be ??!! */ ! 454: if (currslot) ! 455: lastslot = savelast; ! 456: return (new); ! 457: } ! 458: ! 459: ! 460: ! 461: /* ! 462: * buffers the FRTEMP slots which have been waiting ! 463: */ ! 464: ! 465: frtempbuff () ! 466: ! 467: { ! 468: chainp ht; ! 469: register Slotp sp; ! 470: ! 471: for (ht = holdtemps; ht; ht = ht->nextp) ! 472: { ! 473: sp = newslot(); ! 474: /* this slot actually belongs to some previous source line */ ! 475: sp->lineno = sp->lineno - 1; ! 476: sp->type = SKFRTEMP; ! 477: sp->expr = (expptr) ht->datap; ! 478: sp->label = 0; ! 479: sp->ctlinfo = NULL; ! 480: } ! 481: holdtemps = NULL; ! 482: } ! 483: ! 484: ! 485: ! 486: /* ! 487: * puts the given information into a slot at the end of the code buffer ! 488: */ ! 489: ! 490: Slotp optbuff (type,p,l,c) ! 491: int type; ! 492: expptr p; ! 493: int l; ! 494: int *c; ! 495: ! 496: { ! 497: register Slotp sp; ! 498: ! 499: if (debugflag[1]) ! 500: { ! 501: fprintf (diagfile,"-----optbuff-----"); showslottype (type); ! 502: showexpr (p,0); fprintf (diagfile,"\n"); ! 503: } ! 504: ! 505: p = expand (p); ! 506: sp = newslot(); ! 507: sp->type = type; ! 508: sp->expr = p; ! 509: sp->label = l; ! 510: sp->ctlinfo = NULL; ! 511: switch (type) ! 512: { ! 513: case SKCMGOTO: ! 514: sp->ctlinfo = (int*) cplabarr (l, (struct Labelblock**) c); ! 515: break; ! 516: case SKARIF: ! 517: sp->ctlinfo = (int*) cplabarr (3, (struct Labelblock**) c); ! 518: break; ! 519: case SKDOHEAD: ! 520: case SKENDDO: ! 521: sp->ctlinfo = (int*) cpframe ((struct Ctlframe*) c); ! 522: break; ! 523: default: ! 524: break; ! 525: } ! 526: ! 527: frtempbuff (); ! 528: ! 529: return (sp); ! 530: } ! 531: ! 532: ! 533: ! 534: /* ! 535: * expands the given expression, if possible (e.g., concat, min, max, etc.); ! 536: * also frees temporaries when they are indicated as being the last use ! 537: */ ! 538: ! 539: #define APPEND(z) \ ! 540: res = res->exprblock.rightp = mkexpr (OPCOMMA, z, newtemp) ! 541: ! 542: LOCAL expptr expand (p) ! 543: tagptr p; ! 544: ! 545: { ! 546: Addrp t; ! 547: expptr q; ! 548: expptr buffmnmx(), buffpower(); ! 549: ! 550: if (!p) ! 551: return (ENULL); ! 552: switch (p->tag) ! 553: { ! 554: case TEXPR: ! 555: switch (p->exprblock.opcode) ! 556: { ! 557: case OPASSIGN: /* handle a = b // c */ ! 558: if (p->exprblock.vtype != TYCHAR) ! 559: goto standard; ! 560: q = p->exprblock.rightp; ! 561: if (!(q->tag == TEXPR && ! 562: q->exprblock.opcode == OPCONCAT)) ! 563: goto standard; ! 564: t = (Addrp) expand(p->exprblock.leftp); ! 565: frexpr(p->exprblock.vleng); ! 566: free( (charptr) p ); ! 567: p = (tagptr) q; ! 568: goto cat; ! 569: case OPCONCAT: ! 570: t = mktemp (TYCHAR, ICON(lencat(p))); ! 571: cat: ! 572: q = (expptr) cpexpr (p->exprblock.vleng); ! 573: buffcat (cpexpr(t),p); ! 574: frexpr (t->vleng); ! 575: t->vleng = q; ! 576: p = (tagptr) t; ! 577: break; ! 578: case OPMIN: ! 579: case OPMAX: ! 580: p = (tagptr) buffmnmx (p); ! 581: break; ! 582: case OPPOWER: ! 583: p = (tagptr) buffpower (p); ! 584: break; ! 585: default: ! 586: standard: ! 587: p->exprblock.leftp = ! 588: expand (p->exprblock.leftp); ! 589: if (p->exprblock.rightp) ! 590: p->exprblock.rightp = ! 591: expand (p->exprblock.rightp); ! 592: break; ! 593: } ! 594: break; ! 595: ! 596: case TLIST: ! 597: { ! 598: chainp t; ! 599: for (t = p->listblock.listp; t; t = t->nextp) ! 600: t->datap = (tagptr) expand (t->datap); ! 601: } ! 602: break; ! 603: ! 604: case TTEMP: ! 605: if (p->tempblock.istemp) ! 606: frtemp(p); ! 607: break; ! 608: ! 609: case TADDR: ! 610: p->addrblock.memoffset = expand( p->addrblock.memoffset ); ! 611: break; ! 612: ! 613: default: ! 614: break; ! 615: } ! 616: return ((expptr) p); ! 617: } ! 618: ! 619: ! 620: ! 621: /* ! 622: * local version of routine putcat in putpcc.c, called by expand ! 623: */ ! 624: ! 625: LOCAL buffcat(lhs, rhs) ! 626: register Addrp lhs; ! 627: register expptr rhs; ! 628: { ! 629: int n; ! 630: Addrp lp, cp; ! 631: ! 632: n = ncat(rhs); ! 633: lp = (Addrp) mkaltmpn(n, TYLENG, PNULL); ! 634: cp = (Addrp) mkaltmpn(n, TYADDR, PNULL); ! 635: ! 636: n = 0; ! 637: buffct1(rhs, lp, cp, &n); ! 638: ! 639: optbuff (SKCALL, call4(TYSUBR, "s_cat", lhs, cp, lp, mkconv(TYLONG, ICON(n))), ! 640: 0, 0); ! 641: } ! 642: ! 643: ! 644: ! 645: /* ! 646: * local version of routine putct1 in putpcc.c, called by expand ! 647: */ ! 648: ! 649: LOCAL buffct1(q, lp, cp, ip) ! 650: register expptr q; ! 651: register Addrp lp, cp; ! 652: int *ip; ! 653: { ! 654: int i; ! 655: Addrp lp1, cp1; ! 656: ! 657: if(q->tag==TEXPR && q->exprblock.opcode==OPCONCAT) ! 658: { ! 659: buffct1(q->exprblock.leftp, lp, cp, ip); ! 660: buffct1(q->exprblock.rightp, lp, cp, ip); ! 661: frexpr(q->exprblock.vleng); ! 662: free( (charptr) q ); ! 663: } ! 664: else ! 665: { ! 666: i = (*ip)++; ! 667: lp1 = (Addrp) cpexpr(lp); ! 668: lp1->memoffset = mkexpr(OPPLUS,lp1->memoffset, ICON(i*SZLENG)); ! 669: cp1 = (Addrp) cpexpr(cp); ! 670: cp1->memoffset = mkexpr(OPPLUS, cp1->memoffset, ICON(i*SZADDR)); ! 671: optbuff (SKEQ, (mkexpr(OPASSIGN, lp1, cpexpr(q->headblock.vleng))), ! 672: 0,0); ! 673: optbuff (SKEQ, (mkexpr(OPASSIGN, cp1, addrof(expand (q)))), 0, 0); ! 674: } ! 675: } ! 676: ! 677: ! 678: ! 679: /* ! 680: * local version of routine putmnmx in putpcc.c, called by expand ! 681: */ ! 682: ! 683: LOCAL expptr buffmnmx(p) ! 684: register expptr p; ! 685: { ! 686: int op, type; ! 687: expptr qp; ! 688: chainp p0, p1; ! 689: Addrp sp, tp; ! 690: Addrp newtemp; ! 691: expptr result, res; ! 692: ! 693: if(p->tag != TEXPR) ! 694: badtag("buffmnmx", p->tag); ! 695: ! 696: type = p->exprblock.vtype; ! 697: op = (p->exprblock.opcode==OPMIN ? OPLT : OPGT ); ! 698: qp = expand(p->exprblock.leftp); ! 699: if(qp->tag != TLIST) ! 700: badtag("buffmnmx list", qp->tag); ! 701: p0 = qp->listblock.listp; ! 702: free( (charptr) qp ); ! 703: free( (charptr) p ); ! 704: ! 705: sp = mktemp(type, PNULL); ! 706: tp = mktemp(type, PNULL); ! 707: qp = mkexpr(OPCOLON, cpexpr(tp), cpexpr(sp)); ! 708: qp = mkexpr(OPQUEST, mkexpr(op, cpexpr(tp),cpexpr(sp)), qp); ! 709: qp = fixexpr(qp); ! 710: ! 711: newtemp = mktemp (type,PNULL); ! 712: ! 713: result = res = mkexpr (OPCOMMA, ! 714: mkexpr( OPASSIGN, cpexpr(sp), p0->datap ), cpexpr(newtemp)); ! 715: ! 716: for(p1 = p0->nextp ; p1 ; p1 = p1->nextp) ! 717: { ! 718: APPEND (mkexpr( OPASSIGN, cpexpr(tp), p1->datap )); ! 719: if(p1->nextp) ! 720: APPEND (mkexpr (OPASSIGN, cpexpr(sp), cpexpr(qp)) ); ! 721: else ! 722: APPEND (mkexpr (OPASSIGN, cpexpr(newtemp), qp)); ! 723: } ! 724: ! 725: frtemp(sp); ! 726: frtemp(tp); ! 727: frtemp(newtemp); ! 728: frchain( &p0 ); ! 729: ! 730: return (result); ! 731: } ! 732: ! 733: ! 734: ! 735: /* ! 736: * Called by expand() to eliminate exponentiations to integer constants. ! 737: */ ! 738: LOCAL expptr buffpower( p ) ! 739: expptr p; ! 740: { ! 741: expptr base; ! 742: Addrp newtemp; ! 743: expptr storetemp = ENULL; ! 744: expptr powtree(); ! 745: expptr result; ! 746: ftnint exp; ! 747: ! 748: if ( ! ISICON( p->exprblock.rightp ) ) ! 749: fatal( "buffpower: bad non-integer exponent" ); ! 750: ! 751: base = expand(p->exprblock.leftp); ! 752: exp = p->exprblock.rightp->constblock.const.ci; ! 753: if ( exp < 2 ) ! 754: fatal( "buffpower: bad exponent less than 2" ); ! 755: ! 756: if ( exp > 64 ) { ! 757: /* ! 758: * Let's be reasonable, here... Let putpower() do the job. ! 759: */ ! 760: p->exprblock.leftp = base; ! 761: return ( p ); ! 762: } ! 763: ! 764: /* ! 765: * If the base is not a simple variable, evaluate it and copy the ! 766: * result into a temporary. ! 767: */ ! 768: if ( ! (base->tag == TADDR && ISCONST( base->addrblock.memoffset )) ) { ! 769: newtemp = mktemp( base->headblock.vtype, PNULL ); ! 770: storetemp = mkexpr( OPASSIGN, ! 771: cpexpr( (expptr) newtemp ), ! 772: cpexpr( base ) ); ! 773: base = (expptr) newtemp; ! 774: } ! 775: ! 776: result = powtree( base, exp ); ! 777: ! 778: if ( storetemp != ENULL ) ! 779: result = mkexpr( OPCOMMA, storetemp, result ); ! 780: frexpr( p ); ! 781: ! 782: return ( result ); ! 783: } ! 784: ! 785: ! 786: ! 787: /* ! 788: * powtree( base, exp ) -- Create a tree of multiplications which computes ! 789: * base ** exp. The tree is built so that CSE will compact it if ! 790: * possible. The routine works by creating subtrees that compute ! 791: * exponents which are powers of two, then multiplying these ! 792: * together to get the result; this gives a log2( exp ) tree depth ! 793: * and lots of subexpressions which can be eliminated. ! 794: */ ! 795: LOCAL expptr powtree( base, exp ) ! 796: expptr base; ! 797: register ftnint exp; ! 798: { ! 799: register expptr r = ENULL, r1; ! 800: register int i; ! 801: ! 802: for ( i = 0; exp; ++i, exp >>= 1 ) ! 803: if ( exp & 1 ) ! 804: if ( i == 0 ) ! 805: r = (expptr) cpexpr( base ); ! 806: else { ! 807: r1 = powtree( base, 1 << (i - 1) ); ! 808: r1 = mkexpr( OPSTAR, r1, cpexpr( r1 ) ); ! 809: r = (r ? mkexpr( OPSTAR, r1, r ) : r1); ! 810: } ! 811: ! 812: return ( r ); ! 813: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.