]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
Dispatch scheduling for AMD Bulldozer processors.
authorspop <spop@138bc75d-0d04-0410-961f-82ee72b054a4>
Thu, 9 Sep 2010 23:11:36 +0000 (23:11 +0000)
committerspop <spop@138bc75d-0d04-0410-961f-82ee72b054a4>
Thu, 9 Sep 2010 23:11:36 +0000 (23:11 +0000)
2010-09-09  Reza Yazdani  <reza.yazdani@amd.com>

* config/i386/i386.c: Include sched-int.h.
(TARGET_SCHED_DISPATCH): Defined.
(TARGET_SCHED_DISPATCH_DO): Defined.
(DISPATCH_WINDOW_SIZE): Defined.
(MAX_DISPATCH_WINDOWS): Defined.
(MAX_INSN): Defined.
(MAX_IMM): Defined.
(MAX_IMM_SIZE): Defined.
(MAX_IMM_32): Defined.
(MAX_IMM_64): Defined.
(MAX_LOAD): Defined.
(MAX_STORE): Defined.
(BIG): Defined.
(dispatch_group): New.
(num_allowable_groups): New.
(group_name): New.
(sched_insn_info_s): New.
(dispatch_windows_s): New.
(imm_info_s): New.
(dispatch_window_list): New.
(dispatch_window_list1): New.
(get_mem_group): New.
(is_cmp): New.
(dispatch_violation): New.
(is_branch): New.
(is_prefetch): New.
(init_window): New.
(allocate_window): New.
(init_dispatch_sched): New.
(is_end_basic_block): New.
(process_end_window): New.
(allocate_next_window): New.
(find_constant_1): New.
(find_constant): New.
(get_num_immediates): New.
(has_immediate): New.
(get_insn_path): New.
(get_insn_group): New.
(count_num_restricted): New.
(fits_dispatch_window): New.
(add_insn_window): New.
(add_to_dispatch_window): New.
(debug_dispatch_window_file): New.
(debug_dispatch_window): New.
(debug_insn_dispatch_info_file): New.
(debug_ready_dispatch): New.
(do_dispatch): New.
(has_dispatch): New.
* config/i386/i386.h (debug_ready_dispatch): Declared.
(debug_dispatch_window): Declared.
* config/i386/i386.opt (mdispatch-scheduler): New flag.
* doc/tm.texi.in (TARGET_SCHED_DISPATCH): New.
(TARGET_SCHED_DISPATCH_DO): New.
* doc/tm.texi: Regererated.
* haifa-sched.c (choose_ready): Call targetm.sched.dispatch and
ready_remove_first_dispatch
(schedule_block): Call targetm.sched.dispatch and
targetm.sched.dispatch_do.
(sched_init): Call targetm.sched.dispatch and
targetm.sched.dispatch_do.
(ready_remove_first_dispatch): New.
(number_in_ready): New.
(get_ready_element): New.
* hooks.c (hook_bool_rtx_int_false): New.
(hook_void_rtx_int): New.
* hooks.h (hook_bool_rtx_int_false): Declared.
(hook_void_rtx_int): Declared.
* sched-int.h (IS_DISPATCH_ON): Defined.
(IS_CMP): Defined.
(DISPATCH_VIOLATION): Defined.
(FITS_DISPATCH_WINDOW): Defined.
(DISPATCH_INIT): Defined.
(ADD_TO_DISPATCH_WINDOW): Defined.
(get_ready_element): Declared.
(number_in_ready): Declared.
* target.def (dispatch): Defined.
(dispatch_do): Defined.

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

gcc/ChangeLog
gcc/config/i386/i386.c
gcc/config/i386/i386.h
gcc/config/i386/i386.opt
gcc/doc/tm.texi
gcc/doc/tm.texi.in
gcc/haifa-sched.c
gcc/hooks.c
gcc/hooks.h
gcc/sched-int.h
gcc/target.def

index 781d5a1219af4f1555e9a671bccf27fc21ef55d6..17a253afca7563d9258b9ff05ef3a28040c6d61e 100644 (file)
@@ -1,3 +1,83 @@
+2010-09-09  Reza Yazdani  <reza.yazdani@amd.com>
+
+       * config/i386/i386.c: Include sched-int.h.
+       (TARGET_SCHED_DISPATCH): Defined.
+       (TARGET_SCHED_DISPATCH_DO): Defined.
+       (DISPATCH_WINDOW_SIZE): Defined.
+       (MAX_DISPATCH_WINDOWS): Defined.
+       (MAX_INSN): Defined.
+       (MAX_IMM): Defined.
+       (MAX_IMM_SIZE): Defined.
+       (MAX_IMM_32): Defined.
+       (MAX_IMM_64): Defined.
+       (MAX_LOAD): Defined.
+       (MAX_STORE): Defined.
+       (BIG): Defined.
+       (dispatch_group): New.
+       (num_allowable_groups): New.
+       (group_name): New.
+       (sched_insn_info_s): New.
+       (dispatch_windows_s): New.
+       (imm_info_s): New.
+       (dispatch_window_list): New.
+       (dispatch_window_list1): New.
+       (get_mem_group): New.
+       (is_cmp): New.
+       (dispatch_violation): New.
+       (is_branch): New.
+       (is_prefetch): New.
+       (init_window): New.
+       (allocate_window): New.
+       (init_dispatch_sched): New.
+       (is_end_basic_block): New.
+       (process_end_window): New.
+       (allocate_next_window): New.
+       (find_constant_1): New.
+       (find_constant): New.
+       (get_num_immediates): New.
+       (has_immediate): New.
+       (get_insn_path): New.
+       (get_insn_group): New.
+       (count_num_restricted): New.
+       (fits_dispatch_window): New.
+       (add_insn_window): New.
+       (add_to_dispatch_window): New.
+       (debug_dispatch_window_file): New.
+       (debug_dispatch_window): New.
+       (debug_insn_dispatch_info_file): New.
+       (debug_ready_dispatch): New.
+       (do_dispatch): New.
+       (has_dispatch): New.
+       * config/i386/i386.h (debug_ready_dispatch): Declared.
+       (debug_dispatch_window): Declared.
+       * config/i386/i386.opt (mdispatch-scheduler): New flag.
+       * doc/tm.texi.in (TARGET_SCHED_DISPATCH): New.
+       (TARGET_SCHED_DISPATCH_DO): New.
+       * doc/tm.texi: Regererated.
+       * haifa-sched.c (choose_ready): Call targetm.sched.dispatch and
+       ready_remove_first_dispatch
+       (schedule_block): Call targetm.sched.dispatch and
+       targetm.sched.dispatch_do.
+       (sched_init): Call targetm.sched.dispatch and
+       targetm.sched.dispatch_do.
+       (ready_remove_first_dispatch): New.
+       (number_in_ready): New.
+       (get_ready_element): New.
+       * hooks.c (hook_bool_rtx_int_false): New.
+       (hook_void_rtx_int): New.
+       * hooks.h (hook_bool_rtx_int_false): Declared.
+       (hook_void_rtx_int): Declared.
+       * sched-int.h (IS_DISPATCH_ON): Defined.
+       (IS_CMP): Defined.
+       (DISPATCH_VIOLATION): Defined.
+       (FITS_DISPATCH_WINDOW): Defined.
+       (DISPATCH_INIT): Defined.
+       (ADD_TO_DISPATCH_WINDOW): Defined.
+       (get_ready_element): Declared.
+       (number_in_ready): Declared.
+       * target.def (dispatch): Defined.
+       (dispatch_do): Defined.
+
 2010-09-09  Vladimir Makarov  <vmakarov@redhat.com>
 
        PR middle-end/45312
index a3f0567ae4f506f440a1d5de95203f20591e12f2..1d79a18b93a04a1b4a833dbb9211d8dc3bdb42c5 100644 (file)
@@ -55,7 +55,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "cselib.h"
 #include "debug.h"
 #include "dwarf2out.h"
-
+#include "sched-int.h"
 static rtx legitimize_dllimport_symbol (rtx, bool);
 
 #ifndef CHECK_STACK_LIMIT
@@ -31534,6 +31534,806 @@ ix86_enum_va_list (int idx, const char **pname, tree *ptree)
   return 0;
 }
 
+#undef TARGET_SCHED_DISPATCH
+#define TARGET_SCHED_DISPATCH has_dispatch
+#undef TARGET_SCHED_DISPATCH_DO
+#define TARGET_SCHED_DISPATCH_DO do_dispatch
+
+/* The size of the dispatch window is the total number of bytes of
+   object code allowed in a window.  */
+#define DISPATCH_WINDOW_SIZE 16
+
+/* Number of dispatch windows considered for scheduling.  */
+#define MAX_DISPATCH_WINDOWS 3
+
+/* Maximum number of instructions in a window.  */
+#define MAX_INSN 4
+
+/* Maximum number of immediate operands in a window.  */
+#define MAX_IMM 4
+
+/* Maximum number of immediate bits allowed in a window.  */
+#define MAX_IMM_SIZE 128
+
+/* Maximum number of 32 bit immediates allowed in a window.  */
+#define MAX_IMM_32 4
+
+/* Maximum number of 64 bit immediates allowed in a window.  */
+#define MAX_IMM_64 2
+
+/* Maximum total of loads or prefetches allowed in a window.  */
+#define MAX_LOAD 2
+
+/* Maximum total of stores allowed in a window.  */
+#define MAX_STORE 1
+
+#undef BIG
+#define BIG 100
+
+
+/* Dispatch groups.  Istructions that affect the mix in a dispatch window.  */
+enum dispatch_group {
+  disp_no_group = 0,
+  disp_load,
+  disp_store,
+  disp_load_store,
+  disp_prefetch,
+  disp_imm,
+  disp_imm_32,
+  disp_imm_64,
+  disp_branch,
+  disp_cmp,
+  disp_jcc,
+  disp_last
+};
+
+/* Number of allowable groups in a dispatch window.  It is an array
+   indexed by dispatch_group enum.  100 is used as a big number,
+   because the number of these kind of operations does not have any
+   effect in dispatch window, but we need them for other reasons in
+   the table.  */
+static unsigned int num_allowable_groups[disp_last] = {
+  0, 2, 1, 1, 2, 4, 4, 2, 1, BIG, BIG
+};
+
+char group_name[disp_last + 1][16] = {
+  "disp_no_group", "disp_load", "disp_store", "disp_load_store",
+  "disp_prefetch", "disp_imm", "disp_imm_32", "disp_imm_64",
+  "disp_branch", "disp_cmp", "disp_jcc", "disp_last"
+};
+
+/* Instruction path.  */
+enum insn_path {
+  no_path = 0,
+  path_single, /* Single micro op.  */
+  path_double, /* Double micro op.  */
+  path_multi,  /* Instructions with more than 2 micro op..  */
+  last_path
+};
+
+/* sched_insn_info defines a window to the instructions scheduled in
+   the basic block.  It contains a pointer to the insn_info table and
+   the instruction scheduled.
+
+   Windows are allocated for each basic block and are linked
+   together.  */
+typedef struct sched_insn_info_s {
+  rtx insn;
+  enum dispatch_group group;
+  enum insn_path path;
+  int byte_len;
+  int imm_bytes;
+} sched_insn_info;
+
+/* Linked list of dispatch windows.  This is a two way list of
+   dispatch windows of a basic block.  It contains information about
+   the number of uops in the window and the total number of
+   instructions and of bytes in the object code for this dispatch
+   window.  */
+typedef struct dispatch_windows_s {
+  int num_insn;            /* Number of insn in the window.  */
+  int num_uops;            /* Number of uops in the window.  */
+  int window_size;         /* Number of bytes in the window.  */
+  int window_num;          /* Window number between 0 or 1.  */
+  int num_imm;             /* Number of immediates in an insn.  */
+  int num_imm_32;          /* Number of 32 bit immediates in an insn.  */
+  int num_imm_64;          /* Number of 64 bit immediates in an insn.  */
+  int imm_size;            /* Total immediates in the window.  */
+  int num_loads;           /* Total memory loads in the window.  */
+  int num_stores;          /* Total memory stores in the window.  */
+  int violation;          /* Violation exists in window.  */
+  sched_insn_info *window; /* Pointer to the window.  */
+  struct dispatch_windows_s *next;
+  struct dispatch_windows_s *prev;
+} dispatch_windows;
+
+/* Immediate valuse used in an insn.  */
+typedef struct imm_info_s
+  {
+    int imm;
+    int imm32;
+    int imm64;
+  } imm_info;
+
+static dispatch_windows *dispatch_window_list;
+static dispatch_windows *dispatch_window_list1;
+
+/* Get dispatch group of insn.  */
+
+static enum dispatch_group
+get_mem_group (rtx insn)
+{
+  enum attr_memory memory;
+
+  if (INSN_CODE (insn) < 0)
+    return disp_no_group;
+  memory = get_attr_memory (insn);
+  if (memory == MEMORY_STORE)
+    return disp_store;
+
+  if (memory == MEMORY_LOAD)
+    return disp_load;
+
+  if (memory == MEMORY_BOTH)
+    return disp_load_store;
+
+  return disp_no_group;
+}
+
+/* Return true if insn is a compare instruction.  */
+
+static bool
+is_cmp (rtx insn)
+{
+  enum attr_type type;
+
+  type = get_attr_type (insn);
+  return (type == TYPE_TEST
+         || type == TYPE_ICMP
+         || type == TYPE_FCMP
+         || GET_CODE (PATTERN (insn)) == COMPARE);
+}
+
+/* Return true if a dispatch violation encountered.  */
+
+static bool
+dispatch_violation (void)
+{
+  if (dispatch_window_list->next)
+    return dispatch_window_list->next->violation;
+  return dispatch_window_list->violation;
+}
+
+/* Return true if insn is a branch instruction.  */
+
+static bool
+is_branch (rtx insn)
+{
+  return (CALL_P (insn) || JUMP_P (insn));
+}
+
+/* Return true if insn is a prefetch instruction.  */
+
+static bool
+is_prefetch (rtx insn)
+{
+  return NONJUMP_INSN_P (insn) && GET_CODE (PATTERN (insn)) == PREFETCH;
+}
+
+/* This function initializes a dispatch window and the list container holding a
+   pointer to the window.  */
+
+static void
+init_window (int window_num)
+{
+  int i;
+  dispatch_windows *new_list;
+
+  if (window_num == 0)
+    new_list = dispatch_window_list;
+  else
+    new_list = dispatch_window_list1;
+
+  new_list->num_insn = 0;
+  new_list->num_uops = 0;
+  new_list->window_size = 0;
+  new_list->next = NULL;
+  new_list->prev = NULL;
+  new_list->window_num = window_num;
+  new_list->num_imm = 0;
+  new_list->num_imm_32 = 0;
+  new_list->num_imm_64 = 0;
+  new_list->imm_size = 0;
+  new_list->num_loads = 0;
+  new_list->num_stores = 0;
+  new_list->violation = false;
+
+  for (i = 0; i < MAX_INSN; i++)
+    {
+      new_list->window[i].insn = NULL;
+      new_list->window[i].group = disp_no_group;
+      new_list->window[i].path = no_path;
+      new_list->window[i].byte_len = 0;
+      new_list->window[i].imm_bytes = 0;
+    }
+  return;
+}
+
+/* This function allocates and initializes a dispatch window and the
+   list container holding a pointer to the window.  */
+
+static dispatch_windows *
+allocate_window (void)
+{
+  dispatch_windows *new_list = XNEW (struct dispatch_windows_s);
+  new_list->window = XNEWVEC (struct sched_insn_info_s, MAX_INSN + 1);
+
+  return new_list;
+}
+
+/* This routine initializes the dispatch scheduling information.  It
+   initiates building dispatch scheduler tables and constructs the
+   first dispatch window.  */
+
+static void
+init_dispatch_sched (void)
+{
+  /* Allocate a dispatch list and a window.  */
+  dispatch_window_list = allocate_window ();
+  dispatch_window_list1 = allocate_window ();
+  init_window (0);
+  init_window (1);
+}
+
+/* This function returns true if a branch is detected.  End of a basic block
+   does not have to be a branch, but here we assume only branches end a
+   window.  */
+
+static bool
+is_end_basic_block (enum dispatch_group group)
+{
+  return group == disp_branch;
+}
+
+/* This function is called when the end of a window processing is reached.  */
+
+static void
+process_end_window (void)
+{
+  gcc_assert (dispatch_window_list->num_insn <= MAX_INSN);
+  if (dispatch_window_list->next)
+    {
+      gcc_assert (dispatch_window_list1->num_insn <= MAX_INSN);
+      gcc_assert (dispatch_window_list->window_size
+                 + dispatch_window_list1->window_size <= 48);
+      init_window (1);
+    }
+  init_window (0);
+}
+
+/* Allocates a new dispatch window and adds it to WINDOW_LIST.
+   WINDOW_NUM is either 0 or 1.  A maximum of two windows are generated
+   for 48 bytes of instructions.  Note that these windows are not dispatch
+   windows that their sizes are DISPATCH_WINDOW_SIZE.  */
+
+static dispatch_windows *
+allocate_next_window (int window_num)
+{
+  if (window_num == 0)
+    {
+      if (dispatch_window_list->next)
+         init_window (1);
+      init_window (0);
+      return dispatch_window_list;
+    }
+
+  dispatch_window_list->next = dispatch_window_list1;
+  dispatch_window_list1->prev = dispatch_window_list;
+
+  return dispatch_window_list1;
+}
+
+/* Increment the number of immediate operands of an instruction.  */
+
+static int
+find_constant_1 (rtx *in_rtx, imm_info *imm_values)
+{
+  if (*in_rtx == 0)
+    return 0;
+
+    switch ( GET_CODE (*in_rtx))
+    {
+    case CONST:
+    case SYMBOL_REF:
+    case CONST_INT:
+      (imm_values->imm)++;
+      if (x86_64_immediate_operand (*in_rtx, SImode))
+       (imm_values->imm32)++;
+      else
+       (imm_values->imm64)++;
+      break;
+
+    case CONST_DOUBLE:
+      (imm_values->imm)++;
+      (imm_values->imm64)++;
+      break;
+
+    case CODE_LABEL:
+      if (LABEL_KIND (*in_rtx) == LABEL_NORMAL)
+       {
+         (imm_values->imm)++;
+         (imm_values->imm32)++;
+       }
+      break;
+
+    default:
+      break;
+    }
+
+  return 0;
+}
+
+/* Compute number of immediate operands of an instruction.  */
+
+static void
+find_constant (rtx in_rtx, imm_info *imm_values)
+{
+  for_each_rtx (INSN_P (in_rtx) ? &PATTERN (in_rtx) : &in_rtx,
+               (rtx_function) find_constant_1, (void *) imm_values);
+}
+
+/* Return total size of immediate operands of an instruction along with number
+   of corresponding immediate-operands.  It initializes its parameters to zero
+   befor calling FIND_CONSTANT.
+   INSN is the input instruction.  IMM is the total of immediates.
+   IMM32 is the number of 32 bit immediates.  IMM64 is the number of 64
+   bit immediates.  */
+
+static int
+get_num_immediates (rtx insn, int *imm, int *imm32, int *imm64)
+{
+  imm_info imm_values = {0, 0, 0};
+
+  find_constant (insn, &imm_values);
+  *imm = imm_values.imm;
+  *imm32 = imm_values.imm32;
+  *imm64 = imm_values.imm64;
+  return imm_values.imm32 * 4 + imm_values.imm64 * 8;
+}
+
+/* This function indicates if an operand of an instruction is an
+   immediate.  */
+
+static bool
+has_immediate (rtx insn)
+{
+  int num_imm_operand;
+  int num_imm32_operand;
+  int num_imm64_operand;
+
+  if (insn)
+    return get_num_immediates (insn, &num_imm_operand, &num_imm32_operand,
+                              &num_imm64_operand);
+  return false;
+}
+
+/* Return single or double path for instructions.  */
+
+static enum insn_path
+get_insn_path (rtx insn)
+{
+  enum attr_amdfam10_decode path = get_attr_amdfam10_decode (insn);
+
+  if ((int)path == 0)
+    return path_single;
+
+  if ((int)path == 1)
+    return path_double;
+
+  return path_multi;
+}
+
+/* Return insn dispatch group.  */
+
+static enum dispatch_group
+get_insn_group (rtx insn)
+{
+  enum dispatch_group group = get_mem_group (insn);
+  if (group)
+    return group;
+
+  if (is_branch (insn))
+    return disp_branch;
+
+  if (is_cmp (insn))
+    return disp_cmp;
+
+  if (has_immediate (insn))
+    return disp_imm;
+
+  if (is_prefetch (insn))
+    return disp_prefetch;
+
+  return disp_no_group;
+}
+
+/* Count number of GROUP restricted instructions in a dispatch
+   window WINDOW_LIST.  */
+
+static int
+count_num_restricted (rtx insn, dispatch_windows *window_list)
+{
+  enum dispatch_group group = get_insn_group (insn);
+  int imm_size;
+  int num_imm_operand;
+  int num_imm32_operand;
+  int num_imm64_operand;
+
+  if (group == disp_no_group)
+    return 0;
+
+  if (group == disp_imm)
+    {
+      imm_size = get_num_immediates (insn, &num_imm_operand, &num_imm32_operand,
+                             &num_imm64_operand);
+      if (window_list->imm_size + imm_size > MAX_IMM_SIZE
+         || num_imm_operand + window_list->num_imm > MAX_IMM
+         || (num_imm32_operand > 0
+             && (window_list->num_imm_32 + num_imm32_operand > MAX_IMM_32
+                 || window_list->num_imm_64 * 2 + num_imm32_operand > MAX_IMM_32))
+         || (num_imm64_operand > 0
+             && (window_list->num_imm_64 + num_imm64_operand > MAX_IMM_64
+                 || window_list->num_imm_32 + num_imm64_operand * 2 > MAX_IMM_32))
+         || (window_list->imm_size + imm_size == MAX_IMM_SIZE
+             && num_imm64_operand > 0
+             && ((window_list->num_imm_64 > 0
+                  && window_list->num_insn >= 2)
+                 || window_list->num_insn >= 3)))
+       return BIG;
+
+      return 1;
+    }
+
+  if ((group == disp_load_store
+       && (window_list->num_loads >= MAX_LOAD
+          || window_list->num_stores >= MAX_STORE))
+      || ((group == disp_load
+          || group == disp_prefetch)
+         && window_list->num_loads >= MAX_LOAD)
+      || (group == disp_store
+         && window_list->num_stores >= MAX_STORE))
+    return BIG;
+
+  return 1;
+}
+
+/* This function returns true if insn satisfies dispatch rules on the
+   last window scheduled.  */
+
+static bool
+fits_dispatch_window (rtx insn)
+{
+  dispatch_windows *window_list = dispatch_window_list;
+  dispatch_windows *window_list_next = dispatch_window_list->next;
+  unsigned int num_restrict;
+  enum dispatch_group group = get_insn_group (insn);
+  enum insn_path path = get_insn_path (insn);
+  int sum;
+
+  /* Make disp_cmp and disp_jcc get scheduled at the latest.  These
+     instructions should be given the lowest priority in the
+     scheduling process in Haifa scheduler to make sure they will be
+     scheduled in the same dispatch window as the refrence to them.  */
+  if (group == disp_jcc || group == disp_cmp)
+    return false;
+
+  /* Check nonrestricted.  */
+  if (group == disp_no_group || group == disp_branch)
+    return true;
+
+  /* Get last dispatch window.  */
+  if (window_list_next)
+    window_list = window_list_next;
+
+  if (window_list->window_num == 1)
+    {
+      sum = window_list->prev->window_size + window_list->window_size;
+
+      if (sum == 32
+         || (min_insn_size (insn) + sum) >= 48)
+       /* Window 1 is full.  Go for next window.  */
+       return true;
+    }
+
+  num_restrict = count_num_restricted (insn, window_list);
+
+  if (num_restrict > num_allowable_groups[group])
+    return false;
+
+  /* See if it fits in the first window.  */
+  if (window_list->window_num == 0)
+    {
+      /* The first widow should have only single and double path
+        uops.  */
+      if (path == path_double
+         && (window_list->num_uops + 2) > MAX_INSN)
+       return false;
+      else if (path != path_single)
+        return false;
+    }
+  return true;
+}
+
+/* Add an instruction INSN with NUM_UOPS micro-operations to the
+   dispatch window WINDOW_LIST.  */
+
+static void
+add_insn_window (rtx insn, dispatch_windows *window_list, int num_uops)
+{
+  int byte_len = min_insn_size (insn);
+  int num_insn = window_list->num_insn;
+  int imm_size;
+  sched_insn_info *window = window_list->window;
+  enum dispatch_group group = get_insn_group (insn);
+  enum insn_path path = get_insn_path (insn);
+  int num_imm_operand;
+  int num_imm32_operand;
+  int num_imm64_operand;
+
+  if (!window_list->violation && group != disp_cmp
+      && !fits_dispatch_window (insn))
+    window_list->violation = true;
+
+  imm_size = get_num_immediates (insn, &num_imm_operand, &num_imm32_operand,
+                                &num_imm64_operand);
+
+  /* Initialize window with new instruction.  */
+  window[num_insn].insn = insn;
+  window[num_insn].byte_len = byte_len;
+  window[num_insn].group = group;
+  window[num_insn].path = path;
+  window[num_insn].imm_bytes = imm_size;
+
+  window_list->window_size += byte_len;
+  window_list->num_insn = num_insn + 1;
+  window_list->num_uops = window_list->num_uops + num_uops;
+  window_list->imm_size += imm_size;
+  window_list->num_imm += num_imm_operand;
+  window_list->num_imm_32 += num_imm32_operand;
+  window_list->num_imm_64 += num_imm64_operand;
+
+  if (group == disp_store)
+    window_list->num_stores += 1;
+  else if (group == disp_load
+          || group == disp_prefetch)
+    window_list->num_loads += 1;
+  else if (group == disp_load_store)
+    {
+      window_list->num_stores += 1;
+      window_list->num_loads += 1;
+    }
+}
+
+/* Adds a scheduled instruction, INSN, to the current dispatch window.
+   If the total bytes of instructions or the number of instructions in
+   the window exceed allowable, it allocates a new window.  */
+
+static void
+add_to_dispatch_window (rtx insn)
+{
+  int byte_len;
+  dispatch_windows *window_list;
+  dispatch_windows *next_list;
+  dispatch_windows *window0_list;
+  enum insn_path path;
+  enum dispatch_group insn_group;
+  bool insn_fits;
+  int num_insn;
+  int num_uops;
+  int window_num;
+  int insn_num_uops;
+  int sum;
+
+  if (INSN_CODE (insn) < 0)
+    return;
+
+  byte_len = min_insn_size (insn);
+  window_list = dispatch_window_list;
+  next_list = window_list->next;
+  path = get_insn_path (insn);
+  insn_group = get_insn_group (insn);
+
+  /* Get the last dispatch window.  */
+  if (next_list)
+      window_list = dispatch_window_list->next;
+
+  if (path == path_single)
+    insn_num_uops = 1;
+  else if (path == path_double)
+    insn_num_uops = 2;
+  else
+    insn_num_uops = (int) path;
+
+  /* If current window is full, get a new window.
+     Window number zero is full, if MAX_INSN uops are scheduled in it.
+     Window number one is full, if window zero's bytes plus window
+     one's bytes is 32, or if the bytes of the new instruction added
+     to the total makes it greater than 48, or it has already MAX_INSN
+     instructions in it.  */
+  num_insn = window_list->num_insn;
+  num_uops = window_list->num_uops;
+  window_num = window_list->window_num;
+  insn_fits = fits_dispatch_window (insn);
+
+  if (num_insn >= MAX_INSN
+      || num_uops + insn_num_uops > MAX_INSN
+      || !(insn_fits))
+    {
+      window_num = ~window_num & 1;
+      window_list = allocate_next_window (window_num);
+    }
+
+  if (window_num == 0)
+    {
+      add_insn_window (insn, window_list, insn_num_uops);
+      if (window_list->num_insn >= MAX_INSN
+         && insn_group == disp_branch)
+       {
+         process_end_window ();
+         return;
+       }
+    }
+  else if (window_num == 1)
+    {
+      window0_list = window_list->prev;
+      sum = window0_list->window_size + window_list->window_size;
+      if (sum == 32
+         || (byte_len + sum) >= 48)
+       {
+         process_end_window ();
+         window_list = dispatch_window_list;
+       }
+
+      add_insn_window (insn, window_list, insn_num_uops);
+    }
+  else
+    gcc_unreachable ();
+
+  if (is_end_basic_block (insn_group))
+    {
+      /* End of basic block is reached do end-basic-block process.  */
+      process_end_window ();
+      return;
+    }
+}
+
+/* Print the dispatch window, WINDOW_NUM, to FILE.  */
+
+DEBUG_FUNCTION static void
+debug_dispatch_window_file (FILE *file, int window_num)
+{
+  dispatch_windows *list;
+  int i;
+
+  if (window_num == 0)
+    list = dispatch_window_list;
+  else
+    list = dispatch_window_list1;
+
+  fprintf (file, "Window #%d:\n", list->window_num);
+  fprintf (file, "  num_insn = %d, num_uops = %d, window_size = %d\n",
+         list->num_insn, list->num_uops, list->window_size);
+  fprintf (file, "  num_imm = %d, num_imm_32 = %d, num_imm_64 = %d, imm_size = %d\n",
+          list->num_imm, list->num_imm_32, list->num_imm_64, list->imm_size);
+
+  fprintf (file, "  num_loads = %d, num_stores = %d\n", list->num_loads,
+         list->num_stores);
+  fprintf (file, " insn info:\n");
+
+  for (i = 0; i < MAX_INSN; i++)
+    {
+      if (!list->window[i].insn)
+       break;
+      fprintf (file, "    group[%d] = %s, insn[%d] = %p, path[%d] = %d byte_len[%d] = %d, imm_bytes[%d] = %d\n",
+             i, group_name[list->window[i].group],
+             i, (void *)list->window[i].insn,
+             i, list->window[i].path,
+             i, list->window[i].byte_len,
+             i, list->window[i].imm_bytes);
+    }
+}
+
+/* Print to stdout a dispatch window.  */
+
+DEBUG_FUNCTION void
+debug_dispatch_window (int window_num)
+{
+  debug_dispatch_window_file (stdout, window_num);
+}
+
+/* Print INSN dispatch information to FILE.  */
+
+DEBUG_FUNCTION static void
+debug_insn_dispatch_info_file (FILE *file, rtx insn)
+{
+  int byte_len;
+  enum insn_path path;
+  enum dispatch_group group;
+  int imm_size;
+  int num_imm_operand;
+  int num_imm32_operand;
+  int num_imm64_operand;
+
+  if (INSN_CODE (insn) < 0)
+    return;
+
+  byte_len = min_insn_size (insn);
+  path = get_insn_path (insn);
+  group = get_insn_group (insn);
+  imm_size = get_num_immediates (insn, &num_imm_operand, &num_imm32_operand,
+                                &num_imm64_operand);
+
+  fprintf (file, " insn info:\n");
+  fprintf (file, "  group = %s, path = %d, byte_len = %d\n",
+          group_name[group], path, byte_len);
+  fprintf (file, "  num_imm = %d, num_imm_32 = %d, num_imm_64 = %d, imm_size = %d\n",
+          num_imm_operand, num_imm32_operand, num_imm64_operand, imm_size);
+}
+
+/* Print to STDERR the status of the ready list with respect to
+   dispatch windows.  */
+
+DEBUG_FUNCTION void
+debug_ready_dispatch (void)
+{
+  int i;
+  int no_ready = number_in_ready ();
+
+  fprintf (stdout, "Number of ready: %d\n", no_ready);
+
+  for (i = 0; i < no_ready; i++)
+    debug_insn_dispatch_info_file (stdout, get_ready_element (i));
+}
+
+/* This routine is the driver of the dispatch scheduler.  */
+
+static void
+do_dispatch (rtx insn, int mode)
+{
+  if (mode == DISPATCH_INIT)
+    init_dispatch_sched ();
+  else if (mode == ADD_TO_DISPATCH_WINDOW)
+    add_to_dispatch_window (insn);
+}
+
+/* Return TRUE if Dispatch Scheduling is supported.  */
+
+static bool
+has_dispatch (rtx insn, int action)
+{
+  if (ix86_tune == PROCESSOR_BDVER1 && flag_dispatch_scheduler)
+    switch (action)
+      {
+      default:
+       return false;
+
+      case IS_DISPATCH_ON:
+       return true;
+       break;
+
+      case IS_CMP:
+       return is_cmp (insn);
+
+      case DISPATCH_VIOLATION:
+       return dispatch_violation ();
+
+      case FITS_DISPATCH_WINDOW:
+       return fits_dispatch_window (insn);
+      }
+
+  return false;
+}
+
 /* Initialize the GCC target structure.  */
 #undef TARGET_RETURN_IN_MEMORY
 #define TARGET_RETURN_IN_MEMORY ix86_return_in_memory
index 49402d185b13572c170ba086aa027ee735d99449..91238d5d7c7ce45c86ebe0a9c51661bfdc20b5ad 100644 (file)
@@ -2375,6 +2375,9 @@ struct GTY(()) machine_function {
 #define SYMBOL_REF_DLLEXPORT_P(X) \
        ((SYMBOL_REF_FLAGS (X) & SYMBOL_FLAG_DLLEXPORT) != 0)
 
+extern void debug_ready_dispatch (void);
+extern void debug_dispatch_window (int);
+
 /*
 Local variables:
 version-control: t
index 8009830ebfe7b97b113d23ef8a0d505d8781178a..5790e7675115b26a7c2b4f820b5a9da3cd54ed04 100644 (file)
@@ -254,6 +254,11 @@ Enable automatic generation of fused floating point multiply-add instructions
 if the ISA supports such instructions.  The -mfused-madd option is on by
 default.
 
+mdispatch-scheduler
+Target RejectNegative Var(flag_dispatch_scheduler)
+Do dispatch scheduling if processor is bdver1 and Haifa scheduling
+is selected.
+
 ;; ISA support
 
 m32
index e60392f9fa825b9c776962a4486f972d4ea53ab4..91fbaf7a893ff8ca2e277baa46761eac7b9f4f54 100644 (file)
@@ -6777,6 +6777,16 @@ bound will be used in case this hook is not implemented: the total number
 of instructions divided by the issue rate.
 @end deftypefn
 
+@deftypefn {Target Hook} bool TARGET_SCHED_DISPATCH (rtx @var{insn}, int @var{x})
+This hook is called by Haifa Scheduler.  It returns true if dispatch scheduling
+is supported in hardware and the condition specified in the parameter is true.
+@end deftypefn
+
+@deftypefn {Target Hook} void TARGET_SCHED_DISPATCH_DO (rtx @var{insn}, int @var{x})
+This hook is called by Haifa Scheduler.  It performs the operation specified
+in its second parameter.
+@end deftypefn
+
 @node Sections
 @section Dividing the Output into Sections (Texts, Data, @dots{})
 @c the above section title is WAY too long.  maybe cut the part between
index 17fcd4bd4dec84121373407ec6be915a096413b3..a180a56c9ab7b9bc931b526257bec8cee0f8ad62 100644 (file)
@@ -6777,6 +6777,16 @@ bound will be used in case this hook is not implemented: the total number
 of instructions divided by the issue rate.
 @end deftypefn
 
+@hook TARGET_SCHED_DISPATCH
+This hook is called by Haifa Scheduler.  It returns true if dispatch scheduling
+is supported in hardware and the condition specified in the parameter is true.
+@end deftypefn
+
+@hook TARGET_SCHED_DISPATCH_DO
+This hook is called by Haifa Scheduler.  It performs the operation specified
+in its second parameter.
+@end deftypefn
+
 @node Sections
 @section Dividing the Output into Sections (Texts, Data, @dots{})
 @c the above section title is WAY too long.  maybe cut the part between
index 278768547a81cb8392db733feb2f8885b0345f35..5b5459f7caed42a94bb342fd2fc11119793ec610 100644 (file)
@@ -532,6 +532,7 @@ static void extend_h_i_d (void);
 
 static void ready_add (struct ready_list *, rtx, bool);
 static rtx ready_remove_first (struct ready_list *);
+static rtx ready_remove_first_dispatch (struct ready_list *ready);
 
 static void queue_to_ready (struct ready_list *);
 static int early_queue_to_ready (state_t, struct ready_list *);
@@ -2642,7 +2643,11 @@ choose_ready (struct ready_list *ready, rtx *insn_ptr)
   if (lookahead <= 0 || SCHED_GROUP_P (ready_element (ready, 0))
       || DEBUG_INSN_P (ready_element (ready, 0)))
     {
-      *insn_ptr = ready_remove_first (ready);
+      if (targetm.sched.dispatch (NULL_RTX, IS_DISPATCH_ON))
+       *insn_ptr = ready_remove_first_dispatch (ready);
+      else
+       *insn_ptr = ready_remove_first (ready);
+
       return 0;
     }
   else
@@ -3140,6 +3145,10 @@ schedule_block (basic_block *target_bb)
                                                       last_scheduled_insn);
 
          move_insn (insn, last_scheduled_insn, current_sched_info->next_tail);
+
+         if (targetm.sched.dispatch (NULL_RTX, IS_DISPATCH_ON))
+           targetm.sched.dispatch_do (insn, ADD_TO_DISPATCH_WINDOW);
+
          reemit_notes (insn);
          last_scheduled_insn = insn;
 
@@ -3364,8 +3373,12 @@ sched_init (void)
   flag_schedule_speculative_load = 0;
 #endif
 
+  if (targetm.sched.dispatch (NULL_RTX, IS_DISPATCH_ON))
+    targetm.sched.dispatch_do (NULL_RTX, DISPATCH_INIT);
+
   sched_pressure_p = (flag_sched_pressure && ! reload_completed
                      && common_sched_info->sched_pass_id == SCHED_RGN_PASS);
+
   if (sched_pressure_p)
     ira_setup_eliminable_regset ();
 
@@ -5557,4 +5570,73 @@ sched_emit_insn (rtx pat)
   return insn;
 }
 
+/* This function returns a candidate satisfying dispatch constraints from
+   the ready list.  */
+
+static rtx
+ready_remove_first_dispatch (struct ready_list *ready)
+{
+  int i;
+  rtx insn = ready_element (ready, 0);
+
+  if (ready->n_ready == 1
+      || INSN_CODE (insn) < 0
+      || !INSN_P (insn)
+      || !active_insn_p (insn)
+      || targetm.sched.dispatch (insn, FITS_DISPATCH_WINDOW))
+    return ready_remove_first (ready);
+
+  for (i = 1; i < ready->n_ready; i++)
+    {
+      insn = ready_element (ready, i);
+
+      if (INSN_CODE (insn) < 0
+         || !INSN_P (insn)
+         || !active_insn_p (insn))
+       continue;
+
+      if (targetm.sched.dispatch (insn, FITS_DISPATCH_WINDOW))
+       {
+         /* Return ith element of ready.  */
+         insn = ready_remove (ready, i);
+         return insn;
+       }
+    }
+
+  if (targetm.sched.dispatch (NULL_RTX, DISPATCH_VIOLATION))
+    return ready_remove_first (ready);
+
+  for (i = 1; i < ready->n_ready; i++)
+    {
+      insn = ready_element (ready, i);
+
+      if (INSN_CODE (insn) < 0
+         || !INSN_P (insn)
+         || !active_insn_p (insn))
+       continue;
+
+      /* Return i-th element of ready.  */
+      if (targetm.sched.dispatch (insn, IS_CMP))
+       return ready_remove (ready, i);
+    }
+
+  return ready_remove_first (ready);
+}
+
+/* Get number of ready insn in the ready list.  */
+
+int
+number_in_ready (void)
+{
+  return ready.n_ready;
+}
+
+/* Get number of ready's in the ready list.  */
+
+rtx
+get_ready_element (int i)
+{
+  return ready_element (&ready, i);
+}
+
 #endif /* INSN_SCHEDULING */
index 52a40484054d6937aaeed76d8a9fbe3ff4e95e19..4d5be73c5994fe6e171c1c0c208e890fead93a03 100644 (file)
@@ -340,3 +340,18 @@ hook_tree_const_tree_null (const_tree t ATTRIBUTE_UNUSED)
 {
   return NULL;
 }
+
+/* Generic hook that takes a rtx and an int and returns a bool.  */
+
+bool
+hook_bool_rtx_int_false (rtx insn ATTRIBUTE_UNUSED, int mode ATTRIBUTE_UNUSED)
+{
+  return false;
+}
+
+/* Generic hook that takes a rtx and an int and returns void.  */
+
+void
+hook_void_rtx_int (rtx insn ATTRIBUTE_UNUSED, int mode ATTRIBUTE_UNUSED)
+{
+}
index a89a355f879da6a841417b2b91e6c0ca39ad190c..9e4a0aeeb748c255d4a740407e2c0f3ee0a59584 100644 (file)
@@ -46,6 +46,7 @@ extern bool hook_bool_const_tree_hwi_hwi_const_tree_true (const_tree,
                                                          HOST_WIDE_INT,
                                                          const_tree);
 extern bool hook_bool_rtx_false (rtx);
+extern bool hook_bool_rtx_int_false (rtx, int);
 extern bool hook_bool_uintp_uintp_false (unsigned int *, unsigned int *);
 extern bool hook_bool_rtx_int_int_intp_bool_false (rtx, int, int, int *, bool);
 extern bool hook_bool_size_t_constcharptr_int_true (size_t, const char *, int);
@@ -55,6 +56,7 @@ extern bool hook_bool_tree_bool_false (tree, bool);
 
 extern void hook_void_void (void);
 extern void hook_void_constcharptr (const char *);
+extern void hook_void_rtx_int (rtx, int);
 extern void hook_void_FILEptr_constcharptr (FILE *, const char *);
 extern void hook_void_tree (tree);
 extern void hook_void_tree_treeptr (tree, tree *);
index 147e264848aa3aaa5bd6415c059ce34cdd57ee73..fd2e15d70cfe167bbe359723fd97decf41f7fc8b 100644 (file)
@@ -1269,6 +1269,8 @@ extern void add_block (basic_block, basic_block);
 extern rtx bb_note (basic_block);
 extern void concat_note_lists (rtx, rtx *);
 extern rtx sched_emit_insn (rtx);
+extern rtx get_ready_element (int);
+extern int number_in_ready (void);
 \f
 
 /* Types and functions in sched-rgn.c.  */
@@ -1477,6 +1479,13 @@ sd_iterator_next (sd_iterator_def *it_ptr)
        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);
index 6910ce9e2327f96847f4c6a67579749fbbcd182c..cecf882c9054cc2e9c1dbb288c419b4700a6caf5 100644 (file)
@@ -777,6 +777,24 @@ DEFHOOK
  "",
  int, (struct ddg *g), NULL)
 
+/* The following member value is a function that initializes dispatch
+   schedling and adds instructions to dispatch window according to its
+   parameters.  */
+DEFHOOK
+(dispatch_do,
+"",
+void, (rtx insn, int x),
+hook_void_rtx_int)
+
+/* The following member value is a a function that returns true is
+   dispatch schedling is supported in hardware and condition passed
+   as the second parameter is true.  */
+DEFHOOK
+(dispatch,
+"",
+bool, (rtx insn, int x),
+hook_bool_rtx_int_false)
+
 HOOK_VECTOR_END (sched)
 
 /* Functions relating to vectorization.  */