📄 expmed.c
字号:
else if (!CONSTANT_P (value)) /* Parse phase is supposed to make VALUE's data type match that of the component reference, which is a type at least as wide as the field; so VALUE should have a mode that corresponds to that type. */ abort (); } /* If this machine's insv insists on a register, get VALUE1 into a register. */ if (! ((*insn_operand_predicate[(int) CODE_FOR_insv][3]) (value1, maxmode))) value1 = force_reg (maxmode, value1); pat = gen_insv (xop0, GEN_INT (bitsize), GEN_INT (xbitpos), value1); if (pat) emit_insn (pat); else { delete_insns_since (last); store_fixed_bit_field (op0, offset, bitsize, bitpos, value, align); } } else insv_loses:#endif /* Insv is not available; store using shifts and boolean ops. */ store_fixed_bit_field (op0, offset, bitsize, bitpos, value, align); return value;}/* Use shifts and boolean operations to store VALUE into a bit field of width BITSIZE in a memory location specified by OP0 except offset by OFFSET bytes. (OFFSET must be 0 if OP0 is a register.) The field starts at position BITPOS within the byte. (If OP0 is a register, it may be a full word or a narrower mode, but BITPOS still counts within a full word, which is significant on bigendian machines.) STRUCT_ALIGN is the alignment the structure is known to have (in bytes). Note that protect_from_queue has already been done on OP0 and VALUE. */static voidstore_fixed_bit_field (op0, offset, bitsize, bitpos, value, struct_align) register rtx op0; register int offset, bitsize, bitpos; register rtx value; int struct_align;{ register enum machine_mode mode; int total_bits = BITS_PER_WORD; rtx subtarget, temp; int all_zero = 0; int all_one = 0; /* Add OFFSET to OP0's address (if it is in memory) and if a single byte contains the whole bit field change OP0 to a byte. */ /* There is a case not handled here: a structure with a known alignment of just a halfword and a field split across two aligned halfwords within the structure. Or likewise a structure with a known alignment of just a byte and a field split across two bytes. Such cases are not supposed to be able to occur. */ if (GET_CODE (op0) == REG || GET_CODE (op0) == SUBREG) { if (offset != 0) abort (); /* Special treatment for a bit field split across two registers. */ if (bitsize + bitpos > BITS_PER_WORD) { store_split_bit_field (op0, bitsize, bitpos, value, BITS_PER_WORD); return; } } else { /* Get the proper mode to use for this field. We want a mode that includes the entire field. If such a mode would be larger than a word, we won't be doing the extraction the normal way. */ mode = get_best_mode (bitsize, bitpos + offset * BITS_PER_UNIT, struct_align * BITS_PER_UNIT, word_mode, GET_CODE (op0) == MEM && MEM_VOLATILE_P (op0)); if (mode == VOIDmode) { /* The only way this should occur is if the field spans word boundaries. */ store_split_bit_field (op0, bitsize, bitpos + offset * BITS_PER_UNIT, value, struct_align); return; } total_bits = GET_MODE_BITSIZE (mode); /* Get ref to an aligned byte, halfword, or word containing the field. Adjust BITPOS to be position within a word, and OFFSET to be the offset of that word. Then alter OP0 to refer to that word. */ bitpos += (offset % (total_bits / BITS_PER_UNIT)) * BITS_PER_UNIT; offset -= (offset % (total_bits / BITS_PER_UNIT)); op0 = change_address (op0, mode, plus_constant (XEXP (op0, 0), offset)); } mode = GET_MODE (op0); /* Now MODE is either some integral mode for a MEM as OP0, or is a full-word for a REG as OP0. TOTAL_BITS corresponds. The bit field is contained entirely within OP0. BITPOS is the starting bit number within OP0. (OP0's mode may actually be narrower than MODE.) */#if BYTES_BIG_ENDIAN /* BITPOS is the distance between our msb and that of the containing datum. Convert it to the distance from the lsb. */ bitpos = total_bits - bitsize - bitpos;#endif /* Now BITPOS is always the distance between our lsb and that of OP0. */ /* Shift VALUE left by BITPOS bits. If VALUE is not constant, we must first convert its mode to MODE. */ if (GET_CODE (value) == CONST_INT) { register HOST_WIDE_INT v = INTVAL (value); if (bitsize < HOST_BITS_PER_WIDE_INT) v &= ((HOST_WIDE_INT) 1 << bitsize) - 1; if (v == 0) all_zero = 1; else if ((bitsize < HOST_BITS_PER_WIDE_INT && v == ((HOST_WIDE_INT) 1 << bitsize) - 1) || (bitsize == HOST_BITS_PER_WIDE_INT && v == -1)) all_one = 1; value = lshift_value (mode, value, bitpos, bitsize); } else { int must_and = (GET_MODE_BITSIZE (GET_MODE (value)) != bitsize && bitpos + bitsize != GET_MODE_BITSIZE (mode)); if (GET_MODE (value) != mode) { /* If VALUE is a floating-point mode, access it as an integer of the corresponding size, then convert it. This can occur on a machine with 64 bit registers that uses SFmode for float. */ if (GET_MODE_CLASS (GET_MODE (value)) == MODE_FLOAT) { if (GET_CODE (value) != REG) value = copy_to_reg (value); value = gen_rtx (SUBREG, word_mode, value, 0); } if ((GET_CODE (value) == REG || GET_CODE (value) == SUBREG) && GET_MODE_SIZE (mode) < GET_MODE_SIZE (GET_MODE (value))) value = gen_lowpart (mode, value); else value = convert_to_mode (mode, value, 1); } if (must_and) value = expand_binop (mode, and_optab, value, mask_rtx (mode, 0, bitsize, 0), NULL_RTX, 1, OPTAB_LIB_WIDEN); if (bitpos > 0) value = expand_shift (LSHIFT_EXPR, mode, value, build_int_2 (bitpos, 0), NULL_RTX, 1); } /* Now clear the chosen bits in OP0, except that if VALUE is -1 we need not bother. */ subtarget = (GET_CODE (op0) == REG || ! flag_force_mem) ? op0 : 0; if (! all_one) { temp = expand_binop (mode, and_optab, op0, mask_rtx (mode, bitpos, bitsize, 1), subtarget, 1, OPTAB_LIB_WIDEN); subtarget = temp; } else temp = op0; /* Now logical-or VALUE into OP0, unless it is zero. */ if (! all_zero) temp = expand_binop (mode, ior_optab, temp, value, subtarget, 1, OPTAB_LIB_WIDEN); if (op0 != temp) emit_move_insn (op0, temp);}/* Store a bit field that is split across two words. OP0 is the REG, SUBREG or MEM rtx for the first of the two words. BITSIZE is the field width; BITPOS the position of its first bit (within the word). VALUE is the value to store. */static voidstore_split_bit_field (op0, bitsize, bitpos, value, align) rtx op0; int bitsize, bitpos; rtx value; int align;{ /* BITSIZE_1 is size of the part in the first word. */ int bitsize_1 = BITS_PER_WORD - bitpos % BITS_PER_WORD; /* BITSIZE_2 is size of the rest (in the following word). */ int bitsize_2 = bitsize - bitsize_1; rtx part1, part2; int unit = GET_CODE (op0) == MEM ? BITS_PER_UNIT : BITS_PER_WORD; int offset = bitpos / unit; rtx word; /* The field must span exactly one word boundary. */ if (bitpos / BITS_PER_WORD != (bitpos + bitsize - 1) / BITS_PER_WORD - 1) abort (); if (GET_MODE (value) != VOIDmode) value = convert_to_mode (word_mode, value, 1); if (CONSTANT_P (value) && GET_CODE (value) != CONST_INT) value = copy_to_reg (value); /* Split the value into two parts: PART1 gets that which goes in the first word; PART2 the other. */#if BYTES_BIG_ENDIAN /* PART1 gets the more significant part. */ if (GET_CODE (value) == CONST_INT) { part1 = GEN_INT ((unsigned HOST_WIDE_INT) (INTVAL (value)) >> bitsize_2); part2 = GEN_INT ((unsigned HOST_WIDE_INT) (INTVAL (value)) & (((HOST_WIDE_INT) 1 << bitsize_2) - 1)); } else { part1 = extract_fixed_bit_field (word_mode, value, 0, bitsize_1, BITS_PER_WORD - bitsize, NULL_RTX, 1, BITS_PER_WORD); part2 = extract_fixed_bit_field (word_mode, value, 0, bitsize_2, BITS_PER_WORD - bitsize_2, NULL_RTX, 1, BITS_PER_WORD); }#else /* PART1 gets the less significant part. */ if (GET_CODE (value) == CONST_INT) { part1 = GEN_INT ((unsigned HOST_WIDE_INT) (INTVAL (value)) & (((HOST_WIDE_INT) 1 << bitsize_1) - 1)); part2 = GEN_INT ((unsigned HOST_WIDE_INT) (INTVAL (value)) >> bitsize_1); } else { part1 = extract_fixed_bit_field (word_mode, value, 0, bitsize_1, 0, NULL_RTX, 1, BITS_PER_WORD); part2 = extract_fixed_bit_field (word_mode, value, 0, bitsize_2, bitsize_1, NULL_RTX, 1, BITS_PER_WORD); }#endif /* Store PART1 into the first word. If OP0 is a MEM, pass OP0 and the offset computed above. Otherwise, get the proper word and pass an offset of zero. */ word = (GET_CODE (op0) == MEM ? op0 : operand_subword (op0, offset, 1, GET_MODE (op0))); if (word == 0) abort (); store_fixed_bit_field (word, GET_CODE (op0) == MEM ? offset : 0, bitsize_1, bitpos % unit, part1, align); /* Offset op0 by 1 word to get to the following one. */ if (GET_CODE (op0) == SUBREG) word = operand_subword (SUBREG_REG (op0), SUBREG_WORD (op0) + offset + 1, 1, VOIDmode); else if (GET_CODE (op0) == MEM) word = op0; else word = operand_subword (op0, offset + 1, 1, GET_MODE (op0)); if (word == 0) abort (); /* Store PART2 into the second word. */ store_fixed_bit_field (word, (GET_CODE (op0) == MEM ? CEIL (offset + 1, UNITS_PER_WORD) * UNITS_PER_WORD : 0), bitsize_2, 0, part2, align);}/* Generate code to extract a byte-field from STR_RTX containing BITSIZE bits, starting at BITNUM, and put it in TARGET if possible (if TARGET is nonzero). Regardless of TARGET, we return the rtx for where the value is placed. It may be a QUEUED. STR_RTX is the structure containing the byte (a REG or MEM). UNSIGNEDP is nonzero if this is an unsigned bit field. MODE is the natural mode of the field value once extracted. TMODE is the mode the caller would like the value to have; but the value may be returned with type MODE instead. ALIGN is the alignment that STR_RTX is known to have, measured in bytes. TOTAL_SIZE is the size in bytes of the containing structure, or -1 if varying. If a TARGET is specified and we can store in it at no extra cost, we do so, and return TARGET. Otherwise, we return a REG of mode TMODE or MODE, with TMODE preferred if they are equally easy. */rtxextract_bit_field (str_rtx, bitsize, bitnum, unsignedp, target, mode, tmode, align, total_size) rtx str_rtx; register int bitsize; int bitnum; int unsignedp; rtx target; enum machine_mode mode, tmode; int align; int total_size;{ int unit = (GET_CODE (str_rtx) == MEM) ? BITS_PER_UNIT : BITS_PER_WORD; register int offset = bitnum / unit; register int bitpos = bitnum % unit; register rtx op0 = str_rtx; rtx spec_target = target; rtx spec_target_subreg = 0; if (GET_CODE (str_rtx) == MEM && ! MEM_IN_STRUCT_P (str_rtx)) abort (); /* Discount the part of the structure before the desired byte. We need to know how many bytes are safe to reference after it. */ if (total_size >= 0) total_size -= (bitpos / BIGGEST_ALIGNMENT * (BIGGEST_ALIGNMENT / BITS_PER_UNIT)); if (tmode == VOIDmode) tmode = mode; while (GET_CODE (op0) == SUBREG) { offset += SUBREG_WORD (op0); op0 = SUBREG_REG (op0); } #if BYTES_BIG_ENDIAN /* If OP0 is a register, BITPOS must count within a word. But as we have it, it counts within whatever size OP0 now has. On a bigendian machine, these are not the same, so convert. */ if (GET_CODE (op0) != MEM && unit > GET_MODE_BITSIZE (GET_MODE (op0))) bitpos += unit - GET_MODE_BITSIZE (GET_MODE (op0));#endif /* Extracting a full-word or multi-word value from a structure in a register. This can be done with just SUBREG. So too extracting a subword value in the least significant part of the register. */ if (GET_CODE (op0) == REG && ((bitsize >= BITS_PER_WORD && bitsize == GET_MODE_BITSIZE (mode) && bitpos % BITS_PER_WORD == 0) || (mode_for_size (bitsize, GET_MODE_CLASS (tmode), 0) != BLKmode#if BYTES_BIG_ENDIAN && bitpos + bitsize == BITS_PER_WORD#else && bitpos == 0#endif ))) { enum machine_mode mode1 = mode_for_size (bitsize, GET_MODE_CLASS (tmode), 0); if (mode1 != GET_MODE (op0)) op0 = gen_rtx (SUBREG, mode1, op0, offset); if (mode1 != mode) return convert_to_mode (tmode, op0, unsignedp); return op0; } /* Handle fields bigger than a word. */ if (bitsize > BITS_PER_WORD) { /* Here we transfer the words of the field in the order least significant first. This is because the most significant word is the one which may be less than full. */ int nwords = (bitsize + (BITS_PER_WORD - 1)) / BITS_PER_WORD; int i; if (target == 0 || GET_CODE (target) != REG) target = gen_reg_rtx (mode); for (i = 0; i < nwords; i++) { /* If I is 0, use the low-order word in both field and target; if I is 1, use the next to lowest word; and so on. */ int wordnum = (WORDS_BIG_ENDIAN ? nwords - i - 1 : i); int bit_offset = (WORDS_BIG_ENDIAN
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -