This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

RFA: patch cheking dangerous insns in sched-ebb.c


jakub at redhat dot com wrote:
> 
> >Category:       optimization
> >Synopsis:       IA-64 doesn't honor trapping math when doing final schedule
> >Confidential:   no
> >Severity:       serious
> >Priority:       medium
> >Class:          wrong-code
> >Submitter-Id:   net
> >Originator:     jakub at redhat dot com
> >Release:        3.0 ... 3.4 20031117
> >Environment:
> ia64-*-linux*
> >Description:
> sched-ebb.c doesn't honor may_trap_p when scheduling
> during ia64_machine_reorg, so a possibly trapping insn (in
> the testcase below fcmp.lt) can be scheduled before a branch
> in the same extended basic block which should protect it.
> I've tried to add haifa_classify_insn (insn) == TRAP_RISKY
> checks into sched-ebb.c's new_ready and init_ready_list,
> but probably more changes are needed to get it working.

  The following patch solves the problem.  sched-ebb.c ignored that
insns can cause an exception during speculative moving.

  The patch checks such insns in a way a bit different from
sched-rgn.c.  It creates additional dependencies to previous
jump insns from insn with possible exceptions instead of
checking this during scheduling a block.

  The patch still does not implement fully checking PRISKY_CANDIATEs.
It is necessary for better scheduling when
flag_schedule_speculative_load_dangerous is nonzero.  By default, it
is off so it is not important.  I'd not recommend to use the flag for
any port (there is even risk in usage of flag_schedule_speculative_load
which is implemented by the patch but also switched off by default).

The patch has been checked for Itanium2 (the single port using
sched-ebb.c so far) and on x86 because there are minor changes in
machine-independent scheduler code.

I am afraid that code quality will be a bit worse for Itanium after
applying the patch but we actually cheated and were lucky that the
problem did not occur earlier.

Vlad

2003-02-19  Vladimir Makarov  <vmakarov at redhat dot com>

        * sched-int.h (INSN_TRAP_CLASS, WORST_CLASS): Move them from
        sched-rgn.c.
        (add_forward_dependence): New function prototype.

        * sched-rgn.c (INSN_TRAP_CLASS, WORST_CLASS): Move them to
        sched-init.h.
        (CONST_BASED_ADDRESS_P, may_trap_exp, haifa_classify_insn): Move
        them to haifa-sched.c.

        * haifa-sched.c (CONST_BASED_ADDRESS_P, may_trap_exp,
        haifa_classify_insn): Move them from sched-rgn.c.

        * sched-deps.c (add_dependence): Return flag of creating a new
        entry.
        (add_forward_dependence): New function.
        (compute_forward_dependences): Use the function.
        
        * sched-ebb.c (block_has_similiar_load): New function.
        (add_deps_for_risky_insns): New function.
        (schedule_ebb): Call the function.
Index: sched-int.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/sched-int.h,v
retrieving revision 1.23
diff -c -p -r1.23 sched-int.h
*** sched-int.h	27 Sep 2002 12:48:02 -0000	1.23
--- sched-int.h	19 Feb 2003 23:57:05 -0000
*************** extern struct haifa_insn_data *h_i_d;
*** 258,263 ****
--- 258,333 ----
  extern FILE *sched_dump;
  extern int sched_verbose;
  
+ /* Exception Free Loads:
+ 
+    We define five classes of speculative loads: IFREE, IRISKY,
+    PFREE, PRISKY, and MFREE.
+ 
+    IFREE loads are loads that are proved to be exception-free, just
+    by examining the load insn.  Examples for such loads are loads
+    from TOC and loads of global data.
+ 
+    IRISKY loads are loads that are proved to be exception-risky,
+    just by examining the load insn.  Examples for such loads are
+    volatile loads and loads from shared memory.
+ 
+    PFREE loads are loads for which we can prove, by examining other
+    insns, that they are exception-free.  Currently, this class consists
+    of loads for which we are able to find a "similar load", either in
+    the target block, or, if only one split-block exists, in that split
+    block.  Load2 is similar to load1 if both have same single base
+    register.  We identify only part of the similar loads, by finding
+    an insn upon which both load1 and load2 have a DEF-USE dependence.
+ 
+    PRISKY loads are loads for which we can prove, by examining other
+    insns, that they are exception-risky.  Currently we have two proofs for
+    such loads.  The first proof detects loads that are probably guarded by a
+    test on the memory address.  This proof is based on the
+    backward and forward data dependence information for the region.
+    Let load-insn be the examined load.
+    Load-insn is PRISKY iff ALL the following hold:
+ 
+    - insn1 is not in the same block as load-insn
+    - there is a DEF-USE dependence chain (insn1, ..., load-insn)
+    - test-insn is either a compare or a branch, not in the same block
+      as load-insn
+    - load-insn is reachable from test-insn
+    - there is a DEF-USE dependence chain (insn1, ..., test-insn)
+ 
+    This proof might fail when the compare and the load are fed
+    by an insn not in the region.  To solve this, we will add to this
+    group all loads that have no input DEF-USE dependence.
+ 
+    The second proof detects loads that are directly or indirectly
+    fed by a speculative load.  This proof is affected by the
+    scheduling process.  We will use the flag  fed_by_spec_load.
+    Initially, all insns have this flag reset.  After a speculative
+    motion of an insn, if insn is either a load, or marked as
+    fed_by_spec_load, we will also mark as fed_by_spec_load every
+    insn1 for which a DEF-USE dependence (insn, insn1) exists.  A
+    load which is fed_by_spec_load is also PRISKY.
+ 
+    MFREE (maybe-free) loads are all the remaining loads. They may be
+    exception-free, but we cannot prove it.
+ 
+    Now, all loads in IFREE and PFREE classes are considered
+    exception-free, while all loads in IRISKY and PRISKY classes are
+    considered exception-risky.  As for loads in the MFREE class,
+    these are considered either exception-free or exception-risky,
+    depending on whether we are pessimistic or optimistic.  We have
+    to take the pessimistic approach to assure the safety of
+    speculative scheduling, but we can take the optimistic approach
+    by invoking the -fsched_spec_load_dangerous option.  */
+ 
+ enum INSN_TRAP_CLASS
+ {
+   TRAP_FREE = 0, IFREE = 1, PFREE_CANDIDATE = 2,
+   PRISKY_CANDIDATE = 3, IRISKY = 4, TRAP_RISKY = 5
+ };
+ 
+ #define WORST_CLASS(class1, class2) \
+ ((class1 > class2) ? class1 : class2)
+ 
  #ifndef __GNUC__
  #define __inline
  #endif
*************** extern void visualize_alloc PARAMS ((voi
*** 278,284 ****
  extern void visualize_free PARAMS ((void));
  
  /* Functions in sched-deps.c.  */
! extern void add_dependence PARAMS ((rtx, rtx, enum reg_note));
  extern void add_insn_mem_dependence PARAMS ((struct deps *, rtx *, rtx *, rtx,
  					     rtx));
  extern void sched_analyze PARAMS ((struct deps *, rtx, rtx));
--- 348,354 ----
  extern void visualize_free PARAMS ((void));
  
  /* Functions in sched-deps.c.  */
! extern int add_dependence PARAMS ((rtx, rtx, enum reg_note));
  extern void add_insn_mem_dependence PARAMS ((struct deps *, rtx *, rtx *, rtx,
  					     rtx));
  extern void sched_analyze PARAMS ((struct deps *, rtx, rtx));
*************** extern void init_deps PARAMS ((struct de
*** 286,297 ****
--- 356,369 ----
  extern void free_deps PARAMS ((struct deps *));
  extern void init_deps_global PARAMS ((void));
  extern void finish_deps_global PARAMS ((void));
+ extern void add_forward_dependence PARAMS ((rtx, rtx, enum reg_note));
  extern void compute_forward_dependences PARAMS ((rtx, rtx));
  extern rtx find_insn_list PARAMS ((rtx, rtx));
  extern void init_dependency_caches PARAMS ((int));
  extern void free_dependency_caches PARAMS ((void));
  
  /* Functions in haifa-sched.c.  */
+ extern int haifa_classify_insn PARAMS ((rtx));
  extern void get_block_head_tail PARAMS ((int, rtx *, rtx *));
  extern int no_real_insns_p PARAMS ((rtx, rtx));
  
Index: sched-deps.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/sched-deps.c,v
retrieving revision 1.54
diff -c -p -r1.54 sched-deps.c
*** sched-deps.c	28 Jan 2003 17:12:06 -0000	1.54
--- sched-deps.c	19 Feb 2003 23:57:05 -0000
*************** conditions_mutex_p (cond1, cond2)
*** 173,182 ****
  }
  
  /* Add ELEM wrapped in an INSN_LIST with reg note kind DEP_TYPE to the
!    LOG_LINKS of INSN, if not already there.  DEP_TYPE indicates the type
!    of dependence that this link represents.  */
  
! void
  add_dependence (insn, elem, dep_type)
       rtx insn;
       rtx elem;
--- 173,183 ----
  }
  
  /* Add ELEM wrapped in an INSN_LIST with reg note kind DEP_TYPE to the
!    LOG_LINKS of INSN, if not already there.  DEP_TYPE indicates the
!    type of dependence that this link represents.  The function returns
!    nonzero if a new entry has been added to insn's LOG_LINK.  */
  
! int
  add_dependence (insn, elem, dep_type)
       rtx insn;
       rtx elem;
*************** add_dependence (insn, elem, dep_type)
*** 188,200 ****
  
    /* Don't depend an insn on itself.  */
    if (insn == elem)
!     return;
  
    /* We can get a dependency on deleted insns due to optimizations in
       the register allocation and reloading or due to splitting.  Any
       such dependency is useless and can be ignored.  */
    if (GET_CODE (elem) == NOTE)
!     return;
  
    /* flow.c doesn't handle conditional lifetimes entirely correctly;
       calls mess up the conditional lifetimes.  */
--- 189,201 ----
  
    /* Don't depend an insn on itself.  */
    if (insn == elem)
!     return 0;
  
    /* We can get a dependency on deleted insns due to optimizations in
       the register allocation and reloading or due to splitting.  Any
       such dependency is useless and can be ignored.  */
    if (GET_CODE (elem) == NOTE)
!     return 0;
  
    /* flow.c doesn't handle conditional lifetimes entirely correctly;
       calls mess up the conditional lifetimes.  */
*************** add_dependence (insn, elem, dep_type)
*** 213,219 ****
  	  /* Make sure second instruction doesn't affect condition of first
  	     instruction if switched.  */
  	  && !modified_in_p (cond2, insn))
! 	return;
      }
  
    present_p = 1;
--- 214,220 ----
  	  /* Make sure second instruction doesn't affect condition of first
  	     instruction if switched.  */
  	  && !modified_in_p (cond2, insn))
! 	return 0;
      }
  
    present_p = 1;
*************** add_dependence (insn, elem, dep_type)
*** 227,233 ****
       elem is a CALL is still required.  */
    if (GET_CODE (insn) == CALL_INSN
        && (INSN_BB (elem) != INSN_BB (insn)))
!     return;
  #endif
  
    /* If we already have a dependency for ELEM, then we do not need to
--- 228,234 ----
       elem is a CALL is still required.  */
    if (GET_CODE (insn) == CALL_INSN
        && (INSN_BB (elem) != INSN_BB (insn)))
!     return 0;
  #endif
  
    /* If we already have a dependency for ELEM, then we do not need to
*************** add_dependence (insn, elem, dep_type)
*** 251,257 ****
        else
  	present_p = 0;
        if (present_p && (int) dep_type >= (int) present_dep_type)
! 	return;
      }
  #endif
  
--- 252,258 ----
        else
  	present_p = 0;
        if (present_p && (int) dep_type >= (int) present_dep_type)
! 	return 0;
      }
  #endif
  
*************** add_dependence (insn, elem, dep_type)
*** 276,282 ****
  		abort ();
  	    }
  #endif
! 
  	  /* If this is a more restrictive type of dependence than the existing
  	     one, then change the existing dependence to this type.  */
  	  if ((int) dep_type < (int) REG_NOTE_KIND (link))
--- 277,283 ----
  		abort ();
  	    }
  #endif
! 	  
  	  /* If this is a more restrictive type of dependence than the existing
  	     one, then change the existing dependence to this type.  */
  	  if ((int) dep_type < (int) REG_NOTE_KIND (link))
*************** add_dependence (insn, elem, dep_type)
*** 298,305 ****
  			 INSN_LUID (elem));
  	    }
  #endif
! 	  return;
!       }
    /* Might want to check one level of transitivity to save conses.  */
  
    link = alloc_INSN_LIST (elem, LOG_LINKS (insn));
--- 299,306 ----
  			 INSN_LUID (elem));
  	    }
  #endif
! 	  return 0;
! 	}
    /* Might want to check one level of transitivity to save conses.  */
  
    link = alloc_INSN_LIST (elem, LOG_LINKS (insn));
*************** add_dependence (insn, elem, dep_type)
*** 321,326 ****
--- 322,328 ----
  	SET_BIT (output_dependency_cache[INSN_LUID (insn)], INSN_LUID (elem));
      }
  #endif
+   return 1;
  }
  
  /* A convenience wrapper to operate on an entire list.  */
*************** sched_analyze (deps, head, tail)
*** 1310,1315 ****
--- 1312,1357 ----
    abort ();
  }
  
+ 
+ /* The following function adds forward dependence (FROM, TO) with
+    given DEP_TYPE.  The forward dependence should be not exist before.  */
+ 
+ void
+ add_forward_dependence (from, to, dep_type)
+      rtx from;
+      rtx to;
+      enum reg_note dep_type;
+ {
+   rtx new_link;
+ 
+ #ifdef ENABLE_CHECKING
+   /* If add_dependence is working properly there should never
+      be notes, deleted insns or duplicates in the backward
+      links.  Thus we need not check for them here.
+      
+      However, if we have enabled checking we might as well go
+      ahead and verify that add_dependence worked properly.  */
+   if (GET_CODE (from) == NOTE
+       || INSN_DELETED_P (from)
+       || (forward_dependency_cache != NULL
+ 	  && TEST_BIT (forward_dependency_cache[INSN_LUID (from)],
+ 		       INSN_LUID (to)))
+       || (forward_dependency_cache == NULL
+ 	  && find_insn_list (to, INSN_DEPEND (from))))
+     abort ();
+   if (forward_dependency_cache != NULL)
+     SET_BIT (forward_dependency_cache[INSN_LUID (from)],
+ 	     INSN_LUID (to));
+ #endif
+   
+   new_link = alloc_INSN_LIST (to, INSN_DEPEND (from));
+   
+   PUT_REG_NOTE_KIND (new_link, dep_type);
+   
+   INSN_DEPEND (from) = new_link;
+   INSN_DEP_COUNT (to) += 1;
+ }
+ 
  /* Examine insns in the range [ HEAD, TAIL ] and Use the backward
     dependences from LOG_LINKS to build forward dependences in
     INSN_DEPEND.  */
*************** compute_forward_dependences (head, tail)
*** 1320,1326 ****
  {
    rtx insn, link;
    rtx next_tail;
-   enum reg_note dep_type;
  
    next_tail = NEXT_INSN (tail);
    for (insn = head; insn != next_tail; insn = NEXT_INSN (insn))
--- 1362,1367 ----
*************** compute_forward_dependences (head, tail)
*** 1329,1369 ****
  	continue;
  
        for (link = LOG_LINKS (insn); link; link = XEXP (link, 1))
! 	{
! 	  rtx x = XEXP (link, 0);
! 	  rtx new_link;
! 
! 	  if (x != XEXP (link, 0))
! 	    continue;
! 
! #ifdef ENABLE_CHECKING
! 	  /* If add_dependence is working properly there should never
! 	     be notes, deleted insns or duplicates in the backward
! 	     links.  Thus we need not check for them here.
! 
! 	     However, if we have enabled checking we might as well go
! 	     ahead and verify that add_dependence worked properly.  */
! 	  if (GET_CODE (x) == NOTE
! 	      || INSN_DELETED_P (x)
! 	      || (forward_dependency_cache != NULL
! 		  && TEST_BIT (forward_dependency_cache[INSN_LUID (x)],
! 			       INSN_LUID (insn)))
! 	      || (forward_dependency_cache == NULL
! 		  && find_insn_list (insn, INSN_DEPEND (x))))
! 	    abort ();
! 	  if (forward_dependency_cache != NULL)
! 	    SET_BIT (forward_dependency_cache[INSN_LUID (x)],
! 		     INSN_LUID (insn));
! #endif
! 
! 	  new_link = alloc_INSN_LIST (insn, INSN_DEPEND (x));
! 
! 	  dep_type = REG_NOTE_KIND (link);
! 	  PUT_REG_NOTE_KIND (new_link, dep_type);
! 
! 	  INSN_DEPEND (x) = new_link;
! 	  INSN_DEP_COUNT (insn) += 1;
! 	}
      }
  }
  
--- 1370,1376 ----
  	continue;
  
        for (link = LOG_LINKS (insn); link; link = XEXP (link, 1))
! 	add_forward_dependence (XEXP (link, 0), insn, REG_NOTE_KIND (link));
      }
  }
  
Index: sched-rgn.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/sched-rgn.c,v
retrieving revision 1.57
diff -c -p -r1.57 sched-rgn.c
*** sched-rgn.c	28 Jan 2003 17:12:06 -0000	1.57
--- sched-rgn.c	19 Feb 2003 23:57:06 -0000
*************** static void set_spec_fed PARAMS ((rtx));
*** 288,295 ****
  static int is_pfree PARAMS ((rtx, int, int));
  static int find_conditional_protection PARAMS ((rtx, int));
  static int is_conditionally_protected PARAMS ((rtx, int, int));
- static int may_trap_exp PARAMS ((rtx, int));
- static int haifa_classify_insn PARAMS ((rtx));
  static int is_prisky PARAMS ((rtx, int, int));
  static int is_exception_free PARAMS ((rtx, int, int));
  
--- 288,293 ----
*************** update_live (insn, src)
*** 1490,1565 ****
      }
  }
  
- /* Exception Free Loads:
- 
-    We define five classes of speculative loads: IFREE, IRISKY,
-    PFREE, PRISKY, and MFREE.
- 
-    IFREE loads are loads that are proved to be exception-free, just
-    by examining the load insn.  Examples for such loads are loads
-    from TOC and loads of global data.
- 
-    IRISKY loads are loads that are proved to be exception-risky,
-    just by examining the load insn.  Examples for such loads are
-    volatile loads and loads from shared memory.
- 
-    PFREE loads are loads for which we can prove, by examining other
-    insns, that they are exception-free.  Currently, this class consists
-    of loads for which we are able to find a "similar load", either in
-    the target block, or, if only one split-block exists, in that split
-    block.  Load2 is similar to load1 if both have same single base
-    register.  We identify only part of the similar loads, by finding
-    an insn upon which both load1 and load2 have a DEF-USE dependence.
- 
-    PRISKY loads are loads for which we can prove, by examining other
-    insns, that they are exception-risky.  Currently we have two proofs for
-    such loads.  The first proof detects loads that are probably guarded by a
-    test on the memory address.  This proof is based on the
-    backward and forward data dependence information for the region.
-    Let load-insn be the examined load.
-    Load-insn is PRISKY iff ALL the following hold:
- 
-    - insn1 is not in the same block as load-insn
-    - there is a DEF-USE dependence chain (insn1, ..., load-insn)
-    - test-insn is either a compare or a branch, not in the same block
-      as load-insn
-    - load-insn is reachable from test-insn
-    - there is a DEF-USE dependence chain (insn1, ..., test-insn)
- 
-    This proof might fail when the compare and the load are fed
-    by an insn not in the region.  To solve this, we will add to this
-    group all loads that have no input DEF-USE dependence.
- 
-    The second proof detects loads that are directly or indirectly
-    fed by a speculative load.  This proof is affected by the
-    scheduling process.  We will use the flag  fed_by_spec_load.
-    Initially, all insns have this flag reset.  After a speculative
-    motion of an insn, if insn is either a load, or marked as
-    fed_by_spec_load, we will also mark as fed_by_spec_load every
-    insn1 for which a DEF-USE dependence (insn, insn1) exists.  A
-    load which is fed_by_spec_load is also PRISKY.
- 
-    MFREE (maybe-free) loads are all the remaining loads. They may be
-    exception-free, but we cannot prove it.
- 
-    Now, all loads in IFREE and PFREE classes are considered
-    exception-free, while all loads in IRISKY and PRISKY classes are
-    considered exception-risky.  As for loads in the MFREE class,
-    these are considered either exception-free or exception-risky,
-    depending on whether we are pessimistic or optimistic.  We have
-    to take the pessimistic approach to assure the safety of
-    speculative scheduling, but we can take the optimistic approach
-    by invoking the -fsched_spec_load_dangerous option.  */
- 
- enum INSN_TRAP_CLASS
- {
-   TRAP_FREE = 0, IFREE = 1, PFREE_CANDIDATE = 2,
-   PRISKY_CANDIDATE = 3, IRISKY = 4, TRAP_RISKY = 5
- };
- 
- #define WORST_CLASS(class1, class2) \
- ((class1 > class2) ? class1 : class2)
- 
  /* Nonzero if block bb_to is equal to, or reachable from block bb_from.  */
  #define IS_REACHABLE(bb_from, bb_to)					\
    (bb_from == bb_to							\
--- 1488,1493 ----
*************** enum INSN_TRAP_CLASS
*** 1567,1580 ****
     || (TEST_BIT (ancestor_edges[bb_to],					\
  		 EDGE_TO_BIT (IN_EDGES (BB_TO_BLOCK (bb_from))))))
  
- /* Nonzero iff the address is comprised from at most 1 register.  */
- #define CONST_BASED_ADDRESS_P(x)			\
-   (GET_CODE (x) == REG					\
-    || ((GET_CODE (x) == PLUS || GET_CODE (x) == MINUS	\
- 	|| (GET_CODE (x) == LO_SUM))			\
-        && (CONSTANT_P (XEXP (x, 0))			\
- 	   || CONSTANT_P (XEXP (x, 1)))))
- 
  /* Turns on the fed_by_spec_load flag for insns fed by load_insn.  */
  
  static void
--- 1495,1500 ----
*************** is_pfree (load_insn, bb_src, bb_trg)
*** 1728,1887 ****
    /* Couldn't find a similar load.  */
    return 0;
  }				/* is_pfree */
- 
- /* Returns a class that insn with GET_DEST(insn)=x may belong to,
-    as found by analyzing insn's expression.  */
- 
- static int
- may_trap_exp (x, is_store)
-      rtx x;
-      int is_store;
- {
-   enum rtx_code code;
- 
-   if (x == 0)
-     return TRAP_FREE;
-   code = GET_CODE (x);
-   if (is_store)
-     {
-       if (code == MEM && may_trap_p (x))
- 	return TRAP_RISKY;
-       else
- 	return TRAP_FREE;
-     }
-   if (code == MEM)
-     {
-       /* The insn uses memory:  a volatile load.  */
-       if (MEM_VOLATILE_P (x))
- 	return IRISKY;
-       /* An exception-free load.  */
-       if (!may_trap_p (x))
- 	return IFREE;
-       /* A load with 1 base register, to be further checked.  */
-       if (CONST_BASED_ADDRESS_P (XEXP (x, 0)))
- 	return PFREE_CANDIDATE;
-       /* No info on the load, to be further checked.  */
-       return PRISKY_CANDIDATE;
-     }
-   else
-     {
-       const char *fmt;
-       int i, insn_class = TRAP_FREE;
- 
-       /* Neither store nor load, check if it may cause a trap.  */
-       if (may_trap_p (x))
- 	return TRAP_RISKY;
-       /* Recursive step: walk the insn...  */
-       fmt = GET_RTX_FORMAT (code);
-       for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
- 	{
- 	  if (fmt[i] == 'e')
- 	    {
- 	      int tmp_class = may_trap_exp (XEXP (x, i), is_store);
- 	      insn_class = WORST_CLASS (insn_class, tmp_class);
- 	    }
- 	  else if (fmt[i] == 'E')
- 	    {
- 	      int j;
- 	      for (j = 0; j < XVECLEN (x, i); j++)
- 		{
- 		  int tmp_class = may_trap_exp (XVECEXP (x, i, j), is_store);
- 		  insn_class = WORST_CLASS (insn_class, tmp_class);
- 		  if (insn_class == TRAP_RISKY || insn_class == IRISKY)
- 		    break;
- 		}
- 	    }
- 	  if (insn_class == TRAP_RISKY || insn_class == IRISKY)
- 	    break;
- 	}
-       return insn_class;
-     }
- }
- 
- /* Classifies insn for the purpose of verifying that it can be
-    moved speculatively, by examining it's patterns, returning:
-    TRAP_RISKY: store, or risky non-load insn (e.g. division by variable).
-    TRAP_FREE: non-load insn.
-    IFREE: load from a globaly safe location.
-    IRISKY: volatile load.
-    PFREE_CANDIDATE, PRISKY_CANDIDATE: load that need to be checked for
-    being either PFREE or PRISKY.  */
- 
- static int
- haifa_classify_insn (insn)
-      rtx insn;
- {
-   rtx pat = PATTERN (insn);
-   int tmp_class = TRAP_FREE;
-   int insn_class = TRAP_FREE;
-   enum rtx_code code;
- 
-   if (GET_CODE (pat) == PARALLEL)
-     {
-       int i, len = XVECLEN (pat, 0);
- 
-       for (i = len - 1; i >= 0; i--)
- 	{
- 	  code = GET_CODE (XVECEXP (pat, 0, i));
- 	  switch (code)
- 	    {
- 	    case CLOBBER:
- 	      /* Test if it is a 'store'.  */
- 	      tmp_class = may_trap_exp (XEXP (XVECEXP (pat, 0, i), 0), 1);
- 	      break;
- 	    case SET:
- 	      /* Test if it is a store.  */
- 	      tmp_class = may_trap_exp (SET_DEST (XVECEXP (pat, 0, i)), 1);
- 	      if (tmp_class == TRAP_RISKY)
- 		break;
- 	      /* Test if it is a load.  */
- 	      tmp_class
- 		= WORST_CLASS (tmp_class,
- 			       may_trap_exp (SET_SRC (XVECEXP (pat, 0, i)),
- 					     0));
- 	      break;
- 	    case COND_EXEC:
- 	    case TRAP_IF:
- 	      tmp_class = TRAP_RISKY;
- 	      break;
- 	    default:
- 	      ;
- 	    }
- 	  insn_class = WORST_CLASS (insn_class, tmp_class);
- 	  if (insn_class == TRAP_RISKY || insn_class == IRISKY)
- 	    break;
- 	}
-     }
-   else
-     {
-       code = GET_CODE (pat);
-       switch (code)
- 	{
- 	case CLOBBER:
- 	  /* Test if it is a 'store'.  */
- 	  tmp_class = may_trap_exp (XEXP (pat, 0), 1);
- 	  break;
- 	case SET:
- 	  /* Test if it is a store.  */
- 	  tmp_class = may_trap_exp (SET_DEST (pat), 1);
- 	  if (tmp_class == TRAP_RISKY)
- 	    break;
- 	  /* Test if it is a load.  */
- 	  tmp_class =
- 	    WORST_CLASS (tmp_class,
- 			 may_trap_exp (SET_SRC (pat), 0));
- 	  break;
- 	case COND_EXEC:
- 	case TRAP_IF:
- 	  tmp_class = TRAP_RISKY;
- 	  break;
- 	default:;
- 	}
-       insn_class = tmp_class;
-     }
- 
-   return insn_class;
- }
  
  /* Return 1 if load_insn is prisky (i.e. if load_insn is fed by
     a load moved speculatively, or if load_insn is protected by
--- 1648,1653 ----
Index: haifa-sched.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/haifa-sched.c,v
retrieving revision 1.219
diff -c -p -r1.219 haifa-sched.c
*** haifa-sched.c	6 Feb 2003 10:02:33 -0000	1.219
--- haifa-sched.c	19 Feb 2003 23:57:06 -0000
*************** struct ready_list
*** 305,310 ****
--- 305,474 ----
    int n_ready;
  };
  
+ static int may_trap_exp PARAMS ((rtx, int));
+ 
+ /* Nonzero iff the address is comprised from at most 1 register.  */
+ #define CONST_BASED_ADDRESS_P(x)			\
+   (GET_CODE (x) == REG					\
+    || ((GET_CODE (x) == PLUS || GET_CODE (x) == MINUS	\
+ 	|| (GET_CODE (x) == LO_SUM))			\
+        && (CONSTANT_P (XEXP (x, 0))			\
+ 	   || CONSTANT_P (XEXP (x, 1)))))
+ 
+ /* Returns a class that insn with GET_DEST(insn)=x may belong to,
+    as found by analyzing insn's expression.  */
+ 
+ static int
+ may_trap_exp (x, is_store)
+      rtx x;
+      int is_store;
+ {
+   enum rtx_code code;
+ 
+   if (x == 0)
+     return TRAP_FREE;
+   code = GET_CODE (x);
+   if (is_store)
+     {
+       if (code == MEM && may_trap_p (x))
+ 	return TRAP_RISKY;
+       else
+ 	return TRAP_FREE;
+     }
+   if (code == MEM)
+     {
+       /* The insn uses memory:  a volatile load.  */
+       if (MEM_VOLATILE_P (x))
+ 	return IRISKY;
+       /* An exception-free load.  */
+       if (!may_trap_p (x))
+ 	return IFREE;
+       /* A load with 1 base register, to be further checked.  */
+       if (CONST_BASED_ADDRESS_P (XEXP (x, 0)))
+ 	return PFREE_CANDIDATE;
+       /* No info on the load, to be further checked.  */
+       return PRISKY_CANDIDATE;
+     }
+   else
+     {
+       const char *fmt;
+       int i, insn_class = TRAP_FREE;
+ 
+       /* Neither store nor load, check if it may cause a trap.  */
+       if (may_trap_p (x))
+ 	return TRAP_RISKY;
+       /* Recursive step: walk the insn...  */
+       fmt = GET_RTX_FORMAT (code);
+       for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
+ 	{
+ 	  if (fmt[i] == 'e')
+ 	    {
+ 	      int tmp_class = may_trap_exp (XEXP (x, i), is_store);
+ 	      insn_class = WORST_CLASS (insn_class, tmp_class);
+ 	    }
+ 	  else if (fmt[i] == 'E')
+ 	    {
+ 	      int j;
+ 	      for (j = 0; j < XVECLEN (x, i); j++)
+ 		{
+ 		  int tmp_class = may_trap_exp (XVECEXP (x, i, j), is_store);
+ 		  insn_class = WORST_CLASS (insn_class, tmp_class);
+ 		  if (insn_class == TRAP_RISKY || insn_class == IRISKY)
+ 		    break;
+ 		}
+ 	    }
+ 	  if (insn_class == TRAP_RISKY || insn_class == IRISKY)
+ 	    break;
+ 	}
+       return insn_class;
+     }
+ }
+ 
+ /* Classifies insn for the purpose of verifying that it can be
+    moved speculatively, by examining it's patterns, returning:
+    TRAP_RISKY: store, or risky non-load insn (e.g. division by variable).
+    TRAP_FREE: non-load insn.
+    IFREE: load from a globaly safe location.
+    IRISKY: volatile load.
+    PFREE_CANDIDATE, PRISKY_CANDIDATE: load that need to be checked for
+    being either PFREE or PRISKY.  */
+ 
+ int
+ haifa_classify_insn (insn)
+      rtx insn;
+ {
+   rtx pat = PATTERN (insn);
+   int tmp_class = TRAP_FREE;
+   int insn_class = TRAP_FREE;
+   enum rtx_code code;
+ 
+   if (GET_CODE (pat) == PARALLEL)
+     {
+       int i, len = XVECLEN (pat, 0);
+ 
+       for (i = len - 1; i >= 0; i--)
+ 	{
+ 	  code = GET_CODE (XVECEXP (pat, 0, i));
+ 	  switch (code)
+ 	    {
+ 	    case CLOBBER:
+ 	      /* Test if it is a 'store'.  */
+ 	      tmp_class = may_trap_exp (XEXP (XVECEXP (pat, 0, i), 0), 1);
+ 	      break;
+ 	    case SET:
+ 	      /* Test if it is a store.  */
+ 	      tmp_class = may_trap_exp (SET_DEST (XVECEXP (pat, 0, i)), 1);
+ 	      if (tmp_class == TRAP_RISKY)
+ 		break;
+ 	      /* Test if it is a load.  */
+ 	      tmp_class
+ 		= WORST_CLASS (tmp_class,
+ 			       may_trap_exp (SET_SRC (XVECEXP (pat, 0, i)),
+ 					     0));
+ 	      break;
+ 	    case COND_EXEC:
+ 	    case TRAP_IF:
+ 	      tmp_class = TRAP_RISKY;
+ 	      break;
+ 	    default:
+ 	      ;
+ 	    }
+ 	  insn_class = WORST_CLASS (insn_class, tmp_class);
+ 	  if (insn_class == TRAP_RISKY || insn_class == IRISKY)
+ 	    break;
+ 	}
+     }
+   else
+     {
+       code = GET_CODE (pat);
+       switch (code)
+ 	{
+ 	case CLOBBER:
+ 	  /* Test if it is a 'store'.  */
+ 	  tmp_class = may_trap_exp (XEXP (pat, 0), 1);
+ 	  break;
+ 	case SET:
+ 	  /* Test if it is a store.  */
+ 	  tmp_class = may_trap_exp (SET_DEST (pat), 1);
+ 	  if (tmp_class == TRAP_RISKY)
+ 	    break;
+ 	  /* Test if it is a load.  */
+ 	  tmp_class =
+ 	    WORST_CLASS (tmp_class,
+ 			 may_trap_exp (SET_SRC (pat), 0));
+ 	  break;
+ 	case COND_EXEC:
+ 	case TRAP_IF:
+ 	  tmp_class = TRAP_RISKY;
+ 	  break;
+ 	default:;
+ 	}
+       insn_class = tmp_class;
+     }
+ 
+   return insn_class;
+ }
+ 
  /* Forward declarations.  */
  
  /* The scheduler using only DFA description should never use the
Index: sched-ebb.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/sched-ebb.c,v
retrieving revision 1.23
diff -c -p -r1.23 sched-ebb.c
*** sched-ebb.c	11 Feb 2003 12:33:52 -0000	1.23
--- sched-ebb.c	19 Feb 2003 23:57:06 -0000
*************** static const char *ebb_print_insn PARAMS
*** 56,61 ****
--- 56,63 ----
  static int rank PARAMS ((rtx, rtx));
  static int contributes_to_priority PARAMS ((rtx, rtx));
  static void compute_jump_reg_dependencies PARAMS ((rtx, regset));
+ static int block_has_similiar_load PARAMS ((basic_block, rtx));
+ static void add_deps_for_risky_insns PARAMS ((rtx, rtx));
  static basic_block schedule_ebb PARAMS ((rtx, rtx));
  static basic_block fix_basic_block_boundaries PARAMS ((basic_block, basic_block, rtx, rtx));
  static void add_missing_bbs PARAMS ((rtx, basic_block, basic_block));
*************** fix_basic_block_boundaries (bb, last, he
*** 339,344 ****
--- 341,443 ----
    return bb->prev_bb;
  }
  
+ /* Returns 1 if a clue for "similar load" 'insn2' is found in BLOCK,
+    and hence load_insn can move speculatively into BLOCK.  All the
+    following must hold:
+ 
+    (1) both loads have 1 base register (PFREE_CANDIDATEs).
+    (2) load_insn and load1 have a def-use dependence upon
+    the same insn 'insn1'.
+    (3) load2 is in BLOCK
+ 
+    From all these we can conclude that the two loads access memory
+    addresses that differ at most by a constant, and hence if moving
+    load_insn would cause an exception, it would have been caused by
+    load2 anyhow.  */
+ 
+ static int
+ block_has_similiar_load (block, load_insn)
+      basic_block block;
+      rtx load_insn;
+ {
+   rtx back_link;
+ 
+   for (back_link = LOG_LINKS (load_insn);
+        back_link;
+        back_link = XEXP (back_link, 1))
+     {
+       rtx insn1 = XEXP (back_link, 0);
+ 
+       if (GET_MODE (back_link) == VOIDmode)
+ 	{
+ 	  /* Found a DEF-USE dependence (insn1, load_insn).  */
+ 	  rtx fore_link;
+ 
+ 	  for (fore_link = INSN_DEPEND (insn1);
+ 	       fore_link;
+ 	       fore_link = XEXP (fore_link, 1))
+ 	    {
+ 	      rtx insn2 = XEXP (fore_link, 0);
+ 
+ 	      if (GET_MODE (fore_link) == VOIDmode)
+ 		{
+ 		  /* Found a DEF-USE dependence (insn1, insn2).  */
+ 		  if (haifa_classify_insn (insn2) != PFREE_CANDIDATE)
+ 		    /* insn2 not guaranteed to be a 1 base reg load.  */
+ 		    continue;
+ 
+ 		  if (BLOCK_FOR_INSN (insn2) == block)
+ 		    /* insn2 is the similar load, in the target block.  */
+ 		    return 1;
+ 		}
+ 	    }
+ 	}
+     }
+ 
+   /* Couldn't find a similar load.  */
+   return 0;
+ }
+ 
+ /* The following function adds dependecies between jumps and risky
+    insns in given ebb.  */
+ 
+ static void
+ add_deps_for_risky_insns (head, tail)
+      rtx head, tail;
+ {
+   rtx insn, prev;
+   rtx last_jump = NULL_RTX;
+   int class;
+   
+   for (insn = head; insn != NEXT_INSN (tail); insn = NEXT_INSN (insn))
+     if (GET_CODE (insn) == JUMP_INSN)
+       last_jump = insn;
+     else if (INSN_P (insn) && last_jump != NULL_RTX)
+       {
+ 	class = haifa_classify_insn (insn);
+ 	if (class == TRAP_RISKY || class == IRISKY
+ 	    || class == PRISKY_CANDIDATE || class == PFREE_CANDIDATE)
+ 	  for (prev = last_jump;
+ 	       prev != PREV_INSN (head);
+ 	       prev = PREV_INSN (prev))
+ 	    /* ??? We could implement better checking PRISKY_CANDIATEs
+ 	       analogous to sched-rgn.c.  */
+ 	    if (GET_CODE (prev) == JUMP_INSN
+ 		&& (class != PFREE_CANDIDATE
+ 		    || (flag_schedule_speculative_load
+ 			&& block_has_similiar_load (BLOCK_FOR_INSN (prev),
+ 						    insn))))
+ 	      {
+ 		/* We can not change the mode of the backward
+ 		   dependency because REG_DEP_ANTI has the lowest
+ 		   rank.  */
+ 		if (add_dependence (insn, prev, REG_DEP_ANTI))
+ 		  add_forward_dependence (prev, insn, REG_DEP_ANTI);
+ 		break;
+ 	      }
+       }
+ }
+ 
  /* Schedule a single extended basic block, defined by the boundaries HEAD
     and TAIL.  */
  
*************** schedule_ebb (head, tail)
*** 364,369 ****
--- 463,470 ----
  
    /* Compute INSN_DEPEND.  */
    compute_forward_dependences (head, tail);
+ 
+   add_deps_for_risky_insns (head, tail);
  
    if (targetm.sched.dependencies_evaluation_hook)
      targetm.sched.dependencies_evaluation_hook (head, tail);


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]