public inbox for gcc-cvs@sourceware.org
help / color / mirror / Atom feed
* [gcc(refs/users/wschmidt/heads/builtins4)] rs6000: Support two builtin expansion algorithms
@ 2020-11-02 22:08 William Schmidt
  0 siblings, 0 replies; 5+ messages in thread
From: William Schmidt @ 2020-11-02 22:08 UTC (permalink / raw)
  To: gcc-cvs

https://gcc.gnu.org/g:175c5286cc4a31e08a55f2db24b63d00a3b6f0cf

commit 175c5286cc4a31e08a55f2db24b63d00a3b6f0cf
Author: Bill Schmidt <wschmidt@linux.ibm.com>
Date:   Mon Nov 2 11:16:08 2020 -0500

    rs6000: Support two builtin expansion algorithms
    
    2020-11-02  Bill Schmidt  <wschmidt@linux.ibm.com>
    
            * config/rs6000/rs6000-call.c (rs6000_expand_builtin): Support two
            kinds of masks and icodes; use a new algorithm under control of
            new_builtins_are_live, while still supporting the old one; do lazy
            enablement to support #pragma target.

Diff:
---
 gcc/config/rs6000/rs6000-call.c | 618 ++++++++++++++++++++++++++++++----------
 1 file changed, 463 insertions(+), 155 deletions(-)

diff --git a/gcc/config/rs6000/rs6000-call.c b/gcc/config/rs6000/rs6000-call.c
index 4080ffb4681..12ff8a4bb92 100644
--- a/gcc/config/rs6000/rs6000-call.c
+++ b/gcc/config/rs6000/rs6000-call.c
@@ -13428,6 +13428,10 @@ rs6000_expand_builtin (tree exp, rtx target, rtx subtarget ATTRIBUTE_UNUSED,
 		       int ignore ATTRIBUTE_UNUSED)
 {
   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;
@@ -13435,9 +13439,18 @@ rs6000_expand_builtin (tree exp, rtx target, rtx subtarget ATTRIBUTE_UNUSED,
   size_t i;
   rtx ret;
   bool success;
-  HOST_WIDE_INT mask = rs6000_builtin_info[uns_fcode].mask;
+  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);
+  */
   bool func_valid_p = ((rs6000_builtin_mask & mask) == mask);
-  enum insn_code icode = rs6000_builtin_info[uns_fcode].icode;
+  enum insn_code icode = (new_builtins_are_live
+			  ? rs6000_builtin_info_x[uns_fcode].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
@@ -13468,7 +13481,7 @@ rs6000_expand_builtin (tree exp, rtx target, rtx subtarget ATTRIBUTE_UNUSED,
       case CODE_FOR_xststdcqp_kf:	icode = CODE_FOR_xststdcqp_tf;	break;
       }
 
-  if (TARGET_DEBUG_BUILTIN)
+  if (!new_builtins_are_live && TARGET_DEBUG_BUILTIN)
     {
       const char *name1 = rs6000_builtin_info[uns_fcode].name;
       const char *name2 = (icode != CODE_FOR_nothing)
@@ -13506,201 +13519,496 @@ rs6000_expand_builtin (tree exp, rtx target, rtx subtarget ATTRIBUTE_UNUSED,
       return expand_call (exp, target, ignore);
     }
 
-  switch (fcode)
+  if (new_builtins_are_live)
     {
-    case RS6000_BUILTIN_RECIP:
-      return rs6000_expand_binop_builtin (CODE_FOR_recipdf3, exp, target);
-
-    case RS6000_BUILTIN_RECIPF:
-      return rs6000_expand_binop_builtin (CODE_FOR_recipsf3, exp, target);
-
-    case RS6000_BUILTIN_RSQRTF:
-      return rs6000_expand_unop_builtin (CODE_FOR_rsqrtsf2, exp, target);
-
-    case RS6000_BUILTIN_RSQRT:
-      return rs6000_expand_unop_builtin (CODE_FOR_rsqrtdf2, exp, target);
-
-    case POWER7_BUILTIN_BPERMD:
-      return rs6000_expand_binop_builtin (((TARGET_64BIT)
-					   ? CODE_FOR_bpermd_di
-					   : CODE_FOR_bpermd_si), exp, target);
+      bifdata *bifaddr = &rs6000_builtin_info_x[uns_fcode];
 
-    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);
+      /* 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_MTFSB0:
-      return rs6000_expand_mtfsb_builtin (CODE_FOR_rs6000_mtfsb0, exp);
+      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_MTFSB1:
-      return rs6000_expand_mtfsb_builtin (CODE_FOR_rs6000_mtfsb1, exp);
+      if (bif_is_no32bit (*bifaddr) && TARGET_32BIT)
+	fatal_error (input_location,
+		     "%<%s%> is not supported in 32-bit mode",
+		     bifaddr->bifname);
 
-    case RS6000_BUILTIN_SET_FPSCR_RN:
-      return rs6000_expand_set_fpscr_rn_builtin (CODE_FOR_rs6000_set_fpscr_rn,
-						 exp);
+      if (bif_is_cpu (*bifaddr))
+	return cpu_expand_builtin (fcode, 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_init (*bifaddr))
+	return altivec_expand_vec_init_builtin (TREE_TYPE (exp), exp, target);
 
-    case RS6000_BUILTIN_MFFSL:
-      return rs6000_expand_zeroop_builtin (CODE_FOR_rs6000_mffsl, target);
+      if (bif_is_set (*bifaddr))
+	return altivec_expand_vec_set_builtin (exp);
 
-    case RS6000_BUILTIN_MTFSF:
-      return rs6000_expand_mtfsf_builtin (CODE_FOR_rs6000_mtfsf, exp);
+      if (bif_is_extract (*bifaddr))
+	return altivec_expand_vec_ext_builtin (exp, target);
 
-    case RS6000_BUILTIN_CPU_INIT:
-    case RS6000_BUILTIN_CPU_IS:
-    case RS6000_BUILTIN_CPU_SUPPORTS:
-      return cpu_expand_builtin (fcode, exp, target);
+      if (bif_is_predicate (*bifaddr))
+	return altivec_expand_predicate_builtin (icode, exp, target);
 
-    case MISC_BUILTIN_SPEC_BARRIER:
-      {
-	emit_insn (gen_speculation_barrier ());
-	return NULL_RTX;
-      }
+      if (bif_is_htm (*bifaddr))
+	return new_htm_expand_builtin (bifaddr, fcode, 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;
+      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];
 
-	gcc_assert (TARGET_ALTIVEC);
+      int nargs = bifaddr->nargs;
+      gcc_assert (nargs <= MAX_BUILTIN_ARGS);
 
-	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);
+      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;
+	}
 
-	if (target == 0
-	    || GET_MODE (target) != tmode
-	    || ! (*insn_data[icode2].operand[0].predicate) (target, tmode))
-	  target = gen_reg_rtx (tmode);
+      /* 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;
+	      }
+	    }
+	}
 
-	pat = GEN_FCN (icode2) (target, op);
-	if (!pat)
-	  return 0;
-	emit_insn (pat);
+      if (bif_is_ldstmask (*bifaddr))
+	return rs6000_expand_ldst_mask (target, fcode, arg[0]);
 
-	return target;
-      }
+      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 ALTIVEC_BUILTIN_VCFUX:
-    case ALTIVEC_BUILTIN_VCFSX:
-    case ALTIVEC_BUILTIN_VCTUXS:
-    case ALTIVEC_BUILTIN_VCTSXS:
-  /* FIXME: There's got to be a nicer way to handle this case than
-     constructing a new CALL_EXPR.  */
-      if (call_expr_nargs (exp) == 1)
+      if (bif_is_ldvec (*bifaddr))
 	{
-	  exp = build_call_nary (TREE_TYPE (exp), CALL_EXPR_FN (exp),
-				 2, CALL_EXPR_ARG (exp, 0), integer_zero_node);
+	  if (bif_is_reve (*bifaddr))
+	    icode = elemrev_icode (fcode);
+	  return ldv_expand_builtin (target, icode, op, mode[0]);
 	}
-      break;
 
-      /* For the pack and unpack int128 routines, fix up the builtin so it
-	 uses the correct IBM128 type.  */
-    case MISC_BUILTIN_PACK_IF:
-      if (TARGET_LONG_DOUBLE_128 && !TARGET_IEEEQUAD)
+      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)
 	{
 	  icode = CODE_FOR_packtf;
 	  fcode = MISC_BUILTIN_PACK_TF;
 	  uns_fcode = (size_t)fcode;
 	}
-      break;
-
-    case MISC_BUILTIN_UNPACK_IF:
-      if (TARGET_LONG_DOUBLE_128 && !TARGET_IEEEQUAD)
+      else if (fcode == MISC_BUILTIN_UNPACK_IF
+	       && TARGET_LONG_DOUBLE_128 && !TARGET_IEEEQUAD)
 	{
 	  icode = CODE_FOR_unpacktf;
 	  fcode = MISC_BUILTIN_UNPACK_TF;
 	  uns_fcode = (size_t)fcode;
 	}
-      break;
 
-    default:
-      break;
-    }
+      if (target == 0
+	  || GET_MODE (target) != mode[0]
+	  || !(*insn_data[icode].operand[0].predicate) (target, mode[0]))
+	target = gen_reg_rtx (mode[0]);
 
-  if (TARGET_MMA)
-    {
-      ret = mma_expand_builtin (exp, target, &success);
+      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]);
 
-      if (success)
-	return ret;
-    }
-  if (TARGET_ALTIVEC)
-    {
-      ret = altivec_expand_builtin (exp, target, &success);
+      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 (success)
-	return ret;
+      if (!pat)
+	return 0;
+      emit_insn (pat);
+
+      return target;
     }
-  if (TARGET_HTM)
+  else
     {
-      ret = htm_expand_builtin (exp, target, &success);
+      switch (fcode)
+	{
+	case RS6000_BUILTIN_RECIP:
+	  return rs6000_expand_binop_builtin (CODE_FOR_recipdf3, exp, target);
 
-      if (success)
-	return ret;
-    }  
+	case RS6000_BUILTIN_RECIPF:
+	  return rs6000_expand_binop_builtin (CODE_FOR_recipsf3, exp, target);
 
-  unsigned attr = rs6000_builtin_info[uns_fcode].attr & RS6000_BTC_OPND_MASK;
-  /* RS6000_BTC_SPECIAL represents no-operand operators.  */
-  gcc_assert (attr == RS6000_BTC_UNARY
-	      || attr == RS6000_BTC_BINARY
-	      || attr == RS6000_BTC_TERNARY
-	      || attr == RS6000_BTC_QUATERNARY
-	      || attr == RS6000_BTC_SPECIAL);
-  
-  /* Handle simple unary operations.  */
-  d = bdesc_1arg;
-  for (i = 0; i < ARRAY_SIZE (bdesc_1arg); i++, d++)
-    if (d->code == fcode)
-      return rs6000_expand_unop_builtin (icode, exp, target);
+	case RS6000_BUILTIN_RSQRTF:
+	  return rs6000_expand_unop_builtin (CODE_FOR_rsqrtsf2, 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);
+	case RS6000_BUILTIN_RSQRT:
+	  return rs6000_expand_unop_builtin (CODE_FOR_rsqrtdf2, 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);
+	case POWER7_BUILTIN_BPERMD:
+	  return rs6000_expand_binop_builtin (((TARGET_64BIT)
+					       ? CODE_FOR_bpermd_di
+					       : CODE_FOR_bpermd_si),
+					      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);
+	case RS6000_BUILTIN_GET_TB:
+	  return rs6000_expand_zeroop_builtin (CODE_FOR_rs6000_get_timebase,
+					       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);
+	case RS6000_BUILTIN_MFTB:
+	  return rs6000_expand_zeroop_builtin (((TARGET_64BIT)
+						? CODE_FOR_rs6000_mftb_di
+						: CODE_FOR_rs6000_mftb_si),
+					       target);
 
-  gcc_unreachable ();
+	case RS6000_BUILTIN_MFFS:
+	  return rs6000_expand_zeroop_builtin (CODE_FOR_rs6000_mffs, target);
+
+	case RS6000_BUILTIN_MTFSB0:
+	  return rs6000_expand_mtfsb_builtin (CODE_FOR_rs6000_mtfsb0, exp);
+
+	case RS6000_BUILTIN_MTFSB1:
+	  return rs6000_expand_mtfsb_builtin (CODE_FOR_rs6000_mtfsb1, exp);
+
+	case RS6000_BUILTIN_SET_FPSCR_RN:
+	  return rs6000_expand_set_fpscr_rn_builtin
+	    (CODE_FOR_rs6000_set_fpscr_rn, exp);
+
+	case RS6000_BUILTIN_SET_FPSCR_DRN:
+	  return
+	    rs6000_expand_set_fpscr_drn_builtin (CODE_FOR_rs6000_set_fpscr_drn,
+						 exp);
+
+	case RS6000_BUILTIN_MFFSL:
+	  return rs6000_expand_zeroop_builtin (CODE_FOR_rs6000_mffsl, target);
+
+	case RS6000_BUILTIN_MTFSF:
+	  return rs6000_expand_mtfsf_builtin (CODE_FOR_rs6000_mtfsf, exp);
+
+	case RS6000_BUILTIN_CPU_INIT:
+	case RS6000_BUILTIN_CPU_IS:
+	case RS6000_BUILTIN_CPU_SUPPORTS:
+	  return cpu_expand_builtin (fcode, exp, target);
+
+	case MISC_BUILTIN_SPEC_BARRIER:
+	  {
+	    emit_insn (gen_speculation_barrier ());
+	    return NULL_RTX;
+	  }
+
+	case ALTIVEC_BUILTIN_MASK_FOR_LOAD:
+	  {
+	    int icode2 = (BYTES_BIG_ENDIAN ? (int) CODE_FOR_altivec_lvsr_direct
+			  : (int) CODE_FOR_altivec_lvsl_direct);
+	    machine_mode tmode = insn_data[icode2].operand[0].mode;
+	    machine_mode mode = insn_data[icode2].operand[1].mode;
+	    tree arg;
+	    rtx op, addr, pat;
+
+	    gcc_assert (TARGET_ALTIVEC);
+
+	    arg = CALL_EXPR_ARG (exp, 0);
+	    gcc_assert (POINTER_TYPE_P (TREE_TYPE (arg)));
+	    op = expand_expr (arg, NULL_RTX, Pmode, EXPAND_NORMAL);
+	    addr = memory_address (mode, op);
+	    /* We need to negate the address.  */
+	    op = gen_reg_rtx (GET_MODE (addr));
+	    emit_insn (gen_rtx_SET (op, gen_rtx_NEG (GET_MODE (addr), addr)));
+	    op = gen_rtx_MEM (mode, op);
+
+	    if (target == 0
+		|| GET_MODE (target) != tmode
+		|| ! (*insn_data[icode2].operand[0].predicate) (target, tmode))
+	      target = gen_reg_rtx (tmode);
+
+	    pat = GEN_FCN (icode2) (target, op);
+	    if (!pat)
+	      return 0;
+	    emit_insn (pat);
+
+	    return target;
+	  }
+
+	case ALTIVEC_BUILTIN_VCFUX:
+	case ALTIVEC_BUILTIN_VCFSX:
+	case ALTIVEC_BUILTIN_VCTUXS:
+	case ALTIVEC_BUILTIN_VCTSXS:
+	  /* #### 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;
+
+	  /* For the pack and unpack int128 routines, fix up the builtin so it
+	     uses the correct IBM128 type.  */
+	case MISC_BUILTIN_PACK_IF:
+	  if (TARGET_LONG_DOUBLE_128 && !TARGET_IEEEQUAD)
+	    {
+	      icode = CODE_FOR_packtf;
+	      fcode = MISC_BUILTIN_PACK_TF;
+	      uns_fcode = (size_t)fcode;
+	    }
+	  break;
+
+	case MISC_BUILTIN_UNPACK_IF:
+	  if (TARGET_LONG_DOUBLE_128 && !TARGET_IEEEQUAD)
+	    {
+	      icode = CODE_FOR_unpacktf;
+	      fcode = MISC_BUILTIN_UNPACK_TF;
+	      uns_fcode = (size_t)fcode;
+	    }
+	  break;
+
+	default:
+	  break;
+	}
+
+      if (TARGET_MMA)
+	{
+	  ret = mma_expand_builtin (exp, target, &success);
+
+	  if (success)
+	    return ret;
+	}
+      if (TARGET_ALTIVEC)
+	{
+	  ret = altivec_expand_builtin (exp, target, &success);
+
+	  if (success)
+	    return ret;
+	}
+      if (TARGET_HTM)
+	{
+	  ret = htm_expand_builtin (exp, target, &success);
+
+	  if (success)
+	    return ret;
+	}
+
+      unsigned attr = (rs6000_builtin_info[uns_fcode].attr
+		       & RS6000_BTC_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 ();
+    }
 }
 
 /* Create a builtin vector type with a name.  Taking care not to give


^ permalink raw reply	[flat|nested] 5+ messages in thread

* [gcc(refs/users/wschmidt/heads/builtins4)] rs6000: Support two builtin expansion algorithms
@ 2021-02-07 18:14 William Schmidt
  0 siblings, 0 replies; 5+ messages in thread
From: William Schmidt @ 2021-02-07 18:14 UTC (permalink / raw)
  To: gcc-cvs

https://gcc.gnu.org/g:650d82f2668a995ae17994787873424f129a8246

commit 650d82f2668a995ae17994787873424f129a8246
Author: Bill Schmidt <wschmidt@linux.ibm.com>
Date:   Mon Nov 2 11:16:08 2020 -0500

    rs6000: Support two builtin expansion algorithms
    
    2020-11-02  Bill Schmidt  <wschmidt@linux.ibm.com>
    
            * config/rs6000/rs6000-call.c (rs6000_expand_builtin): Support two
            kinds of masks and icodes; use a new algorithm under control of
            new_builtins_are_live, while still supporting the old one; do lazy
            enablement to support #pragma target.

Diff:
---
 gcc/config/rs6000/rs6000-call.c | 618 ++++++++++++++++++++++++++++++----------
 1 file changed, 463 insertions(+), 155 deletions(-)

diff --git a/gcc/config/rs6000/rs6000-call.c b/gcc/config/rs6000/rs6000-call.c
index 049f6ead7bf..5921c674439 100644
--- a/gcc/config/rs6000/rs6000-call.c
+++ b/gcc/config/rs6000/rs6000-call.c
@@ -13560,6 +13560,10 @@ rs6000_expand_builtin (tree exp, rtx target, rtx subtarget ATTRIBUTE_UNUSED,
 		       int ignore ATTRIBUTE_UNUSED)
 {
   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;
@@ -13567,9 +13571,18 @@ rs6000_expand_builtin (tree exp, rtx target, rtx subtarget ATTRIBUTE_UNUSED,
   size_t i;
   rtx ret;
   bool success;
-  HOST_WIDE_INT mask = rs6000_builtin_info[uns_fcode].mask;
+  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);
+  */
   bool func_valid_p = ((rs6000_builtin_mask & mask) == mask);
-  enum insn_code icode = rs6000_builtin_info[uns_fcode].icode;
+  enum insn_code icode = (new_builtins_are_live
+			  ? rs6000_builtin_info_x[uns_fcode].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
@@ -13616,7 +13629,7 @@ rs6000_expand_builtin (tree exp, rtx target, rtx subtarget ATTRIBUTE_UNUSED,
 	break;
       }
 
-  if (TARGET_DEBUG_BUILTIN)
+  if (!new_builtins_are_live && TARGET_DEBUG_BUILTIN)
     {
       const char *name1 = rs6000_builtin_info[uns_fcode].name;
       const char *name2 = (icode != CODE_FOR_nothing)
@@ -13654,201 +13667,496 @@ rs6000_expand_builtin (tree exp, rtx target, rtx subtarget ATTRIBUTE_UNUSED,
       return expand_call (exp, target, ignore);
     }
 
-  switch (fcode)
+  if (new_builtins_are_live)
     {
-    case RS6000_BUILTIN_RECIP:
-      return rs6000_expand_binop_builtin (CODE_FOR_recipdf3, exp, target);
-
-    case RS6000_BUILTIN_RECIPF:
-      return rs6000_expand_binop_builtin (CODE_FOR_recipsf3, exp, target);
-
-    case RS6000_BUILTIN_RSQRTF:
-      return rs6000_expand_unop_builtin (CODE_FOR_rsqrtsf2, exp, target);
-
-    case RS6000_BUILTIN_RSQRT:
-      return rs6000_expand_unop_builtin (CODE_FOR_rsqrtdf2, exp, target);
-
-    case POWER7_BUILTIN_BPERMD:
-      return rs6000_expand_binop_builtin (((TARGET_64BIT)
-					   ? CODE_FOR_bpermd_di
-					   : CODE_FOR_bpermd_si), exp, target);
+      bifdata *bifaddr = &rs6000_builtin_info_x[uns_fcode];
 
-    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);
+      /* 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_MTFSB0:
-      return rs6000_expand_mtfsb_builtin (CODE_FOR_rs6000_mtfsb0, exp);
+      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_MTFSB1:
-      return rs6000_expand_mtfsb_builtin (CODE_FOR_rs6000_mtfsb1, exp);
+      if (bif_is_no32bit (*bifaddr) && TARGET_32BIT)
+	fatal_error (input_location,
+		     "%<%s%> is not supported in 32-bit mode",
+		     bifaddr->bifname);
 
-    case RS6000_BUILTIN_SET_FPSCR_RN:
-      return rs6000_expand_set_fpscr_rn_builtin (CODE_FOR_rs6000_set_fpscr_rn,
-						 exp);
+      if (bif_is_cpu (*bifaddr))
+	return cpu_expand_builtin (fcode, 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_init (*bifaddr))
+	return altivec_expand_vec_init_builtin (TREE_TYPE (exp), exp, target);
 
-    case RS6000_BUILTIN_MFFSL:
-      return rs6000_expand_zeroop_builtin (CODE_FOR_rs6000_mffsl, target);
+      if (bif_is_set (*bifaddr))
+	return altivec_expand_vec_set_builtin (exp);
 
-    case RS6000_BUILTIN_MTFSF:
-      return rs6000_expand_mtfsf_builtin (CODE_FOR_rs6000_mtfsf, exp);
+      if (bif_is_extract (*bifaddr))
+	return altivec_expand_vec_ext_builtin (exp, target);
 
-    case RS6000_BUILTIN_CPU_INIT:
-    case RS6000_BUILTIN_CPU_IS:
-    case RS6000_BUILTIN_CPU_SUPPORTS:
-      return cpu_expand_builtin (fcode, exp, target);
+      if (bif_is_predicate (*bifaddr))
+	return altivec_expand_predicate_builtin (icode, exp, target);
 
-    case MISC_BUILTIN_SPEC_BARRIER:
-      {
-	emit_insn (gen_speculation_barrier ());
-	return NULL_RTX;
-      }
+      if (bif_is_htm (*bifaddr))
+	return new_htm_expand_builtin (bifaddr, fcode, 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;
+      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];
 
-	gcc_assert (TARGET_ALTIVEC);
+      int nargs = bifaddr->nargs;
+      gcc_assert (nargs <= MAX_BUILTIN_ARGS);
 
-	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);
+      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;
+	}
 
-	if (target == 0
-	    || GET_MODE (target) != tmode
-	    || ! (*insn_data[icode2].operand[0].predicate) (target, tmode))
-	  target = gen_reg_rtx (tmode);
+      /* 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;
+	      }
+	    }
+	}
 
-	pat = GEN_FCN (icode2) (target, op);
-	if (!pat)
-	  return 0;
-	emit_insn (pat);
+      if (bif_is_ldstmask (*bifaddr))
+	return rs6000_expand_ldst_mask (target, fcode, arg[0]);
 
-	return target;
-      }
+      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 ALTIVEC_BUILTIN_VCFUX:
-    case ALTIVEC_BUILTIN_VCFSX:
-    case ALTIVEC_BUILTIN_VCTUXS:
-    case ALTIVEC_BUILTIN_VCTSXS:
-  /* FIXME: There's got to be a nicer way to handle this case than
-     constructing a new CALL_EXPR.  */
-      if (call_expr_nargs (exp) == 1)
+      if (bif_is_ldvec (*bifaddr))
 	{
-	  exp = build_call_nary (TREE_TYPE (exp), CALL_EXPR_FN (exp),
-				 2, CALL_EXPR_ARG (exp, 0), integer_zero_node);
+	  if (bif_is_reve (*bifaddr))
+	    icode = elemrev_icode (fcode);
+	  return ldv_expand_builtin (target, icode, op, mode[0]);
 	}
-      break;
 
-      /* For the pack and unpack int128 routines, fix up the builtin so it
-	 uses the correct IBM128 type.  */
-    case MISC_BUILTIN_PACK_IF:
-      if (TARGET_LONG_DOUBLE_128 && !TARGET_IEEEQUAD)
+      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)
 	{
 	  icode = CODE_FOR_packtf;
 	  fcode = MISC_BUILTIN_PACK_TF;
 	  uns_fcode = (size_t)fcode;
 	}
-      break;
-
-    case MISC_BUILTIN_UNPACK_IF:
-      if (TARGET_LONG_DOUBLE_128 && !TARGET_IEEEQUAD)
+      else if (fcode == MISC_BUILTIN_UNPACK_IF
+	       && TARGET_LONG_DOUBLE_128 && !TARGET_IEEEQUAD)
 	{
 	  icode = CODE_FOR_unpacktf;
 	  fcode = MISC_BUILTIN_UNPACK_TF;
 	  uns_fcode = (size_t)fcode;
 	}
-      break;
 
-    default:
-      break;
-    }
+      if (target == 0
+	  || GET_MODE (target) != mode[0]
+	  || !(*insn_data[icode].operand[0].predicate) (target, mode[0]))
+	target = gen_reg_rtx (mode[0]);
 
-  if (TARGET_MMA)
-    {
-      ret = mma_expand_builtin (exp, target, &success);
+      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]);
 
-      if (success)
-	return ret;
-    }
-  if (TARGET_ALTIVEC)
-    {
-      ret = altivec_expand_builtin (exp, target, &success);
+      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 (success)
-	return ret;
+      if (!pat)
+	return 0;
+      emit_insn (pat);
+
+      return target;
     }
-  if (TARGET_HTM)
+  else
     {
-      ret = htm_expand_builtin (exp, target, &success);
+      switch (fcode)
+	{
+	case RS6000_BUILTIN_RECIP:
+	  return rs6000_expand_binop_builtin (CODE_FOR_recipdf3, exp, target);
 
-      if (success)
-	return ret;
-    }  
+	case RS6000_BUILTIN_RECIPF:
+	  return rs6000_expand_binop_builtin (CODE_FOR_recipsf3, exp, target);
 
-  unsigned attr = rs6000_builtin_info[uns_fcode].attr & RS6000_BTC_OPND_MASK;
-  /* RS6000_BTC_SPECIAL represents no-operand operators.  */
-  gcc_assert (attr == RS6000_BTC_UNARY
-	      || attr == RS6000_BTC_BINARY
-	      || attr == RS6000_BTC_TERNARY
-	      || attr == RS6000_BTC_QUATERNARY
-	      || attr == RS6000_BTC_SPECIAL);
-  
-  /* Handle simple unary operations.  */
-  d = bdesc_1arg;
-  for (i = 0; i < ARRAY_SIZE (bdesc_1arg); i++, d++)
-    if (d->code == fcode)
-      return rs6000_expand_unop_builtin (icode, exp, target);
+	case RS6000_BUILTIN_RSQRTF:
+	  return rs6000_expand_unop_builtin (CODE_FOR_rsqrtsf2, 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);
+	case RS6000_BUILTIN_RSQRT:
+	  return rs6000_expand_unop_builtin (CODE_FOR_rsqrtdf2, 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);
+	case POWER7_BUILTIN_BPERMD:
+	  return rs6000_expand_binop_builtin (((TARGET_64BIT)
+					       ? CODE_FOR_bpermd_di
+					       : CODE_FOR_bpermd_si),
+					      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);
+	case RS6000_BUILTIN_GET_TB:
+	  return rs6000_expand_zeroop_builtin (CODE_FOR_rs6000_get_timebase,
+					       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);
+	case RS6000_BUILTIN_MFTB:
+	  return rs6000_expand_zeroop_builtin (((TARGET_64BIT)
+						? CODE_FOR_rs6000_mftb_di
+						: CODE_FOR_rs6000_mftb_si),
+					       target);
 
-  gcc_unreachable ();
+	case RS6000_BUILTIN_MFFS:
+	  return rs6000_expand_zeroop_builtin (CODE_FOR_rs6000_mffs, target);
+
+	case RS6000_BUILTIN_MTFSB0:
+	  return rs6000_expand_mtfsb_builtin (CODE_FOR_rs6000_mtfsb0, exp);
+
+	case RS6000_BUILTIN_MTFSB1:
+	  return rs6000_expand_mtfsb_builtin (CODE_FOR_rs6000_mtfsb1, exp);
+
+	case RS6000_BUILTIN_SET_FPSCR_RN:
+	  return rs6000_expand_set_fpscr_rn_builtin
+	    (CODE_FOR_rs6000_set_fpscr_rn, exp);
+
+	case RS6000_BUILTIN_SET_FPSCR_DRN:
+	  return
+	    rs6000_expand_set_fpscr_drn_builtin (CODE_FOR_rs6000_set_fpscr_drn,
+						 exp);
+
+	case RS6000_BUILTIN_MFFSL:
+	  return rs6000_expand_zeroop_builtin (CODE_FOR_rs6000_mffsl, target);
+
+	case RS6000_BUILTIN_MTFSF:
+	  return rs6000_expand_mtfsf_builtin (CODE_FOR_rs6000_mtfsf, exp);
+
+	case RS6000_BUILTIN_CPU_INIT:
+	case RS6000_BUILTIN_CPU_IS:
+	case RS6000_BUILTIN_CPU_SUPPORTS:
+	  return cpu_expand_builtin (fcode, exp, target);
+
+	case MISC_BUILTIN_SPEC_BARRIER:
+	  {
+	    emit_insn (gen_speculation_barrier ());
+	    return NULL_RTX;
+	  }
+
+	case ALTIVEC_BUILTIN_MASK_FOR_LOAD:
+	  {
+	    int icode2 = (BYTES_BIG_ENDIAN ? (int) CODE_FOR_altivec_lvsr_direct
+			  : (int) CODE_FOR_altivec_lvsl_direct);
+	    machine_mode tmode = insn_data[icode2].operand[0].mode;
+	    machine_mode mode = insn_data[icode2].operand[1].mode;
+	    tree arg;
+	    rtx op, addr, pat;
+
+	    gcc_assert (TARGET_ALTIVEC);
+
+	    arg = CALL_EXPR_ARG (exp, 0);
+	    gcc_assert (POINTER_TYPE_P (TREE_TYPE (arg)));
+	    op = expand_expr (arg, NULL_RTX, Pmode, EXPAND_NORMAL);
+	    addr = memory_address (mode, op);
+	    /* We need to negate the address.  */
+	    op = gen_reg_rtx (GET_MODE (addr));
+	    emit_insn (gen_rtx_SET (op, gen_rtx_NEG (GET_MODE (addr), addr)));
+	    op = gen_rtx_MEM (mode, op);
+
+	    if (target == 0
+		|| GET_MODE (target) != tmode
+		|| ! (*insn_data[icode2].operand[0].predicate) (target, tmode))
+	      target = gen_reg_rtx (tmode);
+
+	    pat = GEN_FCN (icode2) (target, op);
+	    if (!pat)
+	      return 0;
+	    emit_insn (pat);
+
+	    return target;
+	  }
+
+	case ALTIVEC_BUILTIN_VCFUX:
+	case ALTIVEC_BUILTIN_VCFSX:
+	case ALTIVEC_BUILTIN_VCTUXS:
+	case ALTIVEC_BUILTIN_VCTSXS:
+	  /* #### 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;
+
+	  /* For the pack and unpack int128 routines, fix up the builtin so it
+	     uses the correct IBM128 type.  */
+	case MISC_BUILTIN_PACK_IF:
+	  if (TARGET_LONG_DOUBLE_128 && !TARGET_IEEEQUAD)
+	    {
+	      icode = CODE_FOR_packtf;
+	      fcode = MISC_BUILTIN_PACK_TF;
+	      uns_fcode = (size_t)fcode;
+	    }
+	  break;
+
+	case MISC_BUILTIN_UNPACK_IF:
+	  if (TARGET_LONG_DOUBLE_128 && !TARGET_IEEEQUAD)
+	    {
+	      icode = CODE_FOR_unpacktf;
+	      fcode = MISC_BUILTIN_UNPACK_TF;
+	      uns_fcode = (size_t)fcode;
+	    }
+	  break;
+
+	default:
+	  break;
+	}
+
+      if (TARGET_MMA)
+	{
+	  ret = mma_expand_builtin (exp, target, &success);
+
+	  if (success)
+	    return ret;
+	}
+      if (TARGET_ALTIVEC)
+	{
+	  ret = altivec_expand_builtin (exp, target, &success);
+
+	  if (success)
+	    return ret;
+	}
+      if (TARGET_HTM)
+	{
+	  ret = htm_expand_builtin (exp, target, &success);
+
+	  if (success)
+	    return ret;
+	}
+
+      unsigned attr = (rs6000_builtin_info[uns_fcode].attr
+		       & RS6000_BTC_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 ();
+    }
 }
 
 /* Create a builtin vector type with a name.  Taking care not to give


^ permalink raw reply	[flat|nested] 5+ messages in thread

* [gcc(refs/users/wschmidt/heads/builtins4)] rs6000: Support two builtin expansion algorithms
@ 2020-12-16 18:07 William Schmidt
  0 siblings, 0 replies; 5+ messages in thread
From: William Schmidt @ 2020-12-16 18:07 UTC (permalink / raw)
  To: gcc-cvs

https://gcc.gnu.org/g:9f2ee3d47fb34e5f86f95d7974708d09e0e02961

commit 9f2ee3d47fb34e5f86f95d7974708d09e0e02961
Author: Bill Schmidt <wschmidt@linux.ibm.com>
Date:   Mon Nov 2 11:16:08 2020 -0500

    rs6000: Support two builtin expansion algorithms
    
    2020-11-02  Bill Schmidt  <wschmidt@linux.ibm.com>
    
            * config/rs6000/rs6000-call.c (rs6000_expand_builtin): Support two
            kinds of masks and icodes; use a new algorithm under control of
            new_builtins_are_live, while still supporting the old one; do lazy
            enablement to support #pragma target.

Diff:
---
 gcc/config/rs6000/rs6000-call.c | 618 ++++++++++++++++++++++++++++++----------
 1 file changed, 463 insertions(+), 155 deletions(-)

diff --git a/gcc/config/rs6000/rs6000-call.c b/gcc/config/rs6000/rs6000-call.c
index cb2d6a05470..3ad544dcd7e 100644
--- a/gcc/config/rs6000/rs6000-call.c
+++ b/gcc/config/rs6000/rs6000-call.c
@@ -13513,6 +13513,10 @@ rs6000_expand_builtin (tree exp, rtx target, rtx subtarget ATTRIBUTE_UNUSED,
 		       int ignore ATTRIBUTE_UNUSED)
 {
   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;
@@ -13520,9 +13524,18 @@ rs6000_expand_builtin (tree exp, rtx target, rtx subtarget ATTRIBUTE_UNUSED,
   size_t i;
   rtx ret;
   bool success;
-  HOST_WIDE_INT mask = rs6000_builtin_info[uns_fcode].mask;
+  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);
+  */
   bool func_valid_p = ((rs6000_builtin_mask & mask) == mask);
-  enum insn_code icode = rs6000_builtin_info[uns_fcode].icode;
+  enum insn_code icode = (new_builtins_are_live
+			  ? rs6000_builtin_info_x[uns_fcode].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
@@ -13569,7 +13582,7 @@ rs6000_expand_builtin (tree exp, rtx target, rtx subtarget ATTRIBUTE_UNUSED,
 	break;
       }
 
-  if (TARGET_DEBUG_BUILTIN)
+  if (!new_builtins_are_live && TARGET_DEBUG_BUILTIN)
     {
       const char *name1 = rs6000_builtin_info[uns_fcode].name;
       const char *name2 = (icode != CODE_FOR_nothing)
@@ -13607,201 +13620,496 @@ rs6000_expand_builtin (tree exp, rtx target, rtx subtarget ATTRIBUTE_UNUSED,
       return expand_call (exp, target, ignore);
     }
 
-  switch (fcode)
+  if (new_builtins_are_live)
     {
-    case RS6000_BUILTIN_RECIP:
-      return rs6000_expand_binop_builtin (CODE_FOR_recipdf3, exp, target);
-
-    case RS6000_BUILTIN_RECIPF:
-      return rs6000_expand_binop_builtin (CODE_FOR_recipsf3, exp, target);
-
-    case RS6000_BUILTIN_RSQRTF:
-      return rs6000_expand_unop_builtin (CODE_FOR_rsqrtsf2, exp, target);
-
-    case RS6000_BUILTIN_RSQRT:
-      return rs6000_expand_unop_builtin (CODE_FOR_rsqrtdf2, exp, target);
-
-    case POWER7_BUILTIN_BPERMD:
-      return rs6000_expand_binop_builtin (((TARGET_64BIT)
-					   ? CODE_FOR_bpermd_di
-					   : CODE_FOR_bpermd_si), exp, target);
+      bifdata *bifaddr = &rs6000_builtin_info_x[uns_fcode];
 
-    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);
+      /* 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_MTFSB0:
-      return rs6000_expand_mtfsb_builtin (CODE_FOR_rs6000_mtfsb0, exp);
+      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_MTFSB1:
-      return rs6000_expand_mtfsb_builtin (CODE_FOR_rs6000_mtfsb1, exp);
+      if (bif_is_no32bit (*bifaddr) && TARGET_32BIT)
+	fatal_error (input_location,
+		     "%<%s%> is not supported in 32-bit mode",
+		     bifaddr->bifname);
 
-    case RS6000_BUILTIN_SET_FPSCR_RN:
-      return rs6000_expand_set_fpscr_rn_builtin (CODE_FOR_rs6000_set_fpscr_rn,
-						 exp);
+      if (bif_is_cpu (*bifaddr))
+	return cpu_expand_builtin (fcode, 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_init (*bifaddr))
+	return altivec_expand_vec_init_builtin (TREE_TYPE (exp), exp, target);
 
-    case RS6000_BUILTIN_MFFSL:
-      return rs6000_expand_zeroop_builtin (CODE_FOR_rs6000_mffsl, target);
+      if (bif_is_set (*bifaddr))
+	return altivec_expand_vec_set_builtin (exp);
 
-    case RS6000_BUILTIN_MTFSF:
-      return rs6000_expand_mtfsf_builtin (CODE_FOR_rs6000_mtfsf, exp);
+      if (bif_is_extract (*bifaddr))
+	return altivec_expand_vec_ext_builtin (exp, target);
 
-    case RS6000_BUILTIN_CPU_INIT:
-    case RS6000_BUILTIN_CPU_IS:
-    case RS6000_BUILTIN_CPU_SUPPORTS:
-      return cpu_expand_builtin (fcode, exp, target);
+      if (bif_is_predicate (*bifaddr))
+	return altivec_expand_predicate_builtin (icode, exp, target);
 
-    case MISC_BUILTIN_SPEC_BARRIER:
-      {
-	emit_insn (gen_speculation_barrier ());
-	return NULL_RTX;
-      }
+      if (bif_is_htm (*bifaddr))
+	return new_htm_expand_builtin (bifaddr, fcode, 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;
+      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];
 
-	gcc_assert (TARGET_ALTIVEC);
+      int nargs = bifaddr->nargs;
+      gcc_assert (nargs <= MAX_BUILTIN_ARGS);
 
-	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);
+      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;
+	}
 
-	if (target == 0
-	    || GET_MODE (target) != tmode
-	    || ! (*insn_data[icode2].operand[0].predicate) (target, tmode))
-	  target = gen_reg_rtx (tmode);
+      /* 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;
+	      }
+	    }
+	}
 
-	pat = GEN_FCN (icode2) (target, op);
-	if (!pat)
-	  return 0;
-	emit_insn (pat);
+      if (bif_is_ldstmask (*bifaddr))
+	return rs6000_expand_ldst_mask (target, fcode, arg[0]);
 
-	return target;
-      }
+      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 ALTIVEC_BUILTIN_VCFUX:
-    case ALTIVEC_BUILTIN_VCFSX:
-    case ALTIVEC_BUILTIN_VCTUXS:
-    case ALTIVEC_BUILTIN_VCTSXS:
-  /* FIXME: There's got to be a nicer way to handle this case than
-     constructing a new CALL_EXPR.  */
-      if (call_expr_nargs (exp) == 1)
+      if (bif_is_ldvec (*bifaddr))
 	{
-	  exp = build_call_nary (TREE_TYPE (exp), CALL_EXPR_FN (exp),
-				 2, CALL_EXPR_ARG (exp, 0), integer_zero_node);
+	  if (bif_is_reve (*bifaddr))
+	    icode = elemrev_icode (fcode);
+	  return ldv_expand_builtin (target, icode, op, mode[0]);
 	}
-      break;
 
-      /* For the pack and unpack int128 routines, fix up the builtin so it
-	 uses the correct IBM128 type.  */
-    case MISC_BUILTIN_PACK_IF:
-      if (TARGET_LONG_DOUBLE_128 && !TARGET_IEEEQUAD)
+      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)
 	{
 	  icode = CODE_FOR_packtf;
 	  fcode = MISC_BUILTIN_PACK_TF;
 	  uns_fcode = (size_t)fcode;
 	}
-      break;
-
-    case MISC_BUILTIN_UNPACK_IF:
-      if (TARGET_LONG_DOUBLE_128 && !TARGET_IEEEQUAD)
+      else if (fcode == MISC_BUILTIN_UNPACK_IF
+	       && TARGET_LONG_DOUBLE_128 && !TARGET_IEEEQUAD)
 	{
 	  icode = CODE_FOR_unpacktf;
 	  fcode = MISC_BUILTIN_UNPACK_TF;
 	  uns_fcode = (size_t)fcode;
 	}
-      break;
 
-    default:
-      break;
-    }
+      if (target == 0
+	  || GET_MODE (target) != mode[0]
+	  || !(*insn_data[icode].operand[0].predicate) (target, mode[0]))
+	target = gen_reg_rtx (mode[0]);
 
-  if (TARGET_MMA)
-    {
-      ret = mma_expand_builtin (exp, target, &success);
+      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]);
 
-      if (success)
-	return ret;
-    }
-  if (TARGET_ALTIVEC)
-    {
-      ret = altivec_expand_builtin (exp, target, &success);
+      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 (success)
-	return ret;
+      if (!pat)
+	return 0;
+      emit_insn (pat);
+
+      return target;
     }
-  if (TARGET_HTM)
+  else
     {
-      ret = htm_expand_builtin (exp, target, &success);
+      switch (fcode)
+	{
+	case RS6000_BUILTIN_RECIP:
+	  return rs6000_expand_binop_builtin (CODE_FOR_recipdf3, exp, target);
 
-      if (success)
-	return ret;
-    }  
+	case RS6000_BUILTIN_RECIPF:
+	  return rs6000_expand_binop_builtin (CODE_FOR_recipsf3, exp, target);
 
-  unsigned attr = rs6000_builtin_info[uns_fcode].attr & RS6000_BTC_OPND_MASK;
-  /* RS6000_BTC_SPECIAL represents no-operand operators.  */
-  gcc_assert (attr == RS6000_BTC_UNARY
-	      || attr == RS6000_BTC_BINARY
-	      || attr == RS6000_BTC_TERNARY
-	      || attr == RS6000_BTC_QUATERNARY
-	      || attr == RS6000_BTC_SPECIAL);
-  
-  /* Handle simple unary operations.  */
-  d = bdesc_1arg;
-  for (i = 0; i < ARRAY_SIZE (bdesc_1arg); i++, d++)
-    if (d->code == fcode)
-      return rs6000_expand_unop_builtin (icode, exp, target);
+	case RS6000_BUILTIN_RSQRTF:
+	  return rs6000_expand_unop_builtin (CODE_FOR_rsqrtsf2, 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);
+	case RS6000_BUILTIN_RSQRT:
+	  return rs6000_expand_unop_builtin (CODE_FOR_rsqrtdf2, 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);
+	case POWER7_BUILTIN_BPERMD:
+	  return rs6000_expand_binop_builtin (((TARGET_64BIT)
+					       ? CODE_FOR_bpermd_di
+					       : CODE_FOR_bpermd_si),
+					      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);
+	case RS6000_BUILTIN_GET_TB:
+	  return rs6000_expand_zeroop_builtin (CODE_FOR_rs6000_get_timebase,
+					       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);
+	case RS6000_BUILTIN_MFTB:
+	  return rs6000_expand_zeroop_builtin (((TARGET_64BIT)
+						? CODE_FOR_rs6000_mftb_di
+						: CODE_FOR_rs6000_mftb_si),
+					       target);
 
-  gcc_unreachable ();
+	case RS6000_BUILTIN_MFFS:
+	  return rs6000_expand_zeroop_builtin (CODE_FOR_rs6000_mffs, target);
+
+	case RS6000_BUILTIN_MTFSB0:
+	  return rs6000_expand_mtfsb_builtin (CODE_FOR_rs6000_mtfsb0, exp);
+
+	case RS6000_BUILTIN_MTFSB1:
+	  return rs6000_expand_mtfsb_builtin (CODE_FOR_rs6000_mtfsb1, exp);
+
+	case RS6000_BUILTIN_SET_FPSCR_RN:
+	  return rs6000_expand_set_fpscr_rn_builtin
+	    (CODE_FOR_rs6000_set_fpscr_rn, exp);
+
+	case RS6000_BUILTIN_SET_FPSCR_DRN:
+	  return
+	    rs6000_expand_set_fpscr_drn_builtin (CODE_FOR_rs6000_set_fpscr_drn,
+						 exp);
+
+	case RS6000_BUILTIN_MFFSL:
+	  return rs6000_expand_zeroop_builtin (CODE_FOR_rs6000_mffsl, target);
+
+	case RS6000_BUILTIN_MTFSF:
+	  return rs6000_expand_mtfsf_builtin (CODE_FOR_rs6000_mtfsf, exp);
+
+	case RS6000_BUILTIN_CPU_INIT:
+	case RS6000_BUILTIN_CPU_IS:
+	case RS6000_BUILTIN_CPU_SUPPORTS:
+	  return cpu_expand_builtin (fcode, exp, target);
+
+	case MISC_BUILTIN_SPEC_BARRIER:
+	  {
+	    emit_insn (gen_speculation_barrier ());
+	    return NULL_RTX;
+	  }
+
+	case ALTIVEC_BUILTIN_MASK_FOR_LOAD:
+	  {
+	    int icode2 = (BYTES_BIG_ENDIAN ? (int) CODE_FOR_altivec_lvsr_direct
+			  : (int) CODE_FOR_altivec_lvsl_direct);
+	    machine_mode tmode = insn_data[icode2].operand[0].mode;
+	    machine_mode mode = insn_data[icode2].operand[1].mode;
+	    tree arg;
+	    rtx op, addr, pat;
+
+	    gcc_assert (TARGET_ALTIVEC);
+
+	    arg = CALL_EXPR_ARG (exp, 0);
+	    gcc_assert (POINTER_TYPE_P (TREE_TYPE (arg)));
+	    op = expand_expr (arg, NULL_RTX, Pmode, EXPAND_NORMAL);
+	    addr = memory_address (mode, op);
+	    /* We need to negate the address.  */
+	    op = gen_reg_rtx (GET_MODE (addr));
+	    emit_insn (gen_rtx_SET (op, gen_rtx_NEG (GET_MODE (addr), addr)));
+	    op = gen_rtx_MEM (mode, op);
+
+	    if (target == 0
+		|| GET_MODE (target) != tmode
+		|| ! (*insn_data[icode2].operand[0].predicate) (target, tmode))
+	      target = gen_reg_rtx (tmode);
+
+	    pat = GEN_FCN (icode2) (target, op);
+	    if (!pat)
+	      return 0;
+	    emit_insn (pat);
+
+	    return target;
+	  }
+
+	case ALTIVEC_BUILTIN_VCFUX:
+	case ALTIVEC_BUILTIN_VCFSX:
+	case ALTIVEC_BUILTIN_VCTUXS:
+	case ALTIVEC_BUILTIN_VCTSXS:
+	  /* #### 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;
+
+	  /* For the pack and unpack int128 routines, fix up the builtin so it
+	     uses the correct IBM128 type.  */
+	case MISC_BUILTIN_PACK_IF:
+	  if (TARGET_LONG_DOUBLE_128 && !TARGET_IEEEQUAD)
+	    {
+	      icode = CODE_FOR_packtf;
+	      fcode = MISC_BUILTIN_PACK_TF;
+	      uns_fcode = (size_t)fcode;
+	    }
+	  break;
+
+	case MISC_BUILTIN_UNPACK_IF:
+	  if (TARGET_LONG_DOUBLE_128 && !TARGET_IEEEQUAD)
+	    {
+	      icode = CODE_FOR_unpacktf;
+	      fcode = MISC_BUILTIN_UNPACK_TF;
+	      uns_fcode = (size_t)fcode;
+	    }
+	  break;
+
+	default:
+	  break;
+	}
+
+      if (TARGET_MMA)
+	{
+	  ret = mma_expand_builtin (exp, target, &success);
+
+	  if (success)
+	    return ret;
+	}
+      if (TARGET_ALTIVEC)
+	{
+	  ret = altivec_expand_builtin (exp, target, &success);
+
+	  if (success)
+	    return ret;
+	}
+      if (TARGET_HTM)
+	{
+	  ret = htm_expand_builtin (exp, target, &success);
+
+	  if (success)
+	    return ret;
+	}
+
+      unsigned attr = (rs6000_builtin_info[uns_fcode].attr
+		       & RS6000_BTC_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 ();
+    }
 }
 
 /* Create a builtin vector type with a name.  Taking care not to give


^ permalink raw reply	[flat|nested] 5+ messages in thread

* [gcc(refs/users/wschmidt/heads/builtins4)] rs6000: Support two builtin expansion algorithms
@ 2020-11-24 16:45 William Schmidt
  0 siblings, 0 replies; 5+ messages in thread
From: William Schmidt @ 2020-11-24 16:45 UTC (permalink / raw)
  To: gcc-cvs

https://gcc.gnu.org/g:08fa03413bfcfbcf3f965e8279a12fde93407724

commit 08fa03413bfcfbcf3f965e8279a12fde93407724
Author: Bill Schmidt <wschmidt@linux.ibm.com>
Date:   Mon Nov 2 11:16:08 2020 -0500

    rs6000: Support two builtin expansion algorithms
    
    2020-11-02  Bill Schmidt  <wschmidt@linux.ibm.com>
    
            * config/rs6000/rs6000-call.c (rs6000_expand_builtin): Support two
            kinds of masks and icodes; use a new algorithm under control of
            new_builtins_are_live, while still supporting the old one; do lazy
            enablement to support #pragma target.

Diff:
---
 gcc/config/rs6000/rs6000-call.c | 618 ++++++++++++++++++++++++++++++----------
 1 file changed, 463 insertions(+), 155 deletions(-)

diff --git a/gcc/config/rs6000/rs6000-call.c b/gcc/config/rs6000/rs6000-call.c
index bd1ddbfd1b2..562f80e191b 100644
--- a/gcc/config/rs6000/rs6000-call.c
+++ b/gcc/config/rs6000/rs6000-call.c
@@ -13513,6 +13513,10 @@ rs6000_expand_builtin (tree exp, rtx target, rtx subtarget ATTRIBUTE_UNUSED,
 		       int ignore ATTRIBUTE_UNUSED)
 {
   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;
@@ -13520,9 +13524,18 @@ rs6000_expand_builtin (tree exp, rtx target, rtx subtarget ATTRIBUTE_UNUSED,
   size_t i;
   rtx ret;
   bool success;
-  HOST_WIDE_INT mask = rs6000_builtin_info[uns_fcode].mask;
+  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);
+  */
   bool func_valid_p = ((rs6000_builtin_mask & mask) == mask);
-  enum insn_code icode = rs6000_builtin_info[uns_fcode].icode;
+  enum insn_code icode = (new_builtins_are_live
+			  ? rs6000_builtin_info_x[uns_fcode].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
@@ -13569,7 +13582,7 @@ rs6000_expand_builtin (tree exp, rtx target, rtx subtarget ATTRIBUTE_UNUSED,
 	break;
       }
 
-  if (TARGET_DEBUG_BUILTIN)
+  if (!new_builtins_are_live && TARGET_DEBUG_BUILTIN)
     {
       const char *name1 = rs6000_builtin_info[uns_fcode].name;
       const char *name2 = (icode != CODE_FOR_nothing)
@@ -13607,201 +13620,496 @@ rs6000_expand_builtin (tree exp, rtx target, rtx subtarget ATTRIBUTE_UNUSED,
       return expand_call (exp, target, ignore);
     }
 
-  switch (fcode)
+  if (new_builtins_are_live)
     {
-    case RS6000_BUILTIN_RECIP:
-      return rs6000_expand_binop_builtin (CODE_FOR_recipdf3, exp, target);
-
-    case RS6000_BUILTIN_RECIPF:
-      return rs6000_expand_binop_builtin (CODE_FOR_recipsf3, exp, target);
-
-    case RS6000_BUILTIN_RSQRTF:
-      return rs6000_expand_unop_builtin (CODE_FOR_rsqrtsf2, exp, target);
-
-    case RS6000_BUILTIN_RSQRT:
-      return rs6000_expand_unop_builtin (CODE_FOR_rsqrtdf2, exp, target);
-
-    case POWER7_BUILTIN_BPERMD:
-      return rs6000_expand_binop_builtin (((TARGET_64BIT)
-					   ? CODE_FOR_bpermd_di
-					   : CODE_FOR_bpermd_si), exp, target);
+      bifdata *bifaddr = &rs6000_builtin_info_x[uns_fcode];
 
-    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);
+      /* 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_MTFSB0:
-      return rs6000_expand_mtfsb_builtin (CODE_FOR_rs6000_mtfsb0, exp);
+      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_MTFSB1:
-      return rs6000_expand_mtfsb_builtin (CODE_FOR_rs6000_mtfsb1, exp);
+      if (bif_is_no32bit (*bifaddr) && TARGET_32BIT)
+	fatal_error (input_location,
+		     "%<%s%> is not supported in 32-bit mode",
+		     bifaddr->bifname);
 
-    case RS6000_BUILTIN_SET_FPSCR_RN:
-      return rs6000_expand_set_fpscr_rn_builtin (CODE_FOR_rs6000_set_fpscr_rn,
-						 exp);
+      if (bif_is_cpu (*bifaddr))
+	return cpu_expand_builtin (fcode, 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_init (*bifaddr))
+	return altivec_expand_vec_init_builtin (TREE_TYPE (exp), exp, target);
 
-    case RS6000_BUILTIN_MFFSL:
-      return rs6000_expand_zeroop_builtin (CODE_FOR_rs6000_mffsl, target);
+      if (bif_is_set (*bifaddr))
+	return altivec_expand_vec_set_builtin (exp);
 
-    case RS6000_BUILTIN_MTFSF:
-      return rs6000_expand_mtfsf_builtin (CODE_FOR_rs6000_mtfsf, exp);
+      if (bif_is_extract (*bifaddr))
+	return altivec_expand_vec_ext_builtin (exp, target);
 
-    case RS6000_BUILTIN_CPU_INIT:
-    case RS6000_BUILTIN_CPU_IS:
-    case RS6000_BUILTIN_CPU_SUPPORTS:
-      return cpu_expand_builtin (fcode, exp, target);
+      if (bif_is_predicate (*bifaddr))
+	return altivec_expand_predicate_builtin (icode, exp, target);
 
-    case MISC_BUILTIN_SPEC_BARRIER:
-      {
-	emit_insn (gen_speculation_barrier ());
-	return NULL_RTX;
-      }
+      if (bif_is_htm (*bifaddr))
+	return new_htm_expand_builtin (bifaddr, fcode, 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;
+      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];
 
-	gcc_assert (TARGET_ALTIVEC);
+      int nargs = bifaddr->nargs;
+      gcc_assert (nargs <= MAX_BUILTIN_ARGS);
 
-	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);
+      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;
+	}
 
-	if (target == 0
-	    || GET_MODE (target) != tmode
-	    || ! (*insn_data[icode2].operand[0].predicate) (target, tmode))
-	  target = gen_reg_rtx (tmode);
+      /* 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;
+	      }
+	    }
+	}
 
-	pat = GEN_FCN (icode2) (target, op);
-	if (!pat)
-	  return 0;
-	emit_insn (pat);
+      if (bif_is_ldstmask (*bifaddr))
+	return rs6000_expand_ldst_mask (target, fcode, arg[0]);
 
-	return target;
-      }
+      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 ALTIVEC_BUILTIN_VCFUX:
-    case ALTIVEC_BUILTIN_VCFSX:
-    case ALTIVEC_BUILTIN_VCTUXS:
-    case ALTIVEC_BUILTIN_VCTSXS:
-  /* FIXME: There's got to be a nicer way to handle this case than
-     constructing a new CALL_EXPR.  */
-      if (call_expr_nargs (exp) == 1)
+      if (bif_is_ldvec (*bifaddr))
 	{
-	  exp = build_call_nary (TREE_TYPE (exp), CALL_EXPR_FN (exp),
-				 2, CALL_EXPR_ARG (exp, 0), integer_zero_node);
+	  if (bif_is_reve (*bifaddr))
+	    icode = elemrev_icode (fcode);
+	  return ldv_expand_builtin (target, icode, op, mode[0]);
 	}
-      break;
 
-      /* For the pack and unpack int128 routines, fix up the builtin so it
-	 uses the correct IBM128 type.  */
-    case MISC_BUILTIN_PACK_IF:
-      if (TARGET_LONG_DOUBLE_128 && !TARGET_IEEEQUAD)
+      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)
 	{
 	  icode = CODE_FOR_packtf;
 	  fcode = MISC_BUILTIN_PACK_TF;
 	  uns_fcode = (size_t)fcode;
 	}
-      break;
-
-    case MISC_BUILTIN_UNPACK_IF:
-      if (TARGET_LONG_DOUBLE_128 && !TARGET_IEEEQUAD)
+      else if (fcode == MISC_BUILTIN_UNPACK_IF
+	       && TARGET_LONG_DOUBLE_128 && !TARGET_IEEEQUAD)
 	{
 	  icode = CODE_FOR_unpacktf;
 	  fcode = MISC_BUILTIN_UNPACK_TF;
 	  uns_fcode = (size_t)fcode;
 	}
-      break;
 
-    default:
-      break;
-    }
+      if (target == 0
+	  || GET_MODE (target) != mode[0]
+	  || !(*insn_data[icode].operand[0].predicate) (target, mode[0]))
+	target = gen_reg_rtx (mode[0]);
 
-  if (TARGET_MMA)
-    {
-      ret = mma_expand_builtin (exp, target, &success);
+      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]);
 
-      if (success)
-	return ret;
-    }
-  if (TARGET_ALTIVEC)
-    {
-      ret = altivec_expand_builtin (exp, target, &success);
+      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 (success)
-	return ret;
+      if (!pat)
+	return 0;
+      emit_insn (pat);
+
+      return target;
     }
-  if (TARGET_HTM)
+  else
     {
-      ret = htm_expand_builtin (exp, target, &success);
+      switch (fcode)
+	{
+	case RS6000_BUILTIN_RECIP:
+	  return rs6000_expand_binop_builtin (CODE_FOR_recipdf3, exp, target);
 
-      if (success)
-	return ret;
-    }  
+	case RS6000_BUILTIN_RECIPF:
+	  return rs6000_expand_binop_builtin (CODE_FOR_recipsf3, exp, target);
 
-  unsigned attr = rs6000_builtin_info[uns_fcode].attr & RS6000_BTC_OPND_MASK;
-  /* RS6000_BTC_SPECIAL represents no-operand operators.  */
-  gcc_assert (attr == RS6000_BTC_UNARY
-	      || attr == RS6000_BTC_BINARY
-	      || attr == RS6000_BTC_TERNARY
-	      || attr == RS6000_BTC_QUATERNARY
-	      || attr == RS6000_BTC_SPECIAL);
-  
-  /* Handle simple unary operations.  */
-  d = bdesc_1arg;
-  for (i = 0; i < ARRAY_SIZE (bdesc_1arg); i++, d++)
-    if (d->code == fcode)
-      return rs6000_expand_unop_builtin (icode, exp, target);
+	case RS6000_BUILTIN_RSQRTF:
+	  return rs6000_expand_unop_builtin (CODE_FOR_rsqrtsf2, 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);
+	case RS6000_BUILTIN_RSQRT:
+	  return rs6000_expand_unop_builtin (CODE_FOR_rsqrtdf2, 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);
+	case POWER7_BUILTIN_BPERMD:
+	  return rs6000_expand_binop_builtin (((TARGET_64BIT)
+					       ? CODE_FOR_bpermd_di
+					       : CODE_FOR_bpermd_si),
+					      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);
+	case RS6000_BUILTIN_GET_TB:
+	  return rs6000_expand_zeroop_builtin (CODE_FOR_rs6000_get_timebase,
+					       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);
+	case RS6000_BUILTIN_MFTB:
+	  return rs6000_expand_zeroop_builtin (((TARGET_64BIT)
+						? CODE_FOR_rs6000_mftb_di
+						: CODE_FOR_rs6000_mftb_si),
+					       target);
 
-  gcc_unreachable ();
+	case RS6000_BUILTIN_MFFS:
+	  return rs6000_expand_zeroop_builtin (CODE_FOR_rs6000_mffs, target);
+
+	case RS6000_BUILTIN_MTFSB0:
+	  return rs6000_expand_mtfsb_builtin (CODE_FOR_rs6000_mtfsb0, exp);
+
+	case RS6000_BUILTIN_MTFSB1:
+	  return rs6000_expand_mtfsb_builtin (CODE_FOR_rs6000_mtfsb1, exp);
+
+	case RS6000_BUILTIN_SET_FPSCR_RN:
+	  return rs6000_expand_set_fpscr_rn_builtin
+	    (CODE_FOR_rs6000_set_fpscr_rn, exp);
+
+	case RS6000_BUILTIN_SET_FPSCR_DRN:
+	  return
+	    rs6000_expand_set_fpscr_drn_builtin (CODE_FOR_rs6000_set_fpscr_drn,
+						 exp);
+
+	case RS6000_BUILTIN_MFFSL:
+	  return rs6000_expand_zeroop_builtin (CODE_FOR_rs6000_mffsl, target);
+
+	case RS6000_BUILTIN_MTFSF:
+	  return rs6000_expand_mtfsf_builtin (CODE_FOR_rs6000_mtfsf, exp);
+
+	case RS6000_BUILTIN_CPU_INIT:
+	case RS6000_BUILTIN_CPU_IS:
+	case RS6000_BUILTIN_CPU_SUPPORTS:
+	  return cpu_expand_builtin (fcode, exp, target);
+
+	case MISC_BUILTIN_SPEC_BARRIER:
+	  {
+	    emit_insn (gen_speculation_barrier ());
+	    return NULL_RTX;
+	  }
+
+	case ALTIVEC_BUILTIN_MASK_FOR_LOAD:
+	  {
+	    int icode2 = (BYTES_BIG_ENDIAN ? (int) CODE_FOR_altivec_lvsr_direct
+			  : (int) CODE_FOR_altivec_lvsl_direct);
+	    machine_mode tmode = insn_data[icode2].operand[0].mode;
+	    machine_mode mode = insn_data[icode2].operand[1].mode;
+	    tree arg;
+	    rtx op, addr, pat;
+
+	    gcc_assert (TARGET_ALTIVEC);
+
+	    arg = CALL_EXPR_ARG (exp, 0);
+	    gcc_assert (POINTER_TYPE_P (TREE_TYPE (arg)));
+	    op = expand_expr (arg, NULL_RTX, Pmode, EXPAND_NORMAL);
+	    addr = memory_address (mode, op);
+	    /* We need to negate the address.  */
+	    op = gen_reg_rtx (GET_MODE (addr));
+	    emit_insn (gen_rtx_SET (op, gen_rtx_NEG (GET_MODE (addr), addr)));
+	    op = gen_rtx_MEM (mode, op);
+
+	    if (target == 0
+		|| GET_MODE (target) != tmode
+		|| ! (*insn_data[icode2].operand[0].predicate) (target, tmode))
+	      target = gen_reg_rtx (tmode);
+
+	    pat = GEN_FCN (icode2) (target, op);
+	    if (!pat)
+	      return 0;
+	    emit_insn (pat);
+
+	    return target;
+	  }
+
+	case ALTIVEC_BUILTIN_VCFUX:
+	case ALTIVEC_BUILTIN_VCFSX:
+	case ALTIVEC_BUILTIN_VCTUXS:
+	case ALTIVEC_BUILTIN_VCTSXS:
+	  /* #### 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;
+
+	  /* For the pack and unpack int128 routines, fix up the builtin so it
+	     uses the correct IBM128 type.  */
+	case MISC_BUILTIN_PACK_IF:
+	  if (TARGET_LONG_DOUBLE_128 && !TARGET_IEEEQUAD)
+	    {
+	      icode = CODE_FOR_packtf;
+	      fcode = MISC_BUILTIN_PACK_TF;
+	      uns_fcode = (size_t)fcode;
+	    }
+	  break;
+
+	case MISC_BUILTIN_UNPACK_IF:
+	  if (TARGET_LONG_DOUBLE_128 && !TARGET_IEEEQUAD)
+	    {
+	      icode = CODE_FOR_unpacktf;
+	      fcode = MISC_BUILTIN_UNPACK_TF;
+	      uns_fcode = (size_t)fcode;
+	    }
+	  break;
+
+	default:
+	  break;
+	}
+
+      if (TARGET_MMA)
+	{
+	  ret = mma_expand_builtin (exp, target, &success);
+
+	  if (success)
+	    return ret;
+	}
+      if (TARGET_ALTIVEC)
+	{
+	  ret = altivec_expand_builtin (exp, target, &success);
+
+	  if (success)
+	    return ret;
+	}
+      if (TARGET_HTM)
+	{
+	  ret = htm_expand_builtin (exp, target, &success);
+
+	  if (success)
+	    return ret;
+	}
+
+      unsigned attr = (rs6000_builtin_info[uns_fcode].attr
+		       & RS6000_BTC_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 ();
+    }
 }
 
 /* Create a builtin vector type with a name.  Taking care not to give


^ permalink raw reply	[flat|nested] 5+ messages in thread

* [gcc(refs/users/wschmidt/heads/builtins4)] rs6000: Support two builtin expansion algorithms
@ 2020-11-02 16:16 William Schmidt
  0 siblings, 0 replies; 5+ messages in thread
From: William Schmidt @ 2020-11-02 16:16 UTC (permalink / raw)
  To: gcc-cvs

https://gcc.gnu.org/g:c7b91f347aad6ec0224e4dde1760ffe41ab4ec78

commit c7b91f347aad6ec0224e4dde1760ffe41ab4ec78
Author: Bill Schmidt <wschmidt@linux.ibm.com>
Date:   Mon Nov 2 11:16:08 2020 -0500

    rs6000: Support two builtin expansion algorithms
    
    2020-11-02  Bill Schmidt  <wschmidt@linux.ibm.com>
    
            * config/rs6000/rs6000-call.c (rs6000_expand_builtin): Support two
            kinds of masks and icodes; use a new algorithm under control of
            new_builtins_are_live, while still supporting the old one; do lazy
            enablement to support #pragma target.

Diff:
---
 gcc/config/rs6000/rs6000-call.c | 618 ++++++++++++++++++++++++++++++----------
 1 file changed, 463 insertions(+), 155 deletions(-)

diff --git a/gcc/config/rs6000/rs6000-call.c b/gcc/config/rs6000/rs6000-call.c
index 6ee1e7833aa..1001cc1e1e7 100644
--- a/gcc/config/rs6000/rs6000-call.c
+++ b/gcc/config/rs6000/rs6000-call.c
@@ -10138,6 +10138,10 @@ mma_expand_builtin (tree exp, rtx target, bool *expandedp)
 {
   unsigned i;
   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);
   const struct builtin_description *d = bdesc_mma;
@@ -13307,9 +13311,18 @@ rs6000_expand_builtin (tree exp, rtx target, rtx subtarget ATTRIBUTE_UNUSED,
   size_t i;
   rtx ret;
   bool success;
-  HOST_WIDE_INT mask = rs6000_builtin_info[uns_fcode].mask;
+  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);
+  */
   bool func_valid_p = ((rs6000_builtin_mask & mask) == mask);
-  enum insn_code icode = rs6000_builtin_info[uns_fcode].icode;
+  enum insn_code icode = (new_builtins_are_live
+			  ? rs6000_builtin_info_x[uns_fcode].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
@@ -13340,7 +13353,7 @@ rs6000_expand_builtin (tree exp, rtx target, rtx subtarget ATTRIBUTE_UNUSED,
       case CODE_FOR_xststdcqp_kf:	icode = CODE_FOR_xststdcqp_tf;	break;
       }
 
-  if (TARGET_DEBUG_BUILTIN)
+  if (!new_builtins_are_live && TARGET_DEBUG_BUILTIN)
     {
       const char *name1 = rs6000_builtin_info[uns_fcode].name;
       const char *name2 = (icode != CODE_FOR_nothing)
@@ -13378,201 +13391,496 @@ rs6000_expand_builtin (tree exp, rtx target, rtx subtarget ATTRIBUTE_UNUSED,
       return expand_call (exp, target, ignore);
     }
 
-  switch (fcode)
+  if (new_builtins_are_live)
     {
-    case RS6000_BUILTIN_RECIP:
-      return rs6000_expand_binop_builtin (CODE_FOR_recipdf3, exp, target);
-
-    case RS6000_BUILTIN_RECIPF:
-      return rs6000_expand_binop_builtin (CODE_FOR_recipsf3, exp, target);
-
-    case RS6000_BUILTIN_RSQRTF:
-      return rs6000_expand_unop_builtin (CODE_FOR_rsqrtsf2, exp, target);
-
-    case RS6000_BUILTIN_RSQRT:
-      return rs6000_expand_unop_builtin (CODE_FOR_rsqrtdf2, exp, target);
-
-    case POWER7_BUILTIN_BPERMD:
-      return rs6000_expand_binop_builtin (((TARGET_64BIT)
-					   ? CODE_FOR_bpermd_di
-					   : CODE_FOR_bpermd_si), exp, target);
+      bifdata *bifaddr = &rs6000_builtin_info_x[uns_fcode];
 
-    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);
+      /* 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_MTFSB0:
-      return rs6000_expand_mtfsb_builtin (CODE_FOR_rs6000_mtfsb0, exp);
+      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_MTFSB1:
-      return rs6000_expand_mtfsb_builtin (CODE_FOR_rs6000_mtfsb1, exp);
+      if (bif_is_no32bit (*bifaddr) && TARGET_32BIT)
+	fatal_error (input_location,
+		     "%<%s%> is not supported in 32-bit mode",
+		     bifaddr->bifname);
 
-    case RS6000_BUILTIN_SET_FPSCR_RN:
-      return rs6000_expand_set_fpscr_rn_builtin (CODE_FOR_rs6000_set_fpscr_rn,
-						 exp);
+      if (bif_is_cpu (*bifaddr))
+	return cpu_expand_builtin (fcode, 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_init (*bifaddr))
+	return altivec_expand_vec_init_builtin (TREE_TYPE (exp), exp, target);
 
-    case RS6000_BUILTIN_MFFSL:
-      return rs6000_expand_zeroop_builtin (CODE_FOR_rs6000_mffsl, target);
+      if (bif_is_set (*bifaddr))
+	return altivec_expand_vec_set_builtin (exp);
 
-    case RS6000_BUILTIN_MTFSF:
-      return rs6000_expand_mtfsf_builtin (CODE_FOR_rs6000_mtfsf, exp);
+      if (bif_is_extract (*bifaddr))
+	return altivec_expand_vec_ext_builtin (exp, target);
 
-    case RS6000_BUILTIN_CPU_INIT:
-    case RS6000_BUILTIN_CPU_IS:
-    case RS6000_BUILTIN_CPU_SUPPORTS:
-      return cpu_expand_builtin (fcode, exp, target);
+      if (bif_is_predicate (*bifaddr))
+	return altivec_expand_predicate_builtin (icode, exp, target);
 
-    case MISC_BUILTIN_SPEC_BARRIER:
-      {
-	emit_insn (gen_speculation_barrier ());
-	return NULL_RTX;
-      }
+      if (bif_is_htm (*bifaddr))
+	return new_htm_expand_builtin (bifaddr, fcode, 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;
+      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];
 
-	gcc_assert (TARGET_ALTIVEC);
+      int nargs = bifaddr->nargs;
+      gcc_assert (nargs <= MAX_BUILTIN_ARGS);
 
-	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);
+      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;
+	}
 
-	if (target == 0
-	    || GET_MODE (target) != tmode
-	    || ! (*insn_data[icode2].operand[0].predicate) (target, tmode))
-	  target = gen_reg_rtx (tmode);
+      /* 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;
+	      }
+	    }
+	}
 
-	pat = GEN_FCN (icode2) (target, op);
-	if (!pat)
-	  return 0;
-	emit_insn (pat);
+      if (bif_is_ldstmask (*bifaddr))
+	return rs6000_expand_ldst_mask (target, fcode, arg[0]);
 
-	return target;
-      }
+      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 ALTIVEC_BUILTIN_VCFUX:
-    case ALTIVEC_BUILTIN_VCFSX:
-    case ALTIVEC_BUILTIN_VCTUXS:
-    case ALTIVEC_BUILTIN_VCTSXS:
-  /* FIXME: There's got to be a nicer way to handle this case than
-     constructing a new CALL_EXPR.  */
-      if (call_expr_nargs (exp) == 1)
+      if (bif_is_ldvec (*bifaddr))
 	{
-	  exp = build_call_nary (TREE_TYPE (exp), CALL_EXPR_FN (exp),
-				 2, CALL_EXPR_ARG (exp, 0), integer_zero_node);
+	  if (bif_is_reve (*bifaddr))
+	    icode = elemrev_icode (fcode);
+	  return ldv_expand_builtin (target, icode, op, mode[0]);
 	}
-      break;
 
-      /* For the pack and unpack int128 routines, fix up the builtin so it
-	 uses the correct IBM128 type.  */
-    case MISC_BUILTIN_PACK_IF:
-      if (TARGET_LONG_DOUBLE_128 && !TARGET_IEEEQUAD)
+      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)
 	{
 	  icode = CODE_FOR_packtf;
 	  fcode = MISC_BUILTIN_PACK_TF;
 	  uns_fcode = (size_t)fcode;
 	}
-      break;
-
-    case MISC_BUILTIN_UNPACK_IF:
-      if (TARGET_LONG_DOUBLE_128 && !TARGET_IEEEQUAD)
+      else if (fcode == MISC_BUILTIN_UNPACK_IF
+	       && TARGET_LONG_DOUBLE_128 && !TARGET_IEEEQUAD)
 	{
 	  icode = CODE_FOR_unpacktf;
 	  fcode = MISC_BUILTIN_UNPACK_TF;
 	  uns_fcode = (size_t)fcode;
 	}
-      break;
 
-    default:
-      break;
-    }
+      if (target == 0
+	  || GET_MODE (target) != mode[0]
+	  || !(*insn_data[icode].operand[0].predicate) (target, mode[0]))
+	target = gen_reg_rtx (mode[0]);
 
-  if (TARGET_MMA)
-    {
-      ret = mma_expand_builtin (exp, target, &success);
+      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]);
 
-      if (success)
-	return ret;
-    }
-  if (TARGET_ALTIVEC)
-    {
-      ret = altivec_expand_builtin (exp, target, &success);
+      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 (success)
-	return ret;
+      if (!pat)
+	return 0;
+      emit_insn (pat);
+
+      return target;
     }
-  if (TARGET_HTM)
+  else
     {
-      ret = htm_expand_builtin (exp, target, &success);
+      switch (fcode)
+	{
+	case RS6000_BUILTIN_RECIP:
+	  return rs6000_expand_binop_builtin (CODE_FOR_recipdf3, exp, target);
 
-      if (success)
-	return ret;
-    }  
+	case RS6000_BUILTIN_RECIPF:
+	  return rs6000_expand_binop_builtin (CODE_FOR_recipsf3, exp, target);
 
-  unsigned attr = rs6000_builtin_info[uns_fcode].attr & RS6000_BTC_OPND_MASK;
-  /* RS6000_BTC_SPECIAL represents no-operand operators.  */
-  gcc_assert (attr == RS6000_BTC_UNARY
-	      || attr == RS6000_BTC_BINARY
-	      || attr == RS6000_BTC_TERNARY
-	      || attr == RS6000_BTC_QUATERNARY
-	      || attr == RS6000_BTC_SPECIAL);
-  
-  /* Handle simple unary operations.  */
-  d = bdesc_1arg;
-  for (i = 0; i < ARRAY_SIZE (bdesc_1arg); i++, d++)
-    if (d->code == fcode)
-      return rs6000_expand_unop_builtin (icode, exp, target);
+	case RS6000_BUILTIN_RSQRTF:
+	  return rs6000_expand_unop_builtin (CODE_FOR_rsqrtsf2, 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);
+	case RS6000_BUILTIN_RSQRT:
+	  return rs6000_expand_unop_builtin (CODE_FOR_rsqrtdf2, 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);
+	case POWER7_BUILTIN_BPERMD:
+	  return rs6000_expand_binop_builtin (((TARGET_64BIT)
+					       ? CODE_FOR_bpermd_di
+					       : CODE_FOR_bpermd_si),
+					      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);
+	case RS6000_BUILTIN_GET_TB:
+	  return rs6000_expand_zeroop_builtin (CODE_FOR_rs6000_get_timebase,
+					       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);
+	case RS6000_BUILTIN_MFTB:
+	  return rs6000_expand_zeroop_builtin (((TARGET_64BIT)
+						? CODE_FOR_rs6000_mftb_di
+						: CODE_FOR_rs6000_mftb_si),
+					       target);
 
-  gcc_unreachable ();
+	case RS6000_BUILTIN_MFFS:
+	  return rs6000_expand_zeroop_builtin (CODE_FOR_rs6000_mffs, target);
+
+	case RS6000_BUILTIN_MTFSB0:
+	  return rs6000_expand_mtfsb_builtin (CODE_FOR_rs6000_mtfsb0, exp);
+
+	case RS6000_BUILTIN_MTFSB1:
+	  return rs6000_expand_mtfsb_builtin (CODE_FOR_rs6000_mtfsb1, exp);
+
+	case RS6000_BUILTIN_SET_FPSCR_RN:
+	  return rs6000_expand_set_fpscr_rn_builtin
+	    (CODE_FOR_rs6000_set_fpscr_rn, exp);
+
+	case RS6000_BUILTIN_SET_FPSCR_DRN:
+	  return
+	    rs6000_expand_set_fpscr_drn_builtin (CODE_FOR_rs6000_set_fpscr_drn,
+						 exp);
+
+	case RS6000_BUILTIN_MFFSL:
+	  return rs6000_expand_zeroop_builtin (CODE_FOR_rs6000_mffsl, target);
+
+	case RS6000_BUILTIN_MTFSF:
+	  return rs6000_expand_mtfsf_builtin (CODE_FOR_rs6000_mtfsf, exp);
+
+	case RS6000_BUILTIN_CPU_INIT:
+	case RS6000_BUILTIN_CPU_IS:
+	case RS6000_BUILTIN_CPU_SUPPORTS:
+	  return cpu_expand_builtin (fcode, exp, target);
+
+	case MISC_BUILTIN_SPEC_BARRIER:
+	  {
+	    emit_insn (gen_speculation_barrier ());
+	    return NULL_RTX;
+	  }
+
+	case ALTIVEC_BUILTIN_MASK_FOR_LOAD:
+	  {
+	    int icode2 = (BYTES_BIG_ENDIAN ? (int) CODE_FOR_altivec_lvsr_direct
+			  : (int) CODE_FOR_altivec_lvsl_direct);
+	    machine_mode tmode = insn_data[icode2].operand[0].mode;
+	    machine_mode mode = insn_data[icode2].operand[1].mode;
+	    tree arg;
+	    rtx op, addr, pat;
+
+	    gcc_assert (TARGET_ALTIVEC);
+
+	    arg = CALL_EXPR_ARG (exp, 0);
+	    gcc_assert (POINTER_TYPE_P (TREE_TYPE (arg)));
+	    op = expand_expr (arg, NULL_RTX, Pmode, EXPAND_NORMAL);
+	    addr = memory_address (mode, op);
+	    /* We need to negate the address.  */
+	    op = gen_reg_rtx (GET_MODE (addr));
+	    emit_insn (gen_rtx_SET (op, gen_rtx_NEG (GET_MODE (addr), addr)));
+	    op = gen_rtx_MEM (mode, op);
+
+	    if (target == 0
+		|| GET_MODE (target) != tmode
+		|| ! (*insn_data[icode2].operand[0].predicate) (target, tmode))
+	      target = gen_reg_rtx (tmode);
+
+	    pat = GEN_FCN (icode2) (target, op);
+	    if (!pat)
+	      return 0;
+	    emit_insn (pat);
+
+	    return target;
+	  }
+
+	case ALTIVEC_BUILTIN_VCFUX:
+	case ALTIVEC_BUILTIN_VCFSX:
+	case ALTIVEC_BUILTIN_VCTUXS:
+	case ALTIVEC_BUILTIN_VCTSXS:
+	  /* #### 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;
+
+	  /* For the pack and unpack int128 routines, fix up the builtin so it
+	     uses the correct IBM128 type.  */
+	case MISC_BUILTIN_PACK_IF:
+	  if (TARGET_LONG_DOUBLE_128 && !TARGET_IEEEQUAD)
+	    {
+	      icode = CODE_FOR_packtf;
+	      fcode = MISC_BUILTIN_PACK_TF;
+	      uns_fcode = (size_t)fcode;
+	    }
+	  break;
+
+	case MISC_BUILTIN_UNPACK_IF:
+	  if (TARGET_LONG_DOUBLE_128 && !TARGET_IEEEQUAD)
+	    {
+	      icode = CODE_FOR_unpacktf;
+	      fcode = MISC_BUILTIN_UNPACK_TF;
+	      uns_fcode = (size_t)fcode;
+	    }
+	  break;
+
+	default:
+	  break;
+	}
+
+      if (TARGET_MMA)
+	{
+	  ret = mma_expand_builtin (exp, target, &success);
+
+	  if (success)
+	    return ret;
+	}
+      if (TARGET_ALTIVEC)
+	{
+	  ret = altivec_expand_builtin (exp, target, &success);
+
+	  if (success)
+	    return ret;
+	}
+      if (TARGET_HTM)
+	{
+	  ret = htm_expand_builtin (exp, target, &success);
+
+	  if (success)
+	    return ret;
+	}
+
+      unsigned attr = (rs6000_builtin_info[uns_fcode].attr
+		       & RS6000_BTC_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 ();
+    }
 }
 
 /* Create a builtin vector type with a name.  Taking care not to give


^ permalink raw reply	[flat|nested] 5+ messages in thread

end of thread, other threads:[~2021-02-07 18:14 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-11-02 22:08 [gcc(refs/users/wschmidt/heads/builtins4)] rs6000: Support two builtin expansion algorithms William Schmidt
  -- strict thread matches above, loose matches on Subject: below --
2021-02-07 18:14 William Schmidt
2020-12-16 18:07 William Schmidt
2020-11-24 16:45 William Schmidt
2020-11-02 16:16 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).