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