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