+ 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))
+ {
+ if (!TREE_SIDE_EFFECTS (value))
+ return expand_expr (fold (value), target, tmode, modifier);
+ break;
+ }
+ }
+
+ else if (optimize >= 1
+ && modifier != EXPAND_CONST_ADDRESS
+ && modifier != EXPAND_INITIALIZER
+ && modifier != EXPAND_MEMORY
+ && TREE_READONLY (array) && ! TREE_SIDE_EFFECTS (array)
+ && TREE_CODE (array) == VAR_DECL && DECL_INITIAL (array)
+ && TREE_CODE (DECL_INITIAL (array)) != ERROR_MARK
+ && targetm.binds_local_p (array))
+ {
+ if (TREE_CODE (index) == INTEGER_CST)
+ {
+ tree init = DECL_INITIAL (array);
+
+ if (TREE_CODE (init) == CONSTRUCTOR)
+ {
+ unsigned HOST_WIDE_INT ix;
+ tree field, value;
+
+ FOR_EACH_CONSTRUCTOR_ELT (CONSTRUCTOR_ELTS (init), ix,
+ field, value)
+ if (tree_int_cst_equal (field, index))
+ {
+ if (TREE_SIDE_EFFECTS (value))
+ break;
+
+ if (TREE_CODE (value) == CONSTRUCTOR)
+ {
+ /* If VALUE is a CONSTRUCTOR, this
+ optimization is only useful if
+ this doesn't store the CONSTRUCTOR
+ into memory. If it does, it is more
+ efficient to just load the data from
+ the array directly. */
+ rtx ret = expand_constructor (value, target,
+ modifier, true);
+ if (ret == NULL_RTX)
+ break;
+ }
+
+ return expand_expr (fold (value), target, tmode,
+ modifier);
+ }
+ }
+ else if(TREE_CODE (init) == STRING_CST)
+ {
+ tree index1 = index;
+ tree low_bound = array_ref_low_bound (exp);
+ index1 = fold_convert_loc (loc, sizetype,
+ treeop1);
+
+ /* Optimize the special-case of a zero lower bound.
+
+ We convert the low_bound to sizetype to avoid some problems
+ with constant folding. (E.g. suppose the lower bound is 1,
+ and its mode is QI. Without the conversion,l (ARRAY
+ +(INDEX-(unsigned char)1)) becomes ((ARRAY+(-(unsigned char)1))
+ +INDEX), which becomes (ARRAY+255+INDEX). Opps!) */
+
+ if (! integer_zerop (low_bound))
+ index1 = size_diffop_loc (loc, index1,
+ fold_convert_loc (loc, sizetype,
+ low_bound));
+
+ if (0 > compare_tree_int (index1,
+ TREE_STRING_LENGTH (init)))
+ {
+ tree type = TREE_TYPE (TREE_TYPE (init));
+ enum machine_mode mode = TYPE_MODE (type);
+
+ if (GET_MODE_CLASS (mode) == MODE_INT
+ && GET_MODE_SIZE (mode) == 1)
+ return gen_int_mode (TREE_STRING_POINTER (init)
+ [TREE_INT_CST_LOW (index1)],
+ mode);
+ }
+ }
+ }
+ }
+ }
+ goto normal_inner_ref;
+
+ case COMPONENT_REF:
+ /* If the operand is a CONSTRUCTOR, we can just extract the
+ appropriate field if it is present. */
+ if (TREE_CODE (treeop0) == CONSTRUCTOR)