- This patch is prepare for add more logic into increase_alignment pass, which is not related to vectorization.
gcc/ChangeLog * Makefile.in (OBJS): Add ipa-increase-alignment.o. * tree-vectorizer.c (get_vec_alignment_for_type): Moved to ipa-increase-alignment.cc. (type_align_map): Ditto. (get_vec_alignment_for_array_type): Ditto. (get_vec_alignment_for_record_type): Ditto. (increase_alignment): Ditto. (pass_data_ipa_increase_alignment): Ditto. (pass_ipa_increase_alignment): Ditto. (make_pass_ipa_increase_alignment): Ditto. * ipa-increase-alignment.cc (get_vec_alignment_for_type) Moved from ipa-increase-alignment.cc. (type_align_map): Ditto. (get_vec_alignment_for_array_type): Ditto. (get_vec_alignment_for_record_type): Ditto. (increase_alignment): Ditto. (pass_data_ipa_increase_alignment): Ditto. (pass_ipa_increase_alignment): Ditto. (make_pass_ipa_increase_alignment): Ditto. --- gcc/Makefile.in | 1 + gcc/ipa-increase-alignment.cc | 223 ++++++++++++++++++++++++++++++++++ gcc/tree-vectorizer.c | 189 ---------------------------- 3 files changed, 224 insertions(+), 189 deletions(-) create mode 100644 gcc/ipa-increase-alignment.cc diff --git a/gcc/Makefile.in b/gcc/Makefile.in index fa9923bb270..2c11252911c 100644 --- a/gcc/Makefile.in +++ b/gcc/Makefile.in @@ -1408,6 +1408,7 @@ OBJS = \ ipa-inline.o \ ipa-comdats.o \ ipa-visibility.o \ + ipa-increase-alignment.o \ ipa-inline-analysis.o \ ipa-inline-transform.o \ ipa-predicate.o \ diff --git a/gcc/ipa-increase-alignment.cc b/gcc/ipa-increase-alignment.cc new file mode 100644 index 00000000000..6e34124bc03 --- /dev/null +++ b/gcc/ipa-increase-alignment.cc @@ -0,0 +1,223 @@ +/* Increase alignment + Copyright (C) 2003-2020 Free Software Foundation, Inc. + Contributed by Dorit Naishlos <do...@il.ibm.com> + +This file is part of GCC. + +GCC is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation; either version 3, or (at your option) any later +version. + +GCC is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with GCC; see the file COPYING3. If not see +<http://www.gnu.org/licenses/>. */ + +#include "config.h" +#include "system.h" +#include "coretypes.h" +#include "backend.h" +#include "target.h" +#include "tree.h" +#include "gimple.h" +#include "tree-pass.h" +#include "cgraph.h" +#include "fold-const.h" +#include "gimple-iterator.h" +#include "tree-cfg.h" +#include "cfgloop.h" +#include "tree-vectorizer.h" +#include "tm_p.h" + +/* Increase alignment of global arrays to improve vectorization potential. + TODO: + - Consider also structs that have an array field. + - Use ipa analysis to prune arrays that can't be vectorized? + This should involve global alignment analysis and in the future also + array padding. */ + +static unsigned get_vec_alignment_for_type (tree); +static hash_map<tree, unsigned> *type_align_map; + +/* Return alignment of array's vector type corresponding to scalar type. + 0 if no vector type exists. */ +static unsigned +get_vec_alignment_for_array_type (tree type) +{ + gcc_assert (TREE_CODE (type) == ARRAY_TYPE); + poly_uint64 array_size, vector_size; + + tree scalar_type = strip_array_types (type); + tree vectype = get_related_vectype_for_scalar_type (VOIDmode, scalar_type); + if (!vectype + || !poly_int_tree_p (TYPE_SIZE (type), &array_size) + || !poly_int_tree_p (TYPE_SIZE (vectype), &vector_size) + || maybe_lt (array_size, vector_size)) + return 0; + + return TYPE_ALIGN (vectype); +} + +/* Return alignment of field having maximum alignment of vector type + corresponding to it's scalar type. For now, we only consider fields whose + offset is a multiple of it's vector alignment. + 0 if no suitable field is found. */ +static unsigned +get_vec_alignment_for_record_type (tree type) +{ + gcc_assert (TREE_CODE (type) == RECORD_TYPE); + + unsigned max_align = 0, alignment; + HOST_WIDE_INT offset; + tree offset_tree; + + if (TYPE_PACKED (type)) + return 0; + + unsigned *slot = type_align_map->get (type); + if (slot) + return *slot; + + for (tree field = first_field (type); + field != NULL_TREE; + field = DECL_CHAIN (field)) + { + /* Skip if not FIELD_DECL or if alignment is set by user. */ + if (TREE_CODE (field) != FIELD_DECL + || DECL_USER_ALIGN (field) + || DECL_ARTIFICIAL (field)) + continue; + + /* We don't need to process the type further if offset is variable, + since the offsets of remaining members will also be variable. */ + if (TREE_CODE (DECL_FIELD_OFFSET (field)) != INTEGER_CST + || TREE_CODE (DECL_FIELD_BIT_OFFSET (field)) != INTEGER_CST) + break; + + /* Similarly stop processing the type if offset_tree + does not fit in unsigned HOST_WIDE_INT. */ + offset_tree = bit_position (field); + if (!tree_fits_uhwi_p (offset_tree)) + break; + + offset = tree_to_uhwi (offset_tree); + alignment = get_vec_alignment_for_type (TREE_TYPE (field)); + + /* Get maximum alignment of vectorized field/array among those members + whose offset is multiple of the vector alignment. */ + if (alignment + && (offset % alignment == 0) + && (alignment > max_align)) + max_align = alignment; + } + + type_align_map->put (type, max_align); + return max_align; +} + +/* Return alignment of vector type corresponding to decl's scalar type + or 0 if it doesn't exist or the vector alignment is lesser than + decl's alignment. */ +static unsigned +get_vec_alignment_for_type (tree type) +{ + if (type == NULL_TREE) + return 0; + + gcc_assert (TYPE_P (type)); + + static unsigned alignment = 0; + switch (TREE_CODE (type)) + { + case ARRAY_TYPE: + alignment = get_vec_alignment_for_array_type (type); + break; + case RECORD_TYPE: + alignment = get_vec_alignment_for_record_type (type); + break; + default: + alignment = 0; + break; + } + + return (alignment > TYPE_ALIGN (type)) ? alignment : 0; +} + +/* Entry point to increase_alignment pass. */ +static unsigned int +increase_alignment (void) +{ + varpool_node *vnode; + + vect_location = dump_user_location_t (); + type_align_map = new hash_map<tree, unsigned>; + + /* Increase the alignment of all global arrays for vectorization. */ + FOR_EACH_DEFINED_VARIABLE (vnode) + { + tree decl = vnode->decl; + unsigned int alignment; + + if ((decl_in_symtab_p (decl) + && !symtab_node::get (decl)->can_increase_alignment_p ()) + || DECL_USER_ALIGN (decl) || DECL_ARTIFICIAL (decl)) + continue; + + alignment = get_vec_alignment_for_type (TREE_TYPE (decl)); + if (alignment && vect_can_force_dr_alignment_p (decl, alignment)) + { + vnode->increase_alignment (alignment); + if (dump_enabled_p ()) + dump_printf (MSG_NOTE, "Increasing alignment of decl: %T\n", decl); + } + } + + delete type_align_map; + return 0; +} + + +namespace { + +const pass_data pass_data_ipa_increase_alignment = +{ + SIMPLE_IPA_PASS, /* type */ + "increase_alignment", /* name */ + OPTGROUP_LOOP | OPTGROUP_VEC, /* optinfo_flags */ + TV_IPA_OPT, /* tv_id */ + 0, /* properties_required */ + 0, /* properties_provided */ + 0, /* properties_destroyed */ + 0, /* todo_flags_start */ + 0, /* todo_flags_finish */ +}; + +class pass_ipa_increase_alignment : public simple_ipa_opt_pass +{ +public: + pass_ipa_increase_alignment (gcc::context *ctxt) + : simple_ipa_opt_pass (pass_data_ipa_increase_alignment, ctxt) + {} + + /* opt_pass methods: */ + virtual bool gate (function *) + { + return flag_section_anchors && flag_tree_loop_vectorize; + } + + virtual unsigned int execute (function *) { return increase_alignment (); } + +}; // class pass_ipa_increase_alignment + +} // anon namespace + +simple_ipa_opt_pass * +make_pass_ipa_increase_alignment (gcc::context *ctxt) +{ + return new pass_ipa_increase_alignment (ctxt); +} diff --git a/gcc/tree-vectorizer.c b/gcc/tree-vectorizer.c index 8f9444d58a3..e9caf91e174 100644 --- a/gcc/tree-vectorizer.c +++ b/gcc/tree-vectorizer.c @@ -1340,195 +1340,6 @@ make_pass_slp_vectorize (gcc::context *ctxt) return new pass_slp_vectorize (ctxt); } - -/* Increase alignment of global arrays to improve vectorization potential. - TODO: - - Consider also structs that have an array field. - - Use ipa analysis to prune arrays that can't be vectorized? - This should involve global alignment analysis and in the future also - array padding. */ - -static unsigned get_vec_alignment_for_type (tree); -static hash_map<tree, unsigned> *type_align_map; - -/* Return alignment of array's vector type corresponding to scalar type. - 0 if no vector type exists. */ -static unsigned -get_vec_alignment_for_array_type (tree type) -{ - gcc_assert (TREE_CODE (type) == ARRAY_TYPE); - poly_uint64 array_size, vector_size; - - tree scalar_type = strip_array_types (type); - tree vectype = get_related_vectype_for_scalar_type (VOIDmode, scalar_type); - if (!vectype - || !poly_int_tree_p (TYPE_SIZE (type), &array_size) - || !poly_int_tree_p (TYPE_SIZE (vectype), &vector_size) - || maybe_lt (array_size, vector_size)) - return 0; - - return TYPE_ALIGN (vectype); -} - -/* Return alignment of field having maximum alignment of vector type - corresponding to it's scalar type. For now, we only consider fields whose - offset is a multiple of it's vector alignment. - 0 if no suitable field is found. */ -static unsigned -get_vec_alignment_for_record_type (tree type) -{ - gcc_assert (TREE_CODE (type) == RECORD_TYPE); - - unsigned max_align = 0, alignment; - HOST_WIDE_INT offset; - tree offset_tree; - - if (TYPE_PACKED (type)) - return 0; - - unsigned *slot = type_align_map->get (type); - if (slot) - return *slot; - - for (tree field = first_field (type); - field != NULL_TREE; - field = DECL_CHAIN (field)) - { - /* Skip if not FIELD_DECL or if alignment is set by user. */ - if (TREE_CODE (field) != FIELD_DECL - || DECL_USER_ALIGN (field) - || DECL_ARTIFICIAL (field)) - continue; - - /* We don't need to process the type further if offset is variable, - since the offsets of remaining members will also be variable. */ - if (TREE_CODE (DECL_FIELD_OFFSET (field)) != INTEGER_CST - || TREE_CODE (DECL_FIELD_BIT_OFFSET (field)) != INTEGER_CST) - break; - - /* Similarly stop processing the type if offset_tree - does not fit in unsigned HOST_WIDE_INT. */ - offset_tree = bit_position (field); - if (!tree_fits_uhwi_p (offset_tree)) - break; - - offset = tree_to_uhwi (offset_tree); - alignment = get_vec_alignment_for_type (TREE_TYPE (field)); - - /* Get maximum alignment of vectorized field/array among those members - whose offset is multiple of the vector alignment. */ - if (alignment - && (offset % alignment == 0) - && (alignment > max_align)) - max_align = alignment; - } - - type_align_map->put (type, max_align); - return max_align; -} - -/* Return alignment of vector type corresponding to decl's scalar type - or 0 if it doesn't exist or the vector alignment is lesser than - decl's alignment. */ -static unsigned -get_vec_alignment_for_type (tree type) -{ - if (type == NULL_TREE) - return 0; - - gcc_assert (TYPE_P (type)); - - static unsigned alignment = 0; - switch (TREE_CODE (type)) - { - case ARRAY_TYPE: - alignment = get_vec_alignment_for_array_type (type); - break; - case RECORD_TYPE: - alignment = get_vec_alignment_for_record_type (type); - break; - default: - alignment = 0; - break; - } - - return (alignment > TYPE_ALIGN (type)) ? alignment : 0; -} - -/* Entry point to increase_alignment pass. */ -static unsigned int -increase_alignment (void) -{ - varpool_node *vnode; - - vect_location = dump_user_location_t (); - type_align_map = new hash_map<tree, unsigned>; - - /* Increase the alignment of all global arrays for vectorization. */ - FOR_EACH_DEFINED_VARIABLE (vnode) - { - tree decl = vnode->decl; - unsigned int alignment; - - if ((decl_in_symtab_p (decl) - && !symtab_node::get (decl)->can_increase_alignment_p ()) - || DECL_USER_ALIGN (decl) || DECL_ARTIFICIAL (decl)) - continue; - - alignment = get_vec_alignment_for_type (TREE_TYPE (decl)); - if (alignment && vect_can_force_dr_alignment_p (decl, alignment)) - { - vnode->increase_alignment (alignment); - if (dump_enabled_p ()) - dump_printf (MSG_NOTE, "Increasing alignment of decl: %T\n", decl); - } - } - - delete type_align_map; - return 0; -} - - -namespace { - -const pass_data pass_data_ipa_increase_alignment = -{ - SIMPLE_IPA_PASS, /* type */ - "increase_alignment", /* name */ - OPTGROUP_LOOP | OPTGROUP_VEC, /* optinfo_flags */ - TV_IPA_OPT, /* tv_id */ - 0, /* properties_required */ - 0, /* properties_provided */ - 0, /* properties_destroyed */ - 0, /* todo_flags_start */ - 0, /* todo_flags_finish */ -}; - -class pass_ipa_increase_alignment : public simple_ipa_opt_pass -{ -public: - pass_ipa_increase_alignment (gcc::context *ctxt) - : simple_ipa_opt_pass (pass_data_ipa_increase_alignment, ctxt) - {} - - /* opt_pass methods: */ - virtual bool gate (function *) - { - return flag_section_anchors && flag_tree_loop_vectorize; - } - - virtual unsigned int execute (function *) { return increase_alignment (); } - -}; // class pass_ipa_increase_alignment - -} // anon namespace - -simple_ipa_opt_pass * -make_pass_ipa_increase_alignment (gcc::context *ctxt) -{ - return new pass_ipa_increase_alignment (ctxt); -} - /* If the condition represented by T is a comparison or the SSA name result of a comparison, extract the comparison's operands. Represent T as NE_EXPR <T, 0> otherwise. */ -- 2.25.2