From: Bill Schmidt Date: Tue, 14 Dec 2021 17:23:32 +0000 (-0600) Subject: rs6000: Remove new_builtins_are_live and dead code it was guarding X-Git-Tag: upstream/12.2.0~2732 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=2cf62ef5aa80e3659a8150a48d93a1d333f1d292;p=platform%2Fupstream%2Fgcc.git rs6000: Remove new_builtins_are_live and dead code it was guarding To allow for a sane switch-over from the old built-in infrastructure to the new, both sets of code have co-existed, with the enabled one under the control of the boolean variable new_builtins_are_live. As a first step in removing the old code, remove this variable and the now-dead code it was guarding. 2021-12-06 Bill Schmidt gcc/ * config/rs6000/darwin.h (SUBTARGET_INIT_BUILTINS): Remove test for new_builtins_are_live and simplify. * config/rs6000/rs6000-c.c (altivec_build_resolved_builtin): Remove dead function. (altivec_resolve_overloaded_builtin): Remove test for new_builtins_are_live and simplify. * config/rs6000/rs6000-call.c (altivec_init_builtins): Remove forward declaration. (builtin_function_type): Likewise. (rs6000_common_init_builtins): Likewise. (htm_init_builtins): Likewise. (mma_init_builtins): Likewise. (def_builtin): Remove dead function. (rs6000_expand_zeroop_builtin): Likewise. (rs6000_expand_mtfsf_builtin): Likewise. (rs6000_expand_mtfsb_builtin): Likewise. (rs6000_expand_set_fpscr_rn_builtin): Likewise. (rs6000_expand_set_fpscr_drn_builtin): Likewise. (rs6000_expand_unop_builtin): Likewise. (altivec_expand_abs_builtin): Likewise. (rs6000_expand_binop_builtin): Likewise. (altivec_expand_lxvr_builtin): Likewise. (altivec_expand_lv_builtin): Likewise. (altivec_expand_stxvl_builtin): Likewise. (altivec_expand_stv_builtin): Likewise. (mma_expand_builtin): Likewise. (htm_expand_builtin): Likewise. (cpu_expand_builtin): Likewise. (rs6000_expand_quaternop_builtin): Likewise. (rs6000_expand_ternop_builtin): Likewise. (altivec_expand_dst_builtin): Likewise. (altivec_expand_vec_sel_builtin): Likewise. (altivec_expand_builtin): Likewise. (rs6000_invalid_builtin): Likewise. (rs6000_builtin_valid_without_lhs): Likewise. (rs6000_gimple_fold_builtin): Remove test for new_builtins_are_live and simplify. (rs6000_expand_builtin): Likewise. (rs6000_init_builtins): Remove tests for new_builtins_are_live and simplify. (rs6000_builtin_decl): Likewise. (altivec_init_builtins): Remove dead function. (mma_init_builtins): Likewise. (htm_init_builtins): Likewise. (builtin_quaternary_function_type): Likewise. (builtin_function_type): Likewise. (rs6000_common_init_builtins): Likewise. * config/rs6000/rs6000-gen-builtins.c (write_header_file): Don't declare new_builtins_are_live. (write_init_bif_table): In generated code, remove test for new_builtins_are_live and simplify. (write_init_ovld_table): Likewise. (write_init_file): Don't initialize new_builtins_are_live. * config/rs6000/rs6000.c (rs6000_builtin_vectorized_function): Remove test for new_builtins_are_live and simplify. (rs6000_builtin_md_vectorized_function): Likewise. (rs6000_builtin_reciprocal): Likewise. (add_condition_to_bb): Likewise. (rs6000_atomic_assign_expand_fenv): Likewise. --- diff --git a/gcc/config/rs6000/darwin.h b/gcc/config/rs6000/darwin.h index 120b01f9a2b..7bc1009a523 100644 --- a/gcc/config/rs6000/darwin.h +++ b/gcc/config/rs6000/darwin.h @@ -507,12 +507,8 @@ #define SUBTARGET_INIT_BUILTINS \ do { \ darwin_patch_builtins (); \ - if (new_builtins_are_live) \ - rs6000_builtin_decls_x[(unsigned) (RS6000_BIF_CFSTRING)] \ - = darwin_init_cfstring_builtins ((unsigned) (RS6000_BIF_CFSTRING)); \ - else \ - rs6000_builtin_decls[(unsigned) (RS6000_BUILTIN_CFSTRING)] \ - = darwin_init_cfstring_builtins ((unsigned) (RS6000_BUILTIN_CFSTRING)); \ + rs6000_builtin_decls_x[(unsigned) (RS6000_BIF_CFSTRING)] \ + = darwin_init_cfstring_builtins ((unsigned) (RS6000_BIF_CFSTRING)); \ } while(0) /* So far, there is no rs6000_fold_builtin, if one is introduced, then diff --git a/gcc/config/rs6000/rs6000-c.c b/gcc/config/rs6000/rs6000-c.c index 8e83d97e72f..d44edf585aa 100644 --- a/gcc/config/rs6000/rs6000-c.c +++ b/gcc/config/rs6000/rs6000-c.c @@ -873,82 +873,6 @@ fully_fold_convert (tree type, tree expr) return result; } -/* Build a tree for a function call to an Altivec non-overloaded builtin. - The overloaded builtin that matched the types and args is described - by DESC. The N arguments are given in ARGS, respectively. - - Actually the only thing it does is calling fold_convert on ARGS, with - a small exception for vec_{all,any}_{ge,le} predicates. */ - -static tree -altivec_build_resolved_builtin (tree *args, int n, - const struct altivec_builtin_types *desc) -{ - tree impl_fndecl = rs6000_builtin_decls[desc->overloaded_code]; - tree ret_type = rs6000_builtin_type (desc->ret_type); - tree argtypes = TYPE_ARG_TYPES (TREE_TYPE (impl_fndecl)); - tree arg_type[4]; - tree call; - - int i; - for (i = 0; i < n; i++) - arg_type[i] = TREE_VALUE (argtypes), argtypes = TREE_CHAIN (argtypes); - - /* The AltiVec overloading implementation is overall gross, but this - is particularly disgusting. The vec_{all,any}_{ge,le} builtins - are completely different for floating-point vs. integer vector - types, because the former has vcmpgefp, but the latter should use - vcmpgtXX. - - In practice, the second and third arguments are swapped, and the - condition (LT vs. EQ, which is recognizable by bit 1 of the first - argument) is reversed. Patch the arguments here before building - the resolved CALL_EXPR. */ - if (n == 3 - && desc->code == ALTIVEC_BUILTIN_VEC_VCMPGE_P - && desc->overloaded_code != ALTIVEC_BUILTIN_VCMPGEFP_P - && desc->overloaded_code != VSX_BUILTIN_XVCMPGEDP_P) - { - std::swap (args[1], args[2]); - std::swap (arg_type[1], arg_type[2]); - - args[0] = fold_build2 (BIT_XOR_EXPR, TREE_TYPE (args[0]), args[0], - build_int_cst (NULL_TREE, 2)); - } - - switch (n) - { - case 0: - call = build_call_expr (impl_fndecl, 0); - break; - case 1: - call = build_call_expr (impl_fndecl, 1, - fully_fold_convert (arg_type[0], args[0])); - break; - case 2: - call = build_call_expr (impl_fndecl, 2, - fully_fold_convert (arg_type[0], args[0]), - fully_fold_convert (arg_type[1], args[1])); - break; - case 3: - call = build_call_expr (impl_fndecl, 3, - fully_fold_convert (arg_type[0], args[0]), - fully_fold_convert (arg_type[1], args[1]), - fully_fold_convert (arg_type[2], args[2])); - break; - case 4: - call = build_call_expr (impl_fndecl, 4, - fully_fold_convert (arg_type[0], args[0]), - fully_fold_convert (arg_type[1], args[1]), - fully_fold_convert (arg_type[2], args[2]), - fully_fold_convert (arg_type[3], args[3])); - break; - default: - gcc_unreachable (); - } - return fold_convert (ret_type, call); -} - /* Implementation of the resolve_overloaded_builtin target hook, to support Altivec's overloaded builtins. */ @@ -956,1013 +880,7 @@ tree altivec_resolve_overloaded_builtin (location_t loc, tree fndecl, void *passed_arglist) { - if (new_builtins_are_live) - return altivec_resolve_new_overloaded_builtin (loc, fndecl, - passed_arglist); - - vec *arglist = static_cast *> (passed_arglist); - unsigned int nargs = vec_safe_length (arglist); - enum rs6000_builtins fcode - = (enum rs6000_builtins) DECL_MD_FUNCTION_CODE (fndecl); - tree fnargs = TYPE_ARG_TYPES (TREE_TYPE (fndecl)); - tree types[4], args[4]; - const struct altivec_builtin_types *desc; - unsigned int n; - - if (!rs6000_overloaded_builtin_p (fcode)) - return NULL_TREE; - - if (TARGET_DEBUG_BUILTIN) - fprintf (stderr, "altivec_resolve_overloaded_builtin, code = %4d, %s\n", - (int)fcode, IDENTIFIER_POINTER (DECL_NAME (fndecl))); - - /* vec_lvsl and vec_lvsr are deprecated for use with LE element order. */ - if (fcode == ALTIVEC_BUILTIN_VEC_LVSL && !BYTES_BIG_ENDIAN) - warning (OPT_Wdeprecated, - "% is deprecated for little endian; use " - "assignment for unaligned loads and stores"); - else if (fcode == ALTIVEC_BUILTIN_VEC_LVSR && !BYTES_BIG_ENDIAN) - warning (OPT_Wdeprecated, - "% is deprecated for little endian; use " - "assignment for unaligned loads and stores"); - - if (fcode == ALTIVEC_BUILTIN_VEC_MUL) - { - /* vec_mul needs to be special cased because there are no instructions - for it for the {un}signed char, {un}signed short, and {un}signed int - types. */ - if (nargs != 2) - { - error ("builtin %qs only accepts 2 arguments", "vec_mul"); - return error_mark_node; - } - - tree arg0 = (*arglist)[0]; - tree arg0_type = TREE_TYPE (arg0); - tree arg1 = (*arglist)[1]; - tree arg1_type = TREE_TYPE (arg1); - - /* Both arguments must be vectors and the types must be compatible. */ - if (TREE_CODE (arg0_type) != VECTOR_TYPE) - goto bad; - if (!lang_hooks.types_compatible_p (arg0_type, arg1_type)) - goto bad; - - switch (TYPE_MODE (TREE_TYPE (arg0_type))) - { - case E_QImode: - case E_HImode: - case E_SImode: - case E_DImode: - case E_TImode: - { - /* For scalar types just use a multiply expression. */ - return fold_build2_loc (loc, MULT_EXPR, TREE_TYPE (arg0), arg0, - fold_convert (TREE_TYPE (arg0), arg1)); - } - case E_SFmode: - { - /* For floats use the xvmulsp instruction directly. */ - tree call = rs6000_builtin_decls[VSX_BUILTIN_XVMULSP]; - return build_call_expr (call, 2, arg0, arg1); - } - case E_DFmode: - { - /* For doubles use the xvmuldp instruction directly. */ - tree call = rs6000_builtin_decls[VSX_BUILTIN_XVMULDP]; - return build_call_expr (call, 2, arg0, arg1); - } - /* Other types are errors. */ - default: - goto bad; - } - } - - if (fcode == ALTIVEC_BUILTIN_VEC_CMPNE) - { - /* vec_cmpne needs to be special cased because there are no instructions - for it (prior to power 9). */ - if (nargs != 2) - { - error ("builtin %qs only accepts 2 arguments", "vec_cmpne"); - return error_mark_node; - } - - tree arg0 = (*arglist)[0]; - tree arg0_type = TREE_TYPE (arg0); - tree arg1 = (*arglist)[1]; - tree arg1_type = TREE_TYPE (arg1); - - /* Both arguments must be vectors and the types must be compatible. */ - if (TREE_CODE (arg0_type) != VECTOR_TYPE) - goto bad; - if (!lang_hooks.types_compatible_p (arg0_type, arg1_type)) - goto bad; - - /* Power9 instructions provide the most efficient implementation of - ALTIVEC_BUILTIN_VEC_CMPNE if the mode is not DImode or TImode - or SFmode or DFmode. */ - if (!TARGET_P9_VECTOR - || (TYPE_MODE (TREE_TYPE (arg0_type)) == DImode) - || (TYPE_MODE (TREE_TYPE (arg0_type)) == TImode) - || (TYPE_MODE (TREE_TYPE (arg0_type)) == SFmode) - || (TYPE_MODE (TREE_TYPE (arg0_type)) == DFmode)) - { - switch (TYPE_MODE (TREE_TYPE (arg0_type))) - { - /* vec_cmpneq (va, vb) == vec_nor (vec_cmpeq (va, vb), - vec_cmpeq (va, vb)). */ - /* Note: vec_nand also works but opt changes vec_nand's - to vec_nor's anyway. */ - case E_QImode: - case E_HImode: - case E_SImode: - case E_DImode: - case E_TImode: - case E_SFmode: - case E_DFmode: - { - /* call = vec_cmpeq (va, vb) - result = vec_nor (call, call). */ - vec *params = make_tree_vector (); - vec_safe_push (params, arg0); - vec_safe_push (params, arg1); - tree call = altivec_resolve_overloaded_builtin - (loc, rs6000_builtin_decls[ALTIVEC_BUILTIN_VEC_CMPEQ], - params); - /* Use save_expr to ensure that operands used more than once - that may have side effects (like calls) are only evaluated - once. */ - call = save_expr (call); - params = make_tree_vector (); - vec_safe_push (params, call); - vec_safe_push (params, call); - return altivec_resolve_overloaded_builtin - (loc, rs6000_builtin_decls[ALTIVEC_BUILTIN_VEC_NOR], params); - } - /* Other types are errors. */ - default: - goto bad; - } - } - /* else, fall through and process the Power9 alternative below */ - } - - if (fcode == ALTIVEC_BUILTIN_VEC_ADDE - || fcode == ALTIVEC_BUILTIN_VEC_SUBE) - { - /* vec_adde needs to be special cased because there is no instruction - for the {un}signed int version. */ - if (nargs != 3) - { - const char *name = fcode == ALTIVEC_BUILTIN_VEC_ADDE ? - "vec_adde": "vec_sube"; - error ("builtin %qs only accepts 3 arguments", name); - return error_mark_node; - } - - tree arg0 = (*arglist)[0]; - tree arg0_type = TREE_TYPE (arg0); - tree arg1 = (*arglist)[1]; - tree arg1_type = TREE_TYPE (arg1); - tree arg2 = (*arglist)[2]; - tree arg2_type = TREE_TYPE (arg2); - - /* All 3 arguments must be vectors of (signed or unsigned) (int or - __int128) and the types must be compatible. */ - if (TREE_CODE (arg0_type) != VECTOR_TYPE) - goto bad; - if (!lang_hooks.types_compatible_p (arg0_type, arg1_type) - || !lang_hooks.types_compatible_p (arg1_type, arg2_type)) - goto bad; - - switch (TYPE_MODE (TREE_TYPE (arg0_type))) - { - /* For {un}signed ints, - vec_adde (va, vb, carryv) == vec_add (vec_add (va, vb), - vec_and (carryv, 1)). - vec_sube (va, vb, carryv) == vec_sub (vec_sub (va, vb), - vec_and (carryv, 1)). */ - case E_SImode: - { - tree add_sub_builtin; - - vec *params = make_tree_vector (); - vec_safe_push (params, arg0); - vec_safe_push (params, arg1); - - if (fcode == ALTIVEC_BUILTIN_VEC_ADDE) - add_sub_builtin = rs6000_builtin_decls[ALTIVEC_BUILTIN_VEC_ADD]; - else - add_sub_builtin = rs6000_builtin_decls[ALTIVEC_BUILTIN_VEC_SUB]; - - tree call = altivec_resolve_overloaded_builtin (loc, - add_sub_builtin, - params); - tree const1 = build_int_cstu (TREE_TYPE (arg0_type), 1); - tree ones_vector = build_vector_from_val (arg0_type, const1); - tree and_expr = fold_build2_loc (loc, BIT_AND_EXPR, arg0_type, - arg2, ones_vector); - params = make_tree_vector (); - vec_safe_push (params, call); - vec_safe_push (params, and_expr); - return altivec_resolve_overloaded_builtin (loc, add_sub_builtin, - params); - } - /* For {un}signed __int128s use the vaddeuqm instruction - directly. */ - case E_TImode: - { - tree bii; - - if (fcode == ALTIVEC_BUILTIN_VEC_ADDE) - bii = rs6000_builtin_decls[P8V_BUILTIN_VEC_VADDEUQM]; - - else - bii = rs6000_builtin_decls[P8V_BUILTIN_VEC_VSUBEUQM]; - - return altivec_resolve_overloaded_builtin (loc, bii, arglist); - } - - /* Types other than {un}signed int and {un}signed __int128 - are errors. */ - default: - goto bad; - } - } - - if (fcode == ALTIVEC_BUILTIN_VEC_ADDEC - || fcode == ALTIVEC_BUILTIN_VEC_SUBEC) - { - /* vec_addec and vec_subec needs to be special cased because there is - no instruction for the {un}signed int version. */ - if (nargs != 3) - { - const char *name = fcode == ALTIVEC_BUILTIN_VEC_ADDEC ? - "vec_addec": "vec_subec"; - error ("builtin %qs only accepts 3 arguments", name); - return error_mark_node; - } - - tree arg0 = (*arglist)[0]; - tree arg0_type = TREE_TYPE (arg0); - tree arg1 = (*arglist)[1]; - tree arg1_type = TREE_TYPE (arg1); - tree arg2 = (*arglist)[2]; - tree arg2_type = TREE_TYPE (arg2); - - /* All 3 arguments must be vectors of (signed or unsigned) (int or - __int128) and the types must be compatible. */ - if (TREE_CODE (arg0_type) != VECTOR_TYPE) - goto bad; - if (!lang_hooks.types_compatible_p (arg0_type, arg1_type) - || !lang_hooks.types_compatible_p (arg1_type, arg2_type)) - goto bad; - - switch (TYPE_MODE (TREE_TYPE (arg0_type))) - { - /* For {un}signed ints, - vec_addec (va, vb, carryv) == - vec_or (vec_addc (va, vb), - vec_addc (vec_add (va, vb), - vec_and (carryv, 0x1))). */ - case E_SImode: - { - /* Use save_expr to ensure that operands used more than once - that may have side effects (like calls) are only evaluated - once. */ - tree as_builtin; - tree as_c_builtin; - - arg0 = save_expr (arg0); - arg1 = save_expr (arg1); - vec *params = make_tree_vector (); - vec_safe_push (params, arg0); - vec_safe_push (params, arg1); - - if (fcode == ALTIVEC_BUILTIN_VEC_ADDEC) - as_c_builtin = rs6000_builtin_decls[ALTIVEC_BUILTIN_VEC_ADDC]; - else - as_c_builtin = rs6000_builtin_decls[ALTIVEC_BUILTIN_VEC_SUBC]; - - tree call1 = altivec_resolve_overloaded_builtin (loc, as_c_builtin, - params); - params = make_tree_vector (); - vec_safe_push (params, arg0); - vec_safe_push (params, arg1); - - - if (fcode == ALTIVEC_BUILTIN_VEC_ADDEC) - as_builtin = rs6000_builtin_decls[ALTIVEC_BUILTIN_VEC_ADD]; - else - as_builtin = rs6000_builtin_decls[ALTIVEC_BUILTIN_VEC_SUB]; - - tree call2 = altivec_resolve_overloaded_builtin (loc, as_builtin, - params); - tree const1 = build_int_cstu (TREE_TYPE (arg0_type), 1); - tree ones_vector = build_vector_from_val (arg0_type, const1); - tree and_expr = fold_build2_loc (loc, BIT_AND_EXPR, arg0_type, - arg2, ones_vector); - params = make_tree_vector (); - vec_safe_push (params, call2); - vec_safe_push (params, and_expr); - call2 = altivec_resolve_overloaded_builtin (loc, as_c_builtin, - params); - params = make_tree_vector (); - vec_safe_push (params, call1); - vec_safe_push (params, call2); - tree or_builtin = rs6000_builtin_decls[ALTIVEC_BUILTIN_VEC_OR]; - return altivec_resolve_overloaded_builtin (loc, or_builtin, - params); - } - /* For {un}signed __int128s use the vaddecuq/vsubbecuq - instructions. */ - case E_TImode: - { - tree bii; - - if (fcode == ALTIVEC_BUILTIN_VEC_ADDEC) - bii = rs6000_builtin_decls[P8V_BUILTIN_VEC_VADDECUQ]; - - else - bii = rs6000_builtin_decls[P8V_BUILTIN_VEC_VSUBECUQ]; - - return altivec_resolve_overloaded_builtin (loc, bii, arglist); - } - /* Types other than {un}signed int and {un}signed __int128 - are errors. */ - default: - goto bad; - } - } - - /* For now treat vec_splats and vec_promote as the same. */ - if (fcode == ALTIVEC_BUILTIN_VEC_SPLATS - || fcode == ALTIVEC_BUILTIN_VEC_PROMOTE) - { - tree type, arg; - int size; - int i; - bool unsigned_p; - vec *vec; - const char *name = fcode == ALTIVEC_BUILTIN_VEC_SPLATS ? "vec_splats": "vec_promote"; - - if (fcode == ALTIVEC_BUILTIN_VEC_SPLATS && nargs != 1) - { - error ("builtin %qs only accepts 1 argument", name); - return error_mark_node; - } - if (fcode == ALTIVEC_BUILTIN_VEC_PROMOTE && nargs != 2) - { - error ("builtin %qs only accepts 2 arguments", name); - return error_mark_node; - } - /* Ignore promote's element argument. */ - if (fcode == ALTIVEC_BUILTIN_VEC_PROMOTE - && !INTEGRAL_TYPE_P (TREE_TYPE ((*arglist)[1]))) - goto bad; - - arg = (*arglist)[0]; - type = TREE_TYPE (arg); - if (!SCALAR_FLOAT_TYPE_P (type) - && !INTEGRAL_TYPE_P (type)) - goto bad; - unsigned_p = TYPE_UNSIGNED (type); - switch (TYPE_MODE (type)) - { - case E_TImode: - type = (unsigned_p ? unsigned_V1TI_type_node : V1TI_type_node); - size = 1; - break; - case E_DImode: - type = (unsigned_p ? unsigned_V2DI_type_node : V2DI_type_node); - size = 2; - break; - case E_SImode: - type = (unsigned_p ? unsigned_V4SI_type_node : V4SI_type_node); - size = 4; - break; - case E_HImode: - type = (unsigned_p ? unsigned_V8HI_type_node : V8HI_type_node); - size = 8; - break; - case E_QImode: - type = (unsigned_p ? unsigned_V16QI_type_node : V16QI_type_node); - size = 16; - break; - case E_SFmode: type = V4SF_type_node; size = 4; break; - case E_DFmode: type = V2DF_type_node; size = 2; break; - default: - goto bad; - } - arg = save_expr (fold_convert (TREE_TYPE (type), arg)); - vec_alloc (vec, size); - for(i = 0; i < size; i++) - { - constructor_elt elt = {NULL_TREE, arg}; - vec->quick_push (elt); - } - return build_constructor (type, vec); - } - - /* For now use pointer tricks to do the extraction, unless we are on VSX - extracting a double from a constant offset. */ - if (fcode == ALTIVEC_BUILTIN_VEC_EXTRACT) - { - tree arg1; - tree arg1_type; - tree arg2; - tree arg1_inner_type; - tree decl, stmt; - tree innerptrtype; - machine_mode mode; - - /* No second argument. */ - if (nargs != 2) - { - error ("builtin %qs only accepts 2 arguments", "vec_extract"); - return error_mark_node; - } - - arg2 = (*arglist)[1]; - arg1 = (*arglist)[0]; - arg1_type = TREE_TYPE (arg1); - - if (TREE_CODE (arg1_type) != VECTOR_TYPE) - goto bad; - if (!INTEGRAL_TYPE_P (TREE_TYPE (arg2))) - goto bad; - - /* See if we can optimize vec_extracts with the current VSX instruction - set. */ - mode = TYPE_MODE (arg1_type); - if (VECTOR_MEM_VSX_P (mode)) - - { - tree call = NULL_TREE; - int nunits = GET_MODE_NUNITS (mode); - - arg2 = fold_for_warn (arg2); - - /* If the second argument is an integer constant, generate - the built-in code if we can. We need 64-bit and direct - move to extract the small integer vectors. */ - if (TREE_CODE (arg2) == INTEGER_CST) - { - wide_int selector = wi::to_wide (arg2); - selector = wi::umod_trunc (selector, nunits); - arg2 = wide_int_to_tree (TREE_TYPE (arg2), selector); - switch (mode) - { - default: - break; - - case E_V1TImode: - call = rs6000_builtin_decls[VSX_BUILTIN_VEC_EXT_V1TI]; - break; - - case E_V2DFmode: - call = rs6000_builtin_decls[VSX_BUILTIN_VEC_EXT_V2DF]; - break; - - case E_V2DImode: - call = rs6000_builtin_decls[VSX_BUILTIN_VEC_EXT_V2DI]; - break; - - case E_V4SFmode: - call = rs6000_builtin_decls[ALTIVEC_BUILTIN_VEC_EXT_V4SF]; - break; - - case E_V4SImode: - if (TARGET_DIRECT_MOVE_64BIT) - call = rs6000_builtin_decls[ALTIVEC_BUILTIN_VEC_EXT_V4SI]; - break; - - case E_V8HImode: - if (TARGET_DIRECT_MOVE_64BIT) - call = rs6000_builtin_decls[ALTIVEC_BUILTIN_VEC_EXT_V8HI]; - break; - - case E_V16QImode: - if (TARGET_DIRECT_MOVE_64BIT) - call = rs6000_builtin_decls[ALTIVEC_BUILTIN_VEC_EXT_V16QI]; - break; - } - } - - /* If the second argument is variable, we can optimize it if we are - generating 64-bit code on a machine with direct move. */ - else if (TREE_CODE (arg2) != INTEGER_CST && TARGET_DIRECT_MOVE_64BIT) - { - switch (mode) - { - default: - break; - - case E_V2DFmode: - call = rs6000_builtin_decls[VSX_BUILTIN_VEC_EXT_V2DF]; - break; - - case E_V2DImode: - call = rs6000_builtin_decls[VSX_BUILTIN_VEC_EXT_V2DI]; - break; - - case E_V4SFmode: - call = rs6000_builtin_decls[ALTIVEC_BUILTIN_VEC_EXT_V4SF]; - break; - - case E_V4SImode: - call = rs6000_builtin_decls[ALTIVEC_BUILTIN_VEC_EXT_V4SI]; - break; - - case E_V8HImode: - call = rs6000_builtin_decls[ALTIVEC_BUILTIN_VEC_EXT_V8HI]; - break; - - case E_V16QImode: - call = rs6000_builtin_decls[ALTIVEC_BUILTIN_VEC_EXT_V16QI]; - break; - } - } - - if (call) - { - tree result = build_call_expr (call, 2, arg1, arg2); - /* Coerce the result to vector element type. May be no-op. */ - arg1_inner_type = TREE_TYPE (arg1_type); - result = fold_convert (arg1_inner_type, result); - return result; - } - } - - /* Build *(((arg1_inner_type*)&(vector type){arg1})+arg2). */ - arg1_inner_type = TREE_TYPE (arg1_type); - arg2 = build_binary_op (loc, BIT_AND_EXPR, arg2, - build_int_cst (TREE_TYPE (arg2), - TYPE_VECTOR_SUBPARTS (arg1_type) - - 1), 0); - decl = build_decl (loc, VAR_DECL, NULL_TREE, arg1_type); - DECL_EXTERNAL (decl) = 0; - TREE_PUBLIC (decl) = 0; - DECL_CONTEXT (decl) = current_function_decl; - TREE_USED (decl) = 1; - TREE_TYPE (decl) = arg1_type; - TREE_READONLY (decl) = TYPE_READONLY (arg1_type); - if (c_dialect_cxx ()) - { - stmt = build4 (TARGET_EXPR, arg1_type, decl, arg1, - NULL_TREE, NULL_TREE); - SET_EXPR_LOCATION (stmt, loc); - } - else - { - DECL_INITIAL (decl) = arg1; - stmt = build1 (DECL_EXPR, arg1_type, decl); - TREE_ADDRESSABLE (decl) = 1; - SET_EXPR_LOCATION (stmt, loc); - stmt = build1 (COMPOUND_LITERAL_EXPR, arg1_type, stmt); - } - - innerptrtype = build_pointer_type (arg1_inner_type); - - stmt = build_unary_op (loc, ADDR_EXPR, stmt, 0); - stmt = convert (innerptrtype, stmt); - stmt = build_binary_op (loc, PLUS_EXPR, stmt, arg2, 1); - stmt = build_indirect_ref (loc, stmt, RO_NULL); - - /* PR83660: We mark this as having side effects so that - downstream in fold_build_cleanup_point_expr () it will get a - CLEANUP_POINT_EXPR. If it does not we can run into an ICE - later in gimplify_cleanup_point_expr (). Potentially this - causes missed optimization because the actually is no side - effect. */ - if (c_dialect_cxx ()) - TREE_SIDE_EFFECTS (stmt) = 1; - - return stmt; - } - - /* For now use pointer tricks to do the insertion, unless we are on VSX - inserting a double to a constant offset.. */ - if (fcode == ALTIVEC_BUILTIN_VEC_INSERT) - { - tree arg0; - tree arg1; - tree arg2; - tree arg1_type; - tree decl, stmt; - machine_mode mode; - - /* No second or third arguments. */ - if (nargs != 3) - { - error ("builtin %qs only accepts 3 arguments", "vec_insert"); - return error_mark_node; - } - - arg0 = (*arglist)[0]; - arg1 = (*arglist)[1]; - arg1_type = TREE_TYPE (arg1); - arg2 = fold_for_warn ((*arglist)[2]); - - if (TREE_CODE (arg1_type) != VECTOR_TYPE) - goto bad; - if (!INTEGRAL_TYPE_P (TREE_TYPE (arg2))) - goto bad; - - /* If we can use the VSX xxpermdi instruction, use that for insert. */ - mode = TYPE_MODE (arg1_type); - if ((mode == V2DFmode || mode == V2DImode) && VECTOR_UNIT_VSX_P (mode) - && TREE_CODE (arg2) == INTEGER_CST) - { - wide_int selector = wi::to_wide (arg2); - selector = wi::umod_trunc (selector, 2); - tree call = NULL_TREE; - - arg2 = wide_int_to_tree (TREE_TYPE (arg2), selector); - if (mode == V2DFmode) - call = rs6000_builtin_decls[VSX_BUILTIN_VEC_SET_V2DF]; - else if (mode == V2DImode) - call = rs6000_builtin_decls[VSX_BUILTIN_VEC_SET_V2DI]; - - /* Note, __builtin_vec_insert_ has vector and scalar types - reversed. */ - if (call) - return build_call_expr (call, 3, arg1, arg0, arg2); - } - else if (mode == V1TImode && VECTOR_UNIT_VSX_P (mode) - && TREE_CODE (arg2) == INTEGER_CST) - { - tree call = rs6000_builtin_decls[VSX_BUILTIN_VEC_SET_V1TI]; - wide_int selector = wi::zero(32); - - arg2 = wide_int_to_tree (TREE_TYPE (arg2), selector); - /* Note, __builtin_vec_insert_ has vector and scalar types - reversed. */ - return build_call_expr (call, 3, arg1, arg0, arg2); - } - - /* Build *(((arg1_inner_type*)&(vector type){arg1})+arg2) = arg0 with - VIEW_CONVERT_EXPR. i.e.: - D.3192 = v1; - _1 = n & 3; - VIEW_CONVERT_EXPR(D.3192)[_1] = i; - v1 = D.3192; - D.3194 = v1; */ - if (TYPE_VECTOR_SUBPARTS (arg1_type) == 1) - arg2 = build_int_cst (TREE_TYPE (arg2), 0); - else - arg2 = build_binary_op (loc, BIT_AND_EXPR, arg2, - build_int_cst (TREE_TYPE (arg2), - TYPE_VECTOR_SUBPARTS (arg1_type) - - 1), 0); - decl = build_decl (loc, VAR_DECL, NULL_TREE, arg1_type); - DECL_EXTERNAL (decl) = 0; - TREE_PUBLIC (decl) = 0; - DECL_CONTEXT (decl) = current_function_decl; - TREE_USED (decl) = 1; - TREE_TYPE (decl) = arg1_type; - TREE_READONLY (decl) = TYPE_READONLY (arg1_type); - TREE_ADDRESSABLE (decl) = 1; - if (c_dialect_cxx ()) - { - stmt = build4 (TARGET_EXPR, arg1_type, decl, arg1, - NULL_TREE, NULL_TREE); - SET_EXPR_LOCATION (stmt, loc); - } - else - { - DECL_INITIAL (decl) = arg1; - stmt = build1 (DECL_EXPR, arg1_type, decl); - SET_EXPR_LOCATION (stmt, loc); - stmt = build1 (COMPOUND_LITERAL_EXPR, arg1_type, stmt); - } - - if (TARGET_VSX) - { - stmt = build_array_ref (loc, stmt, arg2); - stmt = fold_build2 (MODIFY_EXPR, TREE_TYPE (arg0), stmt, - convert (TREE_TYPE (stmt), arg0)); - stmt = build2 (COMPOUND_EXPR, arg1_type, stmt, decl); - } - else - { - tree arg1_inner_type; - tree innerptrtype; - arg1_inner_type = TREE_TYPE (arg1_type); - innerptrtype = build_pointer_type (arg1_inner_type); - - stmt = build_unary_op (loc, ADDR_EXPR, stmt, 0); - stmt = convert (innerptrtype, stmt); - stmt = build_binary_op (loc, PLUS_EXPR, stmt, arg2, 1); - stmt = build_indirect_ref (loc, stmt, RO_NULL); - stmt = build2 (MODIFY_EXPR, TREE_TYPE (stmt), stmt, - convert (TREE_TYPE (stmt), arg0)); - stmt = build2 (COMPOUND_EXPR, arg1_type, stmt, decl); - } - return stmt; - } - - for (n = 0; - !VOID_TYPE_P (TREE_VALUE (fnargs)) && n < nargs; - fnargs = TREE_CHAIN (fnargs), n++) - { - tree decl_type = TREE_VALUE (fnargs); - tree arg = (*arglist)[n]; - tree type; - - if (arg == error_mark_node) - return error_mark_node; - - if (n >= 4) - abort (); - - arg = default_conversion (arg); - - /* The C++ front-end converts float * to const void * using - NOP_EXPR (NOP_EXPR (x)). */ - type = TREE_TYPE (arg); - if (POINTER_TYPE_P (type) - && TREE_CODE (arg) == NOP_EXPR - && lang_hooks.types_compatible_p (TREE_TYPE (arg), - const_ptr_type_node) - && lang_hooks.types_compatible_p (TREE_TYPE (TREE_OPERAND (arg, 0)), - ptr_type_node)) - { - arg = TREE_OPERAND (arg, 0); - type = TREE_TYPE (arg); - } - - /* Remove the const from the pointers to simplify the overload - matching further down. */ - if (POINTER_TYPE_P (decl_type) - && POINTER_TYPE_P (type) - && TYPE_QUALS (TREE_TYPE (type)) != 0) - { - if (TYPE_READONLY (TREE_TYPE (type)) - && !TYPE_READONLY (TREE_TYPE (decl_type))) - warning (0, "passing argument %d of %qE discards qualifiers from " - "pointer target type", n + 1, fndecl); - type = build_pointer_type (build_qualified_type (TREE_TYPE (type), - 0)); - arg = fold_convert (type, arg); - } - - /* For P9V_BUILTIN_VEC_LXVL, convert any const * to its non constant - equivalent to simplify the overload matching below. */ - if (fcode == P9V_BUILTIN_VEC_LXVL) - { - if (POINTER_TYPE_P (type) - && TYPE_READONLY (TREE_TYPE (type))) - { - type = build_pointer_type (build_qualified_type ( - TREE_TYPE (type),0)); - arg = fold_convert (type, arg); - } - } - - args[n] = arg; - types[n] = type; - } - - /* If the number of arguments did not match the prototype, return NULL - and the generic code will issue the appropriate error message. */ - if (!VOID_TYPE_P (TREE_VALUE (fnargs)) || n < nargs) - return NULL; - - if (n == 0) - abort (); - - if (fcode == ALTIVEC_BUILTIN_VEC_STEP) - { - if (TREE_CODE (types[0]) != VECTOR_TYPE) - goto bad; - - return build_int_cst (NULL_TREE, TYPE_VECTOR_SUBPARTS (types[0])); - } - - { - bool unsupported_builtin = false; - enum rs6000_builtins overloaded_code; - tree result = NULL; - for (desc = altivec_overloaded_builtins; - desc->code && desc->code != fcode; desc++) - continue; - - /* Need to special case __builtin_cmp because the overloaded forms - of this function take (unsigned int, unsigned int) or (unsigned - long long int, unsigned long long int). Since C conventions - allow the respective argument types to be implicitly coerced into - each other, the default handling does not provide adequate - discrimination between the desired forms of the function. */ - if (fcode == P6_OV_BUILTIN_CMPB) - { - machine_mode arg1_mode = TYPE_MODE (types[0]); - machine_mode arg2_mode = TYPE_MODE (types[1]); - - if (nargs != 2) - { - error ("builtin %qs only accepts 2 arguments", "__builtin_cmpb"); - return error_mark_node; - } - - /* If any supplied arguments are wider than 32 bits, resolve to - 64-bit variant of built-in function. */ - if ((GET_MODE_PRECISION (arg1_mode) > 32) - || (GET_MODE_PRECISION (arg2_mode) > 32)) - { - /* Assure all argument and result types are compatible with - the built-in function represented by P6_BUILTIN_CMPB. */ - overloaded_code = P6_BUILTIN_CMPB; - } - else - { - /* Assure all argument and result types are compatible with - the built-in function represented by P6_BUILTIN_CMPB_32. */ - overloaded_code = P6_BUILTIN_CMPB_32; - } - - while (desc->code && desc->code == fcode - && desc->overloaded_code != overloaded_code) - desc++; - - if (desc->code && (desc->code == fcode) - && rs6000_builtin_type_compatible (types[0], desc->op1) - && rs6000_builtin_type_compatible (types[1], desc->op2)) - { - if (rs6000_builtin_decls[desc->overloaded_code] != NULL_TREE) - { - result = altivec_build_resolved_builtin (args, n, desc); - /* overloaded_code is set above */ - if (!rs6000_builtin_is_supported_p (overloaded_code)) - unsupported_builtin = true; - else - return result; - } - else - unsupported_builtin = true; - } - } - else if (fcode == P9V_BUILTIN_VEC_VSIEDP) - { - machine_mode arg1_mode = TYPE_MODE (types[0]); - - if (nargs != 2) - { - error ("builtin %qs only accepts 2 arguments", - "scalar_insert_exp"); - return error_mark_node; - } - - /* If supplied first argument is wider than 64 bits, resolve to - 128-bit variant of built-in function. */ - if (GET_MODE_PRECISION (arg1_mode) > 64) - { - /* If first argument is of float variety, choose variant - that expects __ieee128 argument. Otherwise, expect - __int128 argument. */ - if (GET_MODE_CLASS (arg1_mode) == MODE_FLOAT) - overloaded_code = P9V_BUILTIN_VSIEQPF; - else - overloaded_code = P9V_BUILTIN_VSIEQP; - } - else - { - /* If first argument is of float variety, choose variant - that expects double argument. Otherwise, expect - long long int argument. */ - if (GET_MODE_CLASS (arg1_mode) == MODE_FLOAT) - overloaded_code = P9V_BUILTIN_VSIEDPF; - else - overloaded_code = P9V_BUILTIN_VSIEDP; - } - while (desc->code && desc->code == fcode - && desc->overloaded_code != overloaded_code) - desc++; - - if (desc->code && (desc->code == fcode) - && rs6000_builtin_type_compatible (types[0], desc->op1) - && rs6000_builtin_type_compatible (types[1], desc->op2)) - { - if (rs6000_builtin_decls[desc->overloaded_code] != NULL_TREE) - { - result = altivec_build_resolved_builtin (args, n, desc); - /* overloaded_code is set above. */ - if (!rs6000_builtin_is_supported_p (overloaded_code)) - unsupported_builtin = true; - else - return result; - } - else - unsupported_builtin = true; - } - } - else if ((fcode == P10_BUILTIN_VEC_XXEVAL) - || (fcode == P10V_BUILTIN_VXXPERMX)) - { - signed char op3_type; - - /* Need to special case P10_BUILTIN_VEC_XXEVAL and - P10V_BUILTIN_VXXPERMX because they take 4 arguments and the - existing infrastructure only handles three. */ - if (nargs != 4) - { - const char *name = fcode == P10_BUILTIN_VEC_XXEVAL ? - "__builtin_vec_xxeval":"__builtin_vec_xxpermx"; - - error ("builtin %qs requires 4 arguments", name); - return error_mark_node; - } - - for ( ; desc->code == fcode; desc++) - { - if (fcode == P10_BUILTIN_VEC_XXEVAL) - op3_type = desc->op3; - else /* P10V_BUILTIN_VXXPERMX */ - op3_type = RS6000_BTI_V16QI; - - if (rs6000_builtin_type_compatible (types[0], desc->op1) - && rs6000_builtin_type_compatible (types[1], desc->op2) - && rs6000_builtin_type_compatible (types[2], desc->op3) - && rs6000_builtin_type_compatible (types[2], op3_type) - && rs6000_builtin_type_compatible (types[3], - RS6000_BTI_UINTSI)) - { - if (rs6000_builtin_decls[desc->overloaded_code] == NULL_TREE) - unsupported_builtin = true; - else - { - result = altivec_build_resolved_builtin (args, n, desc); - if (rs6000_builtin_is_supported_p (desc->overloaded_code)) - return result; - /* Allow loop to continue in case a different - definition is supported. */ - overloaded_code = desc->overloaded_code; - unsupported_builtin = true; - } - } - } - } - else - { - /* For arguments after the last, we have RS6000_BTI_NOT_OPAQUE in - the opX fields. */ - for (; desc->code == fcode; desc++) - { - if ((desc->op1 == RS6000_BTI_NOT_OPAQUE - || rs6000_builtin_type_compatible (types[0], desc->op1)) - && (desc->op2 == RS6000_BTI_NOT_OPAQUE - || rs6000_builtin_type_compatible (types[1], desc->op2)) - && (desc->op3 == RS6000_BTI_NOT_OPAQUE - || rs6000_builtin_type_compatible (types[2], desc->op3))) - { - if (rs6000_builtin_decls[desc->overloaded_code] != NULL_TREE) - { - result = altivec_build_resolved_builtin (args, n, desc); - if (!rs6000_builtin_is_supported_p (desc->overloaded_code)) - { - /* Allow loop to continue in case a different - definition is supported. */ - overloaded_code = desc->overloaded_code; - unsupported_builtin = true; - } - else - return result; - } - else - unsupported_builtin = true; - } - } - } - - if (unsupported_builtin) - { - const char *name = rs6000_overloaded_builtin_name (fcode); - if (result != NULL) - { - const char *internal_name - = rs6000_overloaded_builtin_name (overloaded_code); - /* An error message making reference to the name of the - non-overloaded function has already been issued. Add - clarification of the previous message. */ - rich_location richloc (line_table, input_location); - inform (&richloc, - "overloaded builtin %qs is implemented by builtin %qs", - name, internal_name); - } - else - error ("%qs is not supported in this compiler configuration", name); - /* If an error-representing result tree was returned from - altivec_build_resolved_builtin above, use it. */ - return (result != NULL) ? result : error_mark_node; - } - } - bad: - { - const char *name = rs6000_overloaded_builtin_name (fcode); - error ("invalid parameter combination for AltiVec intrinsic %qs", name); - return error_mark_node; - } + return altivec_resolve_new_overloaded_builtin (loc, fndecl, passed_arglist); } /* Build a tree for a function call to an Altivec non-overloaded builtin. diff --git a/gcc/config/rs6000/rs6000-call.c b/gcc/config/rs6000/rs6000-call.c index 3a43a768c5c..85aea9b8c2f 100644 --- a/gcc/config/rs6000/rs6000-call.c +++ b/gcc/config/rs6000/rs6000-call.c @@ -182,13 +182,6 @@ static const struct { "mma", PPC_FEATURE2_MMA, 1 }, }; -static void altivec_init_builtins (void); -static tree builtin_function_type (machine_mode, machine_mode, - machine_mode, machine_mode, - enum rs6000_builtins, const char *name); -static void rs6000_common_init_builtins (void); -static void htm_init_builtins (void); -static void mma_init_builtins (void); static rtx rs6000_expand_new_builtin (tree, rtx, rtx, machine_mode, int); static bool rs6000_gimple_fold_new_builtin (gimple_stmt_iterator *gsi); @@ -9029,89 +9022,6 @@ const char *rs6000_type_string (tree type_node) return "unknown"; } -static void -def_builtin (const char *name, tree type, enum rs6000_builtins code) -{ - tree t; - unsigned classify = rs6000_builtin_info[(int)code].attr; - const char *attr_string = ""; - - /* Don't define the builtin if it doesn't have a type. See PR92661. */ - if (type == NULL_TREE) - return; - - gcc_assert (name != NULL); - gcc_assert (IN_RANGE ((int)code, 0, (int)RS6000_BUILTIN_COUNT)); - - if (rs6000_builtin_decls[(int)code]) - fatal_error (input_location, - "internal error: builtin function %qs already processed", - name); - - rs6000_builtin_decls[(int)code] = t = - add_builtin_function (name, type, (int)code, BUILT_IN_MD, NULL, NULL_TREE); - - /* Set any special attributes. */ - if ((classify & RS6000_BTC_CONST) != 0) - { - /* const function, function only depends on the inputs. */ - TREE_READONLY (t) = 1; - TREE_NOTHROW (t) = 1; - attr_string = "= const"; - } - else if ((classify & RS6000_BTC_PURE) != 0) - { - /* pure function, function can read global memory, but does not set any - external state. */ - DECL_PURE_P (t) = 1; - TREE_NOTHROW (t) = 1; - attr_string = "= pure"; - } - else if ((classify & RS6000_BTC_FP) != 0) - { - /* Function is a math function. If rounding mode is on, then treat the - function as not reading global memory, but it can have arbitrary side - effects. If it is off, then assume the function is a const function. - This mimics the ATTR_MATHFN_FPROUNDING attribute in - builtin-attribute.def that is used for the math functions. */ - TREE_NOTHROW (t) = 1; - if (flag_rounding_math) - { - DECL_PURE_P (t) = 1; - DECL_IS_NOVOPS (t) = 1; - attr_string = "= fp, pure"; - } - else - { - TREE_READONLY (t) = 1; - attr_string = "= fp, const"; - } - } - else if ((classify & (RS6000_BTC_QUAD | RS6000_BTC_PAIR)) != 0) - /* The function uses a register quad and/or pair. Nothing to do. */ - ; - else if ((classify & RS6000_BTC_ATTR_MASK) != 0) - gcc_unreachable (); - - if (TARGET_DEBUG_BUILTIN) - { - tree t = TREE_TYPE (type); - fprintf (stderr, "%s %s (", rs6000_type_string (t), name); - t = TYPE_ARG_TYPES (type); - gcc_assert (t); - - while (TREE_VALUE (t) != void_type_node) - { - fprintf (stderr, "%s", rs6000_type_string (TREE_VALUE (t))); - t = TREE_CHAIN (t); - gcc_assert (t); - if (TREE_VALUE (t) != void_type_node) - fprintf (stderr, ", "); - } - fprintf (stderr, "); %s [%4d]\n", attr_string, (int) code); - } -} - static const struct builtin_compatibility bdesc_compat[] = { #define RS6000_BUILTIN_COMPAT @@ -9473,8744 +9383,3631 @@ rs6000_overloaded_builtin_name (enum rs6000_builtins fncode) return rs6000_builtin_info[(int)fncode].name; } -/* Expand an expression EXP that calls a builtin without arguments. */ static rtx -rs6000_expand_zeroop_builtin (enum insn_code icode, rtx target) +altivec_expand_predicate_builtin (enum insn_code icode, tree exp, rtx target) { - rtx pat; - machine_mode tmode = insn_data[icode].operand[0].mode; - - if (icode == CODE_FOR_nothing) - /* Builtin not supported on this processor. */ - return 0; + rtx pat, scratch; + tree cr6_form = CALL_EXPR_ARG (exp, 0); + tree arg0 = CALL_EXPR_ARG (exp, 1); + tree arg1 = CALL_EXPR_ARG (exp, 2); + rtx op0 = expand_normal (arg0); + rtx op1 = expand_normal (arg1); + machine_mode tmode = SImode; + machine_mode mode0 = insn_data[icode].operand[1].mode; + machine_mode mode1 = insn_data[icode].operand[2].mode; + int cr6_form_int; - if (icode == CODE_FOR_rs6000_mffsl - && rs6000_isa_flags & OPTION_MASK_SOFT_FLOAT) + if (TREE_CODE (cr6_form) != INTEGER_CST) { - error ("%<__builtin_mffsl%> not supported with %<-msoft-float%>"); + error ("argument 1 of %qs must be a constant", + "__builtin_altivec_predicate"); return const0_rtx; } + else + cr6_form_int = TREE_INT_CST_LOW (cr6_form); + + gcc_assert (mode0 == mode1); + + /* If we have invalid arguments, bail out before generating bad rtl. */ + if (arg0 == error_mark_node || arg1 == error_mark_node) + return const0_rtx; if (target == 0 || GET_MODE (target) != tmode || ! (*insn_data[icode].operand[0].predicate) (target, tmode)) target = gen_reg_rtx (tmode); - pat = GEN_FCN (icode) (target); + if (! (*insn_data[icode].operand[1].predicate) (op0, mode0)) + op0 = copy_to_mode_reg (mode0, op0); + if (! (*insn_data[icode].operand[2].predicate) (op1, mode1)) + op1 = copy_to_mode_reg (mode1, op1); + + /* Note that for many of the relevant operations (e.g. cmpne or + cmpeq) with float or double operands, it makes more sense for the + mode of the allocated scratch register to select a vector of + integer. But the choice to copy the mode of operand 0 was made + long ago and there are no plans to change it. */ + scratch = gen_reg_rtx (mode0); + + pat = GEN_FCN (icode) (scratch, op0, op1); if (! pat) return 0; emit_insn (pat); - return target; -} - - -static rtx -rs6000_expand_mtfsf_builtin (enum insn_code icode, tree exp) -{ - rtx pat; - tree arg0 = CALL_EXPR_ARG (exp, 0); - tree arg1 = CALL_EXPR_ARG (exp, 1); - rtx op0 = expand_normal (arg0); - rtx op1 = expand_normal (arg1); - machine_mode mode0 = insn_data[icode].operand[0].mode; - machine_mode mode1 = insn_data[icode].operand[1].mode; - - if (icode == CODE_FOR_nothing) - /* Builtin not supported on this processor. */ - return 0; + /* The vec_any* and vec_all* predicates use the same opcodes for two + different operations, but the bits in CR6 will be different + depending on what information we want. So we have to play tricks + with CR6 to get the right bits out. - /* If we got invalid arguments bail out before generating bad rtl. */ - if (arg0 == error_mark_node || arg1 == error_mark_node) - return const0_rtx; + If you think this is disgusting, look at the specs for the + AltiVec predicates. */ - if (!CONST_INT_P (op0) - || INTVAL (op0) > 255 - || INTVAL (op0) < 0) + switch (cr6_form_int) { - error ("argument 1 must be an 8-bit field value"); - return const0_rtx; + case 0: + emit_insn (gen_cr6_test_for_zero (target)); + break; + case 1: + emit_insn (gen_cr6_test_for_zero_reverse (target)); + break; + case 2: + emit_insn (gen_cr6_test_for_lt (target)); + break; + case 3: + emit_insn (gen_cr6_test_for_lt_reverse (target)); + break; + default: + error ("argument 1 of %qs is out of range", + "__builtin_altivec_predicate"); + break; } - if (! (*insn_data[icode].operand[0].predicate) (op0, mode0)) - op0 = copy_to_mode_reg (mode0, op0); - - if (! (*insn_data[icode].operand[1].predicate) (op1, mode1)) - op1 = copy_to_mode_reg (mode1, op1); - - pat = GEN_FCN (icode) (op0, op1); - if (!pat) - return const0_rtx; - emit_insn (pat); - - return NULL_RTX; + return target; } -static rtx -rs6000_expand_mtfsb_builtin (enum insn_code icode, tree exp) +rtx +swap_endian_selector_for_mode (machine_mode mode) { - rtx pat; - tree arg0 = CALL_EXPR_ARG (exp, 0); - rtx op0 = expand_normal (arg0); + unsigned int swap1[16] = {15,14,13,12,11,10,9,8,7,6,5,4,3,2,1,0}; + unsigned int swap2[16] = {7,6,5,4,3,2,1,0,15,14,13,12,11,10,9,8}; + unsigned int swap4[16] = {3,2,1,0,7,6,5,4,11,10,9,8,15,14,13,12}; + unsigned int swap8[16] = {1,0,3,2,5,4,7,6,9,8,11,10,13,12,15,14}; - if (icode == CODE_FOR_nothing) - /* Builtin not supported on this processor. */ - return 0; + unsigned int *swaparray, i; + rtx perm[16]; - if (rs6000_isa_flags & OPTION_MASK_SOFT_FLOAT) + switch (mode) { - error ("%<__builtin_mtfsb0%> and %<__builtin_mtfsb1%> not supported with " - "%<-msoft-float%>"); - return const0_rtx; + case E_V1TImode: + swaparray = swap1; + break; + case E_V2DFmode: + case E_V2DImode: + swaparray = swap2; + break; + case E_V4SFmode: + case E_V4SImode: + swaparray = swap4; + break; + case E_V8HImode: + swaparray = swap8; + break; + default: + gcc_unreachable (); } - /* If we got invalid arguments bail out before generating bad rtl. */ - if (arg0 == error_mark_node) - return const0_rtx; + for (i = 0; i < 16; ++i) + perm[i] = GEN_INT (swaparray[i]); - /* Only allow bit numbers 0 to 31. */ - if (!u5bit_cint_operand (op0, VOIDmode)) - { - error ("Argument must be a constant between 0 and 31."); - return const0_rtx; - } + return force_reg (V16QImode, gen_rtx_CONST_VECTOR (V16QImode, + gen_rtvec_v (16, perm))); +} - pat = GEN_FCN (icode) (op0); - if (!pat) - return const0_rtx; - emit_insn (pat); +/* Return the appropriate SPR number associated with the given builtin. */ +static inline HOST_WIDE_INT +htm_spr_num (enum rs6000_builtins code) +{ + if (code == HTM_BUILTIN_GET_TFHAR + || code == HTM_BUILTIN_SET_TFHAR) + return TFHAR_SPR; + else if (code == HTM_BUILTIN_GET_TFIAR + || code == HTM_BUILTIN_SET_TFIAR) + return TFIAR_SPR; + else if (code == HTM_BUILTIN_GET_TEXASR + || code == HTM_BUILTIN_SET_TEXASR) + return TEXASR_SPR; + gcc_assert (code == HTM_BUILTIN_GET_TEXASRU + || code == HTM_BUILTIN_SET_TEXASRU); + return TEXASRU_SPR; +} - return NULL_RTX; +/* Return the correct ICODE value depending on whether we are + setting or reading the HTM SPRs. */ +static inline enum insn_code +rs6000_htm_spr_icode (bool nonvoid) +{ + if (nonvoid) + return (TARGET_POWERPC64) ? CODE_FOR_htm_mfspr_di : CODE_FOR_htm_mfspr_si; + else + return (TARGET_POWERPC64) ? CODE_FOR_htm_mtspr_di : CODE_FOR_htm_mtspr_si; } +/* Expand vec_init builtin. */ static rtx -rs6000_expand_set_fpscr_rn_builtin (enum insn_code icode, tree exp) +altivec_expand_vec_init_builtin (tree type, tree exp, rtx target) { - rtx pat; - tree arg0 = CALL_EXPR_ARG (exp, 0); - rtx op0 = expand_normal (arg0); - machine_mode mode0 = insn_data[icode].operand[0].mode; + machine_mode tmode = TYPE_MODE (type); + machine_mode inner_mode = GET_MODE_INNER (tmode); + int i, n_elt = GET_MODE_NUNITS (tmode); - if (icode == CODE_FOR_nothing) - /* Builtin not supported on this processor. */ - return 0; + gcc_assert (VECTOR_MODE_P (tmode)); + gcc_assert (n_elt == call_expr_nargs (exp)); + + if (!target || !register_operand (target, tmode)) + target = gen_reg_rtx (tmode); - if (rs6000_isa_flags & OPTION_MASK_SOFT_FLOAT) + /* If we have a vector compromised of a single element, such as V1TImode, do + the initialization directly. */ + if (n_elt == 1 && GET_MODE_SIZE (tmode) == GET_MODE_SIZE (inner_mode)) { - error ("%<__builtin_set_fpscr_rn%> not supported with %<-msoft-float%>"); - return const0_rtx; + rtx x = expand_normal (CALL_EXPR_ARG (exp, 0)); + emit_move_insn (target, gen_lowpart (tmode, x)); } + else + { + rtvec v = rtvec_alloc (n_elt); - /* If we got invalid arguments bail out before generating bad rtl. */ - if (arg0 == error_mark_node) - return const0_rtx; + for (i = 0; i < n_elt; ++i) + { + rtx x = expand_normal (CALL_EXPR_ARG (exp, i)); + RTVEC_ELT (v, i) = gen_lowpart (inner_mode, x); + } - /* If the argument is a constant, check the range. Argument can only be a - 2-bit value. Unfortunately, can't check the range of the value at - compile time if the argument is a variable. The least significant two - bits of the argument, regardless of type, are used to set the rounding - mode. All other bits are ignored. */ - if (CONST_INT_P (op0) && !const_0_to_3_operand(op0, VOIDmode)) - { - error ("Argument must be a value between 0 and 3."); - return const0_rtx; + rs6000_expand_vector_init (target, gen_rtx_PARALLEL (tmode, v)); } - if (! (*insn_data[icode].operand[0].predicate) (op0, mode0)) - op0 = copy_to_mode_reg (mode0, op0); + return target; +} - pat = GEN_FCN (icode) (op0); - if (!pat) - return const0_rtx; - emit_insn (pat); +/* Return the integer constant in ARG. Constrain it to be in the range + of the subparts of VEC_TYPE; issue an error if not. */ - return NULL_RTX; -} -static rtx -rs6000_expand_set_fpscr_drn_builtin (enum insn_code icode, tree exp) +static int +get_element_number (tree vec_type, tree arg) { - rtx pat; - tree arg0 = CALL_EXPR_ARG (exp, 0); - rtx op0 = expand_normal (arg0); - machine_mode mode0 = insn_data[icode].operand[0].mode; - - if (TARGET_32BIT) - /* Builtin not supported in 32-bit mode. */ - fatal_error (input_location, - "%<__builtin_set_fpscr_drn%> is not supported " - "in 32-bit mode"); + unsigned HOST_WIDE_INT elt, max = TYPE_VECTOR_SUBPARTS (vec_type) - 1; - if (rs6000_isa_flags & OPTION_MASK_SOFT_FLOAT) + if (!tree_fits_uhwi_p (arg) + || (elt = tree_to_uhwi (arg), elt > max)) { - error ("%<__builtin_set_fpscr_drn%> not supported with %<-msoft-float%>"); - return const0_rtx; - } - - if (icode == CODE_FOR_nothing) - /* Builtin not supported on this processor. */ - return 0; - - /* If we got invalid arguments bail out before generating bad rtl. */ - if (arg0 == error_mark_node) - return const0_rtx; - - /* If the argument is a constant, check the range. Agrument can only be a - 3-bit value. Unfortunately, can't check the range of the value at - compile time if the argument is a variable. The least significant two - bits of the argument, regardless of type, are used to set the rounding - mode. All other bits are ignored. */ - if (CONST_INT_P (op0) && !const_0_to_7_operand(op0, VOIDmode)) - { - error ("Argument must be a value between 0 and 7."); - return const0_rtx; + error ("selector must be an integer constant in the range [0, %wi]", max); + return 0; } - if (! (*insn_data[icode].operand[0].predicate) (op0, mode0)) - op0 = copy_to_mode_reg (mode0, op0); - - pat = GEN_FCN (icode) (op0); - if (! pat) - return const0_rtx; - emit_insn (pat); - - return NULL_RTX; + return elt; } +/* Expand vec_set builtin. */ static rtx -rs6000_expand_unop_builtin (enum insn_code icode, tree exp, rtx target) +altivec_expand_vec_set_builtin (tree exp) { - rtx pat; - tree arg0 = CALL_EXPR_ARG (exp, 0); - rtx op0 = expand_normal (arg0); - machine_mode tmode = insn_data[icode].operand[0].mode; - machine_mode mode0 = insn_data[icode].operand[1].mode; - - if (icode == CODE_FOR_nothing) - /* Builtin not supported on this processor. */ - return 0; - - /* If we got invalid arguments bail out before generating bad rtl. */ - if (arg0 == error_mark_node) - return const0_rtx; - - if (icode == CODE_FOR_altivec_vspltisb - || icode == CODE_FOR_altivec_vspltish - || icode == CODE_FOR_altivec_vspltisw) - { - /* Only allow 5-bit *signed* literals. */ - if (!CONST_INT_P (op0) - || INTVAL (op0) > 15 - || INTVAL (op0) < -16) - { - error ("argument 1 must be a 5-bit signed literal"); - return CONST0_RTX (tmode); - } - } - - if (target == 0 - || GET_MODE (target) != tmode - || ! (*insn_data[icode].operand[0].predicate) (target, tmode)) - target = gen_reg_rtx (tmode); - - if (! (*insn_data[icode].operand[1].predicate) (op0, mode0)) - op0 = copy_to_mode_reg (mode0, op0); - - pat = GEN_FCN (icode) (target, op0); - if (! pat) - return 0; - emit_insn (pat); - - return target; -} + machine_mode tmode, mode1; + tree arg0, arg1, arg2; + int elt; + rtx op0, op1; -static rtx -altivec_expand_abs_builtin (enum insn_code icode, tree exp, rtx target) -{ - rtx pat, scratch1, scratch2; - tree arg0 = CALL_EXPR_ARG (exp, 0); - rtx op0 = expand_normal (arg0); - machine_mode tmode = insn_data[icode].operand[0].mode; - machine_mode mode0 = insn_data[icode].operand[1].mode; + arg0 = CALL_EXPR_ARG (exp, 0); + arg1 = CALL_EXPR_ARG (exp, 1); + arg2 = CALL_EXPR_ARG (exp, 2); - /* If we have invalid arguments, bail out before generating bad rtl. */ - if (arg0 == error_mark_node) - return const0_rtx; + tmode = TYPE_MODE (TREE_TYPE (arg0)); + mode1 = TYPE_MODE (TREE_TYPE (TREE_TYPE (arg0))); + gcc_assert (VECTOR_MODE_P (tmode)); - if (target == 0 - || GET_MODE (target) != tmode - || ! (*insn_data[icode].operand[0].predicate) (target, tmode)) - target = gen_reg_rtx (tmode); + op0 = expand_expr (arg0, NULL_RTX, tmode, EXPAND_NORMAL); + op1 = expand_expr (arg1, NULL_RTX, mode1, EXPAND_NORMAL); + elt = get_element_number (TREE_TYPE (arg0), arg2); - if (! (*insn_data[icode].operand[1].predicate) (op0, mode0)) - op0 = copy_to_mode_reg (mode0, op0); + if (GET_MODE (op1) != mode1 && GET_MODE (op1) != VOIDmode) + op1 = convert_modes (mode1, GET_MODE (op1), op1, true); - scratch1 = gen_reg_rtx (mode0); - scratch2 = gen_reg_rtx (mode0); + op0 = force_reg (tmode, op0); + op1 = force_reg (mode1, op1); - pat = GEN_FCN (icode) (target, op0, scratch1, scratch2); - if (! pat) - return 0; - emit_insn (pat); + rs6000_expand_vector_set (op0, op1, GEN_INT (elt)); - return target; + return op0; } +/* Expand vec_ext builtin. */ static rtx -rs6000_expand_binop_builtin (enum insn_code icode, tree exp, rtx target) +altivec_expand_vec_ext_builtin (tree exp, rtx target) { - rtx pat; - tree arg0 = CALL_EXPR_ARG (exp, 0); - tree arg1 = CALL_EXPR_ARG (exp, 1); - rtx op0 = expand_normal (arg0); - rtx op1 = expand_normal (arg1); - machine_mode tmode = insn_data[icode].operand[0].mode; - machine_mode mode0 = insn_data[icode].operand[1].mode; - machine_mode mode1 = insn_data[icode].operand[2].mode; + machine_mode tmode, mode0; + tree arg0, arg1; + rtx op0; + rtx op1; - if (icode == CODE_FOR_nothing) - /* Builtin not supported on this processor. */ - return 0; + arg0 = CALL_EXPR_ARG (exp, 0); + arg1 = CALL_EXPR_ARG (exp, 1); - /* If we got invalid arguments bail out before generating bad rtl. */ - if (arg0 == error_mark_node || arg1 == error_mark_node) - return const0_rtx; + op0 = expand_normal (arg0); + op1 = expand_normal (arg1); - if (icode == CODE_FOR_unpackv1ti - || icode == CODE_FOR_unpackkf - || icode == CODE_FOR_unpacktf - || icode == CODE_FOR_unpackif - || icode == CODE_FOR_unpacktd - || icode == CODE_FOR_vec_cntmb_v16qi - || icode == CODE_FOR_vec_cntmb_v8hi - || icode == CODE_FOR_vec_cntmb_v4si - || icode == CODE_FOR_vec_cntmb_v2di) - { - /* Only allow 1-bit unsigned literals. */ - STRIP_NOPS (arg1); - if (TREE_CODE (arg1) != INTEGER_CST - || !IN_RANGE (TREE_INT_CST_LOW (arg1), 0, 1)) - { - error ("argument 2 must be a 1-bit unsigned literal"); - return CONST0_RTX (tmode); - } - } - else if (icode == CODE_FOR_altivec_vspltw) - { - /* Only allow 2-bit unsigned literals. */ - STRIP_NOPS (arg1); - if (TREE_CODE (arg1) != INTEGER_CST - || TREE_INT_CST_LOW (arg1) & ~3) - { - error ("argument 2 must be a 2-bit unsigned literal"); - return CONST0_RTX (tmode); - } - } - else if (icode == CODE_FOR_vgnb) - { - /* Only allow unsigned literals in range 2..7. */ - /* Note that arg1 is second operand. */ - STRIP_NOPS (arg1); - if (TREE_CODE (arg1) != INTEGER_CST - || (TREE_INT_CST_LOW (arg1) & ~7) - || !IN_RANGE (TREE_INT_CST_LOW (arg1), 2, 7)) - { - error ("argument 2 must be unsigned literal between " - "2 and 7 inclusive"); - return CONST0_RTX (tmode); - } - } - else if (icode == CODE_FOR_altivec_vsplth) - { - /* Only allow 3-bit unsigned literals. */ - STRIP_NOPS (arg1); - if (TREE_CODE (arg1) != INTEGER_CST - || TREE_INT_CST_LOW (arg1) & ~7) - { - error ("argument 2 must be a 3-bit unsigned literal"); - return CONST0_RTX (tmode); - } - } - else if (icode == CODE_FOR_altivec_vspltb) - { - /* Only allow 4-bit unsigned literals. */ - STRIP_NOPS (arg1); - if (TREE_CODE (arg1) != INTEGER_CST - || TREE_INT_CST_LOW (arg1) & ~15) - { - error ("argument 2 must be a 4-bit unsigned literal"); - return CONST0_RTX (tmode); - } - } - else if (icode == CODE_FOR_altivec_vcfux - || icode == CODE_FOR_altivec_vcfsx - || icode == CODE_FOR_altivec_vctsxs - || icode == CODE_FOR_altivec_vctuxs - || icode == CODE_FOR_vsx_xvcvuxddp_scale - || icode == CODE_FOR_vsx_xvcvsxddp_scale) - { - /* Only allow 5-bit unsigned literals. */ - STRIP_NOPS (arg1); - if (TREE_CODE (arg1) != INTEGER_CST - || TREE_INT_CST_LOW (arg1) & ~0x1f) - { - error ("argument 2 must be a 5-bit unsigned literal"); - return CONST0_RTX (tmode); - } - } - else if (icode == CODE_FOR_dfptstsfi_eq_dd - || icode == CODE_FOR_dfptstsfi_lt_dd - || icode == CODE_FOR_dfptstsfi_gt_dd - || icode == CODE_FOR_dfptstsfi_unordered_dd - || icode == CODE_FOR_dfptstsfi_eq_td - || icode == CODE_FOR_dfptstsfi_lt_td - || icode == CODE_FOR_dfptstsfi_gt_td - || icode == CODE_FOR_dfptstsfi_unordered_td) - { - /* Only allow 6-bit unsigned literals. */ - STRIP_NOPS (arg0); - if (TREE_CODE (arg0) != INTEGER_CST - || !IN_RANGE (TREE_INT_CST_LOW (arg0), 0, 63)) - { - error ("argument 1 must be a 6-bit unsigned literal"); - return CONST0_RTX (tmode); - } - } - else if (icode == CODE_FOR_xststdcqp_kf - || icode == CODE_FOR_xststdcqp_tf - || icode == CODE_FOR_xststdcdp - || icode == CODE_FOR_xststdcsp - || icode == CODE_FOR_xvtstdcdp - || icode == CODE_FOR_xvtstdcsp) + if (TREE_CODE (arg1) == INTEGER_CST) { - /* Only allow 7-bit unsigned literals. */ - STRIP_NOPS (arg1); - if (TREE_CODE (arg1) != INTEGER_CST - || !IN_RANGE (TREE_INT_CST_LOW (arg1), 0, 127)) - { - error ("argument 2 must be a 7-bit unsigned literal"); - return CONST0_RTX (tmode); - } + unsigned HOST_WIDE_INT elt; + unsigned HOST_WIDE_INT size = TYPE_VECTOR_SUBPARTS (TREE_TYPE (arg0)); + unsigned int truncated_selector; + /* Even if !tree_fits_uhwi_p (arg1)), TREE_INT_CST_LOW (arg0) + returns low-order bits of INTEGER_CST for modulo indexing. */ + elt = TREE_INT_CST_LOW (arg1); + truncated_selector = elt % size; + op1 = GEN_INT (truncated_selector); } - if (target == 0 - || GET_MODE (target) != tmode - || ! (*insn_data[icode].operand[0].predicate) (target, tmode)) - target = gen_reg_rtx (tmode); + tmode = TYPE_MODE (TREE_TYPE (TREE_TYPE (arg0))); + mode0 = TYPE_MODE (TREE_TYPE (arg0)); + gcc_assert (VECTOR_MODE_P (mode0)); - if (! (*insn_data[icode].operand[1].predicate) (op0, mode0)) - op0 = copy_to_mode_reg (mode0, op0); - if (! (*insn_data[icode].operand[2].predicate) (op1, mode1)) - op1 = copy_to_mode_reg (mode1, op1); + op0 = force_reg (mode0, op0); - pat = GEN_FCN (icode) (target, op0, op1); - if (! pat) - return 0; - emit_insn (pat); + if (optimize || !target || !register_operand (target, tmode)) + target = gen_reg_rtx (tmode); + + rs6000_expand_vector_extract (target, op0, op1); return target; } -static rtx -altivec_expand_predicate_builtin (enum insn_code icode, tree exp, rtx target) +/* Check whether a builtin function is supported in this target + configuration. */ +bool +rs6000_builtin_is_supported_p (enum rs6000_builtins fncode) { - rtx pat, scratch; - tree cr6_form = CALL_EXPR_ARG (exp, 0); - tree arg0 = CALL_EXPR_ARG (exp, 1); - tree arg1 = CALL_EXPR_ARG (exp, 2); - rtx op0 = expand_normal (arg0); - rtx op1 = expand_normal (arg1); - machine_mode tmode = SImode; - machine_mode mode0 = insn_data[icode].operand[1].mode; - machine_mode mode1 = insn_data[icode].operand[2].mode; - int cr6_form_int; - - if (TREE_CODE (cr6_form) != INTEGER_CST) - { - error ("argument 1 of %qs must be a constant", - "__builtin_altivec_predicate"); - return const0_rtx; - } + HOST_WIDE_INT fnmask = rs6000_builtin_info[fncode].mask; + if ((fnmask & rs6000_builtin_mask) != fnmask) + return false; else - cr6_form_int = TREE_INT_CST_LOW (cr6_form); - - gcc_assert (mode0 == mode1); - - /* If we have invalid arguments, bail out before generating bad rtl. */ - if (arg0 == error_mark_node || arg1 == error_mark_node) - return const0_rtx; - - if (target == 0 - || GET_MODE (target) != tmode - || ! (*insn_data[icode].operand[0].predicate) (target, tmode)) - target = gen_reg_rtx (tmode); - - if (! (*insn_data[icode].operand[1].predicate) (op0, mode0)) - op0 = copy_to_mode_reg (mode0, op0); - if (! (*insn_data[icode].operand[2].predicate) (op1, mode1)) - op1 = copy_to_mode_reg (mode1, op1); - - /* Note that for many of the relevant operations (e.g. cmpne or - cmpeq) with float or double operands, it makes more sense for the - mode of the allocated scratch register to select a vector of - integer. But the choice to copy the mode of operand 0 was made - long ago and there are no plans to change it. */ - scratch = gen_reg_rtx (mode0); - - pat = GEN_FCN (icode) (scratch, op0, op1); - if (! pat) - return 0; - emit_insn (pat); + return true; +} - /* The vec_any* and vec_all* predicates use the same opcodes for two - different operations, but the bits in CR6 will be different - depending on what information we want. So we have to play tricks - with CR6 to get the right bits out. +/* Raise an error message for a builtin function that is called without the + appropriate target options being set. */ - If you think this is disgusting, look at the specs for the - AltiVec predicates. */ +void +rs6000_invalid_new_builtin (enum rs6000_gen_builtins fncode) +{ + size_t j = (size_t) fncode; + const char *name = rs6000_builtin_info_x[j].bifname; - switch (cr6_form_int) + switch (rs6000_builtin_info_x[j].enable) { - case 0: - emit_insn (gen_cr6_test_for_zero (target)); + case ENB_P5: + error ("%qs requires the %qs option", name, "-mcpu=power5"); break; - case 1: - emit_insn (gen_cr6_test_for_zero_reverse (target)); + case ENB_P6: + error ("%qs requires the %qs option", name, "-mcpu=power6"); break; - case 2: - emit_insn (gen_cr6_test_for_lt (target)); + case ENB_P6_64: + error ("%qs requires the %qs option and either the %qs or %qs option", + name, "-mcpu=power6", "-m64", "-mpowerpc64"); break; - case 3: - emit_insn (gen_cr6_test_for_lt_reverse (target)); + case ENB_ALTIVEC: + error ("%qs requires the %qs option", name, "-maltivec"); break; - default: - error ("argument 1 of %qs is out of range", - "__builtin_altivec_predicate"); + case ENB_CELL: + error ("%qs requires the %qs option", name, "-mcpu=cell"); break; - } - - return target; -} - -rtx -swap_endian_selector_for_mode (machine_mode mode) -{ - unsigned int swap1[16] = {15,14,13,12,11,10,9,8,7,6,5,4,3,2,1,0}; - unsigned int swap2[16] = {7,6,5,4,3,2,1,0,15,14,13,12,11,10,9,8}; - unsigned int swap4[16] = {3,2,1,0,7,6,5,4,11,10,9,8,15,14,13,12}; - unsigned int swap8[16] = {1,0,3,2,5,4,7,6,9,8,11,10,13,12,15,14}; - - unsigned int *swaparray, i; - rtx perm[16]; - - switch (mode) - { - case E_V1TImode: - swaparray = swap1; + case ENB_VSX: + error ("%qs requires the %qs option", name, "-mvsx"); break; - case E_V2DFmode: - case E_V2DImode: - swaparray = swap2; + case ENB_P7: + error ("%qs requires the %qs option", name, "-mcpu=power7"); break; - case E_V4SFmode: - case E_V4SImode: - swaparray = swap4; + case ENB_P7_64: + error ("%qs requires the %qs option and either the %qs or %qs option", + name, "-mcpu=power7", "-m64", "-mpowerpc64"); break; - case E_V8HImode: - swaparray = swap8; + case ENB_P8: + error ("%qs requires the %qs option", name, "-mcpu=power8"); + break; + case ENB_P8V: + error ("%qs requires the %qs and %qs options", name, "-mcpu=power8", + "-mvsx"); + break; + case ENB_P9: + error ("%qs requires the %qs option", name, "-mcpu=power9"); + break; + case ENB_P9_64: + error ("%qs requires the %qs option and either the %qs or %qs option", + name, "-mcpu=power9", "-m64", "-mpowerpc64"); + break; + case ENB_P9V: + error ("%qs requires the %qs and %qs options", name, "-mcpu=power9", + "-mvsx"); + break; + case ENB_IEEE128_HW: + error ("%qs requires ISA 3.0 IEEE 128-bit floating point", name); + break; + case ENB_DFP: + error ("%qs requires the %qs option", name, "-mhard-dfp"); + break; + case ENB_CRYPTO: + error ("%qs requires the %qs option", name, "-mcrypto"); + break; + case ENB_HTM: + error ("%qs requires the %qs option", name, "-mhtm"); + break; + case ENB_P10: + error ("%qs requires the %qs option", name, "-mcpu=power10"); + break; + case ENB_P10_64: + error ("%qs requires the %qs option and either the %qs or %qs option", + name, "-mcpu=power10", "-m64", "-mpowerpc64"); + break; + case ENB_MMA: + error ("%qs requires the %qs option", name, "-mmma"); break; default: + case ENB_ALWAYS: gcc_unreachable (); } +} - for (i = 0; i < 16; ++i) - perm[i] = GEN_INT (swaparray[i]); +/* Target hook for early folding of built-ins, shamelessly stolen + from ia64.c. */ - return force_reg (V16QImode, gen_rtx_CONST_VECTOR (V16QImode, - gen_rtvec_v (16, perm))); +tree +rs6000_fold_builtin (tree fndecl ATTRIBUTE_UNUSED, + int n_args ATTRIBUTE_UNUSED, + tree *args ATTRIBUTE_UNUSED, + bool ignore ATTRIBUTE_UNUSED) +{ +#ifdef SUBTARGET_FOLD_BUILTIN + return SUBTARGET_FOLD_BUILTIN (fndecl, n_args, args, ignore); +#else + return NULL_TREE; +#endif } -/* For the load and sign extend rightmost elements; load and zero extend - rightmost element builtins. */ -static rtx -altivec_expand_lxvr_builtin (enum insn_code icode, tree exp, rtx target, bool blk, bool sign_extend) +/* Helper function to handle the gimple folding of a vector compare + operation. This sets up true/false vectors, and uses the + VEC_COND_EXPR operation. + CODE indicates which comparison is to be made. (EQ, GT, ...). + TYPE indicates the type of the result. + Code is inserted before GSI. */ +static tree +fold_build_vec_cmp (tree_code code, tree type, tree arg0, tree arg1, + gimple_stmt_iterator *gsi) { - rtx pat, addr; - tree arg0 = CALL_EXPR_ARG (exp, 0); - tree arg1 = CALL_EXPR_ARG (exp, 1); - machine_mode tmode = insn_data[icode].operand[0].mode; - machine_mode smode = insn_data[icode].operand[1].mode; - machine_mode mode0 = Pmode; - machine_mode mode1 = Pmode; - rtx op0 = expand_normal (arg0); - rtx op1 = expand_normal (arg1); - - if (icode == CODE_FOR_nothing) - /* Builtin not supported on this processor. */ - return 0; - - /* If we got invalid arguments bail out before generating bad rtl. */ - if (arg0 == error_mark_node || arg1 == error_mark_node) - return const0_rtx; - - if (target == 0 - || GET_MODE (target) != tmode - || ! (*insn_data[icode].operand[0].predicate) (target, tmode)) - target = gen_reg_rtx (tmode); + tree cmp_type = truth_type_for (type); + tree zero_vec = build_zero_cst (type); + tree minus_one_vec = build_minus_one_cst (type); + tree temp = create_tmp_reg_or_ssa_name (cmp_type); + gimple *g = gimple_build_assign (temp, code, arg0, arg1); + gsi_insert_before (gsi, g, GSI_SAME_STMT); + return fold_build3 (VEC_COND_EXPR, type, temp, minus_one_vec, zero_vec); +} - op1 = copy_to_mode_reg (mode1, op1); +/* Helper function to handle the in-between steps for the + vector compare built-ins. */ +static void +fold_compare_helper (gimple_stmt_iterator *gsi, tree_code code, gimple *stmt) +{ + tree arg0 = gimple_call_arg (stmt, 0); + tree arg1 = gimple_call_arg (stmt, 1); + tree lhs = gimple_call_lhs (stmt); + tree cmp = fold_build_vec_cmp (code, TREE_TYPE (lhs), arg0, arg1, gsi); + gimple *g = gimple_build_assign (lhs, cmp); + gimple_set_location (g, gimple_location (stmt)); + gsi_replace (gsi, g, true); +} - if (op0 == const0_rtx) - addr = gen_rtx_MEM (blk ? BLKmode : tmode, op1); +/* Helper function to map V2DF and V4SF types to their + integral equivalents (V2DI and V4SI). */ +tree map_to_integral_tree_type (tree input_tree_type) +{ + if (INTEGRAL_TYPE_P (TREE_TYPE (input_tree_type))) + return input_tree_type; else { - op0 = copy_to_mode_reg (mode0, op0); - addr = gen_rtx_MEM (blk ? BLKmode : smode, - gen_rtx_PLUS (Pmode, op1, op0)); - } - - if (sign_extend) - { - rtx discratch = gen_reg_rtx (V2DImode); - rtx tiscratch = gen_reg_rtx (TImode); - - /* Emit the lxvr*x insn. */ - pat = GEN_FCN (icode) (tiscratch, addr); - if (!pat) - return 0; - emit_insn (pat); - - /* Emit a sign extension from V16QI,V8HI,V4SI to V2DI. */ - rtx temp1, temp2; - if (icode == CODE_FOR_vsx_lxvrbx) - { - temp1 = simplify_gen_subreg (V16QImode, tiscratch, TImode, 0); - emit_insn (gen_vsx_sign_extend_qi_v2di (discratch, temp1)); - } - else if (icode == CODE_FOR_vsx_lxvrhx) - { - temp1 = simplify_gen_subreg (V8HImode, tiscratch, TImode, 0); - emit_insn (gen_vsx_sign_extend_hi_v2di (discratch, temp1)); - } - else if (icode == CODE_FOR_vsx_lxvrwx) - { - temp1 = simplify_gen_subreg (V4SImode, tiscratch, TImode, 0); - emit_insn (gen_vsx_sign_extend_si_v2di (discratch, temp1)); - } - else if (icode == CODE_FOR_vsx_lxvrdx) - discratch = simplify_gen_subreg (V2DImode, tiscratch, TImode, 0); + if (types_compatible_p (TREE_TYPE (input_tree_type), + TREE_TYPE (V2DF_type_node))) + return V2DI_type_node; + else if (types_compatible_p (TREE_TYPE (input_tree_type), + TREE_TYPE (V4SF_type_node))) + return V4SI_type_node; else gcc_unreachable (); - - /* Emit the sign extension from V2DI (double) to TI (quad). */ - temp2 = simplify_gen_subreg (TImode, discratch, V2DImode, 0); - emit_insn (gen_extendditi2_vector (target, temp2)); - - return target; - } - else - { - /* Zero extend. */ - pat = GEN_FCN (icode) (target, addr); - if (!pat) - return 0; - emit_insn (pat); - return target; } - return 0; } -static rtx -altivec_expand_lv_builtin (enum insn_code icode, tree exp, rtx target, bool blk) +/* Helper function to handle the vector merge[hl] built-ins. The + implementation difference between h and l versions for this code are in + the values used when building of the permute vector for high word versus + low word merge. The variance is keyed off the use_high parameter. */ +static void +fold_mergehl_helper (gimple_stmt_iterator *gsi, gimple *stmt, int use_high) { - rtx pat, addr; - tree arg0 = CALL_EXPR_ARG (exp, 0); - tree arg1 = CALL_EXPR_ARG (exp, 1); - machine_mode tmode = insn_data[icode].operand[0].mode; - machine_mode mode0 = Pmode; - machine_mode mode1 = Pmode; - rtx op0 = expand_normal (arg0); - rtx op1 = expand_normal (arg1); - - if (icode == CODE_FOR_nothing) - /* Builtin not supported on this processor. */ - return 0; - - /* If we got invalid arguments bail out before generating bad rtl. */ - if (arg0 == error_mark_node || arg1 == error_mark_node) - return const0_rtx; + tree arg0 = gimple_call_arg (stmt, 0); + tree arg1 = gimple_call_arg (stmt, 1); + tree lhs = gimple_call_lhs (stmt); + tree lhs_type = TREE_TYPE (lhs); + int n_elts = TYPE_VECTOR_SUBPARTS (lhs_type); + int midpoint = n_elts / 2; + int offset = 0; - if (target == 0 - || GET_MODE (target) != tmode - || ! (*insn_data[icode].operand[0].predicate) (target, tmode)) - target = gen_reg_rtx (tmode); + if (use_high == 1) + offset = midpoint; - op1 = copy_to_mode_reg (mode1, op1); + /* The permute_type will match the lhs for integral types. For double and + float types, the permute type needs to map to the V2 or V4 type that + matches size. */ + tree permute_type; + permute_type = map_to_integral_tree_type (lhs_type); + tree_vector_builder elts (permute_type, VECTOR_CST_NELTS (arg0), 1); - /* For LVX, express the RTL accurately by ANDing the address with -16. - LVXL and LVE*X expand to use UNSPECs to hide their special behavior, - so the raw address is fine. */ - if (icode == CODE_FOR_altivec_lvx_v1ti - || icode == CODE_FOR_altivec_lvx_v2df - || icode == CODE_FOR_altivec_lvx_v2di - || icode == CODE_FOR_altivec_lvx_v4sf - || icode == CODE_FOR_altivec_lvx_v4si - || icode == CODE_FOR_altivec_lvx_v8hi - || icode == CODE_FOR_altivec_lvx_v16qi) + for (int i = 0; i < midpoint; i++) { - rtx rawaddr; - if (op0 == const0_rtx) - rawaddr = op1; - else - { - op0 = copy_to_mode_reg (mode0, op0); - rawaddr = gen_rtx_PLUS (Pmode, op1, op0); - } - addr = gen_rtx_AND (Pmode, rawaddr, gen_rtx_CONST_INT (Pmode, -16)); - addr = gen_rtx_MEM (blk ? BLKmode : tmode, addr); - - emit_insn (gen_rtx_SET (target, addr)); + elts.safe_push (build_int_cst (TREE_TYPE (permute_type), + offset + i)); + elts.safe_push (build_int_cst (TREE_TYPE (permute_type), + offset + n_elts + i)); } - else - { - if (op0 == const0_rtx) - addr = gen_rtx_MEM (blk ? BLKmode : tmode, op1); - else - { - op0 = copy_to_mode_reg (mode0, op0); - addr = gen_rtx_MEM (blk ? BLKmode : tmode, - gen_rtx_PLUS (Pmode, op1, op0)); - } - pat = GEN_FCN (icode) (target, addr); - if (! pat) - return 0; - emit_insn (pat); - } + tree permute = elts.build (); - return target; + gimple *g = gimple_build_assign (lhs, VEC_PERM_EXPR, arg0, arg1, permute); + gimple_set_location (g, gimple_location (stmt)); + gsi_replace (gsi, g, true); } -static rtx -altivec_expand_stxvl_builtin (enum insn_code icode, tree exp) +/* Helper function to handle the vector merge[eo] built-ins. */ +static void +fold_mergeeo_helper (gimple_stmt_iterator *gsi, gimple *stmt, int use_odd) { - rtx pat; - tree arg0 = CALL_EXPR_ARG (exp, 0); - tree arg1 = CALL_EXPR_ARG (exp, 1); - tree arg2 = CALL_EXPR_ARG (exp, 2); - rtx op0 = expand_normal (arg0); - rtx op1 = expand_normal (arg1); - rtx op2 = expand_normal (arg2); - machine_mode mode0 = insn_data[icode].operand[0].mode; - machine_mode mode1 = insn_data[icode].operand[1].mode; - machine_mode mode2 = insn_data[icode].operand[2].mode; + tree arg0 = gimple_call_arg (stmt, 0); + tree arg1 = gimple_call_arg (stmt, 1); + tree lhs = gimple_call_lhs (stmt); + tree lhs_type = TREE_TYPE (lhs); + int n_elts = TYPE_VECTOR_SUBPARTS (lhs_type); - if (icode == CODE_FOR_nothing) - /* Builtin not supported on this processor. */ - return NULL_RTX; + /* The permute_type will match the lhs for integral types. For double and + float types, the permute type needs to map to the V2 or V4 type that + matches size. */ + tree permute_type; + permute_type = map_to_integral_tree_type (lhs_type); - /* If we got invalid arguments bail out before generating bad rtl. */ - if (arg0 == error_mark_node - || arg1 == error_mark_node - || arg2 == error_mark_node) - return NULL_RTX; + tree_vector_builder elts (permute_type, VECTOR_CST_NELTS (arg0), 1); - if (! (*insn_data[icode].operand[1].predicate) (op0, mode0)) - op0 = copy_to_mode_reg (mode0, op0); - if (! (*insn_data[icode].operand[2].predicate) (op1, mode1)) - op1 = copy_to_mode_reg (mode1, op1); - if (! (*insn_data[icode].operand[3].predicate) (op2, mode2)) - op2 = copy_to_mode_reg (mode2, op2); + /* Build the permute vector. */ + for (int i = 0; i < n_elts / 2; i++) + { + elts.safe_push (build_int_cst (TREE_TYPE (permute_type), + 2*i + use_odd)); + elts.safe_push (build_int_cst (TREE_TYPE (permute_type), + 2*i + use_odd + n_elts)); + } - pat = GEN_FCN (icode) (op0, op1, op2); - if (pat) - emit_insn (pat); + tree permute = elts.build (); - return NULL_RTX; + gimple *g = gimple_build_assign (lhs, VEC_PERM_EXPR, arg0, arg1, permute); + gimple_set_location (g, gimple_location (stmt)); + gsi_replace (gsi, g, true); } -static rtx -altivec_expand_stv_builtin (enum insn_code icode, tree exp) -{ - tree arg0 = CALL_EXPR_ARG (exp, 0); - tree arg1 = CALL_EXPR_ARG (exp, 1); - tree arg2 = CALL_EXPR_ARG (exp, 2); - rtx op0 = expand_normal (arg0); - rtx op1 = expand_normal (arg1); - rtx op2 = expand_normal (arg2); - rtx pat, addr, rawaddr, truncrtx; - machine_mode tmode = insn_data[icode].operand[0].mode; - machine_mode smode = insn_data[icode].operand[1].mode; - machine_mode mode1 = Pmode; - machine_mode mode2 = Pmode; - - /* Invalid arguments. Bail before doing anything stoopid! */ - if (arg0 == error_mark_node - || arg1 == error_mark_node - || arg2 == error_mark_node) - return const0_rtx; - - op2 = copy_to_mode_reg (mode2, op2); +/* Expand the MMA built-ins early, so that we can convert the pass-by-reference + __vector_quad arguments into pass-by-value arguments, leading to more + efficient code generation. */ - /* For STVX, express the RTL accurately by ANDing the address with -16. - STVXL and STVE*X expand to use UNSPECs to hide their special behavior, - so the raw address is fine. */ - if (icode == CODE_FOR_altivec_stvx_v2df - || icode == CODE_FOR_altivec_stvx_v2di - || icode == CODE_FOR_altivec_stvx_v4sf - || icode == CODE_FOR_altivec_stvx_v4si - || icode == CODE_FOR_altivec_stvx_v8hi - || icode == CODE_FOR_altivec_stvx_v16qi) - { - if (op1 == const0_rtx) - rawaddr = op2; - else - { - op1 = copy_to_mode_reg (mode1, op1); - rawaddr = gen_rtx_PLUS (Pmode, op2, op1); - } +bool +rs6000_gimple_fold_mma_builtin (gimple_stmt_iterator *gsi) +{ + gimple *stmt = gsi_stmt (*gsi); + tree fndecl = gimple_call_fndecl (stmt); + enum rs6000_builtins fncode + = (enum rs6000_builtins) DECL_MD_FUNCTION_CODE (fndecl); + unsigned attr = rs6000_builtin_info[fncode].attr; - addr = gen_rtx_AND (Pmode, rawaddr, gen_rtx_CONST_INT (Pmode, -16)); - addr = gen_rtx_MEM (tmode, addr); + if ((attr & RS6000_BTC_GIMPLE) == 0) + return false; - op0 = copy_to_mode_reg (tmode, op0); + unsigned nopnds = (attr & RS6000_BTC_OPND_MASK); + gimple_seq new_seq = NULL; + gimple *new_call; + tree new_decl; - emit_insn (gen_rtx_SET (addr, op0)); - } - else if (icode == CODE_FOR_vsx_stxvrbx - || icode == CODE_FOR_vsx_stxvrhx - || icode == CODE_FOR_vsx_stxvrwx - || icode == CODE_FOR_vsx_stxvrdx) + if (fncode == MMA_BUILTIN_DISASSEMBLE_ACC + || fncode == VSX_BUILTIN_DISASSEMBLE_PAIR) { - truncrtx = gen_rtx_TRUNCATE (tmode, op0); - op0 = copy_to_mode_reg (E_TImode, truncrtx); + /* This is an MMA disassemble built-in function. */ + push_gimplify_context (true); + unsigned nvec = (fncode == MMA_BUILTIN_DISASSEMBLE_ACC) ? 4 : 2; + tree dst_ptr = gimple_call_arg (stmt, 0); + tree src_ptr = gimple_call_arg (stmt, 1); + tree src_type = TREE_TYPE (src_ptr); + tree src = create_tmp_reg_or_ssa_name (TREE_TYPE (src_type)); + gimplify_assign (src, build_simple_mem_ref (src_ptr), &new_seq); - if (op1 == const0_rtx) - addr = gen_rtx_MEM (Pmode, op2); - else + /* If we are not disassembling an accumulator/pair or our destination is + another accumulator/pair, then just copy the entire thing as is. */ + if ((fncode == MMA_BUILTIN_DISASSEMBLE_ACC + && TREE_TYPE (TREE_TYPE (dst_ptr)) == vector_quad_type_node) + || (fncode == VSX_BUILTIN_DISASSEMBLE_PAIR + && TREE_TYPE (TREE_TYPE (dst_ptr)) == vector_pair_type_node)) { - op1 = copy_to_mode_reg (mode1, op1); - addr = gen_rtx_MEM (tmode, gen_rtx_PLUS (Pmode, op2, op1)); + tree dst = build_simple_mem_ref (build1 (VIEW_CONVERT_EXPR, + src_type, dst_ptr)); + gimplify_assign (dst, src, &new_seq); + pop_gimplify_context (NULL); + gsi_replace_with_seq (gsi, new_seq, true); + return true; } - pat = GEN_FCN (icode) (addr, op0); - if (pat) - emit_insn (pat); - } - else - { - if (! (*insn_data[icode].operand[1].predicate) (op0, smode)) - op0 = copy_to_mode_reg (smode, op0); - if (op1 == const0_rtx) - addr = gen_rtx_MEM (tmode, op2); - else + /* If we're disassembling an accumulator into a different type, we need + to emit a xxmfacc instruction now, since we cannot do it later. */ + if (fncode == MMA_BUILTIN_DISASSEMBLE_ACC) { - op1 = copy_to_mode_reg (mode1, op1); - addr = gen_rtx_MEM (tmode, gen_rtx_PLUS (Pmode, op2, op1)); + new_decl = rs6000_builtin_decls[MMA_BUILTIN_XXMFACC_INTERNAL]; + new_call = gimple_build_call (new_decl, 1, src); + src = create_tmp_reg_or_ssa_name (vector_quad_type_node); + gimple_call_set_lhs (new_call, src); + gimple_seq_add_stmt (&new_seq, new_call); } - pat = GEN_FCN (icode) (addr, op0); - if (pat) - emit_insn (pat); + /* Copy the accumulator/pair vector by vector. */ + new_decl = rs6000_builtin_decls[fncode + 1]; + tree dst_type = build_pointer_type_for_mode (unsigned_V16QI_type_node, + ptr_mode, true); + tree dst_base = build1 (VIEW_CONVERT_EXPR, dst_type, dst_ptr); + for (unsigned i = 0; i < nvec; i++) + { + unsigned index = WORDS_BIG_ENDIAN ? i : nvec - 1 - i; + tree dst = build2 (MEM_REF, unsigned_V16QI_type_node, dst_base, + build_int_cst (dst_type, index * 16)); + tree dstssa = create_tmp_reg_or_ssa_name (unsigned_V16QI_type_node); + new_call = gimple_build_call (new_decl, 2, src, + build_int_cstu (uint16_type_node, i)); + gimple_call_set_lhs (new_call, dstssa); + gimple_seq_add_stmt (&new_seq, new_call); + gimplify_assign (dst, dstssa, &new_seq); + } + pop_gimplify_context (NULL); + gsi_replace_with_seq (gsi, new_seq, true); + return true; } - - return NULL_RTX; -} - -/* Expand the MMA built-in in EXP. - Store true in *EXPANDEDP if we found a built-in to expand. */ - -static rtx -mma_expand_builtin (tree exp, rtx target, bool *expandedp) -{ - unsigned i; - tree fndecl = TREE_OPERAND (CALL_EXPR_FN (exp), 0); - enum rs6000_builtins fcode - = (enum rs6000_builtins) DECL_MD_FUNCTION_CODE (fndecl); - const struct builtin_description *d = bdesc_mma; - - /* Expand the MMA built-in. */ - for (i = 0; i < ARRAY_SIZE (bdesc_mma); i++, d++) - if (d->code == fcode) - break; - - if (i >= ARRAY_SIZE (bdesc_mma)) + else if (fncode == VSX_BUILTIN_LXVP) { - *expandedp = false; - return NULL_RTX; + push_gimplify_context (true); + tree offset = gimple_call_arg (stmt, 0); + tree ptr = gimple_call_arg (stmt, 1); + tree lhs = gimple_call_lhs (stmt); + if (TREE_TYPE (TREE_TYPE (ptr)) != vector_pair_type_node) + ptr = build1 (VIEW_CONVERT_EXPR, + build_pointer_type (vector_pair_type_node), ptr); + tree mem = build_simple_mem_ref (build2 (POINTER_PLUS_EXPR, + TREE_TYPE (ptr), ptr, offset)); + gimplify_assign (lhs, mem, &new_seq); + pop_gimplify_context (NULL); + gsi_replace_with_seq (gsi, new_seq, true); + return true; + } + else if (fncode == VSX_BUILTIN_STXVP) + { + push_gimplify_context (true); + tree src = gimple_call_arg (stmt, 0); + tree offset = gimple_call_arg (stmt, 1); + tree ptr = gimple_call_arg (stmt, 2); + if (TREE_TYPE (TREE_TYPE (ptr)) != vector_pair_type_node) + ptr = build1 (VIEW_CONVERT_EXPR, + build_pointer_type (vector_pair_type_node), ptr); + tree mem = build_simple_mem_ref (build2 (POINTER_PLUS_EXPR, + TREE_TYPE (ptr), ptr, offset)); + gimplify_assign (mem, src, &new_seq); + pop_gimplify_context (NULL); + gsi_replace_with_seq (gsi, new_seq, true); + return true; } - *expandedp = true; - - tree arg; - call_expr_arg_iterator iter; - enum insn_code icode = d->icode; - const struct insn_operand_data *insn_op; - rtx op[MAX_MMA_OPERANDS]; - unsigned nopnds = 0; - unsigned attr = rs6000_builtin_info[fcode].attr; - bool void_func = (attr & RS6000_BTC_VOID); - machine_mode tmode = VOIDmode; + /* Convert this built-in into an internal version that uses pass-by-value + arguments. The internal built-in follows immediately after this one. */ + new_decl = rs6000_builtin_decls[fncode + 1]; + tree lhs, op[MAX_MMA_OPERANDS]; + tree acc = gimple_call_arg (stmt, 0); + push_gimplify_context (true); - if (TREE_TYPE (TREE_TYPE (fndecl)) != void_type_node) + if ((attr & RS6000_BTC_QUAD) != 0) { - tmode = insn_data[icode].operand[0].mode; - if (!target - || GET_MODE (target) != tmode - || !(*insn_data[icode].operand[0].predicate) (target, tmode)) - target = gen_reg_rtx (tmode); - op[nopnds++] = target; + /* This built-in has a pass-by-reference accumulator input, so load it + into a temporary accumulator for use as a pass-by-value input. */ + op[0] = create_tmp_reg_or_ssa_name (vector_quad_type_node); + for (unsigned i = 1; i < nopnds; i++) + op[i] = gimple_call_arg (stmt, i); + gimplify_assign (op[0], build_simple_mem_ref (acc), &new_seq); } else - target = const0_rtx; - - FOR_EACH_CALL_EXPR_ARG (arg, iter, exp) { - if (arg == error_mark_node) - return const0_rtx; - - rtx opnd; - insn_op = &insn_data[icode].operand[nopnds]; - if (TREE_CODE (arg) == ADDR_EXPR - && MEM_P (DECL_RTL (TREE_OPERAND (arg, 0)))) - opnd = DECL_RTL (TREE_OPERAND (arg, 0)); - else - opnd = expand_normal (arg); - - if (!(*insn_op->predicate) (opnd, insn_op->mode)) - { - if (!strcmp (insn_op->constraint, "n")) - { - if (!CONST_INT_P (opnd)) - error ("argument %d must be an unsigned literal", nopnds); - else - error ("argument %d is an unsigned literal that is " - "out of range", nopnds); - return const0_rtx; - } - opnd = copy_to_mode_reg (insn_op->mode, opnd); - } - - /* Some MMA instructions have INOUT accumulator operands, so force - their target register to be the same as their input register. */ - if (!void_func - && nopnds == 1 - && !strcmp (insn_op->constraint, "0") - && insn_op->mode == tmode - && REG_P (opnd) - && (*insn_data[icode].operand[0].predicate) (opnd, tmode)) - target = op[0] = opnd; - - op[nopnds++] = opnd; + /* This built-in does not use its pass-by-reference accumulator argument + as an input argument, so remove it from the input list. */ + nopnds--; + for (unsigned i = 0; i < nopnds; i++) + op[i] = gimple_call_arg (stmt, i + 1); } - unsigned attr_args = attr & RS6000_BTC_OPND_MASK; - if (attr & RS6000_BTC_QUAD - || fcode == VSX_BUILTIN_DISASSEMBLE_PAIR_INTERNAL) - attr_args++; - - gcc_assert (nopnds == attr_args); - - rtx pat; switch (nopnds) { + case 0: + new_call = gimple_build_call (new_decl, 0); + break; case 1: - pat = GEN_FCN (icode) (op[0]); + new_call = gimple_build_call (new_decl, 1, op[0]); break; case 2: - pat = GEN_FCN (icode) (op[0], op[1]); + new_call = gimple_build_call (new_decl, 2, op[0], op[1]); break; case 3: - /* The ASSEMBLE builtin source operands are reversed in little-endian - mode, so reorder them. */ - if (fcode == VSX_BUILTIN_ASSEMBLE_PAIR_INTERNAL && !WORDS_BIG_ENDIAN) - std::swap (op[1], op[2]); - pat = GEN_FCN (icode) (op[0], op[1], op[2]); + new_call = gimple_build_call (new_decl, 3, op[0], op[1], op[2]); break; case 4: - pat = GEN_FCN (icode) (op[0], op[1], op[2], op[3]); + new_call = gimple_build_call (new_decl, 4, op[0], op[1], op[2], op[3]); break; case 5: - /* The ASSEMBLE builtin source operands are reversed in little-endian - mode, so reorder them. */ - if (fcode == MMA_BUILTIN_ASSEMBLE_ACC_INTERNAL && !WORDS_BIG_ENDIAN) - { - std::swap (op[1], op[4]); - std::swap (op[2], op[3]); - } - pat = GEN_FCN (icode) (op[0], op[1], op[2], op[3], op[4]); + new_call = gimple_build_call (new_decl, 5, op[0], op[1], op[2], op[3], + op[4]); break; case 6: - pat = GEN_FCN (icode) (op[0], op[1], op[2], op[3], op[4], op[5]); + new_call = gimple_build_call (new_decl, 6, op[0], op[1], op[2], op[3], + op[4], op[5]); break; case 7: - pat = GEN_FCN (icode) (op[0], op[1], op[2], op[3], op[4], op[5], op[6]); + new_call = gimple_build_call (new_decl, 7, op[0], op[1], op[2], op[3], + op[4], op[5], op[6]); break; default: gcc_unreachable (); } - if (!pat) - return NULL_RTX; - emit_insn (pat); - return target; + if (fncode == VSX_BUILTIN_BUILD_PAIR || fncode == VSX_BUILTIN_ASSEMBLE_PAIR) + lhs = create_tmp_reg_or_ssa_name (vector_pair_type_node); + else + lhs = create_tmp_reg_or_ssa_name (vector_quad_type_node); + gimple_call_set_lhs (new_call, lhs); + gimple_seq_add_stmt (&new_seq, new_call); + gimplify_assign (build_simple_mem_ref (acc), lhs, &new_seq); + pop_gimplify_context (NULL); + gsi_replace_with_seq (gsi, new_seq, true); + + return true; } -/* Return the appropriate SPR number associated with the given builtin. */ -static inline HOST_WIDE_INT -htm_spr_num (enum rs6000_builtins code) -{ - if (code == HTM_BUILTIN_GET_TFHAR - || code == HTM_BUILTIN_SET_TFHAR) - return TFHAR_SPR; - else if (code == HTM_BUILTIN_GET_TFIAR - || code == HTM_BUILTIN_SET_TFIAR) - return TFIAR_SPR; - else if (code == HTM_BUILTIN_GET_TEXASR - || code == HTM_BUILTIN_SET_TEXASR) - return TEXASR_SPR; - gcc_assert (code == HTM_BUILTIN_GET_TEXASRU - || code == HTM_BUILTIN_SET_TEXASRU); - return TEXASRU_SPR; -} +/* Fold a machine-dependent built-in in GIMPLE. (For folding into + a constant, use rs6000_fold_builtin.) */ -/* Return the correct ICODE value depending on whether we are - setting or reading the HTM SPRs. */ -static inline enum insn_code -rs6000_htm_spr_icode (bool nonvoid) +bool +rs6000_gimple_fold_builtin (gimple_stmt_iterator *gsi) { - if (nonvoid) - return (TARGET_POWERPC64) ? CODE_FOR_htm_mfspr_di : CODE_FOR_htm_mfspr_si; - else - return (TARGET_POWERPC64) ? CODE_FOR_htm_mtspr_di : CODE_FOR_htm_mtspr_si; + return rs6000_gimple_fold_new_builtin (gsi); } -/* Expand the HTM builtin in EXP and store the result in TARGET. - Store true in *EXPANDEDP if we found a builtin to expand. */ -static rtx -htm_expand_builtin (tree exp, rtx target, bool * expandedp) +/* Helper function to sort out which built-ins may be valid without having + a LHS. */ +static bool +rs6000_new_builtin_valid_without_lhs (enum rs6000_gen_builtins fn_code, + tree fndecl) { - tree fndecl = TREE_OPERAND (CALL_EXPR_FN (exp), 0); - bool nonvoid = TREE_TYPE (TREE_TYPE (fndecl)) != void_type_node; - enum rs6000_builtins fcode - = (enum rs6000_builtins) DECL_MD_FUNCTION_CODE (fndecl); - const struct builtin_description *d; - size_t i; - - *expandedp = true; + if (TREE_TYPE (TREE_TYPE (fndecl)) == void_type_node) + return true; - if (!TARGET_POWERPC64 - && (fcode == HTM_BUILTIN_TABORTDC - || fcode == HTM_BUILTIN_TABORTDCI)) + switch (fn_code) { - size_t uns_fcode = (size_t)fcode; - const char *name = rs6000_builtin_info[uns_fcode].name; - error ("builtin %qs is only valid in 64-bit mode", name); - return const0_rtx; + case RS6000_BIF_STVX_V16QI: + case RS6000_BIF_STVX_V8HI: + case RS6000_BIF_STVX_V4SI: + case RS6000_BIF_STVX_V4SF: + case RS6000_BIF_STVX_V2DI: + case RS6000_BIF_STVX_V2DF: + case RS6000_BIF_STXVW4X_V16QI: + case RS6000_BIF_STXVW4X_V8HI: + case RS6000_BIF_STXVW4X_V4SF: + case RS6000_BIF_STXVW4X_V4SI: + case RS6000_BIF_STXVD2X_V2DF: + case RS6000_BIF_STXVD2X_V2DI: + return true; + default: + return false; } - - /* Expand the HTM builtins. */ - d = bdesc_htm; - for (i = 0; i < ARRAY_SIZE (bdesc_htm); i++, d++) - if (d->code == fcode) - { - rtx op[MAX_HTM_OPERANDS], pat; - int nopnds = 0; - tree arg; - call_expr_arg_iterator iter; - unsigned attr = rs6000_builtin_info[fcode].attr; - enum insn_code icode = d->icode; - const struct insn_operand_data *insn_op; - bool uses_spr = (attr & RS6000_BTC_SPR); - rtx cr = NULL_RTX; - - if (uses_spr) - icode = rs6000_htm_spr_icode (nonvoid); - insn_op = &insn_data[icode].operand[0]; - - if (nonvoid) - { - machine_mode tmode = (uses_spr) ? insn_op->mode : E_SImode; - if (!target - || GET_MODE (target) != tmode - || (uses_spr && !(*insn_op->predicate) (target, tmode))) - target = gen_reg_rtx (tmode); - if (uses_spr) - op[nopnds++] = target; - } - - FOR_EACH_CALL_EXPR_ARG (arg, iter, exp) - { - if (arg == error_mark_node || nopnds >= MAX_HTM_OPERANDS) - return const0_rtx; - - insn_op = &insn_data[icode].operand[nopnds]; - - op[nopnds] = expand_normal (arg); - - if (!(*insn_op->predicate) (op[nopnds], insn_op->mode)) - { - if (!strcmp (insn_op->constraint, "n")) - { - int arg_num = (nonvoid) ? nopnds : nopnds + 1; - if (!CONST_INT_P (op[nopnds])) - error ("argument %d must be an unsigned literal", arg_num); - else - error ("argument %d is an unsigned literal that is " - "out of range", arg_num); - return const0_rtx; - } - op[nopnds] = copy_to_mode_reg (insn_op->mode, op[nopnds]); - } - - nopnds++; - } - - /* Handle the builtins for extended mnemonics. These accept - no arguments, but map to builtins that take arguments. */ - switch (fcode) - { - case HTM_BUILTIN_TENDALL: /* Alias for: tend. 1 */ - case HTM_BUILTIN_TRESUME: /* Alias for: tsr. 1 */ - op[nopnds++] = GEN_INT (1); - if (flag_checking) - attr |= RS6000_BTC_UNARY; - break; - case HTM_BUILTIN_TSUSPEND: /* Alias for: tsr. 0 */ - op[nopnds++] = GEN_INT (0); - if (flag_checking) - attr |= RS6000_BTC_UNARY; - break; - default: - break; - } - - /* If this builtin accesses SPRs, then pass in the appropriate - SPR number and SPR regno as the last two operands. */ - if (uses_spr) - { - machine_mode mode = (TARGET_POWERPC64) ? DImode : SImode; - op[nopnds++] = gen_rtx_CONST_INT (mode, htm_spr_num (fcode)); - } - /* If this builtin accesses a CR, then pass in a scratch - CR as the last operand. */ - else if (attr & RS6000_BTC_CR) - { cr = gen_reg_rtx (CCmode); - op[nopnds++] = cr; - } - - if (flag_checking) - { - int expected_nopnds = 0; - if ((attr & RS6000_BTC_OPND_MASK) == RS6000_BTC_UNARY) - expected_nopnds = 1; - else if ((attr & RS6000_BTC_OPND_MASK) == RS6000_BTC_BINARY) - expected_nopnds = 2; - else if ((attr & RS6000_BTC_OPND_MASK) == RS6000_BTC_TERNARY) - expected_nopnds = 3; - else if ((attr & RS6000_BTC_TYPE_MASK) == RS6000_BTC_QUATERNARY) - expected_nopnds = 4; - if (!(attr & RS6000_BTC_VOID)) - expected_nopnds += 1; - if (uses_spr) - expected_nopnds += 1; - - gcc_assert (nopnds == expected_nopnds - && nopnds <= MAX_HTM_OPERANDS); - } - - switch (nopnds) - { - case 1: - pat = GEN_FCN (icode) (op[0]); - break; - case 2: - pat = GEN_FCN (icode) (op[0], op[1]); - break; - case 3: - pat = GEN_FCN (icode) (op[0], op[1], op[2]); - break; - case 4: - pat = GEN_FCN (icode) (op[0], op[1], op[2], op[3]); - break; - default: - gcc_unreachable (); - } - if (!pat) - return NULL_RTX; - emit_insn (pat); - - if (attr & RS6000_BTC_CR) - { - if (fcode == HTM_BUILTIN_TBEGIN) - { - /* Emit code to set TARGET to true or false depending on - whether the tbegin. instruction successfully or failed - to start a transaction. We do this by placing the 1's - complement of CR's EQ bit into TARGET. */ - rtx scratch = gen_reg_rtx (SImode); - emit_insn (gen_rtx_SET (scratch, - gen_rtx_EQ (SImode, cr, - const0_rtx))); - emit_insn (gen_rtx_SET (target, - gen_rtx_XOR (SImode, scratch, - GEN_INT (1)))); - } - else - { - /* Emit code to copy the 4-bit condition register field - CR into the least significant end of register TARGET. */ - rtx scratch1 = gen_reg_rtx (SImode); - rtx scratch2 = gen_reg_rtx (SImode); - rtx subreg = simplify_gen_subreg (CCmode, scratch1, SImode, 0); - emit_insn (gen_movcc (subreg, cr)); - emit_insn (gen_lshrsi3 (scratch2, scratch1, GEN_INT (28))); - emit_insn (gen_andsi3 (target, scratch2, GEN_INT (0xf))); - } - } - - if (nonvoid) - return target; - return const0_rtx; - } - - *expandedp = false; - return NULL_RTX; } -/* Expand the CPU builtin in FCODE and store the result in TARGET. */ +/* Check whether a builtin function is supported in this target + configuration. */ +bool +rs6000_new_builtin_is_supported (enum rs6000_gen_builtins fncode) +{ + switch (rs6000_builtin_info_x[(size_t) fncode].enable) + { + case ENB_ALWAYS: + return true; + case ENB_P5: + return TARGET_POPCNTB; + case ENB_P6: + return TARGET_CMPB; + case ENB_P6_64: + return TARGET_CMPB && TARGET_POWERPC64; + case ENB_P7: + return TARGET_POPCNTD; + case ENB_P7_64: + return TARGET_POPCNTD && TARGET_POWERPC64; + case ENB_P8: + return TARGET_DIRECT_MOVE; + case ENB_P8V: + return TARGET_P8_VECTOR; + case ENB_P9: + return TARGET_MODULO; + case ENB_P9_64: + return TARGET_MODULO && TARGET_POWERPC64; + case ENB_P9V: + return TARGET_P9_VECTOR; + case ENB_P10: + return TARGET_POWER10; + case ENB_P10_64: + return TARGET_POWER10 && TARGET_POWERPC64; + case ENB_ALTIVEC: + return TARGET_ALTIVEC; + case ENB_VSX: + return TARGET_VSX; + case ENB_CELL: + return TARGET_ALTIVEC && rs6000_cpu == PROCESSOR_CELL; + case ENB_IEEE128_HW: + return TARGET_FLOAT128_HW; + case ENB_DFP: + return TARGET_DFP; + case ENB_CRYPTO: + return TARGET_CRYPTO; + case ENB_HTM: + return TARGET_HTM; + case ENB_MMA: + return TARGET_MMA; + default: + gcc_unreachable (); + } + gcc_unreachable (); +} -static rtx -cpu_expand_builtin (enum rs6000_builtins fcode, tree exp ATTRIBUTE_UNUSED, - rtx target) +/* Expand the MMA built-ins early, so that we can convert the pass-by-reference + __vector_quad arguments into pass-by-value arguments, leading to more + efficient code generation. */ +static bool +rs6000_gimple_fold_new_mma_builtin (gimple_stmt_iterator *gsi, + rs6000_gen_builtins fn_code) { - /* __builtin_cpu_init () is a nop, so expand to nothing. */ - if (fcode == RS6000_BUILTIN_CPU_INIT) - return const0_rtx; + gimple *stmt = gsi_stmt (*gsi); + size_t fncode = (size_t) fn_code; - if (target == 0 || GET_MODE (target) != SImode) - target = gen_reg_rtx (SImode); + if (!bif_is_mma (rs6000_builtin_info_x[fncode])) + return false; -#ifdef TARGET_LIBC_PROVIDES_HWCAP_IN_TCB - tree arg = TREE_OPERAND (CALL_EXPR_ARG (exp, 0), 0); - /* Target clones creates an ARRAY_REF instead of STRING_CST, convert it back - to a STRING_CST. */ - if (TREE_CODE (arg) == ARRAY_REF - && TREE_CODE (TREE_OPERAND (arg, 0)) == STRING_CST - && TREE_CODE (TREE_OPERAND (arg, 1)) == INTEGER_CST - && compare_tree_int (TREE_OPERAND (arg, 1), 0) == 0) - arg = TREE_OPERAND (arg, 0); + /* Each call that can be gimple-expanded has an associated built-in + function that it will expand into. If this one doesn't, we have + already expanded it! Exceptions: lxvp and stxvp. */ + if (rs6000_builtin_info_x[fncode].assoc_bif == RS6000_BIF_NONE + && fncode != RS6000_BIF_LXVP + && fncode != RS6000_BIF_STXVP) + return false; - if (TREE_CODE (arg) != STRING_CST) - { - error ("builtin %qs only accepts a string argument", - rs6000_builtin_info[(size_t) fcode].name); - return const0_rtx; - } + bifdata *bd = &rs6000_builtin_info_x[fncode]; + unsigned nopnds = bd->nargs; + gimple_seq new_seq = NULL; + gimple *new_call; + tree new_decl; + + /* Compatibility built-ins; we used to call these + __builtin_mma_{dis,}assemble_pair, but now we call them + __builtin_vsx_{dis,}assemble_pair. Handle the old versions. */ + if (fncode == RS6000_BIF_ASSEMBLE_PAIR) + fncode = RS6000_BIF_ASSEMBLE_PAIR_V; + else if (fncode == RS6000_BIF_DISASSEMBLE_PAIR) + fncode = RS6000_BIF_DISASSEMBLE_PAIR_V; - if (fcode == RS6000_BUILTIN_CPU_IS) + if (fncode == RS6000_BIF_DISASSEMBLE_ACC + || fncode == RS6000_BIF_DISASSEMBLE_PAIR_V) { - const char *cpu = TREE_STRING_POINTER (arg); - rtx cpuid = NULL_RTX; - for (size_t i = 0; i < ARRAY_SIZE (cpu_is_info); i++) - if (strcmp (cpu, cpu_is_info[i].cpu) == 0) - { - /* The CPUID value in the TCB is offset by _DL_FIRST_PLATFORM. */ - cpuid = GEN_INT (cpu_is_info[i].cpuid + _DL_FIRST_PLATFORM); - break; - } - if (cpuid == NULL_RTX) + /* This is an MMA disassemble built-in function. */ + push_gimplify_context (true); + unsigned nvec = (fncode == RS6000_BIF_DISASSEMBLE_ACC) ? 4 : 2; + tree dst_ptr = gimple_call_arg (stmt, 0); + tree src_ptr = gimple_call_arg (stmt, 1); + tree src_type = TREE_TYPE (src_ptr); + tree src = create_tmp_reg_or_ssa_name (TREE_TYPE (src_type)); + gimplify_assign (src, build_simple_mem_ref (src_ptr), &new_seq); + + /* If we are not disassembling an accumulator/pair or our destination is + another accumulator/pair, then just copy the entire thing as is. */ + if ((fncode == RS6000_BIF_DISASSEMBLE_ACC + && TREE_TYPE (TREE_TYPE (dst_ptr)) == vector_quad_type_node) + || (fncode == RS6000_BIF_DISASSEMBLE_PAIR_V + && TREE_TYPE (TREE_TYPE (dst_ptr)) == vector_pair_type_node)) { - /* Invalid CPU argument. */ - error ("cpu %qs is an invalid argument to builtin %qs", - cpu, rs6000_builtin_info[(size_t) fcode].name); - return const0_rtx; + tree dst = build_simple_mem_ref (build1 (VIEW_CONVERT_EXPR, + src_type, dst_ptr)); + gimplify_assign (dst, src, &new_seq); + pop_gimplify_context (NULL); + gsi_replace_with_seq (gsi, new_seq, true); + return true; } - rtx platform = gen_reg_rtx (SImode); - rtx tcbmem = gen_const_mem (SImode, - gen_rtx_PLUS (Pmode, - gen_rtx_REG (Pmode, TLS_REGNUM), - GEN_INT (TCB_PLATFORM_OFFSET))); - emit_move_insn (platform, tcbmem); - emit_insn (gen_eqsi3 (target, platform, cpuid)); - } - else if (fcode == RS6000_BUILTIN_CPU_SUPPORTS) - { - const char *hwcap = TREE_STRING_POINTER (arg); - rtx mask = NULL_RTX; - int hwcap_offset; - for (size_t i = 0; i < ARRAY_SIZE (cpu_supports_info); i++) - if (strcmp (hwcap, cpu_supports_info[i].hwcap) == 0) - { - mask = GEN_INT (cpu_supports_info[i].mask); - hwcap_offset = TCB_HWCAP_OFFSET (cpu_supports_info[i].id); - break; - } - if (mask == NULL_RTX) + /* If we're disassembling an accumulator into a different type, we need + to emit a xxmfacc instruction now, since we cannot do it later. */ + if (fncode == RS6000_BIF_DISASSEMBLE_ACC) { - /* Invalid HWCAP argument. */ - error ("%s %qs is an invalid argument to builtin %qs", - "hwcap", hwcap, rs6000_builtin_info[(size_t) fcode].name); - return const0_rtx; + new_decl = rs6000_builtin_decls_x[RS6000_BIF_XXMFACC_INTERNAL]; + new_call = gimple_build_call (new_decl, 1, src); + src = create_tmp_reg_or_ssa_name (vector_quad_type_node); + gimple_call_set_lhs (new_call, src); + gimple_seq_add_stmt (&new_seq, new_call); } - rtx tcb_hwcap = gen_reg_rtx (SImode); - rtx tcbmem = gen_const_mem (SImode, - gen_rtx_PLUS (Pmode, - gen_rtx_REG (Pmode, TLS_REGNUM), - GEN_INT (hwcap_offset))); - emit_move_insn (tcb_hwcap, tcbmem); - rtx scratch1 = gen_reg_rtx (SImode); - emit_insn (gen_rtx_SET (scratch1, gen_rtx_AND (SImode, tcb_hwcap, mask))); - rtx scratch2 = gen_reg_rtx (SImode); - emit_insn (gen_eqsi3 (scratch2, scratch1, const0_rtx)); - emit_insn (gen_rtx_SET (target, gen_rtx_XOR (SImode, scratch2, const1_rtx))); + /* Copy the accumulator/pair vector by vector. */ + new_decl + = rs6000_builtin_decls_x[rs6000_builtin_info_x[fncode].assoc_bif]; + tree dst_type = build_pointer_type_for_mode (unsigned_V16QI_type_node, + ptr_mode, true); + tree dst_base = build1 (VIEW_CONVERT_EXPR, dst_type, dst_ptr); + for (unsigned i = 0; i < nvec; i++) + { + unsigned index = WORDS_BIG_ENDIAN ? i : nvec - 1 - i; + tree dst = build2 (MEM_REF, unsigned_V16QI_type_node, dst_base, + build_int_cst (dst_type, index * 16)); + tree dstssa = create_tmp_reg_or_ssa_name (unsigned_V16QI_type_node); + new_call = gimple_build_call (new_decl, 2, src, + build_int_cstu (uint16_type_node, i)); + gimple_call_set_lhs (new_call, dstssa); + gimple_seq_add_stmt (&new_seq, new_call); + gimplify_assign (dst, dstssa, &new_seq); + } + pop_gimplify_context (NULL); + gsi_replace_with_seq (gsi, new_seq, true); + return true; } - else - gcc_unreachable (); - - /* Record that we have expanded a CPU builtin, so that we can later - emit a reference to the special symbol exported by LIBC to ensure we - do not link against an old LIBC that doesn't support this feature. */ - cpu_builtin_p = true; - -#else - warning (0, "builtin %qs needs GLIBC (2.23 and newer) that exports hardware " - "capability bits", rs6000_builtin_info[(size_t) fcode].name); - - /* For old LIBCs, always return FALSE. */ - emit_move_insn (target, GEN_INT (0)); -#endif /* TARGET_LIBC_PROVIDES_HWCAP_IN_TCB */ - - return target; -} - -static rtx -rs6000_expand_quaternop_builtin (enum insn_code icode, tree exp, rtx target) -{ - rtx pat; - tree arg0 = CALL_EXPR_ARG (exp, 0); - tree arg1 = CALL_EXPR_ARG (exp, 1); - tree arg2 = CALL_EXPR_ARG (exp, 2); - tree arg3 = CALL_EXPR_ARG (exp, 3); - rtx op0 = expand_normal (arg0); - rtx op1 = expand_normal (arg1); - rtx op2 = expand_normal (arg2); - rtx op3 = expand_normal (arg3); - machine_mode tmode = insn_data[icode].operand[0].mode; - machine_mode mode0 = insn_data[icode].operand[1].mode; - machine_mode mode1 = insn_data[icode].operand[2].mode; - machine_mode mode2 = insn_data[icode].operand[3].mode; - machine_mode mode3 = insn_data[icode].operand[4].mode; - if (icode == CODE_FOR_nothing) - /* Builtin not supported on this processor. */ - return 0; + /* TODO: Do some factoring on these two chunks. */ + if (fncode == RS6000_BIF_LXVP) + { + push_gimplify_context (true); + tree offset = gimple_call_arg (stmt, 0); + tree ptr = gimple_call_arg (stmt, 1); + tree lhs = gimple_call_lhs (stmt); + if (TREE_TYPE (TREE_TYPE (ptr)) != vector_pair_type_node) + ptr = build1 (VIEW_CONVERT_EXPR, + build_pointer_type (vector_pair_type_node), ptr); + tree mem = build_simple_mem_ref (build2 (POINTER_PLUS_EXPR, + TREE_TYPE (ptr), ptr, offset)); + gimplify_assign (lhs, mem, &new_seq); + pop_gimplify_context (NULL); + gsi_replace_with_seq (gsi, new_seq, true); + return true; + } - /* If we got invalid arguments bail out before generating bad rtl. */ - if (arg0 == error_mark_node - || arg1 == error_mark_node - || arg2 == error_mark_node - || arg3 == error_mark_node) - return const0_rtx; + if (fncode == RS6000_BIF_STXVP) + { + push_gimplify_context (true); + tree src = gimple_call_arg (stmt, 0); + tree offset = gimple_call_arg (stmt, 1); + tree ptr = gimple_call_arg (stmt, 2); + if (TREE_TYPE (TREE_TYPE (ptr)) != vector_pair_type_node) + ptr = build1 (VIEW_CONVERT_EXPR, + build_pointer_type (vector_pair_type_node), ptr); + tree mem = build_simple_mem_ref (build2 (POINTER_PLUS_EXPR, + TREE_TYPE (ptr), ptr, offset)); + gimplify_assign (mem, src, &new_seq); + pop_gimplify_context (NULL); + gsi_replace_with_seq (gsi, new_seq, true); + return true; + } - /* Check and prepare argument depending on the instruction code. + /* Convert this built-in into an internal version that uses pass-by-value + arguments. The internal built-in is found in the assoc_bif field. */ + new_decl = rs6000_builtin_decls_x[rs6000_builtin_info_x[fncode].assoc_bif]; + tree lhs, op[MAX_MMA_OPERANDS]; + tree acc = gimple_call_arg (stmt, 0); + push_gimplify_context (true); - Note that a switch statement instead of the sequence of tests - would be incorrect as many of the CODE_FOR values could be - CODE_FOR_nothing and that would yield multiple alternatives - with identical values. We'd never reach here at runtime in - this case. */ - if (icode == CODE_FOR_xxeval) + if (bif_is_quad (*bd)) { - /* Only allow 8-bit unsigned literals. */ - STRIP_NOPS (arg3); - if (TREE_CODE (arg3) != INTEGER_CST - || TREE_INT_CST_LOW (arg3) & ~0xff) - { - error ("argument 4 must be an 8-bit unsigned literal"); - return CONST0_RTX (tmode); - } + /* This built-in has a pass-by-reference accumulator input, so load it + into a temporary accumulator for use as a pass-by-value input. */ + op[0] = create_tmp_reg_or_ssa_name (vector_quad_type_node); + for (unsigned i = 1; i < nopnds; i++) + op[i] = gimple_call_arg (stmt, i); + gimplify_assign (op[0], build_simple_mem_ref (acc), &new_seq); + } + else + { + /* This built-in does not use its pass-by-reference accumulator argument + as an input argument, so remove it from the input list. */ + nopnds--; + for (unsigned i = 0; i < nopnds; i++) + op[i] = gimple_call_arg (stmt, i + 1); } - else if (icode == CODE_FOR_xxpermx) + switch (nopnds) { - /* Only allow 3-bit unsigned literals. */ - STRIP_NOPS (arg3); - if (TREE_CODE (arg3) != INTEGER_CST - || TREE_INT_CST_LOW (arg3) & ~0x7) - { - error ("argument 4 must be a 3-bit unsigned literal"); - return CONST0_RTX (tmode); - } + case 0: + new_call = gimple_build_call (new_decl, 0); + break; + case 1: + new_call = gimple_build_call (new_decl, 1, op[0]); + break; + case 2: + new_call = gimple_build_call (new_decl, 2, op[0], op[1]); + break; + case 3: + new_call = gimple_build_call (new_decl, 3, op[0], op[1], op[2]); + break; + case 4: + new_call = gimple_build_call (new_decl, 4, op[0], op[1], op[2], op[3]); + break; + case 5: + new_call = gimple_build_call (new_decl, 5, op[0], op[1], op[2], op[3], + op[4]); + break; + case 6: + new_call = gimple_build_call (new_decl, 6, op[0], op[1], op[2], op[3], + op[4], op[5]); + break; + case 7: + new_call = gimple_build_call (new_decl, 7, op[0], op[1], op[2], op[3], + op[4], op[5], op[6]); + break; + default: + gcc_unreachable (); } - else if (icode == CODE_FOR_vreplace_elt_v4si - || icode == CODE_FOR_vreplace_elt_v4sf) - { - /* Check whether the 3rd argument is an integer constant in the range - 0 to 3 inclusive. */ - STRIP_NOPS (arg2); - if (TREE_CODE (arg2) != INTEGER_CST - || !IN_RANGE (TREE_INT_CST_LOW (arg2), 0, 3)) - { - error ("argument 3 must be in the range 0 to 3"); - return CONST0_RTX (tmode); - } - } - - else if (icode == CODE_FOR_vreplace_un_v4si - || icode == CODE_FOR_vreplace_un_v4sf) - { - /* Check whether the 3rd argument is an integer constant in the range - 0 to 12 inclusive. */ - STRIP_NOPS (arg2); - if (TREE_CODE (arg2) != INTEGER_CST - || !IN_RANGE(TREE_INT_CST_LOW (arg2), 0, 12)) - { - error ("argument 3 must be in the range 0 to 12"); - return CONST0_RTX (tmode); - } - } - - else if (icode == CODE_FOR_vsldb_v16qi - || icode == CODE_FOR_vsldb_v8hi - || icode == CODE_FOR_vsldb_v4si - || icode == CODE_FOR_vsldb_v2di - || icode == CODE_FOR_vsrdb_v16qi - || icode == CODE_FOR_vsrdb_v8hi - || icode == CODE_FOR_vsrdb_v4si - || icode == CODE_FOR_vsrdb_v2di) - { - /* Check whether the 3rd argument is an integer constant in the range - 0 to 7 inclusive. */ - STRIP_NOPS (arg2); - if (TREE_CODE (arg2) != INTEGER_CST - || !IN_RANGE (TREE_INT_CST_LOW (arg2), 0, 7)) - { - error ("argument 3 must be a constant in the range 0 to 7"); - return CONST0_RTX (tmode); - } - } + if (fncode == RS6000_BIF_BUILD_PAIR || fncode == RS6000_BIF_ASSEMBLE_PAIR_V) + lhs = create_tmp_reg_or_ssa_name (vector_pair_type_node); + else + lhs = create_tmp_reg_or_ssa_name (vector_quad_type_node); + gimple_call_set_lhs (new_call, lhs); + gimple_seq_add_stmt (&new_seq, new_call); + gimplify_assign (build_simple_mem_ref (acc), lhs, &new_seq); + pop_gimplify_context (NULL); + gsi_replace_with_seq (gsi, new_seq, true); - if (target == 0 - || GET_MODE (target) != tmode - || ! (*insn_data[icode].operand[0].predicate) (target, tmode)) - target = gen_reg_rtx (tmode); + return true; +} - if (! (*insn_data[icode].operand[1].predicate) (op0, mode0)) - op0 = copy_to_mode_reg (mode0, op0); - if (! (*insn_data[icode].operand[2].predicate) (op1, mode1)) - op1 = copy_to_mode_reg (mode1, op1); - if (! (*insn_data[icode].operand[3].predicate) (op2, mode2)) - op2 = copy_to_mode_reg (mode2, op2); - if (! (*insn_data[icode].operand[4].predicate) (op3, mode3)) - op3 = copy_to_mode_reg (mode3, op3); +/* Fold a machine-dependent built-in in GIMPLE. (For folding into + a constant, use rs6000_fold_builtin.) */ +static bool +rs6000_gimple_fold_new_builtin (gimple_stmt_iterator *gsi) +{ + gimple *stmt = gsi_stmt (*gsi); + tree fndecl = gimple_call_fndecl (stmt); + gcc_checking_assert (fndecl && DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_MD); + enum rs6000_gen_builtins fn_code + = (enum rs6000_gen_builtins) DECL_MD_FUNCTION_CODE (fndecl); + tree arg0, arg1, lhs, temp; + enum tree_code bcode; + gimple *g; - pat = GEN_FCN (icode) (target, op0, op1, op2, op3); - if (! pat) - return 0; - emit_insn (pat); + size_t uns_fncode = (size_t) fn_code; + enum insn_code icode = rs6000_builtin_info_x[uns_fncode].icode; + const char *fn_name1 = rs6000_builtin_info_x[uns_fncode].bifname; + const char *fn_name2 = (icode != CODE_FOR_nothing) + ? get_insn_name ((int) icode) + : "nothing"; - return target; -} + if (TARGET_DEBUG_BUILTIN) + fprintf (stderr, "rs6000_gimple_fold_new_builtin %d %s %s\n", + fn_code, fn_name1, fn_name2); -static rtx -rs6000_expand_ternop_builtin (enum insn_code icode, tree exp, rtx target) -{ - rtx pat; - tree arg0 = CALL_EXPR_ARG (exp, 0); - tree arg1 = CALL_EXPR_ARG (exp, 1); - tree arg2 = CALL_EXPR_ARG (exp, 2); - rtx op0 = expand_normal (arg0); - rtx op1 = expand_normal (arg1); - rtx op2 = expand_normal (arg2); - machine_mode tmode = insn_data[icode].operand[0].mode; - machine_mode mode0 = insn_data[icode].operand[1].mode; - machine_mode mode1 = insn_data[icode].operand[2].mode; - machine_mode mode2 = insn_data[icode].operand[3].mode; + if (!rs6000_fold_gimple) + return false; - if (icode == CODE_FOR_nothing) - /* Builtin not supported on this processor. */ - return 0; + /* Prevent gimple folding for code that does not have a LHS, unless it is + allowed per the rs6000_new_builtin_valid_without_lhs helper function. */ + if (!gimple_call_lhs (stmt) + && !rs6000_new_builtin_valid_without_lhs (fn_code, fndecl)) + return false; - /* If we got invalid arguments bail out before generating bad rtl. */ - if (arg0 == error_mark_node - || arg1 == error_mark_node - || arg2 == error_mark_node) - return const0_rtx; + /* Don't fold invalid builtins, let rs6000_expand_builtin diagnose it. */ + if (!rs6000_new_builtin_is_supported (fn_code)) + return false; - /* Check and prepare argument depending on the instruction code. - - Note that a switch statement instead of the sequence of tests - would be incorrect as many of the CODE_FOR values could be - CODE_FOR_nothing and that would yield multiple alternatives - with identical values. We'd never reach here at runtime in - this case. */ - if (icode == CODE_FOR_altivec_vsldoi_v4sf - || icode == CODE_FOR_altivec_vsldoi_v2df - || icode == CODE_FOR_altivec_vsldoi_v4si - || icode == CODE_FOR_altivec_vsldoi_v8hi - || icode == CODE_FOR_altivec_vsldoi_v16qi) - { - /* Only allow 4-bit unsigned literals. */ - STRIP_NOPS (arg2); - if (TREE_CODE (arg2) != INTEGER_CST - || TREE_INT_CST_LOW (arg2) & ~0xf) - { - error ("argument 3 must be a 4-bit unsigned literal"); - return CONST0_RTX (tmode); - } - } - else if (icode == CODE_FOR_vsx_xxpermdi_v2df - || icode == CODE_FOR_vsx_xxpermdi_v2di - || icode == CODE_FOR_vsx_xxpermdi_v2df_be - || icode == CODE_FOR_vsx_xxpermdi_v2di_be - || icode == CODE_FOR_vsx_xxpermdi_v1ti - || icode == CODE_FOR_vsx_xxpermdi_v4sf - || icode == CODE_FOR_vsx_xxpermdi_v4si - || icode == CODE_FOR_vsx_xxpermdi_v8hi - || icode == CODE_FOR_vsx_xxpermdi_v16qi - || icode == CODE_FOR_vsx_xxsldwi_v16qi - || icode == CODE_FOR_vsx_xxsldwi_v8hi - || icode == CODE_FOR_vsx_xxsldwi_v4si - || icode == CODE_FOR_vsx_xxsldwi_v4sf - || icode == CODE_FOR_vsx_xxsldwi_v2di - || icode == CODE_FOR_vsx_xxsldwi_v2df) + if (rs6000_gimple_fold_new_mma_builtin (gsi, fn_code)) + return true; + + switch (fn_code) { - /* Only allow 2-bit unsigned literals. */ - STRIP_NOPS (arg2); - if (TREE_CODE (arg2) != INTEGER_CST - || TREE_INT_CST_LOW (arg2) & ~0x3) + /* Flavors of vec_add. We deliberately don't expand + RS6000_BIF_VADDUQM as it gets lowered from V1TImode to + TImode, resulting in much poorer code generation. */ + case RS6000_BIF_VADDUBM: + case RS6000_BIF_VADDUHM: + case RS6000_BIF_VADDUWM: + case RS6000_BIF_VADDUDM: + case RS6000_BIF_VADDFP: + case RS6000_BIF_XVADDDP: + case RS6000_BIF_XVADDSP: + bcode = PLUS_EXPR; + do_binary: + arg0 = gimple_call_arg (stmt, 0); + arg1 = gimple_call_arg (stmt, 1); + lhs = gimple_call_lhs (stmt); + if (INTEGRAL_TYPE_P (TREE_TYPE (TREE_TYPE (lhs))) + && !TYPE_OVERFLOW_WRAPS (TREE_TYPE (TREE_TYPE (lhs)))) { - error ("argument 3 must be a 2-bit unsigned literal"); - return CONST0_RTX (tmode); - } - } - else if (icode == CODE_FOR_vsx_set_v2df - || icode == CODE_FOR_vsx_set_v2di - || icode == CODE_FOR_bcdadd_v16qi - || icode == CODE_FOR_bcdadd_v1ti - || icode == CODE_FOR_bcdadd_lt_v16qi - || icode == CODE_FOR_bcdadd_lt_v1ti - || icode == CODE_FOR_bcdadd_eq_v16qi - || icode == CODE_FOR_bcdadd_eq_v1ti - || icode == CODE_FOR_bcdadd_gt_v16qi - || icode == CODE_FOR_bcdadd_gt_v1ti - || icode == CODE_FOR_bcdsub_v16qi - || icode == CODE_FOR_bcdsub_v1ti - || icode == CODE_FOR_bcdsub_lt_v16qi - || icode == CODE_FOR_bcdsub_lt_v1ti - || icode == CODE_FOR_bcdsub_eq_v16qi - || icode == CODE_FOR_bcdsub_eq_v1ti - || icode == CODE_FOR_bcdsub_gt_v16qi - || icode == CODE_FOR_bcdsub_gt_v1ti) - { - /* Only allow 1-bit unsigned literals. */ - STRIP_NOPS (arg2); - if (TREE_CODE (arg2) != INTEGER_CST - || TREE_INT_CST_LOW (arg2) & ~0x1) - { - error ("argument 3 must be a 1-bit unsigned literal"); - return CONST0_RTX (tmode); - } - } - else if (icode == CODE_FOR_dfp_ddedpd_dd - || icode == CODE_FOR_dfp_ddedpd_td) - { - /* Only allow 2-bit unsigned literals where the value is 0 or 2. */ - STRIP_NOPS (arg0); - if (TREE_CODE (arg0) != INTEGER_CST - || TREE_INT_CST_LOW (arg2) & ~0x3) - { - error ("argument 1 must be 0 or 2"); - return CONST0_RTX (tmode); - } - } - else if (icode == CODE_FOR_dfp_denbcd_dd - || icode == CODE_FOR_dfp_denbcd_td - || icode == CODE_FOR_dfp_denbcd_v16qi) - { - /* Only allow 1-bit unsigned literals. */ - STRIP_NOPS (arg0); - if (TREE_CODE (arg0) != INTEGER_CST - || TREE_INT_CST_LOW (arg0) & ~0x1) - { - error ("argument 1 must be a 1-bit unsigned literal"); - return CONST0_RTX (tmode); - } - } - else if (icode == CODE_FOR_dfp_dscli_dd - || icode == CODE_FOR_dfp_dscli_td - || icode == CODE_FOR_dfp_dscri_dd - || icode == CODE_FOR_dfp_dscri_td) - { - /* Only allow 6-bit unsigned literals. */ - STRIP_NOPS (arg1); - if (TREE_CODE (arg1) != INTEGER_CST - || TREE_INT_CST_LOW (arg1) & ~0x3f) - { - error ("argument 2 must be a 6-bit unsigned literal"); - return CONST0_RTX (tmode); - } - } - else if (icode == CODE_FOR_crypto_vshasigmaw - || icode == CODE_FOR_crypto_vshasigmad) - { - /* Check whether the 2nd and 3rd arguments are integer constants and in - range and prepare arguments. */ - STRIP_NOPS (arg1); - if (TREE_CODE (arg1) != INTEGER_CST || wi::geu_p (wi::to_wide (arg1), 2)) - { - error ("argument 2 must be 0 or 1"); - return CONST0_RTX (tmode); - } - - STRIP_NOPS (arg2); - if (TREE_CODE (arg2) != INTEGER_CST - || wi::geu_p (wi::to_wide (arg2), 16)) - { - error ("argument 3 must be in the range [0, 15]"); - return CONST0_RTX (tmode); - } - } - - if (target == 0 - || GET_MODE (target) != tmode - || ! (*insn_data[icode].operand[0].predicate) (target, tmode)) - target = gen_reg_rtx (tmode); - - if (! (*insn_data[icode].operand[1].predicate) (op0, mode0)) - op0 = copy_to_mode_reg (mode0, op0); - if (! (*insn_data[icode].operand[2].predicate) (op1, mode1)) - op1 = copy_to_mode_reg (mode1, op1); - if (! (*insn_data[icode].operand[3].predicate) (op2, mode2)) - op2 = copy_to_mode_reg (mode2, op2); - - pat = GEN_FCN (icode) (target, op0, op1, op2); - if (! pat) - return 0; - emit_insn (pat); - - return target; -} - - -/* Expand the dst builtins. */ -static rtx -altivec_expand_dst_builtin (tree exp, rtx target ATTRIBUTE_UNUSED, - bool *expandedp) -{ - tree fndecl = TREE_OPERAND (CALL_EXPR_FN (exp), 0); - enum rs6000_builtins fcode - = (enum rs6000_builtins) DECL_MD_FUNCTION_CODE (fndecl); - tree arg0, arg1, arg2; - machine_mode mode0, mode1; - rtx pat, op0, op1, op2; - const struct builtin_description *d; - size_t i; - - *expandedp = false; - - /* Handle DST variants. */ - d = bdesc_dst; - for (i = 0; i < ARRAY_SIZE (bdesc_dst); i++, d++) - if (d->code == fcode) - { - arg0 = CALL_EXPR_ARG (exp, 0); - arg1 = CALL_EXPR_ARG (exp, 1); - arg2 = CALL_EXPR_ARG (exp, 2); - op0 = expand_normal (arg0); - op1 = expand_normal (arg1); - op2 = expand_normal (arg2); - mode0 = insn_data[d->icode].operand[0].mode; - mode1 = insn_data[d->icode].operand[1].mode; - - /* Invalid arguments, bail out before generating bad rtl. */ - if (arg0 == error_mark_node - || arg1 == error_mark_node - || arg2 == error_mark_node) - return const0_rtx; - - *expandedp = true; - STRIP_NOPS (arg2); - if (TREE_CODE (arg2) != INTEGER_CST - || TREE_INT_CST_LOW (arg2) & ~0x3) - { - error ("argument to %qs must be a 2-bit unsigned literal", d->name); - return const0_rtx; - } - - if (! (*insn_data[d->icode].operand[0].predicate) (op0, mode0)) - op0 = copy_to_mode_reg (Pmode, op0); - if (! (*insn_data[d->icode].operand[1].predicate) (op1, mode1)) - op1 = copy_to_mode_reg (mode1, op1); - - pat = GEN_FCN (d->icode) (op0, op1, op2); - if (pat != 0) - emit_insn (pat); - - return NULL_RTX; - } - - return NULL_RTX; -} - -/* Expand vec_init builtin. */ -static rtx -altivec_expand_vec_init_builtin (tree type, tree exp, rtx target) -{ - machine_mode tmode = TYPE_MODE (type); - machine_mode inner_mode = GET_MODE_INNER (tmode); - int i, n_elt = GET_MODE_NUNITS (tmode); - - gcc_assert (VECTOR_MODE_P (tmode)); - gcc_assert (n_elt == call_expr_nargs (exp)); - - if (!target || !register_operand (target, tmode)) - target = gen_reg_rtx (tmode); - - /* If we have a vector compromised of a single element, such as V1TImode, do - the initialization directly. */ - if (n_elt == 1 && GET_MODE_SIZE (tmode) == GET_MODE_SIZE (inner_mode)) - { - rtx x = expand_normal (CALL_EXPR_ARG (exp, 0)); - emit_move_insn (target, gen_lowpart (tmode, x)); - } - else - { - rtvec v = rtvec_alloc (n_elt); - - for (i = 0; i < n_elt; ++i) - { - rtx x = expand_normal (CALL_EXPR_ARG (exp, i)); - RTVEC_ELT (v, i) = gen_lowpart (inner_mode, x); + /* Ensure the binary operation is performed in a type + that wraps if it is integral type. */ + gimple_seq stmts = NULL; + tree type = unsigned_type_for (TREE_TYPE (lhs)); + tree uarg0 = gimple_build (&stmts, VIEW_CONVERT_EXPR, + type, arg0); + tree uarg1 = gimple_build (&stmts, VIEW_CONVERT_EXPR, + type, arg1); + tree res = gimple_build (&stmts, gimple_location (stmt), bcode, + type, uarg0, uarg1); + gsi_insert_seq_before (gsi, stmts, GSI_SAME_STMT); + g = gimple_build_assign (lhs, VIEW_CONVERT_EXPR, + build1 (VIEW_CONVERT_EXPR, + TREE_TYPE (lhs), res)); + gsi_replace (gsi, g, true); + return true; } - - rs6000_expand_vector_init (target, gen_rtx_PARALLEL (tmode, v)); - } - - return target; -} - -/* Return the integer constant in ARG. Constrain it to be in the range - of the subparts of VEC_TYPE; issue an error if not. */ - -static int -get_element_number (tree vec_type, tree arg) -{ - unsigned HOST_WIDE_INT elt, max = TYPE_VECTOR_SUBPARTS (vec_type) - 1; - - if (!tree_fits_uhwi_p (arg) - || (elt = tree_to_uhwi (arg), elt > max)) - { - error ("selector must be an integer constant in the range [0, %wi]", max); - return 0; - } - - return elt; -} - -/* Expand vec_set builtin. */ -static rtx -altivec_expand_vec_set_builtin (tree exp) -{ - machine_mode tmode, mode1; - tree arg0, arg1, arg2; - int elt; - rtx op0, op1; - - arg0 = CALL_EXPR_ARG (exp, 0); - arg1 = CALL_EXPR_ARG (exp, 1); - arg2 = CALL_EXPR_ARG (exp, 2); - - tmode = TYPE_MODE (TREE_TYPE (arg0)); - mode1 = TYPE_MODE (TREE_TYPE (TREE_TYPE (arg0))); - gcc_assert (VECTOR_MODE_P (tmode)); - - op0 = expand_expr (arg0, NULL_RTX, tmode, EXPAND_NORMAL); - op1 = expand_expr (arg1, NULL_RTX, mode1, EXPAND_NORMAL); - elt = get_element_number (TREE_TYPE (arg0), arg2); - - if (GET_MODE (op1) != mode1 && GET_MODE (op1) != VOIDmode) - op1 = convert_modes (mode1, GET_MODE (op1), op1, true); - - op0 = force_reg (tmode, op0); - op1 = force_reg (mode1, op1); - - rs6000_expand_vector_set (op0, op1, GEN_INT (elt)); - - return op0; -} - -/* Expand vec_ext builtin. */ -static rtx -altivec_expand_vec_ext_builtin (tree exp, rtx target) -{ - machine_mode tmode, mode0; - tree arg0, arg1; - rtx op0; - rtx op1; - - arg0 = CALL_EXPR_ARG (exp, 0); - arg1 = CALL_EXPR_ARG (exp, 1); - - op0 = expand_normal (arg0); - op1 = expand_normal (arg1); - - if (TREE_CODE (arg1) == INTEGER_CST) - { - unsigned HOST_WIDE_INT elt; - unsigned HOST_WIDE_INT size = TYPE_VECTOR_SUBPARTS (TREE_TYPE (arg0)); - unsigned int truncated_selector; - /* Even if !tree_fits_uhwi_p (arg1)), TREE_INT_CST_LOW (arg0) - returns low-order bits of INTEGER_CST for modulo indexing. */ - elt = TREE_INT_CST_LOW (arg1); - truncated_selector = elt % size; - op1 = GEN_INT (truncated_selector); - } - - tmode = TYPE_MODE (TREE_TYPE (TREE_TYPE (arg0))); - mode0 = TYPE_MODE (TREE_TYPE (arg0)); - gcc_assert (VECTOR_MODE_P (mode0)); - - op0 = force_reg (mode0, op0); - - if (optimize || !target || !register_operand (target, tmode)) - target = gen_reg_rtx (tmode); - - rs6000_expand_vector_extract (target, op0, op1); - - return target; -} - -/* Expand vec_sel builtin. */ -static rtx -altivec_expand_vec_sel_builtin (enum insn_code icode, tree exp, rtx target) -{ - rtx op0, op1, op2, pat; - tree arg0, arg1, arg2; - - arg0 = CALL_EXPR_ARG (exp, 0); - op0 = expand_normal (arg0); - arg1 = CALL_EXPR_ARG (exp, 1); - op1 = expand_normal (arg1); - arg2 = CALL_EXPR_ARG (exp, 2); - op2 = expand_normal (arg2); - - machine_mode tmode = insn_data[icode].operand[0].mode; - machine_mode mode0 = insn_data[icode].operand[1].mode; - machine_mode mode1 = insn_data[icode].operand[2].mode; - machine_mode mode2 = insn_data[icode].operand[3].mode; - - if (target == 0 || GET_MODE (target) != tmode - || !(*insn_data[icode].operand[0].predicate) (target, tmode)) - target = gen_reg_rtx (tmode); - - if (!(*insn_data[icode].operand[1].predicate) (op0, mode0)) - op0 = copy_to_mode_reg (mode0, op0); - if (!(*insn_data[icode].operand[2].predicate) (op1, mode1)) - op1 = copy_to_mode_reg (mode1, op1); - if (!(*insn_data[icode].operand[3].predicate) (op2, mode2)) - op2 = copy_to_mode_reg (mode2, op2); - - pat = GEN_FCN (icode) (target, op0, op1, op2, op2); - if (pat) - emit_insn (pat); - else - return NULL_RTX; - - return target; -} - -/* Expand the builtin in EXP and store the result in TARGET. Store - true in *EXPANDEDP if we found a builtin to expand. */ -static rtx -altivec_expand_builtin (tree exp, rtx target, bool *expandedp) -{ - const struct builtin_description *d; - size_t i; - enum insn_code icode; - tree fndecl = TREE_OPERAND (CALL_EXPR_FN (exp), 0); - tree arg0, arg1, arg2; - rtx op0, pat; - machine_mode tmode, mode0; - enum rs6000_builtins fcode - = (enum rs6000_builtins) DECL_MD_FUNCTION_CODE (fndecl); - - if (rs6000_overloaded_builtin_p (fcode)) - { - *expandedp = true; - error ("unresolved overload for Altivec builtin %qF", fndecl); - - /* Given it is invalid, just generate a normal call. */ - return expand_call (exp, target, false); - } - - target = altivec_expand_dst_builtin (exp, target, expandedp); - if (*expandedp) - return target; - - *expandedp = true; - - switch (fcode) - { - case ALTIVEC_BUILTIN_STVX_V2DF: - return altivec_expand_stv_builtin (CODE_FOR_altivec_stvx_v2df, exp); - case ALTIVEC_BUILTIN_STVX_V2DI: - return altivec_expand_stv_builtin (CODE_FOR_altivec_stvx_v2di, exp); - case ALTIVEC_BUILTIN_STVX_V4SF: - return altivec_expand_stv_builtin (CODE_FOR_altivec_stvx_v4sf, exp); - case ALTIVEC_BUILTIN_STVX: - case ALTIVEC_BUILTIN_STVX_V4SI: - return altivec_expand_stv_builtin (CODE_FOR_altivec_stvx_v4si, exp); - case ALTIVEC_BUILTIN_STVX_V8HI: - return altivec_expand_stv_builtin (CODE_FOR_altivec_stvx_v8hi, exp); - case ALTIVEC_BUILTIN_STVX_V16QI: - return altivec_expand_stv_builtin (CODE_FOR_altivec_stvx_v16qi, exp); - case ALTIVEC_BUILTIN_STVEBX: - return altivec_expand_stv_builtin (CODE_FOR_altivec_stvebx, exp); - case ALTIVEC_BUILTIN_STVEHX: - return altivec_expand_stv_builtin (CODE_FOR_altivec_stvehx, exp); - case ALTIVEC_BUILTIN_STVEWX: - return altivec_expand_stv_builtin (CODE_FOR_altivec_stvewx, exp); - - case P10_BUILTIN_TR_STXVRBX: - return altivec_expand_stv_builtin (CODE_FOR_vsx_stxvrbx, exp); - case P10_BUILTIN_TR_STXVRHX: - return altivec_expand_stv_builtin (CODE_FOR_vsx_stxvrhx, exp); - case P10_BUILTIN_TR_STXVRWX: - return altivec_expand_stv_builtin (CODE_FOR_vsx_stxvrwx, exp); - case P10_BUILTIN_TR_STXVRDX: - return altivec_expand_stv_builtin (CODE_FOR_vsx_stxvrdx, exp); - - case ALTIVEC_BUILTIN_STVXL_V2DF: - return altivec_expand_stv_builtin (CODE_FOR_altivec_stvxl_v2df, exp); - case ALTIVEC_BUILTIN_STVXL_V2DI: - return altivec_expand_stv_builtin (CODE_FOR_altivec_stvxl_v2di, exp); - case ALTIVEC_BUILTIN_STVXL_V4SF: - return altivec_expand_stv_builtin (CODE_FOR_altivec_stvxl_v4sf, exp); - case ALTIVEC_BUILTIN_STVXL: - case ALTIVEC_BUILTIN_STVXL_V4SI: - return altivec_expand_stv_builtin (CODE_FOR_altivec_stvxl_v4si, exp); - case ALTIVEC_BUILTIN_STVXL_V8HI: - return altivec_expand_stv_builtin (CODE_FOR_altivec_stvxl_v8hi, exp); - case ALTIVEC_BUILTIN_STVXL_V16QI: - return altivec_expand_stv_builtin (CODE_FOR_altivec_stvxl_v16qi, exp); - - case ALTIVEC_BUILTIN_STVLX: - return altivec_expand_stv_builtin (CODE_FOR_altivec_stvlx, exp); - case ALTIVEC_BUILTIN_STVLXL: - return altivec_expand_stv_builtin (CODE_FOR_altivec_stvlxl, exp); - case ALTIVEC_BUILTIN_STVRX: - return altivec_expand_stv_builtin (CODE_FOR_altivec_stvrx, exp); - case ALTIVEC_BUILTIN_STVRXL: - return altivec_expand_stv_builtin (CODE_FOR_altivec_stvrxl, exp); - - case P9V_BUILTIN_STXVL: - return altivec_expand_stxvl_builtin (CODE_FOR_stxvl, exp); - - case P9V_BUILTIN_XST_LEN_R: - return altivec_expand_stxvl_builtin (CODE_FOR_xst_len_r, exp); - - case VSX_BUILTIN_STXVD2X_V1TI: - return altivec_expand_stv_builtin (CODE_FOR_vsx_store_v1ti, exp); - case VSX_BUILTIN_STXVD2X_V2DF: - return altivec_expand_stv_builtin (CODE_FOR_vsx_store_v2df, exp); - case VSX_BUILTIN_STXVD2X_V2DI: - return altivec_expand_stv_builtin (CODE_FOR_vsx_store_v2di, exp); - case VSX_BUILTIN_STXVW4X_V4SF: - return altivec_expand_stv_builtin (CODE_FOR_vsx_store_v4sf, exp); - case VSX_BUILTIN_STXVW4X_V4SI: - return altivec_expand_stv_builtin (CODE_FOR_vsx_store_v4si, exp); - case VSX_BUILTIN_STXVW4X_V8HI: - return altivec_expand_stv_builtin (CODE_FOR_vsx_store_v8hi, exp); - case VSX_BUILTIN_STXVW4X_V16QI: - return altivec_expand_stv_builtin (CODE_FOR_vsx_store_v16qi, exp); - - /* For the following on big endian, it's ok to use any appropriate - unaligned-supporting store, so use a generic expander. For - little-endian, the exact element-reversing instruction must - be used. */ - case VSX_BUILTIN_ST_ELEMREV_V1TI: - { - enum insn_code code = (BYTES_BIG_ENDIAN ? CODE_FOR_vsx_store_v1ti - : CODE_FOR_vsx_st_elemrev_v1ti); - return altivec_expand_stv_builtin (code, exp); - } - case VSX_BUILTIN_ST_ELEMREV_V2DF: - { - enum insn_code code = (BYTES_BIG_ENDIAN ? CODE_FOR_vsx_store_v2df - : CODE_FOR_vsx_st_elemrev_v2df); - return altivec_expand_stv_builtin (code, exp); - } - case VSX_BUILTIN_ST_ELEMREV_V2DI: - { - enum insn_code code = (BYTES_BIG_ENDIAN ? CODE_FOR_vsx_store_v2di - : CODE_FOR_vsx_st_elemrev_v2di); - return altivec_expand_stv_builtin (code, exp); - } - case VSX_BUILTIN_ST_ELEMREV_V4SF: - { - enum insn_code code = (BYTES_BIG_ENDIAN ? CODE_FOR_vsx_store_v4sf - : CODE_FOR_vsx_st_elemrev_v4sf); - return altivec_expand_stv_builtin (code, exp); - } - case VSX_BUILTIN_ST_ELEMREV_V4SI: - { - enum insn_code code = (BYTES_BIG_ENDIAN ? CODE_FOR_vsx_store_v4si - : CODE_FOR_vsx_st_elemrev_v4si); - return altivec_expand_stv_builtin (code, exp); - } - case VSX_BUILTIN_ST_ELEMREV_V8HI: - { - enum insn_code code = (BYTES_BIG_ENDIAN ? CODE_FOR_vsx_store_v8hi - : CODE_FOR_vsx_st_elemrev_v8hi); - return altivec_expand_stv_builtin (code, exp); - } - case VSX_BUILTIN_ST_ELEMREV_V16QI: + g = gimple_build_assign (lhs, bcode, arg0, arg1); + gimple_set_location (g, gimple_location (stmt)); + gsi_replace (gsi, g, true); + return true; + /* Flavors of vec_sub. We deliberately don't expand + RS6000_BIF_VSUBUQM. */ + case RS6000_BIF_VSUBUBM: + case RS6000_BIF_VSUBUHM: + case RS6000_BIF_VSUBUWM: + case RS6000_BIF_VSUBUDM: + case RS6000_BIF_VSUBFP: + case RS6000_BIF_XVSUBDP: + case RS6000_BIF_XVSUBSP: + bcode = MINUS_EXPR; + goto do_binary; + case RS6000_BIF_XVMULSP: + case RS6000_BIF_XVMULDP: + arg0 = gimple_call_arg (stmt, 0); + arg1 = gimple_call_arg (stmt, 1); + lhs = gimple_call_lhs (stmt); + g = gimple_build_assign (lhs, MULT_EXPR, arg0, arg1); + gimple_set_location (g, gimple_location (stmt)); + gsi_replace (gsi, g, true); + return true; + /* Even element flavors of vec_mul (signed). */ + case RS6000_BIF_VMULESB: + case RS6000_BIF_VMULESH: + case RS6000_BIF_VMULESW: + /* Even element flavors of vec_mul (unsigned). */ + case RS6000_BIF_VMULEUB: + case RS6000_BIF_VMULEUH: + case RS6000_BIF_VMULEUW: + arg0 = gimple_call_arg (stmt, 0); + arg1 = gimple_call_arg (stmt, 1); + lhs = gimple_call_lhs (stmt); + g = gimple_build_assign (lhs, VEC_WIDEN_MULT_EVEN_EXPR, arg0, arg1); + gimple_set_location (g, gimple_location (stmt)); + gsi_replace (gsi, g, true); + return true; + /* Odd element flavors of vec_mul (signed). */ + case RS6000_BIF_VMULOSB: + case RS6000_BIF_VMULOSH: + case RS6000_BIF_VMULOSW: + /* Odd element flavors of vec_mul (unsigned). */ + case RS6000_BIF_VMULOUB: + case RS6000_BIF_VMULOUH: + case RS6000_BIF_VMULOUW: + arg0 = gimple_call_arg (stmt, 0); + arg1 = gimple_call_arg (stmt, 1); + lhs = gimple_call_lhs (stmt); + g = gimple_build_assign (lhs, VEC_WIDEN_MULT_ODD_EXPR, arg0, arg1); + gimple_set_location (g, gimple_location (stmt)); + gsi_replace (gsi, g, true); + return true; + /* Flavors of vec_div (Integer). */ + case RS6000_BIF_DIV_V2DI: + case RS6000_BIF_UDIV_V2DI: + arg0 = gimple_call_arg (stmt, 0); + arg1 = gimple_call_arg (stmt, 1); + lhs = gimple_call_lhs (stmt); + g = gimple_build_assign (lhs, TRUNC_DIV_EXPR, arg0, arg1); + gimple_set_location (g, gimple_location (stmt)); + gsi_replace (gsi, g, true); + return true; + /* Flavors of vec_div (Float). */ + case RS6000_BIF_XVDIVSP: + case RS6000_BIF_XVDIVDP: + arg0 = gimple_call_arg (stmt, 0); + arg1 = gimple_call_arg (stmt, 1); + lhs = gimple_call_lhs (stmt); + g = gimple_build_assign (lhs, RDIV_EXPR, arg0, arg1); + gimple_set_location (g, gimple_location (stmt)); + gsi_replace (gsi, g, true); + return true; + /* Flavors of vec_and. */ + case RS6000_BIF_VAND_V16QI_UNS: + case RS6000_BIF_VAND_V16QI: + case RS6000_BIF_VAND_V8HI_UNS: + case RS6000_BIF_VAND_V8HI: + case RS6000_BIF_VAND_V4SI_UNS: + case RS6000_BIF_VAND_V4SI: + case RS6000_BIF_VAND_V2DI_UNS: + case RS6000_BIF_VAND_V2DI: + case RS6000_BIF_VAND_V4SF: + case RS6000_BIF_VAND_V2DF: + arg0 = gimple_call_arg (stmt, 0); + arg1 = gimple_call_arg (stmt, 1); + lhs = gimple_call_lhs (stmt); + g = gimple_build_assign (lhs, BIT_AND_EXPR, arg0, arg1); + gimple_set_location (g, gimple_location (stmt)); + gsi_replace (gsi, g, true); + return true; + /* Flavors of vec_andc. */ + case RS6000_BIF_VANDC_V16QI_UNS: + case RS6000_BIF_VANDC_V16QI: + case RS6000_BIF_VANDC_V8HI_UNS: + case RS6000_BIF_VANDC_V8HI: + case RS6000_BIF_VANDC_V4SI_UNS: + case RS6000_BIF_VANDC_V4SI: + case RS6000_BIF_VANDC_V2DI_UNS: + case RS6000_BIF_VANDC_V2DI: + case RS6000_BIF_VANDC_V4SF: + case RS6000_BIF_VANDC_V2DF: + arg0 = gimple_call_arg (stmt, 0); + arg1 = gimple_call_arg (stmt, 1); + lhs = gimple_call_lhs (stmt); + temp = create_tmp_reg_or_ssa_name (TREE_TYPE (arg1)); + g = gimple_build_assign (temp, BIT_NOT_EXPR, arg1); + gimple_set_location (g, gimple_location (stmt)); + gsi_insert_before (gsi, g, GSI_SAME_STMT); + g = gimple_build_assign (lhs, BIT_AND_EXPR, arg0, temp); + gimple_set_location (g, gimple_location (stmt)); + gsi_replace (gsi, g, true); + return true; + /* Flavors of vec_nand. */ + case RS6000_BIF_NAND_V16QI_UNS: + case RS6000_BIF_NAND_V16QI: + case RS6000_BIF_NAND_V8HI_UNS: + case RS6000_BIF_NAND_V8HI: + case RS6000_BIF_NAND_V4SI_UNS: + case RS6000_BIF_NAND_V4SI: + case RS6000_BIF_NAND_V2DI_UNS: + case RS6000_BIF_NAND_V2DI: + case RS6000_BIF_NAND_V4SF: + case RS6000_BIF_NAND_V2DF: + arg0 = gimple_call_arg (stmt, 0); + arg1 = gimple_call_arg (stmt, 1); + lhs = gimple_call_lhs (stmt); + temp = create_tmp_reg_or_ssa_name (TREE_TYPE (arg1)); + g = gimple_build_assign (temp, BIT_AND_EXPR, arg0, arg1); + gimple_set_location (g, gimple_location (stmt)); + gsi_insert_before (gsi, g, GSI_SAME_STMT); + g = gimple_build_assign (lhs, BIT_NOT_EXPR, temp); + gimple_set_location (g, gimple_location (stmt)); + gsi_replace (gsi, g, true); + return true; + /* Flavors of vec_or. */ + case RS6000_BIF_VOR_V16QI_UNS: + case RS6000_BIF_VOR_V16QI: + case RS6000_BIF_VOR_V8HI_UNS: + case RS6000_BIF_VOR_V8HI: + case RS6000_BIF_VOR_V4SI_UNS: + case RS6000_BIF_VOR_V4SI: + case RS6000_BIF_VOR_V2DI_UNS: + case RS6000_BIF_VOR_V2DI: + case RS6000_BIF_VOR_V4SF: + case RS6000_BIF_VOR_V2DF: + arg0 = gimple_call_arg (stmt, 0); + arg1 = gimple_call_arg (stmt, 1); + lhs = gimple_call_lhs (stmt); + g = gimple_build_assign (lhs, BIT_IOR_EXPR, arg0, arg1); + gimple_set_location (g, gimple_location (stmt)); + gsi_replace (gsi, g, true); + return true; + /* flavors of vec_orc. */ + case RS6000_BIF_ORC_V16QI_UNS: + case RS6000_BIF_ORC_V16QI: + case RS6000_BIF_ORC_V8HI_UNS: + case RS6000_BIF_ORC_V8HI: + case RS6000_BIF_ORC_V4SI_UNS: + case RS6000_BIF_ORC_V4SI: + case RS6000_BIF_ORC_V2DI_UNS: + case RS6000_BIF_ORC_V2DI: + case RS6000_BIF_ORC_V4SF: + case RS6000_BIF_ORC_V2DF: + arg0 = gimple_call_arg (stmt, 0); + arg1 = gimple_call_arg (stmt, 1); + lhs = gimple_call_lhs (stmt); + temp = create_tmp_reg_or_ssa_name (TREE_TYPE (arg1)); + g = gimple_build_assign (temp, BIT_NOT_EXPR, arg1); + gimple_set_location (g, gimple_location (stmt)); + gsi_insert_before (gsi, g, GSI_SAME_STMT); + g = gimple_build_assign (lhs, BIT_IOR_EXPR, arg0, temp); + gimple_set_location (g, gimple_location (stmt)); + gsi_replace (gsi, g, true); + return true; + /* Flavors of vec_xor. */ + case RS6000_BIF_VXOR_V16QI_UNS: + case RS6000_BIF_VXOR_V16QI: + case RS6000_BIF_VXOR_V8HI_UNS: + case RS6000_BIF_VXOR_V8HI: + case RS6000_BIF_VXOR_V4SI_UNS: + case RS6000_BIF_VXOR_V4SI: + case RS6000_BIF_VXOR_V2DI_UNS: + case RS6000_BIF_VXOR_V2DI: + case RS6000_BIF_VXOR_V4SF: + case RS6000_BIF_VXOR_V2DF: + arg0 = gimple_call_arg (stmt, 0); + arg1 = gimple_call_arg (stmt, 1); + lhs = gimple_call_lhs (stmt); + g = gimple_build_assign (lhs, BIT_XOR_EXPR, arg0, arg1); + gimple_set_location (g, gimple_location (stmt)); + gsi_replace (gsi, g, true); + return true; + /* Flavors of vec_nor. */ + case RS6000_BIF_VNOR_V16QI_UNS: + case RS6000_BIF_VNOR_V16QI: + case RS6000_BIF_VNOR_V8HI_UNS: + case RS6000_BIF_VNOR_V8HI: + case RS6000_BIF_VNOR_V4SI_UNS: + case RS6000_BIF_VNOR_V4SI: + case RS6000_BIF_VNOR_V2DI_UNS: + case RS6000_BIF_VNOR_V2DI: + case RS6000_BIF_VNOR_V4SF: + case RS6000_BIF_VNOR_V2DF: + arg0 = gimple_call_arg (stmt, 0); + arg1 = gimple_call_arg (stmt, 1); + lhs = gimple_call_lhs (stmt); + temp = create_tmp_reg_or_ssa_name (TREE_TYPE (arg1)); + g = gimple_build_assign (temp, BIT_IOR_EXPR, arg0, arg1); + gimple_set_location (g, gimple_location (stmt)); + gsi_insert_before (gsi, g, GSI_SAME_STMT); + g = gimple_build_assign (lhs, BIT_NOT_EXPR, temp); + gimple_set_location (g, gimple_location (stmt)); + gsi_replace (gsi, g, true); + return true; + /* flavors of vec_abs. */ + case RS6000_BIF_ABS_V16QI: + case RS6000_BIF_ABS_V8HI: + case RS6000_BIF_ABS_V4SI: + case RS6000_BIF_ABS_V4SF: + case RS6000_BIF_ABS_V2DI: + case RS6000_BIF_XVABSDP: + case RS6000_BIF_XVABSSP: + arg0 = gimple_call_arg (stmt, 0); + if (INTEGRAL_TYPE_P (TREE_TYPE (TREE_TYPE (arg0))) + && !TYPE_OVERFLOW_WRAPS (TREE_TYPE (TREE_TYPE (arg0)))) + return false; + lhs = gimple_call_lhs (stmt); + g = gimple_build_assign (lhs, ABS_EXPR, arg0); + gimple_set_location (g, gimple_location (stmt)); + gsi_replace (gsi, g, true); + return true; + /* flavors of vec_min. */ + case RS6000_BIF_XVMINDP: + case RS6000_BIF_XVMINSP: + case RS6000_BIF_VMINFP: { - enum insn_code code = (BYTES_BIG_ENDIAN ? CODE_FOR_vsx_store_v16qi - : CODE_FOR_vsx_st_elemrev_v16qi); - return altivec_expand_stv_builtin (code, exp); + lhs = gimple_call_lhs (stmt); + tree type = TREE_TYPE (lhs); + if (HONOR_NANS (type)) + return false; + gcc_fallthrough (); } - - case ALTIVEC_BUILTIN_MFVSCR: - icode = CODE_FOR_altivec_mfvscr; - tmode = insn_data[icode].operand[0].mode; - - if (target == 0 - || GET_MODE (target) != tmode - || ! (*insn_data[icode].operand[0].predicate) (target, tmode)) - target = gen_reg_rtx (tmode); - - pat = GEN_FCN (icode) (target); - if (! pat) - return 0; - emit_insn (pat); - return target; - - case ALTIVEC_BUILTIN_MTVSCR: - icode = CODE_FOR_altivec_mtvscr; - arg0 = CALL_EXPR_ARG (exp, 0); - op0 = expand_normal (arg0); - mode0 = insn_data[icode].operand[0].mode; - - /* If we got invalid arguments bail out before generating bad rtl. */ - if (arg0 == error_mark_node) - return const0_rtx; - - if (! (*insn_data[icode].operand[0].predicate) (op0, mode0)) - op0 = copy_to_mode_reg (mode0, op0); - - pat = GEN_FCN (icode) (op0); - if (pat) - emit_insn (pat); - return NULL_RTX; - - case ALTIVEC_BUILTIN_VSEL_2DF: - return altivec_expand_vec_sel_builtin (CODE_FOR_altivec_vselv2df, exp, - target); - case ALTIVEC_BUILTIN_VSEL_2DI: - case ALTIVEC_BUILTIN_VSEL_2DI_UNS: - return altivec_expand_vec_sel_builtin (CODE_FOR_altivec_vselv2di, exp, - target); - case ALTIVEC_BUILTIN_VSEL_4SF: - return altivec_expand_vec_sel_builtin (CODE_FOR_altivec_vselv4sf, exp, - target); - case ALTIVEC_BUILTIN_VSEL_4SI: - case ALTIVEC_BUILTIN_VSEL_4SI_UNS: - return altivec_expand_vec_sel_builtin (CODE_FOR_altivec_vselv4si, exp, - target); - case ALTIVEC_BUILTIN_VSEL_8HI: - case ALTIVEC_BUILTIN_VSEL_8HI_UNS: - return altivec_expand_vec_sel_builtin (CODE_FOR_altivec_vselv8hi, exp, - target); - case ALTIVEC_BUILTIN_VSEL_16QI: - case ALTIVEC_BUILTIN_VSEL_16QI_UNS: - return altivec_expand_vec_sel_builtin (CODE_FOR_altivec_vselv16qi, exp, - target); - - case ALTIVEC_BUILTIN_DSSALL: - emit_insn (gen_altivec_dssall ()); - return NULL_RTX; - - case ALTIVEC_BUILTIN_DSS: - icode = CODE_FOR_altivec_dss; - arg0 = CALL_EXPR_ARG (exp, 0); - STRIP_NOPS (arg0); - op0 = expand_normal (arg0); - mode0 = insn_data[icode].operand[0].mode; - - /* If we got invalid arguments bail out before generating bad rtl. */ - if (arg0 == error_mark_node) - return const0_rtx; - - if (TREE_CODE (arg0) != INTEGER_CST - || TREE_INT_CST_LOW (arg0) & ~0x3) - { - error ("argument to %qs must be a 2-bit unsigned literal", "dss"); - return const0_rtx; - } - - if (! (*insn_data[icode].operand[0].predicate) (op0, mode0)) - op0 = copy_to_mode_reg (mode0, op0); - - emit_insn (gen_altivec_dss (op0)); - return NULL_RTX; - - case ALTIVEC_BUILTIN_VEC_INIT_V4SI: - case ALTIVEC_BUILTIN_VEC_INIT_V8HI: - case ALTIVEC_BUILTIN_VEC_INIT_V16QI: - case ALTIVEC_BUILTIN_VEC_INIT_V4SF: - case VSX_BUILTIN_VEC_INIT_V2DF: - case VSX_BUILTIN_VEC_INIT_V2DI: - case VSX_BUILTIN_VEC_INIT_V1TI: - return altivec_expand_vec_init_builtin (TREE_TYPE (exp), exp, target); - - case ALTIVEC_BUILTIN_VEC_SET_V4SI: - case ALTIVEC_BUILTIN_VEC_SET_V8HI: - case ALTIVEC_BUILTIN_VEC_SET_V16QI: - case ALTIVEC_BUILTIN_VEC_SET_V4SF: - case VSX_BUILTIN_VEC_SET_V2DF: - case VSX_BUILTIN_VEC_SET_V2DI: - case VSX_BUILTIN_VEC_SET_V1TI: - return altivec_expand_vec_set_builtin (exp); - - case ALTIVEC_BUILTIN_VEC_EXT_V4SI: - case ALTIVEC_BUILTIN_VEC_EXT_V8HI: - case ALTIVEC_BUILTIN_VEC_EXT_V16QI: - case ALTIVEC_BUILTIN_VEC_EXT_V4SF: - case VSX_BUILTIN_VEC_EXT_V2DF: - case VSX_BUILTIN_VEC_EXT_V2DI: - case VSX_BUILTIN_VEC_EXT_V1TI: - return altivec_expand_vec_ext_builtin (exp, target); - - case P9V_BUILTIN_VEC_EXTRACT4B: - arg1 = CALL_EXPR_ARG (exp, 1); - STRIP_NOPS (arg1); - - /* Generate a normal call if it is invalid. */ - if (arg1 == error_mark_node) - return expand_call (exp, target, false); - - if (TREE_CODE (arg1) != INTEGER_CST || TREE_INT_CST_LOW (arg1) > 12) - { - error ("second argument to %qs must be [0, 12]", "vec_vextract4b"); - return expand_call (exp, target, false); - } - break; - - case P9V_BUILTIN_VEC_INSERT4B: - arg2 = CALL_EXPR_ARG (exp, 2); - STRIP_NOPS (arg2); - - /* Generate a normal call if it is invalid. */ - if (arg2 == error_mark_node) - return expand_call (exp, target, false); - - if (TREE_CODE (arg2) != INTEGER_CST || TREE_INT_CST_LOW (arg2) > 12) - { - error ("third argument to %qs must be [0, 12]", "vec_vinsert4b"); - return expand_call (exp, target, false); - } - break; - - case P10_BUILTIN_VEC_XXGENPCVM: - arg1 = CALL_EXPR_ARG (exp, 1); - STRIP_NOPS (arg1); - - /* Generate a normal call if it is invalid. */ - if (arg1 == error_mark_node) - return expand_call (exp, target, false); - - if (TREE_CODE (arg1) != INTEGER_CST - || !IN_RANGE (TREE_INT_CST_LOW (arg1), 0, 3)) - { - size_t uns_fcode = (size_t) fcode; - const char *name = rs6000_builtin_info[uns_fcode].name; - error ("Second argument of %qs must be in the range [0, 3].", name); - return expand_call (exp, target, false); - } - break; - - default: - break; - /* Fall through. */ - } - - /* Expand abs* operations. */ - d = bdesc_abs; - for (i = 0; i < ARRAY_SIZE (bdesc_abs); i++, d++) - if (d->code == fcode) - return altivec_expand_abs_builtin (d->icode, exp, target); - - /* Expand the AltiVec predicates. */ - d = bdesc_altivec_preds; - for (i = 0; i < ARRAY_SIZE (bdesc_altivec_preds); i++, d++) - if (d->code == fcode) - return altivec_expand_predicate_builtin (d->icode, exp, target); - - /* LV* are funky. We initialized them differently. */ - switch (fcode) - { - case ALTIVEC_BUILTIN_LVSL: - return altivec_expand_lv_builtin (CODE_FOR_altivec_lvsl, - exp, target, false); - case ALTIVEC_BUILTIN_LVSR: - return altivec_expand_lv_builtin (CODE_FOR_altivec_lvsr, - exp, target, false); - case ALTIVEC_BUILTIN_LVEBX: - return altivec_expand_lv_builtin (CODE_FOR_altivec_lvebx, - exp, target, false); - case ALTIVEC_BUILTIN_LVEHX: - return altivec_expand_lv_builtin (CODE_FOR_altivec_lvehx, - exp, target, false); - case ALTIVEC_BUILTIN_LVEWX: - return altivec_expand_lv_builtin (CODE_FOR_altivec_lvewx, - exp, target, false); - case P10_BUILTIN_SE_LXVRBX: - return altivec_expand_lxvr_builtin (CODE_FOR_vsx_lxvrbx, - exp, target, false, true); - case P10_BUILTIN_SE_LXVRHX: - return altivec_expand_lxvr_builtin (CODE_FOR_vsx_lxvrhx, - exp, target, false, true); - case P10_BUILTIN_SE_LXVRWX: - return altivec_expand_lxvr_builtin (CODE_FOR_vsx_lxvrwx, - exp, target, false, true); - case P10_BUILTIN_SE_LXVRDX: - return altivec_expand_lxvr_builtin (CODE_FOR_vsx_lxvrdx, - exp, target, false, true); - case P10_BUILTIN_ZE_LXVRBX: - return altivec_expand_lxvr_builtin (CODE_FOR_vsx_lxvrbx, - exp, target, false, false); - case P10_BUILTIN_ZE_LXVRHX: - return altivec_expand_lxvr_builtin (CODE_FOR_vsx_lxvrhx, - exp, target, false, false); - case P10_BUILTIN_ZE_LXVRWX: - return altivec_expand_lxvr_builtin (CODE_FOR_vsx_lxvrwx, - exp, target, false, false); - case P10_BUILTIN_ZE_LXVRDX: - return altivec_expand_lxvr_builtin (CODE_FOR_vsx_lxvrdx, - exp, target, false, false); - case ALTIVEC_BUILTIN_LVXL_V2DF: - return altivec_expand_lv_builtin (CODE_FOR_altivec_lvxl_v2df, - exp, target, false); - case ALTIVEC_BUILTIN_LVXL_V2DI: - return altivec_expand_lv_builtin (CODE_FOR_altivec_lvxl_v2di, - exp, target, false); - case ALTIVEC_BUILTIN_LVXL_V4SF: - return altivec_expand_lv_builtin (CODE_FOR_altivec_lvxl_v4sf, - exp, target, false); - case ALTIVEC_BUILTIN_LVXL: - case ALTIVEC_BUILTIN_LVXL_V4SI: - return altivec_expand_lv_builtin (CODE_FOR_altivec_lvxl_v4si, - exp, target, false); - case ALTIVEC_BUILTIN_LVXL_V8HI: - return altivec_expand_lv_builtin (CODE_FOR_altivec_lvxl_v8hi, - exp, target, false); - case ALTIVEC_BUILTIN_LVXL_V16QI: - return altivec_expand_lv_builtin (CODE_FOR_altivec_lvxl_v16qi, - exp, target, false); - case ALTIVEC_BUILTIN_LVX_V1TI: - return altivec_expand_lv_builtin (CODE_FOR_altivec_lvx_v1ti, - exp, target, false); - case ALTIVEC_BUILTIN_LVX_V2DF: - return altivec_expand_lv_builtin (CODE_FOR_altivec_lvx_v2df, - exp, target, false); - case ALTIVEC_BUILTIN_LVX_V2DI: - return altivec_expand_lv_builtin (CODE_FOR_altivec_lvx_v2di, - exp, target, false); - case ALTIVEC_BUILTIN_LVX_V4SF: - return altivec_expand_lv_builtin (CODE_FOR_altivec_lvx_v4sf, - exp, target, false); - case ALTIVEC_BUILTIN_LVX: - case ALTIVEC_BUILTIN_LVX_V4SI: - return altivec_expand_lv_builtin (CODE_FOR_altivec_lvx_v4si, - exp, target, false); - case ALTIVEC_BUILTIN_LVX_V8HI: - return altivec_expand_lv_builtin (CODE_FOR_altivec_lvx_v8hi, - exp, target, false); - case ALTIVEC_BUILTIN_LVX_V16QI: - return altivec_expand_lv_builtin (CODE_FOR_altivec_lvx_v16qi, - exp, target, false); - case ALTIVEC_BUILTIN_LVLX: - return altivec_expand_lv_builtin (CODE_FOR_altivec_lvlx, - exp, target, true); - case ALTIVEC_BUILTIN_LVLXL: - return altivec_expand_lv_builtin (CODE_FOR_altivec_lvlxl, - exp, target, true); - case ALTIVEC_BUILTIN_LVRX: - return altivec_expand_lv_builtin (CODE_FOR_altivec_lvrx, - exp, target, true); - case ALTIVEC_BUILTIN_LVRXL: - return altivec_expand_lv_builtin (CODE_FOR_altivec_lvrxl, - exp, target, true); - case VSX_BUILTIN_LXVD2X_V1TI: - return altivec_expand_lv_builtin (CODE_FOR_vsx_load_v1ti, - exp, target, false); - case VSX_BUILTIN_LXVD2X_V2DF: - return altivec_expand_lv_builtin (CODE_FOR_vsx_load_v2df, - exp, target, false); - case VSX_BUILTIN_LXVD2X_V2DI: - return altivec_expand_lv_builtin (CODE_FOR_vsx_load_v2di, - exp, target, false); - case VSX_BUILTIN_LXVW4X_V4SF: - return altivec_expand_lv_builtin (CODE_FOR_vsx_load_v4sf, - exp, target, false); - case VSX_BUILTIN_LXVW4X_V4SI: - return altivec_expand_lv_builtin (CODE_FOR_vsx_load_v4si, - exp, target, false); - case VSX_BUILTIN_LXVW4X_V8HI: - return altivec_expand_lv_builtin (CODE_FOR_vsx_load_v8hi, - exp, target, false); - case VSX_BUILTIN_LXVW4X_V16QI: - return altivec_expand_lv_builtin (CODE_FOR_vsx_load_v16qi, - exp, target, false); - /* For the following on big endian, it's ok to use any appropriate - unaligned-supporting load, so use a generic expander. For - little-endian, the exact element-reversing instruction must - be used. */ - case VSX_BUILTIN_LD_ELEMREV_V2DF: - { - enum insn_code code = (BYTES_BIG_ENDIAN ? CODE_FOR_vsx_load_v2df - : CODE_FOR_vsx_ld_elemrev_v2df); - return altivec_expand_lv_builtin (code, exp, target, false); - } - case VSX_BUILTIN_LD_ELEMREV_V1TI: - { - enum insn_code code = (BYTES_BIG_ENDIAN ? CODE_FOR_vsx_load_v1ti - : CODE_FOR_vsx_ld_elemrev_v1ti); - return altivec_expand_lv_builtin (code, exp, target, false); - } - case VSX_BUILTIN_LD_ELEMREV_V2DI: - { - enum insn_code code = (BYTES_BIG_ENDIAN ? CODE_FOR_vsx_load_v2di - : CODE_FOR_vsx_ld_elemrev_v2di); - return altivec_expand_lv_builtin (code, exp, target, false); - } - case VSX_BUILTIN_LD_ELEMREV_V4SF: - { - enum insn_code code = (BYTES_BIG_ENDIAN ? CODE_FOR_vsx_load_v4sf - : CODE_FOR_vsx_ld_elemrev_v4sf); - return altivec_expand_lv_builtin (code, exp, target, false); - } - case VSX_BUILTIN_LD_ELEMREV_V4SI: - { - enum insn_code code = (BYTES_BIG_ENDIAN ? CODE_FOR_vsx_load_v4si - : CODE_FOR_vsx_ld_elemrev_v4si); - return altivec_expand_lv_builtin (code, exp, target, false); - } - case VSX_BUILTIN_LD_ELEMREV_V8HI: - { - enum insn_code code = (BYTES_BIG_ENDIAN ? CODE_FOR_vsx_load_v8hi - : CODE_FOR_vsx_ld_elemrev_v8hi); - return altivec_expand_lv_builtin (code, exp, target, false); - } - case VSX_BUILTIN_LD_ELEMREV_V16QI: + case RS6000_BIF_VMINSD: + case RS6000_BIF_VMINUD: + case RS6000_BIF_VMINSB: + case RS6000_BIF_VMINSH: + case RS6000_BIF_VMINSW: + case RS6000_BIF_VMINUB: + case RS6000_BIF_VMINUH: + case RS6000_BIF_VMINUW: + arg0 = gimple_call_arg (stmt, 0); + arg1 = gimple_call_arg (stmt, 1); + lhs = gimple_call_lhs (stmt); + g = gimple_build_assign (lhs, MIN_EXPR, arg0, arg1); + gimple_set_location (g, gimple_location (stmt)); + gsi_replace (gsi, g, true); + return true; + /* flavors of vec_max. */ + case RS6000_BIF_XVMAXDP: + case RS6000_BIF_XVMAXSP: + case RS6000_BIF_VMAXFP: { - enum insn_code code = (BYTES_BIG_ENDIAN ? CODE_FOR_vsx_load_v16qi - : CODE_FOR_vsx_ld_elemrev_v16qi); - return altivec_expand_lv_builtin (code, exp, target, false); + lhs = gimple_call_lhs (stmt); + tree type = TREE_TYPE (lhs); + if (HONOR_NANS (type)) + return false; + gcc_fallthrough (); } - break; - default: - break; - /* Fall through. */ - } - - *expandedp = false; - return NULL_RTX; -} - -/* Check whether a builtin function is supported in this target - configuration. */ -bool -rs6000_builtin_is_supported_p (enum rs6000_builtins fncode) -{ - HOST_WIDE_INT fnmask = rs6000_builtin_info[fncode].mask; - if ((fnmask & rs6000_builtin_mask) != fnmask) - return false; - else - return true; -} - -/* Raise an error message for a builtin function that is called without the - appropriate target options being set. */ - -static void -rs6000_invalid_builtin (enum rs6000_builtins fncode) -{ - size_t uns_fncode = (size_t) fncode; - const char *name = rs6000_builtin_info[uns_fncode].name; - HOST_WIDE_INT fnmask = rs6000_builtin_info[uns_fncode].mask; - - gcc_assert (name != NULL); - if ((fnmask & RS6000_BTM_CELL) != 0) - error ("%qs is only valid for the cell processor", name); - else if ((fnmask & RS6000_BTM_VSX) != 0) - error ("%qs requires the %qs option", name, "-mvsx"); - else if ((fnmask & RS6000_BTM_HTM) != 0) - error ("%qs requires the %qs option", name, "-mhtm"); - else if ((fnmask & RS6000_BTM_ALTIVEC) != 0) - error ("%qs requires the %qs option", name, "-maltivec"); - else if ((fnmask & (RS6000_BTM_DFP | RS6000_BTM_P8_VECTOR)) - == (RS6000_BTM_DFP | RS6000_BTM_P8_VECTOR)) - error ("%qs requires the %qs and %qs options", name, "-mhard-dfp", - "-mpower8-vector"); - else if ((fnmask & RS6000_BTM_DFP) != 0) - error ("%qs requires the %qs option", name, "-mhard-dfp"); - else if ((fnmask & RS6000_BTM_P8_VECTOR) != 0) - error ("%qs requires the %qs option", name, "-mpower8-vector"); - else if ((fnmask & (RS6000_BTM_P9_VECTOR | RS6000_BTM_64BIT)) - == (RS6000_BTM_P9_VECTOR | RS6000_BTM_64BIT)) - error ("%qs requires the %qs and %qs options", name, "-mcpu=power9", - "-m64"); - else if ((fnmask & RS6000_BTM_P9_VECTOR) != 0) - error ("%qs requires the %qs option", name, "-mcpu=power9"); - else if ((fnmask & (RS6000_BTM_P9_MISC | RS6000_BTM_64BIT)) - == (RS6000_BTM_P9_MISC | RS6000_BTM_64BIT)) - error ("%qs requires the %qs and %qs options", name, "-mcpu=power9", - "-m64"); - else if ((fnmask & RS6000_BTM_P9_MISC) == RS6000_BTM_P9_MISC) - error ("%qs requires the %qs option", name, "-mcpu=power9"); - else if ((fnmask & RS6000_BTM_P10) != 0) - error ("%qs requires the %qs option", name, "-mcpu=power10"); - else if ((fnmask & RS6000_BTM_MMA) != 0) - error ("%qs requires the %qs option", name, "-mmma"); - else if ((fnmask & RS6000_BTM_LDBL128) == RS6000_BTM_LDBL128) - { - if (!TARGET_HARD_FLOAT) - error ("%qs requires the %qs option", name, "-mhard-float"); - else - error ("%qs requires the %qs option", name, - TARGET_IEEEQUAD ? "-mabi=ibmlongdouble" : "-mlong-double-128"); - } - else if ((fnmask & RS6000_BTM_HARD_FLOAT) != 0) - error ("%qs requires the %qs option", name, "-mhard-float"); - else if ((fnmask & RS6000_BTM_FLOAT128_HW) != 0) - error ("%qs requires ISA 3.0 IEEE 128-bit floating point", name); - else if ((fnmask & RS6000_BTM_FLOAT128) != 0) - error ("%qs requires the %qs option", name, "%<-mfloat128%>"); - else if ((fnmask & (RS6000_BTM_POPCNTD | RS6000_BTM_POWERPC64)) - == (RS6000_BTM_POPCNTD | RS6000_BTM_POWERPC64)) - error ("%qs requires the %qs (or newer), and %qs or %qs options", - name, "-mcpu=power7", "-m64", "-mpowerpc64"); - else - error ("%qs is not supported with the current options", name); -} - -/* Raise an error message for a builtin function that is called without the - appropriate target options being set. */ - -void -rs6000_invalid_new_builtin (enum rs6000_gen_builtins fncode) -{ - size_t j = (size_t) fncode; - const char *name = rs6000_builtin_info_x[j].bifname; - - switch (rs6000_builtin_info_x[j].enable) - { - case ENB_P5: - error ("%qs requires the %qs option", name, "-mcpu=power5"); - break; - case ENB_P6: - error ("%qs requires the %qs option", name, "-mcpu=power6"); - break; - case ENB_P6_64: - error ("%qs requires the %qs option and either the %qs or %qs option", - name, "-mcpu=power6", "-m64", "-mpowerpc64"); - break; - case ENB_ALTIVEC: - error ("%qs requires the %qs option", name, "-maltivec"); - break; - case ENB_CELL: - error ("%qs requires the %qs option", name, "-mcpu=cell"); - break; - case ENB_VSX: - error ("%qs requires the %qs option", name, "-mvsx"); - break; - case ENB_P7: - error ("%qs requires the %qs option", name, "-mcpu=power7"); - break; - case ENB_P7_64: - error ("%qs requires the %qs option and either the %qs or %qs option", - name, "-mcpu=power7", "-m64", "-mpowerpc64"); - break; - case ENB_P8: - error ("%qs requires the %qs option", name, "-mcpu=power8"); - break; - case ENB_P8V: - error ("%qs requires the %qs and %qs options", name, "-mcpu=power8", - "-mvsx"); - break; - case ENB_P9: - error ("%qs requires the %qs option", name, "-mcpu=power9"); - break; - case ENB_P9_64: - error ("%qs requires the %qs option and either the %qs or %qs option", - name, "-mcpu=power9", "-m64", "-mpowerpc64"); - break; - case ENB_P9V: - error ("%qs requires the %qs and %qs options", name, "-mcpu=power9", - "-mvsx"); - break; - case ENB_IEEE128_HW: - error ("%qs requires ISA 3.0 IEEE 128-bit floating point", name); - break; - case ENB_DFP: - error ("%qs requires the %qs option", name, "-mhard-dfp"); - break; - case ENB_CRYPTO: - error ("%qs requires the %qs option", name, "-mcrypto"); - break; - case ENB_HTM: - error ("%qs requires the %qs option", name, "-mhtm"); - break; - case ENB_P10: - error ("%qs requires the %qs option", name, "-mcpu=power10"); - break; - case ENB_P10_64: - error ("%qs requires the %qs option and either the %qs or %qs option", - name, "-mcpu=power10", "-m64", "-mpowerpc64"); - break; - case ENB_MMA: - error ("%qs requires the %qs option", name, "-mmma"); - break; - default: - case ENB_ALWAYS: - gcc_unreachable (); - } -} - -/* Target hook for early folding of built-ins, shamelessly stolen - from ia64.c. */ - -tree -rs6000_fold_builtin (tree fndecl ATTRIBUTE_UNUSED, - int n_args ATTRIBUTE_UNUSED, - tree *args ATTRIBUTE_UNUSED, - bool ignore ATTRIBUTE_UNUSED) -{ -#ifdef SUBTARGET_FOLD_BUILTIN - return SUBTARGET_FOLD_BUILTIN (fndecl, n_args, args, ignore); -#else - return NULL_TREE; -#endif -} - -/* Helper function to sort out which built-ins may be valid without having - a LHS. */ -static bool -rs6000_builtin_valid_without_lhs (enum rs6000_builtins fn_code) -{ - /* Check for built-ins explicitly marked as a void function. */ - if (rs6000_builtin_info[fn_code].attr & RS6000_BTC_VOID) - return true; - - switch (fn_code) - { - case ALTIVEC_BUILTIN_STVX_V16QI: - case ALTIVEC_BUILTIN_STVX_V8HI: - case ALTIVEC_BUILTIN_STVX_V4SI: - case ALTIVEC_BUILTIN_STVX_V4SF: - case ALTIVEC_BUILTIN_STVX_V2DI: - case ALTIVEC_BUILTIN_STVX_V2DF: - case VSX_BUILTIN_STXVW4X_V16QI: - case VSX_BUILTIN_STXVW4X_V8HI: - case VSX_BUILTIN_STXVW4X_V4SF: - case VSX_BUILTIN_STXVW4X_V4SI: - case VSX_BUILTIN_STXVD2X_V2DF: - case VSX_BUILTIN_STXVD2X_V2DI: + case RS6000_BIF_VMAXSD: + case RS6000_BIF_VMAXUD: + case RS6000_BIF_VMAXSB: + case RS6000_BIF_VMAXSH: + case RS6000_BIF_VMAXSW: + case RS6000_BIF_VMAXUB: + case RS6000_BIF_VMAXUH: + case RS6000_BIF_VMAXUW: + arg0 = gimple_call_arg (stmt, 0); + arg1 = gimple_call_arg (stmt, 1); + lhs = gimple_call_lhs (stmt); + g = gimple_build_assign (lhs, MAX_EXPR, arg0, arg1); + gimple_set_location (g, gimple_location (stmt)); + gsi_replace (gsi, g, true); return true; - default: - return false; - } -} - -/* Helper function to handle the gimple folding of a vector compare - operation. This sets up true/false vectors, and uses the - VEC_COND_EXPR operation. - CODE indicates which comparison is to be made. (EQ, GT, ...). - TYPE indicates the type of the result. - Code is inserted before GSI. */ -static tree -fold_build_vec_cmp (tree_code code, tree type, tree arg0, tree arg1, - gimple_stmt_iterator *gsi) -{ - tree cmp_type = truth_type_for (type); - tree zero_vec = build_zero_cst (type); - tree minus_one_vec = build_minus_one_cst (type); - tree temp = create_tmp_reg_or_ssa_name (cmp_type); - gimple *g = gimple_build_assign (temp, code, arg0, arg1); - gsi_insert_before (gsi, g, GSI_SAME_STMT); - return fold_build3 (VEC_COND_EXPR, type, temp, minus_one_vec, zero_vec); -} - -/* Helper function to handle the in-between steps for the - vector compare built-ins. */ -static void -fold_compare_helper (gimple_stmt_iterator *gsi, tree_code code, gimple *stmt) -{ - tree arg0 = gimple_call_arg (stmt, 0); - tree arg1 = gimple_call_arg (stmt, 1); - tree lhs = gimple_call_lhs (stmt); - tree cmp = fold_build_vec_cmp (code, TREE_TYPE (lhs), arg0, arg1, gsi); - gimple *g = gimple_build_assign (lhs, cmp); - gimple_set_location (g, gimple_location (stmt)); - gsi_replace (gsi, g, true); -} - -/* Helper function to map V2DF and V4SF types to their - integral equivalents (V2DI and V4SI). */ -tree map_to_integral_tree_type (tree input_tree_type) -{ - if (INTEGRAL_TYPE_P (TREE_TYPE (input_tree_type))) - return input_tree_type; - else - { - if (types_compatible_p (TREE_TYPE (input_tree_type), - TREE_TYPE (V2DF_type_node))) - return V2DI_type_node; - else if (types_compatible_p (TREE_TYPE (input_tree_type), - TREE_TYPE (V4SF_type_node))) - return V4SI_type_node; - else - gcc_unreachable (); - } -} - -/* Helper function to handle the vector merge[hl] built-ins. The - implementation difference between h and l versions for this code are in - the values used when building of the permute vector for high word versus - low word merge. The variance is keyed off the use_high parameter. */ -static void -fold_mergehl_helper (gimple_stmt_iterator *gsi, gimple *stmt, int use_high) -{ - tree arg0 = gimple_call_arg (stmt, 0); - tree arg1 = gimple_call_arg (stmt, 1); - tree lhs = gimple_call_lhs (stmt); - tree lhs_type = TREE_TYPE (lhs); - int n_elts = TYPE_VECTOR_SUBPARTS (lhs_type); - int midpoint = n_elts / 2; - int offset = 0; - - if (use_high == 1) - offset = midpoint; - - /* The permute_type will match the lhs for integral types. For double and - float types, the permute type needs to map to the V2 or V4 type that - matches size. */ - tree permute_type; - permute_type = map_to_integral_tree_type (lhs_type); - tree_vector_builder elts (permute_type, VECTOR_CST_NELTS (arg0), 1); - - for (int i = 0; i < midpoint; i++) - { - elts.safe_push (build_int_cst (TREE_TYPE (permute_type), - offset + i)); - elts.safe_push (build_int_cst (TREE_TYPE (permute_type), - offset + n_elts + i)); - } - - tree permute = elts.build (); - - gimple *g = gimple_build_assign (lhs, VEC_PERM_EXPR, arg0, arg1, permute); - gimple_set_location (g, gimple_location (stmt)); - gsi_replace (gsi, g, true); -} - -/* Helper function to handle the vector merge[eo] built-ins. */ -static void -fold_mergeeo_helper (gimple_stmt_iterator *gsi, gimple *stmt, int use_odd) -{ - tree arg0 = gimple_call_arg (stmt, 0); - tree arg1 = gimple_call_arg (stmt, 1); - tree lhs = gimple_call_lhs (stmt); - tree lhs_type = TREE_TYPE (lhs); - int n_elts = TYPE_VECTOR_SUBPARTS (lhs_type); - - /* The permute_type will match the lhs for integral types. For double and - float types, the permute type needs to map to the V2 or V4 type that - matches size. */ - tree permute_type; - permute_type = map_to_integral_tree_type (lhs_type); - - tree_vector_builder elts (permute_type, VECTOR_CST_NELTS (arg0), 1); - - /* Build the permute vector. */ - for (int i = 0; i < n_elts / 2; i++) - { - elts.safe_push (build_int_cst (TREE_TYPE (permute_type), - 2*i + use_odd)); - elts.safe_push (build_int_cst (TREE_TYPE (permute_type), - 2*i + use_odd + n_elts)); - } - - tree permute = elts.build (); - - gimple *g = gimple_build_assign (lhs, VEC_PERM_EXPR, arg0, arg1, permute); - gimple_set_location (g, gimple_location (stmt)); - gsi_replace (gsi, g, true); -} - -/* Expand the MMA built-ins early, so that we can convert the pass-by-reference - __vector_quad arguments into pass-by-value arguments, leading to more - efficient code generation. */ - -bool -rs6000_gimple_fold_mma_builtin (gimple_stmt_iterator *gsi) -{ - gimple *stmt = gsi_stmt (*gsi); - tree fndecl = gimple_call_fndecl (stmt); - enum rs6000_builtins fncode - = (enum rs6000_builtins) DECL_MD_FUNCTION_CODE (fndecl); - unsigned attr = rs6000_builtin_info[fncode].attr; - - if ((attr & RS6000_BTC_GIMPLE) == 0) - return false; - - unsigned nopnds = (attr & RS6000_BTC_OPND_MASK); - gimple_seq new_seq = NULL; - gimple *new_call; - tree new_decl; - - if (fncode == MMA_BUILTIN_DISASSEMBLE_ACC - || fncode == VSX_BUILTIN_DISASSEMBLE_PAIR) - { - /* This is an MMA disassemble built-in function. */ - push_gimplify_context (true); - unsigned nvec = (fncode == MMA_BUILTIN_DISASSEMBLE_ACC) ? 4 : 2; - tree dst_ptr = gimple_call_arg (stmt, 0); - tree src_ptr = gimple_call_arg (stmt, 1); - tree src_type = TREE_TYPE (src_ptr); - tree src = create_tmp_reg_or_ssa_name (TREE_TYPE (src_type)); - gimplify_assign (src, build_simple_mem_ref (src_ptr), &new_seq); - - /* If we are not disassembling an accumulator/pair or our destination is - another accumulator/pair, then just copy the entire thing as is. */ - if ((fncode == MMA_BUILTIN_DISASSEMBLE_ACC - && TREE_TYPE (TREE_TYPE (dst_ptr)) == vector_quad_type_node) - || (fncode == VSX_BUILTIN_DISASSEMBLE_PAIR - && TREE_TYPE (TREE_TYPE (dst_ptr)) == vector_pair_type_node)) - { - tree dst = build_simple_mem_ref (build1 (VIEW_CONVERT_EXPR, - src_type, dst_ptr)); - gimplify_assign (dst, src, &new_seq); - pop_gimplify_context (NULL); - gsi_replace_with_seq (gsi, new_seq, true); - return true; - } - - /* If we're disassembling an accumulator into a different type, we need - to emit a xxmfacc instruction now, since we cannot do it later. */ - if (fncode == MMA_BUILTIN_DISASSEMBLE_ACC) - { - new_decl = rs6000_builtin_decls[MMA_BUILTIN_XXMFACC_INTERNAL]; - new_call = gimple_build_call (new_decl, 1, src); - src = create_tmp_reg_or_ssa_name (vector_quad_type_node); - gimple_call_set_lhs (new_call, src); - gimple_seq_add_stmt (&new_seq, new_call); - } - - /* Copy the accumulator/pair vector by vector. */ - new_decl = rs6000_builtin_decls[fncode + 1]; - tree dst_type = build_pointer_type_for_mode (unsigned_V16QI_type_node, - ptr_mode, true); - tree dst_base = build1 (VIEW_CONVERT_EXPR, dst_type, dst_ptr); - for (unsigned i = 0; i < nvec; i++) - { - unsigned index = WORDS_BIG_ENDIAN ? i : nvec - 1 - i; - tree dst = build2 (MEM_REF, unsigned_V16QI_type_node, dst_base, - build_int_cst (dst_type, index * 16)); - tree dstssa = create_tmp_reg_or_ssa_name (unsigned_V16QI_type_node); - new_call = gimple_build_call (new_decl, 2, src, - build_int_cstu (uint16_type_node, i)); - gimple_call_set_lhs (new_call, dstssa); - gimple_seq_add_stmt (&new_seq, new_call); - gimplify_assign (dst, dstssa, &new_seq); - } - pop_gimplify_context (NULL); - gsi_replace_with_seq (gsi, new_seq, true); - return true; - } - else if (fncode == VSX_BUILTIN_LXVP) - { - push_gimplify_context (true); - tree offset = gimple_call_arg (stmt, 0); - tree ptr = gimple_call_arg (stmt, 1); - tree lhs = gimple_call_lhs (stmt); - if (TREE_TYPE (TREE_TYPE (ptr)) != vector_pair_type_node) - ptr = build1 (VIEW_CONVERT_EXPR, - build_pointer_type (vector_pair_type_node), ptr); - tree mem = build_simple_mem_ref (build2 (POINTER_PLUS_EXPR, - TREE_TYPE (ptr), ptr, offset)); - gimplify_assign (lhs, mem, &new_seq); - pop_gimplify_context (NULL); - gsi_replace_with_seq (gsi, new_seq, true); - return true; - } - else if (fncode == VSX_BUILTIN_STXVP) - { - push_gimplify_context (true); - tree src = gimple_call_arg (stmt, 0); - tree offset = gimple_call_arg (stmt, 1); - tree ptr = gimple_call_arg (stmt, 2); - if (TREE_TYPE (TREE_TYPE (ptr)) != vector_pair_type_node) - ptr = build1 (VIEW_CONVERT_EXPR, - build_pointer_type (vector_pair_type_node), ptr); - tree mem = build_simple_mem_ref (build2 (POINTER_PLUS_EXPR, - TREE_TYPE (ptr), ptr, offset)); - gimplify_assign (mem, src, &new_seq); - pop_gimplify_context (NULL); - gsi_replace_with_seq (gsi, new_seq, true); + /* Flavors of vec_eqv. */ + case RS6000_BIF_EQV_V16QI: + case RS6000_BIF_EQV_V8HI: + case RS6000_BIF_EQV_V4SI: + case RS6000_BIF_EQV_V4SF: + case RS6000_BIF_EQV_V2DF: + case RS6000_BIF_EQV_V2DI: + arg0 = gimple_call_arg (stmt, 0); + arg1 = gimple_call_arg (stmt, 1); + lhs = gimple_call_lhs (stmt); + temp = create_tmp_reg_or_ssa_name (TREE_TYPE (arg1)); + g = gimple_build_assign (temp, BIT_XOR_EXPR, arg0, arg1); + gimple_set_location (g, gimple_location (stmt)); + gsi_insert_before (gsi, g, GSI_SAME_STMT); + g = gimple_build_assign (lhs, BIT_NOT_EXPR, temp); + gimple_set_location (g, gimple_location (stmt)); + gsi_replace (gsi, g, true); return true; - } - - /* Convert this built-in into an internal version that uses pass-by-value - arguments. The internal built-in follows immediately after this one. */ - new_decl = rs6000_builtin_decls[fncode + 1]; - tree lhs, op[MAX_MMA_OPERANDS]; - tree acc = gimple_call_arg (stmt, 0); - push_gimplify_context (true); - - if ((attr & RS6000_BTC_QUAD) != 0) - { - /* This built-in has a pass-by-reference accumulator input, so load it - into a temporary accumulator for use as a pass-by-value input. */ - op[0] = create_tmp_reg_or_ssa_name (vector_quad_type_node); - for (unsigned i = 1; i < nopnds; i++) - op[i] = gimple_call_arg (stmt, i); - gimplify_assign (op[0], build_simple_mem_ref (acc), &new_seq); - } - else - { - /* This built-in does not use its pass-by-reference accumulator argument - as an input argument, so remove it from the input list. */ - nopnds--; - for (unsigned i = 0; i < nopnds; i++) - op[i] = gimple_call_arg (stmt, i + 1); - } - - switch (nopnds) - { - case 0: - new_call = gimple_build_call (new_decl, 0); - break; - case 1: - new_call = gimple_build_call (new_decl, 1, op[0]); - break; - case 2: - new_call = gimple_build_call (new_decl, 2, op[0], op[1]); - break; - case 3: - new_call = gimple_build_call (new_decl, 3, op[0], op[1], op[2]); - break; - case 4: - new_call = gimple_build_call (new_decl, 4, op[0], op[1], op[2], op[3]); - break; - case 5: - new_call = gimple_build_call (new_decl, 5, op[0], op[1], op[2], op[3], - op[4]); - break; - case 6: - new_call = gimple_build_call (new_decl, 6, op[0], op[1], op[2], op[3], - op[4], op[5]); - break; - case 7: - new_call = gimple_build_call (new_decl, 7, op[0], op[1], op[2], op[3], - op[4], op[5], op[6]); - break; - default: - gcc_unreachable (); - } - - if (fncode == VSX_BUILTIN_BUILD_PAIR || fncode == VSX_BUILTIN_ASSEMBLE_PAIR) - lhs = create_tmp_reg_or_ssa_name (vector_pair_type_node); - else - lhs = create_tmp_reg_or_ssa_name (vector_quad_type_node); - gimple_call_set_lhs (new_call, lhs); - gimple_seq_add_stmt (&new_seq, new_call); - gimplify_assign (build_simple_mem_ref (acc), lhs, &new_seq); - pop_gimplify_context (NULL); - gsi_replace_with_seq (gsi, new_seq, true); - - return true; -} - -/* Fold a machine-dependent built-in in GIMPLE. (For folding into - a constant, use rs6000_fold_builtin.) */ - -bool -rs6000_gimple_fold_builtin (gimple_stmt_iterator *gsi) -{ - if (new_builtins_are_live) - return rs6000_gimple_fold_new_builtin (gsi); - - gimple *stmt = gsi_stmt (*gsi); - tree fndecl = gimple_call_fndecl (stmt); - gcc_checking_assert (fndecl && DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_MD); - enum rs6000_builtins fn_code - = (enum rs6000_builtins) DECL_MD_FUNCTION_CODE (fndecl); - tree arg0, arg1, lhs, temp; - enum tree_code bcode; - gimple *g; - - size_t uns_fncode = (size_t) fn_code; - enum insn_code icode = rs6000_builtin_info[uns_fncode].icode; - const char *fn_name1 = rs6000_builtin_info[uns_fncode].name; - const char *fn_name2 = (icode != CODE_FOR_nothing) - ? get_insn_name ((int) icode) - : "nothing"; - - if (TARGET_DEBUG_BUILTIN) - fprintf (stderr, "rs6000_gimple_fold_builtin %d %s %s\n", - fn_code, fn_name1, fn_name2); - - if (!rs6000_fold_gimple) - return false; - - /* Prevent gimple folding for code that does not have a LHS, unless it is - allowed per the rs6000_builtin_valid_without_lhs helper function. */ - if (!gimple_call_lhs (stmt) && !rs6000_builtin_valid_without_lhs (fn_code)) - return false; - - /* Don't fold invalid builtins, let rs6000_expand_builtin diagnose it. */ - if (!rs6000_builtin_is_supported_p (fn_code)) - return false; - - if (rs6000_gimple_fold_mma_builtin (gsi)) - return true; - - switch (fn_code) - { - /* Flavors of vec_add. We deliberately don't expand - P8V_BUILTIN_VADDUQM as it gets lowered from V1TImode to - TImode, resulting in much poorer code generation. */ - case ALTIVEC_BUILTIN_VADDUBM: - case ALTIVEC_BUILTIN_VADDUHM: - case ALTIVEC_BUILTIN_VADDUWM: - case P8V_BUILTIN_VADDUDM: - case ALTIVEC_BUILTIN_VADDFP: - case VSX_BUILTIN_XVADDDP: - bcode = PLUS_EXPR; - do_binary: - arg0 = gimple_call_arg (stmt, 0); - arg1 = gimple_call_arg (stmt, 1); - lhs = gimple_call_lhs (stmt); - if (INTEGRAL_TYPE_P (TREE_TYPE (TREE_TYPE (lhs))) - && !TYPE_OVERFLOW_WRAPS (TREE_TYPE (TREE_TYPE (lhs)))) - { - /* Ensure the binary operation is performed in a type - that wraps if it is integral type. */ - gimple_seq stmts = NULL; - tree type = unsigned_type_for (TREE_TYPE (lhs)); - tree uarg0 = gimple_build (&stmts, VIEW_CONVERT_EXPR, - type, arg0); - tree uarg1 = gimple_build (&stmts, VIEW_CONVERT_EXPR, - type, arg1); - tree res = gimple_build (&stmts, gimple_location (stmt), bcode, - type, uarg0, uarg1); - gsi_insert_seq_before (gsi, stmts, GSI_SAME_STMT); - g = gimple_build_assign (lhs, VIEW_CONVERT_EXPR, - build1 (VIEW_CONVERT_EXPR, - TREE_TYPE (lhs), res)); - gsi_replace (gsi, g, true); - return true; - } - g = gimple_build_assign (lhs, bcode, arg0, arg1); - gimple_set_location (g, gimple_location (stmt)); - gsi_replace (gsi, g, true); - return true; - /* Flavors of vec_sub. We deliberately don't expand - P8V_BUILTIN_VSUBUQM. */ - case ALTIVEC_BUILTIN_VSUBUBM: - case ALTIVEC_BUILTIN_VSUBUHM: - case ALTIVEC_BUILTIN_VSUBUWM: - case P8V_BUILTIN_VSUBUDM: - case ALTIVEC_BUILTIN_VSUBFP: - case VSX_BUILTIN_XVSUBDP: - bcode = MINUS_EXPR; - goto do_binary; - case VSX_BUILTIN_XVMULSP: - case VSX_BUILTIN_XVMULDP: - arg0 = gimple_call_arg (stmt, 0); - arg1 = gimple_call_arg (stmt, 1); - lhs = gimple_call_lhs (stmt); - g = gimple_build_assign (lhs, MULT_EXPR, arg0, arg1); - gimple_set_location (g, gimple_location (stmt)); - gsi_replace (gsi, g, true); - return true; - /* Even element flavors of vec_mul (signed). */ - case ALTIVEC_BUILTIN_VMULESB: - case ALTIVEC_BUILTIN_VMULESH: - case P8V_BUILTIN_VMULESW: - /* Even element flavors of vec_mul (unsigned). */ - case ALTIVEC_BUILTIN_VMULEUB: - case ALTIVEC_BUILTIN_VMULEUH: - case P8V_BUILTIN_VMULEUW: - arg0 = gimple_call_arg (stmt, 0); - arg1 = gimple_call_arg (stmt, 1); - lhs = gimple_call_lhs (stmt); - g = gimple_build_assign (lhs, VEC_WIDEN_MULT_EVEN_EXPR, arg0, arg1); - gimple_set_location (g, gimple_location (stmt)); - gsi_replace (gsi, g, true); - return true; - /* Odd element flavors of vec_mul (signed). */ - case ALTIVEC_BUILTIN_VMULOSB: - case ALTIVEC_BUILTIN_VMULOSH: - case P8V_BUILTIN_VMULOSW: - /* Odd element flavors of vec_mul (unsigned). */ - case ALTIVEC_BUILTIN_VMULOUB: - case ALTIVEC_BUILTIN_VMULOUH: - case P8V_BUILTIN_VMULOUW: - arg0 = gimple_call_arg (stmt, 0); - arg1 = gimple_call_arg (stmt, 1); - lhs = gimple_call_lhs (stmt); - g = gimple_build_assign (lhs, VEC_WIDEN_MULT_ODD_EXPR, arg0, arg1); - gimple_set_location (g, gimple_location (stmt)); - gsi_replace (gsi, g, true); - return true; - /* Flavors of vec_div (Integer). */ - case VSX_BUILTIN_DIV_V2DI: - case VSX_BUILTIN_UDIV_V2DI: - arg0 = gimple_call_arg (stmt, 0); - arg1 = gimple_call_arg (stmt, 1); - lhs = gimple_call_lhs (stmt); - g = gimple_build_assign (lhs, TRUNC_DIV_EXPR, arg0, arg1); - gimple_set_location (g, gimple_location (stmt)); - gsi_replace (gsi, g, true); - return true; - /* Flavors of vec_div (Float). */ - case VSX_BUILTIN_XVDIVSP: - case VSX_BUILTIN_XVDIVDP: - arg0 = gimple_call_arg (stmt, 0); - arg1 = gimple_call_arg (stmt, 1); - lhs = gimple_call_lhs (stmt); - g = gimple_build_assign (lhs, RDIV_EXPR, arg0, arg1); - gimple_set_location (g, gimple_location (stmt)); - gsi_replace (gsi, g, true); - return true; - /* Flavors of vec_and. */ - case ALTIVEC_BUILTIN_VAND_V16QI_UNS: - case ALTIVEC_BUILTIN_VAND_V16QI: - case ALTIVEC_BUILTIN_VAND_V8HI_UNS: - case ALTIVEC_BUILTIN_VAND_V8HI: - case ALTIVEC_BUILTIN_VAND_V4SI_UNS: - case ALTIVEC_BUILTIN_VAND_V4SI: - case ALTIVEC_BUILTIN_VAND_V2DI_UNS: - case ALTIVEC_BUILTIN_VAND_V2DI: - case ALTIVEC_BUILTIN_VAND_V4SF: - case ALTIVEC_BUILTIN_VAND_V2DF: - arg0 = gimple_call_arg (stmt, 0); - arg1 = gimple_call_arg (stmt, 1); - lhs = gimple_call_lhs (stmt); - g = gimple_build_assign (lhs, BIT_AND_EXPR, arg0, arg1); - gimple_set_location (g, gimple_location (stmt)); - gsi_replace (gsi, g, true); - return true; - /* Flavors of vec_andc. */ - case ALTIVEC_BUILTIN_VANDC_V16QI_UNS: - case ALTIVEC_BUILTIN_VANDC_V16QI: - case ALTIVEC_BUILTIN_VANDC_V8HI_UNS: - case ALTIVEC_BUILTIN_VANDC_V8HI: - case ALTIVEC_BUILTIN_VANDC_V4SI_UNS: - case ALTIVEC_BUILTIN_VANDC_V4SI: - case ALTIVEC_BUILTIN_VANDC_V2DI_UNS: - case ALTIVEC_BUILTIN_VANDC_V2DI: - case ALTIVEC_BUILTIN_VANDC_V4SF: - case ALTIVEC_BUILTIN_VANDC_V2DF: - arg0 = gimple_call_arg (stmt, 0); - arg1 = gimple_call_arg (stmt, 1); - lhs = gimple_call_lhs (stmt); - temp = create_tmp_reg_or_ssa_name (TREE_TYPE (arg1)); - g = gimple_build_assign (temp, BIT_NOT_EXPR, arg1); - gimple_set_location (g, gimple_location (stmt)); - gsi_insert_before (gsi, g, GSI_SAME_STMT); - g = gimple_build_assign (lhs, BIT_AND_EXPR, arg0, temp); - gimple_set_location (g, gimple_location (stmt)); - gsi_replace (gsi, g, true); - return true; - /* Flavors of vec_nand. */ - case P8V_BUILTIN_VEC_NAND: - case P8V_BUILTIN_NAND_V16QI_UNS: - case P8V_BUILTIN_NAND_V16QI: - case P8V_BUILTIN_NAND_V8HI_UNS: - case P8V_BUILTIN_NAND_V8HI: - case P8V_BUILTIN_NAND_V4SI_UNS: - case P8V_BUILTIN_NAND_V4SI: - case P8V_BUILTIN_NAND_V2DI_UNS: - case P8V_BUILTIN_NAND_V2DI: - case P8V_BUILTIN_NAND_V4SF: - case P8V_BUILTIN_NAND_V2DF: - arg0 = gimple_call_arg (stmt, 0); - arg1 = gimple_call_arg (stmt, 1); - lhs = gimple_call_lhs (stmt); - temp = create_tmp_reg_or_ssa_name (TREE_TYPE (arg1)); - g = gimple_build_assign (temp, BIT_AND_EXPR, arg0, arg1); - gimple_set_location (g, gimple_location (stmt)); - gsi_insert_before (gsi, g, GSI_SAME_STMT); - g = gimple_build_assign (lhs, BIT_NOT_EXPR, temp); - gimple_set_location (g, gimple_location (stmt)); - gsi_replace (gsi, g, true); - return true; - /* Flavors of vec_or. */ - case ALTIVEC_BUILTIN_VOR_V16QI_UNS: - case ALTIVEC_BUILTIN_VOR_V16QI: - case ALTIVEC_BUILTIN_VOR_V8HI_UNS: - case ALTIVEC_BUILTIN_VOR_V8HI: - case ALTIVEC_BUILTIN_VOR_V4SI_UNS: - case ALTIVEC_BUILTIN_VOR_V4SI: - case ALTIVEC_BUILTIN_VOR_V2DI_UNS: - case ALTIVEC_BUILTIN_VOR_V2DI: - case ALTIVEC_BUILTIN_VOR_V4SF: - case ALTIVEC_BUILTIN_VOR_V2DF: - arg0 = gimple_call_arg (stmt, 0); - arg1 = gimple_call_arg (stmt, 1); - lhs = gimple_call_lhs (stmt); - g = gimple_build_assign (lhs, BIT_IOR_EXPR, arg0, arg1); - gimple_set_location (g, gimple_location (stmt)); - gsi_replace (gsi, g, true); - return true; - /* flavors of vec_orc. */ - case P8V_BUILTIN_ORC_V16QI_UNS: - case P8V_BUILTIN_ORC_V16QI: - case P8V_BUILTIN_ORC_V8HI_UNS: - case P8V_BUILTIN_ORC_V8HI: - case P8V_BUILTIN_ORC_V4SI_UNS: - case P8V_BUILTIN_ORC_V4SI: - case P8V_BUILTIN_ORC_V2DI_UNS: - case P8V_BUILTIN_ORC_V2DI: - case P8V_BUILTIN_ORC_V4SF: - case P8V_BUILTIN_ORC_V2DF: - arg0 = gimple_call_arg (stmt, 0); - arg1 = gimple_call_arg (stmt, 1); - lhs = gimple_call_lhs (stmt); - temp = create_tmp_reg_or_ssa_name (TREE_TYPE (arg1)); - g = gimple_build_assign (temp, BIT_NOT_EXPR, arg1); - gimple_set_location (g, gimple_location (stmt)); - gsi_insert_before (gsi, g, GSI_SAME_STMT); - g = gimple_build_assign (lhs, BIT_IOR_EXPR, arg0, temp); - gimple_set_location (g, gimple_location (stmt)); - gsi_replace (gsi, g, true); - return true; - /* Flavors of vec_xor. */ - case ALTIVEC_BUILTIN_VXOR_V16QI_UNS: - case ALTIVEC_BUILTIN_VXOR_V16QI: - case ALTIVEC_BUILTIN_VXOR_V8HI_UNS: - case ALTIVEC_BUILTIN_VXOR_V8HI: - case ALTIVEC_BUILTIN_VXOR_V4SI_UNS: - case ALTIVEC_BUILTIN_VXOR_V4SI: - case ALTIVEC_BUILTIN_VXOR_V2DI_UNS: - case ALTIVEC_BUILTIN_VXOR_V2DI: - case ALTIVEC_BUILTIN_VXOR_V4SF: - case ALTIVEC_BUILTIN_VXOR_V2DF: - arg0 = gimple_call_arg (stmt, 0); - arg1 = gimple_call_arg (stmt, 1); - lhs = gimple_call_lhs (stmt); - g = gimple_build_assign (lhs, BIT_XOR_EXPR, arg0, arg1); - gimple_set_location (g, gimple_location (stmt)); - gsi_replace (gsi, g, true); - return true; - /* Flavors of vec_nor. */ - case ALTIVEC_BUILTIN_VNOR_V16QI_UNS: - case ALTIVEC_BUILTIN_VNOR_V16QI: - case ALTIVEC_BUILTIN_VNOR_V8HI_UNS: - case ALTIVEC_BUILTIN_VNOR_V8HI: - case ALTIVEC_BUILTIN_VNOR_V4SI_UNS: - case ALTIVEC_BUILTIN_VNOR_V4SI: - case ALTIVEC_BUILTIN_VNOR_V2DI_UNS: - case ALTIVEC_BUILTIN_VNOR_V2DI: - case ALTIVEC_BUILTIN_VNOR_V4SF: - case ALTIVEC_BUILTIN_VNOR_V2DF: - arg0 = gimple_call_arg (stmt, 0); - arg1 = gimple_call_arg (stmt, 1); - lhs = gimple_call_lhs (stmt); - temp = create_tmp_reg_or_ssa_name (TREE_TYPE (arg1)); - g = gimple_build_assign (temp, BIT_IOR_EXPR, arg0, arg1); - gimple_set_location (g, gimple_location (stmt)); - gsi_insert_before (gsi, g, GSI_SAME_STMT); - g = gimple_build_assign (lhs, BIT_NOT_EXPR, temp); - gimple_set_location (g, gimple_location (stmt)); - gsi_replace (gsi, g, true); - return true; - /* flavors of vec_abs. */ - case ALTIVEC_BUILTIN_ABS_V16QI: - case ALTIVEC_BUILTIN_ABS_V8HI: - case ALTIVEC_BUILTIN_ABS_V4SI: - case ALTIVEC_BUILTIN_ABS_V4SF: - case P8V_BUILTIN_ABS_V2DI: - case VSX_BUILTIN_XVABSDP: - arg0 = gimple_call_arg (stmt, 0); - if (INTEGRAL_TYPE_P (TREE_TYPE (TREE_TYPE (arg0))) - && !TYPE_OVERFLOW_WRAPS (TREE_TYPE (TREE_TYPE (arg0)))) - return false; - lhs = gimple_call_lhs (stmt); - g = gimple_build_assign (lhs, ABS_EXPR, arg0); - gimple_set_location (g, gimple_location (stmt)); - gsi_replace (gsi, g, true); - return true; - /* flavors of vec_min. */ - case VSX_BUILTIN_XVMINDP: - case ALTIVEC_BUILTIN_VMINFP: - { - lhs = gimple_call_lhs (stmt); - tree type = TREE_TYPE (lhs); - if (HONOR_NANS (type)) - return false; - gcc_fallthrough (); - } - case P8V_BUILTIN_VMINSD: - case P8V_BUILTIN_VMINUD: - case ALTIVEC_BUILTIN_VMINSB: - case ALTIVEC_BUILTIN_VMINSH: - case ALTIVEC_BUILTIN_VMINSW: - case ALTIVEC_BUILTIN_VMINUB: - case ALTIVEC_BUILTIN_VMINUH: - case ALTIVEC_BUILTIN_VMINUW: + /* Flavors of vec_rotate_left. */ + case RS6000_BIF_VRLB: + case RS6000_BIF_VRLH: + case RS6000_BIF_VRLW: + case RS6000_BIF_VRLD: arg0 = gimple_call_arg (stmt, 0); - arg1 = gimple_call_arg (stmt, 1); - lhs = gimple_call_lhs (stmt); - g = gimple_build_assign (lhs, MIN_EXPR, arg0, arg1); - gimple_set_location (g, gimple_location (stmt)); - gsi_replace (gsi, g, true); - return true; - /* flavors of vec_max. */ - case VSX_BUILTIN_XVMAXDP: - case ALTIVEC_BUILTIN_VMAXFP: - { - lhs = gimple_call_lhs (stmt); - tree type = TREE_TYPE (lhs); - if (HONOR_NANS (type)) - return false; - gcc_fallthrough (); - } - case P8V_BUILTIN_VMAXSD: - case P8V_BUILTIN_VMAXUD: - case ALTIVEC_BUILTIN_VMAXSB: - case ALTIVEC_BUILTIN_VMAXSH: - case ALTIVEC_BUILTIN_VMAXSW: - case ALTIVEC_BUILTIN_VMAXUB: - case ALTIVEC_BUILTIN_VMAXUH: - case ALTIVEC_BUILTIN_VMAXUW: - arg0 = gimple_call_arg (stmt, 0); - arg1 = gimple_call_arg (stmt, 1); - lhs = gimple_call_lhs (stmt); - g = gimple_build_assign (lhs, MAX_EXPR, arg0, arg1); - gimple_set_location (g, gimple_location (stmt)); - gsi_replace (gsi, g, true); - return true; - /* Flavors of vec_eqv. */ - case P8V_BUILTIN_EQV_V16QI: - case P8V_BUILTIN_EQV_V8HI: - case P8V_BUILTIN_EQV_V4SI: - case P8V_BUILTIN_EQV_V4SF: - case P8V_BUILTIN_EQV_V2DF: - case P8V_BUILTIN_EQV_V2DI: - arg0 = gimple_call_arg (stmt, 0); - arg1 = gimple_call_arg (stmt, 1); - lhs = gimple_call_lhs (stmt); - temp = create_tmp_reg_or_ssa_name (TREE_TYPE (arg1)); - g = gimple_build_assign (temp, BIT_XOR_EXPR, arg0, arg1); - gimple_set_location (g, gimple_location (stmt)); - gsi_insert_before (gsi, g, GSI_SAME_STMT); - g = gimple_build_assign (lhs, BIT_NOT_EXPR, temp); - gimple_set_location (g, gimple_location (stmt)); - gsi_replace (gsi, g, true); - return true; - /* Flavors of vec_rotate_left. */ - case ALTIVEC_BUILTIN_VRLB: - case ALTIVEC_BUILTIN_VRLH: - case ALTIVEC_BUILTIN_VRLW: - case P8V_BUILTIN_VRLD: - arg0 = gimple_call_arg (stmt, 0); - arg1 = gimple_call_arg (stmt, 1); - lhs = gimple_call_lhs (stmt); - g = gimple_build_assign (lhs, LROTATE_EXPR, arg0, arg1); - gimple_set_location (g, gimple_location (stmt)); - gsi_replace (gsi, g, true); - return true; - /* Flavors of vector shift right algebraic. - vec_sra{b,h,w} -> vsra{b,h,w}. */ - case ALTIVEC_BUILTIN_VSRAB: - case ALTIVEC_BUILTIN_VSRAH: - case ALTIVEC_BUILTIN_VSRAW: - case P8V_BUILTIN_VSRAD: - { - arg0 = gimple_call_arg (stmt, 0); - arg1 = gimple_call_arg (stmt, 1); - lhs = gimple_call_lhs (stmt); - tree arg1_type = TREE_TYPE (arg1); - tree unsigned_arg1_type = unsigned_type_for (TREE_TYPE (arg1)); - tree unsigned_element_type = unsigned_type_for (TREE_TYPE (arg1_type)); - location_t loc = gimple_location (stmt); - /* Force arg1 into the range valid matching the arg0 type. */ - /* Build a vector consisting of the max valid bit-size values. */ - int n_elts = VECTOR_CST_NELTS (arg1); - tree element_size = build_int_cst (unsigned_element_type, - 128 / n_elts); - tree_vector_builder elts (unsigned_arg1_type, n_elts, 1); - for (int i = 0; i < n_elts; i++) - elts.safe_push (element_size); - tree modulo_tree = elts.build (); - /* Modulo the provided shift value against that vector. */ - gimple_seq stmts = NULL; - tree unsigned_arg1 = gimple_build (&stmts, VIEW_CONVERT_EXPR, - unsigned_arg1_type, arg1); - tree new_arg1 = gimple_build (&stmts, loc, TRUNC_MOD_EXPR, - unsigned_arg1_type, unsigned_arg1, - modulo_tree); - gsi_insert_seq_before (gsi, stmts, GSI_SAME_STMT); - /* And finally, do the shift. */ - g = gimple_build_assign (lhs, RSHIFT_EXPR, arg0, new_arg1); - gimple_set_location (g, loc); - gsi_replace (gsi, g, true); - return true; - } - /* Flavors of vector shift left. - builtin_altivec_vsl{b,h,w} -> vsl{b,h,w}. */ - case ALTIVEC_BUILTIN_VSLB: - case ALTIVEC_BUILTIN_VSLH: - case ALTIVEC_BUILTIN_VSLW: - case P8V_BUILTIN_VSLD: - { - location_t loc; - gimple_seq stmts = NULL; - arg0 = gimple_call_arg (stmt, 0); - tree arg0_type = TREE_TYPE (arg0); - if (INTEGRAL_TYPE_P (TREE_TYPE (arg0_type)) - && !TYPE_OVERFLOW_WRAPS (TREE_TYPE (arg0_type))) - return false; - arg1 = gimple_call_arg (stmt, 1); - tree arg1_type = TREE_TYPE (arg1); - tree unsigned_arg1_type = unsigned_type_for (TREE_TYPE (arg1)); - tree unsigned_element_type = unsigned_type_for (TREE_TYPE (arg1_type)); - loc = gimple_location (stmt); - lhs = gimple_call_lhs (stmt); - /* Force arg1 into the range valid matching the arg0 type. */ - /* Build a vector consisting of the max valid bit-size values. */ - int n_elts = VECTOR_CST_NELTS (arg1); - int tree_size_in_bits = TREE_INT_CST_LOW (size_in_bytes (arg1_type)) - * BITS_PER_UNIT; - tree element_size = build_int_cst (unsigned_element_type, - tree_size_in_bits / n_elts); - tree_vector_builder elts (unsigned_type_for (arg1_type), n_elts, 1); - for (int i = 0; i < n_elts; i++) - elts.safe_push (element_size); - tree modulo_tree = elts.build (); - /* Modulo the provided shift value against that vector. */ - tree unsigned_arg1 = gimple_build (&stmts, VIEW_CONVERT_EXPR, - unsigned_arg1_type, arg1); - tree new_arg1 = gimple_build (&stmts, loc, TRUNC_MOD_EXPR, - unsigned_arg1_type, unsigned_arg1, - modulo_tree); - gsi_insert_seq_before (gsi, stmts, GSI_SAME_STMT); - /* And finally, do the shift. */ - g = gimple_build_assign (lhs, LSHIFT_EXPR, arg0, new_arg1); - gimple_set_location (g, gimple_location (stmt)); - gsi_replace (gsi, g, true); - return true; - } - /* Flavors of vector shift right. */ - case ALTIVEC_BUILTIN_VSRB: - case ALTIVEC_BUILTIN_VSRH: - case ALTIVEC_BUILTIN_VSRW: - case P8V_BUILTIN_VSRD: - { - arg0 = gimple_call_arg (stmt, 0); - arg1 = gimple_call_arg (stmt, 1); - lhs = gimple_call_lhs (stmt); - tree arg1_type = TREE_TYPE (arg1); - tree unsigned_arg1_type = unsigned_type_for (TREE_TYPE (arg1)); - tree unsigned_element_type = unsigned_type_for (TREE_TYPE (arg1_type)); - location_t loc = gimple_location (stmt); - gimple_seq stmts = NULL; - /* Convert arg0 to unsigned. */ - tree arg0_unsigned - = gimple_build (&stmts, VIEW_CONVERT_EXPR, - unsigned_type_for (TREE_TYPE (arg0)), arg0); - /* Force arg1 into the range valid matching the arg0 type. */ - /* Build a vector consisting of the max valid bit-size values. */ - int n_elts = VECTOR_CST_NELTS (arg1); - tree element_size = build_int_cst (unsigned_element_type, - 128 / n_elts); - tree_vector_builder elts (unsigned_arg1_type, n_elts, 1); - for (int i = 0; i < n_elts; i++) - elts.safe_push (element_size); - tree modulo_tree = elts.build (); - /* Modulo the provided shift value against that vector. */ - tree unsigned_arg1 = gimple_build (&stmts, VIEW_CONVERT_EXPR, - unsigned_arg1_type, arg1); - tree new_arg1 = gimple_build (&stmts, loc, TRUNC_MOD_EXPR, - unsigned_arg1_type, unsigned_arg1, - modulo_tree); - /* Do the shift. */ - tree res - = gimple_build (&stmts, RSHIFT_EXPR, - TREE_TYPE (arg0_unsigned), arg0_unsigned, new_arg1); - /* Convert result back to the lhs type. */ - res = gimple_build (&stmts, VIEW_CONVERT_EXPR, TREE_TYPE (lhs), res); - gsi_insert_seq_before (gsi, stmts, GSI_SAME_STMT); - replace_call_with_value (gsi, res); - return true; - } - /* Vector loads. */ - case ALTIVEC_BUILTIN_LVX_V16QI: - case ALTIVEC_BUILTIN_LVX_V8HI: - case ALTIVEC_BUILTIN_LVX_V4SI: - case ALTIVEC_BUILTIN_LVX_V4SF: - case ALTIVEC_BUILTIN_LVX_V2DI: - case ALTIVEC_BUILTIN_LVX_V2DF: - case ALTIVEC_BUILTIN_LVX_V1TI: - { - arg0 = gimple_call_arg (stmt, 0); // offset - arg1 = gimple_call_arg (stmt, 1); // address - lhs = gimple_call_lhs (stmt); - location_t loc = gimple_location (stmt); - /* Since arg1 may be cast to a different type, just use ptr_type_node - here instead of trying to enforce TBAA on pointer types. */ - tree arg1_type = ptr_type_node; - tree lhs_type = TREE_TYPE (lhs); - /* POINTER_PLUS_EXPR wants the offset to be of type 'sizetype'. Create - the tree using the value from arg0. The resulting type will match - the type of arg1. */ - gimple_seq stmts = NULL; - tree temp_offset = gimple_convert (&stmts, loc, sizetype, arg0); - tree temp_addr = gimple_build (&stmts, loc, POINTER_PLUS_EXPR, - arg1_type, arg1, temp_offset); - /* Mask off any lower bits from the address. */ - tree aligned_addr = gimple_build (&stmts, loc, BIT_AND_EXPR, - arg1_type, temp_addr, - build_int_cst (arg1_type, -16)); - gsi_insert_seq_before (gsi, stmts, GSI_SAME_STMT); - if (!is_gimple_mem_ref_addr (aligned_addr)) - { - tree t = make_ssa_name (TREE_TYPE (aligned_addr)); - gimple *g = gimple_build_assign (t, aligned_addr); - gsi_insert_before (gsi, g, GSI_SAME_STMT); - aligned_addr = t; - } - /* Use the build2 helper to set up the mem_ref. The MEM_REF could also - take an offset, but since we've already incorporated the offset - above, here we just pass in a zero. */ - gimple *g - = gimple_build_assign (lhs, build2 (MEM_REF, lhs_type, aligned_addr, - build_int_cst (arg1_type, 0))); - gimple_set_location (g, loc); - gsi_replace (gsi, g, true); - return true; - } - /* Vector stores. */ - case ALTIVEC_BUILTIN_STVX_V16QI: - case ALTIVEC_BUILTIN_STVX_V8HI: - case ALTIVEC_BUILTIN_STVX_V4SI: - case ALTIVEC_BUILTIN_STVX_V4SF: - case ALTIVEC_BUILTIN_STVX_V2DI: - case ALTIVEC_BUILTIN_STVX_V2DF: - { - arg0 = gimple_call_arg (stmt, 0); /* Value to be stored. */ - arg1 = gimple_call_arg (stmt, 1); /* Offset. */ - tree arg2 = gimple_call_arg (stmt, 2); /* Store-to address. */ - location_t loc = gimple_location (stmt); - tree arg0_type = TREE_TYPE (arg0); - /* Use ptr_type_node (no TBAA) for the arg2_type. - FIXME: (Richard) "A proper fix would be to transition this type as - seen from the frontend to GIMPLE, for example in a similar way we - do for MEM_REFs by piggy-backing that on an extra argument, a - constant zero pointer of the alias pointer type to use (which would - also serve as a type indicator of the store itself). I'd use a - target specific internal function for this (not sure if we can have - those target specific, but I guess if it's folded away then that's - fine) and get away with the overload set." */ - tree arg2_type = ptr_type_node; - /* POINTER_PLUS_EXPR wants the offset to be of type 'sizetype'. Create - the tree using the value from arg0. The resulting type will match - the type of arg2. */ - gimple_seq stmts = NULL; - tree temp_offset = gimple_convert (&stmts, loc, sizetype, arg1); - tree temp_addr = gimple_build (&stmts, loc, POINTER_PLUS_EXPR, - arg2_type, arg2, temp_offset); - /* Mask off any lower bits from the address. */ - tree aligned_addr = gimple_build (&stmts, loc, BIT_AND_EXPR, - arg2_type, temp_addr, - build_int_cst (arg2_type, -16)); - gsi_insert_seq_before (gsi, stmts, GSI_SAME_STMT); - if (!is_gimple_mem_ref_addr (aligned_addr)) - { - tree t = make_ssa_name (TREE_TYPE (aligned_addr)); - gimple *g = gimple_build_assign (t, aligned_addr); - gsi_insert_before (gsi, g, GSI_SAME_STMT); - aligned_addr = t; - } - /* The desired gimple result should be similar to: - MEM[(__vector floatD.1407 *)_1] = vf1D.2697; */ - gimple *g - = gimple_build_assign (build2 (MEM_REF, arg0_type, aligned_addr, - build_int_cst (arg2_type, 0)), arg0); - gimple_set_location (g, loc); - gsi_replace (gsi, g, true); - return true; - } - - /* unaligned Vector loads. */ - case VSX_BUILTIN_LXVW4X_V16QI: - case VSX_BUILTIN_LXVW4X_V8HI: - case VSX_BUILTIN_LXVW4X_V4SF: - case VSX_BUILTIN_LXVW4X_V4SI: - case VSX_BUILTIN_LXVD2X_V2DF: - case VSX_BUILTIN_LXVD2X_V2DI: - { - arg0 = gimple_call_arg (stmt, 0); // offset - arg1 = gimple_call_arg (stmt, 1); // address - lhs = gimple_call_lhs (stmt); - location_t loc = gimple_location (stmt); - /* Since arg1 may be cast to a different type, just use ptr_type_node - here instead of trying to enforce TBAA on pointer types. */ - tree arg1_type = ptr_type_node; - tree lhs_type = TREE_TYPE (lhs); - /* In GIMPLE the type of the MEM_REF specifies the alignment. The - required alignment (power) is 4 bytes regardless of data type. */ - tree align_ltype = build_aligned_type (lhs_type, 4); - /* POINTER_PLUS_EXPR wants the offset to be of type 'sizetype'. Create - the tree using the value from arg0. The resulting type will match - the type of arg1. */ - gimple_seq stmts = NULL; - tree temp_offset = gimple_convert (&stmts, loc, sizetype, arg0); - tree temp_addr = gimple_build (&stmts, loc, POINTER_PLUS_EXPR, - arg1_type, arg1, temp_offset); - gsi_insert_seq_before (gsi, stmts, GSI_SAME_STMT); - if (!is_gimple_mem_ref_addr (temp_addr)) - { - tree t = make_ssa_name (TREE_TYPE (temp_addr)); - gimple *g = gimple_build_assign (t, temp_addr); - gsi_insert_before (gsi, g, GSI_SAME_STMT); - temp_addr = t; - } - /* Use the build2 helper to set up the mem_ref. The MEM_REF could also - take an offset, but since we've already incorporated the offset - above, here we just pass in a zero. */ - gimple *g; - g = gimple_build_assign (lhs, build2 (MEM_REF, align_ltype, temp_addr, - build_int_cst (arg1_type, 0))); - gimple_set_location (g, loc); - gsi_replace (gsi, g, true); - return true; - } - - /* unaligned Vector stores. */ - case VSX_BUILTIN_STXVW4X_V16QI: - case VSX_BUILTIN_STXVW4X_V8HI: - case VSX_BUILTIN_STXVW4X_V4SF: - case VSX_BUILTIN_STXVW4X_V4SI: - case VSX_BUILTIN_STXVD2X_V2DF: - case VSX_BUILTIN_STXVD2X_V2DI: - { - arg0 = gimple_call_arg (stmt, 0); /* Value to be stored. */ - arg1 = gimple_call_arg (stmt, 1); /* Offset. */ - tree arg2 = gimple_call_arg (stmt, 2); /* Store-to address. */ - location_t loc = gimple_location (stmt); - tree arg0_type = TREE_TYPE (arg0); - /* Use ptr_type_node (no TBAA) for the arg2_type. */ - tree arg2_type = ptr_type_node; - /* In GIMPLE the type of the MEM_REF specifies the alignment. The - required alignment (power) is 4 bytes regardless of data type. */ - tree align_stype = build_aligned_type (arg0_type, 4); - /* POINTER_PLUS_EXPR wants the offset to be of type 'sizetype'. Create - the tree using the value from arg1. */ - gimple_seq stmts = NULL; - tree temp_offset = gimple_convert (&stmts, loc, sizetype, arg1); - tree temp_addr = gimple_build (&stmts, loc, POINTER_PLUS_EXPR, - arg2_type, arg2, temp_offset); - gsi_insert_seq_before (gsi, stmts, GSI_SAME_STMT); - if (!is_gimple_mem_ref_addr (temp_addr)) - { - tree t = make_ssa_name (TREE_TYPE (temp_addr)); - gimple *g = gimple_build_assign (t, temp_addr); - gsi_insert_before (gsi, g, GSI_SAME_STMT); - temp_addr = t; - } - gimple *g; - g = gimple_build_assign (build2 (MEM_REF, align_stype, temp_addr, - build_int_cst (arg2_type, 0)), arg0); - gimple_set_location (g, loc); - gsi_replace (gsi, g, true); - return true; - } - - /* Vector Fused multiply-add (fma). */ - case ALTIVEC_BUILTIN_VMADDFP: - case VSX_BUILTIN_XVMADDDP: - case ALTIVEC_BUILTIN_VMLADDUHM: - { - arg0 = gimple_call_arg (stmt, 0); - arg1 = gimple_call_arg (stmt, 1); - tree arg2 = gimple_call_arg (stmt, 2); - lhs = gimple_call_lhs (stmt); - gcall *g = gimple_build_call_internal (IFN_FMA, 3, arg0, arg1, arg2); - gimple_call_set_lhs (g, lhs); - gimple_call_set_nothrow (g, true); - gimple_set_location (g, gimple_location (stmt)); - gsi_replace (gsi, g, true); - return true; - } - - /* Vector compares; EQ, NE, GE, GT, LE. */ - case ALTIVEC_BUILTIN_VCMPEQUB: - case ALTIVEC_BUILTIN_VCMPEQUH: - case ALTIVEC_BUILTIN_VCMPEQUW: - case P8V_BUILTIN_VCMPEQUD: - case P10V_BUILTIN_VCMPEQUT: - fold_compare_helper (gsi, EQ_EXPR, stmt); - return true; - - case P9V_BUILTIN_CMPNEB: - case P9V_BUILTIN_CMPNEH: - case P9V_BUILTIN_CMPNEW: - case P10V_BUILTIN_CMPNET: - fold_compare_helper (gsi, NE_EXPR, stmt); - return true; - - case VSX_BUILTIN_CMPGE_16QI: - case VSX_BUILTIN_CMPGE_U16QI: - case VSX_BUILTIN_CMPGE_8HI: - case VSX_BUILTIN_CMPGE_U8HI: - case VSX_BUILTIN_CMPGE_4SI: - case VSX_BUILTIN_CMPGE_U4SI: - case VSX_BUILTIN_CMPGE_2DI: - case VSX_BUILTIN_CMPGE_U2DI: - case P10V_BUILTIN_CMPGE_1TI: - case P10V_BUILTIN_CMPGE_U1TI: - fold_compare_helper (gsi, GE_EXPR, stmt); - return true; - - case ALTIVEC_BUILTIN_VCMPGTSB: - case ALTIVEC_BUILTIN_VCMPGTUB: - case ALTIVEC_BUILTIN_VCMPGTSH: - case ALTIVEC_BUILTIN_VCMPGTUH: - case ALTIVEC_BUILTIN_VCMPGTSW: - case ALTIVEC_BUILTIN_VCMPGTUW: - case P8V_BUILTIN_VCMPGTUD: - case P8V_BUILTIN_VCMPGTSD: - case P10V_BUILTIN_VCMPGTUT: - case P10V_BUILTIN_VCMPGTST: - fold_compare_helper (gsi, GT_EXPR, stmt); - return true; - - case VSX_BUILTIN_CMPLE_16QI: - case VSX_BUILTIN_CMPLE_U16QI: - case VSX_BUILTIN_CMPLE_8HI: - case VSX_BUILTIN_CMPLE_U8HI: - case VSX_BUILTIN_CMPLE_4SI: - case VSX_BUILTIN_CMPLE_U4SI: - case VSX_BUILTIN_CMPLE_2DI: - case VSX_BUILTIN_CMPLE_U2DI: - case P10V_BUILTIN_CMPLE_1TI: - case P10V_BUILTIN_CMPLE_U1TI: - fold_compare_helper (gsi, LE_EXPR, stmt); - return true; - - /* flavors of vec_splat_[us]{8,16,32}. */ - case ALTIVEC_BUILTIN_VSPLTISB: - case ALTIVEC_BUILTIN_VSPLTISH: - case ALTIVEC_BUILTIN_VSPLTISW: - { - arg0 = gimple_call_arg (stmt, 0); - lhs = gimple_call_lhs (stmt); - - /* Only fold the vec_splat_*() if the lower bits of arg 0 is a - 5-bit signed constant in range -16 to +15. */ - if (TREE_CODE (arg0) != INTEGER_CST - || !IN_RANGE (TREE_INT_CST_LOW (arg0), -16, 15)) - return false; - gimple_seq stmts = NULL; - location_t loc = gimple_location (stmt); - tree splat_value = gimple_convert (&stmts, loc, - TREE_TYPE (TREE_TYPE (lhs)), arg0); - gsi_insert_seq_before (gsi, stmts, GSI_SAME_STMT); - tree splat_tree = build_vector_from_val (TREE_TYPE (lhs), splat_value); - g = gimple_build_assign (lhs, splat_tree); - gimple_set_location (g, gimple_location (stmt)); - gsi_replace (gsi, g, true); - return true; - } - - /* Flavors of vec_splat. */ - /* a = vec_splat (b, 0x3) becomes a = { b[3],b[3],b[3],...}; */ - case ALTIVEC_BUILTIN_VSPLTB: - case ALTIVEC_BUILTIN_VSPLTH: - case ALTIVEC_BUILTIN_VSPLTW: - case VSX_BUILTIN_XXSPLTD_V2DI: - case VSX_BUILTIN_XXSPLTD_V2DF: - { - arg0 = gimple_call_arg (stmt, 0); /* input vector. */ - arg1 = gimple_call_arg (stmt, 1); /* index into arg0. */ - /* Only fold the vec_splat_*() if arg1 is both a constant value and - is a valid index into the arg0 vector. */ - unsigned int n_elts = VECTOR_CST_NELTS (arg0); - if (TREE_CODE (arg1) != INTEGER_CST - || TREE_INT_CST_LOW (arg1) > (n_elts -1)) - return false; - lhs = gimple_call_lhs (stmt); - tree lhs_type = TREE_TYPE (lhs); - tree arg0_type = TREE_TYPE (arg0); - tree splat; - if (TREE_CODE (arg0) == VECTOR_CST) - splat = VECTOR_CST_ELT (arg0, TREE_INT_CST_LOW (arg1)); - else - { - /* Determine (in bits) the length and start location of the - splat value for a call to the tree_vec_extract helper. */ - int splat_elem_size = TREE_INT_CST_LOW (size_in_bytes (arg0_type)) - * BITS_PER_UNIT / n_elts; - int splat_start_bit = TREE_INT_CST_LOW (arg1) * splat_elem_size; - tree len = build_int_cst (bitsizetype, splat_elem_size); - tree start = build_int_cst (bitsizetype, splat_start_bit); - splat = tree_vec_extract (gsi, TREE_TYPE (lhs_type), arg0, - len, start); - } - /* And finally, build the new vector. */ - tree splat_tree = build_vector_from_val (lhs_type, splat); - g = gimple_build_assign (lhs, splat_tree); - gimple_set_location (g, gimple_location (stmt)); - gsi_replace (gsi, g, true); - return true; - } - - /* vec_mergel (integrals). */ - case ALTIVEC_BUILTIN_VMRGLH: - case ALTIVEC_BUILTIN_VMRGLW: - case VSX_BUILTIN_XXMRGLW_4SI: - case ALTIVEC_BUILTIN_VMRGLB: - case VSX_BUILTIN_VEC_MERGEL_V2DI: - case VSX_BUILTIN_XXMRGLW_4SF: - case VSX_BUILTIN_VEC_MERGEL_V2DF: - fold_mergehl_helper (gsi, stmt, 1); - return true; - /* vec_mergeh (integrals). */ - case ALTIVEC_BUILTIN_VMRGHH: - case ALTIVEC_BUILTIN_VMRGHW: - case VSX_BUILTIN_XXMRGHW_4SI: - case ALTIVEC_BUILTIN_VMRGHB: - case VSX_BUILTIN_VEC_MERGEH_V2DI: - case VSX_BUILTIN_XXMRGHW_4SF: - case VSX_BUILTIN_VEC_MERGEH_V2DF: - fold_mergehl_helper (gsi, stmt, 0); - return true; - - /* Flavors of vec_mergee. */ - case P8V_BUILTIN_VMRGEW_V4SI: - case P8V_BUILTIN_VMRGEW_V2DI: - case P8V_BUILTIN_VMRGEW_V4SF: - case P8V_BUILTIN_VMRGEW_V2DF: - fold_mergeeo_helper (gsi, stmt, 0); - return true; - /* Flavors of vec_mergeo. */ - case P8V_BUILTIN_VMRGOW_V4SI: - case P8V_BUILTIN_VMRGOW_V2DI: - case P8V_BUILTIN_VMRGOW_V4SF: - case P8V_BUILTIN_VMRGOW_V2DF: - fold_mergeeo_helper (gsi, stmt, 1); - return true; - - /* d = vec_pack (a, b) */ - case P8V_BUILTIN_VPKUDUM: - case ALTIVEC_BUILTIN_VPKUHUM: - case ALTIVEC_BUILTIN_VPKUWUM: - { - arg0 = gimple_call_arg (stmt, 0); - arg1 = gimple_call_arg (stmt, 1); - lhs = gimple_call_lhs (stmt); - gimple *g = gimple_build_assign (lhs, VEC_PACK_TRUNC_EXPR, arg0, arg1); - gimple_set_location (g, gimple_location (stmt)); - gsi_replace (gsi, g, true); - return true; - } - - /* d = vec_unpackh (a) */ - /* Note that the UNPACK_{HI,LO}_EXPR used in the gimple_build_assign call - in this code is sensitive to endian-ness, and needs to be inverted to - handle both LE and BE targets. */ - case ALTIVEC_BUILTIN_VUPKHSB: - case ALTIVEC_BUILTIN_VUPKHSH: - case P8V_BUILTIN_VUPKHSW: - { - arg0 = gimple_call_arg (stmt, 0); - lhs = gimple_call_lhs (stmt); - if (BYTES_BIG_ENDIAN) - g = gimple_build_assign (lhs, VEC_UNPACK_HI_EXPR, arg0); - else - g = gimple_build_assign (lhs, VEC_UNPACK_LO_EXPR, arg0); - gimple_set_location (g, gimple_location (stmt)); - gsi_replace (gsi, g, true); - return true; - } - /* d = vec_unpackl (a) */ - case ALTIVEC_BUILTIN_VUPKLSB: - case ALTIVEC_BUILTIN_VUPKLSH: - case P8V_BUILTIN_VUPKLSW: - { - arg0 = gimple_call_arg (stmt, 0); - lhs = gimple_call_lhs (stmt); - if (BYTES_BIG_ENDIAN) - g = gimple_build_assign (lhs, VEC_UNPACK_LO_EXPR, arg0); - else - g = gimple_build_assign (lhs, VEC_UNPACK_HI_EXPR, arg0); - gimple_set_location (g, gimple_location (stmt)); - gsi_replace (gsi, g, true); - return true; - } - /* There is no gimple type corresponding with pixel, so just return. */ - case ALTIVEC_BUILTIN_VUPKHPX: - case ALTIVEC_BUILTIN_VUPKLPX: - return false; - - /* vec_perm. */ - case ALTIVEC_BUILTIN_VPERM_16QI: - case ALTIVEC_BUILTIN_VPERM_8HI: - case ALTIVEC_BUILTIN_VPERM_4SI: - case ALTIVEC_BUILTIN_VPERM_2DI: - case ALTIVEC_BUILTIN_VPERM_4SF: - case ALTIVEC_BUILTIN_VPERM_2DF: - { - arg0 = gimple_call_arg (stmt, 0); - arg1 = gimple_call_arg (stmt, 1); - tree permute = gimple_call_arg (stmt, 2); - lhs = gimple_call_lhs (stmt); - location_t loc = gimple_location (stmt); - gimple_seq stmts = NULL; - // convert arg0 and arg1 to match the type of the permute - // for the VEC_PERM_EXPR operation. - tree permute_type = (TREE_TYPE (permute)); - tree arg0_ptype = gimple_build (&stmts, loc, VIEW_CONVERT_EXPR, - permute_type, arg0); - tree arg1_ptype = gimple_build (&stmts, loc, VIEW_CONVERT_EXPR, - permute_type, arg1); - tree lhs_ptype = gimple_build (&stmts, loc, VEC_PERM_EXPR, - permute_type, arg0_ptype, arg1_ptype, - permute); - // Convert the result back to the desired lhs type upon completion. - tree temp = gimple_build (&stmts, loc, VIEW_CONVERT_EXPR, - TREE_TYPE (lhs), lhs_ptype); - gsi_insert_seq_before (gsi, stmts, GSI_SAME_STMT); - g = gimple_build_assign (lhs, temp); - gimple_set_location (g, loc); - gsi_replace (gsi, g, true); - return true; - } - - default: - if (TARGET_DEBUG_BUILTIN) - fprintf (stderr, "gimple builtin intrinsic not matched:%d %s %s\n", - fn_code, fn_name1, fn_name2); - break; - } - - return false; -} - -/* Helper function to sort out which built-ins may be valid without having - a LHS. */ -static bool -rs6000_new_builtin_valid_without_lhs (enum rs6000_gen_builtins fn_code, - tree fndecl) -{ - if (TREE_TYPE (TREE_TYPE (fndecl)) == void_type_node) - return true; - - switch (fn_code) - { - case RS6000_BIF_STVX_V16QI: - case RS6000_BIF_STVX_V8HI: - case RS6000_BIF_STVX_V4SI: - case RS6000_BIF_STVX_V4SF: - case RS6000_BIF_STVX_V2DI: - case RS6000_BIF_STVX_V2DF: - case RS6000_BIF_STXVW4X_V16QI: - case RS6000_BIF_STXVW4X_V8HI: - case RS6000_BIF_STXVW4X_V4SF: - case RS6000_BIF_STXVW4X_V4SI: - case RS6000_BIF_STXVD2X_V2DF: - case RS6000_BIF_STXVD2X_V2DI: - return true; - default: - return false; - } -} - -/* Check whether a builtin function is supported in this target - configuration. */ -bool -rs6000_new_builtin_is_supported (enum rs6000_gen_builtins fncode) -{ - switch (rs6000_builtin_info_x[(size_t) fncode].enable) - { - case ENB_ALWAYS: - return true; - case ENB_P5: - return TARGET_POPCNTB; - case ENB_P6: - return TARGET_CMPB; - case ENB_P6_64: - return TARGET_CMPB && TARGET_POWERPC64; - case ENB_P7: - return TARGET_POPCNTD; - case ENB_P7_64: - return TARGET_POPCNTD && TARGET_POWERPC64; - case ENB_P8: - return TARGET_DIRECT_MOVE; - case ENB_P8V: - return TARGET_P8_VECTOR; - case ENB_P9: - return TARGET_MODULO; - case ENB_P9_64: - return TARGET_MODULO && TARGET_POWERPC64; - case ENB_P9V: - return TARGET_P9_VECTOR; - case ENB_P10: - return TARGET_POWER10; - case ENB_P10_64: - return TARGET_POWER10 && TARGET_POWERPC64; - case ENB_ALTIVEC: - return TARGET_ALTIVEC; - case ENB_VSX: - return TARGET_VSX; - case ENB_CELL: - return TARGET_ALTIVEC && rs6000_cpu == PROCESSOR_CELL; - case ENB_IEEE128_HW: - return TARGET_FLOAT128_HW; - case ENB_DFP: - return TARGET_DFP; - case ENB_CRYPTO: - return TARGET_CRYPTO; - case ENB_HTM: - return TARGET_HTM; - case ENB_MMA: - return TARGET_MMA; - default: - gcc_unreachable (); - } - gcc_unreachable (); -} - -/* Expand the MMA built-ins early, so that we can convert the pass-by-reference - __vector_quad arguments into pass-by-value arguments, leading to more - efficient code generation. */ -static bool -rs6000_gimple_fold_new_mma_builtin (gimple_stmt_iterator *gsi, - rs6000_gen_builtins fn_code) -{ - gimple *stmt = gsi_stmt (*gsi); - size_t fncode = (size_t) fn_code; - - if (!bif_is_mma (rs6000_builtin_info_x[fncode])) - return false; - - /* Each call that can be gimple-expanded has an associated built-in - function that it will expand into. If this one doesn't, we have - already expanded it! Exceptions: lxvp and stxvp. */ - if (rs6000_builtin_info_x[fncode].assoc_bif == RS6000_BIF_NONE - && fncode != RS6000_BIF_LXVP - && fncode != RS6000_BIF_STXVP) - return false; - - bifdata *bd = &rs6000_builtin_info_x[fncode]; - unsigned nopnds = bd->nargs; - gimple_seq new_seq = NULL; - gimple *new_call; - tree new_decl; - - /* Compatibility built-ins; we used to call these - __builtin_mma_{dis,}assemble_pair, but now we call them - __builtin_vsx_{dis,}assemble_pair. Handle the old versions. */ - if (fncode == RS6000_BIF_ASSEMBLE_PAIR) - fncode = RS6000_BIF_ASSEMBLE_PAIR_V; - else if (fncode == RS6000_BIF_DISASSEMBLE_PAIR) - fncode = RS6000_BIF_DISASSEMBLE_PAIR_V; - - if (fncode == RS6000_BIF_DISASSEMBLE_ACC - || fncode == RS6000_BIF_DISASSEMBLE_PAIR_V) - { - /* This is an MMA disassemble built-in function. */ - push_gimplify_context (true); - unsigned nvec = (fncode == RS6000_BIF_DISASSEMBLE_ACC) ? 4 : 2; - tree dst_ptr = gimple_call_arg (stmt, 0); - tree src_ptr = gimple_call_arg (stmt, 1); - tree src_type = TREE_TYPE (src_ptr); - tree src = create_tmp_reg_or_ssa_name (TREE_TYPE (src_type)); - gimplify_assign (src, build_simple_mem_ref (src_ptr), &new_seq); - - /* If we are not disassembling an accumulator/pair or our destination is - another accumulator/pair, then just copy the entire thing as is. */ - if ((fncode == RS6000_BIF_DISASSEMBLE_ACC - && TREE_TYPE (TREE_TYPE (dst_ptr)) == vector_quad_type_node) - || (fncode == RS6000_BIF_DISASSEMBLE_PAIR_V - && TREE_TYPE (TREE_TYPE (dst_ptr)) == vector_pair_type_node)) - { - tree dst = build_simple_mem_ref (build1 (VIEW_CONVERT_EXPR, - src_type, dst_ptr)); - gimplify_assign (dst, src, &new_seq); - pop_gimplify_context (NULL); - gsi_replace_with_seq (gsi, new_seq, true); - return true; - } - - /* If we're disassembling an accumulator into a different type, we need - to emit a xxmfacc instruction now, since we cannot do it later. */ - if (fncode == RS6000_BIF_DISASSEMBLE_ACC) - { - new_decl = rs6000_builtin_decls_x[RS6000_BIF_XXMFACC_INTERNAL]; - new_call = gimple_build_call (new_decl, 1, src); - src = create_tmp_reg_or_ssa_name (vector_quad_type_node); - gimple_call_set_lhs (new_call, src); - gimple_seq_add_stmt (&new_seq, new_call); - } - - /* Copy the accumulator/pair vector by vector. */ - new_decl - = rs6000_builtin_decls_x[rs6000_builtin_info_x[fncode].assoc_bif]; - tree dst_type = build_pointer_type_for_mode (unsigned_V16QI_type_node, - ptr_mode, true); - tree dst_base = build1 (VIEW_CONVERT_EXPR, dst_type, dst_ptr); - for (unsigned i = 0; i < nvec; i++) - { - unsigned index = WORDS_BIG_ENDIAN ? i : nvec - 1 - i; - tree dst = build2 (MEM_REF, unsigned_V16QI_type_node, dst_base, - build_int_cst (dst_type, index * 16)); - tree dstssa = create_tmp_reg_or_ssa_name (unsigned_V16QI_type_node); - new_call = gimple_build_call (new_decl, 2, src, - build_int_cstu (uint16_type_node, i)); - gimple_call_set_lhs (new_call, dstssa); - gimple_seq_add_stmt (&new_seq, new_call); - gimplify_assign (dst, dstssa, &new_seq); - } - pop_gimplify_context (NULL); - gsi_replace_with_seq (gsi, new_seq, true); - return true; - } - - /* TODO: Do some factoring on these two chunks. */ - if (fncode == RS6000_BIF_LXVP) - { - push_gimplify_context (true); - tree offset = gimple_call_arg (stmt, 0); - tree ptr = gimple_call_arg (stmt, 1); - tree lhs = gimple_call_lhs (stmt); - if (TREE_TYPE (TREE_TYPE (ptr)) != vector_pair_type_node) - ptr = build1 (VIEW_CONVERT_EXPR, - build_pointer_type (vector_pair_type_node), ptr); - tree mem = build_simple_mem_ref (build2 (POINTER_PLUS_EXPR, - TREE_TYPE (ptr), ptr, offset)); - gimplify_assign (lhs, mem, &new_seq); - pop_gimplify_context (NULL); - gsi_replace_with_seq (gsi, new_seq, true); - return true; - } - - if (fncode == RS6000_BIF_STXVP) - { - push_gimplify_context (true); - tree src = gimple_call_arg (stmt, 0); - tree offset = gimple_call_arg (stmt, 1); - tree ptr = gimple_call_arg (stmt, 2); - if (TREE_TYPE (TREE_TYPE (ptr)) != vector_pair_type_node) - ptr = build1 (VIEW_CONVERT_EXPR, - build_pointer_type (vector_pair_type_node), ptr); - tree mem = build_simple_mem_ref (build2 (POINTER_PLUS_EXPR, - TREE_TYPE (ptr), ptr, offset)); - gimplify_assign (mem, src, &new_seq); - pop_gimplify_context (NULL); - gsi_replace_with_seq (gsi, new_seq, true); - return true; - } - - /* Convert this built-in into an internal version that uses pass-by-value - arguments. The internal built-in is found in the assoc_bif field. */ - new_decl = rs6000_builtin_decls_x[rs6000_builtin_info_x[fncode].assoc_bif]; - tree lhs, op[MAX_MMA_OPERANDS]; - tree acc = gimple_call_arg (stmt, 0); - push_gimplify_context (true); - - if (bif_is_quad (*bd)) - { - /* This built-in has a pass-by-reference accumulator input, so load it - into a temporary accumulator for use as a pass-by-value input. */ - op[0] = create_tmp_reg_or_ssa_name (vector_quad_type_node); - for (unsigned i = 1; i < nopnds; i++) - op[i] = gimple_call_arg (stmt, i); - gimplify_assign (op[0], build_simple_mem_ref (acc), &new_seq); - } - else - { - /* This built-in does not use its pass-by-reference accumulator argument - as an input argument, so remove it from the input list. */ - nopnds--; - for (unsigned i = 0; i < nopnds; i++) - op[i] = gimple_call_arg (stmt, i + 1); - } - - switch (nopnds) - { - case 0: - new_call = gimple_build_call (new_decl, 0); - break; - case 1: - new_call = gimple_build_call (new_decl, 1, op[0]); - break; - case 2: - new_call = gimple_build_call (new_decl, 2, op[0], op[1]); - break; - case 3: - new_call = gimple_build_call (new_decl, 3, op[0], op[1], op[2]); - break; - case 4: - new_call = gimple_build_call (new_decl, 4, op[0], op[1], op[2], op[3]); - break; - case 5: - new_call = gimple_build_call (new_decl, 5, op[0], op[1], op[2], op[3], - op[4]); - break; - case 6: - new_call = gimple_build_call (new_decl, 6, op[0], op[1], op[2], op[3], - op[4], op[5]); - break; - case 7: - new_call = gimple_build_call (new_decl, 7, op[0], op[1], op[2], op[3], - op[4], op[5], op[6]); - break; - default: - gcc_unreachable (); - } - - if (fncode == RS6000_BIF_BUILD_PAIR || fncode == RS6000_BIF_ASSEMBLE_PAIR_V) - lhs = create_tmp_reg_or_ssa_name (vector_pair_type_node); - else - lhs = create_tmp_reg_or_ssa_name (vector_quad_type_node); - gimple_call_set_lhs (new_call, lhs); - gimple_seq_add_stmt (&new_seq, new_call); - gimplify_assign (build_simple_mem_ref (acc), lhs, &new_seq); - pop_gimplify_context (NULL); - gsi_replace_with_seq (gsi, new_seq, true); - - return true; -} - -/* Fold a machine-dependent built-in in GIMPLE. (For folding into - a constant, use rs6000_fold_builtin.) */ -static bool -rs6000_gimple_fold_new_builtin (gimple_stmt_iterator *gsi) -{ - gimple *stmt = gsi_stmt (*gsi); - tree fndecl = gimple_call_fndecl (stmt); - gcc_checking_assert (fndecl && DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_MD); - enum rs6000_gen_builtins fn_code - = (enum rs6000_gen_builtins) DECL_MD_FUNCTION_CODE (fndecl); - tree arg0, arg1, lhs, temp; - enum tree_code bcode; - gimple *g; - - size_t uns_fncode = (size_t) fn_code; - enum insn_code icode = rs6000_builtin_info_x[uns_fncode].icode; - const char *fn_name1 = rs6000_builtin_info_x[uns_fncode].bifname; - const char *fn_name2 = (icode != CODE_FOR_nothing) - ? get_insn_name ((int) icode) - : "nothing"; - - if (TARGET_DEBUG_BUILTIN) - fprintf (stderr, "rs6000_gimple_fold_new_builtin %d %s %s\n", - fn_code, fn_name1, fn_name2); - - if (!rs6000_fold_gimple) - return false; - - /* Prevent gimple folding for code that does not have a LHS, unless it is - allowed per the rs6000_new_builtin_valid_without_lhs helper function. */ - if (!gimple_call_lhs (stmt) - && !rs6000_new_builtin_valid_without_lhs (fn_code, fndecl)) - return false; - - /* Don't fold invalid builtins, let rs6000_expand_builtin diagnose it. */ - if (!rs6000_new_builtin_is_supported (fn_code)) - return false; - - if (rs6000_gimple_fold_new_mma_builtin (gsi, fn_code)) - return true; - - switch (fn_code) - { - /* Flavors of vec_add. We deliberately don't expand - RS6000_BIF_VADDUQM as it gets lowered from V1TImode to - TImode, resulting in much poorer code generation. */ - case RS6000_BIF_VADDUBM: - case RS6000_BIF_VADDUHM: - case RS6000_BIF_VADDUWM: - case RS6000_BIF_VADDUDM: - case RS6000_BIF_VADDFP: - case RS6000_BIF_XVADDDP: - case RS6000_BIF_XVADDSP: - bcode = PLUS_EXPR; - do_binary: - arg0 = gimple_call_arg (stmt, 0); - arg1 = gimple_call_arg (stmt, 1); - lhs = gimple_call_lhs (stmt); - if (INTEGRAL_TYPE_P (TREE_TYPE (TREE_TYPE (lhs))) - && !TYPE_OVERFLOW_WRAPS (TREE_TYPE (TREE_TYPE (lhs)))) - { - /* Ensure the binary operation is performed in a type - that wraps if it is integral type. */ - gimple_seq stmts = NULL; - tree type = unsigned_type_for (TREE_TYPE (lhs)); - tree uarg0 = gimple_build (&stmts, VIEW_CONVERT_EXPR, - type, arg0); - tree uarg1 = gimple_build (&stmts, VIEW_CONVERT_EXPR, - type, arg1); - tree res = gimple_build (&stmts, gimple_location (stmt), bcode, - type, uarg0, uarg1); - gsi_insert_seq_before (gsi, stmts, GSI_SAME_STMT); - g = gimple_build_assign (lhs, VIEW_CONVERT_EXPR, - build1 (VIEW_CONVERT_EXPR, - TREE_TYPE (lhs), res)); - gsi_replace (gsi, g, true); - return true; - } - g = gimple_build_assign (lhs, bcode, arg0, arg1); - gimple_set_location (g, gimple_location (stmt)); - gsi_replace (gsi, g, true); - return true; - /* Flavors of vec_sub. We deliberately don't expand - RS6000_BIF_VSUBUQM. */ - case RS6000_BIF_VSUBUBM: - case RS6000_BIF_VSUBUHM: - case RS6000_BIF_VSUBUWM: - case RS6000_BIF_VSUBUDM: - case RS6000_BIF_VSUBFP: - case RS6000_BIF_XVSUBDP: - case RS6000_BIF_XVSUBSP: - bcode = MINUS_EXPR; - goto do_binary; - case RS6000_BIF_XVMULSP: - case RS6000_BIF_XVMULDP: - arg0 = gimple_call_arg (stmt, 0); - arg1 = gimple_call_arg (stmt, 1); - lhs = gimple_call_lhs (stmt); - g = gimple_build_assign (lhs, MULT_EXPR, arg0, arg1); - gimple_set_location (g, gimple_location (stmt)); - gsi_replace (gsi, g, true); - return true; - /* Even element flavors of vec_mul (signed). */ - case RS6000_BIF_VMULESB: - case RS6000_BIF_VMULESH: - case RS6000_BIF_VMULESW: - /* Even element flavors of vec_mul (unsigned). */ - case RS6000_BIF_VMULEUB: - case RS6000_BIF_VMULEUH: - case RS6000_BIF_VMULEUW: - arg0 = gimple_call_arg (stmt, 0); - arg1 = gimple_call_arg (stmt, 1); - lhs = gimple_call_lhs (stmt); - g = gimple_build_assign (lhs, VEC_WIDEN_MULT_EVEN_EXPR, arg0, arg1); - gimple_set_location (g, gimple_location (stmt)); - gsi_replace (gsi, g, true); - return true; - /* Odd element flavors of vec_mul (signed). */ - case RS6000_BIF_VMULOSB: - case RS6000_BIF_VMULOSH: - case RS6000_BIF_VMULOSW: - /* Odd element flavors of vec_mul (unsigned). */ - case RS6000_BIF_VMULOUB: - case RS6000_BIF_VMULOUH: - case RS6000_BIF_VMULOUW: - arg0 = gimple_call_arg (stmt, 0); - arg1 = gimple_call_arg (stmt, 1); - lhs = gimple_call_lhs (stmt); - g = gimple_build_assign (lhs, VEC_WIDEN_MULT_ODD_EXPR, arg0, arg1); - gimple_set_location (g, gimple_location (stmt)); - gsi_replace (gsi, g, true); - return true; - /* Flavors of vec_div (Integer). */ - case RS6000_BIF_DIV_V2DI: - case RS6000_BIF_UDIV_V2DI: - arg0 = gimple_call_arg (stmt, 0); - arg1 = gimple_call_arg (stmt, 1); - lhs = gimple_call_lhs (stmt); - g = gimple_build_assign (lhs, TRUNC_DIV_EXPR, arg0, arg1); - gimple_set_location (g, gimple_location (stmt)); - gsi_replace (gsi, g, true); - return true; - /* Flavors of vec_div (Float). */ - case RS6000_BIF_XVDIVSP: - case RS6000_BIF_XVDIVDP: - arg0 = gimple_call_arg (stmt, 0); - arg1 = gimple_call_arg (stmt, 1); - lhs = gimple_call_lhs (stmt); - g = gimple_build_assign (lhs, RDIV_EXPR, arg0, arg1); - gimple_set_location (g, gimple_location (stmt)); - gsi_replace (gsi, g, true); - return true; - /* Flavors of vec_and. */ - case RS6000_BIF_VAND_V16QI_UNS: - case RS6000_BIF_VAND_V16QI: - case RS6000_BIF_VAND_V8HI_UNS: - case RS6000_BIF_VAND_V8HI: - case RS6000_BIF_VAND_V4SI_UNS: - case RS6000_BIF_VAND_V4SI: - case RS6000_BIF_VAND_V2DI_UNS: - case RS6000_BIF_VAND_V2DI: - case RS6000_BIF_VAND_V4SF: - case RS6000_BIF_VAND_V2DF: - arg0 = gimple_call_arg (stmt, 0); - arg1 = gimple_call_arg (stmt, 1); - lhs = gimple_call_lhs (stmt); - g = gimple_build_assign (lhs, BIT_AND_EXPR, arg0, arg1); - gimple_set_location (g, gimple_location (stmt)); - gsi_replace (gsi, g, true); - return true; - /* Flavors of vec_andc. */ - case RS6000_BIF_VANDC_V16QI_UNS: - case RS6000_BIF_VANDC_V16QI: - case RS6000_BIF_VANDC_V8HI_UNS: - case RS6000_BIF_VANDC_V8HI: - case RS6000_BIF_VANDC_V4SI_UNS: - case RS6000_BIF_VANDC_V4SI: - case RS6000_BIF_VANDC_V2DI_UNS: - case RS6000_BIF_VANDC_V2DI: - case RS6000_BIF_VANDC_V4SF: - case RS6000_BIF_VANDC_V2DF: - arg0 = gimple_call_arg (stmt, 0); - arg1 = gimple_call_arg (stmt, 1); - lhs = gimple_call_lhs (stmt); - temp = create_tmp_reg_or_ssa_name (TREE_TYPE (arg1)); - g = gimple_build_assign (temp, BIT_NOT_EXPR, arg1); - gimple_set_location (g, gimple_location (stmt)); - gsi_insert_before (gsi, g, GSI_SAME_STMT); - g = gimple_build_assign (lhs, BIT_AND_EXPR, arg0, temp); - gimple_set_location (g, gimple_location (stmt)); - gsi_replace (gsi, g, true); - return true; - /* Flavors of vec_nand. */ - case RS6000_BIF_NAND_V16QI_UNS: - case RS6000_BIF_NAND_V16QI: - case RS6000_BIF_NAND_V8HI_UNS: - case RS6000_BIF_NAND_V8HI: - case RS6000_BIF_NAND_V4SI_UNS: - case RS6000_BIF_NAND_V4SI: - case RS6000_BIF_NAND_V2DI_UNS: - case RS6000_BIF_NAND_V2DI: - case RS6000_BIF_NAND_V4SF: - case RS6000_BIF_NAND_V2DF: - arg0 = gimple_call_arg (stmt, 0); - arg1 = gimple_call_arg (stmt, 1); - lhs = gimple_call_lhs (stmt); - temp = create_tmp_reg_or_ssa_name (TREE_TYPE (arg1)); - g = gimple_build_assign (temp, BIT_AND_EXPR, arg0, arg1); - gimple_set_location (g, gimple_location (stmt)); - gsi_insert_before (gsi, g, GSI_SAME_STMT); - g = gimple_build_assign (lhs, BIT_NOT_EXPR, temp); - gimple_set_location (g, gimple_location (stmt)); - gsi_replace (gsi, g, true); - return true; - /* Flavors of vec_or. */ - case RS6000_BIF_VOR_V16QI_UNS: - case RS6000_BIF_VOR_V16QI: - case RS6000_BIF_VOR_V8HI_UNS: - case RS6000_BIF_VOR_V8HI: - case RS6000_BIF_VOR_V4SI_UNS: - case RS6000_BIF_VOR_V4SI: - case RS6000_BIF_VOR_V2DI_UNS: - case RS6000_BIF_VOR_V2DI: - case RS6000_BIF_VOR_V4SF: - case RS6000_BIF_VOR_V2DF: - arg0 = gimple_call_arg (stmt, 0); - arg1 = gimple_call_arg (stmt, 1); - lhs = gimple_call_lhs (stmt); - g = gimple_build_assign (lhs, BIT_IOR_EXPR, arg0, arg1); - gimple_set_location (g, gimple_location (stmt)); - gsi_replace (gsi, g, true); - return true; - /* flavors of vec_orc. */ - case RS6000_BIF_ORC_V16QI_UNS: - case RS6000_BIF_ORC_V16QI: - case RS6000_BIF_ORC_V8HI_UNS: - case RS6000_BIF_ORC_V8HI: - case RS6000_BIF_ORC_V4SI_UNS: - case RS6000_BIF_ORC_V4SI: - case RS6000_BIF_ORC_V2DI_UNS: - case RS6000_BIF_ORC_V2DI: - case RS6000_BIF_ORC_V4SF: - case RS6000_BIF_ORC_V2DF: - arg0 = gimple_call_arg (stmt, 0); - arg1 = gimple_call_arg (stmt, 1); - lhs = gimple_call_lhs (stmt); - temp = create_tmp_reg_or_ssa_name (TREE_TYPE (arg1)); - g = gimple_build_assign (temp, BIT_NOT_EXPR, arg1); - gimple_set_location (g, gimple_location (stmt)); - gsi_insert_before (gsi, g, GSI_SAME_STMT); - g = gimple_build_assign (lhs, BIT_IOR_EXPR, arg0, temp); - gimple_set_location (g, gimple_location (stmt)); - gsi_replace (gsi, g, true); - return true; - /* Flavors of vec_xor. */ - case RS6000_BIF_VXOR_V16QI_UNS: - case RS6000_BIF_VXOR_V16QI: - case RS6000_BIF_VXOR_V8HI_UNS: - case RS6000_BIF_VXOR_V8HI: - case RS6000_BIF_VXOR_V4SI_UNS: - case RS6000_BIF_VXOR_V4SI: - case RS6000_BIF_VXOR_V2DI_UNS: - case RS6000_BIF_VXOR_V2DI: - case RS6000_BIF_VXOR_V4SF: - case RS6000_BIF_VXOR_V2DF: - arg0 = gimple_call_arg (stmt, 0); - arg1 = gimple_call_arg (stmt, 1); - lhs = gimple_call_lhs (stmt); - g = gimple_build_assign (lhs, BIT_XOR_EXPR, arg0, arg1); - gimple_set_location (g, gimple_location (stmt)); - gsi_replace (gsi, g, true); - return true; - /* Flavors of vec_nor. */ - case RS6000_BIF_VNOR_V16QI_UNS: - case RS6000_BIF_VNOR_V16QI: - case RS6000_BIF_VNOR_V8HI_UNS: - case RS6000_BIF_VNOR_V8HI: - case RS6000_BIF_VNOR_V4SI_UNS: - case RS6000_BIF_VNOR_V4SI: - case RS6000_BIF_VNOR_V2DI_UNS: - case RS6000_BIF_VNOR_V2DI: - case RS6000_BIF_VNOR_V4SF: - case RS6000_BIF_VNOR_V2DF: - arg0 = gimple_call_arg (stmt, 0); - arg1 = gimple_call_arg (stmt, 1); - lhs = gimple_call_lhs (stmt); - temp = create_tmp_reg_or_ssa_name (TREE_TYPE (arg1)); - g = gimple_build_assign (temp, BIT_IOR_EXPR, arg0, arg1); - gimple_set_location (g, gimple_location (stmt)); - gsi_insert_before (gsi, g, GSI_SAME_STMT); - g = gimple_build_assign (lhs, BIT_NOT_EXPR, temp); - gimple_set_location (g, gimple_location (stmt)); - gsi_replace (gsi, g, true); - return true; - /* flavors of vec_abs. */ - case RS6000_BIF_ABS_V16QI: - case RS6000_BIF_ABS_V8HI: - case RS6000_BIF_ABS_V4SI: - case RS6000_BIF_ABS_V4SF: - case RS6000_BIF_ABS_V2DI: - case RS6000_BIF_XVABSDP: - case RS6000_BIF_XVABSSP: - arg0 = gimple_call_arg (stmt, 0); - if (INTEGRAL_TYPE_P (TREE_TYPE (TREE_TYPE (arg0))) - && !TYPE_OVERFLOW_WRAPS (TREE_TYPE (TREE_TYPE (arg0)))) - return false; - lhs = gimple_call_lhs (stmt); - g = gimple_build_assign (lhs, ABS_EXPR, arg0); - gimple_set_location (g, gimple_location (stmt)); - gsi_replace (gsi, g, true); - return true; - /* flavors of vec_min. */ - case RS6000_BIF_XVMINDP: - case RS6000_BIF_XVMINSP: - case RS6000_BIF_VMINFP: - { - lhs = gimple_call_lhs (stmt); - tree type = TREE_TYPE (lhs); - if (HONOR_NANS (type)) - return false; - gcc_fallthrough (); - } - case RS6000_BIF_VMINSD: - case RS6000_BIF_VMINUD: - case RS6000_BIF_VMINSB: - case RS6000_BIF_VMINSH: - case RS6000_BIF_VMINSW: - case RS6000_BIF_VMINUB: - case RS6000_BIF_VMINUH: - case RS6000_BIF_VMINUW: - arg0 = gimple_call_arg (stmt, 0); - arg1 = gimple_call_arg (stmt, 1); - lhs = gimple_call_lhs (stmt); - g = gimple_build_assign (lhs, MIN_EXPR, arg0, arg1); - gimple_set_location (g, gimple_location (stmt)); - gsi_replace (gsi, g, true); - return true; - /* flavors of vec_max. */ - case RS6000_BIF_XVMAXDP: - case RS6000_BIF_XVMAXSP: - case RS6000_BIF_VMAXFP: - { - lhs = gimple_call_lhs (stmt); - tree type = TREE_TYPE (lhs); - if (HONOR_NANS (type)) - return false; - gcc_fallthrough (); - } - case RS6000_BIF_VMAXSD: - case RS6000_BIF_VMAXUD: - case RS6000_BIF_VMAXSB: - case RS6000_BIF_VMAXSH: - case RS6000_BIF_VMAXSW: - case RS6000_BIF_VMAXUB: - case RS6000_BIF_VMAXUH: - case RS6000_BIF_VMAXUW: - arg0 = gimple_call_arg (stmt, 0); - arg1 = gimple_call_arg (stmt, 1); - lhs = gimple_call_lhs (stmt); - g = gimple_build_assign (lhs, MAX_EXPR, arg0, arg1); - gimple_set_location (g, gimple_location (stmt)); - gsi_replace (gsi, g, true); - return true; - /* Flavors of vec_eqv. */ - case RS6000_BIF_EQV_V16QI: - case RS6000_BIF_EQV_V8HI: - case RS6000_BIF_EQV_V4SI: - case RS6000_BIF_EQV_V4SF: - case RS6000_BIF_EQV_V2DF: - case RS6000_BIF_EQV_V2DI: - arg0 = gimple_call_arg (stmt, 0); - arg1 = gimple_call_arg (stmt, 1); - lhs = gimple_call_lhs (stmt); - temp = create_tmp_reg_or_ssa_name (TREE_TYPE (arg1)); - g = gimple_build_assign (temp, BIT_XOR_EXPR, arg0, arg1); - gimple_set_location (g, gimple_location (stmt)); - gsi_insert_before (gsi, g, GSI_SAME_STMT); - g = gimple_build_assign (lhs, BIT_NOT_EXPR, temp); - gimple_set_location (g, gimple_location (stmt)); - gsi_replace (gsi, g, true); - return true; - /* Flavors of vec_rotate_left. */ - case RS6000_BIF_VRLB: - case RS6000_BIF_VRLH: - case RS6000_BIF_VRLW: - case RS6000_BIF_VRLD: - arg0 = gimple_call_arg (stmt, 0); - arg1 = gimple_call_arg (stmt, 1); - lhs = gimple_call_lhs (stmt); - g = gimple_build_assign (lhs, LROTATE_EXPR, arg0, arg1); - gimple_set_location (g, gimple_location (stmt)); - gsi_replace (gsi, g, true); - return true; - /* Flavors of vector shift right algebraic. - vec_sra{b,h,w} -> vsra{b,h,w}. */ - case RS6000_BIF_VSRAB: - case RS6000_BIF_VSRAH: - case RS6000_BIF_VSRAW: - case RS6000_BIF_VSRAD: - { - arg0 = gimple_call_arg (stmt, 0); - arg1 = gimple_call_arg (stmt, 1); - lhs = gimple_call_lhs (stmt); - tree arg1_type = TREE_TYPE (arg1); - tree unsigned_arg1_type = unsigned_type_for (TREE_TYPE (arg1)); - tree unsigned_element_type = unsigned_type_for (TREE_TYPE (arg1_type)); - location_t loc = gimple_location (stmt); - /* Force arg1 into the range valid matching the arg0 type. */ - /* Build a vector consisting of the max valid bit-size values. */ - int n_elts = VECTOR_CST_NELTS (arg1); - tree element_size = build_int_cst (unsigned_element_type, - 128 / n_elts); - tree_vector_builder elts (unsigned_arg1_type, n_elts, 1); - for (int i = 0; i < n_elts; i++) - elts.safe_push (element_size); - tree modulo_tree = elts.build (); - /* Modulo the provided shift value against that vector. */ - gimple_seq stmts = NULL; - tree unsigned_arg1 = gimple_build (&stmts, VIEW_CONVERT_EXPR, - unsigned_arg1_type, arg1); - tree new_arg1 = gimple_build (&stmts, loc, TRUNC_MOD_EXPR, - unsigned_arg1_type, unsigned_arg1, - modulo_tree); - gsi_insert_seq_before (gsi, stmts, GSI_SAME_STMT); - /* And finally, do the shift. */ - g = gimple_build_assign (lhs, RSHIFT_EXPR, arg0, new_arg1); - gimple_set_location (g, loc); - gsi_replace (gsi, g, true); - return true; - } - /* Flavors of vector shift left. - builtin_altivec_vsl{b,h,w} -> vsl{b,h,w}. */ - case RS6000_BIF_VSLB: - case RS6000_BIF_VSLH: - case RS6000_BIF_VSLW: - case RS6000_BIF_VSLD: - { - location_t loc; - gimple_seq stmts = NULL; - arg0 = gimple_call_arg (stmt, 0); - tree arg0_type = TREE_TYPE (arg0); - if (INTEGRAL_TYPE_P (TREE_TYPE (arg0_type)) - && !TYPE_OVERFLOW_WRAPS (TREE_TYPE (arg0_type))) - return false; - arg1 = gimple_call_arg (stmt, 1); - tree arg1_type = TREE_TYPE (arg1); - tree unsigned_arg1_type = unsigned_type_for (TREE_TYPE (arg1)); - tree unsigned_element_type = unsigned_type_for (TREE_TYPE (arg1_type)); - loc = gimple_location (stmt); - lhs = gimple_call_lhs (stmt); - /* Force arg1 into the range valid matching the arg0 type. */ - /* Build a vector consisting of the max valid bit-size values. */ - int n_elts = VECTOR_CST_NELTS (arg1); - int tree_size_in_bits = TREE_INT_CST_LOW (size_in_bytes (arg1_type)) - * BITS_PER_UNIT; - tree element_size = build_int_cst (unsigned_element_type, - tree_size_in_bits / n_elts); - tree_vector_builder elts (unsigned_type_for (arg1_type), n_elts, 1); - for (int i = 0; i < n_elts; i++) - elts.safe_push (element_size); - tree modulo_tree = elts.build (); - /* Modulo the provided shift value against that vector. */ - tree unsigned_arg1 = gimple_build (&stmts, VIEW_CONVERT_EXPR, - unsigned_arg1_type, arg1); - tree new_arg1 = gimple_build (&stmts, loc, TRUNC_MOD_EXPR, - unsigned_arg1_type, unsigned_arg1, - modulo_tree); - gsi_insert_seq_before (gsi, stmts, GSI_SAME_STMT); - /* And finally, do the shift. */ - g = gimple_build_assign (lhs, LSHIFT_EXPR, arg0, new_arg1); - gimple_set_location (g, gimple_location (stmt)); - gsi_replace (gsi, g, true); - return true; - } - /* Flavors of vector shift right. */ - case RS6000_BIF_VSRB: - case RS6000_BIF_VSRH: - case RS6000_BIF_VSRW: - case RS6000_BIF_VSRD: - { - arg0 = gimple_call_arg (stmt, 0); - arg1 = gimple_call_arg (stmt, 1); - lhs = gimple_call_lhs (stmt); - tree arg1_type = TREE_TYPE (arg1); - tree unsigned_arg1_type = unsigned_type_for (TREE_TYPE (arg1)); - tree unsigned_element_type = unsigned_type_for (TREE_TYPE (arg1_type)); - location_t loc = gimple_location (stmt); - gimple_seq stmts = NULL; - /* Convert arg0 to unsigned. */ - tree arg0_unsigned - = gimple_build (&stmts, VIEW_CONVERT_EXPR, - unsigned_type_for (TREE_TYPE (arg0)), arg0); - /* Force arg1 into the range valid matching the arg0 type. */ - /* Build a vector consisting of the max valid bit-size values. */ - int n_elts = VECTOR_CST_NELTS (arg1); - tree element_size = build_int_cst (unsigned_element_type, - 128 / n_elts); - tree_vector_builder elts (unsigned_arg1_type, n_elts, 1); - for (int i = 0; i < n_elts; i++) - elts.safe_push (element_size); - tree modulo_tree = elts.build (); - /* Modulo the provided shift value against that vector. */ - tree unsigned_arg1 = gimple_build (&stmts, VIEW_CONVERT_EXPR, - unsigned_arg1_type, arg1); - tree new_arg1 = gimple_build (&stmts, loc, TRUNC_MOD_EXPR, - unsigned_arg1_type, unsigned_arg1, - modulo_tree); - /* Do the shift. */ - tree res - = gimple_build (&stmts, RSHIFT_EXPR, - TREE_TYPE (arg0_unsigned), arg0_unsigned, new_arg1); - /* Convert result back to the lhs type. */ - res = gimple_build (&stmts, VIEW_CONVERT_EXPR, TREE_TYPE (lhs), res); - gsi_insert_seq_before (gsi, stmts, GSI_SAME_STMT); - replace_call_with_value (gsi, res); - return true; - } - /* Vector loads. */ - case RS6000_BIF_LVX_V16QI: - case RS6000_BIF_LVX_V8HI: - case RS6000_BIF_LVX_V4SI: - case RS6000_BIF_LVX_V4SF: - case RS6000_BIF_LVX_V2DI: - case RS6000_BIF_LVX_V2DF: - case RS6000_BIF_LVX_V1TI: - { - arg0 = gimple_call_arg (stmt, 0); // offset - arg1 = gimple_call_arg (stmt, 1); // address - lhs = gimple_call_lhs (stmt); - location_t loc = gimple_location (stmt); - /* Since arg1 may be cast to a different type, just use ptr_type_node - here instead of trying to enforce TBAA on pointer types. */ - tree arg1_type = ptr_type_node; - tree lhs_type = TREE_TYPE (lhs); - /* POINTER_PLUS_EXPR wants the offset to be of type 'sizetype'. Create - the tree using the value from arg0. The resulting type will match - the type of arg1. */ - gimple_seq stmts = NULL; - tree temp_offset = gimple_convert (&stmts, loc, sizetype, arg0); - tree temp_addr = gimple_build (&stmts, loc, POINTER_PLUS_EXPR, - arg1_type, arg1, temp_offset); - /* Mask off any lower bits from the address. */ - tree aligned_addr = gimple_build (&stmts, loc, BIT_AND_EXPR, - arg1_type, temp_addr, - build_int_cst (arg1_type, -16)); - gsi_insert_seq_before (gsi, stmts, GSI_SAME_STMT); - if (!is_gimple_mem_ref_addr (aligned_addr)) - { - tree t = make_ssa_name (TREE_TYPE (aligned_addr)); - gimple *g = gimple_build_assign (t, aligned_addr); - gsi_insert_before (gsi, g, GSI_SAME_STMT); - aligned_addr = t; - } - /* Use the build2 helper to set up the mem_ref. The MEM_REF could also - take an offset, but since we've already incorporated the offset - above, here we just pass in a zero. */ - gimple *g - = gimple_build_assign (lhs, build2 (MEM_REF, lhs_type, aligned_addr, - build_int_cst (arg1_type, 0))); - gimple_set_location (g, loc); - gsi_replace (gsi, g, true); - return true; - } - /* Vector stores. */ - case RS6000_BIF_STVX_V16QI: - case RS6000_BIF_STVX_V8HI: - case RS6000_BIF_STVX_V4SI: - case RS6000_BIF_STVX_V4SF: - case RS6000_BIF_STVX_V2DI: - case RS6000_BIF_STVX_V2DF: - { - arg0 = gimple_call_arg (stmt, 0); /* Value to be stored. */ - arg1 = gimple_call_arg (stmt, 1); /* Offset. */ - tree arg2 = gimple_call_arg (stmt, 2); /* Store-to address. */ - location_t loc = gimple_location (stmt); - tree arg0_type = TREE_TYPE (arg0); - /* Use ptr_type_node (no TBAA) for the arg2_type. - FIXME: (Richard) "A proper fix would be to transition this type as - seen from the frontend to GIMPLE, for example in a similar way we - do for MEM_REFs by piggy-backing that on an extra argument, a - constant zero pointer of the alias pointer type to use (which would - also serve as a type indicator of the store itself). I'd use a - target specific internal function for this (not sure if we can have - those target specific, but I guess if it's folded away then that's - fine) and get away with the overload set." */ - tree arg2_type = ptr_type_node; - /* POINTER_PLUS_EXPR wants the offset to be of type 'sizetype'. Create - the tree using the value from arg0. The resulting type will match - the type of arg2. */ - gimple_seq stmts = NULL; - tree temp_offset = gimple_convert (&stmts, loc, sizetype, arg1); - tree temp_addr = gimple_build (&stmts, loc, POINTER_PLUS_EXPR, - arg2_type, arg2, temp_offset); - /* Mask off any lower bits from the address. */ - tree aligned_addr = gimple_build (&stmts, loc, BIT_AND_EXPR, - arg2_type, temp_addr, - build_int_cst (arg2_type, -16)); - gsi_insert_seq_before (gsi, stmts, GSI_SAME_STMT); - if (!is_gimple_mem_ref_addr (aligned_addr)) - { - tree t = make_ssa_name (TREE_TYPE (aligned_addr)); - gimple *g = gimple_build_assign (t, aligned_addr); - gsi_insert_before (gsi, g, GSI_SAME_STMT); - aligned_addr = t; - } - /* The desired gimple result should be similar to: - MEM[(__vector floatD.1407 *)_1] = vf1D.2697; */ - gimple *g - = gimple_build_assign (build2 (MEM_REF, arg0_type, aligned_addr, - build_int_cst (arg2_type, 0)), arg0); - gimple_set_location (g, loc); - gsi_replace (gsi, g, true); - return true; - } - - /* unaligned Vector loads. */ - case RS6000_BIF_LXVW4X_V16QI: - case RS6000_BIF_LXVW4X_V8HI: - case RS6000_BIF_LXVW4X_V4SF: - case RS6000_BIF_LXVW4X_V4SI: - case RS6000_BIF_LXVD2X_V2DF: - case RS6000_BIF_LXVD2X_V2DI: - { - arg0 = gimple_call_arg (stmt, 0); // offset - arg1 = gimple_call_arg (stmt, 1); // address - lhs = gimple_call_lhs (stmt); - location_t loc = gimple_location (stmt); - /* Since arg1 may be cast to a different type, just use ptr_type_node - here instead of trying to enforce TBAA on pointer types. */ - tree arg1_type = ptr_type_node; - tree lhs_type = TREE_TYPE (lhs); - /* In GIMPLE the type of the MEM_REF specifies the alignment. The - required alignment (power) is 4 bytes regardless of data type. */ - tree align_ltype = build_aligned_type (lhs_type, 4); - /* POINTER_PLUS_EXPR wants the offset to be of type 'sizetype'. Create - the tree using the value from arg0. The resulting type will match - the type of arg1. */ - gimple_seq stmts = NULL; - tree temp_offset = gimple_convert (&stmts, loc, sizetype, arg0); - tree temp_addr = gimple_build (&stmts, loc, POINTER_PLUS_EXPR, - arg1_type, arg1, temp_offset); - gsi_insert_seq_before (gsi, stmts, GSI_SAME_STMT); - if (!is_gimple_mem_ref_addr (temp_addr)) - { - tree t = make_ssa_name (TREE_TYPE (temp_addr)); - gimple *g = gimple_build_assign (t, temp_addr); - gsi_insert_before (gsi, g, GSI_SAME_STMT); - temp_addr = t; - } - /* Use the build2 helper to set up the mem_ref. The MEM_REF could also - take an offset, but since we've already incorporated the offset - above, here we just pass in a zero. */ - gimple *g; - g = gimple_build_assign (lhs, build2 (MEM_REF, align_ltype, temp_addr, - build_int_cst (arg1_type, 0))); - gimple_set_location (g, loc); - gsi_replace (gsi, g, true); - return true; - } - - /* unaligned Vector stores. */ - case RS6000_BIF_STXVW4X_V16QI: - case RS6000_BIF_STXVW4X_V8HI: - case RS6000_BIF_STXVW4X_V4SF: - case RS6000_BIF_STXVW4X_V4SI: - case RS6000_BIF_STXVD2X_V2DF: - case RS6000_BIF_STXVD2X_V2DI: - { - arg0 = gimple_call_arg (stmt, 0); /* Value to be stored. */ - arg1 = gimple_call_arg (stmt, 1); /* Offset. */ - tree arg2 = gimple_call_arg (stmt, 2); /* Store-to address. */ - location_t loc = gimple_location (stmt); - tree arg0_type = TREE_TYPE (arg0); - /* Use ptr_type_node (no TBAA) for the arg2_type. */ - tree arg2_type = ptr_type_node; - /* In GIMPLE the type of the MEM_REF specifies the alignment. The - required alignment (power) is 4 bytes regardless of data type. */ - tree align_stype = build_aligned_type (arg0_type, 4); - /* POINTER_PLUS_EXPR wants the offset to be of type 'sizetype'. Create - the tree using the value from arg1. */ - gimple_seq stmts = NULL; - tree temp_offset = gimple_convert (&stmts, loc, sizetype, arg1); - tree temp_addr = gimple_build (&stmts, loc, POINTER_PLUS_EXPR, - arg2_type, arg2, temp_offset); - gsi_insert_seq_before (gsi, stmts, GSI_SAME_STMT); - if (!is_gimple_mem_ref_addr (temp_addr)) - { - tree t = make_ssa_name (TREE_TYPE (temp_addr)); - gimple *g = gimple_build_assign (t, temp_addr); - gsi_insert_before (gsi, g, GSI_SAME_STMT); - temp_addr = t; - } - gimple *g; - g = gimple_build_assign (build2 (MEM_REF, align_stype, temp_addr, - build_int_cst (arg2_type, 0)), arg0); - gimple_set_location (g, loc); - gsi_replace (gsi, g, true); - return true; - } - - /* Vector Fused multiply-add (fma). */ - case RS6000_BIF_VMADDFP: - case RS6000_BIF_XVMADDDP: - case RS6000_BIF_XVMADDSP: - case RS6000_BIF_VMLADDUHM: - { - arg0 = gimple_call_arg (stmt, 0); - arg1 = gimple_call_arg (stmt, 1); - tree arg2 = gimple_call_arg (stmt, 2); - lhs = gimple_call_lhs (stmt); - gcall *g = gimple_build_call_internal (IFN_FMA, 3, arg0, arg1, arg2); - gimple_call_set_lhs (g, lhs); - gimple_call_set_nothrow (g, true); - gimple_set_location (g, gimple_location (stmt)); - gsi_replace (gsi, g, true); - return true; - } - - /* Vector compares; EQ, NE, GE, GT, LE. */ - case RS6000_BIF_VCMPEQUB: - case RS6000_BIF_VCMPEQUH: - case RS6000_BIF_VCMPEQUW: - case RS6000_BIF_VCMPEQUD: - /* We deliberately omit RS6000_BIF_VCMPEQUT for now, because gimple - folding produces worse code for 128-bit compares. */ - fold_compare_helper (gsi, EQ_EXPR, stmt); - return true; - - case RS6000_BIF_VCMPNEB: - case RS6000_BIF_VCMPNEH: - case RS6000_BIF_VCMPNEW: - /* We deliberately omit RS6000_BIF_VCMPNET for now, because gimple - folding produces worse code for 128-bit compares. */ - fold_compare_helper (gsi, NE_EXPR, stmt); - return true; - - case RS6000_BIF_CMPGE_16QI: - case RS6000_BIF_CMPGE_U16QI: - case RS6000_BIF_CMPGE_8HI: - case RS6000_BIF_CMPGE_U8HI: - case RS6000_BIF_CMPGE_4SI: - case RS6000_BIF_CMPGE_U4SI: - case RS6000_BIF_CMPGE_2DI: - case RS6000_BIF_CMPGE_U2DI: - /* We deliberately omit RS6000_BIF_CMPGE_1TI and RS6000_BIF_CMPGE_U1TI - for now, because gimple folding produces worse code for 128-bit - compares. */ - fold_compare_helper (gsi, GE_EXPR, stmt); - return true; - - case RS6000_BIF_VCMPGTSB: - case RS6000_BIF_VCMPGTUB: - case RS6000_BIF_VCMPGTSH: - case RS6000_BIF_VCMPGTUH: - case RS6000_BIF_VCMPGTSW: - case RS6000_BIF_VCMPGTUW: - case RS6000_BIF_VCMPGTUD: - case RS6000_BIF_VCMPGTSD: - /* We deliberately omit RS6000_BIF_VCMPGTUT and RS6000_BIF_VCMPGTST - for now, because gimple folding produces worse code for 128-bit - compares. */ - fold_compare_helper (gsi, GT_EXPR, stmt); - return true; - - case RS6000_BIF_CMPLE_16QI: - case RS6000_BIF_CMPLE_U16QI: - case RS6000_BIF_CMPLE_8HI: - case RS6000_BIF_CMPLE_U8HI: - case RS6000_BIF_CMPLE_4SI: - case RS6000_BIF_CMPLE_U4SI: - case RS6000_BIF_CMPLE_2DI: - case RS6000_BIF_CMPLE_U2DI: - /* We deliberately omit RS6000_BIF_CMPLE_1TI and RS6000_BIF_CMPLE_U1TI - for now, because gimple folding produces worse code for 128-bit - compares. */ - fold_compare_helper (gsi, LE_EXPR, stmt); - return true; - - /* flavors of vec_splat_[us]{8,16,32}. */ - case RS6000_BIF_VSPLTISB: - case RS6000_BIF_VSPLTISH: - case RS6000_BIF_VSPLTISW: - { - arg0 = gimple_call_arg (stmt, 0); - lhs = gimple_call_lhs (stmt); - - /* Only fold the vec_splat_*() if the lower bits of arg 0 is a - 5-bit signed constant in range -16 to +15. */ - if (TREE_CODE (arg0) != INTEGER_CST - || !IN_RANGE (TREE_INT_CST_LOW (arg0), -16, 15)) - return false; - gimple_seq stmts = NULL; - location_t loc = gimple_location (stmt); - tree splat_value = gimple_convert (&stmts, loc, - TREE_TYPE (TREE_TYPE (lhs)), arg0); - gsi_insert_seq_before (gsi, stmts, GSI_SAME_STMT); - tree splat_tree = build_vector_from_val (TREE_TYPE (lhs), splat_value); - g = gimple_build_assign (lhs, splat_tree); - gimple_set_location (g, gimple_location (stmt)); - gsi_replace (gsi, g, true); - return true; - } - - /* Flavors of vec_splat. */ - /* a = vec_splat (b, 0x3) becomes a = { b[3],b[3],b[3],...}; */ - case RS6000_BIF_VSPLTB: - case RS6000_BIF_VSPLTH: - case RS6000_BIF_VSPLTW: - case RS6000_BIF_XXSPLTD_V2DI: - case RS6000_BIF_XXSPLTD_V2DF: - { - arg0 = gimple_call_arg (stmt, 0); /* input vector. */ - arg1 = gimple_call_arg (stmt, 1); /* index into arg0. */ - /* Only fold the vec_splat_*() if arg1 is both a constant value and - is a valid index into the arg0 vector. */ - unsigned int n_elts = VECTOR_CST_NELTS (arg0); - if (TREE_CODE (arg1) != INTEGER_CST - || TREE_INT_CST_LOW (arg1) > (n_elts -1)) - return false; - lhs = gimple_call_lhs (stmt); - tree lhs_type = TREE_TYPE (lhs); - tree arg0_type = TREE_TYPE (arg0); - tree splat; - if (TREE_CODE (arg0) == VECTOR_CST) - splat = VECTOR_CST_ELT (arg0, TREE_INT_CST_LOW (arg1)); - else - { - /* Determine (in bits) the length and start location of the - splat value for a call to the tree_vec_extract helper. */ - int splat_elem_size = TREE_INT_CST_LOW (size_in_bytes (arg0_type)) - * BITS_PER_UNIT / n_elts; - int splat_start_bit = TREE_INT_CST_LOW (arg1) * splat_elem_size; - tree len = build_int_cst (bitsizetype, splat_elem_size); - tree start = build_int_cst (bitsizetype, splat_start_bit); - splat = tree_vec_extract (gsi, TREE_TYPE (lhs_type), arg0, - len, start); - } - /* And finally, build the new vector. */ - tree splat_tree = build_vector_from_val (lhs_type, splat); - g = gimple_build_assign (lhs, splat_tree); - gimple_set_location (g, gimple_location (stmt)); - gsi_replace (gsi, g, true); - return true; - } - - /* vec_mergel (integrals). */ - case RS6000_BIF_VMRGLH: - case RS6000_BIF_VMRGLW: - case RS6000_BIF_XXMRGLW_4SI: - case RS6000_BIF_VMRGLB: - case RS6000_BIF_VEC_MERGEL_V2DI: - case RS6000_BIF_XXMRGLW_4SF: - case RS6000_BIF_VEC_MERGEL_V2DF: - fold_mergehl_helper (gsi, stmt, 1); - return true; - /* vec_mergeh (integrals). */ - case RS6000_BIF_VMRGHH: - case RS6000_BIF_VMRGHW: - case RS6000_BIF_XXMRGHW_4SI: - case RS6000_BIF_VMRGHB: - case RS6000_BIF_VEC_MERGEH_V2DI: - case RS6000_BIF_XXMRGHW_4SF: - case RS6000_BIF_VEC_MERGEH_V2DF: - fold_mergehl_helper (gsi, stmt, 0); - return true; - - /* Flavors of vec_mergee. */ - case RS6000_BIF_VMRGEW_V4SI: - case RS6000_BIF_VMRGEW_V2DI: - case RS6000_BIF_VMRGEW_V4SF: - case RS6000_BIF_VMRGEW_V2DF: - fold_mergeeo_helper (gsi, stmt, 0); - return true; - /* Flavors of vec_mergeo. */ - case RS6000_BIF_VMRGOW_V4SI: - case RS6000_BIF_VMRGOW_V2DI: - case RS6000_BIF_VMRGOW_V4SF: - case RS6000_BIF_VMRGOW_V2DF: - fold_mergeeo_helper (gsi, stmt, 1); - return true; - - /* d = vec_pack (a, b) */ - case RS6000_BIF_VPKUDUM: - case RS6000_BIF_VPKUHUM: - case RS6000_BIF_VPKUWUM: - { - arg0 = gimple_call_arg (stmt, 0); - arg1 = gimple_call_arg (stmt, 1); - lhs = gimple_call_lhs (stmt); - gimple *g = gimple_build_assign (lhs, VEC_PACK_TRUNC_EXPR, arg0, arg1); - gimple_set_location (g, gimple_location (stmt)); - gsi_replace (gsi, g, true); - return true; - } - - /* d = vec_unpackh (a) */ - /* Note that the UNPACK_{HI,LO}_EXPR used in the gimple_build_assign call - in this code is sensitive to endian-ness, and needs to be inverted to - handle both LE and BE targets. */ - case RS6000_BIF_VUPKHSB: - case RS6000_BIF_VUPKHSH: - case RS6000_BIF_VUPKHSW: - { - arg0 = gimple_call_arg (stmt, 0); - lhs = gimple_call_lhs (stmt); - if (BYTES_BIG_ENDIAN) - g = gimple_build_assign (lhs, VEC_UNPACK_HI_EXPR, arg0); - else - g = gimple_build_assign (lhs, VEC_UNPACK_LO_EXPR, arg0); - gimple_set_location (g, gimple_location (stmt)); - gsi_replace (gsi, g, true); - return true; - } - /* d = vec_unpackl (a) */ - case RS6000_BIF_VUPKLSB: - case RS6000_BIF_VUPKLSH: - case RS6000_BIF_VUPKLSW: - { - arg0 = gimple_call_arg (stmt, 0); - lhs = gimple_call_lhs (stmt); - if (BYTES_BIG_ENDIAN) - g = gimple_build_assign (lhs, VEC_UNPACK_LO_EXPR, arg0); - else - g = gimple_build_assign (lhs, VEC_UNPACK_HI_EXPR, arg0); - gimple_set_location (g, gimple_location (stmt)); - gsi_replace (gsi, g, true); - return true; - } - /* There is no gimple type corresponding with pixel, so just return. */ - case RS6000_BIF_VUPKHPX: - case RS6000_BIF_VUPKLPX: - return false; - - /* vec_perm. */ - case RS6000_BIF_VPERM_16QI: - case RS6000_BIF_VPERM_8HI: - case RS6000_BIF_VPERM_4SI: - case RS6000_BIF_VPERM_2DI: - case RS6000_BIF_VPERM_4SF: - case RS6000_BIF_VPERM_2DF: - case RS6000_BIF_VPERM_16QI_UNS: - case RS6000_BIF_VPERM_8HI_UNS: - case RS6000_BIF_VPERM_4SI_UNS: - case RS6000_BIF_VPERM_2DI_UNS: - { - arg0 = gimple_call_arg (stmt, 0); - arg1 = gimple_call_arg (stmt, 1); - tree permute = gimple_call_arg (stmt, 2); - lhs = gimple_call_lhs (stmt); - location_t loc = gimple_location (stmt); - gimple_seq stmts = NULL; - // convert arg0 and arg1 to match the type of the permute - // for the VEC_PERM_EXPR operation. - tree permute_type = (TREE_TYPE (permute)); - tree arg0_ptype = gimple_build (&stmts, loc, VIEW_CONVERT_EXPR, - permute_type, arg0); - tree arg1_ptype = gimple_build (&stmts, loc, VIEW_CONVERT_EXPR, - permute_type, arg1); - tree lhs_ptype = gimple_build (&stmts, loc, VEC_PERM_EXPR, - permute_type, arg0_ptype, arg1_ptype, - permute); - // Convert the result back to the desired lhs type upon completion. - tree temp = gimple_build (&stmts, loc, VIEW_CONVERT_EXPR, - TREE_TYPE (lhs), lhs_ptype); - gsi_insert_seq_before (gsi, stmts, GSI_SAME_STMT); - g = gimple_build_assign (lhs, temp); - gimple_set_location (g, loc); - gsi_replace (gsi, g, true); - return true; - } - - default: - if (TARGET_DEBUG_BUILTIN) - fprintf (stderr, "gimple builtin intrinsic not matched:%d %s %s\n", - fn_code, fn_name1, fn_name2); - break; - } - - return false; -} - -/* Expand an expression EXP that calls a built-in function, - with result going to TARGET if that's convenient - (and in mode MODE if that's convenient). - SUBTARGET may be used as the target for computing one of EXP's operands. - IGNORE is nonzero if the value is to be ignored. */ - -rtx -rs6000_expand_builtin (tree exp, rtx target, rtx subtarget ATTRIBUTE_UNUSED, - machine_mode mode ATTRIBUTE_UNUSED, - int ignore ATTRIBUTE_UNUSED) -{ - if (new_builtins_are_live) - return rs6000_expand_new_builtin (exp, target, subtarget, mode, ignore); - - tree fndecl = TREE_OPERAND (CALL_EXPR_FN (exp), 0); - enum rs6000_builtins fcode - = (enum rs6000_builtins) DECL_MD_FUNCTION_CODE (fndecl); - size_t uns_fcode = (size_t)fcode; - const struct builtin_description *d; - size_t i; - rtx ret; - bool success; - HOST_WIDE_INT mask = rs6000_builtin_info[uns_fcode].mask; - bool func_valid_p = ((rs6000_builtin_mask & mask) == mask); - enum insn_code icode = rs6000_builtin_info[uns_fcode].icode; - - /* We have two different modes (KFmode, TFmode) that are the IEEE 128-bit - floating point type, depending on whether long double is the IBM extended - double (KFmode) or long double is IEEE 128-bit (TFmode). It is simpler if - we only define one variant of the built-in function, and switch the code - when defining it, rather than defining two built-ins and using the - overload table in rs6000-c.c to switch between the two. If we don't have - the proper assembler, don't do this switch because CODE_FOR_*kf* and - CODE_FOR_*tf* will be CODE_FOR_nothing. */ - if (FLOAT128_IEEE_P (TFmode)) - switch (icode) - { - default: - break; - - case CODE_FOR_sqrtkf2_odd: icode = CODE_FOR_sqrttf2_odd; break; - case CODE_FOR_trunckfdf2_odd: icode = CODE_FOR_trunctfdf2_odd; break; - case CODE_FOR_addkf3_odd: icode = CODE_FOR_addtf3_odd; break; - case CODE_FOR_subkf3_odd: icode = CODE_FOR_subtf3_odd; break; - case CODE_FOR_mulkf3_odd: icode = CODE_FOR_multf3_odd; break; - case CODE_FOR_divkf3_odd: icode = CODE_FOR_divtf3_odd; break; - case CODE_FOR_fmakf4_odd: icode = CODE_FOR_fmatf4_odd; break; - case CODE_FOR_xsxexpqp_kf: icode = CODE_FOR_xsxexpqp_tf; break; - case CODE_FOR_xsxsigqp_kf: icode = CODE_FOR_xsxsigqp_tf; break; - case CODE_FOR_xststdcnegqp_kf: icode = CODE_FOR_xststdcnegqp_tf; break; - case CODE_FOR_xsiexpqp_kf: icode = CODE_FOR_xsiexpqp_tf; break; - case CODE_FOR_xsiexpqpf_kf: icode = CODE_FOR_xsiexpqpf_tf; break; - case CODE_FOR_xststdcqp_kf: icode = CODE_FOR_xststdcqp_tf; break; - - case CODE_FOR_xscmpexpqp_eq_kf: - icode = CODE_FOR_xscmpexpqp_eq_tf; - break; - - case CODE_FOR_xscmpexpqp_lt_kf: - icode = CODE_FOR_xscmpexpqp_lt_tf; - break; - - case CODE_FOR_xscmpexpqp_gt_kf: - icode = CODE_FOR_xscmpexpqp_gt_tf; - break; - - case CODE_FOR_xscmpexpqp_unordered_kf: - icode = CODE_FOR_xscmpexpqp_unordered_tf; - break; - } - - if (TARGET_DEBUG_BUILTIN) - { - const char *name1 = rs6000_builtin_info[uns_fcode].name; - const char *name2 = (icode != CODE_FOR_nothing) - ? get_insn_name ((int) icode) - : "nothing"; - const char *name3; - - switch (rs6000_builtin_info[uns_fcode].attr & RS6000_BTC_TYPE_MASK) - { - default: name3 = "unknown"; break; - case RS6000_BTC_SPECIAL: name3 = "special"; break; - case RS6000_BTC_UNARY: name3 = "unary"; break; - case RS6000_BTC_BINARY: name3 = "binary"; break; - case RS6000_BTC_TERNARY: name3 = "ternary"; break; - case RS6000_BTC_QUATERNARY:name3 = "quaternary";break; - case RS6000_BTC_PREDICATE: name3 = "predicate"; break; - case RS6000_BTC_ABS: name3 = "abs"; break; - case RS6000_BTC_DST: name3 = "dst"; break; - } - - - fprintf (stderr, - "rs6000_expand_builtin, %s (%d), insn = %s (%d), type=%s%s\n", - (name1) ? name1 : "---", fcode, - (name2) ? name2 : "---", (int) icode, - name3, - func_valid_p ? "" : ", not valid"); - } - - if (!func_valid_p) - { - rs6000_invalid_builtin (fcode); - - /* Given it is invalid, just generate a normal call. */ - return expand_call (exp, target, ignore); - } - - switch (fcode) - { - case RS6000_BUILTIN_RECIP: - return rs6000_expand_binop_builtin (CODE_FOR_recipdf3, exp, target); - - case RS6000_BUILTIN_RECIPF: - return rs6000_expand_binop_builtin (CODE_FOR_recipsf3, exp, target); - - case RS6000_BUILTIN_RSQRTF: - return rs6000_expand_unop_builtin (CODE_FOR_rsqrtsf2, exp, target); - - case RS6000_BUILTIN_RSQRT: - return rs6000_expand_unop_builtin (CODE_FOR_rsqrtdf2, exp, target); - - case POWER7_BUILTIN_BPERMD: - return rs6000_expand_binop_builtin (((TARGET_64BIT) - ? CODE_FOR_bpermd_di - : CODE_FOR_bpermd_si), exp, target); - - case RS6000_BUILTIN_GET_TB: - return rs6000_expand_zeroop_builtin (CODE_FOR_rs6000_get_timebase, - target); - - case RS6000_BUILTIN_MFTB: - return rs6000_expand_zeroop_builtin (((TARGET_64BIT) - ? CODE_FOR_rs6000_mftb_di - : CODE_FOR_rs6000_mftb_si), - target); - - case RS6000_BUILTIN_MFFS: - return rs6000_expand_zeroop_builtin (CODE_FOR_rs6000_mffs, target); - - case RS6000_BUILTIN_MTFSB0: - return rs6000_expand_mtfsb_builtin (CODE_FOR_rs6000_mtfsb0, exp); - - case RS6000_BUILTIN_MTFSB1: - return rs6000_expand_mtfsb_builtin (CODE_FOR_rs6000_mtfsb1, exp); - - case RS6000_BUILTIN_SET_FPSCR_RN: - return rs6000_expand_set_fpscr_rn_builtin (CODE_FOR_rs6000_set_fpscr_rn, - exp); - - case RS6000_BUILTIN_SET_FPSCR_DRN: - return - rs6000_expand_set_fpscr_drn_builtin (CODE_FOR_rs6000_set_fpscr_drn, - exp); - - case RS6000_BUILTIN_MFFSL: - return rs6000_expand_zeroop_builtin (CODE_FOR_rs6000_mffsl, target); - - case RS6000_BUILTIN_MTFSF: - return rs6000_expand_mtfsf_builtin (CODE_FOR_rs6000_mtfsf, exp); - - case RS6000_BUILTIN_CPU_INIT: - case RS6000_BUILTIN_CPU_IS: - case RS6000_BUILTIN_CPU_SUPPORTS: - return cpu_expand_builtin (fcode, exp, target); - - case MISC_BUILTIN_SPEC_BARRIER: - { - emit_insn (gen_speculation_barrier ()); - return NULL_RTX; - } - - case ALTIVEC_BUILTIN_MASK_FOR_LOAD: - { - int icode2 = (BYTES_BIG_ENDIAN ? (int) CODE_FOR_altivec_lvsr_direct - : (int) CODE_FOR_altivec_lvsl_direct); - machine_mode tmode = insn_data[icode2].operand[0].mode; - machine_mode mode = insn_data[icode2].operand[1].mode; - tree arg; - rtx op, addr, pat; - - gcc_assert (TARGET_ALTIVEC); - - arg = CALL_EXPR_ARG (exp, 0); - gcc_assert (POINTER_TYPE_P (TREE_TYPE (arg))); - op = expand_expr (arg, NULL_RTX, Pmode, EXPAND_NORMAL); - addr = memory_address (mode, op); - /* We need to negate the address. */ - op = gen_reg_rtx (GET_MODE (addr)); - emit_insn (gen_rtx_SET (op, gen_rtx_NEG (GET_MODE (addr), addr))); - op = gen_rtx_MEM (mode, op); - - if (target == 0 - || GET_MODE (target) != tmode - || ! (*insn_data[icode2].operand[0].predicate) (target, tmode)) - target = gen_reg_rtx (tmode); - - pat = GEN_FCN (icode2) (target, op); - if (!pat) - return 0; - emit_insn (pat); - - return target; - } - - case ALTIVEC_BUILTIN_VCFUX: - case ALTIVEC_BUILTIN_VCFSX: - case ALTIVEC_BUILTIN_VCTUXS: - case ALTIVEC_BUILTIN_VCTSXS: - /* FIXME: There's got to be a nicer way to handle this case than - constructing a new CALL_EXPR. */ - if (call_expr_nargs (exp) == 1) - { - exp = build_call_nary (TREE_TYPE (exp), CALL_EXPR_FN (exp), - 2, CALL_EXPR_ARG (exp, 0), integer_zero_node); - } - break; - - /* For the pack and unpack int128 routines, fix up the builtin so it - uses the correct IBM128 type. */ - case MISC_BUILTIN_PACK_IF: - if (TARGET_LONG_DOUBLE_128 && !TARGET_IEEEQUAD) - { - icode = CODE_FOR_packtf; - fcode = MISC_BUILTIN_PACK_TF; - uns_fcode = (size_t)fcode; - } - break; - - case MISC_BUILTIN_UNPACK_IF: - if (TARGET_LONG_DOUBLE_128 && !TARGET_IEEEQUAD) - { - icode = CODE_FOR_unpacktf; - fcode = MISC_BUILTIN_UNPACK_TF; - uns_fcode = (size_t)fcode; - } - break; - - default: - break; - } - - if (TARGET_MMA) - { - ret = mma_expand_builtin (exp, target, &success); - - if (success) - return ret; - } - if (TARGET_ALTIVEC) - { - ret = altivec_expand_builtin (exp, target, &success); - - if (success) - return ret; - } - if (TARGET_HTM) - { - ret = htm_expand_builtin (exp, target, &success); - - if (success) - return ret; - } - - unsigned attr = rs6000_builtin_info[uns_fcode].attr & RS6000_BTC_OPND_MASK; - /* RS6000_BTC_SPECIAL represents no-operand operators. */ - gcc_assert (attr == RS6000_BTC_UNARY - || attr == RS6000_BTC_BINARY - || attr == RS6000_BTC_TERNARY - || attr == RS6000_BTC_QUATERNARY - || attr == RS6000_BTC_SPECIAL); - - /* Handle simple unary operations. */ - d = bdesc_1arg; - for (i = 0; i < ARRAY_SIZE (bdesc_1arg); i++, d++) - if (d->code == fcode) - return rs6000_expand_unop_builtin (icode, exp, target); - - /* Handle simple binary operations. */ - d = bdesc_2arg; - for (i = 0; i < ARRAY_SIZE (bdesc_2arg); i++, d++) - if (d->code == fcode) - return rs6000_expand_binop_builtin (icode, exp, target); - - /* Handle simple ternary operations. */ - d = bdesc_3arg; - for (i = 0; i < ARRAY_SIZE (bdesc_3arg); i++, d++) - if (d->code == fcode) - return rs6000_expand_ternop_builtin (icode, exp, target); - - /* Handle simple quaternary operations. */ - d = bdesc_4arg; - for (i = 0; i < ARRAY_SIZE (bdesc_4arg); i++, d++) - if (d->code == fcode) - return rs6000_expand_quaternop_builtin (icode, exp, target); - - /* Handle simple no-argument operations. */ - d = bdesc_0arg; - for (i = 0; i < ARRAY_SIZE (bdesc_0arg); i++, d++) - if (d->code == fcode) - return rs6000_expand_zeroop_builtin (icode, target); - - gcc_unreachable (); -} - -/* Expand ALTIVEC_BUILTIN_MASK_FOR_LOAD. */ -rtx -rs6000_expand_ldst_mask (rtx target, tree arg0) -{ - int icode2 = BYTES_BIG_ENDIAN ? (int) CODE_FOR_altivec_lvsr_direct - : (int) CODE_FOR_altivec_lvsl_direct; - machine_mode tmode = insn_data[icode2].operand[0].mode; - machine_mode mode = insn_data[icode2].operand[1].mode; - - gcc_assert (TARGET_ALTIVEC); - - gcc_assert (POINTER_TYPE_P (TREE_TYPE (arg0))); - rtx op = expand_expr (arg0, NULL_RTX, Pmode, EXPAND_NORMAL); - rtx addr = memory_address (mode, op); - /* We need to negate the address. */ - op = gen_reg_rtx (GET_MODE (addr)); - emit_insn (gen_rtx_SET (op, gen_rtx_NEG (GET_MODE (addr), addr))); - op = gen_rtx_MEM (mode, op); - - if (target == 0 - || GET_MODE (target) != tmode - || !insn_data[icode2].operand[0].predicate (target, tmode)) - target = gen_reg_rtx (tmode); - - rtx pat = GEN_FCN (icode2) (target, op); - if (!pat) - return 0; - emit_insn (pat); - - return target; -} - -/* Expand the CPU builtin in FCODE and store the result in TARGET. */ -static rtx -new_cpu_expand_builtin (enum rs6000_gen_builtins fcode, - tree exp ATTRIBUTE_UNUSED, rtx target) -{ - /* __builtin_cpu_init () is a nop, so expand to nothing. */ - if (fcode == RS6000_BIF_CPU_INIT) - return const0_rtx; - - if (target == 0 || GET_MODE (target) != SImode) - target = gen_reg_rtx (SImode); - - /* TODO: Factor the #ifdef'd code into a separate function. */ -#ifdef TARGET_LIBC_PROVIDES_HWCAP_IN_TCB - tree arg = TREE_OPERAND (CALL_EXPR_ARG (exp, 0), 0); - /* Target clones creates an ARRAY_REF instead of STRING_CST, convert it back - to a STRING_CST. */ - if (TREE_CODE (arg) == ARRAY_REF - && TREE_CODE (TREE_OPERAND (arg, 0)) == STRING_CST - && TREE_CODE (TREE_OPERAND (arg, 1)) == INTEGER_CST - && compare_tree_int (TREE_OPERAND (arg, 1), 0) == 0) - arg = TREE_OPERAND (arg, 0); - - if (TREE_CODE (arg) != STRING_CST) - { - error ("builtin %qs only accepts a string argument", - rs6000_builtin_info_x[(size_t) fcode].bifname); - return const0_rtx; - } - - if (fcode == RS6000_BIF_CPU_IS) - { - const char *cpu = TREE_STRING_POINTER (arg); - rtx cpuid = NULL_RTX; - for (size_t i = 0; i < ARRAY_SIZE (cpu_is_info); i++) - if (strcmp (cpu, cpu_is_info[i].cpu) == 0) - { - /* The CPUID value in the TCB is offset by _DL_FIRST_PLATFORM. */ - cpuid = GEN_INT (cpu_is_info[i].cpuid + _DL_FIRST_PLATFORM); - break; - } - if (cpuid == NULL_RTX) - { - /* Invalid CPU argument. */ - error ("cpu %qs is an invalid argument to builtin %qs", - cpu, rs6000_builtin_info_x[(size_t) fcode].bifname); - return const0_rtx; - } - - rtx platform = gen_reg_rtx (SImode); - rtx address = gen_rtx_PLUS (Pmode, - gen_rtx_REG (Pmode, TLS_REGNUM), - GEN_INT (TCB_PLATFORM_OFFSET)); - rtx tcbmem = gen_const_mem (SImode, address); - emit_move_insn (platform, tcbmem); - emit_insn (gen_eqsi3 (target, platform, cpuid)); - } - else if (fcode == RS6000_BIF_CPU_SUPPORTS) - { - const char *hwcap = TREE_STRING_POINTER (arg); - rtx mask = NULL_RTX; - int hwcap_offset; - for (size_t i = 0; i < ARRAY_SIZE (cpu_supports_info); i++) - if (strcmp (hwcap, cpu_supports_info[i].hwcap) == 0) - { - mask = GEN_INT (cpu_supports_info[i].mask); - hwcap_offset = TCB_HWCAP_OFFSET (cpu_supports_info[i].id); - break; - } - if (mask == NULL_RTX) - { - /* Invalid HWCAP argument. */ - error ("%s %qs is an invalid argument to builtin %qs", - "hwcap", hwcap, - rs6000_builtin_info_x[(size_t) fcode].bifname); - return const0_rtx; - } - - rtx tcb_hwcap = gen_reg_rtx (SImode); - rtx address = gen_rtx_PLUS (Pmode, - gen_rtx_REG (Pmode, TLS_REGNUM), - GEN_INT (hwcap_offset)); - rtx tcbmem = gen_const_mem (SImode, address); - emit_move_insn (tcb_hwcap, tcbmem); - rtx scratch1 = gen_reg_rtx (SImode); - emit_insn (gen_rtx_SET (scratch1, - gen_rtx_AND (SImode, tcb_hwcap, mask))); - rtx scratch2 = gen_reg_rtx (SImode); - emit_insn (gen_eqsi3 (scratch2, scratch1, const0_rtx)); - emit_insn (gen_rtx_SET (target, - gen_rtx_XOR (SImode, scratch2, const1_rtx))); - } - else - gcc_unreachable (); - - /* Record that we have expanded a CPU builtin, so that we can later - emit a reference to the special symbol exported by LIBC to ensure we - do not link against an old LIBC that doesn't support this feature. */ - cpu_builtin_p = true; - -#else - warning (0, "builtin %qs needs GLIBC (2.23 and newer) that exports hardware " - "capability bits", rs6000_builtin_info_x[(size_t) fcode].bifname); - - /* For old LIBCs, always return FALSE. */ - emit_move_insn (target, GEN_INT (0)); -#endif /* TARGET_LIBC_PROVIDES_HWCAP_IN_TCB */ - - return target; -} - -/* For the element-reversing load/store built-ins, produce the correct - insn_code depending on the target endianness. */ -static insn_code -elemrev_icode (rs6000_gen_builtins fcode) -{ - switch (fcode) - { - case RS6000_BIF_ST_ELEMREV_V1TI: - return BYTES_BIG_ENDIAN ? CODE_FOR_vsx_store_v1ti - : CODE_FOR_vsx_st_elemrev_v1ti; - - case RS6000_BIF_ST_ELEMREV_V2DF: - return BYTES_BIG_ENDIAN ? CODE_FOR_vsx_store_v2df - : CODE_FOR_vsx_st_elemrev_v2df; - - case RS6000_BIF_ST_ELEMREV_V2DI: - return BYTES_BIG_ENDIAN ? CODE_FOR_vsx_store_v2di - : CODE_FOR_vsx_st_elemrev_v2di; - - case RS6000_BIF_ST_ELEMREV_V4SF: - return BYTES_BIG_ENDIAN ? CODE_FOR_vsx_store_v4sf - : CODE_FOR_vsx_st_elemrev_v4sf; - - case RS6000_BIF_ST_ELEMREV_V4SI: - return BYTES_BIG_ENDIAN ? CODE_FOR_vsx_store_v4si - : CODE_FOR_vsx_st_elemrev_v4si; - - case RS6000_BIF_ST_ELEMREV_V8HI: - return BYTES_BIG_ENDIAN ? CODE_FOR_vsx_store_v8hi - : CODE_FOR_vsx_st_elemrev_v8hi; - - case RS6000_BIF_ST_ELEMREV_V16QI: - return BYTES_BIG_ENDIAN ? CODE_FOR_vsx_store_v16qi - : CODE_FOR_vsx_st_elemrev_v16qi; - - case RS6000_BIF_LD_ELEMREV_V2DF: - return BYTES_BIG_ENDIAN ? CODE_FOR_vsx_load_v2df - : CODE_FOR_vsx_ld_elemrev_v2df; - - case RS6000_BIF_LD_ELEMREV_V1TI: - return BYTES_BIG_ENDIAN ? CODE_FOR_vsx_load_v1ti - : CODE_FOR_vsx_ld_elemrev_v1ti; - - case RS6000_BIF_LD_ELEMREV_V2DI: - return BYTES_BIG_ENDIAN ? CODE_FOR_vsx_load_v2di - : CODE_FOR_vsx_ld_elemrev_v2di; - - case RS6000_BIF_LD_ELEMREV_V4SF: - return BYTES_BIG_ENDIAN ? CODE_FOR_vsx_load_v4sf - : CODE_FOR_vsx_ld_elemrev_v4sf; - - case RS6000_BIF_LD_ELEMREV_V4SI: - return BYTES_BIG_ENDIAN ? CODE_FOR_vsx_load_v4si - : CODE_FOR_vsx_ld_elemrev_v4si; - - case RS6000_BIF_LD_ELEMREV_V8HI: - return BYTES_BIG_ENDIAN ? CODE_FOR_vsx_load_v8hi - : CODE_FOR_vsx_ld_elemrev_v8hi; - - case RS6000_BIF_LD_ELEMREV_V16QI: - return BYTES_BIG_ENDIAN ? CODE_FOR_vsx_load_v16qi - : CODE_FOR_vsx_ld_elemrev_v16qi; - default: - ; - } - - gcc_unreachable (); -} - -/* Expand an AltiVec vector load builtin, and return the expanded rtx. */ -static rtx -ldv_expand_builtin (rtx target, insn_code icode, rtx *op, machine_mode tmode) -{ - if (target == 0 - || GET_MODE (target) != tmode - || !insn_data[icode].operand[0].predicate (target, tmode)) - target = gen_reg_rtx (tmode); - - op[1] = copy_to_mode_reg (Pmode, op[1]); - - /* These CELL built-ins use BLKmode instead of tmode for historical - (i.e., unknown) reasons. TODO: Is this necessary? */ - bool blk = (icode == CODE_FOR_altivec_lvlx - || icode == CODE_FOR_altivec_lvlxl - || icode == CODE_FOR_altivec_lvrx - || icode == CODE_FOR_altivec_lvrxl); - - /* For LVX, express the RTL accurately by ANDing the address with -16. - LVXL and LVE*X expand to use UNSPECs to hide their special behavior, - so the raw address is fine. */ - /* TODO: That statement seems wrong, as the UNSPECs don't surround the - memory expression, so a latent bug may lie here. The &-16 is likely - needed for all VMX-style loads. */ - if (icode == CODE_FOR_altivec_lvx_v1ti - || icode == CODE_FOR_altivec_lvx_v2df - || icode == CODE_FOR_altivec_lvx_v2di - || icode == CODE_FOR_altivec_lvx_v4sf - || icode == CODE_FOR_altivec_lvx_v4si - || icode == CODE_FOR_altivec_lvx_v8hi - || icode == CODE_FOR_altivec_lvx_v16qi) - { - rtx rawaddr; - if (op[0] == const0_rtx) - rawaddr = op[1]; - else - { - op[0] = copy_to_mode_reg (Pmode, op[0]); - rawaddr = gen_rtx_PLUS (Pmode, op[1], op[0]); - } - rtx addr = gen_rtx_AND (Pmode, rawaddr, gen_rtx_CONST_INT (Pmode, -16)); - addr = gen_rtx_MEM (blk ? BLKmode : tmode, addr); - - emit_insn (gen_rtx_SET (target, addr)); - } - else - { - rtx addr; - if (op[0] == const0_rtx) - addr = gen_rtx_MEM (blk ? BLKmode : tmode, op[1]); - else - { - op[0] = copy_to_mode_reg (Pmode, op[0]); - addr = gen_rtx_MEM (blk ? BLKmode : tmode, - gen_rtx_PLUS (Pmode, op[1], op[0])); - } - - rtx pat = GEN_FCN (icode) (target, addr); - if (!pat) - return 0; - emit_insn (pat); - } - - return target; -} - -/* Expand a builtin function that loads a scalar into a vector register - with sign extension, and return the expanded rtx. */ -static rtx -lxvrse_expand_builtin (rtx target, insn_code icode, rtx *op, - machine_mode tmode, machine_mode smode) -{ - rtx pat, addr; - op[1] = copy_to_mode_reg (Pmode, op[1]); - - if (op[0] == const0_rtx) - addr = gen_rtx_MEM (tmode, op[1]); - else - { - op[0] = copy_to_mode_reg (Pmode, op[0]); - addr = gen_rtx_MEM (smode, - gen_rtx_PLUS (Pmode, op[1], op[0])); - } - - rtx discratch = gen_reg_rtx (V2DImode); - rtx tiscratch = gen_reg_rtx (TImode); - - /* Emit the lxvr*x insn. */ - pat = GEN_FCN (icode) (tiscratch, addr); - if (!pat) - return 0; - emit_insn (pat); - - /* Emit a sign extension from V16QI,V8HI,V4SI to V2DI. */ - rtx temp1; - if (icode == CODE_FOR_vsx_lxvrbx) - { - temp1 = simplify_gen_subreg (V16QImode, tiscratch, TImode, 0); - emit_insn (gen_vsx_sign_extend_qi_v2di (discratch, temp1)); - } - else if (icode == CODE_FOR_vsx_lxvrhx) - { - temp1 = simplify_gen_subreg (V8HImode, tiscratch, TImode, 0); - emit_insn (gen_vsx_sign_extend_hi_v2di (discratch, temp1)); - } - else if (icode == CODE_FOR_vsx_lxvrwx) - { - temp1 = simplify_gen_subreg (V4SImode, tiscratch, TImode, 0); - emit_insn (gen_vsx_sign_extend_si_v2di (discratch, temp1)); - } - else if (icode == CODE_FOR_vsx_lxvrdx) - discratch = simplify_gen_subreg (V2DImode, tiscratch, TImode, 0); - else - gcc_unreachable (); - - /* Emit the sign extension from V2DI (double) to TI (quad). */ - rtx temp2 = simplify_gen_subreg (TImode, discratch, V2DImode, 0); - emit_insn (gen_extendditi2_vector (target, temp2)); - - return target; -} - -/* Expand a builtin function that loads a scalar into a vector register - with zero extension, and return the expanded rtx. */ -static rtx -lxvrze_expand_builtin (rtx target, insn_code icode, rtx *op, - machine_mode tmode, machine_mode smode) -{ - rtx pat, addr; - op[1] = copy_to_mode_reg (Pmode, op[1]); - - if (op[0] == const0_rtx) - addr = gen_rtx_MEM (tmode, op[1]); - else - { - op[0] = copy_to_mode_reg (Pmode, op[0]); - addr = gen_rtx_MEM (smode, - gen_rtx_PLUS (Pmode, op[1], op[0])); - } - - pat = GEN_FCN (icode) (target, addr); - if (!pat) - return 0; - emit_insn (pat); - return target; -} - -/* Expand an AltiVec vector store builtin, and return the expanded rtx. */ -static rtx -stv_expand_builtin (insn_code icode, rtx *op, - machine_mode tmode, machine_mode smode) -{ - op[2] = copy_to_mode_reg (Pmode, op[2]); - - /* For STVX, express the RTL accurately by ANDing the address with -16. - STVXL and STVE*X expand to use UNSPECs to hide their special behavior, - so the raw address is fine. */ - /* TODO: That statement seems wrong, as the UNSPECs don't surround the - memory expression, so a latent bug may lie here. The &-16 is likely - needed for all VMX-style stores. */ - if (icode == CODE_FOR_altivec_stvx_v2df - || icode == CODE_FOR_altivec_stvx_v2di - || icode == CODE_FOR_altivec_stvx_v4sf - || icode == CODE_FOR_altivec_stvx_v4si - || icode == CODE_FOR_altivec_stvx_v8hi - || icode == CODE_FOR_altivec_stvx_v16qi) - { - rtx rawaddr; - if (op[1] == const0_rtx) - rawaddr = op[2]; - else - { - op[1] = copy_to_mode_reg (Pmode, op[1]); - rawaddr = gen_rtx_PLUS (Pmode, op[2], op[1]); - } - - rtx addr = gen_rtx_AND (Pmode, rawaddr, gen_rtx_CONST_INT (Pmode, -16)); - addr = gen_rtx_MEM (tmode, addr); - op[0] = copy_to_mode_reg (tmode, op[0]); - emit_insn (gen_rtx_SET (addr, op[0])); - } - else if (icode == CODE_FOR_vsx_stxvrbx - || icode == CODE_FOR_vsx_stxvrhx - || icode == CODE_FOR_vsx_stxvrwx - || icode == CODE_FOR_vsx_stxvrdx) - { - rtx truncrtx = gen_rtx_TRUNCATE (tmode, op[0]); - op[0] = copy_to_mode_reg (E_TImode, truncrtx); - - rtx addr; - if (op[1] == const0_rtx) - addr = gen_rtx_MEM (Pmode, op[2]); - else - { - op[1] = copy_to_mode_reg (Pmode, op[1]); - addr = gen_rtx_MEM (tmode, gen_rtx_PLUS (Pmode, op[2], op[1])); - } - rtx pat = GEN_FCN (icode) (addr, op[0]); - if (pat) - emit_insn (pat); - } - else - { - if (!insn_data[icode].operand[1].predicate (op[0], smode)) - op[0] = copy_to_mode_reg (smode, op[0]); - - rtx addr; - if (op[1] == const0_rtx) - addr = gen_rtx_MEM (tmode, op[2]); - else - { - op[1] = copy_to_mode_reg (Pmode, op[1]); - addr = gen_rtx_MEM (tmode, gen_rtx_PLUS (Pmode, op[2], op[1])); - } - - rtx pat = GEN_FCN (icode) (addr, op[0]); - if (pat) - emit_insn (pat); - } - - return NULL_RTX; -} - -/* Expand the MMA built-in in EXP, and return it. */ -static rtx -new_mma_expand_builtin (tree exp, rtx target, insn_code icode, - rs6000_gen_builtins fcode) -{ - tree fndecl = TREE_OPERAND (CALL_EXPR_FN (exp), 0); - bool void_func = TREE_TYPE (TREE_TYPE (fndecl)) == void_type_node; - machine_mode tmode = VOIDmode; - rtx op[MAX_MMA_OPERANDS]; - unsigned nopnds = 0; - - if (!void_func) - { - tmode = insn_data[icode].operand[0].mode; - if (!(target - && GET_MODE (target) == tmode - && insn_data[icode].operand[0].predicate (target, tmode))) - target = gen_reg_rtx (tmode); - op[nopnds++] = target; - } - else - target = const0_rtx; - - call_expr_arg_iterator iter; - tree arg; - FOR_EACH_CALL_EXPR_ARG (arg, iter, exp) - { - if (arg == error_mark_node) - return const0_rtx; - - rtx opnd; - const struct insn_operand_data *insn_op; - insn_op = &insn_data[icode].operand[nopnds]; - if (TREE_CODE (arg) == ADDR_EXPR - && MEM_P (DECL_RTL (TREE_OPERAND (arg, 0)))) - opnd = DECL_RTL (TREE_OPERAND (arg, 0)); - else - opnd = expand_normal (arg); - - if (!insn_op->predicate (opnd, insn_op->mode)) - { - /* TODO: This use of constraints needs explanation. */ - if (!strcmp (insn_op->constraint, "n")) - { - if (!CONST_INT_P (opnd)) - error ("argument %d must be an unsigned literal", nopnds); - else - error ("argument %d is an unsigned literal that is " - "out of range", nopnds); - return const0_rtx; - } - opnd = copy_to_mode_reg (insn_op->mode, opnd); - } - - /* Some MMA instructions have INOUT accumulator operands, so force - their target register to be the same as their input register. */ - if (!void_func - && nopnds == 1 - && !strcmp (insn_op->constraint, "0") - && insn_op->mode == tmode - && REG_P (opnd) - && insn_data[icode].operand[0].predicate (opnd, tmode)) - target = op[0] = opnd; - - op[nopnds++] = opnd; - } - - rtx pat; - switch (nopnds) - { - case 1: - pat = GEN_FCN (icode) (op[0]); - break; - case 2: - pat = GEN_FCN (icode) (op[0], op[1]); - break; - case 3: - /* The ASSEMBLE builtin source operands are reversed in little-endian - mode, so reorder them. */ - if (fcode == RS6000_BIF_ASSEMBLE_PAIR_V_INTERNAL && !WORDS_BIG_ENDIAN) - std::swap (op[1], op[2]); - pat = GEN_FCN (icode) (op[0], op[1], op[2]); - break; - case 4: - pat = GEN_FCN (icode) (op[0], op[1], op[2], op[3]); - break; - case 5: - /* The ASSEMBLE builtin source operands are reversed in little-endian - mode, so reorder them. */ - if (fcode == RS6000_BIF_ASSEMBLE_ACC_INTERNAL && !WORDS_BIG_ENDIAN) - { - std::swap (op[1], op[4]); - std::swap (op[2], op[3]); - } - pat = GEN_FCN (icode) (op[0], op[1], op[2], op[3], op[4]); - break; - case 6: - pat = GEN_FCN (icode) (op[0], op[1], op[2], op[3], op[4], op[5]); - break; - case 7: - pat = GEN_FCN (icode) (op[0], op[1], op[2], op[3], op[4], op[5], op[6]); - break; - default: - gcc_unreachable (); - } - - if (!pat) - return NULL_RTX; - - emit_insn (pat); - return target; -} - -/* Return the appropriate SPR number associated with the given builtin. */ -static inline HOST_WIDE_INT -new_htm_spr_num (enum rs6000_gen_builtins code) -{ - if (code == RS6000_BIF_GET_TFHAR - || code == RS6000_BIF_SET_TFHAR) - return TFHAR_SPR; - else if (code == RS6000_BIF_GET_TFIAR - || code == RS6000_BIF_SET_TFIAR) - return TFIAR_SPR; - else if (code == RS6000_BIF_GET_TEXASR - || code == RS6000_BIF_SET_TEXASR) - return TEXASR_SPR; - gcc_assert (code == RS6000_BIF_GET_TEXASRU - || code == RS6000_BIF_SET_TEXASRU); - return TEXASRU_SPR; -} - -/* Expand the HTM builtin in EXP and store the result in TARGET. - Return the expanded rtx. */ -static rtx -new_htm_expand_builtin (bifdata *bifaddr, rs6000_gen_builtins fcode, - tree exp, rtx target) -{ - if (!TARGET_POWERPC64 - && (fcode == RS6000_BIF_TABORTDC - || fcode == RS6000_BIF_TABORTDCI)) - { - error ("builtin %qs is only valid in 64-bit mode", bifaddr->bifname); - return const0_rtx; - } - - tree fndecl = TREE_OPERAND (CALL_EXPR_FN (exp), 0); - bool nonvoid = TREE_TYPE (TREE_TYPE (fndecl)) != void_type_node; - bool uses_spr = bif_is_htmspr (*bifaddr); - insn_code icode = bifaddr->icode; - - if (uses_spr) - icode = rs6000_htm_spr_icode (nonvoid); - - rtx op[MAX_HTM_OPERANDS]; - int nopnds = 0; - const insn_operand_data *insn_op = &insn_data[icode].operand[0]; - - if (nonvoid) - { - machine_mode tmode = (uses_spr) ? insn_op->mode : E_SImode; - if (!target - || GET_MODE (target) != tmode - || (uses_spr && !insn_op->predicate (target, tmode))) - target = gen_reg_rtx (tmode); - if (uses_spr) - op[nopnds++] = target; - } - - tree arg; - call_expr_arg_iterator iter; - - FOR_EACH_CALL_EXPR_ARG (arg, iter, exp) - { - if (arg == error_mark_node || nopnds >= MAX_HTM_OPERANDS) - return const0_rtx; - - insn_op = &insn_data[icode].operand[nopnds]; - op[nopnds] = expand_normal (arg); - - if (!insn_op->predicate (op[nopnds], insn_op->mode)) - { - /* TODO: This use of constraints could use explanation. - This happens a couple of places, perhaps make that a - function to document what's happening. */ - if (!strcmp (insn_op->constraint, "n")) - { - int arg_num = nonvoid ? nopnds : nopnds + 1; - if (!CONST_INT_P (op[nopnds])) - error ("argument %d must be an unsigned literal", arg_num); - else - error ("argument %d is an unsigned literal that is " - "out of range", arg_num); - return const0_rtx; - } - op[nopnds] = copy_to_mode_reg (insn_op->mode, op[nopnds]); - } - - nopnds++; - } - - /* Handle the builtins for extended mnemonics. These accept - no arguments, but map to builtins that take arguments. */ - switch (fcode) - { - case RS6000_BIF_TENDALL: /* Alias for: tend. 1 */ - case RS6000_BIF_TRESUME: /* Alias for: tsr. 1 */ - op[nopnds++] = GEN_INT (1); - break; - case RS6000_BIF_TSUSPEND: /* Alias for: tsr. 0 */ - op[nopnds++] = GEN_INT (0); - break; - default: - break; - } + arg1 = gimple_call_arg (stmt, 1); + lhs = gimple_call_lhs (stmt); + g = gimple_build_assign (lhs, LROTATE_EXPR, arg0, arg1); + gimple_set_location (g, gimple_location (stmt)); + gsi_replace (gsi, g, true); + return true; + /* Flavors of vector shift right algebraic. + vec_sra{b,h,w} -> vsra{b,h,w}. */ + case RS6000_BIF_VSRAB: + case RS6000_BIF_VSRAH: + case RS6000_BIF_VSRAW: + case RS6000_BIF_VSRAD: + { + arg0 = gimple_call_arg (stmt, 0); + arg1 = gimple_call_arg (stmt, 1); + lhs = gimple_call_lhs (stmt); + tree arg1_type = TREE_TYPE (arg1); + tree unsigned_arg1_type = unsigned_type_for (TREE_TYPE (arg1)); + tree unsigned_element_type = unsigned_type_for (TREE_TYPE (arg1_type)); + location_t loc = gimple_location (stmt); + /* Force arg1 into the range valid matching the arg0 type. */ + /* Build a vector consisting of the max valid bit-size values. */ + int n_elts = VECTOR_CST_NELTS (arg1); + tree element_size = build_int_cst (unsigned_element_type, + 128 / n_elts); + tree_vector_builder elts (unsigned_arg1_type, n_elts, 1); + for (int i = 0; i < n_elts; i++) + elts.safe_push (element_size); + tree modulo_tree = elts.build (); + /* Modulo the provided shift value against that vector. */ + gimple_seq stmts = NULL; + tree unsigned_arg1 = gimple_build (&stmts, VIEW_CONVERT_EXPR, + unsigned_arg1_type, arg1); + tree new_arg1 = gimple_build (&stmts, loc, TRUNC_MOD_EXPR, + unsigned_arg1_type, unsigned_arg1, + modulo_tree); + gsi_insert_seq_before (gsi, stmts, GSI_SAME_STMT); + /* And finally, do the shift. */ + g = gimple_build_assign (lhs, RSHIFT_EXPR, arg0, new_arg1); + gimple_set_location (g, loc); + gsi_replace (gsi, g, true); + return true; + } + /* Flavors of vector shift left. + builtin_altivec_vsl{b,h,w} -> vsl{b,h,w}. */ + case RS6000_BIF_VSLB: + case RS6000_BIF_VSLH: + case RS6000_BIF_VSLW: + case RS6000_BIF_VSLD: + { + location_t loc; + gimple_seq stmts = NULL; + arg0 = gimple_call_arg (stmt, 0); + tree arg0_type = TREE_TYPE (arg0); + if (INTEGRAL_TYPE_P (TREE_TYPE (arg0_type)) + && !TYPE_OVERFLOW_WRAPS (TREE_TYPE (arg0_type))) + return false; + arg1 = gimple_call_arg (stmt, 1); + tree arg1_type = TREE_TYPE (arg1); + tree unsigned_arg1_type = unsigned_type_for (TREE_TYPE (arg1)); + tree unsigned_element_type = unsigned_type_for (TREE_TYPE (arg1_type)); + loc = gimple_location (stmt); + lhs = gimple_call_lhs (stmt); + /* Force arg1 into the range valid matching the arg0 type. */ + /* Build a vector consisting of the max valid bit-size values. */ + int n_elts = VECTOR_CST_NELTS (arg1); + int tree_size_in_bits = TREE_INT_CST_LOW (size_in_bytes (arg1_type)) + * BITS_PER_UNIT; + tree element_size = build_int_cst (unsigned_element_type, + tree_size_in_bits / n_elts); + tree_vector_builder elts (unsigned_type_for (arg1_type), n_elts, 1); + for (int i = 0; i < n_elts; i++) + elts.safe_push (element_size); + tree modulo_tree = elts.build (); + /* Modulo the provided shift value against that vector. */ + tree unsigned_arg1 = gimple_build (&stmts, VIEW_CONVERT_EXPR, + unsigned_arg1_type, arg1); + tree new_arg1 = gimple_build (&stmts, loc, TRUNC_MOD_EXPR, + unsigned_arg1_type, unsigned_arg1, + modulo_tree); + gsi_insert_seq_before (gsi, stmts, GSI_SAME_STMT); + /* And finally, do the shift. */ + g = gimple_build_assign (lhs, LSHIFT_EXPR, arg0, new_arg1); + gimple_set_location (g, gimple_location (stmt)); + gsi_replace (gsi, g, true); + return true; + } + /* Flavors of vector shift right. */ + case RS6000_BIF_VSRB: + case RS6000_BIF_VSRH: + case RS6000_BIF_VSRW: + case RS6000_BIF_VSRD: + { + arg0 = gimple_call_arg (stmt, 0); + arg1 = gimple_call_arg (stmt, 1); + lhs = gimple_call_lhs (stmt); + tree arg1_type = TREE_TYPE (arg1); + tree unsigned_arg1_type = unsigned_type_for (TREE_TYPE (arg1)); + tree unsigned_element_type = unsigned_type_for (TREE_TYPE (arg1_type)); + location_t loc = gimple_location (stmt); + gimple_seq stmts = NULL; + /* Convert arg0 to unsigned. */ + tree arg0_unsigned + = gimple_build (&stmts, VIEW_CONVERT_EXPR, + unsigned_type_for (TREE_TYPE (arg0)), arg0); + /* Force arg1 into the range valid matching the arg0 type. */ + /* Build a vector consisting of the max valid bit-size values. */ + int n_elts = VECTOR_CST_NELTS (arg1); + tree element_size = build_int_cst (unsigned_element_type, + 128 / n_elts); + tree_vector_builder elts (unsigned_arg1_type, n_elts, 1); + for (int i = 0; i < n_elts; i++) + elts.safe_push (element_size); + tree modulo_tree = elts.build (); + /* Modulo the provided shift value against that vector. */ + tree unsigned_arg1 = gimple_build (&stmts, VIEW_CONVERT_EXPR, + unsigned_arg1_type, arg1); + tree new_arg1 = gimple_build (&stmts, loc, TRUNC_MOD_EXPR, + unsigned_arg1_type, unsigned_arg1, + modulo_tree); + /* Do the shift. */ + tree res + = gimple_build (&stmts, RSHIFT_EXPR, + TREE_TYPE (arg0_unsigned), arg0_unsigned, new_arg1); + /* Convert result back to the lhs type. */ + res = gimple_build (&stmts, VIEW_CONVERT_EXPR, TREE_TYPE (lhs), res); + gsi_insert_seq_before (gsi, stmts, GSI_SAME_STMT); + replace_call_with_value (gsi, res); + return true; + } + /* Vector loads. */ + case RS6000_BIF_LVX_V16QI: + case RS6000_BIF_LVX_V8HI: + case RS6000_BIF_LVX_V4SI: + case RS6000_BIF_LVX_V4SF: + case RS6000_BIF_LVX_V2DI: + case RS6000_BIF_LVX_V2DF: + case RS6000_BIF_LVX_V1TI: + { + arg0 = gimple_call_arg (stmt, 0); // offset + arg1 = gimple_call_arg (stmt, 1); // address + lhs = gimple_call_lhs (stmt); + location_t loc = gimple_location (stmt); + /* Since arg1 may be cast to a different type, just use ptr_type_node + here instead of trying to enforce TBAA on pointer types. */ + tree arg1_type = ptr_type_node; + tree lhs_type = TREE_TYPE (lhs); + /* POINTER_PLUS_EXPR wants the offset to be of type 'sizetype'. Create + the tree using the value from arg0. The resulting type will match + the type of arg1. */ + gimple_seq stmts = NULL; + tree temp_offset = gimple_convert (&stmts, loc, sizetype, arg0); + tree temp_addr = gimple_build (&stmts, loc, POINTER_PLUS_EXPR, + arg1_type, arg1, temp_offset); + /* Mask off any lower bits from the address. */ + tree aligned_addr = gimple_build (&stmts, loc, BIT_AND_EXPR, + arg1_type, temp_addr, + build_int_cst (arg1_type, -16)); + gsi_insert_seq_before (gsi, stmts, GSI_SAME_STMT); + if (!is_gimple_mem_ref_addr (aligned_addr)) + { + tree t = make_ssa_name (TREE_TYPE (aligned_addr)); + gimple *g = gimple_build_assign (t, aligned_addr); + gsi_insert_before (gsi, g, GSI_SAME_STMT); + aligned_addr = t; + } + /* Use the build2 helper to set up the mem_ref. The MEM_REF could also + take an offset, but since we've already incorporated the offset + above, here we just pass in a zero. */ + gimple *g + = gimple_build_assign (lhs, build2 (MEM_REF, lhs_type, aligned_addr, + build_int_cst (arg1_type, 0))); + gimple_set_location (g, loc); + gsi_replace (gsi, g, true); + return true; + } + /* Vector stores. */ + case RS6000_BIF_STVX_V16QI: + case RS6000_BIF_STVX_V8HI: + case RS6000_BIF_STVX_V4SI: + case RS6000_BIF_STVX_V4SF: + case RS6000_BIF_STVX_V2DI: + case RS6000_BIF_STVX_V2DF: + { + arg0 = gimple_call_arg (stmt, 0); /* Value to be stored. */ + arg1 = gimple_call_arg (stmt, 1); /* Offset. */ + tree arg2 = gimple_call_arg (stmt, 2); /* Store-to address. */ + location_t loc = gimple_location (stmt); + tree arg0_type = TREE_TYPE (arg0); + /* Use ptr_type_node (no TBAA) for the arg2_type. + FIXME: (Richard) "A proper fix would be to transition this type as + seen from the frontend to GIMPLE, for example in a similar way we + do for MEM_REFs by piggy-backing that on an extra argument, a + constant zero pointer of the alias pointer type to use (which would + also serve as a type indicator of the store itself). I'd use a + target specific internal function for this (not sure if we can have + those target specific, but I guess if it's folded away then that's + fine) and get away with the overload set." */ + tree arg2_type = ptr_type_node; + /* POINTER_PLUS_EXPR wants the offset to be of type 'sizetype'. Create + the tree using the value from arg0. The resulting type will match + the type of arg2. */ + gimple_seq stmts = NULL; + tree temp_offset = gimple_convert (&stmts, loc, sizetype, arg1); + tree temp_addr = gimple_build (&stmts, loc, POINTER_PLUS_EXPR, + arg2_type, arg2, temp_offset); + /* Mask off any lower bits from the address. */ + tree aligned_addr = gimple_build (&stmts, loc, BIT_AND_EXPR, + arg2_type, temp_addr, + build_int_cst (arg2_type, -16)); + gsi_insert_seq_before (gsi, stmts, GSI_SAME_STMT); + if (!is_gimple_mem_ref_addr (aligned_addr)) + { + tree t = make_ssa_name (TREE_TYPE (aligned_addr)); + gimple *g = gimple_build_assign (t, aligned_addr); + gsi_insert_before (gsi, g, GSI_SAME_STMT); + aligned_addr = t; + } + /* The desired gimple result should be similar to: + MEM[(__vector floatD.1407 *)_1] = vf1D.2697; */ + gimple *g + = gimple_build_assign (build2 (MEM_REF, arg0_type, aligned_addr, + build_int_cst (arg2_type, 0)), arg0); + gimple_set_location (g, loc); + gsi_replace (gsi, g, true); + return true; + } - /* If this builtin accesses SPRs, then pass in the appropriate - SPR number and SPR regno as the last two operands. */ - rtx cr = NULL_RTX; - if (uses_spr) - { - machine_mode mode = TARGET_POWERPC64 ? DImode : SImode; - op[nopnds++] = gen_rtx_CONST_INT (mode, new_htm_spr_num (fcode)); - } - /* If this builtin accesses a CR field, then pass in a scratch - CR field as the last operand. */ - else if (bif_is_htmcr (*bifaddr)) - { - cr = gen_reg_rtx (CCmode); - op[nopnds++] = cr; - } + /* unaligned Vector loads. */ + case RS6000_BIF_LXVW4X_V16QI: + case RS6000_BIF_LXVW4X_V8HI: + case RS6000_BIF_LXVW4X_V4SF: + case RS6000_BIF_LXVW4X_V4SI: + case RS6000_BIF_LXVD2X_V2DF: + case RS6000_BIF_LXVD2X_V2DI: + { + arg0 = gimple_call_arg (stmt, 0); // offset + arg1 = gimple_call_arg (stmt, 1); // address + lhs = gimple_call_lhs (stmt); + location_t loc = gimple_location (stmt); + /* Since arg1 may be cast to a different type, just use ptr_type_node + here instead of trying to enforce TBAA on pointer types. */ + tree arg1_type = ptr_type_node; + tree lhs_type = TREE_TYPE (lhs); + /* In GIMPLE the type of the MEM_REF specifies the alignment. The + required alignment (power) is 4 bytes regardless of data type. */ + tree align_ltype = build_aligned_type (lhs_type, 4); + /* POINTER_PLUS_EXPR wants the offset to be of type 'sizetype'. Create + the tree using the value from arg0. The resulting type will match + the type of arg1. */ + gimple_seq stmts = NULL; + tree temp_offset = gimple_convert (&stmts, loc, sizetype, arg0); + tree temp_addr = gimple_build (&stmts, loc, POINTER_PLUS_EXPR, + arg1_type, arg1, temp_offset); + gsi_insert_seq_before (gsi, stmts, GSI_SAME_STMT); + if (!is_gimple_mem_ref_addr (temp_addr)) + { + tree t = make_ssa_name (TREE_TYPE (temp_addr)); + gimple *g = gimple_build_assign (t, temp_addr); + gsi_insert_before (gsi, g, GSI_SAME_STMT); + temp_addr = t; + } + /* Use the build2 helper to set up the mem_ref. The MEM_REF could also + take an offset, but since we've already incorporated the offset + above, here we just pass in a zero. */ + gimple *g; + g = gimple_build_assign (lhs, build2 (MEM_REF, align_ltype, temp_addr, + build_int_cst (arg1_type, 0))); + gimple_set_location (g, loc); + gsi_replace (gsi, g, true); + return true; + } - rtx pat; - switch (nopnds) - { - case 1: - pat = GEN_FCN (icode) (op[0]); - break; - case 2: - pat = GEN_FCN (icode) (op[0], op[1]); - break; - case 3: - pat = GEN_FCN (icode) (op[0], op[1], op[2]); - break; - case 4: - pat = GEN_FCN (icode) (op[0], op[1], op[2], op[3]); - break; - default: - gcc_unreachable (); - } - if (!pat) - return NULL_RTX; - emit_insn (pat); + /* unaligned Vector stores. */ + case RS6000_BIF_STXVW4X_V16QI: + case RS6000_BIF_STXVW4X_V8HI: + case RS6000_BIF_STXVW4X_V4SF: + case RS6000_BIF_STXVW4X_V4SI: + case RS6000_BIF_STXVD2X_V2DF: + case RS6000_BIF_STXVD2X_V2DI: + { + arg0 = gimple_call_arg (stmt, 0); /* Value to be stored. */ + arg1 = gimple_call_arg (stmt, 1); /* Offset. */ + tree arg2 = gimple_call_arg (stmt, 2); /* Store-to address. */ + location_t loc = gimple_location (stmt); + tree arg0_type = TREE_TYPE (arg0); + /* Use ptr_type_node (no TBAA) for the arg2_type. */ + tree arg2_type = ptr_type_node; + /* In GIMPLE the type of the MEM_REF specifies the alignment. The + required alignment (power) is 4 bytes regardless of data type. */ + tree align_stype = build_aligned_type (arg0_type, 4); + /* POINTER_PLUS_EXPR wants the offset to be of type 'sizetype'. Create + the tree using the value from arg1. */ + gimple_seq stmts = NULL; + tree temp_offset = gimple_convert (&stmts, loc, sizetype, arg1); + tree temp_addr = gimple_build (&stmts, loc, POINTER_PLUS_EXPR, + arg2_type, arg2, temp_offset); + gsi_insert_seq_before (gsi, stmts, GSI_SAME_STMT); + if (!is_gimple_mem_ref_addr (temp_addr)) + { + tree t = make_ssa_name (TREE_TYPE (temp_addr)); + gimple *g = gimple_build_assign (t, temp_addr); + gsi_insert_before (gsi, g, GSI_SAME_STMT); + temp_addr = t; + } + gimple *g; + g = gimple_build_assign (build2 (MEM_REF, align_stype, temp_addr, + build_int_cst (arg2_type, 0)), arg0); + gimple_set_location (g, loc); + gsi_replace (gsi, g, true); + return true; + } - if (bif_is_htmcr (*bifaddr)) - { - if (fcode == RS6000_BIF_TBEGIN) - { - /* Emit code to set TARGET to true or false depending on - whether the tbegin. instruction succeeded or failed - to start a transaction. We do this by placing the 1's - complement of CR's EQ bit into TARGET. */ - rtx scratch = gen_reg_rtx (SImode); - emit_insn (gen_rtx_SET (scratch, - gen_rtx_EQ (SImode, cr, - const0_rtx))); - emit_insn (gen_rtx_SET (target, - gen_rtx_XOR (SImode, scratch, - GEN_INT (1)))); - } - else - { - /* Emit code to copy the 4-bit condition register field - CR into the least significant end of register TARGET. */ - rtx scratch1 = gen_reg_rtx (SImode); - rtx scratch2 = gen_reg_rtx (SImode); - rtx subreg = simplify_gen_subreg (CCmode, scratch1, SImode, 0); - emit_insn (gen_movcc (subreg, cr)); - emit_insn (gen_lshrsi3 (scratch2, scratch1, GEN_INT (28))); - emit_insn (gen_andsi3 (target, scratch2, GEN_INT (0xf))); - } - } + /* Vector Fused multiply-add (fma). */ + case RS6000_BIF_VMADDFP: + case RS6000_BIF_XVMADDDP: + case RS6000_BIF_XVMADDSP: + case RS6000_BIF_VMLADDUHM: + { + arg0 = gimple_call_arg (stmt, 0); + arg1 = gimple_call_arg (stmt, 1); + tree arg2 = gimple_call_arg (stmt, 2); + lhs = gimple_call_lhs (stmt); + gcall *g = gimple_build_call_internal (IFN_FMA, 3, arg0, arg1, arg2); + gimple_call_set_lhs (g, lhs); + gimple_call_set_nothrow (g, true); + gimple_set_location (g, gimple_location (stmt)); + gsi_replace (gsi, g, true); + return true; + } - if (nonvoid) - return target; - return const0_rtx; -} + /* Vector compares; EQ, NE, GE, GT, LE. */ + case RS6000_BIF_VCMPEQUB: + case RS6000_BIF_VCMPEQUH: + case RS6000_BIF_VCMPEQUW: + case RS6000_BIF_VCMPEQUD: + /* We deliberately omit RS6000_BIF_VCMPEQUT for now, because gimple + folding produces worse code for 128-bit compares. */ + fold_compare_helper (gsi, EQ_EXPR, stmt); + return true; -/* Expand an expression EXP that calls a built-in function, - with result going to TARGET if that's convenient - (and in mode MODE if that's convenient). - SUBTARGET may be used as the target for computing one of EXP's operands. - IGNORE is nonzero if the value is to be ignored. - Use the new builtin infrastructure. */ -static rtx -rs6000_expand_new_builtin (tree exp, rtx target, - rtx /* subtarget */, - machine_mode /* mode */, - int ignore) -{ - tree fndecl = TREE_OPERAND (CALL_EXPR_FN (exp), 0); - enum rs6000_gen_builtins fcode - = (enum rs6000_gen_builtins) DECL_MD_FUNCTION_CODE (fndecl); - size_t uns_fcode = (size_t)fcode; - enum insn_code icode = rs6000_builtin_info_x[uns_fcode].icode; + case RS6000_BIF_VCMPNEB: + case RS6000_BIF_VCMPNEH: + case RS6000_BIF_VCMPNEW: + /* We deliberately omit RS6000_BIF_VCMPNET for now, because gimple + folding produces worse code for 128-bit compares. */ + fold_compare_helper (gsi, NE_EXPR, stmt); + return true; - /* TODO: The following commentary and code is inherited from the original - builtin processing code. The commentary is a bit confusing, with the - intent being that KFmode is always IEEE-128, IFmode is always IBM - double-double, and TFmode is the current long double. The code is - confusing in that it converts from KFmode to TFmode pattern names, - when the other direction is more intuitive. Try to address this. */ + case RS6000_BIF_CMPGE_16QI: + case RS6000_BIF_CMPGE_U16QI: + case RS6000_BIF_CMPGE_8HI: + case RS6000_BIF_CMPGE_U8HI: + case RS6000_BIF_CMPGE_4SI: + case RS6000_BIF_CMPGE_U4SI: + case RS6000_BIF_CMPGE_2DI: + case RS6000_BIF_CMPGE_U2DI: + /* We deliberately omit RS6000_BIF_CMPGE_1TI and RS6000_BIF_CMPGE_U1TI + for now, because gimple folding produces worse code for 128-bit + compares. */ + fold_compare_helper (gsi, GE_EXPR, stmt); + return true; - /* We have two different modes (KFmode, TFmode) that are the IEEE - 128-bit floating point type, depending on whether long double is the - IBM extended double (KFmode) or long double is IEEE 128-bit (TFmode). - It is simpler if we only define one variant of the built-in function, - and switch the code when defining it, rather than defining two built- - ins and using the overload table in rs6000-c.c to switch between the - two. If we don't have the proper assembler, don't do this switch - because CODE_FOR_*kf* and CODE_FOR_*tf* will be CODE_FOR_nothing. */ - if (FLOAT128_IEEE_P (TFmode)) - switch (icode) - { - case CODE_FOR_sqrtkf2_odd: - icode = CODE_FOR_sqrttf2_odd; - break; - case CODE_FOR_trunckfdf2_odd: - icode = CODE_FOR_trunctfdf2_odd; - break; - case CODE_FOR_addkf3_odd: - icode = CODE_FOR_addtf3_odd; - break; - case CODE_FOR_subkf3_odd: - icode = CODE_FOR_subtf3_odd; - break; - case CODE_FOR_mulkf3_odd: - icode = CODE_FOR_multf3_odd; - break; - case CODE_FOR_divkf3_odd: - icode = CODE_FOR_divtf3_odd; - break; - case CODE_FOR_fmakf4_odd: - icode = CODE_FOR_fmatf4_odd; - break; - case CODE_FOR_xsxexpqp_kf: - icode = CODE_FOR_xsxexpqp_tf; - break; - case CODE_FOR_xsxsigqp_kf: - icode = CODE_FOR_xsxsigqp_tf; - break; - case CODE_FOR_xststdcnegqp_kf: - icode = CODE_FOR_xststdcnegqp_tf; - break; - case CODE_FOR_xsiexpqp_kf: - icode = CODE_FOR_xsiexpqp_tf; - break; - case CODE_FOR_xsiexpqpf_kf: - icode = CODE_FOR_xsiexpqpf_tf; - break; - case CODE_FOR_xststdcqp_kf: - icode = CODE_FOR_xststdcqp_tf; - break; - case CODE_FOR_xscmpexpqp_eq_kf: - icode = CODE_FOR_xscmpexpqp_eq_tf; - break; - case CODE_FOR_xscmpexpqp_lt_kf: - icode = CODE_FOR_xscmpexpqp_lt_tf; - break; - case CODE_FOR_xscmpexpqp_gt_kf: - icode = CODE_FOR_xscmpexpqp_gt_tf; - break; - case CODE_FOR_xscmpexpqp_unordered_kf: - icode = CODE_FOR_xscmpexpqp_unordered_tf; - break; - default: - break; + case RS6000_BIF_VCMPGTSB: + case RS6000_BIF_VCMPGTUB: + case RS6000_BIF_VCMPGTSH: + case RS6000_BIF_VCMPGTUH: + case RS6000_BIF_VCMPGTSW: + case RS6000_BIF_VCMPGTUW: + case RS6000_BIF_VCMPGTUD: + case RS6000_BIF_VCMPGTSD: + /* We deliberately omit RS6000_BIF_VCMPGTUT and RS6000_BIF_VCMPGTST + for now, because gimple folding produces worse code for 128-bit + compares. */ + fold_compare_helper (gsi, GT_EXPR, stmt); + return true; + + case RS6000_BIF_CMPLE_16QI: + case RS6000_BIF_CMPLE_U16QI: + case RS6000_BIF_CMPLE_8HI: + case RS6000_BIF_CMPLE_U8HI: + case RS6000_BIF_CMPLE_4SI: + case RS6000_BIF_CMPLE_U4SI: + case RS6000_BIF_CMPLE_2DI: + case RS6000_BIF_CMPLE_U2DI: + /* We deliberately omit RS6000_BIF_CMPLE_1TI and RS6000_BIF_CMPLE_U1TI + for now, because gimple folding produces worse code for 128-bit + compares. */ + fold_compare_helper (gsi, LE_EXPR, stmt); + return true; + + /* flavors of vec_splat_[us]{8,16,32}. */ + case RS6000_BIF_VSPLTISB: + case RS6000_BIF_VSPLTISH: + case RS6000_BIF_VSPLTISW: + { + arg0 = gimple_call_arg (stmt, 0); + lhs = gimple_call_lhs (stmt); + + /* Only fold the vec_splat_*() if the lower bits of arg 0 is a + 5-bit signed constant in range -16 to +15. */ + if (TREE_CODE (arg0) != INTEGER_CST + || !IN_RANGE (TREE_INT_CST_LOW (arg0), -16, 15)) + return false; + gimple_seq stmts = NULL; + location_t loc = gimple_location (stmt); + tree splat_value = gimple_convert (&stmts, loc, + TREE_TYPE (TREE_TYPE (lhs)), arg0); + gsi_insert_seq_before (gsi, stmts, GSI_SAME_STMT); + tree splat_tree = build_vector_from_val (TREE_TYPE (lhs), splat_value); + g = gimple_build_assign (lhs, splat_tree); + gimple_set_location (g, gimple_location (stmt)); + gsi_replace (gsi, g, true); + return true; } - /* In case of "#pragma target" changes, we initialize all builtins - but check for actual availability now, during expand time. For - invalid builtins, generate a normal call. */ - bifdata *bifaddr = &rs6000_builtin_info_x[uns_fcode]; - bif_enable e = bifaddr->enable; + /* Flavors of vec_splat. */ + /* a = vec_splat (b, 0x3) becomes a = { b[3],b[3],b[3],...}; */ + case RS6000_BIF_VSPLTB: + case RS6000_BIF_VSPLTH: + case RS6000_BIF_VSPLTW: + case RS6000_BIF_XXSPLTD_V2DI: + case RS6000_BIF_XXSPLTD_V2DF: + { + arg0 = gimple_call_arg (stmt, 0); /* input vector. */ + arg1 = gimple_call_arg (stmt, 1); /* index into arg0. */ + /* Only fold the vec_splat_*() if arg1 is both a constant value and + is a valid index into the arg0 vector. */ + unsigned int n_elts = VECTOR_CST_NELTS (arg0); + if (TREE_CODE (arg1) != INTEGER_CST + || TREE_INT_CST_LOW (arg1) > (n_elts -1)) + return false; + lhs = gimple_call_lhs (stmt); + tree lhs_type = TREE_TYPE (lhs); + tree arg0_type = TREE_TYPE (arg0); + tree splat; + if (TREE_CODE (arg0) == VECTOR_CST) + splat = VECTOR_CST_ELT (arg0, TREE_INT_CST_LOW (arg1)); + else + { + /* Determine (in bits) the length and start location of the + splat value for a call to the tree_vec_extract helper. */ + int splat_elem_size = TREE_INT_CST_LOW (size_in_bytes (arg0_type)) + * BITS_PER_UNIT / n_elts; + int splat_start_bit = TREE_INT_CST_LOW (arg1) * splat_elem_size; + tree len = build_int_cst (bitsizetype, splat_elem_size); + tree start = build_int_cst (bitsizetype, splat_start_bit); + splat = tree_vec_extract (gsi, TREE_TYPE (lhs_type), arg0, + len, start); + } + /* And finally, build the new vector. */ + tree splat_tree = build_vector_from_val (lhs_type, splat); + g = gimple_build_assign (lhs, splat_tree); + gimple_set_location (g, gimple_location (stmt)); + gsi_replace (gsi, g, true); + return true; + } - if (!(e == ENB_ALWAYS - || (e == ENB_P5 && TARGET_POPCNTB) - || (e == ENB_P6 && TARGET_CMPB) - || (e == ENB_P6_64 && TARGET_CMPB && TARGET_POWERPC64) - || (e == ENB_ALTIVEC && TARGET_ALTIVEC) - || (e == ENB_CELL && TARGET_ALTIVEC && rs6000_cpu == PROCESSOR_CELL) - || (e == ENB_VSX && TARGET_VSX) - || (e == ENB_P7 && TARGET_POPCNTD) - || (e == ENB_P7_64 && TARGET_POPCNTD && TARGET_POWERPC64) - || (e == ENB_P8 && TARGET_DIRECT_MOVE) - || (e == ENB_P8V && TARGET_P8_VECTOR) - || (e == ENB_P9 && TARGET_MODULO) - || (e == ENB_P9_64 && TARGET_MODULO && TARGET_POWERPC64) - || (e == ENB_P9V && TARGET_P9_VECTOR) - || (e == ENB_IEEE128_HW && TARGET_FLOAT128_HW) - || (e == ENB_DFP && TARGET_DFP) - || (e == ENB_CRYPTO && TARGET_CRYPTO) - || (e == ENB_HTM && TARGET_HTM) - || (e == ENB_P10 && TARGET_POWER10) - || (e == ENB_P10_64 && TARGET_POWER10 && TARGET_POWERPC64) - || (e == ENB_MMA && TARGET_MMA))) - { - rs6000_invalid_new_builtin (fcode); - return expand_call (exp, target, ignore); - } + /* vec_mergel (integrals). */ + case RS6000_BIF_VMRGLH: + case RS6000_BIF_VMRGLW: + case RS6000_BIF_XXMRGLW_4SI: + case RS6000_BIF_VMRGLB: + case RS6000_BIF_VEC_MERGEL_V2DI: + case RS6000_BIF_XXMRGLW_4SF: + case RS6000_BIF_VEC_MERGEL_V2DF: + fold_mergehl_helper (gsi, stmt, 1); + return true; + /* vec_mergeh (integrals). */ + case RS6000_BIF_VMRGHH: + case RS6000_BIF_VMRGHW: + case RS6000_BIF_XXMRGHW_4SI: + case RS6000_BIF_VMRGHB: + case RS6000_BIF_VEC_MERGEH_V2DI: + case RS6000_BIF_XXMRGHW_4SF: + case RS6000_BIF_VEC_MERGEH_V2DF: + fold_mergehl_helper (gsi, stmt, 0); + return true; - if (bif_is_nosoft (*bifaddr) - && rs6000_isa_flags & OPTION_MASK_SOFT_FLOAT) - { - error ("%<%s%> not supported with %<-msoft-float%>", - bifaddr->bifname); - return const0_rtx; - } + /* Flavors of vec_mergee. */ + case RS6000_BIF_VMRGEW_V4SI: + case RS6000_BIF_VMRGEW_V2DI: + case RS6000_BIF_VMRGEW_V4SF: + case RS6000_BIF_VMRGEW_V2DF: + fold_mergeeo_helper (gsi, stmt, 0); + return true; + /* Flavors of vec_mergeo. */ + case RS6000_BIF_VMRGOW_V4SI: + case RS6000_BIF_VMRGOW_V2DI: + case RS6000_BIF_VMRGOW_V4SF: + case RS6000_BIF_VMRGOW_V2DF: + fold_mergeeo_helper (gsi, stmt, 1); + return true; - if (bif_is_no32bit (*bifaddr) && TARGET_32BIT) - { - error ("%<%s%> is not supported in 32-bit mode", bifaddr->bifname); - return const0_rtx; - } + /* d = vec_pack (a, b) */ + case RS6000_BIF_VPKUDUM: + case RS6000_BIF_VPKUHUM: + case RS6000_BIF_VPKUWUM: + { + arg0 = gimple_call_arg (stmt, 0); + arg1 = gimple_call_arg (stmt, 1); + lhs = gimple_call_lhs (stmt); + gimple *g = gimple_build_assign (lhs, VEC_PACK_TRUNC_EXPR, arg0, arg1); + gimple_set_location (g, gimple_location (stmt)); + gsi_replace (gsi, g, true); + return true; + } - if (bif_is_ibmld (*bifaddr) && !FLOAT128_2REG_P (TFmode)) - { - error ("%<%s%> requires % to be IBM 128-bit format", - bifaddr->bifname); - return const0_rtx; - } + /* d = vec_unpackh (a) */ + /* Note that the UNPACK_{HI,LO}_EXPR used in the gimple_build_assign call + in this code is sensitive to endian-ness, and needs to be inverted to + handle both LE and BE targets. */ + case RS6000_BIF_VUPKHSB: + case RS6000_BIF_VUPKHSH: + case RS6000_BIF_VUPKHSW: + { + arg0 = gimple_call_arg (stmt, 0); + lhs = gimple_call_lhs (stmt); + if (BYTES_BIG_ENDIAN) + g = gimple_build_assign (lhs, VEC_UNPACK_HI_EXPR, arg0); + else + g = gimple_build_assign (lhs, VEC_UNPACK_LO_EXPR, arg0); + gimple_set_location (g, gimple_location (stmt)); + gsi_replace (gsi, g, true); + return true; + } + /* d = vec_unpackl (a) */ + case RS6000_BIF_VUPKLSB: + case RS6000_BIF_VUPKLSH: + case RS6000_BIF_VUPKLSW: + { + arg0 = gimple_call_arg (stmt, 0); + lhs = gimple_call_lhs (stmt); + if (BYTES_BIG_ENDIAN) + g = gimple_build_assign (lhs, VEC_UNPACK_LO_EXPR, arg0); + else + g = gimple_build_assign (lhs, VEC_UNPACK_HI_EXPR, arg0); + gimple_set_location (g, gimple_location (stmt)); + gsi_replace (gsi, g, true); + return true; + } + /* There is no gimple type corresponding with pixel, so just return. */ + case RS6000_BIF_VUPKHPX: + case RS6000_BIF_VUPKLPX: + return false; - if (bif_is_cpu (*bifaddr)) - return new_cpu_expand_builtin (fcode, exp, target); + /* vec_perm. */ + case RS6000_BIF_VPERM_16QI: + case RS6000_BIF_VPERM_8HI: + case RS6000_BIF_VPERM_4SI: + case RS6000_BIF_VPERM_2DI: + case RS6000_BIF_VPERM_4SF: + case RS6000_BIF_VPERM_2DF: + case RS6000_BIF_VPERM_16QI_UNS: + case RS6000_BIF_VPERM_8HI_UNS: + case RS6000_BIF_VPERM_4SI_UNS: + case RS6000_BIF_VPERM_2DI_UNS: + { + arg0 = gimple_call_arg (stmt, 0); + arg1 = gimple_call_arg (stmt, 1); + tree permute = gimple_call_arg (stmt, 2); + lhs = gimple_call_lhs (stmt); + location_t loc = gimple_location (stmt); + gimple_seq stmts = NULL; + // convert arg0 and arg1 to match the type of the permute + // for the VEC_PERM_EXPR operation. + tree permute_type = (TREE_TYPE (permute)); + tree arg0_ptype = gimple_build (&stmts, loc, VIEW_CONVERT_EXPR, + permute_type, arg0); + tree arg1_ptype = gimple_build (&stmts, loc, VIEW_CONVERT_EXPR, + permute_type, arg1); + tree lhs_ptype = gimple_build (&stmts, loc, VEC_PERM_EXPR, + permute_type, arg0_ptype, arg1_ptype, + permute); + // Convert the result back to the desired lhs type upon completion. + tree temp = gimple_build (&stmts, loc, VIEW_CONVERT_EXPR, + TREE_TYPE (lhs), lhs_ptype); + gsi_insert_seq_before (gsi, stmts, GSI_SAME_STMT); + g = gimple_build_assign (lhs, temp); + gimple_set_location (g, loc); + gsi_replace (gsi, g, true); + return true; + } - if (bif_is_init (*bifaddr)) - return altivec_expand_vec_init_builtin (TREE_TYPE (exp), exp, target); + default: + if (TARGET_DEBUG_BUILTIN) + fprintf (stderr, "gimple builtin intrinsic not matched:%d %s %s\n", + fn_code, fn_name1, fn_name2); + break; + } - if (bif_is_set (*bifaddr)) - return altivec_expand_vec_set_builtin (exp); + return false; +} - if (bif_is_extract (*bifaddr)) - return altivec_expand_vec_ext_builtin (exp, target); +/* Expand an expression EXP that calls a built-in function, + with result going to TARGET if that's convenient + (and in mode MODE if that's convenient). + SUBTARGET may be used as the target for computing one of EXP's operands. + IGNORE is nonzero if the value is to be ignored. */ - if (bif_is_predicate (*bifaddr)) - return altivec_expand_predicate_builtin (icode, exp, target); +rtx +rs6000_expand_builtin (tree exp, rtx target, rtx subtarget ATTRIBUTE_UNUSED, + machine_mode mode ATTRIBUTE_UNUSED, + int ignore ATTRIBUTE_UNUSED) +{ + return rs6000_expand_new_builtin (exp, target, subtarget, mode, ignore); +} - if (bif_is_htm (*bifaddr)) - return new_htm_expand_builtin (bifaddr, fcode, exp, target); +/* Expand ALTIVEC_BUILTIN_MASK_FOR_LOAD. */ +rtx +rs6000_expand_ldst_mask (rtx target, tree arg0) +{ + int icode2 = BYTES_BIG_ENDIAN ? (int) CODE_FOR_altivec_lvsr_direct + : (int) CODE_FOR_altivec_lvsl_direct; + machine_mode tmode = insn_data[icode2].operand[0].mode; + machine_mode mode = insn_data[icode2].operand[1].mode; - if (bif_is_32bit (*bifaddr) && TARGET_32BIT) - { - if (fcode == RS6000_BIF_MFTB) - icode = CODE_FOR_rs6000_mftb_si; - else if (fcode == RS6000_BIF_BPERMD) - icode = CODE_FOR_bpermd_si; - else - gcc_unreachable (); - } + gcc_assert (TARGET_ALTIVEC); - if (bif_is_endian (*bifaddr) && BYTES_BIG_ENDIAN) - { - if (fcode == RS6000_BIF_LD_ELEMREV_V1TI) - icode = CODE_FOR_vsx_load_v1ti; - else if (fcode == RS6000_BIF_LD_ELEMREV_V2DF) - icode = CODE_FOR_vsx_load_v2df; - else if (fcode == RS6000_BIF_LD_ELEMREV_V2DI) - icode = CODE_FOR_vsx_load_v2di; - else if (fcode == RS6000_BIF_LD_ELEMREV_V4SF) - icode = CODE_FOR_vsx_load_v4sf; - else if (fcode == RS6000_BIF_LD_ELEMREV_V4SI) - icode = CODE_FOR_vsx_load_v4si; - else if (fcode == RS6000_BIF_LD_ELEMREV_V8HI) - icode = CODE_FOR_vsx_load_v8hi; - else if (fcode == RS6000_BIF_LD_ELEMREV_V16QI) - icode = CODE_FOR_vsx_load_v16qi; - else if (fcode == RS6000_BIF_ST_ELEMREV_V1TI) - icode = CODE_FOR_vsx_store_v1ti; - else if (fcode == RS6000_BIF_ST_ELEMREV_V2DF) - icode = CODE_FOR_vsx_store_v2df; - else if (fcode == RS6000_BIF_ST_ELEMREV_V2DI) - icode = CODE_FOR_vsx_store_v2di; - else if (fcode == RS6000_BIF_ST_ELEMREV_V4SF) - icode = CODE_FOR_vsx_store_v4sf; - else if (fcode == RS6000_BIF_ST_ELEMREV_V4SI) - icode = CODE_FOR_vsx_store_v4si; - else if (fcode == RS6000_BIF_ST_ELEMREV_V8HI) - icode = CODE_FOR_vsx_store_v8hi; - else if (fcode == RS6000_BIF_ST_ELEMREV_V16QI) - icode = CODE_FOR_vsx_store_v16qi; - else - gcc_unreachable (); - } + gcc_assert (POINTER_TYPE_P (TREE_TYPE (arg0))); + rtx op = expand_expr (arg0, NULL_RTX, Pmode, EXPAND_NORMAL); + rtx addr = memory_address (mode, op); + /* We need to negate the address. */ + op = gen_reg_rtx (GET_MODE (addr)); + emit_insn (gen_rtx_SET (op, gen_rtx_NEG (GET_MODE (addr), addr))); + op = gen_rtx_MEM (mode, op); + if (target == 0 + || GET_MODE (target) != tmode + || !insn_data[icode2].operand[0].predicate (target, tmode)) + target = gen_reg_rtx (tmode); - /* TRUE iff the built-in function returns void. */ - bool void_func = TREE_TYPE (TREE_TYPE (fndecl)) == void_type_node; - /* Position of first argument (0 for void-returning functions, else 1). */ - int k; - /* Modes for the return value, if any, and arguments. */ - const int MAX_BUILTIN_ARGS = 6; - machine_mode mode[MAX_BUILTIN_ARGS + 1]; + rtx pat = GEN_FCN (icode2) (target, op); + if (!pat) + return 0; + emit_insn (pat); - if (void_func) - k = 0; - else - { - k = 1; - mode[0] = insn_data[icode].operand[0].mode; - } + return target; +} - /* Tree expressions for each argument. */ - tree arg[MAX_BUILTIN_ARGS]; - /* RTL expressions for each argument. */ - rtx op[MAX_BUILTIN_ARGS]; +/* Expand the CPU builtin in FCODE and store the result in TARGET. */ +static rtx +new_cpu_expand_builtin (enum rs6000_gen_builtins fcode, + tree exp ATTRIBUTE_UNUSED, rtx target) +{ + /* __builtin_cpu_init () is a nop, so expand to nothing. */ + if (fcode == RS6000_BIF_CPU_INIT) + return const0_rtx; - int nargs = bifaddr->nargs; - gcc_assert (nargs <= MAX_BUILTIN_ARGS); + if (target == 0 || GET_MODE (target) != SImode) + target = gen_reg_rtx (SImode); + /* TODO: Factor the #ifdef'd code into a separate function. */ +#ifdef TARGET_LIBC_PROVIDES_HWCAP_IN_TCB + tree arg = TREE_OPERAND (CALL_EXPR_ARG (exp, 0), 0); + /* Target clones creates an ARRAY_REF instead of STRING_CST, convert it back + to a STRING_CST. */ + if (TREE_CODE (arg) == ARRAY_REF + && TREE_CODE (TREE_OPERAND (arg, 0)) == STRING_CST + && TREE_CODE (TREE_OPERAND (arg, 1)) == INTEGER_CST + && compare_tree_int (TREE_OPERAND (arg, 1), 0) == 0) + arg = TREE_OPERAND (arg, 0); - for (int i = 0; i < nargs; i++) + if (TREE_CODE (arg) != STRING_CST) { - arg[i] = CALL_EXPR_ARG (exp, i); - if (arg[i] == error_mark_node) - return const0_rtx; - STRIP_NOPS (arg[i]); - op[i] = expand_normal (arg[i]); - /* We have a couple of pesky patterns that don't specify the mode... */ - mode[i+k] = insn_data[icode].operand[i+k].mode; - if (!mode[i+k]) - mode[i+k] = Pmode; + error ("builtin %qs only accepts a string argument", + rs6000_builtin_info_x[(size_t) fcode].bifname); + return const0_rtx; } - /* Check for restricted constant arguments. */ - for (int i = 0; i < 2; i++) + if (fcode == RS6000_BIF_CPU_IS) { - switch (bifaddr->restr[i]) - { - case RES_BITS: - { - size_t mask = 1; - mask <<= bifaddr->restr_val1[i]; - mask--; - tree restr_arg = arg[bifaddr->restr_opnd[i] - 1]; - STRIP_NOPS (restr_arg); - if (!(TREE_CODE (restr_arg) == INTEGER_CST - && (TREE_INT_CST_LOW (restr_arg) & ~mask) == 0)) - { - error ("argument %d must be a %d-bit unsigned literal", - bifaddr->restr_opnd[i], bifaddr->restr_val1[i]); - return CONST0_RTX (mode[0]); - } - break; - } - case RES_RANGE: - { - tree restr_arg = arg[bifaddr->restr_opnd[i] - 1]; - STRIP_NOPS (restr_arg); - if (!(TREE_CODE (restr_arg) == INTEGER_CST - && IN_RANGE (tree_to_shwi (restr_arg), - bifaddr->restr_val1[i], - bifaddr->restr_val2[i]))) - { - error ("argument %d must be a literal between %d and %d," - " inclusive", - bifaddr->restr_opnd[i], bifaddr->restr_val1[i], - bifaddr->restr_val2[i]); - return CONST0_RTX (mode[0]); - } - break; - } - case RES_VAR_RANGE: + const char *cpu = TREE_STRING_POINTER (arg); + rtx cpuid = NULL_RTX; + for (size_t i = 0; i < ARRAY_SIZE (cpu_is_info); i++) + if (strcmp (cpu, cpu_is_info[i].cpu) == 0) { - tree restr_arg = arg[bifaddr->restr_opnd[i] - 1]; - STRIP_NOPS (restr_arg); - if (TREE_CODE (restr_arg) == INTEGER_CST - && !IN_RANGE (tree_to_shwi (restr_arg), - bifaddr->restr_val1[i], - bifaddr->restr_val2[i])) - { - error ("argument %d must be a variable or a literal " - "between %d and %d, inclusive", - bifaddr->restr_opnd[i], bifaddr->restr_val1[i], - bifaddr->restr_val2[i]); - return CONST0_RTX (mode[0]); - } + /* The CPUID value in the TCB is offset by _DL_FIRST_PLATFORM. */ + cpuid = GEN_INT (cpu_is_info[i].cpuid + _DL_FIRST_PLATFORM); break; } - case RES_VALUES: + if (cpuid == NULL_RTX) + { + /* Invalid CPU argument. */ + error ("cpu %qs is an invalid argument to builtin %qs", + cpu, rs6000_builtin_info_x[(size_t) fcode].bifname); + return const0_rtx; + } + + rtx platform = gen_reg_rtx (SImode); + rtx address = gen_rtx_PLUS (Pmode, + gen_rtx_REG (Pmode, TLS_REGNUM), + GEN_INT (TCB_PLATFORM_OFFSET)); + rtx tcbmem = gen_const_mem (SImode, address); + emit_move_insn (platform, tcbmem); + emit_insn (gen_eqsi3 (target, platform, cpuid)); + } + else if (fcode == RS6000_BIF_CPU_SUPPORTS) + { + const char *hwcap = TREE_STRING_POINTER (arg); + rtx mask = NULL_RTX; + int hwcap_offset; + for (size_t i = 0; i < ARRAY_SIZE (cpu_supports_info); i++) + if (strcmp (hwcap, cpu_supports_info[i].hwcap) == 0) { - tree restr_arg = arg[bifaddr->restr_opnd[i] - 1]; - STRIP_NOPS (restr_arg); - if (!(TREE_CODE (restr_arg) == INTEGER_CST - && (tree_to_shwi (restr_arg) == bifaddr->restr_val1[i] - || tree_to_shwi (restr_arg) == bifaddr->restr_val2[i]))) - { - error ("argument %d must be either a literal %d or a " - "literal %d", - bifaddr->restr_opnd[i], bifaddr->restr_val1[i], - bifaddr->restr_val2[i]); - return CONST0_RTX (mode[0]); - } + mask = GEN_INT (cpu_supports_info[i].mask); + hwcap_offset = TCB_HWCAP_OFFSET (cpu_supports_info[i].id); break; } - default: - case RES_NONE: - break; + if (mask == NULL_RTX) + { + /* Invalid HWCAP argument. */ + error ("%s %qs is an invalid argument to builtin %qs", + "hwcap", hwcap, + rs6000_builtin_info_x[(size_t) fcode].bifname); + return const0_rtx; } + + rtx tcb_hwcap = gen_reg_rtx (SImode); + rtx address = gen_rtx_PLUS (Pmode, + gen_rtx_REG (Pmode, TLS_REGNUM), + GEN_INT (hwcap_offset)); + rtx tcbmem = gen_const_mem (SImode, address); + emit_move_insn (tcb_hwcap, tcbmem); + rtx scratch1 = gen_reg_rtx (SImode); + emit_insn (gen_rtx_SET (scratch1, + gen_rtx_AND (SImode, tcb_hwcap, mask))); + rtx scratch2 = gen_reg_rtx (SImode); + emit_insn (gen_eqsi3 (scratch2, scratch1, const0_rtx)); + emit_insn (gen_rtx_SET (target, + gen_rtx_XOR (SImode, scratch2, const1_rtx))); } + else + gcc_unreachable (); - if (bif_is_ldstmask (*bifaddr)) - return rs6000_expand_ldst_mask (target, arg[0]); + /* Record that we have expanded a CPU builtin, so that we can later + emit a reference to the special symbol exported by LIBC to ensure we + do not link against an old LIBC that doesn't support this feature. */ + cpu_builtin_p = true; - if (bif_is_stvec (*bifaddr)) - { - if (bif_is_reve (*bifaddr)) - icode = elemrev_icode (fcode); - return stv_expand_builtin (icode, op, mode[0], mode[1]); - } +#else + warning (0, "builtin %qs needs GLIBC (2.23 and newer) that exports hardware " + "capability bits", rs6000_builtin_info_x[(size_t) fcode].bifname); - if (bif_is_ldvec (*bifaddr)) + /* For old LIBCs, always return FALSE. */ + emit_move_insn (target, GEN_INT (0)); +#endif /* TARGET_LIBC_PROVIDES_HWCAP_IN_TCB */ + + return target; +} + +/* For the element-reversing load/store built-ins, produce the correct + insn_code depending on the target endianness. */ +static insn_code +elemrev_icode (rs6000_gen_builtins fcode) +{ + switch (fcode) { - if (bif_is_reve (*bifaddr)) - icode = elemrev_icode (fcode); - return ldv_expand_builtin (target, icode, op, mode[0]); - } + case RS6000_BIF_ST_ELEMREV_V1TI: + return BYTES_BIG_ENDIAN ? CODE_FOR_vsx_store_v1ti + : CODE_FOR_vsx_st_elemrev_v1ti; - if (bif_is_lxvrse (*bifaddr)) - return lxvrse_expand_builtin (target, icode, op, mode[0], mode[1]); + case RS6000_BIF_ST_ELEMREV_V2DF: + return BYTES_BIG_ENDIAN ? CODE_FOR_vsx_store_v2df + : CODE_FOR_vsx_st_elemrev_v2df; - if (bif_is_lxvrze (*bifaddr)) - return lxvrze_expand_builtin (target, icode, op, mode[0], mode[1]); + case RS6000_BIF_ST_ELEMREV_V2DI: + return BYTES_BIG_ENDIAN ? CODE_FOR_vsx_store_v2di + : CODE_FOR_vsx_st_elemrev_v2di; - if (bif_is_mma (*bifaddr)) - return new_mma_expand_builtin (exp, target, icode, fcode); + case RS6000_BIF_ST_ELEMREV_V4SF: + return BYTES_BIG_ENDIAN ? CODE_FOR_vsx_store_v4sf + : CODE_FOR_vsx_st_elemrev_v4sf; - if (fcode == RS6000_BIF_PACK_IF - && TARGET_LONG_DOUBLE_128 - && !TARGET_IEEEQUAD) - { - icode = CODE_FOR_packtf; - fcode = RS6000_BIF_PACK_TF; - uns_fcode = (size_t) fcode; - } - else if (fcode == RS6000_BIF_UNPACK_IF - && TARGET_LONG_DOUBLE_128 - && !TARGET_IEEEQUAD) - { - icode = CODE_FOR_unpacktf; - fcode = RS6000_BIF_UNPACK_TF; - uns_fcode = (size_t) fcode; - } + case RS6000_BIF_ST_ELEMREV_V4SI: + return BYTES_BIG_ENDIAN ? CODE_FOR_vsx_store_v4si + : CODE_FOR_vsx_st_elemrev_v4si; - if (TREE_TYPE (TREE_TYPE (fndecl)) == void_type_node) - target = NULL_RTX; - else if (target == 0 - || GET_MODE (target) != mode[0] - || !insn_data[icode].operand[0].predicate (target, mode[0])) - target = gen_reg_rtx (mode[0]); + case RS6000_BIF_ST_ELEMREV_V8HI: + return BYTES_BIG_ENDIAN ? CODE_FOR_vsx_store_v8hi + : CODE_FOR_vsx_st_elemrev_v8hi; - for (int i = 0; i < nargs; i++) - if (!insn_data[icode].operand[i+k].predicate (op[i], mode[i+k])) - op[i] = copy_to_mode_reg (mode[i+k], op[i]); + case RS6000_BIF_ST_ELEMREV_V16QI: + return BYTES_BIG_ENDIAN ? CODE_FOR_vsx_store_v16qi + : CODE_FOR_vsx_st_elemrev_v16qi; - rtx pat; + case RS6000_BIF_LD_ELEMREV_V2DF: + return BYTES_BIG_ENDIAN ? CODE_FOR_vsx_load_v2df + : CODE_FOR_vsx_ld_elemrev_v2df; - switch (nargs) - { - case 0: - pat = (void_func - ? GEN_FCN (icode) () - : GEN_FCN (icode) (target)); - break; - case 1: - pat = (void_func - ? GEN_FCN (icode) (op[0]) - : GEN_FCN (icode) (target, op[0])); - break; - case 2: - pat = (void_func - ? GEN_FCN (icode) (op[0], op[1]) - : GEN_FCN (icode) (target, op[0], op[1])); - break; - case 3: - pat = (void_func - ? GEN_FCN (icode) (op[0], op[1], op[2]) - : GEN_FCN (icode) (target, op[0], op[1], op[2])); - break; - case 4: - pat = (void_func - ? GEN_FCN (icode) (op[0], op[1], op[2], op[3]) - : GEN_FCN (icode) (target, op[0], op[1], op[2], op[3])); - break; - case 5: - pat = (void_func - ? GEN_FCN (icode) (op[0], op[1], op[2], op[3], op[4]) - : GEN_FCN (icode) (target, op[0], op[1], op[2], op[3], op[4])); - break; - case 6: - pat = (void_func - ? GEN_FCN (icode) (op[0], op[1], op[2], op[3], op[4], op[5]) - : GEN_FCN (icode) (target, op[0], op[1], - op[2], op[3], op[4], op[5])); - break; + case RS6000_BIF_LD_ELEMREV_V1TI: + return BYTES_BIG_ENDIAN ? CODE_FOR_vsx_load_v1ti + : CODE_FOR_vsx_ld_elemrev_v1ti; + + case RS6000_BIF_LD_ELEMREV_V2DI: + return BYTES_BIG_ENDIAN ? CODE_FOR_vsx_load_v2di + : CODE_FOR_vsx_ld_elemrev_v2di; + + case RS6000_BIF_LD_ELEMREV_V4SF: + return BYTES_BIG_ENDIAN ? CODE_FOR_vsx_load_v4sf + : CODE_FOR_vsx_ld_elemrev_v4sf; + + case RS6000_BIF_LD_ELEMREV_V4SI: + return BYTES_BIG_ENDIAN ? CODE_FOR_vsx_load_v4si + : CODE_FOR_vsx_ld_elemrev_v4si; + + case RS6000_BIF_LD_ELEMREV_V8HI: + return BYTES_BIG_ENDIAN ? CODE_FOR_vsx_load_v8hi + : CODE_FOR_vsx_ld_elemrev_v8hi; + + case RS6000_BIF_LD_ELEMREV_V16QI: + return BYTES_BIG_ENDIAN ? CODE_FOR_vsx_load_v16qi + : CODE_FOR_vsx_ld_elemrev_v16qi; default: - gcc_assert (MAX_BUILTIN_ARGS == 6); - gcc_unreachable (); + ; } - if (!pat) - return 0; - - emit_insn (pat); - return target; + gcc_unreachable (); } -/* Create a builtin vector type with a name. Taking care not to give - the canonical type a name. */ - -static tree -rs6000_vector_type (const char *name, tree elt_type, unsigned num_elts) +/* Expand an AltiVec vector load builtin, and return the expanded rtx. */ +static rtx +ldv_expand_builtin (rtx target, insn_code icode, rtx *op, machine_mode tmode) { - tree result = build_vector_type (elt_type, num_elts); + if (target == 0 + || GET_MODE (target) != tmode + || !insn_data[icode].operand[0].predicate (target, tmode)) + target = gen_reg_rtx (tmode); - /* Copy so we don't give the canonical type a name. */ - result = build_variant_type_copy (result); + op[1] = copy_to_mode_reg (Pmode, op[1]); - add_builtin_type (name, result); + /* These CELL built-ins use BLKmode instead of tmode for historical + (i.e., unknown) reasons. TODO: Is this necessary? */ + bool blk = (icode == CODE_FOR_altivec_lvlx + || icode == CODE_FOR_altivec_lvlxl + || icode == CODE_FOR_altivec_lvrx + || icode == CODE_FOR_altivec_lvrxl); - return result; -} + /* For LVX, express the RTL accurately by ANDing the address with -16. + LVXL and LVE*X expand to use UNSPECs to hide their special behavior, + so the raw address is fine. */ + /* TODO: That statement seems wrong, as the UNSPECs don't surround the + memory expression, so a latent bug may lie here. The &-16 is likely + needed for all VMX-style loads. */ + if (icode == CODE_FOR_altivec_lvx_v1ti + || icode == CODE_FOR_altivec_lvx_v2df + || icode == CODE_FOR_altivec_lvx_v2di + || icode == CODE_FOR_altivec_lvx_v4sf + || icode == CODE_FOR_altivec_lvx_v4si + || icode == CODE_FOR_altivec_lvx_v8hi + || icode == CODE_FOR_altivec_lvx_v16qi) + { + rtx rawaddr; + if (op[0] == const0_rtx) + rawaddr = op[1]; + else + { + op[0] = copy_to_mode_reg (Pmode, op[0]); + rawaddr = gen_rtx_PLUS (Pmode, op[1], op[0]); + } + rtx addr = gen_rtx_AND (Pmode, rawaddr, gen_rtx_CONST_INT (Pmode, -16)); + addr = gen_rtx_MEM (blk ? BLKmode : tmode, addr); -void -rs6000_init_builtins (void) -{ - tree tdecl; - tree ftype; - tree t; - machine_mode mode; - const char *str; + emit_insn (gen_rtx_SET (target, addr)); + } + else + { + rtx addr; + if (op[0] == const0_rtx) + addr = gen_rtx_MEM (blk ? BLKmode : tmode, op[1]); + else + { + op[0] = copy_to_mode_reg (Pmode, op[0]); + addr = gen_rtx_MEM (blk ? BLKmode : tmode, + gen_rtx_PLUS (Pmode, op[1], op[0])); + } + + rtx pat = GEN_FCN (icode) (target, addr); + if (!pat) + return 0; + emit_insn (pat); + } - if (TARGET_DEBUG_BUILTIN) - fprintf (stderr, "rs6000_init_builtins%s%s\n", - (TARGET_ALTIVEC) ? ", altivec" : "", - (TARGET_VSX) ? ", vsx" : ""); + return target; +} + +/* Expand a builtin function that loads a scalar into a vector register + with sign extension, and return the expanded rtx. */ +static rtx +lxvrse_expand_builtin (rtx target, insn_code icode, rtx *op, + machine_mode tmode, machine_mode smode) +{ + rtx pat, addr; + op[1] = copy_to_mode_reg (Pmode, op[1]); - if (new_builtins_are_live) - V2DI_type_node = rs6000_vector_type ("__vector long long", - long_long_integer_type_node, 2); + if (op[0] == const0_rtx) + addr = gen_rtx_MEM (tmode, op[1]); else { - str = TARGET_POWERPC64 ? "__vector long" : "__vector long long"; - V2DI_type_node = rs6000_vector_type (str, - long_long_integer_type_node, - 2); + op[0] = copy_to_mode_reg (Pmode, op[0]); + addr = gen_rtx_MEM (smode, + gen_rtx_PLUS (Pmode, op[1], op[0])); } - ptr_V2DI_type_node - = build_pointer_type (build_qualified_type (V2DI_type_node, - TYPE_QUAL_CONST)); - - V2DF_type_node = rs6000_vector_type ("__vector double", double_type_node, 2); - ptr_V2DF_type_node - = build_pointer_type (build_qualified_type (V2DF_type_node, - TYPE_QUAL_CONST)); - - V4SI_type_node = rs6000_vector_type ("__vector signed int", - intSI_type_node, 4); - ptr_V4SI_type_node - = build_pointer_type (build_qualified_type (V4SI_type_node, - TYPE_QUAL_CONST)); - V4SF_type_node = rs6000_vector_type ("__vector float", float_type_node, 4); - ptr_V4SF_type_node - = build_pointer_type (build_qualified_type (V4SF_type_node, - TYPE_QUAL_CONST)); + rtx discratch = gen_reg_rtx (V2DImode); + rtx tiscratch = gen_reg_rtx (TImode); - V8HI_type_node = rs6000_vector_type ("__vector signed short", - intHI_type_node, 8); - ptr_V8HI_type_node - = build_pointer_type (build_qualified_type (V8HI_type_node, - TYPE_QUAL_CONST)); + /* Emit the lxvr*x insn. */ + pat = GEN_FCN (icode) (tiscratch, addr); + if (!pat) + return 0; + emit_insn (pat); - V16QI_type_node = rs6000_vector_type ("__vector signed char", - intQI_type_node, 16); - ptr_V16QI_type_node - = build_pointer_type (build_qualified_type (V16QI_type_node, - TYPE_QUAL_CONST)); + /* Emit a sign extension from V16QI,V8HI,V4SI to V2DI. */ + rtx temp1; + if (icode == CODE_FOR_vsx_lxvrbx) + { + temp1 = simplify_gen_subreg (V16QImode, tiscratch, TImode, 0); + emit_insn (gen_vsx_sign_extend_qi_v2di (discratch, temp1)); + } + else if (icode == CODE_FOR_vsx_lxvrhx) + { + temp1 = simplify_gen_subreg (V8HImode, tiscratch, TImode, 0); + emit_insn (gen_vsx_sign_extend_hi_v2di (discratch, temp1)); + } + else if (icode == CODE_FOR_vsx_lxvrwx) + { + temp1 = simplify_gen_subreg (V4SImode, tiscratch, TImode, 0); + emit_insn (gen_vsx_sign_extend_si_v2di (discratch, temp1)); + } + else if (icode == CODE_FOR_vsx_lxvrdx) + discratch = simplify_gen_subreg (V2DImode, tiscratch, TImode, 0); + else + gcc_unreachable (); - unsigned_V16QI_type_node = rs6000_vector_type ("__vector unsigned char", - unsigned_intQI_type_node, 16); - ptr_unsigned_V16QI_type_node - = build_pointer_type (build_qualified_type (unsigned_V16QI_type_node, - TYPE_QUAL_CONST)); + /* Emit the sign extension from V2DI (double) to TI (quad). */ + rtx temp2 = simplify_gen_subreg (TImode, discratch, V2DImode, 0); + emit_insn (gen_extendditi2_vector (target, temp2)); - unsigned_V8HI_type_node = rs6000_vector_type ("__vector unsigned short", - unsigned_intHI_type_node, 8); - ptr_unsigned_V8HI_type_node - = build_pointer_type (build_qualified_type (unsigned_V8HI_type_node, - TYPE_QUAL_CONST)); + return target; +} - unsigned_V4SI_type_node = rs6000_vector_type ("__vector unsigned int", - unsigned_intSI_type_node, 4); - ptr_unsigned_V4SI_type_node - = build_pointer_type (build_qualified_type (unsigned_V4SI_type_node, - TYPE_QUAL_CONST)); +/* Expand a builtin function that loads a scalar into a vector register + with zero extension, and return the expanded rtx. */ +static rtx +lxvrze_expand_builtin (rtx target, insn_code icode, rtx *op, + machine_mode tmode, machine_mode smode) +{ + rtx pat, addr; + op[1] = copy_to_mode_reg (Pmode, op[1]); - if (new_builtins_are_live) - unsigned_V2DI_type_node - = rs6000_vector_type ("__vector unsigned long long", - long_long_unsigned_type_node, 2); + if (op[0] == const0_rtx) + addr = gen_rtx_MEM (tmode, op[1]); else { - str = TARGET_POWERPC64 - ? "__vector unsigned long" - : "__vector unsigned long long"; - unsigned_V2DI_type_node - = rs6000_vector_type (str, long_long_unsigned_type_node, 2); + op[0] = copy_to_mode_reg (Pmode, op[0]); + addr = gen_rtx_MEM (smode, + gen_rtx_PLUS (Pmode, op[1], op[0])); } - ptr_unsigned_V2DI_type_node - = build_pointer_type (build_qualified_type (unsigned_V2DI_type_node, - TYPE_QUAL_CONST)); - - opaque_V4SI_type_node = build_opaque_vector_type (intSI_type_node, 4); + pat = GEN_FCN (icode) (target, addr); + if (!pat) + return 0; + emit_insn (pat); + return target; +} - const_str_type_node - = build_pointer_type (build_qualified_type (char_type_node, - TYPE_QUAL_CONST)); +/* Expand an AltiVec vector store builtin, and return the expanded rtx. */ +static rtx +stv_expand_builtin (insn_code icode, rtx *op, + machine_mode tmode, machine_mode smode) +{ + op[2] = copy_to_mode_reg (Pmode, op[2]); - /* We use V1TI mode as a special container to hold __int128_t items that - must live in VSX registers. */ - if (intTI_type_node) + /* For STVX, express the RTL accurately by ANDing the address with -16. + STVXL and STVE*X expand to use UNSPECs to hide their special behavior, + so the raw address is fine. */ + /* TODO: That statement seems wrong, as the UNSPECs don't surround the + memory expression, so a latent bug may lie here. The &-16 is likely + needed for all VMX-style stores. */ + if (icode == CODE_FOR_altivec_stvx_v2df + || icode == CODE_FOR_altivec_stvx_v2di + || icode == CODE_FOR_altivec_stvx_v4sf + || icode == CODE_FOR_altivec_stvx_v4si + || icode == CODE_FOR_altivec_stvx_v8hi + || icode == CODE_FOR_altivec_stvx_v16qi) { - V1TI_type_node = rs6000_vector_type ("__vector __int128", - intTI_type_node, 1); - ptr_V1TI_type_node - = build_pointer_type (build_qualified_type (V1TI_type_node, - TYPE_QUAL_CONST)); - unsigned_V1TI_type_node - = rs6000_vector_type ("__vector unsigned __int128", - unsigned_intTI_type_node, 1); - ptr_unsigned_V1TI_type_node - = build_pointer_type (build_qualified_type (unsigned_V1TI_type_node, - TYPE_QUAL_CONST)); - } - - /* The 'vector bool ...' types must be kept distinct from 'vector unsigned ...' - types, especially in C++ land. Similarly, 'vector pixel' is distinct from - 'vector unsigned short'. */ + rtx rawaddr; + if (op[1] == const0_rtx) + rawaddr = op[2]; + else + { + op[1] = copy_to_mode_reg (Pmode, op[1]); + rawaddr = gen_rtx_PLUS (Pmode, op[2], op[1]); + } - bool_char_type_node = build_distinct_type_copy (unsigned_intQI_type_node); - bool_short_type_node = build_distinct_type_copy (unsigned_intHI_type_node); - bool_int_type_node = build_distinct_type_copy (unsigned_intSI_type_node); - bool_long_long_type_node = build_distinct_type_copy (unsigned_intDI_type_node); - pixel_type_node = build_distinct_type_copy (unsigned_intHI_type_node); + rtx addr = gen_rtx_AND (Pmode, rawaddr, gen_rtx_CONST_INT (Pmode, -16)); + addr = gen_rtx_MEM (tmode, addr); + op[0] = copy_to_mode_reg (tmode, op[0]); + emit_insn (gen_rtx_SET (addr, op[0])); + } + else if (icode == CODE_FOR_vsx_stxvrbx + || icode == CODE_FOR_vsx_stxvrhx + || icode == CODE_FOR_vsx_stxvrwx + || icode == CODE_FOR_vsx_stxvrdx) + { + rtx truncrtx = gen_rtx_TRUNCATE (tmode, op[0]); + op[0] = copy_to_mode_reg (E_TImode, truncrtx); - long_integer_type_internal_node = long_integer_type_node; - long_unsigned_type_internal_node = long_unsigned_type_node; - long_long_integer_type_internal_node = long_long_integer_type_node; - long_long_unsigned_type_internal_node = long_long_unsigned_type_node; - intQI_type_internal_node = intQI_type_node; - uintQI_type_internal_node = unsigned_intQI_type_node; - intHI_type_internal_node = intHI_type_node; - uintHI_type_internal_node = unsigned_intHI_type_node; - intSI_type_internal_node = intSI_type_node; - uintSI_type_internal_node = unsigned_intSI_type_node; - intDI_type_internal_node = intDI_type_node; - uintDI_type_internal_node = unsigned_intDI_type_node; - intTI_type_internal_node = intTI_type_node; - uintTI_type_internal_node = unsigned_intTI_type_node; - float_type_internal_node = float_type_node; - double_type_internal_node = double_type_node; - long_double_type_internal_node = long_double_type_node; - dfloat64_type_internal_node = dfloat64_type_node; - dfloat128_type_internal_node = dfloat128_type_node; - void_type_internal_node = void_type_node; + rtx addr; + if (op[1] == const0_rtx) + addr = gen_rtx_MEM (Pmode, op[2]); + else + { + op[1] = copy_to_mode_reg (Pmode, op[1]); + addr = gen_rtx_MEM (tmode, gen_rtx_PLUS (Pmode, op[2], op[1])); + } + rtx pat = GEN_FCN (icode) (addr, op[0]); + if (pat) + emit_insn (pat); + } + else + { + if (!insn_data[icode].operand[1].predicate (op[0], smode)) + op[0] = copy_to_mode_reg (smode, op[0]); - ptr_intQI_type_node - = build_pointer_type (build_qualified_type (intQI_type_internal_node, - TYPE_QUAL_CONST)); - ptr_uintQI_type_node - = build_pointer_type (build_qualified_type (uintQI_type_internal_node, - TYPE_QUAL_CONST)); - ptr_intHI_type_node - = build_pointer_type (build_qualified_type (intHI_type_internal_node, - TYPE_QUAL_CONST)); - ptr_uintHI_type_node - = build_pointer_type (build_qualified_type (uintHI_type_internal_node, - TYPE_QUAL_CONST)); - ptr_intSI_type_node - = build_pointer_type (build_qualified_type (intSI_type_internal_node, - TYPE_QUAL_CONST)); - ptr_uintSI_type_node - = build_pointer_type (build_qualified_type (uintSI_type_internal_node, - TYPE_QUAL_CONST)); - ptr_intDI_type_node - = build_pointer_type (build_qualified_type (intDI_type_internal_node, - TYPE_QUAL_CONST)); - ptr_uintDI_type_node - = build_pointer_type (build_qualified_type (uintDI_type_internal_node, - TYPE_QUAL_CONST)); - ptr_intTI_type_node - = build_pointer_type (build_qualified_type (intTI_type_internal_node, - TYPE_QUAL_CONST)); - ptr_uintTI_type_node - = build_pointer_type (build_qualified_type (uintTI_type_internal_node, - TYPE_QUAL_CONST)); + rtx addr; + if (op[1] == const0_rtx) + addr = gen_rtx_MEM (tmode, op[2]); + else + { + op[1] = copy_to_mode_reg (Pmode, op[1]); + addr = gen_rtx_MEM (tmode, gen_rtx_PLUS (Pmode, op[2], op[1])); + } - t = build_qualified_type (long_integer_type_internal_node, TYPE_QUAL_CONST); - ptr_long_integer_type_node = build_pointer_type (t); + rtx pat = GEN_FCN (icode) (addr, op[0]); + if (pat) + emit_insn (pat); + } - t = build_qualified_type (long_unsigned_type_internal_node, TYPE_QUAL_CONST); - ptr_long_unsigned_type_node = build_pointer_type (t); + return NULL_RTX; +} - ptr_float_type_node - = build_pointer_type (build_qualified_type (float_type_internal_node, - TYPE_QUAL_CONST)); - ptr_double_type_node - = build_pointer_type (build_qualified_type (double_type_internal_node, - TYPE_QUAL_CONST)); - ptr_long_double_type_node - = build_pointer_type (build_qualified_type (long_double_type_internal_node, - TYPE_QUAL_CONST)); - if (dfloat64_type_node) - { - t = build_qualified_type (dfloat64_type_internal_node, TYPE_QUAL_CONST); - ptr_dfloat64_type_node = build_pointer_type (t); - } - else - ptr_dfloat64_type_node = NULL; +/* Expand the MMA built-in in EXP, and return it. */ +static rtx +new_mma_expand_builtin (tree exp, rtx target, insn_code icode, + rs6000_gen_builtins fcode) +{ + tree fndecl = TREE_OPERAND (CALL_EXPR_FN (exp), 0); + bool void_func = TREE_TYPE (TREE_TYPE (fndecl)) == void_type_node; + machine_mode tmode = VOIDmode; + rtx op[MAX_MMA_OPERANDS]; + unsigned nopnds = 0; - if (dfloat128_type_node) + if (!void_func) { - t = build_qualified_type (dfloat128_type_internal_node, TYPE_QUAL_CONST); - ptr_dfloat128_type_node = build_pointer_type (t); + tmode = insn_data[icode].operand[0].mode; + if (!(target + && GET_MODE (target) == tmode + && insn_data[icode].operand[0].predicate (target, tmode))) + target = gen_reg_rtx (tmode); + op[nopnds++] = target; } else - ptr_dfloat128_type_node = NULL; + target = const0_rtx; - t = build_qualified_type (long_long_integer_type_internal_node, - TYPE_QUAL_CONST); - ptr_long_long_integer_type_node = build_pointer_type (t); + call_expr_arg_iterator iter; + tree arg; + FOR_EACH_CALL_EXPR_ARG (arg, iter, exp) + { + if (arg == error_mark_node) + return const0_rtx; - t = build_qualified_type (long_long_unsigned_type_internal_node, - TYPE_QUAL_CONST); - ptr_long_long_unsigned_type_node = build_pointer_type (t); + rtx opnd; + const struct insn_operand_data *insn_op; + insn_op = &insn_data[icode].operand[nopnds]; + if (TREE_CODE (arg) == ADDR_EXPR + && MEM_P (DECL_RTL (TREE_OPERAND (arg, 0)))) + opnd = DECL_RTL (TREE_OPERAND (arg, 0)); + else + opnd = expand_normal (arg); - /* 128-bit floating point support. KFmode is IEEE 128-bit floating point. - IFmode is the IBM extended 128-bit format that is a pair of doubles. - TFmode will be either IEEE 128-bit floating point or the IBM double-double - format that uses a pair of doubles, depending on the switches and - defaults. + if (!insn_op->predicate (opnd, insn_op->mode)) + { + /* TODO: This use of constraints needs explanation. */ + if (!strcmp (insn_op->constraint, "n")) + { + if (!CONST_INT_P (opnd)) + error ("argument %d must be an unsigned literal", nopnds); + else + error ("argument %d is an unsigned literal that is " + "out of range", nopnds); + return const0_rtx; + } + opnd = copy_to_mode_reg (insn_op->mode, opnd); + } - If we don't support for either 128-bit IBM double double or IEEE 128-bit - floating point, we need make sure the type is non-zero or else self-test - fails during bootstrap. + /* Some MMA instructions have INOUT accumulator operands, so force + their target register to be the same as their input register. */ + if (!void_func + && nopnds == 1 + && !strcmp (insn_op->constraint, "0") + && insn_op->mode == tmode + && REG_P (opnd) + && insn_data[icode].operand[0].predicate (opnd, tmode)) + target = op[0] = opnd; - Always create __ibm128 as a separate type, even if the current long double - format is IBM extended double. + op[nopnds++] = opnd; + } - For IEEE 128-bit floating point, always create the type __ieee128. If the - user used -mfloat128, rs6000-c.c will create a define from __float128 to - __ieee128. */ - if (TARGET_FLOAT128_TYPE) + rtx pat; + switch (nopnds) { - if (!TARGET_IEEEQUAD && TARGET_LONG_DOUBLE_128) - ibm128_float_type_node = long_double_type_node; - else + case 1: + pat = GEN_FCN (icode) (op[0]); + break; + case 2: + pat = GEN_FCN (icode) (op[0], op[1]); + break; + case 3: + /* The ASSEMBLE builtin source operands are reversed in little-endian + mode, so reorder them. */ + if (fcode == RS6000_BIF_ASSEMBLE_PAIR_V_INTERNAL && !WORDS_BIG_ENDIAN) + std::swap (op[1], op[2]); + pat = GEN_FCN (icode) (op[0], op[1], op[2]); + break; + case 4: + pat = GEN_FCN (icode) (op[0], op[1], op[2], op[3]); + break; + case 5: + /* The ASSEMBLE builtin source operands are reversed in little-endian + mode, so reorder them. */ + if (fcode == RS6000_BIF_ASSEMBLE_ACC_INTERNAL && !WORDS_BIG_ENDIAN) { - ibm128_float_type_node = make_node (REAL_TYPE); - TYPE_PRECISION (ibm128_float_type_node) = 128; - SET_TYPE_MODE (ibm128_float_type_node, IFmode); - layout_type (ibm128_float_type_node); + std::swap (op[1], op[4]); + std::swap (op[2], op[3]); } - t = build_qualified_type (ibm128_float_type_node, TYPE_QUAL_CONST); - ptr_ibm128_float_type_node = build_pointer_type (t); - lang_hooks.types.register_builtin_type (ibm128_float_type_node, - "__ibm128"); - - if (TARGET_IEEEQUAD && TARGET_LONG_DOUBLE_128) - ieee128_float_type_node = long_double_type_node; - else - ieee128_float_type_node = float128_type_node; - t = build_qualified_type (ieee128_float_type_node, TYPE_QUAL_CONST); - ptr_ieee128_float_type_node = build_pointer_type (t); - lang_hooks.types.register_builtin_type (ieee128_float_type_node, - "__ieee128"); + pat = GEN_FCN (icode) (op[0], op[1], op[2], op[3], op[4]); + break; + case 6: + pat = GEN_FCN (icode) (op[0], op[1], op[2], op[3], op[4], op[5]); + break; + case 7: + pat = GEN_FCN (icode) (op[0], op[1], op[2], op[3], op[4], op[5], op[6]); + break; + default: + gcc_unreachable (); } - else - ieee128_float_type_node = ibm128_float_type_node = long_double_type_node; + if (!pat) + return NULL_RTX; - /* Vector pair and vector quad support. */ - vector_pair_type_node = make_node (OPAQUE_TYPE); - SET_TYPE_MODE (vector_pair_type_node, OOmode); - TYPE_SIZE (vector_pair_type_node) = bitsize_int (GET_MODE_BITSIZE (OOmode)); - TYPE_PRECISION (vector_pair_type_node) = GET_MODE_BITSIZE (OOmode); - TYPE_SIZE_UNIT (vector_pair_type_node) = size_int (GET_MODE_SIZE (OOmode)); - SET_TYPE_ALIGN (vector_pair_type_node, 256); - TYPE_USER_ALIGN (vector_pair_type_node) = 0; - lang_hooks.types.register_builtin_type (vector_pair_type_node, - "__vector_pair"); - t = build_qualified_type (vector_pair_type_node, TYPE_QUAL_CONST); - ptr_vector_pair_type_node = build_pointer_type (t); + emit_insn (pat); + return target; +} - vector_quad_type_node = make_node (OPAQUE_TYPE); - SET_TYPE_MODE (vector_quad_type_node, XOmode); - TYPE_SIZE (vector_quad_type_node) = bitsize_int (GET_MODE_BITSIZE (XOmode)); - TYPE_PRECISION (vector_quad_type_node) = GET_MODE_BITSIZE (XOmode); - TYPE_SIZE_UNIT (vector_quad_type_node) = size_int (GET_MODE_SIZE (XOmode)); - SET_TYPE_ALIGN (vector_quad_type_node, 512); - TYPE_USER_ALIGN (vector_quad_type_node) = 0; - lang_hooks.types.register_builtin_type (vector_quad_type_node, - "__vector_quad"); - t = build_qualified_type (vector_quad_type_node, TYPE_QUAL_CONST); - ptr_vector_quad_type_node = build_pointer_type (t); +/* Return the appropriate SPR number associated with the given builtin. */ +static inline HOST_WIDE_INT +new_htm_spr_num (enum rs6000_gen_builtins code) +{ + if (code == RS6000_BIF_GET_TFHAR + || code == RS6000_BIF_SET_TFHAR) + return TFHAR_SPR; + else if (code == RS6000_BIF_GET_TFIAR + || code == RS6000_BIF_SET_TFIAR) + return TFIAR_SPR; + else if (code == RS6000_BIF_GET_TEXASR + || code == RS6000_BIF_SET_TEXASR) + return TEXASR_SPR; + gcc_assert (code == RS6000_BIF_GET_TEXASRU + || code == RS6000_BIF_SET_TEXASRU); + return TEXASRU_SPR; +} - /* Initialize the modes for builtin_function_type, mapping a machine mode to - tree type node. */ - builtin_mode_to_type[QImode][0] = integer_type_node; - builtin_mode_to_type[QImode][1] = unsigned_intSI_type_node; - builtin_mode_to_type[HImode][0] = integer_type_node; - builtin_mode_to_type[HImode][1] = unsigned_intSI_type_node; - builtin_mode_to_type[SImode][0] = intSI_type_node; - builtin_mode_to_type[SImode][1] = unsigned_intSI_type_node; - builtin_mode_to_type[DImode][0] = intDI_type_node; - builtin_mode_to_type[DImode][1] = unsigned_intDI_type_node; - builtin_mode_to_type[TImode][0] = intTI_type_node; - builtin_mode_to_type[TImode][1] = unsigned_intTI_type_node; - builtin_mode_to_type[SFmode][0] = float_type_node; - builtin_mode_to_type[DFmode][0] = double_type_node; - builtin_mode_to_type[IFmode][0] = ibm128_float_type_node; - builtin_mode_to_type[KFmode][0] = ieee128_float_type_node; - builtin_mode_to_type[TFmode][0] = long_double_type_node; - builtin_mode_to_type[DDmode][0] = dfloat64_type_node; - builtin_mode_to_type[TDmode][0] = dfloat128_type_node; - builtin_mode_to_type[V1TImode][0] = V1TI_type_node; - builtin_mode_to_type[V1TImode][1] = unsigned_V1TI_type_node; - builtin_mode_to_type[V2DImode][0] = V2DI_type_node; - builtin_mode_to_type[V2DImode][1] = unsigned_V2DI_type_node; - builtin_mode_to_type[V2DFmode][0] = V2DF_type_node; - builtin_mode_to_type[V4SImode][0] = V4SI_type_node; - builtin_mode_to_type[V4SImode][1] = unsigned_V4SI_type_node; - builtin_mode_to_type[V4SFmode][0] = V4SF_type_node; - builtin_mode_to_type[V8HImode][0] = V8HI_type_node; - builtin_mode_to_type[V8HImode][1] = unsigned_V8HI_type_node; - builtin_mode_to_type[V16QImode][0] = V16QI_type_node; - builtin_mode_to_type[V16QImode][1] = unsigned_V16QI_type_node; - builtin_mode_to_type[OOmode][1] = vector_pair_type_node; - builtin_mode_to_type[XOmode][1] = vector_quad_type_node; +/* Expand the HTM builtin in EXP and store the result in TARGET. + Return the expanded rtx. */ +static rtx +new_htm_expand_builtin (bifdata *bifaddr, rs6000_gen_builtins fcode, + tree exp, rtx target) +{ + if (!TARGET_POWERPC64 + && (fcode == RS6000_BIF_TABORTDC + || fcode == RS6000_BIF_TABORTDCI)) + { + error ("builtin %qs is only valid in 64-bit mode", bifaddr->bifname); + return const0_rtx; + } - tdecl = add_builtin_type ("__bool char", bool_char_type_node); - TYPE_NAME (bool_char_type_node) = tdecl; + tree fndecl = TREE_OPERAND (CALL_EXPR_FN (exp), 0); + bool nonvoid = TREE_TYPE (TREE_TYPE (fndecl)) != void_type_node; + bool uses_spr = bif_is_htmspr (*bifaddr); + insn_code icode = bifaddr->icode; - tdecl = add_builtin_type ("__bool short", bool_short_type_node); - TYPE_NAME (bool_short_type_node) = tdecl; + if (uses_spr) + icode = rs6000_htm_spr_icode (nonvoid); - tdecl = add_builtin_type ("__bool int", bool_int_type_node); - TYPE_NAME (bool_int_type_node) = tdecl; + rtx op[MAX_HTM_OPERANDS]; + int nopnds = 0; + const insn_operand_data *insn_op = &insn_data[icode].operand[0]; - tdecl = add_builtin_type ("__pixel", pixel_type_node); - TYPE_NAME (pixel_type_node) = tdecl; + if (nonvoid) + { + machine_mode tmode = (uses_spr) ? insn_op->mode : E_SImode; + if (!target + || GET_MODE (target) != tmode + || (uses_spr && !insn_op->predicate (target, tmode))) + target = gen_reg_rtx (tmode); + if (uses_spr) + op[nopnds++] = target; + } - bool_V16QI_type_node = rs6000_vector_type ("__vector __bool char", - bool_char_type_node, 16); - ptr_bool_V16QI_type_node - = build_pointer_type (build_qualified_type (bool_V16QI_type_node, - TYPE_QUAL_CONST)); + tree arg; + call_expr_arg_iterator iter; - bool_V8HI_type_node = rs6000_vector_type ("__vector __bool short", - bool_short_type_node, 8); - ptr_bool_V8HI_type_node - = build_pointer_type (build_qualified_type (bool_V8HI_type_node, - TYPE_QUAL_CONST)); + FOR_EACH_CALL_EXPR_ARG (arg, iter, exp) + { + if (arg == error_mark_node || nopnds >= MAX_HTM_OPERANDS) + return const0_rtx; - bool_V4SI_type_node = rs6000_vector_type ("__vector __bool int", - bool_int_type_node, 4); - ptr_bool_V4SI_type_node - = build_pointer_type (build_qualified_type (bool_V4SI_type_node, - TYPE_QUAL_CONST)); + insn_op = &insn_data[icode].operand[nopnds]; + op[nopnds] = expand_normal (arg); - bool_V2DI_type_node = rs6000_vector_type (TARGET_POWERPC64 - ? "__vector __bool long" - : "__vector __bool long long", - bool_long_long_type_node, 2); - ptr_bool_V2DI_type_node - = build_pointer_type (build_qualified_type (bool_V2DI_type_node, - TYPE_QUAL_CONST)); + if (!insn_op->predicate (op[nopnds], insn_op->mode)) + { + /* TODO: This use of constraints could use explanation. + This happens a couple of places, perhaps make that a + function to document what's happening. */ + if (!strcmp (insn_op->constraint, "n")) + { + int arg_num = nonvoid ? nopnds : nopnds + 1; + if (!CONST_INT_P (op[nopnds])) + error ("argument %d must be an unsigned literal", arg_num); + else + error ("argument %d is an unsigned literal that is " + "out of range", arg_num); + return const0_rtx; + } + op[nopnds] = copy_to_mode_reg (insn_op->mode, op[nopnds]); + } - bool_V1TI_type_node = rs6000_vector_type ("__vector __bool __int128", - intTI_type_node, 1); - ptr_bool_V1TI_type_node - = build_pointer_type (build_qualified_type (bool_V1TI_type_node, - TYPE_QUAL_CONST)); + nopnds++; + } - pixel_V8HI_type_node = rs6000_vector_type ("__vector __pixel", - pixel_type_node, 8); - ptr_pixel_V8HI_type_node - = build_pointer_type (build_qualified_type (pixel_V8HI_type_node, - TYPE_QUAL_CONST)); - pcvoid_type_node - = build_pointer_type (build_qualified_type (void_type_node, - TYPE_QUAL_CONST)); + /* Handle the builtins for extended mnemonics. These accept + no arguments, but map to builtins that take arguments. */ + switch (fcode) + { + case RS6000_BIF_TENDALL: /* Alias for: tend. 1 */ + case RS6000_BIF_TRESUME: /* Alias for: tsr. 1 */ + op[nopnds++] = GEN_INT (1); + break; + case RS6000_BIF_TSUSPEND: /* Alias for: tsr. 0 */ + op[nopnds++] = GEN_INT (0); + break; + default: + break; + } - /* Execute the autogenerated initialization code for builtins. */ - rs6000_init_generated_builtins (); + /* If this builtin accesses SPRs, then pass in the appropriate + SPR number and SPR regno as the last two operands. */ + rtx cr = NULL_RTX; + if (uses_spr) + { + machine_mode mode = TARGET_POWERPC64 ? DImode : SImode; + op[nopnds++] = gen_rtx_CONST_INT (mode, new_htm_spr_num (fcode)); + } + /* If this builtin accesses a CR field, then pass in a scratch + CR field as the last operand. */ + else if (bif_is_htmcr (*bifaddr)) + { + cr = gen_reg_rtx (CCmode); + op[nopnds++] = cr; + } + + rtx pat; + switch (nopnds) + { + case 1: + pat = GEN_FCN (icode) (op[0]); + break; + case 2: + pat = GEN_FCN (icode) (op[0], op[1]); + break; + case 3: + pat = GEN_FCN (icode) (op[0], op[1], op[2]); + break; + case 4: + pat = GEN_FCN (icode) (op[0], op[1], op[2], op[3]); + break; + default: + gcc_unreachable (); + } + if (!pat) + return NULL_RTX; + emit_insn (pat); + + if (bif_is_htmcr (*bifaddr)) + { + if (fcode == RS6000_BIF_TBEGIN) + { + /* Emit code to set TARGET to true or false depending on + whether the tbegin. instruction succeeded or failed + to start a transaction. We do this by placing the 1's + complement of CR's EQ bit into TARGET. */ + rtx scratch = gen_reg_rtx (SImode); + emit_insn (gen_rtx_SET (scratch, + gen_rtx_EQ (SImode, cr, + const0_rtx))); + emit_insn (gen_rtx_SET (target, + gen_rtx_XOR (SImode, scratch, + GEN_INT (1)))); + } + else + { + /* Emit code to copy the 4-bit condition register field + CR into the least significant end of register TARGET. */ + rtx scratch1 = gen_reg_rtx (SImode); + rtx scratch2 = gen_reg_rtx (SImode); + rtx subreg = simplify_gen_subreg (CCmode, scratch1, SImode, 0); + emit_insn (gen_movcc (subreg, cr)); + emit_insn (gen_lshrsi3 (scratch2, scratch1, GEN_INT (28))); + emit_insn (gen_andsi3 (target, scratch2, GEN_INT (0xf))); + } + } + + if (nonvoid) + return target; + return const0_rtx; +} + +/* Expand an expression EXP that calls a built-in function, + with result going to TARGET if that's convenient + (and in mode MODE if that's convenient). + SUBTARGET may be used as the target for computing one of EXP's operands. + IGNORE is nonzero if the value is to be ignored. + Use the new builtin infrastructure. */ +static rtx +rs6000_expand_new_builtin (tree exp, rtx target, + rtx /* subtarget */, + machine_mode /* mode */, + int ignore) +{ + tree fndecl = TREE_OPERAND (CALL_EXPR_FN (exp), 0); + enum rs6000_gen_builtins fcode + = (enum rs6000_gen_builtins) DECL_MD_FUNCTION_CODE (fndecl); + size_t uns_fcode = (size_t)fcode; + enum insn_code icode = rs6000_builtin_info_x[uns_fcode].icode; + + /* TODO: The following commentary and code is inherited from the original + builtin processing code. The commentary is a bit confusing, with the + intent being that KFmode is always IEEE-128, IFmode is always IBM + double-double, and TFmode is the current long double. The code is + confusing in that it converts from KFmode to TFmode pattern names, + when the other direction is more intuitive. Try to address this. */ + + /* We have two different modes (KFmode, TFmode) that are the IEEE + 128-bit floating point type, depending on whether long double is the + IBM extended double (KFmode) or long double is IEEE 128-bit (TFmode). + It is simpler if we only define one variant of the built-in function, + and switch the code when defining it, rather than defining two built- + ins and using the overload table in rs6000-c.c to switch between the + two. If we don't have the proper assembler, don't do this switch + because CODE_FOR_*kf* and CODE_FOR_*tf* will be CODE_FOR_nothing. */ + if (FLOAT128_IEEE_P (TFmode)) + switch (icode) + { + case CODE_FOR_sqrtkf2_odd: + icode = CODE_FOR_sqrttf2_odd; + break; + case CODE_FOR_trunckfdf2_odd: + icode = CODE_FOR_trunctfdf2_odd; + break; + case CODE_FOR_addkf3_odd: + icode = CODE_FOR_addtf3_odd; + break; + case CODE_FOR_subkf3_odd: + icode = CODE_FOR_subtf3_odd; + break; + case CODE_FOR_mulkf3_odd: + icode = CODE_FOR_multf3_odd; + break; + case CODE_FOR_divkf3_odd: + icode = CODE_FOR_divtf3_odd; + break; + case CODE_FOR_fmakf4_odd: + icode = CODE_FOR_fmatf4_odd; + break; + case CODE_FOR_xsxexpqp_kf: + icode = CODE_FOR_xsxexpqp_tf; + break; + case CODE_FOR_xsxsigqp_kf: + icode = CODE_FOR_xsxsigqp_tf; + break; + case CODE_FOR_xststdcnegqp_kf: + icode = CODE_FOR_xststdcnegqp_tf; + break; + case CODE_FOR_xsiexpqp_kf: + icode = CODE_FOR_xsiexpqp_tf; + break; + case CODE_FOR_xsiexpqpf_kf: + icode = CODE_FOR_xsiexpqpf_tf; + break; + case CODE_FOR_xststdcqp_kf: + icode = CODE_FOR_xststdcqp_tf; + break; + case CODE_FOR_xscmpexpqp_eq_kf: + icode = CODE_FOR_xscmpexpqp_eq_tf; + break; + case CODE_FOR_xscmpexpqp_lt_kf: + icode = CODE_FOR_xscmpexpqp_lt_tf; + break; + case CODE_FOR_xscmpexpqp_gt_kf: + icode = CODE_FOR_xscmpexpqp_gt_tf; + break; + case CODE_FOR_xscmpexpqp_unordered_kf: + icode = CODE_FOR_xscmpexpqp_unordered_tf; + break; + default: + break; + } - if (TARGET_DEBUG_BUILTIN) - { - fprintf (stderr, "\nAutogenerated built-in functions:\n\n"); - for (int i = 1; i < (int) RS6000_BIF_MAX; i++) - { - bif_enable e = rs6000_builtin_info_x[i].enable; - if (e == ENB_P5 && !TARGET_POPCNTB) - continue; - if (e == ENB_P6 && !TARGET_CMPB) - continue; - if (e == ENB_P6_64 && !(TARGET_CMPB && TARGET_POWERPC64)) - continue; - if (e == ENB_ALTIVEC && !TARGET_ALTIVEC) - continue; - if (e == ENB_VSX && !TARGET_VSX) - continue; - if (e == ENB_P7 && !TARGET_POPCNTD) - continue; - if (e == ENB_P7_64 && !(TARGET_POPCNTD && TARGET_POWERPC64)) - continue; - if (e == ENB_P8 && !TARGET_DIRECT_MOVE) - continue; - if (e == ENB_P8V && !TARGET_P8_VECTOR) - continue; - if (e == ENB_P9 && !TARGET_MODULO) - continue; - if (e == ENB_P9_64 && !(TARGET_MODULO && TARGET_POWERPC64)) - continue; - if (e == ENB_P9V && !TARGET_P9_VECTOR) - continue; - if (e == ENB_IEEE128_HW && !TARGET_FLOAT128_HW) - continue; - if (e == ENB_DFP && !TARGET_DFP) - continue; - if (e == ENB_CRYPTO && !TARGET_CRYPTO) - continue; - if (e == ENB_HTM && !TARGET_HTM) - continue; - if (e == ENB_P10 && !TARGET_POWER10) - continue; - if (e == ENB_P10_64 && !(TARGET_POWER10 && TARGET_POWERPC64)) - continue; - if (e == ENB_MMA && !TARGET_MMA) - continue; - tree fntype = rs6000_builtin_info_x[i].fntype; - tree t = TREE_TYPE (fntype); - fprintf (stderr, "%s %s (", rs6000_type_string (t), - rs6000_builtin_info_x[i].bifname); - t = TYPE_ARG_TYPES (fntype); - while (t && TREE_VALUE (t) != void_type_node) - { - fprintf (stderr, "%s", - rs6000_type_string (TREE_VALUE (t))); - t = TREE_CHAIN (t); - if (t && TREE_VALUE (t) != void_type_node) - fprintf (stderr, ", "); - } - fprintf (stderr, "); %s [%4d]\n", - rs6000_builtin_info_x[i].attr_string, (int) i); - } - fprintf (stderr, "\nEnd autogenerated built-in functions.\n\n\n"); - } + /* In case of "#pragma target" changes, we initialize all builtins + but check for actual availability now, during expand time. For + invalid builtins, generate a normal call. */ + bifdata *bifaddr = &rs6000_builtin_info_x[uns_fcode]; + bif_enable e = bifaddr->enable; - if (TARGET_XCOFF) + if (!(e == ENB_ALWAYS + || (e == ENB_P5 && TARGET_POPCNTB) + || (e == ENB_P6 && TARGET_CMPB) + || (e == ENB_P6_64 && TARGET_CMPB && TARGET_POWERPC64) + || (e == ENB_ALTIVEC && TARGET_ALTIVEC) + || (e == ENB_CELL && TARGET_ALTIVEC && rs6000_cpu == PROCESSOR_CELL) + || (e == ENB_VSX && TARGET_VSX) + || (e == ENB_P7 && TARGET_POPCNTD) + || (e == ENB_P7_64 && TARGET_POPCNTD && TARGET_POWERPC64) + || (e == ENB_P8 && TARGET_DIRECT_MOVE) + || (e == ENB_P8V && TARGET_P8_VECTOR) + || (e == ENB_P9 && TARGET_MODULO) + || (e == ENB_P9_64 && TARGET_MODULO && TARGET_POWERPC64) + || (e == ENB_P9V && TARGET_P9_VECTOR) + || (e == ENB_IEEE128_HW && TARGET_FLOAT128_HW) + || (e == ENB_DFP && TARGET_DFP) + || (e == ENB_CRYPTO && TARGET_CRYPTO) + || (e == ENB_HTM && TARGET_HTM) + || (e == ENB_P10 && TARGET_POWER10) + || (e == ENB_P10_64 && TARGET_POWER10 && TARGET_POWERPC64) + || (e == ENB_MMA && TARGET_MMA))) { - /* AIX libm provides clog as __clog. */ - if ((tdecl = builtin_decl_explicit (BUILT_IN_CLOG)) != NULL_TREE) - set_user_assembler_name (tdecl, "__clog"); - - /* When long double is 64 bit, some long double builtins of libc - functions (like __builtin_frexpl) must call the double version - (frexp) not the long double version (frexpl) that expects a 128 bit - argument. */ - if (! TARGET_LONG_DOUBLE_128) - { - if ((tdecl = builtin_decl_explicit (BUILT_IN_FMODL)) != NULL_TREE) - set_user_assembler_name (tdecl, "fmod"); - if ((tdecl = builtin_decl_explicit (BUILT_IN_FREXPL)) != NULL_TREE) - set_user_assembler_name (tdecl, "frexp"); - if ((tdecl = builtin_decl_explicit (BUILT_IN_LDEXPL)) != NULL_TREE) - set_user_assembler_name (tdecl, "ldexp"); - if ((tdecl = builtin_decl_explicit (BUILT_IN_MODFL)) != NULL_TREE) - set_user_assembler_name (tdecl, "modf"); - } + rs6000_invalid_new_builtin (fcode); + return expand_call (exp, target, ignore); } - if (new_builtins_are_live) + if (bif_is_nosoft (*bifaddr) + && rs6000_isa_flags & OPTION_MASK_SOFT_FLOAT) { - altivec_builtin_mask_for_load - = rs6000_builtin_decls_x[RS6000_BIF_MASK_FOR_LOAD]; - -#ifdef SUBTARGET_INIT_BUILTINS - SUBTARGET_INIT_BUILTINS; -#endif - return; + error ("%<%s%> not supported with %<-msoft-float%>", + bifaddr->bifname); + return const0_rtx; } - /* Create Altivec, VSX and MMA builtins on machines with at least the - general purpose extensions (970 and newer) to allow the use of - the target attribute. */ - if (TARGET_EXTRA_BUILTINS) + if (bif_is_no32bit (*bifaddr) && TARGET_32BIT) { - altivec_init_builtins (); - mma_init_builtins (); + error ("%<%s%> is not supported in 32-bit mode", bifaddr->bifname); + return const0_rtx; } - if (TARGET_HTM) - htm_init_builtins (); - - if (TARGET_EXTRA_BUILTINS) - rs6000_common_init_builtins (); - - ftype = builtin_function_type (DFmode, DFmode, DFmode, VOIDmode, - RS6000_BUILTIN_RECIP, "__builtin_recipdiv"); - def_builtin ("__builtin_recipdiv", ftype, RS6000_BUILTIN_RECIP); - - ftype = builtin_function_type (SFmode, SFmode, SFmode, VOIDmode, - RS6000_BUILTIN_RECIPF, "__builtin_recipdivf"); - def_builtin ("__builtin_recipdivf", ftype, RS6000_BUILTIN_RECIPF); - - ftype = builtin_function_type (DFmode, DFmode, VOIDmode, VOIDmode, - RS6000_BUILTIN_RSQRT, "__builtin_rsqrt"); - def_builtin ("__builtin_rsqrt", ftype, RS6000_BUILTIN_RSQRT); - - ftype = builtin_function_type (SFmode, SFmode, VOIDmode, VOIDmode, - RS6000_BUILTIN_RSQRTF, "__builtin_rsqrtf"); - def_builtin ("__builtin_rsqrtf", ftype, RS6000_BUILTIN_RSQRTF); - - mode = (TARGET_64BIT) ? DImode : SImode; - ftype = builtin_function_type (mode, mode, mode, VOIDmode, - POWER7_BUILTIN_BPERMD, "__builtin_bpermd"); - def_builtin ("__builtin_bpermd", ftype, POWER7_BUILTIN_BPERMD); - - ftype = build_function_type_list (unsigned_intDI_type_node, - NULL_TREE); - def_builtin ("__builtin_ppc_get_timebase", ftype, RS6000_BUILTIN_GET_TB); - - if (TARGET_64BIT) - ftype = build_function_type_list (unsigned_intDI_type_node, - NULL_TREE); - else - ftype = build_function_type_list (unsigned_intSI_type_node, - NULL_TREE); - def_builtin ("__builtin_ppc_mftb", ftype, RS6000_BUILTIN_MFTB); - - ftype = build_function_type_list (double_type_node, NULL_TREE); - def_builtin ("__builtin_mffs", ftype, RS6000_BUILTIN_MFFS); - - ftype = build_function_type_list (double_type_node, NULL_TREE); - def_builtin ("__builtin_mffsl", ftype, RS6000_BUILTIN_MFFSL); - - ftype = build_function_type_list (void_type_node, - intSI_type_node, - NULL_TREE); - def_builtin ("__builtin_mtfsb0", ftype, RS6000_BUILTIN_MTFSB0); - - ftype = build_function_type_list (void_type_node, - intSI_type_node, - NULL_TREE); - def_builtin ("__builtin_mtfsb1", ftype, RS6000_BUILTIN_MTFSB1); - - ftype = build_function_type_list (void_type_node, - intDI_type_node, - NULL_TREE); - def_builtin ("__builtin_set_fpscr_rn", ftype, RS6000_BUILTIN_SET_FPSCR_RN); - - ftype = build_function_type_list (void_type_node, - intDI_type_node, - NULL_TREE); - def_builtin ("__builtin_set_fpscr_drn", ftype, RS6000_BUILTIN_SET_FPSCR_DRN); - - ftype = build_function_type_list (void_type_node, - intSI_type_node, double_type_node, - NULL_TREE); - def_builtin ("__builtin_mtfsf", ftype, RS6000_BUILTIN_MTFSF); - - ftype = build_function_type_list (void_type_node, NULL_TREE); - def_builtin ("__builtin_cpu_init", ftype, RS6000_BUILTIN_CPU_INIT); - def_builtin ("__builtin_ppc_speculation_barrier", ftype, - MISC_BUILTIN_SPEC_BARRIER); - - ftype = build_function_type_list (bool_int_type_node, const_ptr_type_node, - NULL_TREE); - def_builtin ("__builtin_cpu_is", ftype, RS6000_BUILTIN_CPU_IS); - def_builtin ("__builtin_cpu_supports", ftype, RS6000_BUILTIN_CPU_SUPPORTS); - -#ifdef SUBTARGET_INIT_BUILTINS - SUBTARGET_INIT_BUILTINS; -#endif - /* Register the compatibility builtins after all of the normal - builtins have been defined. */ - const struct builtin_compatibility *d = bdesc_compat; - unsigned i; - for (i = 0; i < ARRAY_SIZE (bdesc_compat); i++, d++) + if (bif_is_ibmld (*bifaddr) && !FLOAT128_2REG_P (TFmode)) { - tree decl = rs6000_builtin_decls[(int)d->code]; - if (decl != NULL) - add_builtin_function (d->name, TREE_TYPE (decl), (int)d->code, - BUILT_IN_MD, NULL, NULL_TREE); + error ("%<%s%> requires % to be IBM 128-bit format", + bifaddr->bifname); + return const0_rtx; } -} -static tree -rs6000_new_builtin_decl (unsigned code, bool /* initialize_p */) -{ - rs6000_gen_builtins fcode = (rs6000_gen_builtins) code; - - if (fcode >= RS6000_OVLD_MAX) - return error_mark_node; + if (bif_is_cpu (*bifaddr)) + return new_cpu_expand_builtin (fcode, exp, target); - return rs6000_builtin_decls_x[code]; -} + if (bif_is_init (*bifaddr)) + return altivec_expand_vec_init_builtin (TREE_TYPE (exp), exp, target); -/* Returns the rs6000 builtin decl for CODE. Note that we don't check - the builtin mask here since there could be some #pragma/attribute - target functions and the rs6000_builtin_mask could be wrong when - this checking happens, though it will be updated properly later. */ + if (bif_is_set (*bifaddr)) + return altivec_expand_vec_set_builtin (exp); -tree -rs6000_builtin_decl (unsigned code, bool initialize_p ATTRIBUTE_UNUSED) -{ - if (new_builtins_are_live) - return rs6000_new_builtin_decl (code, initialize_p); + if (bif_is_extract (*bifaddr)) + return altivec_expand_vec_ext_builtin (exp, target); - if (code >= RS6000_BUILTIN_COUNT) - return error_mark_node; + if (bif_is_predicate (*bifaddr)) + return altivec_expand_predicate_builtin (icode, exp, target); - return rs6000_builtin_decls[code]; -} + if (bif_is_htm (*bifaddr)) + return new_htm_expand_builtin (bifaddr, fcode, exp, target); -static void -altivec_init_builtins (void) -{ - const struct builtin_description *d; - size_t i; - tree ftype; - tree decl; - - tree pvoid_type_node = build_pointer_type (void_type_node); - - tree int_ftype_opaque - = build_function_type_list (integer_type_node, - opaque_V4SI_type_node, NULL_TREE); - tree opaque_ftype_opaque - = build_function_type_list (integer_type_node, NULL_TREE); - tree opaque_ftype_opaque_int - = build_function_type_list (opaque_V4SI_type_node, - opaque_V4SI_type_node, integer_type_node, NULL_TREE); - tree opaque_ftype_opaque_opaque_int - = build_function_type_list (opaque_V4SI_type_node, - opaque_V4SI_type_node, opaque_V4SI_type_node, - integer_type_node, NULL_TREE); - tree opaque_ftype_opaque_opaque_opaque - = build_function_type_list (opaque_V4SI_type_node, - opaque_V4SI_type_node, opaque_V4SI_type_node, - opaque_V4SI_type_node, NULL_TREE); - tree opaque_ftype_opaque_opaque - = build_function_type_list (opaque_V4SI_type_node, - opaque_V4SI_type_node, opaque_V4SI_type_node, - NULL_TREE); - tree int_ftype_int_opaque_opaque - = build_function_type_list (integer_type_node, - integer_type_node, opaque_V4SI_type_node, - opaque_V4SI_type_node, NULL_TREE); - tree int_ftype_int_v4si_v4si - = build_function_type_list (integer_type_node, - integer_type_node, V4SI_type_node, - V4SI_type_node, NULL_TREE); - tree int_ftype_int_v2di_v2di - = build_function_type_list (integer_type_node, - integer_type_node, V2DI_type_node, - V2DI_type_node, NULL_TREE); - tree int_ftype_int_v1ti_v1ti - = build_function_type_list (integer_type_node, - integer_type_node, V1TI_type_node, - V1TI_type_node, NULL_TREE); - tree void_ftype_v4si - = build_function_type_list (void_type_node, V4SI_type_node, NULL_TREE); - tree v8hi_ftype_void - = build_function_type_list (V8HI_type_node, NULL_TREE); - tree void_ftype_void - = build_function_type_list (void_type_node, NULL_TREE); - tree void_ftype_int - = build_function_type_list (void_type_node, integer_type_node, NULL_TREE); - - tree opaque_ftype_long_pcvoid - = build_function_type_list (opaque_V4SI_type_node, - long_integer_type_node, pcvoid_type_node, - NULL_TREE); - tree v16qi_ftype_pcvoid - = build_function_type_list (V16QI_type_node, - pcvoid_type_node, - NULL_TREE); - tree v16qi_ftype_long_pcvoid - = build_function_type_list (V16QI_type_node, - long_integer_type_node, pcvoid_type_node, - NULL_TREE); - tree v8hi_ftype_long_pcvoid - = build_function_type_list (V8HI_type_node, - long_integer_type_node, pcvoid_type_node, - NULL_TREE); - tree v4si_ftype_long_pcvoid - = build_function_type_list (V4SI_type_node, - long_integer_type_node, pcvoid_type_node, - NULL_TREE); - tree v4sf_ftype_long_pcvoid - = build_function_type_list (V4SF_type_node, - long_integer_type_node, pcvoid_type_node, - NULL_TREE); - tree v2df_ftype_long_pcvoid - = build_function_type_list (V2DF_type_node, - long_integer_type_node, pcvoid_type_node, - NULL_TREE); - tree v2di_ftype_long_pcvoid - = build_function_type_list (V2DI_type_node, - long_integer_type_node, pcvoid_type_node, - NULL_TREE); - tree v1ti_ftype_long_pcvoid - = build_function_type_list (V1TI_type_node, - long_integer_type_node, pcvoid_type_node, - NULL_TREE); - - tree void_ftype_opaque_long_pvoid - = build_function_type_list (void_type_node, - opaque_V4SI_type_node, long_integer_type_node, - pvoid_type_node, NULL_TREE); - tree void_ftype_v4si_long_pvoid - = build_function_type_list (void_type_node, - V4SI_type_node, long_integer_type_node, - pvoid_type_node, NULL_TREE); - tree void_ftype_v16qi_long_pvoid - = build_function_type_list (void_type_node, - V16QI_type_node, long_integer_type_node, - pvoid_type_node, NULL_TREE); - - tree void_ftype_v16qi_pvoid_long - = build_function_type_list (void_type_node, - V16QI_type_node, pvoid_type_node, - long_integer_type_node, NULL_TREE); - - tree void_ftype_v8hi_long_pvoid - = build_function_type_list (void_type_node, - V8HI_type_node, long_integer_type_node, - pvoid_type_node, NULL_TREE); - tree void_ftype_v4sf_long_pvoid - = build_function_type_list (void_type_node, - V4SF_type_node, long_integer_type_node, - pvoid_type_node, NULL_TREE); - tree void_ftype_v2df_long_pvoid - = build_function_type_list (void_type_node, - V2DF_type_node, long_integer_type_node, - pvoid_type_node, NULL_TREE); - tree void_ftype_v1ti_long_pvoid - = build_function_type_list (void_type_node, - V1TI_type_node, long_integer_type_node, - pvoid_type_node, NULL_TREE); - tree void_ftype_v2di_long_pvoid - = build_function_type_list (void_type_node, - V2DI_type_node, long_integer_type_node, - pvoid_type_node, NULL_TREE); - tree int_ftype_int_v8hi_v8hi - = build_function_type_list (integer_type_node, - integer_type_node, V8HI_type_node, - V8HI_type_node, NULL_TREE); - tree int_ftype_int_v16qi_v16qi - = build_function_type_list (integer_type_node, - integer_type_node, V16QI_type_node, - V16QI_type_node, NULL_TREE); - tree int_ftype_int_v4sf_v4sf - = build_function_type_list (integer_type_node, - integer_type_node, V4SF_type_node, - V4SF_type_node, NULL_TREE); - tree int_ftype_int_v2df_v2df - = build_function_type_list (integer_type_node, - integer_type_node, V2DF_type_node, - V2DF_type_node, NULL_TREE); - tree v2di_ftype_v2di - = build_function_type_list (V2DI_type_node, V2DI_type_node, NULL_TREE); - tree v4si_ftype_v4si - = build_function_type_list (V4SI_type_node, V4SI_type_node, NULL_TREE); - tree v8hi_ftype_v8hi - = build_function_type_list (V8HI_type_node, V8HI_type_node, NULL_TREE); - tree v16qi_ftype_v16qi - = build_function_type_list (V16QI_type_node, V16QI_type_node, NULL_TREE); - tree v4sf_ftype_v4sf - = build_function_type_list (V4SF_type_node, V4SF_type_node, NULL_TREE); - tree v2df_ftype_v2df - = build_function_type_list (V2DF_type_node, V2DF_type_node, NULL_TREE); - tree void_ftype_pcvoid_int_int - = build_function_type_list (void_type_node, - pcvoid_type_node, integer_type_node, - integer_type_node, NULL_TREE); - - def_builtin ("__builtin_altivec_mtvscr", void_ftype_v4si, ALTIVEC_BUILTIN_MTVSCR); - def_builtin ("__builtin_altivec_mfvscr", v8hi_ftype_void, ALTIVEC_BUILTIN_MFVSCR); - def_builtin ("__builtin_altivec_dssall", void_ftype_void, ALTIVEC_BUILTIN_DSSALL); - def_builtin ("__builtin_altivec_dss", void_ftype_int, ALTIVEC_BUILTIN_DSS); - def_builtin ("__builtin_altivec_lvsl", v16qi_ftype_long_pcvoid, ALTIVEC_BUILTIN_LVSL); - def_builtin ("__builtin_altivec_lvsr", v16qi_ftype_long_pcvoid, ALTIVEC_BUILTIN_LVSR); - def_builtin ("__builtin_altivec_lvebx", v16qi_ftype_long_pcvoid, ALTIVEC_BUILTIN_LVEBX); - def_builtin ("__builtin_altivec_lvehx", v8hi_ftype_long_pcvoid, ALTIVEC_BUILTIN_LVEHX); - def_builtin ("__builtin_altivec_lvewx", v4si_ftype_long_pcvoid, ALTIVEC_BUILTIN_LVEWX); - def_builtin ("__builtin_altivec_se_lxvrbx", v16qi_ftype_long_pcvoid, P10_BUILTIN_SE_LXVRBX); - def_builtin ("__builtin_altivec_se_lxvrhx", v8hi_ftype_long_pcvoid, P10_BUILTIN_SE_LXVRHX); - def_builtin ("__builtin_altivec_se_lxvrwx", v4si_ftype_long_pcvoid, P10_BUILTIN_SE_LXVRWX); - def_builtin ("__builtin_altivec_se_lxvrdx", v2di_ftype_long_pcvoid, P10_BUILTIN_SE_LXVRDX); - def_builtin ("__builtin_altivec_ze_lxvrbx", v16qi_ftype_long_pcvoid, P10_BUILTIN_ZE_LXVRBX); - def_builtin ("__builtin_altivec_ze_lxvrhx", v8hi_ftype_long_pcvoid, P10_BUILTIN_ZE_LXVRHX); - def_builtin ("__builtin_altivec_ze_lxvrwx", v4si_ftype_long_pcvoid, P10_BUILTIN_ZE_LXVRWX); - def_builtin ("__builtin_altivec_ze_lxvrdx", v2di_ftype_long_pcvoid, P10_BUILTIN_ZE_LXVRDX); - def_builtin ("__builtin_altivec_tr_stxvrbx", void_ftype_v1ti_long_pvoid, P10_BUILTIN_TR_STXVRBX); - def_builtin ("__builtin_altivec_tr_stxvrhx", void_ftype_v1ti_long_pvoid, P10_BUILTIN_TR_STXVRHX); - def_builtin ("__builtin_altivec_tr_stxvrwx", void_ftype_v1ti_long_pvoid, P10_BUILTIN_TR_STXVRWX); - def_builtin ("__builtin_altivec_tr_stxvrdx", void_ftype_v1ti_long_pvoid, P10_BUILTIN_TR_STXVRDX); - def_builtin ("__builtin_altivec_lvxl", v4si_ftype_long_pcvoid, ALTIVEC_BUILTIN_LVXL); - def_builtin ("__builtin_altivec_lvxl_v2df", v2df_ftype_long_pcvoid, - ALTIVEC_BUILTIN_LVXL_V2DF); - def_builtin ("__builtin_altivec_lvxl_v2di", v2di_ftype_long_pcvoid, - ALTIVEC_BUILTIN_LVXL_V2DI); - def_builtin ("__builtin_altivec_lvxl_v4sf", v4sf_ftype_long_pcvoid, - ALTIVEC_BUILTIN_LVXL_V4SF); - def_builtin ("__builtin_altivec_lvxl_v4si", v4si_ftype_long_pcvoid, - ALTIVEC_BUILTIN_LVXL_V4SI); - def_builtin ("__builtin_altivec_lvxl_v8hi", v8hi_ftype_long_pcvoid, - ALTIVEC_BUILTIN_LVXL_V8HI); - def_builtin ("__builtin_altivec_lvxl_v16qi", v16qi_ftype_long_pcvoid, - ALTIVEC_BUILTIN_LVXL_V16QI); - def_builtin ("__builtin_altivec_lvx", v4si_ftype_long_pcvoid, ALTIVEC_BUILTIN_LVX); - def_builtin ("__builtin_altivec_lvx_v1ti", v1ti_ftype_long_pcvoid, - ALTIVEC_BUILTIN_LVX_V1TI); - def_builtin ("__builtin_altivec_lvx_v2df", v2df_ftype_long_pcvoid, - ALTIVEC_BUILTIN_LVX_V2DF); - def_builtin ("__builtin_altivec_lvx_v2di", v2di_ftype_long_pcvoid, - ALTIVEC_BUILTIN_LVX_V2DI); - def_builtin ("__builtin_altivec_lvx_v4sf", v4sf_ftype_long_pcvoid, - ALTIVEC_BUILTIN_LVX_V4SF); - def_builtin ("__builtin_altivec_lvx_v4si", v4si_ftype_long_pcvoid, - ALTIVEC_BUILTIN_LVX_V4SI); - def_builtin ("__builtin_altivec_lvx_v8hi", v8hi_ftype_long_pcvoid, - ALTIVEC_BUILTIN_LVX_V8HI); - def_builtin ("__builtin_altivec_lvx_v16qi", v16qi_ftype_long_pcvoid, - ALTIVEC_BUILTIN_LVX_V16QI); - def_builtin ("__builtin_altivec_stvx", void_ftype_v4si_long_pvoid, ALTIVEC_BUILTIN_STVX); - def_builtin ("__builtin_altivec_stvx_v2df", void_ftype_v2df_long_pvoid, - ALTIVEC_BUILTIN_STVX_V2DF); - def_builtin ("__builtin_altivec_stvx_v2di", void_ftype_v2di_long_pvoid, - ALTIVEC_BUILTIN_STVX_V2DI); - def_builtin ("__builtin_altivec_stvx_v4sf", void_ftype_v4sf_long_pvoid, - ALTIVEC_BUILTIN_STVX_V4SF); - def_builtin ("__builtin_altivec_stvx_v4si", void_ftype_v4si_long_pvoid, - ALTIVEC_BUILTIN_STVX_V4SI); - def_builtin ("__builtin_altivec_stvx_v8hi", void_ftype_v8hi_long_pvoid, - ALTIVEC_BUILTIN_STVX_V8HI); - def_builtin ("__builtin_altivec_stvx_v16qi", void_ftype_v16qi_long_pvoid, - ALTIVEC_BUILTIN_STVX_V16QI); - def_builtin ("__builtin_altivec_stvewx", void_ftype_v4si_long_pvoid, ALTIVEC_BUILTIN_STVEWX); - def_builtin ("__builtin_altivec_stvxl", void_ftype_v4si_long_pvoid, ALTIVEC_BUILTIN_STVXL); - def_builtin ("__builtin_altivec_stvxl_v2df", void_ftype_v2df_long_pvoid, - ALTIVEC_BUILTIN_STVXL_V2DF); - def_builtin ("__builtin_altivec_stvxl_v2di", void_ftype_v2di_long_pvoid, - ALTIVEC_BUILTIN_STVXL_V2DI); - def_builtin ("__builtin_altivec_stvxl_v4sf", void_ftype_v4sf_long_pvoid, - ALTIVEC_BUILTIN_STVXL_V4SF); - def_builtin ("__builtin_altivec_stvxl_v4si", void_ftype_v4si_long_pvoid, - ALTIVEC_BUILTIN_STVXL_V4SI); - def_builtin ("__builtin_altivec_stvxl_v8hi", void_ftype_v8hi_long_pvoid, - ALTIVEC_BUILTIN_STVXL_V8HI); - def_builtin ("__builtin_altivec_stvxl_v16qi", void_ftype_v16qi_long_pvoid, - ALTIVEC_BUILTIN_STVXL_V16QI); - def_builtin ("__builtin_altivec_stvebx", void_ftype_v16qi_long_pvoid, ALTIVEC_BUILTIN_STVEBX); - def_builtin ("__builtin_altivec_stvehx", void_ftype_v8hi_long_pvoid, ALTIVEC_BUILTIN_STVEHX); - def_builtin ("__builtin_vec_ld", opaque_ftype_long_pcvoid, ALTIVEC_BUILTIN_VEC_LD); - def_builtin ("__builtin_vec_lde", opaque_ftype_long_pcvoid, ALTIVEC_BUILTIN_VEC_LDE); - def_builtin ("__builtin_vec_ldl", opaque_ftype_long_pcvoid, ALTIVEC_BUILTIN_VEC_LDL); - def_builtin ("__builtin_vec_lvsl", v16qi_ftype_long_pcvoid, ALTIVEC_BUILTIN_VEC_LVSL); - def_builtin ("__builtin_vec_lvsr", v16qi_ftype_long_pcvoid, ALTIVEC_BUILTIN_VEC_LVSR); - def_builtin ("__builtin_vec_lvebx", v16qi_ftype_long_pcvoid, ALTIVEC_BUILTIN_VEC_LVEBX); - def_builtin ("__builtin_vec_lvehx", v8hi_ftype_long_pcvoid, ALTIVEC_BUILTIN_VEC_LVEHX); - def_builtin ("__builtin_vec_lvewx", v4si_ftype_long_pcvoid, ALTIVEC_BUILTIN_VEC_LVEWX); - def_builtin ("__builtin_vec_se_lxvrx", v1ti_ftype_long_pcvoid, P10_BUILTIN_VEC_SE_LXVRX); - def_builtin ("__builtin_vec_ze_lxvrx", v1ti_ftype_long_pcvoid, P10_BUILTIN_VEC_ZE_LXVRX); - def_builtin ("__builtin_vec_tr_stxvrx", void_ftype_opaque_long_pvoid, P10_BUILTIN_VEC_TR_STXVRX); - def_builtin ("__builtin_vec_st", void_ftype_opaque_long_pvoid, ALTIVEC_BUILTIN_VEC_ST); - def_builtin ("__builtin_vec_ste", void_ftype_opaque_long_pvoid, ALTIVEC_BUILTIN_VEC_STE); - def_builtin ("__builtin_vec_stl", void_ftype_opaque_long_pvoid, ALTIVEC_BUILTIN_VEC_STL); - def_builtin ("__builtin_vec_stvewx", void_ftype_opaque_long_pvoid, ALTIVEC_BUILTIN_VEC_STVEWX); - def_builtin ("__builtin_vec_stvebx", void_ftype_opaque_long_pvoid, ALTIVEC_BUILTIN_VEC_STVEBX); - def_builtin ("__builtin_vec_stvehx", void_ftype_opaque_long_pvoid, ALTIVEC_BUILTIN_VEC_STVEHX); - - def_builtin ("__builtin_vsx_lxvd2x_v2df", v2df_ftype_long_pcvoid, - VSX_BUILTIN_LXVD2X_V2DF); - def_builtin ("__builtin_vsx_lxvd2x_v2di", v2di_ftype_long_pcvoid, - VSX_BUILTIN_LXVD2X_V2DI); - def_builtin ("__builtin_vsx_lxvw4x_v4sf", v4sf_ftype_long_pcvoid, - VSX_BUILTIN_LXVW4X_V4SF); - def_builtin ("__builtin_vsx_lxvw4x_v4si", v4si_ftype_long_pcvoid, - VSX_BUILTIN_LXVW4X_V4SI); - def_builtin ("__builtin_vsx_lxvw4x_v8hi", v8hi_ftype_long_pcvoid, - VSX_BUILTIN_LXVW4X_V8HI); - def_builtin ("__builtin_vsx_lxvw4x_v16qi", v16qi_ftype_long_pcvoid, - VSX_BUILTIN_LXVW4X_V16QI); - def_builtin ("__builtin_vsx_stxvd2x_v2df", void_ftype_v2df_long_pvoid, - VSX_BUILTIN_STXVD2X_V2DF); - def_builtin ("__builtin_vsx_stxvd2x_v2di", void_ftype_v2di_long_pvoid, - VSX_BUILTIN_STXVD2X_V2DI); - def_builtin ("__builtin_vsx_stxvw4x_v4sf", void_ftype_v4sf_long_pvoid, - VSX_BUILTIN_STXVW4X_V4SF); - def_builtin ("__builtin_vsx_stxvw4x_v4si", void_ftype_v4si_long_pvoid, - VSX_BUILTIN_STXVW4X_V4SI); - def_builtin ("__builtin_vsx_stxvw4x_v8hi", void_ftype_v8hi_long_pvoid, - VSX_BUILTIN_STXVW4X_V8HI); - def_builtin ("__builtin_vsx_stxvw4x_v16qi", void_ftype_v16qi_long_pvoid, - VSX_BUILTIN_STXVW4X_V16QI); - - def_builtin ("__builtin_vsx_ld_elemrev_v2df", v2df_ftype_long_pcvoid, - VSX_BUILTIN_LD_ELEMREV_V2DF); - def_builtin ("__builtin_vsx_ld_elemrev_v2di", v2di_ftype_long_pcvoid, - VSX_BUILTIN_LD_ELEMREV_V2DI); - def_builtin ("__builtin_vsx_ld_elemrev_v4sf", v4sf_ftype_long_pcvoid, - VSX_BUILTIN_LD_ELEMREV_V4SF); - def_builtin ("__builtin_vsx_ld_elemrev_v4si", v4si_ftype_long_pcvoid, - VSX_BUILTIN_LD_ELEMREV_V4SI); - def_builtin ("__builtin_vsx_ld_elemrev_v8hi", v8hi_ftype_long_pcvoid, - VSX_BUILTIN_LD_ELEMREV_V8HI); - def_builtin ("__builtin_vsx_ld_elemrev_v16qi", v16qi_ftype_long_pcvoid, - VSX_BUILTIN_LD_ELEMREV_V16QI); - def_builtin ("__builtin_vsx_st_elemrev_v2df", void_ftype_v2df_long_pvoid, - VSX_BUILTIN_ST_ELEMREV_V2DF); - def_builtin ("__builtin_vsx_st_elemrev_v1ti", void_ftype_v1ti_long_pvoid, - VSX_BUILTIN_ST_ELEMREV_V1TI); - def_builtin ("__builtin_vsx_st_elemrev_v2di", void_ftype_v2di_long_pvoid, - VSX_BUILTIN_ST_ELEMREV_V2DI); - def_builtin ("__builtin_vsx_st_elemrev_v4sf", void_ftype_v4sf_long_pvoid, - VSX_BUILTIN_ST_ELEMREV_V4SF); - def_builtin ("__builtin_vsx_st_elemrev_v4si", void_ftype_v4si_long_pvoid, - VSX_BUILTIN_ST_ELEMREV_V4SI); - def_builtin ("__builtin_vsx_st_elemrev_v8hi", void_ftype_v8hi_long_pvoid, - VSX_BUILTIN_ST_ELEMREV_V8HI); - def_builtin ("__builtin_vsx_st_elemrev_v16qi", void_ftype_v16qi_long_pvoid, - VSX_BUILTIN_ST_ELEMREV_V16QI); - - def_builtin ("__builtin_vec_vsx_ld", opaque_ftype_long_pcvoid, - VSX_BUILTIN_VEC_LD); - def_builtin ("__builtin_vec_vsx_st", void_ftype_opaque_long_pvoid, - VSX_BUILTIN_VEC_ST); - def_builtin ("__builtin_vec_xl", opaque_ftype_long_pcvoid, - VSX_BUILTIN_VEC_XL); - def_builtin ("__builtin_vec_xl_be", opaque_ftype_long_pcvoid, - VSX_BUILTIN_VEC_XL_BE); - def_builtin ("__builtin_vec_xst", void_ftype_opaque_long_pvoid, - VSX_BUILTIN_VEC_XST); - def_builtin ("__builtin_vec_xst_be", void_ftype_opaque_long_pvoid, - VSX_BUILTIN_VEC_XST_BE); - - def_builtin ("__builtin_vec_step", int_ftype_opaque, ALTIVEC_BUILTIN_VEC_STEP); - def_builtin ("__builtin_vec_splats", opaque_ftype_opaque, ALTIVEC_BUILTIN_VEC_SPLATS); - def_builtin ("__builtin_vec_promote", opaque_ftype_opaque, ALTIVEC_BUILTIN_VEC_PROMOTE); - - def_builtin ("__builtin_vec_sld", opaque_ftype_opaque_opaque_int, ALTIVEC_BUILTIN_VEC_SLD); - def_builtin ("__builtin_vec_splat", opaque_ftype_opaque_int, ALTIVEC_BUILTIN_VEC_SPLAT); - def_builtin ("__builtin_vec_extract", opaque_ftype_opaque_int, ALTIVEC_BUILTIN_VEC_EXTRACT); - def_builtin ("__builtin_vec_insert", opaque_ftype_opaque_opaque_int, ALTIVEC_BUILTIN_VEC_INSERT); - def_builtin ("__builtin_vec_vspltw", opaque_ftype_opaque_int, ALTIVEC_BUILTIN_VEC_VSPLTW); - def_builtin ("__builtin_vec_vsplth", opaque_ftype_opaque_int, ALTIVEC_BUILTIN_VEC_VSPLTH); - def_builtin ("__builtin_vec_vspltb", opaque_ftype_opaque_int, ALTIVEC_BUILTIN_VEC_VSPLTB); - def_builtin ("__builtin_vec_ctf", opaque_ftype_opaque_int, ALTIVEC_BUILTIN_VEC_CTF); - def_builtin ("__builtin_vec_vcfsx", opaque_ftype_opaque_int, ALTIVEC_BUILTIN_VEC_VCFSX); - def_builtin ("__builtin_vec_vcfux", opaque_ftype_opaque_int, ALTIVEC_BUILTIN_VEC_VCFUX); - def_builtin ("__builtin_vec_cts", opaque_ftype_opaque_int, ALTIVEC_BUILTIN_VEC_CTS); - def_builtin ("__builtin_vec_ctu", opaque_ftype_opaque_int, ALTIVEC_BUILTIN_VEC_CTU); - - def_builtin ("__builtin_vec_adde", opaque_ftype_opaque_opaque_opaque, - ALTIVEC_BUILTIN_VEC_ADDE); - def_builtin ("__builtin_vec_addec", opaque_ftype_opaque_opaque_opaque, - ALTIVEC_BUILTIN_VEC_ADDEC); - def_builtin ("__builtin_vec_cmpne", opaque_ftype_opaque_opaque, - ALTIVEC_BUILTIN_VEC_CMPNE); - def_builtin ("__builtin_vec_mul", opaque_ftype_opaque_opaque, - ALTIVEC_BUILTIN_VEC_MUL); - def_builtin ("__builtin_vec_sube", opaque_ftype_opaque_opaque_opaque, - ALTIVEC_BUILTIN_VEC_SUBE); - def_builtin ("__builtin_vec_subec", opaque_ftype_opaque_opaque_opaque, - ALTIVEC_BUILTIN_VEC_SUBEC); - - /* Cell builtins. */ - def_builtin ("__builtin_altivec_lvlx", v16qi_ftype_long_pcvoid, ALTIVEC_BUILTIN_LVLX); - def_builtin ("__builtin_altivec_lvlxl", v16qi_ftype_long_pcvoid, ALTIVEC_BUILTIN_LVLXL); - def_builtin ("__builtin_altivec_lvrx", v16qi_ftype_long_pcvoid, ALTIVEC_BUILTIN_LVRX); - def_builtin ("__builtin_altivec_lvrxl", v16qi_ftype_long_pcvoid, ALTIVEC_BUILTIN_LVRXL); - - def_builtin ("__builtin_vec_lvlx", v16qi_ftype_long_pcvoid, ALTIVEC_BUILTIN_VEC_LVLX); - def_builtin ("__builtin_vec_lvlxl", v16qi_ftype_long_pcvoid, ALTIVEC_BUILTIN_VEC_LVLXL); - def_builtin ("__builtin_vec_lvrx", v16qi_ftype_long_pcvoid, ALTIVEC_BUILTIN_VEC_LVRX); - def_builtin ("__builtin_vec_lvrxl", v16qi_ftype_long_pcvoid, ALTIVEC_BUILTIN_VEC_LVRXL); - - def_builtin ("__builtin_altivec_stvlx", void_ftype_v16qi_long_pvoid, ALTIVEC_BUILTIN_STVLX); - def_builtin ("__builtin_altivec_stvlxl", void_ftype_v16qi_long_pvoid, ALTIVEC_BUILTIN_STVLXL); - def_builtin ("__builtin_altivec_stvrx", void_ftype_v16qi_long_pvoid, ALTIVEC_BUILTIN_STVRX); - def_builtin ("__builtin_altivec_stvrxl", void_ftype_v16qi_long_pvoid, ALTIVEC_BUILTIN_STVRXL); - - def_builtin ("__builtin_vec_stvlx", void_ftype_v16qi_long_pvoid, ALTIVEC_BUILTIN_VEC_STVLX); - def_builtin ("__builtin_vec_stvlxl", void_ftype_v16qi_long_pvoid, ALTIVEC_BUILTIN_VEC_STVLXL); - def_builtin ("__builtin_vec_stvrx", void_ftype_v16qi_long_pvoid, ALTIVEC_BUILTIN_VEC_STVRX); - def_builtin ("__builtin_vec_stvrxl", void_ftype_v16qi_long_pvoid, ALTIVEC_BUILTIN_VEC_STVRXL); - - if (TARGET_P9_VECTOR) + if (bif_is_32bit (*bifaddr) && TARGET_32BIT) { - def_builtin ("__builtin_altivec_stxvl", void_ftype_v16qi_pvoid_long, - P9V_BUILTIN_STXVL); - def_builtin ("__builtin_altivec_xst_len_r", void_ftype_v16qi_pvoid_long, - P9V_BUILTIN_XST_LEN_R); + if (fcode == RS6000_BIF_MFTB) + icode = CODE_FOR_rs6000_mftb_si; + else if (fcode == RS6000_BIF_BPERMD) + icode = CODE_FOR_bpermd_si; + else + gcc_unreachable (); } - /* Add the DST variants. */ - d = bdesc_dst; - for (i = 0; i < ARRAY_SIZE (bdesc_dst); i++, d++) + if (bif_is_endian (*bifaddr) && BYTES_BIG_ENDIAN) { - /* It is expected that these dst built-in functions may have - d->icode equal to CODE_FOR_nothing. */ - def_builtin (d->name, void_ftype_pcvoid_int_int, d->code); + if (fcode == RS6000_BIF_LD_ELEMREV_V1TI) + icode = CODE_FOR_vsx_load_v1ti; + else if (fcode == RS6000_BIF_LD_ELEMREV_V2DF) + icode = CODE_FOR_vsx_load_v2df; + else if (fcode == RS6000_BIF_LD_ELEMREV_V2DI) + icode = CODE_FOR_vsx_load_v2di; + else if (fcode == RS6000_BIF_LD_ELEMREV_V4SF) + icode = CODE_FOR_vsx_load_v4sf; + else if (fcode == RS6000_BIF_LD_ELEMREV_V4SI) + icode = CODE_FOR_vsx_load_v4si; + else if (fcode == RS6000_BIF_LD_ELEMREV_V8HI) + icode = CODE_FOR_vsx_load_v8hi; + else if (fcode == RS6000_BIF_LD_ELEMREV_V16QI) + icode = CODE_FOR_vsx_load_v16qi; + else if (fcode == RS6000_BIF_ST_ELEMREV_V1TI) + icode = CODE_FOR_vsx_store_v1ti; + else if (fcode == RS6000_BIF_ST_ELEMREV_V2DF) + icode = CODE_FOR_vsx_store_v2df; + else if (fcode == RS6000_BIF_ST_ELEMREV_V2DI) + icode = CODE_FOR_vsx_store_v2di; + else if (fcode == RS6000_BIF_ST_ELEMREV_V4SF) + icode = CODE_FOR_vsx_store_v4sf; + else if (fcode == RS6000_BIF_ST_ELEMREV_V4SI) + icode = CODE_FOR_vsx_store_v4si; + else if (fcode == RS6000_BIF_ST_ELEMREV_V8HI) + icode = CODE_FOR_vsx_store_v8hi; + else if (fcode == RS6000_BIF_ST_ELEMREV_V16QI) + icode = CODE_FOR_vsx_store_v16qi; + else + gcc_unreachable (); } - /* Initialize the predicates. */ - d = bdesc_altivec_preds; - for (i = 0; i < ARRAY_SIZE (bdesc_altivec_preds); i++, d++) + + /* TRUE iff the built-in function returns void. */ + bool void_func = TREE_TYPE (TREE_TYPE (fndecl)) == void_type_node; + /* Position of first argument (0 for void-returning functions, else 1). */ + int k; + /* Modes for the return value, if any, and arguments. */ + const int MAX_BUILTIN_ARGS = 6; + machine_mode mode[MAX_BUILTIN_ARGS + 1]; + + if (void_func) + k = 0; + else { - machine_mode mode1; - tree type; + k = 1; + mode[0] = insn_data[icode].operand[0].mode; + } - if (rs6000_overloaded_builtin_p (d->code)) - mode1 = VOIDmode; - else - { - /* Cannot define builtin if the instruction is disabled. */ - gcc_assert (d->icode != CODE_FOR_nothing); - mode1 = insn_data[d->icode].operand[1].mode; - } + /* Tree expressions for each argument. */ + tree arg[MAX_BUILTIN_ARGS]; + /* RTL expressions for each argument. */ + rtx op[MAX_BUILTIN_ARGS]; - switch (mode1) - { - case E_VOIDmode: - type = int_ftype_int_opaque_opaque; - break; - case E_V1TImode: - type = int_ftype_int_v1ti_v1ti; - break; - case E_V2DImode: - type = int_ftype_int_v2di_v2di; - break; - case E_V4SImode: - type = int_ftype_int_v4si_v4si; - break; - case E_V8HImode: - type = int_ftype_int_v8hi_v8hi; - break; - case E_V16QImode: - type = int_ftype_int_v16qi_v16qi; - break; - case E_V4SFmode: - type = int_ftype_int_v4sf_v4sf; - break; - case E_V2DFmode: - type = int_ftype_int_v2df_v2df; - break; - default: - gcc_unreachable (); - } + int nargs = bifaddr->nargs; + gcc_assert (nargs <= MAX_BUILTIN_ARGS); - def_builtin (d->name, type, d->code); - } - /* Initialize the abs* operators. */ - d = bdesc_abs; - for (i = 0; i < ARRAY_SIZE (bdesc_abs); i++, d++) + for (int i = 0; i < nargs; i++) { - machine_mode mode0; - tree type; - - /* Cannot define builtin if the instruction is disabled. */ - gcc_assert (d->icode != CODE_FOR_nothing); - mode0 = insn_data[d->icode].operand[0].mode; + arg[i] = CALL_EXPR_ARG (exp, i); + if (arg[i] == error_mark_node) + return const0_rtx; + STRIP_NOPS (arg[i]); + op[i] = expand_normal (arg[i]); + /* We have a couple of pesky patterns that don't specify the mode... */ + mode[i+k] = insn_data[icode].operand[i+k].mode; + if (!mode[i+k]) + mode[i+k] = Pmode; + } - switch (mode0) + /* Check for restricted constant arguments. */ + for (int i = 0; i < 2; i++) + { + switch (bifaddr->restr[i]) { - case E_V2DImode: - type = v2di_ftype_v2di; - break; - case E_V4SImode: - type = v4si_ftype_v4si; - break; - case E_V8HImode: - type = v8hi_ftype_v8hi; - break; - case E_V16QImode: - type = v16qi_ftype_v16qi; - break; - case E_V4SFmode: - type = v4sf_ftype_v4sf; - break; - case E_V2DFmode: - type = v2df_ftype_v2df; - break; + case RES_BITS: + { + size_t mask = 1; + mask <<= bifaddr->restr_val1[i]; + mask--; + tree restr_arg = arg[bifaddr->restr_opnd[i] - 1]; + STRIP_NOPS (restr_arg); + if (!(TREE_CODE (restr_arg) == INTEGER_CST + && (TREE_INT_CST_LOW (restr_arg) & ~mask) == 0)) + { + error ("argument %d must be a %d-bit unsigned literal", + bifaddr->restr_opnd[i], bifaddr->restr_val1[i]); + return CONST0_RTX (mode[0]); + } + break; + } + case RES_RANGE: + { + tree restr_arg = arg[bifaddr->restr_opnd[i] - 1]; + STRIP_NOPS (restr_arg); + if (!(TREE_CODE (restr_arg) == INTEGER_CST + && IN_RANGE (tree_to_shwi (restr_arg), + bifaddr->restr_val1[i], + bifaddr->restr_val2[i]))) + { + error ("argument %d must be a literal between %d and %d," + " inclusive", + bifaddr->restr_opnd[i], bifaddr->restr_val1[i], + bifaddr->restr_val2[i]); + return CONST0_RTX (mode[0]); + } + break; + } + case RES_VAR_RANGE: + { + tree restr_arg = arg[bifaddr->restr_opnd[i] - 1]; + STRIP_NOPS (restr_arg); + if (TREE_CODE (restr_arg) == INTEGER_CST + && !IN_RANGE (tree_to_shwi (restr_arg), + bifaddr->restr_val1[i], + bifaddr->restr_val2[i])) + { + error ("argument %d must be a variable or a literal " + "between %d and %d, inclusive", + bifaddr->restr_opnd[i], bifaddr->restr_val1[i], + bifaddr->restr_val2[i]); + return CONST0_RTX (mode[0]); + } + break; + } + case RES_VALUES: + { + tree restr_arg = arg[bifaddr->restr_opnd[i] - 1]; + STRIP_NOPS (restr_arg); + if (!(TREE_CODE (restr_arg) == INTEGER_CST + && (tree_to_shwi (restr_arg) == bifaddr->restr_val1[i] + || tree_to_shwi (restr_arg) == bifaddr->restr_val2[i]))) + { + error ("argument %d must be either a literal %d or a " + "literal %d", + bifaddr->restr_opnd[i], bifaddr->restr_val1[i], + bifaddr->restr_val2[i]); + return CONST0_RTX (mode[0]); + } + break; + } default: - gcc_unreachable (); + case RES_NONE: + break; } - - def_builtin (d->name, type, d->code); } - /* Initialize target builtin that implements - targetm.vectorize.builtin_mask_for_load. */ + if (bif_is_ldstmask (*bifaddr)) + return rs6000_expand_ldst_mask (target, arg[0]); - decl = add_builtin_function ("__builtin_altivec_mask_for_load", - v16qi_ftype_pcvoid, - ALTIVEC_BUILTIN_MASK_FOR_LOAD, - BUILT_IN_MD, NULL, NULL_TREE); - TREE_READONLY (decl) = 1; - if (TARGET_DEBUG_BUILTIN) - { - tree arg_type = TREE_VALUE (TYPE_ARG_TYPES (v16qi_ftype_pcvoid)); - fprintf (stderr, "%s __builtin_altivec_mask_for_load (%s); [%4d]\n", - rs6000_type_string (TREE_TYPE (v16qi_ftype_pcvoid)), - rs6000_type_string (arg_type), - (int) ALTIVEC_BUILTIN_MASK_FOR_LOAD); - } - /* Record the decl. Will be used by rs6000_builtin_mask_for_load. */ - altivec_builtin_mask_for_load = decl; - - /* Access to the vec_init patterns. */ - ftype = build_function_type_list (V4SI_type_node, integer_type_node, - integer_type_node, integer_type_node, - integer_type_node, NULL_TREE); - def_builtin ("__builtin_vec_init_v4si", ftype, ALTIVEC_BUILTIN_VEC_INIT_V4SI); - - ftype = build_function_type_list (V8HI_type_node, short_integer_type_node, - short_integer_type_node, - short_integer_type_node, - short_integer_type_node, - short_integer_type_node, - short_integer_type_node, - short_integer_type_node, - short_integer_type_node, NULL_TREE); - def_builtin ("__builtin_vec_init_v8hi", ftype, ALTIVEC_BUILTIN_VEC_INIT_V8HI); - - ftype = build_function_type_list (V16QI_type_node, char_type_node, - char_type_node, char_type_node, - char_type_node, char_type_node, - char_type_node, char_type_node, - char_type_node, char_type_node, - char_type_node, char_type_node, - char_type_node, char_type_node, - char_type_node, char_type_node, - char_type_node, NULL_TREE); - def_builtin ("__builtin_vec_init_v16qi", ftype, - ALTIVEC_BUILTIN_VEC_INIT_V16QI); - - ftype = build_function_type_list (V4SF_type_node, float_type_node, - float_type_node, float_type_node, - float_type_node, NULL_TREE); - def_builtin ("__builtin_vec_init_v4sf", ftype, ALTIVEC_BUILTIN_VEC_INIT_V4SF); - - /* VSX builtins. */ - ftype = build_function_type_list (V2DF_type_node, double_type_node, - double_type_node, NULL_TREE); - def_builtin ("__builtin_vec_init_v2df", ftype, VSX_BUILTIN_VEC_INIT_V2DF); - - ftype = build_function_type_list (V2DI_type_node, intDI_type_node, - intDI_type_node, NULL_TREE); - def_builtin ("__builtin_vec_init_v2di", ftype, VSX_BUILTIN_VEC_INIT_V2DI); - - /* Access to the vec_set patterns. */ - ftype = build_function_type_list (V4SI_type_node, V4SI_type_node, - intSI_type_node, - integer_type_node, NULL_TREE); - def_builtin ("__builtin_vec_set_v4si", ftype, ALTIVEC_BUILTIN_VEC_SET_V4SI); - - ftype = build_function_type_list (V8HI_type_node, V8HI_type_node, - intHI_type_node, - integer_type_node, NULL_TREE); - def_builtin ("__builtin_vec_set_v8hi", ftype, ALTIVEC_BUILTIN_VEC_SET_V8HI); - - ftype = build_function_type_list (V16QI_type_node, V16QI_type_node, - intQI_type_node, - integer_type_node, NULL_TREE); - def_builtin ("__builtin_vec_set_v16qi", ftype, ALTIVEC_BUILTIN_VEC_SET_V16QI); - - ftype = build_function_type_list (V4SF_type_node, V4SF_type_node, - float_type_node, - integer_type_node, NULL_TREE); - def_builtin ("__builtin_vec_set_v4sf", ftype, ALTIVEC_BUILTIN_VEC_SET_V4SF); - - ftype = build_function_type_list (V2DF_type_node, V2DF_type_node, - double_type_node, - integer_type_node, NULL_TREE); - def_builtin ("__builtin_vec_set_v2df", ftype, VSX_BUILTIN_VEC_SET_V2DF); - - ftype = build_function_type_list (V2DI_type_node, V2DI_type_node, - intDI_type_node, - integer_type_node, NULL_TREE); - def_builtin ("__builtin_vec_set_v2di", ftype, VSX_BUILTIN_VEC_SET_V2DI); - - /* Access to the vec_extract patterns. */ - ftype = build_function_type_list (intSI_type_node, V4SI_type_node, - integer_type_node, NULL_TREE); - def_builtin ("__builtin_vec_ext_v4si", ftype, ALTIVEC_BUILTIN_VEC_EXT_V4SI); - - ftype = build_function_type_list (intHI_type_node, V8HI_type_node, - integer_type_node, NULL_TREE); - def_builtin ("__builtin_vec_ext_v8hi", ftype, ALTIVEC_BUILTIN_VEC_EXT_V8HI); - - ftype = build_function_type_list (intQI_type_node, V16QI_type_node, - integer_type_node, NULL_TREE); - def_builtin ("__builtin_vec_ext_v16qi", ftype, ALTIVEC_BUILTIN_VEC_EXT_V16QI); - - ftype = build_function_type_list (float_type_node, V4SF_type_node, - integer_type_node, NULL_TREE); - def_builtin ("__builtin_vec_ext_v4sf", ftype, ALTIVEC_BUILTIN_VEC_EXT_V4SF); - - ftype = build_function_type_list (double_type_node, V2DF_type_node, - integer_type_node, NULL_TREE); - def_builtin ("__builtin_vec_ext_v2df", ftype, VSX_BUILTIN_VEC_EXT_V2DF); - - ftype = build_function_type_list (intDI_type_node, V2DI_type_node, - integer_type_node, NULL_TREE); - def_builtin ("__builtin_vec_ext_v2di", ftype, VSX_BUILTIN_VEC_EXT_V2DI); - - - if (V1TI_type_node) + if (bif_is_stvec (*bifaddr)) { - tree v1ti_ftype_long_pcvoid - = build_function_type_list (V1TI_type_node, - long_integer_type_node, pcvoid_type_node, - NULL_TREE); - tree void_ftype_v1ti_long_pvoid - = build_function_type_list (void_type_node, - V1TI_type_node, long_integer_type_node, - pvoid_type_node, NULL_TREE); - def_builtin ("__builtin_vsx_ld_elemrev_v1ti", v1ti_ftype_long_pcvoid, - VSX_BUILTIN_LD_ELEMREV_V1TI); - def_builtin ("__builtin_vsx_lxvd2x_v1ti", v1ti_ftype_long_pcvoid, - VSX_BUILTIN_LXVD2X_V1TI); - def_builtin ("__builtin_vsx_stxvd2x_v1ti", void_ftype_v1ti_long_pvoid, - VSX_BUILTIN_STXVD2X_V1TI); - ftype = build_function_type_list (V1TI_type_node, intTI_type_node, - NULL_TREE, NULL_TREE); - def_builtin ("__builtin_vec_init_v1ti", ftype, VSX_BUILTIN_VEC_INIT_V1TI); - ftype = build_function_type_list (V1TI_type_node, V1TI_type_node, - intTI_type_node, - integer_type_node, NULL_TREE); - def_builtin ("__builtin_vec_set_v1ti", ftype, VSX_BUILTIN_VEC_SET_V1TI); - ftype = build_function_type_list (intTI_type_node, V1TI_type_node, - integer_type_node, NULL_TREE); - def_builtin ("__builtin_vec_ext_v1ti", ftype, VSX_BUILTIN_VEC_EXT_V1TI); + if (bif_is_reve (*bifaddr)) + icode = elemrev_icode (fcode); + return stv_expand_builtin (icode, op, mode[0], mode[1]); } -} - -static void -mma_init_builtins (void) -{ - const struct builtin_description *d = bdesc_mma; - - for (unsigned i = 0; i < ARRAY_SIZE (bdesc_mma); i++, d++) + if (bif_is_ldvec (*bifaddr)) { - tree op[MAX_MMA_OPERANDS], type; - unsigned icode = (unsigned) d->icode; - unsigned attr = rs6000_builtin_info[d->code].attr; - int attr_args = (attr & RS6000_BTC_OPND_MASK); - bool gimple_func = (attr & RS6000_BTC_GIMPLE); - unsigned nopnds = 0; - - if (d->name == 0) - { - if (TARGET_DEBUG_BUILTIN) - fprintf (stderr, "mma_builtin, bdesc_mma[%ld] no name\n", - (long unsigned) i); - continue; - } - - if (gimple_func) - { - gcc_assert (icode == CODE_FOR_nothing); - /* Some MMA built-ins that are expanded into gimple are converted - into internal MMA built-ins that are expanded into rtl. - The internal built-in follows immediately after this built-in. */ - if (d->code != VSX_BUILTIN_LXVP - && d->code != VSX_BUILTIN_STXVP) - { - op[nopnds++] = void_type_node; - icode = d[1].icode; - } - } - else - { - if (!(d->code == MMA_BUILTIN_DISASSEMBLE_ACC_INTERNAL - || d->code == VSX_BUILTIN_DISASSEMBLE_PAIR_INTERNAL) - && (attr & RS6000_BTC_QUAD) == 0) - attr_args--; + if (bif_is_reve (*bifaddr)) + icode = elemrev_icode (fcode); + return ldv_expand_builtin (target, icode, op, mode[0]); + } - /* Ensure we have the correct number and type of operands. */ - gcc_assert (attr_args == insn_data[icode].n_operands - 1); - } + if (bif_is_lxvrse (*bifaddr)) + return lxvrse_expand_builtin (target, icode, op, mode[0], mode[1]); - /* This is a disassemble pair/acc function. */ - if (d->code == MMA_BUILTIN_DISASSEMBLE_ACC - || d->code == VSX_BUILTIN_DISASSEMBLE_PAIR) - { - op[nopnds++] = build_pointer_type (void_type_node); - if (d->code == MMA_BUILTIN_DISASSEMBLE_ACC) - op[nopnds++] = build_pointer_type (vector_quad_type_node); - else - op[nopnds++] = build_pointer_type (vector_pair_type_node); - } - else if (d->code == VSX_BUILTIN_LXVP) - { - op[nopnds++] = vector_pair_type_node; - op[nopnds++] = sizetype; - op[nopnds++] = build_pointer_type (vector_pair_type_node); - } - else if (d->code == VSX_BUILTIN_STXVP) - { - op[nopnds++] = void_type_node; - op[nopnds++] = vector_pair_type_node; - op[nopnds++] = sizetype; - op[nopnds++] = build_pointer_type (vector_pair_type_node); - } - else - { - /* This is a normal MMA built-in function. */ - unsigned j = 0; - if (attr & RS6000_BTC_QUAD - && d->code != MMA_BUILTIN_DISASSEMBLE_ACC_INTERNAL - && d->code != VSX_BUILTIN_DISASSEMBLE_PAIR_INTERNAL) - j = 1; - for (; j < (unsigned) insn_data[icode].n_operands; j++) - { - machine_mode mode = insn_data[icode].operand[j].mode; - if (gimple_func && mode == XOmode) - op[nopnds++] = build_pointer_type (vector_quad_type_node); - else if (gimple_func - && mode == OOmode - && (d->code == VSX_BUILTIN_BUILD_PAIR - || d->code == VSX_BUILTIN_ASSEMBLE_PAIR)) - op[nopnds++] = build_pointer_type (vector_pair_type_node); - else - /* MMA uses unsigned types. */ - op[nopnds++] = builtin_mode_to_type[mode][1]; - } - } + if (bif_is_lxvrze (*bifaddr)) + return lxvrze_expand_builtin (target, icode, op, mode[0], mode[1]); - switch (nopnds) - { - case 1: - type = build_function_type_list (op[0], NULL_TREE); - break; - case 2: - type = build_function_type_list (op[0], op[1], NULL_TREE); - break; - case 3: - type = build_function_type_list (op[0], op[1], op[2], NULL_TREE); - break; - case 4: - type = build_function_type_list (op[0], op[1], op[2], op[3], - NULL_TREE); - break; - case 5: - type = build_function_type_list (op[0], op[1], op[2], op[3], op[4], - NULL_TREE); - break; - case 6: - type = build_function_type_list (op[0], op[1], op[2], op[3], op[4], - op[5], NULL_TREE); - break; - case 7: - type = build_function_type_list (op[0], op[1], op[2], op[3], op[4], - op[5], op[6], NULL_TREE); - break; - default: - gcc_unreachable (); - } + if (bif_is_mma (*bifaddr)) + return new_mma_expand_builtin (exp, target, icode, fcode); - def_builtin (d->name, type, d->code); + if (fcode == RS6000_BIF_PACK_IF + && TARGET_LONG_DOUBLE_128 + && !TARGET_IEEEQUAD) + { + icode = CODE_FOR_packtf; + fcode = RS6000_BIF_PACK_TF; + uns_fcode = (size_t) fcode; } -} - -static void -htm_init_builtins (void) -{ - HOST_WIDE_INT builtin_mask = rs6000_builtin_mask; - const struct builtin_description *d; - size_t i; - - d = bdesc_htm; - for (i = 0; i < ARRAY_SIZE (bdesc_htm); i++, d++) + else if (fcode == RS6000_BIF_UNPACK_IF + && TARGET_LONG_DOUBLE_128 + && !TARGET_IEEEQUAD) { - tree op[MAX_HTM_OPERANDS], type; - HOST_WIDE_INT mask = d->mask; - unsigned attr = rs6000_builtin_info[d->code].attr; - bool void_func = (attr & RS6000_BTC_VOID); - int attr_args = (attr & RS6000_BTC_OPND_MASK); - int nopnds = 0; - tree gpr_type_node; - tree rettype; - tree argtype; - - /* It is expected that these htm built-in functions may have - d->icode equal to CODE_FOR_nothing. */ - - if (TARGET_32BIT && TARGET_POWERPC64) - gpr_type_node = long_long_unsigned_type_node; - else - gpr_type_node = long_unsigned_type_node; - - if (attr & RS6000_BTC_SPR) - { - rettype = gpr_type_node; - argtype = gpr_type_node; - } - else if (d->code == HTM_BUILTIN_TABORTDC - || d->code == HTM_BUILTIN_TABORTDCI) - { - rettype = unsigned_type_node; - argtype = gpr_type_node; - } - else - { - rettype = unsigned_type_node; - argtype = unsigned_type_node; - } + icode = CODE_FOR_unpacktf; + fcode = RS6000_BIF_UNPACK_TF; + uns_fcode = (size_t) fcode; + } - if ((mask & builtin_mask) != mask) - { - if (TARGET_DEBUG_BUILTIN) - fprintf (stderr, "htm_builtin, skip binary %s\n", d->name); - continue; - } + if (TREE_TYPE (TREE_TYPE (fndecl)) == void_type_node) + target = NULL_RTX; + else if (target == 0 + || GET_MODE (target) != mode[0] + || !insn_data[icode].operand[0].predicate (target, mode[0])) + target = gen_reg_rtx (mode[0]); - if (d->name == 0) - { - if (TARGET_DEBUG_BUILTIN) - fprintf (stderr, "htm_builtin, bdesc_htm[%ld] no name\n", - (long unsigned) i); - continue; - } + for (int i = 0; i < nargs; i++) + if (!insn_data[icode].operand[i+k].predicate (op[i], mode[i+k])) + op[i] = copy_to_mode_reg (mode[i+k], op[i]); - op[nopnds++] = (void_func) ? void_type_node : rettype; + rtx pat; - if (attr_args == RS6000_BTC_UNARY) - op[nopnds++] = argtype; - else if (attr_args == RS6000_BTC_BINARY) - { - op[nopnds++] = argtype; - op[nopnds++] = argtype; - } - else if (attr_args == RS6000_BTC_TERNARY) - { - op[nopnds++] = argtype; - op[nopnds++] = argtype; - op[nopnds++] = argtype; - } + switch (nargs) + { + case 0: + pat = (void_func + ? GEN_FCN (icode) () + : GEN_FCN (icode) (target)); + break; + case 1: + pat = (void_func + ? GEN_FCN (icode) (op[0]) + : GEN_FCN (icode) (target, op[0])); + break; + case 2: + pat = (void_func + ? GEN_FCN (icode) (op[0], op[1]) + : GEN_FCN (icode) (target, op[0], op[1])); + break; + case 3: + pat = (void_func + ? GEN_FCN (icode) (op[0], op[1], op[2]) + : GEN_FCN (icode) (target, op[0], op[1], op[2])); + break; + case 4: + pat = (void_func + ? GEN_FCN (icode) (op[0], op[1], op[2], op[3]) + : GEN_FCN (icode) (target, op[0], op[1], op[2], op[3])); + break; + case 5: + pat = (void_func + ? GEN_FCN (icode) (op[0], op[1], op[2], op[3], op[4]) + : GEN_FCN (icode) (target, op[0], op[1], op[2], op[3], op[4])); + break; + case 6: + pat = (void_func + ? GEN_FCN (icode) (op[0], op[1], op[2], op[3], op[4], op[5]) + : GEN_FCN (icode) (target, op[0], op[1], + op[2], op[3], op[4], op[5])); + break; + default: + gcc_assert (MAX_BUILTIN_ARGS == 6); + gcc_unreachable (); + } - switch (nopnds) - { - case 1: - type = build_function_type_list (op[0], NULL_TREE); - break; - case 2: - type = build_function_type_list (op[0], op[1], NULL_TREE); - break; - case 3: - type = build_function_type_list (op[0], op[1], op[2], NULL_TREE); - break; - case 4: - type = build_function_type_list (op[0], op[1], op[2], op[3], - NULL_TREE); - break; - default: - gcc_unreachable (); - } + if (!pat) + return 0; - def_builtin (d->name, type, d->code); - } + emit_insn (pat); + return target; } -/* Map types for builtin functions with an explicit return type and - exactly 4 arguments. Functions with fewer than 3 arguments use - builtin_function_type. The number of quaternary built-in - functions is very small. Handle each case specially. */ +/* Create a builtin vector type with a name. Taking care not to give + the canonical type a name. */ + static tree -builtin_quaternary_function_type (machine_mode mode_ret, - machine_mode mode_arg0, - machine_mode mode_arg1, - machine_mode mode_arg2, - machine_mode mode_arg3, - enum rs6000_builtins builtin) +rs6000_vector_type (const char *name, tree elt_type, unsigned num_elts) { - tree function_type = NULL; - - static tree v2udi_type = builtin_mode_to_type[V2DImode][1]; - static tree v16uqi_type = builtin_mode_to_type[V16QImode][1]; - static tree uchar_type = builtin_mode_to_type[QImode][1]; - - static tree xxeval_type = - build_function_type_list (v2udi_type, v2udi_type, v2udi_type, - v2udi_type, uchar_type, NULL_TREE); - - static tree xxpermx_type = - build_function_type_list (v2udi_type, v2udi_type, v2udi_type, - v16uqi_type, uchar_type, NULL_TREE); - - switch (builtin) { - - case P10V_BUILTIN_XXEVAL: - gcc_assert ((mode_ret == V2DImode) - && (mode_arg0 == V2DImode) - && (mode_arg1 == V2DImode) - && (mode_arg2 == V2DImode) - && (mode_arg3 == QImode)); - function_type = xxeval_type; - break; - - case P10V_BUILTIN_VXXPERMX: - gcc_assert ((mode_ret == V2DImode) - && (mode_arg0 == V2DImode) - && (mode_arg1 == V2DImode) - && (mode_arg2 == V16QImode) - && (mode_arg3 == QImode)); - function_type = xxpermx_type; - break; - - default: - /* A case for each quaternary built-in must be provided above. */ - gcc_unreachable (); - } + tree result = build_vector_type (elt_type, num_elts); + + /* Copy so we don't give the canonical type a name. */ + result = build_variant_type_copy (result); + + add_builtin_type (name, result); - return function_type; + return result; } -/* Map types for builtin functions with an explicit return type and up to 3 - arguments. Functions with fewer than 3 arguments use VOIDmode as the type - of the argument. */ -static tree -builtin_function_type (machine_mode mode_ret, machine_mode mode_arg0, - machine_mode mode_arg1, machine_mode mode_arg2, - enum rs6000_builtins builtin, const char *name) +void +rs6000_init_builtins (void) { - struct builtin_hash_struct h; - struct builtin_hash_struct *h2; - int num_args = 3; - int i; - tree ret_type = NULL_TREE; - tree arg_type[3] = { NULL_TREE, NULL_TREE, NULL_TREE }; - - /* Create builtin_hash_table. */ - if (builtin_hash_table == NULL) - builtin_hash_table = hash_table::create_ggc (1500); - - h.type = NULL_TREE; - h.mode[0] = mode_ret; - h.mode[1] = mode_arg0; - h.mode[2] = mode_arg1; - h.mode[3] = mode_arg2; - h.uns_p[0] = 0; - h.uns_p[1] = 0; - h.uns_p[2] = 0; - h.uns_p[3] = 0; - - /* If the builtin is a type that produces unsigned results or takes unsigned - arguments, and it is returned as a decl for the vectorizer (such as - widening multiplies, permute), make sure the arguments and return value - are type correct. */ - switch (builtin) - { - /* unsigned 1 argument functions. */ - case CRYPTO_BUILTIN_VSBOX: - case CRYPTO_BUILTIN_VSBOX_BE: - case P8V_BUILTIN_VGBBD: - case MISC_BUILTIN_CDTBCD: - case MISC_BUILTIN_CBCDTD: - case P10V_BUILTIN_XVCVSPBF16: - case P10V_BUILTIN_XVCVBF16SPN: - case P10V_BUILTIN_MTVSRBM: - case P10V_BUILTIN_MTVSRHM: - case P10V_BUILTIN_MTVSRWM: - case P10V_BUILTIN_MTVSRDM: - case P10V_BUILTIN_MTVSRQM: - case P10V_BUILTIN_VCNTMBB: - case P10V_BUILTIN_VCNTMBH: - case P10V_BUILTIN_VCNTMBW: - case P10V_BUILTIN_VCNTMBD: - case P10V_BUILTIN_VEXPANDMB: - case P10V_BUILTIN_VEXPANDMH: - case P10V_BUILTIN_VEXPANDMW: - case P10V_BUILTIN_VEXPANDMD: - case P10V_BUILTIN_VEXPANDMQ: - h.uns_p[0] = 1; - h.uns_p[1] = 1; - break; + tree tdecl; + tree t; - /* unsigned 2 argument functions. */ - case ALTIVEC_BUILTIN_VMULEUB: - case ALTIVEC_BUILTIN_VMULEUH: - case P8V_BUILTIN_VMULEUW: - case ALTIVEC_BUILTIN_VMULOUB: - case ALTIVEC_BUILTIN_VMULOUH: - case P8V_BUILTIN_VMULOUW: - case CRYPTO_BUILTIN_VCIPHER: - case CRYPTO_BUILTIN_VCIPHER_BE: - case CRYPTO_BUILTIN_VCIPHERLAST: - case CRYPTO_BUILTIN_VCIPHERLAST_BE: - case CRYPTO_BUILTIN_VNCIPHER: - case CRYPTO_BUILTIN_VNCIPHER_BE: - case CRYPTO_BUILTIN_VNCIPHERLAST: - case CRYPTO_BUILTIN_VNCIPHERLAST_BE: - case CRYPTO_BUILTIN_VPMSUMB: - case CRYPTO_BUILTIN_VPMSUMH: - case CRYPTO_BUILTIN_VPMSUMW: - case CRYPTO_BUILTIN_VPMSUMD: - case CRYPTO_BUILTIN_VPMSUM: - case MISC_BUILTIN_ADDG6S: - case MISC_BUILTIN_DIVWEU: - case MISC_BUILTIN_DIVDEU: - case VSX_BUILTIN_UDIV_V2DI: - case ALTIVEC_BUILTIN_VMAXUB: - case ALTIVEC_BUILTIN_VMINUB: - case ALTIVEC_BUILTIN_VMAXUH: - case ALTIVEC_BUILTIN_VMINUH: - case ALTIVEC_BUILTIN_VMAXUW: - case ALTIVEC_BUILTIN_VMINUW: - case P8V_BUILTIN_VMAXUD: - case P8V_BUILTIN_VMINUD: - case ALTIVEC_BUILTIN_VAND_V16QI_UNS: - case ALTIVEC_BUILTIN_VAND_V8HI_UNS: - case ALTIVEC_BUILTIN_VAND_V4SI_UNS: - case ALTIVEC_BUILTIN_VAND_V2DI_UNS: - case ALTIVEC_BUILTIN_VANDC_V16QI_UNS: - case ALTIVEC_BUILTIN_VANDC_V8HI_UNS: - case ALTIVEC_BUILTIN_VANDC_V4SI_UNS: - case ALTIVEC_BUILTIN_VANDC_V2DI_UNS: - case ALTIVEC_BUILTIN_VNOR_V16QI_UNS: - case ALTIVEC_BUILTIN_VNOR_V8HI_UNS: - case ALTIVEC_BUILTIN_VNOR_V4SI_UNS: - case ALTIVEC_BUILTIN_VNOR_V2DI_UNS: - case ALTIVEC_BUILTIN_VOR_V16QI_UNS: - case ALTIVEC_BUILTIN_VOR_V8HI_UNS: - case ALTIVEC_BUILTIN_VOR_V4SI_UNS: - case ALTIVEC_BUILTIN_VOR_V2DI_UNS: - case ALTIVEC_BUILTIN_VXOR_V16QI_UNS: - case ALTIVEC_BUILTIN_VXOR_V8HI_UNS: - case ALTIVEC_BUILTIN_VXOR_V4SI_UNS: - case ALTIVEC_BUILTIN_VXOR_V2DI_UNS: - case P8V_BUILTIN_EQV_V16QI_UNS: - case P8V_BUILTIN_EQV_V8HI_UNS: - case P8V_BUILTIN_EQV_V4SI_UNS: - case P8V_BUILTIN_EQV_V2DI_UNS: - case P8V_BUILTIN_EQV_V1TI_UNS: - case P8V_BUILTIN_NAND_V16QI_UNS: - case P8V_BUILTIN_NAND_V8HI_UNS: - case P8V_BUILTIN_NAND_V4SI_UNS: - case P8V_BUILTIN_NAND_V2DI_UNS: - case P8V_BUILTIN_NAND_V1TI_UNS: - case P8V_BUILTIN_ORC_V16QI_UNS: - case P8V_BUILTIN_ORC_V8HI_UNS: - case P8V_BUILTIN_ORC_V4SI_UNS: - case P8V_BUILTIN_ORC_V2DI_UNS: - case P8V_BUILTIN_ORC_V1TI_UNS: - case P10_BUILTIN_CFUGED: - case P10_BUILTIN_CNTLZDM: - case P10_BUILTIN_CNTTZDM: - case P10_BUILTIN_PDEPD: - case P10_BUILTIN_PEXTD: - case P10V_BUILTIN_VCFUGED: - case P10V_BUILTIN_VCLZDM: - case P10V_BUILTIN_VCTZDM: - case P10V_BUILTIN_VGNB: - case P10V_BUILTIN_VPDEPD: - case P10V_BUILTIN_VPEXTD: - case P10V_BUILTIN_XXGENPCVM_V16QI: - case P10V_BUILTIN_XXGENPCVM_V8HI: - case P10V_BUILTIN_XXGENPCVM_V4SI: - case P10V_BUILTIN_XXGENPCVM_V2DI: - case P10V_BUILTIN_DIVEU_V4SI: - case P10V_BUILTIN_DIVEU_V2DI: - case P10V_BUILTIN_DIVEU_V1TI: - case P10V_BUILTIN_DIVU_V4SI: - case P10V_BUILTIN_DIVU_V2DI: - case P10V_BUILTIN_MODU_V1TI: - case P10V_BUILTIN_MODU_V2DI: - case P10V_BUILTIN_MODU_V4SI: - case P10V_BUILTIN_MULHU_V2DI: - case P10V_BUILTIN_MULHU_V4SI: - case P10V_BUILTIN_VMULEUD: - case P10V_BUILTIN_VMULOUD: - h.uns_p[0] = 1; - h.uns_p[1] = 1; - h.uns_p[2] = 1; - break; + if (TARGET_DEBUG_BUILTIN) + fprintf (stderr, "rs6000_init_builtins%s%s\n", + (TARGET_ALTIVEC) ? ", altivec" : "", + (TARGET_VSX) ? ", vsx" : ""); - /* unsigned 3 argument functions. */ - case ALTIVEC_BUILTIN_VPERM_16QI_UNS: - case ALTIVEC_BUILTIN_VPERM_8HI_UNS: - case ALTIVEC_BUILTIN_VPERM_4SI_UNS: - case ALTIVEC_BUILTIN_VPERM_2DI_UNS: - case ALTIVEC_BUILTIN_VSEL_16QI_UNS: - case ALTIVEC_BUILTIN_VSEL_8HI_UNS: - case ALTIVEC_BUILTIN_VSEL_4SI_UNS: - case ALTIVEC_BUILTIN_VSEL_2DI_UNS: - case VSX_BUILTIN_VPERM_16QI_UNS: - case VSX_BUILTIN_VPERM_8HI_UNS: - case VSX_BUILTIN_VPERM_4SI_UNS: - case VSX_BUILTIN_VPERM_2DI_UNS: - case VSX_BUILTIN_XXSEL_16QI_UNS: - case VSX_BUILTIN_XXSEL_8HI_UNS: - case VSX_BUILTIN_XXSEL_4SI_UNS: - case VSX_BUILTIN_XXSEL_2DI_UNS: - case CRYPTO_BUILTIN_VPERMXOR: - case CRYPTO_BUILTIN_VPERMXOR_V2DI: - case CRYPTO_BUILTIN_VPERMXOR_V4SI: - case CRYPTO_BUILTIN_VPERMXOR_V8HI: - case CRYPTO_BUILTIN_VPERMXOR_V16QI: - case CRYPTO_BUILTIN_VSHASIGMAW: - case CRYPTO_BUILTIN_VSHASIGMAD: - case CRYPTO_BUILTIN_VSHASIGMA: - case P10V_BUILTIN_VEXTRACTBL: - case P10V_BUILTIN_VEXTRACTHL: - case P10V_BUILTIN_VEXTRACTWL: - case P10V_BUILTIN_VEXTRACTDL: - case P10V_BUILTIN_VEXTRACTBR: - case P10V_BUILTIN_VEXTRACTHR: - case P10V_BUILTIN_VEXTRACTWR: - case P10V_BUILTIN_VEXTRACTDR: - case P10V_BUILTIN_VINSERTGPRBL: - case P10V_BUILTIN_VINSERTGPRHL: - case P10V_BUILTIN_VINSERTGPRWL: - case P10V_BUILTIN_VINSERTGPRDL: - case P10V_BUILTIN_VINSERTVPRBL: - case P10V_BUILTIN_VINSERTVPRHL: - case P10V_BUILTIN_VINSERTVPRWL: - case P10V_BUILTIN_VREPLACE_ELT_UV4SI: - case P10V_BUILTIN_VREPLACE_ELT_UV2DI: - case P10V_BUILTIN_VREPLACE_UN_UV4SI: - case P10V_BUILTIN_VREPLACE_UN_UV2DI: - case P10V_BUILTIN_VXXBLEND_V16QI: - case P10V_BUILTIN_VXXBLEND_V8HI: - case P10V_BUILTIN_VXXBLEND_V4SI: - case P10V_BUILTIN_VXXBLEND_V2DI: - h.uns_p[0] = 1; - h.uns_p[1] = 1; - h.uns_p[2] = 1; - h.uns_p[3] = 1; - break; + V2DI_type_node = rs6000_vector_type ("__vector long long", + long_long_integer_type_node, 2); + ptr_V2DI_type_node + = build_pointer_type (build_qualified_type (V2DI_type_node, + TYPE_QUAL_CONST)); - /* signed permute functions with unsigned char mask. */ - case ALTIVEC_BUILTIN_VPERM_16QI: - case ALTIVEC_BUILTIN_VPERM_8HI: - case ALTIVEC_BUILTIN_VPERM_4SI: - case ALTIVEC_BUILTIN_VPERM_4SF: - case ALTIVEC_BUILTIN_VPERM_2DI: - case ALTIVEC_BUILTIN_VPERM_2DF: - case VSX_BUILTIN_VPERM_16QI: - case VSX_BUILTIN_VPERM_8HI: - case VSX_BUILTIN_VPERM_4SI: - case VSX_BUILTIN_VPERM_4SF: - case VSX_BUILTIN_VPERM_2DI: - case VSX_BUILTIN_VPERM_2DF: - h.uns_p[3] = 1; - break; + V2DF_type_node = rs6000_vector_type ("__vector double", double_type_node, 2); + ptr_V2DF_type_node + = build_pointer_type (build_qualified_type (V2DF_type_node, + TYPE_QUAL_CONST)); - /* unsigned args, signed return. */ - case VSX_BUILTIN_XVCVUXDSP: - case VSX_BUILTIN_XVCVUXDDP_UNS: - case ALTIVEC_BUILTIN_UNSFLOAT_V4SI_V4SF: - h.uns_p[1] = 1; - break; + V4SI_type_node = rs6000_vector_type ("__vector signed int", + intSI_type_node, 4); + ptr_V4SI_type_node + = build_pointer_type (build_qualified_type (V4SI_type_node, + TYPE_QUAL_CONST)); - /* signed args, unsigned return. */ - case VSX_BUILTIN_XVCVDPUXDS_UNS: - case ALTIVEC_BUILTIN_FIXUNS_V4SF_V4SI: - case MISC_BUILTIN_UNPACK_TD: - case MISC_BUILTIN_UNPACK_V1TI: - h.uns_p[0] = 1; - break; + V4SF_type_node = rs6000_vector_type ("__vector float", float_type_node, 4); + ptr_V4SF_type_node + = build_pointer_type (build_qualified_type (V4SF_type_node, + TYPE_QUAL_CONST)); - /* unsigned arguments, bool return (compares). */ - case ALTIVEC_BUILTIN_VCMPEQUB: - case ALTIVEC_BUILTIN_VCMPEQUH: - case ALTIVEC_BUILTIN_VCMPEQUW: - case P8V_BUILTIN_VCMPEQUD: - case VSX_BUILTIN_CMPGE_U16QI: - case VSX_BUILTIN_CMPGE_U8HI: - case VSX_BUILTIN_CMPGE_U4SI: - case VSX_BUILTIN_CMPGE_U2DI: - case P10V_BUILTIN_CMPGE_U1TI: - case ALTIVEC_BUILTIN_VCMPGTUB: - case ALTIVEC_BUILTIN_VCMPGTUH: - case ALTIVEC_BUILTIN_VCMPGTUW: - case P8V_BUILTIN_VCMPGTUD: - case P10V_BUILTIN_VCMPGTUT: - case P10V_BUILTIN_VCMPEQUT: - h.uns_p[1] = 1; - h.uns_p[2] = 1; - break; + V8HI_type_node = rs6000_vector_type ("__vector signed short", + intHI_type_node, 8); + ptr_V8HI_type_node + = build_pointer_type (build_qualified_type (V8HI_type_node, + TYPE_QUAL_CONST)); - /* unsigned arguments for 128-bit pack instructions. */ - case MISC_BUILTIN_PACK_TD: - case MISC_BUILTIN_PACK_V1TI: - h.uns_p[1] = 1; - h.uns_p[2] = 1; - break; + V16QI_type_node = rs6000_vector_type ("__vector signed char", + intQI_type_node, 16); + ptr_V16QI_type_node + = build_pointer_type (build_qualified_type (V16QI_type_node, + TYPE_QUAL_CONST)); - /* unsigned second arguments (vector shift right). */ - case ALTIVEC_BUILTIN_VSRB: - case ALTIVEC_BUILTIN_VSRH: - case ALTIVEC_BUILTIN_VSRW: - case P8V_BUILTIN_VSRD: - /* Vector splat immediate insert */ - case P10V_BUILTIN_VXXSPLTI32DX_V4SI: - case P10V_BUILTIN_VXXSPLTI32DX_V4SF: - h.uns_p[2] = 1; - break; + unsigned_V16QI_type_node = rs6000_vector_type ("__vector unsigned char", + unsigned_intQI_type_node, 16); + ptr_unsigned_V16QI_type_node + = build_pointer_type (build_qualified_type (unsigned_V16QI_type_node, + TYPE_QUAL_CONST)); - case VSX_BUILTIN_LXVP: - h.uns_p[0] = 1; - h.uns_p[2] = 1; - break; + unsigned_V8HI_type_node = rs6000_vector_type ("__vector unsigned short", + unsigned_intHI_type_node, 8); + ptr_unsigned_V8HI_type_node + = build_pointer_type (build_qualified_type (unsigned_V8HI_type_node, + TYPE_QUAL_CONST)); - case VSX_BUILTIN_STXVP: - h.uns_p[1] = 1; - h.uns_p[3] = 1; - break; + unsigned_V4SI_type_node = rs6000_vector_type ("__vector unsigned int", + unsigned_intSI_type_node, 4); + ptr_unsigned_V4SI_type_node + = build_pointer_type (build_qualified_type (unsigned_V4SI_type_node, + TYPE_QUAL_CONST)); - default: - break; + unsigned_V2DI_type_node + = rs6000_vector_type ("__vector unsigned long long", + long_long_unsigned_type_node, 2); + + ptr_unsigned_V2DI_type_node + = build_pointer_type (build_qualified_type (unsigned_V2DI_type_node, + TYPE_QUAL_CONST)); + + opaque_V4SI_type_node = build_opaque_vector_type (intSI_type_node, 4); + + const_str_type_node + = build_pointer_type (build_qualified_type (char_type_node, + TYPE_QUAL_CONST)); + + /* We use V1TI mode as a special container to hold __int128_t items that + must live in VSX registers. */ + if (intTI_type_node) + { + V1TI_type_node = rs6000_vector_type ("__vector __int128", + intTI_type_node, 1); + ptr_V1TI_type_node + = build_pointer_type (build_qualified_type (V1TI_type_node, + TYPE_QUAL_CONST)); + unsigned_V1TI_type_node + = rs6000_vector_type ("__vector unsigned __int128", + unsigned_intTI_type_node, 1); + ptr_unsigned_V1TI_type_node + = build_pointer_type (build_qualified_type (unsigned_V1TI_type_node, + TYPE_QUAL_CONST)); } - /* Figure out how many args are present. */ - while (num_args > 0 && h.mode[num_args] == VOIDmode) - num_args--; + /* The 'vector bool ...' types must be kept distinct from 'vector unsigned ...' + types, especially in C++ land. Similarly, 'vector pixel' is distinct from + 'vector unsigned short'. */ + + bool_char_type_node = build_distinct_type_copy (unsigned_intQI_type_node); + bool_short_type_node = build_distinct_type_copy (unsigned_intHI_type_node); + bool_int_type_node = build_distinct_type_copy (unsigned_intSI_type_node); + bool_long_long_type_node = build_distinct_type_copy (unsigned_intDI_type_node); + pixel_type_node = build_distinct_type_copy (unsigned_intHI_type_node); - ret_type = builtin_mode_to_type[h.mode[0]][h.uns_p[0]]; - if (!ret_type && h.uns_p[0]) - ret_type = builtin_mode_to_type[h.mode[0]][0]; + long_integer_type_internal_node = long_integer_type_node; + long_unsigned_type_internal_node = long_unsigned_type_node; + long_long_integer_type_internal_node = long_long_integer_type_node; + long_long_unsigned_type_internal_node = long_long_unsigned_type_node; + intQI_type_internal_node = intQI_type_node; + uintQI_type_internal_node = unsigned_intQI_type_node; + intHI_type_internal_node = intHI_type_node; + uintHI_type_internal_node = unsigned_intHI_type_node; + intSI_type_internal_node = intSI_type_node; + uintSI_type_internal_node = unsigned_intSI_type_node; + intDI_type_internal_node = intDI_type_node; + uintDI_type_internal_node = unsigned_intDI_type_node; + intTI_type_internal_node = intTI_type_node; + uintTI_type_internal_node = unsigned_intTI_type_node; + float_type_internal_node = float_type_node; + double_type_internal_node = double_type_node; + long_double_type_internal_node = long_double_type_node; + dfloat64_type_internal_node = dfloat64_type_node; + dfloat128_type_internal_node = dfloat128_type_node; + void_type_internal_node = void_type_node; - /* If the required decimal float type has been disabled, - then return NULL_TREE. */ - if (!ret_type && DECIMAL_FLOAT_MODE_P (h.mode[0])) - return NULL_TREE; + ptr_intQI_type_node + = build_pointer_type (build_qualified_type (intQI_type_internal_node, + TYPE_QUAL_CONST)); + ptr_uintQI_type_node + = build_pointer_type (build_qualified_type (uintQI_type_internal_node, + TYPE_QUAL_CONST)); + ptr_intHI_type_node + = build_pointer_type (build_qualified_type (intHI_type_internal_node, + TYPE_QUAL_CONST)); + ptr_uintHI_type_node + = build_pointer_type (build_qualified_type (uintHI_type_internal_node, + TYPE_QUAL_CONST)); + ptr_intSI_type_node + = build_pointer_type (build_qualified_type (intSI_type_internal_node, + TYPE_QUAL_CONST)); + ptr_uintSI_type_node + = build_pointer_type (build_qualified_type (uintSI_type_internal_node, + TYPE_QUAL_CONST)); + ptr_intDI_type_node + = build_pointer_type (build_qualified_type (intDI_type_internal_node, + TYPE_QUAL_CONST)); + ptr_uintDI_type_node + = build_pointer_type (build_qualified_type (uintDI_type_internal_node, + TYPE_QUAL_CONST)); + ptr_intTI_type_node + = build_pointer_type (build_qualified_type (intTI_type_internal_node, + TYPE_QUAL_CONST)); + ptr_uintTI_type_node + = build_pointer_type (build_qualified_type (uintTI_type_internal_node, + TYPE_QUAL_CONST)); - if (!ret_type) - fatal_error (input_location, - "internal error: builtin function %qs had an unexpected " - "return type %qs", name, GET_MODE_NAME (h.mode[0])); + t = build_qualified_type (long_integer_type_internal_node, TYPE_QUAL_CONST); + ptr_long_integer_type_node = build_pointer_type (t); - for (i = 0; i < (int) ARRAY_SIZE (arg_type); i++) - arg_type[i] = NULL_TREE; + t = build_qualified_type (long_unsigned_type_internal_node, TYPE_QUAL_CONST); + ptr_long_unsigned_type_node = build_pointer_type (t); - for (i = 0; i < num_args; i++) + ptr_float_type_node + = build_pointer_type (build_qualified_type (float_type_internal_node, + TYPE_QUAL_CONST)); + ptr_double_type_node + = build_pointer_type (build_qualified_type (double_type_internal_node, + TYPE_QUAL_CONST)); + ptr_long_double_type_node + = build_pointer_type (build_qualified_type (long_double_type_internal_node, + TYPE_QUAL_CONST)); + if (dfloat64_type_node) { - int m = (int) h.mode[i+1]; - int uns_p = h.uns_p[i+1]; - - arg_type[i] = builtin_mode_to_type[m][uns_p]; - if (!arg_type[i] && uns_p) - arg_type[i] = builtin_mode_to_type[m][0]; - - /* If the required decimal float type has been disabled, - then return NULL_TREE. */ - if (!arg_type[i] && DECIMAL_FLOAT_MODE_P (m)) - return NULL_TREE; - - if (!arg_type[i]) - fatal_error (input_location, - "internal error: builtin function %qs, argument %d " - "had unexpected argument type %qs", name, i, - GET_MODE_NAME (m)); + t = build_qualified_type (dfloat64_type_internal_node, TYPE_QUAL_CONST); + ptr_dfloat64_type_node = build_pointer_type (t); } + else + ptr_dfloat64_type_node = NULL; - builtin_hash_struct **found = builtin_hash_table->find_slot (&h, INSERT); - if (*found == NULL) + if (dfloat128_type_node) { - h2 = ggc_alloc (); - *h2 = h; - *found = h2; - - h2->type = build_function_type_list (ret_type, arg_type[0], arg_type[1], - arg_type[2], NULL_TREE); + t = build_qualified_type (dfloat128_type_internal_node, TYPE_QUAL_CONST); + ptr_dfloat128_type_node = build_pointer_type (t); } + else + ptr_dfloat128_type_node = NULL; - return (*found)->type; -} + t = build_qualified_type (long_long_integer_type_internal_node, + TYPE_QUAL_CONST); + ptr_long_long_integer_type_node = build_pointer_type (t); -static void -rs6000_common_init_builtins (void) -{ - const struct builtin_description *d; - size_t i; + t = build_qualified_type (long_long_unsigned_type_internal_node, + TYPE_QUAL_CONST); + ptr_long_long_unsigned_type_node = build_pointer_type (t); - tree opaque_ftype_opaque = NULL_TREE; - tree opaque_ftype_opaque_opaque = NULL_TREE; - tree opaque_ftype_opaque_opaque_opaque = NULL_TREE; - tree opaque_ftype_opaque_opaque_opaque_opaque = NULL_TREE; - HOST_WIDE_INT builtin_mask = rs6000_builtin_mask; + /* 128-bit floating point support. KFmode is IEEE 128-bit floating point. + IFmode is the IBM extended 128-bit format that is a pair of doubles. + TFmode will be either IEEE 128-bit floating point or the IBM double-double + format that uses a pair of doubles, depending on the switches and + defaults. - /* Create Altivec and VSX builtins on machines with at least the - general purpose extensions (970 and newer) to allow the use of - the target attribute. */ + If we don't support for either 128-bit IBM double double or IEEE 128-bit + floating point, we need make sure the type is non-zero or else self-test + fails during bootstrap. - if (TARGET_EXTRA_BUILTINS) - builtin_mask |= RS6000_BTM_COMMON; + Always create __ibm128 as a separate type, even if the current long double + format is IBM extended double. - /* Add the quaternary operators. */ - d = bdesc_4arg; - for (i = 0; i < ARRAY_SIZE (bdesc_4arg); i++, d++) + For IEEE 128-bit floating point, always create the type __ieee128. If the + user used -mfloat128, rs6000-c.c will create a define from __float128 to + __ieee128. */ + if (TARGET_FLOAT128_TYPE) { - tree type; - HOST_WIDE_INT mask = d->mask; + if (!TARGET_IEEEQUAD && TARGET_LONG_DOUBLE_128) + ibm128_float_type_node = long_double_type_node; + else + { + ibm128_float_type_node = make_node (REAL_TYPE); + TYPE_PRECISION (ibm128_float_type_node) = 128; + SET_TYPE_MODE (ibm128_float_type_node, IFmode); + layout_type (ibm128_float_type_node); + } + t = build_qualified_type (ibm128_float_type_node, TYPE_QUAL_CONST); + ptr_ibm128_float_type_node = build_pointer_type (t); + lang_hooks.types.register_builtin_type (ibm128_float_type_node, + "__ibm128"); + + if (TARGET_IEEEQUAD && TARGET_LONG_DOUBLE_128) + ieee128_float_type_node = long_double_type_node; + else + ieee128_float_type_node = float128_type_node; + t = build_qualified_type (ieee128_float_type_node, TYPE_QUAL_CONST); + ptr_ieee128_float_type_node = build_pointer_type (t); + lang_hooks.types.register_builtin_type (ieee128_float_type_node, + "__ieee128"); + } + + else + ieee128_float_type_node = ibm128_float_type_node = long_double_type_node; + + /* Vector pair and vector quad support. */ + vector_pair_type_node = make_node (OPAQUE_TYPE); + SET_TYPE_MODE (vector_pair_type_node, OOmode); + TYPE_SIZE (vector_pair_type_node) = bitsize_int (GET_MODE_BITSIZE (OOmode)); + TYPE_PRECISION (vector_pair_type_node) = GET_MODE_BITSIZE (OOmode); + TYPE_SIZE_UNIT (vector_pair_type_node) = size_int (GET_MODE_SIZE (OOmode)); + SET_TYPE_ALIGN (vector_pair_type_node, 256); + TYPE_USER_ALIGN (vector_pair_type_node) = 0; + lang_hooks.types.register_builtin_type (vector_pair_type_node, + "__vector_pair"); + t = build_qualified_type (vector_pair_type_node, TYPE_QUAL_CONST); + ptr_vector_pair_type_node = build_pointer_type (t); + + vector_quad_type_node = make_node (OPAQUE_TYPE); + SET_TYPE_MODE (vector_quad_type_node, XOmode); + TYPE_SIZE (vector_quad_type_node) = bitsize_int (GET_MODE_BITSIZE (XOmode)); + TYPE_PRECISION (vector_quad_type_node) = GET_MODE_BITSIZE (XOmode); + TYPE_SIZE_UNIT (vector_quad_type_node) = size_int (GET_MODE_SIZE (XOmode)); + SET_TYPE_ALIGN (vector_quad_type_node, 512); + TYPE_USER_ALIGN (vector_quad_type_node) = 0; + lang_hooks.types.register_builtin_type (vector_quad_type_node, + "__vector_quad"); + t = build_qualified_type (vector_quad_type_node, TYPE_QUAL_CONST); + ptr_vector_quad_type_node = build_pointer_type (t); - if ((mask & builtin_mask) != mask) - { - if (TARGET_DEBUG_BUILTIN) - fprintf (stderr, "rs6000_builtin, skip quaternary %s\n", d->name); - continue; - } + /* Initialize the modes for builtin_function_type, mapping a machine mode to + tree type node. */ + builtin_mode_to_type[QImode][0] = integer_type_node; + builtin_mode_to_type[QImode][1] = unsigned_intSI_type_node; + builtin_mode_to_type[HImode][0] = integer_type_node; + builtin_mode_to_type[HImode][1] = unsigned_intSI_type_node; + builtin_mode_to_type[SImode][0] = intSI_type_node; + builtin_mode_to_type[SImode][1] = unsigned_intSI_type_node; + builtin_mode_to_type[DImode][0] = intDI_type_node; + builtin_mode_to_type[DImode][1] = unsigned_intDI_type_node; + builtin_mode_to_type[TImode][0] = intTI_type_node; + builtin_mode_to_type[TImode][1] = unsigned_intTI_type_node; + builtin_mode_to_type[SFmode][0] = float_type_node; + builtin_mode_to_type[DFmode][0] = double_type_node; + builtin_mode_to_type[IFmode][0] = ibm128_float_type_node; + builtin_mode_to_type[KFmode][0] = ieee128_float_type_node; + builtin_mode_to_type[TFmode][0] = long_double_type_node; + builtin_mode_to_type[DDmode][0] = dfloat64_type_node; + builtin_mode_to_type[TDmode][0] = dfloat128_type_node; + builtin_mode_to_type[V1TImode][0] = V1TI_type_node; + builtin_mode_to_type[V1TImode][1] = unsigned_V1TI_type_node; + builtin_mode_to_type[V2DImode][0] = V2DI_type_node; + builtin_mode_to_type[V2DImode][1] = unsigned_V2DI_type_node; + builtin_mode_to_type[V2DFmode][0] = V2DF_type_node; + builtin_mode_to_type[V4SImode][0] = V4SI_type_node; + builtin_mode_to_type[V4SImode][1] = unsigned_V4SI_type_node; + builtin_mode_to_type[V4SFmode][0] = V4SF_type_node; + builtin_mode_to_type[V8HImode][0] = V8HI_type_node; + builtin_mode_to_type[V8HImode][1] = unsigned_V8HI_type_node; + builtin_mode_to_type[V16QImode][0] = V16QI_type_node; + builtin_mode_to_type[V16QImode][1] = unsigned_V16QI_type_node; + builtin_mode_to_type[OOmode][1] = vector_pair_type_node; + builtin_mode_to_type[XOmode][1] = vector_quad_type_node; - if (rs6000_overloaded_builtin_p (d->code)) - { - type = opaque_ftype_opaque_opaque_opaque_opaque; - if (!type) - type = opaque_ftype_opaque_opaque_opaque_opaque - = build_function_type_list (opaque_V4SI_type_node, - opaque_V4SI_type_node, - opaque_V4SI_type_node, - opaque_V4SI_type_node, - opaque_V4SI_type_node, - NULL_TREE); - } - else - { - enum insn_code icode = d->icode; - if (d->name == 0) - { - if (TARGET_DEBUG_BUILTIN) - fprintf (stderr, "rs6000_builtin, bdesc_4arg[%ld] no name\n", - (long) i); - continue; - } + tdecl = add_builtin_type ("__bool char", bool_char_type_node); + TYPE_NAME (bool_char_type_node) = tdecl; - if (icode == CODE_FOR_nothing) - { - if (TARGET_DEBUG_BUILTIN) - fprintf (stderr, - "rs6000_builtin, skip quaternary %s (no code)\n", - d->name); - continue; - } + tdecl = add_builtin_type ("__bool short", bool_short_type_node); + TYPE_NAME (bool_short_type_node) = tdecl; - type = - builtin_quaternary_function_type (insn_data[icode].operand[0].mode, - insn_data[icode].operand[1].mode, - insn_data[icode].operand[2].mode, - insn_data[icode].operand[3].mode, - insn_data[icode].operand[4].mode, - d->code); - } - def_builtin (d->name, type, d->code); - } + tdecl = add_builtin_type ("__bool int", bool_int_type_node); + TYPE_NAME (bool_int_type_node) = tdecl; - /* Add the ternary operators. */ - d = bdesc_3arg; - for (i = 0; i < ARRAY_SIZE (bdesc_3arg); i++, d++) - { - tree type; - HOST_WIDE_INT mask = d->mask; + tdecl = add_builtin_type ("__pixel", pixel_type_node); + TYPE_NAME (pixel_type_node) = tdecl; - if ((mask & builtin_mask) != mask) - { - if (TARGET_DEBUG_BUILTIN) - fprintf (stderr, "rs6000_builtin, skip ternary %s\n", d->name); - continue; - } + bool_V16QI_type_node = rs6000_vector_type ("__vector __bool char", + bool_char_type_node, 16); + ptr_bool_V16QI_type_node + = build_pointer_type (build_qualified_type (bool_V16QI_type_node, + TYPE_QUAL_CONST)); - if (rs6000_overloaded_builtin_p (d->code)) - { - if (! (type = opaque_ftype_opaque_opaque_opaque)) - type = opaque_ftype_opaque_opaque_opaque - = build_function_type_list (opaque_V4SI_type_node, - opaque_V4SI_type_node, - opaque_V4SI_type_node, - opaque_V4SI_type_node, - NULL_TREE); - } - else - { - enum insn_code icode = d->icode; - if (d->name == 0) - { - if (TARGET_DEBUG_BUILTIN) - fprintf (stderr, "rs6000_builtin, bdesc_3arg[%ld] no name\n", - (long unsigned)i); + bool_V8HI_type_node = rs6000_vector_type ("__vector __bool short", + bool_short_type_node, 8); + ptr_bool_V8HI_type_node + = build_pointer_type (build_qualified_type (bool_V8HI_type_node, + TYPE_QUAL_CONST)); - continue; - } + bool_V4SI_type_node = rs6000_vector_type ("__vector __bool int", + bool_int_type_node, 4); + ptr_bool_V4SI_type_node + = build_pointer_type (build_qualified_type (bool_V4SI_type_node, + TYPE_QUAL_CONST)); - if (icode == CODE_FOR_nothing) - { - if (TARGET_DEBUG_BUILTIN) - fprintf (stderr, "rs6000_builtin, skip ternary %s (no code)\n", - d->name); + bool_V2DI_type_node = rs6000_vector_type (TARGET_POWERPC64 + ? "__vector __bool long" + : "__vector __bool long long", + bool_long_long_type_node, 2); + ptr_bool_V2DI_type_node + = build_pointer_type (build_qualified_type (bool_V2DI_type_node, + TYPE_QUAL_CONST)); - continue; - } + bool_V1TI_type_node = rs6000_vector_type ("__vector __bool __int128", + intTI_type_node, 1); + ptr_bool_V1TI_type_node + = build_pointer_type (build_qualified_type (bool_V1TI_type_node, + TYPE_QUAL_CONST)); - type = builtin_function_type (insn_data[icode].operand[0].mode, - insn_data[icode].operand[1].mode, - insn_data[icode].operand[2].mode, - insn_data[icode].operand[3].mode, - d->code, d->name); - } + pixel_V8HI_type_node = rs6000_vector_type ("__vector __pixel", + pixel_type_node, 8); + ptr_pixel_V8HI_type_node + = build_pointer_type (build_qualified_type (pixel_V8HI_type_node, + TYPE_QUAL_CONST)); + pcvoid_type_node + = build_pointer_type (build_qualified_type (void_type_node, + TYPE_QUAL_CONST)); - def_builtin (d->name, type, d->code); - } + /* Execute the autogenerated initialization code for builtins. */ + rs6000_init_generated_builtins (); - /* Add the binary operators. */ - d = bdesc_2arg; - for (i = 0; i < ARRAY_SIZE (bdesc_2arg); i++, d++) + if (TARGET_DEBUG_BUILTIN) { - machine_mode mode0, mode1, mode2; - tree type; - HOST_WIDE_INT mask = d->mask; - - if ((mask & builtin_mask) != mask) - { - if (TARGET_DEBUG_BUILTIN) - fprintf (stderr, "rs6000_builtin, skip binary %s\n", d->name); - continue; - } - - if (rs6000_overloaded_builtin_p (d->code)) - { - const struct altivec_builtin_types *desc; - - /* Verify the builtin we are overloading has already been defined. */ - type = NULL_TREE; - for (desc = altivec_overloaded_builtins; - desc->code != RS6000_BUILTIN_NONE; desc++) - if (desc->code == d->code - && rs6000_builtin_decls[(int)desc->overloaded_code]) - { - if (! (type = opaque_ftype_opaque_opaque)) - type = opaque_ftype_opaque_opaque - = build_function_type_list (opaque_V4SI_type_node, - opaque_V4SI_type_node, - opaque_V4SI_type_node, - NULL_TREE); - break; - } - } - else + fprintf (stderr, "\nAutogenerated built-in functions:\n\n"); + for (int i = 1; i < (int) RS6000_BIF_MAX; i++) { - enum insn_code icode = d->icode; - if (d->name == 0) - { - if (TARGET_DEBUG_BUILTIN) - fprintf (stderr, "rs6000_builtin, bdesc_2arg[%ld] no name\n", - (long unsigned)i); - - continue; - } - - if (icode == CODE_FOR_nothing) + bif_enable e = rs6000_builtin_info_x[i].enable; + if (e == ENB_P5 && !TARGET_POPCNTB) + continue; + if (e == ENB_P6 && !TARGET_CMPB) + continue; + if (e == ENB_P6_64 && !(TARGET_CMPB && TARGET_POWERPC64)) + continue; + if (e == ENB_ALTIVEC && !TARGET_ALTIVEC) + continue; + if (e == ENB_VSX && !TARGET_VSX) + continue; + if (e == ENB_P7 && !TARGET_POPCNTD) + continue; + if (e == ENB_P7_64 && !(TARGET_POPCNTD && TARGET_POWERPC64)) + continue; + if (e == ENB_P8 && !TARGET_DIRECT_MOVE) + continue; + if (e == ENB_P8V && !TARGET_P8_VECTOR) + continue; + if (e == ENB_P9 && !TARGET_MODULO) + continue; + if (e == ENB_P9_64 && !(TARGET_MODULO && TARGET_POWERPC64)) + continue; + if (e == ENB_P9V && !TARGET_P9_VECTOR) + continue; + if (e == ENB_IEEE128_HW && !TARGET_FLOAT128_HW) + continue; + if (e == ENB_DFP && !TARGET_DFP) + continue; + if (e == ENB_CRYPTO && !TARGET_CRYPTO) + continue; + if (e == ENB_HTM && !TARGET_HTM) + continue; + if (e == ENB_P10 && !TARGET_POWER10) + continue; + if (e == ENB_P10_64 && !(TARGET_POWER10 && TARGET_POWERPC64)) + continue; + if (e == ENB_MMA && !TARGET_MMA) + continue; + tree fntype = rs6000_builtin_info_x[i].fntype; + tree t = TREE_TYPE (fntype); + fprintf (stderr, "%s %s (", rs6000_type_string (t), + rs6000_builtin_info_x[i].bifname); + t = TYPE_ARG_TYPES (fntype); + while (t && TREE_VALUE (t) != void_type_node) { - if (TARGET_DEBUG_BUILTIN) - fprintf (stderr, "rs6000_builtin, skip binary %s (no code)\n", - d->name); - - continue; + fprintf (stderr, "%s", + rs6000_type_string (TREE_VALUE (t))); + t = TREE_CHAIN (t); + if (t && TREE_VALUE (t) != void_type_node) + fprintf (stderr, ", "); } - - mode0 = insn_data[icode].operand[0].mode; - mode1 = insn_data[icode].operand[1].mode; - mode2 = insn_data[icode].operand[2].mode; - - type = builtin_function_type (mode0, mode1, mode2, VOIDmode, - d->code, d->name); + fprintf (stderr, "); %s [%4d]\n", + rs6000_builtin_info_x[i].attr_string, (int) i); } + fprintf (stderr, "\nEnd autogenerated built-in functions.\n\n\n"); + } - def_builtin (d->name, type, d->code); - } - - /* Add the simple unary operators. */ - d = bdesc_1arg; - for (i = 0; i < ARRAY_SIZE (bdesc_1arg); i++, d++) + if (TARGET_XCOFF) { - machine_mode mode0, mode1; - tree type; - HOST_WIDE_INT mask = d->mask; - - if ((mask & builtin_mask) != mask) - { - if (TARGET_DEBUG_BUILTIN) - fprintf (stderr, "rs6000_builtin, skip unary %s\n", d->name); - continue; - } + /* AIX libm provides clog as __clog. */ + if ((tdecl = builtin_decl_explicit (BUILT_IN_CLOG)) != NULL_TREE) + set_user_assembler_name (tdecl, "__clog"); - if (rs6000_overloaded_builtin_p (d->code)) + /* When long double is 64 bit, some long double builtins of libc + functions (like __builtin_frexpl) must call the double version + (frexp) not the long double version (frexpl) that expects a 128 bit + argument. */ + if (! TARGET_LONG_DOUBLE_128) { - if (! (type = opaque_ftype_opaque)) - type = opaque_ftype_opaque - = build_function_type_list (opaque_V4SI_type_node, - opaque_V4SI_type_node, - NULL_TREE); + if ((tdecl = builtin_decl_explicit (BUILT_IN_FMODL)) != NULL_TREE) + set_user_assembler_name (tdecl, "fmod"); + if ((tdecl = builtin_decl_explicit (BUILT_IN_FREXPL)) != NULL_TREE) + set_user_assembler_name (tdecl, "frexp"); + if ((tdecl = builtin_decl_explicit (BUILT_IN_LDEXPL)) != NULL_TREE) + set_user_assembler_name (tdecl, "ldexp"); + if ((tdecl = builtin_decl_explicit (BUILT_IN_MODFL)) != NULL_TREE) + set_user_assembler_name (tdecl, "modf"); } - else - { - enum insn_code icode = d->icode; - if (d->name == 0) - { - if (TARGET_DEBUG_BUILTIN) - fprintf (stderr, "rs6000_builtin, bdesc_1arg[%ld] no name\n", - (long unsigned)i); + } - continue; - } + altivec_builtin_mask_for_load + = rs6000_builtin_decls_x[RS6000_BIF_MASK_FOR_LOAD]; - if (icode == CODE_FOR_nothing) - { - if (TARGET_DEBUG_BUILTIN) - fprintf (stderr, "rs6000_builtin, skip unary %s (no code)\n", - d->name); +#ifdef SUBTARGET_INIT_BUILTINS + SUBTARGET_INIT_BUILTINS; +#endif - continue; - } + return; +} - mode0 = insn_data[icode].operand[0].mode; - mode1 = insn_data[icode].operand[1].mode; +static tree +rs6000_new_builtin_decl (unsigned code, bool /* initialize_p */) +{ + rs6000_gen_builtins fcode = (rs6000_gen_builtins) code; - type = builtin_function_type (mode0, mode1, VOIDmode, VOIDmode, - d->code, d->name); - } + if (fcode >= RS6000_OVLD_MAX) + return error_mark_node; - def_builtin (d->name, type, d->code); - } + return rs6000_builtin_decls_x[code]; +} - /* Add the simple no-argument operators. */ - d = bdesc_0arg; - for (i = 0; i < ARRAY_SIZE (bdesc_0arg); i++, d++) - { - machine_mode mode0; - tree type; - HOST_WIDE_INT mask = d->mask; +/* Returns the rs6000 builtin decl for CODE. Note that we don't check + the builtin mask here since there could be some #pragma/attribute + target functions and the rs6000_builtin_mask could be wrong when + this checking happens, though it will be updated properly later. */ - if ((mask & builtin_mask) != mask) - { - if (TARGET_DEBUG_BUILTIN) - fprintf (stderr, "rs6000_builtin, skip no-argument %s\n", d->name); - continue; - } - if (rs6000_overloaded_builtin_p (d->code)) - { - if (!opaque_ftype_opaque) - opaque_ftype_opaque - = build_function_type_list (opaque_V4SI_type_node, NULL_TREE); - type = opaque_ftype_opaque; - } - else - { - enum insn_code icode = d->icode; - if (d->name == 0) - { - if (TARGET_DEBUG_BUILTIN) - fprintf (stderr, "rs6000_builtin, bdesc_0arg[%lu] no name\n", - (long unsigned) i); - continue; - } - if (icode == CODE_FOR_nothing) - { - if (TARGET_DEBUG_BUILTIN) - fprintf (stderr, - "rs6000_builtin, skip no-argument %s (no code)\n", - d->name); - continue; - } - mode0 = insn_data[icode].operand[0].mode; - type = builtin_function_type (mode0, VOIDmode, VOIDmode, VOIDmode, - d->code, d->name); - } - def_builtin (d->name, type, d->code); - } +tree +rs6000_builtin_decl (unsigned code, bool initialize_p ATTRIBUTE_UNUSED) +{ + return rs6000_new_builtin_decl (code, initialize_p); } /* Return the internal arg pointer used for function incoming diff --git a/gcc/config/rs6000/rs6000-gen-builtins.c b/gcc/config/rs6000/rs6000-gen-builtins.c index 856770c1659..0034fe00111 100644 --- a/gcc/config/rs6000/rs6000-gen-builtins.c +++ b/gcc/config/rs6000/rs6000-gen-builtins.c @@ -2492,7 +2492,6 @@ write_header_file (void) fprintf (header_file, "#ifndef _RS6000_BUILTINS_H\n"); fprintf (header_file, "#define _RS6000_BUILTINS_H 1\n\n"); - fprintf (header_file, "extern int new_builtins_are_live;\n\n"); write_decls (); @@ -2691,68 +2690,64 @@ write_init_bif_table (void) || strstr (bifs[i].fndecl, "dd") != NULL || strstr (bifs[i].fndecl, "td") != NULL); - fprintf (init_file, - " if (new_builtins_are_live)\n"); - fprintf (init_file, " {\n"); - if (tf_found) { - fprintf (init_file, " if (float128_type_node)\n"); - fprintf (init_file, " {\n"); + fprintf (init_file, " if (float128_type_node)\n"); + fprintf (init_file, " {\n"); } else if (dfp_found) { - fprintf (init_file, " if (dfloat64_type_node)\n"); - fprintf (init_file, " {\n"); + fprintf (init_file, " if (dfloat64_type_node)\n"); + fprintf (init_file, " {\n"); } fprintf (init_file, - " rs6000_builtin_decls_x[(int)RS6000_BIF_%s] = t\n", + " rs6000_builtin_decls_x[(int)RS6000_BIF_%s] = t\n", bifs[i].idname); fprintf (init_file, - " = add_builtin_function (\"%s\",\n", + " = add_builtin_function (\"%s\",\n", bifs[i].proto.bifname); fprintf (init_file, - " %s,\n", + " %s,\n", bifs[i].fndecl); fprintf (init_file, - " (int)RS6000_BIF_%s," + " (int)RS6000_BIF_%s," " BUILT_IN_MD,\n", bifs[i].idname); fprintf (init_file, - " NULL, NULL_TREE);\n"); + " NULL, NULL_TREE);\n"); if (bifs[i].kind == FNK_CONST) { - fprintf (init_file, " TREE_READONLY (t) = 1;\n"); - fprintf (init_file, " TREE_NOTHROW (t) = 1;\n"); + fprintf (init_file, " TREE_READONLY (t) = 1;\n"); + fprintf (init_file, " TREE_NOTHROW (t) = 1;\n"); } else if (bifs[i].kind == FNK_PURE) { - fprintf (init_file, " DECL_PURE_P (t) = 1;\n"); - fprintf (init_file, " TREE_NOTHROW (t) = 1;\n"); + fprintf (init_file, " DECL_PURE_P (t) = 1;\n"); + fprintf (init_file, " TREE_NOTHROW (t) = 1;\n"); } else if (bifs[i].kind == FNK_FPMATH) { - fprintf (init_file, " TREE_NOTHROW (t) = 1;\n"); - fprintf (init_file, " if (flag_rounding_math)\n"); - fprintf (init_file, " {\n"); - fprintf (init_file, " DECL_PURE_P (t) = 1;\n"); - fprintf (init_file, " DECL_IS_NOVOPS (t) = 1;\n"); - fprintf (init_file, " }\n"); - fprintf (init_file, " else\n"); - fprintf (init_file, " TREE_READONLY (t) = 1;\n"); + fprintf (init_file, " TREE_NOTHROW (t) = 1;\n"); + fprintf (init_file, " if (flag_rounding_math)\n"); + fprintf (init_file, " {\n"); + fprintf (init_file, " DECL_PURE_P (t) = 1;\n"); + fprintf (init_file, " DECL_IS_NOVOPS (t) = 1;\n"); + fprintf (init_file, " }\n"); + fprintf (init_file, " else\n"); + fprintf (init_file, " TREE_READONLY (t) = 1;\n"); } if (tf_found || dfp_found) { - fprintf (init_file, " }\n"); - fprintf (init_file, " else\n"); - fprintf (init_file, " {\n"); - fprintf (init_file, " rs6000_builtin_decls_x" + fprintf (init_file, " }\n"); + fprintf (init_file, " else\n"); + fprintf (init_file, " {\n"); + fprintf (init_file, " rs6000_builtin_decls_x" "[(int)RS6000_BIF_%s] = NULL_TREE;\n", bifs[i].idname); - fprintf (init_file, " }\n"); + fprintf (init_file, " }\n"); } - fprintf (init_file, " }\n\n"); + fprintf (init_file, "\n"); } } @@ -2789,41 +2784,37 @@ write_init_ovld_table (void) || strstr (ovlds[i].fndecl, "dd") != NULL || strstr (ovlds[i].fndecl, "td") != NULL); - fprintf (init_file, - " if (new_builtins_are_live)\n"); - fprintf (init_file, " {\n"); - if (tf_found) { - fprintf (init_file, " if (float128_type_node)\n"); - fprintf (init_file, " {\n"); + fprintf (init_file, " if (float128_type_node)\n"); + fprintf (init_file, " {\n"); } else if (dfp_found) { - fprintf (init_file, " if (dfloat64_type_node)\n"); - fprintf (init_file, " {\n"); + fprintf (init_file, " if (dfloat64_type_node)\n"); + fprintf (init_file, " {\n"); } fprintf (init_file, - " rs6000_builtin_decls_x[(int)RS6000_OVLD_%s] = t\n", + " rs6000_builtin_decls_x[(int)RS6000_OVLD_%s] = t\n", stanza->stanza_id); fprintf (init_file, - " = add_builtin_function (\"%s\",\n", + " = add_builtin_function (\"%s\",\n", stanza->intern_name); fprintf (init_file, - " %s,\n", + " %s,\n", ovlds[i].fndecl); fprintf (init_file, - " (int)RS6000_OVLD_%s," + " (int)RS6000_OVLD_%s," " BUILT_IN_MD,\n", stanza->stanza_id); fprintf (init_file, - " NULL, NULL_TREE);\n"); + " NULL, NULL_TREE);\n"); if (tf_found || dfp_found) - fprintf (init_file, " }\n"); + fprintf (init_file, " }\n"); - fprintf (init_file, " }\n\n"); + fprintf (init_file, "\n"); fprintf (init_file, " rs6000_overload_info[RS6000_OVLD_%s - base]" @@ -2854,8 +2845,6 @@ write_init_file (void) fprintf (init_file, "#include \"rs6000-builtins.h\"\n"); fprintf (init_file, "\n"); - fprintf (init_file, "int new_builtins_are_live = 1;\n\n"); - fprintf (init_file, "tree rs6000_builtin_decls_x[RS6000_OVLD_MAX];\n\n"); write_bif_static_init (); diff --git a/gcc/config/rs6000/rs6000.c b/gcc/config/rs6000/rs6000.c index 5e129986516..70df511ff98 100644 --- a/gcc/config/rs6000/rs6000.c +++ b/gcc/config/rs6000/rs6000.c @@ -5929,132 +5929,7 @@ static tree rs6000_builtin_vectorized_function (unsigned int fn, tree type_out, tree type_in) { - machine_mode in_mode, out_mode; - int in_n, out_n; - - if (new_builtins_are_live) - return rs6000_new_builtin_vectorized_function (fn, type_out, type_in); - - if (TARGET_DEBUG_BUILTIN) - fprintf (stderr, "rs6000_builtin_vectorized_function (%s, %s, %s)\n", - combined_fn_name (combined_fn (fn)), - GET_MODE_NAME (TYPE_MODE (type_out)), - GET_MODE_NAME (TYPE_MODE (type_in))); - - if (TREE_CODE (type_out) != VECTOR_TYPE - || TREE_CODE (type_in) != VECTOR_TYPE) - return NULL_TREE; - - out_mode = TYPE_MODE (TREE_TYPE (type_out)); - out_n = TYPE_VECTOR_SUBPARTS (type_out); - in_mode = TYPE_MODE (TREE_TYPE (type_in)); - in_n = TYPE_VECTOR_SUBPARTS (type_in); - - switch (fn) - { - CASE_CFN_COPYSIGN: - if (VECTOR_UNIT_VSX_P (V2DFmode) - && out_mode == DFmode && out_n == 2 - && in_mode == DFmode && in_n == 2) - return rs6000_builtin_decls[VSX_BUILTIN_CPSGNDP]; - if (VECTOR_UNIT_VSX_P (V4SFmode) - && out_mode == SFmode && out_n == 4 - && in_mode == SFmode && in_n == 4) - return rs6000_builtin_decls[VSX_BUILTIN_CPSGNSP]; - if (VECTOR_UNIT_ALTIVEC_P (V4SFmode) - && out_mode == SFmode && out_n == 4 - && in_mode == SFmode && in_n == 4) - return rs6000_builtin_decls[ALTIVEC_BUILTIN_COPYSIGN_V4SF]; - break; - CASE_CFN_CEIL: - if (VECTOR_UNIT_VSX_P (V2DFmode) - && out_mode == DFmode && out_n == 2 - && in_mode == DFmode && in_n == 2) - return rs6000_builtin_decls[VSX_BUILTIN_XVRDPIP]; - if (VECTOR_UNIT_VSX_P (V4SFmode) - && out_mode == SFmode && out_n == 4 - && in_mode == SFmode && in_n == 4) - return rs6000_builtin_decls[VSX_BUILTIN_XVRSPIP]; - if (VECTOR_UNIT_ALTIVEC_P (V4SFmode) - && out_mode == SFmode && out_n == 4 - && in_mode == SFmode && in_n == 4) - return rs6000_builtin_decls[ALTIVEC_BUILTIN_VRFIP]; - break; - CASE_CFN_FLOOR: - if (VECTOR_UNIT_VSX_P (V2DFmode) - && out_mode == DFmode && out_n == 2 - && in_mode == DFmode && in_n == 2) - return rs6000_builtin_decls[VSX_BUILTIN_XVRDPIM]; - if (VECTOR_UNIT_VSX_P (V4SFmode) - && out_mode == SFmode && out_n == 4 - && in_mode == SFmode && in_n == 4) - return rs6000_builtin_decls[VSX_BUILTIN_XVRSPIM]; - if (VECTOR_UNIT_ALTIVEC_P (V4SFmode) - && out_mode == SFmode && out_n == 4 - && in_mode == SFmode && in_n == 4) - return rs6000_builtin_decls[ALTIVEC_BUILTIN_VRFIM]; - break; - CASE_CFN_FMA: - if (VECTOR_UNIT_VSX_P (V2DFmode) - && out_mode == DFmode && out_n == 2 - && in_mode == DFmode && in_n == 2) - return rs6000_builtin_decls[VSX_BUILTIN_XVMADDDP]; - if (VECTOR_UNIT_VSX_P (V4SFmode) - && out_mode == SFmode && out_n == 4 - && in_mode == SFmode && in_n == 4) - return rs6000_builtin_decls[VSX_BUILTIN_XVMADDSP]; - if (VECTOR_UNIT_ALTIVEC_P (V4SFmode) - && out_mode == SFmode && out_n == 4 - && in_mode == SFmode && in_n == 4) - return rs6000_builtin_decls[ALTIVEC_BUILTIN_VMADDFP]; - break; - CASE_CFN_TRUNC: - if (VECTOR_UNIT_VSX_P (V2DFmode) - && out_mode == DFmode && out_n == 2 - && in_mode == DFmode && in_n == 2) - return rs6000_builtin_decls[VSX_BUILTIN_XVRDPIZ]; - if (VECTOR_UNIT_VSX_P (V4SFmode) - && out_mode == SFmode && out_n == 4 - && in_mode == SFmode && in_n == 4) - return rs6000_builtin_decls[VSX_BUILTIN_XVRSPIZ]; - if (VECTOR_UNIT_ALTIVEC_P (V4SFmode) - && out_mode == SFmode && out_n == 4 - && in_mode == SFmode && in_n == 4) - return rs6000_builtin_decls[ALTIVEC_BUILTIN_VRFIZ]; - break; - CASE_CFN_NEARBYINT: - if (VECTOR_UNIT_VSX_P (V2DFmode) - && flag_unsafe_math_optimizations - && out_mode == DFmode && out_n == 2 - && in_mode == DFmode && in_n == 2) - return rs6000_builtin_decls[VSX_BUILTIN_XVRDPI]; - if (VECTOR_UNIT_VSX_P (V4SFmode) - && flag_unsafe_math_optimizations - && out_mode == SFmode && out_n == 4 - && in_mode == SFmode && in_n == 4) - return rs6000_builtin_decls[VSX_BUILTIN_XVRSPI]; - break; - CASE_CFN_RINT: - if (VECTOR_UNIT_VSX_P (V2DFmode) - && !flag_trapping_math - && out_mode == DFmode && out_n == 2 - && in_mode == DFmode && in_n == 2) - return rs6000_builtin_decls[VSX_BUILTIN_XVRDPIC]; - if (VECTOR_UNIT_VSX_P (V4SFmode) - && !flag_trapping_math - && out_mode == SFmode && out_n == 4 - && in_mode == SFmode && in_n == 4) - return rs6000_builtin_decls[VSX_BUILTIN_XVRSPIC]; - break; - default: - break; - } - - /* Generate calls to libmass if appropriate. */ - if (rs6000_veclib_handler) - return rs6000_veclib_handler (combined_fn (fn), type_out, type_in); - - return NULL_TREE; + return rs6000_new_builtin_vectorized_function (fn, type_out, type_in); } /* Implement TARGET_VECTORIZE_BUILTIN_MD_VECTORIZED_FUNCTION. */ @@ -6063,113 +5938,7 @@ static tree rs6000_builtin_md_vectorized_function (tree fndecl, tree type_out, tree type_in) { - machine_mode in_mode, out_mode; - int in_n, out_n; - - if (new_builtins_are_live) - return rs6000_new_builtin_md_vectorized_function (fndecl, type_out, - type_in); - - if (TARGET_DEBUG_BUILTIN) - fprintf (stderr, "rs6000_builtin_md_vectorized_function (%s, %s, %s)\n", - IDENTIFIER_POINTER (DECL_NAME (fndecl)), - GET_MODE_NAME (TYPE_MODE (type_out)), - GET_MODE_NAME (TYPE_MODE (type_in))); - - if (TREE_CODE (type_out) != VECTOR_TYPE - || TREE_CODE (type_in) != VECTOR_TYPE) - return NULL_TREE; - - out_mode = TYPE_MODE (TREE_TYPE (type_out)); - out_n = TYPE_VECTOR_SUBPARTS (type_out); - in_mode = TYPE_MODE (TREE_TYPE (type_in)); - in_n = TYPE_VECTOR_SUBPARTS (type_in); - - enum rs6000_builtins fn - = (enum rs6000_builtins) DECL_MD_FUNCTION_CODE (fndecl); - switch (fn) - { - case RS6000_BUILTIN_RSQRTF: - if (VECTOR_UNIT_ALTIVEC_OR_VSX_P (V4SFmode) - && out_mode == SFmode && out_n == 4 - && in_mode == SFmode && in_n == 4) - return rs6000_builtin_decls[ALTIVEC_BUILTIN_VRSQRTFP]; - break; - case RS6000_BUILTIN_RSQRT: - if (VECTOR_UNIT_VSX_P (V2DFmode) - && out_mode == DFmode && out_n == 2 - && in_mode == DFmode && in_n == 2) - return rs6000_builtin_decls[VSX_BUILTIN_RSQRT_2DF]; - break; - case RS6000_BUILTIN_RECIPF: - if (VECTOR_UNIT_ALTIVEC_OR_VSX_P (V4SFmode) - && out_mode == SFmode && out_n == 4 - && in_mode == SFmode && in_n == 4) - return rs6000_builtin_decls[ALTIVEC_BUILTIN_VRECIPFP]; - break; - case RS6000_BUILTIN_RECIP: - if (VECTOR_UNIT_VSX_P (V2DFmode) - && out_mode == DFmode && out_n == 2 - && in_mode == DFmode && in_n == 2) - return rs6000_builtin_decls[VSX_BUILTIN_RECIP_V2DF]; - break; - default: - break; - } - - machine_mode in_vmode = TYPE_MODE (type_in); - machine_mode out_vmode = TYPE_MODE (type_out); - - /* Power10 supported vectorized built-in functions. */ - if (TARGET_POWER10 - && in_vmode == out_vmode - && VECTOR_UNIT_ALTIVEC_OR_VSX_P (in_vmode)) - { - machine_mode exp_mode = DImode; - machine_mode exp_vmode = V2DImode; - enum rs6000_builtins bif; - switch (fn) - { - case MISC_BUILTIN_DIVWE: - case MISC_BUILTIN_DIVWEU: - exp_mode = SImode; - exp_vmode = V4SImode; - if (fn == MISC_BUILTIN_DIVWE) - bif = P10V_BUILTIN_DIVES_V4SI; - else - bif = P10V_BUILTIN_DIVEU_V4SI; - break; - case MISC_BUILTIN_DIVDE: - case MISC_BUILTIN_DIVDEU: - if (fn == MISC_BUILTIN_DIVDE) - bif = P10V_BUILTIN_DIVES_V2DI; - else - bif = P10V_BUILTIN_DIVEU_V2DI; - break; - case P10_BUILTIN_CFUGED: - bif = P10V_BUILTIN_VCFUGED; - break; - case P10_BUILTIN_CNTLZDM: - bif = P10V_BUILTIN_VCLZDM; - break; - case P10_BUILTIN_CNTTZDM: - bif = P10V_BUILTIN_VCTZDM; - break; - case P10_BUILTIN_PDEPD: - bif = P10V_BUILTIN_VPDEPD; - break; - case P10_BUILTIN_PEXTD: - bif = P10V_BUILTIN_VPEXTD; - break; - default: - return NULL_TREE; - } - - if (in_mode == exp_mode && in_vmode == exp_vmode) - return rs6000_builtin_decls[bif]; - } - - return NULL_TREE; + return rs6000_new_builtin_md_vectorized_function (fndecl, type_out, type_in); } /* Default CPU string for rs6000*_file_start functions. */ @@ -22749,17 +22518,13 @@ rs6000_builtin_reciprocal (tree fndecl) if (!RS6000_RECIP_AUTO_RSQRTE_P (V2DFmode)) return NULL_TREE; - if (new_builtins_are_live) - return rs6000_builtin_decls_x[RS6000_BIF_RSQRT_2DF]; - return rs6000_builtin_decls[VSX_BUILTIN_RSQRT_2DF]; + return rs6000_builtin_decls_x[RS6000_BIF_RSQRT_2DF]; case RS6000_BIF_XVSQRTSP: if (!RS6000_RECIP_AUTO_RSQRTE_P (V4SFmode)) return NULL_TREE; - if (new_builtins_are_live) - return rs6000_builtin_decls_x[RS6000_BIF_RSQRT_4SF]; - return rs6000_builtin_decls[VSX_BUILTIN_RSQRT_4SF]; + return rs6000_builtin_decls_x[RS6000_BIF_RSQRT_4SF]; default: return NULL_TREE; @@ -25381,10 +25146,7 @@ add_condition_to_bb (tree function_decl, tree version_decl, tree bool_zero = build_int_cst (bool_int_type_node, 0); tree cond_var = create_tmp_var (bool_int_type_node); - tree predicate_decl - = new_builtins_are_live - ? rs6000_builtin_decls_x[(int) RS6000_BIF_CPU_SUPPORTS] - : rs6000_builtin_decls [(int) RS6000_BUILTIN_CPU_SUPPORTS]; + tree predicate_decl = rs6000_builtin_decls_x[(int) RS6000_BIF_CPU_SUPPORTS]; const char *arg_str = rs6000_clone_map[clone_isa].name; tree predicate_arg = build_string_literal (strlen (arg_str) + 1, arg_str); gimple *call_cond_stmt = gimple_build_call (predicate_decl, 1, predicate_arg); @@ -28024,12 +27786,8 @@ rs6000_atomic_assign_expand_fenv (tree *hold, tree *clear, tree *update) return; } - tree mffs - = new_builtins_are_live ? rs6000_builtin_decls_x[RS6000_BIF_MFFS] - : rs6000_builtin_decls[RS6000_BUILTIN_MFFS]; - tree mtfsf - = new_builtins_are_live ? rs6000_builtin_decls_x[RS6000_BIF_MTFSF] - : rs6000_builtin_decls[RS6000_BUILTIN_MTFSF]; + tree mffs = rs6000_builtin_decls_x[RS6000_BIF_MFFS]; + tree mtfsf = rs6000_builtin_decls_x[RS6000_BIF_MTFSF]; tree call_mffs = build_call_expr (mffs, 0); /* Generates the equivalent of feholdexcept (&fenv_var)