re PR middle-end/60092 (posix_memalign not recognized to derive alias and alignment info)

PR middle-end/60092
	* tree-ssa-ccp.c (surely_varying_stmt_p): Don't return true
	if TYPE_ATTRIBUTES (gimple_call_fntype ()) contain
	assume_aligned or alloc_align attributes.
	(bit_value_assume_aligned): Add ATTR, PTRVAL and ALLOC_ALIGN
	arguments.  Handle also assume_aligned and alloc_align attributes.
	(evaluate_stmt): Adjust bit_value_assume_aligned caller.
	Handle calls to functions with assume_aligned or alloc_align
	attributes.
	* doc/extend.texi: Document assume_aligned and alloc_align
	attributes.
c-family/
	* c-common.c (handle_alloc_size_attribute): Use tree_fits_uhwi_p
	and tree_to_uhwi.
	(handle_alloc_align_attribute, handle_assume_aligned_attribute): New
	functions.
	(c_common_attribute_table): Add alloc_align and assume_aligned
	attributes.
testsuite/
	* gcc.dg/attr-alloc_align-1.c: New test.
	* gcc.dg/attr-alloc_align-2.c: New test.
	* gcc.dg/attr-alloc_align-3.c: New test.
	* gcc.dg/attr-assume_aligned-1.c: New test.
	* gcc.dg/attr-assume_aligned-2.c: New test.
	* gcc.dg/attr-assume_aligned-3.c: New test.

From-SVN: r207628
This commit is contained in:
Jakub Jelinek 2014-02-08 10:09:01 +01:00 committed by Jakub Jelinek
parent 451bdd2308
commit 8fcbce729d
12 changed files with 399 additions and 29 deletions

View File

@ -1,3 +1,17 @@
2014-02-08 Jakub Jelinek <jakub@redhat.com>
PR middle-end/60092
* tree-ssa-ccp.c (surely_varying_stmt_p): Don't return true
if TYPE_ATTRIBUTES (gimple_call_fntype ()) contain
assume_aligned or alloc_align attributes.
(bit_value_assume_aligned): Add ATTR, PTRVAL and ALLOC_ALIGN
arguments. Handle also assume_aligned and alloc_align attributes.
(evaluate_stmt): Adjust bit_value_assume_aligned caller.
Handle calls to functions with assume_aligned or alloc_align
attributes.
* doc/extend.texi: Document assume_aligned and alloc_align
attributes.
2014-02-08 Terry Guo <terry.guo@arm.com>
* doc/invoke.texi: Document ARM -march=armv7e-m.

View File

@ -1,3 +1,13 @@
2014-02-08 Jakub Jelinek <jakub@redhat.com>
PR middle-end/60092
* c-common.c (handle_alloc_size_attribute): Use tree_fits_uhwi_p
and tree_to_uhwi.
(handle_alloc_align_attribute, handle_assume_aligned_attribute): New
functions.
(c_common_attribute_table): Add alloc_align and assume_aligned
attributes.
2014-02-06 Marek Polacek <polacek@redhat.com>
PR c/60087

View File

@ -366,6 +366,8 @@ static tree handle_warn_unused_result_attribute (tree *, tree, tree, int,
static tree handle_sentinel_attribute (tree *, tree, tree, int, bool *);
static tree handle_type_generic_attribute (tree *, tree, tree, int, bool *);
static tree handle_alloc_size_attribute (tree *, tree, tree, int, bool *);
static tree handle_alloc_align_attribute (tree *, tree, tree, int, bool *);
static tree handle_assume_aligned_attribute (tree *, tree, tree, int, bool *);
static tree handle_target_attribute (tree *, tree, tree, int, bool *);
static tree handle_optimize_attribute (tree *, tree, tree, int, bool *);
static tree ignore_attribute (tree *, tree, tree, int, bool *);
@ -766,6 +768,10 @@ const struct attribute_spec c_common_attribute_table[] =
handle_omp_declare_simd_attribute, false },
{ "omp declare target", 0, 0, true, false, false,
handle_omp_declare_target_attribute, false },
{ "alloc_align", 1, 1, false, true, true,
handle_alloc_align_attribute, false },
{ "assume_aligned", 1, 2, false, true, true,
handle_assume_aligned_attribute, false },
{ NULL, 0, 0, false, false, false, NULL, false }
};
@ -8043,10 +8049,9 @@ handle_alloc_size_attribute (tree *node, tree ARG_UNUSED (name), tree args,
&& TREE_CODE (position) != FUNCTION_DECL)
position = default_conversion (position);
if (TREE_CODE (position) != INTEGER_CST
|| TREE_INT_CST_HIGH (position)
|| TREE_INT_CST_LOW (position) < 1
|| TREE_INT_CST_LOW (position) > arg_count )
if (!tree_fits_uhwi_p (position)
|| !arg_count
|| !IN_RANGE (tree_to_uhwi (position), 1, arg_count))
{
warning (OPT_Wattributes,
"alloc_size parameter outside range");
@ -8057,6 +8062,55 @@ handle_alloc_size_attribute (tree *node, tree ARG_UNUSED (name), tree args,
return NULL_TREE;
}
/* Handle a "alloc_align" attribute; arguments as in
struct attribute_spec.handler. */
static tree
handle_alloc_align_attribute (tree *node, tree, tree args, int,
bool *no_add_attrs)
{
unsigned arg_count = type_num_arguments (*node);
tree position = TREE_VALUE (args);
if (position && TREE_CODE (position) != IDENTIFIER_NODE)
position = default_conversion (position);
if (!tree_fits_uhwi_p (position)
|| !arg_count
|| !IN_RANGE (tree_to_uhwi (position), 1, arg_count))
{
warning (OPT_Wattributes,
"alloc_align parameter outside range");
*no_add_attrs = true;
return NULL_TREE;
}
return NULL_TREE;
}
/* Handle a "assume_aligned" attribute; arguments as in
struct attribute_spec.handler. */
static tree
handle_assume_aligned_attribute (tree *, tree, tree args, int,
bool *no_add_attrs)
{
for (; args; args = TREE_CHAIN (args))
{
tree position = TREE_VALUE (args);
if (position && TREE_CODE (position) != IDENTIFIER_NODE
&& TREE_CODE (position) != FUNCTION_DECL)
position = default_conversion (position);
if (TREE_CODE (position) != INTEGER_CST)
{
warning (OPT_Wattributes,
"assume_aligned parameter not integer constant");
*no_add_attrs = true;
return NULL_TREE;
}
}
return NULL_TREE;
}
/* Handle a "fn spec" attribute; arguments as in
struct attribute_spec.handler. */

View File

@ -2154,8 +2154,8 @@ The keyword @code{__attribute__} allows you to specify special
attributes when making a declaration. This keyword is followed by an
attribute specification inside double parentheses. The following
attributes are currently defined for functions on all targets:
@code{aligned}, @code{alloc_size}, @code{noreturn},
@code{returns_twice}, @code{noinline}, @code{noclone},
@code{aligned}, @code{alloc_size}, @code{alloc_align}, @code{assume_aligned},
@code{noreturn}, @code{returns_twice}, @code{noinline}, @code{noclone},
@code{always_inline}, @code{flatten}, @code{pure}, @code{const},
@code{nothrow}, @code{sentinel}, @code{format}, @code{format_arg},
@code{no_instrument_function}, @code{no_split_stack},
@ -2249,6 +2249,46 @@ declares that @code{my_calloc} returns memory of the size given by
the product of parameter 1 and 2 and that @code{my_realloc} returns memory
of the size given by parameter 2.
@item alloc_align
@cindex @code{alloc_align} attribute
The @code{alloc_align} attribute is used to tell the compiler that the
function return value points to memory, where the returned pointer minimum
alignment is given by one of the functions parameters. GCC uses this
information to improve pointer alignment analysis.
The function parameter denoting the allocated alignment is specified by
one integer argument, whose number is the argument of the attribute.
Argument numbering starts at one.
For instance,
@smallexample
void* my_memalign(size_t, size_t) __attribute__((alloc_align(1)))
@end smallexample
@noindent
declares that @code{my_memalign} returns memory with minimum alignment
given by parameter 1.
@item assume_aligned
@cindex @code{assume_aligned} attribute
The @code{assume_aligned} attribute is used to tell the compiler that the
function return value points to memory, where the returned pointer minimum
alignment is given by the first argument.
If the attribute has two arguments, the second argument is misalignment offset.
For instance
@smallexample
void* my_alloc1(size_t) __attribute__((assume_aligned(16)))
void* my_alloc2(size_t) __attribute__((assume_aligned(32, 8)))
@end smallexample
@noindent
declares that @code{my_alloc1} returns 16-byte aligned pointer and
that @code{my_alloc2} returns a pointer whose value modulo 32 is equal
to 8.
@item always_inline
@cindex @code{always_inline} function attribute
Generally, functions are not inlined unless optimization is specified.

View File

@ -1,3 +1,13 @@
2014-02-08 Jakub Jelinek <jakub@redhat.com>
PR middle-end/60092
* gcc.dg/attr-alloc_align-1.c: New test.
* gcc.dg/attr-alloc_align-2.c: New test.
* gcc.dg/attr-alloc_align-3.c: New test.
* gcc.dg/attr-assume_aligned-1.c: New test.
* gcc.dg/attr-assume_aligned-2.c: New test.
* gcc.dg/attr-assume_aligned-3.c: New test.
2014-02-08 Jakub Jelinek <jakub@redhat.com>
PR target/60077

View File

@ -0,0 +1,39 @@
/* { dg-do compile } */
/* { dg-options "-O3" } */
double *my_alloc1 (int len, int align) __attribute__((__alloc_align__ (2)));
double *my_alloc2 (int align, int len) __attribute__((alloc_align (1)));
void
test1 (int len, int align)
{
int i;
double *__restrict o1 = my_alloc1 (len, 32);
double *__restrict o2 = my_alloc1 (len, 32);
double *__restrict o3 = my_alloc1 (len, 32);
double *__restrict i1 = my_alloc1 (len, 32);
double *__restrict i2 = my_alloc1 (len, align);
for (i = 0; i < len; ++i)
{
o1[i] = i1[i] * i2[i];
o2[i] = i1[i] + i2[i];
o3[i] = i1[i] - i2[i];
}
}
void
test2 (int len, int align)
{
int i;
double *__restrict o1 = my_alloc2 (32, len);
double *__restrict o2 = my_alloc2 (32, len);
double *__restrict o3 = my_alloc2 (32, len);
double *__restrict i1 = my_alloc2 (32, len);
double *__restrict i2 = my_alloc2 (align, len);
for (i = 0; i < len; ++i)
{
o1[i] = i1[i] * i2[i];
o2[i] = i1[i] + i2[i];
o3[i] = i1[i] - i2[i];
}
}

View File

@ -0,0 +1,10 @@
/* { dg-do compile } */
int i;
void *f1 (int) __attribute__((alloc_align (1)));
void *f2 (int, int, int) __attribute__((alloc_align (3)));
void *f3 (void) __attribute__((alloc_align)); /* { dg-error "wrong number of arguments specified" } */
void *f4 (int, int) __attribute__((alloc_align (1, 2))); /* { dg-error "wrong number of arguments specified" } */
void *f5 (void) __attribute__((alloc_align (i))); /* { dg-warning "outside range" } */
void *f6 (int) __attribute__((alloc_align (0))); /* { dg-warning "outside range" } */
void *f7 (int) __attribute__((alloc_align (2))); /* { dg-warning "outside range" } */

View File

@ -0,0 +1,56 @@
/* { dg-do compile } */
/* { dg-options "-O2 -fdump-tree-optimized" } */
char *my_alloc1 (int len, int align) __attribute__((__alloc_align__ (2)));
char *my_alloc2 (int align, int len) __attribute__((alloc_align (1)));
int
test1 (int len)
{
int i;
char *p = my_alloc1 (len, 32);
return ((__INTPTR_TYPE__) p) & 31;
}
int
test2 (int len)
{
int i;
char *p = my_alloc2 (32, len);
return ((__INTPTR_TYPE__) p) & 31;
}
int
test3 (int len)
{
int i;
char *p = my_alloc1 (len, 16);
return ((__INTPTR_TYPE__) p) & 15;
}
int
test4 (int len)
{
int i;
char *p = my_alloc2 (16, len);
return ((__INTPTR_TYPE__) p) & 15;
}
int
test5 (int len, int align)
{
int i;
char *p = my_alloc1 (len, align);
return ((__INTPTR_TYPE__) p) & 15;
}
int
test6 (int len, int align)
{
int i;
char *p = my_alloc2 (align, len);
return ((__INTPTR_TYPE__) p) & 15;
}
/* { dg-final { scan-tree-dump-times "return 0" 4 "optimized" } } */
/* { dg-final { cleanup-tree-dump "optimized" } } */

View File

@ -0,0 +1,39 @@
/* { dg-do compile } */
/* { dg-options "-O3" } */
double *my_alloc1 (int len) __attribute__((__assume_aligned__ (16)));
double *my_alloc2 (int len) __attribute__((__assume_aligned__ (32, 16)));
void
test1 (int len)
{
int i;
double *__restrict o1 = my_alloc1 (len);
double *__restrict o2 = my_alloc1 (len);
double *__restrict o3 = my_alloc1 (len);
double *__restrict i1 = my_alloc1 (len);
double *__restrict i2 = my_alloc1 (len);
for (i = 0; i < len; ++i)
{
o1[i] = i1[i] * i2[i];
o2[i] = i1[i] + i2[i];
o3[i] = i1[i] - i2[i];
}
}
void
test2 (int len)
{
int i;
double *__restrict o1 = my_alloc2 (len);
double *__restrict o2 = my_alloc2 (len);
double *__restrict o3 = my_alloc2 (len);
double *__restrict i1 = my_alloc2 (len);
double *__restrict i2 = my_alloc2 (len);
for (i = 0; i < len; ++i)
{
o1[i] = i1[i] * i2[i];
o2[i] = i1[i] + i2[i];
o3[i] = i1[i] - i2[i];
}
}

View File

@ -0,0 +1,8 @@
/* { dg-do compile } */
int i;
void *f1 (void) __attribute__((assume_aligned (32)));
void *f2 (void) __attribute__((assume_aligned (16, 4)));
void *f3 (void) __attribute__((assume_aligned)); /* { dg-error "wrong number of arguments specified" } */
void *f4 (void) __attribute__((assume_aligned (32, 16, 8))); /* { dg-error "wrong number of arguments specified" } */
void *f5 (void) __attribute__((assume_aligned (i))); /* { dg-warning "integer constant" } */

View File

@ -0,0 +1,24 @@
/* { dg-do compile } */
/* { dg-options "-O2 -fdump-tree-optimized" } */
char *my_alloc1 (int len) __attribute__((__assume_aligned__ (32)));
char *my_alloc2 (int len) __attribute__((assume_aligned (32, 4)));
int
test1 (int len)
{
int i;
char *p = my_alloc1 (len);
return ((__INTPTR_TYPE__) p) & 31;
}
int
test2 (int len)
{
int i;
char *p = my_alloc2 (len);
return (((__INTPTR_TYPE__) p) & 31) != 4;
}
/* { dg-final { scan-tree-dump-times "return 0" 2 "optimized" } } */
/* { dg-final { cleanup-tree-dump "optimized" } } */

View File

@ -738,13 +738,18 @@ surely_varying_stmt_p (gimple stmt)
return true;
/* If it is a call and does not return a value or is not a
builtin and not an indirect call, it is varying. */
builtin and not an indirect call or a call to function with
assume_aligned/alloc_align attribute, it is varying. */
if (is_gimple_call (stmt))
{
tree fndecl;
tree fndecl, fntype = gimple_call_fntype (stmt);
if (!gimple_call_lhs (stmt)
|| ((fndecl = gimple_call_fndecl (stmt)) != NULL_TREE
&& !DECL_BUILT_IN (fndecl)))
&& !DECL_BUILT_IN (fndecl)
&& !lookup_attribute ("assume_aligned",
TYPE_ATTRIBUTES (fntype))
&& !lookup_attribute ("alloc_align",
TYPE_ATTRIBUTES (fntype))))
return true;
}
@ -1476,40 +1481,86 @@ bit_value_binop (enum tree_code code, tree type, tree rhs1, tree rhs2)
return val;
}
/* Return the propagation value when applying __builtin_assume_aligned to
its arguments. */
/* Return the propagation value for __builtin_assume_aligned
and functions with assume_aligned or alloc_aligned attribute.
For __builtin_assume_aligned, ATTR is NULL_TREE,
for assume_aligned attribute ATTR is non-NULL and ALLOC_ALIGNED
is false, for alloc_aligned attribute ATTR is non-NULL and
ALLOC_ALIGNED is true. */
static prop_value_t
bit_value_assume_aligned (gimple stmt)
bit_value_assume_aligned (gimple stmt, tree attr, prop_value_t ptrval,
bool alloc_aligned)
{
tree ptr = gimple_call_arg (stmt, 0), align, misalign = NULL_TREE;
tree type = TREE_TYPE (ptr);
tree align, misalign = NULL_TREE, type;
unsigned HOST_WIDE_INT aligni, misaligni = 0;
prop_value_t ptrval = get_value_for_expr (ptr, true);
prop_value_t alignval;
double_int value, mask;
prop_value_t val;
if (attr == NULL_TREE)
{
tree ptr = gimple_call_arg (stmt, 0);
type = TREE_TYPE (ptr);
ptrval = get_value_for_expr (ptr, true);
}
else
{
tree lhs = gimple_call_lhs (stmt);
type = TREE_TYPE (lhs);
}
if (ptrval.lattice_val == UNDEFINED)
return ptrval;
gcc_assert ((ptrval.lattice_val == CONSTANT
&& TREE_CODE (ptrval.value) == INTEGER_CST)
|| ptrval.mask.is_minus_one ());
align = gimple_call_arg (stmt, 1);
if (!tree_fits_uhwi_p (align))
return ptrval;
aligni = tree_to_uhwi (align);
if (aligni <= 1
|| (aligni & (aligni - 1)) != 0)
return ptrval;
if (gimple_call_num_args (stmt) > 2)
if (attr == NULL_TREE)
{
misalign = gimple_call_arg (stmt, 2);
if (!tree_fits_uhwi_p (misalign))
return ptrval;
misaligni = tree_to_uhwi (misalign);
if (misaligni >= aligni)
/* Get aligni and misaligni from __builtin_assume_aligned. */
align = gimple_call_arg (stmt, 1);
if (!tree_fits_uhwi_p (align))
return ptrval;
aligni = tree_to_uhwi (align);
if (gimple_call_num_args (stmt) > 2)
{
misalign = gimple_call_arg (stmt, 2);
if (!tree_fits_uhwi_p (misalign))
return ptrval;
misaligni = tree_to_uhwi (misalign);
}
}
else
{
/* Get aligni and misaligni from assume_aligned or
alloc_align attributes. */
if (TREE_VALUE (attr) == NULL_TREE)
return ptrval;
attr = TREE_VALUE (attr);
align = TREE_VALUE (attr);
if (!tree_fits_uhwi_p (align))
return ptrval;
aligni = tree_to_uhwi (align);
if (alloc_aligned)
{
if (aligni == 0 || aligni > gimple_call_num_args (stmt))
return ptrval;
align = gimple_call_arg (stmt, aligni - 1);
if (!tree_fits_uhwi_p (align))
return ptrval;
aligni = tree_to_uhwi (align);
}
else if (TREE_CHAIN (attr) && TREE_VALUE (TREE_CHAIN (attr)))
{
misalign = TREE_VALUE (TREE_CHAIN (attr));
if (!tree_fits_uhwi_p (misalign))
return ptrval;
misaligni = tree_to_uhwi (misalign);
}
}
if (aligni <= 1 || (aligni & (aligni - 1)) != 0 || misaligni >= aligni)
return ptrval;
align = build_int_cst_type (type, -aligni);
alignval = get_value_for_expr (align, true);
bit_value_binop_1 (BIT_AND_EXPR, type, &value, &mask,
@ -1708,12 +1759,27 @@ evaluate_stmt (gimple stmt)
break;
case BUILT_IN_ASSUME_ALIGNED:
val = bit_value_assume_aligned (stmt);
val = bit_value_assume_aligned (stmt, NULL_TREE, val, false);
break;
default:;
}
}
if (is_gimple_call (stmt) && gimple_call_lhs (stmt))
{
tree fntype = gimple_call_fntype (stmt);
if (fntype)
{
tree attrs = lookup_attribute ("assume_aligned",
TYPE_ATTRIBUTES (fntype));
if (attrs)
val = bit_value_assume_aligned (stmt, attrs, val, false);
attrs = lookup_attribute ("alloc_align",
TYPE_ATTRIBUTES (fntype));
if (attrs)
val = bit_value_assume_aligned (stmt, attrs, val, true);
}
}
is_constant = (val.lattice_val == CONSTANT);
}