This patch is the beginning stages of my revamp of the builtin function handling in the rs6000 port. When I added target attribute support in GCC 4.6, I ran out of time in tackling enabling builtin functions if the user says a function is to be compiled for a different target machine. These patches are not yet ready for checkin, but I was wondering if the general concept is ok before I start converting all of the builtins.
At this point, I'm just trying to move all of information in the various bdesc arrays and *_init_builtin functions into rs6000-builtins.def. I have created a new macro RS6000_BUILTIN_ARGS that takes all of the information I think we will need to create the new builtin. While it would be nice to have a grand new machine independent way of doing this, but I figure that can come in time. I would prefer not to miss the 4.7 window. At the moment, I just have __builtin_altivec_vadd{ubm,uhm,fp} converted to the new style. So any comments on just these pieces before I start creating all of the builtins. One thing that irrates me about the current setup is the fact that we are out of target_flags bits, and paired/spe builtins have special handling. I haven't gone through the rs6000.opts to see if we can squeeze 2 more bits in the masks, but I provided an alternate solution here that does not need them to be re-integrated. 2011-08-12 Michael Meissner <meiss...@linux.vnet.ibm.com> * config/rs6000/rs6000-builtin.def (RS6000_BUILTIN_ARGS): New macros to encode types within the macros, so that we can process the builtins as a single table, instead of being spread out over several different functions. Start converting the Altivec add functions to the new scheme. (RS6000_BUILTIN_ARG0): Ditto. (RS6000_BUILTIN_ARG1): Ditto. (RS6000_BUILTIN_ARG2): Ditto. (RS6000_BUILTIN_ARG2): Ditto. (RS6000_BUILTIN_ARG3): Ditto. * config/rs6000/rs6000.c (rs6000_builtin_decls_init): New static array to record the builtin functions that have been created, even if the current machine does not support the function. (builtin_info): New array to hold all of the information for creating builtin functions. (builtin_classify): Delete, merge into builtin_info. (def_builtin): Use builtin_info instead of builtin_classify. (bdesc_2arg): Remove Altivec add functions moved over to the new format. (rs6000_expand_builtin): Add support for generating builtin functions from a table. (rs6000_create_builtin): New function, create a builtin function from the table of builtins. (rs6000_table_init_builtins): New function to create the builtins that are in the builtin table. * config/rs6000/rs6000.h (enum rs6000_btmask): Masks of the various conditions for creating builtins. (enum rs6000_btc): Add typedef. (enum rs6000_builtin_type_index): Ditto. (enum rs6000_builtins): Define RS6000_BUILTIN_ARGS for new builtin handling. (RS6000_BTI_NONE): New name for no type provided. (RS6000_BTI_NOT_OPAQUE): Map into RS6000_BTI_NONE. -- Michael Meissner, IBM 5 Technology Place Drive, M/S 2757, Westford, MA 01886-3141, USA meiss...@linux.vnet.ibm.com fax +1 (978) 399-6899
Index: gcc/config/rs6000/rs6000-builtin.def =================================================================== --- gcc/config/rs6000/rs6000-builtin.def (revision 177676) +++ gcc/config/rs6000/rs6000-builtin.def (working copy) @@ -26,7 +26,74 @@ /* Before including this file, two macros must be defined: RS6000_BUILTIN -- 2 arguments, the enum name, and classification - RS6000_BUILTIN_EQUATE -- 2 arguments, enum name and value */ + RS6000_BUILTIN_EQUATE -- 2 arguments, enum name and value + + RS6000_BUILTIN_ARGS -- 9 arguments: + argument 1, the string name of the builtin function + argument 2, the enum name + argument 3, the insn code for the function that implments this + argument 4, the classification + argument 5, the mask for whether the builtin should be used + argument 6, RS6000_BTI index for return value + arguments 7-9, RS6000_BTI index for 1-3 arguments. */ + +#ifndef RS6000_BUILTIN_ARG0 +#define RS6000_BUILTIN_ARG0(STR, NAME, ICODE, CLASS, MASK, RET) \ + RS6000_BUILTIN_ARGS(STR, \ + NAME, \ + ICODE, \ + CLASS, \ + MASK, \ + RET, \ + RS6000_BTI_NONE, \ + RS6000_BTI_NONE, \ + RS6000_BTI_NONE) +#endif + +#ifndef RS6000_BUILTIN_ARG1 +#define RS6000_BUILTIN_ARG1(STR, NAME, ICODE, CLASS, MASK, RET, ARG1) \ + RS6000_BUILTIN_ARGS(STR, \ + NAME, \ + ICODE, \ + CLASS, \ + MASK, \ + RET, \ + ARG1, \ + RS6000_BTI_NONE, \ + RS6000_BTI_NONE) +#endif + +#ifndef RS6000_BUILTIN_ARG2 +#define RS6000_BUILTIN_ARG2(STR, NAME, ICODE, CLASS, MASK, RET, ARG1, ARG2) \ + RS6000_BUILTIN_ARGS(STR, \ + NAME, \ + ICODE, \ + CLASS, \ + MASK, \ + RET, \ + ARG1, \ + ARG2, \ + RS6000_BTI_NONE) +#endif + +#ifndef RS6000_BUILTIN_ARG3 +#define RS6000_BUILTIN_ARG3(STR, NAME, ICODE, CLASS, MASK, RET, A1, A2, A3) \ + RS6000_BUILTIN_ARGS(STR, \ + NAME, \ + ICODE, \ + CLASS, \ + MASK, \ + RET, \ + A1, \ + A2, \ + A3) +#endif + +/* For now, convert new macro into old macro. */ +#ifndef RS6000_BUILTIN_ARGS +#define RS6000_BUILTIN_ARGS(STR, NAME, ICODE, CLASS, MASK, RET, A1, A2, A3) \ + RS6000_BUILTIN(NAME, CLASS) +#endif /* AltiVec builtins. */ RS6000_BUILTIN(ALTIVEC_BUILTIN_ST_INTERNAL_4si, RS6000_BTC_MEM) @@ -41,10 +108,50 @@ RS6000_BUILTIN(ALTIVEC_BUILTIN_ST_INTERN RS6000_BUILTIN(ALTIVEC_BUILTIN_LD_INTERNAL_2df, RS6000_BTC_MEM) RS6000_BUILTIN(ALTIVEC_BUILTIN_ST_INTERNAL_2di, RS6000_BTC_MEM) RS6000_BUILTIN(ALTIVEC_BUILTIN_LD_INTERNAL_2di, RS6000_BTC_MEM) + +RS6000_BUILTIN_ARG2("__builtin_altivec_vaddubm", + ALTIVEC_BUILTIN_VADDUBM, + CODE_FOR_addv16qi3, + RS6000_BTC_CONST, + RS6000_BTM_ALTIVEC, + RS6000_BTI_V16QI, + RS6000_BTI_V16QI, + RS6000_BTI_V16QI) + +RS6000_BUILTIN_ARG2("__builtin_altivec_vadduhm", + ALTIVEC_BUILTIN_VADDUHM, + CODE_FOR_addv8hi3, + RS6000_BTC_CONST, + RS6000_BTM_ALTIVEC, + RS6000_BTI_V8HI, + RS6000_BTI_V8HI, + RS6000_BTI_V8HI) + +RS6000_BUILTIN_ARG2("__builtin_altivec_vadduwm", + ALTIVEC_BUILTIN_VADDUWM, + CODE_FOR_addv4si3, + RS6000_BTC_CONST, + RS6000_BTM_ALTIVEC, + RS6000_BTI_V4SI, + RS6000_BTI_V4SI, + RS6000_BTI_V4SI) + +RS6000_BUILTIN_ARG2("__builtin_altivec_vaddfp", + ALTIVEC_BUILTIN_VADDFP, + CODE_FOR_addv4sf3, + RS6000_BTC_CONST, + RS6000_BTM_ALTIVEC, + RS6000_BTI_V4SF, + RS6000_BTI_V4SF, + RS6000_BTI_V4SF) + +#if 0 RS6000_BUILTIN(ALTIVEC_BUILTIN_VADDUBM, RS6000_BTC_CONST) RS6000_BUILTIN(ALTIVEC_BUILTIN_VADDUHM, RS6000_BTC_CONST) RS6000_BUILTIN(ALTIVEC_BUILTIN_VADDUWM, RS6000_BTC_CONST) RS6000_BUILTIN(ALTIVEC_BUILTIN_VADDFP, RS6000_BTC_FP_PURE) +#endif + RS6000_BUILTIN(ALTIVEC_BUILTIN_VADDCUW, RS6000_BTC_CONST) RS6000_BUILTIN(ALTIVEC_BUILTIN_VADDUBS, RS6000_BTC_CONST) RS6000_BUILTIN(ALTIVEC_BUILTIN_VADDSBS, RS6000_BTC_SAT) Index: gcc/config/rs6000/rs6000.c =================================================================== --- gcc/config/rs6000/rs6000.c (revision 177719) +++ gcc/config/rs6000/rs6000.c (working copy) @@ -195,10 +195,15 @@ static enum insn_code rs6000_vector_relo static int dbg_cost_ctrl; -/* Built in types. */ +/* Built in types and declarations. */ tree rs6000_builtin_types[RS6000_BTI_MAX]; tree rs6000_builtin_decls[RS6000_BUILTIN_COUNT]; +/* Built in declarations that have been created at any time, but may or may not + be in rs6000_builtin_declars, depending on the current target attribute or + pragma. */ +tree rs6000_builtin_decls_init[RS6000_BUILTIN_COUNT]; + /* Flag to say the TOC is initialized */ int toc_initialized; char toc_label_name[10]; @@ -848,19 +853,43 @@ struct processor_costs ppca2_cost = { }; -/* Table that classifies rs6000 builtin functions (pure, const, etc.). */ +/* Table that classifies rs6000 builtin functions in terms of effect(pure, + const, etc.), what target machine they run on, and describes their + return value and arguments. */ + +typedef struct rs6000_builtin_info +{ + const char *string; /* function name as a string. */ + enum insn_code icode; /* rtl insn that implemnts builtin. */ + rs6000_btc_type classify; /* builtin classification. */ + rs6000_btm_type mask; /* mask to define builtin. */ + rs6000_bti_type ret; /* return type. */ + rs6000_bti_type args[3]; /* function args. */ +} rs6000_btinfo_type; + #undef RS6000_BUILTIN #undef RS6000_BUILTIN_EQUATE -#define RS6000_BUILTIN(NAME, TYPE) TYPE, +#undef RS6000_BUILTIN_ARGS + +#define RS6000_BUILTIN(NAME, CLASS) \ + { NULL, CODE_FOR_nothing, CLASS, RS6000_BTM_NONE, RS6000_BTI_NONE, \ + { RS6000_BTI_NONE, RS6000_BTI_NONE, RS6000_BTI_NONE } }, + #define RS6000_BUILTIN_EQUATE(NAME, VALUE) -static const enum rs6000_btc builtin_classify[(int)RS6000_BUILTIN_COUNT] = +#define RS6000_BUILTIN_ARGS(STR, NAME, ICODE, CLASS, MASK, RET, A1, A2, A3) \ + { STR, ICODE, CLASS, MASK, RET, { A1, A2, A3 }}, + + +static +const rs6000_btinfo_type builtin_info[(int)RS6000_BUILTIN_COUNT] = { #include "rs6000-builtin.def" }; #undef RS6000_BUILTIN #undef RS6000_BUILTIN_EQUATE +#undef RS6000_BUILTIN_ARGS /* Support for -mveclibabi=<xxx> to control which vector library to use. */ static tree (*rs6000_veclib_handler) (tree, tree, tree); @@ -1000,6 +1029,7 @@ static enum machine_mode rs6000_preferre static void def_builtin (int, const char *, tree, int); static bool rs6000_vector_alignment_reachable (const_tree, bool); static void rs6000_init_builtins (void); +static void rs6000_table_init_builtins (void); static tree rs6000_builtin_decl (unsigned, bool); static rtx rs6000_expand_unop_builtin (enum insn_code, tree, rtx); @@ -9427,7 +9457,7 @@ def_builtin (int mask, const char *name, NULL, NULL_TREE); gcc_assert (code >= 0 && code < (int)RS6000_BUILTIN_COUNT); - switch (builtin_classify[code]) + switch (builtin_info[code].classify) { default: gcc_unreachable (); @@ -9607,10 +9637,12 @@ static const struct builtin_description static struct builtin_description bdesc_2arg[] = { +#if 0 { MASK_ALTIVEC, CODE_FOR_addv16qi3, "__builtin_altivec_vaddubm", ALTIVEC_BUILTIN_VADDUBM }, { MASK_ALTIVEC, CODE_FOR_addv8hi3, "__builtin_altivec_vadduhm", ALTIVEC_BUILTIN_VADDUHM }, { MASK_ALTIVEC, CODE_FOR_addv4si3, "__builtin_altivec_vadduwm", ALTIVEC_BUILTIN_VADDUWM }, { MASK_ALTIVEC, CODE_FOR_addv4sf3, "__builtin_altivec_vaddfp", ALTIVEC_BUILTIN_VADDFP }, +#endif { MASK_ALTIVEC, CODE_FOR_altivec_vaddcuw, "__builtin_altivec_vaddcuw", ALTIVEC_BUILTIN_VADDCUW }, { MASK_ALTIVEC, CODE_FOR_altivec_vaddubs, "__builtin_altivec_vaddubs", ALTIVEC_BUILTIN_VADDUBS }, { MASK_ALTIVEC, CODE_FOR_altivec_vaddsbs, "__builtin_altivec_vaddsbs", ALTIVEC_BUILTIN_VADDSBS }, @@ -11942,6 +11974,24 @@ rs6000_expand_builtin (tree exp, rtx tar gcc_assert (TARGET_ALTIVEC || TARGET_VSX || TARGET_SPE || TARGET_PAIRED_FLOAT); + /* Handle builtins created from the builtins table. */ + if (fcode < RS6000_BUILTIN_COUNT && rs6000_builtin_decls[fcode] + && builtin_info[fcode].icode != CODE_FOR_nothing) + { + /* Figure out if it is a ternary, binary, or unary op. */ + if (builtin_info[fcode].args[2] != RS6000_BTI_NONE) + return rs6000_expand_ternop_builtin (builtin_info[fcode].icode, + exp, target); + + else if (builtin_info[fcode].args[1] != RS6000_BTI_NONE) + return rs6000_expand_binop_builtin (builtin_info[fcode].icode, + exp, target); + + else if (builtin_info[fcode].args[0] != RS6000_BTI_NONE) + return rs6000_expand_unop_builtin (builtin_info[fcode].icode, + exp, target); + } + /* Handle simple unary operations. */ d = (struct builtin_description *) bdesc_1arg; for (i = 0; i < ARRAY_SIZE (bdesc_1arg); i++, d++) @@ -12219,6 +12269,156 @@ rs6000_init_builtins (void) #ifdef SUBTARGET_INIT_BUILTINS SUBTARGET_INIT_BUILTINS; #endif + + /* Initialize all of the builtins described in rs6000-builtins.def. */ + rs6000_table_init_builtins (); +} + +/* Create a builtin described in the builtin_info table. */ + +static void +rs6000_create_builtin (size_t index, unsigned flags) +{ + enum rs6000_builtins bindex = (enum rs6000_builtins)index; + const rs6000_btinfo_type *bt = &builtin_info[index]; + size_t n_args; + int ret = bt->ret; + tree ret_type; + enum machine_mode ret_mode; + enum machine_mode args_mode[3] = { VOIDmode, VOIDmode, VOIDmode }; + tree fndecl; + + gcc_assert (bt->string != NULL); + + /* Validate return type. */ + gcc_assert (IN_RANGE (ret, 0, (int)RS6000_BTI_MAX)); + ret_type = rs6000_builtin_types[ret]; + gcc_assert (ret_type != NULL_TREE); + ret_mode = TYPE_MODE (ret_type); + + /* Validate and count arguments. */ + for (n_args = 0; n_args < 3; n_args++) + { + int arg = bt->args[n_args]; + tree arg_type; + + gcc_assert (IN_RANGE (arg, 0, (int)RS6000_BTI_MAX)); + if (arg == (int)RS6000_BTI_NONE) + break; + + arg_type = rs6000_builtin_types[arg]; + gcc_assert (arg_type != NULL_TREE); + args_mode[n_args] = TYPE_MODE (arg_type); + } + + fndecl = builtin_function_type (ret_mode, args_mode[0], args_mode[1], + args_mode[2], bindex, bt->string); + + def_builtin (flags, bt->string, fndecl, bindex); + rs6000_builtin_decls_init[index] = rs6000_builtin_decls[index]; +} + +/* Define all builtins defined in the builtin_info table. This function might + be called multiple times, if the user uses target attributes or pragmas to + change the machine for a particular function, so we will need to make sure + we don't create more than one declaration. */ + +static void +rs6000_table_init_builtins (void) +{ + size_t i; + unsigned int mask = 0; + unsigned int flags = 0; + + /* Figure out the current mask of functions that should be allowed. */ + if (TARGET_ALTIVEC) + { + mask |= RS6000_BTM_ALTIVEC; + flags |= MASK_ALTIVEC; + } + + if (TARGET_ALTIVEC && rs6000_cpu == PROCESSOR_CELL) + { + mask |= RS6000_BTM_CELL; + flags |= MASK_ALTIVEC; + } + + if (TARGET_VSX) + { + mask |= RS6000_BTM_VSX; + flags |= MASK_VSX; + } + + if (TARGET_PAIRED_FLOAT) + { + mask |= RS6000_BTM_PAIRED; + flags |= target_flags; + } + + if (TARGET_SPE) + { + mask |= RS6000_BTM_SPE; + flags |= target_flags; + } + + if (TARGET_FRE) + { + mask |= RS6000_BTM_FRE; + flags |= MASK_POPCNTB; + } + + if (TARGET_FRES) + { + mask |= RS6000_BTM_FRES; + flags |= MASK_PPC_GFXOPT; + } + + if (TARGET_FRSQRTE) + { + mask |= RS6000_BTM_FRSQRTE; + flags |= MASK_PPC_GFXOPT; + } + + if (TARGET_FRSQRTES) + { + mask |= RS6000_BTM_FRSQRTES; + flags |= MASK_POPCNTB; + } + + if (TARGET_POPCNTD) + { + mask |= RS6000_BTM_POPCNTD; + flags |= MASK_POPCNTD; + } + + if (TARGET_POWERPC) + { + mask |= RS6000_BTM_BSWAP16; + flags |= MASK_POWERPC; + } + + /* Go through the builtins, looking for possibile candidates, skipping + functions that don't have the arguments, etc. in the table. */ + for (i = 0; i < ARRAY_SIZE (builtin_info); i++) + { + const rs6000_btinfo_type *bt = &builtin_info[i]; + if (bt->mask != RS6000_BTM_NONE) + { + /* Function not availble in current machine? */ + if ((bt->mask & mask) == 0) + rs6000_builtin_decls[i] = NULL_TREE; + + else + { + /* Do we need to create the function? */ + if (!rs6000_builtin_decls_init[i]) + rs6000_create_builtin (i, flags); + + else + rs6000_builtin_decls[i] = rs6000_builtin_decls_init[i]; + } + } + } } /* Returns the rs6000 builtin decl for CODE. */ Index: gcc/config/rs6000/rs6000.h =================================================================== --- gcc/config/rs6000/rs6000.h (revision 177719) +++ gcc/config/rs6000/rs6000.h (working copy) @@ -2254,15 +2254,35 @@ extern char rs6000_reg_names[][8]; /* re /* General flags. */ extern int frame_pointer_needed; +/* Masks for builtin functions. We don't use target_flags masks, because we + are out of bits in target_flags, and some switches are now separate + variables. */ + +typedef enum rs6000_btmask +{ + RS6000_BTM_NONE = 0x00000000, /* no mask */ + RS6000_BTM_ALTIVEC = 0x00000001, /* machine supports Altivec. */ + RS6000_BTM_VSX = 0x00000002, /* machine supports VSX. */ + RS6000_BTM_CELL = 0x00000004, /* machine is a cell with Altivec. */ + RS6000_BTM_PAIRED = 0x00000008, /* machine supports paired insns. */ + RS6000_BTM_SPE = 0x00000010, /* machine supports SPE. */ + RS6000_BTM_FRE = 0x00000020, /* machine has FRE insn. */ + RS6000_BTM_FRES = 0x00000040, /* machine has FRES insn. */ + RS6000_BTM_FRSQRTE = 0x00000080, /* machine has FRSQRTE insn. */ + RS6000_BTM_FRSQRTES = 0x00000100, /* machine has FRSQRTES insn. */ + RS6000_BTM_POPCNTD = 0x00000200, /* machine has ISA 2.06 insns. */ + RS6000_BTM_BSWAP16 = 0x00000400 /* machine has 16-bit swap */ +} rs6000_btm_type; + /* Classification of the builtin functions to properly set the declaration tree flags. */ -enum rs6000_btc +typedef enum rs6000_btc { RS6000_BTC_MISC, /* assume builtin can do anything */ RS6000_BTC_CONST, /* builtin is a 'const' function. */ RS6000_BTC_PURE, /* builtin is a 'pure' function. */ RS6000_BTC_FP_PURE /* builtin is 'pure' if rounding math. */ -}; +} rs6000_btc_type; /* Convenience macros to document the instruction type. */ #define RS6000_BTC_MEM RS6000_BTC_MISC /* load/store touches memory */ @@ -2270,8 +2290,11 @@ enum rs6000_btc #undef RS6000_BUILTIN #undef RS6000_BUILTIN_EQUATE +#undef RS6000_BUILTIN_ARGS + #define RS6000_BUILTIN(NAME, TYPE) NAME, #define RS6000_BUILTIN_EQUATE(NAME, VALUE) NAME = VALUE, +#define RS6000_BUILTIN_ARGS(S, N, IC, CLASS, MASK, RET, A1, A2, A3) N, enum rs6000_builtins { @@ -2282,10 +2305,13 @@ enum rs6000_builtins #undef RS6000_BUILTIN #undef RS6000_BUILTIN_EQUATE +#undef RS6000_BUILTIN_ARGS -enum rs6000_builtin_type_index +typedef enum rs6000_builtin_type_index { - RS6000_BTI_NOT_OPAQUE, + RS6000_BTI_NONE, +#define RS6000_BTI_NOT_OPAQUE RS6000_BTI_NONE /* old name */ + RS6000_BTI_opaque_V2SI, RS6000_BTI_opaque_V2SF, RS6000_BTI_opaque_p_V2SI, @@ -2329,7 +2355,7 @@ enum rs6000_builtin_type_index RS6000_BTI_double, /* double_type_node */ RS6000_BTI_void, /* void_type_node */ RS6000_BTI_MAX -}; +} rs6000_bti_type; #define opaque_V2SI_type_node (rs6000_builtin_types[RS6000_BTI_opaque_V2SI])