📄 expr.c
字号:
/* Don't crash if the lhs of the assignment was erroneous. */ if (TREE_CODE (to) == ERROR_MARK) return expand_expr (from, 0, VOIDmode, 0); /* Assignment of a structure component needs special treatment if the structure component's rtx is not simply a MEM. Assignment of an array element at a constant index has the same problem. */ if (TREE_CODE (to) == COMPONENT_REF || (TREE_CODE (to) == ARRAY_REF && TREE_CODE (TREE_OPERAND (to, 1)) == INTEGER_CST && TREE_CODE (TYPE_SIZE (TREE_TYPE (to))) == INTEGER_CST)) { register enum machine_mode mode1; int bitsize; int volstruct = 0; tree tem = to; int bitpos = 0; int unsignedp; if (TREE_CODE (to) == COMPONENT_REF) { tree field = TREE_OPERAND (to, 1); bitsize = TREE_INT_CST_LOW (DECL_SIZE (field)) * DECL_SIZE_UNIT (field); mode1 = DECL_MODE (TREE_OPERAND (to, 1)); unsignedp = TREE_UNSIGNED (field); } else { mode1 = TYPE_MODE (TREE_TYPE (to)); bitsize = GET_MODE_BITSIZE (mode1); unsignedp = TREE_UNSIGNED (TREE_TYPE (to)); } /* Compute cumulative bit-offset for nested component-refs and array-refs, and find the ultimate containing object. */ while (1) { if (TREE_CODE (tem) == COMPONENT_REF) { bitpos += DECL_OFFSET (TREE_OPERAND (tem, 1)); if (TREE_THIS_VOLATILE (tem)) volstruct = 1; } else if (TREE_CODE (tem) == ARRAY_REF && TREE_CODE (TREE_OPERAND (tem, 1)) == INTEGER_CST && TREE_CODE (TYPE_SIZE (TREE_TYPE (tem))) == INTEGER_CST) { bitpos += (TREE_INT_CST_LOW (TREE_OPERAND (tem, 1)) * TREE_INT_CST_LOW (TYPE_SIZE (TREE_TYPE (tem))) * TYPE_SIZE_UNIT (TREE_TYPE (tem))); if (TREE_THIS_VOLATILE (tem)) volstruct = 1; } else break; tem = TREE_OPERAND (tem, 0); } /* TEM is now the containing data object. */ /* If we are going to use store_bit_field and extract_bit_field, make sure to_rtx will be safe for multiple use. */ if (mode1 == BImode && want_value) tem = stabilize_reference (tem); to_rtx = expand_expr (tem, 0, VOIDmode, 0); if (volstruct) { if (GET_CODE (to_rtx) == MEM) MEM_VOLATILE_P (to_rtx) = 1;#if 0 /* This was turned off because, when a field is volatile in an object which is not volatile, the object may be in a register, and then we would abort over here. */ else abort ();#endif } return store_field (to_rtx, bitsize, bitpos, mode1, from, (want_value /* Spurious cast makes HPUX compiler happy. */ ? (enum machine_mode) TYPE_MODE (TREE_TYPE (to)) : VOIDmode), unsignedp, /* Required alignment of containing datum. */ TYPE_ALIGN (TREE_TYPE (tem)) / BITS_PER_UNIT, int_size_in_bytes (TREE_TYPE (tem))); } /* Ordinary treatment. Expand TO to get a REG or MEM rtx. Don't re-expand if it was expanded already (in COMPONENT_REF case). */ if (to_rtx == 0) to_rtx = expand_expr (to, 0, VOIDmode, 0); /* Compute FROM and store the value in the rtx we got. */ return store_expr (from, to_rtx, want_value);}/* Generate code for computing expression EXP, and storing the value into TARGET. Returns TARGET or an equivalent value. TARGET may contain a QUEUED rtx. If SUGGEST_REG is nonzero, copy the value through a register and return that register, if that is possible. If the value stored is a constant, we return the constant. */rtxstore_expr (exp, target, suggest_reg) register tree exp; register rtx target; int suggest_reg;{ register rtx temp; int dont_return_target = 0; /* Copying a non-constant CONSTRUCTOR needs special treatment. */ if (TREE_CODE (exp) == CONSTRUCTOR && ! TREE_STATIC (exp)) { store_constructor (exp, target); return target; } if (suggest_reg && GET_CODE (target) == MEM && GET_MODE (target) != BLKmode) /* If target is in memory and caller wants value in a register instead, arrange that. Pass TARGET as target for expand_expr so that, if EXP is another assignment, SUGGEST_REG will be nonzero for it. We know expand_expr will not use the target in that case. */ { temp = expand_expr (exp, cse_not_expected ? 0 : target, GET_MODE (target), 0); if (GET_MODE (temp) != BLKmode && GET_MODE (temp) != VOIDmode) temp = copy_to_reg (temp); dont_return_target = 1; } else if (queued_subexp_p (target)) /* If target contains a postincrement, it is not safe to use as the returned value. It would access the wrong place by the time the queued increment gets output. So copy the value through a temporary and use that temp as the result. */ { temp = expand_expr (exp, 0, GET_MODE (target), 0); if (GET_MODE (temp) != BLKmode && GET_MODE (temp) != VOIDmode) temp = copy_to_reg (temp); dont_return_target = 1; } else { temp = expand_expr (exp, target, GET_MODE (target), 0); /* DO return TARGET if it's a specified hardware register. expand_return relies on this. */ if (!(target && GET_CODE (target) == REG && REGNO (target) < FIRST_PSEUDO_REGISTER) && (CONSTANT_P (temp) || GET_CODE (temp) == CONST_DOUBLE)) dont_return_target = 1; } /* If value was not generated in the target, store it there. Convert the value to TARGET's type first if nec. */ if (temp != target && TREE_CODE (exp) != ERROR_MARK) { target = protect_from_queue (target, 1); if (GET_MODE (temp) != GET_MODE (target) && GET_MODE (temp) != VOIDmode) { int unsignedp = TREE_UNSIGNED (TREE_TYPE (exp)); if (dont_return_target) { /* In this case, we will return TEMP, so make sure it has the proper mode. But don't forget to store the value into TARGET. */ temp = convert_to_mode (GET_MODE (target), temp, unsignedp); emit_move_insn (target, temp); } else convert_move (target, temp, unsignedp); } else if (GET_MODE (temp) == BLKmode && TREE_CODE (exp) == STRING_CST) { /* Handle copying a string constant into an array. The string constant may be shorter than the array. So copy just the string's actual length, and clear the rest. */ rtx size; emit_block_move (target, temp, gen_rtx (CONST_INT, VOIDmode, TREE_STRING_LENGTH (exp)), TYPE_ALIGN (TREE_TYPE (exp)) / BITS_PER_UNIT); temp = plus_constant (XEXP (target, 0), TREE_STRING_LENGTH (exp)); size = plus_constant (expr_size (exp), - TREE_STRING_LENGTH (exp));#ifdef TARGET_MEM_FUNCTIONS emit_library_call (gen_rtx (SYMBOL_REF, Pmode, "memset"), 0, VOIDmode, 3, temp, Pmode, const0_rtx, Pmode, size, Pmode);#else emit_library_call (gen_rtx (SYMBOL_REF, Pmode, "bzero"), 0, VOIDmode, 2, temp, Pmode, size, Pmode);#endif } else if (GET_MODE (temp) == BLKmode) emit_block_move (target, temp, expr_size (exp), TYPE_ALIGN (TREE_TYPE (exp)) / BITS_PER_UNIT); else emit_move_insn (target, temp); } if (dont_return_target) return temp; return target;}/* Store the value of constructor EXP into the rtx TARGET. TARGET is either a REG or a MEM. */static voidstore_constructor (exp, target) tree exp; rtx target;{ /* Don't try copying piece by piece into a hard register since that is vulnerable to being clobbered by EXP. Instead, construct in a pseudo register and then copy it all. */ if (GET_CODE (target) == REG && REGNO (target) < FIRST_PSEUDO_REGISTER) { rtx temp = gen_reg_rtx (GET_MODE (target)); store_constructor (exp, temp); emit_move_insn (target, temp); return; } if (TREE_CODE (TREE_TYPE (exp)) == RECORD_TYPE || TREE_CODE (TREE_TYPE (exp)) == UNION_TYPE) { register tree elt; if (TREE_CODE (TREE_TYPE (exp)) == UNION_TYPE) /* Inform later passes that the whole union value is dead. */ emit_insn (gen_rtx (CLOBBER, VOIDmode, target)); /* If a record constructor has fewer fields than the structure, clear the whole structure first. */ else if (list_length (CONSTRUCTOR_ELTS (exp)) != list_length (TYPE_FIELDS (TREE_TYPE (exp)))) clear_storage (target, int_size_in_bytes (TREE_TYPE (exp))); else /* Inform later passes that the old value is dead. */ emit_insn (gen_rtx (CLOBBER, VOIDmode, target)); /* Store each element of the constructor into the corresponding field of TARGET. */ for (elt = CONSTRUCTOR_ELTS (exp); elt; elt = TREE_CHAIN (elt)) { register tree field = TREE_PURPOSE (elt); register enum machine_mode mode; int bitsize; int bitpos; int unsignedp; bitsize = TREE_INT_CST_LOW (DECL_SIZE (field)) * DECL_SIZE_UNIT (field); mode = DECL_MODE (field); unsignedp = TREE_UNSIGNED (field); bitpos = DECL_OFFSET (field); store_field (target, bitsize, bitpos, mode, TREE_VALUE (elt), /* The alignment of TARGET is at least what its type requires. */ VOIDmode, 0, TYPE_ALIGN (TREE_TYPE (exp)) / BITS_PER_UNIT, int_size_in_bytes (TREE_TYPE (exp))); } } else if (TREE_CODE (TREE_TYPE (exp)) == ARRAY_TYPE) { register tree elt; register int i; tree domain = TYPE_DOMAIN (TREE_TYPE (exp)); int minelt = TREE_INT_CST_LOW (TYPE_MIN_VALUE (domain)); int maxelt = TREE_INT_CST_LOW (TYPE_MAX_VALUE (domain)); tree elttype = TREE_TYPE (TREE_TYPE (exp)); /* If the constructor has fewer fields than the structure, clear the whole structure first. */ if (list_length (CONSTRUCTOR_ELTS (exp)) < maxelt - minelt + 1) clear_storage (target, maxelt - minelt + 1); else /* Inform later passes that the old value is dead. */ emit_insn (gen_rtx (CLOBBER, VOIDmode, target)); /* Store each element of the constructor into the corresponding element of TARGET, determined by counting the elements. */ for (elt = CONSTRUCTOR_ELTS (exp), i = 0; elt; elt = TREE_CHAIN (elt), i++) { register enum machine_mode mode; int bitsize; int bitpos; int unsignedp; mode = TYPE_MODE (elttype); bitsize = GET_MODE_BITSIZE (mode); unsignedp = TREE_UNSIGNED (elttype); bitpos = (i * TREE_INT_CST_LOW (TYPE_SIZE (elttype)) * TYPE_SIZE_UNIT (elttype)); store_field (target, bitsize, bitpos, mode, TREE_VALUE (elt), /* The alignment of TARGET is at least what its type requires. */ VOIDmode, 0, TYPE_ALIGN (TREE_TYPE (exp)) / BITS_PER_UNIT, int_size_in_bytes (TREE_TYPE (exp))); } }}/* Store the value of EXP (an expression tree) into a subfield of TARGET which has mode MODE and occupies BITSIZE bits, starting BITPOS bits from the start of TARGET. If VALUE_MODE is VOIDmode, return nothing in particular. UNSIGNEDP is not used in this case. Otherwise, return an rtx for the value stored. This rtx has mode VALUE_MODE if that is convenient to do. In this case, UNSIGNEDP must be nonzero if the value is an unsigned type. ALIGN is the alignment that TARGET is known to have, measured in bytes. TOTAL_SIZE is its size in bytes, or -1 if variable. */static rtxstore_field (target, bitsize, bitpos, mode, exp, value_mode, unsignedp, align, total_size) rtx target; int bitsize, bitpos; enum machine_mode mode; tree exp; enum machine_mode value_mode; int unsignedp; int align; int total_size;{ /* If the structure is in a register or if the component is a bit field, we cannot use addressing to access it. Use bit-field techniques or SUBREG to store in it. */ if (mode == BImode || GET_CODE (target) == REG || GET_CODE (target) == SUBREG) { store_bit_field (target, bitsize, bitpos, mode, expand_expr (exp, 0, VOIDmode, 0), align, total_size); if (value_mode != VOIDmode) return extract_bit_field (target, bitsize, bitpos, unsignedp, 0, value_mode, 0, align, total_size); return const0_rtx; } else { rtx addr = XEXP (target, 0); rtx to_rtx; /* If a value is wanted, it must be the lhs; so make the address stable for multiple use. */ if (value_mode != VOIDmode && GET_CODE (addr) != REG && ! CONSTANT_ADDRESS_P (addr)) addr = copy_to_reg (addr); /* Now build a reference to just the desired component. */ to_rtx = change_address (target, mode, plus_constant (addr, (bitpos / BITS_PER_UNIT))); MEM_IN_STRUCT_P (to_rtx) = 1; return store_expr (exp, to_rtx, value_mode != VOIDmode); }}/* Given an rtx VALUE that may contain additions and multiplications, return an equivalent value that just refers to a register or memory. This is done by generating instructions to perform the arithmetic and returning a pseudo-register containing the value. */rtxforce_operand (value, target) rtx value, target;{ register optab binoptab = 0; register rtx op2; /* Use subtarget as the target for operand 0 of a binary operation. */ register rtx subtarget = (target != 0 && GET_CODE (target) == REG ? target : 0); if (GET_CODE (value) == PLUS) binoptab = add_optab; else if (GET_CODE (value) == MINUS) binoptab = sub_optab; else if (GET_CODE (value) == MULT) { op2 = XEXP (value, 1); if (!CONSTANT_P (op2) && !(GET_CODE (op2) == REG && op2 != subtarget)) subtarget = 0; return expand_mult (GET_MODE (value), force_operand (XEXP (value, 0), subtarget), force_operand (op2, 0), target, 0); } if (binoptab) { op2 = XEXP (value, 1); if (!CONSTANT_P (op2) && !(GET_CODE (op2) == REG && op2 != subtarget)) subtarget = 0; if (binoptab == sub_optab && GET_CODE (op2) == CONST_INT && INTVAL (op2) < 0) { binoptab = add_optab; op2 = gen_rtx (CONST_INT, VOIDmode, - INTVAL (op2)); } return expand_binop (GET_MODE (value), binoptab, force_operand (XEXP (value, 0), subtarget), force_operand (op2, 0), target, 0, OPTAB_LIB_WIDEN); /* We give UNSIGNEP = 0 to expand_binop because the only operations we are expanding here are signed ones. */ } return value;}/* expand_expr: generate code for computing expression EXP. An rtx for the computed value is returned. The value is never null. In the case of a void EXP, const0_rtx is returned. The value may b
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -