OSDN Git Service

* rs6000.md (abssi2_nopower): Convert to define_insn_and_split.
[pf3gnuchains/gcc-fork.git] / gcc / cfganal.c
index 1c499f4..46c4758 100644 (file)
@@ -25,9 +25,11 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
 #include "rtl.h"
 #include "hard-reg-set.h"
 #include "basic-block.h"
+#include "insn-config.h"
+#include "recog.h"
 #include "toplev.h"
-
 #include "obstack.h"
+#include "tm_p.h"
 
 /* Store the data structures necessary for depth-first search.  */
 struct depth_first_search_dsS {
@@ -259,17 +261,27 @@ flow_call_edges_add (blocks)
      spanning tree in the case that the call doesn't return.
 
      Handle this by adding a dummy instruction in a new last basic block.  */
-  if (check_last_block
-      && need_fake_edge_p (BASIC_BLOCK (n_basic_blocks - 1)->end))
+  if (check_last_block)
     {
-       edge e;
+      basic_block bb = BASIC_BLOCK (n_basic_blocks - 1);
+      rtx insn = bb->end;
 
-       for (e = BASIC_BLOCK (n_basic_blocks - 1)->succ; e; e = e->succ_next)
-        if (e->dest == EXIT_BLOCK_PTR)
-           break;
+      /* Back up past insns that must be kept in the same block as a call.  */
+      while (insn != bb->head
+            && keep_with_call_p (insn))
+       insn = PREV_INSN (insn);
+
+      if (need_fake_edge_p (insn))
+       {
+         edge e;
 
-       insert_insn_on_edge (gen_rtx_USE (VOIDmode, const0_rtx), e);
-       commit_edge_insertions ();
+         for (e = bb->succ; e; e = e->succ_next)
+           if (e->dest == EXIT_BLOCK_PTR)
+             break;
+
+         insert_insn_on_edge (gen_rtx_USE (VOIDmode, const0_rtx), e);
+         commit_edge_insertions ();
+       }
     }
 
   /* Now add fake edges to the function exit for any non constant
@@ -288,14 +300,22 @@ flow_call_edges_add (blocks)
          if (need_fake_edge_p (insn))
            {
              edge e;
+             rtx split_at_insn = insn;
+
+             /* Don't split the block between a call and an insn that should
+                remain in the same block as the call.  */
+             if (GET_CODE (insn) == CALL_INSN)
+               while (split_at_insn != bb->end
+                      && keep_with_call_p (NEXT_INSN (split_at_insn)))
+                 split_at_insn = NEXT_INSN (split_at_insn);
 
-             /* The above condition should be enough to verify that there is
-                no edge to the exit block in CFG already.  Calling make_edge
-                in such case would make us to mark that edge as fake and
-                remove it later.  */
+             /* The handling above of the final block before the epilogue
+                should be enough to verify that there is no edge to the exit
+                block in CFG already.  Calling make_edge in such case would
+                cause us to mark that edge as fake and remove it later.  */
 
 #ifdef ENABLE_CHECKING
-             if (insn == bb->end)
+             if (split_at_insn == bb->end)
                for (e = bb->succ; e; e = e->succ_next)
                  if (e->dest == EXIT_BLOCK_PTR)
                    abort ();
@@ -303,7 +323,7 @@ flow_call_edges_add (blocks)
 
              /* Note that the following may create a new basic block
                 and renumber the existing basic blocks.  */
-             e = split_block (bb, insn);
+             e = split_block (bb, split_at_insn);
              if (e)
                blocks_split++;