OpenCores
URL https://opencores.org/ocsvn/openrisc/openrisc/trunk

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [gnu-old/] [gcc-4.2.2/] [gcc/] [tree-ssa-loop-unswitch.c] - Diff between revs 38 and 154

Go to most recent revision | Only display areas with differences | Details | Blame | View Log

Rev 38 Rev 154
/* Loop unswitching.
/* Loop unswitching.
   Copyright (C) 2004, 2005, 2007 Free Software Foundation, Inc.
   Copyright (C) 2004, 2005, 2007 Free Software Foundation, Inc.
 
 
This file is part of GCC.
This file is part of GCC.
 
 
GCC is free software; you can redistribute it and/or modify it
GCC is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by the
under the terms of the GNU General Public License as published by the
Free Software Foundation; either version 3, or (at your option) any
Free Software Foundation; either version 3, or (at your option) any
later version.
later version.
 
 
GCC is distributed in the hope that it will be useful, but WITHOUT
GCC is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
for more details.
for more details.
 
 
You should have received a copy of the GNU General Public License
You should have received a copy of the GNU General Public License
along with GCC; see the file COPYING3.  If not see
along with GCC; see the file COPYING3.  If not see
<http://www.gnu.org/licenses/>.  */
<http://www.gnu.org/licenses/>.  */
 
 
#include "config.h"
#include "config.h"
#include "system.h"
#include "system.h"
#include "coretypes.h"
#include "coretypes.h"
#include "tm.h"
#include "tm.h"
#include "tree.h"
#include "tree.h"
#include "rtl.h"
#include "rtl.h"
#include "tm_p.h"
#include "tm_p.h"
#include "hard-reg-set.h"
#include "hard-reg-set.h"
#include "basic-block.h"
#include "basic-block.h"
#include "output.h"
#include "output.h"
#include "diagnostic.h"
#include "diagnostic.h"
#include "tree-flow.h"
#include "tree-flow.h"
#include "tree-dump.h"
#include "tree-dump.h"
#include "timevar.h"
#include "timevar.h"
#include "cfgloop.h"
#include "cfgloop.h"
#include "domwalk.h"
#include "domwalk.h"
#include "params.h"
#include "params.h"
#include "tree-pass.h"
#include "tree-pass.h"
 
 
/* This file implements the loop unswitching, i.e. transformation of loops like
/* This file implements the loop unswitching, i.e. transformation of loops like
 
 
   while (A)
   while (A)
     {
     {
       if (inv)
       if (inv)
         B;
         B;
 
 
       X;
       X;
 
 
       if (!inv)
       if (!inv)
         C;
         C;
     }
     }
 
 
   where inv is the loop invariant, into
   where inv is the loop invariant, into
 
 
   if (inv)
   if (inv)
     {
     {
       while (A)
       while (A)
         {
         {
           B;
           B;
           X;
           X;
         }
         }
     }
     }
   else
   else
     {
     {
       while (A)
       while (A)
         {
         {
           X;
           X;
           C;
           C;
         }
         }
     }
     }
 
 
   Inv is considered invariant iff the values it compares are both invariant;
   Inv is considered invariant iff the values it compares are both invariant;
   tree-ssa-loop-im.c ensures that all the suitable conditions are in this
   tree-ssa-loop-im.c ensures that all the suitable conditions are in this
   shape.  */
   shape.  */
 
 
static struct loop *tree_unswitch_loop (struct loops *, struct loop *, basic_block,
static struct loop *tree_unswitch_loop (struct loops *, struct loop *, basic_block,
                                   tree);
                                   tree);
static bool tree_unswitch_single_loop (struct loops *, struct loop *, int);
static bool tree_unswitch_single_loop (struct loops *, struct loop *, int);
static tree tree_may_unswitch_on (basic_block, struct loop *);
static tree tree_may_unswitch_on (basic_block, struct loop *);
 
 
/* Main entry point.  Perform loop unswitching on all suitable LOOPS.  */
/* Main entry point.  Perform loop unswitching on all suitable LOOPS.  */
 
 
unsigned int
unsigned int
tree_ssa_unswitch_loops (struct loops *loops)
tree_ssa_unswitch_loops (struct loops *loops)
{
{
  int i, num;
  int i, num;
  struct loop *loop;
  struct loop *loop;
  bool changed = false;
  bool changed = false;
 
 
  /* Go through inner loops (only original ones).  */
  /* Go through inner loops (only original ones).  */
  num = loops->num;
  num = loops->num;
 
 
  for (i = 1; i < num; i++)
  for (i = 1; i < num; i++)
    {
    {
      /* Removed loop?  */
      /* Removed loop?  */
      loop = loops->parray[i];
      loop = loops->parray[i];
      if (!loop)
      if (!loop)
        continue;
        continue;
 
 
      if (loop->inner)
      if (loop->inner)
        continue;
        continue;
 
 
      changed |= tree_unswitch_single_loop (loops, loop, 0);
      changed |= tree_unswitch_single_loop (loops, loop, 0);
    }
    }
 
 
  if (changed)
  if (changed)
    return TODO_cleanup_cfg;
    return TODO_cleanup_cfg;
  return 0;
  return 0;
}
}
 
 
/* Checks whether we can unswitch LOOP on condition at end of BB -- one of its
/* Checks whether we can unswitch LOOP on condition at end of BB -- one of its
   basic blocks (for what it means see comments below).  */
   basic blocks (for what it means see comments below).  */
 
 
static tree
static tree
tree_may_unswitch_on (basic_block bb, struct loop *loop)
tree_may_unswitch_on (basic_block bb, struct loop *loop)
{
{
  tree stmt, def, cond, use;
  tree stmt, def, cond, use;
  basic_block def_bb;
  basic_block def_bb;
  ssa_op_iter iter;
  ssa_op_iter iter;
 
 
  /* BB must end in a simple conditional jump.  */
  /* BB must end in a simple conditional jump.  */
  stmt = last_stmt (bb);
  stmt = last_stmt (bb);
  if (!stmt || TREE_CODE (stmt) != COND_EXPR)
  if (!stmt || TREE_CODE (stmt) != COND_EXPR)
    return NULL_TREE;
    return NULL_TREE;
 
 
  /* Condition must be invariant.  */
  /* Condition must be invariant.  */
  FOR_EACH_SSA_TREE_OPERAND (use, stmt, iter, SSA_OP_USE)
  FOR_EACH_SSA_TREE_OPERAND (use, stmt, iter, SSA_OP_USE)
    {
    {
      def = SSA_NAME_DEF_STMT (use);
      def = SSA_NAME_DEF_STMT (use);
      def_bb = bb_for_stmt (def);
      def_bb = bb_for_stmt (def);
      if (def_bb
      if (def_bb
          && flow_bb_inside_loop_p (loop, def_bb))
          && flow_bb_inside_loop_p (loop, def_bb))
        return NULL_TREE;
        return NULL_TREE;
    }
    }
 
 
  cond = COND_EXPR_COND (stmt);
  cond = COND_EXPR_COND (stmt);
  /* To keep the things simple, we do not directly remove the conditions,
  /* To keep the things simple, we do not directly remove the conditions,
     but just replace tests with 0/1.  Prevent the infinite loop where we
     but just replace tests with 0/1.  Prevent the infinite loop where we
     would unswitch again on such a condition.  */
     would unswitch again on such a condition.  */
  if (integer_zerop (cond) || integer_nonzerop (cond))
  if (integer_zerop (cond) || integer_nonzerop (cond))
    return NULL_TREE;
    return NULL_TREE;
 
 
  return cond;
  return cond;
}
}
 
 
/* Simplifies COND using checks in front of the entry of the LOOP.  Just very
/* Simplifies COND using checks in front of the entry of the LOOP.  Just very
   simplish (sufficient to prevent us from duplicating loop in unswitching
   simplish (sufficient to prevent us from duplicating loop in unswitching
   unnecessarily).  */
   unnecessarily).  */
 
 
static tree
static tree
simplify_using_entry_checks (struct loop *loop, tree cond)
simplify_using_entry_checks (struct loop *loop, tree cond)
{
{
  edge e = loop_preheader_edge (loop);
  edge e = loop_preheader_edge (loop);
  tree stmt;
  tree stmt;
 
 
  while (1)
  while (1)
    {
    {
      stmt = last_stmt (e->src);
      stmt = last_stmt (e->src);
      if (stmt
      if (stmt
          && TREE_CODE (stmt) == COND_EXPR
          && TREE_CODE (stmt) == COND_EXPR
          && operand_equal_p (COND_EXPR_COND (stmt), cond, 0))
          && operand_equal_p (COND_EXPR_COND (stmt), cond, 0))
        return (e->flags & EDGE_TRUE_VALUE
        return (e->flags & EDGE_TRUE_VALUE
                ? boolean_true_node
                ? boolean_true_node
                : boolean_false_node);
                : boolean_false_node);
 
 
      if (!single_pred_p (e->src))
      if (!single_pred_p (e->src))
        return cond;
        return cond;
 
 
      e = single_pred_edge (e->src);
      e = single_pred_edge (e->src);
      if (e->src == ENTRY_BLOCK_PTR)
      if (e->src == ENTRY_BLOCK_PTR)
        return cond;
        return cond;
    }
    }
}
}
 
 
/* Unswitch single LOOP.  NUM is number of unswitchings done; we do not allow
/* Unswitch single LOOP.  NUM is number of unswitchings done; we do not allow
   it to grow too much, it is too easy to create example on that the code would
   it to grow too much, it is too easy to create example on that the code would
   grow exponentially.  */
   grow exponentially.  */
 
 
static bool
static bool
tree_unswitch_single_loop (struct loops *loops, struct loop *loop, int num)
tree_unswitch_single_loop (struct loops *loops, struct loop *loop, int num)
{
{
  basic_block *bbs;
  basic_block *bbs;
  struct loop *nloop;
  struct loop *nloop;
  unsigned i;
  unsigned i;
  tree cond = NULL_TREE, stmt;
  tree cond = NULL_TREE, stmt;
  bool changed = false;
  bool changed = false;
 
 
  /* Do not unswitch too much.  */
  /* Do not unswitch too much.  */
  if (num > PARAM_VALUE (PARAM_MAX_UNSWITCH_LEVEL))
  if (num > PARAM_VALUE (PARAM_MAX_UNSWITCH_LEVEL))
    {
    {
      if (dump_file && (dump_flags & TDF_DETAILS))
      if (dump_file && (dump_flags & TDF_DETAILS))
        fprintf (dump_file, ";; Not unswitching anymore, hit max level\n");
        fprintf (dump_file, ";; Not unswitching anymore, hit max level\n");
      return false;
      return false;
    }
    }
 
 
  /* Only unswitch innermost loops.  */
  /* Only unswitch innermost loops.  */
  if (loop->inner)
  if (loop->inner)
    {
    {
      if (dump_file && (dump_flags & TDF_DETAILS))
      if (dump_file && (dump_flags & TDF_DETAILS))
        fprintf (dump_file, ";; Not unswitching, not innermost loop\n");
        fprintf (dump_file, ";; Not unswitching, not innermost loop\n");
      return false;
      return false;
    }
    }
 
 
  /* The loop should not be too large, to limit code growth.  */
  /* The loop should not be too large, to limit code growth.  */
  if (tree_num_loop_insns (loop)
  if (tree_num_loop_insns (loop)
      > (unsigned) PARAM_VALUE (PARAM_MAX_UNSWITCH_INSNS))
      > (unsigned) PARAM_VALUE (PARAM_MAX_UNSWITCH_INSNS))
    {
    {
      if (dump_file && (dump_flags & TDF_DETAILS))
      if (dump_file && (dump_flags & TDF_DETAILS))
        fprintf (dump_file, ";; Not unswitching, loop too big\n");
        fprintf (dump_file, ";; Not unswitching, loop too big\n");
      return false;
      return false;
    }
    }
 
 
  i = 0;
  i = 0;
  bbs = get_loop_body (loop);
  bbs = get_loop_body (loop);
 
 
  while (1)
  while (1)
    {
    {
      /* Find a bb to unswitch on.  */
      /* Find a bb to unswitch on.  */
      for (; i < loop->num_nodes; i++)
      for (; i < loop->num_nodes; i++)
        if ((cond = tree_may_unswitch_on (bbs[i], loop)))
        if ((cond = tree_may_unswitch_on (bbs[i], loop)))
          break;
          break;
 
 
      if (i == loop->num_nodes)
      if (i == loop->num_nodes)
        {
        {
          free (bbs);
          free (bbs);
          return changed;
          return changed;
        }
        }
 
 
      cond = simplify_using_entry_checks (loop, cond);
      cond = simplify_using_entry_checks (loop, cond);
      stmt = last_stmt (bbs[i]);
      stmt = last_stmt (bbs[i]);
      if (integer_nonzerop (cond))
      if (integer_nonzerop (cond))
        {
        {
          /* Remove false path.  */
          /* Remove false path.  */
          COND_EXPR_COND (stmt) = boolean_true_node;
          COND_EXPR_COND (stmt) = boolean_true_node;
          changed = true;
          changed = true;
        }
        }
      else if (integer_zerop (cond))
      else if (integer_zerop (cond))
        {
        {
          /* Remove true path.  */
          /* Remove true path.  */
          COND_EXPR_COND (stmt) = boolean_false_node;
          COND_EXPR_COND (stmt) = boolean_false_node;
          changed = true;
          changed = true;
        }
        }
      else
      else
        break;
        break;
 
 
      update_stmt (stmt);
      update_stmt (stmt);
      i++;
      i++;
    }
    }
 
 
  if (dump_file && (dump_flags & TDF_DETAILS))
  if (dump_file && (dump_flags & TDF_DETAILS))
    fprintf (dump_file, ";; Unswitching loop\n");
    fprintf (dump_file, ";; Unswitching loop\n");
 
 
  initialize_original_copy_tables ();
  initialize_original_copy_tables ();
  /* Unswitch the loop on this condition.  */
  /* Unswitch the loop on this condition.  */
  nloop = tree_unswitch_loop (loops, loop, bbs[i], cond);
  nloop = tree_unswitch_loop (loops, loop, bbs[i], cond);
  if (!nloop)
  if (!nloop)
    {
    {
      free_original_copy_tables ();
      free_original_copy_tables ();
      free (bbs);
      free (bbs);
      return changed;
      return changed;
    }
    }
 
 
  /* Update the SSA form after unswitching.  */
  /* Update the SSA form after unswitching.  */
  update_ssa (TODO_update_ssa);
  update_ssa (TODO_update_ssa);
  free_original_copy_tables ();
  free_original_copy_tables ();
 
 
  /* Invoke itself on modified loops.  */
  /* Invoke itself on modified loops.  */
  tree_unswitch_single_loop (loops, nloop, num + 1);
  tree_unswitch_single_loop (loops, nloop, num + 1);
  tree_unswitch_single_loop (loops, loop, num + 1);
  tree_unswitch_single_loop (loops, loop, num + 1);
  free (bbs);
  free (bbs);
  return true;
  return true;
}
}
 
 
/* Unswitch a LOOP w.r. to given basic block UNSWITCH_ON.  We only support
/* Unswitch a LOOP w.r. to given basic block UNSWITCH_ON.  We only support
   unswitching of innermost loops.  COND is the condition determining which
   unswitching of innermost loops.  COND is the condition determining which
   loop is entered -- the new loop is entered if COND is true.  Returns NULL
   loop is entered -- the new loop is entered if COND is true.  Returns NULL
   if impossible, new loop otherwise.  */
   if impossible, new loop otherwise.  */
 
 
static struct loop *
static struct loop *
tree_unswitch_loop (struct loops *loops, struct loop *loop,
tree_unswitch_loop (struct loops *loops, struct loop *loop,
                    basic_block unswitch_on, tree cond)
                    basic_block unswitch_on, tree cond)
{
{
  basic_block condition_bb;
  basic_block condition_bb;
 
 
  /* Some sanity checking.  */
  /* Some sanity checking.  */
  gcc_assert (flow_bb_inside_loop_p (loop, unswitch_on));
  gcc_assert (flow_bb_inside_loop_p (loop, unswitch_on));
  gcc_assert (EDGE_COUNT (unswitch_on->succs) == 2);
  gcc_assert (EDGE_COUNT (unswitch_on->succs) == 2);
  gcc_assert (loop->inner == NULL);
  gcc_assert (loop->inner == NULL);
 
 
  return loop_version (loops, loop, unshare_expr (cond),
  return loop_version (loops, loop, unshare_expr (cond),
                       &condition_bb, false);
                       &condition_bb, false);
}
}
 
 

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.