Dispatch scheduling for AMD Bulldozer processors.

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.

From-SVN: r164133
This commit is contained in:
Reza Yazdani 2010-09-09 23:11:36 +00:00 committed by Sebastian Pop
parent be1c764ef4
commit 7942e47efd
11 changed files with 1036 additions and 2 deletions

View 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

View 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

View 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

View 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

View 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

View 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

View 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 */

View 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)
{
}

View 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 *);

View 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);
/* 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);

View 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. */