From: Not Zed Date: Mon, 20 Dec 2021 22:24:16 +0000 (+1030) Subject: Extract more symbolic information from the tree. X-Git-Url: https://code.zedzone.au/cvs?a=commitdiff_plain;h=2c26915a98943dfbf6efadb3a0831a7fc4b6840f;p=panamaz Extract more symbolic information from the tree. - names of typedef function pointers - argument names in functions and function prototypes. --- diff --git a/src/Makefile b/src/Makefile index 7b8fdb6..ebab9dc 100644 --- a/src/Makefile +++ b/src/Makefile @@ -1,14 +1,16 @@ +PLUGINDIR=$(shell gcc -print-file-name=plugin) + CXXFLAGS=-fPIC -Wall -Wno-switch -g -CPPFLAGS=-I. -I/usr/lib64/gcc/x86_64-slackware-linux/9.2.0/plugin/include +CPPFLAGS=-I. -I$(PLUGINDIR)/include all: export.so -export.o: export.cc list.h tree-codes.h -export.so: export.o +export.o: export.cc list.h +export.so: export.o tree-codes.o $(CC) $(INCLUDE) -shared -fPIC -o $@ $^ clean: - rm -f export.o export.so + rm -f export.o tree-codes.o export.so .PHONY: clean diff --git a/src/export.cc b/src/export.cc index ed19501..17d4dad 100644 --- a/src/export.cc +++ b/src/export.cc @@ -2,7 +2,7 @@ * export c types and prototypes to perl file. * * Copyright (c) 2019 Yonatan Goldschmidt - * Copyright (c) 2020 Michael Zucchi + * Copyright (c) 2020,2021 Michael Zucchi * * The MIT License (MIT) * @@ -50,12 +50,15 @@ FUNCTION_DECL DECL_ARGUENTS TREE_TYPE(item):PARM_DECL DECL_NAME(item) #include #include #include +#include -#include "tree-codes.h" #include "list.h" #define D(x) do { x; } while(0) +extern const char *tree_codes[]; +#define ZTREE_CODE(x) tree_codes[TREE_CODE(x)] + //Enums have a type, otherwise they're just integers //#define TYPED_ENUMS @@ -65,24 +68,30 @@ FUNCTION_DECL DECL_ARGUENTS TREE_TYPE(item):PARM_DECL DECL_NAME(item) int plugin_is_GPL_compatible; // must be defined for the plugin to run static FILE *output_file; +static int debug_level = 0; static void debug_tree_helper(tree t, const char *msg) { #ifndef NDEBUG - fflush(stdout); - fprintf(stderr, "dumping tree: '%s'\n", msg); - debug_tree(t); - fprintf(stderr, "\n\n"); - fflush(stdout); + if (debug_level > 2) { + fflush(stdout); + fprintf(stderr, "dumping tree: '%s'\n", msg); + debug_tree(t); + fprintf(stderr, "\n\n"); + fflush(stdout); + } #endif } static struct hash dumped; static struct list todump; static struct list context_stack; +static struct list parameters; // last list of params + +static struct hash forward_types; /* Join all names in the stack, in reverse order. - */ +*/ static char *stack_path(struct list *stack, const char *sep) { size_t total = 1; @@ -102,14 +111,24 @@ static char *stack_path(struct list *stack, const char *sep) { return data; } +static void list_clear(struct list *list) { + struct node *node; + + while ((node = list_remhead(list))) { + if (debug_level > 2) + fprintf(stderr, " free: %s\n", node->name); + free(node); + } +} + // returns 0 if type has no size (i.e VOID_TYPE) static bool is_struct_or_union(const_tree type) { - return RECORD_TYPE == TREE_CODE(type) || UNION_TYPE == TREE_CODE(type); + return RECORD_TYPE == TREE_CODE(type) || UNION_TYPE == TREE_CODE(type); } static void print_spaces(int n) { - for (int i = 0; i < n; ++i) - fputc('\t', output_file); + for (int i = 0; i < n; ++i) + fputc('\t', output_file); } static int is_ref_type(tree type) { @@ -154,7 +173,7 @@ static const char *value_name(tree type) { /* Find a non-ref type in the type chain, i.e. skip pointers/arrays. - */ +*/ static tree simple_type(tree t) { while (is_ref_type(t)) t = TREE_TYPE(t); @@ -163,7 +182,7 @@ static tree simple_type(tree t) { /* Create a 'panama' signature for a single type. - */ +*/ static void export_desc(tree field, tree field_type, struct buffer *b) { const size_t data_size = value_size(TYPE_SIZE(field_type)); @@ -221,8 +240,123 @@ static void export_desc(tree field, tree field_type, struct buffer *b) { #else buffer_room(b, 16); b->pos += sprintf(b->data + b->pos, "%c%zu", - TYPE_UNSIGNED(field_type) ? 'u' : 'i', - data_size); + TYPE_UNSIGNED(field_type) ? 'u' : 'i', + data_size); +#endif + break; + case RECORD_TYPE: + case UNION_TYPE: + if (TYPE_IDENTIFIER(field_type)) { + list_add(&todump, node_alloc(field_type, NULL)); + + buffer_add(b, "${"); + buffer_add(b, value_name(field_type)); + buffer_add(b, "}"); + } else { + char *name = stack_path(&context_stack, "_"); + + list_add(&todump, node_alloc(field_type, name)); + + buffer_add(b, "${"); + buffer_add(b, name); + buffer_add(b, "}"); + + free(name); + } + break; + case REAL_TYPE: + buffer_room(b, 16); + b->pos += sprintf(b->data + b->pos, "f%zu", data_size); + break; + case INTEGER_TYPE: + buffer_room(b, 16); + b->pos += sprintf(b->data + b->pos, "%c%zu", + TYPE_UNSIGNED(field_type) ? 'u' : 'i', + data_size); + break; + default: + debug_tree_helper(field_type, "unknown type!"); + gcc_unreachable(); + break; + } +} + +/* + Create a 'c' description of type. +*/ +static void export_cdesc(tree field, tree field_type, struct buffer *b) { + const size_t data_size = value_size(TYPE_SIZE(field_type)); + + switch (TREE_CODE(field_type)) { + case VOID_TYPE: + buffer_add(b, "void"); + break; + case VECTOR_TYPE: + case ARRAY_TYPE: { + const size_t elem_size = tree_to_uhwi(TYPE_SIZE_UNIT(TREE_TYPE(field_type))); + size_t num_elem; + + if (elem_size == 0 || NULL == TYPE_SIZE_UNIT(field_type)) { + // it is a flexible array or empty types + num_elem = 0; + } else { + // it might be 0 / elem_size, in which case we also end up with num_elem = 0. + num_elem = tree_to_uhwi(TYPE_SIZE_UNIT(field_type)) / elem_size; + } + + export_cdesc(field, TREE_TYPE(field_type), b); + + buffer_room(b, 16); + buffer_add(b, "["); + if (num_elem) + b->pos += sprintf(b->data + b->pos, "%zu", num_elem); + buffer_add(b, "]"); + break; + } + case POINTER_TYPE: + case REFERENCE_TYPE: + buffer_room(b, 16); + buffer_add(b, "*"); + //b->pos += sprintf(b->data + b->pos, "u%zu:", data_size); + export_cdesc(field, TREE_TYPE(field_type), b); + break; + case FUNCTION_TYPE: { + // TODO: handle void f() type -> null TYPE_ARG_TYPES() + tree return_type = TREE_TYPE(field_type); + int args = 0; + + export_cdesc(field, return_type, b); + + buffer_add(b, "(*)"); + buffer_add(b, "("); + for (tree param = TYPE_ARG_TYPES(field_type); param != NULL; param = TREE_CHAIN(param)) { + tree param_type = TREE_VALUE(param); + + // TREE_TYPE might? point to a type that a previous decl has also referenced + + if (args++) + buffer_add(b, ", "); + + if (TREE_CODE(param_type) == VOID_TYPE) { + buffer_add(b, "void"); + break; + } + + export_cdesc(param, param_type, b); + } + buffer_add(b, ")"); + break; + } + case ENUMERAL_TYPE: +#if defined(TYPED_ENUMS) + buffer_add(b, "${"); + buffer_add(b, TYPE_IDENTIFIER(field_type) ? value_name(field_type) : "enum"); + buffer_add(b, "}"); +#else + buffer_room(b, 16); + b->pos += sprintf(b->data + b->pos, "%c%zu", + TYPE_UNSIGNED(field_type) ? 'u' : 'i', + data_size); #endif break; case RECORD_TYPE: @@ -252,8 +386,8 @@ static void export_desc(tree field, tree field_type, struct buffer *b) { case INTEGER_TYPE: buffer_room(b, 16); b->pos += sprintf(b->data + b->pos, "%c%zu", - TYPE_UNSIGNED(field_type) ? 'u' : 'i', - data_size); + TYPE_UNSIGNED(field_type) ? 'u' : 'i', + data_size); break; default: debug_tree_helper(field_type, "unknown type!"); @@ -264,7 +398,7 @@ static void export_desc(tree field, tree field_type, struct buffer *b) { /* Print a single parameter or field. - */ +*/ static void export_param(tree field, tree field_type, size_t field_size) { switch (TREE_CODE(field_type)) { case VECTOR_TYPE: @@ -286,6 +420,7 @@ static void export_param(tree field, tree field_type, size_t field_size) { } case VOID_TYPE: fprintf(output_file, " type => 'void',"); + fprintf(output_file, " ctype => 'void',"); break; case ENUMERAL_TYPE: { #if defined(TYPED_ENUMS) @@ -294,24 +429,26 @@ static void export_param(tree field, tree field_type, size_t field_size) { #else fprintf(output_file, " type => '%c%zu',", TYPE_UNSIGNED(field_type) ? 'u' : 'i', field_size); #endif + fprintf(output_file, " ctype => 'enum %s',", value_name(field_type)); break; } case FUNCTION_TYPE: { - // If the function is a typedef we could use the name - // but it's a pain to find up the tree, so don't bother. - // Use the signature instead. This is what jextract appears to use. struct buffer b; + tree root_type = TREE_TYPE(field); - //char *name = stack_path(&context_stack); - //fprintf(output_file, " type => 'call:%s', ", name); - //free(name); + // If this is a typedef we might have a name for the type, otherwise it's a signature based name + if (root_type && TYPE_IDENTIFIER(root_type)) { + fprintf(output_file, " type => 'call:%s', ", value_name(root_type)); + } else { + fprintf(stderr, "save for later param type %p\n", field_type); + buffer_init(&b, 256); + export_desc(field, field_type, &b); + list_add(&todump, node_alloc(field_type, b.data)); + fprintf(output_file, " type => 'call:%s', ", b.data); + } buffer_init(&b, 256); - - export_desc(field, field_type, &b); - list_add(&todump, node_alloc(field_type, b.data)); - fprintf(output_file, " type => 'call:%s', ", b.data); - + export_cdesc(field, field_type, &b); free(b.data); break; @@ -345,7 +482,7 @@ static void export_param(tree field, tree field_type, size_t field_size) { break; } default: - printf("unknown param type: %s\n", ZTREE_CODE(field_type)); + fprintf(stderr, "unknown param type: %s\n", ZTREE_CODE(field_type)); gcc_unreachable(); } } @@ -353,14 +490,42 @@ static void export_param(tree field, tree field_type, size_t field_size) { /* Export a chain of parameters */ -static void export_params(tree first_param, size_t indent_level) { +static void export_params(tree func) { int id = 0; - char nameb[16]; - const char *names = nameb; + char nameb[32]; + struct list args = { 0 }; + struct node *name; + struct node *fwd = hash_lookup_bytype(&forward_types, func); + + if (fwd) { + // use the forward reference to find the names + fprintf(stderr, "found forward reference @ %p\n", fwd); + name = fwd->list.head; + } else { + // paramter names are in the paramters list + // but they are in reverse order + int id = 0; + for (tree param = TYPE_ARG_TYPES(func); param; param = TREE_CHAIN(param)) { + tree param_type = TREE_VALUE(param); + + if (!TREE_CHAIN(param) && TREE_CODE(param_type) == VOID_TYPE) + break; + + struct node *decl = stack_pull(¶meters); + if (decl) { + fprintf(stderr, "(pull parameter '%s')\n", decl->name); + stack_push(&args, decl); + } else + fprintf(stderr, "ERROR: parameter %d missing parameter declaration\n", id); + id++; + } + name = args.head; + } - for (tree param = first_param; param; param = TREE_CHAIN(param)) { + for (tree param = TYPE_ARG_TYPES(func); param; param = TREE_CHAIN(param)) { tree param_type = TREE_VALUE(param); const size_t data_size = value_size(TYPE_SIZE(param_type)); + const char *names = NULL; // non-varags functions end in VOID_TYPE if (!TREE_CHAIN(param) && TREE_CODE(param_type) == VOID_TYPE) @@ -371,8 +536,18 @@ static void export_params(tree first_param, size_t indent_level) { // size: do we need it? fprintf(output_file, " size => %zu,", data_size); - // name: none available, use position - sprintf(nameb, "arg_%d", id); + if (name) { + // this should be a parm_decl with an identifier of the name + names = name->name; + + // can one check it's a matching type? + name = name->next; + } + + if (!names || !names[0]) { + sprintf(nameb, "arg_%d", id); + names = nameb; + } fprintf(output_file, " name => '%s',", names); stack_push(&context_stack, node_alloc(param, names)); @@ -385,6 +560,8 @@ static void export_params(tree first_param, size_t indent_level) { fprintf(output_file, "},\n"); id++; } + + list_clear(&args); } /* @@ -405,7 +582,8 @@ static void export_fields(tree first_field, size_t base_offset, int indent) { } else { const char *names = IDENTIFIER_POINTER(DECL_NAME(field)); - printf(" name=%s\n", names); + if (debug_level > 1) + fprintf(stderr, " field: %s\n", names); print_spaces(indent+1); fprintf(output_file, "{ name => '%s', size => %zu, offset => %zu,", names, field_size, offset); stack_push(&context_stack, node_alloc(field, names)); @@ -428,7 +606,8 @@ static void export_type(tree type, const char *names) { tree deftype; tree target; - D(printf("export: %s %s\n", names, ZTREE_CODE(type))); + if (debug_level > 1) + fprintf(stderr, "export_type(%s, %s)\n", ZTREE_CODE(type), names); switch (TREE_CODE(type)) { case TYPE_DECL: { @@ -442,13 +621,16 @@ static void export_type(tree type, const char *names) { return; hash_put(&dumped, node_alloc(type, names)); + if (debug_level > 1) + fprintf(stderr, "export: %s %s\n", names, ZTREE_CODE(type)); + deftype = TREE_TYPE(type); target = target_type(deftype); switch (TREE_CODE(target)) { case FUNCTION_TYPE: { + // function pointer typdef // I don't know if i even want this - - fprintf(output_file, "'call:%s' => { name => '%s',", names, names); + fprintf(output_file, "'call:%s' => { name => '%s', type => 'call',", names, names); // the deftype is always a pointer for a function_type @@ -459,6 +641,8 @@ static void export_type(tree type, const char *names) { fprintf(output_file, " deref => '%s',", b.data); free(b.data); + fprintf(output_file, " ctype => '%s',", print_generic_expr_to_str(target)); + // TODO: cleanup { tree result_type = TREE_TYPE(target); @@ -470,16 +654,10 @@ static void export_type(tree type, const char *names) { } fprintf(output_file, "\n\targuments => [\n"); - export_params(TYPE_ARG_TYPES(target), 0); + export_params(target); fprintf(output_file, "]},\n"); break; } - case RECORD_TYPE: - printf(" typedef record: %s\n", names); - break; - case UNION_TYPE: - printf(" typedef union: %s\n", names); - break; case ENUMERAL_TYPE: { // TODO: typedef of anonymous enumerations may be repeated // TODO: this could be detected in the frontend - e.g. don't include any @@ -503,12 +681,16 @@ static void export_type(tree type, const char *names) { fprintf(output_file, "]},\n"); break; } + case RECORD_TYPE: // forward declaration or opaque types + case UNION_TYPE: case VOID_TYPE: case INTEGER_TYPE: case REAL_TYPE: + if (debug_level) + fprintf(stderr, "ignored %s: %s\n", ZTREE_CODE(target), names); break; default: - printf("unknown type def: %s\n", ZTREE_CODE(target)); + fprintf(stderr, "unknown type def: %s\n", ZTREE_CODE(target)); gcc_unreachable(); } @@ -524,13 +706,17 @@ static void export_type(tree type, const char *names) { if (hash_lookup(&dumped, names)) return; hash_put(&dumped, node_alloc(type, names)); - printf("export type func decl %s\n", names); + + if (debug_level > 1) + fprintf(stderr, "export type func decl %s\n", names); fprintf(output_file, "'func:%s' => { name => '%s', type => 'func',", names, names); // FUNCTION_DECL -> FUNCTION_TYPE -> RESULT_TYPE, get FUNCTION_TYPE type = TREE_TYPE(type); + fprintf(output_file, " ctype => '%s',", print_generic_expr_to_str(type)); + // TODO: cleanup debug_tree_helper(type, "function 1"); { @@ -544,11 +730,13 @@ static void export_type(tree type, const char *names) { fprintf(output_file, "\n\targuments => [\n"); //export_decl_params(DECL_ARGUMENTS(type), 0); - export_params(TYPE_ARG_TYPES(type), 0); + export_params(type); fprintf(output_file, "]},\n"); break; } case FUNCTION_TYPE: { + // This is called for un-typedef'd function pointers. + // WHY IS THIS DIFFERENT TO ABOVE? if (!names) { name = TYPE_IDENTIFIER(type); if (!name) @@ -558,9 +746,12 @@ static void export_type(tree type, const char *names) { if (hash_lookup(&dumped, names)) return; hash_put(&dumped, node_alloc(type, names)); - printf("export type func %s\n", names); + + if (debug_level > 1) + fprintf(stderr, "export: %s %s\n", names, ZTREE_CODE(type)); fprintf(output_file, "'call:%s' => { name => '%s', type => 'call',", names, names); + fprintf(output_file, " ctype => '%s',", print_generic_expr_to_str(type)); debug_tree_helper(type, "function type"); @@ -572,7 +763,8 @@ static void export_type(tree type, const char *names) { //printf(" result type type %s\n", ZTREE_CODE(result_type)); const size_t data_size = value_size(TYPE_SIZE(result)); - printf(" result size %zu\n", data_size); + if (debug_level > 2) + fprintf(stderr, " result size %zu\n", data_size); fprintf(output_file, "\n\tresult => {"); export_param(type, result, data_size); fprintf(output_file, " },"); @@ -580,7 +772,7 @@ static void export_type(tree type, const char *names) { stack_push(&context_stack, node_alloc(type, names)); fprintf(output_file, "\n\targuments => [\n"); - export_params(TYPE_ARG_TYPES(type), 0); + export_params(type); free(stack_pull(&context_stack)); fprintf(output_file, "]},\n"); break; @@ -603,6 +795,9 @@ static void export_type(tree type, const char *names) { return; hash_put(&dumped, node_alloc(type, names)); + if (debug_level > 1) + fprintf(stderr, "export: %s %s\n", names, ZTREE_CODE(type)); + fprintf(output_file, "'%s:%s' => { name => '%s', type => '%s', size => %zu, fields => [\n", su, names, names, su, tree_to_uhwi(TYPE_SIZE(type))); @@ -647,6 +842,10 @@ static void export_type(tree type, const char *names) { sprintf(nameb, "enum$%d", namei++); names = nameb; } + + if (debug_level > 1) + fprintf(stderr, "export: %s %s\n", names, ZTREE_CODE(type)); + fprintf(output_file, "'enum:%s' => { name => '%s', type => 'enum', size => %zu, value_type => '%c%zu', values => [\n", names, names, size, TYPE_UNSIGNED(type) ? 'u' : 'i', size); @@ -659,14 +858,56 @@ static void export_type(tree type, const char *names) { break; } case FIELD_DECL: - case PARM_DECL: break; + case PARM_DECL: { + // capture PARM_DECLs so they can be used at next function declaration + if (!names) { + name = DECL_NAME(type); + if (name) + names = IDENTIFIER_POINTER(name); + } + // if this is a function pointer typedef, need to suck out the arguments at this point + deftype = TREE_TYPE(type); + + target = target_type(deftype); + + //fprintf(stderr, "type is '%s\n", ZTREE_CODE(deftype)); + //fprintf(stderr, "target is '%s\n", ZTREE_CODE(target)); + + if (TREE_CODE(target) == FUNCTION_TYPE) { + // We need to save the list of parameters for later, + // it's keyed on target + struct node *fwd = node_alloc(target, NULL); + + fprintf(stderr, "save forward reference function type %p\n", target); + + for (tree param = TYPE_ARG_TYPES(target); param != NULL; param = TREE_CHAIN(param)) { + tree param_type = TREE_VALUE(param); + + if (TREE_CODE(param_type) == VOID_TYPE) + break; + + struct node *decl = stack_pull(¶meters); + if (decl) { + fprintf(stderr, "(pull parameter '%s')\n", decl->name); + stack_push(&fwd->list, decl); + } else + fprintf(stderr, " missing parameter name\n"); + } + + hash_put_bytype(&forward_types, fwd); + } + + fprintf(stderr, "(push parameter '%s')\n", names); + stack_push(¶meters, node_alloc(type, names)); + + break; } case VAR_DECL: // global external variables, might want these // well, if there's a way to resolve them break; default: - printf("unknown export: %s\n", ZTREE_CODE(type)); + fprintf(stderr, "unknown export: %s\n", ZTREE_CODE(type)); gcc_unreachable(); } } @@ -674,16 +915,27 @@ static void export_type(tree type, const char *names) { static void plugin_finish_type(void *event_data, void *user_data) { tree type = (tree)event_data; + if (debug_level > 0) + fprintf(stderr, "finish_type\n"); + if (debug_level > 1) + debug_tree(type); + export_type(type, NULL); } static void plugin_finish_decl(void *event_data, void *user_data) { tree type = (tree)event_data; + if (debug_level > 0) + fprintf(stderr, "finish_decl %s\n", ZTREE_CODE(type)); + if (debug_level > 1) + debug_tree(type); + export_type(type, NULL); } static void plugin_finish(void *event_data, void *user_data) { + fprintf(stderr, "plugin finish\n"); for (struct node *n = todump.head; n; n=n->next) { if (COMPLETE_TYPE_P(n->type)) { if (n->name[0]) { @@ -699,34 +951,39 @@ static void plugin_finish(void *event_data, void *user_data) { fprintf(output_file, "# %s\n", n->name); fprintf(output_file, ");\n"); - //fclose(output_file); + fclose(output_file); + + fprintf(stderr, "unhandled paramters:\n"); + list_clear(¶meters); } int plugin_init(struct plugin_name_args *plugin_info, struct plugin_gcc_version *version) { - const char *output = NULL; + const char *output = NULL; - for (int i = 0; i < plugin_info->argc; ++i) { - if (0 == strcmp(plugin_info->argv[i].key, "output")) { - output = plugin_info->argv[i].value; - } - } + for (int i = 0; i < plugin_info->argc; ++i) { + if (0 == strcmp(plugin_info->argv[i].key, "output")) { + output = plugin_info->argv[i].value; + } else if (0 == strcmp(plugin_info->argv[i].key, "debug")) { + debug_level = atoi(plugin_info->argv[i].value); + } + } - if (NULL == output) { - fprintf(stderr, "export plugin: missing parameter: -fplugin-arg-export-output=\n"); - exit(EXIT_FAILURE); - } + if (NULL == output) { + fprintf(stderr, "export plugin: missing parameter: -fplugin-arg-export-output=\n"); + exit(EXIT_FAILURE); + } - output_file = fopen(output, "w"); - if (NULL == output_file) { - perror(output); - exit(EXIT_FAILURE); - } + output_file = fopen(output, "w"); + if (NULL == output_file) { + perror(output); + exit(EXIT_FAILURE); + } - fprintf(output_file, "%%data = (\n"); + fprintf(output_file, "%%data = (\n"); - register_callback(plugin_info->base_name, PLUGIN_FINISH_DECL, plugin_finish_decl, NULL); - register_callback(plugin_info->base_name, PLUGIN_FINISH_TYPE, plugin_finish_type, NULL); - register_callback(plugin_info->base_name, PLUGIN_FINISH, plugin_finish, NULL); + register_callback(plugin_info->base_name, PLUGIN_FINISH_DECL, plugin_finish_decl, NULL); + register_callback(plugin_info->base_name, PLUGIN_FINISH_TYPE, plugin_finish_type, NULL); + register_callback(plugin_info->base_name, PLUGIN_FINISH, plugin_finish, NULL); - return 0; + return 0; } diff --git a/src/list.h b/src/list.h index 33afef7..0ba636f 100644 --- a/src/list.h +++ b/src/list.h @@ -20,20 +20,27 @@ /* ********************************************************************** * a simple ordered hash/list/stack */ + +struct node; + +struct list { + struct node *head; + struct node *tail; +}; + struct node { // list/stack next struct node *next; // hash chain link/stack prev struct node *link; + // metadata + struct list list; + // payload tree type; - char name[]; -}; -struct list { - struct node *head; - struct node *tail; + char name[]; }; struct hash { @@ -47,6 +54,9 @@ static struct node *node_alloc(tree type, const char *name) { n->next = NULL; n->link = NULL; n->type = type; + n->list.head = NULL; + n->list.tail = NULL; + if (name) strcpy(n->name, name); else @@ -61,6 +71,7 @@ static void stack_push(struct list *stack, struct node *node) { node->next = stack->head; stack->head = node; } else { + node->next = NULL; stack->head = node; stack->tail = node; } @@ -91,6 +102,7 @@ static unsigned int ez_hash_string(const char *s) { } static void list_add(struct list *list, struct node *node) { + node->next = NULL; if (list->head) { list->tail->next = node; list->tail = node; @@ -100,6 +112,15 @@ static void list_add(struct list *list, struct node *node) { } } +static struct node *list_remhead(struct list *list) { + struct node *node = list->head; + + if (node && (list->head = node->next) == NULL) + list->tail = NULL; + + return node; +} + static void hash_put(struct hash *hash, struct node *node) { int code = ez_hash_string(node->name) & 63; @@ -120,6 +141,26 @@ struct node *hash_lookup(struct hash *hash, const char *name) { return NULL; } +static void hash_put_bytype(struct hash *hash, struct node *node) { + int code = (int)((uintptr_t)node->type >> 5) & 63; + + list_add(&hash->list, node); + + node->link = hash->table[code]; + hash->table[code] = node; +} + +struct node *hash_lookup_bytype(struct hash *hash, tree type) { + int code = (int)((uintptr_t)type >> 5) & 63; + + for (struct node *n = hash->table[code]; n; n=n->link) { + if (n->type == type) + return n; + } + + return NULL; +} + /* simple growable c buffer */ struct buffer { size_t size; diff --git a/src/tree-codes.c b/src/tree-codes.c new file mode 100644 index 0000000..ca6f237 --- /dev/null +++ b/src/tree-codes.c @@ -0,0 +1,10 @@ +/* + This builds a tree-code to name table, they are indexed + by position. + TODO: Not sure if there is some debug function to get them directly. + */ +#define END_OF_BASE_TREE_CODES "last_and_unused_tree_code" +#define DEFTREECODE(a, b, c, d) b, +const char *tree_codes[] = { +#include +}; diff --git a/src/tree-codes.h b/src/tree-codes.h deleted file mode 100644 index 4b2cdf2..0000000 --- a/src/tree-codes.h +++ /dev/null @@ -1,374 +0,0 @@ -/* -Taken from gcc plugin/tree.defs - -GCC is free software; you can redistribute it and/or modify it under -the terms of the GNU General Public License as published by the Free -Software Foundation; either version 3, or (at your option) any later -version. - -GCC is distributed in the hope that it will be useful, but WITHOUT ANY -WARRANTY; without even the implied warranty of MERCHANTABILITY or -FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -for more details. - -You should have received a copy of the GNU General Public License -along with GCC; see the file COPYING3. If not see -. */ - -const char *tree_codes[] = { - "ERROR_MARK", -"IDENTIFIER_NODE", -"TREE_LIST", -"TREE_VEC", -"BLOCK", -"OFFSET_TYPE", -"ENUMERAL_TYPE", -"BOOLEAN_TYPE", -"INTEGER_TYPE", -"REAL_TYPE", -"POINTER_TYPE", -"REFERENCE_TYPE", -"NULLPTR_TYPE", -"FIXED_POINT_TYPE", -"COMPLEX_TYPE", -"VECTOR_TYPE", -"ARRAY_TYPE", -"RECORD_TYPE", -"UNION_TYPE", -"QUAL_UNION_TYPE", -"VOID_TYPE", -"FUNCTION_TYPE", -"METHOD_TYPE", -"LANG_TYPE", -"VOID_CST", -"INTEGER_CST", -"POLY_INT_CST", -"REAL_CST", -"FIXED_CST", -"COMPLEX_CST", -"VECTOR_CST", -"STRING_CST", -"FUNCTION_DECL", -"LABEL_DECL", -"FIELD_DECL", -"VAR_DECL", -"CONST_DECL", -"PARM_DECL", -"TYPE_DECL", -"RESULT_DECL", -"DEBUG_EXPR_DECL", -"DEBUG_BEGIN_STMT", -"NAMESPACE_DECL", -"IMPORTED_DECL", -"NAMELIST_DECL", -"TRANSLATION_UNIT_DECL", -"COMPONENT_REF", -"BIT_FIELD_REF", -"ARRAY_REF", -"ARRAY_RANGE_REF", -"REALPART_EXPR", -"IMAGPART_EXPR", -"VIEW_CONVERT_EXPR", -"INDIRECT_REF", -"OBJ_TYPE_REF", -"CONSTRUCTOR", -"COMPOUND_EXPR", -"MODIFY_EXPR", -"INIT_EXPR", -"TARGET_EXPR", -"COND_EXPR", -"VEC_DUPLICATE_EXPR", -"VEC_SERIES_EXPR", -"VEC_COND_EXPR", -"VEC_PERM_EXPR", -"BIND_EXPR", -"CALL_EXPR", -"WITH_CLEANUP_EXPR", -"CLEANUP_POINT_EXPR", -"PLACEHOLDER_EXPR", -"PLUS_EXPR", -"MINUS_EXPR", -"MULT_EXPR", -"POINTER_PLUS_EXPR", -"POINTER_DIFF_EXPR", -"MULT_HIGHPART_EXPR", -"TRUNC_DIV_EXPR", -"CEIL_DIV_EXPR", -"FLOOR_DIV_EXPR", -"ROUND_DIV_EXPR", -"TRUNC_MOD_EXPR", -"CEIL_MOD_EXPR", -"FLOOR_MOD_EXPR", -"ROUND_MOD_EXPR", -"RDIV_EXPR", -"EXACT_DIV_EXPR", -"FIX_TRUNC_EXPR", -"FLOAT_EXPR", -"NEGATE_EXPR", -"MIN_EXPR", -"MAX_EXPR", -"ABS_EXPR", -"ABSU_EXPR", -"LSHIFT_EXPR", -"RSHIFT_EXPR", -"LROTATE_EXPR", -"RROTATE_EXPR", -"BIT_IOR_EXPR", -"BIT_XOR_EXPR", -"BIT_AND_EXPR", -"BIT_NOT_EXPR", -"TRUTH_ANDIF_EXPR", -"TRUTH_ORIF_EXPR", -"TRUTH_AND_EXPR", -"TRUTH_OR_EXPR", -"TRUTH_XOR_EXPR", -"TRUTH_NOT_EXPR", -"LT_EXPR", -"LE_EXPR", -"GT_EXPR", -"GE_EXPR", -"EQ_EXPR", -"NE_EXPR", -"UNORDERED_EXPR", -"ORDERED_EXPR", -"UNLT_EXPR", -"UNLE_EXPR", -"UNGT_EXPR", -"UNGE_EXPR", -"UNEQ_EXPR", -"LTGT_EXPR", -"RANGE_EXPR", -"PAREN_EXPR", -"CONVERT_EXPR", -"ADDR_SPACE_CONVERT_EXPR", -"FIXED_CONVERT_EXPR", -"NOP_EXPR", -"NON_LVALUE_EXPR", -"COMPOUND_LITERAL_EXPR", -"SAVE_EXPR", -"ADDR_EXPR", -"FDESC_EXPR", -"BIT_INSERT_EXPR", -"COMPLEX_EXPR", -"CONJ_EXPR", -"PREDECREMENT_EXPR", -"PREINCREMENT_EXPR", -"POSTDECREMENT_EXPR", -"POSTINCREMENT_EXPR", -"VA_ARG_EXPR", -"TRY_CATCH_EXPR", -"TRY_FINALLY_EXPR", -"DECL_EXPR", -"LABEL_EXPR", -"GOTO_EXPR", -"RETURN_EXPR", -"EXIT_EXPR", -"LOOP_EXPR", -"SWITCH_EXPR", -"CASE_LABEL_EXPR", -"ASM_EXPR", -"SSA_NAME", -"CATCH_EXPR", -"EH_FILTER_EXPR", -"SCEV_KNOWN", -"SCEV_NOT_KNOWN", -"POLYNOMIAL_CHREC", -"STATEMENT_LIST", -"ASSERT_EXPR", -"TREE_BINFO", -"WITH_SIZE_EXPR", -"REALIGN_LOAD_EXPR", -"TARGET_MEM_REF", -"MEM_REF", -"OACC_PARALLEL", -"OACC_KERNELS", -"OACC_DATA", -"OACC_HOST_DATA", -"OMP_PARALLEL", -"OMP_TASK", -"OMP_FOR", -"OMP_SIMD", -"OMP_DISTRIBUTE", -"OMP_TASKLOOP", -"OACC_LOOP", -"OMP_TEAMS", -"OMP_TARGET_DATA", -"OMP_TARGET", -"OMP_SECTIONS", -"OMP_ORDERED", -"OMP_CRITICAL", -"OMP_SINGLE", -"OMP_TASKGROUP", -"OMP_SECTION", -"OMP_MASTER", -"OACC_CACHE", -"OACC_DECLARE", -"OACC_ENTER_DATA", -"OACC_EXIT_DATA", -"OACC_UPDATE", -"OMP_TARGET_UPDATE", -"OMP_TARGET_ENTER_DATA", -"OMP_TARGET_EXIT_DATA", -"OMP_ATOMIC", -"OMP_ATOMIC_READ", -"OMP_ATOMIC_CAPTURE_OLD", -"OMP_ATOMIC_CAPTURE_NEW", -"OMP_CLAUSE", -"TRANSACTION_EXPR", -"DOT_PROD_EXPR", -"WIDEN_SUM_EXPR", -"SAD_EXPR", -"WIDEN_MULT_EXPR", -"WIDEN_MULT_PLUS_EXPR", -"WIDEN_MULT_MINUS_EXPR", -"WIDEN_LSHIFT_EXPR", -"VEC_WIDEN_MULT_HI_EXPR", -"VEC_WIDEN_MULT_LO_EXPR", -"VEC_WIDEN_MULT_EVEN_EXPR", -"VEC_WIDEN_MULT_ODD_EXPR", -"VEC_UNPACK_HI_EXPR", -"VEC_UNPACK_LO_EXPR", -"VEC_UNPACK_FLOAT_HI_EXPR", -"VEC_UNPACK_FLOAT_LO_EXPR", -"VEC_UNPACK_FIX_TRUNC_HI_EXPR", -"VEC_UNPACK_FIX_TRUNC_LO_EXPR", -"VEC_PACK_TRUNC_EXPR", -"VEC_PACK_SAT_EXPR", -"VEC_PACK_FIX_TRUNC_EXPR", -"VEC_PACK_FLOAT_EXPR", -"VEC_WIDEN_LSHIFT_HI_EXPR", -"VEC_WIDEN_LSHIFT_LO_EXPR", -"PREDICT_EXPR", -"OPTIMIZATION_NODE", -"TARGET_OPTION_NODE", -"ANNOTATE_EXPR", -"LAST_AND_UNUSED_TREE_CODE", -"C_MAYBE_CONST_EXPR", -"EXCESS_PRECISION_EXPR", -"USERDEF_LITERAL", -"SIZEOF_EXPR", -"UNCONSTRAINED_ARRAY_TYPE", -"UNCONSTRAINED_ARRAY_REF", -"NULL_EXPR", -"PLUS_NOMOD_EXPR", -"MINUS_NOMOD_EXPR", -"POWER_EXPR", -"ATTR_ADDR_EXPR", -"STMT_STMT", -"LOOP_STMT", -"EXIT_STMT", -"OFFSET_REF", -"PTRMEM_CST", -"NEW_EXPR", -"VEC_NEW_EXPR", -"DELETE_EXPR", -"VEC_DELETE_EXPR", -"SCOPE_REF", -"MEMBER_REF", -"TYPE_EXPR", -"AGGR_INIT_EXPR", -"VEC_INIT_EXPR", -"THROW_EXPR", -"EMPTY_CLASS_EXPR", -"BASELINK", -"TEMPLATE_DECL", -"TEMPLATE_PARM_INDEX", -"TEMPLATE_TEMPLATE_PARM", -"TEMPLATE_TYPE_PARM", -"TYPENAME_TYPE", -"TYPEOF_TYPE", -"BOUND_TEMPLATE_TEMPLATE_PARM", -"UNBOUND_CLASS_TEMPLATE", -"USING_DECL", -"USING_STMT", -"DEFAULT_ARG", -"DEFERRED_NOEXCEPT", -"TEMPLATE_ID_EXPR", -"OVERLOAD", -"PSEUDO_DTOR_EXPR", -"MODOP_EXPR", -"CAST_EXPR", -"REINTERPRET_CAST_EXPR", -"CONST_CAST_EXPR", -"STATIC_CAST_EXPR", -"DYNAMIC_CAST_EXPR", -"IMPLICIT_CONV_EXPR", -"DOTSTAR_EXPR", -"TYPEID_EXPR", -"NOEXCEPT_EXPR", -"NON_DEPENDENT_EXPR", -"CTOR_INITIALIZER", -"TRY_BLOCK", -"EH_SPEC_BLOCK", -"HANDLER", -"MUST_NOT_THROW_EXPR", -"CLEANUP_STMT", -"IF_STMT", -"FOR_STMT", -"RANGE_FOR_STMT", -"WHILE_STMT", -"DO_STMT", -"BREAK_STMT", -"CONTINUE_STMT", -"SWITCH_STMT", -"EXPR_STMT", -"TAG_DEFN", -"OFFSETOF_EXPR", -"ADDRESSOF_EXPR", -"ARROW_EXPR", -"ALIGNOF_EXPR", -"AT_ENCODE_EXPR", -"STMT_EXPR", -"UNARY_PLUS_EXPR", -"STATIC_ASSERT", -"TYPE_ARGUMENT_PACK", -"NONTYPE_ARGUMENT_PACK", -"TYPE_PACK_EXPANSION", -"EXPR_PACK_EXPANSION", -"ARGUMENT_PACK_SELECT", -"UNARY_LEFT_FOLD_EXPR", -"UNARY_RIGHT_FOLD_EXPR", -"BINARY_LEFT_FOLD_EXPR", -"BINARY_RIGHT_FOLD_EXPR", -"TRAIT_EXPR", -"LAMBDA_EXPR", -"DECLTYPE_TYPE", -"UNDERLYING_TYPE", -"BASES", -"TEMPLATE_INFO", -"OMP_DEPOBJ", -"CONSTRAINT_INFO", -"WILDCARD_DECL", -"REQUIRES_EXPR", -"SIMPLE_REQ", -"TYPE_REQ", -"COMPOUND_REQ", -"NESTED_REQ", -"PRED_CONSTR", -"CHECK_CONSTR", -"EXPR_CONSTR", -"TYPE_CONSTR", -"ICONV_CONSTR", -"DEDUCT_CONSTR", -"EXCEPT_CONSTR", -"PARM_CONSTR", -"CONJ_CONSTR", -"DISJ_CONSTR", -"UNSIGNED_RSHIFT_EXPR", -"FLOAT_MOD_EXPR", -"FUNCFRAME_INFO", -"CLASS_INTERFACE_TYPE", -"CLASS_IMPLEMENTATION_TYPE", -"CATEGORY_INTERFACE_TYPE", -"CATEGORY_IMPLEMENTATION_TYPE", -"PROTOCOL_INTERFACE_TYPE", -"KEYWORD_DECL", -"INSTANCE_METHOD_DECL", -"CLASS_METHOD_DECL", -"PROPERTY_DECL", -"MESSAGE_SEND_EXPR", -"CLASS_REFERENCE_EXPR", -"PROPERTY_REF", - }; - -#define ZTREE_CODE(x) tree_codes[TREE_CODE(x)]