This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
Re: [PATCH] Add alloc_align and assume_aligned attributes (PR middle-end/60092)
- From: Jakub Jelinek <jakub at redhat dot com>
- To: Richard Biener <rguenther at suse dot de>
- Cc: gcc-patches at gcc dot gnu dot org
- Date: Fri, 7 Feb 2014 14:30:06 +0100
- Subject: Re: [PATCH] Add alloc_align and assume_aligned attributes (PR middle-end/60092)
- Authentication-results: sourceware.org; auth=none
- References: <20140206154149 dot GW12671 at tucnak dot redhat dot com> <alpine dot LSU dot 2 dot 11 dot 1402070947220 dot 29326 at zhemvz dot fhfr dot qr>
- Reply-to: Jakub Jelinek <jakub at redhat dot com>
On Fri, Feb 07, 2014 at 10:02:29AM +0100, Richard Biener wrote:
> > + if (TREE_CODE (position) != INTEGER_CST
> > + || TREE_INT_CST_HIGH (position)
> > + || TREE_INT_CST_LOW (position) < 1
> > + || TREE_INT_CST_LOW (position) > arg_count)
>
> You make it easier for wide-int folks if you use tree_fits_uhwi_p
> and tree_to_uhwi ...
That was just a copy of the code from alloc_size, changed that too.
> > +static prop_value_t
> > +bit_value_alloc_assume_aligned_attribute (gimple stmt, tree attr,
> > + prop_value_t ptrval,
> > + bool alloc_aligned)
> > +{
>
> This function is very similar to the existing bit_value_assume_aligned
> which asks for some factoring? Like share the tails once you've
> figured out align and misalign values?
I've added support for the two attributes and original
__builtin_assume_aligned in just one function, will test it momentarily.
> I wonder if we want to backport support for these attributes
> to 4.8 (and 4.7?).
I think it doesn't help much. At least glibc will need to conditionalize
the attributes on gcc version anyway, so they will be used only for GCC >=
4.9 anyway (unless we'd do it for >= 4.8.4 or something, can't be 4.8.3,
because, while it hasn't been released, current 4.8 branch snapshot mark
themselves as 4.8.3 in the patchlevel).
> Will you be working on a glibc patch?
I'll tell our glibc folks.
2014-02-07 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.
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.
--- gcc/c-family/c-common.c.jj 2014-02-07 11:44:07.114924852 +0100
+++ gcc/c-family/c-common.c 2014-02-07 11:58:23.996841044 +0100
@@ -366,6 +366,8 @@ static tree handle_warn_unused_result_at
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_att
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,16 +8049,62 @@ handle_alloc_size_attribute (tree *node,
&& 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)
+ || !IN_RANGE (tree_to_uhwi (position), 1, arg_count))
{
warning (OPT_Wattributes,
"alloc_size parameter outside range");
*no_add_attrs = true;
return NULL_TREE;
}
+ }
+ 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)
+ || !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;
}
--- gcc/tree-ssa-ccp.c.jj 2014-02-07 11:46:16.296610648 +0100
+++ gcc/tree-ssa-ccp.c 2014-02-07 12:09:57.705818787 +0100
@@ -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, tr
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))
+ /* Get aligni and misaligni from __builtin_assume_aligned. */
+ align = gimple_call_arg (stmt, 1);
+ if (!tree_fits_uhwi_p (align))
return ptrval;
- misaligni = tree_to_uhwi (misalign);
- if (misaligni >= aligni)
+ 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);
}
--- gcc/doc/extend.texi.jj 2014-02-07 11:44:05.843926848 +0100
+++ gcc/doc/extend.texi 2014-02-07 11:53:54.472485819 +0100
@@ -2154,8 +2154,8 @@ The keyword @code{__attribute__} allows
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 m
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.
--- gcc/testsuite/gcc.dg/attr-alloc_align-1.c.jj 2014-02-07 11:53:54.473485822 +0100
+++ gcc/testsuite/gcc.dg/attr-alloc_align-1.c 2014-02-07 11:53:54.473485822 +0100
@@ -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];
+ }
+}
--- gcc/testsuite/gcc.dg/attr-alloc_align-2.c.jj 2014-02-07 11:53:54.473485822 +0100
+++ gcc/testsuite/gcc.dg/attr-alloc_align-2.c 2014-02-07 11:53:54.473485822 +0100
@@ -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" } */
--- gcc/testsuite/gcc.dg/attr-alloc_align-3.c.jj 2014-02-07 11:53:54.474485825 +0100
+++ gcc/testsuite/gcc.dg/attr-alloc_align-3.c 2014-02-07 11:53:54.474485825 +0100
@@ -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" } } */
--- gcc/testsuite/gcc.dg/attr-assume_aligned-1.c.jj 2014-02-07 11:53:54.474485825 +0100
+++ gcc/testsuite/gcc.dg/attr-assume_aligned-1.c 2014-02-07 11:53:54.474485825 +0100
@@ -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];
+ }
+}
--- gcc/testsuite/gcc.dg/attr-assume_aligned-2.c.jj 2014-02-07 11:53:54.474485825 +0100
+++ gcc/testsuite/gcc.dg/attr-assume_aligned-2.c 2014-02-07 11:53:54.474485825 +0100
@@ -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" } */
--- gcc/testsuite/gcc.dg/attr-assume_aligned-3.c.jj 2014-02-07 11:53:54.474485825 +0100
+++ gcc/testsuite/gcc.dg/attr-assume_aligned-3.c 2014-02-07 11:53:54.474485825 +0100
@@ -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" } } */
Jakub