public inbox for gcc-cvs@sourceware.org
help / color / mirror / Atom feed
* [gcc(refs/users/wschmidt/heads/builtins4)] rs6000: Resolve the fcode problems in rs6000_expand_builtin
@ 2020-12-16 18:08 William Schmidt
0 siblings, 0 replies; 4+ messages in thread
From: William Schmidt @ 2020-12-16 18:08 UTC (permalink / raw)
To: gcc-cvs
https://gcc.gnu.org/g:1c6af0bac21b9f19c1dad3d06b72dcee865464c6
commit 1c6af0bac21b9f19c1dad3d06b72dcee865464c6
Author: Bill Schmidt <wschmidt@linux.ibm.com>
Date: Mon Nov 16 15:51:48 2020 -0500
rs6000: Resolve the fcode problems in rs6000_expand_builtin
2020-11-16 Bill Schmidt <wschmidt@linux.ibm.com>
* config/rs6000/rs6000-call.c (rs6000_expand_new_builtin): New
forward decl.
(ldv_expand_builtin): Move.
(new_mma_expand_builtin): Move.
(stv_expand_builtin): Move.
(elemrev_icode): Move and rewrite.
(htm_spr_num): Move and rewrite.
(new_htm_expand_builtin): Move.
(rs6000_expand_ldst_mask): Move and rewrite.
(rs6000_expand_builtin): Call rs6000_expand_new_builtin; remove
logic for new_builtins_are_live.
(rs6000_expand_new_builtin): New.
Diff:
---
gcc/config/rs6000/rs6000-call.c | 2201 +++++++++++++++++++++------------------
1 file changed, 1180 insertions(+), 1021 deletions(-)
diff --git a/gcc/config/rs6000/rs6000-call.c b/gcc/config/rs6000/rs6000-call.c
index 2feb94406c6..aaba53fded4 100644
--- a/gcc/config/rs6000/rs6000-call.c
+++ b/gcc/config/rs6000/rs6000-call.c
@@ -184,7 +184,7 @@ static tree builtin_function_type (machine_mode, machine_mode,
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);
/* Hash table to keep track of the argument types for builtin functions. */
@@ -10262,60 +10262,6 @@ altivec_expand_lv_builtin (enum insn_code icode, tree exp, rtx target, bool blk)
return target;
}
-static rtx
-ldv_expand_builtin (rtx target, insn_code icode, rtx *op, machine_mode tmode)
-{
- rtx pat, addr;
- bool blk = (icode == CODE_FOR_altivec_lvlx
- || icode == CODE_FOR_altivec_lvlxl
- || icode == CODE_FOR_altivec_lvrx
- || icode == CODE_FOR_altivec_lvrxl);
- op[1] = copy_to_mode_reg (Pmode, op[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)
- {
- 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]);
- }
- 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
- {
- 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]));
- }
-
- pat = GEN_FCN (icode) (target, addr);
- if (! pat)
- return 0;
- emit_insn (pat);
- }
-
- return target;
-}
-
static rtx
altivec_expand_stxvl_builtin (enum insn_code icode, tree exp)
{
@@ -10570,357 +10516,148 @@ mma_expand_builtin (tree exp, rtx target, bool *expandedp)
return target;
}
-/* Expand the MMA built-in in EXP. */
+/* 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 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 the HTM builtin in EXP and store the result in TARGET.
+ Store true in *EXPANDEDP if we found a builtin to expand. */
static rtx
-new_mma_expand_builtin (tree exp, rtx target, rs6000_builtins fcode,
- insn_code icode)
+htm_expand_builtin (tree exp, rtx target, bool * expandedp)
{
tree fndecl = TREE_OPERAND (CALL_EXPR_FN (exp), 0);
- tree arg;
- call_expr_arg_iterator iter;
- const struct insn_operand_data *insn_op;
- rtx op[MAX_MMA_OPERANDS];
- unsigned nopnds = 0;
- /* ### This attr/void_func business needs replacing. */
- unsigned attr = rs6000_builtin_info[fcode].attr;
- bool void_func = (attr & RS6000_BTC_VOID);
- machine_mode tmode = VOIDmode;
+ 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;
- if (TREE_TYPE (TREE_TYPE (fndecl)) != void_type_node)
+ *expandedp = true;
+
+ if (!TARGET_POWERPC64
+ && (fcode == HTM_BUILTIN_TABORTDC
+ || fcode == HTM_BUILTIN_TABORTDCI))
{
- 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;
+ 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;
}
- else
- target = const0_rtx;
- FOR_EACH_CALL_EXPR_ARG (arg, iter, exp)
- {
- if (arg == error_mark_node)
- return const0_rtx;
+ /* 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;
- 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 (uses_spr)
+ icode = rs6000_htm_spr_icode (nonvoid);
+ insn_op = &insn_data[icode].operand[0];
- if (!(*insn_op->predicate) (opnd, insn_op->mode))
+ 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 (!strcmp (insn_op->constraint, "n"))
+ 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 (!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;
+ 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]);
}
- opnd = copy_to_mode_reg (insn_op->mode, opnd);
+
+ nopnds++;
}
- /* Some MMA instructions have INOUT accumulator operands, so force
- their target register to be the same as their input register. */
- /* ### The void_func test needs to happen some other way,
- probably with TREE_TYPE (TREE_TYPE (fndecl)) as earlier. */
- 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;
+ /* 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;
+ }
- 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:
- 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:
- 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;
-}
-
-static rtx
-stv_expand_builtin (insn_code icode, rtx *op,
- machine_mode tmode, machine_mode smode)
-{
- rtx pat, addr, rawaddr;
- 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. */
- 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 (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]);
- }
-
- 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 (! (*insn_data[icode].operand[1].predicate) (op[0], smode))
- op[0] = copy_to_mode_reg (smode, op[0]);
-
- 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]));
- }
-
- pat = GEN_FCN (icode) (addr, op[0]);
- if (pat)
- emit_insn (pat);
- }
-
- return NULL_RTX;
-}
-
-static insn_code
-elemrev_icode (rs6000_builtins fcode)
-{
- switch (fcode)
- {
- default:
- gcc_unreachable ();
- case VSX_BUILTIN_ST_ELEMREV_V1TI:
- return (BYTES_BIG_ENDIAN ? CODE_FOR_vsx_store_v1ti
- : CODE_FOR_vsx_st_elemrev_v1ti);
- case VSX_BUILTIN_ST_ELEMREV_V2DF:
- return (BYTES_BIG_ENDIAN ? CODE_FOR_vsx_store_v2df
- : CODE_FOR_vsx_st_elemrev_v2df);
- case VSX_BUILTIN_ST_ELEMREV_V2DI:
- return (BYTES_BIG_ENDIAN ? CODE_FOR_vsx_store_v2di
- : CODE_FOR_vsx_st_elemrev_v2di);
- case VSX_BUILTIN_ST_ELEMREV_V4SF:
- return (BYTES_BIG_ENDIAN ? CODE_FOR_vsx_store_v4sf
- : CODE_FOR_vsx_st_elemrev_v4sf);
- case VSX_BUILTIN_ST_ELEMREV_V4SI:
- return (BYTES_BIG_ENDIAN ? CODE_FOR_vsx_store_v4si
- : CODE_FOR_vsx_st_elemrev_v4si);
- case VSX_BUILTIN_ST_ELEMREV_V8HI:
- return (BYTES_BIG_ENDIAN ? CODE_FOR_vsx_store_v8hi
- : CODE_FOR_vsx_st_elemrev_v8hi);
- case VSX_BUILTIN_ST_ELEMREV_V16QI:
- return (BYTES_BIG_ENDIAN ? CODE_FOR_vsx_store_v16qi
- : CODE_FOR_vsx_st_elemrev_v16qi);
- case VSX_BUILTIN_LD_ELEMREV_V2DF:
- return (BYTES_BIG_ENDIAN ? CODE_FOR_vsx_load_v2df
- : CODE_FOR_vsx_ld_elemrev_v2df);
- case VSX_BUILTIN_LD_ELEMREV_V1TI:
- return (BYTES_BIG_ENDIAN ? CODE_FOR_vsx_load_v1ti
- : CODE_FOR_vsx_ld_elemrev_v1ti);
- case VSX_BUILTIN_LD_ELEMREV_V2DI:
- return (BYTES_BIG_ENDIAN ? CODE_FOR_vsx_load_v2di
- : CODE_FOR_vsx_ld_elemrev_v2di);
- case VSX_BUILTIN_LD_ELEMREV_V4SF:
- return (BYTES_BIG_ENDIAN ? CODE_FOR_vsx_load_v4sf
- : CODE_FOR_vsx_ld_elemrev_v4sf);
- case VSX_BUILTIN_LD_ELEMREV_V4SI:
- return (BYTES_BIG_ENDIAN ? CODE_FOR_vsx_load_v4si
- : CODE_FOR_vsx_ld_elemrev_v4si);
- case VSX_BUILTIN_LD_ELEMREV_V8HI:
- return (BYTES_BIG_ENDIAN ? CODE_FOR_vsx_load_v8hi
- : CODE_FOR_vsx_ld_elemrev_v8hi);
- case VSX_BUILTIN_LD_ELEMREV_V16QI:
- return (BYTES_BIG_ENDIAN ? CODE_FOR_vsx_load_v16qi
- : CODE_FOR_vsx_ld_elemrev_v16qi);
- }
- gcc_unreachable ();
- return (insn_code) 0;
-}
-
-/* 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 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 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)
-{
- 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 (!TARGET_POWERPC64
- && (fcode == HTM_BUILTIN_TABORTDC
- || fcode == HTM_BUILTIN_TABORTDCI))
- {
- 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;
- }
-
- /* 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 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)
{
@@ -11001,156 +10738,6 @@ htm_expand_builtin (tree exp, rtx target, bool * expandedp)
return NULL_RTX;
}
-/* Expand the HTM builtin in EXP and store the result in TARGET. */
-static rtx
-new_htm_expand_builtin (bifdata *bifaddr, rs6000_builtins fcode,
- tree exp, rtx target)
-{
- tree fndecl = TREE_OPERAND (CALL_EXPR_FN (exp), 0);
- bool nonvoid = TREE_TYPE (TREE_TYPE (fndecl)) != void_type_node;
-
- if (!TARGET_POWERPC64
- && (fcode == HTM_BUILTIN_TABORTDC
- || fcode == HTM_BUILTIN_TABORTDCI))
- {
- error ("builtin %qs is only valid in 64-bit mode", bifaddr->bifname);
- return const0_rtx;
- }
-
- rtx op[MAX_HTM_OPERANDS], pat;
- int nopnds = 0;
- tree arg;
- call_expr_arg_iterator iter;
- insn_code icode = bifaddr->icode;
- bool uses_spr = bif_is_htmspr (*bifaddr);
- rtx cr = NULL_RTX;
-
- if (uses_spr)
- icode = rs6000_htm_spr_icode (nonvoid);
- 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;
- }
-
- 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);
- break;
- case HTM_BUILTIN_TSUSPEND: /* Alias for: tsr. 0 */
- op[nopnds++] = GEN_INT (0);
- 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 (bif_is_htmcr (*bifaddr))
- {
- cr = gen_reg_rtx (CCmode);
- op[nopnds++] = cr;
- }
-
- 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 == 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;
-}
-
/* Expand the CPU builtin in FCODE and store the result in TARGET. */
static rtx
@@ -13581,40 +13168,6 @@ rs6000_gimple_fold_builtin (gimple_stmt_iterator *gsi)
return false;
}
-/* Expand ALTIVEC_BUILTIN_MASK_FOR_LOAD. */
-rtx
-rs6000_expand_ldst_mask (rtx target, rs6000_builtins fcode, 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;
- rtx op, addr, pat;
-
- gcc_assert (TARGET_ALTIVEC);
-
- gcc_assert (POINTER_TYPE_P (TREE_TYPE (arg0)));
- op = expand_expr (arg0, NULL_RTX, Pmode, EXPAND_NORMAL);
- addr = memory_address (mode, op);
- gcc_assert (fcode == ALTIVEC_BUILTIN_MASK_FOR_LOAD);
- /* 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;
-}
-
/* 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).
@@ -13626,11 +13179,10 @@ 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);
- /* #### This needs to be rs6000_gen_builtins now. Can't make this
- whole until the full set of builtins has been added, and there
- is no overlap between the two enumerations, so we can run the
- two in parallel. */
enum rs6000_builtins fcode
= (enum rs6000_builtins) DECL_MD_FUNCTION_CODE (fndecl);
size_t uns_fcode = (size_t)fcode;
@@ -13638,18 +13190,9 @@ rs6000_expand_builtin (tree exp, rtx target, rtx subtarget ATTRIBUTE_UNUSED,
size_t i;
rtx ret;
bool success;
- HOST_WIDE_INT mask = (new_builtins_are_live
- ? 0
- : rs6000_builtin_info[uns_fcode].mask);
- /*
- bif_enable enable = (new_builtins_are_live
- ? rs6000_builtin_info_x[uns_fcode].enable
- : (bif_enable) 0);
- */
+ HOST_WIDE_INT mask = rs6000_builtin_info[uns_fcode].mask;
bool func_valid_p = ((rs6000_builtin_mask & mask) == mask);
- enum insn_code icode = (new_builtins_are_live
- ? rs6000_builtin_info_x[uns_fcode].icode
- : rs6000_builtin_info[uns_fcode].icode);
+ 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
@@ -13696,7 +13239,7 @@ rs6000_expand_builtin (tree exp, rtx target, rtx subtarget ATTRIBUTE_UNUSED,
break;
}
- if (!new_builtins_are_live && TARGET_DEBUG_BUILTIN)
+ if (TARGET_DEBUG_BUILTIN)
{
const char *name1 = rs6000_builtin_info[uns_fcode].name;
const char *name2 = (icode != CODE_FOR_nothing)
@@ -13734,496 +13277,1112 @@ rs6000_expand_builtin (tree exp, rtx target, rtx subtarget ATTRIBUTE_UNUSED,
return expand_call (exp, target, ignore);
}
- if (new_builtins_are_live)
+ switch (fcode)
{
- bifdata *bifaddr = &rs6000_builtin_info_x[uns_fcode];
+ case RS6000_BUILTIN_RECIP:
+ return rs6000_expand_binop_builtin (CODE_FOR_recipdf3, exp, target);
- /* In case of "#pragma target" changes, we initialize all builtins
- but check for actual availability during expand time. */
- switch (bifaddr->enable)
- {
- default:
- gcc_unreachable ();
- case ENB_ALWAYS:
- break;
- case ENB_P5:
- if (!TARGET_POPCNTB)
- return const0_rtx;
- break;
- case ENB_P6:
- if (!TARGET_CMPB)
- return const0_rtx;
- break;
- case ENB_ALTIVEC:
- if (!TARGET_ALTIVEC)
- return const0_rtx;
- break;
- case ENB_CELL:
- if (!TARGET_ALTIVEC || rs6000_cpu != PROCESSOR_CELL)
- return const0_rtx;
- break;
- case ENB_VSX:
- if (!TARGET_VSX)
- return const0_rtx;
- break;
- case ENB_P7:
- if (!TARGET_POPCNTD)
- return const0_rtx;
- break;
- case ENB_P7_64:
- if (!TARGET_POPCNTD || !TARGET_POWERPC64)
- return const0_rtx;
- break;
- case ENB_P8:
- if (!TARGET_DIRECT_MOVE)
- return const0_rtx;
- break;
- case ENB_P8V:
- if (!TARGET_P8_VECTOR)
- return const0_rtx;
- break;
- case ENB_P9:
- if (!TARGET_MODULO)
- return const0_rtx;
- break;
- case ENB_P9_64:
- if (!TARGET_MODULO || !TARGET_POWERPC64)
- return const0_rtx;
- break;
- case ENB_P9V:
- if (!TARGET_P9_VECTOR)
- return const0_rtx;
- break;
- case ENB_IEEE128_HW:
- if (!TARGET_FLOAT128_HW)
- return const0_rtx;
- break;
- case ENB_DFP:
- if (!TARGET_DFP)
- return const0_rtx;
- break;
- case ENB_CRYPTO:
- if (!TARGET_CRYPTO)
- return const0_rtx;
- break;
- case ENB_HTM:
- if (!TARGET_HTM)
- return const0_rtx;
- break;
- case ENB_P10:
- if (!TARGET_POWER10)
- return const0_rtx;
- break;
- case ENB_MMA:
- if (!TARGET_MMA)
- return const0_rtx;
- break;
- };
+ case RS6000_BUILTIN_RECIPF:
+ return rs6000_expand_binop_builtin (CODE_FOR_recipsf3, exp, target);
- if (bif_is_nosoft (*bifaddr)
- && rs6000_isa_flags & OPTION_MASK_SOFT_FLOAT)
- {
- error ("%<%s%> not supported with %<-msoft-float%>",
- bifaddr->bifname);
- return const0_rtx;
- }
+ case RS6000_BUILTIN_RSQRTF:
+ return rs6000_expand_unop_builtin (CODE_FOR_rsqrtsf2, exp, target);
- if (bif_is_no32bit (*bifaddr) && TARGET_32BIT)
- fatal_error (input_location,
- "%<%s%> is not supported in 32-bit mode",
- bifaddr->bifname);
+ 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);
- if (bif_is_cpu (*bifaddr))
- return cpu_expand_builtin (fcode, exp, target);
+ case RS6000_BUILTIN_MTFSB0:
+ return rs6000_expand_mtfsb_builtin (CODE_FOR_rs6000_mtfsb0, exp);
- if (bif_is_init (*bifaddr))
- return altivec_expand_vec_init_builtin (TREE_TYPE (exp), exp, target);
+ 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;
+ }
- if (bif_is_set (*bifaddr))
- return altivec_expand_vec_set_builtin (exp);
+ 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;
- if (bif_is_extract (*bifaddr))
- return altivec_expand_vec_ext_builtin (exp, target);
+ gcc_assert (TARGET_ALTIVEC);
- if (bif_is_predicate (*bifaddr))
- return altivec_expand_predicate_builtin (icode, exp, target);
+ 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 (bif_is_htm (*bifaddr))
- return new_htm_expand_builtin (bifaddr, fcode, exp, target);
+ if (target == 0
+ || GET_MODE (target) != tmode
+ || ! (*insn_data[icode2].operand[0].predicate) (target, tmode))
+ target = gen_reg_rtx (tmode);
- rtx pat;
- const int MAX_BUILTIN_ARGS = 5;
- tree arg[MAX_BUILTIN_ARGS];
- rtx op[MAX_BUILTIN_ARGS];
- machine_mode mode[MAX_BUILTIN_ARGS + 1];
+ pat = GEN_FCN (icode2) (target, op);
+ if (!pat)
+ return 0;
+ emit_insn (pat);
- int nargs = bifaddr->nargs;
- gcc_assert (nargs <= MAX_BUILTIN_ARGS);
+ return target;
+ }
- mode[0] = insn_data[icode].operand[0].mode;
- for (int i = 0; i < nargs; i++)
+ case ALTIVEC_BUILTIN_VCFUX:
+ case ALTIVEC_BUILTIN_VCFSX:
+ case ALTIVEC_BUILTIN_VCTUXS:
+ case ALTIVEC_BUILTIN_VCTSXS:
+ /* #### Replace this nonsense with a separate built-in for the
+ vectorizer to use, which I believe is the only way we get
+ into this situation. */
+ /* 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)
{
- arg[i] = CALL_EXPR_ARG (exp, i);
- if (arg[i] == error_mark_node)
- return const0_rtx;
- op[i] = expand_normal (arg[i]);
- mode[i+1] = insn_data[icode].operand[i+1].mode;
+ exp = build_call_nary (TREE_TYPE (exp), CALL_EXPR_FN (exp),
+ 2, CALL_EXPR_ARG (exp, 0),
+ integer_zero_node);
}
+ break;
- /* Check for restricted constant arguments. */
- for (int i = 0; i < 2; i++)
- {
- switch (bifaddr->restr[i])
- {
- default:
- case RES_NONE:
- break;
- case RES_BITS:
- {
- size_t mask = (1 << bifaddr->restr_val1[i]) - 1;
- 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)
- {
- 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;
- }
- }
- }
-
- if (bif_is_ldstmask (*bifaddr))
- return rs6000_expand_ldst_mask (target, fcode, arg[0]);
-
- if (bif_is_stvec (*bifaddr))
- {
- if (bif_is_reve (*bifaddr))
- icode = elemrev_icode (fcode);
- return stv_expand_builtin (icode, op, mode[0], mode[1]);
- }
-
- if (bif_is_ldvec (*bifaddr))
- {
- if (bif_is_reve (*bifaddr))
- icode = elemrev_icode (fcode);
- return ldv_expand_builtin (target, icode, op, mode[0]);
- }
-
- if (bif_is_mma (*bifaddr))
- return new_mma_expand_builtin (exp, target, fcode, icode);
-
- if (fcode == MISC_BUILTIN_PACK_IF
- && TARGET_LONG_DOUBLE_128 && !TARGET_IEEEQUAD)
+ /* 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;
}
- else if (fcode == MISC_BUILTIN_UNPACK_IF
- && TARGET_LONG_DOUBLE_128 && !TARGET_IEEEQUAD)
+ 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;
- if (target == 0
- || GET_MODE (target) != mode[0]
- || !(*insn_data[icode].operand[0].predicate) (target, mode[0]))
- target = gen_reg_rtx (mode[0]);
-
- for (int i = 0; i < nargs; i++)
- if (! (*insn_data[icode].operand[i+1].predicate) (op[i], mode[i+1]))
- op[i] = copy_to_mode_reg (mode[i+1], op[i]);
-
- switch (nargs)
- {
- default:
- gcc_assert (MAX_BUILTIN_ARGS == 5);
- gcc_unreachable ();
- case 0:
- pat = GEN_FCN (icode) (target);
- break;
- case 1:
- pat = GEN_FCN (icode) (target, op[0]);
- break;
- case 2:
- pat = GEN_FCN (icode) (target, op[0], op[1]);
- break;
- case 3:
- pat = GEN_FCN (icode) (target, op[0], op[1], op[2]);
- break;
- case 4:
- pat = GEN_FCN (icode) (target, op[0], op[1], op[2], op[3]);
- break;
- case 5:
- pat = GEN_FCN (icode) (target, op[0], op[1], op[2], op[3], op[4]);
- break;
- }
+ default:
+ break;
+ }
- if (!pat)
- return 0;
- emit_insn (pat);
+ if (TARGET_MMA)
+ {
+ ret = mma_expand_builtin (exp, target, &success);
- return target;
+ if (success)
+ return ret;
}
- else
+ if (TARGET_ALTIVEC)
{
- switch (fcode)
- {
- case RS6000_BUILTIN_RECIP:
- return rs6000_expand_binop_builtin (CODE_FOR_recipdf3, exp, target);
+ ret = altivec_expand_builtin (exp, target, &success);
- 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);
+ if (success)
+ return ret;
+ }
+ if (TARGET_HTM)
+ {
+ ret = htm_expand_builtin (exp, target, &success);
- case RS6000_BUILTIN_RSQRT:
- return rs6000_expand_unop_builtin (CODE_FOR_rsqrtdf2, exp, target);
+ if (success)
+ return ret;
+ }
- case POWER7_BUILTIN_BPERMD:
- return rs6000_expand_binop_builtin (((TARGET_64BIT)
- ? CODE_FOR_bpermd_di
- : CODE_FOR_bpermd_si),
- exp, target);
+ unsigned attr = (rs6000_builtin_info[uns_fcode].attr
+ & RS6000_BTC_TYPE_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);
- case RS6000_BUILTIN_GET_TB:
- return rs6000_expand_zeroop_builtin (CODE_FOR_rs6000_get_timebase,
- target);
+ /* 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);
- case RS6000_BUILTIN_MFTB:
- return rs6000_expand_zeroop_builtin (((TARGET_64BIT)
- ? CODE_FOR_rs6000_mftb_di
- : CODE_FOR_rs6000_mftb_si),
- 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);
- case RS6000_BUILTIN_MFFS:
- return rs6000_expand_zeroop_builtin (CODE_FOR_rs6000_mffs, 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);
- case RS6000_BUILTIN_MTFSB0:
- return rs6000_expand_mtfsb_builtin (CODE_FOR_rs6000_mtfsb0, exp);
+ /* 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);
- case RS6000_BUILTIN_MTFSB1:
- return rs6000_expand_mtfsb_builtin (CODE_FOR_rs6000_mtfsb1, exp);
+ /* 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);
- case RS6000_BUILTIN_SET_FPSCR_RN:
- return rs6000_expand_set_fpscr_rn_builtin
- (CODE_FOR_rs6000_set_fpscr_rn, exp);
+ gcc_unreachable ();
+}
- case RS6000_BUILTIN_SET_FPSCR_DRN:
- return
- rs6000_expand_set_fpscr_drn_builtin (CODE_FOR_rs6000_set_fpscr_drn,
- exp);
+/* 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;
+ rtx op, addr, pat;
- case RS6000_BUILTIN_MFFSL:
- return rs6000_expand_zeroop_builtin (CODE_FOR_rs6000_mffsl, target);
+ gcc_assert (TARGET_ALTIVEC);
- case RS6000_BUILTIN_MTFSF:
- return rs6000_expand_mtfsf_builtin (CODE_FOR_rs6000_mtfsf, exp);
+ gcc_assert (POINTER_TYPE_P (TREE_TYPE (arg0)));
+ op = expand_expr (arg0, 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);
- case RS6000_BUILTIN_CPU_INIT:
- case RS6000_BUILTIN_CPU_IS:
- case RS6000_BUILTIN_CPU_SUPPORTS:
- return cpu_expand_builtin (fcode, exp, target);
+ if (target == 0
+ || GET_MODE (target) != tmode
+ || ! (*insn_data[icode2].operand[0].predicate) (target, tmode))
+ target = gen_reg_rtx (tmode);
- case MISC_BUILTIN_SPEC_BARRIER:
- {
- emit_insn (gen_speculation_barrier ());
- return NULL_RTX;
- }
+ pat = GEN_FCN (icode2) (target, op);
+ if (!pat)
+ return 0;
+ emit_insn (pat);
- 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);
+ return target;
+}
- pat = GEN_FCN (icode2) (target, op);
- if (!pat)
- return 0;
- emit_insn (pat);
+/* Expand the CPU builtin in FCODE and store the result in TARGET. */
- return 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;
- case ALTIVEC_BUILTIN_VCFUX:
- case ALTIVEC_BUILTIN_VCFSX:
- case ALTIVEC_BUILTIN_VCTUXS:
- case ALTIVEC_BUILTIN_VCTSXS:
- /* #### Replace this nonsense with a separate built-in for the
- vectorizer to use, which I believe is the only way we get
- into this situation. */
- /* 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;
+ if (target == 0 || GET_MODE (target) != SImode)
+ target = gen_reg_rtx (SImode);
- /* 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;
+#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);
- 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;
+ 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;
+ }
- default:
- break;
+ 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;
}
- if (TARGET_MMA)
+ 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_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)
{
- ret = mma_expand_builtin (exp, target, &success);
-
- if (success)
- return ret;
+ /* 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;
}
- 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_TYPE_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);
+ 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)));
+ }
+ 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;
+}
+static insn_code
+elemrev_icode (rs6000_gen_builtins fcode)
+{
+ switch (fcode)
+ {
+ default:
gcc_unreachable ();
+ 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);
}
+ gcc_unreachable ();
+ return (insn_code) 0;
+}
+
+static rtx
+ldv_expand_builtin (rtx target, insn_code icode, rtx *op, machine_mode tmode)
+{
+ rtx pat, addr;
+ bool blk = (icode == CODE_FOR_altivec_lvlx
+ || icode == CODE_FOR_altivec_lvlxl
+ || icode == CODE_FOR_altivec_lvrx
+ || icode == CODE_FOR_altivec_lvrxl);
+ op[1] = copy_to_mode_reg (Pmode, op[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)
+ {
+ 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]);
+ }
+ 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
+ {
+ 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]));
+ }
+
+ pat = GEN_FCN (icode) (target, addr);
+ if (! pat)
+ return 0;
+ emit_insn (pat);
+ }
+
+ return target;
+}
+
+static rtx
+stv_expand_builtin (insn_code icode, rtx *op,
+ machine_mode tmode, machine_mode smode)
+{
+ rtx pat, addr, rawaddr;
+ 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. */
+ 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 (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]);
+ }
+
+ 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 (! (*insn_data[icode].operand[1].predicate) (op[0], smode))
+ op[0] = copy_to_mode_reg (smode, op[0]);
+
+ 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]));
+ }
+
+ pat = GEN_FCN (icode) (addr, op[0]);
+ if (pat)
+ emit_insn (pat);
+ }
+
+ return NULL_RTX;
+}
+
+/* Expand the MMA built-in in EXP. */
+static rtx
+new_mma_expand_builtin (tree exp, rtx target, insn_code icode)
+{
+ tree fndecl = TREE_OPERAND (CALL_EXPR_FN (exp), 0);
+ tree arg;
+ call_expr_arg_iterator iter;
+ const struct insn_operand_data *insn_op;
+ rtx op[MAX_MMA_OPERANDS];
+ unsigned nopnds = 0;
+ bool void_func = TREE_TYPE (TREE_TYPE (fndecl)) == void_type_node;
+ machine_mode tmode = VOIDmode;
+
+ if (TREE_TYPE (TREE_TYPE (fndecl)) != void_type_node)
+ {
+ 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;
+
+ 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;
+ }
+
+ 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;
+ case 5:
+ 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. */
+static rtx
+new_htm_expand_builtin (bifdata *bifaddr, rs6000_gen_builtins fcode,
+ tree exp, rtx target)
+{
+ tree fndecl = TREE_OPERAND (CALL_EXPR_FN (exp), 0);
+ bool nonvoid = TREE_TYPE (TREE_TYPE (fndecl)) != void_type_node;
+
+ 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;
+ }
+
+ rtx op[MAX_HTM_OPERANDS], pat;
+ int nopnds = 0;
+ tree arg;
+ call_expr_arg_iterator iter;
+ insn_code icode = bifaddr->icode;
+ bool uses_spr = bif_is_htmspr (*bifaddr);
+ rtx cr = NULL_RTX;
+
+ if (uses_spr)
+ icode = rs6000_htm_spr_icode (nonvoid);
+ 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;
+ }
+
+ 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 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;
+ }
+
+ /* 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, new_htm_spr_num (fcode));
+ }
+ /* If this builtin accesses a CR, then pass in a scratch
+ CR as the last operand. */
+ else if (bif_is_htmcr (*bifaddr))
+ {
+ cr = gen_reg_rtx (CCmode);
+ op[nopnds++] = cr;
+ }
+
+ 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 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;
+}
+
+/* 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 ATTRIBUTE_UNUSED,
+ machine_mode ignore_mode ATTRIBUTE_UNUSED,
+ int ignore ATTRIBUTE_UNUSED)
+{
+ 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;
+
+ /* 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;
+ }
+
+ bifdata *bifaddr = &rs6000_builtin_info_x[uns_fcode];
+
+ /* In case of "#pragma target" changes, we initialize all builtins
+ but check for actual availability during expand time. For
+ invalid builtins, generate a normal call. */
+ switch (bifaddr->enable)
+ {
+ default:
+ gcc_unreachable ();
+ case ENB_ALWAYS:
+ break;
+ case ENB_P5:
+ if (!TARGET_POPCNTB)
+ {
+ error ("%qs requires at least %qs\n",
+ bifaddr->bifname, "-mcpu=power5");
+ return expand_call (exp, target, ignore);
+ }
+ break;
+ case ENB_P6:
+ if (!TARGET_CMPB)
+ return const0_rtx;
+ break;
+ case ENB_ALTIVEC:
+ if (!TARGET_ALTIVEC)
+ return const0_rtx;
+ break;
+ case ENB_CELL:
+ if (!TARGET_ALTIVEC || rs6000_cpu != PROCESSOR_CELL)
+ return const0_rtx;
+ break;
+ case ENB_VSX:
+ if (!TARGET_VSX)
+ return const0_rtx;
+ break;
+ case ENB_P7:
+ if (!TARGET_POPCNTD)
+ return const0_rtx;
+ break;
+ case ENB_P7_64:
+ if (!TARGET_POPCNTD || !TARGET_POWERPC64)
+ return const0_rtx;
+ break;
+ case ENB_P8:
+ if (!TARGET_DIRECT_MOVE)
+ return const0_rtx;
+ break;
+ case ENB_P8V:
+ if (!TARGET_P8_VECTOR)
+ return const0_rtx;
+ break;
+ case ENB_P9:
+ if (!TARGET_MODULO)
+ return const0_rtx;
+ break;
+ case ENB_P9_64:
+ if (!TARGET_MODULO || !TARGET_POWERPC64)
+ return const0_rtx;
+ break;
+ case ENB_P9V:
+ if (!TARGET_P9_VECTOR)
+ return const0_rtx;
+ break;
+ case ENB_IEEE128_HW:
+ if (!TARGET_FLOAT128_HW)
+ return const0_rtx;
+ break;
+ case ENB_DFP:
+ if (!TARGET_DFP)
+ return const0_rtx;
+ break;
+ case ENB_CRYPTO:
+ if (!TARGET_CRYPTO)
+ return const0_rtx;
+ break;
+ case ENB_HTM:
+ if (!TARGET_HTM)
+ return const0_rtx;
+ break;
+ case ENB_P10:
+ if (!TARGET_POWER10)
+ return const0_rtx;
+ break;
+ case ENB_MMA:
+ if (!TARGET_MMA)
+ return const0_rtx;
+ break;
+ };
+
+ if (bif_is_nosoft (*bifaddr)
+ && rs6000_isa_flags & OPTION_MASK_SOFT_FLOAT)
+ {
+ error ("%<%s%> not supported with %<-msoft-float%>",
+ bifaddr->bifname);
+ return const0_rtx;
+ }
+
+ if (bif_is_no32bit (*bifaddr) && TARGET_32BIT)
+ fatal_error (input_location,
+ "%<%s%> is not supported in 32-bit mode",
+ bifaddr->bifname);
+
+ if (bif_is_cpu (*bifaddr))
+ return new_cpu_expand_builtin (fcode, exp, target);
+
+ if (bif_is_init (*bifaddr))
+ return altivec_expand_vec_init_builtin (TREE_TYPE (exp), exp, target);
+
+ if (bif_is_set (*bifaddr))
+ return altivec_expand_vec_set_builtin (exp);
+
+ if (bif_is_extract (*bifaddr))
+ return altivec_expand_vec_ext_builtin (exp, target);
+
+ if (bif_is_predicate (*bifaddr))
+ return altivec_expand_predicate_builtin (icode, exp, target);
+
+ if (bif_is_htm (*bifaddr))
+ return new_htm_expand_builtin (bifaddr, fcode, exp, target);
+
+ rtx pat;
+ const int MAX_BUILTIN_ARGS = 5;
+ tree arg[MAX_BUILTIN_ARGS];
+ rtx op[MAX_BUILTIN_ARGS];
+ machine_mode mode[MAX_BUILTIN_ARGS + 1];
+
+ int nargs = bifaddr->nargs;
+ gcc_assert (nargs <= MAX_BUILTIN_ARGS);
+
+ mode[0] = insn_data[icode].operand[0].mode;
+ for (int i = 0; i < nargs; i++)
+ {
+ arg[i] = CALL_EXPR_ARG (exp, i);
+ if (arg[i] == error_mark_node)
+ return const0_rtx;
+ op[i] = expand_normal (arg[i]);
+ mode[i+1] = insn_data[icode].operand[i+1].mode;
+ }
+
+ /* Check for restricted constant arguments. */
+ for (int i = 0; i < 2; i++)
+ {
+ switch (bifaddr->restr[i])
+ {
+ default:
+ case RES_NONE:
+ break;
+ case RES_BITS:
+ {
+ size_t mask = (1 << bifaddr->restr_val1[i]) - 1;
+ 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)
+ {
+ 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;
+ }
+ }
+ }
+
+ if (bif_is_ldstmask (*bifaddr))
+ return rs6000_expand_ldst_mask (target, arg[0]);
+
+ if (bif_is_stvec (*bifaddr))
+ {
+ if (bif_is_reve (*bifaddr))
+ icode = elemrev_icode (fcode);
+ return stv_expand_builtin (icode, op, mode[0], mode[1]);
+ }
+
+ if (bif_is_ldvec (*bifaddr))
+ {
+ if (bif_is_reve (*bifaddr))
+ icode = elemrev_icode (fcode);
+ return ldv_expand_builtin (target, icode, op, mode[0]);
+ }
+
+ if (bif_is_mma (*bifaddr))
+ return new_mma_expand_builtin (exp, target, icode);
+
+ 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;
+ }
+
+ if (target == 0
+ || GET_MODE (target) != mode[0]
+ || !(*insn_data[icode].operand[0].predicate) (target, mode[0]))
+ target = gen_reg_rtx (mode[0]);
+
+ for (int i = 0; i < nargs; i++)
+ if (! (*insn_data[icode].operand[i+1].predicate) (op[i], mode[i+1]))
+ op[i] = copy_to_mode_reg (mode[i+1], op[i]);
+
+ switch (nargs)
+ {
+ default:
+ gcc_assert (MAX_BUILTIN_ARGS == 5);
+ gcc_unreachable ();
+ case 0:
+ pat = GEN_FCN (icode) (target);
+ break;
+ case 1:
+ pat = GEN_FCN (icode) (target, op[0]);
+ break;
+ case 2:
+ pat = GEN_FCN (icode) (target, op[0], op[1]);
+ break;
+ case 3:
+ pat = GEN_FCN (icode) (target, op[0], op[1], op[2]);
+ break;
+ case 4:
+ pat = GEN_FCN (icode) (target, op[0], op[1], op[2], op[3]);
+ break;
+ case 5:
+ pat = GEN_FCN (icode) (target, op[0], op[1], op[2], op[3], op[4]);
+ break;
+ }
+
+ if (!pat)
+ return 0;
+ emit_insn (pat);
+
+ return target;
}
/* Create a builtin vector type with a name. Taking care not to give
^ permalink raw reply [flat|nested] 4+ messages in thread
* [gcc(refs/users/wschmidt/heads/builtins4)] rs6000: Resolve the fcode problems in rs6000_expand_builtin
@ 2021-02-07 18:14 William Schmidt
0 siblings, 0 replies; 4+ messages in thread
From: William Schmidt @ 2021-02-07 18:14 UTC (permalink / raw)
To: gcc-cvs
https://gcc.gnu.org/g:36e8aab0d26afc7b6f7a1ab24bf716f6ca43f21a
commit 36e8aab0d26afc7b6f7a1ab24bf716f6ca43f21a
Author: Bill Schmidt <wschmidt@linux.ibm.com>
Date: Mon Nov 16 15:51:48 2020 -0500
rs6000: Resolve the fcode problems in rs6000_expand_builtin
2020-11-16 Bill Schmidt <wschmidt@linux.ibm.com>
* config/rs6000/rs6000-call.c (rs6000_expand_new_builtin): New
forward decl.
(ldv_expand_builtin): Move.
(new_mma_expand_builtin): Move.
(stv_expand_builtin): Move.
(elemrev_icode): Move and rewrite.
(htm_spr_num): Move and rewrite.
(new_htm_expand_builtin): Move.
(rs6000_expand_ldst_mask): Move and rewrite.
(rs6000_expand_builtin): Call rs6000_expand_new_builtin; remove
logic for new_builtins_are_live.
(rs6000_expand_new_builtin): New.
Diff:
---
gcc/config/rs6000/rs6000-call.c | 2201 +++++++++++++++++++++------------------
1 file changed, 1180 insertions(+), 1021 deletions(-)
diff --git a/gcc/config/rs6000/rs6000-call.c b/gcc/config/rs6000/rs6000-call.c
index 74bf38739c6..4fc9dcacfdb 100644
--- a/gcc/config/rs6000/rs6000-call.c
+++ b/gcc/config/rs6000/rs6000-call.c
@@ -184,7 +184,7 @@ static tree builtin_function_type (machine_mode, machine_mode,
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);
/* Hash table to keep track of the argument types for builtin functions. */
@@ -10309,60 +10309,6 @@ altivec_expand_lv_builtin (enum insn_code icode, tree exp, rtx target, bool blk)
return target;
}
-static rtx
-ldv_expand_builtin (rtx target, insn_code icode, rtx *op, machine_mode tmode)
-{
- rtx pat, addr;
- bool blk = (icode == CODE_FOR_altivec_lvlx
- || icode == CODE_FOR_altivec_lvlxl
- || icode == CODE_FOR_altivec_lvrx
- || icode == CODE_FOR_altivec_lvrxl);
- op[1] = copy_to_mode_reg (Pmode, op[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)
- {
- 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]);
- }
- 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
- {
- 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]));
- }
-
- pat = GEN_FCN (icode) (target, addr);
- if (! pat)
- return 0;
- emit_insn (pat);
- }
-
- return target;
-}
-
static rtx
altivec_expand_stxvl_builtin (enum insn_code icode, tree exp)
{
@@ -10617,357 +10563,148 @@ mma_expand_builtin (tree exp, rtx target, bool *expandedp)
return target;
}
-/* Expand the MMA built-in in EXP. */
+/* 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 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 the HTM builtin in EXP and store the result in TARGET.
+ Store true in *EXPANDEDP if we found a builtin to expand. */
static rtx
-new_mma_expand_builtin (tree exp, rtx target, rs6000_builtins fcode,
- insn_code icode)
+htm_expand_builtin (tree exp, rtx target, bool * expandedp)
{
tree fndecl = TREE_OPERAND (CALL_EXPR_FN (exp), 0);
- tree arg;
- call_expr_arg_iterator iter;
- const struct insn_operand_data *insn_op;
- rtx op[MAX_MMA_OPERANDS];
- unsigned nopnds = 0;
- /* ### This attr/void_func business needs replacing. */
- unsigned attr = rs6000_builtin_info[fcode].attr;
- bool void_func = (attr & RS6000_BTC_VOID);
- machine_mode tmode = VOIDmode;
+ 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;
- if (TREE_TYPE (TREE_TYPE (fndecl)) != void_type_node)
+ *expandedp = true;
+
+ if (!TARGET_POWERPC64
+ && (fcode == HTM_BUILTIN_TABORTDC
+ || fcode == HTM_BUILTIN_TABORTDCI))
{
- 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;
+ 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;
}
- else
- target = const0_rtx;
- FOR_EACH_CALL_EXPR_ARG (arg, iter, exp)
- {
- if (arg == error_mark_node)
- return const0_rtx;
+ /* 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;
- 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 (uses_spr)
+ icode = rs6000_htm_spr_icode (nonvoid);
+ insn_op = &insn_data[icode].operand[0];
- if (!(*insn_op->predicate) (opnd, insn_op->mode))
+ 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 (!strcmp (insn_op->constraint, "n"))
+ 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 (!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;
+ 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]);
}
- opnd = copy_to_mode_reg (insn_op->mode, opnd);
+
+ nopnds++;
}
- /* Some MMA instructions have INOUT accumulator operands, so force
- their target register to be the same as their input register. */
- /* ### The void_func test needs to happen some other way,
- probably with TREE_TYPE (TREE_TYPE (fndecl)) as earlier. */
- 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;
+ /* 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;
+ }
- 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:
- 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:
- 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;
-}
-
-static rtx
-stv_expand_builtin (insn_code icode, rtx *op,
- machine_mode tmode, machine_mode smode)
-{
- rtx pat, addr, rawaddr;
- 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. */
- 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 (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]);
- }
-
- 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 (! (*insn_data[icode].operand[1].predicate) (op[0], smode))
- op[0] = copy_to_mode_reg (smode, op[0]);
-
- 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]));
- }
-
- pat = GEN_FCN (icode) (addr, op[0]);
- if (pat)
- emit_insn (pat);
- }
-
- return NULL_RTX;
-}
-
-static insn_code
-elemrev_icode (rs6000_builtins fcode)
-{
- switch (fcode)
- {
- default:
- gcc_unreachable ();
- case VSX_BUILTIN_ST_ELEMREV_V1TI:
- return (BYTES_BIG_ENDIAN ? CODE_FOR_vsx_store_v1ti
- : CODE_FOR_vsx_st_elemrev_v1ti);
- case VSX_BUILTIN_ST_ELEMREV_V2DF:
- return (BYTES_BIG_ENDIAN ? CODE_FOR_vsx_store_v2df
- : CODE_FOR_vsx_st_elemrev_v2df);
- case VSX_BUILTIN_ST_ELEMREV_V2DI:
- return (BYTES_BIG_ENDIAN ? CODE_FOR_vsx_store_v2di
- : CODE_FOR_vsx_st_elemrev_v2di);
- case VSX_BUILTIN_ST_ELEMREV_V4SF:
- return (BYTES_BIG_ENDIAN ? CODE_FOR_vsx_store_v4sf
- : CODE_FOR_vsx_st_elemrev_v4sf);
- case VSX_BUILTIN_ST_ELEMREV_V4SI:
- return (BYTES_BIG_ENDIAN ? CODE_FOR_vsx_store_v4si
- : CODE_FOR_vsx_st_elemrev_v4si);
- case VSX_BUILTIN_ST_ELEMREV_V8HI:
- return (BYTES_BIG_ENDIAN ? CODE_FOR_vsx_store_v8hi
- : CODE_FOR_vsx_st_elemrev_v8hi);
- case VSX_BUILTIN_ST_ELEMREV_V16QI:
- return (BYTES_BIG_ENDIAN ? CODE_FOR_vsx_store_v16qi
- : CODE_FOR_vsx_st_elemrev_v16qi);
- case VSX_BUILTIN_LD_ELEMREV_V2DF:
- return (BYTES_BIG_ENDIAN ? CODE_FOR_vsx_load_v2df
- : CODE_FOR_vsx_ld_elemrev_v2df);
- case VSX_BUILTIN_LD_ELEMREV_V1TI:
- return (BYTES_BIG_ENDIAN ? CODE_FOR_vsx_load_v1ti
- : CODE_FOR_vsx_ld_elemrev_v1ti);
- case VSX_BUILTIN_LD_ELEMREV_V2DI:
- return (BYTES_BIG_ENDIAN ? CODE_FOR_vsx_load_v2di
- : CODE_FOR_vsx_ld_elemrev_v2di);
- case VSX_BUILTIN_LD_ELEMREV_V4SF:
- return (BYTES_BIG_ENDIAN ? CODE_FOR_vsx_load_v4sf
- : CODE_FOR_vsx_ld_elemrev_v4sf);
- case VSX_BUILTIN_LD_ELEMREV_V4SI:
- return (BYTES_BIG_ENDIAN ? CODE_FOR_vsx_load_v4si
- : CODE_FOR_vsx_ld_elemrev_v4si);
- case VSX_BUILTIN_LD_ELEMREV_V8HI:
- return (BYTES_BIG_ENDIAN ? CODE_FOR_vsx_load_v8hi
- : CODE_FOR_vsx_ld_elemrev_v8hi);
- case VSX_BUILTIN_LD_ELEMREV_V16QI:
- return (BYTES_BIG_ENDIAN ? CODE_FOR_vsx_load_v16qi
- : CODE_FOR_vsx_ld_elemrev_v16qi);
- }
- gcc_unreachable ();
- return (insn_code) 0;
-}
-
-/* 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 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 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)
-{
- 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 (!TARGET_POWERPC64
- && (fcode == HTM_BUILTIN_TABORTDC
- || fcode == HTM_BUILTIN_TABORTDCI))
- {
- 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;
- }
-
- /* 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 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)
{
@@ -11048,156 +10785,6 @@ htm_expand_builtin (tree exp, rtx target, bool * expandedp)
return NULL_RTX;
}
-/* Expand the HTM builtin in EXP and store the result in TARGET. */
-static rtx
-new_htm_expand_builtin (bifdata *bifaddr, rs6000_builtins fcode,
- tree exp, rtx target)
-{
- tree fndecl = TREE_OPERAND (CALL_EXPR_FN (exp), 0);
- bool nonvoid = TREE_TYPE (TREE_TYPE (fndecl)) != void_type_node;
-
- if (!TARGET_POWERPC64
- && (fcode == HTM_BUILTIN_TABORTDC
- || fcode == HTM_BUILTIN_TABORTDCI))
- {
- error ("builtin %qs is only valid in 64-bit mode", bifaddr->bifname);
- return const0_rtx;
- }
-
- rtx op[MAX_HTM_OPERANDS], pat;
- int nopnds = 0;
- tree arg;
- call_expr_arg_iterator iter;
- insn_code icode = bifaddr->icode;
- bool uses_spr = bif_is_htmspr (*bifaddr);
- rtx cr = NULL_RTX;
-
- if (uses_spr)
- icode = rs6000_htm_spr_icode (nonvoid);
- 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;
- }
-
- 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);
- break;
- case HTM_BUILTIN_TSUSPEND: /* Alias for: tsr. 0 */
- op[nopnds++] = GEN_INT (0);
- 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 (bif_is_htmcr (*bifaddr))
- {
- cr = gen_reg_rtx (CCmode);
- op[nopnds++] = cr;
- }
-
- 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 == 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;
-}
-
/* Expand the CPU builtin in FCODE and store the result in TARGET. */
static rtx
@@ -13628,40 +13215,6 @@ rs6000_gimple_fold_builtin (gimple_stmt_iterator *gsi)
return false;
}
-/* Expand ALTIVEC_BUILTIN_MASK_FOR_LOAD. */
-rtx
-rs6000_expand_ldst_mask (rtx target, rs6000_builtins fcode, 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;
- rtx op, addr, pat;
-
- gcc_assert (TARGET_ALTIVEC);
-
- gcc_assert (POINTER_TYPE_P (TREE_TYPE (arg0)));
- op = expand_expr (arg0, NULL_RTX, Pmode, EXPAND_NORMAL);
- addr = memory_address (mode, op);
- gcc_assert (fcode == ALTIVEC_BUILTIN_MASK_FOR_LOAD);
- /* 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;
-}
-
/* 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).
@@ -13673,11 +13226,10 @@ 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);
- /* #### This needs to be rs6000_gen_builtins now. Can't make this
- whole until the full set of builtins has been added, and there
- is no overlap between the two enumerations, so we can run the
- two in parallel. */
enum rs6000_builtins fcode
= (enum rs6000_builtins) DECL_MD_FUNCTION_CODE (fndecl);
size_t uns_fcode = (size_t)fcode;
@@ -13685,18 +13237,9 @@ rs6000_expand_builtin (tree exp, rtx target, rtx subtarget ATTRIBUTE_UNUSED,
size_t i;
rtx ret;
bool success;
- HOST_WIDE_INT mask = (new_builtins_are_live
- ? 0
- : rs6000_builtin_info[uns_fcode].mask);
- /*
- bif_enable enable = (new_builtins_are_live
- ? rs6000_builtin_info_x[uns_fcode].enable
- : (bif_enable) 0);
- */
+ HOST_WIDE_INT mask = rs6000_builtin_info[uns_fcode].mask;
bool func_valid_p = ((rs6000_builtin_mask & mask) == mask);
- enum insn_code icode = (new_builtins_are_live
- ? rs6000_builtin_info_x[uns_fcode].icode
- : rs6000_builtin_info[uns_fcode].icode);
+ 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
@@ -13743,7 +13286,7 @@ rs6000_expand_builtin (tree exp, rtx target, rtx subtarget ATTRIBUTE_UNUSED,
break;
}
- if (!new_builtins_are_live && TARGET_DEBUG_BUILTIN)
+ if (TARGET_DEBUG_BUILTIN)
{
const char *name1 = rs6000_builtin_info[uns_fcode].name;
const char *name2 = (icode != CODE_FOR_nothing)
@@ -13781,496 +13324,1112 @@ rs6000_expand_builtin (tree exp, rtx target, rtx subtarget ATTRIBUTE_UNUSED,
return expand_call (exp, target, ignore);
}
- if (new_builtins_are_live)
+ switch (fcode)
{
- bifdata *bifaddr = &rs6000_builtin_info_x[uns_fcode];
+ case RS6000_BUILTIN_RECIP:
+ return rs6000_expand_binop_builtin (CODE_FOR_recipdf3, exp, target);
- /* In case of "#pragma target" changes, we initialize all builtins
- but check for actual availability during expand time. */
- switch (bifaddr->enable)
- {
- default:
- gcc_unreachable ();
- case ENB_ALWAYS:
- break;
- case ENB_P5:
- if (!TARGET_POPCNTB)
- return const0_rtx;
- break;
- case ENB_P6:
- if (!TARGET_CMPB)
- return const0_rtx;
- break;
- case ENB_ALTIVEC:
- if (!TARGET_ALTIVEC)
- return const0_rtx;
- break;
- case ENB_CELL:
- if (!TARGET_ALTIVEC || rs6000_cpu != PROCESSOR_CELL)
- return const0_rtx;
- break;
- case ENB_VSX:
- if (!TARGET_VSX)
- return const0_rtx;
- break;
- case ENB_P7:
- if (!TARGET_POPCNTD)
- return const0_rtx;
- break;
- case ENB_P7_64:
- if (!TARGET_POPCNTD || !TARGET_POWERPC64)
- return const0_rtx;
- break;
- case ENB_P8:
- if (!TARGET_DIRECT_MOVE)
- return const0_rtx;
- break;
- case ENB_P8V:
- if (!TARGET_P8_VECTOR)
- return const0_rtx;
- break;
- case ENB_P9:
- if (!TARGET_MODULO)
- return const0_rtx;
- break;
- case ENB_P9_64:
- if (!TARGET_MODULO || !TARGET_POWERPC64)
- return const0_rtx;
- break;
- case ENB_P9V:
- if (!TARGET_P9_VECTOR)
- return const0_rtx;
- break;
- case ENB_IEEE128_HW:
- if (!TARGET_FLOAT128_HW)
- return const0_rtx;
- break;
- case ENB_DFP:
- if (!TARGET_DFP)
- return const0_rtx;
- break;
- case ENB_CRYPTO:
- if (!TARGET_CRYPTO)
- return const0_rtx;
- break;
- case ENB_HTM:
- if (!TARGET_HTM)
- return const0_rtx;
- break;
- case ENB_P10:
- if (!TARGET_POWER10)
- return const0_rtx;
- break;
- case ENB_MMA:
- if (!TARGET_MMA)
- return const0_rtx;
- break;
- };
+ case RS6000_BUILTIN_RECIPF:
+ return rs6000_expand_binop_builtin (CODE_FOR_recipsf3, exp, target);
- if (bif_is_nosoft (*bifaddr)
- && rs6000_isa_flags & OPTION_MASK_SOFT_FLOAT)
- {
- error ("%<%s%> not supported with %<-msoft-float%>",
- bifaddr->bifname);
- return const0_rtx;
- }
+ case RS6000_BUILTIN_RSQRTF:
+ return rs6000_expand_unop_builtin (CODE_FOR_rsqrtsf2, exp, target);
- if (bif_is_no32bit (*bifaddr) && TARGET_32BIT)
- fatal_error (input_location,
- "%<%s%> is not supported in 32-bit mode",
- bifaddr->bifname);
+ 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);
- if (bif_is_cpu (*bifaddr))
- return cpu_expand_builtin (fcode, exp, target);
+ case RS6000_BUILTIN_MTFSB0:
+ return rs6000_expand_mtfsb_builtin (CODE_FOR_rs6000_mtfsb0, exp);
- if (bif_is_init (*bifaddr))
- return altivec_expand_vec_init_builtin (TREE_TYPE (exp), exp, target);
+ 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;
+ }
- if (bif_is_set (*bifaddr))
- return altivec_expand_vec_set_builtin (exp);
+ 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;
- if (bif_is_extract (*bifaddr))
- return altivec_expand_vec_ext_builtin (exp, target);
+ gcc_assert (TARGET_ALTIVEC);
- if (bif_is_predicate (*bifaddr))
- return altivec_expand_predicate_builtin (icode, exp, target);
+ 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 (bif_is_htm (*bifaddr))
- return new_htm_expand_builtin (bifaddr, fcode, exp, target);
+ if (target == 0
+ || GET_MODE (target) != tmode
+ || ! (*insn_data[icode2].operand[0].predicate) (target, tmode))
+ target = gen_reg_rtx (tmode);
- rtx pat;
- const int MAX_BUILTIN_ARGS = 5;
- tree arg[MAX_BUILTIN_ARGS];
- rtx op[MAX_BUILTIN_ARGS];
- machine_mode mode[MAX_BUILTIN_ARGS + 1];
+ pat = GEN_FCN (icode2) (target, op);
+ if (!pat)
+ return 0;
+ emit_insn (pat);
- int nargs = bifaddr->nargs;
- gcc_assert (nargs <= MAX_BUILTIN_ARGS);
+ return target;
+ }
- mode[0] = insn_data[icode].operand[0].mode;
- for (int i = 0; i < nargs; i++)
+ case ALTIVEC_BUILTIN_VCFUX:
+ case ALTIVEC_BUILTIN_VCFSX:
+ case ALTIVEC_BUILTIN_VCTUXS:
+ case ALTIVEC_BUILTIN_VCTSXS:
+ /* #### Replace this nonsense with a separate built-in for the
+ vectorizer to use, which I believe is the only way we get
+ into this situation. */
+ /* 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)
{
- arg[i] = CALL_EXPR_ARG (exp, i);
- if (arg[i] == error_mark_node)
- return const0_rtx;
- op[i] = expand_normal (arg[i]);
- mode[i+1] = insn_data[icode].operand[i+1].mode;
+ exp = build_call_nary (TREE_TYPE (exp), CALL_EXPR_FN (exp),
+ 2, CALL_EXPR_ARG (exp, 0),
+ integer_zero_node);
}
+ break;
- /* Check for restricted constant arguments. */
- for (int i = 0; i < 2; i++)
- {
- switch (bifaddr->restr[i])
- {
- default:
- case RES_NONE:
- break;
- case RES_BITS:
- {
- size_t mask = (1 << bifaddr->restr_val1[i]) - 1;
- 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)
- {
- 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;
- }
- }
- }
-
- if (bif_is_ldstmask (*bifaddr))
- return rs6000_expand_ldst_mask (target, fcode, arg[0]);
-
- if (bif_is_stvec (*bifaddr))
- {
- if (bif_is_reve (*bifaddr))
- icode = elemrev_icode (fcode);
- return stv_expand_builtin (icode, op, mode[0], mode[1]);
- }
-
- if (bif_is_ldvec (*bifaddr))
- {
- if (bif_is_reve (*bifaddr))
- icode = elemrev_icode (fcode);
- return ldv_expand_builtin (target, icode, op, mode[0]);
- }
-
- if (bif_is_mma (*bifaddr))
- return new_mma_expand_builtin (exp, target, fcode, icode);
-
- if (fcode == MISC_BUILTIN_PACK_IF
- && TARGET_LONG_DOUBLE_128 && !TARGET_IEEEQUAD)
+ /* 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;
}
- else if (fcode == MISC_BUILTIN_UNPACK_IF
- && TARGET_LONG_DOUBLE_128 && !TARGET_IEEEQUAD)
+ 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;
- if (target == 0
- || GET_MODE (target) != mode[0]
- || !(*insn_data[icode].operand[0].predicate) (target, mode[0]))
- target = gen_reg_rtx (mode[0]);
-
- for (int i = 0; i < nargs; i++)
- if (! (*insn_data[icode].operand[i+1].predicate) (op[i], mode[i+1]))
- op[i] = copy_to_mode_reg (mode[i+1], op[i]);
-
- switch (nargs)
- {
- default:
- gcc_assert (MAX_BUILTIN_ARGS == 5);
- gcc_unreachable ();
- case 0:
- pat = GEN_FCN (icode) (target);
- break;
- case 1:
- pat = GEN_FCN (icode) (target, op[0]);
- break;
- case 2:
- pat = GEN_FCN (icode) (target, op[0], op[1]);
- break;
- case 3:
- pat = GEN_FCN (icode) (target, op[0], op[1], op[2]);
- break;
- case 4:
- pat = GEN_FCN (icode) (target, op[0], op[1], op[2], op[3]);
- break;
- case 5:
- pat = GEN_FCN (icode) (target, op[0], op[1], op[2], op[3], op[4]);
- break;
- }
+ default:
+ break;
+ }
- if (!pat)
- return 0;
- emit_insn (pat);
+ if (TARGET_MMA)
+ {
+ ret = mma_expand_builtin (exp, target, &success);
- return target;
+ if (success)
+ return ret;
}
- else
+ if (TARGET_ALTIVEC)
{
- switch (fcode)
- {
- case RS6000_BUILTIN_RECIP:
- return rs6000_expand_binop_builtin (CODE_FOR_recipdf3, exp, target);
+ ret = altivec_expand_builtin (exp, target, &success);
- 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);
+ if (success)
+ return ret;
+ }
+ if (TARGET_HTM)
+ {
+ ret = htm_expand_builtin (exp, target, &success);
- case RS6000_BUILTIN_RSQRT:
- return rs6000_expand_unop_builtin (CODE_FOR_rsqrtdf2, exp, target);
+ if (success)
+ return ret;
+ }
- case POWER7_BUILTIN_BPERMD:
- return rs6000_expand_binop_builtin (((TARGET_64BIT)
- ? CODE_FOR_bpermd_di
- : CODE_FOR_bpermd_si),
- exp, target);
+ unsigned attr = (rs6000_builtin_info[uns_fcode].attr
+ & RS6000_BTC_TYPE_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);
- case RS6000_BUILTIN_GET_TB:
- return rs6000_expand_zeroop_builtin (CODE_FOR_rs6000_get_timebase,
- target);
+ /* 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);
- case RS6000_BUILTIN_MFTB:
- return rs6000_expand_zeroop_builtin (((TARGET_64BIT)
- ? CODE_FOR_rs6000_mftb_di
- : CODE_FOR_rs6000_mftb_si),
- 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);
- case RS6000_BUILTIN_MFFS:
- return rs6000_expand_zeroop_builtin (CODE_FOR_rs6000_mffs, 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);
- case RS6000_BUILTIN_MTFSB0:
- return rs6000_expand_mtfsb_builtin (CODE_FOR_rs6000_mtfsb0, exp);
+ /* 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);
- case RS6000_BUILTIN_MTFSB1:
- return rs6000_expand_mtfsb_builtin (CODE_FOR_rs6000_mtfsb1, exp);
+ /* 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);
- case RS6000_BUILTIN_SET_FPSCR_RN:
- return rs6000_expand_set_fpscr_rn_builtin
- (CODE_FOR_rs6000_set_fpscr_rn, exp);
+ gcc_unreachable ();
+}
- case RS6000_BUILTIN_SET_FPSCR_DRN:
- return
- rs6000_expand_set_fpscr_drn_builtin (CODE_FOR_rs6000_set_fpscr_drn,
- exp);
+/* 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;
+ rtx op, addr, pat;
- case RS6000_BUILTIN_MFFSL:
- return rs6000_expand_zeroop_builtin (CODE_FOR_rs6000_mffsl, target);
+ gcc_assert (TARGET_ALTIVEC);
- case RS6000_BUILTIN_MTFSF:
- return rs6000_expand_mtfsf_builtin (CODE_FOR_rs6000_mtfsf, exp);
+ gcc_assert (POINTER_TYPE_P (TREE_TYPE (arg0)));
+ op = expand_expr (arg0, 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);
- case RS6000_BUILTIN_CPU_INIT:
- case RS6000_BUILTIN_CPU_IS:
- case RS6000_BUILTIN_CPU_SUPPORTS:
- return cpu_expand_builtin (fcode, exp, target);
+ if (target == 0
+ || GET_MODE (target) != tmode
+ || ! (*insn_data[icode2].operand[0].predicate) (target, tmode))
+ target = gen_reg_rtx (tmode);
- case MISC_BUILTIN_SPEC_BARRIER:
- {
- emit_insn (gen_speculation_barrier ());
- return NULL_RTX;
- }
+ pat = GEN_FCN (icode2) (target, op);
+ if (!pat)
+ return 0;
+ emit_insn (pat);
- 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);
+ return target;
+}
- pat = GEN_FCN (icode2) (target, op);
- if (!pat)
- return 0;
- emit_insn (pat);
+/* Expand the CPU builtin in FCODE and store the result in TARGET. */
- return 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;
- case ALTIVEC_BUILTIN_VCFUX:
- case ALTIVEC_BUILTIN_VCFSX:
- case ALTIVEC_BUILTIN_VCTUXS:
- case ALTIVEC_BUILTIN_VCTSXS:
- /* #### Replace this nonsense with a separate built-in for the
- vectorizer to use, which I believe is the only way we get
- into this situation. */
- /* 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;
+ if (target == 0 || GET_MODE (target) != SImode)
+ target = gen_reg_rtx (SImode);
- /* 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;
+#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);
- 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;
+ 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;
+ }
- default:
- break;
+ 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;
}
- if (TARGET_MMA)
+ 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_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)
{
- ret = mma_expand_builtin (exp, target, &success);
-
- if (success)
- return ret;
+ /* 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;
}
- 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_TYPE_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);
+ 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)));
+ }
+ 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;
+}
+static insn_code
+elemrev_icode (rs6000_gen_builtins fcode)
+{
+ switch (fcode)
+ {
+ default:
gcc_unreachable ();
+ 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);
}
+ gcc_unreachable ();
+ return (insn_code) 0;
+}
+
+static rtx
+ldv_expand_builtin (rtx target, insn_code icode, rtx *op, machine_mode tmode)
+{
+ rtx pat, addr;
+ bool blk = (icode == CODE_FOR_altivec_lvlx
+ || icode == CODE_FOR_altivec_lvlxl
+ || icode == CODE_FOR_altivec_lvrx
+ || icode == CODE_FOR_altivec_lvrxl);
+ op[1] = copy_to_mode_reg (Pmode, op[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)
+ {
+ 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]);
+ }
+ 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
+ {
+ 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]));
+ }
+
+ pat = GEN_FCN (icode) (target, addr);
+ if (! pat)
+ return 0;
+ emit_insn (pat);
+ }
+
+ return target;
+}
+
+static rtx
+stv_expand_builtin (insn_code icode, rtx *op,
+ machine_mode tmode, machine_mode smode)
+{
+ rtx pat, addr, rawaddr;
+ 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. */
+ 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 (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]);
+ }
+
+ 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 (! (*insn_data[icode].operand[1].predicate) (op[0], smode))
+ op[0] = copy_to_mode_reg (smode, op[0]);
+
+ 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]));
+ }
+
+ pat = GEN_FCN (icode) (addr, op[0]);
+ if (pat)
+ emit_insn (pat);
+ }
+
+ return NULL_RTX;
+}
+
+/* Expand the MMA built-in in EXP. */
+static rtx
+new_mma_expand_builtin (tree exp, rtx target, insn_code icode)
+{
+ tree fndecl = TREE_OPERAND (CALL_EXPR_FN (exp), 0);
+ tree arg;
+ call_expr_arg_iterator iter;
+ const struct insn_operand_data *insn_op;
+ rtx op[MAX_MMA_OPERANDS];
+ unsigned nopnds = 0;
+ bool void_func = TREE_TYPE (TREE_TYPE (fndecl)) == void_type_node;
+ machine_mode tmode = VOIDmode;
+
+ if (TREE_TYPE (TREE_TYPE (fndecl)) != void_type_node)
+ {
+ 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;
+
+ 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;
+ }
+
+ 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;
+ case 5:
+ 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. */
+static rtx
+new_htm_expand_builtin (bifdata *bifaddr, rs6000_gen_builtins fcode,
+ tree exp, rtx target)
+{
+ tree fndecl = TREE_OPERAND (CALL_EXPR_FN (exp), 0);
+ bool nonvoid = TREE_TYPE (TREE_TYPE (fndecl)) != void_type_node;
+
+ 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;
+ }
+
+ rtx op[MAX_HTM_OPERANDS], pat;
+ int nopnds = 0;
+ tree arg;
+ call_expr_arg_iterator iter;
+ insn_code icode = bifaddr->icode;
+ bool uses_spr = bif_is_htmspr (*bifaddr);
+ rtx cr = NULL_RTX;
+
+ if (uses_spr)
+ icode = rs6000_htm_spr_icode (nonvoid);
+ 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;
+ }
+
+ 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 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;
+ }
+
+ /* 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, new_htm_spr_num (fcode));
+ }
+ /* If this builtin accesses a CR, then pass in a scratch
+ CR as the last operand. */
+ else if (bif_is_htmcr (*bifaddr))
+ {
+ cr = gen_reg_rtx (CCmode);
+ op[nopnds++] = cr;
+ }
+
+ 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 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;
+}
+
+/* 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 ATTRIBUTE_UNUSED,
+ machine_mode ignore_mode ATTRIBUTE_UNUSED,
+ int ignore ATTRIBUTE_UNUSED)
+{
+ 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;
+
+ /* 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;
+ }
+
+ bifdata *bifaddr = &rs6000_builtin_info_x[uns_fcode];
+
+ /* In case of "#pragma target" changes, we initialize all builtins
+ but check for actual availability during expand time. For
+ invalid builtins, generate a normal call. */
+ switch (bifaddr->enable)
+ {
+ default:
+ gcc_unreachable ();
+ case ENB_ALWAYS:
+ break;
+ case ENB_P5:
+ if (!TARGET_POPCNTB)
+ {
+ error ("%qs requires at least %qs\n",
+ bifaddr->bifname, "-mcpu=power5");
+ return expand_call (exp, target, ignore);
+ }
+ break;
+ case ENB_P6:
+ if (!TARGET_CMPB)
+ return const0_rtx;
+ break;
+ case ENB_ALTIVEC:
+ if (!TARGET_ALTIVEC)
+ return const0_rtx;
+ break;
+ case ENB_CELL:
+ if (!TARGET_ALTIVEC || rs6000_cpu != PROCESSOR_CELL)
+ return const0_rtx;
+ break;
+ case ENB_VSX:
+ if (!TARGET_VSX)
+ return const0_rtx;
+ break;
+ case ENB_P7:
+ if (!TARGET_POPCNTD)
+ return const0_rtx;
+ break;
+ case ENB_P7_64:
+ if (!TARGET_POPCNTD || !TARGET_POWERPC64)
+ return const0_rtx;
+ break;
+ case ENB_P8:
+ if (!TARGET_DIRECT_MOVE)
+ return const0_rtx;
+ break;
+ case ENB_P8V:
+ if (!TARGET_P8_VECTOR)
+ return const0_rtx;
+ break;
+ case ENB_P9:
+ if (!TARGET_MODULO)
+ return const0_rtx;
+ break;
+ case ENB_P9_64:
+ if (!TARGET_MODULO || !TARGET_POWERPC64)
+ return const0_rtx;
+ break;
+ case ENB_P9V:
+ if (!TARGET_P9_VECTOR)
+ return const0_rtx;
+ break;
+ case ENB_IEEE128_HW:
+ if (!TARGET_FLOAT128_HW)
+ return const0_rtx;
+ break;
+ case ENB_DFP:
+ if (!TARGET_DFP)
+ return const0_rtx;
+ break;
+ case ENB_CRYPTO:
+ if (!TARGET_CRYPTO)
+ return const0_rtx;
+ break;
+ case ENB_HTM:
+ if (!TARGET_HTM)
+ return const0_rtx;
+ break;
+ case ENB_P10:
+ if (!TARGET_POWER10)
+ return const0_rtx;
+ break;
+ case ENB_MMA:
+ if (!TARGET_MMA)
+ return const0_rtx;
+ break;
+ };
+
+ if (bif_is_nosoft (*bifaddr)
+ && rs6000_isa_flags & OPTION_MASK_SOFT_FLOAT)
+ {
+ error ("%<%s%> not supported with %<-msoft-float%>",
+ bifaddr->bifname);
+ return const0_rtx;
+ }
+
+ if (bif_is_no32bit (*bifaddr) && TARGET_32BIT)
+ fatal_error (input_location,
+ "%<%s%> is not supported in 32-bit mode",
+ bifaddr->bifname);
+
+ if (bif_is_cpu (*bifaddr))
+ return new_cpu_expand_builtin (fcode, exp, target);
+
+ if (bif_is_init (*bifaddr))
+ return altivec_expand_vec_init_builtin (TREE_TYPE (exp), exp, target);
+
+ if (bif_is_set (*bifaddr))
+ return altivec_expand_vec_set_builtin (exp);
+
+ if (bif_is_extract (*bifaddr))
+ return altivec_expand_vec_ext_builtin (exp, target);
+
+ if (bif_is_predicate (*bifaddr))
+ return altivec_expand_predicate_builtin (icode, exp, target);
+
+ if (bif_is_htm (*bifaddr))
+ return new_htm_expand_builtin (bifaddr, fcode, exp, target);
+
+ rtx pat;
+ const int MAX_BUILTIN_ARGS = 5;
+ tree arg[MAX_BUILTIN_ARGS];
+ rtx op[MAX_BUILTIN_ARGS];
+ machine_mode mode[MAX_BUILTIN_ARGS + 1];
+
+ int nargs = bifaddr->nargs;
+ gcc_assert (nargs <= MAX_BUILTIN_ARGS);
+
+ mode[0] = insn_data[icode].operand[0].mode;
+ for (int i = 0; i < nargs; i++)
+ {
+ arg[i] = CALL_EXPR_ARG (exp, i);
+ if (arg[i] == error_mark_node)
+ return const0_rtx;
+ op[i] = expand_normal (arg[i]);
+ mode[i+1] = insn_data[icode].operand[i+1].mode;
+ }
+
+ /* Check for restricted constant arguments. */
+ for (int i = 0; i < 2; i++)
+ {
+ switch (bifaddr->restr[i])
+ {
+ default:
+ case RES_NONE:
+ break;
+ case RES_BITS:
+ {
+ size_t mask = (1 << bifaddr->restr_val1[i]) - 1;
+ 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)
+ {
+ 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;
+ }
+ }
+ }
+
+ if (bif_is_ldstmask (*bifaddr))
+ return rs6000_expand_ldst_mask (target, arg[0]);
+
+ if (bif_is_stvec (*bifaddr))
+ {
+ if (bif_is_reve (*bifaddr))
+ icode = elemrev_icode (fcode);
+ return stv_expand_builtin (icode, op, mode[0], mode[1]);
+ }
+
+ if (bif_is_ldvec (*bifaddr))
+ {
+ if (bif_is_reve (*bifaddr))
+ icode = elemrev_icode (fcode);
+ return ldv_expand_builtin (target, icode, op, mode[0]);
+ }
+
+ if (bif_is_mma (*bifaddr))
+ return new_mma_expand_builtin (exp, target, icode);
+
+ 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;
+ }
+
+ if (target == 0
+ || GET_MODE (target) != mode[0]
+ || !(*insn_data[icode].operand[0].predicate) (target, mode[0]))
+ target = gen_reg_rtx (mode[0]);
+
+ for (int i = 0; i < nargs; i++)
+ if (! (*insn_data[icode].operand[i+1].predicate) (op[i], mode[i+1]))
+ op[i] = copy_to_mode_reg (mode[i+1], op[i]);
+
+ switch (nargs)
+ {
+ default:
+ gcc_assert (MAX_BUILTIN_ARGS == 5);
+ gcc_unreachable ();
+ case 0:
+ pat = GEN_FCN (icode) (target);
+ break;
+ case 1:
+ pat = GEN_FCN (icode) (target, op[0]);
+ break;
+ case 2:
+ pat = GEN_FCN (icode) (target, op[0], op[1]);
+ break;
+ case 3:
+ pat = GEN_FCN (icode) (target, op[0], op[1], op[2]);
+ break;
+ case 4:
+ pat = GEN_FCN (icode) (target, op[0], op[1], op[2], op[3]);
+ break;
+ case 5:
+ pat = GEN_FCN (icode) (target, op[0], op[1], op[2], op[3], op[4]);
+ break;
+ }
+
+ if (!pat)
+ return 0;
+ emit_insn (pat);
+
+ return target;
}
/* Create a builtin vector type with a name. Taking care not to give
^ permalink raw reply [flat|nested] 4+ messages in thread
* [gcc(refs/users/wschmidt/heads/builtins4)] rs6000: Resolve the fcode problems in rs6000_expand_builtin
@ 2020-11-24 16:45 William Schmidt
0 siblings, 0 replies; 4+ messages in thread
From: William Schmidt @ 2020-11-24 16:45 UTC (permalink / raw)
To: gcc-cvs
https://gcc.gnu.org/g:78da3e997eed7ffaeece405172484fb8a2bd6aa4
commit 78da3e997eed7ffaeece405172484fb8a2bd6aa4
Author: Bill Schmidt <wschmidt@linux.ibm.com>
Date: Mon Nov 16 15:51:48 2020 -0500
rs6000: Resolve the fcode problems in rs6000_expand_builtin
2020-11-16 Bill Schmidt <wschmidt@linux.ibm.com>
* config/rs6000/rs6000-call.c (rs6000_expand_new_builtin): New
forward decl.
(ldv_expand_builtin): Move.
(new_mma_expand_builtin): Move.
(stv_expand_builtin): Move.
(elemrev_icode): Move and rewrite.
(htm_spr_num): Move and rewrite.
(new_htm_expand_builtin): Move.
(rs6000_expand_ldst_mask): Move and rewrite.
(rs6000_expand_builtin): Call rs6000_expand_new_builtin; remove
logic for new_builtins_are_live.
(rs6000_expand_new_builtin): New.
Diff:
---
gcc/config/rs6000/rs6000-call.c | 2201 +++++++++++++++++++++------------------
1 file changed, 1180 insertions(+), 1021 deletions(-)
diff --git a/gcc/config/rs6000/rs6000-call.c b/gcc/config/rs6000/rs6000-call.c
index ff8625612f8..511efd5bfdc 100644
--- a/gcc/config/rs6000/rs6000-call.c
+++ b/gcc/config/rs6000/rs6000-call.c
@@ -184,7 +184,7 @@ static tree builtin_function_type (machine_mode, machine_mode,
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);
/* Hash table to keep track of the argument types for builtin functions. */
@@ -10262,60 +10262,6 @@ altivec_expand_lv_builtin (enum insn_code icode, tree exp, rtx target, bool blk)
return target;
}
-static rtx
-ldv_expand_builtin (rtx target, insn_code icode, rtx *op, machine_mode tmode)
-{
- rtx pat, addr;
- bool blk = (icode == CODE_FOR_altivec_lvlx
- || icode == CODE_FOR_altivec_lvlxl
- || icode == CODE_FOR_altivec_lvrx
- || icode == CODE_FOR_altivec_lvrxl);
- op[1] = copy_to_mode_reg (Pmode, op[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)
- {
- 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]);
- }
- 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
- {
- 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]));
- }
-
- pat = GEN_FCN (icode) (target, addr);
- if (! pat)
- return 0;
- emit_insn (pat);
- }
-
- return target;
-}
-
static rtx
altivec_expand_stxvl_builtin (enum insn_code icode, tree exp)
{
@@ -10570,357 +10516,148 @@ mma_expand_builtin (tree exp, rtx target, bool *expandedp)
return target;
}
-/* Expand the MMA built-in in EXP. */
+/* 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 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 the HTM builtin in EXP and store the result in TARGET.
+ Store true in *EXPANDEDP if we found a builtin to expand. */
static rtx
-new_mma_expand_builtin (tree exp, rtx target, rs6000_builtins fcode,
- insn_code icode)
+htm_expand_builtin (tree exp, rtx target, bool * expandedp)
{
tree fndecl = TREE_OPERAND (CALL_EXPR_FN (exp), 0);
- tree arg;
- call_expr_arg_iterator iter;
- const struct insn_operand_data *insn_op;
- rtx op[MAX_MMA_OPERANDS];
- unsigned nopnds = 0;
- /* ### This attr/void_func business needs replacing. */
- unsigned attr = rs6000_builtin_info[fcode].attr;
- bool void_func = (attr & RS6000_BTC_VOID);
- machine_mode tmode = VOIDmode;
+ 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;
- if (TREE_TYPE (TREE_TYPE (fndecl)) != void_type_node)
+ *expandedp = true;
+
+ if (!TARGET_POWERPC64
+ && (fcode == HTM_BUILTIN_TABORTDC
+ || fcode == HTM_BUILTIN_TABORTDCI))
{
- 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;
+ 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;
}
- else
- target = const0_rtx;
- FOR_EACH_CALL_EXPR_ARG (arg, iter, exp)
- {
- if (arg == error_mark_node)
- return const0_rtx;
+ /* 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;
- 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 (uses_spr)
+ icode = rs6000_htm_spr_icode (nonvoid);
+ insn_op = &insn_data[icode].operand[0];
- if (!(*insn_op->predicate) (opnd, insn_op->mode))
+ 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 (!strcmp (insn_op->constraint, "n"))
+ 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 (!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;
+ 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]);
}
- opnd = copy_to_mode_reg (insn_op->mode, opnd);
+
+ nopnds++;
}
- /* Some MMA instructions have INOUT accumulator operands, so force
- their target register to be the same as their input register. */
- /* ### The void_func test needs to happen some other way,
- probably with TREE_TYPE (TREE_TYPE (fndecl)) as earlier. */
- 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;
+ /* 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;
+ }
- 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:
- 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:
- 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;
-}
-
-static rtx
-stv_expand_builtin (insn_code icode, rtx *op,
- machine_mode tmode, machine_mode smode)
-{
- rtx pat, addr, rawaddr;
- 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. */
- 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 (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]);
- }
-
- 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 (! (*insn_data[icode].operand[1].predicate) (op[0], smode))
- op[0] = copy_to_mode_reg (smode, op[0]);
-
- 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]));
- }
-
- pat = GEN_FCN (icode) (addr, op[0]);
- if (pat)
- emit_insn (pat);
- }
-
- return NULL_RTX;
-}
-
-static insn_code
-elemrev_icode (rs6000_builtins fcode)
-{
- switch (fcode)
- {
- default:
- gcc_unreachable ();
- case VSX_BUILTIN_ST_ELEMREV_V1TI:
- return (BYTES_BIG_ENDIAN ? CODE_FOR_vsx_store_v1ti
- : CODE_FOR_vsx_st_elemrev_v1ti);
- case VSX_BUILTIN_ST_ELEMREV_V2DF:
- return (BYTES_BIG_ENDIAN ? CODE_FOR_vsx_store_v2df
- : CODE_FOR_vsx_st_elemrev_v2df);
- case VSX_BUILTIN_ST_ELEMREV_V2DI:
- return (BYTES_BIG_ENDIAN ? CODE_FOR_vsx_store_v2di
- : CODE_FOR_vsx_st_elemrev_v2di);
- case VSX_BUILTIN_ST_ELEMREV_V4SF:
- return (BYTES_BIG_ENDIAN ? CODE_FOR_vsx_store_v4sf
- : CODE_FOR_vsx_st_elemrev_v4sf);
- case VSX_BUILTIN_ST_ELEMREV_V4SI:
- return (BYTES_BIG_ENDIAN ? CODE_FOR_vsx_store_v4si
- : CODE_FOR_vsx_st_elemrev_v4si);
- case VSX_BUILTIN_ST_ELEMREV_V8HI:
- return (BYTES_BIG_ENDIAN ? CODE_FOR_vsx_store_v8hi
- : CODE_FOR_vsx_st_elemrev_v8hi);
- case VSX_BUILTIN_ST_ELEMREV_V16QI:
- return (BYTES_BIG_ENDIAN ? CODE_FOR_vsx_store_v16qi
- : CODE_FOR_vsx_st_elemrev_v16qi);
- case VSX_BUILTIN_LD_ELEMREV_V2DF:
- return (BYTES_BIG_ENDIAN ? CODE_FOR_vsx_load_v2df
- : CODE_FOR_vsx_ld_elemrev_v2df);
- case VSX_BUILTIN_LD_ELEMREV_V1TI:
- return (BYTES_BIG_ENDIAN ? CODE_FOR_vsx_load_v1ti
- : CODE_FOR_vsx_ld_elemrev_v1ti);
- case VSX_BUILTIN_LD_ELEMREV_V2DI:
- return (BYTES_BIG_ENDIAN ? CODE_FOR_vsx_load_v2di
- : CODE_FOR_vsx_ld_elemrev_v2di);
- case VSX_BUILTIN_LD_ELEMREV_V4SF:
- return (BYTES_BIG_ENDIAN ? CODE_FOR_vsx_load_v4sf
- : CODE_FOR_vsx_ld_elemrev_v4sf);
- case VSX_BUILTIN_LD_ELEMREV_V4SI:
- return (BYTES_BIG_ENDIAN ? CODE_FOR_vsx_load_v4si
- : CODE_FOR_vsx_ld_elemrev_v4si);
- case VSX_BUILTIN_LD_ELEMREV_V8HI:
- return (BYTES_BIG_ENDIAN ? CODE_FOR_vsx_load_v8hi
- : CODE_FOR_vsx_ld_elemrev_v8hi);
- case VSX_BUILTIN_LD_ELEMREV_V16QI:
- return (BYTES_BIG_ENDIAN ? CODE_FOR_vsx_load_v16qi
- : CODE_FOR_vsx_ld_elemrev_v16qi);
- }
- gcc_unreachable ();
- return (insn_code) 0;
-}
-
-/* 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 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 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)
-{
- 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 (!TARGET_POWERPC64
- && (fcode == HTM_BUILTIN_TABORTDC
- || fcode == HTM_BUILTIN_TABORTDCI))
- {
- 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;
- }
-
- /* 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 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)
{
@@ -11001,156 +10738,6 @@ htm_expand_builtin (tree exp, rtx target, bool * expandedp)
return NULL_RTX;
}
-/* Expand the HTM builtin in EXP and store the result in TARGET. */
-static rtx
-new_htm_expand_builtin (bifdata *bifaddr, rs6000_builtins fcode,
- tree exp, rtx target)
-{
- tree fndecl = TREE_OPERAND (CALL_EXPR_FN (exp), 0);
- bool nonvoid = TREE_TYPE (TREE_TYPE (fndecl)) != void_type_node;
-
- if (!TARGET_POWERPC64
- && (fcode == HTM_BUILTIN_TABORTDC
- || fcode == HTM_BUILTIN_TABORTDCI))
- {
- error ("builtin %qs is only valid in 64-bit mode", bifaddr->bifname);
- return const0_rtx;
- }
-
- rtx op[MAX_HTM_OPERANDS], pat;
- int nopnds = 0;
- tree arg;
- call_expr_arg_iterator iter;
- insn_code icode = bifaddr->icode;
- bool uses_spr = bif_is_htmspr (*bifaddr);
- rtx cr = NULL_RTX;
-
- if (uses_spr)
- icode = rs6000_htm_spr_icode (nonvoid);
- 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;
- }
-
- 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);
- break;
- case HTM_BUILTIN_TSUSPEND: /* Alias for: tsr. 0 */
- op[nopnds++] = GEN_INT (0);
- 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 (bif_is_htmcr (*bifaddr))
- {
- cr = gen_reg_rtx (CCmode);
- op[nopnds++] = cr;
- }
-
- 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 == 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;
-}
-
/* Expand the CPU builtin in FCODE and store the result in TARGET. */
static rtx
@@ -13581,40 +13168,6 @@ rs6000_gimple_fold_builtin (gimple_stmt_iterator *gsi)
return false;
}
-/* Expand ALTIVEC_BUILTIN_MASK_FOR_LOAD. */
-rtx
-rs6000_expand_ldst_mask (rtx target, rs6000_builtins fcode, 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;
- rtx op, addr, pat;
-
- gcc_assert (TARGET_ALTIVEC);
-
- gcc_assert (POINTER_TYPE_P (TREE_TYPE (arg0)));
- op = expand_expr (arg0, NULL_RTX, Pmode, EXPAND_NORMAL);
- addr = memory_address (mode, op);
- gcc_assert (fcode == ALTIVEC_BUILTIN_MASK_FOR_LOAD);
- /* 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;
-}
-
/* 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).
@@ -13626,11 +13179,10 @@ 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);
- /* #### This needs to be rs6000_gen_builtins now. Can't make this
- whole until the full set of builtins has been added, and there
- is no overlap between the two enumerations, so we can run the
- two in parallel. */
enum rs6000_builtins fcode
= (enum rs6000_builtins) DECL_MD_FUNCTION_CODE (fndecl);
size_t uns_fcode = (size_t)fcode;
@@ -13638,18 +13190,9 @@ rs6000_expand_builtin (tree exp, rtx target, rtx subtarget ATTRIBUTE_UNUSED,
size_t i;
rtx ret;
bool success;
- HOST_WIDE_INT mask = (new_builtins_are_live
- ? 0
- : rs6000_builtin_info[uns_fcode].mask);
- /*
- bif_enable enable = (new_builtins_are_live
- ? rs6000_builtin_info_x[uns_fcode].enable
- : (bif_enable) 0);
- */
+ HOST_WIDE_INT mask = rs6000_builtin_info[uns_fcode].mask;
bool func_valid_p = ((rs6000_builtin_mask & mask) == mask);
- enum insn_code icode = (new_builtins_are_live
- ? rs6000_builtin_info_x[uns_fcode].icode
- : rs6000_builtin_info[uns_fcode].icode);
+ 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
@@ -13696,7 +13239,7 @@ rs6000_expand_builtin (tree exp, rtx target, rtx subtarget ATTRIBUTE_UNUSED,
break;
}
- if (!new_builtins_are_live && TARGET_DEBUG_BUILTIN)
+ if (TARGET_DEBUG_BUILTIN)
{
const char *name1 = rs6000_builtin_info[uns_fcode].name;
const char *name2 = (icode != CODE_FOR_nothing)
@@ -13734,496 +13277,1112 @@ rs6000_expand_builtin (tree exp, rtx target, rtx subtarget ATTRIBUTE_UNUSED,
return expand_call (exp, target, ignore);
}
- if (new_builtins_are_live)
+ switch (fcode)
{
- bifdata *bifaddr = &rs6000_builtin_info_x[uns_fcode];
+ case RS6000_BUILTIN_RECIP:
+ return rs6000_expand_binop_builtin (CODE_FOR_recipdf3, exp, target);
- /* In case of "#pragma target" changes, we initialize all builtins
- but check for actual availability during expand time. */
- switch (bifaddr->enable)
- {
- default:
- gcc_unreachable ();
- case ENB_ALWAYS:
- break;
- case ENB_P5:
- if (!TARGET_POPCNTB)
- return const0_rtx;
- break;
- case ENB_P6:
- if (!TARGET_CMPB)
- return const0_rtx;
- break;
- case ENB_ALTIVEC:
- if (!TARGET_ALTIVEC)
- return const0_rtx;
- break;
- case ENB_CELL:
- if (!TARGET_ALTIVEC || rs6000_cpu != PROCESSOR_CELL)
- return const0_rtx;
- break;
- case ENB_VSX:
- if (!TARGET_VSX)
- return const0_rtx;
- break;
- case ENB_P7:
- if (!TARGET_POPCNTD)
- return const0_rtx;
- break;
- case ENB_P7_64:
- if (!TARGET_POPCNTD || !TARGET_POWERPC64)
- return const0_rtx;
- break;
- case ENB_P8:
- if (!TARGET_DIRECT_MOVE)
- return const0_rtx;
- break;
- case ENB_P8V:
- if (!TARGET_P8_VECTOR)
- return const0_rtx;
- break;
- case ENB_P9:
- if (!TARGET_MODULO)
- return const0_rtx;
- break;
- case ENB_P9_64:
- if (!TARGET_MODULO || !TARGET_POWERPC64)
- return const0_rtx;
- break;
- case ENB_P9V:
- if (!TARGET_P9_VECTOR)
- return const0_rtx;
- break;
- case ENB_IEEE128_HW:
- if (!TARGET_FLOAT128_HW)
- return const0_rtx;
- break;
- case ENB_DFP:
- if (!TARGET_DFP)
- return const0_rtx;
- break;
- case ENB_CRYPTO:
- if (!TARGET_CRYPTO)
- return const0_rtx;
- break;
- case ENB_HTM:
- if (!TARGET_HTM)
- return const0_rtx;
- break;
- case ENB_P10:
- if (!TARGET_POWER10)
- return const0_rtx;
- break;
- case ENB_MMA:
- if (!TARGET_MMA)
- return const0_rtx;
- break;
- };
+ case RS6000_BUILTIN_RECIPF:
+ return rs6000_expand_binop_builtin (CODE_FOR_recipsf3, exp, target);
- if (bif_is_nosoft (*bifaddr)
- && rs6000_isa_flags & OPTION_MASK_SOFT_FLOAT)
- {
- error ("%<%s%> not supported with %<-msoft-float%>",
- bifaddr->bifname);
- return const0_rtx;
- }
+ case RS6000_BUILTIN_RSQRTF:
+ return rs6000_expand_unop_builtin (CODE_FOR_rsqrtsf2, exp, target);
- if (bif_is_no32bit (*bifaddr) && TARGET_32BIT)
- fatal_error (input_location,
- "%<%s%> is not supported in 32-bit mode",
- bifaddr->bifname);
+ 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);
- if (bif_is_cpu (*bifaddr))
- return cpu_expand_builtin (fcode, exp, target);
+ case RS6000_BUILTIN_MTFSB0:
+ return rs6000_expand_mtfsb_builtin (CODE_FOR_rs6000_mtfsb0, exp);
- if (bif_is_init (*bifaddr))
- return altivec_expand_vec_init_builtin (TREE_TYPE (exp), exp, target);
+ 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;
+ }
- if (bif_is_set (*bifaddr))
- return altivec_expand_vec_set_builtin (exp);
+ 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;
- if (bif_is_extract (*bifaddr))
- return altivec_expand_vec_ext_builtin (exp, target);
+ gcc_assert (TARGET_ALTIVEC);
- if (bif_is_predicate (*bifaddr))
- return altivec_expand_predicate_builtin (icode, exp, target);
+ 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 (bif_is_htm (*bifaddr))
- return new_htm_expand_builtin (bifaddr, fcode, exp, target);
+ if (target == 0
+ || GET_MODE (target) != tmode
+ || ! (*insn_data[icode2].operand[0].predicate) (target, tmode))
+ target = gen_reg_rtx (tmode);
- rtx pat;
- const int MAX_BUILTIN_ARGS = 5;
- tree arg[MAX_BUILTIN_ARGS];
- rtx op[MAX_BUILTIN_ARGS];
- machine_mode mode[MAX_BUILTIN_ARGS + 1];
+ pat = GEN_FCN (icode2) (target, op);
+ if (!pat)
+ return 0;
+ emit_insn (pat);
- int nargs = bifaddr->nargs;
- gcc_assert (nargs <= MAX_BUILTIN_ARGS);
+ return target;
+ }
- mode[0] = insn_data[icode].operand[0].mode;
- for (int i = 0; i < nargs; i++)
+ case ALTIVEC_BUILTIN_VCFUX:
+ case ALTIVEC_BUILTIN_VCFSX:
+ case ALTIVEC_BUILTIN_VCTUXS:
+ case ALTIVEC_BUILTIN_VCTSXS:
+ /* #### Replace this nonsense with a separate built-in for the
+ vectorizer to use, which I believe is the only way we get
+ into this situation. */
+ /* 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)
{
- arg[i] = CALL_EXPR_ARG (exp, i);
- if (arg[i] == error_mark_node)
- return const0_rtx;
- op[i] = expand_normal (arg[i]);
- mode[i+1] = insn_data[icode].operand[i+1].mode;
+ exp = build_call_nary (TREE_TYPE (exp), CALL_EXPR_FN (exp),
+ 2, CALL_EXPR_ARG (exp, 0),
+ integer_zero_node);
}
+ break;
- /* Check for restricted constant arguments. */
- for (int i = 0; i < 2; i++)
- {
- switch (bifaddr->restr[i])
- {
- default:
- case RES_NONE:
- break;
- case RES_BITS:
- {
- size_t mask = (1 << bifaddr->restr_val1[i]) - 1;
- 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)
- {
- 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;
- }
- }
- }
-
- if (bif_is_ldstmask (*bifaddr))
- return rs6000_expand_ldst_mask (target, fcode, arg[0]);
-
- if (bif_is_stvec (*bifaddr))
- {
- if (bif_is_reve (*bifaddr))
- icode = elemrev_icode (fcode);
- return stv_expand_builtin (icode, op, mode[0], mode[1]);
- }
-
- if (bif_is_ldvec (*bifaddr))
- {
- if (bif_is_reve (*bifaddr))
- icode = elemrev_icode (fcode);
- return ldv_expand_builtin (target, icode, op, mode[0]);
- }
-
- if (bif_is_mma (*bifaddr))
- return new_mma_expand_builtin (exp, target, fcode, icode);
-
- if (fcode == MISC_BUILTIN_PACK_IF
- && TARGET_LONG_DOUBLE_128 && !TARGET_IEEEQUAD)
+ /* 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;
}
- else if (fcode == MISC_BUILTIN_UNPACK_IF
- && TARGET_LONG_DOUBLE_128 && !TARGET_IEEEQUAD)
+ 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;
- if (target == 0
- || GET_MODE (target) != mode[0]
- || !(*insn_data[icode].operand[0].predicate) (target, mode[0]))
- target = gen_reg_rtx (mode[0]);
-
- for (int i = 0; i < nargs; i++)
- if (! (*insn_data[icode].operand[i+1].predicate) (op[i], mode[i+1]))
- op[i] = copy_to_mode_reg (mode[i+1], op[i]);
-
- switch (nargs)
- {
- default:
- gcc_assert (MAX_BUILTIN_ARGS == 5);
- gcc_unreachable ();
- case 0:
- pat = GEN_FCN (icode) (target);
- break;
- case 1:
- pat = GEN_FCN (icode) (target, op[0]);
- break;
- case 2:
- pat = GEN_FCN (icode) (target, op[0], op[1]);
- break;
- case 3:
- pat = GEN_FCN (icode) (target, op[0], op[1], op[2]);
- break;
- case 4:
- pat = GEN_FCN (icode) (target, op[0], op[1], op[2], op[3]);
- break;
- case 5:
- pat = GEN_FCN (icode) (target, op[0], op[1], op[2], op[3], op[4]);
- break;
- }
+ default:
+ break;
+ }
- if (!pat)
- return 0;
- emit_insn (pat);
+ if (TARGET_MMA)
+ {
+ ret = mma_expand_builtin (exp, target, &success);
- return target;
+ if (success)
+ return ret;
}
- else
+ if (TARGET_ALTIVEC)
{
- switch (fcode)
- {
- case RS6000_BUILTIN_RECIP:
- return rs6000_expand_binop_builtin (CODE_FOR_recipdf3, exp, target);
+ ret = altivec_expand_builtin (exp, target, &success);
- 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);
+ if (success)
+ return ret;
+ }
+ if (TARGET_HTM)
+ {
+ ret = htm_expand_builtin (exp, target, &success);
- case RS6000_BUILTIN_RSQRT:
- return rs6000_expand_unop_builtin (CODE_FOR_rsqrtdf2, exp, target);
+ if (success)
+ return ret;
+ }
- case POWER7_BUILTIN_BPERMD:
- return rs6000_expand_binop_builtin (((TARGET_64BIT)
- ? CODE_FOR_bpermd_di
- : CODE_FOR_bpermd_si),
- exp, target);
+ unsigned attr = (rs6000_builtin_info[uns_fcode].attr
+ & RS6000_BTC_TYPE_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);
- case RS6000_BUILTIN_GET_TB:
- return rs6000_expand_zeroop_builtin (CODE_FOR_rs6000_get_timebase,
- target);
+ /* 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);
- case RS6000_BUILTIN_MFTB:
- return rs6000_expand_zeroop_builtin (((TARGET_64BIT)
- ? CODE_FOR_rs6000_mftb_di
- : CODE_FOR_rs6000_mftb_si),
- 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);
- case RS6000_BUILTIN_MFFS:
- return rs6000_expand_zeroop_builtin (CODE_FOR_rs6000_mffs, 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);
- case RS6000_BUILTIN_MTFSB0:
- return rs6000_expand_mtfsb_builtin (CODE_FOR_rs6000_mtfsb0, exp);
+ /* 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);
- case RS6000_BUILTIN_MTFSB1:
- return rs6000_expand_mtfsb_builtin (CODE_FOR_rs6000_mtfsb1, exp);
+ /* 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);
- case RS6000_BUILTIN_SET_FPSCR_RN:
- return rs6000_expand_set_fpscr_rn_builtin
- (CODE_FOR_rs6000_set_fpscr_rn, exp);
+ gcc_unreachable ();
+}
- case RS6000_BUILTIN_SET_FPSCR_DRN:
- return
- rs6000_expand_set_fpscr_drn_builtin (CODE_FOR_rs6000_set_fpscr_drn,
- exp);
+/* 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;
+ rtx op, addr, pat;
- case RS6000_BUILTIN_MFFSL:
- return rs6000_expand_zeroop_builtin (CODE_FOR_rs6000_mffsl, target);
+ gcc_assert (TARGET_ALTIVEC);
- case RS6000_BUILTIN_MTFSF:
- return rs6000_expand_mtfsf_builtin (CODE_FOR_rs6000_mtfsf, exp);
+ gcc_assert (POINTER_TYPE_P (TREE_TYPE (arg0)));
+ op = expand_expr (arg0, 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);
- case RS6000_BUILTIN_CPU_INIT:
- case RS6000_BUILTIN_CPU_IS:
- case RS6000_BUILTIN_CPU_SUPPORTS:
- return cpu_expand_builtin (fcode, exp, target);
+ if (target == 0
+ || GET_MODE (target) != tmode
+ || ! (*insn_data[icode2].operand[0].predicate) (target, tmode))
+ target = gen_reg_rtx (tmode);
- case MISC_BUILTIN_SPEC_BARRIER:
- {
- emit_insn (gen_speculation_barrier ());
- return NULL_RTX;
- }
+ pat = GEN_FCN (icode2) (target, op);
+ if (!pat)
+ return 0;
+ emit_insn (pat);
- 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);
+ return target;
+}
- pat = GEN_FCN (icode2) (target, op);
- if (!pat)
- return 0;
- emit_insn (pat);
+/* Expand the CPU builtin in FCODE and store the result in TARGET. */
- return 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;
- case ALTIVEC_BUILTIN_VCFUX:
- case ALTIVEC_BUILTIN_VCFSX:
- case ALTIVEC_BUILTIN_VCTUXS:
- case ALTIVEC_BUILTIN_VCTSXS:
- /* #### Replace this nonsense with a separate built-in for the
- vectorizer to use, which I believe is the only way we get
- into this situation. */
- /* 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;
+ if (target == 0 || GET_MODE (target) != SImode)
+ target = gen_reg_rtx (SImode);
- /* 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;
+#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);
- 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;
+ 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;
+ }
- default:
- break;
+ 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;
}
- if (TARGET_MMA)
+ 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_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)
{
- ret = mma_expand_builtin (exp, target, &success);
-
- if (success)
- return ret;
+ /* 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;
}
- 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_TYPE_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);
+ 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)));
+ }
+ 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;
+}
+static insn_code
+elemrev_icode (rs6000_gen_builtins fcode)
+{
+ switch (fcode)
+ {
+ default:
gcc_unreachable ();
+ 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);
}
+ gcc_unreachable ();
+ return (insn_code) 0;
+}
+
+static rtx
+ldv_expand_builtin (rtx target, insn_code icode, rtx *op, machine_mode tmode)
+{
+ rtx pat, addr;
+ bool blk = (icode == CODE_FOR_altivec_lvlx
+ || icode == CODE_FOR_altivec_lvlxl
+ || icode == CODE_FOR_altivec_lvrx
+ || icode == CODE_FOR_altivec_lvrxl);
+ op[1] = copy_to_mode_reg (Pmode, op[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)
+ {
+ 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]);
+ }
+ 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
+ {
+ 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]));
+ }
+
+ pat = GEN_FCN (icode) (target, addr);
+ if (! pat)
+ return 0;
+ emit_insn (pat);
+ }
+
+ return target;
+}
+
+static rtx
+stv_expand_builtin (insn_code icode, rtx *op,
+ machine_mode tmode, machine_mode smode)
+{
+ rtx pat, addr, rawaddr;
+ 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. */
+ 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 (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]);
+ }
+
+ 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 (! (*insn_data[icode].operand[1].predicate) (op[0], smode))
+ op[0] = copy_to_mode_reg (smode, op[0]);
+
+ 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]));
+ }
+
+ pat = GEN_FCN (icode) (addr, op[0]);
+ if (pat)
+ emit_insn (pat);
+ }
+
+ return NULL_RTX;
+}
+
+/* Expand the MMA built-in in EXP. */
+static rtx
+new_mma_expand_builtin (tree exp, rtx target, insn_code icode)
+{
+ tree fndecl = TREE_OPERAND (CALL_EXPR_FN (exp), 0);
+ tree arg;
+ call_expr_arg_iterator iter;
+ const struct insn_operand_data *insn_op;
+ rtx op[MAX_MMA_OPERANDS];
+ unsigned nopnds = 0;
+ bool void_func = TREE_TYPE (TREE_TYPE (fndecl)) == void_type_node;
+ machine_mode tmode = VOIDmode;
+
+ if (TREE_TYPE (TREE_TYPE (fndecl)) != void_type_node)
+ {
+ 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;
+
+ 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;
+ }
+
+ 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;
+ case 5:
+ 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. */
+static rtx
+new_htm_expand_builtin (bifdata *bifaddr, rs6000_gen_builtins fcode,
+ tree exp, rtx target)
+{
+ tree fndecl = TREE_OPERAND (CALL_EXPR_FN (exp), 0);
+ bool nonvoid = TREE_TYPE (TREE_TYPE (fndecl)) != void_type_node;
+
+ 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;
+ }
+
+ rtx op[MAX_HTM_OPERANDS], pat;
+ int nopnds = 0;
+ tree arg;
+ call_expr_arg_iterator iter;
+ insn_code icode = bifaddr->icode;
+ bool uses_spr = bif_is_htmspr (*bifaddr);
+ rtx cr = NULL_RTX;
+
+ if (uses_spr)
+ icode = rs6000_htm_spr_icode (nonvoid);
+ 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;
+ }
+
+ 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 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;
+ }
+
+ /* 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, new_htm_spr_num (fcode));
+ }
+ /* If this builtin accesses a CR, then pass in a scratch
+ CR as the last operand. */
+ else if (bif_is_htmcr (*bifaddr))
+ {
+ cr = gen_reg_rtx (CCmode);
+ op[nopnds++] = cr;
+ }
+
+ 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 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;
+}
+
+/* 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 ATTRIBUTE_UNUSED,
+ machine_mode ignore_mode ATTRIBUTE_UNUSED,
+ int ignore ATTRIBUTE_UNUSED)
+{
+ 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;
+
+ /* 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;
+ }
+
+ bifdata *bifaddr = &rs6000_builtin_info_x[uns_fcode];
+
+ /* In case of "#pragma target" changes, we initialize all builtins
+ but check for actual availability during expand time. For
+ invalid builtins, generate a normal call. */
+ switch (bifaddr->enable)
+ {
+ default:
+ gcc_unreachable ();
+ case ENB_ALWAYS:
+ break;
+ case ENB_P5:
+ if (!TARGET_POPCNTB)
+ {
+ error ("%qs requires at least %qs\n",
+ bifaddr->bifname, "-mcpu=power5");
+ return expand_call (exp, target, ignore);
+ }
+ break;
+ case ENB_P6:
+ if (!TARGET_CMPB)
+ return const0_rtx;
+ break;
+ case ENB_ALTIVEC:
+ if (!TARGET_ALTIVEC)
+ return const0_rtx;
+ break;
+ case ENB_CELL:
+ if (!TARGET_ALTIVEC || rs6000_cpu != PROCESSOR_CELL)
+ return const0_rtx;
+ break;
+ case ENB_VSX:
+ if (!TARGET_VSX)
+ return const0_rtx;
+ break;
+ case ENB_P7:
+ if (!TARGET_POPCNTD)
+ return const0_rtx;
+ break;
+ case ENB_P7_64:
+ if (!TARGET_POPCNTD || !TARGET_POWERPC64)
+ return const0_rtx;
+ break;
+ case ENB_P8:
+ if (!TARGET_DIRECT_MOVE)
+ return const0_rtx;
+ break;
+ case ENB_P8V:
+ if (!TARGET_P8_VECTOR)
+ return const0_rtx;
+ break;
+ case ENB_P9:
+ if (!TARGET_MODULO)
+ return const0_rtx;
+ break;
+ case ENB_P9_64:
+ if (!TARGET_MODULO || !TARGET_POWERPC64)
+ return const0_rtx;
+ break;
+ case ENB_P9V:
+ if (!TARGET_P9_VECTOR)
+ return const0_rtx;
+ break;
+ case ENB_IEEE128_HW:
+ if (!TARGET_FLOAT128_HW)
+ return const0_rtx;
+ break;
+ case ENB_DFP:
+ if (!TARGET_DFP)
+ return const0_rtx;
+ break;
+ case ENB_CRYPTO:
+ if (!TARGET_CRYPTO)
+ return const0_rtx;
+ break;
+ case ENB_HTM:
+ if (!TARGET_HTM)
+ return const0_rtx;
+ break;
+ case ENB_P10:
+ if (!TARGET_POWER10)
+ return const0_rtx;
+ break;
+ case ENB_MMA:
+ if (!TARGET_MMA)
+ return const0_rtx;
+ break;
+ };
+
+ if (bif_is_nosoft (*bifaddr)
+ && rs6000_isa_flags & OPTION_MASK_SOFT_FLOAT)
+ {
+ error ("%<%s%> not supported with %<-msoft-float%>",
+ bifaddr->bifname);
+ return const0_rtx;
+ }
+
+ if (bif_is_no32bit (*bifaddr) && TARGET_32BIT)
+ fatal_error (input_location,
+ "%<%s%> is not supported in 32-bit mode",
+ bifaddr->bifname);
+
+ if (bif_is_cpu (*bifaddr))
+ return new_cpu_expand_builtin (fcode, exp, target);
+
+ if (bif_is_init (*bifaddr))
+ return altivec_expand_vec_init_builtin (TREE_TYPE (exp), exp, target);
+
+ if (bif_is_set (*bifaddr))
+ return altivec_expand_vec_set_builtin (exp);
+
+ if (bif_is_extract (*bifaddr))
+ return altivec_expand_vec_ext_builtin (exp, target);
+
+ if (bif_is_predicate (*bifaddr))
+ return altivec_expand_predicate_builtin (icode, exp, target);
+
+ if (bif_is_htm (*bifaddr))
+ return new_htm_expand_builtin (bifaddr, fcode, exp, target);
+
+ rtx pat;
+ const int MAX_BUILTIN_ARGS = 5;
+ tree arg[MAX_BUILTIN_ARGS];
+ rtx op[MAX_BUILTIN_ARGS];
+ machine_mode mode[MAX_BUILTIN_ARGS + 1];
+
+ int nargs = bifaddr->nargs;
+ gcc_assert (nargs <= MAX_BUILTIN_ARGS);
+
+ mode[0] = insn_data[icode].operand[0].mode;
+ for (int i = 0; i < nargs; i++)
+ {
+ arg[i] = CALL_EXPR_ARG (exp, i);
+ if (arg[i] == error_mark_node)
+ return const0_rtx;
+ op[i] = expand_normal (arg[i]);
+ mode[i+1] = insn_data[icode].operand[i+1].mode;
+ }
+
+ /* Check for restricted constant arguments. */
+ for (int i = 0; i < 2; i++)
+ {
+ switch (bifaddr->restr[i])
+ {
+ default:
+ case RES_NONE:
+ break;
+ case RES_BITS:
+ {
+ size_t mask = (1 << bifaddr->restr_val1[i]) - 1;
+ 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)
+ {
+ 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;
+ }
+ }
+ }
+
+ if (bif_is_ldstmask (*bifaddr))
+ return rs6000_expand_ldst_mask (target, arg[0]);
+
+ if (bif_is_stvec (*bifaddr))
+ {
+ if (bif_is_reve (*bifaddr))
+ icode = elemrev_icode (fcode);
+ return stv_expand_builtin (icode, op, mode[0], mode[1]);
+ }
+
+ if (bif_is_ldvec (*bifaddr))
+ {
+ if (bif_is_reve (*bifaddr))
+ icode = elemrev_icode (fcode);
+ return ldv_expand_builtin (target, icode, op, mode[0]);
+ }
+
+ if (bif_is_mma (*bifaddr))
+ return new_mma_expand_builtin (exp, target, icode);
+
+ 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;
+ }
+
+ if (target == 0
+ || GET_MODE (target) != mode[0]
+ || !(*insn_data[icode].operand[0].predicate) (target, mode[0]))
+ target = gen_reg_rtx (mode[0]);
+
+ for (int i = 0; i < nargs; i++)
+ if (! (*insn_data[icode].operand[i+1].predicate) (op[i], mode[i+1]))
+ op[i] = copy_to_mode_reg (mode[i+1], op[i]);
+
+ switch (nargs)
+ {
+ default:
+ gcc_assert (MAX_BUILTIN_ARGS == 5);
+ gcc_unreachable ();
+ case 0:
+ pat = GEN_FCN (icode) (target);
+ break;
+ case 1:
+ pat = GEN_FCN (icode) (target, op[0]);
+ break;
+ case 2:
+ pat = GEN_FCN (icode) (target, op[0], op[1]);
+ break;
+ case 3:
+ pat = GEN_FCN (icode) (target, op[0], op[1], op[2]);
+ break;
+ case 4:
+ pat = GEN_FCN (icode) (target, op[0], op[1], op[2], op[3]);
+ break;
+ case 5:
+ pat = GEN_FCN (icode) (target, op[0], op[1], op[2], op[3], op[4]);
+ break;
+ }
+
+ if (!pat)
+ return 0;
+ emit_insn (pat);
+
+ return target;
}
/* Create a builtin vector type with a name. Taking care not to give
^ permalink raw reply [flat|nested] 4+ messages in thread
* [gcc(refs/users/wschmidt/heads/builtins4)] rs6000: Resolve the fcode problems in rs6000_expand_builtin
@ 2020-11-16 20:52 William Schmidt
0 siblings, 0 replies; 4+ messages in thread
From: William Schmidt @ 2020-11-16 20:52 UTC (permalink / raw)
To: gcc-cvs
https://gcc.gnu.org/g:73a3087a46539c1b143a35e52f38a511bc6f4268
commit 73a3087a46539c1b143a35e52f38a511bc6f4268
Author: Bill Schmidt <wschmidt@linux.ibm.com>
Date: Mon Nov 16 15:51:48 2020 -0500
rs6000: Resolve the fcode problems in rs6000_expand_builtin
2020-11-16 Bill Schmidt <wschmidt@linux.ibm.com>
* config/rs6000/rs6000-call.c (rs6000_expand_new_builtin): New
forward decl.
(ldv_expand_builtin): Move.
(new_mma_expand_builtin): Move.
(stv_expand_builtin): Move.
(elemrev_icode): Move and rewrite.
(htm_spr_num): Move and rewrite.
(new_htm_expand_builtin): Move.
(rs6000_expand_ldst_mask): Move and rewrite.
(rs6000_expand_builtin): Call rs6000_expand_new_builtin; remove
logic for new_builtins_are_live.
(rs6000_expand_new_builtin): New.
Diff:
---
gcc/config/rs6000/rs6000-call.c | 2195 +++++++++++++++++++++------------------
1 file changed, 1177 insertions(+), 1018 deletions(-)
diff --git a/gcc/config/rs6000/rs6000-call.c b/gcc/config/rs6000/rs6000-call.c
index 7cd2138cdb8..0f5e4457af5 100644
--- a/gcc/config/rs6000/rs6000-call.c
+++ b/gcc/config/rs6000/rs6000-call.c
@@ -184,7 +184,7 @@ static tree builtin_function_type (machine_mode, machine_mode,
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);
/* Hash table to keep track of the argument types for builtin functions. */
@@ -10192,60 +10192,6 @@ altivec_expand_lv_builtin (enum insn_code icode, tree exp, rtx target, bool blk)
return target;
}
-static rtx
-ldv_expand_builtin (rtx target, insn_code icode, rtx *op, machine_mode tmode)
-{
- rtx pat, addr;
- bool blk = (icode == CODE_FOR_altivec_lvlx
- || icode == CODE_FOR_altivec_lvlxl
- || icode == CODE_FOR_altivec_lvrx
- || icode == CODE_FOR_altivec_lvrxl);
- op[1] = copy_to_mode_reg (Pmode, op[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)
- {
- 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]);
- }
- 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
- {
- 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]));
- }
-
- pat = GEN_FCN (icode) (target, addr);
- if (! pat)
- return 0;
- emit_insn (pat);
- }
-
- return target;
-}
-
static rtx
altivec_expand_stxvl_builtin (enum insn_code icode, tree exp)
{
@@ -10499,357 +10445,148 @@ mma_expand_builtin (tree exp, rtx target, bool *expandedp)
return target;
}
-/* Expand the MMA built-in in EXP. */
+/* 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 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 the HTM builtin in EXP and store the result in TARGET.
+ Store true in *EXPANDEDP if we found a builtin to expand. */
static rtx
-new_mma_expand_builtin (tree exp, rtx target, rs6000_builtins fcode,
- insn_code icode)
+htm_expand_builtin (tree exp, rtx target, bool * expandedp)
{
tree fndecl = TREE_OPERAND (CALL_EXPR_FN (exp), 0);
- tree arg;
- call_expr_arg_iterator iter;
- const struct insn_operand_data *insn_op;
- rtx op[MAX_MMA_OPERANDS];
- unsigned nopnds = 0;
- /* ### This attr/void_func business needs replacing. */
- unsigned attr = rs6000_builtin_info[fcode].attr;
- bool void_func = (attr & RS6000_BTC_VOID);
- machine_mode tmode = VOIDmode;
+ 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;
- if (TREE_TYPE (TREE_TYPE (fndecl)) != void_type_node)
+ *expandedp = true;
+
+ if (!TARGET_POWERPC64
+ && (fcode == HTM_BUILTIN_TABORTDC
+ || fcode == HTM_BUILTIN_TABORTDCI))
{
- 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;
+ 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;
}
- else
- target = const0_rtx;
- FOR_EACH_CALL_EXPR_ARG (arg, iter, exp)
- {
- if (arg == error_mark_node)
- return const0_rtx;
+ /* 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;
- 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 (uses_spr)
+ icode = rs6000_htm_spr_icode (nonvoid);
+ insn_op = &insn_data[icode].operand[0];
- if (!(*insn_op->predicate) (opnd, insn_op->mode))
+ 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 (!strcmp (insn_op->constraint, "n"))
+ 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 (!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;
+ 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]);
}
- opnd = copy_to_mode_reg (insn_op->mode, opnd);
+
+ nopnds++;
}
- /* Some MMA instructions have INOUT accumulator operands, so force
- their target register to be the same as their input register. */
- /* ### The void_func test needs to happen some other way,
- probably with TREE_TYPE (TREE_TYPE (fndecl)) as earlier. */
- 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;
+ /* 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;
+ }
- 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:
- 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:
- 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;
-}
-
-static rtx
-stv_expand_builtin (insn_code icode, rtx *op,
- machine_mode tmode, machine_mode smode)
-{
- rtx pat, addr, rawaddr;
- 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. */
- 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 (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]);
- }
-
- 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 (! (*insn_data[icode].operand[1].predicate) (op[0], smode))
- op[0] = copy_to_mode_reg (smode, op[0]);
-
- 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]));
- }
-
- pat = GEN_FCN (icode) (addr, op[0]);
- if (pat)
- emit_insn (pat);
- }
-
- return NULL_RTX;
-}
-
-static insn_code
-elemrev_icode (rs6000_builtins fcode)
-{
- switch (fcode)
- {
- default:
- gcc_unreachable ();
- case VSX_BUILTIN_ST_ELEMREV_V1TI:
- return (BYTES_BIG_ENDIAN ? CODE_FOR_vsx_store_v1ti
- : CODE_FOR_vsx_st_elemrev_v1ti);
- case VSX_BUILTIN_ST_ELEMREV_V2DF:
- return (BYTES_BIG_ENDIAN ? CODE_FOR_vsx_store_v2df
- : CODE_FOR_vsx_st_elemrev_v2df);
- case VSX_BUILTIN_ST_ELEMREV_V2DI:
- return (BYTES_BIG_ENDIAN ? CODE_FOR_vsx_store_v2di
- : CODE_FOR_vsx_st_elemrev_v2di);
- case VSX_BUILTIN_ST_ELEMREV_V4SF:
- return (BYTES_BIG_ENDIAN ? CODE_FOR_vsx_store_v4sf
- : CODE_FOR_vsx_st_elemrev_v4sf);
- case VSX_BUILTIN_ST_ELEMREV_V4SI:
- return (BYTES_BIG_ENDIAN ? CODE_FOR_vsx_store_v4si
- : CODE_FOR_vsx_st_elemrev_v4si);
- case VSX_BUILTIN_ST_ELEMREV_V8HI:
- return (BYTES_BIG_ENDIAN ? CODE_FOR_vsx_store_v8hi
- : CODE_FOR_vsx_st_elemrev_v8hi);
- case VSX_BUILTIN_ST_ELEMREV_V16QI:
- return (BYTES_BIG_ENDIAN ? CODE_FOR_vsx_store_v16qi
- : CODE_FOR_vsx_st_elemrev_v16qi);
- case VSX_BUILTIN_LD_ELEMREV_V2DF:
- return (BYTES_BIG_ENDIAN ? CODE_FOR_vsx_load_v2df
- : CODE_FOR_vsx_ld_elemrev_v2df);
- case VSX_BUILTIN_LD_ELEMREV_V1TI:
- return (BYTES_BIG_ENDIAN ? CODE_FOR_vsx_load_v1ti
- : CODE_FOR_vsx_ld_elemrev_v1ti);
- case VSX_BUILTIN_LD_ELEMREV_V2DI:
- return (BYTES_BIG_ENDIAN ? CODE_FOR_vsx_load_v2di
- : CODE_FOR_vsx_ld_elemrev_v2di);
- case VSX_BUILTIN_LD_ELEMREV_V4SF:
- return (BYTES_BIG_ENDIAN ? CODE_FOR_vsx_load_v4sf
- : CODE_FOR_vsx_ld_elemrev_v4sf);
- case VSX_BUILTIN_LD_ELEMREV_V4SI:
- return (BYTES_BIG_ENDIAN ? CODE_FOR_vsx_load_v4si
- : CODE_FOR_vsx_ld_elemrev_v4si);
- case VSX_BUILTIN_LD_ELEMREV_V8HI:
- return (BYTES_BIG_ENDIAN ? CODE_FOR_vsx_load_v8hi
- : CODE_FOR_vsx_ld_elemrev_v8hi);
- case VSX_BUILTIN_LD_ELEMREV_V16QI:
- return (BYTES_BIG_ENDIAN ? CODE_FOR_vsx_load_v16qi
- : CODE_FOR_vsx_ld_elemrev_v16qi);
- }
- gcc_unreachable ();
- return (insn_code) 0;
-}
-
-/* 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 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 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)
-{
- 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 (!TARGET_POWERPC64
- && (fcode == HTM_BUILTIN_TABORTDC
- || fcode == HTM_BUILTIN_TABORTDCI))
- {
- 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;
- }
-
- /* 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 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)
{
@@ -10930,156 +10667,6 @@ htm_expand_builtin (tree exp, rtx target, bool * expandedp)
return NULL_RTX;
}
-/* Expand the HTM builtin in EXP and store the result in TARGET. */
-static rtx
-new_htm_expand_builtin (bifdata *bifaddr, rs6000_builtins fcode,
- tree exp, rtx target)
-{
- tree fndecl = TREE_OPERAND (CALL_EXPR_FN (exp), 0);
- bool nonvoid = TREE_TYPE (TREE_TYPE (fndecl)) != void_type_node;
-
- if (!TARGET_POWERPC64
- && (fcode == HTM_BUILTIN_TABORTDC
- || fcode == HTM_BUILTIN_TABORTDCI))
- {
- error ("builtin %qs is only valid in 64-bit mode", bifaddr->bifname);
- return const0_rtx;
- }
-
- rtx op[MAX_HTM_OPERANDS], pat;
- int nopnds = 0;
- tree arg;
- call_expr_arg_iterator iter;
- insn_code icode = bifaddr->icode;
- bool uses_spr = bif_is_htmspr (*bifaddr);
- rtx cr = NULL_RTX;
-
- if (uses_spr)
- icode = rs6000_htm_spr_icode (nonvoid);
- 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;
- }
-
- 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);
- break;
- case HTM_BUILTIN_TSUSPEND: /* Alias for: tsr. 0 */
- op[nopnds++] = GEN_INT (0);
- 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 (bif_is_htmcr (*bifaddr))
- {
- cr = gen_reg_rtx (CCmode);
- op[nopnds++] = cr;
- }
-
- 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 == 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;
-}
-
/* Expand the CPU builtin in FCODE and store the result in TARGET. */
static rtx
@@ -13496,40 +13083,6 @@ rs6000_gimple_fold_builtin (gimple_stmt_iterator *gsi)
return false;
}
-/* Expand ALTIVEC_BUILTIN_MASK_FOR_LOAD. */
-rtx
-rs6000_expand_ldst_mask (rtx target, rs6000_builtins fcode, 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;
- rtx op, addr, pat;
-
- gcc_assert (TARGET_ALTIVEC);
-
- gcc_assert (POINTER_TYPE_P (TREE_TYPE (arg0)));
- op = expand_expr (arg0, NULL_RTX, Pmode, EXPAND_NORMAL);
- addr = memory_address (mode, op);
- gcc_assert (fcode == ALTIVEC_BUILTIN_MASK_FOR_LOAD);
- /* 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;
-}
-
/* 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).
@@ -13541,11 +13094,10 @@ 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);
- /* #### This needs to be rs6000_gen_builtins now. Can't make this
- whole until the full set of builtins has been added, and there
- is no overlap between the two enumerations, so we can run the
- two in parallel. */
enum rs6000_builtins fcode
= (enum rs6000_builtins) DECL_MD_FUNCTION_CODE (fndecl);
size_t uns_fcode = (size_t)fcode;
@@ -13553,18 +13105,9 @@ rs6000_expand_builtin (tree exp, rtx target, rtx subtarget ATTRIBUTE_UNUSED,
size_t i;
rtx ret;
bool success;
- HOST_WIDE_INT mask = (new_builtins_are_live
- ? 0
- : rs6000_builtin_info[uns_fcode].mask);
- /*
- bif_enable enable = (new_builtins_are_live
- ? rs6000_builtin_info_x[uns_fcode].enable
- : (bif_enable) 0);
- */
+ HOST_WIDE_INT mask = rs6000_builtin_info[uns_fcode].mask;
bool func_valid_p = ((rs6000_builtin_mask & mask) == mask);
- enum insn_code icode = (new_builtins_are_live
- ? rs6000_builtin_info_x[uns_fcode].icode
- : rs6000_builtin_info[uns_fcode].icode);
+ 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
@@ -13595,7 +13138,7 @@ rs6000_expand_builtin (tree exp, rtx target, rtx subtarget ATTRIBUTE_UNUSED,
case CODE_FOR_xststdcqp_kf: icode = CODE_FOR_xststdcqp_tf; break;
}
- if (!new_builtins_are_live && TARGET_DEBUG_BUILTIN)
+ if (TARGET_DEBUG_BUILTIN)
{
const char *name1 = rs6000_builtin_info[uns_fcode].name;
const char *name2 = (icode != CODE_FOR_nothing)
@@ -13633,496 +13176,1112 @@ rs6000_expand_builtin (tree exp, rtx target, rtx subtarget ATTRIBUTE_UNUSED,
return expand_call (exp, target, ignore);
}
- if (new_builtins_are_live)
+ switch (fcode)
{
- bifdata *bifaddr = &rs6000_builtin_info_x[uns_fcode];
+ case RS6000_BUILTIN_RECIP:
+ return rs6000_expand_binop_builtin (CODE_FOR_recipdf3, exp, target);
- /* In case of "#pragma target" changes, we initialize all builtins
- but check for actual availability during expand time. */
- switch (bifaddr->enable)
- {
- default:
- gcc_unreachable ();
- case ENB_ALWAYS:
- break;
- case ENB_P5:
- if (!TARGET_POPCNTB)
- return const0_rtx;
- break;
- case ENB_P6:
- if (!TARGET_CMPB)
- return const0_rtx;
- break;
- case ENB_ALTIVEC:
- if (!TARGET_ALTIVEC)
- return const0_rtx;
- break;
- case ENB_CELL:
- if (!TARGET_ALTIVEC || rs6000_cpu != PROCESSOR_CELL)
- return const0_rtx;
- break;
- case ENB_VSX:
- if (!TARGET_VSX)
- return const0_rtx;
- break;
- case ENB_P7:
- if (!TARGET_POPCNTD)
- return const0_rtx;
- break;
- case ENB_P7_64:
- if (!TARGET_POPCNTD || !TARGET_POWERPC64)
- return const0_rtx;
- break;
- case ENB_P8:
- if (!TARGET_DIRECT_MOVE)
- return const0_rtx;
- break;
- case ENB_P8V:
- if (!TARGET_P8_VECTOR)
- return const0_rtx;
- break;
- case ENB_P9:
- if (!TARGET_MODULO)
- return const0_rtx;
- break;
- case ENB_P9_64:
- if (!TARGET_MODULO || !TARGET_POWERPC64)
- return const0_rtx;
- break;
- case ENB_P9V:
- if (!TARGET_P9_VECTOR)
- return const0_rtx;
- break;
- case ENB_IEEE128_HW:
- if (!TARGET_FLOAT128_HW)
- return const0_rtx;
- break;
- case ENB_DFP:
- if (!TARGET_DFP)
- return const0_rtx;
- break;
- case ENB_CRYPTO:
- if (!TARGET_CRYPTO)
- return const0_rtx;
- break;
- case ENB_HTM:
- if (!TARGET_HTM)
- return const0_rtx;
- break;
- case ENB_P10:
- if (!TARGET_POWER10)
- return const0_rtx;
- break;
- case ENB_MMA:
- if (!TARGET_MMA)
- return const0_rtx;
- break;
- };
+ case RS6000_BUILTIN_RECIPF:
+ return rs6000_expand_binop_builtin (CODE_FOR_recipsf3, exp, target);
- if (bif_is_nosoft (*bifaddr)
- && rs6000_isa_flags & OPTION_MASK_SOFT_FLOAT)
- {
- error ("%<%s%> not supported with %<-msoft-float%>",
- bifaddr->bifname);
- return const0_rtx;
- }
+ case RS6000_BUILTIN_RSQRTF:
+ return rs6000_expand_unop_builtin (CODE_FOR_rsqrtsf2, exp, target);
- if (bif_is_no32bit (*bifaddr) && TARGET_32BIT)
- fatal_error (input_location,
- "%<%s%> is not supported in 32-bit mode",
- bifaddr->bifname);
+ 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);
- if (bif_is_cpu (*bifaddr))
- return cpu_expand_builtin (fcode, exp, 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;
+ }
- if (bif_is_init (*bifaddr))
- return altivec_expand_vec_init_builtin (TREE_TYPE (exp), exp, target);
+ 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;
- if (bif_is_set (*bifaddr))
- return altivec_expand_vec_set_builtin (exp);
+ gcc_assert (TARGET_ALTIVEC);
- if (bif_is_extract (*bifaddr))
- return altivec_expand_vec_ext_builtin (exp, target);
+ 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 (bif_is_predicate (*bifaddr))
- return altivec_expand_predicate_builtin (icode, exp, target);
+ if (target == 0
+ || GET_MODE (target) != tmode
+ || ! (*insn_data[icode2].operand[0].predicate) (target, tmode))
+ target = gen_reg_rtx (tmode);
- if (bif_is_htm (*bifaddr))
- return new_htm_expand_builtin (bifaddr, fcode, exp, target);
+ pat = GEN_FCN (icode2) (target, op);
+ if (!pat)
+ return 0;
+ emit_insn (pat);
- rtx pat;
- const int MAX_BUILTIN_ARGS = 5;
- tree arg[MAX_BUILTIN_ARGS];
- rtx op[MAX_BUILTIN_ARGS];
- machine_mode mode[MAX_BUILTIN_ARGS + 1];
+ return target;
+ }
- int nargs = bifaddr->nargs;
- gcc_assert (nargs <= MAX_BUILTIN_ARGS);
+ case ALTIVEC_BUILTIN_VCFUX:
+ case ALTIVEC_BUILTIN_VCFSX:
+ case ALTIVEC_BUILTIN_VCTUXS:
+ case ALTIVEC_BUILTIN_VCTSXS:
+ /* #### Replace this nonsense with a separate built-in for the
+ vectorizer to use, which I believe is the only way we get
+ into this situation. */
+ /* 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;
- mode[0] = insn_data[icode].operand[0].mode;
- for (int i = 0; i < nargs; i++)
+ /* 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)
{
- arg[i] = CALL_EXPR_ARG (exp, i);
- if (arg[i] == error_mark_node)
- return const0_rtx;
- op[i] = expand_normal (arg[i]);
- mode[i+1] = insn_data[icode].operand[i+1].mode;
+ icode = CODE_FOR_packtf;
+ fcode = MISC_BUILTIN_PACK_TF;
+ uns_fcode = (size_t)fcode;
}
+ break;
- /* Check for restricted constant arguments. */
- for (int i = 0; i < 2; i++)
+ case MISC_BUILTIN_UNPACK_IF:
+ if (TARGET_LONG_DOUBLE_128 && !TARGET_IEEEQUAD)
{
- switch (bifaddr->restr[i])
- {
- default:
- case RES_NONE:
- break;
- case RES_BITS:
- {
- size_t mask = (1 << bifaddr->restr_val1[i]) - 1;
- 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)
- {
- 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;
- }
+ 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_TYPE_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;
+ rtx op, addr, pat;
+
+ gcc_assert (TARGET_ALTIVEC);
+
+ gcc_assert (POINTER_TYPE_P (TREE_TYPE (arg0)));
+ op = expand_expr (arg0, 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;
+}
+
+/* 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);
+
+#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 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_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 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)));
+ }
+ 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;
+}
+
+static insn_code
+elemrev_icode (rs6000_gen_builtins fcode)
+{
+ switch (fcode)
+ {
+ default:
+ gcc_unreachable ();
+ 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);
+ }
+ gcc_unreachable ();
+ return (insn_code) 0;
+}
+
+static rtx
+ldv_expand_builtin (rtx target, insn_code icode, rtx *op, machine_mode tmode)
+{
+ rtx pat, addr;
+ bool blk = (icode == CODE_FOR_altivec_lvlx
+ || icode == CODE_FOR_altivec_lvlxl
+ || icode == CODE_FOR_altivec_lvrx
+ || icode == CODE_FOR_altivec_lvrxl);
+ op[1] = copy_to_mode_reg (Pmode, op[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)
+ {
+ 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]);
+ }
+ 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
+ {
+ 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]));
+ }
+
+ pat = GEN_FCN (icode) (target, addr);
+ if (! pat)
+ return 0;
+ emit_insn (pat);
+ }
+
+ return target;
+}
+
+static rtx
+stv_expand_builtin (insn_code icode, rtx *op,
+ machine_mode tmode, machine_mode smode)
+{
+ rtx pat, addr, rawaddr;
+ 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. */
+ 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 (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]);
+ }
+
+ 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 (! (*insn_data[icode].operand[1].predicate) (op[0], smode))
+ op[0] = copy_to_mode_reg (smode, op[0]);
+
+ 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]));
+ }
+
+ pat = GEN_FCN (icode) (addr, op[0]);
+ if (pat)
+ emit_insn (pat);
+ }
+
+ return NULL_RTX;
+}
+
+/* Expand the MMA built-in in EXP. */
+static rtx
+new_mma_expand_builtin (tree exp, rtx target, insn_code icode)
+{
+ tree fndecl = TREE_OPERAND (CALL_EXPR_FN (exp), 0);
+ tree arg;
+ call_expr_arg_iterator iter;
+ const struct insn_operand_data *insn_op;
+ rtx op[MAX_MMA_OPERANDS];
+ unsigned nopnds = 0;
+ bool void_func = TREE_TYPE (TREE_TYPE (fndecl)) == void_type_node;
+ machine_mode tmode = VOIDmode;
+
+ if (TREE_TYPE (TREE_TYPE (fndecl)) != void_type_node)
+ {
+ 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;
+
+ 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);
}
- if (bif_is_ldstmask (*bifaddr))
- return rs6000_expand_ldst_mask (target, fcode, arg[0]);
+ /* 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:
+ 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:
+ 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. */
+static rtx
+new_htm_expand_builtin (bifdata *bifaddr, rs6000_gen_builtins fcode,
+ tree exp, rtx target)
+{
+ tree fndecl = TREE_OPERAND (CALL_EXPR_FN (exp), 0);
+ bool nonvoid = TREE_TYPE (TREE_TYPE (fndecl)) != void_type_node;
+
+ 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;
+ }
+
+ rtx op[MAX_HTM_OPERANDS], pat;
+ int nopnds = 0;
+ tree arg;
+ call_expr_arg_iterator iter;
+ insn_code icode = bifaddr->icode;
+ bool uses_spr = bif_is_htmspr (*bifaddr);
+ rtx cr = NULL_RTX;
+
+ if (uses_spr)
+ icode = rs6000_htm_spr_icode (nonvoid);
+ 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;
+ }
- if (bif_is_stvec (*bifaddr))
+ 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 (bif_is_reve (*bifaddr))
- icode = elemrev_icode (fcode);
- return stv_expand_builtin (icode, op, mode[0], mode[1]);
+ 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]);
}
- if (bif_is_ldvec (*bifaddr))
- {
- if (bif_is_reve (*bifaddr))
- icode = elemrev_icode (fcode);
- return ldv_expand_builtin (target, icode, op, mode[0]);
- }
+ 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;
+ }
+
+ /* 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, new_htm_spr_num (fcode));
+ }
+ /* If this builtin accesses a CR, then pass in a scratch
+ CR as the last operand. */
+ else if (bif_is_htmcr (*bifaddr))
+ {
+ cr = gen_reg_rtx (CCmode);
+ op[nopnds++] = cr;
+ }
- if (bif_is_mma (*bifaddr))
- return new_mma_expand_builtin (exp, target, fcode, icode);
+ 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 (fcode == MISC_BUILTIN_PACK_IF
- && TARGET_LONG_DOUBLE_128 && !TARGET_IEEEQUAD)
+ if (bif_is_htmcr (*bifaddr))
+ {
+ if (fcode == RS6000_BIF_TBEGIN)
{
- icode = CODE_FOR_packtf;
- fcode = MISC_BUILTIN_PACK_TF;
- uns_fcode = (size_t)fcode;
+ /* 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 if (fcode == MISC_BUILTIN_UNPACK_IF
- && TARGET_LONG_DOUBLE_128 && !TARGET_IEEEQUAD)
+ else
{
- icode = CODE_FOR_unpacktf;
- fcode = MISC_BUILTIN_UNPACK_TF;
- uns_fcode = (size_t)fcode;
+ /* 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 (target == 0
- || GET_MODE (target) != mode[0]
- || !(*insn_data[icode].operand[0].predicate) (target, mode[0]))
- target = gen_reg_rtx (mode[0]);
+ if (nonvoid)
+ return target;
+ return const0_rtx;
+}
- for (int i = 0; i < nargs; i++)
- if (! (*insn_data[icode].operand[i+1].predicate) (op[i], mode[i+1]))
- op[i] = copy_to_mode_reg (mode[i+1], op[i]);
+/* 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 ATTRIBUTE_UNUSED,
+ machine_mode ignore_mode ATTRIBUTE_UNUSED,
+ int ignore ATTRIBUTE_UNUSED)
+{
+ 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;
- switch (nargs)
- {
- default:
- gcc_assert (MAX_BUILTIN_ARGS == 5);
- gcc_unreachable ();
- case 0:
- pat = GEN_FCN (icode) (target);
- break;
- case 1:
- pat = GEN_FCN (icode) (target, op[0]);
- break;
- case 2:
- pat = GEN_FCN (icode) (target, op[0], op[1]);
- break;
- case 3:
- pat = GEN_FCN (icode) (target, op[0], op[1], op[2]);
- break;
- case 4:
- pat = GEN_FCN (icode) (target, op[0], op[1], op[2], op[3]);
- break;
- case 5:
- pat = GEN_FCN (icode) (target, op[0], op[1], op[2], op[3], op[4]);
- break;
- }
+ /* 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;
- if (!pat)
- return 0;
- emit_insn (pat);
+ 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;
+ }
- return target;
- }
- else
+ bifdata *bifaddr = &rs6000_builtin_info_x[uns_fcode];
+
+ /* In case of "#pragma target" changes, we initialize all builtins
+ but check for actual availability during expand time. For
+ invalid builtins, generate a normal call. */
+ switch (bifaddr->enable)
{
- switch (fcode)
+ default:
+ gcc_unreachable ();
+ case ENB_ALWAYS:
+ break;
+ case ENB_P5:
+ if (!TARGET_POPCNTB)
{
- 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);
+ error ("%qs requires at least %qs\n",
+ bifaddr->bifname, "-mcpu=power5");
+ return expand_call (exp, target, ignore);
+ }
+ break;
+ case ENB_P6:
+ if (!TARGET_CMPB)
+ return const0_rtx;
+ break;
+ case ENB_ALTIVEC:
+ if (!TARGET_ALTIVEC)
+ return const0_rtx;
+ break;
+ case ENB_CELL:
+ if (!TARGET_ALTIVEC || rs6000_cpu != PROCESSOR_CELL)
+ return const0_rtx;
+ break;
+ case ENB_VSX:
+ if (!TARGET_VSX)
+ return const0_rtx;
+ break;
+ case ENB_P7:
+ if (!TARGET_POPCNTD)
+ return const0_rtx;
+ break;
+ case ENB_P7_64:
+ if (!TARGET_POPCNTD || !TARGET_POWERPC64)
+ return const0_rtx;
+ break;
+ case ENB_P8:
+ if (!TARGET_DIRECT_MOVE)
+ return const0_rtx;
+ break;
+ case ENB_P8V:
+ if (!TARGET_P8_VECTOR)
+ return const0_rtx;
+ break;
+ case ENB_P9:
+ if (!TARGET_MODULO)
+ return const0_rtx;
+ break;
+ case ENB_P9_64:
+ if (!TARGET_MODULO || !TARGET_POWERPC64)
+ return const0_rtx;
+ break;
+ case ENB_P9V:
+ if (!TARGET_P9_VECTOR)
+ return const0_rtx;
+ break;
+ case ENB_IEEE128_HW:
+ if (!TARGET_FLOAT128_HW)
+ return const0_rtx;
+ break;
+ case ENB_DFP:
+ if (!TARGET_DFP)
+ return const0_rtx;
+ break;
+ case ENB_CRYPTO:
+ if (!TARGET_CRYPTO)
+ return const0_rtx;
+ break;
+ case ENB_HTM:
+ if (!TARGET_HTM)
+ return const0_rtx;
+ break;
+ case ENB_P10:
+ if (!TARGET_POWER10)
+ return const0_rtx;
+ break;
+ case ENB_MMA:
+ if (!TARGET_MMA)
+ return const0_rtx;
+ break;
+ };
- case POWER7_BUILTIN_BPERMD:
- return rs6000_expand_binop_builtin (((TARGET_64BIT)
- ? CODE_FOR_bpermd_di
- : CODE_FOR_bpermd_si),
- exp, target);
+ if (bif_is_nosoft (*bifaddr)
+ && rs6000_isa_flags & OPTION_MASK_SOFT_FLOAT)
+ {
+ error ("%<%s%> not supported with %<-msoft-float%>",
+ bifaddr->bifname);
+ return const0_rtx;
+ }
- case RS6000_BUILTIN_GET_TB:
- return rs6000_expand_zeroop_builtin (CODE_FOR_rs6000_get_timebase,
- target);
+ if (bif_is_no32bit (*bifaddr) && TARGET_32BIT)
+ fatal_error (input_location,
+ "%<%s%> is not supported in 32-bit mode",
+ bifaddr->bifname);
- case RS6000_BUILTIN_MFTB:
- return rs6000_expand_zeroop_builtin (((TARGET_64BIT)
- ? CODE_FOR_rs6000_mftb_di
- : CODE_FOR_rs6000_mftb_si),
- target);
+ if (bif_is_cpu (*bifaddr))
+ return new_cpu_expand_builtin (fcode, exp, target);
- case RS6000_BUILTIN_MFFS:
- return rs6000_expand_zeroop_builtin (CODE_FOR_rs6000_mffs, target);
+ if (bif_is_init (*bifaddr))
+ return altivec_expand_vec_init_builtin (TREE_TYPE (exp), exp, target);
- case RS6000_BUILTIN_MTFSB0:
- return rs6000_expand_mtfsb_builtin (CODE_FOR_rs6000_mtfsb0, exp);
+ if (bif_is_set (*bifaddr))
+ return altivec_expand_vec_set_builtin (exp);
- case RS6000_BUILTIN_MTFSB1:
- return rs6000_expand_mtfsb_builtin (CODE_FOR_rs6000_mtfsb1, exp);
+ if (bif_is_extract (*bifaddr))
+ return altivec_expand_vec_ext_builtin (exp, target);
- case RS6000_BUILTIN_SET_FPSCR_RN:
- return rs6000_expand_set_fpscr_rn_builtin
- (CODE_FOR_rs6000_set_fpscr_rn, exp);
+ if (bif_is_predicate (*bifaddr))
+ return altivec_expand_predicate_builtin (icode, exp, target);
- case RS6000_BUILTIN_SET_FPSCR_DRN:
- return
- rs6000_expand_set_fpscr_drn_builtin (CODE_FOR_rs6000_set_fpscr_drn,
- exp);
+ if (bif_is_htm (*bifaddr))
+ return new_htm_expand_builtin (bifaddr, fcode, exp, target);
- case RS6000_BUILTIN_MFFSL:
- return rs6000_expand_zeroop_builtin (CODE_FOR_rs6000_mffsl, target);
+ rtx pat;
+ const int MAX_BUILTIN_ARGS = 5;
+ tree arg[MAX_BUILTIN_ARGS];
+ rtx op[MAX_BUILTIN_ARGS];
+ machine_mode mode[MAX_BUILTIN_ARGS + 1];
- case RS6000_BUILTIN_MTFSF:
- return rs6000_expand_mtfsf_builtin (CODE_FOR_rs6000_mtfsf, exp);
+ int nargs = bifaddr->nargs;
+ gcc_assert (nargs <= MAX_BUILTIN_ARGS);
- case RS6000_BUILTIN_CPU_INIT:
- case RS6000_BUILTIN_CPU_IS:
- case RS6000_BUILTIN_CPU_SUPPORTS:
- return cpu_expand_builtin (fcode, exp, target);
+ mode[0] = insn_data[icode].operand[0].mode;
+ for (int i = 0; i < nargs; i++)
+ {
+ arg[i] = CALL_EXPR_ARG (exp, i);
+ if (arg[i] == error_mark_node)
+ return const0_rtx;
+ op[i] = expand_normal (arg[i]);
+ mode[i+1] = insn_data[icode].operand[i+1].mode;
+ }
- case MISC_BUILTIN_SPEC_BARRIER:
+ /* Check for restricted constant arguments. */
+ for (int i = 0; i < 2; i++)
+ {
+ switch (bifaddr->restr[i])
+ {
+ default:
+ case RES_NONE:
+ break;
+ case RES_BITS:
{
- emit_insn (gen_speculation_barrier ());
- return NULL_RTX;
+ size_t mask = (1 << bifaddr->restr_val1[i]) - 1;
+ 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)
+ {
+ 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 ALTIVEC_BUILTIN_MASK_FOR_LOAD:
+ case RES_RANGE:
{
- 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;
+ 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;
}
+ }
+ }
- case ALTIVEC_BUILTIN_VCFUX:
- case ALTIVEC_BUILTIN_VCFSX:
- case ALTIVEC_BUILTIN_VCTUXS:
- case ALTIVEC_BUILTIN_VCTSXS:
- /* #### Replace this nonsense with a separate built-in for the
- vectorizer to use, which I believe is the only way we get
- into this situation. */
- /* 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;
+ if (bif_is_ldstmask (*bifaddr))
+ return rs6000_expand_ldst_mask (target, arg[0]);
- /* 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;
+ if (bif_is_stvec (*bifaddr))
+ {
+ if (bif_is_reve (*bifaddr))
+ icode = elemrev_icode (fcode);
+ return stv_expand_builtin (icode, op, mode[0], mode[1]);
+ }
- 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;
+ if (bif_is_ldvec (*bifaddr))
+ {
+ if (bif_is_reve (*bifaddr))
+ icode = elemrev_icode (fcode);
+ return ldv_expand_builtin (target, icode, op, mode[0]);
+ }
- default:
- break;
- }
+ if (bif_is_mma (*bifaddr))
+ return new_mma_expand_builtin (exp, target, icode);
- if (TARGET_MMA)
- {
- ret = mma_expand_builtin (exp, target, &success);
+ 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;
+ }
- if (success)
- return ret;
- }
- if (TARGET_ALTIVEC)
- {
- ret = altivec_expand_builtin (exp, target, &success);
+ if (target == 0
+ || GET_MODE (target) != mode[0]
+ || !(*insn_data[icode].operand[0].predicate) (target, mode[0]))
+ target = gen_reg_rtx (mode[0]);
- 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_TYPE_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);
+ for (int i = 0; i < nargs; i++)
+ if (! (*insn_data[icode].operand[i+1].predicate) (op[i], mode[i+1]))
+ op[i] = copy_to_mode_reg (mode[i+1], op[i]);
+ switch (nargs)
+ {
+ default:
+ gcc_assert (MAX_BUILTIN_ARGS == 5);
gcc_unreachable ();
+ case 0:
+ pat = GEN_FCN (icode) (target);
+ break;
+ case 1:
+ pat = GEN_FCN (icode) (target, op[0]);
+ break;
+ case 2:
+ pat = GEN_FCN (icode) (target, op[0], op[1]);
+ break;
+ case 3:
+ pat = GEN_FCN (icode) (target, op[0], op[1], op[2]);
+ break;
+ case 4:
+ pat = GEN_FCN (icode) (target, op[0], op[1], op[2], op[3]);
+ break;
+ case 5:
+ pat = GEN_FCN (icode) (target, op[0], op[1], op[2], op[3], op[4]);
+ break;
}
+
+ if (!pat)
+ return 0;
+ emit_insn (pat);
+
+ return target;
}
/* Create a builtin vector type with a name. Taking care not to give
^ permalink raw reply [flat|nested] 4+ messages in thread
end of thread, other threads:[~2021-02-07 18:14 UTC | newest]
Thread overview: 4+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-12-16 18:08 [gcc(refs/users/wschmidt/heads/builtins4)] rs6000: Resolve the fcode problems in rs6000_expand_builtin William Schmidt
-- strict thread matches above, loose matches on Subject: below --
2021-02-07 18:14 William Schmidt
2020-11-24 16:45 William Schmidt
2020-11-16 20:52 William Schmidt
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).