- subexp1 = TREE_OPERAND (exp, 1);
- subsubexp0 = TREE_OPERAND (subexp1, 0);
- subsubexp1 = TREE_OPERAND (subexp1, 1);
- code0 = TREE_CODE (subsubexp0);
- code1 = TREE_CODE (subsubexp1);
- this_code = TREE_CODE (type) == INTEGER_TYPE ? NOP_EXPR
- : FIXED_CONVERT_EXPR;
- if (code0 == this_code && code1 == this_code
- && (TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (subsubexp0, 0)))
- < TYPE_PRECISION (TREE_TYPE (subsubexp0)))
- && (TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (subsubexp0, 0)))
- == TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (subsubexp1, 0))))
- && (TYPE_UNSIGNED (TREE_TYPE (TREE_OPERAND (subsubexp0, 0)))
- == TYPE_UNSIGNED (TREE_TYPE (TREE_OPERAND (subsubexp1, 0)))))
- {
- tree op0type = TREE_TYPE (TREE_OPERAND (subsubexp0, 0));
- enum machine_mode innermode = TYPE_MODE (op0type);
- bool zextend_p = TYPE_UNSIGNED (op0type);
- bool sat_p = TYPE_SATURATING (TREE_TYPE (subsubexp0));
- if (sat_p == 0)
- this_optab = zextend_p ? umsub_widen_optab : smsub_widen_optab;
- else
- this_optab = zextend_p ? usmsub_widen_optab
- : ssmsub_widen_optab;
- if (mode == GET_MODE_2XWIDER_MODE (innermode)
- && (optab_handler (this_optab, mode)->insn_code
- != CODE_FOR_nothing))
+ FOR_EACH_CONSTRUCTOR_VALUE (CONSTRUCTOR_ELTS (exp), idx, value)
+ expand_expr (value, const0_rtx, VOIDmode, EXPAND_NORMAL);
+
+ return const0_rtx;
+ }
+
+ return expand_constructor (exp, target, modifier, false);
+
+ case MISALIGNED_INDIRECT_REF:
+ case ALIGN_INDIRECT_REF:
+ case INDIRECT_REF:
+ {
+ tree exp1 = treeop0;
+ addr_space_t as = ADDR_SPACE_GENERIC;
+ enum machine_mode address_mode = Pmode;
+
+ if (modifier != EXPAND_WRITE)
+ {
+ tree t;
+
+ t = fold_read_from_constant_string (exp);
+ if (t)
+ return expand_expr (t, target, tmode, modifier);
+ }
+
+ if (POINTER_TYPE_P (TREE_TYPE (exp1)))
+ {
+ as = TYPE_ADDR_SPACE (TREE_TYPE (TREE_TYPE (exp1)));
+ address_mode = targetm.addr_space.address_mode (as);
+ }
+
+ op0 = expand_expr (exp1, NULL_RTX, VOIDmode, EXPAND_SUM);
+ op0 = memory_address_addr_space (mode, op0, as);
+
+ if (code == ALIGN_INDIRECT_REF)
+ {
+ int align = TYPE_ALIGN_UNIT (type);
+ op0 = gen_rtx_AND (address_mode, op0, GEN_INT (-align));
+ op0 = memory_address_addr_space (mode, op0, as);
+ }
+
+ temp = gen_rtx_MEM (mode, op0);
+
+ set_mem_attributes (temp, exp, 0);
+ set_mem_addr_space (temp, as);
+
+ /* Resolve the misalignment now, so that we don't have to remember
+ to resolve it later. Of course, this only works for reads. */
+ if (code == MISALIGNED_INDIRECT_REF)
+ {
+ int icode;
+ rtx reg, insn;
+
+ gcc_assert (modifier == EXPAND_NORMAL
+ || modifier == EXPAND_STACK_PARM);
+
+ /* The vectorizer should have already checked the mode. */
+ icode = optab_handler (movmisalign_optab, mode)->insn_code;
+ gcc_assert (icode != CODE_FOR_nothing);
+
+ /* We've already validated the memory, and we're creating a
+ new pseudo destination. The predicates really can't fail. */
+ reg = gen_reg_rtx (mode);
+
+ /* Nor can the insn generator. */
+ insn = GEN_FCN (icode) (reg, temp);
+ emit_insn (insn);
+
+ return reg;
+ }
+
+ return temp;
+ }
+
+ case TARGET_MEM_REF:
+ {
+ addr_space_t as = TYPE_ADDR_SPACE (TREE_TYPE (exp));
+ struct mem_address addr;
+ tree base;
+
+ get_address_description (exp, &addr);
+ op0 = addr_for_mem_ref (&addr, as, true);
+ op0 = memory_address_addr_space (mode, op0, as);
+ temp = gen_rtx_MEM (mode, op0);
+ set_mem_attributes (temp, TMR_ORIGINAL (exp), 0);
+ set_mem_addr_space (temp, as);
+ base = get_base_address (TMR_ORIGINAL (exp));
+ if (INDIRECT_REF_P (base)
+ && TMR_BASE (exp)
+ && TREE_CODE (TMR_BASE (exp)) == SSA_NAME
+ && POINTER_TYPE_P (TREE_TYPE (TMR_BASE (exp))))
+ {
+ set_mem_expr (temp, build1 (INDIRECT_REF,
+ TREE_TYPE (exp), TMR_BASE (exp)));
+ set_mem_offset (temp, NULL_RTX);
+ }
+ }
+ return temp;
+
+ case ARRAY_REF:
+
+ {
+ tree array = treeop0;
+ tree index = treeop1;
+
+ /* Fold an expression like: "foo"[2].
+ This is not done in fold so it won't happen inside &.
+ Don't fold if this is for wide characters since it's too
+ difficult to do correctly and this is a very rare case. */
+
+ if (modifier != EXPAND_CONST_ADDRESS
+ && modifier != EXPAND_INITIALIZER
+ && modifier != EXPAND_MEMORY)
+ {
+ tree t = fold_read_from_constant_string (exp);
+
+ if (t)
+ return expand_expr (t, target, tmode, modifier);
+ }
+
+ /* If this is a constant index into a constant array,
+ just get the value from the array. Handle both the cases when
+ we have an explicit constructor and when our operand is a variable
+ that was declared const. */
+
+ if (modifier != EXPAND_CONST_ADDRESS
+ && modifier != EXPAND_INITIALIZER
+ && modifier != EXPAND_MEMORY
+ && TREE_CODE (array) == CONSTRUCTOR
+ && ! TREE_SIDE_EFFECTS (array)
+ && TREE_CODE (index) == INTEGER_CST)
+ {
+ unsigned HOST_WIDE_INT ix;
+ tree field, value;
+
+ FOR_EACH_CONSTRUCTOR_ELT (CONSTRUCTOR_ELTS (array), ix,
+ field, value)
+ if (tree_int_cst_equal (field, index))