annotate gcc/config/aarch64/cortex-a57-fma-steering.c @ 145:1830386684a0

gcc-9.2.0
author anatofuz
date Thu, 13 Feb 2020 11:34:05 +0900
parents 84e7813d76e9
children
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
111
kono
parents:
diff changeset
1 /* FMA steering optimization pass for Cortex-A57.
145
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
2 Copyright (C) 2015-2020 Free Software Foundation, Inc.
111
kono
parents:
diff changeset
3 Contributed by ARM Ltd.
kono
parents:
diff changeset
4
kono
parents:
diff changeset
5 This file is part of GCC.
kono
parents:
diff changeset
6
kono
parents:
diff changeset
7 GCC is free software; you can redistribute it and/or modify it
kono
parents:
diff changeset
8 under the terms of the GNU General Public License as published by
kono
parents:
diff changeset
9 the Free Software Foundation; either version 3, or (at your option)
kono
parents:
diff changeset
10 any later version.
kono
parents:
diff changeset
11
kono
parents:
diff changeset
12 GCC is distributed in the hope that it will be useful, but
kono
parents:
diff changeset
13 WITHOUT ANY WARRANTY; without even the implied warranty of
kono
parents:
diff changeset
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
kono
parents:
diff changeset
15 General Public License for more details.
kono
parents:
diff changeset
16
kono
parents:
diff changeset
17 You should have received a copy of the GNU General Public License
kono
parents:
diff changeset
18 along with GCC; see the file COPYING3. If not see
kono
parents:
diff changeset
19 <http://www.gnu.org/licenses/>. */
kono
parents:
diff changeset
20
131
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
21 #define IN_TARGET_CODE 1
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
22
111
kono
parents:
diff changeset
23 #include "config.h"
kono
parents:
diff changeset
24 #define INCLUDE_LIST
kono
parents:
diff changeset
25 #include "system.h"
kono
parents:
diff changeset
26 #include "coretypes.h"
kono
parents:
diff changeset
27 #include "backend.h"
kono
parents:
diff changeset
28 #include "target.h"
kono
parents:
diff changeset
29 #include "rtl.h"
kono
parents:
diff changeset
30 #include "df.h"
kono
parents:
diff changeset
31 #include "insn-config.h"
kono
parents:
diff changeset
32 #include "regs.h"
kono
parents:
diff changeset
33 #include "memmodel.h"
kono
parents:
diff changeset
34 #include "emit-rtl.h"
kono
parents:
diff changeset
35 #include "recog.h"
kono
parents:
diff changeset
36 #include "cfganal.h"
kono
parents:
diff changeset
37 #include "insn-attr.h"
kono
parents:
diff changeset
38 #include "context.h"
kono
parents:
diff changeset
39 #include "tree-pass.h"
145
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
40 #include "function-abi.h"
111
kono
parents:
diff changeset
41 #include "regrename.h"
kono
parents:
diff changeset
42 #include "aarch64-protos.h"
kono
parents:
diff changeset
43
kono
parents:
diff changeset
44 /* For better performance, the destination of FMADD/FMSUB instructions should
kono
parents:
diff changeset
45 have the same parity as their accumulator register if the accumulator
kono
parents:
diff changeset
46 contains the result of a previous FMUL or FMADD/FMSUB instruction if
kono
parents:
diff changeset
47 targetting Cortex-A57 processors. Performance is also increased by
kono
parents:
diff changeset
48 otherwise keeping a good balance in the parity of the destination register
kono
parents:
diff changeset
49 of FMUL or FMADD/FMSUB.
kono
parents:
diff changeset
50
kono
parents:
diff changeset
51 This pass ensure that registers are renamed so that these conditions hold.
kono
parents:
diff changeset
52 We reuse the existing register renaming facility from regrename.c to build
kono
parents:
diff changeset
53 dependency chains and expose candidate registers for renaming.
kono
parents:
diff changeset
54
kono
parents:
diff changeset
55
kono
parents:
diff changeset
56 The algorithm has three steps:
kono
parents:
diff changeset
57
kono
parents:
diff changeset
58 First, the functions of the register renaming pass are called. These
kono
parents:
diff changeset
59 analyze the instructions and produce a list of def/use chains of
kono
parents:
diff changeset
60 instructions.
kono
parents:
diff changeset
61
kono
parents:
diff changeset
62 Next, this information is used to build trees of multiply and
kono
parents:
diff changeset
63 multiply-accumulate instructions. The roots of these trees are any
kono
parents:
diff changeset
64 multiply, or any multiply-accumulate whose accumulator is not dependent on
kono
parents:
diff changeset
65 a multiply or multiply-accumulate instruction. A child is added to the
kono
parents:
diff changeset
66 tree where a dependency chain exists between the result of the parent
kono
parents:
diff changeset
67 instruction and the accumulator operand of the child, as in the diagram
kono
parents:
diff changeset
68 below:
kono
parents:
diff changeset
69
kono
parents:
diff changeset
70 fmul s2, s0, s1
kono
parents:
diff changeset
71 / \
kono
parents:
diff changeset
72 fmadd s0, s1, s1, s2 fmadd s4, s1, s1 s2
kono
parents:
diff changeset
73 |
kono
parents:
diff changeset
74 fmadd s3, s1, s1, s0
kono
parents:
diff changeset
75
kono
parents:
diff changeset
76 Trees made of a single instruction are permitted.
kono
parents:
diff changeset
77
kono
parents:
diff changeset
78 Finally, renaming is performed. The parity of the destination register at
kono
parents:
diff changeset
79 the root of a tree is checked against the current balance of multiply and
kono
parents:
diff changeset
80 multiply-accumulate on each pipeline. If necessary, the root of a tree is
kono
parents:
diff changeset
81 renamed, in which case the rest of the tree is then renamed to keep the same
kono
parents:
diff changeset
82 parity in the destination registers of all instructions in the tree. */
kono
parents:
diff changeset
83
kono
parents:
diff changeset
84
kono
parents:
diff changeset
85
kono
parents:
diff changeset
86 /* Forward declarations. */
kono
parents:
diff changeset
87 class fma_node;
kono
parents:
diff changeset
88 class fma_root_node;
kono
parents:
diff changeset
89 class func_fma_steering;
kono
parents:
diff changeset
90
kono
parents:
diff changeset
91 /* Dependencies between FMUL or FMADD/FMSUB instructions and subsequent
kono
parents:
diff changeset
92 FMADD/FMSUB instructions form a graph. This is because alternatives can
kono
parents:
diff changeset
93 make a register be set by several FMUL or FMADD/FMSUB instructions in
kono
parents:
diff changeset
94 different basic blocks and because of loops. For ease of browsing, the
kono
parents:
diff changeset
95 connected components of this graph are broken up into forests of trees.
kono
parents:
diff changeset
96 Forests are represented by fma_forest objects, contained in the fma_forests
kono
parents:
diff changeset
97 list. Using a separate object for the forests allows for a better use of
kono
parents:
diff changeset
98 memory as there is some information that is global to each forest, such as
kono
parents:
diff changeset
99 the number of FMSUB and FMADD/FMSUB instructions currently scheduled on each
kono
parents:
diff changeset
100 floating-point execution pipelines. */
kono
parents:
diff changeset
101
kono
parents:
diff changeset
102 class fma_forest
kono
parents:
diff changeset
103 {
kono
parents:
diff changeset
104 public:
kono
parents:
diff changeset
105 fma_forest (func_fma_steering *, fma_root_node *, int);
kono
parents:
diff changeset
106 ~fma_forest ();
kono
parents:
diff changeset
107
kono
parents:
diff changeset
108 int get_id ();
kono
parents:
diff changeset
109 std::list<fma_root_node *> *get_roots ();
kono
parents:
diff changeset
110 func_fma_steering *get_globals ();
kono
parents:
diff changeset
111 int get_target_parity ();
kono
parents:
diff changeset
112 void fma_node_created (fma_node *);
kono
parents:
diff changeset
113 void merge_forest (fma_forest *);
kono
parents:
diff changeset
114 void dump_info ();
kono
parents:
diff changeset
115 void dispatch ();
kono
parents:
diff changeset
116
kono
parents:
diff changeset
117 private:
145
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
118 /* Prohibit copy construction. */
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
119 fma_forest (const fma_forest &);
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
120
111
kono
parents:
diff changeset
121 /* The list of roots that form this forest. */
kono
parents:
diff changeset
122 std::list<fma_root_node *> *m_roots;
kono
parents:
diff changeset
123
kono
parents:
diff changeset
124 /* Target parity the destination register of all FMUL and FMADD/FMSUB
kono
parents:
diff changeset
125 instructions in this forest should have. */
kono
parents:
diff changeset
126 int m_target_parity;
kono
parents:
diff changeset
127
kono
parents:
diff changeset
128 /* Link to the instance of func_fma_steering holding data related to the
kono
parents:
diff changeset
129 FMA steering of the current function (cfun). */
kono
parents:
diff changeset
130 func_fma_steering *m_globals;
kono
parents:
diff changeset
131
kono
parents:
diff changeset
132 /* Identifier for the forest (used for dumps). */
kono
parents:
diff changeset
133 int m_id;
kono
parents:
diff changeset
134
kono
parents:
diff changeset
135 /* Total number of nodes in the forest (for statistics). */
kono
parents:
diff changeset
136 int m_nb_nodes;
kono
parents:
diff changeset
137 };
kono
parents:
diff changeset
138
kono
parents:
diff changeset
139 class fma_node
kono
parents:
diff changeset
140 {
kono
parents:
diff changeset
141 public:
kono
parents:
diff changeset
142 fma_node (fma_node *parent, du_chain *chain);
kono
parents:
diff changeset
143 ~fma_node ();
kono
parents:
diff changeset
144
kono
parents:
diff changeset
145 bool root_p ();
kono
parents:
diff changeset
146 fma_forest *get_forest ();
kono
parents:
diff changeset
147 std::list<fma_node *> *get_children ();
kono
parents:
diff changeset
148 rtx_insn *get_insn ();
kono
parents:
diff changeset
149 void add_child (fma_node *);
kono
parents:
diff changeset
150 int get_parity ();
kono
parents:
diff changeset
151 void set_head (du_head *);
kono
parents:
diff changeset
152 void rename (fma_forest *);
kono
parents:
diff changeset
153 void dump_info (fma_forest *);
kono
parents:
diff changeset
154
145
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
155 private:
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
156 /* Prohibit copy construction. */
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
157 fma_node (const fma_node &);
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
158
111
kono
parents:
diff changeset
159 protected:
kono
parents:
diff changeset
160 /* Root node that lead to this node. */
kono
parents:
diff changeset
161 fma_root_node *m_root;
kono
parents:
diff changeset
162
kono
parents:
diff changeset
163 /* The parent node of this node. If the node belong to a chain with several
kono
parents:
diff changeset
164 parent nodes, the first one encountered in a depth-first search is chosen
kono
parents:
diff changeset
165 as canonical parent. */
kono
parents:
diff changeset
166 fma_node *m_parent;
kono
parents:
diff changeset
167
kono
parents:
diff changeset
168 /* The list of child nodes. If a chain contains several parent nodes, one is
kono
parents:
diff changeset
169 chosen as canonical parent and the others will have no children. */
kono
parents:
diff changeset
170 std::list<fma_node *> *m_children;
kono
parents:
diff changeset
171
kono
parents:
diff changeset
172 /* The associated DU_HEAD chain that the insn represented by this object
kono
parents:
diff changeset
173 is (one of) the root of. When a chain contains several roots, the non
kono
parents:
diff changeset
174 canonical ones have this field set to NULL. */
kono
parents:
diff changeset
175 struct du_head *m_head;
kono
parents:
diff changeset
176
kono
parents:
diff changeset
177 /* The FMUL or FMADD/FMSUB instruction this object corresponds to. */
kono
parents:
diff changeset
178 rtx_insn *m_insn;
kono
parents:
diff changeset
179 };
kono
parents:
diff changeset
180
kono
parents:
diff changeset
181 class fma_root_node : public fma_node
kono
parents:
diff changeset
182 {
kono
parents:
diff changeset
183 public:
kono
parents:
diff changeset
184 fma_root_node (func_fma_steering *, du_chain *, int);
kono
parents:
diff changeset
185
kono
parents:
diff changeset
186 fma_forest *get_forest ();
kono
parents:
diff changeset
187 void set_forest (fma_forest *);
kono
parents:
diff changeset
188 void dump_info (fma_forest *);
kono
parents:
diff changeset
189
kono
parents:
diff changeset
190 private:
kono
parents:
diff changeset
191 /* The forest this node belonged to when it was created. */
kono
parents:
diff changeset
192 fma_forest *m_forest;
kono
parents:
diff changeset
193 };
kono
parents:
diff changeset
194
kono
parents:
diff changeset
195 /* Class holding all data and methods relative to the FMA steering of a given
kono
parents:
diff changeset
196 function. The FMA steering pass could then run in parallel for different
kono
parents:
diff changeset
197 functions. */
kono
parents:
diff changeset
198
kono
parents:
diff changeset
199 class func_fma_steering
kono
parents:
diff changeset
200 {
kono
parents:
diff changeset
201 public:
kono
parents:
diff changeset
202 func_fma_steering ();
kono
parents:
diff changeset
203 ~func_fma_steering ();
kono
parents:
diff changeset
204
kono
parents:
diff changeset
205 int get_fpu_balance ();
kono
parents:
diff changeset
206 void remove_forest (fma_forest *);
kono
parents:
diff changeset
207 bool put_node (fma_node *);
kono
parents:
diff changeset
208 void update_balance (int);
kono
parents:
diff changeset
209 fma_node *get_fma_node (rtx_insn *);
kono
parents:
diff changeset
210 void analyze_fma_fmul_insn (fma_forest *, du_chain *, du_head_p);
kono
parents:
diff changeset
211 void execute_fma_steering ();
kono
parents:
diff changeset
212
kono
parents:
diff changeset
213 private:
145
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
214 /* Prohibit copy construction. */
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
215 func_fma_steering (const func_fma_steering &);
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
216
111
kono
parents:
diff changeset
217 void dfs (void (*) (fma_forest *), void (*) (fma_forest *, fma_root_node *),
kono
parents:
diff changeset
218 void (*) (fma_forest *, fma_node *), bool);
kono
parents:
diff changeset
219 void analyze ();
kono
parents:
diff changeset
220 void rename_fma_trees ();
kono
parents:
diff changeset
221
kono
parents:
diff changeset
222 /* Mapping between FMUL or FMADD/FMSUB instructions and the associated
kono
parents:
diff changeset
223 fma_node object. Used when analyzing an instruction that is a root of
kono
parents:
diff changeset
224 a chain to find if such an object was created because this instruction
kono
parents:
diff changeset
225 is also a use in another chain. */
kono
parents:
diff changeset
226 hash_map<rtx_insn *, fma_node *> *m_insn_fma_head_map;
kono
parents:
diff changeset
227
kono
parents:
diff changeset
228 /* A list of all the forests in a given function. */
kono
parents:
diff changeset
229 std::list<fma_forest *> m_fma_forests;
kono
parents:
diff changeset
230
kono
parents:
diff changeset
231 /* Balance of FMUL and FMADD/FMSUB instructions between the two FPU
kono
parents:
diff changeset
232 pipelines:
kono
parents:
diff changeset
233 < 0: more instruction dispatched to the first pipeline
kono
parents:
diff changeset
234 == 0: perfect balance
kono
parents:
diff changeset
235 > 0: more instruction dispatched to the second pipeline. */
kono
parents:
diff changeset
236 int m_fpu_balance;
kono
parents:
diff changeset
237
kono
parents:
diff changeset
238 /* Identifier for the next forest created. */
kono
parents:
diff changeset
239 int m_next_forest_id;
kono
parents:
diff changeset
240 };
kono
parents:
diff changeset
241
kono
parents:
diff changeset
242 /* Rename the register HEAD->regno in all the insns in the chain HEAD to any
kono
parents:
diff changeset
243 register not in the set UNAVAILABLE. Adapted from rename_chains in
kono
parents:
diff changeset
244 regrename.c. */
kono
parents:
diff changeset
245
kono
parents:
diff changeset
246 static bool
kono
parents:
diff changeset
247 rename_single_chain (du_head_p head, HARD_REG_SET *unavailable)
kono
parents:
diff changeset
248 {
kono
parents:
diff changeset
249 int best_new_reg;
kono
parents:
diff changeset
250 int n_uses = 0;
kono
parents:
diff changeset
251 struct du_chain *tmp;
kono
parents:
diff changeset
252 int reg = head->regno;
kono
parents:
diff changeset
253 enum reg_class super_class = NO_REGS;
kono
parents:
diff changeset
254
kono
parents:
diff changeset
255 if (head->cannot_rename)
kono
parents:
diff changeset
256 return false;
kono
parents:
diff changeset
257
kono
parents:
diff changeset
258 if (fixed_regs[reg] || global_regs[reg]
kono
parents:
diff changeset
259 || (frame_pointer_needed && reg == HARD_FRAME_POINTER_REGNUM))
kono
parents:
diff changeset
260 return false;
kono
parents:
diff changeset
261
kono
parents:
diff changeset
262 /* Iterate over elements in the chain in order to:
kono
parents:
diff changeset
263 1. Count number of uses, and narrow the set of registers we can
kono
parents:
diff changeset
264 use for renaming.
kono
parents:
diff changeset
265 2. Compute the superunion of register classes in this chain. */
kono
parents:
diff changeset
266 for (tmp = head->first; tmp; tmp = tmp->next_use)
kono
parents:
diff changeset
267 {
kono
parents:
diff changeset
268 if (DEBUG_INSN_P (tmp->insn))
kono
parents:
diff changeset
269 continue;
kono
parents:
diff changeset
270 n_uses++;
145
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
271 *unavailable |= ~reg_class_contents[tmp->cl];
111
kono
parents:
diff changeset
272 super_class = reg_class_superunion[(int) super_class][(int) tmp->cl];
kono
parents:
diff changeset
273 }
kono
parents:
diff changeset
274
kono
parents:
diff changeset
275 if (n_uses < 1)
kono
parents:
diff changeset
276 return false;
kono
parents:
diff changeset
277
kono
parents:
diff changeset
278 best_new_reg = find_rename_reg (head, super_class, unavailable, reg,
kono
parents:
diff changeset
279 false);
kono
parents:
diff changeset
280
kono
parents:
diff changeset
281 if (dump_file)
kono
parents:
diff changeset
282 {
kono
parents:
diff changeset
283 fprintf (dump_file, "Register %s in insn %d", reg_names[reg],
kono
parents:
diff changeset
284 INSN_UID (head->first->insn));
145
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
285 if (head->call_abis)
111
kono
parents:
diff changeset
286 fprintf (dump_file, " crosses a call");
kono
parents:
diff changeset
287 }
kono
parents:
diff changeset
288
kono
parents:
diff changeset
289 if (best_new_reg == reg)
kono
parents:
diff changeset
290 {
kono
parents:
diff changeset
291 if (dump_file)
kono
parents:
diff changeset
292 fprintf (dump_file, "; no available better choice\n");
kono
parents:
diff changeset
293 return false;
kono
parents:
diff changeset
294 }
kono
parents:
diff changeset
295
kono
parents:
diff changeset
296 if (regrename_do_replace (head, best_new_reg))
kono
parents:
diff changeset
297 {
kono
parents:
diff changeset
298 if (dump_file)
kono
parents:
diff changeset
299 fprintf (dump_file, ", renamed as %s\n", reg_names[best_new_reg]);
kono
parents:
diff changeset
300 df_set_regs_ever_live (best_new_reg, true);
kono
parents:
diff changeset
301 }
kono
parents:
diff changeset
302 else
kono
parents:
diff changeset
303 {
kono
parents:
diff changeset
304 if (dump_file)
kono
parents:
diff changeset
305 fprintf (dump_file, ", renaming as %s failed\n",
kono
parents:
diff changeset
306 reg_names[best_new_reg]);
kono
parents:
diff changeset
307 return false;
kono
parents:
diff changeset
308 }
kono
parents:
diff changeset
309 return true;
kono
parents:
diff changeset
310 }
kono
parents:
diff changeset
311
kono
parents:
diff changeset
312 /* Return whether T is the attribute of a FMADD/FMSUB-like instruction. */
kono
parents:
diff changeset
313
kono
parents:
diff changeset
314 static bool
kono
parents:
diff changeset
315 is_fmac_op (enum attr_type t)
kono
parents:
diff changeset
316 {
kono
parents:
diff changeset
317 return (t == TYPE_FMACS) || (t == TYPE_FMACD) || (t == TYPE_NEON_FP_MLA_S);
kono
parents:
diff changeset
318 }
kono
parents:
diff changeset
319
kono
parents:
diff changeset
320 /* Return whether T is the attribute of a FMUL instruction. */
kono
parents:
diff changeset
321
kono
parents:
diff changeset
322 static bool
kono
parents:
diff changeset
323 is_fmul_op (enum attr_type t)
kono
parents:
diff changeset
324 {
kono
parents:
diff changeset
325 return (t == TYPE_FMULS) || (t == TYPE_FMULD) || (t == TYPE_NEON_FP_MUL_S);
kono
parents:
diff changeset
326 }
kono
parents:
diff changeset
327
kono
parents:
diff changeset
328 /* Return whether INSN is an FMUL (if FMUL_OK is true) or FMADD/FMSUB
kono
parents:
diff changeset
329 instruction. */
kono
parents:
diff changeset
330
kono
parents:
diff changeset
331 static bool
kono
parents:
diff changeset
332 is_fmul_fmac_insn (rtx_insn *insn, bool fmul_ok)
kono
parents:
diff changeset
333 {
kono
parents:
diff changeset
334 enum attr_type t;
kono
parents:
diff changeset
335
kono
parents:
diff changeset
336 if (!NONDEBUG_INSN_P (insn))
kono
parents:
diff changeset
337 return false;
kono
parents:
diff changeset
338
kono
parents:
diff changeset
339 if (recog_memoized (insn) < 0)
kono
parents:
diff changeset
340 return false;
kono
parents:
diff changeset
341
kono
parents:
diff changeset
342 /* Only consider chain(s) this instruction is a root of if this is an FMUL or
kono
parents:
diff changeset
343 FMADD/FMSUB instruction. This allows to avoid browsing chains of all
kono
parents:
diff changeset
344 instructions for FMUL or FMADD/FMSUB in them. */
kono
parents:
diff changeset
345 t = get_attr_type (insn);
kono
parents:
diff changeset
346 return is_fmac_op (t) || (fmul_ok && is_fmul_op (t));
kono
parents:
diff changeset
347 }
kono
parents:
diff changeset
348
kono
parents:
diff changeset
349
kono
parents:
diff changeset
350 /*
kono
parents:
diff changeset
351 * Class fma_forest method definitions.
kono
parents:
diff changeset
352 */
kono
parents:
diff changeset
353
kono
parents:
diff changeset
354 fma_forest::fma_forest (func_fma_steering *fma_steer, fma_root_node *fma_root,
kono
parents:
diff changeset
355 int id)
kono
parents:
diff changeset
356 {
kono
parents:
diff changeset
357 memset (this, 0, sizeof (*this));
kono
parents:
diff changeset
358 this->m_globals = fma_steer;
kono
parents:
diff changeset
359 this->m_roots = new std::list<fma_root_node *>;
kono
parents:
diff changeset
360 this->m_roots->push_back (fma_root);
kono
parents:
diff changeset
361 this->m_id = id;
kono
parents:
diff changeset
362 }
kono
parents:
diff changeset
363
kono
parents:
diff changeset
364 fma_forest::~fma_forest ()
kono
parents:
diff changeset
365 {
kono
parents:
diff changeset
366 delete this->m_roots;
kono
parents:
diff changeset
367 }
kono
parents:
diff changeset
368
kono
parents:
diff changeset
369 int
kono
parents:
diff changeset
370 fma_forest::get_id ()
kono
parents:
diff changeset
371 {
kono
parents:
diff changeset
372 return this->m_id;
kono
parents:
diff changeset
373 }
kono
parents:
diff changeset
374
kono
parents:
diff changeset
375 std::list<fma_root_node *> *
kono
parents:
diff changeset
376 fma_forest::get_roots ()
kono
parents:
diff changeset
377 {
kono
parents:
diff changeset
378 return this->m_roots;
kono
parents:
diff changeset
379 }
kono
parents:
diff changeset
380
kono
parents:
diff changeset
381 func_fma_steering *
kono
parents:
diff changeset
382 fma_forest::get_globals ()
kono
parents:
diff changeset
383 {
kono
parents:
diff changeset
384 return this->m_globals;
kono
parents:
diff changeset
385 }
kono
parents:
diff changeset
386
kono
parents:
diff changeset
387 int
kono
parents:
diff changeset
388 fma_forest::get_target_parity ()
kono
parents:
diff changeset
389 {
kono
parents:
diff changeset
390 return this->m_target_parity;
kono
parents:
diff changeset
391 }
kono
parents:
diff changeset
392
kono
parents:
diff changeset
393 /* Act on the creation of NODE by updating statistics in FOREST and adding an
kono
parents:
diff changeset
394 entry for it in the func_fma_steering hashmap. */
kono
parents:
diff changeset
395
kono
parents:
diff changeset
396 void fma_forest::fma_node_created (fma_node *node)
kono
parents:
diff changeset
397 {
kono
parents:
diff changeset
398 bool created = !this->m_globals->put_node (node);
kono
parents:
diff changeset
399
kono
parents:
diff changeset
400 gcc_assert (created);
kono
parents:
diff changeset
401 this->m_nb_nodes++;
kono
parents:
diff changeset
402 }
kono
parents:
diff changeset
403
kono
parents:
diff changeset
404 /* Merge REF_FOREST and OTHER_FOREST together, making REF_FOREST the canonical
kono
parents:
diff changeset
405 fma_forest object to represent both. */
kono
parents:
diff changeset
406
kono
parents:
diff changeset
407 void
kono
parents:
diff changeset
408 fma_forest::merge_forest (fma_forest *other_forest)
kono
parents:
diff changeset
409 {
kono
parents:
diff changeset
410 std::list<fma_root_node *> *other_roots;
kono
parents:
diff changeset
411 std::list<fma_root_node *>::iterator other_root_iter;
kono
parents:
diff changeset
412
kono
parents:
diff changeset
413 if (this == other_forest)
kono
parents:
diff changeset
414 return;
kono
parents:
diff changeset
415
kono
parents:
diff changeset
416 other_roots = other_forest->m_roots;
kono
parents:
diff changeset
417
kono
parents:
diff changeset
418 /* Update root nodes' pointer to forest. */
kono
parents:
diff changeset
419 for (other_root_iter = other_roots->begin ();
131
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
420 other_root_iter != other_roots->end (); ++other_root_iter)
111
kono
parents:
diff changeset
421 (*other_root_iter)->set_forest (this);
kono
parents:
diff changeset
422
kono
parents:
diff changeset
423 /* Remove other_forest from the list of forests and move its tree roots in
kono
parents:
diff changeset
424 the list of tree roots of ref_forest. */
kono
parents:
diff changeset
425 this->m_globals->remove_forest (other_forest);
kono
parents:
diff changeset
426 this->m_roots->splice (this->m_roots->begin (), *other_roots);
kono
parents:
diff changeset
427 this->m_nb_nodes += other_forest->m_nb_nodes;
kono
parents:
diff changeset
428
kono
parents:
diff changeset
429 delete other_forest;
kono
parents:
diff changeset
430 }
kono
parents:
diff changeset
431
kono
parents:
diff changeset
432 /* Dump information about the forest FOREST. */
kono
parents:
diff changeset
433
kono
parents:
diff changeset
434 void
kono
parents:
diff changeset
435 fma_forest::dump_info ()
kono
parents:
diff changeset
436 {
kono
parents:
diff changeset
437 gcc_assert (dump_file);
kono
parents:
diff changeset
438
kono
parents:
diff changeset
439 fprintf (dump_file, "Forest #%d has %d nodes\n", this->m_id,
kono
parents:
diff changeset
440 this->m_nb_nodes);
kono
parents:
diff changeset
441 }
kono
parents:
diff changeset
442
kono
parents:
diff changeset
443 /* Wrapper around fma_forest::dump_info for use as parameter of function
kono
parents:
diff changeset
444 pointer type in func_fma_steering::dfs. */
kono
parents:
diff changeset
445
kono
parents:
diff changeset
446 static void
kono
parents:
diff changeset
447 dump_forest_info (fma_forest *forest)
kono
parents:
diff changeset
448 {
kono
parents:
diff changeset
449 forest->dump_info ();
kono
parents:
diff changeset
450 }
kono
parents:
diff changeset
451
kono
parents:
diff changeset
452 /* Dispatch forest to the least utilized pipeline. */
kono
parents:
diff changeset
453
kono
parents:
diff changeset
454 void
kono
parents:
diff changeset
455 fma_forest::dispatch ()
kono
parents:
diff changeset
456 {
kono
parents:
diff changeset
457 this->m_target_parity = this->m_roots->front ()->get_parity ();
kono
parents:
diff changeset
458 int fpu_balance = this->m_globals->get_fpu_balance ();
kono
parents:
diff changeset
459 if (fpu_balance != 0)
kono
parents:
diff changeset
460 this->m_target_parity = (fpu_balance < 0);
kono
parents:
diff changeset
461
kono
parents:
diff changeset
462 if (dump_file)
kono
parents:
diff changeset
463 fprintf (dump_file, "Target parity for forest #%d: %s\n", this->m_id,
kono
parents:
diff changeset
464 this->m_target_parity ? "odd" : "even");
kono
parents:
diff changeset
465 }
kono
parents:
diff changeset
466
kono
parents:
diff changeset
467 /* Wrapper around fma_forest::dispatch for use as parameter of function pointer
kono
parents:
diff changeset
468 type in func_fma_steering::dfs. */
kono
parents:
diff changeset
469
kono
parents:
diff changeset
470 static void
kono
parents:
diff changeset
471 dispatch_forest (fma_forest *forest)
kono
parents:
diff changeset
472 {
kono
parents:
diff changeset
473 forest->dispatch ();
kono
parents:
diff changeset
474 }
kono
parents:
diff changeset
475
kono
parents:
diff changeset
476 fma_node::fma_node (fma_node *parent, du_chain *chain)
kono
parents:
diff changeset
477 {
kono
parents:
diff changeset
478 memset (this, 0, sizeof (*this));
kono
parents:
diff changeset
479 this->m_parent = parent;
kono
parents:
diff changeset
480 this->m_children = new std::list<fma_node *>;
kono
parents:
diff changeset
481 this->m_insn = chain->insn;
kono
parents:
diff changeset
482 /* root_p () cannot be used to check for root before root is set. */
kono
parents:
diff changeset
483 if (this->m_parent == this)
kono
parents:
diff changeset
484 this->m_root = static_cast<fma_root_node *> (parent);
kono
parents:
diff changeset
485 else
kono
parents:
diff changeset
486 {
kono
parents:
diff changeset
487 this->m_root = parent->m_root;
kono
parents:
diff changeset
488 this->get_forest ()->fma_node_created (this);
kono
parents:
diff changeset
489 }
kono
parents:
diff changeset
490 }
kono
parents:
diff changeset
491
kono
parents:
diff changeset
492 fma_node::~fma_node ()
kono
parents:
diff changeset
493 {
kono
parents:
diff changeset
494 delete this->m_children;
kono
parents:
diff changeset
495 }
kono
parents:
diff changeset
496
kono
parents:
diff changeset
497 std::list<fma_node *> *
kono
parents:
diff changeset
498 fma_node::get_children ()
kono
parents:
diff changeset
499 {
kono
parents:
diff changeset
500 return this->m_children;
kono
parents:
diff changeset
501 }
kono
parents:
diff changeset
502
kono
parents:
diff changeset
503 rtx_insn *
kono
parents:
diff changeset
504 fma_node::get_insn ()
kono
parents:
diff changeset
505 {
kono
parents:
diff changeset
506 return this->m_insn;
kono
parents:
diff changeset
507 }
kono
parents:
diff changeset
508
kono
parents:
diff changeset
509 void
kono
parents:
diff changeset
510 fma_node::set_head (du_head *head)
kono
parents:
diff changeset
511 {
kono
parents:
diff changeset
512 gcc_assert (!this->m_head);
kono
parents:
diff changeset
513 this->m_head = head;
kono
parents:
diff changeset
514 }
kono
parents:
diff changeset
515
kono
parents:
diff changeset
516 /* Add a child to this node in the list of children. */
kono
parents:
diff changeset
517
kono
parents:
diff changeset
518 void
kono
parents:
diff changeset
519 fma_node::add_child (fma_node *child)
kono
parents:
diff changeset
520 {
kono
parents:
diff changeset
521 this->m_children->push_back (child);
kono
parents:
diff changeset
522 }
kono
parents:
diff changeset
523
kono
parents:
diff changeset
524 /* Return the parity of the destination register of the instruction represented
kono
parents:
diff changeset
525 by this node. */
kono
parents:
diff changeset
526
kono
parents:
diff changeset
527 int
kono
parents:
diff changeset
528 fma_node::get_parity ()
kono
parents:
diff changeset
529 {
kono
parents:
diff changeset
530 return this->m_head->regno % 2;
kono
parents:
diff changeset
531 }
kono
parents:
diff changeset
532
kono
parents:
diff changeset
533 /* Get the actual forest associated with a non root node as the one the node
kono
parents:
diff changeset
534 points to might have been merged into another one. In that case the pointer
kono
parents:
diff changeset
535 in the root nodes are updated so we return the forest pointer of a root node
kono
parents:
diff changeset
536 pointed to by the initial forest. Despite being a oneliner, this method is
kono
parents:
diff changeset
537 defined here as it references a method from fma_root_node. */
kono
parents:
diff changeset
538
kono
parents:
diff changeset
539 fma_forest *
kono
parents:
diff changeset
540 fma_node::get_forest ()
kono
parents:
diff changeset
541 {
kono
parents:
diff changeset
542 return this->m_root->get_forest ();
kono
parents:
diff changeset
543 }
kono
parents:
diff changeset
544
kono
parents:
diff changeset
545 /* Return whether a node is a root node. */
kono
parents:
diff changeset
546
kono
parents:
diff changeset
547 bool
kono
parents:
diff changeset
548 fma_node::root_p ()
kono
parents:
diff changeset
549 {
kono
parents:
diff changeset
550 return this->m_root == this;
kono
parents:
diff changeset
551 }
kono
parents:
diff changeset
552
kono
parents:
diff changeset
553 /* Dump information about the children of node FMA_NODE in forest FOREST. */
kono
parents:
diff changeset
554
kono
parents:
diff changeset
555 void
kono
parents:
diff changeset
556 fma_node::dump_info (ATTRIBUTE_UNUSED fma_forest *forest)
kono
parents:
diff changeset
557 {
kono
parents:
diff changeset
558 struct du_chain *chain;
kono
parents:
diff changeset
559 std::list<fma_node *>::iterator fma_child;
kono
parents:
diff changeset
560
kono
parents:
diff changeset
561 gcc_assert (dump_file);
kono
parents:
diff changeset
562
kono
parents:
diff changeset
563 if (this->get_children ()->empty ())
kono
parents:
diff changeset
564 return;
kono
parents:
diff changeset
565
kono
parents:
diff changeset
566 fprintf (dump_file, "Instruction(s)");
kono
parents:
diff changeset
567 for (chain = this->m_head->first; chain; chain = chain->next_use)
kono
parents:
diff changeset
568 {
kono
parents:
diff changeset
569 if (!is_fmul_fmac_insn (chain->insn, true))
kono
parents:
diff changeset
570 continue;
kono
parents:
diff changeset
571
kono
parents:
diff changeset
572 if (chain->loc != &SET_DEST (PATTERN (chain->insn)))
kono
parents:
diff changeset
573 continue;
kono
parents:
diff changeset
574
kono
parents:
diff changeset
575 fprintf (dump_file, " %d", INSN_UID (chain->insn));
kono
parents:
diff changeset
576 }
kono
parents:
diff changeset
577
kono
parents:
diff changeset
578 fprintf (dump_file, " is(are) accumulator dependency of instructions");
kono
parents:
diff changeset
579 for (fma_child = this->get_children ()->begin ();
kono
parents:
diff changeset
580 fma_child != this->get_children ()->end (); fma_child++)
kono
parents:
diff changeset
581 fprintf (dump_file, " %d", INSN_UID ((*fma_child)->m_insn));
kono
parents:
diff changeset
582 fprintf (dump_file, "\n");
kono
parents:
diff changeset
583 }
kono
parents:
diff changeset
584
kono
parents:
diff changeset
585 /* Wrapper around fma_node::dump_info for use as parameter of function pointer
kono
parents:
diff changeset
586 type in func_fma_steering::dfs. */
kono
parents:
diff changeset
587
kono
parents:
diff changeset
588 static void
kono
parents:
diff changeset
589 dump_tree_node_info (fma_forest *forest, fma_node *node)
kono
parents:
diff changeset
590 {
kono
parents:
diff changeset
591 node->dump_info (forest);
kono
parents:
diff changeset
592 }
kono
parents:
diff changeset
593
kono
parents:
diff changeset
594 /* Rename the destination register of a single FMUL or FMADD/FMSUB instruction
kono
parents:
diff changeset
595 represented by FMA_NODE to a register that respect the target parity for
kono
parents:
diff changeset
596 FOREST or with same parity of the instruction represented by its parent node
kono
parents:
diff changeset
597 if it has one. */
kono
parents:
diff changeset
598
kono
parents:
diff changeset
599 void
kono
parents:
diff changeset
600 fma_node::rename (fma_forest *forest)
kono
parents:
diff changeset
601 {
kono
parents:
diff changeset
602 int cur_parity, target_parity;
kono
parents:
diff changeset
603
kono
parents:
diff changeset
604 /* This is alternate root of a chain and thus has no children. It will be
kono
parents:
diff changeset
605 renamed when processing the canonical root for that chain. */
kono
parents:
diff changeset
606 if (!this->m_head)
kono
parents:
diff changeset
607 return;
kono
parents:
diff changeset
608
kono
parents:
diff changeset
609 target_parity = forest->get_target_parity ();
kono
parents:
diff changeset
610 if (this->m_parent)
kono
parents:
diff changeset
611 target_parity = this->m_parent->get_parity ();
kono
parents:
diff changeset
612 cur_parity = this->get_parity ();
kono
parents:
diff changeset
613
kono
parents:
diff changeset
614 /* Rename if parity differs. */
kono
parents:
diff changeset
615 if (cur_parity != target_parity)
kono
parents:
diff changeset
616 {
kono
parents:
diff changeset
617 rtx_insn *insn = this->m_insn;
kono
parents:
diff changeset
618 HARD_REG_SET unavailable;
kono
parents:
diff changeset
619 machine_mode mode;
kono
parents:
diff changeset
620 int reg;
kono
parents:
diff changeset
621
kono
parents:
diff changeset
622 if (dump_file)
kono
parents:
diff changeset
623 {
kono
parents:
diff changeset
624 unsigned cur_dest_reg = this->m_head->regno;
kono
parents:
diff changeset
625
kono
parents:
diff changeset
626 fprintf (dump_file, "FMA or FMUL at insn %d but destination "
kono
parents:
diff changeset
627 "register (%s) has different parity from expected to "
kono
parents:
diff changeset
628 "maximize FPU pipeline utilization\n", INSN_UID (insn),
kono
parents:
diff changeset
629 reg_names[cur_dest_reg]);
kono
parents:
diff changeset
630 }
kono
parents:
diff changeset
631
kono
parents:
diff changeset
632 /* Don't clobber traceback for noreturn functions. */
kono
parents:
diff changeset
633 CLEAR_HARD_REG_SET (unavailable);
kono
parents:
diff changeset
634 if (frame_pointer_needed)
kono
parents:
diff changeset
635 {
kono
parents:
diff changeset
636 add_to_hard_reg_set (&unavailable, Pmode, FRAME_POINTER_REGNUM);
kono
parents:
diff changeset
637 add_to_hard_reg_set (&unavailable, Pmode, HARD_FRAME_POINTER_REGNUM);
kono
parents:
diff changeset
638 }
kono
parents:
diff changeset
639
kono
parents:
diff changeset
640 /* Exclude registers with wrong parity. */
kono
parents:
diff changeset
641 mode = GET_MODE (SET_DEST (PATTERN (insn)));
kono
parents:
diff changeset
642 for (reg = cur_parity; reg < FIRST_PSEUDO_REGISTER; reg += 2)
kono
parents:
diff changeset
643 add_to_hard_reg_set (&unavailable, mode, reg);
kono
parents:
diff changeset
644
kono
parents:
diff changeset
645 if (!rename_single_chain (this->m_head, &unavailable))
kono
parents:
diff changeset
646 {
kono
parents:
diff changeset
647 if (dump_file)
kono
parents:
diff changeset
648 fprintf (dump_file, "Destination register of insn %d could not be "
kono
parents:
diff changeset
649 "renamed. Dependent FMA insns will use this parity from "
kono
parents:
diff changeset
650 "there on.\n", INSN_UID (insn));
kono
parents:
diff changeset
651 }
kono
parents:
diff changeset
652 else
kono
parents:
diff changeset
653 cur_parity = target_parity;
kono
parents:
diff changeset
654 }
kono
parents:
diff changeset
655
kono
parents:
diff changeset
656 forest->get_globals ()->update_balance (cur_parity);
kono
parents:
diff changeset
657 }
kono
parents:
diff changeset
658
kono
parents:
diff changeset
659 /* Wrapper around fma_node::dump_info for use as parameter of function pointer
kono
parents:
diff changeset
660 type in func_fma_steering::dfs. */
kono
parents:
diff changeset
661
kono
parents:
diff changeset
662 static void
kono
parents:
diff changeset
663 rename_fma_node (fma_forest *forest, fma_node *node)
kono
parents:
diff changeset
664 {
kono
parents:
diff changeset
665 node->rename (forest);
kono
parents:
diff changeset
666 }
kono
parents:
diff changeset
667
kono
parents:
diff changeset
668 fma_root_node::fma_root_node (func_fma_steering *globals, du_chain *chain,
kono
parents:
diff changeset
669 int id) : fma_node (this, chain)
kono
parents:
diff changeset
670 {
kono
parents:
diff changeset
671 this->m_forest = new fma_forest (globals, this, id);
kono
parents:
diff changeset
672 this->m_forest->fma_node_created (this);
kono
parents:
diff changeset
673 }
kono
parents:
diff changeset
674
kono
parents:
diff changeset
675 fma_forest *
kono
parents:
diff changeset
676 fma_root_node::get_forest ()
kono
parents:
diff changeset
677 {
kono
parents:
diff changeset
678 return this->m_forest;
kono
parents:
diff changeset
679 }
kono
parents:
diff changeset
680
kono
parents:
diff changeset
681 void
kono
parents:
diff changeset
682 fma_root_node::set_forest (fma_forest *ref_forest)
kono
parents:
diff changeset
683 {
kono
parents:
diff changeset
684 this->m_forest = ref_forest;
kono
parents:
diff changeset
685 }
kono
parents:
diff changeset
686
kono
parents:
diff changeset
687 /* Dump information about the roots of forest FOREST. */
kono
parents:
diff changeset
688
kono
parents:
diff changeset
689 void
kono
parents:
diff changeset
690 fma_root_node::dump_info (fma_forest *forest)
kono
parents:
diff changeset
691 {
kono
parents:
diff changeset
692 gcc_assert (dump_file);
kono
parents:
diff changeset
693
kono
parents:
diff changeset
694 if (this == forest->get_roots ()->front ())
kono
parents:
diff changeset
695 fprintf (dump_file, "Instruction(s) at root of forest #%d:",
kono
parents:
diff changeset
696 forest->get_id ());
kono
parents:
diff changeset
697 fprintf (dump_file, " %d", INSN_UID (this->m_insn));
kono
parents:
diff changeset
698 if (this == forest->get_roots ()->back ())
kono
parents:
diff changeset
699 fprintf (dump_file, "\n");
kono
parents:
diff changeset
700 }
kono
parents:
diff changeset
701
kono
parents:
diff changeset
702 /* Wrapper around fma_root_node::dump_info for use as parameter of function
kono
parents:
diff changeset
703 pointer type in func_fma_steering::dfs. */
kono
parents:
diff changeset
704
kono
parents:
diff changeset
705 static void
kono
parents:
diff changeset
706 dump_tree_root_info (fma_forest *forest, fma_root_node *node)
kono
parents:
diff changeset
707 {
kono
parents:
diff changeset
708 node->dump_info (forest);
kono
parents:
diff changeset
709 }
kono
parents:
diff changeset
710
kono
parents:
diff changeset
711 func_fma_steering::func_fma_steering () : m_fpu_balance (0)
kono
parents:
diff changeset
712 {
kono
parents:
diff changeset
713 this->m_insn_fma_head_map = new hash_map<rtx_insn *, fma_node *>;
kono
parents:
diff changeset
714 this->m_fma_forests.clear ();
kono
parents:
diff changeset
715 this->m_next_forest_id = 0;
kono
parents:
diff changeset
716 }
kono
parents:
diff changeset
717
kono
parents:
diff changeset
718 func_fma_steering::~func_fma_steering ()
kono
parents:
diff changeset
719 {
kono
parents:
diff changeset
720 delete this->m_insn_fma_head_map;
kono
parents:
diff changeset
721 }
kono
parents:
diff changeset
722
kono
parents:
diff changeset
723 int
kono
parents:
diff changeset
724 func_fma_steering::get_fpu_balance ()
kono
parents:
diff changeset
725 {
kono
parents:
diff changeset
726 return this->m_fpu_balance;
kono
parents:
diff changeset
727 }
kono
parents:
diff changeset
728
kono
parents:
diff changeset
729 void
kono
parents:
diff changeset
730 func_fma_steering::remove_forest (fma_forest *forest)
kono
parents:
diff changeset
731 {
kono
parents:
diff changeset
732 this->m_fma_forests.remove (forest);
kono
parents:
diff changeset
733 }
kono
parents:
diff changeset
734
kono
parents:
diff changeset
735 /* Memorize the mapping of this instruction to its fma_node object and return
kono
parents:
diff changeset
736 whether such a mapping existed. */
kono
parents:
diff changeset
737
kono
parents:
diff changeset
738 bool
kono
parents:
diff changeset
739 func_fma_steering::put_node (fma_node *node)
kono
parents:
diff changeset
740 {
kono
parents:
diff changeset
741 return this->m_insn_fma_head_map->put (node->get_insn (), node);
kono
parents:
diff changeset
742 }
kono
parents:
diff changeset
743
kono
parents:
diff changeset
744 /* Update the current balance considering a node with the given PARITY. */
kono
parents:
diff changeset
745
kono
parents:
diff changeset
746 void
kono
parents:
diff changeset
747 func_fma_steering::update_balance (int parity)
kono
parents:
diff changeset
748 {
kono
parents:
diff changeset
749 this->m_fpu_balance = parity ? this->m_fpu_balance + 1
kono
parents:
diff changeset
750 : this->m_fpu_balance - 1;
kono
parents:
diff changeset
751 }
kono
parents:
diff changeset
752
kono
parents:
diff changeset
753 /* Return whether an fma_node object exists for instruction INSN and, if not,
kono
parents:
diff changeset
754 allocate one in *RET. */
kono
parents:
diff changeset
755
kono
parents:
diff changeset
756 fma_node *
kono
parents:
diff changeset
757 func_fma_steering::get_fma_node (rtx_insn *insn)
kono
parents:
diff changeset
758 {
kono
parents:
diff changeset
759 fma_node **fma_slot;
kono
parents:
diff changeset
760
kono
parents:
diff changeset
761 fma_slot = this->m_insn_fma_head_map->get (insn);
kono
parents:
diff changeset
762 if (fma_slot)
kono
parents:
diff changeset
763 return *fma_slot;
kono
parents:
diff changeset
764 return NULL;
kono
parents:
diff changeset
765 }
kono
parents:
diff changeset
766
kono
parents:
diff changeset
767 /* Allocate and initialize fma_node objects for the FMUL or FMADD/FMSUB
kono
parents:
diff changeset
768 instruction in CHAIN->insn and its dependent FMADD/FMSUB instructions, all
kono
parents:
diff changeset
769 part of FOREST. For the children, the associated head is left untouched
kono
parents:
diff changeset
770 (and thus null) as this function will be called again when considering the
kono
parents:
diff changeset
771 chain where they are def. For the parent, the chain is given in HEAD. */
kono
parents:
diff changeset
772
kono
parents:
diff changeset
773 void
kono
parents:
diff changeset
774 func_fma_steering::analyze_fma_fmul_insn (fma_forest *ref_forest,
kono
parents:
diff changeset
775 du_chain *chain, du_head_p head)
kono
parents:
diff changeset
776 {
kono
parents:
diff changeset
777 fma_forest *forest;
kono
parents:
diff changeset
778 fma_node *node = this->get_fma_node (chain->insn);
kono
parents:
diff changeset
779
kono
parents:
diff changeset
780 /* This is a root node. */
kono
parents:
diff changeset
781 if (!node)
kono
parents:
diff changeset
782 {
kono
parents:
diff changeset
783 fma_root_node *root_node;
kono
parents:
diff changeset
784
kono
parents:
diff changeset
785 root_node = new fma_root_node (this, chain, this->m_next_forest_id++);
kono
parents:
diff changeset
786 forest = root_node->get_forest ();
kono
parents:
diff changeset
787 node = root_node;
kono
parents:
diff changeset
788
kono
parents:
diff changeset
789 /* Until proved otherwise, assume this root is not part of an existing
kono
parents:
diff changeset
790 forest and thus add its forest to the list of forests. */
kono
parents:
diff changeset
791 this->m_fma_forests.push_back (forest);
kono
parents:
diff changeset
792 }
kono
parents:
diff changeset
793 else
kono
parents:
diff changeset
794 forest = node->get_forest ();
kono
parents:
diff changeset
795
kono
parents:
diff changeset
796 node->set_head (head);
kono
parents:
diff changeset
797
kono
parents:
diff changeset
798 /* fma_node is part of a chain with several defs, one of them having already
kono
parents:
diff changeset
799 been processed. The root of that already processed def is the canonical
kono
parents:
diff changeset
800 one and the root of fma_node is added to its forest. No need to process
kono
parents:
diff changeset
801 the children nodes as they were already processed when the other def was
kono
parents:
diff changeset
802 processed. */
kono
parents:
diff changeset
803 if (ref_forest)
kono
parents:
diff changeset
804 {
kono
parents:
diff changeset
805 ref_forest->merge_forest (forest);
kono
parents:
diff changeset
806 return;
kono
parents:
diff changeset
807 }
kono
parents:
diff changeset
808
kono
parents:
diff changeset
809 for (chain = head->first; chain; chain = chain->next_use)
kono
parents:
diff changeset
810 {
kono
parents:
diff changeset
811 fma_node *child_fma;
kono
parents:
diff changeset
812 rtx fma_rtx, *accum_rtx_p;
kono
parents:
diff changeset
813
kono
parents:
diff changeset
814 if (!is_fmul_fmac_insn (chain->insn, false))
kono
parents:
diff changeset
815 continue;
kono
parents:
diff changeset
816
kono
parents:
diff changeset
817 /* Get FMA rtx. */
kono
parents:
diff changeset
818 fma_rtx = SET_SRC (PATTERN (chain->insn));
kono
parents:
diff changeset
819 /* FMA is negated. */
kono
parents:
diff changeset
820 if (GET_CODE (fma_rtx) == NEG)
kono
parents:
diff changeset
821 fma_rtx = XEXP (fma_rtx, 0);
kono
parents:
diff changeset
822 /* Get accumulator rtx. */
kono
parents:
diff changeset
823 accum_rtx_p = &XEXP (fma_rtx, 2);
kono
parents:
diff changeset
824 /* Accumulator is negated. */
kono
parents:
diff changeset
825 if (!REG_P (*accum_rtx_p))
kono
parents:
diff changeset
826 accum_rtx_p = &XEXP (*accum_rtx_p, 0);
kono
parents:
diff changeset
827
kono
parents:
diff changeset
828 /* This du_chain structure is not for the accumulator register. */
kono
parents:
diff changeset
829 if (accum_rtx_p != chain->loc)
kono
parents:
diff changeset
830 continue;
kono
parents:
diff changeset
831
kono
parents:
diff changeset
832 /* If object already created, this is a loop carried dependency. We
kono
parents:
diff changeset
833 don't include this object in the children as we want trees for
kono
parents:
diff changeset
834 rename_fma_trees to not be an infinite loop. */
kono
parents:
diff changeset
835 if (this->get_fma_node (chain->insn))
kono
parents:
diff changeset
836 continue;
kono
parents:
diff changeset
837
kono
parents:
diff changeset
838 child_fma = new fma_node (node, chain);
kono
parents:
diff changeset
839
kono
parents:
diff changeset
840 /* Memorize the mapping of this instruction to its fma_node object
kono
parents:
diff changeset
841 as it will be processed for the chain starting at its destination
kono
parents:
diff changeset
842 register later. */
kono
parents:
diff changeset
843
kono
parents:
diff changeset
844 /* Link to siblings. */
kono
parents:
diff changeset
845 node->add_child (child_fma);
kono
parents:
diff changeset
846 }
kono
parents:
diff changeset
847 }
kono
parents:
diff changeset
848
kono
parents:
diff changeset
849 /* Perform a depth-first search of the forests of fma_node in
kono
parents:
diff changeset
850 THIS->m_fma_forests, calling PROCESS_FOREST () on each fma_forest object in
kono
parents:
diff changeset
851 THIS->m_fma_forests list, PROCESS_ROOT () on each tree root and
kono
parents:
diff changeset
852 PROCESS_NODE () on each node. If FREE is true, free all std::list in the
kono
parents:
diff changeset
853 same dfs. */
kono
parents:
diff changeset
854
kono
parents:
diff changeset
855 void
kono
parents:
diff changeset
856 func_fma_steering::dfs (void (*process_forest) (fma_forest *),
kono
parents:
diff changeset
857 void (*process_root) (fma_forest *, fma_root_node *),
kono
parents:
diff changeset
858 void (*process_node) (fma_forest *, fma_node *),
kono
parents:
diff changeset
859 bool free)
kono
parents:
diff changeset
860 {
131
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
861 auto_vec<fma_node *> to_process;
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
862 auto_vec<fma_node *> to_free;
111
kono
parents:
diff changeset
863 std::list<fma_forest *>::iterator forest_iter;
kono
parents:
diff changeset
864
kono
parents:
diff changeset
865 /* For each forest. */
kono
parents:
diff changeset
866 for (forest_iter = this->m_fma_forests.begin ();
131
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
867 forest_iter != this->m_fma_forests.end (); ++forest_iter)
111
kono
parents:
diff changeset
868 {
kono
parents:
diff changeset
869 std::list<fma_root_node *>::iterator root_iter;
kono
parents:
diff changeset
870
kono
parents:
diff changeset
871 if (process_forest)
kono
parents:
diff changeset
872 process_forest (*forest_iter);
kono
parents:
diff changeset
873
kono
parents:
diff changeset
874 /* For each tree root in this forest. */
kono
parents:
diff changeset
875 for (root_iter = (*forest_iter)->get_roots ()->begin ();
131
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
876 root_iter != (*forest_iter)->get_roots ()->end (); ++root_iter)
111
kono
parents:
diff changeset
877 {
kono
parents:
diff changeset
878 if (process_root)
kono
parents:
diff changeset
879 process_root (*forest_iter, *root_iter);
kono
parents:
diff changeset
880 to_process.safe_push (*root_iter);
kono
parents:
diff changeset
881 }
kono
parents:
diff changeset
882
kono
parents:
diff changeset
883 /* For each tree node in this forest. */
kono
parents:
diff changeset
884 while (!to_process.is_empty ())
kono
parents:
diff changeset
885 {
kono
parents:
diff changeset
886 fma_node *node;
kono
parents:
diff changeset
887 std::list<fma_node *>::iterator child_iter;
kono
parents:
diff changeset
888
kono
parents:
diff changeset
889 node = to_process.pop ();
kono
parents:
diff changeset
890
kono
parents:
diff changeset
891 if (process_node)
kono
parents:
diff changeset
892 process_node (*forest_iter, node);
kono
parents:
diff changeset
893
131
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
894 for (child_iter = node->get_children ()->begin ();
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
895 child_iter != node->get_children ()->end (); ++child_iter)
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
896 to_process.safe_push (*child_iter);
111
kono
parents:
diff changeset
897
131
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
898 /* Defer freeing so that the process_node callback can access the
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
899 parent and children of the node being processed. */
111
kono
parents:
diff changeset
900 if (free)
131
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
901 to_free.safe_push (node);
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
902 }
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
903
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
904 if (free)
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
905 {
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
906 delete *forest_iter;
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
907
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
908 while (!to_free.is_empty ())
111
kono
parents:
diff changeset
909 {
131
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
910 fma_node *node = to_free.pop ();
111
kono
parents:
diff changeset
911 if (node->root_p ())
kono
parents:
diff changeset
912 delete static_cast<fma_root_node *> (node);
kono
parents:
diff changeset
913 else
kono
parents:
diff changeset
914 delete node;
kono
parents:
diff changeset
915 }
kono
parents:
diff changeset
916 }
kono
parents:
diff changeset
917 }
kono
parents:
diff changeset
918 }
kono
parents:
diff changeset
919
kono
parents:
diff changeset
920 /* Build the dependency trees of FMUL and FMADD/FMSUB instructions. */
kono
parents:
diff changeset
921
kono
parents:
diff changeset
922 void
kono
parents:
diff changeset
923 func_fma_steering::analyze ()
kono
parents:
diff changeset
924 {
kono
parents:
diff changeset
925 int i, n_blocks, *bb_dfs_preorder;
kono
parents:
diff changeset
926 basic_block bb;
kono
parents:
diff changeset
927 rtx_insn *insn;
kono
parents:
diff changeset
928
kono
parents:
diff changeset
929 bb_dfs_preorder = XNEWVEC (int, last_basic_block_for_fn (cfun));
kono
parents:
diff changeset
930 n_blocks = pre_and_rev_post_order_compute (bb_dfs_preorder, NULL, false);
kono
parents:
diff changeset
931
kono
parents:
diff changeset
932 /* Browse the graph of basic blocks looking for FMUL or FMADD/FMSUB
kono
parents:
diff changeset
933 instructions. */
kono
parents:
diff changeset
934 for (i = 0; i < n_blocks; i++)
kono
parents:
diff changeset
935 {
kono
parents:
diff changeset
936 bb = BASIC_BLOCK_FOR_FN (cfun, bb_dfs_preorder[i]);
kono
parents:
diff changeset
937 FOR_BB_INSNS (bb, insn)
kono
parents:
diff changeset
938 {
kono
parents:
diff changeset
939 operand_rr_info *dest_op_info;
kono
parents:
diff changeset
940 struct du_chain *chain = NULL;
kono
parents:
diff changeset
941 unsigned dest_regno;
kono
parents:
diff changeset
942 fma_forest *forest = NULL;
kono
parents:
diff changeset
943 du_head_p head = NULL;
kono
parents:
diff changeset
944 int i;
kono
parents:
diff changeset
945
kono
parents:
diff changeset
946 if (!is_fmul_fmac_insn (insn, true))
kono
parents:
diff changeset
947 continue;
kono
parents:
diff changeset
948
kono
parents:
diff changeset
949 /* Search the chain where this instruction is (one of) the root. */
kono
parents:
diff changeset
950 dest_op_info = insn_rr[INSN_UID (insn)].op_info;
kono
parents:
diff changeset
951 dest_regno = REGNO (SET_DEST (PATTERN (insn)));
kono
parents:
diff changeset
952 for (i = 0; i < dest_op_info->n_chains; i++)
kono
parents:
diff changeset
953 {
kono
parents:
diff changeset
954 /* The register tracked by this chain does not match the
kono
parents:
diff changeset
955 destination register of insn. */
kono
parents:
diff changeset
956 if (dest_op_info->heads[i]->regno != dest_regno)
kono
parents:
diff changeset
957 continue;
kono
parents:
diff changeset
958
kono
parents:
diff changeset
959 head = dest_op_info->heads[i];
kono
parents:
diff changeset
960 /* The chain was merged in another, find the new head. */
kono
parents:
diff changeset
961 if (!head->first)
kono
parents:
diff changeset
962 head = regrename_chain_from_id (head->id);
kono
parents:
diff changeset
963
kono
parents:
diff changeset
964 /* Search the chain element for this instruction and, if another
kono
parents:
diff changeset
965 FMUL or FMADD/FMSUB instruction was already processed, note
kono
parents:
diff changeset
966 the forest of its tree. */
kono
parents:
diff changeset
967 forest = NULL;
kono
parents:
diff changeset
968 for (chain = head->first; chain; chain = chain->next_use)
kono
parents:
diff changeset
969 {
kono
parents:
diff changeset
970 fma_node **fma_slot;
kono
parents:
diff changeset
971
kono
parents:
diff changeset
972 if (!is_fmul_fmac_insn (chain->insn, true))
kono
parents:
diff changeset
973 continue;
kono
parents:
diff changeset
974
kono
parents:
diff changeset
975 /* This is a use, continue. */
kono
parents:
diff changeset
976 if (chain->loc != &SET_DEST (PATTERN (chain->insn)))
kono
parents:
diff changeset
977 continue;
kono
parents:
diff changeset
978
kono
parents:
diff changeset
979 if (chain->insn == insn)
kono
parents:
diff changeset
980 break;
kono
parents:
diff changeset
981
kono
parents:
diff changeset
982 fma_slot = this->m_insn_fma_head_map->get (chain->insn);
kono
parents:
diff changeset
983 if (fma_slot && (*fma_slot)->get_children ())
kono
parents:
diff changeset
984 forest = (*fma_slot)->get_forest ();
kono
parents:
diff changeset
985 }
kono
parents:
diff changeset
986 if (chain)
kono
parents:
diff changeset
987 break;
kono
parents:
diff changeset
988 }
kono
parents:
diff changeset
989
kono
parents:
diff changeset
990 /* Due to implementation of regrename, dest register can slip away
kono
parents:
diff changeset
991 from regrename's analysis. As a result, there is no chain for
kono
parents:
diff changeset
992 the destination register of insn. We simply skip the insn even
kono
parents:
diff changeset
993 it is a fmul/fmac instruction. This can happen when the dest
kono
parents:
diff changeset
994 register is also a source register of insn and one of the below
kono
parents:
diff changeset
995 conditions is satisfied:
kono
parents:
diff changeset
996 1) the source reg is setup in larger mode than this insn;
kono
parents:
diff changeset
997 2) the source reg is uninitialized;
kono
parents:
diff changeset
998 3) the source reg is passed in as parameter. */
kono
parents:
diff changeset
999 if (i < dest_op_info->n_chains)
kono
parents:
diff changeset
1000 this->analyze_fma_fmul_insn (forest, chain, head);
kono
parents:
diff changeset
1001 }
kono
parents:
diff changeset
1002 }
kono
parents:
diff changeset
1003 free (bb_dfs_preorder);
kono
parents:
diff changeset
1004
kono
parents:
diff changeset
1005 if (dump_file)
kono
parents:
diff changeset
1006 this->dfs (dump_forest_info, dump_tree_root_info, dump_tree_node_info,
kono
parents:
diff changeset
1007 false);
kono
parents:
diff changeset
1008 }
kono
parents:
diff changeset
1009
kono
parents:
diff changeset
1010 /* Perform the renaming of all chains with FMUL or FMADD/FMSUB involved with
kono
parents:
diff changeset
1011 the objective of keeping FPU pipeline balanced in term of instructions and
kono
parents:
diff changeset
1012 having FMADD/FMSUB with dependencies on previous FMUL or FMADD/FMSUB be
kono
parents:
diff changeset
1013 scheduled on the same pipeline. */
kono
parents:
diff changeset
1014
kono
parents:
diff changeset
1015 void
kono
parents:
diff changeset
1016 func_fma_steering::rename_fma_trees ()
kono
parents:
diff changeset
1017 {
kono
parents:
diff changeset
1018 this->dfs (dispatch_forest, NULL, rename_fma_node, true);
kono
parents:
diff changeset
1019
kono
parents:
diff changeset
1020 if (dump_file && !this->m_fma_forests.empty ())
kono
parents:
diff changeset
1021 {
kono
parents:
diff changeset
1022 fprintf (dump_file, "Function %s has ", current_function_name ());
kono
parents:
diff changeset
1023 if (this->m_fpu_balance == 0)
kono
parents:
diff changeset
1024 fprintf (dump_file, "perfect balance of FMUL/FMA chains between the "
kono
parents:
diff changeset
1025 "two FPU pipelines\n");
kono
parents:
diff changeset
1026 else if (this->m_fpu_balance > 0)
kono
parents:
diff changeset
1027 fprintf (dump_file, "%d more FMUL/FMA chains scheduled on the second "
kono
parents:
diff changeset
1028 "FPU pipeline\n", this->m_fpu_balance);
kono
parents:
diff changeset
1029 else /* this->m_fpu_balance < 0 */
kono
parents:
diff changeset
1030 fprintf (dump_file, "%d more FMUL/FMA chains scheduled on the first "
kono
parents:
diff changeset
1031 "FPU pipeline\n", - this->m_fpu_balance);
kono
parents:
diff changeset
1032 }
kono
parents:
diff changeset
1033 }
kono
parents:
diff changeset
1034
kono
parents:
diff changeset
1035 /* Execute FMA steering pass. */
kono
parents:
diff changeset
1036
kono
parents:
diff changeset
1037 void
kono
parents:
diff changeset
1038 func_fma_steering::execute_fma_steering ()
kono
parents:
diff changeset
1039 {
kono
parents:
diff changeset
1040 df_set_flags (DF_LR_RUN_DCE);
kono
parents:
diff changeset
1041 df_note_add_problem ();
kono
parents:
diff changeset
1042 df_analyze ();
kono
parents:
diff changeset
1043 df_set_flags (DF_DEFER_INSN_RESCAN);
kono
parents:
diff changeset
1044
kono
parents:
diff changeset
1045 regrename_init (true);
kono
parents:
diff changeset
1046 regrename_analyze (NULL);
kono
parents:
diff changeset
1047 this->analyze ();
kono
parents:
diff changeset
1048 this->rename_fma_trees ();
kono
parents:
diff changeset
1049 regrename_finish ();
kono
parents:
diff changeset
1050 }
kono
parents:
diff changeset
1051
kono
parents:
diff changeset
1052 const pass_data pass_data_fma_steering =
kono
parents:
diff changeset
1053 {
kono
parents:
diff changeset
1054 RTL_PASS, /* type */
kono
parents:
diff changeset
1055 "fma_steering", /* name */
kono
parents:
diff changeset
1056 OPTGROUP_NONE, /* optinfo_flags */
kono
parents:
diff changeset
1057 TV_NONE, /* tv_id */
kono
parents:
diff changeset
1058 0, /* properties_required */
kono
parents:
diff changeset
1059 0, /* properties_provided */
kono
parents:
diff changeset
1060 0, /* properties_destroyed */
kono
parents:
diff changeset
1061 0, /* todo_flags_start */
kono
parents:
diff changeset
1062 TODO_df_finish, /* todo_flags_finish */
kono
parents:
diff changeset
1063 };
kono
parents:
diff changeset
1064
kono
parents:
diff changeset
1065 class pass_fma_steering : public rtl_opt_pass
kono
parents:
diff changeset
1066 {
kono
parents:
diff changeset
1067 public:
kono
parents:
diff changeset
1068 pass_fma_steering (gcc::context *ctxt)
kono
parents:
diff changeset
1069 : rtl_opt_pass (pass_data_fma_steering, ctxt)
kono
parents:
diff changeset
1070 {}
kono
parents:
diff changeset
1071
kono
parents:
diff changeset
1072 /* opt_pass methods: */
kono
parents:
diff changeset
1073 virtual bool gate (function *)
kono
parents:
diff changeset
1074 {
kono
parents:
diff changeset
1075 return (aarch64_tune_params.extra_tuning_flags
kono
parents:
diff changeset
1076 & AARCH64_EXTRA_TUNE_RENAME_FMA_REGS)
kono
parents:
diff changeset
1077 && optimize >= 2;
kono
parents:
diff changeset
1078 }
kono
parents:
diff changeset
1079
kono
parents:
diff changeset
1080 virtual unsigned int execute (function *)
kono
parents:
diff changeset
1081 {
kono
parents:
diff changeset
1082 func_fma_steering *fma_steering = new func_fma_steering;
kono
parents:
diff changeset
1083 fma_steering->execute_fma_steering ();
kono
parents:
diff changeset
1084 delete fma_steering;
kono
parents:
diff changeset
1085 return 0;
kono
parents:
diff changeset
1086 }
kono
parents:
diff changeset
1087
kono
parents:
diff changeset
1088 }; // class pass_fma_steering
kono
parents:
diff changeset
1089
kono
parents:
diff changeset
1090 /* Create a new fma steering pass instance. */
kono
parents:
diff changeset
1091
kono
parents:
diff changeset
1092 rtl_opt_pass *
kono
parents:
diff changeset
1093 make_pass_fma_steering (gcc::context *ctxt)
kono
parents:
diff changeset
1094 {
kono
parents:
diff changeset
1095 return new pass_fma_steering (ctxt);
kono
parents:
diff changeset
1096 }