rch, update, resolve, delete
   and debug instruction dependencies.  */

/* Constants defining dependences lists.  */

/* No list.  */
#define SD_LIST_NONE (0)

/* hard_back_deps.  */
#define SD_LIST_HARD_BACK (1)

/* spec_back_deps.  */
#define SD_LIST_SPEC_BACK (2)

/* forw_deps.  */
#define SD_LIST_FORW (4)

/* resolved_back_deps.  */
#define SD_LIST_RES_BACK (8)

/* resolved_forw_deps.  */
#define SD_LIST_RES_FORW (16)

#define SD_LIST_BACK (SD_LIST_HARD_BACK | SD_LIST_SPEC_BACK)

/* A type to hold above flags.  */
typedef int sd_list_types_def;

extern void sd_next_list (const_rtx, sd_list_types_def *, deps_list_t *, bool *);

/* Iterator to walk through, resolve and delete dependencies.  */
struct _sd_iterator
{
  /* What lists to walk.  Can be any combination of SD_LIST_* flags.  */
  sd_list_types_def types;

  /* Instruction dependencies lists of which will be walked.  */
  rtx insn;

  /* Pointer to the next field of the previous element.  This is not
     simply a pointer to the next element to allow easy deletion from the
     list.  When a dep is being removed from the list the iterator
     will automatically advance because the value in *linkp will start
     referring to the next element.  */
  dep_link_t *linkp;

  /* True if the current list is a resolved one.  */
  bool resolved_p;
};

typedef struct _sd_iterator sd_iterator_def;

/* ??? We can move some definitions that are used in below inline functions
   out of sched-int.h to sched-deps.c provided that the below functions will
   become global externals.
   These definitions include:
   * struct _deps_list: opaque pointer is needed at global scope.
   * struct _dep_link: opaque pointer is needed at scope of sd_iterator_def.
   * struct _dep_node: opaque pointer is needed at scope of
   struct _deps_link.  */

/* Return initialized iterator.  */
static inline sd_iterator_def
sd_iterator_start (rtx insn, sd_list_types_def types)
{
  /* Some dep_link a pointer to which will return NULL.  */
  static dep_link_t null_link = NULL;

  sd_iterator_def i;

  i.types = types;
  i.insn = insn;
  i.linkp = &null_link;

  /* Avoid 'uninitialized warning'.  */
  i.resolved_p = false;

  return i;
}

/* Return the current element.  */
static inline bool
sd_iterator_cond (sd_iterator_def *it_ptr, dep_t *dep_ptr)
{
  while (true)
    {
      dep_link_t link = *it_ptr->linkp;

      if (link != NULL)
	{
	  *dep_ptr = DEP_LINK_DEP (link);
	  return true;
	}
      else
	{
	  sd_list_types_def types = it_ptr->types;

	  if (types != SD_LIST_NONE)
	    /* Switch to next list.  */
	    {
	      deps_list_t list;

	      sd_next_list (it_ptr->insn,
			    &it_ptr->types, &list, &it_ptr->resolved_p);

	      if (list)
		{
		  it_ptr->linkp = &DEPS_LIST_FIRST (list);
		  continue;
		}
	    }

	  *dep_ptr = NULL;
	  return false;
	}
   }
}

/* Advance iterator.  */
static inline void
sd_iterator_next (sd_iterator_def *it_ptr)
{
  it_ptr->linkp = &DEP_LINK_NEXT (*it_ptr->linkp);
}

/* A cycle wrapper.  */
#define FOR_EACH_DEP(INSN, LIST_TYPES, ITER, DEP)		\
  for ((ITER) = sd_iterator_start ((INSN), (LIST_TYPES));	\
       sd_iterator_cond (&(ITER), &(DEP));			\
       sd_iterator_next (&(ITER)))

#define IS_DISPATCH_ON 1
#define IS_CMP 2
#define DISPATCH_VIOLATION 3
#define FITS_DISPATCH_WINDOW 4
#define DISPATCH_INIT 5
#define ADD_TO_DISPATCH_WINDOW 6

extern int sd_lists_size (const_rtx, sd_list_types_def);
extern bool sd_lists_empty_p (const_rtx, sd_list_types_def);
extern void sd_init_insn (rtx_insn *);
extern void sd_finish_insn (rtx_insn *);
extern dep_t sd_find_dep_between (rtx, rtx, bool);
extern void sd_add_dep (dep_t, bool);
extern enum DEPS_ADJUST_RESULT sd_add_or_update_dep (dep_t, bool);
extern void sd_resolve_dep (sd_iterator_def);
extern void sd_unresolve_dep (sd_iterator_def);
extern void sd_copy_back_deps (rtx_insn *, rtx_insn *, bool);
extern void sd_delete_dep (sd_iterator_def);
extern void sd_debug_lists (rtx, sd_list_types_def);

/* Macros and declarations for scheduling fusion.  */
#define FUSION_MAX_PRIORITY (INT_MAX)
extern bool sched_fusion;

#endif /* INSN_SCHEDULING */

#endif /* GCC_SCHED_INT_H */

