===================================================================
@@ -1990,6 +1990,44 @@ lower_eh_constructs_2 (struct leh_state
}
break;
+ case GIMPLE_ASM:
+ /* Similar to normal LHS handling above, replace outputs
+ with new temporaries. */
+ if (stmt_could_throw_p (stmt)
+ && gimple_code (stmt) == GIMPLE_ASM)
+ {
+ unsigned noutputs;
+ unsigned i;
+
+ noutputs = gimple_asm_noutputs (stmt);
+ for (i = 0; i < noutputs; i++)
+ {
+ tree link, op;
+ link = gimple_asm_output_op (stmt, i);
+ op = TREE_VALUE (link);
+ if (!tree_could_throw_p (op)
+ && is_gimple_reg_type (TREE_TYPE (op)))
+ {
+ tree tmp = create_tmp_var (TREE_TYPE (op), NULL);
+ gimple s = gimple_build_assign (op, tmp);
+ gimple_set_location (s, gimple_location (stmt));
+ gimple_set_block (s, gimple_block (stmt));
+ TREE_VALUE (link) = tmp;
+ if (TREE_CODE (TREE_TYPE (tmp)) == COMPLEX_TYPE
+ || TREE_CODE (TREE_TYPE (tmp)) == VECTOR_TYPE)
+ DECL_GIMPLE_REG_P (tmp) = 1;
+ gsi_insert_after (gsi, s, GSI_SAME_STMT);
+ }
+ }
+ }
+ /* Look for things that can throw exceptions, and record them. */
+ if (state->cur_region && stmt_could_throw_p (stmt))
+ {
+ record_stmt_eh_region (state->cur_region, stmt);
+ note_eh_region_may_contain_throw (state->cur_region);
+ }
+ break;
+
case GIMPLE_COND:
case GIMPLE_GOTO:
case GIMPLE_RETURN:
@@ -2639,6 +2677,8 @@ stmt_could_throw_p (gimple stmt)
return stmt_could_throw_1_p (stmt);
case GIMPLE_ASM:
+ if (gimple_asm_can_throw_p (stmt))
+ return true;
if (!cfun->can_throw_non_call_exceptions)
return false;
return gimple_asm_volatile_p (stmt);
===================================================================
@@ -834,9 +834,10 @@ set_user_assembler_name (tree decl, cons
/* Decode an `asm' spec for a declaration as a register name.
Return the register number, or -1 if nothing specified,
- or -2 if the ASMSPEC is not `cc' or `memory' and is not recognized,
+ or -2 if the ASMSPEC is not `cc', `memory' or `throw' and is not recognized,
or -3 if ASMSPEC is `cc' and is not recognized,
- or -4 if ASMSPEC is `memory' and is not recognized.
+ or -4 if ASMSPEC is `memory' and is not recognized,
+ or -5 if ASMSPEC is `throw' and is not recognized.
Accept an exact spelling or a decimal number.
Prefixes such as % are optional. */
@@ -902,6 +903,9 @@ decode_reg_name_and_count (const char *a
}
#endif /* ADDITIONAL_REGISTER_NAMES */
+ if (!strcmp (asmspec, "throw"))
+ return -5;
+
if (!strcmp (asmspec, "memory"))
return -4;
===================================================================
@@ -266,7 +266,8 @@ struct GTY((chain_next ("RTX_NEXT (&%h)"
1 in a CALL_INSN if it is a sibling call.
1 in a SET that is for a return.
In a CODE_LABEL, part of the two-bit alternate entry field.
- 1 in a CONCAT is VAL_EXPR_IS_COPIED in var-tracking.c. */
+ 1 in a CONCAT is VAL_EXPR_IS_COPIED in var-tracking.c.
+ 1 in an ASM_OPERANDS is ASM_OPERANDS_THROW_P. */
unsigned int jump : 1;
/* In a CODE_LABEL, part of the two-bit alternate entry field.
1 in a MEM if it cannot trap.
@@ -1317,6 +1318,8 @@ do { \
#define ASM_OPERANDS_LABEL_LENGTH(RTX) XCVECLEN (RTX, 5, ASM_OPERANDS)
#define ASM_OPERANDS_LABEL(RTX, N) XCVECEXP (RTX, 5, N, ASM_OPERANDS)
#define ASM_OPERANDS_SOURCE_LOCATION(RTX) XCUINT (RTX, 6, ASM_OPERANDS)
+#define ASM_OPERANDS_THROW_P(RTX) \
+ (RTL_FLAG_CHECK1("ASM_OPERANDS_THROW_P", (RTX), ASM_OPERANDS)->jump)
#define ASM_INPUT_SOURCE_LOCATION(RTX) XCUINT (RTX, 1, ASM_INPUT)
/* 1 if RTX is a mem that is statically allocated in read-only memory. */
===================================================================
@@ -5513,4 +5513,21 @@ gimple_asm_clobbers_memory_p (const_gimp
return false;
}
+
+/* Return true if the GIMPLE_ASM STMT can throw. */
+
+bool
+gimple_asm_can_throw_p (const_gimple stmt)
+{
+ unsigned i;
+
+ for (i = 0; i < gimple_asm_nclobbers (stmt); i++)
+ {
+ tree op = gimple_asm_clobber_op (stmt, i);
+ if (strcmp (TREE_STRING_POINTER (TREE_VALUE (op)), "throw") == 0)
+ return true;
+ }
+
+ return false;
+}
#include "gt-gimple.h"
===================================================================
@@ -1030,6 +1030,7 @@ extern bool walk_stmt_load_store_ops (gi
extern bool gimple_ior_addresses_taken (bitmap, gimple);
extern bool gimple_call_builtin_p (gimple, enum built_in_function);
extern bool gimple_asm_clobbers_memory_p (const_gimple);
+extern bool gimple_asm_can_throw_p (const_gimple);
/* In gimplify.c */
extern tree create_tmp_var_raw (tree, const char *);
===================================================================
@@ -580,6 +580,8 @@ make_edges (void)
case GIMPLE_ASM:
make_gimple_asm_edges (bb);
+ if (is_ctrl_altering_stmt (last))
+ make_eh_edges (last);
fallthru = true;
break;
===================================================================
@@ -657,6 +657,7 @@ expand_asm_operands (tree string, tree o
enum machine_mode *inout_mode = XALLOCAVEC (enum machine_mode, noutputs);
const char **constraints = XALLOCAVEC (const char *, noutputs + ninputs);
int old_generating_concat_p = generating_concat_p;
+ bool throw_p = false;
/* An ASM with no outputs needs to be treated as volatile, for now. */
if (noutputs == 0)
@@ -696,6 +697,11 @@ expand_asm_operands (tree string, tree o
i = decode_reg_name_and_count (regname, &nregs);
if (i == -4)
++nclobbers;
+ else if (i == -5)
+ {
+ throw_p = true;
+ vol = 1;
+ }
else if (i == -2)
error ("unknown register name %qs in %<asm%>", regname);
@@ -872,6 +878,7 @@ expand_asm_operands (tree string, tree o
labelvec, locus);
MEM_VOLATILE_P (body) = vol;
+ ASM_OPERANDS_THROW_P (body) = throw_p;
/* Eval the inputs and put them into ARGVEC.
Put their constraints into ASM_INPUTs and store in CONSTRAINTS. */
@@ -1028,6 +1035,7 @@ expand_asm_operands (tree string, tree o
i, argvec, constraintvec, labelvec, locus));
MEM_VOLATILE_P (SET_SRC (XVECEXP (body, 0, i))) = vol;
+ ASM_OPERANDS_THROW_P (SET_SRC (XVECEXP (body, 0, i))) = throw_p;
}
/* If there are no outputs (but there are some clobbers)
===================================================================
@@ -1622,12 +1622,16 @@ make_reg_eh_region_note_nothrow_nononloc
bool
insn_could_throw_p (const_rtx insn)
{
+ rtx tmp;
if (!flag_exceptions)
return false;
if (CALL_P (insn))
return true;
if (INSN_P (insn) && cfun->can_throw_non_call_exceptions)
return may_trap_p (PATTERN (insn));
+ if (INSN_P (insn)
+ && (tmp = extract_asm_operands (PATTERN (insn))) != NULL)
+ return ASM_OPERANDS_THROW_P (tmp);
return false;
}
===================================================================
@@ -82,6 +82,7 @@ inside_basic_block_p (const_rtx insn)
bool
control_flow_insn_p (const_rtx insn)
{
+ rtx tmp;
switch (GET_CODE (insn))
{
case NOTE:
@@ -112,6 +113,8 @@ control_flow_insn_p (const_rtx insn)
if (GET_CODE (PATTERN (insn)) == TRAP_IF
&& XEXP (PATTERN (insn), 0) == const1_rtx)
return true;
+ if ((tmp = extract_asm_operands (PATTERN (insn))) != NULL)
+ return can_throw_internal (insn);
if (!cfun->can_throw_non_call_exceptions)
return false;
break;
@@ -364,6 +367,8 @@ make_edges (basic_block min, basic_block
}
}
}
+ else if (code == INSN && extract_asm_operands (PATTERN (insn)))
+ rtl_make_eh_edge (edge_cache, bb, insn);
/* Find out if we can drop through to the next block. */
insn = NEXT_INSN (insn);
===================================================================
@@ -0,0 +1,16 @@
+// PR c++/52770
+// { dg-do compile }
+// { dg-final { scan-assembler "EHB" } }
+// { dg-options "-O2" }
+int f (void)
+{
+ int x, y;
+ x = 1;
+ y = 2;
+ try {
+ __asm__ ("" : "=r"(x), "=r"(y) : : "throw");
+ } catch (...) {
+ return 2+x+y;
+ }
+ return x+y;
+}