From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 64278 invoked by alias); 10 Nov 2015 11:12:53 -0000 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 Received: (qmail 64244 invoked by uid 89); 10 Nov 2015 11:12:52 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-1.1 required=5.0 tests=AWL,BAYES_20,FREEMAIL_FROM,RCVD_IN_DNSWL_LOW,SPF_PASS autolearn=ham version=3.3.2 X-HELO: mail-yk0-f181.google.com Received: from mail-yk0-f181.google.com (HELO mail-yk0-f181.google.com) (209.85.160.181) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with (AES128-GCM-SHA256 encrypted) ESMTPS; Tue, 10 Nov 2015 11:12:43 +0000 Received: by ykba77 with SMTP id a77so12436531ykb.2 for ; Tue, 10 Nov 2015 03:12:41 -0800 (PST) MIME-Version: 1.0 X-Received: by 10.13.202.141 with SMTP id m135mr2142288ywd.305.1447153961476; Tue, 10 Nov 2015 03:12:41 -0800 (PST) Received: by 10.37.93.11 with HTTP; Tue, 10 Nov 2015 03:12:41 -0800 (PST) In-Reply-To: <87bnb6ro5t.fsf@e105548-lin.cambridge.arm.com> References: <87bnb6ro5t.fsf@e105548-lin.cambridge.arm.com> Date: Tue, 10 Nov 2015 11:12:00 -0000 Message-ID: Subject: Re: Add basic support for direct_optab internal functions From: Richard Biener To: GCC Patches , richard.sandiford@arm.com Content-Type: text/plain; charset=UTF-8 X-IsSubscribed: yes X-SW-Source: 2015-11/txt/msg01185.txt.bz2 On Sat, Nov 7, 2015 at 1:26 PM, Richard Sandiford wrote: > This patch adds a concept of internal functions that map directly to an > optab (here called "direct internal functions"). The function can only > be used if the associated optab can be used. > > We currently have four functions like that: > > - LOAD_LANES > - STORE_LANES > - MASK_LOAD > - MASK_STORE > > so the patch converts them to the new infrastructure. These four > all need different types of optabs, but future patches will add > regular unary and binary ones. > > In general we need one or two modes to decide whether an optab is > supported, depending on whether it's a convert_optab or not. > This in turn means that we need up to two types to decide whether > an internal function is supported. The patch records which types > are needed for each internal function, using -1 if the return type > should be used and N>=0 if the type of argument N should be used. > > (LOAD_LANES and STORE_LANES are unusual in that both optab modes > come from the same array type.) > > Tested on x86_64-linux-gnu, aarch64-linux-gnu and arm-linux-gnueabi. > OK to install? Ok. Thanks, Richard. > Thanks, > Richard > > > gcc/ > * coretypes.h (tree_pair): New type. > * internal-fn.def (DEF_INTERNAL_OPTAB_FN): New macro. Use it > for MASK_LOAD, LOAD_LANES, MASK_STORE and STORE_LANES. > * internal-fn.h (direct_internal_fn_info): New structure. > (direct_internal_fn_array): Declare. > (direct_internal_fn_p, direct_internal_fn): New functions. > (direct_internal_fn_types, direct_internal_fn_supported_p): Declare. > * internal-fn.c (not_direct, mask_load_direct, load_lanes_direct) > (mask_store_direct, store_lanes_direct): New macros. > (direct_internal_fn_array) New array. > (get_multi_vector_move): Return the optab handler without asserting > that it is available. > (expand_LOAD_LANES): Rename to... > (expand_load_lanes_optab_fn): ...this and add an optab argument. > (expand_STORE_LANES): Rename to... > (expand_store_lanes_optab_fn): ...this and add an optab argument. > (expand_MASK_LOAD): Rename to... > (expand_mask_load_optab_fn): ...this and add an optab argument. > (expand_MASK_STORE): Rename to... > (expand_mask_store_optab_fn): ...this and add an optab argument. > (direct_internal_fn_types, direct_optab_supported_p) > (multi_vector_optab_supported_p, direct_internal_fn_supported_p) > (direct_internal_fn_supported_p): New functions. > (direct_mask_load_optab_supported_p): New macro. > (direct_load_lanes_optab_supported_p): Likewise. > (direct_mask_store_optab_supported_p): Likewise. > (direct_store_lanes_optab_supported_p): Likewise. > > diff --git a/gcc/coretypes.h b/gcc/coretypes.h > index 3439c38..d4a75db 100644 > --- a/gcc/coretypes.h > +++ b/gcc/coretypes.h > @@ -251,6 +251,8 @@ namespace gcc { > class context; > } > > +typedef std::pair tree_pair; > + > #else > > struct _dont_use_rtx_here_; > diff --git a/gcc/internal-fn.c b/gcc/internal-fn.c > index afbfae8..72536da 100644 > --- a/gcc/internal-fn.c > +++ b/gcc/internal-fn.c > @@ -66,13 +66,27 @@ init_internal_fns () > internal_fn_fnspec_array[IFN_LAST] = 0; > } > > +/* Create static initializers for the information returned by > + direct_internal_fn. */ > +#define not_direct { -2, -2 } > +#define mask_load_direct { -1, -1 } > +#define load_lanes_direct { -1, -1 } > +#define mask_store_direct { 3, 3 } > +#define store_lanes_direct { 0, 0 } > + > +const direct_internal_fn_info direct_internal_fn_array[IFN_LAST + 1] = { > +#define DEF_INTERNAL_FN(CODE, FLAGS, FNSPEC) not_direct, > +#define DEF_INTERNAL_OPTAB_FN(CODE, FLAGS, OPTAB, TYPE) TYPE##_direct, > +#include "internal-fn.def" > + not_direct > +}; > + > /* ARRAY_TYPE is an array of vector modes. Return the associated insn > - for load-lanes-style optab OPTAB. The insn must exist. */ > + for load-lanes-style optab OPTAB, or CODE_FOR_nothing if none. */ > > static enum insn_code > get_multi_vector_move (tree array_type, convert_optab optab) > { > - enum insn_code icode; > machine_mode imode; > machine_mode vmode; > > @@ -80,15 +94,13 @@ get_multi_vector_move (tree array_type, convert_optab optab) > imode = TYPE_MODE (array_type); > vmode = TYPE_MODE (TREE_TYPE (array_type)); > > - icode = convert_optab_handler (optab, imode, vmode); > - gcc_assert (icode != CODE_FOR_nothing); > - return icode; > + return convert_optab_handler (optab, imode, vmode); > } > > -/* Expand LOAD_LANES call STMT. */ > +/* Expand LOAD_LANES call STMT using optab OPTAB. */ > > static void > -expand_LOAD_LANES (gcall *stmt) > +expand_load_lanes_optab_fn (gcall *stmt, convert_optab optab) > { > struct expand_operand ops[2]; > tree type, lhs, rhs; > @@ -106,13 +118,13 @@ expand_LOAD_LANES (gcall *stmt) > > create_output_operand (&ops[0], target, TYPE_MODE (type)); > create_fixed_operand (&ops[1], mem); > - expand_insn (get_multi_vector_move (type, vec_load_lanes_optab), 2, ops); > + expand_insn (get_multi_vector_move (type, optab), 2, ops); > } > > -/* Expand STORE_LANES call STMT. */ > +/* Expand STORE_LANES call STMT using optab OPTAB. */ > > static void > -expand_STORE_LANES (gcall *stmt) > +expand_store_lanes_optab_fn (gcall *stmt, convert_optab optab) > { > struct expand_operand ops[2]; > tree type, lhs, rhs; > @@ -130,7 +142,7 @@ expand_STORE_LANES (gcall *stmt) > > create_fixed_operand (&ops[0], target); > create_input_operand (&ops[1], reg, TYPE_MODE (type)); > - expand_insn (get_multi_vector_move (type, vec_store_lanes_optab), 2, ops); > + expand_insn (get_multi_vector_move (type, optab), 2, ops); > } > > static void > @@ -1867,8 +1879,10 @@ expand_LOOP_VECTORIZED (gcall *) > gcc_unreachable (); > } > > +/* Expand MASK_LOAD call STMT using optab OPTAB. */ > + > static void > -expand_MASK_LOAD (gcall *stmt) > +expand_mask_load_optab_fn (gcall *stmt, direct_optab optab) > { > struct expand_operand ops[3]; > tree type, lhs, rhs, maskt; > @@ -1889,11 +1903,13 @@ expand_MASK_LOAD (gcall *stmt) > create_output_operand (&ops[0], target, TYPE_MODE (type)); > create_fixed_operand (&ops[1], mem); > create_input_operand (&ops[2], mask, TYPE_MODE (TREE_TYPE (maskt))); > - expand_insn (optab_handler (maskload_optab, TYPE_MODE (type)), 3, ops); > + expand_insn (optab_handler (optab, TYPE_MODE (type)), 3, ops); > } > > +/* Expand MASK_STORE call STMT using optab OPTAB. */ > + > static void > -expand_MASK_STORE (gcall *stmt) > +expand_mask_store_optab_fn (gcall *stmt, direct_optab optab) > { > struct expand_operand ops[3]; > tree type, lhs, rhs, maskt; > @@ -1912,7 +1928,7 @@ expand_MASK_STORE (gcall *stmt) > create_fixed_operand (&ops[0], mem); > create_input_operand (&ops[1], reg, TYPE_MODE (type)); > create_input_operand (&ops[2], mask, TYPE_MODE (TREE_TYPE (maskt))); > - expand_insn (optab_handler (maskstore_optab, TYPE_MODE (type)), 3, ops); > + expand_insn (optab_handler (optab, TYPE_MODE (type)), 3, ops); > } > > static void > @@ -2050,6 +2066,104 @@ expand_GOACC_REDUCTION (gcall *stmt ATTRIBUTE_UNUSED) > gcc_unreachable (); > } > > +/* RETURN_TYPE and ARGS are a return type and argument list that are > + in principle compatible with FN (which satisfies direct_internal_fn_p). > + Return the types that should be used to determine whether the > + target supports FN. */ > + > +tree_pair > +direct_internal_fn_types (internal_fn fn, tree return_type, tree *args) > +{ > + const direct_internal_fn_info &info = direct_internal_fn (fn); > + tree type0 = (info.type0 < 0 ? return_type : TREE_TYPE (args[info.type0])); > + tree type1 = (info.type1 < 0 ? return_type : TREE_TYPE (args[info.type1])); > + return tree_pair (type0, type1); > +} > + > +/* CALL is a call whose return type and arguments are in principle > + compatible with FN (which satisfies direct_internal_fn_p). Return the > + types that should be used to determine whether the target supports FN. */ > + > +tree_pair > +direct_internal_fn_types (internal_fn fn, gcall *call) > +{ > + const direct_internal_fn_info &info = direct_internal_fn (fn); > + tree op0 = (info.type0 < 0 > + ? gimple_call_lhs (call) > + : gimple_call_arg (call, info.type0)); > + tree op1 = (info.type1 < 0 > + ? gimple_call_lhs (call) > + : gimple_call_arg (call, info.type1)); > + return tree_pair (TREE_TYPE (op0), TREE_TYPE (op1)); > +} > + > +/* Return true if OPTAB is supported for TYPES (whose modes should be > + the same). Used for simple direct optabs. */ > + > +static bool > +direct_optab_supported_p (direct_optab optab, tree_pair types) > +{ > + machine_mode mode = TYPE_MODE (types.first); > + gcc_checking_assert (mode == TYPE_MODE (types.second)); > + return direct_optab_handler (optab, mode) != CODE_FOR_nothing; > +} > + > +/* Return true if load/store lanes optab OPTAB is supported for > + array type TYPES.first. */ > + > +static bool > +multi_vector_optab_supported_p (convert_optab optab, tree_pair types) > +{ > + return get_multi_vector_move (types.first, optab) != CODE_FOR_nothing; > +} > + > +#define direct_mask_load_optab_supported_p direct_optab_supported_p > +#define direct_load_lanes_optab_supported_p multi_vector_optab_supported_p > +#define direct_mask_store_optab_supported_p direct_optab_supported_p > +#define direct_store_lanes_optab_supported_p multi_vector_optab_supported_p > + > +/* Return true if FN is supported for the types in TYPES. The types > + are those associated with the "type0" and "type1" fields of FN's > + direct_internal_fn_info structure. */ > + > +bool > +direct_internal_fn_supported_p (internal_fn fn, tree_pair types) > +{ > + switch (fn) > + { > +#define DEF_INTERNAL_FN(CODE, FLAGS, FNSPEC) \ > + case IFN_##CODE: break; > +#define DEF_INTERNAL_OPTAB_FN(CODE, FLAGS, OPTAB, TYPE) \ > + case IFN_##CODE: \ > + return direct_##TYPE##_optab_supported_p (OPTAB##_optab, types); > +#include "internal-fn.def" > + > + case IFN_LAST: > + break; > + } > + gcc_unreachable (); > +} > + > +/* Return true if FN is supported for type TYPE. The caller knows that > + the "type0" and "type1" fields of FN's direct_internal_fn_info > + structure are the same. */ > + > +bool > +direct_internal_fn_supported_p (internal_fn fn, tree type) > +{ > + const direct_internal_fn_info &info = direct_internal_fn (fn); > + gcc_checking_assert (info.type0 == info.type1); > + return direct_internal_fn_supported_p (fn, tree_pair (type, type)); > +} > + > +#define DEF_INTERNAL_OPTAB_FN(CODE, FLAGS, OPTAB, TYPE) \ > + static void \ > + expand_##CODE (gcall *stmt) \ > + { \ > + expand_##TYPE##_optab_fn (stmt, OPTAB##_optab); \ > + } > +#include "internal-fn.def" > + > /* Routines to expand each internal function, indexed by function number. > Each routine has the prototype: > > diff --git a/gcc/internal-fn.def b/gcc/internal-fn.def > index d0eb704..a5f6df2 100644 > --- a/gcc/internal-fn.def > +++ b/gcc/internal-fn.def > @@ -26,29 +26,56 @@ along with GCC; see the file COPYING3. If not see > and its operands are more naturally represented as a GIMPLE_CALL > than a GIMPLE_ASSIGN. > > - Each entry in this file has the form: > + Each entry in this file has one of the forms: > > DEF_INTERNAL_FN (NAME, FLAGS, FNSPEC) > + DEF_INTERNAL_OPTAB_FN (NAME, FLAGS, OPTAB, TYPE) > > where NAME is the name of the function, FLAGS is a set of > ECF_* flags and FNSPEC is a string describing functions fnspec. > > + DEF_INTERNAL_OPTAB_FN defines an internal function that maps to a > + direct optab. The function should only be called with a given > + set of types if the associated optab is available for the modes > + of those types. OPTAB says what optab to use (without the trailing > + "_optab") and TYPE categorizes the optab based on its inputs and > + outputs. The possible types of optab are: > + > + - mask_load: currently just maskload > + - load_lanes: currently just vec_load_lanes > + > + - mask_store: currently just maskstore > + - store_lanes: currently just vec_store_lanes > + > Each entry must have a corresponding expander of the form: > > void expand_NAME (gimple_call stmt) > > - where STMT is the statement that performs the call. */ > + where STMT is the statement that performs the call. These are generated > + automatically for optab functions and call out to a function or macro > + called expand__optab_fn. */ > + > +#ifndef DEF_INTERNAL_FN > +#define DEF_INTERNAL_FN(CODE, FLAGS, FNSPEC) > +#endif > + > +#ifndef DEF_INTERNAL_OPTAB_FN > +#define DEF_INTERNAL_OPTAB_FN(NAME, FLAGS, OPTAB, TYPE) \ > + DEF_INTERNAL_FN (NAME, FLAGS | ECF_LEAF, NULL) > +#endif > + > +DEF_INTERNAL_OPTAB_FN (MASK_LOAD, ECF_PURE, maskload, mask_load) > +DEF_INTERNAL_OPTAB_FN (LOAD_LANES, ECF_CONST, vec_load_lanes, load_lanes) > + > +DEF_INTERNAL_OPTAB_FN (MASK_STORE, 0, maskstore, mask_store) > +DEF_INTERNAL_OPTAB_FN (STORE_LANES, ECF_CONST, vec_store_lanes, store_lanes) > > -DEF_INTERNAL_FN (LOAD_LANES, ECF_CONST | ECF_LEAF, NULL) > -DEF_INTERNAL_FN (STORE_LANES, ECF_CONST | ECF_LEAF, NULL) > DEF_INTERNAL_FN (GOMP_SIMD_LANE, ECF_NOVOPS | ECF_LEAF | ECF_NOTHROW, NULL) > DEF_INTERNAL_FN (GOMP_SIMD_VF, ECF_CONST | ECF_LEAF | ECF_NOTHROW, NULL) > DEF_INTERNAL_FN (GOMP_SIMD_LAST_LANE, ECF_CONST | ECF_LEAF | ECF_NOTHROW, NULL) > DEF_INTERNAL_FN (GOMP_SIMD_ORDERED_START, ECF_LEAF | ECF_NOTHROW, NULL) > DEF_INTERNAL_FN (GOMP_SIMD_ORDERED_END, ECF_LEAF | ECF_NOTHROW, NULL) > DEF_INTERNAL_FN (LOOP_VECTORIZED, ECF_NOVOPS | ECF_LEAF | ECF_NOTHROW, NULL) > -DEF_INTERNAL_FN (MASK_LOAD, ECF_PURE | ECF_LEAF, NULL) > -DEF_INTERNAL_FN (MASK_STORE, ECF_LEAF, NULL) > DEF_INTERNAL_FN (ANNOTATE, ECF_CONST | ECF_LEAF | ECF_NOTHROW, NULL) > DEF_INTERNAL_FN (UBSAN_NULL, ECF_LEAF | ECF_NOTHROW, ".R.") > DEF_INTERNAL_FN (UBSAN_BOUNDS, ECF_LEAF | ECF_NOTHROW, NULL) > @@ -87,4 +114,5 @@ DEF_INTERNAL_FN (GOACC_LOOP, ECF_PURE | ECF_NOTHROW, NULL) > /* OpenACC reduction abstraction. See internal-fn.h for usage. */ > DEF_INTERNAL_FN (GOACC_REDUCTION, ECF_NOTHROW | ECF_LEAF, NULL) > > +#undef DEF_INTERNAL_OPTAB_FN > #undef DEF_INTERNAL_FN > diff --git a/gcc/internal-fn.h b/gcc/internal-fn.h > index 20cbd13..31e895e 100644 > --- a/gcc/internal-fn.h > +++ b/gcc/internal-fn.h > @@ -123,6 +123,44 @@ internal_fn_fnspec (enum internal_fn fn) > return internal_fn_fnspec_array[(int) fn]; > } > > +/* Describes an internal function that maps directly to an optab. */ > +struct direct_internal_fn_info > +{ > + /* optabs can be parameterized by one or two modes. These fields describe > + how to select those modes from the types of the return value and > + arguments. A value of -1 says that the mode is determined by the > + return type while a value N >= 0 says that the mode is determined by > + the type of argument N. A value of -2 says that this internal > + function isn't directly mapped to an optab. */ > + signed int type0 : 8; > + signed int type1 : 8; > +}; > + > +extern const direct_internal_fn_info direct_internal_fn_array[IFN_LAST + 1]; > + > +/* Return true if FN is mapped directly to an optab. */ > + > +inline bool > +direct_internal_fn_p (internal_fn fn) > +{ > + return direct_internal_fn_array[fn].type0 >= -1; > +} > + > +/* Return optab information about internal function FN. Only meaningful > + if direct_internal_fn_p (FN). */ > + > +inline const direct_internal_fn_info & > +direct_internal_fn (internal_fn fn) > +{ > + gcc_checking_assert (direct_internal_fn_p (fn)); > + return direct_internal_fn_array[fn]; > +} > + > +extern tree_pair direct_internal_fn_types (internal_fn, tree, tree *); > +extern tree_pair direct_internal_fn_types (internal_fn, gcall *); > +extern bool direct_internal_fn_supported_p (internal_fn, tree_pair); > +extern bool direct_internal_fn_supported_p (internal_fn, tree); > + > extern void expand_internal_call (gcall *); > > #endif >