Branch data Line data Source code
1 : : /* Schedule GIMPLE vector statements.
2 : : Copyright (C) 2020-2025 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 : : #include "fold-const.h"
43 : :
44 : : /* Expand all ARRAY_REF(VIEW_CONVERT_EXPR) gimple assignments into calls to
45 : : internal function based on vector type of selected expansion.
46 : :
47 : : For vec_set:
48 : :
49 : : VIEW_CONVERT_EXPR<int[4]>(u)[_1] = i_4(D);
50 : : =>
51 : : _7 = u;
52 : : _8 = .VEC_SET (_7, i_4(D), _1);
53 : : u = _8;
54 : :
55 : : For vec_extract:
56 : :
57 : : _3 = VIEW_CONVERT_EXPR<intD.1[4]>(vD.2208)[idx_2(D)];
58 : : =>
59 : : _4 = vD.2208;
60 : : _3 = .VEC_EXTRACT (_4, idx_2(D)); */
61 : :
62 : : static bool
63 : 96806733 : gimple_expand_vec_set_extract_expr (struct function *fun,
64 : : gimple_stmt_iterator *gsi)
65 : : {
66 : 96806733 : gcall *new_stmt = NULL;
67 : 96806733 : gassign *ass_stmt = NULL;
68 : 96806733 : bool cfg_changed = false;
69 : :
70 : : /* Only consider code == GIMPLE_ASSIGN. */
71 : 128838542 : gassign *stmt = dyn_cast<gassign *> (gsi_stmt (*gsi));
72 : 32041724 : if (!stmt)
73 : : return false;
74 : :
75 : 32041724 : bool is_extract = false;
76 : :
77 : 32041724 : tree lhs = gimple_assign_lhs (stmt);
78 : 32041724 : tree rhs = gimple_assign_rhs1 (stmt);
79 : 32041724 : tree val, ref;
80 : 32041724 : if (TREE_CODE (lhs) == ARRAY_REF)
81 : : {
82 : : /* Assume it is a vec_set. */
83 : : val = rhs;
84 : : ref = lhs;
85 : : }
86 : 31430771 : else if (TREE_CODE (rhs) == ARRAY_REF)
87 : : {
88 : : /* vec_extract. */
89 : : is_extract = true;
90 : : val = lhs;
91 : : ref = rhs;
92 : : }
93 : : else
94 : : return false;
95 : :
96 : 1173651 : tree op0 = TREE_OPERAND (ref, 0);
97 : 32093 : if (TREE_CODE (op0) == VIEW_CONVERT_EXPR && DECL_P (TREE_OPERAND (op0, 0))
98 : 26767 : && VECTOR_TYPE_P (TREE_TYPE (TREE_OPERAND (op0, 0)))
99 : 1193525 : && TYPE_MODE (TREE_TYPE (ref))
100 : 9937 : == TYPE_MODE (TREE_TYPE (TREE_TYPE (TREE_OPERAND (op0, 0)))))
101 : : {
102 : 9933 : tree pos = TREE_OPERAND (ref, 1);
103 : :
104 : 9933 : tree view_op0 = TREE_OPERAND (op0, 0);
105 : :
106 : 9933 : tree idx = TREE_OPERAND (ref, 1);
107 : : // if index is a constant, then check the bounds
108 : 9933 : poly_uint64 idx_poly;
109 : 9933 : if (poly_int_tree_p (idx, &idx_poly))
110 : : {
111 : 31 : poly_uint64 nelts = TYPE_VECTOR_SUBPARTS (TREE_TYPE (view_op0));
112 : 31 : if (known_gt (idx_poly, nelts))
113 : 18 : return false;
114 : : }
115 : 9915 : machine_mode outermode = TYPE_MODE (TREE_TYPE (view_op0));
116 : 9915 : machine_mode extract_mode = TYPE_MODE (TREE_TYPE (ref));
117 : :
118 : 9915 : if ((auto_var_in_fn_p (view_op0, fun->decl)
119 : 1307 : || (VAR_P (view_op0) && DECL_HARD_REGISTER (view_op0)))
120 : 8618 : && !TREE_ADDRESSABLE (view_op0)
121 : 16804 : && ((!is_extract && can_vec_set_var_idx_p (outermode))
122 : : || (is_extract
123 : 6750 : && can_vec_extract_var_idx_p (outermode, extract_mode))))
124 : : {
125 : 122 : location_t loc = gimple_location (stmt);
126 : 122 : tree var_src = make_ssa_name (TREE_TYPE (view_op0));
127 : :
128 : 122 : ass_stmt = gimple_build_assign (var_src, view_op0);
129 : 244 : gimple_set_vuse (ass_stmt, gimple_vuse (stmt));
130 : 122 : gimple_set_location (ass_stmt, loc);
131 : 122 : gsi_insert_before (gsi, ass_stmt, GSI_SAME_STMT);
132 : :
133 : 122 : if (!is_extract)
134 : : {
135 : 122 : tree var_dst = make_ssa_name (TREE_TYPE (view_op0));
136 : :
137 : 122 : new_stmt = gimple_build_call_internal (IFN_VEC_SET, 3, var_src,
138 : : val, pos);
139 : :
140 : 122 : gimple_call_set_lhs (new_stmt, var_dst);
141 : 122 : gimple_set_location (new_stmt, loc);
142 : 122 : gsi_insert_before (gsi, new_stmt, GSI_SAME_STMT);
143 : :
144 : 122 : ass_stmt = gimple_build_assign (view_op0, var_dst);
145 : 122 : gimple_set_location (ass_stmt, loc);
146 : 122 : gimple_move_vops (ass_stmt, stmt);
147 : 122 : gsi_insert_before (gsi, ass_stmt, GSI_SAME_STMT);
148 : :
149 : 122 : basic_block bb = gimple_bb (stmt);
150 : 122 : if (gsi_remove (gsi, true)
151 : 122 : && gimple_purge_dead_eh_edges (bb))
152 : : cfg_changed = true;
153 : 122 : *gsi = gsi_for_stmt (ass_stmt);
154 : : }
155 : : else
156 : : {
157 : 0 : new_stmt
158 : 0 : = gimple_build_call_internal (IFN_VEC_EXTRACT, 2, var_src, pos);
159 : 0 : gimple_call_set_lhs (new_stmt, lhs);
160 : :
161 : 0 : gsi_replace (gsi, new_stmt, true);
162 : 0 : cfg_changed = true;
163 : : }
164 : : }
165 : : }
166 : :
167 : : return cfg_changed;
168 : : }
169 : :
170 : : /* Expand all VEC_COND_EXPR gimple assignments into calls to internal
171 : : function based on type of selected expansion. */
172 : :
173 : : static gimple *
174 : 96806733 : gimple_expand_vec_cond_expr (gimple_stmt_iterator *gsi)
175 : : {
176 : 96806733 : tree lhs, op0a = NULL_TREE;
177 : 96806733 : enum tree_code code;
178 : 96806733 : enum tree_code tcode;
179 : :
180 : : /* Only consider code == GIMPLE_ASSIGN. */
181 : 96806733 : gassign *stmt = dyn_cast<gassign *> (gsi_stmt (*gsi));
182 : 32050491 : if (!stmt)
183 : : return NULL;
184 : :
185 : 32050491 : code = gimple_assign_rhs_code (stmt);
186 : 32050491 : if (code != VEC_COND_EXPR)
187 : : return NULL;
188 : :
189 : 19104 : tree op0 = gimple_assign_rhs1 (stmt);
190 : 19104 : tree op1 = gimple_assign_rhs2 (stmt);
191 : 19104 : tree op2 = gimple_assign_rhs3 (stmt);
192 : 19104 : lhs = gimple_assign_lhs (stmt);
193 : 19104 : machine_mode mode = TYPE_MODE (TREE_TYPE (lhs));
194 : :
195 : : /* Lower mask typed, non-vector mode VEC_COND_EXPRs to bitwise operations.
196 : : Those can end up generated by folding and at least for integer mode masks
197 : : we cannot expect vcond expanders to exist. We lower a ? b : c
198 : : to (b & a) | (c & ~a). */
199 : 38208 : if (VECTOR_BOOLEAN_TYPE_P (TREE_TYPE (lhs))
200 : 19105 : && !VECTOR_MODE_P (mode))
201 : : {
202 : 0 : gcc_assert (types_compatible_p (TREE_TYPE (op0), TREE_TYPE (op1)));
203 : 0 : gimple_seq stmts = NULL;
204 : 0 : tree type = TREE_TYPE (lhs);
205 : 0 : location_t loc = gimple_location (stmt);
206 : 0 : tree tem0 = gimple_build (&stmts, loc, BIT_AND_EXPR, type, op1, op0);
207 : 0 : tree tem1 = gimple_build (&stmts, loc, BIT_NOT_EXPR, type, op0);
208 : 0 : tree tem2 = gimple_build (&stmts, loc, BIT_AND_EXPR, type, op2, tem1);
209 : 0 : tree tem3 = gimple_build (&stmts, loc, BIT_IOR_EXPR, type, tem0, tem2);
210 : 0 : gsi_insert_seq_before (gsi, stmts, GSI_SAME_STMT);
211 : 0 : return gimple_build_assign (lhs, tem3);
212 : : }
213 : :
214 : 19104 : bool can_compute_op0 = true;
215 : 19104 : gcc_assert (!COMPARISON_CLASS_P (op0));
216 : 19104 : if (TREE_CODE (op0) == SSA_NAME)
217 : : {
218 : 17816 : gassign *def_stmt = dyn_cast<gassign *> (SSA_NAME_DEF_STMT (op0));
219 : 17806 : if (def_stmt)
220 : : {
221 : 17806 : tcode = gimple_assign_rhs_code (def_stmt);
222 : 17806 : op0a = gimple_assign_rhs1 (def_stmt);
223 : :
224 : 17806 : tree op0_type = TREE_TYPE (op0);
225 : 17806 : tree op0a_type = TREE_TYPE (op0a);
226 : 17806 : if (TREE_CODE_CLASS (tcode) == tcc_comparison)
227 : 13295 : can_compute_op0 = expand_vec_cmp_expr_p (op0a_type, op0_type,
228 : : tcode);
229 : 13295 : gcc_assert (can_compute_op0);
230 : :
231 : 17806 : if (can_compute_op0
232 : 17806 : && TYPE_MODE (TREE_TYPE (lhs)) == TYPE_MODE (TREE_TYPE (op0)))
233 : : {
234 : : /* Assuming c = x CMP y. */
235 : 13094 : bool op1_minus_onep = integer_minus_onep (op1);
236 : 13094 : bool op2_zerop = integer_zerop (op2);
237 : 13094 : tree vtype = TREE_TYPE (lhs);
238 : 13094 : machine_mode vmode = TYPE_MODE (vtype);
239 : : /* Try to fold r = c ? -1 : 0 to r = c. */
240 : 13094 : if (op1_minus_onep && op2_zerop)
241 : : {
242 : 3549 : tree conv_op = build1 (VIEW_CONVERT_EXPR, vtype, op0);
243 : 3549 : return gimple_build_assign (lhs, conv_op);
244 : : }
245 : : /* Try to fold r = c ? -1 : z to r = c | z, or
246 : : r = c ? c : z. */
247 : 9545 : if (op1_minus_onep)
248 : : {
249 : 16 : tree conv_op = build1 (VIEW_CONVERT_EXPR, vtype, op0);
250 : 16 : tree new_op1 = make_ssa_name (vtype);
251 : 16 : gassign *new_stmt = gimple_build_assign (new_op1, conv_op);
252 : 16 : gsi_insert_seq_before (gsi, new_stmt, GSI_SAME_STMT);
253 : 16 : if (optab_handler (ior_optab, vmode) != CODE_FOR_nothing)
254 : : /* r = c | z */
255 : 16 : return gimple_build_assign (lhs, BIT_IOR_EXPR, new_op1,
256 : 16 : op2);
257 : : /* r = c ? c : z */
258 : : op1 = new_op1;
259 : : }
260 : : /* Try to fold r = c ? z : 0 to r = c & z, or
261 : : r = c ? z : c. */
262 : 9529 : else if (op2_zerop)
263 : : {
264 : 6772 : tree conv_op = build1 (VIEW_CONVERT_EXPR, vtype, op0);
265 : 6772 : tree new_op2 = make_ssa_name (vtype);
266 : 6772 : gassign *new_stmt = gimple_build_assign (new_op2, conv_op);
267 : 6772 : gsi_insert_seq_before (gsi, new_stmt, GSI_SAME_STMT);
268 : 6772 : if (optab_handler (and_optab, vmode) != CODE_FOR_nothing)
269 : : /* r = c | z */
270 : 6772 : return gimple_build_assign (lhs, BIT_AND_EXPR, new_op2,
271 : 6772 : op1);
272 : : /* r = c ? z : c */
273 : : op2 = new_op2;
274 : : }
275 : 2757 : bool op1_zerop = integer_zerop (op1);
276 : 2757 : bool op2_minus_onep = integer_minus_onep (op2);
277 : : /* Try to fold r = c ? 0 : z to r = .BIT_ANDN (z, c). */
278 : 2757 : if (op1_zerop
279 : 2757 : && (direct_internal_fn_supported_p (IFN_BIT_ANDN, vtype,
280 : : OPTIMIZE_FOR_BOTH)))
281 : : {
282 : 74 : tree conv_op = build1 (VIEW_CONVERT_EXPR, vtype, op0);
283 : 74 : tree new_op = make_ssa_name (vtype);
284 : 74 : gassign *new_stmt = gimple_build_assign (new_op, conv_op);
285 : 74 : gsi_insert_seq_before (gsi, new_stmt, GSI_SAME_STMT);
286 : 74 : return gimple_build_call_internal (IFN_BIT_ANDN, 2, op2,
287 : 74 : new_op);
288 : : }
289 : : /* Try to fold r = c ? z : -1 to r = .BIT_IORN (z, c). */
290 : 2683 : else if (op2_minus_onep
291 : 2683 : && (direct_internal_fn_supported_p (IFN_BIT_IORN, vtype,
292 : : OPTIMIZE_FOR_BOTH)))
293 : : {
294 : 0 : tree conv_op = build1 (VIEW_CONVERT_EXPR, vtype, op0);
295 : 0 : tree new_op = make_ssa_name (vtype);
296 : 0 : gassign *new_stmt = gimple_build_assign (new_op, conv_op);
297 : 0 : gsi_insert_seq_before (gsi, new_stmt, GSI_SAME_STMT);
298 : 0 : return gimple_build_call_internal (IFN_BIT_IORN, 2, op1,
299 : 0 : new_op);
300 : : }
301 : : }
302 : : }
303 : : }
304 : :
305 : 8693 : gcc_assert (VECTOR_BOOLEAN_TYPE_P (TREE_TYPE (op0)));
306 : 17386 : gcc_assert (get_vcond_mask_icode (mode, TYPE_MODE (TREE_TYPE (op0)))
307 : : != CODE_FOR_nothing);
308 : 8693 : return gimple_build_call_internal (IFN_VCOND_MASK, 3, op0, op1, op2);
309 : : }
310 : :
311 : : /* Duplicate COND_EXPR condition defs of STMT located in BB when they are
312 : : comparisons so RTL expansion with the help of TER
313 : : can perform better if conversion. */
314 : : static void
315 : 557250 : maybe_duplicate_comparison (gassign *stmt, basic_block bb)
316 : : {
317 : 557250 : imm_use_iterator imm_iter;
318 : 557250 : use_operand_p use_p;
319 : 557250 : auto_vec<gassign *, 4> cond_exprs;
320 : 557250 : tree lhs = gimple_assign_lhs (stmt);
321 : 557250 : unsigned cnt = 0;
322 : :
323 : : /* This is should not be used for -O0 nor it is not useful
324 : : when ter is turned off. */
325 : 557250 : if (!optimize || !flag_tree_ter)
326 : : return;
327 : :
328 : 1332804 : FOR_EACH_IMM_USE_FAST (use_p, imm_iter, lhs)
329 : : {
330 : 463572 : if (is_gimple_debug (USE_STMT (use_p)))
331 : 11425 : continue;
332 : 452147 : cnt++;
333 : : /* Add the use statement if it was a cond_expr. */
334 : 452147 : if (gimple_bb (USE_STMT (use_p)) == bb
335 : 403846 : && is_gimple_assign (USE_STMT (use_p))
336 : 384779 : && gimple_assign_rhs_code (USE_STMT (use_p)) == COND_EXPR
337 : 467536 : && gimple_assign_rhs1_ptr (USE_STMT (use_p)) == use_p->use)
338 : 14979 : cond_exprs.safe_push (as_a <gassign *> (USE_STMT (use_p)));
339 : 434616 : }
340 : :
341 : : /* If the comparison has 0 or 1 uses, no reason to do anything. */
342 : 434616 : if (cnt <= 1)
343 : : return;
344 : :
345 : : /* If we only use the expression inside cond_exprs in that BB, we don't
346 : : need to duplicate for one of them so pop the top. */
347 : 23128 : if (cond_exprs.length () == cnt)
348 : 130 : cond_exprs.pop();
349 : :
350 : 23506 : while (!cond_exprs.is_empty())
351 : : {
352 : 378 : auto old_top = cond_exprs.pop();
353 : 378 : gassign *copy = as_a <gassign *> (gimple_copy (stmt));
354 : 378 : tree new_def = duplicate_ssa_name (lhs, copy);
355 : 378 : gimple_assign_set_lhs (copy, new_def);
356 : 378 : auto gsi2 = gsi_for_stmt (old_top);
357 : 378 : gsi_insert_before (&gsi2, copy, GSI_SAME_STMT);
358 : 378 : gimple_assign_set_rhs1 (old_top, new_def);
359 : 378 : update_stmt (old_top);
360 : : }
361 : 557250 : }
362 : :
363 : : /* match.pd function to match atomic_bit_test_and pattern which
364 : : has nop_convert:
365 : : _1 = __atomic_fetch_or_4 (&v, 1, 0);
366 : : _2 = (int) _1;
367 : : _5 = _2 & 1;
368 : : */
369 : : extern bool gimple_nop_atomic_bit_test_and_p (tree, tree *,
370 : : tree (*) (tree));
371 : : extern bool gimple_nop_convert (tree, tree*, tree (*) (tree));
372 : :
373 : : namespace {
374 : :
375 : : const pass_data pass_data_gimple_isel =
376 : : {
377 : : GIMPLE_PASS, /* type */
378 : : "isel", /* name */
379 : : OPTGROUP_VEC, /* optinfo_flags */
380 : : TV_NONE, /* tv_id */
381 : : PROP_cfg, /* properties_required */
382 : : 0, /* properties_provided */
383 : : 0, /* properties_destroyed */
384 : : 0, /* todo_flags_start */
385 : : TODO_update_ssa, /* todo_flags_finish */
386 : : };
387 : :
388 : : class pass_gimple_isel : public gimple_opt_pass
389 : : {
390 : : public:
391 : 289302 : pass_gimple_isel (gcc::context *ctxt)
392 : 578604 : : gimple_opt_pass (pass_data_gimple_isel, ctxt)
393 : : {}
394 : :
395 : : /* opt_pass methods: */
396 : 1472888 : bool gate (function *) final override
397 : : {
398 : 1472888 : return true;
399 : : }
400 : :
401 : : unsigned int execute (function *fun) final override;
402 : : }; // class pass_gimple_isel
403 : :
404 : :
405 : :
406 : : /* Convert
407 : : _1 = __atomic_fetch_or_* (ptr_6, 1, _3);
408 : : _7 = ~_1;
409 : : _5 = (_Bool) _7;
410 : : to
411 : : _1 = __atomic_fetch_or_* (ptr_6, 1, _3);
412 : : _8 = _1 & 1;
413 : : _5 = _8 == 0;
414 : : and convert
415 : : _1 = __atomic_fetch_and_* (ptr_6, ~1, _3);
416 : : _7 = ~_1;
417 : : _4 = (_Bool) _7;
418 : : to
419 : : _1 = __atomic_fetch_and_* (ptr_6, ~1, _3);
420 : : _8 = _1 & 1;
421 : : _4 = (_Bool) _8;
422 : :
423 : : USE_STMT is the gimplt statement which uses the return value of
424 : : __atomic_fetch_or_*. LHS is the return value of __atomic_fetch_or_*.
425 : : MASK is the mask passed to __atomic_fetch_or_*.
426 : : */
427 : :
428 : : static gimple *
429 : 14 : convert_atomic_bit_not (enum internal_fn fn, gimple *use_stmt,
430 : : tree lhs, tree mask)
431 : : {
432 : 14 : tree and_mask;
433 : 14 : if (fn == IFN_ATOMIC_BIT_TEST_AND_RESET)
434 : : {
435 : : /* MASK must be ~1. */
436 : 8 : if (!operand_equal_p (build_int_cst (TREE_TYPE (lhs),
437 : : ~HOST_WIDE_INT_1), mask, 0))
438 : : return nullptr;
439 : 8 : and_mask = build_int_cst (TREE_TYPE (lhs), 1);
440 : : }
441 : : else
442 : : {
443 : : /* MASK must be 1. */
444 : 6 : if (!operand_equal_p (build_int_cst (TREE_TYPE (lhs), 1), mask, 0))
445 : : return nullptr;
446 : : and_mask = mask;
447 : : }
448 : :
449 : 14 : tree use_lhs = gimple_assign_lhs (use_stmt);
450 : :
451 : 14 : use_operand_p use_p;
452 : 14 : gimple *use_not_stmt;
453 : :
454 : 14 : if (!single_imm_use (use_lhs, &use_p, &use_not_stmt)
455 : 14 : || !is_gimple_assign (use_not_stmt))
456 : : return nullptr;
457 : :
458 : 14 : if (!CONVERT_EXPR_CODE_P (gimple_assign_rhs_code (use_not_stmt)))
459 : : return nullptr;
460 : :
461 : 14 : tree use_not_lhs = gimple_assign_lhs (use_not_stmt);
462 : 14 : if (TREE_CODE (TREE_TYPE (use_not_lhs)) != BOOLEAN_TYPE)
463 : : return nullptr;
464 : :
465 : 14 : gimple_stmt_iterator gsi;
466 : 14 : tree var = make_ssa_name (TREE_TYPE (lhs));
467 : : /* use_stmt need to be removed after use_nop_stmt,
468 : : so use_lhs can be released. */
469 : 14 : gimple *use_stmt_removal = use_stmt;
470 : 14 : use_stmt = gimple_build_assign (var, BIT_AND_EXPR, lhs, and_mask);
471 : 14 : gsi = gsi_for_stmt (use_not_stmt);
472 : 14 : gsi_insert_before (&gsi, use_stmt, GSI_NEW_STMT);
473 : 14 : lhs = gimple_assign_lhs (use_not_stmt);
474 : 14 : gimple *g = gimple_build_assign (lhs, EQ_EXPR, var,
475 : 14 : build_zero_cst (TREE_TYPE (mask)));
476 : 14 : gsi_insert_after (&gsi, g, GSI_NEW_STMT);
477 : 14 : gsi = gsi_for_stmt (use_not_stmt);
478 : 14 : gsi_remove (&gsi, true);
479 : 14 : gsi = gsi_for_stmt (use_stmt_removal);
480 : 14 : gsi_remove (&gsi, true);
481 : 14 : return use_stmt;
482 : : }
483 : :
484 : : /* Optimize
485 : : mask_2 = 1 << cnt_1;
486 : : _4 = __atomic_fetch_or_* (ptr_6, mask_2, _3);
487 : : _5 = _4 & mask_2;
488 : : to
489 : : _4 = .ATOMIC_BIT_TEST_AND_SET (ptr_6, cnt_1, 0, _3);
490 : : _5 = _4;
491 : : If _5 is only used in _5 != 0 or _5 == 0 comparisons, 1
492 : : is passed instead of 0, and the builtin just returns a zero
493 : : or 1 value instead of the actual bit.
494 : : Similarly for __sync_fetch_and_or_* (without the ", _3" part
495 : : in there), and/or if mask_2 is a power of 2 constant.
496 : : Similarly for xor instead of or, use ATOMIC_BIT_TEST_AND_COMPLEMENT
497 : : in that case. And similarly for and instead of or, except that
498 : : the second argument to the builtin needs to be one's complement
499 : : of the mask instead of mask. */
500 : :
501 : : static bool
502 : 4613 : optimize_atomic_bit_test_and (gimple_stmt_iterator *gsip,
503 : : enum internal_fn fn, bool has_model_arg,
504 : : bool after)
505 : : {
506 : 4613 : gimple *call = gsi_stmt (*gsip);
507 : 4613 : tree lhs = gimple_call_lhs (call);
508 : 4613 : use_operand_p use_p;
509 : 4613 : gimple *use_stmt;
510 : 4613 : tree mask;
511 : 4613 : optab optab;
512 : :
513 : 4613 : if (!flag_inline_atomics
514 : 4613 : || optimize_debug
515 : 4613 : || !gimple_call_builtin_p (call, BUILT_IN_NORMAL)
516 : 4613 : || !lhs
517 : 2962 : || SSA_NAME_OCCURS_IN_ABNORMAL_PHI (lhs)
518 : 2962 : || !single_imm_use (lhs, &use_p, &use_stmt)
519 : 2932 : || !is_gimple_assign (use_stmt)
520 : 6321 : || !gimple_vdef (call))
521 : 2905 : return false;
522 : :
523 : 1708 : switch (fn)
524 : : {
525 : : case IFN_ATOMIC_BIT_TEST_AND_SET:
526 : : optab = atomic_bit_test_and_set_optab;
527 : : break;
528 : : case IFN_ATOMIC_BIT_TEST_AND_COMPLEMENT:
529 : : optab = atomic_bit_test_and_complement_optab;
530 : : break;
531 : : case IFN_ATOMIC_BIT_TEST_AND_RESET:
532 : : optab = atomic_bit_test_and_reset_optab;
533 : : break;
534 : : default:
535 : : return false;
536 : : }
537 : :
538 : 1708 : tree bit = nullptr;
539 : :
540 : 1708 : mask = gimple_call_arg (call, 1);
541 : 1708 : tree_code rhs_code = gimple_assign_rhs_code (use_stmt);
542 : 1708 : if (rhs_code != BIT_AND_EXPR)
543 : : {
544 : 1416 : if (rhs_code != NOP_EXPR && rhs_code != BIT_NOT_EXPR)
545 : 1259 : return false;
546 : :
547 : 845 : tree use_lhs = gimple_assign_lhs (use_stmt);
548 : 845 : if (TREE_CODE (use_lhs) == SSA_NAME
549 : 845 : && SSA_NAME_OCCURS_IN_ABNORMAL_PHI (use_lhs))
550 : : return false;
551 : :
552 : 845 : tree use_rhs = gimple_assign_rhs1 (use_stmt);
553 : 845 : if (lhs != use_rhs)
554 : : return false;
555 : :
556 : 845 : if (optab_handler (optab, TYPE_MODE (TREE_TYPE (lhs)))
557 : : == CODE_FOR_nothing)
558 : : return false;
559 : :
560 : 581 : gimple *g;
561 : 581 : gimple_stmt_iterator gsi;
562 : 581 : tree var;
563 : 581 : int ibit = -1;
564 : :
565 : 581 : if (rhs_code == BIT_NOT_EXPR)
566 : : {
567 : 14 : g = convert_atomic_bit_not (fn, use_stmt, lhs, mask);
568 : 14 : if (!g)
569 : : return false;
570 : 14 : use_stmt = g;
571 : 14 : ibit = 0;
572 : : }
573 : 567 : else if (TREE_CODE (TREE_TYPE (use_lhs)) == BOOLEAN_TYPE)
574 : : {
575 : 15 : tree and_mask;
576 : 15 : if (fn == IFN_ATOMIC_BIT_TEST_AND_RESET)
577 : : {
578 : : /* MASK must be ~1. */
579 : 8 : if (!operand_equal_p (build_int_cst (TREE_TYPE (lhs),
580 : : ~HOST_WIDE_INT_1),
581 : : mask, 0))
582 : : return false;
583 : :
584 : : /* Convert
585 : : _1 = __atomic_fetch_and_* (ptr_6, ~1, _3);
586 : : _4 = (_Bool) _1;
587 : : to
588 : : _1 = __atomic_fetch_and_* (ptr_6, ~1, _3);
589 : : _5 = _1 & 1;
590 : : _4 = (_Bool) _5;
591 : : */
592 : 8 : and_mask = build_int_cst (TREE_TYPE (lhs), 1);
593 : : }
594 : : else
595 : : {
596 : 7 : and_mask = build_int_cst (TREE_TYPE (lhs), 1);
597 : 7 : if (!operand_equal_p (and_mask, mask, 0))
598 : : return false;
599 : :
600 : : /* Convert
601 : : _1 = __atomic_fetch_or_* (ptr_6, 1, _3);
602 : : _4 = (_Bool) _1;
603 : : to
604 : : _1 = __atomic_fetch_or_* (ptr_6, 1, _3);
605 : : _5 = _1 & 1;
606 : : _4 = (_Bool) _5;
607 : : */
608 : : }
609 : 15 : var = make_ssa_name (TREE_TYPE (use_rhs));
610 : 15 : replace_uses_by (use_rhs, var);
611 : 15 : g = gimple_build_assign (var, BIT_AND_EXPR, use_rhs,
612 : : and_mask);
613 : 15 : gsi = gsi_for_stmt (use_stmt);
614 : 15 : gsi_insert_before (&gsi, g, GSI_NEW_STMT);
615 : 15 : use_stmt = g;
616 : 15 : ibit = 0;
617 : : }
618 : 552 : else if (TYPE_PRECISION (TREE_TYPE (use_lhs))
619 : 552 : <= TYPE_PRECISION (TREE_TYPE (use_rhs)))
620 : : {
621 : 550 : gimple *use_nop_stmt;
622 : 550 : if (!single_imm_use (use_lhs, &use_p, &use_nop_stmt)
623 : 550 : || (!is_gimple_assign (use_nop_stmt)
624 : 93 : && gimple_code (use_nop_stmt) != GIMPLE_COND))
625 : 422 : return false;
626 : : /* Handle both
627 : : _4 = _5 < 0;
628 : : and
629 : : if (_5 < 0)
630 : : */
631 : 466 : tree use_nop_lhs = nullptr;
632 : 466 : rhs_code = ERROR_MARK;
633 : 466 : if (is_gimple_assign (use_nop_stmt))
634 : : {
635 : 457 : use_nop_lhs = gimple_assign_lhs (use_nop_stmt);
636 : 457 : rhs_code = gimple_assign_rhs_code (use_nop_stmt);
637 : : }
638 : 466 : if (!use_nop_lhs || rhs_code != BIT_AND_EXPR)
639 : : {
640 : : /* Also handle
641 : : if (_5 < 0)
642 : : */
643 : 372 : if (use_nop_lhs
644 : 363 : && TREE_CODE (use_nop_lhs) == SSA_NAME
645 : 423 : && SSA_NAME_OCCURS_IN_ABNORMAL_PHI (use_nop_lhs))
646 : : return false;
647 : 372 : if (use_nop_lhs && rhs_code == BIT_NOT_EXPR)
648 : : {
649 : : /* Handle
650 : : _7 = ~_2;
651 : : */
652 : 0 : g = convert_atomic_bit_not (fn, use_nop_stmt, lhs,
653 : : mask);
654 : 0 : if (!g)
655 : : return false;
656 : : /* Convert
657 : : _1 = __atomic_fetch_or_4 (ptr_6, 1, _3);
658 : : _2 = (int) _1;
659 : : _7 = ~_2;
660 : : _5 = (_Bool) _7;
661 : : to
662 : : _1 = __atomic_fetch_or_4 (ptr_6, ~1, _3);
663 : : _8 = _1 & 1;
664 : : _5 = _8 == 0;
665 : : and convert
666 : : _1 = __atomic_fetch_and_4 (ptr_6, ~1, _3);
667 : : _2 = (int) _1;
668 : : _7 = ~_2;
669 : : _5 = (_Bool) _7;
670 : : to
671 : : _1 = __atomic_fetch_and_4 (ptr_6, 1, _3);
672 : : _8 = _1 & 1;
673 : : _5 = _8 == 0;
674 : : */
675 : 0 : gsi = gsi_for_stmt (use_stmt);
676 : 0 : gsi_remove (&gsi, true);
677 : 0 : use_stmt = g;
678 : 0 : ibit = 0;
679 : : }
680 : : else
681 : : {
682 : 372 : tree cmp_rhs1, cmp_rhs2;
683 : 372 : if (use_nop_lhs)
684 : : {
685 : : /* Handle
686 : : _4 = _5 < 0;
687 : : */
688 : 363 : if (TREE_CODE (TREE_TYPE (use_nop_lhs))
689 : : != BOOLEAN_TYPE)
690 : 422 : return false;
691 : 51 : cmp_rhs1 = gimple_assign_rhs1 (use_nop_stmt);
692 : 51 : cmp_rhs2 = gimple_assign_rhs2 (use_nop_stmt);
693 : : }
694 : : else
695 : : {
696 : : /* Handle
697 : : if (_5 < 0)
698 : : */
699 : 9 : rhs_code = gimple_cond_code (use_nop_stmt);
700 : 9 : cmp_rhs1 = gimple_cond_lhs (use_nop_stmt);
701 : 9 : cmp_rhs2 = gimple_cond_rhs (use_nop_stmt);
702 : : }
703 : 60 : if (rhs_code != GE_EXPR && rhs_code != LT_EXPR)
704 : : return false;
705 : 48 : if (use_lhs != cmp_rhs1)
706 : : return false;
707 : 48 : if (!integer_zerop (cmp_rhs2))
708 : : return false;
709 : :
710 : 48 : tree and_mask;
711 : :
712 : 48 : unsigned HOST_WIDE_INT bytes
713 : 48 : = tree_to_uhwi (TYPE_SIZE_UNIT (TREE_TYPE (use_rhs)));
714 : 48 : ibit = bytes * BITS_PER_UNIT - 1;
715 : 48 : unsigned HOST_WIDE_INT highest
716 : 48 : = HOST_WIDE_INT_1U << ibit;
717 : :
718 : 48 : if (fn == IFN_ATOMIC_BIT_TEST_AND_RESET)
719 : : {
720 : : /* Get the signed maximum of the USE_RHS type. */
721 : 19 : and_mask = build_int_cst (TREE_TYPE (use_rhs),
722 : 19 : highest - 1);
723 : 19 : if (!operand_equal_p (and_mask, mask, 0))
724 : : return false;
725 : :
726 : : /* Convert
727 : : _1 = __atomic_fetch_and_4 (ptr_6, 0x7fffffff, _3);
728 : : _5 = (signed int) _1;
729 : : _4 = _5 < 0 or _5 >= 0;
730 : : to
731 : : _1 = __atomic_fetch_and_4 (ptr_6, 0x7fffffff, _3);
732 : : _6 = _1 & 0x80000000;
733 : : _4 = _6 != 0 or _6 == 0;
734 : : and convert
735 : : _1 = __atomic_fetch_and_4 (ptr_6, 0x7fffffff, _3);
736 : : _5 = (signed int) _1;
737 : : if (_5 < 0 or _5 >= 0)
738 : : to
739 : : _1 = __atomic_fetch_and_4 (ptr_6, 0x7fffffff, _3);
740 : : _6 = _1 & 0x80000000;
741 : : if (_6 != 0 or _6 == 0)
742 : : */
743 : 19 : and_mask = build_int_cst (TREE_TYPE (use_rhs),
744 : 19 : highest);
745 : : }
746 : : else
747 : : {
748 : : /* Get the signed minimum of the USE_RHS type. */
749 : 29 : and_mask = build_int_cst (TREE_TYPE (use_rhs),
750 : 29 : highest);
751 : 29 : if (!operand_equal_p (and_mask, mask, 0))
752 : : return false;
753 : :
754 : : /* Convert
755 : : _1 = __atomic_fetch_or_4 (ptr_6, 0x80000000, _3);
756 : : _5 = (signed int) _1;
757 : : _4 = _5 < 0 or _5 >= 0;
758 : : to
759 : : _1 = __atomic_fetch_or_4 (ptr_6, 0x80000000, _3);
760 : : _6 = _1 & 0x80000000;
761 : : _4 = _6 != 0 or _6 == 0;
762 : : and convert
763 : : _1 = __atomic_fetch_or_4 (ptr_6, 0x80000000, _3);
764 : : _5 = (signed int) _1;
765 : : if (_5 < 0 or _5 >= 0)
766 : : to
767 : : _1 = __atomic_fetch_or_4 (ptr_6, 0x80000000, _3);
768 : : _6 = _1 & 0x80000000;
769 : : if (_6 != 0 or _6 == 0)
770 : : */
771 : : }
772 : 36 : var = make_ssa_name (TREE_TYPE (use_rhs));
773 : 36 : gimple* use_stmt_removal = use_stmt;
774 : 36 : g = gimple_build_assign (var, BIT_AND_EXPR, use_rhs,
775 : : and_mask);
776 : 36 : gsi = gsi_for_stmt (use_nop_stmt);
777 : 36 : gsi_insert_before (&gsi, g, GSI_NEW_STMT);
778 : 36 : use_stmt = g;
779 : 36 : rhs_code = rhs_code == GE_EXPR ? EQ_EXPR : NE_EXPR;
780 : 36 : tree const_zero = build_zero_cst (TREE_TYPE (use_rhs));
781 : 36 : if (use_nop_lhs)
782 : 27 : g = gimple_build_assign (use_nop_lhs, rhs_code,
783 : : var, const_zero);
784 : : else
785 : 9 : g = gimple_build_cond (rhs_code, var, const_zero,
786 : : nullptr, nullptr);
787 : 36 : gsi_insert_after (&gsi, g, GSI_NEW_STMT);
788 : 36 : gsi = gsi_for_stmt (use_nop_stmt);
789 : 36 : gsi_remove (&gsi, true);
790 : 36 : gsi = gsi_for_stmt (use_stmt_removal);
791 : 36 : gsi_remove (&gsi, true);
792 : : }
793 : : }
794 : : else
795 : : {
796 : 94 : tree match_op[3];
797 : 94 : gimple *g;
798 : 94 : if (!gimple_nop_atomic_bit_test_and_p (use_nop_lhs,
799 : : &match_op[0], NULL)
800 : 92 : || SSA_NAME_OCCURS_IN_ABNORMAL_PHI (match_op[2])
801 : 92 : || !single_imm_use (match_op[2], &use_p, &g)
802 : 186 : || !is_gimple_assign (g))
803 : 2 : return false;
804 : 92 : mask = match_op[0];
805 : 92 : if (TREE_CODE (match_op[1]) == INTEGER_CST)
806 : : {
807 : 48 : ibit = tree_log2 (match_op[1]);
808 : 48 : gcc_assert (ibit >= 0);
809 : : }
810 : : else
811 : : {
812 : 44 : g = SSA_NAME_DEF_STMT (match_op[1]);
813 : 44 : gcc_assert (is_gimple_assign (g));
814 : 44 : bit = gimple_assign_rhs2 (g);
815 : : }
816 : : /* Convert
817 : : _1 = __atomic_fetch_or_4 (ptr_6, mask, _3);
818 : : _2 = (int) _1;
819 : : _5 = _2 & mask;
820 : : to
821 : : _1 = __atomic_fetch_or_4 (ptr_6, mask, _3);
822 : : _6 = _1 & mask;
823 : : _5 = (int) _6;
824 : : and convert
825 : : _1 = ~mask_7;
826 : : _2 = (unsigned int) _1;
827 : : _3 = __atomic_fetch_and_4 (ptr_6, _2, 0);
828 : : _4 = (int) _3;
829 : : _5 = _4 & mask_7;
830 : : to
831 : : _1 = __atomic_fetch_and_* (ptr_6, ~mask_7, _3);
832 : : _12 = _3 & mask_7;
833 : : _5 = (int) _12;
834 : :
835 : : and Convert
836 : : _1 = __atomic_fetch_and_4 (ptr_6, ~mask, _3);
837 : : _2 = (short int) _1;
838 : : _5 = _2 & mask;
839 : : to
840 : : _1 = __atomic_fetch_and_4 (ptr_6, ~mask, _3);
841 : : _8 = _1 & mask;
842 : : _5 = (short int) _8;
843 : : */
844 : 92 : gimple_seq stmts = NULL;
845 : 92 : match_op[1] = gimple_convert (&stmts,
846 : 92 : TREE_TYPE (use_rhs),
847 : : match_op[1]);
848 : 92 : var = gimple_build (&stmts, BIT_AND_EXPR,
849 : 92 : TREE_TYPE (use_rhs), use_rhs, match_op[1]);
850 : 92 : gsi = gsi_for_stmt (use_stmt);
851 : 92 : gsi_remove (&gsi, true);
852 : 92 : release_defs (use_stmt);
853 : 92 : use_stmt = gimple_seq_last_stmt (stmts);
854 : 92 : gsi = gsi_for_stmt (use_nop_stmt);
855 : 92 : gsi_insert_seq_before (&gsi, stmts, GSI_SAME_STMT);
856 : 92 : gimple_assign_set_rhs_with_ops (&gsi, CONVERT_EXPR, var);
857 : 92 : update_stmt (use_nop_stmt);
858 : : }
859 : : }
860 : : else
861 : : return false;
862 : :
863 : 157 : if (!bit)
864 : : {
865 : 113 : if (ibit < 0)
866 : 0 : gcc_unreachable ();
867 : 113 : bit = build_int_cst (TREE_TYPE (lhs), ibit);
868 : : }
869 : : }
870 : 292 : else if (optab_handler (optab, TYPE_MODE (TREE_TYPE (lhs)))
871 : : == CODE_FOR_nothing)
872 : : return false;
873 : :
874 : 443 : tree use_lhs = gimple_assign_lhs (use_stmt);
875 : 443 : if (!use_lhs)
876 : : return false;
877 : :
878 : 443 : if (!bit)
879 : : {
880 : 286 : if (TREE_CODE (mask) == INTEGER_CST)
881 : : {
882 : 222 : if (fn == IFN_ATOMIC_BIT_TEST_AND_RESET)
883 : 62 : mask = const_unop (BIT_NOT_EXPR, TREE_TYPE (mask), mask);
884 : 222 : mask = fold_convert (TREE_TYPE (lhs), mask);
885 : 222 : int ibit = tree_log2 (mask);
886 : 222 : if (ibit < 0)
887 : 16 : return false;
888 : 220 : bit = build_int_cst (TREE_TYPE (lhs), ibit);
889 : : }
890 : 64 : else if (TREE_CODE (mask) == SSA_NAME)
891 : : {
892 : 64 : gimple *g = SSA_NAME_DEF_STMT (mask);
893 : 64 : tree match_op;
894 : 64 : if (gimple_nop_convert (mask, &match_op, NULL))
895 : : {
896 : 3 : mask = match_op;
897 : 3 : if (TREE_CODE (mask) != SSA_NAME)
898 : 7 : return false;
899 : 3 : g = SSA_NAME_DEF_STMT (mask);
900 : : }
901 : 64 : if (!is_gimple_assign (g))
902 : : return false;
903 : :
904 : 62 : if (fn == IFN_ATOMIC_BIT_TEST_AND_RESET)
905 : : {
906 : 20 : if (gimple_assign_rhs_code (g) != BIT_NOT_EXPR)
907 : : return false;
908 : 20 : mask = gimple_assign_rhs1 (g);
909 : 20 : if (TREE_CODE (mask) != SSA_NAME)
910 : : return false;
911 : 20 : g = SSA_NAME_DEF_STMT (mask);
912 : : }
913 : :
914 : 62 : if (!is_gimple_assign (g)
915 : 57 : || gimple_assign_rhs_code (g) != LSHIFT_EXPR
916 : 119 : || !integer_onep (gimple_assign_rhs1 (g)))
917 : 5 : return false;
918 : 57 : bit = gimple_assign_rhs2 (g);
919 : : }
920 : : else
921 : : return false;
922 : :
923 : 277 : tree cmp_mask;
924 : 277 : if (gimple_assign_rhs1 (use_stmt) == lhs)
925 : 241 : cmp_mask = gimple_assign_rhs2 (use_stmt);
926 : : else
927 : : cmp_mask = gimple_assign_rhs1 (use_stmt);
928 : :
929 : 277 : tree match_op;
930 : 277 : if (gimple_nop_convert (cmp_mask, &match_op, NULL))
931 : 1 : cmp_mask = match_op;
932 : :
933 : 277 : if (!operand_equal_p (cmp_mask, mask, 0))
934 : : return false;
935 : : }
936 : :
937 : 427 : bool use_bool = true;
938 : 427 : bool has_debug_uses = false;
939 : 427 : imm_use_iterator iter;
940 : 427 : gimple *g;
941 : :
942 : 427 : if (SSA_NAME_OCCURS_IN_ABNORMAL_PHI (use_lhs))
943 : 0 : use_bool = false;
944 : 1056 : FOR_EACH_IMM_USE_STMT (g, iter, use_lhs)
945 : : {
946 : 428 : enum tree_code code = ERROR_MARK;
947 : 428 : tree op0 = NULL_TREE, op1 = NULL_TREE;
948 : 428 : if (is_gimple_debug (g))
949 : : {
950 : 1 : has_debug_uses = true;
951 : 1 : continue;
952 : : }
953 : 427 : else if (is_gimple_assign (g))
954 : 385 : switch (gimple_assign_rhs_code (g))
955 : : {
956 : 0 : case COND_EXPR:
957 : 0 : op1 = gimple_assign_rhs1 (g);
958 : 0 : code = TREE_CODE (op1);
959 : 0 : if (TREE_CODE_CLASS (code) != tcc_comparison)
960 : : break;
961 : 0 : op0 = TREE_OPERAND (op1, 0);
962 : 0 : op1 = TREE_OPERAND (op1, 1);
963 : 0 : break;
964 : 173 : case EQ_EXPR:
965 : 173 : case NE_EXPR:
966 : 173 : code = gimple_assign_rhs_code (g);
967 : 173 : op0 = gimple_assign_rhs1 (g);
968 : 173 : op1 = gimple_assign_rhs2 (g);
969 : 173 : break;
970 : : default:
971 : : break;
972 : : }
973 : 42 : else if (gimple_code (g) == GIMPLE_COND)
974 : : {
975 : 28 : code = gimple_cond_code (g);
976 : 28 : op0 = gimple_cond_lhs (g);
977 : 28 : op1 = gimple_cond_rhs (g);
978 : : }
979 : :
980 : 201 : if ((code == EQ_EXPR || code == NE_EXPR)
981 : 201 : && op0 == use_lhs
982 : 402 : && integer_zerop (op1))
983 : : {
984 : 201 : use_operand_p use_p;
985 : 201 : int n = 0;
986 : 402 : FOR_EACH_IMM_USE_ON_STMT (use_p, iter)
987 : 201 : n++;
988 : 201 : if (n == 1)
989 : 201 : continue;
990 : : }
991 : :
992 : : use_bool = false;
993 : : break;
994 : 427 : }
995 : :
996 : 427 : tree new_lhs = make_ssa_name (TREE_TYPE (lhs));
997 : 427 : tree flag = build_int_cst (TREE_TYPE (lhs), use_bool);
998 : 427 : if (has_model_arg)
999 : 296 : g = gimple_build_call_internal (fn, 5, gimple_call_arg (call, 0),
1000 : : bit, flag, gimple_call_arg (call, 2),
1001 : : gimple_call_fn (call));
1002 : : else
1003 : 131 : g = gimple_build_call_internal (fn, 4, gimple_call_arg (call, 0),
1004 : : bit, flag, gimple_call_fn (call));
1005 : 427 : gimple_call_set_lhs (g, new_lhs);
1006 : 427 : gimple_set_location (g, gimple_location (call));
1007 : 427 : gimple_move_vops (g, call);
1008 : 427 : bool throws = stmt_can_throw_internal (cfun, call);
1009 : 427 : gimple_call_set_nothrow (as_a <gcall *> (g),
1010 : 427 : gimple_call_nothrow_p (as_a <gcall *> (call)));
1011 : 427 : gimple_stmt_iterator gsi = *gsip;
1012 : 427 : gsi_insert_after (&gsi, g, GSI_NEW_STMT);
1013 : 427 : edge e = NULL;
1014 : 427 : if (throws)
1015 : : {
1016 : 75 : maybe_clean_or_replace_eh_stmt (call, g);
1017 : 75 : if (after || (use_bool && has_debug_uses))
1018 : 9 : e = find_fallthru_edge (gsi_bb (gsi)->succs);
1019 : : }
1020 : 427 : if (after)
1021 : : {
1022 : : /* The internal function returns the value of the specified bit
1023 : : before the atomic operation. If we are interested in the value
1024 : : of the specified bit after the atomic operation (makes only sense
1025 : : for xor, otherwise the bit content is compile time known),
1026 : : we need to invert the bit. */
1027 : 55 : tree mask_convert = mask;
1028 : 55 : gimple_seq stmts = NULL;
1029 : 55 : if (!use_bool)
1030 : 43 : mask_convert = gimple_convert (&stmts, TREE_TYPE (lhs), mask);
1031 : 55 : new_lhs = gimple_build (&stmts, BIT_XOR_EXPR, TREE_TYPE (lhs), new_lhs,
1032 : 12 : use_bool ? build_int_cst (TREE_TYPE (lhs), 1)
1033 : : : mask_convert);
1034 : 55 : if (throws)
1035 : : {
1036 : 9 : gsi_insert_seq_on_edge_immediate (e, stmts);
1037 : 18 : gsi = gsi_for_stmt (gimple_seq_last (stmts));
1038 : : }
1039 : : else
1040 : 46 : gsi_insert_seq_after (&gsi, stmts, GSI_NEW_STMT);
1041 : : }
1042 : 427 : if (use_bool && has_debug_uses)
1043 : : {
1044 : 1 : tree temp = NULL_TREE;
1045 : 1 : if (!throws || after || single_pred_p (e->dest))
1046 : : {
1047 : 1 : temp = build_debug_expr_decl (TREE_TYPE (lhs));
1048 : 1 : tree t = build2 (LSHIFT_EXPR, TREE_TYPE (lhs), new_lhs, bit);
1049 : 1 : g = gimple_build_debug_bind (temp, t, g);
1050 : 1 : if (throws && !after)
1051 : : {
1052 : 0 : gsi = gsi_after_labels (e->dest);
1053 : 0 : gsi_insert_before (&gsi, g, GSI_SAME_STMT);
1054 : : }
1055 : : else
1056 : 1 : gsi_insert_after (&gsi, g, GSI_NEW_STMT);
1057 : : }
1058 : 4 : FOR_EACH_IMM_USE_STMT (g, iter, use_lhs)
1059 : 2 : if (is_gimple_debug (g))
1060 : : {
1061 : 1 : use_operand_p use_p;
1062 : 1 : if (temp == NULL_TREE)
1063 : 0 : gimple_debug_bind_reset_value (g);
1064 : : else
1065 : 3 : FOR_EACH_IMM_USE_ON_STMT (use_p, iter)
1066 : 1 : SET_USE (use_p, temp);
1067 : 1 : update_stmt (g);
1068 : 1 : }
1069 : : }
1070 : 427 : SSA_NAME_OCCURS_IN_ABNORMAL_PHI (new_lhs)
1071 : 427 : = SSA_NAME_OCCURS_IN_ABNORMAL_PHI (use_lhs);
1072 : 427 : replace_uses_by (use_lhs, new_lhs);
1073 : 427 : gsi = gsi_for_stmt (use_stmt);
1074 : 427 : gsi_remove (&gsi, true);
1075 : 427 : release_defs (use_stmt);
1076 : 427 : gsi_remove (gsip, true);
1077 : 427 : release_ssa_name (lhs);
1078 : 427 : return true;
1079 : : }
1080 : :
1081 : : /* Optimize
1082 : : _4 = __atomic_add_fetch_* (ptr_6, arg_2, _3);
1083 : : _5 = _4 == 0;
1084 : : to
1085 : : _4 = .ATOMIC_ADD_FETCH_CMP_0 (EQ_EXPR, ptr_6, arg_2, _3);
1086 : : _5 = _4;
1087 : : Similarly for __sync_add_and_fetch_* (without the ", _3" part
1088 : : in there). */
1089 : :
1090 : : static bool
1091 : 8978 : optimize_atomic_op_fetch_cmp_0 (gimple_stmt_iterator *gsip,
1092 : : enum internal_fn fn, bool has_model_arg)
1093 : : {
1094 : 8978 : gimple *call = gsi_stmt (*gsip);
1095 : 8978 : tree lhs = gimple_call_lhs (call);
1096 : 8978 : use_operand_p use_p;
1097 : 8978 : gimple *use_stmt;
1098 : :
1099 : 8978 : if (!flag_inline_atomics
1100 : 8978 : || !gimple_call_builtin_p (call, BUILT_IN_NORMAL)
1101 : 8978 : || !lhs
1102 : 6445 : || SSA_NAME_OCCURS_IN_ABNORMAL_PHI (lhs)
1103 : 6445 : || !single_imm_use (lhs, &use_p, &use_stmt)
1104 : 15241 : || !gimple_vdef (call))
1105 : 2715 : return false;
1106 : :
1107 : 6263 : optab optab;
1108 : 6263 : switch (fn)
1109 : : {
1110 : : case IFN_ATOMIC_ADD_FETCH_CMP_0:
1111 : : optab = atomic_add_fetch_cmp_0_optab;
1112 : : break;
1113 : : case IFN_ATOMIC_SUB_FETCH_CMP_0:
1114 : : optab = atomic_sub_fetch_cmp_0_optab;
1115 : : break;
1116 : : case IFN_ATOMIC_AND_FETCH_CMP_0:
1117 : : optab = atomic_and_fetch_cmp_0_optab;
1118 : : break;
1119 : : case IFN_ATOMIC_OR_FETCH_CMP_0:
1120 : : optab = atomic_or_fetch_cmp_0_optab;
1121 : : break;
1122 : : case IFN_ATOMIC_XOR_FETCH_CMP_0:
1123 : : optab = atomic_xor_fetch_cmp_0_optab;
1124 : : break;
1125 : : default:
1126 : : return false;
1127 : : }
1128 : :
1129 : 6263 : if (optab_handler (optab, TYPE_MODE (TREE_TYPE (lhs)))
1130 : : == CODE_FOR_nothing)
1131 : : return false;
1132 : :
1133 : 6245 : tree use_lhs = lhs;
1134 : 6245 : if (gimple_assign_cast_p (use_stmt))
1135 : : {
1136 : 925 : use_lhs = gimple_assign_lhs (use_stmt);
1137 : 925 : if (!tree_nop_conversion_p (TREE_TYPE (use_lhs), TREE_TYPE (lhs))
1138 : 911 : || (!INTEGRAL_TYPE_P (TREE_TYPE (use_lhs))
1139 : 95 : && !POINTER_TYPE_P (TREE_TYPE (use_lhs)))
1140 : 911 : || SSA_NAME_OCCURS_IN_ABNORMAL_PHI (use_lhs)
1141 : 1836 : || !single_imm_use (use_lhs, &use_p, &use_stmt))
1142 : 83 : return false;
1143 : : }
1144 : 6162 : enum tree_code code = ERROR_MARK;
1145 : 6162 : tree op0 = NULL_TREE, op1 = NULL_TREE;
1146 : 6162 : if (is_gimple_assign (use_stmt))
1147 : 1253 : switch (gimple_assign_rhs_code (use_stmt))
1148 : : {
1149 : 0 : case COND_EXPR:
1150 : 0 : op1 = gimple_assign_rhs1 (use_stmt);
1151 : 0 : code = TREE_CODE (op1);
1152 : 0 : if (TREE_CODE_CLASS (code) == tcc_comparison)
1153 : : {
1154 : 0 : op0 = TREE_OPERAND (op1, 0);
1155 : 0 : op1 = TREE_OPERAND (op1, 1);
1156 : : }
1157 : : break;
1158 : 1253 : default:
1159 : 1253 : code = gimple_assign_rhs_code (use_stmt);
1160 : 1253 : if (TREE_CODE_CLASS (code) == tcc_comparison)
1161 : : {
1162 : 842 : op0 = gimple_assign_rhs1 (use_stmt);
1163 : 842 : op1 = gimple_assign_rhs2 (use_stmt);
1164 : : }
1165 : : break;
1166 : : }
1167 : 4909 : else if (gimple_code (use_stmt) == GIMPLE_COND)
1168 : : {
1169 : 4394 : code = gimple_cond_code (use_stmt);
1170 : 4394 : op0 = gimple_cond_lhs (use_stmt);
1171 : 4394 : op1 = gimple_cond_rhs (use_stmt);
1172 : : }
1173 : :
1174 : 5647 : switch (code)
1175 : : {
1176 : 243 : case LT_EXPR:
1177 : 243 : case LE_EXPR:
1178 : 243 : case GT_EXPR:
1179 : 243 : case GE_EXPR:
1180 : 486 : if (!INTEGRAL_TYPE_P (TREE_TYPE (use_lhs))
1181 : 243 : || TREE_CODE (TREE_TYPE (use_lhs)) == BOOLEAN_TYPE
1182 : 486 : || TYPE_UNSIGNED (TREE_TYPE (use_lhs)))
1183 : : return false;
1184 : : /* FALLTHRU */
1185 : 5236 : case EQ_EXPR:
1186 : 5236 : case NE_EXPR:
1187 : 5236 : if (op0 == use_lhs && integer_zerop (op1))
1188 : : break;
1189 : : return false;
1190 : : default:
1191 : : return false;
1192 : : }
1193 : :
1194 : 2306 : int encoded;
1195 : 2306 : switch (code)
1196 : : {
1197 : : /* Use special encoding of the operation. We want to also
1198 : : encode the mode in the first argument and for neither EQ_EXPR
1199 : : etc. nor EQ etc. we can rely it will fit into QImode. */
1200 : : case EQ_EXPR: encoded = ATOMIC_OP_FETCH_CMP_0_EQ; break;
1201 : 877 : case NE_EXPR: encoded = ATOMIC_OP_FETCH_CMP_0_NE; break;
1202 : 106 : case LT_EXPR: encoded = ATOMIC_OP_FETCH_CMP_0_LT; break;
1203 : 40 : case LE_EXPR: encoded = ATOMIC_OP_FETCH_CMP_0_LE; break;
1204 : 40 : case GT_EXPR: encoded = ATOMIC_OP_FETCH_CMP_0_GT; break;
1205 : 48 : case GE_EXPR: encoded = ATOMIC_OP_FETCH_CMP_0_GE; break;
1206 : 0 : default: gcc_unreachable ();
1207 : : }
1208 : :
1209 : 2306 : tree new_lhs = make_ssa_name (boolean_type_node);
1210 : 2306 : gimple *g;
1211 : 2306 : tree flag = build_int_cst (TREE_TYPE (lhs), encoded);
1212 : 2306 : if (has_model_arg)
1213 : 1898 : g = gimple_build_call_internal (fn, 5, flag,
1214 : : gimple_call_arg (call, 0),
1215 : : gimple_call_arg (call, 1),
1216 : : gimple_call_arg (call, 2),
1217 : : gimple_call_fn (call));
1218 : : else
1219 : 408 : g = gimple_build_call_internal (fn, 4, flag,
1220 : : gimple_call_arg (call, 0),
1221 : : gimple_call_arg (call, 1),
1222 : : gimple_call_fn (call));
1223 : 2306 : gimple_call_set_lhs (g, new_lhs);
1224 : 2306 : gimple_set_location (g, gimple_location (call));
1225 : 2306 : gimple_move_vops (g, call);
1226 : 2306 : bool throws = stmt_can_throw_internal (cfun, call);
1227 : 2306 : gimple_call_set_nothrow (as_a <gcall *> (g),
1228 : 2306 : gimple_call_nothrow_p (as_a <gcall *> (call)));
1229 : 2306 : gimple_stmt_iterator gsi = *gsip;
1230 : 2306 : gsi_insert_after (&gsi, g, GSI_SAME_STMT);
1231 : 2306 : if (throws)
1232 : 0 : maybe_clean_or_replace_eh_stmt (call, g);
1233 : 2306 : if (is_gimple_assign (use_stmt))
1234 : 816 : switch (gimple_assign_rhs_code (use_stmt))
1235 : : {
1236 : 0 : case COND_EXPR:
1237 : 0 : gimple_assign_set_rhs1 (use_stmt, new_lhs);
1238 : 0 : break;
1239 : 816 : default:
1240 : 816 : gsi = gsi_for_stmt (use_stmt);
1241 : 816 : if (tree ulhs = gimple_assign_lhs (use_stmt))
1242 : 816 : if (useless_type_conversion_p (TREE_TYPE (ulhs),
1243 : : boolean_type_node))
1244 : : {
1245 : 816 : gimple_assign_set_rhs_with_ops (&gsi, SSA_NAME, new_lhs);
1246 : 816 : break;
1247 : : }
1248 : 0 : gimple_assign_set_rhs_with_ops (&gsi, NOP_EXPR, new_lhs);
1249 : 0 : break;
1250 : : }
1251 : 1490 : else if (gimple_code (use_stmt) == GIMPLE_COND)
1252 : : {
1253 : 1490 : gcond *use_cond = as_a <gcond *> (use_stmt);
1254 : 1490 : gimple_cond_set_code (use_cond, NE_EXPR);
1255 : 1490 : gimple_cond_set_lhs (use_cond, new_lhs);
1256 : 1490 : gimple_cond_set_rhs (use_cond, boolean_false_node);
1257 : : }
1258 : :
1259 : 2306 : update_stmt (use_stmt);
1260 : 2306 : if (use_lhs != lhs)
1261 : : {
1262 : 234 : gsi = gsi_for_stmt (SSA_NAME_DEF_STMT (use_lhs));
1263 : 234 : gsi_remove (&gsi, true);
1264 : 234 : release_ssa_name (use_lhs);
1265 : : }
1266 : 2306 : gsi_remove (gsip, true);
1267 : 2306 : release_ssa_name (lhs);
1268 : 2306 : return true;
1269 : : }
1270 : :
1271 : : /* Process builtin CALL located at GSI.
1272 : : Currently it is only fgr atomic functions optimizations from above. */
1273 : : static void
1274 : 6903896 : gimple_isel_builtin_call (gcall *call, gimple_stmt_iterator *gsi)
1275 : : {
1276 : : /* Don't handle these in non optimization mode or optimize debug mode. */
1277 : 6903896 : if (!optimize || optimize_debug)
1278 : : return;
1279 : :
1280 : 5387434 : if (!gimple_call_builtin_p (call, BUILT_IN_NORMAL))
1281 : : return;
1282 : :
1283 : 1355190 : tree callee = gimple_call_fndecl (call);
1284 : :
1285 : 1355190 : switch (DECL_FUNCTION_CODE (callee))
1286 : : {
1287 : : #define CASE_ATOMIC(NAME) \
1288 : : case BUILT_IN_##NAME##_1: \
1289 : : case BUILT_IN_##NAME##_2: \
1290 : : case BUILT_IN_##NAME##_4: \
1291 : : case BUILT_IN_##NAME##_8: \
1292 : : case BUILT_IN_##NAME##_16
1293 : : #define CASE_ATOMIC_CMP0(ATOMIC, SYNC) \
1294 : : CASE_ATOMIC(ATOMIC_##ATOMIC): \
1295 : : optimize_atomic_op_fetch_cmp_0 (gsi, \
1296 : : IFN_ATOMIC_##ATOMIC##_CMP_0, \
1297 : : true); \
1298 : : break; \
1299 : : CASE_ATOMIC(SYNC_##SYNC): \
1300 : : optimize_atomic_op_fetch_cmp_0 (gsi, \
1301 : : IFN_ATOMIC_##ATOMIC##_CMP_0, \
1302 : : false); \
1303 : : break;
1304 : :
1305 : :
1306 : 4150 : CASE_ATOMIC_CMP0(ADD_FETCH, ADD_AND_FETCH)
1307 : 2579 : CASE_ATOMIC_CMP0(SUB_FETCH, SUB_AND_FETCH)
1308 : 769 : CASE_ATOMIC_CMP0(AND_FETCH, AND_AND_FETCH)
1309 : 766 : CASE_ATOMIC_CMP0(OR_FETCH, OR_AND_FETCH)
1310 : : #define CASE_ATOMIC_BIT_TEST_AND(ATOMIC, SYNC, FN, AFTER) \
1311 : : CASE_ATOMIC(ATOMIC_##ATOMIC): \
1312 : : optimize_atomic_bit_test_and (gsi, \
1313 : : IFN_ATOMIC_BIT_TEST_AND_##FN, \
1314 : : true, AFTER); \
1315 : : break; \
1316 : : CASE_ATOMIC(SYNC_##SYNC): \
1317 : : optimize_atomic_bit_test_and (gsi, \
1318 : : IFN_ATOMIC_BIT_TEST_AND_##FN, \
1319 : : false, AFTER); \
1320 : : break;
1321 : 1429 : CASE_ATOMIC_BIT_TEST_AND(FETCH_OR, FETCH_AND_OR, SET, false)
1322 : 1278 : CASE_ATOMIC_BIT_TEST_AND(FETCH_XOR, FETCH_AND_XOR, COMPLEMENT, false)
1323 : 1137 : CASE_ATOMIC_BIT_TEST_AND(FETCH_AND, FETCH_AND_AND, RESET, false)
1324 : :
1325 : 569 : CASE_ATOMIC(ATOMIC_XOR_FETCH):
1326 : 569 : if (optimize_atomic_bit_test_and
1327 : 569 : (gsi, IFN_ATOMIC_BIT_TEST_AND_COMPLEMENT, true, true))
1328 : : break;
1329 : 531 : optimize_atomic_op_fetch_cmp_0 (gsi,
1330 : : IFN_ATOMIC_XOR_FETCH_CMP_0,
1331 : : true);
1332 : 531 : break;
1333 : 200 : CASE_ATOMIC(SYNC_XOR_AND_FETCH):
1334 : 200 : if (optimize_atomic_bit_test_and
1335 : 200 : (gsi, IFN_ATOMIC_BIT_TEST_AND_COMPLEMENT, false, true))
1336 : : break;
1337 : 183 : optimize_atomic_op_fetch_cmp_0 (gsi,
1338 : : IFN_ATOMIC_XOR_FETCH_CMP_0,
1339 : : false);
1340 : 183 : break;
1341 : :
1342 : 55 : default:;
1343 : : }
1344 : : }
1345 : :
1346 : : /* Iterate all gimple statements and perform pre RTL expansion
1347 : : GIMPLE massaging to improve instruction selection. */
1348 : :
1349 : : unsigned int
1350 : 1472883 : pass_gimple_isel::execute (struct function *fun)
1351 : : {
1352 : 1472883 : gimple_stmt_iterator gsi;
1353 : 1472883 : basic_block bb;
1354 : 1472883 : bool cfg_changed = false;
1355 : :
1356 : 17170772 : FOR_EACH_BB_FN (bb, fun)
1357 : : {
1358 : 128202511 : for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi))
1359 : : {
1360 : : /* Give the target first try at replacing the instruction. */
1361 : 96806733 : cfg_changed |= targetm.instruction_selection (fun, &gsi);
1362 : :
1363 : : /* Pre-expand VEC_COND_EXPRs to .VCOND* internal function
1364 : : calls mapping to supported optabs. */
1365 : 96806733 : gimple *g = gimple_expand_vec_cond_expr (&gsi);
1366 : 96806733 : if (g != NULL)
1367 : : {
1368 : 19104 : tree lhs = gimple_assign_lhs (gsi_stmt (gsi));
1369 : 19104 : gimple_set_lhs (g, lhs);
1370 : 19104 : gsi_replace (&gsi, g, false);
1371 : : }
1372 : :
1373 : : /* Recognize .VEC_SET and .VEC_EXTRACT patterns. */
1374 : 96806733 : cfg_changed |= gimple_expand_vec_set_extract_expr (fun, &gsi);
1375 : 96806733 : if (gsi_end_p (gsi))
1376 : : break;
1377 : :
1378 : 96806733 : if (gcall *call = dyn_cast <gcall*>(*gsi))
1379 : : {
1380 : 6903896 : gimple_isel_builtin_call (call, &gsi);
1381 : 6903896 : continue;
1382 : : }
1383 : 89902837 : gassign *stmt = dyn_cast <gassign *> (*gsi);
1384 : 89902837 : if (!stmt)
1385 : 57861113 : continue;
1386 : :
1387 : 32041724 : tree_code code = gimple_assign_rhs_code (stmt);
1388 : 32041724 : if (TREE_CODE_CLASS (code) == tcc_comparison)
1389 : 557250 : maybe_duplicate_comparison (stmt, bb);
1390 : : }
1391 : : }
1392 : :
1393 : 1472883 : return cfg_changed ? TODO_cleanup_cfg : 0;
1394 : : }
1395 : :
1396 : : } // anon namespace
1397 : :
1398 : : gimple_opt_pass *
1399 : 289302 : make_pass_gimple_isel (gcc::context *ctxt)
1400 : : {
1401 : 289302 : return new pass_gimple_isel (ctxt);
1402 : : }
1403 : :
|