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