Beispiel #1
0
/* Return a tree expression for a call to the overloaded builtin
   function OB_FNDECL at LOC with arguments PASSED_ARGLIST.  */
tree
s390_resolve_overloaded_builtin (location_t loc,
				 tree ob_fndecl,
				 void *passed_arglist)
{
  vec<tree, va_gc> *arglist = static_cast<vec<tree, va_gc> *> (passed_arglist);
  unsigned int in_args_num = vec_safe_length (arglist);
  unsigned int ob_args_num = 0;
  unsigned int ob_fcode = DECL_FUNCTION_CODE (ob_fndecl);
  enum s390_overloaded_builtin_vars bindex;
  unsigned int i;
  int last_match_type = INT_MAX;
  int last_match_index = -1;
  unsigned int all_op_flags;
  int num_matches = 0;
  tree target_builtin_decl, b_arg_chain, return_type;
  enum s390_builtin_ov_type_index last_match_fntype_index;

  if (TARGET_DEBUG_ARG)
    fprintf (stderr,
      "s390_resolve_overloaded_builtin, code = %4d, %s - %s overloaded\n",
      (int)ob_fcode, IDENTIFIER_POINTER (DECL_NAME (ob_fndecl)),
     ob_fcode < S390_BUILTIN_MAX ? "not" : "");

  /* 0...S390_BUILTIN_MAX-1 is for non-overloaded builtins.  */
  if (ob_fcode < S390_BUILTIN_MAX)
    {
      if (bflags_for_builtin(ob_fcode) & B_INT)
	{
	  error_at (loc,
		    "Builtin %qF is for GCC internal use only.",
		    ob_fndecl);
	  return error_mark_node;
	}
      return NULL_TREE;
    }

  ob_fcode -= S390_BUILTIN_MAX;

  for (b_arg_chain = TYPE_ARG_TYPES (TREE_TYPE (ob_fndecl));
       !VOID_TYPE_P (TREE_VALUE (b_arg_chain));
       b_arg_chain = TREE_CHAIN (b_arg_chain))
    ob_args_num++;

  if (ob_args_num != in_args_num)
    {
      error_at (loc,
		"Mismatch in number of arguments for builtin %qF. "
		"Expected: %d got %d", ob_fndecl,
		ob_args_num, in_args_num);
      return error_mark_node;
    }

  for (i = 0; i < in_args_num; i++)
    if ((*arglist)[i] == error_mark_node)
      return error_mark_node;

  /* Overloaded builtins without any variants are directly expanded here.  */
  if (desc_start_for_overloaded_builtin[ob_fcode] ==
      S390_OVERLOADED_BUILTIN_VAR_MAX)
    return s390_expand_overloaded_builtin (loc, ob_fcode, arglist, NULL_TREE);

  for (bindex = desc_start_for_overloaded_builtin[ob_fcode];
       bindex <= desc_end_for_overloaded_builtin[ob_fcode];
       bindex = (enum s390_overloaded_builtin_vars)((int)bindex + 1))
  {
    int match_type;
    enum s390_builtin_ov_type_index type_index =
      type_for_overloaded_builtin_var[bindex];

    if (TARGET_DEBUG_ARG)
      fprintf (stderr, "checking variant number: %d", (int)bindex);

    match_type = s390_fn_types_compatible (type_index, arglist);

    if (match_type == INT_MAX)
      continue;

    if (TARGET_DEBUG_ARG)
      fprintf (stderr,
	       " %s match score: %d\n", match_type == 0 ? "perfect" : "imperfect",
	       match_type);

    if (match_type < last_match_type)
      {
	num_matches = 1;
	last_match_type = match_type;
	last_match_fntype_index = type_index;
	last_match_index = bindex;
      }
    else if (match_type == last_match_type)
      num_matches++;
  }

  if (last_match_type == INT_MAX)
    {
      error_at (loc, "invalid parameter combination for intrinsic %qs",
		IDENTIFIER_POINTER (DECL_NAME (ob_fndecl)));
      return error_mark_node;
    }
  else if (num_matches > 1)
    {
      error_at (loc, "ambiguous overload for intrinsic %qs",
		IDENTIFIER_POINTER (DECL_NAME (ob_fndecl)));
      return error_mark_node;
    }

  if (bt_for_overloaded_builtin_var[last_match_index] == S390_BUILTIN_MAX)
    target_builtin_decl = ob_fndecl;
  else
    target_builtin_decl = s390_builtin_decls[bt_for_overloaded_builtin_var[last_match_index]];

  all_op_flags = opflags_overloaded_builtin_var[last_match_index];
  return_type = s390_builtin_types[s390_builtin_ov_types[last_match_fntype_index][0]];

  /* Check for the operand flags in the overloaded builtin variant.  */
  for (i = 0; i < ob_args_num; i++)
    {
      unsigned int op_flags = all_op_flags & ((1 << O_SHIFT) - 1);
      tree arg = (*arglist)[i];
      tree type = s390_builtin_types[s390_builtin_ov_types[last_match_fntype_index][i + 1]];

      all_op_flags = all_op_flags >> O_SHIFT;

      if (op_flags == O_ELEM)
	{
	  int n_elem = s390_vec_n_elem (target_builtin_decl);
	  gcc_assert (n_elem > 0);
	  gcc_assert (type == integer_type_node);
	  (*arglist)[i] = build2 (BIT_AND_EXPR, integer_type_node,
				  fold_convert (integer_type_node, arg),
				  build_int_cst (NULL_TREE, n_elem - 1));
	}

      if (TREE_CODE (arg) != INTEGER_CST || !O_IMM_P (op_flags))
	continue;

      if ((TYPE_UNSIGNED (type)
	   && !int_fits_type_p (arg, c_common_unsigned_type (type)))
	  || (!TYPE_UNSIGNED (type)
	      && !int_fits_type_p (arg, c_common_signed_type (type))))
	{
	  error("constant argument %d for builtin %qF is out "
		"of range for target type",
		i + 1, target_builtin_decl);
	  return error_mark_node;
	}

      if (TREE_CODE (arg) == INTEGER_CST
	  && !s390_const_operand_ok (arg, i + 1, op_flags, target_builtin_decl))
	return error_mark_node;
    }

  /* Handle builtins we expand directly - without mapping it to a low
     level builtin.  */
  if (bt_for_overloaded_builtin_var[last_match_index] == S390_BUILTIN_MAX)
    return s390_expand_overloaded_builtin (loc, ob_fcode, arglist, return_type);

  s390_adjust_builtin_arglist (ob_fcode, target_builtin_decl, &arglist);

  if (VOID_TYPE_P (return_type))
    return build_function_call_vec (loc, vNULL, target_builtin_decl,
				    arglist, NULL);
  else
    return fully_fold_convert (return_type,
			       build_function_call_vec (loc, vNULL, target_builtin_decl,
							arglist, NULL));
}
Beispiel #2
0
static tree
avr_resolve_overloaded_builtin (unsigned int iloc, tree fndecl, void *vargs)
{
  tree type0, type1, fold = NULL_TREE;
  enum avr_builtin_id id = AVR_BUILTIN_COUNT;
  location_t loc = (location_t) iloc;
  vec<tree, va_gc> &args = * (vec<tree, va_gc>*) vargs;

  switch (DECL_FUNCTION_CODE (fndecl))
    {
    default:
      break;

    case AVR_BUILTIN_ABSFX:
      if (args.length() != 1)
        {
          error_at (loc, "%qs expects 1 argument but %d given",
                    "absfx", (int) args.length());

          fold = error_mark_node;
          break;
        }

      type0 = TREE_TYPE (args[0]);

      if (!FIXED_POINT_TYPE_P (type0))
        {
          error_at (loc, "%qs expects a fixed-point value as argument",
                    "absfx");

          fold = error_mark_node;
        }

      switch (TYPE_MODE (type0))
        {
        case QQmode: id = AVR_BUILTIN_ABSHR; break;
        case HQmode: id = AVR_BUILTIN_ABSR; break;
        case SQmode: id = AVR_BUILTIN_ABSLR; break;
        case DQmode: id = AVR_BUILTIN_ABSLLR; break;

        case HAmode: id = AVR_BUILTIN_ABSHK; break;
        case SAmode: id = AVR_BUILTIN_ABSK; break;
        case DAmode: id = AVR_BUILTIN_ABSLK; break;
        case TAmode: id = AVR_BUILTIN_ABSLLK; break;

        case UQQmode:
        case UHQmode:
        case USQmode:
        case UDQmode:
        case UHAmode:
        case USAmode:
        case UDAmode:
        case UTAmode:
          warning_at (loc, 0, "using %qs with unsigned type has no effect",
                      "absfx");
          return args[0];

        default:
          error_at (loc, "no matching fixed-point overload found for %qs",
                    "absfx");

          fold = error_mark_node;
          break;
        }

      fold = targetm.builtin_decl (id, true);

      if (fold != error_mark_node)
        fold = build_function_call_vec (loc, vNULL, fold, &args, NULL);

      break; // absfx

    case AVR_BUILTIN_ROUNDFX:
      if (args.length() != 2)
        {
          error_at (loc, "%qs expects 2 arguments but %d given",
                    "roundfx", (int) args.length());

          fold = error_mark_node;
          break;
        }

      type0 = TREE_TYPE (args[0]);
      type1 = TREE_TYPE (args[1]);

      if (!FIXED_POINT_TYPE_P (type0))
        {
          error_at (loc, "%qs expects a fixed-point value as first argument",
                    "roundfx");

          fold = error_mark_node;
        }

      if (!INTEGRAL_TYPE_P (type1))
        {
          error_at (loc, "%qs expects an integer value as second argument",
                    "roundfx");

          fold = error_mark_node;
        }

      switch (TYPE_MODE (type0))
        {
        case QQmode: id = AVR_BUILTIN_ROUNDHR; break;
        case HQmode: id = AVR_BUILTIN_ROUNDR; break;
        case SQmode: id = AVR_BUILTIN_ROUNDLR; break;
        case DQmode: id = AVR_BUILTIN_ROUNDLLR; break;

        case UQQmode: id = AVR_BUILTIN_ROUNDUHR; break;
        case UHQmode: id = AVR_BUILTIN_ROUNDUR; break;
        case USQmode: id = AVR_BUILTIN_ROUNDULR; break;
        case UDQmode: id = AVR_BUILTIN_ROUNDULLR; break;

        case HAmode: id = AVR_BUILTIN_ROUNDHK; break;
        case SAmode: id = AVR_BUILTIN_ROUNDK; break;
        case DAmode: id = AVR_BUILTIN_ROUNDLK; break;
        case TAmode: id = AVR_BUILTIN_ROUNDLLK; break;

        case UHAmode: id = AVR_BUILTIN_ROUNDUHK; break;
        case USAmode: id = AVR_BUILTIN_ROUNDUK; break;
        case UDAmode: id = AVR_BUILTIN_ROUNDULK; break;
        case UTAmode: id = AVR_BUILTIN_ROUNDULLK; break;

        default:
          error_at (loc, "no matching fixed-point overload found for %qs",
                    "roundfx");

          fold = error_mark_node;
          break;
        }

      fold = targetm.builtin_decl (id, true);

      if (fold != error_mark_node)
        fold = build_function_call_vec (loc, vNULL, fold, &args, NULL);

      break; // roundfx

    case AVR_BUILTIN_COUNTLSFX:
      if (args.length() != 1)
        {
          error_at (loc, "%qs expects 1 argument but %d given",
                    "countlsfx", (int) args.length());

          fold = error_mark_node;
          break;
        }

      type0 = TREE_TYPE (args[0]);

      if (!FIXED_POINT_TYPE_P (type0))
        {
          error_at (loc, "%qs expects a fixed-point value as first argument",
                    "countlsfx");

          fold = error_mark_node;
        }

      switch (TYPE_MODE (type0))
        {
        case QQmode: id = AVR_BUILTIN_COUNTLSHR; break;
        case HQmode: id = AVR_BUILTIN_COUNTLSR; break;
        case SQmode: id = AVR_BUILTIN_COUNTLSLR; break;
        case DQmode: id = AVR_BUILTIN_COUNTLSLLR; break;

        case UQQmode: id = AVR_BUILTIN_COUNTLSUHR; break;
        case UHQmode: id = AVR_BUILTIN_COUNTLSUR; break;
        case USQmode: id = AVR_BUILTIN_COUNTLSULR; break;
        case UDQmode: id = AVR_BUILTIN_COUNTLSULLR; break;

        case HAmode: id = AVR_BUILTIN_COUNTLSHK; break;
        case SAmode: id = AVR_BUILTIN_COUNTLSK; break;
        case DAmode: id = AVR_BUILTIN_COUNTLSLK; break;
        case TAmode: id = AVR_BUILTIN_COUNTLSLLK; break;

        case UHAmode: id = AVR_BUILTIN_COUNTLSUHK; break;
        case USAmode: id = AVR_BUILTIN_COUNTLSUK; break;
        case UDAmode: id = AVR_BUILTIN_COUNTLSULK; break;
        case UTAmode: id = AVR_BUILTIN_COUNTLSULLK; break;

        default:
          error_at (loc, "no matching fixed-point overload found for %qs",
                    "countlsfx");

          fold = error_mark_node;
          break;
        }

      fold = targetm.builtin_decl (id, true);

      if (fold != error_mark_node)
        fold = build_function_call_vec (loc, vNULL, fold, &args, NULL);

      break; // countlsfx
    }

  return fold;
}
Beispiel #3
0
/* target hook for resolve_overloaded_builtin(). Returns a function call
   RTX if we can resolve the overloaded builtin */
tree
spu_resolve_overloaded_builtin (location_t loc, tree fndecl, void *passed_args)
{
#define SCALAR_TYPE_P(t) (INTEGRAL_TYPE_P (t) \
			  || SCALAR_FLOAT_TYPE_P (t) \
			  || POINTER_TYPE_P (t))
  vec<tree, va_gc> *fnargs = static_cast <vec<tree, va_gc> *> (passed_args);
  unsigned int nargs = vec_safe_length (fnargs);
  int new_fcode, fcode = DECL_FUNCTION_CODE (fndecl);
  struct spu_builtin_description *desc;
  tree match = NULL_TREE;

  /* The vector types are not available if the backend is not initialized.  */
  gcc_assert (!flag_preprocess_only);

  desc = &spu_builtins[fcode];
  if (desc->type != B_OVERLOAD)
    return NULL_TREE;

  /* Compare the signature of each internal builtin function with the
     function arguments until a match is found. */

  for (new_fcode = fcode + 1; spu_builtins[new_fcode].type == B_INTERNAL;
       new_fcode++)
    {
      tree decl = targetm.builtin_decl (new_fcode, true);
      tree params = TYPE_ARG_TYPES (TREE_TYPE (decl));
      tree param;
      bool all_scalar;
      unsigned int p;

      /* Check whether all parameters are scalar.  */
      all_scalar = true;
      for (param = params; param != void_list_node; param = TREE_CHAIN (param))
      if (!SCALAR_TYPE_P (TREE_VALUE (param)))
	all_scalar = false;

      for (param = params, p = 0;
	   param != void_list_node;
	   param = TREE_CHAIN (param), p++)
	{
	  tree var, arg_type, param_type = TREE_VALUE (param);

	  if (p >= nargs)
	    {
	      error ("insufficient arguments to overloaded function %s",
		     desc->name);
	      return error_mark_node;
	    }

	  var = (*fnargs)[p];

	  if (TREE_CODE (var) == NON_LVALUE_EXPR)
	    var = TREE_OPERAND (var, 0);

	  if (TREE_CODE (var) == ERROR_MARK)
	    return NULL_TREE;	/* Let somebody else deal with the problem. */

	  arg_type = TREE_TYPE (var);

	  /* The intrinsics spec does not specify precisely how to
	     resolve generic intrinsics.  We require an exact match
	     for vector types and let C do it's usual parameter type
	     checking/promotions for scalar arguments, except for the
	     first argument of intrinsics which don't have a vector
	     parameter. */
	  if ((!SCALAR_TYPE_P (param_type)
	       || !SCALAR_TYPE_P (arg_type)
	       || (all_scalar && p == 0))
	      && !lang_hooks.types_compatible_p (param_type, arg_type))
	    break;
	}
      if (param == void_list_node)
	{
	  if (p != nargs)
	    {
	      error ("too many arguments to overloaded function %s",
		     desc->name);
	      return error_mark_node;
	    }

	  match = decl;
	  break;
	}
    }

  if (match == NULL_TREE)
    {
      error ("parameter list does not match a valid signature for %s()",
	     desc->name);
      return error_mark_node;
    }

  return build_function_call_vec (loc, vNULL, match, fnargs, NULL);
#undef SCALAR_TYPE_P
}