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