Commit 7a89b97a by Bin Cheng Committed by Bin Cheng

tree-ssa-address.c: Include header file.

	* tree-ssa-address.c: Include header file.
	(move_hint_to_base): Return TRUE if BASE_HINT is moved to memory
	address.
	(add_to_parts): Refactor.
	(addr_to_parts): New parameter.  Update use of move_hint_to_base.
	(create_mem_ref): Update use of addr_to_parts.  Re-associate addr
	in new order.

From-SVN: r247894
parent 80ca1cfa
2017-05-11 Bin Cheng <bin.cheng@arm.com> 2017-05-11 Bin Cheng <bin.cheng@arm.com>
* tree-ssa-address.c: Include header file.
(move_hint_to_base): Return TRUE if BASE_HINT is moved to memory
address.
(add_to_parts): Refactor.
(addr_to_parts): New parameter. Update use of move_hint_to_base.
(create_mem_ref): Update use of addr_to_parts. Re-associate addr
in new order.
2017-05-11 Bin Cheng <bin.cheng@arm.com>
PR tree-optimization/53090 PR tree-optimization/53090
* tree-ssa-loop-ivopts.c (enum comp_iv_rewrite): New enum value * tree-ssa-loop-ivopts.c (enum comp_iv_rewrite): New enum value
COMP_IV_EXPR_2. COMP_IV_EXPR_2.
......
...@@ -46,6 +46,7 @@ along with GCC; see the file COPYING3. If not see ...@@ -46,6 +46,7 @@ along with GCC; see the file COPYING3. If not see
#include "tree-dfa.h" #include "tree-dfa.h"
#include "dumpfile.h" #include "dumpfile.h"
#include "tree-affine.h" #include "tree-affine.h"
#include "gimplify.h"
/* FIXME: We compute address costs using RTL. */ /* FIXME: We compute address costs using RTL. */
#include "tree-ssa-address.h" #include "tree-ssa-address.h"
...@@ -427,9 +428,10 @@ move_fixed_address_to_symbol (struct mem_address *parts, aff_tree *addr) ...@@ -427,9 +428,10 @@ move_fixed_address_to_symbol (struct mem_address *parts, aff_tree *addr)
aff_combination_remove_elt (addr, i); aff_combination_remove_elt (addr, i);
} }
/* If ADDR contains an instance of BASE_HINT, move it to PARTS->base. */ /* Return true if ADDR contains an instance of BASE_HINT and it's moved to
PARTS->base. */
static void static bool
move_hint_to_base (tree type, struct mem_address *parts, tree base_hint, move_hint_to_base (tree type, struct mem_address *parts, tree base_hint,
aff_tree *addr) aff_tree *addr)
{ {
...@@ -448,7 +450,7 @@ move_hint_to_base (tree type, struct mem_address *parts, tree base_hint, ...@@ -448,7 +450,7 @@ move_hint_to_base (tree type, struct mem_address *parts, tree base_hint,
} }
if (i == addr->n) if (i == addr->n)
return; return false;
/* Cast value to appropriate pointer type. We cannot use a pointer /* Cast value to appropriate pointer type. We cannot use a pointer
to TYPE directly, as the back-end will assume registers of pointer to TYPE directly, as the back-end will assume registers of pointer
...@@ -458,6 +460,7 @@ move_hint_to_base (tree type, struct mem_address *parts, tree base_hint, ...@@ -458,6 +460,7 @@ move_hint_to_base (tree type, struct mem_address *parts, tree base_hint,
type = build_qualified_type (void_type_node, qual); type = build_qualified_type (void_type_node, qual);
parts->base = fold_convert (build_pointer_type (type), val); parts->base = fold_convert (build_pointer_type (type), val);
aff_combination_remove_elt (addr, i); aff_combination_remove_elt (addr, i);
return true;
} }
/* If ADDR contains an address of a dereferenced pointer, move it to /* If ADDR contains an address of a dereferenced pointer, move it to
...@@ -535,8 +538,7 @@ add_to_parts (struct mem_address *parts, tree elt) ...@@ -535,8 +538,7 @@ add_to_parts (struct mem_address *parts, tree elt)
if (POINTER_TYPE_P (type)) if (POINTER_TYPE_P (type))
parts->base = fold_build_pointer_plus (parts->base, elt); parts->base = fold_build_pointer_plus (parts->base, elt);
else else
parts->base = fold_build2 (PLUS_EXPR, type, parts->base = fold_build2 (PLUS_EXPR, type, parts->base, elt);
parts->base, elt);
} }
/* Returns true if multiplying by RATIO is allowed in an address. Test the /* Returns true if multiplying by RATIO is allowed in an address. Test the
...@@ -668,7 +670,8 @@ most_expensive_mult_to_index (tree type, struct mem_address *parts, ...@@ -668,7 +670,8 @@ most_expensive_mult_to_index (tree type, struct mem_address *parts,
/* Splits address ADDR for a memory access of type TYPE into PARTS. /* 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 If BASE_HINT is non-NULL, it specifies an SSA name to be used
preferentially as base of the reference, and IV_CAND is the selected preferentially as base of the reference, and IV_CAND is the selected
iv candidate used in ADDR. iv candidate used in ADDR. Store true to VAR_IN_BASE if variant
part of address is split to PARTS.base.
TODO -- be more clever about the distribution of the elements of ADDR TODO -- be more clever about the distribution of the elements of ADDR
to PARTS. Some architectures do not support anything but single to PARTS. Some architectures do not support anything but single
...@@ -678,9 +681,8 @@ most_expensive_mult_to_index (tree type, struct mem_address *parts, ...@@ -678,9 +681,8 @@ most_expensive_mult_to_index (tree type, struct mem_address *parts,
addressing modes is useless. */ addressing modes is useless. */
static void static void
addr_to_parts (tree type, aff_tree *addr, tree iv_cand, addr_to_parts (tree type, aff_tree *addr, tree iv_cand, tree base_hint,
tree base_hint, struct mem_address *parts, struct mem_address *parts, bool *var_in_base, bool speed)
bool speed)
{ {
tree part; tree part;
unsigned i; unsigned i;
...@@ -698,23 +700,20 @@ addr_to_parts (tree type, aff_tree *addr, tree iv_cand, ...@@ -698,23 +700,20 @@ addr_to_parts (tree type, aff_tree *addr, tree iv_cand,
/* Try to find a symbol. */ /* Try to find a symbol. */
move_fixed_address_to_symbol (parts, addr); move_fixed_address_to_symbol (parts, addr);
/* No need to do address parts reassociation if the number of parts /* Since at the moment there is no reliable way to know how to
is <= 2 -- in that case, no loop invariant code motion can be distinguish between pointer and its offset, we decide if var
exposed. */ part is the pointer based on guess. */
*var_in_base = (base_hint != NULL && parts->symbol == NULL);
if (!base_hint && (addr->n > 2)) if (*var_in_base)
*var_in_base = move_hint_to_base (type, parts, base_hint, addr);
else
move_variant_to_index (parts, addr, iv_cand); move_variant_to_index (parts, addr, iv_cand);
/* First move the most expensive feasible multiplication /* First move the most expensive feasible multiplication to index. */
to index. */
if (!parts->index) if (!parts->index)
most_expensive_mult_to_index (type, parts, addr, speed); most_expensive_mult_to_index (type, parts, addr, speed);
/* Try to find a base of the reference. Since at the moment /* Move pointer into base. */
there is no reliable way how to distinguish between pointer and its
offset, this is just a guess. */
if (!parts->symbol && base_hint)
move_hint_to_base (type, parts, base_hint, addr);
if (!parts->symbol && !parts->base) if (!parts->symbol && !parts->base)
move_pointer_to_base (parts, addr); move_pointer_to_base (parts, addr);
...@@ -756,10 +755,11 @@ tree ...@@ -756,10 +755,11 @@ tree
create_mem_ref (gimple_stmt_iterator *gsi, tree type, aff_tree *addr, 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 alias_ptr_type, tree iv_cand, tree base_hint, bool speed)
{ {
bool var_in_base;
tree mem_ref, tmp; tree mem_ref, tmp;
struct mem_address parts; struct mem_address parts;
addr_to_parts (type, addr, iv_cand, base_hint, &parts, speed); addr_to_parts (type, addr, iv_cand, base_hint, &parts, &var_in_base, speed);
gimplify_mem_ref_parts (gsi, &parts); gimplify_mem_ref_parts (gsi, &parts);
mem_ref = create_mem_ref_raw (type, alias_ptr_type, &parts, true); mem_ref = create_mem_ref_raw (type, alias_ptr_type, &parts, true);
if (mem_ref) if (mem_ref)
...@@ -767,9 +767,49 @@ create_mem_ref (gimple_stmt_iterator *gsi, tree type, aff_tree *addr, ...@@ -767,9 +767,49 @@ create_mem_ref (gimple_stmt_iterator *gsi, tree type, aff_tree *addr,
/* The expression is too complicated. Try making it simpler. */ /* The expression is too complicated. Try making it simpler. */
/* Merge symbol into other parts. */
if (parts.symbol)
{
tmp = parts.symbol;
parts.symbol = NULL_TREE;
gcc_assert (is_gimple_val (tmp));
if (parts.base)
{
gcc_assert (useless_type_conversion_p (sizetype,
TREE_TYPE (parts.base)));
if (parts.index)
{
/* Add the symbol to base, eventually forcing it to register. */
tmp = fold_build_pointer_plus (tmp, parts.base);
tmp = force_gimple_operand_gsi_1 (gsi, tmp,
is_gimple_mem_ref_addr,
NULL_TREE, true,
GSI_SAME_STMT);
}
else
{
/* Move base to index, then move the symbol to base. */
parts.index = parts.base;
}
parts.base = tmp;
}
else
parts.base = tmp;
mem_ref = create_mem_ref_raw (type, alias_ptr_type, &parts, true);
if (mem_ref)
return mem_ref;
}
/* Move multiplication to index by transforming address expression:
[... + index << step + ...]
into:
index' = index << step;
[... + index' + ,,,]. */
if (parts.step && !integer_onep (parts.step)) if (parts.step && !integer_onep (parts.step))
{ {
/* Move the multiplication to index. */
gcc_assert (parts.index); gcc_assert (parts.index);
parts.index = force_gimple_operand_gsi (gsi, parts.index = force_gimple_operand_gsi (gsi,
fold_build2 (MULT_EXPR, sizetype, fold_build2 (MULT_EXPR, sizetype,
...@@ -782,69 +822,100 @@ create_mem_ref (gimple_stmt_iterator *gsi, tree type, aff_tree *addr, ...@@ -782,69 +822,100 @@ create_mem_ref (gimple_stmt_iterator *gsi, tree type, aff_tree *addr,
return mem_ref; return mem_ref;
} }
if (parts.symbol) /* Add offset to invariant part by transforming address expression:
[base + index + offset]
into:
base' = base + offset;
[base' + index]
or:
index' = index + offset;
[base + index']
depending on which one is invariant. */
if (parts.offset && !integer_zerop (parts.offset))
{ {
tmp = parts.symbol; tree old_base = unshare_expr (parts.base);
gcc_assert (is_gimple_val (tmp)); tree old_index = unshare_expr (parts.index);
tree old_offset = unshare_expr (parts.offset);
/* Add the symbol to base, eventually forcing it to register. */ tmp = parts.offset;
if (parts.base) parts.offset = NULL_TREE;
/* Add offset to invariant part. */
if (!var_in_base)
{ {
gcc_assert (useless_type_conversion_p if (parts.base)
(sizetype, TREE_TYPE (parts.base)));
if (parts.index)
{ {
parts.base = force_gimple_operand_gsi_1 (gsi, tmp = fold_build_pointer_plus (parts.base, tmp);
fold_build_pointer_plus (tmp, parts.base), tmp = force_gimple_operand_gsi_1 (gsi, tmp,
is_gimple_mem_ref_addr, NULL_TREE, true, GSI_SAME_STMT); is_gimple_mem_ref_addr,
NULL_TREE, true,
GSI_SAME_STMT);
} }
else parts.base = tmp;
}
else
{
if (parts.index)
{ {
parts.index = parts.base; tmp = fold_build_pointer_plus (parts.index, tmp);
parts.base = tmp; tmp = force_gimple_operand_gsi_1 (gsi, tmp,
is_gimple_mem_ref_addr,
NULL_TREE, true,
GSI_SAME_STMT);
} }
parts.index = tmp;
} }
else
parts.base = tmp;
parts.symbol = NULL_TREE;
mem_ref = create_mem_ref_raw (type, alias_ptr_type, &parts, true); mem_ref = create_mem_ref_raw (type, alias_ptr_type, &parts, true);
if (mem_ref) if (mem_ref)
return mem_ref; return mem_ref;
/* Restore parts.base, index and offset so that we can check if
[base + offset] addressing mode is supported in next step.
This is necessary for targets only support [base + offset],
but not [base + index] addressing mode. */
parts.base = old_base;
parts.index = old_index;
parts.offset = old_offset;
} }
/* Transform [base + index + ...] into:
base' = base + index;
[base' + ...]. */
if (parts.index) if (parts.index)
{ {
tmp = parts.index;
parts.index = NULL_TREE;
/* Add index to base. */ /* Add index to base. */
if (parts.base) if (parts.base)
{ {
parts.base = force_gimple_operand_gsi_1 (gsi, tmp = fold_build_pointer_plus (parts.base, tmp);
fold_build_pointer_plus (parts.base, parts.index), tmp = force_gimple_operand_gsi_1 (gsi, tmp,
is_gimple_mem_ref_addr, NULL_TREE, true, GSI_SAME_STMT); is_gimple_mem_ref_addr,
NULL_TREE, true, GSI_SAME_STMT);
} }
else parts.base = tmp;
parts.base = parts.index;
parts.index = NULL_TREE;
mem_ref = create_mem_ref_raw (type, alias_ptr_type, &parts, true); mem_ref = create_mem_ref_raw (type, alias_ptr_type, &parts, true);
if (mem_ref) if (mem_ref)
return mem_ref; return mem_ref;
} }
/* Transform [base + offset] into:
base' = base + offset;
[base']. */
if (parts.offset && !integer_zerop (parts.offset)) if (parts.offset && !integer_zerop (parts.offset))
{ {
/* Try adding offset to base. */ tmp = parts.offset;
parts.offset = NULL_TREE;
/* Add offset to base. */
if (parts.base) if (parts.base)
{ {
parts.base = force_gimple_operand_gsi_1 (gsi, tmp = fold_build_pointer_plus (parts.base, tmp);
fold_build_pointer_plus (parts.base, parts.offset), tmp = force_gimple_operand_gsi_1 (gsi, tmp,
is_gimple_mem_ref_addr, NULL_TREE, true, GSI_SAME_STMT); is_gimple_mem_ref_addr,
NULL_TREE, true, GSI_SAME_STMT);
} }
else parts.base = tmp;
parts.base = parts.offset;
parts.offset = NULL_TREE;
mem_ref = create_mem_ref_raw (type, alias_ptr_type, &parts, true); mem_ref = create_mem_ref_raw (type, alias_ptr_type, &parts, true);
if (mem_ref) if (mem_ref)
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment