Extract more symbolic information from the tree.
authorNot Zed <notzed@gmail.com>
Mon, 20 Dec 2021 22:24:16 +0000 (08:54 +1030)
committerNot Zed <notzed@gmail.com>
Mon, 20 Dec 2021 22:24:16 +0000 (08:54 +1030)
 - names of typedef function pointers
 - argument names in functions and function prototypes.

src/Makefile
src/export.cc
src/list.h
src/tree-codes.c [new file with mode: 0644]
src/tree-codes.h [deleted file]

index 7b8fdb6..ebab9dc 100644 (file)
@@ -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
index ed19501..17d4dad 100644 (file)
@@ -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 <gcc-plugin.h>
 #include <tree.h>
 #include <print-tree.h>
+#include <tree-pretty-print.h>
 
-#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(&parameters);
+                       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(&parameters);
+                               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(&parameters, 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(&parameters);
 }
 
 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=<output>\n");
-        exit(EXIT_FAILURE);
-    }
+       if (NULL == output) {
+               fprintf(stderr, "export plugin: missing parameter: -fplugin-arg-export-output=<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;
 }
index 33afef7..0ba636f 100644 (file)
 /* **********************************************************************
  * 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 (file)
index 0000000..ca6f237
--- /dev/null
@@ -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 <all-tree.def>
+};
diff --git a/src/tree-codes.h b/src/tree-codes.h
deleted file mode 100644 (file)
index 4b2cdf2..0000000
+++ /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
-<http://www.gnu.org/licenses/>.  */
-
-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)]