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