|
|
1.1 ! root 1: /* Medium-level subroutines: convert bit-field store and extract ! 2: and shifts, multiplies and divides to rtl instructions. ! 3: Copyright (C) 1987, 1988 Free Software Foundation, Inc. ! 4: ! 5: This file is part of GNU CC. ! 6: ! 7: GNU CC is distributed in the hope that it will be useful, ! 8: but WITHOUT ANY WARRANTY. No author or distributor ! 9: accepts responsibility to anyone for the consequences of using it ! 10: or for whether it serves any particular purpose or works at all, ! 11: unless he says so in writing. Refer to the GNU CC General Public ! 12: License for full details. ! 13: ! 14: Everyone is granted permission to copy, modify and redistribute ! 15: GNU CC, but only under the conditions described in the ! 16: GNU CC General Public License. A copy of this license is ! 17: supposed to have been given to you along with GNU CC so you ! 18: can know your rights and responsibilities. It should be in a ! 19: file named COPYING. Among other things, the copyright notice ! 20: and this notice must be preserved on all copies. */ ! 21: ! 22: ! 23: #include "config.h" ! 24: #include "rtl.h" ! 25: #include "tree.h" ! 26: #include "flags.h" ! 27: #include "insn-flags.h" ! 28: #include "insn-codes.h" ! 29: #include "insn-config.h" ! 30: #include "expr.h" ! 31: #include "recog.h" ! 32: ! 33: static rtx extract_split_bit_field (); ! 34: static rtx extract_fixed_bit_field (); ! 35: static void store_split_bit_field (); ! 36: static void store_fixed_bit_field (); ! 37: ! 38: /* Return an rtx representing minus the value of X. */ ! 39: ! 40: rtx ! 41: negate_rtx (x) ! 42: rtx x; ! 43: { ! 44: if (GET_CODE (x) == CONST_INT) ! 45: return gen_rtx (CONST_INT, VOIDmode, - INTVAL (x)); ! 46: else ! 47: return expand_unop (GET_MODE (x), neg_optab, x, 0, 0); ! 48: } ! 49: ! 50: /* Generate code to store value from rtx VALUE ! 51: into a bit-field within structure STR_RTX ! 52: containing BITSIZE bits starting at bit BITNUM. ! 53: FIELDMODE is the machine-mode of the FIELD_DECL node for this field. */ ! 54: ! 55: /* ??? This should really have the ability to copy a word into a register ! 56: in order to store the bit-field into it, on machines whose insv insns ! 57: work that way. */ ! 58: ! 59: rtx ! 60: store_bit_field (str_rtx, bitsize, bitnum, fieldmode, value) ! 61: rtx str_rtx; ! 62: register int bitsize; ! 63: int bitnum; ! 64: enum machine_mode fieldmode; ! 65: rtx value; ! 66: { ! 67: int unit = (GET_CODE (str_rtx) == MEM) ? BITS_PER_UNIT : BITS_PER_WORD; ! 68: register int offset = bitnum / unit; ! 69: register int bitpos = bitnum % unit; ! 70: register rtx op0 = str_rtx; ! 71: rtx value1; ! 72: ! 73: if (GET_CODE (op0) == SUBREG) ! 74: { ! 75: offset += SUBREG_WORD (op0); ! 76: op0 = SUBREG_REG (op0); ! 77: } ! 78: ! 79: value = protect_from_queue (value, 0); ! 80: ! 81: if (flag_force_mem) ! 82: value = force_not_mem (value); ! 83: ! 84: if (GET_MODE_SIZE (fieldmode) >= UNITS_PER_WORD) ! 85: { ! 86: /* Storing in a full-word or multi-word field in a register ! 87: can be done with just SUBREG. */ ! 88: if (GET_MODE (op0) != fieldmode) ! 89: op0 = gen_rtx (SUBREG, fieldmode, op0, offset); ! 90: emit_move_insn (op0, value); ! 91: return value; ! 92: } ! 93: ! 94: #ifdef BYTES_BIG_ENDIAN ! 95: /* If OP0 is a register, BITPOS must count within a word. ! 96: But as we have it, it counts within whatever size OP0 now has. ! 97: On a bigendian machine, these are not the same, so convert. */ ! 98: if (GET_CODE (op0) != MEM && unit > GET_MODE_BITSIZE (GET_MODE (op0))) ! 99: bitpos += unit - GET_MODE_BITSIZE (GET_MODE (op0)); ! 100: #endif ! 101: ! 102: /* Storing an lsb-aligned field in a register ! 103: can be done with a movestrict instruction. */ ! 104: ! 105: if (GET_CODE (op0) != MEM ! 106: #ifdef BYTES_BIG_ENDIAN ! 107: && bitpos + bitsize == unit ! 108: #else ! 109: && bitpos == 0 ! 110: #endif ! 111: && (GET_MODE (op0) == fieldmode ! 112: || (movstrict_optab->handlers[(int) fieldmode].insn_code ! 113: != CODE_FOR_nothing))) ! 114: { ! 115: /* Get appropriate low part of the value being stored. */ ! 116: if (GET_CODE (value) == CONST_INT || GET_CODE (value) == REG) ! 117: value = gen_lowpart (fieldmode, value); ! 118: else if (!(GET_CODE (value) == SYMBOL_REF ! 119: || GET_CODE (value) == LABEL_REF ! 120: || GET_CODE (value) == CONST)) ! 121: value = convert_to_mode (fieldmode, value, 0); ! 122: ! 123: if (GET_MODE (op0) == fieldmode) ! 124: emit_move_insn (op0, value); ! 125: else ! 126: emit_insn (GEN_FCN (movstrict_optab->handlers[(int) fieldmode].insn_code) ! 127: (gen_rtx (SUBREG, fieldmode, op0, offset), value)); ! 128: ! 129: return value; ! 130: } ! 131: ! 132: /* From here on we can assume that the field to be stored in is an integer, ! 133: since it is shorter than a word. */ ! 134: ! 135: /* OFFSET is the number of words or bytes (UNIT says which) ! 136: from STR_RTX to the first word or byte containing part of the field. */ ! 137: ! 138: if (GET_CODE (op0) == REG) ! 139: { ! 140: if (offset != 0 ! 141: || GET_MODE_SIZE (GET_MODE (op0)) > GET_MODE_SIZE (SImode)) ! 142: op0 = gen_rtx (SUBREG, SImode, op0, offset); ! 143: offset = 0; ! 144: } ! 145: else ! 146: { ! 147: op0 = protect_from_queue (op0, 1); ! 148: } ! 149: ! 150: /* Now OFFSET is nonzero only if OP0 is memory ! 151: and is therefore always measured in bytes. */ ! 152: ! 153: #ifdef HAVE_insv ! 154: if (HAVE_insv ! 155: && !(bitsize == 1 && GET_CODE (value) == CONST_INT)) ! 156: { ! 157: enum machine_mode mode0 = GET_MODE (op0); ! 158: ! 159: /* Add OFFSET into OP0's address. */ ! 160: if (GET_CODE (op0) == MEM) ! 161: op0 = change_address (op0, QImode, ! 162: plus_constant (XEXP (op0, 0), offset)); ! 163: ! 164: /* If op0 is a register, we need it in SImode ! 165: to make it acceptable to the format of insv. */ ! 166: if (GET_CODE (op0) == SUBREG) ! 167: PUT_MODE (op0, SImode); ! 168: if (GET_CODE (op0) == REG && GET_MODE (op0) != SImode) ! 169: op0 = gen_rtx (SUBREG, SImode, op0, 0); ! 170: ! 171: /* Convert VALUE to SImode (which insv insn wants) in VALUE1. */ ! 172: value1 = value; ! 173: if (GET_MODE (value) != SImode) ! 174: { ! 175: if (GET_MODE_BITSIZE (GET_MODE (value)) >= bitsize) ! 176: { ! 177: if (GET_CODE (value) != REG) ! 178: value1 = copy_to_reg (value); ! 179: /* Optimization: Don't bother really extending VALUE ! 180: if it has all the bits we will actually use. */ ! 181: value1 = gen_rtx (SUBREG, SImode, value1, 0); ! 182: } ! 183: else if (!CONSTANT_P (value)) ! 184: /* Parse phase is supposed to make VALUE's data type ! 185: match that of the component reference, which is a type ! 186: at least as wide as the field; so VALUE should have ! 187: a mode that corresponds to that type. */ ! 188: abort (); ! 189: } ! 190: ! 191: /* If this machine's insv insists on a register, ! 192: get VALUE1 into a register. */ ! 193: if (! (*insn_operand_predicate[(int) CODE_FOR_insv][3]) (value1, SImode)) ! 194: value1 = force_reg (SImode, value1); ! 195: ! 196: /* On big-endian machines, we count bits from the most significant. ! 197: If the bit field insn does not, we must invert. */ ! 198: ! 199: #if defined (BITS_BIG_ENDIAN) != defined (BYTES_BIG_ENDIAN) ! 200: bitpos = unit - 1 - bitpos; ! 201: #endif ! 202: ! 203: emit_insn (gen_insv (op0, ! 204: gen_rtx (CONST_INT, VOIDmode, bitsize), ! 205: gen_rtx (CONST_INT, VOIDmode, bitpos), ! 206: value1)); ! 207: } ! 208: else ! 209: #endif ! 210: /* Insv is not available; store using shifts and boolean ops. */ ! 211: store_fixed_bit_field (op0, offset, bitsize, bitpos, value); ! 212: return value; ! 213: } ! 214: ! 215: /* Use shifts and boolean operations to store VALUE ! 216: into a bit field of width BITSIZE ! 217: in a memory location specified by OP0 except offset by OFFSET bytes. ! 218: The field starts at position BITPOS within the byte. ! 219: (If OP0 is a register, it may be SImode or a narrower mode, ! 220: but BITPOS still counts within a full word, ! 221: which is significant on bigendian machines.) ! 222: ! 223: Note that protect_from_queue has already been done on OP0 and VALUE. */ ! 224: ! 225: static void ! 226: store_fixed_bit_field (op0, offset, bitsize, bitpos, value) ! 227: register rtx op0; ! 228: register int offset, bitsize, bitpos; ! 229: register rtx value; ! 230: { ! 231: register enum machine_mode mode; ! 232: int total_bits = BITS_PER_WORD; ! 233: rtx subtarget; ! 234: int all_zero = 0; ! 235: int all_one = 0; ! 236: ! 237: /* Add OFFSET to OP0's address (if it is in memory) ! 238: and if a single byte contains the whole bit field ! 239: change OP0 to a byte. */ ! 240: ! 241: if (GET_CODE (op0) == REG || GET_CODE (op0) == SUBREG) ! 242: { ! 243: /* Special treatment for a bit field split across two registers. */ ! 244: if (bitsize + bitpos > BITS_PER_WORD) ! 245: { ! 246: store_split_bit_field (op0, bitsize, bitpos, value); ! 247: return; ! 248: } ! 249: } ! 250: else if (bitsize + bitpos <= BITS_PER_UNIT ! 251: && ! SLOW_BYTE_ACCESS) ! 252: { ! 253: total_bits = BITS_PER_UNIT; ! 254: op0 = change_address (op0, QImode, ! 255: plus_constant (XEXP (op0, 0), offset)); ! 256: } ! 257: else ! 258: { ! 259: /* Get ref to word containing the field. */ ! 260: /* Adjust BITPOS to be position within a word, ! 261: and OFFSET to be the offset of that word. ! 262: Then alter OP0 to refer to that word. */ ! 263: bitpos += (offset % (BITS_PER_WORD / BITS_PER_UNIT)) * BITS_PER_UNIT; ! 264: offset -= (offset % (BITS_PER_WORD / BITS_PER_UNIT)); ! 265: op0 = change_address (op0, SImode, ! 266: plus_constant (XEXP (op0, 0), offset)); ! 267: /* Special treatment for a bit field split across two words. */ ! 268: if (bitsize + bitpos > BITS_PER_WORD) ! 269: { ! 270: store_split_bit_field (op0, bitsize, bitpos, value); ! 271: return; ! 272: } ! 273: } ! 274: ! 275: mode = GET_MODE (op0); ! 276: ! 277: /* Now OP0 is either a byte or a word, and the bit field is contained ! 278: entirely within it. TOTAL_BITS and MODE say which one (byte or word). ! 279: BITPOS is the starting bit number within the byte or word. ! 280: (If OP0 is a word, it may actually have a mode narrower than SImode.) */ ! 281: ! 282: #ifdef BYTES_BIG_ENDIAN ! 283: /* BITPOS is the distance between our msb ! 284: and that of the containing byte or word. ! 285: Convert it to the distance from the lsb. */ ! 286: ! 287: bitpos = total_bits - bitsize - bitpos; ! 288: #endif ! 289: /* Now BITPOS is always the distance between our lsb ! 290: and that of the containing byte or word. */ ! 291: ! 292: /* Shift VALUE left by BITPOS bits. If VALUE is not constant, ! 293: we must first convert its mode to MODE. */ ! 294: ! 295: if (GET_CODE (value) == CONST_INT) ! 296: { ! 297: register int v = INTVAL (value); ! 298: ! 299: if (bitsize < HOST_BITS_PER_INT) ! 300: v &= (1 << bitsize) - 1; ! 301: ! 302: if (v == 0) ! 303: all_zero = 1; ! 304: else if (bitsize < HOST_BITS_PER_INT && v == (1 << bitsize) - 1) ! 305: all_one = 1; ! 306: ! 307: value = gen_rtx (CONST_INT, VOIDmode, v << bitpos); ! 308: } ! 309: else ! 310: { ! 311: int must_and = (GET_MODE_BITSIZE (GET_MODE (value)) != bitsize); ! 312: ! 313: if (GET_MODE (value) != mode) ! 314: { ! 315: if (GET_CODE (value) == REG && mode == QImode) ! 316: value = gen_rtx (SUBREG, mode, value, 0); ! 317: else ! 318: value = convert_to_mode (mode, value, 1); ! 319: } ! 320: ! 321: if (must_and && bitsize < HOST_BITS_PER_INT) ! 322: value = expand_bit_and (mode, value, ! 323: gen_rtx (CONST_INT, VOIDmode, ! 324: (1 << bitsize) - 1), ! 325: 0); ! 326: if (bitpos > 0) ! 327: value = expand_shift (LSHIFT_EXPR, mode, value, ! 328: build_int_2 (bitpos, 0), 0, 1); ! 329: } ! 330: ! 331: /* Now clear the chosen bits in OP0, ! 332: except that if VALUE is -1 we need not bother. */ ! 333: ! 334: subtarget = op0; ! 335: ! 336: if (! all_one) ! 337: subtarget = expand_bit_and (mode, op0, ! 338: gen_rtx (CONST_INT, VOIDmode, ! 339: (~ (((1 << bitsize) - 1) << bitpos)) ! 340: & ((1 << GET_MODE_BITSIZE (mode)) - 1)), ! 341: subtarget); ! 342: ! 343: /* Now logical-or VALUE into OP0, unless it is zero. */ ! 344: ! 345: if (! all_zero) ! 346: subtarget = expand_binop (mode, ior_optab, subtarget, value, ! 347: op0, 1, OPTAB_LIB_WIDEN); ! 348: if (op0 != subtarget) ! 349: emit_move_insn (op0, subtarget); ! 350: } ! 351: ! 352: /* Store a bit field that is split across two words. ! 353: ! 354: OP0 is the REG, SUBREG or MEM rtx for the first of the two words. ! 355: BITSIZE is the field width; BITPOS the position of its first bit ! 356: (within the word). ! 357: VALUE is the value to store. */ ! 358: ! 359: static void ! 360: store_split_bit_field (op0, bitsize, bitpos, value) ! 361: rtx op0; ! 362: int bitsize, bitpos; ! 363: rtx value; ! 364: { ! 365: /* BITSIZE_1 is size of the part in the first word. */ ! 366: int bitsize_1 = BITS_PER_WORD - bitpos; ! 367: /* BITSIZE_2 is size of the rest (in the following word). */ ! 368: int bitsize_2 = bitsize - bitsize_1; ! 369: rtx part1, part2; ! 370: ! 371: if (GET_MODE (value) != VOIDmode) ! 372: value = convert_to_mode (SImode, value, 1); ! 373: if (CONSTANT_P (value) && GET_CODE (value) != CONST_INT) ! 374: value = copy_to_reg (value); ! 375: ! 376: /* Split the value into two parts: ! 377: PART1 gets that which goes in the first word; PART2 the other. */ ! 378: #ifdef BYTES_BIG_ENDIAN ! 379: /* PART1 gets the more significant part. */ ! 380: if (GET_CODE (value) == CONST_INT) ! 381: { ! 382: part1 = gen_rtx (CONST_INT, VOIDmode, ! 383: (unsigned) (INTVAL (value)) >> bitsize_2); ! 384: part2 = gen_rtx (CONST_INT, VOIDmode, ! 385: (unsigned) (INTVAL (value)) & ((1 << bitsize_2) - 1)); ! 386: } ! 387: else ! 388: { ! 389: part1 = extract_fixed_bit_field (SImode, value, 0, bitsize_1, ! 390: BITS_PER_WORD - bitsize, 0, 1); ! 391: part2 = extract_fixed_bit_field (SImode, value, 0, bitsize_2, ! 392: BITS_PER_WORD - bitsize_2, 0, 1); ! 393: } ! 394: #else ! 395: /* PART1 gets the less significant part. */ ! 396: if (GET_CODE (value) == CONST_INT) ! 397: { ! 398: part1 = gen_rtx (CONST_INT, VOIDmode, ! 399: (unsigned) (INTVAL (value)) & ((1 << bitsize_1) - 1)); ! 400: part2 = gen_rtx (CONST_INT, VOIDmode, ! 401: (unsigned) (INTVAL (value)) >> bitsize_1); ! 402: } ! 403: else ! 404: { ! 405: part1 = extract_fixed_bit_field (SImode, value, 0, bitsize_1, 0, 0, 1); ! 406: part2 = extract_fixed_bit_field (SImode, value, 0, bitsize_2, ! 407: bitsize_1, 0, 1); ! 408: } ! 409: #endif ! 410: ! 411: /* Store PART1 into the first word. */ ! 412: store_fixed_bit_field (op0, 0, bitsize_1, bitpos, part1); ! 413: ! 414: /* Offset op0 to get to the following word. */ ! 415: if (GET_CODE (op0) == MEM) ! 416: op0 = change_address (op0, SImode, ! 417: plus_constant (XEXP (op0, 0), UNITS_PER_WORD)); ! 418: else if (GET_CODE (op0) == REG) ! 419: op0 = gen_rtx (SUBREG, SImode, op0, 1); ! 420: else ! 421: op0 = gen_rtx (SUBREG, SImode, SUBREG_REG (op0), SUBREG_WORD (op0) + 1); ! 422: ! 423: /* Store PART2 into the second word. */ ! 424: store_fixed_bit_field (op0, 0, bitsize_2, 0, part2); ! 425: } ! 426: ! 427: /* Generate code to extract a byte-field from STR_RTX ! 428: containing BITSIZE bits, starting at BITNUM, ! 429: and put it in TARGET if possible (if TARGET is nonzero). ! 430: Regardless of TARGET, we return the rtx for where the value is placed. ! 431: It may be a QUEUED. ! 432: ! 433: STR_RTX is the structure containing the byte (a REG or MEM). ! 434: UNSIGNEDP is nonzero if this is an unsigned bit field. ! 435: MODE is the natural mode of the field value once extracted. ! 436: TMODE is the mode the caller would like the value to have; ! 437: but the value may be returned with type MODE instead. ! 438: ! 439: If a TARGET is specified and we can store in it at no extra cost, ! 440: we do so, and return TARGET. ! 441: Otherwise, we return a REG of mode TMODE or MODE, with TMODE preferred ! 442: if they are equally easy. */ ! 443: ! 444: rtx ! 445: extract_bit_field (str_rtx, bitsize, bitnum, unsignedp, target, mode, tmode) ! 446: rtx str_rtx; ! 447: register int bitsize; ! 448: int bitnum; ! 449: int unsignedp; ! 450: rtx target; ! 451: enum machine_mode mode, tmode; ! 452: { ! 453: int unit = (GET_CODE (str_rtx) == MEM) ? BITS_PER_UNIT : BITS_PER_WORD; ! 454: register int offset = bitnum / unit; ! 455: register int bitpos = bitnum % unit; ! 456: register rtx op0 = str_rtx; ! 457: rtx spec_target = target; ! 458: rtx bitsize_rtx, bitpos_rtx; ! 459: rtx spec_target_subreg = 0; ! 460: ! 461: if (tmode == VOIDmode) ! 462: tmode = mode; ! 463: ! 464: while (GET_CODE (op0) == SUBREG) ! 465: { ! 466: offset += SUBREG_WORD (op0); ! 467: op0 = SUBREG_REG (op0); ! 468: } ! 469: ! 470: #ifdef BYTES_BIG_ENDIAN ! 471: /* If OP0 is a register, BITPOS must count within a word. ! 472: But as we have it, it counts within whatever size OP0 now has. ! 473: On a bigendian machine, these are not the same, so convert. */ ! 474: if (GET_CODE (op0) != MEM && unit > GET_MODE_BITSIZE (GET_MODE (op0))) ! 475: bitpos += unit - GET_MODE_BITSIZE (GET_MODE (op0)); ! 476: #endif ! 477: ! 478: /* Extracting a full-word or multi-word value ! 479: from a structure in a register. ! 480: This can be done with just SUBREG. ! 481: So too extracting a subword value in ! 482: the least significant part of the register. */ ! 483: ! 484: if (GET_CODE (op0) == REG ! 485: && (bitsize >= BITS_PER_WORD ! 486: || ((bitsize == GET_MODE_BITSIZE (mode) ! 487: || bitsize == GET_MODE_BITSIZE (QImode) ! 488: || bitsize == GET_MODE_BITSIZE (HImode)) ! 489: #ifdef BYTES_BIG_ENDIAN ! 490: && bitpos + bitsize == BITS_PER_WORD ! 491: #else ! 492: && bitpos == 0 ! 493: #endif ! 494: ))) ! 495: { ! 496: enum machine_mode mode1 = mode; ! 497: ! 498: if (bitsize == GET_MODE_BITSIZE (QImode)) ! 499: mode1 = QImode; ! 500: if (bitsize == GET_MODE_BITSIZE (HImode)) ! 501: mode1 = HImode; ! 502: ! 503: if (mode1 != GET_MODE (op0)) ! 504: op0 = gen_rtx (SUBREG, mode1, op0, offset); ! 505: ! 506: if (mode1 != mode) ! 507: return convert_to_mode (tmode, op0, unsignedp); ! 508: return op0; ! 509: } ! 510: ! 511: /* From here on we know the desired field is smaller than a word ! 512: so we can assume it is an integer. So we can safely extract it as one ! 513: size of integer, if necessary, and then truncate or extend ! 514: to the size that is wanted. */ ! 515: ! 516: /* OFFSET is the number of words or bytes (UNIT says which) ! 517: from STR_RTX to the first word or byte containing part of the field. */ ! 518: ! 519: if (GET_CODE (op0) == REG) ! 520: { ! 521: if (offset != 0 ! 522: || GET_MODE_SIZE (GET_MODE (op0)) > GET_MODE_SIZE (SImode)) ! 523: op0 = gen_rtx (SUBREG, SImode, op0, offset); ! 524: offset = 0; ! 525: } ! 526: else ! 527: { ! 528: op0 = protect_from_queue (str_rtx, 1); ! 529: } ! 530: ! 531: /* Now OFFSET is nonzero only for memory operands. */ ! 532: ! 533: if (unsignedp) ! 534: { ! 535: #ifdef HAVE_extzv ! 536: if (HAVE_extzv) ! 537: { ! 538: /* Get ref to first byte containing part of the field. */ ! 539: if (GET_CODE (op0) == MEM) ! 540: op0 = change_address (op0, QImode, ! 541: plus_constant (XEXP (op0, 0), offset)); ! 542: ! 543: /* If op0 is a register, we need it in SImode ! 544: to make it acceptable to the format of extv. */ ! 545: if (GET_CODE (op0) == SUBREG) ! 546: PUT_MODE (op0, SImode); ! 547: if (GET_CODE (op0) == REG && GET_MODE (op0) != SImode) ! 548: op0 = gen_rtx (SUBREG, SImode, op0, 0); ! 549: ! 550: if (target == 0 ! 551: || (flag_force_mem && GET_CODE (target) == MEM)) ! 552: target = spec_target = gen_reg_rtx (tmode); ! 553: ! 554: if (GET_MODE (target) != SImode) ! 555: { ! 556: if (GET_CODE (target) == REG) ! 557: spec_target_subreg = target = gen_rtx (SUBREG, SImode, target, 0); ! 558: else ! 559: target = gen_reg_rtx (SImode); ! 560: } ! 561: ! 562: /* If this machine's extzv insists on a register target, ! 563: make sure we have one. */ ! 564: if (! (*insn_operand_predicate[(int) CODE_FOR_extzv][0]) (target, SImode)) ! 565: target = gen_reg_rtx (SImode); ! 566: ! 567: /* On big-endian machines, we count bits from the most significant. ! 568: If the bit field insn does not, we must invert. */ ! 569: #if defined (BITS_BIG_ENDIAN) != defined (BYTES_BIG_ENDIAN) ! 570: bitpos = unit - 1 - bitpos; ! 571: #endif ! 572: ! 573: bitsize_rtx = gen_rtx (CONST_INT, VOIDmode, bitsize); ! 574: bitpos_rtx = gen_rtx (CONST_INT, VOIDmode, bitpos); ! 575: ! 576: emit_insn (gen_extzv (protect_from_queue (target, 1), ! 577: op0, bitsize_rtx, bitpos_rtx)); ! 578: } ! 579: else ! 580: #endif ! 581: target = extract_fixed_bit_field (tmode, op0, offset, bitsize, bitpos, ! 582: target, 1); ! 583: } ! 584: else ! 585: { ! 586: #ifdef HAVE_extv ! 587: if (HAVE_extv) ! 588: { ! 589: /* Get ref to first byte containing part of the field. */ ! 590: if (GET_CODE (op0) == MEM) ! 591: op0 = change_address (op0, QImode, ! 592: plus_constant (XEXP (op0, 0), offset)); ! 593: ! 594: /* If op0 is a register, we need it in QImode ! 595: to make it acceptable to the format of extv. */ ! 596: if (GET_CODE (op0) == SUBREG) ! 597: PUT_MODE (op0, SImode); ! 598: if (GET_CODE (op0) == REG && GET_MODE (op0) != SImode) ! 599: op0 = gen_rtx (SUBREG, SImode, op0, 0); ! 600: ! 601: if (target == 0 ! 602: || (flag_force_mem && GET_CODE (target) == MEM)) ! 603: target = spec_target = gen_reg_rtx (tmode); ! 604: ! 605: if (GET_MODE (target) != SImode) ! 606: { ! 607: if (GET_CODE (target) == REG) ! 608: spec_target_subreg = target = gen_rtx (SUBREG, SImode, target, 0); ! 609: else ! 610: target = gen_reg_rtx (SImode); ! 611: } ! 612: ! 613: /* If this machine's extv insists on a register target, ! 614: make sure we have one. */ ! 615: if (! (*insn_operand_predicate[(int) CODE_FOR_extzv][0]) (target, SImode)) ! 616: target = gen_reg_rtx (SImode); ! 617: ! 618: /* On big-endian machines, we count bits from the most significant. ! 619: If the bit field insn does not, we must invert. */ ! 620: #if defined (BITS_BIG_ENDIAN) != defined (BYTES_BIG_ENDIAN) ! 621: bitpos = unit - 1 - bitpos; ! 622: #endif ! 623: ! 624: bitsize_rtx = gen_rtx (CONST_INT, VOIDmode, bitsize); ! 625: bitpos_rtx = gen_rtx (CONST_INT, VOIDmode, bitpos); ! 626: ! 627: emit_insn (gen_extv (protect_from_queue (target, 1), op0, ! 628: bitsize_rtx, bitpos_rtx)); ! 629: } ! 630: else ! 631: #endif ! 632: target = extract_fixed_bit_field (tmode, op0, offset, bitsize, bitpos, ! 633: target, 0); ! 634: } ! 635: if (target == spec_target) ! 636: return target; ! 637: if (target == spec_target_subreg) ! 638: return spec_target; ! 639: if (GET_MODE (target) != tmode && GET_MODE (target) != mode) ! 640: return convert_to_mode (tmode, target, unsignedp); ! 641: return target; ! 642: } ! 643: ! 644: /* Extract a bit field using shifts and boolean operations ! 645: Returns an rtx to represent the value. ! 646: OP0 addresses a register (word) or memory (byte). ! 647: BITPOS says which bit within the word or byte the bit field starts in. ! 648: OFFSET says how many bytes farther the bit field starts; ! 649: it is 0 if OP0 is a register. ! 650: BITSIZE says how many bits long the bit field is. ! 651: (If OP0 is a register, it may be narrower than SImode, ! 652: but BITPOS still counts within a full word, ! 653: which is significant on bigendian machines.) ! 654: ! 655: UNSIGNEDP is nonzero for an unsigned bit field (don't sign-extend value). ! 656: If TARGET is nonzero, attempts to store the value there ! 657: and return TARGET, but this is not guaranteed. ! 658: If TARGET is not used, create a pseudo-reg of mode TMODE for the value. */ ! 659: ! 660: static rtx ! 661: extract_fixed_bit_field (tmode, op0, offset, bitsize, bitpos, target, unsignedp) ! 662: enum machine_mode tmode; ! 663: register rtx op0, target; ! 664: register int offset, bitsize, bitpos; ! 665: int unsignedp; ! 666: { ! 667: int total_bits = BITS_PER_WORD; ! 668: enum machine_mode mode; ! 669: rtx orig = op0; ! 670: ! 671: if (GET_CODE (op0) == SUBREG || GET_CODE (op0) == REG) ! 672: { ! 673: /* Special treatment for a bit field split across two registers. */ ! 674: if (bitsize + bitpos > BITS_PER_WORD) ! 675: return extract_split_bit_field (op0, bitsize, bitpos, unsignedp); ! 676: } ! 677: else if (bitsize + bitpos <= BITS_PER_UNIT && ! SLOW_BYTE_ACCESS) ! 678: { ! 679: /* If the bit field fits entirely in one byte of memory, ! 680: let OP0 be that byte. We must add OFFSET to its address. */ ! 681: total_bits = BITS_PER_UNIT; ! 682: op0 = change_address (op0, QImode, ! 683: plus_constant (XEXP (op0, 0), offset)); ! 684: } ! 685: else ! 686: { ! 687: #ifdef STRICT_ALIGNMENT ! 688: #ifndef STRUCTURE_SIZE_BOUNDARY ! 689: /* The following code assumes that OP0 is aligned ! 690: such that a word can be fetched there. ! 691: This could be because words don't need to be aligned, ! 692: or because all structures are suitably aligned. */ ! 693: abort (); ! 694: #endif ! 695: #endif ! 696: ! 697: /* Get ref to word containing the field. */ ! 698: /* Adjust BITPOS to be position within a word, ! 699: and OFFSET to be the offset of that word. */ ! 700: bitpos += (offset % (BITS_PER_WORD / BITS_PER_UNIT)) * BITS_PER_UNIT; ! 701: offset -= (offset % (BITS_PER_WORD / BITS_PER_UNIT)); ! 702: op0 = change_address (op0, SImode, ! 703: plus_constant (XEXP (op0, 0), offset)); ! 704: ! 705: /* Special treatment for a bit field split across two words. */ ! 706: if (bitsize + bitpos > BITS_PER_WORD) ! 707: return extract_split_bit_field (op0, bitsize, bitpos, unsignedp); ! 708: } ! 709: ! 710: mode = GET_MODE (op0); ! 711: ! 712: #ifdef BYTES_BIG_ENDIAN ! 713: /* BITPOS is the distance between our msb ! 714: and that of the containing byte or word. ! 715: Convert it to the distance from the lsb. */ ! 716: ! 717: bitpos = total_bits - bitsize - bitpos; ! 718: #endif ! 719: /* Now BITPOS is always the distance between our lsb ! 720: and that of the containing byte or word. ! 721: We have reduced the big-endian case to the little-endian case. */ ! 722: ! 723: if (unsignedp) ! 724: { ! 725: if (bitpos) ! 726: { ! 727: /* If the field does not already start at the lsb, ! 728: shift it so it does. */ ! 729: tree amount = build_int_2 (bitpos, 0); ! 730: /* Maybe propagate the target for the shift. */ ! 731: /* Certainly do so if we will return the value of the shift. */ ! 732: rtx subtarget = (target != 0 && GET_CODE (target) == REG ! 733: && FUNCTION_VALUE_REGNO_P (REGNO (target)) ! 734: ? target : 0); ! 735: if (tmode != mode) subtarget = 0; ! 736: op0 = expand_shift (RSHIFT_EXPR, mode, op0, amount, subtarget, 1); ! 737: } ! 738: /* Convert the value to the desired mode. */ ! 739: if (mode != tmode) ! 740: op0 = convert_to_mode (tmode, op0, 1); ! 741: ! 742: /* Unless the msb of the field used to be the msb when we shifted, ! 743: mask out the upper bits. */ ! 744: ! 745: if ((GET_MODE_BITSIZE (mode) != bitpos + bitsize ! 746: #if 0 ! 747: #ifdef SLOW_ZERO_EXTEND ! 748: /* Always generate an `and' if ! 749: we just zero-extended op0 and SLOW_ZERO_EXTEND, since it ! 750: will combine fruitfully with the zero-extend. */ ! 751: || tmode != mode ! 752: #endif ! 753: #endif ! 754: ) ! 755: && bitsize < HOST_BITS_PER_INT) ! 756: return expand_bit_and (GET_MODE (op0), op0, ! 757: gen_rtx (CONST_INT, VOIDmode, (1 << bitsize) - 1), ! 758: target); ! 759: return op0; ! 760: } ! 761: ! 762: /* To extract a signed bit-field, first shift its msb to the msb of the word, ! 763: then arithmetic-shift its lsb to the lsb of the word. */ ! 764: op0 = force_reg (mode, op0); ! 765: if (mode != tmode) ! 766: target = 0; ! 767: if (GET_MODE_BITSIZE (QImode) < GET_MODE_BITSIZE (mode) ! 768: && GET_MODE_BITSIZE (QImode) >= bitsize + bitpos) ! 769: mode = QImode, op0 = convert_to_mode (QImode, op0, 0); ! 770: if (GET_MODE_BITSIZE (HImode) < GET_MODE_BITSIZE (mode) ! 771: && GET_MODE_BITSIZE (HImode) >= bitsize + bitpos) ! 772: mode = HImode, op0 = convert_to_mode (HImode, op0, 0); ! 773: if (GET_MODE_BITSIZE (mode) != (bitsize + bitpos)) ! 774: { ! 775: tree amount = build_int_2 (GET_MODE_BITSIZE (mode) - (bitsize + bitpos), 0); ! 776: /* Maybe propagate the target for the shift. */ ! 777: /* Certainly do so if we will return the value of the shift. */ ! 778: rtx subtarget = (target != 0 && GET_CODE (target) == REG ! 779: && FUNCTION_VALUE_REGNO_P (REGNO (target)) ! 780: ? target : 0); ! 781: op0 = expand_shift (LSHIFT_EXPR, mode, op0, amount, subtarget, 1); ! 782: } ! 783: ! 784: return expand_shift (RSHIFT_EXPR, mode, op0, ! 785: build_int_2 (GET_MODE_BITSIZE (mode) - bitsize, 0), ! 786: target, 0); ! 787: } ! 788: ! 789: /* Extract a bit field that is split across two words ! 790: and return an RTX for the result. ! 791: ! 792: OP0 is the REG, SUBREG or MEM rtx for the first of the two words. ! 793: BITSIZE is the field width; BITPOS, position of its first bit, in the word. ! 794: UNSIGNEDP is 1 if should zero-extend the contents; else sign-extend. */ ! 795: ! 796: static rtx ! 797: extract_split_bit_field (op0, bitsize, bitpos, unsignedp) ! 798: rtx op0; ! 799: int bitsize, bitpos, unsignedp; ! 800: { ! 801: /* BITSIZE_1 is size of the part in the first word. */ ! 802: int bitsize_1 = BITS_PER_WORD - bitpos; ! 803: /* BITSIZE_2 is size of the rest (in the following word). */ ! 804: int bitsize_2 = bitsize - bitsize_1; ! 805: rtx part1, part2, result; ! 806: ! 807: /* Get the part of the bit field from the first word. */ ! 808: part1 = extract_fixed_bit_field (SImode, op0, 0, bitsize_1, bitpos, 0, 1); ! 809: ! 810: /* Offset op0 by 1 word to get to the following one. */ ! 811: if (GET_CODE (op0) == MEM) ! 812: op0 = change_address (op0, SImode, ! 813: plus_constant (XEXP (op0, 0), UNITS_PER_WORD)); ! 814: else if (GET_CODE (op0) == REG) ! 815: op0 = gen_rtx (SUBREG, SImode, op0, 1); ! 816: else ! 817: op0 = gen_rtx (SUBREG, SImode, SUBREG_REG (op0), SUBREG_WORD (op0) + 1); ! 818: ! 819: /* Get the part of the bit field from the second word. */ ! 820: part2 = extract_fixed_bit_field (SImode, op0, 0, bitsize_2, 0, 0, 1); ! 821: ! 822: /* Shift the more significant part up to fit above the other part. */ ! 823: #ifdef BYTES_BIG_ENDIAN ! 824: part1 = expand_shift (LSHIFT_EXPR, SImode, part1, ! 825: build_int_2 (bitsize_2, 0), 0, 1); ! 826: #else ! 827: part2 = expand_shift (LSHIFT_EXPR, SImode, part2, ! 828: build_int_2 (bitsize_1, 0), 0, 1); ! 829: #endif ! 830: ! 831: /* Combine the two parts with bitwise or. This works ! 832: because we extracted both parts as unsigned bit fields. */ ! 833: result = expand_binop (SImode, ior_optab, part1, part2, 0, 1, ! 834: OPTAB_LIB_WIDEN); ! 835: ! 836: /* Unsigned bit field: we are done. */ ! 837: if (unsignedp) ! 838: return result; ! 839: /* Signed bit field: sign-extend with two arithmetic shifts. */ ! 840: result = expand_shift (LSHIFT_EXPR, SImode, result, ! 841: build_int_2 (BITS_PER_WORD - bitsize, 0), 0, 0); ! 842: return expand_shift (RSHIFT_EXPR, SImode, result, ! 843: build_int_2 (BITS_PER_WORD - bitsize, 0), 0, 0); ! 844: } ! 845: ! 846: /* Add INC into TARGET. */ ! 847: ! 848: void ! 849: expand_inc (target, inc) ! 850: rtx target, inc; ! 851: { ! 852: rtx value = expand_binop (GET_MODE (target), add_optab, ! 853: target, inc, ! 854: target, 0, OPTAB_LIB_WIDEN); ! 855: if (value != target) ! 856: emit_move_insn (target, value); ! 857: } ! 858: ! 859: /* Subtract INC from TARGET. */ ! 860: ! 861: void ! 862: expand_dec (target, dec) ! 863: rtx target, dec; ! 864: { ! 865: rtx value = expand_binop (GET_MODE (target), sub_optab, ! 866: target, dec, ! 867: target, 0, OPTAB_LIB_WIDEN); ! 868: if (value != target) ! 869: emit_move_insn (target, value); ! 870: } ! 871: ! 872: /* Output a shift instruction for expression code CODE, ! 873: with SHIFTED being the rtx for the value to shift, ! 874: and AMOUNT the tree for the amount to shift by. ! 875: Store the result in the rtx TARGET, if that is convenient. ! 876: If UNSIGNEDP is nonzero, do a logical shift; otherwise, arithmetic. ! 877: Return the rtx for where the value is. */ ! 878: ! 879: /* Pastel, for shifts, converts shift count to SImode here ! 880: independent of the mode being shifted. ! 881: Should that be done in an earlier pass? ! 882: It turns out not to matter for C. */ ! 883: ! 884: rtx ! 885: expand_shift (code, mode, shifted, amount, target, unsignedp) ! 886: enum tree_code code; ! 887: register enum machine_mode mode; ! 888: rtx shifted; ! 889: tree amount; ! 890: register rtx target; ! 891: int unsignedp; ! 892: { ! 893: register rtx op1, temp = 0; ! 894: register int left = (code == LSHIFT_EXPR || code == LROTATE_EXPR); ! 895: int try; ! 896: rtx negated = 0; ! 897: int rotate = code == LROTATE_EXPR || code == RROTATE_EXPR; ! 898: ! 899: /* Previously detected shift-counts computed by NEGATE_EXPR ! 900: and shifted in the other direction; but that does not work ! 901: on all machines. */ ! 902: ! 903: op1 = expand_expr (amount, 0, VOIDmode, 0); ! 904: ! 905: for (try = 0; temp == 0 && try < 3; try++) ! 906: { ! 907: enum optab_methods methods; ! 908: if (try == 0) ! 909: methods = OPTAB_DIRECT; ! 910: else if (try == 1) ! 911: methods = OPTAB_WIDEN; ! 912: else ! 913: methods = OPTAB_LIB_WIDEN; ! 914: ! 915: if (rotate) ! 916: { ! 917: /* Widening does not work for rotation. */ ! 918: if (methods != OPTAB_DIRECT) ! 919: methods = OPTAB_LIB; ! 920: ! 921: temp = expand_binop (mode, ! 922: left ? rotl_optab : rotr_optab, ! 923: shifted, op1, target, -1, methods); ! 924: /* If there is no shift instruction for the desired direction, ! 925: try negating the shift count and shifting in the other direction. ! 926: If a machine has only a left shift instruction then we are ! 927: entitled to assume it shifts right with negative args. */ ! 928: if (temp == 0) ! 929: { ! 930: if (negated != 0) ! 931: ; ! 932: else if (GET_CODE (op1) == CONST_INT) ! 933: negated = gen_rtx (CONST_INT, VOIDmode, -INTVAL (op1)); ! 934: else ! 935: negated = expand_unop (mode, neg_optab, op1, 0, 0); ! 936: temp = expand_binop (mode, ! 937: left ? rotr_optab : rotl_optab, ! 938: shifted, negated, target, -1, methods); ! 939: } ! 940: } ! 941: else if (unsignedp) ! 942: { ! 943: temp = expand_binop (mode, ! 944: left ? lshl_optab : lshr_optab, ! 945: shifted, op1, target, unsignedp, methods); ! 946: if (temp == 0 && left) ! 947: temp = expand_binop (mode, ashl_optab, ! 948: shifted, op1, target, unsignedp, methods); ! 949: if (temp == 0) ! 950: { ! 951: if (negated != 0) ! 952: ; ! 953: else if (GET_CODE (op1) == CONST_INT) ! 954: negated = gen_rtx (CONST_INT, VOIDmode, -INTVAL (op1)); ! 955: else ! 956: negated = expand_unop (mode, neg_optab, op1, 0, 0); ! 957: temp = expand_binop (mode, ! 958: left ? lshr_optab : lshl_optab, ! 959: shifted, negated, ! 960: target, unsignedp, methods); ! 961: } ! 962: ! 963: if (temp != 0) ! 964: return temp; ! 965: } ! 966: /* Do arithmetic shifts. ! 967: Also, if we are going to widen the operand, we can just as well ! 968: use an arithmetic right-shift instead of a logical one. */ ! 969: if (! rotate && (! unsignedp || (! left && methods == OPTAB_WIDEN))) ! 970: { ! 971: /* Arithmetic shift */ ! 972: ! 973: temp = expand_binop (mode, ! 974: left ? ashl_optab : ashr_optab, ! 975: shifted, op1, target, unsignedp, methods); ! 976: if (temp == 0) ! 977: { ! 978: if (negated != 0) ! 979: ; ! 980: else if (GET_CODE (op1) == CONST_INT) ! 981: negated = gen_rtx (CONST_INT, VOIDmode, -INTVAL (op1)); ! 982: else ! 983: negated = expand_unop (mode, neg_optab, op1, 0, 0); ! 984: temp = expand_binop (mode, ! 985: left ? ashr_optab : ashl_optab, ! 986: shifted, negated, target, unsignedp, methods); ! 987: } ! 988: if (temp != 0) ! 989: return temp; ! 990: } ! 991: ! 992: if (unsignedp) ! 993: { ! 994: /* No logical shift insn in either direction => ! 995: try a bit-field extract instruction if we have one. */ ! 996: #ifdef HAVE_extzv ! 997: #ifndef BITS_BIG_ENDIAN ! 998: if (HAVE_extzv && !left ! 999: && ((methods == OPTAB_DIRECT && mode == SImode) ! 1000: || (methods == OPTAB_WIDEN ! 1001: && GET_MODE_SIZE (mode) < GET_MODE_SIZE (SImode)))) ! 1002: { ! 1003: rtx shifted1 = convert_to_mode (SImode, shifted, 1); ! 1004: rtx target1 = target; ! 1005: ! 1006: /* If -fforce-mem, don't let the operand be in memory. */ ! 1007: if (flag_force_mem && GET_CODE (shifted1) == MEM) ! 1008: shifted1 = force_not_mem (shifted1); ! 1009: ! 1010: /* If this machine's extzv insists on a register for ! 1011: operand 1, arrange for that. */ ! 1012: if (! ((*insn_operand_predicate[(int) CODE_FOR_extzv][1]) ! 1013: (shifted1, SImode))) ! 1014: shifted1 = force_reg (SImode, shifted1); ! 1015: ! 1016: /* If we don't have or cannot use a suggested target, ! 1017: make a place for the result, in the proper mode. */ ! 1018: if (methods == OPTAB_WIDEN || target1 == 0 ! 1019: || ! ((*insn_operand_predicate[(int) CODE_FOR_extzv][0]) ! 1020: (target1, SImode))) ! 1021: target1 = gen_reg_rtx (SImode); ! 1022: ! 1023: /* If this machine's extzv insists on a register for ! 1024: operand 3, arrange for that. */ ! 1025: if (! ((*insn_operand_predicate[(int) CODE_FOR_extzv][3]) ! 1026: (op1, SImode))) ! 1027: op1 = force_reg (SImode, op1); ! 1028: ! 1029: op1 = protect_from_queue (op1, 1); ! 1030: ! 1031: /* TEMP gets the width of the bit field to extract: ! 1032: wordsize minus # bits to shift by. */ ! 1033: if (GET_CODE (op1) == CONST_INT) ! 1034: temp = gen_rtx (CONST_INT, VOIDmode, ! 1035: (GET_MODE_BITSIZE (mode) - INTVAL (op1))); ! 1036: else ! 1037: temp = expand_binop (SImode, sub_optab, ! 1038: gen_rtx (CONST_INT, VOIDmode, ! 1039: GET_MODE_BITSIZE (mode)), ! 1040: op1, gen_reg_rtx (SImode), ! 1041: 0, OPTAB_LIB_WIDEN); ! 1042: /* Now extract with width TEMP, omitting OP1 least sig bits. */ ! 1043: emit_insn (gen_extzv (protect_from_queue (target1, 1), ! 1044: protect_from_queue (shifted1, 0), ! 1045: temp, op1)); ! 1046: return convert_to_mode (mode, target1, 1); ! 1047: } ! 1048: /* Can also do logical shift with signed bit-field extract ! 1049: followed by inserting the bit-field at a different position. ! 1050: That strategy is not yet implemented. */ ! 1051: #endif /* not BITS_BIG_ENDIAN */ ! 1052: #endif /* HAVE_extzv */ ! 1053: /* We have failed to generate the logical shift and will abort. */ ! 1054: } ! 1055: } ! 1056: if (temp == 0) ! 1057: abort (); ! 1058: return temp; ! 1059: } ! 1060: ! 1061: /* Output an instruction or two to bitwise-and OP0 with OP1 ! 1062: in mode MODE, with output to TARGET if convenient and TARGET is not zero. ! 1063: Returns where the result is. */ ! 1064: ! 1065: rtx ! 1066: expand_bit_and (mode, op0, op1, target) ! 1067: enum machine_mode mode; ! 1068: rtx op0, op1, target; ! 1069: { ! 1070: register rtx temp; ! 1071: ! 1072: /* First try to open-code it directly. */ ! 1073: temp = expand_binop (mode, and_optab, op0, op1, target, 1, OPTAB_DIRECT); ! 1074: if (temp == 0) ! 1075: { ! 1076: rtx compl; ! 1077: /* If that fails, try to open code using a clear-bits insn. */ ! 1078: if (GET_CODE (op1) == CONST_INT ! 1079: && GET_MODE_BITSIZE (mode) < HOST_BITS_PER_INT) ! 1080: compl = gen_rtx (CONST_INT, VOIDmode, ! 1081: ((1 << GET_MODE_BITSIZE (mode)) - 1) & ~INTVAL (op1)); ! 1082: else ! 1083: compl = expand_unop (mode, one_cmpl_optab, op1, 0, 1); ! 1084: temp = expand_binop (mode, andcb_optab, op0, compl, target, ! 1085: 1, OPTAB_DIRECT); ! 1086: } ! 1087: if (temp == 0) ! 1088: /* If still no luck, try library call or wider modes. */ ! 1089: temp = expand_binop (mode, and_optab, op0, op1, target, ! 1090: 1, OPTAB_LIB_WIDEN); ! 1091: ! 1092: if (temp == 0) ! 1093: abort (); ! 1094: return temp; ! 1095: } ! 1096: ! 1097: /* Perform a multiplication and return an rtx for the result. ! 1098: MODE is mode of value; OP0 and OP1 are what to multiply (rtx's); ! 1099: TARGET is a suggestion for where to store the result (an rtx). ! 1100: ! 1101: We check specially for a constant integer as OP1. ! 1102: If you want this check for OP0 as well, then before calling ! 1103: you should swap the two operands if OP0 would be constant. */ ! 1104: ! 1105: rtx ! 1106: expand_mult (mode, op0, op1, target, unsignedp) ! 1107: enum machine_mode mode; ! 1108: register rtx op0, op1, target; ! 1109: int unsignedp; ! 1110: { ! 1111: /* Don't use the function value register as a target ! 1112: since we have to read it as well as write it, ! 1113: and function-inlining gets confused by this. */ ! 1114: if (target && REG_P (target) && FUNCTION_VALUE_REGNO_P (REGNO (target))) ! 1115: target = 0; ! 1116: ! 1117: if (GET_CODE (op1) == CONST_INT) ! 1118: { ! 1119: register int foo; ! 1120: int bar; ! 1121: int negate = INTVAL (op1) < 0; ! 1122: int absval = INTVAL (op1) * (negate ? -1 : 1); ! 1123: ! 1124: /* Is multiplier a power of 2, or minus that? */ ! 1125: foo = exact_log2 (absval); ! 1126: if (foo >= 0) ! 1127: { ! 1128: rtx tem = expand_shift (LSHIFT_EXPR, mode, op0, ! 1129: build_int_2 (foo, 0), ! 1130: target, 0); ! 1131: return negate ? negate_rtx (tem) : tem; ! 1132: } ! 1133: /* Is multiplier a sum of two powers of 2, or minus that? */ ! 1134: bar = floor_log2 (absval); ! 1135: foo = exact_log2 (absval - (1 << bar)); ! 1136: if (bar >= 0 && foo >= 0) ! 1137: { ! 1138: rtx pow1 = ((foo == 0) ? op0 ! 1139: : expand_shift (LSHIFT_EXPR, mode, op0, ! 1140: build_int_2 (foo, 0), ! 1141: 0, 0)); ! 1142: rtx pow2 = expand_shift (LSHIFT_EXPR, mode, op0, ! 1143: build_int_2 (bar, 0), ! 1144: 0, 0); ! 1145: rtx tem = force_operand (gen_rtx (PLUS, mode, pow1, pow2), target); ! 1146: return negate ? negate_rtx (tem) : tem; ! 1147: } ! 1148: } ! 1149: /* This used to use umul_optab if unsigned, ! 1150: but I think that for non-widening multiply there is no difference ! 1151: between signed and unsigned. */ ! 1152: op0 = expand_binop (mode, smul_optab, ! 1153: op0, op1, target, unsignedp, OPTAB_LIB_WIDEN); ! 1154: if (op0 == 0) ! 1155: abort (); ! 1156: return op0; ! 1157: } ! 1158: ! 1159: /* Emit the code to divide OP0 by OP1, putting the result in TARGET ! 1160: if that is convenient, and returning where the result is. ! 1161: You may request either the quotient or the remainder as the result; ! 1162: specify REM_FLAG nonzero to get the remainder. ! 1163: ! 1164: CODE is the expression code for which kind of division this is; ! 1165: it controls how rounding is done. MODE is the machine mode to use. ! 1166: UNSIGNEDP nonzero means do unsigned division. */ ! 1167: ! 1168: /* ??? For CEIL_MOD_EXPR, can compute incorrect remainder with ANDI ! 1169: and then correct it by or'ing in missing high bits ! 1170: if result of ANDI is nonzero. ! 1171: For ROUND_MOD_EXPR, can use ANDI and then sign-extend the result. ! 1172: This could optimize to a bfexts instruction. ! 1173: But C doesn't use these operations, so their optimizations are ! 1174: left for later. */ ! 1175: ! 1176: rtx ! 1177: expand_divmod (rem_flag, code, mode, op0, op1, target, unsignedp) ! 1178: int rem_flag; ! 1179: enum tree_code code; ! 1180: enum machine_mode mode; ! 1181: register rtx op0, op1, target; ! 1182: int unsignedp; ! 1183: { ! 1184: register rtx label; ! 1185: register rtx temp; ! 1186: int log = -1; ! 1187: int can_clobber_op0; ! 1188: int mod_insn_no_good = 0; ! 1189: rtx adjusted_op0 = op0; ! 1190: ! 1191: /* Don't use the function value register as a target ! 1192: since we have to read it as well as write it, ! 1193: and function-inlining gets confused by this. */ ! 1194: if (target && REG_P (target) && FUNCTION_VALUE_REGNO_P (REGNO (target))) ! 1195: target = 0; ! 1196: ! 1197: if (target == 0) ! 1198: { ! 1199: target = gen_reg_rtx (mode); ! 1200: } ! 1201: ! 1202: /* Don't clobber an operand while doing a multi-step calculation. */ ! 1203: if ((rem_flag && rtx_equal_p (target, op0)) ! 1204: || rtx_equal_p (target, op1)) ! 1205: target = gen_reg_rtx (mode); ! 1206: ! 1207: can_clobber_op0 = (GET_CODE (op0) == REG && op0 == target); ! 1208: ! 1209: if (GET_CODE (op1) == CONST_INT) ! 1210: log = exact_log2 (INTVAL (op1)); ! 1211: ! 1212: /* If log is >= 0, we are dividing by 2**log, and will do it by shifting, ! 1213: which is really floor-division. Otherwise we will really do a divide, ! 1214: and we assume that is trunc-division. ! 1215: ! 1216: We must correct the dividend by adding or subtracting something ! 1217: based on the divisor, in order to do the kind of rounding specified ! 1218: by CODE. The correction depends on what kind of rounding is actually ! 1219: available, and that depends on whether we will shift or divide. */ ! 1220: ! 1221: switch (code) ! 1222: { ! 1223: case TRUNC_MOD_EXPR: ! 1224: case TRUNC_DIV_EXPR: ! 1225: if (log >= 0 && ! unsignedp) ! 1226: { ! 1227: label = gen_label_rtx (); ! 1228: if (! can_clobber_op0) ! 1229: adjusted_op0 = copy_to_suggested_reg (adjusted_op0, target); ! 1230: emit_cmp_insn (adjusted_op0, const0_rtx, 0, 0); ! 1231: emit_jump_insn (gen_bge (label)); ! 1232: expand_inc (adjusted_op0, plus_constant (op1, -1)); ! 1233: emit_label (label); ! 1234: mod_insn_no_good = 1; ! 1235: } ! 1236: break; ! 1237: ! 1238: case FLOOR_DIV_EXPR: ! 1239: case FLOOR_MOD_EXPR: ! 1240: if (log < 0 && ! unsignedp) ! 1241: { ! 1242: label = gen_label_rtx (); ! 1243: if (! can_clobber_op0) ! 1244: adjusted_op0 = copy_to_suggested_reg (adjusted_op0, target); ! 1245: emit_cmp_insn (adjusted_op0, const0_rtx, 0, 0); ! 1246: emit_jump_insn (gen_bge (label)); ! 1247: expand_dec (adjusted_op0, op1); ! 1248: expand_inc (adjusted_op0, const1_rtx); ! 1249: emit_label (label); ! 1250: mod_insn_no_good = 1; ! 1251: } ! 1252: break; ! 1253: ! 1254: case CEIL_DIV_EXPR: ! 1255: case CEIL_MOD_EXPR: ! 1256: if (! can_clobber_op0) ! 1257: adjusted_op0 = copy_to_suggested_reg (adjusted_op0, target); ! 1258: if (log < 0) ! 1259: { ! 1260: if (! unsignedp) ! 1261: { ! 1262: label = gen_label_rtx (); ! 1263: emit_cmp_insn (adjusted_op0, const0_rtx, 0, 0); ! 1264: emit_jump_insn (gen_ble (label)); ! 1265: } ! 1266: expand_inc (adjusted_op0, op1); ! 1267: expand_dec (adjusted_op0, const1_rtx); ! 1268: if (! unsignedp) ! 1269: emit_label (label); ! 1270: } ! 1271: else ! 1272: { ! 1273: adjusted_op0 = expand_binop (GET_MODE (target), add_optab, ! 1274: adjusted_op0, plus_constant (op1, -1), ! 1275: 0, 0, OPTAB_LIB_WIDEN); ! 1276: } ! 1277: mod_insn_no_good = 1; ! 1278: break; ! 1279: ! 1280: case ROUND_DIV_EXPR: ! 1281: case ROUND_MOD_EXPR: ! 1282: if (! can_clobber_op0) ! 1283: adjusted_op0 = copy_to_suggested_reg (adjusted_op0, target); ! 1284: if (log < 0) ! 1285: { ! 1286: op1 = expand_shift (RSHIFT_EXPR, mode, op1, integer_one_node, 0, 0); ! 1287: if (! unsignedp) ! 1288: { ! 1289: label = gen_label_rtx (); ! 1290: emit_cmp_insn (adjusted_op0, const0_rtx, 0, 0); ! 1291: emit_jump_insn (gen_bge (label)); ! 1292: expand_unop (mode, neg_optab, op1, op1, 0); ! 1293: emit_label (label); ! 1294: } ! 1295: expand_inc (adjusted_op0, op1); ! 1296: } ! 1297: else ! 1298: { ! 1299: op1 = gen_rtx (CONST_INT, VOIDmode, INTVAL (op1) / 2); ! 1300: expand_inc (adjusted_op0, op1); ! 1301: } ! 1302: mod_insn_no_good = 1; ! 1303: break; ! 1304: } ! 1305: ! 1306: if (rem_flag && !mod_insn_no_good) ! 1307: { ! 1308: /* Try to produce the remainder directly */ ! 1309: if (log >= 0) ! 1310: { ! 1311: return expand_bit_and (mode, adjusted_op0, ! 1312: gen_rtx (CONST_INT, VOIDmode, ! 1313: INTVAL (op1) - 1), ! 1314: target); ! 1315: } ! 1316: else ! 1317: { ! 1318: /* See if we can do remainder without a library call. */ ! 1319: temp = expand_binop (mode, ! 1320: unsignedp ? umod_optab : smod_optab, ! 1321: adjusted_op0, op1, target, ! 1322: unsignedp, OPTAB_WIDEN); ! 1323: if (temp != 0) ! 1324: return temp; ! 1325: /* No luck there. ! 1326: Can we do remainder and divide at once without a library call? */ ! 1327: temp = gen_reg_rtx (mode); ! 1328: if (expand_twoval_binop (unsignedp ? udivmod_optab : sdivmod_optab, ! 1329: adjusted_op0, op1, ! 1330: 0, temp, unsignedp)) ! 1331: return temp; ! 1332: temp = 0; ! 1333: } ! 1334: } ! 1335: ! 1336: /* Produce the quotient. */ ! 1337: if (log >= 0) ! 1338: temp = expand_shift (RSHIFT_EXPR, mode, adjusted_op0, ! 1339: build_int_2 (exact_log2 (INTVAL (op1)), 0), ! 1340: target, unsignedp); ! 1341: else if (rem_flag && !mod_insn_no_good) ! 1342: /* If producing quotient in order to subtract for remainder, ! 1343: and a remainder subroutine would be ok, ! 1344: don't use a divide subroutine. */ ! 1345: temp = expand_binop (mode, unsignedp ? udiv_optab : sdiv_optab, ! 1346: adjusted_op0, op1, target, ! 1347: unsignedp, OPTAB_WIDEN); ! 1348: else ! 1349: temp = expand_binop (mode, unsignedp ? udiv_optab : sdiv_optab, ! 1350: adjusted_op0, op1, target, ! 1351: unsignedp, OPTAB_LIB_WIDEN); ! 1352: ! 1353: /* If we really want the remainder, get it by subtraction. */ ! 1354: if (rem_flag) ! 1355: { ! 1356: if (temp == 0) ! 1357: { ! 1358: /* No divide instruction either. Use library for remainder. */ ! 1359: temp = expand_binop (mode, ! 1360: unsignedp ? umod_optab : smod_optab, ! 1361: op0, op1, target, ! 1362: unsignedp, OPTAB_LIB_WIDEN); ! 1363: } ! 1364: else ! 1365: { ! 1366: /* We divided. Now finish doing X - Y * (X / Y). */ ! 1367: temp = expand_mult (mode, temp, op1, temp, unsignedp); ! 1368: if (! temp) abort (); ! 1369: temp = expand_binop (mode, sub_optab, op0, ! 1370: temp, target, unsignedp, OPTAB_LIB_WIDEN); ! 1371: } ! 1372: } ! 1373: ! 1374: if (temp == 0) ! 1375: abort (); ! 1376: return temp; ! 1377: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.