OSDN Git Service

Daily bump.
[pf3gnuchains/gcc-fork.git] / gcc / graphite-scop-detection.c
index e30554f..0a3680b 100644 (file)
@@ -1,5 +1,5 @@
 /* Detection of Static Control Parts (SCoP) for Graphite.
-   Copyright (C) 2009 Free Software Foundation, Inc.
+   Copyright (C) 2009, 2010 Free Software Foundation, Inc.
    Contributed by Sebastian Pop <sebastian.pop@amd.com> and
    Tobias Grosser <grosser@fim.uni-passau.de>.
 
@@ -22,35 +22,23 @@ along with GCC; see the file COPYING3.  If not see
 #include "config.h"
 #include "system.h"
 #include "coretypes.h"
-#include "tm.h"
-#include "ggc.h"
-#include "tree.h"
-#include "rtl.h"
-#include "basic-block.h"
-#include "diagnostic.h"
 #include "tree-flow.h"
-#include "toplev.h"
-#include "tree-dump.h"
-#include "timevar.h"
 #include "cfgloop.h"
 #include "tree-chrec.h"
 #include "tree-data-ref.h"
 #include "tree-scalar-evolution.h"
 #include "tree-pass.h"
-#include "domwalk.h"
-#include "value-prof.h"
-#include "pointer-set.h"
-#include "gimple.h"
 #include "sese.h"
 
 #ifdef HAVE_cloog
-#include "cloog/cloog.h"
 #include "ppl_c.h"
 #include "graphite-ppl.h"
-#include "graphite.h"
 #include "graphite-poly.h"
 #include "graphite-scop-detection.h"
 
+/* Forward declarations.  */
+static void make_close_phi_nodes_unique (basic_block);
+
 /* The type of the analyzed basic block.  */
 
 typedef enum gbb_type {
@@ -149,7 +137,7 @@ move_sd_regions (VEC (sd_region, heap) **source,
   sd_region *s;
   int i;
 
-  for (i = 0; VEC_iterate (sd_region, *source, i, s); i++)
+  FOR_EACH_VEC_ELT (sd_region, *source, i, s)
     VEC_safe_push (sd_region, heap, *target, s);
 
   VEC_free (sd_region, heap, *source);
@@ -203,12 +191,10 @@ graphite_can_represent_init (tree e)
 
    1 i + 20 j + (-2) m + 25
 
-   Something like "i * n" or "n * m" is not allowed.
-
-   OUTERMOST_LOOP defines the outermost loop that can variate.  */
+   Something like "i * n" or "n * m" is not allowed.  */
 
 static bool
-graphite_can_represent_scev (tree scev, int outermost_loop)
+graphite_can_represent_scev (tree scev)
 {
   if (chrec_contains_undetermined (scev))
     return false;
@@ -217,16 +203,17 @@ graphite_can_represent_scev (tree scev, int outermost_loop)
     {
     case PLUS_EXPR:
     case MINUS_EXPR:
-      return graphite_can_represent_scev (TREE_OPERAND (scev, 0), outermost_loop)
-       && graphite_can_represent_scev (TREE_OPERAND (scev, 1), outermost_loop);
+      return graphite_can_represent_scev (TREE_OPERAND (scev, 0))
+       && graphite_can_represent_scev (TREE_OPERAND (scev, 1));
 
     case MULT_EXPR:
       return !CONVERT_EXPR_CODE_P (TREE_CODE (TREE_OPERAND (scev, 0)))
        && !CONVERT_EXPR_CODE_P (TREE_CODE (TREE_OPERAND (scev, 1)))
        && !(chrec_contains_symbols (TREE_OPERAND (scev, 0))
             && chrec_contains_symbols (TREE_OPERAND (scev, 1)))
-       && graphite_can_represent_scev (TREE_OPERAND (scev, 0), outermost_loop)
-       && graphite_can_represent_scev (TREE_OPERAND (scev, 1), outermost_loop);
+       && graphite_can_represent_init (scev)
+       && graphite_can_represent_scev (TREE_OPERAND (scev, 0))
+       && graphite_can_represent_scev (TREE_OPERAND (scev, 1));
 
     case POLYNOMIAL_CHREC:
       /* Check for constant strides.  With a non constant stride of
@@ -245,8 +232,7 @@ graphite_can_represent_scev (tree scev, int outermost_loop)
   if (!scev_is_linear_expression (scev))
     return false;
 
-  return evolution_function_is_invariant_p (scev, outermost_loop)
-    || evolution_function_is_affine_multivariate_p (scev, outermost_loop);
+  return true;
 }
 
 
@@ -254,84 +240,57 @@ graphite_can_represent_scev (tree scev, int outermost_loop)
 
    This means an expression can be represented, if it is linear with
    respect to the loops and the strides are non parametric.
-   LOOP is the place where the expr will be evaluated and OUTERMOST_LOOP
-   defindes the outermost loop that can variate.  SCOP_ENTRY defines the
+   LOOP is the place where the expr will be evaluated.  SCOP_ENTRY defines the
    entry of the region we analyse.  */
 
 static bool
 graphite_can_represent_expr (basic_block scop_entry, loop_p loop,
-                            loop_p outermost_loop, tree expr)
+                            tree expr)
 {
   tree scev = analyze_scalar_evolution (loop, expr);
 
   scev = instantiate_scev (scop_entry, loop, scev);
 
-  return graphite_can_represent_scev (scev, outermost_loop->num);
+  return graphite_can_represent_scev (scev);
 }
 
 /* Return true if the data references of STMT can be represented by
    Graphite.  */
 
 static bool
-stmt_has_simple_data_refs_p (loop_p outermost_loop, gimple stmt)
+stmt_has_simple_data_refs_p (loop_p outermost_loop ATTRIBUTE_UNUSED,
+                            gimple stmt)
 {
   data_reference_p dr;
   unsigned i;
   int j;
   bool res = true;
-  int loop = outermost_loop->num;
-  VEC (data_reference_p, heap) *drs = VEC_alloc (data_reference_p, heap, 5);
+  VEC (data_reference_p, heap) *drs = NULL;
+  loop_p outer;
 
-  graphite_find_data_references_in_stmt (outermost_loop, stmt, &drs);
+  for (outer = loop_containing_stmt (stmt); outer; outer = loop_outer (outer))
+    {
+      graphite_find_data_references_in_stmt (outer,
+                                            loop_containing_stmt (stmt),
+                                            stmt, &drs);
 
-  for (j = 0; VEC_iterate (data_reference_p, drs, j, dr); j++)
-    for (i = 0; i < DR_NUM_DIMENSIONS (dr); i++)
-      if (!graphite_can_represent_scev (DR_ACCESS_FN (dr, i), loop))
-       {
-         res = false;
-         goto done;
-       }
+      FOR_EACH_VEC_ELT (data_reference_p, drs, j, dr)
+       for (i = 0; i < DR_NUM_DIMENSIONS (dr); i++)
+         if (!graphite_can_represent_scev (DR_ACCESS_FN (dr, i)))
+           {
+             res = false;
+             goto done;
+           }
+
+      free_data_refs (drs);
+      drs = NULL;
+    }
 
  done:
   free_data_refs (drs);
   return res;
 }
 
-/* Return false if the TREE_CODE of the operand OP or any of its operands
-   is a COMPONENT_REF.  */
-
-static bool
-exclude_component_ref (tree op)
-{
-  int i;
-  int len;
-
-  if (!op)
-    return true;
-
-  if (TREE_CODE (op) == COMPONENT_REF)
-    return false;
-
-  len = TREE_OPERAND_LENGTH (op);
-  for (i = 0; i < len; ++i)
-    if (!exclude_component_ref (TREE_OPERAND (op, i)))
-      return false;
-
-  return true;
-}
-
-/* Return true if the operand OP used in STMT is simple in regards to
-   OUTERMOST_LOOP.  */
-
-static inline bool
-is_simple_operand (tree op)
-{
-  /* It is not a simple operand when it is a declaration or a
-     structure.  */
-  return !DECL_P (op) && !AGGREGATE_TYPE_P (TREE_TYPE (op))
-    && exclude_component_ref (op);
-}
-
 /* Return true only when STMT is simple enough for being handled by
    Graphite.  This depends on SCOP_ENTRY, as the parameters are
    initialized relatively to this basic block, the linear functions
@@ -385,8 +344,7 @@ stmt_simple_for_scop_p (basic_block scop_entry, loop_p outermost_loop,
           return false;
 
        FOR_EACH_SSA_TREE_OPERAND (op, stmt, op_iter, SSA_OP_ALL_USES)
-         if (!graphite_can_represent_expr (scop_entry, loop, outermost_loop,
-                                           op)
+         if (!graphite_can_represent_expr (scop_entry, loop, op)
              /* We can not handle REAL_TYPE. Failed for pr39260.  */
              || TREE_CODE (TREE_TYPE (op)) == REAL_TYPE)
            return false;
@@ -395,42 +353,8 @@ stmt_simple_for_scop_p (basic_block scop_entry, loop_p outermost_loop,
       }
 
     case GIMPLE_ASSIGN:
-      {
-       enum tree_code code = gimple_assign_rhs_code (stmt);
-
-       switch (get_gimple_rhs_class (code))
-         {
-         case GIMPLE_UNARY_RHS:
-         case GIMPLE_SINGLE_RHS:
-           return (is_simple_operand (gimple_assign_lhs (stmt))
-                   && is_simple_operand (gimple_assign_rhs1 (stmt)));
-
-         case GIMPLE_BINARY_RHS:
-           return (is_simple_operand (gimple_assign_lhs (stmt))
-                   && is_simple_operand (gimple_assign_rhs1 (stmt))
-                   && is_simple_operand (gimple_assign_rhs2 (stmt)));
-
-         case GIMPLE_INVALID_RHS:
-         default:
-           gcc_unreachable ();
-         }
-      }
-
     case GIMPLE_CALL:
-      {
-       size_t i;
-       size_t n = gimple_call_num_args (stmt);
-       tree lhs = gimple_call_lhs (stmt);
-
-       if (lhs && !is_simple_operand (lhs))
-         return false;
-
-       for (i = 0; i < n; i++)
-         if (!is_simple_operand (gimple_call_arg (stmt, i)))
-           return false;
-
-       return true;
-      }
+      return true;
 
     default:
       /* These nodes cut a new scope.  */
@@ -458,25 +382,24 @@ harmful_stmt_in_bb (basic_block scop_entry, loop_p outer_loop, basic_block bb)
   return NULL;
 }
 
-/* Return true when it is not possible to represent LOOP in the
-   polyhedral representation.  This is evaluated taking SCOP_ENTRY and
+/* Return true if LOOP can be represented in the polyhedral
+   representation.  This is evaluated taking SCOP_ENTRY and
    OUTERMOST_LOOP in mind.  */
 
 static bool
-graphite_can_represent_loop (basic_block scop_entry, loop_p outermost_loop,
-                            loop_p loop)
+graphite_can_represent_loop (basic_block scop_entry, loop_p loop)
 {
-  tree niter = number_of_latch_executions (loop);
+  tree niter;
+  struct tree_niter_desc niter_desc;
 
-  /* Number of iterations unknown.  */
-  if (chrec_contains_undetermined (niter))
-    return false;
+  /* FIXME: For the moment, graphite cannot be used on loops that
+     iterate using induction variables that wrap.  */
 
-  /* Number of iterations not affine.  */
-  if (!graphite_can_represent_expr (scop_entry, loop, outermost_loop, niter))
-    return false;
-
-  return true;
+  return number_of_iterations_exit (loop, single_exit (loop), &niter_desc, false)
+    && niter_desc.control.no_overflow
+    && (niter = number_of_latch_executions (loop))
+    && !chrec_contains_undetermined (niter)
+    && graphite_can_represent_expr (scop_entry, loop, niter);
 }
 
 /* Store information needed by scopdet_* functions.  */
@@ -546,7 +469,7 @@ scopdet_basic_block_info (basic_block bb, loop_p outermost_loop,
 
        sinfo = build_scops_1 (bb, outermost_loop, &regions, loop);
 
-       if (!graphite_can_represent_loop (entry_block, outermost_loop, loop))
+       if (!graphite_can_represent_loop (entry_block, loop))
          result.difficult = true;
 
        result.difficult |= sinfo.difficult;
@@ -621,7 +544,7 @@ scopdet_basic_block_info (basic_block bb, loop_p outermost_loop,
                  - The exit destinations are dominated by another bb inside
                    the loop.
                  - The loop dominates bbs, that are not exit destinations.  */
-        for (i = 0; VEC_iterate (edge, exits, i, e); i++)
+        FOR_EACH_VEC_ELT (edge, exits, i, e)
           if (e->src->loop_father == loop
              && dominated_by_p (CDI_DOMINATORS, e->dest, e->src))
            {
@@ -659,11 +582,11 @@ scopdet_basic_block_info (basic_block bb, loop_p outermost_loop,
 
        /* First check the successors of BB, and check if it is
           possible to join the different branches.  */
-       for (i = 0; VEC_iterate (edge, bb->succs, i, e); i++)
+       FOR_EACH_VEC_ELT (edge, bb->succs, i, e)
          {
            /* Ignore loop exits.  They will be handled after the loop
               body.  */
-           if (is_loop_exit (loop, e->dest))
+           if (loop_exits_to_bb_p (loop, e->dest))
              {
                result.exits = true;
                continue;
@@ -745,7 +668,7 @@ scopdet_basic_block_info (basic_block bb, loop_p outermost_loop,
        /* Scan remaining bbs dominated by BB.  */
        dominated = get_dominated_by (CDI_DOMINATORS, bb);
 
-       for (i = 0; VEC_iterate (basic_block, dominated, i, dom_bb); i++)
+       FOR_EACH_VEC_ELT (basic_block, dominated, i, dom_bb)
          {
            /* Ignore loop exits: they will be handled after the loop body.  */
            if (loop_depth (find_common_loop (loop, dom_bb->loop_father))
@@ -975,9 +898,7 @@ create_single_entry_edge (sd_region *region)
        single edge pointing from outside into the loop.  */
     gcc_unreachable ();
 
-#ifdef ENABLE_CHECKING
-  gcc_assert (find_single_entry_edge (region));
-#endif
+  gcc_checking_assert (find_single_entry_edge (region));
 }
 
 /* Check if the sd_region, mentioned in EDGE, has no exit bb.  */
@@ -1003,9 +924,6 @@ create_single_exit_edge (sd_region *region)
   edge forwarder = NULL;
   basic_block exit;
 
-  if (find_single_exit_edge (region))
-    return;
-
   /* We create a forwarder bb (5) for all edges leaving this region
      (3->5, 4->5).  All other edges leading to the same bb, are moved
      to a new bb (6).  If these edges where part of another region (2->5)
@@ -1046,9 +964,7 @@ create_single_exit_edge (sd_region *region)
     if (e->aux)
       ((sd_region *) e->aux)->exit = forwarder->dest;
 
-#ifdef ENABLE_CHECKING
-  gcc_assert (find_single_exit_edge (region));
-#endif
+  gcc_checking_assert (find_single_exit_edge (region));
 }
 
 /* Unmark the exit edges of all REGIONS.
@@ -1062,7 +978,7 @@ unmark_exit_edges (VEC (sd_region, heap) *regions)
   edge e;
   edge_iterator ei;
 
-  for (i = 0; VEC_iterate (sd_region, regions, i, s); i++)
+  FOR_EACH_VEC_ELT (sd_region, regions, i, s)
     FOR_EACH_EDGE (e, ei, s->exit->preds)
       e->aux = NULL;
 }
@@ -1079,7 +995,7 @@ mark_exit_edges (VEC (sd_region, heap) *regions)
   edge e;
   edge_iterator ei;
 
-  for (i = 0; VEC_iterate (sd_region, regions, i, s); i++)
+  FOR_EACH_VEC_ELT (sd_region, regions, i, s)
     FOR_EACH_EDGE (e, ei, s->exit->preds)
       if (bb_in_sd_region (e->src, s))
        e->aux = s;
@@ -1093,13 +1009,16 @@ create_sese_edges (VEC (sd_region, heap) *regions)
   int i;
   sd_region *s;
 
-  for (i = 0; VEC_iterate (sd_region, regions, i, s); i++)
+  FOR_EACH_VEC_ELT (sd_region, regions, i, s)
     create_single_entry_edge (s);
 
   mark_exit_edges (regions);
 
-  for (i = 0; VEC_iterate (sd_region, regions, i, s); i++)
-    create_single_exit_edge (s);
+  FOR_EACH_VEC_ELT (sd_region, regions, i, s)
+    /* Don't handle multiple edges exiting the function.  */
+    if (!find_single_exit_edge (s)
+       && s->exit != EXIT_BLOCK_PTR)
+      create_single_exit_edge (s);
 
   unmark_exit_edges (regions);
 
@@ -1121,11 +1040,16 @@ build_graphite_scops (VEC (sd_region, heap) *regions,
   int i;
   sd_region *s;
 
-  for (i = 0; VEC_iterate (sd_region, regions, i, s); i++)
+  FOR_EACH_VEC_ELT (sd_region, regions, i, s)
     {
       edge entry = find_single_entry_edge (s);
       edge exit = find_single_exit_edge (s);
-      scop_p scop = new_scop (new_sese (entry, exit));
+      scop_p scop;
+
+      if (!exit)
+       continue;
+
+      scop = new_scop (new_sese (entry, exit));
       VEC_safe_push (scop_p, heap, *scops, scop);
 
       /* Are there overlapping SCoPs?  */
@@ -1134,7 +1058,7 @@ build_graphite_scops (VEC (sd_region, heap) *regions,
          int j;
          sd_region *s2;
 
-         for (j = 0; VEC_iterate (sd_region, regions, j, s2); j++)
+         FOR_EACH_VEC_ELT (sd_region, regions, j, s2)
            if (s != s2)
              gcc_assert (!bb_in_sd_region (s->entry, s2));
        }
@@ -1223,7 +1147,7 @@ print_graphite_statistics (FILE* file, VEC (scop_p, heap) *scops)
   int i;
   scop_p scop;
 
-  for (i = 0; VEC_iterate (scop_p, scops, i, scop); i++)
+  FOR_EACH_VEC_ELT (scop_p, scops, i, scop)
     print_graphite_scop_statistics (file, scop);
 }
 
@@ -1255,14 +1179,14 @@ limit_scops (VEC (scop_p, heap) **scops)
   int i;
   scop_p scop;
 
-  for (i = 0; VEC_iterate (scop_p, *scops, i, scop); i++)
+  FOR_EACH_VEC_ELT (scop_p, *scops, i, scop)
     {
       int j;
       loop_p loop;
       sese region = SCOP_REGION (scop);
       build_sese_loop_nests (region);
 
-      for (j = 0; VEC_iterate (loop_p, SESE_LOOP_NEST (region), j, loop); j++)
+      FOR_EACH_VEC_ELT (loop_p, SESE_LOOP_NEST (region), j, loop)
         if (!loop_in_sese_p (loop_outer (loop), region)
            && single_exit (loop))
           {
@@ -1288,6 +1212,73 @@ limit_scops (VEC (scop_p, heap) **scops)
   VEC_free (sd_region, heap, regions);
 }
 
+/* Returns true when P1 and P2 are close phis with the same
+   argument.  */
+
+static inline bool
+same_close_phi_node (gimple p1, gimple p2)
+{
+  return operand_equal_p (gimple_phi_arg_def (p1, 0),
+                         gimple_phi_arg_def (p2, 0), 0);
+}
+
+/* Remove the close phi node at GSI and replace its rhs with the rhs
+   of PHI.  */
+
+static void
+remove_duplicate_close_phi (gimple phi, gimple_stmt_iterator *gsi)
+{
+  gimple use_stmt;
+  use_operand_p use_p;
+  imm_use_iterator imm_iter;
+  tree res = gimple_phi_result (phi);
+  tree def = gimple_phi_result (gsi_stmt (*gsi));
+
+  gcc_assert (same_close_phi_node (phi, gsi_stmt (*gsi)));
+
+  FOR_EACH_IMM_USE_STMT (use_stmt, imm_iter, def)
+    {
+      FOR_EACH_IMM_USE_ON_STMT (use_p, imm_iter)
+       SET_USE (use_p, res);
+
+      update_stmt (use_stmt);
+      
+      /* It is possible that we just created a duplicate close-phi
+        for an already-processed containing loop.  Check for this
+        case and clean it up.  */
+      if (gimple_code (use_stmt) == GIMPLE_PHI
+         && gimple_phi_num_args (use_stmt) == 1)
+       make_close_phi_nodes_unique (gimple_bb (use_stmt));
+    }
+
+  remove_phi_node (gsi, true);
+}
+
+/* Removes all the close phi duplicates from BB.  */
+
+static void
+make_close_phi_nodes_unique (basic_block bb)
+{
+  gimple_stmt_iterator psi;
+
+  for (psi = gsi_start_phis (bb); !gsi_end_p (psi); gsi_next (&psi))
+    {
+      gimple_stmt_iterator gsi = psi;
+      gimple phi = gsi_stmt (psi);
+
+      /* At this point, PHI should be a close phi in normal form.  */
+      gcc_assert (gimple_phi_num_args (phi) == 1);
+
+      /* Iterate over the next phis and remove duplicates.  */
+      gsi_next (&gsi);
+      while (!gsi_end_p (gsi))
+       if (same_close_phi_node (phi, gsi_stmt (gsi)))
+         remove_duplicate_close_phi (phi, &gsi);
+       else
+         gsi_next (&gsi);
+    }
+}
+
 /* Transforms LOOP to the canonical loop closed SSA form.  */
 
 static void
@@ -1302,7 +1293,10 @@ canonicalize_loop_closed_ssa (loop_p loop)
   bb = e->dest;
 
   if (VEC_length (edge, bb->preds) == 1)
-    split_block_after_labels (bb);
+    {
+      e = split_block_after_labels (bb);
+      make_close_phi_nodes_unique (e->src);
+    }
   else
     {
       gimple_stmt_iterator psi;
@@ -1337,7 +1331,13 @@ canonicalize_loop_closed_ssa (loop_p loop)
                update_stmt (phi);
              }
        }
+
+      make_close_phi_nodes_unique (close);
     }
+
+  /* The code above does not properly handle changes in the post dominance
+     information (yet).  */
+  free_dominance_info (CDI_POST_DOMINATORS);
 }
 
 /* Converts the current loop closed SSA form to a canonical form
@@ -1357,6 +1357,8 @@ canonicalize_loop_closed_ssa (loop_p loop)
 
    - the basic block containing the close phi nodes does not contain
    other statements.
+
+   - there exist only one phi node per definition in the loop.
 */
 
 static void
@@ -1366,7 +1368,7 @@ canonicalize_loop_closed_ssa_form (void)
   loop_p loop;
 
 #ifdef ENABLE_CHECKING
-  verify_loop_closed_ssa ();
+  verify_loop_closed_ssa (true);
 #endif
 
   FOR_EACH_LOOP (li, loop, 0)
@@ -1376,7 +1378,7 @@ canonicalize_loop_closed_ssa_form (void)
   update_ssa (TODO_update_ssa);
 
 #ifdef ENABLE_CHECKING
-  verify_loop_closed_ssa ();
+  verify_loop_closed_ssa (true);
 #endif
 }
 
@@ -1391,7 +1393,7 @@ build_scops (VEC (scop_p, heap) **scops)
 
   canonicalize_loop_closed_ssa_form ();
   build_scops_1 (single_succ (ENTRY_BLOCK_PTR), ENTRY_BLOCK_PTR->loop_father,
-                             &regions, loop);
+                &regions, loop);
   create_sese_edges (regions);
   build_graphite_scops (regions, scops);
 
@@ -1444,7 +1446,7 @@ dot_all_scops_1 (FILE *file, VEC (scop_p, heap) *scops)
       fprintf (file, "CELLSPACING=\"0\">\n");
 
       /* Select color for SCoP.  */
-      for (i = 0; VEC_iterate (scop_p, scops, i, scop); i++)
+      FOR_EACH_VEC_ELT (scop_p, scops, i, scop)
        {
          sese region = SCOP_REGION (scop);
          if (bb_in_sese_p (bb, region)
@@ -1553,7 +1555,7 @@ dot_all_scops_1 (FILE *file, VEC (scop_p, heap) *scops)
 
 /* Display all SCoPs using dotty.  */
 
-void
+DEBUG_FUNCTION void
 dot_all_scops (VEC (scop_p, heap) *scops)
 {
   /* When debugging, enable the following code.  This cannot be used
@@ -1566,7 +1568,7 @@ dot_all_scops (VEC (scop_p, heap) *scops)
   dot_all_scops_1 (stream, scops);
   fclose (stream);
 
-  x = system ("dotty /tmp/allscops.dot");
+  x = system ("dotty /tmp/allscops.dot &");
 #else
   dot_all_scops_1 (stderr, scops);
 #endif
@@ -1574,7 +1576,7 @@ dot_all_scops (VEC (scop_p, heap) *scops)
 
 /* Display all SCoPs using dotty.  */
 
-void
+DEBUG_FUNCTION void
 dot_scop (scop_p scop)
 {
   VEC (scop_p, heap) *scops = NULL;
@@ -1592,7 +1594,7 @@ dot_scop (scop_p scop)
 
     dot_all_scops_1 (stream, scops);
     fclose (stream);
-    x = system ("dotty /tmp/allscops.dot");
+    x = system ("dotty /tmp/allscops.dot &");
   }
 #else
   dot_all_scops_1 (stderr, scops);