Hi,
So here's an extended variant of my hack that implements throwing asms.
Like rth proposed I've added a new pseudo clobber, throw:
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;
}
The patch handles multiple output arguments by doing the same we do for
calls, i.e. introducing new temporaries. For gimple this clobber is
retained and hence a throwing asm can be simply recognized by searching
for it. For RTL I've added a new flag to mark the ASM_OPERANDS rtx.
Without such marking we would have to treat every asm as potentially
throwing in insn_could_throw_p, and rely on the REG_EH_REGION notes to
mark them as non-throwing. Instead of auditing all MEM_VOLATILE_P uses on
asms to see if they require handling throwing I've settled on simply
implying the volatile bit for throwing asms.
Not yet regstrapped, so no rfa, but does this seem sane?
Ciao,
Michael.
Index: tree-eh.c
===
--- tree-eh.c (revision 183716)
+++ tree-eh.c (working copy)
@@ -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);
Index: varasm.c
===
--- varasm.c(revision 183716)
+++ varasm.c(working copy)
@@ -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;
Index: rtl.h
===
--- rtl.h (revision 183716)
+++ rtl.h (working copy)
@@ -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,