|
|
1.1 ! root 1: #ifndef lint ! 2: static char sccsid[] = "@(#)branch.c 1.1 86/02/03 Copyr 1985 Sun Micro"; ! 3: #endif ! 4: ! 5: /* ! 6: * Copyright (c) 1985 by Sun Microsystems, Inc. ! 7: */ ! 8: ! 9: #include "as.h" ! 10: #include "c2.h" ! 11: ! 12: char *unbranch[] = { ! 13: "jne", "jeq", "jgt", "jlt", "jge", "jle", ! 14: "jhi", "jls", "jpl", "jmi", "jf", ! 15: "jcc", "jcs", "jvc", "jvs", "jra", ! 16: "jfneq", "jfeq", "jfnlt", "jflt", ! 17: "jfnle", "jfle", "jfngt", "jfgt", ! 18: "jfnge", "jfge", ! 19: "fjneq", "fjeq", "fjngt", "fjgt", "fjnge", "fjge", ! 20: "fjnlt", "fjlt", "fjnle", "fjle", "fjngl", "fjgl", ! 21: "fjngle", "fjgle", "fjule", "fjogt", "fjult", "fjoge", ! 22: "fjuge", "fjolt", "fjugt", "fjole", "fjueq", "fjogl", ! 23: "fjun", "fjor", "fjst", "fjsf", "fjsneq", "fjseq" ! 24: }; ! 25: extern NODE *deletenode(); ! 26: ! 27: NODE * ! 28: insert_label( p ) ! 29: register NODE *p; ! 30: { ! 31: static int newlabno = 0; ! 32: register NODE *l; ! 33: register struct sym_bkt *s; ! 34: char labname[20]; ! 35: ! 36: l = new(); ! 37: l->op = OP_LABEL; ! 38: l->nref = 0; ! 39: sprintf( labname, "LY%05d", newlabno++ ); ! 40: l->name = s = lookup(labname); ! 41: s->attr_s |= S_DEF|S_DEC; ! 42: s->csect_s = C_TEXT; ! 43: s->where_s = l; ! 44: l->forw = p; ! 45: l->back = p->back; ! 46: l->back->forw = l; ! 47: p->back = l; ! 48: l->ruse = l->rset = regmask0; ! 49: l->rlive = l->forw->rlive; ! 50: return l; ! 51: } ! 52: ! 53: NODE * ! 54: merge_labels( to, from ) ! 55: register NODE * to, *from ; ! 56: { ! 57: /* ! 58: * there are two kinds of labels: ! 59: * those all of whose references we can find, and ! 60: * the others. ! 61: * In the latter case, we will want to move the label, ! 62: * and let someone smarter than us drop the equate. ! 63: */ ! 64: register refs = 0; ! 65: register NODE *luse; ! 66: if (from->luse!=NULL){ ! 67: for ( luse=from->luse; ; luse=luse->lnext ){ ! 68: luse->luse = to; ! 69: refs++; ! 70: if (luse->lnext==NULL) break; ! 71: } ! 72: luse->lnext=to->luse; ! 73: to->luse =from->luse; ! 74: } ! 75: if (refs == from->nref){ ! 76: from = deletenode( from )->forw; ! 77: meter.nrlab++; ! 78: } else { ! 79: /* ! 80: * at this point there are not references on our list, but ! 81: * still references to this label somewhere out there ! 82: * move the damn thing ! 83: * and null out the use list ! 84: */ ! 85: NODE *temp; ! 86: from->nref -= refs; ! 87: from->luse = NULL; ! 88: temp = from->forw; ! 89: from->back->forw = from->forw; ! 90: from->forw->back = from->back; ! 91: from->forw = to->forw; ! 92: from->forw->back = from; ! 93: from->back = to; ! 94: to->forw = from; ! 95: from = temp; ! 96: } ! 97: to->nref += refs; ! 98: return from; ! 99: } ! 100: ! 101: int ! 102: fallthrough( t ) ! 103: register NODE *t; ! 104: { ! 105: /* ! 106: * return 0 if t is a node that cannot "fall through" to the ! 107: * next instruction, such as an unconditional jump or code- ! 108: * emitting pseudo-instruction ! 109: * return 1 if this is not the case. ! 110: */ ! 111: if (ISDIRECTIVE(t->op) ) return 1; ! 112: else if (ISPSEUDO(t->op) ) return 0; ! 113: else switch (t->op){ ! 114: case OP_CSWITCH: ! 115: case OP_FIRST: ! 116: case OP_EXIT: ! 117: return 0; ! 118: case OP_BRANCH: ! 119: case OP_JUMP: ! 120: return t->subop!=JALL; ! 121: default: ! 122: return 1; ! 123: } ! 124: /* NOTREACHED */ ! 125: } ! 126: ! 127: ! 128: # define nexti( t ) while( t->op==OP_LABEL ) t=t->forw ! 129: tangle() ! 130: { ! 131: /* ! 132: * remove: ! 133: * trivial jumps ! 134: * jumps to jumps ! 135: * jumps around jumps ! 136: */ ! 137: ! 138: int changed = 1; ! 139: int niter=0; ! 140: register NODE *p, *t, *u; ! 141: NODE *j, *jdest, *savelabel; ! 142: ! 143: while (changed){ ! 144: changed=0; ! 145: for (p=first.forw; p!=&first; p=p->forw){ ! 146: if ((p->op==OP_JUMP&&p->subop!=JIND)||p->op==OP_CSWITCH){ ! 147: t = p->luse; ! 148: nexti( t ); ! 149: if (t==p){ ! 150: /* selfloop */ ! 151: if (p->luse->nref==1 && !fallthrough(p->back)){ ! 152: /* unreachable */ ! 153: unreference( p->luse, p); ! 154: p = deletenode( p ); ! 155: meter.nbrbr++; ! 156: changed++; ! 157: } ! 158: continue; ! 159: } ! 160: if (t->op==p->op && (t->subop==JALL || t->subop==p->subop)){ ! 161: /* jump-to-jump -- remove the middle reference */ ! 162: if (p->luse==t->luse){ ! 163: /* jump into selfloop */ ! 164: continue; ! 165: } ! 166: unreference( p->luse, p); ! 167: newreference( t->luse, p); ! 168: t = p->luse; ! 169: nexti( t ); ! 170: meter.nbrbr++; ! 171: changed++; ! 172: } ! 173: if (p->op==OP_CSWITCH ) continue; ! 174: if (p->luse==p->forw){ ! 175: /* trivial jump */ ! 176: unreference( p->luse, p); ! 177: p = deletenode( p ); ! 178: changed++; ! 179: meter.njp1++; ! 180: continue; ! 181: } ! 182: if (p->subop == JALL){ ! 183: u = (t=p->luse)->back; ! 184: /* find the non-pseudo-op before the destination */ ! 185: while (ISDIRECTIVE(u->op)) ! 186: u = u->back; ! 187: if ( t->nref==1 && ( u->op==OP_FIRST || ! 188: ((u->op==OP_JUMP&&u->subop==JALL)|| u->op==OP_EXIT))){ ! 189: /* ! 190: * this piece of code is reachable from p but not by ! 191: * fall through. move it to after p and delete ! 192: * the jump. stop moving after a cswitch ! 193: * or unconditional goto or return. ! 194: */ ! 195: jdest = u->luse; ! 196: savelabel = 0; ! 197: u = t; ! 198: while ((u=u->forw)->op!= OP_FIRST){ ! 199: if (u->op==OP_LABEL ){ ! 200: if ( u->back->op==OP_CSWITCH ) ! 201: break; ! 202: else if (savelabel != jdest ! 203: && !(u->forw->op==OP_CSWITCH ) ) ! 204: savelabel = u; ! 205: }else if ((u->op==OP_JUMP && u->subop==JALL) ! 206: || u->op==OP_EXIT ){ ! 207: u = u->forw; ! 208: break; ! 209: } ! 210: } ! 211: /* t points to the first node to move, and */ ! 212: /* u points to the first node not to move. */ ! 213: j = u->back; ! 214: if (j==p){ ! 215: /* ! 216: * oh, my... a loop. It may be without any ! 217: * way in, but I'm too 'fraid to try deleteing ! 218: * it. Lets try pivoting around an appropriate ! 219: * label in the loop. ! 220: */ ! 221: if (savelabel){ ! 222: u = savelabel; ! 223: j = u->back; ! 224: } else ! 225: continue; ! 226: } ! 227: if (j->op != OP_CSWITCH ! 228: && !(j->op==OP_JUMP && j->subop==JALL) ! 229: && j->op != OP_EXIT ! 230: && u->op==OP_LABEL){ ! 231: /* add unconditional branch here */ ! 232: j->forw = new(); ! 233: j->forw->back = j; ! 234: j = j->forw; ! 235: cannibalize( j, "jra" ); ! 236: j->op = OP_JUMP; /* rather than OP_BRANCH */ ! 237: newreference( u, j); ! 238: } ! 239: u->back = t->back; ! 240: t->back->forw = u; ! 241: t->back = p; ! 242: j->forw = p->forw; ! 243: p->forw->back = j; ! 244: p->forw = t; ! 245: /* the details will take care of themselves */ ! 246: p = p->back; ! 247: changed++; ! 248: meter.ncmot++; ! 249: continue; ! 250: } ! 251: /* delete dead code after unconditional branch */ ! 252: /* should do after exits, too */ ! 253: u = p->forw; ! 254: while ((t=u)->op!=OP_LABEL && t->op!=OP_FIRST ! 255: && t->op != OP_EXIT){ ! 256: u = t->forw; ! 257: if (ISPSEUDO( t->op )) ! 258: continue; /* don't delete pseudoops */ ! 259: if (ISBRANCH(t->op)) ! 260: unreference( t->luse, t); ! 261: (void)deletenode( t ); ! 262: meter.iaftbr++; ! 263: changed++; ! 264: } ! 265: } else { ! 266: /* here for conditional branches */ ! 267: u = p->forw; ! 268: /* may be no intervening branches here */ ! 269: if (u->op==p->op && (u->subop==JALL || u->subop==p->subop)){ ! 270: j = u; ! 271: u = u->forw; ! 272: nexti( u ); ! 273: if (u==t){ ! 274: /* jump-around-jump -- reverse condition, go directly */ ! 275: cannibalize( j, unbranch[(int)(p->subop)-(int)JEQ] ); ! 276: j->op = OP_JUMP; /* cannibalize makes an OP_BRANCH*/ ! 277: unreference( p->luse, p ); ! 278: p = deletenode( p ); ! 279: meter.nrevbr++; ! 280: changed++; ! 281: } ! 282: } else if ( (int)p->subop <= (int)JNONE && u->op==OP_DJMP && u->subop==JNONE){ ! 283: /* ! 284: * jXX Y ! 285: * dbra dZ,W ! 286: * should be changed to: ! 287: * dbXX dZ,W ! 288: * jXX Y ! 289: * because its faster. If label Y directly follows ! 290: * the dbra, the jump can be deleted entirely! ! 291: */ ! 292: static char dbname[5] = {'d', 'b', '\0', '\0', '\0'}; ! 293: /* ! 294: * since we cannot search for the correct instruction ! 295: * indexed by op and subop, we need to synthesize the ! 296: * new name and call cannibalize. ! 297: * jump instruction is of form [jb]CC[ls]. ! 298: */ ! 299: dbname[2] = p->instr->text_i[1]; ! 300: dbname[3] = p->instr->text_i[2]; ! 301: cannibalize( u, dbname ); ! 302: u->op = OP_DJMP; ! 303: ! 304: /* ! 305: * unhook p from the list, reinsert it later ! 306: */ ! 307: u = u->forw; ! 308: nexti( u ); ! 309: if (u==t){ ! 310: unreference( p->luse, p ); ! 311: deletenode(p); ! 312: meter.nskip++; ! 313: } else { ! 314: p->back->forw = p->forw; ! 315: p->forw->back = p->back; ! 316: p->forw = p->back = 0; ! 317: insert( p, u->back ); ! 318: meter.ndbrarev++; ! 319: } ! 320: p = u->back; ! 321: changed++; ! 322: } ! 323: } ! 324: } ! 325: } ! 326: if (++niter > 1000) sys_error("Tangled control-flow logic"); ! 327: } ! 328: return niter-1; ! 329: } ! 330: ! 331: zipper() ! 332: { ! 333: /* ! 334: * For each label: look at all the jumps to that label: ! 335: * for those that are unconditional: ! 336: * compare the instructions preceeding to the ! 337: * instructions preceeding the label. The unconditional ! 338: * jump could jump to an earlier point in the "fall through" ! 339: * flow. ! 340: */ ! 341: ! 342: register NODE *l, *u, *prec, *uprec, *luse; ! 343: NODE *pr, *upr; ! 344: int refs; ! 345: int nchange=0, didchange; ! 346: ! 347: for (l=first.forw; l!= &first; l=l->forw){ ! 348: if (l->op!=OP_LABEL) continue; ! 349: prec = l->back; ! 350: /* skip over stabs */ ! 351: while (ISDIRECTIVE(prec->op) ) ! 352: prec=prec->back; ! 353: if (!ISINSTRUC(prec->op)) ! 354: continue; ! 355: if (prec->op==OP_CSWITCH ) continue; ! 356: if ((prec->op==OP_BRANCH || prec->op==OP_JUMP) && prec->subop==JALL) ! 357: continue; ! 358: pr = prec; ! 359: for (u = l->luse; u!=NULL; u=upr, prec=pr){ ! 360: upr = u->lnext; ! 361: uprec = u->back; ! 362: didchange=0; ! 363: if (u->op!=OP_JUMP || u->subop!=JALL) continue; ! 364: while (ISDIRECTIVE(uprec->op) ) ! 365: uprec=uprec->back; ! 366: if (uprec->op==OP_FIRST) continue; ! 367: while(1){ ! 368: if (uprec->op != prec->op ){ ! 369: if (prec->op==OP_LABEL){ ! 370: /* skip it */ ! 371: prec=prec->back; ! 372: continue; ! 373: }else ! 374: break; ! 375: } ! 376: if (prec==uprec || prec==u || uprec==upr) break; ! 377: if (prec->op == OP_LABEL ){ ! 378: uprec = merge_labels( prec, uprec ); ! 379: didchange++; ! 380: } else{ ! 381: if (ISPSEUDO( prec->op )) goto endzip; ! 382: if (!sameins( prec, uprec) ) goto endzip; ! 383: if (ISBRANCH(prec->op)) ! 384: if (prec->luse != uprec->luse) ! 385: goto endzip; ! 386: else ! 387: unreference( uprec->luse, uprec); ! 388: uprec = deletenode( uprec )->forw; ! 389: didchange++; ! 390: } ! 391: prec=prec->back; ! 392: uprec=uprec->back; ! 393: } ! 394: endzip: ! 395: if (didchange){ ! 396: /* ! 397: * we may have done something here. ! 398: * uprec addresses the first NON-common node we found. ! 399: * put the jump after it. ! 400: */ ! 401: if ( uprec->forw != u ){ ! 402: uprec->forw->back = u; ! 403: u->back->forw = u->forw; ! 404: u->forw->back = u->back; ! 405: u->forw = uprec->forw; ! 406: uprec->forw = u; ! 407: u->back = uprec; ! 408: } ! 409: if (prec->op!=OP_LABEL) ! 410: prec = insert_label( prec->forw ); ! 411: unreference( u->luse, u); ! 412: newreference( prec, u); ! 413: u->rlive = u->luse->rlive; ! 414: nchange++; ! 415: } ! 416: } ! 417: } ! 418: meter.ncomj += nchange; ! 419: return nchange; ! 420: } ! 421: ! 422: int ! 423: tmerge() ! 424: { ! 425: /* ! 426: * For each label, z, in the program, try to find commonality ! 427: * amoung the pieces of code that end up at that label. ! 428: * We are very cautious. ! 429: * We are looking for the forms: ! 430: * jra elsewhere ! 431: * L: X ! 432: * X ! 433: * jra z ! 434: * and ! 435: * jYY L ! 436: * X ! 437: * X ! 438: * jra z ! 439: * L: ! 440: * which we can combine for smaller and no-slower code. ! 441: */ ! 442: ! 443: NODE *z; ! 444: register NODE *a, *b; ! 445: NODE *ajmp; ! 446: NODE *bnext, *anext, *t; ! 447: NODE *bforw, *aforw; ! 448: int nchanged = 0; ! 449: ! 450: for (z=first.forw; z!=&first; z=z->forw){ ! 451: if (z->op != OP_LABEL) continue; ! 452: for (ajmp=z->luse; ajmp!=NULL; ajmp=anext){ ! 453: anext=ajmp->lnext; ! 454: if (ajmp->op != OP_JUMP || ajmp->subop != JALL) continue; ! 455: for (b=ajmp->lnext; b!=NULL; b=bnext){ ! 456: bnext=b->lnext; ! 457: if (b->op != OP_JUMP || b->subop != JALL) continue; ! 458: bforw = b->forw; ! 459: a = ajmp; ! 460: aforw = a->forw; ! 461: /* ! 462: * compare backwards until: ! 463: * -- we hit a non-equality, or ! 464: * -- we hit a label, or ! 465: * -- we hit a jump ! 466: */ ! 467: for ( a=a->back, b=b->back; ! 468: a->op!=OP_FIRST && b->op!=OP_FIRST; ! 469: a=a->back, b=b->back){ ! 470: ! 471: while (ISDIRECTIVE( a->op )) ! 472: a=a->back; ! 473: while (ISDIRECTIVE( b->op )) ! 474: b=b->back; ! 475: switch (a->op){ ! 476: default: /* | */ ! 477: if ( ISPSEUDO(a->op) || !sameins( a, b ) ) break; ! 478: continue; ! 479: case OP_JUMP: ! 480: case OP_LABEL: ! 481: case OP_CSWITCH: ! 482: break; /* to outer break */ ! 483: }/* +--------------------+ */ ! 484: /* v */ ! 485: break; /* out of for loop */ ! 486: }/* +---------------------+ */ ! 487: /* v ! 488: * we have now compared just a little too far: ! 489: * either *a != *b , or they are both pseudo-ops, ! 490: * jumps, labels, or something else unspeakable. ! 491: */ ! 492: a = a->forw; ! 493: b = b->forw; ! 494: if (a == ajmp) ! 495: /* no equal sequences */ ! 496: continue; ! 497: /* look for preceeding label, preceeded by unconditional jump */ ! 498: if (b->back->op == OP_LABEL && (fallthrough(b->back->back) ! 499: || (a->back->op == OP_JUMP && a->back->luse == aforw)) ){ ! 500: /* want to merge into "b" -- exchange */ ! 501: t = b; b = a; a = t; ! 502: t = bforw; bforw = aforw; aforw = t; ! 503: /* and fall through into "a" test, which will succeed */ ! 504: } ! 505: if (a->back->op == OP_LABEL){ ! 506: if ( (t=b->back)->op == OP_LABEL && !fallthrough(t->back)){ ! 507: /* merge into "a" */ ! 508: (void)merge_labels( a->back, t); ! 509: /* cream junk trailing merged-out code */ ! 510: if (anext == bforw->back) ! 511: anext = NULL; ! 512: while ( b!=bforw ){ ! 513: if (ISBRANCH(b->op)) ! 514: unreference( b->luse, b ); ! 515: b = deletenode( b )->forw; ! 516: } ! 517: nchanged++; ! 518: break; ! 519: } else if (t->op == OP_JUMP && t->luse == bforw ){ ! 520: a = a->back; /* "a" now addresses label */ ! 521: cond_jumparound: ! 522: /* ! 523: * delete "b" code, complement branch condition, ! 524: * change branch target to "a" ! 525: */ ! 526: if (anext == bforw->back) ! 527: anext = NULL; ! 528: while ( b!=bforw ){ ! 529: if (ISBRANCH(b->op)) ! 530: unreference( b->luse, b ); ! 531: b = deletenode( b )->forw; ! 532: } ! 533: unreference( t->luse, t); ! 534: newreference( a, t); ! 535: cannibalize( t, unbranch[(int)(t->subop)-(int)JEQ] ); ! 536: t->op = OP_JUMP; /* not BRANCH */ ! 537: nchanged++; ! 538: break; ! 539: } else if (!fallthrough( a->back->back) ){ ! 540: /* ! 541: * we can just move label "a" to before "b" ! 542: * and delete the rest of the "a" code ! 543: */ ! 544: while (a != aforw ){ ! 545: if (ISBRANCH(a->op)) ! 546: unreference( a->luse, a ); ! 547: a = deletenode( a )->forw; ! 548: } ! 549: a->back->back->forw = a; ! 550: a->back->forw = b; ! 551: t->forw = a->back; ! 552: a->back = a->back->back; ! 553: t->forw->back = t; ! 554: b->back = t->forw; ! 555: nchanged++; ! 556: break; ! 557: } ! 558: /* else out of luck */ ! 559: } else if (a->back->op == OP_JUMP && a->back->luse == aforw ! 560: && b->back->op == OP_JUMP && b->back->luse == bforw ){ ! 561: /* ! 562: * must insert new label, then treat like one of ! 563: * the labelled cases above. ! 564: */ ! 565: a = insert_label( a ); ! 566: t = b->back; ! 567: goto cond_jumparound; ! 568: } ! 569: } ! 570: } ! 571: } ! 572: meter.ncomj += nchanged; ! 573: return nchanged; ! 574: } ! 575: ! 576: /* ! 577: * assign a sequential node number to each node. ! 578: * Sequence is used to detect backwards edges. ! 579: */ ! 580: order_nodes() ! 581: { ! 582: register NODE *n; ! 583: register nodenumber; ! 584: ! 585: nodenumber = 0; ! 586: for (n = first.forw; n != &first; n = n->forw) { ! 587: n->lineno = nodenumber++; ! 588: } ! 589: } ! 590: ! 591: /* ! 592: * change test-at-the-top loops to test-at-the-bottom ! 593: * with a jump to the test at the front. ! 594: * In order that we not get confused and loop forever moving the test ! 595: * back and forth, we will recompute the node ordering every time a ! 596: * loop is inverted. ! 597: */ ! 598: int ! 599: invloop() ! 600: { ! 601: int nchanged; ! 602: register NODE *n; ! 603: register nodenumber; ! 604: register NODE *headlabel, *taillabel; ! 605: NODE *jump, *newlabel; ! 606: ! 607: nchanged = 0; ! 608: order_nodes(); ! 609: for (n = first.forw; n != &first; n = n->forw){ ! 610: /* ! 611: * look for this configuaration: ! 612: * headlabel -> Lx: ! 613: * <some instructions ( the test )> ! 614: * n -> conditional jump to Ly ! 615: * <some more instructions ( the loop body )> ! 616: * jump -> jra Lx ! 617: * taillabel -> Ly: ! 618: * If there are many conditional jumps (as in the case of ! 619: * while( xx && yy)) then we can key off of any of the jumps, ! 620: * but the first one makes the most sense, since it will be ! 621: * executed the most frequently. ! 622: */ ! 623: if (n->op == OP_JUMP && n->subop != JALL && ! 624: (taillabel = n->luse)->lineno > n->lineno){ ! 625: jump = taillabel->back; ! 626: if (jump->op == OP_JUMP && jump->subop == JALL && ! 627: (headlabel = jump->luse)->lineno < n->lineno){ ! 628: /* ! 629: * Got it: now reorganize as: ! 630: * Lx: ! 631: * jmp Lnew2 ! 632: * Lnew1: ! 633: * < some instructions ( the loop body ) > ! 634: * Lnew2: ! 635: * < some more instructions ( the test ) > ! 636: * conditional jump to Lnew1 ( reversed conditions ) ! 637: * Ly: ! 638: * in the simple cases, Lx and Ly will become unused at this ! 639: * point. ! 640: */ ! 641: /* move test & jmp code to after the jump */ ! 642: unreference( headlabel, jump ); ! 643: jump->forw = headlabel->forw; ! 644: headlabel->forw = n->forw; ! 645: n->forw->back = headlabel; ! 646: n->forw = taillabel; ! 647: taillabel->back = n; ! 648: jump->forw->back = jump; ! 649: /* delete the jump, replace by a label */ ! 650: newlabel = insert_label( deletenode( jump )->forw ); ! 651: /* insert new jump to new label at head of loop */ ! 652: jump = new(); ! 653: jump->forw = headlabel->forw; ! 654: headlabel->forw = jump; ! 655: jump->back = headlabel; ! 656: jump->forw->back = jump; ! 657: cannibalize( jump, "jra" ); ! 658: jump->op = OP_JUMP; /* rather than OP_BRANCH */ ! 659: newreference( newlabel, jump ); ! 660: /* add another new label after the new jump */ ! 661: newlabel = insert_label( jump->forw ); ! 662: /* flip condition on conditional, point it at the new label */ ! 663: cannibalize( n, unbranch[(int)(n->subop)-(int)JEQ] ); ! 664: n->op = OP_JUMP; /* rather than OP_BRANCH */ ! 665: unreference( taillabel, n ); ! 666: newreference( newlabel, n ); ! 667: order_nodes(); ! 668: n = taillabel->back; ! 669: /* if either of the old labels is superfluous, delete it */ ! 670: if (headlabel->nref == 0 ) (void)deletenode(headlabel); ! 671: if (taillabel->nref == 0 ) (void)deletenode(taillabel); ! 672: nchanged++; ! 673: meter.loopiv++; ! 674: } ! 675: } ! 676: } ! 677: return nchanged; ! 678: } ! 679: ! 680: chase(n,tail) ! 681: register NODE *n, *tail; ! 682: { ! 683: register NODE *p; ! 684: if (n == tail) ! 685: return; ! 686: for (p = n->forw; p != n; p = p->forw) { ! 687: if (p == tail) ! 688: return; ! 689: } ! 690: printf("lost track of node %s\n", tail); ! 691: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.