};
struct affine_tree_combination;
-tree create_mem_ref (gimple_stmt_iterator *, tree, tree,
- struct affine_tree_combination *, tree, bool);
+tree create_mem_ref (gimple_stmt_iterator *, tree,
+ struct affine_tree_combination *, tree, tree, tree, bool);
rtx addr_for_mem_ref (struct mem_address *, addr_space_t, bool);
void get_address_description (tree, struct mem_address *);
tree maybe_fold_tmr (tree);
aff_combination_remove_elt (addr, i);
}
+/* Moves the loop variant part V in linear address ADDR to be the index
+ of PARTS. */
+
+static void
+move_variant_to_index (struct mem_address *parts, aff_tree *addr, tree v)
+{
+ unsigned i;
+ tree val = NULL_TREE;
+
+ gcc_assert (!parts->index);
+ for (i = 0; i < addr->n; i++)
+ {
+ val = addr->elts[i].val;
+ if (operand_equal_p (val, v, 0))
+ break;
+ }
+
+ if (i == addr->n)
+ return;
+
+ parts->index = fold_convert (sizetype, val);
+ parts->step = double_int_to_tree (sizetype, addr->elts[i].coef);
+ aff_combination_remove_elt (addr, i);
+}
+
/* Adds ELT to PARTS. */
static void
/* Splits address ADDR for a memory access of type TYPE into PARTS.
If BASE_HINT is non-NULL, it specifies an SSA name to be used
- preferentially as base of the reference.
+ preferentially as base of the reference, and IV_CAND is the selected
+ iv candidate used in ADDR.
TODO -- be more clever about the distribution of the elements of ADDR
to PARTS. Some architectures do not support anything but single
addressing modes is useless. */
static void
-addr_to_parts (tree type, aff_tree *addr, tree base_hint,
- struct mem_address *parts, bool speed)
+addr_to_parts (tree type, aff_tree *addr, tree iv_cand,
+ tree base_hint, struct mem_address *parts,
+ bool speed)
{
tree part;
unsigned i;
/* Try to find a symbol. */
move_fixed_address_to_symbol (parts, addr);
+ /* No need to do address parts reassociation if the number of parts
+ is <= 2 -- in that case, no loop invariant code motion can be
+ exposed. */
+
+ if (!base_hint && (addr->n > 2))
+ move_variant_to_index (parts, addr, iv_cand);
+
/* First move the most expensive feasible multiplication
to index. */
- most_expensive_mult_to_index (type, parts, addr, speed);
+ if (!parts->index)
+ most_expensive_mult_to_index (type, parts, addr, speed);
/* Try to find a base of the reference. Since at the moment
there is no reliable way how to distinguish between pointer and its
/* Creates and returns a TARGET_MEM_REF for address ADDR. If necessary
computations are emitted in front of GSI. TYPE is the mode
- of created memory reference. */
+ of created memory reference. IV_CAND is the selected iv candidate in ADDR,
+ and BASE_HINT is non NULL if IV_CAND comes from a base address
+ object. */
tree
-create_mem_ref (gimple_stmt_iterator *gsi, tree type, tree alias_ptr_type,
- aff_tree *addr, tree base_hint, bool speed)
+create_mem_ref (gimple_stmt_iterator *gsi, tree type, aff_tree *addr,
+ 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, base_hint, &parts, speed);
+ 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);
if (mem_ref)
aff_tree aff;
gimple_stmt_iterator bsi = gsi_for_stmt (use->stmt);
tree base_hint = NULL_TREE;
- tree ref;
+ tree ref, iv;
bool ok;
adjust_iv_update_pos (cand, use);
if (cand->iv->base_object)
base_hint = var_at_stmt (data->current_loop, cand, use->stmt);
- ref = create_mem_ref (&bsi, TREE_TYPE (*use->op_p),
+ iv = var_at_stmt (data->current_loop, cand, use->stmt);
+ ref = create_mem_ref (&bsi, TREE_TYPE (*use->op_p), &aff,
reference_alias_ptr_type (*use->op_p),
- &aff, base_hint, data->speed);
+ iv, base_hint, data->speed);
copy_ref_info (ref, *use->op_p);
*use->op_p = ref;
}