[PATCH v3 1/2] generate EH info for volatile asm statements (PR93981)

Richard Biener richard.guenther@gmail.com
Fri Nov 13 08:41:28 GMT 2020


On Thu, Mar 12, 2020 at 1:41 AM J.W. Jagersma via Gcc-patches
<gcc-patches@gcc.gnu.org> wrote:
>
> 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  <jwjagersma@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  <jwjagersma@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;

Can you avoid the ugly goto by simply duplicating the common code please?

Otherwise OK.

As you say volatile asms are already considered throwing in some pieces of
code so this is a step towards fulfilling that promise.

Thanks,
Richard.

> +
>      case GIMPLE_COND:
>      case GIMPLE_GOTO:
>      case GIMPLE_RETURN:
> --
> 2.25.1
>


More information about the Gcc-patches mailing list