Branch data Line data Source code
1 : : /* Schedule GIMPLE vector statements.
2 : : Copyright (C) 2020-2024 Free Software Foundation, Inc.
3 : :
4 : : This file is part of GCC.
5 : :
6 : : GCC is free software; you can redistribute it and/or modify it
7 : : under the terms of the GNU General Public License as published by the
8 : : Free Software Foundation; either version 3, or (at your option) any
9 : : later version.
10 : :
11 : : GCC is distributed in the hope that it will be useful, but WITHOUT
12 : : ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 : : FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 : : for more details.
15 : :
16 : : You should have received a copy of the GNU General Public License
17 : : along with GCC; see the file COPYING3. If not see
18 : : <http://www.gnu.org/licenses/>. */
19 : :
20 : : #include "config.h"
21 : : #include "system.h"
22 : : #include "coretypes.h"
23 : : #include "backend.h"
24 : : #include "rtl.h"
25 : : #include "tree.h"
26 : : #include "gimple.h"
27 : : #include "tree-pass.h"
28 : : #include "ssa.h"
29 : : #include "expmed.h"
30 : : #include "optabs-tree.h"
31 : : #include "tree-eh.h"
32 : : #include "gimple-iterator.h"
33 : : #include "gimplify-me.h"
34 : : #include "gimplify.h"
35 : : #include "tree-cfg.h"
36 : : #include "bitmap.h"
37 : : #include "tree-ssa-dce.h"
38 : : #include "memmodel.h"
39 : : #include "optabs.h"
40 : : #include "gimple-fold.h"
41 : : #include "internal-fn.h"
42 : :
43 : : /* Expand all ARRAY_REF(VIEW_CONVERT_EXPR) gimple assignments into calls to
44 : : internal function based on vector type of selected expansion.
45 : :
46 : : For vec_set:
47 : :
48 : : VIEW_CONVERT_EXPR<int[4]>(u)[_1] = i_4(D);
49 : : =>
50 : : _7 = u;
51 : : _8 = .VEC_SET (_7, i_4(D), _1);
52 : : u = _8;
53 : :
54 : : For vec_extract:
55 : :
56 : : _3 = VIEW_CONVERT_EXPR<intD.1[4]>(vD.2208)[idx_2(D)];
57 : : =>
58 : : _4 = vD.2208;
59 : : _3 = .VEC_EXTRACT (_4, idx_2(D)); */
60 : :
61 : : static bool
62 : 84670027 : gimple_expand_vec_set_extract_expr (struct function *fun,
63 : : gimple_stmt_iterator *gsi)
64 : : {
65 : 84670027 : gcall *new_stmt = NULL;
66 : 84670027 : gassign *ass_stmt = NULL;
67 : 84670027 : bool cfg_changed = false;
68 : :
69 : : /* Only consider code == GIMPLE_ASSIGN. */
70 : 114775457 : gassign *stmt = dyn_cast<gassign *> (gsi_stmt (*gsi));
71 : 30105552 : if (!stmt)
72 : : return false;
73 : :
74 : 30105552 : bool is_extract = false;
75 : :
76 : 30105552 : tree lhs = gimple_assign_lhs (stmt);
77 : 30105552 : tree rhs = gimple_assign_rhs1 (stmt);
78 : 30105552 : tree val, ref;
79 : 30105552 : if (TREE_CODE (lhs) == ARRAY_REF)
80 : : {
81 : : /* Assume it is a vec_set. */
82 : : val = rhs;
83 : : ref = lhs;
84 : : }
85 : 29557282 : else if (TREE_CODE (rhs) == ARRAY_REF)
86 : : {
87 : : /* vec_extract. */
88 : : is_extract = true;
89 : : val = lhs;
90 : : ref = rhs;
91 : : }
92 : : else
93 : : return false;
94 : :
95 : 1086619 : tree op0 = TREE_OPERAND (ref, 0);
96 : 30543 : if (TREE_CODE (op0) == VIEW_CONVERT_EXPR && DECL_P (TREE_OPERAND (op0, 0))
97 : 26262 : && VECTOR_TYPE_P (TREE_TYPE (TREE_OPERAND (op0, 0)))
98 : 1106403 : && TYPE_MODE (TREE_TYPE (ref))
99 : 9892 : == TYPE_MODE (TREE_TYPE (TREE_TYPE (TREE_OPERAND (op0, 0)))))
100 : : {
101 : 9888 : tree pos = TREE_OPERAND (ref, 1);
102 : :
103 : 9888 : tree view_op0 = TREE_OPERAND (op0, 0);
104 : 9888 : machine_mode outermode = TYPE_MODE (TREE_TYPE (view_op0));
105 : 9888 : machine_mode extract_mode = TYPE_MODE (TREE_TYPE (ref));
106 : :
107 : 9888 : if ((auto_var_in_fn_p (view_op0, fun->decl)
108 : 1289 : || (VAR_P (view_op0) && DECL_HARD_REGISTER (view_op0)))
109 : 8609 : && !TREE_ADDRESSABLE (view_op0)
110 : 16764 : && ((!is_extract && can_vec_set_var_idx_p (outermode))
111 : : || (is_extract
112 : 6737 : && can_vec_extract_var_idx_p (outermode, extract_mode))))
113 : : {
114 : 122 : location_t loc = gimple_location (stmt);
115 : 122 : tree var_src = make_ssa_name (TREE_TYPE (view_op0));
116 : :
117 : 122 : ass_stmt = gimple_build_assign (var_src, view_op0);
118 : 244 : gimple_set_vuse (ass_stmt, gimple_vuse (stmt));
119 : 122 : gimple_set_location (ass_stmt, loc);
120 : 122 : gsi_insert_before (gsi, ass_stmt, GSI_SAME_STMT);
121 : :
122 : 122 : if (!is_extract)
123 : : {
124 : 122 : tree var_dst = make_ssa_name (TREE_TYPE (view_op0));
125 : :
126 : 122 : new_stmt = gimple_build_call_internal (IFN_VEC_SET, 3, var_src,
127 : : val, pos);
128 : :
129 : 122 : gimple_call_set_lhs (new_stmt, var_dst);
130 : 122 : gimple_set_location (new_stmt, loc);
131 : 122 : gsi_insert_before (gsi, new_stmt, GSI_SAME_STMT);
132 : :
133 : 122 : ass_stmt = gimple_build_assign (view_op0, var_dst);
134 : 122 : gimple_set_location (ass_stmt, loc);
135 : 122 : gimple_move_vops (ass_stmt, stmt);
136 : 122 : gsi_insert_before (gsi, ass_stmt, GSI_SAME_STMT);
137 : :
138 : 122 : basic_block bb = gimple_bb (stmt);
139 : 122 : if (gsi_remove (gsi, true)
140 : 122 : && gimple_purge_dead_eh_edges (bb))
141 : : cfg_changed = true;
142 : 122 : *gsi = gsi_for_stmt (ass_stmt);
143 : : }
144 : : else
145 : : {
146 : 0 : new_stmt
147 : 0 : = gimple_build_call_internal (IFN_VEC_EXTRACT, 2, var_src, pos);
148 : 0 : gimple_call_set_lhs (new_stmt, lhs);
149 : :
150 : 0 : gsi_replace (gsi, new_stmt, true);
151 : 0 : cfg_changed = true;
152 : : }
153 : : }
154 : : }
155 : :
156 : : return cfg_changed;
157 : : }
158 : :
159 : : /* Expand all VEC_COND_EXPR gimple assignments into calls to internal
160 : : function based on type of selected expansion. */
161 : :
162 : : static gimple *
163 : 84670027 : gimple_expand_vec_cond_expr (gimple_stmt_iterator *gsi)
164 : : {
165 : 84670027 : tree lhs, op0a = NULL_TREE;
166 : 84670027 : enum tree_code code;
167 : 84670027 : enum tree_code tcode;
168 : :
169 : : /* Only consider code == GIMPLE_ASSIGN. */
170 : 84670027 : gassign *stmt = dyn_cast<gassign *> (gsi_stmt (*gsi));
171 : 30111901 : if (!stmt)
172 : : return NULL;
173 : :
174 : 30111901 : code = gimple_assign_rhs_code (stmt);
175 : 30111901 : if (code != VEC_COND_EXPR)
176 : : return NULL;
177 : :
178 : 16139 : tree op0 = gimple_assign_rhs1 (stmt);
179 : 16139 : tree op1 = gimple_assign_rhs2 (stmt);
180 : 16139 : tree op2 = gimple_assign_rhs3 (stmt);
181 : 16139 : lhs = gimple_assign_lhs (stmt);
182 : 16139 : machine_mode mode = TYPE_MODE (TREE_TYPE (lhs));
183 : :
184 : : /* Lower mask typed, non-vector mode VEC_COND_EXPRs to bitwise operations.
185 : : Those can end up generated by folding and at least for integer mode masks
186 : : we cannot expect vcond expanders to exist. We lower a ? b : c
187 : : to (b & a) | (c & ~a). */
188 : 32278 : if (VECTOR_BOOLEAN_TYPE_P (TREE_TYPE (lhs))
189 : 16140 : && !VECTOR_MODE_P (mode))
190 : : {
191 : 0 : gcc_assert (types_compatible_p (TREE_TYPE (op0), TREE_TYPE (op1)));
192 : 0 : gimple_seq stmts = NULL;
193 : 0 : tree type = TREE_TYPE (lhs);
194 : 0 : location_t loc = gimple_location (stmt);
195 : 0 : tree tem0 = gimple_build (&stmts, loc, BIT_AND_EXPR, type, op1, op0);
196 : 0 : tree tem1 = gimple_build (&stmts, loc, BIT_NOT_EXPR, type, op0);
197 : 0 : tree tem2 = gimple_build (&stmts, loc, BIT_AND_EXPR, type, op2, tem1);
198 : 0 : tree tem3 = gimple_build (&stmts, loc, BIT_IOR_EXPR, type, tem0, tem2);
199 : 0 : gsi_insert_seq_before (gsi, stmts, GSI_SAME_STMT);
200 : 0 : return gimple_build_assign (lhs, tem3);
201 : : }
202 : :
203 : 16139 : bool can_compute_op0 = true;
204 : 16139 : gcc_assert (!COMPARISON_CLASS_P (op0));
205 : 16139 : if (TREE_CODE (op0) == SSA_NAME)
206 : : {
207 : 16106 : gassign *def_stmt = dyn_cast<gassign *> (SSA_NAME_DEF_STMT (op0));
208 : 16098 : if (def_stmt)
209 : : {
210 : 16098 : tcode = gimple_assign_rhs_code (def_stmt);
211 : 16098 : op0a = gimple_assign_rhs1 (def_stmt);
212 : :
213 : 16098 : tree op0_type = TREE_TYPE (op0);
214 : 16098 : tree op0a_type = TREE_TYPE (op0a);
215 : 16098 : if (TREE_CODE_CLASS (tcode) == tcc_comparison)
216 : 13100 : can_compute_op0 = expand_vec_cmp_expr_p (op0a_type, op0_type,
217 : : tcode);
218 : 13100 : gcc_assert (can_compute_op0);
219 : :
220 : 16098 : if (can_compute_op0
221 : 16098 : && TYPE_MODE (TREE_TYPE (lhs)) == TYPE_MODE (TREE_TYPE (op0)))
222 : : {
223 : : /* Assuming c = x CMP y. */
224 : 12135 : bool op1_minus_onep = integer_minus_onep (op1);
225 : 12135 : bool op2_zerop = integer_zerop (op2);
226 : 12135 : tree vtype = TREE_TYPE (lhs);
227 : 12135 : machine_mode vmode = TYPE_MODE (vtype);
228 : : /* Try to fold r = c ? -1 : 0 to r = c. */
229 : 12135 : if (op1_minus_onep && op2_zerop)
230 : : {
231 : 3095 : tree conv_op = build1 (VIEW_CONVERT_EXPR, vtype, op0);
232 : 3095 : return gimple_build_assign (lhs, conv_op);
233 : : }
234 : : /* Try to fold r = c ? -1 : z to r = c | z, or
235 : : r = c ? c : z. */
236 : 9040 : if (op1_minus_onep)
237 : : {
238 : 10 : tree conv_op = build1 (VIEW_CONVERT_EXPR, vtype, op0);
239 : 10 : tree new_op1 = make_ssa_name (vtype);
240 : 10 : gassign *new_stmt = gimple_build_assign (new_op1, conv_op);
241 : 10 : gsi_insert_seq_before (gsi, new_stmt, GSI_SAME_STMT);
242 : 10 : if (optab_handler (ior_optab, vmode) != CODE_FOR_nothing)
243 : : /* r = c | z */
244 : 10 : return gimple_build_assign (lhs, BIT_IOR_EXPR, new_op1,
245 : 10 : op2);
246 : : /* r = c ? c : z */
247 : : op1 = new_op1;
248 : : }
249 : : /* Try to fold r = c ? z : 0 to r = c & z, or
250 : : r = c ? z : c. */
251 : 9030 : else if (op2_zerop)
252 : : {
253 : 6685 : tree conv_op = build1 (VIEW_CONVERT_EXPR, vtype, op0);
254 : 6685 : tree new_op2 = make_ssa_name (vtype);
255 : 6685 : gassign *new_stmt = gimple_build_assign (new_op2, conv_op);
256 : 6685 : gsi_insert_seq_before (gsi, new_stmt, GSI_SAME_STMT);
257 : 6685 : if (optab_handler (and_optab, vmode) != CODE_FOR_nothing)
258 : : /* r = c | z */
259 : 6685 : return gimple_build_assign (lhs, BIT_AND_EXPR, new_op2,
260 : 6685 : op1);
261 : : /* r = c ? z : c */
262 : : op2 = new_op2;
263 : : }
264 : 2345 : bool op1_zerop = integer_zerop (op1);
265 : 2345 : bool op2_minus_onep = integer_minus_onep (op2);
266 : : /* Try to fold r = c ? 0 : z to r = .BIT_ANDN (z, c). */
267 : 2345 : if (op1_zerop
268 : 2345 : && (direct_internal_fn_supported_p (IFN_BIT_ANDN, vtype,
269 : : OPTIMIZE_FOR_BOTH)))
270 : : {
271 : 93 : tree conv_op = build1 (VIEW_CONVERT_EXPR, vtype, op0);
272 : 93 : tree new_op = make_ssa_name (vtype);
273 : 93 : gassign *new_stmt = gimple_build_assign (new_op, conv_op);
274 : 93 : gsi_insert_seq_before (gsi, new_stmt, GSI_SAME_STMT);
275 : 93 : return gimple_build_call_internal (IFN_BIT_ANDN, 2, op2,
276 : 93 : new_op);
277 : : }
278 : : /* Try to fold r = c ? z : -1 to r = .BIT_IORN (z, c). */
279 : 2252 : else if (op2_minus_onep
280 : 2252 : && (direct_internal_fn_supported_p (IFN_BIT_IORN, vtype,
281 : : OPTIMIZE_FOR_BOTH)))
282 : : {
283 : 0 : tree conv_op = build1 (VIEW_CONVERT_EXPR, vtype, op0);
284 : 0 : tree new_op = make_ssa_name (vtype);
285 : 0 : gassign *new_stmt = gimple_build_assign (new_op, conv_op);
286 : 0 : gsi_insert_seq_before (gsi, new_stmt, GSI_SAME_STMT);
287 : 0 : return gimple_build_call_internal (IFN_BIT_IORN, 2, op1,
288 : 0 : new_op);
289 : : }
290 : : }
291 : : }
292 : : }
293 : :
294 : 6256 : gcc_assert (VECTOR_BOOLEAN_TYPE_P (TREE_TYPE (op0)));
295 : 12512 : gcc_assert (get_vcond_mask_icode (mode, TYPE_MODE (TREE_TYPE (op0)))
296 : : != CODE_FOR_nothing);
297 : 6256 : return gimple_build_call_internal (IFN_VCOND_MASK, 3, op0, op1, op2);
298 : : }
299 : :
300 : : /* Duplicate COND_EXPR condition defs of STMT located in BB when they are
301 : : comparisons so RTL expansion with the help of TER
302 : : can perform better if conversion. */
303 : : static void
304 : 520730 : maybe_duplicate_comparison (gassign *stmt, basic_block bb)
305 : : {
306 : 520730 : imm_use_iterator imm_iter;
307 : 520730 : use_operand_p use_p;
308 : 520730 : auto_vec<gassign *, 4> cond_exprs;
309 : 520730 : tree lhs = gimple_assign_lhs (stmt);
310 : 520730 : unsigned cnt = 0;
311 : :
312 : : /* This is should not be used for -O0 nor it is not useful
313 : : when ter is turned off. */
314 : 520730 : if (!optimize || !flag_tree_ter)
315 : : return;
316 : :
317 : 841039 : FOR_EACH_IMM_USE_FAST (use_p, imm_iter, lhs)
318 : : {
319 : 432357 : if (is_gimple_debug (USE_STMT (use_p)))
320 : 10255 : continue;
321 : 422102 : cnt++;
322 : : /* Add the use statement if it was a cond_expr. */
323 : 422102 : if (gimple_bb (USE_STMT (use_p)) == bb
324 : 379796 : && is_gimple_assign (USE_STMT (use_p))
325 : 361964 : && gimple_assign_rhs_code (USE_STMT (use_p)) == COND_EXPR
326 : 436758 : && gimple_assign_rhs1_ptr (USE_STMT (use_p)) == use_p->use)
327 : 14264 : cond_exprs.safe_push (as_a <gassign *> (USE_STMT (use_p)));
328 : : }
329 : :
330 : : /* If the comparison has 0 or 1 uses, no reason to do anything. */
331 : 408682 : if (cnt <= 1)
332 : : return;
333 : :
334 : : /* If we only use the expression inside cond_exprs in that BB, we don't
335 : : need to duplicate for one of them so pop the top. */
336 : 19612 : if (cond_exprs.length () == cnt)
337 : 127 : cond_exprs.pop();
338 : :
339 : 19976 : while (!cond_exprs.is_empty())
340 : : {
341 : 364 : auto old_top = cond_exprs.pop();
342 : 364 : gassign *copy = as_a <gassign *> (gimple_copy (stmt));
343 : 364 : tree new_def = duplicate_ssa_name (lhs, copy);
344 : 364 : gimple_assign_set_lhs (copy, new_def);
345 : 364 : auto gsi2 = gsi_for_stmt (old_top);
346 : 364 : gsi_insert_before (&gsi2, copy, GSI_SAME_STMT);
347 : 364 : gimple_assign_set_rhs1 (old_top, new_def);
348 : 364 : update_stmt (old_top);
349 : : }
350 : 520730 : }
351 : :
352 : :
353 : : namespace {
354 : :
355 : : const pass_data pass_data_gimple_isel =
356 : : {
357 : : GIMPLE_PASS, /* type */
358 : : "isel", /* name */
359 : : OPTGROUP_VEC, /* optinfo_flags */
360 : : TV_NONE, /* tv_id */
361 : : PROP_cfg, /* properties_required */
362 : : 0, /* properties_provided */
363 : : 0, /* properties_destroyed */
364 : : 0, /* todo_flags_start */
365 : : TODO_update_ssa, /* todo_flags_finish */
366 : : };
367 : :
368 : : class pass_gimple_isel : public gimple_opt_pass
369 : : {
370 : : public:
371 : 280114 : pass_gimple_isel (gcc::context *ctxt)
372 : 560228 : : gimple_opt_pass (pass_data_gimple_isel, ctxt)
373 : : {}
374 : :
375 : : /* opt_pass methods: */
376 : 1416251 : bool gate (function *) final override
377 : : {
378 : 1416251 : return true;
379 : : }
380 : :
381 : : unsigned int execute (function *fun) final override;
382 : : }; // class pass_gimple_isel
383 : :
384 : :
385 : : /* Iterate all gimple statements and perform pre RTL expansion
386 : : GIMPLE massaging to improve instruction selection. */
387 : :
388 : : unsigned int
389 : 1416246 : pass_gimple_isel::execute (struct function *fun)
390 : : {
391 : 1416246 : gimple_stmt_iterator gsi;
392 : 1416246 : basic_block bb;
393 : 1416246 : bool cfg_changed = false;
394 : :
395 : 16131247 : FOR_EACH_BB_FN (bb, fun)
396 : : {
397 : 114100029 : for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi))
398 : : {
399 : : /* Pre-expand VEC_COND_EXPRs to .VCOND* internal function
400 : : calls mapping to supported optabs. */
401 : 84670027 : gimple *g = gimple_expand_vec_cond_expr (&gsi);
402 : 84670027 : if (g != NULL)
403 : : {
404 : 16139 : tree lhs = gimple_assign_lhs (gsi_stmt (gsi));
405 : 16139 : gimple_set_lhs (g, lhs);
406 : 16139 : gsi_replace (&gsi, g, false);
407 : : }
408 : :
409 : : /* Recognize .VEC_SET and .VEC_EXTRACT patterns. */
410 : 84670027 : cfg_changed |= gimple_expand_vec_set_extract_expr (fun, &gsi);
411 : 84670027 : if (gsi_end_p (gsi))
412 : : break;
413 : :
414 : 84670027 : gassign *stmt = dyn_cast <gassign *> (*gsi);
415 : 84670027 : if (!stmt)
416 : 54564475 : continue;
417 : :
418 : 30105552 : tree_code code = gimple_assign_rhs_code (stmt);
419 : 30105552 : if (TREE_CODE_CLASS (code) == tcc_comparison)
420 : 520730 : maybe_duplicate_comparison (stmt, bb);
421 : : }
422 : : }
423 : :
424 : 1416246 : return cfg_changed ? TODO_cleanup_cfg : 0;
425 : : }
426 : :
427 : : } // anon namespace
428 : :
429 : : gimple_opt_pass *
430 : 280114 : make_pass_gimple_isel (gcc::context *ctxt)
431 : : {
432 : 280114 : return new pass_gimple_isel (ctxt);
433 : : }
434 : :
|