summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorebotcazou <ebotcazou@138bc75d-0d04-0410-961f-82ee72b054a4>2009-10-19 18:15:49 +0000
committerebotcazou <ebotcazou@138bc75d-0d04-0410-961f-82ee72b054a4>2009-10-19 18:15:49 +0000
commita2159096117d349c33d569e8d92ae01e1d3ecf46 (patch)
tree194961175bb99ae23489eb50577d4d2f4e2e31bb
parent7ba65099b4d888030fcb580d65907ceff6fe9e69 (diff)
downloadgcc-a2159096117d349c33d569e8d92ae01e1d3ecf46.tar.gz
* gimple-low.c (struct lower_data): Add cannot_fallthru field.
(lower_stmt) <GIMPLE_BIND>: Add comment. <GIMPLE_COND, GIMPLE_GOTO, GIMPLE_SWITCH>: Set cannot_fallthru to true and return. <GIMPLE_RETURN>: Remove the statement if cannot_fallthru is set. Otherwise lower it and set cannot_fallthru to true. <GIMPLE_TRY>: Update cannot_fallthru for GIMPLE_TRY_FINALLY and return. <GIMPLE_CATCH, GIMPLE_EH_FILTER>; Set cannot_fallthru to false. <GIMPLE_CALL>: Set cannot_fallthru to false for BUILT_IN_SETJMP and to true for a noreturn call. Do not remove statements. <GIMPLE_OMP_PARALLEL, GIMPLE_OMP_TASK>: Set cannot_fallthru to false. Set cannot_fallthru to false on function exit. (gimple_stmt_may_fallthru) <GIMPLE_SWITCH>: Really return false. <GIMPLE_ASSIGN>: Remove. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@152984 138bc75d-0d04-0410-961f-82ee72b054a4
-rw-r--r--gcc/ChangeLog17
-rw-r--r--gcc/gimple-low.c76
-rw-r--r--gcc/testsuite/ChangeLog4
-rw-r--r--gcc/testsuite/gnat.dg/noreturn2.adb23
-rw-r--r--gcc/testsuite/gnat.dg/noreturn2.ads8
5 files changed, 104 insertions, 24 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index c4048a577d9..9b854623228 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,20 @@
+2009-10-19 Eric Botcazou <ebotcazou@adacore.com>
+
+ * gimple-low.c (struct lower_data): Add cannot_fallthru field.
+ (lower_stmt) <GIMPLE_BIND>: Add comment.
+ <GIMPLE_COND, GIMPLE_GOTO, GIMPLE_SWITCH>: Set cannot_fallthru to true
+ and return.
+ <GIMPLE_RETURN>: Remove the statement if cannot_fallthru is set.
+ Otherwise lower it and set cannot_fallthru to true.
+ <GIMPLE_TRY>: Update cannot_fallthru for GIMPLE_TRY_FINALLY and return.
+ <GIMPLE_CATCH, GIMPLE_EH_FILTER>; Set cannot_fallthru to false.
+ <GIMPLE_CALL>: Set cannot_fallthru to false for BUILT_IN_SETJMP and
+ to true for a noreturn call. Do not remove statements.
+ <GIMPLE_OMP_PARALLEL, GIMPLE_OMP_TASK>: Set cannot_fallthru to false.
+ Set cannot_fallthru to false on function exit.
+ (gimple_stmt_may_fallthru) <GIMPLE_SWITCH>: Really return false.
+ <GIMPLE_ASSIGN>: Remove.
+
2009-10-19 Andreas Krebbel <Andreas.Krebbel@de.ibm.com>
* config/s390/s390.c (s390_z10_optimize_cmp): Don't touch FP compares.
diff --git a/gcc/gimple-low.c b/gcc/gimple-low.c
index 39c735197a7..cce31e946ff 100644
--- a/gcc/gimple-low.c
+++ b/gcc/gimple-low.c
@@ -76,6 +76,9 @@ struct lower_data
of the function. */
VEC(return_statements_t,heap) *return_statements;
+ /* True if the current statement cannot fall through. */
+ bool cannot_fallthru;
+
/* True if the function calls __builtin_setjmp. */
bool calls_builtin_setjmp;
};
@@ -317,7 +320,12 @@ lower_omp_directive (gimple_stmt_iterator *gsi, struct lower_data *data)
}
-/* Lower statement GSI. DATA is passed through the recursion. */
+/* Lower statement GSI. DATA is passed through the recursion. We try to
+ track the fallthruness of statements and get rid of unreachable return
+ statements in order to prevent the EH lowering pass from adding useless
+ edges that can cause bogus warnings to be issued later; this guess need
+ not be 100% accurate, simply be conservative and reset cannot_fallthru
+ to false if we don't know. */
static void
lower_stmt (gimple_stmt_iterator *gsi, struct lower_data *data)
@@ -330,36 +338,61 @@ lower_stmt (gimple_stmt_iterator *gsi, struct lower_data *data)
{
case GIMPLE_BIND:
lower_gimple_bind (gsi, data);
+ /* Propagate fallthruness. */
return;
case GIMPLE_COND:
- /* The gimplifier has already lowered this into gotos. */
- break;
+ case GIMPLE_GOTO:
+ case GIMPLE_SWITCH:
+ data->cannot_fallthru = true;
+ gsi_next (gsi);
+ return;
case GIMPLE_RETURN:
- lower_gimple_return (gsi, data);
+ if (data->cannot_fallthru)
+ {
+ gsi_remove (gsi, false);
+ /* Propagate fallthruness. */
+ }
+ else
+ {
+ lower_gimple_return (gsi, data);
+ data->cannot_fallthru = true;
+ }
return;
case GIMPLE_TRY:
- lower_sequence (gimple_try_eval (stmt), data);
- lower_sequence (gimple_try_cleanup (stmt), data);
+ {
+ bool try_cannot_fallthru;
+ lower_sequence (gimple_try_eval (stmt), data);
+ try_cannot_fallthru = data->cannot_fallthru;
+ data->cannot_fallthru = false;
+ lower_sequence (gimple_try_cleanup (stmt), data);
+ /* See gimple_stmt_may_fallthru for the rationale. */
+ if (gimple_try_kind (stmt) == GIMPLE_TRY_FINALLY)
+ {
+ data->cannot_fallthru |= try_cannot_fallthru;
+ gsi_next (gsi);
+ return;
+ }
+ }
break;
case GIMPLE_CATCH:
+ data->cannot_fallthru = false;
lower_sequence (gimple_catch_handler (stmt), data);
break;
case GIMPLE_EH_FILTER:
+ data->cannot_fallthru = false;
lower_sequence (gimple_eh_filter_failure (stmt), data);
break;
case GIMPLE_NOP:
case GIMPLE_ASM:
case GIMPLE_ASSIGN:
- case GIMPLE_GOTO:
case GIMPLE_PREDICT:
case GIMPLE_LABEL:
- case GIMPLE_SWITCH:
case GIMPLE_EH_MUST_NOT_THROW:
case GIMPLE_OMP_FOR:
case GIMPLE_OMP_SECTIONS:
@@ -383,21 +416,16 @@ lower_stmt (gimple_stmt_iterator *gsi, struct lower_data *data)
&& DECL_BUILT_IN_CLASS (decl) == BUILT_IN_NORMAL
&& DECL_FUNCTION_CODE (decl) == BUILT_IN_SETJMP)
{
- data->calls_builtin_setjmp = true;
lower_builtin_setjmp (gsi);
+ data->cannot_fallthru = false;
+ data->calls_builtin_setjmp = true;
return;
}
- /* After a noreturn call, remove a subsequent GOTO or RETURN that might
- have been mechanically added; this will prevent the EH lowering pass
- from adding useless edges and thus complicating the initial CFG. */
if (decl && (flags_from_decl_or_type (decl) & ECF_NORETURN))
{
+ data->cannot_fallthru = true;
gsi_next (gsi);
- if (!gsi_end_p (*gsi)
- && (gimple_code (gsi_stmt (*gsi)) == GIMPLE_GOTO
- || gimple_code (gsi_stmt (*gsi)) == GIMPLE_RETURN))
- gsi_remove (gsi, false);
return;
}
}
@@ -405,13 +433,16 @@ lower_stmt (gimple_stmt_iterator *gsi, struct lower_data *data)
case GIMPLE_OMP_PARALLEL:
case GIMPLE_OMP_TASK:
+ data->cannot_fallthru = false;
lower_omp_directive (gsi, data);
+ data->cannot_fallthru = false;
return;
default:
gcc_unreachable ();
}
+ data->cannot_fallthru = false;
gsi_next (gsi);
}
@@ -660,9 +691,9 @@ gimple_stmt_may_fallthru (gimple stmt)
return false;
case GIMPLE_SWITCH:
- /* Switch has already been lowered and represents a
- branch to a selected label and hence can not fall through. */
- return true;
+ /* Switch has already been lowered and represents a branch
+ to a selected label and hence can't fall through. */
+ return false;
case GIMPLE_COND:
/* GIMPLE_COND's are already lowered into a two-way branch. They
@@ -688,13 +719,10 @@ gimple_stmt_may_fallthru (gimple stmt)
return (gimple_seq_may_fallthru (gimple_try_eval (stmt))
&& gimple_seq_may_fallthru (gimple_try_cleanup (stmt)));
- case GIMPLE_ASSIGN:
- return true;
-
case GIMPLE_CALL:
/* Functions that do not return do not fall through. */
return (gimple_call_flags (stmt) & ECF_NORETURN) == 0;
-
+
default:
return true;
}
@@ -744,7 +772,7 @@ lower_gimple_return (gimple_stmt_iterator *gsi, struct lower_data *data)
gsi_remove (gsi, false);
}
-/* Lower a __builtin_setjmp TSI.
+/* Lower a __builtin_setjmp GSI.
__builtin_setjmp is passed a pointer to an array of five words (not
all will be used on all machines). It operates similarly to the C
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index bce4d7cb84f..1437ce664de 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,3 +1,7 @@
+2009-10-19 Eric Botcazou <ebotcazou@adacore.com>
+
+ * gnat.dg/noreturn2.ad[sb]: New test.
+
2009-10-19 Tobias Burnus <burnus@net-b.de>
PR fortran/41755
diff --git a/gcc/testsuite/gnat.dg/noreturn2.adb b/gcc/testsuite/gnat.dg/noreturn2.adb
new file mode 100644
index 00000000000..5caf222f29b
--- /dev/null
+++ b/gcc/testsuite/gnat.dg/noreturn2.adb
@@ -0,0 +1,23 @@
+-- { dg-do compile }
+
+package body Noreturn2 is
+
+ procedure Raise_Exception_No_Defer (Message : String);
+ pragma No_Return (Raise_Exception_No_Defer);
+
+ procedure Raise_From (X : Exception_Occurrence) is
+ Occurrence_Message : constant String := Exception_Message (X);
+ begin
+ if Occurrence_Message = "$" then
+ Raise_Exception_No_Defer (Occurrence_Message);
+ else
+ Raise_Exception_No_Defer ("::" & Occurrence_Message);
+ end if;
+ end;
+
+ procedure Raise_Exception_No_Defer (Message : String) is
+ begin
+ raise Program_Error;
+ end;
+
+end Noreturn2;
diff --git a/gcc/testsuite/gnat.dg/noreturn2.ads b/gcc/testsuite/gnat.dg/noreturn2.ads
new file mode 100644
index 00000000000..1aaf4e97446
--- /dev/null
+++ b/gcc/testsuite/gnat.dg/noreturn2.ads
@@ -0,0 +1,8 @@
+with Ada.Exceptions; use Ada.Exceptions;
+
+package Noreturn2 is
+
+ procedure Raise_From (X : Exception_Occurrence);
+ pragma No_Return (Raise_From);
+
+end Noreturn2;