The following patch extends the generation of exception handling
information, so that it is possible to catch exceptions thrown from
volatile asm statements, when -fnon-call-exceptions is enabled.  Parts
of the gcc code already suggested this should be possible, but it was
never fully implemented.

Two new test cases are added.  The target-dependent test should pass on
platforms where throwing from a signal handler is allowed.  The only
platform I am aware of where that is the case is *-linux-gnu, so it is
set to XFAIL on all others.

gcc/
2020-03-11  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-11  Jan W. Jagersma  <jwjager...@gmail.com>

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

diff --git a/gcc/doc/extend.texi b/gcc/doc/extend.texi
index e0e7f540c21..b51e34c617a 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 its register output operands are assumed to be clobbered and will not be
+used.  Memory operands, however, are always considered valid.
+
 @anchor{AssemblerTemplate}
 @subsubsection Assembler Template
 @cindex @code{asm} assembler template
diff --git a/gcc/testsuite/g++.dg/eh/pr93981.C 
b/gcc/testsuite/g++.dg/eh/pr93981.C
new file mode 100644
index 00000000000..a9adb5c069e
--- /dev/null
+++ b/gcc/testsuite/g++.dg/eh/pr93981.C
@@ -0,0 +1,18 @@
+// PR inline-asm/93981
+// { dg-do compile }
+// { dg-options "-fnon-call-exceptions" }
+
+void
+f ()
+{
+  try
+    {
+      asm ("#try");
+    }
+  catch (...)
+    {
+      asm ("#catch");
+    }
+}
+
+// { dg-final { scan-assembler "#catch" } }
diff --git a/gcc/testsuite/g++.target/i386/pr93981.C 
b/gcc/testsuite/g++.target/i386/pr93981.C
new file mode 100644
index 00000000000..7a3117901f9
--- /dev/null
+++ b/gcc/testsuite/g++.target/i386/pr93981.C
@@ -0,0 +1,55 @@
+// PR inline-asm/93981
+// { dg-do run }
+// { dg-options "-fnon-call-exceptions -O3" }
+// { dg-xfail-if "" { ! *-linux-gnu } }
+// { dg-xfail-run-if "" { ! *-linux-gnu } }
+
+#include <signal.h>
+
+struct illegal_opcode { };
+
+extern "C" void
+sigill (int)
+{
+  throw illegal_opcode ( );
+}
+
+int
+test_mem ()
+{
+  int i = 2;
+  try
+    {
+      asm volatile ("mov%z0 $1, %0; ud2" : "=m" (i));
+    }
+  catch (const illegal_opcode&)
+    {
+      if (i == 1) return 0;
+    }
+  return i;
+}
+
+int
+test_reg ()
+{
+  int i = 8;
+  try
+    {
+      asm volatile ("mov%z0 $4, %0; ud2" : "=r" (i));
+    }
+  catch (const illegal_opcode&)
+    {
+      if (i == 8) return 0;
+    }
+  return i;
+}
+
+int
+main ()
+{
+  struct sigaction sa = { };
+  sa.sa_handler = sigill;
+  sa.sa_flags = SA_NODEFER;
+  sigaction (SIGILL, &sa, 0);
+  return test_mem () | test_reg ();
+}
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..58b16aa763a 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