This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
[tree-ssa] Implement non-call exceptions
- From: Andrew Haley <aph at redhat dot com>
- To: gcc-patches at gcc dot gnu dot org
- Date: Wed, 3 Dec 2003 18:13:23 +0000
- Subject: [tree-ssa] Implement non-call exceptions
Non-call exceptions are pretty much FUBAR on the tree-SSA branch.
We carefully generate EH regions fopr trees, but we don't copy the
information into the RTL we generate.
Also, we don't allow for arithmetic overflow exceptions in
tree_could_trap_p().
Also, we assume that libcalls can't throw.
This patch fixes all these, leaving gcj on the tree-SSA branch in pretty good shape.
Andrew.
* tree-eh.c (tree_could_trap_p): Add division instructions.
* calls.c (emit_library_call_value_1): Set ECF_NOTHROW only if
we're not using flag_non_call_exceptions.
* expr.c (expand_expr): Check the EH region of an expression and
mark all the insns that result from its expansion with the
appropriate REG_EH_REGION.
Index: calls.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/calls.c,v
retrieving revision 1.229.2.38
diff -p -1 -0 -c -r1.229.2.38 calls.c
*** calls.c 25 Nov 2003 02:09:33 -0000 1.229.2.38
--- calls.c 3 Dec 2003 18:09:47 -0000
*************** emit_library_call_value_1 (int retval, r
*** 3634,3654 ****
struct locate_and_pad_arg_data locate;
rtx save_area;
};
struct arg *argvec;
int old_inhibit_defer_pop = inhibit_defer_pop;
rtx call_fusage = 0;
rtx mem_value = 0;
rtx valreg;
int pcc_struct_value = 0;
int struct_value_size = 0;
! int flags;
int reg_parm_stack_space = 0;
int needed;
rtx before_call;
tree tfom; /* type_for_mode (outmode, 0) */
#ifdef REG_PARM_STACK_SPACE
/* Define the boundary of the register parm stack space that needs to be
save, if any. */
int low_to_save, high_to_save;
rtx save_area = 0; /* Place that it is saved. */
--- 3634,3654 ----
struct locate_and_pad_arg_data locate;
rtx save_area;
};
struct arg *argvec;
int old_inhibit_defer_pop = inhibit_defer_pop;
rtx call_fusage = 0;
rtx mem_value = 0;
rtx valreg;
int pcc_struct_value = 0;
int struct_value_size = 0;
! int flags = 0;
int reg_parm_stack_space = 0;
int needed;
rtx before_call;
tree tfom; /* type_for_mode (outmode, 0) */
#ifdef REG_PARM_STACK_SPACE
/* Define the boundary of the register parm stack space that needs to be
save, if any. */
int low_to_save, high_to_save;
rtx save_area = 0; /* Place that it is saved. */
*************** emit_library_call_value_1 (int retval, r
*** 3662,3682 ****
#ifdef REG_PARM_STACK_SPACE
#ifdef MAYBE_REG_PARM_STACK_SPACE
reg_parm_stack_space = MAYBE_REG_PARM_STACK_SPACE;
#else
reg_parm_stack_space = REG_PARM_STACK_SPACE ((tree) 0);
#endif
#endif
/* By default, library functions can not throw. */
! flags = ECF_NOTHROW;
switch (fn_type)
{
case LCT_NORMAL:
break;
case LCT_CONST:
flags |= ECF_CONST;
break;
case LCT_PURE:
flags |= ECF_PURE;
--- 3662,3683 ----
#ifdef REG_PARM_STACK_SPACE
#ifdef MAYBE_REG_PARM_STACK_SPACE
reg_parm_stack_space = MAYBE_REG_PARM_STACK_SPACE;
#else
reg_parm_stack_space = REG_PARM_STACK_SPACE ((tree) 0);
#endif
#endif
/* By default, library functions can not throw. */
! if (! flag_non_call_exceptions)
! flags = ECF_NOTHROW;
switch (fn_type)
{
case LCT_NORMAL:
break;
case LCT_CONST:
flags |= ECF_CONST;
break;
case LCT_PURE:
flags |= ECF_PURE;
Index: expr.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/expr.c,v
retrieving revision 1.467.2.65
diff -p -1 -0 -c -r1.467.2.65 expr.c
*** expr.c 25 Nov 2003 02:09:43 -0000 1.467.2.65
--- expr.c 3 Dec 2003 18:09:51 -0000
*************** expand_operands (tree exp0, tree exp1, r
*** 6275,6331 ****
don't want to use TARGET for anything but the final result;
Intermediate values must go elsewhere. Additionally, calls to
emit_block_move will be flagged with BLOCK_OP_CALL_PARM. */
static rtx expand_expr_1 (tree, rtx, enum machine_mode, enum expand_modifier);
rtx
expand_expr (tree exp, rtx target, enum machine_mode tmode,
enum expand_modifier modifier)
{
/* Handle ERROR_MARK before anybody tries to access its type. */
if (TREE_CODE (exp) == ERROR_MARK
|| TREE_CODE (TREE_TYPE (exp)) == ERROR_MARK)
{
! rtx ret = CONST0_RTX (tmode);
return ret ? ret : const0_rtx;
}
/* If this is an expression of some kind and it has an associated line
number, then emit the line number before expanding the expression.
We need to save and restore the file and line information so that
errors discovered during expansion are emitted with the right
information. It would be better of the diagnostic routines
used the file/line information embedded in the tree nodes rather
than globals. */
if (cfun && EXPR_LOCUS (exp))
{
! location_t saved_location;
! rtx ret;
!
! saved_location = input_location;
input_location = *EXPR_LOCUS (exp);
emit_line_note (input_location);
!
/* Record where the insns produced belong. */
if (cfun->dont_emit_block_notes)
record_block_change (TREE_BLOCK (exp));
ret = expand_expr_1 (exp, target, tmode, modifier);
input_location = saved_location;
! return ret;
}
! return expand_expr_1 (exp, target, tmode, modifier);
}
static rtx
expand_expr_1 (tree exp, rtx target, enum machine_mode tmode,
enum expand_modifier modifier)
{
rtx op0, op1, temp;
tree type = TREE_TYPE (exp);
int unsignedp = TREE_UNSIGNED (type);
enum machine_mode mode;
--- 6275,6364 ----
don't want to use TARGET for anything but the final result;
Intermediate values must go elsewhere. Additionally, calls to
emit_block_move will be flagged with BLOCK_OP_CALL_PARM. */
static rtx expand_expr_1 (tree, rtx, enum machine_mode, enum expand_modifier);
rtx
expand_expr (tree exp, rtx target, enum machine_mode tmode,
enum expand_modifier modifier)
{
+ int rn = -1;
+ rtx ret, last;
+
/* Handle ERROR_MARK before anybody tries to access its type. */
if (TREE_CODE (exp) == ERROR_MARK
|| TREE_CODE (TREE_TYPE (exp)) == ERROR_MARK)
{
! ret = CONST0_RTX (tmode);
return ret ? ret : const0_rtx;
}
+ if (flag_non_call_exceptions)
+ {
+ rn = lookup_stmt_eh_region (exp);
+ /* If rn < 0, then either (1) tree-ssa not used or (2) doesn't
+ throw. */
+ if (rn >= 0)
+ last = get_last_insn ();
+ }
+
/* If this is an expression of some kind and it has an associated line
number, then emit the line number before expanding the expression.
We need to save and restore the file and line information so that
errors discovered during expansion are emitted with the right
information. It would be better of the diagnostic routines
used the file/line information embedded in the tree nodes rather
than globals. */
if (cfun && EXPR_LOCUS (exp))
{
! location_t saved_location = input_location;
input_location = *EXPR_LOCUS (exp);
emit_line_note (input_location);
!
/* Record where the insns produced belong. */
if (cfun->dont_emit_block_notes)
record_block_change (TREE_BLOCK (exp));
ret = expand_expr_1 (exp, target, tmode, modifier);
input_location = saved_location;
+ }
+ else
+ {
+ ret = expand_expr_1 (exp, target, tmode, modifier);
+ }
! /* If using non-call exceptions, mark all insns that may trap.
! expand_call() will mark CALL_INSNs before we get to this code,
! but it doesn't handle libcalls, and these may trap. */
! if (rn >= 0)
! {
! rtx insn;
! for (insn = next_real_insn (last); insn;
! insn = next_real_insn (insn))
! {
! if (! find_reg_note (insn, REG_EH_REGION, NULL_RTX)
! /* If we want exceptions for non-call insns, any
! may_trap_p instruction may throw. */
! && GET_CODE (PATTERN (insn)) != CLOBBER
! && GET_CODE (PATTERN (insn)) != USE
! && (GET_CODE (insn) == CALL_INSN || may_trap_p (PATTERN (insn))))
! {
! REG_NOTES (insn) = alloc_EXPR_LIST (REG_EH_REGION, GEN_INT (rn),
! REG_NOTES (insn));
! }
! }
}
! return ret;
}
static rtx
expand_expr_1 (tree exp, rtx target, enum machine_mode tmode,
enum expand_modifier modifier)
{
rtx op0, op1, temp;
tree type = TREE_TYPE (exp);
int unsignedp = TREE_UNSIGNED (type);
enum machine_mode mode;
Index: tree-eh.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/Attic/tree-eh.c,v
retrieving revision 1.1.2.18
diff -p -1 -0 -c -r1.1.2.18 tree-eh.c
*** tree-eh.c 29 Nov 2003 12:43:10 -0000 1.1.2.18
--- tree-eh.c 3 Dec 2003 18:09:52 -0000
*************** make_eh_edges (tree stmt)
*** 1661,1683 ****
}
/* Return true if the expr can trap, as in dereferencing an
invalid pointer location. */
bool
tree_could_trap_p (tree expr)
{
! return (TREE_CODE (expr) == INDIRECT_REF
! || (TREE_CODE (expr) == COMPONENT_REF
! && (TREE_CODE (TREE_OPERAND (expr, 0)) == INDIRECT_REF)));
}
bool
tree_could_throw_p (tree t)
{
if (!flag_exceptions)
return false;
if (TREE_CODE (t) == MODIFY_EXPR)
{
--- 1661,1701 ----
}
/* Return true if the expr can trap, as in dereferencing an
invalid pointer location. */
bool
tree_could_trap_p (tree expr)
{
! enum tree_code code = TREE_CODE (expr);
! if (code == INDIRECT_REF
! || (code == COMPONENT_REF
! && (TREE_CODE (TREE_OPERAND (expr, 0)) == INDIRECT_REF)))
! return true;
!
! switch (code)
! {
! case TRUNC_DIV_EXPR:
! case CEIL_DIV_EXPR:
! case FLOOR_DIV_EXPR:
! case ROUND_DIV_EXPR:
! case EXACT_DIV_EXPR:
! case CEIL_MOD_EXPR:
! case FLOOR_MOD_EXPR:
! case ROUND_MOD_EXPR:
! case TRUNC_MOD_EXPR:
! return true;
! }
!
! return false;
}
bool
tree_could_throw_p (tree t)
{
if (!flag_exceptions)
return false;
if (TREE_CODE (t) == MODIFY_EXPR)
{