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

Defined functions

buffcat defined in line 629; used 2 times
buffct1 defined in line 656; used 4 times
buffmnmx defined in line 692; used 2 times
buffpower defined in line 747; used 2 times
cpframe defined in line 291; used 2 times
cplabarr defined in line 313; used 2 times
expand defined in line 547; used 10 times
flushopt defined in line 173; used 2 times
frtempbuff defined in line 470; used 2 times
insertslot defined in line 391; used 1 times
newslot defined in line 340; used 3 times
optoff defined in line 141; used 1 times
powtree defined in line 804; used 3 times
putopt defined in line 211; used 1 times
removeslot defined in line 367; used 2 times
setopt defined in line 154; used 1 times

Defined variables

alreadycalled defined in line 171; used 3 times
firstslot defined in line 132; used 7 times
lastslot defined in line 133; used 14 times
numslots defined in line 134; used 7 times
sccsid defined in line 8; never used

Defined macros

APPEND defined in line 544; used 3 times
LM defined in line 248; used 1 times
LP defined in line 250; used 1 times
LZ defined in line 249; used 1 times
Last modified: 1986-03-10
Generated: 2016-12-26
Generated by src2html V0.67
page hit count: 2607
Valid CSS Valid XHTML 1.0 Strict