|
|
1.1 ! root 1: /* ! 2: * This file contains the machine dependent parts of the tree modifier. ! 3: * This version handles both the SMALL and the LARGE model iAPX86. ! 4: * A conditionalization handles machines that have an 8087. ! 5: */ ! 6: #ifdef vax ! 7: #include "INC$LIB:cc1.h" ! 8: #else ! 9: #include "cc1.h" ! 10: #endif ! 11: ! 12: int blkflab; ! 13: ! 14: static char modoptab[] = { ! 15: 'i', 'u', 'i', 'u', 'l', 'v', 'f', ! 16: 'd', 'b', 'i', 'i', 'p', 'p', 'p', 'p' ! 17: }; ! 18: ! 19: ! 20: #if SPLIT_CC1 ! 21: /* ! 22: * Function prolog. ! 23: * Clear "BLK function" label. ! 24: */ ! 25: doprolog() ! 26: { ! 27: blkflab = 0; ! 28: } ! 29: ! 30: /* ! 31: * Copy auto information. ! 32: */ ! 33: doautos() ! 34: { ! 35: iput(iget()); ! 36: iput(iget()); ! 37: } ! 38: #endif ! 39: ! 40: /* ! 41: * This function performs machine specific tree modifications. ! 42: * It is called from "modtree" after all of the machine ! 43: * independent transformations have been done. ! 44: * It returns either a pointer to the new tree ! 45: * (telling "modtree" to do another pass) ! 46: * or NULL (which implies that no changes were made). ! 47: */ ! 48: TREE * ! 49: modoper(tp, ac, ptp) ! 50: register TREE *tp; ! 51: TREE *ptp; ! 52: { ! 53: register TREE *lp; ! 54: register TREE *rp; ! 55: register TREE *tp1; ! 56: register TREE *tp2; ! 57: register TREE *tp3; ! 58: register int c; ! 59: register int o; ! 60: register int op; ! 61: register int tt; ! 62: register int nbase; ! 63: register int ntype; ! 64: register int lt; ! 65: register int rt; ! 66: register int seg; ! 67: register int lab; ! 68: register int makecall; ! 69: ! 70: c = ac; ! 71: if (c==MRETURN || c==MSWITCH || c==MINIT) ! 72: c = MRVALUE; ! 73: #if !ONLYSMALL&&!NDP ! 74: /* ! 75: * All fetches of float or double values are rewritten as ! 76: * routine calls in LARGE model. ! 77: * This makes the code a great deal smaller, ! 78: * and solves the problem of addressability on the _fpac_, ! 79: * which is not in the same segment as the data of the file. ! 80: */ ! 81: if (isvariant(VLARGE) ! 82: && (ac!=MINIT && ac!=MLADDR && ac!=MRADDR) ! 83: && (tp->t_flag&T_LEAF) != 0 ! 84: && isflt(tp->t_type)) { ! 85: tp1 = makenode(GID, LPTR); ! 86: if (tp->t_type == F32) ! 87: tp1->t_sp = gidpool("dfload"); ! 88: else ! 89: tp1->t_sp = gidpool("ddload"); ! 90: tp1->t_seg = SANY; ! 91: tp1 = leftnode(CALL, tp1, F64); ! 92: storedcon(tp); ! 93: if (tp->t_op == STAR) ! 94: tp1->t_rp = tp->t_lp; ! 95: else ! 96: tp1->t_rp = leftnode(ADDR, tp, LPTR); ! 97: return (tp1); ! 98: } ! 99: #endif ! 100: op = tp->t_op; ! 101: if (isleaf(op)) { ! 102: if (op==AID || op==PID) { ! 103: ntype = SPTR; ! 104: nbase = BP; ! 105: #if !ONLYSMALL ! 106: if (isvariant(VLARGE)) { ! 107: ntype = LPTR; ! 108: nbase = SSBP; ! 109: } ! 110: #endif ! 111: o = tp->t_offs; ! 112: tp->t_op = STAR; ! 113: tp->t_rp = NULL; ! 114: tp->t_lp = tp2 = makenode(ADD, ntype); ! 115: tp2->t_lp = tp3 = makenode(REG, ntype); ! 116: tp3->t_reg = nbase; ! 117: tp2->t_rp = ivalnode(o); ! 118: return (tp); ! 119: } ! 120: #if !ONLYSMALL ! 121: /* Generate links to double constants under LARGE RAM option. */ ! 122: if ((ac != MINIT) && (op == DCON) && isvariant(VRAM) && isvariant(VLARGE)) { ! 123: pool(tp); /* the dcon */ ! 124: tp->t_type = LPTR; ! 125: tp->t_size = 0; ! 126: pool(tp); /* the label */ ! 127: tp = leftnode(STAR, tp, F64, 0); ! 128: return (tp); ! 129: } ! 130: /* ! 131: * Build up indirect links to any LID or GID items ! 132: * that you cannot access in a direct fashon. ! 133: */ ! 134: if (ac != MINIT ! 135: && (op==LID || op==GID) ! 136: && (ptp==NULL || ptp->t_op!=CALL || tp!=ptp->t_lp) ! 137: && isvariant(VLARGE)) { ! 138: seg = tp->t_seg; ! 139: if (seg==SANY || seg==SDATA || seg==SBSS ! 140: || (seg==SPURE && isvariant(VRAM)) ! 141: || (seg==SSTRN && notvariant(VROM))) { ! 142: pool(tp); ! 143: tp1=leftnode(STAR, tp, tp->t_type, tp->t_size); ! 144: tp->t_type = LPTR; ! 145: tp->t_size = 0; ! 146: return (tp1); ! 147: } ! 148: } ! 149: #endif ! 150: goto done; ! 151: } ! 152: /* ! 153: * Beat on lvalue fields. ! 154: */ ! 155: if ((op==ASSIGN || (op>=AADD && op<=ASHR) ! 156: || (op>=INCBEF && op<=DECAFT)) ! 157: && tp->t_lp->t_op==FIELD && tp->t_lp->t_type<FLD8) ! 158: return (modlfld(tp, c)); ! 159: /* ! 160: * Non leaf. ! 161: * Gather up subtrees. ! 162: * Rewrite some things as calls to library routines. ! 163: */ ! 164: tt = tp->t_type; ! 165: lp = tp->t_lp; ! 166: if (lp != NULL) ! 167: lt = lp->t_type; ! 168: rp = NULL; ! 169: if (op != FIELD) { ! 170: rp = tp->t_rp; ! 171: if (rp != NULL) ! 172: rt = rp->t_type; ! 173: } ! 174: /* ! 175: * Long MUL, DIV and REM are always a function call. ! 176: * If there is no NDP in the machine, ! 177: * then floating point is a routine call. ! 178: * If there is, we rewrite conversions from bytes and unsigned things ! 179: * and all conversions from float to fixed ! 180: * (a mode switch may be necessary). ! 181: */ ! 182: makecall = 0; ! 183: if (islong(tt) && op>=MUL && op<=REM) { ! 184: ++makecall; ! 185: #if NDP ! 186: } else if (isflt(tt)) { ! 187: if (op==CONVERT || op==CAST) { ! 188: if ((lp->t_flag&T_REG) != 0 ! 189: || (lp->t_flag&T_LEAF) == 0 ! 190: || (lt!=S16 && lt!=S32 && lt!=F32)) ! 191: ++makecall; ! 192: } ! 193: } else if ((op>=GT && op<=LT) && isflt(lt)) { ! 194: tp->t_op += UGT-GT; ! 195: #else ! 196: } else if (isflt(tt)) { ! 197: if (op==CONVERT || op==CAST) { ! 198: if (!isflt(lt)) ! 199: ++makecall; ! 200: } else if ((op>=ADD && op<=REM) ! 201: #if !ONLYSMALL ! 202: || (isvariant(VLARGE) && op==NEG) ! 203: || (isvariant(VLARGE) && op==ASSIGN) ! 204: #endif ! 205: || (op>=AADD && op<=AREM)) ! 206: ++makecall; ! 207: } else if (isrelop(op) && isflt(lt)) { ! 208: ++makecall; ! 209: #endif ! 210: } else if ((op==CONVERT || op==CAST) && isflt(lt)) ! 211: ++makecall; ! 212: if (makecall != 0) ! 213: return (modxfun(tp)); ! 214: switch (op) { ! 215: ! 216: case FIELD: ! 217: if (c != MLADDR) ! 218: return (modefld(tp->t_lp, tp, c, 1)); ! 219: break; ! 220: ! 221: case ASSIGN: ! 222: if (tt == BLK) { ! 223: tp = modsasg(lp, rp, tp->t_size); ! 224: if (c != MEFFECT) ! 225: tp = leftnode(STAR, tp, BLK, tp->t_size); ! 226: return (tp); ! 227: } ! 228: break; ! 229: ! 230: case CONVERT: ! 231: case CAST: ! 232: if (modkind(tt) == modkind(lp->t_type)) { ! 233: lp->t_type = tt; ! 234: return (lp); ! 235: } ! 236: } ! 237: /* ! 238: * If this tree is the return value of a structure function, ! 239: * arrange to copy the value into a secret place ! 240: * and return the address of the place. ! 241: */ ! 242: done: ! 243: if (tp->t_type==BLK && ac==MRETURN) { ! 244: if (blkflab == 0) { ! 245: blkflab = newlab(); ! 246: o = newseg(SBSS); ! 247: genlab(blkflab); ! 248: bput(BLOCK); ! 249: iput((ival_t) tp->t_size); ! 250: newseg(o); ! 251: } ! 252: lp = makenode(LID, BLK, tp->t_size); ! 253: lp->t_label = blkflab; ! 254: lp->t_seg = SBSS; ! 255: return (modsasg(lp, tp, tp->t_size)); ! 256: } ! 257: return (NULL); ! 258: } ! 259: ! 260: /* ! 261: * Given a type, return a kind that is used to see ! 262: * if two objects are just different names for the same bits. ! 263: */ ! 264: modkind(t) ! 265: register t; ! 266: { ! 267: if (t == U16) ! 268: t = S16; ! 269: else if (t == U32) ! 270: t = S32; ! 271: return (t); ! 272: } ! 273: ! 274: /* ! 275: * Build a call node for the assignment of structure data. ! 276: * The rep and a copy operation are not used so that the ES need not be used. ! 277: * The type of the CALL is PTR. ! 278: * The size is valid. ! 279: */ ! 280: TREE * ! 281: modsasg(lp, rp, s) ! 282: register TREE *lp; ! 283: register TREE *rp; ! 284: { ! 285: register TREE *tp; ! 286: int nptdt; ! 287: ! 288: nptdt = SPTR; ! 289: #if !ONLYSMALL ! 290: if (isvariant(VLARGE)) ! 291: nptdt = LPTR; ! 292: #endif ! 293: rp = leftnode(ADDR, rp, nptdt); ! 294: rp = leftnode(ARGLST, rp, nptdt); ! 295: rp->t_rp = ivalnode(s); ! 296: lp = leftnode(ADDR, lp, nptdt); ! 297: lp = leftnode(ARGLST, lp, nptdt); ! 298: lp->t_rp = rp; ! 299: tp = makenode(GID, nptdt); ! 300: tp->t_sp = gidpool("blkmv"); ! 301: tp->t_seg = SANY; ! 302: tp = leftnode(CALL, tp, nptdt); ! 303: tp->t_size = s; ! 304: tp->t_rp = lp; ! 305: return (tp); ! 306: } ! 307: ! 308: /* ! 309: * Modify function calls. ! 310: * Handle functions that return objects of type "BLK" ! 311: * by adding a free indirection node. ! 312: */ ! 313: TREE * ! 314: modcall(tp, c) ! 315: register TREE *tp; ! 316: { ! 317: tp->t_lp = modtree(tp->t_lp, MLADDR, tp); ! 318: tp->t_rp = modargs(tp->t_rp, tp); ! 319: if (tp->t_type == BLK) { ! 320: #if !ONLYSMALL ! 321: if (isvariant(VLARGE)) ! 322: tp->t_type = LPTR; ! 323: else ! 324: tp->t_type = SPTR; ! 325: #else ! 326: tp->t_type = SPTR; ! 327: #endif ! 328: if (c != MEFFECT) ! 329: tp = leftnode(STAR, tp, BLK, tp->t_size); ! 330: } ! 331: return (tp); ! 332: } ! 333: ! 334: /* ! 335: * Modify argument lists. ! 336: */ ! 337: TREE * ! 338: modargs(tp, ptp) ! 339: register TREE *tp; ! 340: TREE *ptp; ! 341: { ! 342: if (tp == NULL) ! 343: return (NULL); ! 344: if (tp->t_op == ARGLST) { ! 345: tp->t_lp = modargs(tp->t_lp, tp); ! 346: tp->t_rp = modargs(tp->t_rp, tp); ! 347: return (tp); ! 348: } ! 349: if (tp->t_type == BLK) { ! 350: #if !ONLYSMALL ! 351: tp = leftnode(ADDR, tp, ! 352: (isvariant(VLARGE))?LPTB:SPTB, ! 353: tp->t_size); ! 354: #else ! 355: tp = leftnode(ADDR, tp, SPTB, tp->t_size); ! 356: #endif ! 357: return (modtree(tp, MRVALUE, ptp)); ! 358: } ! 359: return (modtree(tp, MFNARG, ptp)); ! 360: } ! 361: ! 362: /* ! 363: * Given a pointer to a TREE node that describes an operation ! 364: * that the machine cannot directly perform, ! 365: * rewrite the node as a CALL to a magic routine. ! 366: * On the iAPX-86 we rewrite floating point, long multiply and divide ! 367: * and unsigned long multiply and divide. ! 368: * This routine only has to handle the ASSIGN ! 369: * operation if IEEE format; when using DECVAX format ! 370: * the double=>float conversion is easy. ! 371: */ ! 372: TREE * ! 373: modxfun(tp) ! 374: TREE *tp; ! 375: { ! 376: register TREE *lp, *rp; ! 377: register char *p1, *p2; ! 378: register TREE *tp1; ! 379: register int tt, lt, op; ! 380: register int nptct, nptdt; ! 381: ! 382: static char *name[] = { ! 383: "add", ! 384: "sub", ! 385: "mul", ! 386: "div", ! 387: "rem" ! 388: }; ! 389: ! 390: nptdt = SPTR; ! 391: #if !ONLYSMALL ! 392: if (isvariant(VLARGE)) ! 393: nptdt = LPTR; ! 394: #endif ! 395: tp1 = makenode(GID, nptdt); ! 396: op = tp->t_op; ! 397: lp = tp->t_lp; ! 398: rp = tp->t_rp; ! 399: tt = tp->t_type; ! 400: if (lp != NULL) ! 401: lt = lp->t_type; ! 402: p1 = id; ! 403: if (op==CONVERT || op==CAST || op==NEG) { ! 404: p2 = "cvt"; ! 405: if (op == NEG) ! 406: p2 = "neg"; ! 407: *p1++ = modoptab[tt]; ! 408: if (lt==F32 && tt!=F64) ! 409: lt = F64; ! 410: *p1++ = modoptab[lt]; ! 411: } else { ! 412: walk(tp, amd); ! 413: *p1++ = modoptab[tt]; ! 414: if ((op==ADD || op==MUL || isrelop(op)) ! 415: && ((lp->t_flag&T_LEAF)!=0 && (rp->t_flag&T_LEAF)==0 ! 416: || lp->t_op==DCON && rp->t_op!=DCON)) { ! 417: lp = rp; ! 418: rp = tp->t_lp; ! 419: if (isrelop(op)) ! 420: op = fliprel[op-EQ]; ! 421: } ! 422: if (op==ASSIGN || (op>=AADD && op<=AREM)) { ! 423: *p1++ = modoptab[lt]; ! 424: if (lp->t_op != STAR) ! 425: lp = leftnode(ADDR, lp, nptdt); ! 426: else ! 427: lp = lp->t_lp; ! 428: if (op == ASSIGN) ! 429: p2 = "asg"; ! 430: else ! 431: p2 = name[op-AADD]; ! 432: } else if (isrelop(op)) ! 433: p2 = "cmp"; ! 434: else if (op>=ADD && op<=REM) ! 435: p2 = name[op-ADD]; ! 436: else ! 437: cbotch("modxfun"); ! 438: storedcon(rp); ! 439: if (uselvalueform(op, tt, rp)) { ! 440: *p1++ = 'l'; ! 441: if (rp->t_op != STAR) ! 442: rp = leftnode(ADDR, rp, nptdt); ! 443: else ! 444: rp = rp->t_lp; ! 445: } else ! 446: *p1++ = 'r'; ! 447: } ! 448: while (*p1++ = *p2++) ! 449: ; ! 450: *p1 = 0; ! 451: tp1->t_sp = gidpool(id); ! 452: tp1->t_seg = SANY; ! 453: lp = leftnode(ARGLST, lp, nptdt); ! 454: lp->t_rp = rp; ! 455: tp->t_op = CALL; ! 456: tp->t_lp = tp1; ! 457: tp->t_rp = lp; ! 458: fixtoptype(tp); ! 459: if (tp->t_type!=tt && tt!=F32) ! 460: tp = leftnode(CONVERT, tp, tt); ! 461: if (isrelop(op)) { ! 462: tp = leftnode(op, tp, TRUTH); ! 463: tp->t_rp = ivalnode(0); ! 464: } ! 465: return (tp); ! 466: } ! 467: ! 468: /* ! 469: * Zap a DCON into a block of memory with a double in it. ! 470: */ ! 471: storedcon(tp) ! 472: register TREE *tp; ! 473: { ! 474: if (tp->t_op != DCON) ! 475: return; ! 476: pool(tp); ! 477: tp->t_flag = T_DIR; ! 478: } ! 479: ! 480: /* ! 481: * This routine, used only by the "modxfun" routine, ! 482: * checks if an lvalue form of an operator routine can be used. ! 483: * True return if it can. ! 484: */ ! 485: uselvalueform(op, tt, rp) ! 486: register TREE *rp; ! 487: { ! 488: if (isrelop(op)) { ! 489: if (rp->t_type != F64) ! 490: return (0); ! 491: } else { ! 492: if (rp->t_type != tt) ! 493: return (0); ! 494: } ! 495: if (rp->t_op==STAR || (rp->t_flag&T_DIR)!=0) ! 496: return (1); ! 497: return (0); ! 498: } ! 499: ! 500: /* ! 501: * Test if 1) the tree pointed to by "tp" is a register ! 502: * and 2) the operation "op" can be computed in it. ! 503: */ ! 504: isokareg(tp, op) ! 505: register TREE *tp; ! 506: register op; ! 507: { ! 508: if (op==MUL || op==DIV || op==REM) ! 509: return (0); ! 510: if (tp->t_op!=REG || !isword(tp->t_type)) ! 511: return (0); ! 512: return (1); ! 513: } ! 514: ! 515: /* ! 516: * Modify bit fields in lvalue contexts. ! 517: * The "tp" argument is a pointer to the tree node ! 518: * with the FIELD operation on the left side. ! 519: * This routine has two tasks. ! 520: * First, it rewrites the type in the FIELD node to be the type used by ! 521: * select to match the tree; this is also used as a flag ! 522: * to prevent this routine from being called twice on a node. ! 523: * Second, it inserts explict shift nodes to ! 524: * the operands and results so that all of the optimizations ! 525: * applied to shifts work for fields. ! 526: * A pointer to the new top of the tree is returned. ! 527: */ ! 528: TREE * ! 529: modlfld(tp, c) ! 530: register TREE *tp; ! 531: { ! 532: register TREE *lp, *rp; ! 533: register lt, tt; ! 534: register op; ! 535: register bmop; ! 536: register MASK mask; ! 537: ! 538: op = tp->t_op; ! 539: tt = tp->t_type; ! 540: lp = tp->t_lp; ! 541: if (lp != NULL) ! 542: lt = lp->t_type; ! 543: if (op!=AMUL && op!=ADIV && op!=ASHL && op!=ASHR) { ! 544: rp = tp->t_rp; ! 545: rp = leftnode(SHL, rp, rp->t_type); ! 546: rp->t_rp = ivalnode(lp->t_base); ! 547: tp->t_rp = rp; ! 548: } ! 549: if (op==AAND || op==AOR || op==AXOR || op==ASSIGN) { ! 550: mask = ((MASK)01<<lp->t_width) - 1; ! 551: mask = mask << lp->t_base; ! 552: bmop = AND; ! 553: if (op == AAND) { ! 554: mask = ~mask; ! 555: bmop = OR; ! 556: } ! 557: /* rp set above */ ! 558: rp = leftnode(bmop, rp, rp->t_type); ! 559: rp->t_rp = ivalnode(mask); ! 560: tp->t_rp = rp; ! 561: } ! 562: if (c != MEFFECT) ! 563: tp = modefld(tp, lp, c, 0); ! 564: if (isbyte(lt)) ! 565: lp->t_type = FLD8; ! 566: else ! 567: lp->t_type = FLD16; ! 568: return (tp); ! 569: } ! 570: ! 571: /* ! 572: * This function rewrites any field extraction. ! 573: * The argument "tp" is the base of the field. ! 574: * The argument "fp" is a FIELD node that supplies the width and the base. ! 575: * The argument "flag" is true to enable the mask off in unsigned field extract. ! 576: */ ! 577: TREE * ! 578: modefld(tp, fp, c, flag) ! 579: register TREE *tp; ! 580: register TREE *fp; ! 581: { ! 582: register n; ! 583: register tt; ! 584: register mw; ! 585: register mask; ! 586: register ttold; ! 587: ! 588: mw = 16; ! 589: if (isbyte(ttold = tt = tp->t_type)) { ! 590: mw = 8; ! 591: tp = leftnode(CONVERT, tp, tt); ! 592: fixtoptype(tp); ! 593: tt = tp->t_type; ! 594: } ! 595: if (c == MFLOW) { ! 596: mask = (01<<fp->t_width) - 1; ! 597: if ((n=fp->t_base) != 0) ! 598: mask <<= n; ! 599: tp = leftnode(AND, tp, tt); ! 600: tp->t_rp = ivalnode((ival_t)mask); ! 601: return (tp); ! 602: } ! 603: if (isuns(tt)) { ! 604: if ((n=fp->t_base) != 0) { ! 605: tp = leftnode(SHR, tp, tt); ! 606: tp->t_rp = ivalnode(n); ! 607: } ! 608: if (flag && (n=fp->t_width)<mw) { ! 609: tp = leftnode(AND, tp, tt); ! 610: tp->t_rp = ivalnode(((ival_t)01<<n)-1); ! 611: } ! 612: return (tp); ! 613: } ! 614: if ((n=mw-(fp->t_base+fp->t_width)) != 0) { ! 615: tp = leftnode(SHL, tp, tt); ! 616: tp->t_rp = ivalnode(n); ! 617: } ! 618: if ((n=mw-fp->t_width) != 0) { ! 619: tp = leftnode(SHR, tp, tt); ! 620: tp->t_rp = ivalnode(n); ! 621: } ! 622: if (ttold != tt) ! 623: tp = leftnode(CONVERT, tp, ttold); ! 624: return (tp); ! 625: } ! 626: ! 627: /* ! 628: * Check if a tree should have its left and right subtrees swapped. ! 629: * Do it if it is required. ! 630: * Sometimes the relational operation must be adjusted. ! 631: */ ! 632: modswap(tp, ptp) ! 633: register TREE *tp; ! 634: TREE *ptp; ! 635: { ! 636: register TREE *lp, *rp; ! 637: FLAG lf, rf; ! 638: ! 639: switch (tp->t_op) { ! 640: ! 641: case ADD: ! 642: case MUL: ! 643: case AND: ! 644: case OR: ! 645: case XOR: ! 646: case EQ: ! 647: case NE: ! 648: case GT: ! 649: case GE: ! 650: case LT: ! 651: case LE: ! 652: case UGT: ! 653: case UGE: ! 654: case ULT: ! 655: case ULE: ! 656: lp = tp->t_lp; ! 657: rp = tp->t_rp; ! 658: lf = lp->t_flag; ! 659: rf = rp->t_flag; ! 660: if (lf!=0 || rf!=0) { ! 661: if ((lf&T_CON) != 0 ! 662: || (rf&T_REG) != 0 ! 663: || (lf!=0 && rf==0)) ! 664: swapit(tp); ! 665: } else if (lp->t_cost > rp->t_cost) ! 666: swapit(tp); ! 667: } ! 668: } ! 669: ! 670: /* ! 671: * Swap subtrees. ! 672: * Fix up relational ops. ! 673: */ ! 674: swapit(tp) ! 675: register TREE *tp; ! 676: { ! 677: register TREE *xp; ! 678: register op; ! 679: ! 680: xp = tp->t_lp; ! 681: tp->t_lp = tp->t_rp; ! 682: tp->t_rp = xp; ! 683: op = tp->t_op; ! 684: if (isrelop(op)) ! 685: tp->t_op = fliprel[op-EQ]; ! 686: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.