From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 27647 invoked by alias); 18 Apr 2011 11:10:24 -0000 Received: (qmail 27638 invoked by uid 22791); 18 Apr 2011 11:10:22 -0000 X-SWARE-Spam-Status: No, hits=-2.3 required=5.0 tests=AWL,BAYES_00,DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,FREEMAIL_FROM,RCVD_IN_DNSWL_LOW,RFC_ABUSE_POST,T_TO_NO_BRKTS_FREEMAIL X-Spam-Check-By: sourceware.org Received: from mail-wy0-f175.google.com (HELO mail-wy0-f175.google.com) (74.125.82.175) by sourceware.org (qpsmtpd/0.43rc1) with ESMTP; Mon, 18 Apr 2011 11:09:48 +0000 Received: by wye20 with SMTP id 20so4595360wye.20 for ; Mon, 18 Apr 2011 04:09:46 -0700 (PDT) MIME-Version: 1.0 Received: by 10.227.202.149 with SMTP id fe21mr4855653wbb.205.1303124986508; Mon, 18 Apr 2011 04:09:46 -0700 (PDT) Received: by 10.227.0.140 with HTTP; Mon, 18 Apr 2011 04:09:46 -0700 (PDT) In-Reply-To: References: Date: Mon, 18 Apr 2011 11:54:00 -0000 Message-ID: Subject: Re: [5/9] Main target-independent support for direct interleaving From: Richard Guenther To: gcc-patches@gcc.gnu.org, patches@linaro.org, richard.sandiford@linaro.org Content-Type: text/plain; charset=ISO-8859-1 Content-Transfer-Encoding: quoted-printable X-IsSubscribed: yes Mailing-List: contact gcc-patches-help@gcc.gnu.org; run by ezmlm Precedence: bulk List-Id: List-Archive: List-Post: List-Help: Sender: gcc-patches-owner@gcc.gnu.org X-SW-Source: 2011-04/txt/msg01371.txt.bz2 On Tue, Apr 12, 2011 at 3:59 PM, Richard Sandiford wrote: > This patch adds vec_load_lanes and vec_store_lanes optabs for instructions > like NEON's vldN and vstN. =A0The optabs are defined this way because the > vectors must be allocated to a block of consecutive registers. > > Tested on x86_64-linux-gnu and arm-linux-gnueabi. =A0OK to install? > > Richard > > > gcc/ > =A0 =A0 =A0 =A0* doc/md.texi (vec_load_lanes, vec_store_lanes): Document. > =A0 =A0 =A0 =A0* optabs.h (COI_vec_load_lanes, COI_vec_store_lanes): New > =A0 =A0 =A0 =A0convert_optab_index values. > =A0 =A0 =A0 =A0(vec_load_lanes_optab, vec_store_lanes_optab): New convert= optabs. > =A0 =A0 =A0 =A0* genopinit.c (optabs): Initialize the new optabs. > =A0 =A0 =A0 =A0* internal-fn.def (LOAD_LANES, STORE_LANES): New internal = functions. > =A0 =A0 =A0 =A0* internal-fn.c (get_multi_vector_move, expand_LOAD_LANES) > =A0 =A0 =A0 =A0(expand_STORE_LANES): New functions. > =A0 =A0 =A0 =A0* tree.h (build_simple_array_type): Declare. > =A0 =A0 =A0 =A0* tree.c (build_simple_array_type): New function. > =A0 =A0 =A0 =A0* tree-vectorizer.h (vect_model_store_cost): Add a bool ar= gument. > =A0 =A0 =A0 =A0(vect_model_load_cost): Likewise. > =A0 =A0 =A0 =A0(vect_store_lanes_supported, vect_load_lanes_supported) > =A0 =A0 =A0 =A0(vect_record_strided_load_vectors): Declare. > =A0 =A0 =A0 =A0* tree-vect-data-refs.c (vect_lanes_optab_supported_p) > =A0 =A0 =A0 =A0(vect_store_lanes_supported, vect_load_lanes_supported): N= ew functions. > =A0 =A0 =A0 =A0(vect_transform_strided_load): Split out statement recordi= ng into... > =A0 =A0 =A0 =A0(vect_record_strided_load_vectors): ...this new function. > =A0 =A0 =A0 =A0* tree-vect-stmts.c (create_vector_array, read_vector_arra= y) > =A0 =A0 =A0 =A0(write_vector_array, create_array_ref): New functions. > =A0 =A0 =A0 =A0(vect_model_store_cost): Add store_lanes_p argument. > =A0 =A0 =A0 =A0(vect_model_load_cost): Add load_lanes_p argument. > =A0 =A0 =A0 =A0(vectorizable_store): Try to use store-lanes functions for > =A0 =A0 =A0 =A0interleaved stores. > =A0 =A0 =A0 =A0(vectorizable_load): Likewise load-lanes and loads. > =A0 =A0 =A0 =A0* tree-vect-slp.c (vect_get_and_check_slp_defs) > =A0 =A0 =A0 =A0(vect_build_slp_tree): > > Index: gcc/doc/md.texi > =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D > --- gcc/doc/md.texi =A0 =A0 2011-04-12 12:16:46.000000000 +0100 > +++ gcc/doc/md.texi =A0 =A0 2011-04-12 14:48:28.000000000 +0100 > @@ -3846,6 +3846,48 @@ into consecutive memory locations. =A0Oper > =A0consecutive memory locations, operand 1 is the first register, and > =A0operand 2 is a constant: the number of consecutive registers. > > +@cindex @code{vec_load_lanes@var{m}@var{n}} instruction pattern > +@item @samp{vec_load_lanes@var{m}@var{n}} > +Perform an interleaved load of several vectors from memory operand 1 > +into register operand 0. =A0Both operands have mode @var{m}. =A0The regi= ster > +operand is viewed as holding consecutive vectors of mode @var{n}, > +while the memory operand is a flat array that contains the same number > +of elements. =A0The operation is equivalent to: > + > +@smallexample > +int c =3D GET_MODE_SIZE (@var{m}) / GET_MODE_SIZE (@var{n}); > +for (j =3D 0; j < GET_MODE_NUNITS (@var{n}); j++) > + =A0for (i =3D 0; i < c; i++) > + =A0 =A0operand0[i][j] =3D operand1[j * c + i]; > +@end smallexample > + > +For example, @samp{vec_load_lanestiv4hi} loads 8 16-bit values > +from memory into a register of mode @samp{TI}@. =A0The register > +contains two consecutive vectors of mode @samp{V4HI}@. So vec_load_lanestiv2qi would load ... ? c =3D=3D 8 here. Intuitively such operation would have adjacent blocks of siv2qi memory. But maybe you want to constrain the mode size to GET_MODE_SIZE (@var{n}) * GET_MODE_NUNITS (@var{n})? In which case the mode m is redundant? You could specify that we load NUNITS adjacent vectors into an integer mode of appropriate size. > +This pattern can only be used if: > +@smallexample > +TARGET_ARRAY_MODE_SUPPORTED_P (@var{n}, @var{c}) > +@end smallexample > +is true. =A0GCC assumes that, if a target supports this kind of > +instruction for some mode @var{n}, it also supports unaligned > +loads for vectors of mode @var{n}. > + > +@cindex @code{vec_store_lanes@var{m}@var{n}} instruction pattern > +@item @samp{vec_store_lanes@var{m}@var{n}} > +Equivalent to @samp{vec_load_lanes@var{m}@var{n}}, with the memory > +and register operands reversed. =A0That is, the instruction is > +equivalent to: > + > +@smallexample > +int c =3D GET_MODE_SIZE (@var{m}) / GET_MODE_SIZE (@var{n}); > +for (j =3D 0; j < GET_MODE_NUNITS (@var{n}); j++) > + =A0for (i =3D 0; i < c; i++) > + =A0 =A0operand0[j * c + i] =3D operand1[i][j]; > +@end smallexample > + > +for a memory operand 0 and register operand 1. > + > =A0@cindex @code{vec_set@var{m}} instruction pattern > =A0@item @samp{vec_set@var{m}} > =A0Set given field in the vector value. =A0Operand 0 is the vector to mod= ify, > Index: gcc/optabs.h > =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D > --- gcc/optabs.h =A0 =A0 =A0 =A02011-04-12 12:16:46.000000000 +0100 > +++ gcc/optabs.h =A0 =A0 =A0 =A02011-04-12 14:48:28.000000000 +0100 > @@ -578,6 +578,9 @@ enum convert_optab_index > =A0 COI_satfract, > =A0 COI_satfractuns, > > + =A0COI_vec_load_lanes, > + =A0COI_vec_store_lanes, > + Um, they are not really conversion optabs. Any reason they can't use the direct_optab table and path? What are the two modes usually? I don't see how you specify the kind of permutation that is performed on the load - so, why not go the targetm.expand_builtin path instead (well, targetm.expand_internal_fn, of course - or rather targetm.expand_gimple_call which we need anyway for expanding directly from gimple calls at some point). > =A0 COI_MAX > =A0}; > > @@ -598,6 +601,8 @@ #define fract_optab (&convert_optab_tabl > =A0#define fractuns_optab (&convert_optab_table[COI_fractuns]) > =A0#define satfract_optab (&convert_optab_table[COI_satfract]) > =A0#define satfractuns_optab (&convert_optab_table[COI_satfractuns]) > +#define vec_load_lanes_optab (&convert_optab_table[COI_vec_load_lanes]) > +#define vec_store_lanes_optab (&convert_optab_table[COI_vec_store_lanes]) > > =A0/* Contains the optab used for each rtx code. =A0*/ > =A0extern optab code_to_optab[NUM_RTX_CODE + 1]; > Index: gcc/genopinit.c > =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D > --- gcc/genopinit.c =A0 =A0 2011-04-12 12:16:46.000000000 +0100 > +++ gcc/genopinit.c =A0 =A0 2011-04-12 14:48:28.000000000 +0100 > @@ -74,6 +74,8 @@ static const char * const optabs[] =3D > =A0 "set_convert_optab_handler (fractuns_optab, $B, $A, CODE_FOR_$(fractu= ns$Q$a$I$b2$))", > =A0 "set_convert_optab_handler (satfract_optab, $B, $A, CODE_FOR_$(satfra= ct$a$Q$b2$))", > =A0 "set_convert_optab_handler (satfractuns_optab, $B, $A, CODE_FOR_$(sat= fractuns$I$a$Q$b2$))", > + =A0"set_convert_optab_handler (vec_load_lanes_optab, $A, $B, CODE_FOR_$= (vec_load_lanes$a$b$))", > + =A0"set_convert_optab_handler (vec_store_lanes_optab, $A, $B, CODE_FOR_= $(vec_store_lanes$a$b$))", > =A0 "set_optab_handler (add_optab, $A, CODE_FOR_$(add$P$a3$))", > =A0 "set_optab_handler (addv_optab, $A, CODE_FOR_$(add$F$a3$)),\n\ > =A0 =A0 set_optab_handler (add_optab, $A, CODE_FOR_$(add$F$a3$))", > Index: gcc/internal-fn.def > =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D > --- gcc/internal-fn.def 2011-04-12 14:10:42.000000000 +0100 > +++ gcc/internal-fn.def 2011-04-12 14:48:28.000000000 +0100 > @@ -32,3 +32,6 @@ along with GCC; see the file COPYING3. > > =A0 =A0where NAME is the name of the function and FLAGS is a set of > =A0 =A0ECF_* flags. =A0*/ > + > +DEF_INTERNAL_FN (LOAD_LANES, ECF_CONST | ECF_LEAF) > +DEF_INTERNAL_FN (STORE_LANES, ECF_CONST | ECF_LEAF) > Index: gcc/internal-fn.c > =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D > --- gcc/internal-fn.c =A0 2011-04-12 14:10:42.000000000 +0100 > +++ gcc/internal-fn.c =A0 2011-04-12 14:48:28.000000000 +0100 > @@ -41,6 +41,69 @@ #define DEF_INTERNAL_FN(CODE, FLAGS) FLA > =A0 0 > =A0}; > > +/* ARRAY_TYPE is an array of vector modes. =A0Return the associated insn > + =A0 for load-lanes-style optab OPTAB. =A0The insn must exist. =A0*/ > + > +static enum insn_code > +get_multi_vector_move (tree array_type, convert_optab optab) > +{ > + =A0enum insn_code icode; > + =A0enum machine_mode imode; > + =A0enum machine_mode vmode; > + > + =A0gcc_assert (TREE_CODE (array_type) =3D=3D ARRAY_TYPE); > + =A0imode =3D TYPE_MODE (array_type); > + =A0vmode =3D TYPE_MODE (TREE_TYPE (array_type)); > + > + =A0icode =3D convert_optab_handler (optab, imode, vmode); > + =A0gcc_assert (icode !=3D CODE_FOR_nothing); > + =A0return icode; > +} > + > +/* Expand: LHS =3D LOAD_LANES (ARGS[0]). =A0*/ > + > +static void > +expand_LOAD_LANES (tree lhs, tree *args) > +{ > + =A0struct expand_operand ops[2]; > + =A0tree type; > + =A0rtx target, mem; > + > + =A0type =3D TREE_TYPE (lhs); > + > + =A0target =3D expand_expr (lhs, NULL_RTX, VOIDmode, EXPAND_WRITE); > + =A0mem =3D expand_normal (args[0]); > + > + =A0gcc_assert (MEM_P (mem)); > + =A0PUT_MODE (mem, TYPE_MODE (type)); > + > + =A0create_output_operand (&ops[0], target, TYPE_MODE (type)); > + =A0create_fixed_operand (&ops[1], mem); > + =A0expand_insn (get_multi_vector_move (type, vec_load_lanes_optab), 2, = ops); > +} > + > +/* Expand: LHS =3D STORE_LANES (ARGS[0]). =A0*/ > + > +static void > +expand_STORE_LANES (tree lhs, tree *args) > +{ > + =A0struct expand_operand ops[2]; > + =A0tree type; > + =A0rtx target, rhs; > + > + =A0type =3D TREE_TYPE (args[0]); > + > + =A0target =3D expand_expr (lhs, NULL_RTX, VOIDmode, EXPAND_WRITE); > + =A0rhs =3D expand_normal (args[0]); > + > + =A0gcc_assert (MEM_P (target)); > + =A0PUT_MODE (target, TYPE_MODE (type)); > + > + =A0create_fixed_operand (&ops[0], target); > + =A0create_input_operand (&ops[1], rhs, TYPE_MODE (type)); > + =A0expand_insn (get_multi_vector_move (type, vec_store_lanes_optab), 2,= ops); > +} > + > =A0/* Routines to expand each internal function, indexed by function numb= er. > =A0 =A0Each routine has the prototype: > > Index: gcc/tree.h > =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D > --- gcc/tree.h =A02011-04-12 12:16:46.000000000 +0100 > +++ gcc/tree.h =A02011-04-12 14:48:28.000000000 +0100 > @@ -4198,6 +4198,7 @@ extern tree build_type_no_quals (tree); > =A0extern tree build_index_type (tree); > =A0extern tree build_array_type (tree, tree); > =A0extern tree build_nonshared_array_type (tree, tree); > +extern tree build_simple_array_type (tree, unsigned HOST_WIDE_INT); > =A0extern tree build_function_type (tree, tree); > =A0extern tree build_function_type_list (tree, ...); > =A0extern tree build_function_type_skip_args (tree, bitmap); > Index: gcc/tree.c > =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D > --- gcc/tree.c =A02011-04-12 12:16:46.000000000 +0100 > +++ gcc/tree.c =A02011-04-12 14:48:28.000000000 +0100 > @@ -7385,6 +7385,15 @@ build_nonshared_array_type (tree elt_typ > =A0 return build_array_type_1 (elt_type, index_type, false); > =A0} > > +/* Return a representation of ELT_TYPE[NELTS], using indices of type > + =A0 sizetype. =A0*/ > + > +tree > +build_simple_array_type (tree elt_type, unsigned HOST_WIDE_INT nelts) build_array_type_nelts The rest looks ok to me. Richard.