{ "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);
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
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 %<long double%> 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 %<long double%> 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<builtin_hasher>::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<builtin_hash_struct> ();
- *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