Line data Source code
1 : /* Internal functions.
2 : Copyright (C) 2011-2026 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 under
7 : the terms of the GNU General Public License as published by the Free
8 : Software Foundation; either version 3, or (at your option) any later
9 : version.
10 :
11 : GCC is distributed in the hope that it will be useful, but WITHOUT ANY
12 : 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 : #define INCLUDE_MEMORY
22 : #include "system.h"
23 : #include "coretypes.h"
24 : #include "backend.h"
25 : #include "target.h"
26 : #include "rtl.h"
27 : #include "tree.h"
28 : #include "tree-eh.h"
29 : #include "gimple.h"
30 : #include "predict.h"
31 : #include "stringpool.h"
32 : #include "tree-vrp.h"
33 : #include "tree-ssanames.h"
34 : #include "expmed.h"
35 : #include "memmodel.h"
36 : #include "optabs.h"
37 : #include "emit-rtl.h"
38 : #include "diagnostic-core.h"
39 : #include "fold-const.h"
40 : #include "internal-fn.h"
41 : #include "stor-layout.h"
42 : #include "dojump.h"
43 : #include "expr.h"
44 : #include "attribs.h"
45 : #include "asan.h"
46 : #include "ubsan.h"
47 : #include "recog.h"
48 : #include "builtins.h"
49 : #include "optabs-tree.h"
50 : #include "gimple-ssa.h"
51 : #include "tree-phinodes.h"
52 : #include "ssa-iterators.h"
53 : #include "explow.h"
54 : #include "rtl-iter.h"
55 : #include "gimple-range.h"
56 : #include "fold-const-call.h"
57 : #include "tree-ssa-live.h"
58 : #include "tree-outof-ssa.h"
59 : #include "gcc-urlifier.h"
60 :
61 : /* For lang_hooks.types.type_for_mode. */
62 : #include "langhooks.h"
63 :
64 : /* The names of each internal function, indexed by function number. */
65 : const char *const internal_fn_name_array[] = {
66 : #define DEF_INTERNAL_FN(CODE, FLAGS, FNSPEC) #CODE,
67 : #include "internal-fn.def"
68 : "<invalid-fn>"
69 : };
70 :
71 : /* The ECF_* flags of each internal function, indexed by function number. */
72 : const int internal_fn_flags_array[] = {
73 : #define DEF_INTERNAL_FN(CODE, FLAGS, FNSPEC) FLAGS,
74 : #include "internal-fn.def"
75 : 0
76 : };
77 :
78 : /* Return the internal function called NAME, or IFN_LAST if there's
79 : no such function. */
80 :
81 : internal_fn
82 16 : lookup_internal_fn (const char *name)
83 : {
84 16 : typedef hash_map<nofree_string_hash, internal_fn> name_to_fn_map_type;
85 16 : static name_to_fn_map_type *name_to_fn_map;
86 :
87 16 : if (!name_to_fn_map)
88 : {
89 7 : name_to_fn_map = new name_to_fn_map_type (IFN_LAST);
90 2079 : for (unsigned int i = 0; i < IFN_LAST; ++i)
91 4144 : name_to_fn_map->put (internal_fn_name (internal_fn (i)),
92 2072 : internal_fn (i));
93 : }
94 16 : internal_fn *entry = name_to_fn_map->get (name);
95 16 : return entry ? *entry : IFN_LAST;
96 : }
97 :
98 : /* Geven an internal_fn IFN that is a widening function, return its
99 : corresponding LO and HI internal_fns. */
100 :
101 : extern void
102 70627 : lookup_hilo_internal_fn (internal_fn ifn, internal_fn *lo, internal_fn *hi)
103 : {
104 70627 : gcc_assert (widening_fn_p (ifn));
105 :
106 70627 : switch (ifn)
107 : {
108 0 : default:
109 0 : gcc_unreachable ();
110 : #define DEF_INTERNAL_FN(NAME, FLAGS, TYPE)
111 : #define DEF_INTERNAL_WIDENING_OPTAB_FN(NAME, F, S, SO, UO, T) \
112 : case IFN_##NAME: \
113 : *lo = internal_fn (IFN_##NAME##_LO); \
114 : *hi = internal_fn (IFN_##NAME##_HI); \
115 : break;
116 : #include "internal-fn.def"
117 : }
118 70627 : }
119 :
120 : /* Given an internal_fn IFN that is a widening function, return its
121 : corresponding _EVEN and _ODD internal_fns in *EVEN and *ODD. */
122 :
123 : extern void
124 70627 : lookup_evenodd_internal_fn (internal_fn ifn, internal_fn *even,
125 : internal_fn *odd)
126 : {
127 70627 : gcc_assert (widening_fn_p (ifn));
128 :
129 70627 : switch (ifn)
130 : {
131 0 : default:
132 0 : gcc_unreachable ();
133 : #define DEF_INTERNAL_FN(NAME, FLAGS, TYPE)
134 : #define DEF_INTERNAL_WIDENING_OPTAB_FN(NAME, F, S, SO, UO, T) \
135 : case IFN_##NAME: \
136 : *even = internal_fn (IFN_##NAME##_EVEN); \
137 : *odd = internal_fn (IFN_##NAME##_ODD); \
138 : break;
139 : #include "internal-fn.def"
140 : }
141 70627 : }
142 :
143 :
144 : /* Fnspec of each internal function, indexed by function number. */
145 : const_tree internal_fn_fnspec_array[IFN_LAST + 1];
146 :
147 : void
148 294223 : init_internal_fns ()
149 : {
150 : #define DEF_INTERNAL_FN(CODE, FLAGS, FNSPEC) \
151 : if (FNSPEC) internal_fn_fnspec_array[IFN_##CODE] = \
152 : build_string ((int) sizeof (FNSPEC) - 1, FNSPEC ? FNSPEC : "");
153 : #include "internal-fn.def"
154 294223 : internal_fn_fnspec_array[IFN_LAST] = 0;
155 294223 : }
156 :
157 : /* Create static initializers for the information returned by
158 : direct_internal_fn. */
159 : #define not_direct { -2, -2, false }
160 : #define mask_load_direct { -1, 2, false }
161 : #define load_lanes_direct { -1, -1, false }
162 : #define mask_load_lanes_direct { -1, -1, false }
163 : #define gather_load_direct { 3, 1, false }
164 : #define strided_load_direct { -1, -1, false }
165 : #define len_load_direct { -1, -1, false }
166 : #define mask_len_load_direct { -1, 4, false }
167 : #define mask_store_direct { 3, 2, false }
168 : #define store_lanes_direct { 0, 0, false }
169 : #define mask_store_lanes_direct { 0, 0, false }
170 : #define vec_cond_mask_direct { 1, 0, false }
171 : #define vec_cond_mask_len_direct { 1, 1, false }
172 : #define vec_cond_direct { 2, 0, false }
173 : #define scatter_store_direct { 3, 1, false }
174 : #define strided_store_direct { 1, 1, false }
175 : #define len_store_direct { 3, 3, false }
176 : #define mask_len_store_direct { 4, 5, false }
177 : #define vec_set_direct { 3, 3, false }
178 : #define vec_extract_direct { 0, -1, false }
179 : #define unary_direct { 0, 0, true }
180 : #define unary_convert_direct { -1, 0, true }
181 : #define binary_direct { 0, 0, true }
182 : #define ternary_direct { 0, 0, true }
183 : #define cond_unary_direct { 1, 1, true }
184 : #define cond_binary_direct { 1, 1, true }
185 : #define cond_ternary_direct { 1, 1, true }
186 : #define cond_len_unary_direct { 1, 1, true }
187 : #define cond_len_binary_direct { 1, 1, true }
188 : #define cond_len_ternary_direct { 1, 1, true }
189 : #define while_direct { 0, 2, false }
190 : #define fold_extract_direct { 2, 2, false }
191 : #define fold_len_extract_direct { 2, 2, false }
192 : #define fold_left_direct { 1, 1, false }
193 : #define mask_fold_left_direct { 1, 1, false }
194 : #define mask_len_fold_left_direct { 1, 1, false }
195 : #define check_ptrs_direct { 0, 0, false }
196 : #define crc_direct { 1, -1, true }
197 : #define reduc_sbool_direct { 0, 0, true }
198 : #define select_vl_direct { 2, 0, false }
199 :
200 : const direct_internal_fn_info direct_internal_fn_array[IFN_LAST + 1] = {
201 : #define DEF_INTERNAL_FN(CODE, FLAGS, FNSPEC) not_direct,
202 : #define DEF_INTERNAL_OPTAB_FN(CODE, FLAGS, OPTAB, TYPE) TYPE##_direct,
203 : #define DEF_INTERNAL_SIGNED_OPTAB_FN(CODE, FLAGS, SELECTOR, SIGNED_OPTAB, \
204 : UNSIGNED_OPTAB, TYPE) TYPE##_direct,
205 : #include "internal-fn.def"
206 : not_direct
207 : };
208 :
209 : /* Like create_output_operand, but for callers that will use
210 : assign_call_lhs afterwards. */
211 :
212 : static void
213 87714 : create_call_lhs_operand (expand_operand *op, rtx lhs_rtx, machine_mode mode)
214 : {
215 : /* Do not assign directly to a promoted subreg, since there is no
216 : guarantee that the instruction will leave the upper bits of the
217 : register in the state required by SUBREG_PROMOTED_SIGN. */
218 87714 : rtx dest = lhs_rtx;
219 87714 : if (dest && GET_CODE (dest) == SUBREG && SUBREG_PROMOTED_VAR_P (dest))
220 87714 : dest = NULL_RTX;
221 87714 : create_output_operand (op, dest, mode);
222 87714 : }
223 :
224 : /* Move the result of an expanded instruction into the lhs of a gimple call.
225 : LHS is the lhs of the call, LHS_RTX is its expanded form, and OP is the
226 : result of the expanded instruction. OP should have been set up by
227 : create_call_lhs_operand. */
228 :
229 : static void
230 87714 : assign_call_lhs (tree lhs, rtx lhs_rtx, expand_operand *op)
231 : {
232 87714 : if (rtx_equal_p (lhs_rtx, op->value))
233 : return;
234 :
235 : /* If the return value has an integral type, convert the instruction
236 : result to that type. This is useful for things that return an
237 : int regardless of the size of the input. If the instruction result
238 : is smaller than required, assume that it is signed.
239 :
240 : If the return value has a nonintegral type, its mode must match
241 : the instruction result. */
242 3489 : if (GET_CODE (lhs_rtx) == SUBREG && SUBREG_PROMOTED_VAR_P (lhs_rtx))
243 : {
244 : /* If this is a scalar in a register that is stored in a wider
245 : mode than the declared mode, compute the result into its
246 : declared mode and then convert to the wider mode. */
247 0 : gcc_checking_assert (INTEGRAL_TYPE_P (TREE_TYPE (lhs)));
248 0 : rtx tmp = convert_to_mode (GET_MODE (lhs_rtx), op->value, 0);
249 0 : convert_move (SUBREG_REG (lhs_rtx), tmp,
250 0 : SUBREG_PROMOTED_SIGN (lhs_rtx));
251 : }
252 3489 : else if (GET_MODE (lhs_rtx) == GET_MODE (op->value))
253 40 : emit_move_insn (lhs_rtx, op->value);
254 : else
255 : {
256 3449 : gcc_checking_assert (INTEGRAL_TYPE_P (TREE_TYPE (lhs)));
257 3449 : convert_move (lhs_rtx, op->value, 0);
258 : }
259 : }
260 :
261 : /* Expand STMT using instruction ICODE. The instruction has NOUTPUTS
262 : output operands and NINPUTS input operands, where NOUTPUTS is either
263 : 0 or 1. The output operand (if any) comes first, followed by the
264 : NINPUTS input operands. */
265 :
266 : static void
267 77152 : expand_fn_using_insn (gcall *stmt, insn_code icode, unsigned int noutputs,
268 : unsigned int ninputs)
269 : {
270 77152 : gcc_assert (icode != CODE_FOR_nothing);
271 :
272 77152 : expand_operand *ops = XALLOCAVEC (expand_operand, noutputs + ninputs);
273 77152 : unsigned int opno = 0;
274 77152 : rtx lhs_rtx = NULL_RTX;
275 77152 : tree lhs = gimple_call_lhs (stmt);
276 :
277 77152 : if (noutputs)
278 : {
279 77152 : gcc_assert (noutputs == 1);
280 77152 : if (lhs)
281 77152 : lhs_rtx = expand_expr (lhs, NULL_RTX, VOIDmode, EXPAND_WRITE);
282 77152 : create_call_lhs_operand (&ops[opno], lhs_rtx,
283 77152 : insn_data[icode].operand[opno].mode);
284 77152 : opno += 1;
285 : }
286 : else
287 0 : gcc_assert (!lhs);
288 :
289 220502 : for (unsigned int i = 0; i < ninputs; ++i)
290 : {
291 143350 : tree rhs = gimple_call_arg (stmt, i);
292 143350 : tree rhs_type = TREE_TYPE (rhs);
293 143350 : rtx rhs_rtx = expand_normal (rhs);
294 143350 : if (INTEGRAL_TYPE_P (rhs_type))
295 7258 : create_convert_operand_from (&ops[opno], rhs_rtx,
296 7258 : TYPE_MODE (rhs_type),
297 7258 : TYPE_UNSIGNED (rhs_type));
298 136092 : else if (TREE_CODE (rhs) == SSA_NAME
299 110894 : && SSA_NAME_IS_DEFAULT_DEF (rhs)
300 140596 : && VAR_P (SSA_NAME_VAR (rhs)))
301 247 : create_undefined_input_operand (&ops[opno], TYPE_MODE (rhs_type));
302 55680 : else if (VECTOR_BOOLEAN_TYPE_P (rhs_type)
303 1519 : && SCALAR_INT_MODE_P (TYPE_MODE (rhs_type))
304 137364 : && maybe_ne (GET_MODE_PRECISION (TYPE_MODE (rhs_type)),
305 1519 : TYPE_VECTOR_SUBPARTS (rhs_type).to_constant ()))
306 : {
307 : /* Ensure that the vector bitmasks do not have excess bits. */
308 427 : int nunits = TYPE_VECTOR_SUBPARTS (rhs_type).to_constant ();
309 427 : rtx tmp = expand_binop (TYPE_MODE (rhs_type), and_optab, rhs_rtx,
310 427 : GEN_INT ((HOST_WIDE_INT_1U << nunits) - 1),
311 : NULL_RTX, true, OPTAB_WIDEN);
312 427 : create_input_operand (&ops[opno], tmp, TYPE_MODE (rhs_type));
313 : }
314 : else
315 135418 : create_input_operand (&ops[opno], rhs_rtx, TYPE_MODE (rhs_type));
316 143350 : opno += 1;
317 : }
318 :
319 77152 : gcc_assert (opno == noutputs + ninputs);
320 77152 : expand_insn (icode, opno, ops);
321 77152 : if (lhs_rtx)
322 77152 : assign_call_lhs (lhs, lhs_rtx, &ops[0]);
323 77152 : }
324 :
325 : /* ARRAY_TYPE is an array of vector modes. Return the associated insn
326 : for load-lanes-style optab OPTAB, or CODE_FOR_nothing if none. */
327 :
328 : static enum insn_code
329 0 : get_multi_vector_move (tree array_type, convert_optab optab)
330 : {
331 0 : machine_mode imode;
332 0 : machine_mode vmode;
333 :
334 0 : gcc_assert (TREE_CODE (array_type) == ARRAY_TYPE);
335 0 : imode = TYPE_MODE (array_type);
336 0 : vmode = TYPE_MODE (TREE_TYPE (array_type));
337 :
338 0 : return convert_optab_handler (optab, imode, vmode);
339 : }
340 :
341 : /* Add mask, else, and len arguments according to the STMT. */
342 :
343 : static unsigned int
344 1401 : add_mask_else_and_len_args (expand_operand *ops, unsigned int opno, gcall *stmt)
345 : {
346 1401 : internal_fn ifn = gimple_call_internal_fn (stmt);
347 1401 : int len_index = internal_fn_len_index (ifn);
348 : /* BIAS is always consecutive next of LEN. */
349 1401 : int bias_index = len_index + 1;
350 1401 : int mask_index = internal_fn_mask_index (ifn);
351 :
352 : /* The order of arguments is always {mask, else, len, bias}. */
353 1401 : if (mask_index >= 0)
354 : {
355 1401 : tree mask = gimple_call_arg (stmt, mask_index);
356 1401 : rtx mask_rtx = expand_normal (mask);
357 :
358 1401 : tree mask_type = TREE_TYPE (mask);
359 1401 : if (VECTOR_BOOLEAN_TYPE_P (mask_type)
360 1400 : && SCALAR_INT_MODE_P (TYPE_MODE (mask_type))
361 2445 : && maybe_ne (GET_MODE_PRECISION (TYPE_MODE (mask_type)),
362 2198 : TYPE_VECTOR_SUBPARTS (mask_type).to_constant ()))
363 : {
364 : /* Ensure that the vector bitmasks do not have excess bits. */
365 247 : int nunits = TYPE_VECTOR_SUBPARTS (mask_type).to_constant ();
366 247 : mask_rtx = expand_binop (TYPE_MODE (mask_type), and_optab, mask_rtx,
367 247 : GEN_INT ((HOST_WIDE_INT_1U << nunits) - 1),
368 : NULL_RTX, true, OPTAB_WIDEN);
369 : }
370 :
371 1401 : create_input_operand (&ops[opno++], mask_rtx,
372 1401 : TYPE_MODE (TREE_TYPE (mask)));
373 : }
374 :
375 1401 : int els_index = internal_fn_else_index (ifn);
376 1401 : if (els_index >= 0)
377 : {
378 675 : tree els = gimple_call_arg (stmt, els_index);
379 675 : tree els_type = TREE_TYPE (els);
380 675 : if (TREE_CODE (els) == SSA_NAME
381 0 : && SSA_NAME_IS_DEFAULT_DEF (els)
382 675 : && VAR_P (SSA_NAME_VAR (els)))
383 0 : create_undefined_input_operand (&ops[opno++], TYPE_MODE (els_type));
384 : else
385 : {
386 675 : rtx els_rtx = expand_normal (els);
387 675 : create_input_operand (&ops[opno++], els_rtx, TYPE_MODE (els_type));
388 : }
389 : }
390 1401 : if (len_index >= 0)
391 : {
392 0 : tree len = gimple_call_arg (stmt, len_index);
393 0 : rtx len_rtx = expand_normal (len);
394 0 : create_convert_operand_from (&ops[opno++], len_rtx,
395 0 : TYPE_MODE (TREE_TYPE (len)),
396 0 : TYPE_UNSIGNED (TREE_TYPE (len)));
397 0 : tree biast = gimple_call_arg (stmt, bias_index);
398 0 : rtx bias = expand_normal (biast);
399 0 : create_input_operand (&ops[opno++], bias, QImode);
400 : }
401 1401 : return opno;
402 : }
403 :
404 : /* Expand LOAD_LANES call STMT using optab OPTAB. */
405 :
406 : static void
407 0 : expand_load_lanes_optab_fn (internal_fn, gcall *stmt, convert_optab optab)
408 : {
409 0 : class expand_operand ops[2];
410 0 : tree type, lhs, rhs;
411 0 : rtx target, mem;
412 :
413 0 : lhs = gimple_call_lhs (stmt);
414 0 : rhs = gimple_call_arg (stmt, 0);
415 0 : type = TREE_TYPE (lhs);
416 :
417 0 : target = expand_expr (lhs, NULL_RTX, VOIDmode, EXPAND_WRITE);
418 0 : mem = expand_normal (rhs);
419 :
420 0 : gcc_assert (MEM_P (mem));
421 0 : PUT_MODE (mem, TYPE_MODE (type));
422 :
423 0 : create_call_lhs_operand (&ops[0], target, TYPE_MODE (type));
424 0 : create_fixed_operand (&ops[1], mem);
425 0 : expand_insn (get_multi_vector_move (type, optab), 2, ops);
426 0 : assign_call_lhs (lhs, target, &ops[0]);
427 0 : }
428 :
429 : /* Expand STORE_LANES call STMT using optab OPTAB. */
430 :
431 : static void
432 0 : expand_store_lanes_optab_fn (internal_fn, gcall *stmt, convert_optab optab)
433 : {
434 0 : class expand_operand ops[2];
435 0 : tree type, lhs, rhs;
436 0 : rtx target, reg;
437 :
438 0 : lhs = gimple_call_lhs (stmt);
439 0 : rhs = gimple_call_arg (stmt, 0);
440 0 : type = TREE_TYPE (rhs);
441 :
442 0 : target = expand_expr (lhs, NULL_RTX, VOIDmode, EXPAND_WRITE);
443 0 : reg = expand_normal (rhs);
444 :
445 0 : gcc_assert (MEM_P (target));
446 0 : PUT_MODE (target, TYPE_MODE (type));
447 :
448 0 : create_fixed_operand (&ops[0], target);
449 0 : create_input_operand (&ops[1], reg, TYPE_MODE (type));
450 0 : expand_insn (get_multi_vector_move (type, optab), 2, ops);
451 0 : }
452 :
453 : static void
454 0 : expand_ANNOTATE (internal_fn, gcall *)
455 : {
456 0 : gcc_unreachable ();
457 : }
458 :
459 : /* This should get expanded in omp_device_lower pass. */
460 :
461 : static void
462 0 : expand_GOMP_USE_SIMT (internal_fn, gcall *)
463 : {
464 0 : gcc_unreachable ();
465 : }
466 :
467 : /* This should get expanded in omp_device_lower pass. */
468 :
469 : static void
470 0 : expand_GOMP_SIMT_ENTER (internal_fn, gcall *)
471 : {
472 0 : gcc_unreachable ();
473 : }
474 :
475 : /* Allocate per-lane storage and begin non-uniform execution region. */
476 :
477 : static void
478 0 : expand_GOMP_SIMT_ENTER_ALLOC (internal_fn, gcall *stmt)
479 : {
480 0 : rtx target;
481 0 : tree lhs = gimple_call_lhs (stmt);
482 0 : if (lhs)
483 0 : target = expand_expr (lhs, NULL_RTX, VOIDmode, EXPAND_WRITE);
484 : else
485 0 : target = gen_reg_rtx (Pmode);
486 0 : rtx size = expand_normal (gimple_call_arg (stmt, 0));
487 0 : rtx align = expand_normal (gimple_call_arg (stmt, 1));
488 0 : class expand_operand ops[3];
489 0 : create_call_lhs_operand (&ops[0], target, Pmode);
490 0 : create_input_operand (&ops[1], size, Pmode);
491 0 : create_input_operand (&ops[2], align, Pmode);
492 0 : gcc_assert (targetm.have_omp_simt_enter ());
493 0 : expand_insn (targetm.code_for_omp_simt_enter, 3, ops);
494 0 : assign_call_lhs (lhs, target, &ops[0]);
495 0 : }
496 :
497 : /* Deallocate per-lane storage and leave non-uniform execution region. */
498 :
499 : static void
500 0 : expand_GOMP_SIMT_EXIT (internal_fn, gcall *stmt)
501 : {
502 0 : gcc_checking_assert (!gimple_call_lhs (stmt));
503 0 : rtx arg = expand_normal (gimple_call_arg (stmt, 0));
504 0 : class expand_operand ops[1];
505 0 : create_input_operand (&ops[0], arg, Pmode);
506 0 : gcc_assert (targetm.have_omp_simt_exit ());
507 0 : expand_insn (targetm.code_for_omp_simt_exit, 1, ops);
508 0 : }
509 :
510 : /* Lane index on SIMT targets: thread index in the warp on NVPTX. On targets
511 : without SIMT execution this should be expanded in omp_device_lower pass. */
512 :
513 : static void
514 0 : expand_GOMP_SIMT_LANE (internal_fn, gcall *stmt)
515 : {
516 0 : tree lhs = gimple_call_lhs (stmt);
517 0 : if (!lhs)
518 : return;
519 :
520 0 : rtx target = expand_expr (lhs, NULL_RTX, VOIDmode, EXPAND_WRITE);
521 0 : gcc_assert (targetm.have_omp_simt_lane ());
522 0 : emit_insn (targetm.gen_omp_simt_lane (target));
523 : }
524 :
525 : /* This should get expanded in omp_device_lower pass. */
526 :
527 : static void
528 0 : expand_GOMP_SIMT_VF (internal_fn, gcall *)
529 : {
530 0 : gcc_unreachable ();
531 : }
532 :
533 : /* This should get expanded in omp_device_lower pass. */
534 :
535 : static void
536 0 : expand_GOMP_MAX_VF (internal_fn, gcall *)
537 : {
538 0 : gcc_unreachable ();
539 : }
540 :
541 : /* This should get expanded in omp_device_lower pass. */
542 :
543 : static void
544 0 : expand_GOMP_TARGET_REV (internal_fn, gcall *)
545 : {
546 0 : gcc_unreachable ();
547 : }
548 :
549 : /* Lane index of the first SIMT lane that supplies a non-zero argument.
550 : This is a SIMT counterpart to GOMP_SIMD_LAST_LANE, used to represent the
551 : lane that executed the last iteration for handling OpenMP lastprivate. */
552 :
553 : static void
554 0 : expand_GOMP_SIMT_LAST_LANE (internal_fn, gcall *stmt)
555 : {
556 0 : tree lhs = gimple_call_lhs (stmt);
557 0 : if (!lhs)
558 0 : return;
559 :
560 0 : rtx target = expand_expr (lhs, NULL_RTX, VOIDmode, EXPAND_WRITE);
561 0 : rtx cond = expand_normal (gimple_call_arg (stmt, 0));
562 0 : machine_mode mode = TYPE_MODE (TREE_TYPE (lhs));
563 0 : class expand_operand ops[2];
564 0 : create_call_lhs_operand (&ops[0], target, mode);
565 0 : create_input_operand (&ops[1], cond, mode);
566 0 : gcc_assert (targetm.have_omp_simt_last_lane ());
567 0 : expand_insn (targetm.code_for_omp_simt_last_lane, 2, ops);
568 0 : assign_call_lhs (lhs, target, &ops[0]);
569 : }
570 :
571 : /* Non-transparent predicate used in SIMT lowering of OpenMP "ordered". */
572 :
573 : static void
574 0 : expand_GOMP_SIMT_ORDERED_PRED (internal_fn, gcall *stmt)
575 : {
576 0 : tree lhs = gimple_call_lhs (stmt);
577 0 : if (!lhs)
578 0 : return;
579 :
580 0 : rtx target = expand_expr (lhs, NULL_RTX, VOIDmode, EXPAND_WRITE);
581 0 : rtx ctr = expand_normal (gimple_call_arg (stmt, 0));
582 0 : machine_mode mode = TYPE_MODE (TREE_TYPE (lhs));
583 0 : class expand_operand ops[2];
584 0 : create_call_lhs_operand (&ops[0], target, mode);
585 0 : create_input_operand (&ops[1], ctr, mode);
586 0 : gcc_assert (targetm.have_omp_simt_ordered ());
587 0 : expand_insn (targetm.code_for_omp_simt_ordered, 2, ops);
588 0 : assign_call_lhs (lhs, target, &ops[0]);
589 : }
590 :
591 : /* "Or" boolean reduction across SIMT lanes: return non-zero in all lanes if
592 : any lane supplies a non-zero argument. */
593 :
594 : static void
595 0 : expand_GOMP_SIMT_VOTE_ANY (internal_fn, gcall *stmt)
596 : {
597 0 : tree lhs = gimple_call_lhs (stmt);
598 0 : if (!lhs)
599 0 : return;
600 :
601 0 : rtx target = expand_expr (lhs, NULL_RTX, VOIDmode, EXPAND_WRITE);
602 0 : rtx cond = expand_normal (gimple_call_arg (stmt, 0));
603 0 : machine_mode mode = TYPE_MODE (TREE_TYPE (lhs));
604 0 : class expand_operand ops[2];
605 0 : create_call_lhs_operand (&ops[0], target, mode);
606 0 : create_input_operand (&ops[1], cond, mode);
607 0 : gcc_assert (targetm.have_omp_simt_vote_any ());
608 0 : expand_insn (targetm.code_for_omp_simt_vote_any, 2, ops);
609 0 : assign_call_lhs (lhs, target, &ops[0]);
610 : }
611 :
612 : /* Exchange between SIMT lanes with a "butterfly" pattern: source lane index
613 : is destination lane index XOR given offset. */
614 :
615 : static void
616 0 : expand_GOMP_SIMT_XCHG_BFLY (internal_fn, gcall *stmt)
617 : {
618 0 : tree lhs = gimple_call_lhs (stmt);
619 0 : if (!lhs)
620 0 : return;
621 :
622 0 : rtx target = expand_expr (lhs, NULL_RTX, VOIDmode, EXPAND_WRITE);
623 0 : rtx src = expand_normal (gimple_call_arg (stmt, 0));
624 0 : rtx idx = expand_normal (gimple_call_arg (stmt, 1));
625 0 : machine_mode mode = TYPE_MODE (TREE_TYPE (lhs));
626 0 : class expand_operand ops[3];
627 0 : create_call_lhs_operand (&ops[0], target, mode);
628 0 : create_input_operand (&ops[1], src, mode);
629 0 : create_input_operand (&ops[2], idx, SImode);
630 0 : gcc_assert (targetm.have_omp_simt_xchg_bfly ());
631 0 : expand_insn (targetm.code_for_omp_simt_xchg_bfly, 3, ops);
632 0 : assign_call_lhs (lhs, target, &ops[0]);
633 : }
634 :
635 : /* Exchange between SIMT lanes according to given source lane index. */
636 :
637 : static void
638 0 : expand_GOMP_SIMT_XCHG_IDX (internal_fn, gcall *stmt)
639 : {
640 0 : tree lhs = gimple_call_lhs (stmt);
641 0 : if (!lhs)
642 0 : return;
643 :
644 0 : rtx target = expand_expr (lhs, NULL_RTX, VOIDmode, EXPAND_WRITE);
645 0 : rtx src = expand_normal (gimple_call_arg (stmt, 0));
646 0 : rtx idx = expand_normal (gimple_call_arg (stmt, 1));
647 0 : machine_mode mode = TYPE_MODE (TREE_TYPE (lhs));
648 0 : class expand_operand ops[3];
649 0 : create_call_lhs_operand (&ops[0], target, mode);
650 0 : create_input_operand (&ops[1], src, mode);
651 0 : create_input_operand (&ops[2], idx, SImode);
652 0 : gcc_assert (targetm.have_omp_simt_xchg_idx ());
653 0 : expand_insn (targetm.code_for_omp_simt_xchg_idx, 3, ops);
654 0 : assign_call_lhs (lhs, target, &ops[0]);
655 : }
656 :
657 : /* This should get expanded in adjust_simduid_builtins. */
658 :
659 : static void
660 0 : expand_GOMP_SIMD_LANE (internal_fn, gcall *)
661 : {
662 0 : gcc_unreachable ();
663 : }
664 :
665 : /* This should get expanded in adjust_simduid_builtins. */
666 :
667 : static void
668 0 : expand_GOMP_SIMD_VF (internal_fn, gcall *)
669 : {
670 0 : gcc_unreachable ();
671 : }
672 :
673 : /* This should get expanded in adjust_simduid_builtins. */
674 :
675 : static void
676 0 : expand_GOMP_SIMD_LAST_LANE (internal_fn, gcall *)
677 : {
678 0 : gcc_unreachable ();
679 : }
680 :
681 : /* This should get expanded in adjust_simduid_builtins. */
682 :
683 : static void
684 0 : expand_GOMP_SIMD_ORDERED_START (internal_fn, gcall *)
685 : {
686 0 : gcc_unreachable ();
687 : }
688 :
689 : /* This should get expanded in adjust_simduid_builtins. */
690 :
691 : static void
692 0 : expand_GOMP_SIMD_ORDERED_END (internal_fn, gcall *)
693 : {
694 0 : gcc_unreachable ();
695 : }
696 :
697 : /* This should get expanded in gimplify_omp_dispatch. */
698 :
699 : static void
700 0 : expand_GOMP_DISPATCH (internal_fn, gcall *)
701 : {
702 0 : gcc_unreachable ();
703 : }
704 :
705 : /* This should get expanded in the sanopt pass. */
706 :
707 : static void
708 0 : expand_UBSAN_NULL (internal_fn, gcall *)
709 : {
710 0 : gcc_unreachable ();
711 : }
712 :
713 : /* This should get expanded in the sanopt pass. */
714 :
715 : static void
716 0 : expand_UBSAN_BOUNDS (internal_fn, gcall *)
717 : {
718 0 : gcc_unreachable ();
719 : }
720 :
721 : /* This should get expanded in the sanopt pass. */
722 :
723 : static void
724 0 : expand_UBSAN_VPTR (internal_fn, gcall *)
725 : {
726 0 : gcc_unreachable ();
727 : }
728 :
729 : /* This should get expanded in the sanopt pass. */
730 :
731 : static void
732 0 : expand_UBSAN_PTR (internal_fn, gcall *)
733 : {
734 0 : gcc_unreachable ();
735 : }
736 :
737 : /* This should get expanded in the sanopt pass. */
738 :
739 : static void
740 0 : expand_UBSAN_OBJECT_SIZE (internal_fn, gcall *)
741 : {
742 0 : gcc_unreachable ();
743 : }
744 :
745 : /* This should get expanded in the sanopt pass. */
746 :
747 : static void
748 0 : expand_HWASAN_CHECK (internal_fn, gcall *)
749 : {
750 0 : gcc_unreachable ();
751 : }
752 :
753 : /* For hwasan stack tagging:
754 : Tag memory which is dynamically allocated. */
755 : static void
756 0 : expand_HWASAN_ALLOCA_POISON (internal_fn, gcall *gc)
757 : {
758 0 : gcc_assert (ptr_mode == Pmode);
759 0 : tree g_target = gimple_call_lhs (gc);
760 0 : tree g_ptr = gimple_call_arg (gc, 0);
761 0 : tree g_size = gimple_call_arg (gc, 1);
762 :
763 : /* There is no target; this happens, usually, when we have an alloca of zero
764 : size. */
765 0 : if (!g_target)
766 : return;
767 0 : rtx target = expand_normal (g_target);
768 0 : rtx ptr = expand_normal (g_ptr);
769 0 : rtx size = expand_normal (g_size);
770 :
771 : /* No size, nothing to do. */
772 0 : if (size == const0_rtx)
773 : return;
774 :
775 : /* Get new tag for the alloca'd memory.
776 : Doing a regular add_tag () like so:
777 : rtx tag = targetm.memtag.add_tag (hwasan_frame_base (), 0,
778 : hwasan_current_frame_tag ());
779 : gets a new tag, which can be used for tagging memory. But for alloca, we
780 : need both tagged memory and a tagged pointer to pass to consumers. Invoke
781 : insert_random_tag () instead to add a random tag to ptr to get a tagged
782 : pointer that will work for both purposes. */
783 0 : rtx tagged_ptr
784 0 : = force_reg (Pmode, targetm.memtag.insert_random_tag (ptr, NULL_RTX));
785 0 : rtx tag = targetm.memtag.extract_tag (tagged_ptr, NULL_RTX);
786 :
787 0 : if (memtag_sanitize_p ())
788 : {
789 : /* Need to put the tagged ptr into the `target` RTX for consumers
790 : of alloca'd memory. */
791 0 : if (tagged_ptr != target)
792 0 : emit_move_insn (target, tagged_ptr);
793 : /* Tag the memory. */
794 0 : emit_insn (targetm.gen_tag_memory (ptr, tag, size));
795 0 : hwasan_increment_frame_tag ();
796 : }
797 : else
798 0 : gcc_unreachable ();
799 : }
800 :
801 : /* For hwasan stack tagging:
802 : Clear tags on the dynamically allocated space.
803 : For use after an object dynamically allocated on the stack goes out of
804 : scope. */
805 : static void
806 0 : expand_HWASAN_ALLOCA_UNPOISON (internal_fn, gcall *gc)
807 : {
808 0 : gcc_assert (Pmode == ptr_mode);
809 0 : tree restored_position = gimple_call_arg (gc, 0);
810 0 : rtx restored_rtx = expand_expr (restored_position, NULL_RTX, VOIDmode,
811 : EXPAND_NORMAL);
812 0 : rtx off = expand_simple_binop (Pmode, MINUS, restored_rtx,
813 : stack_pointer_rtx, NULL_RTX, 0,
814 : OPTAB_WIDEN);
815 :
816 0 : if (memtag_sanitize_p ())
817 0 : emit_insn (targetm.gen_tag_memory (virtual_stack_dynamic_rtx,
818 : HWASAN_STACK_BACKGROUND,
819 : off));
820 : else
821 : {
822 0 : rtx func = init_one_libfunc ("__hwasan_tag_memory");
823 0 : emit_library_call_value (func, NULL_RTX, LCT_NORMAL, VOIDmode,
824 0 : virtual_stack_dynamic_rtx, Pmode,
825 : HWASAN_STACK_BACKGROUND, QImode,
826 0 : off, Pmode);
827 : }
828 0 : }
829 :
830 : /* For hwasan stack tagging:
831 : Return a tag to be used for a dynamic allocation. */
832 : static void
833 0 : expand_HWASAN_CHOOSE_TAG (internal_fn, gcall *gc)
834 : {
835 0 : tree tag = gimple_call_lhs (gc);
836 0 : rtx target = expand_expr (tag, NULL_RTX, VOIDmode, EXPAND_NORMAL);
837 0 : machine_mode mode = GET_MODE (target);
838 0 : gcc_assert (mode == QImode);
839 :
840 0 : rtx base_tag = targetm.memtag.extract_tag (hwasan_frame_base (), NULL_RTX);
841 0 : gcc_assert (base_tag);
842 0 : rtx tag_offset = gen_int_mode (hwasan_current_frame_tag (), QImode);
843 0 : rtx chosen_tag = expand_simple_binop (QImode, PLUS, base_tag, tag_offset,
844 : target, /* unsignedp = */1,
845 : OPTAB_WIDEN);
846 0 : chosen_tag = hwasan_truncate_to_tag_size (chosen_tag, target);
847 :
848 : /* Really need to put the tag into the `target` RTX. */
849 0 : if (chosen_tag != target)
850 : {
851 0 : rtx temp = chosen_tag;
852 0 : gcc_assert (GET_MODE (chosen_tag) == mode);
853 0 : emit_move_insn (target, temp);
854 : }
855 :
856 0 : hwasan_increment_frame_tag ();
857 0 : }
858 :
859 : /* For hwasan stack tagging:
860 : Tag a region of space in the shadow stack according to the base pointer of
861 : an object on the stack. N.b. the length provided in the internal call is
862 : required to be aligned to HWASAN_TAG_GRANULE_SIZE. */
863 : static void
864 0 : expand_HWASAN_MARK (internal_fn, gcall *gc)
865 : {
866 0 : gcc_assert (ptr_mode == Pmode);
867 0 : HOST_WIDE_INT flag = tree_to_shwi (gimple_call_arg (gc, 0));
868 0 : bool is_poison = ((asan_mark_flags)flag) == ASAN_MARK_POISON;
869 :
870 0 : tree base = gimple_call_arg (gc, 1);
871 0 : gcc_checking_assert (TREE_CODE (base) == ADDR_EXPR);
872 0 : rtx base_rtx = expand_normal (base);
873 :
874 0 : rtx tag = is_poison ? HWASAN_STACK_BACKGROUND
875 0 : : targetm.memtag.extract_tag (base_rtx, NULL_RTX);
876 0 : rtx address = targetm.memtag.untagged_pointer (base_rtx, NULL_RTX);
877 :
878 0 : tree len = gimple_call_arg (gc, 2);
879 0 : rtx r_len = expand_normal (len);
880 :
881 0 : if (memtag_sanitize_p ())
882 0 : emit_insn (targetm.gen_tag_memory (address, tag, r_len));
883 : else
884 : {
885 0 : rtx func = init_one_libfunc ("__hwasan_tag_memory");
886 0 : emit_library_call (func, LCT_NORMAL, VOIDmode, address, Pmode,
887 0 : tag, QImode, r_len, Pmode);
888 : }
889 0 : }
890 :
891 : /* For hwasan stack tagging:
892 : Store a tag into a pointer. */
893 : static void
894 0 : expand_HWASAN_SET_TAG (internal_fn, gcall *gc)
895 : {
896 0 : gcc_assert (ptr_mode == Pmode);
897 0 : tree g_target = gimple_call_lhs (gc);
898 0 : tree g_ptr = gimple_call_arg (gc, 0);
899 0 : tree g_tag = gimple_call_arg (gc, 1);
900 :
901 0 : rtx ptr = expand_normal (g_ptr);
902 0 : rtx tag = expand_expr (g_tag, NULL_RTX, QImode, EXPAND_NORMAL);
903 0 : rtx target = expand_normal (g_target);
904 :
905 0 : rtx untagged = targetm.memtag.untagged_pointer (ptr, target);
906 0 : rtx tagged_value = targetm.memtag.set_tag (untagged, tag, target);
907 0 : if (tagged_value != target)
908 0 : emit_move_insn (target, tagged_value);
909 0 : }
910 :
911 : /* This should get expanded in the sanopt pass. */
912 :
913 : static void
914 0 : expand_ASAN_CHECK (internal_fn, gcall *)
915 : {
916 0 : gcc_unreachable ();
917 : }
918 :
919 : /* This should get expanded in the sanopt pass. */
920 :
921 : static void
922 0 : expand_ASAN_MARK (internal_fn, gcall *)
923 : {
924 0 : gcc_unreachable ();
925 : }
926 :
927 : /* This should get expanded in the sanopt pass. */
928 :
929 : static void
930 0 : expand_ASAN_POISON (internal_fn, gcall *)
931 : {
932 0 : gcc_unreachable ();
933 : }
934 :
935 : /* This should get expanded in the sanopt pass. */
936 :
937 : static void
938 0 : expand_ASAN_POISON_USE (internal_fn, gcall *)
939 : {
940 0 : gcc_unreachable ();
941 : }
942 :
943 : /* This should get expanded in the tsan pass. */
944 :
945 : static void
946 0 : expand_TSAN_FUNC_EXIT (internal_fn, gcall *)
947 : {
948 0 : gcc_unreachable ();
949 : }
950 :
951 : /* This should get expanded in the lower pass. */
952 :
953 : static void
954 25 : expand_FALLTHROUGH (internal_fn, gcall *call)
955 : {
956 25 : auto_urlify_attributes sentinel;
957 25 : error_at (gimple_location (call),
958 : "invalid use of attribute %<fallthrough%>");
959 25 : }
960 :
961 : /* Return minimum precision needed to represent all values
962 : of ARG in SIGNed integral type. */
963 :
964 : static int
965 156858 : get_min_precision (tree arg, signop sign)
966 : {
967 156858 : int prec = TYPE_PRECISION (TREE_TYPE (arg));
968 156858 : int cnt = 0;
969 156858 : signop orig_sign = sign;
970 156858 : if (TREE_CODE (arg) == INTEGER_CST)
971 : {
972 40630 : int p;
973 40630 : if (TYPE_SIGN (TREE_TYPE (arg)) != sign)
974 : {
975 14548 : widest_int w = wi::to_widest (arg);
976 14548 : w = wi::ext (w, prec, sign);
977 14548 : p = wi::min_precision (w, sign);
978 14548 : }
979 : else
980 26082 : p = wi::min_precision (wi::to_wide (arg), sign);
981 40630 : return MIN (p, prec);
982 : }
983 116183 : while (CONVERT_EXPR_P (arg)
984 7371 : && INTEGRAL_TYPE_P (TREE_TYPE (TREE_OPERAND (arg, 0)))
985 130925 : && TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (arg, 0))) <= prec)
986 : {
987 7371 : arg = TREE_OPERAND (arg, 0);
988 7371 : if (TYPE_PRECISION (TREE_TYPE (arg)) < prec)
989 : {
990 1109 : if (TYPE_UNSIGNED (TREE_TYPE (arg)))
991 : sign = UNSIGNED;
992 805 : else if (sign == UNSIGNED
993 805 : && (get_range_pos_neg (arg,
994 : currently_expanding_gimple_stmt)
995 : != 1))
996 45 : return prec + (orig_sign != sign);
997 1064 : prec = TYPE_PRECISION (TREE_TYPE (arg));
998 : }
999 7326 : if (++cnt > 30)
1000 0 : return prec + (orig_sign != sign);
1001 : }
1002 116183 : if (CONVERT_EXPR_P (arg)
1003 0 : && INTEGRAL_TYPE_P (TREE_TYPE (TREE_OPERAND (arg, 0)))
1004 116183 : && TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (arg, 0))) > prec)
1005 : {
1006 : /* We have e.g. (unsigned short) y_2 where int y_2 = (int) x_1(D);
1007 : If y_2's min precision is smaller than prec, return that. */
1008 0 : int oprec = get_min_precision (TREE_OPERAND (arg, 0), sign);
1009 0 : if (oprec < prec)
1010 0 : return oprec + (orig_sign != sign);
1011 : }
1012 116183 : if (TREE_CODE (arg) != SSA_NAME)
1013 0 : return prec + (orig_sign != sign);
1014 116183 : int_range_max r;
1015 116183 : gimple *cg = currently_expanding_gimple_stmt;
1016 237949 : while (!get_range_query (cfun)->range_of_expr (r, arg, cg)
1017 121766 : || r.varying_p ()
1018 252800 : || r.undefined_p ())
1019 : {
1020 112499 : gimple *g = SSA_NAME_DEF_STMT (arg);
1021 112499 : if (is_gimple_assign (g)
1022 112499 : && CONVERT_EXPR_CODE_P (gimple_assign_rhs_code (g)))
1023 : {
1024 6684 : tree t = gimple_assign_rhs1 (g);
1025 13368 : if (INTEGRAL_TYPE_P (TREE_TYPE (t))
1026 12372 : && TYPE_PRECISION (TREE_TYPE (t)) <= prec)
1027 : {
1028 5590 : arg = t;
1029 5590 : if (TYPE_PRECISION (TREE_TYPE (arg)) < prec)
1030 : {
1031 5208 : if (TYPE_UNSIGNED (TREE_TYPE (arg)))
1032 : sign = UNSIGNED;
1033 2884 : else if (sign == UNSIGNED
1034 2884 : && get_range_pos_neg (arg, g) != 1)
1035 7 : return prec + (orig_sign != sign);
1036 5201 : prec = TYPE_PRECISION (TREE_TYPE (arg));
1037 : }
1038 5583 : if (++cnt > 30)
1039 0 : return prec + (orig_sign != sign);
1040 5583 : continue;
1041 : }
1042 : }
1043 106909 : return prec + (orig_sign != sign);
1044 : }
1045 9267 : if (sign == TYPE_SIGN (TREE_TYPE (arg)))
1046 : {
1047 8685 : int p1 = wi::min_precision (r.lower_bound (), sign);
1048 8685 : int p2 = wi::min_precision (r.upper_bound (), sign);
1049 8685 : p1 = MAX (p1, p2);
1050 8685 : prec = MIN (prec, p1);
1051 : }
1052 1140 : else if (sign == UNSIGNED && !wi::neg_p (r.lower_bound (), SIGNED))
1053 : {
1054 554 : int p = wi::min_precision (r.upper_bound (), UNSIGNED);
1055 582 : prec = MIN (prec, p);
1056 : }
1057 9267 : return prec + (orig_sign != sign);
1058 116183 : }
1059 :
1060 : /* Helper for expand_*_overflow. Set the __imag__ part to true
1061 : (1 except for signed:1 type, in which case store -1). */
1062 :
1063 : static void
1064 82096 : expand_arith_set_overflow (tree lhs, rtx target)
1065 : {
1066 82096 : if (TYPE_PRECISION (TREE_TYPE (TREE_TYPE (lhs))) == 1
1067 82096 : && !TYPE_UNSIGNED (TREE_TYPE (TREE_TYPE (lhs))))
1068 202 : write_complex_part (target, constm1_rtx, true, false);
1069 : else
1070 81894 : write_complex_part (target, const1_rtx, true, false);
1071 82096 : }
1072 :
1073 : /* Helper for expand_*_overflow. Store RES into the __real__ part
1074 : of TARGET. If RES has larger MODE than __real__ part of TARGET,
1075 : set the __imag__ part to 1 if RES doesn't fit into it. Similarly
1076 : if LHS has smaller precision than its mode. */
1077 :
1078 : static void
1079 72049 : expand_arith_overflow_result_store (tree lhs, rtx target,
1080 : scalar_int_mode mode, rtx res)
1081 : {
1082 72049 : scalar_int_mode tgtmode
1083 144098 : = as_a <scalar_int_mode> (GET_MODE_INNER (GET_MODE (target)));
1084 72049 : rtx lres = res;
1085 72049 : if (tgtmode != mode)
1086 : {
1087 18872 : rtx_code_label *done_label = gen_label_rtx ();
1088 18872 : int uns = TYPE_UNSIGNED (TREE_TYPE (TREE_TYPE (lhs)));
1089 18872 : lres = convert_modes (tgtmode, mode, res, uns);
1090 18872 : gcc_assert (GET_MODE_PRECISION (tgtmode) < GET_MODE_PRECISION (mode));
1091 18872 : do_compare_rtx_and_jump (res, convert_modes (mode, tgtmode, lres, uns),
1092 : EQ, true, mode, NULL_RTX, NULL, done_label,
1093 : profile_probability::very_likely ());
1094 18872 : expand_arith_set_overflow (lhs, target);
1095 18872 : emit_label (done_label);
1096 : }
1097 72049 : int prec = TYPE_PRECISION (TREE_TYPE (TREE_TYPE (lhs)));
1098 72049 : int tgtprec = GET_MODE_PRECISION (tgtmode);
1099 72049 : if (prec < tgtprec)
1100 : {
1101 3553 : rtx_code_label *done_label = gen_label_rtx ();
1102 3553 : int uns = TYPE_UNSIGNED (TREE_TYPE (TREE_TYPE (lhs)));
1103 3553 : res = lres;
1104 3553 : if (uns)
1105 : {
1106 2008 : rtx mask
1107 2008 : = immed_wide_int_const (wi::shifted_mask (0, prec, false, tgtprec),
1108 : tgtmode);
1109 2008 : lres = expand_simple_binop (tgtmode, AND, res, mask, NULL_RTX,
1110 : true, OPTAB_LIB_WIDEN);
1111 : }
1112 : else
1113 : {
1114 1545 : lres = expand_shift (LSHIFT_EXPR, tgtmode, res, tgtprec - prec,
1115 : NULL_RTX, 1);
1116 1545 : lres = expand_shift (RSHIFT_EXPR, tgtmode, lres, tgtprec - prec,
1117 : NULL_RTX, 0);
1118 : }
1119 3553 : do_compare_rtx_and_jump (res, lres,
1120 : EQ, true, tgtmode, NULL_RTX, NULL, done_label,
1121 : profile_probability::very_likely ());
1122 3553 : expand_arith_set_overflow (lhs, target);
1123 3553 : emit_label (done_label);
1124 : }
1125 72049 : write_complex_part (target, lres, false, false);
1126 72049 : }
1127 :
1128 : /* Helper for expand_*_overflow. Store RES into TARGET. */
1129 :
1130 : static void
1131 4675 : expand_ubsan_result_store (tree lhs, rtx target, scalar_int_mode mode,
1132 : rtx res, rtx_code_label *do_error)
1133 : {
1134 9296 : if (BITINT_TYPE_P (TREE_TYPE (lhs))
1135 4675 : && TYPE_PRECISION (TREE_TYPE (lhs)) < GET_MODE_PRECISION (mode))
1136 : {
1137 54 : int uns = TYPE_UNSIGNED (TREE_TYPE (lhs));
1138 54 : int prec = TYPE_PRECISION (TREE_TYPE (lhs));
1139 54 : int tgtprec = GET_MODE_PRECISION (mode);
1140 54 : rtx resc = gen_reg_rtx (mode), lres;
1141 54 : emit_move_insn (resc, res);
1142 54 : if (uns)
1143 : {
1144 0 : rtx mask
1145 0 : = immed_wide_int_const (wi::shifted_mask (0, prec, false, tgtprec),
1146 : mode);
1147 0 : lres = expand_simple_binop (mode, AND, res, mask, NULL_RTX,
1148 : true, OPTAB_LIB_WIDEN);
1149 : }
1150 : else
1151 : {
1152 54 : lres = expand_shift (LSHIFT_EXPR, mode, res, tgtprec - prec,
1153 : NULL_RTX, 1);
1154 54 : lres = expand_shift (RSHIFT_EXPR, mode, lres, tgtprec - prec,
1155 : NULL_RTX, 0);
1156 : }
1157 54 : if (lres != res)
1158 54 : emit_move_insn (res, lres);
1159 54 : do_compare_rtx_and_jump (res, resc,
1160 : NE, true, mode, NULL_RTX, NULL, do_error,
1161 : profile_probability::very_unlikely ());
1162 : }
1163 4675 : if (GET_CODE (target) == SUBREG && SUBREG_PROMOTED_VAR_P (target))
1164 : /* If this is a scalar in a register that is stored in a wider mode
1165 : than the declared mode, compute the result into its declared mode
1166 : and then convert to the wider mode. Our value is the computed
1167 : expression. */
1168 0 : convert_move (SUBREG_REG (target), res, SUBREG_PROMOTED_SIGN (target));
1169 : else
1170 4675 : emit_move_insn (target, res);
1171 4675 : }
1172 :
1173 : /* Add sub/add overflow checking to the statement STMT.
1174 : CODE says whether the operation is +, or -. */
1175 :
1176 : void
1177 39124 : expand_addsub_overflow (location_t loc, tree_code code, tree lhs,
1178 : tree arg0, tree arg1, bool unsr_p, bool uns0_p,
1179 : bool uns1_p, bool is_ubsan, tree *datap)
1180 : {
1181 39124 : rtx res, target = NULL_RTX;
1182 39124 : tree fn;
1183 39124 : rtx_code_label *done_label = gen_label_rtx ();
1184 39124 : rtx_code_label *do_error = gen_label_rtx ();
1185 39124 : do_pending_stack_adjust ();
1186 39124 : rtx op0 = expand_normal (arg0);
1187 39124 : rtx op1 = expand_normal (arg1);
1188 39124 : scalar_int_mode mode = SCALAR_INT_TYPE_MODE (TREE_TYPE (arg0));
1189 39124 : int prec = GET_MODE_PRECISION (mode);
1190 39124 : rtx sgn = immed_wide_int_const (wi::min_value (prec, SIGNED), mode);
1191 39124 : bool do_xor = false;
1192 :
1193 39124 : if (is_ubsan)
1194 3391 : gcc_assert (!unsr_p && !uns0_p && !uns1_p);
1195 :
1196 39124 : if (lhs)
1197 : {
1198 38596 : target = expand_expr (lhs, NULL_RTX, VOIDmode, EXPAND_WRITE);
1199 38596 : if (!is_ubsan)
1200 35733 : write_complex_part (target, const0_rtx, true, false);
1201 : }
1202 :
1203 : /* We assume both operands and result have the same precision
1204 : here (GET_MODE_BITSIZE (mode)), S stands for signed type
1205 : with that precision, U for unsigned type with that precision,
1206 : sgn for unsigned most significant bit in that precision.
1207 : s1 is signed first operand, u1 is unsigned first operand,
1208 : s2 is signed second operand, u2 is unsigned second operand,
1209 : sr is signed result, ur is unsigned result and the following
1210 : rules say how to compute result (which is always result of
1211 : the operands as if both were unsigned, cast to the right
1212 : signedness) and how to compute whether operation overflowed.
1213 :
1214 : s1 + s2 -> sr
1215 : res = (S) ((U) s1 + (U) s2)
1216 : ovf = s2 < 0 ? res > s1 : res < s1 (or jump on overflow)
1217 : s1 - s2 -> sr
1218 : res = (S) ((U) s1 - (U) s2)
1219 : ovf = s2 < 0 ? res < s1 : res > s2 (or jump on overflow)
1220 : u1 + u2 -> ur
1221 : res = u1 + u2
1222 : ovf = res < u1 (or jump on carry, but RTL opts will handle it)
1223 : u1 - u2 -> ur
1224 : res = u1 - u2
1225 : ovf = res > u1 (or jump on carry, but RTL opts will handle it)
1226 : s1 + u2 -> sr
1227 : res = (S) ((U) s1 + u2)
1228 : ovf = ((U) res ^ sgn) < u2
1229 : s1 + u2 -> ur
1230 : t1 = (S) (u2 ^ sgn)
1231 : t2 = s1 + t1
1232 : res = (U) t2 ^ sgn
1233 : ovf = t1 < 0 ? t2 > s1 : t2 < s1 (or jump on overflow)
1234 : s1 - u2 -> sr
1235 : res = (S) ((U) s1 - u2)
1236 : ovf = u2 > ((U) s1 ^ sgn)
1237 : s1 - u2 -> ur
1238 : res = (U) s1 - u2
1239 : ovf = s1 < 0 || u2 > (U) s1
1240 : u1 - s2 -> sr
1241 : res = u1 - (U) s2
1242 : ovf = u1 >= ((U) s2 ^ sgn)
1243 : u1 - s2 -> ur
1244 : t1 = u1 ^ sgn
1245 : t2 = t1 - (U) s2
1246 : res = t2 ^ sgn
1247 : ovf = s2 < 0 ? (S) t2 < (S) t1 : (S) t2 > (S) t1 (or jump on overflow)
1248 : s1 + s2 -> ur
1249 : res = (U) s1 + (U) s2
1250 : ovf = s2 < 0 ? (s1 | (S) res) < 0) : (s1 & (S) res) < 0)
1251 : u1 + u2 -> sr
1252 : res = (S) (u1 + u2)
1253 : ovf = (U) res < u2 || res < 0
1254 : u1 - u2 -> sr
1255 : res = (S) (u1 - u2)
1256 : ovf = u1 >= u2 ? res < 0 : res >= 0
1257 : s1 - s2 -> ur
1258 : res = (U) s1 - (U) s2
1259 : ovf = s2 >= 0 ? ((s1 | (S) res) < 0) : ((s1 & (S) res) < 0) */
1260 :
1261 39124 : if (code == PLUS_EXPR && uns0_p && !uns1_p)
1262 : {
1263 : /* PLUS_EXPR is commutative, if operand signedness differs,
1264 : canonicalize to the first operand being signed and second
1265 : unsigned to simplify following code. */
1266 : std::swap (op0, op1);
1267 : std::swap (arg0, arg1);
1268 : uns0_p = false;
1269 : uns1_p = true;
1270 : }
1271 :
1272 : /* u1 +- u2 -> ur */
1273 38341 : if (uns0_p && uns1_p && unsr_p)
1274 : {
1275 20528 : insn_code icode = optab_handler (code == PLUS_EXPR ? uaddv4_optab
1276 : : usubv4_optab, mode);
1277 15421 : if (icode != CODE_FOR_nothing)
1278 : {
1279 14592 : class expand_operand ops[4];
1280 14592 : rtx_insn *last = get_last_insn ();
1281 :
1282 14592 : res = gen_reg_rtx (mode);
1283 14592 : create_output_operand (&ops[0], res, mode);
1284 14592 : create_input_operand (&ops[1], op0, mode);
1285 14592 : create_input_operand (&ops[2], op1, mode);
1286 14592 : create_fixed_operand (&ops[3], do_error);
1287 14592 : if (maybe_expand_insn (icode, 4, ops))
1288 : {
1289 14592 : last = get_last_insn ();
1290 14592 : if (profile_status_for_fn (cfun) != PROFILE_ABSENT
1291 12256 : && JUMP_P (last)
1292 12256 : && any_condjump_p (last)
1293 26848 : && !find_reg_note (last, REG_BR_PROB, 0))
1294 12256 : add_reg_br_prob_note (last,
1295 : profile_probability::very_unlikely ());
1296 14592 : emit_jump (done_label);
1297 14592 : goto do_error_label;
1298 : }
1299 :
1300 0 : delete_insns_since (last);
1301 : }
1302 :
1303 : /* Compute the operation. On RTL level, the addition is always
1304 : unsigned. */
1305 1658 : res = expand_binop (mode, code == PLUS_EXPR ? add_optab : sub_optab,
1306 : op0, op1, NULL_RTX, false, OPTAB_LIB_WIDEN);
1307 829 : rtx tem = op0;
1308 : /* For PLUS_EXPR, the operation is commutative, so we can pick
1309 : operand to compare against. For prec <= BITS_PER_WORD, I think
1310 : preferring REG operand is better over CONST_INT, because
1311 : the CONST_INT might enlarge the instruction or CSE would need
1312 : to figure out we'd already loaded it into a register before.
1313 : For prec > BITS_PER_WORD, I think CONST_INT might be more beneficial,
1314 : as then the multi-word comparison can be perhaps simplified. */
1315 829 : if (code == PLUS_EXPR
1316 0 : && (prec <= BITS_PER_WORD
1317 0 : ? (CONST_SCALAR_INT_P (op0) && REG_P (op1))
1318 0 : : CONST_SCALAR_INT_P (op1)))
1319 829 : tem = op1;
1320 1658 : do_compare_rtx_and_jump (res, tem, code == PLUS_EXPR ? GEU : LEU,
1321 : true, mode, NULL_RTX, NULL, done_label,
1322 : profile_probability::very_likely ());
1323 829 : goto do_error_label;
1324 : }
1325 :
1326 : /* s1 +- u2 -> sr */
1327 23703 : if (!uns0_p && uns1_p && !unsr_p)
1328 : {
1329 : /* Compute the operation. On RTL level, the addition is always
1330 : unsigned. */
1331 2514 : res = expand_binop (mode, code == PLUS_EXPR ? add_optab : sub_optab,
1332 : op0, op1, NULL_RTX, false, OPTAB_LIB_WIDEN);
1333 2514 : rtx tem = expand_binop (mode, add_optab,
1334 : code == PLUS_EXPR ? res : op0, sgn,
1335 : NULL_RTX, false, OPTAB_LIB_WIDEN);
1336 1582 : do_compare_rtx_and_jump (tem, op1, GEU, true, mode, NULL_RTX, NULL,
1337 : done_label, profile_probability::very_likely ());
1338 1582 : goto do_error_label;
1339 : }
1340 :
1341 : /* s1 + u2 -> ur */
1342 22121 : if (code == PLUS_EXPR && !uns0_p && uns1_p && unsr_p)
1343 : {
1344 1691 : op1 = expand_binop (mode, add_optab, op1, sgn, NULL_RTX, false,
1345 : OPTAB_LIB_WIDEN);
1346 : /* As we've changed op1, we have to avoid using the value range
1347 : for the original argument. */
1348 1691 : arg1 = error_mark_node;
1349 1691 : do_xor = true;
1350 1691 : goto do_signed;
1351 : }
1352 :
1353 : /* u1 - s2 -> ur */
1354 20430 : if (code == MINUS_EXPR && uns0_p && !uns1_p && unsr_p)
1355 : {
1356 846 : op0 = expand_binop (mode, add_optab, op0, sgn, NULL_RTX, false,
1357 : OPTAB_LIB_WIDEN);
1358 : /* As we've changed op0, we have to avoid using the value range
1359 : for the original argument. */
1360 846 : arg0 = error_mark_node;
1361 846 : do_xor = true;
1362 846 : goto do_signed;
1363 : }
1364 :
1365 : /* s1 - u2 -> ur */
1366 19584 : if (code == MINUS_EXPR && !uns0_p && uns1_p && unsr_p)
1367 : {
1368 : /* Compute the operation. On RTL level, the addition is always
1369 : unsigned. */
1370 1374 : res = expand_binop (mode, sub_optab, op0, op1, NULL_RTX, false,
1371 : OPTAB_LIB_WIDEN);
1372 1374 : int pos_neg = get_range_pos_neg (arg0, currently_expanding_gimple_stmt);
1373 1374 : if (pos_neg == 2)
1374 : /* If ARG0 is known to be always negative, this is always overflow. */
1375 39 : emit_jump (do_error);
1376 1335 : else if (pos_neg == 3)
1377 : /* If ARG0 is not known to be always positive, check at runtime. */
1378 1335 : do_compare_rtx_and_jump (op0, const0_rtx, LT, false, mode, NULL_RTX,
1379 : NULL, do_error, profile_probability::very_unlikely ());
1380 1374 : do_compare_rtx_and_jump (op1, op0, LEU, true, mode, NULL_RTX, NULL,
1381 : done_label, profile_probability::very_likely ());
1382 1374 : goto do_error_label;
1383 : }
1384 :
1385 : /* u1 - s2 -> sr */
1386 18210 : if (code == MINUS_EXPR && uns0_p && !uns1_p && !unsr_p)
1387 : {
1388 : /* Compute the operation. On RTL level, the addition is always
1389 : unsigned. */
1390 481 : res = expand_binop (mode, sub_optab, op0, op1, NULL_RTX, false,
1391 : OPTAB_LIB_WIDEN);
1392 481 : rtx tem = expand_binop (mode, add_optab, op1, sgn, NULL_RTX, false,
1393 : OPTAB_LIB_WIDEN);
1394 481 : do_compare_rtx_and_jump (op0, tem, LTU, true, mode, NULL_RTX, NULL,
1395 : done_label, profile_probability::very_likely ());
1396 481 : goto do_error_label;
1397 : }
1398 :
1399 : /* u1 + u2 -> sr */
1400 17729 : if (code == PLUS_EXPR && uns0_p && uns1_p && !unsr_p)
1401 : {
1402 : /* Compute the operation. On RTL level, the addition is always
1403 : unsigned. */
1404 1192 : res = expand_binop (mode, add_optab, op0, op1, NULL_RTX, false,
1405 : OPTAB_LIB_WIDEN);
1406 1192 : do_compare_rtx_and_jump (res, const0_rtx, LT, false, mode, NULL_RTX,
1407 : NULL, do_error, profile_probability::very_unlikely ());
1408 1192 : rtx tem = op1;
1409 : /* The operation is commutative, so we can pick operand to compare
1410 : against. For prec <= BITS_PER_WORD, I think preferring REG operand
1411 : is better over CONST_INT, because the CONST_INT might enlarge the
1412 : instruction or CSE would need to figure out we'd already loaded it
1413 : into a register before. For prec > BITS_PER_WORD, I think CONST_INT
1414 : might be more beneficial, as then the multi-word comparison can be
1415 : perhaps simplified. */
1416 1192 : if (prec <= BITS_PER_WORD
1417 1192 : ? (CONST_SCALAR_INT_P (op1) && REG_P (op0))
1418 408 : : CONST_SCALAR_INT_P (op0))
1419 1192 : tem = op0;
1420 1192 : do_compare_rtx_and_jump (res, tem, GEU, true, mode, NULL_RTX, NULL,
1421 : done_label, profile_probability::very_likely ());
1422 1192 : goto do_error_label;
1423 : }
1424 :
1425 : /* s1 +- s2 -> ur */
1426 16537 : if (!uns0_p && !uns1_p && unsr_p)
1427 : {
1428 : /* Compute the operation. On RTL level, the addition is always
1429 : unsigned. */
1430 3825 : res = expand_binop (mode, code == PLUS_EXPR ? add_optab : sub_optab,
1431 : op0, op1, NULL_RTX, false, OPTAB_LIB_WIDEN);
1432 2589 : int pos_neg = get_range_pos_neg (arg1, currently_expanding_gimple_stmt);
1433 2589 : if (code == PLUS_EXPR)
1434 : {
1435 1353 : int pos_neg0 = get_range_pos_neg (arg0,
1436 : currently_expanding_gimple_stmt);
1437 1353 : if (pos_neg0 != 3 && pos_neg == 3)
1438 : {
1439 : std::swap (op0, op1);
1440 : pos_neg = pos_neg0;
1441 : }
1442 : }
1443 2589 : rtx tem;
1444 2589 : if (pos_neg != 3)
1445 : {
1446 1585 : tem = expand_binop (mode, ((pos_neg == 1) ^ (code == MINUS_EXPR))
1447 : ? and_optab : ior_optab,
1448 : op0, res, NULL_RTX, false, OPTAB_LIB_WIDEN);
1449 935 : do_compare_rtx_and_jump (tem, const0_rtx, GE, false, mode, NULL,
1450 : NULL, done_label, profile_probability::very_likely ());
1451 : }
1452 : else
1453 : {
1454 1654 : rtx_code_label *do_ior_label = gen_label_rtx ();
1455 2357 : do_compare_rtx_and_jump (op1, const0_rtx,
1456 : code == MINUS_EXPR ? GE : LT, false, mode,
1457 : NULL_RTX, NULL, do_ior_label,
1458 : profile_probability::even ());
1459 1654 : tem = expand_binop (mode, and_optab, op0, res, NULL_RTX, false,
1460 : OPTAB_LIB_WIDEN);
1461 1654 : do_compare_rtx_and_jump (tem, const0_rtx, GE, false, mode, NULL_RTX,
1462 : NULL, done_label, profile_probability::very_likely ());
1463 1654 : emit_jump (do_error);
1464 1654 : emit_label (do_ior_label);
1465 1654 : tem = expand_binop (mode, ior_optab, op0, res, NULL_RTX, false,
1466 : OPTAB_LIB_WIDEN);
1467 1654 : do_compare_rtx_and_jump (tem, const0_rtx, GE, false, mode, NULL_RTX,
1468 : NULL, done_label, profile_probability::very_likely ());
1469 : }
1470 2589 : goto do_error_label;
1471 : }
1472 :
1473 : /* u1 - u2 -> sr */
1474 13948 : if (code == MINUS_EXPR && uns0_p && uns1_p && !unsr_p)
1475 : {
1476 : /* Compute the operation. On RTL level, the addition is always
1477 : unsigned. */
1478 1729 : res = expand_binop (mode, sub_optab, op0, op1, NULL_RTX, false,
1479 : OPTAB_LIB_WIDEN);
1480 1729 : rtx_code_label *op0_geu_op1 = gen_label_rtx ();
1481 1729 : do_compare_rtx_and_jump (op0, op1, GEU, true, mode, NULL_RTX, NULL,
1482 : op0_geu_op1, profile_probability::even ());
1483 1729 : do_compare_rtx_and_jump (res, const0_rtx, LT, false, mode, NULL_RTX,
1484 : NULL, done_label, profile_probability::very_likely ());
1485 1729 : emit_jump (do_error);
1486 1729 : emit_label (op0_geu_op1);
1487 1729 : do_compare_rtx_and_jump (res, const0_rtx, GE, false, mode, NULL_RTX,
1488 : NULL, done_label, profile_probability::very_likely ());
1489 1729 : goto do_error_label;
1490 : }
1491 :
1492 12219 : gcc_assert (!uns0_p && !uns1_p && !unsr_p);
1493 :
1494 : /* s1 +- s2 -> sr */
1495 12219 : do_signed:
1496 14756 : {
1497 21405 : insn_code icode = optab_handler (code == PLUS_EXPR ? addv4_optab
1498 : : subv4_optab, mode);
1499 14756 : if (icode != CODE_FOR_nothing)
1500 : {
1501 14756 : class expand_operand ops[4];
1502 14756 : rtx_insn *last = get_last_insn ();
1503 :
1504 14756 : res = gen_reg_rtx (mode);
1505 14756 : create_output_operand (&ops[0], res, mode);
1506 14756 : create_input_operand (&ops[1], op0, mode);
1507 14756 : create_input_operand (&ops[2], op1, mode);
1508 14756 : create_fixed_operand (&ops[3], do_error);
1509 14756 : if (maybe_expand_insn (icode, 4, ops))
1510 : {
1511 14756 : last = get_last_insn ();
1512 14756 : if (profile_status_for_fn (cfun) != PROFILE_ABSENT
1513 9703 : && JUMP_P (last)
1514 9703 : && any_condjump_p (last)
1515 24459 : && !find_reg_note (last, REG_BR_PROB, 0))
1516 9703 : add_reg_br_prob_note (last,
1517 : profile_probability::very_unlikely ());
1518 14756 : emit_jump (done_label);
1519 14756 : goto do_error_label;
1520 : }
1521 :
1522 0 : delete_insns_since (last);
1523 : }
1524 :
1525 : /* Compute the operation. On RTL level, the addition is always
1526 : unsigned. */
1527 0 : res = expand_binop (mode, code == PLUS_EXPR ? add_optab : sub_optab,
1528 : op0, op1, NULL_RTX, false, OPTAB_LIB_WIDEN);
1529 :
1530 : /* If we can prove that one of the arguments (for MINUS_EXPR only
1531 : the second operand, as subtraction is not commutative) is always
1532 : non-negative or always negative, we can do just one comparison
1533 : and conditional jump. */
1534 0 : int pos_neg = get_range_pos_neg (arg1, currently_expanding_gimple_stmt);
1535 0 : if (code == PLUS_EXPR)
1536 : {
1537 0 : int pos_neg0 = get_range_pos_neg (arg0,
1538 : currently_expanding_gimple_stmt);
1539 0 : if (pos_neg0 != 3 && pos_neg == 3)
1540 : {
1541 : std::swap (op0, op1);
1542 : pos_neg = pos_neg0;
1543 : }
1544 : }
1545 :
1546 : /* Addition overflows if and only if the two operands have the same sign,
1547 : and the result has the opposite sign. Subtraction overflows if and
1548 : only if the two operands have opposite sign, and the subtrahend has
1549 : the same sign as the result. Here 0 is counted as positive. */
1550 0 : if (pos_neg == 3)
1551 : {
1552 : /* Compute op0 ^ op1 (operands have opposite sign). */
1553 0 : rtx op_xor = expand_binop (mode, xor_optab, op0, op1, NULL_RTX, false,
1554 : OPTAB_LIB_WIDEN);
1555 :
1556 : /* Compute res ^ op1 (result and 2nd operand have opposite sign). */
1557 0 : rtx res_xor = expand_binop (mode, xor_optab, res, op1, NULL_RTX, false,
1558 : OPTAB_LIB_WIDEN);
1559 :
1560 0 : rtx tem;
1561 0 : if (code == PLUS_EXPR)
1562 : {
1563 : /* Compute (res ^ op1) & ~(op0 ^ op1). */
1564 0 : tem = expand_unop (mode, one_cmpl_optab, op_xor, NULL_RTX, false);
1565 0 : tem = expand_binop (mode, and_optab, res_xor, tem, NULL_RTX, false,
1566 : OPTAB_LIB_WIDEN);
1567 : }
1568 : else
1569 : {
1570 : /* Compute (op0 ^ op1) & ~(res ^ op1). */
1571 0 : tem = expand_unop (mode, one_cmpl_optab, res_xor, NULL_RTX, false);
1572 0 : tem = expand_binop (mode, and_optab, op_xor, tem, NULL_RTX, false,
1573 : OPTAB_LIB_WIDEN);
1574 : }
1575 :
1576 : /* No overflow if the result has bit sign cleared. */
1577 0 : do_compare_rtx_and_jump (tem, const0_rtx, GE, false, mode, NULL_RTX,
1578 : NULL, done_label, profile_probability::very_likely ());
1579 : }
1580 :
1581 : /* Compare the result of the operation with the first operand.
1582 : No overflow for addition if second operand is positive and result
1583 : is larger or second operand is negative and result is smaller.
1584 : Likewise for subtraction with sign of second operand flipped. */
1585 : else
1586 0 : do_compare_rtx_and_jump (res, op0,
1587 0 : (pos_neg == 1) ^ (code == MINUS_EXPR) ? GE : LE,
1588 : false, mode, NULL_RTX, NULL, done_label,
1589 : profile_probability::very_likely ());
1590 : }
1591 :
1592 39124 : do_error_label:
1593 39124 : emit_label (do_error);
1594 39124 : if (is_ubsan)
1595 : {
1596 : /* Expand the ubsan builtin call. */
1597 3391 : push_temp_slots ();
1598 3391 : fn = ubsan_build_overflow_builtin (code, loc, TREE_TYPE (arg0),
1599 : arg0, arg1, datap);
1600 3391 : expand_normal (fn);
1601 3391 : pop_temp_slots ();
1602 3391 : do_pending_stack_adjust ();
1603 : }
1604 35733 : else if (lhs)
1605 35733 : expand_arith_set_overflow (lhs, target);
1606 :
1607 : /* We're done. */
1608 39124 : emit_label (done_label);
1609 :
1610 39124 : if (lhs)
1611 : {
1612 38596 : if (is_ubsan)
1613 2863 : expand_ubsan_result_store (lhs, target, mode, res, do_error);
1614 : else
1615 : {
1616 35733 : if (do_xor)
1617 2537 : res = expand_binop (mode, add_optab, res, sgn, NULL_RTX, false,
1618 : OPTAB_LIB_WIDEN);
1619 :
1620 35733 : expand_arith_overflow_result_store (lhs, target, mode, res);
1621 : }
1622 : }
1623 39124 : }
1624 :
1625 : /* Add negate overflow checking to the statement STMT. */
1626 :
1627 : static void
1628 1052 : expand_neg_overflow (location_t loc, tree lhs, tree arg1, bool is_ubsan,
1629 : tree *datap)
1630 : {
1631 1052 : rtx res, op1;
1632 1052 : tree fn;
1633 1052 : rtx_code_label *done_label, *do_error;
1634 1052 : rtx target = NULL_RTX;
1635 :
1636 1052 : done_label = gen_label_rtx ();
1637 1052 : do_error = gen_label_rtx ();
1638 :
1639 1052 : do_pending_stack_adjust ();
1640 1052 : op1 = expand_normal (arg1);
1641 :
1642 1052 : scalar_int_mode mode = SCALAR_INT_TYPE_MODE (TREE_TYPE (arg1));
1643 1052 : if (lhs)
1644 : {
1645 848 : target = expand_expr (lhs, NULL_RTX, VOIDmode, EXPAND_WRITE);
1646 848 : if (!is_ubsan)
1647 402 : write_complex_part (target, const0_rtx, true, false);
1648 : }
1649 :
1650 1052 : enum insn_code icode = optab_handler (negv3_optab, mode);
1651 1052 : if (icode != CODE_FOR_nothing)
1652 : {
1653 974 : class expand_operand ops[3];
1654 974 : rtx_insn *last = get_last_insn ();
1655 :
1656 974 : res = gen_reg_rtx (mode);
1657 974 : create_output_operand (&ops[0], res, mode);
1658 974 : create_input_operand (&ops[1], op1, mode);
1659 974 : create_fixed_operand (&ops[2], do_error);
1660 974 : if (maybe_expand_insn (icode, 3, ops))
1661 : {
1662 974 : last = get_last_insn ();
1663 974 : if (profile_status_for_fn (cfun) != PROFILE_ABSENT
1664 685 : && JUMP_P (last)
1665 685 : && any_condjump_p (last)
1666 1659 : && !find_reg_note (last, REG_BR_PROB, 0))
1667 685 : add_reg_br_prob_note (last,
1668 : profile_probability::very_unlikely ());
1669 974 : emit_jump (done_label);
1670 : }
1671 : else
1672 : {
1673 0 : delete_insns_since (last);
1674 0 : icode = CODE_FOR_nothing;
1675 : }
1676 : }
1677 :
1678 974 : if (icode == CODE_FOR_nothing)
1679 : {
1680 : /* Compute the operation. On RTL level, the addition is always
1681 : unsigned. */
1682 78 : res = expand_unop (mode, neg_optab, op1, NULL_RTX, false);
1683 :
1684 : /* Compare the operand with the most negative value. */
1685 78 : rtx minv = expand_normal (TYPE_MIN_VALUE (TREE_TYPE (arg1)));
1686 78 : do_compare_rtx_and_jump (op1, minv, NE, true, mode, NULL_RTX, NULL,
1687 : done_label, profile_probability::very_likely ());
1688 : }
1689 :
1690 1052 : emit_label (do_error);
1691 1052 : if (is_ubsan)
1692 : {
1693 : /* Expand the ubsan builtin call. */
1694 650 : push_temp_slots ();
1695 650 : fn = ubsan_build_overflow_builtin (NEGATE_EXPR, loc, TREE_TYPE (arg1),
1696 : arg1, NULL_TREE, datap);
1697 650 : expand_normal (fn);
1698 650 : pop_temp_slots ();
1699 650 : do_pending_stack_adjust ();
1700 : }
1701 402 : else if (lhs)
1702 402 : expand_arith_set_overflow (lhs, target);
1703 :
1704 : /* We're done. */
1705 1052 : emit_label (done_label);
1706 :
1707 1052 : if (lhs)
1708 : {
1709 848 : if (is_ubsan)
1710 446 : expand_ubsan_result_store (lhs, target, mode, res, do_error);
1711 : else
1712 402 : expand_arith_overflow_result_store (lhs, target, mode, res);
1713 : }
1714 1052 : }
1715 :
1716 : /* Return true if UNS WIDEN_MULT_EXPR with result mode WMODE and operand
1717 : mode MODE can be expanded without using a libcall. */
1718 :
1719 : static bool
1720 0 : can_widen_mult_without_libcall (scalar_int_mode wmode, scalar_int_mode mode,
1721 : rtx op0, rtx op1, bool uns)
1722 : {
1723 0 : if (find_widening_optab_handler (umul_widen_optab, wmode, mode)
1724 : != CODE_FOR_nothing)
1725 : return true;
1726 :
1727 0 : if (find_widening_optab_handler (smul_widen_optab, wmode, mode)
1728 : != CODE_FOR_nothing)
1729 : return true;
1730 :
1731 0 : rtx_insn *last = get_last_insn ();
1732 0 : if (CONSTANT_P (op0))
1733 0 : op0 = convert_modes (wmode, mode, op0, uns);
1734 : else
1735 0 : op0 = gen_raw_REG (wmode, LAST_VIRTUAL_REGISTER + 1);
1736 0 : if (CONSTANT_P (op1))
1737 0 : op1 = convert_modes (wmode, mode, op1, uns);
1738 : else
1739 0 : op1 = gen_raw_REG (wmode, LAST_VIRTUAL_REGISTER + 2);
1740 0 : rtx ret = expand_mult (wmode, op0, op1, NULL_RTX, uns, true);
1741 0 : delete_insns_since (last);
1742 0 : return ret != NULL_RTX;
1743 : }
1744 :
1745 : /* Add mul overflow checking to the statement STMT. */
1746 :
1747 : static void
1748 18898 : expand_mul_overflow (location_t loc, tree lhs, tree arg0, tree arg1,
1749 : bool unsr_p, bool uns0_p, bool uns1_p, bool is_ubsan,
1750 : tree *datap)
1751 : {
1752 18898 : rtx res, op0, op1;
1753 18898 : tree fn, type, orig_arg0 = arg0, orig_arg1 = arg1;
1754 18898 : rtx_code_label *done_label, *do_error;
1755 18898 : rtx target = NULL_RTX;
1756 18898 : signop sign;
1757 18898 : enum insn_code icode;
1758 18898 : int save_flag_trapv = flag_trapv;
1759 :
1760 : /* We don't want any __mulv?i3 etc. calls from the expansion of
1761 : these internal functions, so disable -ftrapv temporarily. */
1762 18898 : flag_trapv = 0;
1763 18898 : done_label = gen_label_rtx ();
1764 18898 : do_error = gen_label_rtx ();
1765 :
1766 18898 : do_pending_stack_adjust ();
1767 :
1768 18898 : scalar_int_mode mode = SCALAR_INT_TYPE_MODE (TREE_TYPE (arg0));
1769 : /* If the operand types don't have mode precision, extend them
1770 : to mode precision. */
1771 18898 : if (TYPE_PRECISION (TREE_TYPE (arg0)) < GET_MODE_PRECISION (mode))
1772 : {
1773 619 : tree type = build_nonstandard_integer_type (GET_MODE_PRECISION (mode),
1774 : uns0_p);
1775 619 : arg0 = fold_convert_loc (loc, type, arg0);
1776 : }
1777 18898 : if (TYPE_PRECISION (TREE_TYPE (arg1)) < GET_MODE_PRECISION (mode))
1778 : {
1779 619 : tree type = build_nonstandard_integer_type (GET_MODE_PRECISION (mode),
1780 : uns1_p);
1781 619 : arg1 = fold_convert_loc (loc, type, arg1);
1782 : }
1783 :
1784 18898 : op0 = expand_normal (arg0);
1785 18898 : op1 = expand_normal (arg1);
1786 :
1787 18898 : bool uns = unsr_p;
1788 18898 : if (lhs)
1789 : {
1790 18754 : target = expand_expr (lhs, NULL_RTX, VOIDmode, EXPAND_WRITE);
1791 18754 : if (!is_ubsan)
1792 17388 : write_complex_part (target, const0_rtx, true, false);
1793 : }
1794 :
1795 17532 : if (is_ubsan)
1796 1510 : gcc_assert (!unsr_p && !uns0_p && !uns1_p);
1797 :
1798 : /* We assume both operands and result have the same precision
1799 : here (GET_MODE_BITSIZE (mode)), S stands for signed type
1800 : with that precision, U for unsigned type with that precision,
1801 : sgn for unsigned most significant bit in that precision.
1802 : s1 is signed first operand, u1 is unsigned first operand,
1803 : s2 is signed second operand, u2 is unsigned second operand,
1804 : sr is signed result, ur is unsigned result and the following
1805 : rules say how to compute result (which is always result of
1806 : the operands as if both were unsigned, cast to the right
1807 : signedness) and how to compute whether operation overflowed.
1808 : main_ovf (false) stands for jump on signed multiplication
1809 : overflow or the main algorithm with uns == false.
1810 : main_ovf (true) stands for jump on unsigned multiplication
1811 : overflow or the main algorithm with uns == true.
1812 :
1813 : s1 * s2 -> sr
1814 : res = (S) ((U) s1 * (U) s2)
1815 : ovf = main_ovf (false)
1816 : u1 * u2 -> ur
1817 : res = u1 * u2
1818 : ovf = main_ovf (true)
1819 : s1 * u2 -> ur
1820 : res = (U) s1 * u2
1821 : ovf = (s1 < 0 && u2) || main_ovf (true)
1822 : u1 * u2 -> sr
1823 : res = (S) (u1 * u2)
1824 : ovf = res < 0 || main_ovf (true)
1825 : s1 * u2 -> sr
1826 : res = (S) ((U) s1 * u2)
1827 : ovf = (S) u2 >= 0 ? main_ovf (false)
1828 : : (s1 != 0 && (s1 != -1 || u2 != (U) res))
1829 : s1 * s2 -> ur
1830 : t1 = (s1 & s2) < 0 ? (-(U) s1) : ((U) s1)
1831 : t2 = (s1 & s2) < 0 ? (-(U) s2) : ((U) s2)
1832 : res = t1 * t2
1833 : ovf = (s1 ^ s2) < 0 ? (s1 && s2) : main_ovf (true) */
1834 :
1835 18898 : if (uns0_p && !uns1_p)
1836 : {
1837 : /* Multiplication is commutative, if operand signedness differs,
1838 : canonicalize to the first operand being signed and second
1839 : unsigned to simplify following code. */
1840 1558 : std::swap (op0, op1);
1841 1558 : std::swap (arg0, arg1);
1842 1558 : uns0_p = false;
1843 1558 : uns1_p = true;
1844 : }
1845 :
1846 18898 : int pos_neg0 = get_range_pos_neg (arg0, currently_expanding_gimple_stmt);
1847 18898 : int pos_neg1 = get_range_pos_neg (arg1, currently_expanding_gimple_stmt);
1848 :
1849 : /* s1 * u2 -> ur */
1850 18898 : if (!uns0_p && uns1_p && unsr_p)
1851 : {
1852 2254 : switch (pos_neg0)
1853 : {
1854 0 : case 1:
1855 : /* If s1 is non-negative, just perform normal u1 * u2 -> ur. */
1856 1821 : goto do_main;
1857 328 : case 2:
1858 : /* If s1 is negative, avoid the main code, just multiply and
1859 : signal overflow if op1 is not 0. */
1860 328 : struct separate_ops ops;
1861 328 : ops.code = MULT_EXPR;
1862 328 : ops.type = TREE_TYPE (arg1);
1863 328 : ops.op0 = make_tree (ops.type, op0);
1864 328 : ops.op1 = make_tree (ops.type, op1);
1865 328 : ops.op2 = NULL_TREE;
1866 328 : ops.location = loc;
1867 328 : res = expand_expr_real_2 (&ops, NULL_RTX, mode, EXPAND_NORMAL);
1868 328 : do_compare_rtx_and_jump (op1, const0_rtx, EQ, true, mode, NULL_RTX,
1869 : NULL, done_label, profile_probability::very_likely ());
1870 433 : goto do_error_label;
1871 1926 : case 3:
1872 3852 : if (get_min_precision (arg1, UNSIGNED)
1873 1926 : + get_min_precision (arg0, SIGNED) <= GET_MODE_PRECISION (mode))
1874 : {
1875 : /* If the first operand is sign extended from narrower type, the
1876 : second operand is zero extended from narrower type and
1877 : the sum of the two precisions is smaller or equal to the
1878 : result precision: if the first argument is at runtime
1879 : non-negative, maximum result will be 0x7e81 or 0x7f..fe80..01
1880 : and there will be no overflow, if the first argument is
1881 : negative and the second argument zero, the result will be
1882 : 0 and there will be no overflow, if the first argument is
1883 : negative and the second argument positive, the result when
1884 : treated as signed will be negative (minimum -0x7f80 or
1885 : -0x7f..f80..0) there will be always overflow. So, do
1886 : res = (U) (s1 * u2)
1887 : ovf = (S) res < 0 */
1888 105 : struct separate_ops ops;
1889 105 : ops.code = MULT_EXPR;
1890 105 : ops.type
1891 105 : = build_nonstandard_integer_type (GET_MODE_PRECISION (mode),
1892 : 1);
1893 105 : ops.op0 = make_tree (ops.type, op0);
1894 105 : ops.op1 = make_tree (ops.type, op1);
1895 105 : ops.op2 = NULL_TREE;
1896 105 : ops.location = loc;
1897 105 : res = expand_expr_real_2 (&ops, NULL_RTX, mode, EXPAND_NORMAL);
1898 105 : do_compare_rtx_and_jump (res, const0_rtx, GE, false,
1899 : mode, NULL_RTX, NULL, done_label,
1900 : profile_probability::very_likely ());
1901 105 : goto do_error_label;
1902 : }
1903 1821 : rtx_code_label *do_main_label;
1904 1821 : do_main_label = gen_label_rtx ();
1905 1821 : do_compare_rtx_and_jump (op0, const0_rtx, GE, false, mode, NULL_RTX,
1906 : NULL, do_main_label, profile_probability::very_likely ());
1907 1821 : do_compare_rtx_and_jump (op1, const0_rtx, EQ, true, mode, NULL_RTX,
1908 : NULL, do_main_label, profile_probability::very_likely ());
1909 1821 : expand_arith_set_overflow (lhs, target);
1910 1821 : emit_label (do_main_label);
1911 1821 : goto do_main;
1912 0 : default:
1913 0 : gcc_unreachable ();
1914 : }
1915 : }
1916 :
1917 : /* u1 * u2 -> sr */
1918 16644 : if (uns0_p && uns1_p && !unsr_p)
1919 : {
1920 1369 : if ((pos_neg0 | pos_neg1) == 1)
1921 : {
1922 : /* If both arguments are zero extended from narrower types,
1923 : the MSB will be clear on both and so we can pretend it is
1924 : a normal s1 * s2 -> sr multiplication. */
1925 : uns0_p = false;
1926 : uns1_p = false;
1927 : }
1928 : else
1929 957 : uns = true;
1930 : /* Rest of handling of this case after res is computed. */
1931 1369 : goto do_main;
1932 : }
1933 :
1934 : /* s1 * u2 -> sr */
1935 15275 : if (!uns0_p && uns1_p && !unsr_p)
1936 : {
1937 1788 : switch (pos_neg1)
1938 : {
1939 66 : case 1:
1940 1339 : goto do_main;
1941 449 : case 2:
1942 : /* If (S) u2 is negative (i.e. u2 is larger than maximum of S,
1943 : avoid the main code, just multiply and signal overflow
1944 : unless 0 * u2 or -1 * ((U) Smin). */
1945 449 : struct separate_ops ops;
1946 449 : ops.code = MULT_EXPR;
1947 449 : ops.type = TREE_TYPE (arg1);
1948 449 : ops.op0 = make_tree (ops.type, op0);
1949 449 : ops.op1 = make_tree (ops.type, op1);
1950 449 : ops.op2 = NULL_TREE;
1951 449 : ops.location = loc;
1952 449 : res = expand_expr_real_2 (&ops, NULL_RTX, mode, EXPAND_NORMAL);
1953 449 : do_compare_rtx_and_jump (op0, const0_rtx, EQ, true, mode, NULL_RTX,
1954 : NULL, done_label, profile_probability::very_likely ());
1955 449 : do_compare_rtx_and_jump (op0, constm1_rtx, NE, true, mode, NULL_RTX,
1956 : NULL, do_error, profile_probability::very_unlikely ());
1957 449 : int prec;
1958 449 : prec = GET_MODE_PRECISION (mode);
1959 449 : rtx sgn;
1960 449 : sgn = immed_wide_int_const (wi::min_value (prec, SIGNED), mode);
1961 449 : do_compare_rtx_and_jump (op1, sgn, EQ, true, mode, NULL_RTX,
1962 : NULL, done_label, profile_probability::very_likely ());
1963 449 : goto do_error_label;
1964 1273 : case 3:
1965 : /* Rest of handling of this case after res is computed. */
1966 1273 : goto do_main;
1967 0 : default:
1968 0 : gcc_unreachable ();
1969 : }
1970 : }
1971 :
1972 : /* s1 * s2 -> ur */
1973 13487 : if (!uns0_p && !uns1_p && unsr_p)
1974 : {
1975 2329 : rtx tem;
1976 2329 : switch (pos_neg0 | pos_neg1)
1977 : {
1978 0 : case 1: /* Both operands known to be non-negative. */
1979 0 : goto do_main;
1980 12 : case 2: /* Both operands known to be negative. */
1981 12 : op0 = expand_unop (mode, neg_optab, op0, NULL_RTX, false);
1982 12 : op1 = expand_unop (mode, neg_optab, op1, NULL_RTX, false);
1983 : /* Avoid looking at arg0/arg1 ranges, as we've changed
1984 : the arguments. */
1985 12 : arg0 = error_mark_node;
1986 12 : arg1 = error_mark_node;
1987 12 : goto do_main;
1988 2317 : case 3:
1989 2317 : if ((pos_neg0 ^ pos_neg1) == 3)
1990 : {
1991 : /* If one operand is known to be negative and the other
1992 : non-negative, this overflows always, unless the non-negative
1993 : one is 0. Just do normal multiply and set overflow
1994 : unless one of the operands is 0. */
1995 0 : struct separate_ops ops;
1996 0 : ops.code = MULT_EXPR;
1997 0 : ops.type
1998 0 : = build_nonstandard_integer_type (GET_MODE_PRECISION (mode),
1999 : 1);
2000 0 : ops.op0 = make_tree (ops.type, op0);
2001 0 : ops.op1 = make_tree (ops.type, op1);
2002 0 : ops.op2 = NULL_TREE;
2003 0 : ops.location = loc;
2004 0 : res = expand_expr_real_2 (&ops, NULL_RTX, mode, EXPAND_NORMAL);
2005 0 : do_compare_rtx_and_jump (pos_neg0 == 1 ? op0 : op1, const0_rtx, EQ,
2006 : true, mode, NULL_RTX, NULL, done_label,
2007 : profile_probability::very_likely ());
2008 0 : goto do_error_label;
2009 : }
2010 4634 : if (get_min_precision (arg0, SIGNED)
2011 2317 : + get_min_precision (arg1, SIGNED) <= GET_MODE_PRECISION (mode))
2012 : {
2013 : /* If both operands are sign extended from narrower types and
2014 : the sum of the two precisions is smaller or equal to the
2015 : result precision: if both arguments are at runtime
2016 : non-negative, maximum result will be 0x3f01 or 0x3f..f0..01
2017 : and there will be no overflow, if both arguments are negative,
2018 : maximum result will be 0x40..00 and there will be no overflow
2019 : either, if one argument is positive and the other argument
2020 : negative, the result when treated as signed will be negative
2021 : and there will be always overflow, and if one argument is
2022 : zero and the other negative the result will be zero and no
2023 : overflow. So, do
2024 : res = (U) (s1 * s2)
2025 : ovf = (S) res < 0 */
2026 220 : struct separate_ops ops;
2027 220 : ops.code = MULT_EXPR;
2028 220 : ops.type
2029 220 : = build_nonstandard_integer_type (GET_MODE_PRECISION (mode),
2030 : 1);
2031 220 : ops.op0 = make_tree (ops.type, op0);
2032 220 : ops.op1 = make_tree (ops.type, op1);
2033 220 : ops.op2 = NULL_TREE;
2034 220 : ops.location = loc;
2035 220 : res = expand_expr_real_2 (&ops, NULL_RTX, mode, EXPAND_NORMAL);
2036 220 : do_compare_rtx_and_jump (res, const0_rtx, GE, false,
2037 : mode, NULL_RTX, NULL, done_label,
2038 : profile_probability::very_likely ());
2039 220 : goto do_error_label;
2040 : }
2041 : /* The general case, do all the needed comparisons at runtime. */
2042 2097 : rtx_code_label *do_main_label, *after_negate_label;
2043 2097 : rtx rop0, rop1;
2044 2097 : rop0 = gen_reg_rtx (mode);
2045 2097 : rop1 = gen_reg_rtx (mode);
2046 2097 : emit_move_insn (rop0, op0);
2047 2097 : emit_move_insn (rop1, op1);
2048 2097 : op0 = rop0;
2049 2097 : op1 = rop1;
2050 2097 : do_main_label = gen_label_rtx ();
2051 2097 : after_negate_label = gen_label_rtx ();
2052 2097 : tem = expand_binop (mode, and_optab, op0, op1, NULL_RTX, false,
2053 : OPTAB_LIB_WIDEN);
2054 2097 : do_compare_rtx_and_jump (tem, const0_rtx, GE, false, mode, NULL_RTX,
2055 : NULL, after_negate_label, profile_probability::very_likely ());
2056 : /* Both arguments negative here, negate them and continue with
2057 : normal unsigned overflow checking multiplication. */
2058 2097 : emit_move_insn (op0, expand_unop (mode, neg_optab, op0,
2059 : NULL_RTX, false));
2060 2097 : emit_move_insn (op1, expand_unop (mode, neg_optab, op1,
2061 : NULL_RTX, false));
2062 : /* Avoid looking at arg0/arg1 ranges, as we might have changed
2063 : the arguments. */
2064 2097 : arg0 = error_mark_node;
2065 2097 : arg1 = error_mark_node;
2066 2097 : emit_jump (do_main_label);
2067 2097 : emit_label (after_negate_label);
2068 2097 : tem = expand_binop (mode, xor_optab, op0, op1, NULL_RTX, false,
2069 : OPTAB_LIB_WIDEN);
2070 2097 : do_compare_rtx_and_jump (tem, const0_rtx, GE, false, mode, NULL_RTX,
2071 : NULL, do_main_label,
2072 : profile_probability::very_likely ());
2073 : /* One argument is negative here, the other positive. This
2074 : overflows always, unless one of the arguments is 0. But
2075 : if e.g. s2 is 0, (U) s1 * 0 doesn't overflow, whatever s1
2076 : is, thus we can keep do_main code oring in overflow as is. */
2077 2097 : if (pos_neg0 != 2)
2078 2097 : do_compare_rtx_and_jump (op0, const0_rtx, EQ, true, mode, NULL_RTX,
2079 : NULL, do_main_label,
2080 : profile_probability::very_unlikely ());
2081 2097 : if (pos_neg1 != 2)
2082 1080 : do_compare_rtx_and_jump (op1, const0_rtx, EQ, true, mode, NULL_RTX,
2083 : NULL, do_main_label,
2084 : profile_probability::very_unlikely ());
2085 2097 : expand_arith_set_overflow (lhs, target);
2086 2097 : emit_label (do_main_label);
2087 2097 : goto do_main;
2088 0 : default:
2089 0 : gcc_unreachable ();
2090 : }
2091 : }
2092 :
2093 11158 : do_main:
2094 17796 : type = build_nonstandard_integer_type (GET_MODE_PRECISION (mode), uns);
2095 17796 : sign = uns ? UNSIGNED : SIGNED;
2096 17796 : icode = optab_handler (uns ? umulv4_optab : mulv4_optab, mode);
2097 17796 : if (uns
2098 10458 : && (integer_pow2p (arg0) || integer_pow2p (arg1))
2099 18663 : && (optimize_insn_for_speed_p () || icode == CODE_FOR_nothing))
2100 : {
2101 : /* Optimize unsigned multiplication by power of 2 constant
2102 : using 2 shifts, one for result, one to extract the shifted
2103 : out bits to see if they are all zero.
2104 : Don't do this if optimizing for size and we have umulv4_optab,
2105 : in that case assume multiplication will be shorter.
2106 : This is heuristics based on the single target that provides
2107 : umulv4 right now (i?86/x86_64), if further targets add it, this
2108 : might need to be revisited.
2109 : Cases where both operands are constant should be folded already
2110 : during GIMPLE, and cases where one operand is constant but not
2111 : power of 2 are questionable, either the WIDEN_MULT_EXPR case
2112 : below can be done without multiplication, just by shifts and adds,
2113 : or we'd need to divide the result (and hope it actually doesn't
2114 : really divide nor multiply) and compare the result of the division
2115 : with the original operand. */
2116 865 : rtx opn0 = op0;
2117 865 : rtx opn1 = op1;
2118 865 : tree argn0 = arg0;
2119 865 : tree argn1 = arg1;
2120 865 : if (integer_pow2p (arg0))
2121 : {
2122 0 : std::swap (opn0, opn1);
2123 0 : std::swap (argn0, argn1);
2124 : }
2125 865 : int cnt = tree_log2 (argn1);
2126 865 : if (cnt >= 0 && cnt < GET_MODE_PRECISION (mode))
2127 : {
2128 865 : rtx upper = const0_rtx;
2129 865 : res = expand_shift (LSHIFT_EXPR, mode, opn0, cnt, NULL_RTX, uns);
2130 865 : if (cnt != 0)
2131 693 : upper = expand_shift (RSHIFT_EXPR, mode, opn0,
2132 693 : GET_MODE_PRECISION (mode) - cnt,
2133 : NULL_RTX, uns);
2134 865 : do_compare_rtx_and_jump (upper, const0_rtx, EQ, true, mode,
2135 : NULL_RTX, NULL, done_label,
2136 : profile_probability::very_likely ());
2137 865 : goto do_error_label;
2138 : }
2139 : }
2140 16931 : if (icode != CODE_FOR_nothing)
2141 : {
2142 13832 : class expand_operand ops[4];
2143 13832 : rtx_insn *last = get_last_insn ();
2144 :
2145 13832 : res = gen_reg_rtx (mode);
2146 13832 : create_output_operand (&ops[0], res, mode);
2147 13832 : create_input_operand (&ops[1], op0, mode);
2148 13832 : create_input_operand (&ops[2], op1, mode);
2149 13832 : create_fixed_operand (&ops[3], do_error);
2150 13832 : if (maybe_expand_insn (icode, 4, ops))
2151 : {
2152 13832 : last = get_last_insn ();
2153 13832 : if (profile_status_for_fn (cfun) != PROFILE_ABSENT
2154 9154 : && JUMP_P (last)
2155 9154 : && any_condjump_p (last)
2156 22986 : && !find_reg_note (last, REG_BR_PROB, 0))
2157 9154 : add_reg_br_prob_note (last,
2158 : profile_probability::very_unlikely ());
2159 13832 : emit_jump (done_label);
2160 : }
2161 : else
2162 : {
2163 0 : delete_insns_since (last);
2164 0 : icode = CODE_FOR_nothing;
2165 : }
2166 : }
2167 :
2168 0 : if (icode == CODE_FOR_nothing)
2169 : {
2170 3099 : struct separate_ops ops;
2171 3099 : int prec = GET_MODE_PRECISION (mode);
2172 3099 : scalar_int_mode hmode, wmode;
2173 3099 : ops.op0 = make_tree (type, op0);
2174 3099 : ops.op1 = make_tree (type, op1);
2175 3099 : ops.op2 = NULL_TREE;
2176 3099 : ops.location = loc;
2177 :
2178 : /* Optimize unsigned overflow check where we don't use the
2179 : multiplication result, just whether overflow happened.
2180 : If we can do MULT_HIGHPART_EXPR, that followed by
2181 : comparison of the result against zero is cheapest.
2182 : We'll still compute res, but it should be DCEd later. */
2183 3099 : use_operand_p use;
2184 3099 : gimple *use_stmt;
2185 3099 : if (!is_ubsan
2186 3099 : && lhs
2187 3079 : && uns
2188 1973 : && !(uns0_p && uns1_p && !unsr_p)
2189 1692 : && can_mult_highpart_p (mode, uns) == 1
2190 0 : && single_imm_use (lhs, &use, &use_stmt)
2191 0 : && is_gimple_assign (use_stmt)
2192 3099 : && gimple_assign_rhs_code (use_stmt) == IMAGPART_EXPR)
2193 0 : goto highpart;
2194 :
2195 3099 : if (GET_MODE_2XWIDER_MODE (mode).exists (&wmode)
2196 3099 : && targetm.scalar_mode_supported_p (wmode)
2197 0 : && can_widen_mult_without_libcall (wmode, mode, op0, op1, uns))
2198 : {
2199 0 : twoxwider:
2200 0 : ops.code = WIDEN_MULT_EXPR;
2201 0 : ops.type
2202 0 : = build_nonstandard_integer_type (GET_MODE_PRECISION (wmode), uns);
2203 :
2204 0 : res = expand_expr_real_2 (&ops, NULL_RTX, wmode, EXPAND_NORMAL);
2205 0 : rtx hipart = expand_shift (RSHIFT_EXPR, wmode, res, prec,
2206 : NULL_RTX, uns);
2207 0 : hipart = convert_modes (mode, wmode, hipart, uns);
2208 0 : res = convert_modes (mode, wmode, res, uns);
2209 0 : if (uns)
2210 : /* For the unsigned multiplication, there was overflow if
2211 : HIPART is non-zero. */
2212 0 : do_compare_rtx_and_jump (hipart, const0_rtx, EQ, true, mode,
2213 : NULL_RTX, NULL, done_label,
2214 : profile_probability::very_likely ());
2215 : else
2216 : {
2217 : /* RES is used more than once, place it in a pseudo. */
2218 0 : res = force_reg (mode, res);
2219 :
2220 0 : rtx signbit = expand_shift (RSHIFT_EXPR, mode, res, prec - 1,
2221 : NULL_RTX, 0);
2222 : /* RES is low half of the double width result, HIPART
2223 : the high half. There was overflow if
2224 : HIPART is different from RES < 0 ? -1 : 0. */
2225 0 : do_compare_rtx_and_jump (signbit, hipart, EQ, true, mode,
2226 : NULL_RTX, NULL, done_label,
2227 : profile_probability::very_likely ());
2228 : }
2229 : }
2230 3099 : else if (can_mult_highpart_p (mode, uns) == 1)
2231 : {
2232 0 : highpart:
2233 0 : ops.code = MULT_HIGHPART_EXPR;
2234 0 : ops.type = type;
2235 :
2236 0 : rtx hipart = expand_expr_real_2 (&ops, NULL_RTX, mode,
2237 : EXPAND_NORMAL);
2238 0 : ops.code = MULT_EXPR;
2239 0 : res = expand_expr_real_2 (&ops, NULL_RTX, mode, EXPAND_NORMAL);
2240 0 : if (uns)
2241 : /* For the unsigned multiplication, there was overflow if
2242 : HIPART is non-zero. */
2243 0 : do_compare_rtx_and_jump (hipart, const0_rtx, EQ, true, mode,
2244 : NULL_RTX, NULL, done_label,
2245 : profile_probability::very_likely ());
2246 : else
2247 : {
2248 0 : rtx signbit = expand_shift (RSHIFT_EXPR, mode, res, prec - 1,
2249 : NULL_RTX, 0);
2250 : /* RES is low half of the double width result, HIPART
2251 : the high half. There was overflow if
2252 : HIPART is different from RES < 0 ? -1 : 0. */
2253 0 : do_compare_rtx_and_jump (signbit, hipart, EQ, true, mode,
2254 : NULL_RTX, NULL, done_label,
2255 : profile_probability::very_likely ());
2256 : }
2257 :
2258 : }
2259 3099 : else if (int_mode_for_size (prec / 2, 1).exists (&hmode)
2260 3099 : && 2 * GET_MODE_PRECISION (hmode) == prec)
2261 : {
2262 3099 : rtx_code_label *large_op0 = gen_label_rtx ();
2263 3099 : rtx_code_label *small_op0_large_op1 = gen_label_rtx ();
2264 3099 : rtx_code_label *one_small_one_large = gen_label_rtx ();
2265 3099 : rtx_code_label *both_ops_large = gen_label_rtx ();
2266 3099 : rtx_code_label *after_hipart_neg = uns ? NULL : gen_label_rtx ();
2267 1126 : rtx_code_label *after_lopart_neg = uns ? NULL : gen_label_rtx ();
2268 3099 : rtx_code_label *do_overflow = gen_label_rtx ();
2269 3099 : rtx_code_label *hipart_different = uns ? NULL : gen_label_rtx ();
2270 :
2271 3099 : unsigned int hprec = GET_MODE_PRECISION (hmode);
2272 3099 : rtx hipart0 = expand_shift (RSHIFT_EXPR, mode, op0, hprec,
2273 : NULL_RTX, uns);
2274 3099 : hipart0 = convert_modes (hmode, mode, hipart0, uns);
2275 3099 : rtx lopart0 = convert_modes (hmode, mode, op0, uns);
2276 3099 : rtx signbit0 = const0_rtx;
2277 3099 : if (!uns)
2278 1126 : signbit0 = expand_shift (RSHIFT_EXPR, hmode, lopart0, hprec - 1,
2279 : NULL_RTX, 0);
2280 3099 : rtx hipart1 = expand_shift (RSHIFT_EXPR, mode, op1, hprec,
2281 : NULL_RTX, uns);
2282 3099 : hipart1 = convert_modes (hmode, mode, hipart1, uns);
2283 3099 : rtx lopart1 = convert_modes (hmode, mode, op1, uns);
2284 3099 : rtx signbit1 = const0_rtx;
2285 3099 : if (!uns)
2286 1126 : signbit1 = expand_shift (RSHIFT_EXPR, hmode, lopart1, hprec - 1,
2287 : NULL_RTX, 0);
2288 :
2289 3099 : res = gen_reg_rtx (mode);
2290 :
2291 : /* True if op0 resp. op1 are known to be in the range of
2292 : halfstype. */
2293 3099 : bool op0_small_p = false;
2294 3099 : bool op1_small_p = false;
2295 : /* True if op0 resp. op1 are known to have all zeros or all ones
2296 : in the upper half of bits, but are not known to be
2297 : op{0,1}_small_p. */
2298 3099 : bool op0_medium_p = false;
2299 3099 : bool op1_medium_p = false;
2300 : /* -1 if op{0,1} is known to be negative, 0 if it is known to be
2301 : nonnegative, 1 if unknown. */
2302 3099 : int op0_sign = 1;
2303 3099 : int op1_sign = 1;
2304 :
2305 3099 : if (pos_neg0 == 1)
2306 : op0_sign = 0;
2307 2950 : else if (pos_neg0 == 2)
2308 188 : op0_sign = -1;
2309 3099 : if (pos_neg1 == 1)
2310 : op1_sign = 0;
2311 2002 : else if (pos_neg1 == 2)
2312 428 : op1_sign = -1;
2313 :
2314 3099 : unsigned int mprec0 = prec;
2315 3099 : if (arg0 != error_mark_node)
2316 2350 : mprec0 = get_min_precision (arg0, sign);
2317 3099 : if (mprec0 <= hprec)
2318 : op0_small_p = true;
2319 2923 : else if (!uns && mprec0 <= hprec + 1)
2320 3099 : op0_medium_p = true;
2321 3099 : unsigned int mprec1 = prec;
2322 3099 : if (arg1 != error_mark_node)
2323 2350 : mprec1 = get_min_precision (arg1, sign);
2324 3099 : if (mprec1 <= hprec)
2325 : op1_small_p = true;
2326 2582 : else if (!uns && mprec1 <= hprec + 1)
2327 3099 : op1_medium_p = true;
2328 :
2329 3099 : int smaller_sign = 1;
2330 3099 : int larger_sign = 1;
2331 3099 : if (op0_small_p)
2332 : {
2333 : smaller_sign = op0_sign;
2334 : larger_sign = op1_sign;
2335 : }
2336 2923 : else if (op1_small_p)
2337 : {
2338 : smaller_sign = op1_sign;
2339 : larger_sign = op0_sign;
2340 : }
2341 2406 : else if (op0_sign == op1_sign)
2342 : {
2343 1494 : smaller_sign = op0_sign;
2344 1494 : larger_sign = op0_sign;
2345 : }
2346 :
2347 2923 : if (!op0_small_p)
2348 2923 : do_compare_rtx_and_jump (signbit0, hipart0, NE, true, hmode,
2349 : NULL_RTX, NULL, large_op0,
2350 : profile_probability::unlikely ());
2351 :
2352 3099 : if (!op1_small_p)
2353 2582 : do_compare_rtx_and_jump (signbit1, hipart1, NE, true, hmode,
2354 : NULL_RTX, NULL, small_op0_large_op1,
2355 : profile_probability::unlikely ());
2356 :
2357 : /* If both op0 and op1 are sign (!uns) or zero (uns) extended from
2358 : hmode to mode, the multiplication will never overflow. We can
2359 : do just one hmode x hmode => mode widening multiplication. */
2360 3099 : tree halfstype = build_nonstandard_integer_type (hprec, uns);
2361 3099 : ops.op0 = make_tree (halfstype, lopart0);
2362 3099 : ops.op1 = make_tree (halfstype, lopart1);
2363 3099 : ops.code = WIDEN_MULT_EXPR;
2364 3099 : ops.type = type;
2365 3099 : rtx thisres
2366 3099 : = expand_expr_real_2 (&ops, NULL_RTX, mode, EXPAND_NORMAL);
2367 3099 : emit_move_insn (res, thisres);
2368 3099 : emit_jump (done_label);
2369 :
2370 3099 : emit_label (small_op0_large_op1);
2371 :
2372 : /* If op0 is sign (!uns) or zero (uns) extended from hmode to mode,
2373 : but op1 is not, just swap the arguments and handle it as op1
2374 : sign/zero extended, op0 not. */
2375 3099 : rtx larger = gen_reg_rtx (mode);
2376 3099 : rtx hipart = gen_reg_rtx (hmode);
2377 3099 : rtx lopart = gen_reg_rtx (hmode);
2378 3099 : emit_move_insn (larger, op1);
2379 3099 : emit_move_insn (hipart, hipart1);
2380 3099 : emit_move_insn (lopart, lopart0);
2381 3099 : emit_jump (one_small_one_large);
2382 :
2383 3099 : emit_label (large_op0);
2384 :
2385 3099 : if (!op1_small_p)
2386 2582 : do_compare_rtx_and_jump (signbit1, hipart1, NE, true, hmode,
2387 : NULL_RTX, NULL, both_ops_large,
2388 : profile_probability::unlikely ());
2389 :
2390 : /* If op1 is sign (!uns) or zero (uns) extended from hmode to mode,
2391 : but op0 is not, prepare larger, hipart and lopart pseudos and
2392 : handle it together with small_op0_large_op1. */
2393 3099 : emit_move_insn (larger, op0);
2394 3099 : emit_move_insn (hipart, hipart0);
2395 3099 : emit_move_insn (lopart, lopart1);
2396 :
2397 3099 : emit_label (one_small_one_large);
2398 :
2399 : /* lopart is the low part of the operand that is sign extended
2400 : to mode, larger is the other operand, hipart is the
2401 : high part of larger and lopart0 and lopart1 are the low parts
2402 : of both operands.
2403 : We perform lopart0 * lopart1 and lopart * hipart widening
2404 : multiplications. */
2405 3099 : tree halfutype = build_nonstandard_integer_type (hprec, 1);
2406 3099 : ops.op0 = make_tree (halfutype, lopart0);
2407 3099 : ops.op1 = make_tree (halfutype, lopart1);
2408 3099 : rtx lo0xlo1
2409 3099 : = expand_expr_real_2 (&ops, NULL_RTX, mode, EXPAND_NORMAL);
2410 :
2411 3099 : ops.op0 = make_tree (halfutype, lopart);
2412 3099 : ops.op1 = make_tree (halfutype, hipart);
2413 3099 : rtx loxhi = gen_reg_rtx (mode);
2414 3099 : rtx tem = expand_expr_real_2 (&ops, NULL_RTX, mode, EXPAND_NORMAL);
2415 3099 : emit_move_insn (loxhi, tem);
2416 :
2417 3099 : if (!uns)
2418 : {
2419 : /* if (hipart < 0) loxhi -= lopart << (bitsize / 2); */
2420 1126 : if (larger_sign == 0)
2421 72 : emit_jump (after_hipart_neg);
2422 1054 : else if (larger_sign != -1)
2423 1054 : do_compare_rtx_and_jump (hipart, const0_rtx, GE, false, hmode,
2424 : NULL_RTX, NULL, after_hipart_neg,
2425 : profile_probability::even ());
2426 :
2427 1126 : tem = convert_modes (mode, hmode, lopart, 1);
2428 1126 : tem = expand_shift (LSHIFT_EXPR, mode, tem, hprec, NULL_RTX, 1);
2429 1126 : tem = expand_simple_binop (mode, MINUS, loxhi, tem, NULL_RTX,
2430 : 1, OPTAB_WIDEN);
2431 1126 : emit_move_insn (loxhi, tem);
2432 :
2433 1126 : emit_label (after_hipart_neg);
2434 :
2435 : /* if (lopart < 0) loxhi -= larger; */
2436 1126 : if (smaller_sign == 0)
2437 251 : emit_jump (after_lopart_neg);
2438 875 : else if (smaller_sign != -1)
2439 705 : do_compare_rtx_and_jump (lopart, const0_rtx, GE, false, hmode,
2440 : NULL_RTX, NULL, after_lopart_neg,
2441 : profile_probability::even ());
2442 :
2443 1126 : tem = expand_simple_binop (mode, MINUS, loxhi, larger, NULL_RTX,
2444 : 1, OPTAB_WIDEN);
2445 1126 : emit_move_insn (loxhi, tem);
2446 :
2447 1126 : emit_label (after_lopart_neg);
2448 : }
2449 :
2450 : /* loxhi += (uns) lo0xlo1 >> (bitsize / 2); */
2451 3099 : tem = expand_shift (RSHIFT_EXPR, mode, lo0xlo1, hprec, NULL_RTX, 1);
2452 3099 : tem = expand_simple_binop (mode, PLUS, loxhi, tem, NULL_RTX,
2453 : 1, OPTAB_WIDEN);
2454 3099 : emit_move_insn (loxhi, tem);
2455 :
2456 : /* if (loxhi >> (bitsize / 2)
2457 : == (hmode) loxhi >> (bitsize / 2 - 1)) (if !uns)
2458 : if (loxhi >> (bitsize / 2) == 0 (if uns). */
2459 3099 : rtx hipartloxhi = expand_shift (RSHIFT_EXPR, mode, loxhi, hprec,
2460 : NULL_RTX, 0);
2461 3099 : hipartloxhi = convert_modes (hmode, mode, hipartloxhi, 0);
2462 3099 : rtx signbitloxhi = const0_rtx;
2463 3099 : if (!uns)
2464 1126 : signbitloxhi = expand_shift (RSHIFT_EXPR, hmode,
2465 : convert_modes (hmode, mode,
2466 : loxhi, 0),
2467 1126 : hprec - 1, NULL_RTX, 0);
2468 :
2469 3099 : do_compare_rtx_and_jump (signbitloxhi, hipartloxhi, NE, true, hmode,
2470 : NULL_RTX, NULL, do_overflow,
2471 : profile_probability::very_unlikely ());
2472 :
2473 : /* res = (loxhi << (bitsize / 2)) | (hmode) lo0xlo1; */
2474 3099 : rtx loxhishifted = expand_shift (LSHIFT_EXPR, mode, loxhi, hprec,
2475 : NULL_RTX, 1);
2476 3099 : tem = convert_modes (mode, hmode,
2477 : convert_modes (hmode, mode, lo0xlo1, 1), 1);
2478 :
2479 3099 : tem = expand_simple_binop (mode, IOR, loxhishifted, tem, res,
2480 : 1, OPTAB_WIDEN);
2481 3099 : if (tem != res)
2482 0 : emit_move_insn (res, tem);
2483 3099 : emit_jump (done_label);
2484 :
2485 3099 : emit_label (both_ops_large);
2486 :
2487 : /* If both operands are large (not sign (!uns) or zero (uns)
2488 : extended from hmode), then perform the full multiplication
2489 : which will be the result of the operation.
2490 : The only cases which don't overflow are for signed multiplication
2491 : some cases where both hipart0 and highpart1 are 0 or -1.
2492 : For unsigned multiplication when high parts are both non-zero
2493 : this overflows always. */
2494 3099 : ops.code = MULT_EXPR;
2495 3099 : ops.op0 = make_tree (type, op0);
2496 3099 : ops.op1 = make_tree (type, op1);
2497 3099 : tem = expand_expr_real_2 (&ops, NULL_RTX, mode, EXPAND_NORMAL);
2498 3099 : emit_move_insn (res, tem);
2499 :
2500 3099 : if (!uns)
2501 : {
2502 1126 : if (!op0_medium_p)
2503 : {
2504 1126 : tem = expand_simple_binop (hmode, PLUS, hipart0, const1_rtx,
2505 : NULL_RTX, 1, OPTAB_WIDEN);
2506 1126 : do_compare_rtx_and_jump (tem, const1_rtx, GTU, true, hmode,
2507 : NULL_RTX, NULL, do_error,
2508 : profile_probability::very_unlikely ());
2509 : }
2510 :
2511 1126 : if (!op1_medium_p)
2512 : {
2513 1126 : tem = expand_simple_binop (hmode, PLUS, hipart1, const1_rtx,
2514 : NULL_RTX, 1, OPTAB_WIDEN);
2515 1126 : do_compare_rtx_and_jump (tem, const1_rtx, GTU, true, hmode,
2516 : NULL_RTX, NULL, do_error,
2517 : profile_probability::very_unlikely ());
2518 : }
2519 :
2520 : /* At this point hipart{0,1} are both in [-1, 0]. If they are
2521 : the same, overflow happened if res is non-positive, if they
2522 : are different, overflow happened if res is positive. */
2523 1126 : if (op0_sign != 1 && op1_sign != 1 && op0_sign != op1_sign)
2524 12 : emit_jump (hipart_different);
2525 1114 : else if (op0_sign == 1 || op1_sign == 1)
2526 1058 : do_compare_rtx_and_jump (hipart0, hipart1, NE, true, hmode,
2527 : NULL_RTX, NULL, hipart_different,
2528 : profile_probability::even ());
2529 :
2530 1126 : do_compare_rtx_and_jump (res, const0_rtx, LE, false, mode,
2531 : NULL_RTX, NULL, do_error,
2532 : profile_probability::very_unlikely ());
2533 1126 : emit_jump (done_label);
2534 :
2535 1126 : emit_label (hipart_different);
2536 :
2537 1126 : do_compare_rtx_and_jump (res, const0_rtx, GE, false, mode,
2538 : NULL_RTX, NULL, do_error,
2539 : profile_probability::very_unlikely ());
2540 1126 : emit_jump (done_label);
2541 : }
2542 :
2543 3099 : emit_label (do_overflow);
2544 :
2545 : /* Overflow, do full multiplication and fallthru into do_error. */
2546 3099 : ops.op0 = make_tree (type, op0);
2547 3099 : ops.op1 = make_tree (type, op1);
2548 3099 : tem = expand_expr_real_2 (&ops, NULL_RTX, mode, EXPAND_NORMAL);
2549 3099 : emit_move_insn (res, tem);
2550 : }
2551 0 : else if (GET_MODE_2XWIDER_MODE (mode).exists (&wmode)
2552 0 : && targetm.scalar_mode_supported_p (wmode))
2553 : /* Even emitting a libcall is better than not detecting overflow
2554 : at all. */
2555 0 : goto twoxwider;
2556 : else
2557 : {
2558 0 : gcc_assert (!is_ubsan);
2559 0 : ops.code = MULT_EXPR;
2560 0 : ops.type = type;
2561 0 : res = expand_expr_real_2 (&ops, NULL_RTX, mode, EXPAND_NORMAL);
2562 0 : emit_jump (done_label);
2563 : }
2564 : }
2565 :
2566 13832 : do_error_label:
2567 18898 : emit_label (do_error);
2568 18898 : if (is_ubsan)
2569 : {
2570 : /* Expand the ubsan builtin call. */
2571 1510 : push_temp_slots ();
2572 1510 : fn = ubsan_build_overflow_builtin (MULT_EXPR, loc, TREE_TYPE (orig_arg0),
2573 : orig_arg0, orig_arg1, datap);
2574 1510 : expand_normal (fn);
2575 1510 : pop_temp_slots ();
2576 1510 : do_pending_stack_adjust ();
2577 : }
2578 17388 : else if (lhs)
2579 17388 : expand_arith_set_overflow (lhs, target);
2580 :
2581 : /* We're done. */
2582 18898 : emit_label (done_label);
2583 :
2584 : /* u1 * u2 -> sr */
2585 18898 : if (uns0_p && uns1_p && !unsr_p)
2586 : {
2587 957 : rtx_code_label *all_done_label = gen_label_rtx ();
2588 957 : do_compare_rtx_and_jump (res, const0_rtx, GE, false, mode, NULL_RTX,
2589 : NULL, all_done_label, profile_probability::very_likely ());
2590 957 : expand_arith_set_overflow (lhs, target);
2591 957 : emit_label (all_done_label);
2592 : }
2593 :
2594 : /* s1 * u2 -> sr */
2595 18898 : if (!uns0_p && uns1_p && !unsr_p && pos_neg1 == 3)
2596 : {
2597 1273 : rtx_code_label *all_done_label = gen_label_rtx ();
2598 1273 : rtx_code_label *set_noovf = gen_label_rtx ();
2599 1273 : do_compare_rtx_and_jump (op1, const0_rtx, GE, false, mode, NULL_RTX,
2600 : NULL, all_done_label, profile_probability::very_likely ());
2601 1273 : expand_arith_set_overflow (lhs, target);
2602 1273 : do_compare_rtx_and_jump (op0, const0_rtx, EQ, true, mode, NULL_RTX,
2603 : NULL, set_noovf, profile_probability::very_likely ());
2604 1273 : do_compare_rtx_and_jump (op0, constm1_rtx, NE, true, mode, NULL_RTX,
2605 : NULL, all_done_label, profile_probability::very_unlikely ());
2606 1273 : do_compare_rtx_and_jump (op1, res, NE, true, mode, NULL_RTX, NULL,
2607 : all_done_label, profile_probability::very_unlikely ());
2608 1273 : emit_label (set_noovf);
2609 1273 : write_complex_part (target, const0_rtx, true, false);
2610 1273 : emit_label (all_done_label);
2611 : }
2612 :
2613 18898 : if (lhs)
2614 : {
2615 18754 : if (is_ubsan)
2616 1366 : expand_ubsan_result_store (lhs, target, mode, res, do_error);
2617 : else
2618 17388 : expand_arith_overflow_result_store (lhs, target, mode, res);
2619 : }
2620 18898 : flag_trapv = save_flag_trapv;
2621 18898 : }
2622 :
2623 : /* Expand UBSAN_CHECK_* internal function if it has vector operands. */
2624 :
2625 : static void
2626 567 : expand_vector_ubsan_overflow (location_t loc, enum tree_code code, tree lhs,
2627 : tree arg0, tree arg1)
2628 : {
2629 567 : poly_uint64 cnt = TYPE_VECTOR_SUBPARTS (TREE_TYPE (arg0));
2630 567 : rtx_code_label *loop_lab = NULL;
2631 567 : rtx cntvar = NULL_RTX;
2632 567 : tree cntv = NULL_TREE;
2633 567 : tree eltype = TREE_TYPE (TREE_TYPE (arg0));
2634 567 : tree sz = TYPE_SIZE (eltype);
2635 567 : tree data = NULL_TREE;
2636 567 : tree resv = NULL_TREE;
2637 567 : rtx lhsr = NULL_RTX;
2638 567 : rtx resvr = NULL_RTX;
2639 567 : unsigned HOST_WIDE_INT const_cnt = 0;
2640 567 : bool use_loop_p = (!cnt.is_constant (&const_cnt) || const_cnt > 4);
2641 567 : int save_flag_trapv = flag_trapv;
2642 :
2643 : /* We don't want any __mulv?i3 etc. calls from the expansion of
2644 : these internal functions, so disable -ftrapv temporarily. */
2645 567 : flag_trapv = 0;
2646 567 : if (lhs)
2647 : {
2648 567 : optab op;
2649 567 : lhsr = expand_expr (lhs, NULL_RTX, VOIDmode, EXPAND_WRITE);
2650 141 : if (!VECTOR_MODE_P (GET_MODE (lhsr))
2651 426 : || (op = optab_for_tree_code (code, TREE_TYPE (arg0),
2652 : optab_default)) == unknown_optab
2653 993 : || (optab_handler (op, TYPE_MODE (TREE_TYPE (arg0)))
2654 : == CODE_FOR_nothing))
2655 : {
2656 141 : if (MEM_P (lhsr))
2657 141 : resv = make_tree (TREE_TYPE (lhs), lhsr);
2658 : else
2659 : {
2660 0 : resvr = assign_temp (TREE_TYPE (lhs), 1, 1);
2661 0 : resv = make_tree (TREE_TYPE (lhs), resvr);
2662 : }
2663 : }
2664 : }
2665 567 : if (use_loop_p)
2666 : {
2667 417 : do_pending_stack_adjust ();
2668 417 : loop_lab = gen_label_rtx ();
2669 417 : cntvar = gen_reg_rtx (TYPE_MODE (sizetype));
2670 417 : cntv = make_tree (sizetype, cntvar);
2671 417 : emit_move_insn (cntvar, const0_rtx);
2672 417 : emit_label (loop_lab);
2673 : }
2674 567 : if (TREE_CODE (arg0) != VECTOR_CST)
2675 : {
2676 461 : rtx arg0r = expand_normal (arg0);
2677 461 : arg0 = make_tree (TREE_TYPE (arg0), arg0r);
2678 : }
2679 567 : if (TREE_CODE (arg1) != VECTOR_CST)
2680 : {
2681 555 : rtx arg1r = expand_normal (arg1);
2682 555 : arg1 = make_tree (TREE_TYPE (arg1), arg1r);
2683 : }
2684 2334 : for (unsigned int i = 0; i < (use_loop_p ? 1 : const_cnt); i++)
2685 : {
2686 1017 : tree op0, op1, res = NULL_TREE;
2687 1017 : if (use_loop_p)
2688 : {
2689 417 : tree atype = build_array_type_nelts (eltype, cnt);
2690 417 : op0 = uniform_vector_p (arg0);
2691 417 : if (op0 == NULL_TREE)
2692 : {
2693 351 : op0 = fold_build1_loc (loc, VIEW_CONVERT_EXPR, atype, arg0);
2694 351 : op0 = build4_loc (loc, ARRAY_REF, eltype, op0, cntv,
2695 : NULL_TREE, NULL_TREE);
2696 : }
2697 417 : op1 = uniform_vector_p (arg1);
2698 417 : if (op1 == NULL_TREE)
2699 : {
2700 411 : op1 = fold_build1_loc (loc, VIEW_CONVERT_EXPR, atype, arg1);
2701 411 : op1 = build4_loc (loc, ARRAY_REF, eltype, op1, cntv,
2702 : NULL_TREE, NULL_TREE);
2703 : }
2704 417 : if (resv)
2705 : {
2706 141 : res = fold_build1_loc (loc, VIEW_CONVERT_EXPR, atype, resv);
2707 141 : res = build4_loc (loc, ARRAY_REF, eltype, res, cntv,
2708 : NULL_TREE, NULL_TREE);
2709 : }
2710 : }
2711 : else
2712 : {
2713 600 : tree bitpos = bitsize_int (tree_to_uhwi (sz) * i);
2714 600 : op0 = fold_build3_loc (loc, BIT_FIELD_REF, eltype, arg0, sz, bitpos);
2715 600 : op1 = fold_build3_loc (loc, BIT_FIELD_REF, eltype, arg1, sz, bitpos);
2716 600 : if (resv)
2717 0 : res = fold_build3_loc (loc, BIT_FIELD_REF, eltype, resv, sz,
2718 : bitpos);
2719 : }
2720 1017 : switch (code)
2721 : {
2722 317 : case PLUS_EXPR:
2723 317 : expand_addsub_overflow (loc, PLUS_EXPR, res, op0, op1,
2724 : false, false, false, true, &data);
2725 317 : break;
2726 534 : case MINUS_EXPR:
2727 534 : if (use_loop_p ? integer_zerop (arg0) : integer_zerop (op0))
2728 226 : expand_neg_overflow (loc, res, op1, true, &data);
2729 : else
2730 308 : expand_addsub_overflow (loc, MINUS_EXPR, res, op0, op1,
2731 : false, false, false, true, &data);
2732 : break;
2733 166 : case MULT_EXPR:
2734 166 : expand_mul_overflow (loc, res, op0, op1, false, false, false,
2735 : true, &data);
2736 166 : break;
2737 0 : default:
2738 0 : gcc_unreachable ();
2739 : }
2740 : }
2741 567 : if (use_loop_p)
2742 : {
2743 417 : struct separate_ops ops;
2744 417 : ops.code = PLUS_EXPR;
2745 417 : ops.type = TREE_TYPE (cntv);
2746 417 : ops.op0 = cntv;
2747 417 : ops.op1 = build_int_cst (TREE_TYPE (cntv), 1);
2748 417 : ops.op2 = NULL_TREE;
2749 417 : ops.location = loc;
2750 417 : rtx ret = expand_expr_real_2 (&ops, cntvar, TYPE_MODE (sizetype),
2751 : EXPAND_NORMAL);
2752 417 : if (ret != cntvar)
2753 0 : emit_move_insn (cntvar, ret);
2754 417 : rtx cntrtx = gen_int_mode (cnt, TYPE_MODE (sizetype));
2755 834 : do_compare_rtx_and_jump (cntvar, cntrtx, NE, false,
2756 417 : TYPE_MODE (sizetype), NULL_RTX, NULL, loop_lab,
2757 : profile_probability::very_likely ());
2758 : }
2759 567 : if (lhs && resv == NULL_TREE)
2760 : {
2761 426 : struct separate_ops ops;
2762 426 : ops.code = code;
2763 426 : ops.type = TREE_TYPE (arg0);
2764 426 : ops.op0 = arg0;
2765 426 : ops.op1 = arg1;
2766 426 : ops.op2 = NULL_TREE;
2767 426 : ops.location = loc;
2768 426 : rtx ret = expand_expr_real_2 (&ops, lhsr, TYPE_MODE (TREE_TYPE (arg0)),
2769 : EXPAND_NORMAL);
2770 426 : if (ret != lhsr)
2771 5 : emit_move_insn (lhsr, ret);
2772 : }
2773 141 : else if (resvr)
2774 0 : emit_move_insn (lhsr, resvr);
2775 567 : flag_trapv = save_flag_trapv;
2776 567 : }
2777 :
2778 : /* Expand UBSAN_CHECK_ADD call STMT. */
2779 :
2780 : static void
2781 1792 : expand_UBSAN_CHECK_ADD (internal_fn, gcall *stmt)
2782 : {
2783 1792 : location_t loc = gimple_location (stmt);
2784 1792 : tree lhs = gimple_call_lhs (stmt);
2785 1792 : tree arg0 = gimple_call_arg (stmt, 0);
2786 1792 : tree arg1 = gimple_call_arg (stmt, 1);
2787 1792 : if (VECTOR_TYPE_P (TREE_TYPE (arg0)))
2788 185 : expand_vector_ubsan_overflow (loc, PLUS_EXPR, lhs, arg0, arg1);
2789 : else
2790 1607 : expand_addsub_overflow (loc, PLUS_EXPR, lhs, arg0, arg1,
2791 : false, false, false, true, NULL);
2792 1792 : }
2793 :
2794 : /* Expand UBSAN_CHECK_SUB call STMT. */
2795 :
2796 : static void
2797 1865 : expand_UBSAN_CHECK_SUB (internal_fn, gcall *stmt)
2798 : {
2799 1865 : location_t loc = gimple_location (stmt);
2800 1865 : tree lhs = gimple_call_lhs (stmt);
2801 1865 : tree arg0 = gimple_call_arg (stmt, 0);
2802 1865 : tree arg1 = gimple_call_arg (stmt, 1);
2803 1865 : if (VECTOR_TYPE_P (TREE_TYPE (arg0)))
2804 282 : expand_vector_ubsan_overflow (loc, MINUS_EXPR, lhs, arg0, arg1);
2805 1583 : else if (integer_zerop (arg0))
2806 424 : expand_neg_overflow (loc, lhs, arg1, true, NULL);
2807 : else
2808 1159 : expand_addsub_overflow (loc, MINUS_EXPR, lhs, arg0, arg1,
2809 : false, false, false, true, NULL);
2810 1865 : }
2811 :
2812 : /* Expand UBSAN_CHECK_MUL call STMT. */
2813 :
2814 : static void
2815 1444 : expand_UBSAN_CHECK_MUL (internal_fn, gcall *stmt)
2816 : {
2817 1444 : location_t loc = gimple_location (stmt);
2818 1444 : tree lhs = gimple_call_lhs (stmt);
2819 1444 : tree arg0 = gimple_call_arg (stmt, 0);
2820 1444 : tree arg1 = gimple_call_arg (stmt, 1);
2821 1444 : if (VECTOR_TYPE_P (TREE_TYPE (arg0)))
2822 100 : expand_vector_ubsan_overflow (loc, MULT_EXPR, lhs, arg0, arg1);
2823 : else
2824 1344 : expand_mul_overflow (loc, lhs, arg0, arg1, false, false, false, true,
2825 : NULL);
2826 1444 : }
2827 :
2828 : /* Helper function for {ADD,SUB,MUL}_OVERFLOW call stmt expansion. */
2829 :
2830 : static void
2831 71836 : expand_arith_overflow (enum tree_code code, gimple *stmt)
2832 : {
2833 71836 : tree lhs = gimple_call_lhs (stmt);
2834 71836 : if (lhs == NULL_TREE)
2835 : return;
2836 71836 : tree arg0 = gimple_call_arg (stmt, 0);
2837 71836 : tree arg1 = gimple_call_arg (stmt, 1);
2838 71836 : tree type = TREE_TYPE (TREE_TYPE (lhs));
2839 71836 : int uns0_p = TYPE_UNSIGNED (TREE_TYPE (arg0));
2840 71836 : int uns1_p = TYPE_UNSIGNED (TREE_TYPE (arg1));
2841 71836 : int unsr_p = TYPE_UNSIGNED (type);
2842 71836 : int prec0 = TYPE_PRECISION (TREE_TYPE (arg0));
2843 71836 : int prec1 = TYPE_PRECISION (TREE_TYPE (arg1));
2844 71836 : int precres = TYPE_PRECISION (type);
2845 71836 : location_t loc = gimple_location (stmt);
2846 71836 : if (!uns0_p && get_range_pos_neg (arg0, stmt) == 1)
2847 : uns0_p = true;
2848 71836 : if (!uns1_p && get_range_pos_neg (arg1, stmt) == 1)
2849 : uns1_p = true;
2850 106065 : int pr = get_min_precision (arg0, uns0_p ? UNSIGNED : SIGNED);
2851 71836 : prec0 = MIN (prec0, pr);
2852 96974 : pr = get_min_precision (arg1, uns1_p ? UNSIGNED : SIGNED);
2853 71836 : prec1 = MIN (prec1, pr);
2854 71836 : int save_flag_trapv = flag_trapv;
2855 :
2856 : /* We don't want any __mulv?i3 etc. calls from the expansion of
2857 : these internal functions, so disable -ftrapv temporarily. */
2858 71836 : flag_trapv = 0;
2859 : /* If uns0_p && uns1_p, precop is minimum needed precision
2860 : of unsigned type to hold the exact result, otherwise
2861 : precop is minimum needed precision of signed type to
2862 : hold the exact result. */
2863 71836 : int precop;
2864 71836 : if (code == MULT_EXPR)
2865 23396 : precop = prec0 + prec1 + (uns0_p != uns1_p);
2866 : else
2867 : {
2868 48440 : if (uns0_p == uns1_p)
2869 31324 : precop = MAX (prec0, prec1) + 1;
2870 17116 : else if (uns0_p)
2871 5815 : precop = MAX (prec0 + 1, prec1) + 1;
2872 : else
2873 11301 : precop = MAX (prec0, prec1 + 1) + 1;
2874 : }
2875 71836 : int orig_precres = precres;
2876 :
2877 91256 : do
2878 : {
2879 91256 : if ((uns0_p && uns1_p)
2880 91256 : ? ((precop + !unsr_p) <= precres
2881 : /* u1 - u2 -> ur can overflow, no matter what precision
2882 : the result has. */
2883 33624 : && (code != MINUS_EXPR || !unsr_p))
2884 57632 : : (!unsr_p && precop <= precres))
2885 : {
2886 : /* The infinity precision result will always fit into result. */
2887 18526 : rtx target = expand_expr (lhs, NULL_RTX, VOIDmode, EXPAND_WRITE);
2888 18526 : write_complex_part (target, const0_rtx, true, false);
2889 18526 : scalar_int_mode mode = SCALAR_INT_TYPE_MODE (type);
2890 18526 : struct separate_ops ops;
2891 18526 : ops.code = code;
2892 18526 : ops.type = type;
2893 18526 : ops.op0 = fold_convert_loc (loc, type, arg0);
2894 18526 : ops.op1 = fold_convert_loc (loc, type, arg1);
2895 18526 : ops.op2 = NULL_TREE;
2896 18526 : ops.location = loc;
2897 18526 : rtx tem = expand_expr_real_2 (&ops, NULL_RTX, mode, EXPAND_NORMAL);
2898 18526 : expand_arith_overflow_result_store (lhs, target, mode, tem);
2899 18526 : flag_trapv = save_flag_trapv;
2900 18526 : return;
2901 : }
2902 :
2903 : /* For operations with low precision, if target doesn't have them, start
2904 : with precres widening right away, otherwise do it only if the most
2905 : simple cases can't be used. */
2906 72730 : const int min_precision = targetm.min_arithmetic_precision ();
2907 72730 : if (orig_precres == precres && precres < min_precision)
2908 : ;
2909 71463 : else if ((uns0_p && uns1_p && unsr_p && prec0 <= precres
2910 20782 : && prec1 <= precres)
2911 50684 : || ((!uns0_p || !uns1_p) && !unsr_p
2912 20655 : && prec0 + uns0_p <= precres
2913 17465 : && prec1 + uns1_p <= precres))
2914 : {
2915 34086 : arg0 = fold_convert_loc (loc, type, arg0);
2916 34086 : arg1 = fold_convert_loc (loc, type, arg1);
2917 34086 : switch (code)
2918 : {
2919 9845 : case MINUS_EXPR:
2920 9845 : if (integer_zerop (arg0) && !unsr_p)
2921 : {
2922 402 : expand_neg_overflow (loc, lhs, arg1, false, NULL);
2923 402 : flag_trapv = save_flag_trapv;
2924 402 : return;
2925 : }
2926 : /* FALLTHRU */
2927 24036 : case PLUS_EXPR:
2928 24036 : expand_addsub_overflow (loc, code, lhs, arg0, arg1, unsr_p,
2929 : unsr_p, unsr_p, false, NULL);
2930 24036 : flag_trapv = save_flag_trapv;
2931 24036 : return;
2932 9648 : case MULT_EXPR:
2933 9648 : expand_mul_overflow (loc, lhs, arg0, arg1, unsr_p,
2934 : unsr_p, unsr_p, false, NULL);
2935 9648 : flag_trapv = save_flag_trapv;
2936 9648 : return;
2937 0 : default:
2938 0 : gcc_unreachable ();
2939 : }
2940 : }
2941 :
2942 : /* For sub-word operations, retry with a wider type first. */
2943 38645 : if (orig_precres == precres && precop <= BITS_PER_WORD)
2944 : {
2945 19508 : int p = MAX (min_precision, precop);
2946 19508 : scalar_int_mode m = smallest_int_mode_for_size (p).require ();
2947 19508 : tree optype = build_nonstandard_integer_type (GET_MODE_PRECISION (m),
2948 : uns0_p && uns1_p
2949 19508 : && unsr_p);
2950 19508 : p = TYPE_PRECISION (optype);
2951 19508 : if (p > precres)
2952 : {
2953 18805 : precres = p;
2954 18805 : unsr_p = TYPE_UNSIGNED (optype);
2955 18805 : type = optype;
2956 18805 : continue;
2957 : }
2958 : }
2959 :
2960 19839 : if (prec0 <= precres && prec1 <= precres)
2961 : {
2962 19224 : tree types[2];
2963 19224 : if (unsr_p)
2964 : {
2965 11083 : types[0] = build_nonstandard_integer_type (precres, 0);
2966 11083 : types[1] = type;
2967 : }
2968 : else
2969 : {
2970 8141 : types[0] = type;
2971 8141 : types[1] = build_nonstandard_integer_type (precres, 1);
2972 : }
2973 19224 : arg0 = fold_convert_loc (loc, types[uns0_p], arg0);
2974 19224 : arg1 = fold_convert_loc (loc, types[uns1_p], arg1);
2975 19224 : if (code != MULT_EXPR)
2976 11484 : expand_addsub_overflow (loc, code, lhs, arg0, arg1, unsr_p,
2977 : uns0_p, uns1_p, false, NULL);
2978 : else
2979 7740 : expand_mul_overflow (loc, lhs, arg0, arg1, unsr_p,
2980 : uns0_p, uns1_p, false, NULL);
2981 19224 : flag_trapv = save_flag_trapv;
2982 19224 : return;
2983 : }
2984 :
2985 : /* Retry with a wider type. */
2986 615 : if (orig_precres == precres)
2987 : {
2988 615 : int p = MAX (prec0, prec1);
2989 615 : scalar_int_mode m = smallest_int_mode_for_size (p).require ();
2990 615 : tree optype = build_nonstandard_integer_type (GET_MODE_PRECISION (m),
2991 : uns0_p && uns1_p
2992 615 : && unsr_p);
2993 615 : p = TYPE_PRECISION (optype);
2994 615 : if (p > precres)
2995 : {
2996 615 : precres = p;
2997 615 : unsr_p = TYPE_UNSIGNED (optype);
2998 615 : type = optype;
2999 615 : continue;
3000 : }
3001 : }
3002 :
3003 0 : gcc_unreachable ();
3004 : }
3005 : while (1);
3006 : }
3007 :
3008 : /* Expand ADD_OVERFLOW STMT. */
3009 :
3010 : static void
3011 24964 : expand_ADD_OVERFLOW (internal_fn, gcall *stmt)
3012 : {
3013 24964 : expand_arith_overflow (PLUS_EXPR, stmt);
3014 24964 : }
3015 :
3016 : /* Expand SUB_OVERFLOW STMT. */
3017 :
3018 : static void
3019 23476 : expand_SUB_OVERFLOW (internal_fn, gcall *stmt)
3020 : {
3021 23476 : expand_arith_overflow (MINUS_EXPR, stmt);
3022 23476 : }
3023 :
3024 : /* Expand MUL_OVERFLOW STMT. */
3025 :
3026 : static void
3027 23396 : expand_MUL_OVERFLOW (internal_fn, gcall *stmt)
3028 : {
3029 23396 : expand_arith_overflow (MULT_EXPR, stmt);
3030 23396 : }
3031 :
3032 : /* Expand UADDC STMT. */
3033 :
3034 : static void
3035 15899 : expand_UADDC (internal_fn ifn, gcall *stmt)
3036 : {
3037 15899 : tree lhs = gimple_call_lhs (stmt);
3038 15899 : tree arg1 = gimple_call_arg (stmt, 0);
3039 15899 : tree arg2 = gimple_call_arg (stmt, 1);
3040 15899 : tree arg3 = gimple_call_arg (stmt, 2);
3041 15899 : tree type = TREE_TYPE (arg1);
3042 15899 : machine_mode mode = TYPE_MODE (type);
3043 22394 : insn_code icode = optab_handler (ifn == IFN_UADDC
3044 : ? uaddc5_optab : usubc5_optab, mode);
3045 15899 : rtx op1 = expand_normal (arg1);
3046 15899 : rtx op2 = expand_normal (arg2);
3047 15899 : rtx op3 = expand_normal (arg3);
3048 15899 : rtx target = expand_expr (lhs, NULL_RTX, VOIDmode, EXPAND_WRITE);
3049 15899 : rtx re = gen_reg_rtx (mode);
3050 15899 : rtx im = gen_reg_rtx (mode);
3051 15899 : class expand_operand ops[5];
3052 15899 : create_output_operand (&ops[0], re, mode);
3053 15899 : create_output_operand (&ops[1], im, mode);
3054 15899 : create_input_operand (&ops[2], op1, mode);
3055 15899 : create_input_operand (&ops[3], op2, mode);
3056 15899 : create_input_operand (&ops[4], op3, mode);
3057 15899 : expand_insn (icode, 5, ops);
3058 15899 : write_complex_part (target, re, false, false);
3059 15899 : write_complex_part (target, im, true, false);
3060 15899 : }
3061 :
3062 : /* Expand USUBC STMT. */
3063 :
3064 : static void
3065 6495 : expand_USUBC (internal_fn ifn, gcall *stmt)
3066 : {
3067 6495 : expand_UADDC (ifn, stmt);
3068 6495 : }
3069 :
3070 : /* This should get folded in tree-vectorizer.cc. */
3071 :
3072 : static void
3073 0 : expand_LOOP_VECTORIZED (internal_fn, gcall *)
3074 : {
3075 0 : gcc_unreachable ();
3076 : }
3077 :
3078 : /* This should get folded in tree-vectorizer.cc. */
3079 :
3080 : static void
3081 0 : expand_LOOP_DIST_ALIAS (internal_fn, gcall *)
3082 : {
3083 0 : gcc_unreachable ();
3084 : }
3085 :
3086 : /* Return a memory reference of type TYPE for argument INDEX of STMT.
3087 : Use argument INDEX + 1 to derive the second (TBAA) operand. */
3088 :
3089 : static tree
3090 1401 : expand_call_mem_ref (tree type, gcall *stmt, int index)
3091 : {
3092 1401 : tree addr = gimple_call_arg (stmt, index);
3093 1401 : tree alias_ptr_type = TREE_TYPE (gimple_call_arg (stmt, index + 1));
3094 1401 : unsigned int align = tree_to_shwi (gimple_call_arg (stmt, index + 1));
3095 1401 : if (TYPE_ALIGN (type) != align)
3096 1139 : type = build_aligned_type (type, align);
3097 :
3098 1401 : tree tmp = addr;
3099 1401 : if (TREE_CODE (tmp) == SSA_NAME)
3100 : {
3101 1263 : gimple *def = get_gimple_for_ssa_name (tmp);
3102 1263 : if (def && gimple_assign_single_p (def))
3103 562 : tmp = gimple_assign_rhs1 (def);
3104 : }
3105 :
3106 1401 : if (TREE_CODE (tmp) == ADDR_EXPR)
3107 : {
3108 700 : tree mem = TREE_OPERAND (tmp, 0);
3109 700 : if (TREE_CODE (mem) == TARGET_MEM_REF
3110 700 : && types_compatible_p (TREE_TYPE (mem), type))
3111 : {
3112 562 : tree offset = TMR_OFFSET (mem);
3113 562 : if (type != TREE_TYPE (mem)
3114 132 : || alias_ptr_type != TREE_TYPE (offset)
3115 694 : || !integer_zerop (offset))
3116 : {
3117 457 : mem = copy_node (mem);
3118 914 : TMR_OFFSET (mem) = wide_int_to_tree (alias_ptr_type,
3119 457 : wi::to_poly_wide (offset));
3120 457 : TREE_TYPE (mem) = type;
3121 : }
3122 : return mem;
3123 : }
3124 : }
3125 :
3126 839 : return fold_build2 (MEM_REF, type, addr, build_int_cst (alias_ptr_type, 0));
3127 : }
3128 :
3129 : /* Expand MASK_LOAD{,_LANES}, MASK_LEN_LOAD or LEN_LOAD call STMT using optab
3130 : * OPTAB. */
3131 :
3132 : static void
3133 675 : expand_partial_load_optab_fn (internal_fn ifn, gcall *stmt, convert_optab optab)
3134 : {
3135 675 : int i = 0;
3136 675 : class expand_operand ops[6];
3137 675 : tree type, lhs, rhs, maskt;
3138 675 : rtx mem, target;
3139 675 : insn_code icode;
3140 :
3141 675 : maskt = gimple_call_arg (stmt, internal_fn_mask_index (ifn));
3142 675 : lhs = gimple_call_lhs (stmt);
3143 675 : if (lhs == NULL_TREE)
3144 0 : return;
3145 675 : type = TREE_TYPE (lhs);
3146 675 : rhs = expand_call_mem_ref (type, stmt, 0);
3147 :
3148 675 : if (optab == vec_mask_load_lanes_optab
3149 675 : || optab == vec_mask_len_load_lanes_optab)
3150 0 : icode = get_multi_vector_move (type, optab);
3151 675 : else if (optab == len_load_optab)
3152 0 : icode = direct_optab_handler (optab, TYPE_MODE (type));
3153 : else
3154 675 : icode = convert_optab_handler (optab, TYPE_MODE (type),
3155 675 : TYPE_MODE (TREE_TYPE (maskt)));
3156 :
3157 675 : mem = expand_expr (rhs, NULL_RTX, VOIDmode, EXPAND_MEMORY);
3158 675 : gcc_assert (MEM_P (mem));
3159 675 : MEM_NOTRAP_P (mem) = !tree_could_trap_p (rhs);
3160 : /* The built MEM_REF does not accurately reflect that the load
3161 : is only partial. Clear it. */
3162 675 : set_mem_expr (mem, NULL_TREE);
3163 675 : clear_mem_offset (mem);
3164 675 : target = expand_expr (lhs, NULL_RTX, VOIDmode, EXPAND_WRITE);
3165 675 : create_call_lhs_operand (&ops[i++], target, TYPE_MODE (type));
3166 675 : create_fixed_operand (&ops[i++], mem);
3167 675 : i = add_mask_else_and_len_args (ops, i, stmt);
3168 675 : expand_insn (icode, i, ops);
3169 :
3170 675 : assign_call_lhs (lhs, target, &ops[0]);
3171 : }
3172 :
3173 : #define expand_mask_load_optab_fn expand_partial_load_optab_fn
3174 : #define expand_mask_load_lanes_optab_fn expand_mask_load_optab_fn
3175 : #define expand_len_load_optab_fn expand_partial_load_optab_fn
3176 : #define expand_mask_len_load_optab_fn expand_partial_load_optab_fn
3177 :
3178 : /* Expand MASK_STORE{,_LANES}, MASK_LEN_STORE or LEN_STORE call STMT using optab
3179 : * OPTAB. */
3180 :
3181 : static void
3182 726 : expand_partial_store_optab_fn (internal_fn ifn, gcall *stmt, convert_optab optab)
3183 : {
3184 726 : int i = 0;
3185 726 : class expand_operand ops[5];
3186 726 : tree type, lhs, rhs, maskt;
3187 726 : rtx mem, reg;
3188 726 : insn_code icode;
3189 :
3190 726 : maskt = gimple_call_arg (stmt, internal_fn_mask_index (ifn));
3191 726 : rhs = gimple_call_arg (stmt, internal_fn_stored_value_index (ifn));
3192 726 : type = TREE_TYPE (rhs);
3193 726 : lhs = expand_call_mem_ref (type, stmt, 0);
3194 :
3195 726 : if (optab == vec_mask_store_lanes_optab
3196 726 : || optab == vec_mask_len_store_lanes_optab)
3197 0 : icode = get_multi_vector_move (type, optab);
3198 726 : else if (optab == len_store_optab)
3199 0 : icode = direct_optab_handler (optab, TYPE_MODE (type));
3200 : else
3201 726 : icode = convert_optab_handler (optab, TYPE_MODE (type),
3202 726 : TYPE_MODE (TREE_TYPE (maskt)));
3203 :
3204 726 : mem = expand_expr (lhs, NULL_RTX, VOIDmode, EXPAND_WRITE);
3205 726 : gcc_assert (MEM_P (mem));
3206 : /* The built MEM_REF does not accurately reflect that the store
3207 : is only partial. Clear it. */
3208 726 : set_mem_expr (mem, NULL_TREE);
3209 726 : clear_mem_offset (mem);
3210 726 : reg = expand_normal (rhs);
3211 726 : create_fixed_operand (&ops[i++], mem);
3212 726 : create_input_operand (&ops[i++], reg, TYPE_MODE (type));
3213 726 : i = add_mask_else_and_len_args (ops, i, stmt);
3214 726 : expand_insn (icode, i, ops);
3215 726 : }
3216 :
3217 : #define expand_mask_store_optab_fn expand_partial_store_optab_fn
3218 : #define expand_mask_store_lanes_optab_fn expand_mask_store_optab_fn
3219 : #define expand_len_store_optab_fn expand_partial_store_optab_fn
3220 : #define expand_mask_len_store_optab_fn expand_partial_store_optab_fn
3221 :
3222 : /* Expand VCOND_MASK optab internal function.
3223 : The expansion of STMT happens based on OPTAB table associated. */
3224 :
3225 : static void
3226 9267 : expand_vec_cond_mask_optab_fn (internal_fn, gcall *stmt, convert_optab optab)
3227 : {
3228 9267 : class expand_operand ops[4];
3229 :
3230 9267 : tree lhs = gimple_call_lhs (stmt);
3231 9267 : tree op0 = gimple_call_arg (stmt, 0);
3232 9267 : tree op1 = gimple_call_arg (stmt, 1);
3233 9267 : tree op2 = gimple_call_arg (stmt, 2);
3234 9267 : tree vec_cond_type = TREE_TYPE (lhs);
3235 :
3236 9267 : machine_mode mode = TYPE_MODE (vec_cond_type);
3237 9267 : machine_mode mask_mode = TYPE_MODE (TREE_TYPE (op0));
3238 9267 : enum insn_code icode = convert_optab_handler (optab, mode, mask_mode);
3239 9267 : rtx mask, rtx_op1, rtx_op2;
3240 :
3241 9267 : gcc_assert (icode != CODE_FOR_nothing);
3242 :
3243 : /* Find the comparison generating the mask OP0. */
3244 9267 : tree cmp_op0 = NULL_TREE;
3245 9267 : tree cmp_op1 = NULL_TREE;
3246 9267 : enum tree_code cmp_code = TREE_CODE (op0);
3247 9267 : if (TREE_CODE_CLASS (cmp_code) == tcc_comparison)
3248 : {
3249 0 : cmp_op0 = TREE_OPERAND (op0, 0);
3250 0 : cmp_op1 = TREE_OPERAND (op0, 1);
3251 : }
3252 9267 : else if (cmp_code == SSA_NAME)
3253 : {
3254 7931 : gimple *def_stmt = get_gimple_for_ssa_name (op0);
3255 7931 : if (def_stmt && is_gimple_assign (def_stmt))
3256 : {
3257 6314 : cmp_code = gimple_assign_rhs_code (def_stmt);
3258 6314 : if (TREE_CODE_CLASS (cmp_code) == tcc_comparison)
3259 : {
3260 4604 : cmp_op0 = gimple_assign_rhs1 (def_stmt);
3261 4604 : cmp_op1 = gimple_assign_rhs2 (def_stmt);
3262 : }
3263 : }
3264 : }
3265 :
3266 : /* Decide whether to invert comparison based on rtx_cost. */
3267 4604 : if (cmp_op0)
3268 : {
3269 4604 : enum tree_code rev_code;
3270 4604 : tree op_type = TREE_TYPE (cmp_op0);
3271 4604 : int unsignedp = TYPE_UNSIGNED (op_type);
3272 4604 : rev_code = invert_tree_comparison (cmp_code, HONOR_NANS (op_type));
3273 :
3274 4604 : if (rev_code != ERROR_MARK)
3275 : {
3276 3373 : tree cmp_type = TREE_TYPE (op0);
3277 3373 : machine_mode cmp_mode = TYPE_MODE (cmp_type);
3278 3373 : machine_mode op_mode = TYPE_MODE (op_type);
3279 3373 : bool speed_p = optimize_insn_for_speed_p ();
3280 3373 : rtx reg = gen_raw_REG (op_mode, LAST_VIRTUAL_REGISTER + 1);
3281 3373 : enum rtx_code cmp_rtx_code = convert_tree_comp_to_rtx (cmp_code,
3282 : unsignedp);
3283 3373 : rtx veccmp = gen_rtx_fmt_ee (cmp_rtx_code, cmp_mode, reg, reg);
3284 3373 : int old_cost = rtx_cost (veccmp, cmp_mode, SET, 0, speed_p);
3285 3373 : enum rtx_code rev_rtx_code = convert_tree_comp_to_rtx (rev_code,
3286 : unsignedp);
3287 3373 : PUT_CODE (veccmp, rev_rtx_code);
3288 3373 : int new_cost = rtx_cost (veccmp, cmp_mode, SET, 0, speed_p);
3289 3373 : if (new_cost < old_cost)
3290 : {
3291 359 : op0 = fold_build2_loc (EXPR_LOCATION (op0), rev_code,
3292 : cmp_type, cmp_op0, cmp_op1);
3293 359 : std::swap (op1, op2);
3294 : }
3295 :
3296 3373 : if (dump_file && (dump_flags & TDF_DETAILS))
3297 : {
3298 0 : fprintf (dump_file,
3299 : ";; %sswapping operands of .VCOND_MASK\n",
3300 : new_cost >= old_cost ? "not " : "");
3301 0 : fprintf (dump_file,
3302 : ";; cost of original %s: %d\n",
3303 0 : GET_RTX_NAME (cmp_rtx_code), old_cost);
3304 0 : fprintf (dump_file,
3305 : ";; cost of replacement %s: %d\n",
3306 0 : GET_RTX_NAME (rev_rtx_code), new_cost);
3307 : }
3308 : }
3309 : }
3310 :
3311 9267 : mask = expand_normal (op0);
3312 9267 : rtx_op1 = expand_normal (op1);
3313 9267 : rtx_op2 = expand_normal (op2);
3314 :
3315 9267 : rtx target = expand_expr (lhs, NULL_RTX, VOIDmode, EXPAND_WRITE);
3316 9267 : create_call_lhs_operand (&ops[0], target, mode);
3317 9267 : create_input_operand (&ops[1], rtx_op1, mode);
3318 9267 : create_input_operand (&ops[2], rtx_op2, mode);
3319 9267 : create_input_operand (&ops[3], mask, mask_mode);
3320 9267 : expand_insn (icode, 4, ops);
3321 9267 : assign_call_lhs (lhs, target, &ops[0]);
3322 9267 : }
3323 :
3324 : /* Expand VEC_SET internal functions. */
3325 :
3326 : static void
3327 123 : expand_vec_set_optab_fn (internal_fn, gcall *stmt, convert_optab optab)
3328 : {
3329 123 : tree lhs = gimple_call_lhs (stmt);
3330 123 : tree op0 = gimple_call_arg (stmt, 0);
3331 123 : tree op1 = gimple_call_arg (stmt, 1);
3332 123 : tree op2 = gimple_call_arg (stmt, 2);
3333 123 : rtx target = expand_expr (lhs, NULL_RTX, VOIDmode, EXPAND_WRITE);
3334 123 : rtx src = expand_normal (op0);
3335 :
3336 123 : machine_mode outermode = TYPE_MODE (TREE_TYPE (op0));
3337 123 : scalar_mode innermode = GET_MODE_INNER (outermode);
3338 :
3339 123 : rtx value = expand_normal (op1);
3340 123 : rtx pos = expand_normal (op2);
3341 :
3342 123 : class expand_operand ops[3];
3343 123 : enum insn_code icode = optab_handler (optab, outermode);
3344 :
3345 123 : if (icode != CODE_FOR_nothing)
3346 : {
3347 123 : rtx temp = gen_reg_rtx (outermode);
3348 123 : emit_move_insn (temp, src);
3349 :
3350 123 : create_fixed_operand (&ops[0], temp);
3351 123 : create_input_operand (&ops[1], value, innermode);
3352 123 : create_convert_operand_from (&ops[2], pos, TYPE_MODE (TREE_TYPE (op2)),
3353 : true);
3354 123 : if (maybe_expand_insn (icode, 3, ops))
3355 : {
3356 123 : emit_move_insn (target, temp);
3357 123 : return;
3358 : }
3359 : }
3360 0 : gcc_unreachable ();
3361 : }
3362 :
3363 : static void
3364 1872 : expand_ABNORMAL_DISPATCHER (internal_fn, gcall *)
3365 : {
3366 1872 : }
3367 :
3368 : static void
3369 0 : expand_BUILTIN_EXPECT (internal_fn, gcall *stmt)
3370 : {
3371 : /* When guessing was done, the hints should be already stripped away. */
3372 0 : gcc_assert (!flag_guess_branch_prob || optimize == 0 || seen_error ());
3373 :
3374 0 : rtx target;
3375 0 : tree lhs = gimple_call_lhs (stmt);
3376 0 : if (lhs)
3377 0 : target = expand_expr (lhs, NULL_RTX, VOIDmode, EXPAND_WRITE);
3378 : else
3379 0 : target = const0_rtx;
3380 0 : rtx val = expand_expr (gimple_call_arg (stmt, 0), target, VOIDmode, EXPAND_NORMAL);
3381 0 : if (lhs && val != target)
3382 0 : emit_move_insn (target, val);
3383 0 : }
3384 :
3385 : /* IFN_VA_ARG is supposed to be expanded at pass_stdarg. So this dummy function
3386 : should never be called. */
3387 :
3388 : static void
3389 0 : expand_VA_ARG (internal_fn, gcall *)
3390 : {
3391 0 : gcc_unreachable ();
3392 : }
3393 :
3394 : /* IFN_VEC_CONVERT is supposed to be expanded at pass_lower_vector. So this
3395 : dummy function should never be called. */
3396 :
3397 : static void
3398 0 : expand_VEC_CONVERT (internal_fn, gcall *)
3399 : {
3400 0 : gcc_unreachable ();
3401 : }
3402 :
3403 : /* Expand IFN_RAWMEMCHR internal function. */
3404 :
3405 : void
3406 0 : expand_RAWMEMCHR (internal_fn, gcall *stmt)
3407 : {
3408 0 : expand_operand ops[3];
3409 :
3410 0 : tree lhs = gimple_call_lhs (stmt);
3411 0 : if (!lhs)
3412 0 : return;
3413 0 : machine_mode lhs_mode = TYPE_MODE (TREE_TYPE (lhs));
3414 0 : rtx lhs_rtx = expand_expr (lhs, NULL_RTX, VOIDmode, EXPAND_WRITE);
3415 0 : create_call_lhs_operand (&ops[0], lhs_rtx, lhs_mode);
3416 :
3417 0 : tree mem = gimple_call_arg (stmt, 0);
3418 0 : rtx mem_rtx = get_memory_rtx (mem, NULL, false);
3419 0 : create_fixed_operand (&ops[1], mem_rtx);
3420 :
3421 0 : tree pattern = gimple_call_arg (stmt, 1);
3422 0 : machine_mode mode = TYPE_MODE (TREE_TYPE (pattern));
3423 0 : rtx pattern_rtx = expand_normal (pattern);
3424 0 : create_input_operand (&ops[2], pattern_rtx, mode);
3425 :
3426 0 : insn_code icode = direct_optab_handler (rawmemchr_optab, mode);
3427 :
3428 0 : expand_insn (icode, 3, ops);
3429 0 : assign_call_lhs (lhs, lhs_rtx, &ops[0]);
3430 : }
3431 :
3432 : /* Expand the IFN_UNIQUE function according to its first argument. */
3433 :
3434 : static void
3435 0 : expand_UNIQUE (internal_fn, gcall *stmt)
3436 : {
3437 0 : rtx pattern = NULL_RTX;
3438 0 : enum ifn_unique_kind kind
3439 0 : = (enum ifn_unique_kind) TREE_INT_CST_LOW (gimple_call_arg (stmt, 0));
3440 :
3441 0 : switch (kind)
3442 : {
3443 0 : default:
3444 0 : gcc_unreachable ();
3445 :
3446 0 : case IFN_UNIQUE_UNSPEC:
3447 0 : if (targetm.have_unique ())
3448 0 : pattern = targetm.gen_unique ();
3449 : break;
3450 :
3451 0 : case IFN_UNIQUE_OACC_FORK:
3452 0 : case IFN_UNIQUE_OACC_JOIN:
3453 0 : if (targetm.have_oacc_fork () && targetm.have_oacc_join ())
3454 : {
3455 0 : tree lhs = gimple_call_lhs (stmt);
3456 0 : rtx target = const0_rtx;
3457 :
3458 0 : if (lhs)
3459 0 : target = expand_expr (lhs, NULL_RTX, VOIDmode, EXPAND_WRITE);
3460 :
3461 0 : rtx data_dep = expand_normal (gimple_call_arg (stmt, 1));
3462 0 : rtx axis = expand_normal (gimple_call_arg (stmt, 2));
3463 :
3464 0 : if (kind == IFN_UNIQUE_OACC_FORK)
3465 0 : pattern = targetm.gen_oacc_fork (target, data_dep, axis);
3466 : else
3467 0 : pattern = targetm.gen_oacc_join (target, data_dep, axis);
3468 : }
3469 : else
3470 0 : gcc_unreachable ();
3471 : break;
3472 : }
3473 :
3474 0 : if (pattern)
3475 0 : emit_insn (pattern);
3476 0 : }
3477 :
3478 : /* Expand the IFN_DEFERRED_INIT function:
3479 : LHS = DEFERRED_INIT (SIZE of the DECL, INIT_TYPE, NAME of the DECL);
3480 :
3481 : Initialize the LHS with zero/pattern according to its second argument
3482 : INIT_TYPE:
3483 : if INIT_TYPE is AUTO_INIT_ZERO, use zeroes to initialize;
3484 : if INIT_TYPE is AUTO_INIT_PATTERN, use 0xFE byte-repeatable pattern
3485 : to initialize;
3486 : The LHS variable is initialized including paddings.
3487 : The reasons to choose 0xFE for pattern initialization are:
3488 : 1. It is a non-canonical virtual address on x86_64, and at the
3489 : high end of the i386 kernel address space.
3490 : 2. It is a very large float value (-1.694739530317379e+38).
3491 : 3. It is also an unusual number for integers. */
3492 : #define INIT_PATTERN_VALUE 0xFE
3493 : static void
3494 40607 : expand_DEFERRED_INIT (internal_fn, gcall *stmt)
3495 : {
3496 40607 : tree lhs = gimple_call_lhs (stmt);
3497 40607 : tree var_size = gimple_call_arg (stmt, 0);
3498 40607 : enum auto_init_type init_type
3499 40607 : = (enum auto_init_type) TREE_INT_CST_LOW (gimple_call_arg (stmt, 1));
3500 40607 : bool reg_lhs = true;
3501 :
3502 40607 : tree var_type = TREE_TYPE (lhs);
3503 40607 : gcc_assert (init_type > AUTO_INIT_UNINITIALIZED);
3504 :
3505 40607 : if (TREE_CODE (lhs) == SSA_NAME)
3506 : reg_lhs = true;
3507 : else
3508 : {
3509 : tree lhs_base = lhs;
3510 27660 : while (handled_component_p (lhs_base))
3511 4 : lhs_base = TREE_OPERAND (lhs_base, 0);
3512 27656 : reg_lhs = (mem_ref_refers_to_non_mem_p (lhs_base)
3513 27656 : || non_mem_decl_p (lhs_base));
3514 : /* If this expands to a register and the underlying decl is wrapped in
3515 : a MEM_REF that just serves as an access type change expose the decl
3516 : if it is of correct size. This avoids a situation as in PR103271
3517 : if the target does not support a direct move to the registers mode. */
3518 : if (reg_lhs
3519 1832 : && TREE_CODE (lhs_base) == MEM_REF
3520 4 : && TREE_CODE (TREE_OPERAND (lhs_base, 0)) == ADDR_EXPR
3521 4 : && DECL_P (TREE_OPERAND (TREE_OPERAND (lhs_base, 0), 0))
3522 4 : && integer_zerop (TREE_OPERAND (lhs_base, 1))
3523 4 : && tree_fits_uhwi_p (var_size)
3524 4 : && tree_int_cst_equal
3525 4 : (var_size,
3526 4 : DECL_SIZE_UNIT (TREE_OPERAND (TREE_OPERAND (lhs_base, 0), 0))))
3527 : {
3528 4 : lhs = TREE_OPERAND (TREE_OPERAND (lhs_base, 0), 0);
3529 4 : var_type = TREE_TYPE (lhs);
3530 : }
3531 : }
3532 :
3533 27656 : if (!reg_lhs)
3534 : {
3535 : /* If the variable is not in register, expand to a memset
3536 : to initialize it. */
3537 25824 : mark_addressable (lhs);
3538 25824 : tree var_addr = build_fold_addr_expr (lhs);
3539 :
3540 25824 : tree value = ((init_type & ~AUTO_INIT_CXX26) == AUTO_INIT_PATTERN)
3541 25824 : ? build_int_cst (integer_type_node,
3542 : INIT_PATTERN_VALUE)
3543 25747 : : integer_zero_node;
3544 51648 : tree m_call = build_call_expr (builtin_decl_implicit (BUILT_IN_MEMSET),
3545 : 3, var_addr, value, var_size);
3546 : /* Expand this memset call. */
3547 25824 : expand_builtin_memset (m_call, NULL_RTX, TYPE_MODE (var_type));
3548 : }
3549 : else
3550 : {
3551 : /* If this variable is in a register use expand_assignment.
3552 : For boolean scalars force zero-init. */
3553 14783 : tree init;
3554 14783 : scalar_int_mode var_mode;
3555 14783 : if (TREE_CODE (TREE_TYPE (lhs)) != BOOLEAN_TYPE
3556 14410 : && tree_fits_uhwi_p (var_size)
3557 14410 : && ((init_type & ~AUTO_INIT_CXX26) == AUTO_INIT_PATTERN
3558 14324 : || !is_gimple_reg_type (var_type))
3559 1918 : && int_mode_for_size (tree_to_uhwi (var_size) * BITS_PER_UNIT,
3560 14788 : 0).exists (&var_mode)
3561 16701 : && have_insn_for (SET, var_mode))
3562 : {
3563 1913 : unsigned HOST_WIDE_INT total_bytes = tree_to_uhwi (var_size);
3564 1913 : unsigned char *buf = XALLOCAVEC (unsigned char, total_bytes);
3565 1913 : memset (buf, ((init_type & ~AUTO_INIT_CXX26) == AUTO_INIT_PATTERN
3566 : ? INIT_PATTERN_VALUE : 0), total_bytes);
3567 1913 : tree itype
3568 1913 : = build_nonstandard_integer_type (total_bytes * BITS_PER_UNIT, 1);
3569 1913 : wide_int w = wi::from_buffer (buf, total_bytes);
3570 1913 : init = wide_int_to_tree (itype, w);
3571 : /* Pun the LHS to make sure its type has constant size
3572 : unless it is an SSA name where that's already known. */
3573 1913 : if (TREE_CODE (lhs) != SSA_NAME)
3574 1832 : lhs = build1 (VIEW_CONVERT_EXPR, itype, lhs);
3575 : else
3576 81 : init = fold_build1 (VIEW_CONVERT_EXPR, TREE_TYPE (lhs), init);
3577 1913 : }
3578 : else
3579 : /* Use zero-init also for variable-length sizes. */
3580 12870 : init = build_zero_cst (var_type);
3581 :
3582 14783 : expand_assignment (lhs, init, false);
3583 : }
3584 40607 : }
3585 :
3586 : /* Expand the IFN_ACCESS_WITH_SIZE function:
3587 : ACCESS_WITH_SIZE (REF_TO_OBJ, REF_TO_SIZE,
3588 : TYPE_OF_SIZE + ACCESS_MODE, TYPE_SIZE_UNIT for element)
3589 : which returns the REF_TO_OBJ same as the 1st argument;
3590 :
3591 : 1st argument REF_TO_OBJ: The reference to the object;
3592 : 2nd argument REF_TO_SIZE: The reference to the size of the object,
3593 : 3rd argument TYPE_OF_SIZE + ACCESS_MODE: An integer constant with a pointer
3594 : TYPE.
3595 : The pointee TYPE of the pointer TYPE is the TYPE of the object referenced
3596 : by REF_TO_SIZE.
3597 : The integer constant value represents the ACCESS_MODE:
3598 : 0: none
3599 : 1: read_only
3600 : 2: write_only
3601 : 3: read_write
3602 :
3603 : 4th argument: The TYPE_SIZE_UNIT of the element TYPE of the array.
3604 :
3605 : Both the return type and the type of the first argument of this
3606 : function have been converted from the incomplete array type to
3607 : the corresponding pointer type.
3608 :
3609 : For each call to a .ACCESS_WITH_SIZE, replace it with its 1st argument. */
3610 :
3611 : static void
3612 521 : expand_ACCESS_WITH_SIZE (internal_fn, gcall *stmt)
3613 : {
3614 521 : tree lhs = gimple_call_lhs (stmt);
3615 521 : tree ref_to_obj = gimple_call_arg (stmt, 0);
3616 521 : if (lhs)
3617 521 : expand_assignment (lhs, ref_to_obj, false);
3618 521 : }
3619 :
3620 : /* The size of an OpenACC compute dimension. */
3621 :
3622 : static void
3623 5695 : expand_GOACC_DIM_SIZE (internal_fn, gcall *stmt)
3624 : {
3625 5695 : tree lhs = gimple_call_lhs (stmt);
3626 :
3627 5695 : if (!lhs)
3628 : return;
3629 :
3630 5695 : rtx target = expand_expr (lhs, NULL_RTX, VOIDmode, EXPAND_WRITE);
3631 5695 : if (targetm.have_oacc_dim_size ())
3632 : {
3633 0 : rtx dim = expand_expr (gimple_call_arg (stmt, 0), NULL_RTX,
3634 : VOIDmode, EXPAND_NORMAL);
3635 0 : emit_insn (targetm.gen_oacc_dim_size (target, dim));
3636 : }
3637 : else
3638 5695 : emit_move_insn (target, GEN_INT (1));
3639 : }
3640 :
3641 : /* The position of an OpenACC execution engine along one compute axis. */
3642 :
3643 : static void
3644 4567 : expand_GOACC_DIM_POS (internal_fn, gcall *stmt)
3645 : {
3646 4567 : tree lhs = gimple_call_lhs (stmt);
3647 :
3648 4567 : if (!lhs)
3649 : return;
3650 :
3651 4567 : rtx target = expand_expr (lhs, NULL_RTX, VOIDmode, EXPAND_WRITE);
3652 4567 : if (targetm.have_oacc_dim_pos ())
3653 : {
3654 0 : rtx dim = expand_expr (gimple_call_arg (stmt, 0), NULL_RTX,
3655 : VOIDmode, EXPAND_NORMAL);
3656 0 : emit_insn (targetm.gen_oacc_dim_pos (target, dim));
3657 : }
3658 : else
3659 4567 : emit_move_insn (target, const0_rtx);
3660 : }
3661 :
3662 : /* This is expanded by oacc_device_lower pass. */
3663 :
3664 : static void
3665 0 : expand_GOACC_LOOP (internal_fn, gcall *)
3666 : {
3667 0 : gcc_unreachable ();
3668 : }
3669 :
3670 : /* This is expanded by oacc_device_lower pass. */
3671 :
3672 : static void
3673 0 : expand_GOACC_REDUCTION (internal_fn, gcall *)
3674 : {
3675 0 : gcc_unreachable ();
3676 : }
3677 :
3678 : /* This is expanded by oacc_device_lower pass. */
3679 :
3680 : static void
3681 0 : expand_GOACC_TILE (internal_fn, gcall *)
3682 : {
3683 0 : gcc_unreachable ();
3684 : }
3685 :
3686 : /* Set errno to EDOM. */
3687 :
3688 : static void
3689 0 : expand_SET_EDOM (internal_fn, gcall *)
3690 : {
3691 : #ifdef TARGET_EDOM
3692 : #ifdef GEN_ERRNO_RTX
3693 : rtx errno_rtx = GEN_ERRNO_RTX;
3694 : #else
3695 : rtx errno_rtx = gen_rtx_MEM (word_mode, gen_rtx_SYMBOL_REF (Pmode, "errno"));
3696 : #endif
3697 : emit_move_insn (errno_rtx,
3698 : gen_int_mode (TARGET_EDOM, GET_MODE (errno_rtx)));
3699 : #else
3700 0 : gcc_unreachable ();
3701 : #endif
3702 : }
3703 :
3704 : /* Expand atomic bit test and set. */
3705 :
3706 : static void
3707 146 : expand_ATOMIC_BIT_TEST_AND_SET (internal_fn, gcall *call)
3708 : {
3709 146 : expand_ifn_atomic_bit_test_and (call);
3710 146 : }
3711 :
3712 : /* Expand atomic bit test and complement. */
3713 :
3714 : static void
3715 146 : expand_ATOMIC_BIT_TEST_AND_COMPLEMENT (internal_fn, gcall *call)
3716 : {
3717 146 : expand_ifn_atomic_bit_test_and (call);
3718 146 : }
3719 :
3720 : /* Expand atomic bit test and reset. */
3721 :
3722 : static void
3723 135 : expand_ATOMIC_BIT_TEST_AND_RESET (internal_fn, gcall *call)
3724 : {
3725 135 : expand_ifn_atomic_bit_test_and (call);
3726 135 : }
3727 :
3728 : /* Expand atomic bit test and set. */
3729 :
3730 : static void
3731 13951 : expand_ATOMIC_COMPARE_EXCHANGE (internal_fn, gcall *call)
3732 : {
3733 13951 : expand_ifn_atomic_compare_exchange (call);
3734 13951 : }
3735 :
3736 : /* Expand atomic add fetch and cmp with 0. */
3737 :
3738 : static void
3739 946 : expand_ATOMIC_ADD_FETCH_CMP_0 (internal_fn, gcall *call)
3740 : {
3741 946 : expand_ifn_atomic_op_fetch_cmp_0 (call);
3742 946 : }
3743 :
3744 : /* Expand atomic sub fetch and cmp with 0. */
3745 :
3746 : static void
3747 738 : expand_ATOMIC_SUB_FETCH_CMP_0 (internal_fn, gcall *call)
3748 : {
3749 738 : expand_ifn_atomic_op_fetch_cmp_0 (call);
3750 738 : }
3751 :
3752 : /* Expand atomic and fetch and cmp with 0. */
3753 :
3754 : static void
3755 176 : expand_ATOMIC_AND_FETCH_CMP_0 (internal_fn, gcall *call)
3756 : {
3757 176 : expand_ifn_atomic_op_fetch_cmp_0 (call);
3758 176 : }
3759 :
3760 : /* Expand atomic or fetch and cmp with 0. */
3761 :
3762 : static void
3763 112 : expand_ATOMIC_OR_FETCH_CMP_0 (internal_fn, gcall *call)
3764 : {
3765 112 : expand_ifn_atomic_op_fetch_cmp_0 (call);
3766 112 : }
3767 :
3768 : /* Expand atomic xor fetch and cmp with 0. */
3769 :
3770 : static void
3771 176 : expand_ATOMIC_XOR_FETCH_CMP_0 (internal_fn, gcall *call)
3772 : {
3773 176 : expand_ifn_atomic_op_fetch_cmp_0 (call);
3774 176 : }
3775 :
3776 : /* Expand LAUNDER to assignment, lhs = arg0. */
3777 :
3778 : static void
3779 29 : expand_LAUNDER (internal_fn, gcall *call)
3780 : {
3781 29 : tree lhs = gimple_call_lhs (call);
3782 :
3783 29 : if (!lhs)
3784 : return;
3785 :
3786 28 : expand_assignment (lhs, gimple_call_arg (call, 0), false);
3787 : }
3788 :
3789 : /* Expand {MASK_,}SCATTER_STORE{S,U} call CALL using optab OPTAB. */
3790 :
3791 : static void
3792 0 : expand_scatter_store_optab_fn (internal_fn, gcall *stmt, direct_optab optab)
3793 : {
3794 0 : internal_fn ifn = gimple_call_internal_fn (stmt);
3795 0 : int rhs_index = internal_fn_stored_value_index (ifn);
3796 0 : tree base = gimple_call_arg (stmt, 0);
3797 0 : tree offset = gimple_call_arg (stmt, internal_fn_offset_index (ifn));
3798 0 : tree scale = gimple_call_arg (stmt, internal_fn_scale_index (ifn));
3799 0 : tree rhs = gimple_call_arg (stmt, rhs_index);
3800 :
3801 0 : rtx base_rtx = expand_normal (base);
3802 0 : rtx offset_rtx = expand_normal (offset);
3803 0 : HOST_WIDE_INT scale_int = tree_to_shwi (scale);
3804 0 : rtx rhs_rtx = expand_normal (rhs);
3805 :
3806 0 : class expand_operand ops[8];
3807 0 : int i = 0;
3808 0 : create_address_operand (&ops[i++], base_rtx);
3809 0 : create_input_operand (&ops[i++], offset_rtx, TYPE_MODE (TREE_TYPE (offset)));
3810 0 : create_integer_operand (&ops[i++], TYPE_UNSIGNED (TREE_TYPE (offset)));
3811 0 : create_integer_operand (&ops[i++], scale_int);
3812 0 : create_input_operand (&ops[i++], rhs_rtx, TYPE_MODE (TREE_TYPE (rhs)));
3813 0 : i = add_mask_else_and_len_args (ops, i, stmt);
3814 :
3815 0 : insn_code icode = convert_optab_handler (optab, TYPE_MODE (TREE_TYPE (rhs)),
3816 0 : TYPE_MODE (TREE_TYPE (offset)));
3817 0 : expand_insn (icode, i, ops);
3818 0 : }
3819 :
3820 : /* Expand {MASK_,}GATHER_LOAD call CALL using optab OPTAB. */
3821 :
3822 : static void
3823 0 : expand_gather_load_optab_fn (internal_fn ifn, gcall *stmt, direct_optab optab)
3824 : {
3825 0 : tree lhs = gimple_call_lhs (stmt);
3826 0 : tree base = gimple_call_arg (stmt, 0);
3827 0 : tree offset = gimple_call_arg (stmt, internal_fn_offset_index (ifn));
3828 0 : tree scale = gimple_call_arg (stmt, internal_fn_scale_index (ifn));
3829 :
3830 0 : rtx lhs_rtx = expand_expr (lhs, NULL_RTX, VOIDmode, EXPAND_WRITE);
3831 0 : rtx base_rtx = expand_normal (base);
3832 0 : rtx offset_rtx = expand_normal (offset);
3833 0 : HOST_WIDE_INT scale_int = tree_to_shwi (scale);
3834 :
3835 0 : int i = 0;
3836 0 : class expand_operand ops[9];
3837 0 : create_call_lhs_operand (&ops[i++], lhs_rtx, TYPE_MODE (TREE_TYPE (lhs)));
3838 0 : create_address_operand (&ops[i++], base_rtx);
3839 0 : create_input_operand (&ops[i++], offset_rtx, TYPE_MODE (TREE_TYPE (offset)));
3840 0 : create_integer_operand (&ops[i++], TYPE_UNSIGNED (TREE_TYPE (offset)));
3841 0 : create_integer_operand (&ops[i++], scale_int);
3842 0 : i = add_mask_else_and_len_args (ops, i, stmt);
3843 0 : insn_code icode = convert_optab_handler (optab, TYPE_MODE (TREE_TYPE (lhs)),
3844 0 : TYPE_MODE (TREE_TYPE (offset)));
3845 0 : expand_insn (icode, i, ops);
3846 0 : assign_call_lhs (lhs, lhs_rtx, &ops[0]);
3847 0 : }
3848 :
3849 : /* Expand MASK_LEN_STRIDED_LOAD call CALL by optab OPTAB. */
3850 :
3851 : static void
3852 0 : expand_strided_load_optab_fn (ATTRIBUTE_UNUSED internal_fn, gcall *stmt,
3853 : direct_optab optab)
3854 : {
3855 0 : tree lhs = gimple_call_lhs (stmt);
3856 0 : tree base = gimple_call_arg (stmt, 0);
3857 0 : tree stride = gimple_call_arg (stmt, 1);
3858 :
3859 0 : rtx lhs_rtx = expand_expr (lhs, NULL_RTX, VOIDmode, EXPAND_WRITE);
3860 0 : rtx base_rtx = expand_normal (base);
3861 0 : rtx stride_rtx = expand_normal (stride);
3862 :
3863 0 : unsigned i = 0;
3864 0 : class expand_operand ops[7];
3865 0 : machine_mode mode = TYPE_MODE (TREE_TYPE (lhs));
3866 :
3867 0 : create_output_operand (&ops[i++], lhs_rtx, mode);
3868 0 : create_address_operand (&ops[i++], base_rtx);
3869 0 : create_address_operand (&ops[i++], stride_rtx);
3870 :
3871 0 : i = add_mask_else_and_len_args (ops, i, stmt);
3872 0 : expand_insn (direct_optab_handler (optab, mode), i, ops);
3873 :
3874 0 : if (!rtx_equal_p (lhs_rtx, ops[0].value))
3875 0 : emit_move_insn (lhs_rtx, ops[0].value);
3876 0 : }
3877 :
3878 : /* Expand MASK_LEN_STRIDED_STORE call CALL by optab OPTAB. */
3879 :
3880 : static void
3881 0 : expand_strided_store_optab_fn (ATTRIBUTE_UNUSED internal_fn, gcall *stmt,
3882 : direct_optab optab)
3883 : {
3884 0 : internal_fn fn = gimple_call_internal_fn (stmt);
3885 0 : int rhs_index = internal_fn_stored_value_index (fn);
3886 :
3887 0 : tree base = gimple_call_arg (stmt, 0);
3888 0 : tree stride = gimple_call_arg (stmt, 1);
3889 0 : tree rhs = gimple_call_arg (stmt, rhs_index);
3890 :
3891 0 : rtx base_rtx = expand_normal (base);
3892 0 : rtx stride_rtx = expand_normal (stride);
3893 0 : rtx rhs_rtx = expand_normal (rhs);
3894 :
3895 0 : unsigned i = 0;
3896 0 : class expand_operand ops[6];
3897 0 : machine_mode mode = TYPE_MODE (TREE_TYPE (rhs));
3898 :
3899 0 : create_address_operand (&ops[i++], base_rtx);
3900 0 : create_address_operand (&ops[i++], stride_rtx);
3901 0 : create_input_operand (&ops[i++], rhs_rtx, mode);
3902 :
3903 0 : i = add_mask_else_and_len_args (ops, i, stmt);
3904 0 : expand_insn (direct_optab_handler (optab, mode), i, ops);
3905 0 : }
3906 :
3907 : /* Helper for expand_DIVMOD. Return true if the sequence starting with
3908 : INSN contains any call insns or insns with {,U}{DIV,MOD} rtxes. */
3909 :
3910 : static bool
3911 838 : contains_call_div_mod (rtx_insn *insn)
3912 : {
3913 838 : subrtx_iterator::array_type array;
3914 4821 : for (; insn; insn = NEXT_INSN (insn))
3915 4821 : if (CALL_P (insn))
3916 : return true;
3917 3983 : else if (INSN_P (insn))
3918 17804 : FOR_EACH_SUBRTX (iter, array, PATTERN (insn), NONCONST)
3919 13821 : switch (GET_CODE (*iter))
3920 : {
3921 0 : case CALL:
3922 0 : case DIV:
3923 0 : case UDIV:
3924 0 : case MOD:
3925 0 : case UMOD:
3926 0 : return true;
3927 13821 : default:
3928 13821 : break;
3929 : }
3930 : return false;
3931 838 : }
3932 :
3933 : /* Expand DIVMOD() using:
3934 : a) optab handler for udivmod/sdivmod if it is available.
3935 : b) If optab_handler doesn't exist, generate call to
3936 : target-specific divmod libfunc. */
3937 :
3938 : static void
3939 11511 : expand_DIVMOD (internal_fn, gcall *call_stmt)
3940 : {
3941 11511 : tree lhs = gimple_call_lhs (call_stmt);
3942 11511 : tree arg0 = gimple_call_arg (call_stmt, 0);
3943 11511 : tree arg1 = gimple_call_arg (call_stmt, 1);
3944 :
3945 11511 : gcc_assert (TREE_CODE (TREE_TYPE (lhs)) == COMPLEX_TYPE);
3946 11511 : tree type = TREE_TYPE (TREE_TYPE (lhs));
3947 11511 : machine_mode mode = TYPE_MODE (type);
3948 11511 : bool unsignedp = TYPE_UNSIGNED (type);
3949 11511 : optab tab = (unsignedp) ? udivmod_optab : sdivmod_optab;
3950 :
3951 11511 : rtx op0 = expand_normal (arg0);
3952 11511 : rtx op1 = expand_normal (arg1);
3953 11511 : rtx target = expand_expr (lhs, NULL_RTX, VOIDmode, EXPAND_WRITE);
3954 :
3955 11511 : rtx quotient = NULL_RTX, remainder = NULL_RTX;
3956 11511 : rtx_insn *insns = NULL;
3957 :
3958 11511 : if (TREE_CODE (arg1) == INTEGER_CST)
3959 : {
3960 : /* For DIVMOD by integral constants, there could be efficient code
3961 : expanded inline e.g. using shifts and plus/minus. Try to expand
3962 : the division and modulo and if it emits any library calls or any
3963 : {,U}{DIV,MOD} rtxes throw it away and use a divmod optab or
3964 : divmod libcall. */
3965 1182 : scalar_int_mode int_mode;
3966 1182 : if (remainder == NULL_RTX
3967 1182 : && optimize
3968 1182 : && CONST_INT_P (op1)
3969 1178 : && !pow2p_hwi (INTVAL (op1))
3970 2356 : && is_int_mode (TYPE_MODE (type), &int_mode)
3971 1342 : && GET_MODE_SIZE (int_mode) == 2 * UNITS_PER_WORD
3972 1178 : && optab_handler (and_optab, word_mode) != CODE_FOR_nothing
3973 1178 : && optab_handler (add_optab, word_mode) != CODE_FOR_nothing
3974 1178 : && optimize_insn_for_speed_p ())
3975 : {
3976 1178 : rtx_insn *last = get_last_insn ();
3977 1178 : remainder = NULL_RTX;
3978 3534 : quotient = expand_doubleword_divmod (int_mode, op0, op1, &remainder,
3979 1178 : TYPE_UNSIGNED (type));
3980 1178 : if (quotient != NULL_RTX)
3981 : {
3982 344 : if (optab_handler (mov_optab, int_mode) != CODE_FOR_nothing)
3983 : {
3984 344 : rtx_insn *move = emit_move_insn (quotient, quotient);
3985 688 : set_dst_reg_note (move, REG_EQUAL,
3986 344 : gen_rtx_fmt_ee (TYPE_UNSIGNED (type)
3987 : ? UDIV : DIV, int_mode,
3988 : copy_rtx (op0), op1),
3989 : quotient);
3990 344 : move = emit_move_insn (remainder, remainder);
3991 688 : set_dst_reg_note (move, REG_EQUAL,
3992 344 : gen_rtx_fmt_ee (TYPE_UNSIGNED (type)
3993 : ? UMOD : MOD, int_mode,
3994 : copy_rtx (op0), op1),
3995 : quotient);
3996 : }
3997 : }
3998 : else
3999 834 : delete_insns_since (last);
4000 : }
4001 :
4002 1182 : if (remainder == NULL_RTX)
4003 : {
4004 838 : struct separate_ops ops;
4005 838 : ops.code = TRUNC_DIV_EXPR;
4006 838 : ops.type = type;
4007 838 : ops.op0 = make_tree (ops.type, op0);
4008 838 : ops.op1 = arg1;
4009 838 : ops.op2 = NULL_TREE;
4010 838 : ops.location = gimple_location (call_stmt);
4011 838 : start_sequence ();
4012 838 : quotient = expand_expr_real_2 (&ops, NULL_RTX, mode, EXPAND_NORMAL);
4013 838 : if (contains_call_div_mod (get_insns ()))
4014 838 : quotient = NULL_RTX;
4015 : else
4016 : {
4017 0 : ops.code = TRUNC_MOD_EXPR;
4018 0 : remainder = expand_expr_real_2 (&ops, NULL_RTX, mode,
4019 : EXPAND_NORMAL);
4020 0 : if (contains_call_div_mod (get_insns ()))
4021 0 : remainder = NULL_RTX;
4022 : }
4023 838 : if (remainder)
4024 0 : insns = get_insns ();
4025 838 : end_sequence ();
4026 : }
4027 : }
4028 :
4029 11511 : if (remainder)
4030 344 : emit_insn (insns);
4031 :
4032 : /* Check if optab_handler exists for divmod_optab for given mode. */
4033 11167 : else if (optab_handler (tab, mode) != CODE_FOR_nothing)
4034 : {
4035 10275 : quotient = gen_reg_rtx (mode);
4036 10275 : remainder = gen_reg_rtx (mode);
4037 10275 : expand_twoval_binop (tab, op0, op1, quotient, remainder, unsignedp);
4038 : }
4039 :
4040 : /* Generate call to divmod libfunc if it exists. */
4041 892 : else if (rtx libfunc = optab_libfunc (tab, mode))
4042 892 : targetm.expand_divmod_libfunc (libfunc, mode, op0, op1,
4043 : "ient, &remainder);
4044 :
4045 : else
4046 0 : gcc_unreachable ();
4047 :
4048 : /* Wrap the return value (quotient, remainder) within COMPLEX_EXPR. */
4049 23022 : expand_expr (build2 (COMPLEX_EXPR, TREE_TYPE (lhs),
4050 11511 : make_tree (TREE_TYPE (arg0), quotient),
4051 11511 : make_tree (TREE_TYPE (arg1), remainder)),
4052 : target, VOIDmode, EXPAND_NORMAL);
4053 11511 : }
4054 :
4055 : /* Expand a NOP. */
4056 :
4057 : static void
4058 1 : expand_NOP (internal_fn, gcall *)
4059 : {
4060 : /* Nothing. But it shouldn't really prevail. */
4061 1 : }
4062 :
4063 : /* Coroutines, all should have been processed at this stage. */
4064 :
4065 : static void
4066 0 : expand_CO_FRAME (internal_fn, gcall *)
4067 : {
4068 0 : gcc_unreachable ();
4069 : }
4070 :
4071 : static void
4072 0 : expand_CO_YIELD (internal_fn, gcall *)
4073 : {
4074 0 : gcc_unreachable ();
4075 : }
4076 :
4077 : static void
4078 0 : expand_CO_SUSPN (internal_fn, gcall *)
4079 : {
4080 0 : gcc_unreachable ();
4081 : }
4082 :
4083 : static void
4084 0 : expand_CO_ACTOR (internal_fn, gcall *)
4085 : {
4086 0 : gcc_unreachable ();
4087 : }
4088 :
4089 : /* Expand a call to FN using the operands in STMT. FN has a single
4090 : output operand and NARGS input operands. */
4091 :
4092 : static void
4093 76671 : expand_direct_optab_fn (internal_fn fn, gcall *stmt, direct_optab optab,
4094 : unsigned int nargs)
4095 : {
4096 76671 : tree_pair types = direct_internal_fn_types (fn, stmt);
4097 76671 : insn_code icode = direct_optab_handler (optab, TYPE_MODE (types.first));
4098 76671 : expand_fn_using_insn (stmt, icode, 1, nargs);
4099 76671 : }
4100 :
4101 : /* Expand WHILE_ULT call STMT using optab OPTAB. */
4102 :
4103 : static void
4104 0 : expand_while_optab_fn (internal_fn, gcall *stmt, convert_optab optab)
4105 : {
4106 0 : expand_operand ops[4];
4107 0 : tree rhs_type[2];
4108 :
4109 0 : tree lhs = gimple_call_lhs (stmt);
4110 0 : tree lhs_type = TREE_TYPE (lhs);
4111 0 : rtx lhs_rtx = expand_expr (lhs, NULL_RTX, VOIDmode, EXPAND_WRITE);
4112 0 : create_call_lhs_operand (&ops[0], lhs_rtx, TYPE_MODE (lhs_type));
4113 :
4114 0 : for (unsigned int i = 0; i < 2; ++i)
4115 : {
4116 0 : tree rhs = gimple_call_arg (stmt, i);
4117 0 : rhs_type[i] = TREE_TYPE (rhs);
4118 0 : rtx rhs_rtx = expand_normal (rhs);
4119 0 : create_input_operand (&ops[i + 1], rhs_rtx, TYPE_MODE (rhs_type[i]));
4120 : }
4121 :
4122 0 : int opcnt;
4123 0 : if (!VECTOR_MODE_P (TYPE_MODE (lhs_type)))
4124 : {
4125 : /* When the mask is an integer mode the exact vector length may not
4126 : be clear to the backend, so we pass it in operand[3].
4127 : Use the vector in arg2 for the most reliable intended size. */
4128 0 : tree type = TREE_TYPE (gimple_call_arg (stmt, 2));
4129 0 : create_integer_operand (&ops[3], TYPE_VECTOR_SUBPARTS (type));
4130 0 : opcnt = 4;
4131 : }
4132 : else
4133 : /* The mask has a vector type so the length operand is unnecessary. */
4134 : opcnt = 3;
4135 :
4136 0 : insn_code icode = convert_optab_handler (optab, TYPE_MODE (rhs_type[0]),
4137 0 : TYPE_MODE (lhs_type));
4138 :
4139 0 : expand_insn (icode, opcnt, ops);
4140 0 : assign_call_lhs (lhs, lhs_rtx, &ops[0]);
4141 0 : }
4142 :
4143 : /* Expand a call to a convert-like optab using the operands in STMT.
4144 : FN has a single output operand and NARGS input operands. */
4145 :
4146 : static void
4147 481 : expand_convert_optab_fn (internal_fn fn, gcall *stmt, convert_optab optab,
4148 : unsigned int nargs)
4149 : {
4150 481 : tree_pair types = direct_internal_fn_types (fn, stmt);
4151 481 : insn_code icode = convert_optab_handler (optab, TYPE_MODE (types.first),
4152 481 : TYPE_MODE (types.second));
4153 481 : expand_fn_using_insn (stmt, icode, 1, nargs);
4154 481 : }
4155 :
4156 : /* Expand CRC call STMT. */
4157 :
4158 : static void
4159 238 : expand_crc_optab_fn (internal_fn fn, gcall *stmt, convert_optab optab)
4160 : {
4161 238 : tree lhs = gimple_call_lhs (stmt);
4162 238 : tree rhs1 = gimple_call_arg (stmt, 0); // crc
4163 238 : tree rhs2 = gimple_call_arg (stmt, 1); // data
4164 238 : tree rhs3 = gimple_call_arg (stmt, 2); // polynomial
4165 :
4166 238 : tree result_type = TREE_TYPE (lhs);
4167 238 : tree data_type = TREE_TYPE (rhs2);
4168 :
4169 238 : gcc_assert (TYPE_MODE (result_type) >= TYPE_MODE (data_type));
4170 :
4171 238 : rtx dest = expand_expr (lhs, NULL_RTX, VOIDmode, EXPAND_WRITE);
4172 238 : rtx crc = expand_normal (rhs1);
4173 238 : rtx data = expand_normal (rhs2);
4174 238 : rtx polynomial;
4175 238 : if (TREE_CODE (rhs3) != INTEGER_CST)
4176 : {
4177 0 : error ("third argument to %<crc%> builtins must be a constant");
4178 0 : polynomial = const0_rtx;
4179 : }
4180 : else
4181 238 : polynomial = convert_to_mode (TYPE_MODE (result_type), expand_normal (rhs3), 0);
4182 :
4183 : /* Use target specific expansion if it exists.
4184 : Otherwise, generate table-based CRC. */
4185 238 : if (direct_internal_fn_supported_p (fn, tree_pair (data_type, result_type),
4186 : OPTIMIZE_FOR_SPEED))
4187 : {
4188 3 : class expand_operand ops[4];
4189 :
4190 3 : if (dump_file && (dump_flags & TDF_DETAILS))
4191 : {
4192 0 : fprintf (dump_file,
4193 : ";; using optab for crc_%u_polynomial_"
4194 : HOST_WIDE_INT_PRINT_HEX "\n",
4195 0 : GET_MODE_BITSIZE (GET_MODE (dest)).to_constant (),
4196 0 : TREE_INT_CST_LOW (rhs3));
4197 : }
4198 :
4199 3 : create_call_lhs_operand (&ops[0], dest, TYPE_MODE (result_type));
4200 3 : create_input_operand (&ops[1], crc, TYPE_MODE (result_type));
4201 3 : create_input_operand (&ops[2], data, TYPE_MODE (data_type));
4202 3 : create_input_operand (&ops[3], polynomial, TYPE_MODE (result_type));
4203 3 : insn_code icode = convert_optab_handler (optab, TYPE_MODE (data_type),
4204 3 : TYPE_MODE (result_type));
4205 3 : expand_insn (icode, 4, ops);
4206 3 : assign_call_lhs (lhs, dest, &ops[0]);
4207 : }
4208 : else
4209 : {
4210 : /* We're bypassing all the operand conversions that are done in the
4211 : case when we get an icode, operands and pass that off to expand_insn.
4212 :
4213 : That path has special case handling for promoted return values which
4214 : we must emulate here (is the same kind of special treatment ever
4215 : needed for input arguments here?).
4216 :
4217 : In particular we do not want to store directly into a promoted
4218 : SUBREG destination, instead store into a suitably sized pseudo. */
4219 235 : rtx orig_dest = dest;
4220 235 : if (SUBREG_P (dest) && SUBREG_PROMOTED_VAR_P (dest))
4221 0 : dest = gen_reg_rtx (GET_MODE (dest));
4222 :
4223 : /* If it's IFN_CRC generate bit-forward CRC. */
4224 235 : if (fn == IFN_CRC)
4225 116 : expand_crc_table_based (dest, crc, data, polynomial,
4226 116 : TYPE_MODE (data_type));
4227 : else
4228 : /* If it's IFN_CRC_REV generate bit-reversed CRC. */
4229 119 : expand_reversed_crc_table_based (dest, crc, data, polynomial,
4230 119 : TYPE_MODE (data_type));
4231 :
4232 : /* Now get the return value where it needs to be, taking care to
4233 : ensure it's promoted appropriately if the ABI demands it.
4234 :
4235 : Re-use assign_call_lhs to handle the details. */
4236 235 : class expand_operand ops[4];
4237 235 : create_call_lhs_operand (&ops[0], dest, TYPE_MODE (result_type));
4238 235 : ops[0].value = dest;
4239 235 : assign_call_lhs (lhs, orig_dest, &ops[0]);
4240 : }
4241 238 : }
4242 :
4243 : /* Expand .REDUC_SBOOL_{AND,IOR,XOR}. */
4244 :
4245 : static void
4246 49 : expand_reduc_sbool_optab_fn (internal_fn fn, gcall *stmt, direct_optab optab)
4247 : {
4248 49 : tree_pair types = direct_internal_fn_types (fn, stmt);
4249 49 : insn_code icode = direct_optab_handler (optab, TYPE_MODE (types.first));
4250 :
4251 : /* Below copied from expand_fn_using_insn. */
4252 :
4253 49 : gcc_assert (icode != CODE_FOR_nothing);
4254 :
4255 49 : expand_operand *ops = XALLOCAVEC (expand_operand, 3);
4256 49 : rtx lhs_rtx = NULL_RTX;
4257 49 : tree lhs = gimple_call_lhs (stmt);
4258 49 : if (lhs)
4259 49 : lhs_rtx = expand_expr (lhs, NULL_RTX, VOIDmode, EXPAND_WRITE);
4260 49 : create_call_lhs_operand (&ops[0], lhs_rtx,
4261 49 : insn_data[icode].operand[0].mode);
4262 :
4263 49 : tree rhs = gimple_call_arg (stmt, 0);
4264 49 : tree rhs_type = TREE_TYPE (rhs);
4265 49 : rtx rhs_rtx = expand_normal (rhs);
4266 49 : gcc_assert (VECTOR_BOOLEAN_TYPE_P (rhs_type));
4267 49 : create_input_operand (&ops[1], rhs_rtx, TYPE_MODE (rhs_type));
4268 49 : if (SCALAR_INT_MODE_P (TYPE_MODE (rhs_type)))
4269 : {
4270 24 : rtx nunits = GEN_INT (TYPE_VECTOR_SUBPARTS (rhs_type).to_constant ());
4271 24 : gcc_assert (insn_operand_matches (icode, 2, nunits));
4272 24 : create_input_operand (&ops[2], nunits, SImode);
4273 : }
4274 73 : expand_insn (icode, SCALAR_INT_MODE_P (TYPE_MODE (rhs_type)) ? 3 : 2, ops);
4275 49 : if (lhs_rtx)
4276 49 : assign_call_lhs (lhs, lhs_rtx, &ops[0]);
4277 49 : }
4278 :
4279 : /* Expanders for optabs that can use expand_direct_optab_fn. */
4280 :
4281 : #define expand_unary_optab_fn(FN, STMT, OPTAB) \
4282 : expand_direct_optab_fn (FN, STMT, OPTAB, 1)
4283 :
4284 : #define expand_binary_optab_fn(FN, STMT, OPTAB) \
4285 : expand_direct_optab_fn (FN, STMT, OPTAB, 2)
4286 :
4287 : #define expand_ternary_optab_fn(FN, STMT, OPTAB) \
4288 : expand_direct_optab_fn (FN, STMT, OPTAB, 3)
4289 :
4290 : #define expand_cond_unary_optab_fn(FN, STMT, OPTAB) \
4291 : expand_direct_optab_fn (FN, STMT, OPTAB, 3)
4292 :
4293 : #define expand_cond_binary_optab_fn(FN, STMT, OPTAB) \
4294 : expand_direct_optab_fn (FN, STMT, OPTAB, 4)
4295 :
4296 : #define expand_cond_ternary_optab_fn(FN, STMT, OPTAB) \
4297 : expand_direct_optab_fn (FN, STMT, OPTAB, 5)
4298 :
4299 : #define expand_cond_len_unary_optab_fn(FN, STMT, OPTAB) \
4300 : expand_direct_optab_fn (FN, STMT, OPTAB, 5)
4301 :
4302 : #define expand_cond_len_binary_optab_fn(FN, STMT, OPTAB) \
4303 : expand_direct_optab_fn (FN, STMT, OPTAB, 6)
4304 :
4305 : #define expand_cond_len_ternary_optab_fn(FN, STMT, OPTAB) \
4306 : expand_direct_optab_fn (FN, STMT, OPTAB, 7)
4307 :
4308 : #define expand_fold_extract_optab_fn(FN, STMT, OPTAB) \
4309 : expand_direct_optab_fn (FN, STMT, OPTAB, 3)
4310 :
4311 : #define expand_fold_len_extract_optab_fn(FN, STMT, OPTAB) \
4312 : expand_direct_optab_fn (FN, STMT, OPTAB, 5)
4313 :
4314 : #define expand_fold_left_optab_fn(FN, STMT, OPTAB) \
4315 : expand_direct_optab_fn (FN, STMT, OPTAB, 2)
4316 :
4317 : #define expand_mask_fold_left_optab_fn(FN, STMT, OPTAB) \
4318 : expand_direct_optab_fn (FN, STMT, OPTAB, 3)
4319 :
4320 : #define expand_mask_len_fold_left_optab_fn(FN, STMT, OPTAB) \
4321 : expand_direct_optab_fn (FN, STMT, OPTAB, 5)
4322 :
4323 : #define expand_check_ptrs_optab_fn(FN, STMT, OPTAB) \
4324 : expand_direct_optab_fn (FN, STMT, OPTAB, 4)
4325 :
4326 : #define expand_select_vl_optab_fn(FN, STMT, OPTAB) \
4327 : expand_convert_optab_fn (FN, STMT, OPTAB, 3)
4328 :
4329 : /* Expanders for optabs that can use expand_convert_optab_fn. */
4330 :
4331 : #define expand_unary_convert_optab_fn(FN, STMT, OPTAB) \
4332 : expand_convert_optab_fn (FN, STMT, OPTAB, 1)
4333 :
4334 : #define expand_vec_extract_optab_fn(FN, STMT, OPTAB) \
4335 : expand_convert_optab_fn (FN, STMT, OPTAB, 2)
4336 :
4337 : /* RETURN_TYPE and ARGS are a return type and argument list that are
4338 : in principle compatible with FN (which satisfies direct_internal_fn_p).
4339 : Return the types that should be used to determine whether the
4340 : target supports FN. */
4341 :
4342 : tree_pair
4343 8327 : direct_internal_fn_types (internal_fn fn, tree return_type, tree *args)
4344 : {
4345 8327 : const direct_internal_fn_info &info = direct_internal_fn (fn);
4346 8327 : tree type0 = (info.type0 < 0 ? return_type : TREE_TYPE (args[info.type0]));
4347 8327 : tree type1 = (info.type1 < 0 ? return_type : TREE_TYPE (args[info.type1]));
4348 8327 : return tree_pair (type0, type1);
4349 : }
4350 :
4351 : /* CALL is a call whose return type and arguments are in principle
4352 : compatible with FN (which satisfies direct_internal_fn_p). Return the
4353 : types that should be used to determine whether the target supports FN. */
4354 :
4355 : tree_pair
4356 138455 : direct_internal_fn_types (internal_fn fn, gcall *call)
4357 : {
4358 138455 : const direct_internal_fn_info &info = direct_internal_fn (fn);
4359 138455 : tree op0 = (info.type0 < 0
4360 138455 : ? gimple_call_lhs (call)
4361 136926 : : gimple_call_arg (call, info.type0));
4362 138455 : tree op1 = (info.type1 < 0
4363 138455 : ? gimple_call_lhs (call)
4364 138407 : : gimple_call_arg (call, info.type1));
4365 138455 : return tree_pair (TREE_TYPE (op0), TREE_TYPE (op1));
4366 : }
4367 :
4368 : /* Return true if OPTAB is supported for TYPES (whose modes should be
4369 : the same) when the optimization type is OPT_TYPE. Used for simple
4370 : direct optabs. */
4371 :
4372 : static bool
4373 4181576 : direct_optab_supported_p (direct_optab optab, tree_pair types,
4374 : optimization_type opt_type)
4375 : {
4376 4181576 : machine_mode mode = TYPE_MODE (types.first);
4377 4181576 : gcc_checking_assert (mode == TYPE_MODE (types.second));
4378 4181576 : return direct_optab_handler (optab, mode, opt_type) != CODE_FOR_nothing;
4379 : }
4380 :
4381 : /* Return true if OPTAB is supported for TYPES, where the first type
4382 : is the destination and the second type is the source. Used for
4383 : convert optabs. */
4384 :
4385 : static bool
4386 112788 : convert_optab_supported_p (convert_optab optab, tree_pair types,
4387 : optimization_type opt_type)
4388 : {
4389 112788 : return (convert_optab_handler (optab, TYPE_MODE (types.first),
4390 112788 : TYPE_MODE (types.second), opt_type)
4391 112788 : != CODE_FOR_nothing);
4392 : }
4393 :
4394 : /* Return true if load/store lanes optab OPTAB is supported for
4395 : array type TYPES.first when the optimization type is OPT_TYPE. */
4396 :
4397 : static bool
4398 0 : multi_vector_optab_supported_p (convert_optab optab, tree_pair types,
4399 : optimization_type opt_type)
4400 : {
4401 0 : gcc_assert (TREE_CODE (types.first) == ARRAY_TYPE);
4402 0 : machine_mode imode = TYPE_MODE (types.first);
4403 0 : machine_mode vmode = TYPE_MODE (TREE_TYPE (types.first));
4404 0 : return (convert_optab_handler (optab, imode, vmode, opt_type)
4405 0 : != CODE_FOR_nothing);
4406 : }
4407 :
4408 : #define direct_unary_optab_supported_p direct_optab_supported_p
4409 : #define direct_unary_convert_optab_supported_p convert_optab_supported_p
4410 : #define direct_binary_optab_supported_p direct_optab_supported_p
4411 : #define direct_ternary_optab_supported_p direct_optab_supported_p
4412 : #define direct_cond_unary_optab_supported_p direct_optab_supported_p
4413 : #define direct_cond_binary_optab_supported_p direct_optab_supported_p
4414 : #define direct_cond_ternary_optab_supported_p direct_optab_supported_p
4415 : #define direct_cond_len_unary_optab_supported_p direct_optab_supported_p
4416 : #define direct_cond_len_binary_optab_supported_p direct_optab_supported_p
4417 : #define direct_cond_len_ternary_optab_supported_p direct_optab_supported_p
4418 : #define direct_crc_optab_supported_p convert_optab_supported_p
4419 : #define direct_mask_load_optab_supported_p convert_optab_supported_p
4420 : #define direct_load_lanes_optab_supported_p multi_vector_optab_supported_p
4421 : #define direct_mask_load_lanes_optab_supported_p multi_vector_optab_supported_p
4422 : #define direct_gather_load_optab_supported_p convert_optab_supported_p
4423 : #define direct_strided_load_optab_supported_p direct_optab_supported_p
4424 : #define direct_len_load_optab_supported_p direct_optab_supported_p
4425 : #define direct_mask_len_load_optab_supported_p convert_optab_supported_p
4426 : #define direct_mask_store_optab_supported_p convert_optab_supported_p
4427 : #define direct_store_lanes_optab_supported_p multi_vector_optab_supported_p
4428 : #define direct_mask_store_lanes_optab_supported_p multi_vector_optab_supported_p
4429 : #define direct_vec_cond_mask_optab_supported_p convert_optab_supported_p
4430 : #define direct_vec_cond_optab_supported_p convert_optab_supported_p
4431 : #define direct_scatter_store_optab_supported_p convert_optab_supported_p
4432 : #define direct_strided_store_optab_supported_p direct_optab_supported_p
4433 : #define direct_len_store_optab_supported_p direct_optab_supported_p
4434 : #define direct_mask_len_store_optab_supported_p convert_optab_supported_p
4435 : #define direct_while_optab_supported_p convert_optab_supported_p
4436 : #define direct_fold_extract_optab_supported_p direct_optab_supported_p
4437 : #define direct_fold_len_extract_optab_supported_p direct_optab_supported_p
4438 : #define direct_fold_left_optab_supported_p direct_optab_supported_p
4439 : #define direct_mask_fold_left_optab_supported_p direct_optab_supported_p
4440 : #define direct_mask_len_fold_left_optab_supported_p direct_optab_supported_p
4441 : #define direct_check_ptrs_optab_supported_p direct_optab_supported_p
4442 : #define direct_vec_set_optab_supported_p direct_optab_supported_p
4443 : #define direct_vec_extract_optab_supported_p convert_optab_supported_p
4444 : #define direct_reduc_sbool_optab_supported_p direct_optab_supported_p
4445 : #define direct_select_vl_optab_supported_p convert_optab_supported_p
4446 :
4447 : /* Return the optab used by internal function FN. */
4448 :
4449 : optab
4450 283874 : direct_internal_fn_optab (internal_fn fn, tree_pair types)
4451 : {
4452 283874 : switch (fn)
4453 : {
4454 : #define DEF_INTERNAL_FN(CODE, FLAGS, FNSPEC) \
4455 : case IFN_##CODE: break;
4456 : #define DEF_INTERNAL_OPTAB_FN(CODE, FLAGS, OPTAB, TYPE) \
4457 : case IFN_##CODE: return OPTAB##_optab;
4458 : #define DEF_INTERNAL_SIGNED_OPTAB_FN(CODE, FLAGS, SELECTOR, SIGNED_OPTAB, \
4459 : UNSIGNED_OPTAB, TYPE) \
4460 : case IFN_##CODE: return (TYPE_UNSIGNED (types.SELECTOR) \
4461 : ? UNSIGNED_OPTAB ## _optab \
4462 : : SIGNED_OPTAB ## _optab);
4463 : #include "internal-fn.def"
4464 :
4465 : case IFN_LAST:
4466 : break;
4467 : }
4468 0 : gcc_unreachable ();
4469 : }
4470 :
4471 : /* Return the optab used by internal function FN. */
4472 :
4473 : static optab
4474 976116 : direct_internal_fn_optab (internal_fn fn)
4475 : {
4476 976116 : switch (fn)
4477 : {
4478 : #define DEF_INTERNAL_FN(CODE, FLAGS, FNSPEC) \
4479 : case IFN_##CODE: break;
4480 : #define DEF_INTERNAL_OPTAB_FN(CODE, FLAGS, OPTAB, TYPE) \
4481 : case IFN_##CODE: return OPTAB##_optab;
4482 : #include "internal-fn.def"
4483 :
4484 : case IFN_LAST:
4485 : break;
4486 : }
4487 0 : gcc_unreachable ();
4488 : }
4489 :
4490 : /* Return true if TYPE's mode has the same format as TYPE, and if there is
4491 : a 1:1 correspondence between the values that the mode can store and the
4492 : values that the type can store. */
4493 :
4494 : static bool
4495 8740708 : type_strictly_matches_mode_p (const_tree type)
4496 : {
4497 : /* The masked vector operations have both vector data operands and vector
4498 : boolean operands. The vector data operands are expected to have a vector
4499 : mode, but the vector boolean operands can be an integer mode rather than
4500 : a vector mode, depending on how TARGET_VECTORIZE_GET_MASK_MODE is
4501 : defined. PR116103. */
4502 1127808 : if (VECTOR_BOOLEAN_TYPE_P (type)
4503 258840 : && SCALAR_INT_MODE_P (TYPE_MODE (type))
4504 8830947 : && TYPE_PRECISION (TREE_TYPE (type)) == 1)
4505 : return true;
4506 :
4507 8650470 : if (VECTOR_TYPE_P (type))
4508 1037570 : return VECTOR_MODE_P (TYPE_MODE (type));
4509 :
4510 7612900 : if (INTEGRAL_TYPE_P (type))
4511 7204669 : return type_has_mode_precision_p (type);
4512 :
4513 408231 : if (SCALAR_FLOAT_TYPE_P (type) || COMPLEX_FLOAT_TYPE_P (type))
4514 : return true;
4515 :
4516 : return false;
4517 : }
4518 :
4519 : /* Returns true if both types of TYPE_PAIR strictly match their modes,
4520 : else returns false. */
4521 :
4522 : static bool
4523 4446344 : type_pair_strictly_matches_mode_p (tree_pair type_pair)
4524 : {
4525 4446344 : return type_strictly_matches_mode_p (type_pair.first)
4526 4446344 : && type_strictly_matches_mode_p (type_pair.second);
4527 : }
4528 :
4529 : /* Return true if FN is supported for the types in TYPES when the
4530 : optimization type is OPT_TYPE. The types are those associated with
4531 : the "type0" and "type1" fields of FN's direct_internal_fn_info
4532 : structure. */
4533 :
4534 : bool
4535 4446344 : direct_internal_fn_supported_p (internal_fn fn, tree_pair types,
4536 : optimization_type opt_type)
4537 : {
4538 4446344 : if (!type_pair_strictly_matches_mode_p (types))
4539 : return false;
4540 :
4541 4294364 : switch (fn)
4542 : {
4543 : #define DEF_INTERNAL_FN(CODE, FLAGS, FNSPEC) \
4544 : case IFN_##CODE: break;
4545 : #define DEF_INTERNAL_OPTAB_FN(CODE, FLAGS, OPTAB, TYPE) \
4546 : case IFN_##CODE: \
4547 : return direct_##TYPE##_optab_supported_p (OPTAB##_optab, types, \
4548 : opt_type);
4549 : #define DEF_INTERNAL_SIGNED_OPTAB_FN(CODE, FLAGS, SELECTOR, SIGNED_OPTAB, \
4550 : UNSIGNED_OPTAB, TYPE) \
4551 : case IFN_##CODE: \
4552 : { \
4553 : optab which_optab = (TYPE_UNSIGNED (types.SELECTOR) \
4554 : ? UNSIGNED_OPTAB ## _optab \
4555 : : SIGNED_OPTAB ## _optab); \
4556 : return direct_##TYPE##_optab_supported_p (which_optab, types, \
4557 : opt_type); \
4558 : }
4559 : #include "internal-fn.def"
4560 :
4561 : case IFN_LAST:
4562 : break;
4563 : }
4564 0 : gcc_unreachable ();
4565 : }
4566 :
4567 : /* Return true if FN is supported for type TYPE when the optimization
4568 : type is OPT_TYPE. The caller knows that the "type0" and "type1"
4569 : fields of FN's direct_internal_fn_info structure are the same. */
4570 :
4571 : bool
4572 4252845 : direct_internal_fn_supported_p (internal_fn fn, tree type,
4573 : optimization_type opt_type)
4574 : {
4575 4252845 : const direct_internal_fn_info &info = direct_internal_fn (fn);
4576 4252845 : gcc_checking_assert (info.type0 == info.type1);
4577 4252845 : return direct_internal_fn_supported_p (fn, tree_pair (type, type), opt_type);
4578 : }
4579 :
4580 : /* Return true if the STMT is supported when the optimization type is OPT_TYPE,
4581 : given that STMT is a call to a direct internal function. */
4582 :
4583 : bool
4584 389 : direct_internal_fn_supported_p (gcall *stmt, optimization_type opt_type)
4585 : {
4586 389 : internal_fn fn = gimple_call_internal_fn (stmt);
4587 389 : tree_pair types = direct_internal_fn_types (fn, stmt);
4588 389 : return direct_internal_fn_supported_p (fn, types, opt_type);
4589 : }
4590 :
4591 : /* Return true if FN is a binary operation and if FN is commutative. */
4592 :
4593 : bool
4594 34763901 : commutative_binary_fn_p (internal_fn fn)
4595 : {
4596 34763901 : switch (fn)
4597 : {
4598 : case IFN_AVG_FLOOR:
4599 : case IFN_AVG_CEIL:
4600 : case IFN_MULH:
4601 : case IFN_MULHS:
4602 : case IFN_MULHRS:
4603 : case IFN_FMIN:
4604 : case IFN_FMAX:
4605 : case IFN_COMPLEX_MUL:
4606 : case IFN_UBSAN_CHECK_ADD:
4607 : case IFN_UBSAN_CHECK_MUL:
4608 : case IFN_ADD_OVERFLOW:
4609 : case IFN_MUL_OVERFLOW:
4610 : case IFN_SAT_ADD:
4611 : case IFN_SAT_MUL:
4612 : case IFN_VEC_WIDEN_PLUS:
4613 : case IFN_VEC_WIDEN_PLUS_LO:
4614 : case IFN_VEC_WIDEN_PLUS_HI:
4615 : case IFN_VEC_WIDEN_PLUS_EVEN:
4616 : case IFN_VEC_WIDEN_PLUS_ODD:
4617 : return true;
4618 :
4619 33854273 : default:
4620 33854273 : return false;
4621 : }
4622 : }
4623 :
4624 : /* Return true if FN is a ternary operation and if its first two arguments
4625 : are commutative. */
4626 :
4627 : bool
4628 28383881 : commutative_ternary_fn_p (internal_fn fn)
4629 : {
4630 28383881 : switch (fn)
4631 : {
4632 : case IFN_FMA:
4633 : case IFN_FMS:
4634 : case IFN_FNMA:
4635 : case IFN_FNMS:
4636 : case IFN_UADDC:
4637 : return true;
4638 :
4639 28251861 : default:
4640 28251861 : return false;
4641 : }
4642 : }
4643 :
4644 : /* Return true if FN is an associative binary operation. */
4645 :
4646 : bool
4647 52 : associative_binary_fn_p (internal_fn fn)
4648 : {
4649 52 : switch (fn)
4650 : {
4651 : case IFN_FMIN:
4652 : case IFN_FMAX:
4653 : return true;
4654 :
4655 0 : default:
4656 0 : return false;
4657 : }
4658 : }
4659 :
4660 : /* If FN is commutative in two consecutive arguments, return the
4661 : index of the first, otherwise return -1. */
4662 :
4663 : int
4664 28718267 : first_commutative_argument (internal_fn fn)
4665 : {
4666 28718267 : switch (fn)
4667 : {
4668 : case IFN_COND_ADD:
4669 : case IFN_COND_MUL:
4670 : case IFN_COND_MIN:
4671 : case IFN_COND_MAX:
4672 : case IFN_COND_FMIN:
4673 : case IFN_COND_FMAX:
4674 : case IFN_COND_AND:
4675 : case IFN_COND_IOR:
4676 : case IFN_COND_XOR:
4677 : case IFN_COND_FMA:
4678 : case IFN_COND_FMS:
4679 : case IFN_COND_FNMA:
4680 : case IFN_COND_FNMS:
4681 : case IFN_COND_LEN_ADD:
4682 : case IFN_COND_LEN_MUL:
4683 : case IFN_COND_LEN_MIN:
4684 : case IFN_COND_LEN_MAX:
4685 : case IFN_COND_LEN_FMIN:
4686 : case IFN_COND_LEN_FMAX:
4687 : case IFN_COND_LEN_AND:
4688 : case IFN_COND_LEN_IOR:
4689 : case IFN_COND_LEN_XOR:
4690 : case IFN_COND_LEN_FMA:
4691 : case IFN_COND_LEN_FMS:
4692 : case IFN_COND_LEN_FNMA:
4693 : case IFN_COND_LEN_FNMS:
4694 : return 1;
4695 :
4696 28694648 : default:
4697 28694648 : if (commutative_binary_fn_p (fn)
4698 28694648 : || commutative_ternary_fn_p (fn))
4699 447545 : return 0;
4700 : return -1;
4701 : }
4702 : }
4703 :
4704 : /* Return true if this CODE describes an internal_fn that returns a vector with
4705 : elements twice as wide as the element size of the input vectors. */
4706 :
4707 : bool
4708 2110764 : widening_fn_p (code_helper code)
4709 : {
4710 2110764 : if (!code.is_fn_code ())
4711 : return false;
4712 :
4713 219538 : if (!internal_fn_p ((combined_fn) code))
4714 : return false;
4715 :
4716 219538 : internal_fn fn = as_internal_fn ((combined_fn) code);
4717 219538 : switch (fn)
4718 : {
4719 : #define DEF_INTERNAL_WIDENING_OPTAB_FN(NAME, F, S, SO, UO, T) \
4720 : case IFN_##NAME: \
4721 : case IFN_##NAME##_HI: \
4722 : case IFN_##NAME##_LO: \
4723 : case IFN_##NAME##_EVEN: \
4724 : case IFN_##NAME##_ODD: \
4725 : return true;
4726 : #include "internal-fn.def"
4727 :
4728 : default:
4729 : return false;
4730 : }
4731 : }
4732 :
4733 : /* Return true if this CODE describes an internal_fn that returns a vector with
4734 : elements twice as wide as the element size of the input vectors and operates
4735 : on even/odd parts of the input. */
4736 :
4737 : bool
4738 20988 : widening_evenodd_fn_p (code_helper code)
4739 : {
4740 20988 : if (!code.is_fn_code ())
4741 : return false;
4742 :
4743 0 : if (!internal_fn_p ((combined_fn) code))
4744 : return false;
4745 :
4746 0 : internal_fn fn = as_internal_fn ((combined_fn) code);
4747 0 : switch (fn)
4748 : {
4749 : #define DEF_INTERNAL_WIDENING_OPTAB_FN(NAME, F, S, SO, UO, T) \
4750 : case IFN_##NAME##_EVEN: \
4751 : case IFN_##NAME##_ODD: \
4752 : return true;
4753 : #include "internal-fn.def"
4754 :
4755 : default:
4756 : return false;
4757 : }
4758 : }
4759 :
4760 : /* Return true if IFN_SET_EDOM is supported. */
4761 :
4762 : bool
4763 140 : set_edom_supported_p (void)
4764 : {
4765 : #ifdef TARGET_EDOM
4766 : return true;
4767 : #else
4768 140 : return false;
4769 : #endif
4770 : }
4771 :
4772 : #define DEF_INTERNAL_OPTAB_FN(CODE, FLAGS, OPTAB, TYPE) \
4773 : static void \
4774 : expand_##CODE (internal_fn fn, gcall *stmt) \
4775 : { \
4776 : expand_##TYPE##_optab_fn (fn, stmt, OPTAB##_optab); \
4777 : }
4778 : #define DEF_INTERNAL_INT_EXT_FN(CODE, FLAGS, OPTAB, TYPE)
4779 : #define DEF_INTERNAL_INTSZ_EXT_FN(CODE, FLAGS, OPTAB, TYPE)
4780 : #define DEF_INTERNAL_SIGNED_OPTAB_FN(CODE, FLAGS, SELECTOR, SIGNED_OPTAB, \
4781 : UNSIGNED_OPTAB, TYPE) \
4782 : static void \
4783 : expand_##CODE (internal_fn fn, gcall *stmt) \
4784 : { \
4785 : tree_pair types = direct_internal_fn_types (fn, stmt); \
4786 : optab which_optab = direct_internal_fn_optab (fn, types); \
4787 : expand_##TYPE##_optab_fn (fn, stmt, which_optab); \
4788 : }
4789 : #include "internal-fn.def"
4790 :
4791 : /* Routines to expand each internal function, indexed by function number.
4792 : Each routine has the prototype:
4793 :
4794 : expand_<NAME> (gcall *stmt)
4795 :
4796 : where STMT is the statement that performs the call. */
4797 : static void (*const internal_fn_expanders[]) (internal_fn, gcall *) = {
4798 :
4799 : #define DEF_INTERNAL_FN(CODE, FLAGS, FNSPEC) expand_##CODE,
4800 : #include "internal-fn.def"
4801 : 0
4802 : };
4803 :
4804 : /* Invoke T(CODE, SUFFIX) for each conditional function IFN_COND_##SUFFIX
4805 : that maps to a tree code CODE. There is also an IFN_COND_LEN_##SUFFIX
4806 : for each such IFN_COND_##SUFFIX. */
4807 : #define FOR_EACH_CODE_MAPPING(T) \
4808 : T (PLUS_EXPR, ADD) \
4809 : T (MINUS_EXPR, SUB) \
4810 : T (MULT_EXPR, MUL) \
4811 : T (TRUNC_DIV_EXPR, DIV) \
4812 : T (TRUNC_MOD_EXPR, MOD) \
4813 : T (RDIV_EXPR, RDIV) \
4814 : T (MIN_EXPR, MIN) \
4815 : T (MAX_EXPR, MAX) \
4816 : T (BIT_AND_EXPR, AND) \
4817 : T (BIT_IOR_EXPR, IOR) \
4818 : T (BIT_XOR_EXPR, XOR) \
4819 : T (LSHIFT_EXPR, SHL) \
4820 : T (RSHIFT_EXPR, SHR) \
4821 : T (NEGATE_EXPR, NEG)
4822 :
4823 : /* Return a function that only performs CODE when a certain condition is met
4824 : and that uses a given fallback value otherwise. For example, if CODE is
4825 : a binary operation associated with conditional function FN:
4826 :
4827 : LHS = FN (COND, A, B, ELSE)
4828 :
4829 : is equivalent to the C expression:
4830 :
4831 : LHS = COND ? A CODE B : ELSE;
4832 :
4833 : operating elementwise if the operands are vectors.
4834 :
4835 : Return IFN_LAST if no such function exists. */
4836 :
4837 : internal_fn
4838 573538 : get_conditional_internal_fn (tree_code code)
4839 : {
4840 573538 : switch (code)
4841 : {
4842 : #define CASE(CODE, IFN) case CODE: return IFN_COND_##IFN;
4843 : FOR_EACH_CODE_MAPPING(CASE)
4844 : #undef CASE
4845 : default:
4846 : return IFN_LAST;
4847 : }
4848 : }
4849 :
4850 : /* If IFN implements the conditional form of a tree code, return that
4851 : tree code, otherwise return ERROR_MARK. */
4852 :
4853 : tree_code
4854 3486989 : conditional_internal_fn_code (internal_fn ifn)
4855 : {
4856 3486989 : switch (ifn)
4857 : {
4858 : #define CASE(CODE, IFN) \
4859 : case IFN_COND_##IFN: \
4860 : case IFN_COND_LEN_##IFN: \
4861 : return CODE;
4862 : FOR_EACH_CODE_MAPPING (CASE)
4863 : #undef CASE
4864 : default:
4865 : return ERROR_MARK;
4866 : }
4867 : }
4868 :
4869 : /* Like get_conditional_internal_fn, but return a function that
4870 : additionally restricts the operation to the leading elements
4871 : of a vector. The number of elements to process is given by a length
4872 : and bias pair, as for IFN_LOAD_LEN. The values of the remaining
4873 : elements are taken from the fallback ("else") argument.
4874 :
4875 : For example, if CODE is a binary operation associated with FN:
4876 :
4877 : LHS = FN (COND, A, B, ELSE, LEN, BIAS)
4878 :
4879 : is equivalent to the C code:
4880 :
4881 : for (int i = 0; i < NUNITS; i++)
4882 : {
4883 : if (i < LEN + BIAS && COND[i])
4884 : LHS[i] = A[i] CODE B[i];
4885 : else
4886 : LHS[i] = ELSE[i];
4887 : }
4888 : */
4889 :
4890 : internal_fn
4891 550107 : get_conditional_len_internal_fn (tree_code code)
4892 : {
4893 550107 : switch (code)
4894 : {
4895 : #define CASE(CODE, IFN) case CODE: return IFN_COND_LEN_##IFN;
4896 : FOR_EACH_CODE_MAPPING(CASE)
4897 : #undef CASE
4898 : default:
4899 : return IFN_LAST;
4900 : }
4901 : }
4902 :
4903 : /* Invoke T(IFN) for each internal function IFN that also has an
4904 : IFN_COND_* form. */
4905 : #define FOR_EACH_COND_FN_PAIR(T) \
4906 : T (FMAX) \
4907 : T (FMIN) \
4908 : T (FMA) \
4909 : T (FMS) \
4910 : T (FNMA) \
4911 : T (FNMS) \
4912 : T (SQRT) \
4913 : T (ROUND) \
4914 : T (FLOOR) \
4915 : T (RINT) \
4916 : T (CEIL)
4917 :
4918 : /* Return a function that only performs internal function FN when a
4919 : certain condition is met and that uses a given fallback value otherwise.
4920 : In other words, the returned function FN' is such that:
4921 :
4922 : LHS = FN' (COND, A1, ... An, ELSE)
4923 :
4924 : is equivalent to the C expression:
4925 :
4926 : LHS = COND ? FN (A1, ..., An) : ELSE;
4927 :
4928 : operating elementwise if the operands are vectors.
4929 :
4930 : Return IFN_LAST if no such function exists. */
4931 :
4932 : internal_fn
4933 10190 : get_conditional_internal_fn (internal_fn fn)
4934 : {
4935 10190 : switch (fn)
4936 : {
4937 : #define CASE(NAME) case IFN_##NAME: return IFN_COND_##NAME;
4938 2160 : FOR_EACH_COND_FN_PAIR(CASE)
4939 : #undef CASE
4940 8029 : default:
4941 8029 : return IFN_LAST;
4942 : }
4943 : }
4944 :
4945 : /* If there exists an internal function like IFN that operates on vectors,
4946 : but with additional length and bias parameters, return the internal_fn
4947 : for that function, otherwise return IFN_LAST. */
4948 : internal_fn
4949 12315 : get_len_internal_fn (internal_fn fn)
4950 : {
4951 12315 : switch (fn)
4952 : {
4953 : #define DEF_INTERNAL_COND_FN(NAME, ...) \
4954 : case IFN_COND_##NAME: \
4955 : return IFN_COND_LEN_##NAME;
4956 : #define DEF_INTERNAL_SIGNED_COND_FN(NAME, ...) \
4957 : case IFN_COND_##NAME: \
4958 : return IFN_COND_LEN_##NAME;
4959 : #include "internal-fn.def"
4960 7991 : default:
4961 7991 : break;
4962 : }
4963 :
4964 7991 : switch (fn)
4965 : {
4966 : case IFN_MASK_LOAD:
4967 : return IFN_MASK_LEN_LOAD;
4968 : case IFN_MASK_LOAD_LANES:
4969 : return IFN_MASK_LEN_LOAD_LANES;
4970 : case IFN_MASK_GATHER_LOAD:
4971 : return IFN_MASK_LEN_GATHER_LOAD;
4972 : default:
4973 : return IFN_LAST;
4974 : }
4975 : }
4976 :
4977 : /* If IFN implements the conditional form of an unconditional internal
4978 : function, return that unconditional function, otherwise return IFN_LAST. */
4979 :
4980 : internal_fn
4981 3432952 : get_unconditional_internal_fn (internal_fn ifn)
4982 : {
4983 3432952 : switch (ifn)
4984 : {
4985 : #define CASE(NAME) \
4986 : case IFN_COND_##NAME: \
4987 : case IFN_COND_LEN_##NAME: \
4988 : return IFN_##NAME;
4989 : FOR_EACH_COND_FN_PAIR (CASE)
4990 : #undef CASE
4991 : default:
4992 : return IFN_LAST;
4993 : }
4994 : }
4995 :
4996 : /* Return true if STMT can be interpreted as a conditional tree code
4997 : operation of the form:
4998 :
4999 : LHS = COND ? OP (RHS1, ...) : ELSE;
5000 :
5001 : operating elementwise if the operands are vectors. This includes
5002 : the case of an all-true COND, so that the operation always happens.
5003 :
5004 : There is an alternative approach to interpret the STMT when the operands
5005 : are vectors which is the operation predicated by both conditional mask
5006 : and loop control length, the equivalent C code:
5007 :
5008 : for (int i = 0; i < NUNTIS; i++)
5009 : {
5010 : if (i < LEN + BIAS && COND[i])
5011 : LHS[i] = A[i] CODE B[i];
5012 : else
5013 : LHS[i] = ELSE[i];
5014 : }
5015 :
5016 : When returning true, set:
5017 :
5018 : - *COND_OUT to the condition COND, or to NULL_TREE if the condition
5019 : is known to be all-true
5020 : - *CODE_OUT to the tree code
5021 : - OPS[I] to operand I of *CODE_OUT
5022 : - *ELSE_OUT to the fallback value ELSE, or to NULL_TREE if the
5023 : condition is known to be all true.
5024 : - *LEN to the len argument if it COND_LEN_* operations or to NULL_TREE.
5025 : - *BIAS to the bias argument if it COND_LEN_* operations or to NULL_TREE. */
5026 :
5027 : bool
5028 40335 : can_interpret_as_conditional_op_p (gimple *stmt, tree *cond_out,
5029 : tree_code *code_out,
5030 : tree (&ops)[3], tree *else_out,
5031 : tree *len, tree *bias)
5032 : {
5033 40335 : *len = NULL_TREE;
5034 40335 : *bias = NULL_TREE;
5035 40335 : if (gassign *assign = dyn_cast <gassign *> (stmt))
5036 : {
5037 37760 : *cond_out = NULL_TREE;
5038 37760 : *code_out = gimple_assign_rhs_code (assign);
5039 37760 : ops[0] = gimple_assign_rhs1 (assign);
5040 37760 : ops[1] = gimple_assign_rhs2 (assign);
5041 37760 : ops[2] = gimple_assign_rhs3 (assign);
5042 37760 : *else_out = NULL_TREE;
5043 37760 : return true;
5044 : }
5045 2575 : if (gcall *call = dyn_cast <gcall *> (stmt))
5046 1998 : if (gimple_call_internal_p (call))
5047 : {
5048 1941 : internal_fn ifn = gimple_call_internal_fn (call);
5049 1941 : tree_code code = conditional_internal_fn_code (ifn);
5050 1941 : int len_index = internal_fn_len_index (ifn);
5051 1941 : int cond_nargs = len_index >= 0 ? 4 : 2;
5052 1941 : if (code != ERROR_MARK)
5053 : {
5054 216 : *cond_out = gimple_call_arg (call, 0);
5055 216 : *code_out = code;
5056 216 : unsigned int nops = gimple_call_num_args (call) - cond_nargs;
5057 864 : for (unsigned int i = 0; i < 3; ++i)
5058 648 : ops[i] = i < nops ? gimple_call_arg (call, i + 1) : NULL_TREE;
5059 216 : *else_out = gimple_call_arg (call, nops + 1);
5060 216 : if (len_index < 0)
5061 : {
5062 216 : if (integer_truep (*cond_out))
5063 : {
5064 0 : *cond_out = NULL_TREE;
5065 0 : *else_out = NULL_TREE;
5066 : }
5067 : }
5068 : else
5069 : {
5070 0 : *len = gimple_call_arg (call, len_index);
5071 0 : *bias = gimple_call_arg (call, len_index + 1);
5072 : }
5073 : return true;
5074 : }
5075 : }
5076 : return false;
5077 : }
5078 :
5079 : /* Return true if IFN is some form of load from memory. */
5080 :
5081 : bool
5082 992379 : internal_load_fn_p (internal_fn fn)
5083 : {
5084 992379 : switch (fn)
5085 : {
5086 : case IFN_MASK_LOAD:
5087 : case IFN_LOAD_LANES:
5088 : case IFN_MASK_LOAD_LANES:
5089 : case IFN_MASK_LEN_LOAD_LANES:
5090 : case IFN_GATHER_LOAD:
5091 : case IFN_MASK_GATHER_LOAD:
5092 : case IFN_MASK_LEN_GATHER_LOAD:
5093 : case IFN_LEN_LOAD:
5094 : case IFN_MASK_LEN_LOAD:
5095 : return true;
5096 :
5097 259801 : default:
5098 259801 : return false;
5099 : }
5100 : }
5101 :
5102 : /* Return true if IFN is some form of store to memory. */
5103 :
5104 : bool
5105 559463 : internal_store_fn_p (internal_fn fn)
5106 : {
5107 559463 : switch (fn)
5108 : {
5109 : case IFN_MASK_STORE:
5110 : case IFN_STORE_LANES:
5111 : case IFN_MASK_STORE_LANES:
5112 : case IFN_MASK_LEN_STORE_LANES:
5113 : case IFN_SCATTER_STORE:
5114 : case IFN_MASK_SCATTER_STORE:
5115 : case IFN_MASK_LEN_SCATTER_STORE:
5116 : case IFN_LEN_STORE:
5117 : case IFN_MASK_LEN_STORE:
5118 : return true;
5119 :
5120 546817 : default:
5121 546817 : return false;
5122 : }
5123 : }
5124 :
5125 : /* Return true if IFN is some form of gather load or scatter store. */
5126 :
5127 : bool
5128 49526 : internal_gather_scatter_fn_p (internal_fn fn)
5129 : {
5130 49526 : switch (fn)
5131 : {
5132 : case IFN_GATHER_LOAD:
5133 : case IFN_MASK_GATHER_LOAD:
5134 : case IFN_MASK_LEN_GATHER_LOAD:
5135 : case IFN_SCATTER_STORE:
5136 : case IFN_MASK_SCATTER_STORE:
5137 : case IFN_MASK_LEN_SCATTER_STORE:
5138 : return true;
5139 :
5140 49526 : default:
5141 49526 : return false;
5142 : }
5143 : }
5144 :
5145 : /* If FN takes a vector len argument, return the index of that argument,
5146 : otherwise return -1. */
5147 :
5148 : int
5149 3318770 : internal_fn_len_index (internal_fn fn)
5150 : {
5151 3318770 : switch (fn)
5152 : {
5153 : case IFN_LEN_LOAD:
5154 : return 3;
5155 : case IFN_LEN_STORE:
5156 : return 2;
5157 :
5158 : case IFN_MASK_LEN_SCATTER_STORE:
5159 : return 6;
5160 :
5161 : case IFN_MASK_LEN_STRIDED_LOAD:
5162 : return 5;
5163 :
5164 : case IFN_MASK_LEN_GATHER_LOAD:
5165 : return 7;
5166 :
5167 : case IFN_COND_LEN_FMA:
5168 : case IFN_COND_LEN_FMS:
5169 : case IFN_COND_LEN_FNMA:
5170 : case IFN_COND_LEN_FNMS:
5171 : return 5;
5172 :
5173 : case IFN_COND_LEN_ADD:
5174 : case IFN_COND_LEN_SUB:
5175 : case IFN_COND_LEN_MUL:
5176 : case IFN_COND_LEN_DIV:
5177 : case IFN_COND_LEN_MOD:
5178 : case IFN_COND_LEN_RDIV:
5179 : case IFN_COND_LEN_MIN:
5180 : case IFN_COND_LEN_MAX:
5181 : case IFN_COND_LEN_FMIN:
5182 : case IFN_COND_LEN_FMAX:
5183 : case IFN_COND_LEN_AND:
5184 : case IFN_COND_LEN_IOR:
5185 : case IFN_COND_LEN_XOR:
5186 : case IFN_COND_LEN_SHL:
5187 : case IFN_COND_LEN_SHR:
5188 : case IFN_MASK_LEN_STRIDED_STORE:
5189 : return 4;
5190 :
5191 : case IFN_COND_LEN_NEG:
5192 : case IFN_MASK_LEN_STORE:
5193 : case IFN_MASK_LEN_STORE_LANES:
5194 : case IFN_VCOND_MASK_LEN:
5195 : return 3;
5196 :
5197 : case IFN_MASK_LEN_LOAD:
5198 : case IFN_MASK_LEN_LOAD_LANES:
5199 : return 4;
5200 :
5201 : default:
5202 : return -1;
5203 : }
5204 : }
5205 :
5206 : /* If FN is an IFN_COND_* or IFN_COND_LEN_* function, return the index of the
5207 : argument that is used when the condition is false. Return -1 otherwise. */
5208 :
5209 : int
5210 84686 : internal_fn_else_index (internal_fn fn)
5211 : {
5212 84686 : switch (fn)
5213 : {
5214 : case IFN_COND_NEG:
5215 : case IFN_COND_NOT:
5216 : case IFN_COND_SQRT:
5217 : case IFN_COND_CEIL:
5218 : case IFN_COND_FLOOR:
5219 : case IFN_COND_ROUND:
5220 : case IFN_COND_RINT:
5221 : case IFN_COND_LEN_NEG:
5222 : case IFN_COND_LEN_NOT:
5223 : case IFN_COND_LEN_SQRT:
5224 : case IFN_COND_LEN_CEIL:
5225 : case IFN_COND_LEN_FLOOR:
5226 : case IFN_COND_LEN_ROUND:
5227 : case IFN_COND_LEN_RINT:
5228 : return 2;
5229 :
5230 : case IFN_LEN_LOAD:
5231 : return 2;
5232 :
5233 : case IFN_COND_ADD:
5234 : case IFN_COND_SUB:
5235 : case IFN_COND_MUL:
5236 : case IFN_COND_DIV:
5237 : case IFN_COND_MOD:
5238 : case IFN_COND_MIN:
5239 : case IFN_COND_MAX:
5240 : case IFN_COND_FMIN:
5241 : case IFN_COND_FMAX:
5242 : case IFN_COND_AND:
5243 : case IFN_COND_IOR:
5244 : case IFN_COND_XOR:
5245 : case IFN_COND_SHL:
5246 : case IFN_COND_SHR:
5247 : case IFN_COND_LEN_ADD:
5248 : case IFN_COND_LEN_SUB:
5249 : case IFN_COND_LEN_MUL:
5250 : case IFN_COND_LEN_DIV:
5251 : case IFN_COND_LEN_MOD:
5252 : case IFN_COND_LEN_MIN:
5253 : case IFN_COND_LEN_MAX:
5254 : case IFN_COND_LEN_FMIN:
5255 : case IFN_COND_LEN_FMAX:
5256 : case IFN_COND_LEN_AND:
5257 : case IFN_COND_LEN_IOR:
5258 : case IFN_COND_LEN_XOR:
5259 : case IFN_COND_LEN_SHL:
5260 : case IFN_COND_LEN_SHR:
5261 : return 3;
5262 :
5263 : case IFN_MASK_LOAD:
5264 : case IFN_MASK_LEN_LOAD:
5265 : case IFN_MASK_LOAD_LANES:
5266 : case IFN_MASK_LEN_LOAD_LANES:
5267 : return 3;
5268 :
5269 : case IFN_COND_FMA:
5270 : case IFN_COND_FMS:
5271 : case IFN_COND_FNMA:
5272 : case IFN_COND_FNMS:
5273 : case IFN_COND_LEN_FMA:
5274 : case IFN_COND_LEN_FMS:
5275 : case IFN_COND_LEN_FNMA:
5276 : case IFN_COND_LEN_FNMS:
5277 : case IFN_MASK_LEN_STRIDED_LOAD:
5278 : return 4;
5279 :
5280 : case IFN_MASK_GATHER_LOAD:
5281 : case IFN_MASK_LEN_GATHER_LOAD:
5282 : return 6;
5283 :
5284 : default:
5285 : return -1;
5286 : }
5287 :
5288 : return -1;
5289 : }
5290 :
5291 : /* If FN takes a vector mask argument, return the index of that argument,
5292 : otherwise return -1. */
5293 :
5294 : int
5295 208853 : internal_fn_mask_index (internal_fn fn)
5296 : {
5297 208853 : switch (fn)
5298 : {
5299 : case IFN_MASK_LOAD:
5300 : case IFN_MASK_LOAD_LANES:
5301 : case IFN_MASK_LEN_LOAD_LANES:
5302 : case IFN_MASK_STORE:
5303 : case IFN_MASK_STORE_LANES:
5304 : case IFN_MASK_LEN_STORE_LANES:
5305 : case IFN_MASK_LEN_LOAD:
5306 : case IFN_MASK_LEN_STORE:
5307 : return 2;
5308 :
5309 0 : case IFN_MASK_LEN_STRIDED_LOAD:
5310 0 : case IFN_MASK_LEN_STRIDED_STORE:
5311 0 : return 3;
5312 :
5313 0 : case IFN_MASK_GATHER_LOAD:
5314 0 : case IFN_MASK_SCATTER_STORE:
5315 0 : case IFN_MASK_LEN_GATHER_LOAD:
5316 0 : case IFN_MASK_LEN_SCATTER_STORE:
5317 0 : return 5;
5318 :
5319 : case IFN_VCOND_MASK:
5320 : case IFN_VCOND_MASK_LEN:
5321 : return 0;
5322 :
5323 164954 : default:
5324 164954 : return (conditional_internal_fn_code (fn) != ERROR_MARK
5325 164954 : || get_unconditional_internal_fn (fn) != IFN_LAST ? 0 : -1);
5326 : }
5327 : }
5328 :
5329 : /* If FN takes a value that should be stored to memory, return the index
5330 : of that argument, otherwise return -1. */
5331 :
5332 : int
5333 26053 : internal_fn_stored_value_index (internal_fn fn)
5334 : {
5335 26053 : switch (fn)
5336 : {
5337 : case IFN_MASK_LEN_STRIDED_STORE:
5338 : return 2;
5339 :
5340 : case IFN_MASK_STORE:
5341 : case IFN_MASK_STORE_LANES:
5342 : return 3;
5343 : case IFN_SCATTER_STORE:
5344 : case IFN_MASK_SCATTER_STORE:
5345 : case IFN_MASK_LEN_SCATTER_STORE:
5346 : return 4;
5347 :
5348 : case IFN_LEN_STORE:
5349 : return 4;
5350 :
5351 : case IFN_MASK_LEN_STORE:
5352 : case IFN_MASK_LEN_STORE_LANES:
5353 : return 5;
5354 :
5355 : default:
5356 : return -1;
5357 : }
5358 : }
5359 :
5360 : /* If FN has an alias pointer return its index, otherwise return -1. */
5361 :
5362 : int
5363 0 : internal_fn_alias_ptr_index (internal_fn fn)
5364 : {
5365 0 : switch (fn)
5366 : {
5367 : case IFN_MASK_LOAD:
5368 : case IFN_MASK_LEN_LOAD:
5369 : case IFN_GATHER_LOAD:
5370 : case IFN_MASK_GATHER_LOAD:
5371 : case IFN_MASK_LEN_GATHER_LOAD:
5372 : case IFN_SCATTER_STORE:
5373 : case IFN_MASK_SCATTER_STORE:
5374 : case IFN_MASK_LEN_SCATTER_STORE:
5375 : return 1;
5376 :
5377 0 : default:
5378 0 : return -1;
5379 : }
5380 : }
5381 :
5382 : /* If FN is a gather/scatter return the index of its offset argument,
5383 : otherwise return -1. */
5384 :
5385 : int
5386 0 : internal_fn_offset_index (internal_fn fn)
5387 : {
5388 0 : if (!internal_gather_scatter_fn_p (fn))
5389 : return -1;
5390 :
5391 0 : switch (fn)
5392 : {
5393 : case IFN_GATHER_LOAD:
5394 : case IFN_MASK_GATHER_LOAD:
5395 : case IFN_MASK_LEN_GATHER_LOAD:
5396 : case IFN_SCATTER_STORE:
5397 : case IFN_MASK_SCATTER_STORE:
5398 : case IFN_MASK_LEN_SCATTER_STORE:
5399 : return 2;
5400 :
5401 : default:
5402 : return -1;
5403 : }
5404 : }
5405 :
5406 : /* If FN is a gather/scatter return the index of its scale argument,
5407 : otherwise return -1. */
5408 :
5409 : int
5410 0 : internal_fn_scale_index (internal_fn fn)
5411 : {
5412 0 : if (!internal_gather_scatter_fn_p (fn))
5413 : return -1;
5414 :
5415 0 : switch (fn)
5416 : {
5417 : case IFN_GATHER_LOAD:
5418 : case IFN_MASK_GATHER_LOAD:
5419 : case IFN_MASK_LEN_GATHER_LOAD:
5420 : case IFN_SCATTER_STORE:
5421 : case IFN_MASK_SCATTER_STORE:
5422 : case IFN_MASK_LEN_SCATTER_STORE:
5423 : return 3;
5424 :
5425 : default:
5426 : return -1;
5427 : }
5428 : }
5429 :
5430 : /* Store all supported else values for the optab referred to by ICODE
5431 : in ELSE_VALS. The index of the else operand must be specified in
5432 : ELSE_INDEX. */
5433 :
5434 : void
5435 62955 : get_supported_else_vals (enum insn_code icode, unsigned else_index,
5436 : vec<int> &else_vals)
5437 : {
5438 62955 : const struct insn_data_d *data = &insn_data[icode];
5439 62955 : if ((int) else_index >= data->n_operands || (int) else_index == -1)
5440 : return;
5441 :
5442 62955 : machine_mode else_mode = data->operand[else_index].mode;
5443 :
5444 62955 : else_vals.truncate (0);
5445 :
5446 : /* For now we only support else values of 0, -1, and "undefined". */
5447 62955 : if (insn_operand_matches (icode, else_index, CONST0_RTX (else_mode)))
5448 62955 : else_vals.safe_push (MASK_LOAD_ELSE_ZERO);
5449 :
5450 62955 : if (insn_operand_matches (icode, else_index, gen_rtx_SCRATCH (else_mode)))
5451 0 : else_vals.safe_push (MASK_LOAD_ELSE_UNDEFINED);
5452 :
5453 62955 : if (GET_MODE_CLASS (else_mode) == MODE_VECTOR_INT
5454 62955 : && insn_operand_matches (icode, else_index, CONSTM1_RTX (else_mode)))
5455 0 : else_vals.safe_push (MASK_LOAD_ELSE_M1);
5456 : }
5457 :
5458 : /* Return true if the else value ELSE_VAL (one of MASK_LOAD_ELSE_ZERO,
5459 : MASK_LOAD_ELSE_M1, and MASK_LOAD_ELSE_UNDEFINED) is valid fo the optab
5460 : referred to by ICODE. The index of the else operand must be specified
5461 : in ELSE_INDEX. */
5462 :
5463 : bool
5464 0 : supported_else_val_p (enum insn_code icode, unsigned else_index, int else_val)
5465 : {
5466 0 : if (else_val != MASK_LOAD_ELSE_ZERO && else_val != MASK_LOAD_ELSE_M1
5467 0 : && else_val != MASK_LOAD_ELSE_UNDEFINED)
5468 0 : gcc_unreachable ();
5469 :
5470 0 : auto_vec<int> else_vals;
5471 0 : get_supported_else_vals (icode, else_index, else_vals);
5472 0 : return else_vals.contains (else_val);
5473 0 : }
5474 :
5475 : /* Return true if the target supports gather load or scatter store function
5476 : IFN. For loads, VECTOR_TYPE is the vector type of the load result,
5477 : while for stores it is the vector type of the stored data argument.
5478 : MEMORY_ELEMENT_TYPE is the type of the memory elements being loaded
5479 : or stored. OFFSET_VECTOR_TYPE is the vector type that holds the
5480 : offset from the shared base address of each loaded or stored element.
5481 : SCALE is the amount by which these offsets should be multiplied
5482 : *after* they have been extended to address width.
5483 : If the target supports the gather load the supported else values
5484 : will be added to the vector ELSVAL points to if it is nonzero. */
5485 :
5486 : bool
5487 3543198 : internal_gather_scatter_fn_supported_p (internal_fn ifn, tree vector_type,
5488 : tree memory_element_type,
5489 : tree offset_vector_type, int scale,
5490 : vec<int> *elsvals)
5491 : {
5492 3543198 : if (!tree_int_cst_equal (TYPE_SIZE (TREE_TYPE (vector_type)),
5493 3543198 : TYPE_SIZE (memory_element_type)))
5494 : return false;
5495 3543198 : if (maybe_ne (TYPE_VECTOR_SUBPARTS (vector_type),
5496 7086396 : TYPE_VECTOR_SUBPARTS (offset_vector_type)))
5497 : return false;
5498 968920 : optab optab = direct_internal_fn_optab (ifn);
5499 968920 : insn_code icode = convert_optab_handler (optab, TYPE_MODE (vector_type),
5500 968920 : TYPE_MODE (offset_vector_type));
5501 968920 : int output_ops = internal_load_fn_p (ifn) ? 1 : 0;
5502 968920 : bool unsigned_p = TYPE_UNSIGNED (TREE_TYPE (offset_vector_type));
5503 968920 : bool ok = icode != CODE_FOR_nothing
5504 0 : && insn_operand_matches (icode, 2 + output_ops, GEN_INT (unsigned_p))
5505 968920 : && insn_operand_matches (icode, 3 + output_ops, GEN_INT (scale));
5506 :
5507 968920 : if (ok && elsvals)
5508 0 : get_supported_else_vals
5509 0 : (icode, internal_fn_else_index (IFN_MASK_GATHER_LOAD), *elsvals);
5510 :
5511 : return ok;
5512 : }
5513 :
5514 : /* Return true if the target supports a strided load/store function IFN
5515 : with VECTOR_TYPE. If supported and ELSVALS is nonzero the supported else
5516 : values will be added to the vector ELSVALS points to. */
5517 :
5518 : bool
5519 1868 : internal_strided_fn_supported_p (internal_fn ifn, tree vector_type,
5520 : vec<int> *elsvals)
5521 : {
5522 1868 : machine_mode mode = TYPE_MODE (vector_type);
5523 1868 : optab optab = direct_internal_fn_optab (ifn);
5524 1868 : insn_code icode = direct_optab_handler (optab, mode);
5525 :
5526 1868 : bool ok = icode != CODE_FOR_nothing;
5527 :
5528 1868 : if (ok && elsvals)
5529 0 : get_supported_else_vals (icode, internal_fn_else_index (ifn), *elsvals);
5530 :
5531 1868 : return ok;
5532 : }
5533 :
5534 : /* Return true if the target supports IFN_CHECK_{RAW,WAR}_PTRS function IFN
5535 : for pointers of type TYPE when the accesses have LENGTH bytes and their
5536 : common byte alignment is ALIGN. */
5537 :
5538 : bool
5539 5328 : internal_check_ptrs_fn_supported_p (internal_fn ifn, tree type,
5540 : poly_uint64 length, unsigned int align)
5541 : {
5542 5328 : machine_mode mode = TYPE_MODE (type);
5543 5328 : optab optab = direct_internal_fn_optab (ifn);
5544 5328 : insn_code icode = direct_optab_handler (optab, mode);
5545 5328 : if (icode == CODE_FOR_nothing)
5546 : return false;
5547 0 : rtx length_rtx = immed_wide_int_const (length, mode);
5548 0 : return (insn_operand_matches (icode, 3, length_rtx)
5549 0 : && insn_operand_matches (icode, 4, GEN_INT (align)));
5550 : }
5551 :
5552 : /* Return the supported bias for IFN which is either IFN_{LEN_,MASK_LEN_,}LOAD
5553 : or IFN_{LEN_,MASK_LEN_,}STORE. For now we only support the biases of 0 and
5554 : -1 (in case 0 is not an allowable length for {len_,mask_len_}load or
5555 : {len_,mask_len_}store). If none of the biases match what the backend
5556 : provides, return VECT_PARTIAL_BIAS_UNSUPPORTED. */
5557 :
5558 : signed char
5559 0 : internal_len_load_store_bias (internal_fn ifn, machine_mode mode)
5560 : {
5561 0 : optab optab = direct_internal_fn_optab (ifn);
5562 0 : insn_code icode = direct_optab_handler (optab, mode);
5563 0 : int bias_idx = internal_fn_len_index (ifn) + 1;
5564 :
5565 0 : if (icode == CODE_FOR_nothing)
5566 : {
5567 0 : machine_mode mask_mode;
5568 0 : if (!targetm.vectorize.get_mask_mode (mode).exists (&mask_mode))
5569 0 : return VECT_PARTIAL_BIAS_UNSUPPORTED;
5570 0 : if (ifn == IFN_LEN_LOAD)
5571 : {
5572 : /* Try MASK_LEN_LOAD. */
5573 0 : optab = direct_internal_fn_optab (IFN_MASK_LEN_LOAD);
5574 0 : bias_idx = internal_fn_len_index (IFN_MASK_LEN_LOAD) + 1;
5575 : }
5576 : else
5577 : {
5578 : /* Try MASK_LEN_STORE. */
5579 0 : optab = direct_internal_fn_optab (IFN_MASK_LEN_STORE);
5580 0 : bias_idx = internal_fn_len_index (IFN_MASK_LEN_STORE) + 1;
5581 : }
5582 0 : icode = convert_optab_handler (optab, mode, mask_mode);
5583 : }
5584 :
5585 0 : if (icode != CODE_FOR_nothing)
5586 : {
5587 : /* For now we only support biases of 0 or -1. Try both of them. */
5588 0 : if (insn_operand_matches (icode, bias_idx, GEN_INT (0)))
5589 : return 0;
5590 0 : if (insn_operand_matches (icode, bias_idx, GEN_INT (-1)))
5591 0 : return -1;
5592 : }
5593 :
5594 : return VECT_PARTIAL_BIAS_UNSUPPORTED;
5595 : }
5596 :
5597 : /* Expand STMT as though it were a call to internal function FN. */
5598 :
5599 : void
5600 264938 : expand_internal_call (internal_fn fn, gcall *stmt)
5601 : {
5602 264938 : internal_fn_expanders[fn] (fn, stmt);
5603 264938 : }
5604 :
5605 : /* Expand STMT, which is a call to internal function FN. */
5606 :
5607 : void
5608 231512 : expand_internal_call (gcall *stmt)
5609 : {
5610 231512 : expand_internal_call (gimple_call_internal_fn (stmt), stmt);
5611 231512 : }
5612 :
5613 : /* If TYPE is a vector type, return true if IFN is a direct internal
5614 : function that is supported for that type. If TYPE is a scalar type,
5615 : return true if IFN is a direct internal function that is supported for
5616 : the target's preferred vector version of TYPE. */
5617 :
5618 : bool
5619 17290 : vectorized_internal_fn_supported_p (internal_fn ifn, tree type)
5620 : {
5621 17290 : if (VECTOR_MODE_P (TYPE_MODE (type)))
5622 10981 : return direct_internal_fn_supported_p (ifn, type, OPTIMIZE_FOR_SPEED);
5623 :
5624 6309 : scalar_mode smode;
5625 6309 : if (VECTOR_TYPE_P (type)
5626 6309 : || !is_a <scalar_mode> (TYPE_MODE (type), &smode))
5627 : return false;
5628 :
5629 6298 : machine_mode vmode = targetm.vectorize.preferred_simd_mode (smode);
5630 6298 : if (VECTOR_MODE_P (vmode))
5631 : {
5632 6261 : tree vectype = build_vector_type_for_mode (type, vmode);
5633 6261 : if (direct_internal_fn_supported_p (ifn, vectype, OPTIMIZE_FOR_SPEED))
5634 : return true;
5635 : }
5636 :
5637 4283 : auto_vector_modes vector_modes;
5638 4283 : targetm.vectorize.autovectorize_vector_modes (&vector_modes, true);
5639 26710 : for (machine_mode base_mode : vector_modes)
5640 13861 : if (related_vector_mode (base_mode, smode).exists (&vmode))
5641 : {
5642 12162 : tree vectype = build_vector_type_for_mode (type, vmode);
5643 12162 : if (direct_internal_fn_supported_p (ifn, vectype, OPTIMIZE_FOR_SPEED))
5644 : return true;
5645 : }
5646 :
5647 : return false;
5648 4283 : }
5649 :
5650 : void
5651 0 : expand_SHUFFLEVECTOR (internal_fn, gcall *)
5652 : {
5653 0 : gcc_unreachable ();
5654 : }
5655 :
5656 : void
5657 0 : expand_PHI (internal_fn, gcall *)
5658 : {
5659 0 : gcc_unreachable ();
5660 : }
5661 :
5662 : void
5663 333 : expand_SPACESHIP (internal_fn, gcall *stmt)
5664 : {
5665 333 : tree lhs = gimple_call_lhs (stmt);
5666 333 : tree rhs1 = gimple_call_arg (stmt, 0);
5667 333 : tree rhs2 = gimple_call_arg (stmt, 1);
5668 333 : tree rhs3 = gimple_call_arg (stmt, 2);
5669 333 : tree type = TREE_TYPE (rhs1);
5670 :
5671 333 : do_pending_stack_adjust ();
5672 :
5673 333 : rtx target = expand_expr (lhs, NULL_RTX, VOIDmode, EXPAND_WRITE);
5674 333 : rtx op1 = expand_normal (rhs1);
5675 333 : rtx op2 = expand_normal (rhs2);
5676 333 : rtx op3 = expand_normal (rhs3);
5677 :
5678 333 : class expand_operand ops[4];
5679 333 : create_call_lhs_operand (&ops[0], target, TYPE_MODE (TREE_TYPE (lhs)));
5680 333 : create_input_operand (&ops[1], op1, TYPE_MODE (type));
5681 333 : create_input_operand (&ops[2], op2, TYPE_MODE (type));
5682 333 : create_input_operand (&ops[3], op3, TYPE_MODE (TREE_TYPE (rhs3)));
5683 333 : insn_code icode = optab_handler (spaceship_optab, TYPE_MODE (type));
5684 333 : expand_insn (icode, 4, ops);
5685 333 : assign_call_lhs (lhs, target, &ops[0]);
5686 333 : }
5687 :
5688 : void
5689 0 : expand_ASSUME (internal_fn, gcall *)
5690 : {
5691 0 : }
5692 :
5693 : void
5694 0 : expand_MASK_CALL (internal_fn, gcall *)
5695 : {
5696 : /* This IFN should only exist between ifcvt and vect passes. */
5697 0 : gcc_unreachable ();
5698 : }
5699 :
5700 : void
5701 0 : expand_VARYING (internal_fn, gcall *)
5702 : {
5703 : /* This IFN should reach expand. */
5704 0 : gcc_unreachable ();
5705 : }
5706 :
5707 : void
5708 1689 : expand_MULBITINT (internal_fn, gcall *stmt)
5709 : {
5710 1689 : rtx_mode_t args[6];
5711 11823 : for (int i = 0; i < 6; i++)
5712 10134 : args[i] = rtx_mode_t (expand_normal (gimple_call_arg (stmt, i)),
5713 20268 : (i & 1) ? SImode : ptr_mode);
5714 1689 : rtx fun = init_one_libfunc ("__mulbitint3");
5715 1689 : emit_library_call_value_1 (0, fun, NULL_RTX, LCT_NORMAL, VOIDmode, 6, args);
5716 1689 : }
5717 :
5718 : void
5719 163 : expand_DIVMODBITINT (internal_fn, gcall *stmt)
5720 : {
5721 163 : rtx_mode_t args[8];
5722 1467 : for (int i = 0; i < 8; i++)
5723 1304 : args[i] = rtx_mode_t (expand_normal (gimple_call_arg (stmt, i)),
5724 2608 : (i & 1) ? SImode : ptr_mode);
5725 163 : rtx fun = init_one_libfunc ("__divmodbitint4");
5726 163 : emit_library_call_value_1 (0, fun, NULL_RTX, LCT_NORMAL, VOIDmode, 8, args);
5727 163 : }
5728 :
5729 : void
5730 179 : expand_FLOATTOBITINT (internal_fn, gcall *stmt)
5731 : {
5732 179 : machine_mode mode = TYPE_MODE (TREE_TYPE (gimple_call_arg (stmt, 2)));
5733 179 : rtx arg0 = expand_normal (gimple_call_arg (stmt, 0));
5734 179 : rtx arg1 = expand_normal (gimple_call_arg (stmt, 1));
5735 179 : rtx arg2 = expand_normal (gimple_call_arg (stmt, 2));
5736 179 : rtx fun = optab_libfunc (bitintfromfp_optab, mode);
5737 179 : emit_library_call (fun, LCT_NORMAL, VOIDmode, arg0, ptr_mode, arg1,
5738 : SImode, arg2, mode);
5739 179 : }
5740 :
5741 : void
5742 148 : expand_BITINTTOFLOAT (internal_fn, gcall *stmt)
5743 : {
5744 148 : tree lhs = gimple_call_lhs (stmt);
5745 148 : if (!lhs)
5746 : return;
5747 148 : machine_mode mode = TYPE_MODE (TREE_TYPE (lhs));
5748 148 : rtx arg0 = expand_normal (gimple_call_arg (stmt, 0));
5749 148 : rtx arg1 = expand_normal (gimple_call_arg (stmt, 1));
5750 148 : rtx fun = optab_libfunc (bitinttofp_optab, mode);
5751 148 : rtx target = expand_expr (lhs, NULL_RTX, VOIDmode, EXPAND_WRITE);
5752 148 : rtx val = emit_library_call_value (fun, target, LCT_PURE, mode,
5753 : arg0, ptr_mode, arg1, SImode);
5754 148 : if (val != target)
5755 0 : emit_move_insn (target, val);
5756 : }
5757 :
5758 : static bool
5759 6443 : expand_bitquery (internal_fn fn, gcall *stmt)
5760 : {
5761 6443 : tree lhs = gimple_call_lhs (stmt);
5762 6443 : if (lhs == NULL_TREE)
5763 : return false;
5764 6437 : tree arg = gimple_call_arg (stmt, 0);
5765 6437 : if (TREE_CODE (arg) == INTEGER_CST)
5766 : {
5767 0 : tree ret = fold_const_call (as_combined_fn (fn), TREE_TYPE (arg), arg);
5768 0 : gcc_checking_assert (ret && TREE_CODE (ret) == INTEGER_CST);
5769 0 : expand_assignment (lhs, ret, false);
5770 0 : return false;
5771 : }
5772 : return true;
5773 : }
5774 :
5775 : void
5776 1 : expand_CLRSB (internal_fn fn, gcall *stmt)
5777 : {
5778 1 : if (expand_bitquery (fn, stmt))
5779 0 : expand_unary_optab_fn (fn, stmt, clrsb_optab);
5780 1 : }
5781 :
5782 : void
5783 4733 : expand_CLZ (internal_fn fn, gcall *stmt)
5784 : {
5785 4733 : if (expand_bitquery (fn, stmt))
5786 4732 : expand_unary_optab_fn (fn, stmt, clz_optab);
5787 4733 : }
5788 :
5789 : void
5790 1186 : expand_CTZ (internal_fn fn, gcall *stmt)
5791 : {
5792 1186 : if (expand_bitquery (fn, stmt))
5793 1185 : expand_unary_optab_fn (fn, stmt, ctz_optab);
5794 1186 : }
5795 :
5796 : void
5797 133 : expand_FFS (internal_fn fn, gcall *stmt)
5798 : {
5799 133 : if (expand_bitquery (fn, stmt))
5800 132 : expand_unary_optab_fn (fn, stmt, ffs_optab);
5801 133 : }
5802 :
5803 : void
5804 173 : expand_PARITY (internal_fn fn, gcall *stmt)
5805 : {
5806 173 : if (expand_bitquery (fn, stmt))
5807 172 : expand_unary_optab_fn (fn, stmt, parity_optab);
5808 173 : }
5809 :
5810 : void
5811 217 : expand_POPCOUNT (internal_fn fn, gcall *stmt)
5812 : {
5813 217 : if (!expand_bitquery (fn, stmt))
5814 : return;
5815 216 : if (gimple_call_num_args (stmt) == 1)
5816 : {
5817 208 : expand_unary_optab_fn (fn, stmt, popcount_optab);
5818 208 : return;
5819 : }
5820 : /* If .POPCOUNT call has 2 arguments, match_single_bit_test marked it
5821 : because the result is only used in an equality comparison against 1.
5822 : Use rtx costs in that case to determine if .POPCOUNT (arg) == 1
5823 : or (arg ^ (arg - 1)) > arg - 1 is cheaper.
5824 : If .POPCOUNT second argument is 0, we additionally know that arg
5825 : is non-zero, so use arg & (arg - 1) == 0 instead.
5826 : If .POPCOUNT second argument is -1, the comparison was either `<= 1`
5827 : or `> 1`. */
5828 8 : bool speed_p = optimize_insn_for_speed_p ();
5829 8 : tree lhs = gimple_call_lhs (stmt);
5830 8 : tree arg = gimple_call_arg (stmt, 0);
5831 8 : bool nonzero_arg = integer_zerop (gimple_call_arg (stmt, 1));
5832 8 : bool was_le = integer_minus_onep (gimple_call_arg (stmt, 1));
5833 8 : if (was_le)
5834 0 : nonzero_arg = true;
5835 8 : tree type = TREE_TYPE (arg);
5836 8 : machine_mode mode = TYPE_MODE (type);
5837 8 : machine_mode lhsmode = TYPE_MODE (TREE_TYPE (lhs));
5838 8 : do_pending_stack_adjust ();
5839 8 : start_sequence ();
5840 8 : expand_unary_optab_fn (fn, stmt, popcount_optab);
5841 8 : rtx_insn *popcount_insns = end_sequence ();
5842 8 : start_sequence ();
5843 8 : rtx plhs = expand_expr (lhs, NULL_RTX, VOIDmode, EXPAND_WRITE);
5844 8 : rtx pcmp = emit_store_flag (NULL_RTX, EQ, plhs, const1_rtx, lhsmode, 0, 0);
5845 8 : if (pcmp == NULL_RTX)
5846 : {
5847 0 : fail:
5848 0 : end_sequence ();
5849 0 : emit_insn (popcount_insns);
5850 0 : return;
5851 : }
5852 8 : rtx_insn *popcount_cmp_insns = end_sequence ();
5853 8 : start_sequence ();
5854 8 : rtx op0 = expand_normal (arg);
5855 8 : rtx argm1 = expand_simple_binop (mode, PLUS, op0, constm1_rtx, NULL_RTX,
5856 : 1, OPTAB_WIDEN);
5857 8 : if (argm1 == NULL_RTX)
5858 0 : goto fail;
5859 12 : rtx argxorargm1 = expand_simple_binop (mode, nonzero_arg ? AND : XOR, op0,
5860 : argm1, NULL_RTX, 1, OPTAB_WIDEN);
5861 8 : if (argxorargm1 == NULL_RTX)
5862 0 : goto fail;
5863 8 : rtx cmp;
5864 8 : if (nonzero_arg)
5865 4 : cmp = emit_store_flag (NULL_RTX, EQ, argxorargm1, const0_rtx, mode, 1, 1);
5866 : else
5867 4 : cmp = emit_store_flag (NULL_RTX, GTU, argxorargm1, argm1, mode, 1, 1);
5868 8 : if (cmp == NULL_RTX)
5869 0 : goto fail;
5870 8 : rtx_insn *cmp_insns = end_sequence ();
5871 8 : unsigned popcount_cost = (seq_cost (popcount_insns, speed_p)
5872 8 : + seq_cost (popcount_cmp_insns, speed_p));
5873 8 : unsigned cmp_cost = seq_cost (cmp_insns, speed_p);
5874 :
5875 8 : if (dump_file && (dump_flags & TDF_DETAILS))
5876 0 : fprintf(dump_file, "popcount == 1: popcount cost: %u; cmp cost: %u\n",
5877 : popcount_cost, cmp_cost);
5878 :
5879 8 : if (popcount_cost <= cmp_cost)
5880 8 : emit_insn (popcount_insns);
5881 : else
5882 : {
5883 0 : start_sequence ();
5884 0 : emit_insn (cmp_insns);
5885 0 : plhs = expand_expr (lhs, NULL_RTX, VOIDmode, EXPAND_WRITE);
5886 0 : if (GET_MODE (cmp) != GET_MODE (plhs))
5887 0 : cmp = convert_to_mode (GET_MODE (plhs), cmp, 1);
5888 : /* For `<= 1`, we need to produce `2 - cmp` or `cmp ? 1 : 2` as that
5889 : then gets compared against 1 and we need the false case to be 2. */
5890 0 : if (was_le)
5891 : {
5892 0 : cmp = expand_simple_binop (GET_MODE (cmp), MINUS, const2_rtx,
5893 : cmp, NULL_RTX, 1, OPTAB_WIDEN);
5894 0 : if (!cmp)
5895 0 : goto fail;
5896 : }
5897 0 : emit_move_insn (plhs, cmp);
5898 0 : rtx_insn *all_insns = end_sequence ();
5899 0 : emit_insn (all_insns);
5900 : }
5901 : }
5902 :
5903 : void
5904 0 : expand_BSWAP (internal_fn fn, gcall *stmt)
5905 : {
5906 0 : if (expand_bitquery (fn, stmt))
5907 0 : expand_unary_optab_fn (fn, stmt, bswap_optab);
5908 0 : }
5909 :
5910 : void
5911 0 : expand_BITREVERSE (internal_fn fn, gcall *stmt)
5912 : {
5913 0 : if (expand_bitquery (fn, stmt))
5914 0 : expand_unary_optab_fn (fn, stmt, bitreverse_optab);
5915 0 : }
|