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