annotate gcc/config/aarch64/cortex-a57-fma-steering.c @ 131:84e7813d76e9

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