gimple-isel.cc revision 1.1.1.1 1 1.1 mrg /* Schedule GIMPLE vector statements.
2 1.1 mrg Copyright (C) 2020-2022 Free Software Foundation, Inc.
3 1.1 mrg
4 1.1 mrg This file is part of GCC.
5 1.1 mrg
6 1.1 mrg GCC is free software; you can redistribute it and/or modify it
7 1.1 mrg under the terms of the GNU General Public License as published by the
8 1.1 mrg Free Software Foundation; either version 3, or (at your option) any
9 1.1 mrg later version.
10 1.1 mrg
11 1.1 mrg GCC is distributed in the hope that it will be useful, but WITHOUT
12 1.1 mrg ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 1.1 mrg FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 1.1 mrg for more details.
15 1.1 mrg
16 1.1 mrg You should have received a copy of the GNU General Public License
17 1.1 mrg along with GCC; see the file COPYING3. If not see
18 1.1 mrg <http://www.gnu.org/licenses/>. */
19 1.1 mrg
20 1.1 mrg #include "config.h"
21 1.1 mrg #include "system.h"
22 1.1 mrg #include "coretypes.h"
23 1.1 mrg #include "backend.h"
24 1.1 mrg #include "rtl.h"
25 1.1 mrg #include "tree.h"
26 1.1 mrg #include "gimple.h"
27 1.1 mrg #include "tree-pass.h"
28 1.1 mrg #include "ssa.h"
29 1.1 mrg #include "expmed.h"
30 1.1 mrg #include "optabs-tree.h"
31 1.1 mrg #include "tree-eh.h"
32 1.1 mrg #include "gimple-iterator.h"
33 1.1 mrg #include "gimplify-me.h"
34 1.1 mrg #include "gimplify.h"
35 1.1 mrg #include "tree-cfg.h"
36 1.1 mrg #include "bitmap.h"
37 1.1 mrg #include "tree-ssa-dce.h"
38 1.1 mrg #include "memmodel.h"
39 1.1 mrg #include "optabs.h"
40 1.1 mrg #include "gimple-fold.h"
41 1.1 mrg #include "internal-fn.h"
42 1.1 mrg
43 1.1 mrg /* Expand all ARRAY_REF(VIEW_CONVERT_EXPR) gimple assignments into calls to
44 1.1 mrg internal function based on vector type of selected expansion.
45 1.1 mrg i.e.:
46 1.1 mrg VIEW_CONVERT_EXPR<int[4]>(u)[_1] = i_4(D);
47 1.1 mrg =>
48 1.1 mrg _7 = u;
49 1.1 mrg _8 = .VEC_SET (_7, i_4(D), _1);
50 1.1 mrg u = _8; */
51 1.1 mrg
52 1.1 mrg static bool
53 1.1 mrg gimple_expand_vec_set_expr (struct function *fun, gimple_stmt_iterator *gsi)
54 1.1 mrg {
55 1.1 mrg enum tree_code code;
56 1.1 mrg gcall *new_stmt = NULL;
57 1.1 mrg gassign *ass_stmt = NULL;
58 1.1 mrg bool cfg_changed = false;
59 1.1 mrg
60 1.1 mrg /* Only consider code == GIMPLE_ASSIGN. */
61 1.1 mrg gassign *stmt = dyn_cast<gassign *> (gsi_stmt (*gsi));
62 1.1 mrg if (!stmt)
63 1.1 mrg return false;
64 1.1 mrg
65 1.1 mrg tree lhs = gimple_assign_lhs (stmt);
66 1.1 mrg code = TREE_CODE (lhs);
67 1.1 mrg if (code != ARRAY_REF)
68 1.1 mrg return false;
69 1.1 mrg
70 1.1 mrg tree val = gimple_assign_rhs1 (stmt);
71 1.1 mrg tree op0 = TREE_OPERAND (lhs, 0);
72 1.1 mrg if (TREE_CODE (op0) == VIEW_CONVERT_EXPR && DECL_P (TREE_OPERAND (op0, 0))
73 1.1 mrg && VECTOR_TYPE_P (TREE_TYPE (TREE_OPERAND (op0, 0)))
74 1.1 mrg && TYPE_MODE (TREE_TYPE (lhs))
75 1.1 mrg == TYPE_MODE (TREE_TYPE (TREE_TYPE (TREE_OPERAND (op0, 0)))))
76 1.1 mrg {
77 1.1 mrg tree pos = TREE_OPERAND (lhs, 1);
78 1.1 mrg tree view_op0 = TREE_OPERAND (op0, 0);
79 1.1 mrg machine_mode outermode = TYPE_MODE (TREE_TYPE (view_op0));
80 1.1 mrg if (auto_var_in_fn_p (view_op0, fun->decl)
81 1.1 mrg && !TREE_ADDRESSABLE (view_op0) && can_vec_set_var_idx_p (outermode))
82 1.1 mrg {
83 1.1 mrg location_t loc = gimple_location (stmt);
84 1.1 mrg tree var_src = make_ssa_name (TREE_TYPE (view_op0));
85 1.1 mrg tree var_dst = make_ssa_name (TREE_TYPE (view_op0));
86 1.1 mrg
87 1.1 mrg ass_stmt = gimple_build_assign (var_src, view_op0);
88 1.1 mrg gimple_set_vuse (ass_stmt, gimple_vuse (stmt));
89 1.1 mrg gimple_set_location (ass_stmt, loc);
90 1.1 mrg gsi_insert_before (gsi, ass_stmt, GSI_SAME_STMT);
91 1.1 mrg
92 1.1 mrg new_stmt
93 1.1 mrg = gimple_build_call_internal (IFN_VEC_SET, 3, var_src, val, pos);
94 1.1 mrg gimple_call_set_lhs (new_stmt, var_dst);
95 1.1 mrg gimple_set_location (new_stmt, loc);
96 1.1 mrg gsi_insert_before (gsi, new_stmt, GSI_SAME_STMT);
97 1.1 mrg
98 1.1 mrg ass_stmt = gimple_build_assign (view_op0, var_dst);
99 1.1 mrg gimple_set_location (ass_stmt, loc);
100 1.1 mrg gsi_insert_before (gsi, ass_stmt, GSI_SAME_STMT);
101 1.1 mrg
102 1.1 mrg basic_block bb = gimple_bb (stmt);
103 1.1 mrg gimple_move_vops (ass_stmt, stmt);
104 1.1 mrg if (gsi_remove (gsi, true)
105 1.1 mrg && gimple_purge_dead_eh_edges (bb))
106 1.1 mrg cfg_changed = true;
107 1.1 mrg *gsi = gsi_for_stmt (ass_stmt);
108 1.1 mrg }
109 1.1 mrg }
110 1.1 mrg
111 1.1 mrg return cfg_changed;
112 1.1 mrg }
113 1.1 mrg
114 1.1 mrg /* Expand all VEC_COND_EXPR gimple assignments into calls to internal
115 1.1 mrg function based on type of selected expansion. */
116 1.1 mrg
117 1.1 mrg static gimple *
118 1.1 mrg gimple_expand_vec_cond_expr (struct function *fun, gimple_stmt_iterator *gsi,
119 1.1 mrg hash_map<tree, unsigned int> *vec_cond_ssa_name_uses)
120 1.1 mrg {
121 1.1 mrg tree lhs, op0a = NULL_TREE, op0b = NULL_TREE;
122 1.1 mrg enum tree_code code;
123 1.1 mrg enum tree_code tcode;
124 1.1 mrg machine_mode cmp_op_mode;
125 1.1 mrg bool unsignedp;
126 1.1 mrg enum insn_code icode;
127 1.1 mrg imm_use_iterator imm_iter;
128 1.1 mrg
129 1.1 mrg /* Only consider code == GIMPLE_ASSIGN. */
130 1.1 mrg gassign *stmt = dyn_cast<gassign *> (gsi_stmt (*gsi));
131 1.1 mrg if (!stmt)
132 1.1 mrg return NULL;
133 1.1 mrg
134 1.1 mrg code = gimple_assign_rhs_code (stmt);
135 1.1 mrg if (code != VEC_COND_EXPR)
136 1.1 mrg return NULL;
137 1.1 mrg
138 1.1 mrg tree op0 = gimple_assign_rhs1 (stmt);
139 1.1 mrg tree op1 = gimple_assign_rhs2 (stmt);
140 1.1 mrg tree op2 = gimple_assign_rhs3 (stmt);
141 1.1 mrg lhs = gimple_assign_lhs (stmt);
142 1.1 mrg machine_mode mode = TYPE_MODE (TREE_TYPE (lhs));
143 1.1 mrg
144 1.1 mrg /* Lower mask typed, non-vector mode VEC_COND_EXPRs to bitwise operations.
145 1.1 mrg Those can end up generated by folding and at least for integer mode masks
146 1.1 mrg we cannot expect vcond expanders to exist. We lower a ? b : c
147 1.1 mrg to (b & a) | (c & ~a). */
148 1.1 mrg if (VECTOR_BOOLEAN_TYPE_P (TREE_TYPE (lhs))
149 1.1 mrg && !VECTOR_MODE_P (mode))
150 1.1 mrg {
151 1.1 mrg gcc_assert (types_compatible_p (TREE_TYPE (op0), TREE_TYPE (op1)));
152 1.1 mrg gimple_seq stmts = NULL;
153 1.1 mrg tree type = TREE_TYPE (lhs);
154 1.1 mrg location_t loc = gimple_location (stmt);
155 1.1 mrg tree tem0 = gimple_build (&stmts, loc, BIT_AND_EXPR, type, op1, op0);
156 1.1 mrg tree tem1 = gimple_build (&stmts, loc, BIT_NOT_EXPR, type, op0);
157 1.1 mrg tree tem2 = gimple_build (&stmts, loc, BIT_AND_EXPR, type, op2, tem1);
158 1.1 mrg tree tem3 = gimple_build (&stmts, loc, BIT_IOR_EXPR, type, tem0, tem2);
159 1.1 mrg gsi_insert_seq_before (gsi, stmts, GSI_SAME_STMT);
160 1.1 mrg return gimple_build_assign (lhs, tem3);
161 1.1 mrg }
162 1.1 mrg
163 1.1 mrg bool can_compute_op0 = true;
164 1.1 mrg gcc_assert (!COMPARISON_CLASS_P (op0));
165 1.1 mrg if (TREE_CODE (op0) == SSA_NAME)
166 1.1 mrg {
167 1.1 mrg unsigned int used_vec_cond_exprs = 0;
168 1.1 mrg unsigned int *slot = vec_cond_ssa_name_uses->get (op0);
169 1.1 mrg if (slot)
170 1.1 mrg used_vec_cond_exprs = *slot;
171 1.1 mrg else
172 1.1 mrg {
173 1.1 mrg gimple *use_stmt;
174 1.1 mrg FOR_EACH_IMM_USE_STMT (use_stmt, imm_iter, op0)
175 1.1 mrg {
176 1.1 mrg gassign *assign = dyn_cast<gassign *> (use_stmt);
177 1.1 mrg if (assign != NULL
178 1.1 mrg && gimple_assign_rhs_code (assign) == VEC_COND_EXPR
179 1.1 mrg && gimple_assign_rhs1 (assign) == op0)
180 1.1 mrg used_vec_cond_exprs++;
181 1.1 mrg }
182 1.1 mrg vec_cond_ssa_name_uses->put (op0, used_vec_cond_exprs);
183 1.1 mrg }
184 1.1 mrg
185 1.1 mrg gassign *def_stmt = dyn_cast<gassign *> (SSA_NAME_DEF_STMT (op0));
186 1.1 mrg if (def_stmt)
187 1.1 mrg {
188 1.1 mrg tcode = gimple_assign_rhs_code (def_stmt);
189 1.1 mrg op0a = gimple_assign_rhs1 (def_stmt);
190 1.1 mrg op0b = gimple_assign_rhs2 (def_stmt);
191 1.1 mrg
192 1.1 mrg tree op0_type = TREE_TYPE (op0);
193 1.1 mrg tree op0a_type = TREE_TYPE (op0a);
194 1.1 mrg if (TREE_CODE_CLASS (tcode) == tcc_comparison)
195 1.1 mrg can_compute_op0 = expand_vec_cmp_expr_p (op0a_type, op0_type,
196 1.1 mrg tcode);
197 1.1 mrg
198 1.1 mrg /* Try to fold x CMP y ? -1 : 0 to x CMP y. */
199 1.1 mrg if (can_compute_op0
200 1.1 mrg && integer_minus_onep (op1)
201 1.1 mrg && integer_zerop (op2)
202 1.1 mrg && TYPE_MODE (TREE_TYPE (lhs)) == TYPE_MODE (TREE_TYPE (op0)))
203 1.1 mrg {
204 1.1 mrg tree conv_op = build1 (VIEW_CONVERT_EXPR, TREE_TYPE (lhs), op0);
205 1.1 mrg gassign *new_stmt = gimple_build_assign (lhs, conv_op);
206 1.1 mrg gsi_replace (gsi, new_stmt, true);
207 1.1 mrg return new_stmt;
208 1.1 mrg }
209 1.1 mrg
210 1.1 mrg /* When the compare has EH we do not want to forward it when
211 1.1 mrg it has multiple uses and in general because of the complication
212 1.1 mrg with EH redirection. */
213 1.1 mrg if (stmt_can_throw_internal (fun, def_stmt))
214 1.1 mrg tcode = TREE_CODE (op0);
215 1.1 mrg
216 1.1 mrg /* If we can compute op0 and have multiple uses, keep the SSA
217 1.1 mrg name and use vcond_mask. */
218 1.1 mrg else if (can_compute_op0
219 1.1 mrg && used_vec_cond_exprs >= 2
220 1.1 mrg && (get_vcond_mask_icode (mode, TYPE_MODE (op0_type))
221 1.1 mrg != CODE_FOR_nothing))
222 1.1 mrg tcode = TREE_CODE (op0);
223 1.1 mrg }
224 1.1 mrg else
225 1.1 mrg tcode = TREE_CODE (op0);
226 1.1 mrg }
227 1.1 mrg else
228 1.1 mrg tcode = TREE_CODE (op0);
229 1.1 mrg
230 1.1 mrg if (TREE_CODE_CLASS (tcode) != tcc_comparison)
231 1.1 mrg {
232 1.1 mrg gcc_assert (VECTOR_BOOLEAN_TYPE_P (TREE_TYPE (op0)));
233 1.1 mrg if (get_vcond_mask_icode (mode, TYPE_MODE (TREE_TYPE (op0)))
234 1.1 mrg != CODE_FOR_nothing)
235 1.1 mrg return gimple_build_call_internal (IFN_VCOND_MASK, 3, op0, op1, op2);
236 1.1 mrg /* Fake op0 < 0. */
237 1.1 mrg else
238 1.1 mrg {
239 1.1 mrg gcc_assert (GET_MODE_CLASS (TYPE_MODE (TREE_TYPE (op0)))
240 1.1 mrg == MODE_VECTOR_INT);
241 1.1 mrg op0a = op0;
242 1.1 mrg op0b = build_zero_cst (TREE_TYPE (op0));
243 1.1 mrg tcode = LT_EXPR;
244 1.1 mrg }
245 1.1 mrg }
246 1.1 mrg cmp_op_mode = TYPE_MODE (TREE_TYPE (op0a));
247 1.1 mrg unsignedp = TYPE_UNSIGNED (TREE_TYPE (op0a));
248 1.1 mrg
249 1.1 mrg gcc_assert (known_eq (GET_MODE_NUNITS (mode),
250 1.1 mrg GET_MODE_NUNITS (cmp_op_mode)));
251 1.1 mrg
252 1.1 mrg icode = get_vcond_icode (mode, cmp_op_mode, unsignedp);
253 1.1 mrg /* Some targets do not have vcondeq and only vcond with NE/EQ
254 1.1 mrg but not vcondu, so make sure to also try vcond here as
255 1.1 mrg vcond_icode_p would canonicalize the optab query to. */
256 1.1 mrg if (icode == CODE_FOR_nothing
257 1.1 mrg && (tcode == NE_EXPR || tcode == EQ_EXPR)
258 1.1 mrg && ((icode = get_vcond_icode (mode, cmp_op_mode, !unsignedp))
259 1.1 mrg != CODE_FOR_nothing))
260 1.1 mrg unsignedp = !unsignedp;
261 1.1 mrg if (icode == CODE_FOR_nothing)
262 1.1 mrg {
263 1.1 mrg if (tcode == LT_EXPR
264 1.1 mrg && op0a == op0)
265 1.1 mrg {
266 1.1 mrg /* A VEC_COND_EXPR condition could be folded from EQ_EXPR/NE_EXPR
267 1.1 mrg into a constant when only get_vcond_eq_icode is supported.
268 1.1 mrg Try changing it to NE_EXPR. */
269 1.1 mrg tcode = NE_EXPR;
270 1.1 mrg }
271 1.1 mrg if ((tcode == EQ_EXPR || tcode == NE_EXPR)
272 1.1 mrg && direct_internal_fn_supported_p (IFN_VCONDEQ, TREE_TYPE (lhs),
273 1.1 mrg TREE_TYPE (op0a),
274 1.1 mrg OPTIMIZE_FOR_BOTH))
275 1.1 mrg {
276 1.1 mrg tree tcode_tree = build_int_cst (integer_type_node, tcode);
277 1.1 mrg return gimple_build_call_internal (IFN_VCONDEQ, 5, op0a, op0b, op1,
278 1.1 mrg op2, tcode_tree);
279 1.1 mrg }
280 1.1 mrg
281 1.1 mrg gcc_assert (VECTOR_BOOLEAN_TYPE_P (TREE_TYPE (op0))
282 1.1 mrg && can_compute_op0
283 1.1 mrg && (get_vcond_mask_icode (mode, TYPE_MODE (TREE_TYPE (op0)))
284 1.1 mrg != CODE_FOR_nothing));
285 1.1 mrg return gimple_build_call_internal (IFN_VCOND_MASK, 3, op0, op1, op2);
286 1.1 mrg }
287 1.1 mrg
288 1.1 mrg tree tcode_tree = build_int_cst (integer_type_node, tcode);
289 1.1 mrg return gimple_build_call_internal (unsignedp ? IFN_VCONDU : IFN_VCOND,
290 1.1 mrg 5, op0a, op0b, op1, op2, tcode_tree);
291 1.1 mrg }
292 1.1 mrg
293 1.1 mrg
294 1.1 mrg
295 1.1 mrg /* Iterate all gimple statements and try to expand
296 1.1 mrg VEC_COND_EXPR assignments. */
297 1.1 mrg
298 1.1 mrg static unsigned int
299 1.1 mrg gimple_expand_vec_exprs (struct function *fun)
300 1.1 mrg {
301 1.1 mrg gimple_stmt_iterator gsi;
302 1.1 mrg basic_block bb;
303 1.1 mrg hash_map<tree, unsigned int> vec_cond_ssa_name_uses;
304 1.1 mrg auto_bitmap dce_ssa_names;
305 1.1 mrg bool cfg_changed = false;
306 1.1 mrg
307 1.1 mrg FOR_EACH_BB_FN (bb, fun)
308 1.1 mrg {
309 1.1 mrg for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi))
310 1.1 mrg {
311 1.1 mrg gimple *g = gimple_expand_vec_cond_expr (fun, &gsi,
312 1.1 mrg &vec_cond_ssa_name_uses);
313 1.1 mrg if (g != NULL)
314 1.1 mrg {
315 1.1 mrg tree lhs = gimple_assign_lhs (gsi_stmt (gsi));
316 1.1 mrg gimple_set_lhs (g, lhs);
317 1.1 mrg gsi_replace (&gsi, g, false);
318 1.1 mrg }
319 1.1 mrg
320 1.1 mrg cfg_changed |= gimple_expand_vec_set_expr (fun, &gsi);
321 1.1 mrg if (gsi_end_p (gsi))
322 1.1 mrg break;
323 1.1 mrg }
324 1.1 mrg }
325 1.1 mrg
326 1.1 mrg for (hash_map<tree, unsigned int>::iterator it = vec_cond_ssa_name_uses.begin ();
327 1.1 mrg it != vec_cond_ssa_name_uses.end (); ++it)
328 1.1 mrg bitmap_set_bit (dce_ssa_names, SSA_NAME_VERSION ((*it).first));
329 1.1 mrg
330 1.1 mrg simple_dce_from_worklist (dce_ssa_names);
331 1.1 mrg
332 1.1 mrg return cfg_changed ? TODO_cleanup_cfg : 0;
333 1.1 mrg }
334 1.1 mrg
335 1.1 mrg namespace {
336 1.1 mrg
337 1.1 mrg const pass_data pass_data_gimple_isel =
338 1.1 mrg {
339 1.1 mrg GIMPLE_PASS, /* type */
340 1.1 mrg "isel", /* name */
341 1.1 mrg OPTGROUP_VEC, /* optinfo_flags */
342 1.1 mrg TV_NONE, /* tv_id */
343 1.1 mrg PROP_cfg, /* properties_required */
344 1.1 mrg 0, /* properties_provided */
345 1.1 mrg 0, /* properties_destroyed */
346 1.1 mrg 0, /* todo_flags_start */
347 1.1 mrg TODO_update_ssa, /* todo_flags_finish */
348 1.1 mrg };
349 1.1 mrg
350 1.1 mrg class pass_gimple_isel : public gimple_opt_pass
351 1.1 mrg {
352 1.1 mrg public:
353 1.1 mrg pass_gimple_isel (gcc::context *ctxt)
354 1.1 mrg : gimple_opt_pass (pass_data_gimple_isel, ctxt)
355 1.1 mrg {}
356 1.1 mrg
357 1.1 mrg /* opt_pass methods: */
358 1.1 mrg virtual bool gate (function *)
359 1.1 mrg {
360 1.1 mrg return true;
361 1.1 mrg }
362 1.1 mrg
363 1.1 mrg virtual unsigned int execute (function *fun)
364 1.1 mrg {
365 1.1 mrg return gimple_expand_vec_exprs (fun);
366 1.1 mrg }
367 1.1 mrg
368 1.1 mrg }; // class pass_gimple_isel
369 1.1 mrg
370 1.1 mrg } // anon namespace
371 1.1 mrg
372 1.1 mrg gimple_opt_pass *
373 1.1 mrg make_pass_gimple_isel (gcc::context *ctxt)
374 1.1 mrg {
375 1.1 mrg return new pass_gimple_isel (ctxt);
376 1.1 mrg }
377 1.1 mrg
378