/* Memory address lowering and addressing mode selection.
- Copyright (C) 2004, 2006, 2007, 2008, 2009, 2010
+ Copyright (C) 2004, 2006, 2007, 2008, 2009, 2010, 2011
Free Software Foundation, Inc.
This file is part of GCC.
*addr = act_elem;
}
- if (base)
+ if (base && base != const0_rtx)
{
if (*addr)
*addr = simplify_gen_binary (PLUS, address_mode, base, *addr);
bool really_expand)
{
enum machine_mode address_mode = targetm.addr_space.address_mode (as);
+ enum machine_mode pointer_mode = targetm.addr_space.pointer_mode (as);
rtx address, sym, bse, idx, st, off;
struct mem_addr_template *templ;
if (addr->step && !integer_onep (addr->step))
- st = immed_double_int_const (tree_to_double_int (addr->step), address_mode);
+ st = immed_double_int_const (tree_to_double_int (addr->step), pointer_mode);
else
st = NULL_RTX;
if (addr->offset && !integer_zerop (addr->offset))
- off = immed_double_int_const (tree_to_double_int (addr->offset), address_mode);
+ off = immed_double_int_const
+ (double_int_sext (tree_to_double_int (addr->offset),
+ TYPE_PRECISION (TREE_TYPE (addr->offset))),
+ pointer_mode);
else
off = NULL_RTX;
if (!templ->ref)
{
sym = (addr->symbol ?
- gen_rtx_SYMBOL_REF (address_mode, ggc_strdup ("test_symbol"))
+ gen_rtx_SYMBOL_REF (pointer_mode, ggc_strdup ("test_symbol"))
: NULL_RTX);
bse = (addr->base ?
- gen_raw_REG (address_mode, LAST_VIRTUAL_REGISTER + 1)
+ gen_raw_REG (pointer_mode, LAST_VIRTUAL_REGISTER + 1)
: NULL_RTX);
idx = (addr->index ?
- gen_raw_REG (address_mode, LAST_VIRTUAL_REGISTER + 2)
+ gen_raw_REG (pointer_mode, LAST_VIRTUAL_REGISTER + 2)
: NULL_RTX);
- gen_addr_rtx (address_mode, sym, bse, idx,
+ gen_addr_rtx (pointer_mode, sym, bse, idx,
st? const0_rtx : NULL_RTX,
off? const0_rtx : NULL_RTX,
&templ->ref,
/* Otherwise really expand the expressions. */
sym = (addr->symbol
- ? expand_expr (build_addr (addr->symbol, current_function_decl),
- NULL_RTX, address_mode, EXPAND_NORMAL)
+ ? expand_expr (addr->symbol, NULL_RTX, pointer_mode, EXPAND_NORMAL)
: NULL_RTX);
bse = (addr->base
- ? expand_expr (addr->base, NULL_RTX, address_mode, EXPAND_NORMAL)
+ ? expand_expr (addr->base, NULL_RTX, pointer_mode, EXPAND_NORMAL)
: NULL_RTX);
idx = (addr->index
- ? expand_expr (addr->index, NULL_RTX, address_mode, EXPAND_NORMAL)
+ ? expand_expr (addr->index, NULL_RTX, pointer_mode, EXPAND_NORMAL)
: NULL_RTX);
- gen_addr_rtx (address_mode, sym, bse, idx, st, off, &address, NULL, NULL);
+ gen_addr_rtx (pointer_mode, sym, bse, idx, st, off, &address, NULL, NULL);
+ if (pointer_mode != address_mode)
+ address = convert_memory_address (address_mode, address);
return address;
}
tree addr;
tree act_elem;
tree step = TMR_STEP (mem_ref), offset = TMR_OFFSET (mem_ref);
- tree sym = TMR_SYMBOL (mem_ref), base = TMR_BASE (mem_ref);
tree addr_base = NULL_TREE, addr_off = NULL_TREE;
- if (sym)
- addr_base = fold_convert (type, build_addr (sym, current_function_decl));
- else if (base && POINTER_TYPE_P (TREE_TYPE (base)))
- {
- addr_base = fold_convert (type, base);
- base = NULL_TREE;
- }
+ addr_base = fold_convert (type, TMR_BASE (mem_ref));
act_elem = TMR_INDEX (mem_ref);
if (act_elem)
{
if (step)
- act_elem = fold_build2 (MULT_EXPR, sizetype, act_elem, step);
+ act_elem = fold_build2 (MULT_EXPR, TREE_TYPE (act_elem),
+ act_elem, step);
addr_off = act_elem;
}
- act_elem = base;
+ act_elem = TMR_INDEX2 (mem_ref);
if (act_elem)
{
if (addr_off)
- addr_off = fold_build2 (PLUS_EXPR, sizetype, addr_off, act_elem);
+ addr_off = fold_build2 (PLUS_EXPR, TREE_TYPE (addr_off),
+ addr_off, act_elem);
else
addr_off = act_elem;
}
if (offset && !integer_zerop (offset))
{
if (addr_off)
- addr_off = fold_build2 (PLUS_EXPR, sizetype, addr_off, offset);
+ addr_off = fold_build2 (PLUS_EXPR, TREE_TYPE (addr_off), addr_off,
+ fold_convert (TREE_TYPE (addr_off), offset));
else
addr_off = offset;
}
if (addr_off)
- {
- if (addr_base)
- addr = fold_build2 (POINTER_PLUS_EXPR, type, addr_base, addr_off);
- else
- addr = fold_convert (type, addr_off);
- }
- else if (addr_base)
- addr = addr_base;
+ addr = fold_build_pointer_plus (addr_base, addr_off);
else
- addr = build_int_cst (type, 0);
+ addr = addr_base;
return addr;
}
/* Checks whether a TARGET_MEM_REF with type TYPE and parameters given by ADDR
is valid on the current target and if so, creates and returns the
- TARGET_MEM_REF. */
+ TARGET_MEM_REF. If VERIFY is false omit the verification step. */
static tree
-create_mem_ref_raw (tree type, tree alias_ptr_type, struct mem_address *addr)
+create_mem_ref_raw (tree type, tree alias_ptr_type, struct mem_address *addr,
+ bool verify)
{
- if (!valid_mem_ref_p (TYPE_MODE (type), TYPE_ADDR_SPACE (type), addr))
+ tree base, index2;
+
+ if (verify
+ && !valid_mem_ref_p (TYPE_MODE (type), TYPE_ADDR_SPACE (type), addr))
return NULL_TREE;
if (addr->step && integer_onep (addr->step))
addr->step = NULL_TREE;
- if (addr->offset && integer_zerop (addr->offset))
- addr->offset = NULL_TREE;
+ if (addr->offset)
+ addr->offset = fold_convert (alias_ptr_type, addr->offset);
+ else
+ addr->offset = build_int_cst (alias_ptr_type, 0);
- /* If possible use a plain MEM_REF instead of a TARGET_MEM_REF. */
- if (alias_ptr_type
- && !addr->index
- && !addr->step
- && (!addr->base || POINTER_TYPE_P (TREE_TYPE (addr->base))))
+ if (addr->symbol)
{
- tree base, offset;
- gcc_assert (!addr->symbol ^ !addr->base);
- if (addr->symbol)
- base = build_fold_addr_expr (addr->symbol);
- else
- base = addr->base;
- if (addr->offset)
- offset = fold_convert (alias_ptr_type, addr->offset);
- else
- offset = build_int_cst (alias_ptr_type, 0);
- return fold_build2 (MEM_REF, type, base, offset);
+ base = addr->symbol;
+ index2 = addr->base;
+ }
+ else if (addr->base
+ && POINTER_TYPE_P (TREE_TYPE (addr->base)))
+ {
+ base = addr->base;
+ index2 = NULL_TREE;
+ }
+ else
+ {
+ base = build_int_cst (ptr_type_node, 0);
+ index2 = addr->base;
}
- return build6 (TARGET_MEM_REF, type,
- addr->symbol, addr->base, addr->index,
- addr->step, addr->offset, NULL);
+ /* If possible use a plain MEM_REF instead of a TARGET_MEM_REF.
+ ??? As IVOPTs does not follow restrictions to where the base
+ pointer may point to create a MEM_REF only if we know that
+ base is valid. */
+ if ((TREE_CODE (base) == ADDR_EXPR || TREE_CODE (base) == INTEGER_CST)
+ && (!index2 || integer_zerop (index2))
+ && (!addr->index || integer_zerop (addr->index)))
+ return fold_build2 (MEM_REF, type, base, addr->offset);
+
+ return build5 (TARGET_MEM_REF, type,
+ base, addr->offset, addr->index, addr->step, index2);
}
/* Returns true if OBJ is an object whose address is a link time constant. */
if (i == addr->n)
return;
- parts->symbol = TREE_OPERAND (val, 0);
+ parts->symbol = val;
aff_combination_remove_elt (addr, i);
}
/* Add ELT to base. */
type = TREE_TYPE (parts->base);
if (POINTER_TYPE_P (type))
- parts->base = fold_build2 (POINTER_PLUS_EXPR, type,
- parts->base,
- fold_convert (sizetype, elt));
+ parts->base = fold_build_pointer_plus (parts->base, elt);
else
parts->base = fold_build2 (PLUS_EXPR, type,
parts->base, elt);
gimplify_mem_ref_parts (gimple_stmt_iterator *gsi, struct mem_address *parts)
{
if (parts->base)
- parts->base = force_gimple_operand_gsi (gsi, parts->base,
- true, NULL_TREE,
+ parts->base = force_gimple_operand_gsi_1 (gsi, parts->base,
+ is_gimple_mem_ref_addr, NULL_TREE,
true, GSI_SAME_STMT);
if (parts->index)
parts->index = force_gimple_operand_gsi (gsi, parts->index,
tree alias_ptr_type, tree iv_cand, tree base_hint, bool speed)
{
tree mem_ref, tmp;
- tree atype;
struct mem_address parts;
addr_to_parts (type, addr, iv_cand, base_hint, &parts, speed);
gimplify_mem_ref_parts (gsi, &parts);
- mem_ref = create_mem_ref_raw (type, alias_ptr_type, &parts);
+ mem_ref = create_mem_ref_raw (type, alias_ptr_type, &parts, true);
if (mem_ref)
return mem_ref;
true, NULL_TREE, true, GSI_SAME_STMT);
parts.step = NULL_TREE;
- mem_ref = create_mem_ref_raw (type, alias_ptr_type, &parts);
+ mem_ref = create_mem_ref_raw (type, alias_ptr_type, &parts, true);
if (mem_ref)
return mem_ref;
}
if (parts.symbol)
{
- tmp = build_addr (parts.symbol, current_function_decl);
+ tmp = parts.symbol;
gcc_assert (is_gimple_val (tmp));
/* Add the symbol to base, eventually forcing it to register. */
if (parts.index)
{
- atype = TREE_TYPE (tmp);
- parts.base = force_gimple_operand_gsi (gsi,
- fold_build2 (POINTER_PLUS_EXPR, atype,
- tmp,
- fold_convert (sizetype, parts.base)),
- true, NULL_TREE, true, GSI_SAME_STMT);
+ parts.base = force_gimple_operand_gsi_1 (gsi,
+ fold_build_pointer_plus (tmp, parts.base),
+ is_gimple_mem_ref_addr, NULL_TREE, true, GSI_SAME_STMT);
}
else
{
parts.base = tmp;
parts.symbol = NULL_TREE;
- mem_ref = create_mem_ref_raw (type, alias_ptr_type, &parts);
+ mem_ref = create_mem_ref_raw (type, alias_ptr_type, &parts, true);
if (mem_ref)
return mem_ref;
}
/* Add index to base. */
if (parts.base)
{
- atype = TREE_TYPE (parts.base);
- parts.base = force_gimple_operand_gsi (gsi,
- fold_build2 (POINTER_PLUS_EXPR, atype,
- parts.base,
- parts.index),
- true, NULL_TREE, true, GSI_SAME_STMT);
+ parts.base = force_gimple_operand_gsi_1 (gsi,
+ fold_build_pointer_plus (parts.base, parts.index),
+ is_gimple_mem_ref_addr, NULL_TREE, true, GSI_SAME_STMT);
}
else
parts.base = parts.index;
parts.index = NULL_TREE;
- mem_ref = create_mem_ref_raw (type, alias_ptr_type, &parts);
+ mem_ref = create_mem_ref_raw (type, alias_ptr_type, &parts, true);
if (mem_ref)
return mem_ref;
}
/* Try adding offset to base. */
if (parts.base)
{
- atype = TREE_TYPE (parts.base);
- parts.base = force_gimple_operand_gsi (gsi,
- fold_build2 (POINTER_PLUS_EXPR, atype,
- parts.base,
- fold_convert (sizetype, parts.offset)),
- true, NULL_TREE, true, GSI_SAME_STMT);
+ parts.base = force_gimple_operand_gsi_1 (gsi,
+ fold_build_pointer_plus (parts.base, parts.offset),
+ is_gimple_mem_ref_addr, NULL_TREE, true, GSI_SAME_STMT);
}
else
parts.base = parts.offset;
parts.offset = NULL_TREE;
- mem_ref = create_mem_ref_raw (type, alias_ptr_type, &parts);
+ mem_ref = create_mem_ref_raw (type, alias_ptr_type, &parts, true);
if (mem_ref)
return mem_ref;
}
void
get_address_description (tree op, struct mem_address *addr)
{
- addr->symbol = TMR_SYMBOL (op);
- addr->base = TMR_BASE (op);
+ if (TREE_CODE (TMR_BASE (op)) == ADDR_EXPR)
+ {
+ addr->symbol = TMR_BASE (op);
+ addr->base = TMR_INDEX2 (op);
+ }
+ else
+ {
+ addr->symbol = NULL_TREE;
+ if (TMR_INDEX2 (op))
+ {
+ gcc_assert (integer_zerop (TMR_BASE (op)));
+ addr->base = TMR_INDEX2 (op);
+ }
+ else
+ addr->base = TMR_BASE (op);
+ }
addr->index = TMR_INDEX (op);
addr->step = TMR_STEP (op);
addr->offset = TMR_OFFSET (op);
copy_mem_ref_info (tree to, tree from)
{
/* And the info about the original reference. */
- TMR_ORIGINAL (to) = TMR_ORIGINAL (from);
TREE_SIDE_EFFECTS (to) = TREE_SIDE_EFFECTS (from);
TREE_THIS_VOLATILE (to) = TREE_THIS_VOLATILE (from);
}
+/* Copies the reference information from OLD_REF to NEW_REF, where
+ NEW_REF should be either a MEM_REF or a TARGET_MEM_REF. */
+
+void
+copy_ref_info (tree new_ref, tree old_ref)
+{
+ tree new_ptr_base = NULL_TREE;
+
+ gcc_assert (TREE_CODE (new_ref) == MEM_REF
+ || TREE_CODE (new_ref) == TARGET_MEM_REF);
+
+ TREE_SIDE_EFFECTS (new_ref) = TREE_SIDE_EFFECTS (old_ref);
+ TREE_THIS_VOLATILE (new_ref) = TREE_THIS_VOLATILE (old_ref);
+
+ new_ptr_base = TREE_OPERAND (new_ref, 0);
+
+ /* We can transfer points-to information from an old pointer
+ or decl base to the new one. */
+ if (new_ptr_base
+ && TREE_CODE (new_ptr_base) == SSA_NAME
+ && !SSA_NAME_PTR_INFO (new_ptr_base))
+ {
+ tree base = get_base_address (old_ref);
+ if (!base)
+ ;
+ else if ((TREE_CODE (base) == MEM_REF
+ || TREE_CODE (base) == TARGET_MEM_REF)
+ && TREE_CODE (TREE_OPERAND (base, 0)) == SSA_NAME
+ && SSA_NAME_PTR_INFO (TREE_OPERAND (base, 0)))
+ {
+ struct ptr_info_def *new_pi;
+ duplicate_ssa_name_ptr_info
+ (new_ptr_base, SSA_NAME_PTR_INFO (TREE_OPERAND (base, 0)));
+ new_pi = SSA_NAME_PTR_INFO (new_ptr_base);
+ /* We have to be careful about transfering alignment information. */
+ if (TREE_CODE (old_ref) == MEM_REF
+ && !(TREE_CODE (new_ref) == TARGET_MEM_REF
+ && (TMR_INDEX2 (new_ref)
+ || (TMR_STEP (new_ref)
+ && (TREE_INT_CST_LOW (TMR_STEP (new_ref))
+ < new_pi->align)))))
+ {
+ new_pi->misalign += double_int_sub (mem_ref_offset (old_ref),
+ mem_ref_offset (new_ref)).low;
+ new_pi->misalign &= (new_pi->align - 1);
+ }
+ else
+ {
+ new_pi->align = 1;
+ new_pi->misalign = 0;
+ }
+ }
+ else if (TREE_CODE (base) == VAR_DECL
+ || TREE_CODE (base) == PARM_DECL
+ || TREE_CODE (base) == RESULT_DECL)
+ {
+ struct ptr_info_def *pi = get_ptr_info (new_ptr_base);
+ pt_solution_set_var (&pi->pt, base);
+ }
+ }
+}
+
/* Move constants in target_mem_ref REF to offset. Returns the new target
mem ref if anything changes, NULL_TREE otherwise. */
get_address_description (ref, &addr);
- if (addr.base && TREE_CODE (addr.base) == INTEGER_CST)
+ if (addr.base
+ && TREE_CODE (addr.base) == INTEGER_CST
+ && !integer_zerop (addr.base))
{
- if (addr.offset)
- addr.offset = fold_binary_to_constant (PLUS_EXPR, sizetype,
- addr.offset,
- fold_convert (sizetype, addr.base));
- else
- addr.offset = addr.base;
-
+ addr.offset = fold_binary_to_constant (PLUS_EXPR,
+ TREE_TYPE (addr.offset),
+ addr.offset, addr.base);
addr.base = NULL_TREE;
changed = true;
}
+ if (addr.symbol
+ && TREE_CODE (TREE_OPERAND (addr.symbol, 0)) == MEM_REF)
+ {
+ addr.offset = fold_binary_to_constant
+ (PLUS_EXPR, TREE_TYPE (addr.offset),
+ addr.offset,
+ TREE_OPERAND (TREE_OPERAND (addr.symbol, 0), 1));
+ addr.symbol = TREE_OPERAND (TREE_OPERAND (addr.symbol, 0), 0);
+ changed = true;
+ }
+ else if (addr.symbol
+ && handled_component_p (TREE_OPERAND (addr.symbol, 0)))
+ {
+ HOST_WIDE_INT offset;
+ addr.symbol = build_fold_addr_expr
+ (get_addr_base_and_unit_offset
+ (TREE_OPERAND (addr.symbol, 0), &offset));
+ addr.offset = int_const_binop (PLUS_EXPR,
+ addr.offset, size_int (offset));
+ changed = true;
+ }
+
if (addr.index && TREE_CODE (addr.index) == INTEGER_CST)
{
off = addr.index;
addr.step = NULL_TREE;
}
- if (addr.offset)
- {
- addr.offset = fold_binary_to_constant (PLUS_EXPR, sizetype,
- addr.offset, off);
- }
- else
- addr.offset = off;
-
+ addr.offset = fold_binary_to_constant (PLUS_EXPR,
+ TREE_TYPE (addr.offset),
+ addr.offset, off);
addr.index = NULL_TREE;
changed = true;
}
if (!changed)
return NULL_TREE;
- ret = create_mem_ref_raw (TREE_TYPE (ref), NULL_TREE, &addr);
- if (!ret)
- return NULL_TREE;
-
+ /* If we have propagated something into this TARGET_MEM_REF and thus
+ ended up folding it, always create a new TARGET_MEM_REF regardless
+ if it is valid in this for on the target - the propagation result
+ wouldn't be anyway. */
+ ret = create_mem_ref_raw (TREE_TYPE (ref),
+ TREE_TYPE (addr.offset), &addr, false);
copy_mem_ref_info (ret, ref);
return ret;
}
if (parts->symbol)
{
fprintf (file, "symbol: ");
- print_generic_expr (file, parts->symbol, TDF_SLIM);
+ print_generic_expr (file, TREE_OPERAND (parts->symbol, 0), TDF_SLIM);
fprintf (file, "\n");
}
if (parts->base)