On Fri, 7 Feb 2014, Jakub Jelinek wrote: > 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).
Ah, indeed. Didn't think about the snapshots... > > Will you be working on a glibc patch? > > I'll tell our glibc folks. Thanks. Updated patch looks ok. Richard. > 2014-02-07 Jakub Jelinek <ja...@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 > > -- Richard Biener <rguent...@suse.de> SUSE / SUSE Labs SUSE LINUX Products GmbH - Nuernberg - AG Nuernberg - HRB 16746 GF: Jeff Hawn, Jennifer Guild, Felix Imend"orffer