The following patch extends the generation of exception handling
information to cover volatile asms too.  This was already mostly
implemented, and only minor changes are required in order to make it
work.

The new test case works for me on x86_64-linux-gnu, but will likely
fail on most other platforms.

gcc/
2020-03-07  Jan W. Jagersma  <jwjager...@gmail.com>

        PR inline-asm/93981
        * tree-cfg.c (make_edges_bb): Make EH edges for GIMPLE_ASM.
        * tree-eh.c (lower_eh_constructs_2): Add case for GIMPLE_ASM.
        Assign register output operands to temporaries.
        * doc/extend.texi: Document that volatile asms can now throw.

gcc/testsuite/
2020-03-07  Jan W. Jagersma  <jwjager...@gmail.com>

        PR inline-asm/93981
        * g++.target/i386/pr93981.C: New test.
---
 gcc/doc/extend.texi                     |  5 ++++
 gcc/testsuite/g++.target/i386/pr93981.C | 28 ++++++++++++++++++++++
 gcc/tree-cfg.c                          |  2 ++
 gcc/tree-eh.c                           | 32 +++++++++++++++++++++++++
 4 files changed, 67 insertions(+)
 create mode 100644 gcc/testsuite/g++.target/i386/pr93981.C

diff --git a/gcc/doc/extend.texi b/gcc/doc/extend.texi
index 11b79a5852c..adcdd123011 100644
--- a/gcc/doc/extend.texi
+++ b/gcc/doc/extend.texi
@@ -9577,6 +9577,11 @@ errors during compilation if your @code{asm} code 
defines symbols or labels.
 Using @samp{%=} 
 (@pxref{AssemblerTemplate}) may help resolve this problem.
 
+When non-call exceptions (@option{-fnon-call-exceptions}) are enabled, a
+@code{volatile asm} statement is also allowed to throw exceptions.  If it
+does, then the compiler assumes that its output operands have not been written
+yet.
+
 @anchor{AssemblerTemplate}
 @subsubsection Assembler Template
 @cindex @code{asm} assembler template
diff --git a/gcc/testsuite/g++.target/i386/pr93981.C 
b/gcc/testsuite/g++.target/i386/pr93981.C
new file mode 100644
index 00000000000..ca444c5db3b
--- /dev/null
+++ b/gcc/testsuite/g++.target/i386/pr93981.C
@@ -0,0 +1,28 @@
+// PR inline-asm/93981
+// { dg-do run }
+// { dg-options "-fnon-call-exceptions" }
+
+#include <csignal>
+
+struct illegal_opcode { };
+
+extern "C" void
+sigill (int)
+{
+  throw illegal_opcode ( );
+}
+
+int
+main ()
+{
+  std::signal (SIGILL, sigill);
+  try
+    {
+      asm ("ud2");
+    }
+  catch (const illegal_opcode&)
+    {
+      return 0;
+    }
+  return 1;
+}
diff --git a/gcc/tree-cfg.c b/gcc/tree-cfg.c
index f7b817d94e6..c21a7978493 100644
--- a/gcc/tree-cfg.c
+++ b/gcc/tree-cfg.c
@@ -913,6 +913,8 @@ make_edges_bb (basic_block bb, struct omp_region 
**pcur_region, int *pomp_index)
       break;
 
     case GIMPLE_ASM:
+      if (stmt_can_throw_internal (cfun, last))
+       make_eh_edges (last);
       make_gimple_asm_edges (bb);
       fallthru = true;
       break;
diff --git a/gcc/tree-eh.c b/gcc/tree-eh.c
index 2a409dcaffe..cfdd0fdcf23 100644
--- a/gcc/tree-eh.c
+++ b/gcc/tree-eh.c
@@ -2077,6 +2077,8 @@ lower_eh_constructs_2 (struct leh_state *state, 
gimple_stmt_iterator *gsi)
            DECL_GIMPLE_REG_P (tmp) = 1;
          gsi_insert_after (gsi, s, GSI_SAME_STMT);
        }
+
+    record_throwing_stmt:
       /* Look for things that can throw exceptions, and record them.  */
       if (state->cur_region && stmt_could_throw_p (cfun, stmt))
        {
@@ -2085,6 +2087,36 @@ lower_eh_constructs_2 (struct leh_state *state, 
gimple_stmt_iterator *gsi)
        }
       break;
 
+    case GIMPLE_ASM:
+      {
+       /* As above with GIMPLE_ASSIGN.  Change each register output operand
+          to a temporary and insert a new stmt to assign this to the original
+          operand.  */
+       gasm *asm_stmt = as_a <gasm *> (stmt);
+       if (stmt_could_throw_p (cfun, stmt)
+           && gimple_asm_noutputs (asm_stmt) > 0
+           && gimple_stmt_may_fallthru (stmt))
+         {
+           for (unsigned i = 0; i < gimple_asm_noutputs (asm_stmt); ++i)
+             {
+               tree op = gimple_asm_output_op (asm_stmt, i);
+               tree opval = TREE_VALUE (op);
+               if (tree_could_throw_p (opval)
+                   || !is_gimple_reg_type (TREE_TYPE (opval))
+                   || !is_gimple_reg (get_base_address (opval)))
+                 continue;
+
+               tree tmp = create_tmp_reg (TREE_TYPE (opval));
+               gimple *s = gimple_build_assign (opval, tmp);
+               gimple_set_location (s, gimple_location (stmt));
+               gimple_set_block (s, gimple_block (stmt));
+               TREE_VALUE (op) = tmp;
+               gsi_insert_after (gsi, s, GSI_SAME_STMT);
+             }
+         }
+      }
+      goto record_throwing_stmt;
+
     case GIMPLE_COND:
     case GIMPLE_GOTO:
     case GIMPLE_RETURN:
-- 
2.25.1

Reply via email to