[48/55] rs6000: Builtin expansion, part 5

Message ID f75fbd2a4ffe51e08451743d9bb94d8bfce497e5.1623941442.git.wschmidt@linux.ibm.com
State Superseded
Headers show
Series
  • Replace the Power target-specific builtin machinery
Related show

Commit Message

Andreas Krebbel via Gcc-patches June 17, 2021, 3:19 p.m.
2021-06-17  Bill Schmidt  <wschmidt@linux.ibm.com>

gcc/
	* config/rs6000/rs6000-call.c (new_mma_expand_builtin):
	Implement.
---
 gcc/config/rs6000/rs6000-call.c | 103 ++++++++++++++++++++++++++++++++
 1 file changed, 103 insertions(+)

-- 
2.27.0

Comments

Andreas Krebbel via Gcc-patches July 27, 2021, 9:07 p.m. | #1
On Thu, 2021-06-17 at 10:19 -0500, Bill Schmidt via Gcc-patches wrote:
> 2021-06-17  Bill Schmidt  <wschmidt@linux.ibm.com>

> 


Hi,


> gcc/

> 	* config/rs6000/rs6000-call.c (new_mma_expand_builtin):

> 	Implement.


Ok,

> ---

>  gcc/config/rs6000/rs6000-call.c | 103 ++++++++++++++++++++++++++++++++

>  1 file changed, 103 insertions(+)

> 

> diff --git a/gcc/config/rs6000/rs6000-call.c b/gcc/config/rs6000/rs6000-call.c

> index 981eabc1187..e1b685fb874 100644

> --- a/gcc/config/rs6000/rs6000-call.c

> +++ b/gcc/config/rs6000/rs6000-call.c

> @@ -14962,6 +14962,109 @@ static rtx

>  new_mma_expand_builtin (tree exp, rtx target, insn_code icode,

>  			rs6000_gen_builtins fcode)

>  {

> +  tree fndecl = TREE_OPERAND (CALL_EXPR_FN (exp), 0);

> +  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 (!void_func)

> +    {

> +      tmode = insn_data[icode].operand[0].mode;

> +      if (!target

> +	  || GET_MODE (target) != tmode

> +	  || !(*insn_data[icode].operand[0].predicate) (target, tmode))

> +	target = gen_reg_rtx (tmode);

> +      op[nopnds++] = target;

> +    }

> +  else

> +    target = const0_rtx;

> +

> +  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:

> +      /* The ASSEMBLE builtin source operands are reversed in little-endian

> +	 mode, so reorder them.  */

> +      if (fcode == RS6000_BIF_ASSEMBLE_PAIR_V_INTERNAL && !WORDS_BIG_ENDIAN)

> +	std::swap (op[1], op[2]);

> +      pat = GEN_FCN (icode) (op[0], op[1], op[2]);

> +      break;

> +    case 4:

> +      pat = GEN_FCN (icode) (op[0], op[1], op[2], op[3]);

> +      break;

> +    case 5:

> +      /* The ASSEMBLE builtin source operands are reversed in little-endian

> +	 mode, so reorder them.  */


I'd be tempted to consolidate the source operand reversal comments for
RS6000_BIF_ASSEMBLE_PAIR_V_INTERNAL and 
RS6000_BIF_ASSEMBLE_ACC_INTERNAL..  up at the start of the case
statement..  but actually i think this makes sense as-is. 
Ok.


> +      if (fcode == RS6000_BIF_ASSEMBLE_ACC_INTERNAL && !WORDS_BIG_ENDIAN)

> +	{

> +	  std::swap (op[1], op[4]);

> +	  std::swap (op[2], op[3]);

> +	}

> +      pat = GEN_FCN (icode) (op[0], op[1], op[2], op[3], op[4]);

> +      break;

> +    case 6:

> +      pat = GEN_FCN (icode) (op[0], op[1], op[2], op[3], op[4], op[5]);

> +      break;

> +    case 7:

> +      pat = GEN_FCN (icode) (op[0], op[1], op[2], op[3], op[4], op[5], op[6]);

> +      break;

> +    default:

> +      gcc_unreachable ();

> +    }

> +  if (!pat)

> +    return NULL_RTX;

> +  emit_insn (pat);

> +


Ok,
lgtm,
thanks
-Will

>    return target;

>  }

>

Patch

diff --git a/gcc/config/rs6000/rs6000-call.c b/gcc/config/rs6000/rs6000-call.c
index 981eabc1187..e1b685fb874 100644
--- a/gcc/config/rs6000/rs6000-call.c
+++ b/gcc/config/rs6000/rs6000-call.c
@@ -14962,6 +14962,109 @@  static rtx
 new_mma_expand_builtin (tree exp, rtx target, insn_code icode,
 			rs6000_gen_builtins fcode)
 {
+  tree fndecl = TREE_OPERAND (CALL_EXPR_FN (exp), 0);
+  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 (!void_func)
+    {
+      tmode = insn_data[icode].operand[0].mode;
+      if (!target
+	  || GET_MODE (target) != tmode
+	  || !(*insn_data[icode].operand[0].predicate) (target, tmode))
+	target = gen_reg_rtx (tmode);
+      op[nopnds++] = target;
+    }
+  else
+    target = const0_rtx;
+
+  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:
+      /* The ASSEMBLE builtin source operands are reversed in little-endian
+	 mode, so reorder them.  */
+      if (fcode == RS6000_BIF_ASSEMBLE_PAIR_V_INTERNAL && !WORDS_BIG_ENDIAN)
+	std::swap (op[1], op[2]);
+      pat = GEN_FCN (icode) (op[0], op[1], op[2]);
+      break;
+    case 4:
+      pat = GEN_FCN (icode) (op[0], op[1], op[2], op[3]);
+      break;
+    case 5:
+      /* The ASSEMBLE builtin source operands are reversed in little-endian
+	 mode, so reorder them.  */
+      if (fcode == RS6000_BIF_ASSEMBLE_ACC_INTERNAL && !WORDS_BIG_ENDIAN)
+	{
+	  std::swap (op[1], op[4]);
+	  std::swap (op[2], op[3]);
+	}
+      pat = GEN_FCN (icode) (op[0], op[1], op[2], op[3], op[4]);
+      break;
+    case 6:
+      pat = GEN_FCN (icode) (op[0], op[1], op[2], op[3], op[4], op[5]);
+      break;
+    case 7:
+      pat = GEN_FCN (icode) (op[0], op[1], op[2], op[3], op[4], op[5], op[6]);
+      break;
+    default:
+      gcc_unreachable ();
+    }
+  if (!pat)
+    return NULL_RTX;
+  emit_insn (pat);
+
   return target;
 }