1 | /* Scheduler hooks for IA-32 which implement atom+ specific logic. |
2 | Copyright (C) 1988-2023 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 | /* Try to reorder ready list to take advantage of Atom pipelined IMUL |
39 | execution. It is applied if |
40 | (1) IMUL instruction is on the top of list; |
41 | (2) There exists the only producer of independent IMUL instruction in |
42 | ready list. |
43 | Return index of IMUL producer if it was found and -1 otherwise. */ |
44 | static int |
45 | do_reorder_for_imul (rtx_insn **ready, int n_ready) |
46 | { |
47 | rtx_insn *insn; |
48 | rtx set, insn1, insn2; |
49 | sd_iterator_def sd_it; |
50 | dep_t dep; |
51 | int index = -1; |
52 | int i; |
53 | |
54 | if (!TARGET_CPU_P (BONNELL)) |
55 | return index; |
56 | |
57 | /* Check that IMUL instruction is on the top of ready list. */ |
58 | insn = ready[n_ready - 1]; |
59 | set = single_set (insn); |
60 | if (!set) |
61 | return index; |
62 | if (!(GET_CODE (SET_SRC (set)) == MULT |
63 | && GET_MODE (SET_SRC (set)) == SImode)) |
64 | return index; |
65 | |
66 | /* Search for producer of independent IMUL instruction. */ |
67 | for (i = n_ready - 2; i >= 0; i--) |
68 | { |
69 | insn = ready[i]; |
70 | if (!NONDEBUG_INSN_P (insn)) |
71 | continue; |
72 | /* Skip IMUL instruction. */ |
73 | insn2 = PATTERN (insn); |
74 | if (GET_CODE (insn2) == PARALLEL) |
75 | insn2 = XVECEXP (insn2, 0, 0); |
76 | if (GET_CODE (insn2) == SET |
77 | && GET_CODE (SET_SRC (insn2)) == MULT |
78 | && GET_MODE (SET_SRC (insn2)) == SImode) |
79 | continue; |
80 | |
81 | FOR_EACH_DEP (insn, SD_LIST_FORW, sd_it, dep) |
82 | { |
83 | rtx con; |
84 | con = DEP_CON (dep); |
85 | if (!NONDEBUG_INSN_P (con)) |
86 | continue; |
87 | insn1 = PATTERN (insn: con); |
88 | if (GET_CODE (insn1) == PARALLEL) |
89 | insn1 = XVECEXP (insn1, 0, 0); |
90 | |
91 | if (GET_CODE (insn1) == SET |
92 | && GET_CODE (SET_SRC (insn1)) == MULT |
93 | && GET_MODE (SET_SRC (insn1)) == SImode) |
94 | { |
95 | sd_iterator_def sd_it1; |
96 | dep_t dep1; |
97 | /* Check if there is no other dependee for IMUL. */ |
98 | index = i; |
99 | FOR_EACH_DEP (con, SD_LIST_BACK, sd_it1, dep1) |
100 | { |
101 | rtx pro; |
102 | pro = DEP_PRO (dep1); |
103 | if (!NONDEBUG_INSN_P (pro)) |
104 | continue; |
105 | if (pro != insn) |
106 | index = -1; |
107 | } |
108 | if (index >= 0) |
109 | break; |
110 | } |
111 | } |
112 | if (index >= 0) |
113 | break; |
114 | } |
115 | return index; |
116 | } |
117 | |
118 | /* Try to find the best candidate on the top of ready list if two insns |
119 | have the same priority - candidate is best if its dependees were |
120 | scheduled earlier. Applied for Silvermont only. |
121 | Return true if top 2 insns must be interchanged. */ |
122 | static bool |
123 | swap_top_of_ready_list (rtx_insn **ready, int n_ready) |
124 | { |
125 | rtx_insn *top = ready[n_ready - 1]; |
126 | rtx_insn *next = ready[n_ready - 2]; |
127 | rtx set; |
128 | sd_iterator_def sd_it; |
129 | dep_t dep; |
130 | int clock1 = -1; |
131 | int clock2 = -1; |
132 | #define INSN_TICK(INSN) (HID (INSN)->tick) |
133 | |
134 | if (!TARGET_CPU_P (SILVERMONT) && !TARGET_CPU_P (INTEL)) |
135 | return false; |
136 | |
137 | if (!NONDEBUG_INSN_P (top)) |
138 | return false; |
139 | if (!NONJUMP_INSN_P (top)) |
140 | return false; |
141 | if (!NONDEBUG_INSN_P (next)) |
142 | return false; |
143 | if (!NONJUMP_INSN_P (next)) |
144 | return false; |
145 | set = single_set (insn: top); |
146 | if (!set) |
147 | return false; |
148 | set = single_set (insn: next); |
149 | if (!set) |
150 | return false; |
151 | |
152 | if (INSN_PRIORITY_KNOWN (top) && INSN_PRIORITY_KNOWN (next)) |
153 | { |
154 | if (INSN_PRIORITY (top) != INSN_PRIORITY (next)) |
155 | return false; |
156 | /* Determine winner more precise. */ |
157 | FOR_EACH_DEP (top, SD_LIST_RES_BACK, sd_it, dep) |
158 | { |
159 | rtx pro; |
160 | pro = DEP_PRO (dep); |
161 | if (!NONDEBUG_INSN_P (pro)) |
162 | continue; |
163 | if (INSN_TICK (pro) > clock1) |
164 | clock1 = INSN_TICK (pro); |
165 | } |
166 | FOR_EACH_DEP (next, SD_LIST_RES_BACK, sd_it, dep) |
167 | { |
168 | rtx pro; |
169 | pro = DEP_PRO (dep); |
170 | if (!NONDEBUG_INSN_P (pro)) |
171 | continue; |
172 | if (INSN_TICK (pro) > clock2) |
173 | clock2 = INSN_TICK (pro); |
174 | } |
175 | |
176 | if (clock1 == clock2) |
177 | { |
178 | /* Determine winner - load must win. */ |
179 | enum attr_memory memory1, memory2; |
180 | memory1 = get_attr_memory (top); |
181 | memory2 = get_attr_memory (next); |
182 | if (memory2 == MEMORY_LOAD && memory1 != MEMORY_LOAD) |
183 | return true; |
184 | } |
185 | return (bool) (clock2 < clock1); |
186 | } |
187 | return false; |
188 | #undef INSN_TICK |
189 | } |
190 | |
191 | /* Perform possible reodering of ready list for Atom/Silvermont only. |
192 | Return issue rate. */ |
193 | int |
194 | ix86_atom_sched_reorder (FILE *dump, int sched_verbose, rtx_insn **ready, |
195 | int *pn_ready, int clock_var) |
196 | { |
197 | int issue_rate = -1; |
198 | int n_ready = *pn_ready; |
199 | int i; |
200 | rtx_insn *insn; |
201 | int index = -1; |
202 | |
203 | /* Set up issue rate. */ |
204 | issue_rate = ix86_issue_rate (); |
205 | |
206 | /* Do reodering for BONNELL/SILVERMONT only. */ |
207 | if (!TARGET_CPU_P (BONNELL) && !TARGET_CPU_P (SILVERMONT) |
208 | && !TARGET_CPU_P (INTEL)) |
209 | return issue_rate; |
210 | |
211 | /* Nothing to do if ready list contains only 1 instruction. */ |
212 | if (n_ready <= 1) |
213 | return issue_rate; |
214 | |
215 | /* Do reodering for post-reload scheduler only. */ |
216 | if (!reload_completed) |
217 | return issue_rate; |
218 | |
219 | if ((index = do_reorder_for_imul (ready, n_ready)) >= 0) |
220 | { |
221 | if (sched_verbose > 1) |
222 | fprintf (stream: dump, format: ";;\tatom sched_reorder: put %d insn on top\n" , |
223 | INSN_UID (insn: ready[index])); |
224 | |
225 | /* Put IMUL producer (ready[index]) at the top of ready list. */ |
226 | insn = ready[index]; |
227 | for (i = index; i < n_ready - 1; i++) |
228 | ready[i] = ready[i + 1]; |
229 | ready[n_ready - 1] = insn; |
230 | return issue_rate; |
231 | } |
232 | |
233 | /* Skip selective scheduling since HID is not populated in it. */ |
234 | if (clock_var != 0 |
235 | && !sel_sched_p () |
236 | && swap_top_of_ready_list (ready, n_ready)) |
237 | { |
238 | if (sched_verbose > 1) |
239 | fprintf (stream: dump, format: ";;\tslm sched_reorder: swap %d and %d insns\n" , |
240 | INSN_UID (insn: ready[n_ready - 1]), INSN_UID (insn: ready[n_ready - 2])); |
241 | /* Swap 2 top elements of ready list. */ |
242 | insn = ready[n_ready - 1]; |
243 | ready[n_ready - 1] = ready[n_ready - 2]; |
244 | ready[n_ready - 2] = insn; |
245 | } |
246 | return issue_rate; |
247 | } |
248 | |