1 /* Scheduler hooks for IA-32 which implement bdver1-4 specific logic.
2    Copyright (C) 1988-2018 Free Software Foundation, Inc.
3 
4 This file is part of GCC.
5 
6 GCC is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 3, or (at your option)
9 any later version.
10 
11 GCC is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 GNU General Public License for more details.
15 
16 You should have received a copy of the GNU General Public License
17 along with GCC; see the file COPYING3.  If not see
18 <http://www.gnu.org/licenses/>.  */
19 
20 #define IN_TARGET_CODE 1
21 
22 #include "config.h"
23 #include "system.h"
24 #include "coretypes.h"
25 #include "backend.h"
26 #include "rtl.h"
27 #include "tree.h"
28 #include "cfghooks.h"
29 #include "tm_p.h"
30 #include "insn-config.h"
31 #include "insn-attr.h"
32 #include "recog.h"
33 #include "target.h"
34 #include "rtl-iter.h"
35 #include "regset.h"
36 #include "sched-int.h"
37 
38 
39 /* Model decoder of Core 2/i7.
40    Below hooks for multipass scheduling (see haifa-sched.c:max_issue)
41    track the instruction fetch block boundaries and make sure that long
42    (9+ bytes) instructions are assigned to D0.  */
43 
44 /* Maximum length of an insn that can be handled by
45    a secondary decoder unit.  '8' for Core 2/i7.  */
46 static int core2i7_secondary_decoder_max_insn_size;
47 
48 /* Ifetch block size, i.e., number of bytes decoder reads per cycle.
49    '16' for Core 2/i7.  */
50 static int core2i7_ifetch_block_size;
51 
52 /* Maximum number of instructions decoder can handle per cycle.
53    '6' for Core 2/i7.  */
54 static int core2i7_ifetch_block_max_insns;
55 
56 typedef struct ix86_first_cycle_multipass_data_ *
57   ix86_first_cycle_multipass_data_t;
58 typedef const struct ix86_first_cycle_multipass_data_ *
59   const_ix86_first_cycle_multipass_data_t;
60 
61 /* A variable to store target state across calls to max_issue within
62    one cycle.  */
63 static struct ix86_first_cycle_multipass_data_ _ix86_first_cycle_multipass_data,
64   *ix86_first_cycle_multipass_data = &_ix86_first_cycle_multipass_data;
65 
66 /* Initialize DATA.  */
67 static void
68 core2i7_first_cycle_multipass_init (void *_data)
69 {
70   ix86_first_cycle_multipass_data_t data
71     = (ix86_first_cycle_multipass_data_t) _data;
72 
73   data->ifetch_block_len = 0;
74   data->ifetch_block_n_insns = 0;
75   data->ready_try_change = NULL;
76   data->ready_try_change_size = 0;
77 }
78 
79 /* Advancing the cycle; reset ifetch block counts.  */
80 static void
81 core2i7_dfa_post_advance_cycle (void)
82 {
83   ix86_first_cycle_multipass_data_t data = ix86_first_cycle_multipass_data;
84 
85   gcc_assert (data->ifetch_block_n_insns <= core2i7_ifetch_block_max_insns);
86 
87   data->ifetch_block_len = 0;
88   data->ifetch_block_n_insns = 0;
89 }
90 
91 /* Filter out insns from ready_try that the core will not be able to issue
92    on current cycle due to decoder.  */
93 static void
94 core2i7_first_cycle_multipass_filter_ready_try
95 (const_ix86_first_cycle_multipass_data_t data,
96  signed char *ready_try, int n_ready, bool first_cycle_insn_p)
97 {
98   while (n_ready--)
99     {
100       rtx_insn *insn;
101       int insn_size;
102 
103       if (ready_try[n_ready])
104 	continue;
105 
106       insn = get_ready_element (n_ready);
107       insn_size = ix86_min_insn_size (insn);
108 
109       if (/* If this is a too long an insn for a secondary decoder ...  */
110 	  (!first_cycle_insn_p
111 	   && insn_size > core2i7_secondary_decoder_max_insn_size)
112 	  /* ... or it would not fit into the ifetch block ...  */
113 	  || data->ifetch_block_len + insn_size > core2i7_ifetch_block_size
114 	  /* ... or the decoder is full already ...  */
115 	  || data->ifetch_block_n_insns + 1 > core2i7_ifetch_block_max_insns)
116 	/* ... mask the insn out.  */
117 	{
118 	  ready_try[n_ready] = 1;
119 
120 	  if (data->ready_try_change)
121 	    bitmap_set_bit (data->ready_try_change, n_ready);
122 	}
123     }
124 }
125 
126 /* Prepare for a new round of multipass lookahead scheduling.  */
127 static void
128 core2i7_first_cycle_multipass_begin (void *_data,
129 				     signed char *ready_try, int n_ready,
130 				     bool first_cycle_insn_p)
131 {
132   ix86_first_cycle_multipass_data_t data
133     = (ix86_first_cycle_multipass_data_t) _data;
134   const_ix86_first_cycle_multipass_data_t prev_data
135     = ix86_first_cycle_multipass_data;
136 
137   /* Restore the state from the end of the previous round.  */
138   data->ifetch_block_len = prev_data->ifetch_block_len;
139   data->ifetch_block_n_insns = prev_data->ifetch_block_n_insns;
140 
141   /* Filter instructions that cannot be issued on current cycle due to
142      decoder restrictions.  */
143   core2i7_first_cycle_multipass_filter_ready_try (data, ready_try, n_ready,
144 						  first_cycle_insn_p);
145 }
146 
147 /* INSN is being issued in current solution.  Account for its impact on
148    the decoder model.  */
149 static void
150 core2i7_first_cycle_multipass_issue (void *_data,
151 				     signed char *ready_try, int n_ready,
152 				     rtx_insn *insn, const void *_prev_data)
153 {
154   ix86_first_cycle_multipass_data_t data
155     = (ix86_first_cycle_multipass_data_t) _data;
156   const_ix86_first_cycle_multipass_data_t prev_data
157     = (const_ix86_first_cycle_multipass_data_t) _prev_data;
158 
159   int insn_size = ix86_min_insn_size (insn);
160 
161   data->ifetch_block_len = prev_data->ifetch_block_len + insn_size;
162   data->ifetch_block_n_insns = prev_data->ifetch_block_n_insns + 1;
163   gcc_assert (data->ifetch_block_len <= core2i7_ifetch_block_size
164 	      && data->ifetch_block_n_insns <= core2i7_ifetch_block_max_insns);
165 
166   /* Allocate or resize the bitmap for storing INSN's effect on ready_try.  */
167   if (!data->ready_try_change)
168     {
169       data->ready_try_change = sbitmap_alloc (n_ready);
170       data->ready_try_change_size = n_ready;
171     }
172   else if (data->ready_try_change_size < n_ready)
173     {
174       data->ready_try_change = sbitmap_resize (data->ready_try_change,
175 					       n_ready, 0);
176       data->ready_try_change_size = n_ready;
177     }
178   bitmap_clear (data->ready_try_change);
179 
180   /* Filter out insns from ready_try that the core will not be able to issue
181      on current cycle due to decoder.  */
182   core2i7_first_cycle_multipass_filter_ready_try (data, ready_try, n_ready,
183 						  false);
184 }
185 
186 /* Revert the effect on ready_try.  */
187 static void
188 core2i7_first_cycle_multipass_backtrack (const void *_data,
189 					 signed char *ready_try,
190 					 int n_ready ATTRIBUTE_UNUSED)
191 {
192   const_ix86_first_cycle_multipass_data_t data
193     = (const_ix86_first_cycle_multipass_data_t) _data;
194   unsigned int i = 0;
195   sbitmap_iterator sbi;
196 
197   gcc_assert (bitmap_last_set_bit (data->ready_try_change) < n_ready);
198   EXECUTE_IF_SET_IN_BITMAP (data->ready_try_change, 0, i, sbi)
199     {
200       ready_try[i] = 0;
201     }
202 }
203 
204 /* Save the result of multipass lookahead scheduling for the next round.  */
205 static void
206 core2i7_first_cycle_multipass_end (const void *_data)
207 {
208   const_ix86_first_cycle_multipass_data_t data
209     = (const_ix86_first_cycle_multipass_data_t) _data;
210   ix86_first_cycle_multipass_data_t next_data
211     = ix86_first_cycle_multipass_data;
212 
213   if (data != NULL)
214     {
215       next_data->ifetch_block_len = data->ifetch_block_len;
216       next_data->ifetch_block_n_insns = data->ifetch_block_n_insns;
217     }
218 }
219 
220 /* Deallocate target data.  */
221 static void
222 core2i7_first_cycle_multipass_fini (void *_data)
223 {
224   ix86_first_cycle_multipass_data_t data
225     = (ix86_first_cycle_multipass_data_t) _data;
226 
227   if (data->ready_try_change)
228     {
229       sbitmap_free (data->ready_try_change);
230       data->ready_try_change = NULL;
231       data->ready_try_change_size = 0;
232     }
233 }
234 
235 void
236 ix86_core2i7_init_hooks (void)
237 {
238   targetm.sched.dfa_post_advance_cycle
239     = core2i7_dfa_post_advance_cycle;
240   targetm.sched.first_cycle_multipass_init
241     = core2i7_first_cycle_multipass_init;
242   targetm.sched.first_cycle_multipass_begin
243     = core2i7_first_cycle_multipass_begin;
244   targetm.sched.first_cycle_multipass_issue
245     = core2i7_first_cycle_multipass_issue;
246   targetm.sched.first_cycle_multipass_backtrack
247     = core2i7_first_cycle_multipass_backtrack;
248   targetm.sched.first_cycle_multipass_end
249     = core2i7_first_cycle_multipass_end;
250   targetm.sched.first_cycle_multipass_fini
251     = core2i7_first_cycle_multipass_fini;
252 
253   /* Set decoder parameters.  */
254   core2i7_secondary_decoder_max_insn_size = 8;
255   core2i7_ifetch_block_size = 16;
256   core2i7_ifetch_block_max_insns = 6;
257 }
258