Richard Henderson <[EMAIL PROTECTED]> writes:

>       * builtin-types.def (BT_PTR_LONG, BT_PTR_PTR, BT_FN_BOOL, BT_FN_INT,
>       BT_FN_VOID_PTRPTR, BT_PTR_FN_VOID_PTR, BT_FN_VOID_UINT_UINT,
>       BT_FN_BOOL_LONGPTR_LONGPTR, BT_FN_VOID_OMPFN_PTR_UINT,
>       BT_FN_VOID_OMPFN_PTR_UINT_UINT,
>       BT_FN_BOOL_LONG_LONG_LONG_LONGPTR_LONGPTR,
>       BT_FN_BOOL_LONG_LONG_LONG_LONG_LONGPTR_LONGPTR,
>       BT_FN_VOID_OMPFN_PTR_UINT_LONG_LONG_LONG,
>       BT_FN_VOID_OMPFN_PTR_UINT_LONG_LONG_LONG_LONG): New.

I'm working on a target with two gazillion special builtins (well, a
few hundred) and I got tired of defining a new special type every time
I wanted to define a different builtin.  So I did this, slightly
simplified:

enum c2_builtin_type
{
  C2_INT,       /* int */
  C2_SHORT,     /* short */
  C2_CHAR,      /* char */
  C2_VPTR,      /* void * */
  C2_VOID,      /* void */
  /* plus other weird types */
  C2_NONE,      /* indicates no type */
  C2_MAX
};

struct builtin_description
{
  /* The code for this function.  */
  int icode;

  /* The name of the builtin function.  */
  const char *name;

  /* Code for return type.  */
  enum c2_builtin_type ret_type;

  /* Code for parameter types.  */
  enum c2_builtin_type param_types[6];
};

  tree btypes[C2_MAX];
  struct ftype_cache
  {
    tree fn_type;
    struct ftype_cache *next_arg[C2_MAX];
  } ftypes;

  btypes[C2_INT] = integer_type_node;
  btypes[C2_SHORT] = short_integer_type_node;
  btypes[C2_CHAR] = char_type_node;
  btypes[C2_VPTR] = ptr_type_node;
  btypes[C2_VOID] = void_type_node;
  btypes[C2_NONE] = NULL_TREE;

(plus all the other weird types)

  for (i = 0; i < ARRAY_SIZE (builtins); ++i)
    {
      const struct builtin_description *p;
      struct ftype_cache **pf;
      unsigned int j;

      p = &builtins[i];

      /* We cache the function type when we build it so that we don't
         duplicate function types unnecessarily.  */

      gcc_assert (btypes[p->ret_type] != NULL_TREE);
      pf = &ftypes.next_arg[p->ret_type];
      for (j = 0; j < 6; ++j)
        {
          if (*pf == NULL)
            {
              *pf = alloca (sizeof (struct ftype_cache));
              memset (*pf, 0, sizeof (struct ftype_cache));
            }
          if (p->param_types[j] == C2_NONE)
            break;
          gcc_assert (btypes[p->param_types[j]] != NULL_TREE);
          pf = &(*pf)->next_arg[p->param_types[j]];
        }

      if (*pf == NULL)
        {
          *pf = alloca (sizeof (struct ftype_cache));
          memset (*pf, 0, sizeof (struct ftype_cache));
        }

      if ((*pf)->fn_type == NULL)
        {
          gcc_assert (p->ret_type != C2_NONE);
          (*pf)->fn_type = build_function_type_list (btypes[p->ret_type],
                                                     btypes[p->param_types[0]],
                                                     btypes[p->param_types[1]],
                                                     btypes[p->param_types[2]],
                                                     btypes[p->param_types[3]],
                                                     btypes[p->param_types[4]],
                                                     btypes[p->param_types[5]],
                                                     NULL_TREE);
        }

      lang_hooks.builtin_function (p->name, (*pf)->fn_type,
                                   p->icode, BUILT_IN_MD,
                                   NULL, NULL);
    }

The builtins table is initialized with a separate .def file, but it
boils down to initializers this:

  { code, "__builtin_name", C2_INT,
   { C2_INT, C2_VPTR, C2_NONE, C2_NONE, C2_NONE, C2_NONE } },

This way I only have to write the type in one place, I only create the
function types I need, and the types are cached so I don't create the
same type more than once.

Much simpler in the long run, I think.

(And this is why I needed this patch:

2005-02-11  Ian Lance Taylor  <ian@airs.com>

        * tree.c (build_function_type_list): Work correctly if there are
        no arguments.

for the case of a builtin which takes no parameters, for which we wind
up calling build_function_type_list (NULL_TREE, NULL_TREE, ....).)

Ian

Reply via email to