OSDN Git Service

2001-07-16 Daniel Berlin <dan@cgsoftware.com>
authordberlin <dberlin@138bc75d-0d04-0410-961f-82ee72b054a4>
Fri, 3 Aug 2001 16:52:01 +0000 (16:52 +0000)
committerdberlin <dberlin@138bc75d-0d04-0410-961f-82ee72b054a4>
Fri, 3 Aug 2001 16:52:01 +0000 (16:52 +0000)
        * gcse.c: Include df.h for use as a dataflow analyzer.
        Remove regvec.
        Declaration of reg_set_info: gone.
        New df_analyzer variable used by store motion.
        (reg_set_info): Deleted.
        (mark_mem_regs): New function, analyze regs used by a mem.
        (store_ops_ok): Use dataflow analyzer results to determine if
        necessary regs are changed in the block.
        (find_moveable_store): Remove check for symbol ref, we can handle
        much more complex expressions now.
        (compute_store_table): Remove most of the code, it's unnecessary
        now that the dataflow analyzer records the info for us.
        (store_killed_after): Add parameter to say whether to do the
        store_ops_okay test, used to speed up testing when we already know
        the answer, and just want to know if the store itself was killed.
        (build_store_vector): Largely rewritten to calculate the various
        vectors properly, and somewhat optimized.
        (store_motion): Init the df_analyzer, get REG_DEF chains.
        Also handle trapping expressions (since mems almost always trap)
        (simple_mem): Redefine what a simple mem is.

git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@44603 138bc75d-0d04-0410-961f-82ee72b054a4

gcc/ChangeLog
gcc/gcse.c

index 3ffebfd..58e4658 100644 (file)
@@ -1,3 +1,26 @@
+2001-07-16  Daniel Berlin  <dan@cgsoftware.com>
+
+        * gcse.c: Include df.h for use as a dataflow analyzer.
+        Remove regvec.
+        Declaration of reg_set_info: gone.
+        New df_analyzer variable used by store motion.
+        (reg_set_info): Deleted.
+        (mark_mem_regs): New function, analyze regs used by a mem.
+        (store_ops_ok): Use dataflow analyzer results to determine if
+        necessary regs are changed in the block.
+        (find_moveable_store): Remove check for symbol ref, we can handle
+        much more complex expressions now.
+        (compute_store_table): Remove most of the code, it's unnecessary
+        now that the dataflow analyzer records the info for us.
+        (store_killed_after): Add parameter to say whether to do the
+        store_ops_okay test, used to speed up testing when we already know
+        the answer, and just want to know if the store itself was killed.
+        (build_store_vector): Largely rewritten to calculate the various
+        vectors properly, and somewhat optimized.
+        (store_motion): Init the df_analyzer, get REG_DEF chains. 
+        Also handle trapping expressions (since mems almost always trap)
+        (simple_mem): Redefine what a simple mem is.
+
 2001-08-03  DJ Delorie  <dj@redhat.com>
 
        * ifcvt.c (noce_get_alt_condition): Don't make an auxiliary
index 4fe1b3b..349eae6 100644 (file)
@@ -160,8 +160,8 @@ Boston, MA 02111-1307, USA.  */
 #include "expr.h" 
 #include "ggc.h"
 #include "params.h"
-
 #include "obstack.h"
+#include "df.h"
 #define obstack_chunk_alloc gmalloc
 #define obstack_chunk_free free
 
@@ -305,6 +305,10 @@ static char can_copy_p[(int) NUM_MACHINE_MODES];
 /* Non-zero if can_copy_p has been initialized.  */
 static int can_copy_init_p;
 
+/* Dataflow analyzer  */
+struct df *df_analyzer;
+
+
 struct reg_use {rtx reg_rtx; };
 
 /* Hash table of expressions.  */
@@ -466,8 +470,8 @@ struct ls_expr
 {
   struct expr * expr;          /* Gcse expression reference for LM.  */
   rtx pattern;                 /* Pattern of this mem.  */
-  rtx loads;                   /* INSN list of loads seen.  */
-  rtx stores;                  /* INSN list of stores seen.  */
+  rtx loads;                   /* INSN list for where load appears */
+  rtx stores;                  /* INSN list for where store appears */
   struct ls_expr * next;       /* Next in the list.  */
   int invalid;                 /* Invalid for some reason.  */
   int index;                   /* If it maps to a bitmap index.  */
@@ -676,14 +680,13 @@ static void invalidate_any_buried_refs    PARAMS ((rtx));
 static void compute_ld_motion_mems     PARAMS ((void)); 
 static void trim_ld_motion_mems                PARAMS ((void));
 static void update_ld_motion_stores    PARAMS ((struct expr *));
-static void reg_set_info               PARAMS ((rtx, rtx, void *));
-static int store_ops_ok                        PARAMS ((rtx, basic_block));
+static int store_ops_ok                        PARAMS ((rtx, basic_block, rtx, int));
 static void find_moveable_store                PARAMS ((rtx));
 static int compute_store_table         PARAMS ((void));
 static int load_kills_store            PARAMS ((rtx, rtx));
 static int find_loads                  PARAMS ((rtx, rtx));
 static int store_killed_in_insn                PARAMS ((rtx, rtx));
-static int store_killed_after          PARAMS ((rtx, rtx, basic_block));
+static int store_killed_after          PARAMS ((rtx, rtx, basic_block, int));
 static int store_killed_before         PARAMS ((rtx, rtx, basic_block));
 static void build_store_vectors                PARAMS ((void));
 static void insert_insn_start_bb       PARAMS ((rtx, basic_block));
@@ -1466,7 +1469,6 @@ mems_conflict_for_gcse_p (dest, setter, data)
      elsewhere.  */
   if (GET_CODE (dest) != MEM)
     return;
-
   /* If we are setting a MEM in our list of specially recognized MEMs,
      don't mark as killed this time.  */ 
   
@@ -1476,7 +1478,6 @@ mems_conflict_for_gcse_p (dest, setter, data)
        gcse_mems_conflict_p = 1;
       return;
     }
-
   if (true_dependence (dest, GET_MODE (dest), gcse_mem_operand,
                       rtx_addr_varies_p))
     gcse_mems_conflict_p = 1;
@@ -1754,6 +1755,7 @@ hash_expr_1 (x, mode, do_not_record_p)
        hash += hash_string_1 (XSTR (x, i));
       else if (fmt[i] == 'i')
        hash += (unsigned int) XINT (x, i);
+      else if (fmt[i] == 't');
       else
        abort ();
     }
@@ -1912,8 +1914,9 @@ expr_equiv_p (x, y)
        break;
 
        case '0':
+       case 't':
          break;
-
+       
        default:
          abort ();
        }
@@ -5896,9 +5899,9 @@ static void
 free_ldst_entry (ptr)
      struct ls_expr * ptr;
 {
-  free_INSN_LIST_list (& ptr->loads);
-  free_INSN_LIST_list (& ptr->stores);
 
+  free_INSN_LIST_list (&ptr->stores);
+  free_INSN_LIST_list (&ptr->loads);
   free (ptr);
 }
 
@@ -6019,10 +6022,11 @@ simple_mem (x)
   
   if (GET_MODE (x) == BLKmode)
     return 0;
-
-  if (!rtx_varies_p (XEXP (x, 0), 0))
+#if 0
+  /* See comment in find_moveable_store */
+  if (!rtx_addr_varies_p (XEXP (x, 0), 0))
     return 1;
-  
+#endif
   return 0;
 }
 
@@ -6104,7 +6108,6 @@ compute_ld_motion_mems ()
                      /* Make sure there isn't a buried load somewhere.  */
                      invalidate_any_buried_refs (src);
                    }
-                 
                  /* Check for stores. Don't worry about aliased ones, they
                     will block any movement we might do later. We only care
                     about this exact pattern since those are the only
@@ -6251,37 +6254,59 @@ update_ld_motion_stores (expr)
 \f
 /* Store motion code.  */
 
-/* This is used to communicate the target bitvector we want to use in the 
-   reg_set_info routine when called via the note_stores mechanism.  */
-static sbitmap * regvec;
-
 /* Used in computing the reverse edge graph bit vectors.  */
 static sbitmap * st_antloc;
 
 /* Global holding the number of store expressions we are dealing with.  */
 static int num_stores;
 
-/* Checks to set if we need to mark a register set. Called from note_stores.  */
 
-static void
-reg_set_info (dest, setter, data)
-     rtx dest, setter ATTRIBUTE_UNUSED;
-     void * data ATTRIBUTE_UNUSED;
+/* Mark which registers are used by the mem, in the sbitmap used. */
+static int
+mark_mem_regs (x, used)
+     rtx x;
+     sbitmap used;
 {
-  if (GET_CODE (dest) == SUBREG)
-    dest = SUBREG_REG (dest);
+  register const char *fmt;
+  int i, j;
 
-  if (GET_CODE (dest) == REG)
-    SET_BIT (*regvec, REGNO (dest));
+  if (GET_CODE (x) == REG)
+    {
+      if (!TEST_BIT (used, REGNO (x)))
+       {
+         SET_BIT (used, REGNO (x));
+         return 1;
+}
+      return 0;
+    }
+
+  fmt = GET_RTX_FORMAT (GET_CODE (x));
+  for (i = GET_RTX_LENGTH (GET_CODE (x)) - 1; i >= 0; i--)
+    {
+      if (fmt[i] == 'e')
+       {
+         if (mark_mem_regs (XEXP (x, i),used))
+           return 1;
+       }
+      else if (fmt[i] == 'E')
+       for (j = XVECLEN (x, i) - 1; j >= 0; j--)
+         if (mark_mem_regs (XVECEXP (x, i, j),used))
+           return 1;
+    }
+
+  return 0;
 }
 
+
 /* Return non-zero if the register operands of expression X are killed 
-   anywhere in basic block BB.  */
+   before/after insn in basic block BB.  */
 
 static int
-store_ops_ok (x, bb)
+store_ops_ok (x, bb,insn, before)
      rtx x;
      basic_block bb;
+     rtx insn;
+     int before;
 {
   int i;
   enum rtx_code code;
@@ -6297,10 +6322,46 @@ store_ops_ok (x, bb)
   switch (code)
     {
     case REG:
-       /* If a reg has changed after us in this
-          block, the operand has been killed.  */
-       return TEST_BIT (reg_set_in_block[bb->index], REGNO (x));
+       {
+         /* Okay, since the reg def chains are ordered by bb/insn
+            (since that's how it calculates them, and even if it didn't,
+            we could just sort them), we just walk until we find a def
+            in our BB, then walk until we find a def after/before our
+            insn, and if we find a reg def after/before our insn, in the
+            same bb, we return the approriate value.  If there is no
+            such def, to prevent walking *every* reg def, we stop once
+            we are out of our BB again. */
+         struct df_link *currref;
+         bool thereyet=FALSE;
+         for (currref = df_analyzer->regs[REGNO(x)].defs;
+              currref;
+              currref = currref->next)
+           {
+             if (! (DF_REF_BB (currref->ref)  == bb))
+               {
+                 if (!thereyet)
+                   continue;
+                 else 
+                   return 1;
+               }
+             if (before)
+               {
+                 if (INSN_UID (DF_REF_INSN (currref->ref)) >= INSN_UID (insn))
+                   continue;
+               }
+             else
+               {
+                 if (INSN_UID (DF_REF_INSN (currref->ref)) < INSN_UID (insn))
+                   continue;
+               }
+             thereyet = TRUE;
+             if (DF_REF_TYPE (currref->ref) == DF_REF_REG_DEF)
+               return 0;
+           }
+         return 1;
+       }
 
+       
     case MEM:
       x = XEXP (x, 0);
       goto repeat;
@@ -6344,7 +6405,7 @@ store_ops_ok (x, bb)
              goto repeat;
            }
          
-         if (! store_ops_ok (tem, bb))
+         if (! store_ops_ok (tem, bb, insn, before))
            return 0;
        }
       else if (fmt[i] == 'E')
@@ -6353,7 +6414,7 @@ store_ops_ok (x, bb)
          
          for (j = 0; j < XVECLEN (x, i); j++)
            {
-             if (! store_ops_ok (XVECEXP (x, i, j), bb))
+             if (! store_ops_ok (XVECEXP (x, i, j), bb, insn, before))
                return 0;
            }
        }
@@ -6362,7 +6423,9 @@ store_ops_ok (x, bb)
   return 1;
 }
 
-/* Determine whether insn is MEM store pattern that we will consider moving.  */
+/* Determine whether insn is MEM store pattern that we will consider
+   moving.  We'll consider moving pretty much anything that we can
+   move safely. */
 
 static void
 find_moveable_store (insn)
@@ -6371,6 +6434,9 @@ find_moveable_store (insn)
   struct ls_expr * ptr;
   rtx dest = PATTERN (insn);
 
+  /* It's it's not a set, it's not a mem store we want to consider.
+     Also, if it's an ASM, we certainly don't want to try to touch
+     it. */
   if (GET_CODE (dest) != SET
       || GET_CODE (SET_SRC (dest)) == ASM_OPERANDS)
     return;
@@ -6379,66 +6445,43 @@ find_moveable_store (insn)
   
   if (GET_CODE (dest) != MEM || MEM_VOLATILE_P (dest)
       || GET_MODE (dest) == BLKmode)
-    return;
-
-  if (GET_CODE (XEXP (dest, 0)) != SYMBOL_REF)
       return;
-
-  if (rtx_varies_p (XEXP (dest, 0), 0))
+#if 0
+  /* ??? Is this conservative, or just correct? We get more
+     *candidates* without it, but i don't think we ever remove any
+     stores where the address did vary. */
+  if (rtx_addr_varies_p (XEXP (dest, 0), 0))
     return;
-
+#endif
   ptr = ldst_entry (dest);
   ptr->stores = alloc_INSN_LIST (insn, ptr->stores);
 }
 
-/* Perform store motion. Much like gcse, except we move expressions the
-   other way by looking at the flowgraph in reverse.  */
+/* Perform store motion. 
+   Store motion is modeled as a lazy code motion problem, like PRE is
+   above. The main diffence is that we want to move stores down as far
+   as possible, so we have LCM work on the reverse flowgraph. */
 
 static int
 compute_store_table ()
 {
   int bb, ret;
-  unsigned regno;
   rtx insn, pat;
-
   max_gcse_regno = max_reg_num ();
 
-  reg_set_in_block = (sbitmap *) sbitmap_vector_alloc (n_basic_blocks,
-                                                      max_gcse_regno);
-  sbitmap_vector_zero (reg_set_in_block, n_basic_blocks);
   pre_ldst_mems = 0;
-
   /* Find all the stores we care about.  */
   for (bb = 0; bb < n_basic_blocks; bb++)
     {
-      regvec = & (reg_set_in_block[bb]);
       for (insn = BLOCK_END (bb);
           insn && insn != PREV_INSN (BLOCK_HEAD (bb));
           insn = PREV_INSN (insn))
        {
-#ifdef NON_SAVING_SETJMP 
-         if (NON_SAVING_SETJMP && GET_CODE (insn) == NOTE
-             && NOTE_LINE_NUMBER (insn) == NOTE_INSN_SETJMP)
-           {
-             for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
-               SET_BIT (reg_set_in_block[bb], regno);
-             continue;
-           }
-#endif
-       /* Ignore anything that is not a normal insn.  */
-       if (GET_RTX_CLASS (GET_CODE (insn)) != 'i')
+         /* Ignore anything that is not a normal insn.  */
+         if (!INSN_P (insn))
            continue;
 
-         if (GET_CODE (insn) == CALL_INSN)
-           {
-             for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
-               if (TEST_HARD_REG_BIT (regs_invalidated_by_call, regno))
-                 SET_BIT (reg_set_in_block[bb], regno);
-           }
-         
          pat = PATTERN (insn);
-         note_stores (pat, reg_set_info, NULL);
-         
          /* Now that we've marked regs, look for stores.  */
          if (GET_CODE (pat) == SET)
            find_moveable_store (insn);
@@ -6456,7 +6499,8 @@ compute_store_table ()
   return ret;
 }
 
-/* Check to see if the load X is aliased with STORE_PATTERN.  */
+/* Check to see if the load X is aliased with STORE_PATTERN. 
+   If it is, it means that load kills the store.*/
 
 static int
 load_kills_store (x, store_pattern)
@@ -6467,8 +6511,8 @@ load_kills_store (x, store_pattern)
   return 0;
 }
 
-/* Go through the entire insn X, looking for any loads which might alias 
-   STORE_PATTERN.  Return 1 if found.  */
+/* Go through the entire insn X, looking for any loads which might
+   alias, and therefore, kill, STORE_PATTERN.  Return 1 if found.  */
 
 static int
 find_loads (x, store_pattern)
@@ -6524,9 +6568,10 @@ store_killed_in_insn (x, insn)
       rtx pat = PATTERN (insn);
       /* Check for memory stores to aliased objects.  */
       if (GET_CODE (SET_DEST (pat)) == MEM && !expr_equiv_p (SET_DEST (pat), x))
-       /* pretend its a load and check for aliasing.  */
+       {
        if (find_loads (SET_DEST (pat), x))
          return 1;
+       }
       return find_loads (SET_SRC (pat), x);
     }
   else
@@ -6537,31 +6582,31 @@ store_killed_in_insn (x, insn)
    within basic block BB.  */
 
 static int 
-store_killed_after (x, insn, bb)
+store_killed_after (x, insn, bb, testops)
      rtx x, insn;
      basic_block bb;
+     int testops;
 {
    rtx last = bb->end;
    
    if (insn == last)
      return 0;
-
-  /* Check if the register operands of the store are OK in this block.
-     Note that if registers are changed ANYWHERE in the block, we'll 
-     decide we can't move it, regardless of whether it changed above 
-     or below the store. This could be improved by checking the register
-     operands while lookinng for aliasing in each insn.  */
-  if (!store_ops_ok (XEXP (x, 0), bb))
+   
+   if (testops)
+     /* Check if the register operands of the store are OK in this block.*/
+     if (!store_ops_ok (XEXP (x, 0), bb, insn, 0))
     return 1;
 
-   for ( ; insn && insn != NEXT_INSN (last); insn = NEXT_INSN (insn))
+   for ( ; 
+        insn && insn != NEXT_INSN (last); 
+        insn = NEXT_INSN (insn))
      if (store_killed_in_insn (x, insn))
        return 1;
    
   return 0;
 }
 
-/* Returns 1 if the expression X is loaded or clobbered on or before INSN
+/* Returns 1 if the expression X is loaded or clobbered before INSN
    within basic block BB.  */
 static int 
 store_killed_before (x, insn, bb)
@@ -6572,16 +6617,14 @@ store_killed_before (x, insn, bb)
 
    if (insn == first)
      return store_killed_in_insn (x, insn);
-   
-  /* Check if the register operands of the store are OK in this block.
-     Note that if registers are changed ANYWHERE in the block, we'll 
-     decide we can't move it, regardless of whether it changed above 
-     or below the store. This could be improved by checking the register
-     operands while lookinng for aliasing in each insn.  */
-  if (!store_ops_ok (XEXP (x, 0), bb))
+   /* Check if the register operands of the store are OK in this block.*/
+   if (!store_ops_ok (XEXP (x, 0), bb, insn, 1))
     return 1;
 
-   for ( ; insn && insn != PREV_INSN (first); insn = PREV_INSN (insn))
+   for (insn = PREV_INSN (insn) ; 
+       insn && insn != PREV_INSN (first); 
+       insn = PREV_INSN (insn))
+     
      if (store_killed_in_insn (x, insn))
        return 1;
    
@@ -6598,9 +6641,11 @@ static void
 build_store_vectors () 
 {
   basic_block bb;
-  int b;
+  int b,i,j;
   rtx insn, st;
   struct ls_expr * ptr;
+  sbitmap tested, *result;
+  sbitmap used;
 
   /* Build the gen_vector. This is any store in the table which is not killed
      by aliasing later in its block.  */
@@ -6609,7 +6654,16 @@ build_store_vectors ()
 
   st_antloc = (sbitmap *) sbitmap_vector_alloc (n_basic_blocks, num_stores);
   sbitmap_vector_zero (st_antloc, n_basic_blocks);
-
+  
+  /* Note: In case someone needs something to optimize about store
+     motion, here's the next place to look.  We currently test one more
+     basic block per store than necessary (at least).  Since we know, at
+     the end of this for loop, whether a store was killed in one of the
+     basic blocks (We know both whether it's killed before, and killed
+     after, the insn in the bb it resides in. So unless the insn
+     consists of multiple store/loads, we know whether it was killed
+     in the entire bb), we could avoid testing it for kill and transp in
+     the next for loop. */
   for (ptr = first_ls_expr (); ptr != NULL; ptr = next_ls_expr (ptr))
     { 
       /* Put all the stores into either the antic list, or the avail list,
@@ -6621,8 +6675,7 @@ build_store_vectors ()
        {
          insn = XEXP (st, 0);
          bb = BLOCK_FOR_INSN (insn);
-         
-         if (!store_killed_after (ptr->pattern, insn, bb))
+         if (!store_killed_after (ptr->pattern, insn, bb, 1))
            {
              /* If we've already seen an availale expression in this block,
                 we can delete the one we saw already (It occurs earlier in
@@ -6666,50 +6719,142 @@ build_store_vectors ()
   ae_kill = (sbitmap *) sbitmap_vector_alloc (n_basic_blocks, num_stores);
   sbitmap_vector_zero (ae_kill, n_basic_blocks);
 
+
   transp = (sbitmap *) sbitmap_vector_alloc (n_basic_blocks, num_stores);
-  sbitmap_vector_zero (transp, n_basic_blocks);
+  sbitmap_vector_ones (transp, n_basic_blocks);
+
+  tested = sbitmap_alloc (max_gcse_regno);
+  sbitmap_zero (tested);
+  result = sbitmap_vector_alloc (n_basic_blocks, max_gcse_regno);
+  sbitmap_vector_zero (result, n_basic_blocks);
+  used = sbitmap_alloc (max_gcse_regno);
+  sbitmap_zero (used);
+
+  /* This whole big nasty thing computes kill and transparent.
+     It's done in this nasty way because profiling showed store motion
+     taking twice as long as GCSE, with the cause being 1 million calls
+     to store_ops_ok taking 30% of the entire runtime of the
+     compiler. 
+     Since store most expressions use the same registers, there's no
+     point in checking them 8 million times for the same basic blocks. If
+     they weren't okay in a BB the last time we checked, they won't be
+     okay now. Since we check all the bb's on each iteration, we don't
+     need a vector for which registers we've tested, just the results.
+     We then proceed to use the results of what store_ops_ok was for a
+     given reg and bb, and if the results were a kill, we don't even need
+     to check if the store was killed in the basic block, it'll be
+     in the kill set because it's regs changed between here and there.
+
+     
+     If the whole store had no registers, we just skip store_ops_okay
+     anyway (since it's checking reg operands), and proceed to see if
+     it's okay in each bb, setting the approriate bits.
+
+     With this in place, we now take almost no time at all to perform
+     store motion. (It's not on the first page of the profile, it
+     takes less than a second).
+     
+  */
 
   for (ptr = first_ls_expr (); ptr != NULL; ptr = next_ls_expr (ptr))
-    for (b = 0; b < n_basic_blocks; b++)
       {
-       if (store_killed_after (ptr->pattern, BLOCK_HEAD (b), BASIC_BLOCK (b)))
+      /* Make sure we don't have a load-only expr, which we never seem
+        to, but i don't think there's actually a guarantee */
+      if (ptr->stores != NULL)
          {
-           /* The anticipatable expression is not killed if it's gen'd. */
-           /*
-             We leave this check out for now. If we have a code sequence 
-             in a block which looks like:
-                       ST MEMa = x
-                       L     y = MEMa
-                       ST MEMa = z
-             We should flag this as having an ANTIC expression, NOT
-             transparent, NOT killed, and AVAIL.
-             Unfortunately, since we haven't re-written all loads to
-             use the reaching reg, we'll end up doing an incorrect 
-             Load in the middle here if we push the store down. It happens in
-                   gcc.c-torture/execute/960311-1.c with -O3
-             If we always kill it in this case, we'll sometimes do
-             uneccessary work, but it shouldn't actually hurt anything.
-           if (!TEST_BIT (ae_gen[b], ptr->index)).  */
-           SET_BIT (ae_kill[b], ptr->index);
-         }
-       else
-         SET_BIT (transp[b], ptr->index);
-      }
-
-  /* Any block with no exits calls some non-returning function, so
-     we better mark the store killed here, or we might not store to
-     it at all.  If we knew it was abort, we wouldn't have to store,
-     but we don't know that for sure.  */
-  if (gcse_file) 
-    {
-      fprintf (gcse_file, "ST_avail and ST_antic (shown under loads..)\n");
-      print_ldst_list (gcse_file);
-      dump_sbitmap_vector (gcse_file, "st_antloc", "", st_antloc, n_basic_blocks);
-      dump_sbitmap_vector (gcse_file, "st_kill", "", ae_kill, n_basic_blocks);
-      dump_sbitmap_vector (gcse_file, "Transpt", "", transp, n_basic_blocks);
-      dump_sbitmap_vector (gcse_file, "st_avloc", "", ae_gen, n_basic_blocks);
+         /* First mark the regs used by the mem */
+         mark_mem_regs (ptr->pattern, used);
+         /* Now see if it had any regs */
+         if (!(sbitmap_first_set_bit (used) == -1))
+           {
+             /* For each register, see if we've tested it */
+             EXECUTE_IF_SET_IN_SBITMAP (used, 0, i, 
+             {
+               if (TEST_BIT (tested, i))
+                 {
+                   /* Already tested the register, so check the
+                      result, and if we had an okay result, check the
+                      store itself. */
+                   for (j = 0; j < n_basic_blocks; j++)
+                     {
+                       if (!TEST_BIT (result[j], i) 
+                           || store_killed_after (ptr->pattern, BLOCK_HEAD (j), 
+                                                  BASIC_BLOCK (j), FALSE))
+                         {
+                           SET_BIT (ae_kill[j], ptr->index);
+                           if (!TEST_BIT (ae_gen[j], ptr->index)
+                               || !TEST_BIT (st_antloc[j], ptr->index))
+                             RESET_BIT (transp[j], ptr->index);
+                         }
+                     }
+                 }
+               else
+                 {
+                   /* We haven't tested it yet, so mark it tested,
+                      and perform the tests */
+                   SET_BIT (tested, i);
+                   /* Check if it's okay in each BB */
+                   for (j = 0; j < n_basic_blocks; j++)
+                     {
+                       if (store_ops_ok (XEXP (ptr->pattern, 0), 
+                                         BASIC_BLOCK (j), BLOCK_HEAD (j), 0))
+                         {
+                           SET_BIT (result[j], ptr->index);
+                         }
+                       else
+                         {
+                           /* It's not okay, so it's killed and maybe
+                              not transparent */
+                           SET_BIT (ae_kill[j], ptr->index);
+                           if (!TEST_BIT (ae_gen[j], ptr->index)
+                               || !TEST_BIT (st_antloc[j], ptr->index))
+                             {
+                               RESET_BIT (transp[j], ptr->index);
+                             }
+                           continue;
+                         }
+                       /* The ops were okay, so check the store
+                          itself */
+                       if (store_killed_after (ptr->pattern, BLOCK_HEAD (j), 
+                                               BASIC_BLOCK (j), FALSE))
+                         {
+                           SET_BIT (ae_kill[j], ptr->index);
+                           if (!TEST_BIT (ae_gen[j], ptr->index)
+                               || !TEST_BIT (st_antloc[j], ptr->index))
+                             {
+                               RESET_BIT (transp[j], ptr->index);
+                             }
+                         }
+                     }
+                 }
+             });
+             /* Reset the used list */
+             sbitmap_zero (used);
+           }
+         /* If it had no registers, we come here, and do the
+            approriate testing */
+         else
+           {
+             for (j = 0; j < n_basic_blocks; j++)
+               {
+                 if (store_killed_after (ptr->pattern, BLOCK_HEAD (j), 
+                                         BASIC_BLOCK (j), FALSE))
+                   {
+                     SET_BIT (ae_kill[j], ptr->index);
+                     if (!TEST_BIT (ae_gen[j], ptr->index)
+                         || !TEST_BIT (st_antloc[j], ptr->index))
+                       {
+                         RESET_BIT (transp[j], ptr->index);
+                       }
+                   }
+               }
+           }  
     }
 }
+  sbitmap_free (tested);
+  sbitmap_free (used);
+  sbitmap_vector_free (result);
+}
 
 /* Insert an instruction at the begining of a basic block, and update 
    the BLOCK_HEAD if needed.  */
@@ -6888,7 +7033,6 @@ static void
 free_store_memory ()
 {
   free_ldst_mems ();
-  
   if (ae_gen)
     sbitmap_vector_free (ae_gen);
   if (ae_kill)
@@ -6901,8 +7045,6 @@ free_store_memory ()
     sbitmap_vector_free (pre_insert_map);
   if (pre_delete_map)
     sbitmap_vector_free (pre_delete_map);
-  if (reg_set_in_block)
-    sbitmap_vector_free (reg_set_in_block);
   
   ae_gen = ae_kill = transp = st_antloc = NULL;
   pre_insert_map = pre_delete_map = reg_set_in_block = NULL;
@@ -6916,8 +7058,10 @@ store_motion ()
 {
   int x;
   struct ls_expr * ptr;
-  int update_flow = 0;
+  sbitmap trapping_expr;
+  int i;
 
+  int update_flow = 0;
   if (gcse_file)
     {
       fprintf (gcse_file, "before store motion\n");
@@ -6926,12 +7070,13 @@ store_motion ()
 
 
   init_alias_analysis ();
-
+  df_analyzer = df_init();
+  df_analyse (df_analyzer, 0,   DF_RD_CHAIN | DF_HARD_REGS);
   /* Find all the stores that are live to the end of their block.  */
   num_stores = compute_store_table ();
   if (num_stores == 0)
     {
-      sbitmap_vector_free (reg_set_in_block);
+      df_finish (df_analyzer);
       end_alias_analysis ();
       return;
     }
@@ -6940,6 +7085,31 @@ store_motion ()
   add_noreturn_fake_exit_edges ();
   build_store_vectors ();
 
+  /* Collect expressions which might trap.  */
+  trapping_expr = sbitmap_alloc (num_stores);
+  sbitmap_zero (trapping_expr);
+  for (ptr = first_ls_expr (); ptr != NULL; ptr = next_ls_expr(ptr))
+    {
+           if (may_trap_p (ptr->pattern))
+                   SET_BIT (trapping_expr, ptr->index);
+    }
+  for (i = 0; i < n_basic_blocks; i++)
+    {
+      edge e;
+
+      /* If the current block is the destination of an abnormal edge, we
+        kill all trapping expressions because we won't be able to properly
+        place the instruction on the edge.  So make them neither
+        anticipatable nor transparent.  This is fairly conservative.  */
+      for (e = BASIC_BLOCK (i)->pred; e ; e = e->pred_next)
+       if (e->flags & EDGE_ABNORMAL)
+         {
+           sbitmap_difference (st_antloc[i], st_antloc[i], trapping_expr);
+           sbitmap_difference (transp[i], transp[i], trapping_expr);
+           break;
+         }
+    }
+
   edge_list = pre_edge_rev_lcm (gcse_file, num_stores, transp, ae_gen, 
                                st_antloc, ae_kill, &pre_insert_map, 
                                &pre_delete_map);
@@ -6958,9 +7128,10 @@ store_motion ()
 
   if (update_flow)
     commit_edge_insertions ();
-
+  sbitmap_free (trapping_expr);
   free_store_memory ();
   free_edge_list (edge_list);
   remove_fake_edges ();
   end_alias_analysis ();
+  df_finish (df_analyzer);
 }