jit: use deep unsharing of trees [PR 95314]
authorDavid Malcolm <dmalcolm@redhat.com>
Wed, 27 May 2020 13:44:07 +0000 (09:44 -0400)
committerDavid Malcolm <dmalcolm@redhat.com>
Wed, 27 May 2020 18:26:08 +0000 (14:26 -0400)
PR jit/95314 reports a internal error inside verify_gimple, which
turned out to be due to reusing the result of
gcc_jit_lvalue_get_address in several functions, leading to tree nodes
shared between multiple function bodies.

This patch fixes the issue by adopting the "Deep unsharing" strategy
described in the comment in gimplify.c preceding mostly_copy_tree_r:
to mark all of the jit "frontend"'s expression tree nodes with
TREE_VISITED, and to set LANG_HOOKS_DEEP_UNSHARING, so that "they are
unshared on the first reference within functions when the regular
unsharing algorithm runs".

gcc/jit/ChangeLog:
PR jit/95314
* dummy-frontend.c (LANG_HOOKS_DEEP_UNSHARING): Define to be true.
* jit-playback.h (gcc::jit::playback::rvalue): Mark tree node with
TREE_VISITED.

gcc/testsuite/ChangeLog:
PR jit/95314
* jit.dg/all-non-failing-tests.h: Add test-pr95314-rvalue-reuse.c.
* jit.dg/test-pr95314-rvalue-reuse.c: New test.

gcc/jit/dummy-frontend.c
gcc/jit/jit-playback.h
gcc/testsuite/jit.dg/all-non-failing-tests.h
gcc/testsuite/jit.dg/test-pr95314-rvalue-reuse.c [new file with mode: 0644]

index 27fe9d3db9699568f20a44288efb913db1dcd630..6c7b7992a4d40b26ce3394fd83eab612cdfc6ae6 100644 (file)
@@ -269,6 +269,9 @@ jit_langhook_getdecls (void)
 #undef LANG_HOOKS_GETDECLS
 #define LANG_HOOKS_GETDECLS            jit_langhook_getdecls
 
+#undef  LANG_HOOKS_DEEP_UNSHARING
+#define LANG_HOOKS_DEEP_UNSHARING      true
+
 struct lang_hooks lang_hooks = LANG_HOOKS_INITIALIZER;
 
 #include "gt-jit-dummy-frontend.h"
index 074434a9f6b2637e290ed3425f28649602faa0b3..f9b3e675368c74b5deb3989629917eece15b7453 100644 (file)
@@ -576,7 +576,12 @@ public:
   rvalue (context *ctxt, tree inner)
     : m_ctxt (ctxt),
       m_inner (inner)
-  {}
+  {
+    /* Pre-mark tree nodes with TREE_VISITED so that they can be
+       deeply unshared during gimplification (including across
+       functions); this requires LANG_HOOKS_DEEP_UNSHARING to be true.  */
+    TREE_VISITED (inner) = 1;
+  }
 
   rvalue *
   as_rvalue () { return this; }
index babcd3979b751752bca6ddff9cfb15ef5b5b64f3..ca8d3df419373e24a9e9fc6b7d4f7f88dee3e41c 100644 (file)
 #undef create_code
 #undef verify_code
 
+/* test-pr95314-rvalue-reuse.c.  */
+#define create_code create_code_pr95314_rvalue_reuse
+#define verify_code verify_code_pr95314_rvalue_reuse
+#include "test-pr95314-rvalue-reuse.c"
+#undef create_code
+#undef verify_code
+
 /* test-reading-struct.c */
 #define create_code create_code_reading_struct
 #define verify_code verify_code_reading_struct
@@ -401,6 +408,9 @@ const struct testcase testcases[] = {
   {"pr95306_builtin_types",
    create_code_pr95306_builtin_types,
    verify_code_pr95306_builtin_types},
+  {"pr95314_rvalue_reuse",
+   create_code_pr95314_rvalue_reuse,
+   verify_code_pr95314_rvalue_reuse},
   {"reading_struct ",
    create_code_reading_struct ,
    verify_code_reading_struct },
diff --git a/gcc/testsuite/jit.dg/test-pr95314-rvalue-reuse.c b/gcc/testsuite/jit.dg/test-pr95314-rvalue-reuse.c
new file mode 100644 (file)
index 0000000..6bed0bc
--- /dev/null
@@ -0,0 +1,56 @@
+#include <libgccjit.h>
+#include "harness.h"
+
+void create_code (gcc_jit_context *ctxt, void *user_data)
+{
+  gcc_jit_type *t_int =  gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_INT);
+  gcc_jit_type *t_void = gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_VOID);
+  gcc_jit_type *t_const_char_ptr
+    = gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_CONST_CHAR_PTR);
+  gcc_jit_lvalue *global
+    = gcc_jit_context_new_global (ctxt, NULL, GCC_JIT_GLOBAL_INTERNAL,
+                                 t_const_char_ptr, "pr95314_global");
+
+  gcc_jit_rvalue *global_ref = gcc_jit_lvalue_get_address(global, NULL);
+
+  gcc_jit_param *param_string
+    = gcc_jit_context_new_param (ctxt, NULL, t_const_char_ptr, "string");
+  gcc_jit_function *puts_func
+    = gcc_jit_context_new_function (ctxt, NULL, GCC_JIT_FUNCTION_IMPORTED,
+                                   t_int, "puts", 1, &param_string, 0);
+
+#define NUM_INNER_FNS 3
+  gcc_jit_function *inner_fns[NUM_INNER_FNS];
+  for (int i = 0; i < NUM_INNER_FNS; i++)
+    {
+      char fnname[128];
+      sprintf (fnname, "pr95314_inner_%i", i);
+      inner_fns[i]
+       = gcc_jit_context_new_function (ctxt, NULL, GCC_JIT_FUNCTION_INTERNAL,
+                                       t_void, fnname, 0, NULL, 0);
+      gcc_jit_block *block = gcc_jit_function_new_block (inner_fns[i], NULL);
+      gcc_jit_rvalue *arg
+       = gcc_jit_context_new_cast (ctxt, NULL, global_ref, t_const_char_ptr);
+      gcc_jit_block_add_eval (block, NULL,
+                             gcc_jit_context_new_call (ctxt, NULL, puts_func,
+                                                       1, &arg));
+      gcc_jit_block_end_with_void_return (block, NULL);
+    }
+
+  gcc_jit_function *outer_func
+    = gcc_jit_context_new_function (ctxt, NULL, GCC_JIT_FUNCTION_EXPORTED,
+                                   t_void, "pr95314_outer", 0, NULL, 0);
+  gcc_jit_block *block = gcc_jit_function_new_block (outer_func, NULL);
+  for (int i = 0; i < NUM_INNER_FNS; i++)
+    gcc_jit_block_add_eval (block, NULL,
+                           gcc_jit_context_new_call (ctxt, NULL, inner_fns[i],
+                                                     0, NULL));
+  gcc_jit_block_end_with_void_return (block, NULL);
+}
+
+void
+verify_code (gcc_jit_context *ctxt, gcc_jit_result *result)
+{
+  CHECK_NON_NULL (result);
+  (void)gcc_jit_result_get_code (result, "pr95314_outer");
+}