1*38fd1498Szrj /* Scheduler hooks for IA-32 which implement bdver1-4 specific logic.
2*38fd1498Szrj    Copyright (C) 1988-2018 Free Software Foundation, Inc.
3*38fd1498Szrj 
4*38fd1498Szrj This file is part of GCC.
5*38fd1498Szrj 
6*38fd1498Szrj GCC is free software; you can redistribute it and/or modify
7*38fd1498Szrj it under the terms of the GNU General Public License as published by
8*38fd1498Szrj the Free Software Foundation; either version 3, or (at your option)
9*38fd1498Szrj any later version.
10*38fd1498Szrj 
11*38fd1498Szrj GCC is distributed in the hope that it will be useful,
12*38fd1498Szrj but WITHOUT ANY WARRANTY; without even the implied warranty of
13*38fd1498Szrj MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14*38fd1498Szrj GNU General Public License for more details.
15*38fd1498Szrj 
16*38fd1498Szrj You should have received a copy of the GNU General Public License
17*38fd1498Szrj along with GCC; see the file COPYING3.  If not see
18*38fd1498Szrj <http://www.gnu.org/licenses/>.  */
19*38fd1498Szrj 
20*38fd1498Szrj #define IN_TARGET_CODE 1
21*38fd1498Szrj 
22*38fd1498Szrj #include "config.h"
23*38fd1498Szrj #include "system.h"
24*38fd1498Szrj #include "coretypes.h"
25*38fd1498Szrj #include "backend.h"
26*38fd1498Szrj #include "rtl.h"
27*38fd1498Szrj #include "tree.h"
28*38fd1498Szrj #include "cfghooks.h"
29*38fd1498Szrj #include "tm_p.h"
30*38fd1498Szrj #include "insn-config.h"
31*38fd1498Szrj #include "insn-attr.h"
32*38fd1498Szrj #include "recog.h"
33*38fd1498Szrj #include "target.h"
34*38fd1498Szrj #include "rtl-iter.h"
35*38fd1498Szrj #include "regset.h"
36*38fd1498Szrj #include "sched-int.h"
37*38fd1498Szrj 
38*38fd1498Szrj /* The size of the dispatch window is the total number of bytes of
39*38fd1498Szrj    object code allowed in a window.  */
40*38fd1498Szrj #define DISPATCH_WINDOW_SIZE 16
41*38fd1498Szrj 
42*38fd1498Szrj /* Number of dispatch windows considered for scheduling.  */
43*38fd1498Szrj #define MAX_DISPATCH_WINDOWS 3
44*38fd1498Szrj 
45*38fd1498Szrj /* Maximum number of instructions in a window.  */
46*38fd1498Szrj #define MAX_INSN 4
47*38fd1498Szrj 
48*38fd1498Szrj /* Maximum number of immediate operands in a window.  */
49*38fd1498Szrj #define MAX_IMM 4
50*38fd1498Szrj 
51*38fd1498Szrj /* Maximum number of immediate bits allowed in a window.  */
52*38fd1498Szrj #define MAX_IMM_SIZE 128
53*38fd1498Szrj 
54*38fd1498Szrj /* Maximum number of 32 bit immediates allowed in a window.  */
55*38fd1498Szrj #define MAX_IMM_32 4
56*38fd1498Szrj 
57*38fd1498Szrj /* Maximum number of 64 bit immediates allowed in a window.  */
58*38fd1498Szrj #define MAX_IMM_64 2
59*38fd1498Szrj 
60*38fd1498Szrj /* Maximum total of loads or prefetches allowed in a window.  */
61*38fd1498Szrj #define MAX_LOAD 2
62*38fd1498Szrj 
63*38fd1498Szrj /* Maximum total of stores allowed in a window.  */
64*38fd1498Szrj #define MAX_STORE 1
65*38fd1498Szrj 
66*38fd1498Szrj #undef BIG
67*38fd1498Szrj #define BIG 100
68*38fd1498Szrj 
69*38fd1498Szrj 
70*38fd1498Szrj /* Dispatch groups.  Istructions that affect the mix in a dispatch window.  */
71*38fd1498Szrj enum dispatch_group {
72*38fd1498Szrj   disp_no_group = 0,
73*38fd1498Szrj   disp_load,
74*38fd1498Szrj   disp_store,
75*38fd1498Szrj   disp_load_store,
76*38fd1498Szrj   disp_prefetch,
77*38fd1498Szrj   disp_imm,
78*38fd1498Szrj   disp_imm_32,
79*38fd1498Szrj   disp_imm_64,
80*38fd1498Szrj   disp_branch,
81*38fd1498Szrj   disp_cmp,
82*38fd1498Szrj   disp_jcc,
83*38fd1498Szrj   disp_last
84*38fd1498Szrj };
85*38fd1498Szrj 
86*38fd1498Szrj /* Number of allowable groups in a dispatch window.  It is an array
87*38fd1498Szrj    indexed by dispatch_group enum.  100 is used as a big number,
88*38fd1498Szrj    because the number of these kind of operations does not have any
89*38fd1498Szrj    effect in dispatch window, but we need them for other reasons in
90*38fd1498Szrj    the table.  */
91*38fd1498Szrj static unsigned int num_allowable_groups[disp_last] = {
92*38fd1498Szrj   0, 2, 1, 1, 2, 4, 4, 2, 1, BIG, BIG
93*38fd1498Szrj };
94*38fd1498Szrj 
95*38fd1498Szrj char group_name[disp_last + 1][16] = {
96*38fd1498Szrj   "disp_no_group", "disp_load", "disp_store", "disp_load_store",
97*38fd1498Szrj   "disp_prefetch", "disp_imm", "disp_imm_32", "disp_imm_64",
98*38fd1498Szrj   "disp_branch", "disp_cmp", "disp_jcc", "disp_last"
99*38fd1498Szrj };
100*38fd1498Szrj 
101*38fd1498Szrj /* Instruction path.  */
102*38fd1498Szrj enum insn_path {
103*38fd1498Szrj   no_path = 0,
104*38fd1498Szrj   path_single, /* Single micro op.  */
105*38fd1498Szrj   path_double, /* Double micro op.  */
106*38fd1498Szrj   path_multi,  /* Instructions with more than 2 micro op..  */
107*38fd1498Szrj   last_path
108*38fd1498Szrj };
109*38fd1498Szrj 
110*38fd1498Szrj /* sched_insn_info defines a window to the instructions scheduled in
111*38fd1498Szrj    the basic block.  It contains a pointer to the insn_info table and
112*38fd1498Szrj    the instruction scheduled.
113*38fd1498Szrj 
114*38fd1498Szrj    Windows are allocated for each basic block and are linked
115*38fd1498Szrj    together.  */
116*38fd1498Szrj typedef struct sched_insn_info_s {
117*38fd1498Szrj   rtx insn;
118*38fd1498Szrj   enum dispatch_group group;
119*38fd1498Szrj   enum insn_path path;
120*38fd1498Szrj   int byte_len;
121*38fd1498Szrj   int imm_bytes;
122*38fd1498Szrj } sched_insn_info;
123*38fd1498Szrj 
124*38fd1498Szrj /* Linked list of dispatch windows.  This is a two way list of
125*38fd1498Szrj    dispatch windows of a basic block.  It contains information about
126*38fd1498Szrj    the number of uops in the window and the total number of
127*38fd1498Szrj    instructions and of bytes in the object code for this dispatch
128*38fd1498Szrj    window.  */
129*38fd1498Szrj typedef struct dispatch_windows_s {
130*38fd1498Szrj   int num_insn;            /* Number of insn in the window.  */
131*38fd1498Szrj   int num_uops;            /* Number of uops in the window.  */
132*38fd1498Szrj   int window_size;         /* Number of bytes in the window.  */
133*38fd1498Szrj   int window_num;          /* Window number between 0 or 1.  */
134*38fd1498Szrj   int num_imm;             /* Number of immediates in an insn.  */
135*38fd1498Szrj   int num_imm_32;          /* Number of 32 bit immediates in an insn.  */
136*38fd1498Szrj   int num_imm_64;          /* Number of 64 bit immediates in an insn.  */
137*38fd1498Szrj   int imm_size;            /* Total immediates in the window.  */
138*38fd1498Szrj   int num_loads;           /* Total memory loads in the window.  */
139*38fd1498Szrj   int num_stores;          /* Total memory stores in the window.  */
140*38fd1498Szrj   int violation;          /* Violation exists in window.  */
141*38fd1498Szrj   sched_insn_info *window; /* Pointer to the window.  */
142*38fd1498Szrj   struct dispatch_windows_s *next;
143*38fd1498Szrj   struct dispatch_windows_s *prev;
144*38fd1498Szrj } dispatch_windows;
145*38fd1498Szrj 
146*38fd1498Szrj /* Immediate valuse used in an insn.  */
147*38fd1498Szrj typedef struct imm_info_s
148*38fd1498Szrj   {
149*38fd1498Szrj     int imm;
150*38fd1498Szrj     int imm32;
151*38fd1498Szrj     int imm64;
152*38fd1498Szrj   } imm_info;
153*38fd1498Szrj 
154*38fd1498Szrj static dispatch_windows *dispatch_window_list;
155*38fd1498Szrj static dispatch_windows *dispatch_window_list1;
156*38fd1498Szrj 
157*38fd1498Szrj /* Get dispatch group of insn.  */
158*38fd1498Szrj 
159*38fd1498Szrj static enum dispatch_group
get_mem_group(rtx_insn * insn)160*38fd1498Szrj get_mem_group (rtx_insn *insn)
161*38fd1498Szrj {
162*38fd1498Szrj   enum attr_memory memory;
163*38fd1498Szrj 
164*38fd1498Szrj   if (INSN_CODE (insn) < 0)
165*38fd1498Szrj     return disp_no_group;
166*38fd1498Szrj   memory = get_attr_memory (insn);
167*38fd1498Szrj   if (memory == MEMORY_STORE)
168*38fd1498Szrj     return disp_store;
169*38fd1498Szrj 
170*38fd1498Szrj   if (memory == MEMORY_LOAD)
171*38fd1498Szrj     return disp_load;
172*38fd1498Szrj 
173*38fd1498Szrj   if (memory == MEMORY_BOTH)
174*38fd1498Szrj     return disp_load_store;
175*38fd1498Szrj 
176*38fd1498Szrj   return disp_no_group;
177*38fd1498Szrj }
178*38fd1498Szrj 
179*38fd1498Szrj /* Return true if insn is a compare instruction.  */
180*38fd1498Szrj 
181*38fd1498Szrj static bool
is_cmp(rtx_insn * insn)182*38fd1498Szrj is_cmp (rtx_insn *insn)
183*38fd1498Szrj {
184*38fd1498Szrj   enum attr_type type;
185*38fd1498Szrj 
186*38fd1498Szrj   type = get_attr_type (insn);
187*38fd1498Szrj   return (type == TYPE_TEST
188*38fd1498Szrj 	  || type == TYPE_ICMP
189*38fd1498Szrj 	  || type == TYPE_FCMP
190*38fd1498Szrj 	  || GET_CODE (PATTERN (insn)) == COMPARE);
191*38fd1498Szrj }
192*38fd1498Szrj 
193*38fd1498Szrj /* Return true if a dispatch violation encountered.  */
194*38fd1498Szrj 
195*38fd1498Szrj static bool
dispatch_violation(void)196*38fd1498Szrj dispatch_violation (void)
197*38fd1498Szrj {
198*38fd1498Szrj   if (dispatch_window_list->next)
199*38fd1498Szrj     return dispatch_window_list->next->violation;
200*38fd1498Szrj   return dispatch_window_list->violation;
201*38fd1498Szrj }
202*38fd1498Szrj 
203*38fd1498Szrj /* Return true if insn is a branch instruction.  */
204*38fd1498Szrj 
205*38fd1498Szrj static bool
is_branch(rtx_insn * insn)206*38fd1498Szrj is_branch (rtx_insn *insn)
207*38fd1498Szrj {
208*38fd1498Szrj   return (CALL_P (insn) || JUMP_P (insn));
209*38fd1498Szrj }
210*38fd1498Szrj 
211*38fd1498Szrj /* Return true if insn is a prefetch instruction.  */
212*38fd1498Szrj 
213*38fd1498Szrj static bool
is_prefetch(rtx_insn * insn)214*38fd1498Szrj is_prefetch (rtx_insn *insn)
215*38fd1498Szrj {
216*38fd1498Szrj   return NONJUMP_INSN_P (insn) && GET_CODE (PATTERN (insn)) == PREFETCH;
217*38fd1498Szrj }
218*38fd1498Szrj 
219*38fd1498Szrj /* This function initializes a dispatch window and the list container holding a
220*38fd1498Szrj    pointer to the window.  */
221*38fd1498Szrj 
222*38fd1498Szrj static void
init_window(int window_num)223*38fd1498Szrj init_window (int window_num)
224*38fd1498Szrj {
225*38fd1498Szrj   int i;
226*38fd1498Szrj   dispatch_windows *new_list;
227*38fd1498Szrj 
228*38fd1498Szrj   if (window_num == 0)
229*38fd1498Szrj     new_list = dispatch_window_list;
230*38fd1498Szrj   else
231*38fd1498Szrj     new_list = dispatch_window_list1;
232*38fd1498Szrj 
233*38fd1498Szrj   new_list->num_insn = 0;
234*38fd1498Szrj   new_list->num_uops = 0;
235*38fd1498Szrj   new_list->window_size = 0;
236*38fd1498Szrj   new_list->next = NULL;
237*38fd1498Szrj   new_list->prev = NULL;
238*38fd1498Szrj   new_list->window_num = window_num;
239*38fd1498Szrj   new_list->num_imm = 0;
240*38fd1498Szrj   new_list->num_imm_32 = 0;
241*38fd1498Szrj   new_list->num_imm_64 = 0;
242*38fd1498Szrj   new_list->imm_size = 0;
243*38fd1498Szrj   new_list->num_loads = 0;
244*38fd1498Szrj   new_list->num_stores = 0;
245*38fd1498Szrj   new_list->violation = false;
246*38fd1498Szrj 
247*38fd1498Szrj   for (i = 0; i < MAX_INSN; i++)
248*38fd1498Szrj     {
249*38fd1498Szrj       new_list->window[i].insn = NULL;
250*38fd1498Szrj       new_list->window[i].group = disp_no_group;
251*38fd1498Szrj       new_list->window[i].path = no_path;
252*38fd1498Szrj       new_list->window[i].byte_len = 0;
253*38fd1498Szrj       new_list->window[i].imm_bytes = 0;
254*38fd1498Szrj     }
255*38fd1498Szrj   return;
256*38fd1498Szrj }
257*38fd1498Szrj 
258*38fd1498Szrj /* This function allocates and initializes a dispatch window and the
259*38fd1498Szrj    list container holding a pointer to the window.  */
260*38fd1498Szrj 
261*38fd1498Szrj static dispatch_windows *
allocate_window(void)262*38fd1498Szrj allocate_window (void)
263*38fd1498Szrj {
264*38fd1498Szrj   dispatch_windows *new_list = XNEW (struct dispatch_windows_s);
265*38fd1498Szrj   new_list->window = XNEWVEC (struct sched_insn_info_s, MAX_INSN + 1);
266*38fd1498Szrj 
267*38fd1498Szrj   return new_list;
268*38fd1498Szrj }
269*38fd1498Szrj 
270*38fd1498Szrj /* This routine initializes the dispatch scheduling information.  It
271*38fd1498Szrj    initiates building dispatch scheduler tables and constructs the
272*38fd1498Szrj    first dispatch window.  */
273*38fd1498Szrj 
274*38fd1498Szrj static void
init_dispatch_sched(void)275*38fd1498Szrj init_dispatch_sched (void)
276*38fd1498Szrj {
277*38fd1498Szrj   /* Allocate a dispatch list and a window.  */
278*38fd1498Szrj   dispatch_window_list = allocate_window ();
279*38fd1498Szrj   dispatch_window_list1 = allocate_window ();
280*38fd1498Szrj   init_window (0);
281*38fd1498Szrj   init_window (1);
282*38fd1498Szrj }
283*38fd1498Szrj 
284*38fd1498Szrj /* This function returns true if a branch is detected.  End of a basic block
285*38fd1498Szrj    does not have to be a branch, but here we assume only branches end a
286*38fd1498Szrj    window.  */
287*38fd1498Szrj 
288*38fd1498Szrj static bool
is_end_basic_block(enum dispatch_group group)289*38fd1498Szrj is_end_basic_block (enum dispatch_group group)
290*38fd1498Szrj {
291*38fd1498Szrj   return group == disp_branch;
292*38fd1498Szrj }
293*38fd1498Szrj 
294*38fd1498Szrj /* This function is called when the end of a window processing is reached.  */
295*38fd1498Szrj 
296*38fd1498Szrj static void
process_end_window(void)297*38fd1498Szrj process_end_window (void)
298*38fd1498Szrj {
299*38fd1498Szrj   gcc_assert (dispatch_window_list->num_insn <= MAX_INSN);
300*38fd1498Szrj   if (dispatch_window_list->next)
301*38fd1498Szrj     {
302*38fd1498Szrj       gcc_assert (dispatch_window_list1->num_insn <= MAX_INSN);
303*38fd1498Szrj       gcc_assert (dispatch_window_list->window_size
304*38fd1498Szrj 		  + dispatch_window_list1->window_size <= 48);
305*38fd1498Szrj       init_window (1);
306*38fd1498Szrj     }
307*38fd1498Szrj   init_window (0);
308*38fd1498Szrj }
309*38fd1498Szrj 
310*38fd1498Szrj /* Allocates a new dispatch window and adds it to WINDOW_LIST.
311*38fd1498Szrj    WINDOW_NUM is either 0 or 1.  A maximum of two windows are generated
312*38fd1498Szrj    for 48 bytes of instructions.  Note that these windows are not dispatch
313*38fd1498Szrj    windows that their sizes are DISPATCH_WINDOW_SIZE.  */
314*38fd1498Szrj 
315*38fd1498Szrj static dispatch_windows *
allocate_next_window(int window_num)316*38fd1498Szrj allocate_next_window (int window_num)
317*38fd1498Szrj {
318*38fd1498Szrj   if (window_num == 0)
319*38fd1498Szrj     {
320*38fd1498Szrj       if (dispatch_window_list->next)
321*38fd1498Szrj 	  init_window (1);
322*38fd1498Szrj       init_window (0);
323*38fd1498Szrj       return dispatch_window_list;
324*38fd1498Szrj     }
325*38fd1498Szrj 
326*38fd1498Szrj   dispatch_window_list->next = dispatch_window_list1;
327*38fd1498Szrj   dispatch_window_list1->prev = dispatch_window_list;
328*38fd1498Szrj 
329*38fd1498Szrj   return dispatch_window_list1;
330*38fd1498Szrj }
331*38fd1498Szrj 
332*38fd1498Szrj /* Compute number of immediate operands of an instruction.  */
333*38fd1498Szrj 
334*38fd1498Szrj static void
find_constant(rtx in_rtx,imm_info * imm_values)335*38fd1498Szrj find_constant (rtx in_rtx, imm_info *imm_values)
336*38fd1498Szrj {
337*38fd1498Szrj   if (INSN_P (in_rtx))
338*38fd1498Szrj     in_rtx = PATTERN (in_rtx);
339*38fd1498Szrj   subrtx_iterator::array_type array;
340*38fd1498Szrj   FOR_EACH_SUBRTX (iter, array, in_rtx, ALL)
341*38fd1498Szrj     if (const_rtx x = *iter)
342*38fd1498Szrj       switch (GET_CODE (x))
343*38fd1498Szrj 	{
344*38fd1498Szrj 	case CONST:
345*38fd1498Szrj 	case SYMBOL_REF:
346*38fd1498Szrj 	case CONST_INT:
347*38fd1498Szrj 	  (imm_values->imm)++;
348*38fd1498Szrj 	  if (x86_64_immediate_operand (CONST_CAST_RTX (x), SImode))
349*38fd1498Szrj 	    (imm_values->imm32)++;
350*38fd1498Szrj 	  else
351*38fd1498Szrj 	    (imm_values->imm64)++;
352*38fd1498Szrj 	  break;
353*38fd1498Szrj 
354*38fd1498Szrj 	case CONST_DOUBLE:
355*38fd1498Szrj 	case CONST_WIDE_INT:
356*38fd1498Szrj 	  (imm_values->imm)++;
357*38fd1498Szrj 	  (imm_values->imm64)++;
358*38fd1498Szrj 	  break;
359*38fd1498Szrj 
360*38fd1498Szrj 	case CODE_LABEL:
361*38fd1498Szrj 	  if (LABEL_KIND (x) == LABEL_NORMAL)
362*38fd1498Szrj 	    {
363*38fd1498Szrj 	      (imm_values->imm)++;
364*38fd1498Szrj 	      (imm_values->imm32)++;
365*38fd1498Szrj 	    }
366*38fd1498Szrj 	  break;
367*38fd1498Szrj 
368*38fd1498Szrj 	default:
369*38fd1498Szrj 	  break;
370*38fd1498Szrj 	}
371*38fd1498Szrj }
372*38fd1498Szrj 
373*38fd1498Szrj /* Return total size of immediate operands of an instruction along with number
374*38fd1498Szrj    of corresponding immediate-operands.  It initializes its parameters to zero
375*38fd1498Szrj    befor calling FIND_CONSTANT.
376*38fd1498Szrj    INSN is the input instruction.  IMM is the total of immediates.
377*38fd1498Szrj    IMM32 is the number of 32 bit immediates.  IMM64 is the number of 64
378*38fd1498Szrj    bit immediates.  */
379*38fd1498Szrj 
380*38fd1498Szrj static int
get_num_immediates(rtx_insn * insn,int * imm,int * imm32,int * imm64)381*38fd1498Szrj get_num_immediates (rtx_insn *insn, int *imm, int *imm32, int *imm64)
382*38fd1498Szrj {
383*38fd1498Szrj   imm_info imm_values = {0, 0, 0};
384*38fd1498Szrj 
385*38fd1498Szrj   find_constant (insn, &imm_values);
386*38fd1498Szrj   *imm = imm_values.imm;
387*38fd1498Szrj   *imm32 = imm_values.imm32;
388*38fd1498Szrj   *imm64 = imm_values.imm64;
389*38fd1498Szrj   return imm_values.imm32 * 4 + imm_values.imm64 * 8;
390*38fd1498Szrj }
391*38fd1498Szrj 
392*38fd1498Szrj /* This function indicates if an operand of an instruction is an
393*38fd1498Szrj    immediate.  */
394*38fd1498Szrj 
395*38fd1498Szrj static bool
has_immediate(rtx_insn * insn)396*38fd1498Szrj has_immediate (rtx_insn *insn)
397*38fd1498Szrj {
398*38fd1498Szrj   int num_imm_operand;
399*38fd1498Szrj   int num_imm32_operand;
400*38fd1498Szrj   int num_imm64_operand;
401*38fd1498Szrj 
402*38fd1498Szrj   if (insn)
403*38fd1498Szrj     return get_num_immediates (insn, &num_imm_operand, &num_imm32_operand,
404*38fd1498Szrj 			       &num_imm64_operand);
405*38fd1498Szrj   return false;
406*38fd1498Szrj }
407*38fd1498Szrj 
408*38fd1498Szrj /* Return single or double path for instructions.  */
409*38fd1498Szrj 
410*38fd1498Szrj static enum insn_path
get_insn_path(rtx_insn * insn)411*38fd1498Szrj get_insn_path (rtx_insn *insn)
412*38fd1498Szrj {
413*38fd1498Szrj   enum attr_amdfam10_decode path = get_attr_amdfam10_decode (insn);
414*38fd1498Szrj 
415*38fd1498Szrj   if ((int)path == 0)
416*38fd1498Szrj     return path_single;
417*38fd1498Szrj 
418*38fd1498Szrj   if ((int)path == 1)
419*38fd1498Szrj     return path_double;
420*38fd1498Szrj 
421*38fd1498Szrj   return path_multi;
422*38fd1498Szrj }
423*38fd1498Szrj 
424*38fd1498Szrj /* Return insn dispatch group.  */
425*38fd1498Szrj 
426*38fd1498Szrj static enum dispatch_group
get_insn_group(rtx_insn * insn)427*38fd1498Szrj get_insn_group (rtx_insn *insn)
428*38fd1498Szrj {
429*38fd1498Szrj   enum dispatch_group group = get_mem_group (insn);
430*38fd1498Szrj   if (group)
431*38fd1498Szrj     return group;
432*38fd1498Szrj 
433*38fd1498Szrj   if (is_branch (insn))
434*38fd1498Szrj     return disp_branch;
435*38fd1498Szrj 
436*38fd1498Szrj   if (is_cmp (insn))
437*38fd1498Szrj     return disp_cmp;
438*38fd1498Szrj 
439*38fd1498Szrj   if (has_immediate (insn))
440*38fd1498Szrj     return disp_imm;
441*38fd1498Szrj 
442*38fd1498Szrj   if (is_prefetch (insn))
443*38fd1498Szrj     return disp_prefetch;
444*38fd1498Szrj 
445*38fd1498Szrj   return disp_no_group;
446*38fd1498Szrj }
447*38fd1498Szrj 
448*38fd1498Szrj /* Count number of GROUP restricted instructions in a dispatch
449*38fd1498Szrj    window WINDOW_LIST.  */
450*38fd1498Szrj 
451*38fd1498Szrj static int
count_num_restricted(rtx_insn * insn,dispatch_windows * window_list)452*38fd1498Szrj count_num_restricted (rtx_insn *insn, dispatch_windows *window_list)
453*38fd1498Szrj {
454*38fd1498Szrj   enum dispatch_group group = get_insn_group (insn);
455*38fd1498Szrj   int imm_size;
456*38fd1498Szrj   int num_imm_operand;
457*38fd1498Szrj   int num_imm32_operand;
458*38fd1498Szrj   int num_imm64_operand;
459*38fd1498Szrj 
460*38fd1498Szrj   if (group == disp_no_group)
461*38fd1498Szrj     return 0;
462*38fd1498Szrj 
463*38fd1498Szrj   if (group == disp_imm)
464*38fd1498Szrj     {
465*38fd1498Szrj       imm_size = get_num_immediates (insn, &num_imm_operand, &num_imm32_operand,
466*38fd1498Szrj 			      &num_imm64_operand);
467*38fd1498Szrj       if (window_list->imm_size + imm_size > MAX_IMM_SIZE
468*38fd1498Szrj 	  || num_imm_operand + window_list->num_imm > MAX_IMM
469*38fd1498Szrj 	  || (num_imm32_operand > 0
470*38fd1498Szrj 	      && (window_list->num_imm_32 + num_imm32_operand > MAX_IMM_32
471*38fd1498Szrj 		  || window_list->num_imm_64 * 2 + num_imm32_operand > MAX_IMM_32))
472*38fd1498Szrj 	  || (num_imm64_operand > 0
473*38fd1498Szrj 	      && (window_list->num_imm_64 + num_imm64_operand > MAX_IMM_64
474*38fd1498Szrj 		  || window_list->num_imm_32 + num_imm64_operand * 2 > MAX_IMM_32))
475*38fd1498Szrj 	  || (window_list->imm_size + imm_size == MAX_IMM_SIZE
476*38fd1498Szrj 	      && num_imm64_operand > 0
477*38fd1498Szrj 	      && ((window_list->num_imm_64 > 0
478*38fd1498Szrj 		   && window_list->num_insn >= 2)
479*38fd1498Szrj 		  || window_list->num_insn >= 3)))
480*38fd1498Szrj 	return BIG;
481*38fd1498Szrj 
482*38fd1498Szrj       return 1;
483*38fd1498Szrj     }
484*38fd1498Szrj 
485*38fd1498Szrj   if ((group == disp_load_store
486*38fd1498Szrj        && (window_list->num_loads >= MAX_LOAD
487*38fd1498Szrj 	   || window_list->num_stores >= MAX_STORE))
488*38fd1498Szrj       || ((group == disp_load
489*38fd1498Szrj 	   || group == disp_prefetch)
490*38fd1498Szrj 	  && window_list->num_loads >= MAX_LOAD)
491*38fd1498Szrj       || (group == disp_store
492*38fd1498Szrj 	  && window_list->num_stores >= MAX_STORE))
493*38fd1498Szrj     return BIG;
494*38fd1498Szrj 
495*38fd1498Szrj   return 1;
496*38fd1498Szrj }
497*38fd1498Szrj 
498*38fd1498Szrj /* This function returns true if insn satisfies dispatch rules on the
499*38fd1498Szrj    last window scheduled.  */
500*38fd1498Szrj 
501*38fd1498Szrj static bool
fits_dispatch_window(rtx_insn * insn)502*38fd1498Szrj fits_dispatch_window (rtx_insn *insn)
503*38fd1498Szrj {
504*38fd1498Szrj   dispatch_windows *window_list = dispatch_window_list;
505*38fd1498Szrj   dispatch_windows *window_list_next = dispatch_window_list->next;
506*38fd1498Szrj   unsigned int num_restrict;
507*38fd1498Szrj   enum dispatch_group group = get_insn_group (insn);
508*38fd1498Szrj   enum insn_path path = get_insn_path (insn);
509*38fd1498Szrj   int sum;
510*38fd1498Szrj 
511*38fd1498Szrj   /* Make disp_cmp and disp_jcc get scheduled at the latest.  These
512*38fd1498Szrj      instructions should be given the lowest priority in the
513*38fd1498Szrj      scheduling process in Haifa scheduler to make sure they will be
514*38fd1498Szrj      scheduled in the same dispatch window as the reference to them.  */
515*38fd1498Szrj   if (group == disp_jcc || group == disp_cmp)
516*38fd1498Szrj     return false;
517*38fd1498Szrj 
518*38fd1498Szrj   /* Check nonrestricted.  */
519*38fd1498Szrj   if (group == disp_no_group || group == disp_branch)
520*38fd1498Szrj     return true;
521*38fd1498Szrj 
522*38fd1498Szrj   /* Get last dispatch window.  */
523*38fd1498Szrj   if (window_list_next)
524*38fd1498Szrj     window_list = window_list_next;
525*38fd1498Szrj 
526*38fd1498Szrj   if (window_list->window_num == 1)
527*38fd1498Szrj     {
528*38fd1498Szrj       sum = window_list->prev->window_size + window_list->window_size;
529*38fd1498Szrj 
530*38fd1498Szrj       if (sum == 32
531*38fd1498Szrj 	  || (ix86_min_insn_size (insn) + sum) >= 48)
532*38fd1498Szrj 	/* Window 1 is full.  Go for next window.  */
533*38fd1498Szrj 	return true;
534*38fd1498Szrj     }
535*38fd1498Szrj 
536*38fd1498Szrj   num_restrict = count_num_restricted (insn, window_list);
537*38fd1498Szrj 
538*38fd1498Szrj   if (num_restrict > num_allowable_groups[group])
539*38fd1498Szrj     return false;
540*38fd1498Szrj 
541*38fd1498Szrj   /* See if it fits in the first window.  */
542*38fd1498Szrj   if (window_list->window_num == 0)
543*38fd1498Szrj     {
544*38fd1498Szrj       /* The first widow should have only single and double path
545*38fd1498Szrj 	 uops.  */
546*38fd1498Szrj       if (path == path_double
547*38fd1498Szrj 	  && (window_list->num_uops + 2) > MAX_INSN)
548*38fd1498Szrj 	return false;
549*38fd1498Szrj       else if (path != path_single)
550*38fd1498Szrj         return false;
551*38fd1498Szrj     }
552*38fd1498Szrj   return true;
553*38fd1498Szrj }
554*38fd1498Szrj 
555*38fd1498Szrj /* Add an instruction INSN with NUM_UOPS micro-operations to the
556*38fd1498Szrj    dispatch window WINDOW_LIST.  */
557*38fd1498Szrj 
558*38fd1498Szrj static void
add_insn_window(rtx_insn * insn,dispatch_windows * window_list,int num_uops)559*38fd1498Szrj add_insn_window (rtx_insn *insn, dispatch_windows *window_list, int num_uops)
560*38fd1498Szrj {
561*38fd1498Szrj   int byte_len = ix86_min_insn_size (insn);
562*38fd1498Szrj   int num_insn = window_list->num_insn;
563*38fd1498Szrj   int imm_size;
564*38fd1498Szrj   sched_insn_info *window = window_list->window;
565*38fd1498Szrj   enum dispatch_group group = get_insn_group (insn);
566*38fd1498Szrj   enum insn_path path = get_insn_path (insn);
567*38fd1498Szrj   int num_imm_operand;
568*38fd1498Szrj   int num_imm32_operand;
569*38fd1498Szrj   int num_imm64_operand;
570*38fd1498Szrj 
571*38fd1498Szrj   if (!window_list->violation && group != disp_cmp
572*38fd1498Szrj       && !fits_dispatch_window (insn))
573*38fd1498Szrj     window_list->violation = true;
574*38fd1498Szrj 
575*38fd1498Szrj   imm_size = get_num_immediates (insn, &num_imm_operand, &num_imm32_operand,
576*38fd1498Szrj 				 &num_imm64_operand);
577*38fd1498Szrj 
578*38fd1498Szrj   /* Initialize window with new instruction.  */
579*38fd1498Szrj   window[num_insn].insn = insn;
580*38fd1498Szrj   window[num_insn].byte_len = byte_len;
581*38fd1498Szrj   window[num_insn].group = group;
582*38fd1498Szrj   window[num_insn].path = path;
583*38fd1498Szrj   window[num_insn].imm_bytes = imm_size;
584*38fd1498Szrj 
585*38fd1498Szrj   window_list->window_size += byte_len;
586*38fd1498Szrj   window_list->num_insn = num_insn + 1;
587*38fd1498Szrj   window_list->num_uops = window_list->num_uops + num_uops;
588*38fd1498Szrj   window_list->imm_size += imm_size;
589*38fd1498Szrj   window_list->num_imm += num_imm_operand;
590*38fd1498Szrj   window_list->num_imm_32 += num_imm32_operand;
591*38fd1498Szrj   window_list->num_imm_64 += num_imm64_operand;
592*38fd1498Szrj 
593*38fd1498Szrj   if (group == disp_store)
594*38fd1498Szrj     window_list->num_stores += 1;
595*38fd1498Szrj   else if (group == disp_load
596*38fd1498Szrj 	   || group == disp_prefetch)
597*38fd1498Szrj     window_list->num_loads += 1;
598*38fd1498Szrj   else if (group == disp_load_store)
599*38fd1498Szrj     {
600*38fd1498Szrj       window_list->num_stores += 1;
601*38fd1498Szrj       window_list->num_loads += 1;
602*38fd1498Szrj     }
603*38fd1498Szrj }
604*38fd1498Szrj 
605*38fd1498Szrj /* Adds a scheduled instruction, INSN, to the current dispatch window.
606*38fd1498Szrj    If the total bytes of instructions or the number of instructions in
607*38fd1498Szrj    the window exceed allowable, it allocates a new window.  */
608*38fd1498Szrj 
609*38fd1498Szrj static void
add_to_dispatch_window(rtx_insn * insn)610*38fd1498Szrj add_to_dispatch_window (rtx_insn *insn)
611*38fd1498Szrj {
612*38fd1498Szrj   int byte_len;
613*38fd1498Szrj   dispatch_windows *window_list;
614*38fd1498Szrj   dispatch_windows *next_list;
615*38fd1498Szrj   dispatch_windows *window0_list;
616*38fd1498Szrj   enum insn_path path;
617*38fd1498Szrj   enum dispatch_group insn_group;
618*38fd1498Szrj   bool insn_fits;
619*38fd1498Szrj   int num_insn;
620*38fd1498Szrj   int num_uops;
621*38fd1498Szrj   int window_num;
622*38fd1498Szrj   int insn_num_uops;
623*38fd1498Szrj   int sum;
624*38fd1498Szrj 
625*38fd1498Szrj   if (INSN_CODE (insn) < 0)
626*38fd1498Szrj     return;
627*38fd1498Szrj 
628*38fd1498Szrj   byte_len = ix86_min_insn_size (insn);
629*38fd1498Szrj   window_list = dispatch_window_list;
630*38fd1498Szrj   next_list = window_list->next;
631*38fd1498Szrj   path = get_insn_path (insn);
632*38fd1498Szrj   insn_group = get_insn_group (insn);
633*38fd1498Szrj 
634*38fd1498Szrj   /* Get the last dispatch window.  */
635*38fd1498Szrj   if (next_list)
636*38fd1498Szrj       window_list = dispatch_window_list->next;
637*38fd1498Szrj 
638*38fd1498Szrj   if (path == path_single)
639*38fd1498Szrj     insn_num_uops = 1;
640*38fd1498Szrj   else if (path == path_double)
641*38fd1498Szrj     insn_num_uops = 2;
642*38fd1498Szrj   else
643*38fd1498Szrj     insn_num_uops = (int) path;
644*38fd1498Szrj 
645*38fd1498Szrj   /* If current window is full, get a new window.
646*38fd1498Szrj      Window number zero is full, if MAX_INSN uops are scheduled in it.
647*38fd1498Szrj      Window number one is full, if window zero's bytes plus window
648*38fd1498Szrj      one's bytes is 32, or if the bytes of the new instruction added
649*38fd1498Szrj      to the total makes it greater than 48, or it has already MAX_INSN
650*38fd1498Szrj      instructions in it.  */
651*38fd1498Szrj   num_insn = window_list->num_insn;
652*38fd1498Szrj   num_uops = window_list->num_uops;
653*38fd1498Szrj   window_num = window_list->window_num;
654*38fd1498Szrj   insn_fits = fits_dispatch_window (insn);
655*38fd1498Szrj 
656*38fd1498Szrj   if (num_insn >= MAX_INSN
657*38fd1498Szrj       || num_uops + insn_num_uops > MAX_INSN
658*38fd1498Szrj       || !(insn_fits))
659*38fd1498Szrj     {
660*38fd1498Szrj       window_num = ~window_num & 1;
661*38fd1498Szrj       window_list = allocate_next_window (window_num);
662*38fd1498Szrj     }
663*38fd1498Szrj 
664*38fd1498Szrj   if (window_num == 0)
665*38fd1498Szrj     {
666*38fd1498Szrj       add_insn_window (insn, window_list, insn_num_uops);
667*38fd1498Szrj       if (window_list->num_insn >= MAX_INSN
668*38fd1498Szrj 	  && insn_group == disp_branch)
669*38fd1498Szrj 	{
670*38fd1498Szrj 	  process_end_window ();
671*38fd1498Szrj 	  return;
672*38fd1498Szrj 	}
673*38fd1498Szrj     }
674*38fd1498Szrj   else if (window_num == 1)
675*38fd1498Szrj     {
676*38fd1498Szrj       window0_list = window_list->prev;
677*38fd1498Szrj       sum = window0_list->window_size + window_list->window_size;
678*38fd1498Szrj       if (sum == 32
679*38fd1498Szrj 	  || (byte_len + sum) >= 48)
680*38fd1498Szrj 	{
681*38fd1498Szrj 	  process_end_window ();
682*38fd1498Szrj 	  window_list = dispatch_window_list;
683*38fd1498Szrj 	}
684*38fd1498Szrj 
685*38fd1498Szrj       add_insn_window (insn, window_list, insn_num_uops);
686*38fd1498Szrj     }
687*38fd1498Szrj   else
688*38fd1498Szrj     gcc_unreachable ();
689*38fd1498Szrj 
690*38fd1498Szrj   if (is_end_basic_block (insn_group))
691*38fd1498Szrj     {
692*38fd1498Szrj       /* End of basic block is reached do end-basic-block process.  */
693*38fd1498Szrj       process_end_window ();
694*38fd1498Szrj       return;
695*38fd1498Szrj     }
696*38fd1498Szrj }
697*38fd1498Szrj 
698*38fd1498Szrj /* Print the dispatch window, WINDOW_NUM, to FILE.  */
699*38fd1498Szrj 
700*38fd1498Szrj DEBUG_FUNCTION static void
debug_dispatch_window_file(FILE * file,int window_num)701*38fd1498Szrj debug_dispatch_window_file (FILE *file, int window_num)
702*38fd1498Szrj {
703*38fd1498Szrj   dispatch_windows *list;
704*38fd1498Szrj   int i;
705*38fd1498Szrj 
706*38fd1498Szrj   if (window_num == 0)
707*38fd1498Szrj     list = dispatch_window_list;
708*38fd1498Szrj   else
709*38fd1498Szrj     list = dispatch_window_list1;
710*38fd1498Szrj 
711*38fd1498Szrj   fprintf (file, "Window #%d:\n", list->window_num);
712*38fd1498Szrj   fprintf (file, "  num_insn = %d, num_uops = %d, window_size = %d\n",
713*38fd1498Szrj 	  list->num_insn, list->num_uops, list->window_size);
714*38fd1498Szrj   fprintf (file, "  num_imm = %d, num_imm_32 = %d, num_imm_64 = %d, imm_size = %d\n",
715*38fd1498Szrj 	   list->num_imm, list->num_imm_32, list->num_imm_64, list->imm_size);
716*38fd1498Szrj 
717*38fd1498Szrj   fprintf (file, "  num_loads = %d, num_stores = %d\n", list->num_loads,
718*38fd1498Szrj 	  list->num_stores);
719*38fd1498Szrj   fprintf (file, " insn info:\n");
720*38fd1498Szrj 
721*38fd1498Szrj   for (i = 0; i < MAX_INSN; i++)
722*38fd1498Szrj     {
723*38fd1498Szrj       if (!list->window[i].insn)
724*38fd1498Szrj 	break;
725*38fd1498Szrj       fprintf (file, "    group[%d] = %s, insn[%d] = %p, path[%d] = %d byte_len[%d] = %d, imm_bytes[%d] = %d\n",
726*38fd1498Szrj 	      i, group_name[list->window[i].group],
727*38fd1498Szrj 	      i, (void *)list->window[i].insn,
728*38fd1498Szrj 	      i, list->window[i].path,
729*38fd1498Szrj 	      i, list->window[i].byte_len,
730*38fd1498Szrj 	      i, list->window[i].imm_bytes);
731*38fd1498Szrj     }
732*38fd1498Szrj }
733*38fd1498Szrj 
734*38fd1498Szrj /* Print to stdout a dispatch window.  */
735*38fd1498Szrj 
736*38fd1498Szrj DEBUG_FUNCTION void
debug_dispatch_window(int window_num)737*38fd1498Szrj debug_dispatch_window (int window_num)
738*38fd1498Szrj {
739*38fd1498Szrj   debug_dispatch_window_file (stdout, window_num);
740*38fd1498Szrj }
741*38fd1498Szrj 
742*38fd1498Szrj /* Print INSN dispatch information to FILE.  */
743*38fd1498Szrj 
744*38fd1498Szrj DEBUG_FUNCTION static void
debug_insn_dispatch_info_file(FILE * file,rtx_insn * insn)745*38fd1498Szrj debug_insn_dispatch_info_file (FILE *file, rtx_insn *insn)
746*38fd1498Szrj {
747*38fd1498Szrj   int byte_len;
748*38fd1498Szrj   enum insn_path path;
749*38fd1498Szrj   enum dispatch_group group;
750*38fd1498Szrj   int imm_size;
751*38fd1498Szrj   int num_imm_operand;
752*38fd1498Szrj   int num_imm32_operand;
753*38fd1498Szrj   int num_imm64_operand;
754*38fd1498Szrj 
755*38fd1498Szrj   if (INSN_CODE (insn) < 0)
756*38fd1498Szrj     return;
757*38fd1498Szrj 
758*38fd1498Szrj   byte_len = ix86_min_insn_size (insn);
759*38fd1498Szrj   path = get_insn_path (insn);
760*38fd1498Szrj   group = get_insn_group (insn);
761*38fd1498Szrj   imm_size = get_num_immediates (insn, &num_imm_operand, &num_imm32_operand,
762*38fd1498Szrj 				 &num_imm64_operand);
763*38fd1498Szrj 
764*38fd1498Szrj   fprintf (file, " insn info:\n");
765*38fd1498Szrj   fprintf (file, "  group = %s, path = %d, byte_len = %d\n",
766*38fd1498Szrj 	   group_name[group], path, byte_len);
767*38fd1498Szrj   fprintf (file, "  num_imm = %d, num_imm_32 = %d, num_imm_64 = %d, imm_size = %d\n",
768*38fd1498Szrj 	   num_imm_operand, num_imm32_operand, num_imm64_operand, imm_size);
769*38fd1498Szrj }
770*38fd1498Szrj 
771*38fd1498Szrj /* Print to STDERR the status of the ready list with respect to
772*38fd1498Szrj    dispatch windows.  */
773*38fd1498Szrj 
774*38fd1498Szrj DEBUG_FUNCTION void
debug_ready_dispatch(void)775*38fd1498Szrj debug_ready_dispatch (void)
776*38fd1498Szrj {
777*38fd1498Szrj   int i;
778*38fd1498Szrj   int no_ready = number_in_ready ();
779*38fd1498Szrj 
780*38fd1498Szrj   fprintf (stdout, "Number of ready: %d\n", no_ready);
781*38fd1498Szrj 
782*38fd1498Szrj   for (i = 0; i < no_ready; i++)
783*38fd1498Szrj     debug_insn_dispatch_info_file (stdout, get_ready_element (i));
784*38fd1498Szrj }
785*38fd1498Szrj 
786*38fd1498Szrj /* This routine is the driver of the dispatch scheduler.  */
787*38fd1498Szrj 
788*38fd1498Szrj void
ix86_bd_do_dispatch(rtx_insn * insn,int mode)789*38fd1498Szrj ix86_bd_do_dispatch (rtx_insn *insn, int mode)
790*38fd1498Szrj {
791*38fd1498Szrj   if (mode == DISPATCH_INIT)
792*38fd1498Szrj     init_dispatch_sched ();
793*38fd1498Szrj   else if (mode == ADD_TO_DISPATCH_WINDOW)
794*38fd1498Szrj     add_to_dispatch_window (insn);
795*38fd1498Szrj }
796*38fd1498Szrj 
797*38fd1498Szrj /* Return TRUE if Dispatch Scheduling is supported.  */
798*38fd1498Szrj 
799*38fd1498Szrj bool
ix86_bd_has_dispatch(rtx_insn * insn,int action)800*38fd1498Szrj ix86_bd_has_dispatch (rtx_insn *insn, int action)
801*38fd1498Szrj {
802*38fd1498Szrj   /* Current implementation of dispatch scheduler models buldozer only.  */
803*38fd1498Szrj   if ((TARGET_BDVER1 || TARGET_BDVER2 || TARGET_BDVER3
804*38fd1498Szrj       || TARGET_BDVER4) && flag_dispatch_scheduler)
805*38fd1498Szrj     switch (action)
806*38fd1498Szrj       {
807*38fd1498Szrj       default:
808*38fd1498Szrj 	return false;
809*38fd1498Szrj 
810*38fd1498Szrj       case IS_DISPATCH_ON:
811*38fd1498Szrj 	return true;
812*38fd1498Szrj 
813*38fd1498Szrj       case IS_CMP:
814*38fd1498Szrj 	return is_cmp (insn);
815*38fd1498Szrj 
816*38fd1498Szrj       case DISPATCH_VIOLATION:
817*38fd1498Szrj 	return dispatch_violation ();
818*38fd1498Szrj 
819*38fd1498Szrj       case FITS_DISPATCH_WINDOW:
820*38fd1498Szrj 	return fits_dispatch_window (insn);
821*38fd1498Szrj       }
822*38fd1498Szrj 
823*38fd1498Szrj   return false;
824*38fd1498Szrj }
825