|
|
1.1 ! root 1: /* Subroutines for insn-output.c for Vax. ! 2: Copyright (C) 1987 Free Software Foundation, Inc. ! 3: ! 4: This file is part of GNU CC. ! 5: ! 6: GNU CC is free software; you can redistribute it and/or modify ! 7: it under the terms of the GNU General Public License as published by ! 8: the Free Software Foundation; either version 2, or (at your option) ! 9: any later version. ! 10: ! 11: GNU CC is distributed in the hope that it will be useful, ! 12: but WITHOUT ANY WARRANTY; without even the implied warranty of ! 13: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ! 14: GNU General Public License for more details. ! 15: ! 16: You should have received a copy of the GNU General Public License ! 17: along with GNU CC; see the file COPYING. If not, write to ! 18: the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ ! 19: ! 20: #include <stdio.h> ! 21: #include "config.h" ! 22: #include "rtl.h" ! 23: #include "regs.h" ! 24: #include "hard-reg-set.h" ! 25: #include "real.h" ! 26: #include "insn-config.h" ! 27: #include "conditions.h" ! 28: #include "insn-flags.h" ! 29: #include "output.h" ! 30: #include "insn-attr.h" ! 31: ! 32: ! 33: /* This is like nonimmediate_operand with a restriction on the type of MEM. */ ! 34: ! 35: void ! 36: split_quadword_operands (operands, low, n) ! 37: rtx *operands, *low; ! 38: int n; ! 39: { ! 40: int i; ! 41: /* Split operands. */ ! 42: ! 43: low[0] = low[1] = low[2] = 0; ! 44: for (i = 0; i < 3; i++) ! 45: { ! 46: if (low[i]) ! 47: /* it's already been figured out */; ! 48: else if (GET_CODE (operands[i]) == MEM ! 49: && (GET_CODE (XEXP (operands[i], 0)) == POST_INC)) ! 50: { ! 51: rtx addr = XEXP (operands[i], 0); ! 52: operands[i] = low[i] = gen_rtx (MEM, SImode, addr); ! 53: if (which_alternative == 0 && i == 0) ! 54: { ! 55: addr = XEXP (operands[i], 0); ! 56: operands[i+1] = low[i+1] = gen_rtx (MEM, SImode, addr); ! 57: } ! 58: } ! 59: else ! 60: { ! 61: low[i] = operand_subword (operands[i], 0, 0, DImode); ! 62: operands[i] = operand_subword (operands[i], 1, 0, DImode); ! 63: } ! 64: } ! 65: } ! 66: ! 67: print_operand_address (file, addr) ! 68: FILE *file; ! 69: register rtx addr; ! 70: { ! 71: register rtx reg1, reg2, breg, ireg; ! 72: rtx offset; ! 73: ! 74: retry: ! 75: switch (GET_CODE (addr)) ! 76: { ! 77: case MEM: ! 78: fprintf (file, "*"); ! 79: addr = XEXP (addr, 0); ! 80: goto retry; ! 81: ! 82: case REG: ! 83: fprintf (file, "(%s)", reg_names[REGNO (addr)]); ! 84: break; ! 85: ! 86: case PRE_DEC: ! 87: fprintf (file, "-(%s)", reg_names[REGNO (XEXP (addr, 0))]); ! 88: break; ! 89: ! 90: case POST_INC: ! 91: fprintf (file, "(%s)+", reg_names[REGNO (XEXP (addr, 0))]); ! 92: break; ! 93: ! 94: case PLUS: ! 95: /* There can be either two or three things added here. One must be a ! 96: REG. One can be either a REG or a MULT of a REG and an appropriate ! 97: constant, and the third can only be a constant or a MEM. ! 98: ! 99: We get these two or three things and put the constant or MEM in ! 100: OFFSET, the MULT or REG in IREG, and the REG in BREG. If we have ! 101: a register and can't tell yet if it is a base or index register, ! 102: put it into REG1. */ ! 103: ! 104: reg1 = 0; ireg = 0; breg = 0; offset = 0; ! 105: ! 106: if (CONSTANT_ADDRESS_P (XEXP (addr, 0)) ! 107: || GET_CODE (XEXP (addr, 0)) == MEM) ! 108: { ! 109: offset = XEXP (addr, 0); ! 110: addr = XEXP (addr, 1); ! 111: } ! 112: else if (CONSTANT_ADDRESS_P (XEXP (addr, 1)) ! 113: || GET_CODE (XEXP (addr, 1)) == MEM) ! 114: { ! 115: offset = XEXP (addr, 1); ! 116: addr = XEXP (addr, 0); ! 117: } ! 118: else if (GET_CODE (XEXP (addr, 1)) == MULT) ! 119: { ! 120: ireg = XEXP (addr, 1); ! 121: addr = XEXP (addr, 0); ! 122: } ! 123: else if (GET_CODE (XEXP (addr, 0)) == MULT) ! 124: { ! 125: ireg = XEXP (addr, 0); ! 126: addr = XEXP (addr, 1); ! 127: } ! 128: else if (GET_CODE (XEXP (addr, 1)) == REG) ! 129: { ! 130: reg1 = XEXP (addr, 1); ! 131: addr = XEXP (addr, 0); ! 132: } ! 133: else if (GET_CODE (XEXP (addr, 0)) == REG) ! 134: { ! 135: reg1 = XEXP (addr, 0); ! 136: addr = XEXP (addr, 1); ! 137: } ! 138: else ! 139: abort (); ! 140: ! 141: if (GET_CODE (addr) == REG) ! 142: { ! 143: if (reg1) ! 144: ireg = addr; ! 145: else ! 146: reg1 = addr; ! 147: } ! 148: else if (GET_CODE (addr) == MULT) ! 149: ireg = addr; ! 150: else if (GET_CODE (addr) == PLUS) ! 151: { ! 152: if (CONSTANT_ADDRESS_P (XEXP (addr, 0)) ! 153: || GET_CODE (XEXP (addr, 0)) == MEM) ! 154: { ! 155: if (offset) ! 156: { ! 157: if (GET_CODE (offset) == CONST_INT) ! 158: offset = plus_constant (XEXP (addr, 0), INTVAL (offset)); ! 159: else if (GET_CODE (XEXP (addr, 0)) == CONST_INT) ! 160: offset = plus_constant (offset, INTVAL (XEXP (addr, 0))); ! 161: else ! 162: abort (); ! 163: } ! 164: offset = XEXP (addr, 0); ! 165: } ! 166: else if (GET_CODE (XEXP (addr, 0)) == REG) ! 167: { ! 168: if (reg1) ! 169: ireg = reg1, breg = XEXP (addr, 0), reg1 = 0; ! 170: else ! 171: reg1 = XEXP (addr, 0); ! 172: } ! 173: else if (GET_CODE (XEXP (addr, 0)) == MULT) ! 174: { ! 175: if (ireg) ! 176: abort (); ! 177: ireg = XEXP (addr, 0); ! 178: } ! 179: else ! 180: abort (); ! 181: ! 182: if (CONSTANT_ADDRESS_P (XEXP (addr, 1)) ! 183: || GET_CODE (XEXP (addr, 1)) == MEM) ! 184: { ! 185: if (offset) ! 186: { ! 187: if (GET_CODE (offset) == CONST_INT) ! 188: offset = plus_constant (XEXP (addr, 1), INTVAL (offset)); ! 189: else if (GET_CODE (XEXP (addr, 1)) == CONST_INT) ! 190: offset = plus_constant (offset, INTVAL (XEXP (addr, 1))); ! 191: else ! 192: abort (); ! 193: } ! 194: offset = XEXP (addr, 1); ! 195: } ! 196: else if (GET_CODE (XEXP (addr, 1)) == REG) ! 197: { ! 198: if (reg1) ! 199: ireg = reg1, breg = XEXP (addr, 1), reg1 = 0; ! 200: else ! 201: reg1 = XEXP (addr, 1); ! 202: } ! 203: else if (GET_CODE (XEXP (addr, 1)) == MULT) ! 204: { ! 205: if (ireg) ! 206: abort (); ! 207: ireg = XEXP (addr, 1); ! 208: } ! 209: else ! 210: abort (); ! 211: } ! 212: else ! 213: abort (); ! 214: ! 215: /* If REG1 is non-zero, figure out if it is a base or index register. */ ! 216: if (reg1) ! 217: { ! 218: if (breg != 0 || (offset && GET_CODE (offset) == MEM)) ! 219: { ! 220: if (ireg) ! 221: abort (); ! 222: ireg = reg1; ! 223: } ! 224: else ! 225: breg = reg1; ! 226: } ! 227: ! 228: if (offset != 0) ! 229: output_address (offset); ! 230: ! 231: if (breg != 0) ! 232: fprintf (file, "(%s)", reg_names[REGNO (breg)]); ! 233: ! 234: if (ireg != 0) ! 235: { ! 236: if (GET_CODE (ireg) == MULT) ! 237: ireg = XEXP (ireg, 0); ! 238: if (GET_CODE (ireg) != REG) ! 239: abort (); ! 240: fprintf (file, "[%s]", reg_names[REGNO (ireg)]); ! 241: } ! 242: break; ! 243: ! 244: default: ! 245: output_addr_const (file, addr); ! 246: } ! 247: } ! 248: ! 249: char * ! 250: rev_cond_name (op) ! 251: rtx op; ! 252: { ! 253: switch (GET_CODE (op)) ! 254: { ! 255: case EQ: ! 256: return "neq"; ! 257: case NE: ! 258: return "eql"; ! 259: case LT: ! 260: return "geq"; ! 261: case LE: ! 262: return "gtr"; ! 263: case GT: ! 264: return "leq"; ! 265: case GE: ! 266: return "lss"; ! 267: case LTU: ! 268: return "gequ"; ! 269: case LEU: ! 270: return "gtru"; ! 271: case GTU: ! 272: return "lequ"; ! 273: case GEU: ! 274: return "lssu"; ! 275: ! 276: default: ! 277: abort (); ! 278: } ! 279: } ! 280: ! 281: int ! 282: vax_float_literal(c) ! 283: register rtx c; ! 284: { ! 285: register enum machine_mode mode; ! 286: int i; ! 287: union {double d; int i[2];} val; ! 288: ! 289: if (GET_CODE (c) != CONST_DOUBLE) ! 290: return 0; ! 291: ! 292: mode = GET_MODE (c); ! 293: ! 294: if (c == const_tiny_rtx[(int) mode][0] ! 295: || c == const_tiny_rtx[(int) mode][1] ! 296: || c == const_tiny_rtx[(int) mode][2]) ! 297: return 1; ! 298: ! 299: #if HOST_FLOAT_FORMAT == VAX_FLOAT_FORMAT ! 300: ! 301: val.i[0] = CONST_DOUBLE_LOW (c); ! 302: val.i[1] = CONST_DOUBLE_HIGH (c); ! 303: ! 304: for (i = 0; i < 7; i ++) ! 305: if (val.d == 1 << i || val.d == 1 / (1 << i)) ! 306: return 1; ! 307: #endif ! 308: return 0; ! 309: } ! 310: ! 311: ! 312: /* Return the cost in cycles of a memory address, relative to register ! 313: indirect. ! 314: ! 315: Each of the following adds the indicated number of cycles: ! 316: ! 317: 1 - symbolic address ! 318: 1 - pre-decrement ! 319: 1 - indexing and/or offset(register) ! 320: 2 - indirect */ ! 321: ! 322: ! 323: int vax_address_cost(addr) ! 324: register rtx addr; ! 325: { ! 326: int reg = 0, indexed = 0, indir = 0, offset = 0, predec = 0; ! 327: rtx plus_op0 = 0, plus_op1 = 0; ! 328: restart: ! 329: switch (GET_CODE (addr)) ! 330: { ! 331: case PRE_DEC: ! 332: predec = 1; ! 333: case REG: ! 334: case SUBREG: ! 335: case POST_INC: ! 336: reg = 1; ! 337: break; ! 338: case MULT: ! 339: indexed = 1; /* 2 on VAX 2 */ ! 340: break; ! 341: case CONST_INT: ! 342: /* byte offsets cost nothing (on a VAX 2, they cost 1 cycle) */ ! 343: if (offset == 0) ! 344: offset = (unsigned)(INTVAL(addr)+128) > 256; ! 345: break; ! 346: case CONST: ! 347: case SYMBOL_REF: ! 348: offset = 1; /* 2 on VAX 2 */ ! 349: break; ! 350: case LABEL_REF: /* this is probably a byte offset from the pc */ ! 351: if (offset == 0) ! 352: offset = 1; ! 353: break; ! 354: case PLUS: ! 355: if (plus_op0) ! 356: plus_op1 = XEXP (addr, 0); ! 357: else ! 358: plus_op0 = XEXP (addr, 0); ! 359: addr = XEXP (addr, 1); ! 360: goto restart; ! 361: case MEM: ! 362: indir = 2; /* 3 on VAX 2 */ ! 363: addr = XEXP (addr, 0); ! 364: goto restart; ! 365: } ! 366: ! 367: /* Up to 3 things can be added in an address. They are stored in ! 368: plus_op0, plus_op1, and addr. */ ! 369: ! 370: if (plus_op0) ! 371: { ! 372: addr = plus_op0; ! 373: plus_op0 = 0; ! 374: goto restart; ! 375: } ! 376: if (plus_op1) ! 377: { ! 378: addr = plus_op1; ! 379: plus_op1 = 0; ! 380: goto restart; ! 381: } ! 382: /* Indexing and register+offset can both be used (except on a VAX 2) ! 383: without increasing execution time over either one alone. */ ! 384: if (reg && indexed && offset) ! 385: return reg + indir + offset + predec; ! 386: return reg + indexed + indir + offset + predec; ! 387: } ! 388: ! 389: ! 390: /* Cost of an expression on a VAX. This version has costs tuned for the ! 391: CVAX chip (found in the VAX 3 series) with comments for variations on ! 392: other models. */ ! 393: ! 394: int ! 395: vax_rtx_cost (x) ! 396: register rtx x; ! 397: { ! 398: register enum rtx_code code = GET_CODE (x); ! 399: enum machine_mode mode = GET_MODE (x); ! 400: register int c; ! 401: int i = 0; /* may be modified in switch */ ! 402: char *fmt = GET_RTX_FORMAT (code); /* may be modified in switch */ ! 403: ! 404: switch (code) ! 405: { ! 406: case POST_INC: ! 407: return 2; ! 408: case PRE_DEC: ! 409: return 3; ! 410: case MULT: ! 411: switch (mode) ! 412: { ! 413: case DFmode: ! 414: c = 16; /* 4 on VAX 9000 */ ! 415: break; ! 416: case SFmode: ! 417: c = 9; /* 4 on VAX 9000, 12 on VAX 2 */ ! 418: break; ! 419: case DImode: ! 420: c = 16; /* 6 on VAX 9000, 28 on VAX 2 */ ! 421: break; ! 422: case SImode: ! 423: case HImode: ! 424: case QImode: ! 425: c = 10; /* 3-4 on VAX 9000, 20-28 on VAX 2 */ ! 426: break; ! 427: } ! 428: break; ! 429: case UDIV: ! 430: c = 17; ! 431: break; ! 432: case DIV: ! 433: if (mode == DImode) ! 434: c = 30; /* highly variable */ ! 435: else if (mode == DFmode) ! 436: /* divide takes 28 cycles if the result is not zero, 13 otherwise */ ! 437: c = 24; ! 438: else ! 439: c = 11; /* 25 on VAX 2 */ ! 440: break; ! 441: case MOD: ! 442: c = 23; ! 443: break; ! 444: case UMOD: ! 445: c = 29; ! 446: break; ! 447: case FLOAT: ! 448: c = 6 + (mode == DFmode) + (GET_MODE (XEXP (x, 0)) != SImode); ! 449: /* 4 on VAX 9000 */ ! 450: break; ! 451: case FIX: ! 452: c = 7; /* 17 on VAX 2 */ ! 453: break; ! 454: case LSHIFT: ! 455: case ASHIFT: ! 456: case LSHIFTRT: ! 457: case ASHIFTRT: ! 458: if (mode == DImode) ! 459: c = 12; ! 460: else ! 461: c = 10; /* 6 on VAX 9000 */ ! 462: break; ! 463: case ROTATE: ! 464: case ROTATERT: ! 465: c = 6; /* 5 on VAX 2, 4 on VAX 9000 */ ! 466: if (GET_CODE (XEXP (x, 1)) == CONST_INT) ! 467: fmt = "e"; /* all constant rotate counts are short */ ! 468: break; ! 469: case PLUS: ! 470: /* Check for small negative integer operand: subl2 can be used with ! 471: a short positive constant instead. */ ! 472: if (GET_CODE (XEXP (x, 1)) == CONST_INT) ! 473: if ((unsigned)(INTVAL (XEXP (x, 1)) + 63) < 127) ! 474: fmt = "e"; ! 475: case MINUS: ! 476: c = (mode == DFmode) ? 13 : 8; /* 6/8 on VAX 9000, 16/15 on VAX 2 */ ! 477: case IOR: ! 478: case XOR: ! 479: c = 3; ! 480: break; ! 481: case AND: ! 482: /* AND is special because the first operand is complemented. */ ! 483: c = 3; ! 484: if (GET_CODE (XEXP (x, 0)) == CONST_INT) ! 485: { ! 486: if ((unsigned)~INTVAL (XEXP (x, 0)) > 63) ! 487: c = 4; ! 488: fmt = "e"; ! 489: i = 1; ! 490: } ! 491: break; ! 492: case NEG: ! 493: if (mode == DFmode) ! 494: return 9; ! 495: else if (mode == SFmode) ! 496: return 6; ! 497: else if (mode == DImode) ! 498: return 4; ! 499: case NOT: ! 500: return 2; ! 501: case ZERO_EXTRACT: ! 502: case SIGN_EXTRACT: ! 503: c = 15; ! 504: break; ! 505: case MEM: ! 506: if (mode == DImode || mode == DFmode) ! 507: c = 5; /* 7 on VAX 2 */ ! 508: else ! 509: c = 3; /* 4 on VAX 2 */ ! 510: x = XEXP (x, 0); ! 511: if (GET_CODE (x) == REG || GET_CODE (x) == POST_INC) ! 512: return c; ! 513: return c + vax_address_cost (x); ! 514: default: ! 515: c = 3; ! 516: break; ! 517: } ! 518: ! 519: ! 520: /* Now look inside the expression. Operands which are not registers or ! 521: short constants add to the cost. ! 522: ! 523: FMT and I may have been adjusted in the switch above for instructions ! 524: which require special handling */ ! 525: ! 526: while (*fmt++ == 'e') ! 527: { ! 528: register rtx op = XEXP (x, i++); ! 529: code = GET_CODE (op); ! 530: ! 531: /* A NOT is likely to be found as the first operand of an AND ! 532: (in which case the relevant cost is of the operand inside ! 533: the not) and not likely to be found anywhere else. */ ! 534: if (code == NOT) ! 535: op = XEXP (op, 0), code = GET_CODE (op); ! 536: ! 537: switch (code) ! 538: { ! 539: case CONST_INT: ! 540: if ((unsigned)INTVAL (op) > 63 && GET_MODE (x) != QImode) ! 541: c += 1; /* 2 on VAX 2 */ ! 542: break; ! 543: case CONST: ! 544: case LABEL_REF: ! 545: case SYMBOL_REF: ! 546: c += 1; /* 2 on VAX 2 */ ! 547: break; ! 548: case CONST_DOUBLE: ! 549: if (GET_MODE_CLASS (GET_MODE (op)) == MODE_FLOAT) ! 550: { ! 551: /* Registers are faster than floating point constants -- even ! 552: those constants which can be encoded in a single byte. */ ! 553: if (vax_float_literal (op)) ! 554: c++; ! 555: else ! 556: c += (GET_MODE (x) == DFmode) ? 3 : 2; ! 557: } ! 558: else ! 559: { ! 560: if (CONST_DOUBLE_HIGH (op) != 0 ! 561: || (unsigned)CONST_DOUBLE_LOW (op) > 63) ! 562: c += 2; ! 563: } ! 564: break; ! 565: case MEM: ! 566: c += 1; /* 2 on VAX 2 */ ! 567: if (GET_CODE (XEXP (op, 0)) != REG) ! 568: c += vax_address_cost (XEXP (op, 0)); ! 569: break; ! 570: case REG: ! 571: case SUBREG: ! 572: break; ! 573: default: ! 574: c += 1; ! 575: break; ! 576: } ! 577: } ! 578: return c; ! 579: } ! 580: ! 581: /* Check a `double' value for validity for a particular machine mode. */ ! 582: ! 583: static char *float_strings[] = ! 584: { ! 585: "1.70141173319264430e+38", /* 2^127 (2^24 - 1) / 2^24 */ ! 586: "-1.70141173319264430e+38", ! 587: "2.93873587705571877e-39", /* 2^-128 */ ! 588: "-2.93873587705571877e-39" ! 589: }; ! 590: ! 591: static REAL_VALUE_TYPE float_values[4]; ! 592: ! 593: static int inited_float_values = 0; ! 594: ! 595: ! 596: void ! 597: check_float_value (mode, d) ! 598: enum machine_mode mode; ! 599: REAL_VALUE_TYPE *d; ! 600: { ! 601: ! 602: if (inited_float_values == 0) ! 603: { ! 604: int i; ! 605: for (i = 0; i < 4; i++) ! 606: { ! 607: float_values[i] = REAL_VALUE_ATOF (float_strings[i], DFmode); ! 608: } ! 609: inited_float_values = 1; ! 610: } ! 611: ! 612: if ((mode) == SFmode) ! 613: { ! 614: REAL_VALUE_TYPE r; ! 615: bcopy (d, &r, sizeof (REAL_VALUE_TYPE)); ! 616: if (REAL_VALUES_LESS (float_values[0], r)) ! 617: { ! 618: error ("magnitude of constant too large for `float'"); ! 619: bcopy (&float_values[0], d, sizeof (REAL_VALUE_TYPE)); ! 620: } ! 621: else if (REAL_VALUES_LESS (r, float_values[1])) ! 622: { ! 623: error ("magnitude of constant too large for `float'"); ! 624: bcopy (&float_values[1], d, sizeof (REAL_VALUE_TYPE)); ! 625: } ! 626: else if (REAL_VALUES_LESS (dconst0, r) ! 627: && REAL_VALUES_LESS (r, float_values[2])) ! 628: { ! 629: warning ("`float' constant truncated to zero"); ! 630: bcopy (&dconst0, d, sizeof (REAL_VALUE_TYPE)); ! 631: } ! 632: else if (REAL_VALUES_LESS (r, dconst0) ! 633: && REAL_VALUES_LESS (float_values[3], r)) ! 634: { ! 635: warning ("`float' constant truncated to zero"); ! 636: bcopy (&dconst0, d, sizeof (REAL_VALUE_TYPE)); ! 637: } ! 638: } ! 639: } ! 640: ! 641: /* Linked list of all externals that are to be emitted when optimizing ! 642: for the global pointer if they haven't been declared by the end of ! 643: the program with an appropriate .comm or initialization. */ ! 644: ! 645: struct extern_list { ! 646: struct extern_list *next; /* next external */ ! 647: char *name; /* name of the external */ ! 648: } *extern_head = 0; ! 649: ! 650: /* Return 1 if NAME has already had an external definition; ! 651: 0 if it has not (so caller should output one). */ ! 652: ! 653: int ! 654: vms_check_external (name) ! 655: char *name; ! 656: { ! 657: register struct extern_list *p; ! 658: ! 659: for (p = extern_head; p; p = p->next) ! 660: if (!strcmp (p->name, name)) ! 661: return 1; ! 662: ! 663: p = (struct extern_list *)permalloc ((long) sizeof (struct extern_list)); ! 664: p->next = extern_head; ! 665: p->name = name; ! 666: extern_head = p; ! 667: return 0; ! 668: } ! 669: ! 670: #ifdef VMS ! 671: /* Additional support code for VMS. */ ! 672: ! 673: #ifdef QSORT_WORKAROUND ! 674: /* ! 675: Do not use VAXCRTL's qsort() due to a severe bug: once you've ! 676: sorted something which has a size that's an exact multiple of 4 ! 677: and is longword aligned, you cannot safely sort anything which ! 678: is either not a multiple of 4 in size or not longword aligned. ! 679: A static "move-by-longword" optimization flag inside qsort() is ! 680: never reset. This is known of affect VMS V4.6 through VMS V5.5-1. ! 681: ! 682: In this work-around an insertion sort is used for simplicity. ! 683: The qsort code from glibc should probably be used instead. ! 684: */ ! 685: void ! 686: not_qsort (array, count, size, compare) ! 687: void *array; ! 688: unsigned count, size; ! 689: int (*compare)(); ! 690: { ! 691: ! 692: if (size == sizeof (short)) ! 693: { ! 694: register int i; ! 695: register short *next, *prev; ! 696: short tmp, *base = array; ! 697: ! 698: for (next = base, i = count - 1; i > 0; i--) ! 699: { ! 700: prev = next++; ! 701: if ((*compare)(next, prev) < 0) ! 702: { ! 703: tmp = *next; ! 704: do *(prev + 1) = *prev; ! 705: while (--prev >= base ? (*compare)(&tmp, prev) < 0 : 0); ! 706: *(prev + 1) = tmp; ! 707: } ! 708: } ! 709: } ! 710: else if (size == sizeof (long)) ! 711: { ! 712: register int i; ! 713: register long *next, *prev; ! 714: long tmp, *base = array; ! 715: ! 716: for (next = base, i = count - 1; i > 0; i--) ! 717: { ! 718: prev = next++; ! 719: if ((*compare)(next, prev) < 0) ! 720: { ! 721: tmp = *next; ! 722: do *(prev + 1) = *prev; ! 723: while (--prev >= base ? (*compare)(&tmp, prev) < 0 : 0); ! 724: *(prev + 1) = tmp; ! 725: } ! 726: } ! 727: } ! 728: else /* arbitrary size */ ! 729: { ! 730: #ifdef USE_C_ALLOCA ! 731: extern void *alloca (); ! 732: #endif ! 733: register int i; ! 734: register char *next, *prev, *tmp = alloca (size), *base = array; ! 735: ! 736: for (next = base, i = count - 1; i > 0; i--) ! 737: { /* count-1 forward iterations */ ! 738: prev = next, next += size; /* increment front pointer */ ! 739: if ((*compare)(next, prev) < 0) ! 740: { /* found element out of order; move others up then re-insert */ ! 741: memcpy (tmp, next, size); /* save smaller element */ ! 742: do { memcpy (prev + size, prev, size); /* move larger elem. up */ ! 743: prev -= size; /* decrement back pointer */ ! 744: } while (prev >= base ? (*compare)(tmp, prev) < 0 : 0); ! 745: memcpy (prev + size, tmp, size); /* restore small element */ ! 746: } ! 747: } ! 748: #ifdef USE_C_ALLOCA ! 749: alloca (0); ! 750: #endif ! 751: } ! 752: ! 753: return; ! 754: } ! 755: #endif /* QSORT_WORKAROUND */ ! 756: ! 757: #endif /* VMS */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.