libgccjit: Generate debug info for variables
authorPetter Tomner <tomner@kth.se>
Wed, 8 Sep 2021 22:50:06 +0000 (00:50 +0200)
committerPetter Tomner <tomner@kth.se>
Fri, 10 Sep 2021 23:00:48 +0000 (01:00 +0200)
Finalize declares via available helpers after location is set. Set
TYPE_NAME of primitives and friends to "int" etc. Debug info is now
set properly for variables.

Signed-off-by:
2021-09-09 Petter Tomner <tomner@kth.se>

gcc/jit/
* jit-playback.c: Moved global var processing to after loc handling.
  Setting TYPE_NAME for fundamental types.
  Using common functions for finalizing globals.
* jit-playback.h: New method init_types().
  Changed get_tree_node_for_type() to method.

gcc/testsuite/
* jit.dg/test-error-array-bounds.c: Array is not unsigned
* jit.dg/jit.exp: Helper function
* jit.dg/test-debuginfo.c: New testcase

gcc/jit/jit-playback.c
gcc/jit/jit-playback.h
gcc/testsuite/jit.dg/jit.exp
gcc/testsuite/jit.dg/test-debuginfo.c [new file with mode: 0644]
gcc/testsuite/jit.dg/test-error-array-bounds.c

index 79ac525..59399de 100644 (file)
@@ -165,7 +165,8 @@ gt_ggc_mx ()
 
 /* Given an enum gcc_jit_types value, get a "tree" type.  */
 
-static tree
+tree
+playback::context::
 get_tree_node_for_type (enum gcc_jit_types type_)
 {
   switch (type_)
@@ -192,11 +193,7 @@ get_tree_node_for_type (enum gcc_jit_types type_)
       return short_unsigned_type_node;
 
     case GCC_JIT_TYPE_CONST_CHAR_PTR:
-      {
-       tree const_char = build_qualified_type (char_type_node,
-                                               TYPE_QUAL_CONST);
-       return build_pointer_type (const_char);
-      }
+      return m_const_char_ptr;
 
     case GCC_JIT_TYPE_INT:
       return integer_type_node;
@@ -579,10 +576,6 @@ playback::lvalue *
 playback::context::
 global_finalize_lvalue (tree inner)
 {
-  varpool_node::get_create (inner);
-
-  varpool_node::finalize_decl (inner);
-
   m_globals.safe_push (inner);
 
   return new lvalue (this, inner);
@@ -2952,9 +2945,7 @@ replay ()
 {
   JIT_LOG_SCOPE (get_logger ());
 
-  m_const_char_ptr
-    = build_pointer_type (build_qualified_type (char_type_node,
-                                               TYPE_QUAL_CONST));
+  init_types ();
 
   /* Replay the recorded events:  */
   timevar_push (TV_JIT_REPLAY);
@@ -2984,10 +2975,17 @@ replay ()
     {
       int i;
       function *func;
-
+      tree global;
       /* No GC can happen yet; process the cached source locations.  */
       handle_locations ();
 
+      /* Finalize globals. See how FORTRAN 95 does it in gfc_be_parse_file()
+         for a simple reference. */
+      FOR_EACH_VEC_ELT (m_globals, i, global)
+        rest_of_decl_compilation (global, true, true);
+
+      wrapup_global_declarations (m_globals.address(), m_globals.length());
+
       /* We've now created tree nodes for the stmts in the various blocks
         in each function, but we haven't built each function's single stmt
         list yet.  Do so now.  */
@@ -3081,6 +3079,50 @@ location_comparator (const void *lhs, const void *rhs)
   return loc_lhs->get_column_num () - loc_rhs->get_column_num ();
 }
 
+/* Initialize the NAME_TYPE of the primitive types as well as some
+   others. */
+void
+playback::context::
+init_types ()
+{
+  /* See lto_init() in lto-lang.c or void visit (TypeBasic *t) in D's types.cc 
+     for reference. If TYPE_NAME is not set, debug info will not contain types */
+#define NAME_TYPE(t,n) \
+if (t) \
+  TYPE_NAME (t) = build_decl (UNKNOWN_LOCATION, TYPE_DECL, \
+                              get_identifier (n), t)
+
+  NAME_TYPE (integer_type_node, "int");
+  NAME_TYPE (char_type_node, "char");
+  NAME_TYPE (long_integer_type_node, "long int");
+  NAME_TYPE (unsigned_type_node, "unsigned int");
+  NAME_TYPE (long_unsigned_type_node, "long unsigned int");
+  NAME_TYPE (long_long_integer_type_node, "long long int");
+  NAME_TYPE (long_long_unsigned_type_node, "long long unsigned int");
+  NAME_TYPE (short_integer_type_node, "short int");
+  NAME_TYPE (short_unsigned_type_node, "short unsigned int");
+  if (signed_char_type_node != char_type_node)
+    NAME_TYPE (signed_char_type_node, "signed char");
+  if (unsigned_char_type_node != char_type_node)
+    NAME_TYPE (unsigned_char_type_node, "unsigned char");
+  NAME_TYPE (float_type_node, "float");
+  NAME_TYPE (double_type_node, "double");
+  NAME_TYPE (long_double_type_node, "long double");
+  NAME_TYPE (void_type_node, "void");
+  NAME_TYPE (boolean_type_node, "bool");
+  NAME_TYPE (complex_float_type_node, "complex float");
+  NAME_TYPE (complex_double_type_node, "complex double");
+  NAME_TYPE (complex_long_double_type_node, "complex long double");
+  
+  m_const_char_ptr = build_pointer_type(
+    build_qualified_type (char_type_node, TYPE_QUAL_CONST));
+
+  NAME_TYPE (m_const_char_ptr, "char");
+  NAME_TYPE (size_type_node, "size_t");
+  NAME_TYPE (fileptr_type_node, "FILE");
+#undef NAME_TYPE
+}
+
 /* Our API allows locations to be created in arbitrary orders, but the
    linemap API requires locations to be created in ascending order
    as if we were tokenizing files.
index 825a3e1..f670c9e 100644 (file)
@@ -271,8 +271,13 @@ private:
   source_file *
   get_source_file (const char *filename);
 
+  tree
+  get_tree_node_for_type (enum gcc_jit_types type_);
+
   void handle_locations ();
 
+  void init_types ();
+
   const char * get_path_c_file () const;
   const char * get_path_s_file () const;
   const char * get_path_so_file () const;
index 005ba01..4459dbc 100644 (file)
@@ -377,6 +377,34 @@ proc dg-jit-set-exe-params { args } {
     }
 }
 
+# For test-debuginfo.c. Starts gdb, does cmds and checks the output against match
+proc jit-check-debug-info { obj_file cmds match } {
+    verbose "Checking debug info for $obj_file with match: $match"
+
+    if { [catch {exec gdb -v} fid] } {
+        verbose "No gdb seems to be in path. Can't check debug info. Reporting 'unsupported'."
+        unsupported "No gdb seems to be in path. Can't check debug info"
+        return
+    }
+
+    spawn gdb $obj_file
+
+    verbose "Disable color styling in GDB newer then 8.3 (errors on older)"
+    send "set style enabled off\n"
+
+    foreach cmd $cmds {
+        send $cmd
+    }
+    expect {
+        -re $match { pass OK }
+        default { fail FAIL }
+    }
+
+    # Quit gdb
+    send "set confirm off\n"
+    send "q\n"
+}
+
 proc jit-dg-test { prog do_what extra_tool_flags } {
     verbose "within jit-dg-test..."
     verbose "  prog: $prog"
diff --git a/gcc/testsuite/jit.dg/test-debuginfo.c b/gcc/testsuite/jit.dg/test-debuginfo.c
new file mode 100644 (file)
index 0000000..49e8834
--- /dev/null
@@ -0,0 +1,72 @@
+/* Essentially this test checks that debug info are generated for globals
+   locals and functions, including type info. The comment bellow is used
+   as fake code (does not affect the test, use for manual debugging). */
+/*
+int a_global_for_test_debuginfo;
+int main (int argc, char **argv)
+{
+    int a_local_for_test_debuginfo = 2;
+    return a_global_for_test_debuginfo + a_local_for_test_debuginfo;
+}
+*/
+#include "libgccjit.h"
+
+/* We don't want set_options() in harness.h to set -O3 so our little local
+   is optimized away. */
+#define TEST_ESCHEWS_SET_OPTIONS
+static void set_options (gcc_jit_context *ctxt, const char *argv0)
+{
+    gcc_jit_context_set_bool_option(ctxt, GCC_JIT_BOOL_OPTION_DEBUGINFO, 1);
+}
+
+#define TEST_COMPILING_TO_FILE
+#define OUTPUT_KIND      GCC_JIT_OUTPUT_KIND_EXECUTABLE
+#define OUTPUT_FILENAME  "jit-debuginfo.o"
+#include "harness.h"
+
+#define LOC(row, col) gcc_jit_context_new_location(ctxt, "test-debuginfo.c", row, col)
+
+void
+create_code (gcc_jit_context *ctxt, void* p)
+{
+  gcc_jit_type *int_type = gcc_jit_context_get_type(ctxt, GCC_JIT_TYPE_INT);
+
+  gcc_jit_lvalue *bar = gcc_jit_context_new_global(ctxt, 
+    LOC(5,1), GCC_JIT_GLOBAL_EXPORTED, 
+    int_type, "a_global_for_test_debuginfo");
+
+  gcc_jit_param *argc_para = gcc_jit_context_new_param(ctxt, LOC(6,15), 
+    int_type, "argc");
+  gcc_jit_param *argv_para = gcc_jit_context_new_param(ctxt, LOC(6,28), 
+    gcc_jit_type_get_pointer(
+      gcc_jit_type_get_pointer(
+        gcc_jit_context_get_type(ctxt, GCC_JIT_TYPE_CHAR))),
+    "argc");
+
+  gcc_jit_param *params[] = {argc_para, argv_para};
+
+  gcc_jit_function *foo_fn = gcc_jit_context_new_function(ctxt, LOC(6,5), 
+    GCC_JIT_FUNCTION_EXPORTED, int_type, "main", 2, params, 0);
+  gcc_jit_block *start_block = gcc_jit_function_new_block(foo_fn, 
+    "start_block");
+
+  gcc_jit_lvalue *a = gcc_jit_function_new_local(foo_fn, LOC(8,5), 
+    int_type, "a_local_for_test_debuginfo");
+  gcc_jit_block_add_assignment(start_block, LOC(8,36), a, 
+    gcc_jit_context_new_rvalue_from_int(ctxt, int_type, 2));
+  gcc_jit_rvalue *add = gcc_jit_context_new_binary_op(ctxt, LOC(9,40), 
+    GCC_JIT_BINARY_OP_PLUS, int_type, 
+    gcc_jit_lvalue_as_rvalue(a), gcc_jit_lvalue_as_rvalue(bar));
+
+  gcc_jit_block_end_with_return(start_block, LOC(9,5), add);
+}
+
+#undef LOC
+
+/* jit-check-debug-info fires up gdb and checks that the variables have 
+   debug info */
+
+/*  { dg-final { jit-check-debug-info "jit-debuginfo.o" {"info variables\n"} "int\\s+a_global_for_test_debuginfo;" } } */
+/*  { dg-final { jit-check-debug-info "jit-debuginfo.o" {"pt main\n"} "int\\s*\\(\\s*int\\s*,\\s*char\\s*\\*\\*\\s*\\)"} } */
+/*  { dg-final { jit-check-debug-info "jit-debuginfo.o" {"start\n" "info locals\n"} "a_local_for_test_debuginfo"} } */
+/*  { dg-final { jit-check-debug-info "jit-debuginfo.o" {"start\n" "pt a_local_for_test_debuginfo\n"} "int"} } */
\ No newline at end of file
index cd9361f..b6c0ee5 100644 (file)
@@ -70,5 +70,5 @@ verify_code (gcc_jit_context *ctxt, gcc_jit_result *result)
   /* ...and that the message was captured by the API.  */
   CHECK_STRING_VALUE (gcc_jit_context_get_first_error (ctxt),
                      "array subscript 10 is above array bounds of"
-                     " 'unsigned char[10]' [-Warray-bounds]");
+                     " 'char[10]' [-Warray-bounds]");
 }